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