From 2860c733d446d444a1121e3e32ec0bf389973006 Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Thu, 14 May 2026 12:19:26 -0700 Subject: [PATCH] Perform validation in exported function and use it to call private ckd. --- src/lib/crypto/bip44.ts | 33 +++++++++++++++++++++++++-------- src/lib/vault/vault-worker.ts | 4 ++-- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/lib/crypto/bip44.ts b/src/lib/crypto/bip44.ts index aea3ad8..135bae7 100644 --- a/src/lib/crypto/bip44.ts +++ b/src/lib/crypto/bip44.ts @@ -3,14 +3,12 @@ import { Point, getPublicKey as secp256k1_getPublicKey } from '@noble/secp256k1' +type Curve = 'Bitcoin seed' | 'ed25519 seed' type ExtendedKey = { privateKey: ArrayBuffer chainCode: ArrayBuffer publicKey?: ArrayBuffer } - -type Curve = 'Bitcoin seed' | 'ed25519 seed' - const BIP44_PURPOSE: 44 = 44 const HARDENED_OFFSET: 0x80000000 = 0x80000000 @@ -27,25 +25,45 @@ const HARDENED_OFFSET: 0x80000000 = 0x80000000 * @param {number} [address] - Sequentially increasing index of addresses to use for each account * @returns {Promise} Private child key for the account */ -export function ckd (curve: Curve, seed: ArrayBuffer, coin: number, account: number, change?: number, address?: number): Promise { +export function Bip44 (curve: Curve, seed: ArrayBuffer, coin: number, account: number, change?: number, address?: number): Promise +export function Bip44 (curve: unknown, seed: unknown, coin: unknown, account: unknown, change?: unknown, address?: unknown): Promise { if (curve !== 'Bitcoin seed' && curve !== 'ed25519 seed') { throw new TypeError(`Unsupported curve ${curve}`) } + if (!(seed instanceof ArrayBuffer)) { + throw new RangeError(`Invalid seed buffer ${seed}`) + } if (seed.byteLength < 16 || seed.byteLength > 64) { throw new RangeError(`Invalid seed byte length ${seed.byteLength}`) } + if (typeof coin !== 'number') { + throw new RangeError(`Invalid coin ${coin}`) + } if (!Number.isSafeInteger(coin) || coin < 0 || coin > 0x7fffffff) { throw new RangeError(`Invalid coin 0x${coin.toString(16)}`) } + if (typeof account !== 'number') { + throw new RangeError(`Invalid account index ${account}`) + } if (!Number.isSafeInteger(account) || account < 0 || account > 0x7fffffff) { throw new RangeError(`Invalid account index 0x${account.toString(16)}`) } + if (change !== undefined && typeof change !== 'number') { + throw new RangeError(`Invalid change index ${change}`) + } if (change !== undefined && (!Number.isSafeInteger(change) || change < 0 || change > 1)) { throw new RangeError(`Invalid change index 0x${account.toString(16)}`) } + if (address !== undefined && typeof address !== 'number') { + throw new RangeError(`Invalid address index ${address}`) + } if (address !== undefined && (!Number.isSafeInteger(address) || address < 0 || address > 0x7fffffff)) { throw new RangeError(`Invalid address index 0x${account.toString(16)}`) } + return ckd(curve, seed, coin, account, change, address) +} + +function ckd (curve: Curve, seed: ArrayBuffer, coin: number, account: number, change?: number, address?: number): Promise { return slip10(curve, seed) .then(masterKey => CKDpriv(curve, masterKey, BIP44_PURPOSE + HARDENED_OFFSET)) .then(purposeKey => CKDpriv(curve, purposeKey, coin + HARDENED_OFFSET)) @@ -128,8 +146,7 @@ function parse256 (integer: Uint8Array): bigint { } function hmac (key: Uint8Array, data: Uint8Array): Promise { - return crypto.subtle.importKey('raw', key, { name: 'HMAC', hash: 'SHA-512' }, false, ['sign']) - .then(pk => { - return crypto.subtle.sign('HMAC', pk, data) - }) + return crypto.subtle + .importKey('raw', key, { name: 'HMAC', hash: 'SHA-512' }, false, ['sign']) + .then(pk => crypto.subtle.sign('HMAC', pk, data)) } diff --git a/src/lib/vault/vault-worker.ts b/src/lib/vault/vault-worker.ts index 4ff5e96..4028cf4 100644 --- a/src/lib/vault/vault-worker.ts +++ b/src/lib/vault/vault-worker.ts @@ -387,10 +387,10 @@ function _ckd (index: number): Promise { } switch (_type) { case ('BIP-44'): { - return Bip44.ckd('ed25519 seed', _seed, BIP44_COIN_NANO, index) + return Bip44('ed25519 seed', _seed, BIP44_COIN_NANO, index) } case ('Exodus'): { - return Bip44.ckd('Bitcoin seed', _seed, 0x100, index, 0, 0) + return Bip44('Bitcoin seed', _seed, 0x100, index, 0, 0) } default: { return Blake2b.ckd(_seed, index) -- 2.47.3