Tengo una clave privada que se generó ejecutando:
openssl req -new -sha384 -x509 -days 63524 -subj "/C=CA/ST=State/L=City/O=Org/CN=Org-CA" -extensions v3_ca -keyout Org-CA.key -out Org-CA.pem -passout pass:pass1234Necesito usar esta clave privada y este certificado para firmar las CSR de los clientes. Solía usar OpenSSL para hacer esto, pero necesito hacerlo en C# en su lugar.
He encontrado ejemplos de lo que quiero hacer en línea, pero esos ejemplos usan un castillo hinchable y una clave privada sin cifrar.
El archivo clave se ve así:
-----BEGIN ENCRYPTED PRIVATE KEY----- .... -----END ENCRYPTED PRIVATE KEY-----Y estoy tratando de cargarlo haciendo esto:
var privatekey = File.ReadAllBytes(@"Org-CA.key"); var rsaKeyParameters = PrivateKeyFactory.DecryptKey("pass1234".ToArray(), privatekey); Pero eso no funciona. Recibo un error que dice Wrong number of elements in sequence (Parameter 'seq')'
¿Es así como se supone que debo descifrar y cargar la clave privada?
Dependiendo de su versión de .NET, es posible que no necesite BouncyCastle en absoluto. A partir de .NET Core 3.1, existe RSA.ImportEncryptedPkcs8PrivateKey() para claves privadas cifradas PKCS#8 codificadas con DER y, a partir de .NET 5.0, incluso existe RSA.ImportFromEncryptedPem() para claves cifradas codificadas con PEM.
De lo contrario, con C#/BouncyCastle, la importación de una clave PKCS#8 privada cifrada está disponible, por ejemplo, con:
using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.OpenSsl; ... string encPkcs8 = @"-----BEGIN ENCRYPTED PRIVATE KEY----- ... -----END ENCRYPTED PRIVATE KEY-----"; StringReader stringReader = new StringReader(encPkcs8); PemReader pemReader = new PemReader(stringReader, new PasswordFinder("<your password>")); RsaPrivateCrtKeyParameters keyParams = (RsaPrivateCrtKeyParameters)pemReader.ReadObject(); ... con la siguiente implementación de la interfaz IPasswordFinder :
private class PasswordFinder : IPasswordFinder { private string password; public PasswordFinder(string pwd) => password = pwd; public char[] GetPassword() => password.ToCharArray(); } Si es necesario, es posible una conversión de keyParams a System.Security.Cryptography.RSAParameters con:
using Org.BouncyCastle.Security; ... RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(keyParams); que se puede importar directamente, por ejemplo, con RSA.ImportParameters() .
Editar:
Después de buscar en el código fuente de C#/BouncyCastle, su camino también es posible (que no sabía antes).
DecryptKey() tiene varias sobrecargas, una de las cuales puede manejar la clave cifrada codificada DER como ya sospechaba Maarten Bodewes en su comentario. Este último se puede generar fácilmente con la clase Org.BouncyCastle.Utilities.IO.Pem.PemReader() .
Tenga en cuenta que este PemReader es diferente del de la primera implementación (diferentes espacios de nombres), razón por la cual uso el espacio de nombres explícitamente en el siguiente fragmento de código. Con este enfoque, la instancia de RsaPrivateCrtKeyParameters se puede generar de la siguiente manera:
using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Parameters; ... StringReader stringReader = new StringReader(encPkcs8); Org.BouncyCastle.Utilities.IO.Pem.PemReader pemReader = new Org.BouncyCastle.Utilities.IO.Pem.PemReader(stringReader); Org.BouncyCastle.Utilities.IO.Pem.PemObject pem = pemReader.ReadPemObject(); RsaPrivateCrtKeyParameters keyParams = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.DecryptKey("<your password>".ToCharArray(), pem.Content); ... pem.Content contiene la clave privada cifrada PKCS#8 codificada con DER.