侧边栏壁纸
博主头像
Easy to understand and humorous

行动起来,活在当下

  • 累计撰写 39 篇文章
  • 累计创建 4 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

对称加密算法: DES、3DES、AES

fengyang
2025-07-25 / 0 评论 / 0 点赞 / 10 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

DES

DES 全称 Data Encryption Standard,是一种使用密钥加密的块算法。 密钥8个字节(DES使用56位的密钥和64位的明文块进行加密)。

DES采用16轮运算,每轮产生一个轮密匙参与到运算中。

虽然DES算法的分组大小是64位,但是由于DES算法的密钥长度只有56位,因此DES算法存在着弱点,容易受到暴力破解和差分攻击等攻击手段的威胁。 因此,在实际应用中,DES算法已经不再被广泛使用,而被更加安全的算法所取代,如AES算法等。 尽管如此,该加密算法还是运用非常普遍,是一种标准的加密算法,3DES 是 DES 的加强版本。

DES 加密算法出自 IBM 的研究,后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少, 因为 DES 使用56位密钥(密钥长度越长越安全),以现代计算能力24小时内即可被破解。

虽然如此,在某些简单应用中,我们还是可以使用 DES 加密算法。

加密与解密代码样例

Java

加密

private static String desEncrypt(byte[] skey, String input) throws Exception {
    // 实例化DES密钥材料, 使用 b 中的前8个字节作为DES密钥的内容
    DESKeySpec dks = new DESKeySpec(skey);
    // 实例化秘钥工厂
    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
    // 生成秘钥
    SecretKey secretKey = secretKeyFactory.generateSecret(dks);

    // 实例化
//        Cipher cipher = Cipher.getInstance(secretKeyFactory.getAlgorithm());
    Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
    // 初始化。设置为加密模式
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    // 执行
    byte[] data = cipher.doFinal(input.getBytes());

    String basee64Data = Base64.encodeBase64String(data);
    System.out.println(basee64Data);

    return basee64Data;
}

解密

private static String desDecrypt(byte[] skey, String encBase64Data) throws Exception {
    byte[] encData = Base64.decodeBase64(encBase64Data);

    // 实例化DES密钥材料, 使用 b 中的前8个字节作为DES密钥的内容
    DESKeySpec dks = new DESKeySpec(skey);
    // 实例化秘钥工厂
    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
    // 生成秘钥
    SecretKey secretKey = secretKeyFactory.generateSecret(dks);

    // 实例化
//        Cipher cipher = Cipher.getInstance(secretKeyFactory.getAlgorithm());
    Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
    // 初始化。设置为加密模式
    cipher.init(Cipher.DECRYPT_MODE, secretKey);
    // 执行
    byte[] s = cipher.doFinal(encData);

    String rs = new String(s);
    System.out.println(rs);

    return rs;
}

CryptoJS

加密

/**
 * DES 加密
 *
 * @param data 加密的byte数据
 * @param key 私钥的byte数据
 * @returns {*}
 */
function desEncrypt(data, skey){
    var key = CryptoJS.enc.Utf8.parse(skey);

    var encrypted =  CryptoJS.DES.encrypt(data, key, /* cfg */ {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7 // 包含 PKCS5Padding
    });

    return encrypted.ciphertext.toString();
}

解密

/**
 * DES 解密
 */
function desDecrypt(encrypt_data, skey){
    var key = CryptoJS.enc.Utf8.parse(skey);

    var decrypted =  CryptoJS.DES.decrypt(
        {
            ciphertext: CryptoJS.enc.Hex.parse(encrypt_data)
        },
        key,
        /* cfg */ {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7 // 包含 PKCS5Padding
        });

    return decrypted.toString(CryptoJS.enc.Utf8)
}

注意

注意,密钥必须是8的倍数,否则会报 java.security.InvalidKeyException: Wrong key size。

DES 标准密钥就是56位,8个字符即8个字节,每个字节的最高位不用,即每个字节只用7位,8个字符正好是56位。

3DES

3DES(或称为 Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。

它相当于是对每个数据块应用三次 DES 加密算法, 使用3条56位的密钥对数据进行三次加密。 由于计算机运算能力的增强,原版 DES 密码的密钥长度变得容易被暴力破解; 3DES 即是设计用来提供一种相对简单的方法,即通过增加 DES 的密钥长度来避免类似的攻击, 而不是设计一种全新的块密码算法。

3DES(即Triple DES)是 DES 向 AES 过渡的加密算法,它使用3条56位的密钥对数据进行三次加密, 是 DES 的一个更安全的变形。 密钥24个字节(3DES的密钥长度为168位)。

它以 DES 为基本模块,通过组合分组方法设计出分组加密算法。比起最初的 DES,AES 更为安全。

加密与解密代码样例

Java

加密

private static String desedeEncrypt(byte[] skey, String input) throws Exception {
    // 实例化DES密钥材料, 使用 b 中的前8个字节作为DES密钥的内容
    DESedeKeySpec dks = new DESedeKeySpec(skey);
    // 实例化秘钥工厂
    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
    // 生成秘钥
    SecretKey secretKey = secretKeyFactory.generateSecret(dks);

    // 实例化
    Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
    // 初始化。设置为加密模式
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    // 执行
    byte[] data = cipher.doFinal(input.getBytes());

    String basee64Data = Base64.encodeBase64String(data);
    System.out.println(basee64Data);

    return basee64Data;
}

解密

private static String desedeDecrypt(byte[] skey, String encBase64Data) throws Exception {
    byte[] encData = Base64.decodeBase64(encBase64Data);

    // 实例化DES密钥材料, 使用 b 中的前8个字节作为DES密钥的内容
    DESedeKeySpec dks = new DESedeKeySpec(skey);
    // 实例化秘钥工厂
    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
    // 生成秘钥
    SecretKey secretKey = secretKeyFactory.generateSecret(dks);

    // 实例化
    Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
    // 初始化。设置为加密模式
    cipher.init(Cipher.DECRYPT_MODE, secretKey);
    // 执行
    byte[] s = cipher.doFinal(encData);

    String rs = new String(s);
    System.out.println(rs);

    return rs;
}

AES

Advanced Encryption Standard。

AES 加密算法采用分组密码体制,每个分组数据的长度为128位16个字节,密钥长度可以是128位16个字节、192位或256位, 一共有四种加密模式,我们通常采用需要初始向量 IV 的 CBC 模式,初始向量的长度也是128位16个字节。

在AES中,分组长度只能是128 bit,也就是16个字节。(1个字节等于8位,1 Byte = 8 Bit)。 密钥长度可以为三者中的任意一种。最广泛 的使用是密钥128 bit,迭代轮数10轮。

AES 根据秘钥不同的分类

AES算法流程图

Rijndael算法是基于代换-置换网络(SPN,Substitution-permutation network)的迭代算法。

明文数据经过多轮次的转换后方能生成密文,每个轮次的转换操作由轮函数定义。

轮函数任务就是根据密钥编排序列(即轮密码)对数据进行不同的代换及置换等操作。

AES算法流程图

AES 加密的五个关键词,分别是:分组密码体制、Padding、密钥、初始向量 IV 和四种加密模式。

分组密码体制

所谓分组密码体制就是指将明文切成一段一段的来加密,然后再把一段一段的密文拼起来形成最终密文的加密方式。

AES 采用分组密码体制,即 AES 加密会首先把明文切成一段一段的,而且每段数据的长度要求必须是128位16个字节, 如果最后一段不够16个字节了,就需要用 Padding 来把这段数据填满16个字节,然后分别对每段数据进行加密, 最后再把每段加密数据拼起来形成最终的密文。

Padding

Padding 就是用来把不满16个字节的分组数据填满16个字节用的。

它有三种模式 PKCS5、PKCS7 和NOPADDING。

PKCS5 是指分组数据缺少几个字节,就在数据的末尾填充几个字节的几,比如缺少5个字节,就在末尾填充5个字节的5。

PKCS7 是指分组数据缺少几个字节,就在数据的末尾填充几个字节的0,比如缺少7个字节,就在末尾填充7个字节的0。

NoPadding 是指不需要填充,也就是说数据的发送方肯定会保证最后一段数据也正好是16个字节。

那如果在PKCS5 模式下,最后一段数据的内容刚好就是16个16怎么办? 那解密端就不知道这一段数据到底是有效数据还是填充数据了。 因此对于这种情况,PKCS5 模式会自动帮我们在最后一段数据后再添加16个字节的数据,而且填充数据也是16个16, 这样解密段就能知道谁是有效数据谁是填充数据了。 PKCS7 最后一段数据的内容是16个0,也是同样的道理。

解密端需要使用和加密端同样的 Padding 模式,才能准确的识别有效数据和填充数据。

我们开发通常采用 PKCS7 Padding 模式。

初始向量IV

初始向量 IV 的作用是使加密更加安全可靠,我们使用 AES 加密时需要主动提供初始向量, 而且只需要提供一个初始向量就够了,后面每段数据的加密向量都是前面一段的密文。

初始向量 IV 的长度规定为128位16个字节,初始向量的来源为随机生成。

密钥

AES 要求密钥的长度可以是128位16个字节、192位或者256位,位数越高,加密强度自然越大, 但是加密的效率自然会低一些,因此要做好衡量。

通常采用128位16个字节的密钥,使用 AES 加密时需要主动提供密钥,而且只需要提供一个密钥就够了, 每段数据加密使用的都是这一个密钥,密钥来源为随机生成。

四种加密模式

AES 一共有四种加密模式,分别是:

  • ECB(电子密码本模式)
  • CBC(密码分组链接模式)
  • CFB
  • OFB

我们一般使用的是 CBC 模式。

四种模式中除了 ECB 相对不安全之外,其它三种模式的区别并没有那么大。

ECB 模式是最基本的加密模式,即仅仅使用明文和密钥来加密数据,相同的明文块会被加密成相同的密文块, 这样明文和密文的结构将是完全一样的,就会更容易被破解,相对来说不是那么安全,因此很少使用。

而 CBC 模式则比 ECB 模式多了一个初始向量 IV,加密的时候,第一个明文块会首先和初始向量 IV 做异或操作, 然后再经过密钥加密,然后第一个密文块又会作为第二个明文块的加密向量来异或,依次类推下去, 这样相同的明文块加密出的密文块就是不同的,明文的结构和密文的结构也将是不同的, 因此更加安全,我们常用的就是 CBC 加密模式。

加密与解密代码样例

Java

加密

private static String aesEncrypt(byte[] skey, String input) throws Exception {
    SecretKeySpec key = new SecretKeySpec(skey, "AES");

    AlgorithmParameterSpec iv = new IvParameterSpec(skey, 0, 16);

    // 实例化
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    // 初始化。设置为加密模式
    cipher.init(Cipher.ENCRYPT_MODE, key, iv);
    // 执行
    byte[] bres = cipher.doFinal(input.getBytes());

    String base64Data = Base64.encodeBase64String(bres);
    System.out.println(base64Data);

    return base64Data;
}

解密

private static String aesDecrypt(byte[] skey, String encBase64Data) throws Exception {
    byte[] encData = Base64.decodeBase64(encBase64Data);

    // 生成秘钥
    SecretKeySpec key = new SecretKeySpec(skey, "AES");
    AlgorithmParameterSpec iv = new IvParameterSpec(skey, 0, 16);
    // 实例化
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    // 初始化。设置为加密模式
    cipher.init(Cipher.DECRYPT_MODE, key, iv);
    // 执行
    byte[] s = cipher.doFinal(encData);

    String rs = new String(s, "UTF-8");
    System.out.println(rs);

    return rs;
}
0

评论区