C#将加密数据从文件传递到内存流。投掷例外

时间:2010-07-20 05:14:51

标签: c# exception-handling

从早期的问题中继续排序,做了一堆谷歌搜索,但我不认为我在这里正确的道路上。基本上我正在做的是用一段代码打开一个文件,如下所示:

byte[] cipherText = File.ReadAllBytes(encryptedFile);

然后将该字节数组传递给静态bool方法,该方法调用实际的解密方法,如果没有引发加密异常,则返回true。在我的主窗体上,我有一个按钮单击,它从一个If语句调用静态bool,如果它返回true则解锁一些额外的接口项,如果它返回false则弹出一个“无效密码”消息框。

我逐步完成整个过程,并抛出“填充无效,无法删除”。异常,一些搜索显示应该在提供错误的解密密钥时发生。我知道我正在传递相同的密钥,至少我正在键入它,所以我假设问题与byte []的传递方式或者流本身有关。以下是解密方法的示例:

public static string Decrypt(string password, byte[] ciphertext)
    {
        byte[] key, iv;
        CreateKeyIV(password, out key, out iv);
        using (MemoryStream encrypted = new MemoryStream(ciphertext))
        using (CryptoStream dec = new CryptoStream(encrypted, _algorithm.CreateDecryptor(key, iv), CryptoStreamMode.Read))
        using (StreamReader reader = new StreamReader(dec))
        {
            try
            {
                return reader.ReadToEnd();
            }
            catch (CryptographicException)
            {
                throw new CryptographicException("Invalid password.");
            }
            finally
            {
                encrypted.Close();
                dec.Close();
                reader.Close();
            }
        }
    }

有人看到我缺少的东西吗?

2 个答案:

答案 0 :(得分:4)

解密代码看起来没问题,虽然我会做一些改动:

  • 为什么不将流或文件名而不是加密数据作为字节数组传递?没有必要一次性阅读所有内容,然后当您使用MemoryStream作为来源时将数据包装在FileStream
  • 您无需致电Close - 这就是使用声明的目的
  • 为什么要抛出一个错误传达问题的新CryptographicException,而不是让现有的异常冒泡?

换句话说,这就是我的方法:

public static string Decrypt(string password, Stream encrypted)
{
    byte[] key, iv;
    CreateKeyIV(password, out key, out iv);
    using (CryptoStream dec = new CryptoStream(encrypted,
           _algorithm.CreateDecryptor(key, iv), CryptoStreamMode.Read))
    using (StreamReader reader = new StreamReader(dec))
    {
        return reader.ReadToEnd();
    }
 }

但是,你已经在另一条评论中表明了错误:

 // Bad code! Do not use!
 byte[] newCipher = Encryptor.Encrypt(newPass, newPass);
 string writeIt = System.Text.Encoding.UTF8.GetString(newCipher);

您正在破坏加密数据。加密结果很少是有效的UTF-8字符串。您应该直接将其写入磁盘 in binary ,而不是尝试将其转换为文本。您的加密代码可以直接执行此操作,也可以调用File.WriteAllBytes()。如果绝对必须在某个时刻将任意二进制数据转换为字符串,则应使用Convert.ToBase64String(data)将其转换为base64。这样你以后可以通过再次转换它来获得相同的二进制数据。试图将其“解码”为文本是一种几乎可靠的方式来丢失数据 - 就像你在这里一样。

答案 1 :(得分:0)

我不会在StreamReader上打开CryptoStream,但实际上我会直接调用类Read的方法CryptoStream,并传递byte[] }缓冲区,它将保存解密数据。


这是我的一个片段。我已经将它用于MemoryStream和FileStream。

Stream s = ...;

ICryptoTransform cTransform = Encryptor.CreateDecryptor();
using (CryptoStream cStream = new CryptoStream(s, cTransform, CryptoStreamMode.Read)) {
byte[] mCryptoData = new byte[s.Length];
cStream.Read(mCryptoData, 0, mCryptoData.Length);
...