欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaWeb實現(xiàn)RSA+AES混合加密

 更新時間:2023年10月27日 09:40:45   作者:YO_RUI  
RSA+AES的混合加密時,AES用于給傳輸?shù)臄?shù)據(jù)加密,然后通過RSA給AES的秘鑰加密,本文就來詳細(xì)的介紹一下如何實現(xiàn),具有一定的參考價值,感興趣的可以了解一下

一、前言

RSA與AES加密的詳細(xì)介紹這里就不寫了,網(wǎng)上很多博客,這里就只是簡單說明一下:

  • AES:屬于對稱加密,通過一個公共的秘鑰,實現(xiàn)加密解密;
  • RSA:非對稱加密,需要生成一個公鑰、一個私鑰,這兩個秘鑰使用時,一個用來加密時,那么就需要另一個秘鑰進(jìn)行解密,公鑰一般提供給客戶端。

二、整體構(gòu)思

RSA+AES的混合加密時,AES用于給傳輸?shù)臄?shù)據(jù)加密,然后通過RSA給AES的秘鑰加密,所以接收到數(shù)據(jù)后,就需要先解密得到AES的秘鑰,然后通過AES秘鑰再去解密得到數(shù)據(jù)。
下面簡單說下demo中加密解密的實現(xiàn)過程:

  • 前后端各自生成自己的RSA公私密鑰(這就必須確保雙方的RSA算法要匹配,不然雙方就無法正常解密)
  • 當(dāng)訪問項目首頁時,前端生成RSA秘鑰,并存放在window對象中的localStorage
  • 頁面發(fā)起請求獲取服務(wù)端的RSA公鑰,服務(wù)端收到請求后生成RSA公司秘鑰,并將秘鑰放入session,所以每次建立會話連接時都是不一樣的秘鑰,然后將公鑰返回給前端頁面
  • 頁面接收到服務(wù)端的RSA公鑰后,存入window對象,然后用服務(wù)端RSA公鑰加密前端的RSA公鑰發(fā)送給服務(wù)端
  • 服務(wù)端收到前端發(fā)過來的請求后,通過自己的私鑰解密數(shù)據(jù),從而得到前端的公鑰,并存入session。

這里面提到的存儲秘鑰的方式只是在demo中作為演示使用,可以采用更合理、更安全的方式是實現(xiàn)!

這樣,前后端都擁有的對方RSA的公鑰,后面在同一個會話中具體的請求數(shù)據(jù)時,每次各自都會生成新的AES秘鑰(AES的算法也需要前后端能匹配上),RSA的秘鑰則在響應(yīng)位置去取就可以了。

在這里插入圖片描述

在這里插入圖片描述

三、主要代碼

1、服務(wù)端

兩個加密解密工具類,里面部分有使用第三方j(luò)ar(hutool-all.jar)。

  • AESUtil
package com.lr.demo.util;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;

public class AESUtil {
    private static final String KEY_ALGORITHM = "AES";
    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//默認(rèn)的加密算法

    public static String getKey(int len){
        if(len % 16 != 0){
            System.out.println("長度要為16的整數(shù)倍");
            return null;
        }

        char[] chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
        char[] uuid = new char[len];

        if (len > 0) {
            for (int i = 0; i < len; i++) {
                int x = (int) (Math.random() * (len - 0 + 1) + 0);
                uuid[i] = chars[x % chars.length];
            }
        }

        return new String(uuid);
    }


    public static String byteToHexString(byte[] bytes){
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String strHex=Integer.toHexString(bytes[i]);
            if(strHex.length() > 3){
                sb.append(strHex.substring(6));
            } else {
                if(strHex.length() < 2){
                    sb.append("0" + strHex);
                } else {
                    sb.append(strHex);
                }
            }
        }
        return  sb.toString();
    }

    /**
     * AES 加密操作
     *
     * @param content 待加密內(nèi)容
     * @param key 加密密碼
     * @return 返回Base64轉(zhuǎn)碼后的加密數(shù)據(jù)
     */
    public static String encrypt(String content, String key) {
        try {
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 創(chuàng)建密碼器

            byte[] byteContent = content.getBytes("utf-8");

            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));// 初始化為加密模式的密碼器

            byte[] result = cipher.doFinal(byteContent);// 加密

            return org.apache.commons.codec.binary.Base64.encodeBase64String(result);//通過Base64轉(zhuǎn)碼返回
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    /**
     * AES 解密操作
     *
     * @param content
     * @param key
     * @return
     */
    public static String decrypt(String content, String key) {

        try {
            //實例化
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);

            //使用密鑰初始化,設(shè)置為解密模式
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));

            //執(zhí)行操作
            byte[] result = cipher.doFinal(org.apache.commons.codec.binary.Base64.decodeBase64(content));

            return new String(result, "utf-8");
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    private static SecretKeySpec getSecretKey(final String key) throws UnsupportedEncodingException {
        //返回生成指定算法密鑰生成器的 KeyGenerator 對象
        KeyGenerator kg = null;

        try {
            kg = KeyGenerator.getInstance(KEY_ALGORITHM);

            //AES 要求密鑰長度為 128
            kg.init(128, new SecureRandom(key.getBytes()));

            //生成一個密鑰
            SecretKey secretKey = kg.generateKey();

            return new SecretKeySpec(Arrays.copyOf(key.getBytes("utf-8"), 16), KEY_ALGORITHM);// 轉(zhuǎn)換為AES專用密鑰
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        }

        return null;
    }

}

  • RSAUtil
package com.lr.demo.util;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import org.springframework.util.Base64Utils;

import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;

public class RSAUtil {

    public static final String PB_KEY = "pb_key";
    public static final String PR_KEY = "pr_key";

    public static final String CLI_PB_KEY = "cli_pb_key";

    /**
     * 獲取公私秘鑰對
     * @return
     */
    public static Map<String, Key> getRSAKey(){
        KeyPair pair = SecureUtil.generateKeyPair("RSA");
        PrivateKey privateKey = pair.getPrivate();
        PublicKey publicKey = pair.getPublic();

        Map<String, Key> keys = new HashMap<>();
        keys.put(PR_KEY,privateKey);
        keys.put(PB_KEY,publicKey);

        return keys;
    }

    /**
     * 公鑰加密
     * @param pbKey
     * @param content
     * @return
     */
    public static String encByPbKey(String pbKey,String content){
        try {
            byte[] bytes = Base64Utils.decode(pbKey.getBytes("UTF-8"));
            RSA rsa = new RSA(null,bytes);
            byte[] enc = rsa.encrypt(content.getBytes("UTF-8"), KeyType.PublicKey);
            String s = new String(Base64Utils.encode(enc));
            return s;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公鑰加密
     * @param pbKey
     * @param content
     * @return
     */
    public static String encByPbKey(PublicKey pbKey,String content){
        try {
            RSA rsa = new RSA(null,pbKey);
            byte[] enc = rsa.encrypt(content.getBytes("UTF-8"), KeyType.PublicKey);
            String s = new String(Base64Utils.encode(enc));
            return s;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 私鑰解密
     * @param prKey
     * @param content
     * @return
     */
    public static String dencByPrKey(String prKey,String content){
        try {
            byte[] bytes = Base64Utils.decode(prKey.getBytes("UTF-8"));
            RSA rsa = new RSA(bytes,null);
            byte[] denc = rsa.decrypt(Base64Utils.decode(content.getBytes("UTF-8")), KeyType.PrivateKey);
            String s = new String(Base64Utils.encode(denc));
            return s;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 私鑰解密
     * @param prKey
     * @param content
     * @return
     */
    public static String dencByPrKey(PrivateKey prKey,String content){
        try {
            RSA rsa = new RSA(prKey,null);
            byte[] denc = rsa.decrypt(Base64Utils.decode(content.getBytes("UTF-8")), KeyType.PrivateKey);
            String s = new String(denc);
            return s;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

}

l兩個Controller,一個是初始化是秘鑰交換的,一個用于測試

package com.lr.demo.controller;

import com.lr.demo.commons.Result;
import com.lr.demo.util.RSAUtil;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;
import java.security.Key;
import java.security.PrivateKey;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("secret")
public class SecretController {

    /**
     * 返回服務(wù)端的RSA公鑰
     * @param session
     * @return
     */
    @RequestMapping("getKey")
    public Result getKey(HttpSession session){
        Map<String, Key> rsaKey = (Map<String, Key>) session.getAttribute("keys");
        if(rsaKey == null){
            rsaKey = RSAUtil.getRSAKey();
            session.setAttribute("keys",rsaKey);
        }

        byte[] encode = Base64Utils.encode(rsaKey.get(RSAUtil.PB_KEY).getEncoded());
        return Result.success(new String(encode));

    }

    /**
     * 分段解密發(fā)送過來的客戶端RSA公鑰
     * @param map
     * @param session
     * @return
     */
    @RequestMapping("acceptKey")
    public Result acceptKey(@RequestBody Map<String,Object> map, HttpSession session){

        List<String> clientKeys = (List<String>) map.get("clientKey");
        System.out.println("clientKey:" + clientKeys);
        Map<String, Key> rsaKey = (Map<String, Key>) session.getAttribute("keys");

        String cli_key = "";
        if(clientKeys != null){
            for (String item : clientKeys) {
                cli_key += RSAUtil.dencByPrKey((PrivateKey) rsaKey.get(RSAUtil.PR_KEY), item);
            }
        }
        session.setAttribute(RSAUtil.CLI_PB_KEY,cli_key);
        System.out.println("解密后客戶端公鑰:" + cli_key);
        return Result.success();
    }

}

package com.lr.demo.controller;


import com.alibaba.fastjson.JSON;
import com.lr.demo.commons.Constant;
import com.lr.demo.commons.Result;
import com.lr.demo.util.AESUtil;
import com.lr.demo.util.RSAUtil;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.security.Key;
import java.security.PrivateKey;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("sys")
public class SystemController {

    @RequestMapping("login")
    public Result login(@RequestBody String data, HttpServletRequest request,HttpServletResponse response){
        String plaintext = dencrypt(request, data);
        return Result.success(encrypt("登錄成功啦",response));
    }


    private String dencrypt(HttpServletRequest request,String data){
        // 從session中獲取服務(wù)端RSA的私鑰
        HttpSession session = request.getSession();
        Map<String, Key> rsaKey = (Map<String, Key>) session.getAttribute("keys");

        HashMap<String,String> hashMap = JSON.parseObject(data, HashMap.class);
        // 獲取客戶端發(fā)送的加密數(shù)據(jù)
        String enc_data = hashMap.get(Constant.ENCRYPT_DATA);
        System.out.println("獲取請求數(shù)據(jù)---->:" + enc_data);
        // 獲取發(fā)送過來的AES秘鑰
        String enc_aes_key = request.getHeader(Constant.ENCRYPT_AES_KEY);
        // 解密AES秘鑰
        String aes_key = RSAUtil.dencByPrKey((PrivateKey) rsaKey.get(RSAUtil.PR_KEY), enc_aes_key);
        // AES解密
        String plaintext = AESUtil.decrypt(enc_data, aes_key);

        System.out.println("解密數(shù)據(jù)---->:" + plaintext);
        return plaintext;
    }

    public Map<String, String> encrypt(String data, HttpServletResponse response){
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        String cliKey = (String) session.getAttribute(RSAUtil.CLI_PB_KEY); // 獲取客戶端RSA公鑰
        String aesKey = AESUtil.getKey(16); // 獲取AES秘鑰
        // RSA加密AES秘鑰
        String encrypt_aes_key = RSAUtil.encByPbKey(cliKey, aesKey);
        // AES加密返回數(shù)據(jù)
        String encrypt_data = AESUtil.encrypt(data, aesKey);
        // 添加響應(yīng)頭(AES秘鑰)
        response.addHeader(Constant.ENCRYPT_AES_KEY, encrypt_aes_key);
        Map<String,String> map = new HashMap<>();
        map.put(Constant.ENCRYPT_DATA,encrypt_data);
        return map;
    }
}

2、前端

前端涉及的文件較多,這里就只展示下頁面,其余詳細(xì)代碼可以下載源碼后查看。

  • aes_v1.0.js:AES加解密
  • rsa.js、crypto-js.js:RSA加解密
  • demo.js:封裝的函數(shù)

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
    <script src="static/js/aes_v1.0.js"></script> 
    <script src="static/js/rsa.js"></script>
    <script src="static/js/crypto-js.js"></script>
    <script src="static/js/demo.js"></script>
    <script src="static/js/jquery-3.5.1.js"></script>
  </head>
  <body>

  <form action="<%=request.getContextPath()%>/sys/login" id="loginForm">
      <input type="text" name="username" value="">
      <input type="password" name="password" value="">
      <input type="button" value="登錄" id="loginBtn">
  </form>

  <script>
      // 首頁加載時,秘鑰生成和交換
      getRsaKeys(f)
  </script>
  
  <script>

      function getFormJson(formJqueryObj) {
          var o = {};
          var a = formJqueryObj.serializeArray();
          $.each(a, function () {
              if (o[this.name]) {
                  if (!o[this.name].push) {
                      o[this.name] = [o[this.name]];
                  }
                  o[this.name].push(this.value || '');
              } else {
                  o[this.name] = this.value || '';
              }
          });
          return o;
      }


      $('#loginBtn').click(function () {
          var json = getFormJson($('#loginForm'))
          // demo.js封裝的函數(shù)
          request(json,'<%=request.getContextPath()%>/sys/login',function (res) {
              console.log(res)
          })
      })
  </script>
  </body>
</html>

四、測試

啟動項目,打開首頁:

在這里插入圖片描述

服務(wù)端日志:

在這里插入圖片描述

當(dāng)交換完秘鑰后,進(jìn)行登錄測試:

在這里插入圖片描述

服務(wù)端就收時的日志輸出:

在這里插入圖片描述

響應(yīng)后頁面的輸出:

在這里插入圖片描述

在這里插入圖片描述

以上就是一個簡單的demo,源碼點擊下載

到此這篇關(guān)于JavaWeb實現(xiàn)RSA+AES混合加密的文章就介紹到這了,更多相關(guān)JavaWe RSA+AES混合加密內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java Map 通過 key 或者 value 過濾的實例代碼

    Java Map 通過 key 或者 value 過濾的實例代碼

    這篇文章主要介紹了Java Map 通過 key 或者 value 過濾的實例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-06-06
  • springboot集成redis并使用redis生成全局唯一索引ID

    springboot集成redis并使用redis生成全局唯一索引ID

    本文主要介紹了springboot集成redis并使用redis生成全局唯一索引ID,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Spring Boot 入門指南

    Spring Boot 入門指南

    Spring Boot 簡化了Spring 應(yīng)用的初始搭建、開發(fā)過程,開發(fā)人員可使用Spring提供的特定的方式來進(jìn)行配置,不再需要重復(fù)自定義樣板化的配置。本文就將帶你入門Spring Boot
    2021-05-05
  • Spring MVC攔截器的基本使用方法

    Spring MVC攔截器的基本使用方法

    這篇文章主要給大家介紹了關(guān)于Spring MVC攔截器的基本使用方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Spring MVC具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • Spring?Bean獲取方式的實例化方式詳解

    Spring?Bean獲取方式的實例化方式詳解

    工作中需要對一個原本加載屬性文件的工具類修改成對數(shù)據(jù)庫的操作當(dāng)然,ado層已經(jīng)寫好,但是需要從Spring中獲取bean,然而,工具類并沒有交給Spring來管理,所以需要通過方法獲取所需要的bean。于是整理了Spring獲取bean的幾種方法
    2023-03-03
  • Mybatis報錯日志BindingException的解決

    Mybatis報錯日志BindingException的解決

    本文主要介紹了Mybatis報錯日志BindingException的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • MybatisPlus實現(xiàn)數(shù)據(jù)權(quán)限隔離的示例詳解

    MybatisPlus實現(xiàn)數(shù)據(jù)權(quán)限隔離的示例詳解

    Mybatis Plus對Mybatis做了無侵入的增強,非常的好用,今天就給大家介紹它的其中一個實用功能:數(shù)據(jù)權(quán)限插件,感興趣的可以跟隨小編一起了解下
    2024-04-04
  • httpclient的監(jiān)控流程源碼解讀

    httpclient的監(jiān)控流程源碼解讀

    這篇文章主要為大家介紹了httpclient的監(jiān)控流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Java Scanner類及其方法使用圖解

    Java Scanner類及其方法使用圖解

    這篇文章主要介紹了Java Scanner類及其方法使用圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-05-05
  • Java中從Integer到Date的轉(zhuǎn)換方法

    Java中從Integer到Date的轉(zhuǎn)換方法

    這篇文章主要介紹了Java中integer怎么轉(zhuǎn)換date,在Java中,如果我們有一個Integer類型的數(shù)據(jù),想要將其轉(zhuǎn)換為Date類型,本文給大家介紹了實現(xiàn)方法,并通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下
    2024-05-05

最新評論