/*************************************************************************** * __________ __ ___. * 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 memcpy(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; }