diff --git a/README.md b/README.md index 1f4b0ef..bccfad7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# crypto-js +# crypto-js [![Build Status](https://travis-ci.org/brix/crypto-js.svg?branch=develop)](https://travis-ci.org/brix/crypto-js) JavaScript library of crypto standards. @@ -15,6 +15,18 @@ npm install crypto-js ### Usage +ES6 import for typical API call signing use case: + +```javascript +import sha256 from 'crypto-js/sha256'; +import hmacSHA512 from 'crypto-js/hmac-sha512'; +import Base64 from 'crypto-js/enc-base64'; + +const message, nonce, path, privateKey; // ... +const hashDigest = sha256(nonce + message); +const hmacDigest = Base64.stringify(hmacSHA512(path + hashDigest, privateKey)); +``` + Modular include: ```javascript @@ -89,7 +101,7 @@ require(["crypto-js"], function (CryptoJS) { ## API -See: https://code.google.com/p/crypto-js +See: https://cryptojs.gitbook.io/docs/ ### AES Encryption @@ -99,13 +111,13 @@ See: https://code.google.com/p/crypto-js var CryptoJS = require("crypto-js"); // Encrypt -var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123'); +var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123').toString(); // Decrypt -var bytes = CryptoJS.AES.decrypt(ciphertext.toString(), 'secret key 123'); -var plaintext = bytes.toString(CryptoJS.enc.Utf8); +var bytes = CryptoJS.AES.decrypt(ciphertext, 'secret key 123'); +var originalText = bytes.toString(CryptoJS.enc.Utf8); -console.log(plaintext); +console.log(originalText); // 'my message' ``` #### Object encryption @@ -116,13 +128,13 @@ var CryptoJS = require("crypto-js"); var data = [{id: 1}, {id: 2}] // Encrypt -var ciphertext = CryptoJS.AES.encrypt(JSON.stringify(data), 'secret key 123'); +var ciphertext = CryptoJS.AES.encrypt(JSON.stringify(data), 'secret key 123').toString(); // Decrypt -var bytes = CryptoJS.AES.decrypt(ciphertext.toString(), 'secret key 123'); +var bytes = CryptoJS.AES.decrypt(ciphertext, 'secret key 123'); var decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8)); -console.log(decryptedData); +console.log(decryptedData); // [{id: 1}, {id: 2}] ``` ### List of modules diff --git a/aes.js b/aes.js index 508d512..166e3ea 100644 --- a/aes.js +++ b/aes.js @@ -91,6 +91,8 @@ */ var AES = C_algo.AES = BlockCipher.extend({ _doReset: function () { + var t; + // Skip reset of nRounds has been set before and key did not change if (this._nRounds && this._keyPriorReset === this._key) { return; @@ -113,7 +115,7 @@ if (ksRow < keySize) { keySchedule[ksRow] = keyWords[ksRow]; } else { - var t = keySchedule[ksRow - 1]; + t = keySchedule[ksRow - 1]; if (!(ksRow % keySize)) { // Rot word diff --git a/bower.json b/bower.json index a995f68..795718f 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "crypto-js", - "version": "3.1.9", + "version": "3.2.0", "description": "JavaScript library of crypto standards.", "license": "MIT", "homepage": "http://github.com/brix/crypto-js", diff --git a/cipher-core.js b/cipher-core.js index 751c816..c560c9e 100644 --- a/cipher-core.js +++ b/cipher-core.js @@ -351,17 +351,19 @@ }); function xorBlock(words, offset, blockSize) { + var block; + // Shortcut var iv = this._iv; // Choose mixing block if (iv) { - var block = iv; + block = iv; // Remove IV for subsequent blocks this._iv = undefined; } else { - var block = this._prevBlock; + block = this._prevBlock; } // XOR blocks @@ -453,6 +455,8 @@ }), reset: function () { + var modeCreator; + // Reset cipher Cipher.reset.call(this); @@ -463,9 +467,9 @@ // Reset block mode if (this._xformMode == this._ENC_XFORM_MODE) { - var modeCreator = mode.createEncryptor; + modeCreator = mode.createEncryptor; } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { - var modeCreator = mode.createDecryptor; + modeCreator = mode.createDecryptor; // Keep at least one block in the buffer for unpadding this._minBufferSize = 1; } @@ -483,6 +487,8 @@ }, _doFinalize: function () { + var finalProcessedBlocks; + // Shortcut var padding = this.cfg.padding; @@ -492,10 +498,10 @@ padding.pad(this._data, this.blockSize); // Process final blocks - var finalProcessedBlocks = this._process(!!'flush'); + finalProcessedBlocks = this._process(!!'flush'); } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { // Process final blocks - var finalProcessedBlocks = this._process(!!'flush'); + finalProcessedBlocks = this._process(!!'flush'); // Unpad data padding.unpad(finalProcessedBlocks); @@ -587,15 +593,17 @@ * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams); */ stringify: function (cipherParams) { + var wordArray; + // Shortcuts var ciphertext = cipherParams.ciphertext; var salt = cipherParams.salt; // Format if (salt) { - var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); + wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); } else { - var wordArray = ciphertext; + wordArray = ciphertext; } return wordArray.toString(Base64); @@ -615,6 +623,8 @@ * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString); */ parse: function (openSSLStr) { + var salt; + // Parse base64 var ciphertext = Base64.parse(openSSLStr); @@ -624,7 +634,7 @@ // Test for salt if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) { // Extract salt - var salt = WordArray.create(ciphertextWords.slice(2, 4)); + salt = WordArray.create(ciphertextWords.slice(2, 4)); // Remove salt from ciphertext ciphertextWords.splice(0, 4); diff --git a/core.js b/core.js index 28e34c1..dac4ccb 100644 --- a/core.js +++ b/core.js @@ -17,11 +17,40 @@ * CryptoJS core components. */ var CryptoJS = CryptoJS || (function (Math, undefined) { + /* - * Local polyfil of Object.create + * Cryptographically secure pseudorandom number generator + * + * As Math.random() is cryptographically not safe to use + */ + var secureRandom = function () { + // Native crypto module on NodeJS environment + try { + // Crypto from global object + var crypto = global.crypto; + + // Create a random float number between 0 and 1 + return Number('0.' + crypto.randomBytes(3).readUIntBE(0, 3)); + } catch (err) {} + + // Native crypto module in Browser environment + try { + // Support experimental crypto module in IE 11 + var crypto = window.crypto || window.msCrypto; + + // Create a random float number between 0 and 1 + return Number('0.' + window.crypto.getRandomValues(new Uint32Array(1))[0]); + } catch (err) {} + + throw new Error('Native crypto module could not be used to get secure random number.'); + }; + + /* + * Local polyfill of Object.create + */ var create = Object.create || (function () { - function F() {}; + function F() {} return function (obj) { var subtype; @@ -304,26 +333,8 @@ random: function (nBytes) { var words = []; - var r = (function (m_w) { - var m_w = m_w; - var m_z = 0x3ade68b1; - var mask = 0xffffffff; - - return function () { - m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask; - m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask; - var result = ((m_z << 0x10) + m_w) & mask; - result /= 0x100000000; - result += 0.5; - return result * (Math.random() > .5 ? 1 : -1); - } - }); - - for (var i = 0, rcache; i < nBytes; i += 4) { - var _r = r((rcache || Math.random()) * 0x100000000); - - rcache = _r() * 0x3ade67b7; - words.push((_r() * 0x100000000) | 0); + for (var i = 0; i < nBytes; i += 4) { + words.push((secureRandom() * 0x100000000) | 0); } return new WordArray.init(words, nBytes); @@ -554,6 +565,8 @@ * var processedData = bufferedBlockAlgorithm._process(!!'flush'); */ _process: function (doFlush) { + var processedWords; + // Shortcuts var data = this._data; var dataWords = data.words; @@ -586,7 +599,7 @@ } // Remove processed words - var processedWords = dataWords.splice(0, nWordsReady); + processedWords = dataWords.splice(0, nWordsReady); data.sigBytes -= nBytesReady; } diff --git a/crypto-js.js b/crypto-js.js index 17f2b11..275e7ff 100644 --- a/crypto-js.js +++ b/crypto-js.js @@ -17,11 +17,40 @@ * CryptoJS core components. */ var CryptoJS = CryptoJS || (function (Math, undefined) { + /* - * Local polyfil of Object.create + * Cryptographically secure pseudorandom number generator + * + * As Math.random() is cryptographically not safe to use + */ + var secureRandom = function () { + // Native crypto module on NodeJS environment + try { + // Crypto from global object + var crypto = global.crypto; + + // Create a random float number between 0 and 1 + return Number('0.' + crypto.randomBytes(3).readUIntBE(0, 3)); + } catch (err) {} + + // Native crypto module in Browser environment + try { + // Support experimental crypto module in IE 11 + var crypto = window.crypto || window.msCrypto; + + // Create a random float number between 0 and 1 + return Number('0.' + window.crypto.getRandomValues(new Uint32Array(1))[0]); + } catch (err) {} + + throw new Error('Native crypto module could not be used to get secure random number.'); + }; + + /* + * Local polyfill of Object.create + */ var create = Object.create || (function () { - function F() {}; + function F() {} return function (obj) { var subtype; @@ -304,26 +333,8 @@ random: function (nBytes) { var words = []; - var r = (function (m_w) { - var m_w = m_w; - var m_z = 0x3ade68b1; - var mask = 0xffffffff; - - return function () { - m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask; - m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask; - var result = ((m_z << 0x10) + m_w) & mask; - result /= 0x100000000; - result += 0.5; - return result * (Math.random() > .5 ? 1 : -1); - } - }); - - for (var i = 0, rcache; i < nBytes; i += 4) { - var _r = r((rcache || Math.random()) * 0x100000000); - - rcache = _r() * 0x3ade67b7; - words.push((_r() * 0x100000000) | 0); + for (var i = 0; i < nBytes; i += 4) { + words.push((secureRandom() * 0x100000000) | 0); } return new WordArray.init(words, nBytes); @@ -554,6 +565,8 @@ * var processedData = bufferedBlockAlgorithm._process(!!'flush'); */ _process: function (doFlush) { + var processedWords; + // Shortcuts var data = this._data; var dataWords = data.words; @@ -586,7 +599,7 @@ } // Remove processed words - var processedWords = dataWords.splice(0, nWordsReady); + processedWords = dataWords.splice(0, nWordsReady); data.sigBytes -= nBytesReady; } @@ -863,7 +876,8 @@ if (i % 4) { var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); - words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); nBytes++; } } @@ -2182,6 +2196,8 @@ * var key = kdf.compute(password, salt); */ compute: function (password, salt) { + var block; + // Shortcut var cfg = this.cfg; @@ -2201,7 +2217,7 @@ if (block) { hasher.update(block); } - var block = hasher.update(password).finalize(salt); + block = hasher.update(password).finalize(salt); hasher.reset(); // Iterations @@ -2749,6 +2765,9 @@ // Rho Pi for (var laneIndex = 1; laneIndex < 25; laneIndex++) { + var tMsw; + var tLsw; + // Shortcuts var lane = state[laneIndex]; var laneMsw = lane.high; @@ -2757,11 +2776,11 @@ // Rotate lanes if (rhoOffset < 32) { - var tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset)); - var tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset)); + tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset)); + tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset)); } else /* if (rhoOffset >= 32) */ { - var tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset)); - var tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset)); + tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset)); + tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset)); } // Transpose lanes @@ -2796,7 +2815,7 @@ var lane = state[0]; var roundConstant = ROUND_CONSTANTS[round]; lane.high ^= roundConstant.high; - lane.low ^= roundConstant.low;; + lane.low ^= roundConstant.low; } }, @@ -3023,13 +3042,16 @@ // Rounds for (var i = 0; i < 80; i++) { + var Wil; + var Wih; + // Shortcut var Wi = W[i]; // Extend message if (i < 16) { - var Wih = Wi.high = M[offset + i * 2] | 0; - var Wil = Wi.low = M[offset + i * 2 + 1] | 0; + Wih = Wi.high = M[offset + i * 2] | 0; + Wil = Wi.low = M[offset + i * 2 + 1] | 0; } else { // Gamma0 var gamma0x = W[i - 15]; @@ -3054,12 +3076,12 @@ var Wi16h = Wi16.high; var Wi16l = Wi16.low; - var Wil = gamma0l + Wi7l; - var Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); - var Wil = Wil + gamma1l; - var Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); - var Wil = Wil + Wi16l; - var Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); + Wil = gamma0l + Wi7l; + Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); + Wil = Wil + gamma1l; + Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); + Wil = Wil + Wi16l; + Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); Wi.high = Wih; Wi.low = Wil; @@ -3602,17 +3624,19 @@ }); function xorBlock(words, offset, blockSize) { + var block; + // Shortcut var iv = this._iv; // Choose mixing block if (iv) { - var block = iv; + block = iv; // Remove IV for subsequent blocks this._iv = undefined; } else { - var block = this._prevBlock; + block = this._prevBlock; } // XOR blocks @@ -3704,6 +3728,8 @@ }), reset: function () { + var modeCreator; + // Reset cipher Cipher.reset.call(this); @@ -3714,9 +3740,9 @@ // Reset block mode if (this._xformMode == this._ENC_XFORM_MODE) { - var modeCreator = mode.createEncryptor; + modeCreator = mode.createEncryptor; } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { - var modeCreator = mode.createDecryptor; + modeCreator = mode.createDecryptor; // Keep at least one block in the buffer for unpadding this._minBufferSize = 1; } @@ -3734,6 +3760,8 @@ }, _doFinalize: function () { + var finalProcessedBlocks; + // Shortcut var padding = this.cfg.padding; @@ -3743,10 +3771,10 @@ padding.pad(this._data, this.blockSize); // Process final blocks - var finalProcessedBlocks = this._process(!!'flush'); + finalProcessedBlocks = this._process(!!'flush'); } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { // Process final blocks - var finalProcessedBlocks = this._process(!!'flush'); + finalProcessedBlocks = this._process(!!'flush'); // Unpad data padding.unpad(finalProcessedBlocks); @@ -3838,15 +3866,17 @@ * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams); */ stringify: function (cipherParams) { + var wordArray; + // Shortcuts var ciphertext = cipherParams.ciphertext; var salt = cipherParams.salt; // Format if (salt) { - var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); + wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); } else { - var wordArray = ciphertext; + wordArray = ciphertext; } return wordArray.toString(Base64); @@ -3866,6 +3896,8 @@ * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString); */ parse: function (openSSLStr) { + var salt; + // Parse base64 var ciphertext = Base64.parse(openSSLStr); @@ -3875,7 +3907,7 @@ // Test for salt if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) { // Extract salt - var salt = WordArray.create(ciphertextWords.slice(2, 4)); + salt = WordArray.create(ciphertextWords.slice(2, 4)); // Remove salt from ciphertext ciphertextWords.splice(0, 4); @@ -4164,17 +4196,19 @@ }); function generateKeystreamAndEncrypt(words, offset, blockSize, cipher) { + var keystream; + // Shortcut var iv = this._iv; // Generate keystream if (iv) { - var keystream = iv.slice(0); + keystream = iv.slice(0); // Remove IV for subsequent blocks this._iv = undefined; } else { - var keystream = this._prevBlock; + keystream = this._prevBlock; } cipher.encryptBlock(keystream, 0); @@ -4463,6 +4497,8 @@ */ var AES = C_algo.AES = BlockCipher.extend({ _doReset: function () { + var t; + // Skip reset of nRounds has been set before and key did not change if (this._nRounds && this._keyPriorReset === this._key) { return; @@ -4485,7 +4521,7 @@ if (ksRow < keySize) { keySchedule[ksRow] = keyWords[ksRow]; } else { - var t = keySchedule[ksRow - 1]; + t = keySchedule[ksRow - 1]; if (!(ksRow % keySize)) { // Rot word @@ -5313,11 +5349,20 @@ // Shortcuts var key = this._key; var keyWords = key.words; + // Make sure the key length is valid (64, 128 or >= 192 bit) + if (keyWords.length !== 2 && keyWords.length !== 4 && keyWords.length < 6) { + throw new Error('Invalid key length - 3DES requires the key length to be 64, 128, 192 or >192.'); + } + + // Extend the key according to the keying options defined in 3DES standard + var key1 = keyWords.slice(0, 2); + var key2 = keyWords.length < 4 ? keyWords.slice(0, 2) : keyWords.slice(2, 4); + var key3 = keyWords.length < 6 ? keyWords.slice(0, 2) : keyWords.slice(4, 6); // Create DES instances - this._des1 = DES.createEncryptor(WordArray.create(keyWords.slice(0, 2))); - this._des2 = DES.createEncryptor(WordArray.create(keyWords.slice(2, 4))); - this._des3 = DES.createEncryptor(WordArray.create(keyWords.slice(4, 6))); + this._des1 = DES.createEncryptor(WordArray.create(key1)); + this._des2 = DES.createEncryptor(WordArray.create(key2)); + this._des3 = DES.createEncryptor(WordArray.create(key3)); }, encryptBlock: function (M, offset) { @@ -5975,10 +6020,12 @@ // Unpad var i = data.sigBytes - 1; - while (!((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) { - i--; + for (var i = data.sigBytes - 1; i >= 0; i--) { + if (((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) { + data.sigBytes = i + 1; + break; + } } - data.sigBytes = i + 1; } }; diff --git a/enc-base64.js b/enc-base64.js index d5d4082..0ffcd53 100644 --- a/enc-base64.js +++ b/enc-base64.js @@ -121,7 +121,8 @@ if (i % 4) { var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); - words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); nBytes++; } } diff --git a/evpkdf.js b/evpkdf.js index 3fe5c01..578974a 100644 --- a/evpkdf.js +++ b/evpkdf.js @@ -68,6 +68,8 @@ * var key = kdf.compute(password, salt); */ compute: function (password, salt) { + var block; + // Shortcut var cfg = this.cfg; @@ -87,7 +89,7 @@ if (block) { hasher.update(block); } - var block = hasher.update(password).finalize(salt); + block = hasher.update(password).finalize(salt); hasher.reset(); // Iterations diff --git a/mode-cfb.js b/mode-cfb.js index 86231f1..444c9cb 100644 --- a/mode-cfb.js +++ b/mode-cfb.js @@ -49,17 +49,19 @@ }); function generateKeystreamAndEncrypt(words, offset, blockSize, cipher) { + var keystream; + // Shortcut var iv = this._iv; // Generate keystream if (iv) { - var keystream = iv.slice(0); + keystream = iv.slice(0); // Remove IV for subsequent blocks this._iv = undefined; } else { - var keystream = this._prevBlock; + keystream = this._prevBlock; } cipher.encryptBlock(keystream, 0); diff --git a/package.json b/package.json index dae37ed..ee15327 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "crypto-js", - "version": "3.1.9", + "version": "3.2.0", "description": "JavaScript library of crypto standards.", "license": "MIT", "author": { diff --git a/pad-zeropadding.js b/pad-zeropadding.js index 0e8a859..a1a459e 100644 --- a/pad-zeropadding.js +++ b/pad-zeropadding.js @@ -32,10 +32,12 @@ // Unpad var i = data.sigBytes - 1; - while (!((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) { - i--; + for (var i = data.sigBytes - 1; i >= 0; i--) { + if (((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) { + data.sigBytes = i + 1; + break; + } } - data.sigBytes = i + 1; } }; diff --git a/sha3.js b/sha3.js index 4fb27fe..34ad86c 100644 --- a/sha3.js +++ b/sha3.js @@ -173,6 +173,9 @@ // Rho Pi for (var laneIndex = 1; laneIndex < 25; laneIndex++) { + var tMsw; + var tLsw; + // Shortcuts var lane = state[laneIndex]; var laneMsw = lane.high; @@ -181,11 +184,11 @@ // Rotate lanes if (rhoOffset < 32) { - var tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset)); - var tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset)); + tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset)); + tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset)); } else /* if (rhoOffset >= 32) */ { - var tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset)); - var tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset)); + tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset)); + tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset)); } // Transpose lanes @@ -220,7 +223,7 @@ var lane = state[0]; var roundConstant = ROUND_CONSTANTS[round]; lane.high ^= roundConstant.high; - lane.low ^= roundConstant.low;; + lane.low ^= roundConstant.low; } }, diff --git a/sha512.js b/sha512.js index 3359315..d274ab0 100644 --- a/sha512.js +++ b/sha512.js @@ -142,13 +142,16 @@ // Rounds for (var i = 0; i < 80; i++) { + var Wil; + var Wih; + // Shortcut var Wi = W[i]; // Extend message if (i < 16) { - var Wih = Wi.high = M[offset + i * 2] | 0; - var Wil = Wi.low = M[offset + i * 2 + 1] | 0; + Wih = Wi.high = M[offset + i * 2] | 0; + Wil = Wi.low = M[offset + i * 2 + 1] | 0; } else { // Gamma0 var gamma0x = W[i - 15]; @@ -173,12 +176,12 @@ var Wi16h = Wi16.high; var Wi16l = Wi16.low; - var Wil = gamma0l + Wi7l; - var Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); - var Wil = Wil + gamma1l; - var Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); - var Wil = Wil + Wi16l; - var Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); + Wil = gamma0l + Wi7l; + Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); + Wil = Wil + gamma1l; + Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); + Wil = Wil + Wi16l; + Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); Wi.high = Wih; Wi.low = Wil; diff --git a/tripledes.js b/tripledes.js index c7becf3..1a92477 100644 --- a/tripledes.js +++ b/tripledes.js @@ -727,11 +727,20 @@ // Shortcuts var key = this._key; var keyWords = key.words; + // Make sure the key length is valid (64, 128 or >= 192 bit) + if (keyWords.length !== 2 && keyWords.length !== 4 && keyWords.length < 6) { + throw new Error('Invalid key length - 3DES requires the key length to be 64, 128, 192 or >192.'); + } + + // Extend the key according to the keying options defined in 3DES standard + var key1 = keyWords.slice(0, 2); + var key2 = keyWords.length < 4 ? keyWords.slice(0, 2) : keyWords.slice(2, 4); + var key3 = keyWords.length < 6 ? keyWords.slice(0, 2) : keyWords.slice(4, 6); // Create DES instances - this._des1 = DES.createEncryptor(WordArray.create(keyWords.slice(0, 2))); - this._des2 = DES.createEncryptor(WordArray.create(keyWords.slice(2, 4))); - this._des3 = DES.createEncryptor(WordArray.create(keyWords.slice(4, 6))); + this._des1 = DES.createEncryptor(WordArray.create(key1)); + this._des2 = DES.createEncryptor(WordArray.create(key2)); + this._des3 = DES.createEncryptor(WordArray.create(key3)); }, encryptBlock: function (M, offset) {