使用AES加密和解密文件会生成损坏的文件

时间:2016-02-23 10:14:58

标签: c# encryption cryptography aes

我尝试使用AES加密和解密文件。我遇到的问题是,当文件被解密时,它会被破坏而你无法打开它。原始文件的长度为81.970字节,解密文件的长度为81.984字节...因此由于某种原因添加了14个字节。问题可能在于文件加密的方式,但我不知道我做错了什么。

我在这里缺少什么?这可能是我处理密码,iv和填充的方式吗?

谢谢你的时间!

这是我用来加密的代码:

    private AesManaged aesManaged;
    private string filePathToEncrypt;

    public Encrypt(AesManaged aesManaged, string filePathToEncrypt)
    {
        this.aesManaged = aesManaged;
        this.filePathToEncrypt = filePathToEncrypt;
    }

    public void DoEncryption()
    {
        byte[] cipherTextBytes;
        byte[] textBytes = File.ReadAllBytes(this.filePathToEncrypt);

        using(ICryptoTransform encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV))
        using (MemoryStream ms = new MemoryStream())
        using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
        {
            cs.Write(textBytes, 0, textBytes.Length);
            cs.FlushFinalBlock();
            cipherTextBytes = ms.ToArray();
        }

        File.WriteAllBytes("EncryptedFile.aes", cipherTextBytes);
    }

这是我用来解密的代码:

    private AesManaged aesManaged;
    private string filePathToDecrypt;

    public Decrypt(AesManaged aesManaged, string filePathToDecrypt)
    {
        this.aesManaged = aesManaged;
        this.filePathToDecrypt = filePathToDecrypt;
    }
    public void DoDecrypt()
    {
        byte[] cypherBytes = File.ReadAllBytes(this.filePathToDecrypt);
        byte[] clearBytes = new byte[cypherBytes.Length];


        ICryptoTransform encryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV);
        using (MemoryStream ms = new MemoryStream(cypherBytes))
        using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Read))
        {
            cs.Read(clearBytes, 0, clearBytes.Length);
            clearBytes = ms.ToArray();
        }

        File.WriteAllBytes("DecryptedFile.gif", clearBytes);
    }

以下是我如何调用这些函数:

        string filePathToEncrypt = "dilbert.gif";
        string filePathToDecrypt = "EncryptedFile.aes";

        string password = "Password";
        string passwordSalt = "PasswordSalt";

        Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(passwordSalt));
        var aesManaged = new AesManaged
        {

            Key = deriveBytes.GetBytes(128 / 8),
            IV = deriveBytes.GetBytes(16),
            Padding = PaddingMode.PKCS7
        };

        Console.WriteLine("Encrypting File...");
        var encryptor = new Encrypt(aesManaged, filePathToEncrypt);
        encryptor.DoEncryption();
        Thread.Sleep(300);

        Console.WriteLine("Decrypting File...");
        var decryptor = new Decrypt(aesManaged, filePathToDecrypt);
        decryptor.DoDecrypt();
        Thread.Sleep(300);

2 个答案:

答案 0 :(得分:1)

尝试:

public void DoEncryption()
{
    byte[] cipherBytes;
    byte[] textBytes = File.ReadAllBytes(this.filePathToEncrypt);

    using (ICryptoTransform encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV))
    using (MemoryStream input = new MemoryStream(textBytes))
    using (MemoryStream output = new MemoryStream())
    using (CryptoStream cs = new CryptoStream(output, encryptor, CryptoStreamMode.Write))
    {
        input.CopyTo(cs);
        cs.FlushFinalBlock();
        cipherBytes = output.ToArray();
    }

    File.WriteAllBytes("EncryptedFile.aes", cipherBytes);
}

public void DoDecrypt()
{
    byte[] cypherBytes = File.ReadAllBytes(this.filePathToDecrypt);
    byte[] textBytes;

    using (ICryptoTransform decryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV))
    using (MemoryStream input = new MemoryStream(cypherBytes))
    using (MemoryStream output = new MemoryStream())
    using (CryptoStream cs = new CryptoStream(input, decryptor, CryptoStreamMode.Read))
    {
        cs.CopyTo(output);
        textBytes = output.ToArray();
    }

    File.WriteAllBytes("DecryptedFile.gif", textBytes);
}

请注意,可以修改代码以不使用临时byte[]并直接读/写输入/输出流。

一般来说,你不能从密文的长度中设定明文的长度,所以这一行:

new byte[cypherBytes.Length]

完全错了。

请在2016年不要使用Encoding.ASCII。它就像上个世纪一样。使用Encoding.UTF8支持非英文字符。

答案 1 :(得分:0)

答案可能非常简单。我没有看到你在哪里尝试选择密码模式,所以默认情况下它可能需要CBC,因为IV被引入。然后,81.970被14个字节填充,可以被32整除。所以当它发生时,你分配的内存只有81.970,所以填充字节不能正确写入,导致某种内存泄漏,并且当解密时开始,unpadding无法正常工作。