ElGamal算法,是一种较为常见的加密算法,它是基于1985年提出的公钥密码体制和椭圆曲线加密体系。既能用于数据加密也能用于数字签名,其安全性依赖于计算有限域上离散对数这一难题。在加密过程中,生成的密文长度是明文的两倍,且每次加密后都会在密文中生成一个随机数K,在密码中主要应用离散对数问题的几个性质:求解离散对数(可能)是困难的,而其逆运算指数运算可以应用平方-乘的方法有效地计算。也就是说,在适当的群G中,指数函数是单向函数。
密钥生成
- 随机选择一个大素数p,且要求p-1有大素数因子。再选择一个模p的本原元α。将p和α公开。
- sk = d: 随机选择一个整数d作为密钥,2≤d≤p-2 。
- pk = (p, α, y): 计算y=α^d mod p,y为公钥。
加密 : 对M加密
- 随机地选取整数k,2≤k≤p-2
- U=y^k mod p
- C1=α^k mod p
- C2=UM mod p
- 密文为(C1,C2)
解密
- V=C1^d
- M=C2/V mod p=C2V^-1 mod p
加解密过程实现
import java.math.BigInteger;
import java.util.Random;
public class ElGamal {
public static void main(String[] args) {
}
/*
y=α^x(mod p),1≤x≤p-1
x=logαy,1≤y≤p-1
*/
public BigInteger p, alpha, y;
private BigInteger d; //private key
public ElGamal() {
do {
p = BigInteger.probablePrime(100, new Random());
} while (p.subtract(BigInteger.ONE).divide(new BigInteger("2")).isProbablePrime(100));
do {
alpha = new BigInteger(100, new Random());
} while (! isOrigin(alpha, p));
do {
d = new BigInteger(100, new Random());
} while (d.compareTo(BigInteger.ONE) != 1 || d.compareTo(p.subtract(BigInteger.ONE)) != -1);
y = alpha.modPow(d, p);
}
public ElGamal(BigInteger p, BigInteger alpha, BigInteger d) {
this.p = p;
this.alpha = alpha;
this.d = d;
y = alpha.modPow(d, p);
}
/**
* 加密
* @param M
* @return
*/
BigInteger[] encrypt(BigInteger M) {
BigInteger[] C = new BigInteger[2];
BigInteger k, U;
do {
do {
k = new BigInteger(100, new Random());
} while (k.compareTo(BigInteger.ONE) != 1 || k.compareTo(p.subtract(BigInteger.ONE)) != -1);
U = y.modPow(k, p);
} while (U.intValue() != 1);
C[0] = alpha.modPow(k, p);
C[1] = U.multiply(M).mod(p);
return C;
}
/**
* 加密
* @param M
* @param k
* @return
*/
BigInteger[] encrypt(BigInteger M, BigInteger k) {
BigInteger[] C = new BigInteger[2];
BigInteger U = y.modPow(k, p);
C[0] = alpha.modPow(k, p);
C[1] = U.multiply(M).mod(p);
return C;
}
/**
* 解密
* @param C
* @return
*/
BigInteger decrypt(BigInteger[] C) {
BigInteger V = C[0].modPow(d, p);
BigInteger M = C[1].multiply(V.modPow(new BigInteger("-1"), p)).mod(p);
return M;
}
/**
* 判断a是否为模m的原根,其中m为素数
* @param a
* @param m
* @return
*/
static boolean isOrigin(BigInteger a, BigInteger m) {
if (a.gcd(m).intValue() != 1) return false;
BigInteger i = new BigInteger("2");
while (i.compareTo(m.subtract(BigInteger.ONE)) == -1) {
if (m.mod(i).intValue() == 0) {
if (a.modPow(i, m).intValue() == 1)
return false;
while (m.mod(i).intValue() == 0)
m = m.divide(i);
}
i = i.add(BigInteger.ONE);
}
return true;
}
public BigInteger getD() {
return d;
}
}
测试代码
import java.math.BigInteger;
public class TestElGamal {
public static void main(String[] args) {
//BigInteger p=BigInteger.valueOf(2579L);
System.out.println("initial...");
BigInteger p=new BigInteger("2579");
BigInteger alpha=new BigInteger("2");
BigInteger d=new BigInteger("765");//sk
ElGamal elGamalDemo=new ElGamal(p,alpha,d);
System.out.println("System Parameter...");
System.out.println("p="+elGamalDemo.p);
System.out.println("alpha="+elGamalDemo.alpha);
System.out.println("d="+elGamalDemo.getD());
System.out.println("y="+elGamalDemo.y);
BigInteger M=new BigInteger("2023");
BigInteger k=new BigInteger("853");
System.out.println("M="+M);
System.out.println("Encrypt...");
BigInteger[] C=elGamalDemo.encrypt(M,k);
System.out.print("After encryption : ");
System.out.println(C[0]+" "+C[1]);
BigInteger newM=elGamalDemo.decrypt(C);
System.out.println("Decrypt...");
System.out.print("After decryption : ");
System.out.println(newM);
}
}