-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
47 lines (36 loc) · 1.67 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const crypto = require('crypto')
function isArrayBufferOrTypedArray (input) {
return (typeof input.byteLength === 'number' && typeof input.slice === 'function')
}
function hmac (hash, key, input) {
return crypto.createHmac(hash, key).update(input).digest()
}
const hashLengths = {
sha256: 32,
sha384: 48,
sha512: 64
}
module.exports = function hkdf (salt, input, info, keylen, digest) {
if (!isArrayBufferOrTypedArray(salt)) throw new TypeError('Expected "salt" to be an ArrayBuffer, Uint8Array or Buffer')
if (!isArrayBufferOrTypedArray(input)) throw new TypeError('Expected "input" to be an ArrayBuffer, Uint8Array or Buffer')
if (!isArrayBufferOrTypedArray(info)) throw new TypeError('Expected "info" to be an ArrayBuffer, Uint8Array or Buffer')
if (digest !== 'SHA-256' && digest !== 'SHA-384' && digest !== 'SHA-512') throw new TypeError('Expected "digest" to be one of "SHA-256", "SHA-384" or "SHA-512"')
salt = Buffer.from(salt)
input = Buffer.from(input)
info = Buffer.from(info)
digest = digest.replace('SHA-', 'sha')
const hashLength = hashLengths[digest]
const iterations = Math.ceil(keylen / hashLength)
if (iterations > 0xff) {
throw new RangeError('Key length "keylen" exceeds maximum key length for this "digest" parameter')
}
return Promise.resolve().then(function () {
const prk = hmac(digest, salt, input)
const parts = [Buffer.from('')]
for (let i = 0; i < iterations; i++) {
parts.push(hmac(digest, prk, Buffer.concat([parts[i], info, Buffer.from([i + 1])])))
}
const result = Buffer.concat(parts).slice(0, keylen)
return result.buffer.slice(result.byteOffset, result.byteOffset + result.byteLength)
})
}