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

本文关键字:文件 损坏 使用 加密 解密 AES | 更新日期: 2023-09-27 18:35:52

我正在尝试使用 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);

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

尝试:

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 支持非英语字符。

答案可能很简单。我不明白您尝试在哪里选择密码模式,因此默认情况下可能需要 CBC,因为 IV 已启动。然后,81.970 填充 14 个字节,可被 32 整除。因此,当它发生时,您分配的内存仅为 81.970,因此填充字节无法正确写入,导致某种内存泄漏,并且当启动解密时,取消填充无法正常工作。