公司最近让在登录首页登录时,js加密,java解密。
首先必不可少的就是jar包,和js文件
后台引入的jar包:
jar 包 bcprov-jdk16-146.jar 和commons-codec-1.2.jar (maven项目的话引入相对应的依赖就好)
<dependenccies>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
</dependencies>
<dependencys>
前端引入的脚本文件
jquery.min.js和security.js (security.js的源码可以在前一篇中找到)
java工具类 RSAUtils
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.HashMap;
import javax.crypto.Cipher;
public class RSAUtils {
/**
* 生成公钥和私钥
* @throwsNoSuchAlgorithmException
*/
public static HashMap<String, Object> getKeys() throws NoSuchAlgorithmException {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
HashMap<String, Object> map = new HashMap<String, Object>();
//为RSA算法创建一个KeyPairGenerator对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
keyPairGen.initialize(1024);
//生成密钥对
KeyPair keyPair = keyPairGen.generateKeyPair();
//得到公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
//得到私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
map.put("public", publicKey);
map.put("private", privateKey);
return map;
}
/**
*
* 使用模和指数生成RSA公钥
*
* @parammodulus 模
* @paramexponent 指数
* @return
*/
public static RSAPublicKey getPublicKey(String modulus, String exponent) {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
try {
BigInteger b1 = new BigInteger(modulus);
BigInteger b2 = new BigInteger(exponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
*
* 使用模和指数生成RSA私钥
* None/NoPadding
* @parammodulus 模
* @paramexponent指数
* @return
*/
public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
BigInteger b1 = new BigInteger(modulus);
BigInteger b2 = new BigInteger(exponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 公钥加密
* @return
* @paramdata
* @parampublicKey
* @throwsException
*/
public static String encryptByPublicKey(String data, RSAPublicKey publicKey) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
//模长
int key_len = publicKey.getModulus().bitLength() / 8;
//加密数据长度<=模长-11
String[] datas = splitString(data, key_len - 11);
String mi = "";
//如果明文长度大于模长-11则要分组加密
for (String s : datas) {
mi += bcd2Str(cipher.doFinal(s.getBytes()));
}
return mi;
}
/**
* 私钥解密
*
* @paramdata
* @paramprivateKey
* @return
* @throwsException
*/
public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//模长
int key_len = privateKey.getModulus().bitLength() / 8;
byte[] bytes = data.getBytes();
byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
//System.err.println(bcd.length);
//如果密文长度大于模长则要分组解密
String ming = "";
byte[][] arrays = splitArray(bcd, key_len);
for (byte[] arr : arrays) {
ming += new String(cipher.doFinal(arr));
}
return ming;
}
/**
*
* ASCII码转BCD码
*/
public static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
byte[] bcd = new byte[asc_len / 2];
int j = 0;
for (int i = 0; i < (asc_len + 1) / 2; i++) {
bcd[i] = asc_to_bcd(ascii[j++]);
bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4));
}
return bcd;
}
public static byte asc_to_bcd(byte asc) {
byte bcd;
if ((asc >= '0') && (asc <= '9')) {
bcd = (byte) (asc - '0');
} else if ((asc >= 'A') && (asc <= 'F')) {
bcd = (byte) (asc - 'A' + 10);
} else if ((asc >= 'a') && (asc <= 'f')) {
bcd = (byte) (asc - 'a' + 10);
} else {
bcd = (byte) (asc - 48);
}
return bcd;
}
/**
* BCD转字符串
*/
public static String bcd2Str(byte[] bytes) {
char temp[] = new char[bytes.length * 2], val;
for (int i = 0; i < bytes.length; i++) {
val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
val = (char) (bytes[i] & 0x0f);
temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
}
return new String(temp);
}
/**
*
* 拆分字符串
*/
public static String[] splitString(String string, int len) {
int x = string.length() / len;
int y = string.length() % len;
int z = 0;
if (y != 0) {
z = 1;
}
String[] strings = new String[x + z];
String str = "";
for (int i = 0; i < x + z; i++) {
if (i == x + z - 1 && y != 0) {
str = string.substring(i * len, i * len + y);
} else {
str = string.substring(i * len, i * len + len);
}
strings[i] = str;
}
return strings;
}
/**
* 拆分数组
*/
public static byte[][] splitArray(byte[] data, int len) {
int x = data.length / len;
int y = data.length % len;
int z = 0;
if (y != 0) {
z = 1;
}
byte[][] arrays = new byte[x + z][];
byte[] arr;
for (int i = 0; i < x + z; i++) {
arr = new byte[len];
if (i == x + z - 1 && y != 0) {
System.arraycopy(data, i * len, arr, 0, y);
} else {
System.arraycopy(data, i * len, arr, 0, len);
}
arrays[i] = arr;
}
return arrays;
}
public static void main(String[] args) throws Exception {
HashMap<String, Object> map = getKeys();
//生成公钥和私钥
RSAPublicKey publicKey = (RSAPublicKey) map.get("public");
RSAPrivateKey privateKey = (RSAPrivateKey) map.get("private");
//模
String modulus = publicKey.getModulus().toString();
System.out.println("pubkeymodulus=" + modulus);
//公钥指数
String public_exponent = publicKey.getPublicExponent().toString();
System.out.println("pubkeyexponent=" + public_exponent);
//私钥指数
String private_exponent = privateKey.getPrivateExponent().toString();
System.out.println("privateexponent=" + private_exponent);
//明文
String ming = "123456";
//使用模和指数生成公钥和私钥
RSAPublicKey pubKey = RSAUtils.getPublicKey(modulus, public_exponent);
RSAPrivateKey priKey = RSAUtils.getPrivateKey(modulus, private_exponent);
//加密后的密文
String mi = RSAUtils.encryptByPublicKey(ming, pubKey);
System.err.println("mi=" + mi);
//解密后的明文
String ming2 = RSAUtils.decryptByPrivateKey(mi, priKey);
System.err.println("ming2=" + ming2);
}
}
js 加密
账号:<input type="text" id="username" ><br><br>
密码:<input type="password" id="password"><br><br>
<input id="publicKeyExponent" value="" type="hidden"> //后台传过来的公钥
<input id="publicKeyModulus" value="" type="hidden">//后台传过来的模
<script>
$(function(){
//生成登陆用RSA公钥 密钥
$.ajax({
url:'${basePath}UserText/loginRSA.do',
type:'post',
dataType:'json',
success:function(data){
$("#publicKeyExponent").val(data[0]);
$("#publicKeyModulus").val(data[1]);
}
})
});
//点击登录按钮,执行的方法
function login1(){
var username=$("#username").val();
var password=$("#password").val();
//RSA加密
var publicKeyExponent=$("#publicKeyExponent").val();
var publicKeyModulus=$("#publicKeyModulus").val();
RSAUtils.setMaxDigits(200);
var key = new RSAUtils.getKeyPair(publicKeyExponent, "", publicKeyModulus);
var userNameEncrypt = RSAUtils.encryptedString(key,username.split("").reverse().join(""));
var userPwdEncrypt = RSAUtils.encryptedString(key,password.split("").reverse().join(""));
$.ajax({
url:"${basePath}UserText/textLogin.do",
data:'post',
dataType:'json',
data:{"username":userNameEncrypt,"password":userPwdEncrypt},
success:function(data) {
if(data == 'success') {
alert("登录成功")
window.location.href="${basePath}UserText/textList.do";
} else if (data == 'usernameIsNull'){
alert("账号错误")
} else if (data == 'passwordIsNull'){
alert("密码错误")
} else {
alert("登录失败")
}
}
})
}
</script>
java 后台接收,解密
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* @Description:Login
* @Author:Anhk丶
* @Date:2020/7/611:27
* @Version:1.0
*/
public class LoginController {
//生成登陆用RSA公钥密钥
@RequestMapping(value = "/loginRSA")
@ResponseBody
public List<String> loginRSA(HttpServletRequest request) {
//HttpServletRequestrequest=ServletActionContext.getRequest();
String publicKeyExponent = "";
String publicKeyModulus = "";
try {
HashMap<String, Object> map = RSAUtils.getKeys();
//生成公钥和私钥
RSAPublicKey publicKey = (RSAPublicKey) map.get("public");
RSAPrivateKey privateKey = (RSAPrivateKey) map.get("private");
//私钥保存在session中,用于解密
request.getSession().setAttribute("privateKeyLogin", privateKey);
//公钥信息保存在页面,用于加密公钥指数 .toString(16)表示转为16进制的字符串;
publicKeyExponent = publicKey.getPublicExponent().toString(16);
System.out.println("公钥指数:" + publicKeyExponent);
//模 .toString(16)表示转为16进制的字符串;
publicKeyModulus = publicKey.getModulus().toString(16);
System.out.println("模指数:" + publicKeyModulus);
//request.getSession().setAttribute("publicKeyExponent",publicKeyExponent);
//request.getSession().setAttribute("publicKeyModulus",publicKeyModulus);
} catch (Exception e) {
log.error("RSA生成公钥错误", e);
}
List<String> list = new ArrayList<String>();
list.add(publicKeyExponent);
list.add(publicKeyModulus);
return list;
}
//登录验证
@RequestMapping(value = "/textLogin")
@ResponseBody
public String textLogin(String username, String password, HttpServletRequest request) {
if (org.apache.commons.lang.StringUtils.isBlank(username)) {
System.out.println("theusernameisnull");
return "usernameIsNull";
}
if (org.apache.commons.lang.StringUtils.isBlank(password)) {
System.out.println("thepasswordisnull");
return "passwordIsNull";
}
RSAPrivateKey privateKey = (RSAPrivateKey) request.getSession().getAttribute("privateKeyLogin");
try {
username = RSAUtils.decryptByPrivateKey(username, privateKey);
System.out.println("解密后的用户名:" + username);
password = RSAUtils.decryptByPrivateKey(password, privateKey);
System.out.println("解密后密码:" + password);
} catch (Exception e) {
log.error("RSA解密失败", e);
}
User user = userService.getUser(username);
if (user != null) {
if (password.equals(user.getPassword())) {
System.out.println("登陆成功");
return "success";
}
}
System.out.println("登录失败");
return "fail";
}
}