• AES加解


    1.简述

      高级加密标准(Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。

      :使用jdk自带的jce.jar包实现

      加密标准

        AES为分组密码,分组密码也就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节(每个字节8位)。密钥的长度可以使用128位、192位、256位。密钥的长度不同,加密轮数也不同。

    AES

    密钥长度(32位bit)

    分组长度(32位bit)

    加密轮数

    JDK

    AES-128

    4(16个字符)

    4

    10

    支持

    AES-192

    6(24个字符)

    4

    12

    不支持

    AES-256

    8(32个字符)

    4

    14

    不支持

    2.AES加密模式

      JCE支持模式:

    • 电码本模式(Electronic Codebook Book,缩写:ECB):最基本的加密模式,是将整个明文分成若干段相同的小段,然后对每一小段进行加密。
    • 密码分组链接模式(Cipher Block Chaining,缩写:CBC):先将明文切分成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再与密钥进行加密。
    • 计算器模式(Counter,缩写:CTR)计算器模式不常见,在CTR模式中, 有一个自增的算子,这个算子用密钥加密之后的输出和明文异或的结果得到密文,相当于一次一密。这种加密方式简单快速,安全可靠,而且可以并行加密,但是在计算器不能维持很长的情况下,密钥只能使用一次
    • 密码反馈模式(Cipher FeedBack ,缩写:CFB):能够将块密文转换为流密文。
    • 输出反馈模式(Output FeedBack,缩写:OFB):先用块加密器生成密钥流,然后再将密钥流与明文流异或得到密文流,解密是先用块加密器生成密钥流,再将密钥流与密文流异或得到明文,由于异或操作的对称性所以加密和解密的流程是完全一样的。

      JCE5种模式优缺点

        1. ECB

          优点:简单、可并行计算、误差不传递。

          缺点:不能隐藏明文的模式、可能对明文进行主动攻击。

        2. CBC

          优点:不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。

          缺点:需要初始化向量IV、不利于并行计算、误差传递。

        3. CTR

          优点同明文不同密、每个块单独运算,适合并行运算。

          缺点:主动攻击(改明文,后续内容不影响,只要误差不传递该缺点就存在)。

        4. CFB

          优点隐藏了明文模式、分组密码转化为流模式、可以及时加密传送小于分组的数据。

          缺点:不利于并行计算、误差传送:一个明文单元损坏影响多个单元。

        5. OFB

          优点:同明文不同密文,分组密钥转换为流密码。

          缺点串行运算不利并行、误差传送:一个明文单元损坏影响多个单元。

    3.AES填充方式

      JCE中AES支持三种填充:NoPadding,PKCS5Padding,ISO10126Padding。

      注:不带模式和填充来获取AES算法的时候,其默认使用ECB/PKCS5Padding

    填充

    16字节加密后数据长度

    不满16字节加密后长度

    NoPadding

    16

    不支持

    PKCS5Padding

    32

    支持

    ISO10126Padding

    32

    支持

    4.AES加密实现

    (1)NoPadding补码方式实现

    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    /**测试类
     */
    public class Test{
        private static final String AESKEY = "WEBTEST123456789";//密钥
        public static void main(String[] args) {
            try {
                String enString = "asd#测试#13#";//有了#号区分,这样做是为了方便过滤不是16的倍数时填充的0
                System.out.println("加密前的字串是:" + enString);
                enString = AesUtils.Encrypt(enString, AESKEY);
                System.out.println("加密后的字串是:" + enString);
                enString = AesUtils.Decrypt(enString, AESKEY);
                System.out.println("解密后的字串是:" + enString);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**AES加密工具类
     */
    class AesUtils {
        // 加密
        public static String Encrypt(String sSrc, String sKey) throws Exception {
            if (sKey == null) {
                System.out.print("Key为空null");
                return null;
            }
            // 判断Key是否为16位
            if (sKey.length() != 16) {
                System.out.print("Key长度不是16位");
                return null;
            }
            //注意这一步,不是16的倍数,则后面填充0,不填充的话会报错
            while (sSrc.getBytes().length % 16 > 0) {
                sSrc += "0";
            }
            byte[] raw = sKey.getBytes();
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            //注意,不是CBC模式,去除IvParameterSpec
            IvParameterSpec iv = new IvParameterSpec("1234567812345678".getBytes());
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            byte[] encrypted = cipher.doFinal(sSrc.getBytes());
            return byte2hex(encrypted);
        }
    
        // 解密
        public static String Decrypt(String sSrc, String sKey) throws Exception {
            try {
                // 判断Key是否正确
                if (sKey == null) {
                    System.out.print("Key为空null");
                    return null;
                }
                // 判断Key是否为16位
                if (sKey.length() != 16) {
                    System.out.print("Key长度不是16位");
                    return null;
                }
                byte[] raw = sKey.getBytes("ASCII");
                SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
                Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
                IvParameterSpec iv = new IvParameterSpec("1234567812345678".getBytes());
                cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
                byte[] encrypted1 = hex2byte(sSrc);
                try {
                    byte[] original = cipher.doFinal(encrypted1);
                    String originalString = new String(original);
                    return originalString;
                } catch (Exception e) {
                    System.out.println(e.toString());
                    return null;
                }
            } catch (Exception ex) {
                System.out.println(ex.toString());
                return null;
            }
        }
        
        /**自定义二次加密,将二进制转为16进制
         */
        public static String byte2hex(byte[] b) {
            String hs = "";
            String stmp = "";
            for (int n = 0; n < b.length; n++) {
                stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
                if (stmp.length() == 1) {
                    hs = hs + "0" + stmp;
                } else {
                    hs = hs + stmp;
                }
            }
            return hs.toUpperCase();
        }
        /**二次加密内容解密,将16进制转换为二进制
         */
        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;
        }
    }
    View Code

      :使用NoPadding补码方式,需要加密、解密的数据是16字节的倍数,否则会报错。

    (2)其他补码方式实现

    /**测试类
     */
    public class Test{
        private static final String AESKEY = "WEBTEST123456789";//密钥
        public static void main(String[] args) {
            try {
                String enString = "asd#测试#13#";//有了#号区分,这样做是为了方便过滤不是16的倍数时填充的0
                System.out.println("加密前的字串是:" + enString);
                enString = AesUtils.Encrypt(enString, AESKEY);
                System.out.println("加密后的字串是:" + enString);
                enString = AesUtils.Decrypt(enString, AESKEY);
                System.out.println("解密后的字串是:" + enString);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**AES加密工具类
     */
    class AesUtils {
        // 加密
        public static String Encrypt(String sSrc, String sKey) throws Exception {
            if (sKey == null) {
                System.out.print("Key为空null");
                return null;
            }
            // 判断Key是否为16位
            if (sKey.length() != 16) {
                System.out.print("Key长度不是16位");
                return null;
            }
            byte[] raw = sKey.getBytes();
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            //注意,不是CBC模式,去除IvParameterSpec
            IvParameterSpec iv = new IvParameterSpec("1234567812345678".getBytes());
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            byte[] encrypted = cipher.doFinal(sSrc.getBytes());
            return byte2hex(encrypted);
        }
    
        // 解密
        public static String Decrypt(String sSrc, String sKey) throws Exception {
            try {
                // 判断Key是否正确
                if (sKey == null) {
                    System.out.print("Key为空null");
                    return null;
                }
                // 判断Key是否为16位
                if (sKey.length() != 16) {
                    System.out.print("Key长度不是16位");
                    return null;
                }
                byte[] raw = sKey.getBytes("ASCII");
                SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                IvParameterSpec iv = new IvParameterSpec("1234567812345678".getBytes());
                cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
                byte[] encrypted1 = hex2byte(sSrc);
                try {
                    byte[] original = cipher.doFinal(encrypted1);
                    String originalString = new String(original);
                    return originalString;
                } catch (Exception e) {
                    System.out.println(e.toString());
                    return null;
                }
            } catch (Exception ex) {
                System.out.println(ex.toString());
                return null;
            }
        }
        
        /**自定义二次加密,将二进制转为16进制
         */
        public static String byte2hex(byte[] b) {
            String hs = "";
            String stmp = "";
            for (int n = 0; n < b.length; n++) {
                stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
                if (stmp.length() == 1) {
                    hs = hs + "0" + stmp;
                } else {
                    hs = hs + stmp;
                }
            }
            return hs.toUpperCase();
        }
        /**二次加密内容解密,将16进制转换为二进制
         */
        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;
        }
    }
    View Code

      注:使用PKCS5Padding、ISO10126Padding补码方式,不是16字节的倍数也能进行加密、解密。

  • 相关阅读:
    蒸发冷却概述
    2011年2月22日星期2
    在中国搞技术的都是狗
    实用新型专利申请书规范
    我小时候家里穷
    蒸发冷却基本原理
    opera浏览器使用技巧
    浏览器哪个好用
    Matlab数理统计工具箱应用简介(转)
    EXCEL模板读写说明(转)
  • 原文地址:https://www.cnblogs.com/bl123/p/13743126.html
Copyright © 2020-2023  润新知