mirror of
https://github.com/gchq/CyberChef.git
synced 2025-05-11 16:51:31 -04:00
Entropy calculations
This commit is contained in:
parent
e5fb5e0b31
commit
f9dbf5ba21
4 changed files with 37 additions and 16 deletions
|
@ -57,6 +57,10 @@ for (const opObj in Ops) {
|
||||||
if ("mimeCheck" in op.checks) {
|
if ("mimeCheck" in op.checks) {
|
||||||
operationConfig[op.name].mimeCheck = op.checks.mimeCheck;
|
operationConfig[op.name].mimeCheck = op.checks.mimeCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("entropyTests" in op.checks) {
|
||||||
|
operationConfig[op.name].entropyTests = op.checks.entropyTests;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(op.module in modules))
|
if (!(op.module in modules))
|
||||||
|
|
|
@ -162,12 +162,13 @@ class Magic {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the Shannon entropy of the input data.
|
* Calculates the Shannon entropy of the data passed to it.
|
||||||
*
|
*
|
||||||
|
* @param {Uint8Array} data
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
calcEntropy() {
|
calcEntropy(data=this.inputBuffer) {
|
||||||
const prob = this._freqDist();
|
const prob = this._freqDist(data);
|
||||||
let entropy = 0,
|
let entropy = 0,
|
||||||
p;
|
p;
|
||||||
|
|
||||||
|
@ -271,8 +272,9 @@ class Magic {
|
||||||
* @param {Object[]} recipeConfig
|
* @param {Object[]} recipeConfig
|
||||||
* @param {string} crib
|
* @param {string} crib
|
||||||
*/
|
*/
|
||||||
async regexesTests(flag, sensible, prevOp, depth, extLang, intensive, recipeConfig, crib) {
|
async regexesTests(flag, sensible, prevOp, depth, extLang, intensive, recipeConfig, crib, inputEntropy) {
|
||||||
let results = [];
|
let results = [];
|
||||||
|
|
||||||
// Execute each of the matching operations, then recursively call the speculativeExecution()
|
// Execute each of the matching operations, then recursively call the speculativeExecution()
|
||||||
// method on the resulting data, recording the properties of each option.
|
// method on the resulting data, recording the properties of each option.
|
||||||
await Promise.all(sensible.map(async op => {
|
await Promise.all(sensible.map(async op => {
|
||||||
|
@ -286,6 +288,7 @@ class Magic {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the recipe is repeating and returning the same data, do not continue
|
// If the recipe is repeating and returning the same data, do not continue
|
||||||
if (prevOp && op.op === prevOp.op && _buffersEqual(output, this.inputBuffer)) {
|
if (prevOp && op.op === prevOp.op && _buffersEqual(output, this.inputBuffer)) {
|
||||||
return;
|
return;
|
||||||
|
@ -301,6 +304,12 @@ class Magic {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const entropyTests = OperationConfig[op.op].entropyTests;
|
||||||
|
let outputEntropy = 0;
|
||||||
|
if (entropyTests) {
|
||||||
|
outputEntropy = this.calcEntropy(new Uint8Array(output));
|
||||||
|
}
|
||||||
|
|
||||||
const outputRegexes = OperationConfig[op.op].outputRegexes;
|
const outputRegexes = OperationConfig[op.op].outputRegexes;
|
||||||
switch (flag) {
|
switch (flag) {
|
||||||
case "Input":
|
case "Input":
|
||||||
|
@ -329,7 +338,7 @@ class Magic {
|
||||||
}
|
}
|
||||||
const magic = new Magic(output, this.opPatterns),
|
const magic = new Magic(output, this.opPatterns),
|
||||||
speculativeResults = await magic.speculativeExecution(
|
speculativeResults = await magic.speculativeExecution(
|
||||||
depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful, crib);
|
depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful, crib, outputEntropy);
|
||||||
|
|
||||||
results = results.concat(speculativeResults);
|
results = results.concat(speculativeResults);
|
||||||
}));
|
}));
|
||||||
|
@ -349,30 +358,30 @@ class Magic {
|
||||||
* @param {string} [crib=null] - The regex crib provided by the user, for filtering the operation output
|
* @param {string} [crib=null] - The regex crib provided by the user, for filtering the operation output
|
||||||
* @returns {Object[]} - A sorted list of the recipes most likely to result in correct decoding
|
* @returns {Object[]} - A sorted list of the recipes most likely to result in correct decoding
|
||||||
*/
|
*/
|
||||||
async speculativeExecution(depth=0, extLang=false, intensive=false, recipeConfig=[], useful=false, crib=null) {
|
async speculativeExecution(depth=0, extLang=false, intensive=false, recipeConfig=[], useful=false, crib=null, inputEntropy=this.calcEntropy()) {
|
||||||
if (depth < 0) return [];
|
if (depth < 0) return [];
|
||||||
|
|
||||||
// Find any operations that can be run on this data
|
// Find any operations that can be run on this data
|
||||||
const matchingOps = this.opPatterns.findMatchingInputRegexes(this.inputStr);
|
const matchingOps = this.opPatterns.findMatchingInputRegexes(this.inputStr);
|
||||||
|
|
||||||
let results = [];
|
let results = [];
|
||||||
|
|
||||||
// Record the properties of the current data
|
// Record the properties of the current data
|
||||||
|
|
||||||
results.push({
|
results.push({
|
||||||
recipe: recipeConfig,
|
recipe: recipeConfig,
|
||||||
data: this.inputStr.slice(0, 100),
|
data: this.inputStr.slice(0, 100),
|
||||||
languageScores: this.detectLanguage(extLang),
|
languageScores: this.detectLanguage(extLang),
|
||||||
fileType: this.detectFileType(),
|
fileType: this.detectFileType(),
|
||||||
isUTF8: this.isUTF8(),
|
isUTF8: this.isUTF8(),
|
||||||
entropy: this.calcEntropy(),
|
entropy: inputEntropy,
|
||||||
matchingOps: matchingOps,
|
matchingOps: matchingOps,
|
||||||
useful: useful,
|
useful: useful,
|
||||||
matchesCrib: crib && crib.test(this.inputStr)
|
matchesCrib: crib && crib.test(this.inputStr)
|
||||||
});
|
});
|
||||||
const prevOp = recipeConfig[recipeConfig.length - 1];
|
const prevOp = recipeConfig[recipeConfig.length - 1];
|
||||||
|
|
||||||
results = results.concat(await this.regexesTests("Input", matchingOps, prevOp, depth, extLang, intensive, recipeConfig, crib));
|
results = results.concat(await this.regexesTests("Input", matchingOps, prevOp, depth, extLang, intensive, recipeConfig, crib, inputEntropy));
|
||||||
results = results.concat(await this.regexesTests("Output", this.opPatterns.getOutputRegexes(), prevOp, depth, extLang, intensive, recipeConfig, crib));
|
results = results.concat(await this.regexesTests("Output", this.opPatterns.getOutputRegexes(), prevOp, depth, extLang, intensive, recipeConfig, crib, inputEntropy));
|
||||||
|
|
||||||
if (intensive) {
|
if (intensive) {
|
||||||
// Run brute forcing of various types on the data and create a new branch for each option
|
// Run brute forcing of various types on the data and create a new branch for each option
|
||||||
|
@ -469,10 +478,10 @@ class Magic {
|
||||||
* @private
|
* @private
|
||||||
* @returns {number[]}
|
* @returns {number[]}
|
||||||
*/
|
*/
|
||||||
_freqDist() {
|
_freqDist(data=this.inputBuffer) {
|
||||||
if (this.freqDist) return this.freqDist;
|
// if (this.freqDist) return this.freqDist;
|
||||||
|
|
||||||
const len = this.inputBuffer.length;
|
const len = data.length;
|
||||||
let i = len;
|
let i = len;
|
||||||
const counts = new Array(256).fill(0);
|
const counts = new Array(256).fill(0);
|
||||||
|
|
||||||
|
@ -482,7 +491,7 @@ class Magic {
|
||||||
}
|
}
|
||||||
|
|
||||||
while (i--) {
|
while (i--) {
|
||||||
counts[this.inputBuffer[i]]++;
|
counts[data[i]]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.freqDist = counts.map(c => {
|
this.freqDist = counts.map(c => {
|
||||||
|
|
|
@ -7,10 +7,11 @@ class magicObject {
|
||||||
* @param outRegexes
|
* @param outRegexes
|
||||||
* @param mimeCheck
|
* @param mimeCheck
|
||||||
*/
|
*/
|
||||||
constructor (inRegexes = null, outRegexes = null, mimeCheck = null) {
|
constructor (inRegexes = null, outRegexes = null, mimeCheck = null, entropyTests=null) {
|
||||||
this.inRegexes = inRegexes;
|
this.inRegexes = inRegexes;
|
||||||
this.outRegexes = outRegexes;
|
this.outRegexes = outRegexes;
|
||||||
this.mimeCheck = mimeCheck;
|
this.mimeCheck = mimeCheck;
|
||||||
|
this.entropyTests = entropyTests;
|
||||||
}
|
}
|
||||||
|
|
||||||
} export default magicObject;
|
} export default magicObject;
|
||||||
|
|
|
@ -35,7 +35,14 @@ class Gunzip extends Operation {
|
||||||
magic: true,
|
magic: true,
|
||||||
args: []
|
args: []
|
||||||
},
|
},
|
||||||
]);
|
],
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
input: [7, 8],
|
||||||
|
output: [3.5, 7],
|
||||||
|
change: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue