UNPKG

2.2 kBJavaScriptView Raw
1'use strict'
2const assert = require('assert')
3const { randomBytes, timingSafeEqual } = require('crypto')
4const { promisify } = require('util')
5
6const binary = require('node-pre-gyp')
7const path = require('path')
8const bindingPath = binary.find(path.resolve(path.join(__dirname, './package.json')))
9const { hash: _hash, limits, types, names, version } = require(bindingPath) /* eslint-disable-line */
10
11const { deserialize, serialize } = require('@phc/format')
12
13const defaults = Object.freeze({
14 hashLength: 32,
15 saltLength: 16,
16 timeCost: 3,
17 memoryCost: 1 << 12,
18 parallelism: 1,
19 type: types.argon2i,
20 version
21})
22
23const bindingsHash = promisify(_hash)
24const generateSalt = promisify(randomBytes)
25
26const assertLimits = options => ([key, { max, min }]) => {
27 const value = options[key]
28 assert(min <= value && value <= max, `Invalid ${key}, must be between ${min} and ${max}.`)
29}
30
31const hash = async (plain, { raw, salt, ...options } = {}) => {
32 options = { ...defaults, ...options }
33
34 Object.entries(limits).forEach(assertLimits(options))
35
36 salt = salt || await generateSalt(options.saltLength)
37
38 const hash = await bindingsHash(Buffer.from(plain), salt, options)
39 if (raw) {
40 return hash
41 }
42
43 const { type, version, memoryCost: m, timeCost: t, parallelism: p, associatedData: data } = options
44 return serialize({ id: names[type], version, params: { m, t, p, ...(data ? { data } : {}) }, salt, hash })
45}
46
47const needsRehash = (digest, options) => {
48 const { memoryCost, timeCost, version } = { ...defaults, ...options }
49
50 const { version: v, params: { m, t } } = deserialize(digest)
51 return +v !== +version || +m !== +memoryCost || +t !== +timeCost
52}
53
54const verify = async (digest, plain, options) => {
55 const { id, version = 0x10, params: { m, t, p, data }, salt, hash } = deserialize(digest)
56
57 return timingSafeEqual(await bindingsHash(Buffer.from(plain), salt, {
58 ...options,
59 type: types[id],
60 version: +version,
61 hashLength: hash.length,
62 memoryCost: +m,
63 timeCost: +t,
64 parallelism: +p,
65 ...(data ? { associatedData: Buffer.from(data, 'base64') } : {})
66 }), hash)
67}
68
69module.exports = { defaults, limits, hash, needsRehash, verify, ...types }