JAVA实现RSA-不使用security库

本文详细介绍了一位开发者如何从理论到实践,手写RSA加密算法的过程,包括大素数选择、模幂运算、模逆计算,以及如何将算法应用于实际字符串加密。通过实例演示了加密和解密操作,以及如何处理过大的明文数据

学校里的实验正好在学习网络安全方面的密码学基础,就正好想着写一个RSA加密的算法,之前也看到了不少RSA加密的代码,不过大部分都是使用库来实现的,由于想更好的理解就不调用security库来实现一次,当然如果日后使用到RSA的话,肯定还是用库的好,毕竟自己写的基本功能满足了但是肯定还有很多不足,不多BB 了,上代码:

RSA算法

1.随机地选择两个大素数p和q,而且保密;

2.计算n=pq,将n公开;

3.计算φ(n)=(p-1)(q-1),对φ(n)保密;

4.随机地选取一个正整数e,1<e<φ(n)且(e,φ(n))=1,将e公开;

5.根据ed=1(mod φ(n)),求出d,并对d保密;

6.加密运算:C=Me(mod n);

7.解密运算:M=Cd(mod n)。

注意:在加密运算和解密运算中,M和C的值都必须小于n,也就是说,如果明文(或密文)太大,必须进行分组加密(或解密)。(这个是重点,也是本次实验我没完成的一步,人比较废物。。。。。。)

模幂算法

 /**
     * 模指运算
     * @param b
     * @param n
     * @param m
     * @return   b^n(mod m)
     */
    public static BigInteger modExp(BigInteger b, BigInteger n, BigInteger m) {
        BigInteger result = new BigInteger("1");
        b = b.remainder(m);
        do {
            if ((n.remainder(new BigInteger("2"))).compareTo(BigInteger.ONE)==0){
                result=(result.multiply(b)).remainder(m);
            }
            b = (b.multiply(b)).remainder(m);
            n = n.shiftRight(1);
        } while (n != BigInteger.ZERO);
        return result;
    }

因为RSA是大素数为基础的算法,所以使用了BigInteger类,因为long只能满足到64位,实际情况可能一句话都加密不了。

当然Biginteger类中自带了modpow函数可以进行模的幂运算,包括后面的求逆元同样可以使用其进行计算,这里我没有使用他,而是只是自己写出来以便更好的理解

模逆(求逆元)

 /**
     * 模逆运算
     * @param b
     * @param m
     * @return  b^-1(mod m)
     */
    public static BigInteger modInv1(BigInteger b, BigInteger m) {
        if (b.compareTo(m)==1||b.compareTo(m)==0)
            b = b.remainder(m);
        return Gcd(b, m)[1].compareTo(BigInteger.ZERO)==-1 ? Gcd(b, m)[1].add(m) : Gcd(b, m)[1];
    }
    /**
     * 扩展欧几里德算法
     * <p>(a,b)=ax+by
     * @param a
     * @param b
     * @return  返回一个BigInteger数组result,result[0]=x,result[1]=y,result[2]=(a,b)
     */
    public static BigInteger[] Gcd(BigInteger a, BigInteger b) {
        if (a.compareTo(b)==-1) {
            BigInteger temp = a;
            a = b;
            b = temp;
        }
        BigInteger[] result = new BigInteger[3];
        if (b.compareTo(BigInteger.ZERO)==0) {
            result[0] = new BigInteger("1");
            result[1] = new BigInteger("0");
            result[2] = a;
            return result;
        }
        BigInteger[] temp = Gcd(b, a.remainder(b));
        result[0] = temp[1];
        result[1] = temp[0].subtract((a.divide(b)).multiply(temp[1]));
        result[2] = temp[2];
        return result;
    }

RSA加解密

 /**
     * RSA加密操作
     */

    public static BigInteger encyrpt(byte[] textByte,BigInteger e,BigInteger n) throws UnsupportedEncodingException {
        BigInteger t = new BigInteger(1,textByte);
        BigInteger C = modExp(t,e,n);//可以直接使用modpow函数进行模幂算法,这里采取了手动实现以更便于理解底层
        //        System.out.println(C);
        return C;
    }
    /**
     * RSA解密操作
     */
    public static BigInteger dncyrpt(BigInteger C,BigInteger d,BigInteger n) throws UnsupportedEncodingException {
        BigInteger cm = modExp(C,d,n);
        return cm;
    }

因为算法都是数学问题,是以数字的形式体现,那当我们想运用于实际中加密一串字符串或是一段语言时该怎么办呢?

System.out.println("输入明文:");
Scanner input = new Scanner(System.in);
String M = input.next();
System.out.println("需要加密的明文:"+M);
byte[] textByte = M.getBytes("UTF-8");
        BigInteger C = encyrpt(textByte,e,n);
        byte[] cmessage = C.toByteArray();
        String a = base64.encodeToString(cmessage);
        System.out.println("加密得到的密文:"+a);
        BigInteger cm = dncyrpt(C,d,n);
        byte[] recmessage = cm.toByteArray();
        String encodedText2 = base64.encodeToString(recmessage);
        System.out.println("解密后得到的信息明文:"+new String(base64.decode(encodedText2), "UTF-8"));

熟练的在自己设置的函数体调用时对其进行类型的装换
基本为byte[] string BigInteger 三类

代码(全)

package secourity;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;

import java.util.Random;
import java.util.Scanner;


import org.apache.commons.codec.binary.Base64;


public class RSA {
    public static void main(String[] args) throws Exception {
        //需要加密的明文
        System.out.println("输入明文:");
        Scanner input = new Scanner(System.in);
        String M = input.next();
        System.out.println("需要加密的明文:"+M);
        byte[] textByte = M.getBytes("UTF-8");
        System.out.println("bytelength:"+textByte.length);
        //生成大素数p,q
        int bitlength = (textByte.length)*8;//byte=8bite,使用这个步骤,让p,q算出的n的长度一定是大于输入明文的
        Base64 base64 = new Base64();
        BigInteger p = BigInteger.probablePrime(bitlength, new Random());
        BigInteger q = BigInteger.probablePrime(bitlength, new Random());
        //n=p*q生成加解密运算的mod数
        BigInteger n = p.multiply(q);
        int num = n.bitLength();
        System.out.println("bit长度为:"+num);
        //生成欧几里得算法输出的R
        BigInteger r = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));
        //生成公钥e
        BigInteger e;
        do {
//            e = new BigInteger(new Random().nextInt(r.bitLength() - 1) + 1, new Random());
            e = new BigInteger(900, new Random());
        } while (e.compareTo(r) != -1 || e.gcd(r).intValue() != 1);
        //生成私钥
        BigInteger d = modInv1(e,r);
        //公钥和私钥做base64编码操作
        byte[] publickey = e.toByteArray();
        String encodedText = base64.encodeToString(publickey);
//        System.out.println(e);
        byte[] pravitekey = d.toByteArray();
        String encodedText1 = base64.encodeToString(pravitekey);
        System.out.println("公钥为:"+encodedText);
        System.out.println("私钥为:"+encodedText1);


        BigInteger C = encyrpt(textByte,e,n);
        byte[] cmessage = C.toByteArray();
        String a = base64.encodeToString(cmessage);
        System.out.println("加密得到的密文:"+a);
        BigInteger cm = dncyrpt(C,d,n);
        byte[] recmessage = cm.toByteArray();
        String encodedText2 = base64.encodeToString(recmessage);
        System.out.println("解密后得到的信息明文:"+new String(base64.decode(encodedText2), "UTF-8"));




    }
    /**
     * RSA加密操作
     */

    public static BigInteger encyrpt(byte[] textByte,BigInteger e,BigInteger n) throws UnsupportedEncodingException {
        BigInteger t = new BigInteger(1,textByte);
        BigInteger C = modExp(t,e,n);//可以直接使用modpow函数进行模幂算法,这里采取了手动实现以更便于理解底层
        //        System.out.println(C);
        return C;
    }
    /**
     * RSA解密操作
     */
    public static BigInteger dncyrpt(BigInteger C,BigInteger d,BigInteger n) throws UnsupportedEncodingException {
        BigInteger cm = modExp(C,d,n);
        return cm;
    }
    /**
     * 模指运算
     * @param b
     * @param n
     * @param m
     * @return   b^n(mod m)
     */
    public static BigInteger modExp(BigInteger b, BigInteger n, BigInteger m) {
        BigInteger result = new BigInteger("1");
        b = b.remainder(m);
        do {
            if ((n.remainder(new BigInteger("2"))).compareTo(BigInteger.ONE)==0){
                result=(result.multiply(b)).remainder(m);
            }
            b = (b.multiply(b)).remainder(m);
            n = n.shiftRight(1);
        } while (n != BigInteger.ZERO);
        return result;
    }
    /**
     * 模逆运算
     * @param b
     * @param m
     * @return  b^-1(mod m)
     */
    public static BigInteger modInv1(BigInteger b, BigInteger m) {
        if (b.compareTo(m)==1||b.compareTo(m)==0)
            b = b.remainder(m);
        return Gcd(b, m)[1].compareTo(BigInteger.ZERO)==-1 ? Gcd(b, m)[1].add(m) : Gcd(b, m)[1];
    }
    /**
     * 扩展欧几里德算法
     * <p>(a,b)=ax+by
     * @param a
     * @param b
     * @return  返回一个BigInteger数组result,result[0]=x,result[1]=y,result[2]=(a,b)
     */
    public static BigInteger[] Gcd(BigInteger a, BigInteger b) {
        if (a.compareTo(b)==-1) {
            BigInteger temp = a;
            a = b;
            b = temp;
        }
        BigInteger[] result = new BigInteger[3];
        if (b.compareTo(BigInteger.ZERO)==0) {
            result[0] = new BigInteger("1");
            result[1] = new BigInteger("0");
            result[2] = a;
            return result;
        }
        BigInteger[] temp = Gcd(b, a.remainder(b));
        result[0] = temp[1];
        result[1] = temp[0].subtract((a.divide(b)).multiply(temp[1]));
        result[2] = temp[2];
        return result;
    }

}

因为自己代码的习惯和熟练度都还不是很好,所以这段代码的main部分还是封装的不大好,不过逻辑还算相对比较清楚,如果能起到一定的学习作用那是最好,当然真实情况下的RSA还要考虑更多的问题,实际应用中还是调用库比较好。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值