caesar
Version:
An easy-to-use advanced cryptography library.
472 lines (432 loc) • 14.9 kB
JavaScript
// 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);