首先:
写一个控制层,跳转至网页,将公钥,系数,指数带过去.
@RequestMapping(value = "/index")
public String index(Model model) {
//获取公钥对象--注意:前端那边需要用到公钥系数和指数
RSAPublicKey publicKey = RSAUtils.getDefaultPublicKey();
//公钥-系数(n)
String pkModulus = new String(Hex.encode(publicKey.getModulus().toByteArray()));
//公钥-指数(e1)
String pkExponent = new String(Hex.encode(publicKey.getPublicExponent().toByteArray()));
//存储进request域对象中
model.addAttribute("pkModulus",pkModulus);
model.addAttribute("pkExponent",pkExponent);
return "/backStage/home";
}
其次,写一个jsp,接收数据:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<script language="JavaScript" type="text/javascript" src="${pageContext.request.contextPath}/plug_in_tools/jquery-3.3.1/jquery-3.3.1.js"></script>
<script language="JavaScript" type="text/javascript" src="${pageContext.request.contextPath}/plug_in_tools/security.js"></script>
<head>
<title>表单提交</title>
</head>
<body>
<h1>JavaScript RSA Encryption Demo</h1>
需要加密的字符串:
<input type="text" id="word" value="test"/><input type="button" onclick="encryptionByJs()" value="加密"/>
<br/>
<%--获取公钥信息--%>
<div style="display: none">
公钥系数-我这里是通过控制层传递过来,在工具类中已经注明了系数获取:
<input type="text" id="hid_modulus"
value="${pkModulus}"/>
<br/>
公钥指数-同:
<input type="text" id="hid_exponent" value="${pkExponent}"/>
</div>
</body>
</html>
<script language="JavaScript">
//拿到后台传递过来的公钥信息,对需要加密的参数进行加密
function encryptionByJs() {
//获取公钥系数
var modulus = $('#hid_modulus').val();
//获取公钥指数
var exponent = $('#hid_exponent').val();
//获取最终公钥
var key = RSAUtils.getKeyPair(exponent, '', modulus);
//获取送的值
var word = $("#word").val();
//进行数据加密
var ap = RSAUtils.encryptedString(key, encodeURI(word));
//发起ajax请求
$.ajax({
type: "get", //提交方式
url: "/retrieveData",//路径
contentType: 'application/json;charset=utf-8',//返回json结果
data: {"test": ap},//数据,这里使用的是Json格式进行传输
success: function (data) {
alert(data);
}
});
}
</script>
该页面上已经拿到必备的数据,根据这些数据对输入的数据进行加密,走到另一个方法:
//在访问该路径时候直接带上参数
@GetMapping(value = "/retrieveData")
@ResponseBody
public String retrieveData(HttpServletRequest request, String test) throws UnsupportedEncodingException {
System.out.println(test);
String decode = "";
try {
//解密
decode = RSAUtils.decryptStringByJs(test);
} catch (Exception e) {
e.printStackTrace();
}
return decode;
}
最后,附上工具类:
package encryptionanddecryption;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.InvalidParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import javax.crypto.Cipher;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
/**
* RSA算法加密/解密工具类。
* 以下代码可以使用,唯一需要注意的是: org.bouncycastle...这个jar包需要找一到放到项目中,RSA所需jar包在java中已经自带了.
*
* @author liuyan
*/
public class RSAUtils {
/**
* 算法名称
*/
private static final String ALGORITHOM = "RSA";
/**
* 密钥大小
*/
private static final int KEY_SIZE = 1024;
/**
* 默认的安全服务提供者
*/
private static final Provider DEFAULT_PROVIDER = new BouncyCastleProvider();
private static KeyPairGenerator keyPairGen = null;
private static KeyFactory keyFactory = null;
/**
* 缓存的密钥对。
*/
private static KeyPair oneKeyPair = null;
//密文种子, 当想更换RSA钥匙的时候,只需要修改密文种子,即可更换
private static final String radamKey = "zczhang";
//类加载后进行初始化数据
static {
try {
keyPairGen = KeyPairGenerator.getInstance(ALGORITHOM,
DEFAULT_PROVIDER);
keyFactory = KeyFactory.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
}
/**
* 根据指定的密文种子,生成并返回RSA密钥对。
*/
private static synchronized KeyPair generateKeyPair() {
try {
keyPairGen.initialize(KEY_SIZE,
new SecureRandom(radamKey.getBytes()));
oneKeyPair = keyPairGen.generateKeyPair();
return oneKeyPair;
} catch (InvalidParameterException ex) {
ex.printStackTrace();
} catch (NullPointerException ex) {
ex.printStackTrace();
}
return null;
}
/**
* 返回初始化时默认的公钥。
*/
public static RSAPublicKey getDefaultPublicKey() {
KeyPair keyPair = generateKeyPair();
if (keyPair != null) {
return (RSAPublicKey) keyPair.getPublic();
}
return null;
}
/**
* 使用指定的私钥解密数据。
*
* @param privateKey 给定的私钥。
* @param data 要解密的数据。
* @return 原数据。
*/
public static byte[] decrypt(PrivateKey privateKey, byte[] data) throws Exception {
Cipher ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
ci.init(Cipher.DECRYPT_MODE, privateKey);
return ci.doFinal(data);
}
/**
* 使用默认的私钥解密给定的字符串。
* @param encryptText 密文。
* @return 原文字符串。
*/
public static String decryptString(String encryptText) {
if (StringUtils.isBlank(encryptText)) {
return null;
}
KeyPair keyPair = generateKeyPair();
try {
byte[] en_data = Hex.decode(encryptText);
byte[] data = decrypt((RSAPrivateKey) keyPair.getPrivate(), en_data);
return new String(data);
} catch (NullPointerException ex) {
ex.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
/**
* 使用秘钥 - 对js端传递过来密文进行解密
*
* @param encryptText 密文。
* @return {@code encryptText} 的原文字符串。
*/
public static String decryptStringByJs(String encryptText) {
String text = decryptString(encryptText);
if (text == null) {
return null;
}
String reverse = StringUtils.reverse(text);
String decode = null;
try {
//这里需要进行编码转换.注:在前端js对明文加密前需要先进行转码-可自行百度"编码转换"
decode = URLDecoder.decode(reverse, "UTF-8");
System.out.println("解密后文字:" + decode);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return decode;
}
//java端 - 使用公钥进行加密
public static byte[] encrypt(String plaintext) throws Exception {
// 获取公钥及参数e,n
RSAPublicKey publicKey = RSAUtils.getDefaultPublicKey();
//获取公钥指数 e
BigInteger e = publicKey.getPublicExponent();
//获取公钥系数 n
BigInteger n = publicKey.getModulus();
//先将明文进行编码
String encode = URLEncoder.encode(plaintext);
// 获取明文字节数组 m
BigInteger m = new BigInteger(encode.getBytes());
// 进行明文加密 c
BigInteger c = m.modPow(e, n);
//返回密文字节数组
return c.toByteArray();
}
//java端 - 使用私钥进行解密
public static String decrypt(byte[] cipherText) throws Exception {
// 读取私钥
KeyPair keyPair = generateKeyPair();
RSAPrivateKey prk = (RSAPrivateKey) keyPair.getPrivate();
// 获取私钥参数-指数/系数
BigInteger d = prk.getPrivateExponent();
BigInteger n = prk.getModulus();
// 读取密文
BigInteger c = new BigInteger(cipherText);
// 进行解密
BigInteger m = c.modPow(d, n);
// 解密结果-字节数组
byte[] mt = m.toByteArray();
//转成String,此时是乱码
String en = new String(mt);
//再进行编码
String result = java.net.URLDecoder.decode(en, "UTF-8");
//最后返回解密后得到的明文
return result;
}
public static void main(String[] args) {
/*解密js端传递过来的密文*/
//获取公钥对象--注意:前端那边需要用到公钥系数和指数
RSAPublicKey publicKey = RSAUtils.getDefaultPublicKey();
//公钥-系数(n)
System.out.println("public key modulus:" + new String(Hex.encode(publicKey.getModulus().toByteArray())));
//公钥-指数(e1)
System.out.println("public key exponent:" + new String(Hex.encode(publicKey.getPublicExponent().toByteArray())));
//JS加密后的字符串
String param = "8c49dfb92a0c8d15b0187b1eabc343a80f340962ebecc497205f83f6a4792141d4e711b6d439388ecf691df4eda2cae1e6431573b61e3f564ffe1c757e32f3e846b5983e5939ddeb28c9570001d7f208ffbaa069677d363cc73e4c78c0d508e8b0b9f6205473269bbfbc22e7fb9413be4c449520eb6cfb4fbbff4e7e189a005a";
//解密后的字符串
String param1 = RSAUtils.decryptStringByJs(param);
// /*后端的加密和解密-在加密的方法中已经使用了公钥指数和系数*/
// try {
// //加密
// byte[] param3 = encrypt("你好> @# !!# #");
// //解密
// String decrypt = RSAUtils.decrypt(param3);
// System.out.println(decrypt);
// } catch (Exception e) {
// e.printStackTrace();
// }
}
}
至此,结束. 需要RSA的jar包
还有两个辅助工具类,以下
package encryptionanddecryption;
/**
* @program: lycorisradiata
* @description:
* @author: liuyan
* @create: 2018-12-13 16:23
**/
public class HexUtil {
private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
/**
* 16进制转byte数组
* @param data 16进制字符串
* @return byte数组
* @throws Exception 转化失败的异常
*/
public static byte[] hex2Bytes(final String data) throws Exception {
final int len = data.length();
if ((len & 0x01) != 0) {
throw new Exception("Odd number of characters.");
}
final byte[] out = new byte[len >> 1];
// two characters form the hex value.
for (int i = 0, j = 0; j < len; i++) {
int f = toDigit(data.charAt(j), j) << 4;
j++;
f = f | toDigit(data.charAt(j), j);
j++;
out[i] = (byte) (f & 0xFF);
}
return out;
}
/**
* bytes数组转16进制String
* @param data bytes数组
* @return 转化结果
*/
public static String bytes2Hex(final byte[] data) {
return bytes2Hex(data, true);
}
/**
* bytes数组转16进制String
* @param data bytes数组
* @param toLowerCase 是否小写
* @return 转化结果
*/
public static String bytes2Hex(final byte[] data, final boolean toLowerCase) {
return bytes2Hex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
/**
* bytes数组转16进制String
* @param data bytes数组
* @param toDigits DIGITS_LOWER或DIGITS_UPPER
* @return 转化结果
*/
private static String bytes2Hex(final byte[] data, final char[] toDigits) {
final int l = data.length;
final char[] out = new char[l << 1];
// two characters form the hex value.
for (int i = 0, j = 0; i < l; i++) {
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
out[j++] = toDigits[0x0F & data[i]];
}
return new String(out);
}
/**
* 16转化为数字
* @param ch 16进制
* @param index 索引
* @return 转化结果
* @throws Exception 转化失败异常
*/
private static int toDigit(final char ch, final int index)
throws Exception {
final int digit = Character.digit(ch, 16);
if (digit == -1) {
throw new Exception("Illegal hexadecimal character " + ch
+ " at index " + index);
}
return digit;
}
/*
* 16进制字符串转字符串
*/
public static String hex2String(String hex) throws Exception{
String r = bytes2String(hexString2Bytes(hex));
return r;
}
/*
* 字节数组转字符串
*/
public static String bytes2String(byte[] b) throws Exception {
String r = new String (b,"UTF-8");
return r;
}
/*
* 16进制字符串转字节数组
*/
public static byte[] hexString2Bytes(String hex) {
if ((hex == null) || (hex.equals(""))){
return null;
}
else if (hex.length()%2 != 0){
return null;
}
else{
hex = hex.toUpperCase();
int len = hex.length()/2;
byte[] b = new byte[len];
char[] hc = hex.toCharArray();
for (int i=0; i<len; i++){
int p=2*i;
b[i] = (byte) (charToByte(hc[p]) << 4 | charToByte(hc[p+1]));
}
return b;
}
}
/*
* 字符转换为字节
*/
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
/*
* 字符串转16进制字符串
*/
public static String string2HexString(String s) throws Exception{
String r = bytes2HexString(string2Bytes(s));
return r;
}
/*
* 字节数组转16进制字符串
*/
public static String bytes2HexString(byte[] b) {
String r = "";
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
r += hex.toUpperCase();
}
return r;
}
/*
* 字符串转字节数组
*/
public static byte[] string2Bytes(String s){
byte[] r = s.getBytes();
return r;
}
}
package encryptionanddecryption;
import com.sun.org.apache.xml.internal.security.utils.Base64;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/** */
/**
* <p>
* BASE64编码解码工具包
* </p>
* <p>
* 依赖javabase64-1.3.1.jar
* </p>
*
* @author IceWee
* @date 2012-5-19
* @version 1.0
*/
public class Base64Util {
/** */
/**
* 文件读取缓冲区大小
*/
private static final int CACHE_SIZE = 1024;
/** */
/**
* <p>
* BASE64字符串解码为二进制数据
* </p>
*
* @param base64
* @return
* @throws Exception
*/
public static byte[] decode(String base64) throws Exception {
return Base64.decode(base64.getBytes());
}
/** */
/**
* <p>
* 二进制数据编码为BASE64字符串
* </p>
*
* @param bytes
* @return
* @throws Exception
*/
public static String encode(byte[] bytes) throws Exception {
return new String(Base64.encode(bytes));
}
/** */
/**
* <p>
* 将文件编码为BASE64字符串
* </p>
* <p>
* 大文件慎用,可能会导致内存溢出
* </p>
*
* @param filePath
* 文件绝对路径
* @return
* @throws Exception
*/
public static String encodeFile(String filePath) throws Exception {
byte[] bytes = fileToByte(filePath);
return encode(bytes);
}
/** */
/**
* <p>
* BASE64字符串转回文件
* </p>
*
* @param filePath
* 文件绝对路径
* @param base64
* 编码字符串
* @throws Exception
*/
public static void decodeToFile(String filePath, String base64) throws Exception {
byte[] bytes = decode(base64);
byteArrayToFile(bytes, filePath);
}
/** */
/**
* <p>
* 文件转换为二进制数组
* </p>
*
* @param filePath
* 文件路径
* @return
* @throws Exception
*/
public static byte[] fileToByte(String filePath) throws Exception {
byte[] data = new byte[0];
File file = new File(filePath);
if (file.exists()) {
FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
byte[] cache = new byte[CACHE_SIZE];
int nRead = 0;
while ((nRead = in.read(cache)) != -1) {
out.write(cache, 0, nRead);
out.flush();
}
out.close();
in.close();
data = out.toByteArray();
}
return data;
}
/** */
/**
* <p>
* 二进制数据写文件
* </p>
*
* @param bytes
* 二进制数据
* @param filePath
* 文件生成目录
*/
public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception {
InputStream in = new ByteArrayInputStream(bytes);
File destFile = new File(filePath);
if (!destFile.getParentFile().exists()) {
destFile.getParentFile().mkdirs();
}
destFile.createNewFile();
OutputStream out = new FileOutputStream(destFile);
byte[] cache = new byte[CACHE_SIZE];
int nRead = 0;
while ((nRead = in.read(cache)) != -1) {
out.write(cache, 0, nRead);
out.flush();
}
out.close();
in.close();
}
}