c++ .net openssl rsa

c++ - Utilice la clave OpenSSL RSA con.Net



(1)

Estoy usando openssl 0.9.6g y he creado un par de claves público / privado usando RSA_generate_key (). Me da claves como:

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

Creo que lo que estoy buscando es "cómo convertir la clave pública rsa de pkcs # 1 al formato x509.

Sí, .Net puede consumir algunas claves codificadas ASN.1 / DER y algunas claves codificadas PEM. La diferencia es la codificación PKCS versus la codificación tradicional (OpenSSL lo llama "tradicional"). La codificación tradicional es SubjectPublicKeyInfo e incluye el OID y la clave pública.

Por lo tanto, está buscando una codificación ASN.1 / DER o una codificación PEM que escriba SubjectPublicKeyInfo , y no solo la clave pública.

Tengo otro módulo en .NET que arroja una excepción cuando se pasa en esta clave debido a su formato. Toma formato como:

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

En este caso, use PEM_write_bio_PUBKEY lugar de PEM_write_bio_RSAPublicKey .

PEM_write_bio_PUBKEY escribe el SubjectPublicKeyInfo ; mientras que PEM_write_bio_RSAPublicKey escribe solo la clave pública.

Necesitará un EVP_PKEY , así que use EVP_PKEY_set1_RSA para convertirlo.

Esta es una clave PKCS en OpenSSL. Es solo la clave pública. PEM_write_RSAPublicKey para escribirlo:

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

Y esta es una clave tradicional en OpenSSL. Es el SubjectPublicKeyInfo , e incluye un OID para el algoritmo ( rsaEncryption ) y la clave pública. PEM_write_bio_PUBKEY para escribirlo:

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

En lugar de guardar la clave con PEM_write_RSAPublicKey , debe escribir la estructura SubjectPublicKeyInfo en formato ASN.1 / DER con i2d_RSA_PUBKEY_bio ; o escríbalo en formato PEM con PEM_write_bio_PUBKEY .

El siguiente programa crea un par de claves RSA y luego escribe la clave pública en todos los formatos. Asegúrese de guardar la clave privada también.

(Y me alegra que tenga la etiqueta C ++. unique_ptr hace que este ejercicio sea mucho más fácil).

#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; }

El set1 en EVP_PKEY_set1_RSA el recuento de referencias, por lo que no obtienes un segfault en un doble libre.

Después de ejecutar el programa, obtienes el PEM esperado y 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.

Relacionado, vea ¿Cómo generar una clave privada RSA usando openssl? . Le muestra cómo escribir una clave pública y privada RSA en varios formatos.

Estoy usando openssl 0.9.6g y he creado un par de claves público / privado usando RSA_generate_key (). Cuando PEM_write_bio_RSAPublicKey la clave con PEM_write_bio_RSAPublicKey , me da claves como:

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

Tengo otro módulo en .NET que arroja una excepción cuando se pasa en esta clave debido a su formato. Toma formato como:

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

Cómo convertir mis claves a este formato. Estoy usando C ++.

En .NET, estoy usando openssl.net, el código es el siguiente:

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

La excepción viene en línea:

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

Si uso la clave:

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

Funciona bien.

Estaba buscando este problema. Creo que lo que estoy buscando es "cómo convertir la clave pública rsa de pkcs # 1 al formato x509.