Проблема RSA шифрования / дешифрования в .NET - PullRequest
17 голосов
/ 19 марта 2010

У меня проблема с шифрованием и расшифровкой C # с использованием RSA. Я разработал веб-сервис, который будет отправлять конфиденциальную финансовую информацию и транзакции. Я хотел бы иметь возможность на стороне клиента зашифровать определенные поля с помощью закрытого ключа RSA клиента. После того, как он достигнет моей службы, он расшифрует с помощью открытого ключа клиента.

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

Это метод, который я использую для генерации ключей

private void buttonGenerate_Click(object sender, EventArgs e)
{
    string secretKey = RandomString(12, true);

    CspParameters param = new CspParameters();
    param.Flags = CspProviderFlags.UseMachineKeyStore;

    SecureString secureString = new SecureString();
    byte[] stringBytes = Encoding.ASCII.GetBytes(secretKey);
    for (int i = 0; i < stringBytes.Length; i++)
    {
        secureString.AppendChar((char)stringBytes[i]);
    }
    secureString.MakeReadOnly();
    param.KeyPassword = secureString;

    RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(param);
    rsaProvider = (RSACryptoServiceProvider)RSACryptoServiceProvider.Create();
    rsaProvider.KeySize = 1024;


    string publicKey = rsaProvider.ToXmlString(false);
    string privateKey = rsaProvider.ToXmlString(true);

    Repository.RSA_XML_PRIVATE_KEY = privateKey;
    Repository.RSA_XML_PUBLIC_KEY = publicKey;

    textBoxRsaPrivate.Text = Repository.RSA_XML_PRIVATE_KEY;
    textBoxRsaPublic.Text = Repository.RSA_XML_PUBLIC_KEY;

    MessageBox.Show("Please note, when generating keys you must sign on to the gateway\n" +
        " to exhange keys otherwise transactions will fail", "Key Exchange", MessageBoxButtons.OK, MessageBoxIcon.Information);

}

После того, как я сгенерировал ключи, я отправляю открытый ключ веб-службе, которая сохраняет его в виде файла XML.

Теперь я решил проверить это, так что вот мой метод для шифрования строки

public static string RsaEncrypt(string dataToEncrypt)
{
    string rsaPrivate = RSA_XML_PRIVATE_KEY;
    CspParameters csp = new CspParameters();
    csp.Flags = CspProviderFlags.UseMachineKeyStore;

    RSACryptoServiceProvider provider = new RSACryptoServiceProvider(csp);

    provider.FromXmlString(rsaPrivate);

    ASCIIEncoding enc = new ASCIIEncoding();
    int numOfChars = enc.GetByteCount(dataToEncrypt);
    byte[] tempArray = enc.GetBytes(dataToEncrypt);
    byte[] result = provider.Encrypt(tempArray, true);
    string resultString = Convert.ToBase64String(result);
    Console.WriteLine("Encrypted : " + resultString);
    return resultString;
}

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

public string DecryptRSA(string data, string merchantId)
{
    string clearData = null;
    try
    {
        CspParameters param = new CspParameters();
        param.Flags = CspProviderFlags.UseMachineKeyStore;
        RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(param);

        string merchantRsaPublic = GetXmlRsaKey(merchantId);
        rsaProvider.FromXmlString(merchantRsaPublic);
        byte[] asciiString = Encoding.ASCII.GetBytes(data);

        byte[] decryptedData = rsaProvider.Decrypt(asciiString, false);

        clearData = Convert.ToString(decryptedData);
    }
    catch (CryptographicException ex)
    {
        Log.Error("A cryptographic error occured trying to decrypt a value for " + merchantId, ex);

    }
    return clearData;
}

Если бы кто-нибудь мог мне помочь, это было бы замечательно, как я уже сказал, я мало что сделал с шифрованием / дешифрованием C # RSA.

Ответы [ 5 ]

33 голосов
/ 19 марта 2010

Позвольте мне немного терминологии. Существует асимметричное шифрование и цифровая подпись .

  • Асимметричное шифрование - это сохранение конфиденциальности. Некоторые конфиденциальные данные преобразуются во что-то нечитаемое, за исключением объекта, который знает ключ дешифрования. Ключ дешифрования обязательно является личным ключом: если ключ дешифрования является открытым ключом, то каждый может расшифровать данные (открытый ключ, ну, в общем, открытый), и конфиденциальность больше не существует. При асимметричном шифровании выполняется шифрование открытым ключом и расшифровка соответствующим закрытым ключом.

  • Цифровые подписи предназначены для подтверждения целостности. Кто-то вычисляет своего рода контрольную сумму на основе данных таким образом, что связь между контрольной суммой и данными может быть проверена позже. Это «подпись» только потому, что для вычисления этой контрольной суммы требуется знание чего-то, что не является общедоступным - проще говоря, для подписи используется ключ private . Однако проверка должна выполняться любым лицом и, следовательно, использовать открытый ключ.

Достаточная путаница связана с тем фактом, что «алгоритм» RSA на самом деле является математической операцией, которую можно отклонить как в систему асимметричного шифрования, так и в систему цифровой подписи. Путаница еще более усиливается стандартом RSA, также известным как PKCS # 1 , который неявно опирается на то, как цифровые подписи RSA были впервые описаны, то есть как «обратное шифрование» («подписывающее лицо шифрует данные с помощью своего частного ключ "). Что приводит к таким вещам, как подписи RSA, называемые «sha1WithRSAEncryption». Это весьма прискорбно.

Поэтому вы должны сначала решить, хотите ли вы конфиденциальности или подписей. В целях конфиденциальности, для данных, отправляемых с клиентов на сервера, сервер должен иметь закрытый ключ, а клиенты используют открытый ключ сервера для шифрования данных. , Для подписей каждый клиент должен иметь свой личный ключ и использовать его для подписи данных, а сервер проверяет подписи. Из вашего описания я не могу сказать, что вы действительно после, из-за путаницы, о которой я упоминал выше.

Кроме того, есть нечто, называемое аутентификация , которое может выглядеть как цифровая подпись, но слабее. Точка подписи чем кто угодно может проверить подпись. В частности, подпись может быть показана судье и, таким образом, служить легальным оружием против подписавшего (подпись имеет обязательную юридическую силу - по крайней мере, если вы делаете это правильно, и в нынешнем состоянии нормативных актов в отношении электронные подписи, это не просто). В большинстве ситуаций вам нужно только что-то более слабое и более простое, в котором сервер убежден, что он говорит с нужным клиентом, но впоследствии не может убедить кого-либо еще, что этот клиент действительно был там. Любой веб-сайт с паролями пользователей использует такую ​​аутентификацию.

С этим сказано ...

  • Асимметричное шифрование RSA распространяется только на короткие сообщения. Для 1024-битного ключа RSA (то есть ключа, в котором наиболее важной частью, «модулем RSA», является большое число со значением от 2 ^ 1023 до 2 ^ 1024, а зашифрованные сообщения будут иметь длину 128 байт), максимальный размер зашифрованного сообщения составляет 117 байт (это фактический источник вашего сообщения об ошибке). Когда мы хотим отправлять более длинные сообщения, мы используем гибридную систему, в которой мы шифруем только небольшую группу случайных битов (скажем, 128 бит) и используем эту группу в качестве ключа для симметричного шифрования системы (например, AES), который может обрабатывать гораздо более длинные сообщения (и гораздо быстрее).

  • Подписи RSA, аналогично, могут быть вычислены только для коротких сообщений, поэтому стандарт PKCS # 1 требует, чтобы подпись фактически вычислялась по хеш-значению. Хеш-значение является выходом определенной хеш-функции , которая вычисляется по сообщению для подписи. Хэш-функция имеет выход фиксированного размера (например, 256 бит для SHA-256), но принимает входные сообщения (почти) произвольной длины. Хэш-функции являются общедоступными (в них нет ключа) и для надлежащей безопасности должны иметь некоторые специальные свойства. SHA-256 сейчас не плохой выбор. Доказано, что SHA-1 (предшественник SHA-256) имеет некоторые недостатки и его следует избегать. MD5 имеет (дядя SHA-1) имеет большие недостатки и не должен использоваться.

  • Правильное использование асимметричного шифрования, особенно в гибридной схеме и цифровых подписей, сложнее, чем может предложить текст, приведенный выше. В какой-то момент очень легко ошибиться, невидимо , то есть код будет работать, но утечка данных будет полезна для злоумышленника. Правильный способ использования асимметричного шифрования или цифровых подписей состоит в том, чтобы полагаться на существующие хорошо продуманные протоколы. Протокол - это сборка криптографических элементов в единую систему, в которой устраняются утечки. Главный пример - TLS, также известный как SSL. Это протокол, который обеспечивает конфиденциальную передачу данных, целостность и аутентификацию (возможно, взаимную аутентификацию). Протокол HTTPS представляет собой смесь HTTP и SSL. Яркой стороной является то, что HTTPS имеет существующие реализации, особенно в C #. Код, который легче всего реализовать и отладить, - это код, который уже был реализован и отлажен. Так что используйте HTTPS, и вы будете жить дольше и счастливее.

14 голосов
/ 26 марта 2010

Я понимаю, почему вы задаете вопрос. Проблема в том, что RSA не используется как обычный блочный шифр (например, AES или 3DES), который шифрует 8 байтов за раз в течение всего дня. RSA - это математическая операция, которая возвращает остаток от деления (модуль). Вернувшись в начальную школу, когда вы выучили длинное деление, помните, что остаток никогда не может быть больше делителя: если вы делите 20 на 7, ваш остаток равен 6. Независимо от того, какое целое число вы делите на 7, остаток не может быть больше чем шесть.

RSA математика такая же. Например, если вы используете 1024-битный открытый ключ RSA, остаток не может быть больше 2 ^ 1024, что составляет всего 128 байтов. Таким образом, вы можете шифровать только 128 байтов за один раз с помощью этого ключа. (Это одна из причин, по которой мы измеряем размер ключей RSA по количеству битов.)

Технически вы можете использовать этот ключ RSA в цикле для шифрования 128-байтовых блоков ваших данных за раз. В действительности, мы почти никогда не делаем это, потому что математика RSA БОЛЬШАЯ и МЕДЛЕННАЯ. Вместо этого мы используем то, что называется «двухфазным» шифрованием. Мы используем RSA для шифрования только короткого «сеансового ключа», а затем используем этот сеансовый ключ в быстродействующем блочном шифре с симметричным ключом (например, AES) для шифрования фактических данных.

Весь протокол:

  1. Получите открытый ключ RSA вашего пункта назначения. Это часто поставляется в виде сертификата; если это так, не забудьте проверить сертификат, чтобы убедиться, что ключ является подлинным. Допустим, ключ RSA имеет длину 2048 бит.
  2. Создание криптографически стойкого псевдослучайного числа для использования в качестве ключа для блочного шифра (например, вам необходимо 256 бит в качестве ключа для AES-256.) Обратите внимание, что 256 <2048, максимум, что может RSA-2048 зашифровать сразу. Мы называем это случайное число «ключом сеанса». </li>
  3. Зашифруйте сеансовый ключ, используя 2048-битный открытый ключ RSA. Это даст вам 2048 бит зашифрованного сеансового ключа. Обратите внимание, что эта операция очень медленная.
  4. Зашифруйте все секретные данные, используя AES-256, используя ключ сеанса. Обратите внимание, что это намного быстрее, чем шаг 3.
  5. Объедините идентификатор открытого ключа из сертификата, зашифрованный ключ сеанса RSA и зашифрованные данные AES вместе. Я бы также пометил его идентификатором формата и номером версии, чтобы вы знали, в каком формате он находится и как его расшифровать.
  6. Отправьте пакет по назначению.

  7. В месте назначения вы используете идентификатор формата и версию для разделения пакета.

  8. Получить закрытый ключ, идентификатор которого находится в поле идентификатора открытого ключа.
  9. Используйте этот закрытый ключ в RSA для расшифровки сеансового ключа.
  10. Используйте ключ сеанса в AES для расшифровки данных.

Если вы собираетесь это сделать, вы должны знать, что именно для этого предназначен формат CMS (PKCS # 7). Я бы посоветовал вам изучить стандарт и принять его, а не пытаться придумать собственный формат. CSP от Microsoft поддерживает это, так что должно быть легко.

Если вы не следуете стандарту, вам придется самостоятельно принимать решения о таких вещах, как «в каком формате должны быть биты ключа AES в процессе шифрования RSA?» Скорее всего, вы почти наверняка сделаете ошибки безопасности, ослабив вашу систему. Кроме того, вы обнаружите, что с такими инструментами, как CSP, будет очень трудно работать, если вы не будете следовать стандарту.

3 голосов
/ 19 марта 2010

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

Вы захотите использовать алгоритм симметричного шифрования для больших блоков данных - что-то вроде AES или 3DES.

Управлять безопасными транзакциями непросто, и их действительно следует оставить тем парням, которые проводят весь день и ночь, думая об этом. Если вы выставляете сервис как в Интернете, просто используйте SSL, который уже шифрует и защищает ваши данные.

3 голосов
/ 19 марта 2010

В DecryptRSA кодируется "база данных" 64? Если это так, вы должны сначала отменить это.

Честно говоря, я думаю, что вы не должны сами выполнять эту процедуру для защиты "конфиденциальной финансовой информации", если у вас нет большого опыта работы с криптографией. Есть слишком много способов сделать ошибки. Лучше использовать какое-нибудь готовое решение - может быть, SSL и сертификаты, или просто PGP или GnuPG?

2 голосов
/ 19 марта 2010

Сначала решите, от чего вы пытаетесь защитить. Если вы «зашифровываете» что-то с помощью закрытого ключа, любой может «расшифровать» это с помощью открытого ключа, поскольку открытый ключ - это хорошо - открытый .

Если вы действительно хотите его подписать, вам следует (как объясняет Пол Александер) подписать хеш с закрытым ключом, который затем можно проверить на сервере.

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

Вы также можете рассмотреть возможность использования SSL, но не забудьте внимательно рассмотреть аутентификацию. Вам, вероятно, понадобится аутентификация клиента и вы должны решить, каким сертификатам доверять (вы не должны просто слепо принимать любой сертификат, выданный Verisign).

...