Encrypt and Decrypt xlsx, docx files using C# AES or Rijndael
We encrypt all types of files using Rijndael encryption. Newer .xlsx and .docx files are throwing errors when trying to open (after encrypting and trying to decrypt). Error when Excel 2003 tries to open file: "The converter failed to open the file". I have Excel add on installed and when not using encryption/decryption I am able to open xlsx files in Excel 2003.
I have changed out the code to use AES, with same type of issue (but in this case the file will not download, just sits there in the Firefox download list). I've read suggestions here to pay attention to byte size/lengths of encrypted/decrypted files but am at a loss as to how to fix this, I see that if I upload a xls file the length of the encrypted file going in is different from the decrypted file coming out and xls save and open fine, so I don't know how to test if this is the issue since these lenghts differ on files that do work. I am including the code to see if anyone can spot any issues that could be contributing to xlsx/docx file encryption errors. I've minimized the code, so if any syntax errors, is probably due to that.
I have installed Excel 2007 to see if the .xlsx files that are encrypted and decrypted will open in Excel 2007. When I attempt to open the file, I get a prompt:"Excel found unreadable content in 'myfile.xlsx'. Do you want to recover the contents of this workbook?". Excel 2007 is able to recover/repair the file with message: "Excel completed the file level validation and repair. Some parts of this workbook may have been repaired or discarded". So, the encryption/decryption creates invalid file but Excel 2007 is able to repair this; Excel 2003 converter cannot do anything with the file.
public byte [] Encrypt(byte [] bytes)
{
if (myRijndael == null)
myRijndael = new RijndaelManaged();
ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, IV);
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
csEncrypt.Write(bytes, 0, bytes.Length);
csEncrypt.FlushFinalBlock();
return msEncrypt.ToArray();
}
public byte [] Decrypt(byte [] encrypted, string text)
{
if (myRijndael == null)
{
myRijndael = new RijndaelManaged();
}
ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, IV);
MemoryStream msDecrypt = new MemoryStream(encrypted);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
byte [] fromEncrypt = new byte[encrypted.Length];
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
return fromEncrypt;
}
Usage:
ENCRYPT:
ClcCrypto crypt; // Our class for saving keys etc.
ClcCr开发者_JAVA百科ypto(CLC.WebUtil.ClcCrypto.GetDecryptionKey(), Group.IV);
BinaryReader br = new BinaryReader(NewFile);// NewFile is Stream from filMyFile.PostedFile.InputStream
byte[] EncryptedContents = crypt.Encrypt(br.ReadBytes((int)NewFile.Length));
FileStream fs = File.Create(DestFileName);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(EncryptedContents);
bw.Close();
fs.Close();
br.Close();
DECRYPT (file download):
byte[] baOut = null;
baOut = fiOut.GetFileData(out lLength); // See below for method
Response.AddHeader("content-disposition", "attachment; filename=" + FileName));
Response.ContentType = fiOut.MimeType;
Response.AddHeader("content-length", lLength.ToString());
Response.BinaryWrite(baOut);
Response.End();
public byte[] GetFileData(out long intFileSize)
{
FileStream fsOut = new FileStream(FilePath, FileMode.Open, FileAccess.Read);
intFileSize = fsOut.Length;
byte[] Buffer = null;
ClcCrypto crypt;
crypt = new CLC.WebUtil.ClcCrypto(CLC.WebUtil.ClcCrypto.GetDecryptionKey(), IV);
BinaryReader br = new BinaryReader(fsOut);
Buffer = crypt.Decrypt(br.ReadBytes((int)fsOut.Length), null);
br.Close();
fsOut.Close();
return Buffer;
}
If the padding is of concern, here is something for you:
How do I encrypt a string in vb.net using RijndaelManaged, and using PKCS5 padding?
Sounds like a truncation issue; possibly because of the way you're creating the memory stream; when I decrypt it looks like the following
MemoryStream msDecrypt = new MemoryStream();
CryptoStream csDecrypt = new CryptoStream(
msDecrypt,
decryptor,
CryptoStreamMode.Write);
csStream.Write(encrypted, 0, encrypted.Length);
csStream.Flush();
return csDecrypt.ToArray();
I'd guess that there are extra null bytes being appended, and using the alternate approach may alleviate this.
精彩评论