ElGamal算法进行加密和解密的基本原理及实现
1、准备步骤
1)取大素数 p 和 g(g < p,g 最好是 p 的素根)
注解:若 g 是素数 p 的一个素根,则 g mod p, g^2 mod p , …, g^p-1 mod p 是 1 到 p - 1 的排列
2)随机选取一整数 x (2 <= x <= (p - 2),(p,g,x) 是私钥)
3)计算 y = g^x (mod p) ( (p,g,y) 是公钥)
2、加密过程
1)随机选取一整数 k (2 <= k <= (p - 2) 且 k 与 (p - 1) 互素)
2)计算 a = g^k mod p,b = m*y^k mod p(m 为要加密的明文)
3)密文 C = (a, b)
3、解密过程
1)m = b * a^(-x) mod p
注解:b * a^(-x) mod p Ξ m * y^k * g^(-xk) Ξ m * g^(xk) * g^(-xk) Ξ m
加密及解密的实现(Java):
import java.util.ArrayList; public class Main { static ArrayList<Integer> suArr = new ArrayList<>(); public static void main(String[] args) { int max = 8096, p, g, x, y, k, a, b, buffer_data; char[] m = "abc".toCharArray(); // 加密字符串"abc" ArrayList<Integer> C = new ArrayList<>(); // 加密后的密文 int size1; suArr.add(2); // 随机取一个小于2048的素数g for (int i = 3; i <= 2048; i++) { if (isSuShu(i)) suArr.add(i); } size1 = suArr.size(); g = getRanNum(size1); // 随机取一个大素数p for (int i = 2049; i <= max; i++) { if (isSuShu(i)) suArr.add(i); } p = getRanNum(suArr.size() - size1, size1); // x的范围是[2,p-2] x = (int)(Math.random() * (p-3))+2; // k的范围是[2,p-2]且k与p-1互素 k = (int)(Math.random() * (p-3))+2; while (isHuZhi(k, p-1) != 1) { k = (int)(Math.random() * (p-3))+2; } // y = g^x mod p y = myPow(g, x, p); // a = g^k mod p a = myPow(g, k, p); C.add(a); // 特殊数据test // a = 1434; // g=1117; // k=2403; // p=6101; // x=714; // y=2271; // 加密过程,即计算b = m*y^k mod p (m是明文) for (char c : m) { C.add((int)c*myPow(y, k, p) % p); } buffer_data = myPow(a, x, p); buffer_data = exGcd(buffer_data, p)[0]; // 求(a^x)^(-1) mod p等价于求a^(-x) mod p if (buffer_data < 0) buffer_data += p; // 将解密后的明文输出 for (int i = 1; i < C.size(); i++) { System.out.print((char)(C.get(i) * buffer_data % p)); } } // 判断一个数是否为素数 public static boolean isSuShu(int num) { int max = (int) Math.sqrt(num); for (int i = 2; i <= max; i++) { if (num % i == 0) return false; } return true; } // 在素数数组中随机取一个数 public static int getRanNum(int size) { return suArr.get((int) (Math.random() * (size))); } // 在素数数组中的(left, arr.size())之间随机取一个数 public static int getRanNum(int size, int left) { return suArr.get((int) (Math.random() * (size)) + left); } // 判断两个数是否互质 public static int isHuZhi(int a, int b) { return b == 0 ? a : isHuZhi(b, a % b); } public static int myPow(int a, int b, int m) { int res = 1; a %= m; while (b != 0) { if ((b & 1) == 1) res = (res * a) % m; a = (a * a) % m; b >>= 1; } return res; } public static int getSuGen(int p) { boolean isSuGen; for (int g : suArr) { isSuGen = true; for (int i = 1; i < p; i++) { if (myPow(g, i, p) != i) isSuGen = false; } if (isSuGen) return g; } return 2; // 如果在素数数组中找不到p的素根,则返回一个默认值 } // 扩展欧几里得算法求a模b的逆元 public static int[] exGcd(int a, int b) { if (b == 0) { int[] arr = new int[]{1, 0}; return arr; } else { int[] arr = exGcd(b, a % b); int x = arr[0]; arr[0] = arr[1]; arr[1] = x - (a / b) * arr[1]; return arr; } } } /* * 参考: * 素根的定义:a是素数p 的一个素根,如果a mod p, a^2 mod p , …, a^p-1 mod p 是1到p-1的排列,称a是P的一个素根 * 加密时x和k的选取:https://blog.csdn.net/qq_34490018/article/details/79758620 */