diff --git a/packages/shared/src/crypto/userKey.ts b/packages/shared/src/crypto/userKey.ts index 67b3fa7..a9394a3 100644 --- a/packages/shared/src/crypto/userKey.ts +++ b/packages/shared/src/crypto/userKey.ts @@ -1,5 +1,3 @@ -import sodium from 'libsodium-wrappers-sumo'; - import { getCryptoBackend } from './backend'; import type { KeyPair } from './backend'; @@ -23,24 +21,25 @@ export async function generateUserKeyPair(): Promise { return getCryptoBackend().generateKeyPair(); } -async function deriveKek(pin: string, salt: Uint8Array, params: KdfParams): Promise { - await sodium.ready; - return sodium.crypto_pwhash( - sodium.crypto_secretbox_KEYBYTES, +function deriveKek(pin: string, salt: Uint8Array, params: KdfParams): Uint8Array { + const backend = getCryptoBackend(); + return backend.pwhash( + backend.secretboxKeyLength, pin, salt, params.opslimit, params.memlimit, - sodium.crypto_pwhash_ALG_ARGON2ID13, + backend.pwhashConsts.ALG_ARGON2ID13, ); } function defaultKdfParams(): KdfParams { + const backend = getCryptoBackend(); return { algo: 'argon2id', preset: KDF_PRESET, - opslimit: sodium.crypto_pwhash_OPSLIMIT_MODERATE, - memlimit: sodium.crypto_pwhash_MEMLIMIT_MODERATE, + opslimit: backend.pwhashConsts.OPSLIMIT_MODERATE, + memlimit: backend.pwhashConsts.MEMLIMIT_MODERATE, }; } @@ -50,19 +49,16 @@ export async function sealUserKey(opts: { salt?: Uint8Array; kdfParams?: KdfParams; }): Promise { - await sodium.ready; const backend = getCryptoBackend(); const salt = opts.salt ?? backend.randomBytes(SALT_LEN); const kdfParams = opts.kdfParams ?? defaultKdfParams(); - const kek = await deriveKek(opts.pin, salt, kdfParams); - try { - const nonce = backend.randomBytes(backend.secretboxNonceLength); - const cipher = backend.secretbox(opts.privateKey, nonce, kek); - const sealedPrivateKey = new Uint8Array(nonce.length + cipher.length); - sealedPrivateKey.set(nonce, 0); - sealedPrivateKey.set(cipher, nonce.length); - return { sealedPrivateKey, salt, kdfParams }; - } finally { sodium.memzero(kek); } + const kek = deriveKek(opts.pin, salt, kdfParams); + const nonce = backend.randomBytes(backend.secretboxNonceLength); + const cipher = backend.secretbox(opts.privateKey, nonce, kek); + const sealedPrivateKey = new Uint8Array(nonce.length + cipher.length); + sealedPrivateKey.set(nonce, 0); + sealedPrivateKey.set(cipher, nonce.length); + return { sealedPrivateKey, salt, kdfParams }; } export async function openUserKey(opts: { @@ -71,12 +67,11 @@ export async function openUserKey(opts: { salt: Uint8Array; kdfParams: KdfParams; }): Promise { - await sodium.ready; const backend = getCryptoBackend(); const nonceLen = backend.secretboxNonceLength; if (opts.sealed.length <= nonceLen) throw new Error('sealed user key blob too short'); const nonce = opts.sealed.slice(0, nonceLen); const cipher = opts.sealed.slice(nonceLen); - const kek = await deriveKek(opts.pin, opts.salt, opts.kdfParams); - try { return backend.secretboxOpen(cipher, nonce, kek); } finally { sodium.memzero(kek); } + const kek = deriveKek(opts.pin, opts.salt, opts.kdfParams); + return backend.secretboxOpen(cipher, nonce, kek); }