123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmCryptoHash.h"
- #include "cmAlgorithms.h"
- #include "cm_kwiml.h"
- #include "cm_rhash.h"
- #include "cmsys/FStream.hxx"
- #include <string.h>
- #include <memory> // IWYU pragma: keep
- static unsigned int const cmCryptoHashAlgoToId[] = {
- /* clang-format needs this comment to break after the opening brace */
- RHASH_MD5, //
- RHASH_SHA1, //
- RHASH_SHA224, //
- RHASH_SHA256, //
- RHASH_SHA384, //
- RHASH_SHA512, //
- RHASH_SHA3_224, //
- RHASH_SHA3_256, //
- RHASH_SHA3_384, //
- RHASH_SHA3_512
- };
- static int cmCryptoHash_rhash_library_initialized;
- static rhash cmCryptoHash_rhash_init(unsigned int id)
- {
- if (!cmCryptoHash_rhash_library_initialized) {
- cmCryptoHash_rhash_library_initialized = 1;
- rhash_library_init();
- }
- return rhash_init(id);
- }
- cmCryptoHash::cmCryptoHash(Algo algo)
- : Id(cmCryptoHashAlgoToId[algo])
- , CTX(cmCryptoHash_rhash_init(Id))
- {
- }
- cmCryptoHash::~cmCryptoHash()
- {
- rhash_free(this->CTX);
- }
- std::unique_ptr<cmCryptoHash> cmCryptoHash::New(const char* algo)
- {
- if (strcmp(algo, "MD5") == 0) {
- return cm::make_unique<cmCryptoHash>(AlgoMD5);
- }
- if (strcmp(algo, "SHA1") == 0) {
- return cm::make_unique<cmCryptoHash>(AlgoSHA1);
- }
- if (strcmp(algo, "SHA224") == 0) {
- return cm::make_unique<cmCryptoHash>(AlgoSHA224);
- }
- if (strcmp(algo, "SHA256") == 0) {
- return cm::make_unique<cmCryptoHash>(AlgoSHA256);
- }
- if (strcmp(algo, "SHA384") == 0) {
- return cm::make_unique<cmCryptoHash>(AlgoSHA384);
- }
- if (strcmp(algo, "SHA512") == 0) {
- return cm::make_unique<cmCryptoHash>(AlgoSHA512);
- }
- if (strcmp(algo, "SHA3_224") == 0) {
- return cm::make_unique<cmCryptoHash>(AlgoSHA3_224);
- }
- if (strcmp(algo, "SHA3_256") == 0) {
- return cm::make_unique<cmCryptoHash>(AlgoSHA3_256);
- }
- if (strcmp(algo, "SHA3_384") == 0) {
- return cm::make_unique<cmCryptoHash>(AlgoSHA3_384);
- }
- if (strcmp(algo, "SHA3_512") == 0) {
- return cm::make_unique<cmCryptoHash>(AlgoSHA3_512);
- }
- return std::unique_ptr<cmCryptoHash>(nullptr);
- }
- bool cmCryptoHash::IntFromHexDigit(char input, char& output)
- {
- if (input >= '0' && input <= '9') {
- output = char(input - '0');
- return true;
- }
- if (input >= 'a' && input <= 'f') {
- output = char(input - 'a' + 0xA);
- return true;
- }
- if (input >= 'A' && input <= 'F') {
- output = char(input - 'A' + 0xA);
- return true;
- }
- return false;
- }
- std::string cmCryptoHash::ByteHashToString(
- const std::vector<unsigned char>& hash)
- {
- // Map from 4-bit index to hexadecimal representation.
- static char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- std::string res;
- for (unsigned char v : hash) {
- res.push_back(hex[v >> 4]);
- res.push_back(hex[v & 0xF]);
- }
- return res;
- }
- std::vector<unsigned char> cmCryptoHash::ByteHashString(
- const std::string& input)
- {
- this->Initialize();
- this->Append(reinterpret_cast<unsigned char const*>(input.c_str()),
- static_cast<int>(input.size()));
- return this->Finalize();
- }
- std::vector<unsigned char> cmCryptoHash::ByteHashFile(const std::string& file)
- {
- cmsys::ifstream fin(file.c_str(), std::ios::in | std::ios::binary);
- if (fin) {
- this->Initialize();
- {
- // Should be efficient enough on most system:
- KWIML_INT_uint64_t buffer[512];
- char* buffer_c = reinterpret_cast<char*>(buffer);
- unsigned char const* buffer_uc =
- reinterpret_cast<unsigned char const*>(buffer);
- // This copy loop is very sensitive on certain platforms with
- // slightly broken stream libraries (like HPUX). Normally, it is
- // incorrect to not check the error condition on the fin.read()
- // before using the data, but the fin.gcount() will be zero if an
- // error occurred. Therefore, the loop should be safe everywhere.
- while (fin) {
- fin.read(buffer_c, sizeof(buffer));
- if (int gcount = static_cast<int>(fin.gcount())) {
- this->Append(buffer_uc, gcount);
- }
- }
- }
- if (fin.eof()) {
- // Success
- return this->Finalize();
- }
- // Finalize anyway
- this->Finalize();
- }
- // Return without success
- return std::vector<unsigned char>();
- }
- std::string cmCryptoHash::HashString(const std::string& input)
- {
- return ByteHashToString(this->ByteHashString(input));
- }
- std::string cmCryptoHash::HashFile(const std::string& file)
- {
- return ByteHashToString(this->ByteHashFile(file));
- }
- void cmCryptoHash::Initialize()
- {
- rhash_reset(this->CTX);
- }
- void cmCryptoHash::Append(void const* buf, size_t sz)
- {
- rhash_update(this->CTX, buf, sz);
- }
- void cmCryptoHash::Append(std::string const& str)
- {
- this->Append(str.c_str(), str.size());
- }
- std::vector<unsigned char> cmCryptoHash::Finalize()
- {
- std::vector<unsigned char> hash(rhash_get_digest_size(this->Id), 0);
- rhash_final(this->CTX, &hash[0]);
- return hash;
- }
- std::string cmCryptoHash::FinalizeHex()
- {
- return cmCryptoHash::ByteHashToString(this->Finalize());
- }
|