4 * This is free software; see Copyright file in the source
5 * distribution for preciese wording.
7 * Copyrigth (C) 2003 Cordys R&D BV, All rights reserved.
8 * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com>
17 #include <xmlsec/xmlsec.h>
18 #include <xmlsec/keys.h>
19 #include <xmlsec/transforms.h>
20 #include <xmlsec/errors.h>
22 #include <xmlsec/mscrypto/crypto.h>
24 #if defined(__MINGW32__)
25 # include "xmlsec-mingw.h"
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 */
32 static BOOL xmlSecMSCryptoCreatePrivateExponentOneKey (HCRYPTPROV hProv,
33 HCRYPTKEY *hPrivateKey);
34 static BOOL xmlSecMSCryptoImportPlainSessionBlob (HCRYPTPROV hProv,
35 HCRYPTKEY hPrivateKey,
39 HCRYPTKEY *hSessionKey);
41 /**************************************************************************
43 * Internal MSCrypto Block cipher CTX
45 *****************************************************************************/
46 typedef struct _xmlSecMSCryptoBlockCipherCtx xmlSecMSCryptoBlockCipherCtx,
47 *xmlSecMSCryptoBlockCipherCtxPtr;
48 struct _xmlSecMSCryptoBlockCipherCtx {
49 ALG_ID algorithmIdentifier;
51 HCRYPTPROV cryptProvider;
54 xmlSecKeyDataId keyId;
61 /* function declarations */
62 static int xmlSecMSCryptoBlockCipherCtxUpdate (xmlSecMSCryptoBlockCipherCtxPtr ctx,
66 const xmlChar* cipherName,
67 xmlSecTransformCtxPtr transformCtx);
71 xmlSecMSCryptoBlockCipherCtxInit(xmlSecMSCryptoBlockCipherCtxPtr ctx,
75 const xmlChar* cipherName,
76 xmlSecTransformCtxPtr transformCtx) {
79 DWORD dwBlockLen, dwBlockLenLen;
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);
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),
94 XMLSEC_ERRORS_R_CRYPTO_FAILED,
95 XMLSEC_ERRORS_NO_MESSAGE);
99 blockLen = dwBlockLen / 8;
100 xmlSecAssert2(blockLen > 0, -1);
105 /* allocate space for IV */
106 outSize = xmlSecBufferGetSize(out);
107 ret = xmlSecBufferSetSize(out, outSize + blockLen);
109 xmlSecError(XMLSEC_ERRORS_HERE,
110 xmlSecErrorsSafeString(cipherName),
111 "xmlSecBufferSetSize",
112 XMLSEC_ERRORS_R_XMLSEC_FAILED,
113 "size=%d", outSize + blockLen);
116 iv = xmlSecBufferGetData(out) + outSize;
118 /* generate and use random iv */
119 if(!CryptGenRandom(ctx->cryptProvider, blockLen, iv)) {
120 xmlSecError(XMLSEC_ERRORS_HERE,
121 xmlSecErrorsSafeString(cipherName),
123 XMLSEC_ERRORS_R_CRYPTO_FAILED,
128 if(!CryptSetKeyParam(ctx->cryptKey, KP_IV, iv, 0)) {
129 xmlSecError(XMLSEC_ERRORS_HERE,
130 xmlSecErrorsSafeString(cipherName),
132 XMLSEC_ERRORS_R_CRYPTO_FAILED,
133 XMLSEC_ERRORS_NO_MESSAGE);
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) {
142 xmlSecAssert2(xmlSecBufferGetData(in) != NULL, -1);
145 if (!CryptSetKeyParam(ctx->cryptKey, KP_IV, xmlSecBufferGetData(in), 0)) {
146 xmlSecError(XMLSEC_ERRORS_HERE,
147 xmlSecErrorsSafeString(cipherName),
149 XMLSEC_ERRORS_R_CRYPTO_FAILED,
150 XMLSEC_ERRORS_NO_MESSAGE);
154 /* and remove from input */
155 ret = xmlSecBufferRemoveHead(in, blockLen);
157 xmlSecError(XMLSEC_ERRORS_HERE,
158 xmlSecErrorsSafeString(cipherName),
159 "xmlSecBufferRemoveHead",
160 XMLSEC_ERRORS_R_XMLSEC_FAILED,
161 "size=%d", blockLen);
167 ctx->ctxInitialized = 1;
172 xmlSecMSCryptoBlockCipherCtxUpdate(xmlSecMSCryptoBlockCipherCtxPtr ctx,
173 xmlSecBufferPtr in, xmlSecBufferPtr out,
175 const xmlChar* cipherName,
176 xmlSecTransformCtxPtr transformCtx) {
177 size_t inSize, inBlocks, outSize;
179 unsigned char* outBuf;
180 unsigned char* inBuf;
182 DWORD dwBlockLen, dwBlockLenLen, dwCLen;
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);
190 dwBlockLenLen = sizeof(DWORD);
191 if (!CryptGetKeyParam(ctx->cryptKey, KP_BLOCKLEN, (BYTE *)&dwBlockLen, &dwBlockLenLen, 0)) {
192 xmlSecError(XMLSEC_ERRORS_HERE,
193 xmlSecErrorsSafeString(cipherName),
195 XMLSEC_ERRORS_R_CRYPTO_FAILED,
196 XMLSEC_ERRORS_NO_MESSAGE);
199 blockLen = dwBlockLen / 8;
200 xmlSecAssert2(blockLen > 0, -1);
202 inSize = xmlSecBufferGetSize(in);
203 outSize = xmlSecBufferGetSize(out);
205 if(inSize < (size_t)blockLen) {
210 inBlocks = inSize / ((size_t)blockLen);
212 /* we want to have the last block in the input buffer
213 * for padding check */
214 inBlocks = (inSize - 1) / ((size_t)blockLen);
216 inSize = inBlocks * ((size_t)blockLen);
218 /* we write out the input size plus may be one block */
219 ret = xmlSecBufferSetMaxSize(out, outSize + inSize + blockLen);
221 xmlSecError(XMLSEC_ERRORS_HERE,
222 xmlSecErrorsSafeString(cipherName),
223 "xmlSecBufferSetMaxSize",
224 XMLSEC_ERRORS_R_XMLSEC_FAILED,
225 "size=%d", outSize + inSize + blockLen);
228 outBuf = xmlSecBufferGetData(out) + outSize;
229 inBuf = xmlSecBufferGetData(in);
230 xmlSecAssert2(inBuf != NULL, -1);
232 memcpy(outBuf, inBuf, inSize);
235 if(!CryptEncrypt(ctx->cryptKey, 0, FALSE, 0, outBuf, &dwCLen, inSize + blockLen)) {
236 xmlSecError(XMLSEC_ERRORS_HERE,
237 xmlSecErrorsSafeString(cipherName),
239 XMLSEC_ERRORS_R_CRYPTO_FAILED,
240 XMLSEC_ERRORS_NO_MESSAGE);
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);
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),
258 XMLSEC_ERRORS_R_XMLSEC_FAILED,
263 /* set correct output buffer size */
264 ret = xmlSecBufferSetSize(out, outSize + inSize);
266 xmlSecError(XMLSEC_ERRORS_HERE,
267 xmlSecErrorsSafeString(cipherName),
268 "xmlSecBufferSetSize",
269 XMLSEC_ERRORS_R_XMLSEC_FAILED,
270 "size=%d", outSize + inSize);
274 /* remove the processed block from input */
275 ret = xmlSecBufferRemoveHead(in, inSize);
277 xmlSecError(XMLSEC_ERRORS_HERE,
278 xmlSecErrorsSafeString(cipherName),
279 "xmlSecBufferRemoveHead",
280 XMLSEC_ERRORS_R_XMLSEC_FAILED,
288 xmlSecMSCryptoBlockCipherCtxFinal(xmlSecMSCryptoBlockCipherCtxPtr ctx,
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;
299 DWORD dwBlockLen, dwBlockLenLen, dwCLen;
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);
307 dwBlockLenLen = sizeof(DWORD);
308 if (!CryptGetKeyParam(ctx->cryptKey, KP_BLOCKLEN, (BYTE *)&dwBlockLen, &dwBlockLenLen, 0)) {
309 xmlSecError(XMLSEC_ERRORS_HERE,
310 xmlSecErrorsSafeString(cipherName),
312 XMLSEC_ERRORS_R_CRYPTO_FAILED,
313 XMLSEC_ERRORS_NO_MESSAGE);
316 blockLen = dwBlockLen / 8;
317 xmlSecAssert2(blockLen > 0, -1);
319 inSize = xmlSecBufferGetSize(in);
320 outSize = xmlSecBufferGetSize(out);
323 xmlSecAssert2(inSize < (size_t)blockLen, -1);
326 ret = xmlSecBufferSetMaxSize(in, blockLen);
328 xmlSecError(XMLSEC_ERRORS_HERE,
329 xmlSecErrorsSafeString(cipherName),
330 "xmlSecBufferSetMaxSize",
331 XMLSEC_ERRORS_R_XMLSEC_FAILED,
332 "size=%d", blockLen);
335 inBuf = xmlSecBufferGetData(in);
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),
343 XMLSEC_ERRORS_R_CRYPTO_FAILED,
344 XMLSEC_ERRORS_NO_MESSAGE);
348 inBuf[blockLen - 1] = blockLen - inSize;
351 if(inSize != (size_t)blockLen) {
352 xmlSecError(XMLSEC_ERRORS_HERE,
353 xmlSecErrorsSafeString(cipherName),
355 XMLSEC_ERRORS_R_INVALID_DATA,
356 "data=%d;block=%d", inSize, blockLen);
359 inBuf = xmlSecBufferGetData(in);
362 /* process last block */
363 ret = xmlSecBufferSetMaxSize(out, outSize + 2 * blockLen);
365 xmlSecError(XMLSEC_ERRORS_HERE,
366 xmlSecErrorsSafeString(cipherName),
367 "xmlSecBufferSetMaxSize",
368 XMLSEC_ERRORS_R_XMLSEC_FAILED,
369 "size=%d", outSize + 2 * blockLen);
372 outBuf = xmlSecBufferGetData(out) + outSize;
373 memcpy(outBuf, inBuf, inSize);
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),
383 XMLSEC_ERRORS_R_CRYPTO_FAILED,
384 XMLSEC_ERRORS_NO_MESSAGE);
388 if (!CryptDecrypt(ctx->cryptKey, 0, FALSE, 0, outBuf, &dwCLen)) {
389 xmlSecError(XMLSEC_ERRORS_HERE,
390 xmlSecErrorsSafeString(cipherName),
392 XMLSEC_ERRORS_R_CRYPTO_FAILED,
393 XMLSEC_ERRORS_NO_MESSAGE);
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),
403 XMLSEC_ERRORS_R_XMLSEC_FAILED,
410 if(inSize < outBuf[blockLen - 1]) {
411 xmlSecError(XMLSEC_ERRORS_HERE,
412 xmlSecErrorsSafeString(cipherName),
414 XMLSEC_ERRORS_R_INVALID_DATA,
415 "padding=%d;buffer=%d",
416 outBuf[blockLen - 1], inSize);
419 outLen = inSize - outBuf[blockLen - 1];
424 /* set correct output buffer size */
425 ret = xmlSecBufferSetSize(out, outSize + outLen);
427 xmlSecError(XMLSEC_ERRORS_HERE,
428 xmlSecErrorsSafeString(cipherName),
429 "xmlSecBufferSetSize",
430 XMLSEC_ERRORS_R_XMLSEC_FAILED,
431 "size=%d", outSize + outLen);
435 /* remove the processed block from input */
436 ret = xmlSecBufferRemoveHead(in, inSize);
438 xmlSecError(XMLSEC_ERRORS_HERE,
439 xmlSecErrorsSafeString(cipherName),
440 "xmlSecBufferRemoveHead",
441 XMLSEC_ERRORS_R_XMLSEC_FAILED,
449 /******************************************************************************
451 * Block Cipher transforms
453 * xmlSecMSCryptoBlockCipherCtx block is located after xmlSecTransform structure
455 *****************************************************************************/
456 #define xmlSecMSCryptoBlockCipherSize \
457 (sizeof(xmlSecTransform) + sizeof(xmlSecMSCryptoBlockCipherCtx))
458 #define xmlSecMSCryptoBlockCipherGetCtx(transform) \
459 ((xmlSecMSCryptoBlockCipherCtxPtr)(((unsigned char*)(transform)) + sizeof(xmlSecTransform)))
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,
467 static int xmlSecMSCryptoBlockCipherExecute (xmlSecTransformPtr transform,
469 xmlSecTransformCtxPtr transformCtx);
470 static int xmlSecMSCryptoBlockCipherCheckId (xmlSecTransformPtr transform);
473 xmlSecMSCryptoBlockCipherCheckId(xmlSecTransformPtr transform) {
474 #ifndef XMLSEC_NO_DES
475 if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformDes3CbcId)) {
478 #endif /* XMLSEC_NO_DES */
480 #ifndef XMLSEC_NO_AES
481 if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformAes128CbcId) ||
482 xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformAes192CbcId) ||
483 xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformAes256CbcId)) {
487 #endif /* XMLSEC_NO_AES */
493 xmlSecMSCryptoBlockCipherInitialize(xmlSecTransformPtr transform) {
494 xmlSecMSCryptoBlockCipherCtxPtr ctx;
496 xmlSecAssert2(xmlSecMSCryptoBlockCipherCheckId(transform), -1);
497 xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoBlockCipherSize), -1);
499 ctx = xmlSecMSCryptoBlockCipherGetCtx(transform);
500 xmlSecAssert2(ctx != NULL, -1);
502 memset(ctx, 0, sizeof(xmlSecMSCryptoBlockCipherCtx));
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;
512 #endif /* XMLSEC_NO_DES */
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;
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;
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;
534 #endif /* XMLSEC_NO_AES */
537 xmlSecError(XMLSEC_ERRORS_HERE,
538 xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
540 XMLSEC_ERRORS_R_INVALID_TRANSFORM,
541 XMLSEC_ERRORS_NO_MESSAGE);
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);
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)
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);
576 xmlSecError(XMLSEC_ERRORS_HERE,
577 xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
578 "CryptAcquireContext",
579 XMLSEC_ERRORS_R_CRYPTO_FAILED,
580 XMLSEC_ERRORS_NO_MESSAGE);
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);
596 ctx->ctxInitialized = 0;
601 xmlSecMSCryptoBlockCipherFinalize(xmlSecTransformPtr transform) {
602 xmlSecMSCryptoBlockCipherCtxPtr ctx;
604 xmlSecAssert(xmlSecMSCryptoBlockCipherCheckId(transform));
605 xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecMSCryptoBlockCipherSize));
607 ctx = xmlSecMSCryptoBlockCipherGetCtx(transform);
608 xmlSecAssert(ctx != NULL);
611 CryptDestroyKey(ctx->cryptKey);
613 if (ctx->pubPrivKey) {
614 CryptDestroyKey(ctx->pubPrivKey);
616 if (ctx->cryptProvider) {
617 CryptReleaseContext(ctx->cryptProvider, 0);
618 CryptAcquireContext(&ctx->cryptProvider, "xmlSecMSCryptoTempContainer",
619 MS_ENHANCED_PROV, ctx->providerType, CRYPT_DELETEKEYSET);
622 memset(ctx, 0, sizeof(xmlSecMSCryptoBlockCipherCtx));
626 xmlSecMSCryptoBlockCipherSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) {
627 xmlSecMSCryptoBlockCipherCtxPtr ctx;
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);
634 ctx = xmlSecMSCryptoBlockCipherGetCtx(transform);
635 xmlSecAssert2(ctx != NULL, -1);
636 xmlSecAssert2(ctx->cryptProvider != 0, -1);
638 keyReq->keyId = ctx->keyId;
639 keyReq->keyType = xmlSecKeyDataTypeSymmetric;
640 if(transform->operation == xmlSecTransformOperationEncrypt) {
641 keyReq->keyUsage = xmlSecKeyUsageEncrypt;
643 keyReq->keyUsage = xmlSecKeyUsageDecrypt;
646 keyReq->keyBitsSize = 8 * ctx->keySize;
651 xmlSecMSCryptoBlockCipherSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) {
652 xmlSecMSCryptoBlockCipherCtxPtr ctx;
653 xmlSecBufferPtr buffer;
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);
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);
667 xmlSecAssert2(ctx->keySize > 0, -1);
669 buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key));
670 xmlSecAssert2(buffer != NULL, -1);
672 if(xmlSecBufferGetSize(buffer) < ctx->keySize) {
673 xmlSecError(XMLSEC_ERRORS_HERE,
674 xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
676 XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE,
677 "keySize=%d;expected=%d",
678 xmlSecBufferGetSize(buffer), ctx->keySize);
682 bufData = xmlSecBufferGetData(buffer);
683 xmlSecAssert2(bufData != NULL, -1);
685 /* Import this key and get an HCRYPTKEY handle */
686 if (!xmlSecMSCryptoImportPlainSessionBlob(ctx->cryptProvider,
688 ctx->algorithmIdentifier,
693 xmlSecError(XMLSEC_ERRORS_HERE,
694 xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
695 "xmlSecMSCryptoImportPlainSessionBlob",
696 XMLSEC_ERRORS_R_XMLSEC_FAILED,
697 XMLSEC_ERRORS_NO_MESSAGE);
701 ctx->keyInitialized = 1;
706 xmlSecMSCryptoBlockCipherExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) {
707 xmlSecMSCryptoBlockCipherCtxPtr ctx;
708 xmlSecBufferPtr in, out;
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);
716 in = &(transform->inBuf);
717 out = &(transform->outBuf);
719 ctx = xmlSecMSCryptoBlockCipherGetCtx(transform);
720 xmlSecAssert2(ctx != NULL, -1);
722 if(transform->status == xmlSecTransformStatusNone) {
723 transform->status = xmlSecTransformStatusWorking;
726 if(transform->status == xmlSecTransformStatusWorking) {
727 if(ctx->ctxInitialized == 0) {
728 ret = xmlSecMSCryptoBlockCipherCtxInit(ctx,
731 (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0,
732 xmlSecTransformGetName(transform),
736 xmlSecError(XMLSEC_ERRORS_HERE,
737 xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
738 "xmlSecMSCryptoBlockCipherCtxInit",
739 XMLSEC_ERRORS_R_XMLSEC_FAILED,
740 XMLSEC_ERRORS_NO_MESSAGE);
744 if((ctx->ctxInitialized == 0) && (last != 0)) {
745 xmlSecError(XMLSEC_ERRORS_HERE,
746 xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
748 XMLSEC_ERRORS_R_INVALID_DATA,
749 "not enough data to initialize transform");
752 if(ctx->ctxInitialized != 0) {
753 ret = xmlSecMSCryptoBlockCipherCtxUpdate(ctx, in, out,
754 (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0,
755 xmlSecTransformGetName(transform), transformCtx);
757 xmlSecError(XMLSEC_ERRORS_HERE,
758 xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
759 "xmlSecMSCryptoBlockCipherCtxUpdate",
760 XMLSEC_ERRORS_R_XMLSEC_FAILED,
761 XMLSEC_ERRORS_NO_MESSAGE);
767 ret = xmlSecMSCryptoBlockCipherCtxFinal(ctx, in, out,
768 (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0,
769 xmlSecTransformGetName(transform), transformCtx);
772 xmlSecError(XMLSEC_ERRORS_HERE,
773 xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
774 "xmlSecMSCryptoBlockCipherCtxFinal",
775 XMLSEC_ERRORS_R_XMLSEC_FAILED,
776 XMLSEC_ERRORS_NO_MESSAGE);
779 transform->status = xmlSecTransformStatusFinished;
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);
788 xmlSecError(XMLSEC_ERRORS_HERE,
789 xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
791 XMLSEC_ERRORS_R_INVALID_STATUS,
792 "status=%d", transform->status);
799 #ifndef XMLSEC_NO_AES
800 /*********************************************************************
802 * AES CBC cipher transforms
804 ********************************************************************/
805 static xmlSecTransformKlass xmlSecMSCryptoAes128CbcKlass = {
806 /* klass/object sizes */
807 sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */
808 xmlSecMSCryptoBlockCipherSize, /* xmlSecSize objSize */
810 xmlSecNameAes128Cbc, /* const xmlChar* name; */
811 xmlSecHrefAes128Cbc, /* const xmlChar* href; */
812 xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */
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; */
828 NULL, /* void* reserved0; */
829 NULL, /* void* reserved1; */
833 * xmlSecMSCryptoTransformAes128CbcGetKlass:
835 * AES 128 CBC encryption transform klass.
837 * Returns: pointer to AES 128 CBC encryption transform.
840 xmlSecMSCryptoTransformAes128CbcGetKlass(void) {
841 return(&xmlSecMSCryptoAes128CbcKlass);
844 static xmlSecTransformKlass xmlSecMSCryptoAes192CbcKlass = {
845 /* klass/object sizes */
846 sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */
847 xmlSecMSCryptoBlockCipherSize, /* xmlSecSize objSize */
849 xmlSecNameAes192Cbc, /* const xmlChar* name; */
850 xmlSecHrefAes192Cbc, /* const xmlChar* href; */
851 xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */
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; */
867 NULL, /* void* reserved0; */
868 NULL, /* void* reserved1; */
872 * xmlSecMSCryptoTransformAes192CbcGetKlass:
874 * AES 192 CBC encryption transform klass.
876 * Returns: pointer to AES 192 CBC encryption transform.
879 xmlSecMSCryptoTransformAes192CbcGetKlass(void) {
880 return(&xmlSecMSCryptoAes192CbcKlass);
883 static xmlSecTransformKlass xmlSecMSCryptoAes256CbcKlass = {
884 /* klass/object sizes */
885 sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */
886 xmlSecMSCryptoBlockCipherSize, /* xmlSecSize objSize */
888 xmlSecNameAes256Cbc, /* const xmlChar* name; */
889 xmlSecHrefAes256Cbc, /* const xmlChar* href; */
890 xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */
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; */
906 NULL, /* void* reserved0; */
907 NULL, /* void* reserved1; */
911 * xmlSecMSCryptoTransformAes256CbcGetKlass:
913 * AES 256 CBC encryption transform klass.
915 * Returns: pointer to AES 256 CBC encryption transform.
918 xmlSecMSCryptoTransformAes256CbcGetKlass(void) {
919 return(&xmlSecMSCryptoAes256CbcKlass);
922 #endif /* XMLSEC_NO_AES */
925 #ifndef XMLSEC_NO_DES
926 static xmlSecTransformKlass xmlSecMSCryptoDes3CbcKlass = {
927 /* klass/object sizes */
928 sizeof(xmlSecTransformKlass), /* size_t klassSize */
929 xmlSecMSCryptoBlockCipherSize, /* size_t objSize */
931 xmlSecNameDes3Cbc, /* const xmlChar* name; */
932 xmlSecHrefDes3Cbc, /* const xmlChar* href; */
933 xmlSecTransformUsageEncryptionMethod,/* xmlSecAlgorithmUsage usage; */
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; */
949 NULL, /* void* reserved0; */
950 NULL, /* void* reserved1; */
954 * xmlSecMSCryptoTransformDes3CbcGetKlass:
956 * Triple DES CBC encryption transform klass.
958 * Returns: pointer to Triple DES encryption transform.
961 xmlSecMSCryptoTransformDes3CbcGetKlass(void) {
962 return(&xmlSecMSCryptoDes3CbcKlass);
964 #endif /* XMLSEC_NO_DES */
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
970 * These functions are based upon MS kb article: 228786
972 * aleksey: also check "Base Provider Key BLOBs" article for priv key blob format
975 xmlSecMSCryptoCreatePrivateExponentOneKey(HCRYPTPROV hProv, HCRYPTKEY *hPrivateKey)
978 LPBYTE keyBlob = NULL;
980 PUBLICKEYSTRUC* pubKeyStruc;
981 RSAPUBKEY* rsaPubKey;
987 xmlSecAssert2(hProv != 0, FALSE);
988 xmlSecAssert2(hPrivateKey != NULL, FALSE);
993 /* Generate the private key */
994 if(!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey)) {
995 xmlSecError(XMLSEC_ERRORS_HERE,
998 XMLSEC_ERRORS_R_CRYPTO_FAILED,
999 XMLSEC_ERRORS_NO_MESSAGE);
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,
1008 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1009 XMLSEC_ERRORS_NO_MESSAGE);
1013 keyBlob = (LPBYTE)xmlMalloc(sizeof(BYTE) * keyBlobLen);
1014 if(keyBlob == NULL) {
1015 xmlSecError(XMLSEC_ERRORS_HERE,
1018 XMLSEC_ERRORS_R_MALLOC_FAILED,
1019 XMLSEC_ERRORS_NO_MESSAGE);
1023 if(!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, keyBlob, &keyBlobLen)) {
1024 xmlSecError(XMLSEC_ERRORS_HERE,
1027 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1028 XMLSEC_ERRORS_NO_MESSAGE);
1031 CryptDestroyKey(hKey);
1034 /* Get the bit length of the key */
1035 if(keyBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)) {
1036 xmlSecError(XMLSEC_ERRORS_HERE,
1039 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1040 "len=%ld", keyBlobLen);
1043 pubKeyStruc = (PUBLICKEYSTRUC*)keyBlob;
1044 if(pubKeyStruc->bVersion != 0x02) {
1045 xmlSecError(XMLSEC_ERRORS_HERE,
1048 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1049 "pubKeyStruc->bVersion=%d", pubKeyStruc->bVersion);
1052 if(pubKeyStruc->bType != PRIVATEKEYBLOB) {
1053 xmlSecError(XMLSEC_ERRORS_HERE,
1056 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1057 "pubKeyStruc->bType=%d", (int)pubKeyStruc->bType);
1061 /* aleksey: don't ask me why it is RSAPUBKEY, just don't ask */
1062 rsaPubKey = (RSAPUBKEY*)(keyBlob + sizeof(PUBLICKEYSTRUC));
1064 /* check that we have RSA private key */
1065 if(rsaPubKey->magic != 0x32415352) {
1066 xmlSecError(XMLSEC_ERRORS_HERE,
1069 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1070 "rsaPubKey->magic=0x%08lx", rsaPubKey->magic);
1073 bitLen = rsaPubKey->bitlen;
1075 /* Modify the Exponent in Key BLOB format Key BLOB format is documented in SDK */
1076 rsaPubKey->pubexp = 1;
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:
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
1091 if(keyBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + bitLen / 2 + bitLen / 16) {
1092 xmlSecError(XMLSEC_ERRORS_HERE,
1095 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1096 "len=%ld", keyBlobLen);
1099 ptr = (BYTE*)(keyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY));
1101 /* Skip modulus, prime1, prime2 */
1106 /* Convert exponent1 to 1 */
1107 for (n = 0; n < (bitLen / 16); n++) {
1108 if (n == 0) ptr[n] = 1;
1113 /* Convert exponent2 to 1 */
1114 for (n = 0; n < (bitLen / 16); n++) {
1115 if (n == 0) ptr[n] = 1;
1120 /* Skip coefficient */
1123 /* Convert privateExponent to 1 */
1124 for (n = 0; n < (bitLen / 16); n++) {
1125 if (n == 0) ptr[n] = 1;
1129 /* Import the exponent-of-one private key. */
1130 if (!CryptImportKey(hProv, keyBlob, keyBlobLen, 0, 0, &hKey)) {
1131 xmlSecError(XMLSEC_ERRORS_HERE,
1134 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1135 XMLSEC_ERRORS_NO_MESSAGE);
1138 (*hPrivateKey) = hKey;
1143 if(keyBlob != NULL) {
1147 CryptDestroyKey(hKey);
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;
1162 DWORD dwPublicKeySize;
1163 DWORD dwProvSessionKeySize;
1166 PROV_ENUMALGS_EX ProvEnum;
1167 HCRYPTKEY hTempKey = 0;
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);
1177 /* Double check to see if this provider supports this algorithm and key size */
1179 dwFlags = CRYPT_FIRST;
1180 dwSize = sizeof(ProvEnum);
1181 while(CryptGetProvParam(hProv, PP_ENUMALGS_EX, (LPBYTE)&ProvEnum, &dwSize, dwFlags)) {
1182 if (ProvEnum.aiAlgid == dwAlgId) {
1186 dwSize = sizeof(ProvEnum);
1190 xmlSecError(XMLSEC_ERRORS_HERE,
1192 "CryptGetProvParam",
1193 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1194 "algId=%d is not supported", dwAlgId);
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.
1201 if(!CryptGenKey(hProv, dwAlgId, 0, &hTempKey)) {
1202 xmlSecError(XMLSEC_ERRORS_HERE,
1205 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1206 "algId=%d", dwAlgId);
1210 dwSize = sizeof(DWORD);
1211 if(!CryptGetKeyParam(hTempKey, KP_KEYLEN, (LPBYTE)&dwProvSessionKeySize, &dwSize, 0)) {
1212 xmlSecError(XMLSEC_ERRORS_HERE,
1214 "CryptGetKeyParam(KP_KEYLEN)",
1215 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1216 "algId=%d", dwAlgId);
1219 CryptDestroyKey(hTempKey);
1222 /* Our key is too big, leave */
1223 if ((dwKeyMaterial * 8) > dwProvSessionKeySize) {
1224 xmlSecError(XMLSEC_ERRORS_HERE,
1227 XMLSEC_ERRORS_R_INVALID_SIZE,
1228 "dwKeyMaterial=%ld;dwProvSessionKeySize=%ld",
1229 dwKeyMaterial, dwProvSessionKeySize);
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,
1238 "CryptGetKeyParam(KP_ALGID)",
1239 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1240 "algId=%d", dwAlgId);
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,
1249 "CryptGetKeyParam(KP_KEYLEN)",
1250 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1251 "algId=%d", dwAlgId);
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,
1260 XMLSEC_ERRORS_R_INVALID_SIZE,
1261 "dwKeyMaterial=%ld;dwPublicKeySize=%ld",
1262 dwKeyMaterial, dwPublicKeySize);
1265 rndBlobSize = dwPublicKeySize / 8 - (dwKeyMaterial + 3);
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:
1271 * PUBLICKEYSTRUC publickeystruc ;
1273 * BYTE encryptedkey[rsapubkey.bitlen/8];
1276 /* calculate Simple blob's length */
1277 keyBlobLen = sizeof(PUBLICKEYSTRUC) + sizeof(ALG_ID) + (dwPublicKeySize / 8);
1279 /* allocate simple blob buffer */
1280 keyBlob = (LPBYTE)xmlMalloc(sizeof(BYTE) * keyBlobLen);
1281 if(keyBlob == NULL) {
1282 xmlSecError(XMLSEC_ERRORS_HERE,
1285 XMLSEC_ERRORS_R_MALLOC_FAILED,
1286 XMLSEC_ERRORS_NO_MESSAGE);
1289 memset(keyBlob, 0, keyBlobLen);
1291 /* initialize PUBLICKEYSTRUC */
1292 pubKeyStruc = (PUBLICKEYSTRUC*)(keyBlob);
1293 pubKeyStruc->bType = SIMPLEBLOB;
1294 pubKeyStruc->bVersion = 0x02;
1295 pubKeyStruc->reserved = 0;
1296 pubKeyStruc->aiKeyAlg = dwAlgId;
1298 /* Copy private key algorithm to buffer */
1299 algId = (ALG_ID*)(keyBlob + sizeof(PUBLICKEYSTRUC));
1300 (*algId) = dwPrivKeyAlg;
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];
1307 pbPtr += dwKeyMaterial;
1309 /* skip reserved byte */
1312 /* Generate random data for the rest of the buffer */
1313 if((rndBlobSize > 0) && !CryptGenRandom(hProv, rndBlobSize, pbPtr)) {
1314 xmlSecError(XMLSEC_ERRORS_HERE,
1317 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1318 "rndBlobSize=%ld", rndBlobSize);
1321 /* aleksey: why are we doing this? */
1322 for (n = 0; n < rndBlobSize; n++) {
1323 if (pbPtr[n] == 0) pbPtr[n] = 1;
1326 /* set magic number at the end */
1327 keyBlob[keyBlobLen - 2] = 2;
1329 if(!CryptImportKey(hProv, keyBlob , keyBlobLen, hPrivateKey, CRYPT_EXPORTABLE, hSessionKey)) {
1330 xmlSecError(XMLSEC_ERRORS_HERE,
1333 XMLSEC_ERRORS_R_CRYPTO_FAILED,
1334 "algId=%d", dwAlgId);
1343 CryptDestroyKey(hTempKey);
1345 if(keyBlob != NULL) {