aegis-aead 0.2.2 → 0.2.3
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 +25 -20
- package/dist/aegis128l.d.ts +33 -33
- package/dist/aegis128l.js +225 -235
- package/dist/aegis128x.d.ts +35 -35
- package/dist/aegis128x.js +348 -282
- package/dist/aegis256.d.ts +34 -51
- package/dist/aegis256.js +215 -206
- package/dist/aegis256x.d.ts +32 -33
- package/dist/aegis256x.js +333 -265
- package/dist/aes-bs.d.ts +42 -35
- package/dist/aes-bs.js +2269 -401
- package/dist/index.d.ts +4 -7
- package/dist/index.js +4 -7
- package/dist/random.d.ts +0 -1
- package/dist/random.js +0 -1
- package/dist/utils.d.ts +14 -0
- package/dist/utils.js +31 -0
- package/package.json +5 -6
- package/dist/aegis128l-bs.d.ts +0 -137
- package/dist/aegis128l-bs.d.ts.map +0 -1
- package/dist/aegis128l-bs.js +0 -442
- package/dist/aegis128l-bs.js.map +0 -1
- package/dist/aegis128l.d.ts.map +0 -1
- package/dist/aegis128l.js.map +0 -1
- package/dist/aegis128x.d.ts.map +0 -1
- package/dist/aegis128x.js.map +0 -1
- package/dist/aegis256-bs.d.ts +0 -79
- package/dist/aegis256-bs.d.ts.map +0 -1
- package/dist/aegis256-bs.js +0 -366
- package/dist/aegis256-bs.js.map +0 -1
- package/dist/aegis256.d.ts.map +0 -1
- package/dist/aegis256.js.map +0 -1
- package/dist/aegis256x.d.ts.map +0 -1
- package/dist/aegis256x.js.map +0 -1
- package/dist/aes-bs.d.ts.map +0 -1
- package/dist/aes-bs.js.map +0 -1
- package/dist/aes.d.ts +0 -81
- package/dist/aes.d.ts.map +0 -1
- package/dist/aes.js +0 -232
- package/dist/aes.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/random.d.ts.map +0 -1
- package/dist/random.js.map +0 -1
- package/src/aegis128l-bs.ts +0 -600
- package/src/aegis128l.ts +0 -653
- package/src/aegis128x.ts +0 -932
- package/src/aegis256-bs.ts +0 -519
- package/src/aegis256.ts +0 -597
- package/src/aegis256x.ts +0 -893
- package/src/aes-bs.ts +0 -540
- package/src/aes.ts +0 -271
- package/src/index.ts +0 -126
- package/src/random.ts +0 -41
- package/src/typed-array.d.ts +0 -18
package/src/aegis128l.ts
DELETED
|
@@ -1,653 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
aesRoundTo,
|
|
3
|
-
andBlocksTo,
|
|
4
|
-
C0,
|
|
5
|
-
C1,
|
|
6
|
-
constantTimeEqual,
|
|
7
|
-
le64To,
|
|
8
|
-
xorBlocksTo,
|
|
9
|
-
zeroPad,
|
|
10
|
-
} from "./aes.js";
|
|
11
|
-
import { randomBytes } from "./random.js";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* AEGIS-128L cipher state.
|
|
15
|
-
* Uses 8 AES blocks (128 bytes) of internal state and processes 32-byte blocks.
|
|
16
|
-
*/
|
|
17
|
-
export class Aegis128LState {
|
|
18
|
-
private s0: Uint8Array;
|
|
19
|
-
private s1: Uint8Array;
|
|
20
|
-
private s2: Uint8Array;
|
|
21
|
-
private s3: Uint8Array;
|
|
22
|
-
private s4: Uint8Array;
|
|
23
|
-
private s5: Uint8Array;
|
|
24
|
-
private s6: Uint8Array;
|
|
25
|
-
private s7: Uint8Array;
|
|
26
|
-
private tmp0: Uint8Array;
|
|
27
|
-
private tmp1: Uint8Array;
|
|
28
|
-
private z0: Uint8Array;
|
|
29
|
-
private z1: Uint8Array;
|
|
30
|
-
private newS: Uint8Array[];
|
|
31
|
-
private tBuf: Uint8Array;
|
|
32
|
-
|
|
33
|
-
constructor() {
|
|
34
|
-
this.s0 = new Uint8Array(16);
|
|
35
|
-
this.s1 = new Uint8Array(16);
|
|
36
|
-
this.s2 = new Uint8Array(16);
|
|
37
|
-
this.s3 = new Uint8Array(16);
|
|
38
|
-
this.s4 = new Uint8Array(16);
|
|
39
|
-
this.s5 = new Uint8Array(16);
|
|
40
|
-
this.s6 = new Uint8Array(16);
|
|
41
|
-
this.s7 = new Uint8Array(16);
|
|
42
|
-
this.tmp0 = new Uint8Array(16);
|
|
43
|
-
this.tmp1 = new Uint8Array(16);
|
|
44
|
-
this.z0 = new Uint8Array(16);
|
|
45
|
-
this.z1 = new Uint8Array(16);
|
|
46
|
-
this.newS = Array.from({ length: 8 }, () => new Uint8Array(16));
|
|
47
|
-
this.tBuf = new Uint8Array(16);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
get s(): Uint8Array[] {
|
|
51
|
-
return [
|
|
52
|
-
this.s0,
|
|
53
|
-
this.s1,
|
|
54
|
-
this.s2,
|
|
55
|
-
this.s3,
|
|
56
|
-
this.s4,
|
|
57
|
-
this.s5,
|
|
58
|
-
this.s6,
|
|
59
|
-
this.s7,
|
|
60
|
-
];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
set s(states: Uint8Array[]) {
|
|
64
|
-
this.s0.set(states[0]!);
|
|
65
|
-
this.s1.set(states[1]!);
|
|
66
|
-
this.s2.set(states[2]!);
|
|
67
|
-
this.s3.set(states[3]!);
|
|
68
|
-
this.s4.set(states[4]!);
|
|
69
|
-
this.s5.set(states[5]!);
|
|
70
|
-
this.s6.set(states[6]!);
|
|
71
|
-
this.s7.set(states[7]!);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Initializes the state with a key and nonce.
|
|
76
|
-
* @param key - 16-byte encryption key
|
|
77
|
-
* @param nonce - 16-byte nonce (must be unique per message)
|
|
78
|
-
*/
|
|
79
|
-
init(key: Uint8Array, nonce: Uint8Array): void {
|
|
80
|
-
xorBlocksTo(key, nonce, this.s0);
|
|
81
|
-
this.s1.set(C1);
|
|
82
|
-
this.s2.set(C0);
|
|
83
|
-
this.s3.set(C1);
|
|
84
|
-
xorBlocksTo(key, nonce, this.s4);
|
|
85
|
-
xorBlocksTo(key, C0, this.s5);
|
|
86
|
-
xorBlocksTo(key, C1, this.s6);
|
|
87
|
-
xorBlocksTo(key, C0, this.s7);
|
|
88
|
-
|
|
89
|
-
for (let i = 0; i < 10; i++) {
|
|
90
|
-
this.update(nonce, key);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Updates the state with two 16-byte message blocks.
|
|
96
|
-
* @param m0 - First 16-byte message block
|
|
97
|
-
* @param m1 - Second 16-byte message block
|
|
98
|
-
*/
|
|
99
|
-
update(m0: ArrayLike<number>, m1: ArrayLike<number>): void {
|
|
100
|
-
const newS = this.newS;
|
|
101
|
-
|
|
102
|
-
xorBlocksTo(this.s0, m0, this.tmp0);
|
|
103
|
-
aesRoundTo(this.s7, this.tmp0, newS[0]!);
|
|
104
|
-
aesRoundTo(this.s0, this.s1, newS[1]!);
|
|
105
|
-
aesRoundTo(this.s1, this.s2, newS[2]!);
|
|
106
|
-
aesRoundTo(this.s2, this.s3, newS[3]!);
|
|
107
|
-
xorBlocksTo(this.s4, m1, this.tmp1);
|
|
108
|
-
aesRoundTo(this.s3, this.tmp1, newS[4]!);
|
|
109
|
-
aesRoundTo(this.s4, this.s5, newS[5]!);
|
|
110
|
-
aesRoundTo(this.s5, this.s6, newS[6]!);
|
|
111
|
-
aesRoundTo(this.s6, this.s7, newS[7]!);
|
|
112
|
-
|
|
113
|
-
this.s0.set(newS[0]!);
|
|
114
|
-
this.s1.set(newS[1]!);
|
|
115
|
-
this.s2.set(newS[2]!);
|
|
116
|
-
this.s3.set(newS[3]!);
|
|
117
|
-
this.s4.set(newS[4]!);
|
|
118
|
-
this.s5.set(newS[5]!);
|
|
119
|
-
this.s6.set(newS[6]!);
|
|
120
|
-
this.s7.set(newS[7]!);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Absorbs a 32-byte associated data block into the state.
|
|
125
|
-
* @param ai - 32-byte associated data block
|
|
126
|
-
*/
|
|
127
|
-
absorb(ai: Uint8Array): void {
|
|
128
|
-
this.update(ai.subarray(0, 16), ai.subarray(16, 32));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Encrypts a 32-byte plaintext block and writes to output buffer.
|
|
133
|
-
* @param xi - 32-byte plaintext block
|
|
134
|
-
* @param out - 32-byte output buffer
|
|
135
|
-
*/
|
|
136
|
-
encTo(xi: Uint8Array, out: Uint8Array): void {
|
|
137
|
-
const z0 = this.z0;
|
|
138
|
-
const z1 = this.z1;
|
|
139
|
-
const tmp = this.tmp0;
|
|
140
|
-
|
|
141
|
-
xorBlocksTo(this.s1, this.s6, z0);
|
|
142
|
-
andBlocksTo(this.s2, this.s3, tmp);
|
|
143
|
-
for (let i = 0; i < 16; i++) z0[i] ^= tmp[i]!;
|
|
144
|
-
|
|
145
|
-
xorBlocksTo(this.s2, this.s5, z1);
|
|
146
|
-
andBlocksTo(this.s6, this.s7, tmp);
|
|
147
|
-
for (let i = 0; i < 16; i++) z1[i] ^= tmp[i]!;
|
|
148
|
-
|
|
149
|
-
const t0 = xi.subarray(0, 16);
|
|
150
|
-
const t1 = xi.subarray(16, 32);
|
|
151
|
-
|
|
152
|
-
for (let i = 0; i < 16; i++) out[i] = t0[i]! ^ z0[i]!;
|
|
153
|
-
for (let i = 0; i < 16; i++) out[16 + i] = t1[i]! ^ z1[i]!;
|
|
154
|
-
|
|
155
|
-
this.update(t0, t1);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Encrypts a 32-byte plaintext block.
|
|
160
|
-
* @param xi - 32-byte plaintext block
|
|
161
|
-
* @returns 32-byte ciphertext block
|
|
162
|
-
*/
|
|
163
|
-
enc(xi: Uint8Array): Uint8Array {
|
|
164
|
-
const out = new Uint8Array(32);
|
|
165
|
-
this.encTo(xi, out);
|
|
166
|
-
return out;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Decrypts a 32-byte ciphertext block and writes to output buffer.
|
|
171
|
-
* @param ci - 32-byte ciphertext block
|
|
172
|
-
* @param out - 32-byte output buffer
|
|
173
|
-
*/
|
|
174
|
-
decTo(ci: Uint8Array, out: Uint8Array): void {
|
|
175
|
-
const z0 = this.z0;
|
|
176
|
-
const z1 = this.z1;
|
|
177
|
-
const tmp = this.tmp0;
|
|
178
|
-
|
|
179
|
-
xorBlocksTo(this.s1, this.s6, z0);
|
|
180
|
-
andBlocksTo(this.s2, this.s3, tmp);
|
|
181
|
-
for (let i = 0; i < 16; i++) z0[i] ^= tmp[i]!;
|
|
182
|
-
|
|
183
|
-
xorBlocksTo(this.s2, this.s5, z1);
|
|
184
|
-
andBlocksTo(this.s6, this.s7, tmp);
|
|
185
|
-
for (let i = 0; i < 16; i++) z1[i] ^= tmp[i]!;
|
|
186
|
-
|
|
187
|
-
const t0 = ci.subarray(0, 16);
|
|
188
|
-
const t1 = ci.subarray(16, 32);
|
|
189
|
-
|
|
190
|
-
for (let i = 0; i < 16; i++) out[i] = t0[i]! ^ z0[i]!;
|
|
191
|
-
for (let i = 0; i < 16; i++) out[16 + i] = t1[i]! ^ z1[i]!;
|
|
192
|
-
|
|
193
|
-
this.update(out.subarray(0, 16), out.subarray(16, 32));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Decrypts a 32-byte ciphertext block.
|
|
198
|
-
* @param ci - 32-byte ciphertext block
|
|
199
|
-
* @returns 32-byte plaintext block
|
|
200
|
-
*/
|
|
201
|
-
dec(ci: Uint8Array): Uint8Array {
|
|
202
|
-
const out = new Uint8Array(32);
|
|
203
|
-
this.decTo(ci, out);
|
|
204
|
-
return out;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Encrypts a 32-byte plaintext block in-place.
|
|
209
|
-
* @param block - 32-byte buffer (plaintext in, ciphertext out)
|
|
210
|
-
*/
|
|
211
|
-
encInPlace(block: Uint8Array): void {
|
|
212
|
-
const z0 = this.z0;
|
|
213
|
-
const z1 = this.z1;
|
|
214
|
-
const tmp = this.tmp0;
|
|
215
|
-
|
|
216
|
-
xorBlocksTo(this.s1, this.s6, z0);
|
|
217
|
-
andBlocksTo(this.s2, this.s3, tmp);
|
|
218
|
-
for (let i = 0; i < 16; i++) z0[i] ^= tmp[i]!;
|
|
219
|
-
|
|
220
|
-
xorBlocksTo(this.s2, this.s5, z1);
|
|
221
|
-
andBlocksTo(this.s6, this.s7, tmp);
|
|
222
|
-
for (let i = 0; i < 16; i++) z1[i] ^= tmp[i]!;
|
|
223
|
-
|
|
224
|
-
this.update(block.subarray(0, 16), block.subarray(16, 32));
|
|
225
|
-
|
|
226
|
-
for (let i = 0; i < 16; i++) block[i] ^= z0[i]!;
|
|
227
|
-
for (let i = 0; i < 16; i++) block[16 + i] ^= z1[i]!;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Decrypts a 32-byte ciphertext block in-place.
|
|
232
|
-
* @param block - 32-byte buffer (ciphertext in, plaintext out)
|
|
233
|
-
*/
|
|
234
|
-
decInPlace(block: Uint8Array): void {
|
|
235
|
-
this.decTo(block, block);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Decrypts a partial (final) ciphertext block smaller than 32 bytes.
|
|
240
|
-
* @param cn - Partial ciphertext block (1-31 bytes)
|
|
241
|
-
* @returns Decrypted plaintext of the same length
|
|
242
|
-
*/
|
|
243
|
-
decPartial(cn: Uint8Array): Uint8Array {
|
|
244
|
-
const z0 = this.z0;
|
|
245
|
-
const z1 = this.z1;
|
|
246
|
-
const tmp = this.tmp0;
|
|
247
|
-
|
|
248
|
-
xorBlocksTo(this.s1, this.s6, z0);
|
|
249
|
-
andBlocksTo(this.s2, this.s3, tmp);
|
|
250
|
-
for (let i = 0; i < 16; i++) z0[i] ^= tmp[i]!;
|
|
251
|
-
|
|
252
|
-
xorBlocksTo(this.s2, this.s5, z1);
|
|
253
|
-
andBlocksTo(this.s6, this.s7, tmp);
|
|
254
|
-
for (let i = 0; i < 16; i++) z1[i] ^= tmp[i]!;
|
|
255
|
-
|
|
256
|
-
const padded = zeroPad(cn, 32);
|
|
257
|
-
const t0 = padded.subarray(0, 16);
|
|
258
|
-
const t1 = padded.subarray(16, 32);
|
|
259
|
-
|
|
260
|
-
const out = new Uint8Array(32);
|
|
261
|
-
for (let i = 0; i < 16; i++) out[i] = t0[i]! ^ z0[i]!;
|
|
262
|
-
for (let i = 0; i < 16; i++) out[16 + i] = t1[i]! ^ z1[i]!;
|
|
263
|
-
|
|
264
|
-
const xn = new Uint8Array(out.subarray(0, cn.length));
|
|
265
|
-
|
|
266
|
-
const v = zeroPad(xn, 32);
|
|
267
|
-
this.update(v.subarray(0, 16), v.subarray(16, 32));
|
|
268
|
-
|
|
269
|
-
return xn;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Finalizes encryption/decryption and produces an authentication tag.
|
|
274
|
-
* @param adLenBits - Associated data length in bits
|
|
275
|
-
* @param msgLenBits - Message length in bits
|
|
276
|
-
* @param tagLen - Tag length (16 or 32 bytes)
|
|
277
|
-
* @returns Authentication tag
|
|
278
|
-
*/
|
|
279
|
-
finalize(
|
|
280
|
-
adLenBits: bigint,
|
|
281
|
-
msgLenBits: bigint,
|
|
282
|
-
tagLen: 16 | 32 = 16,
|
|
283
|
-
): Uint8Array {
|
|
284
|
-
const t = this.tBuf;
|
|
285
|
-
le64To(adLenBits, t, 0);
|
|
286
|
-
le64To(msgLenBits, t, 8);
|
|
287
|
-
for (let i = 0; i < 16; i++) t[i] ^= this.s2[i]!;
|
|
288
|
-
|
|
289
|
-
for (let i = 0; i < 7; i++) {
|
|
290
|
-
this.update(t, t);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
if (tagLen === 16) {
|
|
294
|
-
const tag = new Uint8Array(16);
|
|
295
|
-
for (let i = 0; i < 16; i++) {
|
|
296
|
-
tag[i] =
|
|
297
|
-
this.s0[i]! ^
|
|
298
|
-
this.s1[i]! ^
|
|
299
|
-
this.s2[i]! ^
|
|
300
|
-
this.s3[i]! ^
|
|
301
|
-
this.s4[i]! ^
|
|
302
|
-
this.s5[i]! ^
|
|
303
|
-
this.s6[i]!;
|
|
304
|
-
}
|
|
305
|
-
return tag;
|
|
306
|
-
} else {
|
|
307
|
-
const tag = new Uint8Array(32);
|
|
308
|
-
for (let i = 0; i < 16; i++) {
|
|
309
|
-
tag[i] = this.s0[i]! ^ this.s1[i]! ^ this.s2[i]! ^ this.s3[i]!;
|
|
310
|
-
}
|
|
311
|
-
for (let i = 0; i < 16; i++) {
|
|
312
|
-
tag[16 + i] = this.s4[i]! ^ this.s5[i]! ^ this.s6[i]! ^ this.s7[i]!;
|
|
313
|
-
}
|
|
314
|
-
return tag;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Encrypts a message using AEGIS-128L (detached mode).
|
|
321
|
-
* @param msg - Plaintext message
|
|
322
|
-
* @param ad - Associated data (authenticated but not encrypted)
|
|
323
|
-
* @param key - 16-byte encryption key
|
|
324
|
-
* @param nonce - 16-byte nonce (must be unique per message with the same key)
|
|
325
|
-
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
326
|
-
* @returns Object containing ciphertext and authentication tag separately
|
|
327
|
-
*/
|
|
328
|
-
export function aegis128LEncryptDetached(
|
|
329
|
-
msg: Uint8Array,
|
|
330
|
-
ad: Uint8Array,
|
|
331
|
-
key: Uint8Array,
|
|
332
|
-
nonce: Uint8Array,
|
|
333
|
-
tagLen: 16 | 32 = 16,
|
|
334
|
-
): { ciphertext: Uint8Array; tag: Uint8Array } {
|
|
335
|
-
const state = new Aegis128LState();
|
|
336
|
-
state.init(key, nonce);
|
|
337
|
-
|
|
338
|
-
const adPadded = zeroPad(ad, 32);
|
|
339
|
-
for (let i = 0; i + 32 <= adPadded.length; i += 32) {
|
|
340
|
-
state.absorb(adPadded.subarray(i, i + 32));
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
const msgPadded = zeroPad(msg, 32);
|
|
344
|
-
const ct = new Uint8Array(msgPadded.length);
|
|
345
|
-
for (let i = 0; i + 32 <= msgPadded.length; i += 32) {
|
|
346
|
-
state.encTo(msgPadded.subarray(i, i + 32), ct.subarray(i, i + 32));
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const tag = state.finalize(
|
|
350
|
-
BigInt(ad.length * 8),
|
|
351
|
-
BigInt(msg.length * 8),
|
|
352
|
-
tagLen,
|
|
353
|
-
);
|
|
354
|
-
const ciphertext = new Uint8Array(ct.subarray(0, msg.length));
|
|
355
|
-
|
|
356
|
-
return { ciphertext, tag };
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Decrypts a message using AEGIS-128L (detached mode).
|
|
361
|
-
* @param ct - Ciphertext
|
|
362
|
-
* @param tag - Authentication tag (16 or 32 bytes)
|
|
363
|
-
* @param ad - Associated data (must match what was used during encryption)
|
|
364
|
-
* @param key - 16-byte encryption key
|
|
365
|
-
* @param nonce - 16-byte nonce (must match what was used during encryption)
|
|
366
|
-
* @returns Decrypted plaintext, or null if authentication fails
|
|
367
|
-
*/
|
|
368
|
-
export function aegis128LDecryptDetached(
|
|
369
|
-
ct: Uint8Array,
|
|
370
|
-
tag: Uint8Array,
|
|
371
|
-
ad: Uint8Array,
|
|
372
|
-
key: Uint8Array,
|
|
373
|
-
nonce: Uint8Array,
|
|
374
|
-
): Uint8Array | null {
|
|
375
|
-
const tagLen = tag.length as 16 | 32;
|
|
376
|
-
const state = new Aegis128LState();
|
|
377
|
-
state.init(key, nonce);
|
|
378
|
-
|
|
379
|
-
const adPadded = zeroPad(ad, 32);
|
|
380
|
-
for (let i = 0; i + 32 <= adPadded.length; i += 32) {
|
|
381
|
-
state.absorb(adPadded.subarray(i, i + 32));
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
const fullBlocksLen = Math.floor(ct.length / 32) * 32;
|
|
385
|
-
const cn = ct.subarray(fullBlocksLen);
|
|
386
|
-
|
|
387
|
-
const msg = new Uint8Array(fullBlocksLen + (cn.length > 0 ? cn.length : 0));
|
|
388
|
-
for (let i = 0; i + 32 <= ct.length; i += 32) {
|
|
389
|
-
state.decTo(ct.subarray(i, i + 32), msg.subarray(i, i + 32));
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
if (cn.length > 0) {
|
|
393
|
-
msg.set(state.decPartial(cn), fullBlocksLen);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
const expectedTag = state.finalize(
|
|
397
|
-
BigInt(ad.length * 8),
|
|
398
|
-
BigInt(msg.length * 8),
|
|
399
|
-
tagLen,
|
|
400
|
-
);
|
|
401
|
-
|
|
402
|
-
if (!constantTimeEqual(tag, expectedTag)) {
|
|
403
|
-
msg.fill(0);
|
|
404
|
-
return null;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
return msg;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
/**
|
|
411
|
-
* Encrypts a message in-place using AEGIS-128L (detached mode).
|
|
412
|
-
* The input buffer is modified to contain the ciphertext.
|
|
413
|
-
* @param data - Buffer containing plaintext (will be overwritten with ciphertext)
|
|
414
|
-
* @param ad - Associated data (authenticated but not encrypted)
|
|
415
|
-
* @param key - 16-byte encryption key
|
|
416
|
-
* @param nonce - 16-byte nonce (must be unique per message with the same key)
|
|
417
|
-
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
418
|
-
* @returns Authentication tag
|
|
419
|
-
*/
|
|
420
|
-
export function aegis128LEncryptDetachedInPlace(
|
|
421
|
-
data: Uint8Array,
|
|
422
|
-
ad: Uint8Array,
|
|
423
|
-
key: Uint8Array,
|
|
424
|
-
nonce: Uint8Array,
|
|
425
|
-
tagLen: 16 | 32 = 16,
|
|
426
|
-
): Uint8Array {
|
|
427
|
-
const state = new Aegis128LState();
|
|
428
|
-
state.init(key, nonce);
|
|
429
|
-
|
|
430
|
-
const adPadded = zeroPad(ad, 32);
|
|
431
|
-
for (let i = 0; i + 32 <= adPadded.length; i += 32) {
|
|
432
|
-
state.absorb(adPadded.subarray(i, i + 32));
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
const msgLen = data.length;
|
|
436
|
-
const fullBlocksLen = Math.floor(msgLen / 32) * 32;
|
|
437
|
-
|
|
438
|
-
for (let i = 0; i < fullBlocksLen; i += 32) {
|
|
439
|
-
state.encInPlace(data.subarray(i, i + 32));
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
if (msgLen > fullBlocksLen) {
|
|
443
|
-
const lastPartial = data.subarray(fullBlocksLen);
|
|
444
|
-
const lastBlock = zeroPad(lastPartial, 32);
|
|
445
|
-
const encBlock = state.enc(lastBlock);
|
|
446
|
-
lastPartial.set(encBlock.subarray(0, lastPartial.length));
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
return state.finalize(BigInt(ad.length * 8), BigInt(msgLen * 8), tagLen);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
/**
|
|
453
|
-
* Decrypts a message in-place using AEGIS-128L (detached mode).
|
|
454
|
-
* The input buffer is modified to contain the plaintext (or zeroed on failure).
|
|
455
|
-
* @param data - Buffer containing ciphertext (will be overwritten with plaintext)
|
|
456
|
-
* @param tag - Authentication tag (16 or 32 bytes)
|
|
457
|
-
* @param ad - Associated data (must match what was used during encryption)
|
|
458
|
-
* @param key - 16-byte encryption key
|
|
459
|
-
* @param nonce - 16-byte nonce (must match what was used during encryption)
|
|
460
|
-
* @returns True if authentication succeeds, false otherwise
|
|
461
|
-
*/
|
|
462
|
-
export function aegis128LDecryptDetachedInPlace(
|
|
463
|
-
data: Uint8Array,
|
|
464
|
-
tag: Uint8Array,
|
|
465
|
-
ad: Uint8Array,
|
|
466
|
-
key: Uint8Array,
|
|
467
|
-
nonce: Uint8Array,
|
|
468
|
-
): boolean {
|
|
469
|
-
const tagLen = tag.length as 16 | 32;
|
|
470
|
-
const state = new Aegis128LState();
|
|
471
|
-
state.init(key, nonce);
|
|
472
|
-
|
|
473
|
-
const adPadded = zeroPad(ad, 32);
|
|
474
|
-
for (let i = 0; i + 32 <= adPadded.length; i += 32) {
|
|
475
|
-
state.absorb(adPadded.subarray(i, i + 32));
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
const msgLen = data.length;
|
|
479
|
-
const fullBlocksLen = Math.floor(msgLen / 32) * 32;
|
|
480
|
-
|
|
481
|
-
for (let i = 0; i < fullBlocksLen; i += 32) {
|
|
482
|
-
state.decInPlace(data.subarray(i, i + 32));
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
if (msgLen > fullBlocksLen) {
|
|
486
|
-
const lastPartial = data.subarray(fullBlocksLen);
|
|
487
|
-
const decrypted = state.decPartial(lastPartial);
|
|
488
|
-
lastPartial.set(decrypted);
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
const expectedTag = state.finalize(
|
|
492
|
-
BigInt(ad.length * 8),
|
|
493
|
-
BigInt(msgLen * 8),
|
|
494
|
-
tagLen,
|
|
495
|
-
);
|
|
496
|
-
|
|
497
|
-
if (!constantTimeEqual(tag, expectedTag)) {
|
|
498
|
-
data.fill(0);
|
|
499
|
-
return false;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
return true;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
/** Nonce size for AEGIS-128L in bytes. */
|
|
506
|
-
export const AEGIS_128L_NONCE_SIZE = 16;
|
|
507
|
-
|
|
508
|
-
/** Key size for AEGIS-128L in bytes. */
|
|
509
|
-
export const AEGIS_128L_KEY_SIZE = 16;
|
|
510
|
-
|
|
511
|
-
/**
|
|
512
|
-
* Encrypts a message using AEGIS-128L.
|
|
513
|
-
* Returns a single buffer containing nonce || ciphertext || tag.
|
|
514
|
-
* @param msg - Plaintext message
|
|
515
|
-
* @param ad - Associated data (authenticated but not encrypted)
|
|
516
|
-
* @param key - 16-byte encryption key
|
|
517
|
-
* @param nonce - 16-byte nonce (optional, generates random nonce if not provided)
|
|
518
|
-
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
519
|
-
* @returns Concatenated nonce || ciphertext || tag
|
|
520
|
-
*/
|
|
521
|
-
export function aegis128LEncrypt(
|
|
522
|
-
msg: Uint8Array,
|
|
523
|
-
ad: Uint8Array,
|
|
524
|
-
key: Uint8Array,
|
|
525
|
-
nonce: Uint8Array | null = null,
|
|
526
|
-
tagLen: 16 | 32 = 16,
|
|
527
|
-
): Uint8Array {
|
|
528
|
-
const actualNonce = nonce ?? randomBytes(AEGIS_128L_NONCE_SIZE);
|
|
529
|
-
const state = new Aegis128LState();
|
|
530
|
-
state.init(key, actualNonce);
|
|
531
|
-
|
|
532
|
-
const adPadded = zeroPad(ad, 32);
|
|
533
|
-
for (let i = 0; i + 32 <= adPadded.length; i += 32) {
|
|
534
|
-
state.absorb(adPadded.subarray(i, i + 32));
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
const nonceSize = AEGIS_128L_NONCE_SIZE;
|
|
538
|
-
const result = new Uint8Array(nonceSize + msg.length + tagLen);
|
|
539
|
-
result.set(actualNonce, 0);
|
|
540
|
-
|
|
541
|
-
const fullBlocks = Math.floor(msg.length / 32) * 32;
|
|
542
|
-
for (let i = 0; i < fullBlocks; i += 32) {
|
|
543
|
-
state.encTo(
|
|
544
|
-
msg.subarray(i, i + 32),
|
|
545
|
-
result.subarray(nonceSize + i, nonceSize + i + 32),
|
|
546
|
-
);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
if (msg.length > fullBlocks) {
|
|
550
|
-
const lastBlock = zeroPad(msg.subarray(fullBlocks), 32);
|
|
551
|
-
const encBlock = state.enc(lastBlock);
|
|
552
|
-
result.set(
|
|
553
|
-
encBlock.subarray(0, msg.length - fullBlocks),
|
|
554
|
-
nonceSize + fullBlocks,
|
|
555
|
-
);
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
const tag = state.finalize(
|
|
559
|
-
BigInt(ad.length * 8),
|
|
560
|
-
BigInt(msg.length * 8),
|
|
561
|
-
tagLen,
|
|
562
|
-
);
|
|
563
|
-
result.set(tag, nonceSize + msg.length);
|
|
564
|
-
|
|
565
|
-
return result;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
/**
|
|
569
|
-
* Decrypts a message using AEGIS-128L.
|
|
570
|
-
* Expects input as nonce || ciphertext || tag.
|
|
571
|
-
* @param sealed - Concatenated nonce || ciphertext || tag
|
|
572
|
-
* @param ad - Associated data (must match what was used during encryption)
|
|
573
|
-
* @param key - 16-byte encryption key
|
|
574
|
-
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
575
|
-
* @returns Decrypted plaintext, or null if authentication fails
|
|
576
|
-
*/
|
|
577
|
-
export function aegis128LDecrypt(
|
|
578
|
-
sealed: Uint8Array,
|
|
579
|
-
ad: Uint8Array,
|
|
580
|
-
key: Uint8Array,
|
|
581
|
-
tagLen: 16 | 32 = 16,
|
|
582
|
-
): Uint8Array | null {
|
|
583
|
-
const nonceSize = AEGIS_128L_NONCE_SIZE;
|
|
584
|
-
if (sealed.length < nonceSize + tagLen) {
|
|
585
|
-
return null;
|
|
586
|
-
}
|
|
587
|
-
const nonce = sealed.subarray(0, nonceSize);
|
|
588
|
-
const ct = sealed.subarray(nonceSize, sealed.length - tagLen);
|
|
589
|
-
const tag = sealed.subarray(sealed.length - tagLen);
|
|
590
|
-
return aegis128LDecryptDetached(ct, tag, ad, key, nonce);
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
/**
|
|
594
|
-
* Computes a MAC (Message Authentication Code) using AEGIS-128L.
|
|
595
|
-
* @param data - Data to authenticate
|
|
596
|
-
* @param key - 16-byte key
|
|
597
|
-
* @param nonce - 16-byte nonce (optional, uses zero nonce if null)
|
|
598
|
-
* @param tagLen - Tag length: 16 or 32 bytes (default: 16)
|
|
599
|
-
* @returns Authentication tag
|
|
600
|
-
*/
|
|
601
|
-
export function aegis128LMac(
|
|
602
|
-
data: Uint8Array,
|
|
603
|
-
key: Uint8Array,
|
|
604
|
-
nonce: Uint8Array | null = null,
|
|
605
|
-
tagLen: 16 | 32 = 16,
|
|
606
|
-
): Uint8Array {
|
|
607
|
-
const state = new Aegis128LState();
|
|
608
|
-
state.init(key, nonce ?? new Uint8Array(16));
|
|
609
|
-
|
|
610
|
-
const dataPadded = zeroPad(data, 32);
|
|
611
|
-
for (let i = 0; i + 32 <= dataPadded.length; i += 32) {
|
|
612
|
-
state.absorb(dataPadded.subarray(i, i + 32));
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
return state.finalize(BigInt(data.length * 8), BigInt(tagLen * 8), tagLen);
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
/**
|
|
619
|
-
* Verifies a MAC computed using AEGIS-128L.
|
|
620
|
-
* @param data - Data to verify
|
|
621
|
-
* @param tag - Expected authentication tag (16 or 32 bytes)
|
|
622
|
-
* @param key - 16-byte key
|
|
623
|
-
* @param nonce - 16-byte nonce (optional, uses zero nonce if null)
|
|
624
|
-
* @returns True if the tag is valid, false otherwise
|
|
625
|
-
*/
|
|
626
|
-
export function aegis128LMacVerify(
|
|
627
|
-
data: Uint8Array,
|
|
628
|
-
tag: Uint8Array,
|
|
629
|
-
key: Uint8Array,
|
|
630
|
-
nonce: Uint8Array | null = null,
|
|
631
|
-
): boolean {
|
|
632
|
-
const tagLen = tag.length as 16 | 32;
|
|
633
|
-
const expectedTag = aegis128LMac(data, key, nonce, tagLen);
|
|
634
|
-
return constantTimeEqual(tag, expectedTag);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
/**
|
|
638
|
-
* Generates a random 16-byte key for AEGIS-128L.
|
|
639
|
-
* @returns 16-byte encryption key
|
|
640
|
-
* @throws Error if no cryptographic random source is available
|
|
641
|
-
*/
|
|
642
|
-
export function aegis128LCreateKey(): Uint8Array {
|
|
643
|
-
return randomBytes(AEGIS_128L_KEY_SIZE);
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
/**
|
|
647
|
-
* Generates a random 16-byte nonce for AEGIS-128L.
|
|
648
|
-
* @returns 16-byte nonce
|
|
649
|
-
* @throws Error if no cryptographic random source is available
|
|
650
|
-
*/
|
|
651
|
-
export function aegis128LCreateNonce(): Uint8Array {
|
|
652
|
-
return randomBytes(AEGIS_128L_NONCE_SIZE);
|
|
653
|
-
}
|