common
common copied to clipboard
Include sender's public key in the encrypted message
This fixes https://github.com/polkadot-js/common/issues/1314 and added the code posted by @LaurentTrk in the tests.
I introduced a new member of Keypair called encryptionPublicKey
that is derived from secretKey.slice(0, 32)
and the public key is calculated on Curve25519. I'm mostly certain that this is a secure operation but leaves the extension or application built on top of this harder, as you cannot simply use the address to send encrypted message anymore. Converting sr25519 pub key to curve25519 is risky (to implement). Doing ECDH directly on sr25519 is possible but harder than converting and is a nightmare to deal with and require users to be on the same KeyringType. So far, I can't think of a quicker and low-risk solution.
Also, it seems to me that decode/encode wallet might be problematic that might worth attention, because the tests passed on cross-usage of ed25519/sr25519 initially (as below). On the new test proposed by @LaurentTrk the key conversion from pairA.publicKey
to curve25519 should failed, because ed2curve
cannot correctly calculate public keys on sr25519. But it didn't fail on the original test. Therefore, I assumed that ed2curve
works on sr25519. But apparently, I was wrong. Let me know if I'm thinking about this the wrong way.
it('validates encryption between ed25519 & sr25519 key pairs', (): void => {
const PASS = 'testing';
const encodedA = keyring.alice.encodePkcs8(PASS);
const encodedB = keyring.bob.encodePkcs8(PASS);
const pairA = createPair({ toSS58, type: 'sr25519' }, { publicKey: keyring.alice.publicKey });
const pairB = createPair({ toSS58, type: 'sr25519' }, { publicKey: keyring.bob.publicKey });
pairA.decodePkcs8(PASS, encodedA);
pairB.decodePkcs8(PASS, encodedB);
const message = new Uint8Array([0x61, 0x62, 0x63, 0x64, 0x65]);
// alice-sr25519 -> bob-ed25519
const encrypted1 = pairA.encryptMessage(message, keyring.bob.publicKey);
// alice-sr25519 -> bob-sr25519
const encrypted2 = pairA.encryptMessage(message, pairB.publicKey);
// alice-ed25519 -> bob-sr25519
const encrypted3 = keyring.alice.encryptMessage(message, pairB.publicKey);
// decrypt: Bob-ed25519 - use alice-ed25519 pubkey
expect(
keyring.bob.decryptMessage(encrypted3, keyring.alice.publicKey)
).toEqual(message);
// decrypt: Bob-ed25519 - use alice-sr25519 pubkey
expect(
keyring.bob.decryptMessage(encrypted1, pairA.publicKey)
).toEqual(message);
// decrypt: Bob-sr25519 - use alice-sr25519 pubkey
expect(
pairB.decryptMessage(encrypted2, pairA.publicKey)
).toEqual(message);
});
Also, I think it's now possible to do encryption/decryption on secp256k1, if doing you guys are fine with introducing encyrptionPublicKey
. Will test it out this week.
Thanks @RoyTimes !
As a non cryptographer, it sounds to me that we are trying to force a square peg into a round hole...
I would prefer to go for a well documented approach like ECIES, which seems compatible both with ed25519 and sr25519 (using the schnorrkelAgreement
already available in wasm-crypto
).
In this approach, we only need one keypair (the one of the receiver), so we don't care about cross wallet exchange.
I can start to work on this, any thought/idea is welcome :)
Sorry about the delay in looking, a bit behind on reviews - I have a note of getting to this one.
Closing, removing this functionality in https://github.com/polkadot-js/common/pull/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.