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

Fix/secret encrypt async #6407

Draft
wants to merge 21 commits into
base: x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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
2 changes: 1 addition & 1 deletion packages/core/src/secret/bip32.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function serNum(p: BigNumber, bits: 32 | 256): Buffer {
}

function ser32(index: number): Buffer {
if (!Number.isInteger(index)) {
if (typeof index !== 'number' || !Number.isInteger(index) || index < 0) {
throw Error('Invalid index.');
}

Expand Down
135 changes: 135 additions & 0 deletions packages/core/src/secret/encryptors/__tests__/aes256.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import {
decrypt,
decryptString,
encrypt,
encryptAsync,
encryptString,
encryptStringAsync,
} from '../aes256';

/* run test ==============================

yarn jest packages/core/src/secret/encryptors/__tests__/aes256.test.ts

*/

describe('aes256', () => {
const testPassword = 'testPassword123';
const testData = 'Hello, World!';
const testBuffer = Buffer.from(testData);

describe('encrypt/decrypt', () => {
it('should encrypt and decrypt data correctly using sync methods', () => {
const encrypted = encrypt(testPassword, testBuffer, true);
const decrypted = decrypt(testPassword, encrypted, false, true);
expect(decrypted.toString()).toBe(testData);
});

it('should encrypt and decrypt data correctly using async methods', async () => {
const encrypted = await encryptAsync({
password: testPassword,
data: testBuffer,
});
const decrypted = decrypt(testPassword, encrypted, false, true);
expect(decrypted.toString()).toBe(testData);
});

it('should produce different ciphertexts for same input', async () => {
const encrypted1 = await encryptAsync({
password: testPassword,
data: testBuffer,
});
const encrypted2 = await encryptAsync({
password: testPassword,
data: testBuffer,
});
expect(encrypted1.toString('hex')).not.toBe(encrypted2.toString('hex'));
});
});

describe('encryptString/decryptString', () => {
it('should encrypt and decrypt strings correctly using sync methods', () => {
const encrypted = encryptString({
password: testPassword,
data: testData,
dataEncoding: 'utf8',
allowRawPassword: true,
});
console.log('encrypted', encrypted);
const decrypted = decryptString({
password: testPassword,
data: encrypted,
dataEncoding: 'hex',
resultEncoding: 'utf8',
allowRawPassword: true,
});
expect(decrypted).toBe(testData);
});

it('should encrypt and decrypt strings correctly using async methods', async () => {
const encrypted = await encryptStringAsync({
password: testPassword,
data: testData,
dataEncoding: 'utf8',
allowRawPassword: true,
});
const decrypted = decryptString({
password: testPassword,
data: encrypted,
dataEncoding: 'hex',
resultEncoding: 'utf8',
allowRawPassword: true,
});
expect(decrypted).toBe(testData);
});

it('should handle different encodings correctly', async () => {
const hexData = Buffer.from(testData).toString('hex');
const encrypted = await encryptStringAsync({
password: testPassword,
data: hexData,
dataEncoding: 'hex',
allowRawPassword: true,
});
const decrypted = decryptString({
password: testPassword,
data: encrypted,
dataEncoding: 'hex',
resultEncoding: 'hex',
allowRawPassword: true,
});
expect(Buffer.from(decrypted, 'hex').toString()).toBe(testData);
});
});

describe('deprecation warnings', () => {
const originalWarn = console.warn;
let warnMock: jest.Mock;

beforeEach(() => {
warnMock = jest.fn();
console.warn = warnMock;
});

afterEach(() => {
console.warn = originalWarn;
});

it('should show deprecation warning for sync encrypt', () => {
encrypt(testPassword, testBuffer);
expect(warnMock).toHaveBeenCalledWith(
expect.stringContaining('deprecated'),
);
});

it('should show deprecation warning for sync encryptString', () => {
encryptString({
password: testPassword,
data: testData,
});
expect(warnMock).toHaveBeenCalledWith(
expect.stringContaining('deprecated'),
);
});
});
});
Loading
Loading