一宋税、概述
1.與對稱加密算法的主要差別在于,加密和解密的密鑰不相同讼油,一個公開(公鑰)杰赛,一個保密(私鑰)。主要解決了對稱加密算法密鑰分配管理的問題矮台,提高了算法安全性乏屯。
2.非對稱加密算法的加密、解密的效率比較低瘦赫。在算法設(shè)計上瓶珊,非對稱加密算法對待加密的數(shù)據(jù)長度有著苛刻的要求。例如RSA算法要求待加密的數(shù)據(jù)不得大于53個字節(jié)耸彪。
3.非對稱加密算法主要用于 交換對稱加密算法的密鑰伞芹,而非數(shù)據(jù)交換
4.java6提供實現(xiàn)了DH和RSA兩種算法。Bouncy Castle提供了E1Gamal算法支持蝉娜。除了上述三種算法還有一個ECC算法唱较,目前沒有相關(guān)的開源組件提供支持
二、模型分析
我們還是以甲乙雙方發(fā)送數(shù)據(jù)為模型進(jìn)行分析
1.甲方(消息發(fā)送方召川,下同)構(gòu)建密鑰對(公鑰+私鑰)南缓,甲方公布公鑰給乙方(消息接收方,下同)
2.乙方以甲方發(fā)送過來的公鑰作為參數(shù)構(gòu)造密鑰對(公鑰+私鑰)荧呐,將構(gòu)造出來的公鑰公布給甲方
3.甲方用“甲方的私鑰+乙方的公鑰”構(gòu)造本地密鑰
4.乙方用“乙方的私鑰+甲方的公鑰”構(gòu)造本地的密鑰
5.這個時候汉形,甲乙兩方本地新構(gòu)造出來的密鑰應(yīng)該一樣纸镊。然后就可以使用AES這類對稱加密算法結(jié)合密鑰進(jìn)行數(shù)據(jù)的安全傳送了。傳送過程參考AES的相關(guān)算法
三概疆、代碼分析
package com.ca.test;
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.DHParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
* 非對稱加密算法DH算法組件
* 非對稱算法一般是用來傳送對稱加密算法的密鑰來使用的逗威,所以這里我們用DH算法模擬密鑰傳送
* 對稱加密AES算法繼續(xù)做我們的數(shù)據(jù)加解密
* @author kongqz
* */
public class DHCoder {
//非對稱密鑰算法
public static final String KEY_ALGORITHM="DH";
//本地密鑰算法,即對稱加密算法岔冀】瘢可選des,aes使套,desede
public static final String SECRET_ALGORITHM="AES";
/**
* 密鑰長度罐呼,DH算法的默認(rèn)密鑰長度是1024
* 密鑰長度必須是64的倍數(shù),在512到1024位之間
* */
private static final int KEY_SIZE=512;
//公鑰
private static final String PUBLIC_KEY="DHPublicKey";
//私鑰
private static final String PRIVATE_KEY="DHPrivateKey";
/**
* 初始化甲方密鑰
* @return Map 甲方密鑰的Map
* */
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>();
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 初始化乙方密鑰
* @param key 甲方密鑰(這個密鑰是通過第三方途徑傳遞的)
* @return Map 乙方密鑰的Map
* */
public static Map<String,Object> initKey(byte[] key) throws Exception{
//解析甲方的公鑰
//轉(zhuǎn)換公鑰的材料
X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
//實例化密鑰工廠
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//產(chǎn)生公鑰
PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
//由甲方的公鑰構(gòu)造乙方密鑰
DHParameterSpec dhParamSpec=((DHPublicKey)pubKey).getParams();
//實例化密鑰生成器
KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
//初始化密鑰生成器
keyPairGenerator.initialize(dhParamSpec);
//產(chǎn)生密鑰對
KeyPair keyPair=keyPairGenerator.genKeyPair();
//乙方公鑰
DHPublicKey publicKey=(DHPublicKey)keyPair.getPublic();
//乙方私鑰
DHPrivateKey privateKey=(DHPrivateKey)keyPair.getPrivate();
//將密鑰存儲在Map中
Map<String,Object> keyMap=new HashMap<String,Object>();
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 加密
* @param data待加密數(shù)據(jù)
* @param key 密鑰
* @return byte[] 加密數(shù)據(jù)
* */
public static byte[] encrypt(byte[] data,byte[] key) throws Exception{
//生成本地密鑰
SecretKey secretKey=new SecretKeySpec(key,SECRET_ALGORITHM);
//數(shù)據(jù)加密
Cipher cipher=Cipher.getInstance(secretKey.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(data);
}
/**
* 解密
* @param data 待解密數(shù)據(jù)
* @param key 密鑰
* @return byte[] 解密數(shù)據(jù)
* */
public static byte[] decrypt(byte[] data,byte[] key) throws Exception{
//生成本地密鑰
SecretKey secretKey=new SecretKeySpec(key,SECRET_ALGORITHM);
//數(shù)據(jù)解密
Cipher cipher=Cipher.getInstance(secretKey.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(data);
}
/**
* 構(gòu)建密鑰
* @param publicKey 公鑰
* @param privateKey 私鑰
* @return byte[] 本地密鑰
* */
public static byte[] getSecretKey(byte[] publicKey,byte[] privateKey) throws Exception{
//實例化密鑰工廠
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//初始化公鑰
//密鑰材料轉(zhuǎn)換
X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(publicKey);
//產(chǎn)生公鑰
PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
//初始化私鑰
//密鑰材料轉(zhuǎn)換
PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(privateKey);
//產(chǎn)生私鑰
PrivateKey priKey=keyFactory.generatePrivate(pkcs8KeySpec);
//實例化
KeyAgreement keyAgree=KeyAgreement.getInstance(keyFactory.getAlgorithm());
//初始化
keyAgree.init(priKey);
keyAgree.doPhase(pubKey, true);
//生成本地密鑰
SecretKey secretKey=keyAgree.generateSecret(SECRET_ALGORITHM);
return secretKey.getEncoded();
}
/**
* 取得私鑰
* @param keyMap 密鑰map
* @return byte[] 私鑰
* */
public static byte[] getPrivateKey(Map<String,Object> keyMap){
Key key=(Key)keyMap.get(PRIVATE_KEY);
return key.getEncoded();
}
/**
* 取得公鑰
* @param keyMap 密鑰map
* @return byte[] 公鑰
* */
public static byte[] getPublicKey(Map<String,Object> keyMap) throws Exception{
Key key=(Key) keyMap.get(PUBLIC_KEY);
return key.getEncoded();
}
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//生成甲方的密鑰對
Map<String,Object> keyMap1=DHCoder.initKey();
//甲方的公鑰
byte[] publicKey1=DHCoder.getPublicKey(keyMap1);
//甲方的私鑰
byte[] privateKey1=DHCoder.getPrivateKey(keyMap1);
System.out.println("甲方公鑰:/n"+Base64.encodeBase64String(publicKey1));
System.out.println("甲方私鑰:/n"+Base64.encodeBase64String(privateKey1));
//由甲方的公鑰產(chǎn)生的密鑰對
Map<String,Object> keyMap2=DHCoder.initKey(publicKey1);
byte[] publicKey2=DHCoder.getPublicKey(keyMap2);
byte[] privateKey2=DHCoder.getPrivateKey(keyMap2);
System.out.println("乙方公鑰:/n"+Base64.encodeBase64String(publicKey2));
System.out.println("乙方私鑰:/n"+Base64.encodeBase64String(privateKey2));
//組裝甲方的本地加密密鑰,由乙方的公鑰和甲方的私鑰組合而成
byte[] key1=DHCoder.getSecretKey(publicKey2, privateKey1);
System.out.println("甲方的本地密鑰:/n"+Base64.encodeBase64String(key1));
//組裝乙方的本地加密密鑰侦高,由甲方的公鑰和乙方的私鑰組合而成
byte[] key2=DHCoder.getSecretKey(publicKey1, privateKey2);
System.out.println("乙方的本地密鑰:/n"+Base64.encodeBase64String(key2));
System.out.println("================密鑰對構(gòu)造完畢嫉柴,開始進(jìn)行加密數(shù)據(jù)的傳輸=============");
String str="密碼交換算法";
System.out.println("/n===========甲方向乙方發(fā)送加密數(shù)據(jù)==============");
System.out.println("原文:"+str);
System.out.println("===========使用甲方本地密鑰對進(jìn)行數(shù)據(jù)加密==============");
//甲方進(jìn)行數(shù)據(jù)的加密
byte[] code1=DHCoder.encrypt(str.getBytes(), key1);
System.out.println("加密后的數(shù)據(jù):"+Base64.encodeBase64String(code1));
System.out.println("===========使用乙方本地密鑰對數(shù)據(jù)進(jìn)行解密==============");
//乙方進(jìn)行數(shù)據(jù)的解密
byte[] decode1=DHCoder.decrypt(code1, key2);
System.out.println("乙方解密后的數(shù)據(jù):"+new String(decode1)+"/n/n");
System.out.println("===========反向進(jìn)行操作,乙方向甲方發(fā)送數(shù)據(jù)==============/n/n");
str="乙方向甲方發(fā)送數(shù)據(jù)DH";
System.out.println("原文:"+str);
//使用乙方本地密鑰對數(shù)據(jù)進(jìn)行加密
byte[] code2=DHCoder.encrypt(str.getBytes(), key2);
System.out.println("===========使用乙方本地密鑰對進(jìn)行數(shù)據(jù)加密==============");
System.out.println("加密后的數(shù)據(jù):"+Base64.encodeBase64String(code2));
System.out.println("=============乙方將數(shù)據(jù)傳送給甲方======================");
System.out.println("===========使用甲方本地密鑰對數(shù)據(jù)進(jìn)行解密==============");
//甲方使用本地密鑰對數(shù)據(jù)進(jìn)行解密
byte[] decode2=DHCoder.decrypt(code2, key1);
System.out.println("甲方解密后的數(shù)據(jù):"+new String(decode2));
}
}
控制臺輸出結(jié)果:
甲方公鑰:
MIHgMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHz
W5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSG
kx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANEAAJBALk1l11UT5Y1
evJv1sLQAXo7Yj/olsPMVJ/7zOx503CRcovA5Q+k2OyIZsl5H2qGCnqi+Da0/9zZx0go8Y/j5B4=
甲方私鑰:
MIHRAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYX
rgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpD
TWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQyAjB0haXhPoDW
gLMF79N1ZZGu1dtHWAObe9obKAh4hGH0HsAsSY8qy17ZE0IyiOwYPXA=
乙方公鑰:
MIHgMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHz
W5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSG
kx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANEAAJBAOWqgUur2jDR
057ohEH4eb3KwOdmcbsv4GnvIlCVzwpBKVlUk0MMIeV8APLz/xIjjoOnNZx3rNknaO/+v85tG3g=
乙方私鑰:
MIHRAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYX
rgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpD
TWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQyAjB+/HgBYVlO
e2eAeU0HoWQyYsHt0tSPUZUqCyY9mWEK/7soxsR/6pfAb1npaaI1NO0=
甲方的本地密鑰:
+E068E5KSWvLYrB5o1ryIY1VFt6WcUnBrXvlBYN++/M=
乙方的本地密鑰:
+E068E5KSWvLYrB5o1ryIY1VFt6WcUnBrXvlBYN++/M=
================密鑰對構(gòu)造完畢奉呛,開始進(jìn)行加密數(shù)據(jù)的傳輸=============
===========甲方向乙方發(fā)送加密數(shù)據(jù)==============
原文:密碼交換算法
===========使用甲方本地密鑰對進(jìn)行數(shù)據(jù)加密==============
加密后的數(shù)據(jù):1PUMKnkyfKauO6kTG5UDtA==
===========使用乙方本地密鑰對數(shù)據(jù)進(jìn)行解密==============
乙方解密后的數(shù)據(jù):密碼交換算法
===========反向進(jìn)行操作计螺,乙方向甲方發(fā)送數(shù)據(jù)==============
原文:乙方向甲方發(fā)送數(shù)據(jù)DH
===========使用乙方本地密鑰對進(jìn)行數(shù)據(jù)加密==============
加密后的數(shù)據(jù):VGLdXmtGyBaE87NiSoHX+yvwyUkAx/qYKYWv+jEwkBY=
=============乙方將數(shù)據(jù)傳送給甲方======================
===========使用甲方本地密鑰對數(shù)據(jù)進(jìn)行解密==============
甲方解密后的數(shù)據(jù):乙方向甲方發(fā)送數(shù)據(jù)DH
四、總結(jié)
1.非對稱加密算法主要用來傳遞密鑰的侧馅,而且性能較低危尿。但是安全性超強呐萌。非對稱加密算法能加密的數(shù)據(jù)長度也受限
2.用非對稱加密算法算出甲乙雙方本地的密鑰后馁痴,可以選擇DES/AES/DESede這些對稱加密算法進(jìn)行數(shù)據(jù)的傳送了