Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Fernet encryption/decryption operation #501

Merged
merged 7 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 2 additions & 0 deletions src/core/config/Categories.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@
"DES Decrypt",
"Triple DES Encrypt",
"Triple DES Decrypt",
"Fernet Encrypt",
"Fernet Decrypt",
"LS47 Encrypt",
"LS47 Decrypt",
"RC2 Encrypt",
Expand Down
63 changes: 63 additions & 0 deletions src/core/operations/FernetDecrypt.mjs
Original file line number Diff line number Diff line change
@@ -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 changes: 54 additions & 0 deletions src/core/operations/FernetEncrypt.mjs
Original file line number Diff line number Diff line change
@@ -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;
2 changes: 1 addition & 1 deletion tests/node/tests/nodeApi.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down
80 changes: 80 additions & 0 deletions tests/operations/tests/Fernet.mjs
Original file line number Diff line number Diff line change
@@ -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="]
}
],
}
]);
Loading