aegis-aead 0.2.1 → 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 +29 -22
- 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 +46 -23
- package/dist/aes-bs.js +2273 -331
- 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 +6 -6
- package/dist/aegis128l-bs.d.ts +0 -194
- package/dist/aegis128l-bs.d.ts.map +0 -1
- package/dist/aegis128l-bs.js +0 -549
- 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 -183
- package/dist/aegis256-bs.d.ts.map +0 -1
- package/dist/aegis256-bs.js +0 -477
- 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 -709
- package/src/aegis128l.ts +0 -653
- package/src/aegis128x.ts +0 -932
- package/src/aegis256-bs.ts +0 -625
- package/src/aegis256.ts +0 -597
- package/src/aegis256x.ts +0 -893
- package/src/aes-bs.ts +0 -459
- 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/dist/aegis256x.js
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* AEGIS-256X implementation with configurable parallelism degree.
|
|
3
|
+
* Extends AEGIS-256 with parallel lanes for improved performance on wide
|
|
4
|
+
* SIMD architectures. Each lane is an independent AEGIS-256 state kept in
|
|
5
|
+
* packed bitsliced form, built on the constant-time bitsliced AES core.
|
|
6
|
+
*/
|
|
7
|
+
import { aegisRound256, blockFromBytes, blocksPut, blockToBytes, blockXor, createAesBlock, createAesBlocks, keystream256, pack, packConstantInput256, unpack, wordIdx, } from "./aes-bs.js";
|
|
2
8
|
import { randomBytes } from "./random.js";
|
|
9
|
+
import { constantTimeEqual, zeroPad } from "./utils.js";
|
|
10
|
+
const C0 = new Uint32Array([
|
|
11
|
+
0x02010100, 0x0d080503, 0x59372215, 0x6279e990,
|
|
12
|
+
]);
|
|
13
|
+
const C1 = new Uint32Array([
|
|
14
|
+
0x55183ddb, 0xf12fc26d, 0x42311120, 0xdd28b573,
|
|
15
|
+
]);
|
|
3
16
|
/**
|
|
4
17
|
* AEGIS-256X cipher state with configurable parallelism degree.
|
|
5
|
-
* Extends AEGIS-256 with parallel AES rounds for improved performance on wide SIMD architectures.
|
|
6
18
|
*/
|
|
7
19
|
export class Aegis256XState {
|
|
8
20
|
/**
|
|
@@ -11,144 +23,125 @@ export class Aegis256XState {
|
|
|
11
23
|
*/
|
|
12
24
|
constructor(degree = 2) {
|
|
13
25
|
this.d = degree;
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
20
|
-
const buf = new Uint8Array(16);
|
|
21
|
-
buf[0] = i;
|
|
22
|
-
buf[1] = degree - 1;
|
|
23
|
-
return buf;
|
|
24
|
-
});
|
|
26
|
+
this.rateBytes = 16 * degree;
|
|
27
|
+
this.lanes = Array.from({ length: degree }, () => createAesBlocks());
|
|
28
|
+
this.ci = createAesBlocks();
|
|
29
|
+
this.ciZero = createAesBlocks();
|
|
30
|
+
this.tmp = createAesBlock();
|
|
31
|
+
this.z = createAesBlock();
|
|
25
32
|
}
|
|
26
33
|
/**
|
|
27
|
-
*
|
|
28
|
-
* @param key - 32-byte encryption key
|
|
29
|
-
* @param nonce - 32-byte nonce (must be unique per message)
|
|
34
|
+
* Returns the state blocks as byte arrays indexed [block][lane] (for testing).
|
|
30
35
|
*/
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const n1 = nonce.subarray(16, 32);
|
|
36
|
-
const k0n0 = new Uint8Array(16);
|
|
37
|
-
const k1n1 = new Uint8Array(16);
|
|
38
|
-
const k0c0 = new Uint8Array(16);
|
|
39
|
-
const k1c1 = new Uint8Array(16);
|
|
40
|
-
xorBlocksTo(k0, n0, k0n0);
|
|
41
|
-
xorBlocksTo(k1, n1, k1n1);
|
|
42
|
-
xorBlocksTo(k0, C0, k0c0);
|
|
43
|
-
xorBlocksTo(k1, C1, k1c1);
|
|
44
|
-
for (let i = 0; i < this.d; i++) {
|
|
45
|
-
this.v[0][i].set(k0n0);
|
|
46
|
-
this.v[1][i].set(k1n1);
|
|
47
|
-
this.v[2][i].set(C1);
|
|
48
|
-
this.v[3][i].set(C0);
|
|
49
|
-
this.v[4][i].set(k0c0);
|
|
50
|
-
this.v[5][i].set(k1c1);
|
|
51
|
-
}
|
|
52
|
-
const k0V = new Uint8Array(16 * this.d);
|
|
53
|
-
const k1V = new Uint8Array(16 * this.d);
|
|
54
|
-
const k0n0V = new Uint8Array(16 * this.d);
|
|
55
|
-
const k1n1V = new Uint8Array(16 * this.d);
|
|
36
|
+
get v() {
|
|
37
|
+
const out = Array.from({ length: 6 }, () => []);
|
|
38
|
+
const unpacked = createAesBlocks();
|
|
39
|
+
const w = createAesBlock();
|
|
56
40
|
for (let i = 0; i < this.d; i++) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
for (let j = 0; j < 16; j++)
|
|
66
|
-
this.v[3][i][j] ^= ctx[j];
|
|
67
|
-
for (let j = 0; j < 16; j++)
|
|
68
|
-
this.v[5][i][j] ^= ctx[j];
|
|
69
|
-
}
|
|
70
|
-
this.update(k0V);
|
|
71
|
-
for (let i = 0; i < this.d; i++) {
|
|
72
|
-
const ctx = this.ctxBufs[i];
|
|
73
|
-
for (let j = 0; j < 16; j++)
|
|
74
|
-
this.v[3][i][j] ^= ctx[j];
|
|
75
|
-
for (let j = 0; j < 16; j++)
|
|
76
|
-
this.v[5][i][j] ^= ctx[j];
|
|
77
|
-
}
|
|
78
|
-
this.update(k1V);
|
|
79
|
-
for (let i = 0; i < this.d; i++) {
|
|
80
|
-
const ctx = this.ctxBufs[i];
|
|
81
|
-
for (let j = 0; j < 16; j++)
|
|
82
|
-
this.v[3][i][j] ^= ctx[j];
|
|
83
|
-
for (let j = 0; j < 16; j++)
|
|
84
|
-
this.v[5][i][j] ^= ctx[j];
|
|
41
|
+
unpacked.set(this.lanes[i]);
|
|
42
|
+
unpack(unpacked);
|
|
43
|
+
for (let b = 0; b < 6; b++) {
|
|
44
|
+
for (let j = 0; j < 4; j++)
|
|
45
|
+
w[j] = unpacked[wordIdx(b, j)];
|
|
46
|
+
const bytes = new Uint8Array(16);
|
|
47
|
+
blockToBytes(bytes, w);
|
|
48
|
+
out[b].push(bytes);
|
|
85
49
|
}
|
|
86
|
-
this.update(k0n0V);
|
|
87
|
-
for (let i = 0; i < this.d; i++) {
|
|
88
|
-
const ctx = this.ctxBufs[i];
|
|
89
|
-
for (let j = 0; j < 16; j++)
|
|
90
|
-
this.v[3][i][j] ^= ctx[j];
|
|
91
|
-
for (let j = 0; j < 16; j++)
|
|
92
|
-
this.v[5][i][j] ^= ctx[j];
|
|
93
|
-
}
|
|
94
|
-
this.update(k1n1V);
|
|
95
50
|
}
|
|
51
|
+
return out;
|
|
96
52
|
}
|
|
97
53
|
/**
|
|
98
|
-
*
|
|
99
|
-
* @param
|
|
54
|
+
* Initializes the state with a key and nonce.
|
|
55
|
+
* @param key - 32-byte encryption key
|
|
56
|
+
* @param nonce - 32-byte nonce (must be unique per message)
|
|
100
57
|
*/
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
const
|
|
58
|
+
init(key, nonce) {
|
|
59
|
+
const k0 = createAesBlock();
|
|
60
|
+
const k1 = createAesBlock();
|
|
61
|
+
const n0 = createAesBlock();
|
|
62
|
+
const n1 = createAesBlock();
|
|
63
|
+
const k0n0 = createAesBlock();
|
|
64
|
+
const k1n1 = createAesBlock();
|
|
65
|
+
const k0c0 = createAesBlock();
|
|
66
|
+
const k1c1 = createAesBlock();
|
|
67
|
+
blockFromBytes(k0, key);
|
|
68
|
+
blockFromBytes(k1, key, 16);
|
|
69
|
+
blockFromBytes(n0, nonce);
|
|
70
|
+
blockFromBytes(n1, nonce, 16);
|
|
71
|
+
blockXor(k0n0, k0, n0);
|
|
72
|
+
blockXor(k1n1, k1, n1);
|
|
73
|
+
blockXor(k0c0, k0, C0);
|
|
74
|
+
blockXor(k1c1, k1, C1);
|
|
75
|
+
const base = createAesBlocks();
|
|
76
|
+
blocksPut(base, k0n0, 0);
|
|
77
|
+
blocksPut(base, k1n1, 1);
|
|
78
|
+
blocksPut(base, C1, 2);
|
|
79
|
+
blocksPut(base, C0, 3);
|
|
80
|
+
blocksPut(base, k0c0, 4);
|
|
81
|
+
blocksPut(base, k1c1, 5);
|
|
82
|
+
pack(base);
|
|
83
|
+
const ciK0 = createAesBlocks();
|
|
84
|
+
const ciK1 = createAesBlocks();
|
|
85
|
+
const ciK0N0 = createAesBlocks();
|
|
86
|
+
const ciK1N1 = createAesBlocks();
|
|
87
|
+
packConstantInput256(ciK0, k0);
|
|
88
|
+
packConstantInput256(ciK1, k1);
|
|
89
|
+
packConstantInput256(ciK0N0, k0n0);
|
|
90
|
+
packConstantInput256(ciK1N1, k1n1);
|
|
91
|
+
const ctx = createAesBlock();
|
|
92
|
+
const deltas = [];
|
|
104
93
|
for (let i = 0; i < this.d; i++) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
aesRoundTo(this.v[4][i], this.v[5][i], newV[5][i]);
|
|
94
|
+
this.lanes[i].set(base);
|
|
95
|
+
const delta = createAesBlocks();
|
|
96
|
+
ctx[0] = i | ((this.d - 1) << 8);
|
|
97
|
+
blocksPut(delta, ctx, 3);
|
|
98
|
+
blocksPut(delta, ctx, 5);
|
|
99
|
+
pack(delta);
|
|
100
|
+
deltas.push(delta);
|
|
113
101
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
102
|
+
const inputs = [ciK0, ciK1, ciK0N0, ciK1N1];
|
|
103
|
+
for (let round = 0; round < 4; round++) {
|
|
104
|
+
for (const input of inputs) {
|
|
105
|
+
for (let i = 0; i < this.d; i++) {
|
|
106
|
+
const st = this.lanes[i];
|
|
107
|
+
const delta = deltas[i];
|
|
108
|
+
for (let w = 0; w < 32; w++)
|
|
109
|
+
st[w] = st[w] ^ delta[w];
|
|
110
|
+
aegisRound256(st, input);
|
|
111
|
+
}
|
|
117
112
|
}
|
|
118
113
|
}
|
|
119
114
|
}
|
|
120
115
|
/**
|
|
121
116
|
* Absorbs an associated data block into the state.
|
|
122
|
-
* @param ai -
|
|
117
|
+
* @param ai - Buffer holding the 16*degree-byte associated data block
|
|
118
|
+
* @param off - Offset of the block within the buffer
|
|
123
119
|
*/
|
|
124
|
-
absorb(ai) {
|
|
125
|
-
this.update(ai);
|
|
126
|
-
}
|
|
127
|
-
computeZ() {
|
|
128
|
-
const z = this.z;
|
|
129
|
-
const tmp = this.tmp;
|
|
120
|
+
absorb(ai, off = 0) {
|
|
130
121
|
for (let i = 0; i < this.d; i++) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
z[off + j] ^= this.v[5][i][j];
|
|
135
|
-
andBlocksTo(this.v[2][i], this.v[3][i], tmp);
|
|
136
|
-
for (let j = 0; j < 16; j++)
|
|
137
|
-
z[off + j] ^= tmp[j];
|
|
122
|
+
blockFromBytes(this.tmp, ai, off + i * 16);
|
|
123
|
+
packConstantInput256(this.ci, this.tmp);
|
|
124
|
+
aegisRound256(this.lanes[i], this.ci);
|
|
138
125
|
}
|
|
139
126
|
}
|
|
140
127
|
/**
|
|
141
128
|
* Encrypts a plaintext block and writes to output buffer.
|
|
142
|
-
* @param xi -
|
|
143
|
-
* @param out - Output buffer
|
|
129
|
+
* @param xi - Buffer holding the 16*degree-byte plaintext block
|
|
130
|
+
* @param out - Output buffer receiving the ciphertext block
|
|
131
|
+
* @param inOff - Offset of the plaintext block within xi
|
|
132
|
+
* @param outOff - Offset of the ciphertext block within out
|
|
144
133
|
*/
|
|
145
|
-
encTo(xi, out) {
|
|
146
|
-
this.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
134
|
+
encTo(xi, out, inOff = 0, outOff = 0) {
|
|
135
|
+
const t = this.tmp;
|
|
136
|
+
for (let i = 0; i < this.d; i++) {
|
|
137
|
+
const st = this.lanes[i];
|
|
138
|
+
keystream256(st, this.z);
|
|
139
|
+
blockFromBytes(t, xi, inOff + i * 16);
|
|
140
|
+
packConstantInput256(this.ci, t);
|
|
141
|
+
aegisRound256(st, this.ci);
|
|
142
|
+
blockXor(t, t, this.z);
|
|
143
|
+
blockToBytes(out, t, outOff + i * 16);
|
|
144
|
+
}
|
|
152
145
|
}
|
|
153
146
|
/**
|
|
154
147
|
* Encrypts a plaintext block.
|
|
@@ -156,23 +149,28 @@ export class Aegis256XState {
|
|
|
156
149
|
* @returns Ciphertext block of the same size
|
|
157
150
|
*/
|
|
158
151
|
enc(xi) {
|
|
159
|
-
const
|
|
160
|
-
const out = new Uint8Array(rateBytes);
|
|
152
|
+
const out = new Uint8Array(this.rateBytes);
|
|
161
153
|
this.encTo(xi, out);
|
|
162
154
|
return out;
|
|
163
155
|
}
|
|
164
156
|
/**
|
|
165
157
|
* Decrypts a ciphertext block and writes to output buffer.
|
|
166
|
-
* @param ci -
|
|
167
|
-
* @param out - Output buffer
|
|
158
|
+
* @param ci - Buffer holding the 16*degree-byte ciphertext block
|
|
159
|
+
* @param out - Output buffer receiving the plaintext block
|
|
160
|
+
* @param inOff - Offset of the ciphertext block within ci
|
|
161
|
+
* @param outOff - Offset of the plaintext block within out
|
|
168
162
|
*/
|
|
169
|
-
decTo(ci, out) {
|
|
170
|
-
this.
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
163
|
+
decTo(ci, out, inOff = 0, outOff = 0) {
|
|
164
|
+
const msg = this.tmp;
|
|
165
|
+
for (let i = 0; i < this.d; i++) {
|
|
166
|
+
const st = this.lanes[i];
|
|
167
|
+
blockFromBytes(msg, ci, inOff + i * 16);
|
|
168
|
+
keystream256(st, this.z);
|
|
169
|
+
blockXor(msg, msg, this.z);
|
|
170
|
+
packConstantInput256(this.ci, msg);
|
|
171
|
+
aegisRound256(st, this.ci);
|
|
172
|
+
blockToBytes(out, msg, outOff + i * 16);
|
|
173
|
+
}
|
|
176
174
|
}
|
|
177
175
|
/**
|
|
178
176
|
* Decrypts a ciphertext block.
|
|
@@ -180,22 +178,13 @@ export class Aegis256XState {
|
|
|
180
178
|
* @returns Plaintext block of the same size
|
|
181
179
|
*/
|
|
182
180
|
dec(ci) {
|
|
183
|
-
const
|
|
184
|
-
const out = new Uint8Array(rateBytes);
|
|
181
|
+
const out = new Uint8Array(this.rateBytes);
|
|
185
182
|
this.decTo(ci, out);
|
|
186
183
|
return out;
|
|
187
184
|
}
|
|
188
|
-
/**
|
|
189
|
-
* Encrypts a plaintext block in-place.
|
|
190
|
-
* @param block - Buffer (plaintext in, ciphertext out), size 16*degree bytes
|
|
191
|
-
*/
|
|
192
185
|
encInPlace(block) {
|
|
193
186
|
this.encTo(block, block);
|
|
194
187
|
}
|
|
195
|
-
/**
|
|
196
|
-
* Decrypts a ciphertext block in-place.
|
|
197
|
-
* @param block - Buffer (ciphertext in, plaintext out), size 16*degree bytes
|
|
198
|
-
*/
|
|
199
188
|
decInPlace(block) {
|
|
200
189
|
this.decTo(block, block);
|
|
201
190
|
}
|
|
@@ -205,121 +194,214 @@ export class Aegis256XState {
|
|
|
205
194
|
* @returns Decrypted plaintext of the same length
|
|
206
195
|
*/
|
|
207
196
|
decPartial(cn) {
|
|
208
|
-
this.
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
197
|
+
const padded = zeroPad(cn, this.rateBytes);
|
|
198
|
+
const ks = new Uint8Array(this.rateBytes);
|
|
199
|
+
for (let i = 0; i < this.d; i++) {
|
|
200
|
+
keystream256(this.lanes[i], this.z);
|
|
201
|
+
blockToBytes(ks, this.z, i * 16);
|
|
202
|
+
}
|
|
203
|
+
const out = new Uint8Array(this.rateBytes);
|
|
204
|
+
for (let j = 0; j < this.rateBytes; j++)
|
|
205
|
+
out[j] = padded[j] ^ ks[j];
|
|
215
206
|
const xn = new Uint8Array(out.subarray(0, cn.length));
|
|
216
|
-
|
|
217
|
-
this.
|
|
207
|
+
out.fill(0, cn.length);
|
|
208
|
+
for (let i = 0; i < this.d; i++) {
|
|
209
|
+
blockFromBytes(this.tmp, out, i * 16);
|
|
210
|
+
packConstantInput256(this.ci, this.tmp);
|
|
211
|
+
aegisRound256(this.lanes[i], this.ci);
|
|
212
|
+
}
|
|
218
213
|
return xn;
|
|
219
214
|
}
|
|
220
215
|
/**
|
|
221
216
|
* Finalizes encryption/decryption and produces an authentication tag.
|
|
222
|
-
* @param
|
|
223
|
-
* @param
|
|
217
|
+
* @param adLen - Associated data length in bytes
|
|
218
|
+
* @param msgLen - Message length in bytes
|
|
224
219
|
* @param tagLen - Tag length (16 or 32 bytes)
|
|
225
220
|
* @returns Authentication tag
|
|
226
221
|
*/
|
|
227
|
-
finalize(
|
|
228
|
-
|
|
229
|
-
const
|
|
222
|
+
finalize(adLen, msgLen, tagLen = 16) {
|
|
223
|
+
const u = createAesBlock();
|
|
224
|
+
const t = this.tmp;
|
|
225
|
+
u[0] = (adLen * 8) & 0xffffffff;
|
|
226
|
+
u[1] = Math.floor((adLen * 8) / 0x100000000);
|
|
227
|
+
u[2] = (msgLen * 8) & 0xffffffff;
|
|
228
|
+
u[3] = Math.floor((msgLen * 8) / 0x100000000);
|
|
229
|
+
const unpacked = createAesBlocks();
|
|
230
230
|
for (let i = 0; i < this.d; i++) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
231
|
+
const st = this.lanes[i];
|
|
232
|
+
unpacked.set(st);
|
|
233
|
+
unpack(unpacked);
|
|
234
|
+
for (let j = 0; j < 4; j++)
|
|
235
|
+
t[j] = u[j] ^ unpacked[wordIdx(3, j)];
|
|
236
|
+
packConstantInput256(this.ci, t);
|
|
237
|
+
for (let round = 0; round < 7; round++) {
|
|
238
|
+
aegisRound256(st, this.ci);
|
|
239
|
+
}
|
|
240
|
+
unpack(st);
|
|
235
241
|
}
|
|
236
242
|
if (tagLen === 16) {
|
|
237
|
-
|
|
243
|
+
const tagBlock = createAesBlock();
|
|
238
244
|
for (let i = 0; i < this.d; i++) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
+
const st = this.lanes[i];
|
|
246
|
+
for (let j = 0; j < 4; j++) {
|
|
247
|
+
tagBlock[j] =
|
|
248
|
+
tagBlock[j] ^
|
|
249
|
+
st[wordIdx(0, j)] ^
|
|
250
|
+
st[wordIdx(1, j)] ^
|
|
251
|
+
st[wordIdx(2, j)] ^
|
|
252
|
+
st[wordIdx(3, j)] ^
|
|
253
|
+
st[wordIdx(4, j)] ^
|
|
254
|
+
st[wordIdx(5, j)];
|
|
255
|
+
}
|
|
245
256
|
}
|
|
257
|
+
const tag = new Uint8Array(16);
|
|
258
|
+
blockToBytes(tag, tagBlock);
|
|
246
259
|
return tag;
|
|
247
260
|
}
|
|
248
261
|
else {
|
|
249
|
-
|
|
250
|
-
|
|
262
|
+
const tagBlock0 = createAesBlock();
|
|
263
|
+
const tagBlock1 = createAesBlock();
|
|
251
264
|
for (let i = 0; i < this.d; i++) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
265
|
+
const st = this.lanes[i];
|
|
266
|
+
for (let j = 0; j < 4; j++) {
|
|
267
|
+
tagBlock0[j] =
|
|
268
|
+
tagBlock0[j] ^
|
|
269
|
+
st[wordIdx(0, j)] ^
|
|
270
|
+
st[wordIdx(1, j)] ^
|
|
271
|
+
st[wordIdx(2, j)];
|
|
272
|
+
tagBlock1[j] =
|
|
273
|
+
tagBlock1[j] ^
|
|
274
|
+
st[wordIdx(3, j)] ^
|
|
275
|
+
st[wordIdx(4, j)] ^
|
|
276
|
+
st[wordIdx(5, j)];
|
|
277
|
+
}
|
|
258
278
|
}
|
|
259
|
-
|
|
279
|
+
const tag = new Uint8Array(32);
|
|
280
|
+
blockToBytes(tag, tagBlock0);
|
|
281
|
+
blockToBytes(tag, tagBlock1, 16);
|
|
282
|
+
return tag;
|
|
260
283
|
}
|
|
261
284
|
}
|
|
262
285
|
/**
|
|
263
286
|
* Finalizes MAC computation and produces an authentication tag.
|
|
264
287
|
* Uses a different finalization procedure than encryption/decryption.
|
|
265
|
-
* @param
|
|
288
|
+
* @param dataLen - Data length in bytes
|
|
266
289
|
* @param tagLen - Tag length (16 or 32 bytes)
|
|
267
290
|
* @returns Authentication tag
|
|
268
291
|
*/
|
|
269
|
-
finalizeMac(
|
|
270
|
-
|
|
271
|
-
const
|
|
292
|
+
finalizeMac(dataLen, tagLen = 16) {
|
|
293
|
+
const u = createAesBlock();
|
|
294
|
+
const t = this.tmp;
|
|
295
|
+
u[0] = (dataLen * 8) & 0xffffffff;
|
|
296
|
+
u[1] = Math.floor((dataLen * 8) / 0x100000000);
|
|
297
|
+
u[2] = tagLen * 8;
|
|
298
|
+
u[3] = 0;
|
|
299
|
+
const unpacked = createAesBlocks();
|
|
272
300
|
for (let i = 0; i < this.d; i++) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
let ti = xorBlocks(this.v[0][i], this.v[1][i]);
|
|
282
|
-
ti = xorBlocks(ti, this.v[2][i]);
|
|
283
|
-
ti = xorBlocks(ti, this.v[3][i]);
|
|
284
|
-
ti = xorBlocks(ti, this.v[4][i]);
|
|
285
|
-
ti = xorBlocks(ti, this.v[5][i]);
|
|
286
|
-
tags = concatBytes(tags, ti);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
else {
|
|
290
|
-
for (let i = 1; i < this.d; i++) {
|
|
291
|
-
let ti0 = xorBlocks(this.v[0][i], this.v[1][i]);
|
|
292
|
-
ti0 = xorBlocks(ti0, this.v[2][i]);
|
|
293
|
-
let ti1 = xorBlocks(this.v[3][i], this.v[4][i]);
|
|
294
|
-
ti1 = xorBlocks(ti1, this.v[5][i]);
|
|
295
|
-
tags = concatBytes(tags, ti0, ti1);
|
|
301
|
+
const st = this.lanes[i];
|
|
302
|
+
unpacked.set(st);
|
|
303
|
+
unpack(unpacked);
|
|
304
|
+
for (let j = 0; j < 4; j++)
|
|
305
|
+
t[j] = u[j] ^ unpacked[wordIdx(3, j)];
|
|
306
|
+
packConstantInput256(this.ci, t);
|
|
307
|
+
for (let round = 0; round < 7; round++) {
|
|
308
|
+
aegisRound256(st, this.ci);
|
|
296
309
|
}
|
|
297
310
|
}
|
|
298
311
|
if (this.d > 1) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
this.
|
|
312
|
+
let tags;
|
|
313
|
+
if (tagLen === 16) {
|
|
314
|
+
tags = new Uint8Array(16 * (this.d - 1));
|
|
315
|
+
const tb = createAesBlock();
|
|
316
|
+
for (let i = 1; i < this.d; i++) {
|
|
317
|
+
unpacked.set(this.lanes[i]);
|
|
318
|
+
unpack(unpacked);
|
|
319
|
+
for (let j = 0; j < 4; j++) {
|
|
320
|
+
tb[j] =
|
|
321
|
+
unpacked[wordIdx(0, j)] ^
|
|
322
|
+
unpacked[wordIdx(1, j)] ^
|
|
323
|
+
unpacked[wordIdx(2, j)] ^
|
|
324
|
+
unpacked[wordIdx(3, j)] ^
|
|
325
|
+
unpacked[wordIdx(4, j)] ^
|
|
326
|
+
unpacked[wordIdx(5, j)];
|
|
327
|
+
}
|
|
328
|
+
blockToBytes(tags, tb, (i - 1) * 16);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
tags = new Uint8Array(32 * (this.d - 1));
|
|
333
|
+
const tb0 = createAesBlock();
|
|
334
|
+
const tb1 = createAesBlock();
|
|
335
|
+
for (let i = 1; i < this.d; i++) {
|
|
336
|
+
unpacked.set(this.lanes[i]);
|
|
337
|
+
unpack(unpacked);
|
|
338
|
+
for (let j = 0; j < 4; j++) {
|
|
339
|
+
tb0[j] =
|
|
340
|
+
unpacked[wordIdx(0, j)] ^
|
|
341
|
+
unpacked[wordIdx(1, j)] ^
|
|
342
|
+
unpacked[wordIdx(2, j)];
|
|
343
|
+
tb1[j] =
|
|
344
|
+
unpacked[wordIdx(3, j)] ^
|
|
345
|
+
unpacked[wordIdx(4, j)] ^
|
|
346
|
+
unpacked[wordIdx(5, j)];
|
|
347
|
+
}
|
|
348
|
+
blockToBytes(tags, tb0, (i - 1) * 32);
|
|
349
|
+
blockToBytes(tags, tb1, (i - 1) * 32 + 16);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
for (let off = 0; off + 16 <= tags.length; off += 16) {
|
|
353
|
+
blockFromBytes(this.tmp, tags, off);
|
|
354
|
+
packConstantInput256(this.ci, this.tmp);
|
|
355
|
+
aegisRound256(this.lanes[0], this.ci);
|
|
356
|
+
for (let i = 1; i < this.d; i++) {
|
|
357
|
+
aegisRound256(this.lanes[i], this.ciZero);
|
|
358
|
+
}
|
|
302
359
|
}
|
|
303
|
-
|
|
304
|
-
|
|
360
|
+
unpacked.set(this.lanes[0]);
|
|
361
|
+
unpack(unpacked);
|
|
362
|
+
t[0] = this.d ^ unpacked[wordIdx(3, 0)];
|
|
363
|
+
t[1] = unpacked[wordIdx(3, 1)];
|
|
364
|
+
t[2] = (tagLen * 8) ^ unpacked[wordIdx(3, 2)];
|
|
365
|
+
t[3] = unpacked[wordIdx(3, 3)];
|
|
366
|
+
packConstantInput256(this.ci, t);
|
|
305
367
|
for (let round = 0; round < 7; round++) {
|
|
306
|
-
this.
|
|
368
|
+
aegisRound256(this.lanes[0], this.ci);
|
|
369
|
+
for (let i = 1; i < this.d; i++) {
|
|
370
|
+
aegisRound256(this.lanes[i], this.ciZero);
|
|
371
|
+
}
|
|
307
372
|
}
|
|
308
373
|
}
|
|
374
|
+
const st = createAesBlocks();
|
|
375
|
+
st.set(this.lanes[0]);
|
|
376
|
+
unpack(st);
|
|
309
377
|
if (tagLen === 16) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
378
|
+
const tag = new Uint8Array(16);
|
|
379
|
+
const tagBlock = createAesBlock();
|
|
380
|
+
for (let j = 0; j < 4; j++) {
|
|
381
|
+
tagBlock[j] =
|
|
382
|
+
st[wordIdx(0, j)] ^
|
|
383
|
+
st[wordIdx(1, j)] ^
|
|
384
|
+
st[wordIdx(2, j)] ^
|
|
385
|
+
st[wordIdx(3, j)] ^
|
|
386
|
+
st[wordIdx(4, j)] ^
|
|
387
|
+
st[wordIdx(5, j)];
|
|
388
|
+
}
|
|
389
|
+
blockToBytes(tag, tagBlock);
|
|
315
390
|
return tag;
|
|
316
391
|
}
|
|
317
392
|
else {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
393
|
+
const tag = new Uint8Array(32);
|
|
394
|
+
const tagBlock0 = createAesBlock();
|
|
395
|
+
const tagBlock1 = createAesBlock();
|
|
396
|
+
for (let j = 0; j < 4; j++) {
|
|
397
|
+
tagBlock0[j] =
|
|
398
|
+
st[wordIdx(0, j)] ^ st[wordIdx(1, j)] ^ st[wordIdx(2, j)];
|
|
399
|
+
tagBlock1[j] =
|
|
400
|
+
st[wordIdx(3, j)] ^ st[wordIdx(4, j)] ^ st[wordIdx(5, j)];
|
|
401
|
+
}
|
|
402
|
+
blockToBytes(tag, tagBlock0);
|
|
403
|
+
blockToBytes(tag, tagBlock1, 16);
|
|
404
|
+
return tag;
|
|
323
405
|
}
|
|
324
406
|
}
|
|
325
407
|
}
|
|
@@ -335,19 +417,23 @@ export class Aegis256XState {
|
|
|
335
417
|
*/
|
|
336
418
|
export function aegis256XEncryptDetached(msg, ad, key, nonce, tagLen = 16, degree = 2) {
|
|
337
419
|
const state = new Aegis256XState(degree);
|
|
338
|
-
const rateBytes =
|
|
420
|
+
const rateBytes = 16 * degree;
|
|
339
421
|
state.init(key, nonce);
|
|
340
422
|
const adPadded = zeroPad(ad, rateBytes);
|
|
341
423
|
for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
|
|
342
|
-
state.absorb(adPadded
|
|
424
|
+
state.absorb(adPadded, i);
|
|
343
425
|
}
|
|
344
|
-
const
|
|
345
|
-
const
|
|
346
|
-
for (let i = 0; i
|
|
347
|
-
state.encTo(
|
|
426
|
+
const ciphertext = new Uint8Array(msg.length);
|
|
427
|
+
const fullBlocks = Math.floor(msg.length / rateBytes) * rateBytes;
|
|
428
|
+
for (let i = 0; i < fullBlocks; i += rateBytes) {
|
|
429
|
+
state.encTo(msg, ciphertext, i, i);
|
|
430
|
+
}
|
|
431
|
+
if (msg.length > fullBlocks) {
|
|
432
|
+
const lastBlock = zeroPad(msg.subarray(fullBlocks), rateBytes);
|
|
433
|
+
const encBlock = state.enc(lastBlock);
|
|
434
|
+
ciphertext.set(encBlock.subarray(0, msg.length - fullBlocks), fullBlocks);
|
|
348
435
|
}
|
|
349
|
-
const tag = state.finalize(
|
|
350
|
-
const ciphertext = new Uint8Array(ct.subarray(0, msg.length));
|
|
436
|
+
const tag = state.finalize(ad.length, msg.length, tagLen);
|
|
351
437
|
return { ciphertext, tag };
|
|
352
438
|
}
|
|
353
439
|
/**
|
|
@@ -363,22 +449,21 @@ export function aegis256XEncryptDetached(msg, ad, key, nonce, tagLen = 16, degre
|
|
|
363
449
|
export function aegis256XDecryptDetached(ct, tag, ad, key, nonce, degree = 2) {
|
|
364
450
|
const tagLen = tag.length;
|
|
365
451
|
const state = new Aegis256XState(degree);
|
|
366
|
-
const rateBytes =
|
|
452
|
+
const rateBytes = 16 * degree;
|
|
367
453
|
state.init(key, nonce);
|
|
368
454
|
const adPadded = zeroPad(ad, rateBytes);
|
|
369
455
|
for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
|
|
370
|
-
state.absorb(adPadded
|
|
456
|
+
state.absorb(adPadded, i);
|
|
371
457
|
}
|
|
372
|
-
const
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
state.decTo(ct.subarray(i, i + rateBytes), msg.subarray(i, i + rateBytes));
|
|
458
|
+
const msg = new Uint8Array(ct.length);
|
|
459
|
+
const fullBlocks = Math.floor(ct.length / rateBytes) * rateBytes;
|
|
460
|
+
for (let i = 0; i < fullBlocks; i += rateBytes) {
|
|
461
|
+
state.decTo(ct, msg, i, i);
|
|
377
462
|
}
|
|
378
|
-
if (
|
|
379
|
-
msg.set(state.decPartial(
|
|
463
|
+
if (ct.length > fullBlocks) {
|
|
464
|
+
msg.set(state.decPartial(ct.subarray(fullBlocks)), fullBlocks);
|
|
380
465
|
}
|
|
381
|
-
const expectedTag = state.finalize(
|
|
466
|
+
const expectedTag = state.finalize(ad.length, msg.length, tagLen);
|
|
382
467
|
if (!constantTimeEqual(tag, expectedTag)) {
|
|
383
468
|
msg.fill(0);
|
|
384
469
|
return null;
|
|
@@ -398,16 +483,16 @@ export function aegis256XDecryptDetached(ct, tag, ad, key, nonce, degree = 2) {
|
|
|
398
483
|
*/
|
|
399
484
|
export function aegis256XEncryptDetachedInPlace(data, ad, key, nonce, tagLen = 16, degree = 2) {
|
|
400
485
|
const state = new Aegis256XState(degree);
|
|
401
|
-
const rateBytes =
|
|
486
|
+
const rateBytes = 16 * degree;
|
|
402
487
|
state.init(key, nonce);
|
|
403
488
|
const adPadded = zeroPad(ad, rateBytes);
|
|
404
489
|
for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
|
|
405
|
-
state.absorb(adPadded
|
|
490
|
+
state.absorb(adPadded, i);
|
|
406
491
|
}
|
|
407
492
|
const msgLen = data.length;
|
|
408
493
|
const fullBlocksLen = Math.floor(msgLen / rateBytes) * rateBytes;
|
|
409
494
|
for (let i = 0; i < fullBlocksLen; i += rateBytes) {
|
|
410
|
-
state.
|
|
495
|
+
state.encTo(data, data, i, i);
|
|
411
496
|
}
|
|
412
497
|
if (msgLen > fullBlocksLen) {
|
|
413
498
|
const lastPartial = data.subarray(fullBlocksLen);
|
|
@@ -415,7 +500,7 @@ export function aegis256XEncryptDetachedInPlace(data, ad, key, nonce, tagLen = 1
|
|
|
415
500
|
const encBlock = state.enc(lastBlock);
|
|
416
501
|
lastPartial.set(encBlock.subarray(0, lastPartial.length));
|
|
417
502
|
}
|
|
418
|
-
return state.finalize(
|
|
503
|
+
return state.finalize(ad.length, msgLen, tagLen);
|
|
419
504
|
}
|
|
420
505
|
/**
|
|
421
506
|
* Decrypts a message in-place using AEGIS-256X (detached mode).
|
|
@@ -431,23 +516,23 @@ export function aegis256XEncryptDetachedInPlace(data, ad, key, nonce, tagLen = 1
|
|
|
431
516
|
export function aegis256XDecryptDetachedInPlace(data, tag, ad, key, nonce, degree = 2) {
|
|
432
517
|
const tagLen = tag.length;
|
|
433
518
|
const state = new Aegis256XState(degree);
|
|
434
|
-
const rateBytes =
|
|
519
|
+
const rateBytes = 16 * degree;
|
|
435
520
|
state.init(key, nonce);
|
|
436
521
|
const adPadded = zeroPad(ad, rateBytes);
|
|
437
522
|
for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
|
|
438
|
-
state.absorb(adPadded
|
|
523
|
+
state.absorb(adPadded, i);
|
|
439
524
|
}
|
|
440
525
|
const msgLen = data.length;
|
|
441
526
|
const fullBlocksLen = Math.floor(msgLen / rateBytes) * rateBytes;
|
|
442
527
|
for (let i = 0; i < fullBlocksLen; i += rateBytes) {
|
|
443
|
-
state.
|
|
528
|
+
state.decTo(data, data, i, i);
|
|
444
529
|
}
|
|
445
530
|
if (msgLen > fullBlocksLen) {
|
|
446
531
|
const lastPartial = data.subarray(fullBlocksLen);
|
|
447
532
|
const decrypted = state.decPartial(lastPartial);
|
|
448
533
|
lastPartial.set(decrypted);
|
|
449
534
|
}
|
|
450
|
-
const expectedTag = state.finalize(
|
|
535
|
+
const expectedTag = state.finalize(ad.length, msgLen, tagLen);
|
|
451
536
|
if (!constantTimeEqual(tag, expectedTag)) {
|
|
452
537
|
data.fill(0);
|
|
453
538
|
return false;
|
|
@@ -479,27 +564,11 @@ export const AEGIS_256X_KEY_SIZE = 32;
|
|
|
479
564
|
*/
|
|
480
565
|
export function aegis256XEncrypt(msg, ad, key, nonce = null, tagLen = 16, degree = 2) {
|
|
481
566
|
const actualNonce = nonce ?? randomBytes(AEGIS_256X_NONCE_SIZE);
|
|
482
|
-
const
|
|
483
|
-
const
|
|
484
|
-
state.init(key, actualNonce);
|
|
485
|
-
const adPadded = zeroPad(ad, rateBytes);
|
|
486
|
-
for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
|
|
487
|
-
state.absorb(adPadded.subarray(i, i + rateBytes));
|
|
488
|
-
}
|
|
489
|
-
const nonceSize = AEGIS_256X_NONCE_SIZE;
|
|
490
|
-
const result = new Uint8Array(nonceSize + msg.length + tagLen);
|
|
567
|
+
const { ciphertext, tag } = aegis256XEncryptDetached(msg, ad, key, actualNonce, tagLen, degree);
|
|
568
|
+
const result = new Uint8Array(AEGIS_256X_NONCE_SIZE + ciphertext.length + tagLen);
|
|
491
569
|
result.set(actualNonce, 0);
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
state.encTo(msg.subarray(i, i + rateBytes), result.subarray(nonceSize + i, nonceSize + i + rateBytes));
|
|
495
|
-
}
|
|
496
|
-
if (msg.length > fullBlocks) {
|
|
497
|
-
const lastBlock = zeroPad(msg.subarray(fullBlocks), rateBytes);
|
|
498
|
-
const encBlock = state.enc(lastBlock);
|
|
499
|
-
result.set(encBlock.subarray(0, msg.length - fullBlocks), nonceSize + fullBlocks);
|
|
500
|
-
}
|
|
501
|
-
const tag = state.finalize(BigInt(ad.length * 8), BigInt(msg.length * 8), tagLen);
|
|
502
|
-
result.set(tag, nonceSize + msg.length);
|
|
570
|
+
result.set(ciphertext, AEGIS_256X_NONCE_SIZE);
|
|
571
|
+
result.set(tag, AEGIS_256X_NONCE_SIZE + ciphertext.length);
|
|
503
572
|
return result;
|
|
504
573
|
}
|
|
505
574
|
/**
|
|
@@ -549,13 +618,13 @@ export const aegis256X4Decrypt = (sealed, ad, key, tagLen = 16) => aegis256XDecr
|
|
|
549
618
|
*/
|
|
550
619
|
export function aegis256XMac(data, key, nonce = null, tagLen = 16, degree = 2) {
|
|
551
620
|
const state = new Aegis256XState(degree);
|
|
552
|
-
const rateBytes =
|
|
621
|
+
const rateBytes = 16 * degree;
|
|
553
622
|
state.init(key, nonce ?? new Uint8Array(32));
|
|
554
623
|
const dataPadded = zeroPad(data, rateBytes);
|
|
555
624
|
for (let i = 0; i + rateBytes <= dataPadded.length; i += rateBytes) {
|
|
556
|
-
state.absorb(dataPadded
|
|
625
|
+
state.absorb(dataPadded, i);
|
|
557
626
|
}
|
|
558
|
-
return state.finalizeMac(
|
|
627
|
+
return state.finalizeMac(data.length, tagLen);
|
|
559
628
|
}
|
|
560
629
|
/**
|
|
561
630
|
* Verifies a MAC computed using AEGIS-256X.
|
|
@@ -603,4 +672,3 @@ export const aegis256X2CreateNonce = aegis256XCreateNonce;
|
|
|
603
672
|
export const aegis256X4CreateKey = aegis256XCreateKey;
|
|
604
673
|
/** AEGIS-256X4 nonce generation (degree=4). */
|
|
605
674
|
export const aegis256X4CreateNonce = aegis256XCreateNonce;
|
|
606
|
-
//# sourceMappingURL=aegis256x.js.map
|