node-forge
Advanced tools
Comparing version 0.1.7 to 0.1.8
442
js/aes.js
@@ -862,235 +862,277 @@ /** | ||
// key must be an array of 32-bit integers by now | ||
if(forge.util.isArray(key) && | ||
(key.length === 4 || key.length === 6 || key.length === 8)) { | ||
// private vars for state (CFB always uses encryption) | ||
var _w = expandKey(key, decrypt && mode !== 'CFB'); | ||
var _blockSize = Nb << 2; | ||
var _input; | ||
var _output; | ||
var _inBlock; | ||
var _outBlock; | ||
var _prev; | ||
var _finish; | ||
cipher = { | ||
// output from AES (either encrypted or decrypted bytes) | ||
output: null | ||
}; | ||
if(!forge.util.isArray(key) || | ||
!(key.length === 4 || key.length === 6 || key.length === 8)) { | ||
return cipher; | ||
} | ||
/** | ||
* Updates the next block according to the cipher mode. | ||
* | ||
* @param input the buffer to read from. | ||
*/ | ||
cipher.update = null; | ||
// private vars for state (CFB/OFB/CTR always uses encryption) | ||
var alwaysEncrypt = (['CFB', 'OFB', 'CTR'].indexOf(mode) !== -1); | ||
var _w = expandKey(key, decrypt && !alwaysEncrypt); | ||
var _blockSize = Nb << 2; | ||
var _input; | ||
var _output; | ||
var _inBlock; | ||
var _outBlock; | ||
var _prev; | ||
var _finish; | ||
var _op; | ||
cipher = { | ||
// output from AES (either encrypted or decrypted bytes) | ||
output: null | ||
}; | ||
if(mode === 'CBC') { | ||
cipher.update = function(input) { | ||
if(!_finish) { | ||
// not finishing, so fill the input buffer with more input | ||
_input.putBuffer(input); | ||
} | ||
if(mode === 'CBC') { | ||
_op = cbcOp; | ||
} | ||
else if(mode === 'CFB') { | ||
_op = cfbOp; | ||
} | ||
else if(mode === 'OFB') { | ||
_op = ofbOp; | ||
} | ||
else if(mode === 'CTR') { | ||
_op = ctrOp; | ||
} | ||
else { | ||
throw { | ||
message: 'Unsupported block cipher mode of operation: "' + mode + '"' | ||
} | ||
} | ||
/* In encrypt mode, the threshold for updating a block is the | ||
block size. As soon as enough input is available to update | ||
a block, encryption may occur. In decrypt mode, we wait for | ||
2 blocks to be available or for the finish flag to be set | ||
with only 1 block available. This is done so that the output | ||
buffer will not be populated with padding bytes at the end | ||
of the decryption -- they can be truncated before returning | ||
from finish(). */ | ||
var threshold = decrypt && !_finish ? _blockSize << 1 : _blockSize; | ||
while(_input.length() >= threshold) { | ||
// get next block | ||
if(decrypt) { | ||
for(var i = 0; i < Nb; ++i) { | ||
_inBlock[i] = _input.getInt32(); | ||
} | ||
} | ||
else { | ||
// CBC XOR's IV (or previous block) with plaintext | ||
for(var i = 0; i < Nb; ++i) { | ||
_inBlock[i] = _prev[i] ^ _input.getInt32(); | ||
} | ||
} | ||
// update block | ||
_updateBlock(_w, _inBlock, _outBlock, decrypt); | ||
// write output, save previous ciphered block | ||
if(decrypt) { | ||
// CBC XOR's IV (or previous block) with ciphertext | ||
for(var i = 0; i < Nb; ++i) { | ||
_output.putInt32(_prev[i] ^ _outBlock[i]); | ||
} | ||
_prev = _inBlock.slice(0); | ||
} | ||
else { | ||
for(var i = 0; i < Nb; ++i) { | ||
_output.putInt32(_outBlock[i]); | ||
} | ||
_prev = _outBlock; | ||
} | ||
} | ||
}; | ||
/** | ||
* Updates the next block according to the cipher mode. | ||
* | ||
* @param input the buffer to read from. | ||
*/ | ||
cipher.update = function(input) { | ||
if(!_finish) { | ||
// not finishing, so fill the input buffer with more input | ||
_input.putBuffer(input); | ||
} | ||
else if(mode === 'CFB') { | ||
cipher.update = function(input) { | ||
if(!_finish) { | ||
// not finishing, so fill the input buffer with more input | ||
_input.putBuffer(input); | ||
} | ||
/* In encrypt mode, the threshold for updating a block is the | ||
block size. As soon as enough input is available to update | ||
a block, encryption may occur. In decrypt mode, we wait for | ||
2 blocks to be available or for the finish flag to be set | ||
with only 1 block available. This is done so that the output | ||
buffer will not be populated with padding bytes at the end | ||
of the decryption -- they can be truncated before returning | ||
from finish(). */ | ||
var threshold = decrypt && !_finish ? _blockSize << 1 : _blockSize; | ||
while(_input.length() >= threshold) { | ||
// update block (CFB always uses encryption mode) | ||
_updateBlock(_w, _inBlock, _outBlock, false); | ||
/* In encrypt mode, the threshold for updating a block is the | ||
block size. As soon as enough input is available to update | ||
a block, encryption may occur. In decrypt mode, we wait for | ||
2 blocks to be available or for the finish flag to be set | ||
with only 1 block available. This is done so that the output | ||
buffer will not be populated with padding bytes at the end | ||
of the decryption -- they can be truncated before returning | ||
from finish(). */ | ||
var threshold = decrypt && !_finish ? _blockSize << 1 : _blockSize; | ||
while(_input.length() >= threshold) { _op(); } | ||
}; | ||
// get next input | ||
for(var i = 0; i < Nb; ++i) { | ||
_inBlock[i] = _input.getInt32(); | ||
} | ||
/** | ||
* Finishes encrypting or decrypting. | ||
* | ||
* @param pad a padding function to use, null for default, | ||
* signature(blockSize, buffer, decrypt). | ||
* | ||
* @return true if successful, false on error. | ||
*/ | ||
cipher.finish = function(pad) { | ||
var rval = true; | ||
// XOR input with output | ||
for(var i = 0; i < Nb; ++i) { | ||
var result = _inBlock[i] ^ _outBlock[i]; | ||
if(!decrypt) { | ||
// update next input block when encrypting | ||
_inBlock[i] = result; | ||
} | ||
_output.putInt32(result); | ||
} | ||
} | ||
}; | ||
if(!decrypt) { | ||
if(pad) { | ||
rval = pad(_blockSize, _input, decrypt); | ||
} | ||
else { | ||
// add PKCS#7 padding to block (each pad byte is the | ||
// value of the number of pad bytes) | ||
var padding = (_input.length() === _blockSize) ? | ||
_blockSize : (_blockSize - _input.length()); | ||
_input.fillWithByte(padding, padding); | ||
} | ||
} | ||
/** | ||
* Finishes encrypting or decrypting. | ||
* | ||
* @param pad a padding function to use, null for default, | ||
* signature(blockSize, buffer, decrypt). | ||
* | ||
* @return true if successful, false on error. | ||
*/ | ||
cipher.finish = function(pad) { | ||
var rval = true; | ||
if(rval) { | ||
// do final update | ||
_finish = true; | ||
cipher.update(); | ||
} | ||
if(!decrypt) { | ||
if(decrypt) { | ||
// check for error: input data not a multiple of blockSize | ||
rval = (_input.length() === 0); | ||
if(rval) { | ||
if(pad) { | ||
rval = pad(_blockSize, _input, decrypt); | ||
rval = pad(_blockSize, _output, decrypt); | ||
} | ||
else { | ||
// add PKCS#7 padding to block (each pad byte is the | ||
// value of the number of pad bytes) | ||
var padding = (_input.length() === _blockSize) ? | ||
_blockSize : (_blockSize - _input.length()); | ||
_input.fillWithByte(padding, padding); | ||
// ensure padding byte count is valid | ||
var len = _output.length(); | ||
var count = _output.at(len - 1); | ||
if(count > (Nb << 2)) { | ||
rval = false; | ||
} | ||
else { | ||
// trim off padding bytes | ||
_output.truncate(count); | ||
} | ||
} | ||
} | ||
} | ||
if(rval) { | ||
// do final update | ||
_finish = true; | ||
cipher.update(); | ||
return rval; | ||
}; | ||
/** | ||
* Starts or restarts the encryption or decryption process, whichever | ||
* was previously configured. | ||
* | ||
* The iv may be given as a string of bytes, an array of bytes, a | ||
* byte buffer, or an array of 32-bit words. | ||
* | ||
* @param iv the initialization vector to use, null to reuse the | ||
* last ciphered block from a previous update(). | ||
* @param output the output the buffer to write to, null to create one. | ||
*/ | ||
cipher.start = function(iv, output) { | ||
// if IV is null, reuse block from previous encryption/decryption | ||
if(iv === null) { | ||
iv = _prev.slice(0); | ||
} | ||
/* Note: The IV may be a string of bytes, an array of bytes, a | ||
byte buffer, or an array of 32-bit integers. If the IV is in | ||
bytes, then it must be Nb (16) bytes in length. If it is in | ||
32-bit integers, then it must be 4 integers long. */ | ||
// convert iv string into byte buffer | ||
if(typeof iv === 'string' && iv.length === 16) { | ||
iv = forge.util.createBuffer(iv); | ||
} | ||
// convert iv byte array into byte buffer | ||
else if(forge.util.isArray(iv) && iv.length === 16) { | ||
var tmp = iv; | ||
var iv = forge.util.createBuffer(); | ||
for(var i = 0; i < 16; ++i) { | ||
iv.putByte(tmp[i]); | ||
} | ||
} | ||
if(decrypt) { | ||
// check for error: input data not a multiple of blockSize | ||
rval = (_input.length() === 0); | ||
if(rval) { | ||
if(pad) { | ||
rval = pad(_blockSize, _output, decrypt); | ||
} | ||
else { | ||
// ensure padding byte count is valid | ||
var len = _output.length(); | ||
var count = _output.at(len - 1); | ||
if(count > (Nb << 2)) { | ||
rval = false; | ||
} | ||
else { | ||
// trim off padding bytes | ||
_output.truncate(count); | ||
} | ||
} | ||
} | ||
// convert iv byte buffer into 32-bit integer array | ||
if(!forge.util.isArray(iv)) { | ||
var tmp = iv; | ||
iv = new Array(4); | ||
iv[0] = tmp.getInt32(); | ||
iv[1] = tmp.getInt32(); | ||
iv[2] = tmp.getInt32(); | ||
iv[3] = tmp.getInt32(); | ||
} | ||
// set private vars | ||
_input = forge.util.createBuffer(); | ||
_output = output || forge.util.createBuffer(); | ||
_prev = iv.slice(0); | ||
_inBlock = new Array(Nb); | ||
_outBlock = new Array(Nb); | ||
_finish = false; | ||
cipher.output = _output; | ||
// CFB/OFB/CTR uses IV as first input | ||
if(['CFB', 'OFB', 'CTR'].indexOf(mode) !== -1) { | ||
for(var i = 0; i < Nb; ++i) { | ||
_inBlock[i] = _prev[i]; | ||
} | ||
_prev = null; | ||
} | ||
}; | ||
if(iv !== null) { | ||
cipher.start(iv, output); | ||
} | ||
return cipher; | ||
return rval; | ||
}; | ||
// block cipher mode operations: | ||
/** | ||
* Starts or restarts the encryption or decryption process, whichever | ||
* was previously configured. | ||
* | ||
* The iv may be given as a string of bytes, an array of bytes, a | ||
* byte buffer, or an array of 32-bit words. | ||
* | ||
* @param iv the initialization vector to use, null to reuse the | ||
* last ciphered block from a previous update(). | ||
* @param output the output the buffer to write to, null to create one. | ||
*/ | ||
cipher.start = function(iv, output) { | ||
// if IV is null, reuse block from previous encryption/decryption | ||
if(iv === null) { | ||
iv = _prev.slice(0); | ||
function cbcOp() { | ||
// get next block | ||
if(decrypt) { | ||
for(var i = 0; i < Nb; ++i) { | ||
_inBlock[i] = _input.getInt32(); | ||
} | ||
} | ||
else { | ||
// CBC XOR's IV (or previous block) with plaintext | ||
for(var i = 0; i < Nb; ++i) { | ||
_inBlock[i] = _prev[i] ^ _input.getInt32(); | ||
} | ||
} | ||
/* Note: The IV may be a string of bytes, an array of bytes, a | ||
byte buffer, or an array of 32-bit integers. If the IV is in | ||
bytes, then it must be Nb (16) bytes in length. If it is in | ||
32-bit integers, then it must be 4 integers long. */ | ||
// update block | ||
_updateBlock(_w, _inBlock, _outBlock, decrypt); | ||
// convert iv string into byte buffer | ||
if(typeof iv === 'string' && iv.length === 16) { | ||
iv = forge.util.createBuffer(iv); | ||
// write output, save previous ciphered block | ||
if(decrypt) { | ||
// CBC XOR's IV (or previous block) with ciphertext | ||
for(var i = 0; i < Nb; ++i) { | ||
_output.putInt32(_prev[i] ^ _outBlock[i]); | ||
} | ||
// convert iv byte array into byte buffer | ||
else if(forge.util.isArray(iv) && iv.length === 16) { | ||
var tmp = iv; | ||
var iv = forge.util.createBuffer(); | ||
for(var i = 0; i < 16; ++i) { | ||
iv.putByte(tmp[i]); | ||
} | ||
_prev = _inBlock.slice(0); | ||
} | ||
else { | ||
for(var i = 0; i < Nb; ++i) { | ||
_output.putInt32(_outBlock[i]); | ||
} | ||
_prev = _outBlock; | ||
} | ||
} | ||
// convert iv byte buffer into 32-bit integer array | ||
if(!forge.util.isArray(iv)) { | ||
var tmp = iv; | ||
iv = new Array(4); | ||
iv[0] = tmp.getInt32(); | ||
iv[1] = tmp.getInt32(); | ||
iv[2] = tmp.getInt32(); | ||
iv[3] = tmp.getInt32(); | ||
function cfbOp() { | ||
// update block (CFB always uses encryption mode) | ||
_updateBlock(_w, _inBlock, _outBlock, false); | ||
// get next input | ||
for(var i = 0; i < Nb; ++i) { | ||
_inBlock[i] = _input.getInt32(); | ||
} | ||
// XOR input with output | ||
for(var i = 0; i < Nb; ++i) { | ||
var result = _inBlock[i] ^ _outBlock[i]; | ||
if(!decrypt) { | ||
// update next input block when encrypting | ||
_inBlock[i] = result; | ||
} | ||
_output.putInt32(result); | ||
} | ||
} | ||
// set private vars | ||
_input = forge.util.createBuffer(); | ||
_output = output || forge.util.createBuffer(); | ||
_prev = iv.slice(0); | ||
_inBlock = new Array(Nb); | ||
_outBlock = new Array(Nb); | ||
_finish = false; | ||
cipher.output = _output; | ||
function ofbOp() { | ||
// update block (OFB always uses encryption mode) | ||
_updateBlock(_w, _inBlock, _outBlock, false); | ||
// CFB uses IV as first input | ||
if(mode === 'CFB') { | ||
for(var i = 0; i < Nb; ++i) { | ||
_inBlock[i] = _prev[i]; | ||
} | ||
_prev = null; | ||
// get next input | ||
for(var i = 0; i < Nb; ++i) { | ||
_inBlock[i] = _input.getInt32(); | ||
} | ||
// XOR input with output and update next input | ||
for(var i = 0; i < Nb; ++i) { | ||
_output.putInt32(_inBlock[i] ^ _outBlock[i]); | ||
_inBlock[i] = _outBlock[i]; | ||
} | ||
} | ||
function ctrOp() { | ||
// update block (CTR always uses encryption mode) | ||
_updateBlock(_w, _inBlock, _outBlock, false); | ||
// increment counter (input block) | ||
for(var i = Nb - 1; i >= 0; --i) { | ||
if(_inBlock[i] === 0xFFFFFFFF) { | ||
_inBlock[i] = 0; | ||
} | ||
}; | ||
if(iv !== null) { | ||
cipher.start(iv, output); | ||
else { | ||
++_inBlock[i]; | ||
break; | ||
} | ||
} | ||
// XOR input with output | ||
for(var i = 0; i < Nb; ++i) { | ||
_output.putInt32(_input.getInt32() ^ _outBlock[i]); | ||
} | ||
} | ||
return cipher; | ||
}; | ||
@@ -1097,0 +1139,0 @@ |
{ | ||
"name": "node-forge", | ||
"version": "0.1.7", | ||
"version": "0.1.8", | ||
"description": "JavaScript implementations of network transports, cryptography, ciphers, PKI, message digests, and various utilties.", | ||
@@ -5,0 +5,0 @@ "homepage": "http://github.com/digitalbazaar/forge", |
@@ -321,3 +321,3 @@ # Forge | ||
Provides basic [AES][] encryption and decryption in CBC mode. | ||
Provides basic [AES][] encryption and decryption in CBC, CFB, OFB, or CTR mode. | ||
@@ -332,2 +332,3 @@ __Examples__ | ||
// encrypt some bytes using CBC mode | ||
// (other modes include: CFB, OFB, and CTR) | ||
var cipher = forge.aes.createEncryptionCipher(key, 'CBC'); | ||
@@ -342,2 +343,3 @@ cipher.start(iv); | ||
// decrypt some bytes using CBC mode | ||
// (other modes include: CFB, OFB, and CTR) | ||
var cipher = forge.aes.createDecryptionCipher(key, 'CBC'); | ||
@@ -350,19 +352,2 @@ cipher.start(iv); | ||
// encrypt some bytes using CFB mode | ||
var cipher = forge.aes.createEncryptionCipher(key, 'CFB'); | ||
cipher.start(iv); | ||
cipher.update(forge.util.createBuffer(someBytes)); | ||
cipher.finish(); | ||
var encrypted = cipher.output; | ||
// outputs encrypted hex | ||
console.log(encrypted.toHex()); | ||
// decrypt some bytes using CFB mode | ||
var cipher = forge.aes.createDecryptionCipher(key, 'CFB'); | ||
cipher.start(iv); | ||
cipher.update(encrypted); | ||
cipher.finish(); | ||
// outputs decrypted hex | ||
console.log(cipher.output.toHex()); | ||
// generate a password-based 16-byte key | ||
@@ -369,0 +354,0 @@ var salt = forge.random.getBytesSync(128); |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1409259
31373
1157