• AES加密个人理解


    这里实现的是AES加密算法的CBC模式的NoPadding加密

    下图是官方文档中Cipher的provider。后面的padding为填充模式,即CBC为128位加密算法,加密内容的byte[]字节数组位数必须是16的倍数,否则会抛异常 Input length not multiple of 16 bytes

    CBC加密提供了两种填充方式,NoPadding是默认不填充。因此不够16位的部分,下面用空格进行了填充凑位数。

    另外CBC加密除了提供AES加密必须的密钥key以外,还要一个响亮iv,应该是增加加密复杂度的。

     以下源码是自己的CBC模式的实现,加密字段返回16进制字符串,解密时,同样通过AES/CBC/NoPadding方式,把16进制字符串转换为二进制byte[]字节数组后再解密,然后根据编码转为原字符串。

    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    
    /**
     * Aes加密工具类--暂时只实现CBC NoPadding加密
     *
     * @author flysand
     **/
    public class AesUtils {
    
        /**
         * 加密 加密方式AES/CBC/NoPadding 不足16位倍数,补空格
         *
         * @param sSrc           加密内容
         * @param encodingFormat 编码格式
         * @param sKey           密钥key
         * @param ivParameter    向量
         * @return
         * @throws Exception
         */
        public static String encrypt(String sSrc, String encodingFormat, String sKey, String ivParameter) throws Exception {
            byte[] sSrcArray = sSrc.getBytes(encodingFormat);
            int length = sSrcArray.length;
            byte[] lastArr;
            //不足16倍数位,补充空
            if (length % 16 != 0) {
                byte[] temp = new byte[16 - length % 16];
                //用空格补位
                byte[] fArr = " ".getBytes(encodingFormat);
                for (int i = 0; i < temp.length; i++) {
                    temp[i] = fArr[0];
                }
                lastArr = new byte[length + temp.length];
                for (int i = 0; i < length; i++) {
                    lastArr[i] = sSrcArray[i];
                }
                for (int i = 0; i < temp.length; i++) {
                    lastArr[length + i] = temp[i];
                }
            } else {
                lastArr = sSrcArray;
            }
            //根据农银需求,采用AES/CBC/NoPadding加密方式
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            byte[] raw = sKey.getBytes(encodingFormat);
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());//使用CBC模式,需要一个向量iv,可增加加密算法的强度
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            byte[] encrypted = cipher.doFinal(lastArr);
            //直接转为16进制传参
            return parseByte2HexStr(encrypted);
        }
    
        /**
         * 解密 根据加密方式AES/CBC/NoPadding解密
         *
         * @param sSrc           加密内容
         * @param encodingFormat 编码格式
         * @param sKey           密钥key
         * @param ivParameter    向量
         * @return
         * @throws Exception
         */
        public static String decrypt(String sSrc, String encodingFormat, String sKey, String ivParameter) throws Exception {
            try {
                byte[] raw = sKey.getBytes(encodingFormat);
                SecretKeySpec keySpec = new SecretKeySpec(raw, "AES");
                Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
                IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes(encodingFormat));
                cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
                //转为二进制字节数组
                byte[] encrypted = hex2byte(sSrc);
                byte[] original = cipher.doFinal(encrypted);
                String originalString = new String(original, encodingFormat);
                return originalString;
            } catch (Exception ex) {
                return null;
            }
        }
    
    
        /**
         * 将十六进制字符串转换成二进制字节数组
         *
         * @param strHex
         * @return
         */
        public static byte[] hex2byte(String strHex) {
            if (strHex == null) {
                return null;
            }
            int l = strHex.length();
            if (l % 2 == 1) {
                return null;
            }
            byte[] b = new byte[l / 2];
            for (int i = 0; i != l / 2; i++) {
                b[i] = (byte) Integer.parseInt(strHex.substring(i * 2, i * 2 + 2), 16);
            }
            return b;
    
        }
    
    
        /**
         * 将二进制字节数组转换成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();
        }
    }
  • 相关阅读:
    【转】html的meta总结
    style.left 与offsetLeft之间的区别
    VM886
    js 获取数据类型
    JS序列化URL方法
    userData 本地存储
    第一章 1.6 HTML5 的新功能(二)
    第一章 1.6 HTML5 的新功能(一)
    第一章 1.5 无插件范式
    第一章 1.4 新的认识
  • 原文地址:https://www.cnblogs.com/flysand/p/7985252.html
Copyright © 2020-2023  润新知