DES 对称加密算法详解
DES(Data Encryption Standard,数据加密标准)是一种经典的对称加密算法,尽管已逐渐被安全性更高的 AES 取代,但作为对称加密的重要里程碑,其设计思想对理解加密算法具有重要意义。
DES 的核心特性
- 对称加密:加密和解密使用相同的密钥,密钥长度固定为56 位(实际存储为 64 位,含 8 位奇偶校验位)。
- 分组加密:将明文按 64 位分组,逐组加密,最后一组不足 64 位时需填充。
- 安全性:由于密钥长度较短(56 位),在现代计算能力下可被暴力破解,安全性已不足,但仍在部分 legacy 系统中使用。
- 工作模式:支持 ECB、CBC、CFB 等多种分组加密模式(示例代码中未指定,默认使用 ECB 模式,安全性较低)。
DES 加密与解密流程解析
1. 加密过程(核心代码解析)
步骤 1:初始化随机数生成器
1
| SecureRandom sr = new SecureRandom();
|
SecureRandom用于生成加密过程中所需的随机数,确保加密的随机性(尽管 DES 的安全性主要依赖密钥)。
步骤 2:处理密钥
1 2 3
| DESKeySpec dks = new DESKeySpec(key); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey securekey = keyFactory.generateSecret(dks);
|
DESKeySpec:验证密钥合法性(必须为 8 字节,对应 56 位有效密钥)。
SecretKeyFactory:将原始密钥转换为 DES 算法可识别的SecretKey对象。
步骤 3:初始化加密器
1 2
| Cipher cipher = Cipher.getInstance("DES"); cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
|
Cipher.getInstance("DES"):默认使用DES/ECB/PKCS5Padding模式(ECB 模式不推荐,因相同明文分组会生成相同密文)。
init方法:传入加密模式、密钥和随机数生成器。
步骤 4:执行加密
1
| return cipher.doFinal(src);
|
doFinal方法完成实际加密操作,返回加密后的字节数组。
2. 解密过程(核心代码解析)
解密流程与加密类似,仅初始化模式不同:
1 2 3
| Cipher cipher = Cipher.getInstance("DES"); cipher.init(Cipher.DECRYPT_MODE, securekey, sr); return cipher.doFinal(src);
|
- 需使用与加密相同的密钥,否则无法正确解密。
- 解密时的
SecureRandom参数不影响结果(随机数仅在加密初始化时影响)。
DES 的局限性与替代方案
局限性
- 密钥长度短:56 位密钥可被现代计算机暴力破解(2^56 种可能,约 7.2×10^16,通过分布式计算可在短时间内破解)。
- ECB 模式不安全:默认的 ECB 模式不使用初始化向量(IV),相同明文分组加密后密文相同,易被攻击。
- 分组大小固定:64 位分组在处理长数据时效率较低,且存在安全性隐患。
替代方案
- 3DES:通过三次 DES 加密提升安全性(使用 3 个 56 位密钥,等效 112 位或 168 位密钥),但效率较低。
- AES:目前的首选对称加密算法,支持 128/192/256 位密钥,安全性和效率均远超 DES。
完整示例:DES 加密解密工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| import javax.crypto.*; import javax.crypto.spec.DESKeySpec; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; import java.util.Base64;
public class DESUtils { private static final String DES = "DES";
public static String encrypt(byte[] src, byte[] key) throws Exception { SecureRandom sr = new SecureRandom(); DESKeySpec dks = new DESKeySpec(key); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); SecretKey securekey = keyFactory.generateSecret(dks); Cipher cipher = Cipher.getInstance(DES); cipher.init(Cipher.ENCRYPT_MODE, securekey, sr); byte[] encrypted = cipher.doFinal(src); return Base64.getEncoder().encodeToString(encrypted); }
public static String decrypt(String encryptedBase64, byte[] key) throws Exception { byte[] src = Base64.getDecoder().decode(encryptedBase64); SecureRandom sr = new SecureRandom(); DESKeySpec dks = new DESKeySpec(key); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); SecretKey securekey = keyFactory.generateSecret(dks); Cipher cipher = Cipher.getInstance(DES); cipher.init(Cipher.DECRYPT_MODE, securekey, sr); byte[] decrypted = cipher.doFinal(src); return new String(decrypted); }
public static void main(String[] args) throws Exception { String plaintext = "Hello, DES!"; byte[] key = "12345678".getBytes();
String encrypted = encrypt(plaintext.getBytes(), key); System.out.println("加密后:" + encrypted);
String decrypted = decrypt(encrypted, key); System.out.println("解密后:" + decrypted); } }
|
v1.3.10