1. 基本原理
1.1 对称加密
基本概念
加密解密都使用同一个密钥。
缺点
- 安全问题:一旦密钥泄露,传输数据将不会安全
- 保管问题:每一类的数据加密需要重新生成一个密钥,一旦需要传输的数据类型多了,密钥管理就成了一个负担
1.2 非对称加密
基本概念
数据传输方和接收方都拥有自己的公钥和私钥,他们将公钥暴露出来提供给对方加密/解密数据,自己使用自己的私钥对数据进行加密/解密。保证加密和解密使用的是不同的密钥,所以叫做非对称加密
数据传输过程
- 传输双方AB都需要生成自己的一对私钥和公钥
- A将数据用B提供的公钥将数据进行加密,传输给B
- B将数据拿到,用自己的私钥对数据进行解密。反过来B传数据给A也是一样
这个过程保证了解密使用的私钥是自己私有的,对数据解密只能使用自己知道的私钥进行解密,这个过程就避免了密钥泄露的问题。
1.3 非对称加密实例(RSA算法)
这里用登录校验功能展开。
- 前端通过调用后端提供的接口获取公钥,在前端对密码进行加密后传输给后端
- 后端通过自己的私钥对数据进行解密,在数据库进行校验后保存登录用户信息
需要引用的包
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
前端JS
$('#loginButton').click(function(e){
//调用后端接口获取公钥
$.ajax({
type:'post',
url:'/getPublicKey.do',
data:{},
success:function(publicKey){
//对密码进行加密
var encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
that.val(encrypt.encrypt(password));
$('#passwd').submit();
}
})
})
RSA工具类
public class RSAUtils {
private static final KeyPair keyPair = initKey();
/**
* 初始化key pair
*
* @return KeyPair
*/
private static KeyPair initKey() {
try {
// 添加provider
Provider provider = new BouncyCastleProvider();
Security.addProvider(provider);
// 随机数用于安全加密
SecureRandom random = new SecureRandom();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", provider);
generator.initialize(1024, random);
return generator.generateKeyPair();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 产生公钥
*
* @return 公钥字符串
*/
public static String generateBase64PublicKey() {
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 使用base64算法对二进制数据进行编码,返回key的原始编码形式
return new String(Base64.encodeBase64(publicKey.getEncoded()));
}
/**
* 解密数据
*
* @param arg 需要解密的字符串
* @return 解密后的字符串
*/
public static String decryptBase64(String arg) {
try {
Provider provider = new BouncyCastleProvider();
Security.addProvider(provider);
// Cipher 提供加密和解密功能
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", provider);
PrivateKey privateKey = keyPair.getPrivate();
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// doFinal(): 加密或者解密数据
byte[] plainText = cipher.doFinal(Base64.decodeBase64(arg));
return new String(plainText);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
获取公钥
@RequestMapping("/getPublicKey.do")
public String getPublicKey(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
try {
PrintWriter writer = httpServletResponse.getWriter();
String publicKey = RSAUtils.generateBase64PublicKey();
writer.write(publicKey);
return publicKey;
} catch (Exception e) {
return null;
}
}
解密处理
@RequestMapping("/login.do")
public String login(HttpServletRequest request, HttpServletResponse response) {
String account = request.getParameter("usename");
String passwd = request.getParameter("passwd");
try {
//解密
passwd = RSAUtils.decryptBase64(passwd);
} catch (Exception e) {
e.printStackTrace();
}
if (account != "" && passwd != "") {
//校验账号密码,成功则保存到session
User user = UserDao.check(account, passwd);
if (user != null) {
session.setAttribute("loginUser", user);
}
}
return "";
}