基本算法首页投稿(暂停使用,暂停投稿)Java学习笔记

AES和RSA加密的组合使用(一)

2016-07-21  本文已影响1406人  Dora404

关于接口安全加解密,做了一些联调,由于工作时间关系,一步步的将使用方法和技巧,实现步骤在简书上发布文章,记录下使用经验。加密步骤将按照下面目录持续更新:

  1. RAS的使用
  2. AES的使用
  3. Base64的使用
  4. 联调问题及解决方案
  5. AES与RAS的联合使用

一、 RAS非对称加密的使用
这里就略过了对RAS非对称加密的介绍,直接上代码:

Test类

package rsa;

import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

import com.google.gson.Gson;

/**
 * 使用RSA实现服务端客户端加解密
 * @author zhaofh 2016年7月6日
 *@version 1.1
 */
public class EncryptionTest2 {
    //客户端-公钥加密
    public static String public_key_client = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn6qfbrh5Or34H4tXEhDhIm30KcPIIWPdklRSK64rVS6Qx/oMqHFVDELzGTNcPaKw04kSbNHTwNQpumtPS/mZVPpTxeKg/jbDMkGYEoCNnVfgwZCBhpz6BxbSovTGWLzlmNBveG0cn1D+PT5vtQ0z40GCTEJIUd13W9UFhV9Yp+QIDAQAB";
    //服务端-私钥解密
    public static String private_key_server = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKfqp9uuHk6vfgfi1cSEOEibfQpw8ghY92SVFIrritVLpDH+gyocVUMQvMZM1w9orDTiRJs0dPA1Cm6a09L+ZlU+lPF4qD+NsMyQZgSgI2dV+DBkIGGnPoHFtKi9MZYvOWY0G94bRyfUP49Pm+1DTPjQYJMQkhR3Xdb1QWFX1in5AgMBAAECgYBtVdTArQpc79YfamsIz5Maa+wqTUq7drp3ir7aie5XXi5mwzNCyzoVNiPE9ymdhemDccV8TdbKxa6qQDQnEbEtSDdKSniqhSNho4oPHwb54V5M7JoKVElJqP8c4pYfCoC6KWA+2drv/DKEAiQp6EEeybcjMjJOxgjVqU0qfuC4UQJBANWp4/ixYv5XKx52esmHsx1RBxvzbYWu+vJLbav3TjHFBiMBW5/sE88RtvCcj3heNbaW1h3Fd5zhyPu+B3lKer0CQQDJMD5Q6FTu6qFlxXTrPRMYW9Kbfc9fYj7mmoOdx9/akK5axSo9h7yNanV+7gRD9uuvictKUTeavAHFizkdKb3tAkAF0BxyrKjL0KVMq96FUxrNZmHyIbpOE8eiBelS72SCOCEFnMjYXfzf+lRm0WuZ075UXGAw6Slq7D2ik7XyV9NlAkEAv2k24KMqq2RvyfPjGSwyTqqN5YH9GjLOxXecYTEYuUmNmK6dUY0ixyjSQMETLdZuxcPDtiEvVfgpd1jOLgDYwQJAJOTzJnufez1RCqd6+lPiy/4r9+CMUVoqRW+KJJAGUVzIMu16or6stxV8IBgXkjwnd5f9n+OTC6JFQewAWcurxw==";
    
    
    //服务端-公钥验签
    public static String public_key_server = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCDe3vhGZ4G2df78Jg8ECf9j/rvFUKDd1A8R4pZdS4pbpYOKuw2txOVzMTT1xiDZTGmq1o3cyzIc/QoYvwW77WZHOGIuMN9HUfV/E4UW6joWkFslwOHr6TNcrfsItQIYxHFOhQR8QjNCNNMpCZJngBzXQCX/xO9+rmypMgYBERMBQIDAQAB";
    //客户端-私钥加签
    public static String private_key_client  = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIN7e+EZngbZ1/vwmDwQJ/2P+u8VQoN3UDxHill1Lilulg4q7Da3E5XMxNPXGINlMaarWjdzLMhz9Chi/BbvtZkc4Yi4w30dR9X8ThRbqOhaQWyXA4evpM1yt+wi1AhjEcU6FBHxCM0I00ykJkmeAHNdAJf/E736ubKkyBgEREwFAgMBAAECgYB3W1CgjmXDKFyGK+m2lKAI8XxFL1J7D4O5xOPVw6dNG0OCxvo5zUYtNX70I43wMZu6BlFWhup/aauaQglANQju/2euUghdy6ql4hG54rGXX95MtlqZYDWraps0WoZ25AXYApI/FhPDlNsFHtd1vSK4RdPCRAorogf713nWJkI2nQJBAP7Wnse4D7zLU2Q0X4K5DTNrXv+OVTIuJKg2vjODUTvIg+jZc9BcODNll6NMsaSl6V5gtne6cJybb1dbrHpnrlMCQQCEFOpN5HSZ/pIxnwb+pG6rn+oJhoFShxgeJgLo9v3BZECP/wJjA7pOXM8lEgMviirgzwh8IQQGpvh6u0HoBOFHAkEAulDZt7VHtEWHy6xK5D09fImU5A0BFvYLkPytJOZufuIEJzrM5Np3sIQnUJojCvjOXVUiMvkZmjY+OkVpHfktxwJAK73herpWA0nTkKth3aMHI79p+o2Y9oPW8OUVwaFKmGljGE0TtUbexGToFRbKB0xyttDZtoIYmztgvwSU5wn2sQJARVGajF3QY7pw28qwxczGrRPqqES4iiP98GVzFeNLZNuDQaXdY0t5z65LSBGH+/RMFbTfnW3xHy2Xq8PKZlj7TA==";
    
    
    @Test
    public void asda() throws Exception{
        //Map传参并生成json
        Map<String,Object> map =new HashMap<String,Object>();
        map.put("userNo", "123456");
        //URL
        String url = "http://localhost:8080/T100040/weather/indexV";
        //生成AES_KEY
        String aesKey = AESCoder.initKey();
        //参数加密格式: BASE64(RSA(AES_KEY))|AES(param)|RSA_SIGN(param)
        String param =URLEncoder.encode(encrpytClient(new Gson().toJson(map),aesKey), "UTF-8");
        //post请求
        String encRsp = ConnectionUtil.sendPost(url,"param="+ param, "utf-8"); 
        if(encRsp!=null&&!"".equals(encRsp)){
            System.out.println(decryptClient(encRsp,aesKey));
        }else{
            
        }
    }
    
    /**
     * <客户端>
     * 公钥加密,私钥签名
     * @author zhaofh 2016年7月6日 上午9:47:23
     * 
     * @param param传输数据
     * @return 返回结果(已加密)
     */
    private static String encrpytClient(String param,String asekey){
        try {
            return encrpytClient(param.getBytes("utf-8"),asekey, public_key_client,private_key_client);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

   /**
     * <客户端> 
     * 数据加密,数据加签
     * @author zhaofh 2016年7月6日 上午9:49:59
     * 
     * @param data       报文明文
     * @param aesKey     临时通信密钥
     * @param selfPriKey 客户端私钥证书
     * @param srvPubKey  服务端公钥证书
     * @return 报文密文
     */
    private static String encrpytClient(byte[] data,String aesKey, String public_key_param, String private_key_sign) throws Exception {
        byte[] encoded_aesKey = RSAUtil.encryptByPublicKey(aesKey.getBytes(), public_key_param);
        String encAesKey = RSAUtil.encryptBASE64(encoded_aesKey);
        byte[] encData = AESCoder.encrypt(data, aesKey);
        String outputStr = AESCoder.encryptBASE64(encData);
        String sign = RSAUtil.sign(data, private_key_sign);
        return encAesKey + "|" + outputStr + "|" + sign;
    }
    
    /**
     * <客户端>
     * 私钥解密,公钥验签
     * @author zhaofh 2016年7月6日 上午9:49:59
     * 
     * @param param传输数据
     * @return 返回结果(已加密)
     */
    private static String decryptClient(String param,String aesKey){
        try {
            return decryptClient(param,aesKey,public_key_client);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * <客户端>
     * 数据解密,数据验签
     * @author zhaofh 2016年7月6日 上午9:49:59
     * 
     * @param data      报文密文
     * @param aesKey    临时通信密钥
     * @param srvPubKey 服务端公钥证书
     * @return aesKey&&报文明文
     */
    private static String decryptClient(String data, String aesKey, String public_key_sign) throws Exception {
     String[] enc_data_seg = data.split("\\|");
     byte[] encData = AESCoder.decrypt(AESCoder.decryptBASE64(enc_data_seg[0]),aesKey);
     boolean status = RSAUtil.verify(encData, public_key_sign, enc_data_seg[1]);
        if (status)
            return new String(encData,"utf-8");
        else
            return null;
    }
    
    /**
     * <服务端>
     * 公钥加密,私钥签名
     * @author zhaofh 2016年7月6日 上午9:47:23
     * 
     * @param param传输数据
     * @param aesKey  AES_KEY
     * @return 返回结果(已加密)
     */
    public static String encrpytService(String param,String aesKey){
        try {
            return encrpytService(param.getBytes("utf-8"),aesKey, public_key_server,private_key_server);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * <服务端>
     * 数据加密,数据加签
     * @author zhaofh 2016年7月6日 上午9:49:59
     * 
     * @param data       报文明文
     * @param aesKey     临时通信密钥
     * @param selfPriKey 客户端私钥证书
     * @param srvPubKey  服务端公钥证书
     * @return 报文密文
     */
    private static String encrpytService(byte[] data,String aesKey, String public_key_param, String private_key_sign) throws Exception {
        byte[] encData = AESCoder.encrypt(data, aesKey);
        String outputStr = AESCoder.encryptBASE64(encData);
        String sign = RSAUtil.sign(data, private_key_sign);
        return outputStr + "|" + sign;
    }
    
    /**
     * <服务端>
     * 私钥解密,公钥验签
     * @author zhaofh 2016年7月6日 上午9:49:59
     * 
     * @param param传输数据
     * @return 返回结果(已加密)
     */
    public static String[] decryptService(String param){
        try {
            return decryptService(param,private_key_server,public_key_server);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * <服务端>
     * 数据解密,数据验签
     * @author zhaofh 2016年7月6日 上午9:49:59
     * 
     * @param data      报文密文
     * @param aesKey    临时通信密钥
     * @param srvPubKey 服务端公钥证书
     * @return aesKey&&报文明文
     */
    private static String[] decryptService(String data, String private_key_param, String public_key_sign) throws Exception {
        String[] enc_data_seg = data.split("\\|");
        System.out.println("解密时数据:\n\r"+data);
        byte[] encoded_aesKey =RSAUtil.decryptBASE64(enc_data_seg[0]); 
        byte[] decoded_aesKey =RSAUtil.decryptByPrivateKey(encoded_aesKey,private_key_param);
        String aesKey =new String(decoded_aesKey);
        byte[] encData = AESCoder.decrypt(AESCoder.decryptBASE64(enc_data_seg[1]),aesKey);
        
     boolean status = RSAUtil.verify(encData, public_key_sign, enc_data_seg[2]);
        if (status)
            return new String[]{aesKey,new String(encData,"utf-8")};
        else
            return null;
    }
    
}


RSAUtil类

package rsa;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

/**
 * RSA安全编码组件
 * @author 《java加密与解密的艺术 梁栋》
 *          zhaofh 2016-07-06   根据项目需求引用并优化
 * @version 1.0
 * @since 1.0
 */
public abstract class RSAUtil extends BaseCoder {
    public static final String KEY_ALGORITHM = "RSA";
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";


    /**
     * 用私钥对信息生成数字签名
     * @param data  加密数据
     * @param privateKey  私钥
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
        // 解密由base64编码的私钥
        byte[] keyBytes = decryptBASE64(privateKey);

        // 构造PKCS8EncodedKeySpec对象
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 取私钥匙对象
        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 用私钥对信息生成数字签名
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(priKey);
        signature.update(data);

        return encryptBASE64(signature.sign());
    }

    /**
     * 校验数字签名
     * 
     * @param data 加密数据
     * @param publicKey 公钥
     * @param sign 数字签名
     * @return 校验成功返回true 失败返回false
     * @throws Exception
     */
    public static boolean verify(byte[] data, String publicKey, String sign)
            throws Exception {

        // 解密由base64编码的公钥
        byte[] keyBytes = decryptBASE64(publicKey);

        // 构造X509EncodedKeySpec对象
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 取公钥匙对象
        PublicKey pubKey = keyFactory.generatePublic(keySpec);

        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(pubKey);
        signature.update(data);

        // 验证签名是否正常
        return signature.verify(decryptBASE64(sign));
    }

    /**
     * 解密<br>
     * 用私钥解密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data, String key)
            throws Exception {
        // 对密钥解密
        byte[] keyBytes = decryptBASE64(key);

        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(data);
    }

    /**
     * 加密<br>
     * 用公钥加密
     * 
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String key)
            throws Exception {
        // 对公钥解密
        byte[] keyBytes = decryptBASE64(key);

        // 取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        return cipher.doFinal(data);
    }


}

BaseCode接口

package rsa;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * @author zhaofh 2016年7月6日
 *
 */
public abstract class BaseCoder {

    /**
     * BASE64解密
     * 
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptBASE64(String key) throws Exception {
        return (new BASE64Decoder()).decodeBuffer(key);
    }

    /**
     * BASE64加密
     * 
     * @param key
     * @return
     * @throws Exception
     */
    public static String encryptBASE64(byte[] key) throws Exception {
        return (new BASE64Encoder()).encodeBuffer(key);
    }
}

总结

以上内容为java服务端仅使用RSA两组密钥对进行双向的加解密过程(显示使用中不推荐双向,效率比较低,单项加密,返回值不需要加密或使用简单加密),仅作为java端使用,安卓和java还是有些许区别需要再做修改优化,记得关注以后内容哦。

上一篇下一篇

猜你喜欢

热点阅读