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/aegis256-bs.ts
DELETED
|
@@ -1,519 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bitsliced AEGIS-256 implementation.
|
|
3
|
-
* Provides constant-time operation by processing state blocks simultaneously.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { constantTimeEqual, zeroPad } from "./aes.js";
|
|
7
|
-
import {
|
|
8
|
-
type AesBlock,
|
|
9
|
-
type AesBlocks,
|
|
10
|
-
aesRound,
|
|
11
|
-
blockFromBytes,
|
|
12
|
-
blocksPut,
|
|
13
|
-
blocksRotr6,
|
|
14
|
-
blocksXor,
|
|
15
|
-
blockToBytes,
|
|
16
|
-
blockXor,
|
|
17
|
-
createAesBlock,
|
|
18
|
-
createAesBlocks,
|
|
19
|
-
pack,
|
|
20
|
-
pack04_6,
|
|
21
|
-
unpack,
|
|
22
|
-
unpack04_6,
|
|
23
|
-
wordIdx,
|
|
24
|
-
} from "./aes-bs.js";
|
|
25
|
-
import { randomBytes } from "./random.js";
|
|
26
|
-
|
|
27
|
-
const RATE = 16;
|
|
28
|
-
|
|
29
|
-
const C0: AesBlock = new Uint32Array([
|
|
30
|
-
0x02010100, 0x0d080503, 0x59372215, 0x6279e990,
|
|
31
|
-
]);
|
|
32
|
-
const C1: AesBlock = new Uint32Array([
|
|
33
|
-
0x55183ddb, 0xf12fc26d, 0x42311120, 0xdd28b573,
|
|
34
|
-
]);
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Bitsliced AEGIS-256 cipher state.
|
|
38
|
-
* Uses 6 AES blocks stored in packed bitsliced form throughout the lifetime
|
|
39
|
-
* of the state.
|
|
40
|
-
*/
|
|
41
|
-
export class Aegis256BsState {
|
|
42
|
-
private st: AesBlocks;
|
|
43
|
-
private st1: AesBlocks;
|
|
44
|
-
private constantInput: AesBlocks;
|
|
45
|
-
private tmp: AesBlock;
|
|
46
|
-
private z: AesBlock;
|
|
47
|
-
|
|
48
|
-
constructor() {
|
|
49
|
-
this.st = createAesBlocks();
|
|
50
|
-
this.st1 = createAesBlocks();
|
|
51
|
-
this.constantInput = createAesBlocks();
|
|
52
|
-
this.tmp = createAesBlock();
|
|
53
|
-
this.z = createAesBlock();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
private aegisRoundPacked(): void {
|
|
57
|
-
const st = this.st;
|
|
58
|
-
const st1 = this.st1;
|
|
59
|
-
|
|
60
|
-
st1.set(st);
|
|
61
|
-
aesRound(st1);
|
|
62
|
-
blocksRotr6(st1);
|
|
63
|
-
blocksXor(st, st1);
|
|
64
|
-
blocksXor(st, this.constantInput);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
private packConstantInput(m: AesBlock): void {
|
|
68
|
-
const out = this.constantInput;
|
|
69
|
-
out.fill(0);
|
|
70
|
-
blocksPut(out, m, 0);
|
|
71
|
-
pack04_6(out);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Extract the keystream block z directly from the packed state.
|
|
76
|
-
*
|
|
77
|
-
* z = S1 ^ S4 ^ S5 ^ (S2 & S3)
|
|
78
|
-
*
|
|
79
|
-
* In the packed layout, logical block j lives at bit position (7 - j) of
|
|
80
|
-
* every byte, so S1 = bit 6, S4 = bit 3, S5 = bit 2, S2 = bit 5,
|
|
81
|
-
* S3 = bit 4. The combination is computed lane-wise into bit position 7
|
|
82
|
-
* and unpack04_6 then extracts the AES block at logical index 0.
|
|
83
|
-
*/
|
|
84
|
-
private keystreamPacked(): void {
|
|
85
|
-
const st = this.st;
|
|
86
|
-
const zPacked = this.st1;
|
|
87
|
-
for (let i = 0; i < 32; i++) {
|
|
88
|
-
const x = st[i]!;
|
|
89
|
-
zPacked[i] =
|
|
90
|
-
((x & 0x40404040) << 1) ^
|
|
91
|
-
((x & 0x08080808) << 4) ^
|
|
92
|
-
((x & 0x04040404) << 5) ^
|
|
93
|
-
((x & (x >>> 1) & 0x10101010) << 3);
|
|
94
|
-
}
|
|
95
|
-
unpack04_6(zPacked);
|
|
96
|
-
const z = this.z;
|
|
97
|
-
for (let i = 0; i < 4; i++) {
|
|
98
|
-
z[i] = zPacked[wordIdx(0, i)]!;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Initializes the state with a key and nonce.
|
|
104
|
-
* @param key - 32-byte encryption key
|
|
105
|
-
* @param nonce - 32-byte nonce (must be unique per message)
|
|
106
|
-
*/
|
|
107
|
-
init(key: Uint8Array, nonce: Uint8Array): void {
|
|
108
|
-
const k0 = createAesBlock();
|
|
109
|
-
const k1 = createAesBlock();
|
|
110
|
-
const n0 = createAesBlock();
|
|
111
|
-
const n1 = createAesBlock();
|
|
112
|
-
const k0n0 = createAesBlock();
|
|
113
|
-
const k1n1 = createAesBlock();
|
|
114
|
-
const k0c0 = createAesBlock();
|
|
115
|
-
const k1c1 = createAesBlock();
|
|
116
|
-
|
|
117
|
-
blockFromBytes(k0, key.subarray(0, 16));
|
|
118
|
-
blockFromBytes(k1, key.subarray(16, 32));
|
|
119
|
-
blockFromBytes(n0, nonce.subarray(0, 16));
|
|
120
|
-
blockFromBytes(n1, nonce.subarray(16, 32));
|
|
121
|
-
blockXor(k0n0, k0, n0);
|
|
122
|
-
blockXor(k1n1, k1, n1);
|
|
123
|
-
blockXor(k0c0, k0, C0);
|
|
124
|
-
blockXor(k1c1, k1, C1);
|
|
125
|
-
|
|
126
|
-
this.st.fill(0);
|
|
127
|
-
blocksPut(this.st, k0n0, 0);
|
|
128
|
-
blocksPut(this.st, k1n1, 1);
|
|
129
|
-
blocksPut(this.st, C1, 2);
|
|
130
|
-
blocksPut(this.st, C0, 3);
|
|
131
|
-
blocksPut(this.st, k0c0, 4);
|
|
132
|
-
blocksPut(this.st, k1c1, 5);
|
|
133
|
-
|
|
134
|
-
pack(this.st);
|
|
135
|
-
for (let i = 0; i < 4; i++) {
|
|
136
|
-
this.packConstantInput(k0);
|
|
137
|
-
this.aegisRoundPacked();
|
|
138
|
-
this.packConstantInput(k1);
|
|
139
|
-
this.aegisRoundPacked();
|
|
140
|
-
this.packConstantInput(k0n0);
|
|
141
|
-
this.aegisRoundPacked();
|
|
142
|
-
this.packConstantInput(k1n1);
|
|
143
|
-
this.aegisRoundPacked();
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Absorbs a 16-byte associated data block into the state.
|
|
149
|
-
*/
|
|
150
|
-
absorb(ai: Uint8Array): void {
|
|
151
|
-
const msg = this.tmp;
|
|
152
|
-
blockFromBytes(msg, ai);
|
|
153
|
-
this.packConstantInput(msg);
|
|
154
|
-
this.aegisRoundPacked();
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Encrypts a 16-byte plaintext block and writes to output buffer.
|
|
159
|
-
*/
|
|
160
|
-
encTo(xi: Uint8Array, out: Uint8Array): void {
|
|
161
|
-
const t = this.tmp;
|
|
162
|
-
|
|
163
|
-
this.keystreamPacked();
|
|
164
|
-
|
|
165
|
-
blockFromBytes(t, xi);
|
|
166
|
-
this.packConstantInput(t);
|
|
167
|
-
this.aegisRoundPacked();
|
|
168
|
-
|
|
169
|
-
blockXor(t, t, this.z);
|
|
170
|
-
blockToBytes(out, t);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
enc(xi: Uint8Array): Uint8Array {
|
|
174
|
-
const out = new Uint8Array(16);
|
|
175
|
-
this.encTo(xi, out);
|
|
176
|
-
return out;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Decrypts a 16-byte ciphertext block and writes to output buffer.
|
|
181
|
-
*/
|
|
182
|
-
decTo(ci: Uint8Array, out: Uint8Array): void {
|
|
183
|
-
const msg = this.tmp;
|
|
184
|
-
|
|
185
|
-
blockFromBytes(msg, ci);
|
|
186
|
-
this.keystreamPacked();
|
|
187
|
-
blockXor(msg, msg, this.z);
|
|
188
|
-
|
|
189
|
-
this.packConstantInput(msg);
|
|
190
|
-
this.aegisRoundPacked();
|
|
191
|
-
|
|
192
|
-
blockToBytes(out, msg);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
dec(ci: Uint8Array): Uint8Array {
|
|
196
|
-
const out = new Uint8Array(16);
|
|
197
|
-
this.decTo(ci, out);
|
|
198
|
-
return out;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
encInPlace(block: Uint8Array): void {
|
|
202
|
-
this.encTo(block, block);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
decInPlace(block: Uint8Array): void {
|
|
206
|
-
this.decTo(block, block);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
decPartial(cn: Uint8Array): Uint8Array {
|
|
210
|
-
const msg = this.tmp;
|
|
211
|
-
|
|
212
|
-
const padded = zeroPad(cn, RATE);
|
|
213
|
-
blockFromBytes(msg, padded);
|
|
214
|
-
|
|
215
|
-
this.keystreamPacked();
|
|
216
|
-
blockXor(msg, msg, this.z);
|
|
217
|
-
|
|
218
|
-
const pad = new Uint8Array(RATE);
|
|
219
|
-
blockToBytes(pad, msg);
|
|
220
|
-
|
|
221
|
-
const xn = new Uint8Array(pad.subarray(0, cn.length));
|
|
222
|
-
|
|
223
|
-
pad.fill(0, cn.length);
|
|
224
|
-
blockFromBytes(msg, pad);
|
|
225
|
-
|
|
226
|
-
this.packConstantInput(msg);
|
|
227
|
-
this.aegisRoundPacked();
|
|
228
|
-
|
|
229
|
-
return xn;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Finalizes encryption/decryption and produces an authentication tag.
|
|
234
|
-
*/
|
|
235
|
-
finalize(adLen: number, msgLen: number, tagLen: 16 | 32 = 16): Uint8Array {
|
|
236
|
-
const st = this.st;
|
|
237
|
-
const tmp = this.tmp;
|
|
238
|
-
|
|
239
|
-
tmp[0] = ((adLen * 8) & 0xffffffff) >>> 0;
|
|
240
|
-
tmp[1] = Math.floor((adLen * 8) / 0x100000000) >>> 0;
|
|
241
|
-
tmp[2] = ((msgLen * 8) & 0xffffffff) >>> 0;
|
|
242
|
-
tmp[3] = Math.floor((msgLen * 8) / 0x100000000) >>> 0;
|
|
243
|
-
|
|
244
|
-
const unpacked = this.st1;
|
|
245
|
-
unpacked.set(st);
|
|
246
|
-
unpack(unpacked);
|
|
247
|
-
|
|
248
|
-
tmp[0] = (tmp[0]! ^ unpacked[wordIdx(3, 0)]!) >>> 0;
|
|
249
|
-
tmp[1] = (tmp[1]! ^ unpacked[wordIdx(3, 1)]!) >>> 0;
|
|
250
|
-
tmp[2] = (tmp[2]! ^ unpacked[wordIdx(3, 2)]!) >>> 0;
|
|
251
|
-
tmp[3] = (tmp[3]! ^ unpacked[wordIdx(3, 3)]!) >>> 0;
|
|
252
|
-
|
|
253
|
-
this.packConstantInput(tmp);
|
|
254
|
-
for (let i = 0; i < 7; i++) {
|
|
255
|
-
this.aegisRoundPacked();
|
|
256
|
-
}
|
|
257
|
-
unpack(st);
|
|
258
|
-
|
|
259
|
-
if (tagLen === 16) {
|
|
260
|
-
const tag = new Uint8Array(16);
|
|
261
|
-
const tagBlock = createAesBlock();
|
|
262
|
-
for (let i = 0; i < 4; i++) {
|
|
263
|
-
tagBlock[i] =
|
|
264
|
-
(st[wordIdx(0, i)]! ^
|
|
265
|
-
st[wordIdx(1, i)]! ^
|
|
266
|
-
st[wordIdx(2, i)]! ^
|
|
267
|
-
st[wordIdx(3, i)]! ^
|
|
268
|
-
st[wordIdx(4, i)]! ^
|
|
269
|
-
st[wordIdx(5, i)]!) >>>
|
|
270
|
-
0;
|
|
271
|
-
}
|
|
272
|
-
blockToBytes(tag, tagBlock);
|
|
273
|
-
return tag;
|
|
274
|
-
} else {
|
|
275
|
-
const tag = new Uint8Array(32);
|
|
276
|
-
const tagBlock0 = createAesBlock();
|
|
277
|
-
const tagBlock1 = createAesBlock();
|
|
278
|
-
for (let i = 0; i < 4; i++) {
|
|
279
|
-
tagBlock0[i] =
|
|
280
|
-
(st[wordIdx(0, i)]! ^ st[wordIdx(1, i)]! ^ st[wordIdx(2, i)]!) >>> 0;
|
|
281
|
-
}
|
|
282
|
-
for (let i = 0; i < 4; i++) {
|
|
283
|
-
tagBlock1[i] =
|
|
284
|
-
(st[wordIdx(3, i)]! ^ st[wordIdx(4, i)]! ^ st[wordIdx(5, i)]!) >>> 0;
|
|
285
|
-
}
|
|
286
|
-
blockToBytes(tag.subarray(0, 16), tagBlock0);
|
|
287
|
-
blockToBytes(tag.subarray(16, 32), tagBlock1);
|
|
288
|
-
return tag;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Encrypts a message using bitsliced AEGIS-256 (detached mode).
|
|
295
|
-
*/
|
|
296
|
-
export function aegis256BsEncryptDetached(
|
|
297
|
-
msg: Uint8Array,
|
|
298
|
-
ad: Uint8Array,
|
|
299
|
-
key: Uint8Array,
|
|
300
|
-
nonce: Uint8Array,
|
|
301
|
-
tagLen: 16 | 32 = 16,
|
|
302
|
-
): { ciphertext: Uint8Array; tag: Uint8Array } {
|
|
303
|
-
const state = new Aegis256BsState();
|
|
304
|
-
state.init(key, nonce);
|
|
305
|
-
|
|
306
|
-
const adPadded = zeroPad(ad, RATE);
|
|
307
|
-
for (let i = 0; i + RATE <= adPadded.length; i += RATE) {
|
|
308
|
-
state.absorb(adPadded.subarray(i, i + RATE));
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const ciphertext = new Uint8Array(msg.length);
|
|
312
|
-
const fullBlocks = Math.floor(msg.length / RATE) * RATE;
|
|
313
|
-
|
|
314
|
-
for (let i = 0; i < fullBlocks; i += RATE) {
|
|
315
|
-
state.encTo(msg.subarray(i, i + RATE), ciphertext.subarray(i, i + RATE));
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (msg.length > fullBlocks) {
|
|
319
|
-
const lastBlock = zeroPad(msg.subarray(fullBlocks), RATE);
|
|
320
|
-
const encBlock = state.enc(lastBlock);
|
|
321
|
-
ciphertext.set(encBlock.subarray(0, msg.length - fullBlocks), fullBlocks);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
const tag = state.finalize(ad.length, msg.length, tagLen);
|
|
325
|
-
|
|
326
|
-
return { ciphertext, tag };
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* Decrypts a message using bitsliced AEGIS-256 (detached mode).
|
|
331
|
-
*/
|
|
332
|
-
export function aegis256BsDecryptDetached(
|
|
333
|
-
ct: Uint8Array,
|
|
334
|
-
tag: Uint8Array,
|
|
335
|
-
ad: Uint8Array,
|
|
336
|
-
key: Uint8Array,
|
|
337
|
-
nonce: Uint8Array,
|
|
338
|
-
): Uint8Array | null {
|
|
339
|
-
const tagLen = tag.length as 16 | 32;
|
|
340
|
-
const state = new Aegis256BsState();
|
|
341
|
-
state.init(key, nonce);
|
|
342
|
-
|
|
343
|
-
const adPadded = zeroPad(ad, RATE);
|
|
344
|
-
for (let i = 0; i + RATE <= adPadded.length; i += RATE) {
|
|
345
|
-
state.absorb(adPadded.subarray(i, i + RATE));
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const msg = new Uint8Array(ct.length);
|
|
349
|
-
const fullBlocks = Math.floor(ct.length / RATE) * RATE;
|
|
350
|
-
|
|
351
|
-
for (let i = 0; i < fullBlocks; i += RATE) {
|
|
352
|
-
state.decTo(ct.subarray(i, i + RATE), msg.subarray(i, i + RATE));
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
if (ct.length > fullBlocks) {
|
|
356
|
-
msg.set(state.decPartial(ct.subarray(fullBlocks)), fullBlocks);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
const expectedTag = state.finalize(ad.length, msg.length, tagLen);
|
|
360
|
-
|
|
361
|
-
if (!constantTimeEqual(tag, expectedTag)) {
|
|
362
|
-
msg.fill(0);
|
|
363
|
-
return null;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
return msg;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
export function aegis256BsEncryptDetachedInPlace(
|
|
370
|
-
data: Uint8Array,
|
|
371
|
-
ad: Uint8Array,
|
|
372
|
-
key: Uint8Array,
|
|
373
|
-
nonce: Uint8Array,
|
|
374
|
-
tagLen: 16 | 32 = 16,
|
|
375
|
-
): Uint8Array {
|
|
376
|
-
const state = new Aegis256BsState();
|
|
377
|
-
state.init(key, nonce);
|
|
378
|
-
|
|
379
|
-
const adPadded = zeroPad(ad, RATE);
|
|
380
|
-
for (let i = 0; i + RATE <= adPadded.length; i += RATE) {
|
|
381
|
-
state.absorb(adPadded.subarray(i, i + RATE));
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
const msgLen = data.length;
|
|
385
|
-
const fullBlocksLen = Math.floor(msgLen / RATE) * RATE;
|
|
386
|
-
|
|
387
|
-
for (let i = 0; i < fullBlocksLen; i += RATE) {
|
|
388
|
-
state.encInPlace(data.subarray(i, i + RATE));
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
if (msgLen > fullBlocksLen) {
|
|
392
|
-
const lastPartial = data.subarray(fullBlocksLen);
|
|
393
|
-
const lastBlock = zeroPad(lastPartial, RATE);
|
|
394
|
-
const encBlock = state.enc(lastBlock);
|
|
395
|
-
lastPartial.set(encBlock.subarray(0, lastPartial.length));
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
return state.finalize(ad.length, msgLen, tagLen);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
export function aegis256BsDecryptDetachedInPlace(
|
|
402
|
-
data: Uint8Array,
|
|
403
|
-
tag: Uint8Array,
|
|
404
|
-
ad: Uint8Array,
|
|
405
|
-
key: Uint8Array,
|
|
406
|
-
nonce: Uint8Array,
|
|
407
|
-
): boolean {
|
|
408
|
-
const tagLen = tag.length as 16 | 32;
|
|
409
|
-
const state = new Aegis256BsState();
|
|
410
|
-
state.init(key, nonce);
|
|
411
|
-
|
|
412
|
-
const adPadded = zeroPad(ad, RATE);
|
|
413
|
-
for (let i = 0; i + RATE <= adPadded.length; i += RATE) {
|
|
414
|
-
state.absorb(adPadded.subarray(i, i + RATE));
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
const msgLen = data.length;
|
|
418
|
-
const fullBlocksLen = Math.floor(msgLen / RATE) * RATE;
|
|
419
|
-
|
|
420
|
-
for (let i = 0; i < fullBlocksLen; i += RATE) {
|
|
421
|
-
state.decInPlace(data.subarray(i, i + RATE));
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
if (msgLen > fullBlocksLen) {
|
|
425
|
-
const lastPartial = data.subarray(fullBlocksLen);
|
|
426
|
-
const decrypted = state.decPartial(lastPartial);
|
|
427
|
-
lastPartial.set(decrypted);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
const expectedTag = state.finalize(ad.length, msgLen, tagLen);
|
|
431
|
-
|
|
432
|
-
if (!constantTimeEqual(tag, expectedTag)) {
|
|
433
|
-
data.fill(0);
|
|
434
|
-
return false;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
return true;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
export const AEGIS_256_BS_NONCE_SIZE = 32;
|
|
441
|
-
export const AEGIS_256_BS_KEY_SIZE = 32;
|
|
442
|
-
|
|
443
|
-
export function aegis256BsEncrypt(
|
|
444
|
-
msg: Uint8Array,
|
|
445
|
-
ad: Uint8Array,
|
|
446
|
-
key: Uint8Array,
|
|
447
|
-
nonce: Uint8Array | null = null,
|
|
448
|
-
tagLen: 16 | 32 = 16,
|
|
449
|
-
): Uint8Array {
|
|
450
|
-
const actualNonce = nonce ?? randomBytes(AEGIS_256_BS_NONCE_SIZE);
|
|
451
|
-
const { ciphertext, tag } = aegis256BsEncryptDetached(
|
|
452
|
-
msg,
|
|
453
|
-
ad,
|
|
454
|
-
key,
|
|
455
|
-
actualNonce,
|
|
456
|
-
tagLen,
|
|
457
|
-
);
|
|
458
|
-
|
|
459
|
-
const result = new Uint8Array(
|
|
460
|
-
AEGIS_256_BS_NONCE_SIZE + ciphertext.length + tagLen,
|
|
461
|
-
);
|
|
462
|
-
result.set(actualNonce, 0);
|
|
463
|
-
result.set(ciphertext, AEGIS_256_BS_NONCE_SIZE);
|
|
464
|
-
result.set(tag, AEGIS_256_BS_NONCE_SIZE + ciphertext.length);
|
|
465
|
-
|
|
466
|
-
return result;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
export function aegis256BsDecrypt(
|
|
470
|
-
sealed: Uint8Array,
|
|
471
|
-
ad: Uint8Array,
|
|
472
|
-
key: Uint8Array,
|
|
473
|
-
tagLen: 16 | 32 = 16,
|
|
474
|
-
): Uint8Array | null {
|
|
475
|
-
const nonceSize = AEGIS_256_BS_NONCE_SIZE;
|
|
476
|
-
if (sealed.length < nonceSize + tagLen) {
|
|
477
|
-
return null;
|
|
478
|
-
}
|
|
479
|
-
const nonce = sealed.subarray(0, nonceSize);
|
|
480
|
-
const ct = sealed.subarray(nonceSize, sealed.length - tagLen);
|
|
481
|
-
const tag = sealed.subarray(sealed.length - tagLen);
|
|
482
|
-
return aegis256BsDecryptDetached(ct, tag, ad, key, nonce);
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
export function aegis256BsMac(
|
|
486
|
-
data: Uint8Array,
|
|
487
|
-
key: Uint8Array,
|
|
488
|
-
nonce: Uint8Array | null = null,
|
|
489
|
-
tagLen: 16 | 32 = 16,
|
|
490
|
-
): Uint8Array {
|
|
491
|
-
const state = new Aegis256BsState();
|
|
492
|
-
state.init(key, nonce ?? new Uint8Array(32));
|
|
493
|
-
|
|
494
|
-
const dataPadded = zeroPad(data, RATE);
|
|
495
|
-
for (let i = 0; i + RATE <= dataPadded.length; i += RATE) {
|
|
496
|
-
state.absorb(dataPadded.subarray(i, i + RATE));
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
return state.finalize(data.length, tagLen, tagLen);
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
export function aegis256BsMacVerify(
|
|
503
|
-
data: Uint8Array,
|
|
504
|
-
tag: Uint8Array,
|
|
505
|
-
key: Uint8Array,
|
|
506
|
-
nonce: Uint8Array | null = null,
|
|
507
|
-
): boolean {
|
|
508
|
-
const tagLen = tag.length as 16 | 32;
|
|
509
|
-
const expectedTag = aegis256BsMac(data, key, nonce, tagLen);
|
|
510
|
-
return constantTimeEqual(tag, expectedTag);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
export function aegis256BsCreateKey(): Uint8Array {
|
|
514
|
-
return randomBytes(AEGIS_256_BS_KEY_SIZE);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
export function aegis256BsCreateNonce(): Uint8Array {
|
|
518
|
-
return randomBytes(AEGIS_256_BS_NONCE_SIZE);
|
|
519
|
-
}
|