xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/hcrypto/evp-wincng.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
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
wincng_do_cipher(EVP_CIPHER_CTX * ctx,unsigned char * out,const unsigned char * in,unsigned int size)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
wincng_cleanup(EVP_CIPHER_CTX * ctx)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
wincng_cipher_algorithm_init(EVP_CIPHER * cipher,LPWSTR pszAlgId)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
wincng_key_init(EVP_CIPHER_CTX * ctx,const unsigned char * key,const unsigned char * iv,int encp)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
wincng_cipher_algorithm_cleanup(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
wincng_md_algorithm_init(EVP_MD * md,LPCWSTR pszAlgId)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
wincng_md_hash_init(BCRYPT_ALG_HANDLE hAlgorithm,EVP_MD_CTX * ctx)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
wincng_md_update(EVP_MD_CTX * ctx,const void * data,size_t length)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
wincng_md_final(void * digest,EVP_MD_CTX * ctx)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
wincng_md_cleanup(EVP_MD_CTX * ctx)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
wincng_md_algorithm_cleanup(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 
_hc_wincng_cleanup(void)711 void _hc_wincng_cleanup(void)
712 {
713     wincng_md_algorithm_cleanup();
714     wincng_cipher_algorithm_cleanup();
715 }
716