【问题标题】:How to generate RSA private key using OpenSSL?如何使用 OpenSSL 生成 RSA 私钥?
【发布时间】:2011-08-21 02:15:44
【问题描述】:

我想知道如何在我的 C 源文件中使用 OpenSSL 库生成 RSA 私钥。我知道如何使用终端命令生成它。

其实我的 server.c 文件会生成一个私钥并发送到 client.c 如果可能,请帮助我提供一些源代码,否则将不胜感激。

我正在使用 Linux 机器。

【问题讨论】:

    标签: c openssl key rsa private


    【解决方案1】:
    #include <openssl/rsa.h>
    #include <openssl/pem.h>
    
    const int kBits = 1024;
    const int kExp = 3;
    
    int keylen;
    char *pem_key;
    
    RSA *rsa = RSA_generate_key(kBits, kExp, 0, 0);
    
    /* To get the C-string PEM form: */
    BIO *bio = BIO_new(BIO_s_mem());
    PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL);
    
    keylen = BIO_pending(bio);
    pem_key = calloc(keylen+1, 1); /* Null-terminate */
    BIO_read(bio, pem_key, keylen);
    
    printf("%s", pem_key);
    
    BIO_free_all(bio);
    RSA_free(rsa);
    free(pem_key);
    

    【讨论】:

    • RSA_generate_key 已弃用;您应该改用 RSA_generate_key_ex。请参阅 RSA_generate_key 的手册页
    • 不需要先初始化库吗?
    【解决方案2】:

    我想知道如何在我的 c 源文件中使用 openssl 库生成 RSA 私钥?

    生成密钥很容易。只需使用RSA_generate_key_ex。下面的程序向您展示了如何做到这一点。

    保存公钥和私钥是另一回事,因为您需要知道格式。下面的程序向您展示了如何以多种格式执行此操作。


    这里有各种功能和格式。

    相关,请参阅What is the differences between “BEGIN RSA PRIVATE KEY” and “BEGIN PRIVATE KEY”。它讨论了SubjectPublicKeyInfoPrivateKeyInfo以及公钥和私钥之间的区别。

    PEM_write_bio_RSAPublicKey(PKCS PEM 格式)。通知BEGIN RSA PUBLIC KEY

    $ cat rsa-public-1.pem
    -----BEGIN RSA PUBLIC KEY-----
    MIIBCgKCAQEAmkD+kwlbsmvyUYOBuVkyWDyBNxGQNJrKUZu97Z+hBG3OA85fY6oV
    CdyoT+KDmtAFgTgY76KRkHVYQH3HYFpec5vNptLJNd6OVJCXR6NFUR2b7aHLkres
    qyPMrAHNU16wp85qdHALNd72EoUPkVItHqaBOldx7J9vyUF3bpAWq4XxRlbiK9iv
    Yuci4/jr4ppRoso6LZm9Inzm53zYt2AqHUZQ+3WgK+czZyk8tLGEN7rtLZ7opvVA
    aAiRGWiUWACtRwmpAq2L5PuWZkYdQ7WQigkx5c3x8iBkeEh022zqYkGOTh2Ue4Uf
    rIYuSqjLb2d+jkfZQ1S4LQLQPtMxNV/FqwIDAQAB
    -----END RSA PUBLIC KEY-----
    

    PEM_write_bio_PUBKEY(传统 PEM 格式)。通知BEGIN PUBLIC KEY

    $ cat rsa-public-2.pem
    -----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmkD+kwlbsmvyUYOBuVky
    WDyBNxGQNJrKUZu97Z+hBG3OA85fY6oVCdyoT+KDmtAFgTgY76KRkHVYQH3HYFpe
    c5vNptLJNd6OVJCXR6NFUR2b7aHLkresqyPMrAHNU16wp85qdHALNd72EoUPkVIt
    HqaBOldx7J9vyUF3bpAWq4XxRlbiK9ivYuci4/jr4ppRoso6LZm9Inzm53zYt2Aq
    HUZQ+3WgK+czZyk8tLGEN7rtLZ7opvVAaAiRGWiUWACtRwmpAq2L5PuWZkYdQ7WQ
    igkx5c3x8iBkeEh022zqYkGOTh2Ue4UfrIYuSqjLb2d+jkfZQ1S4LQLQPtMxNV/F
    qwIDAQAB
    -----END PUBLIC KEY-----
    

    PEM_write_bio_PrivateKey (PEM)。通知BEGIN PRIVATE KEY

    $ cat rsa-private-1.pem
    -----BEGIN PRIVATE KEY-----
    MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCaQP6TCVuya/JR
    g4G5WTJYPIE3EZA0mspRm73tn6EEbc4Dzl9jqhUJ3KhP4oOa0AWBOBjvopGQdVhA
    fcdgWl5zm82m0sk13o5UkJdHo0VRHZvtocuSt6yrI8ysAc1TXrCnzmp0cAs13vYS
    hQ+RUi0epoE6V3Hsn2/JQXdukBarhfFGVuIr2K9i5yLj+OvimlGiyjotmb0ifObn
    fNi3YCodRlD7daAr5zNnKTy0sYQ3uu0tnuim9UBoCJEZaJRYAK1HCakCrYvk+5Zm
    Rh1DtZCKCTHlzfHyIGR4SHTbbOpiQY5OHZR7hR+shi5KqMtvZ36OR9lDVLgtAtA+
    0zE1X8WrAgMBAAECggEAWybDCJJEHGgLdj22v5dE171RQgBf7aX2nkjg7/UfSiW0
    0qz100gjTIOW9jXNPQNl7Vj/60NuryWYc+ufkIF2ROyxlr4CZpHQG4qhypRhlrBf
    fwnX6Sgeobby8EXUVkqjK1YftBStmzTYxlLYwzADN5R+0sHvsTr57LyB3dTJgKsn
    4iAuJXfR4EthZ6iEM+D8FrmXt5lJ2d1FoMLKiC09M7nMuY9ARqR6O5Tr/Tq4vqfw
    La6Mv3mWrD2nIznyTJtxUkAxvCRi1tfHOw2YCl6u2JqqWRjLBeaGNyydhGeVH5PT
    utPHtDciCxpUgGuQ8wNBEstiGYXklpLJFS48+bWVCQKBgQDLC4DNeZ/Tc9g+WUFU
    ypVCTKfCYt2YmLcNeKDqIPdt14PmV3odIxZGJ1OWrNK1LA50pet0xxY1HRjcBsN+
    XUIc5Xa/0nWazdz7c0nqzZgOpVYfPcApQ1K/dqsoWzRY+rlz2PEOYJwMaKW/kkVV
    8EPEg38Ck/qr5iKsBYljTteHhQKBgQDCe+iKtPjlFPJ4WX8vTu5QVpRjYmqj87/j
    4JFpSh7Lv2PsxSCGQR/7JoyB8Zaz9dyP+RV8/ySJuwGqSseU+W495h8oHe1DtIxU
    lTR1GB4YI4BU+txvydzQiaFyEUdEFqJblCxXg+XDAcwCUYESLbR661ljbVV/0Qep
    HMTeXgfnbwKBgDPMYHSK1ZItGHp3bKpD8CX0xktZy2xVcUV3g52XAWg9NcH6iQWL
    4O/Oso1a03oynhF2DoZBD9JG9QOUmiTPh8E1bMDs4OG4KOrg83d6MZNy7HCV4ULl
    kOOVU369HbKha9Q5AO4JCWZFABvKJfQRkkg8v5cZxzY5RJkb5Hu4LlW9AoGACvxg
    2GT8okQapj23934n7BXX7/1BNN2x+zdWP3JWZv/6rwc7nRnUqqU0zqpM7wF2YhOZ
    6SOodrc/ktUCjSHB3nE/VU7LdkWen7CF9A9Ws9pdh29cQFxQwt7jZcQgGHKG3VFz
    Z8Yllmxlj8P23IYEaeUdeYZVjBDMs/rSDBWXsLUCgYEAw4TTKH/4BdnRIKhNLp63
    n8oGo7Cc/idSQD8XbUVpPbLmychOs2no3Y0XT+xRTAuXjm0GYdmY3Sk3/polGMu5
    NHmi5293eAxJ+9ikSD+bYCaLCXFI2PmgJkm+uS1WucqQOSAKOXS6mfsv2pn9YXKw
    QCMIqX4p7BmO7OD1CFEu6ho=
    -----END PRIVATE KEY-----
    

    PEM_write_bio_PKCS8PrivateKey (PEM)。通知BEGIN PRIVATE KEY

    $ cat rsa-private-2.pem
    -----BEGIN PRIVATE KEY-----
    MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCaQP6TCVuya/JR
    g4G5WTJYPIE3EZA0mspRm73tn6EEbc4Dzl9jqhUJ3KhP4oOa0AWBOBjvopGQdVhA
    fcdgWl5zm82m0sk13o5UkJdHo0VRHZvtocuSt6yrI8ysAc1TXrCnzmp0cAs13vYS
    hQ+RUi0epoE6V3Hsn2/JQXdukBarhfFGVuIr2K9i5yLj+OvimlGiyjotmb0ifObn
    fNi3YCodRlD7daAr5zNnKTy0sYQ3uu0tnuim9UBoCJEZaJRYAK1HCakCrYvk+5Zm
    Rh1DtZCKCTHlzfHyIGR4SHTbbOpiQY5OHZR7hR+shi5KqMtvZ36OR9lDVLgtAtA+
    0zE1X8WrAgMBAAECggEAWybDCJJEHGgLdj22v5dE171RQgBf7aX2nkjg7/UfSiW0
    0qz100gjTIOW9jXNPQNl7Vj/60NuryWYc+ufkIF2ROyxlr4CZpHQG4qhypRhlrBf
    fwnX6Sgeobby8EXUVkqjK1YftBStmzTYxlLYwzADN5R+0sHvsTr57LyB3dTJgKsn
    4iAuJXfR4EthZ6iEM+D8FrmXt5lJ2d1FoMLKiC09M7nMuY9ARqR6O5Tr/Tq4vqfw
    La6Mv3mWrD2nIznyTJtxUkAxvCRi1tfHOw2YCl6u2JqqWRjLBeaGNyydhGeVH5PT
    utPHtDciCxpUgGuQ8wNBEstiGYXklpLJFS48+bWVCQKBgQDLC4DNeZ/Tc9g+WUFU
    ypVCTKfCYt2YmLcNeKDqIPdt14PmV3odIxZGJ1OWrNK1LA50pet0xxY1HRjcBsN+
    XUIc5Xa/0nWazdz7c0nqzZgOpVYfPcApQ1K/dqsoWzRY+rlz2PEOYJwMaKW/kkVV
    8EPEg38Ck/qr5iKsBYljTteHhQKBgQDCe+iKtPjlFPJ4WX8vTu5QVpRjYmqj87/j
    4JFpSh7Lv2PsxSCGQR/7JoyB8Zaz9dyP+RV8/ySJuwGqSseU+W495h8oHe1DtIxU
    lTR1GB4YI4BU+txvydzQiaFyEUdEFqJblCxXg+XDAcwCUYESLbR661ljbVV/0Qep
    HMTeXgfnbwKBgDPMYHSK1ZItGHp3bKpD8CX0xktZy2xVcUV3g52XAWg9NcH6iQWL
    4O/Oso1a03oynhF2DoZBD9JG9QOUmiTPh8E1bMDs4OG4KOrg83d6MZNy7HCV4ULl
    kOOVU369HbKha9Q5AO4JCWZFABvKJfQRkkg8v5cZxzY5RJkb5Hu4LlW9AoGACvxg
    2GT8okQapj23934n7BXX7/1BNN2x+zdWP3JWZv/6rwc7nRnUqqU0zqpM7wF2YhOZ
    6SOodrc/ktUCjSHB3nE/VU7LdkWen7CF9A9Ws9pdh29cQFxQwt7jZcQgGHKG3VFz
    Z8Yllmxlj8P23IYEaeUdeYZVjBDMs/rSDBWXsLUCgYEAw4TTKH/4BdnRIKhNLp63
    n8oGo7Cc/idSQD8XbUVpPbLmychOs2no3Y0XT+xRTAuXjm0GYdmY3Sk3/polGMu5
    NHmi5293eAxJ+9ikSD+bYCaLCXFI2PmgJkm+uS1WucqQOSAKOXS6mfsv2pn9YXKw
    QCMIqX4p7BmO7OD1CFEu6ho=
    -----END PRIVATE KEY-----
    

    PEM_write_bio_RSAPrivateKey (PEM)。通知BEGIN RSA PRIVATE KEY

    $ cat rsa-private-3.pem 
    -----BEGIN RSA PRIVATE KEY-----
    MIIEowIBAAKCAQEAtRZEW6EXwMv2j4mZOhPv3GHcVTi2k8rNlaHc//wUfIYxmNPE
    zzPd0JBUyT/dbRzwrPMrnmzgdFRidbpyplatCNhq+Httog+Cxd6MdxqGAqOI/X5p
    6uxFK8/ptR7E84XpclUQSw+X8VxaG4SFDeMYAuGgw4bIezfFoIySdL16UVIjtSzj
    aRoG1R8kZFtfKONukoqmQUPwFpLvbxE0u6/pzWk873EiM9w6+zZ3c4NAc0ehzfzA
    0maQfjbmVSRihplbocreRXLCaaCYUqAf0K3l4NOYBzVOxBeG03wzsZ0J+nWc5zIW
    b6auwqBYTO7gMRFXO5vFQZXKaSsEc+B/KwztUwIDAQABAoIBAQCjKDTe+f4Uz7CP
    E0LjeSMcRW/nuPmHn6orr3MXkWBD8gSt1d/1cJ3iVKiPyuMOdIzExzP9wctaBM3R
    lPPHu0CcP6Hh0BOveJoy/ZlBlrw3lHDRNRzpdYe9Oc8wSVDauUTkpo/PkXUtGjB1
    qqjXIk14CyJ2CPKJUm7VgNJULIQQz5Uh7rMZjK1FvlcLU+v06nHHC4y0w9X/ygXq
    UoFKKlEADcPqHR/imhrozQxqC4wtn6xFiT/cDngazoGqMX5NCZpso1OZChu3vdAa
    PYOz/Wv22C+JIK0xgDIfgTh01IyAedeI2ABQeKrak0nU6Faer2Y6cMvHhidG95/v
    lmIfSqwBAoGBANroQDoZDVYQ7ToYPNd9MIgb217Ug7I6j/NEpGJjUktxeRzgZKDv
    U5rdbaAArhLXY4FZ0UTZ3WytN1wwV1yXo3Ey5l5CzCXN4GYmv41Z57D218fE7mnx
    T8OKD4SxznYcayCWtbjlTXC13rz3gYT3XgyKwTpuywabhOMjDpaos+wTAoGBANPF
    c2uTIPNq+RUouqTnxyBg+/ujwcF32F5n2Rad9cv1NdtZ22JdotKIpSEnvifqbtGG
    od7vWg5gWgtoG67852K5Q5oBELkcPz4r9PmbSo9H9VWuYotCwB3hvZnIA5GFkfW6
    7pLY3j1gdLqMUm0yHPx4or53ScgU9pnYRFJ6UKHBAoGATTE05MfMwhq57JB7c+l7
    YaOhGbGKtyCbfkcoSGGJtXzQHnSqR23dZ3DJpXBX8eDt/8DyYHsK77WtHd8WD1qR
    ketG/NpFLteIV702MtwPLYH92T4CbG1hmSxoCHzCtzeSNy2t6wNA6YvYfX4xt/ea
    vIV5WeeTxEK2+3lzPYFD4O0CgYA+KGJsXM77I5bgowfFh1JnKpBLmBEy3B5h91E8
    1jhjGSIptAI0qQ81hG4TgTrLNIA6d63jZZWlSpqjZndZsVmpHH+/IDjsXGIjuXs6
    GF6WF6Tm9Txva7RAERY5oP+LIw1odum3qHfyw/D/IFjBPEhNworiJNk/JQgMt/G1
    07j/AQKBgHF2AoovqkCVx0TyggVkwBxwrQvR4jmUYmLKYWYc+IkDQzESXIUme61b
    OZ7OfbTKQHBTz7i8bXK5mWSbNgmhcVsKHnbPyXKIrL7p+j2b2gdSNAaP1c5XFI/l
    BvQSuumzUXbzQHbsYjn/4phOv3AK1xGLhnVI69QpaCYYuuPyfm1X
    -----END RSA PRIVATE KEY-----
    

    i2d_RSAPublicKey_bio(ASN.1/DER):

    $ dumpasn1 rsa-public.der 
      0 266: SEQUENCE {
      4 257:   INTEGER
           :     00 9A 40 FE 93 09 5B B2 6B F2 51 83 81 B9 59 32
           :     58 3C 81 37 11 90 34 9A CA 51 9B BD ED 9F A1 04
           :     6D CE 03 CE 5F 63 AA 15 09 DC A8 4F E2 83 9A D0
           :     05 81 38 18 EF A2 91 90 75 58 40 7D C7 60 5A 5E
           :     73 9B CD A6 D2 C9 35 DE 8E 54 90 97 47 A3 45 51
           :     1D 9B ED A1 CB 92 B7 AC AB 23 CC AC 01 CD 53 5E
           :     B0 A7 CE 6A 74 70 0B 35 DE F6 12 85 0F 91 52 2D
           :     1E A6 81 3A 57 71 EC 9F 6F C9 41 77 6E 90 16 AB
           :             [ Another 129 bytes skipped ]
    265   3:   INTEGER 65537
           :   }
    
    0 warnings, 0 errors.
    

    i2d_RSAPrivateKey_bio(ASN.1/DER):

    $ dumpasn1 rsa-private.der 
       0 1187: SEQUENCE {
       4    1:   INTEGER 0
       7  257:   INTEGER
             :     00 9A 40 FE 93 09 5B B2 6B F2 51 83 81 B9 59 32
             :     58 3C 81 37 11 90 34 9A CA 51 9B BD ED 9F A1 04
             :     6D CE 03 CE 5F 63 AA 15 09 DC A8 4F E2 83 9A D0
             :     05 81 38 18 EF A2 91 90 75 58 40 7D C7 60 5A 5E
             :     73 9B CD A6 D2 C9 35 DE 8E 54 90 97 47 A3 45 51
             :     1D 9B ED A1 CB 92 B7 AC AB 23 CC AC 01 CD 53 5E
             :     B0 A7 CE 6A 74 70 0B 35 DE F6 12 85 0F 91 52 2D
             :     1E A6 81 3A 57 71 EC 9F 6F C9 41 77 6E 90 16 AB
             :             [ Another 129 bytes skipped ]
     268    3:   INTEGER 65537
     273  256:   INTEGER
             :     5B 26 C3 08 92 44 1C 68 0B 76 3D B6 BF 97 44 D7
             :     BD 51 42 00 5F ED A5 F6 9E 48 E0 EF F5 1F 4A 25
             :     B4 D2 AC F5 D3 48 23 4C 83 96 F6 35 CD 3D 03 65
             :     ED 58 FF EB 43 6E AF 25 98 73 EB 9F 90 81 76 44
             :     EC B1 96 BE 02 66 91 D0 1B 8A A1 CA 94 61 96 B0
             :     5F 7F 09 D7 E9 28 1E A1 B6 F2 F0 45 D4 56 4A A3
             :     2B 56 1F B4 14 AD 9B 34 D8 C6 52 D8 C3 30 03 37
             :     94 7E D2 C1 EF B1 3A F9 EC BC 81 DD D4 C9 80 AB
             :             [ Another 128 bytes skipped ]
      ...
    

    该程序是用 C++ 编写的,即使您有一个 C 标签。它允许我们避免大量的错误检查和清理,因为它是自动的。而且它很容易转换回 C。

    #include <memory>
    using std::unique_ptr;
    
    #include <openssl/bn.h>
    #include <openssl/rsa.h>
    #include <openssl/pem.h>
    #include <openssl/bio.h>
    #include <openssl/x509.h>
    
    #include <cassert>
    #define ASSERT assert
    
    using BN_ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
    using RSA_ptr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
    using EVP_KEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
    using BIO_FILE_ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>;
    
    int main(int argc, char* argv[])
    {
        int rc;
    
        RSA_ptr rsa(RSA_new(), ::RSA_free);
        BN_ptr bn(BN_new(), ::BN_free);
    
        BIO_FILE_ptr pem1(BIO_new_file("rsa-public-1.pem", "w"), ::BIO_free);
        BIO_FILE_ptr pem2(BIO_new_file("rsa-public-2.pem", "w"), ::BIO_free);
        BIO_FILE_ptr pem3(BIO_new_file("rsa-private-1.pem", "w"), ::BIO_free);
        BIO_FILE_ptr pem4(BIO_new_file("rsa-private-2.pem", "w"), ::BIO_free);
        BIO_FILE_ptr pem5(BIO_new_file("rsa-private-3.pem", "w"), ::BIO_free);
        BIO_FILE_ptr der1(BIO_new_file("rsa-public.der", "w"), ::BIO_free);
        BIO_FILE_ptr der2(BIO_new_file("rsa-private.der", "w"), ::BIO_free);
    
        rc = BN_set_word(bn.get(), RSA_F4);
        ASSERT(rc == 1);
    
        // Generate key
        rc = RSA_generate_key_ex(rsa.get(), 2048, bn.get(), NULL);
        ASSERT(rc == 1);
    
        // Convert RSA to PKEY
        EVP_KEY_ptr pkey(EVP_PKEY_new(), ::EVP_PKEY_free);
        rc = EVP_PKEY_set1_RSA(pkey.get(), rsa.get());
        ASSERT(rc == 1);
    
        //////////
    
        // Write public key in ASN.1/DER
        rc = i2d_RSAPublicKey_bio(der1.get(), rsa.get());
        ASSERT(rc == 1);
    
        // Write public key in PKCS PEM
        rc = PEM_write_bio_RSAPublicKey(pem1.get(), rsa.get());
        ASSERT(rc == 1);       
    
        // Write public key in Traditional PEM
        rc = PEM_write_bio_PUBKEY(pem2.get(), pkey.get());
        ASSERT(rc == 1);
    
        //////////
    
        // Write private key in ASN.1/DER
        rc = i2d_RSAPrivateKey_bio(der2.get(), rsa.get());
        ASSERT(rc == 1);
    
        // Write private key in PKCS PEM.
        rc = PEM_write_bio_PrivateKey(pem3.get(), pkey.get(), NULL, NULL, 0, NULL, NULL);
        ASSERT(rc == 1);
    
        // Write private key in PKCS PEM
        rc = PEM_write_bio_PKCS8PrivateKey(pem4.get(), pkey.get(), NULL, NULL, 0, NULL, NULL);
        ASSERT(rc == 1);
    
        // Write private key in Traditional PEM
        rc = PEM_write_bio_RSAPrivateKey(pem5.get(), rsa.get(), NULL, NULL, 0, NULL, NULL);
        ASSERT(rc == 1);
    
        return 0;
    }
    

    【讨论】:

    • TIL,我不知道你可以用 unique_ptr 做到这一点。太酷了。
    • 使用旧的RSA_generate_key() 时,需要调用RSA_check_key() 以确保密钥有效。 _ex 变体不需要这样做吗?
    【解决方案3】:

    在使用 RAND_add 正确播种 PRNG 后,您将使用 RSA_generate_key_ex

    编辑: 虽然最初编写此答案时需要调用 RAND_add,但当前版本的 OpenSSL 不再需要手动播种 PRNG。

    【讨论】:

    • Plus One 用于先致电RAND-add
    【解决方案4】:

    kExp=3 可能是一个安全漏洞,请改用 65537。这个问题被称为“小 RSA 指数”,参见例如http://en.wikipedia.org/wiki/Coppersmith%27s_Attackhttp://www.usna.edu/Users/math/wdj/book/node45.html 也请使用超过 1024 位。

    【讨论】:

    • 不是问题的答案。如果您正在尝试这样做,那么您最终将在另一个答案上获得足够的代表。
    • 但是如果你把它放在 Fred 的回答之后会非常有用