这几天一直做安全登录网上查了好多资料不尽如意
具体实现思路如下
服务端生成公钥与私钥保存
客户端在请求到登录页面后随机生成一字符串
后此随机字符串作为密钥加密密码再用从服务端获取到的公钥加密生成的随机字符串
将此两段密文传入服务端服务端用私钥解出随机字符串再用此私钥解出加密的密文
这其中有一个关键是解决服务端的公钥传入客户端客户端用此公钥加密字符串后后又能在服务端用私钥解出
此文即为实现此步而作
加密算法为RSA
服务端的RSA java实现
/**
*
*/
package comsunsoftstrutsutil;
import javaioByteArrayOutputStream;
import javaioFileInputStream;
import javaioFileOutputStream;
import javaioObjectInputStream;
import javaioObjectOutputStream;
import javamathBigInteger;
import javasecurityKeyFactory;
import javasecurityKeyPair;
import javasecurityKeyPairGenerator;
import javasecurityNoSuchAlgorithmException;
import javasecurityPrivateKey;
import javasecurityPublicKey;
import javasecuritySecureRandom;
import javasecurityinterfacesRSAPrivateKey;
import javasecurityinterfacesRSAPublicKey;
import javasecurityspecInvalidKeySpecException;
import javasecurityspecRSAPrivateKeySpec;
import javasecurityspecRSAPublicKeySpec;
import javaxcryptoCipher;
/**
* RSA 工具类提供加密解密生成密钥对等方法
* 需要到下载bcprovjdkjar
*
*/
public class RSAUtil {
/**
* * 生成密钥对 *
*
* @return KeyPair *
* @throws EncryptException
*/
public static KeyPair generateKeyPair() throws Exception {
try {
KeyPairGenerator keyPairGen = KeyPairGeneratorgetInstance(RSA
new orgbouncycastlejceproviderBouncyCastleProvider());
final int KEY_SIZE = ;// 没什么好说的了这个值关系到块加密的大小可以更改但是不要太大否则效率会低
keyPairGeninitialize(KEY_SIZE new SecureRandom());
KeyPair keyPair = keyPairGengenerateKeyPair();
saveKeyPair(keyPair);
return keyPair;
} catch (Exception e) {
throw new Exception(egetMessage());
}
}
public static KeyPair getKeyPair()throws Exception{
FileInputStream fis = new FileInputStream(C:/RSAKeytxt);
ObjectInputStream oos = new ObjectInputStream(fis);
KeyPair kp= (KeyPair) oosreadObject();
oosclose();
fisclose();
return kp;
}
public static void saveKeyPair(KeyPair kp)throws Exception{
FileOutputStream fos = new FileOutputStream(C:/RSAKeytxt);
ObjectOutputStream oos = new ObjectOutputStream(fos);
//生成密钥
ooswriteObject(kp);
oosclose();
fosclose();
}
/**
* * 生成公钥 *
*
* @param modulus *
* @param publicExponent *
* @return RSAPublicKey *
* @throws Exception
*/
public static RSAPublicKey generateRSAPublicKey(byte[] modulus
byte[] publicExponent) throws Exception {
KeyFactory keyFac = null;
try {
keyFac = KeyFactorygetInstance(RSA
new orgbouncycastlejceproviderBouncyCastleProvider());
} catch (NoSuchAlgorithmException ex) {
throw new Exception(exgetMessage());
}
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
modulus) new BigInteger(publicExponent));
try {
return (RSAPublicKey) keyFacgeneratePublic(pubKeySpec);
} catch (InvalidKeySpecException ex) {
throw new Exception(exgetMessage());
}
}
/**
* * 生成私钥 *
*
* @param modulus *
* @param privateExponent *
* @return RSAPrivateKey *
* @throws Exception
*/
public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus
byte[] privateExponent) throws Exception {
KeyFactory keyFac = null;
try {
keyFac = KeyFactorygetInstance(RSA
new orgbouncycastlejceproviderBouncyCastleProvider());
} catch (NoSuchAlgorithmException ex) {
throw new Exception(exgetMessage());
}
RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(
modulus) new BigInteger(privateExponent));
try {
return (RSAPrivateKey) keyFacgeneratePrivate(priKeySpec);
} catch (InvalidKeySpecException ex) {
throw new Exception(exgetMessage());
}
}
/**
* * 加密 *
*
* @param key
* 加密的密钥 *
* @param data
* 待加密的明文数据 *
* @return 加密后的数据 *
* @throws Exception
*/
public static byte[] encrypt(PublicKey pk byte[] data) throws Exception {
try {
Cipher cipher = CiphergetInstance(RSA
new orgbouncycastlejceproviderBouncyCastleProvider());
cipherinit(CipherENCRYPT_MODE pk);
int blockSize = ciphergetBlockSize();// 获得加密块大小如加密前数据为个byte而key_size=
// 加密块大小为
// byte加密后为个byte;因此共有个加密块第一个
// byte第二个为个byte
int outputSize = ciphergetOutputSize(datalength);// 获得加密块加密后块大小
int leavedSize = datalength % blockSize;
int blocksSize = leavedSize != ? datalength / blockSize +
: datalength / blockSize;
byte[] raw = new byte[outputSize * blocksSize];
int i = ;
while (datalength i * blockSize > ) {
if (datalength i * blockSize > blockSize)
cipherdoFinal(data i * blockSize blockSize raw i
* outputSize);
else
cipherdoFinal(data i * blockSize datalength i
* blockSize raw i * outputSize);
// 这里面doUpdate方法不可用查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到
// ByteArrayOutputStream中而最后doFinal的时候才将所有的byte[]进行加密可是到了此时加密块大小很可能已经超出了
// OutputSize所以只好用dofinal方法
i++;
}
return raw;
} catch (Exception e) {
throw new Exception(egetMessage());
}
}
/**
* * 解密 *
*
* @param key
* 解密的密钥 *
* @param raw
* 已经加密的数据 *
* @return 解密后的明文 *
* @throws Exception
*/
public static byte[] decrypt(PrivateKey pk byte[] raw) throws Exception {
try {
Cipher cipher = CiphergetInstance(RSA
new orgbouncycastlejceproviderBouncyCastleProvider());
cipherinit(cipherDECRYPT_MODE pk);
int blockSize = ciphergetBlockSize();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
int j = ;
while (rawlength j * blockSize > ) {
boutwrite(cipherdoFinal(raw j * blockSize blockSize));
j++;
}
return bouttoByteArray();
} catch (Exception e) {
throw new Exception(egetMessage());
}
}
/**
* * *
*
* @param args *
* @throws Exception
*/
public static void main(String[] args) throws Exception {
RSAPublicKey rsap = (RSAPublicKey) RSAUtilgenerateKeyPair()getPublic();
String test = hello world;
byte[] en_test = encrypt(getKeyPair()getPublic()testgetBytes());
byte[] de_test = decrypt(getKeyPair()getPrivate()en_test);
Systemoutprintln(new String(de_test));
}
}
/**
*
*/
package comsunsoftstrutsutil;
import javaioByteArrayOutputStream;
import javaioFileInputStream;
import javaioFileOutputStream;
import javaioObjectInputStream;
import javaioObjectOutputStream;
import javamathBigInteger;
import javasecurityKeyFactory;
import javasecurityKeyPair;
import javasecurityKeyPairGenerator;
import javasecurityNoSuchAlgorithmException;
import javasecurityPrivateKey;
import javasecurityPublicKey;
import javasecuritySecureRandom;
import javasecurityinterfacesRSAPrivateKey;
import javasecurityinterfacesRSAPublicKey;
import javasecurityspecInvalidKeySpecException;
import javasecurityspecRSAPrivateKeySpec;
import javasecurityspecRSAPublicKeySpec;
import javaxcryptoCipher;
/**
* RSA 工具类提供加密解密生成密钥对等方法
* 需要到下载bcprovjdkjar
*
*/
public class RSAUtil {
/**
* * 生成密钥对 *
*
* @return KeyPair *
* @throws EncryptException
*/
public static KeyPair generateKeyPair() throws Exception {
try {
KeyPairGenerator keyPairGen = KeyPairGeneratorgetInstance(RSA
new orgbouncycastlejceproviderBouncyCastleProvider());
final int KEY_SIZE = ;// 没什么好说的了这个值关系到块加密的大小可以更改但是不要太大否则效率会低
keyPairGeninitialize(KEY_SIZE new SecureRandom());
KeyPair keyPair = keyPairGengenerateKeyPair();
saveKeyPair(keyPair);
return keyPair;
} catch (Exception e) {
throw new Exception(egetMessage());
}
}
public static KeyPair getKeyPair()throws Exception{
FileInputStream fis = new FileInputStream(C:/RSAKeytxt);
ObjectInputStream oos = new ObjectInputStream(fis);
KeyPair kp= (KeyPair) oosreadObject();
oosclose();
fisclose();
return kp;
}
public static void saveKeyPair(KeyPair kp)throws Exception{
FileOutputStream fos = new FileOutputStream(C:/RSAKeytxt);
ObjectOutputStream oos = new ObjectOutputStream(fos);
//生成密钥
ooswriteObject(kp);
oosclose();
fosclose();
}
/**
* * 生成公钥 *
*
* @param modulus *
* @param publicExponent *
* @return RSAPublicKey *
* @throws Exception
*/
public static RSAPublicKey generateRSAPublicKey(byte[] modulus
byte[] publicExponent) throws Exception {
KeyFactory keyFac = null;
try {
keyFac = KeyFactorygetInstance(RSA
new orgbouncycastlejceproviderBouncyCastleProvider());
} catch (NoSuchAlgorithmException ex) {
throw new Exception(exgetMessage());
}
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
modulus) new BigInteger(publicExponent));
try {
return (RSAPublicKey) keyFacgeneratePublic(pubKeySpec);
} catch (InvalidKeySpecException ex) {
throw new Exception(exgetMessage());
}
}
/**
* * 生成私钥 *
*
* @param modulus *
* @param privateExponent *
* @return RSAPrivateKey *
* @throws Exception
*/
public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus
byte[] privateExponent) throws Exception {
KeyFactory keyFac = null;
try {
keyFac = KeyFactorygetInstance(RSA
new orgbouncycastlejceproviderBouncyCastleProvider());
} catch (NoSuchAlgorithmException ex) {
throw new Exception(exgetMessage());
}
RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(
modulus) new BigInteger(privateExponent));
try {
return (RSAPrivateKey) keyFacgeneratePrivate(priKeySpec);
} catch (InvalidKeySpecException ex) {
throw new Exception(exgetMessage());
}
}
/**
* * 加密 *
*
* @param key
* 加密的密钥 *
* @param data
* 待加密的明文数据 *
* @return 加密后的数据 *
* @throws Exception
*/
public static byte[] encrypt(PublicKey pk byte[] data) throws Exception {
try {
Cipher cipher = CiphergetInstance(RSA
new orgbouncycastlejceproviderBouncyCastleProvider());
cipherinit(CipherENCRYPT_MODE pk);
int blockSize = ciphergetBlockSize();// 获得加密块大小如加密前数据为个byte而key_size=
// 加密块大小为
// byte加密后为个byte;因此共有个加密块第一个
// byte第二个为个byte
int outputSize = ciphergetOutputSize(datalength);// 获得加密块加密后块大小
int leavedSize = datalength % blockSize;
int blocksSize = leavedSize != ? datalength / blockSize +
: datalength / blockSize;
byte[] raw = new byte[outputSize * blocksSize];
int i = ;
while (datalength i * blockSize > ) {
if (datalength i * blockSize > blockSize)
cipherdoFinal(data i * blockSize blockSize raw i
* outputSize);
else
cipherdoFinal(data i * blockSize datalength i
* blockSize raw i * outputSize);
// 这里面doUpdate方法不可用查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到
// ByteArrayOutputStream中而最后doFinal的时候才将所有的byte[]进行加密可是到了此时加密块大小很可能已经超出了
// OutputSize所以只好用dofinal方法
i++;
}
return raw;
} catch (Exception e) {
throw new Exception(egetMessage());
}
}
/**
* * 解密 *
*
* @param key
* 解密的密钥 *
* @param raw
* 已经加密的数据 *
* @return 解密后的明文 *
* @throws Exception
*/
public static byte[] decrypt(PrivateKey pk byte[] raw) throws Exception {
try {
Cipher cipher = CiphergetInstance(RSA
new orgbouncycastlejceproviderBouncyCastleProvider());
cipherinit(cipherDECRYPT_MODE pk);
int blockSize = ciphergetBlockSize();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
int j = ;
while (rawlength j * blockSize > ) {
boutwrite(cipherdoFinal(raw j * blockSize blockSize));
j++;
}
return bouttoByteArray();
} catch (Exception e) {
throw new Exception(egetMessage());
}
}
/**
* * *
*
* @param args *
* @throws Exception
*/
public static void main(String[] args) throws Exception {
RSAPublicKey rsap = (RSAPublicKey) RSAUtilgenerateKeyPair()getPublic();
String test = hello world;
byte[] en_test = encrypt(getKeyPair()getPublic()testgetBytes());
byte[] de_test = decrypt(getKeyPair()getPrivate()en_test);
<A title=system target=_blank>system</A>outprintln(new String(de_test));
}
}
测试页面
IndexActionjava
/*
* Generated by MyEclipse Struts
* Template path: templates/java/JavaClassvtl
*/
package comsunsoftstrutsaction;
import javasecurityinterfacesRSAPrivateKey;
import javasecurityinterfacesRSAPublicKey;
import javaxservlethttpHttpServletRequest;
import javaxservlethttpHttpServletResponse;
import orgapachestrutsactionAction;
import orgapachestrutsactionActionForm;
import orgapachestrutsactionActionForward;
import orgapachestrutsactionActionMapping;
import comsunsoftstrutsutilRSAUtil;
/**
* MyEclipse Struts
* Creation date:
*
* XDoclet definition:
* @strutsaction validate=true
*/
public class IndexAction extends Action {
/*
* Generated Methods
*/
/**
* Method execute
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward execute(ActionMapping mapping ActionForm form
HttpServletRequest request HttpServletResponse response)throws Exception {
RSAPublicKey rsap = (RSAPublicKey) RSAUtilgetKeyPair()getPublic();
String module = rsapgetModulus()toString();
String empoent = rsapgetPublicExponent()toString();
Systemoutprintln(module);
Systemoutprintln(module);
Systemoutprintln(empoent);
Systemoutprintln(empoent);
requestsetAttribute(m module);
requestsetAttribute(e empoent);
return mappingfindForward(login);
}
}
/*
* Generated by MyEclipse Struts
* Template path: templates/java/JavaClassvtl
*/
package comsunsoftstrutsaction;
import javasecurityinterfacesRSAPrivateKey;
import javasecurityinterfacesRSAPublicKey;
import javaxservlethttpHttpServletRequest;
import javaxservlethttpHttpServletResponse;
import orgapachestrutsactionAction;
import orgapachestrutsactionActionForm;
import orgapachestrutsactionActionForward;
import orgapachestrutsactionActionMapping;
import comsunsoftstrutsutilRSAUtil;
/**
* MyEclipse Struts
* Creation date:
*
* XDoclet definition:
* @strutsaction validate=true
*/
public class IndexAction extends Action {
/*
* Generated Methods
*/
/**
* Method execute
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward execute(ActionMapping mapping ActionForm form
HttpServletRequest request HttpServletResponse response)throws Exception {
RSAPublicKey rsap = (RSAPublicKey) RSAUtilgetKeyPair()getPublic();
String module = rsapgetModulus()toString();
String empoent = rsapgetPublicExponent()toString();
<A title=system target=_blank>system</A>outprintln(module);
<A title=system target=_blank>system</A>outprintln(module);
<A title=system target=_blank>system</A>outprintln(empoent);
<A title=system target=_blank>system</A>outprintln(empoent);
requestsetAttribute(m module);
requestsetAttribute(e empoent);
return mappingfindForward(login);
}
}
通过此action进入登录页面并传入公钥的Modulus 与PublicExponent的hex编码形式
登录页面loginjsp
<%@ page language=java pageEncoding=GBK%>
<%@ taglib uri=bean prefix=bean %>
<%@ taglib uri=html prefix=html %>
<%@ taglib uri=logic prefix=logic %>
<%@ taglib uri=tiles prefix=tiles %>
<!DOCTYPE HTML PUBLIC //WC//DTD HTML Transitional//EN>
<html:html lang=true>
<head>
<html:base />
<title>login</title>
<meta httpequiv=pragma content=nocache>
<meta httpequiv=cachecontrol content=nocache>
<meta httpequiv=expires content=>
<meta httpequiv=keywords content=keywordkeywordkeyword>
<meta httpequiv=description content=This is my page>
<!
<link rel=stylesheet type=text/css >
>
<script type=text/javascript src=js/RSAjs></script>
<script type=text/javascript src=js/BigIntjs></script>
<script type=text/javascript src=js/Barrettjs></script>
<script type=text/javascript>
function rsalogin()
{
bodyRSA();
var result = encryptedString(key documentgetElementById(pwd)value);
//alert(result);
loginFormaction=logindo?result=+result;
loginFormsubmit();
}
var key ;
function bodyRSA()
{
setMaxDigits();
key = new RSAKeyPair(ccdaedaafedccfaeafefcabacac
defdbfaffccfdeaabaffdbdfbaeedceefbbaecdc
aeeedfeecaaeadfdaccfebcabfcfbfddefcbd);
}
</script>
</head>
<body >
<html:form action=login method=post focus=username>
<table border=>
<tr>
<td>Login:</td>
<td><html:text property=username /></td>
</tr>
<tr>
<td>Password:</td>
<td><html:password property=password styleId=pwd/></td>
</tr>
<tr>
<td colspan= align=center><input type=button value=SUBMIT onclick=rsalogin();/></td>
</tr>
</table>
</html:form>
</body>
</html:html>
<%@ page language=java pageEncoding=GBK%>
<%@ taglib uri=bean prefix=bean %>
<%@ taglib uri=html prefix=html %>
<%@ taglib uri=logic prefix=logic %>
<%@ taglib uri=tiles prefix=tiles %>
<!DOCTYPE HTML PUBLIC //WC//DTD HTML Transitional//EN>
<html:html lang=true>
<head>
<html:base />
<title>login</title>
<meta httpequiv=pragma content=nocache>
<meta httpequiv=cachecontrol content=nocache>
<meta httpequiv=expires content=>
<meta httpequiv=keywords content=keywordkeywordkeyword>
<meta httpequiv=description content=This is my page>
<!
<link rel=stylesheet type=text/css >
>
<script type=text/javascript src=js/RSAjs></script>
<script type=text/javascript src=js/BigIntjs></script>
<script type=text/javascript src=js/Barrettjs></script>
<script type=text/javascript>
function rsalogin()
{
bodyRSA();
var result = encryptedString(key documentgetElementById(pwd)value);
//alert(result);
loginFormaction=logindo?result=+result;
loginFormsubmit();
}
var key ;
function bodyRSA()
{
setMaxDigits();
key = new RSAKeyPair(ccdaedaafedccfaeafefcabacac
defdbfaffccfdeaabaffdbdfbaeedceefbbaecd
caeeedfeecaaeadfdaccfebcabfcfbfddefcbd);
}
</script>
</head>
<body >
<html:form action=login method=post focus=username>
<table border=>
<tr>
<td>Login:</td>
<td><html:text property=username /></td>
</tr>
<tr>
<td>Password:</td>
<td><html:password property=password styleId=pwd/></td>
</tr>
<tr>
<td colspan= align=center><input type=button value=SUBMIT onclick=rsalogin();/></td>
</tr>
</table>
</html:form>
</body>
</html:html>
/*
* Generated by MyEclipse Struts
* Template path: templates/java/JavaClassvtl
*/
package comsunsoftstrutsaction;
import javamathBigInteger;
import javaxservlethttpHttpServletRequest;
import javaxservlethttpHttpServletResponse;
import orgapachestrutsactionAction;
import orgapachestrutsactionActionForm;
import orgapachestrutsactionActionForward;
import orgapachestrutsactionActionMapping;
import comsunsoftstrutsutilRSAUtil;
/**
* MyEclipse Struts
* Creation date:
*
* XDoclet definition:
* @strutsaction path=/login name=loginForm input=/loginjsp scope=request validate=true
* @strutsactionforward name=error path=/errorjsp
* @strutsactionforward name=success path=/successjsp
*/
public class LoginAction extends Action {
/*
* Generated Methods
*/
/**
* Method execute
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward execute(ActionMapping mapping ActionForm form
HttpServletRequest request HttpServletResponse response) throws Exception{
//LoginForm loginForm = (LoginForm) form;
String result = requestgetParameter(result);
Systemoutprintln(原文加密后为);
Systemoutprintln(result);
byte[] en_result = new BigInteger(result )toByteArray();
Systemoutprintln(转成byte[]+new String(en_result));
byte[] de_result = RSAUtildecrypt(RSAUtilgetKeyPair()getPrivate()en_result);
Systemoutprintln(还原密文);
Systemoutprintln(new String(de_result));
StringBuffer sb = new StringBuffer();
sbappend(new String(de_result));
Systemoutprintln(sbreverse()toString());
return mappingfindForward(success);
}
}
/*
* Generated by MyEclipse Struts
* Template path: templates/java/JavaClassvtl
*/
package comsunsoftstrutsaction;
import javamathBigInteger;
import javaxservlethttpHttpServletRequest;
import javaxservlethttpHttpServletResponse;
import orgapachestrutsactionAction;
import orgapachestrutsactionActionForm;
import orgapachestrutsactionActionForward;
import orgapachestrutsactionActionMapping;
import comsunsoftstrutsutilRSAUtil;
/**
* MyEclipse Struts
* Creation date:
*
* XDoclet definition:
* @strutsaction path=/login name=loginForm input=/loginjsp scope=request validate=true
* @strutsactionforward name=error path=/errorjsp
* @strutsactionforward name=success path=/successjsp
*/
public class LoginAction extends Action {
/*
* Generated Methods
*/
/**
* Method execute
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward execute(ActionMapping mapping ActionForm form
HttpServletRequest request HttpServletResponse response) throws Exception{
//LoginForm loginForm = (LoginForm) form;
String result = requestgetParameter(result);
<A title=system target=_blank>system</A>outprintln(原文加密后为);
<A title=system target=_blank>system</A>outprintln(result);
byte[] en_result = new BigInteger(result )toByteArray();
<A title=system target=_blank>system</A>outprintln(转成byte[]+new String(en_result));
byte[] de_result = RSAUtildecrypt(RSAUtilgetKeyPair()getPrivate()en_result);
<A title=system target=_blank>system</A>outprintln(还原密文);
<A title=system target=_blank>system</A>outprintln(new String(de_result));
StringBuffer sb = new StringBuffer();
sbappend(new String(de_result));
<A title=system target=_blank>system</A>outprintln(sbreverse()toString());
return mappingfindForward(success);
}
}