2011-06-23 117 views
6

我需要传输xml文件,并且需要对它们进行加密。我发现一些例子认为我很接近,但是当我解密文件时,我最终会看到尾随的垃圾字符。有一些关于这方面的帖子,但我没有看到任何确切的帮助。这是加密和解密代码。使用Rijndael加密/解密文件

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 

回答

10

解密时,请注意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); 
+0

我们有一个赢家!非常感谢兄弟! – mjames

2

RijndaelManaged目的,Padding属性设置为PaddingMode.ANSIX923PaddingMode.ISO10126

那些空字节被添加来填写最终的加密块。默认情况下,它填充了零,这意味着没有指示数据的实际长度。其他填充模式在最后一个字节中包含一个长度,以便在解密后可以删除填充。

将加密和解密例程中的填充属性设置为相同的值。

rijndaelCSP.Padding = PaddingMode.ANSIX923; 

如果知道该期待什么,那么解密流将自动删除填充,所以不需要进一步的更改。

UPDATE

从看你的代码,看来你正在写到输出文件的字节数等于字节数读取来自输入文件。

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

解密过程是不会完全填满inputFileData阵列,因为在输入的填充。

输出流将写出缓冲区的整个长度,即使它没有完全填充。

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

这是您的空值的来源。

您可能想要更改加密和解密的方式,以便不再使用固定长度的缓冲区。或者,您可以在开始时存储加密数据的长度,并只写入对应于该长度的字节数。

+0

+1我以前遇到过这种情况。我相信这是我用来修复它的解决方案。 –

+0

我尝试了这两种填充模式并获得相同的结果。 – mjames