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

feat: add encryptStringAsync + refactor calls #6402

Closed
wants to merge 10 commits into from
Closed
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 package.json
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@
"style-loader": "^3.3.3",
"tamagui-loader": "1.108.0",
"ts-jest": "^29.1.1",
"typescript": "5.1.6",
"ultra-runner": "^3.10.5",
"webpack": "5.90.3",
"webpack-bundle-analyzer": "^4.9.1",
Expand Down
11 changes: 9 additions & 2 deletions packages/core/@tests/coreTestsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ import {
mnemonicToRevealableSeed,
} from '../src/secret';

function checkIsDefined<T>(value: T | undefined | null): T {
if (value === undefined || value === null) {
throw new Error('Expected value to be defined');
}
return value;
}

import type {
ICoreTestsAccountInfo,
ICoreTestsHdCredential,
Expand Down Expand Up @@ -170,9 +177,9 @@ async function expectGetPrivateKeysHdOk({
// c1c3e59db78da160261befeef577daa7b54cd756e48601473cfe98d012b3ccfca240a8a3e1a328ee7611ba2688f3fadf1d7c61d36c379c0ced0eec0b66ff9ecd635a8dbfcae4cce36c15c64a79d5873d1d26cbf6c90a36034f96077d66cef413
expect(encryptKey).toBeTruthy();
// 105434ca932be16664cb5e44e5b006728577dd757440d068e6d15ef52c15a82f
const privateKey = decryptString({
const privateKey = await decryptString({
password,
data: encryptKey,
data: checkIsDefined(encryptKey),
});
expect(privateKey).toEqual(account.privateKeyRaw);
}
Expand Down
27 changes: 21 additions & 6 deletions packages/core/src/base/CoreChainApiBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import {
decrypt,
decryptImportedCredential,
ed25519,
encrypt,
encrypt, // @deprecated Use encryptAsync instead
encryptAsync,
nistp256,
secp256k1,
} from '../secret';
Expand Down Expand Up @@ -109,6 +110,10 @@ export abstract class CoreChainApiBase {
});
}

/**
* @deprecated The synchronous encryption methods used in this function will be deprecated.
* Please use async encryption methods instead.
*/
protected async baseGetPrivateKeys({
payload,
curve,
Expand Down Expand Up @@ -140,7 +145,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 All @@ -150,6 +157,10 @@ export abstract class CoreChainApiBase {
return privateKeys;
}

/**
* @deprecated The synchronous encryption methods used in this function will be deprecated.
* Please use async encryption methods instead.
*/
protected async baseGetPrivateKeysHd({
curve,
password,
Expand All @@ -170,14 +181,14 @@ export abstract class CoreChainApiBase {
);
}

const keys = batchGetPrivateKeys(
const keys = await batchGetPrivateKeys(
curve,
hdCredential,
password,
basePath,
usedRelativePaths,
);
const map: ICoreApiPrivateKeysMap = keys.reduce((ret, key) => {
const map: ICoreApiPrivateKeysMap = keys.reduce((ret: ICoreApiPrivateKeysMap, key: ISecretPrivateKeyInfo) => {
const result: ICoreApiPrivateKeysMap = {
...ret,
[key.path]: bufferUtils.bytesToHex(key.extendedKey.key),
Expand All @@ -187,6 +198,10 @@ export abstract class CoreChainApiBase {
return map;
}

/**
* @deprecated The synchronous encryption methods used in this function will be deprecated.
* Please use async encryption methods instead.
*/
protected async baseGetAddressesFromHd(
query: ICoreApiGetAddressesQueryHd,
options: {
Expand All @@ -205,7 +220,7 @@ export abstract class CoreChainApiBase {
let pvtkeyInfos: ISecretPrivateKeyInfo[] = [];

if (isPrivateKeyMode) {
pvtkeyInfos = batchGetPrivateKeys(
pvtkeyInfos = await batchGetPrivateKeys(
curve,
hdCredential,
password,
Expand Down Expand Up @@ -235,7 +250,7 @@ export abstract class CoreChainApiBase {
let result: ICoreApiGetAddressItem | undefined;

if (isPrivateKeyMode) {
const privateKeyRaw = bufferUtils.bytesToHex(decrypt(password, key));
const privateKeyRaw = bufferUtils.bytesToHex(await decrypt(password, key));
result = await this.getAddressFromPrivate({
networkInfo: query.networkInfo,
privateKeyRaw,
Expand Down
6 changes: 3 additions & 3 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, encrypt, encryptAsync } from '../../secret';
import {
ECoreApiExportedSecretKeyType,
type ICoreApiGetAddressItem,
Expand Down Expand Up @@ -53,7 +53,7 @@ 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 Expand Up @@ -280,7 +280,7 @@ export default class CoreChainSoftware extends CoreChainApiBase {
);
}
if (credentials.imported) {
const privateKey = decrypt(password, privateKeyRaw);
const privateKey = await decrypt(password, privateKeyRaw);
return generateXprvFromPrivateKey(privateKey);
}
}
Expand Down
63 changes: 33 additions & 30 deletions packages/core/src/chains/btc/CoreChainSoftware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
batchGetPublicKeysAsync,
decrypt,
encrypt,
encryptAsync,
mnemonicFromEntropyAsync,
mnemonicToSeedAsync,
secp256k1,
Expand Down Expand Up @@ -247,15 +248,15 @@ export default class CoreChainSoftwareBtc extends CoreChainApiBase {
.fill(
Buffer.concat([
Buffer.from([0]),
decrypt(password, privateKeyRaw),
await decrypt(password, privateKeyRaw),
]),
45,
78,
),
);
}
if (credentials.imported) {
return bs58check.encode(decrypt(password, privateKeyRaw));
return bs58check.encode(await decrypt(password, privateKeyRaw));
}
}
throw new Error(`SecretKey type not support: ${keyType}`);
Expand Down Expand Up @@ -433,55 +434,57 @@ 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,
) as IBip32KeyDeriver;

// imported account return "" key as root privateKey
const privateKey = privateKeys[''];
const xprv = decrypt(password, bufferUtils.toBuffer(privateKey));
const xprv = await decrypt(password, bufferUtils.toBuffer(privateKey));
const startKey = {
chainCode: xprv.slice(13, 45),
key: xprv.slice(46, 78),
};

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

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

let currentPath = '';
let parent = startKey;
pathComponents.forEach((pathComponent) => {
currentPath =
currentPath.length > 0
? `${currentPath}/${pathComponent}`
: pathComponent;
if (typeof cache[currentPath] === 'undefined') {
const index = pathComponent.endsWith("'")
? parseInt(pathComponent.slice(0, -1), 10) + 2 ** 31
: parseInt(pathComponent, 10);
const thisPrivKey = deriver.CKDPriv(parent, index);
cache[currentPath] = thisPrivKey;
}
parent = cache[currentPath];
});
await Promise.all(
relPaths?.map(async (relPath) => {
const pathComponents = relPath.split('/');

let currentPath = '';
let parent = startKey;
pathComponents.forEach((pathComponent) => {
currentPath =
currentPath.length > 0
? `${currentPath}/${pathComponent}`
: pathComponent;
if (typeof cache[currentPath] === 'undefined') {
const index = pathComponent.endsWith("'")
? parseInt(pathComponent.slice(0, -1), 10) + 2 ** 31
: parseInt(pathComponent, 10);
const thisPrivKey = deriver.CKDPriv(parent, index);
cache[currentPath] = thisPrivKey;
}
parent = cache[currentPath];
});

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

Expand Down Expand Up @@ -703,7 +706,7 @@ export default class CoreChainSoftwareBtc extends CoreChainApiBase {
curve: curveName,
});
if (isImported) {
this.appendImportedRelPathPrivateKeys({
await this.appendImportedRelPathPrivateKeys({
privateKeys,
password,
relPaths,
Expand Down
69 changes: 45 additions & 24 deletions packages/core/src/chains/dot/CoreChainSoftware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
decrypt,
decryptImportedCredential,
encrypt,
encryptAsync,
mnemonicFromEntropy,
} from '../../secret';
import {
Expand Down Expand Up @@ -78,7 +79,7 @@ export default class CoreChainSoftware extends CoreChainApiBase {
throw new Error('privateKeyRaw is required');
}
if (keyType === ECoreApiExportedSecretKeyType.privateKey) {
return `0x${decrypt(password, privateKeyRaw).toString('hex')}`;
return `0x${(await decrypt(password, privateKeyRaw)).toString('hex')}`;
}
throw new Error(`SecretKey type not support: ${keyType}`);
}
Expand All @@ -90,39 +91,59 @@ export default class CoreChainSoftware extends CoreChainApiBase {
}): Promise<ICoreApiPrivateKeysMap> {
const { credentials, account, password, relPaths } = payload;
let privateKeys: ICoreApiPrivateKeysMap = {};
if (credentials.hd) {
const pathComponents = account.path.split('/');
const usedRelativePaths = relPaths || [pathComponents.pop() as string];
const basePath = pathComponents.join('/');
const mnemonic = mnemonicFromEntropy(credentials.hd, password);
const keys = usedRelativePaths.map((relPath) => {
const path = `${basePath}/${relPath}`;

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

privateKeys = keys.reduce(
try {
if (credentials.hd) {
const pathComponents = account.path.split('/');
const usedRelativePaths = relPaths || [pathComponents.pop() as string];
const basePath = pathComponents.join('/');
const mnemonic = mnemonicFromEntropy(credentials.hd, password);
const keys = await Promise.all(usedRelativePaths.map(async (relPath) => {
const path = `${basePath}/${relPath}`;
try {
const keyPair = derivationHdLedger(mnemonic, path);
const encryptedKey = await encryptAsync({
password,
data: Buffer.from(keyPair.secretKey.slice(0, 32))
});
return {
path,
key: encryptedKey,
};
} catch (error) {
console.error(`Failed to process key for path ${path}:`, error);
throw error;
}
}));

privateKeys = keys.reduce(
(ret, key) => ({ ...ret, [key.path]: bufferUtils.bytesToHex(key.key) }),
{},
);
}
if (credentials.imported) {
const { privateKey: p } = decryptImportedCredential({
password,
credential: credentials.imported,
});
const encryptPrivateKey = bufferUtils.bytesToHex(encrypt(password, p));
privateKeys[account.path] = encryptPrivateKey;
privateKeys[''] = encryptPrivateKey;
try {
const { privateKey: p } = decryptImportedCredential({
password,
credential: credentials.imported,
});
const encryptPrivateKey = bufferUtils.bytesToHex(
await encryptAsync({ password, data: p })
);
privateKeys[account.path] = encryptPrivateKey;
privateKeys[''] = encryptPrivateKey;
} catch (error) {
console.error('Failed to process imported credentials:', error);
throw error;
}
}
if (!Object.keys(privateKeys).length) {
throw new Error('No private keys found');
}
return privateKeys;
} catch (error) {
console.error('Error in baseGetPrivateKeys:', error);
throw error;
}
}

override async getPrivateKeys(
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
Loading
Loading