Procházet zdrojové kódy

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
Brad King před 9 roky
rodič
revize
f203694bb8
2 změnil soubory, kde provedl 117 přidání a 36 odebrání
  1. 78 33
      Source/cmCryptoHash.cxx
  2. 39 3
      Source/cmCryptoHash.h

+ 78 - 33
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)

+ 39 - 3
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);