本文详细解析Java中使用DES算法加密字符数据的实现方法。重点修复了原代码中字节转字符串导致的乱码问题,通过引入Base64编码确保数据完整性。同时优化了资源关闭逻辑,防止内存泄漏,并提供完整的加密解密工具类代码及运行示例。
DES加密最终效果预览
在Java中实现DES加密后,原始明文字符串将被转换为不可读的密文字符串(通常经过Base64编码)。解密过程则能将密文还原为原始明文。下图展示了加密前后的数据形态对比,以及解密成功的控制台输出结果。

操作前准备说明
在开始编写代码之前,请确保开发环境满足以下条件:
- JDK版本:建议使用 JDK 8 或更高版本,以确保包含完整的
javax.crypto包支持。 - 依赖库:Java标准库已内置
javax.crypto.Cipher和javax.crypto.spec相关类,无需额外引入第三方JAR包。 - 编码工具:需使用
java.util.Base64类(JDK 8+)或org.apache.commons.codec.binary.Base64来处理二进制数据到字符串的转换。 - 密钥准备:DES算法要求密钥长度必须为8字节(64位,其中8位用于奇偶校验)。请确保密钥字符串长度符合此要求,否则需进行截断或填充处理。
DES加密解密核心实现步骤
第1步:定义密钥与初始化参数
DES加密需要明确的密钥(Key)和初始化向量(IV)。为了保证安全性,建议使用 SecureRandom 生成随机数,并固定密钥和IV字符串。
操作目的:确立加密所需的密钥材料,确保加密和解密使用相同的参数。
- 定义静态常量
PASSKEY作为IV(初始化向量),长度需为8字节。 - 定义静态常量
DESKEY作为主密钥,长度需为8字节。 - 使用
DESKeySpec将密钥字符串转换为字节数组。 - 通过
SecretKeyFactory.getInstance("DES")生成SecretKey对象。
第2步:配置Cipher实例与模式
操作目的:指定加密算法、工作模式和填充方式,并初始化为加密或解密模式。
- 创建
IvParameterSpec对象,传入IV的字节数组。 - 使用
Cipher.getInstance("DES/CBC/PKCS5Padding")获取Cipher实例。这里采用CBC模式(密码块链接)和PKCS5Padding填充,以增强安全性。 - 调用
cipher.init(mode, securekey, iv, sr),其中mode为Cipher.ENCRYPT_MODE或Cipher.DECRYPT_MODE。
第3步:执行数据流加密与Base64编码
操作目的:将明文转换为密文,并安全地转换为字符串格式,避免乱码。
关键修复点:原代码直接使用 out.toString() 将字节数组转换为字符串,这会导致编码错误和乱码。正确做法是将加密后的字节数组进行 Base64编码。
- 使用
CipherInputStream包装输入流,自动执行加密操作。 - 使用
ByteArrayOutputStream接收加密后的字节数据。 - 读取加密流中的数据块(Buffer),写入输出流。
- 加密完成后,使用
Base64.getEncoder().encodeToString(out.toByteArray())将字节数组转换为Base64字符串,作为最终密文返回。
第4步:执行数据流解密与还原
操作目的:将Base64密文解码为字节数组,并解密还原为原始明文。
- 使用
Base64.getDecoder().decode(src)将密文字符串还原为字节数组。 - 使用
CipherInputStream包装解密流,自动执行解密操作。 - 将解密后的字节数组转换为字符串(使用UTF-8编码)。
- 返回解密后的明文。
优化后的完整代码实现
以下是修复了资源泄漏、乱码问题并优化了结构后的完整工具类代码:
import javax.crypto.Cipher;import javax.crypto.CipherInputStream;import javax.crypto.SecretKey;import javax.crypto.SecretKeyFactory;import javax.crypto.spec.DESKeySpec;import javax.crypto.spec.IvParameterSpec;import java.io.ByteArrayOutputStream;import java.io.InputStream;import java.security.SecureRandom;import java.util.Base64;public class DesTool { // 密钥:必须为8字节 private static final String DESKEY = "12345678"; // IV:必须为8字节 private static final String PASSKEY = "abcdefgh"; /** * 加密或解密方法 * @param src 源数据(加密时为明文,解密时为Base64密文) * @param mode 模式:Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE * @return 加密后的Base64字符串,或解密后的明文 */ public static String encoderOrdecoder(String src, int mode) { String result = ""; InputStream is = null; CipherInputStream cis = null; ByteArrayOutputStream out = null; try { // 1. 生成密钥 SecureRandom sr = new SecureRandom(); DESKeySpec dks = new DESKeySpec(DESKEY.getBytes("UTF-8")); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey securekey = keyFactory.generateSecret(dks); // 2. 生成IV IvParameterSpec iv = new IvParameterSpec(PASSKEY.getBytes("UTF-8")); // 3. 初始化Cipher Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); cipher.init(mode, securekey, iv, sr); // 4. 处理输入数据 byte[] inputBytes; if (mode == Cipher.DECRYPT_MODE) { // 解密时需先进行Base64解码 inputBytes = Base64.getDecoder().decode(src); } else { // 加密时直接使用明文 inputBytes = src.getBytes("UTF-8"); } // 5. 执行加密/解密流操作 cis = new CipherInputStream(new java.io.ByteArrayInputStream(inputBytes), cipher); out = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int r; while ((r = cis.read(buffer)) > 0) { out.write(buffer, 0, r); } // 6. 结果处理 if (mode == Cipher.ENCRYPT_MODE) { // 加密结果转为Base64字符串 result = Base64.getEncoder().encodeToString(out.toByteArray()); } else { // 解密结果转为UTF-8字符串 result = new String(out.toByteArray(), "UTF-8"); } } catch (Exception e) { e.printStackTrace(); } finally { // 7. 安全关闭资源 try { if (cis != null) cis.close(); if (out != null) out.close(); } catch (Exception e1) { // 忽略关闭异常 } } return result; } public static void main(String[] args) { String originalText = "Hello, DES Encryption!"; System.out.println("原始明文: " + originalText); // 加密 String encryptedText = encoderOrdecoder(originalText, Cipher.ENCRYPT_MODE); System.out.println("加密后(Base64): " + encryptedText); // 解密 String decryptedText = encoderOrdecoder(encryptedText, Cipher.DECRYPT_MODE); System.out.println("解密后: " + decryptedText); // 验证 System.out.println("解密是否成功: " + originalText.equals(decryptedText)); }}图片验证与结果核对
运行上述代码后,控制台应输出类似图1所示的内容。请核对以下关键点:
- 原始明文:显示您输入的字符串。
- 加密后(Base64):显示一串由字母、数字和符号组成的长字符串,这是Base64编码后的密文。
- 解密后:显示与原始明文完全一致的字符串。
- 解密是否成功:输出
true,表示加密解密流程无误。
如果输出中出现乱码或异常,请检查密钥长度是否为8字节,以及是否使用了正确的Base64编码/解码方法。
问题与调整
问题1:解密时出现“Bad padding”异常
- 表现:抛出
javax.crypto.BadPaddingException。 - 原因:密文在传输或存储过程中被修改,或者Base64解码失败(例如密文包含空格或换行符)。
- 解决方法:确保密文在传输前已去除首尾空格,且Base64编码/解码过程一致。
问题2:密钥长度不匹配
- 表现:抛出
java.security.InvalidKeyException: Key length not 8 bytes。 - 原因:DES算法严格要求密钥长度为8字节(64位)。
- 解决方法:确保
DESKEY字符串长度为8个字符。如果密钥更长,需截取前8字节;如果更短,需进行填充(不推荐,安全性降低)。
问题3:中文乱码
- 表现:解密后的中文显示为问号或乱码。
- 原因:编码格式不一致,加密时使用UTF-8,解密时使用了ISO-8859-1等默认编码。
- 解决方法:在
getBytes("UTF-8")和new String(..., "UTF-8")中统一指定编码格式为UTF-8。
总结
本文通过修复原代码中的关键缺陷,提供了一个健壮、安全的Java DES加密解密工具类。核心改进包括:
- 使用 Base64编码 解决二进制数据转字符串的乱码问题。
- 优化 资源关闭逻辑,避免内存泄漏。
- 明确指定 UTF-8编码,确保中文等多字节字符的正确处理。
- 强调 密钥长度 必须为8字节,符合DES算法规范。
该实现适用于对安全性要求不高、数据量较小的内部系统加密场景。对于高安全性需求,建议升级至AES算法。
以上就是Java实现DES加密解密:修复代码缺陷与最佳实践的详细内容,更多关于Java加密技术的资料请关注本站其它相关文章!
