解密word,powerpoint文件时出错

时间:2016-10-25 12:44:07

标签: c# .net encryption cryptography

我正在使用aes加密技术来加密文件。

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被创建但无法打开,错误内容。 有没有想法?谢谢!

3 个答案:

答案 0 :(得分:1)

您使用错误的流长度进行解密,而不是fsInput.Length,您应该使用cs.Length,因为那是您实际读取的流。 FileStream和CryptoStream的长度不同,因此您无法互换它们。但是,CryptoStream也是非搜索的,这意味着它无法寻找流的结尾并使用.Length将抛出NotImplementedException。因此,对于像CryptoStream这样的非搜索流,您必须使用ReadByte()一次读取一个字节,直到流说它已完成。

答案 1 :(得分:0)

我在加密文件之前在末尾添加了一些字节。解密字节数组后,我找到这个字节来准确获取文件长度。

答案 2 :(得分:-1)

问题是解密的bytes数组末尾有太多的零。这是因为使用过的密码要求每个加密块匹配块大小,如果它不合适,它就会被填满。所以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));

现在它应该按预期工作。