一、简介

1.1 ECB模式

  ECB(Electronic Codebook,电码本)模式是分组密码的一种最基本的工作模式。在该模式下,待处理信息被分为大小合适的分组,然后分别对每一分组独立进行加密或解密处理。其特点如下:

  • 操作简单
  • 利于实现并行处理(由于其分组的独立性)
  • 能防止误差传播
  • 可能对明文进行主动攻击(不能隐藏明文)

ECB加密过程:

  将数据按照8个字节一段进行DES加密得到一段8个字节的密文或者明文,最后一段不足8个字节,按照需求补足8个字节进行计算,之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。

1.2 CBC模式

  CBC指的是密码分组链接(Cipher-block chaining)的简称。在CBC模式中,每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块。同时,为了保证每条消息的唯一性,在第一个块中需要使用初始化向量。其特点如下:

  • 不容易主动攻击,是SSL、IPSec的标准,安全性好于ECB
  • 加密过程是串行的,无法被并行化
  • 存在误差传递
  • 需要初始化向量IV

CBC加密过程:

  1. 首先将数据按照8个字节一组进行分组得到D1D2D3…Dn(若数据不是8的整数倍,用指定的PADDING数据补位)
  2. 第一组数据D1与初始化向量I异或后的结果进行DES加密得到第一组密文C1
  3. 第二组数据D2与第一组的加密结果C1异或以后的结果进行DES加密,得到第二组密文C2
  4. 之后的数据以此类推,得到Cn
  5. 按顺序连为C1C2C3…Cn即为加密结果。

1.3 填充(PADDING)

  NoPadding: 加密内容不足8位用0补足8位, Cipher类不提供补位功能,需自己实现代码给加密内容添加0, 如{36,36,36,0,0,0,0,0}
  PKCS5Padding: 加密内容不足8位用余位数补足8位, 如{22,22,22,22,4,4,4,4}或者{28,28,28,28,28,3,3,3}刚好8位补8位8
  在PKCS5Padding中,明确定义Block的大小是8位,而在PKCS7Padding定义中,对于块的大小是不确定的,可以在1-255之间(块长度超出255的尚待研究),填充值的算法都是一样的:填充值=块大小 - (数据长度%块大小)
如上面的例子:
  {22,22,22,22}
  填充值 = 8 -(4%8)= 4
  {22,22,22,22,4,4,4,4}

1.4 3DES加解密

  3DES算法顾名思义就是3次DES算法。它以DES为基本模块,通过组合分组方法设计出分组加密算法。比起最初的DES,3DES更为安全
  设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,PP代表明文,RR代表密表,则:
  3DES加密过程为:RR=Ek3(Dk2(Ek1(PP)))
  3DES解密过程为:PP=Dk1((EK2(Dk3(RR)))
  这里可以K1=K3,但不能K1=K2=K3(不然就成了DES算法了)

废话不多说,直接上工具类!

二、3Des工具类(包含CBC和ECB)

DesUtil.java

包含CBC和ECB两种工作模式

package com.alian.csdn.utils;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

/**
 * @program: CSDN
 * @description: 3des工具类
 * @author: Alian
 * @create: 2021-06-04 11:20:10
 **/
public class DesUtil {

    private static final String ALGORITHM = "DESede";
    //格式为:算法/工作模式/填充模式
    private static final String DESEDE_CBC_PADDING = "DESede/CBC/PKCS5Padding";
    private static final String DESEDE_ECB_PADDING = "DESede/ECB/PKCS5Padding";

    private static Key getSecretKey(byte[] key) {//
        try {
            //创建一个DESedeKeySpec密钥规范对象
            DESedeKeySpec spec = new DESedeKeySpec(key);
            //转换指定算法的密钥的SecretKeyFactory对象(这里是:desede)
            SecretKeyFactory keyfactory = SecretKeyFactory.getInstance(DesUtil.ALGORITHM);
            //根据提供的密码密钥规范生成SecretKey对象。
            return keyfactory.generateSecret(spec);
        } catch (InvalidKeyException e) {
            throw new RuntimeException("DES获取密钥出现错误,非法key异常");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("DES获取密钥出现错误,算法异常");
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("DES获取密钥出现错误,密钥规范异常");
        }
    }

    /**
     * 3Des加密(CBC工作模式)
     *
     * @param key   密钥,key长度必须大于等于 3*8 = 24
     * @param keyIv 初始化向量,keyIv长度必须等于8
     * @param data  明文
     * @return 密文
     * @throws Exception
     */
    public static byte[] encodeByCBC(byte[] key, byte[] keyIv, byte[] data)
            throws Exception {
        //获取SecretKey对象
        Key secretKey = getSecretKey(key);
        //获取指定转换的密码对象Cipher(参数:算法/工作模式/填充模式)
        Cipher cipher = Cipher.getInstance(DESEDE_CBC_PADDING);
        //创建向量参数规范也就是初始化向量
        IvParameterSpec ips = new IvParameterSpec(keyIv);
        //用密钥和一组算法参数规范初始化此Cipher对象(加密模式)
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ips);
        //执行加密操作
        return cipher.doFinal(data);
    }

    /**
     * 3Des加密(ECB工作模式)
     *
     * @param key   密钥,key长度必须大于等于 3*8 = 24
     * @param keyIv 初始化向量,keyIv长度必须等于8
     * @param data  密文
     * @return 明文
     * @throws Exception
     */
    public static byte[] decodeByCBC(byte[] key, byte[] keyIv, byte[] data)
            throws Exception {
        //获取SecretKey对象
        Key secretKey = getSecretKey(key);
        //获取指定转换的密码对象Cipher(参数:算法/工作模式/填充模式)
        Cipher cipher = Cipher.getInstance(DESEDE_CBC_PADDING);
        //创建向量参数规范也就是初始化向量
        IvParameterSpec ips = new IvParameterSpec(keyIv);
        //用密钥和一组算法参数规范初始化此Cipher对象(加密模式)
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ips);
        //执行加密操作
        return cipher.doFinal(data);
    }

    /**
     * 3Des加密(ECB工作模式),不要IV
     *
     * @param key  密钥,key长度必须大于等于 3*8 = 24
     * @param data 明文
     * @return 密文
     * @throws Exception
     */
    public static byte[] encodeByECB(byte[] key, byte[] data) throws Exception {
        //获取SecretKey对象
        Key secretKey = getSecretKey(key);
        //获取指定转换的密码对象Cipher(参数:算法/工作模式/填充模式)
        Cipher cipher = Cipher.getInstance(DESEDE_ECB_PADDING);
        //用密钥和一组算法参数规范初始化此Cipher对象(加密模式)
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        //执行加密操作
        return cipher.doFinal(data);
    }

    /**
     * 3Des解密(ECB工作模式),不要IV
     *
     * @param key  密钥,key长度必须大于等于 3*8 = 24
     * @param data 密文
     * @return 明文
     * @throws Exception
     */
    public static byte[] decodeByECB(byte[] key, byte[] data) throws Exception {
        //获取SecretKey对象
        Key secretKey = getSecretKey(key);
        //获取指定转换的密码对象Cipher(参数:算法/工作模式/填充模式)
        Cipher cipher = Cipher.getInstance(DESEDE_ECB_PADDING);
        //用密钥和一组算法参数规范初始化此Cipher对象(加密模式)
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        //执行加密操作
        return cipher.doFinal(data);
    }
}

三、实践

3.1 CBC模式的加密和解码

    /**
     * 3DES加密之CBC加密、解密
     * 此处单元测试的注解是采用:org.junit.Test
     * @throws Exception
     */
    @Test
    public void cbcTest() throws Exception {
        System.out.println("------------------3DES加密之CBC加密、解密------------------");
        String desKey = "4c1ab02124f0941fbc01f902be421843";
        String plainText = "https://blog.csdn.net/Alian_1223";
        System.out.println("CBC加密原始数据:" + plainText);
        byte[] key = desKey.getBytes(StandardCharsets.UTF_8);
        byte[] keyIv = {1, 2, 3, 4, 5, 6, 7, 8};
        byte[] data = plainText.getBytes(StandardCharsets.UTF_8);
        byte[] encode = DesUtil.encodeByCBC(key, keyIv, data);
        System.out.println("CBC加密后的数据:" + ArrayUtils.toString(encode));
        System.out.println("CBC加密后转Base64的数据:" + Base64.getEncoder().encodeToString(encode));
        byte[] decodeStr = DesUtil.decodeByCBC(key, keyIv, encode);
        System.out.println("CBC解密后转字符串数据:" + new String(decodeStr, StandardCharsets.UTF_8));
    }

运行结果:

------------------3DES加密之CBC加密、解密------------------
CBC加密原始数据:https://blog.csdn.net/Alian_1223
CBC加密后的数据:{87,-84,-88,40,-125,85,-73,5,-13,-42,-127,10,64,-122,92,-1,-68,49,-49,79,-63,-48,-43,-62,-88,-110,44,-7,-104,70,85,-51,-102,69,45,122,-12,67,116,-90}
CBC加密后转Base64的数据:V6yoKINVtwXz1oEKQIZc/7wxz0/B0NXCqJIs+ZhGVc2aRS169EN0pg==
CBC解密后转字符串数据:https://blog.csdn.net/Alian_1223

3.2 ECB模式的加密和解码

    /**
     * 3DES加密之ECB加密、解密
     * 此处单元测试的注解是采用:org.junit.Test
     * @throws Exception
     */
    @Test
    public void ecbTest() throws Exception {
        System.out.println("------------------3DES加密之ECB加密、解密------------------");
        String desKey = "4c1ab02124f0941fbc01f902be421843";
        String plainText = "https://blog.csdn.net/Alian_1223";
        System.out.println("ECB加密原始数据:" + plainText);
        byte[] key = desKey.getBytes(StandardCharsets.UTF_8);
        byte[] data = plainText.getBytes(StandardCharsets.UTF_8);
        byte[] encode = DesUtil.encodeByECB(key, data);
        System.out.println("ECB加密后的数据:" + ArrayUtils.toString(encode));
        System.out.println("ECB加密后转Base64的数据:" + Base64.getEncoder().encodeToString(encode));
        byte[] decodeStr = DesUtil.decodeByECB(key, encode);
        System.out.println("ECB解密后转字符串数据:" + new String(decodeStr, StandardCharsets.UTF_8));
    }

运行结果:

------------------3DES加密之ECB加密、解密------------------
ECB加密原始数据:3DES工具类的加密、解密(工作模式包含CBC和ECB)
ECB加密后的数据:{39,-78,-91,94,127,-81,75,-17,-7,64,-78,68,31,-76,39,57,27,37,-28,-19,-5,-87,86,115,36,21,61,-39,-58,-27,-39,106,-103,73,-102,74,64,-25,-26,-2,-68,53,96,-46,-109,7,-22,36,-33,71,28,-74,-81,-95,-108,89,-42,7,-73,66,-72,93,7,-37,121,-69,25,-23,67,-124,48,4}
ECB加密后转Base64的数据:J7KlXn+vS+/5QLJEH7QnORsl5O37qVZzJBU92cbl2WqZSZpKQOfm/rw1YNKTB+ok30cctq+hlFnWB7dCuF0H23m7GelDhDAE
ECB解密后转字符串数据:3DES工具类的加密、解密(工作模式包含CBC和ECB)

结语

  以上就是今天要讲的内容,本文仅仅简单介绍了3DES,简单编写了一个DesUtil工具类,包含了CBC和ECB两种模式,有兴趣的同学可以先去了解一下DES算法的原理,然后再研究3DES,如果对您有帮助,欢迎大家评论交流。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐