本文介绍 Java 语言实现 3DES 加密的方法。
目录
- 3DES 简介
- 代码实现
- CBC
3DES 简介
3DES,原名 Triple Data Encryption Algorithm,即 三重数据加密算法,缩写也为 TDEA。
3DES 是对原版 DES 的改进,相当于对每个数据块应用 3 次 DES算法,是 DES 向 AES 过渡的加密算法。
3DES 的加密过程:C=EK3(DK2(EK1(M)))
3DES 的解密过程:M=DK1(EK2(DK3(C)))
C
是密文,M
是明文,K
代表 DES 算法使用的密钥,EK()
代表 DES 算法的加密过程,DK()
代表 DES 算法的解密过程。
代码实现
CBC
- 添加 Bouncy Castle 依赖
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.65</version>
</dependency>
- 代码
package tutorial.java.util;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.*;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
public class TripleDesUtils {
/**
* 算法名称
*/
private static final String ALGORITHM_3DES = "DESEDE";
private static final SecureRandom RANDOM = new SecureRandom();
/**
* 注意:
* 1.CBC 模式下加解密 Cipher 初始化必须传入同一个 IvParameterSpec 实例参数
* 2.IvParameterSpec 构造函数中参数字节数组长度必须是 8 位
*/
private static final IvParameterSpec IV_PARAMETER_SPEC = new IvParameterSpec(RANDOM.generateSeed(8));
public static byte[] encryptCbc(byte[] key, byte[] content, Padding padding) {
// 添加一个安全供应商
Security.addProvider(new BouncyCastleProvider());
// 生成密钥
try {
Key desKey = keyGenerator(key);
// 实例化一个 Cipher 对象用于完成加密操作
Cipher cipher = Cipher.getInstance(ALGORITHM_3DES + "/CBC/" + padding.value);
// 初始化 Cipher 对象,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, desKey, IV_PARAMETER_SPEC);
return cipher.doFinal(content);
} catch (InvalidKeyException e) {
e.printStackTrace();
throw new UnsupportedOperationException("Invalid Key");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (InvalidKeySpecException e) {
throw new UnsupportedOperationException("Invalid key spec");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
} catch (InvalidAlgorithmParameterException e) {
throw new UnsupportedOperationException("Illegal algorithm parameter");
}
}
public static byte[] decryptCbc(byte[] key, byte[] content, Padding padding) {
try {
// 生成密钥
Key desKey = keyGenerator(key);
// 实例化一个 Cipher 对象用于完成解密操作
Cipher cipher = Cipher.getInstance(ALGORITHM_3DES + "/CBC/" + padding.value);
// 初始化 Cipher 对象,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, desKey, IV_PARAMETER_SPEC);
return cipher.doFinal(content);
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No such padding");
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No such algorithm");
} catch (InvalidKeyException e) {
e.printStackTrace();
throw new UnsupportedOperationException("Invalid Key");
} catch (InvalidKeySpecException e) {
throw new UnsupportedOperationException("Invalid key spec");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal block size");
} catch (InvalidAlgorithmParameterException e) {
throw new UnsupportedOperationException("Illegal algorithm parameter");
}
}
/**
* 生成 3DES 密钥对象
*
* @param key 密钥字节数组
* @return 密钥对象
* @throws InvalidKeyException Key 无效
* @throws NoSuchAlgorithmException 无相关算法
* @throws InvalidKeySpecException KeySepc 无效
*/
private static Key keyGenerator(byte[] key)
throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
DESedeKeySpec deSedeKeySpec = new DESedeKeySpec(key);
// 创建一个密钥工厂,用于转换 DESKeySpec
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(ALGORITHM_3DES);
// 生成一个密钥并返回
return secretKeyFactory.generateSecret(deSedeKeySpec);
}
public static enum Padding {
NO_PADDING("NoPadding"),
PKCS5_PADDING("PKCS5Padding");
private String value;
Padding(String value) {
this.value = value;
}
}
}
- 单元测试
package tutorial.java.util;
import org.junit.Assert;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
public class TripleDesUtilsTest {
private void test(TripleDesUtils.Padding padding, String key, String content) {
byte[] encryptResult = TripleDesUtils.encryptCbc(key.getBytes(StandardCharsets.UTF_8),
content.getBytes(StandardCharsets.UTF_8),
padding);
byte[] decryptResult = TripleDesUtils.decryptCbc(key.getBytes(StandardCharsets.UTF_8),
encryptResult,
padding);
Assert.assertEquals(content, new String(decryptResult, StandardCharsets.UTF_8));
}
@Test
public void testCbcNoPadding() {
// 密钥长度必须是 8 的倍数,最少 24 位
String key = "123456781234567812345678";
// 待加密原文长度必须是 8 的倍数
String content = "12345678";
test(TripleDesUtils.Padding.NO_PADDING, key, content);
}
@Test
public void testCbcPkcs5Padding() {
// 密钥长度必须是 8 的倍数,最少 24 位
String key = "123456781234567812345678";
String content = "123456789";
test(TripleDesUtils.Padding.PKCS5_PADDING, key, content);
}
}
网友评论