首页 > 编程语言 >钥匙对对碰:RSA加密解密(数字版&字符串版)JAVA实现

钥匙对对碰:RSA加密解密(数字版&字符串版)JAVA实现

时间:2024-10-19 13:17:57浏览次数:3  
标签:BigInteger 公钥 加密 对对碰 RSA 解密 字符串 私钥 JAVA

钥匙对对碰:RSA加密解密(数字版)

RSA加密的原理其实很简单,就是你有两把钥匙,一把叫公钥,一把叫私钥。这两把钥匙都有很特别的性质:用公钥加锁(加密)之后,只能用对应的私钥来解锁(解密),反过来也一样。我们来一步步看看它是怎么实现的。


1. 找两把钥匙的“材料”

要做出公钥和私钥,首先需要两个特别的数字,我们叫它们 pq。它们必须是大质数,也就是除了1和它自己,没其他能整除它的数。为啥要质数呢?因为质数特别难分解,能保证“锁”比较安全。

接着我们把 pq 乘起来,得到一个新的数字,叫它 n。这个 n 是加密和解密时的一个重要“模数”,用来限制加密结果不会太大。

然后我们用公式 φ(n) = (p - 1) * (q - 1) 算出一个特别的数,这个数用来帮助我们生成钥匙。


2. 制作公钥(锁)

公钥其实就是两个数字,en

  • e 是一个和 φ(n) 互质的数,通常我们选一个常用的数,比如 65537,这样大家都能认出来。
  • n 是刚才我们算出来的,和 e 组成了公钥。

这个公钥可以用来“加锁”——也就是加密。


3. 制作私钥(解锁工具)

私钥是用来解密的。为了让它能解锁,我们得通过一个公式:(d * e) % φ(n) = 1 来算出私钥 d。这个 d 是啥意思呢?它就是 e 的“模逆元”,意思就是用这个数和 e 一起配合,能解开锁住的东西。


4. 加密:公钥加锁

我们用公钥加密。假设你有个数字 m(比如一条消息的数字表示),想加密它。用下面这个公式:
c = (m^e) % n
这就把 m 通过 en 转换成了密文 c。这样别人只要拿到 c,他们也不知道原本的 m 是啥,因为没有私钥解锁。


5. 解密:私钥解锁

如果你有私钥 d,你就可以用下面的公式:
m = (c^d) % n
把密文 c 重新解成明文 m。这个公式其实就是反过来用公钥加密的步骤,解出来的就是原始的消息。


代码

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

public class KeyPairMatchRSA {

    // n是锁和钥匙的共同基础, e是公钥(锁),d是私钥(解锁器)
    private BigInteger n; 
    private BigInteger e; // 公钥
    private BigInteger d; // 私钥

    // 构造函数:生成钥匙对(公钥和私钥)
    public KeyPairMatchRSA(int bitLength) {
        // 1. 找到两把钥匙的材料:两个大质数 p 和 q
        BigInteger p = BigInteger.probablePrime(bitLength, new Random());
        BigInteger q = BigInteger.probablePrime(bitLength, new Random());
        
        // 2. 把 p 和 q 乘起来得到 n
        n = p.multiply(q);
        
        // 3. 计算 φ(n),用来生成钥匙
        BigInteger phi = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));

        // 4. 制作公钥:e 和 n
        e = new BigInteger("65537"); // 通常选用 65537,大家都认得

        // 5. 制作私钥:d,通过公式求逆元
        d = e.modInverse(phi);
    }

    // 加密方法,用公钥 e 加密(加锁)
    public BigInteger encrypt(BigInteger message) {
        // 密文 c = (m^e) % n
        return message.modPow(e, n);
    }

    // 解密方法,用私钥 d 解密(解锁)
    public BigInteger decrypt(BigInteger cipherText) {
        // 明文 m = (c^d) % n
        return cipherText.modPow(d, n);
    }

    // 主函数:模拟加密和解密过程
    public static void main(String[] args) {
        // 生成钥匙对,bitLength 是密钥长度,越大越安全,512是个基础长度
        KeyPairMatchRSA rsa = new KeyPairMatchRSA(512);

        // 需要加密的消息,比如 "123456789",我们用大数来表示这个消息
        BigInteger message = new BigInteger("123456789");
        System.out.println("原始消息: " + message);

        // 使用公钥加密(加锁)
        BigInteger cipherText = rsa.encrypt(message);
        System.out.println("加密后的密文: " + cipherText);

        // 使用私钥解密(解锁)
        BigInteger decryptedMessage = rsa.decrypt(cipherText);
        System.out.println("解密后的明文: " + decryptedMessage);
    }
}

在这里插入图片描述

代码讲解:
  1. n 是用两个质数 pq 生成的,它是加密和解密的基础。
  2. e 是公钥的一部分,代表“加锁”的工具。我们这里固定用常见的 65537。
  3. d 是通过公式 (d * e) % φ(n) = 1 计算出的私钥,它是用来“解锁”的工具。
步骤
  • 先生成公钥和私钥(钥匙对)。
  • 然后,我们用 encrypt() 函数,利用公钥 en 来加密消息。
  • 最后,用 decrypt() 函数,利用私钥 d 把加密后的密文还原成明文。

总结

  • 公钥 是你可以随便告诉别人用来加密的“锁”,它负责把信息藏起来。
  • 私钥 是你自己保管的“解锁器”,它负责把加密的信息解开。
  • 别人用公钥加锁,你才能用私钥解锁。相当于你家大门,门锁给了所有人,但钥匙只有你自己有!

这样,你的通信就安全了,因为即使有人偷看了密文,没有私钥也是没法解开的!

这个 “钥匙对对碰” 的加密解密过程,核心就是通过数学公式保证只有公钥和私钥能配对工作,确保信息的安全性。

“钥匙对对碰”-RSA加密解密(字符串版)

在之前的“钥匙对对碰”里,我们是加密和解密数字的。现在,我们想对字符串(比如“linchuan”)进行加密和解密。为了让它好理解,咱们来一步一步拆开说,看看这背后的原理。


1. 字符串和数字的转换

问题来了:RSA这种数学加密方式只能处理数字,那我们想要加密的“linchuan”是个字符串怎么办?

答案是:把字符串转换成数字!

具体怎么做呢?先把字符串转换成字节数组(也就是一串数字),再把这个字节数组变成一个巨大的整数(BigInteger)。这样我们就能用RSA的数学魔法来对这个数字进行加密了!

2. 公钥加锁:加密字符串

公钥是两部分组成:en。公钥可以公开,让所有人加密消息,但只有你能解密。我们拿到转换成 BigInteger 的字符串(叫它 messageInt),然后用RSA的公式来加密:

加密公式

cipherText = (messageInt^e) % n

这个公式的意思是,拿 messageInt 乘以它自己 e 次,然后对 n 取余数,最后得到一个加密后的数字 cipherText。为了让这个加密后的东西能看懂,我们把它转换回字符串,方便传递和存储。

3. 私钥解锁:解密字符串

加密后的密文想要变回原来的明文,必须得用私钥 d 进行解锁。解密的时候,RSA有个特别的公式:

解密公式

decryptedInt = (cipherText^d) % n

它的意思是,把加密后的密文 cipherText 乘以它自己 d 次,然后再对 n 取余数,这样就得到了原来的数字 messageInt。再把这个数字转回字节数组,再转换回字符串,就得到了我们想要的原始消息。


代码

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Random;

public class StringRSA {

    // n 是锁和钥匙的共同基础, e 是公钥(加锁),d 是私钥(解锁)
    private BigInteger n;
    private BigInteger e; // 公钥
    private BigInteger d; // 私钥

    // 构造函数:生成密钥对(公钥和私钥)
    public StringRSA(int bitLength) {
        // 1. 找到两个大质数 p 和 q,作为钥匙的材料
        BigInteger p = BigInteger.probablePrime(bitLength, new Random());
        BigInteger q = BigInteger.probablePrime(bitLength, new Random());

        // 2. 计算 n = p * q,这个 n 是加密和解密都要用的
        n = p.multiply(q);

        // 3. 计算 φ(n),这个是 p-1 和 q-1 的乘积,用来帮助生成私钥
        BigInteger phi = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));

        // 4. 设置一个常见的公钥 e,通常我们选 65537(大家常用的数字)
        e = new BigInteger("65537");

        // 5. 通过公式生成私钥 d:d 是 e 的“模逆元”
        d = e.modInverse(phi);
    }

    // 加密方法:把字符串通过公钥 e 加密成密文
    public String encrypt(String message) {
        // 1. 把字符串转成字节数组,再转成一个大整数
        BigInteger messageInt = new BigInteger(message.getBytes(StandardCharsets.UTF_8));
        // 2. 用公钥 e 和 n 进行加密运算,生成密文
        BigInteger cipherText = messageInt.modPow(e, n);
        // 3. 把加密后的大整数转成字符串,返回给调用者
        return cipherText.toString();
    }

    // 解密方法:把加密后的字符串用私钥 d 解密回原始字符串
    public String decrypt(String cipherText) {
        // 1. 把密文字符串转回大整数
        BigInteger cipherInt = new BigInteger(cipherText);
        // 2. 用私钥 d 和 n 进行解密运算,得到原始的数字
        BigInteger decryptedInt = cipherInt.modPow(d, n);
        // 3. 把解密后的大整数转回字节数组,再转成字符串返回
        return new String(decryptedInt.toByteArray(), StandardCharsets.UTF_8);
    }

    // 主函数:演示加密和解密过程
    public static void main(String[] args) {
        // 生成密钥对,位长度为512位(越大越安全)
        StringRSA rsa = new StringRSA(512);

        // 需要加密的消息
        String message = "linchuan";
        System.out.println("原始消息: " + message);

        // 加密消息
        String cipherText = rsa.encrypt(message);
        System.out.println("加密后的密文: " + cipherText);

        // 解密密文
        String decryptedMessage = rsa.decrypt(cipherText);
        System.out.println("解密后的明文: " + decryptedMessage);
    }
}

在这里插入图片描述

代码解释
  1. 生成密钥对:程序首先生成了一对公钥(e, n)和私钥(d, n)。公钥用来加密,私钥用来解密。

    • e = 65537 是个常用的数字,生成私钥 d 是通过数学公式计算出来的。
    • n 是 p 和 q 两个质数的乘积,p 和 q 是加密和解密过程中非常重要的部分。
  2. 加密字符串

    • 先把需要加密的字符串(比如 "linchuan")转换成字节数组,再转换为 BigInteger 大整数。
    • 用公钥 en 来对这个大整数进行加密,得到密文,最后将密文转换成字符串返回。
  3. 解密密文

    • 将加密后的字符串密文转回 BigInteger 大整数。
    • 使用私钥 dn 来进行解密,得到原始的大整数。
    • 最后把大整数转回字节数组,再转回字符串,得出原始的明文。

总结

  1. 字符串 → 数字:把我们想加密的字符串“linchuan”转换成数字(BigInteger)。
  2. 加密:用公钥把这个数字“加锁”,加密得到一个加密后的数字密文。
  3. 解密:用私钥“解锁”,把加密后的密文再还原成原来的数字。
  4. 数字 → 字符串:再把解密后的数字转回原来的字符串,解密完成!

通过这个过程,RSA就能让字符串也能安全地加密和解密。

标签:BigInteger,公钥,加密,对对碰,RSA,解密,字符串,私钥,JAVA
From: https://blog.csdn.net/m0_63141213/article/details/143030482

相关文章