ElGamal算法和ECC算法基于离散对数问题建立。与典型非对称加密算法RSA算法相比,ElGamal算法则被称为常用非对称加密算法。
ElGamal既可用于加密,又可用于数字签名,是除RSA算法外最具代表性的公钥加密算法之一。
ElGamal算法就有较好的安全性,被广发应用。著名的美国数字签名标准(Digital Signature Standard, DSS)就是采用ElGamal签名方案的一种变形——DSA(Digital Signature Algorithm)。
缺点:
ElGamal的密文会成倍扩张。
Java6中没有提供ElGamal算法, 但是Bouncy Castle中对ElGamal算法进行了实现。ElGamal算法在构建密钥时的操作流程几乎和RSA算法完全一致。所不同的是RSA中是Alice构建密钥, 而在ElGamal中,Bob成了密钥构建方。假设的消息模型如下:
Alice为消息发送方,Bob为消息接收方,双方在消息发送前已将ElGamal算法作为消息传递的加密算法。
1、2步骤为构建密钥流程
3、4、5为使用密钥进行加密消息交互
Bouncy Castle提供的ElGamal算法实现遵循 “公钥加密, 私钥解密”的加密/解密方式。
Bouncy Castle对ElGamal算法具体实现细节如下:
算法 | 密钥长度 | 密钥默认长度 | 工作模式 | 填充模式 | 备注 |
---|---|---|---|---|---|
ElGamal | 160~16384位(密钥长度为8的整数倍) | 1024 | ECB、NONE | NoPadding、PKCS1Padding、OAEPWithMD5AndMGF1Padding、OAEPWithSHA1AndMGF1Padding、OAEPWithSHA224AndMGF1Padding、OAEPWithSHA256AndMGF1Padding、OAEPWithSHA384AndMGF1Padding、OAEPWithSHA512AndMGF1Padding、ISO9796-1Padding | Bouncy Castle实现 |
package com.calvin.android.demo2.secrity;
import android.util.Log;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
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.Provider;
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;
/**
* Author:cl
* Email:[email protected]
* Date:20-10-20
*/
public class ElGamalCoder {
//非对称加密密钥算法
public static final String KEY_ALGORITHM = "ElGamal";
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 {
//取得私钥
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM );
//生成私钥
PrivateKey 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[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {
//取得私钥
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
//对数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 公钥解密
* @param data 待解密数据
* @param key 公钥
* @return byte[] 解密数据
* @throws Exception 异常
*/
public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {
//取得公钥
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成公钥
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
//对数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
/**
* 公钥加密
* @param data 待加密数据
* @param key 公钥
* @return byte[] 加密数据
* @throws Exception 异常
*/
public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
//取得公钥
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成公钥
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
//对数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
private static final String TAG = "ElGamalCoder";
public static Map<String, Object> initKey() throws Exception {
//实例化BC Provider, Android系统支持BC Provider, 这里将系统可能是旧的版本去掉,加入新版本的BC Provider
Provider bcProvider = new BouncyCastleProvider();
Security.removeProvider("BC");
Security.addProvider(bcProvider);
/**
Provider[] providers = Security.getProviders();
for (Provider provider: providers){
Log.d(TAG, "provider name = "+provider);
for (Map.Entry
AlgorithmParameterGenerator apg = AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM, bcProvider);
//初始化算法参数生成器
apg.init(KEY_SIZE);
//生成算法参数
AlgorithmParameters algorithmParameters = apg.generateParameters();
//构建参数材料
DHParameterSpec elParams = (DHParameterSpec)algorithmParameters.getParameterSpec(DHParameterSpec.class);
//实例化密钥对生成器
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
//初始化密钥对生辰其
keyPairGen.initialize(elParams,new SecureRandom());
//生成密钥对
KeyPair keyPair = keyPairGen.generateKeyPair();
//公钥
PublicKey publicKey = keyPair.getPublic();
//私钥
PrivateKey privateKey = keyPair.getPrivate();
//封装密钥
Map<String, Object> keyMap = new HashMap<>(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
public static byte[] getPublicKey(Map<String, Object> keyMap){
return ((Key)keyMap.get(PUBLIC_KEY)).getEncoded();
}
public static byte[] getPrivateKey(Map<String, Object> keyMap){
return ((Key)keyMap.get(PRIVATE_KEY)).getEncoded();
}
}
@Test
public void testElGamal() throws Exception {
Map<String, Object> keyMap = ElGamalCoder.initKey();
//公钥
byte[] elgamalPubKey = ElGamalCoder.getPublicKey(keyMap);
//私钥
byte[] elgamalpriKey = ElGamalCoder.getPrivateKey(keyMap);
System.out.println("公钥:\t"+ Base64.encodeToString(elgamalPubKey, Base64.DEFAULT));
System.out.println("私钥:\t"+ Base64.encodeToString(elgamalpriKey, Base64.DEFAULT));
String inputStr = "ElGamal加密";
byte[] data = inputStr.getBytes();
System.out.println("原文:\t"+ inputStr);
byte[] encodedData = ElGamalCoder.encryptByPublicKey(data, elgamalPubKey);
System.out.println("加密后:\t"+ Base64.encodeToString(encodedData,Base64.DEFAULT));
byte[] decodedData = ElGamalCoder.decryptByPrivateKey(encodedData, elgamalpriKey);
String outputStr = new String(decodedData);
System.out.println("解密后:\t"+ outputStr);
assertEquals(inputStr,outputStr);
}
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: 公钥: MHcwUAYGKw4HAgEBMEYCIQD/GaVs/HmUpVVOtSF8C0t/OcPNEHO83sjCdvdhkBM5fwIhAKkFaKSP
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: nrJIz2duJFVY+kEstf31SVuOlLmyt93MghofAyMAAiAKp+k1o2R5ZlBcUvOGwVPl4xtbNjNM6yHi
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: 4lD2+/1Omw==
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: 私钥: MHoCAQAwUAYGKw4HAgEBMEYCIQD/GaVs/HmUpVVOtSF8C0t/OcPNEHO83sjCdvdhkBM5fwIhAKkF
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: aKSPnrJIz2duJFVY+kEstf31SVuOlLmyt93MghofBCMCIQDQXbdvrqqfhkLAfMEGvsLtbawlxsg+
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: wydVKsyJKgZpyg==
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: 原文: ElGamal加密
2020-10-20 17:02:17.019 11052-11067/com.calvin.android.demo2 I/System.out: 加密后: Rx58tvdX4HHKSlAFjTAxRnB0UwZL3L2IVzeQ+KlG7MuBkNRn7hAQ4KKLi/tgTmYDmDsia7VVDEbU
2020-10-20 17:02:17.019 11052-11067/com.calvin.android.demo2 I/System.out: pLGxfKSoHw==
2020-10-20 17:02:17.021 11052-11067/com.calvin.android.demo2 I/System.out: 解密后: ElGamal加密