// bdlde_sha1.h -*-C++-*- #ifndef INCLUDED_BDLDE_SHA1 #define INCLUDED_BDLDE_SHA1 #include <bsls_ident.h> BSLS_IDENT("$Id$ $CSID$") //@PURPOSE: Provide a value-semantic type encoding a message in a SHA-1 digest. // //@CLASSES: // bdlde::Sha1: value-semantic type representing a SHA-1 digest // //@SEE_ALSO: bdlde_md5, bdlde_sha2 // //@DESCRIPTION: This component provides the class 'bdlde::Sha1', which // implements a mechanism for computing and updating a SHA-1 digest (a // cryptographic hash). The specification for this is based on FIPS-180, which // can be found at //.. // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf //.. // // Note that a SHA-1 digest does not aid in error correction. // ///Security ///-------- // Practical collision and chosen-prefix collision attacks are known against // SHA-1. Do not use SHA-1 to generate digital signatures under any // circumstances, and do not use SHA-1 at all except when it is required for // interoperation with legacy systems that use SHA-1. SHA-2 (available in the // 'bdlde_sha2' component) and SHA-3 are more secure alternatives to SHA-1. // // You might think that your application doesn't require collision resistance. // However, (1) you might be mistaken, (2) once you start using SHA-1, you // prevent future versions of your application from being able to rely on // collision resistance unless they break backward compatibility, (3) a // maintainer of your application might accidentally make a change that // implicitly assumes collision resistance, and (4) if you expose SHA-1 hashes // to your users, they might assume that they are secure digital signatures, // which will make their applications insecure. In light of the foregoing // considerations, and the availability of SHA-2 and SHA-3 as alternatives, // there is no justification for using SHA-1 unless you absolutely have to. // ///Usage ///----- // This section illustrates intended use 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. Also note that because SHA-1 // digests are inexpensive to compute, they are vulnerable to brute force // attacks and should not be used for password hashing in real-world // applications. A function like 'validatePassword' must only be used to // validate passwords against previously computed SHA-1 hashes, and only during // a transition period to a more secure password hashing function. //.. // bool validatePassword(const bsl::string_view& password, // const bsl::string_view& salt, // const unsigned char *expected) // // Return 'true' if the specified 'password' concatenated with the // // specified 'salt' has a SHA-1 hash equal to the specified 'expected', // // and 'false' otherwise. // { // bdlde::Sha1 hasher; // hasher.update(password.data(), password.length()); // hasher.update(salt.data(), salt.length()); // // unsigned char digest[bdlde::Sha1::k_DIGEST_SIZE]; // hasher.loadDigest(digest); // return bsl::equal(bsl::begin(digest), bsl::end(digest), 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::Sha1::k_DIGEST_SIZE] = { // 0x5B, 0xAA, 0x61, 0xE4, 0xC9, 0xB9, 0x3F, 0x3F, 0x06, 0x82, // 0x25, 0x0B, 0x6C, 0xF8, 0x33, 0x1B, 0x7E, 0xE6, 0x8F, 0xD8 // }; // // 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 Sha1 // ========== class Sha1 { // This 'class' represents a SHA-1 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. // PRIVATE TYPES typedef bsl::uint32_t Word; // Alias for the word type of the SHA-1 algorithm. typedef Word State[5]; // Alias for the internal state type of the SHA-1 algorithm, an array // of 5 words that is updated after each message block is ingested and // eventually converted into the 160-bit message digest. // CLASS DATA static const bsl::size_t k_BLOCK_SIZE = 512 / 8; // Size (in bytes) of the blocks into which the message is divided // before being ingested into the SHA-1 state. // DATA bsl::uint64_t d_totalSize; // length of the entire message in bytes bsl::uint64_t d_bufferSize; // bytes currently used for 'd_buffer' unsigned char d_buffer[k_BLOCK_SIZE]; // buffer for storing remaining part of message that is not yet // incorporated into 'd_state' State d_state; // current state of the SHA-1 algorithm // instance represented by this 'Sha1' object // FRIENDS friend bool operator==(const Sha1&, const Sha1&); public: // PUBLIC CLASS DATA static const bsl::size_t k_DIGEST_SIZE = 160 / 8; // The size (in bytes) of the output // CREATORS Sha1(); // Construct a SHA-1 digest having the value corresponding to no data // having been provided. Sha1(const void *data, bsl::size_t length); // Construct a SHA-1 digest corresponding to the specified 'data' // having the specified 'length' (in bytes). Note that if 'data' is // null, then 'length' must be 0. // MANIPULATORS void loadDigestAndReset(unsigned char *result); // Load the current value of this SHA-1 digest into the specified // 'result' and reset this 'Sha1' object to the default-constructed // state. void reset(); // Reset the value of this SHA-1 digest to the value provided by the // default constructor. void update(const void *data, bsl::size_t length); // Update the value of this SHA-1 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-1 // digest is the application of the SHA-1 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-1 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 // null, then 'length' must be 0. // ACCESSORS void loadDigest(unsigned char *result) const; // Load the current value of this SHA-1 digest into the specified // 'result'. bsl::ostream& print(bsl::ostream& stream) const; // Format the current value of this SHA-1 digest to the specified // output 'stream' and return a reference to the modifiable 'stream'. }; // FREE OPERATORS bool operator==(const Sha1& lhs, const Sha1& rhs); // Return 'true' if the specified 'lhs' and 'rhs' SHA-1 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 Sha1& lhs, const Sha1& rhs); // Return 'true' if the specified 'lhs' and 'rhs' SHA-1 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 Sha1& digest); // Write to the specified output 'stream' the specified SHA-1 'digest' and // return a reference to the modifiable 'stream'. // ============================================================================ // INLINE DEFINITIONS // ============================================================================ } // close package namespace // FREE OPERATORS inline bool bdlde::operator!=(const Sha1& lhs, const Sha1& rhs) { return !(lhs == rhs); } inline bsl::ostream& bdlde::operator<<(bsl::ostream& stream, const Sha1& digest) { return digest.print(stream); } } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2022 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 ----------------------------------