公钥私钥?一文搞懂非对称加密

非对称加密

非对称加密:

  • 通信双方分别创建公钥和私钥,
  • 并且保证公钥所加密的信息,只有配对的私钥可以解密,
  • 接下来,双方公开交换公钥,通信时,使用对方的公钥进行加密,
  • 如此,就能确保对方能够通过自己的私钥解密
    在这里插入图片描述

在这里插入图片描述

加密算法RSA

按RSA的固定步骤:
在这里插入图片描述

  1. 选择素数

    • 随机选择两个大素数,通常表示为p和q。
  2. 计算乘积

    • 计算两个素数的乘积n,即n = p * q。
  3. 计算欧拉函数

    • 计算n的欧拉函数φ(n),其中φ(n) = (p-1) * (q-1)。
  4. 选择公钥

    • 选择一个整数e,满足1 < e < φ(n),并且e与φ(n)互质。通常,公钥是一个包含两个部分的数对(e, n)。
  5. 计算私钥

    • 计算私钥d,使得e * d ≡ 1 (mod φ(n))。通常,私钥是一个包含两个部分的数对(d, n)。
  6. 加密数据

    • 使用接收者的公钥(e, n),对要传输的数据进行加密。加密操作通常是将明文m的e次方,然后取模n,得到密文c:c = m^e mod n。
  7. 解密数据

    • 接收者使用自己的私钥(d, n)对密文进行解密。解密操作通常是将密文c的d次方,然后取模n,得到明文m:m = c^d mod n。
/**
 * RSA非对称加密算法客户端
 */
@Slf4j
public class RSAClient {

    /**
     * 生成两个质数
     */
    public List<Integer> getTwoPrime() {

        List<Integer> primes = new ArrayList<>();

        int len=0;

        while (len<2) {
            Random random = new Random();
            int num = random.nextInt(500);

            if (isPrime(num)) {
                primes.add(num);
                len++;
            }
        }

        log.info("(1)生成两个质数:{}", primes);

        return primes;
    }

    private boolean isPrime(int num) {

        for (int i = 2; i < Math.sqrt(num); i++) {
            if (num % i == 0) {
                return false;
            }
        }

        return true;
    }

    /**
     * 计算n,m
     */
    public Map<String, Integer> getNAndM(List<Integer> primes) {

        if (primes.size() != 2) {
            throw new IllegalArgumentException("只接受两个质数");
        }

        Integer prime1 = primes.get(0);
        Integer prime2 = primes.get(1);

        Map<String, Integer> map = new HashMap<>();

        //核心算法
        map.put("n", prime1 * prime2);
        map.put("m", (prime1 - 1) * (prime2 - 1));

        log.info("n,m:{}", map);

        return map;
    }

    /**
     * 随机选出m的一个质数,该质数为正且小于m
     */
    public Integer getPrime(Integer m) {

        while (true) {
            Random random = new Random();
            int e = random.nextInt(m);
            while (e == 0) {
                e = random.nextInt(m);
            }
            if (getGCD(e, m) == 1) {
                return e;
            }
        }

    }

    /**
     * 欧几里得算法:a,b最大公因数等于b,a%b的最大公因数,当两数的最大公因数是1时,两数互质,初始时,a<b
     */
    private int getGCD(int a, int b) {
        if (b == 0) {
            return a;
        }
        return getGCD(b, a % b);
    }

    /**
     * 通过扩展欧几里得算法获得d,d满足:(d * e) % m =1
     */
    public int getD(int e, int m) {
        int d = 1;
        while (true) {
            if ((d * e) % m == 1) {
                break;
            }
            d++;
        }
        return d;
    }

    /**
     * 加密
     */
    public byte[] encrypt(String content,Integer n,Integer e) {

        //2.利用公钥加密
        //2.1原文转成数字串
        List<Integer> integers = new ArrayList<>();
        for (byte b : content.getBytes()) {
            integers.add(((int) b ^e) % n);
        }

        Byte[] bytes = integers.stream().map(integer -> (byte) integer.intValue()).toArray(Byte[]::new);
        byte[] result = new byte[bytes.length];
        for (int i = 0; i < bytes.length; i++) {
            result[i]= bytes[i];
        }

        return result;
    }

    /**
    * 解密
    * */
    public String decrypt(byte[] bytes,Integer n,Integer m,Integer e){

        //获取私钥
        int d = getD(e, m);
        log.info("私钥:({},{})",d,n);

        byte[] result = new byte[bytes.length];

        for (int i = 0; i < bytes.length; i++) {
            int num = bytes[i];
            result[i]= (byte) ((num^e)%n);
        }

        return new String(result);
    }

    public static void main(String[] args) {

        RSAClient rsaClient = new RSAClient();
        //计算公钥
        Map<String, Integer> nAndM = rsaClient.getNAndM(rsaClient.getTwoPrime());
        Integer n = nAndM.get("n");
        Integer m = nAndM.get("m");
        Integer e = rsaClient.getPrime(m);
        log.info("公钥:({},{})", e, n);

        //加密
        byte[] bytes = rsaClient.encrypt("hello world",n,e);
        log.info("密文:{}", new String(bytes));
        //解密
        String decrypt = rsaClient.decrypt(bytes, n, m, e);
        log.info("解密:{}",decrypt);

    }

}

效果:

2024-05-07 13:52:17 INFO  [main] c.e.p.RSAClient.(): [信息] (1)生成两个质数:[4, 127]
2024-05-07 13:52:17 INFO  [main] c.e.p.RSAClient.(): [信息] n,m:{m=378, n=508}
2024-05-07 13:52:17 INFO  [main] c.e.p.RSAClient.(): [信息] 公钥:(85508)
2024-05-07 13:52:17 INFO  [main] c.e.p.RSAClient.(): [信息] 密文:=099:u":'91
2024-05-07 13:52:17 INFO  [main] c.e.p.RSAClient.(): [信息] 私钥:(169,508)
2024-05-07 13:52:17 INFO  [main] c.e.p.RSAClient.(): [信息] 解密:hello world

RSA原理

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值