/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 */ |