Rabin简单加解密
算法描述
程序分为两个部分,一部分加密,一部分解密。
解密部分:先通过生成大素数算法生成公钥n和私钥p、q,然后运用广义欧几里得除法计算s,t使sp+tq=1,然后输入用公钥加密的密文c,然后计算同余式x^2=c(modn)的四个根(在求解时可以不用中国剩余定理,直接采用当p=q=3(mod4)时的定理,直接由s,t求解),然后用校验值判断出真正的解,得到明文。
加密部分:先将文本转换为整数,然后在转换后的值中加入校验值,然后利用获得的公钥计算c=m^2(modn)得到密文。
加密类中
1、 生成大素数直接采用java中自带的大数的类的函数BigInteger.probablePrime(n,rnd),rnd为随机数因子,n为生成的随机大素数的二进制的位数,设置n为100时的生成结果如下:
2、 运用广义欧几里得除法时,定义两个数组long s[]= {1,0,0};long t[]= {0,1,0}s[0]为s-2,s[1]为s-1,t同理;设置while循环,当r2!=0时进行循环运算,最后s,t的大小即为s[1]和t[1]。相关代码如下:
3、 解密过程中对于二次同余方程,当p=q=3(mod4)用如下解的公式,u=c[(p+1)/4](modp)。v=c(q+1)/4。x=(tqu+spv)(modn)。y=(tqu-spv)(modn)。四个解分别为x,y,n-x,n-y,将相关公式用程序式表示,程序如下:
4、 进行校验部分,因为会解出四个值,所以在进行加密时加入了校验值,解密时需要根据校验值找出四个解中真正的解,程序中采用在密文的二进制后加入额外的01字符串作为校验值,所以在解出四个解后,将其转化为二进制字符串,将其末尾的01字符串与校验值进行比较,最后将校验值删除,再将二进制字符串转换得到明文,此处校验值为010,程序如下:
解密类中
1、 将文本形式的明文进行编码,转换为整数,这里先将输入的字符串转换为char型数组,再转换为二进制数,再将二进制数转换为十进制整数,程序如下:
2、 添加校验值,为了能从四个解中找出唯一的解,需要在值后面加入校验值,这里先将明文转换为二进制字符串,再在字符串的末尾加入01的二进制校验值,程序中校验值为010,程序如下:
3、 最后由得到的公钥计算c=m^2(modn)得到密文c,程序如下:
另:由于所需计算的数字远远超出了java的int,long的变量类型,所以在程序的运算中运用了java的BigInteger类,可以用该类的方法计算大数的加减乘除等运算,相关方法如下:
BigInteger.add(b)); //大整数加法,b也为一个大数
BigInteger.subtract(b)); //大整数减法
BigInteger.multiply(b)); //大整数乘法
BigInteger.divide(b)); //大整数除法(取整)
BigInteger.remainder(b)); //大整数取模
BigInteger.pow(exponent)); //大整数a的exponent次幂
程序
加密
package rabin;
import java.math.BigInteger;
import java.util.Scanner;
public class Encrypt {
public static void main(String[] args) {
System.out.println("请输入 ");
Scanner in = new Scanner(System.in);
String str = in.next();
//将string转化为char数组,再转化为2进制字符串,再转换为整数
char[] strchar = str.toCharArray();
long binary=0;
for(int i=0;i<strchar.length;i++) {
binary=binary+Integer.parseInt((Integer.toBinaryString(strchar[i])),2);
}
System.out.println("明文为: "+binary);
//添加校验信息,这里设置为010
String strbinary=Long.toString(Integer.parseInt(Long.toBinaryString(binary)+"010",2));
binary=Long.valueOf(strbinary);
System.out.println("请输入公钥: ");
BigInteger n = in.nextBigInteger();
BigInteger m = new BigInteger(Long.toString(binary*binary));
BigInteger c = m.remainder(n);
System.out.println("加密结果为:"+c);
}
}
解密
package rabin;
import java.math.BigInteger;
import java.util.Random;
import java.util.Scanner;
public class Decrypt {
public static void main(String[] args) {
//生成大素数
Random rnd = new Random();
BigInteger p = BigInteger.probablePrime(20,rnd);//生成2进制为n位的大素数p,n可以设置,为了方便这里设置为20
BigInteger q = BigInteger.probablePrime(20,rnd);//生成2进制为n位的大素数q
BigInteger n = p.multiply(q);//私钥p,q相乘得到公钥n
System.out.println("公钥为: "+n+" 私钥为: "+p+"和"+q);
System.out.println("输入要解密的内容");
Scanner in = new Scanner(System.in);
BigInteger c = in.nextBigInteger();
//用广义欧几里得出发求s,t使s*p+t*q=1;
long s[]= {1,0,0};
long t[]= {0,1,0};
long r1=p.longValue();
long r2=q.longValue();
long tmp;
long i=r1/r2;
tmp=r2;
r2=r1%r2;
r1=tmp;
while(r2!=0) {
s[2]=s[0]-i*s[1];
t[2]=t[0]-i*t[1];
s[0]=s[1];
s[1]=s[2];
t[0]=t[1];
t[1]=t[2];
if(r2!=0)
i=r1/r2;
tmp=r2;
r2=r1%r2;
r1=tmp;
}
BigInteger S=BigInteger.valueOf(s[1]);
BigInteger T=BigInteger.valueOf(t[1]);
//开始解密
int P=(p.intValueExact()+1)/4;
int Q=(q.intValueExact()+1)/4;
BigInteger u=(c.pow(P)).remainder(p);
BigInteger v=(c.pow(Q)).remainder(q);
BigInteger x1 = ((T.multiply(q.multiply(u))).add(S.multiply(p.multiply(v)))).remainder(n);
BigInteger x2 = n.subtract(x1);
BigInteger y1 = ((T.multiply(q.multiply(u))).subtract(S.multiply(p.multiply(v)))).remainder(n);
BigInteger y2 = n.subtract(y1);
//用校验值对四个解密结果进行判断
String a= x1.toString(2);
String b= x2.toString(2);
String e= y1.toString(2);
String d= y2.toString(2);
String result[]= {a,b,e,d};
for(int j=0;j<result.length;j++) {
if(result[j].lastIndexOf("010",result[j].length()-3)==result[j].length()-3) {
result[j]=result[j].substring(0,result[j].length()-3);
System.out.println("解密得: "+Long.valueOf(result[j], 2));
break;
}
}
}
}
运行结果
加密
解密