js-libp2p-crypto/src/key-stretcher.js

110 lines
2.3 KiB
JavaScript
Raw Normal View History

'use strict'
const crypto = require('./crypto')
const whilst = require('async/whilst')
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
}
}
// Generates a set of keys for each party by stretching the shared key.
// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
module.exports = (cipherType, hash, secret, callback) => {
2016-05-20 12:50:16 +02:00
const cipher = cipherMap[cipherType]
if (!cipher) {
return callback(new Error('unkown cipherType passed'))
2016-05-20 12:50:16 +02:00
}
if (!hash) {
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
const seed = Buffer.from('key expansion')
2016-05-20 12:50:16 +02:00
const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize)
crypto.hmac.create(hash, secret, (err, m) => {
if (err) {
return callback(err)
2016-05-20 12:50:16 +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
})
}