8.4.3 实现
很遗憾,作为常用非对称加密算法的ElGamal算法并没有出现在Java 6的API中,但却包含在了Bouncy Castle的API中,弥补了Java语言缺少对于ElGamal算法支持的缺憾。
有关ElGamal算法的Bouncy Castle实现细节如表8-3所示。
JCE框架为其他非对称加密算法实现提供了一个构建密钥对方式,均基于DH算法参数材料—DHParameterSpec类。代码清单8-10展示了如何构建ElGamal算法密钥对。
代码清单8-10 构建ElGamal算法密钥对
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
//省略
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//实例化算法参数生成器
AlgorithmParameterGenerator apg=AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM);
//初始化算法参数生成器
apg.init(KEY_SIZE);
//生成算法参数
AlgorithmParameters params=apg.generateParameters();
//构建参数材料
DHParameterSpec elParams=(DHParameterSpec)params.getParameterSpec(DHParameterSpec.class);
//实例化密钥对生成器
KeyPairGenerator kpg=KeyPairGenerator.getInstance(KEY_ALGORITHM);
//初始化密钥对生成器
kpg.initialize(elParams, new SecureRandom());
//生成密钥对
KeyPair keys=kpg.genKeyPair();
有了密钥对实例化对象keys自然就可以获得相应的密钥了。
需要注意的是,这里我们使用Bouncy Castle提供的ElGamal算法实现,在使用各种引擎类做实例化操作前,需导入Bouncy Castle提供者,如代码清单8-11所示。
代码清单8-11 导入Bouncy Castle提供者
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
//省略
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
抛开密钥对的生成实现,ElGamal算法实现与RSA算法实现几乎一致,如代码清单8-12所示。
代码清单8-12 ElGamal算法实现
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.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.spec.DHParameterSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
*ElGamal安全编码组件
*@author梁栋
*@version 1.0
*@since 1.0
*/
public abstract class ElGamalCoder{
//非对称加密密钥算法
public static final String KEY_ALGORITHM="ElGamal";
/**
*密钥长度
*ElGamal算法
*默认密钥长度为1024
*密钥长度范围在160~16384位不等,
*且密钥长度必须是8的倍数。
*/
private static final int KEY_SIZE=256;
//公钥
private static final String PUBLIC_KEY="ElGamalPublicKey";
//私钥
private static final String PRIVATE_KEY="ElGamalPrivateKey";
/**
*用私钥解密
*@param data待解密数据
*@param key私钥
*@return byte[]解密数据
*@throws Exception
*/
public static byte[]decryptByPrivateKey(byte[]data, byte[]key)throws Exception{
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//私钥材料转换
PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(key);
//实例化密钥工厂
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//生成私钥
Key privateKey=keyFactory.generatePrivate(pkcs8KeySpec);
//对数据解密
Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
*用公钥加密
*@param data待加密数据
*@param key公钥
*@return byte[]加密数据
*@throws Exception
*/
public static byte[]encryptByPublicKey(byte[]data, byte[]key)throws Exception{
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//公钥材料转换
X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
//实例化密钥工厂
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//生成公钥
Key publicKey=keyFactory.generatePublic(x509KeySpec);
//对数据加密
Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
*生成密钥
*@return Map密钥Map
*@throws Exception
*/
public static Map<String, Object>initKey()throws Exception{
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//实例化算法参数生成器
AlgorithmParameterGenerator apg=AlgorithmParameterGenerator.getInstance
(KEY_ALGORITHM);
//初始化算法参数生成器
apg.init(KEY_SIZE);
//生成算法参数
AlgorithmParameters params=apg.generateParameters();
//构建参数材料
DHParameterSpec elParams=(DHParameterSpec)params.getParameterSpec
(DHParameterSpec.class);
//实例化密钥对生成器
KeyPairGenerator kpg=KeyPairGenerator.getInstance(KEY_ALGORITHM);
//初始化密钥对生成器
kpg.initialize(elParams, new SecureRandom());
//生成密钥对
KeyPair keys=kpg.genKeyPair();
//取得密钥
PublicKey publicKey=keys.getPublic();
PrivateKey privateKey=keys.getPrivate();
//封装密钥
Map<String, Object>map=new HashMap<String, Object>(2);
map.put(PUBLIC_KEY, publicKey);
map.put(PRIVATE_KEY, privateKey);
return map;
}
/**
*取得私钥
*@param keyMap密钥Map
*@return byte[]私钥
*@throws Exception
*/
public static byte[]getPrivateKey(Map<String, Object>keyMap)throws Exception{
Key key=(Key)keyMap.get(PRIVATE_KEY);
return key.getEncoded();
}
/**
*取得公钥
*@param keyMap
*@return
*@throws Exception
*/
public static byte[]getPublicKey(Map<String, Object>keyMap)throws Exception{
Key key=(Key)keyMap.get(PUBLIC_KEY);
return key.getEncoded();
}
}
ElGamal算法的测试用例与RSA算法测试用例较为相近。不同的是,ElGamal算法实现仅有“公钥加密,私钥解密”的部分。测试用例如代码清单8-13所示。
代码清单8-13 ElGamal算法实现测试用例
import static org.junit.Assert.*;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.junit.Before;
import org.junit.Test;
/**
*ElGamal校验
*@author梁栋
*@version 1.0
*/
public class ElGamalCoderTest{
//公钥
private byte[]publicKey;
//私钥
private byte[]privateKey;
/**
*初始化密钥
*@throws Exception
*/
@Before
public void initKey()throws Exception{
Map<String, Object>keyMap=ElGamalCoder.initKey();
publicKey=ElGamalCoder.getPublicKey(keyMap);
privateKey=ElGamalCoder.getPrivateKey(keyMap);
System.err.println("公钥:\n"+Base64.encodeBase64String(publicKey));
System.err.println("私钥:\n"+Base64.encodeBase64String(privateKey));
}
/**
*校验
*@throws Exception
*/
@Test
public void test()throws Exception{
String inputStr="ElGamal加密";
byte[]data=inputStr.getBytes();
System.err.println("原文:\n"+inputStr);
byte[]encodedData=ElGamalCoder.encryptByPublicKey(data, publicKey);
System.err.println("加密后:\n"+Base64.encodeBase64String(encodedData));
byte[]decodedData=ElGamalCoder.decryptByPrivateKey(encodedData, privateKey);
String outputStr=new String(decodedData);
System.err.println("解密后:\n"+outputStr);
assertEquals(inputStr, outputStr);
}
}
在控制台中的输出信息中,我们可以得到相应的公钥和私钥,如下代码所示:
公钥:
MHcwUAYGKw4HAgEBMEYCIQCutlvZWBGgITJngn6hyMJ/VC/vt7K47W2p7QZdk+xpDwIhAKr3JJo1
jqbZp0YJSeBceSDLL7fJOUATmOzEyXhv0kRcAyMAAiA6HMzcFJSyF78uBXzemyHNFbXOFF0plX15
17p31YQqjQ==
私钥:
MHkCAQAwUAYGKw4HAgEBMEYCIQCutlvZWBGgITJngn6hyMJ/VC/vt7K47W2p7QZdk+xpDwIhAKr3
JJo1jqbZp0YJSeBceSDLL7fJOUATmOzEyXhv0kRcBCICIBecbEByJs28q7NH69zA2xDsjYbx9ihc
IZSZzKO8z/Dn
仔细观察,我们发现公钥和私钥的长度几乎是一致的。
观察控制台的输出信息,加密/解密信息如下代码所示:
原文:
ElGamal加密
加密后:
T92lluoBzFrAkly8I6b9PX9MuuGTiUAcGmn4Zw+iNYozA1BtX/RkhLTtPzDobJQKLAUV3fLN7Jeq
GZsgXC8gOA==
解密后:
ElGamal加密
ElGamal算法公钥和私钥长度几乎一致,基于Bouncy Castle加密组件的ElGamal算法实现仅遵循“公钥加密,私钥解密”的简单原则。