Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ECIES Decrypting a message fetched from API giving me bad public key #75

Open
Mickellz opened this issue Feb 12, 2021 · 7 comments
Open

Comments

@Mickellz
Copy link

Hello. So I have been trying to post the encrypted message as a string hex value to an api and when I retrieve it, buffer the object, and decrypt, it gives me "bad public key". I am not sure why this happens, but how can I effectively store a message as json on an api and fetch it back for client siding decryption?

@JBaczuk
Copy link
Contributor

JBaczuk commented Feb 18, 2021

@Mickellz Sorry, there are examples on the homepage, whether or not you are using an API should make no difference. Can you provide any code, to help you debug?

@kktcell
Copy link

kktcell commented May 30, 2021

Same problem

@giviz
Copy link

giviz commented Nov 11, 2021

This is due to the check on here : https://github.com/bitchan/eccrypto/blob/master/browser.js#L190

When you get the stored message from the API and decode it using something like that

    let parts = blob.split('|');
    let cypher = {
      ciphertext: Uint8Array.from(this.fromBase64(parts[0])),
      ephemPublicKey: Uint8Array.from(this.fromBase64(parts[1])),
      iv: Uint8Array.from(this.fromBase64(parts[2])),
      mac: Uint8Array.from(this.fromBase64(parts[3])), 
    }

It fails because the Buffer.isBuffer check on the Uint8Array of the publicKey fails.
From what I can see, the issue could be that this Uint8Array has a prototype of TypedArray and not Uint8Array like the one generated by eccrypto directly (just guessing here)

By commenting that assert, the code works properly and the message is decoded properly too.

Here is the full code used to encode and decode I'm using :

  public async encrypt(publicKey: string, message: string) : Promise<string> {
    let cypher = await this.eccrypto.encrypt(publicKey, this.stringToArrayBuffer(message));
    let blob = [
      this.toBase64(cypher.ciphertext),
      this.toBase64(cypher.ephemPublicKey),
      this.toBase64(cypher.iv),
      this.toBase64(cypher.mac),
    ].join('|');
    return blob;
  }

  public async decrypt(privateKey: Uint8Array, blob: string) : Promise<string> {
    let parts = blob.split('|');
    let cypher = {
      ciphertext: Uint8Array.from(this.fromBase64(parts[0])),
      ephemPublicKey: Uint8Array.from(this.fromBase64(parts[1])),
      iv: Uint8Array.from(this.fromBase64(parts[2])),
      mac: Uint8Array.from(this.fromBase64(parts[3])), 
    }

    let message = await this.eccrypto.decrypt(privateKey, cypher);
    return this.arrayBufferToString(message);
  }

Edit :

To work with bitcoin keys and not keys generated by eccrypto with the helpers, I also had to comment :

Otherwise, while using eccrypto in the browser it's not working because of the same issue.
With all of that commented, the message encode and decode properly.

Let me know if I can provide more details :)

Edit 2 :

There is a similar issue with the sign and verify methods, I had to replace :

assert(msg.length <= 32, "Message is too long");

By

let length = msg.length;
assert(length <= 32, "Message is too long");

Otherwise it's failing, even if the array is in fact at the correct 32 size :/

@aaronik
Copy link

aaronik commented Mar 16, 2022

@giviz, I'm struggling with storing the private key somewhere, and using that later to (re)generate the public key. I'm having troubles with strings and buffers..

Can you share with us your implementations of this.stringToArrayBuffer and this.fromBase64?

Or if @JBaczuk you're around, or anybody else knows, how exactly does one go from the Uint8Array that eccrypto.generatePrivate() returns to a string and then back again? Preferably a base64 string?

@aaronik
Copy link

aaronik commented Mar 16, 2022

You know what, I finally figured it out (not a minute too soon). This post was instrumental.

To go from buffer to string: const s = eccrypto.generatePrivate().toString(<encoding>)
And from string to buffer: const b = Buffer.from(s, <encoding>)

where encoding works for me best as either 'base64' or 'hex', and I'm going with hex now.

@giviz
Copy link

giviz commented Mar 16, 2022

@aaronik

I'm glad you figured it out, I was actually writing you an email to share my own implementation !
Beware that your current solution will work well in nodejs but not in the browser as it doesn't support Buffer.

For that, you have to take a whole other path... but if it's not required on your use case you're good to go !

@aaronik
Copy link

aaronik commented Mar 16, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants