Coverage Report

Created: 2026-07-16 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/providers/implementations/ciphers/cipher_aes_xts.c
Line
Count
Source
1
2
/*
3
 * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved.
4
 *
5
 * Licensed under the Apache License 2.0 (the "License").  You may not use
6
 * this file except in compliance with the License.  You can obtain a copy
7
 * in the file LICENSE in the source distribution or at
8
 * https://www.openssl.org/source/license.html
9
 */
10
11
/*
12
 * AES low level APIs are deprecated for public use, but still ok for internal
13
 * use where we're using them to implement the higher level EVP interface, as is
14
 * the case here.
15
 */
16
#include "internal/deprecated.h"
17
18
#include <openssl/proverr.h>
19
#include "cipher_aes_xts.h"
20
#include "prov/implementations.h"
21
#include "prov/providercommon.h"
22
#include "providers/implementations/ciphers/cipher_aes_xts.inc"
23
24
#define AES_XTS_FLAGS PROV_CIPHER_FLAG_CUSTOM_IV
25
475
#define AES_XTS_IV_BITS 128
26
475
#define AES_XTS_BLOCK_BITS 8
27
28
/* forward declarations */
29
static OSSL_FUNC_cipher_encrypt_init_fn aes_xts_einit;
30
static OSSL_FUNC_cipher_decrypt_init_fn aes_xts_dinit;
31
static OSSL_FUNC_cipher_update_fn aes_xts_stream_update;
32
static OSSL_FUNC_cipher_final_fn aes_xts_stream_final;
33
static OSSL_FUNC_cipher_cipher_fn aes_xts_cipher;
34
static OSSL_FUNC_cipher_freectx_fn aes_xts_freectx;
35
static OSSL_FUNC_cipher_dupctx_fn aes_xts_dupctx;
36
static OSSL_FUNC_cipher_set_ctx_params_fn aes_xts_set_ctx_params;
37
static OSSL_FUNC_cipher_settable_ctx_params_fn aes_xts_settable_ctx_params;
38
39
/*
40
 * Verify that the two keys are different.
41
 *
42
 * This addresses the vulnerability described in Rogaway's
43
 * September 2004 paper:
44
 *
45
 *      "Efficient Instantiations of Tweakable Blockciphers and
46
 *       Refinements to Modes OCB and PMAC".
47
 *      (http://web.cs.ucdavis.edu/~rogaway/papers/offsets.pdf)
48
 *
49
 * FIPS 140-2 IG A.9 XTS-AES Key Generation Requirements states
50
 * that:
51
 *      "The check for Key_1 != Key_2 shall be done at any place
52
 *       BEFORE using the keys in the XTS-AES algorithm to process
53
 *       data with them."
54
 */
55
static int aes_xts_check_keys_differ(const unsigned char *key, size_t bytes,
56
    int enc)
57
473
{
58
473
    if ((!ossl_aes_xts_allow_insecure_decrypt || enc)
59
237
        && CRYPTO_memcmp(key, key + bytes, bytes) == 0) {
60
1
        ERR_raise(ERR_LIB_PROV, PROV_R_XTS_DUPLICATED_KEYS);
61
1
        return 0;
62
1
    }
63
472
    return 1;
64
473
}
65
66
/*-
67
 * Provider dispatch functions
68
 */
69
static int aes_xts_init(void *vctx, const unsigned char *key, size_t keylen,
70
    const unsigned char *iv, size_t ivlen,
71
    const OSSL_PARAM params[], int enc)
72
614
{
73
614
    PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)vctx;
74
614
    PROV_CIPHER_CTX *ctx = &xctx->base;
75
76
614
    if (!ossl_prov_is_running())
77
0
        return 0;
78
79
614
    ctx->enc = enc;
80
81
614
    if (iv != NULL) {
82
141
        if (!ossl_cipher_generic_initiv(vctx, iv, ivlen))
83
0
            return 0;
84
141
    }
85
614
    if (key != NULL) {
86
473
        if (keylen != ctx->keylen) {
87
0
            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
88
0
            return 0;
89
0
        }
90
473
        if (!aes_xts_check_keys_differ(key, keylen / 2, enc))
91
1
            return 0;
92
472
        if (!ctx->hw->init(ctx, key, keylen))
93
0
            return 0;
94
472
    }
95
#ifdef AES_XTS_S390X
96
    else if (xctx->plat.s390x.fc && ctx->iv_set) {
97
        /* special handle iv-only update */
98
        if (!ctx->hw->init(ctx, NULL, 0))
99
            return 0;
100
    }
101
#endif
102
613
    return aes_xts_set_ctx_params(ctx, params);
103
614
}
104
105
static int aes_xts_einit(void *vctx, const unsigned char *key, size_t keylen,
106
    const unsigned char *iv, size_t ivlen,
107
    const OSSL_PARAM params[])
108
237
{
109
237
    return aes_xts_init(vctx, key, keylen, iv, ivlen, params, 1);
110
237
}
111
112
static int aes_xts_dinit(void *vctx, const unsigned char *key, size_t keylen,
113
    const unsigned char *iv, size_t ivlen,
114
    const OSSL_PARAM params[])
115
377
{
116
377
    return aes_xts_init(vctx, key, keylen, iv, ivlen, params, 0);
117
377
}
118
119
static void *aes_xts_newctx(void *provctx, unsigned int mode, uint64_t flags,
120
    size_t kbits, size_t blkbits, size_t ivbits)
121
473
{
122
473
    PROV_AES_XTS_CTX *ctx;
123
124
473
    CIPHER_PROV_CHECK(provctx, AES_128_XTS);
125
473
    ctx = OPENSSL_zalloc(sizeof(*ctx));
126
473
    if (ctx != NULL) {
127
473
        ossl_cipher_generic_initkey(&ctx->base, kbits, blkbits, ivbits, mode,
128
473
            flags, ossl_prov_cipher_hw_aes_xts(kbits),
129
473
            NULL);
130
473
    }
131
473
    return ctx;
132
473
}
133
134
static void aes_xts_freectx(void *vctx)
135
473
{
136
473
    PROV_AES_XTS_CTX *ctx = (PROV_AES_XTS_CTX *)vctx;
137
138
473
    ossl_cipher_generic_reset_ctx((PROV_CIPHER_CTX *)vctx);
139
473
    OPENSSL_clear_free(ctx, sizeof(*ctx));
140
473
}
141
142
static void *aes_xts_dupctx(void *vctx)
143
0
{
144
0
    PROV_AES_XTS_CTX *in = (PROV_AES_XTS_CTX *)vctx;
145
0
    PROV_AES_XTS_CTX *ret = NULL;
146
147
0
    if (!ossl_prov_is_running())
148
0
        return NULL;
149
150
0
    if (in->xts.key1 != NULL) {
151
0
        if (in->xts.key1 != &in->ks1)
152
0
            return NULL;
153
0
    }
154
0
    if (in->xts.key2 != NULL) {
155
0
        if (in->xts.key2 != &in->ks2)
156
0
            return NULL;
157
0
    }
158
0
    ret = OPENSSL_malloc(sizeof(*ret));
159
0
    if (ret == NULL)
160
0
        return NULL;
161
0
    in->base.hw->copyctx(&ret->base, &in->base);
162
0
    return ret;
163
0
}
164
165
static int aes_xts_cipher(void *vctx, unsigned char *out, size_t *outl,
166
    size_t outsize, const unsigned char *in, size_t inl)
167
141
{
168
141
    PROV_AES_XTS_CTX *ctx = (PROV_AES_XTS_CTX *)vctx;
169
170
141
    if (!ossl_prov_is_running()
171
141
        || inl < AES_BLOCK_SIZE
172
141
        || in == NULL
173
141
        || out == NULL)
174
0
        return 0;
175
176
#ifdef AES_XTS_S390X
177
    if (ctx->plat.s390x.fc) {
178
        if (!ctx->plat.s390x.iv_set || !ctx->plat.s390x.key_set)
179
            return 0;
180
    } else
181
#endif
182
141
    {
183
141
        if (ctx->xts.key1 == NULL || ctx->xts.key2 == NULL
184
141
            || !ctx->base.iv_set)
185
0
            return 0;
186
141
    }
187
188
    /*
189
     * Impose a limit of 2^20 blocks per data unit as specified by
190
     * IEEE Std 1619-2018.  The earlier and obsolete IEEE Std 1619-2007
191
     * indicated that this was a SHOULD NOT rather than a MUST NOT.
192
     * NIST SP 800-38E mandates the same limit.
193
     */
194
141
    if (inl > XTS_MAX_BLOCKS_PER_DATA_UNIT * AES_BLOCK_SIZE) {
195
0
        ERR_raise(ERR_LIB_PROV, PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE);
196
0
        return 0;
197
0
    }
198
199
#ifdef AES_XTS_S390X
200
    if (ctx->plat.s390x.fc)
201
        return s390x_aes_xts_cipher_stream(ctx, out, outl, in, inl);
202
#endif
203
204
141
    if (ctx->stream != NULL)
205
0
        (*ctx->stream)(in, out, inl, ctx->xts.key1, ctx->xts.key2, ctx->base.iv);
206
141
    else if (CRYPTO_xts128_encrypt(&ctx->xts, ctx->base.iv, in, out, inl,
207
141
                 ctx->base.enc))
208
0
        return 0;
209
210
141
    *outl = inl;
211
141
    return 1;
212
141
}
213
214
static int aes_xts_stream_update(void *vctx, unsigned char *out, size_t *outl,
215
    size_t outsize, const unsigned char *in,
216
    size_t inl)
217
141
{
218
141
    PROV_AES_XTS_CTX *ctx = (PROV_AES_XTS_CTX *)vctx;
219
220
141
    if (outsize < inl) {
221
0
        ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
222
0
        return 0;
223
0
    }
224
225
141
    if (!aes_xts_cipher(ctx, out, outl, outsize, in, inl)) {
226
0
        ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
227
0
        return 0;
228
0
    }
229
230
141
    return 1;
231
141
}
232
233
static int aes_xts_stream_final(void *vctx, unsigned char *out, size_t *outl,
234
    size_t outsize)
235
141
{
236
141
    if (!ossl_prov_is_running())
237
0
        return 0;
238
141
    *outl = 0;
239
141
    return 1;
240
141
}
241
242
static const OSSL_PARAM *aes_xts_settable_ctx_params(ossl_unused void *cctx,
243
    ossl_unused void *provctx)
244
0
{
245
0
    return aes_xts_set_ctx_params_list;
246
0
}
247
248
static int aes_xts_set_ctx_params(void *vctx, const OSSL_PARAM params[])
249
1.22k
{
250
1.22k
    PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
251
1.22k
    struct aes_xts_set_ctx_params_st p;
252
253
1.22k
    if (ctx == NULL || !aes_xts_set_ctx_params_decoder(params, &p))
254
0
        return 0;
255
256
1.22k
    if (p.keylen != NULL) {
257
0
        size_t keylen;
258
259
0
        if (!OSSL_PARAM_get_size_t(p.keylen, &keylen)) {
260
0
            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
261
0
            return 0;
262
0
        }
263
        /* The key length can not be modified for xts mode */
264
0
        if (keylen != ctx->keylen)
265
0
            return 0;
266
0
    }
267
268
1.22k
    return 1;
269
1.22k
}
270
271
#define IMPLEMENT_cipher(lcmode, UCMODE, kbits, flags)                             \
272
    static OSSL_FUNC_cipher_get_params_fn aes_##kbits##_##lcmode##_get_params;     \
273
    static int aes_##kbits##_##lcmode##_get_params(OSSL_PARAM params[])            \
274
2
    {                                                                              \
275
2
        return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE,    \
276
2
            flags, 2 * kbits, AES_XTS_BLOCK_BITS,                                  \
277
2
            AES_XTS_IV_BITS);                                                      \
278
2
    }                                                                              \
cipher_aes_xts.c:aes_256_xts_get_params
Line
Count
Source
274
1
    {                                                                              \
275
1
        return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE,    \
276
1
            flags, 2 * kbits, AES_XTS_BLOCK_BITS,                                  \
277
1
            AES_XTS_IV_BITS);                                                      \
278
1
    }                                                                              \
cipher_aes_xts.c:aes_128_xts_get_params
Line
Count
Source
274
1
    {                                                                              \
275
1
        return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE,    \
276
1
            flags, 2 * kbits, AES_XTS_BLOCK_BITS,                                  \
277
1
            AES_XTS_IV_BITS);                                                      \
278
1
    }                                                                              \
279
    static OSSL_FUNC_cipher_newctx_fn aes_##kbits##_xts_newctx;                    \
280
    static void *aes_##kbits##_xts_newctx(void *provctx)                           \
281
473
    {                                                                              \
282
473
        return aes_xts_newctx(provctx, EVP_CIPH_##UCMODE##_MODE, flags, 2 * kbits, \
283
473
            AES_XTS_BLOCK_BITS, AES_XTS_IV_BITS);                                  \
284
473
    }                                                                              \
Unexecuted instantiation: cipher_aes_xts.c:aes_256_xts_newctx
cipher_aes_xts.c:aes_128_xts_newctx
Line
Count
Source
281
473
    {                                                                              \
282
473
        return aes_xts_newctx(provctx, EVP_CIPH_##UCMODE##_MODE, flags, 2 * kbits, \
283
473
            AES_XTS_BLOCK_BITS, AES_XTS_IV_BITS);                                  \
284
473
    }                                                                              \
285
    const OSSL_DISPATCH ossl_aes##kbits##xts_functions[] = {                       \
286
        { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))aes_##kbits##_xts_newctx },     \
287
        { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))aes_xts_einit },          \
288
        { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))aes_xts_dinit },          \
289
        { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))aes_xts_stream_update },        \
290
        { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))aes_xts_stream_final },          \
291
        { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))aes_xts_cipher },               \
292
        { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))aes_xts_freectx },             \
293
        { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))aes_xts_dupctx },               \
294
        { OSSL_FUNC_CIPHER_GET_PARAMS,                                             \
295
            (void (*)(void))aes_##kbits##_##lcmode##_get_params },                 \
296
        { OSSL_FUNC_CIPHER_GETTABLE_PARAMS,                                        \
297
            (void (*)(void))ossl_cipher_generic_gettable_params },                 \
298
        { OSSL_FUNC_CIPHER_GET_CTX_PARAMS,                                         \
299
            (void (*)(void))ossl_cipher_generic_get_ctx_params },                  \
300
        { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS,                                    \
301
            (void (*)(void))ossl_cipher_generic_gettable_ctx_params },             \
302
        { OSSL_FUNC_CIPHER_SET_CTX_PARAMS,                                         \
303
            (void (*)(void))aes_xts_set_ctx_params },                              \
304
        { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS,                                    \
305
            (void (*)(void))aes_xts_settable_ctx_params },                         \
306
        OSSL_DISPATCH_END                                                          \
307
    }
308
309
IMPLEMENT_cipher(xts, XTS, 256, AES_XTS_FLAGS);
310
IMPLEMENT_cipher(xts, XTS, 128, AES_XTS_FLAGS);