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