1 /*
2  * XML Security Library (http://www.aleksey.com/xmlsec).
3  *
4  *
5  * This is free software; see Copyright file in the source
6  * distribution for preciese wording.
7  *
8  * Copyright (C) 2018 Miklos Vajna. All Rights Reserved.
9  */
10 /**
11  * SECTION:ciphers
12  * @Short_description: Ciphers transforms implementation for Microsoft Cryptography API: Next Generation (CNG).
13  * @Stability: Private
14  *
15  */
16 #include "globals.h"
17 
18 #include <string.h>
19 
20 #define WIN32_NO_STATUS
21 #include <windows.h>
22 #undef WIN32_NO_STATUS
23 #include <ntstatus.h>
24 #include <bcrypt.h>
25 #include <ncrypt.h>
26 
27 #include <xmlsec/xmlsec.h>
28 #include <xmlsec/xmltree.h>
29 #include <xmlsec/keys.h>
30 #include <xmlsec/keyinfo.h>
31 #include <xmlsec/transforms.h>
32 #include <xmlsec/errors.h>
33 #include <xmlsec/bn.h>
34 
35 #include <xmlsec/mscng/crypto.h>
36 
37 /**************************************************************************
38  *
39  * Internal MSCng Block cipher CTX
40  *
41  *****************************************************************************/
42 typedef struct _xmlSecMSCngBlockCipherCtx xmlSecMSCngBlockCipherCtx, *xmlSecMSCngBlockCipherCtxPtr;
43 
44 struct _xmlSecMSCngBlockCipherCtx {
45     LPCWSTR pszAlgId;
46     BCRYPT_ALG_HANDLE hAlg;
47     BCRYPT_KEY_HANDLE hKey;
48     BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo;
49     PBYTE pbIV;
50     ULONG cbIV;
51     PBYTE pbKeyObject;
52     DWORD dwBlockLen;
53     xmlSecKeyDataId keyId;
54     xmlSecSize keySize;
55     int cbcMode;
56     int ctxInitialized;
57 };
58 
59 #define xmlSecMSCngBlockCipherSize   \
60     (sizeof(xmlSecTransform) + sizeof(xmlSecMSCngBlockCipherCtx))
61 #define xmlSecMSCngBlockCipherGetCtx(transform) \
62     ((xmlSecMSCngBlockCipherCtxPtr)(((unsigned char*)(transform)) + sizeof(xmlSecTransform)))
63 
64 #define xmlSecMSCngAesGcmNonceLengthInBytes 12
65 #define xmlSecMSCngAesGcmTagLengthInBytes 16
66 
67 static int
xmlSecMSCngBlockCipherCheckId(xmlSecTransformPtr transform)68 xmlSecMSCngBlockCipherCheckId(xmlSecTransformPtr transform) {
69 #ifndef XMLSEC_NO_AES
70     if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformAes128CbcId)) {
71        return(1);
72     } else if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformAes192CbcId)) {
73        return(1);
74     } else if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformAes256CbcId)) {
75        return(1);
76     } else if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformAes128GcmId)) {
77        return(1);
78     } else if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformAes192GcmId)) {
79        return(1);
80     } else if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformAes256GcmId)) {
81        return(1);
82     }
83 #endif /* XMLSEC_NO_AES */
84 
85 #ifndef XMLSEC_NO_DES
86     if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformDes3CbcId)) {
87         return(1);
88     }
89 #endif /* XMLSEC_NO_DES */
90 
91     return(0);
92 }
93 
94 static int
xmlSecMSCngBlockCipherInitialize(xmlSecTransformPtr transform)95 xmlSecMSCngBlockCipherInitialize(xmlSecTransformPtr transform) {
96     xmlSecMSCngBlockCipherCtxPtr ctx;
97     NTSTATUS status;
98 
99     xmlSecAssert2(xmlSecMSCngBlockCipherCheckId(transform), -1);
100     xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCngBlockCipherSize), -1);
101 
102     ctx = xmlSecMSCngBlockCipherGetCtx(transform);
103     xmlSecAssert2(ctx != NULL, -1);
104 
105     memset(ctx, 0, sizeof(xmlSecMSCngBlockCipherCtx));
106 
107 #ifndef XMLSEC_NO_AES
108     if(transform->id == xmlSecMSCngTransformAes128CbcId) {
109         ctx->pszAlgId = BCRYPT_AES_ALGORITHM;
110         ctx->keyId = xmlSecMSCngKeyDataAesId;
111         ctx->keySize = 16;
112         ctx->cbcMode = 1;
113     } else if(transform->id == xmlSecMSCngTransformAes192CbcId) {
114         ctx->pszAlgId = BCRYPT_AES_ALGORITHM;
115         ctx->keyId = xmlSecMSCngKeyDataAesId;
116         ctx->keySize = 24;
117         ctx->cbcMode = 1;
118     } else if(transform->id == xmlSecMSCngTransformAes256CbcId) {
119         ctx->pszAlgId = BCRYPT_AES_ALGORITHM;
120         ctx->keyId = xmlSecMSCngKeyDataAesId;
121         ctx->keySize = 32;
122         ctx->cbcMode = 1;
123     } else if(transform->id == xmlSecMSCngTransformAes128GcmId) {
124         ctx->pszAlgId = BCRYPT_AES_ALGORITHM;
125         ctx->keyId = xmlSecMSCngKeyDataAesId;
126         ctx->keySize = 16;
127         ctx->cbcMode = 0;
128     } else if(transform->id == xmlSecMSCngTransformAes192GcmId) {
129         ctx->pszAlgId = BCRYPT_AES_ALGORITHM;
130         ctx->keyId = xmlSecMSCngKeyDataAesId;
131         ctx->keySize = 24;
132         ctx->cbcMode = 0;
133     } else if(transform->id == xmlSecMSCngTransformAes256GcmId) {
134         ctx->pszAlgId = BCRYPT_AES_ALGORITHM;
135         ctx->keyId = xmlSecMSCngKeyDataAesId;
136         ctx->keySize = 32;
137         ctx->cbcMode = 0;
138     } else
139 #endif /* XMLSEC_NO_AES */
140 
141 #ifndef XMLSEC_NO_DES
142     if(transform->id == xmlSecMSCngTransformDes3CbcId) {
143         ctx->pszAlgId = BCRYPT_3DES_ALGORITHM;
144         ctx->keyId = xmlSecMSCngKeyDataDesId;
145         ctx->keySize = 24;
146         ctx->cbcMode = 1;
147     } else
148 #endif /* XMLSEC_NO_DES */
149 
150     {
151         xmlSecInvalidTransfromError(transform)
152         return(-1);
153     }
154 
155     status = BCryptOpenAlgorithmProvider(
156         &ctx->hAlg,
157         ctx->pszAlgId,
158         NULL,
159         0);
160     if(status != STATUS_SUCCESS) {
161         xmlSecMSCngNtError("BCryptOpenAlgorithmProvider",
162             xmlSecTransformGetName(transform), status);
163         return(-1);
164     }
165 
166     if(ctx->cbcMode) {
167         status = BCryptSetProperty(ctx->hAlg,
168                                    BCRYPT_CHAINING_MODE,
169                                    (PUCHAR)BCRYPT_CHAIN_MODE_CBC,
170                                    sizeof(BCRYPT_CHAIN_MODE_CBC),
171                                    0);
172     } else {
173         status = BCryptSetProperty(ctx->hAlg,
174                                    BCRYPT_CHAINING_MODE,
175                                    (PUCHAR)BCRYPT_CHAIN_MODE_GCM,
176                                    sizeof(BCRYPT_CHAIN_MODE_GCM),
177                                    0);
178     }
179     if(status != STATUS_SUCCESS) {
180         xmlSecMSCngNtError("BCryptSetProperty", xmlSecTransformGetName(transform), status);
181         return(-1);
182     }
183 
184     ctx->ctxInitialized = 0;
185 
186     return(0);
187 }
188 
189 static void
xmlSecMSCngBlockCipherFinalize(xmlSecTransformPtr transform)190 xmlSecMSCngBlockCipherFinalize(xmlSecTransformPtr transform) {
191     xmlSecMSCngBlockCipherCtxPtr ctx;
192 
193     xmlSecAssert(xmlSecMSCngBlockCipherCheckId(transform));
194     xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecMSCngBlockCipherSize));
195 
196     ctx = xmlSecMSCngBlockCipherGetCtx(transform);
197     xmlSecAssert(ctx != NULL);
198 
199     if(ctx->pbIV != NULL) {
200         xmlFree(ctx->pbIV);
201     }
202 
203     if(ctx->authInfo.pbNonce != NULL) {
204         xmlFree(ctx->authInfo.pbNonce);
205     }
206     if(ctx->authInfo.pbTag != NULL) {
207         xmlFree(ctx->authInfo.pbTag);
208     }
209     if(ctx->authInfo.pbMacContext != NULL) {
210         xmlFree(ctx->authInfo.pbMacContext);
211     }
212 
213     if(ctx->hKey != NULL) {
214         BCryptDestroyKey(ctx->hKey);
215     }
216 
217     if(ctx->pbKeyObject != NULL) {
218         xmlFree(ctx->pbKeyObject);
219     }
220 
221     if(ctx->hAlg != NULL) {
222         BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
223     }
224 
225     memset(ctx, 0, sizeof(xmlSecMSCngBlockCipherCtx));
226 }
227 
228 static int
xmlSecMSCngBlockCipherSetKeyReq(xmlSecTransformPtr transform,xmlSecKeyReqPtr keyReq)229 xmlSecMSCngBlockCipherSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) {
230     xmlSecMSCngBlockCipherCtxPtr ctx;
231 
232     xmlSecAssert2(xmlSecMSCngBlockCipherCheckId(transform), -1);
233     xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1);
234     xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCngBlockCipherSize), -1);
235     xmlSecAssert2(keyReq != NULL, -1);
236 
237     ctx = xmlSecMSCngBlockCipherGetCtx(transform);
238     xmlSecAssert2(ctx != NULL, -1);
239     xmlSecAssert2(ctx->hAlg != 0, -1);
240 
241     keyReq->keyId = ctx->keyId;
242     keyReq->keyType = xmlSecKeyDataTypeSymmetric;
243     if(transform->operation == xmlSecTransformOperationEncrypt) {
244         keyReq->keyUsage = xmlSecKeyUsageEncrypt;
245     } else {
246         keyReq->keyUsage = xmlSecKeyUsageDecrypt;
247     }
248 
249     keyReq->keyBitsSize = 8 * ctx->keySize;
250     return(0);
251 }
252 
253 static int
xmlSecMSCngBlockCipherSetKey(xmlSecTransformPtr transform,xmlSecKeyPtr key)254 xmlSecMSCngBlockCipherSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) {
255     xmlSecMSCngBlockCipherCtxPtr ctx;
256     xmlSecBufferPtr buffer;
257     xmlSecBuffer blob;
258     BCRYPT_KEY_DATA_BLOB_HEADER* blobHeader;
259     xmlSecSize blobHeaderLen;
260     BYTE* bufData;
261     DWORD dwKeyObjectLength, bytesWritten;
262     NTSTATUS status;
263     int ret;
264 
265     xmlSecAssert2(xmlSecMSCngBlockCipherCheckId(transform), -1);
266     xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1);
267     xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCngBlockCipherSize), -1);
268     xmlSecAssert2(key != NULL, -1);
269 
270     /* get the symmetric key into bufData */
271     ctx = xmlSecMSCngBlockCipherGetCtx(transform);
272     xmlSecAssert2(ctx != NULL, -1);
273     xmlSecAssert2(ctx->hKey == 0, -1);
274     xmlSecAssert2(ctx->keyId != NULL, -1);
275     xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1);
276     xmlSecAssert2(ctx->keySize > 0, -1);
277     xmlSecAssert2(ctx->pbKeyObject == NULL, -1);
278 
279     buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key));
280     xmlSecAssert2(buffer != NULL, -1);
281 
282     if(xmlSecBufferGetSize(buffer) < ctx->keySize) {
283         xmlSecInvalidKeyDataSizeError(xmlSecBufferGetSize(buffer), ctx->keySize,
284             xmlSecTransformGetName(transform));
285         return(-1);
286     }
287 
288     bufData = xmlSecBufferGetData(buffer);
289     xmlSecAssert2(bufData != NULL, -1);
290 
291     /* allocate the key object */
292     dwKeyObjectLength = 0;
293     status = BCryptGetProperty(ctx->hAlg,
294         BCRYPT_OBJECT_LENGTH,
295         (PUCHAR)&dwKeyObjectLength,
296         (ULONG)sizeof(DWORD),
297         &bytesWritten, 0);
298     if(status != STATUS_SUCCESS) {
299         xmlSecMSCngNtError("BCryptGetProperty",
300             xmlSecTransformGetName(transform), status);
301         return(-1);
302     }
303 
304     ctx->pbKeyObject = xmlMalloc(dwKeyObjectLength);
305     if(ctx->pbKeyObject == NULL) {
306         xmlSecMallocError(dwKeyObjectLength, xmlSecTransformGetName(transform));
307         return(-1);
308     }
309 
310     /* prefix the key with a BCRYPT_KEY_DATA_BLOB_HEADER */
311     blobHeaderLen = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + xmlSecBufferGetSize(buffer);
312     ret = xmlSecBufferInitialize(&blob, blobHeaderLen);
313     if(ret < 0) {
314         xmlSecInternalError2("xmlSecBufferInitialize",
315             xmlSecTransformGetName(transform), "size=%d", blobHeaderLen);
316         return(-1);
317     }
318 
319     blobHeader = (BCRYPT_KEY_DATA_BLOB_HEADER*)xmlSecBufferGetData(&blob);
320     blobHeader->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
321     blobHeader->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
322     blobHeader->cbKeyData = (ULONG)xmlSecBufferGetSize(buffer);
323     memcpy(xmlSecBufferGetData(&blob) + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER),
324         bufData, xmlSecBufferGetSize(buffer));
325     xmlSecBufferSetSize(&blob, blobHeaderLen);
326 
327     /* perform the actual import */
328     status = BCryptImportKey(ctx->hAlg,
329         NULL,
330         BCRYPT_KEY_DATA_BLOB,
331         &ctx->hKey,
332         ctx->pbKeyObject,
333         dwKeyObjectLength,
334         xmlSecBufferGetData(&blob),
335         (ULONG)xmlSecBufferGetSize(&blob),
336         0);
337     if(status != STATUS_SUCCESS) {
338         xmlSecMSCngNtError("BCryptImportKey",
339             xmlSecTransformGetName(transform), status);
340         xmlSecBufferFinalize(&blob);
341         return(-1);
342     }
343 
344     xmlSecBufferFinalize(&blob);
345 
346     return(0);
347 }
348 
xmlSecMSCngCBCBlockCipherCtxInit(xmlSecMSCngBlockCipherCtxPtr ctx,xmlSecBufferPtr in,xmlSecBufferPtr out,int encrypt,const xmlChar * cipherName,xmlSecTransformCtxPtr transformCtx)349 static int xmlSecMSCngCBCBlockCipherCtxInit(xmlSecMSCngBlockCipherCtxPtr ctx,
350         xmlSecBufferPtr in, xmlSecBufferPtr out, int encrypt,
351         const xmlChar* cipherName, xmlSecTransformCtxPtr transformCtx) {
352 
353     NTSTATUS status;
354     int ret;
355 
356     /* unreferenced parameter */
357     (void)transformCtx;
358 
359     xmlSecAssert2(ctx != NULL, -1);
360     xmlSecAssert2(ctx->hKey != 0, -1);
361     xmlSecAssert2(ctx->ctxInitialized == 0, -1);
362     xmlSecAssert2(ctx->dwBlockLen > 0, -1);
363     xmlSecAssert2(in != NULL, -1);
364     xmlSecAssert2(out != NULL, -1);
365     xmlSecAssert2(transformCtx != NULL, -1);
366 
367     /* iv len == block len */
368     ctx->cbIV = ctx->dwBlockLen;
369 
370     if(encrypt) {
371         unsigned char* iv;
372         xmlSecSize outSize;
373 
374         /* allocate space for IV */
375         outSize = xmlSecBufferGetSize(out);
376         ret = xmlSecBufferSetSize(out, outSize + ctx->dwBlockLen);
377         if(ret < 0) {
378             xmlSecInternalError2("xmlSecBufferSetSize", cipherName,
379                 "size=%d", outSize + ctx->dwBlockLen);
380             return(-1);
381         }
382         iv = xmlSecBufferGetData(out) + outSize;
383 
384         /* generate and use random iv */
385         status = BCryptGenRandom(NULL,
386             (PBYTE)iv,
387             ctx->dwBlockLen,
388             BCRYPT_USE_SYSTEM_PREFERRED_RNG);
389         if(status != STATUS_SUCCESS) {
390             xmlSecMSCngNtError("BCryptGenRandom", cipherName, status);
391             return(-1);
392         }
393 
394         if(ctx->pbIV == NULL) {
395             ctx->pbIV = xmlMalloc(ctx->dwBlockLen);
396         }
397         if(ctx->pbIV == NULL) {
398             xmlSecMallocError(ctx->dwBlockLen, cipherName);
399             return(-1);
400         }
401 
402         memcpy(ctx->pbIV, iv, ctx->dwBlockLen);
403     } else {
404         /* if we don't have enough data, exit and hope that
405         * we'll have iv next time */
406         if(xmlSecBufferGetSize(in) < XMLSEC_SIZE_BAD_CAST(ctx->dwBlockLen)) {
407             return(0);
408         }
409         xmlSecAssert2(xmlSecBufferGetData(in) != NULL, -1);
410 
411         /* set iv */
412         ctx->pbIV = xmlMalloc(ctx->dwBlockLen);
413         if(ctx->pbIV == NULL) {
414             xmlSecMallocError(ctx->dwBlockLen, cipherName);
415             return(-1);
416         }
417         memcpy(ctx->pbIV, xmlSecBufferGetData(in), ctx->dwBlockLen);
418 
419         /* and remove from input */
420         ret = xmlSecBufferRemoveHead(in, ctx->dwBlockLen);
421         if(ret < 0) {
422             xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName,
423                 "size=%d", ctx->dwBlockLen);
424             return(-1);
425 
426         }
427     }
428 
429     ctx->ctxInitialized = 1;
430     return(0);
431 }
432 
xmlSecMSCngGCMBlockCipherCtxInit(xmlSecMSCngBlockCipherCtxPtr ctx,xmlSecBufferPtr in,xmlSecBufferPtr out,int encrypt,int last,const xmlChar * cipherName,xmlSecTransformCtxPtr transformCtx)433 static int xmlSecMSCngGCMBlockCipherCtxInit(xmlSecMSCngBlockCipherCtxPtr ctx,
434         xmlSecBufferPtr in, xmlSecBufferPtr out, int encrypt, int last,
435         const xmlChar* cipherName, xmlSecTransformCtxPtr transformCtx) {
436 
437     NTSTATUS status;
438     int ret;
439     xmlSecByte *bufferPtr;
440     xmlSecSize bufferSize;
441     DWORD bytesRead;
442     BCRYPT_AUTH_TAG_LENGTHS_STRUCT authTagLengths;
443 
444     /* unreferenced parameter */
445     (void)transformCtx;
446 
447     xmlSecAssert2(ctx != NULL, -1);
448     xmlSecAssert2(ctx->hKey != 0, -1);
449     xmlSecAssert2(ctx->ctxInitialized == 0, -1);
450     xmlSecAssert2(ctx->dwBlockLen > 0, -1);
451     xmlSecAssert2(in != NULL, -1);
452     xmlSecAssert2(out != NULL, -1);
453     xmlSecAssert2(transformCtx != NULL, -1);
454 
455     /* Check that we haven't already allocated space for the nonce. Might
456      * happen if the context is initialised more that once */
457     if(ctx->authInfo.pbNonce == NULL) {
458         ctx->authInfo.pbNonce = xmlMalloc(xmlSecMSCngAesGcmNonceLengthInBytes);
459         if(ctx->authInfo.pbNonce == NULL) {
460             xmlSecMallocError(xmlSecMSCngAesGcmNonceLengthInBytes, cipherName);
461             return(-1);
462         }
463     }
464     ctx->authInfo.cbNonce = xmlSecMSCngAesGcmNonceLengthInBytes;
465 
466     /* Tag length is 128 bits */
467     /* See http://www.w3.org/TR/xmlenc-core1/#sec-AES-GCM */
468     if(ctx->authInfo.pbTag == NULL) {
469         ctx->authInfo.pbTag = xmlMalloc(xmlSecMSCngAesGcmTagLengthInBytes);
470         if(ctx->authInfo.pbTag == NULL) {
471             xmlSecMallocError(xmlSecMSCngAesGcmTagLengthInBytes, cipherName);
472             return(-1);
473         }
474     }
475     memset(ctx->authInfo.pbTag, 0, xmlSecMSCngAesGcmTagLengthInBytes);
476     ctx->authInfo.cbTag = xmlSecMSCngAesGcmTagLengthInBytes;
477 
478     if(last == 0) {
479         /* Need some working buffers */
480 
481         /* iv len == block len */
482         if(ctx->pbIV == NULL) {
483             ctx->pbIV = xmlMalloc(ctx->dwBlockLen);
484             if(ctx->pbIV == NULL) {
485                 xmlSecMallocError(ctx->dwBlockLen, cipherName);
486                 return(-1);
487             }
488         }
489         ctx->cbIV = ctx->dwBlockLen;
490         memset(ctx->pbIV, 0, ctx->dwBlockLen);
491 
492         /* Setup an empty MAC context if we're chaining calls */
493         status = BCryptGetProperty(ctx->hAlg,
494             BCRYPT_AUTH_TAG_LENGTH,
495             (PUCHAR)&authTagLengths,
496             (ULONG)sizeof(authTagLengths),
497             &bytesRead,
498             0);
499         if(status != STATUS_SUCCESS) {
500             xmlSecMSCngNtError("BCryptGetProperty", cipherName, status);
501             return(-1);
502         }
503 
504         if(ctx->authInfo.pbMacContext == NULL) {
505             ctx->authInfo.pbMacContext = xmlMalloc(authTagLengths.dwMaxLength);
506             if(ctx->authInfo.pbMacContext == NULL) {
507                 xmlSecMallocError(authTagLengths.dwMaxLength, cipherName);
508                 return(-1);
509             }
510         }
511         ctx->authInfo.cbMacContext = authTagLengths.dwMaxLength;
512         memset(ctx->authInfo.pbMacContext, 0, authTagLengths.dwMaxLength);
513         ctx->authInfo.dwFlags |= BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG;
514     } else {
515         ctx->pbIV = NULL;
516         ctx->cbIV = 0;
517     }
518 
519     if(encrypt) {
520 
521         /* allocate space for nonce in the output buffer - it is 96 bits for GCM mode */
522         /* See http://www.w3.org/TR/xmlenc-core1/#sec-AES-GCM */
523         bufferSize = xmlSecBufferGetSize(out);
524         ret = xmlSecBufferSetSize(out, bufferSize + xmlSecMSCngAesGcmNonceLengthInBytes);
525         if(ret < 0) {
526             xmlSecInternalError2("xmlSecBufferSetSize", cipherName,
527                 "size=%d", bufferSize + xmlSecMSCngAesGcmNonceLengthInBytes);
528             return(-1);
529         }
530         bufferPtr = xmlSecBufferGetData(out) + bufferSize;
531 
532         /* generate and use random nonce */
533         status = BCryptGenRandom(NULL,
534             (PBYTE)bufferPtr,
535             xmlSecMSCngAesGcmNonceLengthInBytes,
536             BCRYPT_USE_SYSTEM_PREFERRED_RNG);
537         if(status != STATUS_SUCCESS) {
538             xmlSecMSCngNtError("BCryptGenRandom", cipherName, status);
539             return(-1);
540         }
541         /* copy the nonce into the padding info */
542         memcpy(ctx->authInfo.pbNonce, bufferPtr, xmlSecMSCngAesGcmNonceLengthInBytes);
543 
544     } else {
545         /* if we don't have enough data, exit and hope that
546            we'll have the nonce next time */
547         bufferSize = xmlSecBufferGetSize(in);
548         if(bufferSize < xmlSecMSCngAesGcmNonceLengthInBytes) {
549             return(0);
550         }
551 
552         bufferPtr = xmlSecBufferGetData(in);
553 
554         xmlSecAssert2(bufferPtr != NULL, -1);
555 
556         /* set nonce */
557         memcpy(ctx->authInfo.pbNonce, bufferPtr, xmlSecMSCngAesGcmNonceLengthInBytes);
558 
559         /* remove nonce from input */
560         ret = xmlSecBufferRemoveHead(in, xmlSecMSCngAesGcmNonceLengthInBytes);
561         if(ret < 0) {
562             xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName,
563                 "size=%d", xmlSecMSCngAesGcmNonceLengthInBytes);
564             return(-1);
565         }
566     }
567 
568     ctx->ctxInitialized = 1;
569     return(0);
570 }
571 
572 static int
xmlSecMSCngBlockCipherCtxInit(xmlSecMSCngBlockCipherCtxPtr ctx,xmlSecBufferPtr in,xmlSecBufferPtr out,int encrypt,int last,const xmlChar * cipherName,xmlSecTransformCtxPtr transformCtx)573 xmlSecMSCngBlockCipherCtxInit(xmlSecMSCngBlockCipherCtxPtr ctx,
574         xmlSecBufferPtr in, xmlSecBufferPtr out, int encrypt, int last,
575         const xmlChar* cipherName, xmlSecTransformCtxPtr transformCtx) {
576     NTSTATUS status;
577     DWORD dwBlockLenLen;
578 
579     xmlSecAssert2(ctx != NULL, -1);
580     xmlSecAssert2(ctx->hKey != 0, -1);
581     xmlSecAssert2(ctx->hAlg != 0, -1);
582     xmlSecAssert2(ctx->ctxInitialized == 0, -1);
583 
584     /* Get the cipher block length */
585     dwBlockLenLen = sizeof(DWORD);
586     status = BCryptGetProperty(ctx->hAlg,
587         BCRYPT_BLOCK_LENGTH,
588         (PUCHAR)&ctx->dwBlockLen,
589         sizeof(ctx->dwBlockLen),
590         &dwBlockLenLen,
591         0);
592     if(status != STATUS_SUCCESS) {
593         xmlSecMSCngNtError("BCryptGetProperty", cipherName, status);
594         return(-1);
595     }
596 
597     xmlSecAssert2(ctx->dwBlockLen > 0, -1);
598 
599     if(ctx->cbcMode) {
600         return xmlSecMSCngCBCBlockCipherCtxInit(ctx, in, out, encrypt,
601             cipherName, transformCtx);
602     } else {
603         return xmlSecMSCngGCMBlockCipherCtxInit(ctx, in, out, encrypt, last,
604             cipherName, transformCtx);
605     }
606 }
607 
608 static int
xmlSecMSCngCBCBlockCipherCtxUpdate(xmlSecMSCngBlockCipherCtxPtr ctx,xmlSecBufferPtr in,xmlSecBufferPtr out,int encrypt,const xmlChar * cipherName,xmlSecTransformCtxPtr transformCtx)609 xmlSecMSCngCBCBlockCipherCtxUpdate(xmlSecMSCngBlockCipherCtxPtr ctx,
610         xmlSecBufferPtr in, xmlSecBufferPtr out, int encrypt,
611         const xmlChar* cipherName, xmlSecTransformCtxPtr transformCtx) {
612     xmlSecSize inSize, inBlocks, outSize;
613     unsigned char* outBuf;
614     unsigned char* inBuf;
615     DWORD dwCLen;
616     NTSTATUS status;
617     int ret;
618 
619     /* unreferenced parameter */
620     (void)transformCtx;
621 
622     xmlSecAssert2(ctx != NULL, -1);
623     xmlSecAssert2(ctx->ctxInitialized != 0, -1);
624     xmlSecAssert2(ctx->dwBlockLen > 0, -1);
625     xmlSecAssert2(in != NULL, -1);
626     xmlSecAssert2(out != NULL, -1);
627     xmlSecAssert2(transformCtx != NULL, -1);
628 
629     inSize = xmlSecBufferGetSize(in);
630     outSize = xmlSecBufferGetSize(out);
631 
632     if(inSize < XMLSEC_SIZE_BAD_CAST(ctx->dwBlockLen)) {
633         return(0);
634     }
635 
636     if(encrypt) {
637         inBlocks = inSize / XMLSEC_SIZE_BAD_CAST(ctx->dwBlockLen);
638     } else {
639         /* we want to have the last block in the input buffer
640         * for padding check */
641         inBlocks = (inSize - 1) / XMLSEC_SIZE_BAD_CAST(ctx->dwBlockLen);
642     }
643     inSize = inBlocks * XMLSEC_SIZE_BAD_CAST(ctx->dwBlockLen);
644 
645     /* we write out the input size plus maybe one block */
646     ret = xmlSecBufferSetMaxSize(out, outSize + inSize + ctx->dwBlockLen);
647     if(ret < 0) {
648         xmlSecInternalError2("xmlSecBufferSetMaxSize", cipherName,
649             "size=%d", outSize + inSize + ctx->dwBlockLen);
650         return(-1);
651     }
652     outBuf = xmlSecBufferGetData(out) + outSize;
653     inBuf = xmlSecBufferGetData(in);
654     xmlSecAssert2(inBuf != NULL, -1);
655 
656     dwCLen = (DWORD)inSize;
657     if(encrypt) {
658         status = BCryptEncrypt(ctx->hKey,
659             inBuf,
660             (ULONG)inSize,
661             NULL,
662             ctx->pbIV,
663             ctx->cbIV,
664             outBuf,
665             (ULONG)inSize,
666             &dwCLen,
667             0);
668         if(status != STATUS_SUCCESS) {
669             xmlSecMSCngNtError("BCryptEncrypt", cipherName, status);
670             return(-1);
671         }
672 
673         /* check if we really have encrypted the numbers of bytes that we
674         * requested */
675         if(dwCLen != inSize) {
676             xmlSecInternalError2("BCryptEncrypt", cipherName, "size=%ld",
677                 dwCLen);
678             return(-1);
679         }
680     } else {
681         status = BCryptDecrypt(ctx->hKey,
682             inBuf,
683             (ULONG)inSize,
684             NULL,
685             ctx->pbIV,
686             ctx->cbIV,
687             outBuf,
688             (ULONG)inSize,
689             &dwCLen,
690             0);
691         if(status != STATUS_SUCCESS) {
692             xmlSecMSCngNtError("BCryptDecrypt", cipherName, status);
693             return(-1);
694         }
695 
696         /* check if we really have decrypted the numbers of bytes that we
697         * requested */
698         if(dwCLen != inSize) {
699             xmlSecInternalError2("BCryptDecrypt", cipherName, "size=%ld",
700                 dwCLen);
701             return(-1);
702         }
703     }
704 
705     /* set correct output buffer size */
706     ret = xmlSecBufferSetSize(out, outSize + inSize);
707     if(ret < 0) {
708         xmlSecInternalError2("xmlSecBufferSetSize", cipherName, "size=%d",
709             outSize + inSize);
710         return(-1);
711     }
712 
713     /* remove the processed block from input */
714     ret = xmlSecBufferRemoveHead(in, inSize);
715     if(ret < 0) {
716         xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName, "size=%d",
717             inSize);
718         return(-1);
719     }
720 
721     return(0);
722 }
723 
724 static int
xmlSecMSCngGCMBlockCipherCtxUpdate(xmlSecMSCngBlockCipherCtxPtr ctx,xmlSecBufferPtr in,xmlSecBufferPtr out,int encrypt,int last,const xmlChar * cipherName,xmlSecTransformCtxPtr transformCtx)725 xmlSecMSCngGCMBlockCipherCtxUpdate(xmlSecMSCngBlockCipherCtxPtr ctx,
726         xmlSecBufferPtr in, xmlSecBufferPtr out, int encrypt, int last,
727         const xmlChar* cipherName, xmlSecTransformCtxPtr transformCtx) {
728 
729     NTSTATUS status;
730     xmlSecSize inSize, outSize;
731     xmlSecByte *inBuf, *outBuf;
732     DWORD dwCLen;
733     int ret;
734 
735     /* unreferenced parameter */
736     (void)transformCtx;
737 
738     xmlSecAssert2(ctx != NULL, -1);
739     xmlSecAssert2(ctx->ctxInitialized != 0, -1);
740     xmlSecAssert2(ctx->dwBlockLen > 0, -1);
741     xmlSecAssert2(in != NULL, -1);
742     xmlSecAssert2(out != NULL, -1);
743     xmlSecAssert2(transformCtx != NULL, -1);
744 
745     if(last != 0) {
746         /* We handle everything in finalize for the last block of data */
747         return(0);
748     }
749 
750     inBuf = xmlSecBufferGetData(in);
751     xmlSecAssert2(inBuf != NULL, -1);
752 
753     if(xmlSecBufferGetSize(in) < ctx->dwBlockLen) {
754         return 0;
755     }
756 
757     if(encrypt) {
758         /* Round to the block size. We will finalize this later */
759         inSize = (xmlSecBufferGetSize(in) / XMLSEC_SIZE_BAD_CAST(ctx->dwBlockLen)) * XMLSEC_SIZE_BAD_CAST(ctx->dwBlockLen);
760     } else {
761         /* If we've been called here, we know there is more data
762          * to come, but we don't know how much. The spec tells us that
763          * the tag is the last 16 bytes of the data when decrypting, so to make sure
764          * we don't try to decrypt it, we leave at least 16 bytes in the buffer
765          * until we know we're processing the last one */
766         inSize = ((xmlSecBufferGetSize(in) - xmlSecMSCngAesGcmTagLengthInBytes) / XMLSEC_SIZE_BAD_CAST(ctx->dwBlockLen)) * XMLSEC_SIZE_BAD_CAST(ctx->dwBlockLen);
767         if (inSize < ctx->dwBlockLen) {
768             return 0;
769         }
770     }
771 
772     outSize = xmlSecBufferGetSize(out);
773     ret = xmlSecBufferSetMaxSize(out, outSize + inSize);
774     if(ret < 0) {
775         xmlSecInternalError2("xmlSecBufferSetMaxSize", cipherName,
776             "size=%d", outSize + inSize);
777         return(-1);
778     }
779 
780     outBuf = xmlSecBufferGetData(out) + outSize;
781 
782     dwCLen = 0;
783     if(encrypt) {
784         status = BCryptEncrypt(ctx->hKey,
785             inBuf,
786             (ULONG)inSize,
787             &ctx->authInfo,
788             ctx->pbIV,
789             ctx->cbIV,
790             outBuf,
791             (ULONG)inSize,
792             &dwCLen,
793             0);
794 
795         if(status != STATUS_SUCCESS) {
796             xmlSecMSCngNtError("BCryptEncrypt", cipherName, status);
797             return(-1);
798         }
799 
800         /* check if we really have encrypted the numbers of bytes that we
801         * requested */
802         if(dwCLen != inSize) {
803             xmlSecInternalError2("BCryptEncrypt", cipherName, "size=%ld",
804                 dwCLen);
805             return(-1);
806         }
807 
808     } else {
809         status = BCryptDecrypt(ctx->hKey,
810             inBuf,
811             (ULONG)inSize,
812             &ctx->authInfo,
813             ctx->pbIV,
814             ctx->cbIV,
815             outBuf,
816             (ULONG)inSize,
817             &dwCLen,
818             0);
819 
820         if(status != STATUS_SUCCESS) {
821             xmlSecMSCngNtError("BCryptDecrypt", cipherName, status);
822             return(-1);
823         }
824 
825         /* check if we really have decrypted the numbers of bytes that we
826         * requested */
827         if(dwCLen != inSize) {
828             xmlSecInternalError2("BCryptDecrypt", cipherName, "size=%ld",
829                 dwCLen);
830             return(-1);
831         }
832     }
833 
834     /* set correct output buffer size */
835     ret = xmlSecBufferSetSize(out, outSize + dwCLen);
836     if(ret < 0) {
837         xmlSecInternalError2("xmlSecBufferSetSize", cipherName, "size=%d",
838             outSize + dwCLen);
839         return(-1);
840     }
841 
842     /* remove the processed data from input */
843     ret = xmlSecBufferRemoveHead(in, dwCLen);
844     if(ret < 0) {
845         xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName, "size=%d",
846             dwCLen);
847         return(-1);
848     }
849 
850     return(0);
851 }
852 
853 static int
xmlSecMSCngBlockCipherCtxUpdate(xmlSecMSCngBlockCipherCtxPtr ctx,xmlSecBufferPtr in,xmlSecBufferPtr out,int encrypt,int last,const xmlChar * cipherName,xmlSecTransformCtxPtr transformCtx)854 xmlSecMSCngBlockCipherCtxUpdate(xmlSecMSCngBlockCipherCtxPtr ctx,
855         xmlSecBufferPtr in, xmlSecBufferPtr out, int encrypt, int last,
856         const xmlChar* cipherName, xmlSecTransformCtxPtr transformCtx) {
857 
858     xmlSecAssert2(ctx != NULL, -1);
859 
860     if(ctx->cbcMode) {
861         return xmlSecMSCngCBCBlockCipherCtxUpdate(ctx, in, out, encrypt,
862             cipherName, transformCtx);
863     } else {
864         return xmlSecMSCngGCMBlockCipherCtxUpdate(ctx, in, out, encrypt, last,
865             cipherName, transformCtx);
866     }
867 }
868 
869 static int
xmlSecMSCngCBCBlockCipherCtxFinal(xmlSecMSCngBlockCipherCtxPtr ctx,xmlSecBufferPtr in,xmlSecBufferPtr out,int encrypt,const xmlChar * cipherName,xmlSecTransformCtxPtr transformCtx)870 xmlSecMSCngCBCBlockCipherCtxFinal(xmlSecMSCngBlockCipherCtxPtr ctx,
871         xmlSecBufferPtr in, xmlSecBufferPtr out, int encrypt,
872         const xmlChar* cipherName, xmlSecTransformCtxPtr transformCtx) {
873     xmlSecSize inSize, outSize;
874     int outLen;
875     unsigned char* inBuf;
876     unsigned char* outBuf;
877     DWORD dwCLen;
878     NTSTATUS status;
879     int ret;
880 
881     /* unreferenced parameter */
882     (void)transformCtx;
883 
884     inSize = xmlSecBufferGetSize(in);
885     outSize = xmlSecBufferGetSize(out);
886 
887     if(encrypt != 0) {
888         xmlSecAssert2(inSize < XMLSEC_SIZE_BAD_CAST(ctx->dwBlockLen), -1);
889 
890         /* create padding */
891         ret = xmlSecBufferSetMaxSize(in, ctx->dwBlockLen);
892         if(ret < 0) {
893             xmlSecInternalError2("xmlSecBufferSetMaxSize", cipherName,
894                 "size=%d", ctx->dwBlockLen);
895             return(-1);
896         }
897         inBuf = xmlSecBufferGetData(in);
898 
899         /* create random padding */
900         if(XMLSEC_SIZE_BAD_CAST(ctx->dwBlockLen) > (inSize + 1)) {
901             status = BCryptGenRandom(NULL,
902                 (PBYTE) inBuf + inSize,
903                 (ULONG)(ctx->dwBlockLen - inSize - 1),
904                 BCRYPT_USE_SYSTEM_PREFERRED_RNG);
905             if(status != STATUS_SUCCESS) {
906                 xmlSecMSCngNtError("BCryptGetProperty", cipherName, status);
907                 return(-1);
908             }
909         }
910         inBuf[ctx->dwBlockLen - 1] = (unsigned char)(ctx->dwBlockLen - inSize);
911         inSize = ctx->dwBlockLen;
912     } else {
913         if(inSize != XMLSEC_SIZE_BAD_CAST(ctx->dwBlockLen)) {
914             xmlSecInvalidSizeError("Input data", inSize, ctx->dwBlockLen, cipherName);
915             return(-1);
916         }
917         inBuf = xmlSecBufferGetData(in);
918     }
919 
920     /* process last block */
921     ret = xmlSecBufferSetMaxSize(out, outSize + 2 * ctx->dwBlockLen);
922     if(ret < 0) {
923         xmlSecInternalError2("xmlSecBufferSetMaxSize", cipherName, "size=%d",
924             outSize + 2 * ctx->dwBlockLen);
925         return(-1);
926     }
927 
928     outBuf = xmlSecBufferGetData(out) + outSize;
929 
930     dwCLen = (ULONG)inSize;
931     if(encrypt) {
932         status = BCryptEncrypt(ctx->hKey,
933             inBuf,
934             (ULONG)inSize,
935             NULL,
936             ctx->pbIV,
937             ctx->cbIV,
938             outBuf,
939             (ULONG)(inSize + ctx->dwBlockLen),
940             &dwCLen,
941             0);
942         if(status != STATUS_SUCCESS) {
943             xmlSecMSCngNtError("BCryptDecrypt", cipherName, status);
944             return(-1);
945         }
946 
947         /* check if we really have encrypted the numbers of bytes that we
948          * requested */
949         if(dwCLen != inSize) {
950             xmlSecInternalError2("BCryptEncrypt", cipherName, "size=%ld",
951                 dwCLen);
952             return(-1);
953         }
954     } else {
955         status = BCryptDecrypt(ctx->hKey,
956             inBuf,
957             (ULONG)inSize,
958             NULL,
959             ctx->pbIV,
960             ctx->cbIV,
961             outBuf,
962             (ULONG)inSize,
963             &dwCLen,
964             0);
965         if(status != STATUS_SUCCESS) {
966             xmlSecMSCngNtError("BCryptDecrypt", cipherName, status);
967             return(-1);
968         }
969 
970         /* check if we really have decrypted the numbers of bytes that we
971          * requested */
972         if(dwCLen != inSize) {
973             xmlSecInternalError2("BCryptDecrypt", cipherName, "size=%ld",
974                 dwCLen);
975             return(-1);
976         }
977     }
978 
979     if(encrypt == 0) {
980         /* check padding */
981         if(inSize < outBuf[ctx->dwBlockLen - 1]) {
982             xmlSecInvalidSizeLessThanError("Input data padding", inSize,
983                 outBuf[ctx->dwBlockLen - 1], cipherName);
984             return(-1);
985         }
986         outLen = (int)(inSize - outBuf[ctx->dwBlockLen - 1]);
987     } else {
988         outLen = (int)inSize;
989     }
990 
991     /* set correct output buffer size */
992     ret = xmlSecBufferSetSize(out, outSize + outLen);
993     if(ret < 0) {
994         xmlSecInternalError2("xmlSecBufferSetSize", cipherName, "size=%d",
995             outSize + outLen);
996         return(-1);
997     }
998 
999     /* remove the processed block from input */
1000     ret = xmlSecBufferRemoveHead(in, inSize);
1001     if(ret < 0) {
1002         xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName, "size=%d",
1003             inSize);
1004         return(-1);
1005     }
1006 
1007     return(0);
1008 }
1009 
1010 static int
xmlSecMSCngGCMBlockCipherCtxFinal(xmlSecMSCngBlockCipherCtxPtr ctx,xmlSecBufferPtr in,xmlSecBufferPtr out,int encrypt,const xmlChar * cipherName,xmlSecTransformCtxPtr transformCtx)1011 xmlSecMSCngGCMBlockCipherCtxFinal(xmlSecMSCngBlockCipherCtxPtr ctx,
1012         xmlSecBufferPtr in, xmlSecBufferPtr out, int encrypt,
1013         const xmlChar* cipherName, xmlSecTransformCtxPtr transformCtx)
1014 {
1015     xmlSecByte *inBuf, *outBuf;
1016     xmlSecSize inBufSize, outBufSize, outLen;
1017     DWORD dwCLen;
1018     int ret;
1019     NTSTATUS status;
1020 
1021     /* unreferenced parameter */
1022     (void)transformCtx;
1023 
1024     ctx->authInfo.dwFlags &= ~BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG; /* clear chaining flag */
1025 
1026     outBufSize = xmlSecBufferGetSize(out);
1027     inBufSize = xmlSecBufferGetSize(in);
1028     inBuf = xmlSecBufferGetData(in);
1029 
1030     if(encrypt) {
1031         ret = xmlSecBufferSetMaxSize(out,
1032             outBufSize + inBufSize + xmlSecMSCngAesGcmTagLengthInBytes); /* add space for the tag */
1033         if(ret < 0) {
1034             xmlSecInternalError2("xmlSecBufferSetMaxSize", cipherName,
1035                 "size=%d", outBufSize + inBufSize + xmlSecMSCngAesGcmTagLengthInBytes);
1036             return(-1);
1037         }
1038 
1039         outBuf = xmlSecBufferGetData(out) + outBufSize;
1040 
1041         status = BCryptEncrypt(ctx->hKey,
1042             inBuf,
1043             (ULONG)inBufSize,
1044             &ctx->authInfo,
1045             ctx->pbIV,
1046             ctx->cbIV,
1047             outBuf,
1048             (ULONG)inBufSize,
1049             &dwCLen,
1050             0);
1051 
1052         if(status != STATUS_SUCCESS) {
1053             xmlSecMSCngNtError("BCryptEncrypt", cipherName, status);
1054             return(-1);
1055         }
1056 
1057         /* check if we really have encrypted the numbers of bytes that we
1058         * requested */
1059         if(dwCLen != inBufSize) {
1060             xmlSecInternalError2("BCryptEncrypt", cipherName, "size=%ld",
1061                 dwCLen);
1062             return(-1);
1063         }
1064 
1065         /* Now add the tag at the end of the buffer */
1066         memcpy(outBuf + inBufSize, ctx->authInfo.pbTag, xmlSecMSCngAesGcmTagLengthInBytes);
1067 
1068         outLen = inBufSize + xmlSecMSCngAesGcmTagLengthInBytes;
1069 
1070     } else {
1071         /* Get the tag */
1072         memcpy(ctx->authInfo.pbTag, inBuf + inBufSize - xmlSecMSCngAesGcmTagLengthInBytes,
1073             xmlSecMSCngAesGcmTagLengthInBytes);
1074 
1075         /* remove the tag from the buffer */
1076         ret = xmlSecBufferRemoveTail(in, xmlSecMSCngAesGcmTagLengthInBytes);
1077         if(ret < 0) {
1078             xmlSecInternalError2("xmlSecBufferRemoveTail", cipherName,
1079                 "size=%d", xmlSecMSCngAesGcmTagLengthInBytes);
1080             return(-1);
1081         }
1082 
1083         inBuf = xmlSecBufferGetData(in);
1084         inBufSize = xmlSecBufferGetSize(in);
1085 
1086         ret = xmlSecBufferSetMaxSize(out, outBufSize + inBufSize);
1087         if(ret < 0) {
1088             xmlSecInternalError2("xmlSecBufferSetMaxSize", cipherName,
1089                                  "size=%d", outBufSize + inBufSize);
1090             return(-1);
1091         }
1092 
1093         outBuf = xmlSecBufferGetData(out) + outBufSize;
1094 
1095         status = BCryptDecrypt(ctx->hKey,
1096             inBuf,
1097             (ULONG)inBufSize,
1098             &ctx->authInfo,
1099             ctx->pbIV,
1100             ctx->cbIV,
1101             outBuf,
1102             (ULONG)inBufSize,
1103             &dwCLen,
1104             0);
1105 
1106         if(status != STATUS_SUCCESS) {
1107             xmlSecMSCngNtError("BCryptDecrypt", cipherName, status);
1108             return(-1);
1109         }
1110 
1111         /* check if we really have decrypted the numbers of bytes that we
1112         * requested */
1113         if(dwCLen != inBufSize) {
1114             xmlSecInternalError2("BCryptDecrypt", cipherName, "size=%ld",
1115                 dwCLen);
1116             return(-1);
1117         }
1118 
1119         outLen = inBufSize;
1120     }
1121 
1122     /* set correct output buffer size */
1123     ret = xmlSecBufferSetSize(out, outBufSize + outLen);
1124     if(ret < 0) {
1125         xmlSecInternalError2("xmlSecBufferSetSize", cipherName, "size=%d",
1126             outBufSize + outLen);
1127         return(-1);
1128     }
1129 
1130     /* remove the processed block from input */
1131     ret = xmlSecBufferRemoveHead(in, inBufSize);
1132     if(ret < 0) {
1133         xmlSecInternalError2("xmlSecBufferRemoveHead", cipherName, "size=%d",
1134             inBufSize);
1135         return(-1);
1136     }
1137 
1138     return(0);
1139 }
1140 
1141 static int
xmlSecMSCngBlockCipherCtxFinal(xmlSecMSCngBlockCipherCtxPtr ctx,xmlSecBufferPtr in,xmlSecBufferPtr out,int encrypt,const xmlChar * cipherName,xmlSecTransformCtxPtr transformCtx)1142 xmlSecMSCngBlockCipherCtxFinal(xmlSecMSCngBlockCipherCtxPtr ctx,
1143         xmlSecBufferPtr in, xmlSecBufferPtr out, int encrypt,
1144         const xmlChar* cipherName, xmlSecTransformCtxPtr transformCtx)
1145 {
1146     xmlSecAssert2(ctx != NULL, -1);
1147     xmlSecAssert2(ctx->ctxInitialized != 0, -1);
1148     xmlSecAssert2(in != NULL, -1);
1149     xmlSecAssert2(out != NULL, -1);
1150     xmlSecAssert2(transformCtx != NULL, -1);
1151 
1152     if(ctx->cbcMode) {
1153         return xmlSecMSCngCBCBlockCipherCtxFinal(ctx, in, out, encrypt,
1154                                                  cipherName, transformCtx);
1155     } else {
1156         return xmlSecMSCngGCMBlockCipherCtxFinal(ctx, in, out, encrypt,
1157                                                  cipherName, transformCtx);
1158     }
1159 }
1160 
1161 static int
xmlSecMSCngBlockCipherExecute(xmlSecTransformPtr transform,int last,xmlSecTransformCtxPtr transformCtx)1162 xmlSecMSCngBlockCipherExecute(xmlSecTransformPtr transform, int last,
1163         xmlSecTransformCtxPtr transformCtx) {
1164     xmlSecMSCngBlockCipherCtxPtr ctx;
1165     xmlSecBufferPtr in, out;
1166     int ret, encrypt;
1167 
1168     xmlSecAssert2(xmlSecMSCngBlockCipherCheckId(transform), -1);
1169     xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1);
1170     xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCngBlockCipherSize), -1);
1171     xmlSecAssert2(transformCtx != NULL, -1);
1172 
1173     in = &(transform->inBuf);
1174     out = &(transform->outBuf);
1175 
1176     ctx = xmlSecMSCngBlockCipherGetCtx(transform);
1177     xmlSecAssert2(ctx != NULL, -1);
1178 
1179     if(transform->status == xmlSecTransformStatusNone) {
1180         /* This should only be done once, before the context has been initialised */
1181         BCRYPT_INIT_AUTH_MODE_INFO(ctx->authInfo);
1182         transform->status = xmlSecTransformStatusWorking;
1183     }
1184 
1185     if(transform->status == xmlSecTransformStatusWorking) {
1186 
1187         encrypt = (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0;
1188 
1189         if(ctx->ctxInitialized == 0) {
1190             ret = xmlSecMSCngBlockCipherCtxInit(ctx,
1191                 in,
1192                 out,
1193                 encrypt,
1194                 last,
1195                 xmlSecTransformGetName(transform),
1196                 transformCtx);
1197             if(ret < 0) {
1198                 xmlSecInternalError("xmlSecMSCngBlockCipherCtxInit",
1199                     xmlSecTransformGetName(transform));
1200                 return(-1);
1201             }
1202 
1203         }
1204         if((ctx->ctxInitialized == 0) && (last != 0)) {
1205             xmlSecInvalidDataError("not enough data to initialize transform",
1206                 xmlSecTransformGetName(transform));
1207             return(-1);
1208         }
1209 
1210         if(ctx->ctxInitialized != 0) {
1211             ret = xmlSecMSCngBlockCipherCtxUpdate(ctx, in, out,
1212                 encrypt,
1213                 last,
1214                 xmlSecTransformGetName(transform), transformCtx);
1215             if(ret < 0) {
1216                 xmlSecInternalError("xmlSecMSCngBlockCipherCtxUpdate",
1217                     xmlSecTransformGetName(transform));
1218                 return(-1);
1219             }
1220         }
1221 
1222         if(last) {
1223             ret = xmlSecMSCngBlockCipherCtxFinal(ctx, in, out,
1224                 encrypt,
1225                 xmlSecTransformGetName(transform), transformCtx);
1226 
1227             if(ret < 0) {
1228                 xmlSecInternalError("xmlSecMSCngBlockCipherCtxFinal",
1229                     xmlSecTransformGetName(transform));
1230                 return(-1);
1231             }
1232 
1233             transform->status = xmlSecTransformStatusFinished;
1234         }
1235     } else if(transform->status == xmlSecTransformStatusFinished) {
1236         /* the only way we can get here is if there is no input */
1237         xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1);
1238     } else if(transform->status == xmlSecTransformStatusNone) {
1239         /* the only way we can get here is if there is not enough data in the input */
1240         xmlSecAssert2(last == 0, -1);
1241     } else {
1242         xmlSecInvalidTransfromStatusError(transform);
1243         return(-1);
1244     }
1245 
1246     return(0);
1247 }
1248 
1249 #ifndef XMLSEC_NO_AES
1250 
1251 static xmlSecTransformKlass xmlSecMSCngAes128CbcKlass = {
1252     /* klass/object sizes */
1253     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
1254     xmlSecMSCngBlockCipherSize,                 /* xmlSecSize objSize */
1255 
1256     xmlSecNameAes128Cbc,                        /* const xmlChar* name; */
1257     xmlSecHrefAes128Cbc,                        /* const xmlChar* href; */
1258     xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */
1259 
1260     xmlSecMSCngBlockCipherInitialize,           /* xmlSecTransformInitializeMethod initialize; */
1261     xmlSecMSCngBlockCipherFinalize,             /* xmlSecTransformFinalizeMethod finalize; */
1262     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
1263     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
1264     xmlSecMSCngBlockCipherSetKeyReq,            /* xmlSecTransformSetKeyMethod setKeyReq; */
1265     xmlSecMSCngBlockCipherSetKey,               /* xmlSecTransformSetKeyMethod setKey; */
1266     NULL,                                       /* xmlSecTransformValidateMethod validate; */
1267     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
1268     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
1269     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
1270     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
1271     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
1272     xmlSecMSCngBlockCipherExecute,              /* xmlSecTransformExecuteMethod execute; */
1273 
1274     NULL,                                       /* void* reserved0; */
1275     NULL,                                       /* void* reserved1; */
1276 };
1277 
1278 /**
1279  * xmlSecMSCngTransformAes128CbcGetKlass:
1280  *
1281  * AES 128 CBC encryption transform klass.
1282  *
1283  * Returns: pointer to AES 128 CBC encryption transform.
1284  */
1285 xmlSecTransformId
xmlSecMSCngTransformAes128CbcGetKlass(void)1286 xmlSecMSCngTransformAes128CbcGetKlass(void) {
1287     return(&xmlSecMSCngAes128CbcKlass);
1288 }
1289 
1290 static xmlSecTransformKlass xmlSecMSCngAes192CbcKlass = {
1291     /* klass/object sizes */
1292     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
1293     xmlSecMSCngBlockCipherSize,                 /* xmlSecSize objSize */
1294 
1295     xmlSecNameAes192Cbc,                        /* const xmlChar* name; */
1296     xmlSecHrefAes192Cbc,                        /* const xmlChar* href; */
1297     xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */
1298 
1299     xmlSecMSCngBlockCipherInitialize,           /* xmlSecTransformInitializeMethod initialize; */
1300     xmlSecMSCngBlockCipherFinalize,             /* xmlSecTransformFinalizeMethod finalize; */
1301     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
1302     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
1303     xmlSecMSCngBlockCipherSetKeyReq,            /* xmlSecTransformSetKeyMethod setKeyReq; */
1304     xmlSecMSCngBlockCipherSetKey,               /* xmlSecTransformSetKeyMethod setKey; */
1305     NULL,                                       /* xmlSecTransformValidateMethod validate; */
1306     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
1307     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
1308     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
1309     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
1310     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
1311     xmlSecMSCngBlockCipherExecute,              /* xmlSecTransformExecuteMethod execute; */
1312 
1313     NULL,                                       /* void* reserved0; */
1314     NULL,                                       /* void* reserved1; */
1315 };
1316 
1317 /**
1318  * xmlSecMSCngTransformAes192CbcGetKlass:
1319  *
1320  * AES 192 CBC encryption transform klass.
1321  *
1322  * Returns: pointer to AES 192 CBC encryption transform.
1323  */
1324 xmlSecTransformId
xmlSecMSCngTransformAes192CbcGetKlass(void)1325 xmlSecMSCngTransformAes192CbcGetKlass(void) {
1326     return(&xmlSecMSCngAes192CbcKlass);
1327 }
1328 
1329 static xmlSecTransformKlass xmlSecMSCngAes256CbcKlass = {
1330     /* klass/object sizes */
1331     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
1332     xmlSecMSCngBlockCipherSize,                 /* xmlSecSize objSize */
1333 
1334     xmlSecNameAes256Cbc,                        /* const xmlChar* name; */
1335     xmlSecHrefAes256Cbc,                        /* const xmlChar* href; */
1336     xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */
1337 
1338     xmlSecMSCngBlockCipherInitialize,           /* xmlSecTransformInitializeMethod initialize; */
1339     xmlSecMSCngBlockCipherFinalize,             /* xmlSecTransformFinalizeMethod finalize; */
1340     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
1341     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
1342     xmlSecMSCngBlockCipherSetKeyReq,            /* xmlSecTransformSetKeyMethod setKeyReq; */
1343     xmlSecMSCngBlockCipherSetKey,               /* xmlSecTransformSetKeyMethod setKey; */
1344     NULL,                                       /* xmlSecTransformValidateMethod validate; */
1345     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
1346     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
1347     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
1348     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
1349     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
1350     xmlSecMSCngBlockCipherExecute,              /* xmlSecTransformExecuteMethod execute; */
1351 
1352     NULL,                                       /* void* reserved0; */
1353     NULL,                                       /* void* reserved1; */
1354 };
1355 
1356 /**
1357  * xmlSecMSCngTransformAes256CbcGetKlass:
1358  *
1359  * AES 256 CBC encryption transform klass.
1360  *
1361  * Returns: pointer to AES 256 CBC encryption transform.
1362  */
1363 xmlSecTransformId
xmlSecMSCngTransformAes256CbcGetKlass(void)1364 xmlSecMSCngTransformAes256CbcGetKlass(void) {
1365     return(&xmlSecMSCngAes256CbcKlass);
1366 }
1367 
1368 static xmlSecTransformKlass xmlSecMSCngAes128GcmKlass = {
1369     /* klass/object sizes */
1370     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
1371     xmlSecMSCngBlockCipherSize,                 /* xmlSecSize objSize */
1372 
1373     xmlSecNameAes128Gcm,                        /* const xmlChar* name; */
1374     xmlSecHrefAes128Gcm,                        /* const xmlChar* href; */
1375     xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */
1376 
1377     xmlSecMSCngBlockCipherInitialize,           /* xmlSecTransformInitializeMethod initialize; */
1378     xmlSecMSCngBlockCipherFinalize,             /* xmlSecTransformFinalizeMethod finalize; */
1379     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
1380     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
1381     xmlSecMSCngBlockCipherSetKeyReq,            /* xmlSecTransformSetKeyMethod setKeyReq; */
1382     xmlSecMSCngBlockCipherSetKey,               /* xmlSecTransformSetKeyMethod setKey; */
1383     NULL,                                       /* xmlSecTransformValidateMethod validate; */
1384     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
1385     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
1386     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
1387     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
1388     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
1389     xmlSecMSCngBlockCipherExecute,              /* xmlSecTransformExecuteMethod execute; */
1390 
1391     NULL,                                       /* void* reserved0; */
1392     NULL,                                       /* void* reserved1; */
1393 };
1394 
1395 /**
1396  * xmlSecMSCngTransformAes128GcmGetKlass:
1397  *
1398  * AES 128 GCM encryption transform klass.
1399  *
1400  * Returns: pointer to AES 128 GCM encryption transform.
1401  */
1402 xmlSecTransformId
xmlSecMSCngTransformAes128GcmGetKlass(void)1403 xmlSecMSCngTransformAes128GcmGetKlass(void) {
1404     return(&xmlSecMSCngAes128GcmKlass);
1405 }
1406 
1407 static xmlSecTransformKlass xmlSecMSCngAes192GcmKlass = {
1408     /* klass/object sizes */
1409     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
1410     xmlSecMSCngBlockCipherSize,                 /* xmlSecSize objSize */
1411 
1412     xmlSecNameAes192Gcm,                        /* const xmlChar* name; */
1413     xmlSecHrefAes192Gcm,                        /* const xmlChar* href; */
1414     xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */
1415 
1416     xmlSecMSCngBlockCipherInitialize,           /* xmlSecTransformInitializeMethod initialize; */
1417     xmlSecMSCngBlockCipherFinalize,             /* xmlSecTransformFinalizeMethod finalize; */
1418     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
1419     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
1420     xmlSecMSCngBlockCipherSetKeyReq,            /* xmlSecTransformSetKeyMethod setKeyReq; */
1421     xmlSecMSCngBlockCipherSetKey,               /* xmlSecTransformSetKeyMethod setKey; */
1422     NULL,                                       /* xmlSecTransformValidateMethod validate; */
1423     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
1424     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
1425     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
1426     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
1427     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
1428     xmlSecMSCngBlockCipherExecute,              /* xmlSecTransformExecuteMethod execute; */
1429 
1430     NULL,                                       /* void* reserved0; */
1431     NULL,                                       /* void* reserved1; */
1432 };
1433 
1434 /**
1435  * xmlSecMSCngTransformAes192GcmGetKlass:
1436  *
1437  * AES 192 GCM encryption transform klass.
1438  *
1439  * Returns: pointer to AES 192 GCM encryption transform.
1440  */
1441 xmlSecTransformId
xmlSecMSCngTransformAes192GcmGetKlass(void)1442 xmlSecMSCngTransformAes192GcmGetKlass(void) {
1443     return(&xmlSecMSCngAes192GcmKlass);
1444 }
1445 
1446 
1447 static xmlSecTransformKlass xmlSecMSCngAes256GcmKlass = {
1448     /* klass/object sizes */
1449     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
1450     xmlSecMSCngBlockCipherSize,                 /* xmlSecSize objSize */
1451 
1452     xmlSecNameAes256Gcm,                        /* const xmlChar* name; */
1453     xmlSecHrefAes256Gcm,                        /* const xmlChar* href; */
1454     xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */
1455 
1456     xmlSecMSCngBlockCipherInitialize,           /* xmlSecTransformInitializeMethod initialize; */
1457     xmlSecMSCngBlockCipherFinalize,             /* xmlSecTransformFinalizeMethod finalize; */
1458     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
1459     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
1460     xmlSecMSCngBlockCipherSetKeyReq,            /* xmlSecTransformSetKeyMethod setKeyReq; */
1461     xmlSecMSCngBlockCipherSetKey,               /* xmlSecTransformSetKeyMethod setKey; */
1462     NULL,                                       /* xmlSecTransformValidateMethod validate; */
1463     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
1464     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
1465     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
1466     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
1467     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
1468     xmlSecMSCngBlockCipherExecute,              /* xmlSecTransformExecuteMethod execute; */
1469 
1470     NULL,                                       /* void* reserved0; */
1471     NULL,                                       /* void* reserved1; */
1472 };
1473 
1474 /**
1475  * xmlSecMSCngTransformAes256GcmGetKlass:
1476  *
1477  * AES 256 GCM encryption transform klass.
1478  *
1479  * Returns: pointer to AES 256 GCM encryption transform.
1480  */
1481 xmlSecTransformId
xmlSecMSCngTransformAes256GcmGetKlass(void)1482 xmlSecMSCngTransformAes256GcmGetKlass(void) {
1483     return(&xmlSecMSCngAes256GcmKlass);
1484 }
1485 
1486 #endif /* XMLSEC_NO_AES */
1487 
1488 #ifndef XMLSEC_NO_DES
1489 
1490 static xmlSecTransformKlass xmlSecMSCngDes3CbcKlass = {
1491     /* klass/object sizes */
1492     sizeof(xmlSecTransformKlass),        /* size_t klassSize */
1493     xmlSecMSCngBlockCipherSize,          /* size_t objSize */
1494 
1495     xmlSecNameDes3Cbc,                   /* const xmlChar* name; */
1496     xmlSecHrefDes3Cbc,                   /* const xmlChar* href; */
1497     xmlSecTransformUsageEncryptionMethod,/* xmlSecAlgorithmUsage usage; */
1498 
1499     xmlSecMSCngBlockCipherInitialize,    /* xmlSecTransformInitializeMethod initialize; */
1500     xmlSecMSCngBlockCipherFinalize,      /* xmlSecTransformFinalizeMethod finalize; */
1501     NULL,                                /* xmlSecTransformNodeReadMethod readNode; */
1502     NULL,                                /* xmlSecTransformNodeWriteMethod writeNode; */
1503     xmlSecMSCngBlockCipherSetKeyReq,     /* xmlSecTransformSetKeyMethod setKeyReq; */
1504     xmlSecMSCngBlockCipherSetKey,        /* xmlSecTransformSetKeyMethod setKey; */
1505     NULL,                                /* xmlSecTransformValidateMethod validate; */
1506     xmlSecTransformDefaultGetDataType,   /* xmlSecTransformGetDataTypeMethod getDataType; */
1507     xmlSecTransformDefaultPushBin,       /* xmlSecTransformPushBinMethod pushBin; */
1508     xmlSecTransformDefaultPopBin,        /* xmlSecTransformPopBinMethod popBin; */
1509     NULL,                                /* xmlSecTransformPushXmlMethod pushXml; */
1510     NULL,                                /* xmlSecTransformPopXmlMethod popXml; */
1511     xmlSecMSCngBlockCipherExecute,       /* xmlSecTransformExecuteMethod execute; */
1512 
1513     NULL,                                /* void* reserved0; */
1514     NULL,                                /* void* reserved1; */
1515 };
1516 
1517 /**
1518  * xmlSecMSCngTransformDes3CbcGetKlass:
1519  *
1520  * Triple DES CBC encryption transform klass.
1521  *
1522  * Returns: pointer to Triple DES encryption transform.
1523  */
1524 xmlSecTransformId
xmlSecMSCngTransformDes3CbcGetKlass(void)1525 xmlSecMSCngTransformDes3CbcGetKlass(void) {
1526     return(&xmlSecMSCngDes3CbcKlass);
1527 }
1528 
1529 #endif /* XMLSEC_NO_DES */
1530