2018-05-14 18:30:52 +01:00
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*/
2019-07-09 12:23:59 +01:00
import Operation from "../Operation.mjs" ;
import Utils from "../Utils.mjs" ;
2018-05-14 18:30:52 +01:00
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" ;
2018-08-21 19:07:13 +01:00
this . description = "This operation performs 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 . infoURL = "https://wikipedia.org/wiki/Key_derivation_function" ;
2018-05-14 18:30:52 +01:00
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 );
};