Generate sha256 with OpenSSL and C++

156,369

Solution 1

Here's how I did it:

void sha256_hash_string (unsigned char hash[SHA256_DIGEST_LENGTH], char outputBuffer[65])
{
    int i = 0;

    for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
    }

    outputBuffer[64] = 0;
}


void sha256_string(char *string, char outputBuffer[65])
{
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, string, strlen(string));
    SHA256_Final(hash, &sha256);
    int i = 0;
    for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
    }
    outputBuffer[64] = 0;
}

int sha256_file(char *path, char outputBuffer[65])
{
    FILE *file = fopen(path, "rb");
    if(!file) return -534;

    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    const int bufSize = 32768;
    unsigned char *buffer = malloc(bufSize);
    int bytesRead = 0;
    if(!buffer) return ENOMEM;
    while((bytesRead = fread(buffer, 1, bufSize, file)))
    {
        SHA256_Update(&sha256, buffer, bytesRead);
    }
    SHA256_Final(hash, &sha256);

    sha256_hash_string(hash, outputBuffer);
    fclose(file);
    free(buffer);
    return 0;
}

It's called like this:

static unsigned char buffer[65];
sha256("string", buffer);
printf("%s\n", buffer);

Solution 2

std based

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

using namespace std;

#include <openssl/sha.h>
string sha256(const string str)
{
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, str.c_str(), str.size());
    SHA256_Final(hash, &sha256);
    stringstream ss;
    for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        ss << hex << setw(2) << setfill('0') << (int)hash[i];
    }
    return ss.str();
}

int main() {
    cout << sha256("1234567890_1") << endl;
    cout << sha256("1234567890_2") << endl;
    cout << sha256("1234567890_3") << endl;
    cout << sha256("1234567890_4") << endl;
    return 0;
}

Solution 3

Using OpenSSL's EVP interface (the following is for OpenSSL 1.1):

#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <openssl/evp.h>

bool computeHash(const std::string& unhashed, std::string& hashed)
{
    bool success = false;

    EVP_MD_CTX* context = EVP_MD_CTX_new();

    if(context != NULL)
    {
        if(EVP_DigestInit_ex(context, EVP_sha256(), NULL))
        {
            if(EVP_DigestUpdate(context, unhashed.c_str(), unhashed.length()))
            {
                unsigned char hash[EVP_MAX_MD_SIZE];
                unsigned int lengthOfHash = 0;

                if(EVP_DigestFinal_ex(context, hash, &lengthOfHash))
                {
                    std::stringstream ss;
                    for(unsigned int i = 0; i < lengthOfHash; ++i)
                    {
                        ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
                    }

                    hashed = ss.str();
                    success = true;
                }
            }
        }

        EVP_MD_CTX_free(context);
    }

    return success;
}

int main(int, char**)
{
    std::string pw1 = "password1", pw1hashed;
    std::string pw2 = "password2", pw2hashed;
    std::string pw3 = "password3", pw3hashed;
    std::string pw4 = "password4", pw4hashed;

    hashPassword(pw1, pw1hashed);
    hashPassword(pw2, pw2hashed);
    hashPassword(pw3, pw3hashed);
    hashPassword(pw4, pw4hashed);

    std::cout << pw1hashed << std::endl;
    std::cout << pw2hashed << std::endl;
    std::cout << pw3hashed << std::endl;
    std::cout << pw4hashed << std::endl;

    return 0;
}

The advantage of this higher level interface is that you simply need to swap out the EVP_sha256() call with another digest's function, e.g. EVP_sha512(), to use a different digest. So it adds some flexibility.

Solution 4

A more "C++"ish version

#include <iostream>
#include <sstream>

#include "openssl/sha.h"

using namespace std;

string to_hex(unsigned char s) {
    stringstream ss;
    ss << hex << (int) s;
    return ss.str();
}   

string sha256(string line) {    
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, line.c_str(), line.length());
    SHA256_Final(hash, &sha256);

    string output = "";    
    for(int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        output += to_hex(hash[i]);
    }
    return output;
}

int main() {
    cout << sha256("hello, world") << endl;

    return 0;
}

Solution 5

Here's the function I personally use - I simply derived it from the function I used for sha-1 hashing:

char *str2sha256( const char *str, int length ) {
  int n;
  SHA256_CTX c;
  unsigned char digest[ SHA256_DIGEST_LENGTH ];
  char *out = (char*) malloc( 33 );

  SHA256_Init( &c );

  while ( length > 0 ) {
    if ( length > 512 ) SHA256_Update( &c, str, 512 );
    else SHA256_Update( &c, str, length );

    length -= 512;
    str += 512;
  }

  SHA256_Final ( digest, &c );

  for ( n = 0; n < SHA256_DIGEST_LENGTH; ++n )
    snprintf( &( out[ n*2 ] ), 16*2, "%02x", (unsigned int) digest[ n ] );

  return out;
}
Share:
156,369
stan
Author by

stan

Updated on July 05, 2022

Comments

  • stan
    stan almost 2 years

    I'm looking to create a hash with sha256 using openssl and C++. I know there's a similar post at Generate SHA hash in C++ using OpenSSL library, but I'm looking to specifically create sha256.

    UPDATE:

    Seems to be a problem with the include paths. It can't find any OpenSSL functions even though I included

    #include "openssl/sha.h"
    

    and I included the paths in my build

    -I/opt/ssl/include/ -L/opt/ssl/lib/ -lcrypto 
    
  • TCB13
    TCB13 almost 13 years
    Hi, for everyone using the great QT :) - You can also use this, just add to your project file LIBS +=-lcrypto and then you can just convert the code to a class and everything will work fine ;)
  • jww
    jww over 12 years
    -1: “SHA1_Init(), SHA1_Update() and SHA1_Final() return 1 for success, 0 otherwise.”, openssl.org/docs/crypto/sha.htm.
  • jww
    jww over 12 years
    -1: “SHA1_Init(), SHA1_Update() and SHA1_Final() return 1 for success, 0 otherwise.”, openssl.org/docs/crypto/sha.htm.
  • Max
    Max over 12 years
    didn't want to obscure the code with C-style return value checks. DIY if you care
  • jww
    jww over 12 years
    "DIY if you care" - sorry to inconvenience you. Folks will blindly copy/paste it. Ignoring return values is a dangerous practice, and should not be demonstarated (especially in high integrity code).
  • stan
    stan about 12 years
    Haven't tested this out, but this definitely looks cleaner than all the other "C++" versions.
  • Homer6
    Homer6 over 11 years
    This code compiles and produced the expected output. On ubuntu, you can use: sudo apt-get install libssl-dev && g++ -lcrypto main.cc to compile it.
  • Konrad Rudolph
    Konrad Rudolph over 11 years
    @noloader Irrelevant since these functions aren’t used here.
  • jww
    jww over 11 years
    @Konrad Rudolph Its the same API interface, and the OpenSSL man pages lead back to the SHA1 stuff. Ignoring return values in high integrity software is very bad karma.
  • UpAndAdam
    UpAndAdam almost 10 years
    What the heck is sha256_hash_string(...) looks like you reference a non-existent function in your code...
  • Admin
    Admin over 9 years
    @jww I cried reading your comment because it's true, people will write "secure" applications by copy-and-paste programming. But I also agree to some degree with Max only because it shouldn't be on our shoulders to prevent stupid people from incorrectly using our knowledge, or stupid people from using "secure" software written by a copy and paste programmer.
  • omni
    omni almost 8 years
    This solution is actually better than the accepted one, as ostringstream is much, much safer than messing with arrays and sprintf.
  • villapx
    villapx over 7 years
    According to the OpenSSL docs, "The EVP interface to message digests should almost always be used in preference to the low level interfaces. This is because the code then becomes transparent to the digest used and much more flexible." So keep that in mind when deciding to use this code, i.e. make sure you're positive that you'll only ever use SHA256. Otherwise, it's more worth your time to learn the EVP interface.
  • toinetoine
    toinetoine over 7 years
    @Homer6 for g++, technically the dependency should be after the src file that depends on it (caused complication issues for me on Ubuntu 16.04.1). Should be: g++ main.cc -lcrypto
  • Admin
    Admin almost 7 years
    May I ask how to solve the 'byte' in second function was not declared
  • Fnr
    Fnr almost 6 years
    byte is just as the name says, a byte (can be typedef'd with an unsigned char). sha256_hash_string I think he means the function sha256 he previously defined
  • Nasreddine Galfout
    Nasreddine Galfout about 5 years
    this code does not check for errors, It is a shot on the foot do not copy paste with out making the appropriate Update
  • lmat - Reinstate Monica
    lmat - Reinstate Monica about 5 years
    if statements without else clauses ... so ... deep ... cannot see light ... Upvoted nonetheless because it uses the recommended EVP interface!
  • villapx
    villapx about 5 years
    @LimitedAtonement Indeed, I left "proper" error checking as an exercise to the end developer :) but at a minimum, I made sure I did all the if-checks just to highlight where they're required. Thanks for the +1!
  • lmat - Reinstate Monica
    lmat - Reinstate Monica over 4 years
    "DIY if you care" But seriously now, who cares about error conditions?
  • Olivia Stork
    Olivia Stork over 3 years
    It's even better practice to use std::byte, but this code looks like C++98 only.
  • csavvy
    csavvy over 3 years
    Sorry,I know its very old. The prototype of SHA256 is unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md); as mentioned here sha. May be i am referring old or not sure. As I need to calculate SHA256 of certain files , can you point me in right direction of openssl libs based on C
  • 127
    127 over 2 years
    this one excludes 0s from resulting hash sometimes
  • Csuszmusz
    Csuszmusz over 2 years
    for anybody else coming here: EVP_MD_CTX could be a unique ptr with custom deleter . much cleaner code. just to nitpick here. std::unique_ptr<EVP_MD_CTX, std::function<void(EVP_MD_CTX*)>> mdCtx(EVP_MD_CTX_new(), [](EVP_MD_CTX* g) { EVP_MD_CTX_free(g); });