aegis-aead 0.2.0 → 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 +152 -227
- package/dist/aegis128l-bs.d.ts +32 -0
- package/dist/aegis128l-bs.d.ts.map +1 -1
- package/dist/aegis128l-bs.js +79 -0
- package/dist/aegis128l-bs.js.map +1 -1
- package/dist/aegis128l.d.ts +32 -0
- package/dist/aegis128l.d.ts.map +1 -1
- package/dist/aegis128l.js +94 -0
- package/dist/aegis128l.js.map +1 -1
- package/dist/aegis128x.d.ts +42 -0
- package/dist/aegis128x.d.ts.map +1 -1
- package/dist/aegis128x.js +100 -0
- package/dist/aegis128x.js.map +1 -1
- package/dist/aegis256-bs.d.ts +32 -0
- package/dist/aegis256-bs.d.ts.map +1 -1
- package/dist/aegis256-bs.js +79 -0
- package/dist/aegis256-bs.js.map +1 -1
- package/dist/aegis256.d.ts +32 -0
- package/dist/aegis256.d.ts.map +1 -1
- package/dist/aegis256.js +79 -0
- package/dist/aegis256.js.map +1 -1
- package/dist/aegis256x.d.ts +42 -0
- package/dist/aegis256x.d.ts.map +1 -1
- package/dist/aegis256x.js +91 -0
- package/dist/aegis256x.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/aegis128l-bs.ts +107 -0
- package/src/aegis128l.ts +126 -0
- package/src/aegis128x.ts +168 -0
- package/src/aegis256-bs.ts +107 -0
- package/src/aegis256.ts +111 -0
- package/src/aegis256x.ts +155 -0
- package/src/index.ts +20 -0
package/src/aegis128x.ts
CHANGED
|
@@ -224,6 +224,35 @@ export class Aegis128XState {
|
|
|
224
224
|
return out;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
+
/**
|
|
228
|
+
* Encrypts a plaintext block in-place.
|
|
229
|
+
* @param block - Buffer (plaintext in, ciphertext out), size 32*degree bytes
|
|
230
|
+
*/
|
|
231
|
+
encInPlace(block: Uint8Array): void {
|
|
232
|
+
this.computeZ();
|
|
233
|
+
const z0 = this.z0;
|
|
234
|
+
const z1 = this.z1;
|
|
235
|
+
|
|
236
|
+
const halfRateBytes = this.rate / 16;
|
|
237
|
+
const rateBytes = this.rate / 8;
|
|
238
|
+
|
|
239
|
+
this.update(
|
|
240
|
+
block.subarray(0, halfRateBytes),
|
|
241
|
+
block.subarray(halfRateBytes, rateBytes),
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
for (let i = 0; i < halfRateBytes; i++) block[i] ^= z0[i]!;
|
|
245
|
+
for (let i = 0; i < halfRateBytes; i++) block[halfRateBytes + i] ^= z1[i]!;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Decrypts a ciphertext block in-place.
|
|
250
|
+
* @param block - Buffer (ciphertext in, plaintext out), size 32*degree bytes
|
|
251
|
+
*/
|
|
252
|
+
decInPlace(block: Uint8Array): void {
|
|
253
|
+
this.decTo(block, block);
|
|
254
|
+
}
|
|
255
|
+
|
|
227
256
|
/**
|
|
228
257
|
* Decrypts a partial (final) ciphertext block.
|
|
229
258
|
* @param cn - Partial ciphertext block (smaller than 32*degree bytes)
|
|
@@ -487,6 +516,145 @@ export function aegis128XDecryptDetached(
|
|
|
487
516
|
return msg;
|
|
488
517
|
}
|
|
489
518
|
|
|
519
|
+
/**
|
|
520
|
+
* Encrypts a message in-place using AEGIS-128X (detached mode).
|
|
521
|
+
* The input buffer is modified to contain the ciphertext.
|
|
522
|
+
* @param data - Buffer containing plaintext (will be overwritten with ciphertext)
|
|
523
|
+
* @param ad - Associated data (authenticated but not encrypted)
|
|
524
|
+
* @param key - 16-byte encryption key
|
|
525
|
+
* @param nonce - 16-byte nonce (must be unique per message with the same key)
|
|
526
|
+
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
527
|
+
* @param degree - Parallelism degree (default: 2)
|
|
528
|
+
* @returns Authentication tag
|
|
529
|
+
*/
|
|
530
|
+
export function aegis128XEncryptDetachedInPlace(
|
|
531
|
+
data: Uint8Array,
|
|
532
|
+
ad: Uint8Array,
|
|
533
|
+
key: Uint8Array,
|
|
534
|
+
nonce: Uint8Array,
|
|
535
|
+
tagLen: 16 | 32 = 16,
|
|
536
|
+
degree: number = 2,
|
|
537
|
+
): Uint8Array {
|
|
538
|
+
const state = new Aegis128XState(degree);
|
|
539
|
+
const rateBytes = (256 * degree) / 8;
|
|
540
|
+
|
|
541
|
+
state.init(key, nonce);
|
|
542
|
+
|
|
543
|
+
const adPadded = zeroPad(ad, rateBytes);
|
|
544
|
+
for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
|
|
545
|
+
state.absorb(adPadded.subarray(i, i + rateBytes));
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const msgLen = data.length;
|
|
549
|
+
const fullBlocksLen = Math.floor(msgLen / rateBytes) * rateBytes;
|
|
550
|
+
|
|
551
|
+
for (let i = 0; i < fullBlocksLen; i += rateBytes) {
|
|
552
|
+
state.encInPlace(data.subarray(i, i + rateBytes));
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if (msgLen > fullBlocksLen) {
|
|
556
|
+
const lastPartial = data.subarray(fullBlocksLen);
|
|
557
|
+
const lastBlock = zeroPad(lastPartial, rateBytes);
|
|
558
|
+
const encBlock = state.enc(lastBlock);
|
|
559
|
+
lastPartial.set(encBlock.subarray(0, lastPartial.length));
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return state.finalize(BigInt(ad.length * 8), BigInt(msgLen * 8), tagLen);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Decrypts a message in-place using AEGIS-128X (detached mode).
|
|
567
|
+
* The input buffer is modified to contain the plaintext (or zeroed on failure).
|
|
568
|
+
* @param data - Buffer containing ciphertext (will be overwritten with plaintext)
|
|
569
|
+
* @param tag - Authentication tag (16 or 32 bytes)
|
|
570
|
+
* @param ad - Associated data (must match what was used during encryption)
|
|
571
|
+
* @param key - 16-byte encryption key
|
|
572
|
+
* @param nonce - 16-byte nonce (must match what was used during encryption)
|
|
573
|
+
* @param degree - Parallelism degree (default: 2)
|
|
574
|
+
* @returns True if authentication succeeds, false otherwise
|
|
575
|
+
*/
|
|
576
|
+
export function aegis128XDecryptDetachedInPlace(
|
|
577
|
+
data: Uint8Array,
|
|
578
|
+
tag: Uint8Array,
|
|
579
|
+
ad: Uint8Array,
|
|
580
|
+
key: Uint8Array,
|
|
581
|
+
nonce: Uint8Array,
|
|
582
|
+
degree: number = 2,
|
|
583
|
+
): boolean {
|
|
584
|
+
const tagLen = tag.length as 16 | 32;
|
|
585
|
+
const state = new Aegis128XState(degree);
|
|
586
|
+
const rateBytes = (256 * degree) / 8;
|
|
587
|
+
|
|
588
|
+
state.init(key, nonce);
|
|
589
|
+
|
|
590
|
+
const adPadded = zeroPad(ad, rateBytes);
|
|
591
|
+
for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
|
|
592
|
+
state.absorb(adPadded.subarray(i, i + rateBytes));
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const msgLen = data.length;
|
|
596
|
+
const fullBlocksLen = Math.floor(msgLen / rateBytes) * rateBytes;
|
|
597
|
+
|
|
598
|
+
for (let i = 0; i < fullBlocksLen; i += rateBytes) {
|
|
599
|
+
state.decInPlace(data.subarray(i, i + rateBytes));
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
if (msgLen > fullBlocksLen) {
|
|
603
|
+
const lastPartial = data.subarray(fullBlocksLen);
|
|
604
|
+
const decrypted = state.decPartial(lastPartial);
|
|
605
|
+
lastPartial.set(decrypted);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
const expectedTag = state.finalize(
|
|
609
|
+
BigInt(ad.length * 8),
|
|
610
|
+
BigInt(msgLen * 8),
|
|
611
|
+
tagLen,
|
|
612
|
+
);
|
|
613
|
+
|
|
614
|
+
if (!constantTimeEqual(tag, expectedTag)) {
|
|
615
|
+
data.fill(0);
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
return true;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/** AEGIS-128X2 in-place encryption - detached mode (degree=2). */
|
|
623
|
+
export const aegis128X2EncryptDetachedInPlace = (
|
|
624
|
+
data: Uint8Array,
|
|
625
|
+
ad: Uint8Array,
|
|
626
|
+
key: Uint8Array,
|
|
627
|
+
nonce: Uint8Array,
|
|
628
|
+
tagLen: 16 | 32 = 16,
|
|
629
|
+
) => aegis128XEncryptDetachedInPlace(data, ad, key, nonce, tagLen, 2);
|
|
630
|
+
|
|
631
|
+
/** AEGIS-128X2 in-place decryption - detached mode (degree=2). */
|
|
632
|
+
export const aegis128X2DecryptDetachedInPlace = (
|
|
633
|
+
data: Uint8Array,
|
|
634
|
+
tag: Uint8Array,
|
|
635
|
+
ad: Uint8Array,
|
|
636
|
+
key: Uint8Array,
|
|
637
|
+
nonce: Uint8Array,
|
|
638
|
+
) => aegis128XDecryptDetachedInPlace(data, tag, ad, key, nonce, 2);
|
|
639
|
+
|
|
640
|
+
/** AEGIS-128X4 in-place encryption - detached mode (degree=4). */
|
|
641
|
+
export const aegis128X4EncryptDetachedInPlace = (
|
|
642
|
+
data: Uint8Array,
|
|
643
|
+
ad: Uint8Array,
|
|
644
|
+
key: Uint8Array,
|
|
645
|
+
nonce: Uint8Array,
|
|
646
|
+
tagLen: 16 | 32 = 16,
|
|
647
|
+
) => aegis128XEncryptDetachedInPlace(data, ad, key, nonce, tagLen, 4);
|
|
648
|
+
|
|
649
|
+
/** AEGIS-128X4 in-place decryption - detached mode (degree=4). */
|
|
650
|
+
export const aegis128X4DecryptDetachedInPlace = (
|
|
651
|
+
data: Uint8Array,
|
|
652
|
+
tag: Uint8Array,
|
|
653
|
+
ad: Uint8Array,
|
|
654
|
+
key: Uint8Array,
|
|
655
|
+
nonce: Uint8Array,
|
|
656
|
+
) => aegis128XDecryptDetachedInPlace(data, tag, ad, key, nonce, 4);
|
|
657
|
+
|
|
490
658
|
/** Nonce size for AEGIS-128X in bytes. */
|
|
491
659
|
export const AEGIS_128X_NONCE_SIZE = 16;
|
|
492
660
|
|
package/src/aegis256-bs.ts
CHANGED
|
@@ -210,6 +210,22 @@ export class Aegis256BsState {
|
|
|
210
210
|
return out;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Encrypts a 16-byte plaintext block in-place.
|
|
215
|
+
* @param block - 16-byte buffer (plaintext in, ciphertext out)
|
|
216
|
+
*/
|
|
217
|
+
encInPlace(block: Uint8Array): void {
|
|
218
|
+
this.encTo(block, block);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Decrypts a 16-byte ciphertext block in-place.
|
|
223
|
+
* @param block - 16-byte buffer (ciphertext in, plaintext out)
|
|
224
|
+
*/
|
|
225
|
+
decInPlace(block: Uint8Array): void {
|
|
226
|
+
this.decTo(block, block);
|
|
227
|
+
}
|
|
228
|
+
|
|
213
229
|
/**
|
|
214
230
|
* Decrypts a partial (final) ciphertext block smaller than 16 bytes.
|
|
215
231
|
* @param cn - Partial ciphertext block (1-15 bytes)
|
|
@@ -393,6 +409,97 @@ export function aegis256BsDecryptDetached(
|
|
|
393
409
|
return msg;
|
|
394
410
|
}
|
|
395
411
|
|
|
412
|
+
/**
|
|
413
|
+
* Encrypts a message in-place using bitsliced AEGIS-256 (detached mode).
|
|
414
|
+
* The input buffer is modified to contain the ciphertext.
|
|
415
|
+
* @param data - Buffer containing plaintext (will be overwritten with ciphertext)
|
|
416
|
+
* @param ad - Associated data (authenticated but not encrypted)
|
|
417
|
+
* @param key - 32-byte encryption key
|
|
418
|
+
* @param nonce - 32-byte nonce (must be unique per message with the same key)
|
|
419
|
+
* @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
|
|
420
|
+
* @returns Authentication tag
|
|
421
|
+
*/
|
|
422
|
+
export function aegis256BsEncryptDetachedInPlace(
|
|
423
|
+
data: Uint8Array,
|
|
424
|
+
ad: Uint8Array,
|
|
425
|
+
key: Uint8Array,
|
|
426
|
+
nonce: Uint8Array,
|
|
427
|
+
tagLen: 16 | 32 = 16,
|
|
428
|
+
): Uint8Array {
|
|
429
|
+
const state = new Aegis256BsState();
|
|
430
|
+
state.init(key, nonce);
|
|
431
|
+
|
|
432
|
+
const adPadded = zeroPad(ad, RATE);
|
|
433
|
+
for (let i = 0; i + RATE <= adPadded.length; i += RATE) {
|
|
434
|
+
state.absorb(adPadded.subarray(i, i + RATE));
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const msgLen = data.length;
|
|
438
|
+
const fullBlocksLen = Math.floor(msgLen / RATE) * RATE;
|
|
439
|
+
|
|
440
|
+
for (let i = 0; i < fullBlocksLen; i += RATE) {
|
|
441
|
+
state.encInPlace(data.subarray(i, i + RATE));
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (msgLen > fullBlocksLen) {
|
|
445
|
+
const lastPartial = data.subarray(fullBlocksLen);
|
|
446
|
+
const lastBlock = zeroPad(lastPartial, RATE);
|
|
447
|
+
const encBlock = state.enc(lastBlock);
|
|
448
|
+
lastPartial.set(encBlock.subarray(0, lastPartial.length));
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return state.finalize(ad.length, msgLen, tagLen);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Decrypts a message in-place using bitsliced AEGIS-256 (detached mode).
|
|
456
|
+
* The input buffer is modified to contain the plaintext (or zeroed on failure).
|
|
457
|
+
* @param data - Buffer containing ciphertext (will be overwritten with plaintext)
|
|
458
|
+
* @param tag - Authentication tag (16 or 32 bytes)
|
|
459
|
+
* @param ad - Associated data (must match what was used during encryption)
|
|
460
|
+
* @param key - 32-byte encryption key
|
|
461
|
+
* @param nonce - 32-byte nonce (must match what was used during encryption)
|
|
462
|
+
* @returns True if authentication succeeds, false otherwise
|
|
463
|
+
*/
|
|
464
|
+
export function aegis256BsDecryptDetachedInPlace(
|
|
465
|
+
data: Uint8Array,
|
|
466
|
+
tag: Uint8Array,
|
|
467
|
+
ad: Uint8Array,
|
|
468
|
+
key: Uint8Array,
|
|
469
|
+
nonce: Uint8Array,
|
|
470
|
+
): boolean {
|
|
471
|
+
const tagLen = tag.length as 16 | 32;
|
|
472
|
+
const state = new Aegis256BsState();
|
|
473
|
+
state.init(key, nonce);
|
|
474
|
+
|
|
475
|
+
const adPadded = zeroPad(ad, RATE);
|
|
476
|
+
for (let i = 0; i + RATE <= adPadded.length; i += RATE) {
|
|
477
|
+
state.absorb(adPadded.subarray(i, i + RATE));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const msgLen = data.length;
|
|
481
|
+
const fullBlocksLen = Math.floor(msgLen / RATE) * RATE;
|
|
482
|
+
|
|
483
|
+
for (let i = 0; i < fullBlocksLen; i += RATE) {
|
|
484
|
+
state.decInPlace(data.subarray(i, i + RATE));
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (msgLen > fullBlocksLen) {
|
|
488
|
+
const lastPartial = data.subarray(fullBlocksLen);
|
|
489
|
+
const decrypted = state.decPartial(lastPartial);
|
|
490
|
+
lastPartial.set(decrypted);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const expectedTag = state.finalize(ad.length, msgLen, tagLen);
|
|
494
|
+
|
|
495
|
+
if (!constantTimeEqual(tag, expectedTag)) {
|
|
496
|
+
data.fill(0);
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return true;
|
|
501
|
+
}
|
|
502
|
+
|
|
396
503
|
export const AEGIS_256_BS_NONCE_SIZE = 32;
|
|
397
504
|
export const AEGIS_256_BS_KEY_SIZE = 32;
|
|
398
505
|
|
package/src/aegis256.ts
CHANGED
|
@@ -173,6 +173,22 @@ export class Aegis256State {
|
|
|
173
173
|
return out;
|
|
174
174
|
}
|
|
175
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
|
+
|
|
176
192
|
/**
|
|
177
193
|
* Decrypts a partial (final) ciphertext block smaller than 16 bytes.
|
|
178
194
|
* @param cn - Partial ciphertext block (1-15 bytes)
|
|
@@ -335,6 +351,101 @@ export function aegis256DecryptDetached(
|
|
|
335
351
|
return msg;
|
|
336
352
|
}
|
|
337
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
|
+
|
|
338
449
|
/** Nonce size for AEGIS-256 in bytes. */
|
|
339
450
|
export const AEGIS_256_NONCE_SIZE = 32;
|
|
340
451
|
|
package/src/aegis256x.ts
CHANGED
|
@@ -220,6 +220,22 @@ export class Aegis256XState {
|
|
|
220
220
|
return out;
|
|
221
221
|
}
|
|
222
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
|
+
|
|
223
239
|
/**
|
|
224
240
|
* Decrypts a partial (final) ciphertext block.
|
|
225
241
|
* @param cn - Partial ciphertext block (smaller than 16*degree bytes)
|
|
@@ -461,6 +477,145 @@ export function aegis256XDecryptDetached(
|
|
|
461
477
|
return msg;
|
|
462
478
|
}
|
|
463
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
|
+
|
|
464
619
|
/** Nonce size for AEGIS-256X in bytes. */
|
|
465
620
|
export const AEGIS_256X_NONCE_SIZE = 32;
|
|
466
621
|
|
package/src/index.ts
CHANGED
|
@@ -5,8 +5,10 @@ export {
|
|
|
5
5
|
aegis128LCreateNonce,
|
|
6
6
|
aegis128LDecrypt,
|
|
7
7
|
aegis128LDecryptDetached,
|
|
8
|
+
aegis128LDecryptDetachedInPlace,
|
|
8
9
|
aegis128LEncrypt,
|
|
9
10
|
aegis128LEncryptDetached,
|
|
11
|
+
aegis128LEncryptDetachedInPlace,
|
|
10
12
|
aegis128LMac,
|
|
11
13
|
aegis128LMacVerify,
|
|
12
14
|
} from "./aegis128l.js";
|
|
@@ -18,8 +20,10 @@ export {
|
|
|
18
20
|
aegis128LBsCreateNonce,
|
|
19
21
|
aegis128LBsDecrypt,
|
|
20
22
|
aegis128LBsDecryptDetached,
|
|
23
|
+
aegis128LBsDecryptDetachedInPlace,
|
|
21
24
|
aegis128LBsEncrypt,
|
|
22
25
|
aegis128LBsEncryptDetached,
|
|
26
|
+
aegis128LBsEncryptDetachedInPlace,
|
|
23
27
|
aegis128LBsMac,
|
|
24
28
|
aegis128LBsMacVerify,
|
|
25
29
|
} from "./aegis128l-bs.js";
|
|
@@ -30,24 +34,30 @@ export {
|
|
|
30
34
|
aegis128X2CreateNonce,
|
|
31
35
|
aegis128X2Decrypt,
|
|
32
36
|
aegis128X2DecryptDetached,
|
|
37
|
+
aegis128X2DecryptDetachedInPlace,
|
|
33
38
|
aegis128X2Encrypt,
|
|
34
39
|
aegis128X2EncryptDetached,
|
|
40
|
+
aegis128X2EncryptDetachedInPlace,
|
|
35
41
|
aegis128X2Mac,
|
|
36
42
|
aegis128X2MacVerify,
|
|
37
43
|
aegis128X4CreateKey,
|
|
38
44
|
aegis128X4CreateNonce,
|
|
39
45
|
aegis128X4Decrypt,
|
|
40
46
|
aegis128X4DecryptDetached,
|
|
47
|
+
aegis128X4DecryptDetachedInPlace,
|
|
41
48
|
aegis128X4Encrypt,
|
|
42
49
|
aegis128X4EncryptDetached,
|
|
50
|
+
aegis128X4EncryptDetachedInPlace,
|
|
43
51
|
aegis128X4Mac,
|
|
44
52
|
aegis128X4MacVerify,
|
|
45
53
|
aegis128XCreateKey,
|
|
46
54
|
aegis128XCreateNonce,
|
|
47
55
|
aegis128XDecrypt,
|
|
48
56
|
aegis128XDecryptDetached,
|
|
57
|
+
aegis128XDecryptDetachedInPlace,
|
|
49
58
|
aegis128XEncrypt,
|
|
50
59
|
aegis128XEncryptDetached,
|
|
60
|
+
aegis128XEncryptDetachedInPlace,
|
|
51
61
|
aegis128XMac,
|
|
52
62
|
aegis128XMacVerify,
|
|
53
63
|
} from "./aegis128x.js";
|
|
@@ -58,8 +68,10 @@ export {
|
|
|
58
68
|
aegis256CreateNonce,
|
|
59
69
|
aegis256Decrypt,
|
|
60
70
|
aegis256DecryptDetached,
|
|
71
|
+
aegis256DecryptDetachedInPlace,
|
|
61
72
|
aegis256Encrypt,
|
|
62
73
|
aegis256EncryptDetached,
|
|
74
|
+
aegis256EncryptDetachedInPlace,
|
|
63
75
|
aegis256Mac,
|
|
64
76
|
aegis256MacVerify,
|
|
65
77
|
} from "./aegis256.js";
|
|
@@ -71,8 +83,10 @@ export {
|
|
|
71
83
|
aegis256BsCreateNonce,
|
|
72
84
|
aegis256BsDecrypt,
|
|
73
85
|
aegis256BsDecryptDetached,
|
|
86
|
+
aegis256BsDecryptDetachedInPlace,
|
|
74
87
|
aegis256BsEncrypt,
|
|
75
88
|
aegis256BsEncryptDetached,
|
|
89
|
+
aegis256BsEncryptDetachedInPlace,
|
|
76
90
|
aegis256BsMac,
|
|
77
91
|
aegis256BsMacVerify,
|
|
78
92
|
} from "./aegis256-bs.js";
|
|
@@ -83,24 +97,30 @@ export {
|
|
|
83
97
|
aegis256X2CreateNonce,
|
|
84
98
|
aegis256X2Decrypt,
|
|
85
99
|
aegis256X2DecryptDetached,
|
|
100
|
+
aegis256X2DecryptDetachedInPlace,
|
|
86
101
|
aegis256X2Encrypt,
|
|
87
102
|
aegis256X2EncryptDetached,
|
|
103
|
+
aegis256X2EncryptDetachedInPlace,
|
|
88
104
|
aegis256X2Mac,
|
|
89
105
|
aegis256X2MacVerify,
|
|
90
106
|
aegis256X4CreateKey,
|
|
91
107
|
aegis256X4CreateNonce,
|
|
92
108
|
aegis256X4Decrypt,
|
|
93
109
|
aegis256X4DecryptDetached,
|
|
110
|
+
aegis256X4DecryptDetachedInPlace,
|
|
94
111
|
aegis256X4Encrypt,
|
|
95
112
|
aegis256X4EncryptDetached,
|
|
113
|
+
aegis256X4EncryptDetachedInPlace,
|
|
96
114
|
aegis256X4Mac,
|
|
97
115
|
aegis256X4MacVerify,
|
|
98
116
|
aegis256XCreateKey,
|
|
99
117
|
aegis256XCreateNonce,
|
|
100
118
|
aegis256XDecrypt,
|
|
101
119
|
aegis256XDecryptDetached,
|
|
120
|
+
aegis256XDecryptDetachedInPlace,
|
|
102
121
|
aegis256XEncrypt,
|
|
103
122
|
aegis256XEncryptDetached,
|
|
123
|
+
aegis256XEncryptDetachedInPlace,
|
|
104
124
|
aegis256XMac,
|
|
105
125
|
aegis256XMacVerify,
|
|
106
126
|
} from "./aegis256x.js";
|