1189251Ssam/* 2209158Srpaulo * Crypto wrapper for Microsoft CryptoAPI 3209158Srpaulo * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam#include <windows.h> 11189251Ssam#include <wincrypt.h> 12189251Ssam 13189251Ssam#include "common.h" 14189251Ssam#include "crypto.h" 15189251Ssam 16189251Ssam#ifndef MS_ENH_RSA_AES_PROV 17189251Ssam#ifdef UNICODE 18189251Ssam#define MS_ENH_RSA_AES_PROV \ 19189251SsamL"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" 20189251Ssam#else 21189251Ssam#define MS_ENH_RSA_AES_PROV \ 22189251Ssam"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" 23189251Ssam#endif 24189251Ssam#endif /* MS_ENH_RSA_AES_PROV */ 25189251Ssam 26189251Ssam#ifndef CALG_HMAC 27189251Ssam#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) 28189251Ssam#endif 29189251Ssam 30189251Ssam#ifdef __MINGW32_VERSION 31189251Ssam/* 32189251Ssam * MinGW does not yet include all the needed definitions for CryptoAPI, so 33189251Ssam * define here whatever extra is needed. 34189251Ssam */ 35189251Ssam 36189251Ssamstatic BOOL WINAPI 37189251Ssam(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType, 38189251Ssam PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey) 39189251Ssam= NULL; /* to be loaded from crypt32.dll */ 40189251Ssam 41189251Ssam 42189251Ssamstatic int mingw_load_crypto_func(void) 43189251Ssam{ 44189251Ssam HINSTANCE dll; 45189251Ssam 46189251Ssam /* MinGW does not yet have full CryptoAPI support, so load the needed 47189251Ssam * function here. */ 48189251Ssam 49209158Srpaulo if (CryptImportPublicKeyInfo) 50189251Ssam return 0; 51189251Ssam 52189251Ssam dll = LoadLibrary("crypt32"); 53189251Ssam if (dll == NULL) { 54189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 " 55189251Ssam "library"); 56189251Ssam return -1; 57189251Ssam } 58189251Ssam 59189251Ssam CryptImportPublicKeyInfo = GetProcAddress( 60189251Ssam dll, "CryptImportPublicKeyInfo"); 61189251Ssam if (CryptImportPublicKeyInfo == NULL) { 62189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get " 63189251Ssam "CryptImportPublicKeyInfo() address from " 64189251Ssam "crypt32 library"); 65189251Ssam return -1; 66189251Ssam } 67189251Ssam 68189251Ssam return 0; 69189251Ssam} 70189251Ssam 71189251Ssam#else /* __MINGW32_VERSION */ 72189251Ssam 73189251Ssamstatic int mingw_load_crypto_func(void) 74189251Ssam{ 75189251Ssam return 0; 76189251Ssam} 77189251Ssam 78189251Ssam#endif /* __MINGW32_VERSION */ 79189251Ssam 80189251Ssam 81189251Ssamstatic void cryptoapi_report_error(const char *msg) 82189251Ssam{ 83189251Ssam char *s, *pos; 84189251Ssam DWORD err = GetLastError(); 85189251Ssam 86189251Ssam if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 87189251Ssam FORMAT_MESSAGE_FROM_SYSTEM, 88189251Ssam NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) { 89189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err); 90189251Ssam } 91189251Ssam 92189251Ssam pos = s; 93189251Ssam while (*pos) { 94189251Ssam if (*pos == '\n' || *pos == '\r') { 95189251Ssam *pos = '\0'; 96189251Ssam break; 97189251Ssam } 98189251Ssam pos++; 99189251Ssam } 100189251Ssam 101189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s); 102189251Ssam LocalFree(s); 103189251Ssam} 104189251Ssam 105189251Ssam 106189251Ssamint cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem, 107189251Ssam const u8 *addr[], const size_t *len, u8 *mac) 108189251Ssam{ 109189251Ssam HCRYPTPROV prov; 110189251Ssam HCRYPTHASH hash; 111189251Ssam size_t i; 112189251Ssam DWORD hlen; 113189251Ssam int ret = 0; 114189251Ssam 115189251Ssam if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) { 116189251Ssam cryptoapi_report_error("CryptAcquireContext"); 117189251Ssam return -1; 118189251Ssam } 119189251Ssam 120189251Ssam if (!CryptCreateHash(prov, alg, 0, 0, &hash)) { 121189251Ssam cryptoapi_report_error("CryptCreateHash"); 122189251Ssam CryptReleaseContext(prov, 0); 123189251Ssam return -1; 124189251Ssam } 125189251Ssam 126189251Ssam for (i = 0; i < num_elem; i++) { 127189251Ssam if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) { 128189251Ssam cryptoapi_report_error("CryptHashData"); 129189251Ssam CryptDestroyHash(hash); 130189251Ssam CryptReleaseContext(prov, 0); 131189251Ssam } 132189251Ssam } 133189251Ssam 134189251Ssam hlen = hash_len; 135189251Ssam if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) { 136189251Ssam cryptoapi_report_error("CryptGetHashParam"); 137189251Ssam ret = -1; 138189251Ssam } 139189251Ssam 140189251Ssam CryptDestroyHash(hash); 141189251Ssam CryptReleaseContext(prov, 0); 142189251Ssam 143189251Ssam return ret; 144189251Ssam} 145189251Ssam 146189251Ssam 147214734Srpauloint md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) 148189251Ssam{ 149214734Srpaulo return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac); 150189251Ssam} 151189251Ssam 152189251Ssam 153189251Ssamvoid des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) 154189251Ssam{ 155189251Ssam u8 next, tmp; 156189251Ssam int i; 157189251Ssam HCRYPTPROV prov; 158189251Ssam HCRYPTKEY ckey; 159189251Ssam DWORD dlen; 160189251Ssam struct { 161189251Ssam BLOBHEADER hdr; 162189251Ssam DWORD len; 163189251Ssam BYTE key[8]; 164189251Ssam } key_blob; 165189251Ssam DWORD mode = CRYPT_MODE_ECB; 166189251Ssam 167189251Ssam key_blob.hdr.bType = PLAINTEXTKEYBLOB; 168189251Ssam key_blob.hdr.bVersion = CUR_BLOB_VERSION; 169189251Ssam key_blob.hdr.reserved = 0; 170189251Ssam key_blob.hdr.aiKeyAlg = CALG_DES; 171189251Ssam key_blob.len = 8; 172189251Ssam 173189251Ssam /* Add parity bits to the key */ 174189251Ssam next = 0; 175189251Ssam for (i = 0; i < 7; i++) { 176189251Ssam tmp = key[i]; 177189251Ssam key_blob.key[i] = (tmp >> i) | next | 1; 178189251Ssam next = tmp << (7 - i); 179189251Ssam } 180189251Ssam key_blob.key[i] = next | 1; 181189251Ssam 182189251Ssam if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 183189251Ssam CRYPT_VERIFYCONTEXT)) { 184189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " 185189251Ssam "%d", (int) GetLastError()); 186189251Ssam return; 187189251Ssam } 188189251Ssam 189189251Ssam if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0, 190189251Ssam &ckey)) { 191189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", 192189251Ssam (int) GetLastError()); 193189251Ssam CryptReleaseContext(prov, 0); 194189251Ssam return; 195189251Ssam } 196189251Ssam 197189251Ssam if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) { 198189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " 199189251Ssam "failed: %d", (int) GetLastError()); 200189251Ssam CryptDestroyKey(ckey); 201189251Ssam CryptReleaseContext(prov, 0); 202189251Ssam return; 203189251Ssam } 204189251Ssam 205189251Ssam os_memcpy(cypher, clear, 8); 206189251Ssam dlen = 8; 207189251Ssam if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) { 208189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", 209189251Ssam (int) GetLastError()); 210189251Ssam os_memset(cypher, 0, 8); 211189251Ssam } 212189251Ssam 213189251Ssam CryptDestroyKey(ckey); 214189251Ssam CryptReleaseContext(prov, 0); 215189251Ssam} 216189251Ssam 217189251Ssam 218214734Srpauloint md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) 219189251Ssam{ 220214734Srpaulo return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac); 221189251Ssam} 222189251Ssam 223189251Ssam 224214734Srpauloint sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) 225189251Ssam{ 226214734Srpaulo return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac); 227189251Ssam} 228189251Ssam 229189251Ssam 230189251Ssamstruct aes_context { 231189251Ssam HCRYPTPROV prov; 232189251Ssam HCRYPTKEY ckey; 233189251Ssam}; 234189251Ssam 235189251Ssam 236189251Ssamvoid * aes_encrypt_init(const u8 *key, size_t len) 237189251Ssam{ 238189251Ssam struct aes_context *akey; 239189251Ssam struct { 240189251Ssam BLOBHEADER hdr; 241189251Ssam DWORD len; 242189251Ssam BYTE key[16]; 243189251Ssam } key_blob; 244189251Ssam DWORD mode = CRYPT_MODE_ECB; 245189251Ssam 246189251Ssam if (len != 16) 247189251Ssam return NULL; 248189251Ssam 249189251Ssam key_blob.hdr.bType = PLAINTEXTKEYBLOB; 250189251Ssam key_blob.hdr.bVersion = CUR_BLOB_VERSION; 251189251Ssam key_blob.hdr.reserved = 0; 252189251Ssam key_blob.hdr.aiKeyAlg = CALG_AES_128; 253189251Ssam key_blob.len = len; 254189251Ssam os_memcpy(key_blob.key, key, len); 255189251Ssam 256189251Ssam akey = os_zalloc(sizeof(*akey)); 257189251Ssam if (akey == NULL) 258189251Ssam return NULL; 259189251Ssam 260189251Ssam if (!CryptAcquireContext(&akey->prov, NULL, 261189251Ssam MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 262189251Ssam CRYPT_VERIFYCONTEXT)) { 263189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " 264189251Ssam "%d", (int) GetLastError()); 265189251Ssam os_free(akey); 266189251Ssam return NULL; 267189251Ssam } 268189251Ssam 269189251Ssam if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob), 270189251Ssam 0, 0, &akey->ckey)) { 271189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", 272189251Ssam (int) GetLastError()); 273189251Ssam CryptReleaseContext(akey->prov, 0); 274189251Ssam os_free(akey); 275189251Ssam return NULL; 276189251Ssam } 277189251Ssam 278189251Ssam if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) { 279189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " 280189251Ssam "failed: %d", (int) GetLastError()); 281189251Ssam CryptDestroyKey(akey->ckey); 282189251Ssam CryptReleaseContext(akey->prov, 0); 283189251Ssam os_free(akey); 284189251Ssam return NULL; 285189251Ssam } 286189251Ssam 287189251Ssam return akey; 288189251Ssam} 289189251Ssam 290189251Ssam 291189251Ssamvoid aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) 292189251Ssam{ 293189251Ssam struct aes_context *akey = ctx; 294189251Ssam DWORD dlen; 295189251Ssam 296189251Ssam os_memcpy(crypt, plain, 16); 297189251Ssam dlen = 16; 298189251Ssam if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) { 299189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", 300189251Ssam (int) GetLastError()); 301189251Ssam os_memset(crypt, 0, 16); 302189251Ssam } 303189251Ssam} 304189251Ssam 305189251Ssam 306189251Ssamvoid aes_encrypt_deinit(void *ctx) 307189251Ssam{ 308189251Ssam struct aes_context *akey = ctx; 309189251Ssam if (akey) { 310189251Ssam CryptDestroyKey(akey->ckey); 311189251Ssam CryptReleaseContext(akey->prov, 0); 312189251Ssam os_free(akey); 313189251Ssam } 314189251Ssam} 315189251Ssam 316189251Ssam 317189251Ssamvoid * aes_decrypt_init(const u8 *key, size_t len) 318189251Ssam{ 319189251Ssam return aes_encrypt_init(key, len); 320189251Ssam} 321189251Ssam 322189251Ssam 323189251Ssamvoid aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) 324189251Ssam{ 325189251Ssam struct aes_context *akey = ctx; 326189251Ssam DWORD dlen; 327189251Ssam 328189251Ssam os_memcpy(plain, crypt, 16); 329189251Ssam dlen = 16; 330189251Ssam 331189251Ssam if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) { 332189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d", 333189251Ssam (int) GetLastError()); 334189251Ssam } 335189251Ssam} 336189251Ssam 337189251Ssam 338189251Ssamvoid aes_decrypt_deinit(void *ctx) 339189251Ssam{ 340189251Ssam aes_encrypt_deinit(ctx); 341189251Ssam} 342189251Ssam 343189251Ssam 344189251Ssamstruct crypto_hash { 345189251Ssam enum crypto_hash_alg alg; 346189251Ssam int error; 347189251Ssam HCRYPTPROV prov; 348189251Ssam HCRYPTHASH hash; 349189251Ssam HCRYPTKEY key; 350189251Ssam}; 351189251Ssam 352189251Ssamstruct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, 353189251Ssam size_t key_len) 354189251Ssam{ 355189251Ssam struct crypto_hash *ctx; 356189251Ssam ALG_ID calg; 357189251Ssam struct { 358189251Ssam BLOBHEADER hdr; 359189251Ssam DWORD len; 360189251Ssam BYTE key[32]; 361189251Ssam } key_blob; 362189251Ssam 363189251Ssam os_memset(&key_blob, 0, sizeof(key_blob)); 364189251Ssam switch (alg) { 365189251Ssam case CRYPTO_HASH_ALG_MD5: 366189251Ssam calg = CALG_MD5; 367189251Ssam break; 368189251Ssam case CRYPTO_HASH_ALG_SHA1: 369189251Ssam calg = CALG_SHA; 370189251Ssam break; 371189251Ssam case CRYPTO_HASH_ALG_HMAC_MD5: 372189251Ssam case CRYPTO_HASH_ALG_HMAC_SHA1: 373189251Ssam calg = CALG_HMAC; 374189251Ssam key_blob.hdr.bType = PLAINTEXTKEYBLOB; 375189251Ssam key_blob.hdr.bVersion = CUR_BLOB_VERSION; 376189251Ssam key_blob.hdr.reserved = 0; 377189251Ssam /* 378189251Ssam * Note: RC2 is not really used, but that can be used to 379189251Ssam * import HMAC keys of up to 16 byte long. 380189251Ssam * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to 381189251Ssam * be able to import longer keys (HMAC-SHA1 uses 20-byte key). 382189251Ssam */ 383189251Ssam key_blob.hdr.aiKeyAlg = CALG_RC2; 384189251Ssam key_blob.len = key_len; 385189251Ssam if (key_len > sizeof(key_blob.key)) 386189251Ssam return NULL; 387189251Ssam os_memcpy(key_blob.key, key, key_len); 388189251Ssam break; 389189251Ssam default: 390189251Ssam return NULL; 391189251Ssam } 392189251Ssam 393189251Ssam ctx = os_zalloc(sizeof(*ctx)); 394189251Ssam if (ctx == NULL) 395189251Ssam return NULL; 396189251Ssam 397189251Ssam ctx->alg = alg; 398189251Ssam 399189251Ssam if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) { 400189251Ssam cryptoapi_report_error("CryptAcquireContext"); 401189251Ssam os_free(ctx); 402189251Ssam return NULL; 403189251Ssam } 404189251Ssam 405189251Ssam if (calg == CALG_HMAC) { 406189251Ssam#ifndef CRYPT_IPSEC_HMAC_KEY 407189251Ssam#define CRYPT_IPSEC_HMAC_KEY 0x00000100 408189251Ssam#endif 409189251Ssam if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, 410189251Ssam sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY, 411189251Ssam &ctx->key)) { 412189251Ssam cryptoapi_report_error("CryptImportKey"); 413189251Ssam CryptReleaseContext(ctx->prov, 0); 414189251Ssam os_free(ctx); 415189251Ssam return NULL; 416189251Ssam } 417189251Ssam } 418189251Ssam 419189251Ssam if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) { 420189251Ssam cryptoapi_report_error("CryptCreateHash"); 421189251Ssam CryptReleaseContext(ctx->prov, 0); 422189251Ssam os_free(ctx); 423189251Ssam return NULL; 424189251Ssam } 425189251Ssam 426189251Ssam if (calg == CALG_HMAC) { 427189251Ssam HMAC_INFO info; 428189251Ssam os_memset(&info, 0, sizeof(info)); 429189251Ssam switch (alg) { 430189251Ssam case CRYPTO_HASH_ALG_HMAC_MD5: 431189251Ssam info.HashAlgid = CALG_MD5; 432189251Ssam break; 433189251Ssam case CRYPTO_HASH_ALG_HMAC_SHA1: 434189251Ssam info.HashAlgid = CALG_SHA; 435189251Ssam break; 436189251Ssam default: 437189251Ssam /* unreachable */ 438189251Ssam break; 439189251Ssam } 440189251Ssam 441189251Ssam if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info, 442189251Ssam 0)) { 443189251Ssam cryptoapi_report_error("CryptSetHashParam"); 444189251Ssam CryptDestroyHash(ctx->hash); 445189251Ssam CryptReleaseContext(ctx->prov, 0); 446189251Ssam os_free(ctx); 447189251Ssam return NULL; 448189251Ssam } 449189251Ssam } 450189251Ssam 451189251Ssam return ctx; 452189251Ssam} 453189251Ssam 454189251Ssam 455189251Ssamvoid crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) 456189251Ssam{ 457189251Ssam if (ctx == NULL || ctx->error) 458189251Ssam return; 459189251Ssam 460189251Ssam if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) { 461189251Ssam cryptoapi_report_error("CryptHashData"); 462189251Ssam ctx->error = 1; 463189251Ssam } 464189251Ssam} 465189251Ssam 466189251Ssam 467189251Ssamint crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) 468189251Ssam{ 469189251Ssam int ret = 0; 470189251Ssam DWORD hlen; 471189251Ssam 472189251Ssam if (ctx == NULL) 473189251Ssam return -2; 474189251Ssam 475189251Ssam if (mac == NULL || len == NULL) 476189251Ssam goto done; 477189251Ssam 478189251Ssam if (ctx->error) { 479189251Ssam ret = -2; 480189251Ssam goto done; 481189251Ssam } 482189251Ssam 483189251Ssam hlen = *len; 484189251Ssam if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) { 485189251Ssam cryptoapi_report_error("CryptGetHashParam"); 486189251Ssam ret = -2; 487189251Ssam } 488189251Ssam *len = hlen; 489189251Ssam 490189251Ssamdone: 491189251Ssam if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 || 492189251Ssam ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5) 493189251Ssam CryptDestroyKey(ctx->key); 494189251Ssam 495189251Ssam os_free(ctx); 496189251Ssam 497189251Ssam return ret; 498189251Ssam} 499189251Ssam 500189251Ssam 501189251Ssamstruct crypto_cipher { 502189251Ssam HCRYPTPROV prov; 503189251Ssam HCRYPTKEY key; 504189251Ssam}; 505189251Ssam 506189251Ssam 507189251Ssamstruct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, 508189251Ssam const u8 *iv, const u8 *key, 509189251Ssam size_t key_len) 510189251Ssam{ 511189251Ssam struct crypto_cipher *ctx; 512189251Ssam struct { 513189251Ssam BLOBHEADER hdr; 514189251Ssam DWORD len; 515189251Ssam BYTE key[32]; 516189251Ssam } key_blob; 517189251Ssam DWORD mode = CRYPT_MODE_CBC; 518189251Ssam 519189251Ssam key_blob.hdr.bType = PLAINTEXTKEYBLOB; 520189251Ssam key_blob.hdr.bVersion = CUR_BLOB_VERSION; 521189251Ssam key_blob.hdr.reserved = 0; 522189251Ssam key_blob.len = key_len; 523189251Ssam if (key_len > sizeof(key_blob.key)) 524189251Ssam return NULL; 525189251Ssam os_memcpy(key_blob.key, key, key_len); 526189251Ssam 527189251Ssam switch (alg) { 528189251Ssam case CRYPTO_CIPHER_ALG_AES: 529189251Ssam if (key_len == 32) 530189251Ssam key_blob.hdr.aiKeyAlg = CALG_AES_256; 531189251Ssam else if (key_len == 24) 532189251Ssam key_blob.hdr.aiKeyAlg = CALG_AES_192; 533189251Ssam else 534189251Ssam key_blob.hdr.aiKeyAlg = CALG_AES_128; 535189251Ssam break; 536189251Ssam case CRYPTO_CIPHER_ALG_3DES: 537189251Ssam key_blob.hdr.aiKeyAlg = CALG_3DES; 538189251Ssam break; 539189251Ssam case CRYPTO_CIPHER_ALG_DES: 540189251Ssam key_blob.hdr.aiKeyAlg = CALG_DES; 541189251Ssam break; 542189251Ssam case CRYPTO_CIPHER_ALG_RC2: 543189251Ssam key_blob.hdr.aiKeyAlg = CALG_RC2; 544189251Ssam break; 545189251Ssam case CRYPTO_CIPHER_ALG_RC4: 546189251Ssam key_blob.hdr.aiKeyAlg = CALG_RC4; 547189251Ssam break; 548189251Ssam default: 549189251Ssam return NULL; 550189251Ssam } 551189251Ssam 552189251Ssam ctx = os_zalloc(sizeof(*ctx)); 553189251Ssam if (ctx == NULL) 554189251Ssam return NULL; 555189251Ssam 556189251Ssam if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV, 557189251Ssam PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { 558189251Ssam cryptoapi_report_error("CryptAcquireContext"); 559189251Ssam goto fail1; 560189251Ssam } 561189251Ssam 562189251Ssam if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, 563189251Ssam sizeof(key_blob), 0, 0, &ctx->key)) { 564189251Ssam cryptoapi_report_error("CryptImportKey"); 565189251Ssam goto fail2; 566189251Ssam } 567189251Ssam 568189251Ssam if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) { 569189251Ssam cryptoapi_report_error("CryptSetKeyParam(KP_MODE)"); 570189251Ssam goto fail3; 571189251Ssam } 572189251Ssam 573189251Ssam if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) { 574189251Ssam cryptoapi_report_error("CryptSetKeyParam(KP_IV)"); 575189251Ssam goto fail3; 576189251Ssam } 577189251Ssam 578189251Ssam return ctx; 579189251Ssam 580189251Ssamfail3: 581189251Ssam CryptDestroyKey(ctx->key); 582189251Ssamfail2: 583189251Ssam CryptReleaseContext(ctx->prov, 0); 584189251Ssamfail1: 585189251Ssam os_free(ctx); 586189251Ssam return NULL; 587189251Ssam} 588189251Ssam 589189251Ssam 590189251Ssamint crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, 591189251Ssam u8 *crypt, size_t len) 592189251Ssam{ 593189251Ssam DWORD dlen; 594189251Ssam 595189251Ssam os_memcpy(crypt, plain, len); 596189251Ssam dlen = len; 597189251Ssam if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) { 598189251Ssam cryptoapi_report_error("CryptEncrypt"); 599189251Ssam os_memset(crypt, 0, len); 600189251Ssam return -1; 601189251Ssam } 602189251Ssam 603189251Ssam return 0; 604189251Ssam} 605189251Ssam 606189251Ssam 607189251Ssamint crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, 608189251Ssam u8 *plain, size_t len) 609189251Ssam{ 610189251Ssam DWORD dlen; 611189251Ssam 612189251Ssam os_memcpy(plain, crypt, len); 613189251Ssam dlen = len; 614189251Ssam if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) { 615189251Ssam cryptoapi_report_error("CryptDecrypt"); 616189251Ssam return -1; 617189251Ssam } 618189251Ssam 619189251Ssam return 0; 620189251Ssam} 621189251Ssam 622189251Ssam 623189251Ssamvoid crypto_cipher_deinit(struct crypto_cipher *ctx) 624189251Ssam{ 625189251Ssam CryptDestroyKey(ctx->key); 626189251Ssam CryptReleaseContext(ctx->prov, 0); 627189251Ssam os_free(ctx); 628189251Ssam} 629189251Ssam 630189251Ssam 631189251Ssamstruct crypto_public_key { 632189251Ssam HCRYPTPROV prov; 633189251Ssam HCRYPTKEY rsa; 634189251Ssam}; 635189251Ssam 636189251Ssamstruct crypto_private_key { 637189251Ssam HCRYPTPROV prov; 638189251Ssam HCRYPTKEY rsa; 639189251Ssam}; 640189251Ssam 641189251Ssam 642189251Ssamstruct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) 643189251Ssam{ 644189251Ssam /* Use crypto_public_key_from_cert() instead. */ 645189251Ssam return NULL; 646189251Ssam} 647189251Ssam 648189251Ssam 649189251Ssamstruct crypto_private_key * crypto_private_key_import(const u8 *key, 650214734Srpaulo size_t len, 651214734Srpaulo const char *passwd) 652189251Ssam{ 653189251Ssam /* TODO */ 654189251Ssam return NULL; 655189251Ssam} 656189251Ssam 657189251Ssam 658189251Ssamstruct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, 659189251Ssam size_t len) 660189251Ssam{ 661189251Ssam struct crypto_public_key *pk; 662189251Ssam PCCERT_CONTEXT cc; 663189251Ssam 664189251Ssam pk = os_zalloc(sizeof(*pk)); 665189251Ssam if (pk == NULL) 666189251Ssam return NULL; 667189251Ssam 668189251Ssam cc = CertCreateCertificateContext(X509_ASN_ENCODING | 669189251Ssam PKCS_7_ASN_ENCODING, buf, len); 670189251Ssam if (!cc) { 671189251Ssam cryptoapi_report_error("CryptCreateCertificateContext"); 672189251Ssam os_free(pk); 673189251Ssam return NULL; 674189251Ssam } 675189251Ssam 676189251Ssam if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, 677189251Ssam 0)) { 678189251Ssam cryptoapi_report_error("CryptAcquireContext"); 679189251Ssam os_free(pk); 680189251Ssam CertFreeCertificateContext(cc); 681189251Ssam return NULL; 682189251Ssam } 683189251Ssam 684189251Ssam if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING | 685189251Ssam PKCS_7_ASN_ENCODING, 686189251Ssam &cc->pCertInfo->SubjectPublicKeyInfo, 687189251Ssam &pk->rsa)) { 688189251Ssam cryptoapi_report_error("CryptImportPublicKeyInfo"); 689189251Ssam CryptReleaseContext(pk->prov, 0); 690189251Ssam os_free(pk); 691189251Ssam CertFreeCertificateContext(cc); 692189251Ssam return NULL; 693189251Ssam } 694189251Ssam 695189251Ssam CertFreeCertificateContext(cc); 696189251Ssam 697189251Ssam return pk; 698189251Ssam} 699189251Ssam 700189251Ssam 701189251Ssamint crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, 702189251Ssam const u8 *in, size_t inlen, 703189251Ssam u8 *out, size_t *outlen) 704189251Ssam{ 705189251Ssam DWORD clen; 706189251Ssam u8 *tmp; 707189251Ssam size_t i; 708189251Ssam 709189251Ssam if (*outlen < inlen) 710189251Ssam return -1; 711189251Ssam tmp = malloc(*outlen); 712189251Ssam if (tmp == NULL) 713189251Ssam return -1; 714189251Ssam 715189251Ssam os_memcpy(tmp, in, inlen); 716189251Ssam clen = inlen; 717189251Ssam if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) { 718189251Ssam wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using " 719189251Ssam "public key: %d", (int) GetLastError()); 720189251Ssam os_free(tmp); 721189251Ssam return -1; 722189251Ssam } 723189251Ssam 724189251Ssam *outlen = clen; 725189251Ssam 726189251Ssam /* Reverse the output */ 727189251Ssam for (i = 0; i < *outlen; i++) 728189251Ssam out[i] = tmp[*outlen - 1 - i]; 729189251Ssam 730189251Ssam os_free(tmp); 731189251Ssam 732189251Ssam return 0; 733189251Ssam} 734189251Ssam 735189251Ssam 736189251Ssamint crypto_private_key_sign_pkcs1(struct crypto_private_key *key, 737189251Ssam const u8 *in, size_t inlen, 738189251Ssam u8 *out, size_t *outlen) 739189251Ssam{ 740189251Ssam /* TODO */ 741189251Ssam return -1; 742189251Ssam} 743189251Ssam 744189251Ssam 745189251Ssamvoid crypto_public_key_free(struct crypto_public_key *key) 746189251Ssam{ 747189251Ssam if (key) { 748189251Ssam CryptDestroyKey(key->rsa); 749189251Ssam CryptReleaseContext(key->prov, 0); 750189251Ssam os_free(key); 751189251Ssam } 752189251Ssam} 753189251Ssam 754189251Ssam 755189251Ssamvoid crypto_private_key_free(struct crypto_private_key *key) 756189251Ssam{ 757189251Ssam if (key) { 758189251Ssam CryptDestroyKey(key->rsa); 759189251Ssam CryptReleaseContext(key->prov, 0); 760189251Ssam os_free(key); 761189251Ssam } 762189251Ssam} 763189251Ssam 764189251Ssam 765189251Ssamint crypto_global_init(void) 766189251Ssam{ 767189251Ssam return mingw_load_crypto_func(); 768189251Ssam} 769189251Ssam 770189251Ssam 771189251Ssamvoid crypto_global_deinit(void) 772189251Ssam{ 773189251Ssam} 774189251Ssam 775189251Ssam 776214734Srpauloint crypto_mod_exp(const u8 *base, size_t base_len, 777214734Srpaulo const u8 *power, size_t power_len, 778214734Srpaulo const u8 *modulus, size_t modulus_len, 779214734Srpaulo u8 *result, size_t *result_len) 780214734Srpaulo{ 781214734Srpaulo /* TODO */ 782214734Srpaulo return -1; 783214734Srpaulo} 784