Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ function randomBytes(size) {
return Buffer.from(arr);
}

function sha256(msg) {
return subtle.digest({name: "SHA-256"}, msg).then(function(hash) {
return new Buffer(new Uint8Array(hash));
});
}

function sha512(msg) {
return new Promise(function(resolve) {
var hash = nodeCrypto.createHash('sha512');
Expand Down Expand Up @@ -218,11 +224,11 @@ exports.encrypt = function(publicKeyTo, msg, opts) {
ephemPublicKey = getPublic(ephemPrivateKey);
resolve(derive(ephemPrivateKey, publicKeyTo));
}).then(function(Px) {
return sha512(Px);
return ('aes128cbc' in opts) ? sha256(Px) : sha512(Px);
}).then(function(hash) {
iv = opts.iv || randomBytes(16);
var encryptionKey = hash.slice(0, 32);
macKey = hash.slice(32);
var encryptionKey = ('aes128cbc' in opts) ? hash.slice(0, 16) : hash.slice(0, 32);
macKey = ('aes128cbc' in opts) ? hash.slice(16) : hash.slice(32);
return aesCbcEncrypt(iv, encryptionKey, msg);
}).then(function(data) {
ciphertext = data;
Expand Down
47 changes: 37 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,33 @@ function assert(condition, message) {
}
}

function sha256(msg) {
return crypto.createHash("sha256").update(msg).digest();
}

function sha512(msg) {
return crypto.createHash("sha512").update(msg).digest();
}

function aes128CbcEncrypt(iv, key, plaintext) {
var cipher = crypto.createCipheriv("aes-128-cbc", key, iv);
cipher.setAutoPadding(false)
var firstChunk = cipher.update(plaintext);
var secondChunk = cipher.final();
return Buffer.concat([firstChunk, secondChunk]);
}

function aes128CbcDecrypt(iv, key, ciphertext) {
var cipher = crypto.createDecipheriv("aes-128-cbc", key, iv);
cipher.setAutoPadding(false)
var firstChunk = cipher.update(ciphertext);
var secondChunk = cipher.final();
return Buffer.concat([firstChunk, secondChunk]);
}

function aes256CbcEncrypt(iv, key, plaintext) {
var cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
cipher.setAutoPadding(false)
var firstChunk = cipher.update(plaintext);
var secondChunk = cipher.final();
return Buffer.concat([firstChunk, secondChunk]);
Expand Down Expand Up @@ -216,11 +237,11 @@ exports.encrypt = function(publicKeyTo, msg, opts) {
ephemPublicKey = getPublic(ephemPrivateKey);
resolve(derive(ephemPrivateKey, publicKeyTo));
}).then(function(Px) {
var hash = sha512(Px);
var hash = ('aes128cbc' in opts) ? sha256(Px) : sha512(Px);
var iv = opts.iv || crypto.randomBytes(16);
var encryptionKey = hash.slice(0, 32);
var macKey = hash.slice(32);
var ciphertext = aes256CbcEncrypt(iv, encryptionKey, msg);
var encryptionKey = ('aes128cbc' in opts) ? hash.slice(0, 16) : hash.slice(0, 32);
var macKey = ('aes128cbc' in opts) ? hash.slice(16) : hash.slice(0, 32);
var ciphertext = ('aes128cbc' in opts) ? aes128CbcEncrypt(iv, encryptionKey, msg) : aes256CbcEncrypt(iv, encryptionKey, msg);
var dataToMac = Buffer.concat([iv, ephemPublicKey, ciphertext]);
var mac = Buffer.from(hmacSha256(macKey, dataToMac));
return {
Expand All @@ -242,17 +263,23 @@ exports.encrypt = function(publicKeyTo, msg, opts) {
*/
exports.decrypt = function(privateKey, opts) {
return derive(privateKey, opts.ephemPublicKey).then(function(Px) {
assert(privateKey.length === 32, "Bad private key");
assert(isValidPrivateKey(privateKey), "Bad private key");
var hash = sha512(Px);
var encryptionKey = hash.slice(0, 32);
var macKey = hash.slice(32);
if ('aes128cbc' in opts) {
assert(privateKey.length === 16, "Bad private key");
assert(isValidPrivateKey(privateKey), "Bad private key");
} else {
assert(privateKey.length === 32, "Bad private key");
assert(isValidPrivateKey(privateKey), "Bad private key");
}
var hash = ('aes128cbc' in opts) ? sha256(Px) : sha512(Px);
var encryptionKey = ('aes128cbc' in opts) ? hash.slice(0, 16) : hash.slice(0, 32);
var macKey = ('aes128cbc' in opts) ? hash.slice(16) : hash.slice(32);
var dataToMac = Buffer.concat([
opts.iv,
opts.ephemPublicKey,
opts.ciphertext
]);
var realMac = hmacSha256(macKey, dataToMac);
assert(equalConstTime(opts.mac, realMac), "Bad MAC"); return aes256CbcDecrypt(opts.iv, encryptionKey, opts.ciphertext);
assert(equalConstTime(opts.mac, realMac), "Bad MAC");
return ('aes128cbc' in opts) ? aes128CbcDecrypt(opts.iv, encryptionKey, opts.ciphertext) : aes256CbcDecrypt(opts.iv, encryptionKey, opts.ciphertext);
});
};