Search code examples
javapublic-keyasn.1diffie-hellmanpublic-key-exchange

How to convert hex public key to ASN.1 SubjectPublicKeyInfo structure for Diffie-Hellman key exchange?


I am trying to implement Diffie-Hellman key exchange to generate the symmetric key for encryption/decryption using JAVA cryptography packages. This requires a public key exchange between the two parties.

The public key shared by the client is 1024 bit hexadecimal string, which should be used to calculate the shared secret key. How to convert this string into an encoded key format (ASN.1 SubjectPublicKeyInfo structure) to create a PublicKey object.

Considering a sample public key string. Parameters p and g are fed into inputDHParameterSpec object.

Sample implementation: AutoGen keypair:

    KeyPairGenerator clientKpairGen = keyPairGenerator.getInstance("DiffieHellman");
    clientKpairGen.initialize(inputDHParameterSpec);
    KeyPair clientKpair = clientKpairGen.generateKeyPair();
    byte[] clientPubKeyEnc = clientKpair.getPublic().getEncoded();

    X509EncodedKeySpec testPubKeySpec = new X509EncodedKeySpec(clientPubKeyEnc);
    KeyFactory keyFactory = KeyFactory.getInstance("DiffieHellman");
    PublicKey clientPubKey = keyFactory.generatePublic(testPubKeySpec);

Hex PublicKey - failing:

    String testPublicKey = "85f04dd00345642ad12b65bd1a7c38728bff0b8e281ddb6ac4f2739e82a02145daabf23d173c933913b1f844059710e9125591569de427eae1d269accbfa3305069deb7622d1da3ad9820d11bd24fdcce5381d2df99bda314394738dfcbe210eae247b1303e79297ff746cd919e189f6a5776e6ecc24c8900de0f38f159072de";
    X509EncodedKeySpec testPubKeySpec = new X509EncodedKeySpec(hexStringToByteArray(testPublicKey));
    KeyFactory keyFactory = KeyFactory.getInstance("DiffieHellman");
    PublicKey clientPubKey = keyFactory.generatePublic(testPubKeySpec);//Failing here

byte[] created in first code block has public key in ASN.1 encoded format, but hexStringToByteArray(testPublicKey) merely converts the hex to byte[]. Getting the below error on the marked line, due to this.

Exception in thread "main" java.security.spec.InvalidKeySpecException: Inappropriate key specification
    at com.sun.crypto.provider.DHKeyFactory.engineGeneratePublic(DHKeyFactory.java:85)
    at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
    at MWK_DHGen.main(MWK_DHGen.java:87)
Caused by: java.security.InvalidKeyException: Error parsing key encoding
    at com.sun.crypto.provider.DHPublicKey.<init>(DHPublicKey.java:178)
    at com.sun.crypto.provider.DHKeyFactory.engineGeneratePublic(DHKeyFactory.java:78)
    ... 2 more

Can someone help on how to convert this hex to the requried format here? A different implementation that would use this hex string to arrive at the secret key is also encouraged.


Solution

  • If you already have the domain parameters (p, g) and just the integer value of the public key then a DHPublicKeySpec rather than an X509EncodedKeySpec is the way to go:

    String testPublicKey = "85f04dd00345642ad12b65bd1a7c38728bff0b8e281ddb6ac4f2739e82a02145daabf23d173c933913b1f844059710e9125591569de427eae1d269accbfa3305069deb7622d1da3ad9820d11bd24fdcce5381d2df99bda314394738dfcbe210eae247b1303e79297ff746cd919e189f6a5776e6ecc24c8900de0f38f159072de";
    BigInteger publicKeyInteger = new BigInteger(testPublicKey, 16);
    KeyFactory keyFactory = KeyFactory.getInstance("DiffieHellman");
    PublicKey clientPubKey = keyFactory.generatePublic(new DHPublicKeySpec(publicKeyInteger, g, p));