Compare commits

..

129 Commits

Author SHA1 Message Date
n1474335
68ab2da866 7.10.2 2018-04-30 16:51:24 +00:00
n1474335
72f7f0b70c Utils.fromHex function now defaults to automatically strip all delimiters. Fixes #295 2018-04-30 16:51:04 +00:00
n1474335
d18a7df3bc 7.10.1 2018-04-29 21:45:07 +01:00
n1474335
f81012ef6e CRC Checksum operations now send their input as ArrayBuffers. Tests added. Fixes #293 2018-04-29 21:44:54 +01:00
n1474335
cb66508b8a jsesc is now transpiled with babel 2018-04-06 15:44:49 +01:00
n1474335
c56038a1e2 Added error message for loading errors. Closes #254 2018-04-05 15:58:19 +00:00
n1474335
81e62a6c22 Merge branch 'master' of github.com:gchq/CyberChef 2018-03-29 00:00:09 +01:00
n1474335
c501720cdd 7.10.0 2018-03-28 23:58:52 +01:00
n1474335
92b5aa08f3 Updated dependencies 2018-03-28 23:58:43 +01:00
n1474335
1097170a68 Updated dependencies 2018-03-28 23:56:33 +01:00
n1474335
e6e2b169dc Merge branch 'tlwr-feature-add-pgp-kbpgp' 2018-03-28 23:27:01 +01:00
n1474335
e41145427e Tidied up PGP operations and added progress callback 2018-03-28 23:26:48 +01:00
n1474335
caadf8e762 Added tags to X.509 operation description 2018-03-28 10:22:22 +00:00
n1474335
1143c23ad9 Merge branch 'feature-add-pgp-kbpgp' of https://github.com/tlwr/CyberChef into tlwr-feature-add-pgp-kbpgp 2018-03-27 00:07:20 +01:00
n1474335
c1bb93eec1 7.9.0 2018-03-26 22:43:58 +01:00
n1474335
1ae9c82e29 Merge branch 'feature-updates' 2018-03-26 22:43:48 +01:00
n1474335
715ca1c292 Added Bcrypt, Scrypt, BSON and string operations along with many new tests. 2018-03-26 22:25:36 +01:00
n1474335
2f5b0533d8 Added note to 'From UNIX Timestamp' op regarding date formats. 2018-03-23 20:08:53 +00:00
n1474335
5ece79c74d 7.8.1 2018-03-23 20:02:03 +00:00
n1474335
12c226f874 Updated DisassembleX86-64 library to fix issue with call instrution. Closes #246. 2018-03-23 20:01:56 +00:00
n1474335
567474ce00 Removed confusing delimiters from fuzzy hash comparison ops 2018-03-04 18:49:05 +00:00
n1474335
209a5b7274 7.8.0 2018-03-04 18:45:23 +00:00
n1474335
e962c9594b Merge branch 'feature-fuzzy-hashes' 2018-03-04 18:45:15 +00:00
n1474335
242bad09ea Added SSDEEP and CTPH operations 2018-03-04 18:41:41 +00:00
n1474335
8dd223f1cb 7.7.8 2018-03-04 17:51:39 +00:00
n1474335
d15662dea4 Merge branch 'bug-hashes' 2018-03-04 17:49:36 +00:00
n1474335
f47a408755 Fix for UTF-8/binary handling in hashing operations. Added tests to prevent future breakages. Closes #249. 2018-03-04 17:39:53 +00:00
n1474335
8360c9e9f9 Fixed noindex meta tag for standalone version 2018-03-02 11:15:37 +00:00
n1474335
328142dac7 Added 's' to the standalone version string 2018-03-01 20:32:09 +00:00
n1474335
372b2378a8 7.7.7 2018-03-01 19:45:47 +00:00
n1474335
574207c626 Updated many dependencies including Webpack (v4) and crypto-api (v0.8) 2018-03-01 19:45:34 +00:00
n1474335
ead64dcb47 7.7.6 2018-02-28 16:40:22 +00:00
n1474335
da473de9f0 Switched from uas_parser.js to ua-parser-js library to improve library management and remove ReDos vulnerabilities. Also improved performance of two native regexes. Thanks to James Davis for raising awareness. 2018-02-28 16:40:15 +00:00
n1474335
a177e2ab7e 7.7.5 2018-02-21 11:24:46 +00:00
n1474335
8cef6db482 Added IPv6 interface IDs to the 'Format MAC address' operation 2018-02-21 11:24:38 +00:00
n1474335
79a3128491 Changed fragment to query in sitemap 2018-02-20 17:39:46 +00:00
n1474335
cb1fe80214 Added robots meta tag to inline version to prevent indexing. 2018-02-20 17:34:19 +00:00
n1474335
19f2e6dae0 Fixed robots.txt copy 2018-02-20 17:15:06 +00:00
n1474335
74394a773d Fixed URL in sitemap 2018-02-20 17:09:02 +00:00
n1474335
d491e95d1c 7.7.4 2018-02-20 17:04:47 +00:00
n1474335
881523ce54 Merge branch 'sitemap' 2018-02-20 17:04:34 +00:00
n1474335
502a9fbb92 Added dynamically generated sitemap and robots.txt file to prevent crawling of inline version 2018-02-20 16:52:27 +00:00
n1474335
cc44fe6557 7.7.3 2018-02-16 13:33:41 +00:00
n1474335
5b1ac3de18 Reduced byte length in 'Unescape Unicode Characters' 2018-02-16 13:33:33 +00:00
n1474335
5a2a649d8e 7.7.2 2018-02-15 13:41:17 +00:00
n1474335
1aef193b40 Fixed file loading error message 2018-02-15 13:41:13 +00:00
n1474335
750fa45c04 7.7.1 2018-02-14 10:34:14 +00:00
n1474335
50f2819699 OR now calls the correct function instead of duplicating XOR. Closes #243. 2018-02-14 10:34:08 +00:00
n1474335
ab55b91da1 7.7.0 2018-02-13 15:51:45 +00:00
n1474335
59f7774964 Merge branch 'feature-xkcd-rand' 2018-02-13 15:51:02 +00:00
n1474335
b5eb44af9f When highlighting operation descriptions in search results, HTML tags are now ignored. 2018-02-13 15:43:55 +00:00
n1474335
8518fa67f2 Added 'XKCD Random Number' operation 2018-02-13 15:05:55 +00:00
n1474335
f6b68f9880 Increased file overlay slice to 4096 for larger screen support 2018-02-12 13:57:01 +00:00
n1474335
f6b2783f8b File overlays now show a blurred representation of the file in the background. 2018-02-09 16:26:39 +00:00
n1474335
078849041f 7.6.3 2018-01-26 19:14:15 +00:00
n1474335
1c711f5e03 Updated dependencies 2018-01-26 19:14:05 +00:00
n1474335
614af0602a 7.6.2 2018-01-25 18:41:53 +00:00
n1474335
e55cfe0bc1 Fixed 'Syntax highlighter' operation. Using highlight.js instead of google-code-prettify. 2018-01-25 18:41:47 +00:00
n1474335
2b703b2b9b HTML outputs are now unescaped correctly when converted to a string 2018-01-25 16:25:19 +00:00
n1474335
170feaaff2 7.6.1 2018-01-25 14:03:19 +00:00
n1474335
870c2b6d8b Fixed deep copy bug with Fork/Register ingredient values. 2018-01-25 14:03:13 +00:00
n1474335
eee8b7db56 Fixed dispatchEvent call in recipe loading chain. 2018-01-25 13:46:06 +00:00
n1474335
3c669a075e 7.6.0 2018-01-25 13:45:05 +00:00
n1474335
f528930ad2 Added 'Sleep' operation. 2018-01-25 13:44:39 +00:00
n1474335
231322eddf 7.5.6 2018-01-24 16:54:42 +00:00
n1474335
8e6763c165 'Register' and 'Fork' now play well together. 2018-01-24 16:54:37 +00:00
n1474335
f091918575 7.5.5 2018-01-24 15:50:10 +00:00
n1474335
bb077c87b3 'Extract file paths' operation now handles 8.3 windows file paths correctly. 2018-01-24 15:50:05 +00:00
n1474335
fe8f8bc712 Setting a text value in the input now closes any open files. 2018-01-22 19:58:21 +00:00
n1474335
abe87830cd Operation tooltips now disappear if you hover over them while dragging an opertion. 2018-01-22 17:51:04 +00:00
n1474335
7490651a06 7.5.4 2018-01-22 17:10:02 +00:00
n1474335
6220128a74 Fixed delimiter options in StrUtils. Closes #238. 2018-01-22 17:09:58 +00:00
n1474335
ec205f4f7d 7.5.3 2018-01-18 19:53:01 +00:00
n1474335
512487328d Fixed bugs in pretty recipe format generation 2018-01-18 18:35:17 +00:00
n1474335
6fbb2f26d1 7.5.2 2018-01-18 15:27:26 +00:00
n1474335
c91bfeaa81 Merge branch 'qistoph-SplitAndJoin' 2018-01-18 15:26:34 +00:00
n1474335
aa2b3b2843 Changed order of split delimiters, placing comma first. 2018-01-18 15:26:09 +00:00
Chris van Marle
90d8be48d4 Make Split more flexible so it can be used to join 2018-01-17 15:52:25 +01:00
Toby Lorne
aa3f781e18 Merge pull request #3 from artemisbot/features/add-pgp-kbpgp
Update to master & add verify/sign
2018-01-13 12:33:28 +00:00
n1474335
aa6890432c 7.5.1 2018-01-12 23:59:03 +00:00
n1474335
192d0ed8a6 Merge branch 'feature-unicode-strings' 2018-01-12 23:57:20 +00:00
n1474335
fff188eb30 Merged master into feature-unicode-strings 2018-01-12 23:57:02 +00:00
n1474335
71067939e3 Added Regex tests and updated description 2018-01-12 23:51:51 +00:00
n1474335
b07c014b48 Added more modifiers to the Regex operation 2018-01-12 23:42:48 +00:00
n1474335
f2c073798b 'Strings' now supports various different match types in ASCII and Unicode 2018-01-12 23:09:27 +00:00
n1474335
4cc38db895 Added documentation. 2018-01-12 22:14:06 +00:00
n1474335
2762319dbb 7.5.0 2018-01-12 18:29:10 +00:00
n1474335
8e5d43dfa8 Merge branch 'feature-hamming' 2018-01-12 18:28:55 +00:00
n1474335
82ad8cc444 BigNumber Dish types are now converted to fixed notation instead of exponential when translated between types 2018-01-12 18:28:40 +00:00
Matt C
50a3cc57ad Fixed missing newline 2018-01-12 18:18:52 +00:00
n1474335
1d6bf39548 Added 'Hamming Distance' operation. 2018-01-12 18:17:28 +00:00
Matt C
7554cbda72 Added PGP Sign/Verify operations 2018-01-12 16:52:15 +00:00
Matt C
6a67fe09de Added passphrase support to importing private key 2018-01-12 12:03:46 +00:00
Matt C
f07263ca2a Fix decrypt operation 2018-01-12 11:45:16 +00:00
Matt C
bfbefb7318 Merge branch 'master' into features/add-pgp-kbpgp 2018-01-11 22:57:31 +00:00
n1474335
ec02b7deda Regexes are now checked for 0-length matches and incremented manually to avoid infinite loops 2018-01-10 19:44:25 +00:00
n1474335
fa938f832f Fixed IE 11 detection so that support message is correctly shown. 2018-01-10 18:38:17 +00:00
n1474335
6f59d9217c Changed 'Number' option to 'Integer' in PRNG op 2018-01-06 17:01:01 +00:00
n1474335
7176e5ca6e 7.4.0 2018-01-06 16:34:06 +00:00
n1474335
429829471f Merge branch 'feature-paste-performance' 2018-01-06 16:33:12 +00:00
n1474335
4760e539b7 PRNG operation now supports BigNumbers as output 2018-01-06 16:30:17 +00:00
n1474335
f53e7ad617 Chef now defaults to treat as UTF8 if option is not set 2018-01-06 16:21:42 +00:00
n1474335
28c83fa921 Dish translation now obeys UTF8 rules 2018-01-06 16:02:50 +00:00
n1474335
4588cd151c Data pasted into the input is treat as a file if it's over the IO threshold 2018-01-06 15:29:58 +00:00
n1474335
2d9f87abef Added more loading messages 2018-01-05 20:26:51 +00:00
n1474335
491e6f5f5f 7.3.0 2018-01-05 18:50:48 +00:00
n1474335
ab7c05284d Merge branch 'artemisbot-features/big-number' 2018-01-05 18:50:13 +00:00
n1474335
0586fa0e01 Fixed failing Fork test that required an error. 2018-01-05 18:49:51 +00:00
n1474335
53eba2337c BCD operations now support BigNumbers 2018-01-05 18:38:23 +00:00
n1474335
283d3e1e7b Blank BigNumber dishes are now treat as NaN instead of erroring 2018-01-05 18:20:06 +00:00
n1474335
7992a540ae Conversion operations now support BigNumbers 2018-01-05 18:14:03 +00:00
n1474335
3f3e7a78eb Arithmetic operations now support BigNumbers 2018-01-05 18:04:55 +00:00
n1474335
8d3d39acd3 Merge branch 'features/big-number' of https://github.com/artemisbot/CyberChef into artemisbot-features/big-number 2018-01-05 17:31:27 +00:00
n1474335
7b20aba2ff Improved descriptions for 'Unescape string' and 'Escape string' operations 2018-01-04 18:32:03 +00:00
n1474335
bbfb732d8f 7.2.3 2018-01-04 17:48:08 +00:00
n1474335
566adbcda5 'Unescape string' operation now works with capitalised hex 2018-01-04 17:48:01 +00:00
n1474335
1bff490fa4 7.2.2 2018-01-04 14:43:54 +00:00
n1474335
d38375a08c Improved error handling for file uploads 2018-01-04 14:43:49 +00:00
n1474335
56551712d6 Began implementing UTF-16 support in the 'Strings' operation. 2018-01-03 16:51:10 +00:00
Matt C
c241d2f90b Adds basic BigNumber type support
Fixes `To Base` & `From Base` issues as reported on twitter
2018-01-03 11:26:31 +00:00
n1474335
0ba28dc891 Updated README.md 2018-01-02 16:02:46 +00:00
n1474335
ac9af6d2ba 7.2.1 2018-01-02 15:33:08 +00:00
n1474335
90d9e087f7 'Take bytes' and 'Drop bytes' operations now support ArrayBuffers 2018-01-02 15:33:02 +00:00
n1474335
50b24d9a56 Fixed no-trailing-space lint 2018-01-02 14:46:35 +00:00
Toby Lorne
db8955d90d WIP: add encrypt and decrypt operations
Currently the encrypt operation works only to my public key and not to
keys generated by the generate key pair operation. Probably something
wrong with the generate operation.
2017-12-24 17:44:32 +00:00
Toby Lorne
5a5ce1101b Merge pull request #2 from artemisbot/features/add-pgp-kbpgp
Promisified generation of key pair
2017-12-23 17:33:42 +00:00
Matt C
670566b7eb Promisified generation of key pair 2017-12-21 14:23:31 +00:00
tlwr
dcd8f98e8c Fix linting in PGP operations 2017-11-26 20:13:49 +00:00
tlwr
60c8da7bbb Add operation "Generate PGP Key Pair"
Have not yet found a nice way of working with the kbpgp API as it is
very callback heavy. Probably just my rusty javascript.
2017-11-25 16:00:33 +00:00
74 changed files with 8015 additions and 28294 deletions

View File

@@ -5,7 +5,7 @@
"chrome": 40,
"firefox": 35,
"edge": 14,
"node": "6.5",
"node": "6.5"
},
"modules": false,
"useBuiltIns": true

View File

@@ -51,6 +51,7 @@
"mode": "minimum"
}],
"indent": ["error", 4, {
"ignoreComments": true,
"ArrayExpression": "first",
"SwitchCase": 1
}],

View File

@@ -11,6 +11,7 @@ script:
- grunt node
- grunt prod --msg="$COMPILE_MSG"
before_deploy:
- grunt exec:sitemap
- grunt copy:ghPages
deploy:
- provider: pages

View File

@@ -131,7 +131,7 @@ module.exports = function (grunt) {
grunt.initConfig({
clean: {
dev: ["build/dev/*", "src/core/config/MetaConfig.js"],
dev: ["build/dev/*"],
prod: ["build/prod/*", "src/core/config/MetaConfig.js"],
test: ["build/test/*", "src/core/config/MetaConfig.js"],
node: ["build/node/*", "src/core/config/MetaConfig.js"],
@@ -185,8 +185,12 @@ module.exports = function (grunt) {
webpack: {
options: webpackConfig,
metaConf: {
mode: "production",
target: "node",
entry: "./src/core/config/OperationConfig.js",
entry: [
"babel-polyfill",
"./src/core/config/OperationConfig.js"
],
output: {
filename: "MetaConfig.js",
path: __dirname + "/src/core/config/",
@@ -197,8 +201,12 @@ module.exports = function (grunt) {
externals: [NodeExternals()],
},
metaConfDev: {
mode: "development",
target: "node",
entry: "./src/core/config/OperationConfig.js",
entry: [
"babel-polyfill",
"./src/core/config/OperationConfig.js"
],
output: {
filename: "MetaConfig.js",
path: __dirname + "/src/core/config/",
@@ -210,9 +218,11 @@ module.exports = function (grunt) {
watch: true
},
web: {
mode: "production",
target: "web",
entry: Object.assign({
main: "./src/web/index.js"
main: "./src/web/index.js",
sitemap: "./src/web/static/sitemap.js"
}, moduleEntryPoints),
output: {
path: __dirname + "/build/prod"
@@ -224,15 +234,6 @@ module.exports = function (grunt) {
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
new webpack.optimize.UglifyJsPlugin({
compress: {
"screw_ie8": true,
"dead_code": true,
"unused": true,
"warnings": false
},
comments: false,
}),
new HtmlWebpackPlugin({
filename: "index.html",
template: "./src/web/html/index.html",
@@ -249,6 +250,7 @@ module.exports = function (grunt) {
]
},
webInline: {
mode: "production",
target: "web",
entry: "./src/web/index.js",
output: {
@@ -256,21 +258,14 @@ module.exports = function (grunt) {
path: __dirname + "/build/prod"
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
new webpack.optimize.UglifyJsPlugin({
compress: {
"screw_ie8": true,
"dead_code": true,
"unused": true,
"warnings": false
},
comments: false,
}),
new webpack.DefinePlugin(Object.assign({}, BUILD_CONSTANTS, {
INLINE: "true"
})),
new HtmlWebpackPlugin({
filename: "cyberchef.htm",
template: "./src/web/html/index.html",
compileTime: compileTime,
version: pkg.version,
version: pkg.version + "s",
inline: true,
minify: {
removeComments: true,
@@ -282,6 +277,7 @@ module.exports = function (grunt) {
]
},
tests: {
mode: "development",
target: "node",
entry: "./test/index.js",
externals: [NodeExternals()],
@@ -294,6 +290,7 @@ module.exports = function (grunt) {
]
},
node: {
mode: "production",
target: "node",
entry: "./src/node/index.js",
externals: [NodeExternals()],
@@ -320,11 +317,13 @@ module.exports = function (grunt) {
children: false,
chunks: false,
modules: false,
warningsFilter: /source-map/,
entrypoints: false,
warningsFilter: [/source-map/, /dependency is an expression/],
}
},
start: {
webpack: {
mode: "development",
target: "web",
entry: Object.assign({
main: "./src/web/index.js"
@@ -371,7 +370,7 @@ module.exports = function (grunt) {
expand: true,
src: "docs/**",
dest: "build/prod/"
}
},
]
}
},
@@ -400,6 +399,9 @@ module.exports = function (grunt) {
cleanGit: {
command: "git gc --prune=now --aggressive"
},
sitemap: {
command: "node build/prod/sitemap.js > build/prod/sitemap.xml"
}
},
execute: {
test: "build/test/index.js"

View File

@@ -27,7 +27,7 @@ Cryptographic operations in CyberChef should not be relied upon to provide secur
There are four main areas in CyberChef:
1. The **input** box in the top right, where you can paste, type or drag the data you want to operate on.
1. The **input** box in the top right, where you can paste, type or drag the text or file you want to operate on.
2. The **output** box in the bottom right, where the outcome of your processing will be displayed.
3. The **operations** list on the far left, where you can find all the operations that CyberChef is capable of in categorised lists, or by searching.
4. The **recipe** area in the middle, where you can drag the operations that you want to use and specify arguments and options.
@@ -42,32 +42,32 @@ You can use as many operations as you like in simple or complex ways. Some examp
- [Display multiple timestamps as full dates][7]
- [Carry out different operations on data of different types][8]
- [Use parts of the input as arguments to operations][9]
- [Perform AES decryption, extracting the IV from the beginning of the cipher stream][10]
## Features
- Drag and drop
- Operations can be dragged in and out of the recipe list, or reorganised.
- Files can be dragged over the input box to load them directly.
- Files can be dragged over the input box to load them directly into the browser.
- Auto Bake
- Whenever you modify the input or the recipe, CyberChef will automatically bake for you and produce the output immediately.
- Whenever you modify the input or the recipe, CyberChef will automatically "bake" for you and produce the output immediately.
- This can be turned off and operated manually if it is affecting performance (if the input is very large, for instance).
- If any bake takes longer than 200 milliseconds, auto bake will be switched off automatically to prevent further performance issues.
- Breakpoints
- You can set breakpoints on any operation in your recipe to pause execution before running it.
- You can also step through the recipe one operation at a time to see what the data looks like at each stage.
- Save and load recipes
- If you come up with an awesome recipe that you know youll want to use again, just click save and add it to your local storage. It'll be waiting for you next time you visit CyberChef.
- You can also copy a URL which includes your recipe and input which can be shared with others.
- If you come up with an awesome recipe that you know youll want to use again, just click "Save recipe" and add it to your local storage. It'll be waiting for you next time you visit CyberChef.
- You can also copy the URL, which includes your recipe and input, to easily share it with others.
- Search
- If you know the name of the operation you want or a word associated with it, start typing it into the search field and any matching operations will immediately be shown.
- Highlighting
- When you highlight text in the input or output, the offset and length values will be displayed and, if possible, the corresponding data will be highlighted in the output or input respectively (example: [highlight the word 'question' in the input to see where it appears in the output][10]).
- When you highlight text in the input or output, the offset and length values will be displayed and, if possible, the corresponding data will be highlighted in the output or input respectively (example: [highlight the word 'question' in the input to see where it appears in the output][11]).
- Save to file and load from file
- You can save the output to a file at any time or load a file by dragging and dropping it into the input field. Files up to around 500MB are supported (depending on your browser), however some operations may take a very long time to run over this much data.
- CyberChef is entirely client-side
- It should be noted that none of your recipe configuration or input (either text or files) is ever sent to the CyberChef web server - all processing is carried out within your browser, on your own computer.
- Due to this feature, CyberChef can be compiled into a single HTML file. You can download this file and drop it into a virtual machine, share it with other people, or use it independently on your desktop.
- Due to this feature, CyberChef can be compiled into a single HTML file. You can download this file and drop it into a virtual machine, share it with other people, or use it independently on your local machine.
## Browser support
@@ -100,6 +100,7 @@ CyberChef is released under the [Apache 2.0 Licence](https://www.apache.org/lice
[5]: https://gchq.github.io/CyberChef/#recipe=From_Hexdump()Gunzip()&input=MDAwMDAwMDAgIDFmIDhiIDA4IDAwIDEyIGJjIGYzIDU3IDAwIGZmIDBkIGM3IGMxIDA5IDAwIDIwICB8Li4uLi6881cu/y7HwS4uIHwKMDAwMDAwMTAgIDA4IDA1IGQwIDU1IGZlIDA0IDJkIGQzIDA0IDFmIGNhIDhjIDQ0IDIxIDViIGZmICB8Li7QVf4uLdMuLsouRCFb/3wKMDAwMDAwMjAgIDYwIGM3IGQ3IDAzIDE2IGJlIDQwIDFmIDc4IDRhIDNmIDA5IDg5IDBiIDlhIDdkICB8YMfXLi6%2BQC54Sj8uLi4ufXwKMDAwMDAwMzAgIDRlIGM4IDRlIDZkIDA1IDFlIDAxIDhiIDRjIDI0IDAwIDAwIDAwICAgICAgICAgICB8TshObS4uLi5MJC4uLnw
[6]: https://gchq.github.io/CyberChef/#recipe=RC4(%7B'option':'UTF8','string':'secret'%7D,'Hex','Hex')Disassemble_x86('64','Full%20x86%20architecture',16,0,true,true)&input=MjFkZGQyNTQwMTYwZWU2NWZlMDc3NzEwM2YyYTM5ZmJlNWJjYjZhYTBhYWJkNDE0ZjkwYzZjYWY1MzEyNzU0YWY3NzRiNzZiM2JiY2QxOTNjYjNkZGZkYmM1YTI2NTMzYTY4NmI1OWI4ZmVkNGQzODBkNDc0NDIwMWFlYzIwNDA1MDcxMzhlMmZlMmIzOTUwNDQ2ZGIzMWQyYmM2MjliZTRkM2YyZWIwMDQzYzI5M2Q3YTVkMjk2MmMwMGZlNmRhMzAwNzJkOGM1YTZiNGZlN2Q4NTlhMDQwZWVhZjI5OTczMzYzMDJmNWEwZWMxOQ
[7]: https://gchq.github.io/CyberChef/#recipe=Fork('%5C%5Cn','%5C%5Cn',false)From_UNIX_Timestamp('Seconds%20(s)')&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA
[8]: https://gchq.github.ioeCyberChef/#recipe=Fork('%5C%5Cn','%5C%5Cn',false)Conditional_Jump('1',false,'base64',10)To_Hex('Space')Return()Label('base64')To_Base64('A-Za-z0-9%2B/%3D')&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA
[8]: https://gchq.github.io/CyberChef/#recipe=Fork('%5C%5Cn','%5C%5Cn',false)Conditional_Jump('1',false,'base64',10)To_Hex('Space')Return()Label('base64')To_Base64('A-Za-z0-9%2B/%3D')&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA
[9]: https://gchq.github.io/CyberChef/#recipe=Register('key%3D(%5B%5C%5Cda-f%5D*)',true,false)Find_/_Replace(%7B'option':'Regex','string':'.*data%3D(.*)'%7D,'$1',true,false,true)RC4(%7B'option':'Hex','string':'$R0'%7D,'Hex','Latin1')&input=aHR0cDovL21hbHdhcmV6LmJpei9iZWFjb24ucGhwP2tleT0wZTkzMmE1YyZkYXRhPThkYjdkNWViZTM4NjYzYTU0ZWNiYjMzNGUzZGIxMQ
[10]: https://gchq.github.io/CyberChef/#recipe=XOR(%7B'option':'Hex','string':'3a'%7D,'',false)To_Hexdump(16,false,false)&input=VGhlIGFuc3dlciB0byB0aGUgdWx0aW1hdGUgcXVlc3Rpb24gb2YgbGlmZSwgdGhlIFVuaXZlcnNlLCBhbmQgZXZlcnl0aGluZyBpcyA0Mi4
[10]: https://gchq.github.io/CyberChef/#recipe=Register('(.%7B32%7D)',true,false)Drop_bytes(0,32,false)AES_Decrypt(%7B'option':'Hex','string':'1748e7179bd56570d51fa4ba287cc3e5'%7D,%7B'option':'Hex','string':'$R0'%7D,'CTR','Hex','Raw',%7B'option':'Hex','string':''%7D)&input=NTFlMjAxZDQ2MzY5OGVmNWY3MTdmNzFmNWI0NzEyYWYyMGJlNjc0YjNiZmY1M2QzODU0NjM5NmVlNjFkYWFjNDkwOGUzMTljYTNmY2Y3MDg5YmZiNmIzOGVhOTllNzgxZDI2ZTU3N2JhOWRkNmYzMTFhMzk0MjBiODk3OGU5MzAxNGIwNDJkNDQ3MjZjYWVkZjU0MzZlYWY2NTI0MjljMGRmOTRiNTIxNjc2YzdjMmNlODEyMDk3YzI3NzI3M2M3YzcyY2Q4OWFlYzhkOWZiNGEyNzU4NmNjZjZhYTBhZWUyMjRjMzRiYTNiZmRmN2FlYjFkZGQ0Nzc2MjJiOTFlNzJjOWU3MDlhYjYwZjhkYWY3MzFlYzBjYzg1Y2UwZjc0NmZmMTU1NGE1YTNlYzI5MWNhNDBmOWU2MjlhODcyNTkyZDk4OGZkZDgzNDUzNGFiYTc5YzFhZDE2NzY3NjlhN2MwMTBiZjA0NzM5ZWNkYjY1ZDk1MzAyMzcxZDYyOWQ5ZTM3ZTdiNGEzNjFkYTQ2OGYxZWQ1MzU4OTIyZDJlYTc1MmRkMTFjMzY2ZjMwMTdiMTRhYTAxMWQyYWYwM2M0NGY5NTU3OTA5OGExNWUzY2Y5YjQ0ODZmOGZmZTljMjM5ZjM0ZGU3MTUxZjZjYTY1MDBmZTRiODUwYzNmMWMwMmU4MDFjYWYzYTI0NDY0NjE0ZTQyODAxNjE1YjhmZmFhMDdhYzgyNTE0OTNmZmRhN2RlNWRkZjMzNjg4ODBjMmI5NWIwMzBmNDFmOGYxNTA2NmFkZDA3MWE2NmNmNjBlNWY0NmYzYTIzMGQzOTdiNjUyOTYzYTIxYTUzZg
[11]: https://gchq.github.io/CyberChef/#recipe=XOR(%7B'option':'Hex','string':'3a'%7D,'Standard',false)To_Hexdump(16,false,false)&input=VGhlIGFuc3dlciB0byB0aGUgdWx0aW1hdGUgcXVlc3Rpb24gb2YgbGlmZSwgdGhlIFVuaXZlcnNlLCBhbmQgZXZlcnl0aGluZyBpcyA0Mi4

5867
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "7.2.0",
"version": "7.10.2",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@@ -31,14 +31,16 @@
"bugs": "https://github.com/gchq/CyberChef/issues",
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-loader": "^7.1.4",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.6.1",
"css-loader": "^0.28.7",
"exports-loader": "^0.6.4",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.6",
"grunt": ">=1.0.1",
"grunt-accessibility": "~5.0.0",
"css-loader": "^0.28.11",
"eslint": "^4.19.1",
"exports-loader": "^0.7.0",
"extract-text-webpack-plugin": "^4.0.0-alpha0",
"file-loader": "^1.1.11",
"grunt": ">=1.0.2",
"grunt-accessibility": "~6.0.0",
"grunt-chmod": "~1.1.1",
"grunt-concurrent": "^2.3.1",
"grunt-contrib-clean": "~1.1.0",
@@ -46,62 +48,74 @@
"grunt-eslint": "^20.1.0",
"grunt-exec": "~3.0.0",
"grunt-execute": "^0.2.2",
"grunt-jsdoc": "^2.2.0",
"grunt-webpack": "^3.0.2",
"html-webpack-plugin": "^2.30.1",
"imports-loader": "^0.7.1",
"grunt-jsdoc": "^2.2.1",
"grunt-webpack": "^3.1.1",
"html-webpack-plugin": "^3.1.0",
"imports-loader": "^0.8.0",
"ink-docstrap": "^1.3.2",
"jsdoc-babel": "^0.3.0",
"less": "^2.7.3",
"less-loader": "^4.0.5",
"postcss-css-variables": "^0.8.0",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.0.9",
"style-loader": "^0.19.1",
"url-loader": "^0.6.2",
"jsdoc-babel": "^0.4.0",
"less": "^3.0.1",
"less-loader": "^4.1.0",
"postcss-css-variables": "^0.8.1",
"postcss-import": "^11.1.0",
"postcss-loader": "^2.1.3",
"sitemap": "^1.13.0",
"style-loader": "^0.20.3",
"url-loader": "^1.0.1",
"val-loader": "^1.1.0",
"web-resource-inliner": "^4.2.0",
"webpack": "^3.10.0",
"webpack-dev-server": "^2.9.7",
"web-resource-inliner": "^4.2.1",
"webpack": "^4.3.0",
"webpack-dev-server": "^3.1.1",
"webpack-node-externals": "^1.6.0",
"worker-loader": "^1.1.0"
"worker-loader": "^1.1.1"
},
"dependencies": {
"babel-polyfill": "^6.26.0",
"bcryptjs": "^2.4.3",
"bignumber.js": "^6.0.0",
"bootstrap": "^3.3.7",
"bootstrap-colorpicker": "^2.5.2",
"bootstrap-switch": "^3.3.4",
"crypto-api": "^0.7.5",
"bson": "^2.0.4",
"crypto-api": "^0.8.0",
"crypto-js": "^3.1.9-1",
"diff": "^3.4.0",
"escodegen": "^1.9.0",
"ctph.js": "0.0.5",
"diff": "^3.5.0",
"escodegen": "^1.9.1",
"es6-promisify": "^6.0.0",
"esmangle": "^1.0.1",
"esprima": "^4.0.0",
"exif-parser": "^0.1.12",
"file-saver": "^1.3.3",
"google-code-prettify": "^1.0.5",
"jquery": "^3.2.1",
"file-saver": "^1.3.8",
"highlight.js": "^9.12.0",
"jquery": "^3.3.1",
"js-crc": "^0.2.0",
"js-sha3": "^0.7.0",
"jsbn": "^1.1.0",
"jsesc": "^2.5.1",
"jsonpath": "^1.0.0",
"jsrsasign": "8.0.4",
"lodash": "^4.17.4",
"loglevel": "^1.6.0",
"jsrsasign": "8.0.7",
"lodash": "^4.17.5",
"loglevel": "^1.6.1",
"kbpgp": "^2.0.77",
"loglevel-message-prefix": "^3.0.0",
"moment": "^2.20.1",
"moment": "^2.21.0",
"moment-timezone": "^0.5.14",
"node-forge": "^0.7.1",
"node-forge": "^0.7.4",
"node-md6": "^0.1.0",
"nwmatcher": "^1.4.3",
"nwmatcher": "^1.4.4",
"otp": "^0.1.3",
"scryptsy": "^2.0.0",
"sladex-blowfish": "^0.8.1",
"sortablejs": "^1.7.0",
"split.js": "^1.3.5",
"ssdeep.js": "0.0.2",
"ua-parser-js": "^0.7.17",
"utf8": "^3.0.0",
"vkbeautify": "^0.99.3",
"xmldom": "^0.1.27",
"xpath": "0.0.27",
"xregexp": "^4.1.1",
"zlibjs": "^0.3.1"
},
"scripts": {

View File

@@ -35,10 +35,11 @@ const Chef = function() {
*/
Chef.prototype.bake = async function(input, recipeConfig, options, progress, step) {
log.debug("Chef baking");
let startTime = new Date().getTime(),
const startTime = new Date().getTime(),
recipe = new Recipe(recipeConfig),
containsFc = recipe.containsFlowControl(),
error = false;
notUTF8 = options && options.hasOwnProperty("treatAsUtf8") && !options.treatAsUtf8;
let error = false;
if (containsFc && ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false);
@@ -80,13 +81,13 @@ Chef.prototype.bake = async function(input, recipeConfig, options, progress, ste
// Depending on the size of the output, we may send it back as a string or an ArrayBuffer.
// This can prevent unnecessary casting as an ArrayBuffer can be easily downloaded as a file.
// The threshold is specified in KiB.
const threshold = (options.outputFileThreshold || 1024) * 1024;
const threshold = (options.ioDisplayThreshold || 1024) * 1024;
const returnType = this.dish.size() > threshold ? Dish.ARRAY_BUFFER : Dish.STRING;
return {
result: this.dish.type === Dish.HTML ?
this.dish.get(Dish.HTML) :
this.dish.get(returnType),
this.dish.get(Dish.HTML, notUTF8) :
this.dish.get(returnType, notUTF8),
type: Dish.enumLookup(this.dish.type),
progress: progress,
duration: new Date().getTime() - startTime,

View File

@@ -138,6 +138,7 @@ function loadRequiredModules(recipeConfig) {
log.info("Loading module " + module);
self.sendStatusMessage("Loading module " + module);
self.importScripts(self.docURL + "/" + module + ".js");
self.sendStatusMessage("");
}
});
}

View File

@@ -1,14 +1,16 @@
import Utils from "./Utils.js";
import BigNumber from "bignumber.js";
/**
* The data being operated on by each operation.
*
* @author n1474335 [n1474335@gmail.com]
* @author Matt C [matt@artemisbot.uk]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @class
* @param {byteArray|string|number|ArrayBuffer} value - The value of the input data.
* @param {byteArray|string|number|ArrayBuffer|BigNumber} value - The value of the input data.
* @param {number} type - The data type of value, see Dish enums.
*/
const Dish = function(value, type) {
@@ -47,6 +49,12 @@ Dish.HTML = 3;
* @enum
*/
Dish.ARRAY_BUFFER = 4;
/**
* Dish data type enum for BigNumbers.
* @readonly
* @enum
*/
Dish.BIG_NUMBER = 5;
/**
@@ -57,22 +65,22 @@ Dish.ARRAY_BUFFER = 4;
* @returns {number} The data type enum value.
*/
Dish.typeEnum = function(typeStr) {
switch (typeStr) {
case "byteArray":
case "Byte array":
switch (typeStr.toLowerCase()) {
case "bytearray":
case "byte array":
return Dish.BYTE_ARRAY;
case "string":
case "String":
return Dish.STRING;
case "number":
case "Number":
return Dish.NUMBER;
case "html":
case "HTML":
return Dish.HTML;
case "arrayBuffer":
case "ArrayBuffer":
case "arraybuffer":
case "array buffer":
return Dish.ARRAY_BUFFER;
case "bignumber":
case "big number":
return Dish.BIG_NUMBER;
default:
throw "Invalid data type string. No matching enum.";
}
@@ -83,8 +91,8 @@ Dish.typeEnum = function(typeStr) {
* Returns the data type string for the given type enum.
*
* @static
* @param {string} typeEnum - The enum value of the data type.
* @returns {number} The data type as a string.
* @param {number} typeEnum - The enum value of the data type.
* @returns {string} The data type as a string.
*/
Dish.enumLookup = function(typeEnum) {
switch (typeEnum) {
@@ -98,6 +106,8 @@ Dish.enumLookup = function(typeEnum) {
return "html";
case Dish.ARRAY_BUFFER:
return "ArrayBuffer";
case Dish.BIG_NUMBER:
return "BigNumber";
default:
throw "Invalid data type enum. No matching type.";
}
@@ -107,7 +117,7 @@ Dish.enumLookup = function(typeEnum) {
/**
* Sets the data value and type and then validates them.
*
* @param {byteArray|string|number|ArrayBuffer} value - The value of the input data.
* @param {byteArray|string|number|ArrayBuffer|BigNumber} value - The value of the input data.
* @param {number} type - The data type of value, see Dish enums.
*/
Dish.prototype.set = function(value, type) {
@@ -126,11 +136,12 @@ Dish.prototype.set = function(value, type) {
* Returns the value of the data in the type format specified.
*
* @param {number} type - The data type of value, see Dish enums.
* @returns {byteArray|string|number|ArrayBuffer} The value of the output data.
* @param {boolean} [notUTF8] - Do not treat strings as UTF8.
* @returns {byteArray|string|number|ArrayBuffer|BigNumber} The value of the output data.
*/
Dish.prototype.get = function(type) {
Dish.prototype.get = function(type, notUTF8) {
if (this.type !== type) {
this.translate(type);
this.translate(type, notUTF8);
}
return this.value;
};
@@ -140,9 +151,11 @@ Dish.prototype.get = function(type) {
* Translates the data to the given type format.
*
* @param {number} toType - The data type of value, see Dish enums.
* @param {boolean} [notUTF8] - Do not treat strings as UTF8.
*/
Dish.prototype.translate = function(toType) {
Dish.prototype.translate = function(toType, notUTF8) {
log.debug(`Translating Dish from ${Dish.enumLookup(this.type)} to ${Dish.enumLookup(toType)}`);
const byteArrayToStr = notUTF8 ? Utils.byteArrayToChars : Utils.byteArrayToUtf8;
// Convert data to intermediate byteArray type
switch (this.type) {
@@ -159,6 +172,9 @@ Dish.prototype.translate = function(toType) {
// Array.from() would be nicer here, but it's slightly slower
this.value = Array.prototype.slice.call(new Uint8Array(this.value));
break;
case Dish.BIG_NUMBER:
this.value = this.value instanceof BigNumber ? Utils.strToByteArray(this.value.toFixed()) : [];
break;
default:
break;
}
@@ -169,17 +185,25 @@ Dish.prototype.translate = function(toType) {
switch (toType) {
case Dish.STRING:
case Dish.HTML:
this.value = this.value ? Utils.byteArrayToUtf8(this.value) : "";
this.value = this.value ? byteArrayToStr(this.value) : "";
this.type = Dish.STRING;
break;
case Dish.NUMBER:
this.value = this.value ? parseFloat(Utils.byteArrayToUtf8(this.value)) : 0;
this.value = this.value ? parseFloat(byteArrayToStr(this.value)) : 0;
this.type = Dish.NUMBER;
break;
case Dish.ARRAY_BUFFER:
this.value = new Uint8Array(this.value).buffer;
this.type = Dish.ARRAY_BUFFER;
break;
case Dish.BIG_NUMBER:
try {
this.value = new BigNumber(byteArrayToStr(this.value));
} catch (err) {
this.value = new BigNumber(NaN);
}
this.type = Dish.BIG_NUMBER;
break;
default:
break;
}
@@ -215,6 +239,8 @@ Dish.prototype.valid = function() {
return typeof this.value === "number";
case Dish.ARRAY_BUFFER:
return this.value instanceof ArrayBuffer;
case Dish.BIG_NUMBER:
return this.value instanceof BigNumber;
default:
return false;
}
@@ -235,6 +261,7 @@ Dish.prototype.size = function() {
case Dish.HTML:
return this.value.length;
case Dish.NUMBER:
case Dish.BIG_NUMBER:
return this.value.toString().length;
case Dish.ARRAY_BUFFER:
return this.value.byteLength;

View File

@@ -52,14 +52,25 @@ const FlowControl = {
output = "",
progress = 0;
state.forkOffset += state.progress + 1;
recipe.addOperations(subOpList);
// Take a deep(ish) copy of the ingredient values
const ingValues = subOpList.map(op => JSON.parse(JSON.stringify(op.getIngValues())));
// Run recipe over each tranche
for (i = 0; i < inputs.length; i++) {
log.debug(`Entering tranche ${i + 1} of ${inputs.length}`);
// Baseline ing values for each tranche so that registers are reset
subOpList.forEach((op, i) => {
op.setIngValues(JSON.parse(JSON.stringify(ingValues[i])));
});
const dish = new Dish(inputs[i], inputType);
try {
progress = await recipe.execute(dish, 0);
progress = await recipe.execute(dish, 0, state);
} catch (err) {
if (!ignoreErrors) {
throw err;
@@ -117,7 +128,7 @@ const FlowControl = {
if (!registers) return state;
if (ENVIRONMENT_IS_WORKER()) {
self.setRegisters(state.progress, state.numRegisters, registers.slice(1));
self.setRegisters(state.forkOffset + state.progress, state.numRegisters, registers.slice(1));
}
/**

View File

@@ -141,11 +141,14 @@ Recipe.prototype.lastOpIndex = function(startIndex) {
*
* @param {Dish} dish
* @param {number} [startFrom=0] - The index of the Operation to start executing from
* @param {number} [forkState={}] - If this is a forked recipe, the state of the recipe up to this point
* @returns {number} - The final progress through the recipe
*/
Recipe.prototype.execute = async function(dish, startFrom) {
startFrom = startFrom || 0;
let op, input, output, numJumps = 0, numRegisters = 0;
Recipe.prototype.execute = async function(dish, startFrom = 0, forkState = {}) {
let op, input, output,
numJumps = 0,
numRegisters = forkState.numRegisters || 0;
log.debug(`[*] Executing recipe of ${this.opList.length} operations, starting at ${startFrom}`);
for (let i = startFrom; i < this.opList.length; i++) {
@@ -171,7 +174,8 @@ Recipe.prototype.execute = async function(dish, startFrom) {
"dish": dish,
"opList": this.opList,
"numJumps": numJumps,
"numRegisters": numRegisters
"numRegisters": numRegisters,
"forkOffset": forkState.forkOffset || 0
};
state = await op.run(state);
@@ -256,4 +260,5 @@ Recipe.prototype.generateHighlightList = function() {
return highlights;
};
export default Recipe;

View File

@@ -1,4 +1,5 @@
import utf8 from "utf8";
import moment from "moment-timezone";
/**
@@ -201,21 +202,34 @@ const Utils = {
* Utils.parseEscapedChars("\\n");
*/
parseEscapedChars: function(str) {
return str.replace(/(\\)?\\([nrtbf]|x[\da-f]{2})/g, function(m, a, b) {
return str.replace(/(\\)?\\([bfnrtv0'"]|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\})/g, function(m, a, b) {
if (a === "\\") return "\\"+b;
switch (b[0]) {
case "n":
return "\n";
case "r":
return "\r";
case "t":
return "\t";
case "0":
return "\0";
case "b":
return "\b";
case "t":
return "\t";
case "n":
return "\n";
case "v":
return "\v";
case "f":
return "\f";
case "r":
return "\r";
case '"':
return '"';
case "'":
return "'";
case "x":
return Utils.chr(parseInt(b.substr(1), 16));
return String.fromCharCode(parseInt(b.substr(1), 16));
case "u":
if (b[1] === "{")
return String.fromCodePoint(parseInt(b.slice(2, -1), 16));
else
return String.fromCharCode(parseInt(b.substr(1), 16));
}
});
},
@@ -283,18 +297,18 @@ const Utils = {
/**
* Coverts data of varying types to a byteArray.
* Accepts hex, Base64, UTF8 and Latin1 strings.
*
*
* @param {string} str
* @param {string} type - One of "Hex", "Base64", "UTF8" or "Latin1"
* @returns {byteArray}
*
*
* @example
* // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
* Utils.convertToByteArray("Привет", "utf8");
*
*
* // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
* Utils.convertToByteArray("d097d0b4d180d0b0d0b2d181d182d0b2d183d0b9d182d0b5", "hex");
*
*
* // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
* Utils.convertToByteArray("0JfQtNGA0LDQstGB0YLQstGD0LnRgtC1", "base64");
*/
@@ -316,20 +330,20 @@ const Utils = {
/**
* Coverts data of varying types to a byte string.
* Accepts hex, Base64, UTF8 and Latin1 strings.
*
*
* @param {string} str
* @param {string} type - One of "Hex", "Base64", "UTF8" or "Latin1"
* @returns {string}
*
*
* @example
* // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
* Utils.convertToByteArray("Привет", "utf8");
*
* // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
* Utils.convertToByteArray("d097d0b4d180d0b0d0b2d181d182d0b2d183d0b9d182d0b5", "hex");
*
* // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
* Utils.convertToByteArray("0JfQtNGA0LDQstGB0YLQstGD0LnRgtC1", "base64");
* // returns "Привет"
* Utils.convertToByteString("Привет", "utf8");
*
* // returns "Здравствуйте"
* Utils.convertToByteString("d097d0b4d180d0b0d0b2d181d182d0b2d183d0b9d182d0b5", "hex");
*
* // returns "Здравствуйте"
* Utils.convertToByteString("0JfQtNGA0LDQstGB0YLQstGD0LnRgtC1", "base64");
*/
convertToByteString: function(str, type) {
switch (type.toLowerCase()) {
@@ -493,17 +507,18 @@ const Utils = {
/**
* Converts an ArrayBuffer to a string.
*
*
* @param {ArrayBuffer} arrayBuffer
* @param {boolean} [utf8=true] - Whether to attempt to decode the buffer as UTF-8
* @returns {string}
*
*
* @example
* // returns "hello"
* Utils.arrayBufferToStr(Uint8Array.from([104,101,108,108,111]).buffer);
*/
arrayBufferToStr: function(arrayBuffer) {
arrayBufferToStr: function(arrayBuffer, utf8=true) {
const byteArray = Array.prototype.slice.call(new Uint8Array(arrayBuffer));
return Utils.byteArrayToUtf8(byteArray);
return utf8 ? Utils.byteArrayToUtf8(byteArray) : Utils.byteArrayToChars(byteArray);
},
@@ -703,10 +718,10 @@ const Utils = {
* Utils.fromHex("0a:14:1e", "Colon");
*/
fromHex: function(data, delim, byteLen) {
delim = delim || (data.indexOf(" ") >= 0 ? "Space" : "None");
delim = delim || "Auto";
byteLen = byteLen || 2;
if (delim !== "None") {
const delimRegex = Utils.regexRep[delim];
const delimRegex = delim === "Auto" ? /[^a-f\d]/gi : Utils.regexRep[delim];
data = data.replace(delimRegex, "");
}
@@ -903,9 +918,9 @@ const Utils = {
* "Pretty" CyberChef recipe formats are designed to be included in the fragment (#) or query (?)
* parts of the URL. They can also be loaded into CyberChef through the 'Load' interface. In order
* to make this format as readable as possible, various special characters are used unescaped. This
* reduces the amount of percent-encoding included in the URL which is typically difficult to read,
* as well as substantially increasing the overall length. These characteristics can be quite
* offputting for users.
* reduces the amount of percent-encoding included in the URL which is typically difficult to read
* and substantially increases the overall length. These characteristics can be quite off-putting
* for users.
*
* @param {Object[]} recipeConfig
* @param {boolean} newline - whether to add a newline after each operation
@@ -922,12 +937,11 @@ const Utils = {
name = op.op.replace(/ /g, "_");
args = JSON.stringify(op.args)
.slice(1, -1) // Remove [ and ] as they are implied
// We now need to switch double-quoted (") strings to single-quotes (') as these do not
// need to be percent-encoded.
// We now need to switch double-quoted (") strings to single quotes (') as single quotes
// do not need to be percent-encoded.
.replace(/'/g, "\\'") // Escape single quotes
.replace(/\\"/g, '"') // Unescape double quotes
.replace(/(^|,|{|:)"/g, "$1'") // Replace opening " with '
.replace(/"(,|:|}|$)/g, "'$1"); // Replace closing " with '
.replace(/"((?:[^"\\]|\\.)*)"/g, "'$1'") // Replace opening and closing " with '
.replace(/\\"/g, '"'); // Unescape double quotes
disabled = op.disabled ? "/disabled": "";
bp = op.breakpoint ? "/breakpoint" : "";
@@ -953,7 +967,7 @@ const Utils = {
// Parse bespoke recipe format
recipe = recipe.replace(/\n/g, "");
let m,
recipeRegex = /([^(]+)\(((?:'[^'\\]*(?:\\.[^'\\]*)*'|[^)/])*)(\/[^)]+)?\)/g,
recipeRegex = /([^(]+)\(((?:'[^'\\]*(?:\\.[^'\\]*)*'|[^)/'])*)(\/[^)]+)?\)/g,
recipeConfig = [],
args;

View File

@@ -52,6 +52,7 @@ const Categories = [
"From HTML Entity",
"URL Encode",
"URL Decode",
"Escape Unicode Characters",
"Unescape Unicode Characters",
"To Quoted Printable",
"From Quoted Printable",
@@ -99,6 +100,8 @@ const Categories = [
"Substitute",
"Derive PBKDF2 key",
"Derive EVP key",
"Bcrypt",
"Scrypt",
"Pseudo-Random Number Generator",
]
},
@@ -111,6 +114,11 @@ const Categories = [
"Hex to PEM",
"Hex to Object Identifier",
"Object Identifier to Hex",
"Generate PGP Key Pair",
"PGP Encrypt",
"PGP Decrypt",
"PGP Encrypt and Sign",
"PGP Decrypt and Verify",
]
},
{
@@ -189,6 +197,7 @@ const Categories = [
"Find / Replace",
"Regular expression",
"Offset checker",
"Hamming Distance",
"Convert distance",
"Convert area",
"Convert mass",
@@ -200,6 +209,7 @@ const Categories = [
"Escape string",
"Unescape string",
"Pseudo-Random Number Generator",
"Sleep",
]
},
{
@@ -212,6 +222,7 @@ const Categories = [
"Windows Filetime to UNIX Timestamp",
"UNIX Timestamp to Windows Filetime",
"Extract dates",
"Sleep",
]
},
{
@@ -267,7 +278,15 @@ const Categories = [
"HAS-160",
"Whirlpool",
"Snefru",
"SSDEEP",
"CTPH",
"Compare SSDEEP hashes",
"Compare CTPH hashes",
"HMAC",
"Bcrypt",
"Bcrypt compare",
"Bcrypt parse",
"Scrypt",
"Fletcher-8 Checksum",
"Fletcher-16 Checksum",
"Fletcher-32 Checksum",
@@ -304,6 +323,8 @@ const Categories = [
"To Snake case",
"To Camel case",
"To Kebab case",
"BSON serialise",
"BSON deserialise",
]
},
{
@@ -323,6 +344,7 @@ const Categories = [
"Remove EXIF",
"Extract EXIF",
"Numberwang",
"XKCD Random Number",
]
},
{

567
src/core/config/OperationConfig.js Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
import BSON from "../../operations/BSON.js";
/**
* BSON module.
*
* Libraries:
* - bson
* - buffer
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
OpModules.BSON = {
"BSON serialise": BSON.runBSONSerialise,
"BSON deserialise": BSON.runBSONDeserialise,
};
export default OpModules;

View File

@@ -11,7 +11,7 @@ import Code from "../../operations/Code.js";
* - xmldom
* - xpath
* - jpath
* - googlecodeprettify
* - highlight.js
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017

View File

@@ -10,7 +10,7 @@ import Convert from "../../operations/Convert.js";
import DateTime from "../../operations/DateTime.js";
import Endian from "../../operations/Endian.js";
import Entropy from "../../operations/Entropy.js";
import Extract from "../../operations/Extract.js";
import Filetime from "../../operations/Filetime.js";
import FileType from "../../operations/FileType.js";
import Hexdump from "../../operations/Hexdump.js";
import HTML from "../../operations/HTML.js";
@@ -29,6 +29,8 @@ import StrUtils from "../../operations/StrUtils.js";
import Tidy from "../../operations/Tidy.js";
import Unicode from "../../operations/Unicode.js";
import UUID from "../../operations/UUID.js";
import XKCD from "../../operations/XKCD.js";
/**
* Default module.
@@ -40,6 +42,8 @@ import UUID from "../../operations/UUID.js";
* - Utils.js
* - otp
* - crypto
* - bignumber.js
* - jsesc
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
@@ -78,6 +82,7 @@ OpModules.Default = {
"Strip HTML tags": HTML.runStripTags,
"Parse colour code": HTML.runParseColourCode,
"Unescape Unicode Characters": Unicode.runUnescape,
"Escape Unicode Characters": Unicode.runEscape,
"To Quoted Printable": QuotedPrintable.runTo,
"From Quoted Printable": QuotedPrintable.runFrom,
"Swap endianness": Endian.runSwapEndianness,
@@ -89,7 +94,7 @@ OpModules.Default = {
"Bit shift right": BitwiseOp.runBitShiftRight,
"XOR": BitwiseOp.runXor,
"XOR Brute Force": BitwiseOp.runXorBrute,
"OR": BitwiseOp.runXor,
"OR": BitwiseOp.runOr,
"NOT": BitwiseOp.runNot,
"AND": BitwiseOp.runAnd,
"ADD": BitwiseOp.runAdd,
@@ -99,17 +104,16 @@ OpModules.Default = {
"Format MAC addresses": MAC.runFormat,
"Encode NetBIOS Name": NetBIOS.runEncodeName,
"Decode NetBIOS Name": NetBIOS.runDecodeName,
"Regular expression": StrUtils.runRegex,
"Offset checker": StrUtils.runOffsetChecker,
"To Upper case": StrUtils.runUpper,
"To Lower case": StrUtils.runLower,
"Find / Replace": StrUtils.runFindReplace,
"Split": StrUtils.runSplit,
"Filter": StrUtils.runFilter,
"Escape string": StrUtils.runEscape,
"Unescape string": StrUtils.runUnescape,
"Head": StrUtils.runHead,
"Tail": StrUtils.runTail,
"Hamming Distance": StrUtils.runHamming,
"Remove whitespace": Tidy.runRemoveWhitespace,
"Remove null bytes": Tidy.runRemoveNulls,
"Drop bytes": Tidy.runDropBytes,
@@ -132,14 +136,7 @@ OpModules.Default = {
"Translate DateTime Format": DateTime.runTranslateFormat,
"From UNIX Timestamp": DateTime.runFromUnixTimestamp,
"To UNIX Timestamp": DateTime.runToUnixTimestamp,
"Strings": Extract.runStrings,
"Extract IP addresses": Extract.runIp,
"Extract email addresses": Extract.runEmail,
"Extract MAC addresses": Extract.runMac,
"Extract URLs": Extract.runUrls,
"Extract domains": Extract.runDomains,
"Extract file paths": Extract.runFilePaths,
"Extract dates": Extract.runDates,
"Sleep": DateTime.runSleep,
"Microsoft Script Decoder": MS.runDecodeScript,
"Entropy": Entropy.runEntropy,
"Frequency distribution": Entropy.runFreqDistrib,
@@ -166,6 +163,9 @@ OpModules.Default = {
"Mean": Arithmetic.runMean,
"Median": Arithmetic.runMedian,
"Standard Deviation": Arithmetic.runStdDev,
"Windows Filetime to UNIX Timestamp": Filetime.runFromFiletimeToUnix,
"UNIX Timestamp to Windows Filetime": Filetime.runToFiletimeFromUnix,
"XKCD Random Number": XKCD.runRandomNumber,
/*

View File

@@ -18,31 +18,39 @@ import Hash from "../../operations/Hash.js";
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
OpModules.Hashing = {
"Analyse hash": Hash.runAnalyse,
"Generate all hashes": Hash.runAll,
"MD2": Hash.runMD2,
"MD4": Hash.runMD4,
"MD5": Hash.runMD5,
"MD6": Hash.runMD6,
"SHA0": Hash.runSHA0,
"SHA1": Hash.runSHA1,
"SHA2": Hash.runSHA2,
"SHA3": Hash.runSHA3,
"Keccak": Hash.runKeccak,
"Shake": Hash.runShake,
"RIPEMD": Hash.runRIPEMD,
"HAS-160": Hash.runHAS,
"Whirlpool": Hash.runWhirlpool,
"Snefru": Hash.runSnefru,
"HMAC": Hash.runHMAC,
"Fletcher-8 Checksum": Checksum.runFletcher8,
"Fletcher-16 Checksum": Checksum.runFletcher16,
"Fletcher-32 Checksum": Checksum.runFletcher32,
"Fletcher-64 Checksum": Checksum.runFletcher64,
"Adler-32 Checksum": Checksum.runAdler32,
"CRC-16 Checksum": Checksum.runCRC16,
"CRC-32 Checksum": Checksum.runCRC32,
"TCP/IP Checksum": Checksum.runTCPIP,
"Analyse hash": Hash.runAnalyse,
"Generate all hashes": Hash.runAll,
"MD2": Hash.runMD2,
"MD4": Hash.runMD4,
"MD5": Hash.runMD5,
"MD6": Hash.runMD6,
"SHA0": Hash.runSHA0,
"SHA1": Hash.runSHA1,
"SHA2": Hash.runSHA2,
"SHA3": Hash.runSHA3,
"Keccak": Hash.runKeccak,
"Shake": Hash.runShake,
"RIPEMD": Hash.runRIPEMD,
"HAS-160": Hash.runHAS,
"Whirlpool": Hash.runWhirlpool,
"Snefru": Hash.runSnefru,
"CTPH": Hash.runCTPH,
"SSDEEP": Hash.runSSDEEP,
"Compare CTPH hashes": Hash.runCompareCTPH,
"Compare SSDEEP hashes": Hash.runCompareSSDEEP,
"HMAC": Hash.runHMAC,
"Bcrypt": Hash.runBcrypt,
"Bcrypt compare": Hash.runBcryptCompare,
"Bcrypt parse": Hash.runBcryptParse,
"Scrypt": Hash.runScrypt,
"Fletcher-8 Checksum": Checksum.runFletcher8,
"Fletcher-16 Checksum": Checksum.runFletcher16,
"Fletcher-32 Checksum": Checksum.runFletcher32,
"Fletcher-64 Checksum": Checksum.runFletcher64,
"Adler-32 Checksum": Checksum.runAdler32,
"CRC-16 Checksum": Checksum.runCRC16,
"CRC-32 Checksum": Checksum.runCRC32,
"TCP/IP Checksum": Checksum.runTCPIP,
};
export default OpModules;

View File

@@ -1,5 +1,4 @@
import IP from "../../operations/IP.js";
import Filetime from "../../operations/Filetime.js";
/**
@@ -21,8 +20,6 @@ OpModules.JSBN = {
"Parse IPv4 header": IP.runParseIPv4Header,
"Change IP format": IP.runChangeIpFormat,
"Group IP addresses": IP.runGroupIps,
"Windows Filetime to UNIX Timestamp": Filetime.runFromFiletimeToUnix,
"UNIX Timestamp to Windows Filetime": Filetime.runToFiletimeFromUnix,
};
export default OpModules;

View File

@@ -7,6 +7,7 @@
*/
import OpModules from "./Default.js";
import BSONModule from "./BSON.js";
import CharEncModule from "./CharEnc.js";
import CipherModule from "./Ciphers.js";
import CodeModule from "./Code.js";
@@ -18,11 +19,13 @@ import HTTPModule from "./HTTP.js";
import ImageModule from "./Image.js";
import JSBNModule from "./JSBN.js";
import PublicKeyModule from "./PublicKey.js";
import RegexModule from "./Regex.js";
import ShellcodeModule from "./Shellcode.js";
import URLModule from "./URL.js";
Object.assign(
OpModules,
BSONModule,
CharEncModule,
CipherModule,
CodeModule,
@@ -34,6 +37,7 @@ Object.assign(
ImageModule,
JSBNModule,
PublicKeyModule,
RegexModule,
ShellcodeModule,
URLModule
);

View File

@@ -0,0 +1,25 @@
import PGP from "../../operations/PGP.js";
/**
* PGP module.
*
* Libraries:
* - kbpgp
*
* @author tlwr [toby@toby.codes]
* @author Matt C [matt@artemisbot.uk]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
OpModules.PGP = {
"Generate PGP Key Pair": PGP.runGenerateKeyPair,
"PGP Encrypt": PGP.runEncrypt,
"PGP Decrypt": PGP.runDecrypt,
"PGP Encrypt and Sign": PGP.runSign,
"PGP Decrypt and Verify": PGP.runVerify,
};
export default OpModules;

View File

@@ -0,0 +1,30 @@
import Extract from "../../operations/Extract.js";
import Regex from "../../operations/Regex.js";
/**
* Regex module.
*
* Libraries:
* - XRegExp
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
OpModules.Regex = {
"Regular expression": Regex.runRegex,
"Find / Replace": Regex.runFindReplace,
"Strings": Extract.runStrings,
"Extract IP addresses": Extract.runIp,
"Extract email addresses": Extract.runEmail,
"Extract MAC addresses": Extract.runMac,
"Extract URLs": Extract.runUrls,
"Extract domains": Extract.runDomains,
"Extract file paths": Extract.runFilePaths,
"Extract dates": Extract.runDates,
};
export default OpModules;

View File

@@ -1443,8 +1443,8 @@ const Operands = [
------------------------------------------------------------------------------------------------------------------------*/
"10000004","10000004","10000004","10000004",
"16000C00","170E0C00","0C001600","0C00170E",
"10020008",
"10020008",
"110E0008",
"110E0008",
"0D060C01", //JMP Ap (w:z).
"100000040004",
"16001A01","170E1A01",
@@ -5703,7 +5703,6 @@ function LDisassemble()
}
////////////////////////////////////////////////////////////////////////////////////////////////
/*

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
import Utils from "../Utils.js";
import BigNumber from "bignumber.js";
/**
@@ -24,11 +25,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runSum: function(input, args) {
const val = Arithmetic._sum(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@@ -37,11 +38,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runSub: function(input, args) {
let val = Arithmetic._sub(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@@ -50,11 +51,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runMulti: function(input, args) {
let val = Arithmetic._multi(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@@ -63,11 +64,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runDiv: function(input, args) {
let val = Arithmetic._div(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@@ -76,11 +77,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runMean: function(input, args) {
let val = Arithmetic._mean(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@@ -89,11 +90,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runMedian: function(input, args) {
let val = Arithmetic._median(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@@ -102,11 +103,11 @@ const Arithmetic = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runStdDev: function(input, args) {
let val = Arithmetic._stdDev(Arithmetic._createNumArray(input, args[0]));
return typeof(val) === "number" ? val : NaN;
return val instanceof BigNumber ? val : new BigNumber(NaN);
},
@@ -116,7 +117,7 @@ const Arithmetic = {
* @private
* @param {string[]} input
* @param {string} delim
* @returns {number[]}
* @returns {BigNumber[]}
*/
_createNumArray: function(input, delim) {
delim = Utils.charRep[delim || "Space"];
@@ -125,13 +126,13 @@ const Arithmetic = {
num;
for (let i = 0; i < splitNumbers.length; i++) {
if (splitNumbers[i].indexOf(".") >= 0) {
num = parseFloat(splitNumbers[i].trim());
} else {
num = parseInt(splitNumbers[i].trim(), 0);
}
if (!isNaN(num)) {
numbers.push(num);
try {
num = BigNumber(splitNumbers[i].trim());
if (!num.isNaN()) {
numbers.push(num);
}
} catch (err) {
// This line is not a valid number
}
}
return numbers;
@@ -142,12 +143,12 @@ const Arithmetic = {
* Adds an array of numbers and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_sum: function(data) {
if (data.length > 0) {
return data.reduce((acc, curr) => acc + curr);
return data.reduce((acc, curr) => acc.plus(curr));
}
},
@@ -156,12 +157,12 @@ const Arithmetic = {
* Subtracts an array of numbers and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_sub: function(data) {
if (data.length > 0) {
return data.reduce((acc, curr) => acc - curr);
return data.reduce((acc, curr) => acc.minus(curr));
}
},
@@ -170,12 +171,12 @@ const Arithmetic = {
* Multiplies an array of numbers and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_multi: function(data) {
if (data.length > 0) {
return data.reduce((acc, curr) => acc * curr);
return data.reduce((acc, curr) => acc.times(curr));
}
},
@@ -184,12 +185,12 @@ const Arithmetic = {
* Divides an array of numbers and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_div: function(data) {
if (data.length > 0) {
return data.reduce((acc, curr) => acc / curr);
return data.reduce((acc, curr) => acc.div(curr));
}
},
@@ -198,12 +199,12 @@ const Arithmetic = {
* Computes mean of a number array and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_mean: function(data) {
if (data.length > 0) {
return Arithmetic._sum(data) / data.length;
return Arithmetic._sum(data).div(data.length);
}
},
@@ -212,14 +213,14 @@ const Arithmetic = {
* Computes median of a number array and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_median: function (data) {
if ((data.length % 2) === 0) {
if ((data.length % 2) === 0 && data.length > 0) {
let first, second;
data.sort(function(a, b){
return a - b;
return a.minus(b);
});
first = data[Math.floor(data.length / 2)];
second = data[Math.floor(data.length / 2) - 1];
@@ -234,17 +235,17 @@ const Arithmetic = {
* Computes standard deviation of a number array and returns the value.
*
* @private
* @param {number[]} data
* @returns {number}
* @param {BigNumber[]} data
* @returns {BigNumber}
*/
_stdDev: function (data) {
if (data.length > 0) {
let avg = Arithmetic._mean(data);
let devSum = 0;
let devSum = new BigNumber(0);
for (let i = 0; i < data.length; i++) {
devSum += (data[i] - avg) ** 2;
devSum = devSum.plus(data[i].minus(avg).pow(2));
}
return Math.sqrt(devSum / data.length);
return devSum.div(data.length).sqrt();
}
},
};

View File

@@ -1,4 +1,5 @@
import Utils from "../Utils.js";
import BigNumber from "bignumber.js";
/**
@@ -61,14 +62,14 @@ const BCD = {
/**
* To BCD operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {string}
*/
runToBCD: function(input, args) {
if (isNaN(input))
if (input.isNaN())
return "Invalid input";
if (Math.floor(input) !== input)
if (!input.integerValue(BigNumber.ROUND_DOWN).isEqualTo(input))
return "Fractional values are not supported by BCD";
const encoding = BCD.ENCODING_LOOKUP[args[0]],
@@ -77,7 +78,7 @@ const BCD = {
outputFormat = args[3];
// Split input number up into separate digits
const digits = input.toString().split("");
const digits = input.toFixed().split("");
if (digits[0] === "-" || digits[0] === "+") {
digits.shift();
@@ -152,7 +153,7 @@ const BCD = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runFromBCD: function(input, args) {
const encoding = BCD.ENCODING_LOOKUP[args[0]],
@@ -206,7 +207,7 @@ const BCD = {
output += val.toString();
});
return parseInt(output, 10);
return new BigNumber(output);
},
};

View File

@@ -0,0 +1,59 @@
import bsonjs from "bson";
import {Buffer} from "buffer";
/**
* BSON operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*
* @namespace
*/
const BSON = {
/**
* BSON serialise operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {ArrayBuffer}
*/
runBSONSerialise(input, args) {
if (!input) return new ArrayBuffer();
const bson = new bsonjs();
try {
const data = JSON.parse(input);
return bson.serialize(data).buffer;
} catch (err) {
return err.toString();
}
},
/**
* BSON deserialise operation.
*
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*
*/
runBSONDeserialise(input, args) {
if (!input.byteLength) return "";
const bson = new bsonjs();
try {
const data = bson.deserialize(new Buffer(input));
return JSON.stringify(data, null, 2);
} catch (err) {
return err.toString();
}
},
};
export default BSON;

View File

@@ -1,3 +1,5 @@
import BigNumber from "bignumber.js";
/**
* Numerical base operations.
*
@@ -18,7 +20,7 @@ const Base = {
/**
* To Base operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {string}
*/
@@ -39,7 +41,7 @@ const Base = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runFrom: function(input, args) {
const radix = args[0] || Base.DEFAULT_RADIX;
@@ -48,14 +50,14 @@ const Base = {
}
let number = input.replace(/\s/g, "").split("."),
result = parseInt(number[0], radix) || 0;
result = new BigNumber(number[0], radix) || 0;
if (number.length === 1) return result;
// Fractional part
for (let i = 0; i < number[1].length; i++) {
const digit = parseInt(number[1][i], radix);
result += digit / Math.pow(radix, i+1);
const digit = new BigNumber(number[1][i], radix);
result += digit.div(Math.pow(radix, i+1));
}
return result;

View File

@@ -21,7 +21,12 @@ const ByteRepr = {
* @constant
* @default
*/
HEX_DELIM_OPTIONS: ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"],
TO_HEX_DELIM_OPTIONS: ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"],
/**
* @constant
* @default
*/
FROM_HEX_DELIM_OPTIONS: ["Auto", "Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"],
/**
* @constant
* @default
@@ -148,6 +153,10 @@ const ByteRepr = {
throw "Error: Base argument must be between 2 and 36";
}
if (input.length === 0) {
return [];
}
if (base !== 16 && ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false);
// Split into groups of 2 if the whole string is concatenated and

View File

@@ -120,7 +120,7 @@ const Checksum = {
/**
* CRC-32 Checksum operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -132,7 +132,7 @@ const Checksum = {
/**
* CRC-16 Checksum operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/

View File

@@ -2,6 +2,7 @@ import Utils from "../Utils.js";
import CryptoJS from "crypto-js";
import forge from "imports-loader?jQuery=>null!node-forge/dist/forge.min.js";
import {blowfish as Blowfish} from "sladex-blowfish";
import BigNumber from "bignumber.js";
/**
@@ -332,7 +333,7 @@ DES uses a key length of 8 bytes (64 bits).`;
/**
* Lookup table for Blowfish output types.
*
*
* @private
*/
_BLOWFISH_OUTPUT_TYPE_LOOKUP: {
@@ -340,7 +341,7 @@ DES uses a key length of 8 bytes (64 bits).`;
},
/**
* Lookup table for Blowfish modes.
*
*
* @private
*/
_BLOWFISH_MODE_LOOKUP: {
@@ -520,11 +521,15 @@ DES uses a key length of 8 bytes (64 bits).`;
* @default
*/
PRNG_BYTES: 32,
PRNG_OUTPUT: ["Hex", "Number", "Byte array", "Raw"],
/**
* @constant
* @default
*/
PRNG_OUTPUT: ["Hex", "Integer", "Byte array", "Raw"],
/**
* Pseudo-Random Number Generator operation.
*
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
@@ -542,17 +547,17 @@ DES uses a key length of 8 bytes (64 bits).`;
bytes = forge.random.getBytesSync(numBytes);
}
let value = 0,
let value = new BigNumber(0),
i;
switch (outputAs) {
case "Hex":
return forge.util.bytesToHex(bytes);
case "Number":
case "Integer":
for (i = bytes.length - 1; i >= 0; i--) {
value = (value * 256) + bytes.charCodeAt(i);
value = value.times(256).plus(bytes.charCodeAt(i));
}
return value.toString();
return value.toFixed();
case "Byte array":
return JSON.stringify(Utils.strToCharcode(bytes));
case "Raw":
@@ -944,7 +949,7 @@ DES uses a key length of 8 bytes (64 bits).`;
/**
* A mapping of string formats to their classes in the CryptoJS library.
*
*
* @private
* @constant
*/

View File

@@ -1,12 +1,10 @@
import {camelCase, kebabCase, snakeCase} from "lodash";
import Utils from "../Utils.js";
import vkbeautify from "vkbeautify";
import {DOMParser} from "xmldom";
import xpath from "xpath";
import jpath from "jsonpath";
import nwmatcher from "nwmatcher";
import prettyPrintOne from "imports-loader?window=>global!exports-loader?prettyPrintOne!google-code-prettify/bin/prettify.min.js";
import hljs from "highlight.js";
/**
@@ -24,12 +22,7 @@ const Code = {
* @constant
* @default
*/
LANGUAGES: ["default-code", "default-markup", "bash", "bsh", "c", "cc", "coffee", "cpp", "cs", "csh", "cv", "cxx", "cyc", "htm", "html", "in.tag", "java", "javascript", "js", "json", "m", "mxml", "perl", "pl", "pm", "py", "python", "rb", "rc", "rs", "ruby", "rust", "sh", "uq.val", "xhtml", "xml", "xsl"],
/**
* @constant
* @default
*/
LINE_NUMS: false,
LANGUAGES: ["auto detect"].concat(hljs.listLanguages()),
/**
* Syntax highlighter operation.
@@ -39,9 +32,13 @@ const Code = {
* @returns {html}
*/
runSyntaxHighlight: function(input, args) {
let language = args[0],
lineNums = args[1];
return "<code class='prettyprint'>" + prettyPrintOne(Utils.escapeHtml(input), language, lineNums) + "</code>";
const language = args[0];
if (language === "auto detect") {
return hljs.highlightAuto(input).value;
}
return hljs.highlight(language, input, true).value;
},
@@ -486,12 +483,11 @@ const Code = {
/**
* Converts to snake_case.
* To Snake Case operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*
*/
runToSnakeCase(input, args) {
const smart = args[0];
@@ -505,12 +501,11 @@ const Code = {
/**
* Converts to camelCase.
* To Camel Case operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*
*/
runToCamelCase(input, args) {
const smart = args[0];
@@ -524,12 +519,11 @@ const Code = {
/**
* Converts to kebab-case.
* To Kebab Case operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*
*/
runToKebabCase(input, args) {
const smart = args[0];
@@ -540,6 +534,7 @@ const Code = {
return kebabCase(input);
}
},
};
export default Code;

View File

@@ -60,17 +60,16 @@ const Convert = {
/**
* Convert distance operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runDistance: function (input, args) {
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.DISTANCE_FACTOR[inputUnits];
return input / Convert.DISTANCE_FACTOR[outputUnits];
// TODO Remove rounding errors (e.g. 1.000000000001)
input = input.times(Convert.DISTANCE_FACTOR[inputUnits]);
return input.div(Convert.DISTANCE_FACTOR[outputUnits]);
},
@@ -141,16 +140,16 @@ const Convert = {
/**
* Convert data units operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runDataSize: function (input, args) {
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.DATA_FACTOR[inputUnits];
return input / Convert.DATA_FACTOR[outputUnits];
input = input.times(Convert.DATA_FACTOR[inputUnits]);
return input.div(Convert.DATA_FACTOR[outputUnits]);
},
@@ -221,16 +220,16 @@ const Convert = {
/**
* Convert area operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runArea: function (input, args) {
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.AREA_FACTOR[inputUnits];
return input / Convert.AREA_FACTOR[outputUnits];
input = input.times(Convert.AREA_FACTOR[inputUnits]);
return input.div(Convert.AREA_FACTOR[outputUnits]);
},
@@ -332,16 +331,16 @@ const Convert = {
/**
* Convert mass operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runMass: function (input, args) {
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.MASS_FACTOR[inputUnits];
return input / Convert.MASS_FACTOR[outputUnits];
input = input.times(Convert.MASS_FACTOR[inputUnits]);
return input.div(Convert.MASS_FACTOR[outputUnits]);
},
@@ -397,16 +396,16 @@ const Convert = {
/**
* Convert speed operation.
*
* @param {number} input
* @param {BigNumber} input
* @param {Object[]} args
* @returns {number}
* @returns {BigNumber}
*/
runSpeed: function (input, args) {
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.SPEED_FACTOR[inputUnits];
return input / Convert.SPEED_FACTOR[outputUnits];
input = input.times(Convert.SPEED_FACTOR[inputUnits]);
return input.div(Convert.SPEED_FACTOR[outputUnits]);
},
};

View File

@@ -1,3 +1,6 @@
import moment from "moment-timezone";
/**
* Date and time operations.
*
@@ -57,24 +60,29 @@ const DateTime = {
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
* @returns {string}
*/
runToUnixTimestamp: function(input, args) {
let units = args[0],
const units = args[0],
treatAsUTC = args[1],
showDateTime = args[2],
d = treatAsUTC ? moment.utc(input) : moment(input);
let result = "";
if (units === "Seconds (s)") {
return d.unix();
result = d.unix();
} else if (units === "Milliseconds (ms)") {
return d.valueOf();
result = d.valueOf();
} else if (units === "Microseconds (μs)") {
return d.valueOf() * 1000;
result = d.valueOf() * 1000;
} else if (units === "Nanoseconds (ns)") {
return d.valueOf() * 1000000;
result = d.valueOf() * 1000000;
} else {
throw "Unrecognised unit";
}
return showDateTime ? `${result} (${d.tz("UTC").format("ddd D MMMM YYYY HH:mm:ss")} UTC)` : result.toString();
},
@@ -189,6 +197,20 @@ const DateTime = {
},
/**
* Sleep operation.
*
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {ArrayBuffer}
*/
runSleep: async function(input, args) {
const ms = args[0];
await new Promise(r => setTimeout(r, ms));
return input;
},
/**
* @constant
*/

View File

@@ -1,3 +1,6 @@
import XRegExp from "xregexp";
/**
* Identifier extraction operations.
*
@@ -26,6 +29,11 @@ const Extract = {
match;
while ((match = searchRegex.exec(input))) {
// Moves pointer when an empty string is matched (prevents infinite loop)
if (match.index === searchRegex.lastIndex) {
searchRegex.lastIndex++;
}
if (removeRegex && removeRegex.test(match[0]))
continue;
total++;
@@ -43,7 +51,20 @@ const Extract = {
* @constant
* @default
*/
MIN_STRING_LEN: 3,
MIN_STRING_LEN: 4,
/**
* @constant
* @default
*/
STRING_MATCH_TYPE: [
"[ASCII]", "Alphanumeric + punctuation (A)", "All printable chars (A)", "Null-terminated strings (A)",
"[Unicode]", "Alphanumeric + punctuation (U)", "All printable chars (U)", "Null-terminated strings (U)"
],
/**
* @constant
* @default
*/
ENCODING_LIST: ["Single byte", "16-bit littleendian", "16-bit bigendian", "All"],
/**
* @constant
* @default
@@ -58,10 +79,59 @@ const Extract = {
* @returns {string}
*/
runStrings: function(input, args) {
let minLen = args[0] || Extract.MIN_STRING_LEN,
displayTotal = args[1],
strings = "[A-Z\\d/\\-:.,_$%'\"()<>= !\\[\\]{}@]",
regex = new RegExp(strings + "{" + minLen + ",}", "ig");
const encoding = args[0],
minLen = args[1],
matchType = args[2],
displayTotal = args[3],
alphanumeric = "A-Z\\d",
punctuation = "/\\-:.,_$%'\"()<>= !\\[\\]{}@",
printable = "\x20-\x7e",
uniAlphanumeric = "\\pL\\pN",
uniPunctuation = "\\pP\\pZ",
uniPrintable = "\\pL\\pM\\pZ\\pS\\pN\\pP";
let strings = "";
switch (matchType) {
case "Alphanumeric + punctuation (A)":
strings = `[${alphanumeric + punctuation}]`;
break;
case "All printable chars (A)":
case "Null-terminated strings (A)":
strings = `[${printable}]`;
break;
case "Alphanumeric + punctuation (U)":
strings = `[${uniAlphanumeric + uniPunctuation}]`;
break;
case "All printable chars (U)":
case "Null-terminated strings (U)":
strings = `[${uniPrintable}]`;
break;
}
// UTF-16 support is hacked in by allowing null bytes on either side of the matched chars
switch (encoding) {
case "All":
strings = `(\x00?${strings}\x00?)`;
break;
case "16-bit littleendian":
strings = `(${strings}\x00)`;
break;
case "16-bit bigendian":
strings = `(\x00${strings})`;
break;
case "Single byte":
default:
break;
}
strings = `${strings}{${minLen},}`;
if (matchType.includes("Null-terminated")) {
strings += "\x00";
}
const regex = new XRegExp(strings, "ig");
return Extract._search(input, regex, null, displayTotal);
},
@@ -137,7 +207,7 @@ const Extract = {
*/
runEmail: function(input, args) {
let displayTotal = args[0],
regex = /\w[-.\w]*@[-\w]+(?:\.[-\w]+)*\.[A-Z]{2,4}/ig;
regex = /\b\w[-.\w]*@[-\w]+(?:\.[-\w]+)*\.[A-Z]{2,4}\b/ig;
return Extract._search(input, regex, null, displayTotal);
},
@@ -217,7 +287,7 @@ const Extract = {
includeUnixPath = args[1],
displayTotal = args[2],
winDrive = "[A-Z]:\\\\",
winName = "[A-Z\\d][A-Z\\d\\- '_\\(\\)]{0,61}",
winName = "[A-Z\\d][A-Z\\d\\- '_\\(\\)~]{0,61}",
winExt = "[A-Z\\d]{1,6}",
winPath = winDrive + "(?:" + winName + "\\\\?)*" + winName +
"(?:\\." + winExt + ")?",

View File

@@ -1,4 +1,4 @@
import {BigInteger} from "jsbn";
import BigNumber from "bignumber.js";
/**
* Windows Filetime operations.
@@ -35,27 +35,29 @@ const Filetime = {
let units = args[0],
format = args[1];
if (!input) return "";
if (format === "Hex") {
input = new BigInteger(input, 16);
input = new BigNumber(input, 16);
} else {
input = new BigInteger(input);
input = new BigNumber(input);
}
input = input.subtract(new BigInteger("116444736000000000"));
input = input.minus(new BigNumber("116444736000000000"));
if (units === "Seconds (s)"){
input = input.divide(new BigInteger("10000000"));
input = input.dividedBy(new BigNumber("10000000"));
} else if (units === "Milliseconds (ms)") {
input = input.divide(new BigInteger("10000"));
input = input.dividedBy(new BigNumber("10000"));
} else if (units === "Microseconds (μs)") {
input = input.divide(new BigInteger("10"));
input = input.dividedBy(new BigNumber("10"));
} else if (units === "Nanoseconds (ns)") {
input = input.multiply(new BigInteger("100"));
input = input.multipliedBy(new BigNumber("100"));
} else {
throw "Unrecognised unit";
}
return input.toString();
return input.toFixed();
},
@@ -71,26 +73,28 @@ const Filetime = {
let units = args[0],
format = args[1];
input = new BigInteger(input);
if (!input) return "";
input = new BigNumber(input);
if (units === "Seconds (s)"){
input = input.multiply(new BigInteger("10000000"));
input = input.multipliedBy(new BigNumber("10000000"));
} else if (units === "Milliseconds (ms)") {
input = input.multiply(new BigInteger("10000"));
input = input.multipliedBy(new BigNumber("10000"));
} else if (units === "Microseconds (μs)") {
input = input.multiply(new BigInteger("10"));
input = input.multiplyiedBy(new BigNumber("10"));
} else if (units === "Nanoseconds (ns)") {
input = input.divide(new BigInteger("100"));
input = input.dividedBy(new BigNumber("100"));
} else {
throw "Unrecognised unit";
}
input = input.add(new BigInteger("116444736000000000"));
input = input.plus(new BigNumber("116444736000000000"));
if (format === "Hex"){
return input.toString(16);
} else {
return input.toString();
return input.toFixed();
}
},

View File

@@ -1,4 +1,4 @@
import {UAS_parser as UAParser} from "../lib/uas_parser.js";
import UAParser from "ua-parser-js";
/**
@@ -46,20 +46,22 @@ const HTTP = {
* @returns {string}
*/
runParseUserAgent: function(input, args) {
const ua = UAParser.parse(input);
return "Type: " + ua.type + "\n" +
"Family: " + ua.uaFamily + "\n" +
"Name: " + ua.uaName + "\n" +
"URL: " + ua.uaUrl + "\n" +
"Company: " + ua.uaCompany + "\n" +
"Company URL: " + ua.uaCompanyUrl + "\n\n" +
"OS Family: " + ua.osFamily + "\n" +
"OS Name: " + ua.osName + "\n" +
"OS URL: " + ua.osUrl + "\n" +
"OS Company: " + ua.osCompany + "\n" +
"OS Company URL: " + ua.osCompanyUrl + "\n" +
"Device Type: " + ua.deviceType + "\n";
const ua = UAParser(input);
return `Browser
Name: ${ua.browser.name || "unknown"}
Version: ${ua.browser.version || "unknown"}
Device
Model: ${ua.device.model || "unknown"}
Type: ${ua.device.type || "unknown"}
Vendor: ${ua.device.vendor || "unknown"}
Engine
Name: ${ua.engine.name || "unknown"}
Version: ${ua.engine.version || "unknown"}
OS
Name: ${ua.os.name || "unknown"}
Version: ${ua.os.version || "unknown"}
CPU
Architecture: ${ua.cpu.architecture || "unknown"}`;
},

View File

@@ -1,8 +1,12 @@
import Utils from "../Utils.js";
import CryptoApi from "crypto-api";
import CryptoApi from "babel-loader!crypto-api";
import MD6 from "node-md6";
import * as SHA3 from "js-sha3";
import Checksum from "./Checksum.js";
import ctph from "ctph.js";
import ssdeep from "ssdeep.js";
import bcrypt from "bcryptjs";
import scrypt from "scryptsy";
/**
@@ -20,22 +24,22 @@ const Hash = {
* Generic hash function.
*
* @param {string} name
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object} [options={}]
* @returns {string}
*/
runHash: function(name, input) {
const hasher = CryptoApi.hasher(name);
hasher.state.message = input;
hasher.state.length += input.length;
hasher.process();
return hasher.finalize().stringify("hex");
runHash: function(name, input, options={}) {
const msg = Utils.arrayBufferToStr(input, false),
hasher = CryptoApi.getHasher(name, options);
hasher.update(msg);
return CryptoApi.encoder.toHex(hasher.finalize());
},
/**
* MD2 operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -47,7 +51,7 @@ const Hash = {
/**
* MD4 operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -59,7 +63,7 @@ const Hash = {
/**
* MD5 operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -103,7 +107,7 @@ const Hash = {
/**
* SHA0 operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -115,7 +119,7 @@ const Hash = {
/**
* SHA1 operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -133,7 +137,7 @@ const Hash = {
/**
* SHA2 operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -152,7 +156,7 @@ const Hash = {
/**
* SHA3 operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -190,7 +194,7 @@ const Hash = {
/**
* Keccak operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -233,7 +237,7 @@ const Hash = {
/**
* Shake operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -269,7 +273,7 @@ const Hash = {
/**
* RIPEMD operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -282,7 +286,7 @@ const Hash = {
/**
* HAS-160 operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -300,7 +304,7 @@ const Hash = {
/**
* Whirlpool operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
@@ -324,14 +328,73 @@ const Hash = {
/**
* Snefru operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
runSnefru: function (input, args) {
const rounds = args[0],
size = args[1];
return Hash.runHash(`snefru-${rounds}-${size}`, input);
return Hash.runHash("snefru", input, {
rounds: args[0],
length: args[1]
});
},
/**
* CTPH operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runCTPH: function (input, args) {
return ctph.digest(input);
},
/**
* SSDEEP operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runSSDEEP: function (input, args) {
return ssdeep.digest(input);
},
/**
* @constant
* @default
*/
DELIM_OPTIONS: ["Line feed", "CRLF", "Space", "Comma"],
/**
* Compare CTPH hashes operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {Number}
*/
runCompareCTPH: function (input, args) {
const samples = input.split(Utils.charRep[args[0]]);
if (samples.length !== 2) throw "Incorrect number of samples.";
return ctph.similarity(samples[0], samples[1]);
},
/**
* Compare SSDEEP hashes operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {Number}
*/
runCompareSSDEEP: function (input, args) {
const samples = input.split(Utils.charRep[args[0]]);
if (samples.length !== 2) throw "Incorrect number of samples.";
return ssdeep.similarity(samples[0], samples[1]);
},
@@ -358,71 +421,206 @@ const Hash = {
"HAS160",
"Whirlpool",
"Whirlpool-0",
"Whirlpool-T"
"Whirlpool-T",
"Snefru"
],
/**
* HMAC operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
runHMAC: function (input, args) {
const password = args[0],
const key = args[0],
hashFunc = args[1].toLowerCase(),
hmac = CryptoApi.mac("hmac", password, hashFunc, {});
msg = Utils.arrayBufferToStr(input, false),
hasher = CryptoApi.getHasher(hashFunc);
hmac.update(input);
return hmac.finalize().stringify("hex");
// Horrible shim to fix constructor bug. Reported in nf404/crypto-api#8
hasher.reset = () => {
hasher.state = {};
const tmp = new hasher.constructor();
hasher.state = tmp.state;
};
const mac = CryptoApi.getHmac(CryptoApi.encoder.fromUtf(key), hasher);
mac.update(msg);
return CryptoApi.encoder.toHex(mac.finalize());
},
/**
* @constant
* @default
*/
BCRYPT_ROUNDS: 10,
/**
* Bcrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runBcrypt: async function (input, args) {
const rounds = args[0];
const salt = await bcrypt.genSalt(rounds);
return await bcrypt.hash(input, salt, null, p => {
// Progress callback
if (ENVIRONMENT_IS_WORKER())
self.sendStatusMessage(`Progress: ${(p * 100).toFixed(0)}%`);
});
},
/**
* Bcrypt compare operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runBcryptCompare: async function (input, args) {
const hash = args[0];
const match = await bcrypt.compare(input, hash, null, p => {
// Progress callback
if (ENVIRONMENT_IS_WORKER())
self.sendStatusMessage(`Progress: ${(p * 100).toFixed(0)}%`);
});
return match ? "Match: " + input : "No match";
},
/**
* Bcrypt parse operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runBcryptParse: async function (input, args) {
try {
return `Rounds: ${bcrypt.getRounds(input)}
Salt: ${bcrypt.getSalt(input)}
Password hash: ${input.split(bcrypt.getSalt(input))[1]}
Full hash: ${input}`;
} catch (err) {
return "Error: " + err.toString();
}
},
/**
* @constant
* @default
*/
KEY_FORMAT: ["Hex", "Base64", "UTF8", "Latin1"],
/**
* @constant
* @default
*/
SCRYPT_ITERATIONS: 16384,
/**
* @constant
* @default
*/
SCRYPT_MEM_FACTOR: 8,
/**
* @constant
* @default
*/
SCRYPT_PARALLEL_FACTOR: 1,
/**
* @constant
* @default
*/
SCRYPT_KEY_LENGTH: 64,
/**
* Scrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runScrypt: function (input, args) {
const salt = Utils.convertToByteString(args[0].string || "", args[0].option),
iterations = args[1],
memFactor = args[2],
parallelFactor = args[3],
keyLength = args[4];
try {
const data = scrypt(
input, salt, iterations, memFactor, parallelFactor, keyLength,
p => {
// Progress callback
if (ENVIRONMENT_IS_WORKER())
self.sendStatusMessage(`Progress: ${p.percent.toFixed(0)}%`);
}
);
return data.toString("hex");
} catch (err) {
return "Error: " + err.toString();
}
},
/**
* Generate all hashes operation.
*
* @param {string} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
runAll: function (input, args) {
let byteArray = Utils.strToByteArray(input),
output = "MD2: " + Hash.runMD2(input, []) +
"\nMD4: " + Hash.runMD4(input, []) +
"\nMD5: " + Hash.runMD5(input, []) +
"\nMD6: " + Hash.runMD6(input, []) +
"\nSHA0: " + Hash.runSHA0(input, []) +
"\nSHA1: " + Hash.runSHA1(input, []) +
"\nSHA2 224: " + Hash.runSHA2(input, ["224"]) +
"\nSHA2 256: " + Hash.runSHA2(input, ["256"]) +
"\nSHA2 384: " + Hash.runSHA2(input, ["384"]) +
"\nSHA2 512: " + Hash.runSHA2(input, ["512"]) +
"\nSHA3 224: " + Hash.runSHA3(input, ["224"]) +
"\nSHA3 256: " + Hash.runSHA3(input, ["256"]) +
"\nSHA3 384: " + Hash.runSHA3(input, ["384"]) +
"\nSHA3 512: " + Hash.runSHA3(input, ["512"]) +
"\nKeccak 224: " + Hash.runKeccak(input, ["224"]) +
"\nKeccak 256: " + Hash.runKeccak(input, ["256"]) +
"\nKeccak 384: " + Hash.runKeccak(input, ["384"]) +
"\nKeccak 512: " + Hash.runKeccak(input, ["512"]) +
"\nShake 128: " + Hash.runShake(input, ["128", 256]) +
"\nShake 256: " + Hash.runShake(input, ["256", 512]) +
"\nRIPEMD-128: " + Hash.runRIPEMD(input, ["128"]) +
"\nRIPEMD-160: " + Hash.runRIPEMD(input, ["160"]) +
"\nRIPEMD-256: " + Hash.runRIPEMD(input, ["256"]) +
"\nRIPEMD-320: " + Hash.runRIPEMD(input, ["320"]) +
"\nHAS-160: " + Hash.runHAS(input, []) +
"\nWhirlpool-0: " + Hash.runWhirlpool(input, ["Whirlpool-0"]) +
"\nWhirlpool-T: " + Hash.runWhirlpool(input, ["Whirlpool-T"]) +
"\nWhirlpool: " + Hash.runWhirlpool(input, ["Whirlpool"]) +
const arrayBuffer = input,
str = Utils.arrayBufferToStr(arrayBuffer, false),
byteArray = new Uint8Array(arrayBuffer),
output = "MD2: " + Hash.runMD2(arrayBuffer, []) +
"\nMD4: " + Hash.runMD4(arrayBuffer, []) +
"\nMD5: " + Hash.runMD5(arrayBuffer, []) +
"\nMD6: " + Hash.runMD6(str, []) +
"\nSHA0: " + Hash.runSHA0(arrayBuffer, []) +
"\nSHA1: " + Hash.runSHA1(arrayBuffer, []) +
"\nSHA2 224: " + Hash.runSHA2(arrayBuffer, ["224"]) +
"\nSHA2 256: " + Hash.runSHA2(arrayBuffer, ["256"]) +
"\nSHA2 384: " + Hash.runSHA2(arrayBuffer, ["384"]) +
"\nSHA2 512: " + Hash.runSHA2(arrayBuffer, ["512"]) +
"\nSHA3 224: " + Hash.runSHA3(arrayBuffer, ["224"]) +
"\nSHA3 256: " + Hash.runSHA3(arrayBuffer, ["256"]) +
"\nSHA3 384: " + Hash.runSHA3(arrayBuffer, ["384"]) +
"\nSHA3 512: " + Hash.runSHA3(arrayBuffer, ["512"]) +
"\nKeccak 224: " + Hash.runKeccak(arrayBuffer, ["224"]) +
"\nKeccak 256: " + Hash.runKeccak(arrayBuffer, ["256"]) +
"\nKeccak 384: " + Hash.runKeccak(arrayBuffer, ["384"]) +
"\nKeccak 512: " + Hash.runKeccak(arrayBuffer, ["512"]) +
"\nShake 128: " + Hash.runShake(arrayBuffer, ["128", 256]) +
"\nShake 256: " + Hash.runShake(arrayBuffer, ["256", 512]) +
"\nRIPEMD-128: " + Hash.runRIPEMD(arrayBuffer, ["128"]) +
"\nRIPEMD-160: " + Hash.runRIPEMD(arrayBuffer, ["160"]) +
"\nRIPEMD-256: " + Hash.runRIPEMD(arrayBuffer, ["256"]) +
"\nRIPEMD-320: " + Hash.runRIPEMD(arrayBuffer, ["320"]) +
"\nHAS-160: " + Hash.runHAS(arrayBuffer, []) +
"\nWhirlpool-0: " + Hash.runWhirlpool(arrayBuffer, ["Whirlpool-0"]) +
"\nWhirlpool-T: " + Hash.runWhirlpool(arrayBuffer, ["Whirlpool-T"]) +
"\nWhirlpool: " + Hash.runWhirlpool(arrayBuffer, ["Whirlpool"]) +
"\nSSDEEP: " + Hash.runSSDEEP(str) +
"\nCTPH: " + Hash.runCTPH(str) +
"\n\nChecksums:" +
"\nFletcher-8: " + Checksum.runFletcher8(byteArray, []) +
"\nFletcher-16: " + Checksum.runFletcher16(byteArray, []) +
"\nFletcher-32: " + Checksum.runFletcher32(byteArray, []) +
"\nFletcher-64: " + Checksum.runFletcher64(byteArray, []) +
"\nAdler-32: " + Checksum.runAdler32(byteArray, []) +
"\nCRC-16: " + Checksum.runCRC16(input, []) +
"\nCRC-32: " + Checksum.runCRC32(input, []);
"\nCRC-16: " + Checksum.runCRC16(str, []) +
"\nCRC-32: " + Checksum.runCRC32(str, []);
return output;
},

View File

@@ -78,7 +78,7 @@ const Hexdump = {
*/
runFrom: function(input, args) {
let output = [],
regex = /^\s*(?:[\dA-F]{4,16}:?)?\s*((?:[\dA-F]{2}\s){1,8}(?:\s|[\dA-F]{2}-)(?:[\dA-F]{2}\s){1,8}|(?:[\dA-F]{2}\s|[\dA-F]{4}\s)+)/igm,
regex = /^\s*(?:[\dA-F]{4,16}h?:?)?\s*((?:[\dA-F]{2}\s){1,8}(?:\s|[\dA-F]{2}-)(?:[\dA-F]{2}\s){1,8}|(?:[\dA-F]{2}\s|[\dA-F]{4}\s)+)/igm,
block, line;
while ((block = regex.exec(input))) {

View File

@@ -34,6 +34,11 @@ const MAC = {
* @default
*/
CISCO_STYLE: false,
/**
* @constant
* @default
*/
IPV6_INTERFACE_ID: false,
/**
* Format MAC addresses operation.
@@ -50,6 +55,7 @@ const MAC = {
dashDelim = args[2],
colonDelim = args[3],
ciscoStyle = args[4],
ipv6IntID = args[5],
outputList = [],
macs = input.toLowerCase().split(/[,\s\r\n]+/);
@@ -57,23 +63,32 @@ const MAC = {
let cleanMac = mac.replace(/[:.-]+/g, ""),
macHyphen = cleanMac.replace(/(.{2}(?=.))/g, "$1-"),
macColon = cleanMac.replace(/(.{2}(?=.))/g, "$1:"),
macCisco = cleanMac.replace(/(.{4}(?=.))/g, "$1.");
macCisco = cleanMac.replace(/(.{4}(?=.))/g, "$1."),
macIPv6 = cleanMac.slice(0, 6) + "fffe" + cleanMac.slice(6);
macIPv6 = macIPv6.replace(/(.{4}(?=.))/g, "$1:");
let bite = parseInt(macIPv6.slice(0, 2), 16) ^ 2;
bite = bite.toString(16).padStart(2, "0");
macIPv6 = bite + macIPv6.slice(2);
if (outputCase === "Lower only") {
if (noDelim) outputList.push(cleanMac);
if (dashDelim) outputList.push(macHyphen);
if (colonDelim) outputList.push(macColon);
if (ciscoStyle) outputList.push(macCisco);
if (ipv6IntID) outputList.push(macIPv6);
} else if (outputCase === "Upper only") {
if (noDelim) outputList.push(cleanMac.toUpperCase());
if (dashDelim) outputList.push(macHyphen.toUpperCase());
if (colonDelim) outputList.push(macColon.toUpperCase());
if (ciscoStyle) outputList.push(macCisco.toUpperCase());
if (ipv6IntID) outputList.push(macIPv6.toUpperCase());
} else {
if (noDelim) outputList.push(cleanMac, cleanMac.toUpperCase());
if (dashDelim) outputList.push(macHyphen, macHyphen.toUpperCase());
if (colonDelim) outputList.push(macColon, macColon.toUpperCase());
if (ciscoStyle) outputList.push(macCisco, macCisco.toUpperCase());
if (ipv6IntID) outputList.push(macIPv6, macIPv6.toUpperCase());
}
outputList.push(

358
src/core/operations/PGP.js Executable file
View File

@@ -0,0 +1,358 @@
import * as kbpgp from "kbpgp";
import {promisify} from "es6-promisify";
/**
* PGP operations.
*
* @author tlwr [toby@toby.codes]
* @author Matt C [matt@artemisbot.uk]
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*
* @namespace
*/
const PGP = {
/**
* @constant
* @default
*/
KEY_TYPES: ["RSA-1024", "RSA-2048", "RSA-4096", "ECC-256", "ECC-384"],
/**
* Get size of subkey
*
* @private
* @param {number} keySize
* @returns {number}
*/
_getSubkeySize(keySize) {
return {
1024: 1024,
2048: 1024,
4096: 2048,
256: 256,
384: 256,
}[keySize];
},
/**
* Progress callback
*
* @private
*/
_ASP: new kbpgp.ASP({
"progress_hook": info => {
let msg = "";
switch (info.what) {
case "guess":
msg = "Guessing a prime";
break;
case "fermat":
msg = "Factoring prime using Fermat's factorization method";
break;
case "mr":
msg = "Performing Miller-Rabin primality test";
break;
case "passed_mr":
msg = "Passed Miller-Rabin primality test";
break;
case "failed_mr":
msg = "Failed Miller-Rabin primality test";
break;
case "found":
msg = "Prime found";
break;
default:
msg = `Stage: ${info.what}`;
}
if (ENVIRONMENT_IS_WORKER())
self.sendStatusMessage(msg);
}
}),
/**
* Import private key and unlock if necessary
*
* @private
* @param {string} privateKey
* @param {string} [passphrase]
* @returns {Object}
*/
async _importPrivateKey(privateKey, passphrase) {
try {
const key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
armored: privateKey,
});
if (key.is_pgp_locked() && passphrase) {
if (passphrase) {
await promisify(key.unlock_pgp.bind(key))({
passphrase
});
} else if (!passphrase) {
throw "Did not provide passphrase with locked private key.";
}
}
return key;
} catch (err) {
throw `Could not import private key: ${err}`;
}
},
/**
* Import public key
*
* @private
* @param {string} publicKey
* @returns {Object}
*/
async _importPublicKey (publicKey) {
try {
const key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
armored: publicKey,
});
return key;
} catch (err) {
throw `Could not import public key: ${err}`;
}
},
/**
* Generate PGP Key Pair operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runGenerateKeyPair(input, args) {
let [keyType, keySize] = args[0].split("-"),
password = args[1],
name = args[2],
email = args[3],
userIdentifier = "";
if (name) userIdentifier += name;
if (email) userIdentifier += ` <${email}>`;
let flags = kbpgp.const.openpgp.certify_keys;
flags |= kbpgp.const.openpgp.sign_data;
flags |= kbpgp.const.openpgp.auth;
flags |= kbpgp.const.openpgp.encrypt_comm;
flags |= kbpgp.const.openpgp.encrypt_storage;
let keyGenerationOptions = {
userid: userIdentifier,
ecc: keyType === "ecc",
primary: {
"nbits": keySize,
"flags": flags,
"expire_in": 0
},
subkeys: [{
"nbits": PGP._getSubkeySize(keySize),
"flags": kbpgp.const.openpgp.sign_data,
"expire_in": 86400 * 365 * 8
}, {
"nbits": PGP._getSubkeySize(keySize),
"flags": kbpgp.const.openpgp.encrypt_comm | kbpgp.const.openpgp.encrypt_storage,
"expire_in": 86400 * 365 * 2
}],
asp: PGP._ASP
};
return new Promise(async (resolve, reject) => {
try {
const unsignedKey = await promisify(kbpgp.KeyManager.generate)(keyGenerationOptions);
await promisify(unsignedKey.sign.bind(unsignedKey))({});
let signedKey = unsignedKey;
let privateKeyExportOptions = {};
if (password) privateKeyExportOptions.passphrase = password;
const privateKey = await promisify(signedKey.export_pgp_private.bind(signedKey))(privateKeyExportOptions);
const publicKey = await promisify(signedKey.export_pgp_public.bind(signedKey))({});
resolve(privateKey + "\n" + publicKey.trim());
} catch (err) {
reject(`Error whilst generating key pair: ${err}`);
}
});
},
/**
* PGP Encrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async runEncrypt(input, args) {
let plaintextMessage = input,
plainPubKey = args[0],
key,
encryptedMessage;
if (!plainPubKey) return "Enter the public key of the recipient.";
try {
key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
armored: plainPubKey,
});
} catch (err) {
throw `Could not import public key: ${err}`;
}
try {
encryptedMessage = await promisify(kbpgp.box)({
"msg": plaintextMessage,
"encrypt_for": key,
"asp": PGP._ASP
});
} catch (err) {
throw `Couldn't encrypt message with provided public key: ${err}`;
}
return encryptedMessage.toString();
},
/**
* PGP Decrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async runDecrypt(input, args) {
let encryptedMessage = input,
privateKey = args[0],
passphrase = args[1],
keyring = new kbpgp.keyring.KeyRing(),
plaintextMessage;
if (!privateKey) return "Enter the private key of the recipient.";
const key = await PGP._importPrivateKey(privateKey, passphrase);
keyring.add_key_manager(key);
try {
plaintextMessage = await promisify(kbpgp.unbox)({
armored: encryptedMessage,
keyfetch: keyring,
asp: PGP._ASP
});
} catch (err) {
throw `Couldn't decrypt message with provided private key: ${err}`;
}
return plaintextMessage.toString();
},
/**
* PGP Sign Message operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async runSign(input, args) {
let message = input,
privateKey = args[0],
passphrase = args[1],
publicKey = args[2],
signedMessage;
if (!privateKey) return "Enter the private key of the signer.";
if (!publicKey) return "Enter the public key of the recipient.";
const privKey = await PGP._importPrivateKey(privateKey, passphrase);
const pubKey = await PGP._importPublicKey(publicKey);
try {
signedMessage = await promisify(kbpgp.box)({
"msg": message,
"encrypt_for": pubKey,
"sign_with": privKey,
"asp": PGP._ASP
});
} catch (err) {
throw `Couldn't sign message: ${err}`;
}
return signedMessage;
},
/**
* PGP Verify Message operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async runVerify(input, args) {
let signedMessage = input,
publicKey = args[0],
privateKey = args[1],
passphrase = args[2],
keyring = new kbpgp.keyring.KeyRing(),
unboxedLiterals;
if (!publicKey) return "Enter the public key of the signer.";
if (!privateKey) return "Enter the private key of the recipient.";
const privKey = await PGP._importPrivateKey(privateKey, passphrase);
const pubKey = await PGP._importPublicKey(publicKey);
keyring.add_key_manager(privKey);
keyring.add_key_manager(pubKey);
try {
unboxedLiterals = await promisify(kbpgp.unbox)({
armored: signedMessage,
keyfetch: keyring,
asp: PGP._ASP
});
const ds = unboxedLiterals[0].get_data_signer();
if (ds) {
const km = ds.get_key_manager();
if (km) {
const signer = km.get_userids_mark_primary()[0].components;
let text = "Signed by ";
if (signer.email || signer.username || signer.comment) {
if (signer.username) {
text += `${signer.username} `;
}
if (signer.comment) {
text += `${signer.comment} `;
}
if (signer.email) {
text += `<${signer.email}>`;
}
text += "\n";
}
text += [
`PGP fingerprint: ${km.get_pgp_fingerprint().toString("hex")}`,
`Signed on ${new Date(ds.sig.hashed_subpackets[0].time * 1000).toUTCString()}`,
"----------------------------------\n"
].join("\n");
text += unboxedLiterals.toString();
return text.trim();
} else {
return "Could not identify a key manager.";
}
} else {
return "The data does not appear to be signed.";
}
} catch (err) {
return `Couldn't verify message: ${err}`;
}
},
};
export default PGP;

View File

@@ -0,0 +1,278 @@
import XRegExp from "xregexp";
import Utils from "../Utils.js";
/**
* Regex operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*
* @namespace
*/
const Regex = {
/**
* @constant
* @default
*/
REGEX_PRE_POPULATE: [
{
name: "User defined",
value: ""
},
{
name: "IPv4 address",
value: "(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?"
},
{
name: "IPv6 address",
value: "((?=.*::)(?!.*::.+::)(::)?([\\dA-Fa-f]{1,4}:(:|\\b)|){5}|([\\dA-Fa-f]{1,4}:){6})((([\\dA-Fa-f]{1,4}((?!\\3)::|:\\b|(?![\\dA-Fa-f])))|(?!\\2\\3)){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})"
},
{
name: "Email address",
value: "\\b(\\w[-.\\w]*)@([-\\w]+(?:\\.[-\\w]+)*)\\.([A-Za-z]{2,4})\\b"
},
{
name: "URL",
value: "([A-Za-z]+://)([-\\w]+(?:\\.\\w[-\\w]*)+)(:\\d+)?(/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*)?"
},
{
name: "Domain",
value: "\\b((?=[a-z0-9-]{1,63}\\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}\\b"
},
{
name: "Windows file path",
value: "([A-Za-z]):\\\\((?:[A-Za-z\\d][A-Za-z\\d\\- \\x27_\\(\\)~]{0,61}\\\\?)*[A-Za-z\\d][A-Za-z\\d\\- \\x27_\\(\\)]{0,61})(\\.[A-Za-z\\d]{1,6})?"
},
{
name: "UNIX file path",
value: "(?:/[A-Za-z\\d.][A-Za-z\\d\\-.]{0,61})+"
},
{
name: "MAC address",
value: "[A-Fa-f\\d]{2}(?:[:-][A-Fa-f\\d]{2}){5}"
},
{
name: "Date (yyyy-mm-dd)",
value: "((?:19|20)\\d\\d)[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])"
},
{
name: "Date (dd/mm/yyyy)",
value: "(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.]((?:19|20)\\d\\d)"
},
{
name: "Date (mm/dd/yyyy)",
value: "(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.]((?:19|20)\\d\\d)"
},
{
name: "Strings",
value: "[A-Za-z\\d/\\-:.,_$%\\x27\"()<>= !\\[\\]{}@]{4,}"
},
],
/**
* @constant
* @default
*/
OUTPUT_FORMAT: ["Highlight matches", "List matches", "List capture groups", "List matches with capture groups"],
/**
* @constant
* @default
*/
DISPLAY_TOTAL: false,
/**
* Regular expression operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
runRegex: function(input, args) {
const userRegex = args[1],
i = args[2],
m = args[3],
s = args[4],
u = args[5],
a = args[6],
displayTotal = args[7],
outputFormat = args[8];
let modifiers = "g";
if (i) modifiers += "i";
if (m) modifiers += "m";
if (s) modifiers += "s";
if (u) modifiers += "u";
if (a) modifiers += "A";
if (userRegex && userRegex !== "^" && userRegex !== "$") {
try {
const regex = new XRegExp(userRegex, modifiers);
switch (outputFormat) {
case "Highlight matches":
return Regex._regexHighlight(input, regex, displayTotal);
case "List matches":
return Utils.escapeHtml(Regex._regexList(input, regex, displayTotal, true, false));
case "List capture groups":
return Utils.escapeHtml(Regex._regexList(input, regex, displayTotal, false, true));
case "List matches with capture groups":
return Utils.escapeHtml(Regex._regexList(input, regex, displayTotal, true, true));
default:
return "Error: Invalid output format";
}
} catch (err) {
return "Invalid regex. Details: " + err.message;
}
} else {
return Utils.escapeHtml(input);
}
},
/**
* @constant
* @default
*/
SEARCH_TYPE: ["Regex", "Extended (\\n, \\t, \\x...)", "Simple string"],
/**
* @constant
* @default
*/
FIND_REPLACE_GLOBAL: true,
/**
* @constant
* @default
*/
FIND_REPLACE_CASE: false,
/**
* @constant
* @default
*/
FIND_REPLACE_MULTILINE: true,
/**
* Find / Replace operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runFindReplace: function(input, args) {
let find = args[0].string,
type = args[0].option,
replace = args[1],
g = args[2],
i = args[3],
m = args[4],
modifiers = "";
if (g) modifiers += "g";
if (i) modifiers += "i";
if (m) modifiers += "m";
if (type === "Regex") {
find = new RegExp(find, modifiers);
return input.replace(find, replace);
}
if (type.indexOf("Extended") === 0) {
find = Utils.parseEscapedChars(find);
}
find = new RegExp(Utils.escapeRegex(find), modifiers);
return input.replace(find, replace);
},
/**
* Adds HTML highlights to matches within a string.
*
* @private
* @param {string} input
* @param {RegExp} regex
* @param {boolean} displayTotal
* @returns {string}
*/
_regexHighlight: function(input, regex, displayTotal) {
let output = "",
m,
hl = 1,
i = 0,
total = 0;
while ((m = regex.exec(input))) {
// Moves pointer when an empty string is matched (prevents infinite loop)
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
// Add up to match
output += Utils.escapeHtml(input.slice(i, m.index));
// Add match with highlighting
output += "<span class='hl"+hl+"'>" + Utils.escapeHtml(m[0]) + "</span>";
// Switch highlight
hl = hl === 1 ? 2 : 1;
i = regex.lastIndex;
total++;
}
// Add all after final match
output += Utils.escapeHtml(input.slice(i, input.length));
if (displayTotal)
output = "Total found: " + total + "\n\n" + output;
return output;
},
/**
* Creates a string listing the matches within a string.
*
* @private
* @param {string} input
* @param {RegExp} regex
* @param {boolean} displayTotal
* @param {boolean} matches - Display full match
* @param {boolean} captureGroups - Display each of the capture groups separately
* @returns {string}
*/
_regexList: function(input, regex, displayTotal, matches, captureGroups) {
let output = "",
total = 0,
match;
while ((match = regex.exec(input))) {
// Moves pointer when an empty string is matched (prevents infinite loop)
if (match.index === regex.lastIndex) {
regex.lastIndex++;
}
total++;
if (matches) {
output += match[0] + "\n";
}
if (captureGroups) {
for (let i = 1; i < match.length; i++) {
if (matches) {
output += " Group " + i + ": ";
}
output += match[i] + "\n";
}
}
}
if (displayTotal)
output = "Total found: " + total + "\n\n" + output;
return output.slice(0, -1);
},
};
export default Regex;

View File

@@ -1,4 +1,5 @@
import Utils from "../Utils.js";
import jsesc from "jsesc";
/**
@@ -12,128 +13,6 @@ import Utils from "../Utils.js";
*/
const StrUtils = {
/**
* @constant
* @default
*/
REGEX_PRE_POPULATE: [
{
name: "User defined",
value: ""
},
{
name: "IPv4 address",
value: "(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?"
},
{
name: "IPv6 address",
value: "((?=.*::)(?!.*::.+::)(::)?([\\dA-Fa-f]{1,4}:(:|\\b)|){5}|([\\dA-Fa-f]{1,4}:){6})((([\\dA-Fa-f]{1,4}((?!\\3)::|:\\b|(?![\\dA-Fa-f])))|(?!\\2\\3)){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})"
},
{
name: "Email address",
value: "(\\w[-.\\w]*)@([-\\w]+(?:\\.[-\\w]+)*)\\.([A-Za-z]{2,4})"
},
{
name: "URL",
value: "([A-Za-z]+://)([-\\w]+(?:\\.\\w[-\\w]*)+)(:\\d+)?(/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*)?"
},
{
name: "Domain",
value: "\\b((?=[a-z0-9-]{1,63}\\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}\\b"
},
{
name: "Windows file path",
value: "([A-Za-z]):\\\\((?:[A-Za-z\\d][A-Za-z\\d\\- \\x27_\\(\\)]{0,61}\\\\?)*[A-Za-z\\d][A-Za-z\\d\\- \\x27_\\(\\)]{0,61})(\\.[A-Za-z\\d]{1,6})?"
},
{
name: "UNIX file path",
value: "(?:/[A-Za-z\\d.][A-Za-z\\d\\-.]{0,61})+"
},
{
name: "MAC address",
value: "[A-Fa-f\\d]{2}(?:[:-][A-Fa-f\\d]{2}){5}"
},
{
name: "Date (yyyy-mm-dd)",
value: "((?:19|20)\\d\\d)[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])"
},
{
name: "Date (dd/mm/yyyy)",
value: "(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.]((?:19|20)\\d\\d)"
},
{
name: "Date (mm/dd/yyyy)",
value: "(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.]((?:19|20)\\d\\d)"
},
{
name: "Strings",
value: "[A-Za-z\\d/\\-:.,_$%\\x27\"()<>= !\\[\\]{}@]{4,}"
},
],
/**
* @constant
* @default
*/
REGEX_CASE_INSENSITIVE: true,
/**
* @constant
* @default
*/
REGEX_MULTILINE_MATCHING: true,
/**
* @constant
* @default
*/
OUTPUT_FORMAT: ["Highlight matches", "List matches", "List capture groups", "List matches with capture groups"],
/**
* @constant
* @default
*/
DISPLAY_TOTAL: false,
/**
* Regular expression operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
runRegex: function(input, args) {
let userRegex = args[1],
i = args[2],
m = args[3],
displayTotal = args[4],
outputFormat = args[5],
modifiers = "g";
if (i) modifiers += "i";
if (m) modifiers += "m";
if (userRegex && userRegex !== "^" && userRegex !== "$") {
try {
const regex = new RegExp(userRegex, modifiers);
switch (outputFormat) {
case "Highlight matches":
return StrUtils._regexHighlight(input, regex, displayTotal);
case "List matches":
return Utils.escapeHtml(StrUtils._regexList(input, regex, displayTotal, true, false));
case "List capture groups":
return Utils.escapeHtml(StrUtils._regexList(input, regex, displayTotal, false, true));
case "List matches with capture groups":
return Utils.escapeHtml(StrUtils._regexList(input, regex, displayTotal, true, true));
default:
return "Error: Invalid output format";
}
} catch (err) {
return "Invalid regex. Details: " + err.message;
}
} else {
return Utils.escapeHtml(input);
}
},
/**
* @constant
* @default
@@ -187,68 +66,28 @@ const StrUtils = {
* @constant
* @default
*/
SEARCH_TYPE: ["Regex", "Extended (\\n, \\t, \\x...)", "Simple string"],
SPLIT_DELIM_OPTIONS: [
{name: "Comma", value: ","},
{name: "Space", value: " "},
{name: "Line feed", value: "\\n"},
{name: "CRLF", value: "\\r\\n"},
{name: "Semi-colon", value: ";"},
{name: "Colon", value: ":"},
{name: "Nothing (separate chars)", value: ""}
],
/**
* @constant
* @default
*/
FIND_REPLACE_GLOBAL: true,
/**
* @constant
* @default
*/
FIND_REPLACE_CASE: false,
/**
* @constant
* @default
*/
FIND_REPLACE_MULTILINE: true,
/**
* Find / Replace operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runFindReplace: function(input, args) {
let find = args[0].string,
type = args[0].option,
replace = args[1],
g = args[2],
i = args[3],
m = args[4],
modifiers = "";
if (g) modifiers += "g";
if (i) modifiers += "i";
if (m) modifiers += "m";
if (type === "Regex") {
find = new RegExp(find, modifiers);
return input.replace(find, replace);
}
if (type.indexOf("Extended") === 0) {
find = Utils.parseEscapedChars(find);
}
find = new RegExp(Utils.escapeRegex(find), modifiers);
return input.replace(find, replace);
},
/**
* @constant
* @default
*/
SPLIT_DELIM: ",",
/**
* @constant
* @default
*/
DELIMITER_OPTIONS: ["Line feed", "CRLF", "Space", "Comma", "Semi-colon", "Colon", "Nothing (separate chars)"],
JOIN_DELIM_OPTIONS: [
{name: "Line feed", value: "\\n"},
{name: "CRLF", value: "\\r\\n"},
{name: "Space", value: " "},
{name: "Comma", value: ","},
{name: "Semi-colon", value: ";"},
{name: "Colon", value: ":"},
{name: "Nothing (join chars)", value: ""}
],
/**
* Split operation.
@@ -258,14 +97,20 @@ const StrUtils = {
* @returns {string}
*/
runSplit: function(input, args) {
let splitDelim = args[0] || StrUtils.SPLIT_DELIM,
joinDelim = Utils.charRep[args[1]],
let splitDelim = args[0],
joinDelim = args[1],
sections = input.split(splitDelim);
return sections.join(joinDelim);
},
/**
* @constant
* @default
*/
DELIMITER_OPTIONS: ["Line feed", "CRLF", "Space", "Comma", "Semi-colon", "Colon", "Nothing (separate chars)"],
/**
* Filter operation.
*
@@ -375,35 +220,45 @@ const StrUtils = {
* @constant
* @default
*/
ESCAPE_REPLACEMENTS: [
{"escaped": "\\\\", "unescaped": "\\"}, // Must be first
{"escaped": "\\'", "unescaped": "'"},
{"escaped": "\\\"", "unescaped": "\""},
{"escaped": "\\n", "unescaped": "\n"},
{"escaped": "\\r", "unescaped": "\r"},
{"escaped": "\\t", "unescaped": "\t"},
{"escaped": "\\b", "unescaped": "\b"},
{"escaped": "\\f", "unescaped": "\f"},
],
QUOTE_TYPES: ["Single", "Double", "Backtick"],
/**
* @constant
* @default
*/
ESCAPE_LEVEL: ["Special chars", "Everything", "Minimal"],
/**
* Escape string operation.
*
* @author Vel0x [dalemy@microsoft.com]
* @author n1474335 [n1474335@gmail.com]
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*
* @example
* StrUtils.runUnescape("Don't do that", [])
* StrUtils.runEscape("Don't do that", [])
* > "Don\'t do that"
* StrUtils.runUnescape(`Hello
* StrUtils.runEscape(`Hello
* World`, [])
* > "Hello\nWorld"
*/
runEscape: function(input, args) {
return StrUtils._replaceByKeys(input, "unescaped", "escaped");
const level = args[0],
quotes = args[1],
jsonCompat = args[2],
es6Compat = args[3],
lowercaseHex = !args[4];
return jsesc(input, {
quotes: quotes.toLowerCase(),
es6: es6Compat,
escapeEverything: level === "Everything",
minimal: level === "Minimal",
json: jsonCompat,
lowercaseHex: lowercaseHex,
});
},
@@ -411,6 +266,7 @@ const StrUtils = {
* Unescape string operation.
*
* @author Vel0x [dalemy@microsoft.com]
* @author n1474335 [n1474335@gmail.com]
*
* @param {string} input
* @param {Object[]} args
@@ -424,32 +280,7 @@ const StrUtils = {
* World`
*/
runUnescape: function(input, args) {
return StrUtils._replaceByKeys(input, "escaped", "unescaped");
},
/**
* Replaces all matching tokens in ESCAPE_REPLACEMENTS with the correction. The
* ordering is determined by the patternKey and the replacementKey.
*
* @author Vel0x [dalemy@microsoft.com]
* @author Matt C [matt@artemisbot.uk]
*
* @param {string} input
* @param {string} pattern_key
* @param {string} replacement_key
* @returns {string}
*/
_replaceByKeys: function(input, patternKey, replacementKey) {
let output = input;
// Catch the \\x encoded characters
if (patternKey === "escaped") output = Utils.parseEscapedChars(input);
StrUtils.ESCAPE_REPLACEMENTS.forEach(replacement => {
output = output.split(replacement[patternKey]).join(replacement[replacementKey]);
});
return output;
return Utils.parseEscapedChars(input);
},
@@ -510,80 +341,71 @@ const StrUtils = {
/**
* Adds HTML highlights to matches within a string.
*
* @private
* @param {string} input
* @param {RegExp} regex
* @param {boolean} displayTotal
* @returns {string}
* @constant
* @default
*/
_regexHighlight: function(input, regex, displayTotal) {
let output = "",
m,
hl = 1,
i = 0,
total = 0;
while ((m = regex.exec(input))) {
// Add up to match
output += Utils.escapeHtml(input.slice(i, m.index));
// Add match with highlighting
output += "<span class='hl"+hl+"'>" + Utils.escapeHtml(m[0]) + "</span>";
// Switch highlight
hl = hl === 1 ? 2 : 1;
i = regex.lastIndex;
total++;
}
// Add all after final match
output += Utils.escapeHtml(input.slice(i, input.length));
if (displayTotal)
output = "Total found: " + total + "\n\n" + output;
return output;
},
HAMMING_DELIM: "\\n\\n",
/**
* @constant
* @default
*/
HAMMING_INPUT_TYPE: ["Raw string", "Hex"],
/**
* @constant
* @default
*/
HAMMING_UNIT: ["Byte", "Bit"],
/**
* Creates a string listing the matches within a string.
* Hamming Distance operation.
*
* @author GCHQ Contributor [2]
*
* @private
* @param {string} input
* @param {RegExp} regex
* @param {boolean} displayTotal
* @param {boolean} matches - Display full match
* @param {boolean} captureGroups - Display each of the capture groups separately
* @param {Object[]} args
* @returns {string}
*/
_regexList: function(input, regex, displayTotal, matches, captureGroups) {
let output = "",
total = 0,
match;
runHamming: function(input, args) {
const delim = args[0],
byByte = args[1] === "Byte",
inputType = args[2],
samples = input.split(delim);
while ((match = regex.exec(input))) {
total++;
if (matches) {
output += match[0] + "\n";
}
if (captureGroups) {
for (let i = 1; i < match.length; i++) {
if (matches) {
output += " Group " + i + ": ";
}
output += match[i] + "\n";
if (samples.length !== 2) {
return "Error: You can only calculae the edit distance between 2 strings. Please ensure exactly two inputs are provided, separated by the specified delimiter.";
}
if (samples[0].length !== samples[1].length) {
return "Error: Both inputs must be of the same length.";
}
if (inputType === "Hex") {
samples[0] = Utils.fromHex(samples[0]);
samples[1] = Utils.fromHex(samples[1]);
} else {
samples[0] = Utils.strToByteArray(samples[0]);
samples[1] = Utils.strToByteArray(samples[1]);
}
let dist = 0;
for (let i = 0; i < samples[0].length; i++) {
const lhs = samples[0][i],
rhs = samples[1][i];
if (byByte && lhs !== rhs) {
dist++;
} else if (!byByte) {
let xord = lhs ^ rhs;
while (xord) {
dist++;
xord &= xord - 1;
}
}
}
if (displayTotal)
output = "Total found: " + total + "\n\n" + output;
return output;
return dist.toString();
},
};

View File

@@ -101,32 +101,39 @@ const Tidy = {
/**
* Drop bytes operation.
*
* @param {byteArray} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {byteArray}
* @returns {ArrayBuffer}
*/
runDropBytes: function(input, args) {
let start = args[0],
const start = args[0],
length = args[1],
applyToEachLine = args[2];
if (start < 0 || length < 0)
throw "Error: Invalid value";
if (!applyToEachLine)
return input.slice(0, start).concat(input.slice(start+length, input.length));
if (!applyToEachLine) {
const left = input.slice(0, start),
right = input.slice(start + length, input.byteLength);
let result = new Uint8Array(left.byteLength + right.byteLength);
result.set(new Uint8Array(left), 0);
result.set(new Uint8Array(right), left.byteLength);
return result.buffer;
}
// Split input into lines
const data = new Uint8Array(input);
let lines = [],
line = [],
i;
for (i = 0; i < input.length; i++) {
if (input[i] === 0x0a) {
for (i = 0; i < data.length; i++) {
if (data[i] === 0x0a) {
lines.push(line);
line = [];
} else {
line.push(input[i]);
line.push(data[i]);
}
}
lines.push(line);
@@ -136,7 +143,7 @@ const Tidy = {
output = output.concat(lines[i].slice(0, start).concat(lines[i].slice(start+length, lines[i].length)));
output.push(0x0a);
}
return output.slice(0, output.length-1);
return new Uint8Array(output.slice(0, output.length-1)).buffer;
},
@@ -154,12 +161,12 @@ const Tidy = {
/**
* Take bytes operation.
*
* @param {byteArray} input
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {byteArray}
* @returns {ArrayBuffer}
*/
runTakeBytes: function(input, args) {
let start = args[0],
const start = args[0],
length = args[1],
applyToEachLine = args[2];
@@ -170,16 +177,17 @@ const Tidy = {
return input.slice(start, start+length);
// Split input into lines
const data = new Uint8Array(input);
let lines = [],
line = [];
let i;
line = [],
i;
for (i = 0; i < input.length; i++) {
if (input[i] === 0x0a) {
for (i = 0; i < data.length; i++) {
if (data[i] === 0x0a) {
lines.push(line);
line = [];
} else {
line.push(input[i]);
line.push(data[i]);
}
}
lines.push(line);
@@ -189,7 +197,7 @@ const Tidy = {
output = output.concat(lines[i].slice(start, start+length));
output.push(0x0a);
}
return output.slice(0, output.length-1);
return new Uint8Array(output.slice(0, output.length-1)).buffer;
},

View File

@@ -27,7 +27,7 @@ const Unicode = {
*/
runUnescape: function(input, args) {
let prefix = Unicode._prefixToRegex[args[0]],
regex = new RegExp(prefix+"([a-f\\d]{4,6})", "ig"),
regex = new RegExp(prefix+"([a-f\\d]{4})", "ig"),
output = "",
m,
i = 0;
@@ -50,6 +50,40 @@ const Unicode = {
},
/**
* Escape Unicode Characters operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runEscape: function(input, args) {
const regexWhitelist = /[ -~]/i,
prefix = args[0],
encodeAll = args[1],
padding = args[2],
uppercaseHex = args[3];
let output = "",
character = "";
for (let i = 0; i < input.length; i++) {
character = input[i];
if (!encodeAll && regexWhitelist.test(character)) {
// Its a printable ASCII character so dont escape it.
output += character;
continue;
}
let cp = character.codePointAt(0).toString(16);
if (uppercaseHex) cp = cp.toUpperCase();
output += prefix + cp.padStart(padding, "0");
}
return output;
},
/**
* Lookup table to add prefixes to unicode delimiters so that they can be used in a regex.
*

26
src/core/operations/XKCD.js Executable file
View File

@@ -0,0 +1,26 @@
/**
* XKCD operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*
* @namespace
*/
const XKCD = {
/**
* XKCD Random Number operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
*/
runRandomNumber: function(input, args) {
return 4; // chosen by fair dice roll.
// guaranteed to be random.
},
};
export default XKCD;

View File

@@ -82,6 +82,9 @@ App.prototype.loaded = function() {
// Clear the loading message interval
clearInterval(window.loadingMsgsInt);
// Remove the loading error handler
window.removeEventListener("error", window.loadingErrorHandler);
document.dispatchEvent(this.manager.apploaded);
};
@@ -377,6 +380,7 @@ App.prototype.loadURIParams = function() {
window.location.href.split("#")[1] ||
window.location.hash;
this.uriParams = Utils.parseURIParams(params);
this.autoBakePause = true;
// Read in recipe from URI params
if (this.uriParams.recipe) {
@@ -387,35 +391,29 @@ App.prototype.loadURIParams = function() {
} else if (this.uriParams.op) {
// If there's no recipe, look for single operations
this.manager.recipe.clearRecipe();
try {
this.manager.recipe.addOperation(this.uriParams.op);
} catch (err) {
// If no exact match, search for nearest match and add that
const matchedOps = this.manager.ops.filterOperations(this.uriParams.op, false);
if (matchedOps.length) {
this.manager.recipe.addOperation(matchedOps[0].name);
}
// Populate search with the string
const search = document.getElementById("search");
search.value = this.uriParams.op;
search.dispatchEvent(new Event("search"));
// Search for nearest match and add it
const matchedOps = this.manager.ops.filterOperations(this.uriParams.op, false);
if (matchedOps.length) {
this.manager.recipe.addOperation(matchedOps[0].name);
}
// Populate search with the string
const search = document.getElementById("search");
search.value = this.uriParams.op;
search.dispatchEvent(new Event("search"));
}
// Read in input data from URI params
if (this.uriParams.input) {
this.autoBakePause = true;
try {
const inputData = Utils.fromBase64(this.uriParams.input);
this.setInput(inputData);
} catch (err) {
} finally {
this.autoBakePause = false;
}
} catch (err) {}
}
this.autoBakePause = false;
this.autoBake();
};
@@ -443,6 +441,7 @@ App.prototype.getRecipeConfig = function() {
/**
* Given a recipe configuration, sets the recipe to that configuration.
*
* @fires Manager#statechange
* @param {Object[]} recipeConfig - The recipe configuration
*/
App.prototype.setRecipeConfig = function(recipeConfig) {

View File

@@ -382,10 +382,13 @@ ControlsWaiter.prototype.supportButtonClick = function(e) {
const saveLink = this.generateStateUrl(true, true, null, "https://gchq.github.io/CyberChef/");
if (reportBugInfo) {
reportBugInfo.innerHTML = "* Version: " + PKG_VERSION + "\n" +
"* Compile time: " + COMPILE_TIME + "\n" +
"* User-Agent: \n" + navigator.userAgent + "\n" +
"* [Link to reproduce](" + saveLink + ")\n\n";
reportBugInfo.innerHTML = `* Version: ${PKG_VERSION + (typeof INLINE === "undefined" ? "" : "s")}
* Compile time: ${COMPILE_TIME}
* User-Agent:
${navigator.userAgent}
* [Link to reproduce](${saveLink})
`;
}
};

View File

@@ -110,6 +110,15 @@ HTMLOperation.prototype.highlightSearchString = function(searchStr, namePos, des
}
if (this.description && descPos >= 0) {
// Find HTML tag offsets
const re = /<[^>]+>/g;
let match;
while ((match = re.exec(this.description))) {
// If the search string occurs within an HTML tag, return without highlighting it.
if (descPos >= match.index && descPos <= (match.index + match[0].length))
return;
}
this.description = this.description.slice(0, descPos) + "<b><u>" +
this.description.slice(descPos, descPos + searchStr.length) + "</u></b>" +
this.description.slice(descPos + searchStr.length);

View File

@@ -1,4 +1,5 @@
import LoaderWorker from "worker-loader?inline&fallback=false!./LoaderWorker.js";
import Utils from "../core/Utils.js";
/**
@@ -61,9 +62,14 @@ InputWaiter.prototype.set = function(input) {
if (input instanceof File) {
this.setFile(input);
inputText.value = "";
this.setInputInfo(input.size, null);
} else {
inputText.value = input;
this.closeFile();
window.dispatchEvent(this.manager.statechange);
const lines = input.length < (this.app.options.ioDisplayThreshold * 1024) ?
input.count("\n") + 1 : null;
this.setInputInfo(input.length, lines);
}
};
@@ -81,6 +87,7 @@ InputWaiter.prototype.setFile = function(file) {
fileType = document.getElementById("input-file-type"),
fileLoaded = document.getElementById("input-file-loaded");
this.fileBuffer = new ArrayBuffer();
fileOverlay.style.display = "block";
fileName.textContent = file.name;
fileSize.textContent = file.size.toLocaleString() + " bytes";
@@ -100,21 +107,28 @@ InputWaiter.prototype.setInputInfo = function(length, lines) {
width = width < 2 ? 2 : width;
const lengthStr = length.toString().padStart(width, " ").replace(/ /g, "&nbsp;");
const linesStr = lines.toString().padStart(width, " ").replace(/ /g, "&nbsp;");
let msg = "length: " + lengthStr;
document.getElementById("input-info").innerHTML = "length: " + lengthStr + "<br>lines: " + linesStr;
if (typeof lines === "number") {
const linesStr = lines.toString().padStart(width, " ").replace(/ /g, "&nbsp;");
msg += "<br>lines: " + linesStr;
}
document.getElementById("input-info").innerHTML = msg;
};
/**
* Handler for input scroll events.
* Scrolls the highlighter pane to match the input textarea position and updates history state.
* Handler for input change events.
*
* @param {event} e
*
* @fires Manager#statechange
*/
InputWaiter.prototype.inputChange = function(e) {
// Ignore this function if the input is a File
if (this.fileBuffer) return;
// Remove highlighting from input and output panes as the offsets might be different now
this.manager.highlighter.removeHighlights();
@@ -123,18 +137,47 @@ InputWaiter.prototype.inputChange = function(e) {
// Update the input metadata info
const inputText = this.get();
const lines = inputText.count("\n") + 1;
const lines = inputText.length < (this.app.options.ioDisplayThreshold * 1024) ?
inputText.count("\n") + 1 : null;
this.setInputInfo(inputText.length, lines);
if (this.badKeys.indexOf(e.keyCode) < 0) {
if (e && this.badKeys.indexOf(e.keyCode) < 0) {
// Fire the statechange event as the input has been modified
window.dispatchEvent(this.manager.statechange);
}
};
/**
* Handler for input paste events.
* Checks that the size of the input is below the display limit, otherwise treats it as a file/blob.
*
* @param {event} e
*/
InputWaiter.prototype.inputPaste = function(e) {
const pastedData = e.clipboardData.getData("Text");
if (pastedData.length < (this.app.options.ioDisplayThreshold * 1024)) {
this.inputChange(e);
} else {
e.preventDefault();
e.stopPropagation();
const file = new File([pastedData], "PastedData", {
type: "text/plain",
lastModified: Date.now()
});
this.loaderWorker = new LoaderWorker();
this.loaderWorker.addEventListener("message", this.handleLoaderMessage.bind(this));
this.loaderWorker.postMessage({"file": file});
this.set(file);
return false;
}
};
/**
* Handler for input dragover events.
* Gives the user a visual cue to show that items can be dropped here.
@@ -214,14 +257,35 @@ InputWaiter.prototype.handleLoaderMessage = function(e) {
fileLoaded.textContent = r.progress + "%";
}
if (r.hasOwnProperty("error")) {
this.app.alert(r.error, "danger", 10000);
}
if (r.hasOwnProperty("fileBuffer")) {
log.debug("Input file loaded");
this.fileBuffer = r.fileBuffer;
this.displayFilePreview();
window.dispatchEvent(this.manager.statechange);
}
};
/**
* Shows a chunk of the file in the input behind the file overlay.
*/
InputWaiter.prototype.displayFilePreview = function() {
const inputText = document.getElementById("input-text"),
fileSlice = this.fileBuffer.slice(0, 4096);
inputText.style.overflow = "hidden";
inputText.classList.add("blur");
inputText.value = Utils.printable(Utils.arrayBufferToStr(fileSlice));
if (this.fileBuffer.byteLength > 4096) {
inputText.value += "[truncated]...";
}
};
/**
* Handler for file close events.
*/
@@ -229,6 +293,9 @@ InputWaiter.prototype.closeFile = function() {
if (this.loaderWorker) this.loaderWorker.terminate();
this.fileBuffer = null;
document.getElementById("input-file").style.display = "none";
const inputText = document.getElementById("input-text");
inputText.style.overflow = "auto";
inputText.classList.remove("blur");
};

View File

@@ -20,7 +20,7 @@ self.addEventListener("message", function(e) {
/**
* Loads a file object into an ArrayBuffer, then transfers it back to the parent thread.
*
*
* @param {File} file
*/
self.loadFile = function(file) {
@@ -46,5 +46,9 @@ self.loadFile = function(file) {
seek();
};
reader.onerror = function(e) {
self.postMessage({"error": reader.error.message});
};
seek();
};

View File

@@ -132,7 +132,8 @@ Manager.prototype.initialiseEventListeners = function() {
this.addDynamicListener("#rec-list", "operationremove", this.recipe.opRemove.bind(this.recipe));
// Input
this.addMultiEventListener("#input-text", "keyup paste", this.input.inputChange, this.input);
this.addMultiEventListener("#input-text", "keyup", this.input.inputChange, this.input);
this.addMultiEventListener("#input-text", "paste", this.input.inputPaste, this.input);
document.getElementById("reset-layout").addEventListener("click", this.app.resetLayout.bind(this.app));
document.getElementById("clr-io").addEventListener("click", this.input.clearIoClick.bind(this.input));
this.addListeners("#input-text,#input-file", "dragover", this.input.inputDragover, this.input);

View File

@@ -167,7 +167,8 @@ OperationsWaiter.prototype.opListCreate = function(e) {
OperationsWaiter.prototype.enableOpsListPopovers = function(el) {
$(el).find("[data-toggle=popover]").addBack("[data-toggle=popover]")
.popover({trigger: "manual"})
.on("mouseenter", function() {
.on("mouseenter", function(e) {
if (e.buttons > 0) return; // Mouse button held down - likely dragging an opertion
const _this = this;
$(this).popover("show");
$(".popover").on("mouseleave", function () {
@@ -178,7 +179,7 @@ OperationsWaiter.prototype.enableOpsListPopovers = function(el) {
setTimeout(function() {
// Determine if the popover associated with this element is being hovered over
if ($(_this).data("bs.popover") &&
!$(_this).data("bs.popover").$tip.is(":hover")) {
($(_this).data("bs.popover").$tip && !$(_this).data("bs.popover").$tip.is(":hover"))) {
$(_this).popover("hide");
}
}, 50);

View File

@@ -154,7 +154,7 @@ OptionsWaiter.prototype.setWordWrap = function() {
/**
* Changes the theme by setting the class of the <html> element.
*
*
* @param {Event} e
*/
OptionsWaiter.prototype.themeChange = function (e) {
@@ -166,7 +166,7 @@ OptionsWaiter.prototype.themeChange = function (e) {
/**
* Changes the console logging level.
*
*
* @param {Event} e
*/
OptionsWaiter.prototype.logLevelChange = function (e) {

View File

@@ -64,7 +64,7 @@ OutputWaiter.prototype.set = function(data, type, duration, preserveBuffer) {
outputText.value = "";
outputHtml.innerHTML = data;
this.dishStr = Utils.stripHtmlTags(data, true);
this.dishStr = Utils.unescapeHtml(Utils.stripHtmlTags(data, true));
length = data.length;
lines = this.dishStr.count("\n") + 1;
@@ -128,6 +128,13 @@ OutputWaiter.prototype.setFile = function(buf) {
fileOverlay.style.display = "block";
fileSize.textContent = file.size.toLocaleString() + " bytes";
// Display preview slice in the background
const outputText = document.getElementById("output-text"),
fileSlice = this.dishBuffer.slice(0, 4096);
outputText.classList.add("blur");
outputText.value = Utils.printable(Utils.arrayBufferToStr(fileSlice));
};
@@ -137,6 +144,7 @@ OutputWaiter.prototype.setFile = function(buf) {
OutputWaiter.prototype.closeFile = function() {
this.dishBuffer = null;
document.getElementById("output-file").style.display = "none";
document.getElementById("output-text").classList.remove("blur");
};
@@ -163,6 +171,7 @@ OutputWaiter.prototype.displayFileSlice = function() {
sliceTo = parseInt(sliceToEl.value, 10),
str = Utils.arrayBufferToStr(this.dishBuffer.slice(sliceFrom, sliceTo));
document.getElementById("output-text").classList.remove("blur");
showFileOverlay.style.display = "block";
this.set(str, "string", new Date().getTime() - startTime, true);
};
@@ -170,13 +179,14 @@ OutputWaiter.prototype.displayFileSlice = function() {
/**
* Handler for show file overlay events.
*
*
* @param {Event} e
*/
OutputWaiter.prototype.showFileOverlayClick = function(e) {
const outputFile = document.getElementById("output-file"),
showFileOverlay = e.target;
document.getElementById("output-text").classList.add("blur");
outputFile.style.display = "block";
showFileOverlay.style.display = "none";
this.setOutputInfo(this.dishBuffer.byteLength, null, 0);

View File

@@ -42,7 +42,7 @@
}
// Define loading messages
const loadingMsgs = [
var loadingMsgs = [
"Proving P = NP...",
"Computing 6 x 9...",
"Mining bitcoin...",
@@ -59,22 +59,25 @@
"for i in range(additional): Pylon()",
"(creating unresolved tension...",
"Symlinking emacs and vim to ed...",
"Training branch predictor...",
"Timing cache hits...",
"Speculatively executing recipes..."
];
// Shuffle array using Durstenfeld algorithm
for (let i = loadingMsgs.length - 1; i > 0; --i) {
const j = Math.floor(Math.random() * (i + 1));
const temp = loadingMsgs[i];
var j = Math.floor(Math.random() * (i + 1));
var temp = loadingMsgs[i];
loadingMsgs[i] = loadingMsgs[j];
loadingMsgs[j] = temp;
}
// Show next loading message and move it to the end of the array
function changeLoadingMsg() {
const msg = loadingMsgs.shift();
var msg = loadingMsgs.shift();
loadingMsgs.push(msg);
try {
const el = document.getElementById("preloader-msg");
var el = document.getElementById("preloader-msg");
if (!el.classList.contains("loading"))
el.classList.add("loading"); // Causes CSS transition on first message
el.innerHTML = msg;
@@ -83,8 +86,50 @@
changeLoadingMsg();
window.loadingMsgsInt = setInterval(changeLoadingMsg, (Math.random() * 2000) + 1500);
// If any errors are thrown during loading, handle them here
function loadingErrorHandler(e) {
function escapeHtml(str) {
var HTML_CHARS = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': "&quot;",
"'": "&#x27;", // &apos; not recommended because it's not in the HTML spec
"/": "&#x2F;", // forward slash is included as it helps end an HTML entity
"`": "&#x60;"
};
return str.replace(/[&<>"'/`]/g, function (match) {
return HTML_CHARS[match];
});
}
var msg = e.message +
(e.filename ? "\nFilename: " + e.filename : "") +
(e.lineno ? "\nLine: " + e.lineno : "") +
(e.colno ? "\nColumn: " + e.colno : "") +
(e.error ? "\nError: " + e.error : "") +
"\nUser-Agent: " + navigator.userAgent +
"\nCyberChef version: <%= htmlWebpackPlugin.options.version %>";
clearInterval(window.loadingMsgsInt);
document.getElementById("preloader").remove();
document.getElementById("preloader-msg").remove();
document.getElementById("preloader-error").innerHTML =
"CyberChef encountered an error while loading.<br><br>" +
"The following browser versions are supported:" +
"<ul><li>Google Chrome 40+</li><li>Mozilla Firefox 35+</li><li>Microsoft Edge 14+</li></ul>" +
"Your user agent is:<br>" + escapeHtml(navigator.userAgent) + "<br><br>" +
"If your browser is supported, please <a href='https://github.com/gchq/CyberChef/issues/new'>" +
"raise an issue</a> including the following details:<br><br>" +
"<pre>" + escapeHtml(msg) + "</pre>";
};
window.addEventListener("error", loadingErrorHandler);
</script>
<% if (!htmlWebpackPlugin.options.inline) { %>
<% if (htmlWebpackPlugin.options.inline) { %>
<meta name="robots" content="noindex" />
<% } else { %>
<script type="application/ld+json">
<% print(JSON.stringify(require("../static/structuredData.json"))); %>
</script>
@@ -95,6 +140,7 @@
<div id="loader-wrapper">
<div id="preloader" class="loader"></div>
<div id="preloader-msg" class="loading-msg"></div>
<div id="preloader-error" class="loading-error"></div>
</div>
<!-- End preloader overlay -->
<span id="edit-favourites" class="btn btn-default btn-sm"><img aria-hidden="true" src="<%- require('../static/images/favourite-16x16.png') %>" alt="Star Icon"/> Edit</span>
@@ -115,7 +161,7 @@
<span id="notice">
<script type="text/javascript">
// Must be text/javascript rather than application/javascript otherwise IE won't recognise it...
if (navigator.userAgent && navigator.userAgent.match(/MSIE \d\d?\./)) {
if (navigator.userAgent && navigator.userAgent.match(/Trident/)) {
document.write("Internet Explorer is not supported, please use Firefox or Chrome instead");
alert("Internet Explorer is not supported, please use Firefox or Chrome instead");
}
@@ -180,8 +226,9 @@
</div>
<div class="textarea-wrapper no-select">
<div id="input-highlighter" class="no-select"></div>
<textarea id="input-text"></textarea>
<textarea id="input-text" spellcheck="false"></textarea>
<div id="input-file">
<div class="file-overlay"></div>
<div style="position: relative; height: 100%;">
<div class="card">
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png') %>" alt="File icon"/>
@@ -215,9 +262,10 @@
<div class="textarea-wrapper">
<div id="output-highlighter" class="no-select"></div>
<div id="output-html"></div>
<textarea id="output-text" readonly="readonly"></textarea>
<textarea id="output-text" readonly="readonly" spellcheck="false"></textarea>
<img id="show-file-overlay" aria-hidden="true" src="<%- require('../static/images/file-32x32.png') %>" alt="Show file overlay" title="Show file overlay"/>
<div id="output-file">
<div class="file-overlay"></div>
<div style="position: relative; height: 100%;">
<div class="card">
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png') %>" alt="File icon"/>
@@ -230,7 +278,7 @@
</span>
<input type="number" class="form-control" id="output-file-slice-from" placeholder="From" value="0" step="1024" min="0">
<div class="input-group-addon">to</div>
<input type="number" class="form-control" id="output-file-slice-to" placeholder="To" value="1024" step="1024" min="0">
<input type="number" class="form-control" id="output-file-slice-to" placeholder="To" value="2048" step="1024" min="0">
</div>
</div>
</div>
@@ -369,8 +417,8 @@
<label for="errorTimeout"> Operation error timeout in ms (0 for never)</label>
</div>
<div class="option-item">
<input type="number" option="outputFileThreshold" id="outputFileThreshold" />
<label for="outputFileThreshold"> Size threshold for treating the output as a file (KiB)</label>
<input type="number" option="ioDisplayThreshold" id="ioDisplayThreshold" />
<label for="ioDisplayThreshold"> Size threshold for treating the input and output as a file (KiB)</label>
</div>
<div class="option-item">
<select option="logLevel" id="logLevel">

View File

@@ -12,6 +12,7 @@ import "babel-polyfill";
import "bootstrap";
import "bootstrap-switch";
import "bootstrap-colorpicker";
import moment from "moment-timezone";
import CanvasComponents from "../core/lib/canvascomponents.js";
// CyberChef
@@ -47,7 +48,7 @@ function main() {
attemptHighlight: true,
theme: "classic",
useMetaKey: false,
outputFileThreshold: 1024,
ioDisplayThreshold: 512,
logLevel: "info"
};
@@ -63,3 +64,4 @@ window.compileMessage = COMPILE_MSG;
window.CanvasComponents = CanvasComponents;
document.addEventListener("DOMContentLoaded", main, false);

33
src/web/static/sitemap.js Normal file
View File

@@ -0,0 +1,33 @@
import sm from "sitemap";
import OperationConfig from "../../core/config/MetaConfig.js";
/**
* Generates an XML sitemap for all CyberChef operations and a number of recipes.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
const sitemap = sm.createSitemap({
hostname: "https://gchq.github.io/CyberChef",
});
sitemap.add({
url: "/",
changefreq: "weekly",
priority: 1.0
});
for (let op in OperationConfig) {
sitemap.add({
url: `/?op=${encodeURIComponent(op)}`,
changeFreq: "yearly",
priority: 0.5
});
}
const xml = sitemap.toString();
console.log(xml); // eslint-disable-line no-console

View File

@@ -7,7 +7,7 @@
*/
/* Libraries */
import "google-code-prettify/src/prettify.css";
import "highlight.js/styles/vs.css";
/* Frameworks */
import "./vendors/bootstrap.less";

View File

@@ -84,10 +84,17 @@
top: 0;
width: 100%;
height: 100%;
background-color: var(--title-background-colour);
display: none;
}
.file-overlay {
position: absolute;
opacity: 0.8;
background-color: var(--title-background-colour);
width: 100%;
height: 100%;
}
#show-file-overlay {
position: absolute;
right: 15px;

View File

@@ -74,6 +74,14 @@
transition: all 0.1s ease-in;
}
.loading-error {
display: block;
position: relative;
width: 600px;
left: calc(50% - 300px);
top: 10%;
}
/* Loaded */
.loaded .loading-msg {

View File

@@ -14,22 +14,27 @@ import "babel-polyfill";
import TestRegister from "./TestRegister.js";
import "./tests/operations/Base58.js";
import "./tests/operations/Base64.js";
import "./tests/operations/BCD.js";
import "./tests/operations/BitwiseOp.js";
import "./tests/operations/BSON.js";
import "./tests/operations/ByteRepr.js";
import "./tests/operations/CharEnc.js";
import "./tests/operations/Checksum.js";
import "./tests/operations/Cipher.js";
import "./tests/operations/Code.js";
import "./tests/operations/Compress.js";
import "./tests/operations/DateTime.js";
import "./tests/operations/FlowControl.js";
import "./tests/operations/Hash.js";
import "./tests/operations/Hexdump.js";
import "./tests/operations/Image.js";
import "./tests/operations/MorseCode.js";
import "./tests/operations/MS.js";
import "./tests/operations/PHP.js";
import "./tests/operations/NetBIOS.js";
import "./tests/operations/OTP.js";
import "./tests/operations/Regex.js";
import "./tests/operations/StrUtils.js";
import "./tests/operations/SeqUtils.js";

56
test/tests/operations/BSON.js Executable file
View File

@@ -0,0 +1,56 @@
/**
* BSON tests.
*
* @author n1474335 [n1474335@gmail.com]
*
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import TestRegister from "../../TestRegister.js";
TestRegister.addTests([
{
name: "BSON serialise: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "BSON serialise",
args: [],
},
],
},
{
name: "BSON serialise: basic",
input: "{\"hello\":\"world\"}",
expectedOutput: "\x16\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x00",
recipeConfig: [
{
op: "BSON serialise",
args: [],
},
],
},
{
name: "BSON deserialise: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "BSON deserialise",
args: [],
},
],
},
{
name: "BSON deserialise: basic",
input: "\x16\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x00",
expectedOutput: "{\n \"hello\": \"world\"\n}",
recipeConfig: [
{
op: "BSON deserialise",
args: [],
},
],
},
]);

View File

@@ -0,0 +1,119 @@
/**
* Base64 tests.
*
* @author n1474335 [n1474335@gmail.com]
*
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import TestRegister from "../../TestRegister.js";
const ALL_BYTES = [
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f",
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f",
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f",
"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f",
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f",
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf",
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf",
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
].join("");
TestRegister.addTests([
{
name: "To Base64: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "To Base64",
args: ["A-Za-z0-9+/="],
},
],
},
{
name: "To Base64: Hello, World!",
input: "Hello, World!",
expectedOutput: "SGVsbG8sIFdvcmxkIQ==",
recipeConfig: [
{
op: "To Base64",
args: ["A-Za-z0-9+/="],
},
],
},
{
name: "To Base64: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "4YOc4YOjIOGDnuGDkOGDnOGDmOGDmeGDkOGDoQ==",
recipeConfig: [
{
op: "To Base64",
args: ["A-Za-z0-9+/="],
},
],
},
{
name: "To Base64: All bytes",
input: ALL_BYTES,
expectedOutput: "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==",
recipeConfig: [
{
op: "To Base64",
args: ["A-Za-z0-9+/="],
},
],
},
{
name: "From Base64: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "From Base64",
args: ["A-Za-z0-9+/=", true],
},
],
},
{
name: "From Base64: Hello, World!",
input: "SGVsbG8sIFdvcmxkIQ==",
expectedOutput: "Hello, World!",
recipeConfig: [
{
op: "From Base64",
args: ["A-Za-z0-9+/=", true],
},
],
},
{
name: "From Base64: UTF-8",
input: "4YOc4YOjIOGDnuGDkOGDnOGDmOGDmeGDkOGDoQ==",
expectedOutput: "ნუ პანიკას",
recipeConfig: [
{
op: "From Base64",
args: ["A-Za-z0-9+/=", true],
},
],
},
{
name: "From Base64: All bytes",
input: "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==",
expectedOutput: ALL_BYTES,
recipeConfig: [
{
op: "From Base64",
args: ["A-Za-z0-9+/=", true],
},
],
},
]);

151
test/tests/operations/ByteRepr.js Normal file → Executable file
View File

@@ -7,6 +7,25 @@
*/
import TestRegister from "../../TestRegister.js";
const ALL_BYTES = [
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f",
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f",
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f",
"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f",
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f",
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf",
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf",
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
].join("");
TestRegister.addTests([
{
name: "To Octal: nothing",
@@ -74,4 +93,136 @@ TestRegister.addTests([
}
]
},
{
name: "To Hex: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "To Hex",
args: ["Space"]
},
]
},
{
name: "To Hex: All bytes",
input: ALL_BYTES,
expectedOutput: "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff",
recipeConfig: [
{
op: "To Hex",
args: ["Space"]
},
]
},
{
name: "To Hex: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "e1839ce183a320e1839ee18390e1839ce18398e18399e18390e183a1",
recipeConfig: [
{
op: "To Hex",
args: ["None"]
},
]
},
{
name: "From Hex: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "From Hex",
args: ["Space"]
}
]
},
{
name: "From Hex: All bytes",
input: "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff",
expectedOutput: ALL_BYTES,
recipeConfig: [
{
op: "From Hex",
args: ["Space"]
}
]
},
{
name: "From Hex: UTF-8",
input: "e1839ce183a320e1839ee18390e1839ce18398e18399e18390e183a1",
expectedOutput: "ნუ პანიკას",
recipeConfig: [
{
op: "From Hex",
args: ["None"]
}
]
},
{
name: "To Charcode: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "To Charcode",
args: ["Space", 16]
},
]
},
{
name: "To Charcode: All bytes",
input: ALL_BYTES,
expectedOutput: "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff",
recipeConfig: [
{
op: "To Charcode",
args: ["Space", 16]
},
]
},
{
name: "To Charcode: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "10dc 10e3 20 10de 10d0 10dc 10d8 10d9 10d0 10e1",
recipeConfig: [
{
op: "To Charcode",
args: ["Space", 16]
},
]
},
{
name: "From Charcode: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "From Charcode",
args: ["Space", 16]
}
]
},
{
name: "From Charcode: All bytes",
input: "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff",
expectedOutput: ALL_BYTES,
recipeConfig: [
{
op: "From Charcode",
args: ["Space", 16]
}
]
},
{
name: "From Charcode: UTF-8",
input: "10dc 10e3 20 10de 10d0 10dc 10d8 10d9 10d0 10e1",
expectedOutput: "ნუ პანიკას",
recipeConfig: [
{
op: "From Charcode",
args: ["Space", 16]
}
]
},
]);

View File

@@ -0,0 +1,120 @@
/**
* Checksum tests.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import TestRegister from "../../TestRegister.js";
const BASIC_STRING = "The ships hung in the sky in much the same way that bricks don't.";
const UTF8_STR = "ნუ პანიკას";
const ALL_BYTES = [
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f",
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f",
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f",
"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f",
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f",
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf",
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf",
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
].join("");
TestRegister.addTests([
{
name: "CRC-16: nothing",
input: "",
expectedOutput: "0000",
recipeConfig: [
{
"op": "CRC-16 Checksum",
"args": []
}
]
},
{
name: "CRC-16: basic string",
input: BASIC_STRING,
expectedOutput: "0c70",
recipeConfig: [
{
"op": "CRC-16 Checksum",
"args": []
}
]
},
{
name: "CRC-16: UTF-8",
input: UTF8_STR,
expectedOutput: "dcf6",
recipeConfig: [
{
"op": "CRC-16 Checksum",
"args": []
}
]
},
{
name: "CRC-16: all bytes",
input: ALL_BYTES,
expectedOutput: "bad3",
recipeConfig: [
{
"op": "CRC-16 Checksum",
"args": []
}
]
},
{
name: "CRC-32: nothing",
input: "",
expectedOutput: "00000000",
recipeConfig: [
{
"op": "CRC-32 Checksum",
"args": []
}
]
},
{
name: "CRC-32: basic string",
input: BASIC_STRING,
expectedOutput: "bf4b739c",
recipeConfig: [
{
"op": "CRC-32 Checksum",
"args": []
}
]
},
{
name: "CRC-32: UTF-8",
input: UTF8_STR,
expectedOutput: "87553290",
recipeConfig: [
{
"op": "CRC-32 Checksum",
"args": []
}
]
},
{
name: "CRC-32: all bytes",
input: ALL_BYTES,
expectedOutput: "29058c73",
recipeConfig: [
{
"op": "CRC-32 Checksum",
"args": []
}
]
},
]);

View File

@@ -79,13 +79,13 @@ TestRegister.addTests([
/**
* Ciphers
*
*
* The following expectedOutputs were generated using the following command format:
* > openssl enc -aes-128-cbc -in test.txt -out test.enc -K "00112233445566778899aabbccddeeff" -iv "00112233445566778899aabbccddeeff"
* > xxd -p test.enc | tr -d '\n' | xclip -selection clipboard
*
*
* All random data blocks (binary input, keys and IVs) were generated from /dev/urandom using dd:
* > dd if=/dev/urandom of=key.txt bs=16 count=1
* > dd if=/dev/urandom of=key.txt bs=16 count=1
*/
{
name: "AES Encrypt: no key",

106
test/tests/operations/FlowControl.js Normal file → Executable file
View File

@@ -8,6 +8,25 @@
*/
import TestRegister from "../../TestRegister.js";
const ALL_BYTES = [
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f",
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f",
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f",
"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f",
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f",
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf",
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf",
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
].join("");
TestRegister.addTests([
{
name: "Fork: nothing",
@@ -37,7 +56,7 @@ TestRegister.addTests([
},
{
name: "Fork, (expect) Error, Merge",
input: "1\n2\na\n4",
input: "1.1\n2.5\na\n3.4",
expectedError: true,
recipeConfig: [
{
@@ -45,8 +64,8 @@ TestRegister.addTests([
args: ["\n", "\n", false],
},
{
op: "To Base",
args: [16],
op: "Object Identifier to Hex",
args: [],
},
{
op: "Merge",
@@ -251,7 +270,7 @@ TestRegister.addTests([
],
},
{
name: "Conditional Jump: Skips negatively",
name: "Conditional Jump: Skips backwards",
input: [
"match",
].join("\n"),
@@ -290,4 +309,83 @@ TestRegister.addTests([
},
],
},
{
name: "Register: RC4 key",
input: "http://malwarez.biz/beacon.php?key=0e932a5c&data=8db7d5ebe38663a54ecbb334e3db11",
expectedOutput: "All the secrets",
recipeConfig: [
{
op: "Register",
args: ["key=([\\da-f]*)", true, false]
},
{
op: "Find / Replace",
args: [
{
"option": "Regex",
"string": ".*data=(.*)"
}, "$1", true, false, true
]
},
{
op: "RC4",
args: [
{
"option": "Hex",
"string": "$R0"
}, "Hex", "Latin1"
]
}
]
},
{
name: "Register: AES key",
input: "51e201d463698ef5f717f71f5b4712af20be674b3bff53d38546396ee61daac4908e319ca3fcf7089bfb6b38ea99e781d26e577ba9dd6f311a39420b8978e93014b042d44726caedf5436eaf652429c0df94b521676c7c2ce812097c277273c7c72cd89aec8d9fb4a27586ccf6aa0aee224c34ba3bfdf7aeb1ddd477622b91e72c9e709ab60f8daf731ec0cc85ce0f746ff1554a5a3ec291ca40f9e629a872592d988fdd834534aba79c1ad1676769a7c010bf04739ecdb65d95302371d629d9e37e7b4a361da468f1ed5358922d2ea752dd11c366f3017b14aa011d2af03c44f95579098a15e3cf9b4486f8ffe9c239f34de7151f6ca6500fe4b850c3f1c02e801caf3a24464614e42801615b8ffaa07ac8251493ffda7de5ddf3368880c2b95b030f41f8f15066add071a66cf60e5f46f3a230d397b652963a21a53f",
expectedOutput: `"You know," said Arthur, "it's at times like this, when I'm trapped in a Vogon airlock with a man from Betelgeuse, and about to die of asphyxiation in deep space that I really wish I'd listened to what my mother told me when I was young."
"Why, what did she tell you?"
"I don't know, I didn't listen."`,
recipeConfig: [
{
op: "Register",
args: ["(.{32})", true, false]
},
{
op: "Drop bytes",
args: [0, 32, false]
},
{
op: "AES Decrypt",
args: [
{
"option": "Hex",
"string": "1748e7179bd56570d51fa4ba287cc3e5"
},
{
"option": "Hex",
"string": "$R0"
},
"CTR", "Hex", "Raw",
{
"option": "Hex",
"string": ""
}
]
}
]
},
{
name: "Label, Comment: Complex content",
input: ALL_BYTES,
expectedOutput: ALL_BYTES,
recipeConfig: [
{
op: "Label",
args: [""]
},
{
op: "Comment",
args: [""]
}
]
},
]);

339
test/tests/operations/Hash.js Normal file → Executable file
View File

@@ -415,4 +415,343 @@ TestRegister.addTests([
}
]
},
{
name: "MD5: Complex bytes",
input: "10dc10e32010de10d010dc10d810d910d010e12e",
expectedOutput: "4f4f02e2646545aa8fc42f613c9aa068",
recipeConfig: [
{
"op": "From Hex",
"args": ["None"]
},
{
"op": "MD5",
"args": []
}
]
},
{
name: "SHA1: Complex bytes",
input: "10dc10e32010de10d010dc10d810d910d010e12e",
expectedOutput: "2c5400aaee7e8ad4cad29bfbdf8d566924e5442c",
recipeConfig: [
{
"op": "From Hex",
"args": ["None"]
},
{
"op": "SHA1",
"args": []
}
]
},
{
name: "SHA2 224: Complex bytes",
input: "10dc10e32010de10d010dc10d810d910d010e12e",
expectedOutput: "66c166eba2529ecc44a7b7b218a64a8e3892f873c8d231e8e3c1ef3d",
recipeConfig: [
{
"op": "From Hex",
"args": ["None"]
},
{
"op": "SHA2",
"args": ["224"]
}
]
},
{
name: "SHA2 256: Complex bytes",
input: "10dc10e32010de10d010dc10d810d910d010e12e",
expectedOutput: "186ffd22c3af83995afa4a0316023f81a7f8834fd16bd2ed358c7b1b8182ba41",
recipeConfig: [
{
"op": "From Hex",
"args": ["None"]
},
{
"op": "SHA2",
"args": ["256"]
}
]
},
{
name: "SHA2 384: Complex bytes",
input: "10dc10e32010de10d010dc10d810d910d010e12e",
expectedOutput: "2a6369ffec550ea0bfb810b3b8246b7d6b7f060edfae88441f0f242b98b91549aa4ff407de38c6d03b5f377434ad2f36",
recipeConfig: [
{
"op": "From Hex",
"args": ["None"]
},
{
"op": "SHA2",
"args": ["384"]
}
]
},
{
name: "SHA2 512: Complex bytes",
input: "10dc10e32010de10d010dc10d810d910d010e12e",
expectedOutput: "544ae686522c05b70d12b460b5b39ea0a758eb4027333edbded7e2b3f467aa605804f71f54db61a7bbe50e6e7898510635efd6721fd418a9ea4d05b286d12806",
recipeConfig: [
{
"op": "From Hex",
"args": ["None"]
},
{
"op": "SHA2",
"args": ["512"]
}
]
},
{
name: "SHA3 224: Complex bytes",
input: "10dc10e32010de10d010dc10d810d910d010e12e",
expectedOutput: "e2c07562ee8c2d73e3dd309efea257159abd0948ebc14619bab9ffb3",
recipeConfig: [
{
"op": "From Hex",
"args": ["None"]
},
{
"op": "SHA3",
"args": ["224"]
}
]
},
{
name: "SHA3 256: Complex bytes",
input: "10dc10e32010de10d010dc10d810d910d010e12e",
expectedOutput: "55a55275387586afd1ed64757c9ee7ad1d96ca81a5b7b742c40127856ee78a2d",
recipeConfig: [
{
"op": "From Hex",
"args": ["None"]
},
{
"op": "SHA3",
"args": ["256"]
}
]
},
{
name: "SHA3 384: Complex bytes",
input: "10dc10e32010de10d010dc10d810d910d010e12e",
expectedOutput: "39f8796dd697dc39e5a943817833793f2c29dc0d1adc7037854c0fb51e135c6bd26b113240c4fb1e3fcc16ff8690c91a",
recipeConfig: [
{
"op": "From Hex",
"args": ["None"]
},
{
"op": "SHA3",
"args": ["384"]
}
]
},
{
name: "SHA3 512: Complex bytes",
input: "10dc10e32010de10d010dc10d810d910d010e12e",
expectedOutput: "ee9061bed83b1ad1e2fc4a4bac72a5a65a23a0fa55193b808af0a3e2013b718a5a3e40474765b4f93d1b2747401058a5b58099cc890a159db92b2ea816287add",
recipeConfig: [
{
"op": "From Hex",
"args": ["None"]
},
{
"op": "SHA3",
"args": ["512"]
}
]
},
{
name: "MD5: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "2e93ee2b5b2a337ccb678c7db12eff1b",
recipeConfig: [
{
"op": "MD5",
"args": []
}
]
},
{
name: "SHA1: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "87f483b1515dce672be044bf183ae8103e3b2d4b",
recipeConfig: [
{
"op": "SHA1",
"args": []
}
]
},
{
name: "SHA2 224: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "563ca57b500157717961a5fa87ce42c6db76a488c98ea9c28d620770",
recipeConfig: [
{
"op": "SHA2",
"args": ["224"]
}
]
},
{
name: "SHA2 256: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "36abbb4622ffff06aa3e3cea266765601b21457bb3755a0a2cf0a206422863c1",
recipeConfig: [
{
"op": "SHA2",
"args": ["256"]
}
]
},
{
name: "SHA2 384: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "140b929391a66c9a943bcd60e6964f0d19526d3bc9ba020fbb29aae51cddb8e63a78784d8770f1d36335bf4efff8c131",
recipeConfig: [
{
"op": "SHA2",
"args": ["384"]
}
]
},
{
name: "SHA2 512: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "04a7887c400bf647b7c67b9a0f1ada70d176348b5afdfebea184f7e62748849828669c7b5160be99455fdbf625589bd1689c003bc06ef60c39607d825a2f8838",
recipeConfig: [
{
"op": "SHA2",
"args": ["512"]
}
]
},
{
name: "SHA3 224: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "b3ffc9620949f879cb561fb240452494e2566cb4e4f701a85715e14f",
recipeConfig: [
{
"op": "SHA3",
"args": ["224"]
}
]
},
{
name: "SHA3 256: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "b5f247d725b46546c832502cd07bccb5d4de0c41a6665d3944ed2cc55cd9d156",
recipeConfig: [
{
"op": "SHA3",
"args": ["256"]
}
]
},
{
name: "SHA3 384: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "93e87b9aa8c9c47eba146adac357c525b418b71677f6db01d1c760d87b058682e639c8d43a8bfe91529cecd9800700e3",
recipeConfig: [
{
"op": "SHA3",
"args": ["384"]
}
]
},
{
name: "SHA3 512: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "1fbc484b5184982561795162757717474eebc846ca9f10029a75a54cdd897a7b48d1db42f2478fa1d5d213a0dd7de71c809cb19c60581ba57e7289d29408fb36",
recipeConfig: [
{
"op": "SHA3",
"args": ["512"]
}
]
},
{
name: "Bcrypt compare: dolphin",
input: "dolphin",
expectedOutput: "Match: dolphin",
recipeConfig: [
{
op: "Bcrypt compare",
args: ["$2a$10$qyon0LQCmMxpFFjwWH6Qh.dDdhqntQh./IN0RXCc3XIMILuOYZKgK"]
}
]
},
{
name: "Scrypt: RFC test vector 1",
input: "",
expectedOutput: "77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906",
recipeConfig: [
{
op: "Scrypt",
args: [
{
"option": "Latin1",
"string": ""
},
16, 1, 1, 64
]
}
]
},
{
name: "Scrypt: RFC test vector 2",
input: "password",
expectedOutput: "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640",
recipeConfig: [
{
op: "Scrypt",
args: [
{
"option": "Latin1",
"string": "NaCl"
},
1024, 8, 16, 64
]
}
]
},
{
name: "Scrypt: RFC test vector 3",
input: "pleaseletmein",
expectedOutput: "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887",
recipeConfig: [
{
op: "Scrypt",
args: [
{
"option": "Latin1",
"string": "SodiumChloride"
},
16384, 8, 1, 64
]
}
]
},
/*{ // This takes a LONG time to run (over a minute usually).
name: "Scrypt: RFC test vector 4",
input: "pleaseletmein",
expectedOutput: "2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4",
recipeConfig: [
{
op: "Scrypt",
args: [
{
"option": "Latin1",
"string": "SodiumChloride"
},
1048576, 8, 1, 64
]
}
]
},*/
]);

235
test/tests/operations/Hexdump.js Executable file
View File

@@ -0,0 +1,235 @@
/**
* Hexdump tests.
*
* @author n1474335 [n1474335@gmail.com]
*
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import TestRegister from "../../TestRegister.js";
const ALL_BYTES = [
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f",
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f",
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f",
"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f",
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f",
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf",
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf",
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
].join("");
TestRegister.addTests([
{
name: "Hexdump: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "To Hexdump",
args: [16, false, false]
},
{
op: "From Hexdump",
args: []
}
],
},
{
name: "Hexdump: Hello, World!",
input: "Hello, World!",
expectedOutput: "Hello, World!",
recipeConfig: [
{
op: "To Hexdump",
args: [16, false, false]
},
{
op: "From Hexdump",
args: []
}
],
},
{
name: "Hexdump: UTF-8",
input: "ნუ პანიკას",
expectedOutput: "ნუ პანიკას",
recipeConfig: [
{
op: "To Hexdump",
args: [16, false, false]
},
{
op: "From Hexdump",
args: []
}
],
},
{
name: "Hexdump: All bytes",
input: ALL_BYTES,
expectedOutput: ALL_BYTES,
recipeConfig: [
{
op: "To Hexdump",
args: [16, false, false]
},
{
op: "From Hexdump",
args: []
}
],
},
{
name: "To Hexdump: UTF-8",
input: "ნუ პანიკას",
expectedOutput: `00000000 e1 83 9c e1 83 a3 20 e1 83 9e e1 83 90 e1 83 9c |á..á.£ á..á..á..|
00000010 e1 83 98 e1 83 99 e1 83 90 e1 83 a1 |á..á..á..á.¡|`,
recipeConfig: [
{
op: "To Hexdump",
args: [16, false, false]
}
],
},
{
name: "To Hexdump: All bytes",
input: ALL_BYTES,
expectedOutput: `00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................|
00000010 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |................|
00000020 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f | !"#$%&'()*+,-./|
00000030 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f |0123456789:;<=>?|
00000040 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f |@ABCDEFGHIJKLMNO|
00000050 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f |PQRSTUVWXYZ[\\]^_|
00000060 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f |\`abcdefghijklmno|
00000070 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f |pqrstuvwxyz{|}~.|
00000080 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |................|
00000090 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f |................|
000000a0 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af |\xa0¡¢£¤¥¦§¨©ª«¬.®¯|
000000b0 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf |°±²³´µ¶·¸¹º»¼½¾¿|
000000c0 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf |ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ|
000000d0 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df |ÐÑÒÓÔÕÖרÙÚÛÜÝÞß|
000000e0 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef |àáâãäåæçèéêëìíîï|
000000f0 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff |ðñòóôõö÷øùúûüýþÿ|`,
recipeConfig: [
{
op: "To Hexdump",
args: [16, false, false]
}
],
},
{
name: "From Hexdump: xxd",
input: `00000000: 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f ................
00000010: 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f ................
00000020: 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f !"#$%&'()*+,-./
00000030: 3031 3233 3435 3637 3839 3a3b 3c3d 3e3f 0123456789:;<=>?
00000040: 4041 4243 4445 4647 4849 4a4b 4c4d 4e4f @ABCDEFGHIJKLMNO
00000050: 5051 5253 5455 5657 5859 5a5b 5c5d 5e5f PQRSTUVWXYZ[\\]^_
00000060: 6061 6263 6465 6667 6869 6a6b 6c6d 6e6f \`abcdefghijklmno
00000070: 7071 7273 7475 7677 7879 7a7b 7c7d 7e7f pqrstuvwxyz{|}~.
00000080: 8081 8283 8485 8687 8889 8a8b 8c8d 8e8f ................
00000090: 9091 9293 9495 9697 9899 9a9b 9c9d 9e9f ................
000000a0: a0a1 a2a3 a4a5 a6a7 a8a9 aaab acad aeaf ................
000000b0: b0b1 b2b3 b4b5 b6b7 b8b9 babb bcbd bebf ................
000000c0: c0c1 c2c3 c4c5 c6c7 c8c9 cacb cccd cecf ................
000000d0: d0d1 d2d3 d4d5 d6d7 d8d9 dadb dcdd dedf ................
000000e0: e0e1 e2e3 e4e5 e6e7 e8e9 eaeb eced eeef ................
000000f0: f0f1 f2f3 f4f5 f6f7 f8f9 fafb fcfd feff ................`,
expectedOutput: ALL_BYTES,
recipeConfig: [
{
op: "From Hexdump",
args: []
}
],
},
{
name: "From Hexdump: Wireshark",
input: `00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ........ ........
00000010 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ........ ........
00000020 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f !"#$%&' ()*+,-./
00000030 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 01234567 89:;<=>?
00000040 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFG HIJKLMNO
00000050 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f PQRSTUVW XYZ[\\]^_
00000060 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f \`abcdefg hijklmno
00000070 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f pqrstuvw xyz{|}~.
00000080 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f ........ ........
00000090 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f ........ ........
000000A0 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af ........ ........
000000B0 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf ........ ........
000000C0 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf ........ ........
000000D0 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df ........ ........
000000E0 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef ........ ........
000000F0 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff ........ ........
`,
expectedOutput: ALL_BYTES,
recipeConfig: [
{
op: "From Hexdump",
args: []
}
],
},
{
name: "From Hexdump: 010",
input: `0000h: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ................
0010h: 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F ................
0020h: 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F !"#$%&'()*+,-./
0030h: 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 0123456789:;<=>?
0040h: 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F @ABCDEFGHIJKLMNO
0050h: 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F PQRSTUVWXYZ[\\]^_
0060h: 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F \`abcdefghijklmno
0070h: 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F pqrstuvwxyz{|}~
0080h: 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F €.‚ƒ„…†‡ˆ‰Š‹Œ...
0090h: 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F .‘’“”•–—˜™š›œ.žŸ
00A0h: A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF \xa0¡¢£¤¥¦§¨©ª«¬­®¯
00B0h: B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF °±²³´µ¶·¸¹º»¼½¾¿
00C0h: C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
00D0h: D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF ÐÑÒÓÔÕÖרÙÚÛÜÝÞß
00E0h: E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF àáâãäåæçèéêëìíîï
00F0h: F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF ðñòóôõö÷øùúûüýþÿ`,
expectedOutput: ALL_BYTES,
recipeConfig: [
{
op: "From Hexdump",
args: []
}
],
},
{
name: "From Hexdump: Linux hexdump",
input: `00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |................|
00000010 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |................|
00000020 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f | !"#$%&'()*+,-./|
00000030 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f |0123456789:;<=>?|
00000040 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f |@ABCDEFGHIJKLMNO|
00000050 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f |PQRSTUVWXYZ[\\]^_|
00000060 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f |\`abcdefghijklmno|
00000070 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f |pqrstuvwxyz{|}~.|
00000080 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |................|
00000090 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f |................|
000000a0 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af |................|
000000b0 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf |................|
000000c0 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf |................|
000000d0 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df |................|
000000e0 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef |................|
000000f0 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff |................|
00000100`,
expectedOutput: ALL_BYTES,
recipeConfig: [
{
op: "From Hexdump",
args: []
}
],
},
]);

View File

@@ -0,0 +1,59 @@
/**
* StrUtils tests.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
import TestRegister from "../../TestRegister.js";
TestRegister.addTests([
{
name: "Regex: non-HTML op",
input: "/<>",
expectedOutput: "/<>",
recipeConfig: [
{
"op": "Regular expression",
"args": ["User defined", "", true, true, false, false, false, false, "Highlight matches"]
},
{
"op": "Remove whitespace",
"args": [true, true, true, true, true, false]
}
],
},
{
name: "Regex: Dot matches all",
input: "Hello\nWorld",
expectedOutput: "Hello\nWorld",
recipeConfig: [
{
"op": "Regular expression",
"args": ["User defined", ".+", true, true, true, false, false, false, "List matches"]
}
],
},
{
name: "Regex: Astral off",
input: "𝌆😆",
expectedOutput: "",
recipeConfig: [
{
"op": "Regular expression",
"args": ["User defined", "\\pS", true, true, false, false, false, false, "List matches"]
}
],
},
{
name: "Regex: Astral on",
input: "𝌆😆",
expectedOutput: "𝌆\n😆",
recipeConfig: [
{
"op": "Regular expression",
"args": ["User defined", "\\pS", true, true, false, false, true, false, "List matches"]
}
],
}
]);

58
test/tests/operations/StrUtils.js Normal file → Executable file
View File

@@ -8,21 +8,6 @@
import TestRegister from "../../TestRegister.js";
TestRegister.addTests([
{
name: "Regex, non-HTML op",
input: "/<>",
expectedOutput: "/<>",
recipeConfig: [
{
"op": "Regular expression",
"args": ["User defined", "", true, true, false, "Highlight matches"]
},
{
"op": "Remove whitespace",
"args": [true, true, true, true, true, false]
}
],
},
{
name: "Diff, basic usage",
input: "testing23\n\ntesting123",
@@ -233,13 +218,24 @@ TestRegister.addTests([
],
},
{
name: "Escape String: quotes",
input: "Hello \"World\"! Escape 'these' quotes.",
expectedOutput: "Hello \\\"World\\\"! Escape \\'these\\' quotes.",
name: "Escape String: single quotes",
input: "Escape 'these' quotes.",
expectedOutput: "Escape \\'these\\' quotes.",
recipeConfig: [
{
"op": "Escape string",
"args": []
"args": ["Special chars", "Single", false, true, false]
}
],
},
{
name: "Escape String: double quotes",
input: "Hello \"World\"!",
expectedOutput: "Hello \\\"World\\\"!",
recipeConfig: [
{
"op": "Escape string",
"args": ["Special chars", "Double", false, true, false]
}
],
},
@@ -250,7 +246,7 @@ TestRegister.addTests([
recipeConfig: [
{
"op": "Escape string",
"args": []
"args": ["Special chars", "Double", false, true, false]
}
],
},
@@ -276,4 +272,26 @@ TestRegister.addTests([
}
],
},
{
name: "Escape String: complex",
input: "null\0backspace\btab\tnewline\nverticaltab\vformfeed\fcarriagereturn\rdoublequote\"singlequote'hex\xa9unicode\u2665codepoint\u{1D306}",
expectedOutput: "null\\0backspace\\btab\\tnewline\\nverticaltab\\x0bformfeed\\fcarriagereturn\\rdoublequote\"singlequote\\'hex\\xa9unicode\\u2665codepoint\\u{1d306}",
recipeConfig: [
{
"op": "Escape string",
"args": ["Special chars", "Single", false, true, false]
}
],
},
{
name: "Unescape String: complex",
input: "null\\0backspace\\btab\\tnewline\\nverticaltab\\vformfeed\\fcarriagereturn\\rdoublequote\\\"singlequote\\'hex\\xa9unicode\\u2665codepoint\\u{1D306}",
expectedOutput: "null\0backspace\btab\tnewline\nverticaltab\vformfeed\fcarriagereturn\rdoublequote\"singlequote'hex\xa9unicode\u2665codepoint\u{1D306}",
recipeConfig: [
{
"op": "Unescape string",
"args": []
}
],
},
]);

View File

@@ -35,7 +35,6 @@ module.exports = {
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
moment: "moment-timezone",
log: "loglevel"
}),
new webpack.BannerPlugin({
@@ -54,7 +53,7 @@ module.exports = {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
exclude: /node_modules\/(?!jsesc)/,
loader: "babel-loader?compact=false"
},
{
@@ -109,9 +108,13 @@ module.exports = {
children: false,
chunks: false,
modules: false,
warningsFilter: /source-map/,
entrypoints: false,
warningsFilter: [/source-map/, /dependency is an expression/],
},
node: {
fs: "empty"
},
performance: {
hints: false
}
};