source: mainline/uspace/lib/crypto/crypto.c@ 1dcc0b9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1dcc0b9 was 1dcc0b9, checked in by Jan Kolarik <kolarik@…>, 10 years ago

Scanning whole 2.4GHz spectrum, created supplicant for managing connection between device STA and AP, finished association process between STA and AP, handling 4way handshake protocol used for key management, written needed cryptographic algorithms (AES, SHA1, HMAC, PBKDF2) for CCMP protocol, data communication on OPEN/CCMP networks.

  • Property mode set to 100644
File size: 8.7 KB
Line 
1/*
2 * Copyright (c) 2015 Jan Kolarik
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file crypto.c
30 *
31 * Cryptographic functions library.
32 */
33
34#include <unistd.h>
35#include <str.h>
36#include <macros.h>
37#include <errno.h>
38#include <byteorder.h>
39
40#include "crypto.h"
41
42typedef int (*HASH_FUNC)(uint8_t*, size_t, uint8_t*);
43
44#define ceil_uint32(val) (((val) - (uint32_t)(val)) > 0 ? \
45 (uint32_t)((val) + 1) : (uint32_t)(val))
46#define floor_uint32(val) (((val) - (uint32_t)(val)) < 0 ? \
47 (uint32_t)((val) - 1) : (uint32_t)(val))
48#define rotl_uint32(val, shift) (((val) << shift) | ((val) >> (32 - shift)))
49#define get_at(input, size, i) (i < size ? input[i] : 0)
50
51/**
52 * Setup hash function properties for use in crypto functions.
53 *
54 * @param hash_sel Hash function selector.
55 * @param hash_func Output parameter where hash function pointer is stored.
56 * @param hash_length Output parameter for setup result hash length.
57 */
58static void config_hash_func(hash_func_t hash_sel, HASH_FUNC *hash_func,
59 size_t *hash_length)
60{
61 switch(hash_sel) {
62 case HASH_MD5:
63 if(hash_func) *hash_func = md5;
64 *hash_length = MD5_HASH_LENGTH;
65 break;
66 case HASH_SHA1:
67 if(hash_func) *hash_func = sha1;
68 *hash_length = SHA1_HASH_LENGTH;
69 break;
70 }
71}
72
73/**
74 * MD5 cryptographic hash function.
75 *
76 * @param input Input sequence to be encrypted.
77 * @param input_size Size of input sequence.
78 * @param hash Output parameter for result hash (32 byte value).
79 *
80 * @return EINVAL when input not specified, ENOMEM when pointer for output
81 * hash result is not allocated, otherwise EOK.
82 */
83int md5(uint8_t *input, size_t input_size, uint8_t *hash)
84{
85 if(!input)
86 return EINVAL;
87
88 if(!hash)
89 return ENOMEM;
90
91 // TODO
92
93 return EOK;
94}
95
96/**
97 * SHA-1 cryptographic hash function.
98 *
99 * @param input Input sequence to be encrypted.
100 * @param input_size Size of input sequence.
101 * @param hash Output parameter for result hash (20 byte value).
102 *
103 * @return EINVAL when input not specified, ENOMEM when pointer for output
104 * hash result is not allocated, otherwise EOK.
105 */
106int sha1(uint8_t *input, size_t input_size, uint8_t *hash)
107{
108 if(!input)
109 return EINVAL;
110
111 if(!hash)
112 return ENOMEM;
113
114 uint32_t a, b, c, d, e, f, cf, temp;
115 uint32_t h[5] = {
116 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
117 };
118
119 uint8_t work_input[input_size + 1];
120 memcpy(work_input, input, input_size);
121 work_input[input_size] = 0x80;
122
123 size_t blocks = ceil_uint32((((double)input_size + 1) / 4 + 2) / 16);
124
125 uint32_t work_arr[blocks * 16 * sizeof(uint32_t)];
126 for(size_t i = 0; i < blocks; i++) {
127 for(size_t j = 0; j < 16; j++) {
128 work_arr[i*16 + j] =
129 (get_at(work_input, input_size+1, i*64+j*4) << 24) |
130 (get_at(work_input, input_size+1, i*64+j*4+1) << 16) |
131 (get_at(work_input, input_size+1, i*64+j*4+2) << 8) |
132 get_at(work_input, input_size+1, i*64+j*4+3);
133 }
134 }
135
136 work_arr[(blocks - 1) * 16 + 14] = (uint64_t)(input_size * 8) >> 32;
137 work_arr[(blocks - 1) * 16 + 15] = (input_size * 8) & 0xFFFFFFFF;
138
139 uint32_t sched_arr[80 * sizeof(uint32_t)];
140 for(size_t i = 0; i < blocks; i++) {
141 for(size_t k = 0; k < 16; k++) {
142 sched_arr[k] = work_arr[i*16 + k];
143 }
144
145 for(size_t k = 16; k < 80; k++) {
146 sched_arr[k] =
147 rotl_uint32(
148 sched_arr[k-3] ^
149 sched_arr[k-8] ^
150 sched_arr[k-14] ^
151 sched_arr[k-16],
152 1);
153 }
154
155 a = h[0]; b = h[1]; c = h[2]; d = h[3]; e = h[4];
156
157 for(size_t k = 0; k < 80; k++) {
158 if(k < 20) {
159 f = (b & c) | (~b & d);
160 cf = 0x5A827999;
161 } else if(k >= 20 && k < 40) {
162 f = b ^ c ^ d;
163 cf = 0x6ED9EBA1;
164 } else if(k >= 40 && k < 60) {
165 f = (b & c) | (b & d) | (c & d);
166 cf = 0x8F1BBCDC;
167 } else {
168 f = b ^ c ^ d;
169 cf = 0xCA62C1D6;
170 }
171
172 temp = (rotl_uint32(a, 5) + f + e + cf + sched_arr[k]) &
173 0xFFFFFFFF;
174
175 e = d;
176 d = c;
177 c = rotl_uint32(b, 30);
178 b = a;
179 a = temp;
180 }
181
182 h[0] = (h[0] + a) & 0xFFFFFFFF;
183 h[1] = (h[1] + b) & 0xFFFFFFFF;
184 h[2] = (h[2] + c) & 0xFFFFFFFF;
185 h[3] = (h[3] + d) & 0xFFFFFFFF;
186 h[4] = (h[4] + e) & 0xFFFFFFFF;
187 }
188
189 for(size_t i = 0; i < 5; i++) {
190 h[i] = uint32_t_be2host(h[i]);
191 memcpy(hash + i*sizeof(uint32_t), &h[i], sizeof(uint32_t));
192 }
193
194 return EOK;
195}
196
197/**
198 * Hash-based message authentication code using SHA-1 algorithm.
199 *
200 * @param key Cryptographic key sequence.
201 * @param key_size Size of key sequence.
202 * @param msg Message sequence.
203 * @param msg_size Size of message sequence.
204 * @param hash Output parameter for result hash.
205 * @param hash_sel Hash function selector.
206 *
207 * @return EINVAL when key or message not specified, ENOMEM when pointer for
208 * output hash result is not allocated, otherwise EOK.
209 */
210int hmac(uint8_t *key, size_t key_size, uint8_t *msg, size_t msg_size,
211 uint8_t *hash, hash_func_t hash_sel)
212{
213 if(!key || !msg)
214 return EINVAL;
215
216 if(!hash)
217 return ENOMEM;
218
219 size_t hash_length = 0;
220 HASH_FUNC hash_func = NULL;
221 config_hash_func(hash_sel, &hash_func, &hash_length);
222
223 uint8_t work_key[HMAC_BLOCK_LENGTH];
224 uint8_t o_key_pad[HMAC_BLOCK_LENGTH];
225 uint8_t i_key_pad[HMAC_BLOCK_LENGTH];
226 uint8_t temp_hash[hash_length];
227 memset(work_key, 0, HMAC_BLOCK_LENGTH);
228
229 if(key_size > HMAC_BLOCK_LENGTH) {
230 hash_func(key, key_size, work_key);
231 } else {
232 memcpy(work_key, key, key_size);
233 }
234
235 for(size_t i = 0; i < HMAC_BLOCK_LENGTH; i++) {
236 o_key_pad[i] = work_key[i] ^ 0x5C;
237 i_key_pad[i] = work_key[i] ^ 0x36;
238 }
239
240 uint8_t temp_work[HMAC_BLOCK_LENGTH + msg_size];
241 memcpy(temp_work, i_key_pad, HMAC_BLOCK_LENGTH);
242 memcpy(temp_work + HMAC_BLOCK_LENGTH, msg, msg_size);
243
244 hash_func(temp_work, HMAC_BLOCK_LENGTH + msg_size, temp_hash);
245
246 memcpy(temp_work, o_key_pad, HMAC_BLOCK_LENGTH);
247 memcpy(temp_work + HMAC_BLOCK_LENGTH, temp_hash, hash_length);
248
249 hash_func(temp_work, HMAC_BLOCK_LENGTH + hash_length, hash);
250
251 return EOK;
252}
253
254/**
255 * Password-Based Key Derivation Function 2 as defined in RFC 2898,
256 * using HMAC-SHA1 with 4096 iterations and 32 bytes key result used
257 * for WPA2.
258 *
259 * @param pass Password sequence.
260 * @param pass_size Password sequence length.
261 * @param salt Salt sequence to be used with password.
262 * @param salt_size Salt sequence length.
263 * @param hash Output parameter for result hash (32 byte value).
264 * @param hash_sel Hash function selector.
265 *
266 * @return EINVAL when pass or salt not specified, ENOMEM when pointer for
267 * output hash result is not allocated, otherwise EOK.
268 */
269int pbkdf2(uint8_t *pass, size_t pass_size, uint8_t *salt, size_t salt_size,
270 uint8_t *hash, hash_func_t hash_sel)
271{
272 if(!pass || !salt)
273 return EINVAL;
274
275 if(!hash)
276 return ENOMEM;
277
278 size_t hash_length = 0;
279 config_hash_func(hash_sel, NULL, &hash_length);
280
281 uint8_t work_salt[salt_size + sizeof(uint32_t)];
282 memcpy(work_salt, salt, salt_size);
283 uint8_t work_hmac[hash_length];
284 uint8_t temp_hmac[hash_length];
285 uint8_t xor_hmac[hash_length];
286 uint8_t temp_hash[hash_length*2];
287
288 for(size_t i = 0; i < 2; i++) {
289 uint32_t big_i = host2uint32_t_be(i+1);
290 memcpy(work_salt + salt_size, &big_i, sizeof(uint32_t));
291 hmac(pass, pass_size, work_salt, salt_size + sizeof(uint32_t),
292 work_hmac, hash_sel);
293 memcpy(xor_hmac, work_hmac, hash_length);
294 for(size_t k = 1; k < 4096; k++) {
295 memcpy(temp_hmac, work_hmac, hash_length);
296 hmac(pass, pass_size, temp_hmac, hash_length,
297 work_hmac, hash_sel);
298 for(size_t t = 0; t < hash_length; t++) {
299 xor_hmac[t] ^= work_hmac[t];
300 }
301 }
302 memcpy(temp_hash + i*hash_length, xor_hmac, hash_length);
303 }
304
305 memcpy(hash, temp_hash, PBKDF2_KEY_LENGTH);
306
307 return EOK;
308}
Note: See TracBrowser for help on using the repository browser.