最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實現(xiàn)后端和前端的接口數(shù)據(jù)加密方案詳解

 更新時間:2026年04月03日 09:23:46   作者:咘嚕biu  
這篇文章主要為大家詳細介紹了一種基于橢圓曲線集成加密方案(ECIES)的前后端數(shù)據(jù)安全交互方法,該方案通過橢圓曲線密碼學實現(xiàn)密鑰協(xié)商,結合AES對稱加密保障數(shù)據(jù)傳輸安全,感興趣的小伙伴可以了解下

1.解決問題

前后端在交互過程中,請求和響應的數(shù)據(jù)需要加密處理,并保證安全和性能。

方案名稱:ECIES (Elliptic Curve Integrated Encryption Scheme,橢圓曲線集成加密方案)

2.核心思路

服務端準備

  • 生成密鑰對(EC-橢圓曲線),私鑰servPriKey放在服務端。
  • 公鑰servPubKey安全地預置或下發(fā)給客戶端(如通過初始化接口)。

客戶端加密(每次請求)

  • 生成臨時密鑰對(EC-橢圓曲線),公鑰pubKey,私鑰priKey
  • 私鑰priKey + 服務端公鑰servPubKey計算共享密鑰Key(ECDH-協(xié)商+sha256)
  • 加密請求業(yè)務數(shù)據(jù)(AES):encryptData = AES.encrypt(data, Key)
  • 發(fā)送加密后的業(yè)務數(shù)據(jù)encryptData公鑰pubKey給服務端

服務端解密

  • 私鑰servPriKey + 客戶端公鑰pubKey計算共享密鑰Key(ECDH-協(xié)商+sha256)
  • 解密請求數(shù)據(jù),data = AES.decrypt(encryptData, Key)

服務端加密:通過3中計算的Key直接加密數(shù)據(jù)即可

客戶端解密:通過2中計算的Key直接解密數(shù)據(jù)即可

3.代碼示例

package com.visy.utils;

import cn.hutool.crypto.symmetric.AES;

import javax.crypto.KeyAgreement;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.function.Consumer;


/**
 * ECIES (Elliptic Curve Integrated Encryption Scheme,橢圓曲線集成加密方案)
 * 這個方案是橢圓曲線密碼學中的密碼學方案,用于實現(xiàn)前后端間通信的數(shù)據(jù)加密,是應用內的加密機制。
 * 核心是密鑰協(xié)商:使用ECDH算法生成密鑰對,并計算出共享密鑰。
 */
public class ECIESDemo {

    //Base64工具類
    static class BASE64 {
        public static String encode(byte[] data) {
            return Base64.getEncoder().encodeToString(data);
        }

        public static byte[] decode(String base64Str) {
            return Base64.getDecoder().decode(base64Str);
        }
    }

    //ECDH工具
    static class ECDH {
        public static StrKeyPair generateKeyPair(String curveName) throws Exception {
            // 1. 指定橢圓曲線參數(shù),例如 secp256r1 (NIST P-256)
            ECGenParameterSpec ecSpec = new ECGenParameterSpec(curveName);
            // 2. 生成ECC密鑰對
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
            kpg.initialize(ecSpec, new SecureRandom());
            KeyPair keyPair = kpg.generateKeyPair();
            return StrKeyPair.of(keyPair);
        }

        /**
         * ECDH核心方法:計算共享秘密
         * @param myPriKey 己方的私鑰(Base64字符串)
         * @param otherPubKey 對方的公鑰(Base64字符串)
         * @return Base64編碼的共享秘密字符串
         */
        public static String deriveSharedSecret(String myPriKey, String otherPubKey) throws Exception {
            PrivateKey myPrivateKey = toPrivateKey(myPriKey);
            PublicKey otherPublicKey = toPublicKey(otherPubKey);

            KeyAgreement ka = KeyAgreement.getInstance("ECDH");
            ka.init(myPrivateKey);
            ka.doPhase(otherPublicKey, true);

            byte[] rawSecret = ka.generateSecret();
            //用SHA-256哈希一次,得到32字節(jié)AES-256密鑰
            MessageDigest sha256 = MessageDigest.getInstance("SHA-256");

            String shearedSecret = BASE64.encode(sha256.digest(rawSecret));
            System.out.println("【共享密鑰】計算-私鑰:"+myPriKey);
            System.out.println("【共享密鑰】計算-公鑰:"+otherPubKey);
            System.out.println("【共享密鑰】計算-結果:"+shearedSecret);
            System.out.println("---------------------------------");
            return shearedSecret;
        }

        private static PublicKey toPublicKey(String pubKey) throws Exception {
            byte[] decodedBytes = BASE64.decode(pubKey);
            KeyFactory keyFactory = KeyFactory.getInstance("EC");
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedBytes);
            return keyFactory.generatePublic(keySpec);
        }

        private static PrivateKey toPrivateKey(String priKey) throws Exception {
            byte[] decodedBytes = BASE64.decode(priKey);
            KeyFactory keyFactory = KeyFactory.getInstance("EC");
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedBytes);
            return keyFactory.generatePrivate(keySpec);
        }
    }

    //AES加解密工具
    static class Aes {
        public static String  encrypt(String data, String key){
            AES aes = new AES(BASE64.decode(key));
            return aes.encryptBase64(data);
        }
        public static String decrypt(String data, String key){
            AES aes = new AES(BASE64.decode(key));
            return aes.decryptStr(BASE64.decode(data));
        }
    }

    //模擬客戶端(如瀏覽器)
    static class Client {
        //服務端公鑰,固定值,后續(xù)不再更新
        private final String servPubKey;

        public Client(String servPubKey){
            this.servPubKey = servPubKey;
            System.out.println("【客戶端】初始化完成,服務端公鑰: " + servPubKey);
            System.out.println("---------------------------------");
        }

        public void request(Server server, String message, Consumer<String> callback) throws Exception {
            //生成密鑰對
            StrKeyPair keyPair = genKeyPair();
            //計算共享密鑰
            String sharedSecret = getSharedSecret(keyPair.getPriKey());
            //對稱加密數(shù)據(jù)
            String reqData = Aes.encrypt(message, sharedSecret);
            //封裝傳輸通道
            Channel channel = new Channel(keyPair.getPubKey(), reqData, resData -> {
                //解密數(shù)據(jù)
                String data = Aes.decrypt(resData, sharedSecret);
                //將數(shù)據(jù)傳給回調
                callback.accept(data);
            });
            //發(fā)送給服務端
            server.receive(channel);
        }

        private StrKeyPair genKeyPair() throws Exception {
            StrKeyPair keyPair = ECDH.generateKeyPair("secp256r1");
            System.out.println("【客戶端】公鑰: " + keyPair.getPubKey());
            System.out.println("【客戶端】私鑰: " + keyPair.getPriKey());
            System.out.println("【客戶端】已刷新密鑰對!");
            System.out.println("---------------------------------");
            return keyPair;
        }

        private String getSharedSecret(String priKey) throws Exception {
            return ECDH.deriveSharedSecret(priKey, this.servPubKey);
        }
    }

    //模擬后臺服務端
    static class Server {
        //服務端密鑰對,只生成一次
        private final StrKeyPair keyPair;

        public Server() throws Exception {
            this.keyPair = ECDH.generateKeyPair("secp256r1");
            System.out.println("【服務端】公鑰: " + this.keyPair.getPubKey());
            System.out.println("【服務端】私鑰: " + this.keyPair.getPriKey());
            System.out.println("【服務端】初始化完成!");
            System.out.println("---------------------------------");
        }

        public String getPubKey(){
            return this.keyPair.getPubKey();
        }

        public void receive(Channel channel) throws Exception {
            //客戶端公鑰
            String clientPubKey = channel.getClientPubKey();
            //計算共享密鑰
            //因為服務端私鑰是固定的
            //如果客戶端不是每次請求都刷新密鑰對,可以按clientPubKey直接緩存Key
            //但是要注意內存溢出,可以設置緩存有效時間,指定最大緩存?zhèn)€數(shù)等
            String sharedSecret = getSharedSecret(clientPubKey);
            //解密數(shù)據(jù)
            String message = Aes.decrypt(channel.read(), sharedSecret);
            System.out.println("【服務端】收到消息: " + message);
            System.out.println("【服務端】客戶端公鑰:" + clientPubKey);
            System.out.println("---------------------------------");

            //響應消息
            String resMsg = "服務端已收到消息->"+ message;
            //加密
            String data = Aes.encrypt(resMsg, sharedSecret);
            //發(fā)送
            channel.write(data);
        }

        /**
         * 計算共享密鑰(服務端私鑰 + 客戶端公鑰)
         */
        private String getSharedSecret(String clientPubKey) throws Exception {
            return ECDH.deriveSharedSecret(this.keyPair.getPriKey(), clientPubKey);
        }
    }

    //模擬請求通道
    static class Channel {
        private final String reqData;
        private final String clientPubKey;
        private final Consumer<String> callback;

        public Channel(String clientPubKey, String reqData, Consumer<String> callback) {
            this.reqData = reqData;
            this.clientPubKey = clientPubKey;
            this.callback = callback;
        }

        //獲取客戶端公鑰
        public String getClientPubKey(){
            return this.clientPubKey;
        }

        //讀取數(shù)據(jù)
        public String read() {
            return this.reqData;
        }

        //寫入數(shù)據(jù)
        public void write(String resData){
            this.callback.accept(resData);
        }
    }

    //密鑰對(base64字符串)
    static class StrKeyPair {
        private final String priKey;
        private final String pubKey;

        private StrKeyPair(KeyPair keyPair) {
            this.priKey = BASE64.encode(keyPair.getPrivate().getEncoded());
            this.pubKey = BASE64.encode(keyPair.getPublic().getEncoded());
        }

        public static StrKeyPair of(KeyPair keyPair) {
            return new StrKeyPair(keyPair);
        }

        public String getPriKey() {
            return this.priKey;
        }

        public String getPubKey() {
            return this.pubKey;
        }
    }

    //測試
    public static void main(String[] args) throws  Exception {
        //創(chuàng)建服務端
        Server server = new Server();
        //創(chuàng)建客戶端
        Client client = new Client(server.getPubKey());

        //向服務端發(fā)送請求
        client.request(server, "hello world", data -> {
            System.out.println("【客戶端】收到消息: " + data);
        });
        System.out.println("============================================");
        //向服務端發(fā)送請求
        client.request(server, "{\"name\": \"張三\"}", data -> {
            System.out.println("【客戶端】收到消息: " + data);
        });
        System.out.println("============================================");
    }
}

4.輸出

【服務端】公鑰: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUutqZsAN1Kh+FFvS95lKFob0zKZZY0mtBKNOYFSZ/WzaLO8CHH1zjcH3nV82MxXwyj0t+yhP/Dugfriy8VIWbg==
【服務端】私鑰: MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAaJ/UnsK4Tt+1Vyt9vyAnYqinr8uobgPZOlvCMeihKkg==
【服務端】初始化完成!
---------------------------------
【客戶端】初始化完成,服務端公鑰: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUutqZsAN1Kh+FFvS95lKFob0zKZZY0mtBKNOYFSZ/WzaLO8CHH1zjcH3nV82MxXwyj0t+yhP/Dugfriy8VIWbg==
---------------------------------
【客戶端】公鑰: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDz5YRdfRm1l0Wj0BqIBMEq2zLca96eidX/DEIZipQol8gzV4YKiLwtWxmS2rplAay1/4stiuofvLFZZAJ0rM/w==
【客戶端】私鑰: MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCDLGtJ2Lxm+8cd+o1iDbxkigojjFdy+9k/wVhQ0XJTRQw==
【客戶端】已刷新密鑰對!
---------------------------------
【共享密鑰】計算-私鑰:MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCDLGtJ2Lxm+8cd+o1iDbxkigojjFdy+9k/wVhQ0XJTRQw==
【共享密鑰】計算-公鑰:MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUutqZsAN1Kh+FFvS95lKFob0zKZZY0mtBKNOYFSZ/WzaLO8CHH1zjcH3nV82MxXwyj0t+yhP/Dugfriy8VIWbg==
【共享密鑰】計算-結果:fIPyLCxiu26stP2C4bGyCU8Eh+uYUWp3w8PjRWdxh8k=
---------------------------------
【共享密鑰】計算-私鑰:MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAaJ/UnsK4Tt+1Vyt9vyAnYqinr8uobgPZOlvCMeihKkg==
【共享密鑰】計算-公鑰:MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDz5YRdfRm1l0Wj0BqIBMEq2zLca96eidX/DEIZipQol8gzV4YKiLwtWxmS2rplAay1/4stiuofvLFZZAJ0rM/w==
【共享密鑰】計算-結果:fIPyLCxiu26stP2C4bGyCU8Eh+uYUWp3w8PjRWdxh8k=
---------------------------------
【服務端】收到消息: hello world
【服務端】客戶端公鑰:MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDz5YRdfRm1l0Wj0BqIBMEq2zLca96eidX/DEIZipQol8gzV4YKiLwtWxmS2rplAay1/4stiuofvLFZZAJ0rM/w==
---------------------------------
【客戶端】收到消息: 服務端已收到消息->hello world
============================================
【客戶端】公鑰: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGbyRS8JTE32TLAMXYaFpi8pY8Cf2R7u9gdta+PnB7thgyAZ5FEBGjgRhNEL2MFD7g5B8yLX3cTghpjisajs4Tw==
【客戶端】私鑰: MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCADaXXP8AmBXXhrDJIXpFBH9byFr+ak38DAY1J1+zCktQ==
【客戶端】已刷新密鑰對!
---------------------------------
【共享密鑰】計算-私鑰:MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCADaXXP8AmBXXhrDJIXpFBH9byFr+ak38DAY1J1+zCktQ==
【共享密鑰】計算-公鑰:MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUutqZsAN1Kh+FFvS95lKFob0zKZZY0mtBKNOYFSZ/WzaLO8CHH1zjcH3nV82MxXwyj0t+yhP/Dugfriy8VIWbg==
【共享密鑰】計算-結果:7ngHo0nz8W2Zv9vMKORu5jC7uPIhgsZaS/657vCpcUs=
---------------------------------
【共享密鑰】計算-私鑰:MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAaJ/UnsK4Tt+1Vyt9vyAnYqinr8uobgPZOlvCMeihKkg==
【共享密鑰】計算-公鑰:MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGbyRS8JTE32TLAMXYaFpi8pY8Cf2R7u9gdta+PnB7thgyAZ5FEBGjgRhNEL2MFD7g5B8yLX3cTghpjisajs4Tw==
【共享密鑰】計算-結果:7ngHo0nz8W2Zv9vMKORu5jC7uPIhgsZaS/657vCpcUs=
---------------------------------
【服務端】收到消息: {"name": "張三"}
【服務端】客戶端公鑰:MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGbyRS8JTE32TLAMXYaFpi8pY8Cf2R7u9gdta+PnB7thgyAZ5FEBGjgRhNEL2MFD7g5B8yLX3cTghpjisajs4Tw==
---------------------------------
【客戶端】收到消息: 服務端已收到消息->{"name": "張三"}
============================================

5.落地建議

服務端的加解密數(shù)據(jù)操作應該添加全局處理,比如攔截器,AOP切面等。

客戶端的加解密數(shù)據(jù)操作同樣應該全局處理,比如 axios的攔截器內。

全局處理加解密數(shù)據(jù)可以讓編寫業(yè)務的人不用關心加解密,使用起來是無感的(就像不加解密之前一樣)

前后端應該協(xié)商好傳輸?shù)母袷?,比如?/p>

POST提交,JSON格式:

{
	"key": "客戶端公鑰",
	"data": "加密數(shù)據(jù)"
}

GET提交:url?key=客戶端公鑰&data=加密數(shù)據(jù)

6.結合前端完整示例

本示例中為了和前端js插件統(tǒng)一,所有密鑰均用十六進制(hex)表示,不再用Base64的形式

6.1后端代碼

package com.visy.utils;

import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;

import javax.crypto.KeyAgreement;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.*;
import java.util.Arrays;
import java.util.Base64;

/**
 * Hex 十六進制版本的ECDH工具
 */
public class HexECDHDemo {
    static class Hex {
        /**
         * BigInteger轉64字符hex(補零)
         */
        private static String to64Hex(BigInteger num) {
            String hex = num.toString(16);
            if (hex.length() < 64) {
                return repeatedStr('0', 64 - hex.length()) + hex;
            }
            return hex;
        }

        private static String bytesToHex(byte[] bytes) {
            return HexUtil.encodeHexStr(bytes);
        }

        public static byte[] hexToBytes(String hex){
            return HexUtil.decodeHex(hex);
        }

        private static String repeatedStr(char ch, int count) {
            if (count <= 0) {
                return "";
            }
            char[] chars = new char[count];
            Arrays.fill(chars, ch);
            return new String(chars);
        }
    }

    public static class StrKeyPair {
        private final String priKey;
        private final String pubKey;

        private StrKeyPair(String priKey, String pubKey) {
            this.priKey = priKey;
            this.pubKey = pubKey;
        }

        public static StrKeyPair of(KeyPair keyPair) {
            // 1. 提取公鑰坐標
            ECPublicKey ecPubKey = (ECPublicKey) keyPair.getPublic();
            ECPoint point = ecPubKey.getW(); //返回橢圓曲線上的點 (x, y坐標)

            // 2. 格式化為04+x+y格式
            BigInteger x = point.getAffineX(), y = point.getAffineY();
            String xHex = Hex.to64Hex(x), yHex = Hex.to64Hex(y);
            String publicKey = "04" + xHex + yHex;

            // 3. 提取私鑰原始值
            ECPrivateKey ecPriKey = (ECPrivateKey) keyPair.getPrivate();
            String privateKey = Hex.to64Hex(ecPriKey.getS()); //返回私鑰的標量值(大整數(shù))

            return new StrKeyPair(privateKey, publicKey);
        }

        public String getPriKey() {
            return this.priKey;
        }

        public String getPubKey() {
            return this.pubKey;
        }
    }

    public static class ECDH {
        private static final String CURVE_NAME = "secp256r1";
        /**
         * 生成密鑰對(返回hex格式)
         */
        public static StrKeyPair genKeyPair() throws Exception {
            // 1. 生成標準密鑰對
            ECGenParameterSpec ecSpec = new ECGenParameterSpec(CURVE_NAME);
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
            kpg.initialize(ecSpec, new SecureRandom());
            KeyPair keyPair = kpg.generateKeyPair();

            //轉換成Hex字符串的密鑰對
            return StrKeyPair.of(keyPair);
        }

        public static String derive(String myPriKey, String otherPubKey) throws Exception {
            PrivateKey myPrivateKey = toPrivateKey(myPriKey);
            PublicKey otherPublicKey = toPublicKey(otherPubKey);

            // 3. 執(zhí)行ECDH
            KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH");
            keyAgreement.init(myPrivateKey);
            keyAgreement.doPhase(otherPublicKey, true);

            // 4. 獲取共享密鑰(原始字節(jié))
            byte[] sharedSecret = keyAgreement.generateSecret();

            // 5. 返回hex
            return Hex.bytesToHex(sharedSecret);
        }

        /**
         * 將04+x+y格式的hex公鑰轉換為Java PublicKey
         */
        private static PublicKey toPublicKey(String pubKey) throws Exception {
            if (!pubKey.startsWith("04")) {
                throw new IllegalArgumentException("公鑰必須以04開頭");
            }else if(pubKey.length() !=  130){
                throw new IllegalArgumentException("公鑰格式有誤");
            }

            // 提取x, y坐標
            String xHex = pubKey.substring(2, 66), yHex = pubKey.substring(66, 130);
            BigInteger x = new BigInteger(xHex, 16), y = new BigInteger(yHex, 16);

            // 獲取曲線參數(shù)
            ECParameterSpec ecParams = getECParameterSpec();

            // 創(chuàng)建EC點
            ECPoint point = new ECPoint(x, y);

            // 創(chuàng)建公鑰規(guī)范
            ECPublicKeySpec keySpec = new ECPublicKeySpec(point, ecParams);
            KeyFactory keyFactory = KeyFactory.getInstance("EC");

            return keyFactory.generatePublic(keySpec);
        }

        /**
         * 將hex私鑰轉換為Java PrivateKey
         */
        private static PrivateKey toPrivateKey(String priKey) throws Exception {
            BigInteger s = new BigInteger(priKey, 16);

            // 獲取曲線參數(shù)
            ECParameterSpec ecParams = getECParameterSpec();

            // 創(chuàng)建私鑰規(guī)范
            ECPrivateKeySpec keySpec = new ECPrivateKeySpec(s, ecParams);
            KeyFactory keyFactory = KeyFactory.getInstance("EC");

            return keyFactory.generatePrivate(keySpec);
        }

        /**
         * 獲取橢圓曲線參數(shù)
         */
        private static ECParameterSpec getECParameterSpec() throws Exception {
            // 通過生成臨時密鑰對獲取曲線參數(shù)
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
            kpg.initialize(new ECGenParameterSpec(CURVE_NAME));
            KeyPair tempKeyPair = kpg.generateKeyPair();

            return ((ECPublicKey) tempKeyPair.getPublic()).getParams();
        }
    }

    //Base64工具類
    static class BASE64 {
        public static String encode(byte[] data) {
            return Base64.getEncoder().encodeToString(data);
        }

        public static byte[] decode(String base64Str) {
            return Base64.getDecoder().decode(base64Str);
        }
    }

    //AES加解密工具
    static class Aes {
        public static String  encrypt(String data, String key, String iv){
            AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, Hex.hexToBytes(key), Hex.hexToBytes(iv));
            return aes.encryptBase64(data);
        }
        public static String decrypt(String data, String key, String iv){
            AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, Hex.hexToBytes(key), Hex.hexToBytes(iv));
            return aes.decryptStr(BASE64.decode(data));
        }
    }

    public static void main(String[] args) throws Exception {
        // 生成密鑰對,只生成一次,將公鑰和前端共享
        //StrKeyPair strKeyPair = ECDH.genKeyPair();
        //04122670c45aa251ecef1528f76c248e288cd35dd728538764cbdaf3efa1c91bccc184daec61cc9abd660f947a530da82e3b4a76a07271d0d96a92660592722d39
        //System.out.println("服務端公鑰:" + strKeyPair.getPubKey());
        //9353c717bb2d65b5516e0e6c56fa7574592767d8abe70e796c1719e8f9d4d55b
        //System.out.println("服務端私鑰:" + strKeyPair.getPriKey());

        //服務端私鑰(需保密)
        String servPrivateKey = "9353c717bb2d65b5516e0e6c56fa7574592767d8abe70e796c1719e8f9d4d55b";
        //客戶端公鑰,來自前端請求參數(shù)
        String clientPublicKey = "04dd42dadd5d99539c15410aede7943a9c55ecb175d687feac37a602293e8a90fc76daa2d1d0186147628cb8ca24e86e7710b5e024e5a0d7ff55d0b342cf4f2d6e";
        //計算共享秘密(Aes 加密密鑰)
        String secret = ECDH.derive(servPrivateKey, clientPublicKey);
        System.out.println("共享秘密:"+ secret);

        //來自前端的向量iv和加密后的數(shù)據(jù)
        String iv = "34f5653b77a3b85db7826a40768d12a3";
        String encryptData = "pBkwIDR15BWS7xk2R5YPVmnXasrQpyybTq+C1N8/XTU=";

        //解密并輸出結果
        System.out.println("解密結果:"+Aes.decrypt(encryptData, secret, iv));
    }
}

6.2 前端代碼

<!doctype html>
<html>
  <head >
	<title>ECDH Test</title>
  </head>
  <body >
	  <div style="text-align: center">
		<div style = "margin-top:200px;display:flex;flex-direction: column;align-items: center;gap: 10px;">
		  <div style="width: 800px;display:flex;flex-direction: row">
			<div style="width:150px;text-align:right;margin-right:10px">服務端公鑰: </div>
			<textarea rows="3" cols="80" id="serv_pub_key_ipt" style="font-size: 20px"></textarea>
			<button id="compute" style="margin-left:20px">生成并計算共享密鑰</button>
		  </div>
		  <div style="width: 800px;display:flex;flex-direction: row">
			<div style="width:150px;text-align:right;margin-right:10px">本地公鑰: </div>
			<textarea rows="3" cols="80" id="pub_key_ipt" style="font-size: 20px"></textarea>
		  </div>
		  <div style="width: 800px;display:flex;flex-direction: row">
			<div style="width:150px;text-align:right;margin-right:10px">本地私鑰: </div>
			<textarea rows="3" cols="80" id="pri_key_ipt" style="font-size: 20px"></textarea>
		  </div>
		  <div style="width: 800px;display:flex;flex-direction: row">
			<div style="width:150px;text-align:right;margin-right:10px">共享秘密: </div>
			<textarea rows="3" cols="80" id="sheared_key_ipt" style="font-size: 20px; font-weight:bold"></textarea>
		  </div>
		  <div style="width: 800px;display:flex;flex-direction: row">
			<div style="width:150px;text-align:right;margin-right:10px">發(fā)送內容: </div>
			<textarea rows="3" cols="80" id="data_ipt" style="font-size: 20px"></textarea>
			<button id="do_encrypt" style="margin-left:20px">加密</button>
		  </div>
		  <div style="width: 800px;display:flex;flex-direction: row">
			<div style="width:150px;text-align:right;margin-right:10px">IV: </div>
			<textarea rows="1" cols="80" id="iv_ipt" style="font-size: 20px; font-weight:bold"></textarea>
		  </div>
		  <div style="width: 800px;display:flex;flex-direction: row">
			<div style="width:150px;text-align:right;margin-right:10px">加密結果: </div>
			<textarea rows="3" cols="80" id="encrypt_data_ipt" style="font-size: 20px; font-weight:bold"></textarea>
		  </div>
		</div>
	  </div>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> 
	<!-- ecdh用到的插件,生成密鑰對,計算共享秘密 -->
	<script src="https://cdnjs.cloudflare.com/ajax/libs/elliptic/6.6.1/elliptic.min.js"></script>
	<!-- 數(shù)據(jù)加密插件,需用到AES -->
	<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>
	<script>
		(function(){
			const EC = elliptic.ec;
			const ec = new EC('p256'); // 選擇橢圓曲線secp256k1的別名是p256
			//生成共享秘密
			$("#compute").on("click", function (){
			  const servPubKey = $("#serv_pub_key_ipt").val();
				if(servPubKey==null || !(servPubKey+"").trim()){
					alert("請先輸入服務端公鑰!");
					return;
				}
				const keyPair = ec.genKeyPair(); //生成密鑰對
				const priKey = keyPair.getPrivate("hex");
				const pubKey = keyPair.getPublic("hex");
				$("#pub_key_ipt").val(pubKey);
				$("#pri_key_ipt").val(priKey);
				const secret = derive(priKey, servPubKey);
				$("#sheared_key_ipt").val(secret);
			})
			//加密
			$("#do_encrypt").on("click", function(){
				const data = $("#data_ipt").val();
				if(data==null || !(data+"").trim()){
					alert("請先輸入發(fā)送內容!");
					return;
				}
				const secret = $("#sheared_key_ipt").val();
				if(secret==null || !(secret+"").trim()){
					alert("請先生成共享秘密!");
					return;
				}
			    const iv = generateIV();
				$("#iv_ipt").val(iv);
			    const encryptData = aesEncrypt(data, secret, iv);
				$("#encrypt_data_ipt").val(encryptData);
			})
			// 2. 使用對方公鑰和自己的私鑰生成共享密鑰
			function derive(myPriKey, otherPubKey) {
			  try {
				// 從十六進制字符串加載自己的私鑰
				const myPrivateKey = ec.keyFromPrivate(myPriKey, 'hex');
				// 從十六進制字符串加載對方的公鑰
				const otherPublicKey = ec.keyFromPublic(otherPubKey, 'hex').getPublic();
				// 計算共享密鑰
				const sharedSecret = myPrivateKey.derive(otherPublicKey);
				return sharedSecret.toString(16);
			  } catch (error) {
				console.error('生成共享密鑰失敗:', error);
				return null;
			  }
			}
			/**
			 * AES加密函數(shù)
			 * @param {string} plaintext - 明文
			 * @param {string} keyHex - 密鑰(64字符hex,對應32字節(jié))
			 * @param {string} ivHex - 初始向量(32字符hex,對應16字節(jié))
			 * @returns {string} Base64格式的加密結果
			 */
			function aesEncrypt(plaintext, keyHex, ivHex) {
				// 將hex字符串轉換為CryptoJS格式
				var key = CryptoJS.enc.Hex.parse(keyHex);
				var iv = CryptoJS.enc.Hex.parse(ivHex);
				// 執(zhí)行AES-256-CBC加密
				var encrypted = CryptoJS.AES.encrypt(plaintext, key, {
					iv: iv,
					mode: CryptoJS.mode.CBC,
					padding: CryptoJS.pad.Pkcs7
				});
				// 返回Base64字符串
				return encrypted.toString();
			}
			/**
			 * AES解密函數(shù)
			 * @param {string} ciphertextBase64 - Base64格式的密文
			 * @param {string} keyHex - 密鑰(64字符hex)
			 * @param {string} ivHex - 初始向量(32字符hex)
			 * @returns {string} 解密后的明文
			 */
			function aesDecrypt(ciphertextBase64, keyHex, ivHex) {
				// 將hex字符串轉換為CryptoJS格式
				var key = CryptoJS.enc.Hex.parse(keyHex);
				var iv = CryptoJS.enc.Hex.parse(ivHex);
				// 執(zhí)行AES-256-CBC解密
				var decrypted = CryptoJS.AES.decrypt(ciphertextBase64, key, {
					iv: iv,
					mode: CryptoJS.mode.CBC,
					padding: CryptoJS.pad.Pkcs7
				});
				// 轉換為UTF-8字符串
				return decrypted.toString(CryptoJS.enc.Utf8);
			}
			/**
			 * 生成隨機IV(16字節(jié))
			 * @returns {string} 32字符的hex IV
			 */
			function generateIV() {
				// 生成16字節(jié)隨機數(shù)
				var randomBytes = CryptoJS.lib.WordArray.random(16);
				// 轉換為hex字符串
				return randomBytes.toString(CryptoJS.enc.Hex);
			}
		})();
	</script>
  </body>
</html>

前端頁面

前端傳參

{
	"clientPublicKey": "04dd42dadd5d99539c15410aede7943a9c55ecb175d687feac37a602293e8a90fc76daa2d1d0186147628cb8ca24e86e7710b5e024e5a0d7ff55d0b342cf4f2d6e",
	"iv": "34f5653b77a3b85db7826a40768d12a3",
	"encryptData": "pBkwIDR15BWS7xk2R5YPVmnXasrQpyybTq+C1N8/XTU="
}

后端輸出

后端需接收前端的本地公鑰 + IV + 加密結果,然后計算出共享秘密,解密數(shù)據(jù)

共享秘密:f2e5a1b995524d818c9b6c5076e5bcace40641a6244f91dfe72b560f3723fc3d
解密結果:{"name":"張三","age":25}

到此這篇關于Java實現(xiàn)后端和前端的接口數(shù)據(jù)加密方案詳解的文章就介紹到這了,更多相關Java接口數(shù)據(jù)加密內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot整合Log4j2及配置步驟

    SpringBoot整合Log4j2及配置步驟

    這篇文章主要介紹了SpringBoot整合Log4j2以及配置詳解,刪除spring-boot-starter-parent默認使用spring-boot-starter-logging依賴,本文結合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-01-01
  • 基于idea Maven中的redis配置使用詳解

    基于idea Maven中的redis配置使用詳解

    這篇文章主要介紹了基于idea Maven中的redis配置使用,包括一些配置文件需要的內容,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2021-07-07
  • Java基于Swing實現(xiàn)的打獵射擊游戲代碼

    Java基于Swing實現(xiàn)的打獵射擊游戲代碼

    這篇文章主要介紹了Java基于Swing實現(xiàn)的打獵射擊游戲代碼,包含完整的游戲事件處理與邏輯流程控制,具有不錯的參考借鑒價值,需要的朋友可以參考下
    2014-11-11
  • java分析html算法(java網(wǎng)頁蜘蛛算法示例)

    java分析html算法(java網(wǎng)頁蜘蛛算法示例)

    近來有些朋友在做蜘蛛算法,或者在網(wǎng)頁上面做深度的數(shù)據(jù)挖掘,下面使用示例
    2014-03-03
  • 關于JpaRepository的關聯(lián)查詢和@Query查詢

    關于JpaRepository的關聯(lián)查詢和@Query查詢

    這篇文章主要介紹了JpaRepository的關聯(lián)查詢和@Query查詢,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • mybatis 多表關聯(lián)mapper文件寫法操作

    mybatis 多表關聯(lián)mapper文件寫法操作

    這篇文章主要介紹了mybatis 多表關聯(lián)mapper文件寫法操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 如何使用spring?boot的程序主線程中異步訪問外部接口

    如何使用spring?boot的程序主線程中異步訪問外部接口

    CompletableFuture.supplyAsync提供了一種強大的工具,使您能夠以異步方式執(zhí)行操作,充分利用多核處理器和提高程序性能,同時保持代碼的清晰性和可維護性,本文給大家介紹使用spring?boot的程序主線程中異步訪問外部接口,感興趣的朋友一起看看吧
    2023-10-10
  • 解決springmvc使用@PathVariable路徑匹配問題

    解決springmvc使用@PathVariable路徑匹配問題

    這篇文章主要介紹了解決springmvc使用@PathVariable路徑匹配問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java經(jīng)典排序算法之二分插入排序詳解

    Java經(jīng)典排序算法之二分插入排序詳解

    這篇文章主要為大家詳細介紹了Java經(jīng)典排序算法之二分插入排序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • springboot項目mapper無法自動裝配未找到?UserMapper?類型的Bean解決辦法

    springboot項目mapper無法自動裝配未找到?UserMapper?類型的Bean解決辦法

    這篇文章給大家介紹了springboot項目mapper無法自動裝配,未找到?‘userMapper‘?類型的?Bean解決辦法(含報錯原因),文章通過圖文結合的方式介紹的非常詳細,具有一定的參考價值,需要的朋友可以參考下
    2024-02-02

最新評論

阳江市| 江城| 靖宇县| 朝阳县| 南宁市| 禹州市| 尚义县| 什邡市| 南溪县| 绍兴市| 承德县| 靖州| 富阳市| 札达县| 南汇区| 吉水县| 黎川县| 宁夏| 吕梁市| 南靖县| 称多县| 双鸭山市| 永康市| 安多县| 元朗区| 武乡县| 湟中县| 临洮县| 香港| 孟州市| 通道| 永寿县| 莫力| 诸暨市| 大连市| 东明县| 仁布县| 五寨县| 仙游县| 乌鲁木齐县| 绍兴市|