Index: src/OFSHA1Hash.h ================================================================== --- src/OFSHA1Hash.h +++ src/OFSHA1Hash.h @@ -22,11 +22,14 @@ * @brief A class which provides functions to create an SHA1 hash. */ @interface OFSHA1Hash: OFObject { uint32_t _state[5]; - uint64_t _count; - char _buffer[64]; - uint8_t _digest[20]; - bool _calculated; + uint64_t _bits; + union { + uint8_t bytes[64]; + uint32_t words[80]; + } _buffer; + size_t _bufferLength; + bool _calculated; } @end Index: src/OFSHA1Hash.m ================================================================== --- src/OFSHA1Hash.m +++ src/OFSHA1Hash.m @@ -20,112 +20,72 @@ #import "OFSHA1Hash.h" #import "OFHashAlreadyCalculatedException.h" -/* blk0() and blk() perform the initial expand. */ -#ifndef OF_BIG_ENDIAN -#define blk0(i) \ - (block.l[i] = (OF_ROL(block.l[i], 24) & 0xFF00FF00) | \ - (OF_ROL(block.l[i], 8) & 0x00FF00FF)) -#else -#define blk0(i) block.l[i] -#endif -#define blk(i) \ - (block.l[i & 15] = OF_ROL(block.l[(i + 13) & 15] ^ \ - block.l[(i + 8) & 15] ^ block.l[(i + 2) & 15] ^ \ - block.l[i & 15], 1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v, w, x, y, z, i) \ - z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + OF_ROL(v, 5); \ - w = OF_ROL(w, 30); -#define R1(v, w, x, y, z, i) \ - z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + OF_ROL(v, 5); \ - w = OF_ROL(w, 30); -#define R2(v, w, x, y, z, i) \ - z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + OF_ROL(v, 5); \ - w = OF_ROL(w, 30); -#define R3(v, w, x, y, z, i) \ - z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + OF_ROL(v, 5); \ - w = OF_ROL(w, 30); -#define R4(v, w, x, y, z, i) \ - z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + OF_ROL(v, 5); \ - w = OF_ROL(w, 30); - -typedef union { - char c[64]; - uint32_t l[16]; -} sha1_c64l16_t; - -static inline void -sha1_transform(uint32_t state[5], const char buffer[64]) -{ - uint32_t a, b, c, d, e; - sha1_c64l16_t block; - - memcpy(block.c, buffer, 64); - - /* Copy state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - - /* Add the working vars back into state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; -} - -static inline void -sha1_update(uint32_t *state, uint64_t *count, char *buffer, - const char *buf, size_t length) -{ - size_t i, j; - - j = (size_t)((*count >> 3) & 63); - *count += (length << 3); - - if ((j + length) > 63) { - memcpy(&buffer[j], buf, (i = 64 - j)); - - sha1_transform(state, buffer); - - for (; i + 63 < length; i += 64) - sha1_transform(state, &buf[i]); - - j = 0; - } else - i = 0; - - memcpy(&buffer[j], &buf[i], length - i); +#define F(a, b, c, d) ((d) ^ ((b) & ((c) ^ (d)))) +#define G(a, b, c, d) ((b) ^ (c) ^ (d)) +#define H(a, b, c, d) (((b) & (c)) | ((d) & ((b) | (c)))) +#define I(a, b, c, d) ((b) ^ (c) ^ (d)) + +static void +byteSwapVectorIfLE(uint32_t *vector, uint_fast8_t length) +{ + uint_fast8_t i; + + for (i = 0; i < length; i++) + vector[i] = OF_BSWAP32_IF_LE(vector[i]); +} + +static void +processBlock(uint32_t *state, uint32_t *buffer) +{ + uint32_t new[5]; + uint_fast8_t i; + + new[0] = state[0]; + new[1] = state[1]; + new[2] = state[2]; + new[3] = state[3]; + new[4] = state[4]; + + byteSwapVectorIfLE(buffer, 16); + + for (i = 16; i < 80; i++) { + uint32_t tmp = buffer[i - 3] ^ buffer[i - 8] ^ + buffer[i - 14] ^ buffer[i - 16]; + buffer[i] = OF_ROL(tmp, 1); + } + +#define LOOP_BODY(f, k) \ + { \ + uint32_t tmp = OF_ROL(new[0], 5) + \ + f(new[0], new[1], new[2], new[3]) + \ + new[4] + k + buffer[i]; \ + new[4] = new[3]; \ + new[3] = new[2]; \ + new[2] = OF_ROL(new[1], 30); \ + new[1] = new[0]; \ + new[0] = tmp; \ + } + + for (i = 0; i < 20; i++) + LOOP_BODY(F, 0x5A827999) + for (; i < 40; i++) + LOOP_BODY(G, 0x6ED9EBA1) + for (; i < 60; i++) + LOOP_BODY(H, 0x8F1BBCDC) + for (; i < 80; i++) + LOOP_BODY(I, 0xCA62C1D6) + +#undef LOOP_BODY + + state[0] += new[0]; + state[1] += new[1]; + state[2] += new[2]; + state[3] += new[3]; + state[4] += new[4]; } @implementation OFSHA1Hash + (size_t)digestSize { @@ -153,50 +113,63 @@ _state[4] = 0xC3D2E1F0; return self; } -- (void)updateWithBuffer: (const void*)buffer +- (void)updateWithBuffer: (const void*)buffer_ length: (size_t)length { - if (length == 0) - return; + const uint8_t *buffer = buffer_; if (_calculated) @throw [OFHashAlreadyCalculatedException exceptionWithHash: self]; - sha1_update(_state, &_count, _buffer, buffer, length); + _bits += (length * 8); + + while (length > 0) { + size_t min = 64 - _bufferLength; + + if (min > length) + min = length; + + memcpy(_buffer.bytes + _bufferLength, buffer, min); + _bufferLength += min; + + buffer += min; + length -= min; + + if (_bufferLength == 64) { + processBlock(_state, _buffer.words); + _bufferLength = 0; + } + } } - (const uint8_t*)digest { - size_t i; - char finalcount[8]; - - if (_calculated) - return _digest; - - for (i = 0; i < 8; i++) - /* Endian independent */ - finalcount[i] = (char)((_count >> ((7 - (i & 7)) * 8)) & 255); - sha1_update(_state, &_count, _buffer, "\200", 1); - - while ((_count & 504) != 448) - sha1_update(_state, &_count, _buffer, "\0", 1); - /* Should cause a sha1_transform() */ - sha1_update(_state, &_count, _buffer, finalcount, 8); - - for (i = 0; i < 20; i++) - _digest[i] = (char)((_state[i >> 2] >> - ((3 - (i & 3)) * 8)) & 255); - + if (_calculated) + return (const uint8_t*)_state; + + _buffer.bytes[_bufferLength] = 0x80; + memset(_buffer.bytes + _bufferLength + 1, 0, 64 - _bufferLength - 1); + + if (_bufferLength >= 56) { + processBlock(_state, _buffer.words); + memset(_buffer.bytes, 0, 64); + } + + _buffer.words[14] = OF_BSWAP32_IF_LE((uint32_t)(_bits >> 32)); + _buffer.words[15] = OF_BSWAP32_IF_LE((uint32_t)(_bits & 0xFFFFFFFF)); + + processBlock(_state, _buffer.words); + byteSwapVectorIfLE(_state, 5); _calculated = true; - return _digest; + return (const uint8_t*)_state; } - (bool)isCalculated { return _calculated; } @end