Commit 36112db1 authored by Mark Olesen's avatar Mark Olesen Committed by Andrew Heather
Browse files

ENH: modernize SHA1 classes (#1301)

- localize some functionality, std::array for digest internals.
  Additional append sub-string methods, pass-through write of digest
  etc.
parent 83d26d19
......@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\ / A nd | Copyright (C) 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 <cstring>
// * * * * * * * * * * * * * * 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<const uint32_t*>(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
......
......@@ -45,9 +45,7 @@ SourceFiles
#define SHA1_H
#include <string>
#include <cstddef>
#include "int.H"
#include <cstdint>
#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 string
inline explicit SHA1(const char* str);
//- Construct null and append initial std::string
inline explicit SHA1(const std::string&);
inline explicit SHA1(const std::string& str);
//- Construct null and append initial string
inline explicit SHA1(const char*);
// 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;
};
......
......@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
| Copyright (C) 2011-2015 OpenFOAM Foundation
......@@ -27,29 +27,30 @@ License
#include "SHA1Digest.H"
#include "IOstreams.H"
#include <cstring>
// * * * * * * * * * * * * * * 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');
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// The char 'A' (or 'a') == 10
static constexpr int offsetUpper = int('A') - 10;
unsigned char Foam::SHA1Digest::readHexDigit(Istream& is)
{
// 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');
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// 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);
}
......
......@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
| Copyright (C) 2011-2016 OpenFOAM Foundation
......@@ -40,6 +40,7 @@ SourceFiles
#ifndef SHA1Digest_H
#define SHA1Digest_H
#include <array>
#include <string>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -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<unsigned char, 20> 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;