2015-08-28 2 views
0

У меня есть код для строкового шифрования/дешифрования с использованием алгоритма AES. Шифрование работает отлично, как ожидалось, но я не смог получить правильный текст, когда я его расшифрую. В коде дешифрования должно быть что-то не так.C# AES Код дешифрования

Я скопировал приведенный ниже код.
Пожалуйста, помогите с этим. Благодарю.

Ниже приведен код шифрования и дешифрования.

public static class EncryptionHelper 
{ 
    private static int BlockSize = 16; 

    private static byte[] Key 
    { 
     get 
     { 
      byte[] hash = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes("BlahBlahBlah")); 
      byte[] key = new byte[BlockSize]; 
      Array.Copy(hash, 0, key, 0, BlockSize); 
      return key; 
     } 
    } 

    private static byte[] IV 
    { 
     get 
     { 
      StringBuilder builder = new StringBuilder(); 
      Random random = new Random(); 
      for (int i = 0; i < BlockSize; i++) 
      { 
       char ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))); 
       builder.Append(ch); 
      } 
      return Encoding.UTF8.GetBytes(builder.ToString()); 
     } 
    } 

    public static string DecodeAndDecrypt(string cipherText) 
    { 
     string DecodeAndDecrypt = AesDecrypt(Convert.FromBase64String(HttpUtility.UrlDecode(cipherText))); 
     return (DecodeAndDecrypt); 
    } 

    public static string EncryptAndEncode(string plaintext) 
    { 
     return HttpUtility.UrlEncode(Convert.ToBase64String(AesEncrypt(plaintext))); 
    } 

    public static string AesDecrypt(Byte[] inputBytes) 
    { 
     Byte[] outputBytes = inputBytes; 

     string plaintext = string.Empty; 

     using (MemoryStream memoryStream = new MemoryStream(outputBytes)) 
     { 
      using (CryptoStream cryptoStream = new CryptoStream(memoryStream, GetCryptoAlgorithm().CreateDecryptor(Key, IV), CryptoStreamMode.Read)) 
      { 
       using (StreamReader srDecrypt = new StreamReader(cryptoStream)) 
       { 
        plaintext = srDecrypt.ReadToEnd(); 
       } 
      } 
     } 

     return plaintext; 
    } 

    public static byte[] AesEncrypt(string inputText) 
    { 
     byte[] inputBytes = UTF8Encoding.UTF8.GetBytes(inputText); 

     for (int i = 0; i < BlockSize; i++) 
     { 
      inputBytes[i] ^= IV[i]; 
     } 

     byte[] result = null; 
     using (MemoryStream memoryStream = new MemoryStream()) 
     { 
      using (CryptoStream cryptoStream = new CryptoStream(memoryStream, GetCryptoAlgorithm().CreateEncryptor(Key, IV), CryptoStreamMode.Write)) 
      { 
       cryptoStream.Write(inputBytes, 0, inputBytes.Length); 
       cryptoStream.FlushFinalBlock(); 
       result = memoryStream.ToArray(); 
      } 
     } 
     return result; 
    } 

    private static RijndaelManaged GetCryptoAlgorithm() 
    { 
     RijndaelManaged algorithm = new RijndaelManaged(); 
     algorithm.Padding = PaddingMode.PKCS7; 
     algorithm.Mode = CipherMode.CBC; 
     algorithm.KeySize = 128; 
     algorithm.BlockSize = 128; 
     return algorithm; 
    } 
} 
+3

Что это: 'inputBytes [i]^= IV [i];' Это некоторая предыдущая попытка зашифровать вручную, что не требуется Теперь? – weston

+1

Также 'IV' ** может ** быть одинаков для кодирования и декодирования, не уверен. http://stackoverflow.com/questions/8041451/good-aes-initialization-vector-practice – weston

+0

Я пробовал пропустить входBytes [i]^= IV [i]; Но не повезло –

ответ

1

Я внесла несколько изменений и опубликует некоторые исходные тексты ниже. Чтобы заставить его работать, просто поместите 3 текстовых поля в Form1 и используйте этот код для Form1.cs. Я упомянул выше. Я думаю, что основная проблема заключалась в том, как вы читали StreamReader в виде строки без указания вашей кодировки. Мое изменение использует BinaryReader для чтения в виде байтового массива, а затем преобразуется в строку UTF-8 после чтения. Я также удалил цикл XOR. Я думаю, что вы пытались реализовать CBC самостоятельно (CBC - это своего рода цикл обратной связи XOR), но он не нужен - когда вы указываете режим CBC, .NET выполняет для вас режим CBC. Чтобы моя версия была настолько близка, насколько это было возможно для вас, я не внес много изменений. Но, пожалуйста, запомните некоторые из приведенных выше замечаний. Не используйте простой хеш, когда .NET предоставляет функцию DeriveBytes, например. Относитесь к IV как к бумажному полотенцу - используйте его один раз и только один раз, когда-либо. И так далее. В любом случае, функциональный, если не код «лучшей практики», приведен ниже:

Редактировать: Извините, что я забыл упомянуть, что я также изменил обычный текст на обычные строки, удалив HTTP-код. Это было просто для того, чтобы упростить работу. Он должен работать так же хорошо, как с вашими HTTP-методами, как с обычными строками.

using System; 
using System.IO; 
using System.Security.Cryptography; 
using System.Text; 
using System.Windows.Forms; 

namespace StackOverflow 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void textBox3_TextChanged(object sender, EventArgs e) 
     { 
      textBox1.Text = EncryptionHelper.EncryptAndEncode(textBox3.Text); 
      textBox2.Text = EncryptionHelper.DecodeAndDecrypt(textBox1.Text); 
     } 
    } 

    public static class EncryptionHelper 
    { 
     private static int BlockSize = 16; 

     private static byte[] Key 
     { 
      get 
      { 
       byte[] hash = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes("BlahBlahBlah")); 
       byte[] key = new byte[BlockSize]; 
       Array.Copy(hash, 0, key, 0, BlockSize); 
       return key; 
      } 
     } 

     private static byte[] IV 
     { 
      get 
      { 
       StringBuilder builder = new StringBuilder(); 
       Random random = new Random(); 
       for (int i = 0; i < BlockSize; i++) 
       { 
        char ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))); 
        builder.Append(ch); 
       } 
       return Encoding.UTF8.GetBytes(builder.ToString()); 
      } 
     } 

     public static string DecodeAndDecrypt(string cipherText) 
     { 
      byte[] cipherBytes = Convert.FromBase64String(cipherText); 
      string decodeAndDecrypt = AesDecrypt(cipherBytes); 
      return decodeAndDecrypt; 
     } 

     public static string EncryptAndEncode(string plaintext) 
     { 
      return Convert.ToBase64String(AesEncrypt(plaintext)); 
     } 

     public static string AesDecrypt(Byte[] inputBytes) 
     { 
      Byte[] outputBytes = inputBytes; 

      string plaintext = string.Empty; 

      using (MemoryStream memoryStream = new MemoryStream(outputBytes)) 
      { 
       using (CryptoStream cryptoStream = new CryptoStream(memoryStream, GetCryptoAlgorithm().CreateDecryptor(Key, IV), CryptoStreamMode.Read)) 
       { 
        using (BinaryReader srDecrypt = new BinaryReader(cryptoStream)) 
        { 
         outputBytes = srDecrypt.ReadBytes(inputBytes.Length); 
         plaintext = Encoding.UTF8.GetString(outputBytes); 
        } 
       } 
      } 
      return plaintext; 
     } 

     public static byte[] AesEncrypt(string inputText) 
     { 
      byte[] inputBytes = UTF8Encoding.UTF8.GetBytes(inputText); 
      byte[] result = null; 
      using (MemoryStream memoryStream = new MemoryStream()) 
      { 
       using (CryptoStream cryptoStream = new CryptoStream(memoryStream, GetCryptoAlgorithm().CreateEncryptor(Key, IV), CryptoStreamMode.Write)) 
       { 
        cryptoStream.Write(inputBytes, 0, inputBytes.Length); 
        cryptoStream.FlushFinalBlock(); 
        result = memoryStream.ToArray(); 
       } 
      } 
      return result; 
     } 

     private static RijndaelManaged GetCryptoAlgorithm() 
     { 
      RijndaelManaged algorithm = new RijndaelManaged(); 
      algorithm.Padding = PaddingMode.PKCS7; 
      algorithm.Mode = CipherMode.CBC; 
      algorithm.KeySize = 128; 
      algorithm.BlockSize = 128; 
      return algorithm; 
     } 
    } 
} 
1

Комментарии выше (по этому вопросу) имеют наиболее важный момент: вы должны использовать же IV на Расшифровать, использованного на шифровку, в противном случае ваши первые 16 байт извлеченного открытого текста будут перемещены в корзину. (Режим CBC будет автоматически корректировать после первого блока.)

Вы можете просто объединить IV с зашифрованным текстом перед его отправкой, а затем просто разбить их на другом конце перед расшифровкой.

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

Также, как указывает WDS, вы не должны выполнять эту операцию XOR. (Но я не вижу, как код WDS восстанавливает первые 16 байтов без сохранения IV.)

Кроме того, IMHO, использующий SHA1 над паролем для генерации ключа, представляет собой угрозу безопасности. Вы должны использовать PBKDF2 или подобный для получения пароля.

Редактировать: Как указывает Artjom B., поскольку ваш исходный код XOR является IV против первого блока открытого текста, вы можете восстановить первые 16 байтов, используя IV всех 0x00 байт при расшифровке. Но это будет работать только в том случае, если зашифрованный текст был как минимум двумя блоками (32 байта), в противном случае вы получите ошибки заполнения, так как это повредит заполнение. Попробуйте использовать IV всех нулевых байтов в вашем расшифровке и выясните, всегда ли входной файл имеет значение не менее 16 байт. В любом случае у вас есть ошибка в конце вашего массива, если это не , (У вас все еще будет небезопасный IV, но по крайней мере вы получите дешифровку.)

+0

IV вещь странная, но верьте или нет, IV как-то переносится в дешифрованном коде, когда я его разместил. Однако я согласен с тем, что лучше явно сообщить об этом, чтобы сделать код более долговечным. Поскольку я подозреваю, что если плакат зашифрован и сохранен, перезапустил компьютер, а затем попытался расшифровать, первый блок (или 2 блока с CBC?) Будет уничтожен из-за плохого IV. – WDS

+0

На самом деле, это очень странно. Я просто поставил точку останова на IV-приемнике, так что он попал в Encrypt и снова в Decrypt. Затем меняется IV, и происходит «Bad Padding». Но без точки останова он отлично работает. Очень, очень странно. Недокументированная функция. – WDS

+0

* «Но я не вижу, как код WDS восстанавливает первые 16 байтов, не сохраняя IV.» *, Поскольку IV применяется дважды при шифровании, для дешифрования потребуется только нулевой байт IV. –