diff options
author | Jan Kotas <jkotas@microsoft.com> | 2016-09-29 21:37:19 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2016-09-29 21:37:19 +0300 |
commit | 1e39416f91337cc96e4613133de6e9c72e63dd7b (patch) | |
tree | a955471f109b78ef8245b63e0fb53d05c86a055b /src/Native/Runtime/sha1.cpp | |
parent | e6223697456f895d59d93836b2182783a613d2d2 (diff) |
Branch sha1.cpp/.h from CoreCLR
[tfs-changeset: 1630118]
Diffstat (limited to 'src/Native/Runtime/sha1.cpp')
-rw-r--r-- | src/Native/Runtime/sha1.cpp | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/src/Native/Runtime/sha1.cpp b/src/Native/Runtime/sha1.cpp new file mode 100644 index 000000000..96517b559 --- /dev/null +++ b/src/Native/Runtime/sha1.cpp @@ -0,0 +1,412 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// +// +// =========================================================================== +// File: sha1.cpp +// +// =========================================================================== +/*++ + +Abstract: + + SHA-1 implementation + +Revision History: + +--*/ + +/* + File sha1.cpp <STRIP>Version 03 August 2000.</STRIP> + + + This implements the SHA-1 hash function. + For algorithmic background see (for example) + + + Alfred J. Menezes et al + Handbook of Applied Cryptography + The CRC Press Series on Discrete Mathematics + and its Applications + CRC Press LLC, 1997 + ISBN 0-8495-8523-7 + QA76.9A25M643 + + Also see FIPS 180-1 - Secure Hash Standard, + 1993 May 11 and 1995 April 17, by the U.S. + National Institute of Standards and Technology (NIST). + +*/ + +#include "common.h" +#include "sha1.h" +#include "contract.h" + +typedef const DWORD DWORDC; +#define ROTATE32L(x,n) _rotl(x,n) +#define SHAVE32(x) (DWORD)(x) + +static void SHA1_block(SHA1_CTX *ctx) +/* + Update the SHA-1 hash from a fresh 64 bytes of data. +*/ +{ + static DWORDC sha1_round1 = 0x5A827999u; + static DWORDC sha1_round2 = 0x6ED9EBA1u; + static DWORDC sha1_round3 = 0x8F1BBCDCu; + static DWORDC sha1_round4 = 0xCA62C1D6u; + + DWORD a = ctx->partial_hash[0], b = ctx->partial_hash[1]; + DWORD c = ctx->partial_hash[2], d = ctx->partial_hash[3]; + DWORD e = ctx->partial_hash[4]; + DWORD msg80[80]; + int i; + BOOL OK = TRUE; + + // OACR note: + // Loop conditions are using (i <= limit - increment) instead of (i < limit) to satisfy OACR. When the increment is greater + // than 1, OACR incorrectly thinks that the max value of 'i' is (limit - 1). + + for (i = 0; i < 16; i++) { // Copy to local array, zero original + // Extend length to 80 + DWORDC datval = ctx->awaiting_data[i]; + ctx->awaiting_data[i] = 0; + msg80[i] = datval; + } + + for (i = 16; i <= 80 - 2; i += 2) { + DWORDC temp1 = msg80[i-3] ^ msg80[i-8] + ^ msg80[i-14] ^ msg80[i-16]; + DWORDC temp2 = msg80[i-2] ^ msg80[i-7] + ^ msg80[i-13] ^ msg80[i-15]; + msg80[i ] = ROTATE32L(temp1, 1); + msg80[i+1] = ROTATE32L(temp2, 1); + } + +#define ROUND1(B, C, D) ((D ^ (B & (C ^ D))) + sha1_round1) + // Equivalent to (B & C) | (~B & D). + // (check cases B = 0 and B = 1) +#define ROUND2(B, C, D) ((B ^ C ^ D) + sha1_round2) + +#define ROUND3(B, C, D) ((C & (B | D) | (B & D)) + sha1_round3) + +#define ROUND4(B, C, D) ((B ^ C ^ D) + sha1_round4) + +// Round 1 + for (i = 0; i <= 20 - 5; i += 5) { + e += ROTATE32L(a, 5) + ROUND1(b, c, d) + msg80[i]; + b = ROTATE32L(b, 30); + + d += ROTATE32L(e, 5) + ROUND1(a, b, c) + msg80[i+1]; + a = ROTATE32L(a, 30); + + c += ROTATE32L(d, 5) + ROUND1(e, a, b) + msg80[i+2]; + e = ROTATE32L(e, 30); + + b += ROTATE32L(c, 5) + ROUND1(d, e, a) + msg80[i+3]; + d = ROTATE32L(d, 30); + + a += ROTATE32L(b, 5) + ROUND1(c, d, e) + msg80[i+4]; + c = ROTATE32L(c, 30); +#if 0 + printf("i = %ld %08lx %08lx %08lx %08lx %08lx\n", + i, a, b, c, d, e); +#endif + } // for i + +// Round 2 + for (i = 20; i <= 40 - 5; i += 5) { + e += ROTATE32L(a, 5) + ROUND2(b, c, d) + msg80[i]; + b = ROTATE32L(b, 30); + + d += ROTATE32L(e, 5) + ROUND2(a, b, c) + msg80[i+1]; + a = ROTATE32L(a, 30); + + c += ROTATE32L(d, 5) + ROUND2(e, a, b) + msg80[i+2]; + e = ROTATE32L(e, 30); + + b += ROTATE32L(c, 5) + ROUND2(d, e, a) + msg80[i+3]; + d = ROTATE32L(d, 30); + + a += ROTATE32L(b, 5) + ROUND2(c, d, e) + msg80[i+4]; + c = ROTATE32L(c, 30); + } // for i + +// Round 3 + for (i = 40; i <= 60 - 5; i += 5) { + e += ROTATE32L(a, 5) + ROUND3(b, c, d) + msg80[i]; + b = ROTATE32L(b, 30); + + d += ROTATE32L(e, 5) + ROUND3(a, b, c) + msg80[i+1]; + a = ROTATE32L(a, 30); + + c += ROTATE32L(d, 5) + ROUND3(e, a, b) + msg80[i+2]; + e = ROTATE32L(e, 30); + + b += ROTATE32L(c, 5) + ROUND3(d, e, a) + msg80[i+3]; + d = ROTATE32L(d, 30); + + a += ROTATE32L(b, 5) + ROUND3(c, d, e) + msg80[i+4]; + c = ROTATE32L(c, 30); + } // for i + +// Round 4 + for (i = 60; i <= 80 - 5; i += 5) { + e += ROTATE32L(a, 5) + ROUND4(b, c, d) + msg80[i]; + b = ROTATE32L(b, 30); + + d += ROTATE32L(e, 5) + ROUND4(a, b, c) + msg80[i+1]; + a = ROTATE32L(a, 30); + + c += ROTATE32L(d, 5) + ROUND4(e, a, b) + msg80[i+2]; + e = ROTATE32L(e, 30); + + b += ROTATE32L(c, 5) + ROUND4(d, e, a) + msg80[i+3]; + d = ROTATE32L(d, 30); + + a += ROTATE32L(b, 5) + ROUND4(c, d, e) + msg80[i+4]; + c = ROTATE32L(c, 30); + } // for i + +#undef ROUND1 +#undef ROUND2 +#undef ROUND3 +#undef ROUND4 + + ctx->partial_hash[0] += a; + ctx->partial_hash[1] += b; + ctx->partial_hash[2] += c; + ctx->partial_hash[3] += d; + ctx->partial_hash[4] += e; +#if 0 + for (i = 0; i < 16; i++) { + printf("%8lx ", msg16[i]); + if ((i & 7) == 7) printf("\n"); + } + printf("a, b, c, d, e = %08lx %08lx %08lx %08lx %08lx\n", + a, b, c, d, e); + printf("Partial hash = %08lx %08lx %08lx %08lx %08lx\n", + (long)ctx->partial_hash[0], (long)ctx->partial_hash[1], + (long)ctx->partial_hash[2], (long)ctx->partial_hash[3], + (long)ctx->partial_hash[4]); +#endif +} // end SHA1_block + + +void SHA1Hash::SHA1Init(SHA1_CTX *ctx) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + } CONTRACTL_END; + + ctx->nbit_total[0] = ctx->nbit_total[1] = 0; + + for (DWORD i = 0; i != 16; i++) { + ctx->awaiting_data[i] = 0; + } + + /* + Initialize hash variables. + + */ + + ctx->partial_hash[0] = 0x67452301u; + ctx->partial_hash[1] = 0xefcdab89u; + ctx->partial_hash[2] = ~ctx->partial_hash[0]; + ctx->partial_hash[3] = ~ctx->partial_hash[1]; + ctx->partial_hash[4] = 0xc3d2e1f0u; + +} + +void SHA1Hash::SHA1Update( + SHA1_CTX * ctx, // IN/OUT + const BYTE * msg, // IN + DWORD nbyte) // IN +/* + Append data to a partially hashed SHA-1 message. +*/ +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + } CONTRACTL_END; + + const BYTE *fresh_data = msg; + DWORD nbyte_left = nbyte; + DWORD nbit_occupied = ctx->nbit_total[0] & 511; + DWORD *awaiting_data; + DWORDC nbitnew_low = SHAVE32(8*nbyte); + + + _ASSERTE((nbit_occupied & 7) == 0); // Partial bytes not implemented + + ctx->nbit_total[0] += nbitnew_low; + ctx->nbit_total[1] += (nbyte >> 29) + + (SHAVE32(ctx->nbit_total[0]) < nbitnew_low); + + /* Advance to word boundary in waiting_data */ + + if ((nbit_occupied & 31) != 0) { + awaiting_data = ctx->awaiting_data + nbit_occupied/32; + + while ((nbit_occupied & 31) != 0 && nbyte_left != 0) { + nbit_occupied += 8; + *awaiting_data |= (DWORD)*fresh_data++ + << ((-(int)nbit_occupied) & 31); + nbyte_left--; // Start at most significant byte + } + } // if nbit_occupied + + /* Transfer 4 bytes at a time */ + + do { + DWORDC nword_occupied = nbit_occupied/32; + DWORD nwcopy = min(nbyte_left/4, 16 - nword_occupied); + _ASSERTE (nbit_occupied <= 512); + _ASSERTE ((nbit_occupied & 31) == 0 || nbyte_left == 0); + awaiting_data = ctx->awaiting_data + nword_occupied; + nbyte_left -= 4*nwcopy; + nbit_occupied += 32*nwcopy; + + while (nwcopy != 0) { + DWORDC byte0 = (DWORD)fresh_data[0]; + DWORDC byte1 = (DWORD)fresh_data[1]; + DWORDC byte2 = (DWORD)fresh_data[2]; + DWORDC byte3 = (DWORD)fresh_data[3]; + *awaiting_data++ = byte3 | (byte2 << 8) + | (byte1 << 16) | (byte0 << 24); + /* Big endian */ + fresh_data += 4; + nwcopy--; + } + + if (nbit_occupied == 512) { + SHA1_block(ctx); + nbit_occupied = 0; + awaiting_data -= 16; + _ASSERTE(awaiting_data == ctx->awaiting_data); + } + } while (nbyte_left >= 4); + + _ASSERTE (ctx->awaiting_data + nbit_occupied/32 + == awaiting_data); + + while (nbyte_left != 0) { + DWORDC new_byte = (DWORD)*fresh_data++; + + _ASSERTE((nbit_occupied & 31) <= 16); + nbit_occupied += 8; + *awaiting_data |= new_byte << ((-(int)nbit_occupied) & 31); + nbyte_left--; + } + + _ASSERTE (nbit_occupied == (ctx->nbit_total[0] & 511)); +} // end SHA1Update + + + +void SHA1Hash::SHA1Final( + SHA1_CTX * ctx, // IN/OUT + BYTE * digest) // OUT +/* + Finish a SHA-1 hash. +*/ +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + } CONTRACTL_END; + + DWORDC nbit0 = ctx->nbit_total[0]; + DWORDC nbit1 = ctx->nbit_total[1]; + DWORD nbit_occupied = nbit0 & 511; + DWORD i; + + _ASSERTE((nbit_occupied & 7) == 0); + + ctx->awaiting_data[nbit_occupied/32] + |= (DWORD)0x80 << ((-8-nbit_occupied) & 31); + // Append a 1 bit + nbit_occupied += 8; + + + // Append zero bits until length (in bits) is 448 mod 512. + // Then append the length, in bits. + // Here we assume the buffer was zeroed earlier. + + if (nbit_occupied > 448) { // If fewer than 64 bits left + SHA1_block(ctx); + nbit_occupied = 0; + } + ctx->awaiting_data[14] = nbit1; + ctx->awaiting_data[15] = nbit0; + SHA1_block(ctx); + + /* Copy final digest to user-supplied byte array */ + + for (i = 0; i != 5; i++) { + DWORDC dwi = ctx->partial_hash[i]; + digest[4*i + 0] = (BYTE)((dwi >> 24) & 255); + digest[4*i + 1] = (BYTE)((dwi >> 16) & 255); + digest[4*i + 2] = (BYTE)((dwi >> 8) & 255); + digest[4*i + 3] = (BYTE)(dwi & 255); // Big-endian + } +} // end SHA1Final + +SHA1Hash::SHA1Hash() +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + } CONTRACTL_END; + + m_fFinalized = FALSE; + SHA1Init(&m_Context); +} + +void SHA1Hash::AddData(BYTE *pbData, DWORD cbData) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + } CONTRACTL_END; + + if (m_fFinalized) + return; + + SHA1Update(&m_Context, pbData, cbData); +} + +// Retrieve a pointer to the final hash. +BYTE *SHA1Hash::GetHash() +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + } CONTRACTL_END; + + if (m_fFinalized) + return m_Value; + + SHA1Final(&m_Context, m_Value); + + m_fFinalized = TRUE; + + return m_Value; +} + |