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

    项目包含敏感数据,传输过程要求加密,我们研究了两种算法: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="提交" οnclick="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加密文件下载


  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值