使用C#AES或Rijndael加密和解密xlsx,docx文件

时间:2011-07-12 23:36:10

标签: c# encryption aes xlsx rijndael

我们使用Rijndael加密对所有类型的文件进行加密。较新的.xlsx和.docx文件在尝试打开时(加密并尝试解密后)会抛出错误。 Excel 2003尝试打开文件时出错:“转换器无法打开文件”。我安装了Excel add,当不使用加密/解密时,我可以在Excel 2003中打开xlsx文件。

我已经更改了使用AES的代码,但问题类型相同(但在这种情况下,文件不会下载,只是在Firefox下载列表中)。我在这里读到了建议,要注意加密/解密文件的字节大小/长度,但是如何解决这个问题我不知道,我看到如果我上传一个xls文件,加密文件的长度是不同的从解密文件出来和xls保存并打开正常,所以我不知道如何测试这是否是问题,因为这些长度不同的文件有效。我包含代码,看看是否有人可以发现任何可能导致xlsx / docx文件加密错误的问题。我已经最小化了代码,所以如果有任何语法错误,可能是由于这个原因。

我已经安装了Excel 2007以查看加密和解密的.xlsx文件是否会在Excel 2007中打开。当我尝试打开文件时,我收到提示:“Excel在'myfile.xlsx'中找到了不可读的内容你想恢复这本工作簿的内容吗?“ Excel 2007能够使用以下消息恢复/修复文件:“Excel已完成文件级验证和修复。此工作簿的某些部分可能已被修复或丢弃”。因此,加密/解密创建无效文件,但Excel 2007能够修复此问题; Excel 2003转换器无法对该文件执行任何操作。

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.
ClcCrypto(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;
}

2 个答案:

答案 0 :(得分:0)

如果填充物有问题,可以选择以下内容:

How do I encrypt a string in vb.net using RijndaelManaged, and using PKCS5 padding?

答案 1 :(得分:0)

听起来像是截断问题;可能是因为你创建内存流的方式;当我解密时,它看起来像下面的

MemoryStream msDecrypt = new MemoryStream();
CryptoStream csDecrypt = new CryptoStream(
    msDecrypt, 
    decryptor, 
    CryptoStreamMode.Write);
csStream.Write(encrypted, 0, encrypted.Length);
csStream.Flush();
return csDecrypt.ToArray();

我猜测会附加额外的空字节,并且使用替代方法可能会减轻这种情况。