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