SOP页面跳转设计 RAS AES加密算法应用跨服务免登陆接口设计
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); } }
RSA公私钥生成可以使用支付宝开放平台开发助手.exe工具生成