refactor(shared): route userKey through CryptoBackend (no libsodium-wrappers-sumo)
This commit is contained in:
@@ -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<KeyPair> {
|
||||
return getCryptoBackend().generateKeyPair();
|
||||
}
|
||||
|
||||
async function deriveKek(pin: string, salt: Uint8Array, params: KdfParams): Promise<Uint8Array> {
|
||||
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<SealedUserKey> {
|
||||
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 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 };
|
||||
} finally { sodium.memzero(kek); }
|
||||
}
|
||||
|
||||
export async function openUserKey(opts: {
|
||||
@@ -71,12 +67,11 @@ export async function openUserKey(opts: {
|
||||
salt: Uint8Array;
|
||||
kdfParams: KdfParams;
|
||||
}): Promise<Uint8Array> {
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user