Coverage Report

Created: 2025-07-23 07:18

/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-CFB",
278
    .id = GNUTLS_CIPHER_AES_128_CFB,
279
    .blocksize = 16,
280
    .keysize = 16,
281
    .type = CIPHER_BLOCK,
282
    .explicit_iv = 16,
283
    .cipher_iv = 16 },
284
  { .name = "AES-192-CFB",
285
    .id = GNUTLS_CIPHER_AES_192_CFB,
286
    .blocksize = 16,
287
    .keysize = 24,
288
    .type = CIPHER_BLOCK,
289
    .explicit_iv = 16,
290
    .cipher_iv = 16 },
291
  { .name = "AES-256-CFB",
292
    .id = GNUTLS_CIPHER_AES_256_CFB,
293
    .blocksize = 16,
294
    .keysize = 32,
295
    .type = CIPHER_BLOCK,
296
    .explicit_iv = 16,
297
    .cipher_iv = 16 },
298
  { .name = "AES-128-XTS",
299
    .id = GNUTLS_CIPHER_AES_128_XTS,
300
    .blocksize = 16,
301
    .keysize = 32,
302
    .type = CIPHER_BLOCK,
303
    .explicit_iv = 16,
304
    .cipher_iv = 16 },
305
  { .name = "AES-256-XTS",
306
    .id = GNUTLS_CIPHER_AES_256_XTS,
307
    .blocksize = 16,
308
    .keysize = 64,
309
    .type = CIPHER_BLOCK,
310
    .explicit_iv = 16,
311
    .cipher_iv = 16 },
312
  { .name = "AES-128-SIV",
313
    .id = GNUTLS_CIPHER_AES_128_SIV,
314
    .blocksize = 16,
315
    .keysize = 32,
316
    .type = CIPHER_AEAD,
317
    .explicit_iv = 16,
318
    .cipher_iv = 16,
319
    .flags = GNUTLS_CIPHER_FLAG_ONLY_AEAD |
320
       GNUTLS_CIPHER_FLAG_TAG_PREFIXED,
321
    .tagsize = 16 },
322
  { .name = "AES-256-SIV",
323
    .id = GNUTLS_CIPHER_AES_256_SIV,
324
    .blocksize = 16,
325
    .keysize = 64,
326
    .type = CIPHER_AEAD,
327
    .explicit_iv = 16,
328
    .cipher_iv = 16,
329
    .flags = GNUTLS_CIPHER_FLAG_ONLY_AEAD |
330
       GNUTLS_CIPHER_FLAG_TAG_PREFIXED,
331
    .tagsize = 16 },
332
  { .name = "AES-128-SIV-GCM",
333
    .id = GNUTLS_CIPHER_AES_128_SIV_GCM,
334
    .blocksize = 16,
335
    .keysize = 16,
336
    .type = CIPHER_AEAD,
337
    .explicit_iv = 12,
338
    .cipher_iv = 12,
339
    .flags = GNUTLS_CIPHER_FLAG_ONLY_AEAD,
340
    .tagsize = 16 },
341
  { .name = "AES-256-SIV-GCM",
342
    .id = GNUTLS_CIPHER_AES_256_SIV_GCM,
343
    .blocksize = 16,
344
    .keysize = 32,
345
    .type = CIPHER_AEAD,
346
    .explicit_iv = 12,
347
    .cipher_iv = 12,
348
    .flags = GNUTLS_CIPHER_FLAG_ONLY_AEAD,
349
    .tagsize = 16 },
350
  { .name = "GOST28147-TC26Z-CNT",
351
    .id = GNUTLS_CIPHER_GOST28147_TC26Z_CNT,
352
    .blocksize = 8,
353
    .keysize = 32,
354
    .type = CIPHER_STREAM,
355
    .implicit_iv = 8,
356
    .cipher_iv = 8 },
357
  { .name = "MAGMA-CTR-ACPKM",
358
    .id = GNUTLS_CIPHER_MAGMA_CTR_ACPKM,
359
    .blocksize = 8,
360
    .keysize = 32,
361
    .type = CIPHER_STREAM,
362
    .implicit_iv = 4,
363
    .cipher_iv = 8 },
364
  { .name = "KUZNYECHIK-CTR-ACPKM",
365
    .id = GNUTLS_CIPHER_KUZNYECHIK_CTR_ACPKM,
366
    .blocksize = 16,
367
    .keysize = 32,
368
    .type = CIPHER_STREAM,
369
    .implicit_iv = 8,
370
    .cipher_iv = 16 },
371
  { .name = "3DES-CBC",
372
    .id = GNUTLS_CIPHER_3DES_CBC,
373
    .blocksize = 8,
374
    .keysize = 24,
375
    .type = CIPHER_BLOCK,
376
    .explicit_iv = 8,
377
    .cipher_iv = 8 },
378
  { .name = "DES-CBC",
379
    .id = GNUTLS_CIPHER_DES_CBC,
380
    .blocksize = 8,
381
    .keysize = 8,
382
    .type = CIPHER_BLOCK,
383
    .explicit_iv = 8,
384
    .cipher_iv = 8 },
385
  { .name = "ARCFOUR-40",
386
    .id = GNUTLS_CIPHER_ARCFOUR_40,
387
    .blocksize = 1,
388
    .keysize = 5,
389
    .type = CIPHER_STREAM },
390
  { .name = "RC2-40",
391
    .id = GNUTLS_CIPHER_RC2_40_CBC,
392
    .blocksize = 8,
393
    .keysize = 5,
394
    .type = CIPHER_BLOCK,
395
    .explicit_iv = 8,
396
    .cipher_iv = 8 },
397
  { .name = "NULL",
398
    .id = GNUTLS_CIPHER_NULL,
399
    .blocksize = 1,
400
    .keysize = 0,
401
    .type = CIPHER_STREAM },
402
  { 0, 0, 0, 0, 0, 0, 0 }
403
};
404
405
#define GNUTLS_CIPHER_LOOP(b)                        \
406
0
  const cipher_entry_st *p;                    \
407
0
  for (p = algorithms; p->name != NULL; p++) { \
408
0
    b;                                   \
409
0
  }
410
411
#define GNUTLS_ALG_LOOP(a)                           \
412
0
  GNUTLS_CIPHER_LOOP(if (p->id == algorithm) { \
413
0
    a;                                   \
414
0
    break;                               \
415
0
  })
416
417
/* CIPHER functions */
418
419
const cipher_entry_st *_gnutls_cipher_to_entry(gnutls_cipher_algorithm_t c)
420
0
{
421
0
  GNUTLS_CIPHER_LOOP(if (c == p->id) return p);
422
423
0
  return NULL;
424
0
}
425
426
/* Returns cipher entry even for ciphers that are not supported,
427
 * but are listed (e.g., deprecated ciphers).
428
 */
429
const cipher_entry_st *cipher_name_to_entry(const char *name)
430
0
{
431
0
  GNUTLS_CIPHER_LOOP(if (c_strcasecmp(p->name, name) == 0) { return p; });
432
433
0
  return NULL;
434
0
}
435
436
/**
437
 * gnutls_cipher_get_block_size:
438
 * @algorithm: is an encryption algorithm
439
 *
440
 * Returns: the block size of the encryption algorithm.
441
 *
442
 * Since: 2.10.0
443
 **/
444
unsigned gnutls_cipher_get_block_size(gnutls_cipher_algorithm_t algorithm)
445
0
{
446
0
  size_t ret = 0;
447
0
  GNUTLS_ALG_LOOP(ret = p->blocksize);
448
0
  return ret;
449
0
}
450
451
/**
452
 * gnutls_cipher_get_tag_size:
453
 * @algorithm: is an encryption algorithm
454
 *
455
 * This function returns the tag size of an authenticated encryption
456
 * algorithm. For non-AEAD algorithms, it returns zero.
457
 *
458
 * Returns: the tag size of the authenticated encryption algorithm.
459
 *
460
 * Since: 3.2.2
461
 **/
462
unsigned gnutls_cipher_get_tag_size(gnutls_cipher_algorithm_t algorithm)
463
0
{
464
0
  return _gnutls_cipher_get_tag_size(cipher_to_entry(algorithm));
465
0
}
466
467
/**
468
 * gnutls_cipher_get_iv_size:
469
 * @algorithm: is an encryption algorithm
470
 *
471
 * This function returns the size of the initialization vector (IV) for the
472
 * provided algorithm. For algorithms with variable size IV (e.g., AES-CCM),
473
 * the returned size will be the one used by TLS.
474
 *
475
 * Returns: block size for encryption algorithm.
476
 *
477
 * Since: 3.2.0
478
 **/
479
unsigned gnutls_cipher_get_iv_size(gnutls_cipher_algorithm_t algorithm)
480
0
{
481
0
  size_t ret = 0;
482
0
  GNUTLS_ALG_LOOP(ret = p->cipher_iv);
483
0
  return ret;
484
0
}
485
486
/**
487
 * gnutls_cipher_get_key_size:
488
 * @algorithm: is an encryption algorithm
489
 *
490
 * This function returns the key size of the provided algorithm.
491
 *
492
 * Returns: length (in bytes) of the given cipher's key size, or 0 if
493
 *   the given cipher is invalid.
494
 **/
495
size_t gnutls_cipher_get_key_size(gnutls_cipher_algorithm_t algorithm)
496
0
{ /* In bytes */
497
0
  size_t ret = 0;
498
0
  GNUTLS_ALG_LOOP(ret = p->keysize);
499
0
  return ret;
500
0
}
501
502
/**
503
 * gnutls_cipher_get_name:
504
 * @algorithm: is an encryption algorithm
505
 *
506
 * Convert a #gnutls_cipher_algorithm_t type to a string.
507
 *
508
 * Returns: a pointer to a string that contains the name of the
509
 *   specified cipher, or %NULL.
510
 **/
511
const char *gnutls_cipher_get_name(gnutls_cipher_algorithm_t algorithm)
512
0
{
513
0
  const char *ret = NULL;
514
515
  /* avoid prefix */
516
0
  GNUTLS_ALG_LOOP(ret = p->name);
517
518
0
  return ret;
519
0
}
520
521
/**
522
 * gnutls_cipher_get_id:
523
 * @name: is a cipher algorithm name
524
 *
525
 * The names are compared in a case insensitive way.
526
 *
527
 * Returns: return a #gnutls_cipher_algorithm_t value corresponding to
528
 *   the specified cipher, or %GNUTLS_CIPHER_UNKNOWN on error.
529
 **/
530
gnutls_cipher_algorithm_t gnutls_cipher_get_id(const char *name)
531
0
{
532
0
  gnutls_cipher_algorithm_t ret = GNUTLS_CIPHER_UNKNOWN;
533
534
0
  GNUTLS_CIPHER_LOOP(if (c_strcasecmp(p->name, name) == 0) {
535
0
    if (p->id == GNUTLS_CIPHER_NULL || _gnutls_cipher_exists(p->id))
536
0
      ret = p->id;
537
0
    break;
538
0
  });
539
540
0
  return ret;
541
0
}
542
543
/**
544
 * gnutls_cipher_list:
545
 *
546
 * Get a list of supported cipher algorithms.  Note that not
547
 * necessarily all ciphers are supported as TLS cipher suites.  For
548
 * example, DES is not supported as a cipher suite, but is supported
549
 * for other purposes (e.g., PKCS#8 or similar).
550
 *
551
 * This function is not thread safe.
552
 *
553
 * Returns: a (0)-terminated list of #gnutls_cipher_algorithm_t
554
 *   integers indicating the available ciphers.
555
 *
556
 **/
557
const gnutls_cipher_algorithm_t *gnutls_cipher_list(void)
558
0
{
559
0
  static gnutls_cipher_algorithm_t supported_ciphers[MAX_ALGOS] = { 0 };
560
561
0
  if (supported_ciphers[0] == 0) {
562
0
    int i = 0;
563
564
0
    GNUTLS_CIPHER_LOOP(if (p->id == GNUTLS_CIPHER_NULL ||
565
0
               _gnutls_cipher_exists(p->id))
566
0
             supported_ciphers[i++] = p->id;);
567
0
    supported_ciphers[i++] = 0;
568
0
  }
569
570
0
  return supported_ciphers;
571
0
}