SOP頁面跳轉設計 RAS AES加密演算法應用跨服務免登陸介面設計

oktokeep發表於2024-05-22

SOP頁面跳轉設計 RAS AES加密演算法應用跨服務免登陸介面設計

SOP,是 Standard Operating Procedure三個單詞中首字母的大寫 ,即標準作業程式,指將某一事件的標準操作步驟和要求以統一的格式描述出來,用於指導和規範日常的工作。

加密/加簽過程:
1.動態隨機生成AES金鑰aesKey,而不是靜態的AES金鑰。提高安全性。
2.使用該AES對傳輸的介面資料data加密。 比如:username=AES(username原文,aesKey)&age=AES(age原文,aesKey)
3.使用RSA公鑰對aesKey加密,作為引數傳遞 prikey=RSA(aeskey,公鑰)

以上完整的路徑:http://IP地址+埠/path?username=AES(username,aesKey)&age=AES(age,aesKey)&prikey=RSA(aeskey,公鑰)

解密/解簽過程:
1.先用私鑰從prikey解密獲取aesKey
2.用aesKey解密username,age獲得username原文,age原文

* Invalid AES key length: 33 bytes
*
* 如果未指定init LEN,則根據引數的key自適應。AES KEY長度為 16位,24位,32位。
* 否則可以指定AES KEY長度
* // KeyGenerator kgen = KeyGenerator.getInstance(TYPE);
* // //Wrong keysize: must be equal to 128, 192 or 256
* // kgen.init(LEN); //128 / 8 = 16
*
* 經過測試發現:
* keysize: must be equal to 128, 192 or 256
* aes key長度 16,24,32
* 以上的兩個條件相互都成立,而不是如下的第一組,第二組,第三組的強制配對。

DEMO程式碼示例:

package com.example.core.mydemo.spi;

import com.alibaba.fastjson.JSONObject;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Date;

/**
 * Invalid AES key length: 33 bytes
 *
 * 如果未指定init LEN,則根據引數的key自適應。AES KEY長度為 16位,24位,32位。
 * 否則可以指定AES KEY長度
 * //        KeyGenerator kgen = KeyGenerator.getInstance(TYPE);
 * //        //Wrong keysize: must be equal to 128, 192 or 256
 * //        kgen.init(LEN);  //128 / 8 = 16
 *
 * 經過測試發現:
 * keysize: must be equal to 128, 192 or 256
 * aes key長度 16,24,32
 * 以上的兩個條件相互都成立,而不是如下的第一組,第二組,第三組的強制配對。
 */
public class AesUtil {

    //演算法
    private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
    //金鑰 (靜態aesKey)
    //第一組
    public static final String KEY = "9862ecf540c64534";
//    public static final String KEY = "yyyyyyyyyyyyyyyy";  //16位
    //
    private static final Integer LEN = 128;

    //第二組
//    public static final String KEY = "yyyyyyyyyyyyyyyy91a1e003c11b414e";  //32位
//    private static final Integer LEN = 256;

    //第三組
//    public static final String KEY = "yyyyyyyyyyyyyyyy91a1e003";  //24位
//    private static final Integer LEN = 192;

    // 加密型別
    private static final String TYPE = "AES";

    /**
     * aes加密 - 靜態aesKey
     *
     * @param content
     * @return
     * @throws Exception
     */
    public static String aesEncrypt(String content) {
        try {
            return aesEncrypt(content, KEY);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * aes解密 - 靜態aesKey
     *
     * @param encrypt 內容
     * @return
     * @throws Exception
     */
    public static String aesDecrypt(String encrypt) {
        try {
            return aesDecrypt(encrypt, KEY);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 將base 64 code AES解密
     *
     * @param encryptStr 待解密的base 64 code
     * @param decryptKey 解密金鑰
     * @return 解密後的string
     * @throws Exception
     */
    public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
        return isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
    }

    /**
     * AES解密
     *
     * @param encryptBytes 待解密的byte[]
     * @param decryptKey   解密金鑰
     * @return 解密後的String
     * @throws Exception
     */
    public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance(TYPE);
        //Wrong keysize: must be equal to 128, 192 or 256
        kgen.init(LEN);

        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), TYPE));
        byte[] decryptBytes = cipher.doFinal(encryptBytes);
        return new String(decryptBytes);
    }

    /**
     * base 64 decode
     *
     * @param base64Code 待解碼的base 64 code
     * @return 解碼後的byte[]
     * @throws Exception
     */
    public static byte[] base64Decode(String base64Code) throws Exception {
        return isEmpty(base64Code) ? null : Base64.getDecoder().decode(base64Code);
    }



    /**
     * AES加密為base 64 code
     *
     * @param content    待加密的內容
     * @param encryptKey 加密金鑰
     * @return 加密後的base 64 code
     * @throws Exception
     */
    public static String aesEncrypt(String content, String encryptKey) throws Exception {
        return base64Encode(aesEncryptToBytes(content, encryptKey));
    }

    /**
     * base 64 encode
     *
     * @param bytes 待編碼的byte[]
     * @return 編碼後的base 64 code
     */
    public static String base64Encode(byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes);
    }

    /**
     * AES加密
     *
     * @param content    待加密的內容
     * @param encryptKey 加密金鑰
     * @return 加密後的byte[]
     * @throws Exception
     */
    public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance(TYPE);
        //Wrong keysize: must be equal to 128, 192 or 256
        kgen.init(LEN);  //128 / 8 = 16

        Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), TYPE));
        return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 將byte[]轉為各種進位制的字串
     *
     * @param bytes byte[]
     * @param radix 可以轉換進位制的範圍,從Character.MIN_RADIX到Character.MAX_RADIX,超出範圍後變為10進位制
     * @return 轉換後的字串
     */
    public static String binary(byte[] bytes, int radix) {
        return new BigInteger(1, bytes).toString(radix);// 這裡的1代表正數
    }

    public static boolean isEmpty(CharSequence cs) {
        return cs == null || cs.length() == 0;
    }
    
    /**
     * 測試
     * output:
     * 對比:RASPublicAuthUtil.java輸出結果  對比一致
     * username AES加密後的資料:wG2GS4DxYko57DoL0kAAWA%3D%3D
     * username解碼:wG2GS4DxYko57DoL0kAAWA==
     *
     *encrypt=wG2GS4DxYko57DoL0kAAWA==
     * encodeEncrypt=wG2GS4DxYko57DoL0kAAWA%3D%3D
     * decrypt=admin
     *
     */
    public static void main(String[] args) throws Exception {
//        JSONObject jsonObject = new JSONObject();
//        jsonObject.put("ticketId", "8310000002021051115277C");
//        jsonObject.put("serviceItemId", "100000000708");
//        jsonObject.put("timestamp", new Date());
//        System.out.println("json data=" + jsonObject.toJSONString());
//        String encrypt = aesEncrypt(jsonObject.toJSONString());
        //aes加密
        String encrypt = aesEncrypt("admin");
        System.out.println("encrypt=" + encrypt);
        //aes編碼
        String encodeEncrypt = URLEncoder.encode(encrypt, "UTF-8");
        System.out.println("encodeEncrypt=" + encodeEncrypt);

        //aes解密
        String decodeEncrypt = URLDecoder.decode(encodeEncrypt,"UTF-8");
        String decrypt = aesDecrypt(decodeEncrypt);
        System.out.println("decrypt=" + decrypt);
    }
}
     

package com.example.core.mydemo.spi;

import com.alibaba.fastjson.JSONObject;

import javax.crypto.Cipher;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.UUID;

/**
 **/
public class RSAPublicAuthUtil {

    // Base64解密
    private static final Base64.Decoder decoder = Base64.getDecoder();
    // Base64加密
    private static final Base64.Encoder encoder = Base64.getEncoder();
    
    /**
     * 非對稱金鑰演算法
     */
    public static final String KEY_ALGORITHM = "RSA";

    /**
     * 公鑰
     */
    private static final String PUBLIC_KEY = "可以使用支付寶開放平臺開發助手.exe工具生成";
    /**
     * 私鑰
     */
    private static final String PRIVATE_KEY = "可以使用支付寶開放平臺開發助手.exe工具生成";

    /**
     * @param data
     * @throws
     * @Description:
     * @return: java.lang.String
     * @Author: MeiQi
     * @Date: 2021/7/12 20:50
     **/
    public static String encryptByPublicKey(String data)throws Exception {
        byte[] key_byte = decoder.decode(PUBLIC_KEY);
        byte[] encrypt_str = encryptByPublicKey(decoder.decode(data), key_byte);
        return encoder.encodeToString(encrypt_str);
    }

    /**
     * @param data  待加密資料
     * @param key   金鑰
     * @throws
     * @Description:    公鑰加密
     * @return: byte[]  加密資料
     * @Author: MeiQi
     * @Date: 2021/7/12 20:51
     **/
    private static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
        //例項化金鑰工廠
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //初始化公鑰
        //金鑰材料轉換
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        //產生公鑰
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
        //資料加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return cipher.doFinal(data);
    }

    /**
     * 私鑰解密
     * @param secretText    待解密的密文字串
     * @return 解密後的明文
     */
    public static String decryptByPrivateKey(String secretText) {
        try {
            String privateKeyStr = PRIVATE_KEY;
            String input_charset = "UTF-8";
            // 生成私鑰
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKeyStr));
            // 密文解碼
            byte[] secretTextDecoded = decoder.decode(secretText);
            byte[] tempBytes = cipher.doFinal(secretTextDecoded);
//            return new String(tempBytes);
            return encoder.encodeToString(tempBytes);
        } catch (Exception e) {
            throw new RuntimeException("解密字串[" + secretText + "]時遇到異常", e);
        }
    }

    /**
     * 得到私鑰
     * @param key 金鑰字串(經過base64編碼)
     * @throws Exception
     */
    private static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = decoder.decode(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }


    /**
     * output:
     * 公鑰:~~
     * 原文:admin
     * 原文:25
     * aesKey:9862ecf540c64534
     * username AES加密後的資料:wG2GS4DxYko57DoL0kAAWA%3D%3D
     * age AES加密後的資料:NUjk8UtCDZq7U8HhRNixNQ%3D%3D
     * 使用公鑰加密prikey後的資料:NJ2dUzqqUwzcrYqV5GX0xKDo9eBuC1hjvTUAmtZmC9xoTX7nc0JhEErO2AZRyCS47Bc6CZi68MWSKsBt9bNxIfkY3ciGWOxSgHNhOVpWM8wEjWb6q%2BNcoLV9p7wapdur43v3jdcGFhzD0ugmDMiTPhCPfp0Dz3s9qTZD6rN1uc0%3D
     * http://localhost:8010/#/index?&username=wG2GS4DxYko57DoL0kAAWA%3D%3D&age=NUjk8UtCDZq7U8HhRNixNQ%3D%3D&prikey=NJ2dUzqqUwzcrYqV5GX0xKDo9eBuC1hjvTUAmtZmC9xoTX7nc0JhEErO2AZRyCS47Bc6CZi68MWSKsBt9bNxIfkY3ciGWOxSgHNhOVpWM8wEjWb6q%2BNcoLV9p7wapdur43v3jdcGFhzD0ugmDMiTPhCPfp0Dz3s9qTZD6rN1uc0%3D
     * prikey解碼:NJ2dUzqqUwzcrYqV5GX0xKDo9eBuC1hjvTUAmtZmC9xoTX7nc0JhEErO2AZRyCS47Bc6CZi68MWSKsBt9bNxIfkY3ciGWOxSgHNhOVpWM8wEjWb6q+NcoLV9p7wapdur43v3jdcGFhzD0ugmDMiTPhCPfp0Dz3s9qTZD6rN1uc0=
     * prikey解密:9862ecf540c64534
     * username解碼:wG2GS4DxYko57DoL0kAAWA==
     * username解密:admin
     * age解碼:NUjk8UtCDZq7U8HhRNixNQ==
     * age解密:25
     */

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        //傳送端
        System.out.println("公鑰:" + PUBLIC_KEY);
        String username = "admin";
        System.out.println("原文:" + username);
        String age = "25";
        System.out.println("原文:" + age);


        String nonceStr = UUID.randomUUID().toString().replace("-", "");
        String aesKey = nonceStr.substring(0, 16);
        System.out.println("aesKey:" + aesKey);

        username = AesUtil.aesEncrypt(username, aesKey);
        username = URLEncoder.encode(username, "UTF-8");
        System.out.println("username AES加密後的資料:" + username);

        age = AesUtil.aesEncrypt(age, aesKey);
        age = URLEncoder.encode(age, "UTF-8");
        System.out.println("age AES加密後的資料:" + age);


        //傳送端進行資料的加密
        String prikey = RSAPublicAuthUtil.encryptByPublicKey(aesKey);
        prikey = URLEncoder.encode(prikey, "UTF-8");
        System.out.println("使用公鑰加密prikey後的資料:" + prikey);
        
        String base_url = "http://localhost:8010/#/index?";
        System.out.println(base_url.concat("&username=").concat(username).concat("&age=").concat(age).concat("&prikey=").concat(prikey));

        //接收端
        prikey = URLDecoder.decode(prikey,"UTF-8");
        System.out.println("prikey解碼:" + prikey);
        String decryAes = RSAPublicAuthUtil.decryptByPrivateKey(prikey);
        System.out.println("prikey解密:" + decryAes);

        username = URLDecoder.decode(username,"UTF-8");
        System.out.println("username解碼:" + username);
        String decryUsernameStr = AesUtil.aesDecrypt(username,decryAes);
        System.out.println("username解密:" + decryUsernameStr);

        age = URLDecoder.decode(age,"UTF-8");
        System.out.println("age解碼:" + age);
        String decryAgeStr = AesUtil.aesDecrypt(age,decryAes);
        System.out.println("age解密:" + decryAgeStr);

    }
}

相關文章