RSA加密,java实现

看此片之前,请先看上一篇

 

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;
 }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值