express-jcrypt 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
File without changes
package/index.js ADDED
@@ -0,0 +1,18 @@
1
+ const keyPair = require('../keyPair');
2
+ const cipher = require('../cipher');
3
+ const authTag = require('../authtag');
4
+ const generateIV = require('../iv');
5
+ const { encode, decode } = require('../base64url');
6
+
7
+
8
+ module.exports = {
9
+ keyPair,
10
+ cipher,
11
+ authTag,
12
+ generateIV,
13
+ encode,
14
+ decode,
15
+ undecipher,
16
+ encryptCEK,
17
+ decryptCEK,
18
+ }
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "express-jcrypt",
3
+ "version": "1.0.1",
4
+ "description": "jwe",
5
+ "keywords": [],
6
+ "homepage": "https://github.com/pdotexe/Jcrypt#readme",
7
+ "bugs": {
8
+ "url": "https://github.com/pdotexe/Jcrypt/issues"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/pdotexe/Jcrypt.git"
13
+ },
14
+ "license": "MIT",
15
+ "author": "prestigiouss",
16
+ "type": "module",
17
+ "main": "index.js",
18
+ "scripts": {
19
+ "start": "node index.js",
20
+ "test": "echo \"Error: no test specified\" && exit 1"
21
+ },
22
+ "dependencies": {
23
+ "acorn": "^8.16.0",
24
+ "acorn-walk": "^8.3.5",
25
+ "arg": "^4.1.3",
26
+ "create-require": "^1.1.1",
27
+ "diff": "^4.0.4",
28
+ "make-error": "^1.3.6",
29
+ "ts-node": "^10.9.2",
30
+ "typescript": "^5.9.3",
31
+ "undici-types": "^6.21.0",
32
+ "v8-compile-cache-lib": "^3.0.1",
33
+ "yn": "^3.1.1"
34
+ },
35
+ "devDependencies": {}
36
+ }
package/src/authtag.js ADDED
@@ -0,0 +1,15 @@
1
+ const crypto = require('crypto');
2
+
3
+
4
+
5
+ /**
6
+ *
7
+ * @param {*} cipher
8
+ * @returns - Authentication tag of whichever cipher used to ensure integrity of data.
9
+ */
10
+ const authTag = (cipher) => {
11
+ if (!cipher || typeof cipher.getAuthTag !== 'function') throw new Error(" Invalid cipher object");
12
+ return cipher.getAuthTag();
13
+ }
14
+
15
+ module.exports = authTag;
@@ -0,0 +1,28 @@
1
+ // concise function call for base64url encoding and decoding
2
+
3
+
4
+ /**
5
+ * @description - Converts buffer to URL safe string
6
+ * @param {Buffer | string} buffer - The input buffer to be encoded.
7
+ * @returns {string | null} - Encoded buffer string if buffer exists.
8
+ */
9
+ const encode = (buffer) => {
10
+ if (!buffer) return null;
11
+
12
+ return Buffer.from(buffer).toString('base64url');
13
+
14
+ };
15
+
16
+ /**
17
+ * @param {Buffer | string} encoded - Input string to decode
18
+ * @returns {Buffer | null} - Decoded buffer if input exists.
19
+ */
20
+ const decode = (encoded) => {
21
+ if (!encoded) return null;
22
+
23
+ return Buffer.from(encoded, 'base64url');
24
+ };
25
+
26
+
27
+
28
+ module.exports = { encode, decode };
package/src/cipher.js ADDED
@@ -0,0 +1,46 @@
1
+ import generateIV from './iv.js';
2
+ const crypto = require('crypto');
3
+ const authTag = require('./authtag.js');
4
+
5
+ /**
6
+ * @description - literal encryption function that takes plaintext and public key, generates random IV, CEK, and encrypts using AES-256-GCM.
7
+ * @param {string} plaintext - The data to be encrypted
8
+ */
9
+
10
+ const generateCEK = () => crypto.randomBytes(32);
11
+
12
+ const encryptCEK = (contentEncKey, publicKey) => {
13
+ const cekEncrypt = crypto.publicEncrypt(publicKey, contentEncKey);
14
+ return cekEncrypt;
15
+ };
16
+ const decryptCEK = (encryptedCEK, privateKey, secretPassphrase) => {
17
+ const cekDecrypt = crypto.privateDecrypt(privateKey, encryptedCEK);
18
+ return cekDecrypt;
19
+ }
20
+
21
+ const cipher = (plaintext) => {
22
+ const cek = generateCEK();
23
+
24
+ const iv = generateIV(); // initialization vector
25
+ const enc = crypto.createCipheriv('aes-256-gcm', cek, iv); // actual encryption
26
+ const ciphertext = Buffer.concat([enc.update(plaintext, 'utf8'), enc.final()]); // convert to utf8 and concatenate
27
+ const tag = authTag(enc);
28
+
29
+ return { ciphertext, iv, tag, cek };
30
+
31
+
32
+ }
33
+
34
+ const decipher = (ciphertext, iv, tag, cek) => {
35
+ const undecipher = crypto.createDecipheriv('aes-256-gcm', cek, iv);
36
+ const deciphertag = authTag(undecipher);
37
+ if (deciphertag.equals(tag)) {
38
+ const decrypted = Buffer.concat([undecipher.update(ciphertext), undecipher.final()]);
39
+ return decrypted.toString('utf8');
40
+ }
41
+ else {
42
+ throw new Error('Invalid authentication tag');
43
+ }
44
+ }
45
+
46
+ module.exports = { cipher, encryptCEK, decryptCEK, decipher };
package/src/iv.js ADDED
@@ -0,0 +1,25 @@
1
+ import crypto from 'crypto';
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+ /**
10
+ * @description - Generates random initialization vector for AES-256-GCM to add unique encryption values each time.
11
+ * @property {number} iv - IV value
12
+ * @returns {Buffer} - Randomly generated IV buffer
13
+ */
14
+ const generateIV = () => {
15
+
16
+ const length = 12; // AES256GCM nonce size
17
+
18
+ const iv = crypto.randomBytes(length);
19
+
20
+
21
+ return iv;
22
+ }
23
+
24
+
25
+ module.exports = generateIV;
package/src/key.js ADDED
@@ -0,0 +1,78 @@
1
+
2
+ import { generateKeyPair } from 'crypto';
3
+ import { writeFileSync } from 'fs';
4
+
5
+
6
+ /**
7
+ * @typedef {Object} KeyPairOptions
8
+ * @property {number} modulusLength - RSA key length in bits
9
+ * @property {'spki'} publicKeyType - Public key encoding type
10
+ * @property {'pkcs8'} privateKeyType - Private key encoding type
11
+ * @property {string} [passphrase] - Optional passphrase for private key
12
+ * @property {Function} generateKeys - Instant key generation upon object instantiation
13
+ */
14
+ class keyPair {
15
+
16
+
17
+ /**
18
+ * @param {KeyPairOptions} options
19
+ */
20
+
21
+
22
+
23
+
24
+ constructor(options) {
25
+ if(!options || typeof options !== 'object') throw new Error();
26
+ this.modulusLength = Number(options.modulusLength || 2048);
27
+ if(this.modulusLength < 2048) throw new Error("Modulus length must be at least 2048 bits");
28
+ this.publicKeyType = 'spki';
29
+ this.privateKeyType = String(options.privateKeyType || 'pkcs8');
30
+ this.passphrase = options.passphrase ? String(options.passphrase) : undefined;
31
+
32
+ }
33
+ /**
34
+ * @description - Generates RSA key pair using crypto module's generateKeyPair function
35
+ * @throws Error if key generation fails
36
+ * @returns {Promise<{publicKey, privateKey}>} - Resolves generated key pair
37
+ */
38
+ generateKeys() {
39
+ return new Promise((resolve, reject) => {
40
+ const privateKeyEncoding = {
41
+ type: this.privateKeyType,
42
+ format: 'pem',
43
+ }
44
+ if (this.passphrase){
45
+ privateKeyEncoding.cipher = 'aes-256-cbc';
46
+ privateKeyEncoding.passphrase = this.passphrase;
47
+ }
48
+
49
+ const publicKeyEncoding = {
50
+ type: this.publicKeyType,
51
+ format: 'pem',
52
+ }
53
+
54
+ generateKeyPair(
55
+ 'rsa',
56
+ {
57
+ modulusLength: this.modulusLength,
58
+ publicKeyEncoding: publicKeyEncoding,
59
+ publicExponent: 0x10001,
60
+ privateKeyEncoding: privateKeyEncoding,
61
+
62
+ }, (err, publicKey, privateKey) => {
63
+ if (err) return reject(err);
64
+ /*
65
+ @description: Logs keys to console for readability and verification
66
+ */
67
+ resolve({publicKey, privateKey});
68
+
69
+
70
+ });
71
+ });
72
+ }
73
+ }
74
+
75
+
76
+
77
+
78
+ module.exports = keyPair;
@@ -0,0 +1,17 @@
1
+
2
+ /**
3
+ * @description - metadata containing algorithm and encryption method for JWE header.
4
+ * @returns {Buffer} - Buffer with JSON stringified protected JWE header.
5
+ */
6
+
7
+ const protectedHeader = (alg = "RSA-OAEP-256", enc = "AES-256-GCM", type = "JWE", kid) => {
8
+ const header = {alg, enc};
9
+ if (type) header.typ = type;
10
+ if (kid) header.kid = kid;
11
+
12
+ stringifyHeader = JSON.stringify(header);
13
+ return Buffer.from(stringifyHeader);
14
+ }
15
+
16
+
17
+ module.exports = protectedHeader;