UNPKG

steganos

Version:

Node-based implementation of Steganos Secure Communication Protocol

226 lines (162 loc) 6.51 kB
'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;