【Java】利用Miller-Rabin素性测试、扩展欧几里得算法以及蒙哥马利快速模幂运算实现1024bit的RSA公钥加解密算法

参考:
利用扩展欧几里得算法编程求逆元
蒙哥马利幂模算法(二分快速幂)

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

public class Exp3 {
    public static void main(String[] args) {
        BigInteger[] plainText;
        BigInteger[] ciperText;
        plainText=input();

        BigInteger p=choosePQ();
        System.out.println("p:"+p);
        BigInteger q = choosePQ();
        System.out.println("q:"+q);
        BigInteger n =p.multiply(q);
        System.out.println("n:"+n);
        BigInteger on=p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));
        BigInteger e=new BigInteger("17");//e选择17
        BigInteger d =extendedEuclidean(e,on);
        System.out.println("d:"+d);

        ciperText=rsaEncode(plainText,e,n);
        System.out.println("加密结果:");
        for (int i = 0; i < ciperText.length; i++) {
            System.out.println(ciperText[i]);
        }
        char[] decodeText;
        decodeText=rsaDecode(ciperText,d,n);
        System.out.println("解密结果:");
        for (int i = 0; i < decodeText.length; i++) {
            System.out.print(decodeText[i]);
        }
    }

    //输入明文并将明文处理成bigint类型
    public static BigInteger[] input() {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入要加密的明文");
        String plaintext = sc.nextLine();
        int[] plainInt = new int[plaintext.length()];
        BigInteger[] plainBigint = new BigInteger[plaintext.length()];
        for (int i = 0; i < plaintext.length(); i++) {
            char plaintextChar = plaintext.charAt(i);
            plainInt[i] = plaintextChar;
            plainBigint[i]=BigInteger.valueOf(plainInt[i]);
        }
        return plainBigint;
    }

    public static BigInteger choosePQ() {
        Random r = new Random();
        String tempThree = "3";
        BigInteger three = new BigInteger(tempThree);
        BigInteger bigNum;
        while (true) {
            //生成长度为1024的0,1string字符串,获得1024bit位效果
            while(true) {
                StringBuffer sb = new StringBuffer();
                for (int i = 0; i < 1024; i++) {
                    sb.append(r.nextInt(2));
                }
                String str = sb.toString();
                //将0,1字符串转换为10进制BigInteger类型
                bigNum = new BigInteger(str, 2);
                if(bigNum.compareTo(three)>0)
                    break;
            }
            //System.out.println(bigNum);
            if (Miller_Rabin(bigNum)) {
                break;
            }
        }
        return bigNum;
    }
    public static boolean Miller_Rabin(BigInteger bigNum) {
        String tempTwo = "2";
        BigInteger two = new BigInteger(tempTwo);
        //判断是否为偶数,是则一定不是素数
        if (bigNum.mod(two).equals(BigInteger.ZERO)) {
            return false;
        }
        int j = 0;
        //获得n-1=2^k*q;
        BigInteger k = BigInteger.ZERO;
        //q最初的值就是n-1
        BigInteger q = bigNum.subtract(BigInteger.ONE);
        while (q.mod(two).equals(BigInteger.ZERO)) {
            k = k.add(BigInteger.ONE);
            q = q.divide(two);

        }
        int num_k = k.intValue();
        Random r = new Random();
        int flag = 0;
        while (j < 128) {
            BigInteger a = new BigInteger(bigNum.bitLength(), r);
            while (true) {//确保a>0&&a<n-1
                if (a.compareTo(bigNum.subtract(BigInteger.ONE)) < 0 && a.compareTo(BigInteger.ONE) > 0) {
                    break;
                } else
                    a = new BigInteger(bigNum.bitLength(), r);
            }
            //当a^q mod n =1的时候有可能是素数
            if (a.modPow(q, bigNum).equals(BigInteger.ONE))
                flag = 1;
                //当a^(2*q*i) mod n = n-1的时候有可能是素数
            else {
                for (int i = 0; i <= num_k - 1; i++) {
                    BigInteger twoPowI = BigInteger.valueOf(2^i);
                    if (a.modPow(twoPowI.multiply(q),bigNum).equals(bigNum.subtract(BigInteger.ONE))) {
                        flag = 1;
                        break;
                    }
                }
            }
            j++;
        }
        if (flag == 0)
            return false;
        return true;
    }

    public static BigInteger extendedEuclidean(BigInteger a1,BigInteger b1){
        BigInteger temp=b1;
        if(a1.compareTo(b1)<0)
        {
            a1=b1.add(a1);
            b1=a1.subtract(b1);
            a1=a1.subtract(b1);
        }
        BigInteger q,r,x,y;
        BigInteger x2 = new BigInteger("1");
        BigInteger x1 = new BigInteger("0");
        BigInteger y2 = new BigInteger("0");
        BigInteger y1 = new BigInteger("1");

        while(b1.compareTo(BigInteger.ZERO)>0){
            q=a1.divide(b1);
            r=a1.subtract(q.multiply(b1));
            x=x2.subtract(q.multiply(x1));
            y=y2.subtract(q.multiply(y1));
            a1=b1;
            b1=r;
            x2=x1;
            x1=x;
            y2=y1;
            y1=y;
        }
        y=y2;
        if(y.compareTo(BigInteger.ZERO)<0)
            y=y.add(temp);
        return y;
    }

    public static BigInteger[] rsaEncode(BigInteger[] plainText,BigInteger e,BigInteger n){
        BigInteger[] ciperText=plainText;
        for (int i = 0; i < plainText.length; i++) {
            BigInteger temp;
            temp=MontgomeryPowerModule(plainText[i],e,n);
            ciperText[i]=temp;
        }
        return ciperText;
    }

    public static char[] rsaDecode(BigInteger[] ciperText,BigInteger d,BigInteger n){
        int[] toChar=new int[ciperText.length];
        char[] decodeText=new char[ciperText.length];
        for (int i = 0; i < ciperText.length; i++) {
            BigInteger temp;
            temp=MontgomeryPowerModule(ciperText[i],d,n);
            toChar[i]=temp.intValue();
            decodeText[i]=(char) toChar[i];
        }
        return decodeText;
    }

    public static BigInteger MontgomeryPowerModule(BigInteger a,BigInteger e,BigInteger n){
        BigInteger result=BigInteger.ONE;
        while(e.compareTo(BigInteger.ZERO)>0){
            if(e.mod(BigInteger.TWO).compareTo(BigInteger.ONE)==0){
                result = result.multiply(a).mod(n);
            }
            e=e.divide(BigInteger.TWO);
            a=a.multiply(a).mod(n);
        }
        return result;
    }
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值