RSA算法

RSA非对称加密技术实现过程,代码如下:

package com.zhongji.utils;

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

public class RSA {
    private final static int numLength = 1024;//素数长度
    private final static int accuracy = 100;//素数的准确率为1-(2^(-accuracy))

    //获取最大公约数
    private BigInteger getGCD(BigInteger a, BigInteger b) {
        if (b.byteValue() == 0) return a;
        return getGCD(b, a.mod(b));
    }

    //扩展欧几里得方法,计算 ax + by = 1中的x与y的整数解(a与b互质)
    private static BigInteger[] extGCD(BigInteger a, BigInteger b) {
        if (b.signum() == 0) {
            return new BigInteger[]{a, new BigInteger("1"), new BigInteger("0")};
        } else {
            BigInteger[] bigIntegers = extGCD(b, a.mod(b));
            BigInteger y = bigIntegers[1].subtract(a.divide(b).multiply(bigIntegers[2]));
            return new BigInteger[]{bigIntegers[0], bigIntegers[2], y};
        }
    }

    //超大整数超大次幂然后对超大的整数取模,利用蒙哥马利乘模算法,
    //(base ^ exp) mod n
    //依据(a * b) mod n=(a % n)*(b % n) mod n
    private static BigInteger expMode(BigInteger base, BigInteger exp, BigInteger mod) {
        BigInteger res = BigInteger.ONE;
        //拷贝一份防止修改原引用
        BigInteger tempBase = new BigInteger(base.toString());
        //从左到右实现简答
        for (int i = 0; i < exp.bitLength(); i++) {
            if (exp.testBit(i)) {//判断对应二进制位是否为1
                res = (res.multiply(tempBase)).mod(mod);
            }
            tempBase = tempBase.multiply(tempBase).mod(mod);
        }
        return res;
    }

    //产生公钥与私钥
    public static SecretKey generateKey(BigInteger p, BigInteger q) {
        //令n = p * q。取 φ(n) = (p-1) * (q-1)。
        BigInteger n = p.multiply(q);
        //计算与n互质的整数个数 欧拉函数
        BigInteger fy = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));
        //取 e ∈ [1 < e < φ(n) ] ,( n , e )作为公钥对,这里取65537
        BigInteger e = new BigInteger("65537");
        //计算ed与fy的模反元素d。令 ed mod φ(n)  = 1,计算d,然后将( n , d ) 作为私钥对
        BigInteger[] bigIntegers = extGCD(e, fy);
        //计算出的x不能是负数,如果是负数,则进行x=x+fy。使x为正数,但是x<fy。
        BigInteger x = bigIntegers[1];
        if (x.signum() == -1) {
            x = x.add(fy);
        }
        //返回计算出的密钥
        return new SecretKey(n, e, x);
    }

    public static SecretKey generateKey() {
        BigInteger[] pq = getRandomPQ();
        return generateKey(pq[0], pq[1]);
    }

    //加密
    public static BigInteger encrypt(BigInteger text, SecretKey.PublicKey publicKey) {
        return expMode(text, publicKey.e, publicKey.n);
    }

    //解密
    public static BigInteger decrypt(BigInteger cipher, SecretKey.PrivateKey privateKey) {
        return expMode(cipher, privateKey.d, privateKey.n);
    }

    //加密
    public static String encrypt(String text, SecretKey.PublicKey publicKey) {
        return encrypt(new BigInteger(text.getBytes()), publicKey).toString();
    }

    //解密
    public static String decrypt(String chipper, SecretKey.PrivateKey privateKey) {
        BigInteger bigInteger = expMode(new BigInteger(chipper), privateKey.d, privateKey.n);
        byte[] bytes = new byte[bigInteger.bitLength() / 8 + 1];
        for (int i = 0; i < bytes.length; i++) {
            for (int j = 0; j < 8; j++) {
                if (bigInteger.testBit(j + i * 8)) {
                    bytes[bytes.length - 1 - i] |= 1 << j;
                }
            }
        }
        return new String(bytes);
    }

    //产生两个随机1024位大质数
    public static BigInteger[] getRandomPQ() {
        BigInteger p = BigInteger.probablePrime(numLength, new Random());
        while (!p.isProbablePrime(accuracy)) {
            p = BigInteger.probablePrime(numLength, new Random());
        }
        BigInteger q = BigInteger.probablePrime(numLength, new Random());
        while (!q.isProbablePrime(accuracy)) {
            q = BigInteger.probablePrime(numLength, new Random());
        }
        return new BigInteger[]{p, q};
    }

    //密匙对
    static class SecretKey {
        BigInteger n, e, d;

        public SecretKey(BigInteger n, BigInteger e, BigInteger d) {
            this.n = n;
            this.e = e;
            this.d = d;
        }

        public PublicKey getPublicKey() {
            return new PublicKey(n, e);
        }

        public PrivateKey getPrivateKey() {
            return new PrivateKey(n, d);
        }

        //密钥
        static class PrivateKey {
            public BigInteger n, d;

            public PrivateKey(BigInteger n, BigInteger d) {
                this.n = n;
                this.d = d;
            }
        }

        //公钥
        static class PublicKey {
            public BigInteger n, e;

            public PublicKey(BigInteger n, BigInteger e) {
                this.n = n;
                this.e = e;
            }
        }
    }


    public static void main(String[] args) {
        SecretKey secretKey = RSA.generateKey();
        //明文内容不要超过1024位,超过后需要分段加密
        String text = "Hello world";
        String chipper = RSA.encrypt(text, secretKey.getPublicKey());

        System.out.println("加密后:\n" +
                //密文长度可能会随着随机密钥的改变而改变,最长不超过2048位
                "密文二进制长度:" + new BigInteger(chipper).bitLength()
                + "\n"
                + chipper);
        String origin = RSA.decrypt(chipper, secretKey.getPrivateKey());
        System.out.println("解密后:\n" + origin);
    }
}


  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值