2015-01-02 27 views
1

我正在研究一个简单的实用程序来加密文件作为学习体验。 一切似乎工作正常,但我想知道如果我已安全地设置密钥/ IV /盐数据。Rijndael加密功能 - 密钥/ IV /盐设置

我注意到,当涉及到密码术时,大多数人似乎设想到一个工作环境,加载了一个恶意软件,该恶意软件由远程向导远程准备通过正在运行的应用程序/页面文件的内存来获取这些安全文件。

让我们假装你在一台干净的机器上,然后加密一些文件并关闭计算机。 我想知道的是,某人是否可以拿走你的硬盘,并使用我提出的代码检索文件的内容。

我最关心的攻击矢量是确保页面文件/文件缓存不可访问。 我也想确保使用的Key/IV系统不会使基于彩虹表/散列的攻击变得可行。

输入密码:使用设置为true的passwordchar值的文本框中输入

的密码。

只要在加密后正确删除字符串,我并不关心字符串在内存中。我读到使用SecureString在这一点上是毫无意义的,因为如果您的计算机上已经存在恶意软件,那么您可以轻松地在其上放置一个键盘记录器,这会导致其他一切无用。

private static string salt = "02341235XadfaDADFexA8932F7Dz3J3X"; 

我使用硬编码的32个字符的字符串给密码加盐。 (上面的字符串只是一个例子)

为了解决这个问题,它需要有人用十六进制编辑器反编译/查看.exe文件本身(我知道的东西很容易做到,但是额外的步骤)。

我曾考虑过这种盐是可编辑的,但我不知道如何安全地存储它。我认为加密你的盐有点荒谬,因为那样你就会遇到同样的问题,所以把它作为一个硬编码的字符串放在exe文件中看起来对我来说最有意义。

这种方式的工作方式是,如果你决定让你的密码“密码”,它实际上保存为“thepasswordfaDADFexA8932F7Dz3J3X”。

这里的主要关键是你总是有一个32个字符的密码,而不管你输入什么。

密钥和IV:

密钥和IV也盐腌如下。 这是我希望得到一些意见,因为说实话,我不是很确定它在做什么:

UnicodeEncoding UE = new UnicodeEncoding(); 
byte[] keysalt = UE.GetBytes("Xjafe231x42X423XadXCadfkhjeAdS");  //Another string of random characters hard coded in the exe 
byte[] IVSodium = UE.GetBytes("83Xkda7l78Dkx85KdJazppoqq6SaxDs");  //Another string of random characters hard coded in the exe 
byte[] key = new Rfc2898DeriveBytes(password, keysalt).GetBytes(32); //Derive the key using the password and salt 
byte[] IV = new Rfc2898DeriveBytes(password, IVSodium).GetBytes(16); //Derive the IV using the password and salt 

我主要在这里担心的是,IV基于关键。再次,我不确定这是否会导致任何问题,我希望你们可以让我知道是否有问题,它们是什么。

此外,这是另一种情况下,硬编码盐是一种不好的做法?这应该存储在加密文件中,如果是这样,它是否真的使它更安全?我应该让这个可编辑吗?

的加密流是使用使用关键字的设置:

using (FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create)) 
{ 
    using (RijndaelManaged RMCrypto = new RijndaelManaged()) 
    { 
     using (CryptoStream cs = new CryptoStream(fsCrypt, RMCrypto.CreateEncryptor(key, IV), CryptoStreamMode.Write)) 
     { 
      using (FileStream fsIn = new FileStream(inputFile, FileMode.Open)) 
      { 
       byte[] buffer = new byte[4096]; //4096 is kind of arbitrary - better idea? 
       int data; 
       long bytesRead = 0; 
       while((data = fsIn.Read(buffer, 0, buffer.Length)) > 0) 
       { 
        bytesRead += data; 
        ///////////////////////////////////////// 
        // Handle Aborts and Update Progress Bar 
        ///////////////////////////////////////// 
        if (!caller.isClosing) 
         caller.Invoke((MethodInvoker)delegate { 
          caller.fileProgressBar.Value = ((int)(((double)bytesRead/totalBytes) * 100)); 
         }); 
        else 
         return false; //Encryption Aborted 
        ///////////////////////////////////////// 
        cs.Write(buffer, 0, data); 
        fsIn.Close(); 
        cs.Close(); 
        fsCrypt.Close(); 
        return true; 
       } 
      } 
     } 
    } 
} 

感谢您的时间和请让我知道,如果有设置键/ IV /盐更好的办法。 我认为,只要没有包含类似字符的IV和Key的数学问题,它就很可能足够安全。如果是这样,我是否也应该使用硬编码的IV?这似乎很奇怪。

请注意,我没有保存密码或任何类似的散列。密码不保存在任何地方。它只是用来生成密钥和IV。

谢谢你的时间。

编辑:下面是对未来的任何人推荐的更改。

请注意,这不是用胡椒 - 只是一个随机的盐,虽然这将是很容易的添加

byte[] salt = new byte[32];          //Create a 32 byte salt 
rand.NextBytes(salt);            //Fill it with random values (use RandomNumberGenerator rand = new RNGCryptoServiceProvider(); to be safe 
byte[] IV = new byte[16];           //Create a 16 byte IV 
rand.NextBytes(IV);            //Fill it with random numbers 
byte[] key = new Rfc2898DeriveBytes(password, salt).GetBytes(32); //Derive our Key by mixing our password with the salt 

using (FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create)) 
{ 
    using (RijndaelManaged RMCrypto = new RijndaelManaged()) 
    { 
     using (CryptoStream cs = new CryptoStream(fsCrypt, RMCrypto.CreateEncryptor(key, IV), CryptoStreamMode.Write)) 
     { 
      using (FileStream fsIn = new FileStream(inputFile, FileMode.Open)) 
      { 
       fsCrypt.Write(salt, 0, salt.Length); //Write our salt to the file 
       fsCrypt.Write(IV, 0, IV.Length);  //Write our IV to the file 
       fsIn.CopyTo(cs);      //Encrypt and Write 
      } 
     } 
    } 
} 
+1

不要使用固定盐,盐的一点是如果密码重用,你不能说它被重用。盐不需要保密,只需将其附加到正在加密的文件的前面。 –

+0

好的,那么直接把盐写入被加密文件的开始处?此外,盐在这里真的有必要吗?我没有散列任何东西。没有存储的密码。我想确保密码可以是任意长度,并且仍然可以使用算法,所以我知道它需要一定数量的字符长度。缺少硬编码或将随机字符附加到文件的开头(基本上是同一个东西,不是?)会影响任何内容吗?基本上,我可能会错误地将它称为盐来解释它。 – user1274820

回答

3

该盐被用于两个目的:

  1. 防止彩虹表攻击(如果施加其正确确实);
  2. 防止相同的密码生成相同的密码散列。

为此盐需要是随机数据的8至16个字节(未字符),存储有密码哈希。如果使用静态散列,则会破坏散列的两个用途。

如果您需要字符串,请使用base 64编码盐和密码哈希。如果你想要,你可以在调用密码哈希函数之前向盐中添加静态数据(有时称为“胡椒”)。如果程序数据不容易被攻击者读取,这可能会增加一些安全性。

你不应该直接自己混合盐和密码; Rfc2898DeriveBytes(这是PBKDF2的一个实现)已经混合了这两个。您也不应该存储密码,也不应该向其中添加任何数据。 PBKDF2可以处理任何大小的输入,所以它不会添加任何功能。

现在可以从PBKDF2功能中使用IV(使用GetBytes)。然而,存在一个问题,这很可能会使PBKDF2函数的迭代次数增加一倍,这会消耗CPU时间并降低攻击者的优势。生成一个随机IV并将其加密到密文可能更好。

所以最后你应该存储salt | IV | ciphertext,然后使用salt | pepper作为盐并计算你的密钥,然后使用计算出的密钥和IV进行加密/解密。

+0

非常感谢您的跟进。你回答了几个问题,但我没有问。所以基本上,我不需要加入IV - 我可以随机生成一个并将其写入文件。将密钥与盐结合使用时,我可以使用密码并拨打一个Rfc2898的电话。我将写入salt(16字节),IV(16字节),然后在解密期间将相同数量的字节读入这些值。我喜欢胡椒的想法,所以在这种情况下,我可以使用一个8字节的静态胡椒粉和一个8字节的随机盐,使用rfc2898 – user1274820

+1

来混合是的,听起来像你有想法。盐和胡椒各16个字节是比较保守的,它不会增加很多处理。 –

+0

密钥也不会被添加到它吗?我只应该打电话给rfc2898,听起来就像是你说的那样。 DeriveBytes(key,salt + pepper).GetBytes(32);对? rand.NextBytes(新字节[16])= IV – user1274820

0

据我所知,

  1. IV /盐不需要是私人的。它可以以纯文本形式存储在硬盘上。事实上,盐必须是纯文本的,否则你不能用它产生相同的输出。
  2. 这不是一个好主意,因为它可能会泄漏您的关键信息,因此使用您的关键信息来生成IV。
  3. 你无法防止像彩虹一样的攻击。但随着盐,彩虹的攻击变得昂贵,因为只有这个盐的价值。
  4. 有一个可能对你有用的密钥推导函数的标准(http://en.wikipedia.org/wiki/PBKDF2)。
+0

非常感谢您的回复。因此,对于IV和Key使用相同的盐,或者您认为我应该生成两种随机盐,将它们写入文件,使用盐生成IV,然后使用盐生成最终密钥?此外,我可以将一个静态字符串追加到密钥的末尾,以便它总是32个字符?这会对消费产生负面影响吗?很明显,我永远不会写文件的关键部分,所以我假设我必须使它静态?再次感谢你的回复。 – user1274820

+0

我认为最好分别使用两个盐值和密钥。可以将一个静态字符串附加到密钥的末尾,但它不会使您的原始密钥比不添加该字符串更安全。 – monkeyo

+0

非常感谢您回答我的问题。我很感激! – user1274820