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();