2016-05-19 22:33:09 +02:00
|
|
|
'use strict'
|
2020-03-23 15:55:35 +00:00
|
|
|
const { Buffer } = require('buffer')
|
2019-07-22 06:16:02 -04:00
|
|
|
const errcode = require('err-code')
|
2017-07-22 10:57:27 -07:00
|
|
|
const hmac = require('../hmac')
|
2016-05-20 12:50:16 +02:00
|
|
|
|
|
|
|
const cipherMap = {
|
|
|
|
'AES-128': {
|
|
|
|
ivSize: 16,
|
|
|
|
keySize: 16
|
|
|
|
},
|
|
|
|
'AES-256': {
|
|
|
|
ivSize: 16,
|
|
|
|
keySize: 32
|
|
|
|
},
|
2016-05-20 14:41:25 +02:00
|
|
|
Blowfish: {
|
2016-05-20 12:50:16 +02:00
|
|
|
ivSize: 8,
|
|
|
|
cipherKeySize: 32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-19 22:33:09 +02:00
|
|
|
// Generates a set of keys for each party by stretching the shared key.
|
|
|
|
// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
|
2019-07-10 17:15:26 +01:00
|
|
|
module.exports = async (cipherType, hash, secret) => {
|
2016-05-20 12:50:16 +02:00
|
|
|
const cipher = cipherMap[cipherType]
|
|
|
|
|
|
|
|
if (!cipher) {
|
2019-07-22 06:16:02 -04:00
|
|
|
const allowed = Object.keys(cipherMap).join(' / ')
|
|
|
|
throw errcode(new Error(`unknown cipher type '${cipherType}'. Must be ${allowed}`), 'ERR_INVALID_CIPHER_TYPE')
|
2016-05-20 12:50:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!hash) {
|
2019-10-24 18:16:41 +02:00
|
|
|
throw errcode(new Error('missing hash type'), 'ERR_MISSING_HASH_TYPE')
|
2016-05-20 12:50:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const cipherKeySize = cipher.keySize
|
2016-05-20 14:41:25 +02:00
|
|
|
const ivSize = cipher.ivSize
|
|
|
|
const hmacKeySize = 20
|
2016-09-13 13:23:11 +02:00
|
|
|
const seed = Buffer.from('key expansion')
|
2016-05-20 12:50:16 +02:00
|
|
|
const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize)
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
const m = await hmac.create(hash, secret)
|
|
|
|
let a = await m.digest(seed)
|
2016-09-13 13:23:11 +02:00
|
|
|
|
2019-10-24 18:16:41 +02:00
|
|
|
const result = []
|
2019-07-10 17:15:26 +01:00
|
|
|
let j = 0
|
2016-09-13 13:23:11 +02:00
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
while (j < resultLength) {
|
|
|
|
const b = await m.digest(Buffer.concat([a, seed]))
|
|
|
|
let todo = b.length
|
2016-09-13 13:23:11 +02:00
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
if (j + todo > resultLength) {
|
|
|
|
todo = resultLength - j
|
|
|
|
}
|
2016-09-13 13:23:11 +02:00
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
result.push(b)
|
|
|
|
j += todo
|
|
|
|
a = await m.digest(a)
|
|
|
|
}
|
2016-09-13 13:23:11 +02:00
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
const half = resultLength / 2
|
|
|
|
const resultBuffer = Buffer.concat(result)
|
|
|
|
const r1 = resultBuffer.slice(0, half)
|
|
|
|
const r2 = resultBuffer.slice(half, resultLength)
|
2016-09-13 13:23:11 +02:00
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
const createKey = (res) => ({
|
|
|
|
iv: res.slice(0, ivSize),
|
|
|
|
cipherKey: res.slice(ivSize, ivSize + cipherKeySize),
|
|
|
|
macKey: res.slice(ivSize + cipherKeySize)
|
2016-05-20 15:55:19 +02:00
|
|
|
})
|
2019-07-10 17:15:26 +01:00
|
|
|
|
|
|
|
return {
|
|
|
|
k1: createKey(r1),
|
|
|
|
k2: createKey(r2)
|
|
|
|
}
|
2016-05-19 22:33:09 +02:00
|
|
|
}
|