steganos
Version:
Node-based implementation of Steganos Secure Communication Protocol
226 lines (162 loc) • 6.51 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _ursa = require('ursa');
var _ursa2 = _interopRequireDefault(_ursa);
var _crypto = require('crypto');
var _crypto2 = _interopRequireDefault(_crypto);
var _csprng = require('csprng');
var _csprng2 = _interopRequireDefault(_csprng);
var _guid = require('./utils/guid');
var _guid2 = _interopRequireDefault(_guid);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toArray(arr) { return Array.isArray(arr) ? arr : Array.from(arr); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var IV_LENGTH = 16;
// const PEER_UNKNOWN = 0;
var PEER_HELO = 1;
var PEER_AUTH = 2;
var Private = new WeakMap();
var Steganos = function () {
function Steganos(encoding) {
_classCallCheck(this, Steganos);
var privKey = _ursa2.default.generatePrivateKey();
var pubKey = _ursa2.default.createPublicKey(privKey.toPublicPem());
this.encoding = encoding || 'hex';
Private.set(this, {
peers: {},
signature: (0, _guid2.default)(),
privKey: privKey,
pubKey: pubKey
});
}
_createClass(Steganos, [{
key: 'sendHelo',
value: function sendHelo() {
var _Private$get = Private.get(this),
pubKey = _Private$get.pubKey,
signature = _Private$get.signature;
return {
signature: signature,
type: 'HELO',
payload: pubKey.toPublicPem(this.encoding)
};
}
}, {
key: 'receiveHelo',
value: function receiveHelo(pkg) {
var _Private$get2 = Private.get(this),
peers = _Private$get2.peers;
var signature = pkg.signature,
type = pkg.type,
theirPublicKey = pkg.payload;
if (type !== 'HELO') {
throw new TypeError('Malformed HELO Package: Unknown type \'' + type + '\'.');
}
peers[signature] = {
stage: PEER_HELO,
pubKey: _ursa2.default.createPublicKey(theirPublicKey, this.encoding),
spk: null
};
}
}, {
key: 'sendAuth',
value: function sendAuth(theirSignature) {
// Grab `signature`'s public key from our `peers` (and store it in theirPublicKey)
var _Private$get3 = Private.get(this),
peers = _Private$get3.peers,
ourSignature = _Private$get3.signature;
var theirPublicKey = peers[theirSignature].pubKey;
// Generate Shared Private Key (SPK)
var spk = (0, _csprng2.default)(); // CSPRNG => Pseudo-Random Number Generator : Crytographically Secure
peers[theirSignature].spk = spk;
peers[theirSignature].stage = PEER_AUTH;
// Encrypt it using theirPublicKey
var encryptedSpk = theirPublicKey.encrypt(spk, 'utf8', this.encoding);
// return the encrypted version to send
return {
signature: ourSignature,
type: 'AUTH',
payload: encryptedSpk
};
}
}, {
key: 'receiveAuth',
value: function receiveAuth(pkg) {
var theirSignature = pkg.signature,
type = pkg.type,
payload = pkg.payload;
if (type !== 'AUTH') {
throw new TypeError('Malformed AUTH Package: Unknown type \'' + type + '\'.');
}
var _Private$get4 = Private.get(this),
peers = _Private$get4.peers,
privKey = _Private$get4.privKey;
var spk = peers[theirSignature].spk;
peers[theirSignature].stage = PEER_AUTH;
var theirSpk = privKey.decrypt(payload, this.encoding, 'utf8');
if (theirSpk !== spk) {
throw new Error('Incorrect Shared Private Key');
}
}
// ------------------------
}, {
key: 'sendMessage',
value: function sendMessage(msg, theirSignature) {
var encoding = this.encoding;
// Look up theirPublicKey and the spk
var _Private$get5 = Private.get(this),
peers = _Private$get5.peers,
ourSignature = _Private$get5.signature;
var _peers$theirSignature = peers[theirSignature],
spk = _peers$theirSignature.spk,
theirPublicKey = _peers$theirSignature.pubKey;
// Encrypt message with spk
var iv = _crypto2.default.randomBytes(IV_LENGTH);
var cipher = _crypto2.default.createCipheriv('aes-256-cbc', Buffer.from(spk, 'utf8'), iv);
var encryptedMsg = cipher.update(msg);
var finalizedMsg = Buffer.concat([encryptedMsg, cipher.final()]);
// Encrypt the IV with theirPublicKey
var encryptedIv = theirPublicKey.encrypt(iv.toString(encoding), encoding, encoding);
// Send TEXT message with the encrpyted versions in the payload, signed with our signature
return {
signature: ourSignature,
type: 'TEXT',
payload: encryptedIv + ':' + finalizedMsg.toString(encoding)
};
}
}, {
key: 'receiveMessage',
value: function receiveMessage(pkg) {
// Grab our private key
var _Private$get6 = Private.get(this),
privKey = _Private$get6.privKey,
peers = _Private$get6.peers;
// Look up the spk using theirSignature (from pkg)
var theirSignature = pkg.signature,
type = pkg.type,
payload = pkg.payload;
var spk = peers[theirSignature].spk;
if (type !== 'TEXT') {
throw TypeError('Malformed TYPE Package: Unknown type \'' + type + '\'.');
}
// Split payload into two parts: "encryptedIv:encryptedMsg"
var _payload$split = payload.split(':'),
_payload$split2 = _toArray(_payload$split),
encryptedIv = _payload$split2[0],
encryptedMsg = _payload$split2.slice(1);
// Decrypt the IV using our private key
var decryptedIv = privKey.decrypt(encryptedIv, this.encoding);
// Use the spk and decrypted IV to decrypt message
var decipher = _crypto2.default.createDecipheriv('aes-256-cbc', Buffer.from(spk, 'utf8'), decryptedIv);
var encryptedText = Buffer.from(encryptedMsg.join(':'), this.encoding);
var decrypted = decipher.update(encryptedText);
// return decrypted message
return Buffer.concat([decrypted, decipher.final()]).toString();
}
}]);
return Steganos;
}();
exports.default = Steganos;