您的位置:首页 > 其它

RSA加密传输AES的key和iv (补2016年11月)

2017-02-01 17:37 369 查看
    项目包含敏感数据,传输过程要求加密,我们研究了两种算法:AES和RSA

    传输过程,也就是指前台到后台

    AES,对称加密;只有一把密钥,获得密钥,即可解开加密内容

    RSA,非对称加密,有两把密钥,公钥和私钥,获得两把钥匙,才可解开加密内容

    RSA对需加密的内容长度有限制,前辈们就采取分段加密,但自己并没有解决遇到的问题,技术研究时间有限,最终项目组采取了以下加密方法:

    1.每次请求,随机生成AES的key和iv

    2.用RSA的公钥加密AES的key和iv

    3.用AES加密向后台请求的参数

    4.ajax向后台发送post请求,请求参数有:(1)AES加密的参数 (2)RSA加密的AES的key (3)RSA加密的AES的iv

    5.后台RSA私钥解密key和iv

    6.后台AES解密前台参数

    7.==========================根据参数,读数据库==========================

    8.获得内容

    9.对内容进行AES加密,返回到前台

    10.前台进行AES解密,并展示

    11.RSA的公私密钥对需定期更换

   

以下代码是网上查询和自己思考综合的结果,希望有帮助!

前台代码:

<%@ page language="java" pageEncoding="UTF-8"%>
<%@ page contentType="text/html; chareset=UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>

<style>
*{margin:0;padding:0}
.demo-wrap{width: 400px;height: 50px;margin: 50px auto auto auto}
</style>

<script src="./js/jquery-1.6.4.min.js"></script>
<script src="./js/Encryption.js"></script>
<script src="./js/RSA.js"></script>
<script src="./js/BigInt.js"></script>
<script src="./js/Barrett.js"></script>
<script src="./rollups/aes.js"></script>

</head>

<body>

<div class="demo-wrap">
输入框:<input type="text" id="data-ipt" maxlength="1000000"/>
<input type="button" value="提交" onclick="enAES();" />
<br/>
数据获得:
<p id="decrypted"></p>
</div>

<script type="text/javascript">

function enAES(){
var keyRSA = bodyRSA(); //生成RSA加密用的key
var key  = randomString();//随机生成AES的key 和 iv
var iv   = randomString();
var aKey = encryptedString(keyRSA, encodeURIComponent(key)); //RSA加密AES的key
var aIv = encryptedString(keyRSA, encodeURIComponent(iv)); //RSA加密AES的iv
var inputData = document.getElementById("data-ipt").value; //获取输入框内容
var miwen = getAesString(encodeURIComponent(inputData),key,iv); //AES加密输入框内容

/** 调用后台: ajax */
$.ajax({
url: "/jiami/RSAAES",
type: "post",
data: {"miwen":miwen,"aKey":aKey,"aIv":aIv},
cache: false,
async : false,
dataType: "json",
success: function (data)
{
var decryptedStr = getDAesString(data,key,iv);
document.getElementById("decrypted").innerHTML = decodeURIComponent(decryptedStr);
},
error:function (XMLHttpRequest, textStatus, errorThrown) {
alert("与服务器连接失败!");
}
});
}

</script>

</body>
</html>


后台代码:

package com;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;

import com.google.gson.Gson;

public class RSAAES extends HttpServlet{

private static final long serialVersionUID = -5657272720504177622L;
private static String RSAKeyStore = "C:/RSAKey.txt";

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

request.setCharacterEncoding("UTF-8");	//设定客户端提交给servlet的内容按UTF-8编码
response.setCharacterEncoding("UTF-8");	//设定servlet传回给客户端的内容按UTF-8编码
response.setContentType("text/html;charset=UTF-8");	//告知浏览器用UTF-8格式解析内容

String miwen = request.getParameter("miwen");
String aKey = request.getParameter("aKey");
String aIv = request.getParameter("aIv");

//解密RSA加密的AES的key 和 iv
try {
aKey = getString(aKey);
aIv = getString(aIv);
} catch (Exception e) {
e.printStackTrace();
}

//解密由AES加密的密文
String decrypted = AES_CBC_Decrypt(miwen, aKey.getBytes(), aIv.getBytes());
decrypted = URLDecoder.decode(decrypted,"UTF-8");
System.out.println("解密后:"+decrypted);

/**
* 根据参数 decrypted ,模拟连接数据库,查得以下内容
*/
String yuanCode = "胡歌~!@#¥%……&*()——+=-0987654321·{}:”》?《,。、;’【】、|"
+ "~!@#$%^&*()_LLL";

//后台AES加密
yuanCode = URLEncoder.encode(yuanCode,"UTF-8");
String jiami = AES_CBC_Encrypt(yuanCode,aKey.getBytes(), aIv.getBytes());
Gson gson = new Gson();
String json = gson.toJson(jiami);
response.getWriter().write(json);
}

/**
* AES加密
* @param content  明文
* @param keyBytes 秘钥
* @param iv      偏移量
* @return
*/
public static String AES_CBC_Encrypt(String content, byte[] keyBytes, byte[] iv){

try{
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
byte[] result=cipher.doFinal(content.getBytes());
return new String(Base64.encodeBase64(result),"UTF-8");
}catch (Exception e) {
System.out.println("exception:"+e.toString());
}
return null;
}

/**
* AES解密
* @param content   密文
* @param keyBytes  秘钥
* @param iv        偏移量
* @return
*/
public static String AES_CBC_Decrypt(String content, byte[] keyBytes, byte[] iv){

try{
content = content.replaceAll(" ", "+");
byte[] decryptBaseData=Base64.decodeBase64(content.getBytes("utf-8"));
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
byte[] result=cipher.doFinal(decryptBaseData);
return new String(result);
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return null;
}

/**
* 字符串转为 byte[]
* @param hexString
* @return
*/
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}

/**
* Convert char to byte
*
* @param c char
* @return byte
*/
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}

/**
* 解密由RSA加密的AES的key 和 iv
* @param para
* @return
* @throws Exception
*/
public String getString(String para) throws Exception{
byte[] KeyB = hexStringToBytes(para);
KeyB = decrypt(getKeyPair().getPrivate(),KeyB);
StringBuffer sbKey = new StringBuffer();
sbKey.append(new String(KeyB));
para = sbKey.reverse().toString();
return URLDecoder.decode(para,"UTF-8");
}

/**
* * 生成密钥对 *
*
* @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());

saveKeyPair(keyPair);
return keyPair;
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}

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;
}

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 modulus *
* @param publicExponent *
* @return RSAPublicKey *
* @throws Exception
*/
public static RSAPublicKey generateRSAPublicKey(byte[] modulus,
byte[] publicExponent) throws Exception {
KeyFactory keyFac = null;
try {
keyFac = KeyFactory.getInstance("RSA",
new org.bouncycastle.jce.provider.BouncyCastleProvider());
} catch (NoSuchAlgorithmException ex) {
throw new Exception(ex.getMessage());
}

RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
modulus), new BigInteger(publicExponent));
try {
return (RSAPublicKey) keyFac.generatePublic(pubKeySpec);
} catch (InvalidKeySpecException ex) {
throw new Exception(ex.getMessage());
}
}

/**
* * 生成私钥 *
*
* @param modulus *
* @param privateExponent *
* @return RSAPrivateKey *
* @throws Exception
*/
public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus,
byte[] privateExponent) throws Exception {
KeyFactory keyFac = null;
try {
keyFac = KeyFactory.getInstance("RSA",
new org.bouncycastle.jce.provider.BouncyCastleProvider());
} catch (NoSuchAlgorithmException ex) {
throw new Exception(ex.getMessage());
}

RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(
modulus), new BigInteger(privateExponent));
try {
return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec);
} catch (InvalidKeySpecException ex) {
throw new Exception(ex.getMessage());
}
}

/**
* * 加密 *
*
* @param key
*            加密的密钥 *
* @param data
*            待加密的明文数据 *
* @return 加密后的数据 *
* @throws Exception
*/
public static byte[] encrypt(PublicKey pk, byte[] data) throws Exception {
try {
Cipher cipher = Cipher.getInstance("RSA",
new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE, pk);
int blockSize = cipher.getBlockSize();// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024
// 加密块大小为127
// byte,加密后为128个byte;因此共有2个加密块,第一个127
// byte第二个为1个byte
int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小
int leavedSize = data.length % blockSize;
int blocksSize = leavedSize != 0 ? data.length / blockSize + 1
: data.length / blockSize;
byte[] raw = new byte[outputSize * blocksSize];
int i = 0;
while (data.length - i * blockSize > 0) {
if (data.length - i * blockSize > blockSize)
cipher.doFinal(data, i * blockSize, blockSize, raw, i
* outputSize);
else
cipher.doFinal(data, i * blockSize, data.length - i
* blockSize, raw, i * outputSize);
// 这里面doUpdate方法不可用,查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到
// ByteArrayOutputStream中,而最后doFinal的时候才将所有的byte[]进行加密,可是到了此时加密块大小很可能已经超出了
// OutputSize所以只好用dofinal方法。

i++;
}
return raw;
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}

/**
* * 解密 *
*
* @param key
*            解密的密钥 *
* @param raw
*            已经加密的数据 *
* @return 解密后的明文 *
* @throws Exception
*/
@SuppressWarnings("static-access")
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());
}
}
}


源码下载点击这里




RSA加密文件下载

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  rsa 加密