diff --git a/sha-256.c b/sha-256.c index db044aa..e54955c 100644 --- a/sha-256.c +++ b/sha-256.c @@ -6,6 +6,10 @@ #define CHUNK_SIZE 64 #define TOTAL_LEN_LEN 8 +/* + * ABOUT bool: this file does not use bool in order to be as pre-C99 compatible as possible. + */ + /* * Comments from pseudo-code at https://en.wikipedia.org/wiki/SHA-2 are reproduced here. * When useful for clarification, portions of the pseudo-code are reproduced here too. @@ -30,8 +34,8 @@ struct buffer_state { const uint8_t * p; size_t len; size_t total_len; - int single_one_delivered; - int total_len_delivered; + int single_one_delivered; // bool + int total_len_delivered; // bool }; static inline uint32_t right_rot(uint32_t value, unsigned int count) @@ -52,6 +56,7 @@ static void init_buf_state(struct buffer_state * state, const void * input, size state->total_len_delivered = 0; } +/* Return value: bool */ static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * state) { size_t space_in_chunk; @@ -65,7 +70,6 @@ static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * state) state->p += CHUNK_SIZE; state->len -= CHUNK_SIZE; return 1; - } memcpy(chunk, state->p, state->len); @@ -89,38 +93,18 @@ static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * state) */ if (space_in_chunk >= TOTAL_LEN_LEN) { const size_t left = space_in_chunk - TOTAL_LEN_LEN; - const size_t len = state->total_len * 8; + size_t len = state->total_len; + int i; memset(chunk, 0x00, left); chunk += left; -#if SIZE_MAX > UINT32_MAX - chunk[0] = (uint8_t) (len >> 56); - chunk[1] = (uint8_t) (len >> 48); - chunk[2] = (uint8_t) (len >> 40); - chunk[3] = (uint8_t) (len >> 32); -#else - chunk[0] = 0; - chunk[1] = 0; - chunk[2] = 0; - chunk[3] = 0; -#endif - -#if SIZE_MAX > UINT16_MAX - chunk[4] = (uint8_t) (len >> 24); - chunk[5] = (uint8_t) (len >> 16); -#else - chunk[4] = 0; - chunk[5] = 0; -#endif - -#if SIZE_MAX > UINT8_MAX - chunk[6] = (uint8_t) (len >> 8); -#else - chunk[6] = 0; -#endif - - chunk[7] = (uint8_t) len; - + /* Storing of len * 8 as a big endian 64-bit without overflow. */ + chunk[7] = (uint8_t) (len << 3); + len >>= 5; + for (i = 6; i >= 0; i--) { + chunk[i] = (uint8_t) len; + len >>= 8; + } state->total_len_delivered = 1; } else { memset(chunk, 0x00, space_in_chunk); @@ -131,18 +115,16 @@ static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * state) /* * Limitations: - * - len must be small enough for (8 * len) to fit in len. Otherwise, the results are unpredictable. - * - sizeof size_t is assumed to be either 8, 16, 32 or 64. Otherwise, the results are unpredictable. * - Since input is a pointer in RAM, the data to hash should be in RAM, which could be a problem * for large data sizes. * - SHA algorithms theoretically operate on bit strings. However, this implementation has no support * for bit string lengths that are not multiples of eight, and it really operates on arrays of bytes. - * the len parameter is a number of bytes. + * In particular, the len parameter is a number of bytes. */ void calc_sha_256(uint8_t hash[32], const void * input, size_t len) { /* - * Note 1: All variables are 32 bit unsigned integers and addition is calculated modulo 232 + * Note 1: All integers (expect indexes) are 32-bit unsigned integers and addition is calculated modulo 2^32. * Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 = i = 63 * Note 3: The compression function uses 8 working variables, a through h * Note 4: Big-endian convention is used when expressing the constants in this pseudocode, @@ -154,18 +136,10 @@ void calc_sha_256(uint8_t hash[32], const void * input, size_t len) * Initialize hash values: * (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19): */ - - uint32_t h0 = 0x6a09e667; - uint32_t h1 = 0xbb67ae85; - uint32_t h2 = 0x3c6ef372; - uint32_t h3 = 0xa54ff53a; - uint32_t h4 = 0x510e527f; - uint32_t h5 = 0x9b05688c; - uint32_t h6 = 0x1f83d9ab; - uint32_t h7 = 0x5be0cd19; + uint32_t h[] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }; + int i, j; /* 512-bit chunks is what we will operate on. */ - uint8_t chunk[64]; struct buffer_state state; @@ -173,7 +147,7 @@ void calc_sha_256(uint8_t hash[32], const void * input, size_t len) init_buf_state(&state, input, len); while (calc_chunk(chunk, &state)) { - uint32_t a, b, c, d, e, f, g, h; + uint32_t ah[8]; /* * create a 64-entry message schedule array w[0..63] of 32-bit words @@ -182,7 +156,6 @@ void calc_sha_256(uint8_t hash[32], const void * input, size_t len) */ uint32_t w[64]; const uint8_t *p = chunk; - int i; memset(w, 0x00, sizeof w); for (i = 0; i < 16; i++) { @@ -199,76 +172,39 @@ void calc_sha_256(uint8_t hash[32], const void * input, size_t len) } /* Initialize working variables to current hash value: */ - a = h0; - b = h1; - c = h2; - d = h3; - e = h4; - f = h5; - g = h6; - h = h7; + for (i = 0; i < 8; i++) + ah[i] = h[i]; /* Compression function main loop: */ for (i = 0; i < 64; i++) { - const uint32_t s1 = right_rot(e, 6) ^ right_rot(e, 11) ^ right_rot(e, 25); - const uint32_t ch = (e & f) ^ (~e & g); - const uint32_t temp1 = h + s1 + ch + k[i] + w[i]; - const uint32_t s0 = right_rot(a, 2) ^ right_rot(a, 13) ^ right_rot(a, 22); - const uint32_t maj = (a & b) ^ (a & c) ^ (b & c); + const uint32_t s1 = right_rot(ah[4], 6) ^ right_rot(ah[4], 11) ^ right_rot(ah[4], 25); + const uint32_t ch = (ah[4] & ah[5]) ^ (~ah[4] & ah[6]); + const uint32_t temp1 = ah[7] + s1 + ch + k[i] + w[i]; + const uint32_t s0 = right_rot(ah[0], 2) ^ right_rot(ah[0], 13) ^ right_rot(ah[0], 22); + const uint32_t maj = (ah[0] & ah[1]) ^ (ah[0] & ah[2]) ^ (ah[1] & ah[2]); const uint32_t temp2 = s0 + maj; - h = g; - g = f; - f = e; - e = d + temp1; - d = c; - c = b; - b = a; - a = temp1 + temp2; + ah[7] = ah[6]; + ah[6] = ah[5]; + ah[5] = ah[4]; + ah[4] = ah[3] + temp1; + ah[3] = ah[2]; + ah[2] = ah[1]; + ah[1] = ah[0]; + ah[0] = temp1 + temp2; } /* Add the compressed chunk to the current hash value: */ - h0 = h0 + a; - h1 = h1 + b; - h2 = h2 + c; - h3 = h3 + d; - h4 = h4 + e; - h5 = h5 + f; - h6 = h6 + g; - h7 = h7 + h; + for (i = 0; i < 8; i++) + h[i] += ah[i]; } /* Produce the final hash value (big-endian): */ - hash[0] = (uint8_t) (h0 >> 24); - hash[1] = (uint8_t) (h0 >> 16); - hash[2] = (uint8_t) (h0 >> 8); - hash[3] = (uint8_t) h0; - hash[4] = (uint8_t) (h1 >> 24); - hash[5] = (uint8_t) (h1 >> 16); - hash[6] = (uint8_t) (h1 >> 8); - hash[7] = (uint8_t) h1; - hash[8] = (uint8_t) (h2 >> 24); - hash[9] = (uint8_t) (h2 >> 16); - hash[10] = (uint8_t) (h2 >> 8); - hash[11] = (uint8_t) h2; - hash[12] = (uint8_t) (h3 >> 24); - hash[13] = (uint8_t) (h3 >> 16); - hash[14] = (uint8_t) (h3 >> 8); - hash[15] = (uint8_t) h3; - hash[16] = (uint8_t) (h4 >> 24); - hash[17] = (uint8_t) (h4 >> 16); - hash[18] = (uint8_t) (h4 >> 8); - hash[19] = (uint8_t) h4; - hash[20] = (uint8_t) (h5 >> 24); - hash[21] = (uint8_t) (h5 >> 16); - hash[22] = (uint8_t) (h5 >> 8); - hash[23] = (uint8_t) h5; - hash[24] = (uint8_t) (h6 >> 24); - hash[25] = (uint8_t) (h6 >> 16); - hash[26] = (uint8_t) (h6 >> 8); - hash[27] = (uint8_t) h6; - hash[28] = (uint8_t) (h7 >> 24); - hash[29] = (uint8_t) (h7 >> 16); - hash[30] = (uint8_t) (h7 >> 8); - hash[31] = (uint8_t) h7; + for (i = 0, j = 0; i < 8; i++) + { + hash[j++] = (uint8_t) (h[i] >> 24); + hash[j++] = (uint8_t) (h[i] >> 16); + hash[j++] = (uint8_t) (h[i] >> 8); + hash[j++] = (uint8_t) h[i]; + } }