[xmlsec] adding support for HMAC with MD5, SHA1, SHA256/384/512 and MD5, RSA with MD5 in xmlsec-mscrypto



commit a9fc9ecd394d254f4c7e8ce269d7b88ba9a8daae
Author: Aleksey Sanin <aleksey aleksey com>
Date:   Mon Apr 26 14:43:06 2010 -0700

    adding support for HMAC with MD5, SHA1, SHA256/384/512 and MD5, RSA with MD5 in xmlsec-mscrypto

 ChangeLog                           |    4 +
 TODO                                |   45 ++++-
 docs/xmldsig.html                   |   15 +-
 include/xmlsec/mscrypto/crypto.h    |  119 +++++++++-
 include/xmlsec/mscrypto/keysstore.h |   12 +
 src/mscrypto/Makefile.am            |    1 +
 src/mscrypto/README                 |    5 -
 src/mscrypto/ciphers.c              |  395 +-----------------------------
 src/mscrypto/crypto.c               |   65 ++++-
 src/mscrypto/digests.c              |   71 ++++++-
 src/mscrypto/signatures.c           |  133 +++++++++--
 src/mscrypto/symkeys.c              |  463 ++++++++++++++++++++++++++++++++++-
 win32/Makefile.msvc                 |    2 +
 13 files changed, 883 insertions(+), 447 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 2739f89..b76e1ab 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2010-04-26  Aleksey Sanin  <aleksey aleksey com>
+	* Added support for HMAC with MD5, SHA1, SHA256/384/512 in xmlsec-mscrypto
+	* Added support for MD5 RSA/MD5 in xmlsec-mscrypto
+
 2010-04-25  Aleksey Sanin  <aleksey aleksey com>
 	* Added support for SHA256/384/512 for digest, HMAC and RSA in xmlsec-nss
 	(requires nss 3.8 + nspr 4.3 or greater)
diff --git a/TODO b/TODO
index 0fd14ac..53a5485 100644
--- a/TODO
+++ b/TODO
@@ -32,6 +32,49 @@ merlin-xmlenc-five/encrypt-data-tripledes-cbc-rsa-oaep-mgf1p
 
 merlin-xmldsig-twenty-three/signature-x509-crt-crl
 
-* xmlsec-mscrypto (April 25, 2010)
+* xmlsec-mscrypto (April 26, 2010)
 
 
+** Skipped tests due to missing transforms: RIPEMD160, SHA224, RSA/OAEP, 
+AES and DES KW
+
+aleksey-xmldsig-01/enveloping-ripemd160-hmac-ripemd160
+aleksey-xmldsig-01/enveloping-ripemd160-hmac-ripemd160-64
+aleksey-xmldsig-01/enveloping-sha224-hmac-sha224
+aleksey-xmldsig-01/enveloping-sha224-hmac-sha224-64
+aleksey-xmldsig-01/enveloping-ripemd160-rsa-ripemd160
+aleksey-xmldsig-01/enveloping-sha224-rsa-sha224
+
+merlin-xmlenc-five/encsig-ripemd160-hmac-ripemd160-kw-tripledes
+merlin-xmlenc-five/encsig-sha256-hmac-sha256-kw-aes128
+merlin-xmlenc-five/encsig-sha384-hmac-sha384-kw-aes192
+merlin-xmlenc-five/encsig-sha512-hmac-sha512-kw-aes256
+aleksey-xmlenc-01/enc-des3cbc-aes192-keyname
+merlin-xmlenc-five/encrypt-data-tripledes-cbc-rsa-oaep-mgf1p
+merlin-xmlenc-five/encrypt-data-aes256-cbc-kw-tripledes
+merlin-xmlenc-five/encrypt-content-aes128-cbc-kw-aes192
+merlin-xmlenc-five/encrypt-data-aes192-cbc-kw-aes256
+merlin-xmlenc-five/encrypt-element-tripledes-cbc-kw-aes128
+merlin-xmlenc-five/encrypt-element-aes256-cbc-retrieved-kw-aes256
+01-phaos-xmlenc-3/enc-element-3des-kt-rsa_oaep_sha1
+01-phaos-xmlenc-3/enc-element-aes128-kt-rsa_oaep_sha1
+01-phaos-xmlenc-3/enc-element-aes192-kt-rsa_oaep_sha1
+01-phaos-xmlenc-3/enc-element-3des-kt-rsa_oaep_sha1
+01-phaos-xmlenc-3/enc-element-aes128-kt-rsa_oaep_sha1
+01-phaos-xmlenc-3/enc-element-aes192-kt-rsa_oaep_sha1
+01-phaos-xmlenc-3/enc-text-aes256-kt-rsa_oaep_sha1
+01-phaos-xmlenc-3/enc-element-3des-kw-3des
+01-phaos-xmlenc-3/enc-content-aes128-kw-3des
+01-phaos-xmlenc-3/enc-element-aes128-kw-aes128
+01-phaos-xmlenc-3/enc-element-aes128-kw-aes256
+01-phaos-xmlenc-3/enc-content-3des-kw-aes192
+01-phaos-xmlenc-3/enc-content-aes192-kw-aes256
+01-phaos-xmlenc-3/enc-element-aes192-kw-aes192
+01-phaos-xmlenc-3/enc-element-aes256-kw-aes256
+01-phaos-xmlenc-3/enc-text-3des-kw-aes256
+01-phaos-xmlenc-3/enc-text-aes128-kw-aes192
+
+** Failed tests due to no GOST crypto providers on test machine
+
+aleksey-xmldsig-01/enveloped-gost
+
diff --git a/docs/xmldsig.html b/docs/xmldsig.html
index b70a00f..a00f2b5 100644
--- a/docs/xmldsig.html
+++ b/docs/xmldsig.html
@@ -423,7 +423,7 @@ MSCrypto</b> </td>
 </td>
                   <td style="vertical-align: top;">N<br>
 </td>
-                  <td style="vertical-align: top;">N<br>
+                  <td style="vertical-align: top;">Y<br>
 </td>
                 </tr>
 <tr>
@@ -483,7 +483,7 @@ MSCrypto</b> </td>
 </td>
                   <td style="vertical-align: top;">Y<br>
 </td>
-                  <td style="vertical-align: top;">N<br>
+                  <td style="vertical-align: top;">Y<br>
 </td>
                 </tr>
 <tr>
@@ -506,7 +506,7 @@ MSCrypto</b> </td>
 </td>
                   <td style="vertical-align: top;">N<br>
 </td>
-                  <td style="vertical-align: top;">N<br>
+                  <td style="vertical-align: top;">Y<br>
 </td>
                 </tr>
 <tr>
@@ -517,7 +517,7 @@ MSCrypto</b> </td>
 </td>
                   <td style="vertical-align: top;">N<br>
 </td>
-                  <td style="vertical-align: top;">N<br>
+                  <td style="vertical-align: top;">Y<br>
 </td>
                 </tr>
 <tr>
@@ -528,7 +528,7 @@ MSCrypto</b> </td>
 </td>
                   <td style="vertical-align: top;">N<br>
 </td>
-                  <td style="vertical-align: top;">N<br>
+                  <td style="vertical-align: top;">Y<br>
 </td>
                 </tr>
 <tr>
@@ -552,7 +552,7 @@ MSCrypto</b> </td>
 </td>
                   <td style="vertical-align: top;">N<br>
 </td>
-                  <td style="vertical-align: top;">N<br>
+                  <td style="vertical-align: top;">Y<br>
 </td>
                 </tr>
 <tr>
@@ -728,8 +728,7 @@ MSCrypto</b> </td>
 </td>
                 </tr>
 <tr>
-<td style="vertical-align: top; width: 40%;">Minimal
-C14N (deprecated) </td>
+<td style="vertical-align: top; width: 40%;">Minimal C14N (deprecated) </td>
                   <td style="vertical-align: top;">N<br>
 </td>
                   <td style="vertical-align: top;">N<br>
diff --git a/include/xmlsec/mscrypto/crypto.h b/include/xmlsec/mscrypto/crypto.h
index 0d69935..cf6c17b 100644
--- a/include/xmlsec/mscrypto/crypto.h
+++ b/include/xmlsec/mscrypto/crypto.h
@@ -151,46 +151,60 @@ XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformGost2001GostR3411_
         xmlSecMSCryptoKeyDataRsaGetKlass()
 XMLSEC_CRYPTO_EXPORT xmlSecKeyDataId xmlSecMSCryptoKeyDataRsaGetKlass(void);
 
+#ifndef XMLSEC_NO_MD5
+/**
+ * xmlSecMSCryptoTransformRsaMd5Id:
+ *
+ * The RSA-MD5 signature transform klass.
+ */
+#define xmlSecMSCryptoTransformRsaMd5Id        \
+        xmlSecMSCryptoTransformRsaMd5GetKlass()
+XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformRsaMd5GetKlass(void);
+#endif /* XMLSEC_NO_MD5 */
 
+#ifndef XMLSEC_NO_SHA1
 /**
  * xmlSecMSCryptoTransformRsaSha1Id:
  *
  * The RSA-SHA1 signature transform klass.
  */
-
 #define xmlSecMSCryptoTransformRsaSha1Id        \
         xmlSecMSCryptoTransformRsaSha1GetKlass()
 XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformRsaSha1GetKlass(void);
+#endif /* XMLSEC_NO_SHA1 */
 
+#ifndef XMLSEC_NO_SHA256
 /**
  * xmlSecMSCryptoTransformRsaSha256Id:
  *
  * The RSA-SHA256 signature transform klass.
  */
-
 #define xmlSecMSCryptoTransformRsaSha256Id     \
        xmlSecMSCryptoTransformRsaSha256GetKlass()
 XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformRsaSha256GetKlass(void);
+#endif /* XMLSEC_NO_SHA256 */
 
+#ifndef XMLSEC_NO_SHA384
 /**
  * xmlSecMSCryptoTransformRsaSha384Id:
  *
  * The RSA-SHA384 signature transform klass.
  */
-
 #define xmlSecMSCryptoTransformRsaSha384Id     \
        xmlSecMSCryptoTransformRsaSha384GetKlass()
 XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformRsaSha384GetKlass(void);
+#endif /* XMLSEC_NO_SHA384 */
 
+#ifndef XMLSEC_NO_SHA512
 /**
  * xmlSecMSCryptoTransformRsaSha512Id:
  *
  * The RSA-SHA512 signature transform klass.
  */
-
 #define xmlSecMSCryptoTransformRsaSha512Id     \
        xmlSecMSCryptoTransformRsaSha512GetKlass()
 XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformRsaSha512GetKlass(void);
+#endif /* XMLSEC_NO_SHA512 */
 
 /**
  * xmlSecMSCryptoTransformRsaPkcs1Id:
@@ -213,6 +227,23 @@ XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformRsaOaepGetKlass(vo
 */
 #endif /* XMLSEC_NO_RSA */
 
+/********************************************************************
+ *
+ * Md5 transforms
+ *
+ *******************************************************************/
+#ifndef XMLSEC_NO_MD5
+/**
+ * xmlSecMSCryptoTransformMd5Id:
+ *
+ * The MD5 digest transform klass.
+ */
+#define xmlSecMSCryptoTransformMd5Id \
+        xmlSecMSCryptoTransformMd5GetKlass()
+XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformMd5GetKlass(void);
+#endif /* XMLSEC_NO_MD5 */
+
+
 /********************************************************************
  *
  * SHA1 transform
@@ -370,9 +401,87 @@ XMLSEC_CRYPTO_EXPORT xmlSecKeyDataId    xmlSecMSCryptoKeyDataDesGetKlass(void);
         xmlSecMSCryptoTransformDes3CbcGetKlass()
 XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformDes3CbcGetKlass(void);
 
+#endif /* XMLSEC_NO_DES */
 
 
-#endif /* XMLSEC_NO_DES */
+/********************************************************************
+ *
+ * HMAC transforms
+ *
+ *******************************************************************/
+#ifndef XMLSEC_NO_HMAC
+
+XMLSEC_CRYPTO_EXPORT int               xmlSecMSCryptoHmacGetMinOutputLength(void);
+XMLSEC_CRYPTO_EXPORT void              xmlSecMSCryptoHmacSetMinOutputLength(int min_length);
+
+/**
+ * xmlSecMSCryptoKeyDataHmacId:
+ *
+ * The DHMAC key klass.
+ */
+#define xmlSecMSCryptoKeyDataHmacId \
+        xmlSecMSCryptoKeyDataHmacGetKlass()
+XMLSEC_CRYPTO_EXPORT xmlSecKeyDataId    xmlSecMSCryptoKeyDataHmacGetKlass(void);
+XMLSEC_CRYPTO_EXPORT int                xmlSecMSCryptoKeyDataHmacSet     (xmlSecKeyDataPtr data,
+                                                                         const xmlSecByte* buf,
+                                                                         xmlSecSize bufSize);
+
+#ifndef XMLSEC_NO_MD5
+/**
+ * xmlSecMSCryptoTransformHmacMd5Id:
+ *
+ * The HMAC with MD5 signature transform klass.
+ */
+#define xmlSecMSCryptoTransformHmacMd5Id \
+        xmlSecMSCryptoTransformHmacMd5GetKlass()
+XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformHmacMd5GetKlass(void);
+#endif /* XMLSEC_NO_MD5 */
+
+#ifndef XMLSEC_NO_SHA1
+/**
+ * xmlSecMSCryptoTransformHmacSha1Id:
+ *
+ * The HMAC with SHA1 signature transform klass.
+ */
+#define xmlSecMSCryptoTransformHmacSha1Id \
+        xmlSecMSCryptoTransformHmacSha1GetKlass()
+XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformHmacSha1GetKlass(void);
+#endif /* XMLSEC_NO_SHA1 */
+
+#ifndef XMLSEC_NO_SHA256
+/**
+ * xmlSecMSCryptoTransformHmacSha256Id:
+ *
+ * The HMAC with SHA256 signature transform klass.
+ */
+#define xmlSecMSCryptoTransformHmacSha256Id \
+        xmlSecMSCryptoTransformHmacSha256GetKlass()
+XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformHmacSha256GetKlass(void);
+#endif /* XMLSEC_NO_SHA256 */
+
+#ifndef XMLSEC_NO_SHA384
+/**
+ * xmlSecMSCryptoTransformHmacSha384Id:
+ *
+ * The HMAC with SHA384 signature transform klass.
+ */
+#define xmlSecMSCryptoTransformHmacSha384Id \
+        xmlSecMSCryptoTransformHmacSha384GetKlass()
+XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformHmacSha384GetKlass(void);
+#endif /* XMLSEC_NO_SHA384 */
+
+#ifndef XMLSEC_NO_SHA512
+/**
+ * xmlSecMSCryptoTransformHmacSha512Id:
+ *
+ * The HMAC with SHA512 signature transform klass.
+ */
+#define xmlSecMSCryptoTransformHmacSha512Id \
+        xmlSecMSCryptoTransformHmacSha512GetKlass()
+XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecMSCryptoTransformHmacSha512GetKlass(void);
+#endif /* XMLSEC_NO_SHA512 */
+
+#endif /* XMLSEC_NO_HMAC */
 
 #ifdef __cplusplus
 }
diff --git a/include/xmlsec/mscrypto/keysstore.h b/include/xmlsec/mscrypto/keysstore.h
index bd38547..867a6f7 100644
--- a/include/xmlsec/mscrypto/keysstore.h
+++ b/include/xmlsec/mscrypto/keysstore.h
@@ -38,6 +38,18 @@ XMLSEC_CRYPTO_EXPORT int                xmlSecMSCryptoKeysStoreSave     (xmlSecK
                                                                          const char *filename,
                                                                          xmlSecKeyDataType type);
 
+
+/* keys */
+XMLSEC_CRYPTO_EXPORT BOOL               xmlSecMSCryptoCreatePrivateExponentOneKey   (HCRYPTPROV hProv,
+                                                                         HCRYPTKEY *hPrivateKey);
+
+XMLSEC_CRYPTO_EXPORT BOOL               xmlSecMSCryptoImportPlainSessionBlob (HCRYPTPROV hProv,
+                                                                         HCRYPTKEY hPrivateKey,
+                                                                         ALG_ID dwAlgId,
+                                                                         LPBYTE pbKeyMaterial,
+                                                                         DWORD dwKeyMaterial,
+                                                                         HCRYPTKEY *hSessionKey);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/src/mscrypto/Makefile.am b/src/mscrypto/Makefile.am
index 318af51..b471bb6 100644
--- a/src/mscrypto/Makefile.am
+++ b/src/mscrypto/Makefile.am
@@ -25,6 +25,7 @@ libxmlsec1_mscrypto_la_SOURCES =\
 	ciphers.c \
 	crypto.c \
 	digests.c \
+	hmac.c \
 	keysstore.c \
 	kt_rsa.c \
 	signatures.c \
diff --git a/src/mscrypto/README b/src/mscrypto/README
index e7b8d63..3086024 100644
--- a/src/mscrypto/README
+++ b/src/mscrypto/README
@@ -34,11 +34,6 @@ KNOWN ISSUES.
 (http://bugzilla.gnome.org/show_bug.cgi?id=123668).
 
 2) Missing crypto functionality:
-  - HMAC (http://bugzilla.gnome.org/show_bug.cgi?id=123670): does not look
-  like MS would support it soon.
-
-  See - http://msdn.microsoft.com/en-us/library/Aa379863
-
   - RSA-OAEP (http://bugzilla.gnome.org/show_bug.cgi?id=123671): MS says
   that they will support this in the near future.
   - AES KW (http://bugzilla.gnome.org/show_bug.cgi?id=123672): no native
diff --git a/src/mscrypto/ciphers.c b/src/mscrypto/ciphers.c
index b4601aa..aa34452 100644
--- a/src/mscrypto/ciphers.c
+++ b/src/mscrypto/ciphers.c
@@ -26,14 +26,6 @@
 #endif
 
 
-static BOOL xmlSecMSCryptoCreatePrivateExponentOneKey   (HCRYPTPROV hProv,
-                                                         HCRYPTKEY *hPrivateKey);
-static BOOL xmlSecMSCryptoImportPlainSessionBlob        (HCRYPTPROV hProv,
-                                                         HCRYPTKEY hPrivateKey,
-                                                         ALG_ID dwAlgId,
-                                                         LPBYTE pbKeyMaterial,
-                                                         DWORD dwKeyMaterial,
-                                                         HCRYPTKEY *hSessionKey);
 
 /**************************************************************************
  *
@@ -645,9 +637,9 @@ xmlSecMSCryptoBlockCipherSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key)
     ctx = xmlSecMSCryptoBlockCipherGetCtx(transform);
     xmlSecAssert2(ctx != NULL, -1);
     xmlSecAssert2(ctx->keyInitialized == 0, -1);
+    xmlSecAssert2(ctx->pubPrivKey != 0, -1);
     xmlSecAssert2(ctx->keyId != NULL, -1);
     xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1);
-
     xmlSecAssert2(ctx->keySize > 0, -1);
 
     buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key));
@@ -947,388 +939,3 @@ xmlSecMSCryptoTransformDes3CbcGetKlass(void) {
 }
 #endif /* XMLSEC_NO_DES */
 
-/*
- * Low level helper routines for importing plain text keys in MS HKEY handle,
- * since MSCrypto API does not support import of plain text (session) keys
- * just like that.
- * These functions are based upon MS kb article: 228786
- *
- * aleksey: also check "Base Provider Key BLOBs" article for priv key blob format
- **/
-static BOOL
-xmlSecMSCryptoCreatePrivateExponentOneKey(HCRYPTPROV hProv, HCRYPTKEY *hPrivateKey)
-{
-    HCRYPTKEY hKey = 0;
-    LPBYTE keyBlob = NULL;
-    DWORD keyBlobLen;
-    PUBLICKEYSTRUC* pubKeyStruc;
-    RSAPUBKEY* rsaPubKey;
-    DWORD bitLen;
-    BYTE *ptr;
-    int n;
-    BOOL res = FALSE;
-
-    xmlSecAssert2(hProv != 0, FALSE);
-    xmlSecAssert2(hPrivateKey != NULL, FALSE);
-
-    /* just in case */
-    *hPrivateKey = 0;
-
-    /* Generate the private key */
-    if(!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey)) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptGenKey",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    XMLSEC_ERRORS_NO_MESSAGE);
-        goto done;
-    }
-
-    /* Export the private key, we'll convert it to a private exponent of one key */
-    if(!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, NULL, &keyBlobLen)) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptExportKey",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    XMLSEC_ERRORS_NO_MESSAGE);
-        goto done;
-    }
-
-    keyBlob = (LPBYTE)xmlMalloc(sizeof(BYTE) * keyBlobLen);
-    if(keyBlob == NULL) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    NULL,
-                    XMLSEC_ERRORS_R_MALLOC_FAILED,
-                    XMLSEC_ERRORS_NO_MESSAGE);
-        goto done;
-    }
-
-    if(!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, keyBlob, &keyBlobLen)) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptExportKey",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    XMLSEC_ERRORS_NO_MESSAGE);
-        goto done;
-    }
-    CryptDestroyKey(hKey);
-    hKey = 0;
-
-    /* Get the bit length of the key */
-    if(keyBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptExportKey",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    "len=%ld", keyBlobLen);
-        goto done;
-    }
-    pubKeyStruc = (PUBLICKEYSTRUC*)keyBlob;
-    if(pubKeyStruc->bVersion != 0x02) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptExportKey",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    "pubKeyStruc->bVersion=%d", pubKeyStruc->bVersion);
-        goto done;
-    }
-    if(pubKeyStruc->bType != PRIVATEKEYBLOB) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptExportKey",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    "pubKeyStruc->bType=%d", (int)pubKeyStruc->bType);
-        goto done;
-    }
-
-    /* aleksey: don't ask me why it is RSAPUBKEY, just don't ask */
-    rsaPubKey = (RSAPUBKEY*)(keyBlob + sizeof(PUBLICKEYSTRUC));
-
-    /* check that we have RSA private key */
-    if(rsaPubKey->magic != 0x32415352) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptExportKey",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    "rsaPubKey->magic=0x%08lx", rsaPubKey->magic);
-        goto done;
-    }
-    bitLen = rsaPubKey->bitlen;
-
-    /*  Modify the Exponent in Key BLOB format Key BLOB format is documented in SDK */
-    rsaPubKey->pubexp = 1;
-
-    /* Private-key BLOBs, type PRIVATEKEYBLOB, are used to store private keys outside a CSP.
-     * Base provider private-key BLOBs have the following format:
-     *
-     * PUBLICKEYSTRUC  publickeystruc ;
-     * RSAPUBKEY rsapubkey;
-     * BYTE modulus[rsapubkey.bitlen/8];                1/8
-     * BYTE prime1[rsapubkey.bitlen/16];                1/16
-     * BYTE prime2[rsapubkey.bitlen/16];                1/16
-     * BYTE exponent1[rsapubkey.bitlen/16];             1/16
-     * BYTE exponent2[rsapubkey.bitlen/16];             1/16
-     * BYTE coefficient[rsapubkey.bitlen/16];           1/16
-     * BYTE privateExponent[rsapubkey.bitlen/8];        1/8
-     */
-    if(keyBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + bitLen / 2 + bitLen / 16) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptExportKey",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    "len=%ld", keyBlobLen);
-        goto done;
-    }
-    ptr = (BYTE*)(keyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY));
-
-    /* Skip modulus, prime1, prime2 */
-    ptr += bitLen / 8;
-    ptr += bitLen / 16;
-    ptr += bitLen / 16;
-
-    /* Convert exponent1 to 1 */
-    for (n = 0; n < (bitLen / 16); n++) {
-        if (n == 0) ptr[n] = 1;
-        else ptr[n] = 0;
-    }
-    ptr += bitLen / 16;
-
-    /* Convert exponent2 to 1 */
-    for (n = 0; n < (bitLen / 16); n++) {
-        if (n == 0) ptr[n] = 1;
-        else ptr[n] = 0;
-    }
-    ptr += bitLen / 16;
-
-    /* Skip coefficient */
-    ptr += bitLen / 16;
-
-    /* Convert privateExponent to 1 */
-    for (n = 0; n < (bitLen / 16); n++) {
-        if (n == 0) ptr[n] = 1;
-        else ptr[n] = 0;
-    }
-
-    /* Import the exponent-of-one private key. */
-    if (!CryptImportKey(hProv, keyBlob, keyBlobLen, 0, 0, &hKey)) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptImportKey",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    XMLSEC_ERRORS_NO_MESSAGE);
-        goto done;
-    }
-    (*hPrivateKey) = hKey;
-    hKey = 0;
-    res = TRUE;
-
-done:
-    if(keyBlob != NULL) {
-        xmlFree(keyBlob);
-    }
-    if (hKey != 0) {
-        CryptDestroyKey(hKey);
-    }
-
-    return res;
-}
-
-static BOOL
-xmlSecMSCryptoImportPlainSessionBlob(HCRYPTPROV hProv, HCRYPTKEY hPrivateKey,
-                                     ALG_ID dwAlgId, LPBYTE pbKeyMaterial,
-                                     DWORD dwKeyMaterial, HCRYPTKEY *hSessionKey) {
-    ALG_ID dwPrivKeyAlg;
-    LPBYTE keyBlob = NULL;
-    DWORD keyBlobLen, rndBlobSize, dwSize, n;
-    PUBLICKEYSTRUC* pubKeyStruc;
-    ALG_ID* algId;
-    DWORD dwPublicKeySize;
-    DWORD dwProvSessionKeySize;
-    LPBYTE pbPtr;
-    DWORD dwFlags;
-    PROV_ENUMALGS_EX ProvEnum;
-    HCRYPTKEY hTempKey = 0;
-    BOOL fFound;
-    BOOL res = FALSE;
-
-    xmlSecAssert2(hProv != 0, FALSE);
-    xmlSecAssert2(hPrivateKey != 0, FALSE);
-    xmlSecAssert2(pbKeyMaterial != NULL, FALSE);
-    xmlSecAssert2(dwKeyMaterial > 0, FALSE);
-    xmlSecAssert2(hSessionKey != NULL, FALSE);
-
-    /*  Double check to see if this provider supports this algorithm and key size */
-    fFound = FALSE;
-    dwFlags = CRYPT_FIRST;
-    dwSize = sizeof(ProvEnum);
-    while(CryptGetProvParam(hProv, PP_ENUMALGS_EX, (LPBYTE)&ProvEnum, &dwSize, dwFlags)) {
-        if (ProvEnum.aiAlgid == dwAlgId) {
-            fFound = TRUE;
-            break;
-        }
-        dwSize = sizeof(ProvEnum);
-        dwFlags = 0;
-    }
-    if(!fFound) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptGetProvParam",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    "algId=%d is not supported", dwAlgId);
-        goto done;
-    }
-
-    /* We have to get the key size(including padding) from an HCRYPTKEY handle.
-     * PP_ENUMALGS_EX contains the key size without the padding so we can't use it.
-     */
-    if(!CryptGenKey(hProv, dwAlgId, 0, &hTempKey)) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptGenKey",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    "algId=%d", dwAlgId);
-        goto done;
-    }
-
-    dwSize = sizeof(DWORD);
-    if(!CryptGetKeyParam(hTempKey, KP_KEYLEN, (LPBYTE)&dwProvSessionKeySize, &dwSize, 0)) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptGetKeyParam(KP_KEYLEN)",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    "algId=%d", dwAlgId);
-        goto done;
-    }
-    CryptDestroyKey(hTempKey);
-    hTempKey = 0;
-
-    /* Our key is too big, leave */
-    if ((dwKeyMaterial * 8) > dwProvSessionKeySize) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    NULL,
-                    XMLSEC_ERRORS_R_INVALID_SIZE,
-                    "dwKeyMaterial=%ld;dwProvSessionKeySize=%ld",
-                    dwKeyMaterial, dwProvSessionKeySize);
-        goto done;
-    }
-
-    /* Get private key's algorithm */
-    dwSize = sizeof(ALG_ID);
-    if(!CryptGetKeyParam(hPrivateKey, KP_ALGID, (LPBYTE)&dwPrivKeyAlg, &dwSize, 0)) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptGetKeyParam(KP_ALGID)",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    "algId=%d", dwAlgId);
-        goto done;
-    }
-
-    /* Get private key's length in bits */
-    dwSize = sizeof(DWORD);
-    if(!CryptGetKeyParam(hPrivateKey, KP_KEYLEN, (LPBYTE)&dwPublicKeySize, &dwSize, 0)) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptGetKeyParam(KP_KEYLEN)",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    "algId=%d", dwAlgId);
-        goto done;
-    }
-
-    /* 3 is for the first reserved byte after the key material and the 2 reserved bytes at the end. */
-    if(dwPublicKeySize / 8 < dwKeyMaterial + 3) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    NULL,
-                    XMLSEC_ERRORS_R_INVALID_SIZE,
-                    "dwKeyMaterial=%ld;dwPublicKeySize=%ld",
-                    dwKeyMaterial, dwPublicKeySize);
-        goto done;
-    }
-    rndBlobSize = dwPublicKeySize / 8 - (dwKeyMaterial + 3);
-
-    /* Simple key BLOBs, type SIMPLEBLOB, are used to store and transport session keys outside a CSP.
-     * Base provider simple-key BLOBs are always encrypted with a key exchange public key. The pbData
-     * member of the SIMPLEBLOB is a sequence of bytes in the following format:
-     *
-     * PUBLICKEYSTRUC  publickeystruc ;
-     * ALG_ID algid;
-     * BYTE encryptedkey[rsapubkey.bitlen/8];
-     */
-
-    /* calculate Simple blob's length */
-    keyBlobLen = sizeof(PUBLICKEYSTRUC) + sizeof(ALG_ID) + (dwPublicKeySize / 8);
-
-    /* allocate simple blob buffer */
-    keyBlob = (LPBYTE)xmlMalloc(sizeof(BYTE) * keyBlobLen);
-    if(keyBlob == NULL) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    NULL,
-                    XMLSEC_ERRORS_R_MALLOC_FAILED,
-                    XMLSEC_ERRORS_NO_MESSAGE);
-        goto done;
-    }
-    memset(keyBlob, 0, keyBlobLen);
-
-    /* initialize PUBLICKEYSTRUC */
-    pubKeyStruc             = (PUBLICKEYSTRUC*)(keyBlob);
-    pubKeyStruc->bType      = SIMPLEBLOB;
-    pubKeyStruc->bVersion   = 0x02;
-    pubKeyStruc->reserved   = 0;
-    pubKeyStruc->aiKeyAlg   = dwAlgId;
-
-    /* Copy private key algorithm to buffer */
-    algId                   = (ALG_ID*)(keyBlob + sizeof(PUBLICKEYSTRUC));
-    (*algId)                = dwPrivKeyAlg;
-
-    /* Place the key material in reverse order */
-    pbPtr                   = (BYTE*)(keyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(ALG_ID));
-    for (n = 0; n < dwKeyMaterial; n++) {
-        pbPtr[n] = pbKeyMaterial[dwKeyMaterial - n - 1];
-    }
-    pbPtr += dwKeyMaterial;
-
-    /* skip reserved byte */
-    pbPtr += 1;
-
-    /* Generate random data for the rest of the buffer */
-    if((rndBlobSize > 0) && !CryptGenRandom(hProv, rndBlobSize, pbPtr)) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptGenRandom",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    "rndBlobSize=%ld", rndBlobSize);
-        goto done;
-    }
-    /* aleksey: why are we doing this? */
-    for (n = 0; n < rndBlobSize; n++) {
-        if (pbPtr[n] == 0) pbPtr[n] = 1;
-    }
-
-    /* set magic number at the end */
-    keyBlob[keyBlobLen - 2] = 2;
-
-    if(!CryptImportKey(hProv, keyBlob , keyBlobLen, hPrivateKey, CRYPT_EXPORTABLE, hSessionKey)) {
-        xmlSecError(XMLSEC_ERRORS_HERE,
-                    NULL,
-                    "CryptImportKey",
-                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
-                    "algId=%d", dwAlgId);
-        goto done;
-    }
-
-    /* success */
-    res = TRUE;
-
-done:
-    if(hTempKey != 0) {
-        CryptDestroyKey(hTempKey);
-    }
-    if(keyBlob != NULL) {
-        xmlFree(keyBlob);
-    }
-    return(res);
-}
-
diff --git a/src/mscrypto/crypto.c b/src/mscrypto/crypto.c
index b3d9e8d..5b44e18 100644
--- a/src/mscrypto/crypto.c
+++ b/src/mscrypto/crypto.c
@@ -70,19 +70,12 @@ xmlSecCryptoGetFunctions_mscrypto(void) {
 
 #ifndef XMLSEC_NO_RSA
     gXmlSecMSCryptoFunctions->keyDataRsaGetKlass                = xmlSecMSCryptoKeyDataRsaGetKlass;
-
-#ifndef XMLSEC_NO_SHA256
-    gXmlSecMSCryptoFunctions->transformRsaSha256GetKlass       = xmlSecMSCryptoTransformRsaSha256GetKlass;
-#endif /* XMLSEC_NO_SHA256 */
-#ifndef XMLSEC_NO_SHA384
-    gXmlSecMSCryptoFunctions->transformRsaSha384GetKlass       = xmlSecMSCryptoTransformRsaSha384GetKlass;
-#endif /* XMLSEC_NO_SHA384 */
-#ifndef XMLSEC_NO_SHA512
-    gXmlSecMSCryptoFunctions->transformRsaSha512GetKlass       = xmlSecMSCryptoTransformRsaSha512GetKlass;
-#endif /* XMLSEC_NO_SHA512 */
-
 #endif /* XMLSEC_NO_RSA */
 
+#ifndef XMLSEC_NO_HMAC
+    gXmlSecMSCryptoFunctions->keyDataHmacGetKlass               = xmlSecMSCryptoKeyDataHmacGetKlass;
+#endif /* XMLSEC_NO_HMAC */
+
 #ifndef XMLSEC_NO_DSA
     gXmlSecMSCryptoFunctions->keyDataDsaGetKlass                = xmlSecMSCryptoKeyDataDsaGetKlass;
 #endif /* XMLSEC_NO_DSA */
@@ -117,7 +110,27 @@ xmlSecCryptoGetFunctions_mscrypto(void) {
 #endif /* XMLSEC_NO_DES */
 
 #ifndef XMLSEC_NO_RSA
+
+#ifndef XMLSEC_NO_SMD5
+    gXmlSecMSCryptoFunctions->transformRsaMd5GetKlass          = xmlSecMSCryptoTransformRsaMd5GetKlass;
+#endif /* XMLSEC_NO_MD5 */
+
+#ifndef XMLSEC_NO_SHA1
     gXmlSecMSCryptoFunctions->transformRsaSha1GetKlass          = xmlSecMSCryptoTransformRsaSha1GetKlass;
+#endif /* XMLSEC_NO_SHA1 */
+
+#ifndef XMLSEC_NO_SHA256
+    gXmlSecMSCryptoFunctions->transformRsaSha256GetKlass       = xmlSecMSCryptoTransformRsaSha256GetKlass;
+#endif /* XMLSEC_NO_SHA256 */
+
+#ifndef XMLSEC_NO_SHA384
+    gXmlSecMSCryptoFunctions->transformRsaSha384GetKlass       = xmlSecMSCryptoTransformRsaSha384GetKlass;
+#endif /* XMLSEC_NO_SHA384 */
+
+#ifndef XMLSEC_NO_SHA512
+    gXmlSecMSCryptoFunctions->transformRsaSha512GetKlass       = xmlSecMSCryptoTransformRsaSha512GetKlass;
+#endif /* XMLSEC_NO_SHA512 */
+
     gXmlSecMSCryptoFunctions->transformRsaPkcs1GetKlass         = xmlSecMSCryptoTransformRsaPkcs1GetKlass;
 #endif /* XMLSEC_NO_RSA */
 
@@ -142,6 +155,36 @@ xmlSecCryptoGetFunctions_mscrypto(void) {
     gXmlSecMSCryptoFunctions->transformSha512GetKlass          = xmlSecMSCryptoTransformSha512GetKlass;
 #endif /* XMLSEC_NO_SHA512 */
 
+
+    /******************************* MD5 ********************************/
+#ifndef XMLSEC_NO_MD5
+    gXmlSecMSCryptoFunctions->transformMd5GetKlass             = xmlSecMSCryptoTransformMd5GetKlass;
+#endif /* XMLSEC_NO_MD5 */
+
+    /******************************* HMAC ********************************/
+#ifndef XMLSEC_NO_HMAC
+#ifndef XMLSEC_NO_MD5
+    gXmlSecMSCryptoFunctions->transformHmacMd5GetKlass         = xmlSecMSCryptoTransformHmacMd5GetKlass;
+#endif /* XMLSEC_NO_MD5 */
+
+#ifndef XMLSEC_NO_SHA1
+    gXmlSecMSCryptoFunctions->transformHmacSha1GetKlass        = xmlSecMSCryptoTransformHmacSha1GetKlass;
+#endif /* XMLSEC_NO_SHA1 */
+
+#ifndef XMLSEC_NO_SHA256
+    gXmlSecMSCryptoFunctions->transformHmacSha256GetKlass      = xmlSecMSCryptoTransformHmacSha256GetKlass;
+#endif /* XMLSEC_NO_SHA256 */
+
+#ifndef XMLSEC_NO_SHA384
+    gXmlSecMSCryptoFunctions->transformHmacSha384GetKlass      = xmlSecMSCryptoTransformHmacSha384GetKlass;
+#endif /* XMLSEC_NO_SHA384 */
+
+#ifndef XMLSEC_NO_SHA512
+    gXmlSecMSCryptoFunctions->transformHmacSha512GetKlass      = xmlSecMSCryptoTransformHmacSha512GetKlass;
+#endif /* XMLSEC_NO_SHA512 */
+
+#endif /* XMLSEC_NO_HMAC */
+
 #ifndef XMLSEC_NO_GOST
     gXmlSecMSCryptoFunctions->transformGostR3411_94GetKlass             = xmlSecMSCryptoTransformGostR3411_94GetKlass;
 #endif /* XMLSEC_NO_GOST */
diff --git a/src/mscrypto/digests.c b/src/mscrypto/digests.c
index 7fa7581..7e2c500 100644
--- a/src/mscrypto/digests.c
+++ b/src/mscrypto/digests.c
@@ -80,6 +80,13 @@ static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Sha2[] = {
     { NULL, 0 }
 };
 
+static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Md5[] = {
+    { MS_STRONG_PROV,                                   PROV_RSA_FULL },
+    { MS_ENHANCED_PROV,                                 PROV_RSA_FULL },
+    { MS_DEF_PROV,                                      PROV_RSA_FULL },
+    { NULL, 0 }
+};
+
 static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Gost[] = {
     { MAGPRO_CSP,                                       PROV_MAGPRO_GOST },
     { CRYPTOPRO_CSP,                                    PROV_CRYPTOPRO_GOST },
@@ -88,6 +95,13 @@ static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Gost[] = {
 
 static int
 xmlSecMSCryptoDigestCheckId(xmlSecTransformPtr transform) {
+
+#ifndef XMLSEC_NO_MD5
+    if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformMd5Id)) {
+        return(1);
+    }
+#endif /* XMLSEC_NO_MD5 */
+
 #ifndef XMLSEC_NO_SHA1
     if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformSha1Id)) {
         return(1);
@@ -134,9 +148,16 @@ xmlSecMSCryptoDigestInitialize(xmlSecTransformPtr transform) {
     /* initialize context */
     memset(ctx, 0, sizeof(xmlSecMSCryptoDigestCtx));
 
+#ifndef XMLSEC_NO_MD5
+    if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformMd5Id)) {
+        ctx->alg_id = CALG_MD5;
+        ctx->providers = xmlSecMSCryptoProviderInfo_Md5;
+    } else
+#endif /* XMLSEC_NO_MD5 */
+
 #ifndef XMLSEC_NO_SHA1
     if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformSha1Id)) {
-        ctx->alg_id = CALG_SHA;
+        ctx->alg_id = CALG_SHA1;
         ctx->providers = xmlSecMSCryptoProviderInfo_Sha1;
     } else
 #endif /* XMLSEC_NO_SHA1 */
@@ -203,7 +224,9 @@ static void xmlSecMSCryptoDigestFinalize(xmlSecTransformPtr transform) {
     if(ctx->mscHash != 0) {
         CryptDestroyHash(ctx->mscHash);
     }
-    CryptReleaseContext(ctx->provider, 0);
+    if(ctx->provider != 0) {
+        CryptReleaseContext(ctx->provider, 0);
+    }
 
     memset(ctx, 0, sizeof(xmlSecMSCryptoDigestCtx));
 }
@@ -376,6 +399,50 @@ xmlSecMSCryptoDigestExecute(xmlSecTransformPtr transform,
 }
 
 
+#ifndef XMLSEC_NO_MD5
+/******************************************************************************
+ *
+ * MD5
+ *
+ *****************************************************************************/
+static xmlSecTransformKlass xmlSecMSCryptoMd5Klass = {
+    /* klass/object sizes */
+    sizeof(xmlSecTransformKlass),               /* size_t klassSize */
+    xmlSecMSCryptoDigestSize,                   /* size_t objSize */
+
+    xmlSecNameMd5,                              /* const xmlChar* name; */
+    xmlSecHrefMd5,                              /* const xmlChar* href; */
+    xmlSecTransformUsageDigestMethod,           /* xmlSecTransformUsage usage; */
+    xmlSecMSCryptoDigestInitialize,             /* xmlSecTransformInitializeMethod initialize; */
+    xmlSecMSCryptoDigestFinalize,               /* xmlSecTransformFinalizeMethod finalize; */
+    NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
+    NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
+    NULL,                                       /* xmlSecTransformSetKeyReqMethod setKeyReq; */
+    NULL,                                       /* xmlSecTransformSetKeyMethod setKey; */
+    xmlSecMSCryptoDigestVerify,                 /* xmlSecTransformVerifyMethod verify; */
+    xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
+    xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
+    xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
+    NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
+    NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
+    xmlSecMSCryptoDigestExecute,                /* xmlSecTransformExecuteMethod execute; */
+    NULL,                                       /* void* reserved0; */
+    NULL,                                       /* void* reserved1; */
+};
+
+/**
+ * xmlSecMSCryptoTransformMd5GetKlass:
+ *
+ * SHA-1 digest transform klass.
+ *
+ * Returns: pointer to SHA-1 digest transform klass.
+ */
+xmlSecTransformId
+xmlSecMSCryptoTransformMd5GetKlass(void) {
+    return(&xmlSecMSCryptoMd5Klass);
+}
+#endif /* XMLSEC_NO_MD5 */
+
 #ifndef XMLSEC_NO_SHA1
 /******************************************************************************
  *
diff --git a/src/mscrypto/signatures.c b/src/mscrypto/signatures.c
index 005ea6c..72aaef7 100644
--- a/src/mscrypto/signatures.c
+++ b/src/mscrypto/signatures.c
@@ -83,33 +83,52 @@ static int xmlSecMSCryptoSignatureCheckId(xmlSecTransformPtr transform) {
     }
 #endif /* XMLSEC_NO_DSA */
 
-#ifndef XMLSEC_NO_GOST
-    if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformGost2001GostR3411_94Id)) {
+#ifndef XMLSEC_NO_RSA
+
+#ifndef XMLSEC_NO_MD5
+    if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaMd5Id)) {
         return(1);
-    }
-#endif /* XMLSEC_NO_GOST*/
+    } else
+#endif /* XMLSEC_NO_MD5 */
 
-#ifndef XMLSEC_NO_RSA
+#ifndef XMLSEC_NO_SHA1
     if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha1Id)) {
         return(1);
-    }
+    } else
+#endif /* XMLSEC_NO_SHA1 */
+
 #ifndef XMLSEC_NO_SHA256
     if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha256Id)) {
        return(1);
-    }
+    } else
 #endif /* XMLSEC_NO_SHA256 */
+
 #ifndef XMLSEC_NO_SHA384
     if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha384Id)) {
        return(1);
-    }
+    } else
 #endif /* XMLSEC_NO_SHA384 */
+
 #ifndef XMLSEC_NO_SHA512
     if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha512Id)) {
        return(1);
-    }
+    } else
 #endif /* XMLSEC_NO_SHA512 */
+
 #endif /* XMLSEC_NO_RSA */
 
+#ifndef XMLSEC_NO_GOST
+    if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformGost2001GostR3411_94Id)) {
+        return(1);
+    } else
+#endif /* XMLSEC_NO_GOST*/
+
+
+    /* not found */
+    {
+        return(0);
+    }
+
     return(0);
 }
 
@@ -124,11 +143,29 @@ static int xmlSecMSCryptoSignatureInitialize(xmlSecTransformPtr transform) {
 
     memset(ctx, 0, sizeof(xmlSecMSCryptoSignatureCtx));
 
+
+#ifndef XMLSEC_NO_DSA
+    if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformDsaSha1Id)) {
+        ctx->digestAlgId    = CALG_SHA1;
+        ctx->keyId          = xmlSecMSCryptoKeyDataDsaId;
+    } else
+#endif /* XMLSEC_NO_DSA */
+
 #ifndef XMLSEC_NO_RSA
+
+#ifndef XMLSEC_NO_MD5
+    if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaMd5Id)) {
+        ctx->digestAlgId    = CALG_MD5;
+        ctx->keyId          = xmlSecMSCryptoKeyDataRsaId;
+    } else
+#endif /* XMLSEC_NO_MD5 */
+
+#ifndef XMLSEC_NO_SHA1
     if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha1Id)) {
         ctx->digestAlgId    = CALG_SHA1;
         ctx->keyId          = xmlSecMSCryptoKeyDataRsaId;
     } else
+#endif /* XMLSEC_NO_SHA1 */
 
 #ifndef XMLSEC_NO_SHA256
     if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha256Id)) {
@@ -160,14 +197,8 @@ static int xmlSecMSCryptoSignatureInitialize(xmlSecTransformPtr transform) {
     } else
 #endif /* XMLSEC_NO_GOST*/
 
-#ifndef XMLSEC_NO_DSA
-    if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformDsaSha1Id)) {
-        ctx->digestAlgId    = CALG_SHA1;
-        ctx->keyId          = xmlSecMSCryptoKeyDataDsaId;
-    } else
-#endif /* XMLSEC_NO_DSA */
-
-    if(1) {
+    /* not found */
+    {
         xmlSecError(XMLSEC_ERRORS_HERE,
                     xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
                     NULL,
@@ -308,9 +339,18 @@ static int xmlSecMSCryptoSignatureVerify(xmlSecTransformPtr transform,
     /* Reverse the sig - Windows stores integers as octet streams in little endian
      * order.  The I2OSP algorithm used by XMLDSig to store integers is big endian */
 #ifndef XMLSEC_NO_RSA
+
+#ifndef XMLSEC_NO_MD5
+    if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaMd5Id)) {
+        ConvertEndian(data, tmpBuf, dataSize);
+    } else
+#endif /* XMLSEC_NO_MD5 */
+
+#ifndef XMLSEC_NO_SHA1
     if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha1Id)) {
         ConvertEndian(data, tmpBuf, dataSize);
     } else
+#endif /* XMLSEC_NO_SHA1 */
 
 #ifndef XMLSEC_NO_SHA256
     if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha256Id)) {
@@ -529,9 +569,18 @@ xmlSecMSCryptoSignatureExecute(xmlSecTransformPtr transform, int last, xmlSecTra
             /* Reverse the sig - Windows stores integers as octet streams in little endian
              * order.  The I2OSP algorithm used by XMLDSig to store integers is big endian */
 #ifndef XMLSEC_NO_RSA
+
+#ifndef XMLSEC_NO_MD5
+            if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaMd5Id)) {
+                ConvertEndian(tmpBuf, outBuf, outSize);
+            } else
+#endif /* XMLSEC_NO_MD5 */
+
+#ifndef XMLSEC_NO_SHA1
             if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha1Id)) {
                 ConvertEndian(tmpBuf, outBuf, outSize);
             } else
+#endif /* XMLSEC_NO_SHA1 */
 
 #ifndef XMLSEC_NO_SHA256
             if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha256Id)) {
@@ -551,7 +600,6 @@ xmlSecMSCryptoSignatureExecute(xmlSecTransformPtr transform, int last, xmlSecTra
             } else
 #endif /* XMLSEC_NO_SHA512 */
 
-
 #endif /* XMLSEC_NO_RSA*/
 
 #ifndef XMLSEC_NO_DSA
@@ -599,6 +647,54 @@ xmlSecMSCryptoSignatureExecute(xmlSecTransformPtr transform, int last, xmlSecTra
 
 
 #ifndef XMLSEC_NO_RSA
+
+#ifndef XMLSEC_NO_MD5
+/****************************************************************************
+ *
+ * RSA-MD5 signature transform
+ *
+ ***************************************************************************/
+static xmlSecTransformKlass xmlSecMSCryptoRsaMd5Klass = {
+    /* klass/object sizes */
+    sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */
+    xmlSecMSCryptoSignatureSize,                /* xmlSecSize objSize */
+
+    xmlSecNameRsaMd5,                          /* const xmlChar* name; */
+    xmlSecHrefRsaMd5,                          /* const xmlChar* href; */
+    xmlSecTransformUsageSignatureMethod,        /* xmlSecTransformUsage usage; */
+
+    xmlSecMSCryptoSignatureInitialize,          /* xmlSecTransformInitializeMethod initialize; */
+    xmlSecMSCryptoSignatureFinalize,            /* xmlSecTransformFinalizeMethod finalize; */
+    NULL,                                       /* xmlSecTransformNodeReadMethod readNode; */
+    NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */
+    xmlSecMSCryptoSignatureSetKeyReq,           /* xmlSecTransformSetKeyReqMethod setKeyReq; */
+    xmlSecMSCryptoSignatureSetKey,              /* xmlSecTransformSetKeyMethod setKey; */
+    xmlSecMSCryptoSignatureVerify,              /* xmlSecTransformVerifyMethod verify; */
+    xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */
+    xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */
+    xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */
+    NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */
+    NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */
+    xmlSecMSCryptoSignatureExecute,             /* xmlSecTransformExecuteMethod execute; */
+
+    NULL,                                       /* void* reserved0; */
+    NULL,                                       /* void* reserved1; */
+};
+
+/**
+ * xmlSecMSCryptoTransformRsaMd5GetKlass:
+ *
+ * The RSA-MD5 signature transform klass.
+ *
+ * Returns: RSA-MD5 signature transform klass.
+ */
+xmlSecTransformId
+xmlSecMSCryptoTransformRsaMd5GetKlass(void) {
+    return(&xmlSecMSCryptoRsaMd5Klass);
+}
+#endif /* XMLSEC_NO_MD5 */
+
+#ifndef XMLSEC_NO_SHA1
 /****************************************************************************
  *
  * RSA-SHA1 signature transform
@@ -642,6 +738,7 @@ xmlSecTransformId
 xmlSecMSCryptoTransformRsaSha1GetKlass(void) {
     return(&xmlSecMSCryptoRsaSha1Klass);
 }
+#endif /* XMLSEC_NO_SHA1 */
 
 #ifndef XMLSEC_NO_SHA256
 /****************************************************************************
diff --git a/src/mscrypto/symkeys.c b/src/mscrypto/symkeys.c
index 259db44..d42144e 100644
--- a/src/mscrypto/symkeys.c
+++ b/src/mscrypto/symkeys.c
@@ -160,7 +160,7 @@ static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataDesKlass = {
     /* data */
     xmlSecNameDESKeyValue,
     xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml,
-                                                                        /* xmlSecKeyDataUsage usage; */
+                                                /* xmlSecKeyDataUsage usage; */
     xmlSecHrefDESKeyValue,                      /* const xmlChar* href; */
     xmlSecNodeDESKeyValue,                      /* const xmlChar* dataNodeName; */
     xmlSecNs,                                   /* const xmlChar* dataNodeNs; */
@@ -204,6 +204,63 @@ xmlSecMSCryptoKeyDataDesGetKlass(void) {
 }
 #endif /* XMLSEC_NO_DES */
 
+#ifndef XMLSEC_NO_HMAC
+/**************************************************************************
+ *
+ * <xmlsec:HMACKeyValue> processing
+ *
+ *************************************************************************/
+static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataHmacKlass = {
+    sizeof(xmlSecKeyDataKlass),
+    xmlSecKeyDataBinarySize,
+
+    /* data */
+    xmlSecNameHMACKeyValue,
+    xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml,
+                                                /* xmlSecKeyDataUsage usage; */
+    xmlSecHrefHMACKeyValue,                     /* const xmlChar* href; */
+    xmlSecNodeHMACKeyValue,                     /* const xmlChar* dataNodeName; */
+    xmlSecNs,                                   /* const xmlChar* dataNodeNs; */
+
+    /* constructors/destructor */
+    xmlSecMSCryptoSymKeyDataInitialize,         /* xmlSecKeyDataInitializeMethod initialize; */
+    xmlSecMSCryptoSymKeyDataDuplicate,          /* xmlSecKeyDataDuplicateMethod duplicate; */
+    xmlSecMSCryptoSymKeyDataFinalize,           /* xmlSecKeyDataFinalizeMethod finalize; */
+    xmlSecMSCryptoSymKeyDataGenerate,           /* xmlSecKeyDataGenerateMethod generate; */
+
+    /* get info */
+    xmlSecMSCryptoSymKeyDataGetType,            /* xmlSecKeyDataGetTypeMethod getType; */
+    xmlSecMSCryptoSymKeyDataGetSize,            /* xmlSecKeyDataGetSizeMethod getSize; */
+        NULL,                                   /* xmlSecKeyDataGetIdentifier getIdentifier; */
+
+    /* read/write */
+    xmlSecMSCryptoSymKeyDataXmlRead,            /* xmlSecKeyDataXmlReadMethod xmlRead; */
+    xmlSecMSCryptoSymKeyDataXmlWrite,           /* xmlSecKeyDataXmlWriteMethod xmlWrite; */
+    xmlSecMSCryptoSymKeyDataBinRead,            /* xmlSecKeyDataBinReadMethod binRead; */
+    xmlSecMSCryptoSymKeyDataBinWrite,           /* xmlSecKeyDataBinWriteMethod binWrite; */
+
+    /* debug */
+    xmlSecMSCryptoSymKeyDataDebugDump,          /* xmlSecKeyDataDebugDumpMethod debugDump; */
+    xmlSecMSCryptoSymKeyDataDebugXmlDump,       /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */
+
+    /* reserved for the future */
+    NULL,                                       /* void* reserved0; */
+    NULL,                                       /* void* reserved1; */
+};
+
+/**
+ * xmlSecMSCryptoKeyDataHmacGetKlass:
+ *
+ * The HMAC key data klass.
+ *
+ * Returns: HMAC key data klass.
+ */
+xmlSecKeyDataId
+xmlSecMSCryptoKeyDataHmacGetKlass(void) {
+    return(&xmlSecMSCryptoKeyDataHmacKlass);
+}
+#endif /* XMLSEC_NO_HMAC */
+
 /*
  * GENERIC HELPER FUNCTIONS
  */
@@ -317,17 +374,417 @@ xmlSecMSCryptoSymKeyDataDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) {
 
 static int
 xmlSecMSCryptoSymKeyDataKlassCheck(xmlSecKeyDataKlass* klass) {
+
 #ifndef XMLSEC_NO_DES
     if(klass == xmlSecMSCryptoKeyDataDesId) {
         return(1);
-    }
+    } else 
 #endif /* XMLSEC_NO_DES */
 
 #ifndef XMLSEC_NO_AES
     if(klass == xmlSecMSCryptoKeyDataAesId) {
                 return(1);
-    }
+    } else
 #endif /* XMLSEC_NO_AES */
 
+#ifndef XMLSEC_NO_HMAC
+    if(klass == xmlSecMSCryptoKeyDataHmacId) {
+                return(1);
+    } else
+#endif /* XMLSEC_NO_HMAC */
+
+    {
+        return(0);
+    }
+
     return(0);
 }
+
+
+
+/*
+ * Low level helper routines for importing plain text keys in MS HKEY handle,
+ * since MSCrypto API does not support import of plain text (session) keys
+ * just like that.
+ * These functions are based upon MS kb article: 228786
+ *
+ * aleksey: also check "Base Provider Key BLOBs" article for priv key blob format
+ **/
+BOOL
+xmlSecMSCryptoCreatePrivateExponentOneKey(HCRYPTPROV hProv, HCRYPTKEY *hPrivateKey)
+{
+    HCRYPTKEY hKey = 0;
+    LPBYTE keyBlob = NULL;
+    DWORD keyBlobLen;
+    PUBLICKEYSTRUC* pubKeyStruc;
+    RSAPUBKEY* rsaPubKey;
+    DWORD bitLen;
+    BYTE *ptr;
+    int n;
+    BOOL res = FALSE;
+
+    xmlSecAssert2(hProv != 0, FALSE);
+    xmlSecAssert2(hPrivateKey != NULL, FALSE);
+
+    /* just in case */
+    *hPrivateKey = 0;
+
+    /* Generate the private key */
+    if(!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey)) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptGenKey",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    XMLSEC_ERRORS_NO_MESSAGE);
+        goto done;
+    }
+
+    /* Export the private key, we'll convert it to a private exponent of one key */
+    if(!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, NULL, &keyBlobLen)) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptExportKey",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    XMLSEC_ERRORS_NO_MESSAGE);
+        goto done;
+    }
+
+    keyBlob = (LPBYTE)xmlMalloc(sizeof(BYTE) * keyBlobLen);
+    if(keyBlob == NULL) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    NULL,
+                    XMLSEC_ERRORS_R_MALLOC_FAILED,
+                    XMLSEC_ERRORS_NO_MESSAGE);
+        goto done;
+    }
+
+    if(!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, keyBlob, &keyBlobLen)) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptExportKey",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    XMLSEC_ERRORS_NO_MESSAGE);
+        goto done;
+    }
+    CryptDestroyKey(hKey);
+    hKey = 0;
+
+    /* Get the bit length of the key */
+    if(keyBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptExportKey",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "len=%ld", keyBlobLen);
+        goto done;
+    }
+    pubKeyStruc = (PUBLICKEYSTRUC*)keyBlob;
+    if(pubKeyStruc->bVersion != 0x02) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptExportKey",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "pubKeyStruc->bVersion=%d", pubKeyStruc->bVersion);
+        goto done;
+    }
+    if(pubKeyStruc->bType != PRIVATEKEYBLOB) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptExportKey",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "pubKeyStruc->bType=%d", (int)pubKeyStruc->bType);
+        goto done;
+    }
+
+    /* aleksey: don't ask me why it is RSAPUBKEY, just don't ask */
+    rsaPubKey = (RSAPUBKEY*)(keyBlob + sizeof(PUBLICKEYSTRUC));
+
+    /* check that we have RSA private key */
+    if(rsaPubKey->magic != 0x32415352) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptExportKey",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "rsaPubKey->magic=0x%08lx", rsaPubKey->magic);
+        goto done;
+    }
+    bitLen = rsaPubKey->bitlen;
+
+    /*  Modify the Exponent in Key BLOB format Key BLOB format is documented in SDK */
+    rsaPubKey->pubexp = 1;
+
+    /* Private-key BLOBs, type PRIVATEKEYBLOB, are used to store private keys outside a CSP.
+     * Base provider private-key BLOBs have the following format:
+     *
+     * PUBLICKEYSTRUC  publickeystruc ;
+     * RSAPUBKEY rsapubkey;
+     * BYTE modulus[rsapubkey.bitlen/8];                1/8
+     * BYTE prime1[rsapubkey.bitlen/16];                1/16
+     * BYTE prime2[rsapubkey.bitlen/16];                1/16
+     * BYTE exponent1[rsapubkey.bitlen/16];             1/16
+     * BYTE exponent2[rsapubkey.bitlen/16];             1/16
+     * BYTE coefficient[rsapubkey.bitlen/16];           1/16
+     * BYTE privateExponent[rsapubkey.bitlen/8];        1/8
+     */
+    if(keyBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + bitLen / 2 + bitLen / 16) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptExportKey",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "len=%ld", keyBlobLen);
+        goto done;
+    }
+    ptr = (BYTE*)(keyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY));
+
+    /* Skip modulus, prime1, prime2 */
+    ptr += bitLen / 8;
+    ptr += bitLen / 16;
+    ptr += bitLen / 16;
+
+    /* Convert exponent1 to 1 */
+    for (n = 0; n < (bitLen / 16); n++) {
+        if (n == 0) ptr[n] = 1;
+        else ptr[n] = 0;
+    }
+    ptr += bitLen / 16;
+
+    /* Convert exponent2 to 1 */
+    for (n = 0; n < (bitLen / 16); n++) {
+        if (n == 0) ptr[n] = 1;
+        else ptr[n] = 0;
+    }
+    ptr += bitLen / 16;
+
+    /* Skip coefficient */
+    ptr += bitLen / 16;
+
+    /* Convert privateExponent to 1 */
+    for (n = 0; n < (bitLen / 16); n++) {
+        if (n == 0) ptr[n] = 1;
+        else ptr[n] = 0;
+    }
+
+    /* Import the exponent-of-one private key. */
+    if (!CryptImportKey(hProv, keyBlob, keyBlobLen, 0, 0, &hKey)) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptImportKey",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    XMLSEC_ERRORS_NO_MESSAGE);
+        goto done;
+    }
+    (*hPrivateKey) = hKey;
+    hKey = 0;
+    res = TRUE;
+
+done:
+    if(keyBlob != NULL) {
+        xmlFree(keyBlob);
+    }
+    if (hKey != 0) {
+        CryptDestroyKey(hKey);
+    }
+
+    return res;
+}
+
+BOOL
+xmlSecMSCryptoImportPlainSessionBlob(HCRYPTPROV hProv, HCRYPTKEY hPrivateKey,
+                                     ALG_ID dwAlgId, LPBYTE pbKeyMaterial,
+                                     DWORD dwKeyMaterial, HCRYPTKEY *hSessionKey) {
+    ALG_ID dwPrivKeyAlg;
+    LPBYTE keyBlob = NULL;
+    DWORD keyBlobLen, rndBlobSize, dwSize, n;
+    PUBLICKEYSTRUC* pubKeyStruc;
+    ALG_ID* algId;
+    DWORD dwPublicKeySize;
+    DWORD dwProvSessionKeySize;
+    LPBYTE pbPtr;
+    DWORD dwFlags;
+    PROV_ENUMALGS_EX ProvEnum;
+    HCRYPTKEY hTempKey = 0;
+    BOOL fFound;
+    BOOL res = FALSE;
+
+    xmlSecAssert2(hProv != 0, FALSE);
+    xmlSecAssert2(hPrivateKey != 0, FALSE);
+    xmlSecAssert2(pbKeyMaterial != NULL, FALSE);
+    xmlSecAssert2(dwKeyMaterial > 0, FALSE);
+    xmlSecAssert2(hSessionKey != NULL, FALSE);
+
+    /*  Double check to see if this provider supports this algorithm and key size */
+    fFound = FALSE;
+    dwFlags = CRYPT_FIRST;
+    dwSize = sizeof(ProvEnum);
+    while(CryptGetProvParam(hProv, PP_ENUMALGS_EX, (LPBYTE)&ProvEnum, &dwSize, dwFlags)) {
+        if (ProvEnum.aiAlgid == dwAlgId) {
+            fFound = TRUE;
+            break;
+        }
+        dwSize = sizeof(ProvEnum);
+        dwFlags = 0;
+    }
+    if(!fFound) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptGetProvParam",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "algId=%d is not supported", dwAlgId);
+        goto done;
+    }
+
+    /* We have to get the key size(including padding) from an HCRYPTKEY handle.
+     * PP_ENUMALGS_EX contains the key size without the padding so we can't use it.
+     */
+    if(!CryptGenKey(hProv, dwAlgId, 0, &hTempKey)) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptGenKey",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "algId=%d", dwAlgId);
+        goto done;
+    }
+
+    dwSize = sizeof(DWORD);
+    if(!CryptGetKeyParam(hTempKey, KP_KEYLEN, (LPBYTE)&dwProvSessionKeySize, &dwSize, 0)) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptGetKeyParam(KP_KEYLEN)",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "algId=%d", dwAlgId);
+        goto done;
+    }
+    CryptDestroyKey(hTempKey);
+    hTempKey = 0;
+
+    /* Our key is too big, leave */
+    if ((dwKeyMaterial * 8) > dwProvSessionKeySize) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    NULL,
+                    XMLSEC_ERRORS_R_INVALID_SIZE,
+                    "dwKeyMaterial=%ld;dwProvSessionKeySize=%ld",
+                    dwKeyMaterial, dwProvSessionKeySize);
+        goto done;
+    }
+
+    /* Get private key's algorithm */
+    dwSize = sizeof(ALG_ID);
+    if(!CryptGetKeyParam(hPrivateKey, KP_ALGID, (LPBYTE)&dwPrivKeyAlg, &dwSize, 0)) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptGetKeyParam(KP_ALGID)",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "algId=%d", dwAlgId);
+        goto done;
+    }
+
+    /* Get private key's length in bits */
+    dwSize = sizeof(DWORD);
+    if(!CryptGetKeyParam(hPrivateKey, KP_KEYLEN, (LPBYTE)&dwPublicKeySize, &dwSize, 0)) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptGetKeyParam(KP_KEYLEN)",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "algId=%d", dwAlgId);
+        goto done;
+    }
+
+    /* 3 is for the first reserved byte after the key material and the 2 reserved bytes at the end. */
+    if(dwPublicKeySize / 8 < dwKeyMaterial + 3) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    NULL,
+                    XMLSEC_ERRORS_R_INVALID_SIZE,
+                    "dwKeyMaterial=%ld;dwPublicKeySize=%ld",
+                    dwKeyMaterial, dwPublicKeySize);
+        goto done;
+    }
+    rndBlobSize = dwPublicKeySize / 8 - (dwKeyMaterial + 3);
+
+    /* Simple key BLOBs, type SIMPLEBLOB, are used to store and transport session keys outside a CSP.
+     * Base provider simple-key BLOBs are always encrypted with a key exchange public key. The pbData
+     * member of the SIMPLEBLOB is a sequence of bytes in the following format:
+     *
+     * PUBLICKEYSTRUC  publickeystruc ;
+     * ALG_ID algid;
+     * BYTE encryptedkey[rsapubkey.bitlen/8];
+     */
+
+    /* calculate Simple blob's length */
+    keyBlobLen = sizeof(PUBLICKEYSTRUC) + sizeof(ALG_ID) + (dwPublicKeySize / 8);
+
+    /* allocate simple blob buffer */
+    keyBlob = (LPBYTE)xmlMalloc(sizeof(BYTE) * keyBlobLen);
+    if(keyBlob == NULL) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    NULL,
+                    XMLSEC_ERRORS_R_MALLOC_FAILED,
+                    XMLSEC_ERRORS_NO_MESSAGE);
+        goto done;
+    }
+    memset(keyBlob, 0, keyBlobLen);
+
+    /* initialize PUBLICKEYSTRUC */
+    pubKeyStruc             = (PUBLICKEYSTRUC*)(keyBlob);
+    pubKeyStruc->bType      = SIMPLEBLOB;
+    pubKeyStruc->bVersion   = 0x02;
+    pubKeyStruc->reserved   = 0;
+    pubKeyStruc->aiKeyAlg   = dwAlgId;
+
+    /* Copy private key algorithm to buffer */
+    algId                   = (ALG_ID*)(keyBlob + sizeof(PUBLICKEYSTRUC));
+    (*algId)                = dwPrivKeyAlg;
+
+    /* Place the key material in reverse order */
+    pbPtr                   = (BYTE*)(keyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(ALG_ID));
+    for (n = 0; n < dwKeyMaterial; n++) {
+        pbPtr[n] = pbKeyMaterial[dwKeyMaterial - n - 1];
+    }
+    pbPtr += dwKeyMaterial;
+
+    /* skip reserved byte */
+    pbPtr += 1;
+
+    /* Generate random data for the rest of the buffer */
+    if((rndBlobSize > 0) && !CryptGenRandom(hProv, rndBlobSize, pbPtr)) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptGenRandom",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "rndBlobSize=%ld", rndBlobSize);
+        goto done;
+    }
+    /* aleksey: why are we doing this? */
+    for (n = 0; n < rndBlobSize; n++) {
+        if (pbPtr[n] == 0) pbPtr[n] = 1;
+    }
+
+    /* set magic number at the end */
+    keyBlob[keyBlobLen - 2] = 2;
+
+    if(!CryptImportKey(hProv, keyBlob , keyBlobLen, hPrivateKey, CRYPT_EXPORTABLE, hSessionKey)) {
+        xmlSecError(XMLSEC_ERRORS_HERE,
+                    NULL,
+                    "CryptImportKey",
+                    XMLSEC_ERRORS_R_CRYPTO_FAILED,
+                    "algId=%d", dwAlgId);
+        goto done;
+    }
+
+    /* success */
+    res = TRUE;
+
+done:
+    if(hTempKey != 0) {
+        CryptDestroyKey(hTempKey);
+    }
+    if(keyBlob != NULL) {
+        xmlFree(keyBlob);
+    }
+    return(res);
+}
+
+
diff --git a/win32/Makefile.msvc b/win32/Makefile.msvc
index 401b72e..2e1cc6f 100644
--- a/win32/Makefile.msvc
+++ b/win32/Makefile.msvc
@@ -262,6 +262,7 @@ XMLSEC_MSCRYPTO_OBJS = \
 	$(XMLSEC_MSCRYPTO_INTDIR)\crypto.obj \
 	$(XMLSEC_MSCRYPTO_INTDIR)\ciphers.obj \
 	$(XMLSEC_MSCRYPTO_INTDIR)\digests.obj \
+	$(XMLSEC_MSCRYPTO_INTDIR)\hmac.obj \
 	$(XMLSEC_MSCRYPTO_INTDIR)\symkeys.obj \
 	$(XMLSEC_MSCRYPTO_INTDIR)\kt_rsa.obj \
 	$(XMLSEC_MSCRYPTO_INTDIR)\strings.obj \
@@ -275,6 +276,7 @@ XMLSEC_MSCRYPTO_OBJS_A = \
 	$(XMLSEC_MSCRYPTO_INTDIR_A)\crypto.obj \
 	$(XMLSEC_MSCRYPTO_INTDIR_A)\ciphers.obj \
 	$(XMLSEC_MSCRYPTO_INTDIR_A)\digests.obj \
+	$(XMLSEC_MSCRYPTO_INTDIR_A)\hmac.obj \
 	$(XMLSEC_MSCRYPTO_INTDIR_A)\symkeys.obj \
 	$(XMLSEC_MSCRYPTO_INTDIR_A)\kt_rsa.obj \
 	$(XMLSEC_MSCRYPTO_INTDIR_A)\strings.obj \



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]