wincng: Remove trailing space
[heimdal.git] / lib / hcrypto / evp-wincng.c
blob1e16054689ad6b1ad9471db5217af4c958b81899
1 /*
2 * Copyright (c) 2015, Secure Endpoints Inc.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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
15 * distribution.
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 */
33 #include "config.h"
35 #include <windows.h>
36 #include <assert.h>
38 #if NTDDI_VERSION >= NTDDI_VISTA
40 #include <evp.h>
41 #include <evp-wincng.h>
43 #include <bcrypt.h>
46 * CNG cipher provider
49 struct wincng_key {
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)
57 static int
58 wincng_do_cipher(EVP_CIPHER_CTX *ctx,
59 unsigned char *out,
60 const unsigned char *in,
61 unsigned int size)
63 struct wincng_key *cng = ctx->cipher_data;
64 NTSTATUS status;
65 ULONG cbResult;
67 assert(EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_STREAM_CIPHER ||
68 (size % ctx->cipher->block_size) == 0);
70 if (ctx->encrypt) {
71 status = BCryptEncrypt(cng->hKey,
72 (PUCHAR)in,
73 size,
74 NULL, /* pPaddingInfo */
75 ctx->cipher->iv_len ? ctx->iv : NULL,
76 ctx->cipher->iv_len,
77 out,
78 size,
79 &cbResult,
80 0);
81 } else {
82 status = BCryptDecrypt(cng->hKey,
83 (PUCHAR)in,
84 size,
85 NULL, /* pPaddingInfo */
86 ctx->cipher->iv_len ? ctx->iv : NULL,
87 ctx->cipher->iv_len,
88 out,
89 size,
90 &cbResult,
91 0);
94 return BCRYPT_SUCCESS(status) && cbResult == size;
97 static int
98 wincng_cleanup(EVP_CIPHER_CTX *ctx)
100 struct wincng_key *cng = ctx->cipher_data;
102 if (cng->hKey)
103 BCryptDestroyKey(cng->hKey);
104 SecureZeroMemory(cng->rgbKeyObject, WINCNG_KEY_OBJECT_SIZE(ctx));
106 return 1;
109 static int
110 wincng_cipher_algorithm_init(EVP_CIPHER *cipher,
111 LPWSTR pszAlgId)
113 BCRYPT_ALG_HANDLE hAlgorithm = NULL;
114 NTSTATUS status;
115 LPCWSTR pszChainingMode;
116 ULONG cbKeyObject, cbChainingMode, cbData;
118 if (cipher->app_data)
119 return 1;
121 status = BCryptOpenAlgorithmProvider(&hAlgorithm,
122 pszAlgId,
123 NULL,
125 if (!BCRYPT_SUCCESS(status))
126 return 0;
128 status = BCryptGetProperty(hAlgorithm,
129 BCRYPT_OBJECT_LENGTH,
130 (PUCHAR)&cbKeyObject,
131 sizeof(ULONG),
132 &cbData,
134 if (!BCRYPT_SUCCESS(status)) {
135 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
136 return 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);
145 break;
146 case EVP_CIPH_CFB8_MODE:
147 pszChainingMode = BCRYPT_CHAIN_MODE_CFB;
148 cbChainingMode = sizeof(BCRYPT_CHAIN_MODE_CFB);
149 break;
150 default:
151 pszChainingMode = NULL;
152 cbChainingMode = 0;
153 break;
156 if (cbChainingMode) {
157 status = BCryptSetProperty(hAlgorithm,
158 BCRYPT_CHAINING_MODE,
159 (PUCHAR)pszChainingMode,
160 cbChainingMode,
162 if (!BCRYPT_SUCCESS(status)) {
163 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
164 return 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);
178 return 0;
182 InterlockedCompareExchangePointerRelease(&cipher->app_data,
183 hAlgorithm, NULL);
184 return 1;
187 static int
188 wincng_key_init(EVP_CIPHER_CTX *ctx,
189 const unsigned char *key,
190 const unsigned char *iv,
191 int encp)
193 struct wincng_key *cng = ctx->cipher_data;
194 NTSTATUS status;
196 assert(cng != NULL);
197 assert(ctx->cipher != NULL);
199 if (ctx->cipher->app_data == NULL)
200 return 0;
203 * Note: ctx->key_len not EVP_CIPHER_CTX_key_length() for
204 * variable length key support.
206 status = BCryptGenerateSymmetricKey(ctx->cipher->app_data,
207 &cng->hKey,
208 cng->rgbKeyObject,
209 WINCNG_KEY_OBJECT_SIZE(ctx),
210 (PUCHAR)key,
211 ctx->key_len,
214 return BCRYPT_SUCCESS(status);
217 #define WINCNG_CIPHER_ALGORITHM(name, alg_id, block_size, key_len, \
218 iv_len, flags) \
220 static EVP_CIPHER \
221 wincng_##name = { \
222 0, \
223 block_size, \
224 key_len, \
225 iv_len, \
226 flags, \
227 wincng_key_init, \
228 wincng_do_cipher, \
229 wincng_cleanup, \
230 0, \
231 NULL, \
232 NULL, \
233 NULL, \
234 NULL \
235 }; \
237 const EVP_CIPHER * \
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; \
249 } while (0)
251 #define WINCNG_CIPHER_ALGORITHM_UNAVAILABLE(name) \
253 const EVP_CIPHER * \
254 hc_EVP_wincng_##name(void) \
256 return NULL; \
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,
272 EVP_CIPH_CBC_MODE);
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,
287 EVP_CIPH_CBC_MODE);
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,
302 EVP_CIPH_CBC_MODE);
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,
317 EVP_CIPH_CBC_MODE);
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,
332 EVP_CIPH_CBC_MODE);
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,
347 EVP_CIPH_CFB8_MODE);
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,
362 EVP_CIPH_CFB8_MODE);
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,
377 EVP_CIPH_CFB8_MODE);
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,
392 EVP_CIPH_CBC_MODE);
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,
407 EVP_CIPH_CBC_MODE);
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,
422 EVP_CIPH_CBC_MODE);
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);
484 static void
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;
508 ULONG cbHashObject;
509 UCHAR rgbHashObject[1];
512 static BCRYPT_ALG_HANDLE
513 wincng_md_algorithm_init(EVP_MD *md,
514 LPCWSTR pszAlgId)
516 BCRYPT_ALG_HANDLE hAlgorithm;
517 NTSTATUS status;
518 ULONG cbHashObject, cbData;
519 ULONG cbHash = 0, cbBlock = 0;
521 status = BCryptOpenAlgorithmProvider(&hAlgorithm,
522 pszAlgId,
523 NULL,
525 if (!BCRYPT_SUCCESS(status))
526 return NULL;
528 status = BCryptGetProperty(hAlgorithm,
529 BCRYPT_HASH_LENGTH,
530 (PUCHAR)&cbHash,
531 sizeof(ULONG),
532 &cbData,
534 if (!BCRYPT_SUCCESS(status)) {
535 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
536 return NULL;
539 status = BCryptGetProperty(hAlgorithm,
540 BCRYPT_HASH_BLOCK_LENGTH,
541 (PUCHAR)&cbBlock,
542 sizeof(ULONG),
543 &cbData,
545 if (!BCRYPT_SUCCESS(status)) {
546 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
547 return NULL;
550 status = BCryptGetProperty(hAlgorithm,
551 BCRYPT_OBJECT_LENGTH,
552 (PUCHAR)&cbHashObject,
553 sizeof(ULONG),
554 &cbData,
556 if (!BCRYPT_SUCCESS(status)) {
557 BCryptCloseAlgorithmProvider(hAlgorithm, 0);
558 return NULL;
561 md->hash_size = cbHash;
562 md->block_size = cbBlock;
563 md->ctx_size = sizeof(struct wincng_md_ctx) + cbHashObject - 1;
565 return hAlgorithm;
568 static int
569 wincng_md_hash_init(BCRYPT_ALG_HANDLE hAlgorithm,
570 EVP_MD_CTX *ctx)
572 struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
573 NTSTATUS status;
574 ULONG cbData;
576 status = BCryptGetProperty(hAlgorithm,
577 BCRYPT_OBJECT_LENGTH,
578 (PUCHAR)&cng->cbHashObject,
579 sizeof(ULONG),
580 &cbData,
582 if (!BCRYPT_SUCCESS(status))
583 return 0;
585 status = BCryptCreateHash(hAlgorithm,
586 &cng->hHash,
587 cng->rgbHashObject,
588 cng->cbHashObject,
589 NULL,
593 return BCRYPT_SUCCESS(status);
596 static int
597 wincng_md_update(EVP_MD_CTX *ctx,
598 const void *data,
599 size_t length)
601 struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
602 NTSTATUS status;
604 status = BCryptHashData(cng->hHash, (PUCHAR)data, length, 0);
606 return BCRYPT_SUCCESS(status);
609 static int
610 wincng_md_final(void *digest,
611 EVP_MD_CTX *ctx)
613 struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
614 NTSTATUS status;
615 ULONG cbHash, cbData;
617 status = BCryptGetProperty(cng->hHash,
618 BCRYPT_HASH_LENGTH,
619 (PUCHAR)&cbHash,
620 sizeof(DWORD),
621 &cbData,
623 if (!BCRYPT_SUCCESS(status))
624 return 0;
626 status = BCryptFinishHash(cng->hHash,
627 digest,
628 cbHash,
631 return BCRYPT_SUCCESS(status);
634 static int
635 wincng_md_cleanup(EVP_MD_CTX *ctx)
637 struct wincng_md_ctx *cng = (struct wincng_md_ctx *)ctx;
639 if (cng->hHash)
640 BCryptDestroyHash(cng->hHash);
641 SecureZeroMemory(cng->rgbHashObject, cng->cbHashObject);
643 return 1;
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); \
655 const EVP_MD * \
656 hc_EVP_wincng_##name(void) \
658 static struct hc_evp_md name = { \
659 0, \
660 0, \
661 0, \
662 wincng_##name##_init, \
663 wincng_md_update, \
664 wincng_md_final, \
665 wincng_md_cleanup \
666 }; \
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; \
682 } while (0)
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);
692 static void
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 */