在 .Net 中使用 OpenSSL RSA 密钥

时间:2023-02-03
本文介绍了在 .Net 中使用 OpenSSL RSA 密钥的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我正在使用 openssl 0.9.6g 并且我已经使用 RSA_generate_key() 创建了公共/私有密钥对.当我用 PEM_write_bio_RSAPublicKey 保存密钥时,它给了我这样的密钥:

I am using openssl 0.9.6g and I have created public/private keypair using RSA_generate_key(). When I save the key with PEM_write_bio_RSAPublicKey, it gives me keys like:

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

我在 .NET 中有另一个模块,由于其格式,当传入此键时会引发异常.它采用如下格式:

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-----

如何将我的密钥转换为这种格式.我正在使用 C++.

How to convert my keys to this format. I am using C++.

在.NET中,我使用的是openssl.net,代码如下:

In .NET, I am using openssl.net, the code is as follows:

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 格式.

I was looking around for this issue. I think what I am looking for is "how to convert rsa public key from pkcs#1 to x509 format.

推荐答案

我正在使用 openssl 0.9.6g 并且我已经创建了公钥/私钥对使用 RSA_generate_key().它给了我这样的键:

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-----

我想我正在寻找的是如何将 rsa 公钥从 pkcs#1 转换为 x509 格式.

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 称之为传统").传统的编码是 SubjectPublicKeyInfo,它包括 OID 和公钥.

Yeah, .Net can consume some ASN.1/DER encoded keys, and some PEM encoded keys. The difference is PKCS encoding versus Traditional encoding (OpenSSL calls it "Traditional"). The traditional encoding is the SubjectPublicKeyInfo and it includes the OID and the public key.

因此,您正在寻找写入 SubjectPublicKeyInfo 而不仅仅是公钥的 ASN.1/DER 编码或 PEM 编码.

So you are looking for either an ASN.1/DER encoding or a PEM encoding that writes SubjectPublicKeyInfo, and not just the public key.

我在 .NET 中有另一个模块,它在传入时抛出异常此密钥由于其格式.它采用如下格式:

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.

In this case, use PEM_write_bio_PUBKEY rather than PEM_write_bio_RSAPublicKey.

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

PEM_write_bio_PUBKEY writes the SubjectPublicKeyInfo; while PEM_write_bio_RSAPublicKey writes only the public key.

您将需要一个 EVP_PKEY,因此请使用 EVP_PKEY_set1_RSA 进行转换.

You will need an EVP_PKEY, so use EVP_PKEY_set1_RSA to convert it.

这是 OpenSSL 中的 PKCS 密钥.它只是公钥.您可以使用 PEM_write_RSAPublicKey 来编写它:

This is a PKCS key in OpenSSL. Its just the public key. You would use PEM_write_RSAPublicKey to write it:

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

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

And this is a Traditional key in OpenSSL. Its the SubjectPublicKeyInfo, and it includes an OID for the algorithm (rsaEncryption) and the public key. You would use PEM_write_bio_PUBKEY to write it:

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

<小时>

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


Instead of saving the key with PEM_write_RSAPublicKey, you should write out the SubjectPublicKeyInfo structure in ASN.1/DER format with i2d_RSA_PUBKEY_bio; or write it out in PEM format with PEM_write_bio_PUBKEY.

下面的程序创建一个 RSA 密钥对,然后写出所有格式的公钥.一定要保存私钥.

The program below creates a RSA key pair, and then writes out the public key in all the formats. Be sure to save the private key, too.

(我很高兴你有 C++ 标签.unique_ptr 让这个练习变得更容易).

(And I'm glad you have the C++ tag. unique_ptr makes this exercise so much easier).

#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 会增加引用计数,因此您不会在双重释放时出现段错误.

The set1 in EVP_PKEY_set1_RSA bumps the reference count, so you don't get a segfault on a double free.

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

After executing the program, you get the expected PEM and 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.

<小时>

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


Related, see How to generate RSA private key using openssl?. It shows you how to write a RSA public and private key in a number of formats.

这篇关于在 .Net 中使用 OpenSSL RSA 密钥的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:如何通过 .NET 使用 RSA 和 SHA256 对文件进行签名? 下一篇:C# RSA 公钥输出不正确

相关文章

最新文章