bcrypt: Implement MD5 algorithm and add tests.

Patrick Armstrong pat at triplefox.com
Mon Mar 7 21:45:27 CST 2016


Tested on OS X 10.11, Ubuntu Linux 14.04.

Signed-off-by: Patrick Armstrong <pat at oldpatricka.com>
---
 dlls/bcrypt/bcrypt_main.c  | 27 +++++++++++++++++
 dlls/bcrypt/tests/bcrypt.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++
 include/bcrypt.h           |  1 +
 3 files changed, 102 insertions(+)

diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index ede37e3..957efdd 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -174,6 +174,7 @@ struct object
 
 enum alg_id
 {
+    ALG_ID_MD5,
     ALG_ID_SHA1,
     ALG_ID_SHA256,
     ALG_ID_SHA384,
@@ -184,6 +185,7 @@ static const struct {
     ULONG hash_length;
     const WCHAR *alg_name;
 } alg_props[] = {
+    /* ALG_ID_MD5    */ { 16, BCRYPT_MD5_ALGORITHM },
     /* ALG_ID_SHA1   */ { 20, BCRYPT_SHA1_ALGORITHM },
     /* ALG_ID_SHA256 */ { 32, BCRYPT_SHA256_ALGORITHM },
     /* ALG_ID_SHA384 */ { 48, BCRYPT_SHA384_ALGORITHM },
@@ -211,6 +213,7 @@ NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR
     }
 
     if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
+    else if (!strcmpW( id, BCRYPT_MD5_ALGORITHM )) alg_id = ALG_ID_MD5;
     else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
     else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
     else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
@@ -262,6 +265,7 @@ struct hash
     enum alg_id   alg_id;
     union
     {
+        CC_MD5_CTX    md5_ctx;
         CC_SHA1_CTX   sha1_ctx;
         CC_SHA256_CTX sha256_ctx;
         CC_SHA512_CTX sha512_ctx;
@@ -272,6 +276,9 @@ static NTSTATUS hash_init( struct hash *hash )
 {
     switch (hash->alg_id)
     {
+    case ALG_ID_MD5:
+        CC_MD5_Init( &hash->u.md5_ctx );
+        break;
     case ALG_ID_SHA1:
         CC_SHA1_Init( &hash->u.sha1_ctx );
         break;
@@ -299,6 +306,10 @@ static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
 {
     switch (hash->alg_id)
     {
+    case ALG_ID_MD5:
+        CC_MD5_Update( &hash->u.md5_ctx, input, size );
+        break;
+
     case ALG_ID_SHA1:
         CC_SHA1_Update( &hash->u.sha1_ctx, input, size );
         break;
@@ -326,6 +337,10 @@ static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
 {
     switch (hash->alg_id)
     {
+    case ALG_ID_MD5:
+        CC_MD5_Final( output, &hash->u.md5_ctx );
+        break;
+
     case ALG_ID_SHA1:
         CC_SHA1_Final( output, &hash->u.sha1_ctx );
         break;
@@ -364,6 +379,9 @@ static NTSTATUS hash_init( struct hash *hash )
 
     switch (hash->alg_id)
     {
+    case ALG_ID_MD5:
+        alg = GNUTLS_DIG_MD5;
+        break;
     case ALG_ID_SHA1:
         alg = GNUTLS_DIG_SHA1;
         break;
@@ -426,6 +444,7 @@ static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
 }
 #endif
 
+#define OBJECT_LENGTH_MD5       274
 #define OBJECT_LENGTH_SHA1      278
 #define OBJECT_LENGTH_SHA256    286
 #define OBJECT_LENGTH_SHA384    382
@@ -467,6 +486,14 @@ static NTSTATUS get_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf,
 
     switch (id)
     {
+    case ALG_ID_MD5:
+        if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
+        {
+            value = OBJECT_LENGTH_MD5;
+            break;
+        }
+        FIXME( "unsupported md5 algorithm property %s\n", debugstr_w(prop) );
+        return STATUS_NOT_IMPLEMENTED;
     case ALG_ID_SHA1:
         if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
         {
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
index 2613a07..bcb287b 100644
--- a/dlls/bcrypt/tests/bcrypt.c
+++ b/dlls/bcrypt/tests/bcrypt.c
@@ -404,6 +404,79 @@ static void test_sha512(void)
     ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
 }
 
+static void test_md5(void)
+{
+    static const char expected[] =
+        "e2a3e68d23ce348b8f68b3079de3d4c9";
+    BCRYPT_ALG_HANDLE alg;
+    BCRYPT_HASH_HANDLE hash;
+    UCHAR buf[512], md5[16];
+    ULONG size, len;
+    char str[65];
+    NTSTATUS ret;
+
+    alg = NULL;
+    ret = BCryptOpenAlgorithmProvider(&alg, BCRYPT_MD5_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+    ok(alg != NULL, "alg not set\n");
+
+    len = size = 0xdeadbeef;
+    ret = BCryptGetProperty(NULL, BCRYPT_OBJECT_LENGTH, (UCHAR *)&len, sizeof(len), &size, 0);
+    ok(ret == STATUS_INVALID_HANDLE, "got %08x\n", ret);
+
+    len = size = 0xdeadbeef;
+    ret = BCryptGetProperty(alg, NULL, (UCHAR *)&len, sizeof(len), &size, 0);
+    ok(ret == STATUS_INVALID_PARAMETER, "got %08x\n", ret);
+
+    len = size = 0xdeadbeef;
+    ret = BCryptGetProperty(alg, BCRYPT_OBJECT_LENGTH, (UCHAR *)&len, sizeof(len), NULL, 0);
+    ok(ret == STATUS_INVALID_PARAMETER, "got %08x\n", ret);
+
+    len = size = 0xdeadbeef;
+    ret = BCryptGetProperty(alg, BCRYPT_OBJECT_LENGTH, NULL, sizeof(len), &size, 0);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+    ok(size == sizeof(len), "got %u\n", size);
+
+    len = size = 0xdeadbeef;
+    ret = BCryptGetProperty(alg, BCRYPT_OBJECT_LENGTH, (UCHAR *)&len, 0, &size, 0);
+    ok(ret == STATUS_BUFFER_TOO_SMALL, "got %08x\n", ret);
+    ok(len == 0xdeadbeef, "got %u\n", len);
+    ok(size == sizeof(len), "got %u\n", size);
+
+    len = size = 0xdeadbeef;
+    ret = BCryptGetProperty(alg, BCRYPT_OBJECT_LENGTH, (UCHAR *)&len , sizeof(len), &size, 0);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+    ok(len != 0xdeadbeef, "len not set\n");
+    ok(size == sizeof(len), "got %u\n", size);
+
+    test_hash_length(alg, 16);
+    test_alg_name(alg, "MD5");
+
+    hash = NULL;
+    len = sizeof(buf);
+    ret = BCryptCreateHash(alg, &hash, buf, len, NULL, 0, 0);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+    ok(hash != NULL, "hash not set\n");
+
+    ret = BCryptHashData(hash, (UCHAR *)"test", sizeof("test"), 0);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+
+    test_hash_length(hash, 16);
+    test_alg_name(hash, "MD5");
+
+    memset(md5, 0, sizeof(md5));
+    ret = BCryptFinishHash(hash, md5, sizeof(md5), 0);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+    format_hash( md5, sizeof(md5), str );
+    ok(!strcmp(str, expected), "got %s\n", str);
+
+    ret = BCryptDestroyHash(hash);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+
+    ret = BCryptCloseAlgorithmProvider(alg, 0);
+    ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+}
+
 START_TEST(bcrypt)
 {
     test_BCryptGenRandom();
@@ -412,4 +485,5 @@ START_TEST(bcrypt)
     test_sha256();
     test_sha384();
     test_sha512();
+    test_md5();
 }
diff --git a/include/bcrypt.h b/include/bcrypt.h
index 30988be..3cd14d2 100644
--- a/include/bcrypt.h
+++ b/include/bcrypt.h
@@ -63,6 +63,7 @@ typedef LONG NTSTATUS;
 #define MS_PLATFORM_CRYPTO_PROVIDER (const WCHAR [])\
     {'M','i','c','r','o','s','o','f','t',' ','P','l','a','t','f','o','r','m',' ','C','r','y','p','t','o',' ','P','r','o','v','i','d','e','r',0}
 
+#define BCRYPT_MD5_ALGORITHM        (const WCHAR []){'M','D','5',0}
 #define BCRYPT_SHA1_ALGORITHM       (const WCHAR []){'S','H','A','1',0}
 #define BCRYPT_SHA256_ALGORITHM     (const WCHAR []){'S','H','A','2','5','6',0}
 #define BCRYPT_SHA384_ALGORITHM     (const WCHAR []){'S','H','A','3','8','4',0}
-- 
2.5.4 (Apple Git-61)




More information about the wine-patches mailing list