DH,全稱爲「Diffie-Hellman」,他是一種確保共享KEY安全穿越不安全網絡的方法,也就是常說的密鑰一致協議。由公開密鑰密碼體制的奠定人Diffie和Hellman所提出的一種思想。java
簡單的說就是容許兩名用戶在公開媒體上交換信息以生成「一致」的、能夠共享的密鑰。也就是由甲方產出一對密鑰(公鑰、私鑰),乙方依照甲方公鑰產生乙方密鑰對(公鑰、私鑰)。算法
以此爲基線,做爲數據傳輸保密基礎,同時雙方使用同一種對稱加密算法構建本地密鑰(SecretKey)對數據加密。這樣,在互通了本地密鑰(SecretKey)算法後,甲乙雙方公開本身的公鑰,使用對方的公鑰和剛纔產生的私鑰加密數據,同時可使用對方的公鑰和本身的私鑰對數據解密。不僅僅是甲乙雙方兩方,能夠擴展爲多方共享數據通信,這樣就完成了網絡交互數據的安全通信!數組
整個通訊過程當中g、g^a、g^b是公開的,但因爲g、a、b都是整數,經過g和g^a獲得a仍是比較容易的,b也是如此,因此最終的「密鑰」g^(a*b)仍是能夠被計算出來的。因此實際的過程還須要在基本原理上加入新的計算——模運算。安全
(g^b%p)^a%p=(g^a%p)^b%p 證實:網絡
若是a=2:工具
整個通訊過程當中g、p、g^a%p、g^b%p是公開的,這時經過g、p、g^a%p獲得a比較難,一樣經過g、p、g^b%p獲得b比較難,因此最終的密鑰是比較安全的。測試
以g=五、p=2三、g^a%p=8計算a爲例,a=log(5, (8+23*n)),這個只能將n的可能值逐個帶入公式試驗才能獲得a的值。若是a、p是比較大的數那麼計算更加困難。優化
須要注意的是,爲了防止應用優化算法計算上述問題,質數p不是隨便選擇的,須要符合必定的條件。隨機數a、b的生成算法也必需注意,應使結果儘量隨機,不能出現可預測的規律,不然會使破解變的容易。google
package com.test.dh; import com.google.common.collect.Maps; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import javax.crypto.*; import javax.crypto.interfaces.DHPrivateKey; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Map; /** * Created by xiang.li on 2015/3/4. * DH 加解密工具類 */ public class DH { /** * 定義加密方式 */ private static final String KEY_DH = "DH"; /** * 默認密鑰字節數 */ private static final int KEY_SIZE = 1024; /** * DH加密下須要一種對稱加密算法對數據加密,這裏咱們使用DES,也可使用其餘對稱加密算法 */ private static final String KEY_DH_DES = "DES"; private static final String KEY_DH_PUBLICKEY = "DHPublicKey"; private static final String KEY_DH_PRIVATEKEY = "DHPrivateKey"; /** * 初始化甲方密鑰 * @return */ public static Map<String, Object> init() { Map<String, Object> map = null; try { KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_DH); generator.initialize(KEY_SIZE); KeyPair keyPair = generator.generateKeyPair(); // 甲方公鑰 DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic(); // 甲方私鑰 DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate(); map = Maps.newHashMap(); map.put(KEY_DH_PUBLICKEY, publicKey); map.put(KEY_DH_PRIVATEKEY, privateKey); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return map; } /** * 初始化乙方密鑰 * @param key 甲方密鑰 * @return */ public static Map<String, Object> init(String key) { Map<String, Object> map = null; try { // 解析甲方密鑰 byte[] bytes = decryptBase64(key); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); KeyFactory factory = KeyFactory.getInstance(KEY_DH); PublicKey publicKey = factory.generatePublic(keySpec); // 由甲方公鑰構建乙方密鑰 DHParameterSpec spec = ((DHPublicKey) publicKey).getParams(); KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_DH); generator.initialize(spec); KeyPair keyPair = generator.generateKeyPair(); // 乙方公鑰 DHPublicKey dhPublicKey = (DHPublicKey) keyPair.getPublic(); // 乙方私鑰 DHPrivateKey dhPrivateKey = (DHPrivateKey) keyPair.getPrivate(); map = Maps.newHashMap(); map.put(KEY_DH_PUBLICKEY, dhPublicKey); map.put(KEY_DH_PRIVATEKEY, dhPrivateKey); } catch (Exception e) { e.printStackTrace(); } return map; } /** * DH 加密 * @param data 帶加密數據 * @param publicKey 甲方公鑰 * @param privateKey 乙方私鑰 * @return */ public static byte[] encryptDH(byte[] data, String publicKey, String privateKey) { byte[] bytes = null; try { // 生成本地密鑰 SecretKey secretKey = getSecretKey(publicKey, privateKey); // 數據加密 Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, secretKey); bytes = cipher.doFinal(data); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } return bytes; } /** * DH 解密 * @param data 待解密數據 * @param publicKey 乙方公鑰 * @param privateKey 甲方私鑰 * @return */ public static byte[] decryptDH(byte[] data, String publicKey, String privateKey) { byte[] bytes = null; try { // 生成本地密鑰 SecretKey secretKey = getSecretKey(publicKey, privateKey); // 數據解密 Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, secretKey); bytes = cipher.doFinal(data); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } return bytes; } /** * 取得私鑰 * @param map * @return */ public static String getPrivateKey(Map<String, Object> map) { String str = ""; try { Key key = (Key) map.get(KEY_DH_PRIVATEKEY); str = encryptBase64(key.getEncoded()); } catch (Exception e) { e.printStackTrace(); } return str; } /** * 取得公鑰 * @param map * @return */ public static String getPublicKey(Map<String, Object> map) { String str = ""; try { Key key = (Key) map.get(KEY_DH_PUBLICKEY); str = encryptBase64(key.getEncoded()); } catch (Exception e) { e.printStackTrace(); } return str; } /** * 構建本地密鑰 * @param publicKey 公鑰 * @param privateKey 私鑰 * @return */ private static SecretKey getSecretKey(String publicKey, String privateKey) { SecretKey secretKey = null; try { // 初始化公鑰 byte[] publicBytes = decryptBase64(publicKey); KeyFactory factory = KeyFactory.getInstance(KEY_DH); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes); PublicKey localPublicKey = factory.generatePublic(keySpec); // 初始化私鑰 byte[] privateBytes = decryptBase64(privateKey); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateBytes); PrivateKey localPrivateKey = factory.generatePrivate(spec); KeyAgreement agreement = KeyAgreement.getInstance(factory.getAlgorithm()); agreement.init(localPrivateKey); agreement.doPhase(localPublicKey, true); // 生成本地密鑰 secretKey = agreement.generateSecret(KEY_DH_DES); } catch (Exception e) { e.printStackTrace(); } return secretKey; } /** * BASE64 解密 * @param key 須要解密的字符串 * @return 字節數組 * @throws Exception */ public static byte[] decryptBase64(String key) throws Exception { return (new BASE64Decoder()).decodeBuffer(key); } /** * BASE64 加密 * @param key 須要加密的字節數組 * @return 字符串 * @throws Exception */ public static String encryptBase64(byte[] key) throws Exception { return (new BASE64Encoder()).encodeBuffer(key); } /** * 測試方法 * @param args */ public static void main(String[] args) { // 生成甲方密鑰對 Map<String, Object> mapA = init(); String publicKeyA = getPublicKey(mapA); String privateKeyA = getPrivateKey(mapA); System.out.println("甲方公鑰:\n" + publicKeyA); System.out.println("甲方私鑰:\n" + privateKeyA); // 由甲方公鑰產生本地密鑰對 Map<String, Object> mapB = init(publicKeyA); String publicKeyB = getPublicKey(mapB); String privateKeyB = getPrivateKey(mapB); System.out.println("乙方公鑰:\n" + publicKeyB); System.out.println("乙方私鑰:\n" + privateKeyB); String word = "abc"; System.out.println("原文: " + word); // 由甲方公鑰,乙方私鑰構建密文 byte[] encWord = encryptDH(word.getBytes(), publicKeyA, privateKeyB); // 由乙方公鑰,甲方私鑰解密 byte[] decWord = decryptDH(encWord, publicKeyB, privateKeyA); System.out.println("解密: " + new String(decWord)); } }