Ramachandran
Ramachandran

Reputation: 103

Encrypt/Decrypt failed(private key missing) with ownly generated certificate C#

I need to generate the RSA certificate(self signed certificate) with help of C# code. I have used the below code to create the certificate.

public bool CreateRSACertificate()
{
    RSA rsaKey = RSA.Create();
    CertificateRequest certRequest = new CertificateRequest("cn=MyApplication", rsaKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
    certRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));
    certRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certRequest.PublicKey, false));

    X509Certificate2 certificate = certRequest.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5));

    byte[] certData = certificate.Export(X509ContentType.Pfx, "TestPassword");
    X509Certificate2 cert = new X509Certificate2(certData, "TestPassword", X509KeyStorageFlags.Exportable);

    File.WriteAllBytes("MyCertificate.pfx", cert.Export(X509ContentType.Pfx, "TestPassword"));

    return true;
}

And, after that I try to encrypt the data using the the certificate file which I created using the below code.

public bool EncryptAndDecryptFile()
{
    string data = "{data: '[email protected]'}";

    X509Certificate2 certificate = new X509Certificate2("MyCertificate.pfx", "TestPassword", X509KeyStorageFlags.Exportable);
    if (certificate.HasPrivateKey) {
        Console.WriteLine("Private key available "); // It's says like the private key was available
    }

    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    rsa.FromXmlString(certificate.PublicKey.Key.ToXmlString(false));

    byte[] bytes = Encoding.ASCII.GetBytes(data);
    var encryptedData = rsa.Encrypt(bytes, false); //It seems the data encrypted. I'm not sure.But, I can able to see some encrypted data.

    using (certificate.GetRSAPrivateKey()) {

        RSACryptoServiceProvider drsa = new RSACryptoServiceProvider();
        drsa.FromXmlString(certificate.PrivateKey.ToXmlString(false));
        var decdata = drsa.Decrypt(encryptedData, false); // Here, I see some exception.

        someString = Encoding.ASCII.GetString(decdata);
    }
    Console.WriteLine("someString someString ::: " + someString);

    return true;
}

While, running the above code I see the below error.

Unhandled exception. Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Key not valid for use in specified state.
   at Internal.NativeCrypto.CapiHelper.ExportKeyBlob(Boolean includePrivateParameters, SafeKeyHandle safeKeyHandle)
   at System.Security.Cryptography.RSACryptoServiceProvider.ExportParameters(Boolean includePrivateParameters)
   at ConfigUtility.X509Certificate.ReadRSACertificate()

To verify the certificate I have the below command,

certutil -dump MyCertificate.pfx

So, the above utility gave me the below output,

================ Certificate 0 ================
================ Begin Nesting Level 1 ================
Element 0:
Serial Number: 054834637a713ecf
Issuer: CN=MyApplication
 NotBefore: 29-05-2020 13:49
 NotAfter: 29-05-2025 13:49
Subject: CN=MyApplication
Signature matches Public Key
Root Certificate: Subject matches Issuer
Cert Hash(sha1): 16e83e8a92a38b948adad03a86768e27115851d4
----------------  End Nesting Level 1  ----------------
  Provider = Microsoft Software Key Storage Provider
Private key is NOT plain text exportable
Encryption test passed
CertUtil: -dump command completed successfully.

Upvotes: 0

Views: 1775

Answers (1)

Crypt32
Crypt32

Reputation: 13924

In fact, you get exception in this line:

drsa.FromXmlString(certificate.PrivateKey.ToXmlString(false));

the whole encryption and decryption code pieces are incorrect, you are messing things with old an deprecated RSACryptoServiceProvider and doing unnecessary operations. Here is how the method should look like:

public bool EncryptAndDecryptFile() {
    string data = "{data: '[email protected]'}";

    X509Certificate2 certificate = new X509Certificate2("MyCertificate.pfx", "TestPassword", X509KeyStorageFlags.Exportable);
    if (certificate.HasPrivateKey) {
        Console.WriteLine("Private key available "); // It's says like the private key was available
    }

    Byte[] encryptedData = new Byte[0];
    using (RSA pubKey = certificate.GetRSAPublicKey()) {
        byte[] bytes = Encoding.ASCII.GetBytes(data);
        encryptedData = rsa.Encrypt(bytes, RSAEncryptionPadding.OaepSHA256);
    }

    // assuming, encryptedData is not null
    String someString = String.Empty;
    using (RSA prKey = certificate.GetRSAPrivateKey()) {
        Byte[] decdata = prKey.Decrypt(encryptedData, RSAEncryptionPadding.OaepSHA256);

        someString = Encoding.ASCII.GetString(decdata);
    }

    return data.Equals(someString);
}

Upvotes: 1

Related Questions