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); } }