算法概述
本文主要用了两个参数进行加密解密
一个key:秘钥,一个iv:偏移量。
如果不想要偏移量可根据下面两个步骤进行去除:
1.那cipher.init()方法只传入两个参数即可;
cipher.init(Cipher.ENCRYPT_MODE, deskey);
2.将"DESede/CBC/PKCS5Padding"改成"DESede/ECB/PKCS5Padding"即可
ECB模式和CBC模式的区别
CBC是密码分组链接模式
ECB是电码本模式
ECB模式:
优点:
简单;
有利于并行计算;
误差不会被传递;缺点:
不能隐藏明文的模式;
可能对明文进行主动攻击;
DES ECB(电子密本方式)其实非常简单,就是将数据按照8个字节一段进行DES加密或解密得到一段段的8个字节的密文或者明文,最后一段不足8个字节(一般补0或者F),按照需求补足8个字节进行计算(并行计算),之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。
CBC模式:
优点:
不容易主动攻击,安全性好于ECB,是SSL、IPSec的标准;
缺点:
不利于并行计算;
误差传递;
需要初始化向量IV;
DES CBC(密文分组链接方式)有点麻烦,它的实现机制使加密的各段数据之间有了联系。其实现的机理如下:
- 首先将数据按照8个字节一组进行分组得到D1D2…Dn(若数据不是8的整数倍,用指定的PADDING数据补位)
- 第一组数据D1与初始化向量I异或后的结果进行DES加密得到第一组密文C1(初始化向量I为全零)
- 第二组数据D2与第一组的加密结果C1异或以后的结果进行DES加密,得到第二组密文C2
- 之后的数据以此类推,得到Cn
- 按顺序连为C1C2C3…Cn即为加密结果。
话不多说,直接上代码。(复制即可用)
Des3Utils :
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @author: 慌途L
* @desc: 3DES 加密/解密
*/
@Slf4j
public class Des3Utils {
/**
* 加密算法
*/
private static final String KEY_ALGORITHM = "DESede";
private static final String CIPHER_ALGORITHM = "DESede/CBC/PKCS5Padding";
/**
* 3DES 加密
*
* @param key 秘钥(24位)
* @param iv 偏移量
* @param data 需要加密的字符串
* @return 返回加密的字符串
*/
public static String encrypt(String key, String iv, String data) {
try {
DESedeKeySpec spec = new DESedeKeySpec(key.getBytes(StandardCharsets.UTF_8));
SecretKeyFactory keyfactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
Key deskey = keyfactory.generateSecret(spec);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
IvParameterSpec ips = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
byte[] bOut = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.encodeBase64String(bOut);
} catch (Exception e) {
e.printStackTrace();
log.error("3DES 解密错误:{}", e);
throw new RuntimeException("3DES 解密错误");
}
}
/**
* 3DES 解密
*
* @param key 秘钥(24位)
* @param iv 偏移量
* @param data 需要解密的密文
* @return 返回加密的字符串
*/
public static String decrypt(String key, String iv, String data) {
try {
DESedeKeySpec spec = new DESedeKeySpec(key.getBytes(StandardCharsets.UTF_8));
SecretKeyFactory keyfactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
Key deskey = keyfactory.generateSecret(spec);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
IvParameterSpec ips = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.DECRYPT_MODE, deskey, ips);
byte[] bOut = cipher.doFinal(Base64.decodeBase64(data.getBytes(StandardCharsets.UTF_8)));
return new String(bOut, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
log.error("3DES 解密错误:{}", e);
throw new RuntimeException("3DES 解密错误");
}
}
public static void main(String[] args) {
String data = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
+ "-" + String.format("%04d", (int) ((Math.random() * 9 + 1) * 1000));
System.out.println("需要加密的字符串内容为:" + data);
String des3EncodeCBC = encrypt("H2bsdDdfEEKpldjubTevcPQf", "53152654", data);
System.out.println("加密后的字符串内容为:" + des3EncodeCBC);
String des3DecodeCBC = decrypt("H2bsdDdfEEKpldjubTevcPQf", "53152654", des3EncodeCBC);
System.out.println("解密后的字符串内容为:" + des3DecodeCBC);
}
}