Шифрование RSA больших данных в C#

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

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

    public string[] GenerateKeysToStrings(string uniqueIdentifier)
    {
        string[] keys;
        using (var rsa = new RSACryptoServiceProvider(4096))
        {
            try
            {
                string privateKey = rsa.ToXmlString(true);
                string publicKey = rsa.ToXmlString(false);

                this.pki.StoreKey(publicKey, uniqueIdentifier);

                keys = new string[2];
                keys[0] = privateKey;
                keys[1] = publicKey;
            }
            finally
            {
                //// Clear the RSA key container, deleting generated keys.
                rsa.PersistKeyInCsp = false;
            }
        }
        return keys;
    }

как вы можете видеть, я генерирую ключи и имитирую PKI, отправляя открытый ключ в простой класс, который его хранит, а затем закрытый ключ записывается в файл (Обратите внимание, что у меня также есть другой метод, который делает то же самое, но сохраняет его в массиве, просто потому, что я хотел проверить и упростить вещи, как я получаю No such key exceptions и иногда криптографические исключения, когда я делаю это так, как показано в Примере, поэтому я хотел упростить его, просто сохранив rsa.ToXmlString string, как строка в массиве, но не повезло.)

теперь у меня есть метод шифрования и дешифрования следующим образом:

    public string Encrypt(string keyString, string message)
    {
        string encryptedMessage;
        using (var rsa = new RSACryptoServiceProvider())
        {
            try
            {
                //// Load the key from the specified path
                var encryptKey = new XmlDocument();
                encryptKey.Load(@"C:TestPrivateKeyInfo.xml");
                rsa.FromXmlString(encryptKey.OuterXml);


                //// Conver the string message to a byte array for encryption
                //// var encoder = new UTF8Encoding();
                ASCIIEncoding byteConverter = new ASCIIEncoding();
                byte[] dataToEncrypt = byteConverter.GetBytes(message);

                byte[] encryptedData = rsa.Encrypt(dataToEncrypt, false);

                //// Convert the byte array back to a string message
                encryptedMessage = byteConverter.GetString(encryptedData);
            }
            finally
            {
                //// Clear the RSA key container, deleting generated keys.
                rsa.PersistKeyInCsp = false;
            }
        }
        return encryptedMessage;
    }

расшифровка:

    public string Decrypt(string keyString, string message)
    {
        string decryptedText;
        using (var rsa = new RSACryptoServiceProvider())
        {
            try
            {
                //// Loads the keyinfo into the rsa parameters from the keyfile
                /*
                var privateKey = new XmlDocument();
                privateKey.Load(keyString);
                 */
                rsa.FromXmlString(keyString);

                //// Convert the text from string to byte array for decryption
                ASCIIEncoding byteConverter = new ASCIIEncoding();
                var encryptedBytes = byteConverter.GetBytes(message);

                //// Create an aux array to store all the encrypted bytes
                byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, false);

                decryptedText = byteConverter.GetString(decryptedBytes);
            }
            finally
            {
                //// Clear the RSA key container, deleting generated keys.
                rsa.PersistKeyInCsp = false;
            }
        }
        return decryptedText;
    }

Я знаю, что это стена текста, но я надеюсь вы можете помочь мне, потому что я так долго бился головой о стену, теперь это не смешно:)

проблема в том, как я могу шифровать сообщения с помощью RSA (или любое другое шифрование открытого / закрытого ключа)

вот тестовый клиент:

    public static void Main(string[] args)
    {
        PublicKeyInfrastructure pki = new PublicKeyInfrastructure();
        Cryptograph crypto = new Cryptograph();
        string[] keys = crypto.GenerateKeysToStrings("simonlanghoff@gmail.com");


        string plainText = "Hello play with me, please";
        string publicKey = crypto.GetPublicKey("simonlanghoff@gmail.com");

        string encryptedText = crypto.Encrypt(keys[0], plainText);


        string decryptedText = crypto.Decrypt(keys[1], encryptedText);

    }

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

когда я запускаю тестовый клиент, если я использую закрытый ключ для шифрования и открытый ключ для дешифрования, я получаю "ключ не существует исключения", и если я делаю это наоборот, я получаю плохое исключение данных.

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

Я ценю любую помощь.

3 ответов


Это не то, как шифрование RSA должно быть сделано.

RSA все о математике. То, что вы шифруете, - это число, поэтому оно должно иметь конечную длину и соответствовать длине пары ключей RSA, которую вы используете. Дальнейшие ограничения длины введенной обивка используется (либо формате PKCS#1 или УАМИАЭ).

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

вы можете прочитать о реализации этого на мой блог.


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

вот текущий код у меня есть:

    public static string Encrypt(string dataToEncrypt, RSAParameters publicKeyInfo)
    {
        //// Our bytearray to hold all of our data after the encryption
        byte[] encryptedBytes = new byte[0];
        using (var RSA = new RSACryptoServiceProvider())
        {
            try
            {
                //Create a new instance of RSACryptoServiceProvider.
                UTF8Encoding encoder = new UTF8Encoding();

                byte[] encryptThis = encoder.GetBytes(dataToEncrypt);

                //// Importing the public key
                RSA.ImportParameters(publicKeyInfo);

                int blockSize = (RSA.KeySize / 8) - 32;

                //// buffer to write byte sequence of the given block_size
                byte[] buffer = new byte[blockSize];

                byte[] encryptedBuffer = new byte[blockSize];

                //// Initializing our encryptedBytes array to a suitable size, depending on the size of data to be encrypted
                encryptedBytes = new byte[encryptThis.Length + blockSize - (encryptThis.Length % blockSize) + 32];

                for (int i = 0; i < encryptThis.Length; i += blockSize)
                {
                    //// If there is extra info to be parsed, but not enough to fill out a complete bytearray, fit array for last bit of data
                    if (2 * i > encryptThis.Length && ((encryptThis.Length - i) % blockSize != 0))
                    {
                        buffer = new byte[encryptThis.Length - i];
                        blockSize = encryptThis.Length - i;
                    }

                    //// If the amount of bytes we need to decrypt isn't enough to fill out a block, only decrypt part of it
                    if (encryptThis.Length < blockSize)
                    {
                        buffer = new byte[encryptThis.Length];
                        blockSize = encryptThis.Length;
                    }

                    //// encrypt the specified size of data, then add to final array.
                    Buffer.BlockCopy(encryptThis, i, buffer, 0, blockSize);
                    encryptedBuffer = RSA.Encrypt(buffer, false);
                    encryptedBuffer.CopyTo(encryptedBytes, i);
                }
            }
            catch (CryptographicException e)
            {
                Console.Write(e);
            }
            finally
            {
                //// Clear the RSA key container, deleting generated keys.
                RSA.PersistKeyInCsp = false;
            }
        }
        //// Convert the byteArray using Base64 and returns as an encrypted string
        return Convert.ToBase64String(encryptedBytes);
    }

    /// <summary>
    /// Decrypt this message using this key
    /// </summary>
    /// <param name="dataToDecrypt">
    /// The data To decrypt.
    /// </param>
    /// <param name="privateKeyInfo">
    /// The private Key Info.
    /// </param>
    /// <returns>
    /// The decrypted data.
    /// </returns>
    public static string Decrypt(string dataToDecrypt, RSAParameters privateKeyInfo)
    {
        //// The bytearray to hold all of our data after decryption
        byte[] decryptedBytes;

        //Create a new instance of RSACryptoServiceProvider.
        using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
        {
            try
            {
                byte[] bytesToDecrypt = Convert.FromBase64String(dataToDecrypt);

                //// Import the private key info
                RSA.ImportParameters(privateKeyInfo);

                //// No need to subtract padding size when decrypting (OR do I?)
                int blockSize = RSA.KeySize / 8;

                //// buffer to write byte sequence of the given block_size
                byte[] buffer = new byte[blockSize];

                //// buffer containing decrypted information
                byte[] decryptedBuffer = new byte[blockSize];

                //// Initializes our array to make sure it can hold at least the amount needed to decrypt.
                decryptedBytes = new byte[dataToDecrypt.Length];

                for (int i = 0; i < bytesToDecrypt.Length; i += blockSize)
                {
                    if (2 * i > bytesToDecrypt.Length && ((bytesToDecrypt.Length - i) % blockSize != 0))
                    {
                        buffer = new byte[bytesToDecrypt.Length - i];
                        blockSize = bytesToDecrypt.Length - i;
                    }

                    //// If the amount of bytes we need to decrypt isn't enough to fill out a block, only decrypt part of it
                    if (bytesToDecrypt.Length < blockSize)
                    {
                        buffer = new byte[bytesToDecrypt.Length];
                        blockSize = bytesToDecrypt.Length;
                    }

                    Buffer.BlockCopy(bytesToDecrypt, i, buffer, 0, blockSize);
                    decryptedBuffer = RSA.Decrypt(buffer, false);
                    decryptedBuffer.CopyTo(decryptedBytes, i);
                }
            }
            finally
            {
                //// Clear the RSA key container, deleting generated keys.
                RSA.PersistKeyInCsp = false;
            }
        }

        //// We encode each byte with UTF8 and then write to a string while trimming off the extra empty data created by the overhead.
        var encoder = new UTF8Encoding();
        return encoder.GetString(decryptedBytes).TrimEnd(new[] { '' });

    }

возможно, мне чего-то не хватает, но похоже, что ваша функция Encrypt() не использует ни содержимое encryptKey.