/* Sha1.c -- SHA-1 Hash 2016-05-20 : Igor Pavlov : Public domain This code is based on public domain code of Steve Reid from Wei Dai's Crypto++ library. */ #include "Precomp.h" #include #include "CpuArch.h" #include "RotateDefs.h" #include "Sha1.h" // define it for speed optimization // #define _SHA1_UNROLL #ifdef _SHA1_UNROLL #define kNumW 16 #define WW(i) W[(i)&15] #else #define kNumW 80 #define WW(i) W[i] #endif #define w0(i) (W[i] = data[i]) #define w1(i) (WW(i) = rotlFixed(WW((i)-3) ^ WW((i)-8) ^ WW((i)-14) ^ WW((i)-16), 1)) #define f1(x,y,z) (z^(x&(y^z))) #define f2(x,y,z) (x^y^z) #define f3(x,y,z) ((x&y)|(z&(x|y))) #define f4(x,y,z) (x^y^z) #define RK(a,b,c,d,e, fx, w, k) e += fx(b,c,d) + w + k + rotlFixed(a,5); b = rotlFixed(b,30); #define R0(a,b,c,d,e, i) RK(a,b,c,d,e, f1, w0(i), 0x5A827999) #define R1(a,b,c,d,e, i) RK(a,b,c,d,e, f1, w1(i), 0x5A827999) #define R2(a,b,c,d,e, i) RK(a,b,c,d,e, f2, w1(i), 0x6ED9EBA1) #define R3(a,b,c,d,e, i) RK(a,b,c,d,e, f3, w1(i), 0x8F1BBCDC) #define R4(a,b,c,d,e, i) RK(a,b,c,d,e, f4, w1(i), 0xCA62C1D6) #define RX_1_4(rx1, rx4, i) \ rx1(a,b,c,d,e, i); \ rx4(e,a,b,c,d, i+1); \ rx4(d,e,a,b,c, i+2); \ rx4(c,d,e,a,b, i+3); \ rx4(b,c,d,e,a, i+4); \ #define RX_5(rx, i) RX_1_4(rx, rx, i); #ifdef _SHA1_UNROLL #define RX_15 \ RX_5(R0, 0); \ RX_5(R0, 5); \ RX_5(R0, 10); #define RX_20(rx, i) \ RX_5(rx, i); \ RX_5(rx, i + 5); \ RX_5(rx, i + 10); \ RX_5(rx, i + 15); #else #define RX_15 { unsigned i; for (i = 0; i < 15; i += 5) { RX_5(R0, i); } } #define RX_20(rx, ii) { unsigned i; i = ii; for (; i < ii + 20; i += 5) { RX_5(rx, i); } } #endif void Sha1_Init(CSha1 *p) { p->state[0] = 0x67452301; p->state[1] = 0xEFCDAB89; p->state[2] = 0x98BADCFE; p->state[3] = 0x10325476; p->state[4] = 0xC3D2E1F0; p->count = 0; } void Sha1_GetBlockDigest(CSha1 *p, const UInt32 *data, UInt32 *destDigest) { UInt32 a, b, c, d, e; UInt32 W[kNumW]; a = p->state[0]; b = p->state[1]; c = p->state[2]; d = p->state[3]; e = p->state[4]; RX_15 RX_1_4(R0, R1, 15); RX_20(R2, 20); RX_20(R3, 40); RX_20(R4, 60); destDigest[0] = p->state[0] + a; destDigest[1] = p->state[1] + b; destDigest[2] = p->state[2] + c; destDigest[3] = p->state[3] + d; destDigest[4] = p->state[4] + e; } void Sha1_UpdateBlock_Rar(CSha1 *p, UInt32 *data, int returnRes) { UInt32 a, b, c, d, e; UInt32 W[kNumW]; a = p->state[0]; b = p->state[1]; c = p->state[2]; d = p->state[3]; e = p->state[4]; RX_15 RX_1_4(R0, R1, 15); RX_20(R2, 20); RX_20(R3, 40); RX_20(R4, 60); p->state[0] += a; p->state[1] += b; p->state[2] += c; p->state[3] += d; p->state[4] += e; if (returnRes) { unsigned i; for (i = 0 ; i < SHA1_NUM_BLOCK_WORDS; i++) data[i] = W[kNumW - SHA1_NUM_BLOCK_WORDS + i]; } } #define Sha1_UpdateBlock(p) Sha1_GetBlockDigest(p, p->buffer, p->state) void Sha1_Update(CSha1 *p, const Byte *data, size_t size) { unsigned pos, pos2; if (size == 0) return; pos = (unsigned)p->count & 0x3F; p->count += size; pos2 = pos & 3; pos >>= 2; if (pos2 != 0) { UInt32 w; pos2 = (3 - pos2) * 8; w = ((UInt32)*data++) << pos2; if (--size && pos2) { pos2 -= 8; w |= ((UInt32)*data++) << pos2; if (--size && pos2) { pos2 -= 8; w |= ((UInt32)*data++) << pos2; size--; } } p->buffer[pos] |= w; if (pos2 == 0) pos++; } for (;;) { if (pos == SHA1_NUM_BLOCK_WORDS) { for (;;) { unsigned i; Sha1_UpdateBlock(p); if (size < SHA1_BLOCK_SIZE) break; size -= SHA1_BLOCK_SIZE; for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i += 2) { p->buffer[i ] = GetBe32(data); p->buffer[i + 1] = GetBe32(data + 4); data += 8; } } pos = 0; } if (size < 4) break; p->buffer[pos] = GetBe32(data); data += 4; size -= 4; pos++; } if (size != 0) { UInt32 w = ((UInt32)data[0]) << 24; if (size > 1) { w |= ((UInt32)data[1]) << 16; if (size > 2) w |= ((UInt32)data[2]) << 8; } p->buffer[pos] = w; } } void Sha1_Update_Rar(CSha1 *p, Byte *data, size_t size /* , int rar350Mode */) { int returnRes = False; unsigned pos = (unsigned)p->count & 0x3F; p->count += size; while (size--) { unsigned pos2 = (pos & 3); UInt32 v = ((UInt32)*data++) << (8 * (3 - pos2)); UInt32 *ref = &(p->buffer[pos >> 2]); pos++; if (pos2 == 0) { *ref = v; continue; } *ref |= v; if (pos == SHA1_BLOCK_SIZE) { pos = 0; Sha1_UpdateBlock_Rar(p, p->buffer, returnRes); if (returnRes) { unsigned i; for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) { UInt32 d = p->buffer[i]; Byte *prev = data + i * 4 - SHA1_BLOCK_SIZE; SetUi32(prev, d); } } // returnRes = rar350Mode; returnRes = True; } } } void Sha1_Final(CSha1 *p, Byte *digest) { unsigned pos = (unsigned)p->count & 0x3F; unsigned pos2 = (pos & 3); UInt64 numBits; UInt32 w; unsigned i; pos >>= 2; w = 0; if (pos2 != 0) w = p->buffer[pos]; p->buffer[pos++] = w | (((UInt32)0x80000000) >> (8 * pos2)); while (pos != (SHA1_NUM_BLOCK_WORDS - 2)) { pos &= 0xF; if (pos == 0) Sha1_UpdateBlock(p); p->buffer[pos++] = 0; } numBits = (p->count << 3); p->buffer[SHA1_NUM_BLOCK_WORDS - 2] = (UInt32)(numBits >> 32); p->buffer[SHA1_NUM_BLOCK_WORDS - 1] = (UInt32)(numBits); Sha1_UpdateBlock(p); for (i = 0; i < SHA1_NUM_DIGEST_WORDS; i++) { UInt32 v = p->state[i]; SetBe32(digest, v); digest += 4; } Sha1_Init(p); } void Sha1_32_PrepareBlock(const CSha1 *p, UInt32 *block, unsigned size) { const UInt64 numBits = (p->count + size) << 5; block[SHA1_NUM_BLOCK_WORDS - 2] = (UInt32)(numBits >> 32); block[SHA1_NUM_BLOCK_WORDS - 1] = (UInt32)(numBits); block[size++] = 0x80000000; while (size != (SHA1_NUM_BLOCK_WORDS - 2)) block[size++] = 0; } void Sha1_32_Update(CSha1 *p, const UInt32 *data, size_t size) { unsigned pos = (unsigned)p->count & 0xF; p->count += size; while (size--) { p->buffer[pos++] = *data++; if (pos == SHA1_NUM_BLOCK_WORDS) { pos = 0; Sha1_UpdateBlock(p); } } } void Sha1_32_Final(CSha1 *p, UInt32 *digest) { UInt64 numBits; unsigned pos = (unsigned)p->count & 0xF; p->buffer[pos++] = 0x80000000; while (pos != (SHA1_NUM_BLOCK_WORDS - 2)) { pos &= 0xF; if (pos == 0) Sha1_UpdateBlock(p); p->buffer[pos++] = 0; } numBits = (p->count << 5); p->buffer[SHA1_NUM_BLOCK_WORDS - 2] = (UInt32)(numBits >> 32); p->buffer[SHA1_NUM_BLOCK_WORDS - 1] = (UInt32)(numBits); Sha1_GetBlockDigest(p, p->buffer, digest); Sha1_Init(p); }