How to portably compute a sha1 hash in C++? - c++

The objective is to compute the SHA1 hash of a buffer or multiple buffers as part of a C++ program.

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);
}

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)

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.

OpenSSL library is portable, efficient, implements SHA1 support among other useful features. Available on most platforms...
https://www.openssl.org/docs/crypto/sha.html

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

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})

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.

Related

Crypto++ : Hash generation hangs on windows 10

I have the following simple program :
#include <cryptlib.h>
#include "sha.h"
#include <sha3.h>
#include <filters.h>
#include <hex.h>
#include <beast/core/detail/base64.hpp>
using namespace CryptoPP;
using namespace boost::beast::detail::base64;
int main(int argc, char** argv) {
if (argc < 2) {
std::cout << "missing argument 1 : password";
return 0;
}
std::string password = std::string(argv[1]);
byte digest[SHA3_256::DIGESTSIZE];
SHA3 digestAlgo = SHA3_256();
std::cout << "going to calculate the digest\n";
digestAlgo.Update((const byte*) password.data(), password.size());
std::cout << "updated...\n";
digestAlgo.Final(digest);
std::cout << "calculated the digest\n";
char* b64encodedHash = (char*)malloc(sizeof(byte)*1000);
encode(b64encodedHash, digest, sizeof(byte)*1000);
std::cout << "password hashed : " << b64encodedHash << "\n";
return 1;
}
When I run it the text : "going to calculate the digest" is output on the command line and the program does not continue. It hangs.
Does anyone know why ? I am trying to follow the examples on the Crypto++ wiki, and this is very similar to theirs.
After the Final call I want to base64 encode the digest, you can remove that part, it uses a boost header file.
Thanks,
Regards
Change the line
SHA3 digestAlgo = SHA3_256();
to
SHA3_256 digestAlgo;

C++ find all files of type in folder?

I am trying to list all the files of a certain type in a folder, so that I can loop through them. This should be simple, surely, but I can't get it.
I have found some example using dirent.h, but I need to do this in straight c++.
What is the best way to go about this?
Thanks.
You cannot do this in "straight C++", because C++ does not have a filesystem API yet.
I'd traditionally recommend Boost.Filesystem here, but you allegedly want to "avoid using third party headers if [you] can".
So your best bet is to use POSIX dirent.h, as you have been doing all along. It's about as "non-third party" as you're going to get for the time being.
Something like this? This finds all suid files in folders you specify, but can be modified to find any number of things, or use a regex for the extension if that is what you mean by 'type'.
#include <sys/stat.h>
#include <sys/types.h>
#include <iostream>
#include <string>
#include <sstream>
#include <dirent.h>
#include <vector>
bool is_suid(const char *file)
{
struct stat results;
stat(file, &results);
if (results.st_mode & S_ISUID) return true;
return false;
}
void help_me(char *me) {
std::cout
<< "Usage:" << std::endl
<< " " << me << " /bin/ /usr/sbin/ /usr/bin/ /usr/bin/libexec/" << std::endl;
exit(1);
}
int main(int argc, char **argv)
{
if (argc < 2) help_me(argv[0]);
std::string file_str;
std::vector<std::string> file_list;
for (int path_num = 1; path_num != argc; path_num++) {
const char * path = argv[path_num];
DIR *the_dir;
struct dirent *this_dir;
the_dir = opendir(path);
if (the_dir != NULL) while (this_dir = readdir(the_dir)) file_list.push_back(std::string(this_dir->d_name));
std::string name;
for(int file_num = 0; file_num != file_list.size(); file_num++) {
name = file_list[file_num];
std::string path_to_file = std::string(path) + file_list[file_num];
if (is_suid(path_to_file.c_str()) == true) std::cout << path_to_file << std::endl;
}
file_list.clear();
file_list.shrink_to_fit();
}
exit(0);
}

Store lines from a text file in a list of strings

I've been trying to store the lines of a text file in a list in C++. Better, I've been trying to store each word of each line of the text file in a string that is part of a list of strings, but it seems that I'm doing it in the wrong way.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <list>
using namespace std;
int main()
{
FILE *f= fopen("teste.txt", "r");
size_t len= 100; // valor arbitrário
char *line= (char*)malloc(len);
std::list<string> mylist;
if (!f)
{
perror("teste.txt");
exit(1);
}
while (getline(&line, &len, f) > 0)
{ //THE REAL PROBLEM
for (std::list<string>::iterator it = mylist.begin(); it != mylist.end(); it++){
*it=line;
cout << *it << '\n';
}
}
if (line)
free(line);
fclose(f);
return 0;
}
The exact problem is that this doesn't give any result. It compiles but nothing results from this.
Thanks in advance.
Change your while loop as follows:
while (getline(&line, &len, f) > 0)
{
mylist.push_back(line);
cout << mylist.back() << '\n';
}
You cannot access any non initialized items from a std::list<>.
Also NOTE you should make line a std::string, and omit the malloc() / free() calls from your code.
2nd NOTE: Use std::ifstream instead of FILE* for an input file stream.
Here's the fully fixed (no more errors/exceptions on ideone) code sample:
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <exception>
#include <errno.h>
#include <stdlib.h>
int main()
{
try
{
std::ifstream f("teste.txt");
if(!f)
{
std::cerr << "ERROR: Cannot open 'teste.txt'!" << std::endl;
exit(1);
}
std::string line;
std::list<std::string> mylist;
while (std::getline(f,line))
{
mylist.push_back(line);
std::cout << mylist.back() << std::endl;
}
}
catch(const std::exception& ex)
{
std::cerr << "Exception: '" << ex.what() << "'!" << std::endl;
exit(1);
}
exit(0);
}
You can not assign a char* value to std::string by using '=' operator.
Change
*it=line to
it->assign(line,line+strlen(line);

Pipes boost::iostreams don't have any output

I'm trying using pipes with boost libraries, I just want to execute a background program(e.g.: ls) and get it's output in a string(like you can do with fopen and fread), but I really can't get why I have no output with this code:
#include <iostream>
#include <cstdio>
#include <sstream>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
int
main(int argc, char** argv)
{
using namespace boost::iostreams;
if(argc < 2) {
return -1;
}
FILE* p = popen(argv[1], "r");
if(! p) {
std::cerr << "error open pipe" << std::endl;
return -2;
}
int fd = fileno(p);
std::stringstream ss;
ss << fd;
std::string s = ss.str();
file_descriptor_source pdesc(s);
stream_buffer<file_descriptor_source> pstream(pdesc);
std::istream is(&pstream);
std::string out;
while(is) {
std::getline(is, out);
std::cout << out << std::endl;
}
pstream.close();
pdesc.close();
pclose(p);
return 0;
}
Thanks in advance.
It seems you are trying to open a boost::file_descriptor_source from a "path" which contains the file descriptor number. However, a file of this name probably doesn't exist. What you probably meant to use is something like this:
if (FILE* p = popen(argv[1], "r"))
{
boost::iostreams::file_descriptor_source d(fileno(p), boost::iostreams::close_handle);
boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_source> pstream(d);
std::cout << &pstream;
pclose(p);
}

POSIX Program to search entire file system for a file

Hey everyone. I need to write a POSIX program to search through an entire file system for a specified file starting at the top directory. I've got some code which isn't done at all, but when I run it, and check to see if a particular file is a directory, it's saying this file which is not at all a directory is a directory and is trying to move into it, causing an error. I'm not sure how I can tell it that this type of file isn't a directory.
Here's my code. I know it's not perfect and I could probably do some things differently in the way of getting the directory names and passing them into the function. Either way, I'm pretty sure I have to do this recursively.
The file in question is /dev/dri/card0 and I'm running this from a Debian virtual machine.
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <time.h>
#include <stdint.h>
#include <locale.h>
#include <langinfo.h>
#include <fcntl.h>
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
void SearchDirectory(string file_Name, string directory){
string new_Directory = directory;
DIR *dirp;
dirp = opendir(directory.c_str());
struct dirent *dptr;
struct stat statStruct;
while(dptr = readdir(dirp)){
stat(dptr->d_name, &statStruct);
if( S_ISDIR(statStruct.st_mode) ){
string check = dptr->d_name;
if ( check.compare(".") == 0 || check.compare("..") == 0 ){
continue;
}
else{
cout << dptr->d_name << " is is a directory" << endl;
new_Directory.append("/");
new_Directory.append(dptr->d_name);
SearchDirectory(file_Name, new_Directory);
}
}
else if( S_ISREG(statStruct.st_mode)){
string check = dptr->d_name;
if( check.compare(file_Name) == 0){
cout << "Found " << file_Name << " in " << directory << "/" << endl;
}
}
}
}
int main(int argc, char *argv[]){
if(argc < 2 || argc > 2){
cerr << "This program will find the specified file." << endl;
cerr << "Usage: mysearch <filename>" << endl;
return 1;
}
string file_Name = argv[1];
SearchDirectory(file_Name, "/");
return 0;
}
POSIX.2 requires a working "find" command.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <filename>", argv[0]);
}
execlp("find", "find", "/", "-name", argv[1], "-print", (char *)NULL);
exit(EXIT_FAILURE);
}
->d_name returns just the name of the file, not the path to the file. You need to stat (not yet constructed) new_Directory instead of dptr->d_name.
You also have a problem if a directory contains more than one subdirectories. Your construction of new_Directory is incorrect for each subdirectory after the first.
You never closedir your directory handle, so you run out of resources. You should also consider loading the entire directory into an array before recursing to avoid running out of handles.
void SearchDirectory(string directory, string target_File_Name){
DIR *dirp = opendir(directory.c_str());
if (!dirp) {
perror(("opendir " + directory).c_str());
return;
}
struct dirent *dptr;
while(dptr = readdir(dirp)){
string file_Name = dptr->d_name;
string file_Path = directory + "/" + file_Name;
struct stat statStruct;
stat(file_Path.c_str(), &statStruct);
if( S_ISDIR(statStruct.st_mode) ){
if ( file_Name.compare(".") == 0 || file_Name.compare("..") == 0 ){
continue;
}
SearchDirectory(file_Path, target_File_Name);
}
else if( S_ISREG(statStruct.st_mode)){
if( file_Name.compare(target_File_Name) == 0){
cout << file_Path << endl;
}
}
}
closedir(dirp);
}
Update: Added second problem.
Update: Added third problem.
Update: Added code.
Not for the benefit of the OP, who writes "The point is to come up with a way to do it myself," but rather for the benefit of posterity, here is a way to use Boost.Filesystem:
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
// sample usage: find_file("/home", ".profile");
void find_file( const fs::path& dirPath, const std::string& fileName) {
fs::recursive_directory_iterator end;
for(fs::recursive_directory_iterator it(dirPath); it != end; ++it) {
if(it->leaf() == fileName)
std::cout << it->path() << "\n";
if(fs::is_symlink(it->symlink_status()))
it.no_push();
}
}
Use fork, execv and the Unix implemented /usr/bin/find process and redirect its output for your result area?
I'm not sure if it's POSIX or not but the nftw library function is widely available on UNIX (HP-UX, AIX, Linux).
Your problem is "search a tree for a match"
BFS and DFS are the canonical basic algorithms. Give them a start node and go.
You will get into trouble if you follow symlinks; so test for them and don't follow them.
You should be able to map each point in the *FS algorithms to a directory operation.
Since C++ is an option, why not use something like Boost.Filesystem? The Boost.Filesystem two-minute tutorial gives an example of how to implement your search using directory iterators.