diff --git a/package-lock.json b/package-lock.json
index 8b5641c9e..6e4f92305 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16587,6 +16587,11 @@
"integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==",
"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": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -16976,6 +16981,12 @@
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
},
+ "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 fe93fe52b..46a0f2328 100644
--- a/package.json
+++ b/package.json
@@ -89,6 +89,7 @@
"@astronautlabs/amf": "^0.0.6",
"@babel/polyfill": "^7.12.1",
"@blu3r4y/lzma": "^2.3.3",
+ "argon2-browser": "^1.11.1",
"arrive": "^2.4.1",
"avsc": "^5.7.4",
"bcryptjs": "^2.4.3",
diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json
index 075e8d666..da9e0d0de 100644
--- a/src/core/config/Categories.json
+++ b/src/core/config/Categories.json
@@ -379,6 +379,7 @@
"Bcrypt compare",
"Bcrypt parse",
"Scrypt",
+ "Argon2",
"NT Hash",
"LM Hash",
"Fletcher-8 Checksum",
diff --git a/src/core/operations/Argon2.mjs b/src/core/operations/Argon2.mjs
new file mode 100644
index 000000000..f36e5d0a7
--- /dev/null
+++ b/src/core/operations/Argon2.mjs
@@ -0,0 +1,101 @@
+/**
+ * @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}
+ */
+ async 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]];
+
+ try {
+ const result = await argon2.hash({
+ pass: input,
+ salt,
+ time,
+ mem,
+ parallelism,
+ hashLen,
+ type,
+ });
+
+ return result.encoded;
+ } 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 8611ecb4c..45b38c7e0 100644
--- a/tests/node/tests/operations.mjs
+++ b/tests/node/tests/operations.mjs
@@ -133,6 +133,11 @@ Tiger-128`;
}),
+ it("argon2", async () => {
+ const result = await chef.argon2("argon2password");
+ assert.strictEqual(result.toString(), "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$s43my9eBljQADuF/LWCG8vGqwAJzOorKQ0Yog8jFvbw");
+ }),
+
it("Bcrypt", async () => {
const result = await chef.bcrypt("Put a Sock In It");
const strResult = result.toString();
diff --git a/webpack.config.js b/webpack.config.js
index 50c4c7310..6011b1dd1 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -114,6 +114,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$/,
@@ -127,11 +129,11 @@ module.exports = {
loader: "babel-loader"
},
{
- test: /node-forge/,
- loader: "imports-loader",
- options: {
- additionalCode: "var jQuery = false;"
- }
+ 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: /prime.worker.min.js$/,