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工具生成