Coverage Report

Created: 2024-08-27 12:20

/src/openssl/crypto/modes/siv128.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the OpenSSL license (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 <string.h>
11
#include <stdlib.h>
12
#include <openssl/crypto.h>
13
#include <openssl/evp.h>
14
#include <openssl/core_names.h>
15
#include <openssl/params.h>
16
#include "crypto/modes.h"
17
#include "crypto/siv.h"
18
19
#ifndef OPENSSL_NO_SIV
20
21
__owur static ossl_inline uint32_t rotl8(uint32_t x)
22
0
{
23
0
    return (x << 8) | (x >> 24);
24
0
}
25
26
__owur static ossl_inline uint32_t rotr8(uint32_t x)
27
0
{
28
0
    return (x >> 8) | (x << 24);
29
0
}
30
31
__owur static ossl_inline uint64_t byteswap8(uint64_t x)
32
0
{
33
0
    uint32_t high = (uint32_t)(x >> 32);
34
0
    uint32_t low = (uint32_t)x;
35
36
0
    high = (rotl8(high) & 0x00ff00ff) | (rotr8(high) & 0xff00ff00);
37
0
    low = (rotl8(low) & 0x00ff00ff) | (rotr8(low) & 0xff00ff00);
38
0
    return ((uint64_t)low) << 32 | (uint64_t)high;
39
0
}
40
41
__owur static ossl_inline uint64_t siv128_getword(SIV_BLOCK const *b, size_t i)
42
0
{
43
0
    const union {
44
0
        long one;
45
0
        char little;
46
0
    } is_endian = { 1 };
47
48
0
    if (is_endian.little)
49
0
        return byteswap8(b->word[i]);
50
0
    return b->word[i];
51
0
}
52
53
static ossl_inline void siv128_putword(SIV_BLOCK *b, size_t i, uint64_t x)
54
0
{
55
0
    const union {
56
0
        long one;
57
0
        char little;
58
0
    } is_endian = { 1 };
59
60
0
    if (is_endian.little)
61
0
        b->word[i] = byteswap8(x);
62
0
    else
63
0
        b->word[i] = x;
64
0
}
65
66
static ossl_inline void siv128_xorblock(SIV_BLOCK *x,
67
                                        SIV_BLOCK const *y)
68
0
{
69
0
    x->word[0] ^= y->word[0];
70
0
    x->word[1] ^= y->word[1];
71
0
}
72
73
/*
74
 * Doubles |b|, which is 16 bytes representing an element
75
 * of GF(2**128) modulo the irreducible polynomial
76
 * x**128 + x**7 + x**2 + x + 1.
77
 * Assumes two's-complement arithmetic
78
 */
79
static ossl_inline void siv128_dbl(SIV_BLOCK *b)
80
0
{
81
0
    uint64_t high = siv128_getword(b, 0);
82
0
    uint64_t low = siv128_getword(b, 1);
83
0
    uint64_t high_carry = high & (((uint64_t)1) << 63);
84
0
    uint64_t low_carry = low & (((uint64_t)1) << 63);
85
0
    int64_t low_mask = -((int64_t)(high_carry >> 63)) & 0x87;
86
0
    uint64_t high_mask = low_carry >> 63;
87
88
0
    high = (high << 1) | high_mask;
89
0
    low = (low << 1) ^ (uint64_t)low_mask;
90
0
    siv128_putword(b, 0, high);
91
0
    siv128_putword(b, 1, low);
92
0
}
93
94
__owur static ossl_inline int siv128_do_s2v_p(SIV128_CONTEXT *ctx, SIV_BLOCK *out,
95
                                              unsigned char const* in, size_t len)
96
0
{
97
0
    SIV_BLOCK t;
98
0
    size_t out_len = sizeof(out->byte);
99
0
    EVP_MAC_CTX *mac_ctx;
100
0
    int ret = 0;
101
102
0
    mac_ctx = EVP_MAC_CTX_dup(ctx->mac_ctx_init);
103
0
    if (mac_ctx == NULL)
104
0
        return 0;
105
106
0
    if (len >= SIV_LEN) {
107
0
        if (!EVP_MAC_update(mac_ctx, in, len - SIV_LEN))
108
0
            goto err;
109
0
        memcpy(&t, in + (len-SIV_LEN), SIV_LEN);
110
0
        siv128_xorblock(&t, &ctx->d);
111
0
        if (!EVP_MAC_update(mac_ctx, t.byte, SIV_LEN))
112
0
            goto err;
113
0
    } else {
114
0
        memset(&t, 0, sizeof(t));
115
0
        memcpy(&t, in, len);
116
0
        t.byte[len] = 0x80;
117
0
        siv128_dbl(&ctx->d);
118
0
        siv128_xorblock(&t, &ctx->d);
119
0
        if (!EVP_MAC_update(mac_ctx, t.byte, SIV_LEN))
120
0
            goto err;
121
0
    }
122
0
    if (!EVP_MAC_final(mac_ctx, out->byte, &out_len, sizeof(out->byte))
123
0
        || out_len != SIV_LEN)
124
0
        goto err;
125
126
0
    ret = 1;
127
128
0
err:
129
0
    EVP_MAC_CTX_free(mac_ctx);
130
0
    return ret;
131
0
}
132
133
134
__owur static ossl_inline int siv128_do_encrypt(EVP_CIPHER_CTX *ctx, unsigned char *out,
135
                                             unsigned char const *in, size_t len,
136
                                             SIV_BLOCK *icv)
137
0
{
138
0
    int out_len = (int)len;
139
140
0
    if (!EVP_CipherInit_ex(ctx, NULL, NULL, NULL, icv->byte, 1))
141
0
        return 0;
142
0
    return EVP_EncryptUpdate(ctx, out, &out_len, in, out_len);
143
0
}
144
145
/*
146
 * Create a new SIV128_CONTEXT
147
 */
148
SIV128_CONTEXT *CRYPTO_siv128_new(const unsigned char *key, int klen, EVP_CIPHER* cbc, EVP_CIPHER* ctr)
149
0
{
150
0
    SIV128_CONTEXT *ctx;
151
0
    int ret;
152
153
0
    if ((ctx = OPENSSL_malloc(sizeof(*ctx))) != NULL) {
154
0
        ret = CRYPTO_siv128_init(ctx, key, klen, cbc, ctr);
155
0
        if (ret)
156
0
            return ctx;
157
0
        OPENSSL_free(ctx);
158
0
    }
159
160
0
    return NULL;
161
0
}
162
163
/*
164
 * Initialise an existing SIV128_CONTEXT
165
 */
166
int CRYPTO_siv128_init(SIV128_CONTEXT *ctx, const unsigned char *key, int klen,
167
                       const EVP_CIPHER* cbc, const EVP_CIPHER* ctr)
168
0
{
169
0
    static const unsigned char zero[SIV_LEN] = { 0 };
170
0
    size_t out_len = SIV_LEN;
171
0
    EVP_MAC_CTX *mac_ctx = NULL;
172
0
    OSSL_PARAM params[3];
173
0
    const char *cbc_name = EVP_CIPHER_name(cbc);
174
175
0
    params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER,
176
0
                                                 (char *)cbc_name, 0);
177
0
    params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
178
0
                                                  (void *)key, klen);
179
0
    params[2] = OSSL_PARAM_construct_end();
180
181
0
    memset(&ctx->d, 0, sizeof(ctx->d));
182
0
    ctx->cipher_ctx = NULL;
183
0
    ctx->mac_ctx_init = NULL;
184
185
0
    if (key == NULL || cbc == NULL || ctr == NULL
186
0
            || (ctx->cipher_ctx = EVP_CIPHER_CTX_new()) == NULL
187
            /* TODO(3.0) library context */
188
0
            || (ctx->mac =
189
0
                EVP_MAC_fetch(NULL, OSSL_MAC_NAME_CMAC, NULL)) == NULL
190
0
            || (ctx->mac_ctx_init = EVP_MAC_CTX_new(ctx->mac)) == NULL
191
0
            || !EVP_MAC_CTX_set_params(ctx->mac_ctx_init, params)
192
0
            || !EVP_EncryptInit_ex(ctx->cipher_ctx, ctr, NULL, key + klen, NULL)
193
0
            || (mac_ctx = EVP_MAC_CTX_dup(ctx->mac_ctx_init)) == NULL
194
0
            || !EVP_MAC_update(mac_ctx, zero, sizeof(zero))
195
0
            || !EVP_MAC_final(mac_ctx, ctx->d.byte, &out_len,
196
0
                              sizeof(ctx->d.byte))) {
197
0
        EVP_CIPHER_CTX_free(ctx->cipher_ctx);
198
0
        EVP_MAC_CTX_free(ctx->mac_ctx_init);
199
0
        EVP_MAC_CTX_free(mac_ctx);
200
0
        EVP_MAC_free(ctx->mac);
201
0
        return 0;
202
0
    }
203
0
    EVP_MAC_CTX_free(mac_ctx);
204
205
0
    ctx->final_ret = -1;
206
0
    ctx->crypto_ok = 1;
207
208
0
    return 1;
209
0
}
210
211
/*
212
 * Copy an SIV128_CONTEXT object
213
 */
214
int CRYPTO_siv128_copy_ctx(SIV128_CONTEXT *dest, SIV128_CONTEXT *src)
215
0
{
216
0
    memcpy(&dest->d, &src->d, sizeof(src->d));
217
0
    if (!EVP_CIPHER_CTX_copy(dest->cipher_ctx, src->cipher_ctx))
218
0
        return 0;
219
0
    EVP_MAC_CTX_free(dest->mac_ctx_init);
220
0
    dest->mac_ctx_init = EVP_MAC_CTX_dup(src->mac_ctx_init);
221
0
    if (dest->mac_ctx_init == NULL)
222
0
        return 0;
223
0
    return 1;
224
0
}
225
226
/*
227
 * Provide any AAD. This can be called multiple times.
228
 * Per RFC5297, the last piece of associated data
229
 * is the nonce, but it's not treated special
230
 */
231
int CRYPTO_siv128_aad(SIV128_CONTEXT *ctx, const unsigned char *aad,
232
                      size_t len)
233
0
{
234
0
    SIV_BLOCK mac_out;
235
0
    size_t out_len = SIV_LEN;
236
0
    EVP_MAC_CTX *mac_ctx;
237
238
0
    siv128_dbl(&ctx->d);
239
240
0
    if ((mac_ctx = EVP_MAC_CTX_dup(ctx->mac_ctx_init)) == NULL
241
0
        || !EVP_MAC_update(mac_ctx, aad, len)
242
0
        || !EVP_MAC_final(mac_ctx, mac_out.byte, &out_len,
243
0
                          sizeof(mac_out.byte))
244
0
        || out_len != SIV_LEN) {
245
0
        EVP_MAC_CTX_free(mac_ctx);
246
0
        return 0;
247
0
    }
248
0
    EVP_MAC_CTX_free(mac_ctx);
249
250
0
    siv128_xorblock(&ctx->d, &mac_out);
251
252
0
    return 1;
253
0
}
254
255
/*
256
 * Provide any data to be encrypted. This can be called once.
257
 */
258
int CRYPTO_siv128_encrypt(SIV128_CONTEXT *ctx,
259
                          const unsigned char *in, unsigned char *out,
260
                          size_t len)
261
0
{
262
0
    SIV_BLOCK q;
263
264
    /* can only do one crypto operation */
265
0
    if (ctx->crypto_ok == 0)
266
0
        return 0;
267
0
    ctx->crypto_ok--;
268
269
0
    if (!siv128_do_s2v_p(ctx, &q, in, len))
270
0
        return 0;
271
272
0
    memcpy(ctx->tag.byte, &q, SIV_LEN);
273
0
    q.byte[8] &= 0x7f;
274
0
    q.byte[12] &= 0x7f;
275
276
0
    if (!siv128_do_encrypt(ctx->cipher_ctx, out, in, len, &q))
277
0
        return 0;
278
0
    ctx->final_ret = 0;
279
0
    return len;
280
0
}
281
282
/*
283
 * Provide any data to be decrypted. This can be called once.
284
 */
285
int CRYPTO_siv128_decrypt(SIV128_CONTEXT *ctx,
286
                          const unsigned char *in, unsigned char *out,
287
                          size_t len)
288
0
{
289
0
    unsigned char* p;
290
0
    SIV_BLOCK t, q;
291
0
    int i;
292
293
    /* can only do one crypto operation */
294
0
    if (ctx->crypto_ok == 0)
295
0
        return 0;
296
0
    ctx->crypto_ok--;
297
298
0
    memcpy(&q, ctx->tag.byte, SIV_LEN);
299
0
    q.byte[8] &= 0x7f;
300
0
    q.byte[12] &= 0x7f;
301
302
0
    if (!siv128_do_encrypt(ctx->cipher_ctx, out, in, len, &q)
303
0
        || !siv128_do_s2v_p(ctx, &t, out, len))
304
0
        return 0;
305
306
0
    p = ctx->tag.byte;
307
0
    for (i = 0; i < SIV_LEN; i++)
308
0
        t.byte[i] ^= p[i];
309
310
0
    if ((t.word[0] | t.word[1]) != 0) {
311
0
        OPENSSL_cleanse(out, len);
312
0
        return 0;
313
0
    }
314
0
    ctx->final_ret = 0;
315
0
    return len;
316
0
}
317
318
/*
319
 * Return the already calculated final result.
320
 */
321
int CRYPTO_siv128_finish(SIV128_CONTEXT *ctx)
322
0
{
323
0
    return ctx->final_ret;
324
0
}
325
326
/*
327
 * Set the tag
328
 */
329
int CRYPTO_siv128_set_tag(SIV128_CONTEXT *ctx, const unsigned char *tag, size_t len)
330
0
{
331
0
    if (len != SIV_LEN)
332
0
        return 0;
333
334
    /* Copy the tag from the supplied buffer */
335
0
    memcpy(ctx->tag.byte, tag, len);
336
0
    return 1;
337
0
}
338
339
/*
340
 * Retrieve the calculated tag
341
 */
342
int CRYPTO_siv128_get_tag(SIV128_CONTEXT *ctx, unsigned char *tag, size_t len)
343
0
{
344
0
    if (len != SIV_LEN)
345
0
        return 0;
346
347
    /* Copy the tag into the supplied buffer */
348
0
    memcpy(tag, ctx->tag.byte, len);
349
0
    return 1;
350
0
}
351
352
/*
353
 * Release all resources
354
 */
355
int CRYPTO_siv128_cleanup(SIV128_CONTEXT *ctx)
356
0
{
357
0
    if (ctx != NULL) {
358
0
        EVP_CIPHER_CTX_free(ctx->cipher_ctx);
359
0
        ctx->cipher_ctx = NULL;
360
0
        EVP_MAC_CTX_free(ctx->mac_ctx_init);
361
0
        ctx->mac_ctx_init = NULL;
362
0
        EVP_MAC_free(ctx->mac);
363
0
        ctx->mac = NULL;
364
0
        OPENSSL_cleanse(&ctx->d, sizeof(ctx->d));
365
0
        OPENSSL_cleanse(&ctx->tag, sizeof(ctx->tag));
366
0
        ctx->final_ret = -1;
367
0
        ctx->crypto_ok = 1;
368
0
    }
369
0
    return 1;
370
0
}
371
372
int CRYPTO_siv128_speed(SIV128_CONTEXT *ctx, int arg)
373
0
{
374
0
    ctx->crypto_ok = (arg == 1) ? -1 : 1;
375
0
    return 1;
376
0
}
377
378
#endif                          /* OPENSSL_NO_SIV */