Diffie-Hellman key exchange in Java

前端 未结 3 1417

I am working on a personal project in Java which involves sending sensitive data over an insecure channel. I need to know how to implement Diffie Hellman Key Exchange (DHKE) in

相关标签:
3条回答
  • 2021-02-04 12:44

    Here's a work example:

    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);
    }
    
    0 讨论(0)
  • 2021-02-04 12:49

    What about the official Oracle Docs? They show a DH key exchange in code there.

    0 讨论(0)
  • 2021-02-04 13:04

    Following code uses Elliptic Curve Diffie-Hellman to generate and share 128bit key and AES for encryption.

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

    Extend your own class to add AES encrypting feature

    public class Node extends AESSecurityCap {
    
    //your class
    
    }
    

    Finally, way to use the encryption

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

    output:

    hello is coverted to OugbNvUuylvAr9mKv//nLA==
    OugbNvUuylvAr9mKv//nLA== is converted to hello
    
    Process finished with exit code 0
    
    0 讨论(0)
提交回复
热议问题