2016-05-19 22:33:09 +02:00
|
|
|
'use strict'
|
|
|
|
|
2016-09-13 13:23:11 +02:00
|
|
|
const crypto = require('./crypto')
|
|
|
|
const whilst = require('async/whilst')
|
2017-01-16 05:17:50 +01:00
|
|
|
const Buffer = require('safe-buffer').Buffer
|
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)
|
2016-09-13 13:23:11 +02:00
|
|
|
module.exports = (cipherType, hash, secret, callback) => {
|
2016-05-20 12:50:16 +02:00
|
|
|
const cipher = cipherMap[cipherType]
|
|
|
|
|
|
|
|
if (!cipher) {
|
2016-09-13 13:23:11 +02:00
|
|
|
return callback(new Error('unkown cipherType passed'))
|
2016-05-20 12:50:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!hash) {
|
2016-09-13 13:23:11 +02:00
|
|
|
return callback(new Error('unkown hashType passed'))
|
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)
|
|
|
|
|
2016-09-13 13:23:11 +02:00
|
|
|
crypto.hmac.create(hash, secret, (err, m) => {
|
|
|
|
if (err) {
|
|
|
|
return callback(err)
|
2016-05-20 12:50:16 +02:00
|
|
|
}
|
|
|
|
|
2016-09-13 13:23:11 +02:00
|
|
|
m.digest(seed, (err, a) => {
|
|
|
|
if (err) {
|
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
let result = []
|
|
|
|
let j = 0
|
|
|
|
|
|
|
|
whilst(
|
|
|
|
() => j < resultLength,
|
|
|
|
stretch,
|
|
|
|
finish
|
|
|
|
)
|
|
|
|
|
|
|
|
function stretch (cb) {
|
|
|
|
m.digest(Buffer.concat([a, seed]), (err, b) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
let todo = b.length
|
|
|
|
|
|
|
|
if (j + todo > resultLength) {
|
|
|
|
todo = resultLength - j
|
|
|
|
}
|
|
|
|
|
|
|
|
result.push(b)
|
|
|
|
|
|
|
|
j += todo
|
|
|
|
|
|
|
|
m.digest(a, (err, _a) => {
|
|
|
|
if (err) {
|
|
|
|
return cb(err)
|
|
|
|
}
|
|
|
|
a = _a
|
|
|
|
cb()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function finish (err) {
|
|
|
|
if (err) {
|
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
const half = resultLength / 2
|
|
|
|
const resultBuffer = Buffer.concat(result)
|
|
|
|
const r1 = resultBuffer.slice(0, half)
|
|
|
|
const r2 = resultBuffer.slice(half, resultLength)
|
|
|
|
|
|
|
|
const createKey = (res) => ({
|
|
|
|
iv: res.slice(0, ivSize),
|
|
|
|
cipherKey: res.slice(ivSize, ivSize + cipherKeySize),
|
|
|
|
macKey: res.slice(ivSize + cipherKeySize)
|
|
|
|
})
|
|
|
|
|
|
|
|
callback(null, {
|
|
|
|
k1: createKey(r1),
|
|
|
|
k2: createKey(r2)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
2016-05-20 15:55:19 +02:00
|
|
|
})
|
2016-05-19 22:33:09 +02:00
|
|
|
}
|