C++ で ハッシュ値を生成する。 Windows OpenSSL編

C, C++の標準ライブラリでは、SHA系アルゴリズムを生成するクラス、関数が、提供されていないです。
今回は、OpenSSLの関数でハッシュ値を生成しました。

## 実施環境

* OpenSSL 3.0系
* Visual Stuido 2022 Commnunity

## OpenSSLのインストール

[Win32/Win64 OpenSSL](https://slproweb.com/products/Win32OpenSSL.html)より Windows版 OpenSSLをダウンロードして、インストールします。64bit版のサンプルを作成するので、「Win64 OpenSSL v3.0.7」をインストールしました。

## プロジェクトの設定

サンプルのプロジェクトの「追加のインクルードディレクトリ」に C:\Program Files\OpenSSL-Win64\include を追加します。「追加のライブラリディレクトリ」に C:\Program Files\OpenSSL-Win64\lib\VC を追加します。「追加のライブラリファイル」に libcrypto64MD.lib を追加します。

## サンプルプログラム

### その１

おそらく、コードが一番、短くて済む方法？。　[関数 SHA256](https://www.openssl.org/docs/man3.0/man3/SHA256.html) を使います。

```C++
#include <iostream>
#include <string>
#include <vector>
#include <openssl/sha.h>

int main()
{
    std::string str("Hello World");
    
    unsigned char uchash1[20];
    size_t  hashSize1 = sizeof(uchash1);
    unsigned char uchash2[32];
    size_t hashSize2 = sizeof(uchash2);

    SHA1((const unsigned char *)str.data(), str.size(), uchash1);
    SHA256((const unsigned char*)str.data(), str.size(), uchash2);

    std::vector<unsigned char> hash1;
    hash1.resize(hashSize1);
    for (size_t i = 0; i < hashSize1; i++) {
        hash1.at(i) = uchash1[i];
    }

    std::vector<unsigned char> hash2;
    hash2.resize(hashSize2);
    for (size_t i = 0; i < hashSize2; i++) {
        hash2.at(i) = uchash2[i];
    }

    std::cout << "SHA1" << std::endl;
    for (size_t i = 0; i < hash1.size(); i++) {
        std::cout << std::hex << (int)hash1.at(i);
    }
    std::cout << std::endl;

    std::cout << "SHA256" << std::endl;
    for (size_t i = 0; i < hash2.size(); i++) {
        std::cout << std::hex << (int)hash2.at(i);
    }
    std::cout << std::endl;
}
```

### その2

ハッシュ値の生成を細かく制御したい場合は、[EVP digest](https://www.openssl.org/docs/man3.0/man3/EVP_DigestInit_ex.html)を使います。

```c++
#include <iostream>
#include <string>
#include <vector>
#include <openssl/evp.h>

int main()
{
    std::string str("Hello World");

    EVP_MD_CTX* mdctx;
    const EVP_MD* md;

    md = EVP_get_digestbyname("SHA1");
    if (md == NULL) {
        printf("Unknown message digest %s\n", "SHA1");
        exit(1);
    }

    mdctx = EVP_MD_CTX_new();
    if (!EVP_DigestInit_ex2(mdctx, md, NULL)) {
        printf("Message digest initialization failed.\n");
        EVP_MD_CTX_free(mdctx);
        exit(1);
    }

    if (!EVP_DigestUpdate(mdctx, str.data(), str.size())) {
        printf("Message digest update failed.\n");
        EVP_MD_CTX_free(mdctx);
        exit(1);
    }

    unsigned char uchash1[20];
    unsigned int  hashSize1;

    if (!EVP_DigestFinal_ex(mdctx, uchash1, &hashSize1)) {
        printf("Message digest finalization failed.\n");
        EVP_MD_CTX_free(mdctx);
        exit(1);
    }
    EVP_MD_CTX_free(mdctx);

    std::vector<unsigned char> hash1;
    hash1.resize(hashSize1);
    for (size_t i = 0; i < hashSize1; i++) {
        hash1.at(i) = uchash1[i];
    }

    std::cout << "SHA1" << std::endl;
    for (size_t i = 0; i < hash1.size(); i++) {
        std::cout << std::hex << (int)hash1.at(i);
    }
    std::cout << std::endl;


    md = EVP_get_digestbyname("SHA256");
    if (md == NULL) {
        printf("Unknown message digest %s\n", "SHA256");
        exit(1);
    }

    mdctx = EVP_MD_CTX_new();
    if (!EVP_DigestInit_ex2(mdctx, md, NULL)) {
        printf("Message digest initialization failed.\n");
        EVP_MD_CTX_free(mdctx);
        exit(1);
    }

    if (!EVP_DigestUpdate(mdctx, str.data(), str.size())) {
        printf("Message digest update failed.\n");
        EVP_MD_CTX_free(mdctx);
        exit(1);
    }

    unsigned char uchash2[32];
    unsigned int  hashSize2;

    if (!EVP_DigestFinal_ex(mdctx, uchash2, &hashSize2)) {
        printf("Message digest finalization failed.\n");
        EVP_MD_CTX_free(mdctx);
        exit(1);
    }
    EVP_MD_CTX_free(mdctx);

    std::vector<unsigned char> hash2;
    hash2.resize(hashSize2);
    for (size_t i = 0; i < hashSize2; i++) {
        hash2.at(i) = uchash2[i];
    }

    std::cout << "SHA256" << std::endl;
    for (size_t i = 0; i < hash2.size(); i++) {
        std::cout << std::hex << (int)hash2.at(i);
    }
    std::cout << std::endl;

}
```