Android-RSA 分段加密解密
Android-Openssl创建RSA公钥和私钥
Android-AES加解密
Android-DH 秘钥交换
1. DH(Diffie-Hellman) 介绍
DH 是 Whitfield Diffie 和 Martin Hellman 在1976年共同发明的一种秘钥交换算法。主要用于在不安全的网络上客户端和服务端通过交换公钥,生成一个相同的秘钥,并将该秘钥作为对称加密算法的秘钥,达到使对称加密算法的秘钥可以动态修改的目的。这样便提高了数据在网络上传输的安全性。
DH 总共包含四个部分,分别是:质数原根对、公钥、私钥和秘钥。
2. DH 秘钥交换流程(交换公钥生成共同的秘钥)
1. 客户端和服务端使用相同的质数原根对:P=23 和 G=5,这是秘钥交换的必须条件。
2. 服务端生成随机整数 A = 6,并将 A 作为私钥,使用公钥计算公式:
公钥 = G 的 A 次方 取余 P,等于 Math.pow(5,6) % 23,服务端的公钥为: 8。
3. 客户端生成随机整数 B = 7,并将 B 作为私钥,使用公钥计算公式:
公钥 = G 的 B 次方 取余 P,等于 Math.pow(5,7) % 23,客户端的公钥为: 17。
4. 服务端用客户端的公钥生成秘钥,使用秘钥计算公式:
秘钥 = 17 的 A 次方 取余 P,等于 Math.pow(17,6) % 23,服务端的秘钥为: 12。
5. 客户端用服务端的公钥生成秘钥,使用秘钥计算公式:
秘钥 = 8 的 B 次方 取余 P,等于 Math.pow(8,7) % 23,客户端的秘钥为: 12。
客户端和服务端通过交换公钥,生成了相同的秘钥。
3. DH 代码实现
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.KeyAgreement;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
/**
* DH 秘钥交换
*/
public class DH {
/**
* DH 秘钥长度
*/
private static final int KEY_LENGTH = 1024;
/**
* 秘钥交换算法
*/
private static final String KEY_ALGORITHM = "DH";
/**
* 获取 DH 公钥
*/
public static final String DH_PUBLIC_KEY = "DHPublicKey";
/**
* 获取 DH 私钥
*/
public static final String DH_PRIVATE_KEY = "DHPrivateKey";
/**
* 甲方初始化 公钥 和 私钥
*
* @return 可以通过 {@link this#getPublicKey(Map)} 获取公钥,
* 可以通过 {@link this#getPrivateKey(Map)} 获取私钥钥
*/
public static Map initDHKey() {
try {
// 实例化密钥对生成器
KeyPairGenerator keyPairGenerator =
KeyPairGenerator.getInstance(KEY_ALGORITHM);
// 初始化密钥对生成器 默认是 1024 512-1024 & 64的倍数
keyPairGenerator.initialize(KEY_LENGTH);
// 生成密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 得到甲方公钥
DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
// 得到甲方私钥
DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
// 将公钥和私钥封装在Map中, 方便之后使用
Map keyMap = new HashMap<>();
keyMap.put(DH_PUBLIC_KEY, publicKey);
keyMap.put(DH_PRIVATE_KEY, privateKey);
return keyMap;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 乙方根据甲方公钥初始化并返回密钥对
*
* @param hexStrPubKey 甲方的公钥 16 进制字符串
* @return 可以通过 {@link this#getPublicKey(Map)} 获取公钥,
* 可以通过 {@link this#getPrivateKey(Map)} 获取私钥钥
*/
public static Map initDHKey(String hexStrPubKey) {
return initDHKey(getPublicKey(hexStrPubKey));
}
/**
* 乙方根据甲方公钥初始化并返回密钥对
*
* @param dhPublicKey 甲方的公钥 16 进制字符串
* @return 可以通过 {@link this#getPublicKey(Map)} 获取公钥,
* 可以通过 {@link this#getPrivateKey(Map)} 获取私钥钥
*/
public static Map initDHKey(byte[] dhPublicKey) {
return initDHKey(getPublicKey(dhPublicKey));
}
/**
* 乙方根据甲方公钥初始化并返回密钥对
*
* @param dhPublicKey 甲方的公钥
* @return 可以通过 {@link this#getPublicKey(Map)} 获取公钥,
* 可以通过 {@link this#getPrivateKey(Map)} 获取私钥钥
*/
public static Map initDHKey(DHPublicKey dhPublicKey) {
try {
// 实例化密钥对生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
// 用甲方公钥初始化密钥对生成器
keyPairGenerator.initialize(dhPublicKey.getParams());
// 产生密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 得到乙方公钥
DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
// 得到乙方私钥
DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
// 将公钥和私钥封装在Map中, 方便之后使用
Map keyMap = new HashMap<>();
keyMap.put(DH_PUBLIC_KEY, publicKey);
keyMap.put(DH_PRIVATE_KEY, privateKey);
return keyMap;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 根据对方的公钥和自己的私钥生成 本地密钥,返回SecretKey对象的16进制字符串
*
* @param publicKey 公钥
* @param privateKey 私钥
* @return 秘钥 16 进制字符串
*/
public static String getSecretKeyHexString(DHPublicKey publicKey, DHPrivateKey privateKey) {
byte[] secretKey = getSecretKeyBytes(publicKey, privateKey);
return DataUtils.byte2HexString(secretKey);
}
/**
* 根据对方的公钥和自己的私钥生成 本地密钥,返回的是SecretKey对象的字节数组
*
* @param publicKey 公钥
* @param privateKey 私钥
* @return 秘钥数组
*/
public static byte[] getSecretKeyBytes(DHPublicKey publicKey, DHPrivateKey privateKey) {
try {
// 实例化 KeyAgreement
KeyAgreement keyAgreement = KeyAgreement.getInstance(KEY_ALGORITHM);
// 用自己的私钥初始化keyAgreement
keyAgreement.init(privateKey);
// 结合对方的公钥进行运算
keyAgreement.doPhase(publicKey, true);
// 开始生成本地密钥 SecretKey
// https://blog.csdn.net/fengzun_yi/article/details/104497160
return keyAgreement.generateSecret();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取 DHPublicKey 对象
*
* @param hexStrPubKey DH 16 进制公钥字符串
*/
public static DHPublicKey getPublicKey(String hexStrPubKey) {
byte[] pubKey = DataUtils.hexString2Byte(hexStrPubKey);
return getPublicKey(pubKey);
}
/**
* 获取 DHPublicKey 对象
*
* @param publicKey DH 公钥数组
*/
public static DHPublicKey getPublicKey(byte[] publicKey) {
try {
// 实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 将公钥从字节数组转换为PublicKey
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(publicKey);
return (DHPublicKey) keyFactory.generatePublic(pubKeySpec);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取 DHPrivateKey 对象
*
* @param hexStrPrvKey DH 16 进制私钥字符串
*/
public static DHPrivateKey getPrivateKey(String hexStrPrvKey) {
byte[] prvKey = DataUtils.hexString2Byte(hexStrPrvKey);
return getPrivateKey(prvKey);
}
/**
* 获取 DHPrivateKey 对象
*
* @param privateKey DH 私钥数组
*/
public static DHPrivateKey getPrivateKey(byte[] privateKey) {
try {
// 实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 将私钥从字节数组转换为 PrivateKey
PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(privateKey);
return (DHPrivateKey) keyFactory.generatePrivate(priKeySpec);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取 DHPublicKey 对象 16 进制字符串
*/
public static String getPublicKeyHexString(DHPublicKey dhPublicKey) {
return DataUtils.byte2HexString(dhPublicKey.getEncoded());
}
/**
* 从 Map 中取得私钥
*/
public static String getPrivateKeyHexString(DHPrivateKey dhPrivateKey) {
return DataUtils.byte2HexString(dhPrivateKey.getEncoded());
}
/**
* 从 Map 中取得公钥
*/
public static DHPublicKey getPublicKey(Map keyMap) {
return (DHPublicKey) keyMap.get(DH_PUBLIC_KEY);
}
/**
* 从 Map 中取得私钥
*/
public static DHPrivateKey getPrivateKey(Map keyMap) {
return (DHPrivateKey) keyMap.get(DH_PRIVATE_KEY);
}
}
4. 数据工具类
import android.util.Base64;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.ArrayList;
/**
* 数据工具类
*/
public class DataUtils {
/**
* 将 Base64 字符串 解码成 字节数组
*/
public static byte[] base64Decode(String data) {
return Base64.decode(data, Base64.NO_WRAP);
}
/**
* 将 字节数组 转换成 Base64 编码
*/
public static String base64Encode(byte[] data) {
return Base64.encodeToString(data, Base64.NO_WRAP);
}
}
5. DH 使用测试
public class{
public static void main(String[] args) {
// =================== 甲方 ===================
Map map1 = DH.initDHKey();
DHPublicKey dhPublicKey1 = DH.getPublicKey(map1);
DHPrivateKey dhPrivateKey1 = DH.getPrivateKey(map1);
logDHKey("甲-公钥: " + DH.getPublicKeyHexString(dhPublicKey1));
logDHKey("甲-私钥: " + DH.getPrivateKeyHexString(dhPrivateKey1));
// =================== 乙方 ===================
Map map2 = DH.initDHKey(dhPublicKey1);
DHPublicKey dhPublicKey2 = DH.getPublicKey(map2);
DHPrivateKey dhPrivateKey2 = DH.getPrivateKey(map2);
logDHKey("乙-公钥: " + DH.getPublicKeyHexString(dhPublicKey2));
logDHKey("乙-私钥: " + DH.getPrivateKeyHexString(dhPrivateKey2));
// =================== 甲方-计算秘钥 ===================
// 乙方的公钥 和 自己的私钥
String secretKey1 = DH.getSecretKeyHexString(dhPublicKey2, dhPrivateKey1);
logDHKey("甲-秘钥: " + secretKey1);
// =================== 乙方-计算秘钥 ===================
// 甲方的公钥 和 自己的私钥
String secretKey2 = DH.getSecretKeyHexString(dhPublicKey1, dhPrivateKey2);
logDHKey("乙-秘钥: " + secretKey2);
if (secretKey1.equals(secretKey2)) {
logDHKey("两个秘钥相等...");
}
}
public static void logDHKey(String msg){
System.out.println(msg);
}
}