123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- /**
- * Entropy operations.
- *
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2016
- * @license Apache-2.0
- *
- * @namespace
- */
- var Entropy = {
- /**
- * @constant
- * @default
- */
- CHUNK_SIZE: 1000,
- /**
- * Entropy operation.
- *
- * @param {byteArray} input
- * @param {Object[]} args
- * @returns {html}
- */
- runEntropy: function(input, args) {
- var chunkSize = args[0],
- output = "",
- entropy = Entropy._calcEntropy(input);
- output += "Shannon entropy: " + entropy + "\n" +
- "<br><canvas id='chart-area'></canvas><br>\n" +
- "- 0 represents no randomness (i.e. all the bytes in the data have the same value) whereas 8, the maximum, represents a completely random string.\n" +
- "- Standard English text usually falls somewhere between 3.5 and 5.\n" +
- "- Properly encrypted or compressed data of a reasonable length should have an entropy of over 7.5.\n\n" +
- "The following results show the entropy of chunks of the input data. Chunks with particularly high entropy could suggest encrypted or compressed sections.\n\n" +
- "<br><script>\
- var canvas = document.getElementById('chart-area'),\
- parentRect = canvas.parentNode.getBoundingClientRect(),\
- entropy = " + entropy + ",\
- height = parentRect.height * 0.25;\
- \
- canvas.width = parentRect.width * 0.95;\
- canvas.height = height > 150 ? 150 : height;\
- \
- CanvasComponents.drawScaleBar(canvas, entropy, 8, [\
- {\
- label: 'English text',\
- min: 3.5,\
- max: 5\
- },{\
- label: 'Encrypted/compressed',\
- min: 7.5,\
- max: 8\
- }\
- ]);\
- </script>";
- var chunkEntropy = 0;
- if (chunkSize !== 0) {
- for (var i = 0; i < input.length; i += chunkSize) {
- chunkEntropy = Entropy._calcEntropy(input.slice(i, i+chunkSize));
- output += "Bytes " + i + " to " + (i+chunkSize) + ": " + chunkEntropy + "\n";
- }
- } else {
- output += "Chunk size cannot be 0.";
- }
- return output;
- },
- /**
- * @constant
- * @default
- */
- FREQ_ZEROS: false,
- /**
- * Frequency distribution operation.
- *
- * @param {byteArray} input
- * @param {Object[]} args
- * @returns {html}
- */
- runFreqDistrib: function (input, args) {
- if (!input.length) return "No data";
- var distrib = new Array(256),
- percentages = new Array(256),
- len = input.length,
- showZeroes = args[0];
- // Initialise distrib to 0
- for (var i = 0; i < 256; i++) {
- distrib[i] = 0;
- }
- // Count bytes
- for (i = 0; i < len; i++) {
- distrib[input[i]]++;
- }
- // Calculate percentages
- var repr = 0;
- for (i = 0; i < 256; i++) {
- if (distrib[i] > 0) repr++;
- percentages[i] = distrib[i] / len * 100;
- }
- // Print
- var output = "<canvas id='chart-area'></canvas><br>" +
- "Total data length: " + len +
- "\nNumber of bytes represented: " + repr +
- "\nNumber of bytes not represented: " + (256-repr) +
- "\n\nByte Percentage\n" +
- "<script>\
- var canvas = document.getElementById('chart-area'),\
- parentRect = canvas.parentNode.getBoundingClientRect(),\
- scores = " + JSON.stringify(percentages) + ";\
- \
- canvas.width = parentRect.width * 0.95;\
- canvas.height = parentRect.height * 0.9;\
- \
- CanvasComponents.drawBarChart(canvas, scores, 'Byte', 'Frequency %', 16, 6);\
- </script>";
- for (i = 0; i < 256; i++) {
- if (distrib[i] || showZeroes) {
- output += " " + Utils.hex(i, 2) + " (" +
- Utils.padRight(percentages[i].toFixed(2).replace(".00", "") + "%)", 8) +
- Array(Math.ceil(percentages[i])+1).join("|") + "\n";
- }
- }
- return output;
- },
- /**
- * Calculates the Shannon entropy for a given chunk of data.
- *
- * @private
- * @param {byteArray} data
- * @returns {number}
- */
- _calcEntropy: function(data) {
- var prob = [],
- uniques = data.unique(),
- str = Utils.byteArrayToChars(data);
- for (var i = 0; i < uniques.length; i++) {
- prob.push(str.count(Utils.chr(uniques[i])) / data.length);
- }
- var entropy = 0,
- p;
- for (i = 0; i < prob.length; i++) {
- p = prob[i];
- entropy += p * Math.log(p) / Math.log(2);
- }
- return -entropy;
- },
- };
|