How to Use Openssl's Sha256 Functions

How to use OpenSSL's SHA256 functions

You make a very common beginners mistake... Putting the libraries you link with in the wrong place on the command line when you build.

Dependencies are reversed on the command line, so something that depends on something else should actually be put before what it depends on on the command line.

In your example, you have a source file main.cpp that depends on some set of libraries, then the source file should be before the libraries it depend on:

$ g++ -o main main.cpp -lssl -lcrypto

To be safe, always put libraries last, after any source or object files listed on the command line.

Generate sha256 with OpenSSL and C++

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

C++: Efficiently get Sha256 digest into OpenSSL Bignum?

At the end I ended up using BN_bin2bn() to convert a uint8_t into a BigNum.

#include <openssl/bn.h>

void Crypto::Sha256 (const std::string &p_Data, BIGNUM* hash)
{
uint8_t digestBuffer[256];
SHA256_CTX context;

SHA256_Init (&context);
SHA256_Update (&context, p_Data.c_str (), p_Data.length ());
SHA256_Final (digestBuffer, &context);

BN_bin2bn (digestBuffer, 256, hash);
}

HMAC-SHA256 in C with OpenSSL - how to get a correct output

You are getting the same result, you are just printing it as decimals whereas the online tool is outputting hexadecimal.

204 decimal is CC in hecadecimal, 219 is DB etc.

Try

for (unsigned int i = 0; i < resultlen; i++){
printf("%02hhX", result[i]); // or just "%02X" if you are not using C11 or later
}

instead.

C++ openssl SHA256 running slower than JDK SHA256 implementation

The bottleneck for your c++ code is your custom bytes_to_string function. Calling stringstream functions in a loop simply hits the performance.

You might want to look at this answer to another question.


replace the stringstream functions with the following code snippet. It is faster because it manipulates the string memory directly.

static const char characters[] = "0123456789ABCDEF";
std::string result (SHA256_DIGEST_LENGTH * 2, ' ');
for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
result[2*i] = characters[(unsigned int) hash[i] >> 4];
result[2*i+1] = characters[(unsigned int) hash[i] & 0x0F];
}
return result;

OpenSSL problem with returned SHA256 value - C++

If the goal of this is to produce an asci hex string of the sha bytes (in either case), your sprintf_s loop (a) is lying, the target buffer is decreasingly smaller as you march up so repeatedly passing sizeof(buf)/2 is a lie, and (b) invokes undefined behavior on the final write, which will produce a three character output when you include a terminator, but by that time you're only two bytes away from end-of-buffer).

If you're going to do this in C++, then start using the standard library; it come in handy in oh-so-many ways. Also, use the EVP family (which all modern OpenSSL applications should use if they have any sense; it becomes so much easier in the long run).

// standard includes
#include <iostream>
#include <memory>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdint>

// openssl libraries
#include <openssl/evp.h>
#include <openssl/sha.h>

namespace OpenSSL
{
struct Delete
{
void operator()(EVP_MD_CTX *p) const
{
EVP_MD_CTX_free(p);
}
};

template<class T>
using Ptr = std::unique_ptr<T, Delete>;
}
using EVP_MD_CTX_ptr = OpenSSL::Ptr<EVP_MD_CTX>;

// generic MD digest runner
std::string generateDigest(const void *src, size_t slen, const EVP_MD* digest)
{
unsigned int mdlen = EVP_MD_size(digest);
std::vector<uint8_t> md(mdlen);

EVP_MD_CTX_ptr ctx(EVP_MD_CTX_new());
EVP_DigestInit(ctx.get(), digest);
EVP_DigestUpdate(ctx.get(), src, slen);
EVP_DigestFinal(ctx.get(), md.data(), &mdlen);

// build output string
static const char halpha[] = "0123456789abcdef";
std::string result;
result.reserve(mdlen * 2);
for (auto b : md)
{
result.push_back(halpha[(b >> 4) & 0xF]);
result.push_back(halpha[b & 0xF]);
}
return result;
}

std::string generateSHA1(const void *src, std::size_t slen)
{
return generateDigest(src, slen, EVP_sha1());
}

std::string generateSHA256(const void *src, std::size_t slen)
{
return generateDigest(src, slen, EVP_sha256());
}

int main()
{
OpenSSL_add_all_digests();
OpenSSL_add_all_algorithms();

static const char msg[] = "The quick brown fox jumps over the lazy dog";
static const char kat1[] = "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12";
static const char kat256[] = "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592";

auto s = generateSHA1(msg, sizeof(msg)-1);
if (s != kat1)
{
std::cout << "SHA1 FAIL\n";
return EXIT_FAILURE;
}

s = generateSHA256(msg, sizeof(msg)-1);
if (s != kat256)
{
std::cout << "SHA256 FAIL\n";
return EXIT_FAILURE;
}

std::cout << "Success!!\n";
return EXIT_SUCCESS;
}

Output

Success!!


Related Topics



Leave a reply



Submit