refactor aes.
This commit is contained in:
parent
dd8c92d5fd
commit
5f6aa10cbc
492
lib/bcoin/aes.js
492
lib/bcoin/aes.js
@ -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;
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Loading…
Reference in New Issue
Block a user