简体   繁体   English

用 OpenSSL 和 C++ 生成 sha256

[英]Generate sha256 with OpenSSL and C++

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.我正在寻找使用 openssl 和 C++ 创建带有 sha256 的 hash。我知道在使用 OpenSSL 库在 C++ 中生成 SHA hash 中也有类似的帖子,但我正在寻找 sham25

UPDATE:更新:

Seems to be a problem with the include paths.似乎是包含路径的问题。 It can't find any OpenSSL functions even though I included即使我包括在内,它也找不到任何 OpenSSL 函数

#include "openssl/sha.h"

and I included the paths in my build我在我的构建中包含了路径

-I/opt/ssl/include/ -L/opt/ssl/lib/ -lcrypto 

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

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

Using OpenSSL'sEVP interface (the following is for OpenSSL 1.1):使用 OpenSSL 的EVP 接口(以下针对 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, eg EVP_sha512() , to use a different digest.这个更高级别接口的优点是您只需将EVP_sha256()调用替换为另一个摘要的函数,例如EVP_sha512() ,即可使用不同的摘要。 So it adds some flexibility.所以它增加了一些灵活性。

A more "C++"ish version一个更“C++”的版本

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

Here's the function I personally use - I simply derived it from the function I used for sha-1 hashing:这是我个人使用的函数 - 我只是从我用于sha-1散列的函数中派生出来的:

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

If you want to compute the sha256 hash of a file...如果你想计算一个文件的 sha256 hash ...

auto sha256 = [](std::string fname, 
                 std::vector<unsigned char>& hash) -> bool {
   std::unique_ptr<EVP_MD_CTX, void (*)(EVP_MD_CTX *)>
            evpCtx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
   EVP_DigestInit_ex(evpCtx.get(), EVP_sha256(), nullptr);

   constexpr size_t buffer_size { 1 << 12 };
   std::vector<char> buffer(buffer_size,'\0');

   std::ifstream fp(fname, std::ios::binary);
   if (!fp.is_open()) {
        std::cerr << "Unable to open '" << fname << "'!\n";
        return false;
   }
   while (fp.good()) {
        fp.read(buffer.data(), buffer_size);
        EVP_DigestUpdate (evpCtx.get(), buffer.data(), fp.gcount());
   }
   fp.close();

   hash.resize(SHA256_DIGEST_LENGTH);
   std::fill(hash.begin(), hash.end(), 0);
   unsigned int len;
   EVP_DigestFinal_ex (evpCtx.get(), hash.data(), &len);

   return true;
};

...

std::vector<unsigned char> hash;
sha256("/etc/profile", hash);
std::stringstream out;
for (size_t i = 0; i < hash.size(); i++)
    out << std::setfill('0') << std::setw(2) 
        << std::hex << int(hash[i]);
std::string hashStr = out.str();
std::cout << hashStr << std::endl;
...
a3fe9f414586c0d3cacbe3b6920a09d8718e503bca22e23fef882203bf765065

With the OpenSSL update to 3.0 most of the solution won't work ( as the APIs deprecated ) and it's recommended to use the EVP functions.随着 OpenSSL 更新到 3.0,大多数解决方案将无法使用(因为 API 已弃用),建议使用EVP函数。 Below code shows my take with EVP based on OpenSSL's official documentation下面的代码显示了我根据OpenSSL 的官方文档EVP的看法

This implementation uses pure C and verified on Ubuntu 22.04此实现使用纯C并在Ubuntu 22.04上验证

/**
 * Simple program to calculate message digest using openssl'l new EVP method
 *
 * Verified on Ubuntu 22.04 on Jan 29, 2023
 *
 * Install dependency:
 * sudo apt install make gcc libssl-dev -y
 *
 * To compile:
 * gcc sha256sum.c -o shasum.out -lcrypto
 *
 * To cross verify:
 * echo -n "Hello world" | sha256sum
 *
 * Author: Daniel Selvan D. <danilselvan@gmail.com>
 */

#include <stdio.h>
#include <string.h>

#include <openssl/evp.h>

// OpenSSL engine implementation
#define OPENSSL_ENGINE NULL

/**
 * Returns the SHA256 value of the input string
 *
 * @param string input string for which the hash to be calculated
 * @returns string (32 bytes) - SHA256 hash
 */
static const unsigned char *getShaSum(const unsigned char *string)
{
    EVP_MD_CTX *mdCtx = EVP_MD_CTX_new();
    unsigned char mdVal[EVP_MAX_MD_SIZE], *md;
    unsigned int mdLen, i;

    if (!EVP_DigestInit_ex(mdCtx, EVP_sha256(), OPENSSL_ENGINE))
    {
        printf("Message digest initialization failed.\n");
        EVP_MD_CTX_free(mdCtx);
        exit(EXIT_FAILURE);
    }

    // Hashes cnt bytes of data at d into the digest context mdCtx
    if (!EVP_DigestUpdate(mdCtx, string, strlen((const char *)string)))
    {
        printf("Message digest update failed.\n");
        EVP_MD_CTX_free(mdCtx);
        exit(EXIT_FAILURE);
    }

    if (!EVP_DigestFinal_ex(mdCtx, mdVal, &mdLen))
    {
        printf("Message digest finalization failed.\n");
        EVP_MD_CTX_free(mdCtx);
        exit(EXIT_FAILURE);
    }
    EVP_MD_CTX_free(mdCtx);

    printf("DEBUG: Digest is: ");
    for (i = 0; i < mdLen; i++)
        printf("%02x", mdVal[i]);
    printf("\n");

    md = mdVal;

    return md;
}

int main()
{
    // To calculate the hash of a file, read it and pass the pointer
    getShaSum("Hello world");

    exit(EXIT_SUCCESS);
}

The advantage of this higher level interface is that you simply need to swap out the EVP_sha256() call with another digest's function, eg EVP_sha512() , to use a different digest.这个更高级别接口的优点是您只需将EVP_sha256()调用换成另一个摘要的 function,例如EVP_sha512() ,即可使用不同的摘要。

我认为您只需要使用来自您帖子中的链接的 tatk 代码将 SHA1 函数替换为 SHA256 函数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM