看此片之前,请先看上一篇
package com.my.file;
import java.util.Arrays;
import java.util.Random;
/**
* 应用于RSA公钥密码,此程序存在一个问题,如果ORDER取值过大,就会出现无法解密
*
* @author yan
*
*/
public class Test1
{
// 随机数的数量级
private static final int ORDER = 300;
// 选择的随机数的最小值
private static final int MIN = 40;
public static void main(String[] args)
{
int[] k = getKey();
System.out.println("e:" + k[0]);
System.out.println("n:" + k[1]);
String str = "hello world";
int arr[] = stringToArrOfInt(str);
long arr1[] = encryption(arr, k[0], k[1]);
System.out.println(Arrays.toString(arr1));
String str1 = decryption(arr1, k[2], k[1]);
System.out.println(str1);
}
/**
* 整数转为二进制
*
* @param m整数m
* @return 字节数组
*/
static byte[] getByte(int m)
{
String sb = "";
while (m > 0)
{
sb = (m % 2) + sb;
m = m / 2;
}
return sb.getBytes();
}
/**
* 平方-乘法计算指数模运算 a^m % n
*
* @param a底数
* @param m指数
* @param n被mod数
* @return
*/
static long Square_and_Mutiply(long a, int m, int n)
{
long d = 1;
// 把m转化为二进制数
byte[] bm = getByte(m);
for (int i = 0; i < bm.length; i++)
{
d = (d * d) % n;
// 二进制1等于asciI码的49
if (bm[i] == 49)
{
d = (d * a) % n;
}
}
return d;
}
/**
* 随机选择一个奇数
*/
static int getRandom()
{
int x = 3;
Random rd = new Random();
do
{
x = rd.nextInt(ORDER);
} while (x < MIN || x % 2 == 0);
return x;
}
/**
* 验证一个数是否为素数,将n-1改写为2^k * m的形式,其中m是奇数,在{2,...,n-1}中随机选取一个整数a;
*
* @param n
* @return 如果是素数返回true,否则返回false
*/
static boolean isPrime(int n)
{
// n-1 用2的幂表示
int[] arr = intTOIndex(n - 1);
int k = arr[0];
int m = arr[1];
// 在{2,...,n-1}随机选择一个整数a
Random r = new Random();
int a = 0;
do
{
a = r.nextInt(n - 1);
} while (a < 2);
// b=a^m%n
long b = Square_and_Mutiply(a, m, n);
if (b == 1)
{
return true;
}
for (int i = 0; i < k; i++)
{
if (b == (n - 1))
{
return true;
} else
{
b = (b * b) % n;
}
}
return false;
}
/**
* 将一个数改为2^k * m的形式,其中m是奇数
*
* @param n
* @return arr[0]=k,arr[1]=m
*/
static int[] intTOIndex(int n)
{
int[] arr = new int[2];
int k = 0;
int x;
// 当n为奇数是停止循环
do
{
k++;
// n右移1位
n >>= 1;
x = n & 1;
} while (x == 0);
arr[0] = k;
arr[1] = n;
return arr;
}
/**
* 获取一个随机数为并且检查其为素数
*
* @return
*/
static int getPrime()
{
int x = 0;
boolean flag = false;
// while (x % 2 == 0 || !isPrime(x))
// {
// x = getRandom();
// }
do
{
flag = true;
// 取得随机数
x = getRandom();
// 经5次测试
for (int i = 0; i < 10; i++)
{
if (!isPrime(x))
{
flag = false;
}
}
} while (!flag);
System.out.println(x + ": 是随机数");
return x;
}
/**
* 获取公钥
*
* @author yan
* @return 公钥e和n;
*/
static int[] getKey()
{
int[] arr = new int[3];
// 随机获取两个大素数
int p, q;
do
{
p = getPrime();
q = getPrime();
} while (p == q);
// 计算两数差1的积
int n = p * q;
int f = (p - 1) * (q - 1);
// 生成公钥e和n保存在arr中
int e = getE(f);
int d = getPrivateKey(e, f);
arr[0] = e;
arr[1] = n;
arr[2] = d;
return arr;
}
/**
* 选择与f互质的一个数
*/
static int getE(int f)
{
boolean flag;
int e = 0;
Random r = new Random();
do
{
flag = true;
// 1 < e < f
do
{
e = r.nextInt(f);
} while (e < 2 || e >= f);
// 如果e能被f整除,则重新选择e
if (f % e == 0)
{
flag = false;
} else
// 如果e和f有除1以外的公约数,则重新选择e
{
int n = e / 2;
for (int i = 2; i < n; i++)
{
if (e % i == 0 && f % i == 0)
{
flag = false;
}
}
}
} while (!flag);
return e;
}
/**
* 根据公钥产生私钥,d * e % n = 1
*
* @param e
* @param n
* @return d
*/
static int getPrivateKey(int e, int n)
{
int d = 2;
boolean flag = false;
do
{
if ((d * e) % n == 1)
flag = true;
else
d++;
} while (!flag);
return d;
}
/**
* 加密
*
* @param ming
* @param e
* @param n
* @return
*/
static long[] encryption(int[] ming, int e, int n)
{
long[] arr = new long[ming.length];
for (int i = 0; i < arr.length; i++)
{
arr[i] = Square_and_Mutiply(ming[i], e, n);
}
return arr;
}
/**
* 解密
*
* @param mi
* @param d
* @param n
* @return
*/
static String decryption(long[] mi, int d, int n)
{
String str = "";
long[] arr = new long[mi.length];
for (int i = 0; i < arr.length; i++)
{
arr[i] = Square_and_Mutiply(mi[i], d, n);
}
str = IntToSting(arr);
return str;
}
/**
* 字符串转为int值
*
* @param str
* @return
*/
static int[] stringToArrOfInt(String str)
{
int[] arr = new int[str.length()];
for (int i = 0; i < arr.length; i++)
{
arr[i] = (int) str.charAt(i);
}
return arr;
}
/**
* int 值转为Sting
*
* @param arr
* @return
*/
static String IntToSting(long arr[])
{
String str = "";
for (int i = 0; i < arr.length; i++)
{
str += (char) arr[i];
}
return str;
}
}