1.原理
RSA是一种非对称加密算法。通过生成密钥对,用公钥加密,用私钥解密。对于前后端分离的项目,让前端获取到公钥对敏感数据加密,发送到后端,后端用私钥对加密后的数据进行解密即可。
2.实现
RSA工具类:提供秘钥对生成、公钥获取、私钥解密的方法。
public class RSAUtil {private final static Logger logger = LoggerFactory.getLogger(RSAUtil.class);private static final String RSA = "RSA"; private static final int KEY_SIZE = 2048; private static ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Bouncy Castle加密库提供的一个类,用于为Java提供加密服务private static final BouncyCastleProvider BOUNCY_CASTLE_PROVIDER = new BouncyCastleProvider();// 密钥对生成static void createKey() throws Exception{KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA, BOUNCY_CASTLE_PROVIDER);keyPairGenerator.initialize(KEY_SIZE, new SecureRandom());ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(keyPairGenerator.generateKeyPair());objectOutputStream.close();}// 公钥获取public static RSAPublicKey getPublicKey() throws Exception{return (RSAPublicKey) getKeyPair().getPublic();}// 读取,有密钥对则获取公钥,无密钥对则创建密钥对再获取公钥static KeyPair getKeyPair()throws Exception{if(byteArrayOutputStream.size() == 0){synchronized (byteArrayOutputStream) {createKey();}}ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); KeyPair keyPair= (KeyPair) objectInputStream.readObject(); objectInputStream.close(); byteArrayInputStream.close(); return keyPair; }static byte[] decryptByPrivateKey(byte[] encrypttext){try {Cipher ci = Cipher.getInstance(RSA, BOUNCY_CASTLE_PROVIDER);ci.init(Cipher.DECRYPT_MODE, getKeyPair().getPrivate());return ci.doFinal(encrypttext);} catch (Exception e) {logger.error(e.getMessage(), e);}return null;}// 接收一个String类型,私钥解密public static String decodeString(String string){try { byte[] input = Base64.getDecoder().decode(string); // 解码Base64字符串为字节数组 byte[] raw = decryptByPrivateKey(input); // 使用私钥解密数据 return new String(raw, StandardCharsets.UTF_8); // 直接将字节数组转换为UTF-8字符串 } catch (Exception e) { logger.error("解析失败", e); return ""; }} }
为前端提供一个获取公钥的接口
@GetMapping("getRSAPublickey")
public Result<?> getRSAPublickey() {Map key = new HashMap();try {// 通过提供模数和公共指数,可以间接地提供公钥,同时保持安全性。String modulus = RSAUtil.getPublicKey().getModulus().toString(16);String publicExponent = RSAUtil.getPublicKey().getPublicExponent().toString(16);key.put("m", modulus);key.put("e", publicExponent);} catch (Exception e) {}return Result.ok(key);
}
前端需要导入一个适合前端使用的RSA加密库。利用获取到的模数和公共指数创建RSA公钥对象,对敏感数据加密。
<html><script src="rsa.js"></script><body><script>window.encryptStr = function (m, e, str) {var rsa = new RSAKey()rsa.setPublic(m, e)return rsa.encrypt(str)}</script></body>
</html>
后端接收到前端利用RSA加密后的字符串后,直接调用RSAUtil进行解密,得到原文。
String password = RSAUtil.decodeString(pram.getPassword());
需要注意的是,前端加密只是数据传输过程中的一部分安全措施。为了确保数据的安全性,还需要在后端服务器进行相应的安全措施,例如验证用户身份、使用HTTPS协议进行通信等。