1/*
2 * Crypto wrapper for internal crypto implementation
3 * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#include "common.h"
18#include "crypto.h"
19#include "sha1_i.h"
20#include "md5_i.h"
21
22struct crypto_hash {
23	enum crypto_hash_alg alg;
24	union {
25		struct MD5Context md5;
26		struct SHA1Context sha1;
27	} u;
28	u8 key[64];
29	size_t key_len;
30};
31
32
33struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
34				      size_t key_len)
35{
36	struct crypto_hash *ctx;
37	u8 k_pad[64];
38	u8 tk[20];
39	size_t i;
40
41	ctx = os_zalloc(sizeof(*ctx));
42	if (ctx == NULL)
43		return NULL;
44
45	ctx->alg = alg;
46
47	switch (alg) {
48	case CRYPTO_HASH_ALG_MD5:
49		MD5Init(&ctx->u.md5);
50		break;
51	case CRYPTO_HASH_ALG_SHA1:
52		SHA1Init(&ctx->u.sha1);
53		break;
54	case CRYPTO_HASH_ALG_HMAC_MD5:
55		if (key_len > sizeof(k_pad)) {
56			MD5Init(&ctx->u.md5);
57			MD5Update(&ctx->u.md5, key, key_len);
58			MD5Final(tk, &ctx->u.md5);
59			key = tk;
60			key_len = 16;
61		}
62		os_memcpy(ctx->key, key, key_len);
63		ctx->key_len = key_len;
64
65		os_memcpy(k_pad, key, key_len);
66		os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
67		for (i = 0; i < sizeof(k_pad); i++)
68			k_pad[i] ^= 0x36;
69		MD5Init(&ctx->u.md5);
70		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
71		break;
72	case CRYPTO_HASH_ALG_HMAC_SHA1:
73		if (key_len > sizeof(k_pad)) {
74			SHA1Init(&ctx->u.sha1);
75			SHA1Update(&ctx->u.sha1, key, key_len);
76			SHA1Final(tk, &ctx->u.sha1);
77			key = tk;
78			key_len = 20;
79		}
80		os_memcpy(ctx->key, key, key_len);
81		ctx->key_len = key_len;
82
83		os_memcpy(k_pad, key, key_len);
84		os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
85		for (i = 0; i < sizeof(k_pad); i++)
86			k_pad[i] ^= 0x36;
87		SHA1Init(&ctx->u.sha1);
88		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
89		break;
90	default:
91		os_free(ctx);
92		return NULL;
93	}
94
95	return ctx;
96}
97
98
99void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
100{
101	if (ctx == NULL)
102		return;
103
104	switch (ctx->alg) {
105	case CRYPTO_HASH_ALG_MD5:
106	case CRYPTO_HASH_ALG_HMAC_MD5:
107		MD5Update(&ctx->u.md5, data, len);
108		break;
109	case CRYPTO_HASH_ALG_SHA1:
110	case CRYPTO_HASH_ALG_HMAC_SHA1:
111		SHA1Update(&ctx->u.sha1, data, len);
112		break;
113	}
114}
115
116
117int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
118{
119	u8 k_pad[64];
120	size_t i;
121
122	if (ctx == NULL)
123		return -2;
124
125	if (mac == NULL || len == NULL) {
126		os_free(ctx);
127		return 0;
128	}
129
130	switch (ctx->alg) {
131	case CRYPTO_HASH_ALG_MD5:
132		if (*len < 16) {
133			*len = 16;
134			os_free(ctx);
135			return -1;
136		}
137		*len = 16;
138		MD5Final(mac, &ctx->u.md5);
139		break;
140	case CRYPTO_HASH_ALG_SHA1:
141		if (*len < 20) {
142			*len = 20;
143			os_free(ctx);
144			return -1;
145		}
146		*len = 20;
147		SHA1Final(mac, &ctx->u.sha1);
148		break;
149	case CRYPTO_HASH_ALG_HMAC_MD5:
150		if (*len < 16) {
151			*len = 16;
152			os_free(ctx);
153			return -1;
154		}
155		*len = 16;
156
157		MD5Final(mac, &ctx->u.md5);
158
159		os_memcpy(k_pad, ctx->key, ctx->key_len);
160		os_memset(k_pad + ctx->key_len, 0,
161			  sizeof(k_pad) - ctx->key_len);
162		for (i = 0; i < sizeof(k_pad); i++)
163			k_pad[i] ^= 0x5c;
164		MD5Init(&ctx->u.md5);
165		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
166		MD5Update(&ctx->u.md5, mac, 16);
167		MD5Final(mac, &ctx->u.md5);
168		break;
169	case CRYPTO_HASH_ALG_HMAC_SHA1:
170		if (*len < 20) {
171			*len = 20;
172			os_free(ctx);
173			return -1;
174		}
175		*len = 20;
176
177		SHA1Final(mac, &ctx->u.sha1);
178
179		os_memcpy(k_pad, ctx->key, ctx->key_len);
180		os_memset(k_pad + ctx->key_len, 0,
181			  sizeof(k_pad) - ctx->key_len);
182		for (i = 0; i < sizeof(k_pad); i++)
183			k_pad[i] ^= 0x5c;
184		SHA1Init(&ctx->u.sha1);
185		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
186		SHA1Update(&ctx->u.sha1, mac, 20);
187		SHA1Final(mac, &ctx->u.sha1);
188		break;
189	}
190
191	os_free(ctx);
192
193	return 0;
194}
195
196
197int crypto_global_init(void)
198{
199	return 0;
200}
201
202
203void crypto_global_deinit(void)
204{
205}
206