C# 解密word、powerpoint文件时出错
我正在使用aes加密来加密文件C# 解密word、powerpoint文件时出错,c#,.net,encryption,cryptography,C#,.net,Encryption,Cryptography,我正在使用aes加密来加密文件 private static void Encrypt(string inputFilePath, string outputfilePath) { string EncryptionKey = "MAKV2SPBNI99212"; using (Aes encryptor = Aes.Create()) { Rfc2898DeriveBytes pdb = new Rfc2898De
private static void Encrypt(string inputFilePath, string outputfilePath)
{
string EncryptionKey = "MAKV2SPBNI99212";
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (FileStream fsOutput = new FileStream(outputfilePath, FileMode.Create))
{
using (CryptoStream cs = new CryptoStream(fsOutput, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
using (FileStream fsInput = new FileStream(inputFilePath, FileMode.Open))
{
//int data;
//while ((data = fsInput.ReadByte()) != -1)
//{
// cs.WriteByte((byte)data);
//}
byte[] bytes = new byte[fsInput.Length];
while (fsInput.Read(bytes, 0, (int)fsInput.Length) > 0) ;
cs.Write(bytes, 0, bytes.Length);
}
}
}
}
}
private static void Decrypt(string inputFilePath, string outputfilePath)
{
string EncryptionKey = "MAKV2SPBNI99212";
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (FileStream fsInput = new FileStream(inputFilePath, FileMode.Open))
{
using (CryptoStream cs = new CryptoStream(fsInput, encryptor.CreateDecryptor(), CryptoStreamMode.Read))
{
using (FileStream fsOutput = new FileStream(outputfilePath, FileMode.Create))
{
//int data;
//while ((data = cs.ReadByte()) != -1)
//{
// fsOutput.WriteByte((byte)data);
//}
byte[] bytes = new byte[fsInput.Length];
while (cs.Read(bytes, 0, (int)fsInput.Length) > 0) ;
fsOutput.Write(bytes, 0, bytes.Length);
}
}
}
}
}
在主函数i中,加密、解密word文件:
Encrypt(@"E:\test.docx", @"E:\test.enc");
Decrypt(@"E:\test.enc", @"E:\test_new.docx");
当我使用ReadByte函数加密时,解密每个字节。文件test_new.docx已创建并正常打开。但当我使用Read函数加密、解密许多字节时,文件test_new.docx被创建但无法打开,错误内容。
你有什么想法吗?谢谢 问题在于解密的
字节
数组末尾的零太多。这是因为使用的密码要求每个加密块与块大小匹配,如果不匹配,则会被填满。所以fsInput.Length
实际上大于解密字节的长度
要去除解密字节中的这些零,请在Decrypt
方法中替换此代码
using (FileStream fsOutput = new FileStream(outputfilePath, FileMode.Create))
{
byte[] bytes = new byte[fsInput.Length];
while (cs.Read(bytes, 0, (int)fsInput.Length) > 0) ;
fsOutput.Write(bytes, 0, bytes.Length);
}
使用此代码
using (FileStream fsOutput = new FileStream(outputfilePath, FileMode.Create))
using (BinaryWriter fsDecrypted = new BinaryWriter(fsOutput))
using (BinaryReader br = new BinaryReader(cs))
fsDecrypted.Write(br.ReadBytes((int)fsInput.Length));
现在它应该可以正常工作了。问题是解密的
字节
数组末尾有太多的零。这是因为使用的密码要求每个加密块与块大小匹配,如果不匹配,则会被填满。所以fsInput.Length
实际上大于解密字节的长度
要去除解密字节中的这些零,请在Decrypt
方法中替换此代码
using (FileStream fsOutput = new FileStream(outputfilePath, FileMode.Create))
{
byte[] bytes = new byte[fsInput.Length];
while (cs.Read(bytes, 0, (int)fsInput.Length) > 0) ;
fsOutput.Write(bytes, 0, bytes.Length);
}
使用此代码
using (FileStream fsOutput = new FileStream(outputfilePath, FileMode.Create))
using (BinaryWriter fsDecrypted = new BinaryWriter(fsOutput))
using (BinaryReader br = new BinaryReader(cs))
fsDecrypted.Write(br.ReadBytes((int)fsInput.Length));
现在,它应该可以正常工作。您使用了错误的流长度进行解密,而不是fsInput.length,您应该使用cs.length,因为这是您实际读取的流。FileStream和CryptoStream的长度不同,因此您无法交换它们。然而,CryptoStream也是非寻道的,这意味着它无法寻道流的结尾,并且使用.Length将抛出NotImplementedException。因此,对于像CryptoStream这样的非寻道流,您必须使用ReadByte()一次读取一个字节,直到流表示已完成。您使用了错误的流长度进行解密,而不是fsInput.length。您应该使用cs.length,因为这是您实际读取的流。FileStream和CryptoStream的长度不同,因此您无法交换它们。然而,CryptoStream也是非寻道的,这意味着它无法寻道流的结尾,并且使用.Length将抛出NotImplementedException。因此,对于像CryptoStream这样的非寻道流,您必须使用ReadByte()一次读取一个字节,直到流显示它已完成。在加密文件之前,我在末尾添加了一些字节。在解密字节数组之后,我找到了这个字节来精确地获取文件长度。在加密文件之前,我在末尾添加了一些字节。在解密字节数组之后,我找到这个字节来精确获取文件长度。默认填充为PKCS#7
PaddingMode.PKCS7
非空填充。MSDN上的页面。请看“尼尔·亨比答案”。@扎夫你完全正确,我更正了我的答案。但我认为使用BinaryReader
一次读取所有内容比尼尔·亨比建议的ReadByte()
性能更好。@zaph解密的字节中的零不是来自PKCS 7填充,而是来自byte[]bytes=新字节[fsInput.Length]因为fsInput.Length
实际上太大了。我更正了我的回答以反映这一方面。我的回答还有错误吗?(我愿意学习。)注意,fsInput.Length
在加密和解密在距离和时间上分开的一般情况下是未知的。如果为加密和解密指定相同的填充选项,并对解密的最后字节调用final,则解密的数据将与加密的普通数据匹配。不需要摆弄。如果创建的缓冲区大于解密数据的大小,请将缓冲区截断为解密数据的报告大小。@haindl我已经测试了您的代码。这工作做得很好。BinaryReader的ReadBytes函数精确返回字节长度。默认填充为PKCS#7PaddingMode。PKCS7
非空填充。MSDN上的页面。请看“尼尔·亨比答案”。@扎夫你完全正确,我更正了我的答案。但我认为使用BinaryReader
一次读取所有内容比尼尔·亨比建议的ReadByte()
性能更好。@zaph解密的字节中的零不是来自PKCS 7填充,而是来自byte[]bytes=新字节[fsInput.Length]因为fsInput.Length
实际上太大了。我更正了我的回答以反映这一方面。我的回答还有错误吗?(我愿意学习。)注意,fsInput.Length
在加密和解密在距离和时间上分开的一般情况下是未知的。如果为加密和解密指定相同的填充选项,并对解密的最后字节调用final,则解密的数据将与加密的普通数据匹配。不需要摆弄。如果创建的缓冲区大于解密数据的大小,请将缓冲区截断为解密数据的报告大小。@haindl我已经测试了您的代码。这工作做得很好。BinaryReader的ReadBytes函数精确返回字节长度。new BinaryReader(cs)。ReadBytes((int)fsInput.length)
将立即读取正确的字节数。对于Office文档的典型文件大小,这应该比一次读取一个字节有更好的性能。我使用cs.Length,但它抛出异常,cs.Length无法访问。这是真的。当我比较加密后和解密前的文件流长度时,它是不同的。我想读很多字节以提高加密、解密大文件时的速度。只有在ecrypt、decypt word、powerpoint文件和其他文件正常工作时才会出现此错误。new BinaryReader(cs)。ReadBytes((int)fsInput.Length)
将立即读取正确的字节数。它的性能应该远远好于