Coverage Report

Created: 2026-09-14 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ocudu/include/ocudu/security/ciphering.h
Line
Count
Source
1
// SPDX-FileCopyrightText: Copyright (C) 2021-2026 Software Radio Systems Limited
2
// SPDX-License-Identifier: BSD-3-Clause-Open-MPI
3
// Portions of this file may implement 3GPP specifications, which may be subject to additional licensing requirements.
4
5
#pragma once
6
7
#include "ocudu/adt/byte_buffer.h"
8
#include "ocudu/security/s3g.h"
9
#include "ocudu/security/security.h"
10
#include "ocudu/security/ssl.h"
11
#include "ocudu/security/zuc.h"
12
13
namespace ocudu {
14
namespace security {
15
16
/******************************************************************************
17
 * Encryption / Decryption
18
 *****************************************************************************/
19
inline void security_nea1(const sec_128_key& key,
20
                          uint32_t           count,
21
                          uint8_t            bearer,
22
                          security_direction direction,
23
                          byte_buffer_view&  msg,
24
                          uint32_t           msg_len)
25
0
{
26
0
  S3G_STATE state, *state_ptr;
27
0
  uint32_t  k[]  = {0, 0, 0, 0};
28
0
  uint32_t  iv[] = {0, 0, 0, 0};
29
0
  uint32_t* ks;
30
0
  int32_t   i;
31
0
  uint32_t  msg_len_block_8, msg_len_block_32;
32
0
  uint32_t  len = msg.length();
33
34
0
  state_ptr        = &state;
35
0
  msg_len_block_8  = (msg_len + 7) / 8;
36
0
  msg_len_block_32 = (msg_len + 31) / 32;
37
0
  if (msg_len_block_8 <= len && len > 0) {
38
    // Transform key
39
0
    for (i = 3; i >= 0; i--) {
40
0
      k[i] = (key[4 * (3 - i) + 0] << 24) | (key[4 * (3 - i) + 1] << 16) | (key[4 * (3 - i) + 2] << 8) |
41
0
             (key[4 * (3 - i) + 3]);
42
0
    }
43
44
    // Construct iv
45
0
    iv[3] = count;
46
0
    iv[2] = ((bearer & 0x1f) << 27) | ((static_cast<uint8_t>(direction) & 0x01) << 26);
47
0
    iv[1] = iv[3];
48
0
    iv[0] = iv[2];
49
50
    // Initialize keystream
51
0
    s3g_initialize(state_ptr, k, iv);
52
53
    // Generate keystream
54
0
    ks = (uint32_t*)calloc(msg_len_block_32, sizeof(uint32_t));
55
0
    s3g_generate_keystream(state_ptr, msg_len_block_32, ks);
56
57
    // Generate output except last block
58
0
    uint32_t offset = 0;
59
0
    for (i = 0; i < (int32_t)msg_len_block_32 - 1; i++) {
60
0
      msg[offset]     = msg[offset] ^ ((ks[i] >> 24) & 0xff);
61
0
      msg[offset + 1] = msg[offset + 1] ^ ((ks[i] >> 16) & 0xff);
62
0
      msg[offset + 2] = msg[offset + 2] ^ ((ks[i] >> 8) & 0xff);
63
0
      msg[offset + 3] = msg[offset + 3] ^ ((ks[i]) & 0xff);
64
0
      offset += 4;
65
0
    }
66
67
    // process last bytes
68
0
    for (i = (msg_len_block_32 - 1) * 4; i < (int32_t)msg_len_block_8; i++) {
69
0
      msg[offset] = msg[offset] ^ ((ks[i / 4] >> ((3 - (i % 4)) * 8)) & 0xff);
70
0
      offset++;
71
0
    }
72
73
    // Zero tailing bits
74
0
    zero_tailing_bits(msg[offset - 1], msg_len);
75
76
    // Clean up
77
0
    free(ks);
78
0
    s3g_deinitialize(state_ptr);
79
0
  }
80
0
}
81
82
inline void security_nea1(const sec_128_key& key,
83
                          uint32_t           count,
84
                          uint8_t            bearer,
85
                          security_direction direction,
86
                          byte_buffer_view&  msg)
87
0
{
88
0
  return security_nea1(key, count, bearer, direction, msg, msg.length() * 8);
89
0
}
90
91
#if OCUDU_MBEDTLS_PSA
92
inline void security_nea2_psa(const sec_128_key& key,
93
                              uint32_t           count,
94
                              uint8_t            bearer,
95
                              security_direction direction,
96
                              byte_buffer_view&  msg,
97
                              uint32_t           msg_len)
98
{
99
  aes_context   ctx;
100
  unsigned char nonce_cnt[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
101
  int           ret;
102
103
  uint32_t msg_len_block_8 = (msg_len + 7) / 8;
104
  uint32_t len             = msg.length();
105
106
  ret = crypto_init();
107
  if (ret != 0) {
108
    report_error("Failure in initializing crypto PSA");
109
    return;
110
  }
111
112
  ret = aes_setkey_enc(&ctx, key.data(), 128);
113
  if (ret != 0) {
114
    return;
115
  }
116
117
  if (msg_len_block_8 <= len && len > 0) {
118
    if (ret == 0) {
119
      // Construct nonce
120
      nonce_cnt[0] = (count >> 24) & 0xff;
121
      nonce_cnt[1] = (count >> 16) & 0xff;
122
      nonce_cnt[2] = (count >> 8) & 0xff;
123
      nonce_cnt[3] = (count) & 0xff;
124
      nonce_cnt[4] = ((bearer & 0x1f) << 3) | ((to_number(direction) & 0x01) << 2);
125
126
      // Encryption.
127
      psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
128
      psa_status_t           status    = psa_cipher_encrypt_setup(&operation, ctx.ctr_key_id, PSA_ALG_CTR);
129
      if (status != PSA_SUCCESS) {
130
        return;
131
      }
132
      status = psa_cipher_set_iv(&operation, nonce_cnt, sizeof(nonce_cnt));
133
      if (status != PSA_SUCCESS) {
134
        psa_cipher_abort(&operation);
135
        return;
136
      }
137
138
      byte_buffer_segment_span_range segments = msg.modifiable_segments();
139
      for (const auto& segment : segments) {
140
        size_t output_len = 0;
141
        status =
142
            psa_cipher_update(&operation, segment.data(), segment.size(), segment.data(), segment.size(), &output_len);
143
        if (status != PSA_SUCCESS || output_len != segment.size()) {
144
          psa_cipher_abort(&operation);
145
          return;
146
        }
147
      }
148
149
      unsigned char output[16];
150
      size_t        output_len = 0;
151
152
      status = psa_cipher_finish(&operation, output, sizeof(output), &output_len);
153
154
      if (status != PSA_SUCCESS || output_len != 0) {
155
        return;
156
      }
157
    }
158
  }
159
  if (ret == 0) {
160
    //  Zero tailing bits
161
    zero_tailing_bits(msg[msg.length() - 1], msg_len);
162
  }
163
}
164
#else
165
inline void security_nea2_v3(const sec_128_key& key,
166
                             uint32_t           count,
167
                             uint8_t            bearer,
168
                             security_direction direction,
169
                             byte_buffer_view&  msg,
170
                             uint32_t           msg_len)
171
0
{
172
0
  aes_context   ctx;
173
0
  unsigned char stream_blk[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
174
0
  unsigned char nonce_cnt[16]  = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
175
0
  int           ret;
176
0
  size_t        nc_off = 0;
177
0
178
0
  uint32_t msg_len_block_8 = (msg_len + 7) / 8;
179
0
  uint32_t len             = msg.length();
180
0
181
0
  ret = crypto_init();
182
0
  if (ret != 0) {
183
0
    report_error("Failure in initializing crypto");
184
0
    return;
185
0
  }
186
0
187
0
  ret = aes_setkey_enc(&ctx, key.data(), 128);
188
0
  if (ret != 0) {
189
0
    return;
190
0
  }
191
0
192
0
  if (msg_len_block_8 <= len && len > 0) {
193
0
    if (ret == 0) {
194
0
      // Construct nonce
195
0
      nonce_cnt[0] = (count >> 24) & 0xff;
196
0
      nonce_cnt[1] = (count >> 16) & 0xff;
197
0
      nonce_cnt[2] = (count >> 8) & 0xff;
198
0
      nonce_cnt[3] = (count) & 0xff;
199
0
      nonce_cnt[4] = ((bearer & 0x1f) << 3) | ((to_number(direction) & 0x01) << 2);
200
0
201
0
      // Encryption
202
0
      byte_buffer_segment_span_range segments = msg.modifiable_segments();
203
0
      for (const auto& segment : segments) {
204
0
        ret =
205
0
            mbedtls_aes_crypt_ctr(&ctx, segment.size(), &nc_off, nonce_cnt, stream_blk, segment.data(), segment.data());
206
0
      }
207
0
    }
208
0
  }
209
0
  if (ret == 0) {
210
0
    //  Zero tailing bits
211
0
    zero_tailing_bits(msg[msg.length() - 1], msg_len);
212
0
  }
213
0
}
214
#endif
215
216
inline void security_nea2(const sec_128_key& key,
217
                          uint32_t           count,
218
                          uint8_t            bearer,
219
                          security_direction direction,
220
                          byte_buffer_view&  msg)
221
0
{
222
0
#if OCUDU_MBEDTLS_PSA
223
0
  security_nea2_psa(key, count, bearer, direction, msg, msg.length() * 8);
224
0
#else
225
0
  security_nea2_v3(key, count, bearer, direction, msg, msg.length() * 8);
226
0
#endif
227
0
}
228
229
inline void security_nea2(const sec_128_key& key,
230
                          uint32_t           count,
231
                          uint8_t            bearer,
232
                          security_direction direction,
233
                          byte_buffer_view&  msg,
234
                          uint32_t           msg_len)
235
0
{
236
0
#if OCUDU_MBEDTLS_PSA
237
0
  security_nea2_psa(key, count, bearer, direction, msg, msg_len);
238
0
#else
239
0
  security_nea2_v3(key, count, bearer, direction, msg, msg_len);
240
0
#endif
241
0
}
242
243
inline void security_nea3(const sec_128_key& key,
244
                          uint32_t           count,
245
                          uint8_t            bearer,
246
                          security_direction direction,
247
                          byte_buffer_view&  msg,
248
                          uint32_t           msg_len)
249
0
{
250
0
  uint8_t iv[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
251
252
0
  uint32_t* ks;
253
0
  int32_t   i;
254
0
  uint32_t  msg_len_block_8;
255
0
  uint32_t  msg_len_block_32;
256
0
  uint32_t  len = msg.length();
257
258
0
  msg_len_block_8  = (msg_len + 7) / 8;
259
0
  msg_len_block_32 = (msg_len + 31) / 32;
260
0
  if (msg_len_block_8 <= len && len > 0) {
261
    // Construct iv
262
0
    iv[0]  = (count >> 24) & 0xff;
263
0
    iv[1]  = (count >> 16) & 0xff;
264
0
    iv[2]  = (count >> 8) & 0xff;
265
0
    iv[3]  = (count) & 0xff;
266
0
    iv[4]  = ((bearer & 0x1f) << 3) | ((to_number(direction) & 0x01) << 2);
267
0
    iv[5]  = 0;
268
0
    iv[6]  = 0;
269
0
    iv[7]  = 0;
270
0
    iv[8]  = iv[0];
271
0
    iv[9]  = iv[1];
272
0
    iv[10] = iv[2];
273
0
    iv[11] = iv[3];
274
0
    iv[12] = iv[4];
275
0
    iv[13] = iv[5];
276
0
    iv[14] = iv[6];
277
0
    iv[15] = iv[7];
278
279
0
    zuc_state_t zuc_state;
280
    // Initialize keystream
281
0
    zuc_initialize(&zuc_state, key.data(), iv);
282
283
    // Generate keystream
284
285
0
    ks = (uint32_t*)calloc(msg_len_block_32, sizeof(uint32_t));
286
0
    zuc_generate_keystream(&zuc_state, msg_len_block_32, ks);
287
288
    // Generate output except last block
289
0
    uint32_t offset = 0;
290
0
    for (i = 0; i < (int32_t)msg_len_block_32 - 1; i++) {
291
0
      msg[offset]     = msg[offset] ^ ((ks[i] >> 24) & 0xff);
292
0
      msg[offset + 1] = msg[offset + 1] ^ ((ks[i] >> 16) & 0xff);
293
0
      msg[offset + 2] = msg[offset + 2] ^ ((ks[i] >> 8) & 0xff);
294
0
      msg[offset + 3] = msg[offset + 3] ^ ((ks[i]) & 0xff);
295
0
      offset += 4;
296
0
    }
297
298
    // process last bytes
299
0
    for (i = (msg_len_block_32 - 1) * 4; i < (int32_t)msg_len_block_8; i++) {
300
0
      msg[offset] = msg[offset] ^ ((ks[i / 4] >> ((3 - (i % 4)) * 8)) & 0xff);
301
0
      offset++;
302
0
    }
303
304
0
    zero_tailing_bits(msg[msg.length() - 1], msg_len);
305
306
    // Clean up
307
0
    free(ks);
308
0
  }
309
0
}
310
311
inline void security_nea3(const sec_128_key& key,
312
                          uint32_t           count,
313
                          uint8_t            bearer,
314
                          security_direction direction,
315
                          byte_buffer_view&  msg)
316
0
{
317
0
  security_nea3(key, count, bearer, direction, msg, msg.length() * 8);
318
0
}
319
320
} // namespace security
321
} // namespace ocudu