diff options
author | Brad King <brad.king@kitware.com> | 2016-08-11 17:48:37 (GMT) |
---|---|---|
committer | CMake Topic Stage <kwrobot@kitware.com> | 2016-08-11 17:48:37 (GMT) |
commit | f203694bb848e7a4bd2c623348053532b1b4e589 (patch) | |
tree | 63ec07c00761aea08e42925cb561aaec3bef8945 | |
parent | 3c4d2e84d2659459eeecd2b9da0fceb22a2fb852 (diff) | |
parent | 3a5f609cbb4ae63fca1eb87918767a4296d16e5f (diff) | |
download | CMake-f203694bb848e7a4bd2c623348053532b1b4e589.zip CMake-f203694bb848e7a4bd2c623348053532b1b4e589.tar.gz CMake-f203694bb848e7a4bd2c623348053532b1b4e589.tar.bz2 |
Merge topic 'cmCryptoHash-raw-digest'
3a5f609c cmCryptoHash: New ByteHash methods that return a byte vector
f582dba6 cmCryptoHash: Return byte vector from internal Finalize method
74f0d4ab cmCryptoHash: New byte hash to string function
94c29976 cmCryptoHash: Documentation comments
-rw-r--r-- | Source/cmCryptoHash.cxx | 111 | ||||
-rw-r--r-- | Source/cmCryptoHash.h | 42 |
2 files changed, 117 insertions, 36 deletions
diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index 8d60c1f..9bd07a3 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -34,7 +34,39 @@ CM_AUTO_PTR<cmCryptoHash> cmCryptoHash::New(const char* algo) } } -std::string cmCryptoHash::HashString(const std::string& input) +bool cmCryptoHash::IntFromHexDigit(char input, char& output) +{ + if (input >= '0' && input <= '9') { + output = char(input - '0'); + return true; + } else if (input >= 'a' && input <= 'f') { + output = char(input - 'a' + 0xA); + return true; + } else 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 (std::vector<unsigned char>::const_iterator vit = hash.begin(); + vit != hash.end(); ++vit) { + res.push_back(hex[(*vit) >> 4]); + res.push_back(hex[(*vit) & 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()), @@ -42,35 +74,48 @@ std::string cmCryptoHash::HashString(const std::string& input) return this->Finalize(); } -std::string cmCryptoHash::HashFile(const std::string& file) +std::vector<unsigned char> cmCryptoHash::ByteHashFile(const std::string& file) { cmsys::ifstream fin(file.c_str(), std::ios::in | std::ios::binary); - if (!fin) { - return ""; + if (fin) { + this->Initialize(); + { + // Should be efficient enough on most system: + cm_sha2_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>(); +} - this->Initialize(); +std::string cmCryptoHash::HashString(const std::string& input) +{ + return ByteHashToString(this->ByteHashString(input)); +} - // Should be efficient enough on most system: - cm_sha2_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()) { - return this->Finalize(); - } - return ""; +std::string cmCryptoHash::HashFile(const std::string& file) +{ + return ByteHashToString(this->ByteHashFile(file)); } cmCryptoHashMD5::cmCryptoHashMD5() @@ -93,11 +138,11 @@ void cmCryptoHashMD5::Append(unsigned char const* buf, int sz) cmsysMD5_Append(this->MD5, buf, sz); } -std::string cmCryptoHashMD5::Finalize() +std::vector<unsigned char> cmCryptoHashMD5::Finalize() { - char md5out[32]; - cmsysMD5_FinalizeHex(this->MD5, md5out); - return std::string(md5out, 32); + std::vector<unsigned char> hash(16, 0); + cmsysMD5_Finalize(this->MD5, &hash[0]); + return hash; } #define cmCryptoHash_SHA_CLASS_IMPL(SHA) \ @@ -111,11 +156,11 @@ std::string cmCryptoHashMD5::Finalize() { \ SHA##_Update(this->SHA, buf, sz); \ } \ - std::string cmCryptoHash##SHA::Finalize() \ + std::vector<unsigned char> cmCryptoHash##SHA::Finalize() \ { \ - char out[SHA##_DIGEST_STRING_LENGTH]; \ - SHA##_End(this->SHA, out); \ - return std::string(out, SHA##_DIGEST_STRING_LENGTH - 1); \ + std::vector<unsigned char> hash(SHA##_DIGEST_LENGTH, 0); \ + SHA##_Final(&hash[0], this->SHA); \ + return hash; \ } cmCryptoHash_SHA_CLASS_IMPL(SHA1) cmCryptoHash_SHA_CLASS_IMPL(SHA224) diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h index 6aaaf93..4e92b06 100644 --- a/Source/cmCryptoHash.h +++ b/Source/cmCryptoHash.h @@ -16,18 +16,54 @@ #include <cm_auto_ptr.hxx> +/** + * @brief Abstract base class for cryptographic hash generators + */ class cmCryptoHash { public: virtual ~cmCryptoHash() {} + + /// @brief Returns a new hash generator of the requested type + /// @arg algo Hash type name. Supported hash types are + /// MD5, SHA1, SHA224, SHA256, SHA384, SHA512 + /// @return A valid auto pointer if algo is supported or + /// an invalid/NULL pointer otherwise static CM_AUTO_PTR<cmCryptoHash> New(const char* algo); + + /// @brief Converts a hex character to its binary value (4 bits) + /// @arg input Hex character [0-9a-fA-F]. + /// @arg output Binary value of the input character (4 bits) + /// @return True if input was a valid hex character + static bool IntFromHexDigit(char input, char& output); + + /// @brief Converts a byte hash to a sequence of hex character pairs + static std::string ByteHashToString(const std::vector<unsigned char>& hash); + + /// @brief Calculates a binary hash from string input data + /// @return Binary hash vector + std::vector<unsigned char> ByteHashString(const std::string& input); + + /// @brief Calculates a binary hash from file content + /// @see ByteHashString() + /// @return Non empty binary hash vector if the file was read successfully. + /// An empty vector otherwise. + std::vector<unsigned char> ByteHashFile(const std::string& file); + + /// @brief Calculates a hash string from string input data + /// @return Sequence of hex characters pairs for each byte of the binary hash std::string HashString(const std::string& input); + + /// @brief Calculates a hash string from file content + /// @see HashString() + /// @return Non empty hash string if the file was read successfully. + /// An empty string otherwise. std::string HashFile(const std::string& file); protected: virtual void Initialize() = 0; virtual void Append(unsigned char const*, int) = 0; - virtual std::string Finalize() = 0; + virtual std::vector<unsigned char> Finalize() = 0; }; class cmCryptoHashMD5 : public cmCryptoHash @@ -41,7 +77,7 @@ public: protected: void Initialize() CM_OVERRIDE; void Append(unsigned char const* buf, int sz) CM_OVERRIDE; - std::string Finalize() CM_OVERRIDE; + std::vector<unsigned char> Finalize() CM_OVERRIDE; }; #define cmCryptoHash_SHA_CLASS_DECL(SHA) \ @@ -56,7 +92,7 @@ protected: protected: \ virtual void Initialize(); \ virtual void Append(unsigned char const* buf, int sz); \ - virtual std::string Finalize(); \ + virtual std::vector<unsigned char> Finalize(); \ } cmCryptoHash_SHA_CLASS_DECL(SHA1); |