cyberchef 11.1.0 → 11.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +75 -0
- package/CHANGELOG.md +173 -2
- package/Dockerfile +2 -2
- package/Gruntfile.js +1 -0
- package/README.md +7 -6
- package/SECURITY.md +3 -1
- package/package.json +22 -21
- package/src/core/Chef.mjs +2 -0
- package/src/core/Dish.mjs +1 -5
- package/src/core/Ingredient.mjs +92 -0
- package/src/core/Operation.mjs +19 -0
- package/src/core/Recipe.mjs +4 -0
- package/src/core/Utils.mjs +48 -0
- package/src/core/config/Categories.json +22 -6
- package/src/core/config/OperationConfig.json +4774 -1228
- package/src/core/config/modules/Ciphers.mjs +20 -0
- package/src/core/config/modules/Crypto.mjs +10 -0
- package/src/core/config/modules/Default.mjs +8 -0
- package/src/core/config/modules/File.mjs +16 -0
- package/src/core/config/modules/OpModules.mjs +2 -0
- package/src/core/config/scripts/generateHTMLEntities.mjs +139 -0
- package/src/core/config/scripts/htmlEntityOverrides.mjs +86 -0
- package/src/core/dishTypes/DishType.mjs +1 -1
- package/src/core/errors/ExcludedOperationError.mjs +1 -1
- package/src/core/lib/Arithmetic.mjs +21 -5
- package/src/core/lib/BigIntUtils.mjs +0 -1
- package/src/core/lib/COBS.mjs +86 -0
- package/src/core/lib/Charts.mjs +3 -3
- package/src/core/lib/Decimal.mjs +5 -5
- package/src/core/lib/HTMLEntities.mjs +2068 -0
- package/src/core/lib/Present.mjs +422 -0
- package/src/core/lib/Protocol.mjs +8 -6
- package/src/core/lib/TEA.mjs +494 -0
- package/src/core/lib/TLVParser.mjs +16 -7
- package/src/core/lib/Twofish.mjs +608 -0
- package/src/core/operations/AsconDecrypt.mjs +112 -0
- package/src/core/operations/AsconEncrypt.mjs +108 -0
- package/src/core/operations/AsconHash.mjs +49 -0
- package/src/core/operations/AsconMAC.mjs +68 -0
- package/src/core/operations/AutomatedValidationTestOp.mjs +84 -0
- package/src/core/operations/AvroToJSON.mjs +1 -1
- package/src/core/operations/BLAKE3.mjs +5 -1
- package/src/core/operations/BcryptCompare.mjs +11 -5
- package/src/core/operations/BitShiftLeft.mjs +4 -1
- package/src/core/operations/Bzip2Compress.mjs +1 -1
- package/src/core/operations/DechunkHTTPResponse.mjs +4 -1
- package/src/core/operations/ExtendedGCD.mjs +101 -0
- package/src/core/operations/FromBase.mjs +2 -1
- package/src/core/operations/FromCOBS.mjs +38 -0
- package/src/core/operations/FromDecimal.mjs +6 -1
- package/src/core/operations/FromHTMLEntity.mjs +2 -1458
- package/src/core/operations/GenerateDeBruijnSequence.mjs +8 -0
- package/src/core/operations/GenerateHOTP.mjs +21 -6
- package/src/core/operations/GenerateImage.mjs +22 -10
- package/src/core/operations/GeneratePrime.mjs +154 -0
- package/src/core/operations/GenerateTOTP.mjs +24 -7
- package/src/core/operations/Gzip.mjs +1 -3
- package/src/core/operations/Jsonata.mjs +12 -0
- package/src/core/operations/MIMEDecoding.mjs +1 -1
- package/src/core/operations/MOD.mjs +62 -0
- package/src/core/operations/ModularInverse.mjs +107 -0
- package/src/core/operations/PRESENTDecrypt.mjs +94 -0
- package/src/core/operations/PRESENTEncrypt.mjs +94 -0
- package/src/core/operations/ParityBit.mjs +1 -1
- package/src/core/operations/ParseIPv4Header.mjs +1 -1
- package/src/core/operations/ParseURI.mjs +18 -5
- package/src/core/operations/PseudoRandomNumberGenerator.mjs +2 -1
- package/src/core/operations/RandomPrime.mjs +154 -0
- package/src/core/operations/RenderPDF.mjs +100 -0
- package/src/core/operations/SHA2.mjs +1 -1
- package/src/core/operations/SM4Encrypt.mjs +1 -1
- package/src/core/operations/SetDifference.mjs +8 -1
- package/src/core/operations/SetIntersection.mjs +8 -1
- package/src/core/operations/ShowOnMap.mjs +14 -2
- package/src/core/operations/TEADecrypt.mjs +98 -0
- package/src/core/operations/TEAEncrypt.mjs +98 -0
- package/src/core/operations/ToBase.mjs +4 -4
- package/src/core/operations/ToBase32.mjs +20 -4
- package/src/core/operations/ToBinary.mjs +4 -1
- package/src/core/operations/ToCOBS.mjs +38 -0
- package/src/core/operations/ToHTMLEntity.mjs +7 -1430
- package/src/core/operations/ToHexdump.mjs +7 -1
- package/src/core/operations/TwofishDecrypt.mjs +94 -0
- package/src/core/operations/TwofishEncrypt.mjs +94 -0
- package/src/core/operations/URLEncode.mjs +22 -18
- package/src/core/operations/UnescapeUnicodeCharacters.mjs +2 -1
- package/src/core/operations/ViewBitPlane.mjs +9 -3
- package/src/core/operations/Wrap.mjs +5 -0
- package/src/core/operations/XORBruteForce.mjs +4 -1
- package/src/core/operations/XORChecksum.mjs +10 -3
- package/src/core/operations/XTEADecrypt.mjs +110 -0
- package/src/core/operations/XTEAEncrypt.mjs +110 -0
- package/src/core/operations/index.mjs +42 -0
- package/src/core/vendor/ascon.mjs +162 -0
- package/src/core/vendor/htmlEntities/entity.json +2233 -0
- package/src/core/vendor/htmlEntities/entity.txt +14 -0
- package/src/node/api.mjs +4 -1
- package/src/node/index.mjs +105 -0
- package/src/web/HTMLOperation.mjs +2 -1
- package/src/web/stylesheets/layout/_io.css +8 -0
- package/tests/browser/00_nightwatch.js +26 -0
- package/tests/browser/02_ops.js +20 -4
- package/tests/node/index.mjs +2 -0
- package/tests/node/tests/Dish.mjs +19 -0
- package/tests/node/tests/NodeDish.mjs +36 -0
- package/tests/node/tests/ToHTMLEntity.mjs +82 -0
- package/tests/node/tests/Utils.mjs +77 -0
- package/tests/node/tests/lib/ChartsProtocolPrototypePollution.mjs +90 -0
- package/tests/node/tests/nodeApi.mjs +33 -1
- package/tests/node/tests/operations.mjs +26 -1
- package/tests/operations/index.mjs +17 -0
- package/tests/operations/tests/Arithmetic.mjs +33 -0
- package/tests/operations/tests/Ascon.mjs +501 -0
- package/tests/operations/tests/AutomatedValidation.mjs +154 -0
- package/tests/operations/tests/BLAKE3.mjs +39 -1
- package/tests/operations/tests/Base32.mjs +22 -0
- package/tests/operations/tests/COBS.mjs +476 -0
- package/tests/operations/tests/CharEnc.mjs +2 -2
- package/tests/operations/tests/DechunkHTTPResponse.mjs +66 -0
- package/tests/operations/tests/ExtendedGCD.mjs +78 -0
- package/tests/operations/tests/FromBase.mjs +66 -0
- package/tests/operations/tests/FromDecimal.mjs +55 -0
- package/tests/operations/tests/GenerateLoremIpsum.mjs +2 -2
- package/tests/operations/tests/Gzip.mjs +60 -0
- package/tests/operations/tests/HTMLEntity.mjs +126 -0
- package/tests/operations/tests/Hash.mjs +44 -0
- package/tests/operations/tests/Hexdump.mjs +11 -0
- package/tests/operations/tests/Image.mjs +26 -0
- package/tests/operations/tests/Jsonata.mjs +23 -0
- package/tests/operations/tests/MIMEDecoding.mjs +33 -0
- package/tests/operations/tests/MOD.mjs +208 -0
- package/tests/operations/tests/Median.mjs +33 -0
- package/tests/operations/tests/ModularInverse.mjs +78 -0
- package/tests/operations/tests/OTP.mjs +167 -2
- package/tests/operations/tests/PRESENT.mjs +465 -0
- package/tests/operations/tests/ParseIPv4Header.mjs +11 -0
- package/tests/operations/tests/ParseTLV.mjs +41 -0
- package/tests/operations/tests/RenderPDF.mjs +55 -0
- package/tests/operations/tests/SM2.mjs +1 -1
- package/tests/operations/tests/SetDifference.mjs +22 -0
- package/tests/operations/tests/SetIntersection.mjs +23 -1
- package/tests/operations/tests/ShowOnMap.mjs +61 -0
- package/tests/operations/tests/TEA.mjs +566 -0
- package/tests/operations/tests/Twofish.mjs +486 -0
- package/tests/operations/tests/URLEncodeDecode.mjs +26 -0
- package/tests/operations/tests/UnescapeUnicodeCharacters.mjs +88 -0
- package/tests/operations/tests/Wrap.mjs +44 -0
- package/webpack.config.js +3 -3
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Medjedtxm
|
|
3
|
+
* @copyright Crown Copyright 2026
|
|
4
|
+
* @license Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import Operation from "../Operation.mjs";
|
|
8
|
+
import Utils from "../Utils.mjs";
|
|
9
|
+
import OperationError from "../errors/OperationError.mjs";
|
|
10
|
+
import { toHex } from "../lib/Hex.mjs";
|
|
11
|
+
import { decryptPRESENT } from "../lib/Present.mjs";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* PRESENT Decrypt operation
|
|
15
|
+
*/
|
|
16
|
+
class PRESENTDecrypt extends Operation {
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* PRESENTDecrypt constructor
|
|
20
|
+
*/
|
|
21
|
+
constructor() {
|
|
22
|
+
super();
|
|
23
|
+
|
|
24
|
+
this.name = "PRESENT Decrypt";
|
|
25
|
+
this.module = "Ciphers";
|
|
26
|
+
this.description = "PRESENT is an ultra-lightweight block cipher designed for constrained environments such as RFID tags and sensor networks. It operates on 64-bit blocks and supports 80-bit or 128-bit keys with 31 rounds. Standardised in ISO/IEC 29192-2:2019.<br><br>When using CBC mode, the PKCS#7 padding scheme is used.";
|
|
27
|
+
this.infoURL = "https://wikipedia.org/wiki/PRESENT_(cipher)";
|
|
28
|
+
this.inputType = "string";
|
|
29
|
+
this.outputType = "string";
|
|
30
|
+
this.args = [
|
|
31
|
+
{
|
|
32
|
+
"name": "Key",
|
|
33
|
+
"type": "toggleString",
|
|
34
|
+
"value": "",
|
|
35
|
+
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "IV",
|
|
39
|
+
"type": "toggleString",
|
|
40
|
+
"value": "",
|
|
41
|
+
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "Mode",
|
|
45
|
+
"type": "option",
|
|
46
|
+
"value": ["CBC", "ECB"]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "Input",
|
|
50
|
+
"type": "option",
|
|
51
|
+
"value": ["Hex", "Raw"]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "Output",
|
|
55
|
+
"type": "option",
|
|
56
|
+
"value": ["Raw", "Hex"]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "Padding",
|
|
60
|
+
"type": "option",
|
|
61
|
+
"value": ["PKCS5", "NO", "ZERO", "RANDOM", "BIT"]
|
|
62
|
+
}
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {string} input
|
|
68
|
+
* @param {Object[]} args
|
|
69
|
+
* @returns {string}
|
|
70
|
+
*/
|
|
71
|
+
run(input, args) {
|
|
72
|
+
const key = Utils.convertToByteArray(args[0].string, args[0].option),
|
|
73
|
+
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
|
74
|
+
[,, mode, inputType, outputType, padding] = args;
|
|
75
|
+
|
|
76
|
+
if (key.length !== 10 && key.length !== 16)
|
|
77
|
+
throw new OperationError(`Invalid key length: ${key.length} bytes
|
|
78
|
+
|
|
79
|
+
PRESENT uses a key length of 10 bytes (80 bits) or 16 bytes (128 bits).`);
|
|
80
|
+
|
|
81
|
+
if (iv.length !== 8 && mode !== "ECB")
|
|
82
|
+
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
|
83
|
+
|
|
84
|
+
PRESENT uses an IV length of 8 bytes (64 bits).
|
|
85
|
+
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
|
|
86
|
+
|
|
87
|
+
input = Utils.convertToByteArray(input, inputType);
|
|
88
|
+
const output = decryptPRESENT(input, key, iv, mode, padding);
|
|
89
|
+
return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export default PRESENTDecrypt;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Medjedtxm
|
|
3
|
+
* @copyright Crown Copyright 2026
|
|
4
|
+
* @license Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import Operation from "../Operation.mjs";
|
|
8
|
+
import Utils from "../Utils.mjs";
|
|
9
|
+
import OperationError from "../errors/OperationError.mjs";
|
|
10
|
+
import { toHex } from "../lib/Hex.mjs";
|
|
11
|
+
import { encryptPRESENT } from "../lib/Present.mjs";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* PRESENT Encrypt operation
|
|
15
|
+
*/
|
|
16
|
+
class PRESENTEncrypt extends Operation {
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* PRESENTEncrypt constructor
|
|
20
|
+
*/
|
|
21
|
+
constructor() {
|
|
22
|
+
super();
|
|
23
|
+
|
|
24
|
+
this.name = "PRESENT Encrypt";
|
|
25
|
+
this.module = "Ciphers";
|
|
26
|
+
this.description = "PRESENT is an ultra-lightweight block cipher designed for constrained environments such as RFID tags and sensor networks. It operates on 64-bit blocks and supports 80-bit or 128-bit keys with 31 rounds. Standardised in ISO/IEC 29192-2:2019.<br><br>When using CBC mode, the PKCS#7 padding scheme is used.";
|
|
27
|
+
this.infoURL = "https://wikipedia.org/wiki/PRESENT_(cipher)";
|
|
28
|
+
this.inputType = "string";
|
|
29
|
+
this.outputType = "string";
|
|
30
|
+
this.args = [
|
|
31
|
+
{
|
|
32
|
+
"name": "Key",
|
|
33
|
+
"type": "toggleString",
|
|
34
|
+
"value": "",
|
|
35
|
+
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "IV",
|
|
39
|
+
"type": "toggleString",
|
|
40
|
+
"value": "",
|
|
41
|
+
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "Mode",
|
|
45
|
+
"type": "option",
|
|
46
|
+
"value": ["CBC", "ECB"]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "Input",
|
|
50
|
+
"type": "option",
|
|
51
|
+
"value": ["Raw", "Hex"]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "Output",
|
|
55
|
+
"type": "option",
|
|
56
|
+
"value": ["Hex", "Raw"]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "Padding",
|
|
60
|
+
"type": "option",
|
|
61
|
+
"value": ["PKCS5", "NO", "ZERO", "RANDOM", "BIT"]
|
|
62
|
+
}
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {string} input
|
|
68
|
+
* @param {Object[]} args
|
|
69
|
+
* @returns {string}
|
|
70
|
+
*/
|
|
71
|
+
run(input, args) {
|
|
72
|
+
const key = Utils.convertToByteArray(args[0].string, args[0].option),
|
|
73
|
+
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
|
74
|
+
[,, mode, inputType, outputType, padding] = args;
|
|
75
|
+
|
|
76
|
+
if (key.length !== 10 && key.length !== 16)
|
|
77
|
+
throw new OperationError(`Invalid key length: ${key.length} bytes
|
|
78
|
+
|
|
79
|
+
PRESENT uses a key length of 10 bytes (80 bits) or 16 bytes (128 bits).`);
|
|
80
|
+
|
|
81
|
+
if (iv.length !== 8 && mode !== "ECB")
|
|
82
|
+
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
|
83
|
+
|
|
84
|
+
PRESENT uses an IV length of 8 bytes (64 bits).
|
|
85
|
+
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
|
|
86
|
+
|
|
87
|
+
input = Utils.convertToByteArray(input, inputType);
|
|
88
|
+
const output = encryptPRESENT(input, key, iv, mode, padding);
|
|
89
|
+
return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export default PRESENTEncrypt;
|
|
@@ -20,7 +20,7 @@ class ParityBit extends Operation {
|
|
|
20
20
|
|
|
21
21
|
this.name = "Parity Bit";
|
|
22
22
|
this.module = "Default";
|
|
23
|
-
this.description = "A parity bit, or check bit, is the simplest form of error detection. It is a bit which is added to a string of bits and represents if the number of 1's in the binary string is an even number or odd number.<br><br>If a delimiter is specified, the parity bit calculation will be performed on each 'block' of the input data, where the blocks are created by slicing the input at each
|
|
23
|
+
this.description = "A parity bit, or check bit, is the simplest form of error detection. It is a bit which is added to a string of bits and represents if the number of 1's in the binary string is an even number or odd number.<br><br>If a delimiter is specified, the parity bit calculation will be performed on each 'block' of the input data, where the blocks are created by slicing the input at each occurrence of the delimiter character";
|
|
24
24
|
this.infoURL = "https://wikipedia.org/wiki/Parity_bit";
|
|
25
25
|
this.inputType = "string";
|
|
26
26
|
this.outputType = "string";
|
|
@@ -74,7 +74,7 @@ class ParseIPv4Header extends Operation {
|
|
|
74
74
|
checksum = input[10] << 8 | input[11],
|
|
75
75
|
srcIP = input[12] << 24 | input[13] << 16 | input[14] << 8 | input[15],
|
|
76
76
|
dstIP = input[16] << 24 | input[17] << 16 | input[18] << 8 | input[19],
|
|
77
|
-
checksumHeader = input.slice(0, 10)
|
|
77
|
+
checksumHeader = [...input.slice(0, 10), 0, 0, ...input.slice(12, 20)];
|
|
78
78
|
let version = (input[0] >>> 4) & 0x0f,
|
|
79
79
|
options = [];
|
|
80
80
|
|
|
@@ -33,7 +33,7 @@ class ParseURI extends Operation {
|
|
|
33
33
|
* @returns {string}
|
|
34
34
|
*/
|
|
35
35
|
run(input, args) {
|
|
36
|
-
const uri = url.parse(input,
|
|
36
|
+
const uri = url.parse(input, false);
|
|
37
37
|
|
|
38
38
|
let output = "";
|
|
39
39
|
|
|
@@ -43,7 +43,20 @@ class ParseURI extends Operation {
|
|
|
43
43
|
if (uri.port) output += "Port:\t\t" + uri.port + "\n";
|
|
44
44
|
if (uri.pathname) output += "Path name:\t" + uri.pathname + "\n";
|
|
45
45
|
if (uri.query) {
|
|
46
|
-
const
|
|
46
|
+
const queryObj = Object.create(null);
|
|
47
|
+
for (const [key, value] of new URLSearchParams(uri.query)) {
|
|
48
|
+
if (Object.prototype.hasOwnProperty.call(queryObj, key)) {
|
|
49
|
+
if (Array.isArray(queryObj[key])) {
|
|
50
|
+
queryObj[key].push(value);
|
|
51
|
+
} else {
|
|
52
|
+
queryObj[key] = [queryObj[key], value];
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
queryObj[key] = value;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const keys = Object.keys(queryObj);
|
|
47
60
|
let padding = 0;
|
|
48
61
|
|
|
49
62
|
keys.forEach(k => {
|
|
@@ -51,10 +64,10 @@ class ParseURI extends Operation {
|
|
|
51
64
|
});
|
|
52
65
|
|
|
53
66
|
output += "Arguments:\n";
|
|
54
|
-
for (const key in
|
|
67
|
+
for (const key in queryObj) {
|
|
55
68
|
output += "\t" + key.padEnd(padding, " ");
|
|
56
|
-
if (
|
|
57
|
-
output += " = " +
|
|
69
|
+
if (queryObj[key].length) {
|
|
70
|
+
output += " = " + queryObj[key] + "\n";
|
|
58
71
|
} else {
|
|
59
72
|
output += "\n";
|
|
60
73
|
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author p-leriche [philip.leriche@cantab.net]
|
|
3
|
+
* @copyright Crown Copyright 2025
|
|
4
|
+
* @license Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import Operation from "../Operation.mjs";
|
|
8
|
+
import OperationError from "../errors/OperationError.mjs";
|
|
9
|
+
import { modPow } from "../lib/BigIntUtils.mjs";
|
|
10
|
+
|
|
11
|
+
/* ---------- helper functions ---------- */
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Generate random BigInt with specified bit length
|
|
15
|
+
*/
|
|
16
|
+
function randBigInt(bits) {
|
|
17
|
+
const bytes = Math.ceil(bits / 8);
|
|
18
|
+
const a = new Uint8Array(bytes);
|
|
19
|
+
crypto.getRandomValues(a);
|
|
20
|
+
|
|
21
|
+
// Set high bit to ensure correct bit length
|
|
22
|
+
a[0] |= 1 << (7 - ((8 * bytes - bits)));
|
|
23
|
+
// Set low bit to ensure odd (primes > 2 are odd)
|
|
24
|
+
a[bytes - 1] |= 1;
|
|
25
|
+
|
|
26
|
+
let h = "";
|
|
27
|
+
for (const b of a) h += b.toString(16).padStart(2, "0");
|
|
28
|
+
return BigInt("0x" + h);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Miller-Rabin primality test
|
|
33
|
+
*/
|
|
34
|
+
function isProbablePrime(n, rounds) {
|
|
35
|
+
if (n < 2n) return false;
|
|
36
|
+
if (n === 2n || n === 3n) return true;
|
|
37
|
+
if (n % 2n === 0n) return false;
|
|
38
|
+
|
|
39
|
+
// Write n-1 as 2^r * d
|
|
40
|
+
let d = n - 1n;
|
|
41
|
+
let r = 0n;
|
|
42
|
+
while (d % 2n === 0n) {
|
|
43
|
+
d /= 2n;
|
|
44
|
+
r++;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Witness loop
|
|
48
|
+
for (let i = 0; i < rounds; i++) {
|
|
49
|
+
const a = randBigInt(n.toString(2).length - 1) % (n - 3n) + 2n;
|
|
50
|
+
let x = modPow(a, d, n);
|
|
51
|
+
|
|
52
|
+
if (x === 1n || x === n - 1n) continue;
|
|
53
|
+
|
|
54
|
+
let composite = true;
|
|
55
|
+
for (let j = 0n; j < r - 1n; j++) {
|
|
56
|
+
x = modPow(x, 2n, n);
|
|
57
|
+
if (x === n - 1n) {
|
|
58
|
+
composite = false;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (composite) return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* ---------- operation class ---------- */
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Generate Prime Number operation
|
|
73
|
+
*/
|
|
74
|
+
class GeneratePrime extends Operation {
|
|
75
|
+
/**
|
|
76
|
+
* GeneratePrime constructor
|
|
77
|
+
*/
|
|
78
|
+
constructor() {
|
|
79
|
+
super();
|
|
80
|
+
|
|
81
|
+
this.name = "Pseudo-Random Prime Generator";
|
|
82
|
+
this.module = "Crypto";
|
|
83
|
+
this.description =
|
|
84
|
+
"Generates a random probable prime number of specified bit length using the Miller-Rabin primality test.<br><br>" +
|
|
85
|
+
"<b>Primality guarantee:</b><br>" +
|
|
86
|
+
"For numbers . 3,317, the result is guaranteed prime (deterministic test).<br>" +
|
|
87
|
+
"For larger numbers, uses probabilistic testing:<br>" +
|
|
88
|
+
"- <b>Standard (7 rounds):</b> Probability of composite approx 1 in 16,000)<br><br>" +
|
|
89
|
+
"- <b>Crypto grade (40 rounds):</b> Probability of composite(approx 1 in 10^24)<br>" +
|
|
90
|
+
"Crypto grade is recommended for cryptographic applications (RSA, Diffie-Hellman, etc.).<br><br>" ;
|
|
91
|
+
this.infoURL = "https://wikipedia.org/wiki/Miller-Rabin_primality_test";
|
|
92
|
+
this.inputType = "string";
|
|
93
|
+
this.outputType = "string";
|
|
94
|
+
this.args = [
|
|
95
|
+
{
|
|
96
|
+
name: "Bit length",
|
|
97
|
+
type: "number",
|
|
98
|
+
value: 512,
|
|
99
|
+
min: 2
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "Crypto grade",
|
|
103
|
+
type: "boolean",
|
|
104
|
+
value: false
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "Output format",
|
|
108
|
+
type: "option",
|
|
109
|
+
value: ["Decimal", "Hexadecimal"]
|
|
110
|
+
}
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @param {string} input
|
|
116
|
+
* @param {Object[]} args
|
|
117
|
+
* @returns {string}
|
|
118
|
+
*/
|
|
119
|
+
run(input, args) {
|
|
120
|
+
const [bits, cryptoGrade, outputFormat] = args;
|
|
121
|
+
|
|
122
|
+
if (bits < 2) {
|
|
123
|
+
throw new OperationError("Bit length must be at least 2");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (bits > 4096) {
|
|
127
|
+
throw new OperationError("Bit length limited to 4096 bits for performance reasons");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const rounds = cryptoGrade ? 40 : 7;
|
|
131
|
+
let attempts = 0;
|
|
132
|
+
const maxAttempts = 10000;
|
|
133
|
+
|
|
134
|
+
let n = randBigInt(bits);
|
|
135
|
+
|
|
136
|
+
while (!isProbablePrime(n, rounds)) {
|
|
137
|
+
n = randBigInt(bits);
|
|
138
|
+
attempts++;
|
|
139
|
+
|
|
140
|
+
if (attempts > maxAttempts) {
|
|
141
|
+
throw new OperationError(`Failed to generate prime after ${maxAttempts} attempts. Try a different bit length.`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Return only the prime for pipeability
|
|
146
|
+
if (outputFormat === "Hexadecimal") {
|
|
147
|
+
return "0x" + n.toString(16);
|
|
148
|
+
} else {
|
|
149
|
+
return n.toString();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export default GeneratePrime;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Shailendra [singhshailendra.in]
|
|
3
|
+
* @copyright Crown Copyright 2017
|
|
4
|
+
* @license Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { fromBase64, toBase64 } from "../lib/Base64.mjs";
|
|
8
|
+
import Operation from "../Operation.mjs";
|
|
9
|
+
import OperationError from "../errors/OperationError.mjs";
|
|
10
|
+
import Utils from "../Utils.mjs";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Render PDF operation
|
|
14
|
+
*/
|
|
15
|
+
class RenderPDF extends Operation {
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* RenderPDF constructor
|
|
19
|
+
*/
|
|
20
|
+
constructor() {
|
|
21
|
+
super();
|
|
22
|
+
|
|
23
|
+
this.name = "Render PDF";
|
|
24
|
+
this.module = "File";
|
|
25
|
+
this.description = "Displays the input as a PDF preview. Supports Raw and Base64 input formats.";
|
|
26
|
+
this.inputType = "string";
|
|
27
|
+
this.outputType = "byteArray";
|
|
28
|
+
this.presentType = "html";
|
|
29
|
+
this.args = [
|
|
30
|
+
{
|
|
31
|
+
"name": "Input format",
|
|
32
|
+
"type": "option",
|
|
33
|
+
"value": ["Base64", "Raw"],
|
|
34
|
+
}
|
|
35
|
+
];
|
|
36
|
+
this.checks = [
|
|
37
|
+
{
|
|
38
|
+
pattern: "^%PDF-",
|
|
39
|
+
flags: "",
|
|
40
|
+
args: ["Raw"],
|
|
41
|
+
useful: true,
|
|
42
|
+
output: {
|
|
43
|
+
mime: "application/pdf"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {string} input
|
|
51
|
+
* @param {Object[]} args
|
|
52
|
+
* @returns {byteArray}
|
|
53
|
+
*/
|
|
54
|
+
run(input, args) {
|
|
55
|
+
const inputFormat = args[0];
|
|
56
|
+
|
|
57
|
+
if (!input.length) return [];
|
|
58
|
+
|
|
59
|
+
// Convert input to raw bytes
|
|
60
|
+
switch (inputFormat) {
|
|
61
|
+
case "Base64":
|
|
62
|
+
input = fromBase64(input, undefined, "byteArray");
|
|
63
|
+
break;
|
|
64
|
+
case "Raw":
|
|
65
|
+
default:
|
|
66
|
+
input = Utils.strToByteArray(input);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Check PDF signature
|
|
71
|
+
if (
|
|
72
|
+
input[0] !== 0x25 || // %
|
|
73
|
+
input[1] !== 0x50 || // P
|
|
74
|
+
input[2] !== 0x44 || // D
|
|
75
|
+
input[3] !== 0x46 // F
|
|
76
|
+
) {
|
|
77
|
+
throw new OperationError("Input does not appear to be a PDF file.");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return input;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Displays the PDF using HTML for web apps.
|
|
85
|
+
*
|
|
86
|
+
* @param {byteArray} data
|
|
87
|
+
* @returns {html}
|
|
88
|
+
*/
|
|
89
|
+
async present(data) {
|
|
90
|
+
if (!data.length) return "";
|
|
91
|
+
|
|
92
|
+
const base64 = toBase64(data);
|
|
93
|
+
const dataURI = "data:application/pdf;base64," + base64;
|
|
94
|
+
|
|
95
|
+
return `<iframe src="${dataURI}" style="width:100%;height:100%;border:1px solid #ccc;"></iframe>`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export default RenderPDF;
|
|
@@ -20,7 +20,7 @@ class SHA2 extends Operation {
|
|
|
20
20
|
|
|
21
21
|
this.name = "SHA2";
|
|
22
22
|
this.module = "Crypto";
|
|
23
|
-
this.description = "The SHA-2 (Secure Hash Algorithm 2) hash functions were designed by the NSA. SHA-2 includes significant changes from its predecessor, SHA-1. The SHA-2 family consists of hash functions with digests (hash values) that are 224, 256, 384 or 512 bits: SHA224, SHA256, SHA384, SHA512.<br><br><ul><li>SHA-512 operates on 64-bit words.</li><li>SHA-256 operates on 32-bit words.</li><li>SHA-384 is largely identical to SHA-512 but is truncated to 384
|
|
23
|
+
this.description = "The SHA-2 (Secure Hash Algorithm 2) hash functions were designed by the NSA. SHA-2 includes significant changes from its predecessor, SHA-1. The SHA-2 family consists of hash functions with digests (hash values) that are 224, 256, 384 or 512 bits: SHA224, SHA256, SHA384, SHA512.<br><br><ul><li>SHA-512 operates on 64-bit words.</li><li>SHA-256 operates on 32-bit words.</li><li>SHA-384 is largely identical to SHA-512 but is truncated to 384 bits.</li><li>SHA-224 is largely identical to SHA-256 but is truncated to 224 bits.</li><li>SHA-512/224 and SHA-512/256 are truncated versions of SHA-512, but the initial values are generated using the method described in Federal Information Processing Standards (FIPS) PUB 180-4.</li></ul> The message digest algorithm for SHA256 variants consists, by default, of 64 rounds, and for SHA512 variants, it is, by default, 160.";
|
|
24
24
|
this.infoURL = "https://wikipedia.org/wiki/SHA-2";
|
|
25
25
|
this.inputType = "ArrayBuffer";
|
|
26
26
|
this.outputType = "string";
|
|
@@ -75,9 +75,16 @@ class SetDifference extends Operation {
|
|
|
75
75
|
* @returns {Object[]}
|
|
76
76
|
*/
|
|
77
77
|
runSetDifference(a, b) {
|
|
78
|
+
const excluded = new Set(b);
|
|
79
|
+
const seen = new Set();
|
|
80
|
+
|
|
78
81
|
return a
|
|
79
82
|
.filter((item) => {
|
|
80
|
-
|
|
83
|
+
if (excluded.has(item) || seen.has(item)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
seen.add(item);
|
|
87
|
+
return true;
|
|
81
88
|
})
|
|
82
89
|
.join(this.itemDelimiter);
|
|
83
90
|
}
|
|
@@ -75,9 +75,16 @@ class SetIntersection extends Operation {
|
|
|
75
75
|
* @returns {Object[]}
|
|
76
76
|
*/
|
|
77
77
|
runIntersect(a, b) {
|
|
78
|
+
const included = new Set(b);
|
|
79
|
+
const seen = new Set();
|
|
80
|
+
|
|
78
81
|
return a
|
|
79
82
|
.filter((item) => {
|
|
80
|
-
|
|
83
|
+
if (!included.has(item) || seen.has(item)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
seen.add(item);
|
|
87
|
+
return true;
|
|
81
88
|
})
|
|
82
89
|
.join(this.itemDelimiter);
|
|
83
90
|
}
|
|
@@ -36,7 +36,8 @@ class ShowOnMap extends Operation {
|
|
|
36
36
|
{
|
|
37
37
|
name: "Input Format",
|
|
38
38
|
type: "option",
|
|
39
|
-
value: ["Auto"].concat(FORMATS)
|
|
39
|
+
value: ["Auto"].concat(FORMATS),
|
|
40
|
+
allowEmpty: false
|
|
40
41
|
},
|
|
41
42
|
{
|
|
42
43
|
name: "Input Delimiter",
|
|
@@ -49,7 +50,8 @@ class ShowOnMap extends Operation {
|
|
|
49
50
|
"Comma",
|
|
50
51
|
"Semi-colon",
|
|
51
52
|
"Colon"
|
|
52
|
-
]
|
|
53
|
+
],
|
|
54
|
+
allowEmpty: false
|
|
53
55
|
}
|
|
54
56
|
];
|
|
55
57
|
}
|
|
@@ -71,6 +73,16 @@ class ShowOnMap extends Operation {
|
|
|
71
73
|
}
|
|
72
74
|
latLong = latLong.replace(/[,]$/, "");
|
|
73
75
|
latLong = latLong.replace(/°/g, "");
|
|
76
|
+
|
|
77
|
+
// The map requires a latitude and longitude pair. If the conversion only produced a
|
|
78
|
+
// single value (e.g. because the chosen input delimiter didn't match the input), bail
|
|
79
|
+
// out with a helpful message rather than passing it on to the map, which would throw an
|
|
80
|
+
// uncaught TypeError in the browser.
|
|
81
|
+
const coords = latLong.split(",").map(v => v.trim());
|
|
82
|
+
if (coords.length !== 2 || coords.some(v => v === "" || isNaN(Number(v)))) {
|
|
83
|
+
throw new OperationError(`Could not show coordinates '${latLong}' on the map. Expected a latitude and longitude pair - check that the input format and delimiter are correct.`);
|
|
84
|
+
}
|
|
85
|
+
|
|
74
86
|
return latLong;
|
|
75
87
|
}
|
|
76
88
|
return input;
|