java加密体系-秘钥交换算法DH

密钥交换算法(秘钥协商算法)——DH

1.简述

    1976年,W.Diffie和M.Hellman在发表的论文中提出了公钥加密算法思想,但当时并没有给出具体的实施方案,原因在于没有找到单向函数(也就是消息摘要算法),但在该论文中给出了通信双方通过信息交换协商密钥的算法,即Diffie-Hellman密钥交换算法(简称为DH算法)。该算法的目的在于让消息的收发双方可以在安全的条件下交换密钥,以备后续加密/解密使用。因此,DH算法是第一个密钥协商算法,但仅能用于密钥分配,不能用于加密或者解密消息。

    DH密钥交换算法的安全性基于有限域上的离散对数难题。基于这种安全性,通过DH算法进行密钥分配,使得消息的收发双方可以安全地交换一个密钥,再通过这个密钥对数据进行加密和解密处理。

2.模型分析

    我们以消息传递模型为例,甲方作为发送者,乙方作为接受者,分述甲乙双方如何构建密钥、交互密钥和加密数据。

    首先,甲乙双方需要在收发消息前构建自己的密钥对,如图1所示。

    

    甲乙双方构建密钥需要经过以下几个步骤:

    1)由消息发送的一方构建密钥,这里由甲方构建密钥。

    2)由构建密钥的一方向对方公布其公钥,这里由甲方向乙方发布公钥。

    3)由消息接收的一方通过对方公钥构建自身密钥,这里由乙方使用甲方公钥构建乙方密钥。

    4)由消息接收的一方向对方公布其公钥,这里由乙方向甲方公布公钥。

    这里要注意的是,乙方构建自己密钥对的时候需要使用甲方公钥作为参数这是很关键的一点,如果缺少了这一环节则无法确保甲乙双方获得同一个密钥,消息加密更无从谈起。

    其次,假设甲乙双方事先约定好了用于数据加密的对称加密算法(如AES算法),并构建本地密钥(即对称加密算法中的密钥),如图2所示。

    甲方需要使用自己的私钥和乙方的公钥才能构建自己的本地密钥,乙方需要使用自己的私钥和甲方的公钥才能构建自己的本地密钥。

    虽然甲乙双方使用了不同的密钥来构建本地密钥,但是甲乙两方得到的密钥其实是一致的,后面的demo可以证明,也正是基于此,甲乙双方才能顺利地进行加密消息的传送。

    最后,甲乙双方构建了本地密钥后,可按照基于对称加密算法的消息传递模型完成消息传递。如图4所示。

    作为对称加密体制向非对称加密体制的一种过渡,DH算法仅仅比一般的对称加密算法多了密钥对的构建和本地密钥的构建这两项操作,而真正的数据加密/解密操作仍由对称加密算法完成。

3.实现

1)DH算法实现(DHUtil.java)

package com.mpush.dh;
 
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.SecretKeySpec;
 
public abstract class DHUtil {
	
    /**
     * 秘钥交换算法(非对称加密算法)
     */
	private static final String KEY_ALGORITHM = "DH";
	
    /**
     * 本地密钥算法,即对称加密密钥算法
     * 可选DES、DESede或者AES
     */
	private static final String SELECT_ALGORITHM = "AES";
	
	/**
	 * 密钥长度
	 */
	private static final int KEY_SIZE = 512;
	
	//公钥
	private static final String PUBLIC_KEY = "DHPublicKey";
	
	//私钥
	private static final String PRIVATE_KEY = "DHPrivateKey";
	
	
	/**
	 * 初始化密钥
	 * @return Map 密钥Map
	 * @throws Exception
	 */
	public static Map<String, Object> initKey() throws Exception{
		//实例化密钥对生成器
		KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		//初始化密钥对生成器
		keyPairGenerator.initialize(KEY_SIZE);
		//生成密钥对
		KeyPair keyPair = keyPairGenerator.generateKeyPair();
		//甲方公钥
		DHPublicKey publicKey = (DHPublicKey)keyPair.getPublic();
		//甲方私钥
		DHPrivateKey privateKey = (DHPrivateKey)keyPair.getPrivate();
		//将密钥对存储在Map中
		Map<String, Object> keyMap = new HashMap<String, Object>(2);
		keyMap.put(PUBLIC_KEY, publicKey);
		keyMap.put(PRIVATE_KEY, privateKey);
		return keyMap;
	}
	
	/**
	 * 加密
	 * @param data 待加密数据
	 * @param key 密钥
	 * @return byte[] 加密数据
	 * @throws Exception
	 */
    public static byte[] encrypt(byte[] data, byte[] key) throws Exception{
    	//生成本地密钥
    	SecretKey secretKey = new SecretKeySpec(key, SELECT_ALGORITHM);
    	//数据加密
    	Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
    	cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    	return cipher.doFinal(data);
    }
    
    /**
     * 解密
     * @param data 待解密数据
     * @param key 密钥
     * @return byte[] 解密数据
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, byte[] key) throws Exception{
    	//生成本地密钥
    	SecretKey secretKey = new SecretKeySpec(key, SELECT_ALGORITHM);
    	//数据揭秘
    	Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
    	cipher.init(Cipher.DECRYPT_MODE, secretKey);
    	return cipher.doFinal(data);
    }
    
    /**
     * 构建密钥
     * @param publicKey 公钥
     * @param privateKey 私钥
     * @return byte[] 本地密钥
     * @throws Exception
     */
    public static byte[] getSecretKey(byte[] publicKey, byte[] privateKey) throws Exception{
    	//实例化密钥工厂
    	KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    	//初始化公钥
    	//密钥材料转换
    	X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
    	//产生公钥
    	PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
    	//初始化私钥
    	//密钥材料转换
    	PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
    	//产生私钥
    	PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
    	//实例化
    	KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory.getAlgorithm());
    	//初始化
    	keyAgree.init(priKey);
    	keyAgree.doPhase(pubKey, true);
    	//生成本地密钥
    	SecretKey secretKey = keyAgree.generateSecret(SELECT_ALGORITHM);
    	return secretKey.getEncoded();
    }
    
    /**
     * 取得私钥
     * @param keyMap 密钥Map
     * @return byte[] 私钥
     * @throws Exception
     */
    public static byte[] getPrivateKey(Map<String, Object> keyMap) throws Exception{
    	Key key = (Key) keyMap.get(PRIVATE_KEY);
    	return key.getEncoded();
    }
    
    /**
     * 取得公钥
     * @param keyMap 密钥Map
     * @return byte[] 公钥
     * @throws Exception
     */
    public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception{
    	Key key = (Key) keyMap.get(PUBLIC_KEY);
    	return key.getEncoded();
    }
}

2)DH算法测试(DHTest.java)

package com.mpush.dh;

import java.util.Map;
import org.apache.commons.codec.binary.Hex;

public class DHTest {
	
	public static void main(String[] args) throws Exception {
		//构建a本地秘钥对
		Map<String, Object> aKeyMap = DHUtil.initKey();
		byte[] aPublickeyBytes = DHUtil.getPublicKey(aKeyMap);
		byte[] aPrivatekeyBytes = DHUtil.getPrivateKey(aKeyMap);
		//公布公钥
		System.out.println("a公布公钥:"+Hex.encodeHexString(aPublickeyBytes));
		
		//构建b本地秘钥对
		Map<String, Object> bKeyMap = DHUtil.initKey();
		byte[] bPublickeyBytes = DHUtil.getPublicKey(bKeyMap);
		byte[] bPrivatekeyBytes = DHUtil.getPrivateKey(bKeyMap);
		//公布公钥
		System.out.println("b公布公钥:"+Hex.encodeHexString(bPublickeyBytes));//实际开发中要保证公钥传输安全(数字签名)
		
		//a构建共享秘钥
		byte[] aSecretKey = DHUtil.getSecretKey(bPublickeyBytes, aPrivatekeyBytes);
		String aSecretKeyStr = Hex.encodeHexString(aSecretKey);
		System.out.println("a构建共享秘钥:"+aSecretKeyStr);
		//b构建共享秘钥
		byte[] bSecretKey = DHUtil.getSecretKey(aPublickeyBytes, bPrivatekeyBytes);
		String bSecretKeyStr = Hex.encodeHexString(bSecretKey);
		System.out.println("b构建共享秘钥:"+bSecretKeyStr);
		//c中间人构建共享秘钥
		/*byte[] cSecretKey = DHUtil.getSecretKey(bPublickeyBytes, bPrivatekeyBytes);
		String cSecretKeyStr = Hex.encodeHexString(cSecretKey);
		System.out.println("c构建共享秘钥:"+cSecretKeyStr);*/
		//秘钥构建对比
		System.out.println(aSecretKeyStr.equals(bSecretKeyStr));
		
		//a发送消息
		String msg = "你好,癫狗";
		byte[] encryptMsg = DHUtil.encrypt(msg.getBytes(), aSecretKey);
		//b解密消息
		byte[] decryptMsg = DHUtil.decrypt(encryptMsg, bSecretKey);
		System.out.println(new String(decryptMsg));
		
	}

}

4.测试结果

a公布公钥:3081df30819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800343000240216c56913593ed52e468b81945a141e6b4f1f1cf7e6b77d1200c7cef145c9e7ad3fb9bfa05e79f0c79f545bd017b49696394fd173724ba9ee3e94ff97f3e52aa
b公布公钥:3081e030819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800344000241009a961219af79cc295dabbf476a6c4696ecc89482baba405ea9ba73a14df0c5faf8c8dff95f6ce1a31a5827dab3f4797986e7435314a61b33dc25385a5a64868c
a构建共享秘钥:4a9ddf389f6712c04c7a48c46b845fc7fa685093f49bf734cc702d9bbca595a9
b构建共享秘钥:4a9ddf389f6712c04c7a48c46b845fc7fa685093f49bf734cc702d9bbca595a9
true
你好,癫狗

猜你喜欢

转载自blog.csdn.net/u010739551/article/details/83058313