mirror of
https://github.com/gchq/CyberChef.git
synced 2024-11-16 08:58:30 +01:00
138 lines
4.2 KiB
JavaScript
138 lines
4.2 KiB
JavaScript
/**
|
|
* @author mikecat
|
|
* @copyright Crown Copyright 2023
|
|
* @license Apache-2.0
|
|
*/
|
|
|
|
import Operation from "../Operation.mjs";
|
|
import Utils from "../Utils.mjs";
|
|
import OperationError from "../errors/OperationError.mjs";
|
|
import CryptoApi from "crypto-api/src/crypto-api.mjs";
|
|
|
|
/**
|
|
* Derive HKDF Key operation
|
|
*/
|
|
class DeriveHKDFKey extends Operation {
|
|
|
|
/**
|
|
* DeriveHKDFKey constructor
|
|
*/
|
|
constructor() {
|
|
super();
|
|
|
|
this.name = "Derive HKDF key";
|
|
this.module = "Crypto";
|
|
this.description = "A simple Hashed Message Authenticaton Code (HMAC)-based key derivation function (HKDF), defined in RFC5869.";
|
|
this.infoURL = "https://wikipedia.org/wiki/HKDF";
|
|
this.inputType = "ArrayBuffer";
|
|
this.outputType = "string";
|
|
this.args = [
|
|
{
|
|
"name": "Salt",
|
|
"type": "toggleString",
|
|
"value": "",
|
|
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
|
|
},
|
|
{
|
|
"name": "Info",
|
|
"type": "toggleString",
|
|
"value": "",
|
|
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
|
|
},
|
|
{
|
|
"name": "Hashing function",
|
|
"type": "option",
|
|
"value": [
|
|
"MD2",
|
|
"MD4",
|
|
"MD5",
|
|
"SHA0",
|
|
"SHA1",
|
|
"SHA224",
|
|
"SHA256",
|
|
"SHA384",
|
|
"SHA512",
|
|
"SHA512/224",
|
|
"SHA512/256",
|
|
"RIPEMD128",
|
|
"RIPEMD160",
|
|
"RIPEMD256",
|
|
"RIPEMD320",
|
|
"HAS160",
|
|
"Whirlpool",
|
|
"Whirlpool-0",
|
|
"Whirlpool-T",
|
|
"Snefru"
|
|
],
|
|
"defaultIndex": 6
|
|
},
|
|
{
|
|
"name": "Extract mode",
|
|
"type": "argSelector",
|
|
"value": [
|
|
{
|
|
"name": "with salt",
|
|
"on": [0]
|
|
},
|
|
{
|
|
"name": "no salt",
|
|
"off": [0]
|
|
},
|
|
{
|
|
"name": "skip",
|
|
"off": [0]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "L (number of output octets)",
|
|
"type": "number",
|
|
"value": 16,
|
|
"min": 0
|
|
},
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param {ArrayBuffer} input
|
|
* @param {Object[]} args
|
|
* @returns {ArrayBuffer}
|
|
*/
|
|
run(input, args) {
|
|
const argSalt = Utils.convertToByteString(args[0].string || "", args[0].option),
|
|
info = Utils.convertToByteString(args[1].string || "", args[1].option),
|
|
hashFunc = args[2].toLowerCase(),
|
|
extractMode = args[3],
|
|
L = args[4],
|
|
IKM = Utils.arrayBufferToStr(input, false),
|
|
hasher = CryptoApi.getHasher(hashFunc),
|
|
HashLen = hasher.finalize().length;
|
|
|
|
if (L < 0) {
|
|
throw new OperationError("L must be non-negative");
|
|
}
|
|
if (L > 255 * HashLen) {
|
|
throw new OperationError("L too large (maximum length for " + args[2] + " is " + (255 * HashLen) + ")");
|
|
}
|
|
|
|
const hmacHash = function(key, data) {
|
|
hasher.reset();
|
|
const mac = CryptoApi.getHmac(key, hasher);
|
|
mac.update(data);
|
|
return mac.finalize();
|
|
};
|
|
const salt = extractMode === "with salt" ? argSalt : "\0".repeat(HashLen);
|
|
const PRK = extractMode === "skip" ? IKM : hmacHash(salt, IKM);
|
|
let T = "";
|
|
let result = "";
|
|
for (let i = 1; i <= 255 && result.length < L; i++) {
|
|
const TNext = hmacHash(PRK, T + info + String.fromCharCode(i));
|
|
result += TNext;
|
|
T = TNext;
|
|
}
|
|
return CryptoApi.encoder.toHex(result.substring(0, L));
|
|
}
|
|
|
|
}
|
|
|
|
export default DeriveHKDFKey;
|