AES128 CBC加密算法

 

测试类:



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>

猜你喜欢

转载自blog.csdn.net/nmjhehe/article/details/83793042