Using Rijndael to encrypt/decrypt files

若如初见. 提交于 2019-12-21 16:24:12

问题


I need to transfer xml files and they are required to be encrypted. I have found some examples think I'm close but when I decrypt the file I end up with trailing junk characters. There are some posts about this but I have not seen any that will exactly help. Here is the encrypt and decrypt code.

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!");
}

I end up with

<?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

回答1:


When decrypting, pay attention to the return value from the CryptoStream.Read call. It tells you the length of the decrypted data in your byte array (usually will not match the length of the encrypted data due to padding). Try using the following in your decrypt function:

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:


On the RijndaelManaged object, set the Padding property to PaddingMode.ANSIX923 or PaddingMode.ISO10126.

Those null bytes were added to fill out the final encrypted block. It was padded with zeros by default, which means that no indication is given as to the actual length of the data. The other padding modes include a length in the final byte, so that the padding can be removed after decryption.

Set the padding property in both the encrypt and decrypt routine to the same value.

 rijndaelCSP.Padding = PaddingMode.ANSIX923;

If it knows what to expect, then the decryption stream will remove the padding automatically, so no further changes should be necessary.

UPDATE

From looking at your code, it appears that the number of bytes that you are writing to the output file is equal to the number of bytes read in from the input file.

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

The decryption process is not going to completely fill up the inputFileData array, because of the padding in the input.

The output stream will then write out the entire length of the buffer, even though it wasn't completely filled.

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

This is the source of your nulls.

You may want to change the way you are doing the encryption and decryption so that it no longer uses fixed-length bufferes. Alternatively, you could store the length of the encrypted data at the beginning, and only write the number of bytes that correspond to that length.



来源:https://stackoverflow.com/questions/6460793/using-rijndael-to-encrypt-decrypt-files

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!