Java密钥库-详细信息

Øriginally posted on my blog

Java KeyStore用于以加密和完整性保护的方式存储密钥材料和关联的证书。 像Java的所有事物一样,此机制是可插入的,因此存在多种不同的选择。 那里有很多文章描述了不同的类型以及如何初始化它们,加载密钥和证书等。但是,缺少有关这些密钥库如何存储和保护密钥材料的详细技术信息。 这篇文章试图将最重要的KeyStore的那些重要细节集中在一处。

每个密钥存储区都有一个用于保护整个存储区的总体密码,并且可以选择为每个秘密或私有密钥条目(如果您的后端支持)都具有按条目输入的密码。

Java密钥库(JKS)

原始的Sun JKS(Java密钥库)格式是专有的二进制格式文件,只能存储非对称私钥和关联的X.509证书。

Individual private key entries are protected with a simple home-spun stream cipher—basically the password is salted (160-bits) and hashed with SHA-1 in a trivial chained construction until it has generated enough output bytes to XOR into the private key. It then stores a simple authenticator tag consisting of SHA-1(password + private key bytes) — that's the unencrypted private key bytes. In other words, this is an Encrypt-and-MAC scheme with homespun constructions both based on simple prefix-keyed SHA-1. (This scheme has OID 1.3.6.1.4.1.42.2.17.1.1).

整个档案库再次受到本地旋转前缀键哈希构造的完整性保护,该构造包括原始密钥库密码的UTF-16字节的SHA1哈希,后跟短语“ Mighty Aphrodite”的UTF-8字节(I (不是在开玩笑),后跟编码的密钥存储区条目的字节。

如果此描述的每个部分都没有让您在屏幕上同时发出恐怖和迷惑的尖叫,那么您可能还没有完全理解这是多么的糟糕。 即使仅用于存储证书,也不要使用它-防篡改功能是要比加密还差的东西。

JCE密钥库(JCEKS)

Sun随后通过Java密码扩展(JCE)更新了JVM的密码功能。 通过这种方式,他们还引入了一种新的专有密钥存储格式:JCEKS。

JCEKS uses "PBEWithMD5AndTripleDES" to encrypt individual key entries, with a 64-bit random salt and 200,000 iterations of PBKDF1 to derive the key. TripleDES is used with 3 keys ("encrypt-decrypt-encrypt") in CBC mode. There is no separate integrity protection of individual keys, which is fine if the archive as a whole is integrity protected, but it means that access control is effectively at the level of the whole keystore. This is not terrible from a crypto point of view, but can definitely be improved—neither MD5 nor TripleDES are considered secure any more, and it's been a long time since anyone recommended them for new projects. However, it would also not be a trivial effort to break it.

JCEKS使用与JKS相同的荒谬“ Mighty Aphrodite”前缀键哈希来保护整个档案。 最好假定这些密钥存储库中的任何一个都没有严格的完整性保护。

PKCS#12

除了这些专有密钥库之外,Java还支持“标准” PKCS#12格式密钥库。 之所以在“标准”周围加上引号,是因为它确实是一种标准格式,但是它却是一种非常灵活的格式,因此在实践中,不同软件所支持的“密钥袋”格式和加密算法之间存在显着差异。 。 例如,当您从Java将对称SecretKey对象存储在PKCS#12密钥存储区中时,OpenSSL无法读取它们,因为它们使用的是袋类型(“ secretBag”-OID 1.2.840.113549.1.12.10.1.5) 了解。

Java使用PKCS#12标准格式的版本3。 它以前述的“ secretBag”格式存储秘密密钥,并以“ PKCS#8覆盖的密钥袋”格式(OID 1.2.840.113549.1.12.10.1.2)存储非对称私钥。 这仅指示磁盘上字节的格式。 在这两种情况下,实际的密钥材料都是使用某种形式的基于密码的加密(PBE)模式加密的。 默认情况下,这是“ PBEWithSHA1AndDESede” —“ DESede”是在加密-解密-加密模式下TripleDES的另一个名称,因此与JCEKS所使用的模式非常相似,不同之处在于它使用的形式略好(但仍不建议使用)哈希 SHA-1。 默认情况下,它使用160位盐和50,000次迭代。

乙ut, there is an important improvement in the PKCS#12 implementation—you get to choose the encryption algorithm! By passing in a PasswordProtection parameter (from Java 8 onwards) when saving a key you can specify a particular (password-based) cipher to use. I haven't checked exactly what ciphers are allowed, but you can at least specify a stronger PBE mode, such as "PBEWithHmacSHA512AndAES_256", which will derive a 256-bit AES key using salted PBKDF2 and then encrypt the stored key using AES/CBC/PKCS5Padding with that key. You can also increase the number of iterations of PBKDF2 used. For example:

import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.KeyStore.PasswordProtection;
import java.security.KeyStore.SecretKeyEntry;
import java.security.SecureRandom;

import javax.crypto.SecretKey;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class scratch {
    public static void main(String... args) throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(null, null); // Initialize a blank keystore

        SecretKey key = new SecretKeySpec(new byte[32], "AES");

        char[] password = "changeit".toCharArray();
        byte[] salt = new byte[20];
        new SecureRandom().nextBytes(salt);
        keyStore.setEntry("test", new SecretKeyEntry(key),
            new PasswordProtection(password,
                "PBEWithHmacSHA512AndAES_128",
                new PBEParameterSpec(salt, 100_000)));

        keyStore.store(new FileOutputStream("/tmp/keystore.p12"), password);
    }
}

请注意,尽管在上述PBE模式中包括了“ HmacSHA512”,但这仅适用于从密码派生的密钥。 在单个条目级别没有完整性保护。

还值得注意的是,密钥库和单个密钥密码应该一样。 我认为这不是Java中PKCS#12的基本限制,但是可以肯定,诸如命令行“ keytool”实用程序之类的标准Java工具将无法使用用于商店的密码与单个密钥来处理具有不同密码的PKCS#12密钥库。 如果您不需要使用这些工具,则可以为每个密钥使用不同的密码。

与之前的条目相比,PKCS#12密钥存储格式实际上也确实对证书进行了加密。 它使用硬编码算法“ PBEWithSHA1AndRC2_40”来执行此操作。 这将使用50,000轮盐腌的PBKDF1得出40位 key for RC2 encryption. RC2 is an old stream cipher that I certainly wouldn't recommend. The 40位 key is 远太小,无法提供任何严重的安全性。 这让我想知道为什么要花50,000轮PBKDF1来保护密码,同时生成本身容易受到暴力破解的密钥。 暴力破解派生密钥的速度实际上可能比原始密码要快。 我只能假设它与某些参与其中的决策保持了兼容性,而参与决策的各方深深地感到遗憾。

整个PKCS#12密钥存储的完整性受“ HmacPBESHA1”保护。 这是HMAC-SHA1,使用从商店密码派生的密钥,该密钥使用了100,000次盐腌的PBKDF2-HMAC-SHA1迭代。 这些都是硬编码的,因此无法更改。 这是一个不错的选择,尽管能够在此处使用SHA-1以外的其他功能会很不错,因为PKCS#12似乎允许使用其他MAC。 对于HMAC的使用,SHA-1暂时还可以,但是最好删除它。 能够调整迭代次数也很不错。

总体而言,PKCS#12密钥存储要比Sun设计的任何专有选项都要好得多。 如果您使用AES和SHA2指定您自己的PasswordProtection实例,并使用高迭代次数和良好的随机盐,那么即使按现代标准,它实际上也是一个相当可靠的设计。 唯一真正丑陋的部分是受信任证书的40位RC2加密,但是如果您不关心证书的机密性,那么我们可以忽略该细节,而只是对它们进行了模糊处理。 至少,使用HMAC-SHA1至少是一个体面的完整性保护。

PKCS#11

There's not much to say about PKCS#11. It is a standard interface, intended for use with hardware security tokens of various kinds: in particular Hardware Security Modules (HSMs). These range from 50 Euro USB sticks up to network-attached behemoths that cost tens or hundreds of thousands of dollars. The hardware is usually proprietary and closed, so it's hard to say exactly how your keys will be stored. Generally, though, there are significant protections against access to keys from either remote attackers or even those with physical access to the hardware and a lot of time on their hands. This isn't a guarantee of security, as there are lots of ways that keys might accidentally leak from the hardware, as the recent ROCA vulnerability in Infineon hardware demonstrated. Still, a well-tested HSM is probably a pretty secure option for high-value keys.

我不会详细介绍如何设置PKCS#11密钥存储,因为每个供应商的确有所不同。 对于PKCS#12,虽然接口是标准化的,但在该标准内仍有很大的变化空间。 在大多数情况下,您将让HSM在安全的硬件中生成密钥,而从不导出私钥材料(也许用于备份)。

摘要

使用HSM或PKCS#12密钥库,并在存储密钥时指定手动的PasswordProtection参数。 避免使用专有密钥库。

Alternatively, farm out key management to somebody else and use a Key Management System (KMS) like Hashicorp Vault.

from: https://dev.to//neilmadden/java-keystoresthe-gory-details-dnj

你可能感兴趣的:(Java密钥库-详细信息)