In my android application I would like to implement the Diffie-Hellman protocol in order to generate a common secret between two users.
What I do is the following: when the first user sends a friendship request to the second one, the app generates a key pair, storing the public one in a remote database and the private in a local database.
Here is the code for this first part:
generateKeys();
localDB.insertPrivateKey(userId, entityId, privateKey);
remoteDB.insertFirstPublicKey(userId, entityId, publicKey);
The generateKeys method is the following:
private void generateKeys() {
try {
final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH");
keyPairGenerator.initialize(1024);
final KeyPair keyPair = keyPairGenerator.generateKeyPair();
privateKey = keyPair.getPrivate();
publicKey = keyPair.getPublic();
} catch (Exception e) {
e.printStackTrace();
}
}
When the second user accepts the request, another key pair is generated, once again storing the private key in the local db and the public in the remote. Then it fetches the public key of the first user from the remote db, converts it back to PublicKey and generate the common secret.
Here is the code for the second part:
generateKeys();
localDB.insertPrivateKey(userId, entityId, privateKey);
remoteDB.insertSecondPublicKey(entityId, userId, publicKey);
String stringFirstPubKey = remoteDB.fetchFirstKey(entityId, userId);
PublicKey firstPubKey = stringToPublicKey(stringFirstPubKey);
byte[] commonSecret = generateCommonSecret(firstPubKey);
The stringToPublicKey is the following:
private PublicKey stringToPublicKey(String stringPubK) throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] pubK = Base64.decodeBase64(stringPubK);
KeyFactory keyFactory = KeyFactory.getInstance("DH");
EncodedKeySpec keySpec = new X509EncodedKeySpec(pubK);
return keyFactory.generatePublic(keySpec);
}
And the generataCommonSecret:
private byte[] generateCommonSecret(PublicKey firstPubKey) {
try {
final KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");
keyAgreement.init(privateKey);
keyAgreement.doPhase(firstPubKey, true);
byte[] secretKey = adjustKeyLenght(keyAgreement.generateSecret());
return secretKey;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Also when storing the keys I convert them into String with the following:
String stringPubK = Base64.encodeBase64String(publicKey.getEncoded());
When executing the following line in generateCommonSecret
keyAgreement.doPhase(firstPubKey, true);
I get this exception
java.security.InvalidKeyException: DHPublicKey not for this KeyAgreement!
at com.android.org.bouncycastle.jcajce.provider.asymmetric.dh.KeyAgreementSpi.engineDoPhase(KeyAgreementSpi.java:101)
at javax.crypto.KeyAgreement.doPhase(KeyAgreement.java:383)
Can someone help me finding the problem? What is weird is that if I try to do this in a single java class, without storing and retrieving keys, it works fine.