native-jwe 1.0.0
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/LICENSE +23 -0
- package/README.md +66 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +328 -0
- package/dist/index.js.map +1 -0
- package/package.json +25 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 thangngh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
Portions of this software are based on the work of https://github.com/psenger/jwe_example.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# In-House High-Performance JWE/JWS Core Engine
|
|
2
|
+
|
|
3
|
+
[](https://paypal.me/thangngh)
|
|
4
|
+
|
|
5
|
+
A high-performance JWE/JWS encryption/decryption and signing module, with zero dependencies (using only Node.js `crypto` & `zlib`), specifically optimized for multi-session IAM (Identity and Access Management) systems.
|
|
6
|
+
|
|
7
|
+
## 1. Design Philosophy
|
|
8
|
+
|
|
9
|
+
* **Zero-Dependency:** Utilizes only native Node.js `crypto` and `zlib` modules. Minimizes Supply Chain Attack risks and keeps the source code lean.
|
|
10
|
+
* **Low-Level Optimization:** Directly manipulates Buffers to optimize RAM and CPU usage.
|
|
11
|
+
* **Security First:** Hardened against common attack vectors such as DoS, Zip Bombs, Timing Attacks, and Information Leakage.
|
|
12
|
+
* **Robustness:** Prioritizes operational stability, fail-safe mechanisms, and resource protection.
|
|
13
|
+
|
|
14
|
+
## 2. Technical Architecture & Performance Optimization
|
|
15
|
+
|
|
16
|
+
This Core Engine is not just a simple wrapper; it applies deep processing techniques:
|
|
17
|
+
|
|
18
|
+
### ⚡ Direct Native Bindings (OpenSSL Support)
|
|
19
|
+
Instead of processing encryption logic with slow pure Javascript, all heavy tasks (`createCipheriv`, `publicEncrypt`, `verify`) are bound directly to the C++ OpenSSL layer of Node.js.
|
|
20
|
+
* => **Speed:** Comparable to compiled languages like Go/Rust for Crypto tasks.
|
|
21
|
+
|
|
22
|
+
### 🚀 Zero-Copy & Native Base64Url
|
|
23
|
+
The system **completely eliminates** manual regex string processing functions (which are memory-intensive and slow).
|
|
24
|
+
Instead, it uses the `Buffer.from(str, 'base64url')` API (Node.js native):
|
|
25
|
+
* Minimizes Intermediate Memory Allocation.
|
|
26
|
+
* Avoids Memory Fragmentation when handling thousands of concurrent requests.
|
|
27
|
+
|
|
28
|
+
### 🛡️ Memory Protection (First Line of Defense)
|
|
29
|
+
Before any logic runs, the system applies **"Hard Limits"**:
|
|
30
|
+
* **JWE Max Size:** 200KB.
|
|
31
|
+
* **JWS Max Size:** 50KB.
|
|
32
|
+
* **Zip Max Output:** 2MB.
|
|
33
|
+
* **Effect:** Prevents DoS attacks aiming for Out-Of-Memory (OOM) via large malicious payloads.
|
|
34
|
+
|
|
35
|
+
## 3. Security Hardening Features
|
|
36
|
+
|
|
37
|
+
The engine has been patched and fortified against the following vulnerabilities:
|
|
38
|
+
|
|
39
|
+
| Threat Vector | Technical Countermeasure |
|
|
40
|
+
| :--- | :--- |
|
|
41
|
+
| **Zip Bomb (DoS)** | Limits `gunzipSync` output to a maximum of 2MB. |
|
|
42
|
+
| **Information Leakage** | `decrypt` only returns a generic `DecryptionFailed` error. Does not reveal specific Header/Key errors to prevent Enumeration. |
|
|
43
|
+
| **Timing Attacks** | Uses safe comparison functions or appropriate fail-fast logic at the Header level. |
|
|
44
|
+
| **Downgrade Attacks** | Hardcodes the strongest algorithms `RSA-OAEP-256` and `AES-256-GCM`. Rejects all weaker algorithms. |
|
|
45
|
+
|
|
46
|
+
## 4. Operational Usage in IAM Systems
|
|
47
|
+
|
|
48
|
+
### Scenarios
|
|
49
|
+
1. **JWS (Signature):** Used as **Access Token** (short-term).
|
|
50
|
+
* *Location:* API Gateway.
|
|
51
|
+
* *Pros:* Extremely fast `verify`, high load tolerance.
|
|
52
|
+
2. **JWE (Encryption):** Used as **Refresh Token** or **Secure Cookie** (long-term).
|
|
53
|
+
* *Location:* Auth Service.
|
|
54
|
+
* *Pros:* Completely hides token structure, protects session information (Session ID) stored on Client.
|
|
55
|
+
|
|
56
|
+
### Best Practices
|
|
57
|
+
* **Key Management:** The module uses PEM keys. In Production, mount Keys from a Secret Manager (Vault/AWS/K8s Secrets) into RAM at startup; avoid hardcoding them.
|
|
58
|
+
* **Error Logging:** Although generic errors are returned to the Client, the system still logs details via `console.error`. Connect these logs to a Monitoring system (ELK, Loki) to detect attack signs.
|
|
59
|
+
|
|
60
|
+
## 5. Credits & Acknowledgments
|
|
61
|
+
This project is inspired by and based on portions of the work from [psenger/jwe_example](https://github.com/psenger/jwe_example).
|
|
62
|
+
|
|
63
|
+
## 6. License
|
|
64
|
+
MIT License.
|
|
65
|
+
|
|
66
|
+
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { KeyLike, PrivateKeyInput } from 'crypto';
|
|
2
|
+
export declare enum ZIP {
|
|
3
|
+
GZIP = "GZIP"
|
|
4
|
+
}
|
|
5
|
+
export interface JOSE {
|
|
6
|
+
alg: string;
|
|
7
|
+
/**
|
|
8
|
+
* The content of the message
|
|
9
|
+
*/
|
|
10
|
+
cty?: MEDIA_TYPES;
|
|
11
|
+
/**
|
|
12
|
+
* The public key to which the JWE was encrypted; this can be used to determine the private key needed to decrypt the JWE.
|
|
13
|
+
* @see https://tools.ietf.org/html/rfc7515#section-4.1.4
|
|
14
|
+
*/
|
|
15
|
+
kid?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface JWE_JOSE extends JOSE {
|
|
18
|
+
enc: string;
|
|
19
|
+
zip?: ZIP;
|
|
20
|
+
}
|
|
21
|
+
export interface JWS_JOSE extends JOSE {
|
|
22
|
+
}
|
|
23
|
+
export declare enum MEDIA_TYPES {
|
|
24
|
+
JSON = "json"
|
|
25
|
+
}
|
|
26
|
+
export interface JWE_OPTIONS {
|
|
27
|
+
zip?: ZIP;
|
|
28
|
+
cty: MEDIA_TYPES;
|
|
29
|
+
}
|
|
30
|
+
export declare const JWE: {
|
|
31
|
+
encrypt: (value: string, publicKey: KeyLike, options: JWE_OPTIONS) => string;
|
|
32
|
+
decrypt: (payload: string, privateKey: KeyLike, passphrase: string) => string;
|
|
33
|
+
};
|
|
34
|
+
export declare const JWS: {
|
|
35
|
+
decode: (jwsPayload: string) => string;
|
|
36
|
+
encode: (value: string, privateKey: PrivateKeyInput) => string;
|
|
37
|
+
verify: (jwsPayload: string, publicKey: string) => boolean;
|
|
38
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JWS = exports.JWE = exports.MEDIA_TYPES = exports.ZIP = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const zlib_1 = require("zlib");
|
|
6
|
+
var ZIP;
|
|
7
|
+
(function (ZIP) {
|
|
8
|
+
ZIP["GZIP"] = "GZIP";
|
|
9
|
+
})(ZIP || (exports.ZIP = ZIP = {}));
|
|
10
|
+
var MEDIA_TYPES;
|
|
11
|
+
(function (MEDIA_TYPES) {
|
|
12
|
+
MEDIA_TYPES["JSON"] = "json";
|
|
13
|
+
})(MEDIA_TYPES || (exports.MEDIA_TYPES = MEDIA_TYPES = {}));
|
|
14
|
+
/**
|
|
15
|
+
* a safer way to do toString on an object
|
|
16
|
+
* @param obj
|
|
17
|
+
*/
|
|
18
|
+
const toSafeString = function toSafeString(obj) {
|
|
19
|
+
if (typeof obj === 'string')
|
|
20
|
+
return obj;
|
|
21
|
+
if (typeof obj === 'number' || Buffer.isBuffer(obj))
|
|
22
|
+
return obj.toString();
|
|
23
|
+
return JSON.stringify(obj);
|
|
24
|
+
};
|
|
25
|
+
// Max size limits to protect RAM/CPU (IAM Performance & Security)
|
|
26
|
+
// JWEs can be larger due to encrypted payload + overhead.
|
|
27
|
+
const MAX_JWE_SIZE_BYTES = 200 * 1024; // 200KB limit for JWE
|
|
28
|
+
// JWS is usually smaller (header + payload + signature).
|
|
29
|
+
const MAX_JWS_SIZE_BYTES = 50 * 1024; // 50KB limit for JWS
|
|
30
|
+
/**
|
|
31
|
+
* a safer way to do toString on an object
|
|
32
|
+
* @param obj
|
|
33
|
+
*/
|
|
34
|
+
const isObject = function isObject(thing) {
|
|
35
|
+
return Object.prototype.toString.call(thing) === '[object Object]';
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Safe JSON parse...
|
|
39
|
+
* @param thing
|
|
40
|
+
*/
|
|
41
|
+
const safeJsonParse = function safeJsonParse(thing) {
|
|
42
|
+
if (isObject(thing))
|
|
43
|
+
return thing;
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(thing);
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Asymmetric Encrypt With Public Key
|
|
53
|
+
* @param value
|
|
54
|
+
* @param publicKey
|
|
55
|
+
*/
|
|
56
|
+
const AsymmetricEncryptWithPublicKey = function AsymmetricEncryptWithPublicKey(value, publicKey) {
|
|
57
|
+
// If key ( A PEM encoded public key ) is a string, it is treated as the
|
|
58
|
+
// key with no passphrase and will use RSA_PKCS1_OAEP_PADDING.
|
|
59
|
+
// We are passing as KeyLike Typescript object, which means
|
|
60
|
+
// we need to declare the padding.
|
|
61
|
+
const public_key = {
|
|
62
|
+
key: publicKey,
|
|
63
|
+
padding: crypto_1.constants.RSA_PKCS1_OAEP_PADDING
|
|
64
|
+
};
|
|
65
|
+
return (0, crypto_1.publicEncrypt)(public_key, value);
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Asymmetric Decrypt With Private Key
|
|
69
|
+
* @param value
|
|
70
|
+
* @param privateKey
|
|
71
|
+
* @param passphrase
|
|
72
|
+
*/
|
|
73
|
+
const AsymmetricDecryptWithPrivateKey = function AsymmetricDecryptWithPrivateKey(value, privateKey, passphrase) {
|
|
74
|
+
const private_key = {
|
|
75
|
+
key: privateKey,
|
|
76
|
+
passphrase,
|
|
77
|
+
// @todo: Still trying to establish why this is not working.
|
|
78
|
+
// oaepLabel: https://github.com/nodejs/help/issues/1726
|
|
79
|
+
// oaepHash: 'sha256', // this does not appear to work on Mac OSX with OpenSSL 1.0.1g 7 Apr 2014 or OpenSSL 1.1.1d 10 Sep 2019 ( via Brew )
|
|
80
|
+
padding: crypto_1.constants.RSA_PKCS1_OAEP_PADDING
|
|
81
|
+
};
|
|
82
|
+
return (0, crypto_1.privateDecrypt)(private_key, value);
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* JWE Decrypt
|
|
86
|
+
*
|
|
87
|
+
* When decrypting, particular care must be taken not to allow the JWE recipient to be used as an oracle for
|
|
88
|
+
* decrypting messages. RFC 3218 should be consulted for specific countermeasures to attacks on RSAES-PKCS1-v1_5.
|
|
89
|
+
*
|
|
90
|
+
* An attacker might modify the contents of the "alg" Header Parameter from "RSA-OAEP" to "RSA1_5" in order to
|
|
91
|
+
* generate a formatting error that can be detected and used to recover the CEK even if RSAES-OAEP was used to
|
|
92
|
+
* encrypt the CEK. It is therefore particularly important to report all formatting errors to the CEK, Additional
|
|
93
|
+
* Authenticated Data, or ciphertext as a single error when the encrypted content is rejected.
|
|
94
|
+
*
|
|
95
|
+
* Additionally, this type of attack can be prevented by restricting the use of a key to a limited set of
|
|
96
|
+
* algorithms -- usually one. This means, for instance, that if the key is marked as being for "RSA-OAEP" only,
|
|
97
|
+
* any attempt to decrypt a message using the "RSA1_5" algorithm with that key should fail immediately due to
|
|
98
|
+
* invalid use of the key.
|
|
99
|
+
*
|
|
100
|
+
* @param payload
|
|
101
|
+
* @param privateKey
|
|
102
|
+
* @param passphrase
|
|
103
|
+
*/
|
|
104
|
+
const decrypt = function decrypt(payload, privateKey, passphrase) {
|
|
105
|
+
// 1. First Line of Defense: Size Check
|
|
106
|
+
if (!payload || payload.length > MAX_JWE_SIZE_BYTES) {
|
|
107
|
+
throw new Error('JWE Size Check Failed'); // Protect RAM immediately
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
let joseStr;
|
|
111
|
+
let cekStr;
|
|
112
|
+
let ivStr;
|
|
113
|
+
let cipherTextStr;
|
|
114
|
+
let tagStr;
|
|
115
|
+
/**
|
|
116
|
+
* JOSE - Javascript Object Signing and Encryption Header
|
|
117
|
+
* CEK - Content Encryption Key ( Asymmetrically encrypted with the )
|
|
118
|
+
* IV - Initialization Vector
|
|
119
|
+
* cipherText - The Symmetrically encrypted payload of a UTF-8 String, with the mime type identified as `cty` in the JOSE
|
|
120
|
+
* tag - Auth tag is the message authentication code (MAC) calculated during the encryption
|
|
121
|
+
*/
|
|
122
|
+
[joseStr, cekStr, ivStr, cipherTextStr, tagStr] = payload.split('.');
|
|
123
|
+
// @TODO: need to exit here, if there are any values equal to null
|
|
124
|
+
// Native Node.js base64url decode (Zero-Regex, High Performance)
|
|
125
|
+
let jose = safeJsonParse(Buffer.from(joseStr, 'base64url').toString('utf8'));
|
|
126
|
+
// Security Logic: Information Leakage Prevention
|
|
127
|
+
// Validate headers internally but do NOT expose specific errors.
|
|
128
|
+
const isAlgValid = jose.alg === 'RSA-OAEP-256';
|
|
129
|
+
const isEncValid = jose.enc === 'A256GCM';
|
|
130
|
+
const isZipValid = !jose.zip || jose.zip === ZIP.GZIP;
|
|
131
|
+
if (!isAlgValid || !isEncValid || !isZipValid) {
|
|
132
|
+
console.error(`JWE Header Validation Failed: alg=${jose.alg}, enc=${jose.enc}, zip=${jose.zip}`);
|
|
133
|
+
throw new Error('JWE Header Validation Failed');
|
|
134
|
+
}
|
|
135
|
+
const cek = AsymmetricDecryptWithPrivateKey(Buffer.from(cekStr, 'base64url'), privateKey, passphrase);
|
|
136
|
+
const decipher = (0, crypto_1.createDecipheriv)('aes-256-gcm', cek, Buffer.from(ivStr, 'base64url'));
|
|
137
|
+
/**
|
|
138
|
+
* When using an authenticated encryption mode ( like GCM ),
|
|
139
|
+
* the decipher.setAuthTag() method is used to pass in the received authentication tag. If no tag is
|
|
140
|
+
* provided, or if the cipher text has been tampered with, decipher.final() will throw, indicating
|
|
141
|
+
* that the cipher text should be discarded due to failed authentication. If the tag length is
|
|
142
|
+
* invalid according to NIST SP 800-38D or does not match the value of the authTagLength option,
|
|
143
|
+
* decipher.setAuthTag() will throw an error.
|
|
144
|
+
*
|
|
145
|
+
* The decipher.setAuthTag() method must be called before decipher.final() and can only be called once.
|
|
146
|
+
*/
|
|
147
|
+
decipher.setAuthTag(Buffer.from(tagStr, 'base64url'));
|
|
148
|
+
decipher.setAAD(Buffer.from(toSafeString(jose), 'utf8'));
|
|
149
|
+
let text = Buffer.concat([decipher.update(Buffer.from(cipherTextStr, 'base64url')), decipher.final()]);
|
|
150
|
+
if (jose.zip && jose.zip === ZIP.GZIP) {
|
|
151
|
+
// Added maxOutputLength to prevent Zip Bomb attacks (DoS).
|
|
152
|
+
// Limiting the uncompressed JSON payload to 2MB.
|
|
153
|
+
return (0, zlib_1.gunzipSync)(text, {
|
|
154
|
+
level: zlib_1.constants.Z_BEST_COMPRESSION,
|
|
155
|
+
maxOutputLength: 2 * 1024 * 1024
|
|
156
|
+
}).toString('utf8');
|
|
157
|
+
}
|
|
158
|
+
return text.toString('utf8');
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
console.error(e);
|
|
162
|
+
// Generic Error for all failure cases to prevent Information Leakage
|
|
163
|
+
throw new Error('DecryptionFailed');
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const encrypt = function encrypt(value, publicKey, options) {
|
|
167
|
+
// RSA-OAEP-256 - RSAES OAEP using SHA-256 and MGF1 with SHA-256
|
|
168
|
+
// @see https://www.rfc-editor.org/rfc/rfc7518#section-4.3
|
|
169
|
+
const alg = 'RSA-OAEP-256';
|
|
170
|
+
// AES 256 GCM - encryption of the content.
|
|
171
|
+
const enc = 'A256GCM';
|
|
172
|
+
/**
|
|
173
|
+
* Javascript Object Signing and Encryption (JOSE ) - describe the encryption
|
|
174
|
+
* applied to the plaintext and optionally additional properties of the JWE.
|
|
175
|
+
*/
|
|
176
|
+
const jose = { alg, enc };
|
|
177
|
+
/**
|
|
178
|
+
* Optional the body zip type, should be omitted from the JOSE to indicate no compression
|
|
179
|
+
*/
|
|
180
|
+
if (options && options.zip) {
|
|
181
|
+
if (options.zip !== ZIP.GZIP) {
|
|
182
|
+
throw new Error(`Unsupported "zip" detected in JOSE. currently only "${ZIP.GZIP}" supported`);
|
|
183
|
+
}
|
|
184
|
+
jose.zip = ZIP.GZIP;
|
|
185
|
+
}
|
|
186
|
+
if (options && options.cty !== MEDIA_TYPES.JSON) {
|
|
187
|
+
throw new Error(`Unsupported "cty" detected in JOSE. currently only "${MEDIA_TYPES.JSON}" supported`);
|
|
188
|
+
}
|
|
189
|
+
jose.cty = MEDIA_TYPES.JSON;
|
|
190
|
+
/**
|
|
191
|
+
* Content Encryption Key (CEK) - ( this is the symmetrical key, which will later be
|
|
192
|
+
* encrypted asymmetrically ) A new symmetric key generated to encrypt the Plaintext
|
|
193
|
+
* for the recipient to produce the Ciphertext, which is encrypted to the recipient as
|
|
194
|
+
* the JWE Encrypted Key. 32 Bytes = 256 bits
|
|
195
|
+
*/
|
|
196
|
+
const cek = (0, crypto_1.randomBytes)(32);
|
|
197
|
+
if (cek.length !== 32)
|
|
198
|
+
throw new Error('AES Key Must be 256 bytes (32 characters)');
|
|
199
|
+
/**
|
|
200
|
+
* JWE Initialization Vector
|
|
201
|
+
* The bit block size of the encryption algorithm dictates the
|
|
202
|
+
* Byte size of the IV. eg: A128GCM is 128 Bits = 16 Bytes and 256 Bits would be 32
|
|
203
|
+
*/
|
|
204
|
+
const iv = (0, crypto_1.randomBytes)(32);
|
|
205
|
+
/**
|
|
206
|
+
* aes-256-cgm - Advanced Encryption Standard (AES) in Galois/Counter Mode (GCM)
|
|
207
|
+
* AES-GCM is a more secure cipher than AES-CBC, because AES-CBC, operates by XOR'ing
|
|
208
|
+
* each block with the previous block and cannot be written in parallel and
|
|
209
|
+
* Initialization Vector is required because AES is a Block Encryption method.
|
|
210
|
+
* AES is a block cipher mode type of encryption
|
|
211
|
+
*/
|
|
212
|
+
const cipher = (0, crypto_1.createCipheriv)('aes-256-gcm', cek, iv);
|
|
213
|
+
/**
|
|
214
|
+
* When using an authenticated encryption mode (GCM, CCM and OCB are currently supported), the cipher.setAAD()
|
|
215
|
+
* method sets the value used for the additional authenticated data (AAD) input parameter.
|
|
216
|
+
*
|
|
217
|
+
* The options argument is optional for GCM and OCB. When using CCM, the plaintextLength option must be
|
|
218
|
+
* specified and its value must match the length of the plaintext in bytes. See CCM mode.
|
|
219
|
+
*
|
|
220
|
+
* The cipher.setAAD() method must be called before cipher.update().
|
|
221
|
+
*/
|
|
222
|
+
cipher.setAAD(Buffer.from(toSafeString(jose), 'utf8'));
|
|
223
|
+
let content;
|
|
224
|
+
if (options && options.zip && options.zip === ZIP.GZIP) {
|
|
225
|
+
content = cipher.update((0, zlib_1.gzipSync)(value, {
|
|
226
|
+
level: zlib_1.constants.Z_BEST_COMPRESSION
|
|
227
|
+
}));
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
content = cipher.update(value);
|
|
231
|
+
}
|
|
232
|
+
const cipherText = Buffer.concat([content, cipher.final()]);
|
|
233
|
+
/**
|
|
234
|
+
* When using an authenticated encryption mode ( like GCM ), cipher.getAuthTag() method
|
|
235
|
+
* returns a Buffer containing the authentication tag that has been computed from the given data.
|
|
236
|
+
*
|
|
237
|
+
* Message Authentication Code (MAC)
|
|
238
|
+
*
|
|
239
|
+
* The cipher.getAuthTag() method should only be called after encryption has been completed using the
|
|
240
|
+
* cipher.final() method.
|
|
241
|
+
*/
|
|
242
|
+
const tag = cipher.getAuthTag();
|
|
243
|
+
const ecek = AsymmetricEncryptWithPublicKey(cek, publicKey); // we asymmetrically encrypt the key with the users Public Key.
|
|
244
|
+
// @todo: I think it would be best, if we make sure the output is ASCII
|
|
245
|
+
// Buffer.from( '').toString('ascii')
|
|
246
|
+
// Use native base64url encoding for speed
|
|
247
|
+
return `${Buffer.from(toSafeString(jose), 'utf8').toString('base64url')}.${ecek.toString('base64url')}.${iv.toString('base64url')}.${cipherText.toString('base64url')}.${tag.toString('base64url')}`;
|
|
248
|
+
};
|
|
249
|
+
/**
|
|
250
|
+
* Generate a JWS Token
|
|
251
|
+
* @param value
|
|
252
|
+
* @param privateKey
|
|
253
|
+
*/
|
|
254
|
+
const encode = function encode(value, privateKey) {
|
|
255
|
+
// while HMAC-SHA256 is by far better than RSA-SHA256. It would require a private key by both parties. Therefore,
|
|
256
|
+
// we will use RSA and exchange Public Keys.
|
|
257
|
+
const signature = (0, crypto_1.createSign)('RSA-SHA256');
|
|
258
|
+
/**
|
|
259
|
+
* Javascript Object Signing and Encryption (JOSE ) - describe the encryption
|
|
260
|
+
* applied to the plaintext and optionally additional properties of the JWE.
|
|
261
|
+
*/
|
|
262
|
+
const jose = { alg: 'RSA-SHA256' };
|
|
263
|
+
const joseAndValue = `${Buffer.from(toSafeString(jose), 'utf8').toString('base64url')}.${Buffer.from(value, 'utf8').toString('base64url')}`;
|
|
264
|
+
/**
|
|
265
|
+
* Compute the JWS Signature with RSA-SHA256
|
|
266
|
+
*
|
|
267
|
+
* ASCII( BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload) )
|
|
268
|
+
*
|
|
269
|
+
* The "alg" (algorithm) Header Parameter
|
|
270
|
+
* MUST be present in the JOSE Header, with the algorithm value
|
|
271
|
+
* accurately representing the algorithm used to construct the JWS
|
|
272
|
+
* Signature.
|
|
273
|
+
*/
|
|
274
|
+
signature.write(joseAndValue);
|
|
275
|
+
signature.end();
|
|
276
|
+
// Native base64url output
|
|
277
|
+
const base64Signature = signature.sign(privateKey, 'base64url');
|
|
278
|
+
return `${joseAndValue}.${base64Signature}`;
|
|
279
|
+
};
|
|
280
|
+
/**
|
|
281
|
+
* Verify the Payload is signed correctly.
|
|
282
|
+
* @param jwsPayload
|
|
283
|
+
* @param publicKey
|
|
284
|
+
*/
|
|
285
|
+
const verify = function verify(jwsPayload, publicKey) {
|
|
286
|
+
if (!jwsPayload || jwsPayload.length > MAX_JWS_SIZE_BYTES)
|
|
287
|
+
return false;
|
|
288
|
+
try {
|
|
289
|
+
const [joseStr, message, sig] = jwsPayload.split('.');
|
|
290
|
+
// Ensure encoded parts are valid strings before parsing
|
|
291
|
+
if (!joseStr || !message || !sig)
|
|
292
|
+
return false;
|
|
293
|
+
const jose = JSON.parse(Buffer.from(joseStr, 'base64url').toString('utf8'));
|
|
294
|
+
// Strict check: return false if algorithm is not RSA-SHA256
|
|
295
|
+
if (!jose || !jose.alg || jose.alg !== 'RSA-SHA256') {
|
|
296
|
+
console.error(`JWS Verification Failed: Unsupported alg ${jose?.alg}`);
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
const verify = (0, crypto_1.createVerify)(jose.alg);
|
|
300
|
+
verify.write(`${joseStr}.${message}`);
|
|
301
|
+
verify.end();
|
|
302
|
+
return verify.verify(publicKey, sig, 'base64url');
|
|
303
|
+
}
|
|
304
|
+
catch (e) {
|
|
305
|
+
console.error('JWS Verification Error:', e);
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
/**
|
|
310
|
+
* Extract the message from the JwsPayload.
|
|
311
|
+
* @param jwsPayload
|
|
312
|
+
*/
|
|
313
|
+
const decode = function decode(jwsPayload) {
|
|
314
|
+
if (!jwsPayload || jwsPayload.length > MAX_JWS_SIZE_BYTES)
|
|
315
|
+
return '';
|
|
316
|
+
const [, message,] = jwsPayload.split('.');
|
|
317
|
+
return Buffer.from(message, 'base64url').toString('utf8');
|
|
318
|
+
};
|
|
319
|
+
exports.JWE = {
|
|
320
|
+
encrypt,
|
|
321
|
+
decrypt
|
|
322
|
+
};
|
|
323
|
+
exports.JWS = {
|
|
324
|
+
decode,
|
|
325
|
+
encode,
|
|
326
|
+
verify
|
|
327
|
+
};
|
|
328
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "native-jwe",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
11
|
+
"pretest": "npm run prepare",
|
|
12
|
+
"prepare": "tsc"
|
|
13
|
+
},
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"funding": {
|
|
17
|
+
"type": "paypal",
|
|
18
|
+
"url": "https://paypal.me/thangngh"
|
|
19
|
+
},
|
|
20
|
+
"description": "",
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^25.0.5",
|
|
23
|
+
"typescript": "^5.9.3"
|
|
24
|
+
}
|
|
25
|
+
}
|