之前提到、会采用openresty作为网关进行加解密。在实践的过程中、第一步就要调整代码了。我们之前Java采用的是AES/CBC/PKCS5Padding的填充方式,而openresty的aes.lua里面采用的是openssl的、默认的填充方式是AES/CBC/PKCS7Padding的。而Java本身的加密包是不支持这种填充方式的。需要引入新的加密包bcprov-jdk18on(1.71这个版本对应jdk1.8),这个包能支持AES/CBC/PKCS7Padding的填充模式。
AesBouncycastleUtil
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* bouncycastle包AES加密
*/
@Slf4j
public class AesBouncycastleUtil {
private static final String CHARSET_NAME = "UTF-8";
private static final String AES_NAME = "AES";
// 加密模式
public static final String AES_ALGORITHM = "AES/CBC/PKCS7Padding";
static {
// 指定使用bouncycastle包来加密
Security.addProvider(new BouncyCastleProvider());
}
/**
* 加密
* @param text
* @param key
* @param iv
* @return
*/
public String encrypt(String text,String key,String iv) {
byte[] result = null;
try {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(CHARSET_NAME), AES_NAME);
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keySpec, paramSpec);
result = cipher.doFinal(text.getBytes(CHARSET_NAME));
} catch (Exception e) {
log.error("AESP7 加密错误:{}",e.toString());
}
return Base64.encodeBase64String(result);
}
/**
* 解密
* @param pass 密文
* @param key 密钥
* @param iv 向量
* @return
*/
public String decrypt(String pass,String key,String iv) {
try {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(CHARSET_NAME), AES_NAME);
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, keySpec, paramSpec);
return new String(cipher.doFinal(Base64.decodeBase64(pass)), CHARSET_NAME);
} catch (Exception e) {
log.error("AESP7 解密错误:{}",e.toString());
}
return null;
}
public static void main(String[] args) {
// 密钥
String key = "16位字符串";
// 向量
String iv = "16位字符串";
AesBouncycastleUtil aes = new AesBouncycastleUtil();
String contents = "12d57406-28aa-41f5-818d-6521e44949bd@e086a63d-196c-4b3e-9aa4-768f7d51cf52";
String encrypt = aes.encrypt(contents,key,iv);
System.out.println("加密后:" + encrypt);
String decrypt = aes.decrypt(encrypt,key,iv);
System.out.println("解密后:" + decrypt);
}
}
加密后:PGpgSf1e6ZfD8tzTnHUr4WO8JCNi6GeZE+WP9FfA/rdZRAeFp1Kan8FOVrf0D9FHLIQpMGfKY075EEichxlytedD4Y2zVE7xRJQL0ejnxj4=
解密后:12d57406-28aa-41f5-818d-6521e44949bd@e086a63d-196c-4b3e-9aa4-768f7d51cf52
上面的key跟iv都是随机生成的、只要是16位就好、还可以加上一些特殊字符。内容的话就是两个uuid。接下来我们将会在openresty中对上面的加密字符串进行解密。
nginx配置
server {
listen 6378;
location /redis {
default_type text/html;
content_by_lua_file lua/aesUtil.lua;
}
}
lua解密脚本
local headers = ngx.req.get_headers()
local key = "16位字符串"
local iv = "16位字符串"
local aes = require "resty.aes"
local str = require "resty.string"
local aes_128_cbc_with_iv = assert(aes:new(key,nil, aes.cipher(128,"cbc"), {iv=iv}))
-- AES 128 CBC with IV and no SALT
local encrypted = aes_128_cbc_with_iv:encrypt("12d57406-28aa-41f5-818d-6521e44949bd@e086a63d-196c-4b3e-9aa4-768f7d51cf52")
ngx.say("AES 128 CBC (WITH IV) encode_base64: ", ngx.encode_base64(encrypted))
ngx.say("token:",headers["token"])
local cipherBytes = ngx.decode_base64(headers["token"])
local text = aes_128_cbc_with_iv:decrypt(cipherBytes)
ngx.say("text:",text)
运行结果:
AES 128 CBC (WITH IV) encode_base64:PGpgSf1e6ZfD8tzTnHUr4WO8JCNi6GeZE+WP9FfA/rdZRAeFp1Kan8FOVrf0D9FHLIQpMGfKY075EEichxlytedD4Y2zVE7xRJQL0ejnxj4=
token:PGpgSf1e6ZfD8tzTnHUr4WO8JCNi6GeZE+WP9FfA/rdZRAeFp1Kan8FOVrf0D9FHLIQpMGfKY075EEichxlytedD4Y2zVE7xRJQL0ejnxj4=
text:12d57406-28aa-41f5-818d-6521e44949bd@e086a63d-196c-4b3e-9aa4-768f7d51cf52