【Java】对称加密DES和AES

前言

对称加密,加密和解密用的同一个秘钥,也叫单密钥加密。

1、 核心原理

流加密和块加密

  • 流加密(序列密码):是对信息中的每一个元素(一个字母或者一个比特)作为基础的处理单元进行加密。
    例如:1234678 先加密1再加密2再见3,以此类推。
  • 块加密(分组密码):是先对信息进行分块,在对每一块分别加密。
    例如:1234678 先分块 分为 1234 和 5678 再先加密1234 再加密5678。
2、 特点
  • 加密速度快,可加密大文件。
  • 密文可逆,一旦秘钥文件泄露,就会导致数据暴露。
  • 加密后编码表找不到对应字符出现乱码。
  • 一般结合Base64使用。
3、 常见的加密算法

DES加解密,key必须8个字节
AES加解密,key必须16个字节

4、 加密模式

加密模式:ECB、CBC

  • ECB Electronic code book 电子密码本,需要加密的消息按照块密码的大小被分为数个块,并对每个块进行独立加密。
    在这里插入图片描述
    优点:可以并行处理数据
    缺点:同样的原文生成同样的密文,不能很好的保护数据,
    同时加密,原文是一样的,加密出来的密文也是一样的。
  • CBC Cipher-block chaining 密码块连接,每个明文块先和前一个密文块进行异或后,在进行加密。这样每个密文块都依赖了他前面的所有明文块。
    在这里插入图片描述
    优点:同样的原文生成不一样的密文
    缺点:串行处理数据,加密慢
    CBC模式需要指定iv变量
5、 填充模式

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

  • NoPadding
    1、不填充
    2、在DES加密算法下,要求原文长度必须是8Byte的整数倍。
    3、在AES加密算法下,要求原文长度必须是16Byte的整数倍.
  • PKCS5Padding
    数据块的大小为8位不够就补充,先分块,最后一个可能够8位,也不够8位,不够时就补全。
6、DES加密实现
package com.lh.basecryptology.desaes;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class DesDemo {

    public static void main(String[] args) throws Exception {
        // 原文
        String text = "十里洋场,遍地黄金";
        // 密钥 如果用Des加密密钥必须8位
        String key = "12345678";
        // 算法
        // DES 默认是 DES/ECB/PKCS5Padding
        String transformation = "DES";
        // DES/ECB/PKCS5Padding URi9FEpJ67KLV+LYiQjmRZ+dulH/ltTO5ejvMir6dwo=
        // String transformation = "DES/ECB/PKCS5Padding";
        System.out.println("==========" + transformation);
        // 加密类型 ECB/PKCS5Padding
        String algorithm = "DES";
        String encrypt = encryptECB(text, key, transformation, algorithm);
        System.out.println("密文ECB:" + encrypt);
        String decrypt = decryptECB(encrypt, key, transformation, algorithm);
        System.out.println("原文ECB:" + decrypt);

        // 加密类型 ECB/PKCS5Padding
        transformation = "DES/ECB/NoPadding";
        System.out.println("==========" + transformation);
        String encryptNoPadding = encryptNoPadding(text, key, transformation, algorithm);
        System.out.println("密文ECBNoPadding:" + encryptNoPadding);
        String decryptNoPadding = decryptECB(encrypt, key, transformation, algorithm);
        System.out.println("原文ECBNoPadding:" + decryptNoPadding);

        // 加密模式为CBC时需要指定iv向量
        transformation = "DES/CBC/PKCS5Padding";
        System.out.println("==========" + transformation);
        String encryptCBC = encryptCBC(text, key, "DES/CBC/PKCS5Padding", algorithm);
        System.out.println("密文CBC:" + encryptCBC);
        String decryptCBC = decryptCBC(encryptCBC, key, "DES/CBC/PKCS5Padding", algorithm);
        System.out.println("原文CBC:" + decryptCBC);

    }

    /**
     * 使用DES加密
     *
     * @param text           原文
     * @param key            密钥
     * @param transformation 加密算法
     * @param algorithm      加密类型
     * @throws Exception
     */
    private static String encryptECB(String text, String key, String transformation, String algorithm) throws Exception {
        //创建加密对象 transformation加密算法
        Cipher cipher = Cipher.getInstance(transformation);
        //创建加密规则 第一个参数key字节 第二个参数表示加密类型
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm);
        // 进行加密初始化 第一个参数表示模式 加密模式和解密模式 第二个参数表示加密规则
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        // 调用加密方法
        // 参数是原文的字节数组
        byte[] bytes = cipher.doFinal(text.getBytes());
        /*for (byte aByte : bytes) {
            System.out.println(aByte);
        }
        // 如果直接打印密文会出现乱码,是因为在编码表里面找不到对应的字符,ascii码只有正数
        System.out.println(new String(bytes));*/
        // 使用base64 转码
        return Base64.encode(bytes);
    }

    /**
     * 解密
     *
     * @param encrypt        密文
     * @param key            秘钥
     * @param transformation 加密算法
     * @param algorithm      机密类型
     * @return 解密后的内容
     */
    private static String decryptECB(String encrypt, String key, String transformation, String algorithm) throws Exception {
        byte[] decode = Base64.decode(encrypt);
        Cipher cipher = Cipher.getInstance(transformation);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm);
        // 进行加密初始化 第一个参数表示模式 加密模式和解密模式 第二个参数表示加密规则
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
        // 调用解密方法
        byte[] bytes = cipher.doFinal(decode);
        return new String(bytes);
    }

    /**
     * 使用DES加密
     *
     * @param text           原文
     * @param key            密钥
     * @param transformation 加密算法
     * @param algorithm      加密类型
     * @throws Exception
     */
    private static String encryptCBC(String text, String key, String transformation, String algorithm) throws Exception {
        //创建加密对象 transformation加密算法
        Cipher cipher = Cipher.getInstance(transformation);
        //创建加密规则 第一个参数key字节 第二个参数表示加密类型
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm);
        // 创建IV向量 在使用iv向量是 iv的字节也必须要8个字节
        IvParameterSpec iv = new IvParameterSpec(key.getBytes());
        // 进行加密初始化 第一个参数表示模式 加密模式和解密模式 第二个参数表示加密规则
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);
        // 调用加密方法
        // 参数是原文的字节数组
        byte[] bytes = cipher.doFinal(text.getBytes());
        /*for (byte aByte : bytes) {
            System.out.println(aByte);
        }
        // 如果直接打印密文会出现乱码,是因为在编码表里面找不到对应的字符,ascii码只有正数
        System.out.println(new String(bytes));*/
        // 使用base64 转码
        return Base64.encode(bytes);
    }

    /**
     * 解密
     *
     * @param encrypt        密文
     * @param key            秘钥
     * @param transformation 加密算法
     * @param algorithm      机密类型
     * @return 解密后的内容
     */
    private static String decryptCBC(String encrypt, String key, String transformation, String algorithm) throws Exception {
        byte[] decode = Base64.decode(encrypt);
        Cipher cipher = Cipher.getInstance(transformation);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm);
        // 创建IV向量
        IvParameterSpec iv = new IvParameterSpec(key.getBytes());
        // 进行加密初始化 第一个参数表示模式 加密模式和解密模式 第二个参数表示加密规则
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv);
        // 调用解密方法
        byte[] bytes = cipher.doFinal(decode);
        return new String(bytes);
    }

    /**
     * 使用DES加密
     *
     * @param text           原文
     * @param key            密钥
     * @param transformation 加密算法
     * @param algorithm      加密类型
     * @throws Exception
     */
    private static String encryptNoPadding(String text, String key, String transformation, String algorithm) throws Exception {
        //创建加密对象 transformation加密算法
        Cipher cipher = Cipher.getInstance(transformation);
        //创建加密规则 第一个参数key字节 第二个参数表示加密类型
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm);
        // 进行加密初始化 第一个参数表示模式 加密模式和解密模式 第二个参数表示加密规则
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        // 调用加密方法
        // 参数是原文的字节数组
        return Base64.encode(cipher.doFinal(addZero(text.getBytes())));
    }

    /**
     * NoPadding 补0
     * 在DES加密算法下,要求原文长度必须是8Byte的整数倍。
     * 在AES加密算法下,要求原文长度必须是16Byte的整数倍.
     *
     * @param data 数组
     * @return 补0之后
     */
    private static byte[] addZero(byte[] data) {
        byte[] dataByte = data;
        if (data.length % 8 != 0) {
            byte[] temp = new byte[8 - data.length % 8];
            dataByte = byteMerger(data, temp);
        }
        return dataByte;
    }

    /**
     * java 合并两个byte数组
     * System.arraycopy()方法
     *
     * @param bt1 数组1
     * @param bt2 数组2
     * @return 合并结果
     */
    private static byte[] byteMerger(byte[] bt1, byte[] bt2) {
        byte[] bt3 = new byte[bt1.length + bt2.length];
        System.arraycopy(bt1, 0, bt3, 0, bt1.length);
        System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
        return bt3;
    }
}
7、AES加密实现
package com.lh.basecryptology.desaes;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class AesDemo {

    public static void main(String[] args) throws Exception {
        // 原文
        String text = "十里洋场,遍地黄金";
        // 密钥 如果用AES加密密钥必须16个字节
        String key = "1234567812345678";
        // 算法
        String transformation = "AES";
        // 加密类型
        String algorithm = "AES";
        String encrypt = encryptAES(text, key, transformation, algorithm);
        System.out.println("密文:" + encrypt);
        String decrypt = decryptAES(encrypt, key, transformation, algorithm);
        System.out.println("原文:" + decrypt);

    }

    /**
     * 解密
     *
     * @param encrypt        密文
     * @param key            秘钥
     * @param transformation 加密算法
     * @param algorithm      机密类型
     * @return 解密后的内容
     */
    private static String decryptAES(String encrypt, String key, String transformation, String algorithm) throws Exception {
        byte[] decode = Base64.decode(encrypt);
        Cipher cipher = Cipher.getInstance(transformation);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm);
        // 进行AES加密初始化 第一个参数表示模式 加密模式和解密模式 第二个参数表示加密规则
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
        // 调用解密方法
        byte[] bytes = cipher.doFinal(decode);
        return new String(bytes);
    }

    /**
     * 使用AES加密
     *
     * @param text           原文
     * @param key            密钥
     * @param transformation 加密算法
     * @param algorithm      加密类型
     * @throws Exception
     */
    private static String encryptAES(String text, String key, String transformation, String algorithm) throws Exception {
        //创建加密对象 transformation加密算法
        Cipher cipher = Cipher.getInstance(transformation);
        //创建加密规则 第一个参数key字节 第二个参数表示加密类型
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm);
        // 进行AES加密初始化 第一个参数表示模式 加密模式和解密模式 第二个参数表示加密规则
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        // 调用加密方法
        // 参数是原文的字节数组
        byte[] bytes = cipher.doFinal(text.getBytes());
        /*for (byte aByte : bytes) {
            System.out.println(aByte);
        }
        // 如果直接打印密文会出现乱码,是因为在编码表里面找不到对应的字符,ascii码只有正数
        System.out.println(new String(bytes));*/
        // 使用base64 转码
        return Base64.encode(bytes);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值