使用hutool工具类实现sm2和rsa公钥加密 私钥解密demo
1.相关依赖
dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-web-services' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' implementation 'cn.hutool:hutool-all:5.8.15' implementation 'org.bouncycastle:bcprov-jdk15on:1.70' }
2.接口
package com.ruoyi.rsa_sm2_demo.controller; import cn.hutool.crypto.SmUtil; import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.RSA; import cn.hutool.crypto.asymmetric.SM2; import io.micrometer.common.util.StringUtils; import jakarta.annotation.PostConstruct; import org.bouncycastle.crypto.engines.SM2Engine; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.util.encoders.Hex; import org.springframework.web.bind.annotation.*; import java.security.PrivateKey; import java.util.Arrays; import java.util.Base64; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/api/crypto") public class CryptoController { private RSA rsa; private SM2 sm2; @PostConstruct public void init() { // 在PostConstruct中初始化,而不是在字段声明时直接初始化 rsa = new RSA(); // 初始化SM2,使用SmUtil工具类生成密钥对,并设置为C1C3C2模式 sm2 = SmUtil.sm2(); sm2.setMode(SM2Engine.Mode.C1C3C2); sm2.usePlainEncoding(); //打印密钥信息用于调试 System.out.println("RSA公钥: " + rsa.getPublicKeyBase64()); System.out.println("RSA私钥: " + rsa.getPrivateKeyBase64()); System.out.println("SM2公钥: " + sm2.getPublicKeyBase64()); System.out.println("SM2私钥: " + sm2.getPrivateKeyBase64()); } @GetMapping("/keys") public Map<String, Object> getKeys() { Map<String, Object> keys = new HashMap<>(); // RSA密钥 keys.put("rsaPublicKey", rsa.getPublicKeyBase64()); keys.put("rsaPrivateKey", rsa.getPrivateKeyBase64()); // SM2密钥 keys.put("sm2PublicKey", sm2.getPublicKeyBase64()); keys.put("sm2PrivateKey", sm2.getPrivateKeyBase64()); return keys; } @PostMapping("/rsa/decrypt") public String rsaDecrypt(@RequestBody String encryptedData) { try { // 检查输入是否为空 if (StringUtils.isEmpty(encryptedData)) { throw new IllegalArgumentException("加密数据不能为空"); } // 执行解密 return rsa.decryptStr(encryptedData.trim(), KeyType.PrivateKey); } catch (Exception e) { throw new RuntimeException("RSA解密失败:" + e.getMessage()); } } @PostMapping("/rsa/encrypt") public String rsaEncrypt(@RequestBody String data) { try { if (StringUtils.isEmpty(data)) { throw new IllegalArgumentException("待加密数据不能为空"); } return rsa.encryptBase64(data, KeyType.PublicKey); } catch (Exception e) { throw new RuntimeException("RSA加密失败:" + e.getMessage()); } } @PostMapping("/sm2/decrypt") public String sm2Decrypt(@RequestBody Sm2Param sm2Param) { String encryptedData = sm2Param.getData(); if (StringUtils.isEmpty(encryptedData)) { throw new IllegalArgumentException("加密数据不能为空"); } try { // 预处理输入数据,移除所有空白字符 encryptedData = encryptedData.replaceAll("\\s+", ""); // 预处理输入数据,替换URL安全的Base64字符 encryptedData = encryptedData.replace('-', '+').replace('_', '/'); // 尝试Base64解码,先尝试标准Base64,如果失败则尝试URL安全的Base64 byte[] decodedBytes; try { try { decodedBytes = Base64.getDecoder().decode(encryptedData); } catch (IllegalArgumentException e) { // 如果标准Base64解码失败,尝试URL安全的Base64 decodedBytes = Base64.getUrlDecoder().decode(encryptedData); } } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Base64解码失败:请确保输入的是有效的Base64编码字符串"); } // 基本格式验证 if (decodedBytes.length < 45) { throw new IllegalArgumentException("数据格式错误:不是有效的SM2加密数据"); } // 假设 sm2 是你的 SM2 加密工具类实例 // 先获取私钥对象 String privateKey = sm2.getPrivateKeyBase64(); System.out.println(privateKey); // 执行解密 String decryptedData = sm2.decryptStr(encryptedData, KeyType.PrivateKey); if (StringUtils.isEmpty(decryptedData)) { throw new IllegalArgumentException("解密结果为空"); } return decryptedData; } catch (IllegalArgumentException e) { throw new IllegalArgumentException("SM2解密失败:" + e.getMessage()); } catch (Exception e) { throw new IllegalArgumentException("SM2解密失败:密文格式错误或密钥不匹配"); } } public static class Sm2Param{ private String data; public String getData() { return data; } public void setData(String data) { this.data = data; } } @PostMapping("/sm2/encrypt") public String sm2Encrypt(@RequestBody Sm2Param param) { String data = param.getData(); try { if (StringUtils.isEmpty(data)) { throw new IllegalArgumentException("待加密数据不能为空"); } // 去除可能的空白字符 data = data.trim(); try { // 执行加密并返回Base64编码的结果 String encryptedData = sm2.encryptBase64(data, KeyType.PublicKey); if (StringUtils.isEmpty(encryptedData)) { throw new RuntimeException("SM2加密结果为空"); } // 验证加密结果是否为有效的Base64编码 try { byte[] testDecode = Base64.getDecoder().decode(encryptedData); if (testDecode.length == 0) { throw new RuntimeException("加密结果无效:生成的Base64编码为空"); } } catch (IllegalArgumentException e) { throw new RuntimeException("加密结果格式错误:生成的不是有效的Base64编码"); } return encryptedData; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException("SM2加密失败:" + e.getMessage()); } } catch (IllegalArgumentException e) { throw new RuntimeException("SM2加密失败:" + e.getMessage()); } catch (Exception e) { throw new RuntimeException("SM2加密失败:加密过程发生错误,请检查输入数据格式"); } } }
3.前端demo
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>加密解密演示</title> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> </head> <body> <h2>RSA加解密演示</h2> <div> <h3>RSA加密</h3> <textarea id="rsaPlaintext" rows="4" cols="50" placeholder="请输入要加密的内容"></textarea><br> <button onclick="rsaEncrypt()">加密</button><br> <textarea id="rsaCiphertext" rows="4" cols="50" readonly></textarea> </div> <div> <h3>RSA解密</h3> <textarea id="rsaEncryptedText" rows="4" cols="50" placeholder="请输入要解密的内容"></textarea><br> <button onclick="rsaDecrypt()">解密</button><br> <textarea id="rsaDecryptedText" rows="4" cols="50" readonly></textarea> </div> <h2>SM2加解密演示</h2> <div> <h3>SM2加密</h3> <textarea id="sm2Plaintext" rows="4" cols="50" placeholder="请输入要加密的内容"></textarea><br> <button onclick="sm2Encrypt()">加密</button><br> <textarea id="sm2Ciphertext" rows="4" cols="50" readonly></textarea> </div> <div> <h3>SM2解密</h3> <textarea id="sm2EncryptedText" rows="4" cols="50" placeholder="请输入要解密的内容"></textarea><br> <button onclick="sm2Decrypt()">解密</button><br> <textarea id="sm2DecryptedText" rows="4" cols="50" readonly></textarea> </div> <script> // RSA加密 async function rsaEncrypt() { try { const plaintext = document.getElementById('rsaPlaintext').value; const response = await axios.post('/api/crypto/rsa/encrypt', plaintext, { headers: { 'Content-Type': 'text/plain' }, transformResponse: [(data) => { // 确保返回的是原始数据,不要让axios自动解析 return data; }] }); document.getElementById('rsaCiphertext').value = response.data; } catch (error) { alert('加密失败:' + (error.response?.data || error.message)); } } // RSA解密 async function rsaDecrypt() { try { const encryptedText = document.getElementById('rsaEncryptedText').value.trim(); // 检查是否是有效的Base64 if (!isValidBase64(encryptedText)) { throw new Error('输入的不是有效的Base64编码字符串'); } const response = await axios.post('/api/crypto/rsa/decrypt', encryptedText, { headers: { 'Content-Type': 'text/plain' }, transformResponse: [(data) => { return data; }] }); document.getElementById('rsaDecryptedText').value = response.data; } catch (error) { alert('解密失败:' + (error.response?.data || error.message)); } } // 检查是否是有效的Base64字符串 function isValidBase64(str) { try { return btoa(atob(str)) === str; } catch (err) { return false; } } // SM2加密 async function sm2Encrypt() { try { const plaintext = document.getElementById('sm2Plaintext').value; console.log("plaintext====="+plaintext) // 使用 JSON 格式包装数据 const response = await axios.post('/api/crypto/sm2/encrypt', { data: plaintext } ,{ headers: { 'Content-Type': 'application/json' }, transformResponse: [(data) => { return data; }] }); document.getElementById('sm2Ciphertext').value = response.data; } catch (error) { alert('加密失败:' + (error.response?.data || error.message)); } } // SM2解密 async function sm2Decrypt() { try { const response = await axios.post('/api/crypto/sm2/decrypt', {data:document.getElementById('sm2EncryptedText').value}, { headers: { 'Content-Type': 'application/json' }, transformResponse: [(data) => { return data; }] } ); document.getElementById('sm2DecryptedText').value = response.data; } catch (error) { alert('解密失败:' + error); } } </script> </body> </html>
运行结果如下图


浙公网安备 33010602011771号