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 { getCryptoBackend } from './backend';
|
||||||
import type { KeyPair } from './backend';
|
import type { KeyPair } from './backend';
|
||||||
|
|
||||||
@@ -23,24 +21,25 @@ export async function generateUserKeyPair(): Promise<KeyPair> {
|
|||||||
return getCryptoBackend().generateKeyPair();
|
return getCryptoBackend().generateKeyPair();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deriveKek(pin: string, salt: Uint8Array, params: KdfParams): Promise<Uint8Array> {
|
function deriveKek(pin: string, salt: Uint8Array, params: KdfParams): Uint8Array {
|
||||||
await sodium.ready;
|
const backend = getCryptoBackend();
|
||||||
return sodium.crypto_pwhash(
|
return backend.pwhash(
|
||||||
sodium.crypto_secretbox_KEYBYTES,
|
backend.secretboxKeyLength,
|
||||||
pin,
|
pin,
|
||||||
salt,
|
salt,
|
||||||
params.opslimit,
|
params.opslimit,
|
||||||
params.memlimit,
|
params.memlimit,
|
||||||
sodium.crypto_pwhash_ALG_ARGON2ID13,
|
backend.pwhashConsts.ALG_ARGON2ID13,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function defaultKdfParams(): KdfParams {
|
function defaultKdfParams(): KdfParams {
|
||||||
|
const backend = getCryptoBackend();
|
||||||
return {
|
return {
|
||||||
algo: 'argon2id',
|
algo: 'argon2id',
|
||||||
preset: KDF_PRESET,
|
preset: KDF_PRESET,
|
||||||
opslimit: sodium.crypto_pwhash_OPSLIMIT_MODERATE,
|
opslimit: backend.pwhashConsts.OPSLIMIT_MODERATE,
|
||||||
memlimit: sodium.crypto_pwhash_MEMLIMIT_MODERATE,
|
memlimit: backend.pwhashConsts.MEMLIMIT_MODERATE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,19 +49,16 @@ export async function sealUserKey(opts: {
|
|||||||
salt?: Uint8Array;
|
salt?: Uint8Array;
|
||||||
kdfParams?: KdfParams;
|
kdfParams?: KdfParams;
|
||||||
}): Promise<SealedUserKey> {
|
}): Promise<SealedUserKey> {
|
||||||
await sodium.ready;
|
|
||||||
const backend = getCryptoBackend();
|
const backend = getCryptoBackend();
|
||||||
const salt = opts.salt ?? backend.randomBytes(SALT_LEN);
|
const salt = opts.salt ?? backend.randomBytes(SALT_LEN);
|
||||||
const kdfParams = opts.kdfParams ?? defaultKdfParams();
|
const kdfParams = opts.kdfParams ?? defaultKdfParams();
|
||||||
const kek = await deriveKek(opts.pin, salt, kdfParams);
|
const kek = deriveKek(opts.pin, salt, kdfParams);
|
||||||
try {
|
const nonce = backend.randomBytes(backend.secretboxNonceLength);
|
||||||
const nonce = backend.randomBytes(backend.secretboxNonceLength);
|
const cipher = backend.secretbox(opts.privateKey, nonce, kek);
|
||||||
const cipher = backend.secretbox(opts.privateKey, nonce, kek);
|
const sealedPrivateKey = new Uint8Array(nonce.length + cipher.length);
|
||||||
const sealedPrivateKey = new Uint8Array(nonce.length + cipher.length);
|
sealedPrivateKey.set(nonce, 0);
|
||||||
sealedPrivateKey.set(nonce, 0);
|
sealedPrivateKey.set(cipher, nonce.length);
|
||||||
sealedPrivateKey.set(cipher, nonce.length);
|
return { sealedPrivateKey, salt, kdfParams };
|
||||||
return { sealedPrivateKey, salt, kdfParams };
|
|
||||||
} finally { sodium.memzero(kek); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function openUserKey(opts: {
|
export async function openUserKey(opts: {
|
||||||
@@ -71,12 +67,11 @@ export async function openUserKey(opts: {
|
|||||||
salt: Uint8Array;
|
salt: Uint8Array;
|
||||||
kdfParams: KdfParams;
|
kdfParams: KdfParams;
|
||||||
}): Promise<Uint8Array> {
|
}): Promise<Uint8Array> {
|
||||||
await sodium.ready;
|
|
||||||
const backend = getCryptoBackend();
|
const backend = getCryptoBackend();
|
||||||
const nonceLen = backend.secretboxNonceLength;
|
const nonceLen = backend.secretboxNonceLength;
|
||||||
if (opts.sealed.length <= nonceLen) throw new Error('sealed user key blob too short');
|
if (opts.sealed.length <= nonceLen) throw new Error('sealed user key blob too short');
|
||||||
const nonce = opts.sealed.slice(0, nonceLen);
|
const nonce = opts.sealed.slice(0, nonceLen);
|
||||||
const cipher = opts.sealed.slice(nonceLen);
|
const cipher = opts.sealed.slice(nonceLen);
|
||||||
const kek = await deriveKek(opts.pin, opts.salt, opts.kdfParams);
|
const kek = deriveKek(opts.pin, opts.salt, opts.kdfParams);
|
||||||
try { return backend.secretboxOpen(cipher, nonce, kek); } finally { sodium.memzero(kek); }
|
return backend.secretboxOpen(cipher, nonce, kek);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user