mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-04-29 04:22:14 +00:00
99 lines
2.5 KiB
JavaScript
99 lines
2.5 KiB
JavaScript
|
'use strict'
|
||
|
|
||
|
const pull = require('pull-stream')
|
||
|
const debug = require('debug')
|
||
|
const Errors = require('./errors')
|
||
|
const xsalsa20 = require('xsalsa20')
|
||
|
const KEY_LENGTH = require('./key-generator').KEY_LENGTH
|
||
|
|
||
|
const log = debug('libp2p:pnet')
|
||
|
log.trace = debug('libp2p:pnet:trace')
|
||
|
log.err = debug('libp2p:pnet:err')
|
||
|
|
||
|
/**
|
||
|
* Creates a pull stream to encrypt messages in a private network
|
||
|
*
|
||
|
* @param {Buffer} nonce The nonce to use in encryption
|
||
|
* @param {Buffer} psk The private shared key to use in encryption
|
||
|
* @returns {PullStream} a through stream
|
||
|
*/
|
||
|
module.exports.createBoxStream = (nonce, psk) => {
|
||
|
const xor = xsalsa20(nonce, psk)
|
||
|
return pull(
|
||
|
ensureBuffer(),
|
||
|
pull.map((chunk) => {
|
||
|
return xor.update(chunk, chunk)
|
||
|
})
|
||
|
)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a pull stream to decrypt messages in a private network
|
||
|
*
|
||
|
* @param {Object} remote Holds the nonce of the peer
|
||
|
* @param {Buffer} psk The private shared key to use in decryption
|
||
|
* @returns {PullStream} a through stream
|
||
|
*/
|
||
|
module.exports.createUnboxStream = (remote, psk) => {
|
||
|
let xor
|
||
|
return pull(
|
||
|
ensureBuffer(),
|
||
|
pull.map((chunk) => {
|
||
|
if (!xor) {
|
||
|
xor = xsalsa20(remote.nonce, psk)
|
||
|
log.trace('Decryption enabled')
|
||
|
}
|
||
|
|
||
|
return xor.update(chunk, chunk)
|
||
|
})
|
||
|
)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Decode the version 1 psk from the given Buffer
|
||
|
*
|
||
|
* @param {Buffer} pskBuffer
|
||
|
* @throws {INVALID_PSK}
|
||
|
* @returns {Object} The PSK metadata (tag, codecName, psk)
|
||
|
*/
|
||
|
module.exports.decodeV1PSK = (pskBuffer) => {
|
||
|
try {
|
||
|
// This should pull from multibase/multicodec to allow for
|
||
|
// more encoding flexibility. Ideally we'd consume the codecs
|
||
|
// from the buffer line by line to evaluate the next line
|
||
|
// programatically instead of making assumptions about the
|
||
|
// encodings of each line.
|
||
|
const metadata = pskBuffer.toString().split(/(?:\r\n|\r|\n)/g)
|
||
|
const pskTag = metadata.shift()
|
||
|
const codec = metadata.shift()
|
||
|
const psk = Buffer.from(metadata.shift(), 'hex')
|
||
|
|
||
|
if (psk.byteLength !== KEY_LENGTH) {
|
||
|
throw new Error(Errors.INVALID_PSK)
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
tag: pskTag,
|
||
|
codecName: codec,
|
||
|
psk: psk
|
||
|
}
|
||
|
} catch (err) {
|
||
|
throw new Error(Errors.INVALID_PSK)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a through pull-stream that ensures the passed chunks
|
||
|
* are buffers instead of strings
|
||
|
* @returns {PullStream} a through stream
|
||
|
*/
|
||
|
function ensureBuffer () {
|
||
|
return pull.map((chunk) => {
|
||
|
if (typeof chunk === 'string') {
|
||
|
return Buffer.from(chunk, 'utf-8')
|
||
|
}
|
||
|
|
||
|
return chunk
|
||
|
})
|
||
|
}
|