测试类:
import org.junit.Test;
public class EncryptorTest
{
//加密
@Test
public void encryptor(){
String str="I am is liu";
String key= EncryptorUtil.getEncryptionFactor();
String encrypt = EncryptorUtil.encrypt(str, key);
System.out.println("encrypt:"+encrypt);
}
//加密+解密
@Test
public void decode(){
String str="I am is liu";
String key= EncryptorUtil.getEncryptionFactor();
System.out.println("key:"+key); //key:JMEMMYYYYYMMDD
String encrypt = EncryptorUtil.encrypt(str, key);
System.out.println("加密后结果:encrypt:"+encrypt);
//decrypt:I am is liu 解密成功
String decrypt = EncryptorUtil.decrypt(encrypt, key);
//key --> key+"a" 解密失败
// String decrypt = EncryptorUtil.decrypt(encrypt, key+"a");
System.out.println("解密后结果:decrypt:"+decrypt);
}
}
EncryptorUtil 加密类
import org.apache.commons.lang3.StringUtils;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Locale;
import java.util.Properties;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import lombok.extern.slf4j.Slf4j;
/**
* 加密/解密工具类
*/
@Slf4j
public class EncryptorUtil
{
/**
* 加密因子存储位置
*/
private static final String KEYPROPERTIES = "/opt/UPORTAL2800/workshop/conf/parms.properties";
/**
* 加密因子key值
*/
private static final String ENCRYPTFACTORNAME="encryption.second.factor";
/**
* 第一部分加密因子
*/
private static final byte[] FIRST_BTINITFACTOR = new byte[8];
/**
* 第二部分加密因子
*/
private static final byte[] SECOND_BTINITFACTOR = new byte[8];
/**
* 第二部分加密因子长度
*/
private static final int SECOND_FACTOR_LENGTH = 8;
/**
* IV 值的长度
*/
private static final int IV_LENGTH = 16;
/**
* UTF-8
*/
private static final Charset UTF8 = Charset.forName("UTF-8");
static
{
// 初始化加密因子,
FIRST_BTINITFACTOR[0] = 74;
FIRST_BTINITFACTOR[1] = 77;
FIRST_BTINITFACTOR[2] = 69;
FIRST_BTINITFACTOR[3] = 12;
FIRST_BTINITFACTOR[4] = 77;
FIRST_BTINITFACTOR[5] = 20;
FIRST_BTINITFACTOR[6] = 77;
FIRST_BTINITFACTOR[7] = 89;
SECOND_BTINITFACTOR[0] = 89;
SECOND_BTINITFACTOR[1] = 89;
SECOND_BTINITFACTOR[2] = 89;
SECOND_BTINITFACTOR[3] = 89;
SECOND_BTINITFACTOR[4] = 77;
SECOND_BTINITFACTOR[5] = 77;
SECOND_BTINITFACTOR[6] = 68;
SECOND_BTINITFACTOR[7] = 68;
}
/**
* AES128 CBC 进行加密
* @param plainText 待加密文本
* @param key 指定加密秘钥,若为null,则取系统根秘钥
* @return
*/
public static String encrypt(String plainText, String key)
{
if (null == plainText || 0 == plainText.length())
{
return "";
}
if (StringUtils.isEmpty(key))
{
log.info("encrypt key is null");
key = getEncryptionFactor();
}
String strResult = null;
try
{
byte[] iv = randomBytes(IV_LENGTH);
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(UTF8), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes(UTF8));
byte[] cipherData = new byte[iv.length + encrypted.length];
System.arraycopy(iv, 0, cipherData, 0, iv.length);
System.arraycopy(encrypted, 0, cipherData, iv.length, encrypted.length);
strResult = byteToHexStr(cipherData);
}
catch (InvalidAlgorithmParameterException | InvalidKeyException | NoSuchAlgorithmException
| NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e)
{
log.error("encrypt failed. catch exception:", e);
strResult = "";
}
return strResult;
}
/**
* AES128 CBC 进行解密
* @param cipherText 待解密文本
* @param key 指定解密秘钥,若为null,则取系统根秘钥
* @return
*/
public static String decrypt(String cipherText, String key)
{
if (null == cipherText || 0 == cipherText.length())
{
return "";
}
if (StringUtils.isEmpty(key))
{
log.info("decrypt key is null");
key = getEncryptionFactor();
}
String strResult = null;
try
{
byte[] cipherIvBytes = hexStringToBytes(cipherText);
if (cipherIvBytes.length <= IV_LENGTH)
{
log.error("decrypt failed. cipher text length is invalid. return original cipher text.");
return cipherText;
}
byte[] iv = new byte[IV_LENGTH];
byte[] cipherBytes = new byte[cipherIvBytes.length - IV_LENGTH];
System.arraycopy(cipherIvBytes, 0, iv, 0, IV_LENGTH);
System.arraycopy(cipherIvBytes, IV_LENGTH, cipherBytes, 0, cipherIvBytes.length - IV_LENGTH);
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(UTF8), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
byte[] original = cipher.doFinal(cipherBytes);
strResult = new String(original, UTF8);
}
catch (InvalidAlgorithmParameterException | InvalidKeyException | NoSuchAlgorithmException
| NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e)
{
log.error("decrypt failed. catch exception:", e);
strResult = "";
}
return strResult;
}
/**
* 16进制字符串转为byte[]
* @param hexString
* @return
*/
private static byte[] hexStringToBytes(String hexString)
{
if ((hexString == null) || (0 == hexString.length()))
{
return new byte[0];
}
hexString = hexString.toUpperCase(Locale.US);
char[] hexChars = hexString.toCharArray();
int length = hexString.length() / 2;
byte[] d = new byte[length];
for (int i = 0; i < length; i++)
{
int pos = i * 2;
d[i] = ((byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[(pos + 1)])));
}
return d;
}
/**
* 单个16进制字符转为十进制数字
* @param c
* @return
*/
private static byte charToByte(char c)
{
return (byte) "0123456789ABCDEF".indexOf(c);
}
/**
* 将字节数组转换为16进制字符串
* @param data
* @return
*/
public static String byteToHexStr(byte[] data)
{
StringBuilder sb = new StringBuilder();
for (byte b : data)
{
int val = b & 0xFF;
if (val < 16)
{
sb.append("0");
}
sb.append(Integer.toHexString(val));
}
return sb.toString();
}
/**
* 获取指定长度的随机字节数组
* @param length
* @return
*/
private static byte[] randomBytes(int length)
{
byte[] data = new byte[length];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(data);
return data;
}
/**
* 获取系统加密因子,若无法解析配置文件,则获取默认加密因子
* @return
*/
public static String getEncryptionFactor()
{
String secondFactor = getValueFromProperties(KEYPROPERTIES, ENCRYPTFACTORNAME);
if (secondFactor == null || secondFactor.isEmpty() || secondFactor.length() != SECOND_FACTOR_LENGTH)
{
secondFactor = new String(SECOND_BTINITFACTOR, UTF8);
}
return getEncryptionFactor(secondFactor);
}
/**
* 根据第二段加密因子生成完整加密因子
* @param secondFactor
* @return
*/
private static String getEncryptionFactor(String secondFactor)
{
String firstFactor = new String(FIRST_BTINITFACTOR, UTF8);
return firstFactor + secondFactor;
}
/**
* 根据key值从配置文件中获取结果
* @param fileName
* @param key
* @return
*/
private static String getValueFromProperties(String fileName, String key)
{
// 适应该方法,每次请求对是重新读取文件,不会缓存
Properties p = new Properties();
FileReader fileReader = null;
try
{
fileReader = new FileReader(fileName);
p.load(fileReader);
}
catch (IOException e)
{
log.warn("get encryption factor from properties file failed. The default encryption factor will be used.");
return "";
}
finally
{
CommonUtil.close(fileReader);
}
return p.getProperty(key);
}
/**
* 获取一个4位随机数
* @return
*/
public static String randomNumber()
{
// 获取一个[1000, 9999]区间内的随机数
SecureRandom secureRandom = new SecureRandom();
int result = 1000 + secureRandom.nextInt(9000);
return String.valueOf(result);
}
/**
* 主函数,用于加密解密字符串,此函数被shell调用
* @param args
*/
public static void main(String[] args)
{
// 通过参数来计算密文或者明文,要提供给外部shell调用,请不要修改
if (args.length >= 1 && args.length <= 3)
{
switch (args[0])
{
//生成根秘钥的后半部分
case "-g":
System.out.println(EncryptorUtil.byteToHexStr(new SecureRandom().generateSeed(4)));
break;
//解密
case "-d":
if (args.length > 1)
{
System.out.println(EncryptorUtil.decrypt(args[1], args.length == 3 ? args[2] : null));
}
break;
//加密
case "-e":
if (args.length > 1)
{
System.out.println(EncryptorUtil.encrypt(args[1], args.length == 3 ? args[2] : null));
}
break;
default:
System.out.println("args[0] is invalid.");
break;
}
}
}
}
POM.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.heima</groupId>
<artifactId>jiami</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>7</source>
<target>7</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>