1

当我使用错误的密钥时,我得到一个“解密的”垃圾文件和来自 mscorlib.dll 的异常,“指定的块大小对此算法无效。” 相反,我想要的是解密完全失败而不会引发异常。

这是我当前的代码(改编自我在互联网上找到的 vb.net 示例,因此如果有更好的解决方案将不胜感激)

    public static bool EncryptOrDecryptFile(string strInputFile,
        string strOutputFile, string pKey, string pIv, CryptoAction Direction)
    {
        Byte[] bytKey = CreateKey(pKey);
        Byte[] bytIV = CreateIV(pIv);
        bool pRet = false;
        if (!File.Exists(strInputFile))
            return false;

        try
        {
            using (FileStream fsInput = new FileStream(strInputFile, FileMode.Open, FileAccess.Read))
            {
                using (FileStream fsOutput = new FileStream(strOutputFile, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    fsOutput.SetLength(0);
                    byte[] bytBuffer = new byte[4097];
                    long lngBytesProcessed = 0;
                    long lngFileLength = fsInput.Length;
                    int intBytesInCurrentBlock = 0;
                    CryptoStream csCryptoStream = null;
                    RijndaelManaged cspRijndael = new RijndaelManaged();
                    cspRijndael.BlockSize = 4096;
                    switch (Direction)
                    {
                        case CryptoAction.ActionEncrypt:
                            csCryptoStream = new CryptoStream(fsOutput, cspRijndael.CreateEncryptor(bytKey, bytIV),
                                                              CryptoStreamMode.Write);
                            break;
                        case CryptoAction.ActionDecrypt:
                            csCryptoStream = new CryptoStream(fsOutput, cspRijndael.CreateDecryptor(bytKey, bytIV),
                                                              CryptoStreamMode.Write);
                            break;
                    }
                    while (lngBytesProcessed < lngFileLength)
                    {
                        intBytesInCurrentBlock = fsInput.Read(bytBuffer, 0, 4096);
                        csCryptoStream.Write(bytBuffer, 0, intBytesInCurrentBlock);
                        lngBytesProcessed = lngBytesProcessed + Convert.ToInt64(intBytesInCurrentBlock);
                    }
                    csCryptoStream.Close();
                }
            }
            pRet = true;
        }
        catch (Exception ex)
        {
            pRet = false;
        }
        return pRet;
    }
    #endregion
}
4

2 回答 2

1

没有一种操作模式可用于RijndaelManaged提供完整性保护或身份验证。依靠检查填充的有效性是不可替代的,因为您很容易通过有效的填充得到不正确的消息。

相反,您应该将HMAC应用于加密消息。

于 2011-03-01T13:42:13.650 回答
1

鉴于任何正确长度的位组合都可能是有效密钥,IV 也是如此,因此加密流无法确定其中任何一个是不正确的,直到它尝试解密最后的密码文本块 -此时它检测到填充错误并引发异常。此外,你不能使用任何你想要的块大小——某些块大小对特定的加密提供者有效——对于 Rijndael,我认为有效的块大小是 128、192 和 256。

避免“垃圾”文件的唯一方法是在内存中执行所有解密,或者写入临时文件而不是最终输出文件。没有办法避免异常,但无论如何它应该是一个不寻常的事件。


我还将摆脱代码中的所有缓冲区管理以及长度检查等,只在输入流和加密流之间使用Stream.CopyTo 。例如:

using (FileStream fsInput = new FileStream(strInputFile, FileMode.Open, FileAccess.Read))
{
    using (FileStream fsOutput = new FileStream(strOutputFile, FileMode.OpenOrCreate, FileAccess.Write))
    {
        CryptoStream csCryptoStream = null;
        RijndaelManaged cspRijndael = new RijndaelManaged();
        cspRijndael.BlockSize = 256;
        switch (Direction)
        {
            case CryptoAction.ActionEncrypt:
                csCryptoStream = new CryptoStream(fsOutput, cspRijndael.CreateEncryptor(bytKey, bytIV),
                                                  CryptoStreamMode.Write);
                break;
            case CryptoAction.ActionDecrypt:
                csCryptoStream = new CryptoStream(fsOutput, cspRijndael.CreateDecryptor(bytKey, bytIV),
                                                  CryptoStreamMode.Write);
                break;
        }
        fsInput.CopyTo(csCryptoStream);
        csCryptoStream.Close();
    }
}
pRet = true;
于 2011-03-01T13:14:50.597 回答