I currently generate a key pair and then encrypt the private key with a paraphase as you can see in the following code in node with the node-forge library.
const keypair = forge.pki.rsa.generateKeyPair({ bits: 4096 });
const publicKey = forge.pki.publicKeyToPem(keypair.publicKey);
const privateKey = forge.pki.encryptRsaPrivateKey(keypair.privateKey, passphrase, { algorithm: 'aes256' });
However, when I try to do client-side decryption in C# with the BouncyCastle library I get the following error.
public static string DecryptPrivateKey(string privateKey, string passphrase)
{
// Utiliza Bouncy Castle para descifrar la clave privada
AsymmetricCipherKeyPair keyPair;
using (TextReader reader = new StringReader(privateKey))
{
PemReader pemReader = new PemReader(reader, new PasswordFinder(passphrase));
keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
}
// Extrae la clave privada en formato PEM
StringWriter stringWriter = new StringWriter();
PemWriter pemWriter = new PemWriter(stringWriter);
pemWriter.WriteObject(keyPair.Private);
pemWriter.Writer.Flush();
return stringWriter.ToString();
}
private class PasswordFinder : IPasswordFinder
{
private readonly string password;
public PasswordFinder(string password)
{
this.password = password;
}
public char[] GetPassword()
{
return password.ToCharArray();
}
}
"The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters"
I have looked for information so that what Forge generates is compatible with Bouncycastle, but I still cannot achieve it. I would be grateful if you could give me a clue or perhaps a node -> c# implementation that has worked for you. Thank you
C#: .net 6.0, BouncyCastle.NetCore 2.2.1 Node: v16.16.0, node-forge ^1.3.1
privateKey:
-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n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\r\n4ipuuNdc4dxqGyUw/2ttDqulBw==\r\n-----END ENCRYPTED PRIVATE KEY-----\r\n
passphrase: "my-new-secret-key"
The posted key is a PEM encoded, encrypted private RSA key in PKCS#8 format. The C# code, on the other hand, is written for the import of a PEM encoded, encrypted private RSA key in PKCS#1 format, which is why the import fails.
So that the import of the posted key works, the DecryptPrivateKey()
method must be changed as follows:
using Org.BouncyCastle.Crypto.Parameters;
...
public static string DecryptPrivateKey(string privateKey, string passphrase)
{
RsaPrivateCrtKeyParameters privKey;
using (TextReader reader = new StringReader(privateKey))
{
PemReader pemReader = new PemReader(reader, new PasswordFinder(passphrase));
privKey = (RsaPrivateCrtKeyParameters)pemReader.ReadObject();
}
StringWriter stringWriter = new StringWriter();
PemWriter pemWriter = new PemWriter(stringWriter);
pemWriter.WriteObject(privKey);
pemWriter.Writer.Flush();
return stringWriter.ToString();
}
Note the use of the RsaPrivateCrtKeyParameters
type instead of the AsymmetricCipherKeyPair
type.
For completeness: Be aware that the key is exported as PEM encoded private RSA key in PKCS#1 format.
However, in my environment I cannot reproduce the error message you observed, instead I get the (more plausible) message:
System.InvalidCastException: Unable to cast object of type 'Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters' to type 'Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair'.
Note that as of .NET 5 there is a built-in support for importing a PEM encoded, encrypted private RSA key in PKCS#8 format, namely RSA.ImportFromEncryptedPem()
, as well as for PEM encoding, namely PemEncoding
, so BouncyCastle is actually not needed for this.
using System.Security.Cryptography;
...
RSA rsa = RSA.Create();
rsa.ImportFromEncryptedPem(privateKey, Encoding.UTF8.GetBytes(passphrase));
Console.WriteLine(new string(PemEncoding.Write("PRIVATE RSA KEY", rsa.ExportRSAPrivateKey())));