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
 */

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM