zoukankan      html  css  js  c++  java
  • 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();
        }
    }
  • 相关阅读:
    gc buffer busy/gcs log flush sync与log file sync
    给Oracle年轻的初学者的几点建议
    Android 编程下帧动画在 Activity 启动时自动运行的几种方式
    Android 编程下 Touch 事件的分发和消费机制
    Java 编程下 static 关键字
    Java 编程下 final 关键字
    Android 编程下模拟 HOME 键效果
    Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated ?
    Extjs4 大型项目目录结构重构
    [转]SQLServer 2008 允许远程连接的配置方法
  • 原文地址:https://www.cnblogs.com/flysand/p/7985252.html
Copyright © 2011-2022 走看看