source: mainline/uspace/lib/crypto/crypto.c@ 34e1206

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 34e1206 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 10.6 KB
RevLine 
[1dcc0b9]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
[8a64320e]30 *
[1dcc0b9]31 * Cryptographic functions library.
32 */
33
34#include <str.h>
35#include <macros.h>
36#include <errno.h>
37#include <byteorder.h>
38#include "crypto.h"
39
[8a64320e]40/** Hash function procedure definition. */
41typedef void (*hash_fnc_t)(uint32_t *, uint32_t *);
[1dcc0b9]42
[8a64320e]43/** Length of HMAC block. */
44#define HMAC_BLOCK_LENGTH 64
[d7dadcb4]45
[8a64320e]46/** Ceiling for uint32_t. */
47#define ceil_uint32(val) \
48 (((val) - (uint32_t) (val)) > 0 ? \
49 (uint32_t) ((val) + 1) : (uint32_t) (val))
[d7dadcb4]50
[8a64320e]51/** Floor for uint32_t. */
52#define floor_uint32(val) \
53 (((val) - (uint32_t) (val)) < 0 ? \
54 (uint32_t) ((val) - 1) : (uint32_t) (val))
[d7dadcb4]55
[8a64320e]56/** Pick value at specified index from array or zero if out of bounds. */
57#define get_at(input, size, i) \
58 ((i) < (size) ? (input[i]) : 0)
[1dcc0b9]59
[8a64320e]60/** Init values used in SHA1 and MD5 functions. */
[d7dadcb4]61static const uint32_t hash_init[] = {
[8a64320e]62 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
[d7dadcb4]63};
64
[8a64320e]65/** Shift amount array for MD5 algorithm. */
[d7dadcb4]66static const uint32_t md5_shift[] = {
67 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
68 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
69 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
70 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
71};
72
[8a64320e]73/** Substitution box for MD5 algorithm. */
[d7dadcb4]74static const uint32_t md5_sbox[] = {
75 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
76 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
77 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
78 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
79 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
80 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
81 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
82 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
83 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
84 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
85 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
86 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
87 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
88 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
89 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
90 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
91};
92
[8a64320e]93/** Working procedure of MD5 cryptographic hash function.
94 *
95 * @param h Working array with interim hash parts values.
[d7dadcb4]96 * @param sched_arr Input array with scheduled values from input string.
[8a64320e]97 *
[1dcc0b9]98 */
[d7dadcb4]99static void md5_proc(uint32_t *h, uint32_t *sched_arr)
[1dcc0b9]100{
[d7dadcb4]101 uint32_t f, g, temp;
[8a64320e]102 uint32_t w[HASH_MD5 / 4];
[a35b458]103
[8a64320e]104 memcpy(w, h, (HASH_MD5 / 4) * sizeof(uint32_t));
[a35b458]105
[8a64320e]106 for (size_t k = 0; k < 64; k++) {
107 if (k < 16) {
[d7dadcb4]108 f = (w[1] & w[2]) | (~w[1] & w[3]);
109 g = k;
[8a64320e]110 } else if ((k >= 16) && (k < 32)) {
[d7dadcb4]111 f = (w[1] & w[3]) | (w[2] & ~w[3]);
[8a64320e]112 g = (5 * k + 1) % 16;
113 } else if ((k >= 32) && (k < 48)) {
[d7dadcb4]114 f = w[1] ^ w[2] ^ w[3];
[8a64320e]115 g = (3 * k + 5) % 16;
[d7dadcb4]116 } else {
117 f = w[2] ^ (w[1] | ~w[3]);
[8a64320e]118 g = 7 * k % 16;
[d7dadcb4]119 }
[a35b458]120
[d7dadcb4]121 temp = w[3];
122 w[3] = w[2];
123 w[2] = w[1];
[8a64320e]124 w[1] += rotl_uint32(w[0] + f + md5_sbox[k] +
125 uint32_t_byteorder_swap(sched_arr[g]),
126 md5_shift[k]);
[d7dadcb4]127 w[0] = temp;
[1dcc0b9]128 }
[a35b458]129
[8a64320e]130 for (uint8_t k = 0; k < HASH_MD5 / 4; k++)
[d7dadcb4]131 h[k] += w[k];
[1dcc0b9]132}
133
[8a64320e]134/** Working procedure of SHA-1 cryptographic hash function.
135 *
136 * @param h Working array with interim hash parts values.
[d7dadcb4]137 * @param sched_arr Input array with scheduled values from input string.
[8a64320e]138 *
[1dcc0b9]139 */
[d7dadcb4]140static void sha1_proc(uint32_t *h, uint32_t *sched_arr)
[1dcc0b9]141{
[d7dadcb4]142 uint32_t f, cf, temp;
[8a64320e]143 uint32_t w[HASH_SHA1 / 4];
[a35b458]144
[8a64320e]145 for (size_t k = 16; k < 80; k++) {
[d7dadcb4]146 sched_arr[k] = rotl_uint32(
[8a64320e]147 sched_arr[k-3] ^
148 sched_arr[k-8] ^
149 sched_arr[k-14] ^
150 sched_arr[k-16],
151 1);
[d7dadcb4]152 }
[a35b458]153
[8a64320e]154 memcpy(w, h, (HASH_SHA1 / 4) * sizeof(uint32_t));
[a35b458]155
[8a64320e]156 for (size_t k = 0; k < 80; k++) {
157 if (k < 20) {
[d7dadcb4]158 f = (w[1] & w[2]) | (~w[1] & w[3]);
159 cf = 0x5A827999;
[8a64320e]160 } else if ((k >= 20) && (k < 40)) {
[d7dadcb4]161 f = w[1] ^ w[2] ^ w[3];
[8a64320e]162 cf = 0x6ed9eba1;
163 } else if ((k >= 40) && (k < 60)) {
[d7dadcb4]164 f = (w[1] & w[2]) | (w[1] & w[3]) | (w[2] & w[3]);
[8a64320e]165 cf = 0x8f1bbcdc;
[d7dadcb4]166 } else {
167 f = w[1] ^ w[2] ^ w[3];
[8a64320e]168 cf = 0xca62c1d6;
[d7dadcb4]169 }
[a35b458]170
[d7dadcb4]171 temp = rotl_uint32(w[0], 5) + f + w[4] + cf + sched_arr[k];
[a35b458]172
[d7dadcb4]173 w[4] = w[3];
174 w[3] = w[2];
175 w[2] = rotl_uint32(w[1], 30);
176 w[1] = w[0];
177 w[0] = temp;
178 }
[a35b458]179
[8a64320e]180 for (uint8_t k = 0; k < HASH_SHA1 / 4; k++)
[d7dadcb4]181 h[k] += w[k];
[1dcc0b9]182}
183
[8a64320e]184/** Create hash based on selected algorithm.
185 *
186 * @param input Input message byte sequence.
[d7dadcb4]187 * @param input_size Size of message sequence.
[8a64320e]188 * @param output Result hash byte sequence.
189 * @param hash_sel Hash function selector.
190 *
191 * @return EINVAL when input not specified,
192 * ENOMEM when pointer for output hash result
193 * is not allocated, otherwise EOK.
194 *
[1dcc0b9]195 */
[b7fd2a0]196errno_t create_hash(uint8_t *input, size_t input_size, uint8_t *output,
[8a64320e]197 hash_func_t hash_sel)
[1dcc0b9]198{
[8a64320e]199 if (!input)
[1dcc0b9]200 return EINVAL;
[a35b458]201
[8a64320e]202 if (!output)
[1dcc0b9]203 return ENOMEM;
[a35b458]204
[8a64320e]205 hash_fnc_t hash_func = (hash_sel == HASH_MD5) ? md5_proc : sha1_proc;
[a35b458]206
[d7dadcb4]207 /* Prepare scheduled input. */
[1dcc0b9]208 uint8_t work_input[input_size + 1];
209 memcpy(work_input, input, input_size);
210 work_input[input_size] = 0x80;
[a35b458]211
[8a64320e]212 // FIXME: double?
213 size_t blocks = ceil_uint32((((double) input_size + 1) / 4 + 2) / 16);
[d7dadcb4]214 uint32_t work_arr[blocks * 16];
[8a64320e]215 for (size_t i = 0; i < blocks; i++) {
216 for (size_t j = 0; j < 16; j++) {
217 work_arr[i*16 + j] =
218 (get_at(work_input, input_size + 1, i * 64 + j * 4) << 24) |
219 (get_at(work_input, input_size + 1, i * 64 + j * 4 + 1) << 16) |
220 (get_at(work_input, input_size + 1, i * 64 + j * 4 + 2) << 8) |
221 get_at(work_input, input_size + 1, i * 64 + j * 4 + 3);
[1dcc0b9]222 }
223 }
[a35b458]224
[8a64320e]225 uint64_t bits_size = (uint64_t) (input_size * 8);
226 if (hash_sel == HASH_MD5)
[d7dadcb4]227 bits_size = uint64_t_byteorder_swap(bits_size);
[a35b458]228
[d7dadcb4]229 work_arr[(blocks - 1) * 16 + 14] = bits_size >> 32;
[8a64320e]230 work_arr[(blocks - 1) * 16 + 15] = bits_size & 0xffffffff;
[a35b458]231
[d7dadcb4]232 /* Hash computation. */
[8a64320e]233 uint32_t h[hash_sel / 4];
234 memcpy(h, hash_init, (hash_sel / 4) * sizeof(uint32_t));
[d7dadcb4]235 uint32_t sched_arr[80];
[8a64320e]236 for (size_t i = 0; i < blocks; i++) {
237 for (size_t k = 0; k < 16; k++)
238 sched_arr[k] = work_arr[i * 16 + k];
[a35b458]239
[d7dadcb4]240 hash_func(h, sched_arr);
[1dcc0b9]241 }
[a35b458]242
[d7dadcb4]243 /* Copy hash parts into final result. */
[8a64320e]244 for (size_t i = 0; i < hash_sel / 4; i++) {
245 if (hash_sel == HASH_SHA1)
[d7dadcb4]246 h[i] = uint32_t_byteorder_swap(h[i]);
[a35b458]247
[8a64320e]248 memcpy(output + i * sizeof(uint32_t), &h[i], sizeof(uint32_t));
[1dcc0b9]249 }
[a35b458]250
[1dcc0b9]251 return EOK;
252}
253
[8a64320e]254/** Hash-based message authentication code.
255 *
256 * @param key Cryptographic key sequence.
[1dcc0b9]257 * @param key_size Size of key sequence.
[8a64320e]258 * @param msg Message sequence.
[1dcc0b9]259 * @param msg_size Size of message sequence.
[8a64320e]260 * @param hash Output parameter for result hash.
[1dcc0b9]261 * @param hash_sel Hash function selector.
[8a64320e]262 *
263 * @return EINVAL when key or message not specified,
264 * ENOMEM when pointer for output hash result
265 * is not allocated, otherwise EOK.
266 *
[1dcc0b9]267 */
[1b20da0]268errno_t hmac(uint8_t *key, size_t key_size, uint8_t *msg, size_t msg_size,
[8a64320e]269 uint8_t *hash, hash_func_t hash_sel)
[1dcc0b9]270{
[8a64320e]271 if ((!key) || (!msg))
[1dcc0b9]272 return EINVAL;
[a35b458]273
[8a64320e]274 if (!hash)
[1dcc0b9]275 return ENOMEM;
[a35b458]276
[1dcc0b9]277 uint8_t work_key[HMAC_BLOCK_LENGTH];
278 uint8_t o_key_pad[HMAC_BLOCK_LENGTH];
279 uint8_t i_key_pad[HMAC_BLOCK_LENGTH];
[d7dadcb4]280 uint8_t temp_hash[hash_sel];
[1dcc0b9]281 memset(work_key, 0, HMAC_BLOCK_LENGTH);
[a35b458]282
[8a64320e]283 if(key_size > HMAC_BLOCK_LENGTH)
[d7dadcb4]284 create_hash(key, key_size, work_key, hash_sel);
[8a64320e]285 else
[1dcc0b9]286 memcpy(work_key, key, key_size);
[a35b458]287
[8a64320e]288 for (size_t i = 0; i < HMAC_BLOCK_LENGTH; i++) {
289 o_key_pad[i] = work_key[i] ^ 0x5c;
[1dcc0b9]290 i_key_pad[i] = work_key[i] ^ 0x36;
291 }
[a35b458]292
[cc575ef9]293 uint8_t temp_work[HMAC_BLOCK_LENGTH + max(msg_size, hash_sel)];
[1dcc0b9]294 memcpy(temp_work, i_key_pad, HMAC_BLOCK_LENGTH);
295 memcpy(temp_work + HMAC_BLOCK_LENGTH, msg, msg_size);
[a35b458]296
[8a64320e]297 create_hash(temp_work, HMAC_BLOCK_LENGTH + msg_size, temp_hash,
298 hash_sel);
[a35b458]299
[1dcc0b9]300 memcpy(temp_work, o_key_pad, HMAC_BLOCK_LENGTH);
[d7dadcb4]301 memcpy(temp_work + HMAC_BLOCK_LENGTH, temp_hash, hash_sel);
[a35b458]302
[d7dadcb4]303 create_hash(temp_work, HMAC_BLOCK_LENGTH + hash_sel, hash, hash_sel);
[a35b458]304
[1dcc0b9]305 return EOK;
306}
307
[8a64320e]308/** Password-Based Key Derivation Function 2.
309 *
310 * As defined in RFC 2898, using HMAC-SHA1 with 4096 iterations
311 * and 32 bytes key result used for WPA/WPA2.
312 *
313 * @param pass Password sequence.
[1dcc0b9]314 * @param pass_size Password sequence length.
[8a64320e]315 * @param salt Salt sequence to be used with password.
[1dcc0b9]316 * @param salt_size Salt sequence length.
[8a64320e]317 * @param hash Output parameter for result hash (32 byte value).
318 *
319 * @return EINVAL when pass or salt not specified,
320 * ENOMEM when pointer for output hash result
321 * is not allocated, otherwise EOK.
322 *
[1dcc0b9]323 */
[b7fd2a0]324errno_t pbkdf2(uint8_t *pass, size_t pass_size, uint8_t *salt, size_t salt_size,
[8a64320e]325 uint8_t *hash)
[1dcc0b9]326{
[8a64320e]327 if ((!pass) || (!salt))
[1dcc0b9]328 return EINVAL;
[a35b458]329
[8a64320e]330 if (!hash)
[1dcc0b9]331 return ENOMEM;
[a35b458]332
[cc575ef9]333 uint8_t work_salt[salt_size + 4];
[1dcc0b9]334 memcpy(work_salt, salt, salt_size);
[a931b7b]335 uint8_t work_hmac[HASH_SHA1];
336 uint8_t temp_hmac[HASH_SHA1];
337 uint8_t xor_hmac[HASH_SHA1];
[8a64320e]338 uint8_t temp_hash[HASH_SHA1 * 2];
[a35b458]339
[8a64320e]340 for (size_t i = 0; i < 2; i++) {
341 uint32_t be_i = host2uint32_t_be(i + 1);
[a35b458]342
[cc575ef9]343 memcpy(work_salt + salt_size, &be_i, 4);
344 hmac(pass, pass_size, work_salt, salt_size + 4,
[8a64320e]345 work_hmac, HASH_SHA1);
[a931b7b]346 memcpy(xor_hmac, work_hmac, HASH_SHA1);
[a35b458]347
[8a64320e]348 for (size_t k = 1; k < 4096; k++) {
[a931b7b]349 memcpy(temp_hmac, work_hmac, HASH_SHA1);
[8a64320e]350 hmac(pass, pass_size, temp_hmac, HASH_SHA1,
351 work_hmac, HASH_SHA1);
[a35b458]352
[8a64320e]353 for (size_t t = 0; t < HASH_SHA1; t++)
[1dcc0b9]354 xor_hmac[t] ^= work_hmac[t];
355 }
[a35b458]356
[8a64320e]357 memcpy(temp_hash + i * HASH_SHA1, xor_hmac, HASH_SHA1);
[1dcc0b9]358 }
[a35b458]359
[1dcc0b9]360 memcpy(hash, temp_hash, PBKDF2_KEY_LENGTH);
[a35b458]361
[1dcc0b9]362 return EOK;
363}
Note: See TracBrowser for help on using the repository browser.