node-forge
Advanced tools
Comparing version
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
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1409259
0.26%32018
0.45%1157
-1.28%