RSA非對稱加密演算法(表單提交時,前端js加密,後端java解密)
阿新 • • 發佈:2018-11-07
RSA非對稱加密演算法(表單提交時,前端js加密,後端java解密
非對稱加密演算法
非對稱加密演算法是一種金鑰的保密方法。
非對稱加密演算法需要兩個金鑰:公開金鑰(publickey)和私有金鑰(privatekey)。公開金鑰與私有金鑰是一對,如果用公開金鑰對資料進行加密,只有用對應的私有金鑰才能解密;如果用私有金鑰對資料進行加密,那麼只有用對應的公開金鑰才能解密。因為加密和解密使用的是兩個不同的金鑰,所以這種演算法叫作非對稱加密演算法。 非對稱加密演算法實現機密資訊交換的基本過程是:甲方生成一對金鑰並將其中的一把作為公用金鑰向其它方公開;得到該公用金鑰的乙方使用該金鑰對機密資訊進行加密後再發送給甲方;甲方再用自己儲存的另一把專用金鑰對加密後的資訊進行解密。
RSA公開金鑰加密系統採用公鑰加密,私鑰解密,能夠安全傳輸需要加密的文字。但是,由於其需要進行大量的指數運算,速度慢,成本高,常用於加密少量的文字。
我們對於表單提交時的密碼採用公開金鑰系統進行加密和解密。前端用JS進行公鑰加密,後端用Java私鑰解密。
需要的工具
1.bcprov-jdk16-146.jar.
2.commons-codec-1.10.jar.
3.jsencrypt.min.js.
前端jsp頁面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset= "UTF-8">
<title>註冊</title>
<script src="/js/jquery.min.js"></script>
<script src="/js/jsencrypt.min.js"></script>
</head>
<body>
<form id="erlingyiba" class="form1" action="/toregist.do" method="post">
<div class="one">
<div class="user stle" >
<span>
<i>*</i>
使用者名稱
</span>
<input class="border-box admin" type="text" name="username" placeholder="請輸入您的使用者名稱" />
<label>請輸入使用者名稱</label>
</div>
<div class="password stle">
<span>
<i>*</i>
登入密碼
</span>
<input class="passwordone border-box" type="password" name="password" placeholder="請輸入密碼" />
<label>請輸入密碼</label>
</div>
<div class="password stle">
<span>
<i>*</i>
確認密碼
</span>
<input class="passwordtwo border-box" type="password" placeholder="請輸入密碼" />
<label>請再次輸入密碼</label>
</div>
</div>
<div class="sublimeButton stle">
<span>
<i></i>
</span>
<input id="registbutton" class="border-box" type="submit" value="注 冊" />
<input id="registreg" name="registreg" type="hidden" value="1" show="true" />
</div>
</div>
</form>
</body>
</html>
js程式碼
新增提交按鈕的點選事件,點選後,通過介面,到後臺獲取公鑰,對密碼加密,然後提交表單。
$('#registbutton').click(function(e){
//登出預設事件
e.preventDefault();
var that = $('.passwordone');
//獲取公鑰
$.ajax({
type:'post',
url:'/getPasswprdKey.do',
data:{},
success:function(date){
var publicKey = date;
//對密碼進行加密
var encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
var password = that.val();
that.val(encrypt.encrypt(password));
$('#erlingyiba').submit();
}
})
})
加密解密的工具類
這裡除了常用的JAR包以外,還需要依賴bcprov-jdk16-146.jar和commons-codec-1.10.jar這兩個JAR包。bcprov-jdk16-146.jar提供用於加密和解密的provider,它實現了演算法和金鑰的生成等。commons-codec-1.10.jar提供編碼解碼功能。
package com.jzsoft.util;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.interfaces.RSAPublicKey;
import java.util.Scanner;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;
public class RSAUtils {
// KeyPair is a simple holder for a key pair.
private static final KeyPair keyPair = initKey();
/**
* 初始化方法,產生key pair,提供provider和random
* @return KeyPair instance
*/
private static KeyPair initKey() {
try {
// 新增provider
Provider provider = new org.bouncycastle.jce.provider.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);
}
}
/**
* 產生public key
* @return public key字串
*/
public static String generateBase64PublicKey() {
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// encodeBase64(): Encodes binary data using the base64
// algorithm but does not chunk the output.
// getEncoded():返回key的原始編碼形式
return new String(Base64.encodeBase64(publicKey.getEncoded()));
}
/**
* 解密資料
* @param string 需要解密的字串
* @return 破解之後的字串
*/
public static String decryptBase64(String string) {
// decodeBase64():將Base64資料解碼為"八位位元組”資料
return new String(decrypt(Base64.decodeBase64(string)));
}
private static byte[] decrypt(byte[] byteArray) {
try {
Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(provider);
// Cipher: 提供加密和解密功能的例項
// transformation: "algorithm/mode/padding"
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", provider);
PrivateKey privateKey = keyPair.getPrivate();
// 初始化
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// doFinal(): 加密或者解密資料
byte[] plainText = cipher.doFinal(byteArray);
return plainText;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
產生公鑰的類
@RequestMapping("/getPasswprdKey.do")
public String getPasswprdKey(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
try {
PrintWriter writer = httpServletResponse.getWriter();
String publickey = RSAUtils.generateBase64PublicKey();
writer.write(publickey);
System.out.println(publickey);
return null;
} catch (Exception e) {
// TODO: handle exception
return null;
}
}
處理登陸請求的類
@RequestMapping("/login.do")
public String login(HttpServletRequest request, HttpServletResponse response, HttpSession session, ModelMap mm) {
IUserDao UserDao = ServiceFactory.getBean(IUserDao.class);
String retUrl = ParamUtils.getParameter(request, "retUrl", "");
String account = ParamUtils.getParameter(request, "usename", "");
try {
//處理亂碼
account = new String(account.getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//獲取密碼,密碼是加密後的密碼
String passwd = ParamUtils.getParameter(request, "password", "");
try {
//解密
passwd = RSAUtils.decryptBase64(passwd);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
if (account != "" && passwd != "") {
User user = UserDao.login(account, passwd);
if (user != null) {
mm.addAttribute("user", user);
session.setAttribute(Constant.USER_FRONT_SESSION_KEY, user);
return "forward:" + retUrl;
} else {
mm.addAttribute("msgCode", "使用者名稱或密碼錯誤!");
return "forward:/tologin.do";
}
} else {
mm.addAttribute("msgCode", "使用者名稱或密碼不能為空!");
return "forward:/tologin.do";
}
}