对称加密算法之DES与AES的使用

  • 对称加密
  • DES的使用
  • AES的使用
  • Base64算法
  • 加密模式
  • 填充模式
  • 测试加密模式与填充模式


对称加密

加密和解密时使用相同的密钥,这种加密方法称为对称加密

分类

流加密:按顺序一个一个加密,如文本:123456,则先加密1再加密2,以此类推

块加密:分块分组加密,如文本:123456,若分3组,则先加密12,再加密34,以此类推

常见加密算法

DES

AES

特点

加密速度快, 可以加密大文件

密文可逆, 一旦密钥文件泄漏, 就会导致数据暴露

加密后再ASCII编码表找不到对应字符, 出现乱码

一般结合Base64使用,防止乱码

DES的使用

DES是数据加密标准,是一种使用密钥加密的块算法。

Java的Cipher类供加密和解密功能,在线文档:https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html

public static void main(String[] args) throws Exception {
        // 原文
        String input = "Hello Word";
        // 使用des进行加密,密钥必须是8个字节
        String key = "12345678";
        // 获取Cipher对象的算法
        String transformation = "DES";
        // 指定获取密钥的算法
        String algorithm = "DES";
        
        String encrypt = encrypt(input, key, transformation, algorithm);
        System.out.println("加密:" + encrypt);
        String decrypt = dncrypt(encrypt, key, transformation, algorithm);
        System.out.println("解密:" + decrypt);

    }

    /**
     * 加密数据
     */
    private static String encrypt(String input, String key, String transformation, String algorithm) throws Exception {
        // 获取加密对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 指定秘钥规则:传入密钥的字节数组与指定的算法
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        // 初始化加密对象: 指定加密模式与秘钥规则
        cipher.init(Cipher.ENCRYPT_MODE, sks);
        // 开始加密
        byte[] bytes = cipher.doFinal(input.getBytes());
        // 打印密文,由于bytes字节数字中存在负数,即ascii码有负数,解析不出来,将输出乱码
        System.out.println("bytes = " + new String(bytes));
        // 对字节数字进行Base64编码
        return Base64.encode(bytes);
    }

    /**
     * 解密数据
     */
    private static String dncrypt(String input, String key, String transformation, String algorithm) throws Exception {
        // 获取Cipher对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 指定秘钥规则:传入密钥的字节数组与指定的算法
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        // 初始化解密对象: 指定解密模式与秘钥规则
        cipher.init(Cipher.DECRYPT_MODE, sks);
        // 解密
        byte[] bytes = cipher.doFinal(Base64.decode(input));
        return new String(bytes);
    }
bytes = �Rd��ʩ� h�� 
加密:01Jk6AecyqnqsABousAVIA==
解密:Hello Word

AES的使用

AES是高级加密标准,用来替代DES。

public static void main(String[] args) throws Exception {
        // 原文
        String input = "Hello Word";
        // AES加密算法:密匙必须是16个字节
        String key = "1234567891234567";
        // 获取Cipher对象的算法
        String transformation = "AES";
        // 指定获取密钥的算法
        String algorithm = "AES";

        String encrypt = encrypt(input, key, transformation, algorithm);
        System.out.println("加密:" + encrypt);
        String decrypt = dncrypt(encrypt, key, transformation, algorithm);
        System.out.println("解密:" + decrypt);
    }
bytes = ��F�p��Ny�|08�k2
加密:/fZGj3CTnE5503wwONlrMg==
解密:Hello Word

Base64算法

Base64算法不是加密算法,是用于传输8Bit字节码的可读性编码算法之一。

可读性编码不改变信息内容,只改变信息内容的表现形式

Base64是说在编码过程中使用了64种字符:大写A到Z、小写a到z、数字0到9、“+”和“/”

构成

26个小写字母: a - z 

26个大写字母: A - Z

10 个数字: 0 - 9

2个符号: + /

算法原理

base64是3个字节为一组,一个字节 8位,一共就是24位 ,然后把3个字节转成4组,每组6位(3 * 8 = 4 * 6 = 24 )。

当每组6位时则缺少2位,在高位进行补0 ,于是控制了base64的取值范围在0-63位,所以就叫base64(00111 111 = 32 + 16 + 8 + 4 + 2 + 1 =63

注意:

由于base64是三个字节一组 ,当一组三个字节位数不够的时候,会使用等号来补齐。

public static void main(String[] args) throws Exception {
        System.out.println(Base64.encode("1".getBytes()));
        System.out.println(Base64.encode("12".getBytes()));
        System.out.println(Base64.encode("123".getBytes()));
        // UTF-8编码下:一个汉字站3个字节
        System.out.println(Base64.encode("中国".getBytes("UTF-8")));
        // GBK编码下:一个汉字站2个字节
        System.out.println(Base64.encode("中国".getBytes("GBK")));
        }
MQ==
MTI=
MTIz
5Lit5Zu9
1tC5+g==

加密模式

ECB :

电子密码本, 需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密

可以并行处理数据,但同样的原文生成同样的密文, 不能很好的保护数据

CBC

密码块链接. 每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块

同样的原文生成的密文不一样,但串行处理数据速度慢

填充模式

当需要按块处理的数据的数据长度不符合块处理需求时, 会按照一定的方法规则填充满块

NoPadding:不填充

DES加密算法:要求原文长度必须是8byte的整数倍

AES加密算法: 要求原文长度必须是16byte的整数倍

PKCS5Padding:填充

数据块的大小为8位, 不够就补足

注意:

默认情况下, 加密模式和填充模式为 : ECB/PKCS5Padding。如果使用CBC模式, 在初始化Cipher对象时, 需要添加初始化向量IV参数 : IvParameterSpec iv = new IvParameterSpec(key.getBytes());

测试加密模式与填充模式

Cipher的加密类型如下:

aes ecb nopadding 在线加密_安全


1.使用默认ECB加密模式与PKCS5Padding填充模式

public static void main(String[] args) throws Exception {
        // 原文
        String input = "Hello Word";
        // 使用des进行加密,密钥必须是8个字节
        String key = "12345678";
        // 获取Cipher对象的算法;如果没有指定加密模式和填充模式,默认值:ECB/PKCS5Padding
        String transformation = "DES";
        // 指定获取密钥的算法
        String algorithm = "DES";

        String encrypt = encrypt(input, key, transformation, algorithm);
        System.out.println("加密:" + encrypt);
        String decrypt = dncrypt(encrypt, key, transformation, algorithm);
        System.out.println("解密:" + decrypt);
    }
bytes = �Rd��ʩ� h�� 
加密:01Jk6AecyqnqsABousAVIA==
解密:Hello Word

2.明确指定ECB加密模式和PKCS5Padding填充模式

public static void main(String[] args) throws Exception {
        // 原文
        String input = "Hello Word";
        // 使用des进行加密,密钥必须是8个字节
        String key = "12345678";
        // 获取Cipher对象的算法;如果没有指定加密模式和填充模式,默认值:ECB/PKCS5Padding
        String transformation = "DES/ECB/PKCS5Padding";
        // 指定获取密钥的算法
        String algorithm = "DES";

        String encrypt = encrypt(input, key, transformation, algorithm);
        System.out.println("加密:" + encrypt);
        String decrypt = dncrypt(encrypt, key, transformation, algorithm);
        System.out.println("解密:" + decrypt);
    }
bytes = �Rd��ʩ� h�� 
加密:01Jk6AecyqnqsABousAVIA==
解密:Hello Word

3.明确指定ECB加密模式和NoPadding填充模式

此时原文必须为8byte的整数倍,否则报错:Input length not multiple of 8 bytes

public static void main(String[] args) throws Exception {
        // 原文
        String input = "Hello Wo";
        // 使用des进行加密,密钥必须是8个字节
        String key = "12345678";
        // 获取Cipher对象的算法;如果没有指定加密模式和填充模式,默认值:ECB/PKCS5Padding
        String transformation = "DES/ECB/NoPadding";
        // 指定获取密钥的算法
        String algorithm = "DES";

        String encrypt = encrypt(input, key, transformation, algorithm);
        System.out.println("加密:" + encrypt);
        String decrypt = dncrypt(encrypt, key, transformation, algorithm);
        System.out.println("解密:" + decrypt);
    }
bytes = �Rd��ʩ
加密:01Jk6Aecyqk=
解密:Hello Wo

4.明确指定CBC加密模式和PKCS5Padding填充模式

public static void main(String[] args) throws Exception {
        // 原文
        String input = "Hello Word";
        // 使用des进行加密,密钥必须是8个字节
        String key = "12345678";
        // 获取Cipher对象的算法;如果没有指定加密模式和填充模式,默认值:ECB/PKCS5Padding
        String transformation = "DES/CBC/PKCS5Padding";
        // 指定获取密钥的算法
        String algorithm = "DES";

        String encrypt = encrypt(input, key, transformation, algorithm);
        System.out.println("加密:" + encrypt);
        String decrypt = dncrypt(encrypt, key, transformation, algorithm);
        System.out.println("解密:" + decrypt);
    }

    /**
     * 加密数据
     */
    private static String encrypt(String input, String key, String transformation, String algorithm) throws Exception {
        // 获取加密对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 指定秘钥规则:传入密钥的字节数组与指定的算法
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        // 初始向量,参数表示跟谁进行异或,初始向量的长度必须是8位
        IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
        // 初始化加密对象: 指定加密模式与秘钥规则
        cipher.init(Cipher.ENCRYPT_MODE, sks, ivParameterSpec);
        // 开始加密
        byte[] bytes = cipher.doFinal(input.getBytes());
        // 打印密文,由于bytes字节数字中存在负数,即ascii码有负数,解析不出来,将输出乱码
        System.out.println("bytes = " + new String(bytes));
        // 对字节数字进行Base64编码
        return Base64.encode(bytes);
    }

    /**
     * 解密数据
     */
    private static String dncrypt(String input, String key, String transformation, String algorithm) throws Exception {
        // 获取Cipher对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 指定秘钥规则:传入密钥的字节数组与指定的算法
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        // 初始向量,参数表示跟谁进行异或,初始向量的长度必须是8位
        IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
        // 初始化解密对象: 指定解密模式与秘钥规则
        cipher.init(Cipher.DECRYPT_MODE, sks, ivParameterSpec);
        // 解密
        byte[] bytes = cipher.doFinal(Base64.decode(input));
        return new String(bytes);
    }
bytes = �uQ�w�AоH~�q
加密:w3VRu3f3QdC+E0h+2gRxfw==
解密:Hello Word