SHA3​​-512 在 Java 中生成密钥

SHA3-512 to Generate Keys in Java

是否可以使用 SHA3-512(Java9 中可用的 keccak 子集)在 Java 中生成密钥?

我搜索了很多噪音和文档,试图弄清楚这一点。 目前看来 SHA3-512 可用作 MessageDigest 的哈希,但不能用于生成密钥。我下面的代码试图以可预测的方式生成密钥(用于 BIP32 之类的钱包目的,但不限于区块链使用的货币)

https://github.com/devssh/BlockchainFullNode/blob/d2978e598b4cdecdf4b3337713b2c3e839a6b181/src/main/java/app/model/Keyz.java#L111-L128

    public static String GenerateSeed() throws Exception {
        SecureRandom random = new SecureRandom();
        byte[] seed = random.generateSeed(512);
        return Base64.getEncoder().encodeToString(seed);
    }

    public static Keyz GenerateKey(String seedString) {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        KeyPairGenerator keyGen1 = KeyPairGenerator.getInstance("ECDSA");
        ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256k1");
        SecureRandom random1 = SecureRandom.getInstance("SHA1PRNG");
        random1.setSeed(Base64.getDecoder().decode(seedString));
        keyGen1.initialize(ecSpec, random1);
        KeyPair keyPair1 = keyGen1.generateKeyPair();
        PublicKey pub1 = keyPair1.getPublic();
        PrivateKey priv1 = keyPair1.getPrivate();
        //Keyz is a simple model that stores the 3 fields below and overrides equals and hashcode on those fields
        return new Keyz("random", pub1, priv1);
    }

如您所见,它使用 SHA1PRNG 可预测地确定性地生成密钥对(我对这方面的安全问题没有意见)以便可以确定性地重新创建密钥。

这是一个 JUnit 测试,用于确保密钥是确定性的(适用于 SHA1PRNG,需要在 SHA3PRNG 中工作)。理想情况下,需要的是 GenerateSeed 中的 SHA3-512 TRNG 和 GenerateKey 中的 SHA3PRNG。由于密钥生成器需要一个 SecureRandom,如果 java.Security.SecureRandom 仍然像 SHA1PRNG 这样不安全,我会感到惊讶。

https://github.com/devssh/BlockchainFullNode/blob/d2978e598b4cdecdf4b3337713b2c3e839a6b181/test/main/java/app/model/KeyzTest.java#L16-L22

    @Test
    public void shouldReturnDeterministicKeys() throws Exception {
        String seedString = GenerateSeed();
        Keyz random1 = GenerateKey(seedString);
        Keyz random2 = GenerateKey(seedString);
        //This assertion works as we override equals and hashcode
        assertEquals(random1, random2);
    }

有人能告诉我他们是否想出了办法让这个工作吗

您要找的东西似乎没有开箱即用:

请注意 SHA1SHA1PRNG 并不等价。前者是哈希算法,后者是伪随机生成算法(当然,它使用 SHA1 来更新其内部状态。)这种差异的一个微不足道的结果是,SHA1 输出一个固定的位的大小,其中 SHA1PRNG 输出任意多的位。

由于这种差异,SHA3-512 不能直接用作 PRNG,尽管它在 Java 中可用。你需要做的是,使用 SHA3-512 实现一个 PRNG 算法(这部分真的很棘手,因为生成伪随机流非常困难。)并通过你的自定义 Security Provider 注册它(就像 Bouncy Castle 那样)有一些名字 MySHA3PRNG。之后,您可以像为 SHA1PRNG 一样获取名称为 MySHA3PRNG 的实例。其余保持原样。

这个棘手部分的一个主要问题可能如下:引用自 here,

The paper "Sponge-based pseudo-random number generators" talks about just that and it also describes a clean and efficient way to construct a re-seedable PRNG with a (Keccak) sponge function. What you'll get is a PRNG based on a cryptographic hash function… with the usual security implications.

For example: the paper explicitly states that you should reseed regularly with sufficient entropy to prevent an attacker from going backwards on the period of the PRNG (which is probably what you've been hearing about).

然而,你需要的是一个不需要重新播种的PRNG算法。我希望你有足够的理论背景来证明你的自定义 PRNG 算法是安全的。

祝你好运!