/src/ocudu/lib/security/s3g.cpp
Line | Count | Source |
1 | | // SPDX-FileCopyrightText: Copyright (C) 2021-2026 Software Radio Systems Limited |
2 | | // SPDX-FileCopyrightText: Copyright (C) 2026 OCUDU contributors |
3 | | // SPDX-License-Identifier: BSD-3-Clause-Open-MPI |
4 | | // Portions of this file may implement 3GPP specifications, which may be subject to additional licensing requirements. |
5 | | |
6 | | #include "ocudu/security/s3g.h" |
7 | | #include "s3g.h" |
8 | | |
9 | | using namespace ocudu; |
10 | | using namespace ocudu::security; |
11 | | |
12 | | /********************************************************************* |
13 | | Name: s3g_mul_x |
14 | | |
15 | | Description: Multiplication with reduction. |
16 | | |
17 | | Document Reference: Specification of the 3GPP Confidentiality and |
18 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
19 | | Section 3.1.1 |
20 | | *********************************************************************/ |
21 | | uint8_t s3g_mul_x(uint8_t v, uint8_t c); |
22 | | |
23 | | /********************************************************************* |
24 | | Name: s3g_mul_x_pow |
25 | | |
26 | | Description: Recursive multiplication with reduction. |
27 | | |
28 | | Document Reference: Specification of the 3GPP Confidentiality and |
29 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
30 | | Section 3.1.2 |
31 | | *********************************************************************/ |
32 | | uint8_t s3g_mul_x_pow(uint8_t v, uint8_t i, uint8_t c); |
33 | | |
34 | | /********************************************************************* |
35 | | Name: s3g_mul_alpha |
36 | | |
37 | | Description: Multiplication with alpha. |
38 | | |
39 | | Document Reference: Specification of the 3GPP Confidentiality and |
40 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
41 | | Section 3.4.2 |
42 | | *********************************************************************/ |
43 | | uint32_t s3g_mul_alpha(uint8_t c); |
44 | | |
45 | | /********************************************************************* |
46 | | Name: s3g_div_alpha |
47 | | |
48 | | Description: Division by alpha. |
49 | | |
50 | | Document Reference: Specification of the 3GPP Confidentiality and |
51 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
52 | | Section 3.4.3 |
53 | | *********************************************************************/ |
54 | | uint32_t s3g_div_alpha(uint8_t c); |
55 | | |
56 | | /********************************************************************* |
57 | | Name: s3g_s1 |
58 | | |
59 | | Description: S-Box S1. |
60 | | |
61 | | Document Reference: Specification of the 3GPP Confidentiality and |
62 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
63 | | Section 3.3.1 |
64 | | *********************************************************************/ |
65 | | uint32_t s3g_s1(uint32_t w); |
66 | | |
67 | | /********************************************************************* |
68 | | Name: s3g_s2 |
69 | | |
70 | | Description: S-Box S2. |
71 | | |
72 | | Document Reference: Specification of the 3GPP Confidentiality and |
73 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
74 | | Section 3.3.2 |
75 | | *********************************************************************/ |
76 | | uint32_t s3g_s2(uint32_t w); |
77 | | |
78 | | /********************************************************************* |
79 | | Name: s3g_clock_lfsr |
80 | | |
81 | | Description: Clocking LFSR. |
82 | | |
83 | | Document Reference: Specification of the 3GPP Confidentiality and |
84 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
85 | | Section 3.4.4 and Section 3.4.5 |
86 | | *********************************************************************/ |
87 | | void s3g_clock_lfsr(S3G_STATE* state, uint32_t f); |
88 | | |
89 | | /********************************************************************* |
90 | | Name: s3g_clock_fsm |
91 | | |
92 | | Description: Clocking FSM. |
93 | | |
94 | | Document Reference: Specification of the 3GPP Confidentiality and |
95 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
96 | | Section 3.4.6 |
97 | | *********************************************************************/ |
98 | | uint32_t s3g_clock_fsm(S3G_STATE* state); |
99 | | |
100 | | /********************************************************************* |
101 | | Name: s3g_deinitialize |
102 | | |
103 | | Description: Deinitialization. |
104 | | |
105 | | Document Reference: Specification of the 3GPP Confidentiality and |
106 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
107 | | *********************************************************************/ |
108 | | void ocudu::security::s3g_deinitialize(S3G_STATE* state); |
109 | | |
110 | | /********************************************************************* |
111 | | Name: s3g_generate_keystream |
112 | | |
113 | | Description: Generation of Keystream. |
114 | | |
115 | | Document Reference: Specification of the 3GPP Confidentiality and |
116 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
117 | | Section 4.2 |
118 | | *********************************************************************/ |
119 | | void ocudu::security::s3g_generate_keystream(S3G_STATE* state, uint32_t n, uint32_t* ks); |
120 | | |
121 | | /********************************************************************* |
122 | | Name: s3g_mul_x |
123 | | |
124 | | Description: Multiplication with reduction. |
125 | | |
126 | | Document Reference: Specification of the 3GPP Confidentiality and |
127 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
128 | | Section 3.1.1 |
129 | | *********************************************************************/ |
130 | | uint8_t s3g_mul_x(uint8_t v, uint8_t c) |
131 | 0 | { |
132 | 0 | if (v & 0x80) |
133 | 0 | return ((v << 1) ^ c); |
134 | 0 | else |
135 | 0 | return (v << 1); |
136 | 0 | } |
137 | | |
138 | | /********************************************************************* |
139 | | Name: s3g_mul_x_pow |
140 | | |
141 | | Description: Recursive multiplication with reduction. |
142 | | |
143 | | Document Reference: Specification of the 3GPP Confidentiality and |
144 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
145 | | Section 3.1.2 |
146 | | *********************************************************************/ |
147 | | uint8_t s3g_mul_x_pow(uint8_t v, uint8_t i, uint8_t c) |
148 | 0 | { |
149 | 0 | if (i == 0) |
150 | 0 | return v; |
151 | 0 | else |
152 | 0 | return s3g_mul_x(s3g_mul_x_pow(v, i - 1, c), c); |
153 | 0 | } |
154 | | |
155 | | /********************************************************************* |
156 | | Name: s3g_mul_alpha |
157 | | |
158 | | Description: Multiplication with alpha. |
159 | | |
160 | | Document Reference: Specification of the 3GPP Confidentiality and |
161 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
162 | | Section 3.4.2 |
163 | | *********************************************************************/ |
164 | | uint32_t s3g_mul_alpha(uint8_t c) |
165 | 0 | { |
166 | 0 | return MUL_ALPHA[c]; |
167 | 0 | } |
168 | | |
169 | | /********************************************************************* |
170 | | Name: s3g_div_alpha |
171 | | |
172 | | Description: Division by alpha. |
173 | | |
174 | | Document Reference: Specification of the 3GPP Confidentiality and |
175 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
176 | | Section 3.4.3 |
177 | | *********************************************************************/ |
178 | | uint32_t s3g_div_alpha(uint8_t c) |
179 | 0 | { |
180 | 0 | return DIV_ALPHA[c]; |
181 | 0 | } |
182 | | |
183 | | /********************************************************************* |
184 | | Name: s3g_s1 |
185 | | |
186 | | Description: S-Box S1. |
187 | | |
188 | | Document Reference: Specification of the 3GPP Confidentiality and |
189 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
190 | | Section 3.3.1 |
191 | | *********************************************************************/ |
192 | | uint32_t s3g_s1(uint32_t w) |
193 | 0 | { |
194 | 0 | return S1_T0[static_cast<uint8_t>(w & 0xff)] ^ S1_T1[static_cast<uint8_t>((w >> 8) & 0xff)] ^ |
195 | 0 | S1_T2[static_cast<uint8_t>((w >> 16) & 0xff)] ^ S1_T3[static_cast<uint8_t>((w >> 24) & 0xff)]; |
196 | 0 | } |
197 | | |
198 | | /********************************************************************* |
199 | | Name: s3g_s2 |
200 | | |
201 | | Description: S-Box S2. |
202 | | |
203 | | Document Reference: Specification of the 3GPP Confidentiality and |
204 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
205 | | Section 3.3.2 |
206 | | *********************************************************************/ |
207 | | uint32_t s3g_s2(uint32_t w) |
208 | 0 | { |
209 | 0 | return S2_T0[static_cast<uint8_t>(w & 0xff)] ^ S2_T1[static_cast<uint8_t>((w >> 8) & 0xff)] ^ |
210 | 0 | S2_T2[static_cast<uint8_t>((w >> 16) & 0xff)] ^ S2_T3[static_cast<uint8_t>((w >> 24) & 0xff)]; |
211 | 0 | } |
212 | | |
213 | | /********************************************************************* |
214 | | Name: s3g_clock_lfsr |
215 | | |
216 | | Description: Clocking LFSR. |
217 | | |
218 | | Document Reference: Specification of the 3GPP Confidentiality and |
219 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
220 | | Section 3.4.4 and Section 3.4.5 |
221 | | *********************************************************************/ |
222 | | void s3g_clock_lfsr(S3G_STATE* state, uint32_t f) |
223 | 0 | { |
224 | 0 | uint32_t v = (((state->lfsr[0] << 8) & 0xffffff00) ^ (s3g_mul_alpha((uint8_t)((state->lfsr[0] >> 24) & 0xff))) ^ |
225 | 0 | (state->lfsr[2]) ^ ((state->lfsr[11] >> 8) & 0x00ffffff) ^ |
226 | 0 | (s3g_div_alpha((uint8_t)((state->lfsr[11]) & 0xff))) ^ (f)); |
227 | 0 | uint8_t i; |
228 | |
|
229 | 0 | for (i = 0; i < 15; i++) { |
230 | 0 | state->lfsr[i] = state->lfsr[i + 1]; |
231 | 0 | } |
232 | 0 | state->lfsr[15] = v; |
233 | 0 | } |
234 | | |
235 | | /********************************************************************* |
236 | | Name: s3g_clock_fsm |
237 | | |
238 | | Description: Clocking FSM. |
239 | | |
240 | | Document Reference: Specification of the 3GPP Confidentiality and |
241 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
242 | | Section 3.4.6 |
243 | | *********************************************************************/ |
244 | | uint32_t s3g_clock_fsm(S3G_STATE* state) |
245 | 0 | { |
246 | 0 | uint32_t f = ((state->lfsr[15] + state->fsm[0]) & 0xffffffff) ^ state->fsm[1]; |
247 | 0 | uint32_t r = (state->fsm[1] + (state->fsm[2] ^ state->lfsr[5])) & 0xffffffff; |
248 | |
|
249 | 0 | state->fsm[2] = s3g_s2(state->fsm[1]); |
250 | 0 | state->fsm[1] = s3g_s1(state->fsm[0]); |
251 | 0 | state->fsm[0] = r; |
252 | |
|
253 | 0 | return f; |
254 | 0 | } |
255 | | |
256 | | /********************************************************************* |
257 | | Name: s3g_initialize |
258 | | |
259 | | Description: Initialization. |
260 | | |
261 | | Document Reference: Specification of the 3GPP Confidentiality and |
262 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
263 | | Section 4.1 |
264 | | *********************************************************************/ |
265 | | void ocudu::security::s3g_initialize(S3G_STATE* state, uint32_t k[4], uint32_t iv[4]) |
266 | 0 | { |
267 | 0 | uint8_t i = 0; |
268 | 0 | uint32_t f = 0x0; |
269 | |
|
270 | 0 | state->lfsr = (uint32_t*)calloc(16, sizeof(uint32_t)); |
271 | 0 | state->fsm = (uint32_t*)calloc(3, sizeof(uint32_t)); |
272 | |
|
273 | 0 | state->lfsr[15] = k[3] ^ iv[0]; |
274 | 0 | state->lfsr[14] = k[2]; |
275 | 0 | state->lfsr[13] = k[1]; |
276 | 0 | state->lfsr[12] = k[0] ^ iv[1]; |
277 | |
|
278 | 0 | state->lfsr[11] = k[3] ^ 0xffffffff; |
279 | 0 | state->lfsr[10] = k[2] ^ 0xffffffff ^ iv[2]; |
280 | 0 | state->lfsr[9] = k[1] ^ 0xffffffff ^ iv[3]; |
281 | 0 | state->lfsr[8] = k[0] ^ 0xffffffff; |
282 | 0 | state->lfsr[7] = k[3]; |
283 | 0 | state->lfsr[6] = k[2]; |
284 | 0 | state->lfsr[5] = k[1]; |
285 | 0 | state->lfsr[4] = k[0]; |
286 | 0 | state->lfsr[3] = k[3] ^ 0xffffffff; |
287 | 0 | state->lfsr[2] = k[2] ^ 0xffffffff; |
288 | 0 | state->lfsr[1] = k[1] ^ 0xffffffff; |
289 | 0 | state->lfsr[0] = k[0] ^ 0xffffffff; |
290 | |
|
291 | 0 | state->fsm[0] = 0x0; |
292 | 0 | state->fsm[1] = 0x0; |
293 | 0 | state->fsm[2] = 0x0; |
294 | 0 | for (i = 0; i < 32; i++) { |
295 | 0 | f = s3g_clock_fsm(state); |
296 | 0 | s3g_clock_lfsr(state, f); |
297 | 0 | } |
298 | 0 | } |
299 | | |
300 | | /********************************************************************* |
301 | | Name: s3g_deinitialize |
302 | | |
303 | | Description: Deinitialization. |
304 | | |
305 | | Document Reference: Specification of the 3GPP Confidentiality and |
306 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
307 | | *********************************************************************/ |
308 | | void ocudu::security::s3g_deinitialize(S3G_STATE* state) |
309 | 0 | { |
310 | 0 | free(state->lfsr); |
311 | 0 | free(state->fsm); |
312 | 0 | } |
313 | | |
314 | | /********************************************************************* |
315 | | Name: s3g_generate_keystream |
316 | | |
317 | | Description: Generation of Keystream. |
318 | | |
319 | | Document Reference: Specification of the 3GPP Confidentiality and |
320 | | Integrity Algorithms UEA2 & UIA2 D2 v1.1 |
321 | | Section 4.2 |
322 | | *********************************************************************/ |
323 | | void ocudu::security::s3g_generate_keystream(S3G_STATE* state, uint32_t n, uint32_t* ks) |
324 | 0 | { |
325 | 0 | uint32_t t = 0; |
326 | 0 | uint32_t f = 0x0; |
327 | | |
328 | | // Clock FSM once. Discard the output. |
329 | 0 | s3g_clock_fsm(state); |
330 | | // Clock LFSR in keystream mode once. |
331 | 0 | s3g_clock_lfsr(state, 0x0); |
332 | |
|
333 | 0 | for (t = 0; t < n; t++) { |
334 | 0 | f = s3g_clock_fsm(state); |
335 | | // Note that ks[t] corresponds to z_{t+1} in section 4.2 |
336 | 0 | ks[t] = f ^ state->lfsr[0]; |
337 | 0 | s3g_clock_lfsr(state, 0x0); |
338 | 0 | } |
339 | 0 | } |
340 | | |
341 | | /* MUL64x. |
342 | | * Input V: a 64-bit input. |
343 | | * Input c: a 64-bit input. |
344 | | * Output : a 64-bit output. |
345 | | * A 64-bit memory is allocated which is to be freed by the calling |
346 | | * function. |
347 | | * See section 4.3.2 for details. |
348 | | */ |
349 | | static uint64_t s3g_MUL64x(uint64_t V, uint64_t c) |
350 | 0 | { |
351 | 0 | if (V & 0x8000000000000000) |
352 | 0 | return (V << 1) ^ c; |
353 | 0 | else |
354 | 0 | return V << 1; |
355 | 0 | } |
356 | | |
357 | | /* MUL64xPOW. |
358 | | * Input V: a 64-bit input. |
359 | | * Input i: a positive integer. |
360 | | * Input c: a 64-bit input. |
361 | | * Output : a 64-bit output. |
362 | | * A 64-bit memory is allocated which is to be freed by the calling function. |
363 | | * See section 4.3.3 for details. |
364 | | */ |
365 | | static uint64_t s3g_MUL64xPOW(uint64_t V, uint8_t i, uint64_t c) |
366 | 0 | { |
367 | 0 | if (i == 0) |
368 | 0 | return V; |
369 | 0 | else |
370 | 0 | return s3g_MUL64x(s3g_MUL64xPOW(V, i - 1, c), c); |
371 | 0 | } |
372 | | |
373 | | /* MUL64. |
374 | | * Input V: a 64-bit input. |
375 | | * Input P: a 64-bit input. |
376 | | * Input c: a 64-bit input. |
377 | | * Output : a 64-bit output. |
378 | | * A 64-bit memory is allocated which is to be freed by the calling |
379 | | * function. |
380 | | * See section 4.3.4 for details. |
381 | | */ |
382 | | static uint64_t s3g_MUL64(uint64_t V, uint64_t P, uint64_t c) |
383 | 0 | { |
384 | 0 | uint64_t result = 0; |
385 | 0 | int i = 0; |
386 | |
|
387 | 0 | for (i = 0; i < 64; i++) { |
388 | 0 | if ((P >> i) & 0x1) |
389 | 0 | result ^= s3g_MUL64xPOW(V, i, c); |
390 | 0 | } |
391 | 0 | return result; |
392 | 0 | } |
393 | | |
394 | | /// \brief Initializes the lookup tables for the MUL operation. |
395 | | /// \param[out] PM lookup tables to be generated. |
396 | | /// \param[in] P a 64-bit input. |
397 | | /// \param[in] c a 64-bit input. |
398 | | /// Implemented as specified in "Specification of the 3GPP Confidentiality and Integrity Algorithms UEA2 & UIA2 D1 v2.1" |
399 | | /// Annex 2. |
400 | | static void s3g_PRE_MUL_P(std::array<std::array<uint64_t, 256>, 8>& PM, uint64_t P, uint64_t c) |
401 | 0 | { |
402 | 0 | for (uint8_t i = 0; i != 8; ++i) { |
403 | 0 | PM[i][0] = 0; |
404 | 0 | } |
405 | 0 | PM[0][1] = P; |
406 | |
|
407 | 0 | for (uint8_t i = 1; i != 64; ++i) { |
408 | 0 | uint64_t a = PM[(i - 1) >> 3][1 << ((i - 1) & 0x7)]; |
409 | 0 | PM[i >> 3][1 << (i & 0x7)] = a << 1; |
410 | | // If the leftmost bit... |
411 | 0 | static constexpr uint64_t leftmost_bit_mask = 1UL << 63UL; |
412 | 0 | if (a & leftmost_bit_mask) { |
413 | 0 | PM[i >> 3][1 << (i & 0x7)] ^= c; |
414 | 0 | } |
415 | 0 | } |
416 | |
|
417 | 0 | for (uint8_t i = 0; i != 8; ++i) { |
418 | 0 | for (uint8_t j = 1; j != 8; ++j) { |
419 | 0 | for (uint8_t k = 1, k_end = (1 << j); k != k_end; ++k) { |
420 | 0 | PM[i][(1 << j) + k] = PM[i][1 << j] ^ PM[i][k]; |
421 | 0 | } |
422 | 0 | } |
423 | 0 | } |
424 | 0 | } |
425 | | |
426 | | /// \brief Performs the MUL operation using the precomputed lookup tables. |
427 | | /// \param[in] PM lookup tables to be generated. |
428 | | /// \param[in] X a 64-bit input. |
429 | | /// \returns the result of the MUL operation. |
430 | | /// Implemented as specified in "Specification of the 3GPP Confidentiality and Integrity Algorithms UEA2 & UIA2 D1 v2.1" |
431 | | /// Annex 2. |
432 | | static uint64_t s3g_MUL_P(const std::array<std::array<uint64_t, 256>, 8>& PM, uint64_t X) |
433 | 0 | { |
434 | 0 | return PM[0][X & 0xff] ^ PM[1][(X >> 8) & 0xff] ^ PM[2][(X >> 16) & 0xff] ^ PM[3][(X >> 24) & 0xff] ^ |
435 | 0 | PM[4][(X >> 32) & 0xff] ^ PM[5][(X >> 40) & 0xff] ^ PM[6][(X >> 48) & 0xff] ^ PM[7][(X >> 56) & 0xff]; |
436 | 0 | } |
437 | | |
438 | | /* mask8bit. |
439 | | * Input n: an integer in 1-7. |
440 | | * Output : an 8 bit mask. |
441 | | * Prepares an 8 bit mask with required number of 1 bits on the MSB side. |
442 | | */ |
443 | | static uint8_t mask8bit(int n) |
444 | 0 | { |
445 | 0 | return 0xff ^ ((1 << (8 - n)) - 1); |
446 | 0 | } |
447 | | |
448 | | /* f9. |
449 | | * Input key: 128 bit Integrity Key. |
450 | | * Input count:32-bit Count, Frame dependent input. |
451 | | * Input fresh: 32-bit Random number. |
452 | | * Input dir:1 bit, direction of transmission (in the LSB). |
453 | | * Input data: length number of bits, input bit stream. |
454 | | * Input length: 64 bit Length, i.e., the number of bits to be MAC'd. |
455 | | * Output : 32 bit block used as MAC |
456 | | * Generates 32-bit MAC using UIA2 algorithm as defined in Section 4. |
457 | | */ |
458 | | void ocudu::security::s3g_f9(ocudu::security::sec_mac& mac, |
459 | | const uint8_t* key, |
460 | | uint32_t count, |
461 | | uint32_t fresh, |
462 | | uint32_t dir, |
463 | | uint8_t* data, |
464 | | uint64_t length) |
465 | 0 | { |
466 | 0 | uint32_t K[4], IV[4], z[5]; |
467 | 0 | uint32_t i = 0, D; |
468 | 0 | uint64_t EVAL; |
469 | 0 | uint64_t V; |
470 | 0 | uint64_t P; |
471 | 0 | uint64_t Q; |
472 | 0 | uint64_t c; |
473 | 0 | S3G_STATE state, *state_ptr; |
474 | |
|
475 | 0 | uint64_t M_D_2; |
476 | 0 | int rem_bits = 0; |
477 | 0 | state_ptr = &state; |
478 | | /* Load the Integrity Key for SNOW3G initialization as in section 4.4. */ |
479 | 0 | for (i = 0; i < 4; i++) |
480 | 0 | K[3 - i] = (key[4 * i] << 24) ^ (key[4 * i + 1] << 16) ^ (key[4 * i + 2] << 8) ^ (key[4 * i + 3]); |
481 | | |
482 | | /* Prepare the Initialization Vector (IV) for SNOW3G initialization as |
483 | | in section 4.4. */ |
484 | 0 | IV[3] = count; |
485 | 0 | IV[2] = fresh; |
486 | 0 | IV[1] = count ^ (dir << 31); |
487 | 0 | IV[0] = fresh ^ (dir << 15); |
488 | |
|
489 | 0 | z[0] = z[1] = z[2] = z[3] = z[4] = 0; |
490 | | |
491 | | /* Run SNOW 3G to produce 5 keystream words z_1, z_2, z_3, z_4 and z_5. */ |
492 | 0 | s3g_initialize(state_ptr, K, IV); |
493 | 0 | s3g_generate_keystream(state_ptr, 5, z); |
494 | 0 | s3g_deinitialize(state_ptr); |
495 | 0 | P = (uint64_t)z[0] << 32 | (uint64_t)z[1]; |
496 | 0 | Q = (uint64_t)z[2] << 32 | (uint64_t)z[3]; |
497 | | |
498 | | /* Calculation */ |
499 | 0 | if ((length % 64) == 0) |
500 | 0 | D = (length >> 6) + 1; |
501 | 0 | else |
502 | 0 | D = (length >> 6) + 2; |
503 | 0 | EVAL = 0; |
504 | 0 | c = 0x1b; |
505 | | // Compute the lookup tables for the MUL operation. |
506 | 0 | std::array<std::array<uint64_t, 256>, 8> PM; |
507 | 0 | s3g_PRE_MUL_P(PM, P, c); |
508 | | |
509 | | /* for 0 <= i <= D-3 */ |
510 | 0 | for (i = 0; i < D - 2; i++) { |
511 | 0 | V = EVAL ^ ((uint64_t)data[8 * i] << 56 | (uint64_t)data[8 * i + 1] << 48 | (uint64_t)data[8 * i + 2] << 40 | |
512 | 0 | (uint64_t)data[8 * i + 3] << 32 | (uint64_t)data[8 * i + 4] << 24 | (uint64_t)data[8 * i + 5] << 16 | |
513 | 0 | (uint64_t)data[8 * i + 6] << 8 | (uint64_t)data[8 * i + 7]); |
514 | 0 | EVAL = s3g_MUL_P(PM, V); |
515 | 0 | } |
516 | | |
517 | | /* for D-2 */ |
518 | 0 | rem_bits = length % 64; |
519 | 0 | if (rem_bits == 0) |
520 | 0 | rem_bits = 64; |
521 | |
|
522 | 0 | M_D_2 = 0; |
523 | 0 | i = 0; |
524 | 0 | while (rem_bits > 7) { |
525 | 0 | M_D_2 |= (uint64_t)data[8 * (D - 2) + i] << (8 * (7 - i)); |
526 | 0 | rem_bits -= 8; |
527 | 0 | i++; |
528 | 0 | } |
529 | 0 | if (rem_bits > 0) |
530 | 0 | M_D_2 |= (uint64_t)(data[8 * (D - 2) + i] & mask8bit(rem_bits)) << (8 * (7 - i)); |
531 | |
|
532 | 0 | V = EVAL ^ M_D_2; |
533 | 0 | EVAL = s3g_MUL_P(PM, V); |
534 | | |
535 | | /* for D-1 */ |
536 | 0 | EVAL ^= length; |
537 | | |
538 | | /* Multiply by Q */ |
539 | | // Note: s3g_MUL_P is not used here because the lookup tables were generated for P, not Q. |
540 | 0 | EVAL = s3g_MUL64(EVAL, Q, c); |
541 | | |
542 | | /* XOR with z_5: this is a modification to the reference C code, |
543 | | which forgot to XOR z[5] */ |
544 | 0 | for (i = 0; i < 4; i++) { |
545 | | /* |
546 | | MAC_I[i] = (mac32 >> (8*(3-i))) & 0xff; |
547 | | */ |
548 | 0 | mac[i] = ((EVAL >> (56 - (i * 8))) ^ (z[4] >> (24 - (i * 8)))) & 0xff; |
549 | 0 | } |
550 | 0 | } |