import lombok.extern.slf4j.Slf4j;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.spec.KeySpec;
/**
* 3DES加密工具类
*
*/
@Slf4j
public class DES3Utils {
/**
* 随意定一个私钥(长度必须为24位) 固定密钥字符串
*/
public static final String FIXED_KEY_STRING = "@@111111111IJKLMN123456E";
/**
* 加密
*
* @param inStr 需要加密的内容
* @param secretKey 密钥
* @return 加密后的数据
*/
public static String encrypt(String inStr, String secretKey) throws Exception {
SecretKey desKey = generateKey(secretKey);
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding"); // 明确分组和填充模式
cipher.init(Cipher.ENCRYPT_MODE, desKey);
byte[] encryptedBytes = cipher.doFinal(inStr.getBytes(StandardCharsets.UTF_8));
return byte2hex(encryptedBytes);
}
/**
* 解密
*
* @param inStr 需要解密的内容
* @param secretKey 密钥
* @return 解密后的数据
*/
public static String decrypt(String inStr, String secretKey) throws Exception {
SecretKey desKey = generateKey(secretKey);
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, desKey);
byte[] decryptedBytes = cipher.doFinal(hex2byte(inStr));
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
private static SecretKey generateKey(String keyStr) throws Exception {
KeySpec keySpec = new DESedeKeySpec(keyStr.getBytes(StandardCharsets.UTF_8));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
return keyFactory.generateSecret(keySpec);
}
/**
* 转化为16进制字符串方法
*
* @param digest 需要转换的字节组
* @return 转换后的字符串
*/
private static String byte2hex(byte[] digest) {
StringBuffer hs = new StringBuffer();
String stmp = "";
for (int n = 0; n < digest.length; n++) {
stmp = Integer.toHexString(digest[n] & 0XFF);
if (stmp.length() == 1) {
hs.append("0" + stmp);
} else {
hs.append(stmp);
}
}
return hs.toString().toUpperCase();
}
/**
* 十六进转二进制
*
* @param hexStr 待转换16进制字符串
* @return 二进制字节组
*/
public static byte[] hex2byte(String hexStr) {
if (hexStr == null)
return null;
hexStr = hexStr.trim();
int len = hexStr.length();
if (len == 0 || len % 2 == 1)
return null;
byte[] digest = new byte[len / 2];
try {
for (int i = 0; i < hexStr.length(); i += 2) {
digest[i / 2] = (byte) Integer.decode("0x" + hexStr.substring(i, i + 2)).intValue();
}
return digest;
} catch (Exception e) {
return null;
}
}
public static void main(String[] args) {
try {
String cdkey = "XXXXXXXXXXXXXXX";
// key需要24位
String s1 = encrypt(cdkey, "@@111111111IJKLMN123456E");
System.out.println("Encrypted: " + s1);
String s2 = decrypt(s1, "@@111111111IJKLMN123456E");
System.out.println("Decrypted: " + s2);
} catch (Exception e) {
// 异常处理
log.error("异常情况:{}", e);
}
}
}
这个Java类DES3Utils
是一个用于执行3DES(Triple Data Encryption Standard,即三重数据加密算法)加密和解密操作的工具类。下面是对该类功能和重要部分的详细解析:
类定义与常量
- 类注解
@Slf4j
: 引入Lombok库的注解,自动为类添加日志记录功能,简化日志记录代码。 - 常量
FIXED_KEY_STRING
: 定义了一个固定的24字符长度的密钥字符串,用于3DES算法。3DES要求密钥长度为24字节(即192位),因为它实际上执行三次DES加密,每次需要8字节密钥。
加密方法 encrypt(String inStr, String secretKey)
- 密钥生成: 调用
generateKey(String keyStr)
方法,根据传入的密钥字符串生成一个SecretKey
对象。这里通过DESedeKeySpec
指定密钥材料,然后利用SecretKeyFactory
创建密钥实例。 - Cipher实例化: 使用
Cipher.getInstance("DESede/ECB/PKCS5Padding")
获取一个Cipher对象,指定算法模式为ECB(Electronic Codebook,电子密码本模式),填充模式为PKCS5Padding。 - 初始化Cipher: 根据密钥和加密模式初始化Cipher实例。
- 执行加密: 调用
doFinal
方法对输入字符串的字节表示进行加密,得到加密后的字节数组。 - 转换输出: 将加密后的字节数组通过
byte2hex
方法转换为16进制字符串,便于显示和存储。
解密方法 decrypt(String inStr, String secretKey)
解密过程与加密类似,但操作相反:
- 初始化Cipher为解密模式。
- 使用相同的密钥和填充模式。
- 将输入的16进制字符串通过
hex2byte
转换回字节数组。 - 执行解密并转换回字符串输出。
辅助方法
generateKey(String keyStr)
: 用于从给定的字符串密钥生成SecretKey
。byte2hex(byte[] digest)
: 将字节数组转换成大写的16进制字符串。hex2byte(String hexStr)
: 将16进制字符串转换回字节数组。
发现 key的前24是起作用的 24位之后更改字符不会影响解析效果(第24位如果是前后2个字符也不影响解析效果)
这个问题涉及到3DES(Triple DES)算法的密钥结构和处理方式。3DES是一种对称加密算法,它是基于原来的DES算法扩展而来,通过使用三个不同的密钥对数据进行三次加密(或者加密-解密-加密步骤)处理,来提高安全性。
在3DES中,密钥长度可以是168位(即24字节)或者192位(24字节密钥在实际处理时会扩展到192位)。具体来说:
- 当使用168位密钥时,实际上密钥会被分成两部分,每部分8字节,然后在内部处理中会生成第三部分密钥作为中间密钥,这样总共还是进行三次加密操作。
- 如果提供的是24字节密钥,这24字节会被直接分为三段,每8字节一段,分别作为三次加密的密钥。
当你提到“key的前24位是起作用的,24位之后更改字符不会影响解析效果”,这很可能是因为在你的实现中,虽然你提供了超过24位的密钥,但实际使用的只是前24位(三个8字节的部分),超出的部分被忽略了。这是因为DESede/ECB/PKCS5Padding模式在处理密钥时,只会使用前24字节来生成实际的加密密钥,多余的字符不会参与密钥生成过程,因此更改它们不影响加密和解密的结果。
此外,关于“第24位如果是前后2个字符也不影响解析效果”的描述可能是指,在某些情况下,即使第24位字符及其前后有变化(比如字符被误写或修改),如果这些变化没有导致密钥的有效部分(即前24位)发生改变,加密和解密的过程仍然能够正确进行,因为真正用于加密的密钥部分保持不变。
总之,这种现象是因为3DES算法仅使用密钥的特定部分(最多24字节,按8字节分段),超出这个长度的密钥部分在你的实现中未被使用,所以不会影响加密解密过程。在设计和实施安全系统时,应当避免使用无效或冗余的密钥材料,确保密钥管理的严谨性。
DES(Data Encryption Standard)算法,其密钥长度固定为56位,即7字节。但在实际应用中,密钥通常以8字节(即64位)的形式输入,其中前7字节(56位)用于加密运算,而最后一位(第8字节的最高位)在标准的DES实现中并不使用于加密过程,有时会被设置为奇偶校验位或其他校验用途。因此,从广义上讲,可以认为DES算法处理的是基于前7个字节的有效密钥数据,尽管在软件实现中常常以8字节的形式处理和传递。