From: Chris Duncan Date: Fri, 8 Aug 2025 21:22:54 +0000 (-0700) Subject: Set safe seed and mnemonic directly from decryption method instead of returning.... X-Git-Tag: v0.10.5~41^2~163 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=3a41fb3235a0ff38cbb9683b6ee0ce435c188e98;p=libnemo.git Set safe seed and mnemonic directly from decryption method instead of returning. Encode and decode bytes explicitly to avoid string handling. --- diff --git a/src/lib/safe.ts b/src/lib/safe.ts index 6aecb1e..08e6ceb 100644 --- a/src/lib/safe.ts +++ b/src/lib/safe.ts @@ -223,15 +223,13 @@ export class Safe { if (encrypted == null) { throw new TypeError('Wallet encrypted data is required') } - const { seed, mnemonic } = await this.#decryptWallet(type, key, iv, encrypted) - if (!(seed instanceof ArrayBuffer)) { + await this.#decryptWallet(type, key, iv, encrypted) + if (!(this.#seed instanceof ArrayBuffer)) { throw new TypeError('Invalid seed') } - if (mnemonic != null && typeof mnemonic !== 'string') { + if (this.#mnemonic != null && typeof this.#mnemonic !== 'string') { throw new TypeError('Invalid seed') } - this.#seed = seed - if (mnemonic != null) this.#mnemonic = (await Bip39.fromPhrase(mnemonic)).phrase this.#locked = false return { isUnlocked: !this.#locked } } catch (err) { @@ -315,22 +313,13 @@ export class Safe { return await crypto.subtle.deriveKey(derivationAlgorithm, derivationKey, derivedKeyType, false, [purpose]) } - static async #decryptWallet (type: string, key: CryptoKey, iv: ArrayBuffer, encrypted: ArrayBuffer): Promise> { - let decrypted, decoded, parsed - + static async #decryptWallet (type: string, key: CryptoKey, iv: ArrayBuffer, encrypted: ArrayBuffer): Promise { + const seedLength = type === 'BIP-44' ? 64 : 32 const additionalData = utf8.toBytes(type) - decrypted = new Uint8Array(await crypto.subtle.decrypt({ name: 'AES-GCM', iv, additionalData }, key, encrypted)) - decoded = bytes.toUtf8(decrypted) - bytes.erase(decrypted) - decrypted = undefined - - parsed = JSON.parse(decoded) - decoded = undefined - - const seed = hex.toBuffer(parsed.seed) - const mnemonic = parsed.mnemonic - parsed = parsed.seed = parsed.mnemonic = undefined - return { seed, mnemonic } + const decrypted = new Uint8Array(await crypto.subtle.decrypt({ name: 'AES-GCM', iv, additionalData }, key, encrypted)) + this.#seed = decrypted.buffer.slice(0, seedLength) + this.#mnemonic = bytes.toUtf8(decrypted.slice(seedLength)) + decrypted.fill(0) } /** @@ -361,15 +350,12 @@ export class Safe { if (this.#seed == null) { throw new Error('Wallet seed not found') } - const data: NamedData = { - seed: bytes.toHex(new Uint8Array(this.#seed)) - } - if (this.#mnemonic != null) data.mnemonic = this.#mnemonic - + const seed = new Uint8Array(this.#seed) + const mnemonic = utf8.toBytes(this.#mnemonic ?? '') // restrict iv to 96 bits per GCM best practice const iv = crypto.getRandomValues(new Uint8Array(12)).buffer const additionalData = utf8.toBytes(this.#type) - const encoded = utf8.toBytes(JSON.stringify(data)) + const encoded = new Uint8Array([...seed, ...mnemonic]) const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv, additionalData }, key, encoded) return { iv, encrypted } }