xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/hcrypto/evp-wincng.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: evp-wincng.c,v 1.2 2017/01/28 21:31:47 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     /*
202      * Note: ctx->key_len not EVP_CIPHER_CTX_key_length() for
203      * variable length key support.
204      */
205     status = BCryptGenerateSymmetricKey(ctx->cipher->app_data,
206 					&cng->hKey,
207 					cng->rgbKeyObject,
208 					WINCNG_KEY_OBJECT_SIZE(ctx),
209 					(PUCHAR)key,
210 					ctx->key_len,
211 					0);
212 
213     return BCRYPT_SUCCESS(status);
214 }
215 
216 #define WINCNG_CIPHER_ALGORITHM(name, alg_id, block_size, key_len,      \
217 				iv_len, flags)				\
218 									\
219     static EVP_CIPHER							\
220     wincng_##name = {							\
221 	0,								\
222 	block_size,							\
223 	key_len,							\
224 	iv_len,								\
225 	flags,								\
226 	wincng_key_init,						\
227 	wincng_do_cipher,						\
228 	wincng_cleanup,							\
229 	0,								\
230 	NULL,								\
231 	NULL,								\
232 	NULL,								\
233 	NULL								\
234     };									\
235 									\
236     const EVP_CIPHER *							\
237     hc_EVP_wincng_##name(void)						\
238     {									\
239 	wincng_cipher_algorithm_init(&wincng_##name, alg_id);		\
240 	return wincng_##name.app_data ? &wincng_##name : NULL;		\
241     }
242 
243 #define WINCNG_CIPHER_ALGORITHM_CLEANUP(name) do {			\
244 	if (wincng_##name.app_data) {					\
245 	    BCryptCloseAlgorithmProvider(wincng_##name.app_data, 0);	\
246 	    wincng_##name.app_data = NULL;				\
247 	}								\
248     } while (0)
249 
250 #define WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(name)			\
251 									\
252     const EVP_CIPHER *							\
253     hc_EVP_wincng_##name(void)						\
254     {									\
255 	return NULL;							\
256     }
257 
258 /**
259  * The triple DES cipher type (Windows CNG provider)
260  *
261  * @return the DES-EDE3-CBC EVP_CIPHER pointer.
262  *
263  * @ingroup hcrypto_evp
264  */
265 
266 WINCNG_CIPHER_ALGORITHM(des_ede3_cbc,
267 			BCRYPT_3DES_ALGORITHM,
268 			8,
269 			24,
270 			8,
271 			EVP_CIPH_CBC_MODE);
272 
273 /**
274  * The DES cipher type (Windows CNG provider)
275  *
276  * @return the DES-CBC EVP_CIPHER pointer.
277  *
278  * @ingroup hcrypto_evp
279  */
280 
281 WINCNG_CIPHER_ALGORITHM(des_cbc,
282 			BCRYPT_DES_ALGORITHM,
283 			8,
284 			8,
285 			8,
286 			EVP_CIPH_CBC_MODE);
287 
288 /**
289  * The AES-128 cipher type (Windows CNG provider)
290  *
291  * @return the AES-128-CBC EVP_CIPHER pointer.
292  *
293  * @ingroup hcrypto_evp
294  */
295 
296 WINCNG_CIPHER_ALGORITHM(aes_128_cbc,
297 			BCRYPT_AES_ALGORITHM,
298 			16,
299 			16,
300 			16,
301 			EVP_CIPH_CBC_MODE);
302 
303 /**
304  * The AES-192 cipher type (Windows CNG provider)
305  *
306  * @return the AES-192-CBC EVP_CIPHER pointer.
307  *
308  * @ingroup hcrypto_evp
309  */
310 
311 WINCNG_CIPHER_ALGORITHM(aes_192_cbc,
312 			BCRYPT_AES_ALGORITHM,
313 			16,
314 			24,
315 			16,
316 			EVP_CIPH_CBC_MODE);
317 
318 /**
319  * The AES-256 cipher type (Windows CNG provider)
320  *
321  * @return the AES-256-CBC EVP_CIPHER pointer.
322  *
323  * @ingroup hcrypto_evp
324  */
325 
326 WINCNG_CIPHER_ALGORITHM(aes_256_cbc,
327 			BCRYPT_AES_ALGORITHM,
328 			16,
329 			32,
330 			16,
331 			EVP_CIPH_CBC_MODE);
332 
333 /**
334  * The AES-128 CFB8 cipher type (Windows CNG provider)
335  *
336  * @return the AES-128-CFB8 EVP_CIPHER pointer.
337  *
338  * @ingroup hcrypto_evp
339  */
340 
341 WINCNG_CIPHER_ALGORITHM(aes_128_cfb8,
342 			BCRYPT_AES_ALGORITHM,
343 			16,
344 			16,
345 			16,
346 			EVP_CIPH_CFB8_MODE);
347 
348 /**
349  * The AES-192 CFB8 cipher type (Windows CNG provider)
350  *
351  * @return the AES-192-CFB8 EVP_CIPHER pointer.
352  *
353  * @ingroup hcrypto_evp
354  */
355 
356 WINCNG_CIPHER_ALGORITHM(aes_192_cfb8,
357 			BCRYPT_AES_ALGORITHM,
358 			16,
359 			24,
360 			16,
361 			EVP_CIPH_CFB8_MODE);
362 
363 /**
364  * The AES-256 CFB8 cipher type (Windows CNG provider)
365  *
366  * @return the AES-256-CFB8 EVP_CIPHER pointer.
367  *
368  * @ingroup hcrypto_evp
369  */
370 
371 WINCNG_CIPHER_ALGORITHM(aes_256_cfb8,
372 			BCRYPT_AES_ALGORITHM,
373 			16,
374 			32,
375 			16,
376 			EVP_CIPH_CFB8_MODE);
377 
378 /**
379  * The RC2 cipher type - Windows CNG
380  *
381  * @return the RC2 EVP_CIPHER pointer.
382  *
383  * @ingroup hcrypto_evp
384  */
385 
386 WINCNG_CIPHER_ALGORITHM(rc2_cbc,
387 			BCRYPT_RC2_ALGORITHM,
388 			8,
389 			16,
390 			8,
391 			EVP_CIPH_CBC_MODE);
392 
393 /**
394  * The RC2-40 cipher type - Windows CNG
395  *
396  * @return the RC2-40 EVP_CIPHER pointer.
397  *
398  * @ingroup hcrypto_evp
399  */
400 
401 WINCNG_CIPHER_ALGORITHM(rc2_40_cbc,
402 			BCRYPT_RC2_ALGORITHM,
403 			8,
404 			5,
405 			8,
406 			EVP_CIPH_CBC_MODE);
407 
408 /**
409  * The RC2-64 cipher type - Windows CNG
410  *
411  * @return the RC2-64 EVP_CIPHER pointer.
412  *
413  * @ingroup hcrypto_evp
414  */
415 
416 WINCNG_CIPHER_ALGORITHM(rc2_64_cbc,
417 			BCRYPT_RC2_ALGORITHM,
418 			8,
419 			8,
420 			8,
421 			EVP_CIPH_CBC_MODE);
422 
423 /**
424  * The Camellia-128 cipher type - CommonCrypto
425  *
426  * @return the Camellia-128 EVP_CIPHER pointer.
427  *
428  * @ingroup hcrypto_evp
429  */
430 
431 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_128_cbc);
432 
433 /**
434  * The Camellia-198 cipher type - CommonCrypto
435  *
436  * @return the Camellia-198 EVP_CIPHER pointer.
437  *
438  * @ingroup hcrypto_evp
439  */
440 
441 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_192_cbc);
442 
443 /**
444  * The Camellia-256 cipher type - CommonCrypto
445  *
446  * @return the Camellia-256 EVP_CIPHER pointer.
447  *
448  * @ingroup hcrypto_evp
449  */
450 
451 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_256_cbc);
452 
453 /**
454  * The RC4 cipher type (Windows CNG provider)
455  *
456  * @return the RC4 EVP_CIPHER pointer.
457  *
458  * @ingroup hcrypto_evp
459  */
460 
461 WINCNG_CIPHER_ALGORITHM(rc4,
462 			BCRYPT_RC4_ALGORITHM,
463 			1,
464 			16,
465 			0,
466 			EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH);
467 
468 /**
469  * The RC4-40 cipher type (Windows CNG provider)
470  *
471  * @return the RC4 EVP_CIPHER pointer.
472  *
473  * @ingroup hcrypto_evp
474  */
475 
476 WINCNG_CIPHER_ALGORITHM(rc4_40,
477 			BCRYPT_RC4_ALGORITHM,
478 			1,
479 			5,
480 			0,
481 			EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH);
482 
483 static void
484 wincng_cipher_algorithm_cleanup(void)
485 {
486     WINCNG_CIPHER_ALGORITHM_CLEANUP(des_ede3_cbc);
487     WINCNG_CIPHER_ALGORITHM_CLEANUP(des_cbc);
488     WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_128_cbc);
489     WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_192_cbc);
490     WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_256_cbc);
491     WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_128_cfb8);
492     WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_192_cfb8);
493     WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_256_cfb8);
494     WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_cbc);
495     WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_40_cbc);
496     WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_64_cbc);
497     WINCNG_CIPHER_ALGORITHM_CLEANUP(rc4);
498     WINCNG_CIPHER_ALGORITHM_CLEANUP(rc4_40);
499 }
500 
501 /*
502  * CNG digest provider
503  */
504 
505 struct wincng_md_ctx {
506     BCRYPT_HASH_HANDLE hHash;
507     ULONG cbHashObject;
508     UCHAR rgbHashObject[1];
509 };
510 
511 static BCRYPT_ALG_HANDLE
512 wincng_md_algorithm_init(EVP_MD *md,
513 			 LPCWSTR pszAlgId)
514 {
515     BCRYPT_ALG_HANDLE hAlgorithm;
516     NTSTATUS status;
517     ULONG cbHashObject, cbData;
518     ULONG cbHash = 0, cbBlock = 0;
519 
520     status = BCryptOpenAlgorithmProvider(&hAlgorithm,
521 					 pszAlgId,
522 					 NULL,
523 					 0);
524     if (!BCRYPT_SUCCESS(status))
525 	return NULL;
526 
527     status = BCryptGetProperty(hAlgorithm,
528 			       BCRYPT_HASH_LENGTH,
529 			       (PUCHAR)&cbHash,
530 			       sizeof(ULONG),
531 			       &cbData,
532 			       0);
533     if (!BCRYPT_SUCCESS(status)) {
534 	BCryptCloseAlgorithmProvider(hAlgorithm, 0);
535 	return NULL;
536     }
537 
538     status = BCryptGetProperty(hAlgorithm,
539 			       BCRYPT_HASH_BLOCK_LENGTH,
540 			       (PUCHAR)&cbBlock,
541 			       sizeof(ULONG),
542 			       &cbData,
543 			       0);
544     if (!BCRYPT_SUCCESS(status)) {
545 	BCryptCloseAlgorithmProvider(hAlgorithm, 0);
546 	return NULL;
547     }
548 
549     status = BCryptGetProperty(hAlgorithm,
550 			       BCRYPT_OBJECT_LENGTH,
551 			       (PUCHAR)&cbHashObject,
552 			       sizeof(ULONG),
553 			       &cbData,
554 			       0);
555     if (!BCRYPT_SUCCESS(status)) {
556 	BCryptCloseAlgorithmProvider(hAlgorithm, 0);
557 	return NULL;
558     }
559 
560     md->hash_size = cbHash;
561     md->block_size = cbBlock;
562     md->ctx_size = sizeof(struct wincng_md_ctx) + cbHashObject - 1;
563 
564     return hAlgorithm;
565 }
566 
567 static int
568 wincng_md_hash_init(BCRYPT_ALG_HANDLE hAlgorithm,
569 		    EVP_MD_CTX *ctx)
570 {
571     struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
572     NTSTATUS status;
573     ULONG cbData;
574 
575     status = BCryptGetProperty(hAlgorithm,
576 			       BCRYPT_OBJECT_LENGTH,
577 			       (PUCHAR)&cng->cbHashObject,
578 			       sizeof(ULONG),
579 			       &cbData,
580 			       0);
581     if (!BCRYPT_SUCCESS(status))
582 	return 0;
583 
584     status = BCryptCreateHash(hAlgorithm,
585 			      &cng->hHash,
586 			      cng->rgbHashObject,
587 			      cng->cbHashObject,
588 			      NULL,
589 			      0,
590 			      0);
591 
592     return BCRYPT_SUCCESS(status);
593 }
594 
595 static int
596 wincng_md_update(EVP_MD_CTX *ctx,
597 		 const void *data,
598 		 size_t length)
599 {
600     struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
601     NTSTATUS status;
602 
603     status = BCryptHashData(cng->hHash, (PUCHAR)data, length, 0);
604 
605     return BCRYPT_SUCCESS(status);
606 }
607 
608 static int
609 wincng_md_final(void *digest,
610 		EVP_MD_CTX *ctx)
611 {
612     struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
613     NTSTATUS status;
614     ULONG cbHash, cbData;
615 
616     status = BCryptGetProperty(cng->hHash,
617 			       BCRYPT_HASH_LENGTH,
618 			       (PUCHAR)&cbHash,
619 			       sizeof(DWORD),
620 			       &cbData,
621 			       0);
622     if (!BCRYPT_SUCCESS(status))
623 	return 0;
624 
625     status = BCryptFinishHash(cng->hHash,
626 			      digest,
627 			      cbHash,
628 			      0);
629 
630     return BCRYPT_SUCCESS(status);
631 }
632 
633 static int
634 wincng_md_cleanup(EVP_MD_CTX *ctx)
635 {
636     struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
637 
638     if (cng->hHash)
639 	BCryptDestroyHash(cng->hHash);
640     SecureZeroMemory(cng->rgbHashObject, cng->cbHashObject);
641 
642     return 1;
643 }
644 
645 #define WINCNG_MD_ALGORITHM(name, alg_id)				\
646 									\
647     static BCRYPT_ALG_HANDLE wincng_hAlgorithm_##name;			\
648 									\
649     static int wincng_##name##_init(EVP_MD_CTX *ctx)			\
650     {									\
651 	return wincng_md_hash_init(wincng_hAlgorithm_##name, ctx);	\
652     }									\
653 									\
654     const EVP_MD *							\
655     hc_EVP_wincng_##name(void)						\
656     {									\
657 	static struct hc_evp_md name = {				\
658 	    0,								\
659 	    0,								\
660 	    0,								\
661 	    wincng_##name##_init,					\
662 	    wincng_md_update,						\
663 	    wincng_md_final,						\
664 	    wincng_md_cleanup						\
665 	};								\
666 									\
667 	if (wincng_hAlgorithm_##name == NULL) {				\
668 	    BCRYPT_ALG_HANDLE hAlgorithm =				\
669 		wincng_md_algorithm_init(&name, alg_id);		\
670 	    InterlockedCompareExchangePointerRelease(			\
671 		&wincng_hAlgorithm_##name, hAlgorithm, NULL);		\
672 	}								\
673 	return wincng_hAlgorithm_##name ? &name : NULL;			\
674     }
675 
676 #define WINCNG_MD_ALGORITHM_CLEANUP(name) do {				\
677 	if (wincng_hAlgorithm_##name) {					\
678 	    BCryptCloseAlgorithmProvider(wincng_hAlgorithm_##name, 0);	\
679 	    wincng_hAlgorithm_##name = NULL;				\
680 	}								\
681     } while (0)
682 
683 WINCNG_MD_ALGORITHM(md2,    BCRYPT_MD2_ALGORITHM);
684 WINCNG_MD_ALGORITHM(md4,    BCRYPT_MD4_ALGORITHM);
685 WINCNG_MD_ALGORITHM(md5,    BCRYPT_MD5_ALGORITHM);
686 WINCNG_MD_ALGORITHM(sha1,   BCRYPT_SHA1_ALGORITHM);
687 WINCNG_MD_ALGORITHM(sha256, BCRYPT_SHA256_ALGORITHM);
688 WINCNG_MD_ALGORITHM(sha384, BCRYPT_SHA384_ALGORITHM);
689 WINCNG_MD_ALGORITHM(sha512, BCRYPT_SHA512_ALGORITHM);
690 
691 static void
692 wincng_md_algorithm_cleanup(void)
693 {
694     WINCNG_MD_ALGORITHM_CLEANUP(md2);
695     WINCNG_MD_ALGORITHM_CLEANUP(md4);
696     WINCNG_MD_ALGORITHM_CLEANUP(md5);
697     WINCNG_MD_ALGORITHM_CLEANUP(sha1);
698     WINCNG_MD_ALGORITHM_CLEANUP(sha256);
699     WINCNG_MD_ALGORITHM_CLEANUP(sha384);
700     WINCNG_MD_ALGORITHM_CLEANUP(sha512);
701 }
702 
703 void _hc_wincng_cleanup(void)
704 {
705     wincng_md_algorithm_cleanup();
706     wincng_cipher_algorithm_cleanup();
707 }
708