web-dev-qa-db-fra.com

Échange de clé Diffie-Hellman en Java

Je travaille sur un projet personnel en Java qui consiste à envoyer des données sensibles sur un canal non sécurisé. J'ai besoin de savoir comment implémenter DHKE (Diffie Hellman Key Exchange) en Java en utilisant ses bibliothèques. Je connais toute la théorie cryptographique à ce sujet, donc inutile d’entrer dans les détails, j’ai juste besoin d’une implémentation très basique pour que deux programmes puissent partager une clé secrète. J'ai eu l'exemple de Java2s.com, mais ce n'est pas complet:

import Java.math.BigInteger;
import Java.security.KeyFactory;
import Java.security.KeyPair;
import Java.security.KeyPairGenerator;
import Java.security.SecureRandom;

import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPublicKeySpec;

public class Main {
  public final static int pValue = 47;

  public final static int gValue = 71;

  public final static int XaValue = 9;

  public final static int XbValue = 14;

  public static void main(String[] args) throws Exception {
    BigInteger p = new BigInteger(Integer.toString(pValue));
    BigInteger g = new BigInteger(Integer.toString(gValue));
    BigInteger Xa = new BigInteger(Integer.toString(XaValue));
    BigInteger Xb = new BigInteger(Integer.toString(XbValue));

    int bitLength = 512; // 512 bits
    SecureRandom rnd = new SecureRandom();
    p = BigInteger.probablePrime(bitLength, rnd);
    g = BigInteger.probablePrime(bitLength, rnd);

    createSpecificKey(p, g);
  }

  public static void createSpecificKey(BigInteger p, BigInteger g) throws Exception {
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("DiffieHellman");

    DHParameterSpec param = new DHParameterSpec(p, g);
    kpg.initialize(param);
    KeyPair kp = kpg.generateKeyPair();

    KeyFactory kfactory = KeyFactory.getInstance("DiffieHellman");

    DHPublicKeySpec kspec = (DHPublicKeySpec) kfactory.getKeySpec(kp.getPublic(),
        DHPublicKeySpec.class);
  }
}

Comment puis-je continuer à partir de cela? Quelqu'un pourrait-il m'aider à compléter le code restant?

9
user2435860

Qu'en est-il les documents officiels Oracle ? Ils affichent un échange de clé DH dans le code.

6
thr0wable

Voici un exemple de travail:

static void main() {

    DH dh = new DH();
    byte[] myPublicKey = dh.generatePublicKey();

    /* Send myPublicKey to other party, and get hisPublicKey in return */

    byte[] sharedKey = dh.computeSharedKey(hisPublicKey)
    /* sharedKey is now 'shared' between both parties */

}

public class DH {

    private static final String TAG = "DH";

    private KeyPair keyPair;
    private KeyAgreement keyAgree;

    public byte[] generatePublicKey() {
        DHParameterSpec dhParamSpec;

        try {
            dhParamSpec = new DHParameterSpec(P, G);
            Log.i(TAG, "P = " + P.toString(16));
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DiffieHellman");
            keyPairGen.initialize(dhParamSpec);
            keyPair = keyPairGen.generateKeyPair();
            Log.i(TAG, "Y = " + ((DHPublicKey) keyPair.getPublic()).getY().toString(16));
            keyAgree = KeyAgreement.getInstance("DiffieHellman");
            keyAgree.init(keyPair.getPrivate());

            BigInteger pubKeyBI = ((DHPublicKey) keyPair.getPublic()).getY();
            byte[] pubKeyBytes = pubKeyBI.toByteArray();
            Log.i(TAG, String.format(TAG, "Y [%d] = %s", pubKeyBytes.length, Utils.toHexString(pubKeyBytes)));
            return pubKeyBytes;
        } catch (Exception e) {
            Log.e(TAG, "generatePubKey(): " + e.getMessage());
            return null;
        }
    }

    public byte[] computeSharedKey(byte[] pubKeyBytes) {
        if (keyAgree == null) {
            Log.e(TAG, "computeSharedKey(): keyAgree IS NULL!!");
            return null;
        }

        try {
            KeyFactory keyFactory = KeyFactory.getInstance("DiffieHellman");
            BigInteger pubKeyBI = new BigInteger(1, pubKeyBytes);
            Log.i(TAG, "Y = " + pubKeyBI.toString(16));
            PublicKey pubKey = keyFactory.generatePublic(new DHPublicKeySpec(pubKeyBI, P, G));
            keyAgree.doPhase(pubKey, true);
            byte[] sharedKeyBytes = keyAgree.generateSecret();
            Log.i(TAG, String.format("SHARED KEY[%d] = %s", sharedKeyBytes.length, Utils.toHexString(sharedKeyBytes)));
            return sharedKeyBytes;
        } catch (Exception e) {
            Log.e(TAG, "computeSharedKey(): " + e.getMessage());
            return null;
        }
    }

    private static final byte P_BYTES[] = {
            (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58,
            ...
            (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7
    };
    private static final BigInteger P = new BigInteger(1, P_BYTES);

    private static final BigInteger G = BigInteger.valueOf(2);
}
1
Wing Poon

Le code suivant utilise Elliptic Curve Diffie-Hellman pour générer et partager une clé 128 bits et AES pour le cryptage.

import Sun.misc.BASE64Decoder;
import Sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import Java.io.IOException;
import Java.security.*;

public class AESSecurityCap {

private PublicKey publickey;
KeyAgreement keyAgreement;
byte[] sharedsecret;

String ALGO = "AES";

AESSecurityCap() {
    makeKeyExchangeParams();
}

private void makeKeyExchangeParams() {
    KeyPairGenerator kpg = null;
    try {
        kpg = KeyPairGenerator.getInstance("EC");
        kpg.initialize(128);
        KeyPair kp = kpg.generateKeyPair();
        publickey = kp.getPublic();
        keyAgreement = KeyAgreement.getInstance("ECDH");
        keyAgreement.init(kp.getPrivate());

    } catch (NoSuchAlgorithmException | InvalidKeyException e) {
        e.printStackTrace();
    }
}

public void setReceiverPublicKey(PublicKey publickey) {
    try {
        keyAgreement.doPhase(publickey, true);
        sharedsecret = keyAgreement.generateSecret();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    }
}

public String encrypt(String msg) {
    try {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encVal = c.doFinal(msg.getBytes());
        return new BASE64Encoder().encode(encVal);
    } catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return msg;
}

public String decrypt(String encryptedData) {
    try {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(decordedValue);
        return new String(decValue);
    } catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException | IOException e) {
        e.printStackTrace();
    }
    return encryptedData;
}

public PublicKey getPublickey() {
    return publickey;
}

protected Key generateKey() {
    return new SecretKeySpec(sharedsecret, ALGO);
}
}

Étendez votre propre classe pour ajouter une fonctionnalité de cryptage AES

public class Node extends AESSecurityCap {

//your class

}

Enfin, moyen d'utiliser le cryptage

public class Main {

public static void main(String[] args) throws IOException {
    Node server = new Node();
    Node client = new Node();

    server.setReceiverPublicKey(client.getPublickey());

    client.setReceiverPublicKey(server.getPublickey());

    String data = "hello";

    String enc = server.encrypt(data);

    System.out.println("hello is coverted to "+enc);

    System.out.println(enc+" is converted to "+client.decrypt(enc));

}
}

sortie:

hello is coverted to OugbNvUuylvAr9mKv//nLA==
OugbNvUuylvAr9mKv//nLA== is converted to hello

Process finished with exit code 0
1
Jegan Babu