How can I create a key pair in Java, based on a password?

Viewed 7113

I want to allow Alice to create a public/private key pair so that Bob can send her confidential messages. However, I want Alice to be able to check her messages from anywhere, and it would be a pain for her to have to carry around a memory stick containing her private key. Is there some way that Alice can create a public/private key pair based on a password which she remembers? In this way she could simply generate the private key (and public key) whenever she wanted to.

The short version of this question is: Where can I find the Java equivalent of cryptico.js.

Also, here's the same question on Stack Overflow, but for javascript.

Edit: Here's my first attempt at a solution:

    SecureRandom saltRand = new SecureRandom(new byte[] { 1, 2, 3, 4 });
    byte[] salt = new byte[16];
    saltRand.nextBytes(salt);

    int keyLength = 3248;
    SecretKeyFactory factory = SecretKeyFactory
            .getInstance("PBKDF2WithHmacSHA1");
    KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 8192, keyLength);
    SecretKey key = factory.generateSecret(spec);

    SecureRandom keyGenRand = SecureRandom.getInstance("SHA1PRNG");
    keyGenRand.setSeed(key.getEncoded());

    KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
    gen.initialize(keyLength, keyGenRand);
    java.security.KeyPair p = gen.generateKeyPair();
6 Answers

Disclaimer: this naive approach is insecure, so it is NOT recommended for production systems. However for testing - suits very well.

Code

private KeyPair getKeyPair(String password) throws GeneralSecurityException {
    /*// https://stackoverflow.com/a/992413/2078908
    byte[] salt = new byte[]{1, 2, 3};
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    KeySpec seedSpec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
    byte[] seed = factory.generateSecret(seedSpec).getEncoded();*/
    byte[] seed = password.getBytes(UTF_8);

    SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
    rnd.setSeed(seed);

    RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4);
    KeyPairGenerator pairGenerator = KeyPairGenerator.getInstance("RSA");
    pairGenerator.initialize(spec, rnd);

    return pairGenerator.generateKeyPair();
}

Test

@Test
public void testPrivateKeys() throws Exception {
    System.out.println("private key 1: " + md5(getKeyPair("pwd-1").getPrivate().getEncoded()));
    System.out.println("private key 1: " + md5(getKeyPair("pwd-1").getPrivate().getEncoded()));
    System.out.println("private key 2: " + md5(getKeyPair("pwd-2").getPrivate().getEncoded()));
    System.out.println("private key 2: " + md5(getKeyPair("pwd-2").getPrivate().getEncoded()));
}


private String md5(byte[] data) throws GeneralSecurityException {
    return javax.xml.bind.DatatypeConverter.printHexBinary(
        MessageDigest.getInstance("md5").digest(data));
}

Test output

private key 1: 5A2009E6DC8B25321C6304F62BE45398
private key 1: 5A2009E6DC8B25321C6304F62BE45398
private key 2: 2ACB65656AF9AF7036F40ACF0CFE7CA3
private key 2: 2ACB65656AF9AF7036F40ACF0CFE7CA3
Related