【问题标题】:Why is crypto with .Net Framework so complicated?为什么 .Net Framework 的加密如此复杂?
【发布时间】:2019-10-01 05:18:09
【问题描述】:

在大多数情况下,我需要使用密码加密字符串,然后将其发送/保存到某处。稍后我想用密码解密它。我没有加密核导弹代码或医疗病人数据!理想的情况是 2 个功能:

string Encrypt(string plainText, string password);
string Decrypt(string cipherText, string password);

我看过crypto documentation...哦,天哪!所以我尝试自己编写上述调用 (see a proof of concept using AES Managed and Base64 encoded payload)。我不是加密专家,为什么我必须编码?我可能做错了什么......

  1. 要从密码中派生密钥,接口需要盐。我可以将密码用作盐吗?我可以重复使用静脉输液作为盐吗?也许不是,但我不想添加其他参数。
  2. 我可以使用固定静脉输液吗?相同的明文和密码应该会产生不同的密文,所以我必须在有效载荷中提供 IV 进行解密。
  3. 我可以使用盐作为密钥并保持 IV 不变吗?感觉不对。
  4. 创建一个 nonce 并从中派生 IV 和 key salt 是一种有效的方法吗?
  5. 如果 .Net 支持 GCM 模式,我还会遇到这个问题吗?

【问题讨论】:

  • 完全有效的问题。这些 API 将非常有用,我认为它们应该存在。加密 API 感觉有点讨厌。 1.0 中的不同 .NET API 由不同的团队完成。大多数都非常好,但框架的某些区域不是。你可以在 GitHub 的 corefx 存储库中提出这个建议。
  • @MarcGravell 固有的复杂性相当有限。例如,您可以使用 AES-GCM 制作一个非常安全且通用的经过身份验证的加密原语。一个电话byte[] Encrypt(byte[] data, byte[] key, byte[] authTag) 就足够了。用户仍然必须了解一些事情,但误用的可能性相当有限。 .NET 框架没有理由让事情变得如此困难。
  • @MarcGravell 和类似的库旨在创建难以误用的原语并具有 非常 简单的 API。 .NET 中的加密具有很多人为的复杂性。就像 ADO.NET 一样,大部分时间你都需要 EF 或 Dapper。想要执行查询?来电查询。不打开和配置大量对象并通过阅读器运行。
  • @usr 同意,我听到了;也许您的 ADO.NET 比较是一个很好的比较,这里是必要的复杂性与不必要的复杂性;失分;但是(旁白)......我认为你不能相信那些 Dapper 的人......
  • 您可能对此(免责声明,由我编写)repository 感兴趣,它包含的方法与您用 14 种不同语言(包括 C#)概述的方法完全相同。

标签: c# .net cryptography aes


【解决方案1】:

.NET 加密 API 公开了一个通用加密库,其中包含实现加密算法的面向对象的方法。当然,要使用这些算法和算法实现,您需要很好地掌握密码学,而这是您目前所缺乏的。

需要这个通用库来实现现有的各种协议。通常,单个算法不能满足特定的用例(在您的情况下,使用密码加密字符串,返回不同的字符串)。因此,需要选择或设计一个能够满足该用例的协议。该协议可以例如定义容器格式,例如 CMS 或 PGP,例如可用于加密电子邮件(用例)。

您直接尝试应用加密算法来解决您的用例。那是行不通的。您需要一个预制的协议,最好使用预制的 API。


请注意,有许多不同的用例、许多不同的协议以及关于如何正确创建和实施这些协议的更多意见。例如,Libsodium / NaCl 定义了一个名为 SecretBox 的小型容器格式,它确实需要您完成一些工作。

但是,在 NaCl 之上实现 TLS 当然是不可能的,因为功能/算法不存在。同样,.NET 需要一个像 .NET API 这样的通用加密库,以便其他人实现他们的协议。


因此,要么您必须硬着头皮尝试创建自己的协议,要么采用现有的协议并进行有根据的猜测,如果它是安全的(希望该协议已经过多次审查/更新)。远离没有额外贡献者的单人项目(例如许多未经审查的示例代码)。

对于您自己的协议,是的,存在诸如未将盐与密文一起存储之类的错误。您需要一个随机的(或至少是唯一的)盐以确保安全,重复使用密码肯定是不安全的。不要让它成为一个人的项目本身,然后借用协议或对其进行审查。


好的,那么快:

  1. 要从密码中派生密钥,接口需要盐。我可以将密码用作盐吗?我可以重复使用静脉输液作为盐吗?也许不是,但我不想添加其他参数。

不,盐需要是唯一的,最好是随机的;密码/盐的组合应该是唯一的(它不应该重复,即使在时间上也不应该重复,或者跨越不同的域)。

  1. 我可以使用固定静脉输液吗?相同的明文和密码应该会产生不同的密文,所以我必须在有效载荷中提供 IV 进行解密。

不,除非键每次都更改值(见上文)。对于 CBC,IV 应该是不可预测的除非您每次都使用新密钥。

  1. 我可以使用盐作为密钥并保持 IV 不变吗?感觉不对。

这是可能的,只要你不重复加盐。

  1. 创建一个 nonce 并从中派生 IV 和 key salt 是一种有效的方法吗?

这取决于非常具体的细节。换句话说,如果您不完全了解自己在做什么,我不会尝试。

  1. 如果 .Net 支持 GCM 模式,我还会遇到这个问题吗?

当然,从某种意义上说,如果您使用 GCM,您的问题会更糟,因为使用具有相同密钥的 GCM 和 IV 完全被破坏了。


请记住,GCM 只是一种算法,而不是协议,它本身无法解决您的用例。

【讨论】:

  • 盐需要什么?密钥派生只是获取密码字符串并将其转换为字节的一种方法。这不是密码数据库。
  • 您也可以在彩虹表中使用某个明文的加密。所以至少每个密码的盐应该是不同的。您可以为每个密码使用静态盐,但是您将拥有一个静态密钥,并且您必须使用随机 IV;您不妨使用随机盐。更多信息,例如here。请注意,PBKDF2(通常用于对数据库存储的密码进行哈希处理)设计用于基于密码的加密/密钥派生(顾名思义)并且使用盐。
  • 所以您是说使用随机盐而不是随机 IV(使用 0 IV)并以这种方式获得更好的属性?对我来说,基于彩虹的加密攻击似乎非常深奥。它需要索引所有可能的密码和组合的明文。但我想这是一种可能。
  • 只有一个加密块最好使用已知的明文就足够了。但是,是的,这将是一个长镜头。这么看:如果你使用相同的密钥,你通常需要一个随机的 IV,为什么不派生一个不同的密钥?
猜你喜欢
  • 1970-01-01
  • 2017-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-22
  • 2015-02-11
相关资源
最近更新 更多