Git init
[external/xmlsec1.git] / src / mscrypto / ciphers.c
1 /** 
2  * XMLSec library
3  *
4  * This is free software; see Copyright file in the source
5  * distribution for preciese wording.
6  * 
7  * Copyrigth (C) 2003 Cordys R&D BV, All rights reserved.
8  * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com>
9  */
10 #include "globals.h"
11
12 #include <string.h>
13
14 #include <windows.h>
15 #include <wincrypt.h>
16
17 #include <xmlsec/xmlsec.h>
18 #include <xmlsec/keys.h>
19 #include <xmlsec/transforms.h>
20 #include <xmlsec/errors.h>
21
22 #include <xmlsec/mscrypto/crypto.h>
23
24 #if defined(__MINGW32__)
25 #  include "xmlsec-mingw.h"
26 #endif
27
28 #ifndef MS_ENH_RSA_AES_PROV_PROTO
29 #define MS_ENH_RSA_AES_PROV_PROTO "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
30 #endif /* MS_ENH_RSA_AES_PROV_PROTO */
31
32 static BOOL xmlSecMSCryptoCreatePrivateExponentOneKey   (HCRYPTPROV hProv, 
33                                                          HCRYPTKEY *hPrivateKey);
34 static BOOL xmlSecMSCryptoImportPlainSessionBlob        (HCRYPTPROV hProv, 
35                                                          HCRYPTKEY hPrivateKey,
36                                                          ALG_ID dwAlgId, 
37                                                          LPBYTE pbKeyMaterial,
38                                                          DWORD dwKeyMaterial, 
39                                                          HCRYPTKEY *hSessionKey);
40
41 /**************************************************************************
42  *
43  * Internal MSCrypto Block cipher CTX
44  *
45  *****************************************************************************/
46 typedef struct _xmlSecMSCryptoBlockCipherCtx            xmlSecMSCryptoBlockCipherCtx,
47                                                         *xmlSecMSCryptoBlockCipherCtxPtr;
48 struct _xmlSecMSCryptoBlockCipherCtx {
49     ALG_ID              algorithmIdentifier;
50     int                 mode;
51     HCRYPTPROV          cryptProvider;
52     HCRYPTKEY           cryptKey;
53     HCRYPTKEY           pubPrivKey;
54     xmlSecKeyDataId     keyId;
55     LPCTSTR             providerName;
56     int                 providerType;
57     int                 keyInitialized;
58     int                 ctxInitialized;
59     xmlSecSize          keySize;
60 };
61 /* function declarations */
62 static int      xmlSecMSCryptoBlockCipherCtxUpdate      (xmlSecMSCryptoBlockCipherCtxPtr ctx,
63                                                          xmlSecBufferPtr in,
64                                                          xmlSecBufferPtr out,
65                                                          int encrypt,
66                                                          const xmlChar* cipherName,
67                                                          xmlSecTransformCtxPtr transformCtx);
68
69
70 static int 
71 xmlSecMSCryptoBlockCipherCtxInit(xmlSecMSCryptoBlockCipherCtxPtr ctx,
72                                  xmlSecBufferPtr in,
73                                  xmlSecBufferPtr out,
74                                  int encrypt,
75                                  const xmlChar* cipherName,
76                                  xmlSecTransformCtxPtr transformCtx) {
77     int blockLen;
78     int ret;
79     DWORD dwBlockLen, dwBlockLenLen;
80
81     xmlSecAssert2(ctx != NULL, -1);
82     xmlSecAssert2(ctx->keyInitialized != 0, -1);
83     xmlSecAssert2(ctx->ctxInitialized == 0, -1);
84     xmlSecAssert2(in != NULL, -1);
85     xmlSecAssert2(out != NULL, -1);
86     xmlSecAssert2(transformCtx != NULL, -1);
87
88     /* iv len == block len */
89     dwBlockLenLen = sizeof(DWORD);
90     if (!CryptGetKeyParam(ctx->cryptKey, KP_BLOCKLEN, (BYTE *)&dwBlockLen, &dwBlockLenLen, 0)) {
91         xmlSecError(XMLSEC_ERRORS_HERE, 
92                     xmlSecErrorsSafeString(cipherName),
93                     "CryptGetKeyParam",
94                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
95                     XMLSEC_ERRORS_NO_MESSAGE);
96         return(-1);
97     }
98     
99     blockLen = dwBlockLen / 8;
100     xmlSecAssert2(blockLen > 0, -1);
101     if(encrypt) {
102         unsigned char* iv;
103         size_t outSize;
104
105         /* allocate space for IV */     
106         outSize = xmlSecBufferGetSize(out);
107         ret = xmlSecBufferSetSize(out, outSize + blockLen);
108         if(ret < 0) {
109             xmlSecError(XMLSEC_ERRORS_HERE, 
110                         xmlSecErrorsSafeString(cipherName),
111                         "xmlSecBufferSetSize",
112                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
113                         "size=%d", outSize + blockLen);
114             return(-1);
115         }
116         iv = xmlSecBufferGetData(out) + outSize;
117
118         /* generate and use random iv */
119         if(!CryptGenRandom(ctx->cryptProvider, blockLen, iv)) {
120             xmlSecError(XMLSEC_ERRORS_HERE, 
121                         xmlSecErrorsSafeString(cipherName),
122                         "CryptGenRandom",
123                         XMLSEC_ERRORS_R_CRYPTO_FAILED,
124                         "len=%d", blockLen);
125             return(-1);
126         }
127             
128         if(!CryptSetKeyParam(ctx->cryptKey, KP_IV, iv, 0)) {
129             xmlSecError(XMLSEC_ERRORS_HERE, 
130                         xmlSecErrorsSafeString(cipherName),
131                         "CryptSetKeyParam",
132                         XMLSEC_ERRORS_R_CRYPTO_FAILED,
133                         XMLSEC_ERRORS_NO_MESSAGE);
134             return(-1);
135         }
136     } else {
137         /* if we don't have enough data, exit and hope that 
138         * we'll have iv next time */
139         if(xmlSecBufferGetSize(in) < (size_t)blockLen) {
140             return(0);
141         }
142         xmlSecAssert2(xmlSecBufferGetData(in) != NULL, -1);
143
144         /* set iv */
145         if (!CryptSetKeyParam(ctx->cryptKey, KP_IV, xmlSecBufferGetData(in), 0)) {
146             xmlSecError(XMLSEC_ERRORS_HERE, 
147                         xmlSecErrorsSafeString(cipherName),
148                         "CryptSetKeyParam",
149                         XMLSEC_ERRORS_R_CRYPTO_FAILED,
150                         XMLSEC_ERRORS_NO_MESSAGE);
151             return(-1);
152         }
153
154         /* and remove from input */
155         ret = xmlSecBufferRemoveHead(in, blockLen);
156         if(ret < 0) {
157             xmlSecError(XMLSEC_ERRORS_HERE, 
158                         xmlSecErrorsSafeString(cipherName),
159                         "xmlSecBufferRemoveHead",
160                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
161                         "size=%d", blockLen);
162             return(-1);
163
164         }
165     }
166
167     ctx->ctxInitialized = 1;
168     return(0);                                                           
169 }
170
171 static int 
172 xmlSecMSCryptoBlockCipherCtxUpdate(xmlSecMSCryptoBlockCipherCtxPtr ctx,
173                                    xmlSecBufferPtr in, xmlSecBufferPtr out,
174                                    int encrypt,
175                                    const xmlChar* cipherName,
176                                    xmlSecTransformCtxPtr transformCtx) {
177     size_t inSize, inBlocks, outSize;
178     int blockLen;
179     unsigned char* outBuf;
180     unsigned char* inBuf;
181     int ret;
182     DWORD dwBlockLen, dwBlockLenLen, dwCLen;
183
184     xmlSecAssert2(ctx != NULL, -1);
185     xmlSecAssert2(ctx->ctxInitialized != 0, -1);
186     xmlSecAssert2(in != NULL, -1);
187     xmlSecAssert2(out != NULL, -1);
188     xmlSecAssert2(transformCtx != NULL, -1);
189         
190     dwBlockLenLen = sizeof(DWORD);
191     if (!CryptGetKeyParam(ctx->cryptKey, KP_BLOCKLEN, (BYTE *)&dwBlockLen, &dwBlockLenLen, 0)) {
192         xmlSecError(XMLSEC_ERRORS_HERE, 
193                     xmlSecErrorsSafeString(cipherName),
194                     "CryptSetKeyParam",
195                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
196                     XMLSEC_ERRORS_NO_MESSAGE);
197         return(-1);
198     }
199     blockLen = dwBlockLen / 8;
200     xmlSecAssert2(blockLen > 0, -1);
201
202     inSize = xmlSecBufferGetSize(in);
203     outSize = xmlSecBufferGetSize(out);
204     
205     if(inSize < (size_t)blockLen) {
206         return(0);
207     }
208
209     if(encrypt) {
210         inBlocks = inSize / ((size_t)blockLen);
211     } else {
212         /* we want to have the last block in the input buffer 
213          * for padding check */
214         inBlocks = (inSize - 1) / ((size_t)blockLen);
215     }
216     inSize = inBlocks * ((size_t)blockLen);
217
218     /* we write out the input size plus may be one block */
219     ret = xmlSecBufferSetMaxSize(out, outSize + inSize + blockLen);
220     if(ret < 0) {
221         xmlSecError(XMLSEC_ERRORS_HERE, 
222                     xmlSecErrorsSafeString(cipherName),
223                     "xmlSecBufferSetMaxSize",
224                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
225                     "size=%d", outSize + inSize + blockLen);
226         return(-1);
227     }
228     outBuf = xmlSecBufferGetData(out) + outSize;
229     inBuf = xmlSecBufferGetData(in);
230     xmlSecAssert2(inBuf != NULL, -1);
231
232     memcpy(outBuf, inBuf, inSize);
233     dwCLen = inSize;
234     if(encrypt) {
235         if(!CryptEncrypt(ctx->cryptKey, 0, FALSE, 0, outBuf, &dwCLen, inSize + blockLen)) {
236             xmlSecError(XMLSEC_ERRORS_HERE, 
237                         xmlSecErrorsSafeString(cipherName),
238                         "CryptEncrypt",
239                         XMLSEC_ERRORS_R_CRYPTO_FAILED,
240                         XMLSEC_ERRORS_NO_MESSAGE);
241             return(-1);
242         }
243     } else {
244         if (!CryptDecrypt(ctx->cryptKey, 0, FALSE, 0, outBuf, &dwCLen)) {
245             xmlSecError(XMLSEC_ERRORS_HERE, 
246                         xmlSecErrorsSafeString(cipherName),
247                         "CryptSetKeyDecrypt",
248                         XMLSEC_ERRORS_R_CRYPTO_FAILED,
249                         XMLSEC_ERRORS_NO_MESSAGE);
250             return(-1);
251         }
252     }
253     /* Check if we really have de/encrypted the numbers of bytes that we requested */
254     if (dwCLen != inSize) {
255         xmlSecError(XMLSEC_ERRORS_HERE, 
256                     xmlSecErrorsSafeString(cipherName),
257                     "CryptEn/Decrypt",
258                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
259                     "size=%ld", dwCLen);
260         return(-1);
261     }
262
263     /* set correct output buffer size */
264     ret = xmlSecBufferSetSize(out, outSize + inSize);
265     if(ret < 0) {
266         xmlSecError(XMLSEC_ERRORS_HERE, 
267                     xmlSecErrorsSafeString(cipherName),
268                     "xmlSecBufferSetSize",
269                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
270                     "size=%d", outSize + inSize);
271         return(-1);
272     }
273
274     /* remove the processed block from input */
275     ret = xmlSecBufferRemoveHead(in, inSize);
276     if(ret < 0) {
277         xmlSecError(XMLSEC_ERRORS_HERE, 
278                     xmlSecErrorsSafeString(cipherName),
279                     "xmlSecBufferRemoveHead",
280                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
281                     "size=%d", inSize);
282         return(-1);
283     }
284     return(0);
285 }
286
287 static int 
288 xmlSecMSCryptoBlockCipherCtxFinal(xmlSecMSCryptoBlockCipherCtxPtr ctx,
289                                   xmlSecBufferPtr in,
290                                   xmlSecBufferPtr out,
291                                   int encrypt,
292                                   const xmlChar* cipherName,
293                                   xmlSecTransformCtxPtr transformCtx) {
294     size_t inSize, outSize;
295     int blockLen, outLen = 0;
296     unsigned char* inBuf;
297     unsigned char* outBuf;
298     int ret;
299     DWORD dwBlockLen, dwBlockLenLen, dwCLen;
300     
301     xmlSecAssert2(ctx != NULL, -1);
302     xmlSecAssert2(ctx->ctxInitialized != 0, -1);
303     xmlSecAssert2(in != NULL, -1);
304     xmlSecAssert2(out != NULL, -1);
305     xmlSecAssert2(transformCtx != NULL, -1);
306
307     dwBlockLenLen = sizeof(DWORD);
308     if (!CryptGetKeyParam(ctx->cryptKey, KP_BLOCKLEN, (BYTE *)&dwBlockLen, &dwBlockLenLen, 0)) {
309         xmlSecError(XMLSEC_ERRORS_HERE, 
310                     xmlSecErrorsSafeString(cipherName),
311                     "CryptGetKeyParam",
312                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
313                     XMLSEC_ERRORS_NO_MESSAGE);
314         return(-1);
315     }
316     blockLen = dwBlockLen / 8;
317     xmlSecAssert2(blockLen > 0, -1);
318
319     inSize = xmlSecBufferGetSize(in);
320     outSize = xmlSecBufferGetSize(out);
321
322     if(encrypt != 0) {
323         xmlSecAssert2(inSize < (size_t)blockLen, -1);        
324
325         /* create padding */
326         ret = xmlSecBufferSetMaxSize(in, blockLen);
327         if(ret < 0) {
328             xmlSecError(XMLSEC_ERRORS_HERE, 
329                         xmlSecErrorsSafeString(cipherName),
330                         "xmlSecBufferSetMaxSize",
331                         XMLSEC_ERRORS_R_XMLSEC_FAILED,
332                         "size=%d", blockLen);
333             return(-1);
334         }
335         inBuf = xmlSecBufferGetData(in);
336
337         /* create random padding */
338         if((size_t)blockLen > (inSize + 1)) {
339             if (!CryptGenRandom(ctx->cryptProvider, blockLen - inSize - 1, inBuf + inSize)) {
340                 xmlSecError(XMLSEC_ERRORS_HERE, 
341                             xmlSecErrorsSafeString(cipherName),
342                             "CryptGenRandom",
343                             XMLSEC_ERRORS_R_CRYPTO_FAILED,
344                             XMLSEC_ERRORS_NO_MESSAGE);
345                 return(-1);
346             }
347         }
348         inBuf[blockLen - 1] = blockLen - inSize;
349         inSize = blockLen;
350     } else {
351         if(inSize != (size_t)blockLen) {
352             xmlSecError(XMLSEC_ERRORS_HERE, 
353                         xmlSecErrorsSafeString(cipherName),
354                         NULL,
355                         XMLSEC_ERRORS_R_INVALID_DATA,
356                         "data=%d;block=%d", inSize, blockLen);
357             return(-1);
358         }
359         inBuf = xmlSecBufferGetData(in);
360     }
361     
362     /* process last block */
363     ret = xmlSecBufferSetMaxSize(out, outSize + 2 * blockLen);
364     if(ret < 0) {
365         xmlSecError(XMLSEC_ERRORS_HERE, 
366                     xmlSecErrorsSafeString(cipherName),
367                     "xmlSecBufferSetMaxSize",
368                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
369                     "size=%d", outSize + 2 * blockLen);
370         return(-1);
371     }
372     outBuf = xmlSecBufferGetData(out) + outSize;
373     memcpy(outBuf, inBuf, inSize);
374
375     dwCLen = inSize;
376     if(encrypt) {
377         /* Set process last block to false, since we handle padding ourselves, and MSCrypto padding 
378          * can be skipped. I hope this will work .... */
379         if(!CryptEncrypt(ctx->cryptKey, 0, FALSE, 0, outBuf, &dwCLen, inSize + blockLen)) {
380             xmlSecError(XMLSEC_ERRORS_HERE, 
381                         xmlSecErrorsSafeString(cipherName),
382                         "CryptEncrypt",
383                         XMLSEC_ERRORS_R_CRYPTO_FAILED,
384                         XMLSEC_ERRORS_NO_MESSAGE);
385             return(-1);
386         }
387     } else {
388         if (!CryptDecrypt(ctx->cryptKey, 0, FALSE, 0, outBuf, &dwCLen)) {
389             xmlSecError(XMLSEC_ERRORS_HERE, 
390                         xmlSecErrorsSafeString(cipherName),
391                         "CryptDecrypt",
392                         XMLSEC_ERRORS_R_CRYPTO_FAILED,
393                         XMLSEC_ERRORS_NO_MESSAGE);
394             return(-1);
395         }
396     }
397
398     /* Check if we really have de/encrypted the numbers of bytes that we requested */
399     if (dwCLen != inSize) {
400         xmlSecError(XMLSEC_ERRORS_HERE, 
401                     xmlSecErrorsSafeString(cipherName),
402                     "CryptEn/Decrypt",
403                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
404                     "size=%ld", dwCLen);
405         return(-1);
406     }
407
408     if(encrypt == 0) {
409         /* check padding */
410         if(inSize < outBuf[blockLen - 1]) {
411             xmlSecError(XMLSEC_ERRORS_HERE,
412                         xmlSecErrorsSafeString(cipherName),
413                         NULL,
414                         XMLSEC_ERRORS_R_INVALID_DATA,
415                         "padding=%d;buffer=%d",
416                         outBuf[blockLen - 1], inSize);
417             return(-1); 
418         }
419         outLen = inSize - outBuf[blockLen - 1];
420     } else {
421         outLen = inSize;
422     }
423
424     /* set correct output buffer size */
425     ret = xmlSecBufferSetSize(out, outSize + outLen);
426     if(ret < 0) {
427         xmlSecError(XMLSEC_ERRORS_HERE, 
428                     xmlSecErrorsSafeString(cipherName),
429                     "xmlSecBufferSetSize",
430                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
431                     "size=%d", outSize + outLen);
432         return(-1);
433     }
434
435     /* remove the processed block from input */
436     ret = xmlSecBufferRemoveHead(in, inSize);
437     if(ret < 0) {
438         xmlSecError(XMLSEC_ERRORS_HERE, 
439                     xmlSecErrorsSafeString(cipherName),
440                     "xmlSecBufferRemoveHead",
441                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
442                     "size=%d", inSize);
443         return(-1);
444     }
445     
446     return(0);
447 }
448
449 /******************************************************************************
450  *
451  *  Block Cipher transforms
452  *
453  * xmlSecMSCryptoBlockCipherCtx block is located after xmlSecTransform structure
454  * 
455  *****************************************************************************/
456 #define xmlSecMSCryptoBlockCipherSize   \
457     (sizeof(xmlSecTransform) + sizeof(xmlSecMSCryptoBlockCipherCtx))
458 #define xmlSecMSCryptoBlockCipherGetCtx(transform) \
459     ((xmlSecMSCryptoBlockCipherCtxPtr)(((unsigned char*)(transform)) + sizeof(xmlSecTransform)))
460
461 static int      xmlSecMSCryptoBlockCipherInitialize     (xmlSecTransformPtr transform);
462 static void     xmlSecMSCryptoBlockCipherFinalize       (xmlSecTransformPtr transform);
463 static int      xmlSecMSCryptoBlockCipherSetKeyReq      (xmlSecTransformPtr transform, 
464                                                          xmlSecKeyReqPtr keyReq);
465 static int      xmlSecMSCryptoBlockCipherSetKey         (xmlSecTransformPtr transform,
466                                                          xmlSecKeyPtr key);
467 static int      xmlSecMSCryptoBlockCipherExecute        (xmlSecTransformPtr transform,
468                                                          int last,
469                                                          xmlSecTransformCtxPtr transformCtx);
470 static int      xmlSecMSCryptoBlockCipherCheckId        (xmlSecTransformPtr transform);
471                                                          
472 static int
473 xmlSecMSCryptoBlockCipherCheckId(xmlSecTransformPtr transform) {
474 #ifndef XMLSEC_NO_DES
475     if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformDes3CbcId)) {
476         return(1);
477     }
478 #endif /* XMLSEC_NO_DES */
479
480 #ifndef XMLSEC_NO_AES
481     if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformAes128CbcId) ||
482        xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformAes192CbcId) ||
483        xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformAes256CbcId)) {
484
485        return(1);
486     }
487 #endif /* XMLSEC_NO_AES */
488
489     return(0);
490 }
491
492 static int 
493 xmlSecMSCryptoBlockCipherInitialize(xmlSecTransformPtr transform) {
494     xmlSecMSCryptoBlockCipherCtxPtr ctx;
495
496     xmlSecAssert2(xmlSecMSCryptoBlockCipherCheckId(transform), -1);
497     xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoBlockCipherSize), -1);
498
499     ctx = xmlSecMSCryptoBlockCipherGetCtx(transform);
500     xmlSecAssert2(ctx != NULL, -1);
501     
502     memset(ctx, 0, sizeof(xmlSecMSCryptoBlockCipherCtx));
503
504 #ifndef XMLSEC_NO_DES
505     if(transform->id == xmlSecMSCryptoTransformDes3CbcId) {
506         ctx->algorithmIdentifier    = CALG_3DES;
507         ctx->keyId                  = xmlSecMSCryptoKeyDataDesId;
508         ctx->providerName           = MS_ENHANCED_PROV;
509         ctx->providerType           = PROV_RSA_FULL;
510         ctx->keySize                = 24;
511     } else 
512 #endif /* XMLSEC_NO_DES */
513
514 #ifndef XMLSEC_NO_AES
515     if(transform->id == xmlSecMSCryptoTransformAes128CbcId) {
516         ctx->algorithmIdentifier    = CALG_AES_128;
517         ctx->keyId                  = xmlSecMSCryptoKeyDataAesId;
518         ctx->providerName           = MS_ENH_RSA_AES_PROV_PROTO;
519         ctx->providerType           = PROV_RSA_AES;
520         ctx->keySize                = 16;
521     } else if(transform->id == xmlSecMSCryptoTransformAes192CbcId) {
522         ctx->algorithmIdentifier    = CALG_AES_192;
523         ctx->keyId                  = xmlSecMSCryptoKeyDataAesId;
524         ctx->providerName           = MS_ENH_RSA_AES_PROV_PROTO;
525         ctx->providerType           = PROV_RSA_AES;
526         ctx->keySize                = 24;
527     } else if(transform->id == xmlSecMSCryptoTransformAes256CbcId) {
528         ctx->algorithmIdentifier    = CALG_AES_256;
529         ctx->keyId                  = xmlSecMSCryptoKeyDataAesId;
530         ctx->providerName           = MS_ENH_RSA_AES_PROV_PROTO;
531         ctx->providerType           = PROV_RSA_AES;
532         ctx->keySize                = 32;
533     } else 
534 #endif /* XMLSEC_NO_AES */
535
536     if(1) {
537         xmlSecError(XMLSEC_ERRORS_HERE, 
538             xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
539             NULL,
540             XMLSEC_ERRORS_R_INVALID_TRANSFORM,
541             XMLSEC_ERRORS_NO_MESSAGE);
542         return(-1);
543     }        
544         
545     if(!CryptAcquireContext(&ctx->cryptProvider, NULL /*"xmlSecMSCryptoTempContainer"*/, 
546                              ctx->providerName, ctx->providerType, 0)) {
547         DWORD dwError = GetLastError();
548         if (dwError == NTE_EXISTS) {
549             if (!CryptAcquireContext(&ctx->cryptProvider, "xmlSecMSCryptoTempContainer", 
550                                      ctx->providerName, ctx->providerType, 0)) {
551                 xmlSecError(XMLSEC_ERRORS_HERE, 
552                             xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
553                             "CryptAcquireContext",
554                             XMLSEC_ERRORS_R_CRYPTO_FAILED,
555                             XMLSEC_ERRORS_NO_MESSAGE);
556
557                 return(-1);
558             }
559         } else if (dwError == NTE_BAD_KEYSET) {
560           /* This error can indicate that a newly installed provider 
561            * does not have a usable key container yet. It needs to be
562            * created, and then we have to try again CryptAcquireContext.
563            * This is also referenced in 
564            * http://www.microsoft.com/mind/0697/crypto.asp (inituser)
565            */
566             if(!CryptAcquireContext(&ctx->cryptProvider, NULL, ctx->providerName,
567                                     ctx->providerType, CRYPT_NEWKEYSET)) {
568                 xmlSecError(XMLSEC_ERRORS_HERE, 
569                     xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
570                     "CryptAcquireContext",
571                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
572                     XMLSEC_ERRORS_NO_MESSAGE);
573                 return(-1);
574             }
575         } else {
576             xmlSecError(XMLSEC_ERRORS_HERE, 
577                         xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
578                         "CryptAcquireContext",
579                         XMLSEC_ERRORS_R_CRYPTO_FAILED,
580                         XMLSEC_ERRORS_NO_MESSAGE);
581             return(-1);
582         }
583     }
584
585     /* Create dummy key to be able to import plain session keys */
586     if (!xmlSecMSCryptoCreatePrivateExponentOneKey(ctx->cryptProvider, &(ctx->pubPrivKey))) {
587         xmlSecError(XMLSEC_ERRORS_HERE, 
588                     xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
589                     "xmlSecMSCryptoCreatePrivateExponentOneKey",
590                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
591                     XMLSEC_ERRORS_NO_MESSAGE);
592
593         return(-1);
594     }
595
596     ctx->ctxInitialized = 0;
597     return(0);
598 }
599
600 static void 
601 xmlSecMSCryptoBlockCipherFinalize(xmlSecTransformPtr transform) {
602     xmlSecMSCryptoBlockCipherCtxPtr ctx;
603
604     xmlSecAssert(xmlSecMSCryptoBlockCipherCheckId(transform));
605     xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecMSCryptoBlockCipherSize));
606
607     ctx = xmlSecMSCryptoBlockCipherGetCtx(transform);
608     xmlSecAssert(ctx != NULL);
609
610     if (ctx->cryptKey) {
611         CryptDestroyKey(ctx->cryptKey);
612     }
613     if (ctx->pubPrivKey) {
614         CryptDestroyKey(ctx->pubPrivKey);
615     }
616     if (ctx->cryptProvider) {
617         CryptReleaseContext(ctx->cryptProvider, 0);
618         CryptAcquireContext(&ctx->cryptProvider, "xmlSecMSCryptoTempContainer", 
619                             MS_ENHANCED_PROV, ctx->providerType, CRYPT_DELETEKEYSET);
620     }
621
622     memset(ctx, 0, sizeof(xmlSecMSCryptoBlockCipherCtx));
623 }
624
625 static int  
626 xmlSecMSCryptoBlockCipherSetKeyReq(xmlSecTransformPtr transform,  xmlSecKeyReqPtr keyReq) {
627     xmlSecMSCryptoBlockCipherCtxPtr ctx;
628
629     xmlSecAssert2(xmlSecMSCryptoBlockCipherCheckId(transform), -1);
630     xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1);
631     xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoBlockCipherSize), -1);
632     xmlSecAssert2(keyReq != NULL, -1);
633
634     ctx = xmlSecMSCryptoBlockCipherGetCtx(transform);
635     xmlSecAssert2(ctx != NULL, -1);
636     xmlSecAssert2(ctx->cryptProvider != 0, -1);
637
638     keyReq->keyId       = ctx->keyId;
639     keyReq->keyType     = xmlSecKeyDataTypeSymmetric;
640     if(transform->operation == xmlSecTransformOperationEncrypt) {
641         keyReq->keyUsage = xmlSecKeyUsageEncrypt;
642     } else {
643         keyReq->keyUsage = xmlSecKeyUsageDecrypt;
644     }
645
646     keyReq->keyBitsSize = 8 * ctx->keySize;
647     return(0);
648 }
649
650 static int
651 xmlSecMSCryptoBlockCipherSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) {
652     xmlSecMSCryptoBlockCipherCtxPtr ctx;
653     xmlSecBufferPtr buffer;
654     BYTE* bufData;
655
656     xmlSecAssert2(xmlSecMSCryptoBlockCipherCheckId(transform), -1);
657     xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1);
658     xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoBlockCipherSize), -1);
659     xmlSecAssert2(key != NULL, -1);
660
661     ctx = xmlSecMSCryptoBlockCipherGetCtx(transform);
662     xmlSecAssert2(ctx != NULL, -1);
663     xmlSecAssert2(ctx->keyInitialized == 0, -1);
664     xmlSecAssert2(ctx->keyId != NULL, -1);
665     xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1);
666
667     xmlSecAssert2(ctx->keySize > 0, -1);
668
669     buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key));
670     xmlSecAssert2(buffer != NULL, -1);
671
672     if(xmlSecBufferGetSize(buffer) < ctx->keySize) {
673         xmlSecError(XMLSEC_ERRORS_HERE,
674                     xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
675                     NULL,
676                     XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE,
677                     "keySize=%d;expected=%d",
678                     xmlSecBufferGetSize(buffer), ctx->keySize);
679         return(-1);
680     }
681
682     bufData = xmlSecBufferGetData(buffer);
683     xmlSecAssert2(bufData != NULL, -1);
684
685     /* Import this key and get an HCRYPTKEY handle */
686     if (!xmlSecMSCryptoImportPlainSessionBlob(ctx->cryptProvider,
687         ctx->pubPrivKey,
688         ctx->algorithmIdentifier, 
689         bufData, 
690         ctx->keySize, 
691         &(ctx->cryptKey)))  {
692
693         xmlSecError(XMLSEC_ERRORS_HERE, 
694                     xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
695                     "xmlSecMSCryptoImportPlainSessionBlob",
696                     XMLSEC_ERRORS_R_XMLSEC_FAILED,
697                     XMLSEC_ERRORS_NO_MESSAGE);
698         return(-1);
699     }
700
701     ctx->keyInitialized = 1;
702     return(0);
703 }
704
705 static int 
706 xmlSecMSCryptoBlockCipherExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) {
707     xmlSecMSCryptoBlockCipherCtxPtr ctx;
708     xmlSecBufferPtr in, out;
709     int ret;
710     
711     xmlSecAssert2(xmlSecMSCryptoBlockCipherCheckId(transform), -1);
712     xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1);
713     xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoBlockCipherSize), -1);
714     xmlSecAssert2(transformCtx != NULL, -1);
715         
716     in = &(transform->inBuf);
717     out = &(transform->outBuf);
718
719     ctx = xmlSecMSCryptoBlockCipherGetCtx(transform);
720     xmlSecAssert2(ctx != NULL, -1);
721
722     if(transform->status == xmlSecTransformStatusNone) {
723         transform->status = xmlSecTransformStatusWorking;
724     }
725
726     if(transform->status == xmlSecTransformStatusWorking) {
727         if(ctx->ctxInitialized == 0) {
728             ret = xmlSecMSCryptoBlockCipherCtxInit(ctx, 
729                                                    in, 
730                                                    out,
731                                                    (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0,
732                                                    xmlSecTransformGetName(transform),
733                                                    transformCtx);
734                                 
735             if(ret < 0) {
736                 xmlSecError(XMLSEC_ERRORS_HERE, 
737                             xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
738                             "xmlSecMSCryptoBlockCipherCtxInit",
739                             XMLSEC_ERRORS_R_XMLSEC_FAILED,
740                             XMLSEC_ERRORS_NO_MESSAGE);
741                 return(-1);
742             }
743         }
744         if((ctx->ctxInitialized == 0) && (last != 0)) {
745             xmlSecError(XMLSEC_ERRORS_HERE, 
746                         xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
747                         NULL,
748                         XMLSEC_ERRORS_R_INVALID_DATA,
749                         "not enough data to initialize transform");
750             return(-1);
751         }
752         if(ctx->ctxInitialized != 0) {
753             ret = xmlSecMSCryptoBlockCipherCtxUpdate(ctx, in, out, 
754                 (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0,
755                 xmlSecTransformGetName(transform), transformCtx);
756             if(ret < 0) {
757                 xmlSecError(XMLSEC_ERRORS_HERE, 
758                             xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
759                             "xmlSecMSCryptoBlockCipherCtxUpdate",
760                             XMLSEC_ERRORS_R_XMLSEC_FAILED,
761                             XMLSEC_ERRORS_NO_MESSAGE);
762                 return(-1);
763             }
764         }
765         
766         if(last) {
767             ret = xmlSecMSCryptoBlockCipherCtxFinal(ctx, in, out, 
768                 (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0,
769                 xmlSecTransformGetName(transform), transformCtx);
770
771             if(ret < 0) {
772                 xmlSecError(XMLSEC_ERRORS_HERE, 
773                             xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
774                             "xmlSecMSCryptoBlockCipherCtxFinal",
775                             XMLSEC_ERRORS_R_XMLSEC_FAILED,
776                             XMLSEC_ERRORS_NO_MESSAGE);
777                 return(-1);
778             }
779             transform->status = xmlSecTransformStatusFinished;
780         } 
781     } else if(transform->status == xmlSecTransformStatusFinished) {
782         /* the only way we can get here is if there is no input */
783         xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1);
784     } else if(transform->status == xmlSecTransformStatusNone) {
785         /* the only way we can get here is if there is no enough data in the input */
786         xmlSecAssert2(last == 0, -1);
787     } else {
788         xmlSecError(XMLSEC_ERRORS_HERE, 
789                     xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
790                     NULL,
791                     XMLSEC_ERRORS_R_INVALID_STATUS,
792                     "status=%d", transform->status);
793         return(-1);
794     }
795     
796     return(0);
797 }
798
799 #ifndef XMLSEC_NO_AES
800 /*********************************************************************
801  *
802  * AES CBC cipher transforms
803  *
804  ********************************************************************/
805 static xmlSecTransformKlass xmlSecMSCryptoAes128CbcKlass = {
806     /* klass/object sizes */
807     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
808     xmlSecMSCryptoBlockCipherSize,              /* xmlSecSize objSize */
809
810     xmlSecNameAes128Cbc,                        /* const xmlChar* name; */
811     xmlSecHrefAes128Cbc,                        /* const xmlChar* href; */
812     xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */
813
814     xmlSecMSCryptoBlockCipherInitialize,        /* xmlSecTransformInitializeMethod initialize; */
815     xmlSecMSCryptoBlockCipherFinalize,          /* xmlSecTransformFinalizeMethod finalize; */
816     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
817     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
818     xmlSecMSCryptoBlockCipherSetKeyReq,         /* xmlSecTransformSetKeyMethod setKeyReq; */
819     xmlSecMSCryptoBlockCipherSetKey,            /* xmlSecTransformSetKeyMethod setKey; */
820     NULL,                                       /* xmlSecTransformValidateMethod validate; */
821     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
822     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
823     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
824     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
825     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
826     xmlSecMSCryptoBlockCipherExecute,           /* xmlSecTransformExecuteMethod execute; */
827
828     NULL,                                       /* void* reserved0; */
829     NULL,                                       /* void* reserved1; */
830 };
831
832 /**
833  * xmlSecMSCryptoTransformAes128CbcGetKlass:
834  * 
835  * AES 128 CBC encryption transform klass.
836  * 
837  * Returns: pointer to AES 128 CBC encryption transform.
838  */ 
839 xmlSecTransformId 
840 xmlSecMSCryptoTransformAes128CbcGetKlass(void) {
841     return(&xmlSecMSCryptoAes128CbcKlass);
842 }
843
844 static xmlSecTransformKlass xmlSecMSCryptoAes192CbcKlass = {
845     /* klass/object sizes */
846     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
847     xmlSecMSCryptoBlockCipherSize,              /* xmlSecSize objSize */
848
849     xmlSecNameAes192Cbc,                        /* const xmlChar* name; */
850     xmlSecHrefAes192Cbc,                        /* const xmlChar* href; */
851     xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */
852
853     xmlSecMSCryptoBlockCipherInitialize,        /* xmlSecTransformInitializeMethod initialize; */
854     xmlSecMSCryptoBlockCipherFinalize,          /* xmlSecTransformFinalizeMethod finalize; */
855     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
856     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
857     xmlSecMSCryptoBlockCipherSetKeyReq,         /* xmlSecTransformSetKeyMethod setKeyReq; */
858     xmlSecMSCryptoBlockCipherSetKey,            /* xmlSecTransformSetKeyMethod setKey; */
859     NULL,                                       /* xmlSecTransformValidateMethod validate; */
860     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
861     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
862     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
863     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
864     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
865     xmlSecMSCryptoBlockCipherExecute,           /* xmlSecTransformExecuteMethod execute; */
866     
867     NULL,                                       /* void* reserved0; */
868     NULL,                                       /* void* reserved1; */
869 };
870
871 /**
872  * xmlSecMSCryptoTransformAes192CbcGetKlass:
873  * 
874  * AES 192 CBC encryption transform klass.
875  * 
876  * Returns: pointer to AES 192 CBC encryption transform.
877  */ 
878 xmlSecTransformId 
879 xmlSecMSCryptoTransformAes192CbcGetKlass(void) {
880     return(&xmlSecMSCryptoAes192CbcKlass);
881 }
882
883 static xmlSecTransformKlass xmlSecMSCryptoAes256CbcKlass = {
884     /* klass/object sizes */
885     sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
886     xmlSecMSCryptoBlockCipherSize,              /* xmlSecSize objSize */
887
888     xmlSecNameAes256Cbc,                        /* const xmlChar* name; */
889     xmlSecHrefAes256Cbc,                        /* const xmlChar* href; */
890     xmlSecTransformUsageEncryptionMethod,       /* xmlSecAlgorithmUsage usage; */
891
892     xmlSecMSCryptoBlockCipherInitialize,        /* xmlSecTransformInitializeMethod initialize; */
893     xmlSecMSCryptoBlockCipherFinalize,          /* xmlSecTransformFinalizeMethod finalize; */
894     NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
895     NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
896     xmlSecMSCryptoBlockCipherSetKeyReq,         /* xmlSecTransformSetKeyMethod setKeyReq; */
897     xmlSecMSCryptoBlockCipherSetKey,            /* xmlSecTransformSetKeyMethod setKey; */
898     NULL,                                       /* xmlSecTransformValidateMethod validate; */
899     xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
900     xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
901     xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
902     NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
903     NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
904     xmlSecMSCryptoBlockCipherExecute,           /* xmlSecTransformExecuteMethod execute; */
905     
906     NULL,                                       /* void* reserved0; */
907     NULL,                                       /* void* reserved1; */
908 };
909
910 /**
911  * xmlSecMSCryptoTransformAes256CbcGetKlass:
912  * 
913  * AES 256 CBC encryption transform klass.
914  * 
915  * Returns: pointer to AES 256 CBC encryption transform.
916  */ 
917 xmlSecTransformId 
918 xmlSecMSCryptoTransformAes256CbcGetKlass(void) {
919     return(&xmlSecMSCryptoAes256CbcKlass);
920 }
921
922 #endif /* XMLSEC_NO_AES */
923
924
925 #ifndef XMLSEC_NO_DES
926 static xmlSecTransformKlass xmlSecMSCryptoDes3CbcKlass = {
927     /* klass/object sizes */
928     sizeof(xmlSecTransformKlass),       /* size_t klassSize */
929     xmlSecMSCryptoBlockCipherSize,      /* size_t objSize */
930
931     xmlSecNameDes3Cbc,                  /* const xmlChar* name; */
932     xmlSecHrefDes3Cbc,                  /* const xmlChar* href; */
933     xmlSecTransformUsageEncryptionMethod,/* xmlSecAlgorithmUsage usage; */
934
935     xmlSecMSCryptoBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */
936     xmlSecMSCryptoBlockCipherFinalize,   /* xmlSecTransformFinalizeMethod finalize; */
937     NULL,                                /* xmlSecTransformNodeReadMethod readNode; */
938     NULL,                                /* xmlSecTransformNodeWriteMethod writeNode; */
939     xmlSecMSCryptoBlockCipherSetKeyReq,  /* xmlSecTransformSetKeyMethod setKeyReq; */
940     xmlSecMSCryptoBlockCipherSetKey,     /* xmlSecTransformSetKeyMethod setKey; */
941     NULL,                                /* xmlSecTransformValidateMethod validate; */
942     xmlSecTransformDefaultGetDataType,   /* xmlSecTransformGetDataTypeMethod getDataType; */
943     xmlSecTransformDefaultPushBin,       /* xmlSecTransformPushBinMethod pushBin; */
944     xmlSecTransformDefaultPopBin,        /* xmlSecTransformPopBinMethod popBin; */
945     NULL,                                /* xmlSecTransformPushXmlMethod pushXml; */
946     NULL,                                /* xmlSecTransformPopXmlMethod popXml; */
947     xmlSecMSCryptoBlockCipherExecute,    /* xmlSecTransformExecuteMethod execute; */
948     
949     NULL,                                /* void* reserved0; */
950     NULL,                                /* void* reserved1; */
951 };
952
953 /** 
954  * xmlSecMSCryptoTransformDes3CbcGetKlass:
955  *
956  * Triple DES CBC encryption transform klass.
957  * 
958  * Returns: pointer to Triple DES encryption transform.
959  */
960 xmlSecTransformId 
961 xmlSecMSCryptoTransformDes3CbcGetKlass(void) {
962     return(&xmlSecMSCryptoDes3CbcKlass);
963 }
964 #endif /* XMLSEC_NO_DES */
965
966 /*
967  * Low level helper routines for importing plain text keys in MS HKEY handle, 
968  * since MSCrypto API does not support import of plain text (session) keys
969  * just like that.
970  * These functions are based upon MS kb article: 228786
971  * 
972  * aleksey: also check "Base Provider Key BLOBs" article for priv key blob format
973  **/
974 static BOOL 
975 xmlSecMSCryptoCreatePrivateExponentOneKey(HCRYPTPROV hProv, HCRYPTKEY *hPrivateKey)
976 {
977     HCRYPTKEY hKey = 0;
978     LPBYTE keyBlob = NULL;
979     DWORD keyBlobLen;
980     PUBLICKEYSTRUC* pubKeyStruc;
981     RSAPUBKEY* rsaPubKey;
982     DWORD bitLen;
983     BYTE *ptr;
984     int n;
985     BOOL res = FALSE;
986
987     xmlSecAssert2(hProv != 0, FALSE);
988     xmlSecAssert2(hPrivateKey != NULL, FALSE);
989
990     /* just in case */
991     *hPrivateKey = 0;
992
993     /* Generate the private key */
994     if(!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey)) {
995         xmlSecError(XMLSEC_ERRORS_HERE, 
996                     NULL,
997                     "CryptGenKey",
998                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
999                     XMLSEC_ERRORS_NO_MESSAGE);
1000         goto done;
1001     }
1002
1003     /* Export the private key, we'll convert it to a private exponent of one key */
1004     if(!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, NULL, &keyBlobLen)) {
1005         xmlSecError(XMLSEC_ERRORS_HERE, 
1006                     NULL,
1007                     "CryptExportKey",
1008                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1009                     XMLSEC_ERRORS_NO_MESSAGE);
1010         goto done;
1011     }
1012
1013     keyBlob = (LPBYTE)xmlMalloc(sizeof(BYTE) * keyBlobLen);
1014     if(keyBlob == NULL) {
1015         xmlSecError(XMLSEC_ERRORS_HERE, 
1016                     NULL,
1017                     NULL,
1018                     XMLSEC_ERRORS_R_MALLOC_FAILED,
1019                     XMLSEC_ERRORS_NO_MESSAGE);
1020         goto done;
1021     }
1022  
1023     if(!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, keyBlob, &keyBlobLen)) {
1024         xmlSecError(XMLSEC_ERRORS_HERE, 
1025                     NULL,
1026                     "CryptExportKey",
1027                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1028                     XMLSEC_ERRORS_NO_MESSAGE);
1029         goto done;
1030     }
1031     CryptDestroyKey(hKey);
1032     hKey = 0;
1033
1034     /* Get the bit length of the key */
1035     if(keyBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)) {
1036         xmlSecError(XMLSEC_ERRORS_HERE, 
1037                     NULL,
1038                     "CryptExportKey",
1039                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1040                     "len=%ld", keyBlobLen);
1041         goto done;
1042     }
1043     pubKeyStruc = (PUBLICKEYSTRUC*)keyBlob;
1044     if(pubKeyStruc->bVersion != 0x02) {
1045         xmlSecError(XMLSEC_ERRORS_HERE, 
1046                     NULL,
1047                     "CryptExportKey",
1048                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1049                     "pubKeyStruc->bVersion=%d", pubKeyStruc->bVersion);
1050         goto done;
1051     }
1052     if(pubKeyStruc->bType != PRIVATEKEYBLOB) {
1053         xmlSecError(XMLSEC_ERRORS_HERE, 
1054                     NULL,
1055                     "CryptExportKey",
1056                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1057                     "pubKeyStruc->bType=%d", (int)pubKeyStruc->bType);
1058         goto done;
1059     }
1060
1061     /* aleksey: don't ask me why it is RSAPUBKEY, just don't ask */
1062     rsaPubKey = (RSAPUBKEY*)(keyBlob + sizeof(PUBLICKEYSTRUC)); 
1063
1064     /* check that we have RSA private key */
1065     if(rsaPubKey->magic != 0x32415352) { 
1066         xmlSecError(XMLSEC_ERRORS_HERE, 
1067                     NULL,
1068                     "CryptExportKey",
1069                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1070                     "rsaPubKey->magic=0x%08lx", rsaPubKey->magic);
1071         goto done;
1072     }
1073     bitLen = rsaPubKey->bitlen;
1074
1075     /*  Modify the Exponent in Key BLOB format Key BLOB format is documented in SDK */
1076     rsaPubKey->pubexp = 1;
1077
1078     /* Private-key BLOBs, type PRIVATEKEYBLOB, are used to store private keys outside a CSP. 
1079      * Base provider private-key BLOBs have the following format:
1080      * 
1081      * PUBLICKEYSTRUC  publickeystruc ;
1082      * RSAPUBKEY rsapubkey;
1083      * BYTE modulus[rsapubkey.bitlen/8];                1/8
1084      * BYTE prime1[rsapubkey.bitlen/16];                1/16 
1085      * BYTE prime2[rsapubkey.bitlen/16];                1/16 
1086      * BYTE exponent1[rsapubkey.bitlen/16];             1/16 
1087      * BYTE exponent2[rsapubkey.bitlen/16];             1/16 
1088      * BYTE coefficient[rsapubkey.bitlen/16];           1/16
1089      * BYTE privateExponent[rsapubkey.bitlen/8];        1/8
1090      */
1091     if(keyBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + bitLen / 2 + bitLen / 16) {
1092         xmlSecError(XMLSEC_ERRORS_HERE, 
1093                     NULL,
1094                     "CryptExportKey",
1095                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1096                     "len=%ld", keyBlobLen);
1097         goto done;
1098     }
1099     ptr = (BYTE*)(keyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)); 
1100
1101     /* Skip modulus, prime1, prime2 */
1102     ptr += bitLen / 8;
1103     ptr += bitLen / 16;
1104     ptr += bitLen / 16;
1105
1106     /* Convert exponent1 to 1 */
1107     for (n = 0; n < (bitLen / 16); n++) {
1108         if (n == 0) ptr[n] = 1;
1109         else ptr[n] = 0;
1110     }
1111     ptr += bitLen / 16;
1112
1113     /* Convert exponent2 to 1 */
1114     for (n = 0; n < (bitLen / 16); n++) {
1115         if (n == 0) ptr[n] = 1;
1116         else ptr[n] = 0;
1117     }
1118     ptr += bitLen / 16;
1119
1120     /* Skip coefficient */
1121     ptr += bitLen / 16;
1122
1123     /* Convert privateExponent to 1 */
1124     for (n = 0; n < (bitLen / 16); n++) {
1125         if (n == 0) ptr[n] = 1;
1126         else ptr[n] = 0;
1127     }
1128
1129     /* Import the exponent-of-one private key. */
1130     if (!CryptImportKey(hProv, keyBlob, keyBlobLen, 0, 0, &hKey)) {                 
1131         xmlSecError(XMLSEC_ERRORS_HERE, 
1132                     NULL,
1133                     "CryptImportKey",
1134                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1135                     XMLSEC_ERRORS_NO_MESSAGE);
1136         goto done;
1137     }
1138     (*hPrivateKey) = hKey;
1139     hKey = 0;
1140     res = TRUE;
1141    
1142 done:
1143     if(keyBlob != NULL) { 
1144         xmlFree(keyBlob);
1145     }
1146     if (hKey != 0) {
1147         CryptDestroyKey(hKey);
1148     }
1149
1150     return res;
1151 }
1152
1153 static BOOL 
1154 xmlSecMSCryptoImportPlainSessionBlob(HCRYPTPROV hProv, HCRYPTKEY hPrivateKey,
1155                                      ALG_ID dwAlgId, LPBYTE pbKeyMaterial,
1156                                      DWORD dwKeyMaterial, HCRYPTKEY *hSessionKey) {
1157     ALG_ID dwPrivKeyAlg;
1158     LPBYTE keyBlob = NULL;
1159     DWORD keyBlobLen, rndBlobSize, dwSize, n;
1160     PUBLICKEYSTRUC* pubKeyStruc;
1161     ALG_ID* algId;
1162     DWORD dwPublicKeySize;
1163     DWORD dwProvSessionKeySize;
1164     LPBYTE pbPtr; 
1165     DWORD dwFlags;
1166     PROV_ENUMALGS_EX ProvEnum;
1167     HCRYPTKEY hTempKey = 0;
1168     BOOL fFound;
1169     BOOL res = FALSE;
1170     
1171     xmlSecAssert2(hProv != 0, FALSE);
1172     xmlSecAssert2(hPrivateKey != 0, FALSE);
1173     xmlSecAssert2(pbKeyMaterial != NULL, FALSE);
1174     xmlSecAssert2(dwKeyMaterial > 0, FALSE);
1175     xmlSecAssert2(hSessionKey != NULL, FALSE);
1176
1177     /*  Double check to see if this provider supports this algorithm and key size */
1178     fFound = FALSE;
1179     dwFlags = CRYPT_FIRST;
1180     dwSize = sizeof(ProvEnum);
1181     while(CryptGetProvParam(hProv, PP_ENUMALGS_EX, (LPBYTE)&ProvEnum, &dwSize, dwFlags)) {
1182         if (ProvEnum.aiAlgid == dwAlgId) {
1183             fFound = TRUE;
1184             break;
1185         }
1186         dwSize = sizeof(ProvEnum);
1187         dwFlags = 0;
1188     }
1189     if(!fFound) {
1190         xmlSecError(XMLSEC_ERRORS_HERE, 
1191                     NULL,
1192                     "CryptGetProvParam",
1193                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1194                     "algId=%d is not supported", dwAlgId);
1195         goto done;
1196     }
1197
1198     /* We have to get the key size(including padding) from an HCRYPTKEY handle.  
1199      * PP_ENUMALGS_EX contains the key size without the padding so we can't use it.
1200      */
1201     if(!CryptGenKey(hProv, dwAlgId, 0, &hTempKey)) {
1202         xmlSecError(XMLSEC_ERRORS_HERE, 
1203                     NULL,
1204                     "CryptGenKey",
1205                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1206                     "algId=%d", dwAlgId);
1207         goto done;
1208     }
1209
1210     dwSize = sizeof(DWORD);
1211     if(!CryptGetKeyParam(hTempKey, KP_KEYLEN, (LPBYTE)&dwProvSessionKeySize, &dwSize, 0)) {
1212         xmlSecError(XMLSEC_ERRORS_HERE, 
1213                     NULL,
1214                     "CryptGetKeyParam(KP_KEYLEN)",
1215                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1216                     "algId=%d", dwAlgId);
1217         goto done;
1218     }
1219     CryptDestroyKey(hTempKey);
1220     hTempKey = 0;
1221
1222     /* Our key is too big, leave */
1223     if ((dwKeyMaterial * 8) > dwProvSessionKeySize) {
1224         xmlSecError(XMLSEC_ERRORS_HERE, 
1225                     NULL,
1226                     NULL,
1227                     XMLSEC_ERRORS_R_INVALID_SIZE,
1228                     "dwKeyMaterial=%ld;dwProvSessionKeySize=%ld", 
1229                     dwKeyMaterial, dwProvSessionKeySize);
1230         goto done;
1231     }
1232
1233     /* Get private key's algorithm */
1234     dwSize = sizeof(ALG_ID);
1235     if(!CryptGetKeyParam(hPrivateKey, KP_ALGID, (LPBYTE)&dwPrivKeyAlg, &dwSize, 0)) {
1236         xmlSecError(XMLSEC_ERRORS_HERE, 
1237                     NULL,
1238                     "CryptGetKeyParam(KP_ALGID)",
1239                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1240                     "algId=%d", dwAlgId);
1241         goto done;
1242     }
1243
1244     /* Get private key's length in bits */
1245     dwSize = sizeof(DWORD);
1246     if(!CryptGetKeyParam(hPrivateKey, KP_KEYLEN, (LPBYTE)&dwPublicKeySize, &dwSize, 0)) {
1247         xmlSecError(XMLSEC_ERRORS_HERE, 
1248                     NULL,
1249                     "CryptGetKeyParam(KP_KEYLEN)",
1250                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1251                     "algId=%d", dwAlgId);
1252         goto done;
1253     }
1254     
1255     /* 3 is for the first reserved byte after the key material and the 2 reserved bytes at the end. */
1256     if(dwPublicKeySize / 8 < dwKeyMaterial + 3) {
1257         xmlSecError(XMLSEC_ERRORS_HERE, 
1258                     NULL,
1259                     NULL,
1260                     XMLSEC_ERRORS_R_INVALID_SIZE,
1261                     "dwKeyMaterial=%ld;dwPublicKeySize=%ld", 
1262                     dwKeyMaterial, dwPublicKeySize);
1263         goto done;
1264     }
1265     rndBlobSize = dwPublicKeySize / 8 - (dwKeyMaterial + 3);
1266
1267     /* Simple key BLOBs, type SIMPLEBLOB, are used to store and transport session keys outside a CSP. 
1268      * Base provider simple-key BLOBs are always encrypted with a key exchange public key. The pbData 
1269      * member of the SIMPLEBLOB is a sequence of bytes in the following format:
1270      * 
1271      * PUBLICKEYSTRUC  publickeystruc ;
1272      * ALG_ID algid;
1273      * BYTE encryptedkey[rsapubkey.bitlen/8];
1274      */
1275
1276     /* calculate Simple blob's length */
1277     keyBlobLen = sizeof(PUBLICKEYSTRUC) + sizeof(ALG_ID) + (dwPublicKeySize / 8);
1278
1279     /* allocate simple blob buffer */
1280     keyBlob = (LPBYTE)xmlMalloc(sizeof(BYTE) * keyBlobLen);
1281     if(keyBlob == NULL) {
1282         xmlSecError(XMLSEC_ERRORS_HERE, 
1283                     NULL,
1284                     NULL,
1285                     XMLSEC_ERRORS_R_MALLOC_FAILED,
1286                     XMLSEC_ERRORS_NO_MESSAGE);
1287         goto done;
1288     }
1289     memset(keyBlob, 0, keyBlobLen);
1290
1291     /* initialize PUBLICKEYSTRUC */
1292     pubKeyStruc             = (PUBLICKEYSTRUC*)(keyBlob);
1293     pubKeyStruc->bType      = SIMPLEBLOB;
1294     pubKeyStruc->bVersion   = 0x02;
1295     pubKeyStruc->reserved   = 0;
1296     pubKeyStruc->aiKeyAlg   = dwAlgId;  
1297
1298     /* Copy private key algorithm to buffer */
1299     algId                   = (ALG_ID*)(keyBlob + sizeof(PUBLICKEYSTRUC));
1300     (*algId)                = dwPrivKeyAlg;
1301
1302     /* Place the key material in reverse order */
1303     pbPtr                   = (BYTE*)(keyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(ALG_ID));
1304     for (n = 0; n < dwKeyMaterial; n++) {
1305         pbPtr[n] = pbKeyMaterial[dwKeyMaterial - n - 1];
1306     }
1307     pbPtr += dwKeyMaterial;
1308
1309     /* skip reserved byte */
1310     pbPtr += 1;
1311
1312     /* Generate random data for the rest of the buffer */
1313     if((rndBlobSize > 0) && !CryptGenRandom(hProv, rndBlobSize, pbPtr)) {
1314         xmlSecError(XMLSEC_ERRORS_HERE, 
1315                     NULL,
1316                     "CryptGenRandom",
1317                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1318                     "rndBlobSize=%ld", rndBlobSize);
1319         goto done;
1320     }
1321     /* aleksey: why are we doing this? */
1322     for (n = 0; n < rndBlobSize; n++) {
1323         if (pbPtr[n] == 0) pbPtr[n] = 1;
1324     }
1325
1326     /* set magic number at the end */
1327     keyBlob[keyBlobLen - 2] = 2;
1328
1329     if(!CryptImportKey(hProv, keyBlob , keyBlobLen, hPrivateKey, CRYPT_EXPORTABLE, hSessionKey)) {
1330         xmlSecError(XMLSEC_ERRORS_HERE, 
1331                     NULL,
1332                     "CryptImportKey",
1333                     XMLSEC_ERRORS_R_CRYPTO_FAILED,
1334                     "algId=%d", dwAlgId);
1335         goto done;
1336     }
1337
1338     /* success */
1339     res = TRUE;           
1340
1341 done:
1342     if(hTempKey != 0) {
1343         CryptDestroyKey(hTempKey);
1344     }
1345     if(keyBlob != NULL) {
1346         xmlFree(keyBlob);
1347     }
1348     return(res);
1349 }
1350