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