Encrypt/Decrypt 使用自己生成的证书 C# 失败(缺少私钥)

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

我需要借助 C# 代码生成 RSA 证书(自签名证书)。我使用下面的代码创建了证书。

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

然后,我尝试使用我使用以下代码创建的证书文件来加密数据。

public bool EncryptAndDecryptFile()
{
    string data = "{data: 'mydate123@gmail.com'}";

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

虽然,运行上面的代码我看到了下面的错误。

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

要验证证书,我有以下命令,

certutil -dump MyCertificate.pfx

所以,上面的实用程序给了我下面的输出,

================ 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.

事实上,你在这一行得到了例外:

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

整个加密和解密代码段都不正确,你在乱用旧的已弃用的 RSACryptoServiceProvider 并进行不必要的操作。该方法应如下所示:

public bool EncryptAndDecryptFile() {
    string data = "{data: 'mydate123@gmail.com'}";

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