【问题标题】:Beginner: Is this good encryption?初学者:这是好的加密吗?
【发布时间】:2014-04-11 09:02:53
【问题描述】:

我设法拼凑了一些代码来加密/解密一个字符串,我想知道我是否做得很好。换句话说,它真的安全吗?

我在 StackOverflow 的一篇文章中读到,重复使用 IV 是不好的做法,应该避免。我不能肯定地说,但我相信这就是我在这里所做的。确认/拒绝?

也就是说,对于每个操作使用不同的 IV 不会使加密流无法解密吗?恐怕我对这方面的了解并不如我所愿。

代码如下:

Private Function Crypt(InBytes As Byte(), Password As String, Action As EncryptionActions) As Byte()
  Dim oCryptoTransform As ICryptoTransform
  Dim oDesProvider As AesCryptoServiceProvider

  Dim _
    iBlockSize,
    iKeySize,
    iSize As Integer

  Dim _
    aSalt,
    aKey,
    aIV As Byte()

  oDesProvider = New AesCryptoServiceProvider
  oDesProvider.Mode = CipherMode.CBC

  aSalt = {&H10, &H20, &H12, &H23, &H37, &HA4, &HC5, &HA6, &HF1, &HF0, &HEE, &H21, &H22, &H45}

  For iSize = 1024 To 1 Step -1
    If oDesProvider.ValidKeySize(iSize) Then
      iKeySize = iSize
      Exit For
    End If
  Next

  iBlockSize = oDesProvider.BlockSize

  With New Rfc2898DeriveBytes(Password, aSalt, 12345)
    aKey = .GetBytes(iKeySize \ 8)
    aIV = .GetBytes(iBlockSize \ 8)
  End With

  Select Case Action
    Case EncryptionActions.Encrypt : oCryptoTransform = oDesProvider.CreateEncryptor(aKey, aIV)
    Case EncryptionActions.Decrypt : oCryptoTransform = oDesProvider.CreateDecryptor(aKey, aIV)
    Case Else : Throw New ArgumentException("Invalid encryption action specified.")
  End Select

  Using oOutStream As New MemoryStream
    Using oCryptoStream As New CryptoStream(oOutStream, oCryptoTransform, CryptoStreamMode.Write)
      oCryptoStream.Write(InBytes, 0, InBytes.Length)
    End Using

    Return oOutStream.ToArray
  End Using
End Function

【问题讨论】:

  • 你可能想看看加密规则一:NEVER roll your own :)
  • @pnp 即使你没有,你也必须找到一个好的现有实现。这几乎一样难。
  • “永远不要自己动手。”好的,我会买那个。听起来不错,我同意。但是在哪里画出那条线呢?例如,在这段代码中,我使用的是标准的 .NET 库;不能说我没有自己动手吗?但是,如果我有,那么规则 #1 会阻止使用这些库,从而使它们无效。你让我很好奇。请详细说明。
  • @CodesInChaos - 您对 ProtectedData.Unprotect() 有何看法?我发现在我写了这个方法之后,我暂时搁置了这个方法,等待这次调查的结果。
  • @InteXX 这不是通用加密例程。如果您需要操作系统提供的按进程、按 Windows 用户帐户或按机器密钥,它主要有用。我只会用它来加密我自己的密钥,而不是数据。

标签: encryption .net pbkdf2


【解决方案1】:

我不了解.net,所以我不了解详细的代码,但据我所知,至少存在以下问题:

  • 您没有使用经过身份验证的加密。您应该使用 HMAC 之类的 MAC 来检测对密文的操纵。否则,攻击者可能会操纵密文,以便将其解密为合理的明文。
  • 对于 DES,存在弱密钥。如果你不走运,你的派生密钥是一个弱密钥,但获得弱密钥的可能性通常可以忽略不计。此外,您应该使用 AES 而不是 3DES。
  • 我看不到您使用的是哪种密码模式。不推荐欧洲央行。如今,大多数密码学家都推荐使用 CBC 或 CTR。

你应该做的加密方式如下:

  • 随机选择一个密钥或从密码中派生一个密钥
  • 在带有 PKCS#5 填充的 CBC 模式下使用 AES-256
  • 随机选择静脉注射
  • 加密数据
  • 通过 IV + 密文计算 HMAC
  • 发送 IV + 密文 + HMAC

收到密文时:

  • 检查IV+密文的HMAC是否正确
  • 解密密文

【讨论】:

  • OP 的代码使用 PBKDF2,这就是 RFC 2898。 PBKDF2-HMAC-SHA1 使用固定的盐和迭代计数调用,用于提供密钥和 IV。因此,相同的加密密钥和 IV 用于给定的密码。
  • "send IV + ciphertext + HMAC" 在解密时 IV 是 8 个字节,所以这很容易——但是你怎么知道 [ciphertext] 结束和 [HMAC] 开始的地方? (HMAC 用于签署证书,是吗?)
  • 按照您的建议,我已编辑代码以将密码模式设置为 CBC。谢谢。
  • 我刚刚在documentation 中注意到 Mode 属性默认值为 CBC。不过,在代码中显式设置它可能会很好。
  • @InteXX 你需要一个合适的数据序列化方案。正如 DanielE 指出的那样,您应该使用 AesCryptoServiceProvider,而不是 TripleDESCryptoServiceProvider。如果你确实使用 HMAC,你也需要为它生成一个密钥。
【解决方案2】:

您的问题缺乏上下文。你到底想达到什么目的?更准确地说,您要防御哪些攻击?

据我了解,您的代码始终使用相同的密钥和初始化向量。

传递给 PBKDF2 的 salt 参数和传递给分组密码的 IV 都应该使用正确播种的 CSPRNG 生成。在.Net 中使用RNGCryptoServiceProvider

编辑:

盐和静脉注射不是秘密。它们应该是消息或文件的一部分,或者是您的代码生成的任何内容。

还有一条评论:您可能不应该使用硬编码的 PBKDF2 迭代次数。随着硬件变得更快,所需的迭代次数随着时间的推移而增加。因此,迭代次数也应该是消息/文件/记录/任何内容的一部分。

【讨论】:

  • 上下文:这是一个单一的桌面应用程序,它加密并存储密码,以便以后自动登录到不受我控制的远程第三方服务器。重复 Salt/IV:不会为每个操作使用这些新值会使密文无法解密吗?或者我误解了你的建议。
  • 更多上下文:攻击者将从 Windows 注册表中获取 Byte() 数组。
  • 对于随机 salt/IV 问题,正如编辑中所说,SALT 和 IV 不是秘密,您的数据可能看起来像 Salt_bytes + IV_Bytes + PBKDF2_Itteration_Count + Encrypted_Bytes 然后您从文件中读取这三个信息时你解密。
  • @Scott Chamberlain:没错!
  • 不,您永远不会重复使用它,即使在多个会话中也是如此。要么使用固定长度,要么在字节之前添加长度,这样它将是Salt_length (32 bits large) + Salt_bytes (Salt_length bytes large) + IV_Length (32 bits large) + IV_Bytes (IV_Length bytes large) + PBKDF2_Itteration_Count (32 bits large) + Encrypted_Bytes (The rest of the file)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-10
  • 2021-11-04
  • 2019-04-12
  • 1970-01-01
  • 2012-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多