// file : libbutl/sha256.mxx -*- C++ -*- // copyright : Copyright (c) 2014-2019 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #ifndef __cpp_modules_ts #pragma once #endif // C includes. #ifndef __cpp_lib_modules_ts #include #include // size_t #include #include // strlen(), memcpy() #include // enable_if, is_integral #endif // Other includes. #ifdef __cpp_modules_ts export module butl.sha256; #ifdef __cpp_lib_modules_ts import std.core; #endif #endif #include LIBBUTL_MODEXPORT namespace butl { class ifdstream; // SHA256 checksum calculator. // // For a single chunk of data a sum can be obtained in one line, for // example: // // cerr << sha256 ("123").string () << endl; // class LIBBUTL_SYMEXPORT sha256 { public: sha256 () {reset ();} // Append binary data. // void append (const void*, std::size_t); sha256 (const void* b, std::size_t n): sha256 () {append (b, n);} // Append string. // // Note that the hash includes the '\0' terminator. Failed that, a call // with an empty string will be indistinguishable from no call at all. // void append (const std::string& s) {append (s.c_str (), s.size () + 1);} void append (const char* s) {append (s, std::strlen (s) + 1);} explicit sha256 (const std::string& s): sha256 () {append (s);} explicit sha256 (const char* s): sha256 () {append (s);} // Append an integral type with a fast path optimization (see // SHA256_Update() for details). // void append (char c) { std::uint32_t r ((ctx_.count >> 3) & 0x3f); if (1 < 64 - r) { ctx_.buf[r] = static_cast (c); ctx_.count += 8; } else append (&c, 1); } template typename std::enable_if::value>::type append (T x) { const std::size_t len (sizeof (x)); std::uint32_t r ((ctx_.count >> 3) & 0x3f); if (len < 64 - r) { std::memcpy (&ctx_.buf[r], &x, sizeof (x)); ctx_.count += len << 3; } else append (&x, len); } // Append stream. // void append (ifdstream&); explicit sha256 (ifdstream& i): sha256 () {append (i);} // Check if any data has been hashed. // bool empty () const {return empty_;} // Reset to the default-constructed state. // void reset (); // Extract result. // // It can be obtained as either a 32-byte binary digest or as a 64- // character hex-encoded C-string. // using digest_type = std::uint8_t[32]; const digest_type& binary () const; const char* string () const; std::string abbreviated_string (std::size_t n) const { return std::string (string (), n < 64 ? n : 64); } private: struct context // Note: identical to SHA256_CTX. { std::uint32_t state[8]; std::uint64_t count; std::uint8_t buf[64]; }; union { mutable context ctx_; mutable char buf_[sizeof (context)]; // Also used to store string rep. }; mutable digest_type bin_; mutable bool done_; bool empty_; }; // Convert a SHA256 string representation (64 hex digits) to the fingerprint // canonical representation (32 colon-separated upper case hex digit pairs, // like 01:AB:CD:...). Throw invalid_argument if the argument is not a valid // SHA256 string. // LIBBUTL_SYMEXPORT std::string sha256_to_fingerprint (const std::string&); // Convert a fingerprint (32 colon-separated hex digit pairs) to the possibly // abbreviated SHA256 string representation (up to 64 lower case hex digits). // Throw invalid_argument if the first argument is not a valid fingerprint. // LIBBUTL_SYMEXPORT std::string fingerprint_to_sha256 (const std::string&, std::size_t = 64); }