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