Coverage Report

Created: 2026-09-17 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/crypto/ascon/ascon_aead128.c
Line
Count
Source
1
/*
2
 * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
#include "crypto/ascon.h"
11
#include <string.h>
12
#include "internal/cryptlib.h"
13
#include <openssl/byteorder.h>
14
#include <openssl/crypto.h>
15
16
0
#define ROR64(x, i) ((x << (64 - i)) | (x >> i))
17
18
/**
19
 * constant addition layer, NIST SP 800-232 Table 5
20
 * 3c 2d 1e 0f f0 e1 d2 c3 b4 a5 96 87 78 69 5a 4b
21
 */
22
#define ASCONPC(x0, x1, x2, x3, x4, rcon) \
23
0
    do {                                  \
24
0
        x2 ^= rcon;                       \
25
0
    } while (0)
26
27
/**
28
 * nonlinear layer, lifted from p43 of
29
 * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/
30
 * documents/finalist-round/updated-spec-doc/ascon-spec-final.pdf
31
 */
32
#define ASCONPS(x0, x1, x2, x3, x4) \
33
0
    do {                            \
34
0
        uint64_t q0, q1;            \
35
0
                                    \
36
0
        x0 ^= x4;                   \
37
0
        x4 ^= x3;                   \
38
0
        x2 ^= x1;                   \
39
0
        q0 = x0 & (~x4);            \
40
0
        q1 = x2 & (~x1);            \
41
0
        x0 ^= q1;                   \
42
0
        q1 = x4 & (~x3);            \
43
0
        x2 ^= q1;                   \
44
0
        q1 = x1 & (~x0);            \
45
0
        x4 ^= q1;                   \
46
0
        q1 = x3 & (~x2);            \
47
0
        x1 ^= q1;                   \
48
0
        x3 ^= q0;                   \
49
0
        x1 ^= x0;                   \
50
0
        x3 ^= x2;                   \
51
0
        x0 ^= x4;                   \
52
0
        x2 = ~x2;                   \
53
0
    } while (0)
54
55
/* linear layer, NIST SP 800-232 Figure 3 */
56
#define ASCONPL(x0, x1, x2, x3, x4)          \
57
0
    do {                                     \
58
0
        x0 ^= ROR64(x0, 19) ^ ROR64(x0, 28); \
59
0
        x1 ^= ROR64(x1, 61) ^ ROR64(x1, 39); \
60
0
        x2 ^= ROR64(x2, 1) ^ ROR64(x2, 6);   \
61
0
        x3 ^= ROR64(x3, 10) ^ ROR64(x3, 17); \
62
0
        x4 ^= ROR64(x4, 7) ^ ROR64(x4, 41);  \
63
0
    } while (0)
64
65
/* one round */
66
#define ASCONP1(x0, x1, x2, x3, x4, rcon)  \
67
0
    do {                                   \
68
0
        ASCONPC(x0, x1, x2, x3, x4, rcon); \
69
0
        ASCONPS(x0, x1, x2, x3, x4);       \
70
0
        ASCONPL(x0, x1, x2, x3, x4);       \
71
0
    } while (0)
72
73
/* 8 rounds */
74
#define ASCONP8(x0, x1, x2, x3, x4)           \
75
0
    do {                                      \
76
0
        ASCONP1(x0, x1, x2, x3, x4, 0xB4ULL); \
77
0
        ASCONP1(x0, x1, x2, x3, x4, 0xA5ULL); \
78
0
        ASCONP1(x0, x1, x2, x3, x4, 0x96ULL); \
79
0
        ASCONP1(x0, x1, x2, x3, x4, 0x87ULL); \
80
0
        ASCONP1(x0, x1, x2, x3, x4, 0x78ULL); \
81
0
        ASCONP1(x0, x1, x2, x3, x4, 0x69ULL); \
82
0
        ASCONP1(x0, x1, x2, x3, x4, 0x5AULL); \
83
0
        ASCONP1(x0, x1, x2, x3, x4, 0x4BULL); \
84
0
    } while (0)
85
86
/* 12 rounds */
87
#define ASCONP12(x0, x1, x2, x3, x4)          \
88
0
    do {                                      \
89
0
        ASCONP1(x0, x1, x2, x3, x4, 0xF0ULL); \
90
0
        ASCONP1(x0, x1, x2, x3, x4, 0xE1ULL); \
91
0
        ASCONP1(x0, x1, x2, x3, x4, 0xD2ULL); \
92
0
        ASCONP1(x0, x1, x2, x3, x4, 0xC3ULL); \
93
0
        ASCONP8(x0, x1, x2, x3, x4);          \
94
0
    } while (0)
95
96
/* misc ascon flags for the context */
97
0
#define ASCONFLG_AAD 0x0000000000000001ULL /* has AAD inputs? */
98
0
#define ASCONFLG_DEC 0x0000000000000002ULL /* in decrypt mode? */
99
0
#define ASCONFLG_DOMAINSEP 0x8000000000000000ULL /* ready to absorb non-AAD? */
100
101
static ossl_inline void ascon_aead128_update(ascon_aead128_ctx *ctx,
102
    unsigned char *out,
103
    const unsigned char *in,
104
    size_t len)
105
0
{
106
0
    uint64_t s0, s1, s2, s3, s4, flags;
107
0
    unsigned char pad = 0x01;
108
109
0
    if (ctx->flags & ASCONFLG_DOMAINSEP) {
110
0
        flags = ctx->flags;
111
0
        if (flags & ASCONFLG_AAD) {
112
0
            ctx->flags = 0;
113
0
            ascon_aead128_update(ctx, NULL, &pad, 1);
114
0
            ASCONP8(ctx->state[0], ctx->state[1], ctx->state[2], ctx->state[3], ctx->state[4]);
115
0
            flags ^= ASCONFLG_AAD;
116
0
            ctx->offset = 0;
117
0
        }
118
0
        ctx->state[4] ^= ASCONFLG_DOMAINSEP;
119
0
        flags ^= ASCONFLG_DOMAINSEP;
120
0
        ctx->flags = flags;
121
0
    }
122
123
0
    s0 = ctx->state[0];
124
0
    s1 = ctx->state[1];
125
0
    s2 = ctx->state[2];
126
0
    s3 = ctx->state[3];
127
0
    s4 = ctx->state[4];
128
129
0
    while (len--) {
130
0
        unsigned char ob, ib = *in++;
131
132
0
        if (ctx->offset >= 16) {
133
0
            ASCONP8(s0, s1, s2, s3, s4);
134
0
            ctx->offset = 0;
135
0
        }
136
137
0
        if (ctx->flags & ASCONFLG_DEC) {
138
0
            if (ctx->offset >= 8) {
139
0
                ob = (unsigned char)(s1 >> 8 * (ctx->offset & 0x7)) ^ ib;
140
0
                s1 ^= (uint64_t)(ob) << 8 * (ctx->offset & 0x7);
141
0
            } else {
142
0
                ob = (unsigned char)(s0 >> 8 * ctx->offset) ^ ib;
143
0
                s0 ^= (uint64_t)(ob) << 8 * ctx->offset;
144
0
            }
145
0
        } else {
146
0
            if (ctx->offset >= 8) {
147
0
                s1 ^= (uint64_t)(ib) << 8 * (ctx->offset & 0x7);
148
0
                ob = (unsigned char)(s1 >> 8 * (ctx->offset & 0x7));
149
0
            } else {
150
0
                s0 ^= (uint64_t)(ib) << 8 * ctx->offset;
151
0
                ob = (unsigned char)(s0 >> 8 * ctx->offset);
152
0
            }
153
0
        }
154
155
0
        if (out != NULL)
156
0
            *out++ = ob;
157
158
0
        ctx->offset++;
159
0
    }
160
161
0
    ctx->state[0] = s0;
162
0
    ctx->state[1] = s1;
163
0
    ctx->state[2] = s2;
164
0
    ctx->state[3] = s3;
165
0
    ctx->state[4] = s4;
166
0
}
167
168
static void ascon_aead128_encrypt_update(ascon_aead128_ctx *ctx, unsigned char *ct,
169
    const unsigned char *pt, size_t len)
170
0
{
171
0
    ascon_aead128_update(ctx, ct, pt, len);
172
0
}
173
174
static void ascon_aead128_decrypt_update(ascon_aead128_ctx *ctx, unsigned char *pt,
175
    const unsigned char *ct, size_t len)
176
0
{
177
0
    ctx->flags |= ASCONFLG_DEC;
178
0
    ascon_aead128_update(ctx, pt, ct, len);
179
0
}
180
181
static void ascon_aead128_init(ascon_aead128_ctx *ctx, const unsigned char *k,
182
    const unsigned char *n)
183
0
{
184
0
    uint64_t s0, s1, s2, s3, s4, k0, k1;
185
186
0
    OPENSSL_load_u64_le(&s1, k);
187
0
    OPENSSL_load_u64_le(&s2, k + 8);
188
0
    OPENSSL_load_u64_le(&s3, n);
189
0
    OPENSSL_load_u64_le(&s4, n + 8);
190
0
    ctx->key[0] = k0 = s1;
191
0
    ctx->key[1] = k1 = s2;
192
0
    s0 = 0x00001000808C0001ULL;
193
0
    ASCONP12(s0, s1, s2, s3, s4);
194
0
    s3 ^= k0;
195
0
    s4 ^= k1;
196
0
    ctx->state[0] = s0;
197
0
    ctx->state[1] = s1;
198
0
    ctx->state[2] = s2;
199
0
    ctx->state[3] = s3;
200
0
    ctx->state[4] = s4;
201
0
    ctx->offset = 0;
202
0
    ctx->flags = ASCONFLG_DOMAINSEP;
203
0
}
204
205
static void ascon_aead128_aad_update(ascon_aead128_ctx *ctx, const unsigned char *in,
206
    size_t len)
207
0
{
208
0
    uint64_t flags;
209
210
0
    flags = ctx->flags;
211
0
    ctx->flags = 0;
212
0
    ascon_aead128_update(ctx, NULL, in, len);
213
0
    ctx->flags = (len > 0) ? flags |= ASCONFLG_AAD : flags;
214
0
}
215
216
static void ascon_aead128_final(ascon_aead128_ctx *ctx, unsigned char *tag)
217
0
{
218
0
    uint64_t s0, s1, s2, s3, s4, k0, k1;
219
0
    unsigned char pad = 0x01;
220
221
0
    ascon_aead128_update(ctx, NULL, NULL, 0);
222
0
    ctx->flags = 0;
223
0
    ascon_aead128_update(ctx, NULL, &pad, 1);
224
225
0
    k0 = ctx->key[0];
226
0
    k1 = ctx->key[1];
227
0
    s0 = ctx->state[0];
228
0
    s1 = ctx->state[1];
229
0
    s2 = ctx->state[2] ^ k0;
230
0
    s3 = ctx->state[3] ^ k1;
231
0
    s4 = ctx->state[4];
232
0
    ASCONP12(s0, s1, s2, s3, s4);
233
0
    s3 ^= k0;
234
0
    s4 ^= k1;
235
0
    OPENSSL_store_u64_le(tag, s3);
236
0
    OPENSSL_store_u64_le(tag + 8, s4);
237
0
}
238
239
/* Provider compatibility wrapper functions */
240
void ossl_ascon_aead128_init(ASCON_AEAD_CTX *ctx, const unsigned char *k,
241
    const unsigned char *n)
242
0
{
243
0
    ascon_aead128_init(ctx, k, n);
244
0
}
245
246
void ossl_ascon_aead128_assoc_data_update(ASCON_AEAD_CTX *ctx,
247
    const unsigned char *in, size_t inl)
248
0
{
249
0
    ascon_aead128_aad_update(ctx, in, inl);
250
0
}
251
252
size_t ossl_ascon_aead128_encrypt_update(ASCON_AEAD_CTX *ctx,
253
    unsigned char *out,
254
    const unsigned char *in, size_t inl)
255
0
{
256
0
    ascon_aead128_encrypt_update(ctx, out, in, inl);
257
0
    return inl;
258
0
}
259
260
size_t ossl_ascon_aead128_decrypt_update(ASCON_AEAD_CTX *ctx,
261
    unsigned char *out,
262
    const unsigned char *in, size_t inl)
263
0
{
264
0
    ascon_aead128_decrypt_update(ctx, out, in, inl);
265
0
    return inl;
266
0
}
267
268
size_t ossl_ascon_aead128_encrypt_final(ASCON_AEAD_CTX *ctx,
269
    unsigned char *out,
270
    unsigned char *tag, size_t tag_len)
271
0
{
272
0
    unsigned char computed_tag[16];
273
274
0
    ascon_aead128_final(ctx, computed_tag);
275
0
    if (tag != NULL && tag_len >= 16)
276
0
        memcpy(tag, computed_tag, 16);
277
0
    if (out != NULL) {
278
        /* No additional output for final */
279
0
    }
280
0
    return 0;
281
0
}
282
283
size_t ossl_ascon_aead128_decrypt_final(ASCON_AEAD_CTX *ctx,
284
    unsigned char *out,
285
    int *is_tag_valid,
286
    const unsigned char *tag,
287
    size_t tag_len)
288
0
{
289
0
    unsigned char computed_tag[16];
290
291
0
    ascon_aead128_final(ctx, computed_tag);
292
0
    if (is_tag_valid != NULL && tag != NULL && tag_len >= 16) {
293
0
        *is_tag_valid = (CRYPTO_memcmp(computed_tag, tag, 16) == 0);
294
0
    } else if (is_tag_valid != NULL) {
295
0
        *is_tag_valid = 0;
296
0
    }
297
0
    return 0;
298
0
}
299
300
void ossl_ascon_aead_cleanup(ASCON_AEAD_CTX *ctx)
301
0
{
302
0
    if (ctx != NULL)
303
0
        OPENSSL_cleanse(ctx, sizeof(ASCON_AEAD_CTX));
304
0
}