Шифрование и дешифрование с использованием PFX на нескольких серверах - PullRequest
1 голос
/ 07 марта 2019

В настоящее время я пытаюсь создать систему, которая шифрует данные клиентов и добавляет их в удаленную очередь MSMQ, которая находится на другом сервере.Затем данные отбираются заданием, которое запускается каждую X-минуту, которое будет пытаться расшифровать данные и обрабатывать их.

От нас требуется использование сертификата .PFX для шифрования / дешифрования (Я знаю, что это не самый эффективный способ сделать что-то, но есть требование, и я не могу его изменить).

В настоящее время я использую самоподписанный сертификат с использованием Open-SSL, используя:

openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem

openssl pkcs12 -inkey key.pem -in certificate.pem -export -out certificate.p12

Я успешно зашифровал данные, но каждый раз, когда я пытаюсь расшифровать, я получаю общее исключение «Параметр неверен».

Чтобы загрузить сертификат, у нас есть файл .PFX, сохраненный локально на машинах, и с помощью класса X509Certificate2 мы импортируем его и используем для шифрования и дешифрования.Вот упрощенная версия вспомогательного класса, с которой я работаю:

public static string EncryptData(string data)
{
    var certificate = GetCertificate();

    using (var rsa = certificate.PublicKey.Key as RSACryptoServiceProvider)
    {
        var dataBytes = Convert.FromBase64String(data);
        var encryptedBytes = rsa.Encrypt(dataBytes, false);

        return Convert.ToBase64String(encryptedBytes);
    }
}

public static string DecryptData(string data)
{
    var certificate = GetCertificate();

    using (var rsa = certificate.PrivateKey as RSACryptoServiceProvider)
    {
        var dataBytes = Convert.FromBase64String(data);
        var decryptedBytes = rsa.Decrypt(dataBytes, false);

        return Convert.ToBase64String(decryptedBytes);
    }
}

private static X509Certificate2 GetCertificate()
{   
    var certificate = new X509Certificate2();
    certificate.Import("certificatePath", "certificatePassword", X509KeyStorageFlags.PersistKeySet);
    return certificate;
}

Ошибка всегда возникает при вызове rsa.Decrypt ().

Я попытался сделать следующее:

  • Вызовите «rsa.Decrypt ()» в моем методе «EncryptData» сразу после шифрования.Это работает без проблем, и «rsa.Decrypt» дает мне те же байты, что и исходные байты данных.

  • Вызовите метод «DecryptData» сразу после вызова «EncryptData».Возникает та же проблема, и я получаю исключение с параметром «Неверный параметр»

Вот почему я подозреваю, что создается «новый» X509Certificate2, что закрытый ключ больше не тоти больше не могу расшифровывать данные.

Обратите внимание, что я не эксперт по безопасности и не работал с сертификатами X509 или какой-либо криптографией, поэтому я немного не в себе и могу что-то делать действительноглупо, пожалуйста, дайте мне знать, если я.

Обновление 1 (08/03/2019)

Обновили кодовый код согласно пунктам рекомендаций 1-3 и5 предоставлено @ bartonjs

public static string EncryptData(string data)
{
    var certificate = GetCertificate();

    using (var rsa = certificate.GetRSAPublicKey())
    {
        var dataBytes = Convert.FromBase64String(data);
        var encryptedBytes = rsa.Encrypt(dataBytes, RSAEncryptionPadding.OaepSHA1);

        return Convert.ToBase64String(encryptedBytes);
    }
}

public static string DecryptData(string data)
{
    var certificate = GetCertificate();

    using (var rsa = certificate.GetRSAPrivateKey())
    {
        var dataBytes = Convert.FromBase64String(data);
        var decryptedBytes = rsa.Decrypt(dataBytes, RSAEncryptionPadding.OaepSHA1);

        return Convert.ToBase64String(decryptedBytes);
    }
}

private static X509Certificate2 GetCertificate()
{   
    var certificate = new X509Certificate2("certificatePath", "certificatePassword", X509KeyStorageFlags.PersistKeySet);
    return certificate;
}

Добавлено сообщение об ошибке:

Message: The parameter is incorrect.

Stack Trace:
 at System.Security.Cryptography.NCryptNative.DecryptData[T](SafeNCryptKeyHandle key, Byte[] data, T& paddingInfo, AsymmetricPaddingMode paddingMode, NCryptDecryptor`1 decryptor)
 at System.Security.Cryptography.NCryptNative.DecryptDataOaep(SafeNCryptKeyHandle key, Byte[] data, String hashAlgorithm)
 at System.Security.Cryptography.RSACng.Decrypt(Byte[] data, RSAEncryptionPadding padding)

1 Ответ

0 голосов
/ 07 марта 2019

Извините, что почти все здесь не так.

GetCertificate

private static X509Certificate2 GetCertificate()
{   
    var certificate = new X509Certificate2();
    certificate.Import("certificatePath", "certificatePassword", X509KeyStorageFlags.PersistKeySet);
    return certificate;
}

Вы импортируете с помощью PersistKeySet, поэтому вы медленно заполняете свой жесткий диск. См. Каково обоснование для всех различных X509KeyStorageFlags?

Кроме того, вы используете certificate.Import, который недоступен в .NET Core (поскольку изменение объектов X509Certificate2 является неожиданным). Просто используйте конструктор. Таким образом, весь этот метод должен быть

private static X509Certificate2 GetCertificate()
{
    // Assuming you do nothing else with the certificate than what's shown here,
    // EphemeralKeySet will work for you (except on macOS).
    return new X509Certificate2(path, password, X509KeyStorageFlags.EphemeralKeySet);
}

EncryptData

public static string EncryptData(string data)
{
    var certificate = GetCertificate();

    using (var rsa = certificate.PublicKey.Key as RSACryptoServiceProvider)
    {
        var dataBytes = Convert.FromBase64String(data);
        var encryptedBytes = rsa.Encrypt(dataBytes, false);

        return Convert.ToBase64String(encryptedBytes);
    }
}

Здесь есть пара неправильных вещей.

1) PrivateKey является общим свойством, поэтому, если его прочитали более одного раза, вы бы избавились от объекта из-под другого вызывающего.

2) Вы не утилизируете его, если случайно получили сертификат не RSA

3) Вы используете PrivateKey, который не поддерживает лучшие классы RSA или DSA, которые поддерживают современные опции.

4) Вы единственный обработчик сертификата, но не распоряжались им. Может быть, ваша семантика собственности может быть более ясной.

С точки зрения безопасности также 5) вы используете заполнение PKCS # 1 вместо OAEP

С точки зрения данных также 6) почему шифрованию дают данные base64 вместо необработанных данных?

Я не буду обращаться к №ам 4-6.

public static string EncryptData(string data)
{
    var certificate = GetCertificate();

    using (RSA rsa = certificate.GetRSAPublicKey())
    {
        var dataBytes = Convert.FromBase64String(data);
        var encryptedBytes = rsa.Encrypt(dataBytes, RSAEncryptionPadding.Pkcs1);

        return Convert.ToBase64String(encryptedBytes);
    }
}

В этом случае правильно указать закрытый ключ в операторе using, метод GetRSAPrivateKey() всегда возвращает новый объект.

DecryptData

Расшифровка должна быть изменена аналогично шифрованию.

Если после всего этого вы все еще получаете исключения, пожалуйста, включите точное сообщение и трассировку стека (по крайней мере, части от вызова к RSA.Decrypt до того места, где оно было брошено)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...