-
Notifications
You must be signed in to change notification settings - Fork 145
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
Asymmetric encryption/decryption feature #1331
Asymmetric encryption/decryption feature #1331
Conversation
Generally good. However I have two suggestions:
|
Thanks @h4x3rotab ! Regarding your proposal on exposing the agreement, I would like to propose the 2 options (ephemeral key as ECIES and 2nd party key), depending on the way you call the
In both options, the Edit: add implementation details to PR description. |
Thanks for this work @LaurentTrk - I'm not able to add any coding or encryption contributions but from a usability point |
Hello @LaurentTrk, thanks a lot for this contribution! I reviewed the code and IMHO, everything is fine (documentation, style, tests). Is there something preventing you to change the status of this PR to pending? If not, I suggest that you do so so that maintainers can review it as well. Remove also the [WIP] is the PR's title. ;-) |
Thanks for your comment @gdethier ;) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just left a small suggestion.
|
||
return type === 'ed25519' | ||
? ed25519Decrypt(u8aToU8a(encryptedMessage), { publicKey, secretKey }) | ||
: sr25519Decrypt(u8aToU8a(encryptedMessage), { publicKey, secretKey }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In above 2 lines, no need to pass-in the public key, only the secret key is needed to decrypt the message.
Hello @jacogr ! Did you already have a look at this PR? We would really love to see this feature integrated as we rely on it in this fork of the Polkadot JS extension which brings encryption/decryption: https://github.com/LaurentTrk/extension/tree/DecryptionFeature (we are actually waiting for this PR to be merged before creating the one on the extension). If there is anything we can do to make your life easier, please do not hesitate to tell. |
I am also anxiously awaiting this feature, into this library and the corresponding one on the extension. thank you! |
Will bump it up the overflowing task queue. Sorry for the long time getting here, it is on the list, but not a lot of progress seems to be made on my side getting through. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is nice work. However I'm not at all convinced about the requirement to have to specify the key type for the recipient - this is the stickler in making it available to all users, techy and non-techy.
... this is exactly the bigger issue that we are facing with this functionality: multiple key types, without users knowing what they are and them having to magically co-operate.
* The encrypted message can be decrypted by the corresponding keypair using keypair.decrypt() method | ||
*/ | ||
public encrypt (message: string | Uint8Array, recipientPublicKey: string | Uint8Array, recipientKeyType?: KeypairType): Uint8Array { | ||
return cryptoEncrypt(message, recipientPublicKey, recipientKeyType || this.type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally users have no idea even what their own keypair types are, let alone somebody else knowing what a specific user has.
This means that the addition of the recipientKeyType
here is an issue - the sender won't know which type the actual recipient uses. It could be anything and for most users this is not known at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @jacogr,
Thanks for your review.
I actually did not catch your point here, the users of this library are not end users, I guess that they are more techy (as developers) and aware of what key types and encryption are.
I agree that passing the wrong key type for a given public key will fail, but we need this information.
In case the user don't know which type to use, the keyring will use its default value (the one used when creating new key pairs)
it('allows encrypt/decrypt with sr25519 keypair', (): void => { | ||
const aliceSR25519KeyPair = new Keyring().createFromUri(mnemonicGenerate(), { name: 'sr25519 pair' }, 'sr25519'); | ||
const bobSR25519KeyPair = new Keyring().createFromUri(mnemonicGenerate(), { name: 'sr25519 pair' }, 'sr25519'); | ||
const message = new Uint8Array([0x61, 0x62, 0x63, 0x64, 0x65]); | ||
const encryptedMessage = aliceSR25519KeyPair.encrypt(message, bobSR25519KeyPair.publicKey); | ||
|
||
expect(bobSR25519KeyPair.decrypt(encryptedMessage)).toEqual(message); | ||
expect((): Uint8Array | null => aliceSR25519KeyPair.decrypt(encryptedMessage)).toThrow("Mac values don't match"); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would need an additional test (on the back of the above above comment), where the one party uses ed25519 and the other party using sr25519 and they can exchange messages bi-directionally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test has not been done as you cannot exchange messages if the 2 key types differs.
Hello @jacogr and thank you very much for your review. Sorry to come back to you so late but I had to test a few things. I tried to implement encryption/decryption without any prior knowledge about the key type but was not completely successful. Here is what I came up with: LaurentTrk#1 (in another PR to keep this one "clean" of my experiments). In the code, when no type is provided, the key type is guessed. However, that method does not work in all cases (this test passes but this one does not). I am no cryptographer so I think that I reached the limits of what I can achieve. Suggestions are more than welcome. |
Hi @gdethier ! |
Closing, removing this functionality in #1762 |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Hi all,
This work is an alternative way to add the asymmetric encryption/decryption feature than the one already implemented, which does not work with sr25519 (see workaround proposal by @RoyTimes).
It works more like the eth_decrypt function from Metamask, where only one public key/private key pair is involved : you can encrypt data with the public key of the recipient, and only this recipient can decrypt the data with his private/secret key (vs the already implemented solution using nacl.box which requires 2 keypairs).
What has been done ?
encrypt/decrypt
methods toutil-crypto\sr25519
following ECIESencrypt/decrypt
methods toutil-crypto\ed25519
using existing encryption feature, but with an ephemeral key (similar as ECIES)encrypt
method tokeyring
(encrypt data without the need of a keypair)encrypt/decrypt
methods tokeyringPair
Implementation details
Following SR25519 Encryption/Decryption following Elliptic Curve Integrated Encryption Scheme (ECIES)
See https://cryptobook.nakov.com/asymmetric-key-ciphers/ecies-public-key-encryption
The algorithms used were chosen among those already used in this library.
Generate new keypair using the wasm
sr25519KeypairFromSeed
function, with a random seed frommnemonicGenerate
Use wasm
sr25519Agree
function between the generated ephemeral private key and the recipient public keyUse
pbkdf2
(random salt is generated, default 2048 rounds) to derive a new secret from the previous step outputThe derived secret is split into :
Use
nacl.secretbox
api symmetric encryption (xsalsa20-poly1305) to encrypt the messagewith the encryption key generated at step 3.
A nonce (24 bytes) is randomly generated.
HMAC SHA256 (using the MAC key from step 3) of the concatenation of the encryption nonce, ephemeral public key and encrypted message
The encrypted message is the concatenation of the following elements :
Feel free to share your comments and feedbacks 🙏
Nota : Some folks were interested in this feature: