Coverage Report

Created: 2026-10-28 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}