Подтвердить что ты не робот

CryptographicException "недействителен для использования в указанном состоянии." при попытке экспорта RSAP-параметров закрытого ключа X509

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

Почему я озадачен: шифрование/дешифрование работает, когда я передаю ссылку самому RSACryptoServiceProvider:

byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider);
string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider);

Но если вы экспортируете и обходите вокруг RSAParameter:

byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false));
string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true));

... он выдает "Ключ, недействительный для использования в указанном состоянии". исключение при попытке экспортировать закрытый ключ в RSAParameter. Обратите внимание, что сертификат, сгенерированный из PFX, отмечен как экспортируемый (т.е. Я использовал флаг pe при создании сертификата). Любая идея, что вызывает исключение?

 static void Main(string[] args)
    {
        X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test");
        x.FriendlyName = "My test Cert";

        X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        store.Open(OpenFlags.ReadWrite);
        try
        {
            store.Add(x);
        }
        finally
        {
            store.Close();
        }

        byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider);
        string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider);

        byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false));
        string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true));
    }

private static byte[] EncryptRSA(string data, RSAParameters rsaParameters)
{
    UnicodeEncoding bytConvertor = new UnicodeEncoding();
    byte[] plainData = bytConvertor.GetBytes(data);

    RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider();
    publicKey.ImportParameters(rsaParameters);
    return publicKey.Encrypt(plainData, true);
}

private static string DecryptRSA(byte[] data, RSAParameters rsaParameters)
{
    UnicodeEncoding bytConvertor = new UnicodeEncoding();

    RSACryptoServiceProvider privateKey = new RSACryptoServiceProvider();
    privateKey.ImportParameters(rsaParameters);

    byte[] deData = privateKey.Decrypt(data, true);
    return bytConvertor.GetString(deData);
}

private static byte[] EncryptRSA(string data, RSACryptoServiceProvider publicKey)
{
    UnicodeEncoding bytConvertor = new UnicodeEncoding();
    byte[] plainData = bytConvertor.GetBytes(data);

    return publicKey.Encrypt(plainData, true);
}

private static string DecryptRSA(byte[] data, RSACryptoServiceProvider privateKey)
{
    UnicodeEncoding bytConvertor = new UnicodeEncoding();

    byte[] deData = privateKey.Decrypt(data, true);
    return bytConvertor.GetString(deData);
}

Чтобы уточнить в коде выше, полужирная часть бросает: string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider)**.ExportParameters(true)**);

4b9b3361

Ответ 1

Я считаю, что проблема может заключаться в том, что ключ не помечен как экспортируемый. Существует еще один конструктор для X509Certificate2, который переводит перечисление X509KeyStorageFlags. Попробуйте заменить строку:

X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test");

При этом:

X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test", X509KeyStorageFlags.Exportable);

Ответ 2

Я встретил некоторую аналогичную проблему, и X509KeyStorageFlags.Exportable решил мою проблему.

Ответ 3

Для проблемы, с которой я столкнулся, изменение кода не было возможным, поскольку одна и та же библиотека была установлена ​​и работала в другом месте.

Иридиум-ответ заставил меня посмотреть, как сделать экспорт ключа, и я смог это сделать как часть мастера импорта сертификатов MMC.

Надеюсь, это поможет кому-то другому. Спасибо кучи

Мастер импорта импорта

Ответ 4

Я не совсем эксперт в этих вещах, но я сделал быстрый google и нашел это:

http://social.msdn.microsoft.com/Forums/en/clr/thread/4e3ada0a-bcaf-4c67-bdef-a6b15f5bfdce

", если в вашем массиве байтов содержится более 245 байтов, которые вы передаете в свой метод RSACryptoServiceProvider.Encrypt(byte [] rgb, bool fOAEP), тогда он выдает исключение."

Ответ 5

AFAIK это должно сработать, и вы, вероятно, столкнетесь с ошибкой/некоторыми ограничениями. Вот несколько вопросов, которые могут помочь вам выяснить, в чем проблема.

  • Как вы создали файл PKCS # 12 (PFX)? Я видел несколько ключей, которые CryptoAPI не нравится (необычные параметры RSA). Можете ли вы использовать другой инструмент (чтобы быть уверенным)?

  • Можно ли экспортировать экземпляр PrivateKey в XML, например. ToXmlString(true), затем загрузите (импортируйте) его обратно таким образом?

  • У старых версий фреймворка возникли некоторые проблемы при импорте ключа, который был другого размера, чем текущий экземпляр (по умолчанию 1024 бит). Каков размер открытого ключа RSA в вашем сертификате?

Также обратите внимание, что это не, как вы должны шифровать данные с помощью RSA. Размер необработанного шифрования ограничен используемым открытым ключом. Зацикливание над этим лимитом приведет только к плохой производительности действительно.

Фокус в том, чтобы использовать симметричный алгоритм (например, AES) с полностью случайным ключом, а затем шифровать этот ключ (обертка) с помощью открытого ключа RSA. Вы можете найти код С# для этого в моей старой записи по этой теме.

Ответ 6

Для других, которые попадают сюда через Google, но не используют X509Certificate2, если вы вызываете ToXmlString на RSACryptoServiceProvider, но вы только загрузили открытый ключ, вы получите это сообщение. Исправлено это (обратите внимание на последнюю строку):

var rsaAlg = new RSACryptoServiceProvider();

rsaAlg.ImportParameters(rsaParameters);

var xml = rsaAlg.ToXmlString(!rsaAlg.PublicOnly);