Skip to content

Commit

Permalink
Fix/secret encrypt async (#6407)
Browse files Browse the repository at this point in the history
* fix: secret async encrypt

* fix: secret unit tests
  • Loading branch information
sidmorizon authored Jan 3, 2025
1 parent 101f26d commit bb104ae
Show file tree
Hide file tree
Showing 33 changed files with 856 additions and 426 deletions.
1 change: 1 addition & 0 deletions jest-setup.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
// require('react-native-reanimated').setUpTests();

// FIX: ReferenceError: self is not defined
Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ module.exports = async () => {
[
'./node_modules/jest-html-reporter',
{
'pageTitle': 'Test Report',
'pageTitle': 'Jest UnitTest Report',
},
],
],
Expand Down
4 changes: 2 additions & 2 deletions packages/core/@tests/coreTestsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ async function expectSignTransactionOk({
const resultImported = await coreApi.signTransaction({
...signTxPayload,
credentials: {
imported: encryptImportedCredential({
imported: await encryptImportedCredential({
password,
credential: { privateKey: account.xpvtRaw || account.privateKeyRaw },
}),
Expand Down Expand Up @@ -258,7 +258,7 @@ async function expectSignMessageOk({
const resultImported = await coreApi.signMessage({
...signMsgPayload,
credentials: {
imported: encryptImportedCredential({
imported: await encryptImportedCredential({
password,
credential: { privateKey: account.privateKeyRaw },
}),
Expand Down
10 changes: 6 additions & 4 deletions packages/core/src/base/CoreChainApiBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
decrypt,
decryptImportedCredential,
ed25519,
encrypt,
encryptAsync,
nistp256,
secp256k1,
} from '../secret';
Expand Down Expand Up @@ -140,7 +140,9 @@ export abstract class CoreChainApiBase {
password,
credential: credentials.imported,
});
const encryptPrivateKey = bufferUtils.bytesToHex(encrypt(password, p));
const encryptPrivateKey = bufferUtils.bytesToHex(
await encryptAsync({ password, data: p }),
);
privateKeys[account.path] = encryptPrivateKey;
privateKeys[''] = encryptPrivateKey;
}
Expand Down Expand Up @@ -170,7 +172,7 @@ export abstract class CoreChainApiBase {
);
}

const keys = batchGetPrivateKeys(
const keys = await batchGetPrivateKeys(
curve,
hdCredential,
password,
Expand Down Expand Up @@ -205,7 +207,7 @@ export abstract class CoreChainApiBase {
let pvtkeyInfos: ISecretPrivateKeyInfo[] = [];

if (isPrivateKeyMode) {
pvtkeyInfos = batchGetPrivateKeys(
pvtkeyInfos = await batchGetPrivateKeys(
curve,
hdCredential,
password,
Expand Down
7 changes: 5 additions & 2 deletions packages/core/src/chains/ada/CoreChainSoftware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { checkIsDefined } from '@onekeyhq/shared/src/utils/assertUtils';
import bufferUtils from '@onekeyhq/shared/src/utils/bufferUtils';

import { CoreChainApiBase } from '../../base/CoreChainApiBase';
import { decrypt, encrypt } from '../../secret';
import { decrypt, encryptAsync } from '../../secret';
import {
ECoreApiExportedSecretKeyType,
type ICoreApiGetAddressItem,
Expand Down Expand Up @@ -53,7 +53,10 @@ export default class CoreChainSoftware extends CoreChainApiBase {

const xprv = await generateExportedCredential(password, hdCredential, path);
const privateKey = decodePrivateKeyByXprv(xprv);
const privateKeyEncrypt = encrypt(password, privateKey);
const privateKeyEncrypt = await encryptAsync({
password,
data: privateKey,
});

const map: ICoreApiPrivateKeysMap = {
[path]: bufferUtils.bytesToHex(privateKeyEncrypt),
Expand Down
18 changes: 9 additions & 9 deletions packages/core/src/chains/btc/CoreChainSoftware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
BaseBip32KeyDeriver,
batchGetPublicKeysAsync,
decrypt,
encrypt,
encryptAsync,
mnemonicFromEntropyAsync,
mnemonicToSeedAsync,
secp256k1,
Expand Down Expand Up @@ -433,15 +433,15 @@ export default class CoreChainSoftwareBtc extends CoreChainApiBase {
return psbt;
}

private appendImportedRelPathPrivateKeys({
private async appendImportedRelPathPrivateKeys({
privateKeys,
password,
relPaths,
}: {
privateKeys: ICoreApiPrivateKeysMap;
password: string;
relPaths?: string[];
}): ICoreApiPrivateKeysMap {
}): Promise<ICoreApiPrivateKeysMap> {
const deriver = new BaseBip32KeyDeriver(
Buffer.from('Bitcoin seed'),
secp256k1,
Expand All @@ -457,12 +457,12 @@ export default class CoreChainSoftwareBtc extends CoreChainApiBase {

const cache: Record<string, IBip32ExtendedKey> = {};

relPaths?.forEach((relPath) => {
for (const relPath of relPaths ?? []) {
const pathComponents = relPath.split('/');

let currentPath = '';
let parent = startKey;
pathComponents.forEach((pathComponent) => {
for (const pathComponent of pathComponents) {
currentPath =
currentPath.length > 0
? `${currentPath}/${pathComponent}`
Expand All @@ -475,13 +475,13 @@ export default class CoreChainSoftwareBtc extends CoreChainApiBase {
cache[currentPath] = thisPrivKey;
}
parent = cache[currentPath];
});
}

// TODO use dbAccountAddresses save fullPath/relPath key
privateKeys[relPath] = bufferUtils.bytesToHex(
encrypt(password, cache[relPath].key),
await encryptAsync({ password, data: cache[relPath].key }),
);
});
}
return privateKeys;
}

Expand Down Expand Up @@ -703,7 +703,7 @@ export default class CoreChainSoftwareBtc extends CoreChainApiBase {
curve: curveName,
});
if (isImported) {
this.appendImportedRelPathPrivateKeys({
await this.appendImportedRelPathPrivateKeys({
privateKeys,
password,
relPaths,
Expand Down
17 changes: 12 additions & 5 deletions packages/core/src/chains/dot/CoreChainSoftware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ import { CoreChainApiBase } from '../../base/CoreChainApiBase';
import {
decrypt,
decryptImportedCredential,
encrypt,
encryptAsync,
mnemonicFromEntropy,
} from '../../secret';
import {
ECoreApiExportedSecretKeyType,
type ICoreApiGetAddressItem,
type ICoreApiGetAddressQueryImported,
type ICoreApiGetAddressQueryPublicKey,
Expand All @@ -30,7 +31,6 @@ import {
type ICurveName,
type ISignedTxPro,
} from '../../types';
import { ECoreApiExportedSecretKeyType } from '../../types';
import { slicePathTemplate } from '../../utils';

import { serializeMessage, serializeSignedTransaction } from './sdkDot';
Expand Down Expand Up @@ -95,16 +95,21 @@ export default class CoreChainSoftware extends CoreChainApiBase {
const usedRelativePaths = relPaths || [pathComponents.pop() as string];
const basePath = pathComponents.join('/');
const mnemonic = mnemonicFromEntropy(credentials.hd, password);
const keys = usedRelativePaths.map((relPath) => {
const keysPromised = usedRelativePaths.map(async (relPath) => {
const path = `${basePath}/${relPath}`;

const keyPair = derivationHdLedger(mnemonic, path);
return {
path,
key: encrypt(password, Buffer.from(keyPair.secretKey.slice(0, 32))),
key: await encryptAsync({
password,
data: Buffer.from(keyPair.secretKey.slice(0, 32)),
}),
};
});

const keys = await Promise.all(keysPromised);

privateKeys = keys.reduce(
(ret, key) => ({ ...ret, [key.path]: bufferUtils.bytesToHex(key.key) }),
{},
Expand All @@ -115,7 +120,9 @@ export default class CoreChainSoftware extends CoreChainApiBase {
password,
credential: credentials.imported,
});
const encryptPrivateKey = bufferUtils.bytesToHex(encrypt(password, p));
const encryptPrivateKey = bufferUtils.bytesToHex(
await encryptAsync({ password, data: p }),
);
privateKeys[account.path] = encryptPrivateKey;
privateKeys[''] = encryptPrivateKey;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/chains/lightning/sdkLightning/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const generateNativeSegwitAccounts = async ({
(index) => `${index.toString()}'`, // btc
);

const pubkeyInfos = batchGetPublicKeys(
const pubkeyInfos = await batchGetPublicKeys(
curve,
hdCredential,
password,
Expand Down
49 changes: 25 additions & 24 deletions packages/core/src/secret/__tests__/secret-aes256.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,12 @@ describe('AES256 Encryption Tests', () => {
expect(decrypted.toString()).toBe(TEST_DATA);
});

it('should throw on incorrect password', () => {
it('should throw on incorrect password', async () => {
const encrypted = encrypt(TEST_PASSWORD, TEST_DATA_HEX);
expect(() =>
decrypt(encodePassword({ password: 'wrong-password' }), encrypted),
).toThrow();
const encodedPassword = await encodePassword({
password: 'wrong-password',
});
expect(() => decrypt(encodedPassword, encrypted)).toThrow();
});

it('should throw on empty password', () => {
Expand Down Expand Up @@ -214,8 +215,8 @@ describe('AES256 Encryption Tests', () => {
});

describe('encodePassword/decodePassword', () => {
it('should encode and decode password with snapshot', () => {
const encoded = encodePassword({
it('should encode and decode password with snapshot', async () => {
const encoded = await encodePassword({
password: TEST_PASSWORD,
key: 'test-key',
});
Expand All @@ -228,8 +229,8 @@ describe('AES256 Encryption Tests', () => {
expect(decoded).toBe(TEST_PASSWORD);
});

it('should throw on incorrect key', () => {
const encoded = encodePassword({
it('should throw on incorrect key', async () => {
const encoded = await encodePassword({
password: TEST_PASSWORD,
key: 'test-key',
});
Expand All @@ -242,15 +243,15 @@ describe('AES256 Encryption Tests', () => {
});

// TODO empty key should throw
it.skip('should throw on empty key', () => {
expect(() =>
it.skip('should throw on empty key', async () => {
await expect(
encodePassword({
password: TEST_PASSWORD,
key: '',
}),
).toThrow();
).rejects.toThrow();

const encoded = encodePassword({
const encoded = await encodePassword({
password: TEST_PASSWORD,
key: 'test-key',
});
Expand All @@ -264,8 +265,8 @@ describe('AES256 Encryption Tests', () => {
});

describe('encodeSensitiveText/decodeSensitiveText', () => {
it('should encode and decode sensitive text with snapshot', () => {
const encoded = encodeSensitiveText({
it('should encode and decode sensitive text with snapshot', async () => {
const encoded = await encodeSensitiveText({
text: TEST_DATA,
key: 'test-key',
});
Expand All @@ -278,8 +279,8 @@ describe('AES256 Encryption Tests', () => {
expect(decoded).toBe(TEST_DATA);
});

it('should throw on incorrect key', () => {
const encoded = encodeSensitiveText({
it('should throw on incorrect key', async () => {
const encoded = await encodeSensitiveText({
text: TEST_DATA,
key: 'test-key',
});
Expand All @@ -292,15 +293,15 @@ describe('AES256 Encryption Tests', () => {
});

// TODO empty key should throw
it.skip('should throw on empty key', () => {
it.skip('should throw on empty key', async () => {
expect(() =>
encodeSensitiveText({
text: TEST_DATA,
key: '',
}),
).toThrow();

const encoded = encodeSensitiveText({
const encoded = await encodeSensitiveText({
text: TEST_DATA,
key: 'test-key',
});
Expand Down Expand Up @@ -375,17 +376,17 @@ describe('AES256 Encryption Tests', () => {
});

describe('isEncodedSensitiveText and ensureSensitiveTextEncoded', () => {
it('should correctly identify encoded sensitive text', () => {
const encoded = encodeSensitiveText({
it('should correctly identify encoded sensitive text', async () => {
const encoded = await encodeSensitiveText({
text: TEST_DATA,
key: 'test-key',
});
expect(isEncodedSensitiveText(encoded)).toBe(true);
expect(isEncodedSensitiveText('not-encoded-text')).toBe(false);
});

it('should handle both aes and xor prefixes', () => {
const aesEncoded = encodeSensitiveText({
it('should handle both aes and xor prefixes', async () => {
const aesEncoded = await encodeSensitiveText({
text: TEST_DATA,
key: 'test-key',
});
Expand All @@ -404,8 +405,8 @@ describe('AES256 Encryption Tests', () => {
);
});

it('should not throw for valid encoded text in ensureSensitiveTextEncoded', () => {
const encoded = encodeSensitiveText({
it('should not throw for valid encoded text in ensureSensitiveTextEncoded', async () => {
const encoded = await encodeSensitiveText({
text: TEST_DATA,
key: 'test-key',
});
Expand Down
Loading

0 comments on commit bb104ae

Please sign in to comment.