mirror of
https://github.com/gchq/CyberChef
synced 2025-01-10 11:38:46 +00:00
145 lines
4.8 KiB
JavaScript
145 lines
4.8 KiB
JavaScript
|
/**
|
||
|
* @author n1474335 [n1474335@gmail.com]
|
||
|
* @copyright Crown Copyright 2016
|
||
|
* @license Apache-2.0
|
||
|
*/
|
||
|
|
||
|
import Operation from "../Operation";
|
||
|
import Utils from "../Utils";
|
||
|
import CryptoJS from "crypto-js";
|
||
|
|
||
|
/**
|
||
|
* Derive EVP key operation
|
||
|
*/
|
||
|
class DeriveEVPKey extends Operation {
|
||
|
|
||
|
/**
|
||
|
* DeriveEVPKey constructor
|
||
|
*/
|
||
|
constructor() {
|
||
|
super();
|
||
|
|
||
|
this.name = "Derive EVP key";
|
||
|
this.module = "Ciphers";
|
||
|
this.description = "EVP is a password-based key derivation function (PBKDF) used extensively in OpenSSL. 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.<br><br>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.<br><br>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] / 32,
|
||
|
iterations = args[2],
|
||
|
hasher = args[3],
|
||
|
salt = Utils.convertToByteString(args[4].string, args[4].option),
|
||
|
key = CryptoJS.EvpKDF(passphrase, salt, {
|
||
|
keySize: keySize,
|
||
|
hasher: CryptoJS.algo[hasher],
|
||
|
iterations: iterations,
|
||
|
});
|
||
|
|
||
|
return key.toString(CryptoJS.enc.Hex);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
export default DeriveEVPKey;
|
||
|
|
||
|
/**
|
||
|
* Overwriting the CryptoJS OpenSSL key derivation function so that it is possible to not pass a
|
||
|
* salt in.
|
||
|
|
||
|
* @param {string} password - The password to derive from.
|
||
|
* @param {number} keySize - The size in words of the key to generate.
|
||
|
* @param {number} ivSize - The size in words of the IV to generate.
|
||
|
* @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be
|
||
|
* generated randomly. If set to false, no salt will be added.
|
||
|
*
|
||
|
* @returns {CipherParams} A cipher params object with the key, IV, and salt.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
* // Randomly generates a salt
|
||
|
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);
|
||
|
* // Uses the salt 'saltsalt'
|
||
|
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');
|
||
|
* // Does not use a salt
|
||
|
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, false);
|
||
|
*/
|
||
|
CryptoJS.kdf.OpenSSL.execute = function (password, keySize, ivSize, salt) {
|
||
|
// Generate random salt if no salt specified and not set to false
|
||
|
// This line changed from `if (!salt) {` to the following
|
||
|
if (salt === undefined || salt === null) {
|
||
|
salt = CryptoJS.lib.WordArray.random(64/8);
|
||
|
}
|
||
|
|
||
|
// Derive key and IV
|
||
|
const key = CryptoJS.algo.EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt);
|
||
|
|
||
|
// Separate key and IV
|
||
|
const iv = CryptoJS.lib.WordArray.create(key.words.slice(keySize), ivSize * 4);
|
||
|
key.sigBytes = keySize * 4;
|
||
|
|
||
|
// Return params
|
||
|
return CryptoJS.lib.CipherParams.create({ key: key, iv: iv, salt: salt });
|
||
|
};
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Override for the CryptoJS Hex encoding parser to remove whitespace before attempting to parse
|
||
|
* the hex string.
|
||
|
*
|
||
|
* @param {string} hexStr
|
||
|
* @returns {CryptoJS.lib.WordArray}
|
||
|
*/
|
||
|
CryptoJS.enc.Hex.parse = function (hexStr) {
|
||
|
// Remove whitespace
|
||
|
hexStr = hexStr.replace(/\s/g, "");
|
||
|
|
||
|
// Shortcut
|
||
|
const hexStrLength = hexStr.length;
|
||
|
|
||
|
// Convert
|
||
|
const words = [];
|
||
|
for (let i = 0; i < hexStrLength; i += 2) {
|
||
|
words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
|
||
|
}
|
||
|
|
||
|
return new CryptoJS.lib.WordArray.init(words, hexStrLength / 2);
|
||
|
};
|