# RSA加密（可逆）

#### RSA加密：

RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。

#### 非对称加密算法：

非对称加密算法需要两个密钥：

* 公开密钥（publickey: 简称公钥）
* 私有密钥（privatekey: 简称私钥）
* 公钥与私钥是一对，如果用公钥对数据进行加密，只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥，所以这种算法叫作非对称加密算法。

#### 注意：

* 使用时都是使用公匙加密使用私匙解密。公匙可以公开，私匙自己保留。
* 算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂，而使得加密解密速度没有对称加密解密的速度快。

#### 使用流程和场景介绍

通过公匙加密，使用私匙解密。私匙是通过公匙计算生成的。假设ABC三方之间相互要进行加密通信。大家相互之间使用公匙进行信息加密，信息读取时使用各自对应的私匙进行信息解密

用户输入的支付密码会通过RSA加密

#### 公钥私钥生成方式：

公私匙可以在线生成 <http://web.chacuo.net/netrsakeypair>

#### 环境安装：npm install jsencrypt

### 代码实现

#### JS代码示例：

```javascript
window = globalThis;
const JSEncrypt = require('jsencrypt');

var PUBLIC_KEY = '-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcekx7v5PI5bR27IkW7b3Dr3xtlSUZQM6sWrwSqZkry5MNKZYYESTCQsJ5TvV5Bv72HgaN9B+3iRJA6LZwMoiC0qJ8sfRqzxTgcjZOwRyLuYQLpDNZn7Rz19XX+lgKK1eA146NFyYFQy800K+wAptcO6ZX9Ivnl8p/uV5BsWTIVQIDAQAB-----END PUBLIC KEY-----';
//私钥
var PRIVATE_KEY = '-----BEGIN RSA PRIVATE KEY-----MIICWwIBAAKBgQCcekx7v5PI5bR27IkW7b3Dr3xtlSUZQM6sWrwSqZkry5MNKZYYESTCQsJ5TvV5Bv72HgaN9B+3iRJA6LZwMoiC0qJ8sfRqzxTgcjZOwRyLuYQLpDNZn7Rz19XX+lgKK1eA146NFyYFQy800K+wAptcO6ZX9Ivnl8p/uV5BsWTIVQIDAQABAoGAB7X5HeH/aNd08KVQThpyDvoPUiEW3ms0pAamnO7RlvhlqzDg7heuLYp3pd2vuAKRvtQU85rTk0pEZYFyOA4tbt0l7t/TaWhphM589iTqhAKrunspyy4NR2afrYwJswCO5C7v5mXnF3/ez7CV17Hv+HxPfNtkWRrK4lmGKdHZuDECQQC590NewmuTMfDWlcuw1uwOPcerRxZCF4OTxs7zntiYemDQqcFP6QlGHcmGeaNTkr4fd+rQZzF0nZY9 /hsipe/9AkEA12ge6GWfVQVIJq8B+7qDE+QUGjG3JpBWplipsBotJ2IUgcEjTqGBZtQFMwW2dMwaBna0465nA/vfbAk0Y5SNOQJAfilGdkn1yzVtS1byijU0jfDRvdwLOKlVJXMRwWs5TDBx7/3KXNke5oecyXNKH4+FFjo3fk0T2yZx3/q9FAN5TQJANZTSy2Ar6AwuTGEQDzvvywza60Eem9sfkrVPUFzSio9dJoGSdMa714Y53N0464ixmJYCnPgO6/DFPKx1eafEEQJASvz8S+ZN7nnBjkAx00F4nStejzAuIztBad0jmdO9uulcuAdPNdy1Y18IczEAxNSO6VJkc4BldCoc6+9dWEbnAw==-----END RSA PRIVATE KEY-----';
//使用公钥加密
var encrypt = new JSEncrypt(); //实例化加密对象
encrypt.setPublicKey(PUBLIC_KEY); //设置公钥
// 待加密的明文
text = 'Hello world!'
var encrypted = encrypt.encrypt(text); //对指定数据进行加密
console.log(encrypted);//使用私钥解密

//使用私钥解密
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(PRIVATE_KEY); //设置私钥
var uncrypted = decrypt.decrypt(encrypted); //解密
console.log(uncrypted);
```

默认 JSEncrypt 使用 Base64 编码，无法直接处理 UTF-8 中文字符。 如果加密 UTF-8 字符（如中文），解密后可能乱码。

加密前先将 UTF-8 文本转换为 Base64（确保字符完整）。 解密后再将 Base64 转换回 UTF-8。

**改进版本**（支持 UTF-8）**：**

```javascript
window = globalThis;
const JSEncrypt = require('jsencrypt');

// 1. 定义公私钥
var PUBLIC_KEY = '-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcekx7v5PI5bR27IkW7b3Dr3xtlSUZQM6sWrwSqZkry5MNKZYYESTCQsJ5TvV5Bv72HgaN9B+3iRJA6LZwMoiC0qJ8sfRqzxTgcjZOwRyLuYQLpDNZn7Rz19XX+lgKK1eA146NFyYFQy800K+wAptcO6ZX9Ivnl8p/uV5BsWTIVQIDAQAB-----END PUBLIC KEY-----';
var PRIVATE_KEY = '-----BEGIN RSA PRIVATE KEY-----MIICWwIBAAKBgQCcekx7v5PI5bR27IkW7b3Dr3xtlSUZQM6sWrwSqZkry5MNKZYYESTCQsJ5TvV5Bv72HgaN9B+3iRJA6LZwMoiC0qJ8sfRqzxTgcjZOwRyLuYQLpDNZn7Rz19XX+lgKK1eA146NFyYFQy800K+wAptcO6ZX9Ivnl8p/uV5BsWTIVQIDAQABAoGAB7X5HeH/aNd08KVQThpyDvoPUiEW3ms0pAamnO7RlvhlqzDg7heuLYp3pd2vuAKRvtQU85rTk0pEZYFyOA4tbt0l7t/TaWhphM589iTqhAKrunspyy4NR2afrYwJswCO5C7v5mXnF3/ez7CV17Hv+HxPfNtkWRrK4lmGKdHZuDECQQC590NewmuTMfDWlcuw1uwOPcerRxZCF4OTxs7zntiYemDQqcFP6QlGHcmGeaNTkr4fd+rQZzF0nZY9 /hsipe/9AkEA12ge6GWfVQVIJq8B+7qDE+QUGjG3JpBWplipsBotJ2IUgcEjTqGBZtQFMwW2dMwaBna0465nA/vfbAk0Y5SNOQJAfilGdkn1yzVtS1byijU0jfDRvdwLOKlVJXMRwWs5TDBx7/3KXNke5oecyXNKH4+FFjo3fk0T2yZx3/q9FAN5TQJANZTSy2Ar6AwuTGEQDzvvywza60Eem9sfkrVPUFzSio9dJoGSdMa714Y53N0464ixmJYCnPgO6/DFPKx1eafEEQJASvz8S+ZN7nnBjkAx00F4nStejzAuIztBad0jmdO9uulcuAdPNdy1Y18IczEAxNSO6VJkc4BldCoc6+9dWEbnAw==-----END RSA PRIVATE KEY-----';

// 2. 定义 UTF-8 文本
var plaintext = "你好，世界！"; // 这段文本包含中文

// 3. 转换 UTF-8 为 Base64（确保兼容）
var utf8_to_base64 = (text) => Buffer.from(text, 'utf-8').toString('base64');
var base64_to_utf8 = (text) => Buffer.from(text, 'base64').toString('utf-8');

var base64_plaintext = utf8_to_base64(plaintext);

// 4. 加密
var encrypt = new JSEncrypt();
encrypt.setPublicKey(PUBLIC_KEY);
var encrypted = encrypt.encrypt(base64_plaintext);
console.log("加密后的数据:", encrypted);

// 5. 解密
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(PRIVATE_KEY);
var decrypted_base64 = decrypt.decrypt(encrypted);

// 6. 转换回 UTF-8
var decrypted_text = base64_to_utf8(decrypted_base64);
console.log("解密后的数据:", decrypted_text);

```

#### Python代码示例：

1.创建公钥和私钥

```python
from Crypto.PublicKey import RSA

# 1. 生成 1024 位 RSA 密钥对
rsakey = RSA.generate(1024)

# 2. 保存公钥到文件
with open("rsa.public.pem", mode="wb") as f:
    f.write(rsakey.publickey().exportKey())

# 3. 保存私钥到文件
with open("rsa.private.pem", mode="wb") as f:
    f.write(rsakey.exportKey())

```

2.加密算法实现

```python
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64

data = "Hello world!"

# 1. 读取公钥
with open("rsa.public.pem", mode="r") as f:
    pk = f.read()
    rsa_pk = RSA.importKey(pk)  # 导入公钥

    # 2. 创建 RSA 加密器（使用 PKCS1_v1_5 填充）
    rsa = PKCS1_v1_5.new(rsa_pk)

    # 3. 加密数据
    result = rsa.encrypt(data.encode("utf-8"))

    # 4. 转换为 Base64 方便存储和传输
    b64_result = base64.b64encode(result).decode("utf-8")
    print(b64_result)​
```

3.解密算法实现

```python
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64

# 1. 加密后的数据（Base64 编码的密文）
data = 'XkBp7xaomVVJhaYMW/7ELTUcP+3wZOlIMxVKqr0Kr9vUkk48tKsMVkAmwu++4HM3dcmcZd17vC1dxEqmS2LUiM81EbwbFqS8jjOwSjG8uTKZc3hnULU9pOdOt3WHSbUNoFnmq0piGoYJfrv2uDXwQr0ZZDL65Hj8U89U6wDrxOw='

# 2. 读取私钥
with open("rsa.private.pem", mode="r") as f:
    prikey = f.read()
    rsa_pk = RSA.importKey(prikey)  # 导入私钥

    # 3. 创建 RSA 解密器（PKCS1_v1_5 模式）
    rsa = PKCS1_v1_5.new(rsa_pk)

    # 4. Base64 解码密文，并解密
    result = rsa.decrypt(base64.b64decode(data), None)

    # 5. 输出解密后的明文
    print("rsa解密数据:::", result.decode("utf-8"))
```

上述代码提取关键字：

* RSA
* setPublicKey（设置公钥）
* setPrivateKey（设置私钥）
* encrypt,decrypt
