Использование Rijndael для шифрования / дешифрования файлов - PullRequest
6 голосов
/ 24 июня 2011

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

private void EncryptFile(string inputFile, string outputFile, string key) {
    try {
        byte[] keyBytes;
        keyBytes = Encoding.Unicode.GetBytes(key);

        Rfc2898DeriveBytes derivedKey = new Rfc2898DeriveBytes(key, keyBytes);

        RijndaelManaged rijndaelCSP = new RijndaelManaged();
        rijndaelCSP.Key = derivedKey.GetBytes(rijndaelCSP.KeySize / 8);
        rijndaelCSP.IV = derivedKey.GetBytes(rijndaelCSP.BlockSize / 8);

        ICryptoTransform encryptor = rijndaelCSP.CreateEncryptor();

        FileStream inputFileStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read);

        byte[] inputFileData = new byte[(int)inputFileStream.Length];
        inputFileStream.Read(inputFileData, 0, (int)inputFileStream.Length);

        FileStream outputFileStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write);

        CryptoStream encryptStream = new CryptoStream(outputFileStream, encryptor, CryptoStreamMode.Write);
        encryptStream.Write(inputFileData, 0, (int)inputFileStream.Length);
        encryptStream.FlushFinalBlock();

        rijndaelCSP.Clear();
        encryptStream.Close();
        inputFileStream.Close();
        outputFileStream.Close();
    }
    catch (Exception ex) {
        MessageBox.Show(ex.Message, "Encryption Failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }

    MessageBox.Show("File Encryption Complete!");

}

private void DecryptFile(string inputFile, string outputFile, string key) {
    try {
        byte[] keyBytes = Encoding.Unicode.GetBytes(key);

        Rfc2898DeriveBytes derivedKey = new Rfc2898DeriveBytes(key, keyBytes);

        RijndaelManaged rijndaelCSP = new RijndaelManaged();
        rijndaelCSP.Key = derivedKey.GetBytes(rijndaelCSP.KeySize / 8);
        rijndaelCSP.IV = derivedKey.GetBytes(rijndaelCSP.BlockSize / 8);
        ICryptoTransform decryptor = rijndaelCSP.CreateDecryptor();

        FileStream inputFileStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read);

        CryptoStream decryptStream = new CryptoStream(inputFileStream, decryptor, CryptoStreamMode.Read);

        byte[] inputFileData = new byte[(int)inputFileStream.Length];
        decryptStream.Read(inputFileData, 0, (int)inputFileStream.Length);

        FileStream outputFileStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write);
        outputFileStream.Write(inputFileData, 0, inputFileData.Length);
        outputFileStream.Flush();

        rijndaelCSP.Clear();

        decryptStream.Close();
        inputFileStream.Close();
        outputFileStream.Close();
    }
    catch (Exception ex) {
        MessageBox.Show(ex.Message, "Decryption Failed!", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }

    MessageBox.Show("File Decryption Complete!");
}

Я получаю

<?xml version="1.0" encoding="UTF-8"?>
<transaction>
  <header>
    <qOrderNumber></qOrderNumber>
    <qRequestDate></qRequestDate>
    <testOrder></testOrder>
    <qCustomerNumber></qCustomerNumber>
    <transactionStatus></transactionStatus>
  </header>
  <lines>
    <line>
      <productID></productID>
      <serialNumber></serialNumber>
    </line>
    <line> 
      <productID></productID>
      <serialNumber></serialNumber>
    </line>
  </lines>
</transaction>NULNULNULNULNULNUL

Ответы [ 2 ]

10 голосов
/ 24 июня 2011

При расшифровке обращайте внимание на возвращаемое значение из вызова CryptoStream.Read.Он сообщает вам длину расшифрованных данных в вашем байтовом массиве (обычно не совпадает с длиной зашифрованных данных из-за заполнения).Попробуйте использовать следующее в вашей функции расшифровки:

int decrypt_length = decryptStream.Read(inputFileData, 0, (int)inputFileStream.Length);
FileStream outputFileStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write);
outputFileStream.Write(inputFileData, 0, decrypt_length);
2 голосов
/ 24 июня 2011

Для объекта RijndaelManaged установите для свойства Padding значение PaddingMode.ANSIX923 или PaddingMode.ISO10126.

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

Установите для свойства заполнения в подпрограмме шифрования и дешифрования одинаковое значение.

 rijndaelCSP.Padding = PaddingMode.ANSIX923;

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

ОБНОВЛЕНИЕ

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

byte[] inputFileData = new byte[(int)inputFileStream.Length];
decryptStream.Read(inputFileData, 0, (int)inputFileStream.Length);

Процесс расшифровки не собирается полностью заполнитьвверх по массиву inputFileData из-за заполнения входных данных.

Затем выходной поток запишет всю длину буфера, даже если он не был полностью заполнен.

outputFileStream.Write(inputFileData, 0, inputFileData.Length);

Это источник ваших нулей.

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

...