Функция не генерирует правильные ключи openssl rsa

Эту функцию я написал для генерации ключей openssl rsa 4096 bit.

    bool rsa_gen_keys()
    {    
    int             ret = 0;
    RSA             *rsa = NULL;
    BIGNUM          *bignum = NULL;
    BIO             *bio_private = NULL;
    BIO             *bio_public = NULL;
    int              bits = 4096;

    unsigned long k = RSA_F4;

    bignum = BN_new();
    ret = BN_set_word(bignum,k);
    if(ret != 1){
        goto cleanup;
    }

    rsa = RSA_new();
    ret = RSA_generate_key_ex(rsa, bits, bignum, NULL);
    if(ret != 1){
        goto cleanup;
    }
    // write rsa private key to file
    bio_private = BIO_new_file("private_new.pem", "w+");
    ret = PEM_write_bio_RSAPrivateKey(bio_private, rsa, NULL, NULL, 0, NULL, NULL);
    BIO_flush(bio_private);
    // write rsa public key to file
    bio_public = BIO_new_file("public_new.pem", "w+");
    ret = PEM_write_bio_RSAPublicKey(bio_public, rsa);
    if(ret != 1){
        goto cleanup;
    }    
    BIO_flush(bio_public);
cleanup:
    BIO_free_all(bio_private);
    BIO_free_all(bio_public);
    RSA_free(rsa);
    BN_free(bignum);
    return ret;
}

Ключи, сгенерированные вышеуказанной функцией, похоже, что-то упустили Когда я пытаюсь использовать файл public_new.pem в другой программе, я получаю следующую ошибку:

140286309791384:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:701:Expecting: PUBLIC KEY

Однако, если я использую команду openssl для генерации файлов ключей, файлы работают нормально.

$openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:4096

Я заметил, что размеры клавиш, сгенерированные из функции и из командной строки, не совпадают. Это подсказка, но что мне нужно изменить в моей функции, чтобы это исправить?

-rw-rw-r-- 1 3272 Feb  6 09:19 private_key.pem
-rw-rw-r-- 1  800 Feb  6 09:20 public_key.pem
-rw-rw-r-- 1 3243 Feb  6 10:43 private_new.pem
-rw-rw-r-- 1  775 Feb  6 10:43 public_new.pem

Кстати, я попробовал выше с ключами 2048 бит, и я получаю тот же результат и то же несоответствие размера

2 ответа

openssl genpkey использует PEM_write_bio_PrivateKey (PKCS#8) вместо PEM_write_bio_RSAPrivateKey (PKCS # 1): https://github.com/openssl/openssl/blob/master/apps/genpkey.c#L161-L164.

Вы не показываете, как вы создали public_key.pem, но это, вероятно, было написано с PEM_write_bio_PUBKEY (X.509 SubjectPublicKeyInfo) против PEM_write_bio_RSAPublicKey (PKCS#1).

С точки зрения брони PEM:

  • PKCS # 1 Public: BEGIN RSA PUBLIC KEY
  • X.509 SubjectPublicKeyInfo: НАЧАТЬ ПУБЛИЧНЫЙ КЛЮЧ
  • PKCS#1 Private: BEGIN RSA ЧАСТНЫЙ КЛЮЧ
  • PKCS#8: НАЧАТЬ ЧАСТНЫЙ КЛЮЧ

Я понял, что мне нужно использовать формат ключей для PKCS#8 и X.509. Поэтому я переключился на функции EVP для их генерации. Вот очень упрощенная версия кода, который я использовал (без проверки ошибок):

bool rsa_gen_keys() {
    int ret = 0;
    BIO *bio_private = NULL;
    BIO *bio_public = NULL;
    int bits = 4096;

    EVP_PKEY_CTX *ctx;
    EVP_PKEY *pkey = NULL;

    // Get the context
    ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
    if (!ctx)
        goto cleanup;

    // init keygen
    if (EVP_PKEY_keygen_init(ctx) <= 0)
        goto cleanup;

    // set the bit size 
    if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0)
    goto cleanup;

    /* Generate key */
    if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
        goto cleanup;


    // write rsa private key to file
    bio_private = BIO_new_file("private_new.pem", "w+");
    ret = PEM_write_bio_PrivateKey(bio_private, pkey, NULL, NULL, 0, NULL, NULL);
    if (ret != 1) {
        goto cleanup;
    }
    BIO_flush(bio_private);

    // write rsa public key to file
    bio_public = BIO_new_file("public_new.pem", "w+");

    //ret = PEM_write_bio_RSAPublicKey(bio_public, rsa);
    ret = PEM_write_bio_PUBKEY(bio_public, pkey);
    if (ret != 1) {
        goto cleanup;
    }
    BIO_flush(bio_public);


cleanup:
    if(bio_private) BIO_free_all(bio_private);
    if(bio_public) BIO_free_all(bio_public);
    if(pkey) EVP_PKEY_free(pkey);

    return ret;
}
Другие вопросы по тегам