2 * Copyright (c) 2015, Secure Endpoints Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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
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.
31 /* Windows CNG provider */
36 #include <versionsupport.h>
39 #include <evp-wincng.h>
43 #ifndef BCRYPT_HASH_REUSABLE_FLAG
44 #define BCRYPT_HASH_REUSABLE_FLAG 0x00000020
52 BCRYPT_KEY_HANDLE hKey;
53 UCHAR rgbKeyObject[1];
56 #define WINCNG_KEY_OBJECT_SIZE(ctx) \
57 ((ctx)->cipher->ctx_size - sizeof(struct wincng_key) + 1)
60 wincng_do_cipher(EVP_CIPHER_CTX *ctx,
62 const unsigned char *in,
65 struct wincng_key *cng = ctx->cipher_data;
69 assert(EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_STREAM_CIPHER ||
70 (size % ctx->cipher->block_size) == 0);
73 status = BCryptEncrypt(cng->hKey,
76 NULL, /* pPaddingInfo */
77 ctx->cipher->iv_len ? ctx->iv : NULL,
84 status = BCryptDecrypt(cng->hKey,
87 NULL, /* pPaddingInfo */
88 ctx->cipher->iv_len ? ctx->iv : NULL,
96 return BCRYPT_SUCCESS(status) && cbResult == size;
100 wincng_cleanup(EVP_CIPHER_CTX *ctx)
102 struct wincng_key *cng = ctx->cipher_data;
105 BCryptDestroyKey(cng->hKey);
106 cng->hKey = (BCRYPT_KEY_HANDLE)0;
108 SecureZeroMemory(cng->rgbKeyObject, WINCNG_KEY_OBJECT_SIZE(ctx));
114 wincng_cipher_algorithm_init(EVP_CIPHER *cipher,
117 BCRYPT_ALG_HANDLE hAlgorithm = NULL;
119 LPCWSTR pszChainingMode;
120 ULONG cbKeyObject, cbChainingMode, cbData;
122 if (cipher->app_data)
125 status = BCryptOpenAlgorithmProvider(&hAlgorithm,
129 if (!BCRYPT_SUCCESS(status))
132 status = BCryptGetProperty(hAlgorithm,
133 BCRYPT_OBJECT_LENGTH,
134 (PUCHAR)&cbKeyObject,
138 if (!BCRYPT_SUCCESS(status)) {
139 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
143 cipher->ctx_size = sizeof(struct wincng_key) + cbKeyObject - 1;
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);
150 case EVP_CIPH_CFB8_MODE:
151 pszChainingMode = BCRYPT_CHAIN_MODE_CFB;
152 cbChainingMode = sizeof(BCRYPT_CHAIN_MODE_CFB);
155 pszChainingMode = NULL;
160 if (cbChainingMode) {
161 status = BCryptSetProperty(hAlgorithm,
162 BCRYPT_CHAINING_MODE,
163 (PUCHAR)pszChainingMode,
166 if (!BCRYPT_SUCCESS(status)) {
167 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
172 if (wcscmp(pszAlgId, BCRYPT_RC2_ALGORITHM) == 0) {
173 ULONG cbEffectiveKeyLength = EVP_CIPHER_key_length(cipher) * 8;
175 status = BCryptSetProperty(hAlgorithm,
176 BCRYPT_EFFECTIVE_KEY_LENGTH,
177 (PUCHAR)&cbEffectiveKeyLength,
178 sizeof(cbEffectiveKeyLength),
180 if (!BCRYPT_SUCCESS(status)) {
181 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
186 InterlockedCompareExchangePointerRelease(&cipher->app_data,
192 wincng_key_init(EVP_CIPHER_CTX *ctx,
193 const unsigned char *key,
194 const unsigned char *iv,
197 struct wincng_key *cng = ctx->cipher_data;
201 assert(ctx->cipher != NULL);
203 if (ctx->cipher->app_data == NULL)
209 * Note: ctx->key_len not EVP_CIPHER_CTX_key_length() for
210 * variable length key support.
212 status = BCryptGenerateSymmetricKey(ctx->cipher->app_data,
215 WINCNG_KEY_OBJECT_SIZE(ctx),
220 return BCRYPT_SUCCESS(status);
223 #define WINCNG_CIPHER_ALGORITHM(name, alg_id, block_size, key_len, \
244 hc_EVP_wincng_##name(void) \
246 wincng_cipher_algorithm_init(&wincng_##name, alg_id); \
247 return wincng_##name.app_data ? &wincng_##name : NULL; \
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; \
257 #define WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(name) \
260 hc_EVP_wincng_##name(void) \
266 * The triple DES cipher type (Windows CNG provider)
268 * @return the DES-EDE3-CBC EVP_CIPHER pointer.
270 * @ingroup hcrypto_evp
273 WINCNG_CIPHER_ALGORITHM(des_ede3_cbc,
274 BCRYPT_3DES_ALGORITHM,
281 * The DES cipher type (Windows CNG provider)
283 * @return the DES-CBC EVP_CIPHER pointer.
285 * @ingroup hcrypto_evp
288 WINCNG_CIPHER_ALGORITHM(des_cbc,
289 BCRYPT_DES_ALGORITHM,
296 * The AES-128 cipher type (Windows CNG provider)
298 * @return the AES-128-CBC EVP_CIPHER pointer.
300 * @ingroup hcrypto_evp
303 WINCNG_CIPHER_ALGORITHM(aes_128_cbc,
304 BCRYPT_AES_ALGORITHM,
311 * The AES-192 cipher type (Windows CNG provider)
313 * @return the AES-192-CBC EVP_CIPHER pointer.
315 * @ingroup hcrypto_evp
318 WINCNG_CIPHER_ALGORITHM(aes_192_cbc,
319 BCRYPT_AES_ALGORITHM,
326 * The AES-256 cipher type (Windows CNG provider)
328 * @return the AES-256-CBC EVP_CIPHER pointer.
330 * @ingroup hcrypto_evp
333 WINCNG_CIPHER_ALGORITHM(aes_256_cbc,
334 BCRYPT_AES_ALGORITHM,
341 * The AES-128 CFB8 cipher type (Windows CNG provider)
343 * @return the AES-128-CFB8 EVP_CIPHER pointer.
345 * @ingroup hcrypto_evp
348 WINCNG_CIPHER_ALGORITHM(aes_128_cfb8,
349 BCRYPT_AES_ALGORITHM,
356 * The AES-192 CFB8 cipher type (Windows CNG provider)
358 * @return the AES-192-CFB8 EVP_CIPHER pointer.
360 * @ingroup hcrypto_evp
363 WINCNG_CIPHER_ALGORITHM(aes_192_cfb8,
364 BCRYPT_AES_ALGORITHM,
371 * The AES-256 CFB8 cipher type (Windows CNG provider)
373 * @return the AES-256-CFB8 EVP_CIPHER pointer.
375 * @ingroup hcrypto_evp
378 WINCNG_CIPHER_ALGORITHM(aes_256_cfb8,
379 BCRYPT_AES_ALGORITHM,
386 * The RC2 cipher type - Windows CNG
388 * @return the RC2 EVP_CIPHER pointer.
390 * @ingroup hcrypto_evp
393 WINCNG_CIPHER_ALGORITHM(rc2_cbc,
394 BCRYPT_RC2_ALGORITHM,
401 * The RC2-40 cipher type - Windows CNG
403 * @return the RC2-40 EVP_CIPHER pointer.
405 * @ingroup hcrypto_evp
408 WINCNG_CIPHER_ALGORITHM(rc2_40_cbc,
409 BCRYPT_RC2_ALGORITHM,
416 * The RC2-64 cipher type - Windows CNG
418 * @return the RC2-64 EVP_CIPHER pointer.
420 * @ingroup hcrypto_evp
423 WINCNG_CIPHER_ALGORITHM(rc2_64_cbc,
424 BCRYPT_RC2_ALGORITHM,
431 * The Camellia-128 cipher type - CommonCrypto
433 * @return the Camellia-128 EVP_CIPHER pointer.
435 * @ingroup hcrypto_evp
438 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_128_cbc);
441 * The Camellia-198 cipher type - CommonCrypto
443 * @return the Camellia-198 EVP_CIPHER pointer.
445 * @ingroup hcrypto_evp
448 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_192_cbc);
451 * The Camellia-256 cipher type - CommonCrypto
453 * @return the Camellia-256 EVP_CIPHER pointer.
455 * @ingroup hcrypto_evp
458 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_256_cbc);
461 * The RC4 cipher type (Windows CNG provider)
463 * @return the RC4 EVP_CIPHER pointer.
465 * @ingroup hcrypto_evp
468 WINCNG_CIPHER_ALGORITHM(rc4,
469 BCRYPT_RC4_ALGORITHM,
473 EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH);
476 * The RC4-40 cipher type (Windows CNG provider)
478 * @return the RC4 EVP_CIPHER pointer.
480 * @ingroup hcrypto_evp
483 WINCNG_CIPHER_ALGORITHM(rc4_40,
484 BCRYPT_RC4_ALGORITHM,
488 EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH);
491 wincng_cipher_algorithm_cleanup(void)
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);
509 * CNG digest provider
512 struct wincng_md_ctx {
513 BCRYPT_HASH_HANDLE hHash;
515 UCHAR rgbHashObject[1];
518 static BCRYPT_ALG_HANDLE
519 wincng_md_algorithm_init(EVP_MD *md,
522 BCRYPT_ALG_HANDLE hAlgorithm;
524 ULONG cbHashObject, cbData;
525 ULONG cbHash = 0, cbBlock = 0;
527 status = BCryptOpenAlgorithmProvider(&hAlgorithm,
531 if (!BCRYPT_SUCCESS(status))
534 status = BCryptGetProperty(hAlgorithm,
540 if (!BCRYPT_SUCCESS(status)) {
541 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
545 status = BCryptGetProperty(hAlgorithm,
546 BCRYPT_HASH_BLOCK_LENGTH,
551 if (!BCRYPT_SUCCESS(status)) {
552 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
556 status = BCryptGetProperty(hAlgorithm,
557 BCRYPT_OBJECT_LENGTH,
558 (PUCHAR)&cbHashObject,
562 if (!BCRYPT_SUCCESS(status)) {
563 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
567 md->hash_size = cbHash;
568 md->block_size = cbBlock;
569 md->ctx_size = sizeof(struct wincng_md_ctx) + cbHashObject - 1;
575 wincng_md_cleanup(EVP_MD_CTX *ctx);
578 wincng_md_hash_init(BCRYPT_ALG_HANDLE hAlgorithm,
581 struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
583 ULONG cbData, dwFlags = 0;
585 if (IsWindows8OrGreaterCached()) {
589 dwFlags |= BCRYPT_HASH_REUSABLE_FLAG;
591 wincng_md_cleanup(ctx);
593 status = BCryptGetProperty(hAlgorithm,
594 BCRYPT_OBJECT_LENGTH,
595 (PUCHAR)&cng->cbHashObject,
599 if (!BCRYPT_SUCCESS(status))
602 status = BCryptCreateHash(hAlgorithm,
610 return BCRYPT_SUCCESS(status);
614 wincng_md_update(EVP_MD_CTX *ctx,
618 struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
621 status = BCryptHashData(cng->hHash, (PUCHAR)data, length, 0);
623 return BCRYPT_SUCCESS(status);
627 wincng_md_final(void *digest,
630 struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
632 ULONG cbHash, cbData;
634 status = BCryptGetProperty(cng->hHash,
640 if (!BCRYPT_SUCCESS(status))
643 status = BCryptFinishHash(cng->hHash,
648 return BCRYPT_SUCCESS(status);
652 wincng_md_cleanup(EVP_MD_CTX *ctx)
654 struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
657 BCryptDestroyHash(cng->hHash);
658 cng->hHash = (BCRYPT_HASH_HANDLE)0;
660 SecureZeroMemory(cng->rgbHashObject, cng->cbHashObject);
665 #define WINCNG_MD_ALGORITHM(name, alg_id) \
667 static BCRYPT_ALG_HANDLE wincng_hAlgorithm_##name; \
669 static int wincng_##name##_init(EVP_MD_CTX *ctx) \
671 return wincng_md_hash_init(wincng_hAlgorithm_##name, ctx); \
675 hc_EVP_wincng_##name(void) \
677 static struct hc_evp_md name = { \
681 wincng_##name##_init, \
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); \
693 return wincng_hAlgorithm_##name ? &name : NULL; \
696 #define WINCNG_MD_ALGORITHM_CLEANUP(name) do { \
697 if (wincng_hAlgorithm_##name) { \
698 BCryptCloseAlgorithmProvider(wincng_hAlgorithm_##name, 0); \
699 wincng_hAlgorithm_##name = NULL; \
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);
712 wincng_md_algorithm_cleanup(void)
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);
723 void _hc_wincng_cleanup(void)
725 wincng_md_algorithm_cleanup();
726 wincng_cipher_algorithm_cleanup();