X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fmystery-box.js;fp=lib%2Fmystery-box.js;h=05fe28f72c872ac80b0604af4d15bbe8f52e069f;hb=b3d316d4fa45a66db0dd7b08a34e79eb97898180;hp=2fb68a583e2c9b2408e37f7d17dcde212bb9a481;hpb=75c98d382607b7d6bcfba9f97cc9edabb6f0395b;p=squeep-mystery-box diff --git a/lib/mystery-box.js b/lib/mystery-box.js index 2fb68a5..05fe28f 100644 --- a/lib/mystery-box.js +++ b/lib/mystery-box.js @@ -77,8 +77,13 @@ class MysteryBox { // Filter any unavailable algorithms const availableCiphers = crypto.getCiphers(); + const availableHashes = crypto.getHashes(); + // Add legacy scrypt to available hashes for filtering key derivations + availableHashes.push('scrypt'); this.versionParameters = Object.entries(allVersions).reduce((acc, [v, p]) => { - if (availableCiphers.includes(p.algorithm)) { + const validCipher = availableCiphers.includes(p.algorithm); + const validKeyDeriver = availableHashes.includes(p.keyDeriver); + if (validCipher && validKeyDeriver) { acc[v] = p; // eslint-disable-line security/detect-object-injection } return acc; @@ -109,6 +114,38 @@ class MysteryBox { } + /** + * Generate key data. + */ + static async _keyFromSecret(deriver, secret, salt, keyBytes) { + switch (deriver) { + case 'shake256': { + const hash = crypto.createHash('shake256', { outputLength: keyBytes }); + hash.update(salt); + hash.update(secret); + return hash.digest(); + } + + case 'blake2b512': { + const hash = crypto.createHash('blake2b512'); + hash.update(salt); + hash.update(secret); + const digest = hash.digest(); + // should assert that keyBytes <= 64 + // but not concerned about that for now + // until we have a new algorithm with bigger key size + return digest.subarray(0, keyBytes); + } + + case 'scrypt': + return scryptAsync(secret, salt, keyBytes); + + default: + throw new RangeError('unsupported key deriver'); + } + } + + /** * Put contents into a mysterious box. * @param {Object|Buffer} contents @@ -177,7 +214,7 @@ class MysteryBox { // Always encrypt with first secret const secret = this.secrets[0]; - const key = await scryptAsync(secret, salt, v.keyBytes); + const key = await MysteryBox._keyFromSecret(v.keyDeriver, secret, salt, v.keyBytes); const cipher = crypto.createCipheriv(v.algorithm, key, iv, v.algOptions); cipher.setAAD(aadBuffer); const encrypted = cipher.update(payload); @@ -254,7 +291,7 @@ class MysteryBox { let err; let success = false; for await (const secret of this.secrets) { - const key = await scryptAsync(secret, salt, v.keyBytes); + const key = await MysteryBox._keyFromSecret(v.keyDeriver, secret, salt, v.keyBytes); const decipher = crypto.createDecipheriv(v.algorithm, key, iv, v.algOptions); decipher.setAAD(aad); decipher.setAuthTag(tag);