From 9ffab374dbf8cc580aa8e8e644e0fc14a033d127 Mon Sep 17 00:00:00 2001 From: Matt C Date: Wed, 23 May 2018 18:31:26 +0100 Subject: [PATCH] Converted PBKDF2 and RC2, enabled tests, deleted legacy Cipher file Also made DESDecrypt test pass --- src/core/operations/DESDecrypt.mjs | 1 + src/core/operations/DerivePBKDF2Key.mjs | 77 +++++++++++ src/core/operations/RC2Decrypt.mjs | 76 ++++++++++ src/core/operations/RC2Encrypt.mjs | 77 +++++++++++ src/core/operations/legacy/Cipher.js | 175 ------------------------ test/index.mjs | 2 +- 6 files changed, 232 insertions(+), 176 deletions(-) create mode 100644 src/core/operations/DerivePBKDF2Key.mjs create mode 100644 src/core/operations/RC2Decrypt.mjs create mode 100644 src/core/operations/RC2Encrypt.mjs delete mode 100755 src/core/operations/legacy/Cipher.js diff --git a/src/core/operations/DESDecrypt.mjs b/src/core/operations/DESDecrypt.mjs index 4c8a37ce..9cdcf5fd 100644 --- a/src/core/operations/DESDecrypt.mjs +++ b/src/core/operations/DESDecrypt.mjs @@ -69,6 +69,7 @@ class DESDecrypt extends Operation { if (key.length !== 8) { return `Invalid key length: ${key.length} bytes + DES uses a key length of 8 bytes (64 bits). Triple DES uses a key length of 24 bytes (192 bits).`; } diff --git a/src/core/operations/DerivePBKDF2Key.mjs b/src/core/operations/DerivePBKDF2Key.mjs new file mode 100644 index 00000000..d3f7fe9a --- /dev/null +++ b/src/core/operations/DerivePBKDF2Key.mjs @@ -0,0 +1,77 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import Utils from "../Utils"; +import forge from "node-forge/dist/forge.min.js"; + +/** + * Derive PBKDF2 key operation + */ +class DerivePBKDF2Key extends Operation { + + /** + * DerivePBKDF2Key constructor + */ + constructor() { + super(); + + this.name = "Derive PBKDF2 key"; + this.module = "Ciphers"; + this.description = "PBKDF2 is a password-based key derivation function. It is part of RSA Laboratories' Public-Key Cryptography Standards (PKCS) series, specifically PKCS #5 v2.0, also published as Internet Engineering Task Force's RFC 2898.

In many applications of cryptography, user security is ultimately dependent on a password, and because a password usually can't be used directly as a cryptographic key, some processing is required.

A salt provides a large set of keys for any given password, and an iteration count increases the cost of producing keys from a password, thereby also increasing the difficulty of attack.

If you leave the salt argument empty, a random salt will be generated."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Passphrase", + "type": "toggleString", + "value": "", + "toggleValues": ["UTF8", "Latin1", "Hex", "Base64"] + }, + { + "name": "Key size", + "type": "number", + "value": 128 + }, + { + "name": "Iterations", + "type": "number", + "value": 1 + }, + { + "name": "Hashing function", + "type": "option", + "value": ["SHA1", "SHA256", "SHA384", "SHA512", "MD5"] + }, + { + "name": "Salt", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const passphrase = Utils.convertToByteString(args[0].string, args[0].option), + keySize = args[1], + iterations = args[2], + hasher = args[3], + salt = Utils.convertToByteString(args[4].string, args[4].option) || + forge.random.getBytesSync(keySize), + derivedKey = forge.pkcs5.pbkdf2(passphrase, salt, iterations, keySize / 8, hasher.toLowerCase()); + + return forge.util.bytesToHex(derivedKey); + } + +} + +export default DerivePBKDF2Key; diff --git a/src/core/operations/RC2Decrypt.mjs b/src/core/operations/RC2Decrypt.mjs new file mode 100644 index 00000000..77dc5da5 --- /dev/null +++ b/src/core/operations/RC2Decrypt.mjs @@ -0,0 +1,76 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import Utils from "../Utils"; +import forge from "node-forge/dist/forge.min.js"; + +/** + * RC2 Decrypt operation + */ +class RC2Decrypt extends Operation { + + /** + * RC2Decrypt constructor + */ + constructor() { + super(); + + this.name = "RC2 Decrypt"; + this.module = "Ciphers"; + this.description = "RC2 (also known as ARC2) is a symmetric-key block cipher designed by Ron Rivest in 1987. 'RC' stands for 'Rivest Cipher'.

Key: RC2 uses a variable size key.

IV: To run the cipher in CBC mode, the Initialization Vector should be 8 bytes long. If the IV is left blank, the cipher will run in ECB mode.

Padding: In both CBC and ECB mode, PKCS#7 padding will be used."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Key", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "IV", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "Input", + "type": "option", + "value": ["Hex", "Raw"] + }, + { + "name": "Output", + "type": "option", + "value": ["Raw", "Hex"] + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const key = Utils.convertToByteString(args[0].string, args[0].option), + iv = Utils.convertToByteString(args[1].string, args[1].option), + inputType = args[2], + outputType = args[3], + decipher = forge.rc2.createDecryptionCipher(key); + + input = Utils.convertToByteString(input, inputType); + + decipher.start(iv || null); + decipher.update(forge.util.createBuffer(input)); + decipher.finish(); + + return outputType === "Hex" ? decipher.output.toHex() : decipher.output.getBytes(); + } + +} + +export default RC2Decrypt; diff --git a/src/core/operations/RC2Encrypt.mjs b/src/core/operations/RC2Encrypt.mjs new file mode 100644 index 00000000..0c2fcd61 --- /dev/null +++ b/src/core/operations/RC2Encrypt.mjs @@ -0,0 +1,77 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import Utils from "../Utils"; +import forge from "node-forge/dist/forge.min.js"; + + +/** + * RC2 Encrypt operation + */ +class RC2Encrypt extends Operation { + + /** + * RC2Encrypt constructor + */ + constructor() { + super(); + + this.name = "RC2 Encrypt"; + this.module = "Ciphers"; + this.description = "RC2 (also known as ARC2) is a symmetric-key block cipher designed by Ron Rivest in 1987. 'RC' stands for 'Rivest Cipher'.

Key: RC2 uses a variable size key.

You can generate a password-based key using one of the KDF operations.

IV: To run the cipher in CBC mode, the Initialization Vector should be 8 bytes long. If the IV is left blank, the cipher will run in ECB mode.

Padding: In both CBC and ECB mode, PKCS#7 padding will be used."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Key", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "IV", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "Input", + "type": "option", + "value": ["Raw", "Hex"] + }, + { + "name": "Output", + "type": "option", + "value": ["Hex", "Raw"] + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const key = Utils.convertToByteString(args[0].string, args[0].option), + iv = Utils.convertToByteString(args[1].string, args[1].option), + inputType = args[2], + outputType = args[3], + cipher = forge.rc2.createEncryptionCipher(key); + + input = Utils.convertToByteString(input, inputType); + + cipher.start(iv || null); + cipher.update(forge.util.createBuffer(input)); + cipher.finish(); + + return outputType === "Hex" ? cipher.output.toHex() : cipher.output.getBytes(); + } + +} + +export default RC2Encrypt; diff --git a/src/core/operations/legacy/Cipher.js b/src/core/operations/legacy/Cipher.js deleted file mode 100755 index 3a81281d..00000000 --- a/src/core/operations/legacy/Cipher.js +++ /dev/null @@ -1,175 +0,0 @@ -import Utils from "../Utils.js"; -import forge from "imports-loader?jQuery=>null!node-forge/dist/forge.min.js"; -import BigNumber from "bignumber.js"; - - -/** - * Cipher operations. - * - * @author n1474335 [n1474335@gmail.com] - * @copyright Crown Copyright 2016 - * @license Apache-2.0 - * - * @namespace - */ -const Cipher = { - - /** - * @constant - * @default - */ - IO_FORMAT1: ["Hex", "UTF8", "Latin1", "Base64"], - /** - * @constant - * @default - */ - IO_FORMAT2: ["UTF8", "Latin1", "Hex", "Base64"], - /** - * @constant - * @default - */ - IO_FORMAT3: ["Raw", "Hex"], - /** - * @constant - * @default - */ - IO_FORMAT4: ["Hex", "Raw"], - - - /** - * RC2 Encrypt operation. - * - * @param {string} input - * @param {Object[]} args - * @returns {string} - */ - runRc2Enc: function (input, args) { - const key = Utils.convertToByteString(args[0].string, args[0].option), - iv = Utils.convertToByteString(args[1].string, args[1].option), - inputType = args[2], - outputType = args[3], - cipher = forge.rc2.createEncryptionCipher(key); - - input = Utils.convertToByteString(input, inputType); - - cipher.start(iv || null); - cipher.update(forge.util.createBuffer(input)); - cipher.finish(); - - return outputType === "Hex" ? cipher.output.toHex() : cipher.output.getBytes(); - }, - - - /** - * RC2 Decrypt operation. - * - * @param {string} input - * @param {Object[]} args - * @returns {string} - */ - runRc2Dec: function (input, args) { - const key = Utils.convertToByteString(args[0].string, args[0].option), - iv = Utils.convertToByteString(args[1].string, args[1].option), - inputType = args[2], - outputType = args[3], - decipher = forge.rc2.createDecryptionCipher(key); - - input = Utils.convertToByteString(input, inputType); - - decipher.start(iv || null); - decipher.update(forge.util.createBuffer(input)); - decipher.finish(); - - return outputType === "Hex" ? decipher.output.toHex() : decipher.output.getBytes(); - }, - - - /** - * @constant - * @default - */ - KDF_KEY_SIZE: 128, - /** - * @constant - * @default - */ - KDF_ITERATIONS: 1, - /** - * @constant - * @default - */ - HASHERS: ["SHA1", "SHA256", "SHA384", "SHA512", "MD5"], - - /** - * Derive PBKDF2 key operation. - * - * @param {string} input - * @param {Object[]} args - * @returns {string} - */ - runPbkdf2: function (input, args) { - const passphrase = Utils.convertToByteString(args[0].string, args[0].option), - keySize = args[1], - iterations = args[2], - hasher = args[3], - salt = Utils.convertToByteString(args[4].string, args[4].option) || - forge.random.getBytesSync(keySize), - derivedKey = forge.pkcs5.pbkdf2(passphrase, salt, iterations, keySize / 8, hasher.toLowerCase()); - - return forge.util.bytesToHex(derivedKey); - }, - - - /** - * @constant - * @default - */ - PRNG_BYTES: 32, - /** - * @constant - * @default - */ - PRNG_OUTPUT: ["Hex", "Integer", "Byte array", "Raw"], - - /** - * Pseudo-Random Number Generator operation. - * - * @param {string} input - * @param {Object[]} args - * @returns {string} - */ - runPRNG: function(input, args) { - const numBytes = args[0], - outputAs = args[1]; - - let bytes; - - if (ENVIRONMENT_IS_WORKER() && self.crypto) { - bytes = self.crypto.getRandomValues(new Uint8Array(numBytes)); - bytes = Utils.arrayBufferToStr(bytes.buffer); - } else { - bytes = forge.random.getBytesSync(numBytes); - } - - let value = new BigNumber(0), - i; - - switch (outputAs) { - case "Hex": - return forge.util.bytesToHex(bytes); - case "Integer": - for (i = bytes.length - 1; i >= 0; i--) { - value = value.times(256).plus(bytes.charCodeAt(i)); - } - return value.toFixed(); - case "Byte array": - return JSON.stringify(Utils.strToCharcode(bytes)); - case "Raw": - default: - return bytes; - } - }, - -}; - -export default Cipher; diff --git a/test/index.mjs b/test/index.mjs index a20d5fa6..07312fa4 100644 --- a/test/index.mjs +++ b/test/index.mjs @@ -36,7 +36,7 @@ import "./tests/operations/Ciphers"; import "./tests/operations/Checksum"; // import "./tests/operations/Code"; import "./tests/operations/Compress"; -// import "./tests/operations/Crypt"; +import "./tests/operations/Crypt"; import "./tests/operations/DateTime"; import "./tests/operations/Fork"; import "./tests/operations/Jump";