Add Windows CNG (BCrypt) support to HCrypto EVP API
authorLuke Howard <lukeh@padl.com>
Fri, 6 Feb 2015 05:26:08 +0000 (16:26 +1100)
committerLuke Howard <lukeh@padl.com>
Wed, 11 Feb 2015 05:00:32 +0000 (16:00 +1100)
28 files changed:
doc/copyright.texi
lib/hcrypto/Makefile.am
lib/hcrypto/NTMakefile
lib/hcrypto/dllmain.c [deleted file]
lib/hcrypto/evp-cc.c
lib/hcrypto/evp-hcrypto.c
lib/hcrypto/evp-w32.c [new file with mode: 0644]
lib/hcrypto/evp-w32.h [new file with mode: 0644]
lib/hcrypto/evp-wincng.c [new file with mode: 0644]
lib/hcrypto/evp-wincng.h [new file with mode: 0644]
lib/hcrypto/evp.c
lib/hcrypto/libhcrypto-exports.def
lib/hcrypto/md2.c
lib/hcrypto/md2.h
lib/hcrypto/md4.c
lib/hcrypto/md4.h
lib/hcrypto/md5.c
lib/hcrypto/md5.h
lib/hcrypto/sha.c
lib/hcrypto/sha.h
lib/hcrypto/sha256.c
lib/hcrypto/sha512.c
lib/hcrypto/test_bulk.c [new file with mode: 0644]
lib/hcrypto/test_cipher.c
lib/hcrypto/version-script.map
lib/heimdal/NTMakefile
lib/krb5/dll.c
windows/NTMakefile.w32

index 490abbccee8332d98854122daf4baeb2d2bd3b45..84baec52a6071e4b9f09d3f67153ba2dc6ec553c 100644 (file)
@@ -443,7 +443,7 @@ Windows support
 
 @verbatim
 
-Copyright (c) 2009, Secure Endpoints Inc.
+Copyright (c) 2009-2015, Secure Endpoints Inc.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
index d47cf92f8ede6bedbef9736efa6fcb8008f1454d..510e5350e886112e136d55beed768017c6bf74eb 100644 (file)
@@ -60,6 +60,7 @@ PROGRAM_TESTS = \
        rc2test  \
        rctest \
        test_bn \
+       test_bulk \
        test_cipher \
        test_engine_dso \
        test_hmac \
index eced950c604c086742b9cbbdaaa159709c597d03..c46325f1b27275cda9191cf0bf37cece4875366e 100644 (file)
@@ -62,6 +62,8 @@ INCFILES=     \
        $(HCRYPTOINCLUDEDIR)\evp.h      \
        $(HCRYPTOINCLUDEDIR)\evp-hcrypto.h      \
        $(HCRYPTOINCLUDEDIR)\evp-cc.h   \
+       $(HCRYPTOINCLUDEDIR)\evp-wincng.h       \
+       $(HCRYPTOINCLUDEDIR)\evp-w32.h  \
        $(HCRYPTOINCLUDEDIR)\hmac.h     \
        $(HCRYPTOINCLUDEDIR)\md2.h      \
        $(HCRYPTOINCLUDEDIR)\md4.h      \
@@ -103,6 +105,8 @@ libhcrypto_OBJs =                   \
        $(OBJ)\evp.obj                  \
        $(OBJ)\evp-hcrypto.obj          \
        $(OBJ)\evp-cc.obj               \
+       $(OBJ)\evp-wincng.obj           \
+       $(OBJ)\evp-w32.obj              \
        $(OBJ)\engine.obj               \
        $(OBJ)\hmac.obj                 \
        $(OBJ)\md2.obj                  \
@@ -150,6 +154,7 @@ test-binaries:                              \
        $(OBJ)\rc2test.exe              \
        $(OBJ)\rctest.exe               \
        $(OBJ)\test_bn.exe              \
+       $(OBJ)\test_bulk.exe            \
        $(OBJ)\test_cipher.exe          \
        $(OBJ)\test_engine_dso.exe      \
        $(OBJ)\test_hmac.exe            \
@@ -184,6 +189,10 @@ $(OBJ)\test_bn.exe: $(OBJ)\test_bn.obj $(LIBHEIMDAL) $(LIBROKEN)
        $(EXECONLINK)
        $(EXEPREP_NODIST)
 
+$(OBJ)\test_bulk.exe: $(OBJ)\test_bulk.obj $(TESTLIB) $(LIBHEIMDAL) $(LIBROKEN) $(LIBVERS)
+       $(EXECONLINK)
+       $(EXEPREP_NODIST)
+
 $(OBJ)\test_cipher.exe: $(OBJ)\test_cipher.obj $(TESTLIB) $(LIBHEIMDAL) $(LIBROKEN) $(LIBVERS)
        $(EXECONLINK)
        $(EXEPREP_NODIST)
@@ -231,6 +240,7 @@ test-run:
        rc2test.exe
        rctest.exe
        test_bn.exe
+       test_bulk.exe
        test_cipher.exe
        test_engine_dso.exe
        test_hmac.exe
diff --git a/lib/hcrypto/dllmain.c b/lib/hcrypto/dllmain.c
deleted file mode 100644 (file)
index b241c73..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the Institute nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <config.h>
-
-#include <Windows.h>
-
-BOOL WINAPI
-DllMain (HANDLE hInst,
-        ULONG reason,
-        LPVOID lpReserved)
-{
-    switch(reason) {
-    case DLL_PROCESS_ATTACH:
-    case DLL_PROCESS_DETACH:
-    default:
-       return TRUE;
-    }
-}
index bd084a25e20d4cdef1c9817e16a6c20bf11e3123..8ba1ba7f5d1e7693534336975f8fcacb46bec74c 100644 (file)
@@ -148,9 +148,12 @@ init_cc_key(int encp, CCAlgorithm alg, CCOptions opts, const void *key,
        CCCryptorRelease(*ref);
     }
 
-    ret = CCCryptorCreate(op, alg, opts, key, keylen, iv, ref);
-    if (ret)
-       return 0;
+    if (key) {
+        ret = CCCryptorCreate(op, alg, opts, key, keylen, iv, ref);
+        if (ret)
+           return 0;
+    }
+
     return 1;
 }
 
@@ -375,7 +378,8 @@ cc_aes_cfb8_init(EVP_CIPHER_CTX *ctx,
                int encp)
 {
     struct cc_key *cc = ctx->cipher_data;
-    memcpy(ctx->iv, iv, ctx->cipher->iv_len);
+    if (iv)
+        memcpy(ctx->iv, iv, ctx->cipher->iv_len);
     return init_cc_key(1, kCCAlgorithmAES128, kCCOptionECBMode,
                       key, ctx->cipher->key_len, NULL, &cc->href);
 }
index bf37b42edcaca83b52d4a64859e71c690053a30e..387fe8d198fae4a6b9e915bb01c072b6f75fbaaa 100644 (file)
@@ -69,7 +69,7 @@ aes_init(EVP_CIPHER_CTX *ctx,
         int encp)
 {
     AES_KEY *k = ctx->cipher_data;
-    if (ctx->encrypt)
+    if (ctx->encrypt || EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CFB8_MODE)
        AES_set_encrypt_key(key, ctx->cipher->key_len * 8, k);
     else
        AES_set_decrypt_key(key, ctx->cipher->key_len * 8, k);
@@ -83,7 +83,7 @@ aes_do_cipher(EVP_CIPHER_CTX *ctx,
              unsigned int size)
 {
     AES_KEY *k = ctx->cipher_data;
-    if (ctx->flags & EVP_CIPH_CFB8_MODE)
+    if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CFB8_MODE)
         AES_cfb8_encrypt(in, out, size, k, ctx->iv, ctx->encrypt);
     else
         AES_cbc_encrypt(in, out, size, k, ctx->iv, ctx->encrypt);
diff --git a/lib/hcrypto/evp-w32.c b/lib/hcrypto/evp-w32.c
new file mode 100644 (file)
index 0000000..a72af16
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Windows fallback provider: decides whether to use hcrypto or
+ * wincng depending on whether bcrypt.dll is available (i.e. it
+ * is runtime compatible back to XP, but will use the native
+ * crypto APIs from Vista onwards).
+ */
+
+#include "config.h"
+
+#include <windows.h>
+#include <assert.h>
+
+#include <evp.h>
+#include <evp-w32.h>
+#include <evp-hcrypto.h>
+
+#if NTDDI_VERSION >= NTDDI_VISTA
+
+#include <evp-wincng.h>
+
+static LONG wincng_available = -1;
+
+static __inline int
+wincng_check_availability(void)
+{
+    if (wincng_available == -1) {
+       char szBCryptDllPath[MAX_PATH];
+       UINT cbBCryptDllPath;
+
+       cbBCryptDllPath = GetSystemDirectory(szBCryptDllPath,
+                                            sizeof(szBCryptDllPath));
+       if (cbBCryptDllPath > 0 &&
+           cbBCryptDllPath < sizeof(szBCryptDllPath) &&
+           strncat_s(szBCryptDllPath,
+                     sizeof(szBCryptDllPath), "\\bcrypt.dll", 11) == 0) {
+           HANDLE hBCryptDll = LoadLibrary(szBCryptDllPath);
+
+           InterlockedCompareExchangeRelease(&wincng_available,
+                                             !!hBCryptDll, -1);
+           if (hBCryptDll)
+               FreeLibrary(hBCryptDll);
+       }
+    }
+
+    return wincng_available == 1;
+}
+
+BOOL WINAPI
+_hc_w32crypto_DllMain(HINSTANCE hinstDLL,
+                     DWORD fdwReason,
+                     LPVOID lpvReserved)
+{
+    if (fdwReason == DLL_PROCESS_DETACH) {
+       /*
+        * Don't bother cleaning up on process exit, only on
+        * FreeLibrary() (in which case lpvReserved will be NULL).
+        */
+       if (lpvReserved == NULL)
+           _hc_wincng_cleanup();
+    }
+
+    return TRUE;
+}
+
+#define EVP_W32CRYPTO_PROVIDER(type, name)                 \
+                                                           \
+    const type *hc_EVP_w32crypto_ ##name (void)                    \
+    {                                                      \
+       if (wincng_check_availability())                    \
+           return hc_EVP_wincng_ ##name ();                \
+       else                                                \
+           return hc_EVP_hcrypto_ ##name ();               \
+    }
+
+#else
+
+#define EVP_W32CRYPTO_PROVIDER(type, name)                 \
+       EVP_W32CRYPTO_PROVIDER_CNG_UNAVAILABLE(type, name)
+
+#endif /* NTDDI_VERSION >= NTDDI_VISTA */
+
+#define EVP_W32CRYPTO_PROVIDER_CNG_UNAVAILABLE(type, name)  \
+                                                           \
+    const type *hc_EVP_w32crypto_ ##name (void)                    \
+    {                                                      \
+       return hc_EVP_hcrypto_ ##name ();                   \
+    }
+
+EVP_W32CRYPTO_PROVIDER(EVP_MD, md2)
+EVP_W32CRYPTO_PROVIDER(EVP_MD, md4)
+EVP_W32CRYPTO_PROVIDER(EVP_MD, md5)
+EVP_W32CRYPTO_PROVIDER(EVP_MD, sha1)
+EVP_W32CRYPTO_PROVIDER(EVP_MD, sha256)
+EVP_W32CRYPTO_PROVIDER(EVP_MD, sha384)
+EVP_W32CRYPTO_PROVIDER(EVP_MD, sha512)
+
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, rc2_cbc)
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, rc2_40_cbc)
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, rc2_64_cbc)
+
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, rc4)
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, rc4_40)
+
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, des_cbc)
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, des_ede3_cbc)
+
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, aes_128_cbc)
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, aes_192_cbc)
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, aes_256_cbc)
+
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, aes_128_cfb8)
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, aes_192_cfb8)
+EVP_W32CRYPTO_PROVIDER(EVP_CIPHER, aes_256_cfb8)
+
+EVP_W32CRYPTO_PROVIDER_CNG_UNAVAILABLE(EVP_CIPHER, camellia_128_cbc)
+EVP_W32CRYPTO_PROVIDER_CNG_UNAVAILABLE(EVP_CIPHER, camellia_192_cbc)
+EVP_W32CRYPTO_PROVIDER_CNG_UNAVAILABLE(EVP_CIPHER, camellia_256_cbc)
diff --git a/lib/hcrypto/evp-w32.h b/lib/hcrypto/evp-w32.h
new file mode 100644 (file)
index 0000000..89bfa4d
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifndef HEIM_EVP_W32_H
+#define HEIM_EVP_W32_H 1
+
+/* symbol renaming */
+#define EVP_w32crypto_md2() hc_EVP_w32crypto_md2()
+#define EVP_w32crypto_md4() hc_EVP_w32crypto_md4()
+#define EVP_w32crypto_md5() hc_EVP_w32crypto_md5()
+#define EVP_w32crypto_sha1() hc_EVP_w32crypto_sha1()
+#define EVP_w32crypto_sha256() hc_EVP_w32crypto_sha256()
+#define EVP_w32crypto_sha384() hc_EVP_w32crypto_sha384()
+#define EVP_w32crypto_sha512() hc_EVP_w32crypto_sha512()
+#define EVP_w32crypto_des_cbc() hc_EVP_w32crypto_des_cbc()
+#define EVP_w32crypto_des_ede3_cbc() hc_EVP_w32crypto_des_ede3_cbc()
+#define EVP_w32crypto_aes_128_cbc() hc_EVP_w32crypto_aes_128_cbc()
+#define EVP_w32crypto_aes_192_cbc() hc_EVP_w32crypto_aes_192_cbc()
+#define EVP_w32crypto_aes_256_cbc() hc_EVP_w32crypto_aes_256_cbc()
+#define EVP_w32crypto_aes_128_cfb8() hc_EVP_w32crypto_aes_128_cfb8()
+#define EVP_w32crypto_aes_192_cfb8() hc_EVP_w32crypto_aes_192_cfb8()
+#define EVP_w32crypto_aes_256_cfb8() hc_EVP_w32crypto_aes_256_cfb8()
+#define EVP_w32crypto_rc4() hc_EVP_w32crypto_rc4()
+#define EVP_w32crypto_rc4_40() hc_EVP_w32crypto_rc4_40()
+#define EVP_w32crypto_rc2_40_cbc() hc_EVP_w32crypto_rc2_40_cbc()
+#define EVP_w32crypto_rc2_64_cbc() hc_EVP_w32crypto_rc2_64_cbc()
+#define EVP_w32crypto_rc2_cbc() hc_EVP_w32crypto_rc2_cbc()
+#define EVP_w32crypto_camellia_128_cbc() hc_EVP_w32crypto_camellia_128_cbc()
+#define EVP_w32crypto_camellia_192_cbc() hc_EVP_w32crypto_camellia_192_cbc()
+#define EVP_w32crypto_camellia_256_cbc() hc_EVP_w32crypto_camellia_256_cbc()
+
+/*
+ * This provider dynamically selects between Windows CNG (if running
+ * on Vista or above) or the inbuilt provider (if running on XP).
+ */
+
+HC_CPP_BEGIN
+
+const EVP_MD * hc_EVP_w32crypto_md2(void);
+const EVP_MD * hc_EVP_w32crypto_md4(void);
+const EVP_MD * hc_EVP_w32crypto_md5(void);
+const EVP_MD * hc_EVP_w32crypto_sha1(void);
+const EVP_MD * hc_EVP_w32crypto_sha256(void);
+const EVP_MD * hc_EVP_w32crypto_sha384(void);
+const EVP_MD * hc_EVP_w32crypto_sha512(void);
+
+const EVP_CIPHER * hc_EVP_w32crypto_des_cbc(void);
+const EVP_CIPHER * hc_EVP_w32crypto_des_ede3_cbc(void);
+
+const EVP_CIPHER * hc_EVP_w32crypto_aes_128_cbc(void);
+const EVP_CIPHER * hc_EVP_w32crypto_aes_192_cbc(void);
+const EVP_CIPHER * hc_EVP_w32crypto_aes_256_cbc(void);
+
+const EVP_CIPHER * hc_EVP_w32crypto_aes_128_cfb8(void);
+const EVP_CIPHER * hc_EVP_w32crypto_aes_192_cfb8(void);
+const EVP_CIPHER * hc_EVP_w32crypto_aes_256_cfb8(void);
+
+const EVP_CIPHER * hc_EVP_w32crypto_rc4(void);
+const EVP_CIPHER * hc_EVP_w32crypto_rc4_40(void);
+
+const EVP_CIPHER * hc_EVP_w32crypto_rc2_cbc(void);
+const EVP_CIPHER * hc_EVP_w32crypto_rc2_40_cbc(void);
+const EVP_CIPHER * hc_EVP_w32crypto_rc2_64_cbc(void);
+
+const EVP_CIPHER * hc_EVP_w32crypto_camellia_128_cbc(void);
+const EVP_CIPHER * hc_EVP_w32crypto_camellia_192_cbc(void);
+const EVP_CIPHER * hc_EVP_w32crypto_camellia_256_cbc(void);
+
+HC_CPP_END
+
+#endif /* HEIM_EVP_W32_H */
diff --git a/lib/hcrypto/evp-wincng.c b/lib/hcrypto/evp-wincng.c
new file mode 100644 (file)
index 0000000..c5d444c
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+ * Copyright (c) 2015, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Windows CNG provider */
+
+#include "config.h"
+
+#include <windows.h>
+#include <assert.h>
+
+#if NTDDI_VERSION >= NTDDI_VISTA
+
+#include <evp.h>
+#include <evp-wincng.h>
+
+#include <bcrypt.h>
+
+/*
+ * CNG cipher provider
+ */
+
+struct wincng_key {
+    BCRYPT_KEY_HANDLE hKey;
+    UCHAR rgbKeyObject[1];
+};
+
+#define WINCNG_KEY_OBJECT_SIZE(ctx) \
+       ((ctx)->cipher->ctx_size - sizeof(struct wincng_key) + 1)
+
+static int
+wincng_do_cipher(EVP_CIPHER_CTX *ctx,
+                unsigned char *out,
+                const unsigned char *in,
+                unsigned int size)
+{
+    struct wincng_key *cng = ctx->cipher_data;
+    NTSTATUS status;
+    ULONG cbResult;
+
+    assert(EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_STREAM_CIPHER ||
+          (size % ctx->cipher->block_size) == 0);
+
+    if (ctx->encrypt) {
+       status = BCryptEncrypt(cng->hKey,
+                              (PUCHAR)in,
+                              size,
+                              NULL, /* pPaddingInfo */
+                              ctx->cipher->iv_len ? ctx->iv : NULL,
+                              ctx->cipher->iv_len,
+                              out,
+                              size,
+                              &cbResult,
+                              0);
+    } else {
+       status = BCryptDecrypt(cng->hKey,
+                              (PUCHAR)in,
+                              size,
+                              NULL, /* pPaddingInfo */
+                              ctx->cipher->iv_len ? ctx->iv : NULL,
+                              ctx->cipher->iv_len,
+                              out,
+                              size,
+                              &cbResult,
+                              0);
+    }
+
+    return BCRYPT_SUCCESS(status) && cbResult == size;
+}
+
+static int
+wincng_cleanup(EVP_CIPHER_CTX *ctx)
+{
+    struct wincng_key *cng = ctx->cipher_data;
+
+    if (cng->hKey)
+       BCryptDestroyKey(cng->hKey);
+    SecureZeroMemory(cng->rgbKeyObject, WINCNG_KEY_OBJECT_SIZE(ctx));
+
+    return 1;
+}
+
+static int
+wincng_cipher_algorithm_init(EVP_CIPHER *cipher,
+                            LPWSTR pszAlgId)
+{
+    BCRYPT_ALG_HANDLE hAlgorithm = NULL;
+    NTSTATUS status;
+    LPCWSTR pszChainingMode;
+    ULONG cbKeyObject, cbChainingMode, cbData;
+
+    if (cipher->app_data)
+       return 1;
+
+    status = BCryptOpenAlgorithmProvider(&hAlgorithm,
+                                        pszAlgId,
+                                        NULL,
+                                        0);
+    if (!BCRYPT_SUCCESS(status))
+       return 0;
+
+    status = BCryptGetProperty(hAlgorithm,
+                              BCRYPT_OBJECT_LENGTH,
+                              (PUCHAR)&cbKeyObject,
+                              sizeof(ULONG),
+                              &cbData,
+                              0);
+    if (!BCRYPT_SUCCESS(status)) {
+       BCryptCloseAlgorithmProvider(hAlgorithm, 0);
+       return 0;
+    }
+
+    cipher->ctx_size = sizeof(struct wincng_key) + cbKeyObject - 1;
+
+    switch (cipher->flags & EVP_CIPH_MODE) {
+    case EVP_CIPH_CBC_MODE:
+       pszChainingMode = BCRYPT_CHAIN_MODE_CBC;
+       cbChainingMode = sizeof(BCRYPT_CHAIN_MODE_CBC);
+       break;
+    case EVP_CIPH_CFB8_MODE:
+       pszChainingMode = BCRYPT_CHAIN_MODE_CFB;
+       cbChainingMode = sizeof(BCRYPT_CHAIN_MODE_CFB);
+       break;
+    default:
+       pszChainingMode = NULL;
+       cbChainingMode = 0;
+       break;
+    }
+
+    if (cbChainingMode) {
+       status = BCryptSetProperty(hAlgorithm,
+                                  BCRYPT_CHAINING_MODE,
+                                  (PUCHAR)pszChainingMode,
+                                  cbChainingMode,
+                                  0);
+       if (!BCRYPT_SUCCESS(status)) {
+           BCryptCloseAlgorithmProvider(hAlgorithm, 0);
+           return 0;
+       }
+    }
+
+    if (wcscmp(pszAlgId, BCRYPT_RC2_ALGORITHM) == 0) {
+       ULONG cbEffectiveKeyLength = EVP_CIPHER_key_length(cipher) * 8;
+
+       status = BCryptSetProperty(hAlgorithm,
+                                  BCRYPT_EFFECTIVE_KEY_LENGTH,
+                                  (PUCHAR)&cbEffectiveKeyLength,
+                                  sizeof(cbEffectiveKeyLength),
+                                  0);
+       if (!BCRYPT_SUCCESS(status)) {
+           BCryptCloseAlgorithmProvider(hAlgorithm, 0);
+           return 0;
+       }
+    }
+
+    InterlockedCompareExchangePointerRelease(&cipher->app_data,
+                                            hAlgorithm, NULL);
+    return 1;
+}
+
+static int
+wincng_key_init(EVP_CIPHER_CTX *ctx,
+               const unsigned char *key,
+               const unsigned char *iv,
+               int encp)
+{
+    struct wincng_key *cng = ctx->cipher_data;
+    NTSTATUS status;
+
+    assert(cng != NULL);
+    assert(ctx->cipher != NULL);
+
+    if (ctx->cipher->app_data == NULL)
+       return 0;
+
+    /*
+     * Note: ctx->key_len not EVP_CIPHER_CTX_key_length() for
+     * variable length key support.
+     */
+    status = BCryptGenerateSymmetricKey(ctx->cipher->app_data,
+                                       &cng->hKey,
+                                       cng->rgbKeyObject,
+                                       WINCNG_KEY_OBJECT_SIZE(ctx),
+                                       (PUCHAR)key,
+                                       ctx->key_len,
+                                       0);
+
+    return BCRYPT_SUCCESS(status);
+}
+
+#define WINCNG_CIPHER_ALGORITHM(name, alg_id, block_size, key_len,      \
+                               iv_len, flags)                          \
+                                                                       \
+    static EVP_CIPHER                                                  \
+    wincng_##name = {                                                  \
+       0,                                                              \
+       block_size,                                                     \
+       key_len,                                                        \
+       iv_len,                                                         \
+       flags,                                                          \
+       wincng_key_init,                                                \
+       wincng_do_cipher,                                               \
+       wincng_cleanup,                                                 \
+       0,                                                              \
+       NULL,                                                           \
+       NULL,                                                           \
+       NULL,                                                           \
+       NULL                                                            \
+    };                                                                 \
+                                                                       \
+    const EVP_CIPHER *                                                 \
+    hc_EVP_wincng_##name(void)                                         \
+    {                                                                  \
+       wincng_cipher_algorithm_init(&wincng_##name, alg_id);           \
+       return wincng_##name.app_data ? &wincng_##name : NULL;          \
+    }
+
+#define WINCNG_CIPHER_ALGORITHM_CLEANUP(name) do {                     \
+       if (wincng_##name.app_data) {                                   \
+           BCryptCloseAlgorithmProvider(wincng_##name.app_data, 0);    \
+           wincng_##name.app_data = NULL;                              \
+       }                                                               \
+    } while (0)
+
+#define WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(name)                      \
+                                                                       \
+    const EVP_CIPHER *                                                 \
+    hc_EVP_wincng_##name(void)                                         \
+    {                                                                  \
+       return NULL;                                                    \
+    }
+
+/**
+ * The tripple DES cipher type (Windows CNG provider)
+ *
+ * @return the DES-EDE3-CBC EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(des_ede3_cbc,
+                       BCRYPT_3DES_ALGORITHM,
+                       8,
+                       24,
+                       8,
+                       EVP_CIPH_CBC_MODE);
+
+/**
+ * The DES cipher type (Windows CNG provider)
+ *
+ * @return the DES-CBC EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(des_cbc,
+                       BCRYPT_DES_ALGORITHM,
+                       8,
+                       8,
+                       8,
+                       EVP_CIPH_CBC_MODE);
+
+/**
+ * The AES-128 cipher type (Windows CNG provider)
+ *
+ * @return the AES-128-CBC EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(aes_128_cbc,
+                       BCRYPT_AES_ALGORITHM,
+                       16,
+                       16,
+                       16,
+                       EVP_CIPH_CBC_MODE);
+
+/**
+ * The AES-192 cipher type (Windows CNG provider)
+ *
+ * @return the AES-192-CBC EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(aes_192_cbc,
+                       BCRYPT_AES_ALGORITHM,
+                       16,
+                       24,
+                       16,
+                       EVP_CIPH_CBC_MODE);
+
+/**
+ * The AES-256 cipher type (Windows CNG provider)
+ *
+ * @return the AES-256-CBC EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(aes_256_cbc,
+                       BCRYPT_AES_ALGORITHM,
+                       16,
+                       32,
+                       16,
+                       EVP_CIPH_CBC_MODE);
+
+/**
+ * The AES-128 CFB8 cipher type (Windows CNG provider)
+ *
+ * @return the AES-128-CFB8 EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(aes_128_cfb8,
+                       BCRYPT_AES_ALGORITHM,
+                       16,
+                       16,
+                       16,
+                       EVP_CIPH_CFB8_MODE);
+
+/**
+ * The AES-192 CFB8 cipher type (Windows CNG provider)
+ *
+ * @return the AES-192-CFB8 EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(aes_192_cfb8,
+                       BCRYPT_AES_ALGORITHM,
+                       16,
+                       24,
+                       16,
+                       EVP_CIPH_CFB8_MODE);
+
+/**
+ * The AES-256 CFB8 cipher type (Windows CNG provider)
+ *
+ * @return the AES-256-CFB8 EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(aes_256_cfb8,
+                       BCRYPT_AES_ALGORITHM,
+                       16,
+                       32,
+                       16,
+                       EVP_CIPH_CFB8_MODE);
+
+/**
+ * The RC2 cipher type - Windows CNG
+ *
+ * @return the RC2 EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(rc2_cbc,
+                       BCRYPT_RC2_ALGORITHM,
+                       8,
+                       16,
+                       8,
+                       EVP_CIPH_CBC_MODE);
+
+/**
+ * The RC2-40 cipher type - Windows CNG
+ *
+ * @return the RC2-40 EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(rc2_40_cbc,
+                       BCRYPT_RC2_ALGORITHM,
+                       8,
+                       5,
+                       8,
+                       EVP_CIPH_CBC_MODE);
+
+/**
+ * The RC2-64 cipher type - Windows CNG
+ *
+ * @return the RC2-64 EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(rc2_64_cbc,
+                       BCRYPT_RC2_ALGORITHM,
+                       8,
+                       8,
+                       8,
+                       EVP_CIPH_CBC_MODE);
+
+/**
+ * The Camellia-128 cipher type - CommonCrypto
+ *
+ * @return the Camellia-128 EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_128_cbc);
+
+/**
+ * The Camellia-198 cipher type - CommonCrypto
+ *
+ * @return the Camellia-198 EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_192_cbc);
+
+/**
+ * The Camellia-256 cipher type - CommonCrypto
+ *
+ * @return the Camellia-256 EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_256_cbc);
+
+/**
+ * The RC4 cipher type (Windows CNG provider)
+ *
+ * @return the RC4 EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(rc4,
+                       BCRYPT_RC4_ALGORITHM,
+                       1,
+                       16,
+                       0,
+                       EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH);
+
+/**
+ * The RC4-40 cipher type (Windows CNG provider)
+ *
+ * @return the RC4 EVP_CIPHER pointer.
+ *
+ * @ingroup hcrypto_evp
+ */
+
+WINCNG_CIPHER_ALGORITHM(rc4_40,
+                       BCRYPT_RC4_ALGORITHM,
+                       1,
+                       5,
+                       0,
+                       EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH);
+
+static void
+wincng_cipher_algorithm_cleanup(void)
+{
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(des_ede3_cbc);
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(des_cbc);
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_128_cbc);
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_192_cbc);
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_256_cbc);
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_128_cfb8);
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_192_cfb8);
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_256_cfb8);
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_cbc);
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_40_cbc);
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_64_cbc);
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(rc4);
+    WINCNG_CIPHER_ALGORITHM_CLEANUP(rc4_40);
+}
+
+/*
+ * CNG digest provider
+ */
+
+struct wincng_md_ctx {
+    BCRYPT_HASH_HANDLE hHash;
+    ULONG cbHashObject;
+    UCHAR rgbHashObject[1];
+};
+
+static BCRYPT_ALG_HANDLE
+wincng_md_algorithm_init(EVP_MD *md,
+                        LPCWSTR pszAlgId)
+{
+    BCRYPT_ALG_HANDLE hAlgorithm;
+    NTSTATUS status;
+    ULONG cbHashObject, cbData;
+    ULONG cbHash = 0, cbBlock = 0;
+
+    status = BCryptOpenAlgorithmProvider(&hAlgorithm,
+                                        pszAlgId,
+                                        NULL,
+                                        0);
+    if (!BCRYPT_SUCCESS(status))
+       return NULL;
+
+    status = BCryptGetProperty(hAlgorithm,
+                              BCRYPT_HASH_LENGTH,
+                              (PUCHAR)&cbHash,
+                              sizeof(ULONG),
+                              &cbData,
+                              0);
+    if (!BCRYPT_SUCCESS(status)) {
+       BCryptCloseAlgorithmProvider(hAlgorithm, 0);
+       return NULL;
+    }
+
+    status = BCryptGetProperty(hAlgorithm,
+                              BCRYPT_HASH_BLOCK_LENGTH,
+                              (PUCHAR)&cbBlock,
+                              sizeof(ULONG),
+                              &cbData,
+                              0);
+    if (!BCRYPT_SUCCESS(status)) {
+       BCryptCloseAlgorithmProvider(hAlgorithm, 0);
+       return NULL;
+    }
+
+    status = BCryptGetProperty(hAlgorithm,
+                              BCRYPT_OBJECT_LENGTH,
+                              (PUCHAR)&cbHashObject,
+                              sizeof(ULONG),
+                              &cbData,
+                              0);
+    if (!BCRYPT_SUCCESS(status)) {
+       BCryptCloseAlgorithmProvider(hAlgorithm, 0);
+       return NULL;
+    }
+
+    md->hash_size = cbHash;
+    md->block_size = cbBlock;
+    md->ctx_size = sizeof(struct wincng_md_ctx) + cbHashObject - 1;
+
+    return hAlgorithm;
+}
+
+static int
+wincng_md_hash_init(BCRYPT_ALG_HANDLE hAlgorithm,
+                   EVP_MD_CTX *ctx)
+{
+    struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
+    NTSTATUS status;
+    ULONG cbData;
+
+    status = BCryptGetProperty(hAlgorithm,
+                              BCRYPT_OBJECT_LENGTH,
+                              (PUCHAR)&cng->cbHashObject,
+                              sizeof(ULONG),
+                              &cbData,
+                              0);
+    if (!BCRYPT_SUCCESS(status))
+       return 0;
+    status = BCryptCreateHash(hAlgorithm,
+                             &cng->hHash,
+                             cng->rgbHashObject,
+                             cng->cbHashObject,
+                             NULL,
+                             0,
+                             0);
+
+    return BCRYPT_SUCCESS(status);
+}
+
+static int
+wincng_md_update(EVP_MD_CTX *ctx,
+                const void *data,
+                size_t length)
+{
+    struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
+    NTSTATUS status;
+
+    status = BCryptHashData(cng->hHash, (PUCHAR)data, length, 0);
+
+    return BCRYPT_SUCCESS(status);
+}
+
+static int
+wincng_md_final(void *digest,
+               EVP_MD_CTX *ctx)
+{
+    struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
+    NTSTATUS status;
+    ULONG cbHash, cbData;
+
+    status = BCryptGetProperty(cng->hHash,
+                              BCRYPT_HASH_LENGTH,
+                              (PUCHAR)&cbHash,
+                              sizeof(DWORD),
+                              &cbData,
+                              0);
+    if (!BCRYPT_SUCCESS(status))
+       return 0;
+
+    status = BCryptFinishHash(cng->hHash,
+                             digest,
+                             cbHash,
+                             0);
+
+    return BCRYPT_SUCCESS(status);
+}
+
+static int
+wincng_md_cleanup(EVP_MD_CTX *ctx)
+{
+    struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
+
+    if (cng->hHash)
+       BCryptDestroyHash(cng->hHash);
+    SecureZeroMemory(cng->rgbHashObject, cng->cbHashObject);
+
+    return 1;
+}
+
+#define WINCNG_MD_ALGORITHM(name, alg_id)                              \
+                                                                       \
+    static BCRYPT_ALG_HANDLE wincng_hAlgorithm_##name;                 \
+                                                                       \
+    static int wincng_##name##_init(EVP_MD_CTX *ctx)                   \
+    {                                                                  \
+       return wincng_md_hash_init(wincng_hAlgorithm_##name, ctx);      \
+    }                                                                  \
+                                                                       \
+    const EVP_MD *                                                     \
+    hc_EVP_wincng_##name(void)                                         \
+    {                                                                  \
+       static struct hc_evp_md name = {                                \
+           0,                                                          \
+           0,                                                          \
+           0,                                                          \
+           wincng_##name##_init,                                       \
+           wincng_md_update,                                           \
+           wincng_md_final,                                            \
+           wincng_md_cleanup                                           \
+       };                                                              \
+                                                                       \
+       if (wincng_hAlgorithm_##name == NULL) {                         \
+           BCRYPT_ALG_HANDLE hAlgorithm =                              \
+               wincng_md_algorithm_init(&name, alg_id);                \
+           InterlockedCompareExchangePointerRelease(                   \
+               &wincng_hAlgorithm_##name, hAlgorithm, NULL);           \
+       }                                                               \
+       return wincng_hAlgorithm_##name ? &name : NULL;                 \
+    }
+
+#define WINCNG_MD_ALGORITHM_CLEANUP(name) do {                         \
+       if (wincng_hAlgorithm_##name) {                                 \
+           BCryptCloseAlgorithmProvider(wincng_hAlgorithm_##name, 0);  \
+           wincng_hAlgorithm_##name = NULL;                            \
+       }                                                               \
+    } while (0)
+
+WINCNG_MD_ALGORITHM(md2,    BCRYPT_MD2_ALGORITHM);
+WINCNG_MD_ALGORITHM(md4,    BCRYPT_MD4_ALGORITHM);
+WINCNG_MD_ALGORITHM(md5,    BCRYPT_MD5_ALGORITHM);
+WINCNG_MD_ALGORITHM(sha1,   BCRYPT_SHA1_ALGORITHM);
+WINCNG_MD_ALGORITHM(sha256, BCRYPT_SHA256_ALGORITHM);
+WINCNG_MD_ALGORITHM(sha384, BCRYPT_SHA384_ALGORITHM);
+WINCNG_MD_ALGORITHM(sha512, BCRYPT_SHA512_ALGORITHM);
+
+static void
+wincng_md_algorithm_cleanup(void)
+{
+    WINCNG_MD_ALGORITHM_CLEANUP(md2);
+    WINCNG_MD_ALGORITHM_CLEANUP(md4);
+    WINCNG_MD_ALGORITHM_CLEANUP(md5);
+    WINCNG_MD_ALGORITHM_CLEANUP(sha1);
+    WINCNG_MD_ALGORITHM_CLEANUP(sha256);
+    WINCNG_MD_ALGORITHM_CLEANUP(sha384);
+    WINCNG_MD_ALGORITHM_CLEANUP(sha512);
+}
+
+void _hc_wincng_cleanup(void)
+{
+    wincng_md_algorithm_cleanup();
+    wincng_cipher_algorithm_cleanup();
+}
+
+#endif /* NTDDI_VERSION >= NTDDI_VISTA */
diff --git a/lib/hcrypto/evp-wincng.h b/lib/hcrypto/evp-wincng.h
new file mode 100644 (file)
index 0000000..ed7037a
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, Secure Endpoints Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifndef HEIM_EVP_WINCNG_H
+#define HEIM_EVP_WINCNG_H 1
+
+/* symbol renaming */
+#define EVP_wincng_md2() EVP_wincng_md2()
+#define EVP_wincng_md4() EVP_wincng_md4()
+#define EVP_wincng_md5() EVP_wincng_md5()
+#define EVP_wincng_sha1() EVP_wincng_sha1()
+#define EVP_wincng_sha256() EVP_wincng_sha256()
+#define EVP_wincng_sha384() EVP_wincng_sha384()
+#define EVP_wincng_sha512() EVP_wincng_sha512()
+#define EVP_wincng_des_cbc() EVP_wincng_des_cbc()
+#define EVP_wincng_des_ede3_cbc() EVP_wincng_des_ede3_cbc()
+#define EVP_wincng_aes_128_cbc() EVP_wincng_aes_128_cbc()
+#define EVP_wincng_aes_192_cbc() EVP_wincng_aes_192_cbc()
+#define EVP_wincng_aes_256_cbc() EVP_wincng_aes_256_cbc()
+#define EVP_wincng_aes_128_cfb8() EVP_wincng_aes_128_cfb8()
+#define EVP_wincng_aes_192_cfb8() EVP_wincng_aes_192_cfb8()
+#define EVP_wincng_aes_256_cfb8() EVP_wincng_aes_256_cfb8()
+#define EVP_wincng_rc4() EVP_wincng_rc4()
+#define EVP_wincng_rc4_40() EVP_wincng_rc4_40()
+#define EVP_wincng_rc2_40_cbc() EVP_wincng_rc2_40_cbc()
+#define EVP_wincng_rc2_64_cbc() EVP_wincng_rc2_64_cbc()
+#define EVP_wincng_rc2_cbc() EVP_wincng_rc2_cbc()
+#define EVP_wincng_camellia_128_cbc() EVP_wincng_camellia_128_cbc()
+#define EVP_wincng_camellia_192_cbc() EVP_wincng_camellia_192_cbc()
+#define EVP_wincng_camellia_256_cbc() EVP_wincng_camellia_256_cbc()
+
+/*
+ *
+ */
+
+HC_CPP_BEGIN
+
+const EVP_MD * hc_EVP_wincng_md2(void);
+const EVP_MD * hc_EVP_wincng_md4(void);
+const EVP_MD * hc_EVP_wincng_md5(void);
+const EVP_MD * hc_EVP_wincng_sha1(void);
+const EVP_MD * hc_EVP_wincng_sha256(void);
+const EVP_MD * hc_EVP_wincng_sha384(void);
+const EVP_MD * hc_EVP_wincng_sha512(void);
+
+const EVP_CIPHER * hc_EVP_wincng_rc2_cbc(void);
+const EVP_CIPHER * hc_EVP_wincng_rc2_40_cbc(void);
+const EVP_CIPHER * hc_EVP_wincng_rc2_64_cbc(void);
+
+const EVP_CIPHER * hc_EVP_wincng_rc4(void);
+const EVP_CIPHER * hc_EVP_wincng_rc4_40(void);
+
+const EVP_CIPHER * hc_EVP_wincng_des_cbc(void);
+const EVP_CIPHER * hc_EVP_wincng_des_ede3_cbc(void);
+
+const EVP_CIPHER * hc_EVP_wincng_aes_128_cbc(void);
+const EVP_CIPHER * hc_EVP_wincng_aes_192_cbc(void);
+const EVP_CIPHER * hc_EVP_wincng_aes_256_cbc(void);
+
+const EVP_CIPHER * hc_EVP_wincng_aes_128_cfb8(void);
+const EVP_CIPHER * hc_EVP_wincng_aes_192_cfb8(void);
+const EVP_CIPHER * hc_EVP_wincng_aes_256_cfb8(void);
+
+void _hc_wincng_cleanup(void);
+
+HC_CPP_END
+
+#endif /* HEIM_EVP_WINCNG_H */
index 75eefc49312e3acbf241e2eb591939280c9239bc..c564353e4232edd9dc52f907a3e42847a37b162f 100644 (file)
@@ -47,6 +47,7 @@
 #include <evp.h>
 #include <evp-hcrypto.h>
 #include <evp-cc.h>
+#include <evp-w32.h>
 
 #include <krb5-types.h>
 #include <roken.h>
@@ -175,10 +176,13 @@ EVP_MD_CTX_destroy(EVP_MD_CTX *ctx)
 int
 EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) HC_DEPRECATED
 {
-    if (ctx->md && ctx->md->cleanup)
-       (ctx->md->cleanup)(ctx);
-    else if (ctx->md)
+    if (ctx->md && ctx->md->cleanup) {
+       int ret = (ctx->md->cleanup)(ctx);
+       if (!ret)
+           return ret;
+    } else if (ctx->md) {
        memset(ctx->ptr, 0, ctx->md->ctx_size);
+    }
     ctx->md = NULL;
     ctx->engine = NULL;
     free(ctx->ptr);
@@ -258,8 +262,7 @@ EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, ENGINE *engine)
        if (ctx->ptr == NULL)
            return 0;
     }
-    (ctx->md->init)(ctx->ptr);
-    return 1;
+    return (ctx->md->init)(ctx->ptr);
 }
 
 /**
@@ -582,8 +585,11 @@ EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *c)
 int
 EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c)
 {
-    if (c->cipher && c->cipher->cleanup)
-       c->cipher->cleanup(c);
+    if (c->cipher && c->cipher->cleanup) {
+       int ret = c->cipher->cleanup(c);
+       if (!ret)
+           return ret;
+    }
     if (c->cipher_data) {
        memset(c->cipher_data, 0, c->cipher->ctx_size);
        free(c->cipher_data);
@@ -814,7 +820,7 @@ EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *c, ENGINE *engine,
     }
 
     if (key || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT))
-       ctx->cipher->init(ctx, key, iv, encp);
+       return ctx->cipher->init(ctx, key, iv, encp);
 
     return 1;
 }
index a7208f9319fc6162fbac88622a32740562d49e94..6fc728614ef48e39c48a4dbfee5873b3ba478a7f 100644 (file)
@@ -175,6 +175,26 @@ EXPORTS
 ;!     hc_EVP_cc_aes_192_cfb8
 ;!     hc_EVP_cc_aes_256_cfb8
 
+       hc_EVP_w32crypto_md2            ;!
+       hc_EVP_w32crypto_md4            ;!
+       hc_EVP_w32crypto_md5            ;!
+       hc_EVP_w32crypto_sha1           ;!
+       hc_EVP_w32crypto_sha256         ;!
+       hc_EVP_w32crypto_sha384         ;!
+       hc_EVP_w32crypto_sha512         ;!
+       hc_EVP_w32crypto_des_ede3_cbc   ;!
+       hc_EVP_w32crypto_aes_128_cbc    ;!
+       hc_EVP_w32crypto_aes_192_cbc    ;!
+       hc_EVP_w32crypto_aes_256_cbc    ;!
+       hc_EVP_w32crypto_rc2_40_cbc     ;!
+       hc_EVP_w32crypto_rc2_cbc        ;!
+       hc_EVP_w32crypto_rc4            ;!
+       hc_EVP_w32crypto_rc4_40         ;!
+
+       hc_EVP_w32crypto_aes_128_cfb8   ;!
+       hc_EVP_w32crypto_aes_192_cfb8   ;!
+       hc_EVP_w32crypto_aes_256_cfb8   ;!
+
        hc_EVP_hcrypto_md2
        hc_EVP_hcrypto_md4
        hc_EVP_hcrypto_md5
@@ -284,6 +304,7 @@ EXPORTS
        hc_EVP_CIPHER_CTX_ctrl
        hc_EVP_CIPHER_CTX_rand_key
        hc_EVP_CIPHER_CTX_set_key_length
+       hc_EVP_hcrypto_rc2_cbc
        hc_EVP_hcrypto_rc2_40_cbc
        hc_EVP_hcrypto_camellia_128_cbc
        hc_EVP_CipherUpdate
index b6517a63190dba98104ed0ee91ab04c37ca3eb03..58075765e615a6bf9332901002a60768a23fd822 100644 (file)
@@ -57,10 +57,11 @@ static const unsigned char subst[256] = {
   31, 26, 219, 153, 141, 51, 159, 17, 131, 20
 };
 
-void
+int
 MD2_Init (struct md2 *m)
 {
     memset(m, 0, sizeof(*m));
+    return 1;
 }
 
 static void
@@ -91,7 +92,7 @@ calc(struct md2 *m, const void *v)
     memset(x, 0, sizeof(x));
 }
 
-void
+int
 MD2_Update (struct md2 *m, const void *v, size_t len)
 {
     size_t idx = m->len & 0xf;
@@ -114,9 +115,10 @@ MD2_Update (struct md2 *m, const void *v, size_t len)
     }
 
     memcpy(m->data + idx, p, len);
+    return 1;
 }
 
-void
+int
 MD2_Final (void *res, struct md2 *m)
 {
     unsigned char pad[16];
@@ -131,4 +133,5 @@ MD2_Final (void *res, struct md2 *m)
 
     memcpy(res, m->state, MD2_DIGEST_LENGTH);
     memset(m, 0, sizeof(*m));
+    return 1;
 }
index af765060aa53f09d8a35ef0e24a8e49d4ef7332b..d82334eac94832745be04108f6155fd62fe1dbf9 100644 (file)
@@ -56,8 +56,8 @@ struct md2 {
 
 typedef struct md2 MD2_CTX;
 
-void MD2_Init (struct md2 *m);
-void MD2_Update (struct md2 *m, const void *p, size_t len);
-void MD2_Final (void *res, struct md2 *m);
+int MD2_Init (struct md2 *m);
+int MD2_Update (struct md2 *m, const void *p, size_t len);
+int MD2_Final (void *res, struct md2 *m);
 
 #endif /* HEIM_MD2_H */
index 1a9f77fed250ef45c9bec0924febf6861ac58dd0..7617d9af5ef5d59adb967fb19132aeb162224a42 100644 (file)
@@ -42,7 +42,7 @@
 #define D m->counter[3]
 #define X data
 
-void
+int
 MD4_Init (struct md4 *m)
 {
   m->sz[0] = 0;
@@ -51,6 +51,7 @@ MD4_Init (struct md4 *m)
   C = 0x98badcfe;
   B = 0xefcdab89;
   A = 0x67452301;
+  return 1;
 }
 
 #define F(x,y,z) CRAYFIX((x & y) | (~x & z))
@@ -170,7 +171,7 @@ struct x32{
   unsigned int b:32;
 };
 
-void
+int
 MD4_Update (struct md4 *m, const void *v, size_t len)
 {
     const unsigned char *p = v;
@@ -203,9 +204,10 @@ MD4_Update (struct md4 *m, const void *v, size_t len)
            offset = 0;
        }
     }
+    return 1;
 }
 
-void
+int
 MD4_Final (void *res, struct md4 *m)
 {
   unsigned char zeros[72];
@@ -243,4 +245,5 @@ MD4_Final (void *res, struct md4 *m)
       r[i] = swap_uint32_t (m->counter[i]);
   }
 #endif
+  return 1;
 }
index ce17d0f0885bc1797c601700f7f82e559098ce4c..06575c5c34a7be809af67043d0b2ba7632f1a1a3 100644 (file)
@@ -55,8 +55,8 @@ struct md4 {
 
 typedef struct md4 MD4_CTX;
 
-void MD4_Init (struct md4 *m);
-void MD4_Update (struct md4 *m, const void *p, size_t len);
-void MD4_Final (void *res, struct md4 *m);
+int MD4_Init (struct md4 *m);
+int MD4_Update (struct md4 *m, const void *p, size_t len);
+int MD4_Final (void *res, struct md4 *m);
 
 #endif /* HEIM_MD4_H */
index aa0bab46327234b50b7e529944914d31aad08226..cf8219dcd7b170ce00e483742ce78c78f1217551 100644 (file)
@@ -42,7 +42,7 @@
 #define D m->counter[3]
 #define X data
 
-void
+int
 MD5_Init (struct md5 *m)
 {
   m->sz[0] = 0;
@@ -51,6 +51,7 @@ MD5_Init (struct md5 *m)
   C = 0x98badcfe;
   B = 0xefcdab89;
   A = 0x67452301;
+  return 1;
 }
 
 #define F(x,y,z) CRAYFIX((x & y) | (~x & z))
@@ -194,7 +195,7 @@ struct x32{
   unsigned int b:32;
 };
 
-void
+int
 MD5_Update (struct md5 *m, const void *v, size_t len)
 {
   const unsigned char *p = v;
@@ -227,9 +228,10 @@ MD5_Update (struct md5 *m, const void *v, size_t len)
       offset = 0;
     }
   }
+  return 1;
 }
 
-void
+int
 MD5_Final (void *res, struct md5 *m)
 {
   unsigned char zeros[72];
@@ -267,4 +269,5 @@ MD5_Final (void *res, struct md5 *m)
       r[i] = swap_uint32_t (m->counter[i]);
   }
 #endif
+    return 1;
 }
index b2df6e56fcd2cf033fe9903d65445c830f414d17..ab1ac3540bc3545b4d0f2b64cfa23df2e52ae93e 100644 (file)
@@ -55,8 +55,8 @@ struct md5 {
 
 typedef struct md5 MD5_CTX;
 
-void MD5_Init (struct md5 *m);
-void MD5_Update (struct md5 *m, const void *p, size_t len);
-void MD5_Final (void *res, struct md5 *m); /* uint32_t res[4] */
+int MD5_Init (struct md5 *m);
+int MD5_Update (struct md5 *m, const void *p, size_t len);
+int MD5_Final (void *res, struct md5 *m); /* uint32_t res[4] */
 
 #endif /* HEIM_MD5_H */
index 9c8b39e2419006ad51b7bfef27ffaa54294ac32a..0f8f53a332b2e7004f88a32b15f433ed0d67a017 100644 (file)
@@ -43,7 +43,7 @@
 #define E m->counter[4]
 #define X data
 
-void
+int
 SHA1_Init (struct sha *m)
 {
   m->sz[0] = 0;
@@ -53,6 +53,7 @@ SHA1_Init (struct sha *m)
   C = 0x98badcfe;
   D = 0x10325476;
   E = 0xc3d2e1f0;
+  return 1;
 }
 
 
@@ -220,7 +221,7 @@ struct x32{
   unsigned int b:32;
 };
 
-void
+int
 SHA1_Update (struct sha *m, const void *v, size_t len)
 {
   const unsigned char *p = v;
@@ -253,9 +254,10 @@ SHA1_Update (struct sha *m, const void *v, size_t len)
       offset = 0;
     }
   }
+  return 1;
 }
 
-void
+int
 SHA1_Final (void *res, struct sha *m)
 {
   unsigned char zeros[72];
@@ -293,4 +295,5 @@ SHA1_Final (void *res, struct sha *m)
       r[i] = swap_uint32_t (m->counter[i]);
   }
 #endif
+  return 1;
 }
index fbc1810b4aee875b55984b0d417d3695f7a1eacc..59d72408c579eec4a547f48e04d3f2769aee9bf3 100644 (file)
@@ -64,9 +64,9 @@ struct sha {
 
 typedef struct sha SHA_CTX;
 
-void SHA1_Init (struct sha *m);
-void SHA1_Update (struct sha *m, const void *v, size_t len);
-void SHA1_Final (void *res, struct sha *m);
+int SHA1_Init (struct sha *m);
+int SHA1_Update (struct sha *m, const void *v, size_t len);
+int SHA1_Final (void *res, struct sha *m);
 
 /*
  * SHA-2 256
@@ -82,9 +82,9 @@ struct hc_sha256state {
 
 typedef struct hc_sha256state SHA256_CTX;
 
-void SHA256_Init (SHA256_CTX *);
-void SHA256_Update (SHA256_CTX *, const void *, size_t);
-void SHA256_Final (void *, SHA256_CTX *);
+int SHA256_Init (SHA256_CTX *);
+int SHA256_Update (SHA256_CTX *, const void *, size_t);
+int SHA256_Final (void *, SHA256_CTX *);
 
 /*
  * SHA-2 512
@@ -100,16 +100,16 @@ struct hc_sha512state {
 
 typedef struct hc_sha512state SHA512_CTX;
 
-void SHA512_Init (SHA512_CTX *);
-void SHA512_Update (SHA512_CTX *, const void *, size_t);
-void SHA512_Final (void *, SHA512_CTX *);
+int SHA512_Init (SHA512_CTX *);
+int SHA512_Update (SHA512_CTX *, const void *, size_t);
+int SHA512_Final (void *, SHA512_CTX *);
 
 #define SHA384_DIGEST_LENGTH 48
 
 typedef struct hc_sha512state SHA384_CTX;
 
-void SHA384_Init (SHA384_CTX *);
-void SHA384_Update (SHA384_CTX *, const void *, size_t);
-void SHA384_Final (void *, SHA384_CTX *);
+int SHA384_Init (SHA384_CTX *);
+int SHA384_Update (SHA384_CTX *, const void *, size_t);
+int SHA384_Final (void *, SHA384_CTX *);
 
 #endif /* HEIM_SHA_H */
index 108afdccc800548b962344d4f862b83c9152216e..221e832c292a023f83cb68dbc68ea0e6f1a25942 100644 (file)
@@ -74,7 +74,7 @@ static const uint32_t constant_256[64] = {
     0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
 };
 
-void
+int
 SHA256_Init (SHA256_CTX *m)
 {
     m->sz[0] = 0;
@@ -87,6 +87,7 @@ SHA256_Init (SHA256_CTX *m)
     F = 0x9b05688c;
     G = 0x1f83d9ab;
     H = 0x5be0cd19;
+    return 1;
 }
 
 static void
@@ -162,7 +163,7 @@ struct x32{
     unsigned int b:32;
 };
 
-void
+int
 SHA256_Update (SHA256_CTX *m, const void *v, size_t len)
 {
     const unsigned char *p = v;
@@ -195,9 +196,10 @@ SHA256_Update (SHA256_CTX *m, const void *v, size_t len)
            offset = 0;
        }
     }
+    return 1;
 }
 
-void
+int
 SHA256_Final (void *res, SHA256_CTX *m)
 {
     unsigned char zeros[72];
@@ -226,4 +228,5 @@ SHA256_Final (void *res, SHA256_CTX *m)
            r[4*i]   = (m->counter[i] >> 24) & 0xFF;
        }
     }
+    return 1;
 }
index 4bea21666852940bf27010c57bf5de2722f2fb43..bf079b39a4183187901e61547cc23e374628ef83 100644 (file)
@@ -98,7 +98,7 @@ static const uint64_t constant_512[80] = {
     0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
 };
 
-void
+int
 SHA512_Init (SHA512_CTX *m)
 {
     m->sz[0] = 0;
@@ -111,6 +111,7 @@ SHA512_Init (SHA512_CTX *m)
     F = 0x9b05688c2b3e6c1fULL;
     G = 0x1f83d9abfb41bd6bULL;
     H = 0x5be0cd19137e2179ULL;
+    return 1;
 }
 
 static void
@@ -184,7 +185,7 @@ struct x64{
 };
 #endif
 
-void
+int
 SHA512_Update (SHA512_CTX *m, const void *v, size_t len)
 {
     const unsigned char *p = v;
@@ -217,9 +218,10 @@ SHA512_Update (SHA512_CTX *m, const void *v, size_t len)
            offset = 0;
        }
     }
+    return 1;
 }
 
-void
+int
 SHA512_Final (void *res, SHA512_CTX *m)
 {
     unsigned char zeros[128 + 16];
@@ -261,9 +263,10 @@ SHA512_Final (void *res, SHA512_CTX *m)
            r[8*i]   = (m->counter[i] >> 56) & 0xFF;
        }
     }
+    return 1;
 }
 
-void
+int
 SHA384_Init(SHA384_CTX *m)
 {
     m->sz[0] = 0;
@@ -276,19 +279,22 @@ SHA384_Init(SHA384_CTX *m)
     F = 0x8eb44a8768581511ULL;
     G = 0xdb0c2e0d64f98fa7ULL;
     H = 0x47b5481dbefa4fa4ULL;
+    return 1;
 }
 
-void
+int
 SHA384_Update (SHA384_CTX *m, const void *v, size_t len)
 {
     SHA512_Update(m, v, len);
+    return 1;
 }
 
-void
+int
 SHA384_Final (void *res, SHA384_CTX *m)
 {
     unsigned char data[SHA512_DIGEST_LENGTH];
     SHA512_Final(data, m);
     memcpy(res, data, SHA384_DIGEST_LENGTH);
+    return 1;
 }
 
diff --git a/lib/hcrypto/test_bulk.c b/lib/hcrypto/test_bulk.c
new file mode 100644 (file)
index 0000000..6e87ef0
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getarg.h>
+#include <roken.h>
+
+#include <evp.h>
+#include <evp-hcrypto.h>
+#include <evp-cc.h>
+#include <evp-w32.h>
+#include <hex.h>
+#include <err.h>
+
+#ifdef WIN32
+#define STATS_START(M)                                                      \
+        LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;        \
+        LARGE_INTEGER Frequency;                                            \
+                                                                            \
+        QueryPerformanceFrequency(&Frequency);                              \
+        QueryPerformanceCounter(&StartingTime);
+
+#define STATS_END(M)                                                        \
+        QueryPerformanceCounter(&EndingTime);                               \
+        ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart; \
+        ElapsedMicroseconds.QuadPart *= 1000000;                            \
+        ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;                 \
+                                                                            \
+        M += (ElapsedMicroseconds.QuadPart - M) / (i + 1);
+#else
+#define STATS_START(M)                                                      \
+        struct timeval StartingTime, EndingTime;                            \
+                                                                            \
+        gettimeofday(&StartingTime, NULL);
+
+#define STATS_END(M)                                                        \
+        gettimeofday(&EndingTime, NULL);                                    \
+        timevalsub(&EndingTime, &StartingTime);                             \
+        M += (EndingTime.tv_sec * 1000000 + EndingTime.tv_usec - M) / (i + 1);
+#endif
+
+static int version_flag;
+static int help_flag;
+static int len = 1;
+static int loops = 20;
+static char *provider = "hcrypto";
+static unsigned char *d;
+
+#ifdef __APPLE__
+#define PROVIDER_USAGE "hcrypto|cc"
+#elif defined(WIN32)
+#define PROVIDER_USAGE "hcrypto|w32crypto"
+#else
+#define PROVIDER_USAGE "hcrypto"
+#endif
+
+static struct getargs args[] = {
+    { "provider",      0,      arg_string,     &provider,
+      "crypto provider", PROVIDER_USAGE },
+    { "loops",         0,      arg_integer,    &loops,
+      "number of loops",       "loops" },
+    { "size",  0,      arg_integer,    &len,
+      "size (KB)", NULL },
+    { "version",       0,      arg_flag,       &version_flag,
+      "print version", NULL },
+    { "help",          0,      arg_flag,       &help_flag,
+      NULL,    NULL }
+};
+
+static void
+usage (int ret)
+{
+    arg_printusage (args,
+                   sizeof(args)/sizeof(*args),
+                   NULL,
+                   "");
+    exit (ret);
+}
+
+static int
+test_bulk_cipher(const char *cname, const EVP_CIPHER *c)
+{
+    static unsigned char key[16];
+    static unsigned char iv[16];
+    int i;
+    int64_t M = 0;
+
+    for (i = 0; i < loops; i++) {
+        EVP_CIPHER_CTX ectx;
+        EVP_CIPHER_CTX dctx;
+
+        STATS_START(M)
+
+        EVP_CIPHER_CTX_init(&ectx);
+        EVP_CIPHER_CTX_init(&dctx);
+
+        if (EVP_CipherInit_ex(&ectx, c, NULL, NULL, NULL, 1) != 1)
+           errx(1, "can't init encrypt");
+        if (EVP_CipherInit_ex(&dctx, c, NULL, NULL, NULL, 0) != 1)
+           errx(1, "can't init decrypt");
+
+        EVP_CIPHER_CTX_set_key_length(&ectx, sizeof(key));
+        EVP_CIPHER_CTX_set_key_length(&dctx, sizeof(key));
+
+        if (EVP_CipherInit_ex(&ectx, NULL, NULL, key, iv, 1) != 1)
+           errx(1, "can't init encrypt");
+        if (EVP_CipherInit_ex(&dctx, NULL, NULL, key, iv, 0) != 1)
+           errx(1, "can't init decrypt");
+
+        if (!EVP_Cipher(&ectx, d, d, len))
+           errx(1, "can't encrypt");
+        if (!EVP_Cipher(&dctx, d, d, len))
+           errx(1, "can't decrypt");
+
+        EVP_CIPHER_CTX_cleanup(&ectx);
+        EVP_CIPHER_CTX_cleanup(&dctx);
+
+        STATS_END(M);
+
+       if (d[0] != 0x00 || d[len - 1] != ((len - 1) & 0xff))
+           errx(1, "encrypt/decrypt inconsistent");
+    }
+
+    printf("%s: mean time %llu usec%s\n", cname, M, (M == 1) ? "" : "s");
+
+    return 0;
+}
+
+static int
+test_bulk_digest(const char *cname, const EVP_MD *md)
+{
+    char digest[EVP_MAX_MD_SIZE];
+    int i;
+    unsigned int tmp = sizeof(digest);
+    int64_t M = 0;
+
+    for (i = 0; i < loops; i++) {
+        STATS_START(M);
+        EVP_Digest(d, len, digest, &tmp, md, NULL);
+        STATS_END(M);
+    }
+
+    printf("%s: mean time %llu usec%s\n", cname, M, (M == 1) ? "" : "s");
+
+    return 0;
+}
+
+static void
+test_bulk_provider_hcrypto(void)
+{
+    test_bulk_cipher("hcrypto_aes_256_cbc",    EVP_hcrypto_aes_256_cbc());
+#if 0
+    test_bulk_cipher("hcrypto_aes_256_cfb8",   EVP_hcrypto_aes_256_cfb8());
+#endif
+    test_bulk_cipher("hcrypto_rc4",            EVP_hcrypto_rc4());
+    test_bulk_digest("hcrypto_md2",            EVP_hcrypto_md2());
+    test_bulk_digest("hcrypto_md4",            EVP_hcrypto_md4());
+    test_bulk_digest("hcrypto_md5",            EVP_hcrypto_md5());
+    test_bulk_digest("hcrypto_sha1",           EVP_hcrypto_sha1());
+    test_bulk_digest("hcrypto_sha256",         EVP_hcrypto_sha256());
+    test_bulk_digest("hcrypto_sha384",         EVP_hcrypto_sha384());
+    test_bulk_digest("hcrypto_sha512",         EVP_hcrypto_sha512());
+}
+
+#ifdef __APPLE__
+static void
+test_bulk_provider_cc(void)
+{
+    test_bulk_cipher("cc_aes_256_cbc",         EVP_cc_aes_256_cbc());
+#if 0
+    test_bulk_cipher("cc_aes_256_cfb8",                EVP_cc_aes_256_cfb8());
+#endif
+    test_bulk_cipher("cc_rc4",                 EVP_cc_rc4());
+    test_bulk_digest("cc_md2",                 EVP_cc_md2());
+    test_bulk_digest("cc_md4",                 EVP_cc_md4());
+    test_bulk_digest("cc_md5",                 EVP_cc_md5());
+    test_bulk_digest("cc_sha1",                        EVP_cc_sha1());
+    test_bulk_digest("cc_sha256",              EVP_cc_sha256());
+}
+#endif /* __APPLE__ */
+
+#ifdef WIN32
+static void
+test_bulk_provider_w32crypto(void)
+{
+    test_bulk_cipher("w32crypto_aes_256_cbc",  EVP_w32crypto_aes_256_cbc());
+#if 0
+    test_bulk_cipher("w32crypto_aes_256_cfb8", EVP_w32crypto_aes_256_cfb8());
+#endif
+    test_bulk_cipher("w32crypto_rc4",          EVP_w32crypto_rc4());
+    test_bulk_digest("w32crypto_md2",          EVP_w32crypto_md2());
+    test_bulk_digest("w32crypto_md4",          EVP_w32crypto_md4());
+    test_bulk_digest("w32crypto_md5",          EVP_w32crypto_md5());
+    test_bulk_digest("w32crypto_sha1",         EVP_w32crypto_sha1());
+    test_bulk_digest("w32crypto_sha256",       EVP_w32crypto_sha256());
+    test_bulk_digest("w32crypto_sha384",       EVP_w32crypto_sha384());
+    test_bulk_digest("w32crypto_sha512",       EVP_w32crypto_sha512());
+}
+#endif /* WIN32 */
+
+int
+main(int argc, char **argv)
+{
+    int ret = 0;
+    int idx = 0;
+    int i;
+
+    setprogname(argv[0]);
+
+    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &idx))
+       usage(1);
+
+    if (help_flag)
+       usage(0);
+
+    if(version_flag) {
+       print_version(NULL);
+       exit(0);
+    }
+
+    argc -= idx;
+    argv += idx;
+
+    len *= 1024;
+
+    d = emalloc(len);
+    for (i = 0; i < len; i++)
+        d[i] = i & 0xff;
+
+    if (strcmp(provider, "hcrypto") == 0)
+        test_bulk_provider_hcrypto();
+#ifdef __APPLE__
+    else if (strcmp(provider, "cc") == 0)
+        test_bulk_provider_cc();
+#endif
+#ifdef WIN32
+    else if (strcmp(provider, "w32crypto") == 0)
+        test_bulk_provider_w32crypto();
+#endif
+    else
+        usage(1);
+
+    free(d);
+
+    return ret;
+}
index 8075efb3e5301d2f8c35d5d007805c2cf149a2b6..6eb9f3fe5134d7eeea7dee06f8ea542bd48ccc4f 100644 (file)
@@ -46,6 +46,7 @@
 #include <evp.h>
 #include <evp-hcrypto.h>
 #include <evp-cc.h>
+#include <evp-w32.h>
 #include <hex.h>
 #include <err.h>
 
@@ -80,11 +81,25 @@ struct tests aes_cfb_tests[] = {
       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
       16,
       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
-      "\x66\xe9\x4b\xd4\xef\x8a\x2c\x3b\x88\x4c\xfa\x59\xca\x34\x2b\x2e",
+      "\x66\x16\xf9\x2e\x42\xa8\xf1\x1a\x91\x16\x68\x57\x8e\xc3\xaa\x0f",
       NULL
     }
 };
 
+
+struct tests rc2_tests[] = {
+    { "rc2",
+      "\x88\xbc\xa9\x0e\x90\x87\x5a\x7f\x0f\x79\xc3\x84\x62\x7b\xaf\xb2",
+      16,
+      "\x00\x00\x00\x00\x00\x00\x00\x00",
+      8,
+      "\x00\x00\x00\x00\x00\x00\x00\x00",
+      "\x22\x69\x55\x2a\xb0\xf8\x5c\xa6",
+      NULL
+    }
+};
+
+
 struct tests rc2_40_tests[] = {
     { "rc2-40",
       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
@@ -264,7 +279,7 @@ test_cipher(int i, const EVP_CIPHER *c, struct tests *t)
     d = emalloc(t->datasize);
 
     if (!EVP_Cipher(&ectx, d, t->indata, t->datasize))
-       return 1;
+       errx(1, "%s: %d EVP_Cipher encrypt failed", t->name, i);
 
     if (memcmp(d, t->outdata, t->datasize) != 0) {
        char *s, *s2;
@@ -274,7 +289,7 @@ test_cipher(int i, const EVP_CIPHER *c, struct tests *t)
     }
 
     if (!EVP_Cipher(&dctx, d, d, t->datasize))
-       return 1;
+       errx(1, "%s: %d EVP_Cipher decrypt failed", t->name, i);
 
     if (memcmp(d, t->indata, t->datasize) != 0) {
        char *s;
@@ -338,7 +353,8 @@ main(int argc, char **argv)
        ret += test_cipher(i, EVP_hcrypto_aes_256_cbc(), &aes_tests[i]);
     for (i = 0; i < sizeof(aes_cfb_tests)/sizeof(aes_cfb_tests[0]); i++)
        ret += test_cipher(i, EVP_hcrypto_aes_128_cfb8(), &aes_cfb_tests[i]);
-
+    for (i = 0; i < sizeof(rc2_tests)/sizeof(rc2_tests[0]); i++)
+       ret += test_cipher(i, EVP_hcrypto_rc2_cbc(), &rc2_tests[i]);
     for (i = 0; i < sizeof(rc2_40_tests)/sizeof(rc2_40_tests[0]); i++)
        ret += test_cipher(i, EVP_hcrypto_rc2_40_cbc(), &rc2_40_tests[i]);
     for (i = 0; i < sizeof(des_ede3_tests)/sizeof(des_ede3_tests[0]); i++)
@@ -353,10 +369,8 @@ main(int argc, char **argv)
 #ifdef __APPLE__
     for (i = 0; i < sizeof(aes_tests)/sizeof(aes_tests[0]); i++)
        ret += test_cipher(i, EVP_cc_aes_256_cbc(), &aes_tests[i]);
-#if 0
     for (i = 0; i < sizeof(aes_cfb_tests)/sizeof(aes_cfb_tests[0]); i++)
        ret += test_cipher(i, EVP_cc_aes_128_cfb8(), &aes_cfb_tests[i]);
-#endif
     for (i = 0; i < sizeof(rc2_40_tests)/sizeof(rc2_40_tests[0]); i++)
        ret += test_cipher(i, EVP_cc_rc2_40_cbc(), &rc2_40_tests[i]);
     for (i = 0; i < sizeof(des_ede3_tests)/sizeof(des_ede3_tests[0]); i++)
@@ -366,7 +380,23 @@ main(int argc, char **argv)
                           &camellia128_tests[i]);
     for (i = 0; i < sizeof(rc4_tests)/sizeof(rc4_tests[0]); i++)
        ret += test_cipher(i, EVP_cc_rc4(), &rc4_tests[i]);
-#endif
+#endif /* __APPLE__ */
+
+    /* Windows CNG (if available) */
+#ifdef WIN32
+    for (i = 0; i < sizeof(aes_tests)/sizeof(aes_tests[0]); i++)
+       ret += test_cipher(i, EVP_w32crypto_aes_256_cbc(), &aes_tests[i]);
+    for (i = 0; i < sizeof(aes_cfb_tests)/sizeof(aes_cfb_tests[0]); i++)
+       ret += test_cipher(i, EVP_w32crypto_aes_128_cfb8(), &aes_cfb_tests[i]);
+    for (i = 0; i < sizeof(rc2_tests)/sizeof(rc2_tests[0]); i++)
+       ret += test_cipher(i, EVP_w32crypto_rc2_cbc(), &rc2_tests[i]);
+    for (i = 0; i < sizeof(rc2_40_tests)/sizeof(rc2_40_tests[0]); i++)
+       ret += test_cipher(i, EVP_w32crypto_rc2_40_cbc(), &rc2_40_tests[i]);
+    for (i = 0; i < sizeof(des_ede3_tests)/sizeof(des_ede3_tests[0]); i++)
+       ret += test_cipher(i, EVP_w32crypto_des_ede3_cbc(), &des_ede3_tests[i]);
+    for (i = 0; i < sizeof(rc4_tests)/sizeof(rc4_tests[0]); i++)
+       ret += test_cipher(i, EVP_w32crypto_rc4(), &rc4_tests[i]);
+#endif /* WIN32 */
 
     return ret;
 }
index 6985d1b9e22683d23c4298966ed7f293218bf6cd..ec202133fdc703d98f84cb2825b887dd2a67f359 100644 (file)
@@ -289,6 +289,7 @@ HEIMDAL_CRYPTO_1.0 {
                hc_EVP_CIPHER_CTX_ctrl;
                hc_EVP_CIPHER_CTX_rand_key;
                hc_EVP_CIPHER_CTX_set_key_length;
+               hc_EVP_hcrypto_rc2_cbc;
                hc_EVP_hcrypto_rc2_40_cbc;
                hc_EVP_hcrypto_camellia_128_cbc;
                hc_EVP_CipherUpdate;
index 39ac7ade8416e53210c326670c4175efb710e9e6..b206cd3a8ba19eea193a1857aa3313c56b5966e1 100644 (file)
@@ -54,6 +54,11 @@ DLLSDKDEPS= \
        dnsapi.lib      \
         shlwapi.lib
 
+dlllflags=$(dlllflags) /DELAYLOAD:bcrypt.dll
+DLLSDKDEPS=$(DLLSDKDEPS)\
+       bcrypt.lib      \
+       delayimp.lib 
+
 DEF=$(OBJ)\heimdal.def
 
 RES=$(OBJ)\heimdal-version.res
index d03df3d29b87c2aedd74e7fafdbe64ddda8df8e4..a4748781676fbd45f2aadbea08d446589c42ef1b 100644 (file)
 
 HINSTANCE _krb5_hInstance = NULL;
 
+#if NTDDI_VERSION >= NTDDI_VISTA
+extern BOOL WINAPI
+_hc_w32crypto_DllMain(HINSTANCE hinstDLL,
+                     DWORD fdwReason,
+                     LPVOID lpvReserved);
+#endif
+
 BOOL WINAPI DllMain(HINSTANCE hinstDLL,
                    DWORD fdwReason,
                    LPVOID lpvReserved)
 {
+#if NTDDI_VERSION >= NTDDI_VISTA
+    BOOL ret;
+
+    ret = _hc_w32crypto_DllMain(hinstDLL, fdwReason, lpvReserved);
+    if (!ret)
+       return ret;
+#endif
+
     switch (fdwReason) {
     case DLL_PROCESS_ATTACH:
 
index c5a3823137be9a7e3bbc167e943324e502168e89..48e6aed260482106fc60c9b585d3dbd92ff9a9bf 100644 (file)
@@ -162,6 +162,8 @@ pthreadinc= -I$(PTHREAD_INC)
 
 cincdirs=$(cincdirs) -I$(INCDIR) -I$(INCDIR)\krb5 $(pthreadinc)
 cdefines=$(cdefines) -DHAVE_CONFIG_H
+# Windows CNG provider
+cdefines=$(cdefines) -DHCRYPTO_DEF_PROVIDER=w32crypto
 cdebug=$(cdebug) /Zi
 ldebug=$(ldebug) /DEBUG
 localcflags=$(localcflags) /Oy-