RSA算法的实现原理
RSA公钥密码体制描述如下:(m为明文,c为密文)
- 选取两个大素数p,q。p和q保密
- 计算n=pq,r=(p-1)(q-1)。n公开,r保密
- 随机选取正整数1<e<r,满足gcd(e,r)=1.e是公开的加密密钥
- 计算d,满足de=1(mod r).d是保密的解密密钥
- 加密变换: c=m^e mod n
- 解密变换: m=c^d mod n
所以在实现RSA算法之前,首先要先做以下几件事:
- 实现素数的选择判断,以便于随机生成素数
- 实现模逆运算,以便求出某个元的逆元,因为ed互逆
- 实现快速模指运算
- 根据以上公式,实现RSA的加密与解密
实现素数的选择判断
检验素数的方法有很多,最简单的一个方法就是平方根检验,还有费马检测,素数的概率性检测算法等等。或者直接进行循环判断。详细的不多说,大家有兴趣的可以自行前去百度,这里说下费马检测的,具体请看代码:
/**
* 费马测试
* @param args
*/
public static boolean isPrimeByFeima(int n) {
boolean result=false;
int test = n/2;
Random random = new Random();
List<Integer>lists = new ArrayList<Integer>();
for(int i=0;i<test;i++) {
int j = random.nextInt(n);
int mod = 1;
for(int k=0;k<n;k++) {
mod = j%n *mod;
if(mod > n) {
mod = mod %n;
}
}
if(mod == j) {
lists.add(j);
}
}
if(lists.size() ==test) {
result = true;
System.out.println("该数是素数!");
}else {
result=false;
System.out.println("该数不是素数!");
}
return result;
}
我们可以获取一个随机数,然后用以上方法判断这个数是否是素数,是的话就返回,不是的话就继续生成。以此来生成两个随机素数。当然在,笔者具体代码里用的是更为难得一点方法,有兴趣的可以去看看,当然也可以用以上方法去生成素数。
模逆运算
这是用来求一个数的逆元,如果说ab=1,则我们可以说ab互逆,当然,这不是简单的直接让a= 1/b,而是应该用扩展欧几里得算法,去求得一个元的逆元,模逆则是 ab=1modn 好了用java如何实现呢?下面请看一段代码:
// 求逆元
public static int Inverse(int a, int b) { //返回的结果为moda后b的逆元
// System.out.println("a="+a);
// System.out.println("b="+b);
int[] m = { 1, 0, a };
int[] n = { 0, 1, b };
int[] temp = new int[3];
int q = 0; // 初始化
boolean flag = true;
while (flag) {
q = m[2] / n[2];
for (int i = 0; i < 3; i++) {
temp[i] = m[i] - q * n[i];
m[i] = n[i];
n[i] = temp[i];
}
if (n[2] == 1) {
if (n[1] < 0) {
n[1] = n[1] + a;
}
return n[1];
}
if (n[2] == 0) {
flag = false;
}
}
return 0;
}
用这个方法,可以求出一个元的逆元,当然,百度上还可以百度到其他方法,大家可以自行尝试。这里只给出一个最简单的方式
快速模指运算
模指运算就比较简单,但是大家要注意一点,不要直接把这个指乘出来再运算,而应该mod一个,乘一个。
//幂指运算
public static int calc2(int a,int b,int mod){
int result =1;
for(int i = 0;i<b;i++){
result = (i%mod) *result;
if(result > mod){
result = result%mod;
}
}
return result;
}
RSA加密
之后便是根据公式,进行加密操作就可以了。一步一步进行操作
/**
* Rsa 的加密算法
* @param M
* @return
*/
public int c_RSA(){
RSAUtil rsaUtil= new RSAUtil();
ModUtils modUtils = new ModUtils();
p = RSAUtil.getPrime();
q = RSAUtil.getPrime();
while(p==q){
q = RSAUtil.getPrime();
}
int n = (p-1)*(q-1);
Random rd = new Random();
e = rd.nextInt(n);
C= (int) modUtils.calc(M, e, p*q);
d = ModUtils.Inverse(n,e);
if(d==0){
return c_RSA();
}
return C;
}
在这个方法里面,求取d的时候有可能会导致d==0,这里存在一点小bug,不过概率很小,笔者测试过了100次大概会出现3次,所以为了以防万一,最后再做个判断,若是d=0,那么这组ed就舍弃。
结果
除此之外,笔者还做了一个 图形界面,方便大家操作。下面展示下操作结果
输入13进行加密
加密结果如下:
将这个密文进行解密