Java 使用 RSA算法 进行前后端加密解密

文章目录

    • 使用RSA対前后端的消息进行加密和解密
      • 前端
        • 1. 安装依赖:`pip install`
        • 2. ts文件中导入依赖:`import forge from 'node-forge'`
        • 3. 选择加密方式
        • 4. 查看帮助文档:[Forge的Github链接](https://github.com/digitalbazaar/forge?tab=readme-ov-file#rsa)
        • 5. 前端生成公钥和私钥测试一下
        • 6. 实际生产环境中,肯定公钥是从后端获取的,私钥拿不到
        • 7. 那么我们通过测试一下前端加密和解密操作
        • 8. 最后一步骤,删除不需要的代码:解密操作,公钥从后端获取
      • 后端
        • 1. 生成公钥和私钥
        • 2. 利用公钥加密(虽然这是在前端做的)
        • 3. 利用私钥进行解密
        • 4. 下面过程是完整的过程:SpringBoot项目中

使用RSA対前后端的消息进行加密和解密

前端

  • 帮助文档:Forge的Github链接

  • 步骤:

1. 安装依赖:pip install
2. ts文件中导入依赖:import forge from 'node-forge'
3. 选择加密方式
 例如指定:RSA/ECB/OAEPWithSHA-256AndMGF1Padding

 - **RSA**: 这表示使用 RSA 加密算法。
 - **ECB**: 这表示使用电子密码本 (Electronic Codebook) 模式进行加密。ECB 模式是一种基本的块加密模式,将明文分成固定大小的块,然后分别用密钥加密。
 - **OAEPWithSHA-256AndMGF1Padding**: 这表示使用 OAEP (Optimal Asymmetric Encryption Padding) 填充方案进行填充,并指定了哈希算法 SHA-256 和 MGF1 (Mask Generation Function 1) 作为填充方案的一部分。OAEP 是一种针对 RSA 加密算法设计的填充方案,旨在提供更好的安全性和随机性,以及防止对明文的长度或结构进行分析。

 综合起来,"RSA/ECB/OAEPWithSHA-256AndMGF1Padding" 表示使用 RSA 加密算法,采用 ECB 模式进行加密,并使用 OAEP 填充方案,其中哈希算法为 SHA-256,MGF1 作为填充方案的一部分。
4. 查看帮助文档:Forge的Github链接

Java 使用 RSA算法 进行前后端加密解密_第1张图片

 注释还贴心指定了Java参数是什么样子,你可一观察一下不同位置设置的对应关系推到一下你的参数设置;
5. 前端生成公钥和私钥测试一下
 ```ts
 export const $encryptMessage = (plaintext: any, publicKeyString: any) => {
     console.log("@5")
     // 生成一个 2048 位的 RSA 密钥对
     var keypair = forge.pki.rsa.generateKeyPair({ bits: 2048, e: 0x10001 });
 
     // 获取生成的公钥和私钥
     const publicKey = keypair.publicKey;
     const privateKey = keypair.privateKey;
   
     // 将待加密的字符串转换为字节数组
     var dataBytes = forge.util.encodeUtf8(plaintext);
 
     // 加密数据
     var encryptedBytes = publicKey.encrypt(dataBytes, 'RSA-OAEP', {
         md: forge.md.sha256.create(),
         mgf1: {
             md: forge.md.sha1.create()
         }
     });
 
     // 将加密后的字节数组转换为 Base64 编码的字符串
     var encryptedBase64 = forge.util.encode64(encryptedBytes);
     console.log("加密后数据", encryptedBase64);
 
     // 使用私钥解密数据
     var receivedEncryptedBytes = forge.util.decode64(encryptedBase64);
     var decryptedBytes = privateKey.decrypt(receivedEncryptedBytes, 'RSA-OAEP', {
         md: forge.md.sha256.create()
     });
 
     // 将解密后的字节数组转换为字符串
     var decryptedPlaintext = forge.util.decodeUtf8(decryptedBytes);
 
     console.log("Original plaintext:", plaintext);
     console.log("Decrypted plaintext:", decryptedPlaintext);
 ```
6. 实际生产环境中,肯定公钥是从后端获取的,私钥拿不到
 ------

 注意一下钥匙的格式为PEM格式:PEM 格式的数据通常以 `-----BEGIN` 开头,以 `-----END` 结尾,之间是经过 Base64 编码的数据。这种格式常用于存储和传输各种类型的密钥、证书等信息。

 ```vbnet
 公钥:
 -----BEGIN PUBLIC KEY-----
 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjgRrqVP+D+CZCHr++8Bs
 e+mQ/Wjt0lW9zkp6bghQAfg3wR5XmYYOFWs/0lqWYgCYiwSX+iFQap6+dtkuE7jP
 HjU6d9I0hXXSoUIMaxo2WA3IfXI45n2tRHPInCTgCoPNpHtycfMaaboBQ99altqd
 TvOylEiEgdZZ4v8Elksi9F7suvx7cCy2yJFF5rK0PtVEUMYe31EFWuKDlMyUvXcn
 8aU/81v2Z+cxyIph9WL4kVFo8qV3R+eFilbm/gPFSl5YXra16aUxwWEFvZVsNoK9
 zHNA0K4XjzF1eGk99M28B65gM5FIdKQ6SF3CdKk9C1mYCAVX6WeOC1i+5XNGJRry
 nwIDAQAB
 -----END PUBLIC KEY-----
 私钥:
 -----BEGIN RSA PRIVATE KEY-----
 MIIEpAIBAAKCAQEA3F0fXoAC5elYAYU27JQ61iD/GKc+Km3LHV4J+7JNNfX7JzoY
 2fYgbVc+JJESmISs8O2z6LsjSQQ6VG2ukYcEZwIiq++HebZOHimIBLLaKry7NmQ3
 BJpJ8Y70jY2xqOQ29S+Z1Z+1HKnmUl44xJ5UG1C3ZoCYvh/PzPqC3Mfk2mT/rV2m
 UCj9g83eazw/e0ONi5DqcXyKq0EQW0rE4rZVHLuw4pNgRXwWLO5qSgN+4YhOfNpH
 ...此处省略私钥长一点....
 -----END RSA PRIVATE KEY-----
 ```

 --------

 如果你的公钥和私钥只有中间部分,就需要转换

 ```ts
 function convertToPublicPem(publicKeyBase64: string): string {
     const lines = [];
     lines.push('-----BEGIN PUBLIC KEY-----');
     for (let i = 0; i < publicKeyBase64.length; i += 64) {
         lines.push(publicKeyBase64.slice(i, i + 64));
     }
     lines.push('-----END PUBLIC KEY-----');
     return lines.join('\n');
 }
 function convertToPrivatePem(privateKeyBase64: string): string {
     const lines = [];
     lines.push('-----BEGIN PRIVATE KEY-----');
     for (let i = 0; i < privateKeyBase64.length; i += 64) {
         lines.push(privateKeyBase64.slice(i, i + 64));
     }
     lines.push('-----END PRIVATE KEY-----');
     return lines.join('\n');
 }
 ```
7. 那么我们通过测试一下前端加密和解密操作
 (通常加密在前端,解密在后端,为了你好定位问题,提供加密和解密,代码写错了是无法解密的)

 ```ts
 console.log("@5")
     // 生成一个 2048 位的 RSA 密钥对
     // var keypair = forge.pki.rsa.generateKeyPair({ bits: 2048, e: 0x10001 });
 
     // 获取生成的公钥和私钥
     // const publicKey = keypair.publicKey;
     // const privateKey = keypair.privateKey;
     // 从 PEM 格式的字符串加载公钥和私钥
     console.log("@4")
     var publicKeyString1 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjgRrqVP+D+CZCHr++8Bse+mQ/Wjt0lW9zkp6bghQAfg3wR5XmYYOFWs/0lqWYgCYiwSX+iFQap6+dtkuE7jPHjU6d9I0hXXSoUIMaxo2WA3IfXI45n2tRHPInCTgCoPNpHtycfMaaboBQ99altqdTvOylEiEgdZZ4v8Elksi9F7suvx7cCy2yJFF5rK0PtVEUMYe31EFWuKDlMyUvXcn8aU/81v2Z+cxyIph9WL4kVFo8qV3R+eFilbm/gPFSl5YXra16aUxwWEFvZVsNoK9zHNA0K4XjzF1eGk99M28B65gM5FIdKQ6SF3CdKk9C1mYCAVX6WeOC1i+5XNGJRrynwIDAQAB";
     var privateKeyString ="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCOBGupU/4P4JkIev77wGx76ZD9aO3SVb3OSnpuCFAB+DfBHleZhg4Vaz/SWpZiAJiLBJf6IVBqnr522S4TuM8eNTp30jSFddKhQgxrGjZYDch9cjjmfa1Ec8icJOAKg82ke3Jx8xppugFD31qW2p1O87KUSISB1lni/wSWSyL0Xuy6/HtwLLbIkUXmsrQ+1URQxh7fUQVa4oOUzJS9dyfxpT/zW/Zn5zHIimH1YviRUWjypXdH54WKVub+A8VKXlhetrXppTHBYQW9lWw2gr3Mc0DQrhePMXV4aT30zbwHrmAzkUh0pDpIXcJ0qT0LWZgIBVfpZ44LWL7lc0YlGvKfAgMBAAECggEADZIZkZwvlmfRZ9CNBhSMqUiX7Mc2lpdP5GMUkOglcRK9jSwvlcGMHfraJek3HpVM/lfJiALf8thJfgTh1MufqxTOCf4hu7EXGAa+NgvSrpZelrIwAsJ2qKhhvp39dLPEllefh4kB+KFoForE1s58IrvB0E6fruKDQ2A4GX6DkBNPlAykT7a8KrO1dqBJe8jtjf4CiOCR6Y6j0hq4tz12dZXO1FY5/gFcq7Oj5j4k1iXAPGkVLS7cZYUQhfsXfiP75q/y/hyUbYsVDW6xBWidfyc8cCNRo8fDnC8MDLa0H5TRAe+mWkYKX6M1ZSpo3E2LDTizVr7GaMBwgZ9yxmvA1QKBgQC2F1ymUQexGXecYBsHlesH0ulOlU90XptH0fMDXxR+Z7ae5gK4QAZePRZNofatOyyQGQ1+u21d9mOLv7Wm/HcTofVYODQTEBheFlbzpYZ5ciLUfuYXNmRgQlnZFkP/x3xA+lVhuCEyE87liQ+iH3FCFHh9X2mAoAim7hN8J5SpBQKBgQDHqRKVW4UXSN5sQYn0j8yGPUB5Q5BCrZCn38T+NWXNPnXBcTY80VhOZtWR41+9zdowDp7AzOZV6xWMn1hrt9xaMP+tcbB1iIcc6XTxcHDVzppt8HXIqqnpXxM041Sz1rEGW/lcNADZabJIWn2AE4XDiP2iX+IV3AU27dS5tKhuUwKBgCgX0MCWCtmFv/5gctMiwVNBrzksSwhWZF5V7eoKH1sNvvoRrvuerUhGrwh85vGRm+hGe+AxqI0N2TFGDtsrr5RVDs5T4bNo0dS1moOfKJLI/L5JCqSFx2gic+IGswY4iDVOaUpQ3o5GKkIEAbsyrR9dnoIMZhB6LC2FMikeFe95AoGBAMa5o8OBOjD42FmLyhHfZsReBuQruVSEiKxubxZOc6sbdf05/6/89hXjCMOSOmMilv6qLpzb1I7D08kJeOqOMAadKn6p3+a8Iy9Ftp3xOn20i8TNR46ZP1EGzokfk9kD4WLg/IsnP4kmSMr3Nl7aD5OVsE2DffYf7hjEE61bASH9AoGAFGDQg/ym2KwNqpt1xOVdpXpVTrkwKCqMiugcMEnFo3YaiODGH8wPqGjbkrbF+xlHZZK2tmcPpSzo2AidgSUAsgna6mYpSlLb9mfQTzMufMk7H27dUwjXKfhZdZkOnHaUy07ElokbjItGv8zedJBrzzz8hQdfy6id+vLJda0OFFI=";
     console.log("@3")
     const publicKey = forge.pki.publicKeyFromPem(convertToPublicPem(publicKeyString1));
     console.log("@2")
     const privateKey = forge.pki.privateKeyFromPem(convertToPrivatePem(privateKeyString));
     console.log("@1")
     // 将待加密的字符串转换为字节数组
     var dataBytes = forge.util.encodeUtf8(plaintext);
 
     // 加密数据
     var encryptedBytes = publicKey.encrypt(dataBytes, 'RSA-OAEP', {
         md: forge.md.sha256.create(),
         mgf1: {
             md: forge.md.sha1.create()
         }
     });
 
     // 将加密后的字节数组转换为 Base64 编码的字符串
     var encryptedBase64 = forge.util.encode64(encryptedBytes);
     console.log("加密后数据", encryptedBase64);
 
     // 使用私钥解密数据
     var receivedEncryptedBytes = forge.util.decode64(encryptedBase64);
     var decryptedBytes = privateKey.decrypt(receivedEncryptedBytes, 'RSA-OAEP', {
         md: forge.md.sha256.create()
     });
 
     // 将解密后的字节数组转换为字符串
     var decryptedPlaintext = forge.util.decodeUtf8(decryptedBytes);
 
     console.log("Original plaintext:", plaintext);
     console.log("Decrypted plaintext:", decryptedPlaintext);
 ```
8. 最后一步骤,删除不需要的代码:解密操作,公钥从后端获取
 ```
 //获取公钥
 export const $getPublicKey = async ()=>{
     const {data} = await $post(UserApi.getPublicKey,"");
     return data
 }
 function convertToPublicPem(publicKeyBase64: string): string {
     const lines = [];
     lines.push('-----BEGIN PUBLIC KEY-----');
     for (let i = 0; i < publicKeyBase64.length; i += 64) {
         lines.push(publicKeyBase64.slice(i, i + 64));
     }
     lines.push('-----END PUBLIC KEY-----');
     return lines.join('\n');
 }
 // 加密消息
 export const $encryptMessage = (plaintext: any, publicKeyString: any) => {
     const publicKey = forge.pki.publicKeyFromPem(convertToPublicPem(publicKeyString));
     // 将待加密的字符串转换为字节数组
     var dataBytes = forge.util.encodeUtf8(plaintext);
     // 加密数据
     var encryptedBytes = publicKey.encrypt(dataBytes, 'RSA-OAEP', {
         md: forge.md.sha256.create(),
         mgf1: {
             md: forge.md.sha1.create()
         }
     });
     // 将加密后的字节数组转换为 Base64 编码的字符串
     var encryptedBase64 = forge.util.encode64(encryptedBytes);
     console.log("加密后数据", encryptedBase64);
     return encryptedBase64;
 }
 
 
 export const $login = async (params:any)=>{
     try{
         const publicKey = await $getPublicKey()
         params.password = $encryptMessage(params.password, publicKey)
         xxxx发送请求xxxx
 	}catch (error) {
         console.error('登录时发生错误:', error);
         throw error; // 将错误继续向外抛出
     }
 }
 ```

后端

1. 生成公钥和私钥
if (publicKey == null && privateKey == null) {
   
            try {
   
                KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
                keyGen.initialize(2048);
                KeyPair pair = keyGen.generateKeyPair();
                // 保存公钥和私钥
                publicKey = pair.getPublic();
                privateKey = pair.getPrivate();
                // 输出公钥和私钥的Base64编码值
                log.info("RSA密钥生成成功: 公钥={}, 私钥={}", 		
                         Base64.getEncoder().encodeToString(publicKey.getEncoded()), 
                         Base64.getEncoder().encodeToString(privateKey.getEncoded()));
            } catch (Exception e) {
   
                log.error("初始化RSA密钥失败:", e.getMessage());
            

你可能感兴趣的:(java,算法,开发语言,javascript)