2

RSA とその高レベルのエンベロープ機能を使用して、OpenSSL で公開暗号化を実行しようとしています。しかし、私はそれらを理解することができないようで、セグメンテーション違反が発生しています。私のプロジェクトからのこの要約されたコードは、問題を再現します:

#include <iostream>
#include <string>

#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/rand.h>

int main()
{
    EVP_CIPHER_CTX *rsaCtx;
    rsaCtx = new EVP_CIPHER_CTX;

    unsigned char *ek;
    size_t ekl;
    unsigned char *iv;
    size_t ivl;

    EVP_PKEY *keypair;
    keypair = NULL;

    EVP_CIPHER_CTX_init(rsaCtx);

    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
    EVP_PKEY_keygen_init(ctx);
    EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048);
    EVP_PKEY_keygen(ctx, &keypair);
    EVP_PKEY_CTX_free(ctx);

    ek = new unsigned char[EVP_PKEY_size(keypair)];
    iv = new unsigned char[EVP_MAX_IV_LENGTH];
    ivl = EVP_MAX_IV_LENGTH;

    std::string cipherText;
    std::string plainText = "A STRING";
    size_t encMsgLen = 0;
    size_t blockLen  = 0;

    EVP_SealInit(rsaCtx, EVP_aes_256_cbc(), &ek, (int*)ekl, iv, &keypair, 1);
    EVP_SealUpdate(rsaCtx, (unsigned char*)cipherText.c_str() + encMsgLen, (int*)&blockLen, (const unsigned char*)plainText.c_str(), (int)plainText.size() + 1);
    encMsgLen += blockLen;
    EVP_SealFinal(rsaCtx, (unsigned char*)cipherText.c_str() + encMsgLen, (int*)&blockLen);
    encMsgLen += blockLen;
    EVP_CIPHER_CTX_cleanup(rsaCtx);

    EVP_PKEY_free(keypair);
    delete[] ek;
    delete[] iv;
    delete rsaCtx;

    std::cout << cipherText;

    return 0;
}

行でセグメンテーション違反が発生しますEVP_SealInit(rsaCtx, EVP_aes_256_cbc(), &ek, (int*)ekl, iv, &keypair, 1);

私は何を間違っていますか?

4

2 に答える 2

3

eklは でありsize_t、それを にキャストしてい(int*)ます。

言うためのドキュメントEVP_SealInit

暗号化された各秘密鍵の実際のサイズは、配列 ekl に書き込まれます。

1 つのキーを渡すだけなので、単一の整数のアドレスを渡すだけで十分ですが、その整数のアドレスを渡す必要があります。

EVP_SealInit(rsaCtx, EVP_aes_256_cbc(), &ek, reinterpret_cast<int*>(&ekl), iv, &keypair, 1);

eklまたは、最初にとして宣言するだけintで、キャストを回避できます。

int ekl;
//...
EVP_SealInit(rsaCtx, EVP_aes_256_cbc(), &ek, &ekl, iv, &keypair, 1);

初期化されていないローカル変数の使用についてコンパイラが警告しなかったことに驚きました。

更新: セグメンテーション違反以外にも、このコードにはいくつかの問題があります。

空のstd::string( cipherText) からEVP_SealUpdateandにバッファを渡していますEVP_SealFinal。これは一般的には機能せず、バッファに十分なスペースがない場合、メモリがクラッシュまたは破損する可能性があります。

出力に適したサイズのバッファを として宣言し、最初の要素へのポインタを取得するためにstd::vector<unsigned char> cipherText(bufferSize);渡す必要があります。&cipherText[0]

のデータはcipherText人間が読める文字列ではなく、バイナリ データでありstd::cout、表示には適していません。

より一般的な注意事項:

  • C++ での C スタイルのキャストを避け、可能であればコードを記述して、まったくキャストする必要がないようにします (たとえば、API が期待するものである場合でintはなく、整数を宣言するなど)。size_t
  • バッファに使用するなど、明示的なメモリ管理をできる限り避けてくださいnewdeletestd::vector<unsigned char>

これらの関数のドキュメントを再度確認するか、Web 上のその他の使用例を参照することをお勧めします。また、平文が正しくラウンドトリップしていることをテストできるように、復号化ステップを実行するコードを書きます。

于 2015-03-01T00:07:05.907 に答える