1. 程式人生 > >非對稱加密演算法(3):ElGamal

非對稱加密演算法(3):ElGamal

一.ElGamal:ElGamal演算法,是一種較為常見的加密演算法,它是基於1985年提出的公鑰密碼體制和橢圓曲線加密體系。既能用於資料加密也能用於數字簽名,其安全性依賴於計算有限域上離散對數這一難題。在加密過程中,生成的密文長度是明文的兩倍,且每次加密後都會在密文中生成一個隨機數K,在密碼中主要應用離散對數問題的幾個性質:求解離散對數(可能)是困難的,而其逆運算指數運算可以應用平方-乘的方法有效地計算。

二.注意!!!

原因:Illegal key size or default parameters是指金鑰長度是受限制的,java執行時環境讀到的是受限的policy檔案。檔案位於${java_home}/jre/lib/security,

這種限制是因為美國對軟體出口的控制。

解決方案:替換 ${java_home}/jre/lib/security 的 local_policy.jar 和 US_export_policy.jar ,不同的jdk版本的替換檔案不一致,具體參看下面的lian:

三.具體的實現(java):

import java.security.AlgorithmParameterGenerator;  
import java.security.AlgorithmParameters;  
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;  
import java.security.KeyPair;  
import java.security.KeyPairGenerator;  
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;  
import java.security.PublicKey;  
import java.security.SecureRandom;  
import java.security.Security;  
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.PKCS8EncodedKeySpec;  
import java.security.spec.X509EncodedKeySpec;  

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;  
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.DHParameterSpec;  

import org.apache.commons.codec.binary.Base64;  
import org.bouncycastle.jce.provider.BouncyCastleProvider;  

public class ElGamal {

	public static void main(String[] args) throws Exception {
		
		String src = "歐陽草帽";
		KeyPair keyPair = getKeyPair();  
		//公鑰
        PublicKey publicKey = getPublicKey(keyPair);  
        //私鑰
        PrivateKey privateKey = getPrivateKey(keyPair); 

        byte[] publicKeyEnc = publicKey.getEncoded();
        byte[] privateKeyEnc = privateKey.getEncoded();
        System.out.println("祕鑰 :"+Base64.encodeBase64String(privateKeyEnc));
		System.out.println("公鑰 :"+Base64.encodeBase64String(publicKeyEnc));
        
		//加密資料 
		byte[] result = ensrypt(src, publicKeyEnc);  
        System.out.println("加密的資料 :"+Base64.encodeBase64String(result));
		
        result = decrypt(privateKeyEnc, result);
		System.out.println("解密資料:"+new String(result));
	}

	/**
	 * 解密資料 
	 * @param privateKeyEnc :私鑰 
	 * @param result  : 解密資料 
	 * @return
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeySpecException
	 * @throws NoSuchPaddingException
	 * @throws InvalidKeyException
	 * @throws IllegalBlockSizeException
	 * @throws BadPaddingException
	 */
	public static byte[] decrypt(byte[] privateKeyEnc, byte[] result)
			throws NoSuchAlgorithmException, InvalidKeySpecException,
			NoSuchPaddingException, InvalidKeyException,
			IllegalBlockSizeException, BadPaddingException {
		KeyFactory keyFactory = KeyFactory.getInstance("ElGamal");
		PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyEnc);
		PrivateKey priKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, priKey);
		result = cipher.doFinal(result);
		return result;
	}

	/**
	 * 加密資料 
	 * @param src : 加密資料 
	 * @param publicKeyEnc : 公鑰
	 * @return
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeySpecException
	 * @throws NoSuchPaddingException
	 * @throws InvalidKeyException
	 * @throws IllegalBlockSizeException
	 * @throws BadPaddingException
	 */
	public static byte[] ensrypt(String src, byte[] publicKeyEnc)
			throws NoSuchAlgorithmException, InvalidKeySpecException,
			NoSuchPaddingException, InvalidKeyException,
			IllegalBlockSizeException, BadPaddingException {
		KeyFactory keyFactory=KeyFactory.getInstance("ElGamal");  
        //初始化公鑰  
        //金鑰材料轉換  
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(publicKeyEnc);  
        //產生公鑰  
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);  
        //資料加密  
        Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());  
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);  
        byte [] result = cipher.doFinal(src.getBytes());
		return result;
	}

	/**
	 * 獲取私鑰
	 * @param keyPair
	 * @return
	 */
	public static PrivateKey getPrivateKey(KeyPair keyPair) {
		PrivateKey privateKey= keyPair.getPrivate();
		return privateKey;
	}

	/**
	 * 獲取公鑰 
	 * @param keyPair
	 * @return
	 */
	public static PublicKey getPublicKey(KeyPair keyPair) {
		PublicKey publicKey= keyPair.getPublic();
		return publicKey;
	}

	private static KeyPair getKeyPair() throws NoSuchAlgorithmException,
			InvalidParameterSpecException, InvalidAlgorithmParameterException {
		//加入對BouncyCastle支援  
        Security.addProvider(new BouncyCastleProvider());  
        AlgorithmParameterGenerator apg=AlgorithmParameterGenerator.getInstance("ElGamal");  
        //初始化引數生成器  
        apg.init(256);  
        //生成演算法引數  
        AlgorithmParameters params=apg.generateParameters();  
        //構建引數材料  
        DHParameterSpec elParams=(DHParameterSpec)params.getParameterSpec(DHParameterSpec.class);  
        //例項化金鑰生成器  
        KeyPairGenerator kpg=KeyPairGenerator.getInstance("ElGamal") ;  
        //初始化金鑰對生成器  
        kpg.initialize(elParams,new SecureRandom());  
        KeyPair keyPair=kpg.generateKeyPair();
		return keyPair;
	}
}