2019-08-16 17:30:03 +02:00
|
|
|
'use strict'
|
|
|
|
|
2019-11-04 14:05:58 +01:00
|
|
|
const pipe = require('it-pipe')
|
2019-08-16 17:30:03 +02:00
|
|
|
const assert = require('assert')
|
2019-11-04 14:05:58 +01:00
|
|
|
const duplexPair = require('it-pair/duplex')
|
|
|
|
const crypto = require('libp2p-crypto')
|
2019-08-16 17:30:03 +02:00
|
|
|
const Errors = require('./errors')
|
2019-11-04 14:05:58 +01:00
|
|
|
const {
|
|
|
|
createBoxStream,
|
|
|
|
createUnboxStream,
|
|
|
|
decodeV1PSK
|
|
|
|
} = require('./crypto')
|
|
|
|
const handshake = require('it-handshake')
|
|
|
|
const { NONCE_LENGTH } = require('./key-generator')
|
2019-08-16 17:30:03 +02:00
|
|
|
const debug = require('debug')
|
|
|
|
const log = debug('libp2p:pnet')
|
|
|
|
log.err = debug('libp2p:pnet:err')
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Takes a Private Shared Key (psk) and provides a `protect` method
|
|
|
|
* for wrapping existing connections in a private encryption stream
|
|
|
|
*/
|
|
|
|
class Protector {
|
|
|
|
/**
|
|
|
|
* @param {Buffer} keyBuffer The private shared key buffer
|
|
|
|
* @constructor
|
|
|
|
*/
|
|
|
|
constructor (keyBuffer) {
|
|
|
|
const decodedPSK = decodeV1PSK(keyBuffer)
|
|
|
|
this.psk = decodedPSK.psk
|
|
|
|
this.tag = decodedPSK.tag
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-11-04 14:05:58 +01:00
|
|
|
* Takes a given Connection and creates a private encryption stream
|
2019-08-16 17:30:03 +02:00
|
|
|
* between its two peers from the PSK the Protector instance was
|
|
|
|
* created with.
|
|
|
|
*
|
|
|
|
* @param {Connection} connection The connection to protect
|
2019-11-04 14:05:58 +01:00
|
|
|
* @returns {*} A protected duplex iterable
|
2019-08-16 17:30:03 +02:00
|
|
|
*/
|
2019-11-04 14:05:58 +01:00
|
|
|
async protect (connection) {
|
2019-08-16 17:30:03 +02:00
|
|
|
assert(connection, Errors.NO_HANDSHAKE_CONNECTION)
|
|
|
|
|
2019-11-04 14:05:58 +01:00
|
|
|
// Exchange nonces
|
2019-08-16 17:30:03 +02:00
|
|
|
log('protecting the connection')
|
2019-11-04 14:05:58 +01:00
|
|
|
const localNonce = crypto.randomBytes(NONCE_LENGTH)
|
|
|
|
|
|
|
|
const shake = handshake(connection)
|
|
|
|
shake.write(localNonce)
|
2019-08-16 17:30:03 +02:00
|
|
|
|
2019-11-04 14:05:58 +01:00
|
|
|
const result = await shake.reader.next(NONCE_LENGTH)
|
|
|
|
const remoteNonce = result.value.slice()
|
|
|
|
shake.rest()
|
2019-08-16 17:30:03 +02:00
|
|
|
|
2019-11-04 14:05:58 +01:00
|
|
|
// Create the boxing/unboxing pipe
|
|
|
|
log('exchanged nonces')
|
|
|
|
const [internal, external] = duplexPair()
|
|
|
|
pipe(
|
|
|
|
external,
|
|
|
|
// Encrypt all outbound traffic
|
|
|
|
createBoxStream(localNonce, this.psk),
|
|
|
|
shake.stream,
|
|
|
|
// Decrypt all inbound traffic
|
|
|
|
createUnboxStream(remoteNonce, this.psk),
|
|
|
|
external
|
2019-08-16 17:30:03 +02:00
|
|
|
)
|
|
|
|
|
2019-11-04 14:05:58 +01:00
|
|
|
return internal
|
2019-08-16 17:30:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = Protector
|
|
|
|
module.exports.errors = Errors
|
|
|
|
module.exports.generate = require('./key-generator')
|