SHA
Documentation |
#include <cryptopp/sha.h>
|
SHA is the Secure Hash Standard and specified in FIPS 180-4. The standard provides SHA1, but it is now considered insecure for many applications. Crypto++ provides all hashes from FIPS 180-4.
The security level of SHA-1 has been reduced to approximately 260. The best publicly available cryptanalysis result is a 2011 attack by Marc Stevens that can produce hash collisions with a complexity of 261 operations. Also see hashclash - Framework for MD5 & SHA-1 Differential Path Construction and Chosen-Prefix Collisions.
In 2019 new attacks reduced complexity of chosen-prefix collisions to 261. The new attacks are economical for academia and effectively puts all CA intermediate certificates using SHA-1 at risk. Also see SHA-1 is a Shambles: First Chosen-Prefix Collision on SHA-1 and Application to the PGP Web of Trust.
SHA-1 is no longer recommended by NIST for use in digital signatures in the Federal arena. See SP 800-57, Recommendation for Key Management, Table 3 on page 64. You should use the SHA-2 or SHA-3, instead.
All Crypto++ hashes derive from HashTransformation
. The base class provides functions like Update
, Final
and Verify
. You can swap-in any hash for any other hash in your program. You can also use ChannelSwitch
to send data to multiple hashes at the same time.
Sample Programs
There are five sample programs. The first prints information about the hash. The second creates a hash using SHA1 class. The third creates a hash using a pipeline. The fourth and filth examples show how to verify an existing digest.
The examples below use SHA1, but you can swap-in any hash function, like PanamaHash or SM3.
The first example dumps the name, digest size and internal block size of the hash.
#include "cryptlib.h" #include "sha.h" #include <iostream> int main (int argc, char* argv[]) { using namespace CryptoPP; SHA1 hash; std::cout << "Name: " << hash.AlgorithmName() << std::endl; std::cout << "Digest size: " << hash.DigestSize() << std::endl; std::cout << "Block size: " << hash.BlockSize() << std::endl; return 0; }
Running the program results in the following. In general you should use DigestSize
and avoid BlockSize
. BlockSize
is usually not required by a program.
$ ./test.exe Name: SHA-1 Digest size: 20 Block size: 64
The second example creates a hash using the hash object and member functions. You add data using Update
and you calculate the hash using Final
. Calling Final
resets the hash so you don't need to do it manually.
using namespace CryptoPP; HexEncoder encoder(new FileSink(std::cout)); std::string msg = "Yoda said, Do or do not. There is no try."; std::string digest; SHA1 hash; hash.Update((const byte*)msg.data(), msg.size()); digest.resize(hash.DigestSize()); hash.Final((byte*)&digest[0]); std::cout << "Message: " << msg << std::endl; std::cout << "Digest: "; StringSource(digest, true, new Redirector(encoder)); std::cout << std::endl;
Running the program results in the following.
$ ./test.exe Message: Yoda said, Do or do not. There is no try. Digest: 05C0042DF9A7793B7BDE3AB9724C08CF37398652
You can also obtain a truncated hash rather than the full hash using TruncatedFinal
.
std::cout << "Message: " << msg << std::endl; hash.Update((const byte*)msg.data(), msg.size()); digest.resize(hash.DigestSize()/2); hash.TruncatedFinal((byte*)&digest[0], digest.size()); std::cout << "Digest: "; StringSource(digest, true, new Redirector(encoder)); std::cout << std::endl;
The program produces the following result.
$ ./test.exe Message: Yoda said, Do or do not. There is no try. Digest: 05C0042DF9A7793B7BDE
Using a pipeline produces the same result. It relieves you of calling Update
and Final manually. The code also uses a HashFilter
, which has its own wiki page at HashFilter.
std::string msg = "Yoda said, Do or do not. There is no try."; std::string digest; StringSource(msg, true, new HashFilter(hash, new StringSink(digest))); std::cout << "Message: " << msg << std::endl; std::cout << "Digest: "; StringSource(digest, true, new Redirector(encoder)); std::cout << std::endl;
Running the program results in the following.
$ ./test.exe Message: Yoda said, Do or do not. There is no try. Digest: 05C0042DF9A7793B7BDE3AB9724C08CF37398652
The fourth program verifies an existing hash using the hash object. Notice the program proceeds as if the hash is going to be calculated. But rather than calling Final
to retrieve the hash, Verify
is called to verify the existing hash.
SHA1 hash; hash.Update((const byte*)msg.data(), msg.size()); bool verified = hash.Verify((const byte*)digest.data()); if (verified == true) std::cout << "Verified hash over message" << std::endl; else std::cout << "Failed to verify hash over message" << std::endl;
The final program verifies an existing hash using a pipeline. The code uses a HashVerificationFilter
, which has its own wiki page at HashVerificationFilter.
bool result; StringSource(digest+msg, true, new HashVerificationFilter(hash, new ArraySink((byte*)&result, sizeof(result)))); if (result == true) std::cout << "Verified hash over message" << std::endl; else std::cout << "Failed to verify hash over message" << std::endl;
Running the program results in the following output.
$ ./test.exe Message: Yoda said, Do or do not. There is no try. Digest: 05C0042DF9A7793B7BDE3AB9724C08CF37398652 Verified hash over message
Downloads
No downloads available.