diff --git a/.jshintrc b/.jshintrc index ae02577..72c2b12 100644 --- a/.jshintrc +++ b/.jshintrc @@ -1,16 +1,33 @@ { - "bitwise" : false, // Prohibits the use of bitwise operators (not confuse & with &&) - "curly" : true, // Requires to always put curly braces around blocks in loops and conditionals - "eqeqeq" : false, // Prohibits the use of == and != in favor of === and !== - "eqnull" : true, // Suppresses warnings about == null comparisons - "immed" : true, // Requires immediate invocations to be wrapped in parens e.g. `(function () { } ());` - "latedef" : true, // Prohibits the use of a variable before it was defined - "newcap" : false, // Requires to capitalize names of constructor functions - "noarg" : true, // Prohibits the use of arguments.caller and arguments.callee - "strict" : false, // Requires all functions to run in ECMAScript 5's strict mode - "undef" : true, // Require non-global variables to be declared (prevents global leaks) - "asi" : true, // Suppresses warnings about missing semicolons - "globals": { - "CryptoJS": true - } + "bitwise": false, // Prohibits the use of bitwise operators (not confuse & with &&) + "curly": true, // Requires to always put curly braces around blocks in loops and conditionals + "eqeqeq": false, // Prohibits the use of == and != in favor of === and !== + "eqnull": true, // Suppresses warnings about == null comparisons + "immed": true, // Requires immediate invocations to be wrapped in parens e.g. `(function () { } ());` + "latedef": false, // Prohibits the use of a variable before it was defined + "newcap": false, // Requires to capitalize names of constructor functions + "noarg": true, // Prohibits the use of arguments.caller and arguments.callee + "strict": false, // Requires all functions to run in ECMAScript 5's strict mode + "undef": true, // Require non-global variables to be declared (prevents global leaks) + "asi": true, // Suppresses warnings about missing semicolons + "funcscope": false, + "shadow": true, + "expr": true, + "-W041": true, + "-W018": true, + "globals": { + "CryptoJS": true, + "escape": true, + "unescape": true, + "Int8Array": true, + "Int16Array": true, + "Int32Array": true, + "Uint8Array": true, + "Uint16Array": true, + "Uint32Array": true, + "Uint8ClampedArray": true, + "ArrayBuffer": true, + "Float32Array": true, + "Float64Array": true + } } diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..cca89fb --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +dist: trusty +sudo: false + +language: node_js +node_js: + - "6" + - "7" + +before_script: + - npm install -g grunt-cli + - npm install build + +cache: + directories: + - "node_modules" diff --git a/Gruntfile.js b/Gruntfile.js index 9f67b00..e083f92 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -29,6 +29,8 @@ module.exports = function (grunt) { } } }); + + // Will load the custom tasks grunt.loadTasks('./grunt/tasks'); diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b0828e5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +# License + +[The MIT License (MIT)](http://opensource.org/licenses/MIT) + +Copyright (c) 2009-2013 Jeff Mott +Copyright (c) 2013-2016 Evan Vosberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index 5e4ace1..6a9bcdf 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,12 @@ JavaScript library of crypto standards. +## Discontinued + +Active development of CryptoJS has been discontinued. This library is no longer maintained. + +Nowadays, NodeJS and modern browsers have a native `Crypto` module. The latest version of CryptoJS already uses the native Crypto module for random number generation, since `Math.random()` is not crypto-safe. Further development of CryptoJS would result in it only being a wrapper of native Crypto. Therefore, development and maintenance has been discontinued, it is time to go for the native `crypto` module. + ## Node.js (Install) Requirements: @@ -15,6 +21,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 @@ -68,7 +86,7 @@ Including all libraries, for access to extra methods: // Above-mentioned will work or use this simple form require.config({ paths: { - 'require-js': 'path-to/bower_components/crypto-js/crypto-js' + 'crypto-js': 'path-to/bower_components/crypto-js/crypto-js' } }); @@ -89,7 +107,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 +117,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 +134,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 @@ -197,27 +215,61 @@ console.log(decryptedData); - ```crypto-js/pad-zeropadding``` - ```crypto-js/pad-nopadding``` -## License -[The MIT License (MIT)](http://opensource.org/licenses/MIT) +## Release notes + +### 4.2.0 + +Change default hash algorithm and iteration's for PBKDF2 to prevent weak security by using the default configuration. + +Custom KDF Hasher + +Blowfish support + +### 4.1.1 + +Fix module order in bundled release. + +Include the browser field in the released package.json. + +### 4.1.0 + +Added url safe variant of base64 encoding. [357](https://github.com/brix/crypto-js/pull/357) + +Avoid webpack to add crypto-browser package. [364](https://github.com/brix/crypto-js/pull/364) + +### 4.0.0 + +This is an update including breaking changes for some environments. + +In this version `Math.random()` has been replaced by the random methods of the native crypto module. + +For this reason CryptoJS might not run in some JavaScript environments without native crypto module. Such as IE 10 or before or React Native. + +### 3.3.0 + +Rollback, `3.3.0` is the same as `3.1.9-1`. + +The move of using native secure crypto module will be shifted to a new `4.x.x` version. As it is a breaking change the impact is too big for a minor release. + +### 3.2.1 + +The usage of the native crypto module has been fixed. The import and access of the native crypto module has been improved. + +### 3.2.0 + +In this version `Math.random()` has been replaced by the random methods of the native crypto module. + +For this reason CryptoJS might does not run in some JavaScript environments without native crypto module. Such as IE 10 or before. + +If it's absolute required to run CryptoJS in such an environment, stay with `3.1.x` version. Encrypting and decrypting stays compatible. But keep in mind `3.1.x` versions still use `Math.random()` which is cryptographically not secure, as it's not random enough. + +This version came along with `CRITICAL` `BUG`. + +DO NOT USE THIS VERSION! Please, go for a newer version! -Copyright (c) 2009-2013 Jeff Mott -Copyright (c) 2013-2015 Evan Vosberg +### 3.1.x -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +The `3.1.x` are based on the original CryptoJS, wrapped in CommonJS modules. -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/grunt/config/copy.js b/grunt/config/copy.js index 4e6a603..2aa74e2 100644 --- a/grunt/config/copy.js +++ b/grunt/config/copy.js @@ -10,7 +10,7 @@ module.exports = { src: [ 'README.md', 'CONTRIBUTING.md', - 'license.md', + 'LICENSE', 'docs/**/*' ], dest: '<%= meta.build %>' diff --git a/grunt/config/jshint.js b/grunt/config/jshint.js index 1a3aa11..1c3cb23 100644 --- a/grunt/config/jshint.js +++ b/grunt/config/jshint.js @@ -5,7 +5,8 @@ module.exports = { dev: { options: { - jshintrc: true + jshintrc: process.cwd() + '/.jshintrc', + reporterOutput: '' }, files: { src: [ diff --git a/grunt/config/modularize.js b/grunt/config/modularize.js index bf7d378..33218ee 100644 --- a/grunt/config/modularize.js +++ b/grunt/config/modularize.js @@ -13,13 +13,13 @@ module.exports = { "index": { "global": "CryptoJS", "exports": "CryptoJS", - "components": ["core", "x64-core", "lib-typedarrays", "enc-utf16", "enc-base64", "md5", "sha1", "sha256", "sha224", "sha512", "sha384", "sha3", "ripemd160", "hmac", "pbkdf2", "evpkdf", "cipher-core", "mode-cfb", "mode-ctr", "mode-ctr-gladman", "mode-ofb", "mode-ecb", "pad-ansix923", "pad-iso10126", "pad-iso97971", "pad-zeropadding", "pad-nopadding", "format-hex", "aes", "tripledes", "rc4", "rabbit", "rabbit-legacy"] + "components": ["core", "x64-core", "lib-typedarrays", "enc-utf16", "enc-base64", "enc-base64url", "md5", "sha1", "sha256", "sha224", "sha512", "sha384", "sha3", "ripemd160", "hmac", "pbkdf2", "evpkdf", "cipher-core", "mode-cfb", "mode-ctr", "mode-ctr-gladman", "mode-ofb", "mode-ecb", "pad-ansix923", "pad-iso10126", "pad-iso97971", "pad-zeropadding", "pad-nopadding", "format-hex", "aes", "tripledes", "rc4", "rabbit", "rabbit-legacy","blowfish"] }, "crypto-js": { "pack": true, "global": "CryptoJS", "exports": "CryptoJS", - "components": ["core", "x64-core", "lib-typedarrays", "enc-utf16", "enc-base64", "md5", "sha1", "sha256", "sha224", "sha512", "sha384", "sha3", "ripemd160", "hmac", "pbkdf2", "evpkdf", "cipher-core", "mode-cfb", "mode-ctr", "mode-ctr-gladman", "mode-ofb", "mode-ecb", "pad-ansix923", "pad-iso10126", "pad-iso97971", "pad-zeropadding", "pad-nopadding", "format-hex", "aes", "tripledes", "rc4", "rabbit", "rabbit-legacy"] + "components": ["core", "x64-core", "lib-typedarrays", "enc-utf16", "enc-base64", "enc-base64url", "md5", "sha1", "sha256", "sha224", "sha512", "sha384", "sha3", "ripemd160", "hmac", "pbkdf2", "evpkdf", "cipher-core", "mode-cfb", "mode-ctr", "mode-ctr-gladman", "mode-ofb", "mode-ecb", "pad-ansix923", "pad-iso10126", "pad-iso97971", "pad-zeropadding", "pad-nopadding", "format-hex", "aes", "tripledes", "rc4", "rabbit", "rabbit-legacy","blowfish"] }, // hash @@ -91,7 +91,7 @@ module.exports = { }, "pbkdf2": { "exports": "CryptoJS.PBKDF2", - "components": ["core", "sha1", "hmac", "pbkdf2"] + "components": ["core", "sha256", "hmac", "pbkdf2"] }, "evpkdf": { "exports": "CryptoJS.EvpKDF", @@ -103,6 +103,10 @@ module.exports = { "exports": "CryptoJS.AES", "components": ["core", "enc-base64", "md5", "evpkdf", "cipher-core", "aes"] }, + "blowfish": { + "exports": "CryptoJS.Blowfish", + "components": ["core", "enc-base64", "md5", "evpkdf", "cipher-core", "blowfish"] + }, "tripledes": { "exports": "CryptoJS.TripleDES", "components": ["core", "enc-base64", "md5", "evpkdf", "cipher-core", "tripledes"] @@ -124,7 +128,7 @@ module.exports = { "core": { "exports": "CryptoJS", "components": ["core"], - "global": "CryptoJS" + "global": "CryptoJS" }, "x64-core": { "exports": "CryptoJS", @@ -134,7 +138,7 @@ module.exports = { "components": ["core", "hmac"] }, "cipher-core": { - "components": ["core", "cipher-core"] + "components": ["core", "evpkdf", "cipher-core"] }, // lib @@ -174,6 +178,10 @@ module.exports = { "exports": "CryptoJS.enc.Base64", "components": ["core", "enc-base64"] }, + "enc-base64url": { + "exports": "CryptoJS.enc.Base64url", + "components": ["core", "enc-base64url"] + }, // mode "mode-cfb": { diff --git a/grunt/config/update_json.js b/grunt/config/update_json.js index 46a5656..1b92a78 100644 --- a/grunt/config/update_json.js +++ b/grunt/config/update_json.js @@ -19,7 +19,8 @@ module.exports = { 'repository': null, 'keywords': null, 'main': null, - 'dependencies': null + 'dependencies': null, + 'browser': null } }, bower: { @@ -36,6 +37,7 @@ module.exports = { 'keywords': null, 'main': null, 'dependencies': null, + 'browser': null, 'ignore': [] } } diff --git a/grunt/tasks/modularize.js b/grunt/tasks/modularize.js index 30e7f7b..228e9ae 100644 --- a/grunt/tasks/modularize.js +++ b/grunt/tasks/modularize.js @@ -1,8 +1,9 @@ /*jshint node: true*/ +/*jshint esversion: 6*/ var _ = require("lodash"), - fmd = require("fmd"); + fmd = require("fmd"); module.exports = function (grunt) { @@ -14,78 +15,84 @@ module.exports = function (grunt) { modules = {}, config = { - target: this.target + '/', - factories: ["commonjs", "amd", "global"], - trim_whitespace: true, - new_line: "unix", - indent: "\t" - }; + target: this.target + '/', + factories: ["commonjs", "amd", "global"], + trim_whitespace: true, + new_line: "unix", + indent: "\t" + }; // Prepare Factory-Module-Definition settings - _.each(options, function (conf, name) { + _.each(options, (conf, name) => { var sources = [], - opts = { - depends: {} - }, + opts = { + depends: {} + }, - deps = []; + deps = []; - if (conf.exports) { - opts.exports = conf.exports; - } + if (conf.exports) { + opts.exports = conf.exports; + } - if (conf.global) { - opts.global = conf.global; - } + if (conf.global) { + opts.global = conf.global; + } // Find and add self as source - _.each(this.filesSrc, function (source) { - if (grunt.file.exists(source + name + ".js")) { - sources.push(source + name + ".js"); - } - }, this); + _.each(this.filesSrc, (source) => { + if (grunt.file.exists(source + name + ".js")) { + sources.push(source + name + ".js"); + } + }); if (conf.pack) { - // Collect all components - deps = _.chain(conf.components) - .map(function (depName) { - return options[depName].components; - }) - .flatten() - .unique() - .without(name) - .sort(function (a, b) { - return options[a].components.indexOf(b) === -1 ? -1 : 1; - }) - .value(); + // Collect all components + deps = _.chain(conf.components) + .map(depName => options[depName].components) + .flatten() + .uniq() + .without(name) + .sort((a, b) => { + if (options[a].components.includes(b)) { + return 1 + } + + if (options[b].components.includes(a)) { + return -1 + } + + return 0; + }) + .value(); // Add components as source files -> results a single file - _.each(this.filesSrc, function (source) { - _.each(deps, function (depName) { - if (grunt.file.exists(source + depName + ".js")) { - sources.push(source + depName + ".js"); - } - }); - }, this); + _.each(this.filesSrc, (source) => { + _.each(deps, (depName) => { + if (grunt.file.exists(source + depName + ".js")) { + sources.push(source + depName + ".js"); + } + }); + }); } else { - // Read components and add them as dependecies - _.each(_.without(conf.components, name), function (value, i) { - opts.depends['./' + value] = value === "core" ? "CryptoJS" : null; - }); - } + // Read components and add them as dependecies + _.each(_.without(conf.components, name), (value, i) => { + opts.depends['./' + value] = value === "core" ? "CryptoJS" : null; + }); + } - // Remove duplicates - sources = _.unique(sources); + // Remove duplicates + sources = _.uniq(sources); // Add module settings to fmd definition - modules[name] = [sources, opts]; - }, this); + modules[name] = [sources, opts]; + }); - // Build packege modules - fmd(config) - .define(modules) - .build(function (createdFiles) { + // Build packege modules + fmd(config) + .define(modules) + .build(() => { done(); }); diff --git a/package.json b/package.json index fcf2d13..4f3f02b 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "crypto-js", "title": "crypto-js", "description": "JavaScript library of crypto standards.", - "version": "3.1.5", + "version": "4.2.0", "homepage": "http://github.com/brix/crypto-js", "author": { "name": "Evan Vosberg", @@ -18,20 +18,24 @@ "license": "MIT", "scripts": { "build": "grunt build", - "check": "grunt default" + "test": "grunt default" }, "main": "index.js", + "browser": { + "crypto": false + }, "dependencies": {}, "devDependencies": { "fmd": "~0.0.3", - "grunt": "^0.4.5", - "grunt-contrib-clean": "^0.6.0", - "grunt-contrib-copy": "^0.6.0", - "grunt-contrib-jshint": "^0.10.0", - "grunt-jsonlint": "^1.0.4", - "grunt-update-json": "^0.2.0", - "load-grunt-config": "^0.16.0", - "lodash": "^3.5.0" + "grunt": "^1.4.3", + "grunt-cli": "^1.4.3", + "grunt-contrib-clean": "^2.0.0", + "grunt-contrib-copy": "^1.0.0", + "grunt-contrib-jshint": "^3.0.0", + "grunt-jsonlint": "^2.1.3", + "grunt-update-json": "^0.2.2", + "load-grunt-config": "^4.0.0", + "lodash": "^4.17.21" }, "keywords": [ "security", @@ -52,6 +56,7 @@ "CFB", "CTR", "CBC", - "Base64" + "Base64", + "Base64url" ] } diff --git a/src/aes.js b/src/aes.js index 80eff25..2d033c0 100644 --- a/src/aes.js +++ b/src/aes.js @@ -76,13 +76,20 @@ */ 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; + } + // Shortcuts - var key = this._key; + var key = this._keyPriorReset = this._key; var keyWords = key.words; var keySize = key.sigBytes / 4; // Compute number of rounds - var nRounds = this._nRounds = keySize + 6 + var nRounds = this._nRounds = keySize + 6; // Compute number of key schedule rows var ksRows = (nRounds + 1) * 4; @@ -93,7 +100,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/src/blowfish.js b/src/blowfish.js new file mode 100644 index 0000000..60eb220 --- /dev/null +++ b/src/blowfish.js @@ -0,0 +1,451 @@ +(function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + const N = 16; + + //Origin pbox and sbox, derived from PI + const ORIG_P = [ + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, + 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, + 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, + 0x9216D5D9, 0x8979FB1B + ]; + + const ORIG_S = [ + [ 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, + 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, + 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, + 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, + 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, + 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, + 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, + 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, + 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, + 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, + 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, + 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, + 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, + 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, + 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, + 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, + 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, + 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, + 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, + 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, + 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, + 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, + 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, + 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, + 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, + 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, + 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, + 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, + 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, + 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, + 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, + 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, + 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, + 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, + 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, + 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, + 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, + 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, + 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, + 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, + 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, + 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, + 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A ], + [ 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, + 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, + 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, + 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, + 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, + 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, + 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, + 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, + 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, + 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, + 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, + 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, + 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, + 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, + 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, + 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, + 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, + 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, + 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, + 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, + 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, + 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, + 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, + 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, + 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, + 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, + 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, + 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, + 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, + 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, + 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, + 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, + 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, + 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, + 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, + 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, + 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, + 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, + 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, + 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, + 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, + 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, + 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 ], + [ 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, + 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, + 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, + 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, + 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, + 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, + 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, + 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, + 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, + 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, + 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, + 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, + 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, + 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, + 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, + 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, + 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, + 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, + 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, + 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, + 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, + 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, + 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, + 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, + 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, + 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, + 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, + 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, + 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, + 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, + 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, + 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, + 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, + 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, + 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, + 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, + 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, + 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, + 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, + 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, + 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, + 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, + 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 ], + [ 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, + 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, + 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, + 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, + 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, + 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, + 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, + 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, + 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, + 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, + 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, + 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, + 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, + 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, + 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, + 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, + 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, + 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, + 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, + 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, + 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, + 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, + 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, + 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, + 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, + 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, + 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, + 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, + 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, + 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, + 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, + 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, + 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, + 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, + 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, + 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, + 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, + 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, + 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, + 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, + 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, + 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, + 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 ] + ]; + + var BLOWFISH_CTX = { + pbox: [], + sbox: [] + } + + function F(ctx, x){ + let a = (x >> 24) & 0xFF; + let b = (x >> 16) & 0xFF; + let c = (x >> 8) & 0xFF; + let d = x & 0xFF; + + let y = ctx.sbox[0][a] + ctx.sbox[1][b]; + y = y ^ ctx.sbox[2][c]; + y = y + ctx.sbox[3][d]; + + return y; + } + + function BlowFish_Encrypt(ctx, left, right){ + let Xl = left; + let Xr = right; + let temp; + + for(let i = 0; i < N; ++i){ + Xl = Xl ^ ctx.pbox[i]; + Xr = F(ctx, Xl) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx.pbox[N]; + Xl = Xl ^ ctx.pbox[N + 1]; + + return {left: Xl, right: Xr}; + } + + function BlowFish_Decrypt(ctx, left, right){ + let Xl = left; + let Xr = right; + let temp; + + for(let i = N + 1; i > 1; --i){ + Xl = Xl ^ ctx.pbox[i]; + Xr = F(ctx, Xl) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx.pbox[1]; + Xl = Xl ^ ctx.pbox[0]; + + return {left: Xl, right: Xr}; + } + + /** + * Initialization ctx's pbox and sbox. + * + * @param {Object} ctx The object has pbox and sbox. + * @param {Array} key An array of 32-bit words. + * @param {int} keysize The length of the key. + * + * @example + * + * BlowFishInit(BLOWFISH_CTX, key, 128/32); + */ + function BlowFishInit(ctx, key, keysize) + { + for(let Row = 0; Row < 4; Row++) + { + ctx.sbox[Row] = []; + for(let Col = 0; Col < 256; Col++) + { + ctx.sbox[Row][Col] = ORIG_S[Row][Col]; + } + } + + let keyIndex = 0; + for(let index = 0; index < N + 2; index++) + { + ctx.pbox[index] = ORIG_P[index] ^ key[keyIndex]; + keyIndex++; + if(keyIndex >= keysize) + { + keyIndex = 0; + } + } + + let Data1 = 0; + let Data2 = 0; + let res = 0; + for(let i = 0; i < N + 2; i += 2) + { + res = BlowFish_Encrypt(ctx, Data1, Data2); + Data1 = res.left; + Data2 = res.right; + ctx.pbox[i] = Data1; + ctx.pbox[i + 1] = Data2; + } + + for(let i = 0; i < 4; i++) + { + for(let j = 0; j < 256; j += 2) + { + res = BlowFish_Encrypt(ctx, Data1, Data2); + Data1 = res.left; + Data2 = res.right; + ctx.sbox[i][j] = Data1; + ctx.sbox[i][j + 1] = Data2; + } + } + + return true; + } + + /** + * Blowfish block cipher algorithm. + */ + var Blowfish = C_algo.Blowfish = BlockCipher.extend({ + _doReset: function () { + // Skip reset of nRounds has been set before and key did not change + if (this._keyPriorReset === this._key) { + return; + } + + // Shortcuts + var key = this._keyPriorReset = this._key; + var keyWords = key.words; + var keySize = key.sigBytes / 4; + + //Initialization pbox and sbox + BlowFishInit(BLOWFISH_CTX, keyWords, keySize); + }, + + encryptBlock: function (M, offset) { + var res = BlowFish_Encrypt(BLOWFISH_CTX, M[offset], M[offset + 1]); + M[offset] = res.left; + M[offset + 1] = res.right; + }, + + decryptBlock: function (M, offset) { + var res = BlowFish_Decrypt(BLOWFISH_CTX, M[offset], M[offset + 1]); + M[offset] = res.left; + M[offset + 1] = res.right; + }, + + blockSize: 64/32, + + keySize: 128/32, + + ivSize: 64/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.Blowfish.encrypt(message, key, cfg); + * var plaintext = CryptoJS.Blowfish.decrypt(ciphertext, key, cfg); + */ + C.Blowfish = BlockCipher._createHelper(Blowfish); +}()); diff --git a/src/cipher-core.js b/src/cipher-core.js index 15a9e67..125632c 100644 --- a/src/cipher-core.js +++ b/src/cipher-core.js @@ -336,17 +336,19 @@ CryptoJS.lib.Cipher || (function (undefined) { }); 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 @@ -438,6 +440,8 @@ CryptoJS.lib.Cipher || (function (undefined) { }), reset: function () { + var modeCreator; + // Reset cipher Cipher.reset.call(this); @@ -448,14 +452,19 @@ CryptoJS.lib.Cipher || (function (undefined) { // 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; } - this._mode = modeCreator.call(mode, this, iv && iv.words); + + if (this._mode && this._mode.__creator == modeCreator) { + this._mode.init(this, iv && iv.words); + } else { + this._mode = modeCreator.call(mode, this, iv && iv.words); + this._mode.__creator = modeCreator; + } }, _doProcessBlock: function (words, offset) { @@ -463,6 +472,8 @@ CryptoJS.lib.Cipher || (function (undefined) { }, _doFinalize: function () { + var finalProcessedBlocks; + // Shortcut var padding = this.cfg.padding; @@ -472,10 +483,10 @@ CryptoJS.lib.Cipher || (function (undefined) { 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); @@ -567,15 +578,17 @@ CryptoJS.lib.Cipher || (function (undefined) { * 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); @@ -595,6 +608,8 @@ CryptoJS.lib.Cipher || (function (undefined) { * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString); */ parse: function (openSSLStr) { + var salt; + // Parse base64 var ciphertext = Base64.parse(openSSLStr); @@ -604,7 +619,7 @@ CryptoJS.lib.Cipher || (function (undefined) { // 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); @@ -750,14 +765,19 @@ CryptoJS.lib.Cipher || (function (undefined) { * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32); * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt'); */ - execute: function (password, keySize, ivSize, salt) { + execute: function (password, keySize, ivSize, salt, hasher) { // Generate random salt if (!salt) { salt = WordArray.random(64/8); } // Derive key and IV - var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt); + if (!hasher) { + var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt); + } else { + var key = EvpKDF.create({ keySize: keySize + ivSize, hasher: hasher }).compute(password, salt); + } + // Separate key and IV var iv = WordArray.create(key.words.slice(keySize), ivSize * 4); @@ -804,7 +824,7 @@ CryptoJS.lib.Cipher || (function (undefined) { cfg = this.cfg.extend(cfg); // Derive key and other params - var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize); + var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, cfg.salt, cfg.hasher); // Add IV to config cfg.iv = derivedParams.iv; @@ -843,7 +863,7 @@ CryptoJS.lib.Cipher || (function (undefined) { ciphertext = this._parse(ciphertext, cfg.format); // Derive key and other params - var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt); + var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt, cfg.hasher); // Add IV to config cfg.iv = derivedParams.iv; diff --git a/src/core.js b/src/core.js index 22711eb..e1330e7 100644 --- a/src/core.js +++ b/src/core.js @@ -1,7 +1,89 @@ +/*globals window, global, require*/ + /** * CryptoJS core components. */ var CryptoJS = CryptoJS || (function (Math, undefined) { + + var crypto; + + // Native crypto from window (Browser) + if (typeof window !== 'undefined' && window.crypto) { + crypto = window.crypto; + } + + // Native crypto in web worker (Browser) + if (typeof self !== 'undefined' && self.crypto) { + crypto = self.crypto; + } + + // Native crypto from worker + if (typeof globalThis !== 'undefined' && globalThis.crypto) { + crypto = globalThis.crypto; + } + + // Native (experimental IE 11) crypto from window (Browser) + if (!crypto && typeof window !== 'undefined' && window.msCrypto) { + crypto = window.msCrypto; + } + + // Native crypto from global (NodeJS) + if (!crypto && typeof global !== 'undefined' && global.crypto) { + crypto = global.crypto; + } + + // Native crypto import via require (NodeJS) + if (!crypto && typeof require === 'function') { + try { + crypto = require('crypto'); + } catch (err) {} + } + + /* + * Cryptographically secure pseudorandom number generator + * + * As Math.random() is cryptographically not safe to use + */ + var cryptoSecureRandomInt = function () { + if (crypto) { + // Use getRandomValues method (Browser) + if (typeof crypto.getRandomValues === 'function') { + try { + return crypto.getRandomValues(new Uint32Array(1))[0]; + } catch (err) {} + } + + // Use randomBytes method (NodeJS) + if (typeof crypto.randomBytes === 'function') { + try { + return crypto.randomBytes(4).readInt32LE(); + } 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() {} + + return function (obj) { + var subtype; + + F.prototype = obj; + + subtype = new F(); + + F.prototype = null; + + return subtype; + }; + }()); + /** * CryptoJS namespace. */ @@ -16,7 +98,7 @@ var CryptoJS = CryptoJS || (function (Math, undefined) { * Base object for prototypal inheritance. */ var Base = C_lib.Base = (function () { - function F() {} + return { /** @@ -39,8 +121,7 @@ var CryptoJS = CryptoJS || (function (Math, undefined) { */ extend: function (overrides) { // Spawn - F.prototype = this; - var subtype = new F(); + var subtype = create(this); // Augment if (overrides) { @@ -48,7 +129,7 @@ var CryptoJS = CryptoJS || (function (Math, undefined) { } // Create default initializer - if (!subtype.hasOwnProperty('init')) { + if (!subtype.hasOwnProperty('init') || this.init === subtype.init) { subtype.init = function () { subtype.$super.init.apply(this, arguments); }; @@ -212,8 +293,8 @@ var CryptoJS = CryptoJS || (function (Math, undefined) { } } else { // Copy one word at a time - for (var i = 0; i < thatSigBytes; i += 4) { - thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; + for (var j = 0; j < thatSigBytes; j += 4) { + thisWords[(thisSigBytes + j) >>> 2] = thatWords[j >>> 2]; } } this.sigBytes += thatSigBytes; @@ -271,26 +352,8 @@ var CryptoJS = CryptoJS || (function (Math, undefined) { 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(cryptoSecureRandomInt()); } return new WordArray.init(words, nBytes); @@ -521,6 +584,8 @@ var CryptoJS = CryptoJS || (function (Math, undefined) { * var processedData = bufferedBlockAlgorithm._process(!!'flush'); */ _process: function (doFlush) { + var processedWords; + // Shortcuts var data = this._data; var dataWords = data.words; @@ -553,7 +618,7 @@ var CryptoJS = CryptoJS || (function (Math, undefined) { } // Remove processed words - var processedWords = dataWords.splice(0, nWordsReady); + processedWords = dataWords.splice(0, nWordsReady); data.sigBytes -= nBytesReady; } diff --git a/src/enc-base64.js b/src/enc-base64.js index 25cc001..a32b9a4 100644 --- a/src/enc-base64.js +++ b/src/enc-base64.js @@ -73,31 +73,44 @@ // Shortcuts var base64StrLength = base64Str.length; var map = this._map; + var reverseMap = this._reverseMap; + + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } // Ignore padding var paddingChar = map.charAt(64); if (paddingChar) { var paddingIndex = base64Str.indexOf(paddingChar); - if (paddingIndex != -1) { + if (paddingIndex !== -1) { base64StrLength = paddingIndex; } } // Convert - var words = []; - var nBytes = 0; - for (var i = 0; i < base64StrLength; i++) { - if (i % 4) { - var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2); - var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2); - words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); - nBytes++; - } - } + return parseLoop(base64Str, base64StrLength, reverseMap); - return WordArray.create(words, nBytes); }, _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' }; + + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } }()); diff --git a/src/enc-base64url.js b/src/enc-base64url.js new file mode 100644 index 0000000..73b6262 --- /dev/null +++ b/src/enc-base64url.js @@ -0,0 +1,128 @@ +(function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * Base64url encoding strategy. + */ + var Base64url = C_enc.Base64url = { + /** + * Converts a word array to a Base64url string. + * + * @param {WordArray} wordArray The word array. + * + * @param {boolean} urlSafe Whether to use url safe + * + * @return {string} The Base64url string. + * + * @static + * + * @example + * + * var base64String = CryptoJS.enc.Base64url.stringify(wordArray); + */ + stringify: function (wordArray, urlSafe) { + if (urlSafe === undefined) { + urlSafe = true + } + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = urlSafe ? this._safe_map : this._map; + + // Clamp excess bits + wordArray.clamp(); + + // Convert + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64url string to a word array. + * + * @param {string} base64Str The Base64url string. + * + * @param {boolean} urlSafe Whether to use url safe + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64url.parse(base64String); + */ + parse: function (base64Str, urlSafe) { + if (urlSafe === undefined) { + urlSafe = true + } + + // Shortcuts + var base64StrLength = base64Str.length; + var map = urlSafe ? this._safe_map : this._map; + var reverseMap = this._reverseMap; + + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex !== -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + return parseLoop(base64Str, base64StrLength, reverseMap); + + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', + _safe_map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_', + }; + + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + var bitsCombined = bits1 | bits2; + words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } +}()); diff --git a/src/evpkdf.js b/src/evpkdf.js index e0fe703..2bc993e 100644 --- a/src/evpkdf.js +++ b/src/evpkdf.js @@ -53,6 +53,8 @@ * var key = kdf.compute(password, salt); */ compute: function (password, salt) { + var block; + // Shortcut var cfg = this.cfg; @@ -72,7 +74,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/src/md5.js b/src/md5.js index 5189321..77ae69d 100644 --- a/src/md5.js +++ b/src/md5.js @@ -60,7 +60,7 @@ var M_offset_14 = M[offset + 14]; var M_offset_15 = M[offset + 15]; - // Working varialbes + // Working variables var a = H[0]; var b = H[1]; var c = H[2]; diff --git a/src/mode-cfb.js b/src/mode-cfb.js index 8d8d449..e750620 100644 --- a/src/mode-cfb.js +++ b/src/mode-cfb.js @@ -34,17 +34,19 @@ CryptoJS.mode.CFB = (function () { }); 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/src/pad-zeropadding.js b/src/pad-zeropadding.js index 76bb279..2b82b58 100644 --- a/src/pad-zeropadding.js +++ b/src/pad-zeropadding.js @@ -17,9 +17,11 @@ CryptoJS.pad.ZeroPadding = { // 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/src/pbkdf2.js b/src/pbkdf2.js index 15a1cfd..92ecf6b 100644 --- a/src/pbkdf2.js +++ b/src/pbkdf2.js @@ -5,7 +5,7 @@ var Base = C_lib.Base; var WordArray = C_lib.WordArray; var C_algo = C.algo; - var SHA1 = C_algo.SHA1; + var SHA256 = C_algo.SHA256; var HMAC = C_algo.HMAC; /** @@ -16,13 +16,13 @@ * Configuration options. * * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) - * @property {Hasher} hasher The hasher to use. Default: SHA1 - * @property {number} iterations The number of iterations to perform. Default: 1 + * @property {Hasher} hasher The hasher to use. Default: SHA256 + * @property {number} iterations The number of iterations to perform. Default: 250000 */ cfg: Base.extend({ keySize: 128/32, - hasher: SHA1, - iterations: 1 + hasher: SHA256, + iterations: 250000 }), /** diff --git a/src/sha3.js b/src/sha3.js index 72ca230..9545fcd 100644 --- a/src/sha3.js +++ b/src/sha3.js @@ -158,6 +158,9 @@ // Rho Pi for (var laneIndex = 1; laneIndex < 25; laneIndex++) { + var tMsw; + var tLsw; + // Shortcuts var lane = state[laneIndex]; var laneMsw = lane.high; @@ -166,11 +169,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 @@ -205,7 +208,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/src/sha512.js b/src/sha512.js index 8646322..2ca9991 100644 --- a/src/sha512.js +++ b/src/sha512.js @@ -127,13 +127,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]; @@ -158,12 +161,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/src/tripledes.js b/src/tripledes.js index 8771943..0777c7c 100644 --- a/src/tripledes.js +++ b/src/tripledes.js @@ -712,11 +712,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) { diff --git a/test/blowfish-test.js b/test/blowfish-test.js new file mode 100644 index 0000000..607354a --- /dev/null +++ b/test/blowfish-test.js @@ -0,0 +1,33 @@ +YUI.add('algo-aes-test', function (Y) { + var C = CryptoJS; + + Y.Test.Runner.add(new Y.Test.Case({ + name: 'Blowfish', + + setUp: function () { + this.data = { + saltA: CryptoJS.enc.Hex.parse('AA00000000000000') + }; + }, + + testEncrypt: function () { + let encryptedA = C.Blowfish.encrypt('Test', + 'pass', + { + salt: this.data.saltA, + hasher: CryptoJS.algo.SHA256 + }).toString(); + Y.Assert.areEqual('U2FsdGVkX1+qAAAAAAAAAKTIU8MPrBdH', encryptedA); + }, + + testDecrypt: function () { + let encryptedA = C.Blowfish.encrypt('Test', + 'pass', + { + salt: this.data.saltA, + hasher: CryptoJS.algo.SHA256 + }).toString(); + Y.Assert.areEqual('Test', C.Blowfish.decrypt(encryptedA, 'pass', {hasher: CryptoJS.algo.SHA256}).toString(C.enc.Utf8)); + } + })); +}, '$Rev$'); diff --git a/test/cipher-test.js b/test/cipher-test.js new file mode 100644 index 0000000..2529eff --- /dev/null +++ b/test/cipher-test.js @@ -0,0 +1,522 @@ +function extendWithCMAC(C) { + function createExt(C) { + /* + * The MIT License (MIT) + * + * Copyright (c) 2015 artjomb + */ + // put on ext property in CryptoJS + var ext; + if (!C.hasOwnProperty("ext")) { + ext = C.ext = {}; + } else { + ext = C.ext; + } + + // Shortcuts + var Base = C.lib.Base; + var WordArray = C.lib.WordArray; + + // Constants + ext.const_Zero = new WordArray.init([0x00000000, 0x00000000, 0x00000000, 0x00000000]); + ext.const_One = new WordArray.init([0x00000000, 0x00000000, 0x00000000, 0x00000001]); + ext.const_Rb = new WordArray.init([0x00000000, 0x00000000, 0x00000000, 0x00000087]); // 00..0010000111 + ext.const_Rb_Shifted = new WordArray.init([0x80000000, 0x00000000, 0x00000000, 0x00000043]); // 100..001000011 + ext.const_nonMSB = new WordArray.init([0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF]); // 1^64 || 0^1 || 1^31 || 0^1 || 1^31 + + /** + * Looks into the object to see if it is a WordArray. + * + * @param obj Some object + * + * @returns {boolean} + */ + ext.isWordArray = function(obj) { + return obj && typeof obj.clamp === "function" && typeof obj.concat === "function" && typeof obj.words === "array"; + } + + /** + * This padding is a 1 bit followed by as many 0 bits as needed to fill + * up the block. This implementation doesn't work on bits directly, + * but on bytes. Therefore the granularity is much bigger. + */ + C.pad.OneZeroPadding = { + pad: function (data, blocksize) { + // Shortcut + var blockSizeBytes = blocksize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; + + // Create padding + var paddingWords = []; + for (var i = 0; i < nPaddingBytes; i += 4) { + var paddingWord = 0x00000000; + if (i === 0) { + paddingWord = 0x80000000; + } + paddingWords.push(paddingWord); + } + var padding = new WordArray.init(paddingWords, nPaddingBytes); + + // Add padding + data.concat(padding); + }, + unpad: function () { + // TODO: implement + } + }; + + /** + * No padding is applied. This is necessary for streaming cipher modes + * like CTR. + */ + C.pad.NoPadding = { + pad: function () {}, + unpad: function () {} + }; + + /** + * Returns the n leftmost bytes of the WordArray. + * + * @param {WordArray} wordArray WordArray to work on + * @param {int} n Bytes to retrieve + * + * @returns new WordArray + */ + ext.leftmostBytes = function(wordArray, n){ + var lmArray = wordArray.clone(); + lmArray.sigBytes = n; + lmArray.clamp(); + return lmArray; + }; + + /** + * Returns the n rightmost bytes of the WordArray. + * + * @param {WordArray} wordArray WordArray to work on + * @param {int} n Bytes to retrieve (must be positive) + * + * @returns new WordArray + */ + ext.rightmostBytes = function(wordArray, n){ + wordArray.clamp(); + var wordSize = 32; + var rmArray = wordArray.clone(); + var bitsToShift = (rmArray.sigBytes - n) * 8; + if (bitsToShift >= wordSize) { + var popCount = Math.floor(bitsToShift/wordSize); + bitsToShift -= popCount * wordSize; + rmArray.words.splice(0, popCount); + rmArray.sigBytes -= popCount * wordSize / 8; + } + if (bitsToShift > 0) { + ext.bitshift(rmArray, bitsToShift); + rmArray.sigBytes -= bitsToShift / 8; + } + return rmArray; + }; + + /** + * Returns the n rightmost words of the WordArray. It assumes + * that the current WordArray has at least n words. + * + * @param {WordArray} wordArray WordArray to work on + * @param {int} n Words to retrieve (must be positive) + * + * @returns popped words as new WordArray + */ + ext.popWords = function(wordArray, n){ + var left = wordArray.words.splice(0, n); + wordArray.sigBytes -= n * 4; + return new WordArray.init(left); + }; + + /** + * Shifts the array to the left and returns the shifted dropped elements + * as WordArray. The initial WordArray must contain at least n bytes and + * they have to be significant. + * + * @param {WordArray} wordArray WordArray to work on (is modified) + * @param {int} n Bytes to shift (must be positive, default 16) + * + * @returns new WordArray + */ + ext.shiftBytes = function(wordArray, n){ + n = n || 16; + var r = n % 4; + n -= r; + + var shiftedArray = new WordArray.init(); + for(var i = 0; i < n; i += 4) { + shiftedArray.words.push(wordArray.words.shift()); + wordArray.sigBytes -= 4; + shiftedArray.sigBytes += 4; + } + if (r > 0) { + shiftedArray.words.push(wordArray.words[0]); + shiftedArray.sigBytes += r; + + ext.bitshift(wordArray, r * 8); + wordArray.sigBytes -= r; + } + return shiftedArray; + }; + + /** + * XORs arr2 to the end of arr1 array. This doesn't modify the current + * array aside from clamping. + * + * @param {WordArray} arr1 Bigger array + * @param {WordArray} arr2 Smaller array to be XORed to the end + * + * @returns new WordArray + */ + ext.xorendBytes = function(arr1, arr2){ + // TODO: more efficient + return ext.leftmostBytes(arr1, arr1.sigBytes-arr2.sigBytes) + .concat(ext.xor(ext.rightmostBytes(arr1, arr2.sigBytes), arr2)); + }; + + /** + * Doubling operation on a 128-bit value. This operation modifies the + * passed array. + * + * @param {WordArray} wordArray WordArray to work on + * + * @returns passed WordArray + */ + ext.dbl = function(wordArray){ + var carry = ext.msb(wordArray); + ext.bitshift(wordArray, 1); + ext.xor(wordArray, carry === 1 ? ext.const_Rb : ext.const_Zero); + return wordArray; + }; + + /** + * Inverse operation on a 128-bit value. This operation modifies the + * passed array. + * + * @param {WordArray} wordArray WordArray to work on + * + * @returns passed WordArray + */ + ext.inv = function(wordArray){ + var carry = wordArray.words[4] & 1; + ext.bitshift(wordArray, -1); + ext.xor(wordArray, carry === 1 ? ext.const_Rb_Shifted : ext.const_Zero); + return wordArray; + }; + + /** + * Check whether the word arrays are equal. + * + * @param {WordArray} arr1 Array 1 + * @param {WordArray} arr2 Array 2 + * + * @returns boolean + */ + ext.equals = function(arr1, arr2){ + if (!arr2 || !arr2.words || arr1.sigBytes !== arr2.sigBytes) { + return false; + } + arr1.clamp(); + arr2.clamp(); + var equal = 0; + for(var i = 0; i < arr1.words.length; i++) { + equal |= arr1.words[i] ^ arr2.words[i]; + } + return equal === 0; + }; + + /** + * Retrieves the most significant bit of the WordArray as an Integer. + * + * @param {WordArray} arr + * + * @returns Integer + */ + ext.msb = function(arr) { + return arr.words[0] >>> 31; + } + } + + function createExtBit(C) { + /* + * The MIT License (MIT) + * + * Copyright (c) 2015 artjomb + */ + // put on ext property in CryptoJS + var ext; + if (!C.hasOwnProperty("ext")) { + ext = C.ext = {}; + } else { + ext = C.ext; + } + + /** + * Shifts the array by n bits to the left. Zero bits are added as the + * least significant bits. This operation modifies the current array. + * + * @param {WordArray} wordArray WordArray to work on + * @param {int} n Bits to shift by + * + * @returns the WordArray that was passed in + */ + ext.bitshift = function(wordArray, n){ + var carry = 0, + words = wordArray.words, + wres, + skipped = 0, + carryMask; + if (n > 0) { + while(n > 31) { + // delete first element: + words.splice(0, 1); + + // add `0` word to the back + words.push(0); + + n -= 32; + skipped++; + } + if (n == 0) { + // 1. nothing to shift if the shift amount is on a word boundary + // 2. This has to be done, because the following algorithm computes + // wrong values only for n==0 + return carry; + } + for(var i = words.length - skipped - 1; i >= 0; i--) { + wres = words[i]; + words[i] <<= n; + words[i] |= carry; + carry = wres >>> (32 - n); + } + } else if (n < 0) { + while(n < -31) { + // insert `0` word to the front: + words.splice(0, 0, 0); + + // remove last element: + words.length--; + + n += 32; + skipped++; + } + if (n == 0) { + // nothing to shift if the shift amount is on a word boundary + return carry; + } + n = -n; + carryMask = (1 << n) - 1; + for(var i = skipped; i < words.length; i++) { + wres = words[i] & carryMask; + words[i] >>>= n; + words[i] |= carry; + carry = wres << (32 - n); + } + } + return carry; + }; + + /** + * Negates all bits in the WordArray. This manipulates the given array. + * + * @param {WordArray} wordArray WordArray to work on + * + * @returns the WordArray that was passed in + */ + ext.neg = function(wordArray){ + var words = wordArray.words; + for(var i = 0; i < words.length; i++) { + words[i] = ~words[i]; + } + return wordArray; + }; + + /** + * Applies XOR on both given word arrays and returns a third resulting + * WordArray. The initial word arrays must have the same length + * (significant bytes). + * + * @param {WordArray} wordArray1 WordArray + * @param {WordArray} wordArray2 WordArray + * + * @returns first passed WordArray (modified) + */ + ext.xor = function(wordArray1, wordArray2){ + for(var i = 0; i < wordArray1.words.length; i++) { + wordArray1.words[i] ^= wordArray2.words[i]; + } + return wordArray1; + }; + + /** + * Logical AND between the two passed arrays. Both arrays must have the + * same length. + * + * @param {WordArray} arr1 Array 1 + * @param {WordArray} arr2 Array 2 + * + * @returns new WordArray + */ + ext.bitand = function(arr1, arr2){ + var newArr = arr1.clone(), + tw = newArr.words, + ow = arr2.words; + for(var i = 0; i < tw.length; i++) { + tw[i] &= ow[i]; + } + return newArr; + }; + } + + function createCMAC(C) { + /* + * The MIT License (MIT) + * + * Copyright (c) 2015 artjomb + */ + // Shortcuts + var Base = C.lib.Base; + var WordArray = C.lib.WordArray; + var AES = C.algo.AES; + var ext = C.ext; + var OneZeroPadding = C.pad.OneZeroPadding; + + var CMAC = C.algo.CMAC = Base.extend({ + /** + * Initializes a newly created CMAC + * + * @param {WordArray} key The secret key + * + * @example + * + * var cmacer = CryptoJS.algo.CMAC.create(key); + */ + init: function(key){ + // generate sub keys... + this._aes = AES.createEncryptor(key, { iv: new WordArray.init(), padding: C.pad.NoPadding }); + + // Step 1 + var L = this._aes.finalize(ext.const_Zero); + + // Step 2 + var K1 = L.clone(); + ext.dbl(K1); + + // Step 3 + if (!this._isTwo) { + var K2 = K1.clone(); + ext.dbl(K2); + } else { + var K2 = L.clone(); + ext.inv(K2); + } + + this._K1 = K1; + this._K2 = K2; + + this._const_Bsize = 16; + + this.reset(); + }, + + reset: function () { + this._x = ext.const_Zero.clone(); + this._counter = 0; + this._buffer = new WordArray.init(); + }, + + update: function (messageUpdate) { + if (!messageUpdate) { + return this; + } + + // Shortcuts + var buffer = this._buffer; + var bsize = this._const_Bsize; + + if (typeof messageUpdate === "string") { + messageUpdate = C.enc.Utf8.parse(messageUpdate); + } + + buffer.concat(messageUpdate); + + while(buffer.sigBytes > bsize){ + var M_i = ext.shiftBytes(buffer, bsize); + ext.xor(this._x, M_i); + this._x.clamp(); + this._aes.reset(); + this._x = this._aes.finalize(this._x); + this._counter++; + } + + // Chainable + return this; + }, + + finalize: function (messageUpdate) { + this.update(messageUpdate); + + // Shortcuts + var buffer = this._buffer; + var bsize = this._const_Bsize; + + var M_last = buffer.clone(); + if (buffer.sigBytes === bsize) { + ext.xor(M_last, this._K1); + } else { + OneZeroPadding.pad(M_last, bsize/4); + ext.xor(M_last, this._K2); + } + + ext.xor(M_last, this._x); + + this.reset(); // Can be used immediately afterwards + + this._aes.reset(); + return this._aes.finalize(M_last); + }, + + _isTwo: false + }); + + /** + * Directly invokes the CMAC and returns the calculated MAC. + * + * @param {WordArray} key The key to be used for CMAC + * @param {WordArray|string} message The data to be MAC'ed (either WordArray or UTF-8 encoded string) + * + * @returns {WordArray} MAC + */ + C.CMAC = function(key, message){ + return CMAC.create(key).finalize(message); + }; + + C.algo.OMAC1 = CMAC; + C.algo.OMAC2 = CMAC.extend({ + _isTwo: true + }); + } + + createExt(C); + createExtBit(C); + createCMAC(C); +} + +YUI.add('cipher-core-test', function (Y) { + var C = CryptoJS; + + // Extend with CMAC to test `cipher-core.js` L:457-462 + extendWithCMAC(C); + + Y.Test.Runner.add(new Y.Test.Case({ + name: 'Cipher', + + testCMAC: function () { + Y.Assert.areEqual('35e1872b95ce5d99bb5dbbbbd79b9b9b', C.CMAC('69c4e0d86a7b0430d8cdb78070b4c55a', 'Test message').toString()); + } + })); +}, '$Rev$'); diff --git a/test/config-test.js b/test/config-test.js new file mode 100644 index 0000000..c09e425 --- /dev/null +++ b/test/config-test.js @@ -0,0 +1,51 @@ +YUI.add('config-test', function (Y) { + var C = CryptoJS; + + Y.Test.Runner.add(new Y.Test.Case({ + name: 'Config', + + setUp: function () { + this.data = { + saltA: CryptoJS.enc.Hex.parse('AA00000000000000'), + saltB: CryptoJS.enc.Hex.parse('BB00000000000000') + }; + }, + + testEncrypt: function () { + Y.Assert.areEqual(C.AES.encrypt('Test', 'Pass', { salt: this.data.saltA }).toString(), C.AES.encrypt('Test', 'Pass', { salt: this.data.saltA }).toString()); + Y.Assert.areNotEqual(C.AES.encrypt('Test', 'Pass', { salt: this.data.saltA }).toString(), C.AES.encrypt('Test', 'Pass', { salt: this.data.saltB }).toString()); + }, + + testDecrypt: function () { + var encryptedA = C.AES.encrypt('Test', 'Pass', { salt: this.data.saltA }); + var encryptedB = C.AES.encrypt('Test', 'Pass', { salt: this.data.saltB }); + Y.Assert.areEqual('Test', C.AES.decrypt(encryptedA, 'Pass').toString(C.enc.Utf8)); + Y.Assert.areEqual('Test', C.AES.decrypt(encryptedB, 'Pass').toString(C.enc.Utf8)); + }, + + testCustomKDFHasher: function () { + //SHA1 + let encryptedSHA1 = C.AES.encrypt('Test', 'Pass', { salt: this.data.saltA, hasher: C.algo.SHA1}).toString(); + Y.Assert.areEqual('Test', C.AES.decrypt(encryptedSHA1, 'Pass', { hasher: C.algo.SHA1}).toString(C.enc.Utf8)); + + //SHA256 + let encryptedSHA256 = C.AES.encrypt('Test', 'Pass', { salt: this.data.saltA, hasher: C.algo.SHA256}).toString(); + Y.Assert.areEqual('Test', C.AES.decrypt(encryptedSHA256, 'Pass', { hasher: C.algo.SHA256}).toString(C.enc.Utf8)); + + //SHA512 + let encryptedSHA512 = C.AES.encrypt('Test', 'Pass', { salt: this.data.saltA, hasher: C.algo.SHA512}).toString(); + Y.Assert.areEqual('Test', C.AES.decrypt(encryptedSHA512, 'Pass', { hasher: C.algo.SHA512}).toString(C.enc.Utf8)); + + //Default: MD5 + let encryptedDefault = C.AES.encrypt('Test', 'Pass', { salt: this.data.saltA }).toString(); + let encryptedMD5 = C.AES.encrypt('Test', 'Pass', { salt: this.data.saltA, hasher: C.algo.MD5}).toString(); + Y.Assert.areEqual('Test', C.AES.decrypt(encryptedMD5, 'Pass', { hasher: C.algo.MD5}).toString(C.enc.Utf8)); + Y.Assert.areEqual(encryptedDefault, encryptedMD5); + + //Different KDFHasher + Y.Assert.areNotEqual(encryptedDefault, encryptedSHA1); + Y.Assert.areNotEqual(encryptedDefault, encryptedSHA256); + Y.Assert.areNotEqual(encryptedDefault, encryptedSHA512); + } + })); +}, '$Rev$'); \ No newline at end of file diff --git a/test/hmac-md5-test.js b/test/hmac-md5-test.js index b50bb04..b87aaf9 100644 --- a/test/hmac-md5-test.js +++ b/test/hmac-md5-test.js @@ -17,11 +17,11 @@ YUI.add('algo-hmac-md5-test', function (Y) { }, testVector4: function () { - Y.Assert.areEqual('7ee2a3cc979ab19865704644ce13355c', C.HmacMD5('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'A')); + Y.Assert.areEqual('7ee2a3cc979ab19865704644ce13355c', C.HmacMD5('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'A').toString()); }, testVector5: function () { - Y.Assert.areEqual('0e1bd89c43e3e6e3b3f8cf1d5ba4f77a', C.HmacMD5('abcdefghijklmnopqrstuvwxyz', 'A')); + Y.Assert.areEqual('0e1bd89c43e3e6e3b3f8cf1d5ba4f77a', C.HmacMD5('abcdefghijklmnopqrstuvwxyz', 'A').toString()); }, testUpdate: function () { diff --git a/test/hmac-sha224-test.js b/test/hmac-sha224-test.js index 77b1788..4895137 100644 --- a/test/hmac-sha224-test.js +++ b/test/hmac-sha224-test.js @@ -17,11 +17,11 @@ YUI.add('algo-hmac-sha224-test', function (Y) { }, testVector4: function () { - Y.Assert.areEqual('61bf669da4fdcd8e5c3bd09ebbb4a986d3d1b298d3ca05c511f7aeff', C.HmacSHA224('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'A')); + Y.Assert.areEqual('61bf669da4fdcd8e5c3bd09ebbb4a986d3d1b298d3ca05c511f7aeff', C.HmacSHA224('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'A').toString()); }, testVector5: function () { - Y.Assert.areEqual('16fc69ada3c3edc1fe9144d6b98d93393833ae442bedf681110a1176', C.HmacSHA224('abcdefghijklmnopqrstuvwxyz', 'A')); + Y.Assert.areEqual('16fc69ada3c3edc1fe9144d6b98d93393833ae442bedf681110a1176', C.HmacSHA224('abcdefghijklmnopqrstuvwxyz', 'A').toString()); }, testUpdate: function () { diff --git a/test/hmac-sha256-test.js b/test/hmac-sha256-test.js index e8c3b1f..f10d89e 100644 --- a/test/hmac-sha256-test.js +++ b/test/hmac-sha256-test.js @@ -17,11 +17,11 @@ YUI.add('algo-hmac-sha256-test', function (Y) { }, testVector4: function () { - Y.Assert.areEqual('a89dc8178c1184a62df87adaa77bf86e93064863d93c5131140b0ae98b866687', C.HmacSHA256('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'A')); + Y.Assert.areEqual('a89dc8178c1184a62df87adaa77bf86e93064863d93c5131140b0ae98b866687', C.HmacSHA256('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'A').toString()); }, testVector5: function () { - Y.Assert.areEqual('d8cb78419c02fe20b90f8b77427dd9f81817a751d74c2e484e0ac5fc4e6ca986', C.HmacSHA256('abcdefghijklmnopqrstuvwxyz', 'A')); + Y.Assert.areEqual('d8cb78419c02fe20b90f8b77427dd9f81817a751d74c2e484e0ac5fc4e6ca986', C.HmacSHA256('abcdefghijklmnopqrstuvwxyz', 'A').toString()); }, testUpdate: function () { diff --git a/test/hmac-sha384-test.js b/test/hmac-sha384-test.js index aa89455..ebea5e1 100644 --- a/test/hmac-sha384-test.js +++ b/test/hmac-sha384-test.js @@ -17,11 +17,11 @@ YUI.add('algo-hmac-sha384-test', function (Y) { }, testVector4: function () { - Y.Assert.areEqual('365dfb271adb8e30fe6c74220b75df1b38c2d19b9d37f2e5a0ec2f3f22bd0406bf5b786e98d81b82c36d3d8a1be6cd07', C.HmacSHA384('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'A')); + Y.Assert.areEqual('365dfb271adb8e30fe6c74220b75df1b38c2d19b9d37f2e5a0ec2f3f22bd0406bf5b786e98d81b82c36d3d8a1be6cd07', C.HmacSHA384('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'A').toString()); }, testVector5: function () { - Y.Assert.areEqual('a8357d5e84da64140e41545562ae0782e2a58e39c6cd98939fad8d9080e774c84b7eaca4ba07f6dbf0f12eab912c5285', C.HmacSHA384('abcdefghijklmnopqrstuvwxyz', 'A')); + Y.Assert.areEqual('a8357d5e84da64140e41545562ae0782e2a58e39c6cd98939fad8d9080e774c84b7eaca4ba07f6dbf0f12eab912c5285', C.HmacSHA384('abcdefghijklmnopqrstuvwxyz', 'A').toString()); }, testUpdate: function () { diff --git a/test/hmac-sha512-test.js b/test/hmac-sha512-test.js index ceb2c7d..1e5d820 100644 --- a/test/hmac-sha512-test.js +++ b/test/hmac-sha512-test.js @@ -17,11 +17,11 @@ YUI.add('algo-hmac-sha512-test', function (Y) { }, testVector4: function () { - Y.Assert.areEqual('a303979f7c94bb39a8ab6ce05cdbe28f0255da8bb305263e3478ef7e855f0242729bf1d2be55398f14da8e63f0302465a8a3f76c297bd584ad028d18ed7f0195', C.HmacSHA512('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'A')); + Y.Assert.areEqual('a303979f7c94bb39a8ab6ce05cdbe28f0255da8bb305263e3478ef7e855f0242729bf1d2be55398f14da8e63f0302465a8a3f76c297bd584ad028d18ed7f0195', C.HmacSHA512('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'A').toString()); }, testVector5: function () { - Y.Assert.areEqual('8c2d56f7628325e62124c0a870ad98d101327fc42696899a06ce0d7121454022fae597e42c25ac3a4c380fd514f553702a5b0afaa9b5a22050902f024368e9d9', C.HmacSHA512('abcdefghijklmnopqrstuvwxyz', 'A')); + Y.Assert.areEqual('8c2d56f7628325e62124c0a870ad98d101327fc42696899a06ce0d7121454022fae597e42c25ac3a4c380fd514f553702a5b0afaa9b5a22050902f024368e9d9', C.HmacSHA512('abcdefghijklmnopqrstuvwxyz', 'A').toString()); }, testUpdate: function () { diff --git a/test/lib-base-test.js b/test/lib-base-test.js index 8d3c715..ed8e642 100644 --- a/test/lib-base-test.js +++ b/test/lib-base-test.js @@ -81,6 +81,12 @@ YUI.add('lib-base-test', function (Y) { this.data.obj.initArg = 'newValue'; Y.Assert.areNotEqual(this.data.obj.initArg, this.data.objClone.initArg); + }, + + testCloneLeavesOriginalInitPrototypeUnchanged: function() { + Y.Assert.areEqual(this.data.obj, this.data.obj.init.prototype); + Y.Assert.areEqual(this.data.objClone, this.data.objClone.init.prototype); + Y.Assert.areNotEqual(this.data.obj.init.prototype, this.data.objClone.init.prototype); } })); }, '$Rev$'); diff --git a/test/pbkdf2-test.js b/test/pbkdf2-test.js index e187008..c15f569 100644 --- a/test/pbkdf2-test.js +++ b/test/pbkdf2-test.js @@ -5,59 +5,59 @@ YUI.add('algo-pbkdf2-test', function (Y) { name: 'PBKDF2', testKeySize128: function () { - Y.Assert.areEqual('cdedb5281bb2f801565a1122b2563515', C.PBKDF2('password', 'ATHENA.MIT.EDUraeburn', { keySize: 128/32 }).toString()); + Y.Assert.areEqual('62929ab995a1111c75c37bc562261ea3', C.PBKDF2('password', 'ATHENA.MIT.EDUraeburn', { keySize: 128/32 }).toString()); }, testKeySize256: function () { - Y.Assert.areEqual('cdedb5281bb2f801565a1122b25635150ad1f7a04bb9f3a333ecc0e2e1f70837', C.PBKDF2('password', 'ATHENA.MIT.EDUraeburn', { keySize: 256/32 }).toString()); + Y.Assert.areEqual('62929ab995a1111c75c37bc562261ea3fb3cdc7e725c4ca87c03cec5bb7663e1', C.PBKDF2('password', 'ATHENA.MIT.EDUraeburn', { keySize: 256/32 }).toString()); }, testKeySize128Iterations2: function () { - Y.Assert.areEqual('01dbee7f4a9e243e988b62c73cda935d', C.PBKDF2('password', 'ATHENA.MIT.EDUraeburn', { keySize: 128/32, iterations: 2 }).toString()); + Y.Assert.areEqual('262fb72ea65b44ab5ceba7f8c8bfa781', C.PBKDF2('password', 'ATHENA.MIT.EDUraeburn', { keySize: 128/32, iterations: 2 }).toString()); }, testKeySize256Iterations2: function () { - Y.Assert.areEqual('01dbee7f4a9e243e988b62c73cda935da05378b93244ec8f48a99e61ad799d86', C.PBKDF2('password', 'ATHENA.MIT.EDUraeburn', { keySize: 256/32, iterations: 2 }).toString()); + Y.Assert.areEqual('262fb72ea65b44ab5ceba7f8c8bfa7815ff9939204eb7357a59a75877d745777', C.PBKDF2('password', 'ATHENA.MIT.EDUraeburn', { keySize: 256/32, iterations: 2 }).toString()); }, testKeySize128Iterations1200: function () { - Y.Assert.areEqual('5c08eb61fdf71e4e4ec3cf6ba1f5512b', C.PBKDF2('password', 'ATHENA.MIT.EDUraeburn', { keySize: 128/32, iterations: 1200 }).toString()); + Y.Assert.areEqual('c76a982415f1acc71dc197273c5b6ada', C.PBKDF2('password', 'ATHENA.MIT.EDUraeburn', { keySize: 128/32, iterations: 1200 }).toString()); }, testKeySize256Iterations1200: function () { - Y.Assert.areEqual('5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13', C.PBKDF2('password', 'ATHENA.MIT.EDUraeburn', { keySize: 256/32, iterations: 1200 }).toString()); + Y.Assert.areEqual('c76a982415f1acc71dc197273c5b6ada32f62915ed461718aad32843762433fa', C.PBKDF2('password', 'ATHENA.MIT.EDUraeburn', { keySize: 256/32, iterations: 1200 }).toString()); }, testKeySize128Iterations5: function () { - Y.Assert.areEqual('d1daa78615f287e6a1c8b120d7062a49', C.PBKDF2('password', C.enc.Hex.parse('1234567878563412'), { keySize: 128/32, iterations: 5 }).toString()); + Y.Assert.areEqual('74e98b2e9eeddaab3113c1efc6d82b07', C.PBKDF2('password', C.enc.Hex.parse('1234567878563412'), { keySize: 128/32, iterations: 5 }).toString()); }, testKeySize256Iterations5: function () { - Y.Assert.areEqual('d1daa78615f287e6a1c8b120d7062a493f98d203e6be49a6adf4fa574b6e64ee', C.PBKDF2('password', C.enc.Hex.parse('1234567878563412'), { keySize: 256/32, iterations: 5 }).toString()); + Y.Assert.areEqual('74e98b2e9eeddaab3113c1efc6d82b073c4860195b3e0737fa21a4778f376321', C.PBKDF2('password', C.enc.Hex.parse('1234567878563412'), { keySize: 256/32, iterations: 5 }).toString()); }, testKeySize128Iterations1200PassPhraseEqualsBlockSize: function () { - Y.Assert.areEqual('139c30c0966bc32ba55fdbf212530ac9', C.PBKDF2('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 'pass phrase equals block size', { keySize: 128/32, iterations: 1200 }).toString()); + Y.Assert.areEqual('c1dfb29a4d2f2fb67c6f78d074d66367', C.PBKDF2('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 'pass phrase equals block size', { keySize: 128/32, iterations: 1200 }).toString()); }, testKeySize256Iterations1200PassPhraseEqualsBlockSize: function () { - Y.Assert.areEqual('139c30c0966bc32ba55fdbf212530ac9c5ec59f1a452f5cc9ad940fea0598ed1', C.PBKDF2('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 'pass phrase equals block size', { keySize: 256/32, iterations: 1200 }).toString()); + Y.Assert.areEqual('c1dfb29a4d2f2fb67c6f78d074d663671e6fd4da1e598572b1fecf256cb7cf61', C.PBKDF2('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 'pass phrase equals block size', { keySize: 256/32, iterations: 1200 }).toString()); }, testKeySize128Iterations1200PassPhraseExceedsBlockSize: function () { - Y.Assert.areEqual('9ccad6d468770cd51b10e6a68721be61', C.PBKDF2('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 'pass phrase exceeds block size', { keySize: 128/32, iterations: 1200 }).toString()); + Y.Assert.areEqual('22344bc4b6e32675a8090f3ea80be01d', C.PBKDF2('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 'pass phrase exceeds block size', { keySize: 128/32, iterations: 1200 }).toString()); }, testKeySize256Iterations1200PassPhraseExceedsBlockSize: function () { - Y.Assert.areEqual('9ccad6d468770cd51b10e6a68721be611a8b4d282601db3b36be9246915ec82a', C.PBKDF2('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 'pass phrase exceeds block size', { keySize: 256/32, iterations: 1200 }).toString()); + Y.Assert.areEqual('22344bc4b6e32675a8090f3ea80be01d5f95126a2cddc3facc4a5e6dca04ec58', C.PBKDF2('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 'pass phrase exceeds block size', { keySize: 256/32, iterations: 1200 }).toString()); }, testKeySize128Iterations50: function () { - Y.Assert.areEqual('6b9cf26d45455a43a5b8bb276a403b39', C.PBKDF2(C.enc.Hex.parse('f09d849e'), 'EXAMPLE.COMpianist', { keySize: 128/32, iterations: 50 }).toString()); + Y.Assert.areEqual('44b0781253db3141ac4174af29325818', C.PBKDF2(C.enc.Hex.parse('f09d849e'), 'EXAMPLE.COMpianist', { keySize: 128/32, iterations: 50 }).toString()); }, testKeySize256Iterations50: function () { - Y.Assert.areEqual('6b9cf26d45455a43a5b8bb276a403b39e7fe37a0c41e02c281ff3069e1e94f52', C.PBKDF2(C.enc.Hex.parse('f09d849e'), 'EXAMPLE.COMpianist', { keySize: 256/32, iterations: 50 }).toString()); + Y.Assert.areEqual('44b0781253db3141ac4174af29325818584698d507a79f9879033dec308a2b77', C.PBKDF2(C.enc.Hex.parse('f09d849e'), 'EXAMPLE.COMpianist', { keySize: 256/32, iterations: 50 }).toString()); }, testInputIntegrity: function () { diff --git a/test/test-build.html b/test/test-build.html new file mode 100644 index 0000000..c6eb05c --- /dev/null +++ b/test/test-build.html @@ -0,0 +1,105 @@ + + + + + CryptoJS Test Suite + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/test.html b/test/test.html index 6a05ea6..70a0edf 100644 --- a/test/test.html +++ b/test/test.html @@ -35,6 +35,7 @@ + @@ -84,9 +85,12 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/tripledes-test.js b/test/tripledes-test.js index b531bc8..dcc7f4a 100644 --- a/test/tripledes-test.js +++ b/test/tripledes-test.js @@ -62,6 +62,39 @@ YUI.add('algo-tripledes-test', function (Y) { Y.Assert.areEqual(expectedIv, iv.toString()); }, + test64BitKey: function() { + var message = C.enc.Hex.parse('00112233445566778899aabbccddeeff'); + var key = C.enc.Hex.parse('0011223344556677'); + var extendedKey = C.enc.Hex.parse('001122334455667700112233445566770011223344556677') + + var output1 = C.TripleDES.encrypt(message, key, { mode: C.mode.ECB }).toString(); + var output2 = C.TripleDES.encrypt(message, extendedKey, { mode: C.mode.ECB }).toString(); + + Y.Assert.areEqual(output1, output2); + }, + + test128BitKey: function() { + var message = C.enc.Hex.parse('00112233445566778899aabbccddeeff'); + var key = C.enc.Hex.parse('00112233445566778899aabbccddeeff'); + var extendedKey = C.enc.Hex.parse('00112233445566778899aabbccddeeff0011223344556677') + + var output1 = C.TripleDES.encrypt(message, key, { mode: C.mode.ECB }).toString(); + var output2 = C.TripleDES.encrypt(message, extendedKey, { mode: C.mode.ECB }).toString(); + + Y.Assert.areEqual(output1, output2); + }, + + test256BitKey: function() { + var message = C.enc.Hex.parse('00112233445566778899aabbccddeeff'); + var key = C.enc.Hex.parse('00112233445566778899aabbccddeeff0112233445566778899aabbccddeeff0'); + var truncatedKey = C.enc.Hex.parse('00112233445566778899aabbccddeeff0112233445566778') + + var output1 = C.TripleDES.encrypt(message, key, { mode: C.mode.ECB }).toString(); + var output2 = C.TripleDES.encrypt(message, truncatedKey, { mode: C.mode.ECB }).toString(); + + Y.Assert.areEqual(output1, output2); + }, + testHelper: function () { // Save original random method var random = C.lib.WordArray.random;