refactor aes.

This commit is contained in:
Christopher Jeffrey 2016-05-18 22:15:00 -07:00
parent dd8c92d5fd
commit 5f6aa10cbc
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
2 changed files with 331 additions and 195 deletions

View File

@ -8,51 +8,105 @@
* Entered into the public domain by Vincent Rijmen.
*/
var aes = exports;
var assert = require('assert');
/**
* An AES object for encrypting and decrypting blocks.
* @exports AES
* @constructor
* @param {Buffer} key
* @param {Number} bits
* @param {Buffer?} iv
*/
function AES(key, bits, iv) {
if (!(this instanceof AES))
return new AES(key, bits, iv);
this.userKey = key;
this.bits = bits;
this.iv = iv;
if (this.bits === 128)
this.rounds = 10;
else if (this.bits === 192)
this.rounds = 12;
else if (this.bits === 256)
this.rounds = 14;
else
throw new Error('Bad key size.');
this.decryptKey = null;
this.encryptKey = null;
}
/**
* Destroy the object and zero the keys.
*/
AES.prototype.destroy = function destroy() {
var i;
assert(this.userKey, 'Already destroyed.');
this.userKey.fill(0);
this.userKey = null;
if (this.iv) {
this.iv.fill(0);
this.iv = null;
}
if (this.decryptKey) {
for (i = 0; i < this.decryptKey.length; i++)
this.decryptKey[i] = 0;
this.decryptKey = null;
}
if (this.encryptKey) {
for (i = 0; i < this.encryptKey.length; i++)
this.encryptKey[i] = 0;
this.encryptKey = null;
}
};
/**
* Convert the user key into an encryption key.
* @param {Buffer} userKey
* @param {Number} bits
* @returns {Object} key
*/
aes.getEncryptKey = function getEncryptKey(userKey, bits) {
var key = { data: [], rounds: 0 };
var i, kp, rk, tmp;
AES.prototype.getEncryptKey = function getEncryptKey() {
var i = 0;
var key, kp, tmp;
if (bits !== 128 && bits !== 192 && bits !== 256)
throw new Error('Bad key size.');
assert(this.userKey, 'Cannot use AES once it is destroyed.');
i = 0;
if (this.encryptKey)
return this.encryptKey;
key = [];
kp = 0;
rk = key.data;
if (bits === 128)
key.rounds = 10;
else if (bits === 192)
key.rounds = 12;
else
key.rounds = 14;
key[kp + 0] = readU32(this.userKey, 0);
key[kp + 1] = readU32(this.userKey, 4);
key[kp + 2] = readU32(this.userKey, 8);
key[kp + 3] = readU32(this.userKey, 12);
rk[kp + 0] = readU32(userKey, 0);
rk[kp + 1] = readU32(userKey, 4);
rk[kp + 2] = readU32(userKey, 8);
rk[kp + 3] = readU32(userKey, 12);
this.encryptKey = key;
if (bits === 128) {
if (this.bits === 128) {
for (;;) {
tmp = rk[kp + 3];
tmp = key[kp + 3];
rk[kp + 4] = rk[kp + 0]
key[kp + 4] = key[kp + 0]
^ (TE2[(tmp >>> 16) & 0xff] & 0xff000000)
^ (TE3[(tmp >>> 8) & 0xff] & 0x00ff0000)
^ (TE0[(tmp >>> 0) & 0xff] & 0x0000ff00)
^ (TE1[(tmp >>> 24) & 0xff] & 0x000000ff)
^ RCON[i];
rk[kp + 5] = rk[kp + 1] ^ rk[kp + 4];
rk[kp + 6] = rk[kp + 2] ^ rk[kp + 5];
rk[kp + 7] = rk[kp + 3] ^ rk[kp + 6];
key[kp + 5] = key[kp + 1] ^ key[kp + 4];
key[kp + 6] = key[kp + 2] ^ key[kp + 5];
key[kp + 7] = key[kp + 3] ^ key[kp + 6];
if (++i === 10)
return key;
@ -61,62 +115,62 @@ aes.getEncryptKey = function getEncryptKey(userKey, bits) {
}
}
rk[kp + 4] = readU32(userKey, 16);
rk[kp + 5] = readU32(userKey, 20);
key[kp + 4] = readU32(this.userKey, 16);
key[kp + 5] = readU32(this.userKey, 20);
if (bits === 192) {
if (this.bits === 192) {
for (;;) {
tmp = rk[kp + 5];
tmp = key[kp + 5];
rk[kp + 6] = rk[kp + 0]
key[kp + 6] = key[kp + 0]
^ (TE2[(tmp >>> 16) & 0xff] & 0xff000000)
^ (TE3[(tmp >>> 8) & 0xff] & 0x00ff0000)
^ (TE0[(tmp >>> 0) & 0xff] & 0x0000ff00)
^ (TE1[(tmp >>> 24) & 0xff] & 0x000000ff)
^ RCON[i];
rk[kp + 7] = rk[kp + 1] ^ rk[kp + 6];
rk[kp + 8] = rk[kp + 2] ^ rk[kp + 7];
rk[kp + 9] = rk[kp + 3] ^ rk[kp + 8];
key[kp + 7] = key[kp + 1] ^ key[kp + 6];
key[kp + 8] = key[kp + 2] ^ key[kp + 7];
key[kp + 9] = key[kp + 3] ^ key[kp + 8];
if (++i === 8)
return key;
rk[kp + 10] = rk[kp + 4] ^ rk[kp + 9];
rk[kp + 11] = rk[kp + 5] ^ rk[kp + 10];
key[kp + 10] = key[kp + 4] ^ key[kp + 9];
key[kp + 11] = key[kp + 5] ^ key[kp + 10];
kp += 6;
}
}
rk[kp + 6] = readU32(userKey, 24);
rk[kp + 7] = readU32(userKey, 28);
key[kp + 6] = readU32(this.userKey, 24);
key[kp + 7] = readU32(this.userKey, 28);
if (bits === 256) {
if (this.bits === 256) {
for (;;) {
tmp = rk[kp + 7];
tmp = key[kp + 7];
rk[kp + 8] = rk[kp + 0]
key[kp + 8] = key[kp + 0]
^ (TE2[(tmp >>> 16) & 0xff] & 0xff000000)
^ (TE3[(tmp >>> 8) & 0xff] & 0x00ff0000)
^ (TE0[(tmp >>> 0) & 0xff] & 0x0000ff00)
^ (TE1[(tmp >>> 24) & 0xff] & 0x000000ff)
^ RCON[i];
rk[kp + 9] = rk[kp + 1] ^ rk[kp + 8];
rk[kp + 10] = rk[kp + 2] ^ rk[kp + 9];
rk[kp + 11] = rk[kp + 3] ^ rk[kp + 10];
key[kp + 9] = key[kp + 1] ^ key[kp + 8];
key[kp + 10] = key[kp + 2] ^ key[kp + 9];
key[kp + 11] = key[kp + 3] ^ key[kp + 10];
if (++i === 7)
return key;
tmp = rk[kp + 11];
tmp = key[kp + 11];
rk[kp + 12] = rk[kp + 4]
key[kp + 12] = key[kp + 4]
^ (TE2[(tmp >>> 24) & 0xff] & 0xff000000)
^ (TE3[(tmp >>> 16) & 0xff] & 0x00ff0000)
^ (TE0[(tmp >>> 8) & 0xff] & 0x0000ff00)
^ (TE1[(tmp >>> 0) & 0xff] & 0x000000ff);
rk[kp + 13] = rk[kp + 5] ^ rk[kp + 12];
rk[kp + 14] = rk[kp + 6] ^ rk[kp + 13];
rk[kp + 15] = rk[kp + 7] ^ rk[kp + 14];
key[kp + 13] = key[kp + 5] ^ key[kp + 12];
key[kp + 14] = key[kp + 6] ^ key[kp + 13];
key[kp + 15] = key[kp + 7] ^ key[kp + 14];
kp += 8;
}
@ -127,48 +181,62 @@ aes.getEncryptKey = function getEncryptKey(userKey, bits) {
/**
* Convert the user key into a decryption key.
* @param {Buffer} userKey
* @param {Number} bits
* @returns {Object} key
*/
aes.getDecryptKey = function getDecryptKey(userKey, bits) {
var i, j, kp, rk, key, tmp;
AES.prototype.getDecryptKey = function getDecryptKey() {
var i, j, kp, key, tmp;
assert(this.userKey, 'Cannot use AES once it is destroyed.');
if (this.decryptKey)
return this.decryptKey;
// First, start with an encryption schedule.
key = aes.getEncryptKey(userKey, bits);
key = this.getEncryptKey().slice();
kp = 0;
rk = key.data;
this.decryptKey = key;
// Invert the order of the round keys.
for (i = 0, j = 4 * key.rounds; i < j; i += 4, j -= 4) {
tmp = rk[kp + i + 0]; rk[kp + i + 0] = rk[kp + j + 0]; rk[kp + j + 0] = tmp;
tmp = rk[kp + i + 1]; rk[kp + i + 1] = rk[kp + j + 1]; rk[kp + j + 1] = tmp;
tmp = rk[kp + i + 2]; rk[kp + i + 2] = rk[kp + j + 2]; rk[kp + j + 2] = tmp;
tmp = rk[kp + i + 3]; rk[kp + i + 3] = rk[kp + j + 3]; rk[kp + j + 3] = tmp;
for (i = 0, j = 4 * this.rounds; i < j; i += 4, j -= 4) {
tmp = key[kp + i + 0];
key[kp + i + 0] = key[kp + j + 0];
key[kp + j + 0] = tmp;
tmp = key[kp + i + 1];
key[kp + i + 1] = key[kp + j + 1];
key[kp + j + 1] = tmp;
tmp = key[kp + i + 2];
key[kp + i + 2] = key[kp + j + 2];
key[kp + j + 2] = tmp;
tmp = key[kp + i + 3];
key[kp + i + 3] = key[kp + j + 3];
key[kp + j + 3] = tmp;
}
// Apply the inverse MixColumn transform to
// all round keys but the first and the last.
for (i = 1; i < key.rounds; i++) {
for (i = 1; i < this.rounds; i++) {
kp += 4;
rk[kp + 0] = TD0[TE1[(rk[kp + 0] >>> 24) & 0xff] & 0xff]
^ TD1[TE1[(rk[kp + 0] >>> 16) & 0xff] & 0xff]
^ TD2[TE1[(rk[kp + 0] >>> 8) & 0xff] & 0xff]
^ TD3[TE1[(rk[kp + 0] >>> 0) & 0xff] & 0xff];
rk[kp + 1] = TD0[TE1[(rk[kp + 1] >>> 24) & 0xff] & 0xff]
^ TD1[TE1[(rk[kp + 1] >>> 16) & 0xff] & 0xff]
^ TD2[TE1[(rk[kp + 1] >>> 8) & 0xff] & 0xff]
^ TD3[TE1[(rk[kp + 1] >>> 0) & 0xff] & 0xff];
rk[kp + 2] = TD0[TE1[(rk[kp + 2] >>> 24) & 0xff] & 0xff]
^ TD1[TE1[(rk[kp + 2] >>> 16) & 0xff] & 0xff]
^ TD2[TE1[(rk[kp + 2] >>> 8) & 0xff] & 0xff]
^ TD3[TE1[(rk[kp + 2] >>> 0) & 0xff] & 0xff];
rk[kp + 3] = TD0[TE1[(rk[kp + 3] >>> 24) & 0xff] & 0xff]
^ TD1[TE1[(rk[kp + 3] >>> 16) & 0xff] & 0xff]
^ TD2[TE1[(rk[kp + 3] >>> 8) & 0xff] & 0xff]
^ TD3[TE1[(rk[kp + 3] >>> 0) & 0xff] & 0xff];
key[kp + 0] = TD0[TE1[(key[kp + 0] >>> 24) & 0xff] & 0xff]
^ TD1[TE1[(key[kp + 0] >>> 16) & 0xff] & 0xff]
^ TD2[TE1[(key[kp + 0] >>> 8) & 0xff] & 0xff]
^ TD3[TE1[(key[kp + 0] >>> 0) & 0xff] & 0xff];
key[kp + 1] = TD0[TE1[(key[kp + 1] >>> 24) & 0xff] & 0xff]
^ TD1[TE1[(key[kp + 1] >>> 16) & 0xff] & 0xff]
^ TD2[TE1[(key[kp + 1] >>> 8) & 0xff] & 0xff]
^ TD3[TE1[(key[kp + 1] >>> 0) & 0xff] & 0xff];
key[kp + 2] = TD0[TE1[(key[kp + 2] >>> 24) & 0xff] & 0xff]
^ TD1[TE1[(key[kp + 2] >>> 16) & 0xff] & 0xff]
^ TD2[TE1[(key[kp + 2] >>> 8) & 0xff] & 0xff]
^ TD3[TE1[(key[kp + 2] >>> 0) & 0xff] & 0xff];
key[kp + 3] = TD0[TE1[(key[kp + 3] >>> 24) & 0xff] & 0xff]
^ TD1[TE1[(key[kp + 3] >>> 16) & 0xff] & 0xff]
^ TD2[TE1[(key[kp + 3] >>> 8) & 0xff] & 0xff]
^ TD3[TE1[(key[kp + 3] >>> 0) & 0xff] & 0xff];
}
return key;
@ -177,48 +245,48 @@ aes.getDecryptKey = function getDecryptKey(userKey, bits) {
/**
* Encrypt a 16 byte block of data.
* @param {Buffer} input
* @param {Object} key
* @returns {Buffer}
*/
aes.encryptBlock = function encryptBlock(input, key) {
var output = new Buffer(16);
var kp, rk, r, s0, s1, s2, s3, t0, t1, t2, t3;
AES.prototype.encryptBlock = function encryptBlock(input) {
var output, kp, key, r, s0, s1, s2, s3, t0, t1, t2, t3;
rk = key.data;
assert(this.userKey, 'Cannot use AES once it is destroyed.');
key = this.getEncryptKey();
kp = 0;
// Map byte array block to cipher
// state and add initial round key.
s0 = readU32(input, 0) ^ rk[0];
s1 = readU32(input, 4) ^ rk[1];
s2 = readU32(input, 8) ^ rk[2];
s3 = readU32(input, 12) ^ rk[3];
s0 = readU32(input, 0) ^ key[0];
s1 = readU32(input, 4) ^ key[1];
s2 = readU32(input, 8) ^ key[2];
s3 = readU32(input, 12) ^ key[3];
// Nr - 1 full rounds
r = key.rounds >>> 1;
r = this.rounds >>> 1;
for (;;) {
t0 = TE0[(s0 >>> 24) & 0xff]
^ TE1[(s1 >>> 16) & 0xff]
^ TE2[(s2 >>> 8) & 0xff]
^ TE3[(s3 >>> 0) & 0xff]
^ rk[kp + 4];
^ key[kp + 4];
t1 = TE0[(s1 >>> 24) & 0xff]
^ TE1[(s2 >>> 16) & 0xff]
^ TE2[(s3 >>> 8) & 0xff]
^ TE3[(s0 >>> 0) & 0xff]
^ rk[kp + 5];
^ key[kp + 5];
t2 = TE0[(s2 >>> 24) & 0xff]
^ TE1[(s3 >>> 16) & 0xff]
^ TE2[(s0 >>> 8) & 0xff]
^ TE3[(s1 >>> 0) & 0xff]
^ rk[kp + 6];
^ key[kp + 6];
t3 = TE0[(s3 >>> 24) & 0xff]
^ TE1[(s0 >>> 16) & 0xff]
^ TE2[(s1 >>> 8) & 0xff]
^ TE3[(s2 >>> 0) & 0xff]
^ rk[kp + 7];
^ key[kp + 7];
kp += 8;
@ -229,22 +297,22 @@ aes.encryptBlock = function encryptBlock(input, key) {
^ TE1[(t1 >>> 16) & 0xff]
^ TE2[(t2 >>> 8) & 0xff]
^ TE3[(t3 >>> 0) & 0xff]
^ rk[kp + 0];
^ key[kp + 0];
s1 = TE0[(t1 >>> 24) & 0xff]
^ TE1[(t2 >>> 16) & 0xff]
^ TE2[(t3 >>> 8) & 0xff]
^ TE3[(t0 >>> 0) & 0xff]
^ rk[kp + 1];
^ key[kp + 1];
s2 = TE0[(t2 >>> 24) & 0xff]
^ TE1[(t3 >>> 16) & 0xff]
^ TE2[(t0 >>> 8) & 0xff]
^ TE3[(t1 >>> 0) & 0xff]
^ rk[kp + 2];
^ key[kp + 2];
s3 = TE0[(t3 >>> 24) & 0xff]
^ TE1[(t0 >>> 16) & 0xff]
^ TE2[(t1 >>> 8) & 0xff]
^ TE3[(t2 >>> 0) & 0xff]
^ rk[kp + 3];
^ key[kp + 3];
}
// Apply last round and map cipher
@ -253,23 +321,24 @@ aes.encryptBlock = function encryptBlock(input, key) {
^ (TE3[(t1 >>> 16) & 0xff] & 0x00ff0000)
^ (TE0[(t2 >>> 8) & 0xff] & 0x0000ff00)
^ (TE1[(t3 >>> 0) & 0xff] & 0x000000ff)
^ rk[kp + 0];
^ key[kp + 0];
s1 = (TE2[(t1 >>> 24) & 0xff] & 0xff000000)
^ (TE3[(t2 >>> 16) & 0xff] & 0x00ff0000)
^ (TE0[(t3 >>> 8) & 0xff] & 0x0000ff00)
^ (TE1[(t0 >>> 0) & 0xff] & 0x000000ff)
^ rk[kp + 1];
^ key[kp + 1];
s2 = (TE2[(t2 >>> 24) & 0xff] & 0xff000000)
^ (TE3[(t3 >>> 16) & 0xff] & 0x00ff0000)
^ (TE0[(t0 >>> 8) & 0xff] & 0x0000ff00)
^ (TE1[(t1 >>> 0) & 0xff] & 0x000000ff)
^ rk[kp + 2];
^ key[kp + 2];
s3 = (TE2[(t3 >>> 24) & 0xff] & 0xff000000)
^ (TE3[(t0 >>> 16) & 0xff] & 0x00ff0000)
^ (TE0[(t1 >>> 8) & 0xff] & 0x0000ff00)
^ (TE1[(t2 >>> 0) & 0xff] & 0x000000ff)
^ rk[kp + 3];
^ key[kp + 3];
output = new Buffer(16);
writeU32(output, s0, 0);
writeU32(output, s1, 4);
writeU32(output, s2, 8);
@ -281,48 +350,48 @@ aes.encryptBlock = function encryptBlock(input, key) {
/**
* Decrypt a 16 byte block of data.
* @param {Buffer} input
* @param {Object} key
* @returns {Buffer}
*/
aes.decryptBlock = function decryptBlock(input, key) {
var output = new Buffer(16);
var kp, rk, r, s0, s1, s2, s3, t0, t1, t2, t3;
AES.prototype.decryptBlock = function decryptBlock(input) {
var output, kp, key, r, s0, s1, s2, s3, t0, t1, t2, t3;
assert(this.userKey, 'Cannot use AES once it is destroyed.');
key = this.getDecryptKey();
kp = 0;
rk = key.data;
// Map byte array block to cipher
// state and add initial round key.
s0 = readU32(input, 0) ^ rk[kp + 0];
s1 = readU32(input, 4) ^ rk[kp + 1];
s2 = readU32(input, 8) ^ rk[kp + 2];
s3 = readU32(input, 12) ^ rk[kp + 3];
s0 = readU32(input, 0) ^ key[kp + 0];
s1 = readU32(input, 4) ^ key[kp + 1];
s2 = readU32(input, 8) ^ key[kp + 2];
s3 = readU32(input, 12) ^ key[kp + 3];
// Nr - 1 full rounds
r = key.rounds >>> 1;
r = this.rounds >>> 1;
for (;;) {
t0 = TD0[(s0 >>> 24) & 0xff]
^ TD1[(s3 >>> 16) & 0xff]
^ TD2[(s2 >>> 8) & 0xff]
^ TD3[(s1 >>> 0) & 0xff]
^ rk[kp + 4];
^ key[kp + 4];
t1 = TD0[(s1 >>> 24) & 0xff]
^ TD1[(s0 >>> 16) & 0xff]
^ TD2[(s3 >>> 8) & 0xff]
^ TD3[(s2 >>> 0) & 0xff]
^ rk[kp + 5];
^ key[kp + 5];
t2 = TD0[(s2 >>> 24) & 0xff]
^ TD1[(s1 >>> 16) & 0xff]
^ TD2[(s0 >>> 8) & 0xff]
^ TD3[(s3 >>> 0) & 0xff]
^ rk[kp + 6];
^ key[kp + 6];
t3 = TD0[(s3 >>> 24) & 0xff]
^ TD1[(s2 >>> 16) & 0xff]
^ TD2[(s1 >>> 8) & 0xff]
^ TD3[(s0 >>> 0) & 0xff]
^ rk[kp + 7];
^ key[kp + 7];
kp += 8;
@ -333,22 +402,22 @@ aes.decryptBlock = function decryptBlock(input, key) {
^ TD1[(t3 >>> 16) & 0xff]
^ TD2[(t2 >>> 8) & 0xff]
^ TD3[(t1 >>> 0) & 0xff]
^ rk[kp + 0];
^ key[kp + 0];
s1 = TD0[(t1 >>> 24) & 0xff]
^ TD1[(t0 >>> 16) & 0xff]
^ TD2[(t3 >>> 8) & 0xff]
^ TD3[(t2 >>> 0) & 0xff]
^ rk[kp + 1];
^ key[kp + 1];
s2 = TD0[(t2 >>> 24) & 0xff]
^ TD1[(t1 >>> 16) & 0xff]
^ TD2[(t0 >>> 8) & 0xff]
^ TD3[(t3 >>> 0) & 0xff]
^ rk[kp + 2];
^ key[kp + 2];
s3 = TD0[(t3 >>> 24) & 0xff]
^ TD1[(t2 >>> 16) & 0xff]
^ TD2[(t1 >>> 8) & 0xff]
^ TD3[(t0 >>> 0) & 0xff]
^ rk[kp + 3];
^ key[kp + 3];
}
// Apply last round and map cipher
@ -357,23 +426,24 @@ aes.decryptBlock = function decryptBlock(input, key) {
^ (TD4[(t3 >>> 16) & 0xff] << 16)
^ (TD4[(t2 >>> 8) & 0xff] << 8)
^ (TD4[(t1 >>> 0) & 0xff] << 0)
^ rk[kp + 0];
^ key[kp + 0];
s1 = (TD4[(t1 >>> 24) & 0xff] << 24)
^ (TD4[(t0 >>> 16) & 0xff] << 16)
^ (TD4[(t3 >>> 8) & 0xff] << 8)
^ (TD4[(t2 >>> 0) & 0xff] << 0)
^ rk[kp + 1];
^ key[kp + 1];
s2 = (TD4[(t2 >>> 24) & 0xff] << 24)
^ (TD4[(t1 >>> 16) & 0xff] << 16)
^ (TD4[(t0 >>> 8) & 0xff] << 8)
^ (TD4[(t3 >>> 0) & 0xff] << 0)
^ rk[kp + 2];
^ key[kp + 2];
s3 = (TD4[(t3 >>> 24) & 0xff] << 24)
^ (TD4[(t2 >>> 16) & 0xff] << 16)
^ (TD4[(t1 >>> 8) & 0xff] << 8)
^ (TD4[(t0 >>> 0) & 0xff] << 0)
^ rk[kp + 3];
^ key[kp + 3];
output = new Buffer(16);
writeU32(output, s0, 0);
writeU32(output, s1, 4);
writeU32(output, s2, 8);
@ -383,103 +453,146 @@ aes.decryptBlock = function decryptBlock(input, key) {
};
/**
* Encrypt data with aes 256 (no chaining).
* Encrypt data with aes 256.
* @param {Buffer} data
* @param {Buffer} key
* @param {Buffer} iv
* @param {Boolean?} chain - XOR chaining (cbc).
* @returns {Buffer}
*/
aes.encrypt = function encrypt(data, key, iv, chain) {
var i, out, key, prev, block, left, pad;
AES.encrypt = function encrypt(data, key, iv, chain) {
var aes = new AES(key, 256, iv);
var trailing = data.length % 16;
var len = data.length - trailing;
var blocks = [];
var i, prev, block, left, pad;
key = aes.getEncryptKey(key, 256);
prev = iv;
out = [];
// Setup initialization vector.
prev = aes.iv;
for (i = 0; i < data.length; i += 16) {
// Encrypt all blocks except for the last.
for (i = 0; i < len; i += 16) {
block = data.slice(i, i + 16);
if (i + 16 >= data.length) {
left = 16 - block.length;
if (left === 0) {
pad = new Buffer(16);
pad.fill(16);
if (chain)
block = xor(block, prev);
prev = aes.encryptBlock(block, key);
out.push(prev);
block = pad;
} else {
pad = new Buffer(left);
pad.fill(left);
block = Buffer.concat([block, pad]);
}
}
if (chain)
block = xor(block, prev);
prev = aes.encryptBlock(block, key);
out.push(prev);
prev = aes.encryptBlock(block);
blocks.push(prev);
}
return Buffer.concat(out);
// Handle padding on the last block.
if (trailing === 0) {
block = new Buffer(16);
block.fill(16);
} else {
block = data.slice(len, len + trailing);
left = 16 - trailing;
pad = new Buffer(left);
pad.fill(left);
block = Buffer.concat([block, pad]);
}
// Encrypt the last block,
// as well as the padding.
if (chain)
block = xor(block, prev);
block = aes.encryptBlock(block);
blocks.push(block);
aes.destroy();
return Buffer.concat(blocks);
};
/**
* Decrypt data with aes 256 (no chaining).
* Derives key from passphrase automatically.
* Decrypt data with aes 256.
* @param {Buffer} data
* @param {Buffer} key
* @param {Buffer} iv
* @param {Boolean?} chain - XOR chaining (cbc).
* @returns {Buffer}
*/
aes.decrypt = function decrypt(data, key, iv, chain) {
var i, j, b, n, out, key, prev, chunk, block;
AES.decrypt = function decrypt(data, key, iv, chain) {
var aes = new AES(key, 256, iv);
var blocks = [];
var i, b, n, prev, chunk, block;
key = aes.getDecryptKey(key, 256);
prev = iv;
out = [];
assert(data.length > 0);
assert(data.length % 16 === 0);
// Setup initialization vector.
prev = aes.iv;
// Decrypt all blocks.
for (i = 0; i < data.length; i += 16) {
chunk = prev;
prev = data.slice(i, i + 16);
block = aes.decryptBlock(prev, key);
block = aes.decryptBlock(prev);
if (chain)
block = xor(block, chunk);
if (i + 16 >= data.length) {
b = 16;
n = block[b - 1];
if (n === 0 || n > b)
throw new Error('Bad decrypt');
for (j = 0; j < n; j++) {
if (block[--b] !== n)
throw new Error('Bad decrypt');
}
if (n === 16)
break;
block = block.slice(0, -n);
}
out.push(block);
blocks.push(block);
}
return Buffer.concat(out);
// Check padding on the last block.
block = blocks.pop();
b = 16;
n = block[b - 1];
if (n === 0 || n > b)
throw new Error('Bad decrypt');
for (i = 0; i < n; i++) {
if (block[--b] !== n)
throw new Error('Bad decrypt');
}
// Slice off the padding unless
// the entire block was padding.
if (n < 16) {
block = block.slice(0, -n);
blocks.push(block);
}
aes.destroy();
return Buffer.concat(blocks);
};
/**
* Electronic codebook mode.
*/
AES.ecb = {};
/**
* Encrypt data with aes 256 ecb.
* @param {Buffer} data
* @param {Buffer} key
* @returns {Buffer}
*/
AES.ecb.encrypt = function encrypt(data, key) {
return AES.encrypt(data, key, null, false);
};
/**
* Decrypt data with aes 256 ecb.
* @param {Buffer} data
* @param {Buffer} key
* @returns {Buffer}
*/
AES.ecb.decrypt = function decrypt(data, key) {
return AES.decrypt(data, key, null, false);
};
/**
* Cipher block chaining mode.
*/
aes.cbc = {};
AES.cbc = {};
/**
* Encrypt data with aes 256 cbc.
@ -489,21 +602,20 @@ aes.cbc = {};
* @returns {Buffer}
*/
aes.cbc.encrypt = function encrypt(data, key, iv) {
return aes.encrypt(data, key, iv, true);
AES.cbc.encrypt = function encrypt(data, key, iv) {
return AES.encrypt(data, key, iv, true);
};
/**
* Decrypt data with aes 256 cbc.
* Derives key from passphrase automatically.
* @param {Buffer} data
* @param {Buffer} key
* @param {Buffer} iv
* @returns {Buffer}
*/
aes.cbc.decrypt = function decrypt(data, key, iv) {
return aes.decrypt(data, key, iv, true);
AES.cbc.decrypt = function decrypt(data, key, iv) {
return AES.decrypt(data, key, iv, true);
};
/*
@ -1111,3 +1223,9 @@ var RCON = [
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x1B000000, 0x36000000
];
/*
* Expose
*/
module.exports = AES;

View File

@ -398,7 +398,7 @@ utils.pbkdf2 = function pbkdf2(key, salt, iterations, dkLen, alg) {
*/
utils.encrypt = function encrypt(data, passphrase) {
var key, cipher;
var key, cipher, out;
assert(crypto, 'No crypto module available.');
assert(passphrase, 'No passphrase.');
@ -411,15 +411,24 @@ utils.encrypt = function encrypt(data, passphrase) {
key = utils.pbkdf2key(passphrase, null, 2048, 32, 16);
if (!crypto)
return aes.cbc.encrypt(data, key.key, key.iv);
if (!crypto) {
out = aes.cbc.encrypt(data, key.key, key.iv);
key.key.fill(0);
key.iv.fill(0);
return out;
}
cipher = crypto.createCipheriv('aes-256-cbc', key.key, key.iv);
return Buffer.concat([
out = Buffer.concat([
cipher.update(data),
cipher.final()
]);
key.key.fill(0);
key.iv.fill(0);
return out;
};
/**
@ -430,7 +439,7 @@ utils.encrypt = function encrypt(data, passphrase) {
*/
utils.decrypt = function decrypt(data, passphrase) {
var key, decipher;
var key, decipher, out;
assert(crypto, 'No crypto module available.');
assert(passphrase, 'No passphrase.');
@ -443,15 +452,24 @@ utils.decrypt = function decrypt(data, passphrase) {
key = utils.pbkdf2key(passphrase, null, 2048, 32, 16);
if (!crypto)
return aes.cbc.decrypt(data, key.key, key.iv);
if (!crypto) {
out = aes.cbc.decrypt(data, key.key, key.iv);
key.key.fill(0);
key.iv.fill(0);
return out;
}
decipher = crypto.createDecipheriv('aes-256-cbc', key.key, key.iv);
return Buffer.concat([
out = Buffer.concat([
decipher.update(data),
decipher.final()
]);
key.key.fill(0);
key.iv.fill(0);
return out;
};
/**