Files
js-libp2p/src/pnet/crypto.js
Alex Potsides 3bed7b4cb2 chore: update aegir (#1027)
Updates aegir, fixes all new linting errors.
2021-11-19 08:02:24 +00:00

85 lines
2.6 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')
// @ts-ignore xsalsa20 has no types exported
const xsalsa20 = require('xsalsa20')
const KEY_LENGTH = require('./key-generator').KEY_LENGTH
const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string')
const { toString: 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 (/** @type {AsyncIterable<Uint8Array>} */ 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 (/** @type {AsyncIterable<Uint8Array>} */ 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 {{ tag?: string, codecName?: string, psk: Uint8Array }} 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 pskString = metadata.shift()
const psk = pskString && uint8ArrayFromString(pskString, 'base16')
if (!psk || psk.byteLength !== KEY_LENGTH) {
throw new Error(Errors.INVALID_PSK)
}
return {
tag: pskTag,
codecName: codec,
psk: psk
}
} catch (/** @type {any} */ err) {
log.error(err)
throw new Error(Errors.INVALID_PSK)
}
}