crypto_cryptoapi.c revision 209158
1218822Sdim/* 238889Sjdp * Crypto wrapper for Microsoft CryptoAPI 3218822Sdim * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 4218822Sdim * 5218822Sdim * This program is free software; you can redistribute it and/or modify 6218822Sdim * it under the terms of the GNU General Public License version 2 as 7218822Sdim * published by the Free Software Foundation. 838889Sjdp * 9218822Sdim * Alternatively, this software may be distributed under the terms of BSD 10218822Sdim * license. 11218822Sdim * 12218822Sdim * See README and COPYING for more details. 1338889Sjdp */ 14218822Sdim 15218822Sdim#include "includes.h" 16218822Sdim#include <windows.h> 17218822Sdim#include <wincrypt.h> 18218822Sdim 19130561Sobrien#include "common.h" 20218822Sdim#include "crypto.h" 21218822Sdim 22218822Sdim#ifndef MS_ENH_RSA_AES_PROV 23218822Sdim#ifdef UNICODE 24218822Sdim#define MS_ENH_RSA_AES_PROV \ 2533965SjdpL"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" 26218822Sdim#else 27218822Sdim#define MS_ENH_RSA_AES_PROV \ 28218822Sdim"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" 29218822Sdim#endif 30218822Sdim#endif /* MS_ENH_RSA_AES_PROV */ 31218822Sdim 3233965Sjdp#ifndef CALG_HMAC 33218822Sdim#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) 3438889Sjdp#endif 35218822Sdim 36218822Sdim#ifdef CONFIG_TLS_INTERNAL 37218822Sdim#ifdef __MINGW32_VERSION 38218822Sdim/* 39218822Sdim * MinGW does not yet include all the needed definitions for CryptoAPI, so 4060484Sobrien * define here whatever extra is needed. 41218822Sdim */ 42218822Sdim 43218822Sdimstatic BOOL WINAPI 44218822Sdim(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType, 45218822Sdim PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey) 46218822Sdim= NULL; /* to be loaded from crypt32.dll */ 47218822Sdim 48218822Sdim 49218822Sdimstatic int mingw_load_crypto_func(void) 50218822Sdim{ 51218822Sdim HINSTANCE dll; 52218822Sdim 53218822Sdim /* MinGW does not yet have full CryptoAPI support, so load the needed 54218822Sdim * function here. */ 55218822Sdim 56218822Sdim if (CryptImportPublicKeyInfo) 57218822Sdim return 0; 58218822Sdim 59218822Sdim dll = LoadLibrary("crypt32"); 60218822Sdim if (dll == NULL) { 61218822Sdim wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 " 62218822Sdim "library"); 63218822Sdim return -1; 64218822Sdim } 65218822Sdim 66218822Sdim CryptImportPublicKeyInfo = GetProcAddress( 67218822Sdim dll, "CryptImportPublicKeyInfo"); 68218822Sdim if (CryptImportPublicKeyInfo == NULL) { 69218822Sdim wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get " 70218822Sdim "CryptImportPublicKeyInfo() address from " 71218822Sdim "crypt32 library"); 72218822Sdim return -1; 73218822Sdim } 74218822Sdim 75218822Sdim return 0; 76218822Sdim} 77218822Sdim 7860484Sobrien#else /* __MINGW32_VERSION */ 79218822Sdim 80218822Sdimstatic int mingw_load_crypto_func(void) 81218822Sdim{ 82218822Sdim return 0; 83218822Sdim} 8460484Sobrien 8560484Sobrien#endif /* __MINGW32_VERSION */ 86218822Sdim#endif /* CONFIG_TLS_INTERNAL */ 8760484Sobrien 88218822Sdim 89218822Sdimstatic void cryptoapi_report_error(const char *msg) 90218822Sdim{ 91218822Sdim char *s, *pos; 92218822Sdim DWORD err = GetLastError(); 93218822Sdim 9460484Sobrien if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 95218822Sdim FORMAT_MESSAGE_FROM_SYSTEM, 96104834Sobrien NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) { 97218822Sdim wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err); 98218822Sdim } 99104834Sobrien 100104834Sobrien pos = s; 101218822Sdim while (*pos) { 102218822Sdim if (*pos == '\n' || *pos == '\r') { 103218822Sdim *pos = '\0'; 104218822Sdim break; 105218822Sdim } 106104834Sobrien pos++; 107104834Sobrien } 108104834Sobrien 109104834Sobrien wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s); 110104834Sobrien LocalFree(s); 111104834Sobrien} 112218822Sdim 113218822Sdim 114218822Sdimint cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem, 115218822Sdim const u8 *addr[], const size_t *len, u8 *mac) 116218822Sdim{ 117218822Sdim HCRYPTPROV prov; 118104834Sobrien HCRYPTHASH hash; 119130561Sobrien size_t i; 120218822Sdim DWORD hlen; 121218822Sdim int ret = 0; 122218822Sdim 123218822Sdim if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) { 124218822Sdim cryptoapi_report_error("CryptAcquireContext"); 125218822Sdim return -1; 126130561Sobrien } 127218822Sdim 128130561Sobrien if (!CryptCreateHash(prov, alg, 0, 0, &hash)) { 129218822Sdim cryptoapi_report_error("CryptCreateHash"); 130218822Sdim CryptReleaseContext(prov, 0); 131218822Sdim return -1; 132218822Sdim } 133218822Sdim 134130561Sobrien for (i = 0; i < num_elem; i++) { 135130561Sobrien if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) { 136218822Sdim cryptoapi_report_error("CryptHashData"); 137218822Sdim CryptDestroyHash(hash); 138218822Sdim CryptReleaseContext(prov, 0); 139218822Sdim } 140218822Sdim } 141218822Sdim 142218822Sdim hlen = hash_len; 143218822Sdim if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) { 144218822Sdim cryptoapi_report_error("CryptGetHashParam"); 145218822Sdim ret = -1; 146218822Sdim } 147218822Sdim 148218822Sdim CryptDestroyHash(hash); 149218822Sdim CryptReleaseContext(prov, 0); 150218822Sdim 15138889Sjdp return ret; 152218822Sdim} 153218822Sdim 154218822Sdim 155218822Sdimvoid md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) 156218822Sdim{ 15738889Sjdp cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac); 158218822Sdim} 159218822Sdim 160218822Sdim 161218822Sdimvoid des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) 162218822Sdim{ 163218822Sdim u8 next, tmp; 164218822Sdim int i; 165218822Sdim HCRYPTPROV prov; 166218822Sdim HCRYPTKEY ckey; 167218822Sdim DWORD dlen; 168218822Sdim struct { 169218822Sdim BLOBHEADER hdr; 170218822Sdim DWORD len; 171218822Sdim BYTE key[8]; 172218822Sdim } key_blob; 173218822Sdim DWORD mode = CRYPT_MODE_ECB; 174218822Sdim 175218822Sdim key_blob.hdr.bType = PLAINTEXTKEYBLOB; 176218822Sdim key_blob.hdr.bVersion = CUR_BLOB_VERSION; 177218822Sdim key_blob.hdr.reserved = 0; 17838889Sjdp key_blob.hdr.aiKeyAlg = CALG_DES; 179218822Sdim key_blob.len = 8; 180218822Sdim 181218822Sdim /* Add parity bits to the key */ 182218822Sdim next = 0; 183218822Sdim for (i = 0; i < 7; i++) { 184218822Sdim tmp = key[i]; 185218822Sdim key_blob.key[i] = (tmp >> i) | next | 1; 186218822Sdim next = tmp << (7 - i); 187218822Sdim } 188218822Sdim key_blob.key[i] = next | 1; 189218822Sdim 190218822Sdim if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 191218822Sdim CRYPT_VERIFYCONTEXT)) { 192218822Sdim wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " 193218822Sdim "%d", (int) GetLastError()); 194218822Sdim return; 195218822Sdim } 196218822Sdim 197218822Sdim if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0, 198218822Sdim &ckey)) { 199218822Sdim wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", 200218822Sdim (int) GetLastError()); 201218822Sdim CryptReleaseContext(prov, 0); 202218822Sdim return; 203218822Sdim } 204218822Sdim 205218822Sdim if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) { 206218822Sdim wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " 207218822Sdim "failed: %d", (int) GetLastError()); 208218822Sdim CryptDestroyKey(ckey); 209218822Sdim CryptReleaseContext(prov, 0); 210218822Sdim return; 211218822Sdim } 212218822Sdim 213218822Sdim os_memcpy(cypher, clear, 8); 214218822Sdim dlen = 8; 215218822Sdim if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) { 216218822Sdim wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", 217218822Sdim (int) GetLastError()); 218218822Sdim os_memset(cypher, 0, 8); 219218822Sdim } 220218822Sdim 221218822Sdim CryptDestroyKey(ckey); 222218822Sdim CryptReleaseContext(prov, 0); 223218822Sdim} 224218822Sdim 225218822Sdim 226218822Sdim#ifdef EAP_TLS_FUNCS 227218822Sdimvoid md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) 228218822Sdim{ 229218822Sdim cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac); 230218822Sdim} 231218822Sdim 232218822Sdim 233218822Sdimvoid sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) 234218822Sdim{ 235218822Sdim cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac); 236218822Sdim} 237218822Sdim 238218822Sdim 239218822Sdimstruct aes_context { 240218822Sdim HCRYPTPROV prov; 241218822Sdim HCRYPTKEY ckey; 242218822Sdim}; 243218822Sdim 244218822Sdim 245218822Sdimvoid * aes_encrypt_init(const u8 *key, size_t len) 246218822Sdim{ 247218822Sdim struct aes_context *akey; 248218822Sdim struct { 249218822Sdim BLOBHEADER hdr; 250218822Sdim DWORD len; 251218822Sdim BYTE key[16]; 252218822Sdim } key_blob; 253218822Sdim DWORD mode = CRYPT_MODE_ECB; 254218822Sdim 255218822Sdim if (len != 16) 256218822Sdim return NULL; 257218822Sdim 258218822Sdim key_blob.hdr.bType = PLAINTEXTKEYBLOB; 259218822Sdim key_blob.hdr.bVersion = CUR_BLOB_VERSION; 260218822Sdim key_blob.hdr.reserved = 0; 261218822Sdim key_blob.hdr.aiKeyAlg = CALG_AES_128; 262218822Sdim key_blob.len = len; 263218822Sdim os_memcpy(key_blob.key, key, len); 264218822Sdim 265218822Sdim akey = os_zalloc(sizeof(*akey)); 266218822Sdim if (akey == NULL) 267218822Sdim return NULL; 268218822Sdim 269218822Sdim if (!CryptAcquireContext(&akey->prov, NULL, 270218822Sdim MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 271218822Sdim CRYPT_VERIFYCONTEXT)) { 272218822Sdim wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " 273218822Sdim "%d", (int) GetLastError()); 274218822Sdim os_free(akey); 275218822Sdim return NULL; 276218822Sdim } 277218822Sdim 278218822Sdim if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob), 279218822Sdim 0, 0, &akey->ckey)) { 280218822Sdim wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", 281218822Sdim (int) GetLastError()); 282218822Sdim CryptReleaseContext(akey->prov, 0); 283218822Sdim os_free(akey); 284218822Sdim return NULL; 285218822Sdim } 286218822Sdim 287218822Sdim if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) { 288218822Sdim wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " 289218822Sdim "failed: %d", (int) GetLastError()); 290218822Sdim CryptDestroyKey(akey->ckey); 291218822Sdim CryptReleaseContext(akey->prov, 0); 292218822Sdim os_free(akey); 293218822Sdim return NULL; 294218822Sdim } 295218822Sdim 296218822Sdim return akey; 297218822Sdim} 298218822Sdim 299218822Sdim 300218822Sdimvoid aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) 301218822Sdim{ 302218822Sdim struct aes_context *akey = ctx; 303218822Sdim DWORD dlen; 304218822Sdim 305218822Sdim os_memcpy(crypt, plain, 16); 306218822Sdim dlen = 16; 307218822Sdim if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) { 308218822Sdim wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", 309218822Sdim (int) GetLastError()); 310218822Sdim os_memset(crypt, 0, 16); 311218822Sdim } 312218822Sdim} 313218822Sdim 314218822Sdim 315218822Sdimvoid aes_encrypt_deinit(void *ctx) 316218822Sdim{ 317218822Sdim struct aes_context *akey = ctx; 318218822Sdim if (akey) { 319218822Sdim CryptDestroyKey(akey->ckey); 320218822Sdim CryptReleaseContext(akey->prov, 0); 321218822Sdim os_free(akey); 322218822Sdim } 323218822Sdim} 324218822Sdim 325218822Sdim 326218822Sdimvoid * aes_decrypt_init(const u8 *key, size_t len) 327218822Sdim{ 328218822Sdim return aes_encrypt_init(key, len); 329218822Sdim} 330218822Sdim 331218822Sdim 332218822Sdimvoid aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) 333218822Sdim{ 334218822Sdim struct aes_context *akey = ctx; 335218822Sdim DWORD dlen; 336218822Sdim 337218822Sdim os_memcpy(plain, crypt, 16); 338218822Sdim dlen = 16; 339218822Sdim 340218822Sdim if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) { 341218822Sdim wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d", 342218822Sdim (int) GetLastError()); 343218822Sdim } 344218822Sdim} 345218822Sdim 346218822Sdim 347218822Sdimvoid aes_decrypt_deinit(void *ctx) 348218822Sdim{ 349218822Sdim aes_encrypt_deinit(ctx); 350218822Sdim} 351218822Sdim 352218822Sdim#ifdef CONFIG_TLS_INTERNAL 353218822Sdim 354218822Sdimstruct crypto_hash { 355218822Sdim enum crypto_hash_alg alg; 356218822Sdim int error; 357218822Sdim HCRYPTPROV prov; 358218822Sdim HCRYPTHASH hash; 359218822Sdim HCRYPTKEY key; 360218822Sdim}; 361218822Sdim 362218822Sdimstruct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, 363218822Sdim size_t key_len) 364218822Sdim{ 365218822Sdim struct crypto_hash *ctx; 366218822Sdim ALG_ID calg; 367218822Sdim struct { 368218822Sdim BLOBHEADER hdr; 369218822Sdim DWORD len; 370218822Sdim BYTE key[32]; 371218822Sdim } key_blob; 372218822Sdim 373218822Sdim os_memset(&key_blob, 0, sizeof(key_blob)); 374218822Sdim switch (alg) { 375218822Sdim case CRYPTO_HASH_ALG_MD5: 376218822Sdim calg = CALG_MD5; 377218822Sdim break; 378218822Sdim case CRYPTO_HASH_ALG_SHA1: 379218822Sdim calg = CALG_SHA; 38094536Sobrien break; 381218822Sdim case CRYPTO_HASH_ALG_HMAC_MD5: 382218822Sdim case CRYPTO_HASH_ALG_HMAC_SHA1: 383218822Sdim calg = CALG_HMAC; 384218822Sdim key_blob.hdr.bType = PLAINTEXTKEYBLOB; 385218822Sdim key_blob.hdr.bVersion = CUR_BLOB_VERSION; 386218822Sdim key_blob.hdr.reserved = 0; 387218822Sdim /* 388218822Sdim * Note: RC2 is not really used, but that can be used to 389218822Sdim * import HMAC keys of up to 16 byte long. 39038889Sjdp * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to 39138889Sjdp * be able to import longer keys (HMAC-SHA1 uses 20-byte key). 39238889Sjdp */ 393218822Sdim key_blob.hdr.aiKeyAlg = CALG_RC2; 394218822Sdim key_blob.len = key_len; 395218822Sdim if (key_len > sizeof(key_blob.key)) 396218822Sdim return NULL; 397218822Sdim os_memcpy(key_blob.key, key, key_len); 398218822Sdim break; 399218822Sdim default: 400218822Sdim return NULL; 401218822Sdim } 402130561Sobrien 403218822Sdim ctx = os_zalloc(sizeof(*ctx)); 404218822Sdim if (ctx == NULL) 405218822Sdim return NULL; 406218822Sdim 407218822Sdim ctx->alg = alg; 408218822Sdim 409218822Sdim if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) { 410218822Sdim cryptoapi_report_error("CryptAcquireContext"); 411218822Sdim os_free(ctx); 412130561Sobrien return NULL; 413218822Sdim } 414218822Sdim 415218822Sdim if (calg == CALG_HMAC) { 416130561Sobrien#ifndef CRYPT_IPSEC_HMAC_KEY 417218822Sdim#define CRYPT_IPSEC_HMAC_KEY 0x00000100 418218822Sdim#endif 419218822Sdim if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, 420218822Sdim sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY, 421218822Sdim &ctx->key)) { 422218822Sdim cryptoapi_report_error("CryptImportKey"); 423218822Sdim CryptReleaseContext(ctx->prov, 0); 424218822Sdim os_free(ctx); 425218822Sdim return NULL; 426218822Sdim } 427218822Sdim } 428218822Sdim 429218822Sdim if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) { 430218822Sdim cryptoapi_report_error("CryptCreateHash"); 431218822Sdim CryptReleaseContext(ctx->prov, 0); 432218822Sdim os_free(ctx); 433218822Sdim return NULL; 434218822Sdim } 435218822Sdim 436218822Sdim if (calg == CALG_HMAC) { 437218822Sdim HMAC_INFO info; 438218822Sdim os_memset(&info, 0, sizeof(info)); 439218822Sdim switch (alg) { 440218822Sdim case CRYPTO_HASH_ALG_HMAC_MD5: 441218822Sdim info.HashAlgid = CALG_MD5; 442218822Sdim break; 443218822Sdim case CRYPTO_HASH_ALG_HMAC_SHA1: 444218822Sdim info.HashAlgid = CALG_SHA; 445218822Sdim break; 446218822Sdim default: 447130561Sobrien /* unreachable */ 448130561Sobrien break; 449218822Sdim } 450218822Sdim 451218822Sdim if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info, 452130561Sobrien 0)) { 453218822Sdim cryptoapi_report_error("CryptSetHashParam"); 454218822Sdim CryptDestroyHash(ctx->hash); 455218822Sdim CryptReleaseContext(ctx->prov, 0); 456218822Sdim os_free(ctx); 457218822Sdim return NULL; 458218822Sdim } 459218822Sdim } 460218822Sdim 461218822Sdim return ctx; 462218822Sdim} 463218822Sdim 464218822Sdim 465218822Sdimvoid crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) 466218822Sdim{ 467218822Sdim if (ctx == NULL || ctx->error) 468218822Sdim return; 469218822Sdim 47038889Sjdp if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) { 471218822Sdim cryptoapi_report_error("CryptHashData"); 472218822Sdim ctx->error = 1; 473218822Sdim } 474218822Sdim} 475218822Sdim 476218822Sdim 477218822Sdimint crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) 478218822Sdim{ 479218822Sdim int ret = 0; 480218822Sdim DWORD hlen; 481218822Sdim 482218822Sdim if (ctx == NULL) 483218822Sdim return -2; 484218822Sdim 485218822Sdim if (mac == NULL || len == NULL) 486218822Sdim goto done; 487218822Sdim 48838889Sjdp if (ctx->error) { 489218822Sdim ret = -2; 490218822Sdim goto done; 491218822Sdim } 49238889Sjdp 493218822Sdim hlen = *len; 494218822Sdim if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) { 495218822Sdim cryptoapi_report_error("CryptGetHashParam"); 496218822Sdim ret = -2; 497218822Sdim } 498218822Sdim *len = hlen; 499218822Sdim 500218822Sdimdone: 501218822Sdim if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 || 502218822Sdim ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5) 503218822Sdim CryptDestroyKey(ctx->key); 504218822Sdim 505218822Sdim os_free(ctx); 506218822Sdim 507218822Sdim return ret; 508218822Sdim} 509218822Sdim 510218822Sdim 511218822Sdimstruct crypto_cipher { 512218822Sdim HCRYPTPROV prov; 513218822Sdim HCRYPTKEY key; 514218822Sdim}; 515218822Sdim 516218822Sdim 517218822Sdimstruct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, 518218822Sdim const u8 *iv, const u8 *key, 519218822Sdim size_t key_len) 520218822Sdim{ 521218822Sdim struct crypto_cipher *ctx; 522218822Sdim struct { 523218822Sdim BLOBHEADER hdr; 524218822Sdim DWORD len; 525218822Sdim BYTE key[32]; 526218822Sdim } key_blob; 527218822Sdim DWORD mode = CRYPT_MODE_CBC; 528218822Sdim 529218822Sdim key_blob.hdr.bType = PLAINTEXTKEYBLOB; 530218822Sdim key_blob.hdr.bVersion = CUR_BLOB_VERSION; 531218822Sdim key_blob.hdr.reserved = 0; 532218822Sdim key_blob.len = key_len; 533218822Sdim if (key_len > sizeof(key_blob.key)) 534218822Sdim return NULL; 535218822Sdim os_memcpy(key_blob.key, key, key_len); 536218822Sdim 537218822Sdim switch (alg) { 538218822Sdim case CRYPTO_CIPHER_ALG_AES: 539218822Sdim if (key_len == 32) 540218822Sdim key_blob.hdr.aiKeyAlg = CALG_AES_256; 541218822Sdim else if (key_len == 24) 542218822Sdim key_blob.hdr.aiKeyAlg = CALG_AES_192; 543218822Sdim else 544218822Sdim key_blob.hdr.aiKeyAlg = CALG_AES_128; 545218822Sdim break; 546218822Sdim case CRYPTO_CIPHER_ALG_3DES: 547218822Sdim key_blob.hdr.aiKeyAlg = CALG_3DES; 548218822Sdim break; 549218822Sdim case CRYPTO_CIPHER_ALG_DES: 550218822Sdim key_blob.hdr.aiKeyAlg = CALG_DES; 551218822Sdim break; 552218822Sdim case CRYPTO_CIPHER_ALG_RC2: 553218822Sdim key_blob.hdr.aiKeyAlg = CALG_RC2; 554218822Sdim break; 555218822Sdim case CRYPTO_CIPHER_ALG_RC4: 556218822Sdim key_blob.hdr.aiKeyAlg = CALG_RC4; 557218822Sdim break; 558218822Sdim default: 559218822Sdim return NULL; 560218822Sdim } 561218822Sdim 562218822Sdim ctx = os_zalloc(sizeof(*ctx)); 563218822Sdim if (ctx == NULL) 564218822Sdim return NULL; 565218822Sdim 566218822Sdim if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV, 567218822Sdim PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { 568218822Sdim cryptoapi_report_error("CryptAcquireContext"); 569218822Sdim goto fail1; 570218822Sdim } 571218822Sdim 572218822Sdim if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, 573218822Sdim sizeof(key_blob), 0, 0, &ctx->key)) { 574218822Sdim cryptoapi_report_error("CryptImportKey"); 575218822Sdim goto fail2; 576218822Sdim } 577218822Sdim 578218822Sdim if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) { 579218822Sdim cryptoapi_report_error("CryptSetKeyParam(KP_MODE)"); 580218822Sdim goto fail3; 581218822Sdim } 582218822Sdim 583218822Sdim if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) { 584218822Sdim cryptoapi_report_error("CryptSetKeyParam(KP_IV)"); 585218822Sdim goto fail3; 586218822Sdim } 587218822Sdim 588218822Sdim return ctx; 589218822Sdim 590218822Sdimfail3: 591218822Sdim CryptDestroyKey(ctx->key); 592218822Sdimfail2: 593218822Sdim CryptReleaseContext(ctx->prov, 0); 594218822Sdimfail1: 595218822Sdim os_free(ctx); 596218822Sdim return NULL; 597218822Sdim} 598218822Sdim 599218822Sdim 600218822Sdimint crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, 601218822Sdim u8 *crypt, size_t len) 602218822Sdim{ 603218822Sdim DWORD dlen; 604218822Sdim 605218822Sdim os_memcpy(crypt, plain, len); 606218822Sdim dlen = len; 607218822Sdim if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) { 608218822Sdim cryptoapi_report_error("CryptEncrypt"); 609218822Sdim os_memset(crypt, 0, len); 610218822Sdim return -1; 611218822Sdim } 612218822Sdim 613218822Sdim return 0; 614218822Sdim} 615218822Sdim 616218822Sdim 617218822Sdimint crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, 618218822Sdim u8 *plain, size_t len) 619218822Sdim{ 620218822Sdim DWORD dlen; 621218822Sdim 622218822Sdim os_memcpy(plain, crypt, len); 623218822Sdim dlen = len; 624218822Sdim if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) { 625218822Sdim cryptoapi_report_error("CryptDecrypt"); 626218822Sdim return -1; 627218822Sdim } 628218822Sdim 629218822Sdim return 0; 630218822Sdim} 631218822Sdim 632218822Sdim 633218822Sdimvoid crypto_cipher_deinit(struct crypto_cipher *ctx) 634218822Sdim{ 635218822Sdim CryptDestroyKey(ctx->key); 636218822Sdim CryptReleaseContext(ctx->prov, 0); 637218822Sdim os_free(ctx); 638218822Sdim} 639218822Sdim 640218822Sdim 641218822Sdimstruct crypto_public_key { 642218822Sdim HCRYPTPROV prov; 643218822Sdim HCRYPTKEY rsa; 644218822Sdim}; 645218822Sdim 646218822Sdimstruct crypto_private_key { 647218822Sdim HCRYPTPROV prov; 648218822Sdim HCRYPTKEY rsa; 649218822Sdim}; 650218822Sdim 651218822Sdim 652218822Sdimstruct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) 653218822Sdim{ 654218822Sdim /* Use crypto_public_key_from_cert() instead. */ 655218822Sdim return NULL; 656218822Sdim} 657218822Sdim 658218822Sdim 659218822Sdimstruct crypto_private_key * crypto_private_key_import(const u8 *key, 660218822Sdim size_t len) 661218822Sdim{ 662218822Sdim /* TODO */ 663218822Sdim return NULL; 664218822Sdim} 665218822Sdim 666218822Sdim 667218822Sdimstruct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, 668218822Sdim size_t len) 669218822Sdim{ 670218822Sdim struct crypto_public_key *pk; 671218822Sdim PCCERT_CONTEXT cc; 672218822Sdim 673218822Sdim pk = os_zalloc(sizeof(*pk)); 674218822Sdim if (pk == NULL) 675218822Sdim return NULL; 676218822Sdim 677218822Sdim cc = CertCreateCertificateContext(X509_ASN_ENCODING | 678218822Sdim PKCS_7_ASN_ENCODING, buf, len); 679218822Sdim if (!cc) { 680218822Sdim cryptoapi_report_error("CryptCreateCertificateContext"); 681218822Sdim os_free(pk); 682218822Sdim return NULL; 683218822Sdim } 684218822Sdim 685218822Sdim if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, 686218822Sdim 0)) { 687218822Sdim cryptoapi_report_error("CryptAcquireContext"); 688218822Sdim os_free(pk); 689218822Sdim CertFreeCertificateContext(cc); 690218822Sdim return NULL; 691218822Sdim } 692218822Sdim 693218822Sdim if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING | 694218822Sdim PKCS_7_ASN_ENCODING, 695218822Sdim &cc->pCertInfo->SubjectPublicKeyInfo, 696218822Sdim &pk->rsa)) { 697218822Sdim cryptoapi_report_error("CryptImportPublicKeyInfo"); 698218822Sdim CryptReleaseContext(pk->prov, 0); 699218822Sdim os_free(pk); 700218822Sdim CertFreeCertificateContext(cc); 701218822Sdim return NULL; 702218822Sdim } 703218822Sdim 704218822Sdim CertFreeCertificateContext(cc); 705218822Sdim 706218822Sdim return pk; 707218822Sdim} 70894536Sobrien 70938889Sjdp 71038889Sjdpint crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, 71138889Sjdp const u8 *in, size_t inlen, 712218822Sdim u8 *out, size_t *outlen) 71338889Sjdp{ 71438889Sjdp DWORD clen; 71538889Sjdp u8 *tmp; 71638889Sjdp size_t i; 71738889Sjdp 71838889Sjdp if (*outlen < inlen) 719218822Sdim return -1; 720218822Sdim tmp = malloc(*outlen); 72138889Sjdp if (tmp == NULL) 722218822Sdim return -1; 72338889Sjdp 724218822Sdim os_memcpy(tmp, in, inlen); 725218822Sdim clen = inlen; 726218822Sdim if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) { 72738889Sjdp wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using " 72838889Sjdp "public key: %d", (int) GetLastError()); 72938889Sjdp os_free(tmp); 73038889Sjdp return -1; 73138889Sjdp } 73238889Sjdp 73338889Sjdp *outlen = clen; 73438889Sjdp 73538889Sjdp /* Reverse the output */ 736218822Sdim for (i = 0; i < *outlen; i++) 73738889Sjdp out[i] = tmp[*outlen - 1 - i]; 73838889Sjdp 73938889Sjdp os_free(tmp); 74038889Sjdp 74138889Sjdp return 0; 74238889Sjdp} 74338889Sjdp 74438889Sjdp 74538889Sjdpint crypto_private_key_sign_pkcs1(struct crypto_private_key *key, 74638889Sjdp const u8 *in, size_t inlen, 747218822Sdim u8 *out, size_t *outlen) 748218822Sdim{ 749218822Sdim /* TODO */ 750218822Sdim return -1; 751218822Sdim} 752218822Sdim 753218822Sdim 754218822Sdimvoid crypto_public_key_free(struct crypto_public_key *key) 755218822Sdim{ 756218822Sdim if (key) { 757218822Sdim CryptDestroyKey(key->rsa); 758218822Sdim CryptReleaseContext(key->prov, 0); 759218822Sdim os_free(key); 760218822Sdim } 761218822Sdim} 762218822Sdim 763218822Sdim 764218822Sdimvoid crypto_private_key_free(struct crypto_private_key *key) 765218822Sdim{ 766218822Sdim if (key) { 767218822Sdim CryptDestroyKey(key->rsa); 768218822Sdim CryptReleaseContext(key->prov, 0); 769218822Sdim os_free(key); 770218822Sdim } 77138889Sjdp} 772218822Sdim 773218822Sdim 77438889Sjdpint crypto_global_init(void) 775218822Sdim{ 77638889Sjdp return mingw_load_crypto_func(); 777218822Sdim} 778218822Sdim 779218822Sdim 780218822Sdimvoid crypto_global_deinit(void) 781218822Sdim{ 782218822Sdim} 783218822Sdim 784218822Sdim#endif /* CONFIG_TLS_INTERNAL */ 785218822Sdim 786218822Sdim#endif /* EAP_TLS_FUNCS */ 787218822Sdim