js-libp2p/src/pnet/crypto.js
2020-12-16 13:56:41 +01:00

82 lines
2.4 KiB
JavaScript

'use strict'
const debug = require('debug')
const log = Object.assign(debug('libp2p:pnet'), {
trace: debug('libp2p:pnet:trace'),
error: debug('libp2p:pnet:err')
})
const Errors = require('./errors')
const xsalsa20 = require('xsalsa20')
const KEY_LENGTH = require('./key-generator').KEY_LENGTH
const uint8ArrayFromString = require('uint8arrays/from-string')
const uint8ArrayToString = require('uint8arrays/to-string')
/**
* Creates a stream iterable to encrypt messages in a private network
*
* @param {Uint8Array} nonce - The nonce to use in encryption
* @param {Uint8Array} psk - The private shared key to use in encryption
* @returns {*} a through iterable
*/
module.exports.createBoxStream = (nonce, psk) => {
const xor = xsalsa20(nonce, psk)
return (source) => (async function * () {
for await (const chunk of source) {
yield Uint8Array.from(xor.update(chunk.slice()))
}
})()
}
/**
* Creates a stream iterable to decrypt messages in a private network
*
* @param {Uint8Array} nonce - The nonce of the remote peer
* @param {Uint8Array} psk - The private shared key to use in decryption
* @returns {*} a through iterable
*/
module.exports.createUnboxStream = (nonce, psk) => {
return (source) => (async function * () {
const xor = xsalsa20(nonce, psk)
log.trace('Decryption enabled')
for await (const chunk of source) {
yield Uint8Array.from(xor.update(chunk.slice()))
}
})()
}
/**
* Decode the version 1 psk from the given Uint8Array
*
* @param {Uint8Array} 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
// programmatically instead of making assumptions about the
// encodings of each line.
const metadata = uint8ArrayToString(pskBuffer).split(/(?:\r\n|\r|\n)/g)
const pskTag = metadata.shift()
const codec = metadata.shift()
const psk = uint8ArrayFromString(metadata.shift(), 'base16')
if (psk.byteLength !== KEY_LENGTH) {
throw new Error(Errors.INVALID_PSK)
}
return {
tag: pskTag,
codecName: codec,
psk: psk
}
} catch (err) {
log.error(err)
throw new Error(Errors.INVALID_PSK)
}
}