UNPKG

caesar

Version:

An easy-to-use advanced cryptography library.

472 lines (432 loc) 14.9 kB
// Generated by CoffeeScript 1.7.1 (function() { var crypto, keyLib, msgpack, stream, ursa, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; crypto = require('crypto'); ursa = require('ursa'); msgpack = require('msgpack'); stream = require('stream'); keyLib = require('./key'); Buffer.prototype.toArray = function() { return Array.prototype.slice.call(this, 0); }; exports.Encrypter = (function(_super) { __extends(Encrypter, _super); function Encrypter(keys, confidential, integrous, cut) { var requiresKey; this.keys = keys; this.confidential = confidential; this.integrous = integrous; this.cut = cut != null ? cut : 14336; if (!this instanceof exports.Encrypter) { return new exports.Encrypter(this.keys, this.confidential, this.integrous, this.cut); } stream.Transform.call(this, { objectMode: true, decodeStrings: true }); this.leftover = new Buffer(0); if (this.confidential !== true && this.confidential !== false) { throw 'Confidential must be true or false.'; } if ((this.integrous != null) && this.integrous !== 'sym' && this.integrous !== 'asym') { throw 'Integrous must be null, sym, or asym.'; } requiresKey = this.confidential || this.integrous === 'sym'; if (requiresKey && (this.keys.key == null) && (this.keys["public"] == null)) { throw 'No symmetric or public key.'; } if (this.integrous === 'asym' && (this.keys["private"] == null)) { throw 'No private key to sign messages with.'; } if (!this.confidential) { this.buffer = new stream.PassThrough(); } else if (this.keys.key != null) { this.buffer = crypto.createCipher('aes-256-ctr', this.keys.key); } } Encrypter.prototype._transform = function(dump, encoding, done) { var chunk, data, footer, k, key, len, mac, more, out, sigs, v, _ref, _ref1, _ref2, _ref3; while (dump.length !== 0) { len = dump.length > this.cut ? this.cut : dump.length; chunk = new Buffer(len); dump.copy(chunk); dump = dump.slice(len); if (this.keys.key == null) { key = keyLib.createRandom(); this.buffer = crypto.createCipher('aes-256-ctr', key); } else { key = this.keys.key; } this.buffer.write(chunk); data = this.buffer.read(); footer = {}; if (this.integrous === 'sym') { mac = crypto.createHmac('sha512', key); mac.end(data); footer.mac = mac.read().toArray(); } if (this.integrous === 'asym') { sigs = {}; footer.sigs = this.keys["private"] instanceof Array ? [] : {}; for (k in this.keys["private"]) { sigs[k] = ursa.createSigner('sha512'); } for (k in this.keys["private"]) { sigs[k].update(data); } _ref = this.keys["private"]; for (k in _ref) { v = _ref[k]; footer.sigs[k] = sigs[k].sign(v); } _ref1 = footer.sigs; for (k in _ref1) { v = _ref1[k]; footer.sigs[k] = v.toArray(); } } if (this.keys["public"] != null) { footer.keys = this.keys["public"] instanceof Array ? [] : {}; _ref2 = this.keys["public"]; for (k in _ref2) { v = _ref2[k]; footer.keys[k] = v.encrypt(key); } _ref3 = footer.keys; for (k in _ref3) { v = _ref3[k]; footer.keys[k] = v.toArray(); } } footer = msgpack.pack(footer); out = new Buffer(4 + data.length + footer.length); out.writeUInt16BE(data.length, 0); data.copy(out, 2, 0, data.length); out.writeUInt16BE(footer.length, data.length + 2); footer.copy(out, data.length + 4, 0, footer.length); more = this.push(out); if (!more) { return done(); } } return done(); }; Encrypter.prototype._flush = function(done) { this.push(this.leftover.length === 0 ? null : this.leftover); this.leftover = new Buffer(0); return done(); }; return Encrypter; })(stream.Transform); exports.Decrypter = (function(_super) { __extends(Decrypter, _super); function Decrypter(keys, confidential, integrous) { var requiresKey; this.keys = keys; this.confidential = confidential; this.integrous = integrous; if (!this instanceof exports.Decrypter) { return new exports.Decrypter(this.keys, this.confidential, this.integrous); } stream.Transform.call(this, { decodeStrings: true }); if (this.confidential !== true && this.confidential !== false) { throw 'Confidential must be true or false.'; } if ((this.integrous != null) && this.integrous !== 'sym' && this.integrous !== 'asym') { throw 'Integrous must be null, sym, or asym.'; } requiresKey = this.confidential || this.integrous === 'sym'; if (requiresKey && (this.keys.key == null) && (this.keys["private"] == null)) { throw 'No symmetric or private key.'; } if ((this.keys.key != null) && this.confidential) { this.cipher = crypto.createDecipher('aes-256-ctr', this.keys.key); } else { this.cipher = new stream.PassThrough(); } } Decrypter.prototype._transform = function(chunk, encoding, done) { var candidateTag, data, dlen, e, err, flen, footer, k, key, keys, mac, n, ok, privKey, pubKey, requiresKey, sig, tag, v, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2, _ref3; dlen = chunk.readUInt16BE(0); data = chunk.slice(2, 2 + dlen); flen = chunk.readUInt16BE(2 + dlen); footer = msgpack.unpack(chunk.slice(4 + dlen)); if (data == null) { return done('No payload.'); } if ((footer.mac == null) && this.integrous === 'sym') { return done('No MAC.'); } if ((footer.sigs == null) && this.integrous === 'asym') { return done('No sigs.'); } requiresKey = this.confidential || this.integrous === 'sym'; if (requiresKey && (this.keys.key == null) && (footer.keys == null)) { return done('No method of key derivation.'); } key = null; if (this.keys.key != null) { key = this.keys.key; } else { if (footer.keys instanceof Array) { _ref = footer.keys; for (_i = 0, _len = _ref.length; _i < _len; _i++) { tag = _ref[_i]; _ref1 = this.keys["private"]; for (n in _ref1) { privKey = _ref1[n]; try { key = privKey.decrypt(tag); } catch (_error) { err = _error; key = null; } if (key != null) { break; } } if (key != null) { break; } } } else { keys = (function() { var _results; _results = []; for (key in this.keys["private"]) { if (footer.keys[key] != null) { _results.push(key); } } return _results; }).call(this); if (keys.length === 0) { return done('No valid keys for decryption.'); } for (_j = 0, _len1 = keys.length; _j < _len1; _j++) { k = keys[_j]; try { key = this.keys["private"][k].decrypt(new Buffer(footer.keys[k])); } catch (_error) { err = _error; key = null; } if (key != null) { break; } } } } if (key == null) { return done('No key was successfully derived.'); } if (this.keys.key == null) { this.cipher = crypto.createDecipher('aes-256-ctr', key); } if (this.integrous === 'sym') { mac = crypto.createHmac('sha512', key); mac.end(new Buffer(footer.mac)); candidateTag = mac.read().toString('base64'); mac = crypto.createHmac('sha512', key); mac.end(data); tag = mac.read(); mac = crypto.createHmac('sha512', key); mac.end(tag); tag = mac.read().toString('base64'); if (candidateTag !== tag) { return done('Bad MAC.'); } } if (this.integrous === 'asym') { ok = false; if (footer.sigs instanceof Array) { _ref2 = footer.sigs; for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { sig = _ref2[_k]; sig = new Buffer(sig); _ref3 = this.keys["public"]; for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) { pubKey = _ref3[_l]; v = ursa.createVerifier('sha512'); v.update(data); ok = v.verify(pubKey, sig, 'base64'); if (ok) { break; } } if (ok) { break; } } } else { keys = (function() { var _results; _results = []; for (key in this.keys["public"]) { if (footer.sigs[key] != null) { _results.push(key); } } return _results; }).call(this); if (keys.length === 0) { return done('No valid keys for auth.'); } for (_m = 0, _len4 = keys.length; _m < _len4; _m++) { k = keys[_m]; try { v = ursa.createVerifier('sha512'); v.update(data); ok = v.verify(this.keys["public"][k], new Buffer(footer.sigs[k])); if (ok) { break; } } catch (_error) { e = _error; } } } if (!ok) { return done('Bad signature.'); } } this.cipher.write(data); this.push(this.cipher.read()); return done(); }; return Decrypter; })(stream.Transform); exports.SIVEncrypter = (function(_super) { __extends(SIVEncrypter, _super); function SIVEncrypter(key1, key2) { this.key1 = key1; this.key2 = key2; if (!this instanceof exports.SIVEncrypter) { return new exports.SIVEncrypter(this.key1, this.key2); } stream.Transform.call(this, { objectMode: true, decodeStrings: true }); this.leftover = new Buffer(0); } SIVEncrypter.prototype._transform = function(dump, encoding, done) { var chunk, cipher, end, hash, iv, len, more, tag, temp; while (dump.length !== 0) { len = dump.length > 16368 ? 16368 : dump.length; chunk = new Buffer(len); dump.copy(chunk); dump = dump.slice(len); hash = crypto.createHash('sha256'); hash.end(chunk); tag = hash.read(); temp = crypto.createCipher('aes-256-ctr', this.key1); temp.end(tag); iv = temp.read().slice(0, 16); cipher = crypto.createCipheriv('aes-256-ctr', this.key2, iv); cipher.end(chunk); end = Buffer.concat([iv, cipher.read()]); more = this.push(end); if (!more) { return done(); } } return done(); }; SIVEncrypter.prototype._flush = function(done) { this.push(this.leftover.length === 0 ? null : this.leftover); this.leftover = new Buffer(0); return done(); }; return SIVEncrypter; })(stream.Transform); exports.SIVDecrypter = (function(_super) { __extends(SIVDecrypter, _super); function SIVDecrypter(key1, key2) { this.key1 = key1; this.key2 = key2; if (!this instanceof exports.SIVDecrypter) { return new exports.SIVDecrypter(this.key1, this.key2); } stream.Transform.call(this, { decodeStrings: true }); } SIVDecrypter.prototype._transform = function(chunk, encoding, done) { var data, decipher, hash, iv, ivCand, pt, tag, temp; iv = chunk.slice(0, 16); data = chunk.slice(16); decipher = crypto.createDecipheriv('aes-256-ctr', this.key2, iv); decipher.end(data); pt = decipher.read(); hash = crypto.createHash('sha256'); hash.end(pt); tag = hash.read(); temp = crypto.createCipher('aes-256-ctr', this.key1); temp.end(tag); ivCand = temp.read().slice(0, 16); if (iv.toString('base64') !== ivCand.toString('base64')) { return done('Failed auth.'); } this.push(pt); return done(); }; return SIVDecrypter; })(stream.Transform); exports.XTSEncrypter = (function(_super) { __extends(XTSEncrypter, _super); function XTSEncrypter(key, cut) { this.key = key; this.cut = cut != null ? cut : 32; if (!this instanceof exports.XTSEncrypter) { return new exports.XTSEncrypter(this.key, this.cut); } stream.Transform.call(this, { decodeStrings: true }); this.cipher = crypto.createCipher('aes-256-xts', this.key); } XTSEncrypter.prototype._transform = function(dump, encoding, done) { var chunk; while (dump.length !== 0) { chunk = new Buffer(this.cut); dump.copy(chunk); dump = dump.slice(this.cut); this.cipher.write(chunk); this.push(this.cipher.read()); } return done(); }; return XTSEncrypter; })(stream.Transform); exports.XTSDecrypter = (function(_super) { __extends(XTSDecrypter, _super); function XTSDecrypter(key, cut) { this.key = key; this.cut = cut != null ? cut : 32; if (!this instanceof exports.XTSDecrypter) { return new exports.XTSDecrypter(this.key); } stream.Transform.call(this, { decodeStrings: true }); this.decipher = crypto.createDecipher('aes-256-xts', this.key); } XTSDecrypter.prototype._transform = function(dump, encoding, done) { var chunk; while (dump.length !== 0) { chunk = new Buffer(this.cut); dump.copy(chunk); dump = dump.slice(this.cut); this.decipher.write(chunk); this.push(this.decipher.read()); } return done(); }; return XTSDecrypter; })(stream.Transform); }).call(this);