1189251Ssam/*
2214734Srpaulo * Crypto wrapper for internal crypto implementation
3252726Srpaulo * Copyright (c) 2006-2011, 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
11189251Ssam#include "common.h"
12189251Ssam#include "crypto.h"
13252726Srpaulo#include "sha256_i.h"
14214734Srpaulo#include "sha1_i.h"
15214734Srpaulo#include "md5_i.h"
16189251Ssam
17189251Ssamstruct crypto_hash {
18189251Ssam	enum crypto_hash_alg alg;
19189251Ssam	union {
20189251Ssam		struct MD5Context md5;
21189251Ssam		struct SHA1Context sha1;
22252726Srpaulo#ifdef CONFIG_SHA256
23252726Srpaulo		struct sha256_state sha256;
24252726Srpaulo#endif /* CONFIG_SHA256 */
25189251Ssam	} u;
26189251Ssam	u8 key[64];
27189251Ssam	size_t key_len;
28189251Ssam};
29189251Ssam
30189251Ssam
31189251Ssamstruct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
32189251Ssam				      size_t key_len)
33189251Ssam{
34189251Ssam	struct crypto_hash *ctx;
35189251Ssam	u8 k_pad[64];
36252726Srpaulo	u8 tk[32];
37189251Ssam	size_t i;
38189251Ssam
39189251Ssam	ctx = os_zalloc(sizeof(*ctx));
40189251Ssam	if (ctx == NULL)
41189251Ssam		return NULL;
42189251Ssam
43189251Ssam	ctx->alg = alg;
44189251Ssam
45189251Ssam	switch (alg) {
46189251Ssam	case CRYPTO_HASH_ALG_MD5:
47189251Ssam		MD5Init(&ctx->u.md5);
48189251Ssam		break;
49189251Ssam	case CRYPTO_HASH_ALG_SHA1:
50189251Ssam		SHA1Init(&ctx->u.sha1);
51189251Ssam		break;
52252726Srpaulo#ifdef CONFIG_SHA256
53252726Srpaulo	case CRYPTO_HASH_ALG_SHA256:
54252726Srpaulo		sha256_init(&ctx->u.sha256);
55252726Srpaulo		break;
56252726Srpaulo#endif /* CONFIG_SHA256 */
57189251Ssam	case CRYPTO_HASH_ALG_HMAC_MD5:
58189251Ssam		if (key_len > sizeof(k_pad)) {
59189251Ssam			MD5Init(&ctx->u.md5);
60189251Ssam			MD5Update(&ctx->u.md5, key, key_len);
61189251Ssam			MD5Final(tk, &ctx->u.md5);
62189251Ssam			key = tk;
63189251Ssam			key_len = 16;
64189251Ssam		}
65189251Ssam		os_memcpy(ctx->key, key, key_len);
66189251Ssam		ctx->key_len = key_len;
67189251Ssam
68189251Ssam		os_memcpy(k_pad, key, key_len);
69252726Srpaulo		if (key_len < sizeof(k_pad))
70252726Srpaulo			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
71189251Ssam		for (i = 0; i < sizeof(k_pad); i++)
72189251Ssam			k_pad[i] ^= 0x36;
73189251Ssam		MD5Init(&ctx->u.md5);
74189251Ssam		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
75189251Ssam		break;
76189251Ssam	case CRYPTO_HASH_ALG_HMAC_SHA1:
77189251Ssam		if (key_len > sizeof(k_pad)) {
78189251Ssam			SHA1Init(&ctx->u.sha1);
79189251Ssam			SHA1Update(&ctx->u.sha1, key, key_len);
80189251Ssam			SHA1Final(tk, &ctx->u.sha1);
81189251Ssam			key = tk;
82189251Ssam			key_len = 20;
83189251Ssam		}
84189251Ssam		os_memcpy(ctx->key, key, key_len);
85189251Ssam		ctx->key_len = key_len;
86189251Ssam
87189251Ssam		os_memcpy(k_pad, key, key_len);
88252726Srpaulo		if (key_len < sizeof(k_pad))
89252726Srpaulo			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
90189251Ssam		for (i = 0; i < sizeof(k_pad); i++)
91189251Ssam			k_pad[i] ^= 0x36;
92189251Ssam		SHA1Init(&ctx->u.sha1);
93189251Ssam		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
94189251Ssam		break;
95252726Srpaulo#ifdef CONFIG_SHA256
96252726Srpaulo	case CRYPTO_HASH_ALG_HMAC_SHA256:
97252726Srpaulo		if (key_len > sizeof(k_pad)) {
98252726Srpaulo			sha256_init(&ctx->u.sha256);
99252726Srpaulo			sha256_process(&ctx->u.sha256, key, key_len);
100252726Srpaulo			sha256_done(&ctx->u.sha256, tk);
101252726Srpaulo			key = tk;
102252726Srpaulo			key_len = 32;
103252726Srpaulo		}
104252726Srpaulo		os_memcpy(ctx->key, key, key_len);
105252726Srpaulo		ctx->key_len = key_len;
106252726Srpaulo
107252726Srpaulo		os_memcpy(k_pad, key, key_len);
108252726Srpaulo		if (key_len < sizeof(k_pad))
109252726Srpaulo			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
110252726Srpaulo		for (i = 0; i < sizeof(k_pad); i++)
111252726Srpaulo			k_pad[i] ^= 0x36;
112252726Srpaulo		sha256_init(&ctx->u.sha256);
113252726Srpaulo		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
114252726Srpaulo		break;
115252726Srpaulo#endif /* CONFIG_SHA256 */
116189251Ssam	default:
117189251Ssam		os_free(ctx);
118189251Ssam		return NULL;
119189251Ssam	}
120189251Ssam
121189251Ssam	return ctx;
122189251Ssam}
123189251Ssam
124189251Ssam
125189251Ssamvoid crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
126189251Ssam{
127189251Ssam	if (ctx == NULL)
128189251Ssam		return;
129189251Ssam
130189251Ssam	switch (ctx->alg) {
131189251Ssam	case CRYPTO_HASH_ALG_MD5:
132189251Ssam	case CRYPTO_HASH_ALG_HMAC_MD5:
133189251Ssam		MD5Update(&ctx->u.md5, data, len);
134189251Ssam		break;
135189251Ssam	case CRYPTO_HASH_ALG_SHA1:
136189251Ssam	case CRYPTO_HASH_ALG_HMAC_SHA1:
137189251Ssam		SHA1Update(&ctx->u.sha1, data, len);
138189251Ssam		break;
139252726Srpaulo#ifdef CONFIG_SHA256
140252726Srpaulo	case CRYPTO_HASH_ALG_SHA256:
141252726Srpaulo	case CRYPTO_HASH_ALG_HMAC_SHA256:
142252726Srpaulo		sha256_process(&ctx->u.sha256, data, len);
143252726Srpaulo		break;
144252726Srpaulo#endif /* CONFIG_SHA256 */
145252726Srpaulo	default:
146252726Srpaulo		break;
147189251Ssam	}
148189251Ssam}
149189251Ssam
150189251Ssam
151189251Ssamint crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
152189251Ssam{
153189251Ssam	u8 k_pad[64];
154189251Ssam	size_t i;
155189251Ssam
156189251Ssam	if (ctx == NULL)
157189251Ssam		return -2;
158189251Ssam
159189251Ssam	if (mac == NULL || len == NULL) {
160189251Ssam		os_free(ctx);
161189251Ssam		return 0;
162189251Ssam	}
163189251Ssam
164189251Ssam	switch (ctx->alg) {
165189251Ssam	case CRYPTO_HASH_ALG_MD5:
166189251Ssam		if (*len < 16) {
167189251Ssam			*len = 16;
168189251Ssam			os_free(ctx);
169189251Ssam			return -1;
170189251Ssam		}
171189251Ssam		*len = 16;
172189251Ssam		MD5Final(mac, &ctx->u.md5);
173189251Ssam		break;
174189251Ssam	case CRYPTO_HASH_ALG_SHA1:
175189251Ssam		if (*len < 20) {
176189251Ssam			*len = 20;
177189251Ssam			os_free(ctx);
178189251Ssam			return -1;
179189251Ssam		}
180189251Ssam		*len = 20;
181189251Ssam		SHA1Final(mac, &ctx->u.sha1);
182189251Ssam		break;
183252726Srpaulo#ifdef CONFIG_SHA256
184252726Srpaulo	case CRYPTO_HASH_ALG_SHA256:
185252726Srpaulo		if (*len < 32) {
186252726Srpaulo			*len = 32;
187252726Srpaulo			os_free(ctx);
188252726Srpaulo			return -1;
189252726Srpaulo		}
190252726Srpaulo		*len = 32;
191252726Srpaulo		sha256_done(&ctx->u.sha256, mac);
192252726Srpaulo		break;
193252726Srpaulo#endif /* CONFIG_SHA256 */
194189251Ssam	case CRYPTO_HASH_ALG_HMAC_MD5:
195189251Ssam		if (*len < 16) {
196189251Ssam			*len = 16;
197189251Ssam			os_free(ctx);
198189251Ssam			return -1;
199189251Ssam		}
200189251Ssam		*len = 16;
201189251Ssam
202189251Ssam		MD5Final(mac, &ctx->u.md5);
203189251Ssam
204189251Ssam		os_memcpy(k_pad, ctx->key, ctx->key_len);
205189251Ssam		os_memset(k_pad + ctx->key_len, 0,
206189251Ssam			  sizeof(k_pad) - ctx->key_len);
207189251Ssam		for (i = 0; i < sizeof(k_pad); i++)
208189251Ssam			k_pad[i] ^= 0x5c;
209189251Ssam		MD5Init(&ctx->u.md5);
210189251Ssam		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
211189251Ssam		MD5Update(&ctx->u.md5, mac, 16);
212189251Ssam		MD5Final(mac, &ctx->u.md5);
213189251Ssam		break;
214189251Ssam	case CRYPTO_HASH_ALG_HMAC_SHA1:
215189251Ssam		if (*len < 20) {
216189251Ssam			*len = 20;
217189251Ssam			os_free(ctx);
218189251Ssam			return -1;
219189251Ssam		}
220189251Ssam		*len = 20;
221189251Ssam
222189251Ssam		SHA1Final(mac, &ctx->u.sha1);
223189251Ssam
224189251Ssam		os_memcpy(k_pad, ctx->key, ctx->key_len);
225189251Ssam		os_memset(k_pad + ctx->key_len, 0,
226189251Ssam			  sizeof(k_pad) - ctx->key_len);
227189251Ssam		for (i = 0; i < sizeof(k_pad); i++)
228189251Ssam			k_pad[i] ^= 0x5c;
229189251Ssam		SHA1Init(&ctx->u.sha1);
230189251Ssam		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
231189251Ssam		SHA1Update(&ctx->u.sha1, mac, 20);
232189251Ssam		SHA1Final(mac, &ctx->u.sha1);
233189251Ssam		break;
234252726Srpaulo#ifdef CONFIG_SHA256
235252726Srpaulo	case CRYPTO_HASH_ALG_HMAC_SHA256:
236252726Srpaulo		if (*len < 32) {
237252726Srpaulo			*len = 32;
238252726Srpaulo			os_free(ctx);
239252726Srpaulo			return -1;
240252726Srpaulo		}
241252726Srpaulo		*len = 32;
242252726Srpaulo
243252726Srpaulo		sha256_done(&ctx->u.sha256, mac);
244252726Srpaulo
245252726Srpaulo		os_memcpy(k_pad, ctx->key, ctx->key_len);
246252726Srpaulo		os_memset(k_pad + ctx->key_len, 0,
247252726Srpaulo			  sizeof(k_pad) - ctx->key_len);
248252726Srpaulo		for (i = 0; i < sizeof(k_pad); i++)
249252726Srpaulo			k_pad[i] ^= 0x5c;
250252726Srpaulo		sha256_init(&ctx->u.sha256);
251252726Srpaulo		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
252252726Srpaulo		sha256_process(&ctx->u.sha256, mac, 32);
253252726Srpaulo		sha256_done(&ctx->u.sha256, mac);
254252726Srpaulo		break;
255252726Srpaulo#endif /* CONFIG_SHA256 */
256252726Srpaulo	default:
257252726Srpaulo		os_free(ctx);
258252726Srpaulo		return -1;
259189251Ssam	}
260189251Ssam
261189251Ssam	os_free(ctx);
262189251Ssam
263189251Ssam	return 0;
264189251Ssam}
265189251Ssam
266189251Ssam
267189251Ssamint crypto_global_init(void)
268189251Ssam{
269189251Ssam	return 0;
270189251Ssam}
271189251Ssam
272189251Ssam
273189251Ssamvoid crypto_global_deinit(void)
274189251Ssam{
275189251Ssam}
276