cleaner flow around the .toV3 KDF parameters

This commit is contained in:
Jack Cook 2019-07-16 20:32:06 -07:00
parent 288442924e
commit 807b98003d

View File

@ -52,7 +52,12 @@ function mergeToV3ParamsWithDefaults(params?: Partial<V3Params>): V3Params {
} }
} }
// KDF params // KDF
const enum KDFFunctions {
PBKDF = 'pbkdf2',
Scrypt = 'scrypt',
}
interface ScryptKDFParams { interface ScryptKDFParams {
dklen: number dklen: number
@ -69,48 +74,24 @@ interface PBKDFParams {
salt: string salt: string
} }
// union of both the PBKDF2 and Scrypt KDF parameters representing all possible
// parameters the user could supply
type AllKDFParams = ScryptKDFParams & PBKDFParams
type KDFParams = ScryptKDFParams | PBKDFParams type KDFParams = ScryptKDFParams | PBKDFParams
function kdfParamsForPBKDF(params: AllKDFParams): PBKDFParams { function kdfParamsForPBKDF(opts: V3Params): PBKDFParams {
delete params.n
delete params.p
delete params.r
return params
}
function kdfParamsForScrypt(params: AllKDFParams): ScryptKDFParams {
delete params.c
delete params.prf
return params
}
/**
* Based on the parameter list passed to the Wallet.prototype.toV3() method this
* returns a list of parameters for running the key derivation function.
* @param params params passed into the .toV3() method
*/
function mergeKDFParamsWithDefaults(params: V3Params): AllKDFParams {
const kdfDefaults = {
c: 262144,
prf: 'hmac-sha256',
n: 262144,
r: 8,
p: 1,
salt: params.salt.toString('hex'),
}
return { return {
dklen: params.dklen, dklen: opts.dklen,
salt: kdfDefaults.salt, salt: opts.salt.toString('hex'),
c: params.c || kdfDefaults.c, c: opts.c,
prf: kdfDefaults.prf, prf: 'hmac-sha256',
n: params.n || kdfDefaults.n, }
r: params.r || kdfDefaults.r, }
p: params.p || kdfDefaults.p,
function kdfParamsForScrypt(opts: V3Params): ScryptKDFParams {
return {
dklen: opts.dklen,
salt: opts.salt.toString('hex'),
n: opts.n,
r: opts.r,
p: opts.p,
} }
} }
@ -413,40 +394,41 @@ export default class Wallet {
throw new Error('This is a public key only wallet') throw new Error('This is a public key only wallet')
} }
const params = mergeToV3ParamsWithDefaults(opts) const v3Params: V3Params = mergeToV3ParamsWithDefaults(opts)
const kdfParams = mergeKDFParamsWithDefaults(params)
let kdfParams: PBKDFParams | ScryptKDFParams
let derivedKey: Buffer let derivedKey: Buffer
let finalKDFParams: KDFParams switch (v3Params.kdf) {
case KDFFunctions.PBKDF:
if (params.kdf === 'pbkdf2') { kdfParams = kdfParamsForPBKDF(v3Params)
derivedKey = crypto.pbkdf2Sync( derivedKey = crypto.pbkdf2Sync(
Buffer.from(password), Buffer.from(password),
params.salt, v3Params.salt,
kdfParams.c, kdfParams.c,
kdfParams.dklen, kdfParams.dklen,
'sha256', 'sha256',
) )
finalKDFParams = kdfParamsForPBKDF(kdfParams) break
} else if (params.kdf === 'scrypt') { case KDFFunctions.Scrypt:
// FIXME: support progress reporting callback kdfParams = kdfParamsForScrypt(v3Params)
derivedKey = scryptsy( // FIXME: support progress reporting callback
Buffer.from(password), derivedKey = scryptsy(
params.salt, Buffer.from(password),
kdfParams.n, v3Params.salt,
kdfParams.r, kdfParams.n,
kdfParams.p, kdfParams.r,
kdfParams.dklen, kdfParams.p,
) kdfParams.dklen,
finalKDFParams = kdfParamsForScrypt(kdfParams) )
} else { break
throw new Error('Unsupported kdf') default:
throw new Error('Unsupported kdf')
} }
const cipher: crypto.Cipher = crypto.createCipheriv( const cipher: crypto.Cipher = crypto.createCipheriv(
params.cipher, v3Params.cipher,
derivedKey.slice(0, 16), derivedKey.slice(0, 16),
params.iv, v3Params.iv,
) )
if (!cipher) { if (!cipher) {
throw new Error('Unsupported cipher') throw new Error('Unsupported cipher')
@ -459,15 +441,15 @@ export default class Wallet {
return { return {
version: 3, version: 3,
id: uuidv4({ random: params.uuid }), id: uuidv4({ random: v3Params.uuid }),
// @ts-ignore FIXME: official V3 keystore spec omits the address key // @ts-ignore - the official V3 keystore spec omits the address key
address: this.getAddress().toString('hex'), address: this.getAddress().toString('hex'),
crypto: { crypto: {
ciphertext: ciphertext.toString('hex'), ciphertext: ciphertext.toString('hex'),
cipherparams: { iv: params.iv.toString('hex') }, cipherparams: { iv: v3Params.iv.toString('hex') },
cipher: params.cipher, cipher: v3Params.cipher,
kdf: params.kdf, kdf: v3Params.kdf,
kdfparams: finalKDFParams, kdfparams: kdfParams,
mac: mac.toString('hex'), mac: mac.toString('hex'),
}, },
} }