69

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 
jww
  • 83,594
  • 69
  • 338
  • 732
stan
  • 4,752
  • 4
  • 43
  • 68
  • Also as a bonus, it would be nice if it would output the hash in binary :) – stan Feb 14 '10 at 19:29
  • 1
    I posted a new answer there which explains what you want. You could close this question as duplicate if that answer helps. – AndiDog Feb 14 '10 at 20:01
  • @AndiDog - Everything seems to work right, except the compiler cannot find the functions. It could not even find a reference to SHA1. Also coudln't find any of the SHA256 functions like `SHA256_Final'. Not sure what I'm doing wrong, I included #include "openssl/sha.h" and I included the include and library during the compilation -I/opt/ssl/include/ -L/opt/ssl/lib/ -lcrypto – stan Feb 14 '10 at 20:26
  • As you can see in the header (http://google.com/codesearch/p?hl=en#2CnO_mGaYOA/source/openssl-0.9.8e.tar.gz|eVvq2YWVpsY/openssl-0.9.8e/crypto/sha/sha.h&d=1), the SHA256 functions are only defined if OpenSSL is compiled with it. So check the value of `OPENSSL_NO_SHA256` to see what's wrong. The `-lcrypto` parameter should be correct. – AndiDog Feb 14 '10 at 21:07
  • It also doesn't work with any sha1 functions either :/ – stan Feb 14 '10 at 21:35
  • Ok solved my own problem. I just used #include and without -I/opt/ssl/include/ -L/opt/ssl/lib/ – stan Feb 14 '10 at 21:41

6 Answers6

72

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);
Adam Lamers
  • 1,053
  • 7
  • 8
  • 1
    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 ;) – TCB13 Aug 29 '11 at 23:58
  • 3
    -1: “SHA1_Init(), SHA1_Update() and SHA1_Final() return 1 for success, 0 otherwise.”, http://www.openssl.org/docs/crypto/sha.htm. – jww Jan 04 '12 at 19:19
  • @noloader Irrelevant since these functions aren’t used here. – Konrad Rudolph Mar 25 '13 at 10:27
  • 1
    @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. – jww Mar 26 '13 at 03:26
  • 14
    What the heck is sha256_hash_string(...) looks like you reference a non-existent function in your code... – UpAndAdam Aug 26 '14 at 19:43
  • 3
    May I ask how to solve the 'byte' in second function was not declared –  Aug 15 '17 at 08:17
  • `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 – Fabiotk Aug 23 '18 at 19:38
  • It's even better practice to use [`std::byte`](https://en.cppreference.com/w/cpp/types/byte), but this code looks like C++98 only. – Olivia Stork Dec 01 '20 at 20:50
57

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;
}
Jonathan Drapeau
  • 2,578
  • 2
  • 24
  • 32
Yola
  • 16,575
  • 11
  • 57
  • 92
  • 7
    Haven't tested this out, but this definitely looks cleaner than all the other "C++" versions. – stan May 23 '12 at 04:58
  • 4
    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. – Homer6 Jan 12 '13 at 04:03
  • 1
    This solution is actually better than the accepted one, as ostringstream is much, much safer than messing with arrays and `sprintf`. – omni Jul 19 '16 at 22:26
  • 6
    According to the [OpenSSL docs](https://www.openssl.org/docs/manmaster/crypto/EVP_DigestInit.html), **"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. – villapx Oct 20 '16 at 12:36
  • 2
    @Homer6 for g++, technically the dependency should be [after](http://stackoverflow.com/a/13784484/1053362) the src file that depends on it (caused complication issues for me on Ubuntu 16.04.1). Should be: `g++ main.cc -lcrypto` – toinetoine Jan 04 '17 at 18:39
  • 1
    this code does not check for errors, **It is a shot on the foot do not copy paste** with out making the appropriate Update – Nasreddine Galfout Mar 30 '19 at 09:41
  • 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](https://www.openssl.org/docs/man1.0.2/man3/sha.html). 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` – csavvy Dec 16 '20 at 17:33
23

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.

villapx
  • 1,308
  • 12
  • 26
  • if statements without else clauses ... so ... deep ... cannot see light ... Upvoted nonetheless because it uses the recommended EVP interface! – lmat - Reinstate Monica May 13 '19 at 14:03
  • 2
    @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! – villapx May 13 '19 at 14:27
1

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;
}
Max
  • 461
  • 5
  • 4
  • 1
    -1: “SHA1_Init(), SHA1_Update() and SHA1_Final() return 1 for success, 0 otherwise.”, openssl.org/docs/crypto/sha.htm. – jww Jan 04 '12 at 19:22
  • 3
    didn't want to obscure the code with C-style return value checks. DIY if you care – Max Feb 08 '12 at 22:24
  • 15
    "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). – jww Feb 14 '12 at 23:58
  • 1
    @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. –  Mar 10 '15 at 20:12
  • 1
    "DIY if you care" But seriously now, who cares about error conditions? – lmat - Reinstate Monica Feb 10 '20 at 02:11
0

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;
}
finnmglas
  • 1,047
  • 3
  • 14
  • 28
-1

I think that you only have to replace SHA1 function with SHA256 function with tatk code from link in Your post

Peter
  • 3,661
  • 4
  • 35
  • 59
matekm
  • 5,490
  • 3
  • 24
  • 31