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/aegis128l.js
CHANGED
|
@@ -1,47 +1,61 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* AEGIS-128L implementation.
|
|
3
|
+
* Built on the constant-time bitsliced AES core, which processes all 8 state
|
|
4
|
+
* blocks simultaneously without lookup tables.
|
|
5
|
+
*/
|
|
6
|
+
import { aegisRound128, blockFromBytes, blocksPut, blockToBytes, blockXor, createAesBlock, createAesBlocks, keystream128, pack, packConstantInput128, unpack, wordIdx, } from "./aes-bs.js";
|
|
2
7
|
import { randomBytes } from "./random.js";
|
|
8
|
+
import { constantTimeEqual, zeroPad } from "./utils.js";
|
|
9
|
+
const RATE = 32;
|
|
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-128L cipher state.
|
|
5
|
-
*
|
|
18
|
+
* The state is kept in packed bitsliced form between operations so that
|
|
19
|
+
* pack/unpack does not need to be applied at every round.
|
|
6
20
|
*/
|
|
7
21
|
export class Aegis128LState {
|
|
8
22
|
constructor() {
|
|
9
|
-
this.
|
|
10
|
-
this.
|
|
11
|
-
this.
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
this.s6 = new Uint8Array(16);
|
|
16
|
-
this.s7 = new Uint8Array(16);
|
|
17
|
-
this.tmp0 = new Uint8Array(16);
|
|
18
|
-
this.tmp1 = new Uint8Array(16);
|
|
19
|
-
this.z0 = new Uint8Array(16);
|
|
20
|
-
this.z1 = new Uint8Array(16);
|
|
21
|
-
this.newS = Array.from({ length: 8 }, () => new Uint8Array(16));
|
|
22
|
-
this.tBuf = new Uint8Array(16);
|
|
23
|
+
this.st = createAesBlocks();
|
|
24
|
+
this.constantInput = createAesBlocks();
|
|
25
|
+
this.tmp0 = createAesBlock();
|
|
26
|
+
this.tmp1 = createAesBlock();
|
|
27
|
+
this.z0 = createAesBlock();
|
|
28
|
+
this.z1 = createAesBlock();
|
|
23
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns the 8 state blocks as byte arrays (for testing).
|
|
32
|
+
*/
|
|
24
33
|
get s() {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
const unpacked = createAesBlocks();
|
|
35
|
+
unpacked.set(this.st);
|
|
36
|
+
unpack(unpacked);
|
|
37
|
+
const blocks = [];
|
|
38
|
+
const w = createAesBlock();
|
|
39
|
+
for (let i = 0; i < 8; i++) {
|
|
40
|
+
for (let j = 0; j < 4; j++)
|
|
41
|
+
w[j] = unpacked[wordIdx(i, j)];
|
|
42
|
+
const bytes = new Uint8Array(16);
|
|
43
|
+
blockToBytes(bytes, w);
|
|
44
|
+
blocks.push(bytes);
|
|
45
|
+
}
|
|
46
|
+
return blocks;
|
|
35
47
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
this.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Sets the 8 state blocks from byte arrays (for testing).
|
|
50
|
+
*/
|
|
51
|
+
set s(blocks) {
|
|
52
|
+
this.st.fill(0);
|
|
53
|
+
const w = createAesBlock();
|
|
54
|
+
for (let i = 0; i < 8; i++) {
|
|
55
|
+
blockFromBytes(w, blocks[i]);
|
|
56
|
+
blocksPut(this.st, w, i);
|
|
57
|
+
}
|
|
58
|
+
pack(this.st);
|
|
45
59
|
}
|
|
46
60
|
/**
|
|
47
61
|
* Initializes the state with a key and nonce.
|
|
@@ -49,16 +63,28 @@ export class Aegis128LState {
|
|
|
49
63
|
* @param nonce - 16-byte nonce (must be unique per message)
|
|
50
64
|
*/
|
|
51
65
|
init(key, nonce) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
66
|
+
const k = createAesBlock();
|
|
67
|
+
const n = createAesBlock();
|
|
68
|
+
const kn = createAesBlock();
|
|
69
|
+
const kc0 = createAesBlock();
|
|
70
|
+
const kc1 = createAesBlock();
|
|
71
|
+
blockFromBytes(k, key);
|
|
72
|
+
blockFromBytes(n, nonce);
|
|
73
|
+
blockXor(kn, k, n);
|
|
74
|
+
blockXor(kc0, k, C0);
|
|
75
|
+
blockXor(kc1, k, C1);
|
|
76
|
+
blocksPut(this.st, kn, 0);
|
|
77
|
+
blocksPut(this.st, C1, 1);
|
|
78
|
+
blocksPut(this.st, C0, 2);
|
|
79
|
+
blocksPut(this.st, C1, 3);
|
|
80
|
+
blocksPut(this.st, kn, 4);
|
|
81
|
+
blocksPut(this.st, kc0, 5);
|
|
82
|
+
blocksPut(this.st, kc1, 6);
|
|
83
|
+
blocksPut(this.st, kc0, 7);
|
|
84
|
+
packConstantInput128(this.constantInput, n, k);
|
|
85
|
+
pack(this.st);
|
|
60
86
|
for (let i = 0; i < 10; i++) {
|
|
61
|
-
this.
|
|
87
|
+
aegisRound128(this.st, this.constantInput);
|
|
62
88
|
}
|
|
63
89
|
}
|
|
64
90
|
/**
|
|
@@ -67,57 +93,43 @@ export class Aegis128LState {
|
|
|
67
93
|
* @param m1 - Second 16-byte message block
|
|
68
94
|
*/
|
|
69
95
|
update(m0, m1) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
aesRoundTo(this.s1, this.s2, newS[2]);
|
|
75
|
-
aesRoundTo(this.s2, this.s3, newS[3]);
|
|
76
|
-
xorBlocksTo(this.s4, m1, this.tmp1);
|
|
77
|
-
aesRoundTo(this.s3, this.tmp1, newS[4]);
|
|
78
|
-
aesRoundTo(this.s4, this.s5, newS[5]);
|
|
79
|
-
aesRoundTo(this.s5, this.s6, newS[6]);
|
|
80
|
-
aesRoundTo(this.s6, this.s7, newS[7]);
|
|
81
|
-
this.s0.set(newS[0]);
|
|
82
|
-
this.s1.set(newS[1]);
|
|
83
|
-
this.s2.set(newS[2]);
|
|
84
|
-
this.s3.set(newS[3]);
|
|
85
|
-
this.s4.set(newS[4]);
|
|
86
|
-
this.s5.set(newS[5]);
|
|
87
|
-
this.s6.set(newS[6]);
|
|
88
|
-
this.s7.set(newS[7]);
|
|
96
|
+
blockFromBytes(this.tmp0, m0);
|
|
97
|
+
blockFromBytes(this.tmp1, m1);
|
|
98
|
+
packConstantInput128(this.constantInput, this.tmp0, this.tmp1);
|
|
99
|
+
aegisRound128(this.st, this.constantInput);
|
|
89
100
|
}
|
|
90
101
|
/**
|
|
91
102
|
* Absorbs a 32-byte associated data block into the state.
|
|
92
|
-
* @param ai - 32-byte associated data block
|
|
103
|
+
* @param ai - Buffer holding the 32-byte associated data block
|
|
104
|
+
* @param off - Offset of the block within the buffer
|
|
93
105
|
*/
|
|
94
|
-
absorb(ai) {
|
|
95
|
-
|
|
106
|
+
absorb(ai, off = 0) {
|
|
107
|
+
const msg0 = this.tmp0;
|
|
108
|
+
const msg1 = this.tmp1;
|
|
109
|
+
blockFromBytes(msg0, ai, off);
|
|
110
|
+
blockFromBytes(msg1, ai, off + 16);
|
|
111
|
+
packConstantInput128(this.constantInput, msg0, msg1);
|
|
112
|
+
aegisRound128(this.st, this.constantInput);
|
|
96
113
|
}
|
|
97
114
|
/**
|
|
98
115
|
* Encrypts a 32-byte plaintext block and writes to output buffer.
|
|
99
|
-
* @param xi - 32-byte plaintext block
|
|
100
|
-
* @param out - 32-byte
|
|
116
|
+
* @param xi - Buffer holding the 32-byte plaintext block
|
|
117
|
+
* @param out - Output buffer receiving the 32-byte ciphertext block
|
|
118
|
+
* @param inOff - Offset of the plaintext block within xi
|
|
119
|
+
* @param outOff - Offset of the ciphertext block within out
|
|
101
120
|
*/
|
|
102
|
-
encTo(xi, out) {
|
|
103
|
-
const
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const t0 = xi.subarray(0, 16);
|
|
115
|
-
const t1 = xi.subarray(16, 32);
|
|
116
|
-
for (let i = 0; i < 16; i++)
|
|
117
|
-
out[i] = t0[i] ^ z0[i];
|
|
118
|
-
for (let i = 0; i < 16; i++)
|
|
119
|
-
out[16 + i] = t1[i] ^ z1[i];
|
|
120
|
-
this.update(t0, t1);
|
|
121
|
+
encTo(xi, out, inOff = 0, outOff = 0) {
|
|
122
|
+
const t0 = this.tmp0;
|
|
123
|
+
const t1 = this.tmp1;
|
|
124
|
+
keystream128(this.st, this.z0, this.z1);
|
|
125
|
+
blockFromBytes(t0, xi, inOff);
|
|
126
|
+
blockFromBytes(t1, xi, inOff + 16);
|
|
127
|
+
packConstantInput128(this.constantInput, t0, t1);
|
|
128
|
+
aegisRound128(this.st, this.constantInput);
|
|
129
|
+
blockXor(t0, t0, this.z0);
|
|
130
|
+
blockXor(t1, t1, this.z1);
|
|
131
|
+
blockToBytes(out, t0, outOff);
|
|
132
|
+
blockToBytes(out, t1, outOff + 16);
|
|
121
133
|
}
|
|
122
134
|
/**
|
|
123
135
|
* Encrypts a 32-byte plaintext block.
|
|
@@ -131,28 +143,23 @@ export class Aegis128LState {
|
|
|
131
143
|
}
|
|
132
144
|
/**
|
|
133
145
|
* Decrypts a 32-byte ciphertext block and writes to output buffer.
|
|
134
|
-
* @param ci - 32-byte ciphertext block
|
|
135
|
-
* @param out - 32-byte
|
|
146
|
+
* @param ci - Buffer holding the 32-byte ciphertext block
|
|
147
|
+
* @param out - Output buffer receiving the 32-byte plaintext block
|
|
148
|
+
* @param inOff - Offset of the ciphertext block within ci
|
|
149
|
+
* @param outOff - Offset of the plaintext block within out
|
|
136
150
|
*/
|
|
137
|
-
decTo(ci, out) {
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const t0 = ci.subarray(0, 16);
|
|
150
|
-
const t1 = ci.subarray(16, 32);
|
|
151
|
-
for (let i = 0; i < 16; i++)
|
|
152
|
-
out[i] = t0[i] ^ z0[i];
|
|
153
|
-
for (let i = 0; i < 16; i++)
|
|
154
|
-
out[16 + i] = t1[i] ^ z1[i];
|
|
155
|
-
this.update(out.subarray(0, 16), out.subarray(16, 32));
|
|
151
|
+
decTo(ci, out, inOff = 0, outOff = 0) {
|
|
152
|
+
const msg0 = this.tmp0;
|
|
153
|
+
const msg1 = this.tmp1;
|
|
154
|
+
blockFromBytes(msg0, ci, inOff);
|
|
155
|
+
blockFromBytes(msg1, ci, inOff + 16);
|
|
156
|
+
keystream128(this.st, this.z0, this.z1);
|
|
157
|
+
blockXor(msg0, msg0, this.z0);
|
|
158
|
+
blockXor(msg1, msg1, this.z1);
|
|
159
|
+
packConstantInput128(this.constantInput, msg0, msg1);
|
|
160
|
+
aegisRound128(this.st, this.constantInput);
|
|
161
|
+
blockToBytes(out, msg0, outOff);
|
|
162
|
+
blockToBytes(out, msg1, outOff + 16);
|
|
156
163
|
}
|
|
157
164
|
/**
|
|
158
165
|
* Decrypts a 32-byte ciphertext block.
|
|
@@ -164,32 +171,9 @@ export class Aegis128LState {
|
|
|
164
171
|
this.decTo(ci, out);
|
|
165
172
|
return out;
|
|
166
173
|
}
|
|
167
|
-
/**
|
|
168
|
-
* Encrypts a 32-byte plaintext block in-place.
|
|
169
|
-
* @param block - 32-byte buffer (plaintext in, ciphertext out)
|
|
170
|
-
*/
|
|
171
174
|
encInPlace(block) {
|
|
172
|
-
|
|
173
|
-
const z1 = this.z1;
|
|
174
|
-
const tmp = this.tmp0;
|
|
175
|
-
xorBlocksTo(this.s1, this.s6, z0);
|
|
176
|
-
andBlocksTo(this.s2, this.s3, tmp);
|
|
177
|
-
for (let i = 0; i < 16; i++)
|
|
178
|
-
z0[i] ^= tmp[i];
|
|
179
|
-
xorBlocksTo(this.s2, this.s5, z1);
|
|
180
|
-
andBlocksTo(this.s6, this.s7, tmp);
|
|
181
|
-
for (let i = 0; i < 16; i++)
|
|
182
|
-
z1[i] ^= tmp[i];
|
|
183
|
-
this.update(block.subarray(0, 16), block.subarray(16, 32));
|
|
184
|
-
for (let i = 0; i < 16; i++)
|
|
185
|
-
block[i] ^= z0[i];
|
|
186
|
-
for (let i = 0; i < 16; i++)
|
|
187
|
-
block[16 + i] ^= z1[i];
|
|
175
|
+
this.encTo(block, block);
|
|
188
176
|
}
|
|
189
|
-
/**
|
|
190
|
-
* Decrypts a 32-byte ciphertext block in-place.
|
|
191
|
-
* @param block - 32-byte buffer (ciphertext in, plaintext out)
|
|
192
|
-
*/
|
|
193
177
|
decInPlace(block) {
|
|
194
178
|
this.decTo(block, block);
|
|
195
179
|
}
|
|
@@ -199,68 +183,87 @@ export class Aegis128LState {
|
|
|
199
183
|
* @returns Decrypted plaintext of the same length
|
|
200
184
|
*/
|
|
201
185
|
decPartial(cn) {
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
for (let i = 0; i < 16; i++)
|
|
220
|
-
out[16 + i] = t1[i] ^ z1[i];
|
|
221
|
-
const xn = new Uint8Array(out.subarray(0, cn.length));
|
|
222
|
-
const v = zeroPad(xn, 32);
|
|
223
|
-
this.update(v.subarray(0, 16), v.subarray(16, 32));
|
|
186
|
+
const msg0 = this.tmp0;
|
|
187
|
+
const msg1 = this.tmp1;
|
|
188
|
+
const padded = zeroPad(cn, RATE);
|
|
189
|
+
blockFromBytes(msg0, padded);
|
|
190
|
+
blockFromBytes(msg1, padded, 16);
|
|
191
|
+
keystream128(this.st, this.z0, this.z1);
|
|
192
|
+
blockXor(msg0, msg0, this.z0);
|
|
193
|
+
blockXor(msg1, msg1, this.z1);
|
|
194
|
+
const pad = new Uint8Array(RATE);
|
|
195
|
+
blockToBytes(pad, msg0);
|
|
196
|
+
blockToBytes(pad, msg1, 16);
|
|
197
|
+
const xn = new Uint8Array(pad.subarray(0, cn.length));
|
|
198
|
+
pad.fill(0, cn.length);
|
|
199
|
+
blockFromBytes(msg0, pad);
|
|
200
|
+
blockFromBytes(msg1, pad, 16);
|
|
201
|
+
packConstantInput128(this.constantInput, msg0, msg1);
|
|
202
|
+
aegisRound128(this.st, this.constantInput);
|
|
224
203
|
return xn;
|
|
225
204
|
}
|
|
226
205
|
/**
|
|
227
206
|
* Finalizes encryption/decryption and produces an authentication tag.
|
|
228
|
-
* @param
|
|
229
|
-
* @param
|
|
207
|
+
* @param adLen - Associated data length in bytes
|
|
208
|
+
* @param msgLen - Message length in bytes
|
|
230
209
|
* @param tagLen - Tag length (16 or 32 bytes)
|
|
231
210
|
* @returns Authentication tag
|
|
232
211
|
*/
|
|
233
|
-
finalize(
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
212
|
+
finalize(adLen, msgLen, tagLen = 16) {
|
|
213
|
+
const st = this.st;
|
|
214
|
+
const tmp = this.tmp0;
|
|
215
|
+
tmp[0] = (adLen * 8) & 0xffffffff;
|
|
216
|
+
tmp[1] = Math.floor((adLen * 8) / 0x100000000);
|
|
217
|
+
tmp[2] = (msgLen * 8) & 0xffffffff;
|
|
218
|
+
tmp[3] = Math.floor((msgLen * 8) / 0x100000000);
|
|
219
|
+
const unpacked = createAesBlocks();
|
|
220
|
+
unpacked.set(st);
|
|
221
|
+
unpack(unpacked);
|
|
222
|
+
tmp[0] = tmp[0] ^ unpacked[wordIdx(2, 0)];
|
|
223
|
+
tmp[1] = tmp[1] ^ unpacked[wordIdx(2, 1)];
|
|
224
|
+
tmp[2] = tmp[2] ^ unpacked[wordIdx(2, 2)];
|
|
225
|
+
tmp[3] = tmp[3] ^ unpacked[wordIdx(2, 3)];
|
|
226
|
+
packConstantInput128(this.constantInput, tmp, tmp);
|
|
239
227
|
for (let i = 0; i < 7; i++) {
|
|
240
|
-
|
|
228
|
+
aegisRound128(st, this.constantInput);
|
|
241
229
|
}
|
|
230
|
+
unpack(st);
|
|
242
231
|
if (tagLen === 16) {
|
|
243
232
|
const tag = new Uint8Array(16);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
233
|
+
const tagBlock = createAesBlock();
|
|
234
|
+
for (let i = 0; i < 4; i++) {
|
|
235
|
+
tagBlock[i] =
|
|
236
|
+
st[wordIdx(0, i)] ^
|
|
237
|
+
st[wordIdx(1, i)] ^
|
|
238
|
+
st[wordIdx(2, i)] ^
|
|
239
|
+
st[wordIdx(3, i)] ^
|
|
240
|
+
st[wordIdx(4, i)] ^
|
|
241
|
+
st[wordIdx(5, i)] ^
|
|
242
|
+
st[wordIdx(6, i)];
|
|
253
243
|
}
|
|
244
|
+
blockToBytes(tag, tagBlock);
|
|
254
245
|
return tag;
|
|
255
246
|
}
|
|
256
247
|
else {
|
|
257
248
|
const tag = new Uint8Array(32);
|
|
258
|
-
|
|
259
|
-
|
|
249
|
+
const tagBlock0 = createAesBlock();
|
|
250
|
+
const tagBlock1 = createAesBlock();
|
|
251
|
+
for (let i = 0; i < 4; i++) {
|
|
252
|
+
tagBlock0[i] =
|
|
253
|
+
st[wordIdx(0, i)] ^
|
|
254
|
+
st[wordIdx(1, i)] ^
|
|
255
|
+
st[wordIdx(2, i)] ^
|
|
256
|
+
st[wordIdx(3, i)];
|
|
260
257
|
}
|
|
261
|
-
for (let i = 0; i <
|
|
262
|
-
|
|
258
|
+
for (let i = 0; i < 4; i++) {
|
|
259
|
+
tagBlock1[i] =
|
|
260
|
+
st[wordIdx(4, i)] ^
|
|
261
|
+
st[wordIdx(5, i)] ^
|
|
262
|
+
st[wordIdx(6, i)] ^
|
|
263
|
+
st[wordIdx(7, i)];
|
|
263
264
|
}
|
|
265
|
+
blockToBytes(tag, tagBlock0);
|
|
266
|
+
blockToBytes(tag, tagBlock1, 16);
|
|
264
267
|
return tag;
|
|
265
268
|
}
|
|
266
269
|
}
|
|
@@ -277,17 +280,21 @@ export class Aegis128LState {
|
|
|
277
280
|
export function aegis128LEncryptDetached(msg, ad, key, nonce, tagLen = 16) {
|
|
278
281
|
const state = new Aegis128LState();
|
|
279
282
|
state.init(key, nonce);
|
|
280
|
-
const adPadded = zeroPad(ad,
|
|
281
|
-
for (let i = 0; i +
|
|
282
|
-
state.absorb(adPadded
|
|
283
|
+
const adPadded = zeroPad(ad, RATE);
|
|
284
|
+
for (let i = 0; i + RATE <= adPadded.length; i += RATE) {
|
|
285
|
+
state.absorb(adPadded, i);
|
|
286
|
+
}
|
|
287
|
+
const ciphertext = new Uint8Array(msg.length);
|
|
288
|
+
const fullBlocks = Math.floor(msg.length / RATE) * RATE;
|
|
289
|
+
for (let i = 0; i < fullBlocks; i += RATE) {
|
|
290
|
+
state.encTo(msg, ciphertext, i, i);
|
|
283
291
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
292
|
+
if (msg.length > fullBlocks) {
|
|
293
|
+
const lastBlock = zeroPad(msg.subarray(fullBlocks), RATE);
|
|
294
|
+
const encBlock = state.enc(lastBlock);
|
|
295
|
+
ciphertext.set(encBlock.subarray(0, msg.length - fullBlocks), fullBlocks);
|
|
288
296
|
}
|
|
289
|
-
const tag = state.finalize(
|
|
290
|
-
const ciphertext = new Uint8Array(ct.subarray(0, msg.length));
|
|
297
|
+
const tag = state.finalize(ad.length, msg.length, tagLen);
|
|
291
298
|
return { ciphertext, tag };
|
|
292
299
|
}
|
|
293
300
|
/**
|
|
@@ -303,20 +310,19 @@ export function aegis128LDecryptDetached(ct, tag, ad, key, nonce) {
|
|
|
303
310
|
const tagLen = tag.length;
|
|
304
311
|
const state = new Aegis128LState();
|
|
305
312
|
state.init(key, nonce);
|
|
306
|
-
const adPadded = zeroPad(ad,
|
|
307
|
-
for (let i = 0; i +
|
|
308
|
-
state.absorb(adPadded
|
|
313
|
+
const adPadded = zeroPad(ad, RATE);
|
|
314
|
+
for (let i = 0; i + RATE <= adPadded.length; i += RATE) {
|
|
315
|
+
state.absorb(adPadded, i);
|
|
309
316
|
}
|
|
310
|
-
const
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
state.decTo(ct.subarray(i, i + 32), msg.subarray(i, i + 32));
|
|
317
|
+
const msg = new Uint8Array(ct.length);
|
|
318
|
+
const fullBlocks = Math.floor(ct.length / RATE) * RATE;
|
|
319
|
+
for (let i = 0; i < fullBlocks; i += RATE) {
|
|
320
|
+
state.decTo(ct, msg, i, i);
|
|
315
321
|
}
|
|
316
|
-
if (
|
|
317
|
-
msg.set(state.decPartial(
|
|
322
|
+
if (ct.length > fullBlocks) {
|
|
323
|
+
msg.set(state.decPartial(ct.subarray(fullBlocks)), fullBlocks);
|
|
318
324
|
}
|
|
319
|
-
const expectedTag = state.finalize(
|
|
325
|
+
const expectedTag = state.finalize(ad.length, msg.length, tagLen);
|
|
320
326
|
if (!constantTimeEqual(tag, expectedTag)) {
|
|
321
327
|
msg.fill(0);
|
|
322
328
|
return null;
|
|
@@ -336,22 +342,22 @@ export function aegis128LDecryptDetached(ct, tag, ad, key, nonce) {
|
|
|
336
342
|
export function aegis128LEncryptDetachedInPlace(data, ad, key, nonce, tagLen = 16) {
|
|
337
343
|
const state = new Aegis128LState();
|
|
338
344
|
state.init(key, nonce);
|
|
339
|
-
const adPadded = zeroPad(ad,
|
|
340
|
-
for (let i = 0; i +
|
|
341
|
-
state.absorb(adPadded
|
|
345
|
+
const adPadded = zeroPad(ad, RATE);
|
|
346
|
+
for (let i = 0; i + RATE <= adPadded.length; i += RATE) {
|
|
347
|
+
state.absorb(adPadded, i);
|
|
342
348
|
}
|
|
343
349
|
const msgLen = data.length;
|
|
344
|
-
const fullBlocksLen = Math.floor(msgLen /
|
|
345
|
-
for (let i = 0; i < fullBlocksLen; i +=
|
|
346
|
-
state.
|
|
350
|
+
const fullBlocksLen = Math.floor(msgLen / RATE) * RATE;
|
|
351
|
+
for (let i = 0; i < fullBlocksLen; i += RATE) {
|
|
352
|
+
state.encTo(data, data, i, i);
|
|
347
353
|
}
|
|
348
354
|
if (msgLen > fullBlocksLen) {
|
|
349
355
|
const lastPartial = data.subarray(fullBlocksLen);
|
|
350
|
-
const lastBlock = zeroPad(lastPartial,
|
|
356
|
+
const lastBlock = zeroPad(lastPartial, RATE);
|
|
351
357
|
const encBlock = state.enc(lastBlock);
|
|
352
358
|
lastPartial.set(encBlock.subarray(0, lastPartial.length));
|
|
353
359
|
}
|
|
354
|
-
return state.finalize(
|
|
360
|
+
return state.finalize(ad.length, msgLen, tagLen);
|
|
355
361
|
}
|
|
356
362
|
/**
|
|
357
363
|
* Decrypts a message in-place using AEGIS-128L (detached mode).
|
|
@@ -367,21 +373,21 @@ export function aegis128LDecryptDetachedInPlace(data, tag, ad, key, nonce) {
|
|
|
367
373
|
const tagLen = tag.length;
|
|
368
374
|
const state = new Aegis128LState();
|
|
369
375
|
state.init(key, nonce);
|
|
370
|
-
const adPadded = zeroPad(ad,
|
|
371
|
-
for (let i = 0; i +
|
|
372
|
-
state.absorb(adPadded
|
|
376
|
+
const adPadded = zeroPad(ad, RATE);
|
|
377
|
+
for (let i = 0; i + RATE <= adPadded.length; i += RATE) {
|
|
378
|
+
state.absorb(adPadded, i);
|
|
373
379
|
}
|
|
374
380
|
const msgLen = data.length;
|
|
375
|
-
const fullBlocksLen = Math.floor(msgLen /
|
|
376
|
-
for (let i = 0; i < fullBlocksLen; i +=
|
|
377
|
-
state.
|
|
381
|
+
const fullBlocksLen = Math.floor(msgLen / RATE) * RATE;
|
|
382
|
+
for (let i = 0; i < fullBlocksLen; i += RATE) {
|
|
383
|
+
state.decTo(data, data, i, i);
|
|
378
384
|
}
|
|
379
385
|
if (msgLen > fullBlocksLen) {
|
|
380
386
|
const lastPartial = data.subarray(fullBlocksLen);
|
|
381
387
|
const decrypted = state.decPartial(lastPartial);
|
|
382
388
|
lastPartial.set(decrypted);
|
|
383
389
|
}
|
|
384
|
-
const expectedTag = state.finalize(
|
|
390
|
+
const expectedTag = state.finalize(ad.length, msgLen, tagLen);
|
|
385
391
|
if (!constantTimeEqual(tag, expectedTag)) {
|
|
386
392
|
data.fill(0);
|
|
387
393
|
return false;
|
|
@@ -404,26 +410,11 @@ export const AEGIS_128L_KEY_SIZE = 16;
|
|
|
404
410
|
*/
|
|
405
411
|
export function aegis128LEncrypt(msg, ad, key, nonce = null, tagLen = 16) {
|
|
406
412
|
const actualNonce = nonce ?? randomBytes(AEGIS_128L_NONCE_SIZE);
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
const adPadded = zeroPad(ad, 32);
|
|
410
|
-
for (let i = 0; i + 32 <= adPadded.length; i += 32) {
|
|
411
|
-
state.absorb(adPadded.subarray(i, i + 32));
|
|
412
|
-
}
|
|
413
|
-
const nonceSize = AEGIS_128L_NONCE_SIZE;
|
|
414
|
-
const result = new Uint8Array(nonceSize + msg.length + tagLen);
|
|
413
|
+
const { ciphertext, tag } = aegis128LEncryptDetached(msg, ad, key, actualNonce, tagLen);
|
|
414
|
+
const result = new Uint8Array(AEGIS_128L_NONCE_SIZE + ciphertext.length + tagLen);
|
|
415
415
|
result.set(actualNonce, 0);
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
state.encTo(msg.subarray(i, i + 32), result.subarray(nonceSize + i, nonceSize + i + 32));
|
|
419
|
-
}
|
|
420
|
-
if (msg.length > fullBlocks) {
|
|
421
|
-
const lastBlock = zeroPad(msg.subarray(fullBlocks), 32);
|
|
422
|
-
const encBlock = state.enc(lastBlock);
|
|
423
|
-
result.set(encBlock.subarray(0, msg.length - fullBlocks), nonceSize + fullBlocks);
|
|
424
|
-
}
|
|
425
|
-
const tag = state.finalize(BigInt(ad.length * 8), BigInt(msg.length * 8), tagLen);
|
|
426
|
-
result.set(tag, nonceSize + msg.length);
|
|
416
|
+
result.set(ciphertext, AEGIS_128L_NONCE_SIZE);
|
|
417
|
+
result.set(tag, AEGIS_128L_NONCE_SIZE + ciphertext.length);
|
|
427
418
|
return result;
|
|
428
419
|
}
|
|
429
420
|
/**
|
|
@@ -456,11 +447,11 @@ export function aegis128LDecrypt(sealed, ad, key, tagLen = 16) {
|
|
|
456
447
|
export function aegis128LMac(data, key, nonce = null, tagLen = 16) {
|
|
457
448
|
const state = new Aegis128LState();
|
|
458
449
|
state.init(key, nonce ?? new Uint8Array(16));
|
|
459
|
-
const dataPadded = zeroPad(data,
|
|
460
|
-
for (let i = 0; i +
|
|
461
|
-
state.absorb(dataPadded
|
|
450
|
+
const dataPadded = zeroPad(data, RATE);
|
|
451
|
+
for (let i = 0; i + RATE <= dataPadded.length; i += RATE) {
|
|
452
|
+
state.absorb(dataPadded, i);
|
|
462
453
|
}
|
|
463
|
-
return state.finalize(
|
|
454
|
+
return state.finalize(data.length, tagLen, tagLen);
|
|
464
455
|
}
|
|
465
456
|
/**
|
|
466
457
|
* Verifies a MAC computed using AEGIS-128L.
|
|
@@ -491,4 +482,3 @@ export function aegis128LCreateKey() {
|
|
|
491
482
|
export function aegis128LCreateNonce() {
|
|
492
483
|
return randomBytes(AEGIS_128L_NONCE_SIZE);
|
|
493
484
|
}
|
|
494
|
-
//# sourceMappingURL=aegis128l.js.map
|