aegis-aead 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +195 -89
- package/dist/aegis128l-bs.d.ts +194 -0
- package/dist/aegis128l-bs.d.ts.map +1 -0
- package/dist/aegis128l-bs.js +549 -0
- package/dist/aegis128l-bs.js.map +1 -0
- package/dist/aegis128l.d.ts +74 -5
- package/dist/aegis128l.d.ts.map +1 -1
- package/dist/aegis128l.js +173 -5
- package/dist/aegis128l.js.map +1 -1
- package/dist/aegis128x.d.ts +109 -12
- package/dist/aegis128x.d.ts.map +1 -1
- package/dist/aegis128x.js +202 -9
- package/dist/aegis128x.js.map +1 -1
- package/dist/aegis256-bs.d.ts +183 -0
- package/dist/aegis256-bs.d.ts.map +1 -0
- package/dist/aegis256-bs.js +477 -0
- package/dist/aegis256-bs.js.map +1 -0
- package/dist/aegis256.d.ts +74 -5
- package/dist/aegis256.d.ts.map +1 -1
- package/dist/aegis256.js +158 -5
- package/dist/aegis256.js.map +1 -1
- package/dist/aegis256x.d.ts +109 -12
- package/dist/aegis256x.d.ts.map +1 -1
- package/dist/aegis256x.js +193 -9
- package/dist/aegis256x.js.map +1 -1
- package/dist/aes-bs.d.ts +71 -0
- package/dist/aes-bs.d.ts.map +1 -0
- package/dist/aes-bs.js +399 -0
- package/dist/aes-bs.js.map +1 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/random.d.ts +22 -0
- package/dist/random.d.ts.map +1 -0
- package/dist/random.js +36 -0
- package/dist/random.js.map +1 -0
- package/package.json +1 -1
- package/src/aegis128l-bs.ts +709 -0
- package/src/aegis128l.ts +238 -5
- package/src/aegis128x.ts +342 -15
- package/src/aegis256-bs.ts +625 -0
- package/src/aegis256.ts +223 -5
- package/src/aegis256x.ts +329 -15
- package/src/aes-bs.ts +459 -0
- package/src/index.ts +86 -0
- package/src/random.ts +41 -0
- package/README.md~ +0 -154
package/src/aegis256.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
xorBlocksTo,
|
|
9
9
|
zeroPad,
|
|
10
10
|
} from "./aes.js";
|
|
11
|
+
import { randomBytes } from "./random.js";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* AEGIS-256 cipher state.
|
|
@@ -172,6 +173,22 @@ export class Aegis256State {
|
|
|
172
173
|
return out;
|
|
173
174
|
}
|
|
174
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Encrypts a 16-byte plaintext block in-place.
|
|
178
|
+
* @param block - 16-byte buffer (plaintext in, ciphertext out)
|
|
179
|
+
*/
|
|
180
|
+
encInPlace(block: Uint8Array): void {
|
|
181
|
+
this.encTo(block, block);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Decrypts a 16-byte ciphertext block in-place.
|
|
186
|
+
* @param block - 16-byte buffer (ciphertext in, plaintext out)
|
|
187
|
+
*/
|
|
188
|
+
decInPlace(block: Uint8Array): void {
|
|
189
|
+
this.decTo(block, block);
|
|
190
|
+
}
|
|
191
|
+
|
|
175
192
|
/**
|
|
176
193
|
* Decrypts a partial (final) ciphertext block smaller than 16 bytes.
|
|
177
194
|
* @param cn - Partial ciphertext block (1-15 bytes)
|
|
@@ -244,15 +261,15 @@ export class Aegis256State {
|
|
|
244
261
|
}
|
|
245
262
|
|
|
246
263
|
/**
|
|
247
|
-
* Encrypts a message using AEGIS-256.
|
|
264
|
+
* Encrypts a message using AEGIS-256 (detached mode).
|
|
248
265
|
* @param msg - Plaintext message
|
|
249
266
|
* @param ad - Associated data (authenticated but not encrypted)
|
|
250
267
|
* @param key - 32-byte encryption key
|
|
251
268
|
* @param nonce - 32-byte nonce (must be unique per message with the same key)
|
|
252
269
|
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
253
|
-
* @returns Object containing ciphertext and authentication tag
|
|
270
|
+
* @returns Object containing ciphertext and authentication tag separately
|
|
254
271
|
*/
|
|
255
|
-
export function
|
|
272
|
+
export function aegis256EncryptDetached(
|
|
256
273
|
msg: Uint8Array,
|
|
257
274
|
ad: Uint8Array,
|
|
258
275
|
key: Uint8Array,
|
|
@@ -284,7 +301,7 @@ export function aegis256Encrypt(
|
|
|
284
301
|
}
|
|
285
302
|
|
|
286
303
|
/**
|
|
287
|
-
* Decrypts a message using AEGIS-256.
|
|
304
|
+
* Decrypts a message using AEGIS-256 (detached mode).
|
|
288
305
|
* @param ct - Ciphertext
|
|
289
306
|
* @param tag - Authentication tag (16 or 32 bytes)
|
|
290
307
|
* @param ad - Associated data (must match what was used during encryption)
|
|
@@ -292,7 +309,7 @@ export function aegis256Encrypt(
|
|
|
292
309
|
* @param nonce - 32-byte nonce (must match what was used during encryption)
|
|
293
310
|
* @returns Decrypted plaintext, or null if authentication fails
|
|
294
311
|
*/
|
|
295
|
-
export function
|
|
312
|
+
export function aegis256DecryptDetached(
|
|
296
313
|
ct: Uint8Array,
|
|
297
314
|
tag: Uint8Array,
|
|
298
315
|
ad: Uint8Array,
|
|
@@ -334,6 +351,189 @@ export function aegis256Decrypt(
|
|
|
334
351
|
return msg;
|
|
335
352
|
}
|
|
336
353
|
|
|
354
|
+
/**
|
|
355
|
+
* Encrypts a message in-place using AEGIS-256 (detached mode).
|
|
356
|
+
* The input buffer is modified to contain the ciphertext.
|
|
357
|
+
* @param data - Buffer containing plaintext (will be overwritten with ciphertext)
|
|
358
|
+
* @param ad - Associated data (authenticated but not encrypted)
|
|
359
|
+
* @param key - 32-byte encryption key
|
|
360
|
+
* @param nonce - 32-byte nonce (must be unique per message with the same key)
|
|
361
|
+
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
362
|
+
* @returns Authentication tag
|
|
363
|
+
*/
|
|
364
|
+
export function aegis256EncryptDetachedInPlace(
|
|
365
|
+
data: Uint8Array,
|
|
366
|
+
ad: Uint8Array,
|
|
367
|
+
key: Uint8Array,
|
|
368
|
+
nonce: Uint8Array,
|
|
369
|
+
tagLen: 16 | 32 = 16,
|
|
370
|
+
): Uint8Array {
|
|
371
|
+
const state = new Aegis256State();
|
|
372
|
+
state.init(key, nonce);
|
|
373
|
+
|
|
374
|
+
const adPadded = zeroPad(ad, 16);
|
|
375
|
+
for (let i = 0; i + 16 <= adPadded.length; i += 16) {
|
|
376
|
+
state.absorb(adPadded.subarray(i, i + 16));
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const msgLen = data.length;
|
|
380
|
+
const fullBlocksLen = Math.floor(msgLen / 16) * 16;
|
|
381
|
+
|
|
382
|
+
for (let i = 0; i < fullBlocksLen; i += 16) {
|
|
383
|
+
state.encInPlace(data.subarray(i, i + 16));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (msgLen > fullBlocksLen) {
|
|
387
|
+
const lastPartial = data.subarray(fullBlocksLen);
|
|
388
|
+
const lastBlock = zeroPad(lastPartial, 16);
|
|
389
|
+
const encBlock = state.enc(lastBlock);
|
|
390
|
+
lastPartial.set(encBlock.subarray(0, lastPartial.length));
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return state.finalize(BigInt(ad.length * 8), BigInt(msgLen * 8), tagLen);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Decrypts a message in-place using AEGIS-256 (detached mode).
|
|
398
|
+
* The input buffer is modified to contain the plaintext (or zeroed on failure).
|
|
399
|
+
* @param data - Buffer containing ciphertext (will be overwritten with plaintext)
|
|
400
|
+
* @param tag - Authentication tag (16 or 32 bytes)
|
|
401
|
+
* @param ad - Associated data (must match what was used during encryption)
|
|
402
|
+
* @param key - 32-byte encryption key
|
|
403
|
+
* @param nonce - 32-byte nonce (must match what was used during encryption)
|
|
404
|
+
* @returns True if authentication succeeds, false otherwise
|
|
405
|
+
*/
|
|
406
|
+
export function aegis256DecryptDetachedInPlace(
|
|
407
|
+
data: Uint8Array,
|
|
408
|
+
tag: Uint8Array,
|
|
409
|
+
ad: Uint8Array,
|
|
410
|
+
key: Uint8Array,
|
|
411
|
+
nonce: Uint8Array,
|
|
412
|
+
): boolean {
|
|
413
|
+
const tagLen = tag.length as 16 | 32;
|
|
414
|
+
const state = new Aegis256State();
|
|
415
|
+
state.init(key, nonce);
|
|
416
|
+
|
|
417
|
+
const adPadded = zeroPad(ad, 16);
|
|
418
|
+
for (let i = 0; i + 16 <= adPadded.length; i += 16) {
|
|
419
|
+
state.absorb(adPadded.subarray(i, i + 16));
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const msgLen = data.length;
|
|
423
|
+
const fullBlocksLen = Math.floor(msgLen / 16) * 16;
|
|
424
|
+
|
|
425
|
+
for (let i = 0; i < fullBlocksLen; i += 16) {
|
|
426
|
+
state.decInPlace(data.subarray(i, i + 16));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (msgLen > fullBlocksLen) {
|
|
430
|
+
const lastPartial = data.subarray(fullBlocksLen);
|
|
431
|
+
const decrypted = state.decPartial(lastPartial);
|
|
432
|
+
lastPartial.set(decrypted);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const expectedTag = state.finalize(
|
|
436
|
+
BigInt(ad.length * 8),
|
|
437
|
+
BigInt(msgLen * 8),
|
|
438
|
+
tagLen,
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
if (!constantTimeEqual(tag, expectedTag)) {
|
|
442
|
+
data.fill(0);
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/** Nonce size for AEGIS-256 in bytes. */
|
|
450
|
+
export const AEGIS_256_NONCE_SIZE = 32;
|
|
451
|
+
|
|
452
|
+
/** Key size for AEGIS-256 in bytes. */
|
|
453
|
+
export const AEGIS_256_KEY_SIZE = 32;
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Encrypts a message using AEGIS-256.
|
|
457
|
+
* Returns a single buffer containing nonce || ciphertext || tag.
|
|
458
|
+
* @param msg - Plaintext message
|
|
459
|
+
* @param ad - Associated data (authenticated but not encrypted)
|
|
460
|
+
* @param key - 32-byte encryption key
|
|
461
|
+
* @param nonce - 32-byte nonce (optional, generates random nonce if not provided)
|
|
462
|
+
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
463
|
+
* @returns Concatenated nonce || ciphertext || tag
|
|
464
|
+
*/
|
|
465
|
+
export function aegis256Encrypt(
|
|
466
|
+
msg: Uint8Array,
|
|
467
|
+
ad: Uint8Array,
|
|
468
|
+
key: Uint8Array,
|
|
469
|
+
nonce: Uint8Array | null = null,
|
|
470
|
+
tagLen: 16 | 32 = 16,
|
|
471
|
+
): Uint8Array {
|
|
472
|
+
const actualNonce = nonce ?? randomBytes(AEGIS_256_NONCE_SIZE);
|
|
473
|
+
const state = new Aegis256State();
|
|
474
|
+
state.init(key, actualNonce);
|
|
475
|
+
|
|
476
|
+
const adPadded = zeroPad(ad, 16);
|
|
477
|
+
for (let i = 0; i + 16 <= adPadded.length; i += 16) {
|
|
478
|
+
state.absorb(adPadded.subarray(i, i + 16));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const nonceSize = AEGIS_256_NONCE_SIZE;
|
|
482
|
+
const result = new Uint8Array(nonceSize + msg.length + tagLen);
|
|
483
|
+
result.set(actualNonce, 0);
|
|
484
|
+
|
|
485
|
+
const fullBlocks = Math.floor(msg.length / 16) * 16;
|
|
486
|
+
for (let i = 0; i < fullBlocks; i += 16) {
|
|
487
|
+
state.encTo(
|
|
488
|
+
msg.subarray(i, i + 16),
|
|
489
|
+
result.subarray(nonceSize + i, nonceSize + i + 16),
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
if (msg.length > fullBlocks) {
|
|
494
|
+
const lastBlock = zeroPad(msg.subarray(fullBlocks), 16);
|
|
495
|
+
const encBlock = state.enc(lastBlock);
|
|
496
|
+
result.set(
|
|
497
|
+
encBlock.subarray(0, msg.length - fullBlocks),
|
|
498
|
+
nonceSize + fullBlocks,
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const tag = state.finalize(
|
|
503
|
+
BigInt(ad.length * 8),
|
|
504
|
+
BigInt(msg.length * 8),
|
|
505
|
+
tagLen,
|
|
506
|
+
);
|
|
507
|
+
result.set(tag, nonceSize + msg.length);
|
|
508
|
+
|
|
509
|
+
return result;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Decrypts a message using AEGIS-256.
|
|
514
|
+
* Expects input as nonce || ciphertext || tag.
|
|
515
|
+
* @param sealed - Concatenated nonce || ciphertext || tag
|
|
516
|
+
* @param ad - Associated data (must match what was used during encryption)
|
|
517
|
+
* @param key - 32-byte encryption key
|
|
518
|
+
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
519
|
+
* @returns Decrypted plaintext, or null if authentication fails
|
|
520
|
+
*/
|
|
521
|
+
export function aegis256Decrypt(
|
|
522
|
+
sealed: Uint8Array,
|
|
523
|
+
ad: Uint8Array,
|
|
524
|
+
key: Uint8Array,
|
|
525
|
+
tagLen: 16 | 32 = 16,
|
|
526
|
+
): Uint8Array | null {
|
|
527
|
+
const nonceSize = AEGIS_256_NONCE_SIZE;
|
|
528
|
+
if (sealed.length < nonceSize + tagLen) {
|
|
529
|
+
return null;
|
|
530
|
+
}
|
|
531
|
+
const nonce = sealed.subarray(0, nonceSize);
|
|
532
|
+
const ct = sealed.subarray(nonceSize, sealed.length - tagLen);
|
|
533
|
+
const tag = sealed.subarray(sealed.length - tagLen);
|
|
534
|
+
return aegis256DecryptDetached(ct, tag, ad, key, nonce);
|
|
535
|
+
}
|
|
536
|
+
|
|
337
537
|
/**
|
|
338
538
|
* Computes a MAC (Message Authentication Code) using AEGIS-256.
|
|
339
539
|
* @param data - Data to authenticate
|
|
@@ -377,3 +577,21 @@ export function aegis256MacVerify(
|
|
|
377
577
|
const expectedTag = aegis256Mac(data, key, nonce, tagLen);
|
|
378
578
|
return constantTimeEqual(tag, expectedTag);
|
|
379
579
|
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Generates a random 32-byte key for AEGIS-256.
|
|
583
|
+
* @returns 32-byte encryption key
|
|
584
|
+
* @throws Error if no cryptographic random source is available
|
|
585
|
+
*/
|
|
586
|
+
export function aegis256CreateKey(): Uint8Array {
|
|
587
|
+
return randomBytes(AEGIS_256_KEY_SIZE);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Generates a random 32-byte nonce for AEGIS-256.
|
|
592
|
+
* @returns 32-byte nonce
|
|
593
|
+
* @throws Error if no cryptographic random source is available
|
|
594
|
+
*/
|
|
595
|
+
export function aegis256CreateNonce(): Uint8Array {
|
|
596
|
+
return randomBytes(AEGIS_256_NONCE_SIZE);
|
|
597
|
+
}
|
package/src/aegis256x.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
xorBlocksTo,
|
|
11
11
|
zeroPad,
|
|
12
12
|
} from "./aes.js";
|
|
13
|
+
import { randomBytes } from "./random.js";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* AEGIS-256X cipher state with configurable parallelism degree.
|
|
@@ -219,6 +220,22 @@ export class Aegis256XState {
|
|
|
219
220
|
return out;
|
|
220
221
|
}
|
|
221
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Encrypts a plaintext block in-place.
|
|
225
|
+
* @param block - Buffer (plaintext in, ciphertext out), size 16*degree bytes
|
|
226
|
+
*/
|
|
227
|
+
encInPlace(block: Uint8Array): void {
|
|
228
|
+
this.encTo(block, block);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Decrypts a ciphertext block in-place.
|
|
233
|
+
* @param block - Buffer (ciphertext in, plaintext out), size 16*degree bytes
|
|
234
|
+
*/
|
|
235
|
+
decInPlace(block: Uint8Array): void {
|
|
236
|
+
this.decTo(block, block);
|
|
237
|
+
}
|
|
238
|
+
|
|
222
239
|
/**
|
|
223
240
|
* Decrypts a partial (final) ciphertext block.
|
|
224
241
|
* @param cn - Partial ciphertext block (smaller than 16*degree bytes)
|
|
@@ -359,16 +376,16 @@ export class Aegis256XState {
|
|
|
359
376
|
}
|
|
360
377
|
|
|
361
378
|
/**
|
|
362
|
-
* Encrypts a message using AEGIS-256X.
|
|
379
|
+
* Encrypts a message using AEGIS-256X (detached mode).
|
|
363
380
|
* @param msg - Plaintext message
|
|
364
381
|
* @param ad - Associated data (authenticated but not encrypted)
|
|
365
382
|
* @param key - 32-byte encryption key
|
|
366
383
|
* @param nonce - 32-byte nonce (must be unique per message with the same key)
|
|
367
384
|
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
368
385
|
* @param degree - Parallelism degree (default: 2)
|
|
369
|
-
* @returns Object containing ciphertext and authentication tag
|
|
386
|
+
* @returns Object containing ciphertext and authentication tag separately
|
|
370
387
|
*/
|
|
371
|
-
export function
|
|
388
|
+
export function aegis256XEncryptDetached(
|
|
372
389
|
msg: Uint8Array,
|
|
373
390
|
ad: Uint8Array,
|
|
374
391
|
key: Uint8Array,
|
|
@@ -406,7 +423,7 @@ export function aegis256XEncrypt(
|
|
|
406
423
|
}
|
|
407
424
|
|
|
408
425
|
/**
|
|
409
|
-
* Decrypts a message using AEGIS-256X.
|
|
426
|
+
* Decrypts a message using AEGIS-256X (detached mode).
|
|
410
427
|
* @param ct - Ciphertext
|
|
411
428
|
* @param tag - Authentication tag (16 or 32 bytes)
|
|
412
429
|
* @param ad - Associated data (must match what was used during encryption)
|
|
@@ -415,7 +432,7 @@ export function aegis256XEncrypt(
|
|
|
415
432
|
* @param degree - Parallelism degree (default: 2)
|
|
416
433
|
* @returns Decrypted plaintext, or null if authentication fails
|
|
417
434
|
*/
|
|
418
|
-
export function
|
|
435
|
+
export function aegis256XDecryptDetached(
|
|
419
436
|
ct: Uint8Array,
|
|
420
437
|
tag: Uint8Array,
|
|
421
438
|
ad: Uint8Array,
|
|
@@ -460,41 +477,308 @@ export function aegis256XDecrypt(
|
|
|
460
477
|
return msg;
|
|
461
478
|
}
|
|
462
479
|
|
|
480
|
+
/**
|
|
481
|
+
* Encrypts a message in-place using AEGIS-256X (detached mode).
|
|
482
|
+
* The input buffer is modified to contain the ciphertext.
|
|
483
|
+
* @param data - Buffer containing plaintext (will be overwritten with ciphertext)
|
|
484
|
+
* @param ad - Associated data (authenticated but not encrypted)
|
|
485
|
+
* @param key - 32-byte encryption key
|
|
486
|
+
* @param nonce - 32-byte nonce (must be unique per message with the same key)
|
|
487
|
+
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
488
|
+
* @param degree - Parallelism degree (default: 2)
|
|
489
|
+
* @returns Authentication tag
|
|
490
|
+
*/
|
|
491
|
+
export function aegis256XEncryptDetachedInPlace(
|
|
492
|
+
data: Uint8Array,
|
|
493
|
+
ad: Uint8Array,
|
|
494
|
+
key: Uint8Array,
|
|
495
|
+
nonce: Uint8Array,
|
|
496
|
+
tagLen: 16 | 32 = 16,
|
|
497
|
+
degree: number = 2,
|
|
498
|
+
): Uint8Array {
|
|
499
|
+
const state = new Aegis256XState(degree);
|
|
500
|
+
const rateBytes = (128 * degree) / 8;
|
|
501
|
+
|
|
502
|
+
state.init(key, nonce);
|
|
503
|
+
|
|
504
|
+
const adPadded = zeroPad(ad, rateBytes);
|
|
505
|
+
for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
|
|
506
|
+
state.absorb(adPadded.subarray(i, i + rateBytes));
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const msgLen = data.length;
|
|
510
|
+
const fullBlocksLen = Math.floor(msgLen / rateBytes) * rateBytes;
|
|
511
|
+
|
|
512
|
+
for (let i = 0; i < fullBlocksLen; i += rateBytes) {
|
|
513
|
+
state.encInPlace(data.subarray(i, i + rateBytes));
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (msgLen > fullBlocksLen) {
|
|
517
|
+
const lastPartial = data.subarray(fullBlocksLen);
|
|
518
|
+
const lastBlock = zeroPad(lastPartial, rateBytes);
|
|
519
|
+
const encBlock = state.enc(lastBlock);
|
|
520
|
+
lastPartial.set(encBlock.subarray(0, lastPartial.length));
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
return state.finalize(BigInt(ad.length * 8), BigInt(msgLen * 8), tagLen);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Decrypts a message in-place using AEGIS-256X (detached mode).
|
|
528
|
+
* The input buffer is modified to contain the plaintext (or zeroed on failure).
|
|
529
|
+
* @param data - Buffer containing ciphertext (will be overwritten with plaintext)
|
|
530
|
+
* @param tag - Authentication tag (16 or 32 bytes)
|
|
531
|
+
* @param ad - Associated data (must match what was used during encryption)
|
|
532
|
+
* @param key - 32-byte encryption key
|
|
533
|
+
* @param nonce - 32-byte nonce (must match what was used during encryption)
|
|
534
|
+
* @param degree - Parallelism degree (default: 2)
|
|
535
|
+
* @returns True if authentication succeeds, false otherwise
|
|
536
|
+
*/
|
|
537
|
+
export function aegis256XDecryptDetachedInPlace(
|
|
538
|
+
data: Uint8Array,
|
|
539
|
+
tag: Uint8Array,
|
|
540
|
+
ad: Uint8Array,
|
|
541
|
+
key: Uint8Array,
|
|
542
|
+
nonce: Uint8Array,
|
|
543
|
+
degree: number = 2,
|
|
544
|
+
): boolean {
|
|
545
|
+
const tagLen = tag.length as 16 | 32;
|
|
546
|
+
const state = new Aegis256XState(degree);
|
|
547
|
+
const rateBytes = (128 * degree) / 8;
|
|
548
|
+
|
|
549
|
+
state.init(key, nonce);
|
|
550
|
+
|
|
551
|
+
const adPadded = zeroPad(ad, rateBytes);
|
|
552
|
+
for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
|
|
553
|
+
state.absorb(adPadded.subarray(i, i + rateBytes));
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const msgLen = data.length;
|
|
557
|
+
const fullBlocksLen = Math.floor(msgLen / rateBytes) * rateBytes;
|
|
558
|
+
|
|
559
|
+
for (let i = 0; i < fullBlocksLen; i += rateBytes) {
|
|
560
|
+
state.decInPlace(data.subarray(i, i + rateBytes));
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
if (msgLen > fullBlocksLen) {
|
|
564
|
+
const lastPartial = data.subarray(fullBlocksLen);
|
|
565
|
+
const decrypted = state.decPartial(lastPartial);
|
|
566
|
+
lastPartial.set(decrypted);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const expectedTag = state.finalize(
|
|
570
|
+
BigInt(ad.length * 8),
|
|
571
|
+
BigInt(msgLen * 8),
|
|
572
|
+
tagLen,
|
|
573
|
+
);
|
|
574
|
+
|
|
575
|
+
if (!constantTimeEqual(tag, expectedTag)) {
|
|
576
|
+
data.fill(0);
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return true;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/** AEGIS-256X2 in-place encryption - detached mode (degree=2). */
|
|
584
|
+
export const aegis256X2EncryptDetachedInPlace = (
|
|
585
|
+
data: Uint8Array,
|
|
586
|
+
ad: Uint8Array,
|
|
587
|
+
key: Uint8Array,
|
|
588
|
+
nonce: Uint8Array,
|
|
589
|
+
tagLen: 16 | 32 = 16,
|
|
590
|
+
) => aegis256XEncryptDetachedInPlace(data, ad, key, nonce, tagLen, 2);
|
|
591
|
+
|
|
592
|
+
/** AEGIS-256X2 in-place decryption - detached mode (degree=2). */
|
|
593
|
+
export const aegis256X2DecryptDetachedInPlace = (
|
|
594
|
+
data: Uint8Array,
|
|
595
|
+
tag: Uint8Array,
|
|
596
|
+
ad: Uint8Array,
|
|
597
|
+
key: Uint8Array,
|
|
598
|
+
nonce: Uint8Array,
|
|
599
|
+
) => aegis256XDecryptDetachedInPlace(data, tag, ad, key, nonce, 2);
|
|
600
|
+
|
|
601
|
+
/** AEGIS-256X4 in-place encryption - detached mode (degree=4). */
|
|
602
|
+
export const aegis256X4EncryptDetachedInPlace = (
|
|
603
|
+
data: Uint8Array,
|
|
604
|
+
ad: Uint8Array,
|
|
605
|
+
key: Uint8Array,
|
|
606
|
+
nonce: Uint8Array,
|
|
607
|
+
tagLen: 16 | 32 = 16,
|
|
608
|
+
) => aegis256XEncryptDetachedInPlace(data, ad, key, nonce, tagLen, 4);
|
|
609
|
+
|
|
610
|
+
/** AEGIS-256X4 in-place decryption - detached mode (degree=4). */
|
|
611
|
+
export const aegis256X4DecryptDetachedInPlace = (
|
|
612
|
+
data: Uint8Array,
|
|
613
|
+
tag: Uint8Array,
|
|
614
|
+
ad: Uint8Array,
|
|
615
|
+
key: Uint8Array,
|
|
616
|
+
nonce: Uint8Array,
|
|
617
|
+
) => aegis256XDecryptDetachedInPlace(data, tag, ad, key, nonce, 4);
|
|
618
|
+
|
|
619
|
+
/** Nonce size for AEGIS-256X in bytes. */
|
|
620
|
+
export const AEGIS_256X_NONCE_SIZE = 32;
|
|
621
|
+
|
|
622
|
+
/** Key size for AEGIS-256X in bytes. */
|
|
623
|
+
export const AEGIS_256X_KEY_SIZE = 32;
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Encrypts a message using AEGIS-256X.
|
|
627
|
+
* Returns a single buffer containing nonce || ciphertext || tag.
|
|
628
|
+
* @param msg - Plaintext message
|
|
629
|
+
* @param ad - Associated data (authenticated but not encrypted)
|
|
630
|
+
* @param key - 32-byte encryption key
|
|
631
|
+
* @param nonce - 32-byte nonce (optional, generates random nonce if not provided)
|
|
632
|
+
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
633
|
+
* @param degree - Parallelism degree (default: 2)
|
|
634
|
+
* @returns Concatenated nonce || ciphertext || tag
|
|
635
|
+
*/
|
|
636
|
+
export function aegis256XEncrypt(
|
|
637
|
+
msg: Uint8Array,
|
|
638
|
+
ad: Uint8Array,
|
|
639
|
+
key: Uint8Array,
|
|
640
|
+
nonce: Uint8Array | null = null,
|
|
641
|
+
tagLen: 16 | 32 = 16,
|
|
642
|
+
degree: number = 2,
|
|
643
|
+
): Uint8Array {
|
|
644
|
+
const actualNonce = nonce ?? randomBytes(AEGIS_256X_NONCE_SIZE);
|
|
645
|
+
const state = new Aegis256XState(degree);
|
|
646
|
+
const rateBytes = (128 * degree) / 8;
|
|
647
|
+
|
|
648
|
+
state.init(key, actualNonce);
|
|
649
|
+
|
|
650
|
+
const adPadded = zeroPad(ad, rateBytes);
|
|
651
|
+
for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
|
|
652
|
+
state.absorb(adPadded.subarray(i, i + rateBytes));
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
const nonceSize = AEGIS_256X_NONCE_SIZE;
|
|
656
|
+
const result = new Uint8Array(nonceSize + msg.length + tagLen);
|
|
657
|
+
result.set(actualNonce, 0);
|
|
658
|
+
|
|
659
|
+
const fullBlocks = Math.floor(msg.length / rateBytes) * rateBytes;
|
|
660
|
+
for (let i = 0; i < fullBlocks; i += rateBytes) {
|
|
661
|
+
state.encTo(
|
|
662
|
+
msg.subarray(i, i + rateBytes),
|
|
663
|
+
result.subarray(nonceSize + i, nonceSize + i + rateBytes),
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
if (msg.length > fullBlocks) {
|
|
668
|
+
const lastBlock = zeroPad(msg.subarray(fullBlocks), rateBytes);
|
|
669
|
+
const encBlock = state.enc(lastBlock);
|
|
670
|
+
result.set(
|
|
671
|
+
encBlock.subarray(0, msg.length - fullBlocks),
|
|
672
|
+
nonceSize + fullBlocks,
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
const tag = state.finalize(
|
|
677
|
+
BigInt(ad.length * 8),
|
|
678
|
+
BigInt(msg.length * 8),
|
|
679
|
+
tagLen,
|
|
680
|
+
);
|
|
681
|
+
result.set(tag, nonceSize + msg.length);
|
|
682
|
+
|
|
683
|
+
return result;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Decrypts a message using AEGIS-256X.
|
|
688
|
+
* Expects input as nonce || ciphertext || tag.
|
|
689
|
+
* @param sealed - Concatenated nonce || ciphertext || tag
|
|
690
|
+
* @param ad - Associated data (must match what was used during encryption)
|
|
691
|
+
* @param key - 32-byte encryption key
|
|
692
|
+
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
693
|
+
* @param degree - Parallelism degree (default: 2)
|
|
694
|
+
* @returns Decrypted plaintext, or null if authentication fails
|
|
695
|
+
*/
|
|
696
|
+
export function aegis256XDecrypt(
|
|
697
|
+
sealed: Uint8Array,
|
|
698
|
+
ad: Uint8Array,
|
|
699
|
+
key: Uint8Array,
|
|
700
|
+
tagLen: 16 | 32 = 16,
|
|
701
|
+
degree: number = 2,
|
|
702
|
+
): Uint8Array | null {
|
|
703
|
+
const nonceSize = AEGIS_256X_NONCE_SIZE;
|
|
704
|
+
if (sealed.length < nonceSize + tagLen) {
|
|
705
|
+
return null;
|
|
706
|
+
}
|
|
707
|
+
const nonce = sealed.subarray(0, nonceSize);
|
|
708
|
+
const ct = sealed.subarray(nonceSize, sealed.length - tagLen);
|
|
709
|
+
const tag = sealed.subarray(sealed.length - tagLen);
|
|
710
|
+
return aegis256XDecryptDetached(ct, tag, ad, key, nonce, degree);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/** AEGIS-256X2 encryption - detached mode (degree=2). */
|
|
714
|
+
export const aegis256X2EncryptDetached = (
|
|
715
|
+
msg: Uint8Array,
|
|
716
|
+
ad: Uint8Array,
|
|
717
|
+
key: Uint8Array,
|
|
718
|
+
nonce: Uint8Array,
|
|
719
|
+
tagLen: 16 | 32 = 16,
|
|
720
|
+
) => aegis256XEncryptDetached(msg, ad, key, nonce, tagLen, 2);
|
|
721
|
+
|
|
722
|
+
/** AEGIS-256X2 decryption - detached mode (degree=2). */
|
|
723
|
+
export const aegis256X2DecryptDetached = (
|
|
724
|
+
ct: Uint8Array,
|
|
725
|
+
tag: Uint8Array,
|
|
726
|
+
ad: Uint8Array,
|
|
727
|
+
key: Uint8Array,
|
|
728
|
+
nonce: Uint8Array,
|
|
729
|
+
) => aegis256XDecryptDetached(ct, tag, ad, key, nonce, 2);
|
|
730
|
+
|
|
731
|
+
/** AEGIS-256X4 encryption - detached mode (degree=4). */
|
|
732
|
+
export const aegis256X4EncryptDetached = (
|
|
733
|
+
msg: Uint8Array,
|
|
734
|
+
ad: Uint8Array,
|
|
735
|
+
key: Uint8Array,
|
|
736
|
+
nonce: Uint8Array,
|
|
737
|
+
tagLen: 16 | 32 = 16,
|
|
738
|
+
) => aegis256XEncryptDetached(msg, ad, key, nonce, tagLen, 4);
|
|
739
|
+
|
|
740
|
+
/** AEGIS-256X4 decryption - detached mode (degree=4). */
|
|
741
|
+
export const aegis256X4DecryptDetached = (
|
|
742
|
+
ct: Uint8Array,
|
|
743
|
+
tag: Uint8Array,
|
|
744
|
+
ad: Uint8Array,
|
|
745
|
+
key: Uint8Array,
|
|
746
|
+
nonce: Uint8Array,
|
|
747
|
+
) => aegis256XDecryptDetached(ct, tag, ad, key, nonce, 4);
|
|
748
|
+
|
|
463
749
|
/** AEGIS-256X2 encryption (degree=2). */
|
|
464
750
|
export const aegis256X2Encrypt = (
|
|
465
751
|
msg: Uint8Array,
|
|
466
752
|
ad: Uint8Array,
|
|
467
753
|
key: Uint8Array,
|
|
468
|
-
nonce: Uint8Array,
|
|
754
|
+
nonce: Uint8Array | null = null,
|
|
469
755
|
tagLen: 16 | 32 = 16,
|
|
470
756
|
) => aegis256XEncrypt(msg, ad, key, nonce, tagLen, 2);
|
|
471
757
|
|
|
472
758
|
/** AEGIS-256X2 decryption (degree=2). */
|
|
473
759
|
export const aegis256X2Decrypt = (
|
|
474
|
-
|
|
475
|
-
tag: Uint8Array,
|
|
760
|
+
sealed: Uint8Array,
|
|
476
761
|
ad: Uint8Array,
|
|
477
762
|
key: Uint8Array,
|
|
478
|
-
|
|
479
|
-
) => aegis256XDecrypt(
|
|
763
|
+
tagLen: 16 | 32 = 16,
|
|
764
|
+
) => aegis256XDecrypt(sealed, ad, key, tagLen, 2);
|
|
480
765
|
|
|
481
766
|
/** AEGIS-256X4 encryption (degree=4). */
|
|
482
767
|
export const aegis256X4Encrypt = (
|
|
483
768
|
msg: Uint8Array,
|
|
484
769
|
ad: Uint8Array,
|
|
485
770
|
key: Uint8Array,
|
|
486
|
-
nonce: Uint8Array,
|
|
771
|
+
nonce: Uint8Array | null = null,
|
|
487
772
|
tagLen: 16 | 32 = 16,
|
|
488
773
|
) => aegis256XEncrypt(msg, ad, key, nonce, tagLen, 4);
|
|
489
774
|
|
|
490
775
|
/** AEGIS-256X4 decryption (degree=4). */
|
|
491
776
|
export const aegis256X4Decrypt = (
|
|
492
|
-
|
|
493
|
-
tag: Uint8Array,
|
|
777
|
+
sealed: Uint8Array,
|
|
494
778
|
ad: Uint8Array,
|
|
495
779
|
key: Uint8Array,
|
|
496
|
-
|
|
497
|
-
) => aegis256XDecrypt(
|
|
780
|
+
tagLen: 16 | 32 = 16,
|
|
781
|
+
) => aegis256XDecrypt(sealed, ad, key, tagLen, 4);
|
|
498
782
|
|
|
499
783
|
/**
|
|
500
784
|
* Computes a MAC (Message Authentication Code) using AEGIS-256X.
|
|
@@ -577,3 +861,33 @@ export const aegis256X4MacVerify = (
|
|
|
577
861
|
key: Uint8Array,
|
|
578
862
|
nonce: Uint8Array | null = null,
|
|
579
863
|
) => aegis256XMacVerify(data, tag, key, nonce, 4);
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* Generates a random 32-byte key for AEGIS-256X.
|
|
867
|
+
* @returns 32-byte encryption key
|
|
868
|
+
* @throws Error if no cryptographic random source is available
|
|
869
|
+
*/
|
|
870
|
+
export function aegis256XCreateKey(): Uint8Array {
|
|
871
|
+
return randomBytes(AEGIS_256X_KEY_SIZE);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Generates a random 32-byte nonce for AEGIS-256X.
|
|
876
|
+
* @returns 32-byte nonce
|
|
877
|
+
* @throws Error if no cryptographic random source is available
|
|
878
|
+
*/
|
|
879
|
+
export function aegis256XCreateNonce(): Uint8Array {
|
|
880
|
+
return randomBytes(AEGIS_256X_NONCE_SIZE);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/** AEGIS-256X2 key generation (degree=2). */
|
|
884
|
+
export const aegis256X2CreateKey = aegis256XCreateKey;
|
|
885
|
+
|
|
886
|
+
/** AEGIS-256X2 nonce generation (degree=2). */
|
|
887
|
+
export const aegis256X2CreateNonce = aegis256XCreateNonce;
|
|
888
|
+
|
|
889
|
+
/** AEGIS-256X4 key generation (degree=4). */
|
|
890
|
+
export const aegis256X4CreateKey = aegis256XCreateKey;
|
|
891
|
+
|
|
892
|
+
/** AEGIS-256X4 nonce generation (degree=4). */
|
|
893
|
+
export const aegis256X4CreateNonce = aegis256XCreateNonce;
|