【问题标题】:Encrypt a file using File.Encrypt and then Decrypt it to memory stream使用 File.Encrypt 加密文件,然后将其解密到内存流
【发布时间】:2013-02-08 17:07:54
【问题描述】:

我需要实现一个简单的文件加密,然后在需要时将其解密到内存流。 最简单的方法似乎是使用 File.Encrypt 执行此操作,但是否可以将文件解密到内存流,而不是在将文件读取到内存流之前解密文件,从而将其暴露一段时间?

如果 File.Encrypt 不是这种情况下的最佳方式,您会推荐什么?

【问题讨论】:

  • 你想防御什么?
  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
  • 我认为File.Encrypt 设置了文件系统级别的标志。所以如果你在一个空文件上调用File.Encrypt,然后写入它,明文可能永远不会写入磁盘。

标签: c# file memory encryption


【解决方案1】:

File.Encrypt 是一项操作系统功能,但听起来您确实想控制加密的完成方式。

http://msdn.microsoft.com/en-us/library/system.io.file.encrypt.aspx

// This is where the data will be written do.
MemoryStream dataStream = new MemoryStream();

// The encryption vectors
byte[] key = {145,12,32,245,98,132,98,214,6,77,131,44,221,3,9,50};
byte[] iv  = {15,122,132,5,93,198,44,31,9,39,241,49,250,188,80,7};

// Build the encryption mathematician
using (TripleDESCryptoServiceProvider encryption = new TripleDESCryptoServiceProvider())
using (ICryptoTransform transform = encryption.CreateEncryptor(key, iv))
using (Stream encryptedOutputStream = new CryptoStream(dataStream, transform, CryptoStreamMode.Write))
using (StreamWriter writer = new StreamWriter(encryptedOutputStream))
{
    // In this block, you do your writing, and it will automatically be encrypted
    writer.Write("This is the encrypted output data I want to write");
}

加密不适合胆小的人。不过请注意,在尝试此操作之前,您确实应该对常规 IO 和数据流有很强的了解。

【讨论】:

  • 另外,不知道你可以这样嵌套使用!
  • 您应该为每个加密使用随机 IV,我更喜欢 3DES 的 AES。您还忘记了使用 MAC。
  • 是的,我在概念上得到了加密,但我缺乏详细的理解。不过肯定想学。
  • Dan Boneh 的 Coursea Crypto I 课程是免费的,非常非常好。
【解决方案2】:

实施 Crypto 看似简单,实际上相当乏味,有很多细节,而错误的细节通常是安全方面所利用的。最佳实践是使用隐藏这些细节的高级加密框架 ivs、salts、mac、比较、填充、密钥轮换,虽然高级框架不太可能有细节错误,但当它们出现时,它们会被发现并且已修复,堆栈溢出的代码 sn-ps 一般不会。

我一直在移植 Google Keyczar 框架,因此对于 C# 来说会有这样一个高级库。

Keyczar-dotnet

它可用于加密和解密 io 流。

使用nuget在您的项目中安装

PM> Install-Package Keyczar -Pre

然后创建您的密钥集。 (通过拥有一个单独的密钥集文件,它使您能够在将来轮换密钥,并防止您意外地对不应进行硬编码的内容进行硬编码。)

PM> KeyczarTool.exe create --location=path_to_key_set --purpose=crypt
PM> KeyczarTool.exe addkey --location=path_to_key_set --status=primary

然后在您的代码中,您可以使用任何您想要的 IO 流进行加密:

using(var encrypter = new Encrypter("path_to_key_set"))
{
     encrypter.Encrypt(plaintextStream, ciphertextStream);
}

和解密:

using(var crypter = new Crypter("path_to_key_set"))
{
     crypter.Decrypt(ciphertextStream, plaintextStream);
}

【讨论】:

    【解决方案3】:

    这是我编写的第一个加密代码 - 请注意,虽然这是了解正在发生的事情的良好起点,但静态密码和静态盐不是一个好主意! (感谢您突出显示此 CodesInChaos)

    您可以解密为您喜欢的任何流,包括直接解密为内存流...

    FileInfo file = new FileInfo("SomeFile");
    using (FileStream inFs = file.OpenRead())
    {
        using (MemoryStream outMs = new MemoryStream())
        {
            encryption.Decrypt(inFs, outMs);                    
    
            BinaryFormatter bf = new BinaryFormatter();
            targetType target= bf.Deserialize(outMs) as targetType;
        }
    }
    

    其中加密是其中之一:

    public class EncryptionHelper
    {        
        static SymmetricAlgorithm encryption; 
        static string password = "password";
        static string salt = "this is my salt. There are many like it, but this one is mine.";
    
        static EncryptionHelper()
        {
            encryption = new RijndaelManaged();
            Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(salt));
    
            encryption.Key = key.GetBytes(encryption.KeySize / 8);
            encryption.IV = key.GetBytes(encryption.BlockSize / 8);
            encryption.Padding = PaddingMode.PKCS7;
        }
    
        public void Encrypt(Stream inStream, Stream OutStream)
        {
            ICryptoTransform encryptor = encryption.CreateEncryptor();
            inStream.Position = 0;
            CryptoStream encryptStream = new CryptoStream(OutStream, encryptor, CryptoStreamMode.Write);
            inStream.CopyTo(encryptStream);
            encryptStream.FlushFinalBlock();
    
        }
    
    
        public void Decrypt(Stream inStream, Stream OutStream)
        {
            ICryptoTransform encryptor = encryption.CreateDecryptor();
            inStream.Position = 0;
            CryptoStream encryptStream = new CryptoStream(inStream, encryptor, CryptoStreamMode.Read);
            encryptStream.CopyTo(OutStream);
            OutStream.Position = 0;  
        }
    }
    

    【讨论】:

    • 嘿,我喜欢你的盐评论。说到这里,盐是怎么起作用的?我明白它的目的是什么,但你能指出一个解释它如何运作的资源的方向吗?
    • 错误 1) 每个应用程序的盐,而不是每个加密的盐 2) 静态密码 3) 没有 MAC => 填充预言 4) 常量 IV(如果您使用不会有问题适当的盐,但你没有)
    • @CodesInChaos,你说得完全正确(除了我认为我在设置 IV?)这是我写的第一个加密代码,所以我认为这将是一个有用的开始。
    • 您永远不应该重复使用 (key, iv) 对。由于您的盐是恒定的,因此密码将确定性地生成 (key, iv) 对,因此您的 IV 是无用的。如果您使用随机盐,那么密钥将是唯一的,因此 IV 不再是必需的。
    • @CodesInChaos,我已经更新了我的答案以反映你在这里所说的内容
    猜你喜欢
    • 1970-01-01
    • 2014-10-22
    • 2022-06-27
    • 2020-06-18
    • 1970-01-01
    • 2012-05-19
    • 2016-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多