// bdlde_sha2.h -*-C++-*- #ifndef INCLUDED_BDLDE_SHA2 #define INCLUDED_BDLDE_SHA2 #include <bsls_ident.h> BSLS_IDENT("$Id$ $CSID$") //@PURPOSE: Provide a value-semantic type encoding a message in a SHA-2 digest. // //@CLASSES: // bdlde::Sha224: value-semantic type representing a SHA-224 digest // bdlde::Sha256: value-semantic type representing a SHA-256 digest // bdlde::Sha384: value-semantic type representing a SHA-384 digest // bdlde::Sha512: value-semantic type representing a SHA-512 digest // //@SEE_ALSO: bdlde_md5 // //@DESCRIPTION: This component provides a set of classes ('Sha224', 'Sha256', // 'Sha384', and 'Sha512') that implement a mechanism for computing and // updating a SHA-2 digest (a cryptographic hash). The specification for this // is based on FIPS-180, which can be found at //.. // http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf //.. // // Note that a SHA-2 digest does not aid in error correction. // ///Usage ///----- // In this section we show intended usage of this component. The // 'validatePassword' function below returns whether a specified password has a // specified hash value. The 'assertPasswordIsExpected' function below has a // sample password to hash and a hash value that matches it. Note that the // output of 'loadDigest' is a binary representation. When hashes are // displayed for human consumption, they are typically converted to hex, but // that would create unnecessary overhead here. //.. // bool validatePassword(const bsl::string& password, // const bsl::string& salt, // const unsigned char *expected) // // Return 'true' if the specified 'password' concatenated with the // // specified 'salt' has a SHA-512 hash equal to the specified // // 'expected', and 'false' otherwise. // { // bdlde::Sha512 hasher; // hasher.update(password.c_str(), password.length()); // hasher.update(salt.c_str(), salt.length()); // // unsigned char digest[bdlde::Sha512::k_DIGEST_SIZE]; // hasher.loadDigest(digest); // // return bsl::equal(digest, // digest + bdlde::Sha512::k_DIGEST_SIZE, // expected); // } // // void assertPasswordIsExpected() // // Asserts that the constant string 'pass' salted with 'word' has the // // expected hash value. In a real application, the expected hash would // // likely come from some sort of database. // { // const bsl::string password = "pass"; // const bsl::string salt = "word"; // const unsigned char expected[bdlde::Sha512::k_DIGEST_SIZE] = { // 0xB1, 0x09, 0xF3, 0xBB, 0xBC, 0x24, 0x4E, 0xB8, 0x24, 0x41, 0x91, // 0x7E, 0xD0, 0x6D, 0x61, 0x8B, 0x90, 0x08, 0xDD, 0x09, 0xB3, 0xBE, // 0xFD, 0x1B, 0x5E, 0x07, 0x39, 0x4C, 0x70, 0x6A, 0x8B, 0xB9, 0x80, // 0xB1, 0xD7, 0x78, 0x5E, 0x59, 0x76, 0xEC, 0x04, 0x9B, 0x46, 0xDF, // 0x5F, 0x13, 0x26, 0xAF, 0x5A, 0x2E, 0xA6, 0xD1, 0x03, 0xFD, 0x07, // 0xC9, 0x53, 0x85, 0xFF, 0xAB, 0x0C, 0xAC, 0xBC, 0x86 // }; // // ASSERT(validatePassword(password, salt, expected)); // } //.. #include <bdlscm_version.h> #include <bsl_cstddef.h> #include <bsl_cstdint.h> #include <bsl_iosfwd.h> namespace BloombergLP { namespace bdlde { // ============ // class Sha224 // ============ class Sha224 { // This 'class' represents a SHA-224 digest that can be updated as // additional data is provided. // // More generally, this class supports a complete set of *value* // *semantic* operations, including copy construction, assignment, equality // comparison, and 'ostream' printing. (A precise operational definition // of when two instances have the same value can be found in the // description of 'operator==' for the class.) This container is // *exception* *neutral* with no guarantee of rollback: if an exception is // thrown during the invocation of a method on a pre-existing instance, the // class is left in a valid state, but its value is undefined. In no event // is memory leaked. Finally, *aliasing* (e.g., using all or part of an // object as both source and destination) is supported in all cases. // DATA bsl::uint64_t d_totalSize; // length of the entire message bsl::uint64_t d_bufferSize; // bytes currently used for 'd_buffer' unsigned char d_buffer[512 / 8]; // buffer for storing remaining part of // message that is not yet incorporated // into 'd_state' bsl::uint32_t d_state[8]; // state array storing the digest // FRIENDS friend bool operator==(const Sha224&, const Sha224&); public: // TYPES static const bsl::size_t k_DIGEST_SIZE = 224 / 8; // The size (in bytes) of the output // CREATORS Sha224(); // Construct a SHA-2 digest having the value corresponding to no data // having been provided. Sha224(const void *data, bsl::size_t length); // Construct a SHA-2 digest corresponding to the specified 'data' // having the specified 'length' (in bytes). Note that if 'data' is 0, // then 'length' also must be 0. // MANIPULATORS void reset(); // Reset the value of this SHA-2 digest to the value provided by the // default constructor. void update(const void *data, bsl::size_t length); // Update the value of this SHA-2 digest to incorporate the specified // 'data' having the specified 'length' in bytes. If the current // state is the default state, the resultant value of this SHA-2 // digest is the application of the SHA-2 algorithm upon the currently // given 'data' of the given 'length'. If this digest has been // previously provided data and has not been subsequently reset, the // current state is not the default state and the resultant value is // equivalent to applying the SHA-2 algorithm upon the concatenation of // all the provided data. The behavior is undefined unless the range // '[data, data + length)' is a valid range. Note that if 'data' is 0, // then 'length' must also be 0. void loadDigestAndReset(unsigned char *result); // Load the current value of this SHA-2 digest into the specified // 'result' and set the value of this SHA-2 digest to the value // provided by the default constructor. // ACCESSORS void loadDigest(unsigned char *result) const; // Load the value of this SHA-2 digest into the specified 'result'. bsl::ostream& print(bsl::ostream& stream) const; // Format the current value of this SHA-2 digest to the specified // output 'stream' and return a reference to the modifiable 'stream'. }; // ============ // class Sha256 // ============ class Sha256 { // This 'class' represents a SHA-256 digest that can be updated as // additional data is provided. // // More generally, this class supports a complete set of *value* // *semantic* operations, including copy construction, assignment, equality // comparison, and 'ostream' printing. (A precise operational definition // of when two instances have the same value can be found in the // description of 'operator==' for the class.) This container is // *exception* *neutral* with no guarantee of rollback: if an exception is // thrown during the invocation of a method on a pre-existing instance, the // class is left in a valid state, but its value is undefined. In no event // is memory leaked. Finally, *aliasing* (e.g., using all or part of an // object as both source and destination) is supported in all cases. // DATA bsl::uint64_t d_totalSize; // length of the entire message bsl::uint64_t d_bufferSize; // bytes currently used for 'd_buffer' unsigned char d_buffer[512 / 8]; // buffer for storing remaining part of // message that is not yet incorporated // into 'd_state' bsl::uint32_t d_state[8]; // state array storing the digest // FRIENDS friend bool operator==(const Sha256&, const Sha256&); public: // TYPES static const bsl::size_t k_DIGEST_SIZE = 256 / 8; // The size (in bytes) of the output // CREATORS Sha256(); // Construct a SHA-2 digest having the value corresponding to no data // having been provided. Sha256(const void *data, bsl::size_t length); // Construct a SHA-2 digest corresponding to the specified 'data' // having the specified 'length' (in bytes). Note that if 'data' is 0, // then 'length' also must be 0. // MANIPULATORS void reset(); // Reset the value of this SHA-2 digest to the value provided by the // default constructor. void update(const void *data, bsl::size_t length); // Update the value of this SHA-2 digest to incorporate the specified // 'data' having the specified 'length' in bytes. If the current // state is the default state, the resultant value of this SHA-2 // digest is the application of the SHA-2 algorithm upon the currently // given 'data' of the given 'length'. If this digest has been // previously provided data and has not been subsequently reset, the // current state is not the default state and the resultant value is // equivalent to applying the SHA-2 algorithm upon the concatenation of // all the provided data. The behavior is undefined unless the range // '[data, data + length)' is a valid range. Note that if 'data' is 0, // then 'length' must also be 0. void loadDigestAndReset(unsigned char *result); // Load the current value of this SHA-2 digest into the specified // 'result' and set the value of this SHA-2 digest to the value // provided by the default constructor. // ACCESSORS void loadDigest(unsigned char *result) const; // Load the value of this SHA-2 digest into the specified 'result'. bsl::ostream& print(bsl::ostream& stream) const; // Format the current value of this SHA-2 digest to the specified // output 'stream' and return a reference to the modifiable 'stream'. }; // ============ // class Sha384 // ============ class Sha384 { // This 'class' represents a SHA-384 digest that can be updated as // additional data is provided. // // More generally, this class supports a complete set of *value* // *semantic* operations, including copy construction, assignment, equality // comparison, and 'ostream' printing. (A precise operational definition // of when two instances have the same value can be found in the // description of 'operator==' for the class.) This container is // *exception* *neutral* with no guarantee of rollback: if an exception is // thrown during the invocation of a method on a pre-existing instance, the // class is left in a valid state, but its value is undefined. In no event // is memory leaked. Finally, *aliasing* (e.g., using all or part of an // object as both source and destination) is supported in all cases. // DATA bsl::uint64_t d_totalSize; // length of the entire message bsl::uint64_t d_bufferSize; // bytes currently used for 'd_buffer' unsigned char d_buffer[1024 / 8]; // buffer for storing remaining part of // message that is not yet incorporated // into 'd_state' bsl::uint64_t d_state[8]; // state array storing the digest // FRIENDS friend bool operator==(const Sha384&, const Sha384&); public: // TYPES static const bsl::size_t k_DIGEST_SIZE = 384 / 8; // The size (in bytes) of the output // CREATORS Sha384(); // Construct a SHA-2 digest having the value corresponding to no data // having been provided. Sha384(const void *data, bsl::size_t length); // Construct a SHA-2 digest corresponding to the specified 'data' // having the specified 'length' (in bytes). Note that if 'data' is 0, // then 'length' also must be 0. // MANIPULATORS void reset(); // Reset the value of this SHA-2 digest to the value provided by the // default constructor. void update(const void *data, bsl::size_t length); // Update the value of this SHA-2 digest to incorporate the specified // 'data' having the specified 'length' in bytes. If the current // state is the default state, the resultant value of this SHA-2 // digest is the application of the SHA-2 algorithm upon the currently // given 'data' of the given 'length'. If this digest has been // previously provided data and has not been subsequently reset, the // current state is not the default state and the resultant value is // equivalent to applying the SHA-2 algorithm upon the concatenation of // all the provided data. The behavior is undefined unless the range // '[data, data + length)' is a valid range. Note that if 'data' is 0, // then 'length' must also be 0. void loadDigestAndReset(unsigned char *result); // Load the current value of this SHA-2 digest into the specified // 'result' and set the value of this SHA-2 digest to the value // provided by the default constructor. // ACCESSORS void loadDigest(unsigned char *result) const; // Load the value of this SHA-2 digest into the specified 'result'. bsl::ostream& print(bsl::ostream& stream) const; // Format the current value of this SHA-2 digest to the specified // output 'stream' and return a reference to the modifiable 'stream'. }; // ============ // class Sha512 // ============ class Sha512 { // This 'class' represents a SHA-512 digest that can be updated as // additional data is provided. // // More generally, this class supports a complete set of *value* // *semantic* operations, including copy construction, assignment, equality // comparison, and 'ostream' printing. (A precise operational definition // of when two instances have the same value can be found in the // description of 'operator==' for the class.) This container is // *exception* *neutral* with no guarantee of rollback: if an exception is // thrown during the invocation of a method on a pre-existing instance, the // class is left in a valid state, but its value is undefined. In no event // is memory leaked. Finally, *aliasing* (e.g., using all or part of an // object as both source and destination) is supported in all cases. // DATA bsl::uint64_t d_totalSize; // length of the entire message bsl::uint64_t d_bufferSize; // bytes currently used for 'd_buffer' unsigned char d_buffer[1024 / 8]; // buffer for storing remaining part of // message that is not yet incorporated // into 'd_state' bsl::uint64_t d_state[8]; // state array storing the digest // FRIENDS friend bool operator==(const Sha512&, const Sha512&); public: // TYPES static const bsl::size_t k_DIGEST_SIZE = 512 / 8; // The size (in bytes) of the output // CREATORS Sha512(); // Construct a SHA-2 digest having the value corresponding to no data // having been provided. Sha512(const void *data, bsl::size_t length); // Construct a SHA-2 digest corresponding to the specified 'data' // having the specified 'length' (in bytes). Note that if 'data' is 0, // then 'length' also must be 0. // MANIPULATORS void reset(); // Reset the value of this SHA-2 digest to the value provided by the // default constructor. void update(const void *data, bsl::size_t length); // Update the value of this SHA-2 digest to incorporate the specified // 'data' having the specified 'length' in bytes. If the current // state is the default state, the resultant value of this SHA-2 // digest is the application of the SHA-2 algorithm upon the currently // given 'data' of the given 'length'. If this digest has been // previously provided data and has not been subsequently reset, the // current state is not the default state and the resultant value is // equivalent to applying the SHA-2 algorithm upon the concatenation of // all the provided data. The behavior is undefined unless the range // '[data, data + length)' is a valid range. Note that if 'data' is 0, // then 'length' must also be 0. void loadDigestAndReset(unsigned char *result); // Load the current value of this SHA-2 digest into the specified // 'result' and set the value of this SHA-2 digest to the value // provided by the default constructor. // ACCESSORS void loadDigest(unsigned char *result) const; // Load the value of this SHA-2 digest into the specified 'result'. bsl::ostream& print(bsl::ostream& stream) const; // Format the current value of this SHA-2 digest to the specified // output 'stream' and return a reference to the modifiable 'stream'. }; // FREE OPERATORS bool operator==(const Sha224& lhs, const Sha224& rhs); // Return 'true' if the specified 'lhs' and 'rhs' SHA digests have the same // value, and 'false' otherwise. Two digests have the same value if, after // applying any number of equivalent updates to both (possibly including no // updates), the values obtained from their respective 'loadDigest' methods // are identical. inline bool operator!=(const Sha224& lhs, const Sha224& rhs); // Return 'true' if the specified 'lhs' and 'rhs' SHA digests do not have // the same value, and 'false' otherwise. Two digests do not have the same // value if there exists a set of updates (possibly including the empty // set) that, if applied to both, lead to different values being obtained // from their respective 'loadDigest' methods. bool operator==(const Sha256& lhs, const Sha256& rhs); // Return 'true' if the specified 'lhs' and 'rhs' SHA digests have the same // value, and 'false' otherwise. Two digests have the same value if, after // applying any number of equivalent updates to both (possibly including no // updates), the values obtained from their respective 'loadDigest' methods // are identical. inline bool operator!=(const Sha256& lhs, const Sha256& rhs); // Return 'true' if the specified 'lhs' and 'rhs' SHA digests do not have // the same value, and 'false' otherwise. Two digests do not have the same // value if there exists a set of updates (possibly including the empty // set) that, if applied to both, lead to different values being obtained // from their respective 'loadDigest' methods. bool operator==(const Sha384& lhs, const Sha384& rhs); // Return 'true' if the specified 'lhs' and 'rhs' SHA digests have the same // value, and 'false' otherwise. Two digests have the same value if, after // applying any number of equivalent updates to both (possibly including no // updates), the values obtained from their respective 'loadDigest' methods // are identical. inline bool operator!=(const Sha384& lhs, const Sha384& rhs); // Return 'true' if the specified 'lhs' and 'rhs' SHA digests do not have // the same value, and 'false' otherwise. Two digests do not have the same // value if there exists a set of updates (possibly including the empty // set) that, if applied to both, lead to different values being obtained // from their respective 'loadDigest' methods. bool operator==(const Sha512& lhs, const Sha512& rhs); // Return 'true' if the specified 'lhs' and 'rhs' SHA digests have the same // value, and 'false' otherwise. Two digests have the same value if, after // applying any number of equivalent updates to both (possibly including no // updates), the values obtained from their respective 'loadDigest' methods // are identical. inline bool operator!=(const Sha512& lhs, const Sha512& rhs); // Return 'true' if the specified 'lhs' and 'rhs' SHA digests do not have // the same value, and 'false' otherwise. Two digests do not have the same // value if there exists a set of updates (possibly including the empty // set) that, if applied to both, lead to different values being obtained // from their respective 'loadDigest' methods. inline bsl::ostream& operator<<(bsl::ostream& stream, const Sha224& digest); // Write to the specified output 'stream' the specified SHA-2 'digest' and // return a reference to the modifiable 'stream'. inline bsl::ostream& operator<<(bsl::ostream& stream, const Sha256& digest); // Write to the specified output 'stream' the specified SHA-2 'digest' and // return a reference to the modifiable 'stream'. inline bsl::ostream& operator<<(bsl::ostream& stream, const Sha384& digest); // Write to the specified output 'stream' the specified SHA-2 'digest' and // return a reference to the modifiable 'stream'. inline bsl::ostream& operator<<(bsl::ostream& stream, const Sha512& digest); // Write to the specified output 'stream' the specified SHA-2 'digest' and // return a reference to the modifiable 'stream'. // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ } // close package namespace // ------------ // class Sha224 // ------------ // FREE OPERATORS inline bool bdlde::operator!=(const Sha224& lhs, const Sha224& rhs) { return !(lhs == rhs); } inline bsl::ostream& bdlde::operator<<(bsl::ostream& stream, const Sha224& digest) { return digest.print(stream); } // ------------ // class Sha256 // ------------ // FREE OPERATORS inline bool bdlde::operator!=(const Sha256& lhs, const Sha256& rhs) { return !(lhs == rhs); } inline bsl::ostream& bdlde::operator<<(bsl::ostream& stream, const Sha256& digest) { return digest.print(stream); } // ------------ // class Sha384 // ------------ inline bsl::ostream& bdlde::operator<<(bsl::ostream& stream, const Sha384& digest) { return digest.print(stream); } // FREE OPERATORS inline bool bdlde::operator!=(const Sha384& lhs, const Sha384& rhs) { return !(lhs == rhs); } // ------------ // class Sha512 // ------------ // FREE OPERATORS inline bool bdlde::operator!=(const Sha512& lhs, const Sha512& rhs) { return !(lhs == rhs); } inline bsl::ostream& bdlde::operator<<(bsl::ostream& stream, const Sha512& digest) { return digest.print(stream); } } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2018 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------