From 7447f374093b6b32e67e3e13daa9542e97b9f486 Mon Sep 17 00:00:00 2001 From: Tan Zhen Yong Date: Mon, 7 Oct 2019 02:24:09 +0800 Subject: [PATCH] Add Argon2 hash operation --- package-lock.json | 11 ++++ package.json | 2 + src/core/config/Categories.json | 1 + src/core/operations/Argon2.mjs | 99 +++++++++++++++++++++++++++++++++ tests/node/tests/operations.mjs | 6 ++ webpack.config.js | 9 +++ 6 files changed, 128 insertions(+) create mode 100644 src/core/operations/Argon2.mjs diff --git a/package-lock.json b/package-lock.json index 11c80ca0a5..ee189f7b0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1906,6 +1906,11 @@ "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", "dev": true }, + "argon2-browser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/argon2-browser/-/argon2-browser-1.11.1.tgz", + "integrity": "sha512-C+WsBLSkwQExkDYB7vriugrBTXq2z+fTRDlGWqr2zm89TaKo7zYtSGARMgoBxpDnmNNzduNlZJmpY2j0Dp7ZOQ==" + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -2382,6 +2387,12 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" }, + "base64-loader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64-loader/-/base64-loader-1.0.0.tgz", + "integrity": "sha1-5TC62I6QbdKh+tCvLZ5oP6i9kqg=", + "dev": true + }, "basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", diff --git a/package.json b/package.json index e9c33484b8..fd84742a56 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "babel-eslint": "^10.0.3", "babel-loader": "^8.0.6", "babel-plugin-dynamic-import-node": "^2.3.0", + "base64-loader": "^1.0.0", "chromedriver": "^76.0.1", "colors": "^1.3.3", "copy-webpack-plugin": "^5.0.4", @@ -85,6 +86,7 @@ "dependencies": { "@babel/polyfill": "^7.4.4", "@babel/runtime": "^7.5.5", + "argon2-browser": "^1.11.1", "arrive": "^2.4.1", "babel-plugin-transform-builtin-extend": "1.1.2", "bcryptjs": "^2.4.3", diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 94f7fd309f..5b8de47537 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -320,6 +320,7 @@ "Bcrypt compare", "Bcrypt parse", "Scrypt", + "Argon2", "Fletcher-8 Checksum", "Fletcher-16 Checksum", "Fletcher-32 Checksum", diff --git a/src/core/operations/Argon2.mjs b/src/core/operations/Argon2.mjs new file mode 100644 index 0000000000..8eff40797c --- /dev/null +++ b/src/core/operations/Argon2.mjs @@ -0,0 +1,99 @@ +/** + * @author Tan Zhen Yong [tzy@beyondthesprawl.com] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import argon2 from "argon2-browser"; + +/** + * Argon2 operation + */ +class Argon2 extends Operation { + + /** + * Argon2 constructor + */ + constructor() { + super(); + + this.name = "Argon2"; + this.module = "Crypto"; + this.description = "Argon2 is a key derivation function that was selected as the winner of the Password Hashing Competition in July 2015. It was designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich from the University of Luxembourg.

Enter the password in the input to generate its hash."; + this.infoURL = "https://wikipedia.org/wiki/Argon2"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Salt", + "type": "string", + "value": "somesalt" + }, + { + "name": "Iterations", + "type": "number", + "value": 3 + }, + { + "name": "Memory (KiB)", + "type": "number", + "value": 4096 + }, + { + "name": "Parallelism", + "type": "number", + "value": 1 + }, + { + "name": "Hash length (bytes)", + "type": "number", + "value": 32 + }, + { + "name": "Type", + "type": "option", + "value": ["Argon2i", "Argon2d", "Argon2id"], + "defaultIndex": 0 + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const argon2Types = { + "Argon2i": argon2.ArgonType.Argon2i, + "Argon2d": argon2.ArgonType.Argon2d, + "Argon2id": argon2.ArgonType.Argon2id + }; + + const salt = args[0], + time = args[1], + mem = args[2], + parallelism = args[3], + hashLen = args[4], + type = argon2Types[args[5]]; + + return argon2.hash({ + pass: input, + salt, + time, + mem, + parallelism, + hashLen, + type, + }).then(res => { + return `Encoded: ${res.encoded}\nHash: ${res.hashHex}`; + }).catch(err => { + throw new OperationError(`Error: ${err.message}`); + }); + } + +} + +export default Argon2; diff --git a/tests/node/tests/operations.mjs b/tests/node/tests/operations.mjs index 75f37ab175..ff5603cee9 100644 --- a/tests/node/tests/operations.mjs +++ b/tests/node/tests/operations.mjs @@ -132,6 +132,12 @@ Tiger-128`; assert.strictEqual(result.toString(), "Szkkb zh z Xozn"); }), + it("Argon2", async () => { + const result = await chef.Argon2("argon2password"); + assert.strictEqual(result.toString(), `Encoded: $argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$s43my9eBljQADuF/LWCG8vGqwAJzOorKQ0Yog8jFvbw +Hash: b38de6cbd7819634000ee17f2d6086f2f1aac002733a8aca43462883c8c5bdbc`); + }), + it("Bcrypt", async () => { const result = await chef.bcrypt("Put a Sock In It"); assert.strictEqual(result.toString(), "$2a$10$ODeP1.6fMsb.ENk2ngPUCO7qTGVPyHA9TqDVcyupyed8FjsiF65L6"); diff --git a/webpack.config.js b/webpack.config.js index 1042a1a978..6d8a115c51 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -65,6 +65,8 @@ module.exports = { }, }, module: { + // argon2-browser loads argon2.wasm by itself, so Webpack should not load it + noParse: /node_modules\/argon2-browser\/dist\/argon2\.wasm$/, rules: [ { test: /\.m?js$/, @@ -77,6 +79,13 @@ module.exports = { type: "javascript/auto", loader: "babel-loader" }, + { + test: /node_modules\/argon2-browser\/dist\/argon2\.wasm$/, + // Load argon2.wasm as base64-encoded binary file + // expected by argon2-browser + loaders: "base64-loader", + type: "javascript/auto" + }, { test: /forge.min.js$/, loader: "imports-loader?jQuery=>null"