2017-02-06 3 views
0

Это c-функция, которую я написал для генерации ключей openssl rsa 4096 бит.Функция не генерирует правильные ключи openssl rsa

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 бит ключей и я получаю тот же результат и тот же несоответствие размера

+1

'c/C++ function' == Неопределенное поведение. : P –

+0

Какую форму или кодировку вы хотите? Вы можете видеть различные кодировки в [Использовать ключ OpenSSL RSA с .Net] (http://stackoverflow.com/q/30475758/608639). – jww

ответ

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: BEGIN PUBLIC KEY
  • PKCS # 1 Private: BEGIN RSA PRIVATE KEY
  • PKCS # 8: НАЧАТЬ ЧАСТНЫЙ КЛЮЧ
+0

Это объясняет разницу. Возможно, мне придется переключиться на использование EVP-вызовов для создания правильного формата вместо прямого вызова RSA .. например, EVP_PKEY_keygen() ?. – seedhom

+1

Да. Структура 'EVP_ *' (огибающая (d)), а соответствующие форматы файлов - это «какой ключ это» и «о, вот ключ». Использование прямых API-интерфейсов RSA означает, что вы уже должны знать, какой тип ключа он есть, поэтому он не работает. – bartonjs

0

Я понял, что мне нужно использовать формат ключей для 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; 
} 
Смежные вопросы