Добро пожаловать, Гость
Логин: Пароль: Запомнить меня
  • Страница:
  • 1

ТЕМА:

Шифрование и дешифрование строки в C # 4 года 3 нед. назад #331

  • Олег Коровяков
  • Олег Коровяков аватар Автор темы
  • Не в сети
  • Автор сайта
  • Автор сайта
  • Сообщений: 280
  • Репутация: 1
  • Спасибо получено: 1
Каков самый современный (лучший) способ удовлетворения следующего в С#?
string encryptedString = SomeStaticClass.Encrypt(sourceString);
string decryptedString = SomeStaticClass.Decrypt(encryptedString);

НО с минимумом суеты, включающей соли, ключи, сбрасывание байт [] и т.д.

Был Google и смущен тем, что я нахожу (вы можете увидеть список подобных SO Qs, чтобы увидеть, что это обманчивый вопрос, чтобы спросить).

Вопрос создал Richard 16 апр. 2012, в 05:14

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Шифрование и дешифрование строки в C # 4 года 3 нед. назад #332

  • Олег Коровяков
  • Олег Коровяков аватар Автор темы
  • Не в сети
  • Автор сайта
  • Автор сайта
  • Сообщений: 280
  • Репутация: 1
  • Спасибо получено: 1
23/Дек/2015: поскольку этот ответ, похоже, получает много оборотов, я обновил его, чтобы исправить глупые ошибки и, как правило, улучшить код, основанный на комментариях и отзывах. См. Конец сообщения для получения списка конкретных улучшений.

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

Вы можете, однако, "перевернуть свой" класс-оболочку вокруг чего-то вроде встроенного класса RijndaelManaged .

Rijndael - это алгоритмическое имя текущего Advanced Encryption Standard, поэтому вы, безусловно, используете алгоритм, который можно было бы считать "лучшей практикой",.

Класс RijndaelManaged действительно требует от вас "гашения" с байтовыми массивами, солями, ключами, векторами инициализации и т.д., но это именно те детали, которые можно отвлечь в своем классе "обертка".

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

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

"Сила" использования этого исходит из использования класса RijndaelManaged для выполнения шифрования для вас, а также с помощью Rfc2898DeriveBytes из пространства имен System.Security.Cryptography, которое будет генерировать ваш ключ шифрования с использованием стандартного и безопасного алгоритма (в частности, PBKDF2 ) на основе строкового пароля, который вы предоставляете. (Обратите внимание, что это улучшает использование первой версии старого алгоритма PBKDF1).

Наконец, важно отметить, что это еще не прошедшее проверку подлинность шифрование. Только шифрование обеспечивает только конфиденциальность (то есть сообщение неизвестно третьим сторонам), в то время как аутентифицированное шифрование имеет целью обеспечить как конфиденциальность, так и аутентичность (то есть сообщение получателя сообщения отправлено отправителем).

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

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

Здесь код:
using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Linq;

namespace EncryptStringSample
{
    public static class StringCipher
    {
        // This constant is used to determine the keysize of the encryption algorithm in bits.
        // We divide this by 8 within the code below to get the equivalent number of bytes.
        private const int Keysize = 256;

        // This constant determines the number of iterations for the password bytes generation function.
        private const int DerivationIterations = 1000;

        public static string Encrypt(string plainText, string passPhrase)
        {
            // Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
            // so that the same Salt and IV values can be used when decrypting.  
            var saltStringBytes = Generate256BitsOfRandomEntropy();
            var ivStringBytes = Generate256BitsOfRandomEntropy();
            var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
            using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
            {
                var keyBytes = password.GetBytes(Keysize / 8);
                using (var symmetricKey = new RijndaelManaged())
                {
                    symmetricKey.BlockSize = 256;
                    symmetricKey.Mode = CipherMode.CBC;
                    symmetricKey.Padding = PaddingMode.PKCS7;
                    using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
                    {
                        using (var memoryStream = new MemoryStream())
                        {
                            using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                            {
                                cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                                cryptoStream.FlushFinalBlock();
                                // Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
                                var cipherTextBytes = saltStringBytes;
                                cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
                                cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
                                memoryStream.Close();
                                cryptoStream.Close();
                                return Convert.ToBase64String(cipherTextBytes);
                            }
                        }
                    }
                }
            }
        }

        public static string Decrypt(string cipherText, string passPhrase)
        {
            // Get the complete stream of bytes that represent:
            // [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
            var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
            // Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
            var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
            // Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
            var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
            // Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
            var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();

            using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
            {
                var keyBytes = password.GetBytes(Keysize / 8);
                using (var symmetricKey = new RijndaelManaged())
                {
                    symmetricKey.BlockSize = 256;
                    symmetricKey.Mode = CipherMode.CBC;
                    symmetricKey.Padding = PaddingMode.PKCS7;
                    using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
                    {
                        using (var memoryStream = new MemoryStream(cipherTextBytes))
                        {
                            using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                            {
                                var plainTextBytes = new byte[cipherTextBytes.Length];
                                var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                                memoryStream.Close();
                                cryptoStream.Close();
                                return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
                            }
                        }
                    }
                }
            }
        }

        private static byte[] Generate256BitsOfRandomEntropy()
        {
            var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
            using (var rngCsp = new RNGCryptoServiceProvider())
            {
                // Fill the array with cryptographically secure random bytes.
                rngCsp.GetBytes(randomBytes);
            }
            return randomBytes;
        }
    }
}

Вышеприведенный класс можно использовать довольно просто с кодом, подобным следующему:
using System;

namespace EncryptStringSample
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Please enter a password to use:");
            string password = Console.ReadLine();
            Console.WriteLine("Please enter a string to encrypt:");
            string plaintext = Console.ReadLine();
            Console.WriteLine("");

            Console.WriteLine("Your encrypted string is:");
            string encryptedstring = StringCipher.Encrypt(plaintext, password);
            Console.WriteLine(encryptedstring);
            Console.WriteLine("");

            Console.WriteLine("Your decrypted string is:");
            string decryptedstring = StringCipher.Decrypt(encryptedstring, password);
            Console.WriteLine(decryptedstring);
            Console.WriteLine("");

            Console.WriteLine("Press any key to exit...");
            Console.ReadLine();
        }
    }
}

(Вы можете скачать простое решение VS2013 (которое включает в себя несколько модульных тестов) в конце этого поста прикреплен файл).

ОБНОВЛЕНИЕ 23/Дек/2015: Список конкретных улучшений для кода:

1. Исправлена ​​глупая ошибка, когда кодирование различалось между шифрованием и дешифрования. Поскольку механизм, с помощью которого генерируются значения соли и IV, изменился, кодирование больше не требуется.
2. Из-за изменения соли /IV предыдущий комментарий кода, который неправильно указал, что UTF8, кодирующий 16-значную строку, создает 32 байта, больше не применим (поскольку кодирование больше не требуется).
3. Использование замененного алгоритма PBKDF1 заменено использованием более современного алгоритма PBKDF2.
4. Вывод пароля теперь должным образом солен, тогда как ранее он вообще не был солен (другая глупая ошибка сжималась).
Ответ дал CraigTP 16 апр. 2012, в 15:24

Вложенный файл:

Имя файла: EncryptStr...mple.zip
Размер файла:10 KB
Вложения:

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Шифрование и дешифрование строки в C # 4 года 3 нед. назад #333

  • Олег Коровяков
  • Олег Коровяков аватар Автор темы
  • Не в сети
  • Автор сайта
  • Автор сайта
  • Сообщений: 280
  • Репутация: 1
  • Спасибо получено: 1
Если вам нужно сохранить пароль в памяти и хотите, чтобы он был зашифрован, вы должны использовать SecureString:

msdn.microsoft.com/ru-ru/library/system....ty.securestring.aspx

Для более общих применений я бы использовал утвержденный FIPS алгоритм, такой как Advanced Encryption Standard, ранее известный как Rijndael. См. Эту страницу для примера реализации:

msdn.microsoft.com/ru-ru/library/system....graphy.rijndael.aspx

Ответ дал Ulises 16 апр. 2012, в 04:02

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Шифрование и дешифрование строки в C # 4 года 3 нед. назад #334

  • Олег Коровяков
  • Олег Коровяков аватар Автор темы
  • Не в сети
  • Автор сайта
  • Автор сайта
  • Сообщений: 280
  • Репутация: 1
  • Спасибо получено: 1
Попробуйте этот класс:
public class DataEncryptor
{
    TripleDESCryptoServiceProvider symm;

    #region Factory
    public DataEncryptor()
    {
        this.symm = new TripleDESCryptoServiceProvider();
        this.symm.Padding = PaddingMode.PKCS7;
    }
    public DataEncryptor(TripleDESCryptoServiceProvider keys)
    {
        this.symm = keys;
    }

    public DataEncryptor(byte[] key, byte[] iv)
    {
        this.symm = new TripleDESCryptoServiceProvider();
        this.symm.Padding = PaddingMode.PKCS7;
        this.symm.Key = key;
        this.symm.IV = iv;
    }

    #endregion

    #region Properties
    public TripleDESCryptoServiceProvider Algorithm
    {
        get { return symm; }
        set { symm = value; }
    }
    public byte[] Key
    {
        get { return symm.Key; }
        set { symm.Key = value; }
    }
    public byte[] IV
    {
        get { return symm.IV; }
        set { symm.IV = value; }
    }

    #endregion

    #region Crypto

    public byte[] Encrypt(byte[] data) { return Encrypt(data, data.Length); }
    public byte[] Encrypt(byte[] data, int length)
    {
        try
        {
            // Create a MemoryStream.
            var ms = new MemoryStream();

            // Create a CryptoStream using the MemoryStream 
            // and the passed key and initialization vector (IV).
            var cs = new CryptoStream(ms,
                symm.CreateEncryptor(symm.Key, symm.IV),
                CryptoStreamMode.Write);

            // Write the byte array to the crypto stream and flush it.
            cs.Write(data, 0, length);
            cs.FlushFinalBlock();

            // Get an array of bytes from the 
            // MemoryStream that holds the 
            // encrypted data.
            byte[] ret = ms.ToArray();

            // Close the streams.
            cs.Close();
            ms.Close();

            // Return the encrypted buffer.
            return ret;
        }
        catch (CryptographicException ex)
        {
            Console.WriteLine("A cryptographic error occured: {0}", ex.Message);
        }
        return null;
    }

    public string EncryptString(string text)
    {
        return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(text)));
    }

    public byte[] Decrypt(byte[] data) { return Decrypt(data, data.Length); }
    public byte[] Decrypt(byte[] data, int length)
    {
        try
        {
            // Create a new MemoryStream using the passed 
            // array of encrypted data.
            MemoryStream ms = new MemoryStream(data);

            // Create a CryptoStream using the MemoryStream 
            // and the passed key and initialization vector (IV).
            CryptoStream cs = new CryptoStream(ms,
                symm.CreateDecryptor(symm.Key, symm.IV),
                CryptoStreamMode.Read);

            // Create buffer to hold the decrypted data.
            byte[] result = new byte[length];

            // Read the decrypted data out of the crypto stream
            // and place it into the temporary buffer.
            cs.Read(result, 0, result.Length);
            return result;
        }
        catch (CryptographicException ex)
        {
            Console.WriteLine("A cryptographic error occured: {0}", ex.Message);
        }
        return null;
    }

    public string DecryptString(string data)
    {
        return Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(data))).TrimEnd('\0');
    }

    #endregion

}

и используйте его следующим образом:
string message="A very secret message here.";
DataEncryptor keys=new DataEncryptor();
string encr=keys.EncryptString(message);

// later
string actual=keys.DecryptString(encr);

Ответ дал ja72 16 апр. 2012, в 15:51

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

  • Страница:
  • 1

О сайте

Строительство индивидуальных домов из лёгкого самана - опыт, советы, методика строительства и подробные инструкции. А также возможность применения альтернативных источников энергии.


Контакты

08340. ул.Салютная 17. с.Гнедын.
Киевская обл. Украина.

+38 067 492 4124.
+38 095 065 8860.

info@okwood.com.ua
www.okwood.com.ua

Местоположения


8PM2+7R Гнедин, Kyiv Oblast