在.net中使用OpenSSL RSA密钥

Use OpenSSL RSA key with .Net

本文关键字:OpenSSL RSA 密钥 net      更新时间:2023-10-16

我使用openssl 0.9.6g,我使用RSA_generate_key()创建了公共/私有密钥对。当我用PEM_write_bio_RSAPublicKey保存密钥时,它会给我这样的密钥:

-----BEGIN RSA PUBLIC KEY-----
...
-----END RSA PUBLIC KEY-----

我在。net中有另一个模块,由于其格式,当传入此键时抛出异常。它采用如下格式:

-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----

如何将我的键转换为此格式。我正在使用c++。

在。net中,我使用openssl.net,代码如下:

string publicKey = @"-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAKGtqUVBBqcGCRYa7Sb6JVQirOX3hggWP2k7CzEtbF/soOONK510Kefm
omXBrGn2t79ES+hAcCvGSiiVZGuEb3UPiznzbiY150SME5nRC+zU0vvdX64ni0Mu
DeUlGcxM1eWSpozO71at6mxLloEMUg0oSWHfAlS5a4LVaURrJqXfAgMBAAE=
-----END RSA PUBLIC KEY-----";
Encoding enc = Encoding.ASCII;
string text = "hello world";
byte[] msg = enc.GetBytes(text);
CryptoKey key = CryptoKey.FromPublicKey(publicKey, "");
RSA rsa = key.GetRSA();
byte[] res = rsa.PublicEncrypt(msg, RSA.Padding.PKCS1);

异常出现在下面一行:

CryptoKey key = CryptoKey.FromPublicKey(publicKey, "");

如果我使用键:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbhcU+fhYmYLESZQAj1hKBXsNY
si0kYHNkxpP7ftxZiTFowWUVXHzQgkcYiCNnp3pt1eG6Vt0WDzyFYXqUUqugvX41
gkaIrKQw/sRiWEx49krcz7Vxr3dufL6Mg3eK7NyWDGsqwFrx/qVNqdhsHg12PGNx
IMY4UBtxin2A8pd4OwIDAQAB
-----END PUBLIC KEY-----

很好。

我正在寻找这个问题。我想我要找的是"如何将rsa公钥从pkcs#1转换为x509格式。

我使用openssl 0.9.6g,我已经创建了公共/私有密钥对使用RSA_generate_key()。它给了我如下键:

-----BEGIN RSA PUBLIC KEY-----
...
-----END RSA PUBLIC KEY-----

我想我要找的是"如何将rsa公钥从pkcs#1转换为x509格式。

是的,. net可以使用一些ASN.1/DER编码的密钥和一些PEM编码的密钥。区别在于PKCS编码与传统编码(OpenSSL称之为"传统")。传统的编码是SubjectPublicKeyInfo,它包括OID和公钥。

所以你正在寻找一个ASN.1/DER编码或PEM编码,写SubjectPublicKeyInfo,而不仅仅是公钥。


我在。net中有另一个模块,当传入时抛出异常此键由于其格式。它采用如下格式:

-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----

在本例中,使用PEM_write_bio_PUBKEY而不是PEM_write_bio_RSAPublicKey

PEM_write_bio_PUBKEY写入SubjectPublicKeyInfo;而PEM_write_bio_RSAPublicKey只写公钥。

你将需要一个EVP_PKEY,所以使用EVP_PKEY_set1_RSA来转换它。


这是OpenSSL中的PKCS密钥。它只是一个公钥。你可以用PEM_write_RSAPublicKey来写:

-----BEGIN RSA PUBLIC KEY-----

这是OpenSSL中的传统密钥。它是SubjectPublicKeyInfo,它包括算法的OID (rsaEncryption)和公钥。您可以使用PEM_write_bio_PUBKEY来写:

-----BEGIN PUBLIC KEY-----

不是用PEM_write_RSAPublicKey保存密钥,你应该用i2d_RSA_PUBKEY_bio以ASN.1/DER格式写出SubjectPublicKeyInfo结构;或者用PEM_write_bio_PUBKEY的PEM格式写出来。

下面的程序创建一个RSA密钥对,然后以所有格式写出公钥。请确保也保存了私钥。

我很高兴你有c++标签。unique_ptr使这个练习更容易)。

#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 der1(BIO_new_file("rsa-public-1.der", "w"), ::BIO_free);
    BIO_FILE_ptr der2(BIO_new_file("rsa-public-2.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 key 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 just the public key in ASN.1/DER
    // Load with d2i_RSAPublicKey_bio
    rc = i2d_RSAPublicKey_bio(der1.get(), rsa.get());
    ASSERT(rc == 1);
    // Write just the public key in PEM
    // Load with PEM_read_bio_RSAPublicKey
    rc = PEM_write_bio_RSAPublicKey(pem1.get(), rsa.get());
    ASSERT(rc == 1);
    // Write SubjectPublicKeyInfo with OID and public key in ASN.1/DER
    // Load with d2i_RSA_PUBKEY_bio
    rc = i2d_RSA_PUBKEY_bio(der2.get(), rsa.get());
    ASSERT(rc == 1);
    // Write SubjectPublicKeyInfo with OID and public key in PEM
    // Load with PEM_read_bio_PUBKEY
    rc = PEM_write_bio_PUBKEY(pem2.get(), pkey.get());
    ASSERT(rc == 1);
    return 0;
}

EVP_PKEY_set1_RSA中的set1增加了引用计数,所以你不会在double free上得到段错误。

执行程序后,您将得到期望的PEM和ASN.1/DER:

$ cat rsa-public-1.pem 
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA0cgFv6wEcqoOhPtHdVmX4YFlCwodnSqooeCxFF1XadTS4sZkVJTC
kszHmRqXiXL2NmqnuDQsq6nLd+sNoU5yJJ+W1hwo7UToCyJ/81tS4n6mXvF8oilP
8YudD5QnBdW9LhqttBIN4Gk+Cxun+HG1rSJLGP9yiPPFd7DPiFz0Gd+juyWznWnP
gapDIWEKqANKma3j6b9eopBDWB0XAgU0HQ71MSNbcsPvDd23Ftx0re/7jG53V7Bn
eBy7fQsPmxcn4c74Lz4CvhOr7VdQpeBzNeG2CtkefKWyTk7Vu4FZnAgNd/202XAr
c6GmEQqD2M2zXH/nVZg5oLznECDVQ1x/pwIDAQAB
-----END RSA PUBLIC KEY-----
$ cat rsa-public-2.pem 
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0cgFv6wEcqoOhPtHdVmX
4YFlCwodnSqooeCxFF1XadTS4sZkVJTCkszHmRqXiXL2NmqnuDQsq6nLd+sNoU5y
JJ+W1hwo7UToCyJ/81tS4n6mXvF8oilP8YudD5QnBdW9LhqttBIN4Gk+Cxun+HG1
rSJLGP9yiPPFd7DPiFz0Gd+juyWznWnPgapDIWEKqANKma3j6b9eopBDWB0XAgU0
HQ71MSNbcsPvDd23Ftx0re/7jG53V7BneBy7fQsPmxcn4c74Lz4CvhOr7VdQpeBz
NeG2CtkefKWyTk7Vu4FZnAgNd/202XArc6GmEQqD2M2zXH/nVZg5oLznECDVQ1x/
pwIDAQAB
-----END PUBLIC KEY-----
$ dumpasn1 rsa-public-1.der 
  0 266: SEQUENCE {
  4 257:   INTEGER
       :     00 D1 C8 05 BF AC 04 72 AA 0E 84 FB 47 75 59 97
       :     E1 81 65 0B 0A 1D 9D 2A A8 A1 E0 B1 14 5D 57 69
       :     D4 D2 E2 C6 64 54 94 C2 92 CC C7 99 1A 97 89 72
       :     F6 36 6A A7 B8 34 2C AB A9 CB 77 EB 0D A1 4E 72
       :     24 9F 96 D6 1C 28 ED 44 E8 0B 22 7F F3 5B 52 E2
       :     7E A6 5E F1 7C A2 29 4F F1 8B 9D 0F 94 27 05 D5
       :     BD 2E 1A AD B4 12 0D E0 69 3E 0B 1B A7 F8 71 B5
       :     AD 22 4B 18 FF 72 88 F3 C5 77 B0 CF 88 5C F4 19
       :             [ Another 129 bytes skipped ]
265   3:   INTEGER 65537
       :   }
0 warnings, 0 errors.
$ dumpasn1 rsa-public-2.der 
  0 290: SEQUENCE {
  4  13:   SEQUENCE {
  6   9:     OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
 17   0:     NULL
       :     }
 19 271:   BIT STRING, encapsulates {
 24 266:     SEQUENCE {
 28 257:       INTEGER
       :         00 D1 C8 05 BF AC 04 72 AA 0E 84 FB 47 75 59 97
       :         E1 81 65 0B 0A 1D 9D 2A A8 A1 E0 B1 14 5D 57 69
       :         D4 D2 E2 C6 64 54 94 C2 92 CC C7 99 1A 97 89 72
       :         F6 36 6A A7 B8 34 2C AB A9 CB 77 EB 0D A1 4E 72
       :         24 9F 96 D6 1C 28 ED 44 E8 0B 22 7F F3 5B 52 E2
       :         7E A6 5E F1 7C A2 29 4F F1 8B 9D 0F 94 27 05 D5
       :         BD 2E 1A AD B4 12 0D E0 69 3E 0B 1B A7 F8 71 B5
       :         AD 22 4B 18 FF 72 88 F3 C5 77 B0 CF 88 5C F4 19
       :                 [ Another 129 bytes skipped ]
289   3:       INTEGER 65537
       :       }
       :     }
       :   }
0 warnings, 0 errors.

相关内容请参见如何使用openssl生成RSA私钥。它向您展示了如何以多种格式编写RSA公钥和私钥。