zoukankan      html  css  js  c++  java
  • 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;
    			}
    		}
    		
    	}
    	
    }
    

    运行结果

    加密

    解密

  • 相关阅读:
    一条语句批量插入多条数据
    VMware Workstation 15 Pro 永久激活密钥
    windows下java项目打包、启动批处理 .bat文件
    java简写名词解释
    windows查看所有进程:netstat -ano
    Java验证jwt token
    【转载】三种方法从 HTTPS 网站导出 SSL 证书链
    使用solr将CSV/XML/DB/JSON数据发布为Rest Service
    检验多个xsd的xml是否合法
    Eclipse 打包运行maven项目
  • 原文地址:https://www.cnblogs.com/Qi-Lin/p/12221751.html
Copyright © 2011-2022 走看看