cardano-serialization-lib icon indicating copy to clipboard operation
cardano-serialization-lib copied to clipboard

Creating PublicKey from the result of a dApp signData

Open olliejm opened this issue 2 years ago • 8 comments

Hi, I started an issue over on the message-signing library asking a question about how to go about verifying signed arbitrary data, as there was a lack of examples.

I've not had a response however and there seems to be much less activity over there, so considering that the question also involves this library (perhaps more), maybe someone is able to assist me with at least that part of it.

Essentially, using the dApp injected API signData function I'm able to sign something and get back an object like

{ "signature": "<...>", "key": "<...>" }

Where I could be mistaken is that to get the public key information for the wallet that signed the data, you would then need to convert the key hex string to bytes, and run...

cardano_serialization_lib::crypto::PublicKey::from_bytes(key_bytes);

...to get an instance of the public key? Is that correct? As the result of that call in Rust has an "Invalid Public Key size" when I supply the result of as_bytes on the hex string that Nami provided.

I'm probably doing something really stupid here, but I'm struggling to find any examples to help. It'd be really appreciated if anyone can give a pointer

olliejm avatar Mar 08 '22 17:03 olliejm

Hi @olliejm I'm on vacation right now but I did see your issue in the message signing lib. I'm not up to date with to what degree Nami follows the recent updates to the CIP-30 data sign endpoint which affect this. How many bytes is the key you get? It's possible that they've already updated to storing the CBOR bytes of a COSEKey. It's also possible it's a CBOR bytes vs raw bytes mix-up if it's 1 extra byte.

rooooooooob avatar Mar 08 '22 19:03 rooooooooob

No problem, appreciate the help. Nami has moved to the new API as far as I understand. The key string is 84 bytes.

Calling the WASM from node I was able to construct a SignedMessage instance from the signature value, which I was then able to get the payload back from. I was also able to do COSEKey.from_bytes from the key without an error - but was stumped on what information I needed back from it

I'm working on a presumption that I should be able to get some data from that to ultimately derive the address of the signature's owner

olliejm avatar Mar 08 '22 21:03 olliejm

Hey @olliejm,

I'm not sure how much use this will be but I've been working on adding Signature Verification / Address Verification to the web3-cardano-token project.

https://github.com/gavinharris-dev/web3-cardano-token

Take a look at the verify.js file. In here I try to do 2 things:

  1. Verify that the address signing the message is the same address as in the Message header.
  2. Verify that the message has not been tempered with (by checking the Ed25519Signature with the Address Public Key).

I'd be very happy to get feedback on the approach! Gav

gavinharris-dev avatar Mar 08 '22 23:03 gavinharris-dev

This looks like it could be extremely helpful, thank you! I will take a closer look tomorrow evening

olliejm avatar Mar 08 '22 23:03 olliejm

Thanks @gavinharris-dev I think I've managed to get where I need now. I have a couple of questions:

  1. baseAddress is not declared here - I was able to construct it from checkAddress, was the the intention? https://github.com/gavinharris-dev/web3-cardano-token/blob/main/src/lib/verify.js#L112
  2. checkAddress.hash() here is also not a function - I wasn't as sure this time what type was supposed to have the .hash() function as it's not on BaseAddress. It could be PublicKey?. More generally though I was just curious if that second try block does much differently than just being a backup - is the first method preferred for a reason? https://github.com/gavinharris-dev/web3-cardano-token/blob/main/src/lib/verify.js#L130-L151

Can't thank you enough for linking me to your project! I don't think I would have ever figured out that this was the specific process required to do the verification based on the documentation and examples available.

I'd skip what I'm doing and use your library as it looks great, but I'm trying to add this authentication to a C# web API. So my intention is to create an extremely basic convenience function in Rust which takes the signData output and validates it, then bind that function in C#

olliejm avatar Mar 09 '22 19:03 olliejm

Hey @olliejm did you managed to do it?

On the client side, I tried signData with:

  1. "old Nami" method (window.cardano):
  2. "new Nami" method (window.cardano.nami.enable()):
  3. as well as Eternl (window.cardano.ccvault.enable()):

On the server side, I've tried:

  1. https://github.com/gavinharris-dev/web3-cardano-token by @gavinharris-dev
  2. https://github.com/pyropy/web3-cardano-token
  3. Matt solution in https://cardano.stackexchange.com/questions/4793/how-to-establish-trust-between-a-users-wallet-and-the-backend-of-a-website

signData using Nami older method (window.cardano.signData(publicAddress, signature)), it returned Code: 4. If a wallet enforces data format requirements, this error signifies that the data did not conform to valid formats.. Where both inputs publicAddress and signature are string, for example addrblabla and abcabcabc.

signData using Eternl's signData(publicAddress, signature) returns a string, where both inputs publicAddress and signature are string, for example addrblabla and abcabcabc. Unfortunately on the server side, it returns ERROR [ExceptionsHandler] Deserialization failed in Address because: Encountered unknown address header 0b10101101 when calling const addressCose: Serialization.Address = Serialization.Address.from_bytes(headerCBORBytes);.

Using web3-cardano-token codes by pyropy and @gavinharris-dev also have the same error, Deserialization failed in Address because: Encountered unknown address header 0b10101101.

jinglescode avatar Apr 18 '22 06:04 jinglescode

@jinglescode just in case you haven't solved it. I was receiving the same error in Nami wallet but using the Stake address the error disappears.

You need to do something like this, where api is the cardano api of the wallet:

const rewardAddress = await api.getRewardAddresses();
const stakeAddress = rewardAddress[0]
const cose = await api.signData(stakeAddress, Buffer.from('Data to sign').toString('hex'));

georgeos avatar May 24 '22 04:05 georgeos

I ended up re-signing CCVault/Eternal Data Signs since it dose not preserve the data that was signed.

yungtechboy1 avatar Jul 07 '22 00:07 yungtechboy1