Coverage Report

Created: 2026-07-16 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xmlsec/src/openssl/ciphers.c
Line
Count
Source
1
/**
2
 * XML Security Library (http://www.aleksey.com/xmlsec).
3
 *
4
 * This is free software; see the Copyright file in the source distribution for precise wording.
5
 *
6
 * Copyright (C) 2002-2026 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved.
7
 */
8
/**
9
 * @addtogroup xmlsec_openssl_crypto
10
 * @brief Ciphers transforms implementation for OpenSSL.
11
 */
12
#include "globals.h"
13
14
#include <string.h>
15
16
#include <openssl/evp.h>
17
#include <openssl/rand.h>
18
19
#include <xmlsec/xmlsec.h>
20
#include <xmlsec/errors.h>
21
#include <xmlsec/keys.h>
22
#include <xmlsec/private.h>
23
#include <xmlsec/transforms.h>
24
#include <xmlsec/xmltree.h>
25
26
#include <xmlsec/openssl/crypto.h>
27
#include <xmlsec/openssl/evp.h>
28
#include "openssl_compat.h"
29
30
#include "../cast_helpers.h"
31
#include "../keysdata_helpers.h"
32
#include "../transform_helpers.h"
33
34
#define XMLSEC_OPENSSL_EVP_CIPHER_PAD_SIZE    (2 * EVP_MAX_BLOCK_LENGTH)
35
0
#define XMLSEC_OPENSSL_AES_GCM_NONCE_SIZE     12
36
0
#define XMLSEC_OPENSSL_AES_GCM_TAG_SIZE       16
37
38
39
/******************************************************************************
40
 *
41
 * Internal OpenSSL Block cipher CTX
42
 *
43
  *****************************************************************************/
44
typedef struct _xmlSecOpenSSLEvpBlockCipherCtx          xmlSecOpenSSLEvpBlockCipherCtx,
45
                                                        *xmlSecOpenSSLEvpBlockCipherCtxPtr;
46
struct _xmlSecOpenSSLEvpBlockCipherCtx {
47
#ifndef XMLSEC_OPENSSL_API_300
48
    const EVP_CIPHER*   cipher;
49
#else /* XMLSEC_OPENSSL_API_300 */
50
    const char*         cipherName;
51
    EVP_CIPHER*         cipher;
52
#endif /* XMLSEC_OPENSSL_API_300 */
53
    xmlSecKeyDataId     keyId;
54
    EVP_CIPHER_CTX*     cipherCtx;
55
    int                 cbcMode;            /* cbc / stream or gcm / aead */
56
    xmlSecOpenSSLUInt   ivLen;
57
    int                 isIvPrepended;   /* iv is prepended to encrypted data or not */
58
    xmlSecSize          ivRandomOffset;
59
60
    xmlSecByte          key[EVP_MAX_KEY_LENGTH];
61
    xmlSecByte          iv[EVP_MAX_IV_LENGTH];
62
    xmlSecByte          pad[XMLSEC_OPENSSL_EVP_CIPHER_PAD_SIZE];
63
    xmlSecBuffer        aad;  /* Additional Authentication Data (AEAD ciphers only) */
64
65
    int                 ctxInitialized;
66
    int                 keyInitialized;
67
    int                 ivInitialized;
68
};
69
70
static int      xmlSecOpenSSLEvpBlockCipherCtxInit      (xmlSecOpenSSLEvpBlockCipherCtxPtr ctx,
71
                                                         xmlSecBufferPtr in,
72
                                                         xmlSecBufferPtr out,
73
                                                         int encrypt,
74
                                                         const xmlChar* cipherName,
75
                                                         xmlSecTransformCtxPtr transformCtx);
76
static int      xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx,
77
                                                         const xmlSecByte * in,
78
                                                         xmlSecSize inSize,
79
                                                         xmlSecBufferPtr out,
80
                                                         const xmlChar* cipherName,
81
                                                         int final,
82
                                                         xmlSecByte *tag);
83
static int      xmlSecOpenSSLEvpBlockCipherCtxUpdate    (xmlSecOpenSSLEvpBlockCipherCtxPtr ctx,
84
                                                         xmlSecBufferPtr in,
85
                                                         xmlSecBufferPtr out,
86
                                                         const xmlChar* cipherName,
87
                                                         xmlSecTransformCtxPtr transformCtx);
88
static int      xmlSecOpenSSLEvpBlockCipherCtxFinal     (xmlSecOpenSSLEvpBlockCipherCtxPtr ctx,
89
                                                         xmlSecBufferPtr in,
90
                                                         xmlSecBufferPtr out,
91
                                                         const xmlChar* cipherName,
92
                                                         xmlSecTransformCtxPtr transformCtx);
93
94
static int
95
xmlSecOpenSSLEvpBlockCipherCtxInit(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx,
96
                                xmlSecBufferPtr in, xmlSecBufferPtr out,
97
                                int encrypt,
98
                                const xmlChar* cipherName,
99
0
                                xmlSecTransformCtxPtr transformCtx) {
100
0
    xmlSecSize ivSize;
101
0
    int ret;
102
103
0
    xmlSecAssert2(ctx != NULL, -1);
104
0
    xmlSecAssert2(ctx->cipher != NULL, -1);
105
0
    xmlSecAssert2(ctx->cipherCtx != NULL, -1);
106
0
    xmlSecAssert2(ctx->ivLen > 0, -1);
107
0
    xmlSecAssert2(ctx->keyInitialized != 0, -1);
108
0
    xmlSecAssert2(ctx->ctxInitialized == 0, -1);
109
0
    xmlSecAssert2(in != NULL, -1);
110
0
    xmlSecAssert2(out != NULL, -1);
111
0
    xmlSecAssert2(transformCtx != NULL, -1);
112
113
0
    XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_SIZE(ctx->ivLen, ivSize, return(-1), NULL);
114
0
    xmlSecAssert2(ivSize <= sizeof(ctx->iv), -1);
115
116
0
    if(!ctx->ivInitialized) {
117
0
        if(encrypt) {
118
0
            xmlSecAssert2(ctx->ivRandomOffset < ivSize, -1);
119
120
            /* generate random iv */
121
0
            ret = xmlSecOpenSSLGenerateRandomBytes(ctx->iv + ctx->ivRandomOffset, ivSize - ctx->ivRandomOffset);
122
0
            if(ret < 0) {
123
0
                xmlSecInternalError("xmlSecOpenSSLGenerateRandom", cipherName);
124
0
                return(-1);
125
0
            }
126
127
0
            if(ctx->isIvPrepended) {
128
                /* write iv to the output (prepend to ciphertext) */
129
0
                ret = xmlSecBufferAppend(out, ctx->iv, ivSize);
130
0
                if(ret < 0) {
131
0
                    xmlSecInternalError2("xmlSecBufferAppend", cipherName, "size=" XMLSEC_SIZE_FMT, ivSize);
132
0
                    return(-1);
133
0
                }
134
0
            }
135
            /* else: IV is written to the XML transform node via NodeWrite */
136
0
        } else {
137
0
            if(!ctx->isIvPrepended) {
138
                /* IV is not prepended to input, it should be in XML transform node */
139
0
                xmlSecInvalidDataError("IV is expected to be in XML transform node", cipherName);
140
0
                return(-1);
141
0
            }
142
143
            /* if we don't have enough data, exit and hope that
144
             * we'll have iv next time */
145
0
            if(xmlSecBufferGetSize(in) < ivSize) {
146
0
                return(0);
147
0
            }
148
149
            /* copy iv to our buffer*/
150
0
            xmlSecAssert2(xmlSecBufferGetData(in) != NULL, -1);
151
0
            memcpy(ctx->iv, xmlSecBufferGetData(in), ivSize);
152
153
            /* and remove from input */
154
0
            ret = xmlSecBufferRemoveHead(in, ivSize);
155
0
            if(ret < 0) {
156
0
                xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName, "size=" XMLSEC_SIZE_FMT, ivSize);
157
0
                return(-1);
158
0
            }
159
0
        }
160
0
        ctx->ivInitialized = 1;
161
0
    }
162
163
    /* set iv */
164
0
    ret = EVP_CipherInit_ex(ctx->cipherCtx, ctx->cipher, NULL, ctx->key, ctx->iv, encrypt);
165
0
    if(ret != 1) {
166
0
        xmlSecOpenSSLError("EVP_CipherInit_ex", cipherName);
167
0
        return(-1);
168
0
    }
169
170
    /* set AAD if present (AEAD ciphers only) */
171
0
    if(ctx->cbcMode == 0) {
172
0
        xmlSecByte* aadData = xmlSecBufferGetData(&(ctx->aad));
173
0
        xmlSecSize aadSize  = xmlSecBufferGetSize(&(ctx->aad));
174
175
0
        if((aadData != NULL) && (aadSize > 0)) {
176
0
            int aadLen, aadOutLen = 0;
177
178
0
            XMLSEC_SAFE_CAST_SIZE_TO_INT(aadSize, aadLen, return(-1), cipherName);
179
0
            ret = EVP_CipherUpdate(ctx->cipherCtx, NULL, &aadOutLen, aadData, aadLen);
180
0
            if(ret != 1) {
181
0
                xmlSecOpenSSLError("EVP_CipherUpdate(aad)", cipherName);
182
0
                return(-1);
183
0
            }
184
0
        }
185
0
    }
186
187
0
    ctx->ctxInitialized = 1;
188
189
    /*
190
     * The padding used in XML Enc does not follow RFC 1423
191
     * and is not supported by OpenSSL. However, it is possible
192
     * to disable padding and do it by yourself
193
     *
194
     * https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html#sec-Alg-Block
195
     */
196
0
    if(ctx->cbcMode != 0) {
197
0
        EVP_CIPHER_CTX_set_padding(ctx->cipherCtx, 0);
198
0
    }
199
200
0
    return(0);
201
0
}
202
203
static int
204
xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx,
205
        const xmlSecByte * in,
206
        xmlSecSize inSize,
207
        xmlSecBufferPtr out,
208
        const xmlChar* cipherName,
209
        int final,
210
0
        xmlSecByte *tagData) {
211
0
    xmlSecByte* outBuf;
212
0
    xmlSecSize outSize, outSize2, blockSize;
213
0
    xmlSecOpenSSLUInt blockLen;
214
0
    int inLen;
215
0
    int outLen = 0;
216
0
    int ret;
217
218
0
    xmlSecAssert2(ctx != NULL, -1);
219
0
    xmlSecAssert2(ctx->cipher != NULL, -1);
220
0
    xmlSecAssert2(ctx->cipherCtx != NULL, -1);
221
0
    xmlSecAssert2(ctx->keyInitialized != 0, -1);
222
0
    xmlSecAssert2(ctx->ctxInitialized != 0, -1);
223
0
    xmlSecAssert2(in != NULL, -1);
224
0
    xmlSecAssert2(out != NULL, -1);
225
226
0
    if (ctx->cbcMode != 0) {
227
0
        xmlSecAssert2(inSize > 0, -1);
228
0
    } else {
229
0
        if (final != 0) {
230
0
            xmlSecAssert2(tagData != NULL, -1);
231
0
        }
232
0
    }
233
234
    /* OpenSSL docs: If the pad parameter is zero then no padding is performed, the total amount of
235
     * data encrypted or decrypted must then be a multiple of the block size or an error will occur.
236
     */
237
0
    blockLen = EVP_CIPHER_block_size(ctx->cipher);
238
0
    xmlSecAssert2(blockLen > 0, -1);
239
240
0
    XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_SIZE(blockLen, blockSize, return(-1), NULL);
241
0
    xmlSecAssert2((inSize % blockSize) == 0, -1);
242
243
0
    outSize = xmlSecBufferGetSize(out);
244
0
    if(ctx->cbcMode != 0) {
245
        /* prepare: ensure we have enough space (+blockLen for final) */
246
0
        ret = xmlSecBufferSetMaxSize(out, outSize + inSize + blockSize);
247
0
        if(ret < 0) {
248
0
            xmlSecInternalError2("xmlSecBufferSetMaxSize",
249
0
                xmlSecErrorsSafeString(cipherName),
250
0
                "size=" XMLSEC_SIZE_FMT, (outSize + inSize + blockSize));
251
0
            return(-1);
252
0
        }
253
0
    } else {
254
        /* prepare: ensure we have enough space */
255
0
        ret = xmlSecBufferSetMaxSize(out, outSize + inSize);
256
0
        if(ret < 0) {
257
0
            xmlSecInternalError2("xmlSecBufferSetMaxSize",
258
0
                xmlSecErrorsSafeString(cipherName),
259
0
                "size=" XMLSEC_SIZE_FMT, (outSize + inSize));
260
0
            return(-1);
261
0
        }
262
0
    }
263
264
0
    outBuf  = xmlSecBufferGetData(out) + outSize;
265
266
    /* encrypt/decrypt */
267
0
    XMLSEC_SAFE_CAST_SIZE_TO_INT(inSize, inLen, return(-1), cipherName);
268
0
    ret = EVP_CipherUpdate(ctx->cipherCtx, outBuf, &outLen, in, inLen);
269
0
    if(ret != 1) {
270
0
        xmlSecOpenSSLError("EVP_CipherUpdate", cipherName);
271
0
        return(-1);
272
0
    }
273
0
    xmlSecAssert2(outLen == inLen, -1);
274
275
    /* finalize transform if needed */
276
0
    if(final != 0) {
277
0
        int outLen2 = 0;
278
279
0
        if(ctx->cbcMode == 0) {
280
0
            xmlSecAssert2(tagData != NULL, -1);
281
0
            if(!EVP_CIPHER_CTX_encrypting(ctx->cipherCtx)) {
282
0
                ret = EVP_CIPHER_CTX_ctrl(ctx->cipherCtx, EVP_CTRL_GCM_SET_TAG,
283
0
                    XMLSEC_OPENSSL_AES_GCM_TAG_SIZE, tagData);
284
0
                if(ret != 1) {
285
0
                    xmlSecOpenSSLError("EVP_CIPHER_CTX_ctrl", cipherName);
286
0
                    return(-1);
287
0
                }
288
0
            }
289
0
        }
290
291
0
        ret = EVP_CipherFinal_ex(ctx->cipherCtx, outBuf + outLen, &outLen2);
292
0
        if(ret != 1) {
293
0
            xmlSecOpenSSLError("EVP_CipherFinal_ex", cipherName);
294
0
            return(-1);
295
0
        }
296
297
0
        if(ctx->cbcMode == 0) {
298
0
            xmlSecAssert2(tagData != NULL, -1);
299
0
            if(EVP_CIPHER_CTX_encrypting(ctx->cipherCtx)) {
300
0
                ret = EVP_CIPHER_CTX_ctrl(ctx->cipherCtx, EVP_CTRL_GCM_GET_TAG,
301
0
                    XMLSEC_OPENSSL_AES_GCM_TAG_SIZE, tagData);
302
0
                if(ret != 1) {
303
0
                    xmlSecOpenSSLError("EVP_CIPHER_CTX_ctrl", cipherName);
304
0
                    return(-1);
305
0
                }
306
0
            }
307
0
        }
308
309
0
        outLen += outLen2;
310
0
    }
311
0
    XMLSEC_SAFE_CAST_INT_TO_SIZE(outLen, outSize2, return(-1), NULL);
312
313
    /* set correct output buffer size */
314
0
    ret = xmlSecBufferSetSize(out, outSize + outSize2);
315
0
    if(ret < 0) {
316
0
        xmlSecInternalError2("xmlSecBufferSetSize", cipherName,
317
0
            "size=" XMLSEC_SIZE_FMT, (outSize + outSize2));
318
0
        return(-1);
319
0
    }
320
321
    /* done */
322
0
    return (0);
323
0
}
324
325
static int
326
xmlSecOpenSSLEvpBlockCipherCtxUpdate(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx,
327
                                     xmlSecBufferPtr in, xmlSecBufferPtr out,
328
                                     const xmlChar* cipherName,
329
0
                                     xmlSecTransformCtxPtr transformCtx) {
330
0
    xmlSecSize inSize, blockSize, inBlocksSize;
331
0
    xmlSecOpenSSLUInt blockLen;
332
0
    xmlSecByte* inBuf;
333
0
    int ret;
334
335
0
    xmlSecAssert2(ctx != NULL, -1);
336
0
    xmlSecAssert2(ctx->cipherCtx != NULL, -1);
337
0
    xmlSecAssert2(ctx->keyInitialized != 0, -1);
338
0
    xmlSecAssert2(ctx->ctxInitialized != 0, -1);
339
0
    xmlSecAssert2(in != NULL, -1);
340
0
    xmlSecAssert2(out != NULL, -1);
341
0
    xmlSecAssert2(transformCtx != NULL, -1);
342
343
0
    blockLen = EVP_CIPHER_block_size(ctx->cipher);
344
0
    xmlSecAssert2(blockLen > 0, -1);
345
0
    XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_SIZE(blockLen, blockSize, return(-1), NULL);
346
347
    /* determine how much data we can process right now */
348
0
    inSize = xmlSecBufferGetSize(in);
349
0
    if(ctx->cbcMode != 0) {
350
0
        if(blockSize > 1) {
351
            /* block cipher: we want to make sure we keep the last chunk in tmp buffer for padding check/removal on decryption */
352
0
            inBlocksSize = blockSize * (inSize / blockSize);
353
0
            if(inBlocksSize == inSize) {
354
0
                inBlocksSize -= blockSize;
355
0
            }
356
0
        } else {
357
            /* stream cipher: process all data immediately (no padding, no need to keep last byte) */
358
0
            xmlSecAssert2(blockSize <= 1, -1);
359
0
            inBlocksSize = inSize;
360
0
        }
361
0
    } else {
362
        /* GCM mode: we want to keep the last bytes in input until the Final() call to verify the tag */
363
0
        if(inSize <= XMLSEC_OPENSSL_AES_GCM_TAG_SIZE) {
364
            /* In GCM mode during decryption the last 16 bytes of the buffer are the tag.
365
             * Make sure there are always at least 16 bytes left over until we know we're
366
             * processing the last buffer */
367
0
            return(0);
368
0
        }
369
370
        /* ensure we keep the last 16 bytes around until the Final() call */
371
0
        inBlocksSize = blockSize * ((inSize - XMLSEC_OPENSSL_AES_GCM_TAG_SIZE) / blockSize);
372
0
    }
373
0
    if(inBlocksSize == 0) {
374
0
        return(0);
375
0
    }
376
377
    /* process the blocks */
378
0
    inBuf = xmlSecBufferGetData(in);
379
0
    ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, inBuf, inBlocksSize, out, cipherName, 0, NULL); /* not final */
380
0
    if(ret < 0) {
381
0
        xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", cipherName);
382
0
        return(-1);
383
0
    }
384
385
    /* remove the processed block from input */
386
0
    ret = xmlSecBufferRemoveHead(in, inBlocksSize);
387
0
    if(ret < 0) {
388
0
        xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName,
389
0
            "size=" XMLSEC_SIZE_FMT, inBlocksSize);
390
0
        return(-1);
391
0
    }
392
393
    /* just a double check */
394
0
    inSize = xmlSecBufferGetSize(in);
395
0
    if(ctx->cbcMode != 0    ) {
396
0
        if(blockSize > 1) {
397
            /* for block ciphers, the last block should remain in input for padding */
398
0
            xmlSecAssert2(inSize > 0, -1);
399
0
            xmlSecAssert2(inSize <= blockSize, -1);
400
0
        }
401
        /* for stream ciphers (blockSize == 1), all data was processed, input may be empty */
402
0
    } else {
403
        /* GCM: tag bytes should still remain in input */
404
0
        xmlSecAssert2(inSize > 0, -1);
405
0
    }
406
407
    /* done */
408
0
    return(0);
409
0
}
410
411
412
static int
413
xmlSecOpenSSLEvpBlockCipherCBCCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx,
414
        xmlSecBufferPtr in,
415
        xmlSecBufferPtr out,
416
        const xmlChar* cipherName,
417
        xmlSecTransformCtxPtr transformCtx XMLSEC_ATTRIBUTE_UNUSED)
418
0
{
419
0
    xmlSecSize size, inSize, outSize;
420
0
    xmlSecOpenSSLUInt inLen, outLen, padLen, blockLen;
421
0
    xmlSecByte* inBuf;
422
0
    xmlSecByte* outBuf;
423
0
    int ret;
424
425
0
    xmlSecAssert2(ctx != NULL, -1);
426
0
    xmlSecAssert2(ctx->cipher != NULL, -1);
427
0
    xmlSecAssert2(ctx->cipherCtx != NULL, -1);
428
0
    xmlSecAssert2(ctx->keyInitialized != 0, -1);
429
0
    xmlSecAssert2(ctx->ctxInitialized != 0, -1);
430
0
    xmlSecAssert2(in != NULL, -1);
431
0
    xmlSecAssert2(out != NULL, -1);
432
0
    UNREFERENCED_PARAMETER(transformCtx);
433
434
0
    blockLen = EVP_CIPHER_block_size(ctx->cipher);
435
0
    xmlSecAssert2(blockLen > 0, -1);
436
0
    xmlSecAssert2(blockLen <= EVP_MAX_BLOCK_LENGTH, -1);
437
438
    /* not more than one block left */
439
0
    inSize = xmlSecBufferGetSize(in);
440
0
    inBuf = xmlSecBufferGetData(in);
441
442
0
    if(blockLen <= 1) {
443
0
        xmlSecSize outSize2;
444
0
        int outLen2 = 0;
445
446
        /* stream cipher (e.g. ChaCha20): no padding, all data should already be processed by Update() */
447
0
        xmlSecAssert2(inSize == 0, -1);
448
449
        /* no remaining data; finalize the cipher (returns 0 bytes for stream ciphers) */
450
0
        outSize = xmlSecBufferGetSize(out);
451
0
        ret = xmlSecBufferSetMaxSize(out, outSize + EVP_MAX_BLOCK_LENGTH);
452
0
        if(ret < 0) {
453
0
            xmlSecInternalError("xmlSecBufferSetMaxSize", cipherName);
454
0
            return(-1);
455
0
        }
456
0
        outBuf = xmlSecBufferGetData(out);
457
0
        xmlSecAssert2(outBuf != NULL, -1);
458
0
        outBuf += outSize;
459
460
        /* process */
461
0
        ret = EVP_CipherFinal_ex(ctx->cipherCtx, outBuf, &outLen2);
462
0
        if(ret != 1) {
463
0
            xmlSecOpenSSLError("EVP_CipherFinal_ex", cipherName);
464
0
            return(-1);
465
0
        }
466
0
        XMLSEC_SAFE_CAST_INT_TO_SIZE(outLen2, outSize2, return(-1), NULL);
467
468
        /* set correct output buffer size */
469
0
        ret = xmlSecBufferSetSize(out, outSize + outSize2);
470
0
        if(ret < 0) {
471
0
            xmlSecInternalError2("xmlSecBufferSetSize", cipherName, "size=" XMLSEC_SIZE_FMT, (outSize + outSize2));
472
0
            return(-1);
473
0
        }
474
475
        /* done */
476
0
        return(0);
477
0
    }
478
479
    /*
480
    * The padding used in XML Enc does not follow RFC 1423
481
    * and is not supported by OpenSSL. However, it is possible
482
    * to disable padding and do it by yourself
483
    *
484
    * https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html#sec-Alg-Block
485
    */
486
0
    XMLSEC_OPENSSL_SAFE_CAST_SIZE_TO_UINT(inSize, inLen, return(-1), NULL);
487
0
    xmlSecAssert2(inLen <= blockLen, -1);
488
489
0
    if(EVP_CIPHER_CTX_encrypting(ctx->cipherCtx)) {
490
        /* figure out pad length, if it is 0 (i.e. inLen == blockLen) then set it to blockLen */
491
0
        padLen = blockLen - inLen;
492
0
        if(padLen == 0) {
493
0
            padLen = blockLen;
494
0
        }
495
0
        xmlSecAssert2(padLen > 0, -1);
496
0
        xmlSecAssert2((inLen + padLen) <= XMLSEC_OPENSSL_EVP_CIPHER_PAD_SIZE, -1);
497
498
        /* we can have inLen == 0 if there were no data at all, otherwise -- copy the data */
499
0
        if(inLen > 0) {
500
0
            XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_SIZE(inLen, size, return(-1), NULL);
501
0
            memcpy(ctx->pad, inBuf, size);
502
0
        }
503
504
        /* generate random padding */
505
0
        if(padLen > 1) {
506
0
            XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_SIZE(padLen, size, return(-1), NULL);
507
0
            ret = xmlSecOpenSSLGenerateRandomBytes(ctx->pad + inLen, size - 1);
508
0
            if(ret < 0) {
509
0
                xmlSecInternalError("xmlSecOpenSSLGenerateRandom", cipherName);
510
0
                return(-1);
511
0
            }
512
0
        }
513
514
        /* set the last byte to the pad length */
515
0
        outLen = inLen + padLen;
516
0
        XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_BYTE(padLen, ctx->pad[outLen - 1], return(-1), cipherName);
517
518
        /* update the last 1 or 2 blocks with padding */
519
0
        XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_SIZE(outLen, outSize, return(-1), NULL);
520
0
        ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, ctx->pad, outSize, out, cipherName, 1, NULL); /* final */
521
0
        if(ret < 0) {
522
0
            xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", cipherName);
523
0
            return(-1);
524
0
        }
525
0
    } else {
526
0
        xmlSecSize padSize;
527
528
        /* update the last one block with padding */
529
0
        ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, inBuf, inSize, out, cipherName, 1, NULL); /* final */
530
0
        if(ret < 0) {
531
0
            xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", cipherName);
532
0
            return(-1);
533
0
        }
534
535
        /* we expect at least one block in the output -- the one we just decrypted */
536
0
        outBuf = xmlSecBufferGetData(out);
537
0
        outSize = xmlSecBufferGetSize(out);
538
0
        XMLSEC_OPENSSL_SAFE_CAST_SIZE_TO_UINT(outSize, outLen, return(-1), NULL);
539
0
        if(outLen < blockLen) {
540
0
            xmlSecInvalidDataError("data length is less than block size for cipher", cipherName);
541
0
            return(-1);
542
0
        }
543
544
        /* get the pad length from the last byte */
545
0
        padLen = outBuf[outLen - 1];
546
0
        if(padLen > blockLen) {
547
0
            xmlSecInvalidDataError("padding length is greater than block size for cipher", cipherName);
548
0
            return(-1);
549
0
        }
550
0
        xmlSecAssert2(padLen <= outLen, -1);
551
552
        /* remove the padding */
553
0
        XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_SIZE(padLen, padSize, return(-1), NULL);
554
0
        ret = xmlSecBufferRemoveTail(out, padSize);
555
0
        if(ret < 0) {
556
0
            xmlSecInternalError("xmlSecBufferRemoveTail", cipherName);
557
0
            return(-1);
558
0
        }
559
0
    }
560
561
    /* remove the processed block from input */
562
0
    ret = xmlSecBufferRemoveHead(in, inSize);
563
0
    if(ret < 0) {
564
0
        xmlSecInternalError("xmlSecBufferRemoveHead", cipherName);
565
0
        return(-1);
566
0
    }
567
568
    /* done */
569
0
    return(0);
570
571
0
}
572
573
static int
574
xmlSecOpenSSLEvpBlockCipherGCMCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx,
575
        xmlSecBufferPtr in,
576
        xmlSecBufferPtr out,
577
        const xmlChar* cipherName,
578
        xmlSecTransformCtxPtr transformCtx)
579
0
{
580
0
    xmlSecSize inSize, outSize;
581
0
    xmlSecByte* inBuf;
582
0
    xmlSecByte* outBuf;
583
0
    xmlSecByte tag[XMLSEC_OPENSSL_AES_GCM_TAG_SIZE];
584
0
    int ret;
585
586
    /* unreferenced parameter */
587
0
    (void)transformCtx;
588
589
0
    xmlSecAssert2(ctx != NULL, -1);
590
0
    xmlSecAssert2(ctx->cipher != NULL, -1);
591
0
    xmlSecAssert2(ctx->cipherCtx != NULL, -1);
592
0
    xmlSecAssert2(ctx->keyInitialized != 0, -1);
593
0
    xmlSecAssert2(ctx->ctxInitialized != 0, -1);
594
0
    xmlSecAssert2(in != NULL, -1);
595
0
    xmlSecAssert2(out != NULL, -1);
596
0
    xmlSecAssert2(transformCtx != NULL, -1);
597
598
0
    inSize = xmlSecBufferGetSize(in);
599
0
    inBuf = xmlSecBufferGetData(in);
600
601
0
    if(EVP_CIPHER_CTX_encrypting(ctx->cipherCtx)) {
602
0
        ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, inBuf, inSize, out, cipherName, 1, tag); /* final */
603
0
        if(ret < 0) {
604
0
            xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", cipherName);
605
0
            return(-1);
606
0
        }
607
608
        /* get the tag and add to the output */
609
0
        outSize = xmlSecBufferGetSize(out);
610
0
        ret = xmlSecBufferSetMaxSize(out, outSize + XMLSEC_OPENSSL_AES_GCM_TAG_SIZE);
611
0
        if(ret < 0) {
612
0
            xmlSecInternalError("xmlSecBufferSetMaxSize", cipherName);
613
0
            return(-1);
614
0
        }
615
0
        outBuf = xmlSecBufferGetData(out) + outSize;
616
0
        memcpy(outBuf, tag, XMLSEC_OPENSSL_AES_GCM_TAG_SIZE);
617
0
        ret = xmlSecBufferSetSize(out, outSize + XMLSEC_OPENSSL_AES_GCM_TAG_SIZE);
618
0
        if(ret < 0) {
619
0
            xmlSecInternalError("xmlSecBufferSetSize", cipherName);
620
0
            return(-1);
621
0
        }
622
0
    } else {
623
        /* There must be at least 16 bytes in the buffer - the tag and anything left over */
624
0
        xmlSecAssert2(inSize >= XMLSEC_OPENSSL_AES_GCM_TAG_SIZE, -1);
625
626
        /* extract the tag */
627
0
        memcpy(tag, inBuf + inSize - XMLSEC_OPENSSL_AES_GCM_TAG_SIZE, XMLSEC_OPENSSL_AES_GCM_TAG_SIZE);
628
0
        ret = xmlSecBufferRemoveTail(in, XMLSEC_OPENSSL_AES_GCM_TAG_SIZE);
629
0
        if(ret < 0) {
630
0
            xmlSecInternalError("xmlSecBufferRemoveTail", cipherName);
631
0
            return(-1);
632
0
        }
633
634
0
        inBuf = xmlSecBufferGetData(in);
635
0
        inSize = xmlSecBufferGetSize(in);
636
637
        /* Decrypt anything remaining and verify the tag */
638
0
        ret = xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock(ctx, inBuf, inSize, out, cipherName, 1, tag); /* final */
639
0
        if(ret < 0) {
640
0
            xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxUpdateBlock", cipherName);
641
0
            return(-1);
642
0
        }
643
0
    }
644
645
    /* remove the processed data from input */
646
0
    ret = xmlSecBufferRemoveHead(in, inSize);
647
0
    if(ret < 0) {
648
0
        xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName,
649
0
                             "size=" XMLSEC_SIZE_FMT, inSize);
650
0
        return(-1);
651
0
    }
652
653
    /* done */
654
0
    return(0);
655
0
}
656
657
static int
658
xmlSecOpenSSLEvpBlockCipherCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx,
659
        xmlSecBufferPtr in,
660
        xmlSecBufferPtr out,
661
        const xmlChar* cipherName,
662
        xmlSecTransformCtxPtr transformCtx)
663
0
{
664
0
    xmlSecAssert2(ctx != NULL, -1);
665
666
0
    if (ctx->cbcMode != 0) {
667
0
        return xmlSecOpenSSLEvpBlockCipherCBCCtxFinal(ctx, in, out, cipherName, transformCtx);
668
0
    } else {
669
0
        return xmlSecOpenSSLEvpBlockCipherGCMCtxFinal(ctx, in, out, cipherName, transformCtx);
670
0
    }
671
0
}
672
673
674
/******************************************************************************
675
 *
676
 * EVP Block Cipher transforms
677
 *
678
  *****************************************************************************/
679
0
XMLSEC_TRANSFORM_DECLARE(OpenSSLEvpBlockCipher, xmlSecOpenSSLEvpBlockCipherCtx)
680
0
#define xmlSecOpenSSLEvpBlockCipherSize XMLSEC_TRANSFORM_SIZE(OpenSSLEvpBlockCipher)
681
0
682
0
static int      xmlSecOpenSSLEvpBlockCipherInitialize   (xmlSecTransformPtr transform);
683
0
static void     xmlSecOpenSSLEvpBlockCipherFinalize     (xmlSecTransformPtr transform);
684
0
static int      xmlSecOpenSSLEvpBlockCipherSetKeyReq    (xmlSecTransformPtr transform,
685
0
                                                         xmlSecKeyReqPtr keyReq);
686
0
static int      xmlSecOpenSSLEvpBlockCipherSetKey       (xmlSecTransformPtr transform,
687
0
                                                         xmlSecKeyPtr key);
688
0
static int      xmlSecOpenSSLEvpBlockCipherExecute      (xmlSecTransformPtr transform,
689
0
                                                         int last,
690
0
                                                         xmlSecTransformCtxPtr transformCtx);
691
0
static int      xmlSecOpenSSLEvpBlockCipherCheckId      (xmlSecTransformPtr transform);
692
0
693
0
694
0
695
0
static int
696
0
xmlSecOpenSSLEvpBlockCipherCheckId(xmlSecTransformPtr transform) {
697
0
#ifndef XMLSEC_NO_DES
698
0
    if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformDes3CbcId)) {
699
0
        return(1);
700
0
    }
701
0
#endif /* XMLSEC_NO_DES */
702
703
0
#ifndef XMLSEC_NO_AES
704
0
    if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes128CbcId) ||
705
0
       xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes192CbcId) ||
706
0
       xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes256CbcId) ||
707
0
       xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes128GcmId) ||
708
0
       xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes192GcmId) ||
709
0
       xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes256GcmId)) {
710
711
0
       return(1);
712
0
    }
713
0
#endif /* XMLSEC_NO_AES */
714
715
0
#ifndef XMLSEC_NO_CAMELLIA
716
0
    if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformCamellia128CbcId) ||
717
0
       xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformCamellia192CbcId) ||
718
0
       xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformCamellia256CbcId)) {
719
720
0
       return(1);
721
0
    }
722
0
#endif /* XMLSEC_NO_CAMELLIA */
723
724
0
#ifndef XMLSEC_NO_CHACHA20
725
0
    if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformChaCha20Id) ||
726
0
       xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformChaCha20Poly1305Id)) {
727
0
        return(1);
728
0
    }
729
0
#endif /* XMLSEC_NO_CHACHA20 */
730
731
0
    return(0);
732
0
}
733
734
/* small helper macro to reduce clutter in the code */
735
#ifndef XMLSEC_OPENSSL_API_300
736
#define XMLSEC_OPENSSL_SET_CIPHER(ctx, cipherVal, cipherNameVal) \
737
    (ctx)->cipher = (cipherVal)
738
#else /* XMLSEC_OPENSSL_API_300 */
739
#define XMLSEC_OPENSSL_SET_CIPHER(ctx, cipherVal, cipherNameVal) \
740
0
    (ctx)->cipherName = (cipherNameVal)
741
#endif /* XMLSEC_OPENSSL_API_300 */
742
743
static int
744
0
xmlSecOpenSSLEvpBlockCipherInitialize(xmlSecTransformPtr transform) {
745
0
    xmlSecOpenSSLEvpBlockCipherCtxPtr ctx;
746
0
    int ret;
747
748
0
    xmlSecAssert2(xmlSecOpenSSLEvpBlockCipherCheckId(transform), -1);
749
0
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1);
750
751
0
    ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform);
752
0
    xmlSecAssert2(ctx != NULL, -1);
753
754
0
    memset(ctx, 0, sizeof(xmlSecOpenSSLEvpBlockCipherCtx));
755
756
0
    ret = xmlSecBufferInitialize(&(ctx->aad), 0);
757
0
    if(ret < 0) {
758
0
        xmlSecInternalError("xmlSecBufferInitialize", xmlSecTransformGetName(transform));
759
0
        xmlSecOpenSSLEvpBlockCipherFinalize(transform);
760
0
        return(-1);
761
0
    }
762
763
0
#ifndef XMLSEC_NO_DES
764
0
    if(transform->id == xmlSecOpenSSLTransformDes3CbcId) {
765
0
        XMLSEC_OPENSSL_SET_CIPHER(ctx, EVP_des_ede3_cbc(), XMLSEC_OPENSSL_CIPHER_NAME_DES3_EDE);
766
0
        ctx->keyId      = xmlSecOpenSSLKeyDataDesId;
767
0
        ctx->cbcMode    = 1;
768
0
        ctx->isIvPrepended = 1;
769
0
    } else
770
0
#endif /* XMLSEC_NO_DES */
771
772
0
#ifndef XMLSEC_NO_AES
773
0
    if(transform->id == xmlSecOpenSSLTransformAes128CbcId) {
774
0
        XMLSEC_OPENSSL_SET_CIPHER(ctx, EVP_aes_128_cbc(), XMLSEC_OPENSSL_CIPHER_NAME_AES128_CBC);
775
0
        ctx->keyId      = xmlSecOpenSSLKeyDataAesId;
776
0
        ctx->cbcMode    = 1;
777
0
        ctx->isIvPrepended = 1;
778
0
    } else if(transform->id == xmlSecOpenSSLTransformAes192CbcId) {
779
0
        XMLSEC_OPENSSL_SET_CIPHER(ctx, EVP_aes_192_cbc(), XMLSEC_OPENSSL_CIPHER_NAME_AES192_CBC);
780
0
        ctx->keyId      = xmlSecOpenSSLKeyDataAesId;
781
0
        ctx->cbcMode    = 1;
782
0
        ctx->isIvPrepended = 1;
783
0
    } else if(transform->id == xmlSecOpenSSLTransformAes256CbcId) {
784
0
        XMLSEC_OPENSSL_SET_CIPHER(ctx, EVP_aes_256_cbc(), XMLSEC_OPENSSL_CIPHER_NAME_AES256_CBC);
785
0
        ctx->keyId      = xmlSecOpenSSLKeyDataAesId;
786
0
        ctx->cbcMode    = 1;
787
0
        ctx->isIvPrepended = 1;
788
0
    } else if(transform->id == xmlSecOpenSSLTransformAes128GcmId) {
789
0
        XMLSEC_OPENSSL_SET_CIPHER(ctx, EVP_aes_128_gcm(), XMLSEC_OPENSSL_CIPHER_NAME_AES128_GCM);
790
0
        ctx->keyId      = xmlSecOpenSSLKeyDataAesId;
791
0
        ctx->cbcMode    = 0;
792
0
        ctx->ivLen      = XMLSEC_OPENSSL_AES_GCM_NONCE_SIZE;   /* This is the nonce length for GCM mode rather than an IV */
793
0
        ctx->isIvPrepended = 1;
794
0
    } else if(transform->id == xmlSecOpenSSLTransformAes192GcmId) {
795
0
        XMLSEC_OPENSSL_SET_CIPHER(ctx, EVP_aes_192_gcm(), XMLSEC_OPENSSL_CIPHER_NAME_AES192_GCM);
796
0
        ctx->keyId      = xmlSecOpenSSLKeyDataAesId;
797
0
        ctx->cbcMode    = 0;
798
0
        ctx->ivLen      = XMLSEC_OPENSSL_AES_GCM_NONCE_SIZE;   /* This is the nonce length for GCM mode rather than an IV */
799
0
        ctx->isIvPrepended = 1;
800
0
    } else if(transform->id == xmlSecOpenSSLTransformAes256GcmId) {
801
0
        XMLSEC_OPENSSL_SET_CIPHER(ctx, EVP_aes_256_gcm(), XMLSEC_OPENSSL_CIPHER_NAME_AES256_GCM);
802
0
        ctx->keyId      = xmlSecOpenSSLKeyDataAesId;
803
0
        ctx->cbcMode    = 0;
804
0
        ctx->ivLen      = XMLSEC_OPENSSL_AES_GCM_NONCE_SIZE;   /* This is the nonce length for GCM mode rather than an IV */
805
0
        ctx->isIvPrepended = 1;
806
0
    } else
807
0
#endif /* XMLSEC_NO_AES */
808
809
0
#ifndef XMLSEC_NO_CAMELLIA
810
0
    if(transform->id == xmlSecOpenSSLTransformCamellia128CbcId) {
811
0
        XMLSEC_OPENSSL_SET_CIPHER(ctx, EVP_camellia_128_cbc(), SN_camellia_128_cbc);
812
0
        ctx->keyId      = xmlSecOpenSSLKeyDataCamelliaId;
813
0
        ctx->cbcMode    = 1;
814
0
        ctx->isIvPrepended = 1;
815
0
    } else if(transform->id == xmlSecOpenSSLTransformCamellia192CbcId) {
816
0
        XMLSEC_OPENSSL_SET_CIPHER(ctx, EVP_camellia_192_cbc(), SN_camellia_192_cbc);
817
0
        ctx->keyId      = xmlSecOpenSSLKeyDataCamelliaId;
818
0
        ctx->cbcMode    = 1;
819
0
        ctx->isIvPrepended = 1;
820
0
    } else if(transform->id == xmlSecOpenSSLTransformCamellia256CbcId) {
821
0
        XMLSEC_OPENSSL_SET_CIPHER(ctx, EVP_camellia_256_cbc(), SN_camellia_256_cbc);
822
0
        ctx->keyId      = xmlSecOpenSSLKeyDataCamelliaId;
823
0
        ctx->cbcMode    = 1;
824
0
        ctx->isIvPrepended = 1;
825
0
    } else
826
0
#endif /* XMLSEC_NO_CAMELLIA */
827
828
0
#ifndef XMLSEC_NO_CHACHA20
829
0
    if(transform->id == xmlSecOpenSSLTransformChaCha20Id) {
830
0
        XMLSEC_OPENSSL_SET_CIPHER(ctx, EVP_chacha20(), SN_chacha20);
831
0
        ctx->keyId      = xmlSecOpenSSLKeyDataChaCha20Id;
832
0
        ctx->cbcMode    = 1;                            /* stream cipher treated as CBC-mode (blockLen=1, no padding, IV from XML node) */
833
0
        ctx->ivLen      = XMLSEC_CHACHA20_IV_SIZE;
834
0
        ctx->isIvPrepended = 0;                         /* IV is in XML transform (nonce + counter) */
835
0
    } else if(transform->id == xmlSecOpenSSLTransformChaCha20Poly1305Id) {
836
0
        XMLSEC_OPENSSL_SET_CIPHER(ctx, EVP_chacha20_poly1305(), SN_chacha20_poly1305);
837
0
        ctx->keyId      = xmlSecOpenSSLKeyDataChaCha20Id;
838
0
        ctx->cbcMode    = 0;                            /* AEAD cipher (GCM-like mode: no CBC padding, tag appended) */
839
0
        ctx->ivLen      = XMLSEC_CHACHA20_NONCE_SIZE ;  /* This is the nonce length for rather than an IV */
840
0
        ctx->isIvPrepended = 0; /* IV is in XML transform (nonce) */
841
0
    } else
842
0
#endif /* XMLSEC_NO_CHACHA20 */
843
844
0
    if(1) {
845
0
        xmlSecInvalidTransfromError(transform)
846
0
        return(-1);
847
0
    }
848
849
0
#ifdef XMLSEC_OPENSSL_API_300
850
    /* fetch cipher */
851
0
    xmlSecAssert2(ctx->cipherName != NULL, -1);
852
0
    ctx->cipher = EVP_CIPHER_fetch(xmlSecOpenSSLGetLibCtx(), ctx->cipherName, NULL);
853
0
    if(ctx->cipher == NULL) {
854
0
        xmlSecOpenSSLError2("EVP_CIPHER_fetch", xmlSecTransformGetName(transform),
855
0
            "cipherName=%s", xmlSecErrorsSafeString(ctx->cipherName));
856
0
        xmlSecOpenSSLEvpBlockCipherFinalize(transform);
857
0
        return(-1);
858
0
    }
859
0
#endif /* XMLSEC_OPENSSL_API_300 */
860
861
    /* create cipher ctx */
862
0
    ctx->cipherCtx = EVP_CIPHER_CTX_new();
863
0
    if(ctx->cipherCtx == NULL) {
864
0
        xmlSecOpenSSLError("EVP_CIPHER_CTX_new", xmlSecTransformGetName(transform));
865
0
        xmlSecOpenSSLEvpBlockCipherFinalize(transform);
866
0
        return(-1);
867
0
    }
868
869
    /* set IV length if not already set above  */
870
0
    if(ctx->ivLen == 0) {
871
0
        ctx->ivLen = EVP_CIPHER_iv_length(ctx->cipher);
872
0
    }
873
874
875
    /* done */
876
0
    return(0);
877
0
}
878
879
static void
880
0
xmlSecOpenSSLEvpBlockCipherFinalize(xmlSecTransformPtr transform) {
881
0
    xmlSecOpenSSLEvpBlockCipherCtxPtr ctx;
882
883
0
    xmlSecAssert(xmlSecOpenSSLEvpBlockCipherCheckId(transform));
884
0
    xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize));
885
886
0
    ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform);
887
0
    xmlSecAssert(ctx != NULL);
888
889
0
    if(ctx->cipherCtx != NULL) {
890
0
        EVP_CIPHER_CTX_free(ctx->cipherCtx);
891
0
    }
892
0
#ifdef XMLSEC_OPENSSL_API_300
893
0
    if(ctx->cipher != NULL) {
894
0
        EVP_CIPHER_free(ctx->cipher);
895
0
    }
896
0
#endif /* XMLSEC_OPENSSL_API_300 */
897
0
    xmlSecBufferFinalize(&(ctx->aad));
898
0
    memset(ctx, 0, sizeof(xmlSecOpenSSLEvpBlockCipherCtx));
899
0
}
900
901
static int
902
0
xmlSecOpenSSLEvpBlockCipherSetKeyReq(xmlSecTransformPtr transform,  xmlSecKeyReqPtr keyReq) {
903
0
    xmlSecOpenSSLEvpBlockCipherCtxPtr ctx;
904
0
    xmlSecOpenSSLUInt cipherKeyLen, keyBitsLen;
905
906
0
    xmlSecAssert2(xmlSecOpenSSLEvpBlockCipherCheckId(transform), -1);
907
0
    xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1);
908
0
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1);
909
0
    xmlSecAssert2(keyReq != NULL, -1);
910
911
0
    ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform);
912
0
    xmlSecAssert2(ctx != NULL, -1);
913
0
    xmlSecAssert2(ctx->cipher != NULL, -1);
914
0
    xmlSecAssert2(ctx->keyId != NULL, -1);
915
916
0
    keyReq->keyId       = ctx->keyId;
917
0
    keyReq->keyType     = xmlSecKeyDataTypeSymmetric;
918
0
    if(transform->operation == xmlSecTransformOperationEncrypt) {
919
0
        keyReq->keyUsage = xmlSecKeyUsageEncrypt;
920
0
    } else {
921
0
        keyReq->keyUsage = xmlSecKeyUsageDecrypt;
922
0
    }
923
924
0
    cipherKeyLen = EVP_CIPHER_key_length(ctx->cipher);
925
0
    xmlSecAssert2(cipherKeyLen > 0, -1);
926
927
0
    keyBitsLen = 8 * cipherKeyLen;
928
0
    XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_SIZE(keyBitsLen, keyReq->keyBitsSize, return(-1), xmlSecTransformGetName(transform));
929
0
    return(0);
930
0
}
931
932
static int
933
0
xmlSecOpenSSLEvpBlockCipherSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) {
934
0
    xmlSecOpenSSLEvpBlockCipherCtxPtr ctx;
935
0
    xmlSecBufferPtr buffer;
936
0
    xmlSecSize cipherKeySize;
937
0
    xmlSecOpenSSLUInt cipherKeyLen;
938
939
0
    xmlSecAssert2(xmlSecOpenSSLEvpBlockCipherCheckId(transform), -1);
940
0
    xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1);
941
0
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1);
942
0
    xmlSecAssert2(key != NULL, -1);
943
944
0
    ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform);
945
0
    xmlSecAssert2(ctx != NULL, -1);
946
0
    xmlSecAssert2(ctx->cipher != NULL, -1);
947
0
    xmlSecAssert2(ctx->keyInitialized == 0, -1);
948
0
    xmlSecAssert2(ctx->keyId != NULL, -1);
949
0
    xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1);
950
951
0
    cipherKeyLen = EVP_CIPHER_key_length(ctx->cipher);
952
0
    xmlSecAssert2(cipherKeyLen > 0, -1);
953
0
    XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_SIZE(cipherKeyLen, cipherKeySize, return(-1), xmlSecTransformGetName(transform));
954
0
    xmlSecAssert2(cipherKeySize <= sizeof(ctx->key), -1);
955
956
0
    buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key));
957
0
    xmlSecAssert2(buffer != NULL, -1);
958
959
0
    if(xmlSecBufferGetSize(buffer) < cipherKeySize) {
960
0
        xmlSecInvalidKeyDataSizeError(xmlSecBufferGetSize(buffer), cipherKeySize,
961
0
            xmlSecTransformGetName(transform));
962
0
        return(-1);
963
0
    }
964
0
    xmlSecAssert2(xmlSecBufferGetData(buffer) != NULL, -1);
965
0
    memcpy(ctx->key, xmlSecBufferGetData(buffer), cipherKeySize);
966
967
0
    ctx->keyInitialized = 1;
968
0
    return(0);
969
0
}
970
971
static int
972
0
xmlSecOpenSSLEvpBlockCipherExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) {
973
0
    xmlSecOpenSSLEvpBlockCipherCtxPtr ctx;
974
0
    xmlSecBufferPtr in, out;
975
0
    int ret;
976
977
0
    xmlSecAssert2(xmlSecOpenSSLEvpBlockCipherCheckId(transform), -1);
978
0
    xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1);
979
0
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1);
980
0
    xmlSecAssert2(transformCtx != NULL, -1);
981
982
0
    in = &(transform->inBuf);
983
0
    out = &(transform->outBuf);
984
985
0
    ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform);
986
0
    xmlSecAssert2(ctx != NULL, -1);
987
988
0
    if(transform->status == xmlSecTransformStatusNone) {
989
0
        transform->status = xmlSecTransformStatusWorking;
990
0
    }
991
992
0
    if(transform->status == xmlSecTransformStatusWorking) {
993
0
        if(ctx->ctxInitialized == 0) {
994
0
            ret = xmlSecOpenSSLEvpBlockCipherCtxInit(ctx, in, out,
995
0
                        (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0,
996
0
                        xmlSecTransformGetName(transform), transformCtx);
997
0
            if(ret < 0) {
998
0
                xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxInit",
999
0
                        xmlSecTransformGetName(transform));
1000
0
                return(-1);
1001
0
            }
1002
0
        }
1003
0
        if((ctx->ctxInitialized == 0) && (last != 0)) {
1004
0
            xmlSecInvalidDataError("not enough data to initialize transform",
1005
0
                    xmlSecTransformGetName(transform));
1006
0
            return(-1);
1007
0
        }
1008
1009
0
        if(ctx->ctxInitialized != 0) {
1010
0
            ret = xmlSecOpenSSLEvpBlockCipherCtxUpdate(ctx, in, out,
1011
0
                    xmlSecTransformGetName(transform),
1012
0
                    transformCtx);
1013
0
            if(ret < 0) {
1014
0
                xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxUpdate",
1015
0
                        xmlSecTransformGetName(transform));
1016
0
                return(-1);
1017
0
            }
1018
0
        }
1019
1020
0
        if(last != 0) {
1021
0
            ret = xmlSecOpenSSLEvpBlockCipherCtxFinal(ctx, in, out,
1022
0
                    xmlSecTransformGetName(transform),
1023
0
                    transformCtx);
1024
0
            if(ret < 0) {
1025
0
                xmlSecInternalError("xmlSecOpenSSLEvpBlockCipherCtxFinal",
1026
0
                        xmlSecTransformGetName(transform));
1027
0
                return(-1);
1028
0
            }
1029
0
            transform->status = xmlSecTransformStatusFinished;
1030
1031
            /* by now there should be no input */
1032
0
            xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1);
1033
0
        }
1034
0
    } else if(transform->status == xmlSecTransformStatusFinished) {
1035
        /* the only way we can get here is if there is no input */
1036
0
        xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1);
1037
0
    } else if(transform->status == xmlSecTransformStatusNone) {
1038
        /* the only way we can get here is if there is no enough data in the input */
1039
0
        xmlSecAssert2(last == 0, -1);
1040
0
    } else {
1041
0
        xmlSecInvalidTransfromStatusError(transform);
1042
0
        return(-1);
1043
0
    }
1044
1045
0
    return(0);
1046
0
}
1047
1048
/* Helper macros to define block cipher transform klasses */
1049
#define XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS_EX(name, readNode, writeNode)                                 \
1050
static xmlSecTransformKlass xmlSecOpenSSL ## name ## Klass = {                                          \
1051
    /* klass/object sizes */                                                                            \
1052
    sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */                              \
1053
    xmlSecOpenSSLEvpBlockCipherSize,            /* xmlSecSize objSize */                                \
1054
    xmlSecName ## name,                         /* const xmlChar* name; */                              \
1055
    xmlSecHref ## name,                         /* const xmlChar* href; */                              \
1056
    xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */                       \
1057
    xmlSecOpenSSLEvpBlockCipherInitialize,      /* xmlSecTransformInitializeMethod initialize; */       \
1058
    xmlSecOpenSSLEvpBlockCipherFinalize,        /* xmlSecTransformFinalizeMethod finalize; */           \
1059
    readNode,                                   /* xmlSecTransformNodeReadMethod readNode; */           \
1060
    writeNode,                                  /* xmlSecTransformNodeWriteMethod writeNode; */         \
1061
    xmlSecOpenSSLEvpBlockCipherSetKeyReq,       /* xmlSecTransformSetKeyReqMethod setKeyReq; */         \
1062
    xmlSecOpenSSLEvpBlockCipherSetKey,          /* xmlSecTransformSetKeyMethod setKey; */               \
1063
    NULL,                                       /* xmlSecTransformValidateMethod validate; */           \
1064
    xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */     \
1065
    xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */             \
1066
    xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */               \
1067
    NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */             \
1068
    NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */               \
1069
    xmlSecOpenSSLEvpBlockCipherExecute,         /* xmlSecTransformExecuteMethod execute; */             \
1070
    NULL,                                       /* void* reserved0; */                                  \
1071
    NULL,                                       /* void* reserved1; */                                  \
1072
};
1073
1074
#define XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS(name)                                                         \
1075
    XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS_EX(name, NULL, NULL)
1076
1077
1078
#ifndef XMLSEC_NO_AES
1079
/******************************************************************************
1080
 *
1081
 * AES CBC cipher transforms
1082
 *
1083
  *****************************************************************************/
1084
/* AES 128 CBC cipher transform: xmlSecOpenSSLAes128CbcKlass */
1085
XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS(Aes128Cbc)
1086
1087
/**
1088
 * @brief AES 128 CBC encryption transform klass.
1089
 * @return pointer to AES 128 CBC encryption transform.
1090
 */
1091
xmlSecTransformId
1092
0
xmlSecOpenSSLTransformAes128CbcGetKlass(void) {
1093
0
    return(&xmlSecOpenSSLAes128CbcKlass);
1094
0
}
1095
1096
/* AES 192 CBC cipher transform: xmlSecOpenSSLAes192CbcKlass */
1097
XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS(Aes192Cbc)
1098
1099
/**
1100
 * @brief AES 192 CBC encryption transform klass.
1101
 * @return pointer to AES 192 CBC encryption transform.
1102
 */
1103
xmlSecTransformId
1104
0
xmlSecOpenSSLTransformAes192CbcGetKlass(void) {
1105
0
    return(&xmlSecOpenSSLAes192CbcKlass);
1106
0
}
1107
1108
/* AES 256 CBC cipher transform: xmlSecOpenSSLAes256CbcKlass */
1109
XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS(Aes256Cbc)
1110
1111
/**
1112
 * @brief AES 256 CBC encryption transform klass.
1113
 * @return pointer to AES 256 CBC encryption transform.
1114
 */
1115
xmlSecTransformId
1116
0
xmlSecOpenSSLTransformAes256CbcGetKlass(void) {
1117
0
    return(&xmlSecOpenSSLAes256CbcKlass);
1118
0
}
1119
1120
/* AES 128 GCM cipher transform: xmlSecOpenSSLAes128GcmKlass */
1121
XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS(Aes128Gcm)
1122
1123
/**
1124
 * @brief AES 128 GCM encryption transform klass.
1125
 * @return pointer to AES 128 GCM encryption transform.
1126
 */
1127
xmlSecTransformId
1128
xmlSecOpenSSLTransformAes128GcmGetKlass(void)
1129
0
{
1130
0
    return(&xmlSecOpenSSLAes128GcmKlass);
1131
0
}
1132
1133
/* AES 192 GCM cipher transform: xmlSecOpenSSLAes192GcmKlass */
1134
XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS(Aes192Gcm)
1135
1136
/**
1137
 * @brief AES 192 GCM encryption transform klass.
1138
 * @return pointer to AES 192 GCM encryption transform.
1139
 */
1140
xmlSecTransformId
1141
xmlSecOpenSSLTransformAes192GcmGetKlass(void)
1142
0
{
1143
0
    return(&xmlSecOpenSSLAes192GcmKlass);
1144
0
}
1145
1146
/* AES 256 GCM cipher transform: xmlSecOpenSSLAes256GcmKlass */
1147
XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS(Aes256Gcm)
1148
1149
/**
1150
 * @brief AES 256 GCM encryption transform klass.
1151
 * @return pointer to AES 256 GCM encryption transform.
1152
 */
1153
xmlSecTransformId
1154
xmlSecOpenSSLTransformAes256GcmGetKlass(void)
1155
0
{
1156
0
    return(&xmlSecOpenSSLAes256GcmKlass);
1157
0
}
1158
1159
#endif /* XMLSEC_NO_AES */
1160
1161
#ifndef XMLSEC_NO_CAMELLIA
1162
/******************************************************************************
1163
 *
1164
 * Camellia CBC cipher transforms
1165
 *
1166
  *****************************************************************************/
1167
/* Camellia 128 CBC cipher transform: xmlSecOpenSSLCamellia128CbcKlass */
1168
XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS(Camellia128Cbc)
1169
1170
/**
1171
 * @brief Camellia 128 CBC encryption transform klass.
1172
 * @return pointer to Camellia 128 CBC encryption transform.
1173
 */
1174
xmlSecTransformId
1175
0
xmlSecOpenSSLTransformCamellia128CbcGetKlass(void) {
1176
0
    return(&xmlSecOpenSSLCamellia128CbcKlass);
1177
0
}
1178
1179
/* Camellia 192 CBC cipher transform: xmlSecOpenSSLCamellia192CbcKlass */
1180
XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS(Camellia192Cbc)
1181
1182
/**
1183
 * @brief Camellia 192 CBC encryption transform klass.
1184
 * @return pointer to Camellia 192 CBC encryption transform.
1185
 */
1186
xmlSecTransformId
1187
0
xmlSecOpenSSLTransformCamellia192CbcGetKlass(void) {
1188
0
    return(&xmlSecOpenSSLCamellia192CbcKlass);
1189
0
}
1190
1191
/* Camellia 256 CBC cipher transform: xmlSecOpenSSLCamellia256CbcKlass */
1192
XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS(Camellia256Cbc)
1193
1194
/**
1195
 * @brief Camellia 256 CBC encryption transform klass.
1196
 * @return pointer to Camellia 256 CBC encryption transform.
1197
 */
1198
xmlSecTransformId
1199
0
xmlSecOpenSSLTransformCamellia256CbcGetKlass(void) {
1200
0
    return(&xmlSecOpenSSLCamellia256CbcKlass);
1201
0
}
1202
1203
#endif /* XMLSEC_NO_CAMELLIA */
1204
1205
#ifndef XMLSEC_NO_DES
1206
/* Triple DES CBC cipher transform: xmlSecOpenSSLDes3CbcKlass */
1207
XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS(Des3Cbc)
1208
1209
/**
1210
 * @brief Triple DES CBC encryption transform klass.
1211
 * @return pointer to Triple DES encryption transform.
1212
 */
1213
xmlSecTransformId
1214
0
xmlSecOpenSSLTransformDes3CbcGetKlass(void) {
1215
0
    return(&xmlSecOpenSSLDes3CbcKlass);
1216
0
}
1217
#endif /* XMLSEC_NO_DES */
1218
1219
#ifndef XMLSEC_NO_CHACHA20
1220
/******************************************************************************
1221
 *
1222
 * ChaCha20 cipher support
1223
 *
1224
  *****************************************************************************/
1225
1226
/******************************************************************************
1227
 *
1228
 * ChaCha20 stream cipher transform (uses xmlSecOpenSSLEvpBlockCipher framework,
1229
 * cbcMode=1 with blockLen=1: no padding, IV provided via XML node params)
1230
 *
1231
  *****************************************************************************/
1232
static int
1233
xmlSecOpenSSLChaCha20NodeRead(xmlSecTransformPtr transform, xmlNodePtr node,
1234
0
                               xmlSecTransformCtxPtr transformCtx) {
1235
0
    xmlSecOpenSSLEvpBlockCipherCtxPtr ctx;
1236
0
    xmlSecSize ivSize = 0;
1237
0
    int noncePresent = 0;
1238
0
    int ret;
1239
1240
0
    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformChaCha20Id), -1);
1241
0
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1);
1242
0
    xmlSecAssert2(node != NULL, -1);
1243
0
    UNREFERENCED_PARAMETER(transformCtx);
1244
1245
0
    ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform);
1246
0
    xmlSecAssert2(ctx != NULL, -1);
1247
0
    xmlSecAssert2(ctx->ivInitialized == 0, -1);
1248
1249
0
    ret = xmlSecTransformChaCha20ParamsRead(node, ctx->iv, sizeof(ctx->iv), &ivSize, &noncePresent);
1250
0
    if((ret < 0) || (ivSize != XMLSEC_CHACHA20_IV_SIZE)) {
1251
0
        xmlSecInternalError("xmlSecTransformChaCha20ParamsRead", xmlSecTransformGetName(transform));
1252
0
        return(-1);
1253
0
    }
1254
1255
0
    if(noncePresent != 0) {
1256
        /* both nonce and counter were present in XML: IV is ready */
1257
0
        ctx->ivInitialized = 1;
1258
0
    } else {
1259
        /* add random nonce agter counter */
1260
0
        ctx->ivRandomOffset = XMLSEC_CHACHA20_COUNTER_SIZE;
1261
0
    }
1262
1263
    /* done */
1264
0
    return(0);
1265
0
}
1266
1267
static int
1268
xmlSecOpenSSLChaCha20NodeWrite(xmlSecTransformPtr transform, xmlNodePtr node,
1269
0
                               xmlSecTransformCtxPtr transformCtx) {
1270
0
    xmlSecOpenSSLEvpBlockCipherCtxPtr ctx;
1271
0
    int ret;
1272
1273
0
    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformChaCha20Id), -1);
1274
0
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1);
1275
0
    xmlSecAssert2(node != NULL, -1);
1276
0
    UNREFERENCED_PARAMETER(transformCtx);
1277
1278
0
    ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform);
1279
0
    xmlSecAssert2(ctx != NULL, -1);
1280
0
    xmlSecAssert2(ctx->ivInitialized != 0, -1);
1281
1282
0
    ret = xmlSecTransformChaCha20ParamsWrite(node, ctx->iv, XMLSEC_CHACHA20_IV_SIZE);
1283
0
    if(ret < 0) {
1284
0
        xmlSecInternalError("xmlSecTransformChaCha20ParamsWrite", xmlSecTransformGetName(transform));
1285
0
        return(-1);
1286
0
    }
1287
1288
0
    return(0);
1289
0
}
1290
1291
/* ChaCha20 cipher transform: xmlSecOpenSSLChaCha20Klass */
1292
XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS_EX(ChaCha20, xmlSecOpenSSLChaCha20NodeRead, xmlSecOpenSSLChaCha20NodeWrite)
1293
1294
/**
1295
 * @brief ChaCha20 stream cipher transform.
1296
 * @return pointer to ChaCha20 transform.
1297
 */
1298
xmlSecTransformId
1299
0
xmlSecOpenSSLTransformChaCha20GetKlass(void) {
1300
0
    return(&xmlSecOpenSSLChaCha20Klass);
1301
0
}
1302
1303
1304
/******************************************************************************
1305
 *
1306
 * ChaCha20-Poly1305 AEAD transform (uses xmlSecOpenSSLEvpBlockCipher framework,
1307
 * cbcMode=0: nonce and AAD provided via XML node params, tag appended to output)
1308
 *
1309
  *****************************************************************************/
1310
static int
1311
xmlSecOpenSSLChaCha20Poly1305NodeRead(xmlSecTransformPtr transform, xmlNodePtr node,
1312
0
                                      xmlSecTransformCtxPtr transformCtx) {
1313
0
    xmlSecOpenSSLEvpBlockCipherCtxPtr ctx;
1314
0
    xmlSecSize ivSize = 0;
1315
0
    int noncePresent = 0;
1316
0
    int ret;
1317
1318
0
    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformChaCha20Poly1305Id), -1);
1319
0
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1);
1320
0
    xmlSecAssert2(node != NULL, -1);
1321
0
    UNREFERENCED_PARAMETER(transformCtx);
1322
1323
0
    ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform);
1324
0
    xmlSecAssert2(ctx != NULL, -1);
1325
0
    xmlSecAssert2(ctx->ivInitialized == 0, -1);
1326
1327
0
    ret = xmlSecTransformChaCha20Poly1305ParamsRead(node, &(ctx->aad), ctx->iv, sizeof(ctx->iv), &ivSize, &noncePresent);
1328
0
    if((ret < 0) || (ivSize != XMLSEC_CHACHA20_NONCE_SIZE)) {
1329
0
        xmlSecInternalError("xmlSecTransformChaCha20Poly1305ParamsRead", xmlSecTransformGetName(transform));
1330
0
        return(-1);
1331
0
    }
1332
1333
0
    if(noncePresent != 0) {
1334
        /* nonce is present in XML: IV is ready */
1335
0
        ctx->ivInitialized = 1;
1336
0
    }
1337
1338
    /* done */
1339
0
    return(0);
1340
0
}
1341
1342
static int
1343
xmlSecOpenSSLChaCha20Poly1305NodeWrite(xmlSecTransformPtr transform, xmlNodePtr node,
1344
0
                                       xmlSecTransformCtxPtr transformCtx) {
1345
0
    xmlSecOpenSSLEvpBlockCipherCtxPtr ctx;
1346
0
    int ret;
1347
1348
0
    xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformChaCha20Poly1305Id), -1);
1349
0
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1);
1350
0
    xmlSecAssert2(node != NULL, -1);
1351
0
    UNREFERENCED_PARAMETER(transformCtx);
1352
1353
0
    ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform);
1354
0
    xmlSecAssert2(ctx != NULL, -1);
1355
0
    xmlSecAssert2(ctx->ivInitialized != 0, -1);
1356
1357
0
    ret = xmlSecTransformChaCha20Poly1305ParamsWrite(node, ctx->iv, XMLSEC_CHACHA20_NONCE_SIZE);
1358
0
    if(ret < 0) {
1359
0
        xmlSecInternalError("xmlSecTransformChaCha20Poly1305ParamsWrite", xmlSecTransformGetName(transform));
1360
0
        return(-1);
1361
0
    }
1362
1363
0
    return(0);
1364
0
}
1365
1366
/* ChaCha20-Poly1305 AEAD cipher transform: xmlSecOpenSSLChaCha20Poly1305Klass */
1367
XMLSEC_OPENSSL_BLOCK_CIPHER_KLASS_EX(ChaCha20Poly1305, xmlSecOpenSSLChaCha20Poly1305NodeRead, xmlSecOpenSSLChaCha20Poly1305NodeWrite)
1368
1369
/**
1370
 * @brief ChaCha20-Poly1305 AEAD encryption transform.
1371
 * @return pointer to ChaCha20-Poly1305 transform.
1372
 */
1373
xmlSecTransformId
1374
0
xmlSecOpenSSLTransformChaCha20Poly1305GetKlass(void) {
1375
0
    return(&xmlSecOpenSSLChaCha20Poly1305Klass);
1376
0
}
1377
1378
#endif /* XMLSEC_NO_CHACHA20 */