一、概述
1.ElGamal算法和ECC算法基于離散對數(shù)問題
2.這個是一個單向的過程。雖然密鑰對構(gòu)造簡單,但是只是乙方向另外一方單向傳送數(shù)據(jù)進行加解密,不能反向操作
3.這里只有“公鑰加密、私鑰解密”這個過程
4.ElGamal不足之處就是 密文會成倍增長
5.ElGamal和RSA最大不同就是他們構(gòu)造密鑰對的方式不同。還有就是是否為雙向加解密
二、模型分析
以甲方向乙方發(fā)送數(shù)據(jù)為模型
1.甲方構(gòu)造密鑰對(公鑰+私鑰),公布公鑰給乙方
2.這里甲方?jīng)]法給乙方發(fā)送數(shù)據(jù)了,只有乙方能給甲方傳送數(shù)據(jù)
3.乙方用公鑰對數(shù)據(jù)進行加密,傳送給甲方,甲方用私鑰對數(shù)據(jù)進行解密
三、代碼實現(xiàn)
package com.ca.test;
import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
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.SecureRandom;
import java.security.Security;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
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.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* 非對稱加密算法ElGamal算法組件
* 非對稱算法一般是用來傳送對稱加密算法的密鑰來使用的。相對于RSA算法,這個算法只支持私鑰加密公鑰解密
* @author kongqz
* */
public class ElGamalCoder {
//非對稱密鑰算法
public static final String KEY_ALGORITHM="ElGamal";
/**
* 密鑰長度,DH算法的默認密鑰長度是1024
* 密鑰長度必須是8的倍數(shù),在160到16384位之間
* */
private static final int KEY_SIZE=256;
//公鑰
private static final String PUBLIC_KEY="ElGamalPublicKey";
//私鑰
private static final String PRIVATE_KEY="ElGamalPrivateKey";
/**
* 初始化密鑰對
* @return Map 甲方密鑰的Map
* */
public static Map<String,Object> initKey() throws Exception{
//加入對BouncyCastle支持
Security.addProvider(new BouncyCastleProvider());
AlgorithmParameterGenerator apg=AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM);
//初始化參數(shù)生成器
apg.init(KEY_SIZE);
//生成算法參數(shù)
AlgorithmParameters params=apg.generateParameters();
//構(gòu)建參數(shù)材料
DHParameterSpec elParams=(DHParameterSpec)params.getParameterSpec(DHParameterSpec.class);
//實例化密鑰生成器
KeyPairGenerator kpg=KeyPairGenerator.getInstance(KEY_ALGORITHM) ;
//初始化密鑰對生成器
kpg.initialize(elParams,new SecureRandom());
KeyPair keyPair=kpg.generateKeyPair();
//甲方公鑰
PublicKey publicKey= keyPair.getPublic();
//甲方私鑰
PrivateKey privateKey= 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[] encryptByPublicKey(byte[] data,byte[] key) throws Exception{
//實例化密鑰工廠
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//初始化公鑰
//密鑰材料轉(zhuǎn)換
X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
//產(chǎn)生公鑰
PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
//數(shù)據(jù)加密
Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(data);
}
/**
* 私鑰解密
* @param data 待解密數(shù)據(jù)
* @param key 密鑰
* @return byte[] 解密數(shù)據(jù)
* */
public static byte[] decryptByPrivateKey(byte[] data,byte[] key) throws Exception{
//取得私鑰
PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//生成私鑰
PrivateKey privateKey=keyFactory.generatePrivate(pkcs8KeySpec);
//數(shù)據(jù)解密
Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 取得私鑰
* @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> keyMap=ElGamalCoder.initKey();
//公鑰
byte[] publicKey=ElGamalCoder.getPublicKey(keyMap);
//私鑰
byte[] privateKey=ElGamalCoder.getPrivateKey(keyMap);
System.out.println("公鑰:/n"+Base64.encodeBase64String(publicKey));
System.out.println("私鑰:/n"+Base64.encodeBase64String(privateKey));
System.out.println("================密鑰對構(gòu)造完畢,甲方將公鑰公布給乙方,開始進行加密數(shù)據(jù)的傳輸=============");
String str="ElGamal密碼交換算法";
System.out.println("/n===========甲方向乙方發(fā)送加密數(shù)據(jù)==============");
System.out.println("原文:"+str);
//乙方使用公鑰對數(shù)據(jù)進行加密
byte[] code2=ElGamalCoder.encryptByPublicKey(str.getBytes(), publicKey);
System.out.println("===========乙方使用公鑰對數(shù)據(jù)進行加密==============");
System.out.println("加密后的數(shù)據(jù):"+Base64.encodeBase64String(code2));
//甲方使用私鑰對數(shù)據(jù)進行解密
byte[] decode2=ElGamalCoder.decryptByPrivateKey(code2, privateKey);
System.out.println("甲方解密后的數(shù)據(jù):"+new String(decode2));
}
}
控制臺輸出:
公鑰:
MHgwUAYGKw4HAgEBMEYCIQD0uq+9qH/RFRMgdsbGP9scyNhsDF51I40kDUGYfDs9LwIhAMxG0VQV
ZBaqTMZzLeFGYO2SBQX2UMAnuiBzLhKEcPh1AyQAAiEA2eL2mHUbsm/3p9wNRLSaikuOmkRoIbbp
Ltvj8Lok3OE=
私鑰:
MHkCAQAwUAYGKw4HAgEBMEYCIQD0uq+9qH/RFRMgdsbGP9scyNhsDF51I40kDUGYfDs9LwIhAMxG
0VQVZBaqTMZzLeFGYO2SBQX2UMAnuiBzLhKEcPh1BCICIHkLWWt3E212XnDAMZonNEE4tDbDtkVV
9GOHK/rBjAQi
================密鑰對構(gòu)造完畢,甲方將公鑰公布給乙方,開始進行加密數(shù)據(jù)的傳輸=============
===========甲方向乙方發(fā)送加密數(shù)據(jù)==============
原文:ElGamal密碼交換算法
===========乙方使用公鑰對數(shù)據(jù)進行加密==============
加密后的數(shù)據(jù):d9HzNTy1AnEk9c7f6cUs7B6QRbHnMSd3666pfqlffC+ziJj0jYCcmV4Jso8eU1gTs57z8pjJB23j
mCB1A8uFjw==
甲方解密后的數(shù)據(jù):ElGamal密碼交換算法
四、總結(jié)
1.這個是一個單向傳遞數(shù)據(jù)的過程,這個和RSA不同,RSA的公鑰私鑰都可以用來做加解密數(shù)據(jù)的
2.這里java6不支持ElGamal算法,BouncyCastle支持這個算法
3.這里的公鑰私鑰長度幾乎一致
4.這里只有“公鑰加密、私鑰解密”這一個原則