前后端交互
- 通信请求使用https
- 对请求参数进行签名,防止数据篡改
- 对请求参数以及响应数据进行加解密
- app中使用ssl pinning防止抓包操作
https协议
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-78n9M2PH-1677252127361)(安全.assets/https加密流程.jpg)]
签名参数
加签和验签:发送方将请求参数通过加密算法生成一个sign值,放到请求参数里;接收方收到请求后,使用同样的方式对请求参数进行加密得到一个sign值,只要两个sign值相同,就说明参数没有被篡改。
加签操作步骤:
- 将所有参数(除了sign本身,以及值是空的参数)按参数键字母升序排序。
- 然后把排序后的参数按 参数1值1 参数2值2 … 参数n值n 的方式拼接成一个字符串。
- 在上一步得到的字符串前面加上密钥key,然后计算md5值,得到32位字符串,然后转成大写,得到的字符串作为sign的值放到请求参数里。
验签操作步骤:
同 加签操作步骤
现在假设需要传输的数据:/guest/rechargeNotify?p2=v2&p1=v1&method=cancel&p3=&pn=vn(实际情况最好是通过post方式发送)
- 拼接字符串,首先去除值是空的参数p3,剩下p2=v2&p1=v1&method=cancel&pn=vn,然后按参数名字符升序排序得到字符串:method=cancel&p1=v1&p2=v2&pn=vn。
- 然后做参数名和值的拼接,最后得到methodcancelp1v1p2v2pnvn。
- 在上面拼接得到的字符串前面加上验证密钥key,假设是abc,得到新的字符串abcmethodcancelp1v1p2v2pnvn。
- 将上面得到的字符串进行md5计算,假设得到的是abcdef,然后转为大写,得到ABCDEF这个值即为sign签名值。最终产生的url应该如下:/guest/rechargeNotify?p2=v2&p1=v1&method=cancel&p3=&pn=vn&sign=ABCDEF
MD5加密:
public String getSignMD5(String param, String sign) {
StringBuffer str = new StringBuffer(sign);
if(StringUtils.isNotEmpty(param)){
JSONObject obj = JSONObject.parseObject(param);
List<String> keys = new ArrayList<String>(obj.keySet());
keys.remove(ApiSignUtil.SIGN);
Collections.sort(keys);
for (String key : keys) {
Object value = obj.get(key);
if (value == null) {
value = "";
}
str.append(value);
}
}
return getMd5(str.toString());
}
public String getMd5(String plainText) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(plainText.getBytes());
byte[] b = md.digest();
StringBuilder buf = new StringBuilder();
byte[] var5 = b;
int var6 = b.length;
for(int var7 = 0; var7 < var6; ++var7) {
byte aB = var5[var7];
int i = aB;
if (aB < 0) {
i = aB + 256;
}
if (i < 16) {
buf.append("0");
}
buf.append(Integer.toHexString(i));
}
return buf.toString();
} catch (NoSuchAlgorithmException var9) {
var9.printStackTrace();
return "";
}
}
加解密请求响应数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bfRrbNux-1677252127362)(安全.assets/1648114154350.png)]
前后端交互常用的通信加密方案:
客户端:
- 生成AES密钥,并保存AES密钥;
- 用AES密钥对请求传输数据进行加密;
- 使用RSA公钥对AES密钥加密,然后把值放到自定义的请求头;
- 向服务器发起请求;
服务端:
- 拿到自定义的请求头,用RSA私钥解密,得到AES密钥;
- 使用AES密钥对请求数据进行解密;
- 使用AES密钥对响应数据进行加密;
- 向客户端发送响应;
AES对称加密
AES加解密总共有以下这些
算法/模式/填充 字节加密后数据长度 不满16字节加密后长度
AES/CBC/NoPadding 16 不支持
AES/CBC/PKCS5Padding 32 16
AES/CBC/ISO10126Padding 32 16
AES/CFB/NoPadding 16 原始数据长度
AES/CFB/PKCS5Padding 32 16
AES/CFB/ISO10126Padding 32 16
AES/ECB/NoPadding 16 不支持
AES/ECB/PKCS5Padding 32 16
AES/ECB/ISO10126Padding 32 16
AES/OFB/NoPadding 16 原始数据长度
AES/OFB/PKCS5Padding 32 16
AES/OFB/ISO10126Padding 32 16
AES/PCBC/NoPadding 16 不支持
AES/PCBC/PKCS5Padding 32 16
AES/PCBC/ISO10126Padding 32 16
AES/ECB
- 不带模式和填充来获取AES算法的时候,其默认使用AES/ECB/PKCS5Padding(输入可以不是16字节,也不需要向量)
Cipher cipher = Cipher.getInstance("AES");
AES/ECB/PKCS5Padding
String content = "在线助手";
// 生成密钥需要的密码值
String key = "www.it399.com";
/**
* AES加密方式一:AES不指定模式和填充,默认为 ECB/PKCS5Padding
*
* 不能使用填充向量
* java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
*/
System.out.println("【0】AES不指定模式和填充,默认为 ECB/PKCS5Padding,输入可以不是16字节,也不需要填充向量\n");
//128
byte[] encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_DEFAULT);
encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_DEFAULT);
//192
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_DEFAULT);
encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_DEFAULT);
//256
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_DEFAULT);
encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_DEFAULT);
AES/CBC
- 输入必须是16字节,不然报错 javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
- CBC模式必须提供初始向量IvParameterSpec,不然报错 java.security.InvalidKeyException: Parameters missing
content: 在线助手
key: www.it399.com111
javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1041)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:1009)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at com.csy.spring.it399.controller.encode.aes.AESUtil.encrypt(AESUtil.java:80)
at com.csy.spring.it399.controller.encode.aes.AESUtil.main(AESUtil.java:200)
java.security.InvalidKeyException: Parameters missing
at com.sun.crypto.provider.CipherCore.init(CipherCore.java:470)
at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:313)
at javax.crypto.Cipher.implInit(Cipher.java:802)
at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
at javax.crypto.Cipher.init(Cipher.java:1249)
at javax.crypto.Cipher.init(Cipher.java:1186)
at com.csy.spring.it399.controller.encode.aes.AESUtil.decrypt(AESUtil.java:117)
at com.csy.spring.it399.controller.encode.aes.AESUtil.main(AESUtil.java:202)
encode: null
decode: null
初始化加密模式的时改成
Cipher cipher = Cipher.getInstance(“AES/CBC/NoPadding”);
java.security.InvalidKeyException: Parameters missing解决办法:
if (modeAndPadding.equals(EncodeType.AES_CBC_NoPadding)) {
//指定一个初始化向量 (Initialization vector,IV), IV 必须是16位
cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(getIV()));
} else {
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
}
AES/CBC/NoPadding, AES/CBC/PKCS5Padding, AES/CBC/ISO10126Padding
/**
* 1.1 AES/CBC
* AES/CBC/NoPadding
* AES/CBC/PKCS5Padding
* AES/CBC/ISO10126Padding
*/
System.out.println("【1.1】AES_CBC_NoPadding模式");
content = "在线助手在线助手在线助手在线助手";
key = "www.it399.com";
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
AES/CFB
-
需要向量,不然报如下错误
java.security.InvalidKeyException: Parameters missing
-
AES/CFB/NoPadding,AES/CFB/PKCS5Padding,AES/CFB/ISO10126Padding
/** * 1.2 AES/CFB * AES/CBC/NoPadding * AES/CBC/PKCS5Padding * AES/CBC/ISO10126Padding */ System.out.println("【1.2】AES_CFB_NoPadding模式\n"); content = "在线助手"; // 生成密钥需要的密码值 key = "https://www.it399.com"; encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding); encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding); encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding); encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding); encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding); encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
AES/ECB
-
AES/ECB不要填充变量,不然会报如下错误
java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
AES/ECB/NoPadding,AES/ECB/PKCS5Padding,AES/ECB/ISO10126Padding
/**
* 1.3 AES/ECB
* AES/ECB/NoPadding
* AES/ECB/PKCS5Padding
* AES/ECB/ISO10126Padding
*/
System.out.println("【1.3】AES_ECB模式");
content = "在线助手";
// 生成密钥需要的密码值
key = "https://www.it399.com";
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_ECB_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_ECB_PKCS5Padding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_ECB_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_ECB_PKCS5Padding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_ECB_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_ECB_PKCS5Padding);
完整代码
AESUtil .java文章来源:https://www.toymoban.com/news/detail-774867.html
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* 在线助手|在线工具|在线生成|在线制作
* https://www.it399.com/
* 在线助手博客
* https://www.it399.com/blog/index
*/
public class AESUtil {
public static final String CHARSET = "UTF-8";
private static byte[] encryptOrDecrypt(int mode,byte[] byteContent, String key,byte[] iv, AESType type, String modeAndPadding) throws InvalidKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
//此处解决mac,linux报错
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(key.getBytes());
kgen.init(type.value, random);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec keySpec = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance(modeAndPadding);// 创建密码器
if ( null !=iv ) {
//指定一个初始化向量 (Initialization vector,IV), IV 必须是16位
cipher.init(mode, keySpec, new IvParameterSpec(iv));
} else {
cipher.init(mode, keySpec);
}
byte[] result = cipher.doFinal(byteContent);
return result;
}
public static void main(String[] args) throws Exception {
// System.out.println("【1】AES不指定模式和填充,默认为 ECB/PKCS5Padding,输入可以不是16字节,也不需要填充向量\n");
// // 需要加密的内容
// String content = "在线助手";
// // 生成密钥需要的密码值
// String key = "www.it399.com111";
// System.out.println("content: " + content + "\nkey: " + key);
// byte[] encodeByte;
// byte[] decodeByte;
// //默认方式 每次加密都不一样,但是秘钥是一样的,所以解密还是一样的
// // 内容加密后的值
// encodeByte = encrypt(content.getBytes(CHARSET), key, AESType.AES_128, EncodeType.AES_DEFAULT);
// String encodeStr = TypeConvert.bytesToHexString(encodeByte);
// // 被加密的内容解密后的值
// decodeByte = decrypt(encodeByte, key, AESType.AES_128, EncodeType.AES_DEFAULT);
// String decodeStr = new String(decodeByte,CHARSET);
// System.out.println("encode: " + encodeStr + "\ndecode: " + decodeStr);
//
//
// System.out.println("【2】AES_CBC_NoPadding模式,输入必须是16*n字节,需要填充向量\n");
// // 内容加密后的值
// //待加密内容不足16*n位 报错javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
// //需要填充向量,不然报错java.security.InvalidKeyException: Parameters missing
// //得到加密后的内容先base64编码再解码再传给解码,不然直接转回乱码
// content = "哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈";
// encodeByte = encrypt(content.getBytes(CHARSET), key, AESType.AES_256, EncodeType.AES_CBC_NoPadding);
// encodeStr = TypeConvert.bytesToHexString(encodeByte);
// decodeByte = decrypt(TypeConvert.hexStringToBytes(encodeStr), key, AESType.AES_256, EncodeType.AES_CBC_NoPadding);
// decodeStr = new String(decodeByte,CHARSET);
// System.out.println("encode: " + encodeStr + "\ndecode: " + decodeStr);
String content = "在线助手";
// 生成密钥需要的密码值
String key = "www.it399.com";
byte[] encrypt;
/**
* AES加密方式一:AES不指定模式和填充,默认为 ECB/PKCS5Padding
*/
// System.out.println("【0】AES不指定模式和填充,默认为 ECB/PKCS5Padding,输入可以不是16字节,也不需要填充向量\n");
// //128
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_DEFAULT);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_DEFAULT);
// //192
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_DEFAULT);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_DEFAULT);
// //256
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_DEFAULT);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_DEFAULT);
// /**
// * 1.1 AES/CBC (需要填充向量16*n)
// * AES/CBC/NoPadding
// * AES/CBC/PKCS5Padding
// * AES/CBC/ISO10126Padding
// */
// System.out.println("【1.1】AES_CBC_NoPadding模式,需要填充向量,待加密必须是16*n");
// content = "在线助手在线助手在线助手在线助手";
// key = "www.it399.com";
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
// /**
// * 1.2 AES/CFB
// * AES/CBC/NoPadding
// * AES/CBC/PKCS5Padding
// * AES/CBC/ISO10126Padding
// */
// System.out.println("【1.2】AES_CFB_NoPadding模式\n");
// content = "在线助手";
// // 生成密钥需要的密码值
// key = "https://www.it399.com";
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
// /**
// * 1.2 AES/ECB
// * AES/ECB/NoPadding
// * AES/ECB/PKCS5Padding
// * AES/ECB/ISO10126Padding
// */
// System.out.println("【1.3】AES_ECB模式");
// content = "在线助手";
// // 生成密钥需要的密码值
// key = "https://www.it399.com";
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_ECB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_ECB_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_ECB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_ECB_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_ECB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_ECB_PKCS5Padding);
/**
* 1.4 AES/OFB
* AES/OFB/NoPadding
* AES/OFB/PKCS5Padding
* AES/OFB/ISO10126Padding
*/
System.out.println("【1.4】AES_OFB模式");
content = "在线助手";
// 生成密钥需要的密码值
key = "https://www.it399.com";
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_OFB_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_OFB_PKCS5Padding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_OFB_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_OFB_PKCS5Padding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_OFB_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_OFB_PKCS5Padding);
/**
* 1.5 AES/PCBC
* AES/PCBC/NoPadding
* AES/PCBC/PKCS5Padding
* AES/PCBC/ISO10126Padding
*/
System.out.println("【1.5】AES_PCBC模式");
content = "在线助手";
// 生成密钥需要的密码值
key = "https://www.it399.com";
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_PCBC_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_PCBC_PKCS5Padding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_PCBC_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_PCBC_PKCS5Padding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_PCBC_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_PCBC_PKCS5Padding);
//
// /**1.3 AES/CBC
// * AES_CBC_NoPadding模式(填充向量可选)
// */
System.out.println("【1.3】AES_CBC_NoPadding模式");
content = "在线助手在线助手在线助手在线助手";
// 生成密钥需要的密码值
key = "www.it399.com";
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
content = "在线助手";
// 生成密钥需要的密码值
key = "www.it399.com";
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
//
//
//
// /**
// * 2.1 AES/CFB 128/192/256位加解密
// * AES_CFB_NoPadding模式(填充向量可选)
// */
// System.out.println("【2.1】AES_CFB_NoPadding模式,需要填充向量\n");
// content = "在线助手";
// // 生成密钥需要的密码值
// key = "www.it399.com";
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_CFB_NoPadding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_CFB_NoPadding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_CFB_NoPadding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_CFB_NoPadding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_CFB_NoPadding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_CFB_NoPadding);
//
// /**
// * 2.2 AES/CFB
// * AES_CFB_NoPadding模式(填充向量可选)
// */
// System.out.println("【2.2】AES_CFB_NoPadding模式\n");
// content = "在线助手";
// // 生成密钥需要的密码值
// key = "www.it399.com";
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
//
// /**2.3 AES/CFB
// * AES_CFB_NoPadding模式(填充向量可选)
// */
// System.out.println("【2.3】AES_CFB_NoPadding模式\n");
// content = "在线助手";
// // 生成密钥需要的密码值
// key = "www.it399.com";
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_CFB_ISO10126Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_CFB_ISO10126Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_CFB_ISO10126Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_CFB_ISO10126Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_CFB_ISO10126Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_CFB_ISO10126Padding);
}
/**
*
* @param isEncrypt
* @param source
* @param key
* @param type
* @param encodeType
*/
public static byte[] encryptOrdecrypt(boolean isEncrypt,byte[] source,String key,byte[] iv,AESType type,String encodeType) throws UnsupportedEncodingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {
if (isEncrypt){
byte[] encodeByte = encryptOrDecrypt(Cipher.ENCRYPT_MODE,source,key,iv,type,encodeType);
String encodeStr = TypeConvert.bytesToHexString(encodeByte);
return encodeByte;
}else{
byte[] decodeByte = encryptOrDecrypt(Cipher.DECRYPT_MODE,source, key,iv,type, encodeType);
String decodeStr = new String(decodeByte,CHARSET);
return decodeByte;
}
}
/**
* 指定一个初始化向量 (Initialization vector,IV),IV 必须是16位
*/
public static final byte[] getIV() throws Exception {
return "1234567812345678".getBytes(CHARSET);
}
EncodeType文章来源地址https://www.toymoban.com/news/detail-774867.html
/**
* 在线助手|在线工具|在线生成|在线制作
* https://www.it399.com/
* 在线助手博客
* https://www.it399.com/blog/index
*/
public class EncodeType {
// 算法/模式/填充 16字节加密后数据长度 不满16字节加密后长度
// AES/CBC/NoPadding 16 不支持
// AES/CBC/PKCS5Padding 32 16
// AES/CBC/ISO10126Padding 32 16
// AES/CFB/NoPadding 16 原始数据长度
// AES/CFB/PKCS5Padding 32 16
// AES/CFB/ISO10126Padding 32 16
// AES/ECB/NoPadding 16 不支持
// AES/ECB/PKCS5Padding 32 16
// AES/ECB/ISO10126Padding 32 16
// AES/OFB/NoPadding 16 原始数据长度
// AES/OFB/PKCS5Padding 32 16
// AES/OFB/ISO10126Padding 32 16
// AES/PCBC/NoPadding 16 不支持
// AES/PCBC/PKCS5Padding 32 16
// AES/PCBC/ISO10126Padding 32 16
//默认为 ECB/PKCS5Padding
public final static String AES_DEFAULT = "AES";
public final static String AES_CBC_NoPadding = "AES/CBC/NoPadding";
public final static String AES_CBC_PKCS5Padding = "AES/CBC/PKCS5Padding";
public final static String AES_CBC_ISO10126Padding = "AES/CBC/ISO10126Padding";
public final static String AES_CFB_NoPadding = "AES/CFB/NoPadding";
public final static String AES_CFB_PKCS5Padding = "AES/CFB/PKCS5Padding";
public final static String AES_CFB_ISO10126Padding = "AES/CFB/ISO10126Padding";
public final static String AES_ECB_NoPadding = "AES/ECB/NoPadding";
public final static String AES_ECB_PKCS5Padding = "AES/ECB/PKCS5Padding";
public final static String AES_ECB_ISO10126Padding = "AES/ECB/ISO10126Padding";
public final static String AES_OFB_NoPadding = "AES/OFB/NoPadding";
public final static String AES_OFB_PKCS5Padding = "AES/OFB/PKCS5Padding";
public final static String AES_OFB_ISO10126Padding = "AES/OFB/ISO10126Padding";
public final static String AES_PCBC_NoPadding = "AES/PCBC/NoPadding";
public final static String AES_PCBC_PKCS5Padding = "AES/PCBC/PKCS5Padding";
public final static String AES_PCBC_ISO10126Padding = "AES/PCBC/ISO10126Padding";
}
另附代码
package net.trueland.employee.common;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.JSONObject;
public class SecurityUtils {
public static final String ALGORITHM_AES = "AES";
public static final String CHARSET_UTF8 = "UTF-8";
/**
* 参数加签
* @param json 参数,仅支持json对象
* @param key 密钥
* @return 密文
*/
public static String signParam(String json, String key) throws Exception {
if (StringUtils.isBlank(json)) {
return StringUtils.EMPTY;
}
if (StringUtils.isBlank(key)) {
throw new Exception("param add sign error: no key");
}
StringBuffer stringBuffer = new StringBuffer(key);
JSONObject jsonObject = JSONObject.parseObject(json);
List<String> keyList = new ArrayList<String>(jsonObject.keySet());
keyList.remove("sign");
Collections.sort(keyList);
for (String s : keyList) {
Object o = jsonObject.get(s);
if (o == null) {
o = "";
}
stringBuffer.append(s);
stringBuffer.append(o);
}
return stringBuffer.toString();
}
/**
* md5 加密
* @param str 明文
* @return
*/
public static String encryptMD5(String str) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
// TODO 异常处理
}
md.update(str.getBytes());
byte[] b = md.digest();
StringBuilder buf = new StringBuilder();
byte[] var5 = b;
int var6 = b.length;
for (int var7 = 0; var7 < var6; ++var7) {
byte aB = var5[var7];
int i = aB;
if (aB < 0) {
i = aB + 256;
}
if (i < 16) {
buf.append("0");
}
buf.append(Integer.toHexString(i));
}
return buf.toString();
}
// ------------------------------------------AES/ECB/PKCS5Padding加解密, AES默认的加密方式--------------------------------------------------
/**
* 加密速度快
* 该模式不可以使用向量,否则报错:java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
* @param plaintext 明文
* @param key 密钥 不强制位数
* @return 密文
*/
public static String encrypt(String plaintext, String key) throws Exception {
return encryptOrDecrypt(Cipher.ENCRYPT_MODE, plaintext, key, null, "AES/ECB/PKCS5Padding");
}
/**
* 加密速度快
* 该模式不可以使用向量,否则报错:java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
* @param ciphertext 密文
* @param key 密钥 不强制位数
* @return 明文
*/
public static String decrypt(String ciphertext, String key) throws Exception {
return encryptOrDecrypt(Cipher.DECRYPT_MODE, ciphertext, key, null, "AES/ECB/PKCS5Padding");
}
// ------------------------------------------AES/CBC/PKCS5Padding 加解密--------------------------------------------------
/**
* 安全性高,加密速度慢
* CBC模式必须提供向量,否则报错:java.security.InvalidKeyException: Parameters missing
* @param plaintext 明文
* @param key 密钥,不强制位数
* @param offset 偏移量,提高安全性,强制16位
* @return 密文
*/
public static String encrypt(String plaintext, String key, String offset) throws Exception {
return encryptOrDecrypt(Cipher.ENCRYPT_MODE, plaintext, key, offset.getBytes(CHARSET_UTF8), "AES/CBC/PKCS5Padding");
}
/**
* 安全性高,加密速度慢
* CBC模式必须提供向量,否则报错:java.security.InvalidKeyException: Parameters missing
* @param ciphertext 密文
* @param key 密钥,不强制位数
* @param offset 偏移量,提高安全性,强制16位
* @return 明文
*/
public static String decrypt(String ciphertext, String key, String offset) throws Exception {
return encryptOrDecrypt(Cipher.DECRYPT_MODE, ciphertext, key, offset.getBytes(CHARSET_UTF8), "AES/CBC/PKCS5Padding");
}
/**
* 加密或解密
* @param mode 加密1 解密2
* @param content 明文或密文
* @param key 密钥
* @param iv 向量
* @param modeAndPadding 加密类型和填充类型
* @return
* @throws Exception
*/
private static String encryptOrDecrypt(int mode, String content, String key, byte[] iv, String modeAndPadding) throws Exception {
byte[] byteContent = Cipher.ENCRYPT_MODE == mode ? content.getBytes(CHARSET_UTF8) : Base64.decodeBase64(content);
// 密钥生成器
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES);
// 随机数,不可以随时间随机,否则mac,linux报错
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
// 设置随机种子
random.setSeed(key.getBytes(CHARSET_UTF8));
// 初始化密钥生成器
keyGenerator.init(128, random);
// 生成密钥
SecretKey secretKey = keyGenerator.generateKey();
// 生成AES专用密钥
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), ALGORITHM_AES);
// 创建加/解密器
Cipher cipher = Cipher.getInstance(modeAndPadding);
// 初始化加/解密器
if (null != iv){
// 指定向量,提高安全性
cipher.init(mode,secretKeySpec,new IvParameterSpec(iv));
}else {
cipher.init(mode, secretKeySpec);
}
// 加密/解密
byte[] result = cipher.doFinal(byteContent);
return Cipher.ENCRYPT_MODE == mode ? Base64.encodeBase64String(result) : new String(result);
}
/**
* 随机生成指定长度的密钥
* @param length
*/
public static String randomKey(int length){
return RandomStringUtils.randomAlphanumeric(length);
}
}
RSA非对称加密
public class RSAEncrypt {
private static Map<Integer, String> keyMap = new HashMap<Integer, String>(); //用于封装随机产生的公钥与私钥
public static void main(String[] args) throws Exception {
//生成公钥和私钥
genKeyPair();
//加密字符串
String message = "df723820";
System.out.println("随机生成的公钥为:" + keyMap.get(0));
System.out.println("随机生成的私钥为:" + keyMap.get(1));
String messageEn = encrypt(message,keyMap.get(0));
System.out.println(message + "\t加密后的字符串为:" + messageEn);
String messageDe = decrypt(messageEn,keyMap.get(1));
System.out.println("还原后的字符串为:" + messageDe);
}
/**
* 随机生成密钥对
* @throws NoSuchAlgorithmException
*/
public static void genKeyPair() throws NoSuchAlgorithmException {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(1024,new SecureRandom());
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥
String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
// 得到私钥字符串
String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
// 将公钥和私钥保存到Map
keyMap.put(0,publicKeyString); //0表示公钥
keyMap.put(1,privateKeyString); //1表示私钥
}
/**
* RSA公钥加密
*
* @param str
* 加密字符串
* @param publicKey
* 公钥
* @return 密文
* @throws Exception
* 加密过程中的异常信息
*/
public static String encrypt( String str, String publicKey ) throws Exception{
//base64编码的公钥
byte[] decoded = Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
return outStr;
}
/**
* RSA私钥解密
*
* @param str
* 加密字符串
* @param privateKey
* 私钥
* @return 铭文
* @throws Exception
* 解密过程中的异常信息
*/
public static String decrypt(String str, String privateKey) throws Exception{
//64位解码加密后的字符串
byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
//base64编码的私钥
byte[] decoded = Base64.decodeBase64(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
String outStr = new String(cipher.doFinal(inputByte));
return outStr;
}
}
到了这里,关于全后端交互数据加密的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!