cmCryptoHash.cxx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmCryptoHash.h"
  4. #include "cm_kwiml.h"
  5. #include "cm_rhash.h"
  6. #include "cmsys/FStream.hxx"
  7. #include <string.h>
  8. static unsigned int const cmCryptoHashAlgoToId[] = {
  9. /* clang-format needs this comment to break after the opening brace */
  10. RHASH_MD5, //
  11. RHASH_SHA1, //
  12. RHASH_SHA224, //
  13. RHASH_SHA256, //
  14. RHASH_SHA384, //
  15. RHASH_SHA512, //
  16. RHASH_SHA3_224, //
  17. RHASH_SHA3_256, //
  18. RHASH_SHA3_384, //
  19. RHASH_SHA3_512
  20. };
  21. static int cmCryptoHash_rhash_library_initialized;
  22. static rhash cmCryptoHash_rhash_init(unsigned int id)
  23. {
  24. if (!cmCryptoHash_rhash_library_initialized) {
  25. cmCryptoHash_rhash_library_initialized = 1;
  26. rhash_library_init();
  27. }
  28. return rhash_init(id);
  29. }
  30. cmCryptoHash::cmCryptoHash(Algo algo)
  31. : Id(cmCryptoHashAlgoToId[algo])
  32. , CTX(cmCryptoHash_rhash_init(Id))
  33. {
  34. }
  35. cmCryptoHash::~cmCryptoHash()
  36. {
  37. rhash_free(this->CTX);
  38. }
  39. CM_AUTO_PTR<cmCryptoHash> cmCryptoHash::New(const char* algo)
  40. {
  41. if (strcmp(algo, "MD5") == 0) {
  42. return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHash(AlgoMD5));
  43. }
  44. if (strcmp(algo, "SHA1") == 0) {
  45. return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHash(AlgoSHA1));
  46. }
  47. if (strcmp(algo, "SHA224") == 0) {
  48. return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHash(AlgoSHA224));
  49. }
  50. if (strcmp(algo, "SHA256") == 0) {
  51. return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHash(AlgoSHA256));
  52. }
  53. if (strcmp(algo, "SHA384") == 0) {
  54. return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHash(AlgoSHA384));
  55. }
  56. if (strcmp(algo, "SHA512") == 0) {
  57. return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHash(AlgoSHA512));
  58. }
  59. if (strcmp(algo, "SHA3_224") == 0) {
  60. return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHash(AlgoSHA3_224));
  61. }
  62. if (strcmp(algo, "SHA3_256") == 0) {
  63. return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHash(AlgoSHA3_256));
  64. }
  65. if (strcmp(algo, "SHA3_384") == 0) {
  66. return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHash(AlgoSHA3_384));
  67. }
  68. if (strcmp(algo, "SHA3_512") == 0) {
  69. return CM_AUTO_PTR<cmCryptoHash>(new cmCryptoHash(AlgoSHA3_512));
  70. }
  71. return CM_AUTO_PTR<cmCryptoHash>(nullptr);
  72. }
  73. bool cmCryptoHash::IntFromHexDigit(char input, char& output)
  74. {
  75. if (input >= '0' && input <= '9') {
  76. output = char(input - '0');
  77. return true;
  78. }
  79. if (input >= 'a' && input <= 'f') {
  80. output = char(input - 'a' + 0xA);
  81. return true;
  82. }
  83. if (input >= 'A' && input <= 'F') {
  84. output = char(input - 'A' + 0xA);
  85. return true;
  86. }
  87. return false;
  88. }
  89. std::string cmCryptoHash::ByteHashToString(
  90. const std::vector<unsigned char>& hash)
  91. {
  92. // Map from 4-bit index to hexadecimal representation.
  93. static char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
  94. '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
  95. std::string res;
  96. for (std::vector<unsigned char>::const_iterator vit = hash.begin();
  97. vit != hash.end(); ++vit) {
  98. res.push_back(hex[(*vit) >> 4]);
  99. res.push_back(hex[(*vit) & 0xF]);
  100. }
  101. return res;
  102. }
  103. std::vector<unsigned char> cmCryptoHash::ByteHashString(
  104. const std::string& input)
  105. {
  106. this->Initialize();
  107. this->Append(reinterpret_cast<unsigned char const*>(input.c_str()),
  108. static_cast<int>(input.size()));
  109. return this->Finalize();
  110. }
  111. std::vector<unsigned char> cmCryptoHash::ByteHashFile(const std::string& file)
  112. {
  113. cmsys::ifstream fin(file.c_str(), std::ios::in | std::ios::binary);
  114. if (fin) {
  115. this->Initialize();
  116. {
  117. // Should be efficient enough on most system:
  118. KWIML_INT_uint64_t buffer[512];
  119. char* buffer_c = reinterpret_cast<char*>(buffer);
  120. unsigned char const* buffer_uc =
  121. reinterpret_cast<unsigned char const*>(buffer);
  122. // This copy loop is very sensitive on certain platforms with
  123. // slightly broken stream libraries (like HPUX). Normally, it is
  124. // incorrect to not check the error condition on the fin.read()
  125. // before using the data, but the fin.gcount() will be zero if an
  126. // error occurred. Therefore, the loop should be safe everywhere.
  127. while (fin) {
  128. fin.read(buffer_c, sizeof(buffer));
  129. if (int gcount = static_cast<int>(fin.gcount())) {
  130. this->Append(buffer_uc, gcount);
  131. }
  132. }
  133. }
  134. if (fin.eof()) {
  135. // Success
  136. return this->Finalize();
  137. }
  138. // Finalize anyway
  139. this->Finalize();
  140. }
  141. // Return without success
  142. return std::vector<unsigned char>();
  143. }
  144. std::string cmCryptoHash::HashString(const std::string& input)
  145. {
  146. return ByteHashToString(this->ByteHashString(input));
  147. }
  148. std::string cmCryptoHash::HashFile(const std::string& file)
  149. {
  150. return ByteHashToString(this->ByteHashFile(file));
  151. }
  152. void cmCryptoHash::Initialize()
  153. {
  154. rhash_reset(this->CTX);
  155. }
  156. void cmCryptoHash::Append(void const* buf, size_t sz)
  157. {
  158. rhash_update(this->CTX, buf, sz);
  159. }
  160. void cmCryptoHash::Append(std::string const& str)
  161. {
  162. this->Append(str.c_str(), str.size());
  163. }
  164. std::vector<unsigned char> cmCryptoHash::Finalize()
  165. {
  166. std::vector<unsigned char> hash(rhash_get_digest_size(this->Id), 0);
  167. rhash_final(this->CTX, &hash[0]);
  168. return hash;
  169. }
  170. std::string cmCryptoHash::FinalizeHex()
  171. {
  172. return cmCryptoHash::ByteHashToString(this->Finalize());
  173. }