/* // // Copyright (c) 1993-2015 Robert McNeel & Associates. All rights reserved. // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert // McNeel & Associates. // // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF // MERCHANTABILITY ARE HEREBY DISCLAIMED. // // For complete openNURBS copyright information see . // //////////////////////////////////////////////////////////////// */ #if !defined(OPENNURBS_SHA1_INC_) #define OPENNURBS_SHA1_INC_ class ON_CLASS ON_SHA1_Hash { public: static const ON_SHA1_Hash ZeroDigest; // all digest bytes are zero static const ON_SHA1_Hash EmptyContentHash; // SHA-1 hash of zero bytes // The default constructor creates a zero digest sha1 hash ON_SHA1_Hash(); ~ON_SHA1_Hash() = default; ON_SHA1_Hash(const ON_SHA1_Hash&) = default; ON_SHA1_Hash& operator=(const ON_SHA1_Hash&) = default; static int Compare( const ON_SHA1_Hash& a, const ON_SHA1_Hash& b ); /* Parameters: buffer - [in] sizeof_buffer - [in] number of bytes in buffer Returns: SHA1-1 hash of the buffer. */ static ON_SHA1_Hash BufferContentHash( const void* buffer, size_t sizeof_buffer ); /* Parameters: file_name - [in] Name of file sizeof_file - [out] number of bytes in file Returns: SHA1-1 hash of the buffer. */ static ON_SHA1_Hash FileContentHash( const wchar_t* file_name, ON__UINT64& sizeof_file ); static ON_SHA1_Hash FileContentHash( const char* file_name, ON__UINT64& sizeof_file ); /* Description: Return a hash of the file system path that is independent of the size of wchar_t, constant across platforms, and constant across varations in the way the path is formatted. Parameters: path - [in] File system path to a directory or file. Returns: SHA1-1 hash of the buffer. Example: These file system paths have identical values of FileSystemPathHash(). /x/y/z/name.ext \x\y\z\name.ext /x//y//z/name.ext /x/y/a/b/c/../../../z/name.ext /X/Y/Z/NAME.EXT (When ON_ComparePathIgnoreCase() is true) Remarks: This function uses the value of ON_FileSystemPath::PlatformPathIgnoreCase() to determine if case should be ignored. Use the version with a bIgnoreCase parameter if you want to explicitly control this decision. */ static ON_SHA1_Hash FileSystemPathHash( const wchar_t* path ); static ON_SHA1_Hash FileSystemPathHash( const char* path ); static ON_SHA1_Hash FileSystemPathHash( const wchar_t* path, bool bIgnoreCase ); static ON_SHA1_Hash FileSystemPathHash( const char* path, bool bIgnoreCase ); /* Parameters: file - [in] File stream from ON_FileStream::Open(...,L"rb"); sizeof_file - [out] number of bytes in file Returns: SHA1-1 hash of the file stream from the current offset to the end of the file. */ static ON_SHA1_Hash FileContentHash( FILE* file, ON__UINT64& sizeof_file ); /* Parameters: str - [in] string byte_count - [out] number of bytes in UTF-8 encoding of the string. Returns: SHA1-1 hash of the UTF-8 encoding of the string. (Platforms and endian independent.) */ static ON_SHA1_Hash StringHash( const ON_wString& str, ON__UINT64& byte_count ); static ON_SHA1_Hash StringHash( const wchar_t* str, size_t str_length, ON__UINT64& byte_count ); static ON_SHA1_Hash StringHash( const wchar_t* null_terminated_string ); /* Parameters: str - [in] byte_count - [out] number of bytes in the string. Returns: SHA1-1 hash of the UTF-8 encoding of the string. (Platforms and endian independent.) */ static ON_SHA1_Hash StringHash( const ON_String& str, ON__UINT64& byte_count ); static ON_SHA1_Hash StringHash( const char* str, size_t str_length, ON__UINT64& byte_count ); static ON_SHA1_Hash StringHash( const char* null_terminated_string ); /* Parameters: bUpperCaseHexadecimalDigits - [in] false - use 0-9, a-f true - use 0-9, A-F Returns: The SHA-1 hash value as a 40 hexadecimal digits. The first digit in the string is the hexadecimal value of m_digest[0]. */ const ON_String ToUTF8String( bool bUpperCaseHexadecimalDigits ) const; /* Parameters: bUpperCaseHexadecimalDigits - [in] false - use 0-9, a-f true - use 0-9, A-F Returns: The SHA-1 hash value as a 40 hexadecimal digits. The first digit in the string is the hexadecimal value of m_digest[0]. */ const ON_wString ToString( bool bUpperCaseHexadecimalDigits ) const; /* Description: Same as ToString but prints EmptyContentSHA1 or ZeroSHA1 for those two special cases. */ const ON_wString ToStringEx( bool bUpperCaseHexadecimalDigits ) const; /* Description: Parse a string of 40 hexadecimal digits to create a SHA-1 hash. Parameters: string_to_parse - [in] bParseLeadinglSpaces - [in] If true, leading space characters are parsed. Otherwise leading space characters cause parsing to fail. bParseInteriorSpace - [in] If true, interior space characters are parsed. Otherwise interior space characters cause parsing to fail. bParseInteriorHyphen - [in] If true, interior hyphen characters are parsed. Otherwise interior hyphen characters cause parsing to fail. bIgnoreInternalSpaces - [in] If true, isolated hyphens are ingored until 40 hex digits are read. bIgnoreInternalHyphens - [in] If true, leading spaces and isolated interior spacess are ingored until 40 hex digits are read. failure_return_value - [in] Value to return if string_to_parse cannot be parsed as 40 hex digits. Returns: If parsing is successful, the value of the SHA-1 hash is returned. Otherwise failure_return_value is returned. */ static const ON_SHA1_Hash FromString( const ON_wString string_to_parse, bool bParseLeasingSpaces, bool bParseInteriorSpace, bool bParseInteriorHyphen, ON_SHA1_Hash failure_return_value ); bool Read( class ON_BinaryArchive& archive ); bool Write( class ON_BinaryArchive& archive ) const; void Dump( class ON_TextLog& text_log ) const; /* Returns: True if this and ON_SHA1_Hash::ZeroDigest have identical digest values. */ bool IsZeroDigest() const; /* Returns: True if this and ON_SHA1_Hash::EmptyContentHash have identical digest values. */ bool IsEmptyContentHash() const; bool IsZeroDigestOrEmptyContentHash() const; ON_DEPRECATED_MSG("Use IsZeroDigestOrEmptyContentHash() instead. (Spelling error in this one's name.") bool IsZeroDigentOrEmptyContentHash() const; /* Returns: True if this hash is not equal to ON_SHA1_Hash::EmptyContentHash or ON_SHA1_Hash::ZeroDigest. Remarks: ON_SHA1_Hash::EmptyContentHash is the SHA1 of hasing zero bytes and has a non zero digest. ON_SHA1_Hash::ZeroDigest is 20 bytes of zeros. Opennurbs uses ON_SHA1_Hash::ZeroDigest to indicate a SHA1 has is not initialized. */ bool IsSet() const; ON__UINT8 m_digest[20]; }; ON_DECL bool operator==(const ON_SHA1_Hash& a, const ON_SHA1_Hash& b); ON_DECL bool operator!=(const ON_SHA1_Hash& a, const ON_SHA1_Hash& b); /* Description: ON_SHA1 is a small class for calculating the SHA-1 hash of a sequence of bytes. It may be use incrementally (the bytes do not have to be in a contiguous array in memory at one time). Remarks: The ON_SHA1 class cannot be used for cryptographic or security applications. The SHA-1 hash algorithm is not suitable for cryptographic or security applications. The ON_SHA1 class does not "wipe" intermediate results. If you have two different seqences of N bytes storing information (lower entropy than a random sequence) are you are not intentionally calculating the information to create a SHA-1 hash collision, then the probability that the sequences have the same SHA-1 hash is approximately 2^-80 ~ 10^-24. */ class ON_CLASS ON_SHA1 { public: ON_SHA1() = default; ~ON_SHA1() = default; ON_SHA1(const ON_SHA1&) = default; ON_SHA1& operator=(const ON_SHA1&) = default; /* Description: Make one or more calls to AccumulateBytes() as the sequenence of bytes is available. Parameters: buffer - [in] sizeof_buffer - [in] number of bytes in buffer */ #if defined(ON_COMPILER_MSC) && defined(NDEBUG) // Reduces release build link time optimization by several hours for // large programs that make lots of calls to ON_SHA1.Accumulate*() functions. __declspec(noinline) #endif void AccumulateBytes( const void* buffer, ON__UINT64 sizeof_buffer ); /* Description: Add the double value to the SHA1 in a manner that -0.0 and +0.0 will generate identical SHA-1 values and the result is independent of endian byte order. */ void AccumulateDouble( double x ); /* Description: Add the double value to the SHA1 in a manner that -0.0 and +0.0 will generate identical SHA-1 values and the result is independent of endian byte order. */ void AccumulateDoubleArray( size_t count, const double* a ); /* Description: Add the double value to the SHA1 in a manner that -0.0 and +0.0 will generate identical SHA-1 values and the result is independent of endian byte order. */ void AccumulateFloat( float x ); /* Description: Add the double value to the SHA1 in a manner that -0.0 and +0.0 will generate identical SHA-1 values and the result is independent of endian byte order. */ void AccumulateFloatArray( size_t count, const float* a ); void Accumulate2fPoint( const class ON_2fPoint& point ); void Accumulate3fPoint( const class ON_3fPoint& point ); void Accumulate4fPoint( const class ON_4fPoint& point ); void Accumulate2fVector( const class ON_2fVector& vector ); void Accumulate3fVector( const class ON_3fVector& vector ); void Accumulate2dPoint( const class ON_2dPoint& point ); void Accumulate3dPoint( const class ON_3dPoint& point ); void Accumulate4dPoint( const class ON_4dPoint& point ); void Accumulate2dVector( const class ON_2dVector& vector ); void Accumulate3dVector( const class ON_3dVector& vector ); void AccumulateBoundingBox( const class ON_BoundingBox& bbox ); void AccumulateUnitSystem( const class ON_UnitSystem& unit_system ); void AccumulateLengthUnitSystem( const ON::LengthUnitSystem length_unit_system ); /* Description: Accumuates the full and relative path names. */ void AccumulateFileReference( const class ON_FileReference& file_reference ); void AccumulateTransformation( const class ON_Xform& xform ); void AccumulateInteger8( ON__INT8 i ); void AccumulateUnsigned8( ON__UINT8 u ); void AccumulateInteger16( ON__INT16 i ); void AccumulateUnsigned16( ON__UINT16 u ); void AccumulateInteger32( ON__INT32 i ); void AccumulateInteger32Array( size_t count, const ON__INT32* a ); void AccumulateUnsigned32( ON__UINT32 u ); void AccumulateInteger64( ON__INT64 i ); void AccumulateUnsigned64( ON__UINT64 u ); void AccumulateBool( bool b ); void AccumulateString( const class ON_String& str ); void AccumulateString( const class ON_wString& str ); void AccumulateId( const ON_UUID& id ); void AccumulateString( const char* sUTF8, int element_count, ON_StringMapOrdinalType mapping ); void AccumulateString( const wchar_t* sUTF8, int element_count, ON_StringMapOrdinalType mapping ); void AccumulateString( const class ON_String& str, ON_StringMapOrdinalType mapping ); void AccumulateString( const class ON_wString& str, ON_StringMapOrdinalType mapping ); void AccumulateSubHash( const class ON_SHA1_Hash& sub_hash ); private: void Internal_SwapBigEndianUpdate( const void* buffer, ON__UINT64 sizeof_buffer ); public: /* Returns: Total number of bytes passed to Update(). */ ON__UINT64 ByteCount() const; /* Returns: SHA-1 hash value of the sequenence of ByteCount() bytes that have been passed to this ON_SHA1 classe's Update() function since construction or the last call to Reset(). Remarks: You may use Hash() to compute intermediate SHA-1 hash values. Put another way, you may call Update() zero or more times passing in N1 bytes, call Digest() to get the SHA-1 hash of those N1 bytes, make zero or more additional calls to Update() passing in N2 additional bytes, call digest to get the SHA-1 hash of the seqence of (N1 + N2) bytes, and so on. */ ON_SHA1_Hash Hash() const; /* Description: Reset this ON_SHA1 class so it can be reused. */ void Reset(); /* Description: This is a static function that uses ON_SHA1 to compute SHA-1 hash values of sequences of bytes with known SHA-1 hash values and compares the results from ON_SHA1 with the known SHA-1 hash values. This function can be used to validate the ON_SHA1 class compiled correctly. Returns: true All validation tests passed. false At least one validation test failed. */ static bool Validate(); private: void Internal_Accumulate(const ON__UINT8* input, ON__UINT32 length); void set_final_hash(); ON__UINT64 m_byte_count = 0; // number of bytes that have passed through calls to update(). // if 1 == m_status_bits & 1, then update has been called at least once (perhaps with 0 bytes). // if 2 == m_status_bits & 2, then m_sha1_hash is current. mutable ON__UINT32 m_status_bits = 0; ON__UINT32 m_reserved = 0; // current "remainder" ON__UINT8 m_buffer[64]; // bytes that didn't fit in last 64 byte chunk ON__UINT32 m_bit_count[2]; // number of bits (lo, hi) ON__UINT32 m_state[5]; // current state // chached SHA1 hash - valid if 2 = (2 & m_status_bits) mutable ON_SHA1_Hash m_sha1_hash; }; /* Description: Test speeds of various hash algoritmhs. Parameters: byte_count - [in] Number of bytes to hash. This number is rounded up to the nearest multiple of 1024. crc16 - [in/out] If crc16 is not nullptr, then 16 bit CRC hashing is tested using function ON_CRC16(). crc32 - [in/out] If crc32 is not nullptr, then 32 bit CRC hashing is tested using function ON_CRC32(). md5_hash - [in/out] If md5_hash is not nullptr, then MD5 hashing is tested using class ON_MD5. sha1_hash - [in/out] If sha1_hash is not nullptr, then SHA-1 hashing is tested class ON_SHA1. elapsed_time_in_seconds - [out] elapsed_time_in_seconds[0] = 16 bit CRC hash time in seconds. elapsed_time_in_seconds[1] = 32 bit CRC hash time in seconds. elapsed_time_in_seconds[2] = MD5 hash time in seconds. elapsed_time_in_seconds[3] = SHA-1 hash time in seconds. If a hash was tested, then number of seconds it took to compute the hash is returned. Otherwise ON_DBL_QNAN is returned. */ ON_DECL void ON_TestHashSpeed( size_t byte_count, ON__UINT16* crc16, ON__UINT32* crc32, ON_MD5_Hash* md5_hash, ON_SHA1_Hash* sha1_hash, double elapsed_time_in_seconds[4] ); /* Description: Test speeds of various hash algoritmhs and use text_log to print the results. Parameters: byte_count - [in] Number of bytes to hash. This number is rounded up to the nearest multiple of 1024. bCRC16 - [in] True to test 16 bit CRC hashing speed. bCRC32 - [in] True to test 32 bit CRC hashing speed. bMD5 - [in] True to test MD5 hashing speed. bSHA1 - [in] True to test SHA-1 hashing speed. text_log - [in] Test results are printed using text_log. */ ON_DECL void ON_TestHashSpeed( size_t byte_count, bool bTestCRC16, bool bTestCRC32, bool bTestMD5, bool bTestSHA1, ON_TextLog& text_log ); ON_DECL void ON_TestHashSpeed( size_t byte_count, ON_TextLog& text_log ); #endif