1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <soulng/util/Sha1.hpp>
  7 #include <soulng/util/TextUtils.hpp>
  8 
  9 namespace soulng {namespace util {
 10 
 11 inline uint32_t LeftRotate(uint32_t  xuint32_t  n)
 12 {
 13     return (x << n) ^ (x >> (32 - n));
 14 }
 15 
 16 Sha1::Sha1()
 17 {
 18     Reset();
 19 }
 20 
 21 void Sha1::Reset()
 22 {
 23     digest[0] = 0x67452301u;
 24     digest[1] = 0xEFCDAB89u;
 25     digest[2] = 0x98BADCFEu;
 26     digest[3] = 0x10325476u;
 27     digest[4] = 0xC3D2E1F0u;
 28     byteIndex = 0u;
 29     bitCount = 0u;
 30 }
 31 
 32 void Sha1::Process(void* beginvoid* end)
 33 {
 34     uint8_t* b = static_cast<uint8_t*>(begin);
 35     uint8_t* e = static_cast<uint8_t*>(end);
 36     while (b != e)
 37     {
 38         Process(*b);
 39         ++b;
 40     }
 41 }
 42 
 43 std::string Sha1::GetDigest()
 44 {
 45     ProcessByte(0x80u);
 46     if (byteIndex > 56u)
 47     {
 48         while (byteIndex != 0u)
 49         {
 50             ProcessByte(0u);
 51         }
 52         while (byteIndex < 56u)
 53         {
 54             ProcessByte(0u);
 55         }
 56     }
 57     else
 58     {
 59         while (byteIndex < 56u)
 60         {
 61             ProcessByte(0u);
 62         }
 63     }
 64     ProcessByte(static_cast<uint8_t>((bitCount >> 56u) & 0xFFu));
 65     ProcessByte(static_cast<uint8_t>((bitCount >> 48u) & 0xFFu));
 66     ProcessByte(static_cast<uint8_t>((bitCount >> 40u) & 0xFFu));
 67     ProcessByte(static_cast<uint8_t>((bitCount >> 32u) & 0xFFu));
 68     ProcessByte(static_cast<uint8_t>((bitCount >> 24u) & 0xFFu));
 69     ProcessByte(static_cast<uint8_t>((bitCount >> 16u) & 0xFFu));
 70     ProcessByte(static_cast<uint8_t>((bitCount >> 8u) & 0xFFu));
 71     ProcessByte(static_cast<uint8_t>(bitCount & 0xFFu));
 72     std::string s = ToHexString(digest[0]);
 73     s.append(ToHexString(digest[1]));
 74     s.append(ToHexString(digest[2]));
 75     s.append(ToHexString(digest[3]));
 76     s.append(ToHexString(digest[4]));
 77     return s;
 78 }
 79 
 80 void Sha1::ProcessBlock()
 81 {
 82     uint32_t w[80];
 83     for (int i = 0; i < 16; ++i)
 84     {
 85         w[i] = static_cast<uint32_t>(block[4 * i]) << 24u;
 86         w[i] = w[i] | static_cast<uint32_t>(block[4 * i + 1]) << 16u;
 87         w[i] = w[i] | static_cast<uint32_t>(block[4 * i + 2]) << 8u;
 88         w[i] = w[i] | static_cast<uint32_t>(block[4 * i + 3]);
 89     }
 90     for (int i = 16; i < 80; ++i)
 91     {
 92         w[i] = LeftRotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]1u);
 93     }
 94     uint32_t a = digest[0];
 95     uint32_t b = digest[1];
 96     uint32_t c = digest[2];
 97     uint32_t d = digest[3];
 98     uint32_t e = digest[4];
 99     for (int i = 0; i < 80; ++i)
100     {
101         uint32_t f;
102         uint32_t k;
103         if (i < 20)
104         {
105             f = (b & c) | (~b & d);
106             k = 0x5A827999u;
107         }
108         else if (i < 40)
109         {
110             f = b ^ c ^ d;
111             k = 0x6ED9EBA1u;
112         }
113         else if (i < 60)
114         {
115             f = (b & c) | (b & d) | (c & d);
116             k = 0x8F1BBCDCu;
117         }
118         else
119         {
120             f = b ^ c ^ d;
121             k = 0xCA62C1D6u;
122         }
123         uint32_t temp = LeftRotate(a5u) + f + e + k + w[i];
124         e = d;
125         d = c;
126         c = LeftRotate(b30u);
127         b = a;
128         a = temp;
129     }
130     digest[0] = digest[0] + a;
131     digest[1] = digest[1] + b;
132     digest[2] = digest[2] + c;
133     digest[3] = digest[3] + d;
134     digest[4] = digest[4] + e;
135 }
136 
137 std::string GetSha1MessageDigest(const std::string& message)
138 {
139     Sha1 sha1;
140     sha1.Process((void*)message.c_str()int(message.length()));
141     return sha1.GetDigest();
142 }
143 
144 } } // namespace soulng::util