教学服务系统

 找回密码
 立即注册
搜索
查看: 628|回复: 3

信息计算2019级2班16号吴盛盛

[复制链接]

8

主题

17

帖子

134

积分

注册会员

Rank: 2

积分
134
发表于 2022-4-22 15:23:47 | 显示全部楼层 |阅读模式
4月22日

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

8

主题

17

帖子

134

积分

注册会员

Rank: 2

积分
134
 楼主| 发表于 2022-4-29 20:00:04 | 显示全部楼层
4月29日

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

8

主题

17

帖子

134

积分

注册会员

Rank: 2

积分
134
 楼主| 发表于 2022-5-27 18:56:08 | 显示全部楼层
RSA算法的具体描述如下:
(1)任意选取两个不同的大素数p和q计算乘积n=pq,φ(n)=(p-1)(q-1);
(2)任意选取一个大整数e,满足gcd(e, φ(n))=1且1<e<φ(n),e用做加密钥;
(3)确定的解密钥d,满足(de)modφ(n)=1,即de=kφ(n)+1,k>=1且为整数;
(4)公开整数n和e,秘密保存d;
(5)将明文m(m<n,是一个整数)加密成密文c,加密算法为c=E(m)=memodn;
(6)将密文c解密为明文m,解密算法为m=D(c)=cdmodn。 根据如上所示的RSA算法的基本流程,结合本实例来说明一下程序结构。公钥e直接使用通用的65537,在generateKey函数中可使用文件读入或随机的方式产生p、q,随机产生的方式会利用到函数generateNBitRandomPrime和isPrime产生指定位的素数,然后利用extdGcd函数计算出私钥d。接着在encryption加密函数中会根据m<n的原则进行分组逐组加密,利用expMod进行快速幂模运算,解密函数decryption中同样逐组利用expMod函数进行幂模运算。
  1. import java.io.BufferedReader;
  2. import java.io.FileNotFoundException;
  3. import java.io.FileReader;
  4. import java.io.IOException;
  5. import java.io.UnsupportedEncodingException;
  6. import java.math.BigInteger;
  7. import java.util.Random;

  8. /*** RSA算法实现。*/
  9. public class RSA {

  10.         private BigInteger n;// = p * q,两个大质数的乘积
  11.         private BigInteger e;// 公钥指数
  12.         private BigInteger d;// 私钥指数
  13.         private final int PQMINLENGTH = 1024;// p、q最小的长度(比特数)

  14.         /**
  15.          * 根据传入参数产生密钥(公钥、私钥)。
  16.          */
  17.         public RSA(BigInteger e, int generateKeyFlag, int pqLength) throws RSA.pqException {
  18.                 this.e = e;
  19.                 generateKey(generateKeyFlag, pqLength);// 产生密钥
  20.         }

  21.         public static void main(String[] args) throws RSA.pqException, UnsupportedEncodingException {
  22.                 int generateKeyFlag = 1;// 大质数p、q的产生方式,0:文件读入;1:随机产生
  23.                 int pqLength = 1024;// p、q长度(比特数)
  24.                 String e = "65537";// 公钥指数
  25.                 String originalText = "信息计算";// 原文
  26.                 System.out.println("加密前:" + originalText);
  27.                 RSA rsa = new RSA(new BigInteger(e), generateKeyFlag, pqLength);
  28.                 BigInteger[] c = rsa.encryption(originalText);// 加密
  29.                 System.out.print("加密后:");
  30.                 for (int i = 0; i < c.length; i++) {
  31.                         System.out.println(c[i]);
  32.                 }
  33.                 System.out.println("解密后:" + rsa.decryption(c));// 解密
  34.         }

  35.         /**
  36.          * 自定义异常内部类,用于输出由于大素数p、q不符合要求所产生的异常。
  37.          */
  38.         private class pqException extends Exception {
  39.                 private static final long serialVersionUID = -7777566816579144864L;

  40.                 public pqException(String message) {
  41.                         super(message);
  42.                 }
  43.         }

  44.         /**
  45.          * 密钥产生。
  46.          */
  47.         private void generateKey(int generateKeyFlag, int pqLength) throws RSA.pqException {
  48.                 BigInteger p = BigInteger.ZERO;// 两个大素数
  49.                 BigInteger q = BigInteger.ZERO;
  50.                 BigInteger φn;// = (p-1)(q-1)

  51.                 // 随机产生
  52.                         if (pqLength < PQMINLENGTH) {
  53.                                 throw new pqException("p、q长度小于" + PQMINLENGTH + ",请重新选择更长的质数!");
  54.                         }
  55.                         p = RSA.generateNBitRandomPrime(pqLength);
  56.                         q = RSA.generateNBitRandomPrime(pqLength);
  57.                

  58.                 n = p.multiply(q);
  59.                 φn = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
  60.                 d = RSA.extdGcd(e, φn)[1];// 利用扩展欧几里得算法求私钥d
  61.                 if (d.compareTo(BigInteger.ZERO) != 1) {// 私钥不可以小于0
  62.                         d = d.add(φn);
  63.                 }
  64.                 System.out.println("随机产生的两个大素数p,q");
  65.                 System.out.println("p="+p);
  66.                 System.out.println("q="+q);
  67.         }

  68.         /**
  69.          * RSA加密。
  70.          */
  71.         private BigInteger[] encryption(String plainText) throws UnsupportedEncodingException {
  72.                 String textNum = "";// 明文数字字符串表示形式
  73.                 BigInteger m = BigInteger.ZERO;// 明文数字表示形式
  74.                 byte[] textByte = plainText.getBytes("UTF-8");
  75.                 for (int i = 0; i < textByte.length; i++) {// 每个字节用3位数的整数表示,不够则在前面补0
  76.                         int bn = textByte[i] & 0xff;
  77.                         if (bn < 10) {
  78.                                 textNum += "00" + bn;
  79.                         } else if (bn < 100) {
  80.                                 textNum += "0" + bn;
  81.                         } else {
  82.                                 textNum += bn;
  83.                         }
  84.                 }
  85.                 m = new BigInteger(textNum);

  86.                 BigInteger[] mArray = null;// 明文分组结果
  87.                 if (m.compareTo(n) == -1) {// m < n,可直接加密
  88.                         mArray = new BigInteger[1];
  89.                         mArray[0] = m;
  90.                 } else {
  91.                         int groupLength = n.toString().length() - 1;// 每组明文长度
  92.                         int mStringLength = m.toString().length();// 明文转化为字符串的长度
  93.                         while (groupLength % 3 != 0) {// 由于前面每个字节用3位整数表示,因此每组的长度必须为3的整数,避免恢复时错误
  94.                                 groupLength--;
  95.                         }
  96.                         if (mStringLength % groupLength != 0) {// 如果最后一组的长度不足
  97.                                 mArray = new BigInteger[mStringLength / groupLength + 1];
  98.                         } else {
  99.                                 mArray = new BigInteger[mStringLength / groupLength];
  100.                         }

  101.                         String tmp;
  102.                         for (int i = 0; i < mArray.length; i++) {
  103.                                 tmp = "";
  104.                                 if (i != mArray.length - 1) {// 根据每组长度进行分割分组保存
  105.                                         tmp = textNum.substring(groupLength * i, groupLength * i + groupLength);
  106.                                 } else {
  107.                                         tmp = textNum.substring(groupLength * i);
  108.                                 }
  109.                                 mArray[i] = new BigInteger(tmp);
  110.                         }
  111.                 }

  112.                 for (int i = 0; i < mArray.length; i++) {// 逐组加密并返回
  113.                         mArray[i] = expMod(mArray[i], e, n);
  114.                 }
  115.                 return mArray;
  116.         }

  117.         /**
  118.          * RSA解密。
  119.          */
  120.         private String decryption(BigInteger[] c) {
  121.                 String cPadding = "";
  122.                 String mToString = "";
  123.                 int mToStringLengthMod = 0;
  124.                 BigInteger m = BigInteger.ZERO;
  125.                 for (int i = 0; i < c.length; i++) {// 逐组解密
  126.                         m = RSA.expMod(c[i], d, n);
  127.                         mToString = m.toString();
  128.                         mToStringLengthMod = m.toString().length() % 3;
  129.                         if (mToStringLengthMod != 0) {// 由于加密时String转BigInter时前者前面的0并不会计入,所以需要确认并补全
  130.                                 for (int j = 0; j < 3 - mToStringLengthMod; j++) {
  131.                                         mToString = "0" + mToString;
  132.                                 }
  133.                         }
  134.                         cPadding += mToString;
  135.                 }

  136.                 int byteNum = cPadding.length() / 3;// 明文总字节数
  137.                 byte[] result = new byte[byteNum];
  138.                 for (int i = 0; i < byteNum; i++) {// 每三位数转化为byte型并返回该byte数组所表达的字符串
  139.                         result[i] = (byte) (Integer.parseInt(cPadding.substring(i * 3, i * 3 + 3)));
  140.                 }
  141.                 return new String(result);
  142.         }

  143.         /**         利用扩展欧几里得算法求出私钥d,使得de = kφ(n)+1,k为整数。*/
  144.         private static BigInteger[] extdGcd(BigInteger e, BigInteger φn) {
  145.                 BigInteger[] gdk = new BigInteger[3];

  146.                 if (φn.compareTo(BigInteger.ZERO) == 0) {
  147.                         gdk[0] = e;
  148.                         gdk[1] = BigInteger.ONE;
  149.                         gdk[2] = BigInteger.ZERO;
  150.                         return gdk;
  151.                 } else {
  152.                         gdk = extdGcd(φn, e.remainder(φn));
  153.                         BigInteger tmp_k = gdk[2];
  154.                         gdk[2] = gdk[1].subtract(e.divide(φn).multiply(gdk[2]));
  155.                         gdk[1] = tmp_k;
  156.                         return gdk;
  157.                 }
  158.         }

  159.         /*** 利用米勒·罗宾算法判断一个数是否是质数。 */
  160.         private static boolean isPrime(BigInteger p) {
  161.                 if (p.compareTo(BigInteger.TWO) == -1) {// 小于2直接返回false
  162.                         return false;
  163.                 }
  164.                 if ((p.compareTo(BigInteger.TWO) != 0) && (p.remainder(BigInteger.TWO).compareTo(BigInteger.ZERO) == 0)) {// 不等于2且是偶数直接返回false
  165.                         return false;
  166.                 }

  167.                 BigInteger p_1 = p.subtract(BigInteger.ONE);
  168.                 BigInteger m = p_1;// 找到q和m使得p = 1 + 2^q * m
  169.                 int q = m.getLowestSetBit();// 二进制下从右往左返回第一次出现1的索引
  170.                 m = m.shiftRight(q);

  171.                 for (int i = 0; i < 5; i++) {// 判断的轮数,精度、轮数和时间三者之间成正比关系
  172.                         BigInteger b;
  173.                         do {// 在区间1~p上生成均匀随机数
  174.                                 b = new BigInteger(String.valueOf(p.bitLength()));
  175.                         } while (b.compareTo(BigInteger.ONE) <= 0 || b.compareTo(p) >= 0);

  176.                         int j = 0;
  177.                         BigInteger z = RSA.expMod(b, m, p);
  178.                         while (!((j == 0 && z.equals(BigInteger.ONE)) || z.equals(p_1))) {
  179.                                 if ((j > 0 && z.equals(BigInteger.ONE)) || ++j == q) {
  180.                                         return false;
  181.                                 }
  182.                                 z = RSA.expMod(z, BigInteger.TWO, p);
  183.                         }
  184.                 }

  185.                 return true;
  186.         }

  187.         /**
  188.          * 随机产生n比特的素数。最高位是1,从高位开始随机产生共n-1个0和1(0和1的比例是随机的,不是
  189.          * 平均),并将每位所得值相加最终形成一个n位数。然后判断该数是否是素数,是则返回,否则重新开始产生新的数直至该数为素数为止。
  190.          */
  191.         private static BigInteger generateNBitRandomPrime(int n) {
  192.                 BigInteger tmp = new BigInteger("2").pow(n - 1);// 最高位肯定是1
  193.                 BigInteger result = new BigInteger("2").pow(n - 1);
  194.                 Random random = new Random();
  195.                 int r1 = random.nextInt(101);// 产生0-100的整数,用于确定0和1的比例
  196.                 int r2;

  197.                 while (true) {// 循环产生数,直到该数为素数
  198.                         for (int i = n - 2; i >= 0; i--) {// 逐位产生表示数的0和1,并根据所在位计算结果相加起来
  199.                                 r2 = random.nextInt(101);
  200.                                 if (0 < r2 && r2 < r1) {// 产生的数为1
  201.                                         result = result.add(BigInteger.TWO.pow(i));
  202.                                 }
  203.                                 continue;
  204.                         }

  205.                         if (RSA.isPrime(result)) {// 素数判断
  206.                                 return result;
  207.                         }

  208.                         result = tmp;// 重新计算
  209.                 }
  210.         }

  211.         /*** 蒙哥马利快速幂模运算,返回base^exponent mod module的结果。*/
  212.         private static BigInteger expMod(BigInteger base, BigInteger exponent, BigInteger module) {
  213.                 BigInteger result = BigInteger.ONE;
  214.                 BigInteger tmp = base.mod(module);

  215.                 while (exponent.compareTo(BigInteger.ZERO) != 0) {
  216.                         if ((exponent.and(BigInteger.ONE).compareTo(BigInteger.ZERO)) != 0) {
  217.                                 result = result.multiply(tmp).mod(module);
  218.                         }
  219.                         tmp = tmp.multiply(tmp).mod(module);
  220.                         exponent = exponent.shiftRight(1);
  221.                 }

  222.                 return result;
  223.         }

  224. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

8

主题

17

帖子

134

积分

注册会员

Rank: 2

积分
134
 楼主| 发表于 2022-5-27 18:56:46 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

教学服务系统

GMT+8, 2025-4-30 08:06 , Processed in 0.014971 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表