mirror of
https://github.com/fluencelabs/js-libp2p-secio
synced 2025-05-13 23:01:19 +00:00
140 lines
2.9 KiB
JavaScript
140 lines
2.9 KiB
JavaScript
'use strict'
|
|
|
|
const mh = require('multihashing-async')
|
|
const lp = require('pull-length-prefixed')
|
|
const pull = require('pull-stream')
|
|
const crypto = require('libp2p-crypto')
|
|
const parallel = require('async/parallel')
|
|
|
|
exports.exchanges = [
|
|
'P-256',
|
|
'P-384',
|
|
'P-521'
|
|
]
|
|
|
|
exports.ciphers = [
|
|
'AES-256',
|
|
'AES-128'
|
|
]
|
|
|
|
exports.hashes = [
|
|
'SHA256',
|
|
'SHA512'
|
|
]
|
|
|
|
// Determines which algorithm to use. Note: f(a, b) = f(b, a)
|
|
exports.theBest = (order, p1, p2) => {
|
|
let first
|
|
let second
|
|
|
|
if (order < 0) {
|
|
first = p2
|
|
second = p1
|
|
} else if (order > 0) {
|
|
first = p1
|
|
second = p2
|
|
} else {
|
|
return p1[0]
|
|
}
|
|
|
|
for (let firstCandidate of first) {
|
|
for (let secondCandidate of second) {
|
|
if (firstCandidate === secondCandidate) {
|
|
return firstCandidate
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new Error('No algorithms in common!')
|
|
}
|
|
|
|
exports.makeMacAndCipher = (target, callback) => {
|
|
parallel([
|
|
(cb) => makeMac(target.hashT, target.keys.macKey, cb),
|
|
(cb) => makeCipher(target.cipherT, target.keys.iv, target.keys.cipherKey, cb)
|
|
], (err, macAndCipher) => {
|
|
if (err) {
|
|
return callback(err)
|
|
}
|
|
|
|
target.mac = macAndCipher[0]
|
|
target.cipher = macAndCipher[1]
|
|
callback()
|
|
})
|
|
}
|
|
|
|
function makeMac (hash, key, callback) {
|
|
crypto.hmac.create(hash, key, callback)
|
|
}
|
|
|
|
function makeCipher (cipherType, iv, key, callback) {
|
|
if (cipherType === 'AES-128' || cipherType === 'AES-256') {
|
|
return crypto.aes.create(key, iv, callback)
|
|
}
|
|
|
|
// TODO: figure out if Blowfish is needed and if so find a library for it.
|
|
callback(new Error(`unrecognized cipher type: ${cipherType}`))
|
|
}
|
|
|
|
exports.randomBytes = (nonceSize) => {
|
|
return Buffer.from(crypto.webcrypto.getRandomValues(new Uint8Array(nonceSize)))
|
|
}
|
|
|
|
exports.selectBest = (local, remote, cb) => {
|
|
exports.digest(Buffer.concat([
|
|
remote.pubKeyBytes,
|
|
local.nonce
|
|
]), (err, oh1) => {
|
|
if (err) {
|
|
return cb(err)
|
|
}
|
|
|
|
exports.digest(Buffer.concat([
|
|
local.pubKeyBytes,
|
|
remote.nonce
|
|
]), (err, oh2) => {
|
|
if (err) {
|
|
return cb(err)
|
|
}
|
|
|
|
const order = Buffer.compare(oh1, oh2)
|
|
|
|
if (order === 0) {
|
|
return cb(new Error('you are trying to talk to yourself'))
|
|
}
|
|
|
|
cb(null, {
|
|
curveT: exports.theBest(order, local.exchanges, remote.exchanges),
|
|
cipherT: exports.theBest(order, local.ciphers, remote.ciphers),
|
|
hashT: exports.theBest(order, local.hashes, remote.hashes),
|
|
order
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
exports.digest = (buf, cb) => {
|
|
mh.digest(buf, 'sha2-256', buf.length, cb)
|
|
}
|
|
|
|
exports.write = function write (state, msg, cb) {
|
|
cb = cb || (() => {})
|
|
pull(
|
|
pull.values([
|
|
msg
|
|
]),
|
|
lp.encode({fixed: true, bytes: 4}),
|
|
pull.collect((err, res) => {
|
|
if (err) {
|
|
return cb(err)
|
|
}
|
|
state.shake.write(res[0])
|
|
cb()
|
|
})
|
|
)
|
|
}
|
|
|
|
exports.read = function read (reader, cb) {
|
|
lp.decodeFromReader(reader, {fixed: true, bytes: 4}, cb)
|
|
}
|