From 879d280bb9c4bd17dd1ee25787107bfbc38b8fdc Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Wed, 1 May 2019 12:14:09 +0200 Subject: [PATCH] ENH: modernize SHA1 classes (#1301) - localize some functionality, std::array for digest internals. Additional append sub-string methods, pass-through write of digest etc. --- src/OpenFOAM/primitives/hashes/SHA1/SHA1.C | 56 ++----- src/OpenFOAM/primitives/hashes/SHA1/SHA1.H | 58 ++++--- .../primitives/hashes/SHA1/SHA1Digest.C | 151 +++++++++--------- .../primitives/hashes/SHA1/SHA1Digest.H | 81 +++++----- src/OpenFOAM/primitives/hashes/SHA1/SHA1I.H | 95 ++++++++--- 5 files changed, 241 insertions(+), 200 deletions(-) diff --git a/src/OpenFOAM/primitives/hashes/SHA1/SHA1.C b/src/OpenFOAM/primitives/hashes/SHA1/SHA1.C index d1548333ed..c4a790600d 100644 --- a/src/OpenFOAM/primitives/hashes/SHA1/SHA1.C +++ b/src/OpenFOAM/primitives/hashes/SHA1/SHA1.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2009-2011 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2009-2011, 2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- | Copyright (C) 2011-2016 OpenFOAM Foundation @@ -36,9 +36,8 @@ Description \*---------------------------------------------------------------------------*/ #include "SHA1.H" -#include "IOstreams.H" #include "endian.H" - +#include "IOstreams.H" #include // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -77,17 +76,17 @@ static inline void set_uint32(unsigned char *dst, uint32_t v) void Foam::SHA1::processBytes(const void *data, size_t len) { - // already finalized, thus need to restart from nothing + // Already finalized, thus need to restart from nothing if (finalized_) { clear(); } - // complete filling of internal buffer + // Complete filling of internal buffer if (bufLen_) { - size_t remaining = bufLen_; - size_t add = + const size_t remaining = bufLen_; + const size_t add = ( sizeof(buffer_) - remaining > len ? len @@ -158,10 +157,10 @@ void Foam::SHA1::processBytes(const void *data, size_t len) void Foam::SHA1::processBlock(const void *data, size_t len) { const uint32_t *words = reinterpret_cast(data); - size_t nwords = len / sizeof(uint32_t); + const size_t nwords = len / sizeof(uint32_t); const uint32_t *endp = words + nwords; - // calculate with sixteen words of 32-bits + // Calculate with sixteen words of 32-bits uint32_t x[16]; uint32_t a = hashsumA_; uint32_t b = hashsumB_; @@ -295,7 +294,7 @@ void Foam::SHA1::calcDigest(SHA1Digest& dig) const { if (bufTotal_[0] || bufTotal_[1]) { - unsigned char *r = dig.v_; + unsigned char *r = dig.data(); set_uint32(r + 0 * sizeof(uint32_t), swapBytes(hashsumA_)); set_uint32(r + 1 * sizeof(uint32_t), swapBytes(hashsumB_)); @@ -305,8 +304,7 @@ void Foam::SHA1::calcDigest(SHA1Digest& dig) const } else { - // no data! - dig.clear(); + dig.clear(); // No data! } } @@ -334,24 +332,24 @@ bool Foam::SHA1::finalize() { finalized_ = true; - // account for unprocessed bytes - uint32_t bytes = bufLen_; - size_t size = (bytes < 56 ? 64 : 128) / sizeof(uint32_t); + // Account for unprocessed bytes + const uint32_t bytes = bufLen_; + const size_t size = (bytes < 56 ? 64 : 128) / sizeof(uint32_t); - // count remaining bytes. + // Count remaining bytes. bufTotal_[0] += bytes; if (bufTotal_[0] < bytes) { ++bufTotal_[1]; } - // finalized, but no data! + // Finalized, but no data! if (!bufTotal_[0] && !bufTotal_[1]) { return false; } - // place the 64-bit file length in *bits* at the end of the buffer. + // Place the 64-bit length in *bits* at the end of the buffer. buffer_[size-2] = swapBytes((bufTotal_[1] << 3) | (bufTotal_[0] >> 29)); buffer_[size-1] = swapBytes(bufTotal_[0] << 3); @@ -367,28 +365,6 @@ bool Foam::SHA1::finalize() } -Foam::SHA1Digest Foam::SHA1::digest() const -{ - SHA1Digest dig; - - if (finalized_) - { - calcDigest(dig); - } - else - { - // avoid disturbing our data - use a copy - SHA1 sha(*this); - if (sha.finalize()) - { - sha.calcDigest(dig); - } - } - - return dig; -} - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // #undef K1 diff --git a/src/OpenFOAM/primitives/hashes/SHA1/SHA1.H b/src/OpenFOAM/primitives/hashes/SHA1/SHA1.H index 2e6f182657..93ea3e6a55 100644 --- a/src/OpenFOAM/primitives/hashes/SHA1/SHA1.H +++ b/src/OpenFOAM/primitives/hashes/SHA1/SHA1.H @@ -45,9 +45,7 @@ SourceFiles #define SHA1_H #include -#include - -#include "int.H" +#include #include "SHA1Digest.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -61,7 +59,7 @@ namespace Foam class SHA1 { - // Private data + // Private Data //- Track if the hashsum has been finalized (added count, etc) bool finalized_; @@ -91,8 +89,9 @@ class SHA1 //- Process for the next LEN bytes, LEN need not be a multiple of 64. void processBytes(const void *data, size_t len); - //- Calculate current digest from appended data. - void calcDigest(SHA1Digest&) const; + //- Calculate digest from current data. + void calcDigest(SHA1Digest& dig) const; + public: @@ -101,41 +100,60 @@ public: //- Construct null inline SHA1(); - //- Construct null and append initial std::string - inline explicit SHA1(const std::string&); - //- Construct null and append initial string - inline explicit SHA1(const char*); + inline explicit SHA1(const char* str); + + //- Construct null and append initial std::string + inline explicit SHA1(const std::string& str); + // Member Functions //- Reset the hashed data before appending more void clear(); + //- Append data for processing + inline SHA1& append(const char* str); + //- Append data for processing inline SHA1& append(const char* data, size_t len); //- Append string for processing - inline SHA1& append(const std::string&); + inline SHA1& append(const std::string& str); - //- Append string for processing - inline SHA1& append(const char* str); + //- Append substring for processing + inline SHA1& append + ( + const std::string& str, + size_t pos, + size_t len = std::string::npos + ); //- Finalized the calculations (normally not needed directly). // Returns false if no bytes were passed for processing bool finalize(); - //- Calculate current digest from appended data. - SHA1Digest digest() const; + //- Calculate digest from current data. + inline SHA1Digest digest() const; + + //- The digest (40-byte) text representation, optionally with '_' prefix + inline std::string str(const bool prefixed=false) const; + + //- Write digest (40-byte) representation, optionally with '_' prefix + inline Ostream& write(Ostream& os, const bool prefixed=false) const; // Member Operators + //- Cast conversion to a SHA1Digest, + // calculates the %digest from the current data + inline operator SHA1Digest() const; + //- Equality operator, compares %digests - inline bool operator==(const SHA1&) const; + inline bool operator==(const SHA1& rhs) const; //- Compare %digest - inline bool operator==(const SHA1Digest&) const; + inline bool operator==(const SHA1Digest& dig) const; //- Compare %digest to (40-byte) text representation (eg, from sha1sum) // An %empty string is equivalent to @@ -147,7 +165,6 @@ public: // "0000000000000000000000000000000000000000" inline bool operator==(const char* hexdigits) const; - //- Inequality operator, compares %digests inline bool operator!=(const SHA1&) const; @@ -159,11 +176,6 @@ public: //- Inequality operator, compare %digest inline bool operator!=(const char* hexdigits) const; - - - //- Convert to a SHA1Digest, - // calculate current %digest from appended data - inline operator SHA1Digest() const; }; diff --git a/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.C b/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.C index 9c60efc10b..5b52bfbacd 100644 --- a/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.C +++ b/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2009-2011 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2009-2011, 2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- | Copyright (C) 2011-2015 OpenFOAM Foundation @@ -27,29 +27,30 @@ License #include "SHA1Digest.H" #include "IOstreams.H" - #include // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // const Foam::SHA1Digest Foam::SHA1Digest::null; -//! \cond fileScope static const char hexChars[] = "0123456789abcdef"; -//! \endcond + +// The char '0' == 0 +static constexpr int offsetZero = int('0'); + +// The char 'A' (or 'a') == 10 +static constexpr int offsetUpper = int('A') - 10; -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // +// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // -unsigned char Foam::SHA1Digest::readHexDigit(Istream& is) +namespace Foam { - // Takes into account that 'a' (or 'A') is 10 - static const int alphaOffset = toupper('A') - 10; - // Takes into account that '0' is 0 - static const int zeroOffset = int('0'); - - // silently ignore leading or intermediate '_' +// Read hexadecimal value, ignoring leading or intermediate '_' +static unsigned char readHexDigit(Istream& is) +{ + // Silently ignore leading or intermediate '_' char c = 0; do { @@ -57,23 +58,22 @@ unsigned char Foam::SHA1Digest::readHexDigit(Istream& is) } while (c == '_'); - if (!isxdigit(c)) + if (isdigit(c)) + { + return int(c) - offsetZero; + } + else if (!isxdigit(c)) { FatalIOErrorInFunction(is) << "Illegal hex digit: '" << c << "'" << exit(FatalIOError); } - if (isdigit(c)) - { - return int(c) - zeroOffset; - } - else - { - return toupper(c) - alphaOffset; - } + return toupper(c) - offsetUpper; } +} // End namespace Foam + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // @@ -85,7 +85,8 @@ Foam::SHA1Digest::SHA1Digest() Foam::SHA1Digest::SHA1Digest(Istream& is) { - is >> *this; + clear(); + read(is); } @@ -93,15 +94,15 @@ Foam::SHA1Digest::SHA1Digest(Istream& is) void Foam::SHA1Digest::clear() { - memset(v_, 0, length); + dig_.fill(0); // Same as memset(dig_.data(), 0, dig_.size()); } bool Foam::SHA1Digest::empty() const { - for (unsigned i = 0; i < length; ++i) + for (const auto& byteVal : dig_) { - if (v_[i]) + if (byteVal) { return false; } @@ -118,24 +119,39 @@ std::string Foam::SHA1Digest::str(const bool prefixed) const if (prefixed) { - buf.resize(1 + length*2); + buf.resize(1 + 2*dig_.size()); buf[nChar++] = '_'; } else { - buf.resize(length*2); + buf.resize(2*dig_.size()); } - for (unsigned i = 0; i < length; ++i) + for (const auto& byteVal : dig_) { - buf[nChar++] = hexChars[((v_[i] >> 4) & 0xF)]; - buf[nChar++] = hexChars[(v_[i] & 0xF)]; + buf[nChar++] = hexChars[((byteVal >> 4) & 0xF)]; // Upper nibble + buf[nChar++] = hexChars[(byteVal & 0xF)]; // Lower nibble } return buf; } +Foam::Istream& Foam::SHA1Digest::read(Istream& is) +{ + for (auto& byteVal : dig_) + { + const unsigned char upp = readHexDigit(is); + const unsigned char low = readHexDigit(is); + + byteVal = (upp << 4) + low; + } + + is.check(FUNCTION_NAME); + return is; +} + + Foam::Ostream& Foam::SHA1Digest::write(Ostream& os, const bool prefixed) const { if (prefixed) @@ -143,10 +159,10 @@ Foam::Ostream& Foam::SHA1Digest::write(Ostream& os, const bool prefixed) const os.write('_'); } - for (unsigned i = 0; i < length; ++i) + for (const auto& byteVal : dig_) { - os.write(hexChars[((v_[i] >> 4) & 0xF)]); - os.write(hexChars[(v_[i] & 0xF)]); + os.write(hexChars[((byteVal >> 4) & 0xF)]); // Upper nibble + os.write(hexChars[(byteVal & 0xF)]); // Lower nibble } os.check(FUNCTION_NAME); @@ -158,46 +174,38 @@ Foam::Ostream& Foam::SHA1Digest::write(Ostream& os, const bool prefixed) const bool Foam::SHA1Digest::operator==(const SHA1Digest& rhs) const { - for (unsigned i = 0; i < length; ++i) - { - if (v_[i] != rhs.v_[i]) - { - return false; - } - } - - return true; + return (dig_ == rhs.dig_); } bool Foam::SHA1Digest::operator==(const std::string& hexdigits) const { - // null or empty string is not an error - interpret as '0000..' + // Null or empty string is not an error - interpret as '0000..' if (hexdigits.empty()) { return empty(); } - // skip possible '_' prefix - unsigned charI = 0; + // Skip possible '_' prefix + unsigned nChar = 0; if (hexdigits[0] == '_') { - ++charI; + ++nChar; } - // incorrect length - can never match - if (hexdigits.size() != charI + length*2) + // Incorrect length - can never match + if (hexdigits.size() != nChar + 2*dig_.size()) { return false; } - for (unsigned i = 0; i < length; ++i) + for (const auto& byteVal : dig_) { - const char c1 = hexChars[((v_[i] >> 4) & 0xF)]; - const char c2 = hexChars[(v_[i] & 0xF)]; + const char upp = hexChars[((byteVal >> 4) & 0xF)]; // Upper nibble + const char low = hexChars[(byteVal & 0xF)]; // Lower nibble - if (c1 != hexdigits[charI++]) return false; - if (c2 != hexdigits[charI++]) return false; + if (upp != hexdigits[nChar++]) return false; + if (low != hexdigits[nChar++]) return false; } return true; @@ -206,32 +214,32 @@ bool Foam::SHA1Digest::operator==(const std::string& hexdigits) const bool Foam::SHA1Digest::operator==(const char* hexdigits) const { - // null or empty string is not an error - interpret as '0000..' + // Null or empty string is not an error - interpret as '0000..' if (!hexdigits || !*hexdigits) { return empty(); } - // skip possible '_' prefix - unsigned charI = 0; + // Skip possible '_' prefix + unsigned nChar = 0; if (hexdigits[0] == '_') { - ++charI; + ++nChar; } - // incorrect length - can never match - if (strlen(hexdigits) != charI + length*2) + // Incorrect length - can never match + if (strlen(hexdigits) != nChar + 2*dig_.size()) { return false; } - for (unsigned i = 0; i < length; ++i) + for (const auto& byteVal : dig_) { - const char c1 = hexChars[((v_[i] >> 4) & 0xF)]; - const char c2 = hexChars[(v_[i] & 0xF)]; + const char upp = hexChars[((byteVal >> 4) & 0xF)]; + const char low = hexChars[(byteVal & 0xF)]; - if (c1 != hexdigits[charI++]) return false; - if (c2 != hexdigits[charI++]) return false; + if (upp != hexdigits[nChar++]) return false; + if (low != hexdigits[nChar++]) return false; } return true; @@ -256,22 +264,11 @@ bool Foam::SHA1Digest::operator!=(const char* rhs) const } -// * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * * // +// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * // Foam::Istream& Foam::operator>>(Istream& is, SHA1Digest& dig) { - unsigned char *v = dig.v_; - - for (unsigned i = 0; i < dig.length; ++i) - { - unsigned char c1 = SHA1Digest::readHexDigit(is); - unsigned char c2 = SHA1Digest::readHexDigit(is); - - v[i] = (c1 << 4) + c2; - } - - is.check(FUNCTION_NAME); - return is; + return dig.read(is); } diff --git a/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.H b/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.H index b09d0dcf36..a1d04757a2 100644 --- a/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.H +++ b/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2009-2011 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2009-2011, 2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- | Copyright (C) 2011-2016 OpenFOAM Foundation @@ -40,6 +40,7 @@ SourceFiles #ifndef SHA1Digest_H #define SHA1Digest_H +#include #include // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -47,30 +48,39 @@ SourceFiles namespace Foam { -// Forward declaration of classes +// Forward Declarations +class SHA1; class Istream; class Ostream; -// Forward declaration of friend functions and operators -class SHA1; -class SHA1Digest; -Ostream& operator<<(Ostream&, const SHA1Digest&); -Istream& operator>>(Istream&, SHA1Digest&); - - /*---------------------------------------------------------------------------*\ Class SHA1Digest Declaration \*---------------------------------------------------------------------------*/ class SHA1Digest { + // Private Data + + //- The digest contents, which has 20 (uncoded) bytes + std::array dig_; + + + // Private Member Functions + + //- Pointer to the underlying digest data + unsigned char* data() + { + return dig_.data(); + } + + // Permit SHA1 to calculate the digest + friend class SHA1; + + public: - friend class SHA1; - // Static data members - //- The length of the (uncoded) digest contents - static const unsigned length = 20; + // Static Data Members //- A null digest (ie, all zero) static const SHA1Digest null; @@ -81,8 +91,8 @@ public: //- Construct a zero digest SHA1Digest(); - //- Construct read a digest - SHA1Digest(Istream&); + //- Read construct a digest + explicit SHA1Digest(Istream& is); // Member Functions @@ -96,8 +106,14 @@ public: //- Return (40-byte) text representation, optionally with '_' prefix std::string str(const bool prefixed=false) const; + //- Read (40-byte) text representation. + // Since leading and intermediate underscores are skipped, a '_' can + // be prefixed to the text representation to use an unquoted + // SHA1Digest without parsing ambiguities as a number. + Istream& read(Istream& is); + //- Write (40-byte) text representation, optionally with '_' prefix - Ostream& write(Ostream&, const bool prefixed=false) const; + Ostream& write(Ostream& os, const bool prefixed=false) const; // Member Operators @@ -126,33 +142,18 @@ public: //- Inequality operator bool operator!=(const char* hexdigits) const; - - - - - // IOstream Operators - - //- Read (40-byte) text representation - // Since leading and intermediate underscores are skipped, a '_' can - // be prefixed to the text representation to use an unquoted - // SHA1Digest without parsing ambiguities as a number. - friend Istream& operator>>(Istream&, SHA1Digest&); - - //- Write (40-byte) text representation, unquoted and without prefix - friend Ostream& operator<<(Ostream&, const SHA1Digest&); - - -private: - // Private data - - //- The digest contents - unsigned char v_[length]; - - //- Read hexadecimal value, ignoring leading or intermediate '_' - static unsigned char readHexDigit(Istream&); }; +// IOstream Operators + +//- Read (40-byte) text representation (ignoring leading '_' prefix) +Istream& operator>>(Istream&is , SHA1Digest& dig); + +//- Write (40-byte) text representation, unquoted and without prefix +Ostream& operator<<(Ostream& os, const SHA1Digest& dig); + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // } // End namespace Foam diff --git a/src/OpenFOAM/primitives/hashes/SHA1/SHA1I.H b/src/OpenFOAM/primitives/hashes/SHA1/SHA1I.H index 09b906d1e7..e351145d62 100644 --- a/src/OpenFOAM/primitives/hashes/SHA1/SHA1I.H +++ b/src/OpenFOAM/primitives/hashes/SHA1/SHA1I.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2009-2011 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2009-2011, 2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- | Copyright (C) 2011 OpenFOAM Foundation @@ -36,14 +36,14 @@ inline Foam::SHA1::SHA1() } -inline Foam::SHA1::SHA1(const std::string& str) +inline Foam::SHA1::SHA1(const char* str) { clear(); append(str); } -inline Foam::SHA1::SHA1(const char* str) +inline Foam::SHA1::SHA1(const std::string& str) { clear(); append(str); @@ -59,16 +59,9 @@ inline Foam::SHA1& Foam::SHA1::append(const char* data, size_t len) } -inline Foam::SHA1& Foam::SHA1::append(const std::string& str) -{ - processBytes(str.data(), str.size()); - return *this; -} - - inline Foam::SHA1& Foam::SHA1::append(const char* str) { - if (str) + if (str && *str) { processBytes(str, strlen(str)); } @@ -76,17 +69,85 @@ inline Foam::SHA1& Foam::SHA1::append(const char* str) } +inline Foam::SHA1& Foam::SHA1::append(const std::string& str) +{ + processBytes(str.data(), str.size()); + return *this; +} + + +inline Foam::SHA1& Foam::SHA1::append +( + const std::string& str, + size_t pos, + size_t len +) +{ + if (std::string::npos != pos && pos < str.length()) + { + if (std::string::npos == len || pos + len > str.length()) + { + len = str.length() - pos; + } + + processBytes(str.data() + pos, len); + } + + return *this; +} + + +inline Foam::SHA1Digest Foam::SHA1::digest() const +{ + SHA1Digest dig; + + if (finalized_) + { + calcDigest(dig); + } + else + { + // Avoid disturbing current data - use a copy + SHA1 sha(*this); + if (sha.finalize()) + { + sha.calcDigest(dig); + } + } + + return dig; +} + + +inline std::string Foam::SHA1::str(const bool prefixed) const +{ + return digest().str(prefixed); +} + + +inline Foam::Ostream& Foam::SHA1::write(Ostream& os, const bool prefixed) const +{ + return digest().write(os, prefixed); +} + + // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // +inline Foam::SHA1::operator Foam::SHA1Digest() const +{ + return digest(); +} + + inline bool Foam::SHA1::operator==(const SHA1& rhs) const { return this->digest() == rhs.digest(); } -inline bool Foam::SHA1::operator==(const SHA1Digest& rhs) const +inline bool Foam::SHA1::operator==(const SHA1Digest& dig) const { - return this->digest() == rhs; + return this->digest() == dig; } @@ -126,17 +187,11 @@ inline bool Foam::SHA1::operator!=(const char* rhs) const } -inline Foam::SHA1::operator Foam::SHA1Digest() const -{ - return digest(); -} - - // * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * // inline Foam::Ostream& Foam::operator<<(Ostream& os, const SHA1& sha) { - return (os << sha.digest()); + return sha.write(os); }