Created
February 10, 2021 21:36
-
-
Save cynecx/19fbb175a2f0c2981d758bdce15ef1b8 to your computer and use it in GitHub Desktop.
SHA256 implementation based on botan's impl for LLVM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "llvm/Support/SHA256.h" | |
#include "llvm/ADT/ArrayRef.h" | |
#include "llvm/ADT/StringRef.h" | |
#include "llvm/Support/Endian.h" | |
#include "llvm/Support/Host.h" | |
#include <string.h> | |
namespace llvm { | |
#define ROTR(x,n) (((x) >> n) | ((x) << (32 - (n)))) | |
#define SHA2_32_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) do { \ | |
uint32_t A_rho = ROTR(A, 2) ^ ROTR(A, 13) ^ ROTR(A, 22); \ | |
uint32_t E_rho = ROTR(E, 6) ^ ROTR(E, 11) ^ ROTR(E, 25); \ | |
uint32_t M2_sigma = ROTR(M2, 17) ^ ROTR(M2, 19) ^ (M2 >> 10); \ | |
uint32_t M4_sigma = ROTR(M4, 7) ^ ROTR(M4, 18) ^ (M4 >> 3); \ | |
H += magic + E_rho + ((E & F) ^ (~E & G)) + M1; \ | |
D += H; \ | |
H += A_rho + ((A & B) | ((A | B) & C)); \ | |
M1 += M2_sigma + M3 + M4_sigma; \ | |
} while(0); | |
void SHA256::init() { | |
InternalState.State[0] = 0x6A09E667; | |
InternalState.State[1] = 0xBB67AE85; | |
InternalState.State[2] = 0x3C6EF372; | |
InternalState.State[3] = 0xA54FF53A; | |
InternalState.State[4] = 0x510E527F; | |
InternalState.State[5] = 0x9B05688C; | |
InternalState.State[6] = 0x1F83D9AB; | |
InternalState.State[7] = 0x5BE0CD19; | |
InternalState.ByteCount = 0; | |
InternalState.BufferOffset = 0; | |
} | |
void SHA256::hashBlock() { | |
uint32_t A = InternalState.State[0]; | |
uint32_t B = InternalState.State[1]; | |
uint32_t C = InternalState.State[2]; | |
uint32_t D = InternalState.State[3]; | |
uint32_t E = InternalState.State[4]; | |
uint32_t F = InternalState.State[5]; | |
uint32_t G = InternalState.State[6]; | |
uint32_t H = InternalState.State[7]; | |
uint32_t W00 = InternalState.Buffer.L[0]; | |
uint32_t W01 = InternalState.Buffer.L[1]; | |
uint32_t W02 = InternalState.Buffer.L[2]; | |
uint32_t W03 = InternalState.Buffer.L[3]; | |
uint32_t W04 = InternalState.Buffer.L[4]; | |
uint32_t W05 = InternalState.Buffer.L[5]; | |
uint32_t W06 = InternalState.Buffer.L[6]; | |
uint32_t W07 = InternalState.Buffer.L[7]; | |
uint32_t W08 = InternalState.Buffer.L[8]; | |
uint32_t W09 = InternalState.Buffer.L[9]; | |
uint32_t W10 = InternalState.Buffer.L[10]; | |
uint32_t W11 = InternalState.Buffer.L[11]; | |
uint32_t W12 = InternalState.Buffer.L[12]; | |
uint32_t W13 = InternalState.Buffer.L[13]; | |
uint32_t W14 = InternalState.Buffer.L[14]; | |
uint32_t W15 = InternalState.Buffer.L[15]; | |
SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x428A2F98); | |
SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x71374491); | |
SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0xB5C0FBCF); | |
SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0xE9B5DBA5); | |
SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x3956C25B); | |
SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x59F111F1); | |
SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x923F82A4); | |
SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0xAB1C5ED5); | |
SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xD807AA98); | |
SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x12835B01); | |
SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x243185BE); | |
SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x550C7DC3); | |
SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x72BE5D74); | |
SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0x80DEB1FE); | |
SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x9BDC06A7); | |
SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC19BF174); | |
SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0xE49B69C1); | |
SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0xEFBE4786); | |
SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x0FC19DC6); | |
SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x240CA1CC); | |
SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x2DE92C6F); | |
SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4A7484AA); | |
SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5CB0A9DC); | |
SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x76F988DA); | |
SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x983E5152); | |
SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA831C66D); | |
SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xB00327C8); | |
SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xBF597FC7); | |
SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xC6E00BF3); | |
SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD5A79147); | |
SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0x06CA6351); | |
SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x14292967); | |
SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x27B70A85); | |
SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x2E1B2138); | |
SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x4D2C6DFC); | |
SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x53380D13); | |
SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x650A7354); | |
SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x766A0ABB); | |
SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x81C2C92E); | |
SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x92722C85); | |
SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0xA2BFE8A1); | |
SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0xA81A664B); | |
SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0xC24B8B70); | |
SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0xC76C51A3); | |
SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0xD192E819); | |
SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xD6990624); | |
SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xF40E3585); | |
SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0x106AA070); | |
SHA2_32_F(A, B, C, D, E, F, G, H, W00, W14, W09, W01, 0x19A4C116); | |
SHA2_32_F(H, A, B, C, D, E, F, G, W01, W15, W10, W02, 0x1E376C08); | |
SHA2_32_F(G, H, A, B, C, D, E, F, W02, W00, W11, W03, 0x2748774C); | |
SHA2_32_F(F, G, H, A, B, C, D, E, W03, W01, W12, W04, 0x34B0BCB5); | |
SHA2_32_F(E, F, G, H, A, B, C, D, W04, W02, W13, W05, 0x391C0CB3); | |
SHA2_32_F(D, E, F, G, H, A, B, C, W05, W03, W14, W06, 0x4ED8AA4A); | |
SHA2_32_F(C, D, E, F, G, H, A, B, W06, W04, W15, W07, 0x5B9CCA4F); | |
SHA2_32_F(B, C, D, E, F, G, H, A, W07, W05, W00, W08, 0x682E6FF3); | |
SHA2_32_F(A, B, C, D, E, F, G, H, W08, W06, W01, W09, 0x748F82EE); | |
SHA2_32_F(H, A, B, C, D, E, F, G, W09, W07, W02, W10, 0x78A5636F); | |
SHA2_32_F(G, H, A, B, C, D, E, F, W10, W08, W03, W11, 0x84C87814); | |
SHA2_32_F(F, G, H, A, B, C, D, E, W11, W09, W04, W12, 0x8CC70208); | |
SHA2_32_F(E, F, G, H, A, B, C, D, W12, W10, W05, W13, 0x90BEFFFA); | |
SHA2_32_F(D, E, F, G, H, A, B, C, W13, W11, W06, W14, 0xA4506CEB); | |
SHA2_32_F(C, D, E, F, G, H, A, B, W14, W12, W07, W15, 0xBEF9A3F7); | |
SHA2_32_F(B, C, D, E, F, G, H, A, W15, W13, W08, W00, 0xC67178F2); | |
InternalState.State[0] += A; | |
InternalState.State[1] += B; | |
InternalState.State[2] += C; | |
InternalState.State[3] += D; | |
InternalState.State[4] += E; | |
InternalState.State[5] += F; | |
InternalState.State[6] += G; | |
InternalState.State[7] += H; | |
} | |
void SHA256::addUncounted(uint8_t Data) { | |
#ifdef SHA_BIG_ENDIAN | |
InternalState.Buffer.C[InternalState.BufferOffset] = Data; | |
#else | |
InternalState.Buffer.C[InternalState.BufferOffset ^ 3] = Data; | |
#endif | |
InternalState.BufferOffset++; | |
if (InternalState.BufferOffset == BLOCK_LENGTH) { | |
hashBlock(); | |
InternalState.BufferOffset = 0; | |
} | |
} | |
void SHA256::writebyte(uint8_t Data) { | |
++InternalState.ByteCount; | |
addUncounted(Data); | |
} | |
void SHA256::update(ArrayRef<uint8_t> Data) { | |
InternalState.ByteCount += Data.size(); | |
// Finish the current block. | |
if (InternalState.BufferOffset > 0) { | |
const size_t Remainder = std::min<size_t>( | |
Data.size(), BLOCK_LENGTH - InternalState.BufferOffset); | |
for (size_t I = 0; I < Remainder; ++I) | |
addUncounted(Data[I]); | |
Data = Data.drop_front(Remainder); | |
} | |
// Fast buffer filling for large inputs. | |
while (Data.size() >= BLOCK_LENGTH) { | |
assert(InternalState.BufferOffset == 0); | |
assert(BLOCK_LENGTH % 4 == 0); | |
constexpr size_t BLOCK_LENGTH_32 = BLOCK_LENGTH / 4; | |
for (size_t I = 0; I < BLOCK_LENGTH_32; ++I) | |
InternalState.Buffer.L[I] = support::endian::read32be(&Data[I * 4]); | |
hashBlock(); | |
Data = Data.drop_front(BLOCK_LENGTH); | |
} | |
// Finish the remainder. | |
for (uint8_t C : Data) | |
addUncounted(C); | |
} | |
void SHA256::update(StringRef Str) { | |
update( | |
ArrayRef<uint8_t>((uint8_t *)const_cast<char *>(Str.data()), Str.size())); | |
} | |
void SHA256::pad() { | |
// Implement SHA-2 padding (fips180-2 5.1.1) | |
// Pad with 0x80 followed by 0x00 until the end of the block | |
addUncounted(0x80); | |
while (InternalState.BufferOffset != 56) | |
addUncounted(0x00); | |
uint64_t len = InternalState.ByteCount << 3; // bit size | |
// Append length in the last 8 bytes big edian encoded | |
addUncounted(len >> 56); | |
addUncounted(len >> 48); | |
addUncounted(len >> 40); | |
addUncounted(len >> 32); | |
addUncounted(len >> 24); | |
addUncounted(len >> 16); | |
addUncounted(len >> 8); | |
addUncounted(len); | |
} | |
StringRef SHA256::final() { | |
// Pad to complete the last block | |
pad(); | |
#ifdef SHA_BIG_ENDIAN | |
// Just copy the current state | |
for (int i = 0; i < 8; i++) { | |
HashResult[i] = InternalState.State[i]; | |
} | |
#else | |
// Swap byte order back | |
for (int i = 0; i < 8; i++) { | |
HashResult[i] = (((InternalState.State[i]) << 24) & 0xff000000) | | |
(((InternalState.State[i]) << 8) & 0x00ff0000) | | |
(((InternalState.State[i]) >> 8) & 0x0000ff00) | | |
(((InternalState.State[i]) >> 24) & 0x000000ff); | |
} | |
#endif | |
// Return pointer to hash (32 characters) | |
return StringRef((char *)HashResult, HASH_LENGTH); | |
} | |
StringRef SHA256::result() { | |
auto StateToRestore = InternalState; | |
auto Hash = final(); | |
// Restore the state | |
InternalState = StateToRestore; | |
// Return pointer to hash (32 characters) | |
return Hash; | |
} | |
std::array<uint8_t, 32> SHA256::hash(ArrayRef<uint8_t> Data) { | |
SHA256 Hash; | |
Hash.update(Data); | |
StringRef S = Hash.final(); | |
std::array<uint8_t, 32> Arr; | |
memcpy(Arr.data(), S.data(), S.size()); | |
return Arr; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* The SHA-256 Secure Hash Standard was published by NIST in 2002. | |
* | |
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf | |
*/ | |
/* | |
The implementation is based on botans's SHA256 implementation [0]. | |
[0] https://github.com/randombit/botan/blob/master/src/lib/hash/sha2_32/sha2_32.cpp | |
*/ | |
#ifndef LLVM_SUPPORT_SHA2_H | |
#define LLVM_SUPPORT_SHA2_H | |
#include <array> | |
#include <cstdint> | |
namespace llvm { | |
template <typename T> class ArrayRef; | |
class StringRef; | |
class SHA256 { | |
public: | |
explicit SHA256() { init(); } | |
/// Reinitialize the internal state | |
void init(); | |
/// Digest more data. | |
void update(ArrayRef<uint8_t> Data); | |
/// Digest more data. | |
void update(StringRef Str); | |
/// Return a reference to the current raw 256-bits SHA256 for the digested data | |
/// since the last call to init(). This call will add data to the internal | |
/// state and as such is not suited for getting an intermediate result | |
/// (see result()). | |
StringRef final(); | |
/// Return a reference to the current raw 256-bits SHA256 for the digested data | |
/// since the last call to init(). This is suitable for getting the SHA256 at | |
/// any time without invalidating the internal state so that more calls can be | |
/// made into update. | |
StringRef result(); | |
/// Returns a raw 256-bit SHA256 hash for the given data. | |
static std::array<uint8_t, 32> hash(ArrayRef<uint8_t> Data); | |
private: | |
/// Define some constants. | |
/// "static constexpr" would be cleaner but MSVC does not support it yet. | |
enum { BLOCK_LENGTH = 64 }; | |
enum { HASH_LENGTH = 32 }; | |
// Internal State | |
struct { | |
union { | |
uint8_t C[BLOCK_LENGTH]; | |
uint32_t L[BLOCK_LENGTH / 4]; | |
} Buffer; | |
uint32_t State[HASH_LENGTH / 4]; | |
uint32_t ByteCount; | |
uint8_t BufferOffset; | |
} InternalState; | |
// Internal copy of the hash, populated and accessed on calls to result() | |
uint32_t HashResult[HASH_LENGTH / 4]; | |
// Helper | |
void writebyte(uint8_t data); | |
void hashBlock(); | |
void addUncounted(uint8_t data); | |
void pad(); | |
}; | |
} // end llvm namespace | |
#endif // LLVM_SUPPORT_SHA2_H | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment