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

来源:互联网 发布:网络管理系统 编辑:程序博客网 时间:2024/06/16 23:59

    项目包含敏感数据,传输过程要求加密,我们研究了两种算法: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加密用的keyvar key  = randomString();//随机生成AES的key 和 iv        var iv   = randomString();var aKey = encryptedString(keyRSA, encodeURIComponent(key)); //RSA加密AES的keyvar aIv = encryptedString(keyRSA, encodeURIComponent(iv)); //RSA加密AES的ivvar 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 和 ivtry {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个byteint 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);elsecipher.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加密文件下载


0 0
原创粉丝点击