Coverage Report

Created: 2025-08-26 06:41

/src/strongswan/src/libstrongswan/plugins/xcbc/xcbc.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2012 Tobias Brunner
3
 * Copyright (C) 2008 Martin Willi
4
 *
5
 * Copyright (C) secunet Security Networks AG
6
 *
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License as published by the
9
 * Free Software Foundation; either version 2 of the License, or (at your
10
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
11
 *
12
 * This program is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
 * for more details.
16
 */
17
18
#include <string.h>
19
20
#include "xcbc.h"
21
22
#include <utils/debug.h>
23
#include <crypto/mac.h>
24
#include <crypto/prfs/mac_prf.h>
25
#include <crypto/signers/mac_signer.h>
26
27
typedef struct private_mac_t private_mac_t;
28
29
/**
30
 * Private data of a mac_t object.
31
 *
32
 * The variable names are the same as in the RFC.
33
 */
34
struct private_mac_t {
35
36
  /**
37
   * Public mac_t interface.
38
   */
39
  mac_t public;
40
41
  /**
42
   * Block size, in bytes
43
   */
44
  uint8_t b;
45
46
  /**
47
   * crypter using k1
48
   */
49
  crypter_t *k1;
50
51
  /**
52
   * k2
53
   */
54
  uint8_t *k2;
55
56
  /**
57
   * k3
58
   */
59
  uint8_t *k3;
60
61
  /**
62
   * E
63
   */
64
  uint8_t *e;
65
66
  /**
67
   * remaining, unprocessed bytes in append mode
68
   */
69
  uint8_t *remaining;
70
71
  /**
72
   * number of bytes in remaining
73
   */
74
  int remaining_bytes;
75
76
  /**
77
   * TRUE if we have zero bytes to xcbc in final()
78
   */
79
  bool zero;
80
};
81
82
/**
83
 * xcbc supplied data, but do not run final operation
84
 */
85
static bool update(private_mac_t *this, chunk_t data)
86
0
{
87
0
  chunk_t iv;
88
89
0
  if (data.len)
90
0
  {
91
0
    this->zero = FALSE;
92
0
  }
93
94
0
  if (this->remaining_bytes + data.len <= this->b)
95
0
  { /* no complete block, just copy into remaining */
96
0
    memcpy(this->remaining + this->remaining_bytes, data.ptr, data.len);
97
0
    this->remaining_bytes += data.len;
98
0
    return TRUE;
99
0
  }
100
101
0
  iv = chunk_alloca(this->b);
102
0
  memset(iv.ptr, 0, iv.len);
103
104
  /* (3) For each block M[i], where i = 1 ... n-1:
105
   *     XOR M[i] with E[i-1], then encrypt the result with Key K1,
106
   *     yielding E[i].
107
   */
108
109
  /* append data to remaining bytes, process block M[1] */
110
0
  memcpy(this->remaining + this->remaining_bytes, data.ptr,
111
0
       this->b - this->remaining_bytes);
112
0
  data = chunk_skip(data, this->b - this->remaining_bytes);
113
0
  memxor(this->e, this->remaining, this->b);
114
0
  if (!this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL))
115
0
  {
116
0
    return FALSE;
117
0
  }
118
119
  /* process blocks M[2] ... M[n-1] */
120
0
  while (data.len > this->b)
121
0
  {
122
0
    memcpy(this->remaining, data.ptr, this->b);
123
0
    data = chunk_skip(data, this->b);
124
0
    memxor(this->e, this->remaining, this->b);
125
0
    if (!this->k1->encrypt(this->k1, chunk_create(this->e, this->b),
126
0
                 iv, NULL))
127
0
    {
128
0
      return FALSE;
129
0
    }
130
0
  }
131
132
  /* store remaining bytes of block M[n] */
133
0
  memcpy(this->remaining, data.ptr, data.len);
134
0
  this->remaining_bytes = data.len;
135
136
0
  return TRUE;
137
0
}
138
139
/**
140
 * run last round, data is in this->e
141
 */
142
static bool final(private_mac_t *this, uint8_t *out)
143
0
{
144
0
  chunk_t iv;
145
146
0
  iv = chunk_alloca(this->b);
147
0
  memset(iv.ptr, 0, iv.len);
148
149
  /* (4) For block M[n]: */
150
0
  if (this->remaining_bytes == this->b && !this->zero)
151
0
  {
152
    /* a) If the blocksize of M[n] is 128 bits:
153
     *    XOR M[n] with E[n-1] and Key K2, then encrypt the result with
154
     *    Key K1, yielding E[n].
155
     */
156
0
    memxor(this->e, this->remaining, this->b);
157
0
    memxor(this->e, this->k2, this->b);
158
0
  }
159
0
  else
160
0
  {
161
    /* b) If the blocksize of M[n] is less than 128 bits:
162
     *
163
     *  i) Pad M[n] with a single "1" bit, followed by the number of
164
     *     "0" bits (possibly none) required to increase M[n]'s
165
     *     blocksize to 128 bits.
166
     */
167
0
    if (this->remaining_bytes < this->b)
168
0
    {
169
0
      this->remaining[this->remaining_bytes] = 0x80;
170
0
      while (++this->remaining_bytes < this->b)
171
0
      {
172
0
        this->remaining[this->remaining_bytes] = 0x00;
173
0
      }
174
0
    }
175
    /*  ii) XOR M[n] with E[n-1] and Key K3, then encrypt the result
176
     *      with Key K1, yielding E[n].
177
     */
178
0
    memxor(this->e, this->remaining, this->b);
179
0
    memxor(this->e, this->k3, this->b);
180
0
  }
181
0
  if (!this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL))
182
0
  {
183
0
    return FALSE;
184
0
  }
185
186
0
  memcpy(out, this->e, this->b);
187
188
  /* (2) Define E[0] = 0x00000000000000000000000000000000 */
189
0
  memset(this->e, 0, this->b);
190
0
  this->remaining_bytes = 0;
191
0
  this->zero = TRUE;
192
193
0
  return TRUE;
194
0
}
195
196
METHOD(mac_t, get_mac, bool,
197
  private_mac_t *this, chunk_t data, uint8_t *out)
198
0
{
199
  /* update E, do not process last block */
200
0
  if (!update(this, data))
201
0
  {
202
0
    return FALSE;
203
0
  }
204
205
0
  if (out)
206
0
  { /* if not in append mode, process last block and output result */
207
0
    return final(this, out);
208
0
  }
209
0
  return TRUE;
210
0
}
211
212
METHOD(mac_t, get_mac_size, size_t,
213
  private_mac_t *this)
214
0
{
215
0
  return this->b;
216
0
}
217
218
METHOD(mac_t, set_key, bool,
219
  private_mac_t *this, chunk_t key)
220
0
{
221
0
  chunk_t iv, k1, lengthened;
222
223
0
  memset(this->e, 0, this->b);
224
0
  this->remaining_bytes = 0;
225
0
  this->zero = TRUE;
226
227
  /* we support variable keys from RFC4434 */
228
0
  if (key.len == this->b)
229
0
  {
230
0
    lengthened = key;
231
0
  }
232
0
  else if (key.len < this->b)
233
0
  { /* pad short keys */
234
0
    lengthened = chunk_alloca(this->b);
235
0
    memset(lengthened.ptr, 0, lengthened.len);
236
0
    memcpy(lengthened.ptr, key.ptr, key.len);
237
0
  }
238
0
  else
239
0
  { /* shorten key using xcbc */
240
0
    lengthened = chunk_alloca(this->b);
241
0
    memset(lengthened.ptr, 0, lengthened.len);
242
0
    if (!set_key(this, lengthened) ||
243
0
      !get_mac(this, key, lengthened.ptr))
244
0
    {
245
0
      return FALSE;
246
0
    }
247
0
  }
248
249
0
  k1 = chunk_alloca(this->b);
250
0
  iv = chunk_alloca(this->b);
251
0
  memset(iv.ptr, 0, iv.len);
252
253
  /*
254
   * (1) Derive 3 128-bit keys (K1, K2 and K3) from the 128-bit secret
255
   *     key K, as follows:
256
   *     K1 = 0x01010101010101010101010101010101 encrypted with Key K
257
   *     K2 = 0x02020202020202020202020202020202 encrypted with Key K
258
   *     K3 = 0x03030303030303030303030303030303 encrypted with Key K
259
   */
260
261
0
  memset(k1.ptr, 0x01, this->b);
262
0
  memset(this->k2, 0x02, this->b);
263
0
  memset(this->k3, 0x03, this->b);
264
265
0
  if (!this->k1->set_key(this->k1, lengthened) ||
266
0
    !this->k1->encrypt(this->k1, chunk_create(this->k2, this->b), iv, NULL) ||
267
0
    !this->k1->encrypt(this->k1, chunk_create(this->k3, this->b), iv, NULL) ||
268
0
    !this->k1->encrypt(this->k1, k1, iv, NULL) ||
269
0
    !this->k1->set_key(this->k1, k1))
270
0
  {
271
0
    memwipe(k1.ptr, k1.len);
272
0
    return FALSE;
273
0
  }
274
0
  memwipe(k1.ptr, k1.len);
275
0
  return TRUE;
276
0
}
277
278
METHOD(mac_t, destroy, void,
279
  private_mac_t *this)
280
0
{
281
0
  this->k1->destroy(this->k1);
282
0
  memwipe(this->k2, this->b);
283
0
  free(this->k2);
284
0
  memwipe(this->k3, this->b);
285
0
  free(this->k3);
286
0
  free(this->e);
287
0
  free(this->remaining);
288
0
  free(this);
289
0
}
290
291
/*
292
 * Described in header
293
 */
294
static mac_t *xcbc_create(encryption_algorithm_t algo, size_t key_size)
295
0
{
296
0
  private_mac_t *this;
297
0
  crypter_t *crypter;
298
0
  uint8_t b;
299
300
0
  crypter = lib->crypto->create_crypter(lib->crypto, algo, key_size);
301
0
  if (!crypter)
302
0
  {
303
0
    return NULL;
304
0
  }
305
0
  b = crypter->get_block_size(crypter);
306
  /* input and output of crypter must be equal for xcbc */
307
0
  if (b != key_size)
308
0
  {
309
0
    crypter->destroy(crypter);
310
0
    return NULL;
311
0
  }
312
313
0
  INIT(this,
314
0
    .public = {
315
0
      .get_mac = _get_mac,
316
0
      .get_mac_size = _get_mac_size,
317
0
      .set_key = _set_key,
318
0
      .destroy = _destroy,
319
0
    },
320
0
    .b = b,
321
0
    .k1 = crypter,
322
0
    .k2 = malloc(b),
323
0
    .k3 = malloc(b),
324
0
    .e = malloc(b),
325
0
    .remaining = malloc(b),
326
0
    .zero = TRUE,
327
0
  );
328
0
  memset(this->e, 0, b);
329
330
0
  return &this->public;
331
0
}
332
333
/*
334
 * Described in header.
335
 */
336
prf_t *xcbc_prf_create(pseudo_random_function_t algo)
337
0
{
338
0
  mac_t *xcbc;
339
340
0
  switch (algo)
341
0
  {
342
0
    case PRF_AES128_XCBC:
343
0
      xcbc = xcbc_create(ENCR_AES_CBC, 16);
344
0
      break;
345
0
    case PRF_CAMELLIA128_XCBC:
346
0
      xcbc = xcbc_create(ENCR_CAMELLIA_CBC, 16);
347
0
      break;
348
0
    default:
349
0
      return NULL;
350
0
  }
351
0
  if (xcbc)
352
0
  {
353
0
    return mac_prf_create(xcbc);
354
0
  }
355
0
  return NULL;
356
0
}
357
358
/*
359
 * Described in header
360
 */
361
signer_t *xcbc_signer_create(integrity_algorithm_t algo)
362
0
{
363
0
  size_t trunc;
364
0
  mac_t *xcbc;
365
366
0
  switch (algo)
367
0
  {
368
0
    case AUTH_AES_XCBC_96:
369
0
      xcbc = xcbc_create(ENCR_AES_CBC, 16);
370
0
      trunc = 12;
371
0
      break;
372
0
    case AUTH_CAMELLIA_XCBC_96:
373
0
      xcbc = xcbc_create(ENCR_CAMELLIA_CBC, 16);
374
0
      trunc = 12;
375
0
      break;
376
0
    default:
377
0
      return NULL;
378
0
  }
379
0
  if (xcbc)
380
0
  {
381
0
    return mac_signer_create(xcbc, trunc);
382
0
  }
383
0
  return NULL;
384
0
}