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"
14337817Scy#include "sha384_i.h"
15337817Scy#include "sha512_i.h"
16214734Srpaulo#include "sha1_i.h"
17214734Srpaulo#include "md5_i.h"
18189251Ssam
19189251Ssamstruct crypto_hash {
20189251Ssam	enum crypto_hash_alg alg;
21189251Ssam	union {
22189251Ssam		struct MD5Context md5;
23189251Ssam		struct SHA1Context sha1;
24252726Srpaulo#ifdef CONFIG_SHA256
25252726Srpaulo		struct sha256_state sha256;
26252726Srpaulo#endif /* CONFIG_SHA256 */
27337817Scy#ifdef CONFIG_INTERNAL_SHA384
28337817Scy		struct sha384_state sha384;
29337817Scy#endif /* CONFIG_INTERNAL_SHA384 */
30337817Scy#ifdef CONFIG_INTERNAL_SHA512
31337817Scy		struct sha512_state sha512;
32337817Scy#endif /* CONFIG_INTERNAL_SHA512 */
33189251Ssam	} u;
34189251Ssam	u8 key[64];
35189251Ssam	size_t key_len;
36189251Ssam};
37189251Ssam
38189251Ssam
39189251Ssamstruct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
40189251Ssam				      size_t key_len)
41189251Ssam{
42189251Ssam	struct crypto_hash *ctx;
43189251Ssam	u8 k_pad[64];
44252726Srpaulo	u8 tk[32];
45189251Ssam	size_t i;
46189251Ssam
47189251Ssam	ctx = os_zalloc(sizeof(*ctx));
48189251Ssam	if (ctx == NULL)
49189251Ssam		return NULL;
50189251Ssam
51189251Ssam	ctx->alg = alg;
52189251Ssam
53189251Ssam	switch (alg) {
54189251Ssam	case CRYPTO_HASH_ALG_MD5:
55189251Ssam		MD5Init(&ctx->u.md5);
56189251Ssam		break;
57189251Ssam	case CRYPTO_HASH_ALG_SHA1:
58189251Ssam		SHA1Init(&ctx->u.sha1);
59189251Ssam		break;
60252726Srpaulo#ifdef CONFIG_SHA256
61252726Srpaulo	case CRYPTO_HASH_ALG_SHA256:
62252726Srpaulo		sha256_init(&ctx->u.sha256);
63252726Srpaulo		break;
64252726Srpaulo#endif /* CONFIG_SHA256 */
65337817Scy#ifdef CONFIG_INTERNAL_SHA384
66337817Scy	case CRYPTO_HASH_ALG_SHA384:
67337817Scy		sha384_init(&ctx->u.sha384);
68337817Scy		break;
69337817Scy#endif /* CONFIG_INTERNAL_SHA384 */
70337817Scy#ifdef CONFIG_INTERNAL_SHA512
71337817Scy	case CRYPTO_HASH_ALG_SHA512:
72337817Scy		sha512_init(&ctx->u.sha512);
73337817Scy		break;
74337817Scy#endif /* CONFIG_INTERNAL_SHA512 */
75189251Ssam	case CRYPTO_HASH_ALG_HMAC_MD5:
76189251Ssam		if (key_len > sizeof(k_pad)) {
77189251Ssam			MD5Init(&ctx->u.md5);
78189251Ssam			MD5Update(&ctx->u.md5, key, key_len);
79189251Ssam			MD5Final(tk, &ctx->u.md5);
80189251Ssam			key = tk;
81189251Ssam			key_len = 16;
82189251Ssam		}
83189251Ssam		os_memcpy(ctx->key, key, key_len);
84189251Ssam		ctx->key_len = key_len;
85189251Ssam
86189251Ssam		os_memcpy(k_pad, key, key_len);
87252726Srpaulo		if (key_len < sizeof(k_pad))
88252726Srpaulo			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
89189251Ssam		for (i = 0; i < sizeof(k_pad); i++)
90189251Ssam			k_pad[i] ^= 0x36;
91189251Ssam		MD5Init(&ctx->u.md5);
92189251Ssam		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
93189251Ssam		break;
94189251Ssam	case CRYPTO_HASH_ALG_HMAC_SHA1:
95189251Ssam		if (key_len > sizeof(k_pad)) {
96189251Ssam			SHA1Init(&ctx->u.sha1);
97189251Ssam			SHA1Update(&ctx->u.sha1, key, key_len);
98189251Ssam			SHA1Final(tk, &ctx->u.sha1);
99189251Ssam			key = tk;
100189251Ssam			key_len = 20;
101189251Ssam		}
102189251Ssam		os_memcpy(ctx->key, key, key_len);
103189251Ssam		ctx->key_len = key_len;
104189251Ssam
105189251Ssam		os_memcpy(k_pad, key, key_len);
106252726Srpaulo		if (key_len < sizeof(k_pad))
107252726Srpaulo			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
108189251Ssam		for (i = 0; i < sizeof(k_pad); i++)
109189251Ssam			k_pad[i] ^= 0x36;
110189251Ssam		SHA1Init(&ctx->u.sha1);
111189251Ssam		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
112189251Ssam		break;
113252726Srpaulo#ifdef CONFIG_SHA256
114252726Srpaulo	case CRYPTO_HASH_ALG_HMAC_SHA256:
115252726Srpaulo		if (key_len > sizeof(k_pad)) {
116252726Srpaulo			sha256_init(&ctx->u.sha256);
117252726Srpaulo			sha256_process(&ctx->u.sha256, key, key_len);
118252726Srpaulo			sha256_done(&ctx->u.sha256, tk);
119252726Srpaulo			key = tk;
120252726Srpaulo			key_len = 32;
121252726Srpaulo		}
122252726Srpaulo		os_memcpy(ctx->key, key, key_len);
123252726Srpaulo		ctx->key_len = key_len;
124252726Srpaulo
125252726Srpaulo		os_memcpy(k_pad, key, key_len);
126252726Srpaulo		if (key_len < sizeof(k_pad))
127252726Srpaulo			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
128252726Srpaulo		for (i = 0; i < sizeof(k_pad); i++)
129252726Srpaulo			k_pad[i] ^= 0x36;
130252726Srpaulo		sha256_init(&ctx->u.sha256);
131252726Srpaulo		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
132252726Srpaulo		break;
133252726Srpaulo#endif /* CONFIG_SHA256 */
134189251Ssam	default:
135189251Ssam		os_free(ctx);
136189251Ssam		return NULL;
137189251Ssam	}
138189251Ssam
139189251Ssam	return ctx;
140189251Ssam}
141189251Ssam
142189251Ssam
143189251Ssamvoid crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
144189251Ssam{
145189251Ssam	if (ctx == NULL)
146189251Ssam		return;
147189251Ssam
148189251Ssam	switch (ctx->alg) {
149189251Ssam	case CRYPTO_HASH_ALG_MD5:
150189251Ssam	case CRYPTO_HASH_ALG_HMAC_MD5:
151189251Ssam		MD5Update(&ctx->u.md5, data, len);
152189251Ssam		break;
153189251Ssam	case CRYPTO_HASH_ALG_SHA1:
154189251Ssam	case CRYPTO_HASH_ALG_HMAC_SHA1:
155189251Ssam		SHA1Update(&ctx->u.sha1, data, len);
156189251Ssam		break;
157252726Srpaulo#ifdef CONFIG_SHA256
158252726Srpaulo	case CRYPTO_HASH_ALG_SHA256:
159252726Srpaulo	case CRYPTO_HASH_ALG_HMAC_SHA256:
160252726Srpaulo		sha256_process(&ctx->u.sha256, data, len);
161252726Srpaulo		break;
162252726Srpaulo#endif /* CONFIG_SHA256 */
163337817Scy#ifdef CONFIG_INTERNAL_SHA384
164337817Scy	case CRYPTO_HASH_ALG_SHA384:
165337817Scy		sha384_process(&ctx->u.sha384, data, len);
166337817Scy		break;
167337817Scy#endif /* CONFIG_INTERNAL_SHA384 */
168337817Scy#ifdef CONFIG_INTERNAL_SHA512
169337817Scy	case CRYPTO_HASH_ALG_SHA512:
170337817Scy		sha512_process(&ctx->u.sha512, data, len);
171337817Scy		break;
172337817Scy#endif /* CONFIG_INTERNAL_SHA512 */
173252726Srpaulo	default:
174252726Srpaulo		break;
175189251Ssam	}
176189251Ssam}
177189251Ssam
178189251Ssam
179189251Ssamint crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
180189251Ssam{
181189251Ssam	u8 k_pad[64];
182189251Ssam	size_t i;
183189251Ssam
184189251Ssam	if (ctx == NULL)
185189251Ssam		return -2;
186189251Ssam
187189251Ssam	if (mac == NULL || len == NULL) {
188189251Ssam		os_free(ctx);
189189251Ssam		return 0;
190189251Ssam	}
191189251Ssam
192189251Ssam	switch (ctx->alg) {
193189251Ssam	case CRYPTO_HASH_ALG_MD5:
194189251Ssam		if (*len < 16) {
195189251Ssam			*len = 16;
196189251Ssam			os_free(ctx);
197189251Ssam			return -1;
198189251Ssam		}
199189251Ssam		*len = 16;
200189251Ssam		MD5Final(mac, &ctx->u.md5);
201189251Ssam		break;
202189251Ssam	case CRYPTO_HASH_ALG_SHA1:
203189251Ssam		if (*len < 20) {
204189251Ssam			*len = 20;
205189251Ssam			os_free(ctx);
206189251Ssam			return -1;
207189251Ssam		}
208189251Ssam		*len = 20;
209189251Ssam		SHA1Final(mac, &ctx->u.sha1);
210189251Ssam		break;
211252726Srpaulo#ifdef CONFIG_SHA256
212252726Srpaulo	case CRYPTO_HASH_ALG_SHA256:
213252726Srpaulo		if (*len < 32) {
214252726Srpaulo			*len = 32;
215252726Srpaulo			os_free(ctx);
216252726Srpaulo			return -1;
217252726Srpaulo		}
218252726Srpaulo		*len = 32;
219252726Srpaulo		sha256_done(&ctx->u.sha256, mac);
220252726Srpaulo		break;
221252726Srpaulo#endif /* CONFIG_SHA256 */
222337817Scy#ifdef CONFIG_INTERNAL_SHA384
223337817Scy	case CRYPTO_HASH_ALG_SHA384:
224337817Scy		if (*len < 48) {
225337817Scy			*len = 48;
226337817Scy			os_free(ctx);
227337817Scy			return -1;
228337817Scy		}
229337817Scy		*len = 48;
230337817Scy		sha384_done(&ctx->u.sha384, mac);
231337817Scy		break;
232337817Scy#endif /* CONFIG_INTERNAL_SHA384 */
233337817Scy#ifdef CONFIG_INTERNAL_SHA512
234337817Scy	case CRYPTO_HASH_ALG_SHA512:
235337817Scy		if (*len < 64) {
236337817Scy			*len = 64;
237337817Scy			os_free(ctx);
238337817Scy			return -1;
239337817Scy		}
240337817Scy		*len = 64;
241337817Scy		sha512_done(&ctx->u.sha512, mac);
242337817Scy		break;
243337817Scy#endif /* CONFIG_INTERNAL_SHA512 */
244189251Ssam	case CRYPTO_HASH_ALG_HMAC_MD5:
245189251Ssam		if (*len < 16) {
246189251Ssam			*len = 16;
247189251Ssam			os_free(ctx);
248189251Ssam			return -1;
249189251Ssam		}
250189251Ssam		*len = 16;
251189251Ssam
252189251Ssam		MD5Final(mac, &ctx->u.md5);
253189251Ssam
254189251Ssam		os_memcpy(k_pad, ctx->key, ctx->key_len);
255189251Ssam		os_memset(k_pad + ctx->key_len, 0,
256189251Ssam			  sizeof(k_pad) - ctx->key_len);
257189251Ssam		for (i = 0; i < sizeof(k_pad); i++)
258189251Ssam			k_pad[i] ^= 0x5c;
259189251Ssam		MD5Init(&ctx->u.md5);
260189251Ssam		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
261189251Ssam		MD5Update(&ctx->u.md5, mac, 16);
262189251Ssam		MD5Final(mac, &ctx->u.md5);
263189251Ssam		break;
264189251Ssam	case CRYPTO_HASH_ALG_HMAC_SHA1:
265189251Ssam		if (*len < 20) {
266189251Ssam			*len = 20;
267189251Ssam			os_free(ctx);
268189251Ssam			return -1;
269189251Ssam		}
270189251Ssam		*len = 20;
271189251Ssam
272189251Ssam		SHA1Final(mac, &ctx->u.sha1);
273189251Ssam
274189251Ssam		os_memcpy(k_pad, ctx->key, ctx->key_len);
275189251Ssam		os_memset(k_pad + ctx->key_len, 0,
276189251Ssam			  sizeof(k_pad) - ctx->key_len);
277189251Ssam		for (i = 0; i < sizeof(k_pad); i++)
278189251Ssam			k_pad[i] ^= 0x5c;
279189251Ssam		SHA1Init(&ctx->u.sha1);
280189251Ssam		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
281189251Ssam		SHA1Update(&ctx->u.sha1, mac, 20);
282189251Ssam		SHA1Final(mac, &ctx->u.sha1);
283189251Ssam		break;
284252726Srpaulo#ifdef CONFIG_SHA256
285252726Srpaulo	case CRYPTO_HASH_ALG_HMAC_SHA256:
286252726Srpaulo		if (*len < 32) {
287252726Srpaulo			*len = 32;
288252726Srpaulo			os_free(ctx);
289252726Srpaulo			return -1;
290252726Srpaulo		}
291252726Srpaulo		*len = 32;
292252726Srpaulo
293252726Srpaulo		sha256_done(&ctx->u.sha256, mac);
294252726Srpaulo
295252726Srpaulo		os_memcpy(k_pad, ctx->key, ctx->key_len);
296252726Srpaulo		os_memset(k_pad + ctx->key_len, 0,
297252726Srpaulo			  sizeof(k_pad) - ctx->key_len);
298252726Srpaulo		for (i = 0; i < sizeof(k_pad); i++)
299252726Srpaulo			k_pad[i] ^= 0x5c;
300252726Srpaulo		sha256_init(&ctx->u.sha256);
301252726Srpaulo		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
302252726Srpaulo		sha256_process(&ctx->u.sha256, mac, 32);
303252726Srpaulo		sha256_done(&ctx->u.sha256, mac);
304252726Srpaulo		break;
305252726Srpaulo#endif /* CONFIG_SHA256 */
306252726Srpaulo	default:
307252726Srpaulo		os_free(ctx);
308252726Srpaulo		return -1;
309189251Ssam	}
310189251Ssam
311189251Ssam	os_free(ctx);
312189251Ssam
313346981Scy	if (TEST_FAIL())
314346981Scy		return -1;
315346981Scy
316189251Ssam	return 0;
317189251Ssam}
318189251Ssam
319189251Ssam
320189251Ssamint crypto_global_init(void)
321189251Ssam{
322189251Ssam	return 0;
323189251Ssam}
324189251Ssam
325189251Ssam
326189251Ssamvoid crypto_global_deinit(void)
327189251Ssam{
328189251Ssam}
329