osa_stream_eea.c 7.06 KB
Newer Older
nikaeinn's avatar
nikaeinn committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*******************************************************************************
    OpenAirInterface
    Copyright(c) 1999 - 2014 Eurecom

    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.


    OpenAirInterface is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with OpenAirInterface.The full GNU General Public License is
    included in this distribution in the file called "COPYING". If not,
    see <http://www.gnu.org/licenses/>.

  Contact Information
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
24
  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
nikaeinn's avatar
nikaeinn committed
25

ghaddab's avatar
ghaddab committed
26
  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
nikaeinn's avatar
nikaeinn committed
27
28
29

*******************************************************************************/

30
31
32
33
34
35
36
37
38
39
40
41
42
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#include <nettle/nettle-meta.h>
#include <nettle/aes.h>
#include <nettle/ctr.h>

#include "UTIL/LOG/log.h"

#include "assertions.h"
#include "osa_defs.h"
gauthier's avatar
   
gauthier committed
43
#include "osa_snow3g.h"
44
45
#include "osa_internal.h"

46
47
int stream_encrypt_eea0(stream_cipher_t *stream_cipher, uint8_t **out)
{
48
  uint8_t *data = NULL;
49

50
  uint32_t byte_length;
51

52
53
  DevAssert(stream_cipher != NULL);
  DevAssert(out != NULL);
54

55
56
57
58
  LOG_D(OSA, "Entering stream_encrypt_eea0, bits length %u, bearer %u, "
        "count %u, direction %s\n", stream_cipher->blength,
        stream_cipher->bearer, stream_cipher->count, stream_cipher->direction == SECU_DIRECTION_DOWNLINK ?
        "Downlink" : "Uplink");
59

60
  byte_length = (stream_cipher->blength + 7) >> 3;
61

62
63
64
65
66
67
68
  if (*out == NULL) {
    /* User did not provide output buffer */
    data = malloc(byte_length);
    *out = data;
  } else {
    data = *out;
  }
69

70
  memcpy (data, stream_cipher->message, byte_length);
71

72
  return 0;
73
74
}

gauthier's avatar
   
gauthier committed
75
76
int stream_encrypt_eea1(stream_cipher_t *stream_cipher, uint8_t **out)
{
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  osa_snow_3g_context_t snow_3g_context;
  int       n ;
  int       i           = 0;
  uint32_t  zero_bit    = 0;
  uint32_t *KS;
  uint32_t  K[4],IV[4];

  DevAssert(stream_cipher != NULL);
  DevAssert(stream_cipher->key != NULL);
  DevAssert(stream_cipher->key_length == 16);
  DevAssert(out != NULL);

  n = ( stream_cipher->blength + 31 ) / 32;
  zero_bit = stream_cipher->blength & 0x7;

  memset(&snow_3g_context, 0, sizeof(snow_3g_context));
  /*Initialisation*/
  /* Load the confidentiality key for SNOW 3G initialization as in section
  3.4. */
  memcpy(K+3,stream_cipher->key+0,4); /*K[3] = key[0]; we assume
  K[3]=key[0]||key[1]||...||key[31] , with key[0] the
  * most important bit of key*/
  memcpy(K+2,stream_cipher->key+4,4); /*K[2] = key[1];*/
  memcpy(K+1,stream_cipher->key+8,4); /*K[1] = key[2];*/
  memcpy(K+0,stream_cipher->key+12,4); /*K[0] = key[3]; we assume
  K[0]=key[96]||key[97]||...||key[127] , with key[127] the
  * least important bit of key*/
  K[3] = hton_int32(K[3]);
  K[2] = hton_int32(K[2]);
  K[1] = hton_int32(K[1]);
  K[0] = hton_int32(K[0]);
  /* Prepare the initialization vector (IV) for SNOW 3G initialization as in
  section 3.4. */
  IV[3] = stream_cipher->count;
  IV[2] = ((((uint32_t)stream_cipher->bearer) << 3) | ((((uint32_t)stream_cipher->direction) & 0x1) << 2)) << 24;
  IV[1] = IV[3];
  IV[0] = IV[2];

  /* Run SNOW 3G algorithm to generate sequence of key stream bits KS*/
  osa_snow3g_initialize(K, IV, &snow_3g_context);
  KS = (uint32_t *)malloc(4*n);
  osa_snow3g_generate_key_stream(n,(uint32_t*)KS, &snow_3g_context);

  if (zero_bit > 0) {

    KS[n - 1] = KS[n - 1] & (uint32_t)(0xFFFFFFFF << (8 - zero_bit));
  }

  for (i=0; i<n; i++) {
    KS[i] = hton_int32(KS[i]);
  }

  /* Exclusive-OR the input data with keystream to generate the output bit
  stream */
  for (i=0; i<n*4; i++) {
    stream_cipher->message[i] ^= *(((uint8_t*)KS)+i);
  }

  if (zero_bit > 0) {
    int ceil_index = (stream_cipher->blength+7) >> 3;
    stream_cipher->message[ceil_index - 1] = stream_cipher->message[ceil_index - 1] & (uint8_t)(0xFF << (8 - zero_bit));
  }

  free(KS);
  *out = stream_cipher->message;
  return 0;
gauthier's avatar
   
gauthier committed
143
144
}

145
146
int stream_encrypt_eea2(stream_cipher_t *stream_cipher, uint8_t **out)
{
147
148
  uint8_t m[16];
  uint32_t local_count;
149

150
151
  void *ctx;
  uint8_t *data = NULL;
152

153
154
  uint32_t zero_bit = 0;
  uint32_t byte_length;
155

156
157
  DevAssert(stream_cipher != NULL);
  DevAssert(out != NULL);
158

159
160
161
162
  LOG_D(OSA, "Entering stream_encrypt_eea2, bits length %u, bearer %u, "
        "count %u, direction %s\n", stream_cipher->blength,
        stream_cipher->bearer, stream_cipher->count, stream_cipher->direction == SECU_DIRECTION_DOWNLINK ?
        "Downlink" : "Uplink");
163

164
  zero_bit = stream_cipher->blength & 0x7;
165

166
  byte_length = stream_cipher->blength >> 3;
167

168
169
  if (zero_bit > 0)
    byte_length += 1;
170

171
  ctx = malloc(nettle_aes128.context_size);
172

173
174
175
176
177
178
179
  if (*out == NULL) {
    /* User provided output buffer */
    data = malloc(byte_length);
    *out = data;
  } else {
    data = *out;
  }
180

181
182
183
184
185
186
187
  local_count = hton_int32(stream_cipher->count);

  memset(m, 0, sizeof(m));
  memcpy(&m[0], &local_count, 4);
  m[4] = ((stream_cipher->bearer & 0x1F) << 3) |
         ((stream_cipher->direction & 0x01) << 2);
  /* Other bits are 0 */
188
189

#if defined(SECU_DEBUG)
190
191
192
193
194
195
196
197
198
199
  {
    int i;
    char payload[6 * byte_length + 1];
    int  index = 0;

    for (i = 0; i < byte_length; i++)
      index += sprintf(&payload[index], "0x%02x ", stream_cipher->message[i]);

    LOG_D(OSA, "Original message: %s\n", payload);
  }
200
201
#endif

202
203
204
205
#if NETTLE_VERSION <= 27
  nettle_aes128.set_encrypt_key(ctx, stream_cipher->key_length,
                                stream_cipher->key);
#else
206
  nettle_aes128.set_encrypt_key(ctx, 
207
                                stream_cipher->key);
208
#endif
209

210
211
212
  nettle_ctr_crypt(ctx, nettle_aes128.encrypt,
                   nettle_aes128.block_size, m,
                   byte_length, data, stream_cipher->message);
213

214
215
  if (zero_bit > 0)
    data[byte_length - 1] = data[byte_length - 1] & (uint8_t)(0xFF << (8 - zero_bit));
216

217
  free(ctx);
218
219

#if defined(SECU_DEBUG)
220
221
222
223
224
225
226
227
228
229
  {
    int i;
    char payload[6 * byte_length + 1];
    int  index = 0;

    for (i = 0; i < byte_length; i++)
      index += sprintf(&payload[index], "0x%02x ", data[i]);

    LOG_D(OSA, "Encrypted message: %s\n", payload);
  }
230
231
#endif

232
  return 0;
233
234
235
236
}

int stream_encrypt(uint8_t algorithm, stream_cipher_t *stream_cipher, uint8_t **out)
{
237
238
239
240
241
242
243
244
245
246
  if (algorithm == EEA0_ALG_ID) {
    return stream_encrypt_eea0(stream_cipher, out);
  } else if (algorithm == EEA1_128_ALG_ID) {
    return stream_encrypt_eea1(stream_cipher, out);
  } else if (algorithm == EEA2_128_ALG_ID) {
    return stream_encrypt_eea2(stream_cipher, out);
  }

  LOG_E(OSA, "Provided encryption algorithm is currently not supported = %u\n", algorithm);
  return -1;
247
}