Browse Source

Merge pull request #501 from kassi/fernet

Add Fernet encryption/decryption operation
a3957273 1 year ago
parent
commit
c4e7c41a6e

+ 15 - 0
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"

+ 1 - 0
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",

+ 2 - 0
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",

+ 63 - 0
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().<br><br><b>Key:</b> 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;

+ 54 - 0
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().<br><br><b>Key:</b> 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;

+ 1 - 1
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", () => {

+ 80 - 0
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="]
+            }
+        ],
+    }
+]);