2 * Crypto wrapper for Microsoft CryptoAPI
3 * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
22 #ifndef MS_ENH_RSA_AES_PROV
24 #define MS_ENH_RSA_AES_PROV \
25 L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
27 #define MS_ENH_RSA_AES_PROV \
28 "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
30 #endif /* MS_ENH_RSA_AES_PROV */
33 #define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
36 #ifdef CONFIG_TLS_INTERNAL
37 #ifdef __MINGW32_VERSION
39 * MinGW does not yet include all the needed definitions for CryptoAPI, so
40 * define here whatever extra is needed.
44 (*CryptImportPublicKeyInfo
)(HCRYPTPROV hCryptProv
, DWORD dwCertEncodingType
,
45 PCERT_PUBLIC_KEY_INFO pInfo
, HCRYPTKEY
*phKey
)
46 = NULL
; /* to be loaded from crypt32.dll */
49 static int mingw_load_crypto_func(void)
53 /* MinGW does not yet have full CryptoAPI support, so load the needed
56 if (CryptImportPublicKeyInfo
)
59 dll
= LoadLibrary("crypt32");
61 wpa_printf(MSG_DEBUG
, "CryptoAPI: Could not load crypt32 "
66 CryptImportPublicKeyInfo
= GetProcAddress(
67 dll
, "CryptImportPublicKeyInfo");
68 if (CryptImportPublicKeyInfo
== NULL
) {
69 wpa_printf(MSG_DEBUG
, "CryptoAPI: Could not get "
70 "CryptImportPublicKeyInfo() address from "
78 #else /* __MINGW32_VERSION */
80 static int mingw_load_crypto_func(void)
85 #endif /* __MINGW32_VERSION */
86 #endif /* CONFIG_TLS_INTERNAL */
89 static void cryptoapi_report_error(const char *msg
)
92 DWORD err
= GetLastError();
94 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
95 FORMAT_MESSAGE_FROM_SYSTEM
,
96 NULL
, err
, 0, (LPTSTR
) &s
, 0, NULL
) == 0) {
97 wpa_printf(MSG_DEBUG
, "CryptoAPI: %s: %d", msg
, (int) err
);
102 if (*pos
== '\n' || *pos
== '\r') {
109 wpa_printf(MSG_DEBUG
, "CryptoAPI: %s: %d: (%s)", msg
, (int) err
, s
);
114 int cryptoapi_hash_vector(ALG_ID alg
, size_t hash_len
, size_t num_elem
,
115 const u8
*addr
[], const size_t *len
, u8
*mac
)
123 if (!CryptAcquireContext(&prov
, NULL
, NULL
, PROV_RSA_FULL
, 0)) {
124 cryptoapi_report_error("CryptAcquireContext");
128 if (!CryptCreateHash(prov
, alg
, 0, 0, &hash
)) {
129 cryptoapi_report_error("CryptCreateHash");
130 CryptReleaseContext(prov
, 0);
134 for (i
= 0; i
< num_elem
; i
++) {
135 if (!CryptHashData(hash
, (BYTE
*) addr
[i
], len
[i
], 0)) {
136 cryptoapi_report_error("CryptHashData");
137 CryptDestroyHash(hash
);
138 CryptReleaseContext(prov
, 0);
143 if (!CryptGetHashParam(hash
, HP_HASHVAL
, mac
, &hlen
, 0)) {
144 cryptoapi_report_error("CryptGetHashParam");
148 CryptDestroyHash(hash
);
149 CryptReleaseContext(prov
, 0);
155 void md4_vector(size_t num_elem
, const u8
*addr
[], const size_t *len
, u8
*mac
)
157 cryptoapi_hash_vector(CALG_MD4
, 16, num_elem
, addr
, len
, mac
);
161 void des_encrypt(const u8
*clear
, const u8
*key
, u8
*cypher
)
173 DWORD mode
= CRYPT_MODE_ECB
;
175 key_blob
.hdr
.bType
= PLAINTEXTKEYBLOB
;
176 key_blob
.hdr
.bVersion
= CUR_BLOB_VERSION
;
177 key_blob
.hdr
.reserved
= 0;
178 key_blob
.hdr
.aiKeyAlg
= CALG_DES
;
181 /* Add parity bits to the key */
183 for (i
= 0; i
< 7; i
++) {
185 key_blob
.key
[i
] = (tmp
>> i
) | next
| 1;
186 next
= tmp
<< (7 - i
);
188 key_blob
.key
[i
] = next
| 1;
190 if (!CryptAcquireContext(&prov
, NULL
, MS_ENHANCED_PROV
, PROV_RSA_FULL
,
191 CRYPT_VERIFYCONTEXT
)) {
192 wpa_printf(MSG_DEBUG
, "CryptoAPI: CryptAcquireContext failed: "
193 "%d", (int) GetLastError());
197 if (!CryptImportKey(prov
, (BYTE
*) &key_blob
, sizeof(key_blob
), 0, 0,
199 wpa_printf(MSG_DEBUG
, "CryptoAPI: CryptImportKey failed: %d",
200 (int) GetLastError());
201 CryptReleaseContext(prov
, 0);
205 if (!CryptSetKeyParam(ckey
, KP_MODE
, (BYTE
*) &mode
, 0)) {
206 wpa_printf(MSG_DEBUG
, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
207 "failed: %d", (int) GetLastError());
208 CryptDestroyKey(ckey
);
209 CryptReleaseContext(prov
, 0);
213 os_memcpy(cypher
, clear
, 8);
215 if (!CryptEncrypt(ckey
, 0, FALSE
, 0, cypher
, &dlen
, 8)) {
216 wpa_printf(MSG_DEBUG
, "CryptoAPI: CryptEncrypt failed: %d",
217 (int) GetLastError());
218 os_memset(cypher
, 0, 8);
221 CryptDestroyKey(ckey
);
222 CryptReleaseContext(prov
, 0);
227 void md5_vector(size_t num_elem
, const u8
*addr
[], const size_t *len
, u8
*mac
)
229 cryptoapi_hash_vector(CALG_MD5
, 16, num_elem
, addr
, len
, mac
);
233 void sha1_vector(size_t num_elem
, const u8
*addr
[], const size_t *len
, u8
*mac
)
235 cryptoapi_hash_vector(CALG_SHA
, 20, num_elem
, addr
, len
, mac
);
245 void * aes_encrypt_init(const u8
*key
, size_t len
)
247 struct aes_context
*akey
;
253 DWORD mode
= CRYPT_MODE_ECB
;
258 key_blob
.hdr
.bType
= PLAINTEXTKEYBLOB
;
259 key_blob
.hdr
.bVersion
= CUR_BLOB_VERSION
;
260 key_blob
.hdr
.reserved
= 0;
261 key_blob
.hdr
.aiKeyAlg
= CALG_AES_128
;
263 os_memcpy(key_blob
.key
, key
, len
);
265 akey
= os_zalloc(sizeof(*akey
));
269 if (!CryptAcquireContext(&akey
->prov
, NULL
,
270 MS_ENH_RSA_AES_PROV
, PROV_RSA_AES
,
271 CRYPT_VERIFYCONTEXT
)) {
272 wpa_printf(MSG_DEBUG
, "CryptoAPI: CryptAcquireContext failed: "
273 "%d", (int) GetLastError());
278 if (!CryptImportKey(akey
->prov
, (BYTE
*) &key_blob
, sizeof(key_blob
),
279 0, 0, &akey
->ckey
)) {
280 wpa_printf(MSG_DEBUG
, "CryptoAPI: CryptImportKey failed: %d",
281 (int) GetLastError());
282 CryptReleaseContext(akey
->prov
, 0);
287 if (!CryptSetKeyParam(akey
->ckey
, KP_MODE
, (BYTE
*) &mode
, 0)) {
288 wpa_printf(MSG_DEBUG
, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
289 "failed: %d", (int) GetLastError());
290 CryptDestroyKey(akey
->ckey
);
291 CryptReleaseContext(akey
->prov
, 0);
300 void aes_encrypt(void *ctx
, const u8
*plain
, u8
*crypt
)
302 struct aes_context
*akey
= ctx
;
305 os_memcpy(crypt
, plain
, 16);
307 if (!CryptEncrypt(akey
->ckey
, 0, FALSE
, 0, crypt
, &dlen
, 16)) {
308 wpa_printf(MSG_DEBUG
, "CryptoAPI: CryptEncrypt failed: %d",
309 (int) GetLastError());
310 os_memset(crypt
, 0, 16);
315 void aes_encrypt_deinit(void *ctx
)
317 struct aes_context
*akey
= ctx
;
319 CryptDestroyKey(akey
->ckey
);
320 CryptReleaseContext(akey
->prov
, 0);
326 void * aes_decrypt_init(const u8
*key
, size_t len
)
328 return aes_encrypt_init(key
, len
);
332 void aes_decrypt(void *ctx
, const u8
*crypt
, u8
*plain
)
334 struct aes_context
*akey
= ctx
;
337 os_memcpy(plain
, crypt
, 16);
340 if (!CryptDecrypt(akey
->ckey
, 0, FALSE
, 0, plain
, &dlen
)) {
341 wpa_printf(MSG_DEBUG
, "CryptoAPI: CryptDecrypt failed: %d",
342 (int) GetLastError());
347 void aes_decrypt_deinit(void *ctx
)
349 aes_encrypt_deinit(ctx
);
352 #ifdef CONFIG_TLS_INTERNAL
355 enum crypto_hash_alg alg
;
362 struct crypto_hash
* crypto_hash_init(enum crypto_hash_alg alg
, const u8
*key
,
365 struct crypto_hash
*ctx
;
373 os_memset(&key_blob
, 0, sizeof(key_blob
));
375 case CRYPTO_HASH_ALG_MD5
:
378 case CRYPTO_HASH_ALG_SHA1
:
381 case CRYPTO_HASH_ALG_HMAC_MD5
:
382 case CRYPTO_HASH_ALG_HMAC_SHA1
:
384 key_blob
.hdr
.bType
= PLAINTEXTKEYBLOB
;
385 key_blob
.hdr
.bVersion
= CUR_BLOB_VERSION
;
386 key_blob
.hdr
.reserved
= 0;
388 * Note: RC2 is not really used, but that can be used to
389 * import HMAC keys of up to 16 byte long.
390 * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
391 * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
393 key_blob
.hdr
.aiKeyAlg
= CALG_RC2
;
394 key_blob
.len
= key_len
;
395 if (key_len
> sizeof(key_blob
.key
))
397 os_memcpy(key_blob
.key
, key
, key_len
);
403 ctx
= os_zalloc(sizeof(*ctx
));
409 if (!CryptAcquireContext(&ctx
->prov
, NULL
, NULL
, PROV_RSA_FULL
, 0)) {
410 cryptoapi_report_error("CryptAcquireContext");
415 if (calg
== CALG_HMAC
) {
416 #ifndef CRYPT_IPSEC_HMAC_KEY
417 #define CRYPT_IPSEC_HMAC_KEY 0x00000100
419 if (!CryptImportKey(ctx
->prov
, (BYTE
*) &key_blob
,
420 sizeof(key_blob
), 0, CRYPT_IPSEC_HMAC_KEY
,
422 cryptoapi_report_error("CryptImportKey");
423 CryptReleaseContext(ctx
->prov
, 0);
429 if (!CryptCreateHash(ctx
->prov
, calg
, ctx
->key
, 0, &ctx
->hash
)) {
430 cryptoapi_report_error("CryptCreateHash");
431 CryptReleaseContext(ctx
->prov
, 0);
436 if (calg
== CALG_HMAC
) {
438 os_memset(&info
, 0, sizeof(info
));
440 case CRYPTO_HASH_ALG_HMAC_MD5
:
441 info
.HashAlgid
= CALG_MD5
;
443 case CRYPTO_HASH_ALG_HMAC_SHA1
:
444 info
.HashAlgid
= CALG_SHA
;
451 if (!CryptSetHashParam(ctx
->hash
, HP_HMAC_INFO
, (BYTE
*) &info
,
453 cryptoapi_report_error("CryptSetHashParam");
454 CryptDestroyHash(ctx
->hash
);
455 CryptReleaseContext(ctx
->prov
, 0);
465 void crypto_hash_update(struct crypto_hash
*ctx
, const u8
*data
, size_t len
)
467 if (ctx
== NULL
|| ctx
->error
)
470 if (!CryptHashData(ctx
->hash
, (BYTE
*) data
, len
, 0)) {
471 cryptoapi_report_error("CryptHashData");
477 int crypto_hash_finish(struct crypto_hash
*ctx
, u8
*mac
, size_t *len
)
485 if (mac
== NULL
|| len
== NULL
)
494 if (!CryptGetHashParam(ctx
->hash
, HP_HASHVAL
, mac
, &hlen
, 0)) {
495 cryptoapi_report_error("CryptGetHashParam");
501 if (ctx
->alg
== CRYPTO_HASH_ALG_HMAC_SHA1
||
502 ctx
->alg
== CRYPTO_HASH_ALG_HMAC_MD5
)
503 CryptDestroyKey(ctx
->key
);
511 struct crypto_cipher
{
517 struct crypto_cipher
* crypto_cipher_init(enum crypto_cipher_alg alg
,
518 const u8
*iv
, const u8
*key
,
521 struct crypto_cipher
*ctx
;
527 DWORD mode
= CRYPT_MODE_CBC
;
529 key_blob
.hdr
.bType
= PLAINTEXTKEYBLOB
;
530 key_blob
.hdr
.bVersion
= CUR_BLOB_VERSION
;
531 key_blob
.hdr
.reserved
= 0;
532 key_blob
.len
= key_len
;
533 if (key_len
> sizeof(key_blob
.key
))
535 os_memcpy(key_blob
.key
, key
, key_len
);
538 case CRYPTO_CIPHER_ALG_AES
:
540 key_blob
.hdr
.aiKeyAlg
= CALG_AES_256
;
541 else if (key_len
== 24)
542 key_blob
.hdr
.aiKeyAlg
= CALG_AES_192
;
544 key_blob
.hdr
.aiKeyAlg
= CALG_AES_128
;
546 case CRYPTO_CIPHER_ALG_3DES
:
547 key_blob
.hdr
.aiKeyAlg
= CALG_3DES
;
549 case CRYPTO_CIPHER_ALG_DES
:
550 key_blob
.hdr
.aiKeyAlg
= CALG_DES
;
552 case CRYPTO_CIPHER_ALG_RC2
:
553 key_blob
.hdr
.aiKeyAlg
= CALG_RC2
;
555 case CRYPTO_CIPHER_ALG_RC4
:
556 key_blob
.hdr
.aiKeyAlg
= CALG_RC4
;
562 ctx
= os_zalloc(sizeof(*ctx
));
566 if (!CryptAcquireContext(&ctx
->prov
, NULL
, MS_ENH_RSA_AES_PROV
,
567 PROV_RSA_AES
, CRYPT_VERIFYCONTEXT
)) {
568 cryptoapi_report_error("CryptAcquireContext");
572 if (!CryptImportKey(ctx
->prov
, (BYTE
*) &key_blob
,
573 sizeof(key_blob
), 0, 0, &ctx
->key
)) {
574 cryptoapi_report_error("CryptImportKey");
578 if (!CryptSetKeyParam(ctx
->key
, KP_MODE
, (BYTE
*) &mode
, 0)) {
579 cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
583 if (iv
&& !CryptSetKeyParam(ctx
->key
, KP_IV
, (BYTE
*) iv
, 0)) {
584 cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
591 CryptDestroyKey(ctx
->key
);
593 CryptReleaseContext(ctx
->prov
, 0);
600 int crypto_cipher_encrypt(struct crypto_cipher
*ctx
, const u8
*plain
,
601 u8
*crypt
, size_t len
)
605 os_memcpy(crypt
, plain
, len
);
607 if (!CryptEncrypt(ctx
->key
, 0, FALSE
, 0, crypt
, &dlen
, len
)) {
608 cryptoapi_report_error("CryptEncrypt");
609 os_memset(crypt
, 0, len
);
617 int crypto_cipher_decrypt(struct crypto_cipher
*ctx
, const u8
*crypt
,
618 u8
*plain
, size_t len
)
622 os_memcpy(plain
, crypt
, len
);
624 if (!CryptDecrypt(ctx
->key
, 0, FALSE
, 0, plain
, &dlen
)) {
625 cryptoapi_report_error("CryptDecrypt");
633 void crypto_cipher_deinit(struct crypto_cipher
*ctx
)
635 CryptDestroyKey(ctx
->key
);
636 CryptReleaseContext(ctx
->prov
, 0);
641 struct crypto_public_key
{
646 struct crypto_private_key
{
652 struct crypto_public_key
* crypto_public_key_import(const u8
*key
, size_t len
)
654 /* Use crypto_public_key_from_cert() instead. */
659 struct crypto_private_key
* crypto_private_key_import(const u8
*key
,
667 struct crypto_public_key
* crypto_public_key_from_cert(const u8
*buf
,
670 struct crypto_public_key
*pk
;
673 pk
= os_zalloc(sizeof(*pk
));
677 cc
= CertCreateCertificateContext(X509_ASN_ENCODING
|
678 PKCS_7_ASN_ENCODING
, buf
, len
);
680 cryptoapi_report_error("CryptCreateCertificateContext");
685 if (!CryptAcquireContext(&pk
->prov
, NULL
, MS_DEF_PROV
, PROV_RSA_FULL
,
687 cryptoapi_report_error("CryptAcquireContext");
689 CertFreeCertificateContext(cc
);
693 if (!CryptImportPublicKeyInfo(pk
->prov
, X509_ASN_ENCODING
|
695 &cc
->pCertInfo
->SubjectPublicKeyInfo
,
697 cryptoapi_report_error("CryptImportPublicKeyInfo");
698 CryptReleaseContext(pk
->prov
, 0);
700 CertFreeCertificateContext(cc
);
704 CertFreeCertificateContext(cc
);
710 int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key
*key
,
711 const u8
*in
, size_t inlen
,
712 u8
*out
, size_t *outlen
)
720 tmp
= malloc(*outlen
);
724 os_memcpy(tmp
, in
, inlen
);
726 if (!CryptEncrypt(key
->rsa
, 0, TRUE
, 0, tmp
, &clen
, *outlen
)) {
727 wpa_printf(MSG_DEBUG
, "CryptoAPI: Failed to encrypt using "
728 "public key: %d", (int) GetLastError());
735 /* Reverse the output */
736 for (i
= 0; i
< *outlen
; i
++)
737 out
[i
] = tmp
[*outlen
- 1 - i
];
745 int crypto_private_key_sign_pkcs1(struct crypto_private_key
*key
,
746 const u8
*in
, size_t inlen
,
747 u8
*out
, size_t *outlen
)
754 void crypto_public_key_free(struct crypto_public_key
*key
)
757 CryptDestroyKey(key
->rsa
);
758 CryptReleaseContext(key
->prov
, 0);
764 void crypto_private_key_free(struct crypto_private_key
*key
)
767 CryptDestroyKey(key
->rsa
);
768 CryptReleaseContext(key
->prov
, 0);
774 int crypto_global_init(void)
776 return mingw_load_crypto_func();
780 void crypto_global_deinit(void)
784 #endif /* CONFIG_TLS_INTERNAL */
786 #endif /* EAP_TLS_FUNCS */