首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >.NET DPAPI和AES加密:感官检查

.NET DPAPI和AES加密:感官检查
EN

Stack Overflow用户
提问于 2016-07-16 23:17:56
回答 2查看 1.8K关注 0票数 0

我正准备为我目前正在工作的一个网站编写一个新的加密系统,并想看看我是否能让人感觉到-如果可能的话,在我开始之前检查它!

更新:应该更清楚我最初的问题。我需要加密一些用户数据,我也需要能够在以后的数据中读取这些数据。此外,我还需要存储用户密码或密码哈希,以便在登录时验证用户。

计划是:

  1. 主密钥:创建一个DPAPI应用程序来获取基于文本的主密钥,通过DPAPI加密,然后将加密的输出保存到服务器上的文本文件中。这是一个一次性的任务,我将在每次将站点移动到新服务器时执行。主密钥将用于执行AES加密。
  2. 新用户注册时的 2.1。保存密码数据/密码数据的散列。 2.2。加载主密钥文件,使用DPAPI解密密钥。使用解密的主密钥,并为每个用户数据创建一个新的随机IV创建一个AES加密字符串。以相应的随机IV作为加密字符串的前缀,保存每个加密字符串,然后插入数据库中的varchar列。
  3. 用户登录时的 3.1。匹配密码散列以验证user.3.2。对于每个加密的用户数据字段,将内容分成两部分: IV和加密数据。从DPAPI和IV中获取主密钥,解密数据并在屏幕上显示.

这听起来怎么样?上述问题是否存在明显的缺陷?

我对此很陌生,以前我用过企业图书馆安全来处理这类东西(这在.NET内核中不再可用了!),所以我们会非常感谢您的帮助!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-07-17 18:32:49

忽略密码问题,只考虑用户数据,您的方案是好的,但可以改进。

基本上,您有一个主密钥--一个对称密钥或16或32个字节,它在rest (磁盘上)受到保护,并在服务器上的内存中解密。

使用主密钥对用户数据进行加密,对每一段数据使用随机IV。确保使用加密强随机数据。

你把IV和密文放在一起,这很好。尽管IV和密文是二进制的,所以您必须使用blob数据库类型,或者使用Base64对二进制文件进行编码,以便将其存储为varchar。

您应该考虑添加某种形式的篡改检测。例如,您可以使用两个主密钥-一个用于加密/解密,另一个用于数据上的HMAC。您将使用加密密钥对数据进行加密,然后在IV +密文(使用HMAC的第二个主密钥)上应用HMAC,并将HMAC存储在IV和密文旁边(您甚至可以附加它)。在解密之前,您要验证HMAC。这将告诉您,如果IV +密文中的任何内容已被更改。

你没提到填充物。如果使用AES CBC模式,则如果数据不是16个字节的倍数,则需要对其进行填充。使用填充时,您必须小心,不要意外地提供“填充oracle",攻击者可以向服务器发送任意密文,服务器的响应告诉攻击者”填充错误“或”无效解密“--即服务器响应中存在差异。

如果您使用AES GCM模式,那么等效的HMAC是内置的-您只需要一个主密钥,而GCM本身将检测到密文的篡改。这还允许您包含“关联数据”,这不是加密的一部分,而是包含在“身份验证”中,也就是说,就好像它包含在HMAC中一样。例如,用户名"Joe“可以作为关联数据包含在Joe的数据的GCM加密中。然后,当GCM模式对数据进行解密时,它不仅会检测到对IV +密文的篡改,而且用户名也必须仍然是"Joe“--注意这里没有加密"Joe”。

个人IV,每一次随机,对于每一段数据,是一个非常好的主意。您还可以考虑在替换主键之前使用了多长时间。它的寿命应该是有限的,当它被“旋转”、“滚动”或“重键”(所有的意思都是相同的东西--你正在替换它)时,你需要一些方法来重新加密所有的东西。您希望定期更改主密钥(可能是3个月,可能是一年)到1)限制在主密钥被泄露时公开的数据量(例如,只有3个月的值)和2)限制用于加密的单个密钥的数据量(因为在技术上,您可以用单个密钥加密多少数据,但在数学上仍然是“安全的”)。

票数 1
EN

Stack Overflow用户

发布于 2016-07-17 00:41:54

如果你能避免密码的话,你就不应该储存密码。

我不清楚第一步中的密码是什么。如果一个新用户直到第二步才出现,这是谁的密码?

无论如何,对于您的用户来说,一个更好的计划是使用/保存派生材料。例如,在新用户注册时,请执行以下操作

代码语言:javascript
复制
byte[] exportBytes;
byte[] exportSalt;
int exportPasswordSettingsVersion = YourSystemConfiguration.NewPasswordSettingsVersion;

using (Rfc2898DeriveBytes registerer = new Rfc2898DeriveBytes(
    newUserPassword,
    YourSystemConfiguration.GetSaltSize(exportPasswordSettingsVersion),
    YourSystemConfiguration.GetIterationCount(exportPasswordSettingsVersion)))
{
    exportSalt = registerer.Salt;

    exportBytes = registerer.GetBytes(
        YourSystemConfiguration.GetDerivedKeySize(exportPasswordSettingsVersion));
}

然后导出盐字节(为您随机生成的)、派生的密码字节、sett作为用户配置文件的一部分。当用户登录时,您将这些值加载回并检查它们是否匹配:

代码语言:javascript
复制
using (Rfc2898DeriveBytes verifier = new Rfc2898DeriveBytes(
    inputPassword,
    loadedProfile.Salt,
    YourSystemConfiguration.GetIterationCount(loadedProfile.PasswordSettingsVersion)))
{
    byte[] verifyBytes = registerer.GetBytes(loadedProfile.PasswordVerify.Length);

    if (!ConstantTimeEquals(verifyBytes, loadedProfile.PasswordVerify))
    {
        return false;
    }

    if (loadedProfile.PasswordSettingsVersion < YourSystemConfiguration.GetIterationCount(exportPasswordSettingsVersion))
    {
        // Re-derive their password and save it with your newer (stronger, presumably) cryptographic settings.
    }

    return true;
}

这一计划:

  • 使用key 2898的PBKDF2算法从密码派生密钥,存储这个派生值比存储密码要好,因为如果凭据数据库被破坏,它不会泄露密码。
  • 为每个新用户使用新的随机盐。(也可以在更改密码或升级登录时重新生成)
  • 保存(和加载)有关设置密码时使用的设置的信息,以便以后可以更改默认设置。
  • 不使用DPAPI (DPAPI不错,但它是Windows专用的,如果您使用的是.NET核心,那么您可能需要跨平台的解决方案)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38416512

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档