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