非对称加密算法:用两个密钥(公钥/私钥)对数据进行加密和解密。

一、原理

非对称加密算法实现机密信息交换的基本过程是:
1)甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;
2)得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;
3)甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。

二、编码

1.依赖

前端(乙方):jsencrypt.min.js
后端(甲方):Java原生API

2.后端加密/解密工具类编码

import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import org.apache.tomcat.util.codec.binary.Base64; public class RsaUtil {
/**
* 定义加密方式
*/
private final static String KEY_RSA = "RSA";
/**
* 定义签名算法
*/
private final static String KEY_RSA_SIGNATURE = "MD5withRSA";
/**
* 定义公钥算法
*/
private final static String KEY_RSA_PUBLICKEY = "RSAPublicKey";
/**
* 定义私钥算法
*/
private final static String KEY_RSA_PRIVATEKEY = "RSAPrivateKey"; private RsaUtil() {} /**
* 创建密钥
* @return
*/
public static Map<String, Object> generateKey() {
Map<String, Object> map = null;
try {
KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_RSA);
generator.initialize(1024);
KeyPair keyPair = generator.generateKeyPair();
// 公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 将密钥封装为map
map = new HashMap<>(2);
map.put(KEY_RSA_PUBLICKEY, publicKey);
map.put(KEY_RSA_PRIVATEKEY, privateKey);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return map;
} /**
* 用私钥对信息生成数字签名
* @param data 加密数据
* @param privateKey 私钥
* @return
*/
public static String sign(String privateKey, byte[] data) {
String str = "";
try {
// 解密由base64编码的私钥
byte[] bytes = decryptBase64(privateKey);
// 构造PKCS8EncodedKeySpec对象
PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(bytes);
// 指定的加密算法
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
// 取私钥对象
PrivateKey key = factory.generatePrivate(pkcs);
// 用私钥对信息生成数字签名
Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
signature.initSign(key);
signature.update(data);
str = encryptBase64(signature.sign());
} catch (Exception e) {
e.printStackTrace();
}
return str;
} /**
* 校验数字签名
* @param data 加密数据
* @param publicKey 公钥
* @param sign 数字签名
* @return 校验成功返回true,失败返回false
*/
public static boolean verify(String publicKey, byte[] data, String sign) {
boolean flag = false;
try {
// 解密由base64编码的公钥
byte[] bytes = decryptBase64(publicKey);
// 构造X509EncodedKeySpec对象
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
// 指定的加密算法
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
// 取公钥对象
PublicKey key = factory.generatePublic(keySpec);
// 用公钥验证数字签名
Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE);
signature.initVerify(key);
signature.update(data);
flag = signature.verify(decryptBase64(sign));
} catch (Exception e) {
e.printStackTrace();
}
return flag;
} /**
* 公钥加密
* @param key 公钥
* @param data 待加密数据
* @return
*/
public static byte[] encryptByPublicKey(String key, String data) {
byte[] result = null;
try {
// 获取公钥字符串时,进行了encryptBase64操作,因此此处需对公钥钥解密
byte[] bytes = decryptBase64(key);
// 取得公钥
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PublicKey publicKey = factory.generatePublic(keySpec);
// 对数据加密
Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
result = cipher.doFinal(data.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
return result;
} /**
* 私钥解密
* @param data 加密数据
* @param key 私钥
* @return
*/
public static byte[] decryptByPrivateKey(String key, byte[] data) {
byte[] result = null;
try {
// 获取私钥字符串时,进行了encryptBase64操作,因此此处需对私钥解密
byte[] bytes = decryptBase64(key);
// 取得私钥
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PrivateKey privateKey = factory.generatePrivate(keySpec);
// 对数据解密
Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
result = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return result;
} /**
* 私钥加密
* @param data 待加密数据
* @param key 私钥
* @return
*/
public static byte[] encryptByPrivateKey(String key, byte[] data) {
byte[] result = null;
try {
byte[] bytes = decryptBase64(key);
// 取得私钥
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PrivateKey privateKey = factory.generatePrivate(keySpec);
// 对数据加密
Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
result = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return result;
} /**
* 公钥钥解密
* @param key 公钥
* @param data 加密数据
* @return
*/
public static byte[] decryptByPublicKey(String key, byte[] data) {
byte[] result = null;
try {
// 对公钥解密
byte[] bytes = decryptBase64(key);
// 取得公钥
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance(KEY_RSA);
PublicKey publicKey = factory.generatePublic(keySpec);
// 对数据解密
Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicKey);
result = cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return result;
} /**
* 获取公钥
* @param map
* @return
*/
public static String getPublicKey(Map<String, Object> map) {
String str = "";
try {
Key key = (Key) map.get(KEY_RSA_PUBLICKEY);
str = encryptBase64(key.getEncoded());
} catch (Exception e) {
e.printStackTrace();
}
return str;
} /**
* 获取私钥
* @param map
* @return
*/
public static String getPrivateKey(Map<String, Object> map) {
String str = "";
try {
Key key = (Key) map.get(KEY_RSA_PRIVATEKEY);
str = encryptBase64(key.getEncoded());
} catch (Exception e) {
e.printStackTrace();
}
return str;
} /**
* BASE64 解密
* @param key 需要解密的字符串
* @return 字节数组
* @throws Exception
*/
public static byte[] decryptBase64(String key) throws Exception {
return Base64.decodeBase64(key);
} /**
* BASE64 加密
* @param key 需要加密的字节数组
* @return 字符串
* @throws Exception
*/
public static String encryptBase64(byte[] key) throws Exception {
return Base64.encodeBase64String(key);
}
}

3.接口编码

import java.util.Map;
import javax.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.light.utils.RsaUtil;
import com.light.vo.Result; @RestController
public class RsaController { /**
* 获取公钥
* @param session
* @return
* @throws Exception
*/
@GetMapping("rsa/publicKey")
public Result randomNum(HttpSession session) throws Exception {
Map<String, Object> map = RsaUtil.generateKey();
String publicKey = RsaUtil.getPublicKey(map);
String privateKey = RsaUtil.getPrivateKey(map);
session.setAttribute("privateKey", privateKey);
return Result.success(publicKey);
} /**
* 解密
* @param msg
* @param session
* @return
*/
@RequestMapping("rsa/decrypt")
public Result decrypt(String msg, HttpSession session) {
String rtStr = "";
try {
String privateKey = (String) session.getAttribute("privateKey");
session.removeAttribute("privateKey");
//下边需要解密的字符串需要使用RsaUtils.decryptBase64转成byte[]
rtStr = new String(RsaUtil.decryptByPrivateKey(privateKey, RsaUtil.decryptBase64(msg)));
// 下边的写法会报错:javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes
// rtStr = new String(RsaUtils.decryptByPrivateKey(privateKey, msg.getBytes()));
} catch (Exception e) {
e.printStackTrace();
}
return Result.success(rtStr);
}
}

4.前端编码

//1.通过ajax获取公钥
//2.加密数据
var encrypt = new JSEncrypt();//来源于jsencrypt.min.js
encrypt.setPublicKey("公钥");
var content = encrypt.encrypt("待加密数据");//content为加密后的密文
//3.通过ajax提交加密数据

三、总结

如果使用对称加密,http请求下通过抓包工具可以获取用户提交的参数数据,暴露加密数据和密钥。由于前端js加密源码是可见的,黑客可以很容易的对加密数据进行破解。
但是,当使用非对称加密时,由于加密和破解使用的不同的密钥,因此即使抓包获取到参数(公钥),黑客也很难破解数据。

最新文章

  1. centos 更换 yum源
  2. JavaScript中常见的字符串操作函数及用法
  3. SignalR 资料
  4. Z-XML团队 软件工程课之我感我思我收获
  5. [HDOJ5542]The Battle of Chibi(DP,树状数组)
  6. 关于OJ上内存问题的试验
  7. HTML5 Canvas核心技术—图形、动画与游戏开发.pdf6
  8. USB通讯协议之深入理解
  9. nodejs学习笔记之网络编程
  10. 如何成为一个真正在路上的Linuxer
  11. SQL Server 主动防止阻塞的 1 方法
  12. windows平台下载android源代码
  13. WP Super Cache+七牛云配置CDN加速,让你的网站秒开
  14. Redis 5.0.3集群部署
  15. 机器学习算法 Python&amp;R 速查表
  16. WireShark如何抓取本地localhost的包
  17. 查看进程在CPU和内存占用的命令
  18. ls操作总结
  19. hibernate注解主键生成策略
  20. QtWebKit_cookie

热门文章

  1. SPOJ 694 && SPOJ 705 (不重复子串个数:后缀数组)
  2. 变更Linux下的Java版本 alternatives
  3. IOS-CocoaPods的详细安装与使用
  4. C#,WebRequest类、HttpWebRequest类与HttpRequest类的区别
  5. querySelectorAll 与jquery.find 与htmlcollection 的区别
  6. hdu 6097 Mindis(数学几何,圆心的反演点)
  7. html5 圆角ie8
  8. javascript 事件委托 event delegation
  9. kibana安装
  10. Java基础学习-常见API