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