教学服务系统

 找回密码
 立即注册
搜索
查看: 576|回复: 1

信息计算2019级1班17号刘帆杰

[复制链接]

9

主题

16

帖子

117

积分

注册会员

Rank: 2

积分
117
发表于 2022-5-2 23:07:37 | 显示全部楼层 |阅读模式
本帖最后由 刘帆杰 于 2022-5-2 23:08 编辑
  1. package com.密码算法;

  2. import java.io.UnsupportedEncodingException;
  3. import java.math.BigInteger;
  4. import java.util.Random;
  5. import java.util.Scanner;

  6. public class RSA {
  7.     private BigInteger n;// = p * q,两个大质数的乘积
  8.     private BigInteger e;// 公钥指数
  9.     private BigInteger d;// 私钥指数
  10.     private final int PQMINLENGTH = 1024;// p、q最小的长度(比特数)

  11.     public static void main(String[] args) throws RSA.pqException, UnsupportedEncodingException {
  12.         Scanner input = new Scanner(System.in);
  13.         int pqLength = 1024;// p、q长度(比特数)
  14.         String e = "65537";// 公钥指数
  15.         System.out.println("请输入要加密的内容:");
  16.         String originalText=input.nextLine();
  17.         RSA rsa = new RSA(new BigInteger(e), pqLength);
  18.         System.out.println("加密前:" + originalText);
  19.         BigInteger[] c = rsa.encryption(originalText);// 加密
  20.         System.out.print("加密后:");
  21.         for (int i = 0; i < c.length; i++) {
  22.             System.out.println(c[i]);
  23.         }
  24.         System.out.println("解密后:" + rsa.decryption(c));// 解密
  25.     }

  26.     private class pqException extends Exception {
  27.         private static final long serialVersionUID = -7777566816579144864L;

  28.         public pqException(String message) {
  29.             super(message);
  30.         }
  31.     }

  32.     public RSA(BigInteger e, int pqLength) throws RSA.pqException {
  33.         this.e = e;
  34.         generateKey(pqLength);// 产生密钥
  35.     }
  36.    

  37.     private void generateKey(int pqLength) throws RSA.pqException {
  38.         BigInteger p = BigInteger.ZERO;// 两个大素数
  39.         BigInteger q = BigInteger.ZERO;
  40.         BigInteger φn;// = (p-1)(q-1)

  41.         if (pqLength < PQMINLENGTH) {
  42.                 throw new pqException("p、q长度小于" + PQMINLENGTH + ",请重新选择更大的比特数!");
  43.             }
  44.             p = RSA.generateNBitRandomPrime(pqLength);
  45.             q = RSA.generateNBitRandomPrime(pqLength);

  46.         n = p.multiply(q);
  47.         System.out.println("随机产生两个素数p、q");
  48.         System.out.println("p:"+p);
  49.         System.out.println("q:"+q);
  50.         System.out.println("p、q乘积为n:"+n);
  51.         φn = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
  52.         d = RSA.extdGcd(e, φn)[1];// 利用扩展欧几里得算法求私钥d
  53.         if (d.compareTo(BigInteger.ZERO) != 1) {// 私钥不可以小于0
  54.             d = d.add(φn);
  55.         }
  56.         System.out.println("公钥为:"+e);
  57.         System.out.println("私钥为:"+d);
  58.     }


  59.     private BigInteger[] encryption(String plainText) throws UnsupportedEncodingException {
  60.         String textNum = "";// 明文数字字符串表示形式
  61.         BigInteger m = BigInteger.ZERO;// 明文数字表示形式
  62.         byte[] textByte = plainText.getBytes("UTF-8");
  63.         for (int i = 0; i < textByte.length; i++) {// 每个字节用3位数的整数表示,不够则在前面补0
  64.             int bn = textByte[i] & 0xff;
  65.             if (bn < 10) {
  66.                 textNum += "00" + bn;
  67.             } else if (bn < 100) {
  68.                 textNum += "0" + bn;
  69.             } else {
  70.                 textNum += bn;
  71.             }
  72.         }
  73.         m = new BigInteger(textNum);

  74.         BigInteger[] mArray = null;// 明文分组结果
  75.         if (m.compareTo(n) == -1) {// m < n,可直接加密
  76.             mArray = new BigInteger[1];
  77.             mArray[0] = m;
  78.         } else {
  79.             int groupLength = n.toString().length() - 1;// 每组明文长度
  80.             int mStringLength = m.toString().length();// 明文转化为字符串的长度
  81.             while (groupLength % 3 != 0) {// 由于前面每个字节用3位整数表示,因此每组的长度必须为3的整数,避免恢复时错误
  82.                 groupLength--;
  83.             }
  84.             if (mStringLength % groupLength != 0) {// 如果最后一组的长度不足
  85.                 mArray = new BigInteger[mStringLength / groupLength + 1];
  86.             } else {
  87.                 mArray = new BigInteger[mStringLength / groupLength];
  88.             }

  89.             String tmp;
  90.             for (int i = 0; i < mArray.length; i++) {
  91.                 tmp = "";
  92.                 if (i != mArray.length - 1) {// 根据每组长度进行分割分组保存
  93.                     tmp = textNum.substring(groupLength * i, groupLength * i + groupLength);
  94.                 } else {
  95.                     tmp = textNum.substring(groupLength * i);
  96.                 }
  97.                 mArray[i] = new BigInteger(tmp);
  98.             }
  99.         }

  100.         for (int i = 0; i < mArray.length; i++) {// 逐组加密并返回
  101.             mArray[i] = expMod(mArray[i], e, n);
  102.         }
  103.         return mArray;
  104.     }


  105.     private String decryption(BigInteger[] c) {
  106.         String cPadding = "";
  107.         String mToString = "";
  108.         int mToStringLengthMod = 0;
  109.         BigInteger m = BigInteger.ZERO;
  110.         for (int i = 0; i < c.length; i++) {// 逐组解密
  111.             m = RSA.expMod(c[i], d, n);
  112.             mToString = m.toString();
  113.             mToStringLengthMod = m.toString().length() % 3;
  114.             if (mToStringLengthMod != 0) {// 由于加密时String转BigInter时前者前面的0并不会计入,所以需要确认并补全
  115.                 for (int j = 0; j < 3 - mToStringLengthMod; j++) {
  116.                     mToString = "0" + mToString;
  117.                 }
  118.             }
  119.             cPadding += mToString;
  120.         }

  121.         int byteNum = cPadding.length() / 3;// 明文总字节数
  122.         byte[] result = new byte[byteNum];
  123.         for (int i = 0; i < byteNum; i++) {// 每三位数转化为byte型并返回该byte数组所表达的字符串
  124.             result[i] = (byte) (Integer.parseInt(cPadding.substring(i * 3, i * 3 + 3)));
  125.         }
  126.         return new String(result);
  127.     }


  128.     private static BigInteger[] extdGcd(BigInteger e, BigInteger φn) {
  129.         BigInteger[] gdk = new BigInteger[3];

  130.         if (φn.compareTo(BigInteger.ZERO) == 0) {
  131.             gdk[0] = e;
  132.             gdk[1] = BigInteger.ONE;
  133.             gdk[2] = BigInteger.ZERO;
  134.             return gdk;
  135.         } else {
  136.             gdk = extdGcd(φn, e.remainder(φn));
  137.             BigInteger tmp_k = gdk[2];
  138.             gdk[2] = gdk[1].subtract(e.divide(φn).multiply(gdk[2]));
  139.             gdk[1] = tmp_k;
  140.             return gdk;
  141.         }
  142.     }


  143.     private static boolean isPrime(BigInteger p) {
  144.         if (p.compareTo(BigInteger.TWO) == -1) {// 小于2直接返回false
  145.             return false;
  146.         }
  147.         if ((p.compareTo(BigInteger.TWO) != 0) && (p.remainder(BigInteger.TWO).compareTo(BigInteger.ZERO) == 0)) {// 不等于2且是偶数直接返回false
  148.             return false;
  149.         }

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

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

  159.             int j = 0;
  160.             BigInteger z = RSA.expMod(b, m, p);
  161.             while (!((j == 0 && z.equals(BigInteger.ONE)) || z.equals(p_1))) {
  162.                 if ((j > 0 && z.equals(BigInteger.ONE)) || ++j == q) {
  163.                     return false;
  164.                 }
  165.                 z = RSA.expMod(z, BigInteger.TWO, p);
  166.             }
  167.         }

  168.         return true;
  169.     }


  170.     private static BigInteger generateNBitRandomPrime(int n) {
  171.         BigInteger tmp = new BigInteger("2").pow(n - 1);// 最高位肯定是1
  172.         BigInteger result = new BigInteger("2").pow(n - 1);
  173.         Random random = new Random();
  174.         int r1 = random.nextInt(101);// 产生0-100的整数,用于确定0和1的比例
  175.         int r2;

  176.         while (true) {// 循环产生数,直到该数为素数
  177.             for (int i = n - 2; i >= 0; i--) {// 逐位产生表示数的0和1,并根据所在位计算结果相加起来
  178.                 r2 = random.nextInt(101);
  179.                 if (0 < r2 && r2 < r1) {// 产生的数为1
  180.                     result = result.add(BigInteger.TWO.pow(i));
  181.                 }
  182.                 continue;
  183.             }

  184.             if (RSA.isPrime(result)) {// 素数判断
  185.                 return result;
  186.             }

  187.             result = tmp;// 重新计算
  188.         }
  189.     }


  190.     private static BigInteger expMod(BigInteger base, BigInteger exponent, BigInteger module) {
  191.         BigInteger result = BigInteger.ONE;
  192.         BigInteger tmp = base.mod(module);

  193.         while (exponent.compareTo(BigInteger.ZERO) != 0) {
  194.             if ((exponent.and(BigInteger.ONE).compareTo(BigInteger.ZERO)) != 0) {
  195.                 result = result.multiply(tmp).mod(module);
  196.             }
  197.             tmp = tmp.multiply(tmp).mod(module);
  198.             exponent = exponent.shiftRight(1);
  199.         }

  200.         return result;
  201.     }

  202. }

复制代码

本帖子中包含更多资源

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

x
回复

使用道具 举报

9

主题

16

帖子

117

积分

注册会员

Rank: 2

积分
117
 楼主| 发表于 2022-5-3 16:01:39 | 显示全部楼层

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

教学服务系统

GMT+8, 2025-4-30 14:21 , Processed in 0.017378 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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