2 * Crypto wrapper for Microsoft CryptoAPI
3 * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
16 #ifndef MS_ENH_RSA_AES_PROV
18 #define MS_ENH_RSA_AES_PROV \
19 L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
21 #define MS_ENH_RSA_AES_PROV \
22 "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
24 #endif /* MS_ENH_RSA_AES_PROV */
27 #define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
30 #ifdef __MINGW32_VERSION
32 * MinGW does not yet include all the needed definitions for CryptoAPI, so
33 * define here whatever extra is needed.
37 (*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
38 PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
39 = NULL; /* to be loaded from crypt32.dll */
42 static int mingw_load_crypto_func(void)
46 /* MinGW does not yet have full CryptoAPI support, so load the needed
49 if (CryptImportPublicKeyInfo)
52 dll = LoadLibrary("crypt32");
54 wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
59 CryptImportPublicKeyInfo = GetProcAddress(
60 dll, "CryptImportPublicKeyInfo");
61 if (CryptImportPublicKeyInfo == NULL) {
62 wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
63 "CryptImportPublicKeyInfo() address from "
71 #else /* __MINGW32_VERSION */
73 static int mingw_load_crypto_func(void)
78 #endif /* __MINGW32_VERSION */
81 static void cryptoapi_report_error(const char *msg)
84 DWORD err = GetLastError();
86 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
87 FORMAT_MESSAGE_FROM_SYSTEM,
88 NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
89 wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
94 if (*pos == '\n' || *pos == '\r') {
101 wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
106 int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
107 const u8 *addr[], const size_t *len, u8 *mac)
115 if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
116 cryptoapi_report_error("CryptAcquireContext");
120 if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
121 cryptoapi_report_error("CryptCreateHash");
122 CryptReleaseContext(prov, 0);
126 for (i = 0; i < num_elem; i++) {
127 if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
128 cryptoapi_report_error("CryptHashData");
129 CryptDestroyHash(hash);
130 CryptReleaseContext(prov, 0);
135 if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
136 cryptoapi_report_error("CryptGetHashParam");
140 CryptDestroyHash(hash);
141 CryptReleaseContext(prov, 0);
147 int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
149 return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
153 void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
165 DWORD mode = CRYPT_MODE_ECB;
167 key_blob.hdr.bType = PLAINTEXTKEYBLOB;
168 key_blob.hdr.bVersion = CUR_BLOB_VERSION;
169 key_blob.hdr.reserved = 0;
170 key_blob.hdr.aiKeyAlg = CALG_DES;
173 /* Add parity bits to the key */
175 for (i = 0; i < 7; i++) {
177 key_blob.key[i] = (tmp >> i) | next | 1;
178 next = tmp << (7 - i);
180 key_blob.key[i] = next | 1;
182 if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
183 CRYPT_VERIFYCONTEXT)) {
184 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
185 "%d", (int) GetLastError());
189 if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
191 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
192 (int) GetLastError());
193 CryptReleaseContext(prov, 0);
197 if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
198 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
199 "failed: %d", (int) GetLastError());
200 CryptDestroyKey(ckey);
201 CryptReleaseContext(prov, 0);
205 os_memcpy(cypher, clear, 8);
207 if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
208 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
209 (int) GetLastError());
210 os_memset(cypher, 0, 8);
213 CryptDestroyKey(ckey);
214 CryptReleaseContext(prov, 0);
218 int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
220 return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
224 int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
226 return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
236 void * aes_encrypt_init(const u8 *key, size_t len)
238 struct aes_context *akey;
244 DWORD mode = CRYPT_MODE_ECB;
249 key_blob.hdr.bType = PLAINTEXTKEYBLOB;
250 key_blob.hdr.bVersion = CUR_BLOB_VERSION;
251 key_blob.hdr.reserved = 0;
252 key_blob.hdr.aiKeyAlg = CALG_AES_128;
254 os_memcpy(key_blob.key, key, len);
256 akey = os_zalloc(sizeof(*akey));
260 if (!CryptAcquireContext(&akey->prov, NULL,
261 MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
262 CRYPT_VERIFYCONTEXT)) {
263 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
264 "%d", (int) GetLastError());
269 if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
270 0, 0, &akey->ckey)) {
271 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
272 (int) GetLastError());
273 CryptReleaseContext(akey->prov, 0);
278 if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
279 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
280 "failed: %d", (int) GetLastError());
281 CryptDestroyKey(akey->ckey);
282 CryptReleaseContext(akey->prov, 0);
291 void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
293 struct aes_context *akey = ctx;
296 os_memcpy(crypt, plain, 16);
298 if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
299 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
300 (int) GetLastError());
301 os_memset(crypt, 0, 16);
306 void aes_encrypt_deinit(void *ctx)
308 struct aes_context *akey = ctx;
310 CryptDestroyKey(akey->ckey);
311 CryptReleaseContext(akey->prov, 0);
317 void * aes_decrypt_init(const u8 *key, size_t len)
319 return aes_encrypt_init(key, len);
323 void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
325 struct aes_context *akey = ctx;
328 os_memcpy(plain, crypt, 16);
331 if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
332 wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
333 (int) GetLastError());
338 void aes_decrypt_deinit(void *ctx)
340 aes_encrypt_deinit(ctx);
345 enum crypto_hash_alg alg;
352 struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
355 struct crypto_hash *ctx;
363 os_memset(&key_blob, 0, sizeof(key_blob));
365 case CRYPTO_HASH_ALG_MD5:
368 case CRYPTO_HASH_ALG_SHA1:
371 case CRYPTO_HASH_ALG_HMAC_MD5:
372 case CRYPTO_HASH_ALG_HMAC_SHA1:
374 key_blob.hdr.bType = PLAINTEXTKEYBLOB;
375 key_blob.hdr.bVersion = CUR_BLOB_VERSION;
376 key_blob.hdr.reserved = 0;
378 * Note: RC2 is not really used, but that can be used to
379 * import HMAC keys of up to 16 byte long.
380 * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
381 * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
383 key_blob.hdr.aiKeyAlg = CALG_RC2;
384 key_blob.len = key_len;
385 if (key_len > sizeof(key_blob.key))
387 os_memcpy(key_blob.key, key, key_len);
393 ctx = os_zalloc(sizeof(*ctx));
399 if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
400 cryptoapi_report_error("CryptAcquireContext");
405 if (calg == CALG_HMAC) {
406 #ifndef CRYPT_IPSEC_HMAC_KEY
407 #define CRYPT_IPSEC_HMAC_KEY 0x00000100
409 if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
410 sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
412 cryptoapi_report_error("CryptImportKey");
413 CryptReleaseContext(ctx->prov, 0);
419 if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
420 cryptoapi_report_error("CryptCreateHash");
421 CryptReleaseContext(ctx->prov, 0);
426 if (calg == CALG_HMAC) {
428 os_memset(&info, 0, sizeof(info));
430 case CRYPTO_HASH_ALG_HMAC_MD5:
431 info.HashAlgid = CALG_MD5;
433 case CRYPTO_HASH_ALG_HMAC_SHA1:
434 info.HashAlgid = CALG_SHA;
441 if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
443 cryptoapi_report_error("CryptSetHashParam");
444 CryptDestroyHash(ctx->hash);
445 CryptReleaseContext(ctx->prov, 0);
455 void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
457 if (ctx == NULL || ctx->error)
460 if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
461 cryptoapi_report_error("CryptHashData");
467 int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
475 if (mac == NULL || len == NULL)
484 if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
485 cryptoapi_report_error("CryptGetHashParam");
491 if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
492 ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
493 CryptDestroyKey(ctx->key);
501 struct crypto_cipher {
507 struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
508 const u8 *iv, const u8 *key,
511 struct crypto_cipher *ctx;
517 DWORD mode = CRYPT_MODE_CBC;
519 key_blob.hdr.bType = PLAINTEXTKEYBLOB;
520 key_blob.hdr.bVersion = CUR_BLOB_VERSION;
521 key_blob.hdr.reserved = 0;
522 key_blob.len = key_len;
523 if (key_len > sizeof(key_blob.key))
525 os_memcpy(key_blob.key, key, key_len);
528 case CRYPTO_CIPHER_ALG_AES:
530 key_blob.hdr.aiKeyAlg = CALG_AES_256;
531 else if (key_len == 24)
532 key_blob.hdr.aiKeyAlg = CALG_AES_192;
534 key_blob.hdr.aiKeyAlg = CALG_AES_128;
536 case CRYPTO_CIPHER_ALG_3DES:
537 key_blob.hdr.aiKeyAlg = CALG_3DES;
539 case CRYPTO_CIPHER_ALG_DES:
540 key_blob.hdr.aiKeyAlg = CALG_DES;
542 case CRYPTO_CIPHER_ALG_RC2:
543 key_blob.hdr.aiKeyAlg = CALG_RC2;
545 case CRYPTO_CIPHER_ALG_RC4:
546 key_blob.hdr.aiKeyAlg = CALG_RC4;
552 ctx = os_zalloc(sizeof(*ctx));
556 if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
557 PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
558 cryptoapi_report_error("CryptAcquireContext");
562 if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
563 sizeof(key_blob), 0, 0, &ctx->key)) {
564 cryptoapi_report_error("CryptImportKey");
568 if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
569 cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
573 if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
574 cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
581 CryptDestroyKey(ctx->key);
583 CryptReleaseContext(ctx->prov, 0);
590 int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
591 u8 *crypt, size_t len)
595 os_memcpy(crypt, plain, len);
597 if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
598 cryptoapi_report_error("CryptEncrypt");
599 os_memset(crypt, 0, len);
607 int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
608 u8 *plain, size_t len)
612 os_memcpy(plain, crypt, len);
614 if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
615 cryptoapi_report_error("CryptDecrypt");
623 void crypto_cipher_deinit(struct crypto_cipher *ctx)
625 CryptDestroyKey(ctx->key);
626 CryptReleaseContext(ctx->prov, 0);
631 struct crypto_public_key {
636 struct crypto_private_key {
642 struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
644 /* Use crypto_public_key_from_cert() instead. */
649 struct crypto_private_key * crypto_private_key_import(const u8 *key,
658 struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
661 struct crypto_public_key *pk;
664 pk = os_zalloc(sizeof(*pk));
668 cc = CertCreateCertificateContext(X509_ASN_ENCODING |
669 PKCS_7_ASN_ENCODING, buf, len);
671 cryptoapi_report_error("CryptCreateCertificateContext");
676 if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
678 cryptoapi_report_error("CryptAcquireContext");
680 CertFreeCertificateContext(cc);
684 if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
686 &cc->pCertInfo->SubjectPublicKeyInfo,
688 cryptoapi_report_error("CryptImportPublicKeyInfo");
689 CryptReleaseContext(pk->prov, 0);
691 CertFreeCertificateContext(cc);
695 CertFreeCertificateContext(cc);
701 int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
702 const u8 *in, size_t inlen,
703 u8 *out, size_t *outlen)
711 tmp = malloc(*outlen);
715 os_memcpy(tmp, in, inlen);
717 if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
718 wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
719 "public key: %d", (int) GetLastError());
726 /* Reverse the output */
727 for (i = 0; i < *outlen; i++)
728 out[i] = tmp[*outlen - 1 - i];
736 int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
737 const u8 *in, size_t inlen,
738 u8 *out, size_t *outlen)
745 void crypto_public_key_free(struct crypto_public_key *key)
748 CryptDestroyKey(key->rsa);
749 CryptReleaseContext(key->prov, 0);
755 void crypto_private_key_free(struct crypto_private_key *key)
758 CryptDestroyKey(key->rsa);
759 CryptReleaseContext(key->prov, 0);
765 int crypto_global_init(void)
767 return mingw_load_crypto_func();
771 void crypto_global_deinit(void)
776 int crypto_mod_exp(const u8 *base, size_t base_len,
777 const u8 *power, size_t power_len,
778 const u8 *modulus, size_t modulus_len,
779 u8 *result, size_t *result_len)