mini-tor-js/src/tor/CircuitNodeCryptoState.js
Nicolas Dextraze a5230b9105 initial commit
2021-01-10 12:43:30 -05:00

101 lines
2.9 KiB
JavaScript

const crypto = require('crypto');
const Cell = require('./Cell')
class CircuitNodeCryptoState {
/** @type Hash */
_forward_digest = null;
/** @type Hash */
_backward_digest = null;
/** @type Cipher */
_backward_cipher = null;
/** @type Cipher */
_forward_cipher = null;
constructor (key_material) {
this._forward_digest = crypto.createHash('sha1');
const df = key_material.slice(0, 20);
this._forward_digest.update(df);
this._backward_digest = crypto.createHash('sha1');
const db = key_material.slice(20, 20 + 20);
this._backward_digest.update(db);
const kf = key_material.slice(20 + 20, 20 + 20 + 16);
this._forward_cipher = crypto.createCipheriv('aes-128-ctr', kf, Buffer.alloc(16));
const kb = key_material.slice(20 + 20 + 16, 20 + 20 + 16 + 16);
this._backward_cipher = crypto.createCipheriv('aes-128-ctr', kb, Buffer.alloc(16));
}
/**
* @param {RelayCell} cell
*/
encrypt_forward_cell(cell) {
const relay_payload_bytes = Buffer.alloc(Cell.payload_size);
if (cell.payload == null)
{
relay_payload_bytes.writeUInt8(cell.relay_command, 0);
relay_payload_bytes.writeUInt16BE(0, 1); // 'recognized'
relay_payload_bytes.writeUInt16BE(cell.stream_id, 3);
relay_payload_bytes.writeInt32BE(0, 5); // digest placeholder
relay_payload_bytes.writeUInt16BE(cell.relay_payload.length, 9);
cell.relay_payload.copy(relay_payload_bytes, 11);
//
// update digest field in the payload
//
this._forward_digest.update(relay_payload_bytes);
const digest = this._forward_digest.copy().digest(); // requires node >= 12.16
digest.copy(relay_payload_bytes, 5, 0, 4);
}
else
{
cell.payload.copy(relay_payload_bytes, 0);
}
//
// encrypt the payload
//
cell.payload = this._forward_cipher.update(relay_payload_bytes);
// console.debug("CircuitNodeCryptoState.encrypt_forward_cell(): %s %s",
// relay_payload_bytes.toString('hex'),
// cell.payload.toString('hex'));
}
/**
* @param {Cell} cell
* @returns {boolean}
*/
decrypt_backward_cell(cell) {
cell.payload = this._backward_cipher.update(cell.payload);
//
// check if this is a cell for us.
//
if (cell.is_recognized())
{
//
// remove the digest from the payload
//
const payload_without_digest = Buffer.alloc(cell.payload.length);
cell.payload.copy(payload_without_digest);
payload_without_digest.writeInt32BE(0, 5);
const backward_digest_clone = this._backward_digest.copy();
backward_digest_clone.update(payload_without_digest);
const digest = backward_digest_clone.digest();
if (digest.compare(cell.payload, 5, 5 + 4, 0, 4) === 0)
{
this._backward_digest.update(payload_without_digest);
return true;
}
}
return false;
}
}
module.exports = CircuitNodeCryptoState;