RSA是非对称加密,关于它的算法原理。可以查看这个博客链接,我是没看懂(本人数学太差)。
这里介绍下简单的实现方式。
前端需要导入RSA.js、BigInt.js、Barrett.js 。后端需要 依赖 bcprov-jdk15on-160.jar 。js与jar包百度云分享。
这是后端的工具类方法
public class UtilsRSA {
private static String RSAKeyStore = "E:/RSAKey.txt";
/**
* * 生成密钥对 *
* @return KeyPair *
* @throws EncryptException
*/
public static KeyPair generateKeyPair() throws Exception {
try {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA",
new org.bouncycastle.jce.provider.BouncyCastleProvider());
final int KEY_SIZE = 1024;// 没什么好说的了,这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会低
keyPairGen.initialize(KEY_SIZE, new SecureRandom());
KeyPair keyPair = keyPairGen.generateKeyPair();
// System.out.println(keyPair.getPrivate());
// System.out.println(keyPair.getPublic());
// System.out.println("getModulus");
// RSAPublicKey rsapublicKey = (RSAPublicKey) keyPair.getPublic();
// System.out.println(rsapublicKey.getModulus());
// System.out.println("十六进制=>"+UtilsRSA.intToHex(rsapublicKey.getModulus()));
// System.out.println("getPublicExponent");
// System.out.println(rsapublicKey.getPublicExponent());
// System.out.println("十六进制=>"+UtilsRSA.intToHex(rsapublicKey.getPublicExponent()));
//保存keyPair
saveKeyPair(keyPair);
return keyPair;
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}
//得到PublicModulus
public static String getPublicModulus() throws Exception {
FileInputStream fis = new FileInputStream(RSAKeyStore);
ObjectInputStream oos = new ObjectInputStream(fis);
KeyPair keyPair = (KeyPair) oos.readObject();
oos.close();
fis.close();
RSAPublicKey rsapublicKey = (RSAPublicKey) keyPair.getPublic();
return UtilsRSA.intToHex(rsapublicKey.getModulus());
}
//得到PublicExponent
public static String getPublicExponent() throws Exception {
FileInputStream fis = new FileInputStream(RSAKeyStore);
ObjectInputStream oos = new ObjectInputStream(fis);
KeyPair keyPair = (KeyPair) oos.readObject();
oos.close();
fis.close();
RSAPublicKey rsapublicKey = (RSAPublicKey) keyPair.getPublic();
return UtilsRSA.intToHex(rsapublicKey.getPublicExponent());
}
//从本地文件中得到KeyPair
public static KeyPair getKeyPair() throws Exception {
FileInputStream fis = new FileInputStream(RSAKeyStore);
ObjectInputStream oos = new ObjectInputStream(fis);
KeyPair kp = (KeyPair) oos.readObject();
oos.close();
fis.close();
return kp;
}
//保存在本地文件中(这里写了保存在本地的方式,你也可以保存在session中)
public static void saveKeyPair(KeyPair kp) throws Exception {
FileOutputStream fos = new FileOutputStream(RSAKeyStore);
ObjectOutputStream oos = new ObjectOutputStream(fos);
// 保存密钥
oos.writeObject(kp);
oos.close();
fos.close();
}
/**
* * 解密 *
*
* @param key 解密的密钥 *
* @param raw 已经加密的数据 *
* @return 解密后的明文 *
* @throws Exception
*/
public static byte[] decrypt(PrivateKey pk, byte[] raw) throws Exception {
try {
Cipher cipher = Cipher.getInstance("RSA",
new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(cipher.DECRYPT_MODE, pk);
int blockSize = cipher.getBlockSize();
ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
int j = 0;
while (raw.length - j * blockSize > 0) {
bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
j++;
}
return bout.toByteArray();
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}
//把十进制的BigInteger数转换为十六进制的字符串
private static String intToHex(BigInteger n) {
BigInteger zero = new BigInteger("0");
BigInteger bi2 = new BigInteger("16");
StringBuilder sb = new StringBuilder();
String a;
char []b = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
while(n.compareTo(zero) > 0){
BigInteger[] arr = n.divideAndRemainder(bi2);
int index = Integer.valueOf(arr[1].toString());
sb = sb.append(b[index]);
n = arr[0];
}
a = sb.reverse().toString();
return a;
}
/**
* * *
* 可以先使用main方法生成一个KeyPair,并保存在本地。方便获取使用(保存方式随你使用);
*/
public static void main(String[] args) throws Exception {
UtilsRSA.generateKeyPair();
}
}
前端JSP代码。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="mseas.utils.UtilsRSA" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>RSA测试</title>
<script type="text/javascript" src="js/comm/RSA.js"></script>
<script type="text/javascript" src="js/comm/BigInt.js"></script>
<script type="text/javascript" src="js/comm/Barrett.js"></script>
<script type="text/javascript">
function rsalogin(){
var thisPwd = document.getElementById("password").value;
bodyRSA(); //获得公钥
var result = encryptedString(key, thisPwd);//加密
document.getElementById("result").value = result;
alert(thisPwd+"\r\n"+result);
loginForm.action="/RSAWeb/TestSer";//访问的servlet路径
loginForm.submit();//提交
}
var key ;
function bodyRSA(){
//与后台密钥长度成正比
setMaxDigits(130);
//参数传值('exponent', '', 'Modulus')
key = new RSAKeyPair("<%=UtilsRSA.getPublicExponent() %>","","<%=UtilsRSA.getPublicModulus() %>");
}
</script>
</head>
<body>
<form method="post" name="loginForm" target=_blank>
<table border="0">
<tr>
<td>
Password:
</td>
<td>
<input type='text' name="password" id="password" style='width:300px' value=""/>
<input type="hidden" name="result" id="result" />
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="button" value="SUBMIT" onclick="rsalogin();" />
</td>
</tr>
</table>
</form>
</body>
</html>
后台servlet处理并解析。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
String result = request.getParameter("result");
System.out.println("原文加密后为:");
System.out.println("result=>"+result);
//new BigInteger(result, 16) 这个‘16’代表着 result参数是 16进制的 结果是返回 十进制的
byte[] en_result = new BigInteger(result, 16).toByteArray();
System.out.println("转成byte[]" + new String(en_result));
byte[] de_result = UtilsRSA.decrypt(UtilsRSA.getKeyPair().getPrivate(), en_result);
System.out.println("还原密文:");
System.out.println(new String(de_result));
} catch (Exception e) {
e.printStackTrace();
}
response.getWriter().append("Served at: ").append("End!");
}
这里还有一份比较详细的代码,百度云分享 分享链接