DPAPI.Protect 的熵参数的目的是什么?

信息安全 加密 视窗
2021-08-20 23:38:40

因此,在 Windows 中,当您调用数据保护 API 时,您可以将一些字节指定为“熵”。

对我来说,这听起来像盐。在 PBKDF2 中,盐是可以的,实际上需要以纯文本形式存储。它不会损害算法的安全性,它是算法实现的一部分。

您传递给 DPAPI 的“熵”是否具有相同的功能?我读过它所做的只是使您的密钥在一定程度上是特定于应用程序的,因为如果登录的用户读出了使用 DPAPI 存储的密钥,他们就无法在没有熵的情况下解密您的加密数据。当然,熵必须以纯文本形式存储(否则最终会出现无限回归)。

那么,将熵存储为纯文本(也许是硬编码)可以吗?

感谢 jimbob 博士:

熵参数“是由将被添加到密钥导出应用程序提供可选的熵[...]默认情况下,DPAPI已经使用了不同的熵每个斑,所以在实践中增加额外的熵也没有[大胆添加]提高加密安全性。根据文档,其目的是允许依赖 DPAPI 的应用程序降低其机密被另一个应用程序窃取的风险。在我们的测试中,我们发现只有 GTalk 使用了条件熵,其值存储在一个注册表项,因此对攻击者来说不是真正的障碍。”

2个回答

MSDN 文档很好地解释了它

使用登录密码的一个小缺点是,在同一用户下运行的所有应用程序都可以访问他们知道的任何受保护数据。当然,由于应用程序必须存储自己的受保护数据,因此其他应用程序访问数据可能有些困难,但肯定不是不可能的。

基本上,如果有人发现了一些受保护的数据(例如,存储在注册表中的加密连接字符串),在用户上下文中运行的简单应用程序可以轻松地使用 DPAPI 来解密受保护的数据。

为了解决这个问题,DPAPI 允许应用程序在保护数据时使用额外的机密。然后需要这个额外的秘密来解除对数据的保护。

从技术上讲,这个“秘密”应该被称为二次熵。它是次要的,因为虽然它不会加强用于加密数据的密钥,但它确实增加了在同一用户下运行的一个应用程序破坏另一个应用程序的加密密钥的难度。应用程序应该小心他们如何使用和存储这个熵。如果它只是简单地保存到未受保护的文件中,那么攻击者可以访问熵并使用它来取消保护应用程序的数据。

显然,将熵以明文形式存储在与受保护数据相同的位置完全违背了目的。

该参数进一步解释如下:

内部保护功能

pOptionalEntropy
指向DATA_BLOB包含用于保护数据的附加熵的指针cbData成员持有的长度pbData成员的字节字符串包含可选的熵。DATA_BLOB在保护调用中使用,还必须在解除保护调用中使用。这是前面提到的应用程序特定的“秘密”。
此参数是可选的,可以是 NULL

内部解除保护功能

pOptionalEntropy
指向DATA_BLOB包含在数据受到保护时使用的附加熵的指针。成员保存包含可选熵的成员字节字符串cbData长度。pbData这是前面提到的应用程序特定的“秘密”。
此参数是可选的,可以是 NULL但是,如果在保护调用中使用了可选熵,则必须在取消保护调用中使用相同的熵。

因此,您可以通过使用熵参数来增加对其他应用程序(甚至用户)的保护,并使发现熵值变得有点困难。

那么,将熵存储为纯文本(也许是硬编码)可以吗?

明文可能没问题,只要该位置难以找到或访问。将其放在与受保护数据相同的位置有点毫无意义。

对于已经拥有用户访问权限和足够时间和资源的攻击,您将无法获得“完美的安全性”。但是你可以做一些小事情来减慢它们的速度:

  • 如果您在应用程序中对熵值进行硬编码,则可以在二进制文件中找到它。但这更难做到。
  • 如果您在使用熵值之前对其应用简单的转换(例如 XOR),则需要对您的应用程序进行反编译或以其他方式破坏源代码,以便攻击者知道该怎么做。
  • 您可以远程存储熵值。这意味着攻击者需要知道在哪里可以找到它。并且需要适当的其他凭据才能访问它。(当然,应用程序还需要可以访问其他凭据,这就是为什么在这种情况下“完美的安全性”是不可能的。)

从浏览:http: //msdn.microsoft.com/en-us/library/ms229741.aspx

熵提供 16 字节(128 位)初始化向量,而不是加密盐。

您通常不需要对 IV 保密[1],您只需要注意不要重复使用相同的 IV(如果它是随机生成的,则不会发生这种情况,因为有 2 128个可能的值)。

初始化向量的目的是在加密之前初始随机化您的消息(通常只是第一个块)。

比较不需要 IV 的电子密码本 (ECB)和需要 IV 的密码块链接

假设您有一些加密功能encrypted_block = Encrypt(block, key),它将采用一个固定大小的数据块(比如 128 位)、一个秘密加密密钥并返回一个加密的数据块,可以使用block = Decrypt(encrypted_block, key). 因此,如果您使用 128 位块大小加密 10 kB 文件,那么您有 640 个块要加密。如果原始的两个块是相同的(比如说它是一个熵很小的图像),那么最后的加密块最终将是相同的,并且通常可以辨别出模式。因此,ECB 基本上只是将文件拆分为块并将加密功能单独应用于每个块(不依赖于先前块的输出)。

现在让我们看看像 CBC 这样使用初始化向量 (IV) 的方案。第一个块由 加密encrypted_block_0 = Encrypt(block_0 ^ IV, key),其中^是 XOR(按位异或运算符)。下一个块被加密encrypted_block_1 = Encrypt(block_1 ^ encrypted_block_0, key); 也就是说,您在输入加密函数之前使用前一个块的加密结果来“随机化”当前块。现在,如果他们没有对第一个块使用初始化向量,则可以通过观察前几个块来推断事情。例如,如果您有两个具有相同初始化向量的加密文件,并且看到前 10 个块是相同的,您将了解到明文文件的前 10 个块是相同的,并且您会获得额外的信息。并不是说仅仅知道明文中的 IV 对你一点帮助都没有,因为它在一个复杂的非线性Encrypt函数中,你不知道秘密就无法反转key

编辑:实际上,我认为在 DPAPI 中将 16 个字节用作初始化向量是错误的;这是微软秘密 DPAPI 的逆向工程:http: //cdn.ly.tl/publications/Recovering-Windows-Secrets-and-EFS-Certi%EF%AC%81cates-Of%EF%AC%82ine.pdf