The objective is to compute the SHA1 hash of a buffer or multiple buffers as part of a C++ program.
-
2You need to ask the specific question you have. Stating your task isn't a real question. That's why you're getting down votes and close votes. – David Schwartz Feb 13 '15 at 01:02
-
@DavidSchwartz The more _specific question_ might turn out, to ask for 3rd party resource outside SO. Marked to close for this reason already. – πάντα ῥεῖ Feb 13 '15 at 02:14
-
@DavidSchwartz, huch, the very specific question is in the title, isn't it? Do you mean that I should delete the requirements block? I just added it to make it even more specific. I really don't see the qualitative difference of my question to - say - http://stackoverflow.com/questions/34490/how-do-i-create-a-sha1-hash-in-ruby ... – maxschlepzig Feb 13 '15 at 07:52
-
That's not a specific question at all. That's an assignment. It's not even clear if you're looking for help writing code, someone to write code, or someone to point you to existing code. If anything but the latter, it's not a question. If the latter, it's something that can be trivially answered with a search engine. – David Schwartz Feb 13 '15 at 09:01
-
3I had the same question. I used a search engine. It brought me here. I got my answer. I don't understand what's wrong with that. – bluedog Jul 08 '17 at 22:58
7 Answers
I'm not sure whether the one using boost's UUID will do leading zeros in hash values correctly (your string should always have the same length afaik), so here's a simplified version of the example above which will do that:
#include <cstdio>
#include <string>
#include <boost/uuid/sha1.hpp>
std::string get_sha1(const std::string& p_arg)
{
boost::uuids::detail::sha1 sha1;
sha1.process_bytes(p_arg.data(), p_arg.size());
unsigned hash[5] = {0};
sha1.get_digest(hash);
// Back to string
char buf[41] = {0};
for (int i = 0; i < 5; i++)
{
std::sprintf(buf + (i << 3), "%08x", hash[i]);
}
return std::string(buf);
}

- 421
- 4
- 6
-
You mean that you aren't sure if the boost hex algorithm prints leading zeros? This [minimal example shows that it does](https://gist.github.com/gsauthof/a5794849d6faadf80ed4a6b2d920e3e3). Btw, your sprintf approach doesn't yield the same result on little-endian architectures. That means if you use sprinf like this you must not byte swap. The other version swaps bytes because the hex algorithm iterates byte-wise over the 4 byte integer. – maxschlepzig Oct 03 '16 at 20:00
-
Yes, you're right, I remove the bswap32() call, thanks. Yields now the same as hashlib.sha1(str).hexdigest() of Python does. – Flo Oct 08 '16 at 16:31
-
It turns out that Boost has gained a more high-level API for SHA1 hashing strings which allows for more concise code: https://stackoverflow.com/a/28489154/427158 – maxschlepzig Dec 21 '21 at 12:10
The Qt library contains since version 4.3 the class QCryptographicHash that supports various hashing algorithms, including SHA1. Although Qt is arguably less portable than - say - OpenSSL, at least for projects that already depend on Qt QCryptographicHash is the obvious way to compute a SHA1 hash.
Example program that computes the SHA1 hash of a file:
#include <QCryptographicHash>
#include <QByteArray>
#include <QFile>
#include <iostream>
#include <stdexcept>
using namespace std;
int main(int argc, char **argv)
{
try {
if (argc < 2)
throw runtime_error(string("Call: ") + *argv + string(" FILE"));
const char *filename = argv[1];
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Unbuffered))
throw runtime_error("Could not open: " + string(filename));
QCryptographicHash hash(QCryptographicHash::Sha1);
vector<char> v(128*1024);
for (;;) {
qint64 n = file.read(v.data(), v.size());
if (!n)
break;
if (n == -1)
throw runtime_error("Read error");
hash.addData(v.data(), n);
}
QByteArray h(hash.result().toHex());
cout << h.data() << '\n';
} catch (const exception &e) {
cerr << "Error: " << e.what() << '\n';
return 1;
}
return 0;
}
The used Qt classes are all part of Qt core library. An example cmake build file:
cmake_minimum_required(VERSION 2.8.11)
project(hash_qt CXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
find_package(Qt5Core)
add_executable(hash_qt hash_qt.cc)
target_link_libraries(hash_qt Qt5::Core)

- 35,645
- 14
- 145
- 182
Boost provides a simple API for computing the SHA1 hash of strings:
#include <iostream>
#include <string>
#include <boost/compute/detail/sha1.hpp>
int main(int argc, char **argv)
{
if (argc < 2) {
std::cerr << "Call: " << *argv << " STR\n";
return 1;
}
boost::compute::detail::sha1 sha1 { argv[1] };
std::string s { sha1 };
std::cout << s << '\n';
return 0;
}
That API is private to the Boost Compute library, though, because it's part of a detail namespace. Meaning that it doesn't have any stability guarantees.
Boost also provides a SHA1 hashing class as part of the Boost Uuid Library, whose API is better suited for hashing arbitrary binary input, such as files. Although it is part of the detail namespace, meaning that it is kind of library-private, it is there for many years and stable.
A small example that computes the SHA1 hash of a file and prints it to stdout:
Prelude:
#include <boost/uuid/detail/sha1.hpp>
#include <boost/predef/other/endian.h>
#include <boost/endian/conversion.hpp>
#include <boost/algorithm/hex.hpp>
#include <boost/range/iterator_range_core.hpp>
#include <iostream>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
using namespace std;
The main function:
{
if (argc < 2) { cerr << "Call: " << *argv << " FILE\n"; return 1; }
const char *filename = argv[1];
int fd = open(filename, O_RDONLY);
if (fd == -1) { cerr << "open: " << strerror(errno) << ")\n"; return 1; }
vector<char> v(128*1024);
boost::uuids::detail::sha1 sha1;
for (;;) {
ssize_t n = read(fd, v.data(), v.size());
if (n == -1) {
if (errno == EINTR) continue;
cerr << "read error: " << strerror(errno) << '\n';
return 1;
}
if (!n) break;
sha1.process_bytes(v.data(), n);
}
boost::uuids::detail::sha1::digest_type hash;
sha1.get_digest(hash);
#ifdef BOOST_ENDIAN_BIG_BYTE
for (unsigned i = 0; i < sizeof hash / sizeof hash[0]; ++i)
boost::endian::endian_reverse_inplace(hash[i]);
#endif
boost::algorithm::hex(boost::make_iterator_range(
reinterpret_cast<const char*>(hash),
reinterpret_cast<const char*>(hash) + sizeof hash),
std::ostream_iterator<char>(cout)); cout << '\n';
int r = close(fd);
if (r == -1) { cerr << "close error: " << strerror(errno) << '\n';
return 1; }
return 0;
}
The used parts of Boost don't create dependencies on any boost shared library. Since Boost is quite portable and available for various architectures, using Boost for computing SHA1 hashes is quite portable as well.

- 35,645
- 14
- 145
- 182
OpenSSL library is portable, efficient, implements SHA1 support among other useful features. Available on most platforms...

- 5,125
- 2
- 16
- 18
The OpenSSL library contains an API to different hashing methods and is very portable and readily available on many systems.
An C++ example that uses the recommended EVP API of OpenSSL to compute the SHA1 hash of a file:
int main(int argc, char **argv)
{
try {
if (argc < 2) throw runtime_error(string("Call: ") + *argv
+ string(" FILE"));
const char *filename = argv[1];
int fd = open(filename, O_RDONLY);
if (fd == -1) throw runtime_error("Could not open " + string(filename)
+ " (" + string(strerror(errno)) + ")");
BOOST_SCOPE_EXIT(&fd) { close(fd); } BOOST_SCOPE_EXIT_END
const EVP_MD *md = EVP_sha1();
if (!md) throw logic_error("Couldn't get SHA1 md");
unique_ptr<EVP_MD_CTX, void (*)(EVP_MD_CTX*)> md_ctx(EVP_MD_CTX_create(),
EVP_MD_CTX_destroy);
if (!md_ctx) throw logic_error("Couldn't create md context");
int r = EVP_DigestInit_ex(md_ctx.get(), md, 0);
if (!r) throw logic_error("Could not init digest");
vector<char> v(128*1024);
for (;;) {
ssize_t n = read(fd, v.data(), v.size());
if (n == -1) {
if (errno == EINTR)
continue;
throw runtime_error(string("read error: ") + strerror(errno));
}
if (!n)
break;
int r = EVP_DigestUpdate(md_ctx.get(), v.data(), n);
if (!r) throw logic_error("Digest update failed");
}
array<unsigned char, EVP_MAX_MD_SIZE> hash;
unsigned int n = 0;
r = EVP_DigestFinal_ex(md_ctx.get(), hash.data(), &n);
if (!r) throw logic_error("Could not finalize digest");
boost::algorithm::hex(boost::make_iterator_range(
reinterpret_cast<const char*>(hash.data()),
reinterpret_cast<const char*>(hash.data()+n)),
std::ostream_iterator<char>(cout));
cout << '\n';
} catch (const exception &e) {
cerr << "Error: " << e.what() << '\n';
return 1;
}
return 0;
}
The prelude of the example:
#include <openssl/evp.h>
#include <boost/algorithm/hex.hpp>
#include <boost/range/iterator_range_core.hpp>
#include <boost/scope_exit.hpp>
#include <iostream>
#include <vector>
#include <array>
#include <memory>
#include <string>
#include <stdexcept>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
using namespace std;
For the EVP API, the program must be linked against libcrypto, e.g.:
g++ -g -std=c++11 sha1_example.cc -lcrypto

- 35,645
- 14
- 145
- 182
The Botan library implements 'a kitchen sink' of cryptographic algorithms, including SHA1 (of course). It is portable between various systems that provide a recent C++ compiler.
Computing a SHA1 hash value and obtaining it as hexadecimal string is straight forward using Botan's high-level stream-like C++ API for constructing pipes.
Example for computing the SHA1 hash of a file:
#include <botan/pipe.h>
#include <botan/basefilt.h>
#include <botan/filters.h>
#include <botan/data_snk.h>
using namespace Botan;
#include <fstream>
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
try {
if (argc < 2)
throw runtime_error(string("Call: ") + *argv + string(" FILE"));
const char *filename = argv[1];
ifstream in(filename, ios::binary);
in.exceptions(ifstream::badbit);
Pipe pipe(new Chain(new Hash_Filter("SHA-1"),
new Hex_Encoder(Hex_Encoder::Lowercase)),
new DataSink_Stream(cout));
pipe.start_msg();
in >> pipe;
pipe.end_msg();
} catch (const exception &e) {
cerr << "Error: " << e.what() << '\n';
return 1;
}
return 0;
}
When the hash value should be processed as string, an ostringstream
(instead of cout) can be used as data sink stream.
Depending on the target system/distribution, the headerfiles might be placed at a slightly unusual location and the library might contain a slightly unexpected suffix (e.g. on Fedora 21). Following cmake snippet accounts for that:
cmake_minimum_required(VERSION 2.8.11)
project(hash CXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
find_library(LIB_BOTAN NAMES botan botan-1.10)
find_path(HEADER_BOTAN NAMES botan/pipe.h PATH_SUFFIXES botan-1.10)
add_executable(hash_botan hash_botan.cc)
set_property(TARGET hash_botan PROPERTY INCLUDE_DIRECTORIES ${HEADER_BOTAN})
target_link_libraries(hash_botan ${LIB_BOTAN})

- 35,645
- 14
- 145
- 182
The Crypto++ library is a portable C++ library that includes several cryptographic algorithms, including several hashing algorithms like SHA1.
The API provides various source and sink classes, where a bunch of transformations can be attached in between.
An example for computing the SHA1 hash of a file:
#include <cryptopp/files.h>
#include <cryptopp/filters.h>
#include <cryptopp/hex.h>
#include <cryptopp/sha.h>
using namespace CryptoPP;
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
try {
if (argc < 2)
throw runtime_error(string("Call: ") + *argv + string(" FILE"));
const char *filename = argv[1];
SHA1 sha1;
FileSource source(filename, true,
new HashFilter(sha1,
new HexEncoder(new FileSink(cout), false, 0, ""),
false)
);
} catch (const exception &e) {
cerr << "Error: " << e.what() << '\n';
return 1;
}
return 0;
}
It can be compiled via e.g.: g++ -Wall -g -std=c++11 hash_cryptopp.cc -lcryptopp
Crypto++ 'pumps' the content from the source through several attached transformations into the the sink. Instead of the FileSink
other sinks are available, e.g. StringSinkTemplate
for writing directly into a string object.
The attached objects are reference counted, such that they are automatically destructed on scope exit.

- 35,645
- 14
- 145
- 182