在 .Net 中使用 OpenSSL RSA 密钥
Use OpenSSL RSA key with .Net
我正在使用 openssl 0.9.6g,并且我使用 RSA_generate_key() 创建了 public/private 密钥对。当我用 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 public 密钥从 pkcs#1 格式转换为 x509 格式。
I am using openssl 0.9.6g and I have created public/private keypair
using RSA_generate_key(). It gives me keys like:
-----BEGIN RSA PUBLIC KEY-----
...
-----END RSA PUBLIC KEY-----
I think what I am looking for is "how to convert rsa public key from pkcs#1 to x509 format.
是的,.Net 可以使用一些 ASN.1/DER 编码密钥和一些 PEM 编码密钥。不同之处在于 PKCS 编码与传统编码(OpenSSL 称之为 "Traditional")。传统的编码是 SubjectPublicKeyInfo,它包括 OID 和 public 密钥。
所以您正在寻找写入 SubjectPublicKeyInfo 而不仅仅是 public 密钥的 ASN.1/DER 编码或 PEM 编码。
I have another module in .NET which throws an exception when passed in
this key due to its format. It takes format like:
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
在这种情况下,使用 PEM_write_bio_PUBKEY
而不是 PEM_write_bio_RSAPublicKey
。
PEM_write_bio_PUBKEY
写入 SubjectPublicKeyInfo;而 PEM_write_bio_RSAPublicKey
只写入 public 键。
您将需要一个 EVP_PKEY
,因此请使用 EVP_PKEY_set1_RSA
进行转换。
这是 OpenSSL 中的 PKCS 密钥。它只是 public 键。您将使用 PEM_write_RSAPublicKey
来编写它:
-----BEGIN RSA PUBLIC KEY-----
这是 OpenSSL 中的 传统 密钥。它是 SubjectPublicKeyInfo,它包括算法的 OID (rsaEncryption
) 和 public 密钥。你会用 PEM_write_bio_PUBKEY
来写它:
-----BEGIN PUBLIC KEY-----
而不是用 PEM_write_RSAPublicKey
保存密钥,你应该用 i2d_RSA_PUBKEY_bio
写出 ASN.1/DER 格式的 SubjectPublicKeyInfo 结构;或者用 PEM_write_bio_PUBKEY
.
以 PEM 格式写出来
下面的程序创建一个 RSA 密钥对,然后写出所有格式的 public 密钥。一定要保存私钥。
(我很高兴你有 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
增加了引用计数,因此您不会在双重释放时遇到段错误。
执行程序后,得到预期的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.
相关,参见How to generate RSA private key using openssl?。它向您展示了如何以多种格式编写 RSA public 和私钥。
我正在使用 openssl 0.9.6g,并且我使用 RSA_generate_key() 创建了 public/private 密钥对。当我用 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 public 密钥从 pkcs#1 格式转换为 x509 格式。
I am using openssl 0.9.6g and I have created public/private keypair using RSA_generate_key(). It gives me keys like:
-----BEGIN RSA PUBLIC KEY----- ... -----END RSA PUBLIC KEY-----
I think what I am looking for is "how to convert rsa public key from pkcs#1 to x509 format.
是的,.Net 可以使用一些 ASN.1/DER 编码密钥和一些 PEM 编码密钥。不同之处在于 PKCS 编码与传统编码(OpenSSL 称之为 "Traditional")。传统的编码是 SubjectPublicKeyInfo,它包括 OID 和 public 密钥。
所以您正在寻找写入 SubjectPublicKeyInfo 而不仅仅是 public 密钥的 ASN.1/DER 编码或 PEM 编码。
I have another module in .NET which throws an exception when passed in this key due to its format. It takes format like:
-----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----
在这种情况下,使用 PEM_write_bio_PUBKEY
而不是 PEM_write_bio_RSAPublicKey
。
PEM_write_bio_PUBKEY
写入 SubjectPublicKeyInfo;而 PEM_write_bio_RSAPublicKey
只写入 public 键。
您将需要一个 EVP_PKEY
,因此请使用 EVP_PKEY_set1_RSA
进行转换。
这是 OpenSSL 中的 PKCS 密钥。它只是 public 键。您将使用 PEM_write_RSAPublicKey
来编写它:
-----BEGIN RSA PUBLIC KEY-----
这是 OpenSSL 中的 传统 密钥。它是 SubjectPublicKeyInfo,它包括算法的 OID (rsaEncryption
) 和 public 密钥。你会用 PEM_write_bio_PUBKEY
来写它:
-----BEGIN PUBLIC KEY-----
而不是用 PEM_write_RSAPublicKey
保存密钥,你应该用 i2d_RSA_PUBKEY_bio
写出 ASN.1/DER 格式的 SubjectPublicKeyInfo 结构;或者用 PEM_write_bio_PUBKEY
.
下面的程序创建一个 RSA 密钥对,然后写出所有格式的 public 密钥。一定要保存私钥。
(我很高兴你有 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
增加了引用计数,因此您不会在双重释放时遇到段错误。
执行程序后,得到预期的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.
相关,参见How to generate RSA private key using openssl?。它向您展示了如何以多种格式编写 RSA public 和私钥。