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 */
38 #if NTDDI_VERSION >= NTDDI_VISTA
41 #include <evp-wincng.h>
50 BCRYPT_KEY_HANDLE hKey
;
51 UCHAR rgbKeyObject
[1];
54 #define WINCNG_KEY_OBJECT_SIZE(ctx) \
55 ((ctx)->cipher->ctx_size - sizeof(struct wincng_key) + 1)
58 wincng_do_cipher(EVP_CIPHER_CTX
*ctx
,
60 const unsigned char *in
,
63 struct wincng_key
*cng
= ctx
->cipher_data
;
67 assert(EVP_CIPHER_CTX_mode(ctx
) == EVP_CIPH_STREAM_CIPHER
||
68 (size
% ctx
->cipher
->block_size
) == 0);
71 status
= BCryptEncrypt(cng
->hKey
,
74 NULL
, /* pPaddingInfo */
75 ctx
->cipher
->iv_len
? ctx
->iv
: NULL
,
82 status
= BCryptDecrypt(cng
->hKey
,
85 NULL
, /* pPaddingInfo */
86 ctx
->cipher
->iv_len
? ctx
->iv
: NULL
,
94 return BCRYPT_SUCCESS(status
) && cbResult
== size
;
98 wincng_cleanup(EVP_CIPHER_CTX
*ctx
)
100 struct wincng_key
*cng
= ctx
->cipher_data
;
103 BCryptDestroyKey(cng
->hKey
);
104 SecureZeroMemory(cng
->rgbKeyObject
, WINCNG_KEY_OBJECT_SIZE(ctx
));
110 wincng_cipher_algorithm_init(EVP_CIPHER
*cipher
,
113 BCRYPT_ALG_HANDLE hAlgorithm
= NULL
;
115 LPCWSTR pszChainingMode
;
116 ULONG cbKeyObject
, cbChainingMode
, cbData
;
118 if (cipher
->app_data
)
121 status
= BCryptOpenAlgorithmProvider(&hAlgorithm
,
125 if (!BCRYPT_SUCCESS(status
))
128 status
= BCryptGetProperty(hAlgorithm
,
129 BCRYPT_OBJECT_LENGTH
,
130 (PUCHAR
)&cbKeyObject
,
134 if (!BCRYPT_SUCCESS(status
)) {
135 BCryptCloseAlgorithmProvider(hAlgorithm
, 0);
139 cipher
->ctx_size
= sizeof(struct wincng_key
) + cbKeyObject
- 1;
141 switch (cipher
->flags
& EVP_CIPH_MODE
) {
142 case EVP_CIPH_CBC_MODE
:
143 pszChainingMode
= BCRYPT_CHAIN_MODE_CBC
;
144 cbChainingMode
= sizeof(BCRYPT_CHAIN_MODE_CBC
);
146 case EVP_CIPH_CFB8_MODE
:
147 pszChainingMode
= BCRYPT_CHAIN_MODE_CFB
;
148 cbChainingMode
= sizeof(BCRYPT_CHAIN_MODE_CFB
);
151 pszChainingMode
= NULL
;
156 if (cbChainingMode
) {
157 status
= BCryptSetProperty(hAlgorithm
,
158 BCRYPT_CHAINING_MODE
,
159 (PUCHAR
)pszChainingMode
,
162 if (!BCRYPT_SUCCESS(status
)) {
163 BCryptCloseAlgorithmProvider(hAlgorithm
, 0);
168 if (wcscmp(pszAlgId
, BCRYPT_RC2_ALGORITHM
) == 0) {
169 ULONG cbEffectiveKeyLength
= EVP_CIPHER_key_length(cipher
) * 8;
171 status
= BCryptSetProperty(hAlgorithm
,
172 BCRYPT_EFFECTIVE_KEY_LENGTH
,
173 (PUCHAR
)&cbEffectiveKeyLength
,
174 sizeof(cbEffectiveKeyLength
),
176 if (!BCRYPT_SUCCESS(status
)) {
177 BCryptCloseAlgorithmProvider(hAlgorithm
, 0);
182 InterlockedCompareExchangePointerRelease(&cipher
->app_data
,
188 wincng_key_init(EVP_CIPHER_CTX
*ctx
,
189 const unsigned char *key
,
190 const unsigned char *iv
,
193 struct wincng_key
*cng
= ctx
->cipher_data
;
197 assert(ctx
->cipher
!= NULL
);
199 if (ctx
->cipher
->app_data
== NULL
)
203 * Note: ctx->key_len not EVP_CIPHER_CTX_key_length() for
204 * variable length key support.
206 status
= BCryptGenerateSymmetricKey(ctx
->cipher
->app_data
,
209 WINCNG_KEY_OBJECT_SIZE(ctx
),
214 return BCRYPT_SUCCESS(status
);
217 #define WINCNG_CIPHER_ALGORITHM(name, alg_id, block_size, key_len, \
238 hc_EVP_wincng_##name(void) \
240 wincng_cipher_algorithm_init(&wincng_##name, alg_id); \
241 return wincng_##name.app_data ? &wincng_##name : NULL; \
244 #define WINCNG_CIPHER_ALGORITHM_CLEANUP(name) do { \
245 if (wincng_##name.app_data) { \
246 BCryptCloseAlgorithmProvider(wincng_##name.app_data, 0); \
247 wincng_##name.app_data = NULL; \
251 #define WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(name) \
254 hc_EVP_wincng_##name(void) \
260 * The tripple DES cipher type (Windows CNG provider)
262 * @return the DES-EDE3-CBC EVP_CIPHER pointer.
264 * @ingroup hcrypto_evp
267 WINCNG_CIPHER_ALGORITHM(des_ede3_cbc
,
268 BCRYPT_3DES_ALGORITHM
,
275 * The DES cipher type (Windows CNG provider)
277 * @return the DES-CBC EVP_CIPHER pointer.
279 * @ingroup hcrypto_evp
282 WINCNG_CIPHER_ALGORITHM(des_cbc
,
283 BCRYPT_DES_ALGORITHM
,
290 * The AES-128 cipher type (Windows CNG provider)
292 * @return the AES-128-CBC EVP_CIPHER pointer.
294 * @ingroup hcrypto_evp
297 WINCNG_CIPHER_ALGORITHM(aes_128_cbc
,
298 BCRYPT_AES_ALGORITHM
,
305 * The AES-192 cipher type (Windows CNG provider)
307 * @return the AES-192-CBC EVP_CIPHER pointer.
309 * @ingroup hcrypto_evp
312 WINCNG_CIPHER_ALGORITHM(aes_192_cbc
,
313 BCRYPT_AES_ALGORITHM
,
320 * The AES-256 cipher type (Windows CNG provider)
322 * @return the AES-256-CBC EVP_CIPHER pointer.
324 * @ingroup hcrypto_evp
327 WINCNG_CIPHER_ALGORITHM(aes_256_cbc
,
328 BCRYPT_AES_ALGORITHM
,
335 * The AES-128 CFB8 cipher type (Windows CNG provider)
337 * @return the AES-128-CFB8 EVP_CIPHER pointer.
339 * @ingroup hcrypto_evp
342 WINCNG_CIPHER_ALGORITHM(aes_128_cfb8
,
343 BCRYPT_AES_ALGORITHM
,
350 * The AES-192 CFB8 cipher type (Windows CNG provider)
352 * @return the AES-192-CFB8 EVP_CIPHER pointer.
354 * @ingroup hcrypto_evp
357 WINCNG_CIPHER_ALGORITHM(aes_192_cfb8
,
358 BCRYPT_AES_ALGORITHM
,
365 * The AES-256 CFB8 cipher type (Windows CNG provider)
367 * @return the AES-256-CFB8 EVP_CIPHER pointer.
369 * @ingroup hcrypto_evp
372 WINCNG_CIPHER_ALGORITHM(aes_256_cfb8
,
373 BCRYPT_AES_ALGORITHM
,
380 * The RC2 cipher type - Windows CNG
382 * @return the RC2 EVP_CIPHER pointer.
384 * @ingroup hcrypto_evp
387 WINCNG_CIPHER_ALGORITHM(rc2_cbc
,
388 BCRYPT_RC2_ALGORITHM
,
395 * The RC2-40 cipher type - Windows CNG
397 * @return the RC2-40 EVP_CIPHER pointer.
399 * @ingroup hcrypto_evp
402 WINCNG_CIPHER_ALGORITHM(rc2_40_cbc
,
403 BCRYPT_RC2_ALGORITHM
,
410 * The RC2-64 cipher type - Windows CNG
412 * @return the RC2-64 EVP_CIPHER pointer.
414 * @ingroup hcrypto_evp
417 WINCNG_CIPHER_ALGORITHM(rc2_64_cbc
,
418 BCRYPT_RC2_ALGORITHM
,
425 * The Camellia-128 cipher type - CommonCrypto
427 * @return the Camellia-128 EVP_CIPHER pointer.
429 * @ingroup hcrypto_evp
432 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_128_cbc
);
435 * The Camellia-198 cipher type - CommonCrypto
437 * @return the Camellia-198 EVP_CIPHER pointer.
439 * @ingroup hcrypto_evp
442 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_192_cbc
);
445 * The Camellia-256 cipher type - CommonCrypto
447 * @return the Camellia-256 EVP_CIPHER pointer.
449 * @ingroup hcrypto_evp
452 WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(camellia_256_cbc
);
455 * The RC4 cipher type (Windows CNG provider)
457 * @return the RC4 EVP_CIPHER pointer.
459 * @ingroup hcrypto_evp
462 WINCNG_CIPHER_ALGORITHM(rc4
,
463 BCRYPT_RC4_ALGORITHM
,
467 EVP_CIPH_STREAM_CIPHER
| EVP_CIPH_VARIABLE_LENGTH
);
470 * The RC4-40 cipher type (Windows CNG provider)
472 * @return the RC4 EVP_CIPHER pointer.
474 * @ingroup hcrypto_evp
477 WINCNG_CIPHER_ALGORITHM(rc4_40
,
478 BCRYPT_RC4_ALGORITHM
,
482 EVP_CIPH_STREAM_CIPHER
| EVP_CIPH_VARIABLE_LENGTH
);
485 wincng_cipher_algorithm_cleanup(void)
487 WINCNG_CIPHER_ALGORITHM_CLEANUP(des_ede3_cbc
);
488 WINCNG_CIPHER_ALGORITHM_CLEANUP(des_cbc
);
489 WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_128_cbc
);
490 WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_192_cbc
);
491 WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_256_cbc
);
492 WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_128_cfb8
);
493 WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_192_cfb8
);
494 WINCNG_CIPHER_ALGORITHM_CLEANUP(aes_256_cfb8
);
495 WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_cbc
);
496 WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_40_cbc
);
497 WINCNG_CIPHER_ALGORITHM_CLEANUP(rc2_64_cbc
);
498 WINCNG_CIPHER_ALGORITHM_CLEANUP(rc4
);
499 WINCNG_CIPHER_ALGORITHM_CLEANUP(rc4_40
);
503 * CNG digest provider
506 struct wincng_md_ctx
{
507 BCRYPT_HASH_HANDLE hHash
;
509 UCHAR rgbHashObject
[1];
512 static BCRYPT_ALG_HANDLE
513 wincng_md_algorithm_init(EVP_MD
*md
,
516 BCRYPT_ALG_HANDLE hAlgorithm
;
518 ULONG cbHashObject
, cbData
;
519 ULONG cbHash
= 0, cbBlock
= 0;
521 status
= BCryptOpenAlgorithmProvider(&hAlgorithm
,
525 if (!BCRYPT_SUCCESS(status
))
528 status
= BCryptGetProperty(hAlgorithm
,
534 if (!BCRYPT_SUCCESS(status
)) {
535 BCryptCloseAlgorithmProvider(hAlgorithm
, 0);
539 status
= BCryptGetProperty(hAlgorithm
,
540 BCRYPT_HASH_BLOCK_LENGTH
,
545 if (!BCRYPT_SUCCESS(status
)) {
546 BCryptCloseAlgorithmProvider(hAlgorithm
, 0);
550 status
= BCryptGetProperty(hAlgorithm
,
551 BCRYPT_OBJECT_LENGTH
,
552 (PUCHAR
)&cbHashObject
,
556 if (!BCRYPT_SUCCESS(status
)) {
557 BCryptCloseAlgorithmProvider(hAlgorithm
, 0);
561 md
->hash_size
= cbHash
;
562 md
->block_size
= cbBlock
;
563 md
->ctx_size
= sizeof(struct wincng_md_ctx
) + cbHashObject
- 1;
569 wincng_md_hash_init(BCRYPT_ALG_HANDLE hAlgorithm
,
572 struct wincng_md_ctx
*cng
= (struct wincng_md_ctx
*)ctx
;
576 status
= BCryptGetProperty(hAlgorithm
,
577 BCRYPT_OBJECT_LENGTH
,
578 (PUCHAR
)&cng
->cbHashObject
,
582 if (!BCRYPT_SUCCESS(status
))
585 status
= BCryptCreateHash(hAlgorithm
,
593 return BCRYPT_SUCCESS(status
);
597 wincng_md_update(EVP_MD_CTX
*ctx
,
601 struct wincng_md_ctx
*cng
= (struct wincng_md_ctx
*)ctx
;
604 status
= BCryptHashData(cng
->hHash
, (PUCHAR
)data
, length
, 0);
606 return BCRYPT_SUCCESS(status
);
610 wincng_md_final(void *digest
,
613 struct wincng_md_ctx
*cng
= (struct wincng_md_ctx
*)ctx
;
615 ULONG cbHash
, cbData
;
617 status
= BCryptGetProperty(cng
->hHash
,
623 if (!BCRYPT_SUCCESS(status
))
626 status
= BCryptFinishHash(cng
->hHash
,
631 return BCRYPT_SUCCESS(status
);
635 wincng_md_cleanup(EVP_MD_CTX
*ctx
)
637 struct wincng_md_ctx
*cng
= (struct wincng_md_ctx
*)ctx
;
640 BCryptDestroyHash(cng
->hHash
);
641 SecureZeroMemory(cng
->rgbHashObject
, cng
->cbHashObject
);
646 #define WINCNG_MD_ALGORITHM(name, alg_id) \
648 static BCRYPT_ALG_HANDLE wincng_hAlgorithm_##name; \
650 static int wincng_##name##_init(EVP_MD_CTX *ctx) \
652 return wincng_md_hash_init(wincng_hAlgorithm_##name, ctx); \
656 hc_EVP_wincng_##name(void) \
658 static struct hc_evp_md name = { \
662 wincng_##name##_init, \
668 if (wincng_hAlgorithm_##name == NULL) { \
669 BCRYPT_ALG_HANDLE hAlgorithm = \
670 wincng_md_algorithm_init(&name, alg_id); \
671 InterlockedCompareExchangePointerRelease( \
672 &wincng_hAlgorithm_##name, hAlgorithm, NULL); \
674 return wincng_hAlgorithm_##name ? &name : NULL; \
677 #define WINCNG_MD_ALGORITHM_CLEANUP(name) do { \
678 if (wincng_hAlgorithm_##name) { \
679 BCryptCloseAlgorithmProvider(wincng_hAlgorithm_##name, 0); \
680 wincng_hAlgorithm_##name = NULL; \
684 WINCNG_MD_ALGORITHM(md2
, BCRYPT_MD2_ALGORITHM
);
685 WINCNG_MD_ALGORITHM(md4
, BCRYPT_MD4_ALGORITHM
);
686 WINCNG_MD_ALGORITHM(md5
, BCRYPT_MD5_ALGORITHM
);
687 WINCNG_MD_ALGORITHM(sha1
, BCRYPT_SHA1_ALGORITHM
);
688 WINCNG_MD_ALGORITHM(sha256
, BCRYPT_SHA256_ALGORITHM
);
689 WINCNG_MD_ALGORITHM(sha384
, BCRYPT_SHA384_ALGORITHM
);
690 WINCNG_MD_ALGORITHM(sha512
, BCRYPT_SHA512_ALGORITHM
);
693 wincng_md_algorithm_cleanup(void)
695 WINCNG_MD_ALGORITHM_CLEANUP(md2
);
696 WINCNG_MD_ALGORITHM_CLEANUP(md4
);
697 WINCNG_MD_ALGORITHM_CLEANUP(md5
);
698 WINCNG_MD_ALGORITHM_CLEANUP(sha1
);
699 WINCNG_MD_ALGORITHM_CLEANUP(sha256
);
700 WINCNG_MD_ALGORITHM_CLEANUP(sha384
);
701 WINCNG_MD_ALGORITHM_CLEANUP(sha512
);
704 void _hc_wincng_cleanup(void)
706 wincng_md_algorithm_cleanup();
707 wincng_cipher_algorithm_cleanup();
710 #endif /* NTDDI_VERSION >= NTDDI_VISTA */