diff --git a/package-lock.json b/package-lock.json
index 82c74477..5e6671a5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -40,6 +40,7 @@
"escodegen": "^2.1.0",
"esprima": "^4.0.1",
"exif-parser": "^0.1.12",
+ "fernet": "^0.3.2",
"file-saver": "^2.0.5",
"flat": "^6.0.1",
"geodesy": "1.1.3",
@@ -7100,6 +7101,15 @@
"pend": "~1.2.0"
}
},
+ "node_modules/fernet": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/fernet/-/fernet-0.3.2.tgz",
+ "integrity": "sha512-VPwO4hF9sp8YrCeiOjMb4HTg5WV5VC7Nk2EG3pfotqW9ZHa3aNnR+oGiOZu8k0Jp4VxJi0RTJwHmloyjWs+Mzg==",
+ "dependencies": {
+ "crypto-js": "~4.2.0",
+ "urlsafe-base64": "1.0.0"
+ }
+ },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"dev": true,
@@ -14081,6 +14091,11 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/urlsafe-base64": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/urlsafe-base64/-/urlsafe-base64-1.0.0.tgz",
+ "integrity": "sha512-RtuPeMy7c1UrHwproMZN9gN6kiZ0SvJwRaEzwZY0j9MypEkFqyBaKv176jvlPtg58Zh36bOkS0NFABXMHvvGCA=="
+ },
"node_modules/utf8": {
"version": "3.0.0",
"license": "MIT"
diff --git a/package.json b/package.json
index b0e37f7f..334d88b5 100644
--- a/package.json
+++ b/package.json
@@ -122,6 +122,7 @@
"escodegen": "^2.1.0",
"esprima": "^4.0.1",
"exif-parser": "^0.1.12",
+ "fernet": "^0.3.2",
"file-saver": "^2.0.5",
"flat": "^6.0.1",
"geodesy": "1.1.3",
diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json
index 4f1b3328..8e300c76 100644
--- a/src/core/config/Categories.json
+++ b/src/core/config/Categories.json
@@ -86,6 +86,8 @@
"DES Decrypt",
"Triple DES Encrypt",
"Triple DES Decrypt",
+ "Fernet Encrypt",
+ "Fernet Decrypt",
"LS47 Encrypt",
"LS47 Decrypt",
"RC2 Encrypt",
diff --git a/src/core/operations/FernetDecrypt.mjs b/src/core/operations/FernetDecrypt.mjs
new file mode 100644
index 00000000..78d6efb9
--- /dev/null
+++ b/src/core/operations/FernetDecrypt.mjs
@@ -0,0 +1,63 @@
+/**
+ * @author Karsten Silkenbäumer [github.com/kassi]
+ * @copyright Karsten Silkenbäumer 2019
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation.mjs";
+import OperationError from "../errors/OperationError.mjs";
+import fernet from "fernet";
+
+/**
+ * FernetDecrypt operation
+ */
+class FernetDecrypt extends Operation {
+ /**
+ * FernetDecrypt constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "Fernet Decrypt";
+ this.module = "Default";
+ this.description = "Fernet is a symmetric encryption method which makes sure that the message encrypted cannot be manipulated/read without the key. It uses URL safe encoding for the keys. Fernet uses 128-bit AES in CBC mode and PKCS7 padding, with HMAC using SHA256 for authentication. The IV is created from os.random().
Key: The key must be 32 bytes (256 bits) encoded with Base64.";
+ this.infoURL = "https://asecuritysite.com/encryption/fer";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [
+ {
+ "name": "Key",
+ "type": "string",
+ "value": ""
+ },
+ ];
+ this.patterns = [
+ {
+ match: "^[A-Z\\d\\-_=]{20,}$",
+ flags: "i",
+ args: []
+ },
+ ];
+ }
+ /**
+ * @param {String} input
+ * @param {Object[]} args
+ * @returns {String}
+ */
+ run(input, args) {
+ const [secretInput] = args;
+ try {
+ const secret = new fernet.Secret(secretInput);
+ const token = new fernet.Token({
+ secret: secret,
+ token: input,
+ ttl: 0
+ });
+ return token.decode();
+ } catch (err) {
+ throw new OperationError(err);
+ }
+ }
+}
+
+export default FernetDecrypt;
diff --git a/src/core/operations/FernetEncrypt.mjs b/src/core/operations/FernetEncrypt.mjs
new file mode 100644
index 00000000..84778486
--- /dev/null
+++ b/src/core/operations/FernetEncrypt.mjs
@@ -0,0 +1,54 @@
+/**
+ * @author Karsten Silkenbäumer [github.com/kassi]
+ * @copyright Karsten Silkenbäumer 2019
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation.mjs";
+import OperationError from "../errors/OperationError.mjs";
+import fernet from "fernet";
+
+/**
+ * FernetEncrypt operation
+ */
+class FernetEncrypt extends Operation {
+ /**
+ * FernetEncrypt constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "Fernet Encrypt";
+ this.module = "Default";
+ this.description = "Fernet is a symmetric encryption method which makes sure that the message encrypted cannot be manipulated/read without the key. It uses URL safe encoding for the keys. Fernet uses 128-bit AES in CBC mode and PKCS7 padding, with HMAC using SHA256 for authentication. The IV is created from os.random().
Key: The key must be 32 bytes (256 bits) encoded with Base64.";
+ this.infoURL = "https://asecuritysite.com/encryption/fer";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [
+ {
+ "name": "Key",
+ "type": "string",
+ "value": ""
+ },
+ ];
+ }
+ /**
+ * @param {String} input
+ * @param {Object[]} args
+ * @returns {String}
+ */
+ run(input, args) {
+ const [secretInput] = args;
+ try {
+ const secret = new fernet.Secret(secretInput);
+ const token = new fernet.Token({
+ secret: secret,
+ });
+ return token.encode(input);
+ } catch (err) {
+ throw new OperationError(err);
+ }
+ }
+}
+
+export default FernetEncrypt;
diff --git a/tests/node/tests/nodeApi.mjs b/tests/node/tests/nodeApi.mjs
index 0d4a04a4..8992ed36 100644
--- a/tests/node/tests/nodeApi.mjs
+++ b/tests/node/tests/nodeApi.mjs
@@ -136,7 +136,7 @@ TestRegister.addApiTests([
it("chef.help: returns multiple results", () => {
const result = chef.help("base 64");
- assert.strictEqual(result.length, 11);
+ assert.strictEqual(result.length, 13);
}),
it("chef.help: looks in description for matches too", () => {
diff --git a/tests/operations/tests/Fernet.mjs b/tests/operations/tests/Fernet.mjs
new file mode 100644
index 00000000..ee9ba2f1
--- /dev/null
+++ b/tests/operations/tests/Fernet.mjs
@@ -0,0 +1,80 @@
+/**
+ * Fernet tests.
+ *
+ * @author Karsten Silkenbäumer [github.com/kassi]
+ * @copyright Karsten Silkenbäumer 2019
+ * @license Apache-2.0
+ */
+import TestRegister from "../TestRegister";
+
+TestRegister.addTests([
+ {
+ name: "Fernet Decrypt: no input",
+ input: "",
+ expectedOutput: "Error: Invalid version",
+ recipeConfig: [
+ {
+ op: "Fernet Decrypt",
+ args: ["MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="]
+ }
+ ],
+ },
+ {
+ name: "Fernet Decrypt: no secret",
+ input: "gAAAAABce-Tycae8klRxhDX2uenJ-uwV8-A1XZ2HRnfOXlNzkKKfRxviNLlgtemhT_fd1Fw5P_zFUAjd69zaJBQyWppAxVV00SExe77ql8c5n62HYJOnoIU=",
+ expectedOutput: "Error: Secret must be 32 url-safe base64-encoded bytes.",
+ recipeConfig: [
+ {
+ op: "Fernet Decrypt",
+ args: [""]
+ }
+ ],
+ },
+ {
+ name: "Fernet Decrypt: valid arguments",
+ input: "gAAAAABce-Tycae8klRxhDX2uenJ-uwV8-A1XZ2HRnfOXlNzkKKfRxviNLlgtemhT_fd1Fw5P_zFUAjd69zaJBQyWppAxVV00SExe77ql8c5n62HYJOnoIU=",
+ expectedOutput: "This is a secret message.\n",
+ recipeConfig: [
+ {
+ op: "Fernet Decrypt",
+ args: ["VGhpc0lzVGhpcnR5VHdvQ2hhcmFjdGVyc0xvbmdLZXk="]
+ }
+ ],
+ }
+]);
+
+TestRegister.addTests([
+ {
+ name: "Fernet Encrypt: no input",
+ input: "",
+ expectedMatch: /^gAAAAABce-[\w-]+={0,2}$/,
+ recipeConfig: [
+ {
+ op: "Fernet Encrypt",
+ args: ["MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="]
+ }
+ ],
+ },
+ {
+ name: "Fernet Encrypt: no secret",
+ input: "This is a secret message.\n",
+ expectedOutput: "Error: Secret must be 32 url-safe base64-encoded bytes.",
+ recipeConfig: [
+ {
+ op: "Fernet Encrypt",
+ args: [""]
+ }
+ ],
+ },
+ {
+ name: "Fernet Encrypt: valid arguments",
+ input: "This is a secret message.\n",
+ expectedMatch: /^gAAAAABce-[\w-]+={0,2}$/,
+ recipeConfig: [
+ {
+ op: "Fernet Encrypt",
+ args: ["MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="]
+ }
+ ],
+ }
+]);