图解密码技术——RSA 公钥密码算法

公钥密码

公钥密码(Public-key cryptography)也称为非对称密码。是一种基于密钥对的密码体制。他需要两个密钥:公开密钥(public key )和私有密钥(private key)。一般使用公钥加密,私钥解密。

RSA

什么是 RSA ?

RSA 是一种公钥密码算法,是目前使用最广泛的公钥密码算法。RSA 三个字母的含义是:它的三位发明者的姓氏首字母——

Ron Rivest、Adi Shamir 和 Leonard Adleman(Rivest Shamir Adleman)。

在详细介绍 RSA 之前,需要先普及一点数学知识。

取模(余数)

我们知道在编程语言中有取模运算,取模运算就是求余数的运算。例如:

我们要计算 12 除以 5 的余数,运算过程为:

  1. 12 中有几个 5?答案是 2 个。因为 5 * 2 = 10, 5 * 3 = 15 。所以 12 中只包含 2 个 5
  2. 那么两个 5 相乘不够 12 ,还差多少呢?12 - 10 = 2,这个 2 就是余数。
  3. 那么上述过程用Java 编程语言表示就是:System.out.println(12 % 5);
  4. 这是简单的取模运算,那么我在来搞的复杂一点,12 这个数字可以分解为 2 * 2 * 2 * 2,也就是 24
  5. 我们来写一次取模的运算 24 mod 5

我们简单回顾了十几二十年前的知识,如果你理解了上面的过程那么你就已经为详细学习 RSA 打好了基础,因为 RSA 的加密解密过程所进行的就是上述运算

RSA 加密

RSA 加密的过程

在 RSA 中,明文、密文、密钥都是用数字表示的。RSA 加密的过程可以用下面的公式来表示:

密文 = 明文E mod N RSA 加密

我们来对比取模中第五步骤:**我们来写一次取模的运算 24 mod 5。是不是很像?

没错,RSA 的加密过程就是明文的 E 次方然后 mod N 的结果。

公式中的E 和 N

我们上面公示中有两个中文词:密文、明文。很容易理解是什么意思。那么,公式中的 E 和 N 是什么意思呢?

别忘了,RSA属于公钥密码算法的一种。公式中的 E 和 N 参与了 RSA 的加密运算过程,那无论是谁知道 E 和 N 的值都是可以进行 RSA 加密的(这也就是常说的任何人都可以使用公钥来加密数据,但是解密就不行了)。所以,E 和 N就是 RSA 的密钥。注意,这里提到了密钥而不是公钥。E 和 N这两个数字的组合才算是 RSA 的公钥。

到这里,我相信你们已经明白了 RSA 的加密就是“ 明文 E 次方的mod N”。接下来, 我们来了解下 RSA 的解密。

RSA 解密

RSA 的解密和加密一样简单。公式如下

明文 = 密文D mod N RSA 解密

是不是很直观。我们可以把解密的过程描述为:密文 D 次方mod N 等于明文。换句话说就是将密文和自己做 D 次的乘法,然后再用结果除以 N 取余数,就可以得到明文。

注意🚩:这里使用到的 N 和加密的 N 是同一个数字

根据上面 RSA 加密公式中 E 和 N 的规律我们可以直观的看出来,解密公式中的 D 和 N 就是 RSA 解密用到的密钥,而这两个数字的组合就是私钥

RSA 加密解密图示

image-20230826225041270

Java 语言实现 RSA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static void main(String[] args) throws Exception {
// 生成公钥和私钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();

// 明文
String plainText = "hello RSA";

// 使用公钥加密
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] secretMessage = encryptCipher.doFinal(plainText.getBytes());

System.out.println(new String(secretMessage)); // 加密后的内容

// 使用私钥解密
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedMessage = decryptCipher.doFinal(secretMessage);

System.out.println(new String(decryptedMessage)); // hello RSA
}

上面的代码首先使用 KeyPairGenerator 类生成一对公钥和私钥。然后定义一个明文字符串 “hello RSA”。接下来,使用公钥和 Cipher 类的 ENCRYPT_MODE 对明文进行加密,加密后的密文是一个字节数组。然后,使用私钥和 Cipher 类的 DECRYPT_MODE 对密文进行解密,得到的结果是一个字节数组,将其转换为字符串,就得到了原始的明文。

注意,这个示例中使用了 2048 位的密钥,这是因为对于 RSA 加密,密钥的长度越长,安全性就越高,但同时加密和解密所需的时间也会增加。