学习加密(四)spring boot 使用RSA+AES混合加密,前后端传递参数加解密

 

学习加密(四)spring boot 使用RSA+AES混合加密,前后端传递参数加解密

技术标签: RSA  AES  RSA AES  混合加密  整合

 

前言:
   为了提高安全性采用了RSA,但是为了解决RSA加解密性能问题,所以采用了RSA(非对称)+AES(对称加密)方式,如果只考虑其中一种的,可以去看我前面两篇文章,专门单独写的demo,可以自行整合在项目中

大致思路:

  1. 客户端启动,发送请求到服务端,服务端用RSA算法生成一对公钥和私钥,我们简称为pubkey1,prikey1,将公钥pubkey1返回给客户端。
  2. 客户端拿到服务端返回的公钥pubkey1后,自己用RSA算法生成一对公钥和私钥,我们简称为pubkey2,prikey2,并将公钥pubkey2通过公钥pubkey1加密,加密之后传输给服务端。
  3. 此时服务端收到客户端传输的密文,用私钥prikey1进行解密,因为数据是用公钥pubkey1加密的,通过解密就可以得到客户端生成的公钥pubkey2
  4. 然后自己在生成对称加密,也就是我们的AES,其实也就是相对于我们配置中的那个16的长度的加密key,生成了这个key之后我们就用公钥pubkey2进行加密,返回给客户端,因为只有客户端有pubkey2对应的私钥prikey2,只有客户端才能解密,客户端得到数据之后,用prikey2进行解密操作,得到AES的加密key,最后就用加密key进行数据传输的加密,至此整个流程结束。

具体实践(前端请求加密,服务端解密,服务端响应加密,前端解密):

1.创建spring boot项目,导入相关依赖,
2.编写RSA加解密工具类,AES加解密工具类
3.编写自定义注解(让加解密细粒度)
4.编写自定义DecodeRequestAdvice和EncodeResponseAdvice
5.创建controller
6.创建jsp或者html,引入js(加密和解密的通用js),还有配置,配置文件
ps:因为这里没https证书,所有使用http, 考虑到前后端分离,使用json来传递数据,

第一步:创建spring boot项目过程省略,相关依赖:
 

  1.  
  2.  
  3.  
    org.springframework.boot
  4.  
    spring-boot-starter-web
  5.  
  6.  
  7.  
    org.springframework.boot
  8.  
    spring-boot-starter-test
  9.  
    test
  10.  
  11.  
  12.  
  13.  
    org.springframework.boot
  14.  
    spring-boot-devtools
  15.  
    true
  16.  
  17.  
  18.  
  19.  
    mysql
  20.  
    mysql-connector-java
  21.  
    runtime
  22.  
  23.  
  24.  
  25.  
    org.projectlombok
  26.  
    lombok
  27.  
    1.16.20
  28.  
  29.  
  30.  
  31.  
    org.slf4j
  32.  
    log4j-over-slf4j
  33.  
  34.  
  35.  
  36.  
    com.alibaba
  37.  
    druid
  38.  
    1.1.12
  39.  
  40.  
  41.  
  42.  
    org.apache.directory.studio
  43.  
    org.apache.commons.codec
  44.  
    1.8
  45.  
  46.  
  47.  
  48.  
    com.alibaba
  49.  
    fastjson
  50.  
    1.2.47
  51.  
  52.  
  53.  
  54.  
    com.google.code.gson
  55.  
    gson
  56.  
    2.8.2
  57.  
  58.  
  59.  
  60.  
    org.apache.commons
  61.  
    commons-lang3
  62.  
    3.4
  63.  
  64.  
  65.  
    commons-io
  66.  
    commons-io
  67.  
    2.4
  68.  
  69.  
  70.  
  71.  
    org.apache.tomcat.embed
  72.  
    tomcat-embed-jasper
  73.  
    provided
  74.  
  75.  
  76.  
  77.  
    javax.servlet
  78.  
    jstl
  79.  
  80.  
  81.  
  82.  
    javax.servlet
  83.  
    javax.servlet-api
  84.  
    provided
  85.  
  86.  
  87.  
  88.  
    org.springframework.boot
  89.  
    spring-boot-starter-thymeleaf
  90.  

第二步: 
 

  1.  
    import javax.crypto.Cipher;
  2.  
    import javax.crypto.KeyGenerator;
  3.  
    import javax.crypto.spec.SecretKeySpec;
  4.  
     
  5.  
    import org.apache.commons.codec.binary.Base64;
  6.  
     
  7.  
     
  8.  
    /**
  9.  
    * 前后端数据传输加密工具类
  10.  
    * @author monkey
  11.  
    *
  12.  
    */
  13.  
    public class AesEncryptUtils {
  14.  
     
  15.  
    //参数分别代表 算法名称/加密模式/数据填充方式
  16.  
    private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
  17.  
     
  18.  
    /**
  19.  
    * 加密
  20.  
    * @param content 加密的字符串
  21.  
    * @param encryptKey key值
  22.  
    * @return
  23.  
    * @throws Exception
  24.  
    */
  25.  
    public static String encrypt(String content, String encryptKey) throws Exception {
  26.  
    KeyGenerator kgen = KeyGenerator.getInstance( "AES");
  27.  
    kgen.init( 128);
  28.  
    Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
  29.  
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
  30.  
    byte[] b = cipher.doFinal(content.getBytes("utf-8"));
  31.  
    // 采用base64算法进行转码,避免出现中文乱码
  32.  
    return Base64.encodeBase64String(b);
  33.  
     
  34.  
    }
  35.  
     
  36.  
    /**
  37.  
    * 解密
  38.  
    * @param encryptStr 解密的字符串
  39.  
    * @param decryptKey 解密的key值
  40.  
    * @return
  41.  
    * @throws Exception
  42.  
    */
  43.  
    public static String decrypt(String encryptStr, String decryptKey) throws Exception {
  44.  
    KeyGenerator kgen = KeyGenerator.getInstance( "AES");
  45.  
    kgen.init( 128);
  46.  
    Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
  47.  
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
  48.  
    // 采用base64算法进行转码,避免出现中文乱码
  49.  
    byte[] encryptBytes = Base64.decodeBase64(encryptStr);
  50.  
    byte[] decryptBytes = cipher.doFinal(encryptBytes);
  51.  
    return new String(decryptBytes);
  52.  
    }
  53.  
    }
  1.  
    import org.apache.commons.codec.binary.Base64;
  2.  
     
  3.  
    import java.io.ByteArrayOutputStream;
  4.  
    import java.security.Key;
  5.  
    import java.security.KeyFactory;
  6.  
    import java.security.KeyPair;
  7.  
    import java.security.KeyPairGenerator;
  8.  
    import java.security.PrivateKey;
  9.  
    import java.security.PublicKey;
  10.  
    import java.security.Signature;
  11.  
    import java.security.interfaces.RSAPrivateKey;
  12.  
    import java.security.interfaces.RSAPublicKey;
  13.  
    import java.security.spec.PKCS8EncodedKeySpec;
  14.  
    import java.security.spec.X509EncodedKeySpec;
  15.  
    import java.util.HashMap;
  16.  
    import java.util.Map;
  17.  
     
  18.  
    import javax.crypto.Cipher;
  19.  
     
  20.  
    /** */
  21.  
    /**
  22.  
    *

  23.  
    * RSA公钥/私钥/签名工具包
  24.  
    *

  25.  
    *

  26.  
    * 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman)
  27.  
    *

  28.  
    *

  29.  
    * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式
  30.  
    * 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,
  31.  
    * 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全
  32.  
    *

  33.  
    *
  34.  
    * @author monkey
  35.  
    * @date 2018-10-29
  36.  
    */
  37.  
    public class RSAUtils {
  38.  
     
  39.  
    /** */
  40.  
    /**
  41.  
    * 加密算法RSA
  42.  
    */
  43.  
    public static final String KEY_ALGORITHM = "RSA";
  44.  
     
  45.  
    /** */
  46.  
    /**
  47.  
    * 签名算法
  48.  
    */
  49.  
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
  50.  
     
  51.  
    /** */
  52.  
    /**
  53.  
    * 获取公钥的key
  54.  
    */
  55.  
    private static final String PUBLIC_KEY = "RSAPublicKey";
  56.  
     
  57.  
    /** */
  58.  
    /**
  59.  
    * 获取私钥的key
  60.  
    */
  61.  
    private static final String PRIVATE_KEY = "RSAPrivateKey";
  62.  
     
  63.  
    /** */
  64.  
    /**
  65.  
    * RSA最大加密明文大小
  66.  
    */
  67.  
    private static final int MAX_ENCRYPT_BLOCK = 117;
  68.  
     
  69.  
    /** */
  70.  
    /**
  71.  
    * RSA最大解密密文大小
  72.  
    */
  73.  
    private static final int MAX_DECRYPT_BLOCK = 128;
  74.  
     
  75.  
    /** */
  76.  
    /**
  77.  
    * RSA 位数 如果采用2048 上面最大加密和最大解密则须填写: 245 256
  78.  
    */
  79.  
    private static final int INITIALIZE_LENGTH = 1024;
  80.  
     
  81.  
    /** */
  82.  
    /**
  83.  
    *

  84.  
    * 生成密钥对(公钥和私钥)
  85.  
    *

  86.  
    *
  87.  
    * @return
  88.  
    * @throws Exception
  89.  
    */
  90.  
    public static Map genKeyPair() throws Exception {
  91.  
    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
  92.  
    keyPairGen.initialize(INITIALIZE_LENGTH);
  93.  
    KeyPair keyPair = keyPairGen.generateKeyPair();
  94.  
    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
  95.  
    RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
  96.  
    Map keyMap = new HashMap(2);
  97.  
    keyMap.put(PUBLIC_KEY, publicKey);
  98.  
    keyMap.put(PRIVATE_KEY, privateKey);
  99.  
    return keyMap;
  100.  
    }
  101.  
     
  102.  
    /** */
  103.  
    /**
  104.  
    *

  105.  
    * 用私钥对信息生成数字签名
  106.  
    *

  107.  
    *
  108.  
    * @param data
  109.  
    * 已加密数据
  110.  
    * @param privateKey
  111.  
    * 私钥(BASE64编码)
  112.  
    *
  113.  
    * @return
  114.  
    * @throws Exception
  115.  
    */
  116.  
    public static String sign(byte[] data, String privateKey) throws Exception {
  117.  
    byte[] keyBytes = Base64.decodeBase64(privateKey);
  118.  
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
  119.  
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  120.  
    PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
  121.  
    Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
  122.  
    signature.initSign(privateK);
  123.  
    signature.update(data);
  124.  
    return Base64.encodeBase64String(signature.sign());
  125.  
    }
  126.  
     
  127.  
    /** */
  128.  
    /**
  129.  
    *

  130.  
    * 校验数字签名
  131.  
    *

  132.  
    *
  133.  
    * @param data
  134.  
    * 已加密数据
  135.  
    * @param publicKey
  136.  
    * 公钥(BASE64编码)
  137.  
    * @param sign
  138.  
    * 数字签名
  139.  
    *
  140.  
    * @return
  141.  
    * @throws Exception
  142.  
    *
  143.  
    */
  144.  
    public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
  145.  
    byte[] keyBytes = Base64.decodeBase64(publicKey);
  146.  
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
  147.  
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  148.  
    PublicKey publicK = keyFactory.generatePublic(keySpec);
  149.  
    Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
  150.  
    signature.initVerify(publicK);
  151.  
    signature.update(data);
  152.  
    return signature.verify(Base64.decodeBase64(sign));
  153.  
    }
  154.  
     
  155.  
    /** */
  156.  
    /**
  157.  
    *

  158.  
    * 私钥解密
  159.  
    *

  160.  
    *
  161.  
    * @param encryptedData
  162.  
    * 已加密数据
  163.  
    * @param privateKey
  164.  
    * 私钥(BASE64编码)
  165.  
    * @return
  166.  
    * @throws Exception
  167.  
    */
  168.  
    public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
  169.  
    byte[] keyBytes = Base64.decodeBase64(privateKey);
  170.  
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
  171.  
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  172.  
    Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
  173.  
    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
  174.  
    cipher.init(Cipher.DECRYPT_MODE, privateK);
  175.  
    int inputLen = encryptedData.length;
  176.  
    ByteArrayOutputStream out = new ByteArrayOutputStream();
  177.  
    int offSet = 0;
  178.  
    byte[] cache;
  179.  
    int i = 0;
  180.  
    // 对数据分段解密
  181.  
    while (inputLen - offSet > 0) {
  182.  
    if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
  183.  
    cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
  184.  
    } else {
  185.  
    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
  186.  
    }
  187.  
    out.write(cache, 0, cache.length);
  188.  
    i++;
  189.  
    offSet = i * MAX_DECRYPT_BLOCK;
  190.  
    }
  191.  
    byte[] decryptedData = out.toByteArray();
  192.  
    out.close();
  193.  
    return decryptedData;
  194.  
    }
  195.  
     
  196.  
    /** */
  197.  
    /**
  198.  
    *

  199.  
    * 公钥解密
  200.  
    *

  201.  
    *
  202.  
    * @param encryptedData
  203.  
    * 已加密数据
  204.  
    * @param publicKey
  205.  
    * 公钥(BASE64编码)
  206.  
    * @return
  207.  
    * @throws Exception
  208.  
    */
  209.  
    public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
  210.  
    byte[] keyBytes = Base64.decodeBase64(publicKey);
  211.  
    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
  212.  
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  213.  
    Key publicK = keyFactory.generatePublic(x509KeySpec);
  214.  
    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
  215.  
    cipher.init(Cipher.DECRYPT_MODE, publicK);
  216.  
    int inputLen = encryptedData.length;
  217.  
    ByteArrayOutputStream out = new ByteArrayOutputStream();
  218.  
    int offSet = 0;
  219.  
    byte[] cache;
  220.  
    int i = 0;
  221.  
    // 对数据分段解密
  222.  
    while (inputLen - offSet > 0) {
  223.  
    if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
  224.  
    cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
  225.  
    } else {
  226.  
    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
  227.  
    }
  228.  
    out.write(cache, 0, cache.length);
  229.  
    i++;
  230.  
    offSet = i * MAX_DECRYPT_BLOCK;
  231.  
    }
  232.  
    byte[] decryptedData = out.toByteArray();
  233.  
    out.close();
  234.  
    return decryptedData;
  235.  
    }
  236.  
     
  237.  
    /** */
  238.  
    /**
  239.  
    *

  240.  
    * 公钥加密
  241.  
    *

  242.  
    *
  243.  
    * @param data
  244.  
    * 源数据
  245.  
    * @param publicKey
  246.  
    * 公钥(BASE64编码)
  247.  
    * @return
  248.  
    * @throws Exception
  249.  
    */
  250.  
    public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
  251.  
    byte[] keyBytes = Base64.decodeBase64(publicKey);
  252.  
    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
  253.  
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  254.  
    Key publicK = keyFactory.generatePublic(x509KeySpec);
  255.  
    // 对数据加密
  256.  
    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
  257.  
    cipher.init(Cipher.ENCRYPT_MODE, publicK);
  258.  
    int inputLen = data.length;
  259.  
    ByteArrayOutputStream out = new ByteArrayOutputStream();
  260.  
    int offSet = 0;
  261.  
    byte[] cache;
  262.  
    int i = 0;
  263.  
    // 对数据分段加密
  264.  
    while (inputLen - offSet > 0) {
  265.  
    if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
  266.  
    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
  267.  
    } else {
  268.  
    cache = cipher.doFinal(data, offSet, inputLen - offSet);
  269.  
    }
  270.  
    out.write(cache, 0, cache.length);
  271.  
    i++;
  272.  
    offSet = i * MAX_ENCRYPT_BLOCK;
  273.  
    }
  274.  
    byte[] encryptedData = out.toByteArray();
  275.  
    out.close();
  276.  
    return encryptedData;
  277.  
    }
  278.  
     
  279.  
    /** */
  280.  
    /**
  281.  
    *

  282.  
    * 私钥加密
  283.  
    *

  284.  
    *
  285.  
    * @param data
  286.  
    * 源数据
  287.  
    * @param privateKey
  288.  
    * 私钥(BASE64编码)
  289.  
    * @return
  290.  
    * @throws Exception
  291.  
    */
  292.  
    public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
  293.  
    byte[] keyBytes = Base64.decodeBase64(privateKey);
  294.  
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
  295.  
    KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
  296.  
    Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
  297.  
    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
  298.  
    cipher.init(Cipher.ENCRYPT_MODE, privateK);
  299.  
    int inputLen = data.length;
  300.  
    ByteArrayOutputStream out = new ByteArrayOutputStream();
  301.  
    int offSet = 0;
  302.  
    byte[] cache;
  303.  
    int i = 0;
  304.  
    // 对数据分段加密
  305.  
    while (inputLen - offSet > 0) {
  306.  
    if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
  307.  
    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
  308.  
    } else {
  309.  
    cache = cipher.doFinal(data, offSet, inputLen - offSet);
  310.  
    }
  311.  
    out.write(cache, 0, cache.length);
  312.  
    i++;
  313.  
    offSet = i * MAX_ENCRYPT_BLOCK;
  314.  
    }
  315.  
    byte[] encryptedData = out.toByteArray();
  316.  
    out.close();
  317.  
    return encryptedData;
  318.  
    }
  319.  
     
  320.  
    /** */
  321.  
    /**
  322.  
    *

  323.  
    * 获取私钥
  324.  
    *

  325.  
    *
  326.  
    * @param keyMap
  327.  
    * 密钥对
  328.  
    * @return
  329.  
    * @throws Exception
  330.  
    */
  331.  
    public static String getPrivateKey(Map keyMap) throws Exception {
  332.  
    Key key = (Key) keyMap.get(PRIVATE_KEY);
  333.  
    return Base64.encodeBase64String(key.getEncoded());
  334.  
    }
  335.  
     
  336.  
    /** */
  337.  
    /**
  338.  
    *

  339.  
    * 获取公钥
  340.  
    *

  341.  
    *
  342.  
    * @param keyMap
  343.  
    * 密钥对
  344.  
    * @return
  345.  
    * @throws Exception
  346.  
    */
  347.  
    public static String getPublicKey(Map keyMap) throws Exception {
  348.  
    Key key = (Key) keyMap.get(PUBLIC_KEY);
  349.  
    return Base64.encodeBase64String(key.getEncoded());
  350.  
    }
  351.  
     
  352.  
    /**
  353.  
    * java端公钥加密
  354.  
    */
  355.  
    public static String encryptedDataOnJava(String data, String PUBLICKEY) {
  356.  
    try {
  357.  
    data = Base64.encodeBase64String(encryptByPublicKey(data.getBytes(), PUBLICKEY));
  358.  
    } catch (Exception e) {
  359.  
    // TODO Auto-generated catch block
  360.  
    e.printStackTrace();
  361.  
    }
  362.  
    return data;
  363.  
    }
  364.  
     
  365.  
    /**
  366.  
    * java端私钥解密
  367.  
    */
  368.  
    public static String decryptDataOnJava(String data, String PRIVATEKEY) {
  369.  
    String temp = "";
  370.  
    try {
  371.  
    byte[] rs = Base64.decodeBase64(data);
  372.  
    temp = new String(RSAUtils.decryptByPrivateKey(rs, PRIVATEKEY),"UTF-8");
  373.  
    } catch (Exception e) {
  374.  
    e.printStackTrace();
  375.  
    }
  376.  
    return temp;
  377.  
    }

第三步:
 

  1.  
    import org.springframework.web.bind.annotation.Mapping;
  2.  
     
  3.  
    import java.lang.annotation.*;
  4.  
     
  5.  
     
  6.  
    /**
  7.  
    * @author monkey
  8.  
    * @desc 请求数据解密
  9.  
    * @date 2018/10/25 20:17
  10.  
    */
  11.  
    @Target({ElementType.METHOD,ElementType.TYPE})
  12.  
    @Retention(RetentionPolicy.RUNTIME)
  13.  
    @Mapping
  14.  
    @Documented
  15.  
    public @interface SecurityParameter {
  16.  
     
  17.  
    /**
  18.  
    * 入参是否解密,默认解密
  19.  
    */
  20.  
    boolean inDecode() default true;
  21.  
     
  22.  
    /**
  23.  
    * 出参是否加密,默认加密
  24.  
    */
  25.  
    boolean outEncode() default true;
  26.  
    }

第四步:
 

  1.  
    import com.google.gson.Gson;
  2.  
    import com.google.gson.reflect.TypeToken;
  3.  
    import com.monkey.springboot.demo.annotation.SecurityParameter;
  4.  
    import com.monkey.springboot.demo.utils.AesEncryptUtils;
  5.  
    import com.monkey.springboot.demo.utils.RSAUtils;
  6.  
    import org.apache.commons.io.IOUtils;
  7.  
    import org.apache.commons.lang3.StringUtils;
  8.  
    import org.slf4j.Logger;
  9.  
    import org.slf4j.LoggerFactory;
  10.  
    import org.springframework.beans.factory.annotation.Value;
  11.  
    import org.springframework.core.MethodParameter;
  12.  
    import org.springframework.http.HttpHeaders;
  13.  
    import org.springframework.http.HttpInputMessage;
  14.  
    import org.springframework.http.converter.HttpMessageConverter;
  15.  
    import org.springframework.web.bind.annotation.ControllerAdvice;
  16.  
    import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
  17.  
     
  18.  
    import java.io.IOException;
  19.  
    import java.io.InputStream;
  20.  
    import java.lang.reflect.Type;
  21.  
    import java.util.Map;
  22.  
     
  23.  
    /**
  24.  
    * @author monkey
  25.  
    * @desc 请求数据解密
  26.  
    * @date 2018/10/29 20:17
  27.  
    */
  28.  
    @ControllerAdvice(basePackages = "com.monkey.springboot.demo.controller")
  29.  
    public class DecodeRequestBodyAdvice implements RequestBodyAdvice {
  30.  
     
  31.  
    private static final Logger logger = LoggerFactory.getLogger(DecodeRequestBodyAdvice.class);
  32.  
     
  33.  
    @Value("${server.private.key}")
  34.  
    private String SERVER_PRIVATE_KEY;
  35.  
    //private static final String SERVER_PRIVATE_KEY="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIn2zWqU7K/2qm5pOpq5bp9R+3MTnStWTfJU9nC/Vo7UKH9dITPvrELCTK+qlqpx5Fes+l0GY7n6u4n4jyiw4ejsvkZYQ5ww477yLOn2FcoEGuZEwPgSCmfTST0OFUgQqn+/J11k9L92jEHyieE3qmhMkMt0UsVUSJwx/nZxo30ZAgMBAAECgYBD3YHigeuEC4R+14iaf8jo2j0kuGtB3Cxvnlez0otTqw1YyYkBsU49cLKkXvfKVEgM0Ow/QltgKvSBxCE31PrrDka5TygVMqqA/IM7NrDvjUcGLjyoeNmLA8660fWcDxUTlAGN5kxIvUATayVwKVflpWPWu0FPKsWrZustnEo+4QJBAMCmYsWqAKWYMVRXFP3/XGRfio8DV793TOckyBSN9eh8UhgoZyT3u7oeHmDJEwm4aNMHlg1Pcdc6tNsvi1FRCiUCQQC3VNzfF4xOtUgX7vWPL8YVljLuXmy12iVYmg6ofu9l31nwM9FLQ1TRFglvF5LWrIXTQb07PgGd5DJMAQWGsqLlAkAPE7Z9M73TN+L8b8hDzJ1leZi1cpSGdoa9PEKwYR/SrxAZtefEm+LEQSEtf+8OfrEtetWCeyo0pvKKiOEFXytFAkEAgynL/DC0yXsZYUYtmYvshHU5ayFTVagFICbYZeSrEo+BoUDxdI9vl0fU6A5NmBlGhaZ65G+waG5jLc1tTrlvoQJAXBEoPcBNAosiZHQfYBwHqU6mJ9/ZacJh3MtJzGGebfEwJgtln5b154iANqNWXpySBLvkK+Boq7FYRiD83pqmUg==";
  36.  
     
  37.  
    @Override
  38.  
    public boolean supports(MethodParameter methodParameter, Type type, Class> aClass) {
  39.  
    return true;
  40.  
    }
  41.  
     
  42.  
    @Override
  43.  
    public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class> aClass) {
  44.  
    return body;
  45.  
    }
  46.  
     
  47.  
    @Override
  48.  
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type type, Class> aClass) throws IOException {
  49.  
    try {
  50.  
    boolean encode = false;
  51.  
    if (methodParameter.getMethod().isAnnotationPresent(SecurityParameter.class)) {
  52.  
    //获取注解配置的包含和去除字段
  53.  
    SecurityParameter serializedField = methodParameter.getMethodAnnotation(SecurityParameter.class);
  54.  
    //入参是否需要解密
  55.  
    encode = serializedField.inDecode();
  56.  
    }
  57.  
    if (encode) {
  58.  
    logger.info( "对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密");
  59.  
    return new MyHttpInputMessage(inputMessage);
  60.  
    } else{
  61.  
    return inputMessage;
  62.  
    }
  63.  
    } catch (Exception e) {
  64.  
    e.printStackTrace();
  65.  
    logger.error( "对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:"+e.getMessage());
  66.  
    return inputMessage;
  67.  
    }
  68.  
    }
  69.  
     
  70.  
    @Override
  71.  
    public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class> aClass) {
  72.  
    return body;
  73.  
    }
  74.  
     
  75.  
    class MyHttpInputMessage implements HttpInputMessage {
  76.  
    private HttpHeaders headers;
  77.  
     
  78.  
    private InputStream body;
  79.  
     
  80.  
    public MyHttpInputMessage(HttpInputMessage inputMessage) throws Exception {
  81.  
    this.headers = inputMessage.getHeaders();
  82.  
    this.body = IOUtils.toInputStream(easpString(IOUtils.toString(inputMessage.getBody(),"utf-8")));
  83.  
    }
  84.  
     
  85.  
    @Override
  86.  
    public InputStream getBody() throws IOException {
  87.  
    return body;
  88.  
    }
  89.  
     
  90.  
    @Override
  91.  
    public HttpHeaders getHeaders() {
  92.  
    return headers;
  93.  
    }
  94.  
     
  95.  
    /**
  96.  
    *
  97.  
    * @param requestData
  98.  
    * @return
  99.  
    */
  100.  
    public String easpString(String requestData) {
  101.  
    if(requestData != null && !requestData.equals("")){
  102.  
    Map map = new Gson().fromJson(requestData,new TypeToken>() {
  103.  
    }.getType());
  104.  
    // 密文
  105.  
    String data = map.get( "requestData");
  106.  
    // 加密的ase秘钥
  107.  
    String encrypted = map.get( "encrypted");
  108.  
    if(StringUtils.isEmpty(data) || StringUtils.isEmpty(encrypted)){
  109.  
    throw new RuntimeException("参数【requestData】缺失异常!");
  110.  
    } else{
  111.  
    String content = null ;
  112.  
    String aseKey = null;
  113.  
    try {
  114.  
    aseKey = RSAUtils.decryptDataOnJava(encrypted,SERVER_PRIVATE_KEY);
  115.  
    } catch (Exception e){
  116.  
    throw new RuntimeException("参数【aseKey】解析异常!");
  117.  
    }
  118.  
    try {
  119.  
    content = AesEncryptUtils.decrypt(data, aseKey);
  120.  
    } catch (Exception e){
  121.  
    throw new RuntimeException("参数【content】解析异常!");
  122.  
    }
  123.  
    if (StringUtils.isEmpty(content) || StringUtils.isEmpty(aseKey)){
  124.  
    throw new RuntimeException("参数【requestData】解析参数空指针异常!");
  125.  
    }
  126.  
    return content;
  127.  
    }
  128.  
    }
  129.  
    throw new RuntimeException("参数【requestData】不合法异常!");
  130.  
    }
  131.  
    }
  132.  
    }
  1.  
    import com.fasterxml.jackson.databind.ObjectMapper;
  2.  
    import com.monkey.springboot.demo.annotation.SecurityParameter;
  3.  
    import com.monkey.springboot.demo.utils.AesEncryptUtils;
  4.  
    import com.monkey.springboot.demo.utils.RSAUtils;
  5.  
    import org.slf4j.Logger;
  6.  
    import org.slf4j.LoggerFactory;
  7.  
    import org.springframework.beans.factory.annotation.Value;
  8.  
    import org.springframework.core.MethodParameter;
  9.  
    import org.springframework.http.MediaType;
  10.  
    import org.springframework.http.server.ServerHttpRequest;
  11.  
    import org.springframework.http.server.ServerHttpResponse;
  12.  
    import org.springframework.web.bind.annotation.ControllerAdvice;
  13.  
    import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
  14.  
     
  15.  
    import java.util.HashMap;
  16.  
    import java.util.Map;
  17.  
    import java.util.Random;
  18.  
     
  19.  
    /**
  20.  
    * @author monkey
  21.  
    * @desc 返回数据加密
  22.  
    * @date 2018/10/25 20:17
  23.  
    */
  24.  
    @ControllerAdvice(basePackages = "com.monkey.springboot.demo.controller")
  25.  
    public class EncodeResponseBodyAdvice implements ResponseBodyAdvice {
  26.  
     
  27.  
    private final static Logger logger = LoggerFactory.getLogger(EncodeResponseBodyAdvice.class);
  28.  
     
  29.  
    @Value("${client.public.key}")
  30.  
    private String CLIENT_PUBLIC_KEY;
  31.  
    //private static final String CLIENT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9ikrLxa/cgLZXQugBQFhdxCPQmEZ9j9hadra81MqAxmRkc3eFwROAHk/+39fhmDwgtjE/w4cO6XDabL/mi5V37ioByS1QpovF8ZlJgz/RjvV3TEanvxluridXlNTfOd45uC9+TmR2DzRk5p25U1F74wF7K2KSGv2gyqZvttxrfwIDAQAB";
  32.  
     
  33.  
    @Override
  34.  
    public boolean supports(MethodParameter methodParameter, Class aClass) {
  35.  
    return true;
  36.  
    }
  37.  
     
  38.  
    @Override
  39.  
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
  40.  
    boolean encode = false;
  41.  
    if (methodParameter.getMethod().isAnnotationPresent(SecurityParameter.class)) {
  42.  
    //获取注解配置的包含和去除字段
  43.  
    SecurityParameter serializedField = methodParameter.getMethodAnnotation(SecurityParameter.class);
  44.  
    //出参是否需要加密
  45.  
    encode = serializedField.outEncode();
  46.  
    }
  47.  
    if (encode) {
  48.  
    logger.info( "对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行加密");
  49.  
    ObjectMapper objectMapper = new ObjectMapper();
  50.  
    try {
  51.  
    String result = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(body);
  52.  
    // 生成aes秘钥
  53.  
    String aseKey = getRandomString( 16);
  54.  
    // rsa加密
  55.  
    String encrypted = RSAUtils.encryptedDataOnJava(aseKey, CLIENT_PUBLIC_KEY);
  56.  
    // aes加密
  57.  
    String requestData = AesEncryptUtils.encrypt(result, aseKey);
  58.  
    Map map = new HashMap<>();
  59.  
    map.put( "encrypted", encrypted);
  60.  
    map.put( "requestData", requestData);
  61.  
    return map;
  62.  
    } catch (Exception e) {
  63.  
    e.printStackTrace();
  64.  
    logger.error( "对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:" + e.getMessage());
  65.  
    }
  66.  
    }
  67.  
    return body;
  68.  
    }
  69.  
     
  70.  
    /**
  71.  
    * 创建指定位数的随机字符串
  72.  
    * @param length 表示生成字符串的长度
  73.  
    * @return 字符串
  74.  
    */
  75.  
    public static String getRandomString(int length) {
  76.  
    String base = "abcdefghijklmnopqrstuvwxyz0123456789";
  77.  
    Random random = new Random();
  78.  
    StringBuffer sb = new StringBuffer();
  79.  
    for (int i = 0; i < length; i++) {
  80.  
    int number = random.nextInt(base.length());
  81.  
    sb.append(base.charAt(number));
  82.  
    }
  83.  
    return sb.toString();
  84.  
    }
  85.  
     
  86.  
    }

第五步:
 

  1.  
    /**
  2.  
    * 跳转RSA+AES双重加密页面
  3.  
    *
  4.  
    * @return
  5.  
    */
  6.  
     
  7.  
    @RequestMapping("/test")
  8.  
    public String goTest() {
  9.  
    return "test";
  10.  
    }
  11.  
     
  12.  
    /**
  13.  
    * RSA+AES双重加密测试
  14.  
    *
  15.  
    * @return object
  16.  
    */
  17.  
    @RequestMapping("/testEncrypt")
  18.  
    @ResponseBody
  19.  
    @SecurityParameter
  20.  
    public Persion testEncrypt(@RequestBody Persion info) {
  21.  
    System.out.println(info.getName());
  22.  
    String content = "内容";
  23.  
    info.setName(content);
  24.  
    return info;
  25.  
    }

第六步: 其中random,js(生成一个16位数的随机字符串),是我自己定义的,其余的都可以去官方下载
学习加密(四)spring boot 使用RSA+AES混合加密,前后端传递参数加解密_第1张图片
 

  1.  
  2.  
    "en" xmlns:th="http://www.thymeleaf.org">
  3.  
  4.  
    "UTF-8">
  5.  
    RSA+AES 加解密
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
     
  15.  
  16.  

    服务端公钥:

  17.  
  18.  

    客户端私钥:

  19.  
  20.  
    "button" id="bt" value="提交" />
  21.  
  22.  

application.properties :

  1.  
    server. private.key=MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIn2zWqU7K/2qm5pOpq5bp9R+3MTnStWTfJU9nC/Vo7UKH9dITPvrELCTK+qlqpx5Fes+l0GY7n6u4n4jyiw4ejsvkZYQ5ww477yLOn2FcoEGuZEwPgSCmfTST0OFUgQqn+/J11k9L92jEHyieE3qmhMkMt0UsVUSJwx/nZxo30ZAgMBAAECgYBD3YHigeuEC4R+14iaf8jo2j0kuGtB3Cxvnlez0otTqw1YyYkBsU49cLKkXvfKVEgM0Ow/QltgKvSBxCE31PrrDka5TygVMqqA/IM7NrDvjUcGLjyoeNmLA8660fWcDxUTlAGN5kxIvUATayVwKVflpWPWu0FPKsWrZustnEo+4QJBAMCmYsWqAKWYMVRXFP3/XGRfio8DV793TOckyBSN9eh8UhgoZyT3u7oeHmDJEwm4aNMHlg1Pcdc6tNsvi1FRCiUCQQC3VNzfF4xOtUgX7vWPL8YVljLuXmy12iVYmg6ofu9l31nwM9FLQ1TRFglvF5LWrIXTQb07PgGd5DJMAQWGsqLlAkAPE7Z9M73TN+L8b8hDzJ1leZi1cpSGdoa9PEKwYR/SrxAZtefEm+LEQSEtf+8OfrEtetWCeyo0pvKKiOEFXytFAkEAgynL/DC0yXsZYUYtmYvshHU5ayFTVagFICbYZeSrEo+BoUDxdI9vl0fU6A5NmBlGhaZ65G+waG5jLc1tTrlvoQJAXBEoPcBNAosiZHQfYBwHqU6mJ9/ZacJh3MtJzGGebfEwJgtln5b154iANqNWXpySBLvkK+Boq7FYRiD83pqmUg==
  2.  
    client. public.key=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9ikrLxa/cgLZXQugBQFhdxCPQmEZ9j9hadra81MqAxmRkc3eFwROAHk/+39fhmDwgtjE/w4cO6XDabL/mi5V37ioByS1QpovF8ZlJgz/RjvV3TEanvxluridXlNTfOd45uC9+TmR2DzRk5p25U1F74wF7K2KSGv2gyqZvttxrfwIDAQAB

后记:
     现在我要把这种混合加密方式,要整合进行到我的项目当中,到时候如果出现一些别的问题,我在更新帖,
                                                                                                                               ---没有绝对安全,只有相对安全!!!!

 
 

相关文章

  • vue java 使用AES 前后端加密解密
  • spring boot使用jasypt加密原理解析
  • spring boot简单使用学习
  • Spring boot学习(四)Spring boot整合Druid
  • 学习笔记(四)、MongoDB入门使用以及Spring Boot 整合操作
  • Spring Boot Admin 使用
  • Spring Boot Admin 使用
  • Spring Boot使用Thymeleaf
  • GraphQL Spring Boot 使用
  • Spring Boot + Spring Security 前后端分离搭建

转载于:https://www.cnblogs.com/leigepython/p/10930139.html

你可能感兴趣的:(学习加密(四)spring boot 使用RSA+AES混合加密,前后端传递参数加解密)