pqp
Version:
NodeJS version of libPQP
248 lines (196 loc) • 9.23 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
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 _cryptoJs = require('crypto-js');
var _cryptoJs2 = _interopRequireDefault(_cryptoJs);
var _keygen = require('./keygen');
var _keygen2 = _interopRequireDefault(_keygen);
var _qcmdpc = require('./qcmdpc');
var _qcmdpc2 = _interopRequireDefault(_qcmdpc);
var _randomgen = require('../operations/randomgen');
var _randomgen2 = _interopRequireDefault(_randomgen);
var _keyio = require('../operations/keyio');
var _keyio2 = _interopRequireDefault(_keyio);
var _conversion = require('../operations/conversion');
var _encBase = require('crypto-js/enc-base64');
var _encBase2 = _interopRequireDefault(_encBase);
var _aesJs = require('aes-js');
var _aesJs2 = _interopRequireDefault(_aesJs);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Pkcs7 = _cryptoJs2.default.pad.Pkcs7;
var AES = _cryptoJs2.default.AES;
function Utf8ArrayToStr(array) {
var out, i, len, c;
var char2, char3;
out = "";
len = array.length;
i = 0;
while (i < len) {
c = array[i++];
switch (c >> 4) {
case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:
// 0xxxxxxx
out += String.fromCharCode(c);
break;
case 12:case 13:
// 110x xxxx 10xx xxxx
char2 = array[i++];
out += String.fromCharCode((c & 0x1F) << 6 | char2 & 0x3F);
break;
case 14:
// 1110 xxxx 10xx xxxx 10xx xxxx
char2 = array[i++];
char3 = array[i++];
out += String.fromCharCode((c & 0x0F) << 12 | (char2 & 0x3F) << 6 | (char3 & 0x3F) << 0);
break;
}
}
return out;
}
// WordArray
function sliceWordArray(array, start, end) {
return _cryptoJs2.default.enc.Hex.parse(array.toString(_cryptoJs2.default.enc.Hex).substr(start, end * 2));
}
var Protocol = function () {
function Protocol() {
_classCallCheck(this, Protocol);
// instantiate primitives
this.asymmetric_cipher = new _qcmdpc2.default();
this.randgen = new _randomgen2.default();
this.io = new _keyio2.default();
// just some random salts
this.saltA = 'this is just a salt';
this.saltB = 'this is another a salt';
this.ivSalt = 'third salt';
}
_createClass(Protocol, [{
key: 'generate_keypair',
value: function generate_keypair() {
// instantiate keygenerator and set keypair
var keygen = new _keygen2.default();
var _keygen$generate = keygen.generate(),
_keygen$generate2 = _slicedToArray(_keygen$generate, 2),
privateKey = _keygen$generate2[0],
publicKey = _keygen$generate2[1];
this.priv_key = privateKey;
this.pub_key = publicKey;
this.asymmetric_cipher.set_private_key(this.priv_key);
}
}, {
key: 'set_private_key',
value: function set_private_key(key) {
key = this.io.extract_der_priv_key(key);
this.priv_key = key;
this.asymmetric_cipher.set_private_key(key);
}
}, {
key: 'set_public_key',
value: function set_public_key(key) {
key = this.io.extract_der_pub_key(key);
this.pub_key = key;
}
}, {
key: 'get_private_key',
value: function get_private_key() {
return this.io.get_der_priv_key(this.priv_key);
}
}, {
key: 'get_public_key',
value: function get_public_key() {
return this.io.get_der_pub_key(this.pub_key);
}
}, {
key: 'generate_mac',
value: function generate_mac(message, token, key) {
var word = message.appendWordArray(token).concat(key);
return _cryptoJs2.default.SHA256(word);
}
}, {
key: 'symmetric_cipher_enc',
value: function symmetric_cipher_enc(message, mac, key, iv) {
var array = message.appendWordArray(mac);
var plain = _aesJs2.default.utils.hex.toBytes(array.toString(_cryptoJs2.default.enc.Hex));
plain = _aesJs2.default.padding.pkcs7.pad(plain);
key = _aesJs2.default.utils.hex.toBytes(key.toString());
iv = _aesJs2.default.utils.hex.toBytes(iv.toString());
var aesCbc = new _aesJs2.default.ModeOfOperation.cbc(key, iv);
var data = aesCbc.encrypt(plain);
return Buffer.from(data);
}
}, {
key: 'symmetric_cipher_dec',
value: function symmetric_cipher_dec(ciphertext, key, iv) {
var encryptedBytes = _aesJs2.default.utils.hex.toBytes(ciphertext.toString());
key = _aesJs2.default.utils.hex.toBytes(key.toString());
iv = _aesJs2.default.utils.hex.toBytes(iv.toString());
var aesCbc = new _aesJs2.default.ModeOfOperation.cbc(key, iv);
var decrypted = aesCbc.decrypt(encryptedBytes);
decrypted = _aesJs2.default.padding.pkcs7.strip(decrypted);
var length = 32;
var len = decrypted.length;
var mac = new Buffer(decrypted.slice(len - length, len)).toString('hex');
var message = decrypted.slice(0, len - length);
message = Utf8ArrayToStr(message);
return [message, mac];
}
}, {
key: 'encrypt_message',
value: function encrypt_message(message, recv_pub_key) {
// generate random data
var randomized = this.randgen.get_random_vector(this.pub_key.block_length);
var token = randomized.pack();
// derive keys
var keyA = _cryptoJs2.default.SHA256(this.append(token, this.saltA)); // just some conversion
var keyB = _cryptoJs2.default.SHA256(this.append(token, this.saltB));
// derive iv
var iv = _cryptoJs2.default.SHA512(this.append(token, this.ivSalt));
iv = sliceWordArray(iv, 0, 16);
// generate mac
var mac = this.generate_mac(message, token, keyB);
var _asymmetric_cipher$en = this.asymmetric_cipher.encrypt(recv_pub_key, randomized),
_asymmetric_cipher$en2 = _slicedToArray(_asymmetric_cipher$en, 2),
c_0 = _asymmetric_cipher$en2[0],
c_1 = _asymmetric_cipher$en2[1];
// generate ciphertext
return this.io.get_der_ciphertext(c_0, c_1, this.symmetric_cipher_enc(message, mac, keyA, iv));
}
}, {
key: 'append',
value: function append(digest, suffix) {
var array = digest.clone();
return array.concat(suffix.toWordArray());
}
}, {
key: 'decrypt_message',
value: function decrypt_message(ciphertext) {
// extract ciphertext data from DER
var _io$extract_der_ciphe = this.io.extract_der_ciphertext(ciphertext),
_io$extract_der_ciphe2 = _slicedToArray(_io$extract_der_ciphe, 3),
rc_0 = _io$extract_der_ciphe2[0],
rc_1 = _io$extract_der_ciphe2[1],
symmetric_stream = _io$extract_der_ciphe2[2];
// decrypt necessary data
var decrypted_token = this.asymmetric_cipher.decrypt(rc_0, rc_1).pack();
// derive keys from data
var decrypted_keyA = _cryptoJs2.default.SHA256(this.append(decrypted_token, this.saltA)); // just some conversion
var decrypted_keyB = _cryptoJs2.default.SHA256(this.append(decrypted_token, this.saltB));
// derive iv
var digest = _cryptoJs2.default.SHA512(this.append(decrypted_token, this.ivSalt));
var decrypted_iv = sliceWordArray(digest, 0, 16);
// decrypt ciphertext and derive mac
var stream = _cryptoJs2.default.lib.WordArray.create(new Uint8Array(symmetric_stream));
var _symmetric_cipher_dec = this.symmetric_cipher_dec(stream, decrypted_keyA, decrypted_iv),
_symmetric_cipher_dec2 = _slicedToArray(_symmetric_cipher_dec, 2),
decrypted_message = _symmetric_cipher_dec2[0],
decrypted_mac = _symmetric_cipher_dec2[1];
var receiver_mac = this.generate_mac(decrypted_message, decrypted_token, decrypted_keyB);
return [decrypted_message, receiver_mac.toString(_cryptoJs2.default.enc.Hex) == decrypted_mac];
}
}]);
return Protocol;
}();
exports.default = Protocol;