密碼學程序設計實現RSA加解密

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

class ProducePrime {
    /*
     * 獲取第一個素數的方法
     */
    
    public Integer Prime1() {
        List<Integer> list = new ArrayList<Integer>();// 存儲素數的集合
        for (int i = (int) Math.pow(2, 16) + 1; i <= Math.pow(2, 17); i+=2) {// 判斷奇數
            boolean num2 = true;// 防止被false覆蓋
            for (int m = 2; m <= Math.sqrt(i); m++) {// 提高試除效率
                if (i % m == 0) {
                    num2 = false;// 不是素數
                    break;
                } else if (num2) {
                    list.add(i);// 存儲素數到集合中
                }
            }

        }
        Random random = new Random();
        int n = random.nextInt(list.size());
        return list.get(n);

    }

    /*
     * 獲取第二個素數的方法
     */
    
    public int Prime2() {
        int max = (int) Math.pow(2, 22);
        int min = (int) Math.pow(2, 21);
        int temp = 0;
        int num = new Random().nextInt(max - min + 1) + min;// 隨機獲取指定范圍內的數字
        if (Odd(num)) {
            boolean flag = true;
            for (int m = 2; m <= Math.sqrt(num); m++) {// 提高試除效率
                if (num % m == 0) {
                    flag = false;// 不是素數
                    num = num + 2;
                    continue;
                } 
                else if(flag) {
                    temp = num;
                }
            }
        }
        else {
            num = num + 1;
            boolean flag = true;
            for (int m = 2; m <= Math.sqrt(num); m++) {// 提高試除效率
                if (num % m == 0) {
                    flag = false;// 不是素數
                    num = num + 2;
                    continue;
                } 
                else if(flag) {
                    temp = num;
                }
            }
        }
        return temp;

    }

    public boolean Odd(int n) {
        boolean flag = true;
        if (n % 2 == 0) {
            flag = false;
            return flag;
        } else {
            return flag;
        }
    }

}

class Division {
    public void divison(int m) {
        int temp = 1;
        int c = 1;
        int[] arr = new int[1000];
        arr[0] = 2;
        for (int i = 3; i < 1000; i+=2) {// 判斷奇數即可
            boolean flag = true;
            for (int q = 2; q <= Math.sqrt(i); q++) {
                if (i % q == 0) {
                    flag = false;// 該數不是素數
                    break;
                }
            }
            if (flag) {
                arr[temp] = i;// 存儲1000以內素數,用于試除
                temp++;
            }
        }
        
        System.out.println("1000以內素數試除開始:");
        System.out.println();
        
        for (int a = 0; a < temp; a++) {
            int b = m % arr[a];// 試除1000以內的素數,保存余數
            System.out.println("試除第" + c + "次:" + m + " % " + arr[a] + "=" + b);
            c++;
            System.out.println("得到的余數為:" + b);
            System.out.println();
        }
        System.out.println("1000以內素數試除結束");
    }
}

class MillerRabin {
    /*
     * Miller-Rabin檢測算法,n為檢測數據
     */
    
    public boolean MillerRabin2(int n) {
        int a = new Random().nextInt(n) + 1;
        long s = 1;
        long n2 = n - 1;
        long n3 = n - 1;
        int t = 0, temp = 0;
        boolean flag = true;
        out :
            for(;;) {
            if (n2 % 2 != 0) {
                s = temp;
                break out;
            }else {
                n2 = n2 / 2;
                temp++;
            }
        }
        t = (int) (n3 / Math.pow(2, s));
        int b = (int) Math.pow(a, t);
        for(long i = (long) Math.pow(2,s - 1); i >= 1; i--){
            if((Math.pow(b, i) + 1) % n == 0){
                break;
            }
            if(i == 1){
                if((Math.pow(b, i) - 1) % n == 0){
                    break;
                }
                else{
                    flag = false;
                }
            }
        }
        return flag;
    }

}

class EuclideanAlgorithm {
    /*
     * 獲取私鑰d的方法
     * 歐幾里得擴展算法
     * 公鑰e = 17
     */
    
    BigInteger x, y, a, b, t, r;
    public BigInteger exgcd(BigInteger a, BigInteger b) {
        if (b == BigInteger.valueOf(0)) {
            x = BigInteger.valueOf(1);
            y = BigInteger.valueOf(0);
            return a;
        }
        r = exgcd(b, a.mod(b));
        t = x;
        x = y;
        y = t.subtract((a.divide(b)).multiply(y));
        return r;
    }
    
    public void XY(BigInteger fn, BigInteger e) {
        System.out.println("解得x為:" + x);
        System.out.println("解得y為:" + y);
        if (y.compareTo(BigInteger.valueOf(0)) < 0) {
            System.out.println("所以密鑰d為:" + (y.add(fn)));
        }else {
            System.out.println("所以密鑰d為:" + y);
        }
        
    }

}

class MoChongFuPingFang {
    /*
     * 模重復平方算法加密
     * 輸入加密明文m = 32655,公鑰e = 17,模數為n
     */
    
    String binary;
    long a = 1;
    BigInteger a2 = BigInteger.valueOf(a);

    public BigInteger Encryption(long m, long e2, long n) {
        binary = Long.toBinaryString(e2);
        BigInteger a3 = a2;
        BigInteger m2 = BigInteger.valueOf(m);
        BigInteger m3 = m2;
        BigInteger n2 = BigInteger.valueOf(n);
        
        for (int i = binary.length() - 1; i >= 0; i--) {
            if (binary.charAt(i) == '1') {
                a3 = a2.multiply(m2).mod(n2);
                a2 = a3;
                m3 = m2.multiply(m2).mod(n2);
                m2 = m3;
            }else {
                m3 = m2.multiply(m2).mod(n2);
                m2 = m3;
            }
        }
        return a3;  
    }

}

class PingFangCheng {
    /*
     * 平方乘算法解密
     * 密文m,私鑰d,模數n
     */
    
    String binary;
    long x = 0, y = 1;
    BigInteger x2 = BigInteger.valueOf(x);
    BigInteger y2 = BigInteger.valueOf(y);
    public BigInteger Decryption(long m, long d, long n) {
        binary = Long.toBinaryString(d);
        BigInteger x3 = x2;
        BigInteger m2 = BigInteger.valueOf(m);
        BigInteger n2 = BigInteger.valueOf(n);
        BigInteger y3 = y2;
        BigInteger c = BigInteger.valueOf(2);
        BigInteger c2 = BigInteger.valueOf(1);
        for(int i = 0; i < binary.length(); i++) {
            x3 = x2.multiply(c);
            x2 = x3;
            y3 = y2.multiply(y2).mod(n2);
            y2 = y3;
            if (binary.charAt(i) == '1') {
                x3 = x2.add(c2);
                x2 = x3;
                y3 = y2.multiply(m2).mod(n2); 
                y2 = y3;
            }
        }
        return y3;
    }

}

public class RSADemo {
    public static void main(String[] args) {
        ProducePrime ProducePrime = new ProducePrime();
        Division Division = new Division();
        EuclideanAlgorithm euclideanAlgorithm = new EuclideanAlgorithm();
        MoChongFuPingFang moChongFuPingFang = new MoChongFuPingFang();
        PingFangCheng pingFangCheng = new PingFangCheng();
        MillerRabin MillerRabin = new MillerRabin();
        Scanner scanner = new Scanner(System.in);
        System.out.println("/****************/");
        System.out.println("RSA算法加密解密實現");
        System.out.println("/****************/");
        int p = 1009;//ProducePrime.Prime1();
        //int p = ProducePrime.Prime1();
        System.out.println("輸出滿足要求的第一個素數p:" + p);
        int q = 997;//ProducePrime.Prime2();
        //int q = ProducePrime.Prime2();
        System.out.println("輸出滿足要求的第二個素數q:" + q);
        System.out.println("/****************/");
        long n = (long)p * q;//避免越界,強制轉型
        long fn = (long)(p - 1) * (q - 1);
        System.out.println("n=p*q=" + n);
        System.out.println("f(n)=(p-1)*(q-1)=" + fn);
        System.out.println("/****************/");
        Division.divison(p);
        System.out.println("/****************/");
        int p2 = (int)p;
        boolean flag = MillerRabin.MillerRabin2(p2);
        System.out.println("Miller-Rabin算法檢測標志符為:" + flag);
        System.out.println("/****************/");
        System.out.println("請輸入公鑰e:");
        long e = scanner.nextLong();
        BigInteger e3 = BigInteger.valueOf(e);
        BigInteger fn2 = BigInteger.valueOf(fn);
        System.out.println("公鑰e與fn的最大公約數為:" + euclideanAlgorithm.exgcd(fn2, e3));//最大公約數        
        euclideanAlgorithm.XY(fn2, e3);
        System.out.println("/****************/");
        //加密明文
        System.out.println("加密開始:");
        System.out.println("請輸入明文m:");
        long m = scanner.nextLong();
        System.out.println("請輸入公鑰e:");
        long e2 = scanner.nextLong();
        System.out.println("加密后的密文m2為:" + moChongFuPingFang.Encryption(m, e2, n));
        System.out.println("/****************/");
        //解密密文
        System.out.println("解密開始:");
        System.out.println("請輸入密文m2:");
        long m2 = scanner.nextLong();
        System.out.println("請輸入密鑰d:");
        long d2 = scanner.nextLong();
        System.out.println("解密后的明文為:" + pingFangCheng.Decryption(m2, d2, n));
    }
}
  • 一些說明:
  1. 大素數的運算使用BigInteger類解決數據長度溢出的問題。
  2. 自動獲取的大素數用來加解密會失敗,多番檢查也沒找到問題所在。
  3. 自定義的素數p = 1009,q = 997,公鑰e = 17可以加解密成功。
  4. 如果您有興趣,不妨試試解決這個問題,手動狗頭。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,634評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,653評論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,835評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,235評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,459評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,000評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,819評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,004評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,257評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,717評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,003評論 2 374

推薦閱讀更多精彩內容

  • 本文主要介紹移動端的加解密算法的分類、其優缺點特性及應用,幫助讀者由淺入深地了解和選擇加解密算法。文中會包含算法的...
    蘋果粉閱讀 11,540評論 5 29
  • 公鑰密碼系統及RSA公鑰算法 本文簡單介紹了公開密鑰密碼系統的思想和特點,并具體介紹了RSA算法的理論基礎,工作原...
    火狼o閱讀 4,310評論 2 15
  • 姓名:于川皓 學號:16140210089 轉載自:https://baike.baidu.com/item/RS...
    道無涯_cc76閱讀 2,584評論 0 1
  • 密鑰分為兩種:對稱密鑰與非對稱密鑰 對稱密鑰加密,又稱私鑰加密,即信息的發送方和接收方用一個密鑰去加密和解密數據。...
    卡卡羅2017閱讀 10,332評論 0 6
  • 我媽今天陪客戶吃飯去了,老說舍不得我,要早早回家,但卻經常偶爾性回家已半夜。今天讓我爸拉著我去接他。給我打了電話,...
    蘇田田閱讀 171評論 0 0