使用Java Keytool实用程序构建密钥库时,如何保护密钥?我已经阅读了文档,并且我意识到每个私钥都有一个密钥密码,然后商店有一个商店密码。
但是用什么机制来保护数据呢?它是加密密码吗?如果是这样,算法是什么?我特别关注keytool在构建JKS文件时如何进行保护。
答案 0 :(得分:6)
Sun的默认JKS密钥库使用专有算法,主要用于解决对标准算法的导出限制。该算法在这个类中实现,
sun.security.provider.KeyProtector
是算法的描述,
这是Sun专有的可导出算法的实现,旨在用于保护(或恢复明文版本)敏感密钥。该算法不是用作通用密码。这就是算法如何用于密钥保护:p - 用户密码s - 随机盐X - xor密钥P - 要保护密钥Y - 受保护密钥R - 存储在密钥库中的内容步骤1:获取用户密码,向其附加一个随机盐(固定大小),并对其进行散列:d1 =摘要(p,s)将d1存储在X中。步骤2:获取用户密码,附加上一步的摘要结果,并对其进行散列: dn =消化(p,dn-1)。将dn存储在X中(将其附加到先前存储的摘要中)。重复此步骤,直到X的长度与私钥P的长度匹配。步骤3:XOR X和P,并将结果存储在Y:Y = X XOR P.步骤4:存储s,Y和摘要(p ,P)在结果缓冲器R中:R = s + Y + digest(p,P),其中“+”表示连接。 (注意:摘要(p,P)存储在结果缓冲区中,这样当密钥恢复时,我们可以检查恢复的密钥是否确实与原始密钥匹配。)R存储在密钥库中。受保护的密钥恢复如下:步骤1和步骤2与上述相同,除了盐不是随机生成的,而是取自步骤4的结果R(第一个长度(s)字节)。步骤3(XOR运算)产生明文密钥。然后将密码与恢复的密钥连接起来,并与R的最后长度(摘要(p,P))字节进行比较。如果它们匹配,则恢复的密钥确实与原始密钥相同。
答案 1 :(得分:2)
使用的算法取决于您使用的密钥库(例如,它可能是SmartCard)。
Sun随JDK一起提供的默认密钥库使用three encryption options创建一个软令牌(在磁盘文件上):
默认值:“jks”,专有密钥库类型(格式)。不确定算法。
“jceks”,一种替代的专有格式,使用3-DES
“pkcs12”,一种标准格式(OpenSSL可以读取它),有多个选项,但通常是3-DES用于私钥,RC2-40用于证书。
在所有这三种情况下,您都会对私有数据进行加密(对称,使用单个密码),以及受密码摘要保护的整个密钥存储区的完整性(使用密钥库密码)。
答案 2 :(得分:1)
从版本 9 开始的 Java 版本不再使用专有的 JKS 密钥存储类型。相反,它们默认使用 PKCS#12 密钥存储类型,也称为 PFX 文件。
这些密钥库由单独的 PBKDF 密钥派生机制保护,用于密钥库完整性、私钥和证书。
默认情况下,使用 HMAC-SHA-1 保护整个密钥库的完整性,尽管使用了可以生成冲突的哈希算法,但它仍然是安全的。同样,这可能不是您想告诉审计员您仍在使用的算法。
密钥本身使用 3 密钥三重 DES 进行保护。这里出现了同样的问题,因为 3 键三重 DES 在这些场景中仍然提供大约 112 位的安全性。现在您当然更愿意使用 AES-256,尤其是在保护私钥方面。
证书使用 40 位 RC2 进行“保护”。基本上我会称之为混淆而不是实际的加密。幸运的是,整个密钥库的完整性无论如何都受到保护,并且证书通常被认为是“公共的”。但是,如果您(仍然)认为切换公钥和私钥是个好主意,那么您就会(另一个)大惊喜。
PBE 意味着用于提供(完整性和)机密性的密钥是根据密码计算的。一旦攻击者掌握了密钥存储文件,就可以使用“离线”攻击来攻击这些密码。
基于密码的加密安全性主要取决于所使用的密码或密码短语的安全性。如果它只是 6 个字符(keytool
似乎接受的最小值),那么通常不提供安全性。如果每个字符的熵为 6 位,则整个安全性为 6 x 6 = 36 位。
然而,PBKDF 确实指定了密码和盐在用作密钥之前被散列的迭代次数。这增加了一点安全性。但是,keytool
仅使用最少 50,000 次迭代,而目前建议至少使用 100 万次迭代。 50,000 次迭代为总数增加了 15/16 位的安全性。这很好,但如果使用完全随机的 6 个字符密码,您仍然会受到 50 位安全性的限制。
更糟糕的是,PKCS#12 似乎使用了更多的迭代来计算 HMAC、3DES 和 RC2 密钥的各种密钥。这意味着普通用户实际上必须为每个密码执行更多的工作来计算密钥,而攻击者只需要计算 RC2 40 位密钥来验证正确的猜测。除此之外,Java 的 PBKDF 实现肯定不是最快的。最后,您不能真正依靠 PBKDF 为所使用的密码增加很多安全性。幸运的是,密钥库只加载一次;之后存储在内存中。
最后,PFX 密钥存储格式已经过时了,Java 的 keytool
和 PKCS12KeyStore
实现也是如此。保持合理安全的唯一方法是使用密码生成器和密码存储(例如 KeyPass`)来生成一个非常强的密码。它推荐使用字母数字字母表(大写、小写和数字)的 12 个随机字符。这提供了大约 12 x ~6 + ~16 = ~88 位的安全性。
那么让我们验证一下:
keytool -genkeypair -alias test -keyalg RSA -keysize 4096 -sigalg SHA256withRSA -keystore test.pfx
然后
openssl pkcs12 -info -in test.pfx
结果:
MAC: sha1, Iteration 100000
MAC length: 20, salt length: 20
PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 50000
Bag Attributes
friendlyName: test
localKeyID: 54 69 6D 65 20 31 36 31 34 39 34 35 39 34 35 38 32 33
Key Attributes: <No Attributes>
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----BEGIN ENCRYPTED PRIVATE KEY-----
<PKCS8ShroudedKeyBag in base 64>
-----END ENCRYPTED PRIVATE KEY-----
PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 50000
Certificate bag
Bag Attributes
friendlyName: test
localKeyID: 54 69 6D 65 20 31 36 31 34 39 34 35 39 34 35 38 32 33
subject=C = Unknown, ST = Unknown, L = Unknown, O = Unknown, OU = Unknown, CN = Test
issuer=C = Unknown, ST = Unknown, L = Unknown, O = Unknown, OU = Unknown, CN = Test
-----BEGIN CERTIFICATE-----
<base 64 encoded self-signed certificate>
-----END CERTIFICATE-----
您想更好地保护您的密钥,然后请联系安全顾问。正如我们在此处显示的那样,全世界都使用 keytool
的事实并不一定使其安全。这个问题(甚至)比这里的答案还多。