Java实现对称加密算法 DES/3DES/AES

2024-04-17 260点热度 0人点赞 0条评论

一、DES加密算法

1.1 原理

DES是一种对称加密算法,它使用相同的密钥进行加密和解密操作。
DES算法的核心是一个称为Feistel网络的结构,它将明文分成左右两部分,并通过多轮迭代和替换操作来生成密文。

DES算法使用56位密钥(实际上有64位,但其中8位用于奇偶校验),并通过一系列复杂的变换和置换操作来加密数据。
这些操作包括初始置换、16轮Feistel网络、以及逆初始置换等步骤。每一轮Feistel网络都包括替换、置换和异或等操作,以增加加密的复杂性和安全性:

1.1.1. 密钥生成

DES算法使用一个56位的密钥(实际上有64位,但其中8位用于奇偶校验,不参与加密过程),并通过一系列复杂的操作生成16个48位的子密钥,每个子密钥用于加密算法的一轮迭代中。密钥生成的过程包括置换、移位和压缩等操作,以确保生成的子密钥具有足够的随机性和复杂性。

1.1.2. 初始置换

在加密过程的开始,明文数据首先经过一个初始置换操作。这个置换是一个固定的置换表,将明文数据的64位重新排列,以打乱数据的原始顺序。初始置换的目的是为了增加加密算法的复杂性和混淆性。

1.1.3. Feistel网络

DES算法的核心是一个称为Feistel网络的结构。Feistel网络将初始置换后的明文数据分成左右两部分,每部分32位。然后,通过16轮迭代,对这两部分数据进行交替的加密操作。

在每一轮迭代中,Feistel网络使用当前轮的子密钥对右半部分数据进行加密,并将加密结果与左半部分数据进行异或运算。然后,将异或运算的结果作为下一轮的右半部分数据,而将原始的左半部分数据作为下一轮的左半部分数据。这样,左右两部分数据在每一轮迭代中都会进行交换和更新。

每一轮迭代中的加密操作包括扩展置换、S盒代替、P盒置换和异或运算四个步骤。扩展置换将32位的数据扩展成48位,以便与48位的子密钥进行异或运算。S盒代替是一种非线性替换操作,将48位的数据分成8个6位的部分,并分别通过8个不同的S盒进行替换,得到8个4位的结果。P盒置换是一种置换操作,将8个4位的结果合并成一个32位的结果。最后,异或运算将P盒置换的结果与左半部分数据进行异或运算,得到加密后的右半部分数据。

1.1.4. 逆置换

经过16轮迭代后,左右两部分数据再次合并成一个64位的数据,并进行一个逆置换操作。逆置换是初始置换的逆过程,将数据的顺序恢复到加密前的状态。最终得到的数据就是加密后的密文。

需要注意的是,DES加密算法的安全性主要依赖于密钥的保密性和算法的复杂性。然而,由于DES算法使用的密钥长度较短(56位),它已经受到暴力破解攻击的威胁。因此,在实际应用中,建议使用更安全的加密算法,如AES(Advanced Encryption Standard)。AES算法提供了更大的密钥长度和更复杂的加密过程,以提供更高的安全性。

1.2 特点

密钥长度较短:DES使用56位密钥,相对于现代加密算法来说,密钥长度较短,容易受到暴力破解攻击。
加密速度快:由于DES算法相对简单,加密和解密速度较快,适用于对性能要求较高的场景。
安全性较低:由于密钥长度较短和算法设计的局限性,DES算法的安全性已经受到质疑,不再适用于高安全性的应用。

1999 年,distributed.net在 22 小时 15 分钟内破解了一个 DES 密钥,
在这事件发生后,NIST 撤回了该算法作为标准。(现在不建议使用了,推荐使用AES)
为了提高安全性,通常使用3DES(Triple DES)来替代DES。3DES是对DES算法进行三次迭代,使用两个或三个不同的密钥,以增强加密的强度。

二、3DES加密算法

2.1 原理

3DES(Triple DES)是DES算法的一种改进版本,旨在提高安全性。它使用三个不同的密钥对明文进行三次DES加密操作。
具体来说,3DES可以采用两种模式:加密-解密-加密(EDE)模式和加密-加密-解密(EEE)模式。其中,EDE模式更为常用。

在EDE模式下,首先使用第一个密钥对明文进行DES加密;然后使用第二个密钥对加密后的结果进行DES解密;
最后使用第三个密钥再次对解密后的结果进行DES加密。这样,通过增加密钥数量和加密轮数,3DES提高了算法的安全性和复杂性。

2.2 特点

  1. 安全性较高:由于使用了三个密钥和三轮加密操作,3DES算法的安全性相对于DES算法有了显著的提升。它提供了更高的密钥长度和更复杂的加密过程,使得破解更加困难。

  2. 加密速度较慢:与DES算法相比,3DES算法的加密和解密速度较慢。这是因为它需要进行三轮加密操作,每轮操作都需要进行复杂的替换、置换和异或等计算。

  3. 密钥管理较复杂:由于使用了三个密钥,3DES算法的密钥管理相对复杂。需要确保三个密钥的安全性和独立性,以防止密钥泄露和攻击。

三、AES 加密算法(推荐使用)

简介

AES 数据加密是一种在数学上更高效、更优雅的加密算法,由美国国家标准与技术研究院于 2001 年推出。
作为高级加密标准,AES提供三种密钥长度,分别是128 位、192 位和 256 位,密钥长度越高,
破解系统或破解系统所需的时间就越多。因此,AES 被认为比 DES 算法更好。
高级数据加密标准,能够有效抵御已知的针对DES算法的所有攻击。

AES 在通过计算机网络传输数据时被广泛使用,特别是在无线网络中,AES 使用 128 位明文和 128 位密钥来创建 128 位块,
然后对其进行处理以生成 16 字节(128 位)密文。

高级加密标准的加密过程是基于迭代方式的替换和置换操作,16 字节的数据以四列四行的矩阵排列,在这个矩阵上,AES 执行几轮替换置换操作。

这些轮次中的每一轮都使用不同的密码密钥,该密钥是根据原始 AES 密钥计算得出的,操作的轮数取决于密钥的大小,方式如下:

  • 128 位密钥,10 轮
  • 192 位密钥,12 轮
  • 256 位密钥,14 轮

特点

密钥建立时间短、灵敏性好、内存需求低、安全性高

代码demo


import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

public class BaseSymmetry {

    /**
     * 生成DES密钥
     */
    public static SecretKey generateKey(String algorithm) throws Exception {
        //密钥生成器
        KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);

        SecureRandom random = new SecureRandom(String.valueOf(System.currentTimeMillis()).getBytes(StandardCharsets.UTF_8));

        //可指定密钥长度
        switch (algorithm) {
            case "DES": {
                //固定长度56
                keyGenerator.init(56, random);
                break;
            }

            case "DESede": {
                //可指定密钥长度为112或168,默认为168
                // 3DES密钥长度通常是168位,但实际上会使用192位(24字节),最后24位作为奇偶校验位
                keyGenerator.init(168, random);
                break;
            }

            case "AES": {
                //这里可以是 128、192、256、越大越安全
                keyGenerator.init(256, random);
                break;
            }
            default: {
                keyGenerator.init(random);
            }
        }

        //生成key
        return keyGenerator.generateKey();
    }

    /**
     * 将密钥转成字符串
     *
     * @param secretKey
     * @return
     */
    public static String Key2Str(SecretKey secretKey) {
        //密钥数组
        byte[] key = secretKey.getEncoded();
        //转换成字符串
        return Base64.getEncoder().encodeToString(key);
    }

    /**
     * 将使用 Base64 加密后的字符串类型的 secretKey 转为 SecretKey
     *
     * @return SecretKey
     */
    public static SecretKey strKey2SecretKey(String strKey, String algorithm) {
        byte[] bytes = Base64.getDecoder().decode(strKey);
        return new SecretKeySpec(bytes, algorithm);
    }

    /**
     * 加密
     *
     * @param content   待加密内容
     * @param secretKey 加密使用的 AES 密钥
     * @return 加密后的密文 byte[]
     */
    public static byte[] encrypt(byte[] content, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        return cipher.doFinal(content);
    }

    /**
     * 加密
     *
     * @param content   待加密内容
     * @param secretKey 加密使用的 AES 密钥
     * @return 加密后的密文 byte[]
     */
    public static byte[] encrypt(String content, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 解密
     *
     * @param content   待解密内容
     * @param secretKey 解密使用的 AES 密钥
     * @return 解密后的明文 byte[]
     */
    public static byte[] decrypt(String content, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 解密
     *
     * @param content   待解密内容
     * @param secretKey 解密使用的 AES 密钥
     * @return 解密后的明文 byte[]
     */
    public static byte[] decrypt(byte[] content, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return cipher.doFinal(content);
    }

    public static void main(String[] args) throws Exception {
        String algorithm = "DES";
//        String algorithm = "DESede";
//        String algorithm = "AES";

        //生成密钥key
        SecretKey key = BaseSymmetry.generateKey(algorithm);
        //转成字符串
        String keyStr = Base64.getEncoder().encodeToString(key.getEncoded());
        System.out.println("经BASE64处理之后的密钥 : " + keyStr);
        //根据字符串再生成密钥key
        key = BaseSymmetry.strKey2SecretKey(keyStr, algorithm);

        //明文
        String plainText = "我是明文";

        //加密
        byte[] encryptedBytes = BaseSymmetry.encrypt(plainText, key);
        String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
        System.out.println("Encrypted Text: " + encryptedText);

        //解密
        byte[] decryptedBytes = BaseSymmetry.decrypt(encryptedBytes, key);
        System.out.println("Decrypted Text: " + new String(decryptedBytes));
    }
}

参考

https://blog.csdn.net/qq_26664043/article/details/136989938

mylomen

本人从事 JAVA 开发10多年,将之前整理的笔记分享出来,希望能够帮助到努力的你。