Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Sha256.h
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // Header section
- #include "Sha256.h"
- #include <sstream>
- #include <iomanip>
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // Declaration section
- using namespace Engine;
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // Definition section
- /// <summary>Hashing key</summary>
- constexpr std::array<uint32_t, 64> Sha256::mKey;
- /// <summary>
- /// Default constructor
- /// </summary>
- Sha256::Sha256() : mBlockLength(0), mBitLength(0)
- {
- memset(mData, 0, sizeof(mData));
- mState[0] = 0x6a09e667;
- mState[1] = 0xbb67ae85;
- mState[2] = 0x3c6ef372;
- mState[3] = 0xa54ff53a;
- mState[4] = 0x510e527f;
- mState[5] = 0x9b05688c;
- mState[6] = 0x1f83d9ab;
- mState[7] = 0x5be0cd19;
- }
- /// <summary>
- /// Add data to hash (and re-calculate hash)
- /// </summary>
- /// <param name="data">Inpute data</param>
- /// <param name="length">Length of data in bytes</param>
- void Sha256::Update(const uint8_t* data, size_t length)
- {
- for (size_t i = 0; i < length; i++)
- {
- mData[mBlockLength++] = data[i];
- if (mBlockLength == 64)
- {
- Transform();
- // End of block
- mBitLength += 512;
- mBlockLength = 0;
- }
- }
- }
- /// <summary>
- /// Add data to hash (and re-calculate hash) - C string variant
- /// </summary>
- /// <param name="data">Inpute data</param>
- /// <param name="length">Length of data in bytes</param>
- void Sha256::Update(const char* data, size_t length)
- {
- Update(reinterpret_cast<const uint8_t*>(data), length);
- }
- /// <summary>
- /// Add data to hash (and re-calculate hash) - C++ String variant
- /// </summary>
- /// <param name="data">Inpute data</param>
- void Sha256::Update(const std::string& data)
- {
- Update(reinterpret_cast<const uint8_t*>(data.c_str()), data.size());
- }
- /// <summary>
- /// Get SHA-256 hash
- /// </summary>
- /// <returns>SHA-256 hash</returns>
- std::array<uint8_t, 32> Sha256::Digest()
- {
- std::array<uint8_t, 32> hash;
- Pad();
- Revert(hash);
- return hash;
- }
- /// <summary>
- /// Get string representing SHA-256 hash (hexadecimal)
- /// </summary>
- /// <param name="digest">SHA-256 to get string of</param>
- /// <returns>String representation of SHA-256 hash (hexadecimal)</returns>
- std::string Sha256::ToString(const std::array<uint8_t, 32>& digest)
- {
- std::stringstream ss;
- ss << std::setfill('0') << std::hex;
- for (uint8_t i = 0; i < 32; i++)
- {
- ss << std::setw(2) << (unsigned int)digest[i];
- }
- return ss.str();
- }
- /// <summary>
- /// Rotate bits right
- /// </summary>
- /// <param name="value">Input value</param>
- /// <param name="count">No. of bits to rotate right</param>
- /// <returns>Value rotated right by count bits</returns>
- uint32_t Sha256::RotateRight(uint32_t value, uint32_t count)
- {
- return (value >> count) | (value << (32 - count));
- }
- /// <summary>
- /// Choose function - select input F or G based on mask
- /// </summary>
- /// <param name="e">Mask</param>
- /// <param name="f">Input F</param>
- /// <param name="g">Input G</param>
- /// <returns>Combination of Input F and G based on mask</returns>
- uint32_t Sha256::Choose(uint32_t e, uint32_t f, uint32_t g)
- {
- return (e & f) ^ (~e & g);
- }
- /// <summary>
- /// Bit majority function - median bit operator (n-th bit is 1 when majority of inputs is 1, otherwise 0)
- /// </summary>
- /// <param name="a">Input A</param>
- /// <param name="b">Input B</param>
- /// <param name="c">Input C</param>
- /// <returns>Bit majority of A, B and C</returns>
- uint32_t Sha256::Majority(uint32_t a, uint32_t b, uint32_t c)
- {
- return (a & (b | c)) | (b & c);
- }
- /// <summary>
- /// Sigma-0 function for SHA
- /// </summary>
- /// <param name="value">Input value</param>
- /// <returns>Sigma-0 of input value</returns>
- uint32_t Sha256::Sigma0(uint32_t value)
- {
- return RotateRight(value, 7) ^ RotateRight(value, 18) ^ (value >> 3);
- }
- /// <summary>
- /// Sigma-1 function for SHA
- /// </summary>
- /// <param name="value">Input value</param>
- /// <returns>Sigma-1 of input value</returns>
- uint32_t Sha256::Sigma1(uint32_t value)
- {
- return RotateRight(value, 17) ^ RotateRight(value, 19) ^ (value >> 10);
- }
- /// <summary>
- /// Transformation function
- /// </summary>
- void Sha256::Transform()
- {
- uint32_t m[64] = { 0 };
- // Split data with 32-bits into first 16 blocks
- for (uint8_t i = 0, j = 0; i < 16; i++, j += 4)
- {
- m[i] = (mData[j] << 24) | (mData[j + 1] << 16) | (mData[j + 2] << 8) | mData[j + 3];
- }
- // Remaining 48 blocks
- for (uint8_t i = 16; i < 64; i++)
- {
- m[i] = Sigma1(m[i - 2]) + m[i - 7] + Sigma0(m[i - 15]) + m[i - 16];
- }
- // Store state to local
- uint32_t state[8] = { 0 };
- for (uint8_t i = 0; i < 8; i++)
- {
- state[i] = mState[i];
- }
- for (uint8_t i = 0; i < 64; i++)
- {
- uint32_t majority = Majority(state[0], state[1], state[2]);
- uint32_t xora = RotateRight(state[0], 2) ^ RotateRight(state[0], 13) ^ RotateRight(state[0], 22);
- uint32_t ch = Choose(state[4], state[5], state[6]);
- uint32_t xore = RotateRight(state[4], 6) ^ RotateRight(state[4], 11) ^ RotateRight(state[4], 25);
- uint32_t sum = m[i] + mKey[i] + state[7] + ch + xore;
- uint32_t newa = xora + majority + sum;
- uint32_t newe = state[3] + sum;
- state[7] = state[6];
- state[6] = state[5];
- state[5] = state[4];
- state[4] = newe;
- state[3] = state[2];
- state[2] = state[1];
- state[1] = state[0];
- state[0] = newa;
- }
- for (uint8_t i = 0; i < 8; i++)
- {
- mState[i] += state[i];
- }
- }
- /// <summary>
- /// Padding function
- /// </summary>
- void Sha256::Pad()
- {
- uint64_t i = mBlockLength;
- uint8_t end = mBlockLength < 56 ? 56 : 64;
- // Append bit 1
- mData[i++] = 0x80;
- // Pad with 0
- while (i < end)
- {
- mData[i++] = 0x00;
- }
- if (mBlockLength >= 56)
- {
- Transform();
- memset(mData, 0, 56);
- }
- // Append padding to the total messages length in bits and transform
- mBitLength += mBlockLength * 8;
- mData[63] = (uint8_t)mBitLength;
- mData[62] = (uint8_t)(mBitLength >> 8);
- mData[61] = (uint8_t)(mBitLength >> 16);
- mData[60] = (uint8_t)(mBitLength >> 24);
- mData[59] = (uint8_t)(mBitLength >> 32);
- mData[58] = (uint8_t)(mBitLength >> 40);
- mData[57] = (uint8_t)(mBitLength >> 48);
- mData[56] = (uint8_t)(mBitLength >> 56);
- Transform();
- }
- /// <summary>
- /// Revert hash
- ///
- /// SHA generally uses big-endian ordering, revert all the bytes
- /// </summary>
- /// <param name="hash">Hash array to revert</param>
- void Sha256::Revert(std::array<uint8_t, 32>& hash)
- {
- // SHA generally uses big-endian ordering, revert all the bytes
- for (uint8_t i = 0; i < 4; i++)
- {
- for (uint8_t j = 0; j < 8; j++)
- {
- hash[i + (j * 4)] = (mState[j] >> (24 - i * 8)) & 0xFF;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment