Changeset 8a64320e in mainline for uspace/lib/crypto/crypto.c
- Timestamp:
- 2015-04-23T23:40:14Z (10 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- dcba819
- Parents:
- 09044cb
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/crypto/crypto.c
r09044cb r8a64320e 28 28 29 29 /** @file crypto.c 30 * 30 * 31 31 * Cryptographic functions library. 32 32 */ … … 37 37 #include <errno.h> 38 38 #include <byteorder.h> 39 40 39 #include "crypto.h" 41 40 42 /* Hash function procedure definition. */ 43 typedef void (*HASH_FUNC)(uint32_t*, uint32_t*); 44 45 /* Length of HMAC block. */ 46 #define HMAC_BLOCK_LENGTH 64 47 48 /* Ceiling for UINT32. */ 49 #define ceil_uint32(val) (((val) - (uint32_t)(val)) > 0 ? \ 50 (uint32_t)((val) + 1) : (uint32_t)(val)) 51 52 /* Floor for UINT32. */ 53 #define floor_uint32(val) (((val) - (uint32_t)(val)) < 0 ? \ 54 (uint32_t)((val) - 1) : (uint32_t)(val)) 55 56 /* Pick value at specified index from array or zero if out of bounds. */ 57 #define get_at(input, size, i) (i < size ? input[i] : 0) 58 59 /* Init values used in SHA1 and MD5 functions. */ 41 /** Hash function procedure definition. */ 42 typedef void (*hash_fnc_t)(uint32_t *, uint32_t *); 43 44 /** Length of HMAC block. */ 45 #define HMAC_BLOCK_LENGTH 64 46 47 /** Ceiling for uint32_t. */ 48 #define ceil_uint32(val) \ 49 (((val) - (uint32_t) (val)) > 0 ? \ 50 (uint32_t) ((val) + 1) : (uint32_t) (val)) 51 52 /** Floor for uint32_t. */ 53 #define floor_uint32(val) \ 54 (((val) - (uint32_t) (val)) < 0 ? \ 55 (uint32_t) ((val) - 1) : (uint32_t) (val)) 56 57 /** Pick value at specified index from array or zero if out of bounds. */ 58 #define get_at(input, size, i) \ 59 ((i) < (size) ? (input[i]) : 0) 60 61 /** Init values used in SHA1 and MD5 functions. */ 60 62 static const uint32_t hash_init[] = { 61 0x67452301, 0x EFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F063 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 62 64 }; 63 65 64 /* Shift amount array for MD5 algorithm. */66 /** Shift amount array for MD5 algorithm. */ 65 67 static const uint32_t md5_shift[] = { 66 68 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, … … 70 72 }; 71 73 72 /* Substitution box for MD5 algorithm. */74 /** Substitution box for MD5 algorithm. */ 73 75 static const uint32_t md5_sbox[] = { 74 76 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, … … 90 92 }; 91 93 92 /** 93 * Working procedure of MD5 cryptographic hash function. 94 * 95 * @param h Working array with interim hash parts values. 94 /** Working procedure of MD5 cryptographic hash function. 95 * 96 * @param h Working array with interim hash parts values. 96 97 * @param sched_arr Input array with scheduled values from input string. 98 * 97 99 */ 98 100 static void md5_proc(uint32_t *h, uint32_t *sched_arr) 99 101 { 100 102 uint32_t f, g, temp; 101 uint32_t w[HASH_MD5 /4];102 103 memcpy(w, h, (HASH_MD5 /4) * sizeof(uint32_t));104 105 for (size_t k = 0; k < 64; k++) {106 if (k < 16) {103 uint32_t w[HASH_MD5 / 4]; 104 105 memcpy(w, h, (HASH_MD5 / 4) * sizeof(uint32_t)); 106 107 for (size_t k = 0; k < 64; k++) { 108 if (k < 16) { 107 109 f = (w[1] & w[2]) | (~w[1] & w[3]); 108 110 g = k; 109 } else if (k >= 16 && k < 32) {111 } else if ((k >= 16) && (k < 32)) { 110 112 f = (w[1] & w[3]) | (w[2] & ~w[3]); 111 g = (5 *k + 1) % 16;112 } else if (k >= 32 && k < 48) {113 g = (5 * k + 1) % 16; 114 } else if ((k >= 32) && (k < 48)) { 113 115 f = w[1] ^ w[2] ^ w[3]; 114 g = (3 *k + 5) % 16;116 g = (3 * k + 5) % 16; 115 117 } else { 116 118 f = w[2] ^ (w[1] | ~w[3]); 117 g = 7 *k % 16;119 g = 7 * k % 16; 118 120 } 121 119 122 temp = w[3]; 120 123 w[3] = w[2]; 121 124 w[2] = w[1]; 122 w[1] += rotl_uint32(w[0] + f + md5_sbox[k] + 123 uint32_t_byteorder_swap(sched_arr[g]),124 125 w[1] += rotl_uint32(w[0] + f + md5_sbox[k] + 126 uint32_t_byteorder_swap(sched_arr[g]), 127 md5_shift[k]); 125 128 w[0] = temp; 126 129 } 127 130 128 for (uint8_t k = 0; k < HASH_MD5/4; k++)131 for (uint8_t k = 0; k < HASH_MD5 / 4; k++) 129 132 h[k] += w[k]; 130 133 } 131 134 132 /** 133 * Working procedure of SHA-1 cryptographic hash function. 134 * 135 * @param h Working array with interim hash parts values. 135 /** Working procedure of SHA-1 cryptographic hash function. 136 * 137 * @param h Working array with interim hash parts values. 136 138 * @param sched_arr Input array with scheduled values from input string. 139 * 137 140 */ 138 141 static void sha1_proc(uint32_t *h, uint32_t *sched_arr) 139 142 { 140 143 uint32_t f, cf, temp; 141 uint32_t w[HASH_SHA1 /4];142 143 for (size_t k = 16; k < 80; k++) {144 uint32_t w[HASH_SHA1 / 4]; 145 146 for (size_t k = 16; k < 80; k++) { 144 147 sched_arr[k] = rotl_uint32( 145 146 147 148 sched_arr[k-16],149 150 } 151 152 memcpy(w, h, (HASH_SHA1 /4) * sizeof(uint32_t));153 154 for (size_t k = 0; k < 80; k++) {155 if (k < 20) {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 memcpy(w, h, (HASH_SHA1 / 4) * sizeof(uint32_t)); 156 157 for (size_t k = 0; k < 80; k++) { 158 if (k < 20) { 156 159 f = (w[1] & w[2]) | (~w[1] & w[3]); 157 160 cf = 0x5A827999; 158 } else if (k >= 20 && k < 40) {161 } else if ((k >= 20) && (k < 40)) { 159 162 f = w[1] ^ w[2] ^ w[3]; 160 cf = 0x6 ED9EBA1;161 } else if (k >= 40 && k < 60) {163 cf = 0x6ed9eba1; 164 } else if ((k >= 40) && (k < 60)) { 162 165 f = (w[1] & w[2]) | (w[1] & w[3]) | (w[2] & w[3]); 163 cf = 0x8 F1BBCDC;166 cf = 0x8f1bbcdc; 164 167 } else { 165 168 f = w[1] ^ w[2] ^ w[3]; 166 cf = 0x CA62C1D6;169 cf = 0xca62c1d6; 167 170 } 168 171 169 172 temp = rotl_uint32(w[0], 5) + f + w[4] + cf + sched_arr[k]; 170 173 171 174 w[4] = w[3]; 172 175 w[3] = w[2]; … … 175 178 w[0] = temp; 176 179 } 177 178 for (uint8_t k = 0; k < HASH_SHA1/4; k++)180 181 for (uint8_t k = 0; k < HASH_SHA1 / 4; k++) 179 182 h[k] += w[k]; 180 183 } 181 184 182 /** 183 * Create hash based on selected algorithm. 184 * 185 * @param input Input message byte sequence. 185 /** Create hash based on selected algorithm. 186 * 187 * @param input Input message byte sequence. 186 188 * @param input_size Size of message sequence. 187 * @param output Result hash byte sequence. 188 * @param hash_sel Hash function selector. 189 * 190 * @return EINVAL when input not specified, ENOMEM when pointer for 191 * output hash result is not allocated, otherwise EOK. 189 * @param output Result hash byte sequence. 190 * @param hash_sel Hash function selector. 191 * 192 * @return EINVAL when input not specified, 193 * ENOMEM when pointer for output hash result 194 * is not allocated, otherwise EOK. 195 * 192 196 */ 193 197 int create_hash(uint8_t *input, size_t input_size, uint8_t *output, 194 195 { 196 if (!input)198 hash_func_t hash_sel) 199 { 200 if (!input) 197 201 return EINVAL; 198 202 199 if (!output)203 if (!output) 200 204 return ENOMEM; 201 205 202 HASH_FUNChash_func = (hash_sel == HASH_MD5) ? md5_proc : sha1_proc;206 hash_fnc_t hash_func = (hash_sel == HASH_MD5) ? md5_proc : sha1_proc; 203 207 204 208 /* Prepare scheduled input. */ … … 207 211 work_input[input_size] = 0x80; 208 212 209 size_t blocks = ceil_uint32((((double)input_size + 1) / 4 + 2) / 16); 213 // FIXME: double? 214 size_t blocks = ceil_uint32((((double) input_size + 1) / 4 + 2) / 16); 210 215 uint32_t work_arr[blocks * 16]; 211 for (size_t i = 0; i < blocks; i++) {212 for (size_t j = 0; j < 16; j++) {213 work_arr[i*16 + j] = 214 (get_at(work_input, input_size+1, i*64+j*4) << 24) |215 (get_at(work_input, input_size+1, i*64+j*4+1) << 16) |216 (get_at(work_input, input_size+1, i*64+j*4+2) << 8) |217 get_at(work_input, input_size+1, i*64+j*4+3);216 for (size_t i = 0; i < blocks; i++) { 217 for (size_t j = 0; j < 16; j++) { 218 work_arr[i*16 + j] = 219 (get_at(work_input, input_size + 1, i * 64 + j * 4) << 24) | 220 (get_at(work_input, input_size + 1, i * 64 + j * 4 + 1) << 16) | 221 (get_at(work_input, input_size + 1, i * 64 + j * 4 + 2) << 8) | 222 get_at(work_input, input_size + 1, i * 64 + j * 4 + 3); 218 223 } 219 224 } 220 225 221 uint64_t bits_size = (uint64_t) (input_size * 8);222 if (hash_sel == HASH_MD5)226 uint64_t bits_size = (uint64_t) (input_size * 8); 227 if (hash_sel == HASH_MD5) 223 228 bits_size = uint64_t_byteorder_swap(bits_size); 224 229 225 230 work_arr[(blocks - 1) * 16 + 14] = bits_size >> 32; 226 work_arr[(blocks - 1) * 16 + 15] = bits_size & 0x FFFFFFFF;231 work_arr[(blocks - 1) * 16 + 15] = bits_size & 0xffffffff; 227 232 228 233 /* Hash computation. */ 229 uint32_t h[hash_sel /4];230 memcpy(h, hash_init, (hash_sel /4) * sizeof(uint32_t));234 uint32_t h[hash_sel / 4]; 235 memcpy(h, hash_init, (hash_sel / 4) * sizeof(uint32_t)); 231 236 uint32_t sched_arr[80]; 232 for(size_t i = 0; i < blocks; i++) { 233 for(size_t k = 0; k < 16; k++) { 234 sched_arr[k] = work_arr[i*16 + k]; 235 } 237 for (size_t i = 0; i < blocks; i++) { 238 for (size_t k = 0; k < 16; k++) 239 sched_arr[k] = work_arr[i * 16 + k]; 236 240 237 241 hash_func(h, sched_arr); … … 239 243 240 244 /* Copy hash parts into final result. */ 241 for (size_t i = 0; i < hash_sel/4; i++) {242 if (hash_sel == HASH_SHA1)245 for (size_t i = 0; i < hash_sel / 4; i++) { 246 if (hash_sel == HASH_SHA1) 243 247 h[i] = uint32_t_byteorder_swap(h[i]); 244 memcpy(output + i*sizeof(uint32_t), &h[i], sizeof(uint32_t)); 248 249 memcpy(output + i * sizeof(uint32_t), &h[i], sizeof(uint32_t)); 245 250 } 246 251 … … 248 253 } 249 254 250 /** 251 * Hash-based message authentication code. 252 * 253 * @param key Cryptographic key sequence. 255 /** Hash-based message authentication code. 256 * 257 * @param key Cryptographic key sequence. 254 258 * @param key_size Size of key sequence. 255 * @param msg Message sequence.259 * @param msg Message sequence. 256 260 * @param msg_size Size of message sequence. 257 * @param hash Output parameter for result hash.261 * @param hash Output parameter for result hash. 258 262 * @param hash_sel Hash function selector. 259 * 260 * @return EINVAL when key or message not specified, ENOMEM when pointer for 261 * output hash result is not allocated, otherwise EOK. 263 * 264 * @return EINVAL when key or message not specified, 265 * ENOMEM when pointer for output hash result 266 * is not allocated, otherwise EOK. 267 * 262 268 */ 263 269 int hmac(uint8_t *key, size_t key_size, uint8_t *msg, size_t msg_size, 264 265 { 266 if (!key || !msg)270 uint8_t *hash, hash_func_t hash_sel) 271 { 272 if ((!key) || (!msg)) 267 273 return EINVAL; 268 274 269 if (!hash)275 if (!hash) 270 276 return ENOMEM; 271 277 … … 276 282 memset(work_key, 0, HMAC_BLOCK_LENGTH); 277 283 278 if(key_size > HMAC_BLOCK_LENGTH) {284 if(key_size > HMAC_BLOCK_LENGTH) 279 285 create_hash(key, key_size, work_key, hash_sel); 280 } else {286 else 281 287 memcpy(work_key, key, key_size); 282 } 283 284 for(size_t i = 0; i < HMAC_BLOCK_LENGTH; i++) { 285 o_key_pad[i] = work_key[i] ^ 0x5C; 288 289 for (size_t i = 0; i < HMAC_BLOCK_LENGTH; i++) { 290 o_key_pad[i] = work_key[i] ^ 0x5c; 286 291 i_key_pad[i] = work_key[i] ^ 0x36; 287 292 } … … 291 296 memcpy(temp_work + HMAC_BLOCK_LENGTH, msg, msg_size); 292 297 293 create_hash(temp_work, HMAC_BLOCK_LENGTH + msg_size, temp_hash, 294 298 create_hash(temp_work, HMAC_BLOCK_LENGTH + msg_size, temp_hash, 299 hash_sel); 295 300 296 301 memcpy(temp_work, o_key_pad, HMAC_BLOCK_LENGTH); … … 302 307 } 303 308 304 /** 305 * Password-Based Key Derivation Function 2 as defined in RFC 2898,306 * using HMAC-SHA1 with 4096 iterations and 32 bytes key result used307 * for WPA/WPA2.308 * 309 * @param pass Password sequence.309 /** Password-Based Key Derivation Function 2. 310 * 311 * As defined in RFC 2898, using HMAC-SHA1 with 4096 iterations 312 * and 32 bytes key result used for WPA/WPA2. 313 * 314 * @param pass Password sequence. 310 315 * @param pass_size Password sequence length. 311 * @param salt Salt sequence to be used with password.316 * @param salt Salt sequence to be used with password. 312 317 * @param salt_size Salt sequence length. 313 * @param hash Output parameter for result hash (32 byte value). 314 * 315 * @return EINVAL when pass or salt not specified, ENOMEM when pointer for 316 * output hash result is not allocated, otherwise EOK. 317 */ 318 int pbkdf2(uint8_t *pass, size_t pass_size, uint8_t *salt, size_t salt_size, 319 uint8_t *hash) 320 { 321 if(!pass || !salt) 318 * @param hash Output parameter for result hash (32 byte value). 319 * 320 * @return EINVAL when pass or salt not specified, 321 * ENOMEM when pointer for output hash result 322 * is not allocated, otherwise EOK. 323 * 324 */ 325 int pbkdf2(uint8_t *pass, size_t pass_size, uint8_t *salt, size_t salt_size, 326 uint8_t *hash) 327 { 328 if ((!pass) || (!salt)) 322 329 return EINVAL; 323 330 324 if (!hash)331 if (!hash) 325 332 return ENOMEM; 326 333 … … 330 337 uint8_t temp_hmac[HASH_SHA1]; 331 338 uint8_t xor_hmac[HASH_SHA1]; 332 uint8_t temp_hash[HASH_SHA1*2]; 333 334 for(size_t i = 0; i < 2; i++) { 335 uint32_t be_i = host2uint32_t_be(i+1); 339 uint8_t temp_hash[HASH_SHA1 * 2]; 340 341 for (size_t i = 0; i < 2; i++) { 342 uint32_t be_i = host2uint32_t_be(i + 1); 343 336 344 memcpy(work_salt + salt_size, &be_i, 4); 337 345 hmac(pass, pass_size, work_salt, salt_size + 4, 338 346 work_hmac, HASH_SHA1); 339 347 memcpy(xor_hmac, work_hmac, HASH_SHA1); 340 348 341 for (size_t k = 1; k < 4096; k++) {349 for (size_t k = 1; k < 4096; k++) { 342 350 memcpy(temp_hmac, work_hmac, HASH_SHA1); 343 hmac(pass, pass_size, temp_hmac, HASH_SHA1, 344 work_hmac, HASH_SHA1); 345 for(size_t t = 0; t < HASH_SHA1; t++) { 351 hmac(pass, pass_size, temp_hmac, HASH_SHA1, 352 work_hmac, HASH_SHA1); 353 354 for (size_t t = 0; t < HASH_SHA1; t++) 346 355 xor_hmac[t] ^= work_hmac[t]; 347 }348 356 } 349 memcpy(temp_hash + i*HASH_SHA1, xor_hmac, HASH_SHA1); 357 358 memcpy(temp_hash + i * HASH_SHA1, xor_hmac, HASH_SHA1); 350 359 } 351 360
Note:
See TracChangeset
for help on using the changeset viewer.