Android-RSA 分段加密解密
Android-Openssl創(chuàng)建RSA公鑰和私鑰
Android-AES加解密
Android-DH 秘鑰交換
1. DH(Diffie-Hellman) 介紹
DH 是 Whitfield Diffie 和 Martin Hellman 在1976年共同發(fā)明的一種秘鑰交換算法。主要用于在不安全的網(wǎng)絡(luò)上客戶端和服務端通過交換公鑰,生成一個相同的秘鑰,并將該秘鑰作為對稱加密算法的秘鑰,達到使對稱加密算法的秘鑰可以動態(tài)修改的目的。這樣便提高了數(shù)據(jù)在網(wǎng)絡(luò)上傳輸?shù)陌踩浴?br> DH 總共包含四個部分,分別是:質(zhì)數(shù)原根對、公鑰、私鑰和秘鑰。
2. DH 秘鑰交換流程(交換公鑰生成共同的秘鑰)
1. 客戶端和服務端使用相同的質(zhì)數(shù)原根對:P=23 和 G=5,這是秘鑰交換的必須條件。
2. 服務端生成隨機整數(shù) A = 6,并將 A 作為私鑰,使用公鑰計算公式:
公鑰 = G 的 A 次方 取余 P,等于 Math.pow(5,6) % 23,服務端的公鑰為: 8。

3. 客戶端生成隨機整數(shù) 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 代碼實現(xiàn)
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<String, Object> initDHKey() {
try {
// 實例化密鑰對生成器
KeyPairGenerator keyPairGenerator =
KeyPairGenerator.getInstance(KEY_ALGORITHM);
// 初始化密鑰對生成器 默認是 1024 512-1024 & 64的倍數(shù)
keyPairGenerator.initialize(KEY_LENGTH);
// 生成密鑰對
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 得到甲方公鑰
DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
// 得到甲方私鑰
DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
// 將公鑰和私鑰封裝在Map中, 方便之后使用
Map<String, Object> keyMap = new HashMap<>();
keyMap.put(DH_PUBLIC_KEY, publicKey);
keyMap.put(DH_PRIVATE_KEY, privateKey);
return keyMap;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 乙方根據(jù)甲方公鑰初始化并返回密鑰對
*
* @param hexStrPubKey 甲方的公鑰 16 進制字符串
* @return 可以通過 {@link this#getPublicKey(Map)} 獲取公鑰,
* 可以通過 {@link this#getPrivateKey(Map)} 獲取私鑰鑰
*/
public static Map<String, Object> initDHKey(String hexStrPubKey) {
return initDHKey(getPublicKey(hexStrPubKey));
}
/**
* 乙方根據(jù)甲方公鑰初始化并返回密鑰對
*
* @param dhPublicKey 甲方的公鑰 16 進制字符串
* @return 可以通過 {@link this#getPublicKey(Map)} 獲取公鑰,
* 可以通過 {@link this#getPrivateKey(Map)} 獲取私鑰鑰
*/
public static Map<String, Object> initDHKey(byte[] dhPublicKey) {
return initDHKey(getPublicKey(dhPublicKey));
}
/**
* 乙方根據(jù)甲方公鑰初始化并返回密鑰對
*
* @param dhPublicKey 甲方的公鑰
* @return 可以通過 {@link this#getPublicKey(Map)} 獲取公鑰,
* 可以通過 {@link this#getPrivateKey(Map)} 獲取私鑰鑰
*/
public static Map<String, Object> initDHKey(DHPublicKey dhPublicKey) {
try {
// 實例化密鑰對生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
// 用甲方公鑰初始化密鑰對生成器
keyPairGenerator.initialize(dhPublicKey.getParams());
// 產(chǎn)生密鑰對
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 得到乙方公鑰
DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
// 得到乙方私鑰
DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
// 將公鑰和私鑰封裝在Map中, 方便之后使用
Map<String, Object> keyMap = new HashMap<>();
keyMap.put(DH_PUBLIC_KEY, publicKey);
keyMap.put(DH_PRIVATE_KEY, privateKey);
return keyMap;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 根據(jù)對方的公鑰和自己的私鑰生成 本地密鑰,返回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);
}
/**
* 根據(jù)對方的公鑰和自己的私鑰生成 本地密鑰,返回的是SecretKey對象的字節(jié)數(shù)組
*
* @param publicKey 公鑰
* @param privateKey 私鑰
* @return 秘鑰數(shù)組
*/
public static byte[] getSecretKeyBytes(DHPublicKey publicKey, DHPrivateKey privateKey) {
try {
// 實例化 KeyAgreement
KeyAgreement keyAgreement = KeyAgreement.getInstance(KEY_ALGORITHM);
// 用自己的私鑰初始化keyAgreement
keyAgreement.init(privateKey);
// 結(jié)合對方的公鑰進行運算
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 公鑰數(shù)組
*/
public static DHPublicKey getPublicKey(byte[] publicKey) {
try {
// 實例化密鑰工廠
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 將公鑰從字節(jié)數(shù)組轉(zhuǎn)換為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 私鑰數(shù)組
*/
public static DHPrivateKey getPrivateKey(byte[] privateKey) {
try {
// 實例化密鑰工廠
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 將私鑰從字節(jié)數(shù)組轉(zhuǎn)換為 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<String, Object> keyMap) {
return (DHPublicKey) keyMap.get(DH_PUBLIC_KEY);
}
/**
* 從 Map 中取得私鑰
*/
public static DHPrivateKey getPrivateKey(Map<String, Object> keyMap) {
return (DHPrivateKey) keyMap.get(DH_PRIVATE_KEY);
}
}
4. 數(shù)據(jù)工具類
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;
/**
* 數(shù)據(jù)工具類
*/
public class DataUtils {
/**
* 將 Base64 字符串 解碼成 字節(jié)數(shù)組
*/
public static byte[] base64Decode(String data) {
return Base64.decode(data, Base64.NO_WRAP);
}
/**
* 將 字節(jié)數(shù)組 轉(zhuǎn)換成 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<String, Object> map1 = DH.initDHKey();
DHPublicKey dhPublicKey1 = DH.getPublicKey(map1);
DHPrivateKey dhPrivateKey1 = DH.getPrivateKey(map1);
logDHKey("甲-公鑰: " + DH.getPublicKeyHexString(dhPublicKey1));
logDHKey("甲-私鑰: " + DH.getPrivateKeyHexString(dhPrivateKey1));
// =================== 乙方 ===================
Map<String, Object> 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);
}
}