Merge branch 'vendor/OPENBSD_LIBM'
[dragonfly.git] / contrib / hostapd / src / crypto / crypto_internal.c
1 /*
2  * Crypto wrapper for internal crypto implementation
3  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include "includes.h"
10
11 #include "common.h"
12 #include "crypto.h"
13 #include "sha256_i.h"
14 #include "sha1_i.h"
15 #include "md5_i.h"
16
17 struct crypto_hash {
18         enum crypto_hash_alg alg;
19         union {
20                 struct MD5Context md5;
21                 struct SHA1Context sha1;
22 #ifdef CONFIG_SHA256
23                 struct sha256_state sha256;
24 #endif /* CONFIG_SHA256 */
25         } u;
26         u8 key[64];
27         size_t key_len;
28 };
29
30
31 struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
32                                       size_t key_len)
33 {
34         struct crypto_hash *ctx;
35         u8 k_pad[64];
36         u8 tk[32];
37         size_t i;
38
39         ctx = os_zalloc(sizeof(*ctx));
40         if (ctx == NULL)
41                 return NULL;
42
43         ctx->alg = alg;
44
45         switch (alg) {
46         case CRYPTO_HASH_ALG_MD5:
47                 MD5Init(&ctx->u.md5);
48                 break;
49         case CRYPTO_HASH_ALG_SHA1:
50                 SHA1Init(&ctx->u.sha1);
51                 break;
52 #ifdef CONFIG_SHA256
53         case CRYPTO_HASH_ALG_SHA256:
54                 sha256_init(&ctx->u.sha256);
55                 break;
56 #endif /* CONFIG_SHA256 */
57         case CRYPTO_HASH_ALG_HMAC_MD5:
58                 if (key_len > sizeof(k_pad)) {
59                         MD5Init(&ctx->u.md5);
60                         MD5Update(&ctx->u.md5, key, key_len);
61                         MD5Final(tk, &ctx->u.md5);
62                         key = tk;
63                         key_len = 16;
64                 }
65                 os_memcpy(ctx->key, key, key_len);
66                 ctx->key_len = key_len;
67
68                 os_memcpy(k_pad, key, key_len);
69                 if (key_len < sizeof(k_pad))
70                         os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
71                 for (i = 0; i < sizeof(k_pad); i++)
72                         k_pad[i] ^= 0x36;
73                 MD5Init(&ctx->u.md5);
74                 MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
75                 break;
76         case CRYPTO_HASH_ALG_HMAC_SHA1:
77                 if (key_len > sizeof(k_pad)) {
78                         SHA1Init(&ctx->u.sha1);
79                         SHA1Update(&ctx->u.sha1, key, key_len);
80                         SHA1Final(tk, &ctx->u.sha1);
81                         key = tk;
82                         key_len = 20;
83                 }
84                 os_memcpy(ctx->key, key, key_len);
85                 ctx->key_len = key_len;
86
87                 os_memcpy(k_pad, key, key_len);
88                 if (key_len < sizeof(k_pad))
89                         os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
90                 for (i = 0; i < sizeof(k_pad); i++)
91                         k_pad[i] ^= 0x36;
92                 SHA1Init(&ctx->u.sha1);
93                 SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
94                 break;
95 #ifdef CONFIG_SHA256
96         case CRYPTO_HASH_ALG_HMAC_SHA256:
97                 if (key_len > sizeof(k_pad)) {
98                         sha256_init(&ctx->u.sha256);
99                         sha256_process(&ctx->u.sha256, key, key_len);
100                         sha256_done(&ctx->u.sha256, tk);
101                         key = tk;
102                         key_len = 32;
103                 }
104                 os_memcpy(ctx->key, key, key_len);
105                 ctx->key_len = key_len;
106
107                 os_memcpy(k_pad, key, key_len);
108                 if (key_len < sizeof(k_pad))
109                         os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
110                 for (i = 0; i < sizeof(k_pad); i++)
111                         k_pad[i] ^= 0x36;
112                 sha256_init(&ctx->u.sha256);
113                 sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
114                 break;
115 #endif /* CONFIG_SHA256 */
116         default:
117                 os_free(ctx);
118                 return NULL;
119         }
120
121         return ctx;
122 }
123
124
125 void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
126 {
127         if (ctx == NULL)
128                 return;
129
130         switch (ctx->alg) {
131         case CRYPTO_HASH_ALG_MD5:
132         case CRYPTO_HASH_ALG_HMAC_MD5:
133                 MD5Update(&ctx->u.md5, data, len);
134                 break;
135         case CRYPTO_HASH_ALG_SHA1:
136         case CRYPTO_HASH_ALG_HMAC_SHA1:
137                 SHA1Update(&ctx->u.sha1, data, len);
138                 break;
139 #ifdef CONFIG_SHA256
140         case CRYPTO_HASH_ALG_SHA256:
141         case CRYPTO_HASH_ALG_HMAC_SHA256:
142                 sha256_process(&ctx->u.sha256, data, len);
143                 break;
144 #endif /* CONFIG_SHA256 */
145         default:
146                 break;
147         }
148 }
149
150
151 int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
152 {
153         u8 k_pad[64];
154         size_t i;
155
156         if (ctx == NULL)
157                 return -2;
158
159         if (mac == NULL || len == NULL) {
160                 os_free(ctx);
161                 return 0;
162         }
163
164         switch (ctx->alg) {
165         case CRYPTO_HASH_ALG_MD5:
166                 if (*len < 16) {
167                         *len = 16;
168                         os_free(ctx);
169                         return -1;
170                 }
171                 *len = 16;
172                 MD5Final(mac, &ctx->u.md5);
173                 break;
174         case CRYPTO_HASH_ALG_SHA1:
175                 if (*len < 20) {
176                         *len = 20;
177                         os_free(ctx);
178                         return -1;
179                 }
180                 *len = 20;
181                 SHA1Final(mac, &ctx->u.sha1);
182                 break;
183 #ifdef CONFIG_SHA256
184         case CRYPTO_HASH_ALG_SHA256:
185                 if (*len < 32) {
186                         *len = 32;
187                         os_free(ctx);
188                         return -1;
189                 }
190                 *len = 32;
191                 sha256_done(&ctx->u.sha256, mac);
192                 break;
193 #endif /* CONFIG_SHA256 */
194         case CRYPTO_HASH_ALG_HMAC_MD5:
195                 if (*len < 16) {
196                         *len = 16;
197                         os_free(ctx);
198                         return -1;
199                 }
200                 *len = 16;
201
202                 MD5Final(mac, &ctx->u.md5);
203
204                 os_memcpy(k_pad, ctx->key, ctx->key_len);
205                 os_memset(k_pad + ctx->key_len, 0,
206                           sizeof(k_pad) - ctx->key_len);
207                 for (i = 0; i < sizeof(k_pad); i++)
208                         k_pad[i] ^= 0x5c;
209                 MD5Init(&ctx->u.md5);
210                 MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
211                 MD5Update(&ctx->u.md5, mac, 16);
212                 MD5Final(mac, &ctx->u.md5);
213                 break;
214         case CRYPTO_HASH_ALG_HMAC_SHA1:
215                 if (*len < 20) {
216                         *len = 20;
217                         os_free(ctx);
218                         return -1;
219                 }
220                 *len = 20;
221
222                 SHA1Final(mac, &ctx->u.sha1);
223
224                 os_memcpy(k_pad, ctx->key, ctx->key_len);
225                 os_memset(k_pad + ctx->key_len, 0,
226                           sizeof(k_pad) - ctx->key_len);
227                 for (i = 0; i < sizeof(k_pad); i++)
228                         k_pad[i] ^= 0x5c;
229                 SHA1Init(&ctx->u.sha1);
230                 SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
231                 SHA1Update(&ctx->u.sha1, mac, 20);
232                 SHA1Final(mac, &ctx->u.sha1);
233                 break;
234 #ifdef CONFIG_SHA256
235         case CRYPTO_HASH_ALG_HMAC_SHA256:
236                 if (*len < 32) {
237                         *len = 32;
238                         os_free(ctx);
239                         return -1;
240                 }
241                 *len = 32;
242
243                 sha256_done(&ctx->u.sha256, mac);
244
245                 os_memcpy(k_pad, ctx->key, ctx->key_len);
246                 os_memset(k_pad + ctx->key_len, 0,
247                           sizeof(k_pad) - ctx->key_len);
248                 for (i = 0; i < sizeof(k_pad); i++)
249                         k_pad[i] ^= 0x5c;
250                 sha256_init(&ctx->u.sha256);
251                 sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
252                 sha256_process(&ctx->u.sha256, mac, 32);
253                 sha256_done(&ctx->u.sha256, mac);
254                 break;
255 #endif /* CONFIG_SHA256 */
256         default:
257                 os_free(ctx);
258                 return -1;
259         }
260
261         os_free(ctx);
262
263         return 0;
264 }
265
266
267 int crypto_global_init(void)
268 {
269         return 0;
270 }
271
272
273 void crypto_global_deinit(void)
274 {
275 }