[注:本文为本人本科期间实验成果,仅供参考,拷贝以及转载引起的后果自负!]
RSA大整数版本的JAVA实现
目前网络上大多数的RSA实现均为一般的整数,这里就涉及到一个大素数版本的时候,已经公钥如何求私钥的过程(这里指的是密钥产生期间)。普通的试探法无法满足需要,需要采用“扩展的欧几里德算法”才可以得到。还有一个难点,就是如何产生大素数。
RSA的具体算法这里就不再给出了。下面看下运行结果!
难点:
(1)如何随机产生一个随机的大整数,使得它是一个素数;
(2)在知道公钥e的前提下,如何求解私钥d(最初采用的是传统的策略,使得直接进入“死”循环,在有限的时间内,根本不可能求得解,通过网上寻找,知道可以通过扩展的欧几里德算法进行求解,并且顺利实现了扩展的欧几里德算法。)
附上JAVA代码。
1.node.java
public class Node { private double p;// 记录概率 private char alpha;// 记录对应的字母 public Node(double p, char alpha) { this.p = p; this.alpha = alpha; } public void setp(double p) { this.p = p; } public void setalpha(char a) { this.alpha = a; } public double getp() { return p; } public char getalpha() { return alpha; } }
import java.math.BigInteger; public class Prime { public boolean sushu(double n) { // 判断素数//////////////////////////////////////////////////////////////////////////////////// boolean isPrime = true; // 如果n大于2 继续判断 否则 isPrime的值不变 2素数 if (n > 2) { // 如果n是大于2的偶数 认定不是素数 修改变量值为false if (n % 2 == 0) { isPrime = false; } else { // 循环判断如果找到一个可以整除的数 则判定不是素数跳出循环 因为是判断奇数 因此 2 4 6 ...? // 不用考虑 循环递增2 即?3 5 7 ... for (int i = 3; i <= (int) Math.sqrt(n); i += 2) { if (n % i == 0) { isPrime = false; break; } } } } return isPrime; } private static final BigInteger ZERO = BigInteger.ZERO; private static final BigInteger ONE = BigInteger.ONE; private static final BigInteger TWO = new BigInteger("2"); private static final int ERR_VAL = 100; public BigInteger nextPrime(BigInteger start) { // 产生一个比给定大整数 start 大的素数,错误率低于 1/2 的 ERR_VAL 次方 if (isEven(start)) start = start.add(ONE); else start = start.add(TWO); if (start.isProbablePrime(ERR_VAL)) return (start); else // 采用递归方式(递归的层数会是个天文数字吗?) return (nextPrime(start)); } private static boolean isEven(BigInteger n) { // 测试一个大整数是否为偶数 return (n.mod(TWO).equals(ZERO)); } public BigInteger bigRandom(int numDigits) { // 产生一个随机大整数,各位上的数字都是随机产生的,首位不为 0 StringBuffer s = new StringBuffer(""); for (int i = 0; i < numDigits; i++) if (i == 0) s.append(randomDigit(false)); else s.append(randomDigit(true)); return (new BigInteger(s.toString())); } private StringBuffer randomDigit(boolean isZeroOK) { // 产生一个随机的数字(字符串形式的),isZeroOK 决定这个数字是否可以为 0 int index; if (isZeroOK) index = (int) Math.floor(Math.random() * 10); else index = 1 + (int) Math.floor(Math.random() * 9); return (digits[index]); } private static StringBuffer[] digits = { new StringBuffer("0"), new StringBuffer("1"), new StringBuffer("2"), new StringBuffer("3"), new StringBuffer("4"), new StringBuffer("5"), new StringBuffer("6"), new StringBuffer("7"), new StringBuffer("8"), new StringBuffer("9") }; public static void main(String[] args) { } }
import java.math.BigInteger; import java.util.ArrayList; import java.util.Scanner; public class RSA { static BigInteger x, y; public static boolean fun(BigInteger x, BigInteger y) { BigInteger t; while (!(y.equals(new BigInteger("0")))) { t = x; x = y; y = t.mod(y); } if (x.equals(new BigInteger("1"))) return false; else return true; } public static BigInteger siyue(BigInteger a, BigInteger b) { BigInteger temp; if (b.equals(new BigInteger("0"))) { x = new BigInteger("1"); y = new BigInteger("0"); return x; } siyue(b, a.mod(b)); temp = x; x = y; y = temp.subtract((a.divide(b).multiply(y))); return x; } public static double entropy(String mess) { ArrayList<Node> jieguo = new ArrayList<Node>(); jieguo.clear(); double num = mess.length(); for (int i = 0; i < num; i++) { boolean flag_exit = true; for (int j = 0; j < jieguo.size(); j++) { if (jieguo.get(j).getalpha() == mess.charAt(i)) { flag_exit = false; jieguo.get(j).setp(jieguo.get(j).getp() + 1 / num); } } if (flag_exit) jieguo.add(new Node(1 / num, mess.charAt(i))); } /** 计算熵 */ double entropy = 0; for (int i = 0; i < jieguo.size(); i++) { double p1 = jieguo.get(i).getp(); entropy += (-p1 * (Math.log(p1) / Math.log(2))); } return entropy; } public static void main(String[] args) { BigInteger p = null; BigInteger e, d, n, t, c; BigInteger q = null; for (int i = 0; i < 2; i++) { int numDigits; Prime pri = new Prime(); try { numDigits = Integer.parseInt("15"); } catch (Exception e1) { numDigits = 128; } BigInteger start = pri.bigRandom(numDigits); BigInteger big = pri.nextPrime(start); if (i == 0) p = big; else q = big; } Scanner input = new Scanner(System.in); n = p.multiply(q); t = p.subtract(new BigInteger("1")).multiply( q.subtract(new BigInteger("1"))); int numDigits; Prime pri = new Prime(); try { numDigits = Integer.parseInt("15"); } catch (Exception e1) { numDigits = 128; } BigInteger start = pri.bigRandom(numDigits); BigInteger big = pri.nextPrime(start); e = big; while (e.compareTo(t) == 1 || fun(e, t)) { System.out.println("e不合要求,请重新产生" + (e.compareTo(t) == 1) + fun(e, t)); pri = new Prime(); try { numDigits = Integer.parseInt("15"); } catch (Exception e1) { numDigits = 128; } start = pri.bigRandom(numDigits); big = pri.nextPrime(start); e = big; } // 求出私钥d d = siyue(e, t); System.out.println("由计算机随机产生2个素数p,q,分别如下:"); System.out.println(p); System.out.println(q); System.out.println("计算得到的n:"); System.out.println(n); System.out.println("计算得到的t:"); System.out.println(t); System.out.println("随机产生的公钥:"); System.out.println(e); System.out.println("由扩展的欧几里德算法求得私钥:"); System.out.println(d); while (true) { System.out.println("请输入明文:"); String mess = input.nextLine(); // BigInteger m = new BigInteger(mess.getBytes());// 把字串转成一个BigInteger对象 System.out.println("明文的大整数表示形式:" + m); /** 调用函数计算信息,统计信息 */ mess = m.toString(); System.out.println("计算得明文熵:" + entropy(mess)); // 修改第一位,+1 c = m.modPow(e, n);// JAVA中的方法 System.out.println("密文的大整数表示形式:" + c); System.out.println("计算得密文熵:" + entropy(c.toString())); System.out.println("密文的字符串表示形式:" + new String(c.toByteArray())); m = c.modPow(d, n); System.out.println("解密得到明文的大整数表示形式:" + c); String str = new String(m.toByteArray());// 把返回的结果还原成一个字串 System.out.println("解密得到明文为:" + str); } } }