Home | History | Annotate | Line # | Download | only in hcrypto
      1 /*	$NetBSD: evp-wincng.c,v 1.4 2023/06/19 21:41:43 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2015, Secure Endpoints Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  *
     11  * - Redistributions of source code must retain the above copyright
     12  *   notice, this list of conditions and the following disclaimer.
     13  *
     14  * - Redistributions in binary form must reproduce the above copyright
     15  *   notice, this list of conditions and the following disclaimer in
     16  *   the documentation and/or other materials provided with the
     17  *   distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     30  * OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /* Windows CNG provider */
     34 
     35 #include <config.h>
     36 #include <krb5/roken.h>
     37 #include <assert.h>
     38 
     39 #include <evp.h>
     40 #include <evp-wincng.h>
     41 
     42 #include <bcrypt.h>
     43 
     44 /*
     45  * CNG cipher provider
     46  */
     47 
     48 struct wincng_key {
     49     BCRYPT_KEY_HANDLE hKey;
     50     UCHAR rgbKeyObject[1];
     51 };
     52 
     53 #define WINCNG_KEY_OBJECT_SIZE(ctx) \
     54 	((ctx)->cipher->ctx_size - sizeof(struct wincng_key) + 1)
     55 
     56 static int
     57 wincng_do_cipher(EVP_CIPHER_CTX *ctx,
     58 		 unsigned char *out,
     59 		 const unsigned char *in,
     60 		 unsigned int size)
     61 {
     62     struct wincng_key *cng = ctx->cipher_data;
     63     NTSTATUS status;
     64     ULONG cbResult;
     65 
     66     assert(EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_STREAM_CIPHER ||
     67 	   (size % ctx->cipher->block_size) == 0);
     68 
     69     if (ctx->encrypt) {
     70 	status = BCryptEncrypt(cng->hKey,
     71 			       (PUCHAR)in,
     72 			       size,
     73 			       NULL, /* pPaddingInfo */
     74 			       ctx->cipher->iv_len ? ctx->iv : NULL,
     75 			       ctx->cipher->iv_len,
     76 			       out,
     77 			       size,
     78 			       &cbResult,
     79 			       0);
     80     } else {
     81 	status = BCryptDecrypt(cng->hKey,
     82 			       (PUCHAR)in,
     83 			       size,
     84 			       NULL, /* pPaddingInfo */
     85 			       ctx->cipher->iv_len ? ctx->iv : NULL,
     86 			       ctx->cipher->iv_len,
     87 			       out,
     88 			       size,
     89 			       &cbResult,
     90 			       0);
     91     }
     92 
     93     return BCRYPT_SUCCESS(status) && cbResult == size;
     94 }
     95 
     96 static int
     97 wincng_cleanup(EVP_CIPHER_CTX *ctx)
     98 {
     99     struct wincng_key *cng = ctx->cipher_data;
    100 
    101     if (cng->hKey)
    102 	BCryptDestroyKey(cng->hKey);
    103     SecureZeroMemory(cng->rgbKeyObject, WINCNG_KEY_OBJECT_SIZE(ctx));
    104 
    105     return 1;
    106 }
    107 
    108 static int
    109 wincng_cipher_algorithm_init(EVP_CIPHER *cipher,
    110 			     LPWSTR pszAlgId)
    111 {
    112     BCRYPT_ALG_HANDLE hAlgorithm = NULL;
    113     NTSTATUS status;
    114     LPCWSTR pszChainingMode;
    115     ULONG cbKeyObject, cbChainingMode, cbData;
    116 
    117     if (cipher->app_data)
    118 	return 1;
    119 
    120     status = BCryptOpenAlgorithmProvider(&hAlgorithm,
    121 					 pszAlgId,
    122 					 NULL,
    123 					 0);
    124     if (!BCRYPT_SUCCESS(status))
    125 	return 0;
    126 
    127     status = BCryptGetProperty(hAlgorithm,
    128 			       BCRYPT_OBJECT_LENGTH,
    129 			       (PUCHAR)&cbKeyObject,
    130 			       sizeof(ULONG),
    131 			       &cbData,
    132 			       0);
    133     if (!BCRYPT_SUCCESS(status)) {
    134 	BCryptCloseAlgorithmProvider(hAlgorithm, 0);
    135 	return 0;
    136     }
    137 
    138     cipher->ctx_size = sizeof(struct wincng_key) + cbKeyObject - 1;
    139 
    140     switch (cipher->flags & EVP_CIPH_MODE) {
    141     case EVP_CIPH_CBC_MODE:
    142 	pszChainingMode = BCRYPT_CHAIN_MODE_CBC;
    143 	cbChainingMode = sizeof(BCRYPT_CHAIN_MODE_CBC);
    144 	break;
    145     case EVP_CIPH_CFB8_MODE:
    146 	pszChainingMode = BCRYPT_CHAIN_MODE_CFB;
    147 	cbChainingMode = sizeof(BCRYPT_CHAIN_MODE_CFB);
    148 	break;
    149     default:
    150 	pszChainingMode = NULL;
    151 	cbChainingMode = 0;
    152 	break;
    153     }
    154 
    155     if (cbChainingMode) {
    156 	status = BCryptSetProperty(hAlgorithm,
    157 				   BCRYPT_CHAINING_MODE,
    158 				   (PUCHAR)pszChainingMode,
    159 				   cbChainingMode,
    160 				   0);
    161 	if (!BCRYPT_SUCCESS(status)) {
    162 	    BCryptCloseAlgorithmProvider(hAlgorithm, 0);
    163 	    return 0;
    164 	}
    165     }
    166 
    167     if (wcscmp(pszAlgId, BCRYPT_RC2_ALGORITHM) == 0) {
    168 	ULONG cbEffectiveKeyLength = EVP_CIPHER_key_length(cipher) * 8;
    169 
    170 	status = BCryptSetProperty(hAlgorithm,
    171 				   BCRYPT_EFFECTIVE_KEY_LENGTH,
    172 				   (PUCHAR)&cbEffectiveKeyLength,
    173 				   sizeof(cbEffectiveKeyLength),
    174 				   0);
    175 	if (!BCRYPT_SUCCESS(status)) {
    176 	    BCryptCloseAlgorithmProvider(hAlgorithm, 0);
    177 	    return 0;
    178 	}
    179     }
    180 
    181     InterlockedCompareExchangePointerRelease(&cipher->app_data,
    182 					     hAlgorithm, NULL);
    183     return 1;
    184 }
    185 
    186 static int
    187 wincng_key_init(EVP_CIPHER_CTX *ctx,
    188 		const unsigned char *key,
    189 		const unsigned char *iv,
    190 		int encp)
    191 {
    192     struct wincng_key *cng = ctx->cipher_data;
    193     NTSTATUS status;
    194 
    195     assert(cng != NULL);
    196     assert(ctx->cipher != NULL);
    197 
    198     if (ctx->cipher->app_data == NULL)
    199 	return 0;
    200 
    201     if (cng->hKey) {
    202 	BCryptDestroyKey(cng->hKey); /* allow reinitialization */
    203 	cng->hKey = (BCRYPT_KEY_HANDLE)0;
    204     }
    205 
    206     /*
    207      * Note: ctx->key_len not EVP_CIPHER_CTX_key_length() for
    208      * variable length key support.
    209      */
    210     status = BCryptGenerateSymmetricKey(ctx->cipher->app_data,
    211 					&cng->hKey,
    212 					cng->rgbKeyObject,
    213 					WINCNG_KEY_OBJECT_SIZE(ctx),
    214 					(PUCHAR)key,
    215 					ctx->key_len,
    216 					0);
    217 
    218     return BCRYPT_SUCCESS(status);
    219 }
    220 
    221 #define WINCNG_CIPHER_ALGORITHM(name, alg_id, block_size, key_len,      \
    222 				iv_len, flags)				\
    223 									\
    224     static EVP_CIPHER							\
    225     wincng_##name = {							\
    226 	0,								\
    227 	block_size,							\
    228 	key_len,							\
    229 	iv_len,								\
    230 	flags,								\
    231 	wincng_key_init,						\
    232 	wincng_do_cipher,						\
    233 	wincng_cleanup,							\
    234 	0,								\
    235 	NULL,								\
    236 	NULL,								\
    237 	NULL,								\
    238 	NULL								\
    239     };									\
    240 									\
    241     const EVP_CIPHER *							\
    242     hc_EVP_wincng_##name(void)						\
    243     {									\
    244 	wincng_cipher_algorithm_init(&wincng_##name, alg_id);		\
    245 	return wincng_##name.app_data ? &wincng_##name : NULL;		\
    246     }
    247 
    248 #define WINCNG_CIPHER_ALGORITHM_CLEANUP(name) do {			\
    249 	if (wincng_##name.app_data) {					\
    250 	    BCryptCloseAlgorithmProvider(wincng_##name.app_data, 0);	\
    251 	    wincng_##name.app_data = NULL;				\
    252 	}								\
    253     } while (0)
    254 
    255 #define WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(name)			\
    256 									\
    257     const EVP_CIPHER *							\
    258     hc_EVP_wincng_##name(void)						\
    259     {									\
    260 	return NULL;							\
    261     }
    262 
    263 /**
    264  * The triple DES cipher type (Windows CNG provider)
    265  *
    266  * @return the DES-EDE3-CBC EVP_CIPHER pointer.
    267  *
    268  * @ingroup hcrypto_evp
    269  */
    270 
    271 WINCNG_CIPHER_ALGORITHM(des_ede3_cbc,
    272 			BCRYPT_3DES_ALGORITHM,
    273 			8,
    274 			24,
    275 			8,
    276 			EVP_CIPH_CBC_MODE);
    277 
    278 /**
    279  * The DES cipher type (Windows CNG provider)
    280  *
    281  * @return the DES-CBC EVP_CIPHER pointer.
    282  *
    283  * @ingroup hcrypto_evp
    284  */
    285 
    286 WINCNG_CIPHER_ALGORITHM(des_cbc,
    287 			BCRYPT_DES_ALGORITHM,
    288 			8,
    289 			8,
    290 			8,
    291 			EVP_CIPH_CBC_MODE);
    292 
    293 /**
    294  * The AES-128 cipher type (Windows CNG provider)
    295  *
    296  * @return the AES-128-CBC EVP_CIPHER pointer.
    297  *
    298  * @ingroup hcrypto_evp
    299  */
    300 
    301 WINCNG_CIPHER_ALGORITHM(aes_128_cbc,
    302 			BCRYPT_AES_ALGORITHM,
    303 			16,
    304 			16,
    305 			16,
    306 			EVP_CIPH_CBC_MODE);
    307 
    308 /**
    309  * The AES-192 cipher type (Windows CNG provider)
    310  *
    311  * @return the AES-192-CBC EVP_CIPHER pointer.
    312  *
    313  * @ingroup hcrypto_evp
    314  */
    315 
    316 WINCNG_CIPHER_ALGORITHM(aes_192_cbc,
    317 			BCRYPT_AES_ALGORITHM,
    318 			16,
    319 			24,
    320 			16,
    321 			EVP_CIPH_CBC_MODE);
    322 
    323 /**
    324  * The AES-256 cipher type (Windows CNG provider)
    325  *
    326  * @return the AES-256-CBC EVP_CIPHER pointer.
    327  *
    328  * @ingroup hcrypto_evp
    329  */
    330 
    331 WINCNG_CIPHER_ALGORITHM(aes_256_cbc,
    332 			BCRYPT_AES_ALGORITHM,
    333 			16,
    334 			32,
    335 			16,
    336 			EVP_CIPH_CBC_MODE);
    337 
    338 /**
    339  * The AES-128 CFB8 cipher type (Windows CNG provider)
    340  *
    341  * @return the AES-128-CFB8 EVP_CIPHER pointer.
    342  *
    343  * @ingroup hcrypto_evp
    344  */
    345 
    346 WINCNG_CIPHER_ALGORITHM(aes_128_cfb8,
    347 			BCRYPT_AES_ALGORITHM,
    348 			16,
    349 			16,
    350 			16,
    351 			EVP_CIPH_CFB8_MODE);
    352 
    353 /**
    354  * The AES-192 CFB8 cipher type (Windows CNG provider)
    355  *
    356  * @return the AES-192-CFB8 EVP_CIPHER pointer.
    357  *
    358  * @ingroup hcrypto_evp
    359  */
    360 
    361 WINCNG_CIPHER_ALGORITHM(aes_192_cfb8,
    362 			BCRYPT_AES_ALGORITHM,
    363 			16,
    364 			24,
    365 			16,
    366 			EVP_CIPH_CFB8_MODE);
    367 
    368 /**
    369  * The AES-256 CFB8 cipher type (Windows CNG provider)
    370  *
    371  * @return the AES-256-CFB8 EVP_CIPHER pointer.
    372  *
    373  * @ingroup hcrypto_evp
    374  */
    375 
    376 WINCNG_CIPHER_ALGORITHM(aes_256_cfb8,
    377 			BCRYPT_AES_ALGORITHM,
    378 			16,
    379 			32,
    380 			16,
    381 			EVP_CIPH_CFB8_MODE);
    382 
    383 /**
    384  * The RC2 cipher type - Windows CNG
    385  *
    386  * @return the RC2 EVP_CIPHER pointer.
    387  *
    388  * @ingroup hcrypto_evp
    389  */
    390 
    391 WINCNG_CIPHER_ALGORITHM(rc2_cbc,
    392 			BCRYPT_RC2_ALGORITHM,
    393 			8,
    394 			16,
    395 			8,
    396 			EVP_CIPH_CBC_MODE);
    397 
    398 /**
    399  * The RC2-40 cipher type - Windows CNG
    400  *
    401  * @return the RC2-40 EVP_CIPHER pointer.
    402  *
    403  * @ingroup hcrypto_evp
    404  */
    405 
    406 WINCNG_CIPHER_ALGORITHM(rc2_40_cbc,
    407 			BCRYPT_RC2_ALGORITHM,
    408 			8,
    409 			5,
    410 			8,
    411 			EVP_CIPH_CBC_MODE);
    412 
    413 /**
    414  * The RC2-64 cipher type - Windows CNG
    415  *
    416  * @return the RC2-64 EVP_CIPHER pointer.
    417  *
    418  * @ingroup hcrypto_evp
    419  */
    420 
    421 WINCNG_CIPHER_ALGORITHM(rc2_64_cbc,
    422 			BCRYPT_RC2_ALGORITHM,
    423 			8,
    424 			8,
    425 			8,
    426 			EVP_CIPH_CBC_MODE);
    427 
    428 /**
    429  * The Camellia-128 cipher type - CommonCrypto
    430  *
    431  * @return the Camellia-128 EVP_CIPHER pointer.
    432  *
    433  * @ingroup hcrypto_evp
    434  */
    435 
    436 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_128_cbc);
    437 
    438 /**
    439  * The Camellia-198 cipher type - CommonCrypto
    440  *
    441  * @return the Camellia-198 EVP_CIPHER pointer.
    442  *
    443  * @ingroup hcrypto_evp
    444  */
    445 
    446 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_192_cbc);
    447 
    448 /**
    449  * The Camellia-256 cipher type - CommonCrypto
    450  *
    451  * @return the Camellia-256 EVP_CIPHER pointer.
    452  *
    453  * @ingroup hcrypto_evp
    454  */
    455 
    456 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_256_cbc);
    457 
    458 /**
    459  * The RC4 cipher type (Windows CNG provider)
    460  *
    461  * @return the RC4 EVP_CIPHER pointer.
    462  *
    463  * @ingroup hcrypto_evp
    464  */
    465 
    466 WINCNG_CIPHER_ALGORITHM(rc4,
    467 			BCRYPT_RC4_ALGORITHM,
    468 			1,
    469 			16,
    470 			0,
    471 			EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH);
    472 
    473 /**
    474  * The RC4-40 cipher type (Windows CNG provider)
    475  *
    476  * @return the RC4 EVP_CIPHER pointer.
    477  *
    478  * @ingroup hcrypto_evp
    479  */
    480 
    481 WINCNG_CIPHER_ALGORITHM(rc4_40,
    482 			BCRYPT_RC4_ALGORITHM,
    483 			1,
    484 			5,
    485 			0,
    486 			EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH);
    487 
    488 static void
    489 wincng_cipher_algorithm_cleanup(void)
    490 {
    491     WINCNG_CIPHER_ALGORITHM_CLEANUP(des_ede3_cbc);
    492     WINCNG_CIPHER_ALGORITHM_CLEANUP(des_cbc);
    493     WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_128_cbc);
    494     WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_192_cbc);
    495     WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_256_cbc);
    496     WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_128_cfb8);
    497     WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_192_cfb8);
    498     WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_256_cfb8);
    499     WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_cbc);
    500     WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_40_cbc);
    501     WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_64_cbc);
    502     WINCNG_CIPHER_ALGORITHM_CLEANUP(rc4);
    503     WINCNG_CIPHER_ALGORITHM_CLEANUP(rc4_40);
    504 }
    505 
    506 /*
    507  * CNG digest provider
    508  */
    509 
    510 struct wincng_md_ctx {
    511     BCRYPT_HASH_HANDLE hHash;
    512     ULONG cbHashObject;
    513     UCHAR rgbHashObject[1];
    514 };
    515 
    516 static BCRYPT_ALG_HANDLE
    517 wincng_md_algorithm_init(EVP_MD *md,
    518 			 LPCWSTR pszAlgId)
    519 {
    520     BCRYPT_ALG_HANDLE hAlgorithm;
    521     NTSTATUS status;
    522     ULONG cbHashObject, cbData;
    523     ULONG cbHash = 0, cbBlock = 0;
    524 
    525     status = BCryptOpenAlgorithmProvider(&hAlgorithm,
    526 					 pszAlgId,
    527 					 NULL,
    528 					 0);
    529     if (!BCRYPT_SUCCESS(status))
    530 	return NULL;
    531 
    532     status = BCryptGetProperty(hAlgorithm,
    533 			       BCRYPT_HASH_LENGTH,
    534 			       (PUCHAR)&cbHash,
    535 			       sizeof(ULONG),
    536 			       &cbData,
    537 			       0);
    538     if (!BCRYPT_SUCCESS(status)) {
    539 	BCryptCloseAlgorithmProvider(hAlgorithm, 0);
    540 	return NULL;
    541     }
    542 
    543     status = BCryptGetProperty(hAlgorithm,
    544 			       BCRYPT_HASH_BLOCK_LENGTH,
    545 			       (PUCHAR)&cbBlock,
    546 			       sizeof(ULONG),
    547 			       &cbData,
    548 			       0);
    549     if (!BCRYPT_SUCCESS(status)) {
    550 	BCryptCloseAlgorithmProvider(hAlgorithm, 0);
    551 	return NULL;
    552     }
    553 
    554     status = BCryptGetProperty(hAlgorithm,
    555 			       BCRYPT_OBJECT_LENGTH,
    556 			       (PUCHAR)&cbHashObject,
    557 			       sizeof(ULONG),
    558 			       &cbData,
    559 			       0);
    560     if (!BCRYPT_SUCCESS(status)) {
    561 	BCryptCloseAlgorithmProvider(hAlgorithm, 0);
    562 	return NULL;
    563     }
    564 
    565     md->hash_size = cbHash;
    566     md->block_size = cbBlock;
    567     md->ctx_size = sizeof(struct wincng_md_ctx) + cbHashObject - 1;
    568 
    569     return hAlgorithm;
    570 }
    571 
    572 static int
    573 wincng_md_hash_init(BCRYPT_ALG_HANDLE hAlgorithm,
    574 		    EVP_MD_CTX *ctx)
    575 {
    576     struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
    577     NTSTATUS status;
    578     ULONG cbData;
    579 
    580     if (cng->hHash) {
    581 	BCryptDestroyHash(cng->hHash); /* allow reinitialization */
    582 	cng->hHash = (BCRYPT_HASH_HANDLE)0;
    583     }
    584 
    585     status = BCryptGetProperty(hAlgorithm,
    586 			       BCRYPT_OBJECT_LENGTH,
    587 			       (PUCHAR)&cng->cbHashObject,
    588 			       sizeof(ULONG),
    589 			       &cbData,
    590 			       0);
    591     if (!BCRYPT_SUCCESS(status))
    592 	return 0;
    593 
    594     status = BCryptCreateHash(hAlgorithm,
    595 			      &cng->hHash,
    596 			      cng->rgbHashObject,
    597 			      cng->cbHashObject,
    598 			      NULL,
    599 			      0,
    600 			      0);
    601 
    602     return BCRYPT_SUCCESS(status);
    603 }
    604 
    605 static int
    606 wincng_md_update(EVP_MD_CTX *ctx,
    607 		 const void *data,
    608 		 size_t length)
    609 {
    610     struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
    611     NTSTATUS status;
    612 
    613     status = BCryptHashData(cng->hHash, (PUCHAR)data, length, 0);
    614 
    615     return BCRYPT_SUCCESS(status);
    616 }
    617 
    618 static int
    619 wincng_md_final(void *digest,
    620 		EVP_MD_CTX *ctx)
    621 {
    622     struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
    623     NTSTATUS status;
    624     ULONG cbHash, cbData;
    625 
    626     status = BCryptGetProperty(cng->hHash,
    627 			       BCRYPT_HASH_LENGTH,
    628 			       (PUCHAR)&cbHash,
    629 			       sizeof(DWORD),
    630 			       &cbData,
    631 			       0);
    632     if (!BCRYPT_SUCCESS(status))
    633 	return 0;
    634 
    635     status = BCryptFinishHash(cng->hHash,
    636 			      digest,
    637 			      cbHash,
    638 			      0);
    639 
    640     return BCRYPT_SUCCESS(status);
    641 }
    642 
    643 static int
    644 wincng_md_cleanup(EVP_MD_CTX *ctx)
    645 {
    646     struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
    647 
    648     if (cng->hHash)
    649 	BCryptDestroyHash(cng->hHash);
    650     SecureZeroMemory(cng->rgbHashObject, cng->cbHashObject);
    651 
    652     return 1;
    653 }
    654 
    655 #define WINCNG_MD_ALGORITHM(name, alg_id)				\
    656 									\
    657     static BCRYPT_ALG_HANDLE wincng_hAlgorithm_##name;			\
    658 									\
    659     static int wincng_##name##_init(EVP_MD_CTX *ctx)			\
    660     {									\
    661 	return wincng_md_hash_init(wincng_hAlgorithm_##name, ctx);	\
    662     }									\
    663 									\
    664     const EVP_MD *							\
    665     hc_EVP_wincng_##name(void)						\
    666     {									\
    667 	static struct hc_evp_md name = {				\
    668 	    0,								\
    669 	    0,								\
    670 	    0,								\
    671 	    wincng_##name##_init,					\
    672 	    wincng_md_update,						\
    673 	    wincng_md_final,						\
    674 	    wincng_md_cleanup						\
    675 	};								\
    676 									\
    677 	if (wincng_hAlgorithm_##name == NULL) {				\
    678 	    BCRYPT_ALG_HANDLE hAlgorithm =				\
    679 		wincng_md_algorithm_init(&name, alg_id);		\
    680 	    InterlockedCompareExchangePointerRelease(			\
    681 		&wincng_hAlgorithm_##name, hAlgorithm, NULL);		\
    682 	}								\
    683 	return wincng_hAlgorithm_##name ? &name : NULL;			\
    684     }
    685 
    686 #define WINCNG_MD_ALGORITHM_CLEANUP(name) do {				\
    687 	if (wincng_hAlgorithm_##name) {					\
    688 	    BCryptCloseAlgorithmProvider(wincng_hAlgorithm_##name, 0);	\
    689 	    wincng_hAlgorithm_##name = NULL;				\
    690 	}								\
    691     } while (0)
    692 
    693 WINCNG_MD_ALGORITHM(md4,    BCRYPT_MD4_ALGORITHM);
    694 WINCNG_MD_ALGORITHM(md5,    BCRYPT_MD5_ALGORITHM);
    695 WINCNG_MD_ALGORITHM(sha1,   BCRYPT_SHA1_ALGORITHM);
    696 WINCNG_MD_ALGORITHM(sha256, BCRYPT_SHA256_ALGORITHM);
    697 WINCNG_MD_ALGORITHM(sha384, BCRYPT_SHA384_ALGORITHM);
    698 WINCNG_MD_ALGORITHM(sha512, BCRYPT_SHA512_ALGORITHM);
    699 
    700 static void
    701 wincng_md_algorithm_cleanup(void)
    702 {
    703     WINCNG_MD_ALGORITHM_CLEANUP(md4);
    704     WINCNG_MD_ALGORITHM_CLEANUP(md5);
    705     WINCNG_MD_ALGORITHM_CLEANUP(sha1);
    706     WINCNG_MD_ALGORITHM_CLEANUP(sha256);
    707     WINCNG_MD_ALGORITHM_CLEANUP(sha384);
    708     WINCNG_MD_ALGORITHM_CLEANUP(sha512);
    709 }
    710 
    711 void _hc_wincng_cleanup(void)
    712 {
    713     wincng_md_algorithm_cleanup();
    714     wincng_cipher_algorithm_cleanup();
    715 }
    716