Coverage Report

Created: 2025-10-12 07:18

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