Ошибка шифрования / дешифрования (закрытый ключ отсутствует) с помощью собственного сертификата C# - PullRequest
0 голосов
/ 29 мая 2020

Мне нужно сгенерировать сертификат RSA (самоподписанный сертификат) с помощью кода C#. Я использовал приведенный ниже код для создания сертификата.

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.

1 Ответ

1 голос
/ 29 мая 2020

Фактически, вы получаете исключение в этой строке:

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