c++hashsha1

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


In a C++ program, I need to compute the SHA1 hash of a buffer or multiple buffers.

The program is portable, i.e. it compiles and runs on various operating systems, such as Linux, Unix-like OS and Windows. Thus, the sha1 computation should be as portable, as well.

I prefer to use an existing (portable) common open source library for the sha1 computation, such as Boost, Qt or a widely available crypto library, for the sha1 computation to avoid re-inventing the wheel, code duplication/bloat.


Solution

  • You can use the Boost Hash2 header-only library to compute the SHA1 hash of a buffer or a sequence of buffers, in a portable fashion.

    Hash2 is part of Boost since version 1.88 which was released in April, 2025.

    Example that computes the sha1 hash of a buffer:

    #include <boost/hash2/sha1.hpp>
    
    #include <string>
    #include <stdio.h>
    #include <string.h>
    
    static std::string buffer_sha1(const char *b , size_t n)
    {
        boost::hash2::sha1_160 h;
        h.update(b, n);
        return boost::hash2::to_string(h.result());
    }
    
    int main(int argc, char **argv)
    {
        auto r = buffer_sha1(argv[1], strlen(argv[1]));
        puts(r.c_str());
        return 0;
    }
    

    On Linux, you can verify the result of ./a.out fubar with echo -n fubar | sha1sum.


    In order to compute the sha1 hash of a sequence of buffers one has to invoke the update() method of the hash object multiple time like this:

    #include <boost/hash2/sha1.hpp>
    #include <string>
    #include <stdexcept>
    #include <array>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <string.h>
    
    static std::string file_sha1(const char *filename)
    {
        boost::hash2::sha1_160 h;
        int fd = open(filename, O_RDONLY);
        if (fd == -1)
                throw std::runtime_error(strerror(errno));
        std::array<unsigned char, 256 * 1024> b;
        for (;;) {
            ssize_t n = read(fd, b.data(), b.size());
            if (n == -1) {
                if (errno == EINTR)
                    continue;
                close(fd);
                throw std::runtime_error(strerror(errno));
            }
            if (!n)
                break;
            h.update(b.data(), n);
        }
        close(fd);
        return boost::hash2::to_string(h.result());
    }
    
    
    int main(int argc, char **argv)
    {
        for (int i=1; i<argc; ++i) {
            const char *filename = argv[i];
            auto r = file_sha1(filename);
            printf("%s  %s\n", r.c_str(), filename);
        }
        return 0;
    }
    

    On Linux, you can compare the results of that example like this:

    $ ./a.out /path/to/foo.iso /path/to/bar.iso
    $ sha1sum /path/to/foo.iso /path/to/bar.iso
    

    NB: In contrast to older boost answers, this solution doesn't depend on any private boost implementation details.