• RSA算法的基本原理及实现


    1、准备步骤:

    1)取 8-bit 的两个素数(质数)p、q

    2)n = p * q,计算 n 的欧拉函数 m(表示在小于等于 n 的正整数之中,与 n 构成互质关系的数的个数),当 p 和 q 均为质数时,m = (p - 1) * (q - 1)

    3)随机选取一个整数 e,满足条件 1 < e < m 且 e 与 m 互质(但不能选择 m - 1,否则公钥和私钥将相同)

    4)找出一个整数 d,使得 e * d mod m = 1,即找出 e 模 m 的逆元(扩展欧几里得算法求逆元,之前的一篇随笔有说明)

    5)公钥为(n, e),私钥为(n, d)

    2、加密过程

    对明文的 e 次方后除以 n 求余数,即求:(mingwen)^e mod n

    3、解密过程

    对密文进行 d 次方后除以 n 求余数,即求:(miwen)^d mod n

    4、加密及解密实现(对学号+姓名加密):

    import java.util.ArrayList;
    
    public class Main {
        static ArrayList<Integer> suArr = new ArrayList<>();
        static int[] xy = new int[2];
    
        public static void main(String[] args) {
            // 由于题目要求取8-bit的两个素数 p,q 因此素数集合的最大值不超过255
            int max = 255, p = 0, q = 0, n, m, e = -1, index = 0;
            char[] myInfo = "1700802067GJQ".toCharArray();
            int[] miwen = new int[myInfo.length];
            char[] mingwen = new char[myInfo.length];
            suArr.add(2);
    
            for (int i = 3; i <= max; i++) {
                if (isSuShu(i))
                    suArr.add(i);
            }
    
            // 保证取到的两个素数不相等
            while (p == q) {
                p = getRanNum(suArr.size());
                q = getRanNum(suArr.size());
            }
    
            n = p * q;
            m = (p - 1) * (q - 1);
    
            // 求得公钥为(n, e)
            for (int i = 2; i < m; i++) {
                if (isHuZhi(m, i) == 1) {
                    e = i;
                    break;
                }
            }
    
            if (e != -1) {
                exGcd(e, m);
                /*
                根据要求(e*d)%m=1求得的d(即xy[0])可能为负数,因此当其为负数时要将其转化为正数,转换的原理为:
                a%b=(a%b+b)%b
                当a为负数且b为正数时可使用上述公式将a转换为正数
                */
                if (xy[0] < 0) xy[0] = (xy[0] % m + m) % m;
                System.out.println("p为" + String.valueOf(p) + ",q为" + String.valueOf(q));
                System.out.println("公钥为(" + String.valueOf(n) + ", " + String.valueOf(e) + "),私钥为(" + String.valueOf(n) + ", " + String.valueOf(xy[0]) + ")");
    
                // 公钥进行加密(mingwen)^e mod n
                for (char c : myInfo) {
                    miwen[index++] = myPow((int) c, e, n);
                }
                System.out.print("加密后的密文:");
                for (int c : miwen) {
                    System.out.print(c + " ");
                }
                System.out.println();
    
                index = 0;
                // 私钥进行解密(miwen)^d mod n
                for (int i : miwen) {
                    mingwen[index] = (char) myPow(miwen[index], xy[0], n);
                    index++;
                }
    
                System.out.print("解密后的明文:");
                for (char c : mingwen) {
                    System.out.print(c);
                }
    
            }
    
        }
    
        // 判断一个数是否为素数
        public static boolean isSuShu(int num) {
            int max = (int) Math.sqrt(num);
            for (int i = 2; i <= max; i++) {
                if (num % i == 0)
                    return false;
            }
            return true;
        }
    
        // 在素数数组中随机取一个数
        public static int getRanNum(int size) {
            return suArr.get((int) (Math.random() * (size)));
        }
    
        // 判断两个数是否互质
        public static int isHuZhi(int a, int b) {
            return b == 0 ? a : isHuZhi(b, a % b);
        }
    
        // 扩展欧几里得算法求得私钥(n, xy[0])即(n, d)
        public static void exGcd(int a, int b) {
            if (b == 0) {
                xy[0] = 1;
                xy[1] = 0;
            } else {
                exGcd(b, a % b);
                int x = xy[0];
                xy[0] = xy[1];
                xy[1] = x - (a / b) * xy[1];
            }
        }
    
        public static int myPow(int a, int b, int m) {
            int res = 1;
            a %= m;
            while (b != 0) {
                if ((b & 1) == 1)
                    res = (res * a) % m;
                a = (a * a) % m;
                b >>= 1;
            }
            return res;
        }
    }
    
    /*
     * 参考: https://www.jianshu.com/p/fbb8bf7baa97
     * https://www.cnblogs.com/shuaihui520/p/8954788.html
     * https://www.cnblogs.com/linkzijun/p/6151486.html
     */
  • 相关阅读:
    find 命令
    shell 脚本 测试webApp
    thinkphp模板继承
    Tp-validate进阶thinkphp
    B2B、B2C、C2C、O2O
    phpstorm自定义代码片段
    phpstorm开启xdebug断点调试,断点调试不成功来这里
    app接口设计
    socket
    字符集转换
  • 原文地址:https://www.cnblogs.com/GjqDream/p/11543073.html
Copyright © 2020-2023  润新知