Skip to content

Commit c4e7c41

Browse files
authored
Merge pull request #501 from kassi/fernet
Add Fernet encryption/decryption operation
2 parents bebb216 + 210186e commit c4e7c41

File tree

7 files changed

+216
-1
lines changed

7 files changed

+216
-1
lines changed

Diff for: package-lock.json

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
"escodegen": "^2.1.0",
123123
"esprima": "^4.0.1",
124124
"exif-parser": "^0.1.12",
125+
"fernet": "^0.3.2",
125126
"file-saver": "^2.0.5",
126127
"flat": "^6.0.1",
127128
"geodesy": "1.1.3",

Diff for: src/core/config/Categories.json

+2
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@
8686
"DES Decrypt",
8787
"Triple DES Encrypt",
8888
"Triple DES Decrypt",
89+
"Fernet Encrypt",
90+
"Fernet Decrypt",
8991
"LS47 Encrypt",
9092
"LS47 Decrypt",
9193
"RC2 Encrypt",

Diff for: src/core/operations/FernetDecrypt.mjs

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* @author Karsten Silkenbäumer [github.com/kassi]
3+
* @copyright Karsten Silkenbäumer 2019
4+
* @license Apache-2.0
5+
*/
6+
7+
import Operation from "../Operation.mjs";
8+
import OperationError from "../errors/OperationError.mjs";
9+
import fernet from "fernet";
10+
11+
/**
12+
* FernetDecrypt operation
13+
*/
14+
class FernetDecrypt extends Operation {
15+
/**
16+
* FernetDecrypt constructor
17+
*/
18+
constructor() {
19+
super();
20+
21+
this.name = "Fernet Decrypt";
22+
this.module = "Default";
23+
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.";
24+
this.infoURL = "https://asecuritysite.com/encryption/fer";
25+
this.inputType = "string";
26+
this.outputType = "string";
27+
this.args = [
28+
{
29+
"name": "Key",
30+
"type": "string",
31+
"value": ""
32+
},
33+
];
34+
this.patterns = [
35+
{
36+
match: "^[A-Z\\d\\-_=]{20,}$",
37+
flags: "i",
38+
args: []
39+
},
40+
];
41+
}
42+
/**
43+
* @param {String} input
44+
* @param {Object[]} args
45+
* @returns {String}
46+
*/
47+
run(input, args) {
48+
const [secretInput] = args;
49+
try {
50+
const secret = new fernet.Secret(secretInput);
51+
const token = new fernet.Token({
52+
secret: secret,
53+
token: input,
54+
ttl: 0
55+
});
56+
return token.decode();
57+
} catch (err) {
58+
throw new OperationError(err);
59+
}
60+
}
61+
}
62+
63+
export default FernetDecrypt;

Diff for: src/core/operations/FernetEncrypt.mjs

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* @author Karsten Silkenbäumer [github.com/kassi]
3+
* @copyright Karsten Silkenbäumer 2019
4+
* @license Apache-2.0
5+
*/
6+
7+
import Operation from "../Operation.mjs";
8+
import OperationError from "../errors/OperationError.mjs";
9+
import fernet from "fernet";
10+
11+
/**
12+
* FernetEncrypt operation
13+
*/
14+
class FernetEncrypt extends Operation {
15+
/**
16+
* FernetEncrypt constructor
17+
*/
18+
constructor() {
19+
super();
20+
21+
this.name = "Fernet Encrypt";
22+
this.module = "Default";
23+
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.";
24+
this.infoURL = "https://asecuritysite.com/encryption/fer";
25+
this.inputType = "string";
26+
this.outputType = "string";
27+
this.args = [
28+
{
29+
"name": "Key",
30+
"type": "string",
31+
"value": ""
32+
},
33+
];
34+
}
35+
/**
36+
* @param {String} input
37+
* @param {Object[]} args
38+
* @returns {String}
39+
*/
40+
run(input, args) {
41+
const [secretInput] = args;
42+
try {
43+
const secret = new fernet.Secret(secretInput);
44+
const token = new fernet.Token({
45+
secret: secret,
46+
});
47+
return token.encode(input);
48+
} catch (err) {
49+
throw new OperationError(err);
50+
}
51+
}
52+
}
53+
54+
export default FernetEncrypt;

Diff for: tests/node/tests/nodeApi.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ TestRegister.addApiTests([
136136

137137
it("chef.help: returns multiple results", () => {
138138
const result = chef.help("base 64");
139-
assert.strictEqual(result.length, 11);
139+
assert.strictEqual(result.length, 13);
140140
}),
141141

142142
it("chef.help: looks in description for matches too", () => {

Diff for: tests/operations/tests/Fernet.mjs

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* Fernet tests.
3+
*
4+
* @author Karsten Silkenbäumer [github.com/kassi]
5+
* @copyright Karsten Silkenbäumer 2019
6+
* @license Apache-2.0
7+
*/
8+
import TestRegister from "../TestRegister";
9+
10+
TestRegister.addTests([
11+
{
12+
name: "Fernet Decrypt: no input",
13+
input: "",
14+
expectedOutput: "Error: Invalid version",
15+
recipeConfig: [
16+
{
17+
op: "Fernet Decrypt",
18+
args: ["MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="]
19+
}
20+
],
21+
},
22+
{
23+
name: "Fernet Decrypt: no secret",
24+
input: "gAAAAABce-Tycae8klRxhDX2uenJ-uwV8-A1XZ2HRnfOXlNzkKKfRxviNLlgtemhT_fd1Fw5P_zFUAjd69zaJBQyWppAxVV00SExe77ql8c5n62HYJOnoIU=",
25+
expectedOutput: "Error: Secret must be 32 url-safe base64-encoded bytes.",
26+
recipeConfig: [
27+
{
28+
op: "Fernet Decrypt",
29+
args: [""]
30+
}
31+
],
32+
},
33+
{
34+
name: "Fernet Decrypt: valid arguments",
35+
input: "gAAAAABce-Tycae8klRxhDX2uenJ-uwV8-A1XZ2HRnfOXlNzkKKfRxviNLlgtemhT_fd1Fw5P_zFUAjd69zaJBQyWppAxVV00SExe77ql8c5n62HYJOnoIU=",
36+
expectedOutput: "This is a secret message.\n",
37+
recipeConfig: [
38+
{
39+
op: "Fernet Decrypt",
40+
args: ["VGhpc0lzVGhpcnR5VHdvQ2hhcmFjdGVyc0xvbmdLZXk="]
41+
}
42+
],
43+
}
44+
]);
45+
46+
TestRegister.addTests([
47+
{
48+
name: "Fernet Encrypt: no input",
49+
input: "",
50+
expectedMatch: /^gAAAAABce-[\w-]+={0,2}$/,
51+
recipeConfig: [
52+
{
53+
op: "Fernet Encrypt",
54+
args: ["MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="]
55+
}
56+
],
57+
},
58+
{
59+
name: "Fernet Encrypt: no secret",
60+
input: "This is a secret message.\n",
61+
expectedOutput: "Error: Secret must be 32 url-safe base64-encoded bytes.",
62+
recipeConfig: [
63+
{
64+
op: "Fernet Encrypt",
65+
args: [""]
66+
}
67+
],
68+
},
69+
{
70+
name: "Fernet Encrypt: valid arguments",
71+
input: "This is a secret message.\n",
72+
expectedMatch: /^gAAAAABce-[\w-]+={0,2}$/,
73+
recipeConfig: [
74+
{
75+
op: "Fernet Encrypt",
76+
args: ["MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="]
77+
}
78+
],
79+
}
80+
]);

0 commit comments

Comments
 (0)