web-dev-qa-db-ja.com

Cのpemファイルへのrsaキーの読み取りと書き込み

RSAのキーを生成し、それらをファイルに書き込んでから読み取るためのCプログラムを作成しています。宿題では、openssl形式でファイルを生成する必要があります。そこで、PEMを選びました。これで、ファイルを作成するための次の関数があります

rsa = RSA_new();
// These 3 keys are generated beforehand
rsa->e = e;
rsa->n = n;
rsa->d = d;

fp = fopen(pubkey_file, "w");
if(!PEM_write_RSAPublicKey(fp, rsa))
{
    printf("\n%s\n", "Error writing public key");
}
fflush(fp);
fclose(fp);

fp = fopen(privkey_file, "w");
// pRsaKey = EVP_PKEY_new();
// EVP_PKEY_assign_RSA(pRsaKey, rsa);
if(!PEM_write_RSAPrivateKey(fp, rsa, NULL, 0, 0, NULL, NULL))
// if (!PEM_write_PrivateKey(fp, pRsaKey, NULL, NULL, 0, 0, NULL))
{
    printf("\n%s\n", "Error writing private key");
}
fflush(fp);
fclose(fp);

そしてこれはファイルを読み取る機能です

rsa = RSA_new();
fp = fopen(pubkey_file, "r");
if(PEM_read_RSAPublicKey(fp, &rsa, NULL, NULL) == NULL)
{
    printf("\n%s\n", "Error Reading public key");
    return;
}

fclose(fp);
BN_bn2bin(rsa->n, (unsigned char *)modulus);
BN_bn2bin(rsa->e, (unsigned char *)exp);
printf("\n%s\n%s\n", exp, modulus);
RSA_free(rsa);

// pRsaKey = EVP_PKEY_new();
fp = fopen(privkey_file, "r");
if(fp)
    // if((PEM_read_PrivateKey(fp, &pRsaKey, NULL, NULL)) == NULL)
    if((PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL)) == NULL)
    {
        printf("\n%s\n", "Error Reading private key");
        return;
    }
// rsa = RSA_new();
// rsa = EVP_PKEY_get1_RSA(pRsaKey);
fclose(fp);

公開鍵は必要に応じて読み書きされますが、提出鍵は失敗します。私はrsaとevp(上記のコードでコメントされています)の両方を使用して書いてみました。しかし、両方とも失敗します。なぜこれが起こっているのか頭を悩ませたり、この問題をデバッグする場所を見つけようとしたりすることができません。誰かがこれについていくつかの指針を提供できますか?

15
Max Jindal

RSA鍵は対称的であり、それらのいずれも秘密鍵または公開鍵として使用できます。これは単に選択の問題です(ただし、DSA鍵は[〜#〜] not [〜#〜]対称)。以下のプログラムは、2つの2048ビット長のRSAキーを生成し、それらをファイルに保存してメモリに読み込みます。それはあなたにそれを行う方法のアイデアを与えるはずです。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/pem.h>

const char* pcszPassphrase = "open sezamee";

static void gen_callback(int iWhat, int inPrime, void* pParam);
static void init_openssl(void);
static void cleanup_openssl(void);
static int passwd_callback(char *pcszBuff,int size,int rwflag, void *pPass);
static EVP_PKEY* create_rsa_key(void);
static void handle_openssl_error(void);

int main(int argc, char **argv)
{
    int iRet = EXIT_SUCCESS;
    EVP_PKEY* pPrivKey = NULL;
    EVP_PKEY* pPubKey  = NULL;
    FILE*     pFile    = NULL;
    const EVP_CIPHER* pCipher = NULL;
    init_openssl();

    pPrivKey = create_rsa_key();
    pPubKey  = create_rsa_key();

    if(pPrivKey && pPubKey)
    {/* Save the keys */
        if((pFile = fopen("privkey.pem","wt")) && (pCipher = EVP_aes_256_cbc()))
        {

            if(!PEM_write_PrivateKey(pFile,pPrivKey,pCipher,
                                    (unsigned char*)pcszPassphrase,
                                    (int)strlen(pcszPassphrase),NULL,NULL))
            {
                fprintf(stderr,"PEM_write_PrivateKey failed.\n");
                handle_openssl_error();
                iRet = EXIT_FAILURE;
            }
            fclose(pFile);
            pFile = NULL;
            if(iRet == EXIT_SUCCESS)
            {
                if((pFile = fopen("pubkey.pem","wt")) && PEM_write_PUBKEY(pFile,pPubKey))
                    fprintf(stderr,"Both keys saved.\n");
                else
                {
                    handle_openssl_error();
                    iRet = EXIT_FAILURE;
                }
                if(pFile)
                {
                    fclose(pFile);
                    pFile = NULL;
                }
            }
        }
        else
        {
            fprintf(stderr,"Cannot create \"privkey.pem\".\n");
            handle_openssl_error();
            iRet = EXIT_FAILURE;
            if(pFile)
            {
                fclose(pFile);
                pFile = NULL;
            }
        }
        if(iRet == EXIT_SUCCESS)
        {/* Read the keys */
            EVP_PKEY_free(pPrivKey);
            pPrivKey = NULL;
            EVP_PKEY_free(pPubKey);
            pPubKey = NULL;

            if((pFile = fopen("privkey.pem","rt")) && 
               (pPrivKey = PEM_read_PrivateKey(pFile,NULL,passwd_callback,(void*)pcszPassphrase)))
            {
                fprintf(stderr,"Private key read.\n");
            }
            else
            {
                fprintf(stderr,"Cannot read \"privkey.pem\".\n");
                handle_openssl_error();
                iRet = EXIT_FAILURE;
            }
            if(pFile)
            {
                fclose(pFile);
                pFile = NULL;
            }

            if((pFile = fopen("pubkey.pem","rt")) && 
               (pPubKey = PEM_read_PUBKEY(pFile,NULL,NULL,NULL)))
            {
                fprintf(stderr,"Public key read.\n");
            }
            else
            {
                fprintf(stderr,"Cannot read \"pubkey.pem\".\n");
                handle_openssl_error();
                iRet = EXIT_FAILURE;
            }
        }
    }

    if(pPrivKey)
    {
        EVP_PKEY_free(pPrivKey);
        pPrivKey = NULL;
    }
    if(pPubKey)
    {
        EVP_PKEY_free(pPubKey);
        pPubKey = NULL;
    }
    cleanup_openssl();
    return iRet;
}

EVP_PKEY* create_rsa_key(void)
{
    RSA *pRSA      = NULL;
    EVP_PKEY* pKey = NULL;
    pRSA = RSA_generate_key(2048,RSA_3,gen_callback,NULL);
    pKey = EVP_PKEY_new();
    if(pRSA && pKey && EVP_PKEY_assign_RSA(pKey,pRSA))
    {
        /* pKey owns pRSA from now */
        if(RSA_check_key(pRSA) <= 0)
        {
            fprintf(stderr,"RSA_check_key failed.\n");
            handle_openssl_error();
            EVP_PKEY_free(pKey);
            pKey = NULL;
        }
    }
    else
    {
        handle_openssl_error();
        if(pRSA)
        {
            RSA_free(pRSA);
            pRSA = NULL;
        }
        if(pKey)
        {
            EVP_PKEY_free(pKey);
            pKey = NULL;
        }
    }
    return pKey;
}

void gen_callback(int iWhat, int inPrime, void* pParam)
{
    char c='*';
    switch(iWhat)
    {
        case 0: c = '.';  break;
        case 1: c = '+';  break;
        case 2: c = '*';  break;
        case 3: c = '\n'; break;
    }
    fprintf(stderr,"%c",c);
}

int passwd_callback(char *pcszBuff,int size,int rwflag, void *pPass)
{
    size_t unPass = strlen((char*)pPass);
    if(unPass > (size_t)size)
        unPass = (size_t)size;
    memcpy(pcszBuff, pPass, unPass);
    return (int)unPass;
}

void init_openssl(void)
{
    if(SSL_library_init())
    {
        SSL_load_error_strings();
        OpenSSL_add_all_algorithms();
        Rand_load_file("/dev/urandom", 1024);
    }
    else
        exit(EXIT_FAILURE);
}

void cleanup_openssl(void)
{
    CRYPTO_cleanup_all_ex_data();
    ERR_free_strings();
    ERR_remove_thread_state(0);
    EVP_cleanup();
}

void handle_openssl_error(void)
{
    ERR_print_errors_fp(stderr);
}
13
sirgeorge

Sirgeorgeによって与えられた答えは、コードに誤りがあります。 create_rsa_keyを2回呼び出さないでください。 2回呼び出された場合、秘密鍵には一致する公開鍵がありません。これにより、復号化中に問題が発生します。 mainメソッドで必要な変更

RSA *pRSA      = NULL;
pRSA = RSA_generate_key(2048,RSA_3,gen_callback,NULL);    
pPrivKey = create_rsa_key(pRSA);
pPubKey  = create_rsa_key(pRSA);

create_rsa_keyで必要な変更

EVP_PKEY* create_rsa_key(RSA *pRSA)
{
    EVP_PKEY* pKey = NULL;
    pKey = EVP_PKEY_new();
    if(pRSA && pKey && EVP_PKEY_assign_RSA(pKey,pRSA))
    {
        /* pKey owns pRSA from now */
        if(RSA_check_key(pRSA) <= 0)
        {
            fprintf(stderr,"RSA_check_key failed.\n");
            handle_openssl_error();
            EVP_PKEY_free(pKey);
            pKey = NULL;
        }
    }
    else
    {
        handle_openssl_error();
        if(pRSA)
        {
            RSA_free(pRSA);
            pRSA = NULL;
        }
        if(pKey)
        {
            EVP_PKEY_free(pKey);
            pKey = NULL;
        }
    }
    return pKey;
}
9
user2281107