HashingUtils.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/core/utils/logging/LogMacros.h>
  6. #include <aws/core/utils/HashingUtils.h>
  7. #include <aws/core/utils/StringUtils.h>
  8. #include <aws/core/utils/base64/Base64.h>
  9. #include <aws/core/utils/crypto/Sha256.h>
  10. #include <aws/core/utils/crypto/Sha256HMAC.h>
  11. #include <aws/core/utils/crypto/Sha1.h>
  12. #include <aws/core/utils/crypto/MD5.h>
  13. #include <aws/core/utils/crypto/CRC32.h>
  14. #include <aws/core/utils/Outcome.h>
  15. #include <aws/core/utils/memory/stl/AWSStringStream.h>
  16. #include <aws/core/utils/memory/stl/AWSList.h>
  17. #include <iomanip>
  18. using namespace Aws::Utils;
  19. using namespace Aws::Utils::Base64;
  20. using namespace Aws::Utils::Crypto;
  21. // internal buffers are fixed-size arrays, so this is harmless memory-management wise
  22. static Aws::Utils::Base64::Base64 s_base64;
  23. // Aws Glacier Tree Hash calculates hash value for each 1MB data
  24. const static size_t TREE_HASH_ONE_MB = 1024 * 1024;
  25. Aws::String HashingUtils::Base64Encode(const ByteBuffer& message)
  26. {
  27. return s_base64.Encode(message);
  28. }
  29. ByteBuffer HashingUtils::Base64Decode(const Aws::String& encodedMessage)
  30. {
  31. return s_base64.Decode(encodedMessage);
  32. }
  33. ByteBuffer HashingUtils::CalculateSHA256HMAC(const ByteBuffer& toSign, const ByteBuffer& secret)
  34. {
  35. Sha256HMAC hash;
  36. return hash.Calculate(toSign, secret).GetResult();
  37. }
  38. ByteBuffer HashingUtils::CalculateSHA256(const Aws::String& str)
  39. {
  40. Sha256 hash;
  41. return hash.Calculate(str).GetResult();
  42. }
  43. ByteBuffer HashingUtils::CalculateSHA256(Aws::IOStream& stream)
  44. {
  45. Sha256 hash;
  46. return hash.Calculate(stream).GetResult();
  47. }
  48. /**
  49. * This function is only used by HashingUtils::CalculateSHA256TreeHash() in this cpp file
  50. * It's a helper function be used to compute the TreeHash defined at:
  51. * http://docs.aws.amazon.com/amazonglacier/latest/dev/checksum-calculations.html
  52. */
  53. static ByteBuffer TreeHashFinalCompute(Aws::List<ByteBuffer>& input)
  54. {
  55. Sha256 hash;
  56. assert(input.size() != 0);
  57. // O(n) time complexity of merging (n + n/2 + n/4 + n/8 +...+ 1)
  58. while (input.size() > 1)
  59. {
  60. auto iter = input.begin();
  61. // if only one element left, just left it there
  62. while (std::next(iter) != input.end())
  63. {
  64. // if >= two elements
  65. Aws::String str(reinterpret_cast<char*>(iter->GetUnderlyingData()), iter->GetLength());
  66. // list erase returns iterator of next element next to the erased element or end() if erased the last one
  67. // list insert inserts element before pos, here we erase two elements, and insert a new element
  68. iter = input.erase(iter);
  69. str.append(reinterpret_cast<char*>(iter->GetUnderlyingData()), iter->GetLength());
  70. iter = input.erase(iter);
  71. input.insert(iter, hash.Calculate(str).GetResult());
  72. if (iter == input.end()) break;
  73. } // while process to the last element
  74. } // while the list has only one element left
  75. return *(input.begin());
  76. }
  77. ByteBuffer HashingUtils::CalculateSHA256TreeHash(const Aws::String& str)
  78. {
  79. Sha256 hash;
  80. if (str.size() == 0)
  81. {
  82. return hash.Calculate(str).GetResult();
  83. }
  84. Aws::List<ByteBuffer> input;
  85. size_t pos = 0;
  86. while (pos < str.size())
  87. {
  88. input.push_back(hash.Calculate(Aws::String(str, pos, TREE_HASH_ONE_MB)).GetResult());
  89. pos += TREE_HASH_ONE_MB;
  90. }
  91. return TreeHashFinalCompute(input);
  92. }
  93. ByteBuffer HashingUtils::CalculateSHA256TreeHash(Aws::IOStream& stream)
  94. {
  95. Sha256 hash;
  96. Aws::List<ByteBuffer> input;
  97. auto currentPos = stream.tellg();
  98. if (currentPos == std::ios::pos_type(-1))
  99. {
  100. currentPos = 0;
  101. stream.clear();
  102. }
  103. stream.seekg(0, stream.beg);
  104. Array<char> streamBuffer(TREE_HASH_ONE_MB);
  105. while (stream.good())
  106. {
  107. stream.read(streamBuffer.GetUnderlyingData(), TREE_HASH_ONE_MB);
  108. auto bytesRead = stream.gcount();
  109. if (bytesRead > 0)
  110. {
  111. input.push_back(hash.Calculate(Aws::String(reinterpret_cast<char*>(streamBuffer.GetUnderlyingData()), static_cast<size_t>(bytesRead))).GetResult());
  112. }
  113. }
  114. stream.clear();
  115. stream.seekg(currentPos, stream.beg);
  116. if (input.size() == 0)
  117. {
  118. return hash.Calculate("").GetResult();
  119. }
  120. return TreeHashFinalCompute(input);
  121. }
  122. Aws::String HashingUtils::HexEncode(const ByteBuffer& message)
  123. {
  124. Aws::String encoded;
  125. encoded.reserve(2 * message.GetLength());
  126. for (unsigned i = 0; i < message.GetLength(); ++i)
  127. {
  128. encoded.push_back("0123456789abcdef"[message[i] >> 4]);
  129. encoded.push_back("0123456789abcdef"[message[i] & 0x0f]);
  130. }
  131. return encoded;
  132. }
  133. ByteBuffer HashingUtils::HexDecode(const Aws::String& str)
  134. {
  135. //number of characters should be even
  136. assert(str.length() % 2 == 0);
  137. assert(str.length() >= 2);
  138. if(str.length() < 2 || str.length() % 2 != 0)
  139. {
  140. return ByteBuffer();
  141. }
  142. size_t strLength = str.length();
  143. size_t readIndex = 0;
  144. if(str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
  145. {
  146. strLength -= 2;
  147. readIndex = 2;
  148. }
  149. ByteBuffer hexBuffer(strLength / 2);
  150. size_t bufferIndex = 0;
  151. for (size_t i = readIndex; i < str.length(); i += 2)
  152. {
  153. if(!StringUtils::IsAlnum(str[i]) || !StringUtils::IsAlnum(str[i + 1]))
  154. {
  155. //contains non-hex characters
  156. assert(0);
  157. }
  158. char firstChar = str[i];
  159. uint8_t distance = firstChar - '0';
  160. if(isalpha(firstChar))
  161. {
  162. firstChar = static_cast<char>(toupper(firstChar));
  163. distance = firstChar - 'A' + 10;
  164. }
  165. unsigned char val = distance * 16;
  166. char secondChar = str[i + 1];
  167. distance = secondChar - '0';
  168. if(isalpha(secondChar))
  169. {
  170. secondChar = static_cast<char>(toupper(secondChar));
  171. distance = secondChar - 'A' + 10;
  172. }
  173. val += distance;
  174. hexBuffer[bufferIndex++] = val;
  175. }
  176. return hexBuffer;
  177. }
  178. ByteBuffer HashingUtils::CalculateSHA1(const Aws::String& str)
  179. {
  180. Sha1 hash;
  181. return hash.Calculate(str).GetResult();
  182. }
  183. ByteBuffer HashingUtils::CalculateSHA1(Aws::IOStream& stream)
  184. {
  185. Sha1 hash;
  186. return hash.Calculate(stream).GetResult();
  187. }
  188. ByteBuffer HashingUtils::CalculateMD5(const Aws::String& str)
  189. {
  190. MD5 hash;
  191. return hash.Calculate(str).GetResult();
  192. }
  193. ByteBuffer HashingUtils::CalculateMD5(Aws::IOStream& stream)
  194. {
  195. MD5 hash;
  196. return hash.Calculate(stream).GetResult();
  197. }
  198. ByteBuffer HashingUtils::CalculateCRC32(const Aws::String& str)
  199. {
  200. CRC32 hash;
  201. return hash.Calculate(str).GetResult();
  202. }
  203. ByteBuffer HashingUtils::CalculateCRC32(Aws::IOStream& stream)
  204. {
  205. CRC32 hash;
  206. return hash.Calculate(stream).GetResult();
  207. }
  208. ByteBuffer HashingUtils::CalculateCRC32C(const Aws::String& str)
  209. {
  210. CRC32C hash;
  211. return hash.Calculate(str).GetResult();
  212. }
  213. ByteBuffer HashingUtils::CalculateCRC32C(Aws::IOStream& stream)
  214. {
  215. CRC32C hash;
  216. return hash.Calculate(stream).GetResult();
  217. }
  218. int HashingUtils::HashString(const char* strToHash)
  219. {
  220. if (!strToHash)
  221. return 0;
  222. unsigned hash = 0;
  223. while (char charValue = *strToHash++)
  224. {
  225. hash = charValue + 31 * hash;
  226. }
  227. return hash;
  228. }