AES加密工具

本文整理了AES加密工具的相关内容,旨在消除之前的使用困惑,提供清晰的加密步骤和注意事项。

AES加密工具 之前有些坑在里面,现在整理一下,条理清晰点


import android.text.TextUtils;
import android.util.Base64;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Provider;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES 加密工具
 */
public class AESUtils {
    /**
     * 算法/模式/填充
     * 加密模式(Cipher Mode)有CBC、ECB、CTR、OFB、CFB五种。
     * 初始向量Iv(Initialization Vector),使用除ECB以外的其他加密模式均需要传入一个初始向量,其大小与块大小相等,
     * AES块大小是128bit,所以Iv的长度是16字节,秘钥也要是16字节,初始向量可以加强算法强度。
     **/

    /**
     * 加密算法
     */
    private static final String Algorithm_AES = "AES";//AES算法
    private static final String Algorithm_DES = "DES";//DES算法

    /**
     * 加密模式
     */
    private static final String CipherMode_CBC_PKCS5 = "AES/CBC/PKCS5Padding";
    private static final String CipherMode_ECB_PKCS5 = "AES/ECB/PKCS5Padding";

    private static final String CipherMode_CBC_PKCS7 = "AES/CBC/PKCS7Padding";
    private static final String CipherMode_ECB_PKCS7 = "AES/ECB/PKCS7Padding";


    public static String encryptAES_ECB7_2Base64(String contentStr, String key) {
        return encryptAES2Base64(contentStr, key, CipherMode_ECB_PKCS7, null);
    }

    public static String decryptBase64AES_ECB7(String base64Str, String key) {
        return decryptBase64AES(base64Str, key, CipherMode_ECB_PKCS7, null);
    }

    /**
     * AES加密 输出base64字符串
     *
     * @param content        加密内容
     * @param key            秘钥 长度16
     * @param transformation 加密模式  例:AES/CBC/PKCS5Padding
     * @param iv             偏移量 长度16 ,可选 ,除ECB外 都需要加
     * @return
     */
    public static String encryptAES2Base64(String content, String key, String transformation, String iv) {
        if (TextUtils.isEmpty(content)) return "";
        try {
            key = create128BitsKey(key);//截取key 16位
            byte[] strByte = content.getBytes("UTF-8");
            byte[] keyByte = key.getBytes("UTF-8");
            byte[] ivByte = null;
            if (!TextUtils.isEmpty(iv)) {
                ivByte = create128BitsIV(iv).getBytes("UTF-8");
            }
            byte[] result = encryptAES(strByte, keyByte, transformation, ivByte);//AES加密

            return Base64.encodeToString(result, Base64.NO_WRAP);//要进行base64再一次加密 NO_WRAP不带换行符 DEFAULT带
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * AES解密  输入base64字符串
     *
     * @param base64Str      加密内容
     * @param key            秘钥 长度16
     * @param transformation 加密模式  例:AES/CBC/PKCS5Padding
     * @param iv             偏移量 长度16 ,可选 ,除ECB外 都需要加
     * @return
     */
    public static String decryptBase64AES(String base64Str, String key, String transformation, String iv) {
        if (TextUtils.isEmpty(base64Str)) return "";
        try {
            key = create128BitsKey(key);//截取key 16位

            byte[] strByte = Base64.decode(base64Str, Base64.NO_WRAP);//要先base64解密 NO_WRAP不带换行符 DEFAULT带

            byte[] keyByte = key.getBytes("UTF-8");
            byte[] ivByte = null;
            if (!TextUtils.isEmpty(iv)) {
                ivByte = create128BitsIV(iv).getBytes("UTF-8");
            }
            byte[] result = decryptAES(strByte, keyByte, transformation, ivByte);//AES解密

            return new String(result, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * AES加密 输出16进制字符串
     *
     * @param content        加密内容
     * @param key            秘钥 长度16
     * @param transformation 加密模式  例:AES/CBC/PKCS5Padding
     * @param iv             偏移量 长度16 ,可选 ,除ECB外 都需要加
     * @return
     */
    public static String encryptAES2Hex(String content, String key, String transformation, String iv) {
        key = create128BitsKey(key);//截取key 16位
        try {
            byte[] strByte = content.getBytes("UTF-8");
            byte[] keyByte = key.getBytes("UTF-8");
            byte[] ivByte = null;
            if (!TextUtils.isEmpty(iv)) {
                ivByte = create128BitsIV(iv).getBytes("UTF-8");
            }
            byte[] result = encryptAES(strByte, keyByte, transformation, ivByte);//AES加密
            if (result != null) return bytesToHexString(result);//输出16进制字符串
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * AES解密 输入16进制字符串
     *
     * @param hexStr         加密内容
     * @param key            秘钥 长度16
     * @param transformation 加密模式  例:AES/CBC/PKCS5Padding
     * @param iv             偏移量 长度16 ,可选 ,除ECB外 都需要加
     * @return
     */
    public static String decryptHexAES(String hexStr, String key, String transformation, String iv) {
        key = create128BitsKey(key);//截取key 16位
        try {
            byte[] strByte = hexStringToBytes(hexStr);//16进制字符串转换bytes

            byte[] keyByte = key.getBytes("UTF-8");
            byte[] ivByte = null;
            if (!TextUtils.isEmpty(iv)) {
                ivByte = create128BitsIV(iv).getBytes("UTF-8");
            }
            byte[] result = decryptAES(strByte, keyByte, transformation, ivByte);//AES解密

            return new String(result, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * JDK只支持AES-128加密,也就是密钥长度必须是128bit;参数为密钥key,key的长度小于16字符时用"0"补充,key长度大于16字符时截取前16位
     **/
    private static String create128BitsKey(String key) {
        if (key == null || key.length() != 16) {
            throw new RuntimeException("Unsupported key size,秘钥长度必须为16字节");
        }
        StringBuffer buffer = new StringBuffer(16);
        buffer.append(key);
        //小于16后面补0
        while (buffer.length() < 16) {
            buffer.append("0");
        }
        //大于16,截取前16个字符
        if (buffer.length() > 16) {
            buffer.setLength(16);
        }
        return buffer.toString();
    }

    /**
     * 创建128位的偏移量,iv的长度小于16时后面补0,大于16,截取前16个字符;
     *
     * @param iv
     * @return
     */
    private static String create128BitsIV(String iv) {
        if (iv == null || iv.length() != 16) {
            throw new RuntimeException("Unsupported iv size,iv长度必须为16字节");
        }
        StringBuffer buffer = new StringBuffer(16);
        buffer.append(iv);
        while (buffer.length() < 16) {
            buffer.append("0");
        }
        if (buffer.length() > 16) {
            buffer.setLength(16);
        }

        return buffer.toString();
    }


    /**
     * AES加密
     *
     * @param content        加密内容
     * @param keyBytes       秘钥 长度16
     * @param transformation 加密模式  例:AES/CBC/PKCS5Padding
     * @param iv             偏移量 长度16 ,可选 ,除ECB外 都需要加
     * @return
     */
    public static byte[] encryptAES(byte[] content, byte[] keyBytes, String transformation, byte[] iv) {
        return encrypt(content, keyBytes, Algorithm_AES, transformation, iv);
    }

    /**
     * DES加密
     *
     * @param content        加密内容
     * @param keyBytes       秘钥 长度16
     * @param transformation 加密模式  例:DES/CBC/PKCS5Padding
     * @param iv             偏移量 长度16 ,可选 ,除ECB外 都需要加
     * @return
     */
    public static byte[] encryptDES(byte[] content, byte[] keyBytes, String transformation, byte[] iv) {
        return encrypt(content, keyBytes, Algorithm_DES, transformation, iv);
    }

    /**
     * 加密
     *
     * @param content        加密内容
     * @param keyBytes       秘钥 长度16
     * @param transformation 加密算法  AES或DES
     * @param transformation 加密模式  例:AES/CBC/PKCS5Padding
     * @param iv             偏移量 长度16 ,可选 ,除ECB外 都需要加
     * @return
     */
    public static byte[] encrypt(byte[] content, byte[] keyBytes, String algorithm, String transformation, byte[] iv) {
        try {
            SecretKey key;
            if (Algorithm_DES.equals(algorithm)) {
                DESKeySpec desKey = new DESKeySpec(keyBytes);
                SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
                key = keyFactory.generateSecret(desKey);
            } else {
                key = new SecretKeySpec(keyBytes, algorithm);
            }

            Cipher cipher;
            if (iv == null || iv.length == 0) {
                cipher = Cipher.getInstance(transformation);//ECB不需要iv
                cipher.init(Cipher.ENCRYPT_MODE, key);
            } else {
                cipher = Cipher.getInstance(transformation);
                cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
            }

            return cipher.doFinal(content);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * AES解密
     *
     * @param content        加密内容
     * @param keyBytes       秘钥 长度16
     * @param transformation 加密模式  例:AES/CBC/PKCS5Padding
     * @param iv             偏移量 长度16 ,可选 ,除ECB外 都需要加
     * @return
     */
    public static byte[] decryptAES(byte[] content, byte[] keyBytes, String transformation, byte[] iv) {
        return decrypt(content, keyBytes, Algorithm_AES, transformation, iv);
    }

    /**
     * DES解密
     *
     * @param content        加密内容
     * @param keyBytes       秘钥 长度16
     * @param transformation 加密模式  例:DES/CBC/PKCS5Padding
     * @param iv             偏移量 长度16 ,可选 ,除ECB外 都需要加
     * @return
     */
    public static byte[] decryptDES(byte[] content, byte[] keyBytes, String transformation, byte[] iv) {
        return decrypt(content, keyBytes, Algorithm_DES, transformation, iv);
    }

    /**
     * 解密
     *
     * @param content        加密内容
     * @param keyBytes       秘钥 长度16
     * @param algorithm      加密算法  AES或DES
     * @param transformation 加密模式  例:AES/CBC/PKCS5Padding
     * @param iv             偏移量 长度16 ,可选 ,除ECB外 都需要加
     * @return
     */
    public static byte[] decrypt(byte[] content, byte[] keyBytes, String algorithm, String transformation, byte[] iv) {
        try {
            SecretKey key;
            if (Algorithm_DES.equals(algorithm)) {
                DESKeySpec desKey = new DESKeySpec(keyBytes);
                SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
                key = keyFactory.generateSecret(desKey);
            } else {
                key = new SecretKeySpec(keyBytes, algorithm);
            }

            Cipher cipher;
            if (iv == null || iv.length == 0) {
                cipher = Cipher.getInstance(transformation);//ECB不需要iv
                cipher.init(Cipher.DECRYPT_MODE, key);
            } else {
                cipher = Cipher.getInstance(transformation);
                cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
            }

            return cipher.doFinal(content);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }


    // 对密钥进行处理
    private static byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        //for android
        SecureRandom sr = null;
        int sdk_version = android.os.Build.VERSION.SDK_INT;
        if (sdk_version > 23) {  // Android  6.0 以上
            sr = SecureRandom.getInstance("SHA1PRNG", new CryptoProvider());
        } else if (sdk_version >= 17) {
            sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
        } else {
            sr = SecureRandom.getInstance("SHA1PRNG");
        }

        // for Java
        // secureRandom = SecureRandom.getInstance(SHA1PRNG);
        sr.setSeed(seed);
        kgen.init(128, sr); //256 bits or 128 bits,192bits
        //AES中128位密钥版本有10个加密循环,192比特密钥版本有12个加密循环,256比特密钥版本则有14个加密循环。
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        return raw;
    }


    /**
     * 将二进制转换成16进制
     *
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 把16进制字符串转换成字节数组
     *
     * @param hex
     * @return byte[]
     */
    public static byte[] hexStringToBytes(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
        }
        return result;
    }

    private static int toByte(char c) {
        byte b = (byte) "0123456789ABCDEF".indexOf(c);
        return b;
    }

    /**
     * 数组转换成十六进制字符串
     *
     * @param bArray
     * @return HexString
     */
    public static final String bytesToHexString(byte[] bArray) {
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 将16进制转换为二进制
     *
     * @param hexStr
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2),
                    16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值