| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Copyright (C) 2010 Amaury Pouly |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| /* Based on http://en.wikipedia.org/wiki/SHA-1 */ |
| #include "crypto.h" |
| |
| static uint32_t rot_left(uint32_t val, int rot) |
| { |
| return (val << rot) | (val >> (32 - rot)); |
| } |
| |
| static inline void byte_swapxx(byte *ptr, int size) |
| { |
| for(int i = 0; i < size / 2; i++) |
| { |
| byte c = ptr[i]; |
| ptr[i] = ptr[size - i - 1]; |
| ptr[size - i - 1] = c; |
| } |
| } |
| |
| static void byte_swap32(uint32_t *v) |
| { |
| byte_swapxx((byte *)v, 4); |
| } |
| |
| void sha_1_init(struct sha_1_params_t *params) |
| { |
| params->hash[0] = 0x67452301; |
| params->hash[1] = 0xEFCDAB89; |
| params->hash[2] = 0x98BADCFE; |
| params->hash[3] = 0x10325476; |
| params->hash[4] = 0xC3D2E1F0; |
| params->buffer_nr_bits = 0; |
| } |
| |
| void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size) |
| { |
| int buffer_nr_bytes = (params->buffer_nr_bits / 8) % 64; |
| params->buffer_nr_bits += 8 * size; |
| int pos = 0; |
| if(buffer_nr_bytes + size >= 64) |
| { |
| pos = 64 - buffer_nr_bytes; |
| memcpy((byte *)(params->w) + buffer_nr_bytes, buffer, 64 - buffer_nr_bytes); |
| sha_1_block(params, params->hash, (byte *)params->w); |
| for(; pos + 64 <= size; pos += 64) |
| sha_1_block(params, params->hash, buffer + pos); |
| buffer_nr_bytes = 0; |
| } |
| memcpy((byte *)(params->w) + buffer_nr_bytes, buffer + pos, size - pos); |
| } |
| |
| void sha_1_finish(struct sha_1_params_t *params) |
| { |
| /* length (in bits) in big endian BEFORE preprocessing */ |
| byte length_big_endian[8]; |
| memcpy(length_big_endian, ¶ms->buffer_nr_bits, 8); |
| byte_swapxx(length_big_endian, 8); |
| /* append '1' and then '0's to the message to get 448 bit length for the last block */ |
| byte b = 0x80; |
| sha_1_update(params, &b, 1); |
| b = 0; |
| while((params->buffer_nr_bits % 512) != 448) |
| sha_1_update(params, &b, 1); |
| /* append length */ |
| sha_1_update(params, length_big_endian, 8); |
| /* go back to big endian */ |
| for(int i = 0; i < 5; i++) |
| byte_swap32(¶ms->hash[i]); |
| } |
| |
| void sha_1_output(struct sha_1_params_t *params, byte *out) |
| { |
| memcpy(out, params->hash, 20); |
| } |
| |
| void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data) |
| { |
| uint32_t a, b, c, d, e; |
| a = cur_hash[0]; |
| b = cur_hash[1]; |
| c = cur_hash[2]; |
| d = cur_hash[3]; |
| e = cur_hash[4]; |
| |
| #define w params->w |
| |
| memmove(w, data, 64); |
| for(int i = 0; i < 16; i++) |
| byte_swap32(&w[i]); |
| |
| for(int i = 16; i <= 79; i++) |
| w[i] = rot_left(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); |
| |
| for(int i = 0; i<= 79; i++) |
| { |
| uint32_t f, k; |
| if(i <= 19) |
| { |
| f = (b & c) | ((~b) & d); |
| k = 0x5A827999; |
| } |
| else if(i <= 39) |
| { |
| f = b ^ c ^ d; |
| k = 0x6ED9EBA1; |
| } |
| else if(i <= 59) |
| { |
| f = (b & c) | (b & d) | (c & d); |
| k = 0x8F1BBCDC; |
| } |
| else |
| { |
| f = b ^ c ^ d; |
| k = 0xCA62C1D6; |
| } |
| uint32_t temp = rot_left(a, 5) + f + e + k + w[i]; |
| e = d; |
| d = c; |
| c = rot_left(b, 30); |
| b = a; |
| a = temp; |
| } |
| #undef w |
| |
| cur_hash[0] += a; |
| cur_hash[1] += b; |
| cur_hash[2] += c; |
| cur_hash[3] += d; |
| cur_hash[4] += e; |
| } |