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

Enable public key type guessing in encryption #1

Open
wants to merge 1 commit into
base: asymmetric_decyption_feature
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 30 additions & 3 deletions packages/keyring/src/keyring.ts
Expand Up @@ -4,8 +4,8 @@
import type { EncryptedJsonEncoding, Keypair, KeypairType } from '@polkadot/util-crypto/types';
import type { KeyringInstance, KeyringOptions, KeyringPair, KeyringPair$Json, KeyringPair$Meta } from './types';

import { assert, hexToU8a, isHex, isUndefined, stringToU8a } from '@polkadot/util';
import { base64Decode, decodeAddress, ed25519PairFromSeed as ed25519FromSeed, encodeAddress, encrypt as cryptoEncrypt, ethereumEncode, hdEthereum, keyExtractSuri, keyFromPath, mnemonicToLegacySeed, mnemonicToMiniSecret, secp256k1PairFromSeed as secp256k1FromSeed, sr25519PairFromSeed as sr25519FromSeed } from '@polkadot/util-crypto';
import { assert, hexToU8a, isHex, isUndefined, stringToU8a, u8aConcat } from '@polkadot/util';
import { base64Decode, decodeAddress, ed25519PairFromSeed as ed25519FromSeed, encodeAddress, encrypt as cryptoEncrypt, ethereumEncode, hdEthereum, keyExtractSuri, keyFromPath, mnemonicToLegacySeed, mnemonicToMiniSecret, secp256k1PairFromSeed as secp256k1FromSeed, sr25519PairFromSeed as sr25519FromSeed, convertPublicKeyToCurve25519, sr25519DerivePublic } from '@polkadot/util-crypto';

import { DEV_PHRASE } from './defaults';
import { createPair } from './pair';
Expand Down Expand Up @@ -304,6 +304,33 @@ export class Keyring implements KeyringInstance {
* 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);
const publicKey = decodeAddress(recipientPublicKey);
let keyType = recipientKeyType ? recipientKeyType : this.guessKeyType(publicKey);
const encryptedMessage = cryptoEncrypt(message, recipientPublicKey, keyType);
return u8aConcat(publicKey, encryptedMessage);
}

private guessKeyType (publicKey: Uint8Array): KeypairType {
if(this.isEd25519PublicKey(publicKey)) {
return "ed25519";
} {
return "sr25519";
}
}

private isEd25519PublicKey (publicKey: Uint8Array): boolean {
try {
convertPublicKeyToCurve25519(publicKey);
return true;
} catch(e) {
return false;
}
}

public decrypt (message: Uint8Array): Uint8Array | null {
const publicKeyBytes = message.slice(0, 32);
const encryptedMessage = message.slice(32);
const keyPair = this.getPair(publicKeyBytes);
return keyPair.decrypt(encryptedMessage);
}
}
35 changes: 32 additions & 3 deletions packages/keyring/src/pair/index.spec.ts
Expand Up @@ -243,7 +243,7 @@ describe('pair', (): void => {
expect(keyring.alice.decrypt(encryptedMessage)).toEqual(null);
});

it('allows encrypt/decrypt with sr25519 keypair', (): void => {
it('allows encrypt/decrypt with sr25519 keypairs', (): 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]);
Expand All @@ -253,11 +253,40 @@ describe('pair', (): void => {
expect((): Uint8Array | null => aliceSR25519KeyPair.decrypt(encryptedMessage)).toThrow("Mac values don't match");
});

it('allows encrypt/decrypt with ed25519 keypair and type guessing', (): void => {
const keyring = new Keyring();
const bobED25519KeyPair = keyring.addFromUri(mnemonicGenerate(), { name: 'ed25519 pair' }, 'ed25519');
const message = new Uint8Array([0x61, 0x62, 0x63, 0x64, 0x65]);
const encryptedMessage = keyring.encrypt(message, bobED25519KeyPair.publicKey);

expect(keyring.decrypt(encryptedMessage)).toEqual(message);
});

it('allows encrypt/decrypt with sr25519 keypair and type guessing with non-convertible public key', (): void => {
const keyring = new Keyring();
const mnemonic = "easily dust bright surface scale walnut stick buddy spare quick trial crane";
const bobSR25519KeyPair = keyring.addFromUri(mnemonic, { name: 'sr25519 pair' }, 'sr25519');
const message = new Uint8Array([0x61, 0x62, 0x63, 0x64, 0x65]);
const encryptedMessage = keyring.encrypt(message, bobSR25519KeyPair.publicKey);

expect(keyring.decrypt(encryptedMessage)).toEqual(message);
});

it('allows encrypt/decrypt with sr25519 keypair and type guessing with convertible public key', (): void => {
const keyring = new Keyring();
const mnemonic = "excess control wrestle sustain gauge swear unveil trap tunnel coil nurse salt";
const bobSR25519KeyPair = keyring.addFromUri(mnemonic, { name: 'sr25519 pair' }, 'sr25519');
const message = new Uint8Array([0x61, 0x62, 0x63, 0x64, 0x65]);
const encryptedMessage = keyring.encrypt(message, bobSR25519KeyPair.publicKey);

expect(keyring.decrypt(encryptedMessage)).toEqual(message);
});

it('allows encrypt for an ed25519 keypair', (): void => {
const message = new Uint8Array([0x61, 0x62, 0x63, 0x64, 0x65]);
const encryptedMessage = new Keyring().encrypt(message, keyring.alice.publicKey, keyring.alice.type);

expect(keyring.alice.decrypt(encryptedMessage)).toEqual(message);
expect(keyring.alice.decrypt(encryptedMessage.slice(32))).toEqual(message);
});

it('allows encrypt for an sr25519 keypair', (): void => {
Expand All @@ -266,7 +295,7 @@ describe('pair', (): void => {
const message = new Uint8Array([0x61, 0x62, 0x63, 0x64, 0x65]);
const encryptedMessage = keyring.encrypt(message, sr25519KeyPair.publicKey, sr25519KeyPair.type);

expect(sr25519KeyPair.decrypt(encryptedMessage)).toEqual(message);
expect(sr25519KeyPair.decrypt(encryptedMessage.slice(32))).toEqual(message);
});

it('fails to encrypt when locked', (): void => {
Expand Down