Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/algorithms/ciphers.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2011-2012 Free Software Foundation, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation; either version 2.1 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
#include "gnutls_int.h"
24
#include "algorithms.h"
25
#include "errors.h"
26
#include "x509/common.h"
27
#include "c-strcase.h"
28
29
/* Note that all algorithms are in CBC or STREAM modes.
30
 * Do not add any algorithms in other modes (avoid modified algorithms).
31
 * View first: "The order of encryption and authentication for
32
 * protecting communications" by Hugo Krawczyk - CRYPTO 2001
33
 *
34
 * On update, make sure to update MAX_CIPHER_BLOCK_SIZE, MAX_CIPHER_IV_SIZE,
35
 * and MAX_CIPHER_KEY_SIZE as well.
36
 * If any ciphers are removed, remove them from the back-end but
37
 * keep them in that list to allow backwards compatibility with applications
38
 * that specify them (they will be a no-op).
39
 */
40
static const cipher_entry_st algorithms[] = {
41
  { .name = "AES-256-CBC",
42
    .id = GNUTLS_CIPHER_AES_256_CBC,
43
    .blocksize = 16,
44
    .keysize = 32,
45
    .type = CIPHER_BLOCK,
46
    .explicit_iv = 16,
47
    .cipher_iv = 16 },
48
  { .name = "AES-192-CBC",
49
    .id = GNUTLS_CIPHER_AES_192_CBC,
50
    .blocksize = 16,
51
    .keysize = 24,
52
    .type = CIPHER_BLOCK,
53
    .explicit_iv = 16,
54
    .cipher_iv = 16 },
55
  { .name = "AES-128-CBC",
56
    .id = GNUTLS_CIPHER_AES_128_CBC,
57
    .blocksize = 16,
58
    .keysize = 16,
59
    .type = CIPHER_BLOCK,
60
    .explicit_iv = 16,
61
    .cipher_iv = 16 },
62
  { .name = "AES-128-GCM",
63
    .id = GNUTLS_CIPHER_AES_128_GCM,
64
    .blocksize = 16,
65
    .keysize = 16,
66
    .type = CIPHER_AEAD,
67
    .implicit_iv = 4,
68
    .explicit_iv = 8,
69
    .cipher_iv = 12,
70
    .tagsize = 16 },
71
  { .name = "AES-192-GCM",
72
    .id = GNUTLS_CIPHER_AES_192_GCM,
73
    .blocksize = 16,
74
    .keysize = 24,
75
    .type = CIPHER_AEAD,
76
    .implicit_iv = 4,
77
    .explicit_iv = 8,
78
    .cipher_iv = 12,
79
    .tagsize = 16 },
80
  { .name = "AES-256-GCM",
81
    .id = GNUTLS_CIPHER_AES_256_GCM,
82
    .blocksize = 16,
83
    .keysize = 32,
84
    .type = CIPHER_AEAD,
85
    .implicit_iv = 4,
86
    .explicit_iv = 8,
87
    .cipher_iv = 12,
88
    .tagsize = 16 },
89
  { .name = "AES-128-CCM",
90
    .id = GNUTLS_CIPHER_AES_128_CCM,
91
    .blocksize = 16,
92
    .keysize = 16,
93
    .type = CIPHER_AEAD,
94
    .implicit_iv = 4,
95
    .explicit_iv = 8,
96
    .cipher_iv = 12,
97
    .flags = GNUTLS_CIPHER_FLAG_ONLY_AEAD,
98
    .tagsize = 16 },
99
  { .name = "AES-256-CCM",
100
    .id = GNUTLS_CIPHER_AES_256_CCM,
101
    .blocksize = 16,
102
    .keysize = 32,
103
    .type = CIPHER_AEAD,
104
    .implicit_iv = 4,
105
    .explicit_iv = 8,
106
    .cipher_iv = 12,
107
    .flags = GNUTLS_CIPHER_FLAG_ONLY_AEAD,
108
    .tagsize = 16 },
109
  { .name = "AES-128-CCM-8",
110
    .id = GNUTLS_CIPHER_AES_128_CCM_8,
111
    .blocksize = 16,
112
    .keysize = 16,
113
    .type = CIPHER_AEAD,
114
    .implicit_iv = 4,
115
    .explicit_iv = 8,
116
    .cipher_iv = 12,
117
    .flags = GNUTLS_CIPHER_FLAG_ONLY_AEAD,
118
    .tagsize = 8 },
119
  { .name = "AES-256-CCM-8",
120
    .id = GNUTLS_CIPHER_AES_256_CCM_8,
121
    .blocksize = 16,
122
    .keysize = 32,
123
    .type = CIPHER_AEAD,
124
    .implicit_iv = 4,
125
    .explicit_iv = 8,
126
    .cipher_iv = 12,
127
    .flags = GNUTLS_CIPHER_FLAG_ONLY_AEAD,
128
    .tagsize = 8 },
129
  { .name = "ARCFOUR-128",
130
    .id = GNUTLS_CIPHER_ARCFOUR_128,
131
    .blocksize = 1,
132
    .keysize = 16,
133
    .type = CIPHER_STREAM,
134
    0,
135
    0,
136
    0,
137
    0 },
138
  { .name = "ESTREAM-SALSA20-256",
139
    .id = GNUTLS_CIPHER_ESTREAM_SALSA20_256,
140
    .blocksize = 64,
141
    .keysize = 32,
142
    .type = CIPHER_STREAM,
143
    0,
144
    0,
145
    8,
146
    0 },
147
  { .name = "SALSA20-256",
148
    .id = GNUTLS_CIPHER_SALSA20_256,
149
    .blocksize = 64,
150
    .keysize = 32,
151
    .type = CIPHER_STREAM,
152
    .explicit_iv = 0,
153
    .cipher_iv = 8 },
154
  { .name = "CHACHA20-32",
155
    .id = GNUTLS_CIPHER_CHACHA20_32,
156
    .blocksize = 64,
157
    .keysize = 32,
158
    .type = CIPHER_STREAM,
159
    .explicit_iv = 0,
160
    /* IV includes counter */
161
    .cipher_iv = 16 },
162
  { .name = "CHACHA20-64",
163
    .id = GNUTLS_CIPHER_CHACHA20_64,
164
    .blocksize = 64,
165
    .keysize = 32,
166
    .type = CIPHER_STREAM,
167
    .explicit_iv = 0,
168
    /* IV includes counter */
169
    .cipher_iv = 16 },
170
  { .name = "CAMELLIA-256-CBC",
171
    .id = GNUTLS_CIPHER_CAMELLIA_256_CBC,
172
    .blocksize = 16,
173
    .keysize = 32,
174
    .type = CIPHER_BLOCK,
175
    .explicit_iv = 16,
176
    .cipher_iv = 16 },
177
  { .name = "CAMELLIA-192-CBC",
178
    .id = GNUTLS_CIPHER_CAMELLIA_192_CBC,
179
    .blocksize = 16,
180
    .keysize = 24,
181
    .type = CIPHER_BLOCK,
182
    .explicit_iv = 16,
183
    .cipher_iv = 16 },
184
  { .name = "CAMELLIA-128-CBC",
185
    .id = GNUTLS_CIPHER_CAMELLIA_128_CBC,
186
    .blocksize = 16,
187
    .keysize = 16,
188
    .type = CIPHER_BLOCK,
189
    .explicit_iv = 16,
190
    .cipher_iv = 16 },
191
  { .name = "CHACHA20-POLY1305",
192
    .id = GNUTLS_CIPHER_CHACHA20_POLY1305,
193
    .blocksize = 64,
194
    .keysize = 32,
195
    .type = CIPHER_AEAD,
196
    .implicit_iv = 12,
197
    .explicit_iv = 0,
198
    /* in chacha20 we don't need a rekey after 2^24 messages */
199
    .flags = GNUTLS_CIPHER_FLAG_XOR_NONCE | GNUTLS_CIPHER_FLAG_NO_REKEY,
200
    .cipher_iv = 12,
201
    .tagsize = 16 },
202
  { .name = "CAMELLIA-128-GCM",
203
    .id = GNUTLS_CIPHER_CAMELLIA_128_GCM,
204
    .blocksize = 16,
205
    .keysize = 16,
206
    .type = CIPHER_AEAD,
207
    4,
208
    8,
209
    12,
210
    16 },
211
  { .name = "CAMELLIA-256-GCM",
212
    .id = GNUTLS_CIPHER_CAMELLIA_256_GCM,
213
    .blocksize = 16,
214
    .keysize = 32,
215
    .type = CIPHER_AEAD,
216
    .implicit_iv = 4,
217
    .explicit_iv = 8,
218
    .cipher_iv = 12,
219
    .tagsize = 16 },
220
  { .name = "GOST28147-TC26Z-CFB",
221
    .id = GNUTLS_CIPHER_GOST28147_TC26Z_CFB,
222
    .blocksize = 8,
223
    .keysize = 32,
224
    .type = CIPHER_STREAM,
225
    .implicit_iv = 8,
226
    .cipher_iv = 8 },
227
  { .name = "GOST28147-CPA-CFB",
228
    .id = GNUTLS_CIPHER_GOST28147_CPA_CFB,
229
    .blocksize = 8,
230
    .keysize = 32,
231
    .type = CIPHER_STREAM,
232
    .implicit_iv = 8,
233
    .cipher_iv = 8 },
234
  { .name = "GOST28147-CPB-CFB",
235
    .id = GNUTLS_CIPHER_GOST28147_CPB_CFB,
236
    .blocksize = 8,
237
    .keysize = 32,
238
    .type = CIPHER_STREAM,
239
    .implicit_iv = 8,
240
    .cipher_iv = 8 },
241
  { .name = "GOST28147-CPC-CFB",
242
    .id = GNUTLS_CIPHER_GOST28147_CPC_CFB,
243
    .blocksize = 8,
244
    .keysize = 32,
245
    .type = CIPHER_STREAM,
246
    .implicit_iv = 8,
247
    .cipher_iv = 8 },
248
  { .name = "GOST28147-CPD-CFB",
249
    .id = GNUTLS_CIPHER_GOST28147_CPD_CFB,
250
    .blocksize = 8,
251
    .keysize = 32,
252
    .type = CIPHER_STREAM,
253
    .implicit_iv = 8,
254
    .cipher_iv = 8 },
255
256
  { .name = "AES-128-CFB8",
257
    .id = GNUTLS_CIPHER_AES_128_CFB8,
258
    .blocksize = 16,
259
    .keysize = 16,
260
    .type = CIPHER_BLOCK,
261
    .explicit_iv = 16,
262
    .cipher_iv = 16 },
263
  { .name = "AES-192-CFB8",
264
    .id = GNUTLS_CIPHER_AES_192_CFB8,
265
    .blocksize = 16,
266
    .keysize = 24,
267
    .type = CIPHER_BLOCK,
268
    .explicit_iv = 16,
269
    .cipher_iv = 16 },
270
  { .name = "AES-256-CFB8",
271
    .id = GNUTLS_CIPHER_AES_256_CFB8,
272
    .blocksize = 16,
273
    .keysize = 32,
274
    .type = CIPHER_BLOCK,
275
    .explicit_iv = 16,
276
    .cipher_iv = 16 },
277
  { .name = "AES-128-XTS",
278
    .id = GNUTLS_CIPHER_AES_128_XTS,
279
    .blocksize = 16,
280
    .keysize = 32,
281
    .type = CIPHER_BLOCK,
282
    .explicit_iv = 16,
283
    .cipher_iv = 16 },
284
  { .name = "AES-256-XTS",
285
    .id = GNUTLS_CIPHER_AES_256_XTS,
286
    .blocksize = 16,
287
    .keysize = 64,
288
    .type = CIPHER_BLOCK,
289
    .explicit_iv = 16,
290
    .cipher_iv = 16 },
291
  { .name = "AES-128-SIV",
292
    .id = GNUTLS_CIPHER_AES_128_SIV,
293
    .blocksize = 16,
294
    .keysize = 32,
295
    .type = CIPHER_AEAD,
296
    .explicit_iv = 16,
297
    .cipher_iv = 16,
298
    .flags = GNUTLS_CIPHER_FLAG_ONLY_AEAD |
299
       GNUTLS_CIPHER_FLAG_TAG_PREFIXED,
300
    .tagsize = 16 },
301
  { .name = "AES-256-SIV",
302
    .id = GNUTLS_CIPHER_AES_256_SIV,
303
    .blocksize = 16,
304
    .keysize = 64,
305
    .type = CIPHER_AEAD,
306
    .explicit_iv = 16,
307
    .cipher_iv = 16,
308
    .flags = GNUTLS_CIPHER_FLAG_ONLY_AEAD |
309
       GNUTLS_CIPHER_FLAG_TAG_PREFIXED,
310
    .tagsize = 16 },
311
  { .name = "AES-128-SIV-GCM",
312
    .id = GNUTLS_CIPHER_AES_128_SIV_GCM,
313
    .blocksize = 16,
314
    .keysize = 16,
315
    .type = CIPHER_AEAD,
316
    .explicit_iv = 12,
317
    .cipher_iv = 12,
318
    .flags = GNUTLS_CIPHER_FLAG_ONLY_AEAD,
319
    .tagsize = 16 },
320
  { .name = "AES-256-SIV-GCM",
321
    .id = GNUTLS_CIPHER_AES_256_SIV_GCM,
322
    .blocksize = 16,
323
    .keysize = 32,
324
    .type = CIPHER_AEAD,
325
    .explicit_iv = 12,
326
    .cipher_iv = 12,
327
    .flags = GNUTLS_CIPHER_FLAG_ONLY_AEAD,
328
    .tagsize = 16 },
329
  { .name = "GOST28147-TC26Z-CNT",
330
    .id = GNUTLS_CIPHER_GOST28147_TC26Z_CNT,
331
    .blocksize = 8,
332
    .keysize = 32,
333
    .type = CIPHER_STREAM,
334
    .implicit_iv = 8,
335
    .cipher_iv = 8 },
336
  { .name = "MAGMA-CTR-ACPKM",
337
    .id = GNUTLS_CIPHER_MAGMA_CTR_ACPKM,
338
    .blocksize = 8,
339
    .keysize = 32,
340
    .type = CIPHER_STREAM,
341
    .implicit_iv = 4,
342
    .cipher_iv = 8 },
343
  { .name = "KUZNYECHIK-CTR-ACPKM",
344
    .id = GNUTLS_CIPHER_KUZNYECHIK_CTR_ACPKM,
345
    .blocksize = 16,
346
    .keysize = 32,
347
    .type = CIPHER_STREAM,
348
    .implicit_iv = 8,
349
    .cipher_iv = 16 },
350
  { .name = "3DES-CBC",
351
    .id = GNUTLS_CIPHER_3DES_CBC,
352
    .blocksize = 8,
353
    .keysize = 24,
354
    .type = CIPHER_BLOCK,
355
    .explicit_iv = 8,
356
    .cipher_iv = 8 },
357
  { .name = "DES-CBC",
358
    .id = GNUTLS_CIPHER_DES_CBC,
359
    .blocksize = 8,
360
    .keysize = 8,
361
    .type = CIPHER_BLOCK,
362
    .explicit_iv = 8,
363
    .cipher_iv = 8 },
364
  { .name = "ARCFOUR-40",
365
    .id = GNUTLS_CIPHER_ARCFOUR_40,
366
    .blocksize = 1,
367
    .keysize = 5,
368
    .type = CIPHER_STREAM },
369
  { .name = "RC2-40",
370
    .id = GNUTLS_CIPHER_RC2_40_CBC,
371
    .blocksize = 8,
372
    .keysize = 5,
373
    .type = CIPHER_BLOCK,
374
    .explicit_iv = 8,
375
    .cipher_iv = 8 },
376
  { .name = "NULL",
377
    .id = GNUTLS_CIPHER_NULL,
378
    .blocksize = 1,
379
    .keysize = 0,
380
    .type = CIPHER_STREAM },
381
  { 0, 0, 0, 0, 0, 0, 0 }
382
};
383
384
#define GNUTLS_CIPHER_LOOP(b)                        \
385
0
  const cipher_entry_st *p;                    \
386
0
  for (p = algorithms; p->name != NULL; p++) { \
387
0
    b;                                   \
388
0
  }
389
390
#define GNUTLS_ALG_LOOP(a)                           \
391
0
  GNUTLS_CIPHER_LOOP(if (p->id == algorithm) { \
392
0
    a;                                   \
393
0
    break;                               \
394
0
  })
395
396
/* CIPHER functions */
397
398
const cipher_entry_st *_gnutls_cipher_to_entry(gnutls_cipher_algorithm_t c)
399
0
{
400
0
  GNUTLS_CIPHER_LOOP(if (c == p->id) return p);
401
402
0
  return NULL;
403
0
}
404
405
/* Returns cipher entry even for ciphers that are not supported,
406
 * but are listed (e.g., deprecated ciphers).
407
 */
408
const cipher_entry_st *cipher_name_to_entry(const char *name)
409
0
{
410
0
  GNUTLS_CIPHER_LOOP(if (c_strcasecmp(p->name, name) == 0) { return p; });
411
412
0
  return NULL;
413
0
}
414
415
/**
416
 * gnutls_cipher_get_block_size:
417
 * @algorithm: is an encryption algorithm
418
 *
419
 * Returns: the block size of the encryption algorithm.
420
 *
421
 * Since: 2.10.0
422
 **/
423
unsigned gnutls_cipher_get_block_size(gnutls_cipher_algorithm_t algorithm)
424
0
{
425
0
  size_t ret = 0;
426
0
  GNUTLS_ALG_LOOP(ret = p->blocksize);
427
0
  return ret;
428
0
}
429
430
/**
431
 * gnutls_cipher_get_tag_size:
432
 * @algorithm: is an encryption algorithm
433
 *
434
 * This function returns the tag size of an authenticated encryption
435
 * algorithm. For non-AEAD algorithms, it returns zero.
436
 *
437
 * Returns: the tag size of the authenticated encryption algorithm.
438
 *
439
 * Since: 3.2.2
440
 **/
441
unsigned gnutls_cipher_get_tag_size(gnutls_cipher_algorithm_t algorithm)
442
0
{
443
0
  return _gnutls_cipher_get_tag_size(cipher_to_entry(algorithm));
444
0
}
445
446
/**
447
 * gnutls_cipher_get_iv_size:
448
 * @algorithm: is an encryption algorithm
449
 *
450
 * This function returns the size of the initialization vector (IV) for the
451
 * provided algorithm. For algorithms with variable size IV (e.g., AES-CCM),
452
 * the returned size will be the one used by TLS.
453
 *
454
 * Returns: block size for encryption algorithm.
455
 *
456
 * Since: 3.2.0
457
 **/
458
unsigned gnutls_cipher_get_iv_size(gnutls_cipher_algorithm_t algorithm)
459
0
{
460
0
  size_t ret = 0;
461
0
  GNUTLS_ALG_LOOP(ret = p->cipher_iv);
462
0
  return ret;
463
0
}
464
465
/**
466
 * gnutls_cipher_get_key_size:
467
 * @algorithm: is an encryption algorithm
468
 *
469
 * This function returns the key size of the provided algorithm.
470
 *
471
 * Returns: length (in bytes) of the given cipher's key size, or 0 if
472
 *   the given cipher is invalid.
473
 **/
474
size_t gnutls_cipher_get_key_size(gnutls_cipher_algorithm_t algorithm)
475
0
{ /* In bytes */
476
0
  size_t ret = 0;
477
0
  GNUTLS_ALG_LOOP(ret = p->keysize);
478
0
  return ret;
479
0
}
480
481
/**
482
 * gnutls_cipher_get_name:
483
 * @algorithm: is an encryption algorithm
484
 *
485
 * Convert a #gnutls_cipher_algorithm_t type to a string.
486
 *
487
 * Returns: a pointer to a string that contains the name of the
488
 *   specified cipher, or %NULL.
489
 **/
490
const char *gnutls_cipher_get_name(gnutls_cipher_algorithm_t algorithm)
491
0
{
492
0
  const char *ret = NULL;
493
494
  /* avoid prefix */
495
0
  GNUTLS_ALG_LOOP(ret = p->name);
496
497
0
  return ret;
498
0
}
499
500
/**
501
 * gnutls_cipher_get_id:
502
 * @name: is a cipher algorithm name
503
 *
504
 * The names are compared in a case insensitive way.
505
 *
506
 * Returns: return a #gnutls_cipher_algorithm_t value corresponding to
507
 *   the specified cipher, or %GNUTLS_CIPHER_UNKNOWN on error.
508
 **/
509
gnutls_cipher_algorithm_t gnutls_cipher_get_id(const char *name)
510
0
{
511
0
  gnutls_cipher_algorithm_t ret = GNUTLS_CIPHER_UNKNOWN;
512
513
0
  GNUTLS_CIPHER_LOOP(if (c_strcasecmp(p->name, name) == 0) {
514
0
    if (p->id == GNUTLS_CIPHER_NULL || _gnutls_cipher_exists(p->id))
515
0
      ret = p->id;
516
0
    break;
517
0
  });
518
519
0
  return ret;
520
0
}
521
522
/**
523
 * gnutls_cipher_list:
524
 *
525
 * Get a list of supported cipher algorithms.  Note that not
526
 * necessarily all ciphers are supported as TLS cipher suites.  For
527
 * example, DES is not supported as a cipher suite, but is supported
528
 * for other purposes (e.g., PKCS#8 or similar).
529
 *
530
 * This function is not thread safe.
531
 *
532
 * Returns: a (0)-terminated list of #gnutls_cipher_algorithm_t
533
 *   integers indicating the available ciphers.
534
 *
535
 **/
536
const gnutls_cipher_algorithm_t *gnutls_cipher_list(void)
537
0
{
538
0
  static gnutls_cipher_algorithm_t supported_ciphers[MAX_ALGOS] = { 0 };
539
540
0
  if (supported_ciphers[0] == 0) {
541
0
    int i = 0;
542
543
0
    GNUTLS_CIPHER_LOOP(if (p->id == GNUTLS_CIPHER_NULL ||
544
0
               _gnutls_cipher_exists(p->id))
545
0
             supported_ciphers[i++] = p->id;);
546
0
    supported_ciphers[i++] = 0;
547
0
  }
548
549
0
  return supported_ciphers;
550
0
}