Skip to content

Commit fdeb419

Browse files
authored
Merge pull request #1 from linuxgemini/class-re
* Rewritten key generation script * Rewritten class * Cleaned up code * Cleaned up readme
2 parents 81bc2e5 + d2ef841 commit fdeb419

File tree

10 files changed

+254
-125
lines changed

10 files changed

+254
-125
lines changed

.eslintrc.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"env": {
3+
"es6": true,
4+
"node": true
5+
},
6+
"extends": "eslint:recommended",
7+
"parserOptions": {
8+
"ecmaVersion": 2017,
9+
"sourceType": "module",
10+
"impliedStrict": true,
11+
"ecmaFeatures": {
12+
"experimentalObjectRestSpread": true
13+
}
14+
},
15+
"rules": {
16+
"indent": [
17+
"error",
18+
4,
19+
{
20+
"SwitchCase": 1
21+
}
22+
],
23+
"linebreak-style": [
24+
"error",
25+
"unix"
26+
],
27+
"quotes": [
28+
"error",
29+
"double"
30+
],
31+
"semi": [
32+
"error",
33+
"always"
34+
],
35+
"no-console": 0,
36+
"no-unused-vars": "warn"
37+
}
38+
}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
.basic256rc.js

.travis.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ sudo: enabled
33
group: edge
44
node_js:
55
- "node"
6-
- "7"
7-
- "6"
8-
- "5"
9-
- "4"
6+
- "8"
107
install:
118
- npm install
129
script:

DontRunMe.js

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,60 @@
1-
'use strict';
1+
"use strict";
22

3-
let crypto = require('crypto'); // define crypto
4-
let fs = require('fs'); // define filesys
3+
const detectNewline = require("detect-newline");
4+
const crypto = require("crypto"); // define crypto
5+
const fs = require("fs"); // define filesys
6+
let projectRoot = require("path").dirname(require.main.filename);
7+
let fetchedKey, fetchedHMAC, convertedConfig = false;
58

6-
function randomValueHex (len) {
9+
const exit = (msg) => {
10+
console.log(msg);
11+
return setTimeout(() => {
12+
process.exit(0);
13+
}, 2000);
14+
};
15+
16+
const randomValueHex = (len) => {
717
return crypto.randomBytes(Math.ceil(len/2))
8-
.toString('hex') // convert to hexadecimal format
18+
.toString("hex") // convert to hexadecimal format
919
.slice(0,len); // return required number of characters
1020
};
1121

12-
if (fs.existsSync("./config.js")) {
13-
return setTimeout(function(){
14-
process.exit(0); // exit script if config already exists
15-
}, 833);
16-
}
22+
const main = () => {
23+
if (fs.existsSync(`${projectRoot}/.gitignore`)) {
24+
var file = fs.readFileSync(`${projectRoot}/.gitignore`).toString();
25+
var newlineChar = detectNewline(file);
26+
if (!file.includes(".basic256rc.js")) fs.appendFileSync(`${projectRoot}/.gitignore`, `${newlineChar}.basic256rc.js${newlineChar}`);
27+
}
28+
29+
if (fs.existsSync(`${projectRoot}/.basic256rc.js`)) {
30+
return exit("\n.basic256rc.js already exists, stopping setup.\n");
31+
}
32+
33+
if (fs.existsSync("./config.js")) {
34+
try {
35+
var c = require("./config.js").k;
36+
if (c.key) fetchedKey = c.key;
37+
if (c.hmac_key) fetchedHMAC = c.hmac_key;
38+
convertedConfig = true;
39+
} catch (e) {
40+
fetchedKey = null,
41+
fetchedHMAC = null;
42+
console.warn(`\nThere is an old config.js file in package.\nHowever, reading of the keys have failed:\n\n${e.stack}\n`);
43+
}
44+
}
1745

18-
let key = randomValueHex(32); // create random hex val for enc key
19-
let hmac = randomValueHex(32); // create random hex val for hmac key
20-
let randFold = "./" + randomValueHex(32) + "/"; // create random hex val with filesys encoding for folder
21-
let randFile = randomValueHex(32) + ".json"; // create random hex val with .json ending for file
22-
let resSysop = randFold + randFile; // merge foldername and filename
46+
const enduserconfig = {
47+
key: fetchedKey || randomValueHex(32), // create random hex val for enc key
48+
hmac_key: fetchedHMAC || randomValueHex(32) // create random hex val for hmac key
49+
};
2350

24-
fs.mkdirSync(randFold); // create folder
25-
fs.appendFileSync(resSysop, "{\n \"key\": \"" + key + "\",\n \"hmac_key\": \"" + hmac + "\"\n}\n"); // create file with keys necessary
26-
fs.appendFileSync("./config.js", "\'use strict\';\n\nvar k = require(\"" + resSysop + "\");\n\nmodule.exports = {\n k\n};\n\n"); // generate config file with necessary info
51+
fs.appendFileSync(`${projectRoot}/.basic256rc.js`, `"use strict";
52+
53+
module.exports = ${JSON.stringify(enduserconfig, null, 4)}
54+
`); // generate config file with necessary info
55+
56+
if (convertedConfig) return exit("\nYour old configuration is saved to a file named .basic256rc.js has been created on the project root.\nDON'T FORGET TO BACK THIS UP.\n");
57+
return exit("\nA file named .basic256rc.js has been created on the project root. DON'T FORGET TO BACK THIS UP.\n");
58+
};
2759

28-
setTimeout(function(){process.exit(0);}, 2000); // exit script
60+
main();

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@
176176
END OF TERMS AND CONDITIONS
177177

178178
Copyright 2014 Levi Gross
179-
Copyright 2016 linuxgemini. All Rights Reserved.
179+
Copyright 2018 linuxgemini. All Rights Reserved.
180180

181181
Licensed under the Apache License, Version 2.0 (the "License");
182182
you may not use this file except in compliance with the License.

README.md

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,43 @@ basic256.js
33

44
[![Build Status](https://travis-ci.org/linuxgemini/basic256.js.svg?branch=master)](https://travis-ci.org/linuxgemini/basic256.js)
55

6+
WARNING
7+
-------
8+
9+
**THIS PACKAGE SAVES IMPORTANT KEYS ON YOUR PROJECT, DON'T LOSE IT.**
10+
611
A basic encryption/decryption script/API for resting data for Node.js users.
712

813
*Slightly* modified the work of [Levi Gross](http://www.levigross.com/2014/03/30/how-to-write-an-encrypt-and-decrypt-api-for-data-at-rest-in-nodejs/).
914

10-
Usage with downloading from NPM
15+
Usage
1116
-----
1217

1318
Open a terminal in your project folder and make sure that you have a package.json file.
1419

1520
And do this on your terminal if you are not root:
1621

17-
npm install --save basic256.js
22+
`
23+
$ npm install --save basic256.js
24+
`
1825

1926
If you are running as root, do this:
2027

21-
npm install --unsafe-perm --save basic256.js
28+
`
29+
$ npm install --unsafe-perm --save basic256.js
30+
`
2231

2332
Then make your script connected. Example:
2433

25-
var crypter = require("basic256.js");
26-
27-
var blob = crypter.encrypt("FOO").catch(console.error); // This encrypts the string "FOO".
28-
console.log(blob); // This will show the encrypted string.
29-
30-
var unblob = crypter.decrypt(blob).catch(console.error); // This decrypts the encrypted string.
31-
console.log(unblob); // This will show the decrypted string. (Which in this case, it is "FOO")
32-
33-
34-
Usage without downloading from NPM
35-
-----
36-
37-
Gather basic256.js first, copy all files inside to your project folder/direcory.
34+
```js
35+
const b256 = require("basic256.js");
36+
const basic256 = new b256();
3837

39-
And do this on your terminal if you are not root:
40-
41-
npm install
42-
43-
If you are running as root, do this:
44-
45-
npm install --unsafe-perm
38+
var blob = basic256.encrypt("FOO"); // This encrypts the string "FOO".
39+
console.log(blob); // This will show the encrypted string.
4640

47-
Then make your script connected. Example:
41+
var unblob = basic256.decrypt(blob); // This decrypts the encrypted string.
42+
console.log(unblob); // This will show the decrypted string. (Which in this case, it is "FOO")
43+
```
4844

49-
var crypter = require("./basic256.js");
50-
51-
var blob = crypter.encrypt("FOO").catch(console.error); // This encrypts the string "FOO".
52-
console.log(blob); // This will show the encrypted string.
53-
54-
var unblob = crypter.decrypt(blob).catch(console.error); // This decrypts the encrypted string.
55-
console.log(unblob); // This will show the decrypted string. (Which in this case, it is "FOO")
45+
**Don't forget to back your .basic256rc.js file as it contains your keys to encrypt and decrypt strings.**

basic256.js

Lines changed: 65 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,93 @@
1-
'use strict';
2-
3-
let crypto = require('crypto');
4-
5-
try {
6-
var savedKeys = require("./config.js").k;
7-
} catch (e) {
8-
return Promise.reject('No Configuration Exists!');
9-
}
10-
11-
var ALGORITHM, KEY, HMAC_ALGORITHM, HMAC_KEY;
12-
13-
ALGORITHM = 'AES-256-CBC'; // CBC because CTR isn't possible with the current version of the Node.JS crypto library
14-
HMAC_ALGORITHM = 'SHA256';
15-
KEY = savedKeys.key; // Use the automated script.
16-
HMAC_KEY = savedKeys.hmac_key; // Use the automated script.
17-
18-
function randomValueHex (len) {
19-
return crypto.randomBytes(Math.ceil(len/2))
20-
.toString('hex') // convert to hexadecimal format
21-
.slice(0,len); // return required number of characters
22-
};
23-
24-
var constant_time_compare = function (val1, val2) {
25-
var sentinel;
26-
27-
if (val1.length !== val2.length) {
28-
return false;
29-
}
30-
1+
"use strict";
2+
3+
let crypto = require("crypto");
4+
let projectRoot = require("path").dirname(require.main.filename);
5+
6+
/**
7+
* A basic encryption/decryption script/API for resting data for Node.js users.
8+
* @class
9+
*/
10+
class basic256 {
11+
constructor() {
12+
try {
13+
var savedKeys = require(`${projectRoot}/.basic256rc.js`);
14+
} catch (e) {
15+
throw new Error("An error happened while loading the key");
16+
}
3117

32-
for (var i = 0; i <= (val1.length - 1); i++) {
33-
sentinel |= val1.charCodeAt(i) ^ val2.charCodeAt(i);
18+
this.ALGORITHM = "AES-256-CBC";
19+
this.HMAC_ALGORITHM = "SHA256";
20+
this.KEY = savedKeys.key; // Use the automated script.
21+
this.HMAC_KEY = savedKeys.hmac_key; // Use the automated script.
3422
}
3523

36-
return sentinel === 0
37-
};
38-
39-
module.exports = {
40-
41-
"encrypt": function (plain_text) {
42-
if (!plain_text || typeof(plain_text) !== "string") return Promise.reject("Plain text was not found.");
24+
encrypt(plain_text) {
25+
if (!plain_text || typeof (plain_text) !== "string") throw new Error("Plain text was not found.");
4326

44-
var IV = Buffer.from(randomValueHex(16)); // ensure that the IV (initialization vector) is random
27+
var IV = Buffer.from(tools.randomValueHex(16)); // ensure that the IV (initialization vector) is random
4528
var encryptor, cipher_text, hmac;
4629

47-
encryptor = crypto.createCipheriv(ALGORITHM, KEY, IV);
48-
encryptor.setEncoding('hex');
30+
encryptor = crypto.createCipheriv(this.ALGORITHM, this.KEY, IV);
31+
encryptor.setEncoding("hex");
4932
encryptor.write(plain_text);
5033
encryptor.end();
5134

5235
cipher_text = encryptor.read();
5336

54-
hmac = crypto.createHmac(HMAC_ALGORITHM, HMAC_KEY);
37+
hmac = crypto.createHmac(this.HMAC_ALGORITHM, this.HMAC_KEY);
5538
hmac.update(cipher_text);
56-
hmac.update(IV.toString('hex')); // ensure that both the IV and the cipher-text is protected by the HMAC
39+
hmac.update(IV.toString("hex")); // ensure that both the IV and the cipher-text is protected by the HMAC
5740

5841
// The IV isn't a secret so it can be stored along side everything else
59-
return cipher_text + "$" + IV.toString('hex') + "$" + hmac.digest('hex')
60-
},
42+
return cipher_text + "$" + IV.toString("hex") + "$" + hmac.digest("hex");
43+
}
6144

62-
"decrypt": function (cipher_text) {
63-
if (!cipher_text || typeof(cipher_text) !== "string" || !cipher_text.match(/\$/g)) return Promise.reject("A valid cipher text was not found.");
45+
decrypt(cipher_text) {
46+
if (!cipher_text || typeof (cipher_text) !== "string" || !cipher_text.match(/\$/g)) throw new Error("A valid cipher text was not found.");
6447

6548
var cipher_blob = cipher_text.split("$");
49+
50+
if (cipher_blob.length !== 3) throw new Error("Cipher text is broken.");
51+
6652
var ct = cipher_blob[0];
67-
var IV = Buffer.from(cipher_blob[1], 'hex');
53+
var IV = Buffer.from(cipher_blob[1], "hex");
6854
var hmac = cipher_blob[2];
6955
var chmac, decryptor;
7056

71-
chmac = crypto.createHmac(HMAC_ALGORITHM, HMAC_KEY);
57+
chmac = crypto.createHmac(this.HMAC_ALGORITHM, this.HMAC_KEY);
7258
chmac.update(ct);
73-
chmac.update(IV.toString('hex'));
59+
chmac.update(IV.toString("hex"));
7460

75-
if (!constant_time_compare(chmac.digest('hex'), hmac)) {
76-
return Promise.reject("Encrypted Blob has been tampered with.");
61+
if (!tools.constant_time_compare(chmac.digest("hex"), hmac)) {
62+
throw new Error("Encrypted Blob has been tampered with.");
7763
}
7864

79-
decryptor = crypto.createDecipheriv(ALGORITHM, KEY, IV);
80-
var decryptedText = decryptor.update(ct, 'hex', 'utf-8');
81-
return decryptedText + decryptor.final('utf-8');
65+
decryptor = crypto.createDecipheriv(this.ALGORITHM, this.KEY, IV);
66+
var decryptedText = decryptor.update(ct, "hex", "utf-8");
67+
return decryptedText + decryptor.final("utf-8");
8268
}
8369

8470
}
71+
72+
class tools {
73+
static constant_time_compare(val1, val2) {
74+
var sentinel;
75+
76+
if (val1.length !== val2.length) {
77+
return false;
78+
}
79+
80+
for (var i = 0; i <= (val1.length - 1); i++) {
81+
sentinel |= val1.charCodeAt(i) ^ val2.charCodeAt(i);
82+
}
83+
84+
return sentinel === 0;
85+
}
86+
static randomValueHex(len) {
87+
return crypto.randomBytes(Math.ceil(len / 2))
88+
.toString("hex") // convert to hexadecimal format
89+
.slice(0, len); // return required number of characters
90+
}
91+
}
92+
93+
module.exports = basic256;

package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)