Coverage Report

Created: 2024-04-25 06:03

/src/ntpsec/libaes_siv/aes_siv.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright Akamai Technologies, Inc.
2
 * SPDX-License-Identifier: Apache-2.0
3
 */
4
5
/* Hack to supress a blizzard of warnings when built on OpenSSL 3
6
 * Drop this patch when upstream is fixed. */
7
#define OPENSSL_SUPPRESS_DEPRECATED 1
8
9
#define _POSIX_C_SOURCE 200112L
10
#define _ISOC99_SOURCE 1
11
12
#include "config.h"
13
#include "aes_siv.h"
14
15
#include <assert.h>
16
#include <limits.h>
17
#include <stddef.h>
18
#include <stdint.h>
19
#ifdef ENABLE_DEBUG_OUTPUT
20
#include <stdio.h>
21
#endif
22
#ifdef _MSC_VER
23
/* For _byteswap_uint64 */
24
#include <stdlib.h>
25
#endif
26
#include <string.h>
27
28
#include <openssl/cmac.h>
29
#include <openssl/crypto.h>
30
#include <openssl/evp.h>
31
32
#ifdef ENABLE_CTGRIND
33
#include <ctgrind.h>
34
#endif
35
36
#if CHAR_BIT != 8
37
#error "libaes_siv requires an 8-bit char type"
38
#endif
39
40
#if -1 != ~0
41
#error "libaes_siv requires a two's-complement architecture"
42
#endif
43
44
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
45
#undef inline
46
#elif defined(__GNUC__) || defined(__clang__)
47
#define inline __inline__
48
#elif defined(_MSC_VER)
49
#define inline __inline
50
#else
51
#define inline
52
#endif
53
54
#if defined(__GNUC__) || defined(__clang__)
55
0
#define LIKELY(cond) __builtin_expect(cond, 1)
56
0
#define UNLIKELY(cond) __builtin_expect(cond, 0)
57
#else
58
#define LIKELY(cond) cond
59
#define UNLIKELY(cond) cond
60
#endif
61
62
#ifndef ENABLE_CTGRIND
63
0
static inline void ct_poison(const void *data, size_t len) {
64
0
        (void)data;
65
0
        (void)len;
66
0
}
67
0
static inline void ct_unpoison(const void *data, size_t len) {
68
0
        (void)data;
69
0
        (void)len;
70
0
}
71
#endif
72
73
0
static void debug(const char *label, const unsigned char *hex, size_t len) {
74
/* ENABLE_CTGRIND has to override ENABLE_DEBUG_OUTPUT since sensitive data
75
   gets printed.
76
*/
77
#if defined(ENABLE_DEBUG_OUTPUT) && !defined(ENABLE_CTGRIND)
78
        size_t i;
79
        printf("%16s: ", label);
80
        for (i = 0; i < len; i++) {
81
                if (i > 0 && i % 16 == 0) {
82
                        printf("\n                  ");
83
                }
84
                printf("%.2x", (int)hex[i]);
85
                if (i > 0 && i % 4 == 3) {
86
                        printf(" ");
87
                }
88
        }
89
        printf("\n");
90
#else
91
0
        (void)label;
92
0
        (void)hex;
93
0
        (void)len;
94
0
#endif
95
0
}
96
97
typedef union block_un {
98
        uint64_t word[2];
99
        unsigned char byte[16];
100
} block;
101
102
const union {
103
        uint64_t word;
104
        char byte[8];
105
} endian = {0x0102030405060708};
106
107
0
#define I_AM_BIG_ENDIAN (endian.byte[0] == 1 && \
108
0
                         endian.byte[1] == 2 && \
109
0
                         endian.byte[2] == 3 && \
110
0
                         endian.byte[3] == 4 && \
111
0
                         endian.byte[4] == 5 && \
112
0
                         endian.byte[5] == 6 && \
113
0
                         endian.byte[6] == 7 && \
114
0
                         endian.byte[7] == 8)
115
116
0
#define I_AM_LITTLE_ENDIAN (endian.byte[0] == 8 && \
117
0
                            endian.byte[1] == 7 && \
118
0
                            endian.byte[2] == 6 && \
119
0
                            endian.byte[3] == 5 && \
120
0
                            endian.byte[4] == 4 && \
121
0
                            endian.byte[5] == 3 && \
122
0
                            endian.byte[6] == 2 && \
123
0
                            endian.byte[7] == 1)
124
125
#if defined(__GNUC__) || defined(__clang__)
126
0
static inline uint64_t bswap64(uint64_t x) { return __builtin_bswap64(x); }
127
#elif defined(_MSC_VER)
128
static inline uint64_t bswap64(uint64_t x) { return _byteswap_uint64(x); }
129
#else
130
131
static inline uint32_t rotl(uint32_t x) { return (x << 8) | (x >> 24); }
132
static inline uint32_t rotr(uint32_t x) { return (x >> 8) | (x << 24); }
133
134
static inline uint64_t bswap64(uint64_t x) {
135
        uint32_t high = (uint32_t)(x >> 32);
136
        uint32_t low = (uint32_t)x;
137
138
        high = (rotl(high) & 0x00ff00ff) | (rotr(high) & 0xff00ff00);
139
        low = (rotl(low) & 0x00ff00ff) | (rotr(low) & 0xff00ff00);
140
        return ((uint64_t)low) << 32 | (uint64_t)high;
141
}
142
#endif
143
144
0
static inline uint64_t getword(block const *block, size_t i) {
145
0
#ifndef ENABLE_DEBUG_WEIRD_ENDIAN
146
0
        if (I_AM_BIG_ENDIAN) {
147
0
                return block->word[i];
148
0
        } else if (I_AM_LITTLE_ENDIAN) {
149
0
                return bswap64(block->word[i]);
150
0
        } else {
151
0
#endif
152
0
                i <<= 3;
153
0
                return ((uint64_t)block->byte[i + 7]) |
154
0
                       ((uint64_t)block->byte[i + 6] << 8) |
155
0
                       ((uint64_t)block->byte[i + 5] << 16) |
156
0
                       ((uint64_t)block->byte[i + 4] << 24) |
157
0
                       ((uint64_t)block->byte[i + 3] << 32) |
158
0
                       ((uint64_t)block->byte[i + 2] << 40) |
159
0
                       ((uint64_t)block->byte[i + 1] << 48) |
160
0
                       ((uint64_t)block->byte[i] << 56);
161
0
#ifndef ENABLE_DEBUG_WEIRD_ENDIAN
162
0
        }
163
0
#endif
164
0
}
165
166
0
static inline void putword(block *block, size_t i, uint64_t x) {
167
0
#ifndef ENABLE_DEBUG_WEIRD_ENDIAN
168
0
        if (I_AM_BIG_ENDIAN) {
169
0
                block->word[i] = x;
170
0
        } else if (I_AM_LITTLE_ENDIAN) {
171
0
                block->word[i] = bswap64(x);
172
0
        } else {
173
0
#endif
174
0
                i <<= 3;
175
0
                block->byte[i] = (unsigned char)(x >> 56);
176
0
                block->byte[i + 1] = (unsigned char)((x >> 48) & 0xff);
177
0
                block->byte[i + 2] = (unsigned char)((x >> 40) & 0xff);
178
0
                block->byte[i + 3] = (unsigned char)((x >> 32) & 0xff);
179
0
                block->byte[i + 4] = (unsigned char)((x >> 24) & 0xff);
180
0
                block->byte[i + 5] = (unsigned char)((x >> 16) & 0xff);
181
0
                block->byte[i + 6] = (unsigned char)((x >> 8) & 0xff);
182
0
                block->byte[i + 7] = (unsigned char)(x & 0xff);
183
0
#ifndef ENABLE_DEBUG_WEIRD_ENDIAN
184
0
        }
185
0
#endif
186
0
}
187
188
0
static inline void xorblock(block *x, block const *y) {
189
0
        x->word[0] ^= y->word[0];
190
0
        x->word[1] ^= y->word[1];
191
0
}
192
193
/* Doubles `block`, which is 16 bytes representing an element
194
   of GF(2**128) modulo the irreducible polynomial
195
   x**128 + x**7 + x**2 + x + 1. */
196
0
static inline void dbl(block *block) {
197
0
        uint64_t high = getword(block, 0);
198
0
        uint64_t low = getword(block, 1);
199
0
        uint64_t high_carry = high & (((uint64_t)1) << 63);
200
0
        uint64_t low_carry = low & (((uint64_t)1) << 63);
201
        /* Assumes two's-complement arithmetic */
202
0
        int64_t low_mask = -((int64_t)(high_carry >> 63)) & 0x87;
203
0
        uint64_t high_mask = low_carry >> 63;
204
0
        high = (high << 1) | high_mask;
205
0
        low = (low << 1) ^ (uint64_t)low_mask;
206
0
        putword(block, 0, high);
207
0
        putword(block, 1, low);
208
0
}
209
210
struct AES_SIV_CTX_st {
211
        /* d stores intermediate results of S2V; it corresponds to D from the
212
           pseudocode in section 2.4 of RFC 5297. */
213
        block d;
214
        EVP_CIPHER_CTX *cipher_ctx;
215
        /* SIV_AES_Init() sets up cmac_ctx_init. cmac_ctx is a scratchpad used
216
           by SIV_AES_AssociateData() and SIV_AES_(En|De)cryptFinal. */
217
        CMAC_CTX *cmac_ctx_init, *cmac_ctx;
218
};
219
220
0
void AES_SIV_CTX_cleanup(AES_SIV_CTX *ctx) {
221
0
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
222
0
        EVP_CIPHER_CTX_reset(ctx->cipher_ctx);
223
#else
224
        EVP_CIPHER_CTX_cleanup(ctx->cipher_ctx);
225
#endif
226
227
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER <= 0x10100060L
228
  /* Workaround for an OpenSSL bug that causes a double free
229
     if you call CMAC_CTX_cleanup() before CMAC_CTX_free().
230
     https://github.com/openssl/openssl/pull/2798
231
  */
232
  CMAC_CTX_free(ctx->cmac_ctx_init);
233
  ctx->cmac_ctx_init = CMAC_CTX_new();
234
  CMAC_CTX_free(ctx->cmac_ctx);
235
  ctx->cmac_ctx = CMAC_CTX_new();
236
#else
237
0
        CMAC_CTX_cleanup(ctx->cmac_ctx_init);
238
0
        CMAC_CTX_cleanup(ctx->cmac_ctx);
239
0
#endif
240
0
        OPENSSL_cleanse(&ctx->d, sizeof ctx->d);
241
0
}
242
243
0
void AES_SIV_CTX_free(AES_SIV_CTX *ctx) {
244
0
        if (ctx) {
245
0
                EVP_CIPHER_CTX_free(ctx->cipher_ctx);
246
                /* Prior to OpenSSL 1.0.2b, CMAC_CTX_free() crashes on NULL */
247
0
                if (LIKELY(ctx->cmac_ctx_init != NULL)) {
248
0
                        CMAC_CTX_free(ctx->cmac_ctx_init);
249
0
                }
250
0
                if (LIKELY(ctx->cmac_ctx != NULL)) {
251
0
                        CMAC_CTX_free(ctx->cmac_ctx);
252
0
                }
253
0
    OPENSSL_cleanse(&ctx->d, sizeof ctx->d);
254
0
                OPENSSL_free(ctx);
255
0
        }
256
0
}
257
258
0
AES_SIV_CTX *AES_SIV_CTX_new(void) {
259
0
        AES_SIV_CTX *ctx = OPENSSL_malloc(sizeof(struct AES_SIV_CTX_st));
260
0
        if (UNLIKELY(ctx == NULL)) {
261
0
                return NULL;
262
0
        }
263
264
0
        ctx->cipher_ctx = EVP_CIPHER_CTX_new();
265
0
        ctx->cmac_ctx_init = CMAC_CTX_new();
266
0
        ctx->cmac_ctx = CMAC_CTX_new();
267
268
0
        if (UNLIKELY(ctx->cipher_ctx == NULL ||
269
0
                     ctx->cmac_ctx_init == NULL ||
270
0
                     ctx->cmac_ctx == NULL)) {
271
0
                AES_SIV_CTX_free(ctx);
272
0
                return NULL;
273
0
        }
274
275
0
        return ctx;
276
0
}
277
278
0
int AES_SIV_CTX_copy(AES_SIV_CTX *dst, AES_SIV_CTX const *src) {
279
0
        memcpy(&dst->d, &src->d, sizeof src->d);
280
0
        if(UNLIKELY(EVP_CIPHER_CTX_copy(dst->cipher_ctx, src->cipher_ctx)
281
0
                    != 1)) {
282
0
                return 0;
283
0
        }
284
0
        if (UNLIKELY(CMAC_CTX_copy(dst->cmac_ctx_init, src->cmac_ctx_init)
285
0
                     != 1)) {
286
0
                return 0;
287
0
        }
288
        /* Not necessary to copy cmac_ctx since it's just temporary
289
         * storage */
290
0
        return 1;
291
0
}
292
293
0
int AES_SIV_Init(AES_SIV_CTX *ctx, unsigned char const *key, size_t key_len) {
294
0
        static const unsigned char zero[] = {0, 0, 0, 0, 0, 0, 0, 0,
295
0
                                             0, 0, 0, 0, 0, 0, 0, 0};
296
0
        size_t out_len;
297
0
        int ret = 0;
298
299
0
        ct_poison(key, key_len);
300
301
0
        switch (key_len) {
302
0
        case 32:
303
0
                if (UNLIKELY(CMAC_Init(ctx->cmac_ctx_init, key, 16,
304
0
                                       EVP_aes_128_cbc(), NULL) != 1)) {
305
0
                        goto done;
306
0
                }
307
0
                if (UNLIKELY(EVP_EncryptInit_ex(ctx->cipher_ctx,
308
0
                                                EVP_aes_128_ctr(),
309
0
                                                NULL, key + 16, NULL) != 1)) {
310
0
                        goto done;
311
0
                }
312
0
                break;
313
0
        case 48:
314
0
                if (UNLIKELY(CMAC_Init(ctx->cmac_ctx_init, key, 24,
315
0
                                       EVP_aes_192_cbc(), NULL) != 1)) {
316
0
                        goto done;
317
0
                }
318
0
                if (UNLIKELY(EVP_EncryptInit_ex(ctx->cipher_ctx,
319
0
                                                EVP_aes_192_ctr(),
320
0
                                                NULL, key + 24, NULL) != 1)) {
321
0
                        goto done;
322
0
                }
323
0
                break;
324
0
        case 64:
325
0
                if (UNLIKELY(CMAC_Init(ctx->cmac_ctx_init, key, 32,
326
0
                                       EVP_aes_256_cbc(), NULL) != 1)) {
327
0
                        goto done;
328
0
                }
329
0
                if (UNLIKELY(EVP_EncryptInit_ex(ctx->cipher_ctx,
330
0
                                                EVP_aes_256_ctr(),
331
0
                                                NULL, key + 32, NULL) != 1)) {
332
0
                        goto done;
333
0
                }
334
0
                break;
335
0
        default:
336
0
                goto done;
337
0
        }
338
339
0
        if (UNLIKELY(CMAC_CTX_copy(ctx->cmac_ctx, ctx->cmac_ctx_init) != 1)) {
340
0
                goto done;
341
0
        }
342
0
        if (UNLIKELY(CMAC_Update(ctx->cmac_ctx, zero, sizeof zero) != 1)) {
343
0
                goto done;
344
0
        }
345
0
        out_len = sizeof ctx->d;
346
0
        if (UNLIKELY(CMAC_Final(ctx->cmac_ctx, ctx->d.byte, &out_len) != 1)) {
347
0
                goto done;
348
0
        }
349
0
        debug("CMAC(zero)", ctx->d.byte, out_len);
350
0
        ret = 1;
351
352
0
 done:
353
0
        ct_unpoison(key, key_len);
354
0
        return ret;
355
0
}
356
357
int AES_SIV_AssociateData(AES_SIV_CTX *ctx, unsigned char const *data,
358
0
                          size_t len) {
359
0
        block cmac_out;
360
0
        size_t out_len = sizeof cmac_out;
361
0
        int ret = 0;
362
363
0
        ct_poison(data, len);
364
365
0
        dbl(&ctx->d);
366
0
        debug("double()", ctx->d.byte, 16);
367
368
0
        if (UNLIKELY(CMAC_CTX_copy(ctx->cmac_ctx, ctx->cmac_ctx_init) != 1)) {
369
0
                goto done;
370
0
        }
371
0
        if (UNLIKELY(CMAC_Update(ctx->cmac_ctx, data, len) != 1)) {
372
0
                goto done;
373
0
        }
374
0
        if (UNLIKELY(CMAC_Final(ctx->cmac_ctx, cmac_out.byte, &out_len) != 1)) {
375
0
                goto done;
376
0
        }
377
0
        assert(out_len == 16);
378
0
        debug("CMAC(ad)", cmac_out.byte, 16);
379
380
0
        xorblock(&ctx->d, &cmac_out);
381
0
        debug("xor", ctx->d.byte, 16);
382
0
        ret = 1;
383
384
0
done:
385
0
        ct_unpoison(data, len);
386
0
        return ret;
387
0
}
388
389
static inline int do_s2v_p(AES_SIV_CTX *ctx, block *out,
390
0
                           unsigned char const* in, size_t len) {
391
0
        block t;
392
0
        size_t out_len = sizeof out->byte;
393
394
0
        if (UNLIKELY(CMAC_CTX_copy(ctx->cmac_ctx, ctx->cmac_ctx_init) != 1)) {
395
0
                return 0;
396
0
        }
397
398
0
        if(len >= 16) {
399
0
                if(UNLIKELY(CMAC_Update(ctx->cmac_ctx, in, len - 16) != 1)) {
400
0
                        return 0;
401
0
                }
402
0
                debug("xorend part 1", in, len - 16);
403
0
                memcpy(&t, in + (len-16), 16);
404
0
                xorblock(&t, &ctx->d);
405
0
                debug("xorend part 2", t.byte, 16);
406
0
                if(UNLIKELY(CMAC_Update(ctx->cmac_ctx, t.byte, 16) != 1)) {
407
0
                        return 0;
408
0
                }
409
0
        } else {
410
0
                size_t i;
411
0
                memcpy(&t, in, len);
412
0
                t.byte[len] = 0x80;
413
0
                for(i = len + 1; i < 16; i++) {
414
0
                        t.byte[i] = 0;
415
0
                }
416
0
                debug("pad", t.byte, 16);
417
0
                dbl(&ctx->d);
418
0
                xorblock(&t, &ctx->d);
419
0
                debug("xor", t.byte, 16);
420
0
                if(UNLIKELY(CMAC_Update(ctx->cmac_ctx, t.byte, 16) != 1)) {
421
0
                        return 0;
422
0
                }
423
0
        }
424
0
        if(UNLIKELY(CMAC_Final(ctx->cmac_ctx, out->byte, &out_len) != 1)) {
425
0
                return 0;
426
0
        }
427
0
        assert(out_len == 16);
428
0
        debug("CMAC(final)", out->byte, 16);
429
0
        return 1;
430
0
}
431
432
static inline int do_encrypt(EVP_CIPHER_CTX *ctx, unsigned char *out,
433
0
                             unsigned char const *in, size_t len, block *icv) {
434
#ifdef ENABLE_DEBUG_TINY_CHUNK_SIZE
435
        const int chunk_size = 7;
436
#else
437
0
        const int chunk_size = 1 << 30;
438
0
#endif
439
0
        size_t len_remaining = len;
440
0
        int out_len;
441
0
        int ret;
442
443
0
        if(UNLIKELY(EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, icv->byte)
444
0
                    != 1)) {
445
0
                return 0;
446
0
        }
447
448
0
        while(UNLIKELY(len_remaining > (size_t)chunk_size)) {
449
0
                out_len = chunk_size;
450
0
                if(UNLIKELY(EVP_EncryptUpdate(ctx, out, &out_len, in, out_len)
451
0
                            != 1)) {
452
0
                        return 0;
453
0
                }
454
0
                assert(out_len == chunk_size);
455
0
                out += out_len;
456
0
                in += out_len;
457
0
                len_remaining -= (size_t)out_len;
458
0
        }
459
460
0
        out_len = (int)len_remaining;
461
0
        ret = EVP_EncryptUpdate(ctx, out, &out_len, in, out_len);
462
0
        assert(!ret || out_len == (int)len_remaining);
463
0
        return ret;
464
0
}
465
466
int AES_SIV_EncryptFinal(AES_SIV_CTX *ctx, unsigned char *v_out,
467
                         unsigned char *c_out, unsigned char const *plaintext,
468
0
                         size_t len) {
469
0
        block q;
470
0
        int ret = 0;
471
472
0
        ct_poison(plaintext, len);
473
474
0
        if(UNLIKELY(do_s2v_p(ctx, &q, plaintext, len) != 1)) {
475
0
                goto done;
476
0
        }
477
478
0
        ct_unpoison(&q, sizeof q);
479
0
        memcpy(v_out, &q, 16);
480
0
        q.byte[8] &= 0x7f;
481
0
        q.byte[12] &= 0x7f;
482
483
0
        if(UNLIKELY(do_encrypt(ctx->cipher_ctx, c_out, plaintext, len, &q)
484
0
                    != 1)) {
485
0
                goto done;
486
0
        }
487
488
0
        ret = 1;
489
0
        debug("ciphertext", c_out, len);
490
491
0
done:
492
0
        ct_unpoison(plaintext, len);
493
0
        ct_unpoison(c_out, len);
494
0
        ct_unpoison(v_out, 16);
495
0
        return ret;
496
0
}
497
498
int AES_SIV_DecryptFinal(AES_SIV_CTX *ctx, unsigned char *out,
499
                         unsigned char const *v, unsigned char const *c,
500
0
                         size_t len) {
501
0
        block t, q;
502
0
        size_t i;
503
0
        uint64_t result;
504
0
        int ret = 0;
505
506
0
        ct_poison(c, len);
507
508
0
        memcpy(&q, v, 16);
509
0
        q.byte[8] &= 0x7f;
510
0
        q.byte[12] &= 0x7f;
511
512
0
        if(UNLIKELY(do_encrypt(ctx->cipher_ctx, out, c, len, &q) != 1)) {
513
0
                goto done;
514
0
        }
515
0
        debug("plaintext", out, len);
516
517
0
        if(UNLIKELY(do_s2v_p(ctx, &t, out, len) != 1)) {
518
0
                goto done;
519
0
        }
520
521
0
        for (i = 0; i < 16; i++) {
522
0
                t.byte[i] ^= v[i];
523
0
        }
524
525
0
        result = t.word[0] | t.word[1];
526
0
        ct_unpoison(&result, sizeof result);
527
0
        ret = !result;
528
529
0
        if(ret) {
530
0
                ct_unpoison(out, len);
531
0
        } else {
532
0
                OPENSSL_cleanse(out, len);
533
0
        }
534
535
0
done:
536
0
        ct_unpoison(c, len);
537
0
        return ret;
538
0
}
539
540
int AES_SIV_Encrypt(AES_SIV_CTX *ctx, unsigned char *out, size_t *out_len,
541
                    unsigned char const *key, size_t key_len,
542
                    unsigned char const *nonce, size_t nonce_len,
543
                    unsigned char const *plaintext, size_t plaintext_len,
544
0
                    unsigned char const *ad, size_t ad_len) {
545
0
        if (UNLIKELY(*out_len < plaintext_len + 16)) {
546
0
                return 0;
547
0
        }
548
0
        *out_len = plaintext_len + 16;
549
550
0
        if (UNLIKELY(AES_SIV_Init(ctx, key, key_len) != 1)) {
551
0
                return 0;
552
0
        }
553
0
        if (UNLIKELY(AES_SIV_AssociateData(ctx, ad, ad_len) != 1)) {
554
0
                return 0;
555
0
        }
556
0
        if (nonce != NULL &&
557
0
            UNLIKELY(AES_SIV_AssociateData(ctx, nonce, nonce_len) != 1)) {
558
0
                return 0;
559
0
        }
560
0
        if (UNLIKELY(AES_SIV_EncryptFinal(ctx, out, out + 16, plaintext,
561
0
                                          plaintext_len) != 1)) {
562
0
                return 0;
563
0
        }
564
565
0
        debug("IV || C", out, *out_len);
566
0
        return 1;
567
0
}
568
569
int AES_SIV_Decrypt(AES_SIV_CTX *ctx, unsigned char *out, size_t *out_len,
570
                    unsigned char const *key, size_t key_len,
571
                    unsigned char const *nonce, size_t nonce_len,
572
                    unsigned char const *ciphertext, size_t ciphertext_len,
573
0
                    unsigned char const *ad, size_t ad_len) {
574
0
        if (UNLIKELY(ciphertext_len < 16)) {
575
0
                return 0;
576
0
        }
577
0
        if (UNLIKELY(*out_len < ciphertext_len - 16)) {
578
0
                return 0;
579
0
        }
580
0
        *out_len = ciphertext_len - 16;
581
582
0
        if (UNLIKELY(AES_SIV_Init(ctx, key, key_len) != 1)) {
583
0
                return 0;
584
0
        }
585
0
        if (UNLIKELY(AES_SIV_AssociateData(ctx, ad, ad_len) != 1)) {
586
0
                return 0;
587
0
        }
588
0
        if (nonce != NULL &&
589
0
            UNLIKELY(AES_SIV_AssociateData(ctx, nonce, nonce_len) != 1)) {
590
0
                return 0;
591
0
        }
592
0
        if (UNLIKELY(AES_SIV_DecryptFinal(ctx, out, ciphertext, ciphertext + 16,
593
0
                                          ciphertext_len - 16) != 1)) {
594
0
                return 0;
595
0
        }
596
0
        debug("plaintext", out, *out_len);
597
0
        return 1;
598
0
}