none
Проблемы с расшифровкой RRS feed

  • Вопрос

  • Использую шифрование Rijndael. Проблема следующая:
    если зашифровать строку і тут же расшифровать, то все работает отлично,
    а если зашифровать строку і записать в файл, а потом считать его и расшифровать то выдает ошибку

    "System.Security.Cryptography.CryptographicException' occurred in mscorlib.dll
    Additional information: Заполнение неверно и не может быть удалено."

    public static class SymmetricEncryptionUtility
        {
            private static bool _ProtectKey;
            private static string _AlgorithmName;
            public static string AlgorithmName
            {
                get { return _AlgorithmName; }
                set { _AlgorithmName = value; }
            }
            public static bool ProtectKey
            {
                get { return _ProtectKey; }
                set { _ProtectKey = value; }
            }
    
            public static void GenerateKey(string targetFile)
            {
                // Создать алгоритм
                SymmetricAlgorithm Algorithm = SymmetricAlgorithm.Create(AlgorithmName);
                Algorithm.GenerateKey();
    
                // Получить ключ
                byte[] Key = Algorithm.Key;
    
                if (ProtectKey)
                {
                    // Использовать DPAPI для шифрования ключа
                    Key = ProtectedData.Protect(
                        Key, null, DataProtectionScope.LocalMachine);
                }
    
                // Сохранить ключ в файле 
                using (FileStream fs = new FileStream(targetFile, FileMode.OpenOrCreate))
                {
                    fs.Write(Key, 0, Key.Length);
                }
            }
    
            public static void ReadKey(SymmetricAlgorithm algorithm, string keyFile)
            {
                byte[] Key;
    
                using (FileStream fs = new FileStream(keyFile, FileMode.Open))
                {
                    Key = new byte[fs.Length];
                    fs.Read(Key, 0, (int)fs.Length);
                }
    
                if (ProtectKey)
                    algorithm.Key = ProtectedData.Unprotect(Key, null, DataProtectionScope.LocalMachine);
                else
                    algorithm.Key = Key;
            }
    
            public static byte[] EncryptData(string data, string keyFile)
            {
                // Преобразовать строку data в байтовый массив
                byte[] ClearData = Encoding.UTF8.GetBytes(data);
    
                // Создать алгоритм шифрования
                SymmetricAlgorithm Algorithm = SymmetricAlgorithm.Create(AlgorithmName);
                ReadKey(Algorithm, keyFile);
    
                // Зашифровать информацию
                MemoryStream Target = new MemoryStream();
    
                // Сгенерировать случайный вектор инициализации (IV)
                // для использования с алгоритмом
                Algorithm.GenerateIV();
                Target.Write(Algorithm.IV, 0, Algorithm.IV.Length);
    
                // Зашифровать реальные данные
                CryptoStream cs = new CryptoStream(Target, Algorithm.CreateEncryptor(), CryptoStreamMode.Write);
                cs.Write(ClearData, 0, ClearData.Length);
                cs.FlushFinalBlock();
    
                // Вернуть зашифрованный поток данных в виде байтового массива
                 
                return Target.ToArray();
            }
    
            public static string DecryptData(byte[] data, string keyFile)
            {
                // Создать алгоритм
                SymmetricAlgorithm Algorithm = SymmetricAlgorithm.Create(AlgorithmName);
                ReadKey(Algorithm, keyFile);
    
                // Расшифровать информацию
                MemoryStream Target = new MemoryStream();
    
                // Прочитать вектор инициализации (IV)
                // и инициализировать им алгоритм
                int ReadPos = 0;
                byte[] IV = new byte[Algorithm.IV.Length];
                Array.Copy(data, IV, IV.Length);
                Algorithm.IV = IV;
                ReadPos += Algorithm.IV.Length;
    
                CryptoStream cs = new CryptoStream(Target, Algorithm.CreateDecryptor(),
                    CryptoStreamMode.Write);
                cs.Write(data, ReadPos, data.Length - ReadPos);
                cs.FlushFinalBlock(); /////////////// ОШИБКА ////////////////////
    
                // Получить байты из потока в памяти и преобразовать их в текст
                return Encoding.UTF8.GetString(Target.ToArray());
            }
        }

    Вот так записываю в файл

    StringBuilder sb = new StringBuilder();
                foreach(Account ac in login.allAccounts)
                {
                    sb.AppendLine(String.Format("{0} {1} {2}", ac.Name, ac.Password, ac.Folder));
                }
    
                byte[] data = SymmetricEncryptionUtility.EncryptData(sb.ToString(), login.keyFileName);
                File.WriteAllBytes("./users/users.dat", data);
    Потом читаю с файла 
    byte []data = File.ReadAllBytes("./users/users.dat");
                    string decr = SymmetricEncryptionUtility.DecryptData(data, keyFileName);
    Подскажите, пожалуйста, в чем проблема...

Все ответы

  • Я в своем приложении чат тоже использую шифрование. Когда разрабатывала свой собственный алгоритм шифрования долго не могла понять причину такого же поведения, только у меня зашифрованные данные хранятся не в файле, а передаются по сети интернет. При шифровании получаются различные сочетания спец символов, которые приводят либо к отсечению части данных, либо к неверному их чтению. Сравните строки до сохранения в файл и после. Обратите внимание на длину, плюс какие символы потерялись или заменились при операции записи/чтения.
  • У меня ошибка не воспроизводится.
  • У меня ошибка не воспроизводится.
    Этого не легко добиться... Чтоб выходная строка содержала определенный набор спец символов.
  • Какие именно символы? Вы уверены, что ваша проблема и проблема топик стартера вообще связаны? 

    Есть огромная разница между "Rijndael" и "свой собственный алгоритм шифрования", "записываю в файл" и "передаются по сети интернет". Если использовался WCF, там есть много способов ошибиться, при работе с файлами все гораздо проще.

  • Возможно и не связаны. В старом добром досе, конец файла обозначался спецсимволом. Раз автор читает данные построчно, то могут затесаться символы перевода каретки и прочие. Автор топика спросил о возможных проблемах, я озвучила свои мысли по данному поводу...
  • Возможно и связаны, но не с конкретным символом, а с тем что автор делает вот такую ужасную штуку:

    return Encoding.UTF8.GetString(Target.ToArray());

    Это, конечно, не может работать, ведь произвольные байты в символы в какой то кодировки преобразовать нельзя, там просто может не быть определенных комбинаций. В строке при этом появятся знаки вопроса.

    Если надо передать двоичные данные в виде текста, то для этого можно использовать только те символы которые в конкретной кодировке имеются. Например, можно представить каждый двоичный байт в виде чисел от 0 до 255. Более компактной стандартной формой является Base64 (что видимо и следует использовать):

    return System.Convert.ToBase64String(Target.ToArray());

    Обратное преобразование выполняется вызовом System.Convert.FromBase64String().

    Base64 работает практически со всеми кодировками, требуется лишь наличие прописных и строчных букв латиницы и цифр.

    Кстати, в старом добром досе конец файла в общем случае не обозначался спецсимволом. Хотя так делали некоторые программы, обычно текстовые редакторы. Забавно что компилятор C# все еще так делает: если вставить символ \0 в код, то компилятор ничего за ним не увидит. В то же время VS на него ни малейшего внимания не обращает.


    This posting is provided "AS IS" with no warranties, and confers no rights.

    • Предложено в качестве ответа Liliya Muray 14 мая 2017 г. 19:59
    Модератор
  • Так падает то программа, по утверждению автора, при расшифровке, т.е до "ужасной штуки"... 
  • Потому что при записи вместо символов которых не может быть в кодировке вставляются знаки вопроса, данные повреждаются еще при записи. 

    This posting is provided "AS IS" with no warranties, and confers no rights.

    Модератор
  • Так записывается в файл поток байтов, а не текст. Шифруется также поток байтов, полученный преобразованием из UTF-16 в UTF-8. Откуда могут взяться знаки вопроса? Кто-нибудь может, наконец, сказать, при каких именно условиях воспроизводиться ошибка? 

  • Посмотрел внимательнее - вы правы, проблемы нет. Она бы возникла только если криптотекст бы преобразовывался бы строку, например для передачи или сохранения. Преобразовывать строку в байты и те же байты обратно в строку конечно вполне допустимо.


    This posting is provided "AS IS" with no warranties, and confers no rights.

    Модератор