0

From my certificat, I want to retrieve the public key then decrypt my message. I use X509Certificate2 to get information from my certificat then RSA class to decrypt but I have the error : key doesn't exist.

I see here Best way to initiate RSACryptoServiceProvider from x509Certificate2?:

"Since .NET 4.6, casting to RSACryptoServiceProvider as suggested by is no longer recommended. This is even more an issue now since there are several versions of .NET (such as .NET Core).

By casting to RSACryptoServiceProvider that way, there is a good chance you might get this cast exception (depending on the platform and libraries used):

Unable to cast object of type 'System.Security.Cryptography.RSACng' to type 'System.Security.Cryptography.RSACryptoServiceProvider'

The reason is the actual implementation could be different from each platform, on Windows RSACng is used."

So I try to use the RSA class instead of RSACryptoServiceProvider.

     string pemcert;

     X509Certificate2 Lcertificate = new X509Certificate2(Encoding.UTF8.GetBytes(pemcert));

     //my message
     byte[] bytesCypherText = Convert.FromBase64String(b64_crypted_text);

     using (RSA LRSApublicKeyProvider = Lcertificate.GetRSAPublicKey())
     {

        string decrypted = Encoding.UTF8.GetString((LRSApublicKeyProvider.Decrypt(bytesCypherText, RSAEncryptionPadding.Pkcs1)));
        return decrypted;
     }

I have this error :

     Certificat: Error => key doesn't exist
       /  System.Security.Cryptography.CryptographicException

       Certificat. StackTrace :    à System.Security.Cryptography.NCryptNative.DecryptData[T](SafeNCryptKeyHandle key, Byte[] data, T& paddingInfo, AsymmetricPaddingMode paddingMode, NCryptDecryptor`1 decryptor)
        à System.Security.Cryptography.NCryptNative.DecryptDataPkcs1(SafeNCryptKeyHandle key, Byte[] data)
        à System.Security.Cryptography.RSACng.Decrypt(Byte[] data, RSAEncryptionPadding padding)
        à EA_Crocodile.CryptoHelper.RSADecryptJEAM(String b64_crypted_text, String pemcert) 

If I do :

     Lcertificate.GetPublicKeyString() I have the key: 3082020A0282020100B39A5....

If I do :

     Lcertificate.GetRSAPublicKey().ToString(): System.Security.Cryptography.RSACng

why the GetRSAPublicKey() seems not have the public key ? Is it the best way to decrypt ?

Florent
  • 1
  • 3

1 Answers1

1

RSA public keys can only be used for encryption or signature verification.

For decryption you need the private key (GetRSAPrivateKey, which requires that the cert knows where to find it).

bartonjs
  • 30,352
  • 2
  • 71
  • 111
  • From the client I need to use the server public key to encrypt. then I send the encrypted message to server and server can decrypt with his private key. I thing it doesn' t matter public or private key for the function to encrypt, for him it's just a key. – Florent Sep 09 '19 at 19:32
  • Okay... so why are you calling Decrypt then? :) – bartonjs Sep 09 '19 at 19:33
  • because when the server sends me something, the server crypted with his private key so I need to decrypt with his public key. I need to do encrypt and decrypt – Florent Sep 09 '19 at 19:38
  • @florent I highly doubt the server encrypted anything with their private key, and if they did there’s not a way for you to solve your problem with built-in crypto types in .NET. If they Signed data you can Verify it with the public key, but Encrypt is public key and Decrypt is private key. Applying the encryption padding and then using the private key to transform the data is mathematically possible, but extraordinarily non-standard. The “key not found” error is that you are doing Decrypt (a private key operation) with a public key (the private half is what is “not found”). – bartonjs Sep 09 '19 at 20:21
  • You say: "Encrypt is public key and Decrypt is private key." I don't thing it is so specific I want to do. With BouncyCastle it's possible : `var decryptEngine = new Pkcs1Encoding(new Org.BouncyCastle.Crypto.Engines.RsaEngine()); decryptEngine.Init(false, cert.GetPublicKey()); string decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesCypherText, 0, bytesCypherText.Length));` For example in php there is : `openssl_public_encrypt / openssl_private_decrypt(). and openssl_private_encrypt / openssl_public_decrypt().` Is it really not possible in rsa class ? – Florent Sep 10 '19 at 09:09
  • @Florent it is not possible with the RSA class, no. The PHP openssl_public_decrypt is a primitive for decomposing a signature for verification. As I said, the operation is mathematically possible, but it is not a defined operation and conforms to no standard. .NET does not expose “raw” RSA or non-standard RSA. Perhaps Bouncy Castle can meet your needs if the scheme really is using non-standard RSA. – bartonjs Sep 10 '19 at 17:25