@gjsify/crypto 0.1.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/README.md +27 -0
- package/lib/esm/asn1.js +504 -0
- package/lib/esm/bigint-math.js +34 -0
- package/lib/esm/cipher.js +1272 -0
- package/lib/esm/constants.js +15 -0
- package/lib/esm/crypto-utils.js +47 -0
- package/lib/esm/dh.js +411 -0
- package/lib/esm/ecdh.js +356 -0
- package/lib/esm/ecdsa.js +125 -0
- package/lib/esm/hash.js +100 -0
- package/lib/esm/hkdf.js +58 -0
- package/lib/esm/hmac.js +93 -0
- package/lib/esm/index.js +158 -0
- package/lib/esm/key-object.js +330 -0
- package/lib/esm/mgf1.js +27 -0
- package/lib/esm/pbkdf2.js +68 -0
- package/lib/esm/public-encrypt.js +175 -0
- package/lib/esm/random.js +138 -0
- package/lib/esm/rsa-oaep.js +95 -0
- package/lib/esm/rsa-pss.js +100 -0
- package/lib/esm/scrypt.js +134 -0
- package/lib/esm/sign.js +248 -0
- package/lib/esm/timing-safe-equal.js +13 -0
- package/lib/esm/x509.js +214 -0
- package/lib/types/asn1.d.ts +87 -0
- package/lib/types/bigint-math.d.ts +13 -0
- package/lib/types/cipher.d.ts +84 -0
- package/lib/types/constants.d.ts +10 -0
- package/lib/types/crypto-utils.d.ts +22 -0
- package/lib/types/dh.d.ts +79 -0
- package/lib/types/ecdh.d.ts +96 -0
- package/lib/types/ecdsa.d.ts +21 -0
- package/lib/types/hash.d.ts +25 -0
- package/lib/types/hkdf.d.ts +9 -0
- package/lib/types/hmac.d.ts +20 -0
- package/lib/types/index.d.ts +105 -0
- package/lib/types/key-object.d.ts +36 -0
- package/lib/types/mgf1.d.ts +5 -0
- package/lib/types/pbkdf2.d.ts +9 -0
- package/lib/types/public-encrypt.d.ts +42 -0
- package/lib/types/random.d.ts +22 -0
- package/lib/types/rsa-oaep.d.ts +8 -0
- package/lib/types/rsa-pss.d.ts +8 -0
- package/lib/types/scrypt.d.ts +11 -0
- package/lib/types/sign.d.ts +61 -0
- package/lib/types/timing-safe-equal.d.ts +6 -0
- package/lib/types/x509.d.ts +72 -0
- package/package.json +45 -0
- package/src/asn1.ts +797 -0
- package/src/bigint-math.ts +45 -0
- package/src/cipher.spec.ts +332 -0
- package/src/cipher.ts +952 -0
- package/src/constants.ts +16 -0
- package/src/crypto-utils.ts +64 -0
- package/src/dh.spec.ts +111 -0
- package/src/dh.ts +761 -0
- package/src/ecdh.spec.ts +116 -0
- package/src/ecdh.ts +624 -0
- package/src/ecdsa.ts +243 -0
- package/src/extended.spec.ts +444 -0
- package/src/gcm.spec.ts +141 -0
- package/src/hash.spec.ts +86 -0
- package/src/hash.ts +119 -0
- package/src/hkdf.ts +99 -0
- package/src/hmac.spec.ts +64 -0
- package/src/hmac.ts +123 -0
- package/src/index.ts +93 -0
- package/src/key-object.spec.ts +202 -0
- package/src/key-object.ts +401 -0
- package/src/mgf1.ts +37 -0
- package/src/pbkdf2.spec.ts +76 -0
- package/src/pbkdf2.ts +106 -0
- package/src/public-encrypt.ts +288 -0
- package/src/random.spec.ts +133 -0
- package/src/random.ts +183 -0
- package/src/rsa-oaep.ts +167 -0
- package/src/rsa-pss.ts +190 -0
- package/src/scrypt.spec.ts +90 -0
- package/src/scrypt.ts +191 -0
- package/src/sign.spec.ts +160 -0
- package/src/sign.ts +319 -0
- package/src/test.mts +19 -0
- package/src/timing-safe-equal.ts +21 -0
- package/src/x509.spec.ts +210 -0
- package/src/x509.ts +262 -0
- package/tsconfig.json +31 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// BigInt math utilities for GJS — original implementation
|
|
2
|
+
// Centralizes modular exponentiation and BigInt-to-bytes conversion
|
|
3
|
+
// used across sign, rsa-pss, rsa-oaep, public-encrypt, ecdsa, ecdh, and dh modules.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Modular exponentiation using square-and-multiply (BigInt).
|
|
7
|
+
* Returns (base ** exp) % mod.
|
|
8
|
+
*/
|
|
9
|
+
export function modPow(base: bigint, exp: bigint, mod: bigint): bigint {
|
|
10
|
+
if (mod === 1n) return 0n;
|
|
11
|
+
base = ((base % mod) + mod) % mod;
|
|
12
|
+
let result = 1n;
|
|
13
|
+
while (exp > 0n) {
|
|
14
|
+
if (exp & 1n) {
|
|
15
|
+
result = (result * base) % mod;
|
|
16
|
+
}
|
|
17
|
+
exp >>= 1n;
|
|
18
|
+
base = (base * base) % mod;
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Convert a BigInt to a big-endian Uint8Array of exactly `length` bytes.
|
|
25
|
+
*/
|
|
26
|
+
export function bigIntToBytes(value: bigint, length: number): Uint8Array {
|
|
27
|
+
const result = new Uint8Array(length);
|
|
28
|
+
let v = value;
|
|
29
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
30
|
+
result[i] = Number(v & 0xffn);
|
|
31
|
+
v >>= 8n;
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Convert a Uint8Array (big-endian) to a non-negative BigInt.
|
|
38
|
+
*/
|
|
39
|
+
export function bytesToBigInt(bytes: Uint8Array): bigint {
|
|
40
|
+
let result = 0n;
|
|
41
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
42
|
+
result = (result << 8n) | BigInt(bytes[i]);
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { describe, it, expect } from '@gjsify/unit';
|
|
2
|
+
import { createCipheriv, createDecipheriv, getCiphers } from 'node:crypto';
|
|
3
|
+
import { Buffer } from 'node:buffer';
|
|
4
|
+
|
|
5
|
+
export default async () => {
|
|
6
|
+
|
|
7
|
+
// --- getCiphers ---
|
|
8
|
+
await describe('crypto.getCiphers', async () => {
|
|
9
|
+
await it('should return an array of cipher names', async () => {
|
|
10
|
+
const ciphers = getCiphers();
|
|
11
|
+
expect(Array.isArray(ciphers)).toBe(true);
|
|
12
|
+
expect(ciphers.length).toBeGreaterThan(0);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
await it('should include AES-CBC ciphers', async () => {
|
|
16
|
+
const ciphers = getCiphers();
|
|
17
|
+
expect(ciphers).toContain('aes-128-cbc');
|
|
18
|
+
expect(ciphers).toContain('aes-192-cbc');
|
|
19
|
+
expect(ciphers).toContain('aes-256-cbc');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
await it('should include AES-CTR ciphers', async () => {
|
|
23
|
+
const ciphers = getCiphers();
|
|
24
|
+
expect(ciphers).toContain('aes-128-ctr');
|
|
25
|
+
expect(ciphers).toContain('aes-256-ctr');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
await it('should include AES-ECB ciphers', async () => {
|
|
29
|
+
const ciphers = getCiphers();
|
|
30
|
+
expect(ciphers).toContain('aes-128-ecb');
|
|
31
|
+
expect(ciphers).toContain('aes-256-ecb');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await it('should return only strings', async () => {
|
|
35
|
+
const ciphers = getCiphers();
|
|
36
|
+
for (const c of ciphers) {
|
|
37
|
+
expect(typeof c).toBe('string');
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// --- AES-256-CBC round-trip ---
|
|
43
|
+
await describe('crypto.createCipheriv / createDecipheriv (AES-256-CBC)', async () => {
|
|
44
|
+
const algorithm = 'aes-256-cbc';
|
|
45
|
+
const key = Buffer.from('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', 'hex');
|
|
46
|
+
const iv = Buffer.from('00112233445566778899aabbccddeeff', 'hex');
|
|
47
|
+
|
|
48
|
+
await it('should encrypt and decrypt a simple string', async () => {
|
|
49
|
+
const cipher = createCipheriv(algorithm, key, iv);
|
|
50
|
+
let encrypted = cipher.update('Hello World!', 'utf8', 'hex');
|
|
51
|
+
encrypted += cipher.final('hex');
|
|
52
|
+
|
|
53
|
+
expect(typeof encrypted).toBe('string');
|
|
54
|
+
expect(encrypted.length).toBeGreaterThan(0);
|
|
55
|
+
|
|
56
|
+
const decipher = createDecipheriv(algorithm, key, iv);
|
|
57
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
58
|
+
decrypted += decipher.final('utf8');
|
|
59
|
+
|
|
60
|
+
expect(decrypted).toBe('Hello World!');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await it('should encrypt and decrypt with Buffer input/output', async () => {
|
|
64
|
+
const plaintext = Buffer.from('Buffer round-trip test');
|
|
65
|
+
|
|
66
|
+
const cipher = createCipheriv(algorithm, key, iv);
|
|
67
|
+
const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
68
|
+
|
|
69
|
+
expect(encrypted.length).toBeGreaterThan(0);
|
|
70
|
+
|
|
71
|
+
const decipher = createDecipheriv(algorithm, key, iv);
|
|
72
|
+
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
|
|
73
|
+
|
|
74
|
+
expect(decrypted.toString('utf8')).toBe('Buffer round-trip test');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
await it('should handle empty string', async () => {
|
|
78
|
+
const cipher = createCipheriv(algorithm, key, iv);
|
|
79
|
+
let encrypted = cipher.update('', 'utf8', 'hex');
|
|
80
|
+
encrypted += cipher.final('hex');
|
|
81
|
+
|
|
82
|
+
const decipher = createDecipheriv(algorithm, key, iv);
|
|
83
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
84
|
+
decrypted += decipher.final('utf8');
|
|
85
|
+
|
|
86
|
+
expect(decrypted).toBe('');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
await it('should handle block-aligned data (16 bytes)', async () => {
|
|
90
|
+
const plaintext = 'Exactly16bytes!!'; // 16 bytes
|
|
91
|
+
const cipher = createCipheriv(algorithm, key, iv);
|
|
92
|
+
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
|
|
93
|
+
encrypted += cipher.final('hex');
|
|
94
|
+
|
|
95
|
+
const decipher = createDecipheriv(algorithm, key, iv);
|
|
96
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
97
|
+
decrypted += decipher.final('utf8');
|
|
98
|
+
|
|
99
|
+
expect(decrypted).toBe(plaintext);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await it('should handle multi-block data', async () => {
|
|
103
|
+
const plaintext = 'This is a longer message that spans multiple AES blocks for testing purposes!';
|
|
104
|
+
const cipher = createCipheriv(algorithm, key, iv);
|
|
105
|
+
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
|
|
106
|
+
encrypted += cipher.final('hex');
|
|
107
|
+
|
|
108
|
+
const decipher = createDecipheriv(algorithm, key, iv);
|
|
109
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
110
|
+
decrypted += decipher.final('utf8');
|
|
111
|
+
|
|
112
|
+
expect(decrypted).toBe(plaintext);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
await it('should fail to decrypt with wrong key', async () => {
|
|
116
|
+
const cipher = createCipheriv(algorithm, key, iv);
|
|
117
|
+
let encrypted = cipher.update('secret data', 'utf8', 'hex');
|
|
118
|
+
encrypted += cipher.final('hex');
|
|
119
|
+
|
|
120
|
+
const wrongKey = Buffer.from('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 'hex');
|
|
121
|
+
const decipher = createDecipheriv(algorithm, wrongKey, iv);
|
|
122
|
+
let threw = false;
|
|
123
|
+
try {
|
|
124
|
+
decipher.update(encrypted, 'hex', 'utf8');
|
|
125
|
+
decipher.final('utf8');
|
|
126
|
+
} catch (e) {
|
|
127
|
+
threw = true;
|
|
128
|
+
}
|
|
129
|
+
// Wrong key should produce garbage or throw (padding error)
|
|
130
|
+
expect(threw).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
await it('should produce different ciphertext with different IVs', async () => {
|
|
134
|
+
const plaintext = 'Same plaintext';
|
|
135
|
+
const iv2 = Buffer.from('ffeeddccbbaa99887766554433221100', 'hex');
|
|
136
|
+
|
|
137
|
+
const cipher1 = createCipheriv(algorithm, key, iv);
|
|
138
|
+
let enc1 = cipher1.update(plaintext, 'utf8', 'hex');
|
|
139
|
+
enc1 += cipher1.final('hex');
|
|
140
|
+
|
|
141
|
+
const cipher2 = createCipheriv(algorithm, key, iv2);
|
|
142
|
+
let enc2 = cipher2.update(plaintext, 'utf8', 'hex');
|
|
143
|
+
enc2 += cipher2.final('hex');
|
|
144
|
+
|
|
145
|
+
expect(enc1 !== enc2).toBe(true);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// --- AES-128-CBC round-trip ---
|
|
150
|
+
await describe('crypto.createCipheriv / createDecipheriv (AES-128-CBC)', async () => {
|
|
151
|
+
const algorithm = 'aes-128-cbc';
|
|
152
|
+
const key = Buffer.from('0123456789abcdef0123456789abcdef', 'hex');
|
|
153
|
+
const iv = Buffer.from('00112233445566778899aabbccddeeff', 'hex');
|
|
154
|
+
|
|
155
|
+
await it('should encrypt and decrypt', async () => {
|
|
156
|
+
const cipher = createCipheriv(algorithm, key, iv);
|
|
157
|
+
let encrypted = cipher.update('AES-128 test', 'utf8', 'hex');
|
|
158
|
+
encrypted += cipher.final('hex');
|
|
159
|
+
|
|
160
|
+
const decipher = createDecipheriv(algorithm, key, iv);
|
|
161
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
162
|
+
decrypted += decipher.final('utf8');
|
|
163
|
+
|
|
164
|
+
expect(decrypted).toBe('AES-128 test');
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// --- AES-256-CTR round-trip ---
|
|
169
|
+
await describe('crypto.createCipheriv / createDecipheriv (AES-256-CTR)', async () => {
|
|
170
|
+
const algorithm = 'aes-256-ctr';
|
|
171
|
+
const key = Buffer.from('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', 'hex');
|
|
172
|
+
const iv = Buffer.from('00112233445566778899aabbccddeeff', 'hex');
|
|
173
|
+
|
|
174
|
+
await it('should encrypt and decrypt', async () => {
|
|
175
|
+
const cipher = createCipheriv(algorithm, key, iv);
|
|
176
|
+
let encrypted = cipher.update('CTR mode test', 'utf8', 'hex');
|
|
177
|
+
encrypted += cipher.final('hex');
|
|
178
|
+
|
|
179
|
+
const decipher = createDecipheriv(algorithm, key, iv);
|
|
180
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
181
|
+
decrypted += decipher.final('utf8');
|
|
182
|
+
|
|
183
|
+
expect(decrypted).toBe('CTR mode test');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
await it('CTR ciphertext should be same length as plaintext (no padding)', async () => {
|
|
187
|
+
const plaintext = 'No padding in CTR!';
|
|
188
|
+
const cipher = createCipheriv(algorithm, key, iv);
|
|
189
|
+
const encrypted = Buffer.concat([cipher.update(Buffer.from(plaintext)), cipher.final()]);
|
|
190
|
+
|
|
191
|
+
// CTR mode: ciphertext length = plaintext length (no padding)
|
|
192
|
+
expect(encrypted.length).toBe(plaintext.length);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// --- AES-128-ECB ---
|
|
197
|
+
await describe('crypto.createCipheriv / createDecipheriv (AES-128-ECB)', async () => {
|
|
198
|
+
const algorithm = 'aes-128-ecb';
|
|
199
|
+
const key = Buffer.from('0123456789abcdef0123456789abcdef', 'hex');
|
|
200
|
+
|
|
201
|
+
await it('should encrypt and decrypt with null IV', async () => {
|
|
202
|
+
const cipher = createCipheriv(algorithm, key, null);
|
|
203
|
+
let encrypted = cipher.update('ECB mode test!', 'utf8', 'hex');
|
|
204
|
+
encrypted += cipher.final('hex');
|
|
205
|
+
|
|
206
|
+
const decipher = createDecipheriv(algorithm, key, null);
|
|
207
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
208
|
+
decrypted += decipher.final('utf8');
|
|
209
|
+
|
|
210
|
+
expect(decrypted).toBe('ECB mode test!');
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// --- Known test vector: AES-128-CBC (NIST-like) ---
|
|
215
|
+
await describe('crypto: known test vectors', async () => {
|
|
216
|
+
await it('AES-128-CBC: should produce known ciphertext', async () => {
|
|
217
|
+
// Key and IV from refs/node/test/parallel/test-crypto-padding.js
|
|
218
|
+
const key = Buffer.from('S3c.r.e.t.K.e.Y!', 'utf8'); // 16 bytes
|
|
219
|
+
const iv = Buffer.from('blahFizz2011Buzz', 'utf8'); // 16 bytes
|
|
220
|
+
|
|
221
|
+
const cipher = createCipheriv('aes-128-cbc', key, iv);
|
|
222
|
+
let encrypted = cipher.update('Hello node world!', 'utf8', 'hex');
|
|
223
|
+
encrypted += cipher.final('hex');
|
|
224
|
+
|
|
225
|
+
expect(encrypted).toBe('7f57859550d4d2fdb9806da2a750461a9fe77253cd1cbd4b07beee4e070d561f');
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
await it('AES-128-CBC: should decrypt known ciphertext', async () => {
|
|
229
|
+
const key = Buffer.from('S3c.r.e.t.K.e.Y!', 'utf8');
|
|
230
|
+
const iv = Buffer.from('blahFizz2011Buzz', 'utf8');
|
|
231
|
+
|
|
232
|
+
const decipher = createDecipheriv('aes-128-cbc', key, iv);
|
|
233
|
+
let decrypted = decipher.update('7f57859550d4d2fdb9806da2a750461a9fe77253cd1cbd4b07beee4e070d561f', 'hex', 'utf8');
|
|
234
|
+
decrypted += decipher.final('utf8');
|
|
235
|
+
|
|
236
|
+
expect(decrypted).toBe('Hello node world!');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
await it('AES-128-CBC: 32-byte aligned plaintext', async () => {
|
|
240
|
+
const key = Buffer.from('S3c.r.e.t.K.e.Y!', 'utf8');
|
|
241
|
+
const iv = Buffer.from('blahFizz2011Buzz', 'utf8');
|
|
242
|
+
|
|
243
|
+
const cipher = createCipheriv('aes-128-cbc', key, iv);
|
|
244
|
+
let encrypted = cipher.update('Hello node world!AbC09876dDeFgHi', 'utf8', 'hex');
|
|
245
|
+
encrypted += cipher.final('hex');
|
|
246
|
+
|
|
247
|
+
expect(encrypted).toBe('7f57859550d4d2fdb9806da2a750461ab46e71b3d78ebe2d9684dfc87f7575b9886119866912cb8c7bcaf76c5ebc2378');
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// --- setAutoPadding ---
|
|
252
|
+
await describe('crypto: setAutoPadding', async () => {
|
|
253
|
+
await it('should support setAutoPadding(false) for block-aligned data', async () => {
|
|
254
|
+
const key = Buffer.from('S3c.r.e.t.K.e.Y!', 'utf8');
|
|
255
|
+
const iv = Buffer.from('blahFizz2011Buzz', 'utf8');
|
|
256
|
+
const plaintext = 'Hello node world!AbC09876dDeFgHi'; // 32 bytes = 2 blocks
|
|
257
|
+
|
|
258
|
+
const cipher = createCipheriv('aes-128-cbc', key, iv);
|
|
259
|
+
cipher.setAutoPadding(false);
|
|
260
|
+
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
|
|
261
|
+
encrypted += cipher.final('hex');
|
|
262
|
+
|
|
263
|
+
// Without padding, 32 bytes of plaintext → 32 bytes of ciphertext
|
|
264
|
+
expect(encrypted).toBe('7f57859550d4d2fdb9806da2a750461ab46e71b3d78ebe2d9684dfc87f7575b9');
|
|
265
|
+
|
|
266
|
+
const decipher = createDecipheriv('aes-128-cbc', key, iv);
|
|
267
|
+
decipher.setAutoPadding(false);
|
|
268
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
269
|
+
decrypted += decipher.final('utf8');
|
|
270
|
+
|
|
271
|
+
expect(decrypted).toBe(plaintext);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// --- Multiple update calls ---
|
|
276
|
+
await describe('crypto: multiple update calls', async () => {
|
|
277
|
+
await it('should handle multiple update() calls', async () => {
|
|
278
|
+
const key = Buffer.from('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', 'hex');
|
|
279
|
+
const iv = Buffer.from('00112233445566778899aabbccddeeff', 'hex');
|
|
280
|
+
|
|
281
|
+
const cipher = createCipheriv('aes-256-cbc', key, iv);
|
|
282
|
+
let encrypted = '';
|
|
283
|
+
encrypted += cipher.update('Hello ', 'utf8', 'hex');
|
|
284
|
+
encrypted += cipher.update('World', 'utf8', 'hex');
|
|
285
|
+
encrypted += cipher.update('!', 'utf8', 'hex');
|
|
286
|
+
encrypted += cipher.final('hex');
|
|
287
|
+
|
|
288
|
+
const decipher = createDecipheriv('aes-256-cbc', key, iv);
|
|
289
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
290
|
+
decrypted += decipher.final('utf8');
|
|
291
|
+
|
|
292
|
+
expect(decrypted).toBe('Hello World!');
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// --- Unicode data ---
|
|
297
|
+
await describe('crypto: Unicode data', async () => {
|
|
298
|
+
await it('should handle Unicode text', async () => {
|
|
299
|
+
const key = Buffer.from('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', 'hex');
|
|
300
|
+
const iv = Buffer.from('00112233445566778899aabbccddeeff', 'hex');
|
|
301
|
+
const plaintext = 'Héllo Wörld! 日本語 🎉';
|
|
302
|
+
|
|
303
|
+
const cipher = createCipheriv('aes-256-cbc', key, iv);
|
|
304
|
+
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
|
|
305
|
+
encrypted += cipher.final('hex');
|
|
306
|
+
|
|
307
|
+
const decipher = createDecipheriv('aes-256-cbc', key, iv);
|
|
308
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
309
|
+
decrypted += decipher.final('utf8');
|
|
310
|
+
|
|
311
|
+
expect(decrypted).toBe(plaintext);
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// --- Base64 encoding ---
|
|
316
|
+
await describe('crypto: base64 encoding', async () => {
|
|
317
|
+
await it('should support base64 output encoding', async () => {
|
|
318
|
+
const key = Buffer.from('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', 'hex');
|
|
319
|
+
const iv = Buffer.from('00112233445566778899aabbccddeeff', 'hex');
|
|
320
|
+
|
|
321
|
+
const cipher = createCipheriv('aes-256-cbc', key, iv);
|
|
322
|
+
let encrypted = cipher.update('Base64 test', 'utf8', 'base64');
|
|
323
|
+
encrypted += cipher.final('base64');
|
|
324
|
+
|
|
325
|
+
const decipher = createDecipheriv('aes-256-cbc', key, iv);
|
|
326
|
+
let decrypted = decipher.update(encrypted, 'base64', 'utf8');
|
|
327
|
+
decrypted += decipher.final('utf8');
|
|
328
|
+
|
|
329
|
+
expect(decrypted).toBe('Base64 test');
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
};
|