javasecuritybouncycastleblockchainsha-3

SHA3-512 to Generate Keys in Java


Is it possible to use SHA3-512(a subset of keccak available in Java9) to generate keys in Java?

I have searched through a lot of noise and documentation to try to figure this out. Currently it seems SHA3-512 is available as a hash for MessageDigest but not for generating keys. My code below tries to generate keys predictably(for wallet purposes like BIP32 but beyond currency to blockchain uses)

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);
    }

As you can see, it uses SHA1PRNG to predictably generate keypair deterministically(I am fine with the security concerns on this) so that the keys can be recreated deterministically.

Here is a JUnit test to make sure the keys are deterministic(works for SHA1PRNG, needs to work in SHA3PRNG). Ideally what is needed is a SHA3-512 TRNG in the GenerateSeed and a SHA3PRNG in the GenerateKey. Since the keygenerator needs a SecureRandom I would be surprised if java.Security.SecureRandom is still on something as insecure as 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);
    }

Can someone please let me know if they figured a way to get this to work


Solution

  • It seems what you are looking for is not available out of the box:

    Note that SHA1 and SHA1PRNG are not equivalent. While the former is a hash algorithm, the latter is a pseudo random generation algorithm (that uses SHA1 to update its internal state, of course.) One trivial result of this difference is, SHA1 outputs a fixed size of bits, where SHA1PRNG outputs as many bits as you like.

    Because of this difference, SHA3-512 cannot be used as PRNG directly, although it is available in Java. What you need to do is, implement a PRNG algorithm using SHA3-512 (this part is really tricky, since generating a pseudo random stream is quite difficult.) and register it through your custom Security Provider (like Bouncy Castle does) with some name MySHA3PRNG. After that, you can get an instance of it with name MySHA3PRNG as you do for SHA1PRNG. The rest remains as-is.

    A major problem with this tricky part might be as follows: Quoting from 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).

    However, what you need is a PRNG algorithm that does not need to be re-seeded. I hope you have sufficient theoretical background to prove that your custom PRNG algorithm is secure.

    Good luck!