使⽤rsa对⽤户名,密码加解密传输(js前端加密,java后台解
密)
由于安全原因,需要对⽤户名密码做加密传输,,考虑⼏种⽅式,md5,base64,rsa,由于md5加密不可逆,为了减⼩代码的改动放
弃,base64加密严格来说并不是⽤来加密的主要是⽤来⽅便数据传输的,所以采⽤rsa⾮对称加密的⽅式!
贴代码
java
public class Test {
public static void main(String[] args) throws Exception {
//⽣产秘钥对
//bouncy castle(轻量级密码术包)是⼀种⽤于 Java 平台的开放源码的轻量级密码术包
Provider provider = new BouncyCastleProvider();
KeyPairGenerator keyPairGen = Instance("RSA", provider);
keyPairGen.initialize(1024, new SecureRandom());
KeyPair keyPair = ateKeyPair();
//打印公钥
System.out.Public());
//打印私钥
System.out.Private());
执⾏以上代码得到如下
其中private exponent是私钥⽤户后台解密不能泄露出去
RSA Public Key 中的modulus和public exponent 公钥⽤于交给前段js加密
前端:引⼊js⽂件    security.js
html页⾯中导⼊此js,以下为js加密代码
//rsa 私钥
var password = 'ceshi';
var username = 'user_01';
var key = KeyPair('10001', '', '9a12794abc04faa6f78350fe0e73403994eb58199d030477f97d6acd9825e9fc13b230edcb68741d1f87b257506e90 //加密后的密码
password = ptedString(key, password);
console.log("password:" + password);
//加密后的⽤户名
username = ptedString(key,username);
console.log("username" + username);
java后台解密
public static void main(String[] args) throws Exception {
//rsa js加密,后台java解密
//RSA Private CRT Key的modulus
String hexModulus = "9a12794abc04faa6f78350fe0e73403994eb58199d030477f97d6acd9825e9fc13b230edcb68741d1f87b257506e909df0926ad9c12ab99b4  //RSA Private CRT Key的private exponent
String hexPrivateExponent = "5131951bee53cd67ba1e48cb6a00108387d832786507170ec6baf252e070728b7631bc99444d8a8b62775763ae2e6625e586b3a    // js页⾯加密后的密码和⽤户名
String passwrod = "03f87bada52fc13c892b39498cb06d4641eb0aefb92d7e243cdd7683c0aab29424954cb18cc53e92c589f9a1096cc8dbe5a75429321ba177f18  String username = "5354f3480cce53432b29fd212577951dd8b0fc6a002e440f96d7519a5233e4040fe9ad2d27d0fe8b20dfe390a1d21b0cf362818df9706c5f7f49  Provider provider = new BouncyCastleProvider();
KeyFactory keyFac = Instance("RSA", provider);
RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(hexModulus, 16), new BigInteger(hexPrivateExponent, 16));
// ⽣成⽤于解密的私钥
RSAPrivateKey pk = (RSAPrivateKey) atePrivate(priKeySpec);
// 解密
Cipher cipher = Instance("RSA", provider);
cipher.init(2, pk);
byte[] pwd = cipher.doFinal(Hex.CharArray()));
byte[] usn = cipher.doFinal(Hex.CharArray()));
System.out.verse(new String(pwd)));
System.out.verse(new String(usn)));
运⾏结果,解密成功
题外话:rsa加解密效率⽐较慢,可以做⼀些⼩改动来提升效率,上代码,测试过户解密⼤概在3毫秒,改动之前解密⼀次需要200毫秒左
右!
static Cipher cipher;
static RSAPrivateKey pk;
static org.slf4j.Logger log = Logger(LogonAction.class);
//传⼊加密后的密码,进⾏解密    pwOrUn加密后的密码
public String passwordAndUsernameRsaDecode(String pwOrUn) {
try {
long l = System.currentTimeMillis();
pk = getPk();
// 解密
cipher = getCipher();
cipher.init(2, LogonAction.pk);
byte[] rawPasswordByte = cipher.doFinal(Hex.CharArray()));
pwOrUn = verse(new String(rawPasswordByte));
long l1 = System.currentTimeMillis();
log.info("解密成功,⽤时" + (l1-l));
}catch (Exception e){
throw new RuntimeException("Rsa密码解密失败");
}
return pwOrUn;
}
public static synchronized RSAPrivateKey getPk()
throws Exception{
if(pk == null){
log.info("私钥为空,⽣成私钥");
String hexModulus = "c6e442535e1dd6968e4ccd7735299278d989cb938a2f97c1081c4e6796895a3063510592e2e90ed427d5a604428ce46391dcb2ba6b5f4      String hexPrivateExponent = "1ce625c15c66146a983d82cd493c95242ae35603ba73b4f810682c838d0f4bbb242d5c2bc9cee12b41bff1108b369885fadaa05f0      // 这就是上⾯html输出的密⽂
Provider provider = new BouncyCastleProvider();
KeyFactory keyFac = Instance("RSA", provider);
RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(hexModulus, 16), new BigInteger(hexPrivateExponent, 16));
// ⽣成⽤于解密的私钥
pk = (RSAPrivateKey) atePrivate(priKeySpec);
}
return pk;
}
public static synchronized Cipher getCipher()
java源代码加密
throws NoSuchAlgorithmException, NoSuchPaddingException {
if (cipher == null) {
cipher = Instance("RSA", new BouncyCastleProvider());
}
return cipher;
}
以上改动后的⽅法经过线上测试存在问题:问题如下 :
java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block
问题描述:加密后的密码,进⾏解密,会出现同样的加密密码有时会解密成功,有时解密失败的情况!解密失败时报以上错误!
查阅资料,出现此错误有两种可能性
1,加密的密码过长导致
2,多线程引起的
分析之后排除1,那么就是多线程引起的问题
原因:pto.Cipher 是有状态的,不要把 Cipher 当做⼀个静态变量,除⾮你的程序是单线程的,也就是说你能够保证同⼀时刻只有⼀个线程在调⽤ Cipher。否则你可能会遇到 java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block 异常。解决⽅法:
public  synchronized String passwordAndUsernameRsaDecode(String pwOrUn) {
try {
long l = System.currentTimeMillis();
pk = getPk();
// 解密
cipher = getCipher();
cipher.init(2, LogonAction.pk);
byte[] rawPasswordByte = cipher.doFinal(Hex.CharArray()));
pwOrUn = verse(new String(rawPasswordByte));
long l1 = System.currentTimeMillis();
log.info("解密成功,⽤时" + (l1-l));
}catch (Exception e){
throw new RuntimeException("Rsa密码解密失败");
}
return pwOrUn;
}
在此⽅法上加上同步,解决问题。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。