简介
DES(Data Encryption Standard)
是一种对称加密算法
,是一种用56位密钥
来加密64位数据
的方法。一般密码长度为8个字节,其中56位加密密钥,每个第8位都用作奇偶校验。
DES
算法一般有两个关键点,第一个是加密算法
,第二个是数据补位
。
DES算法的几种加密模式
加密算法常见的有ECB模式
和CBC模式
:
ECB模式:
电子密本方式,这是JAVA
封装的DES
算法的默认模式,就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文,最后一段不足8个字节,则补足8个字节(注意:这里就涉及到数据补位了)进行计算,之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。
CBC模式:
密文分组链接方式,这是.NET
封装的DES
算法的默认模式
DES算法的填补方式
数据补位一般有NoPadding
和PKCS7Padding
(JAVA
中是PKCS5Padding
)填充方式,PKCS7Padding
和PKCS5Padding
实际只是协议不一样。
根据相关资料说明:PKCS5Padding
明确定义了加密块是8字节,PKCS7Padding
加密快可以是1-255之间。
但是封装的DES
算法默认都是8字节
,所以可以认为他们一样。
数据补位
实际是在数据不满8字节的倍数,才补充到8字节的倍数的填充过程。
NoPadding
填充方式:算法本身不填充,比如.NET
的padding
提供了有None
,Zeros
方式,分别为不填充
和填充0
的方式。
PKCS7Padding
(PKCS5Padding
)填充方式:为.NET
和JAVA
的默认填充方式,对加密数据字节长度对8取余为r,如r大于0,则补8-r个字节,字节为8-r的值;如果r等于0,则补8个字节8。
比如:
加密字符串为为AAA,则补位为AAA55555;加密字符串为BBBBBB,则补位为BBBBBB22;加密字符串为CCCCCCCC,则补位为CCCCCCCC88888888。
小结:
java
中,DES
默认ECB
加密模式,默认PKCS5Padding
填充方式
Java 实现 DES 加解密
- 获得 DES 密钥对象
/**
* 获得 DES 密钥对象
*
* @param secretKeyStr 原始密钥字符串
* @return SecretKey 密钥对象
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws InvalidKeyException
*/
private static SecretKey generateKey(String secretKeyStr)
throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
// 从原始密钥数据 secretKeyStr 创建 DESKeySpec 对象
DESKeySpec keySpec = new DESKeySpec(secretKeyStr.getBytes());
// 创建一个密钥工厂,然后用它把 DESKeySpec 转换成 SecretKey 对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
SecretKey securekey = keyFactory.generateSecret(keySpec);
return securekey;
}
- DES加密
/**
* DES加密
*
* @param plainData 原始字符串
* @param secretKey 加密密钥
* @return 加密后的字符串
*
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static String encryption(String plainData, String secretKey)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, InvalidKeySpecException,
IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, generateKey(secretKey));
byte[] buf = cipher.doFinal(plainData.getBytes());
return Hex.encodeHexString(buf);
}
- DES解密
/**
* DES解密
*
* @param secretData 密码字符串
* @param secretKey 解密密钥
* @return 原始字符串
*
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws InvalidKeyException
* @throws DecoderException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
* @throws UnsupportedEncodingException
*/
public static String decryption(String secretData, String secretKey)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException,
BadPaddingException, DecoderException, UnsupportedEncodingException {
// DES/ECB/NoPadding
// 默认 DES/ECB/PKCS5Padding ==> DES
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, generateKey(secretKey));
byte[] buf = cipher.doFinal(Hex.decodeHex(secretData.toCharArray()));
return new String(buf, "utf-8");
}
- 测试
public static void main(String[] args) {
String keyStr = "12345678";
String strOld = "汉字+Admin@123";
String encodeStr = "";
String decodeStr = "";
try {
//加密
encodeStr = encryption(strOld, keyStr);
//解密
decodeStr = decryption(encodeStr, keyStr);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(encodeStr);
// 373e13088cd22a5a19816fd3a5873024feb959b7d4642fcb
System.out.println(decodeStr);
// 汉字+Admin@123
}
Js 实现 DES 加解密
前端采用第三方框架 cryptoJs
实现,git 地址
- DES 加密
// DES加密
function encryptByDES(message) {
//把私钥转换成16进制的字符串
let keyHex = CryptoJS.enc.Utf8.parse(key);
//模式为ECB padding为Pkcs7
let encrypted = CryptoJS.DES.encrypt(message, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
//加密出来是一个16进制的字符串
return encrypted.ciphertext.toString();
}
- DES 解密
//DES ECB模式解密
function decryptByDESModeEBC(ciphertext) {
//把私钥转换成16进制的字符串
let keyHex = CryptoJS.enc.Utf8.parse(key);
//把需要解密的数据从16进制字符串转换成字符byte数组
let decrypted = CryptoJS.DES.decrypt({
ciphertext: CryptoJS.enc.Hex.parse(ciphertext)
}, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
//以utf-8的形式输出解密过后内容
let result_value = decrypted.toString(CryptoJS.enc.Utf8);
return result_value;
}
- 测试
//需要加密的内容
let str1 = encryptByDES('汉字+Admin@123');
let str2 = decryptByDESModeEBC(str1);
console.log(str1) // 373e13088cd22a5a19816fd3a5873024feb959b7d4642fcb
console.log(str2) // 汉字+Admin@123
总结
- Java 中,
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
默认采用的是ESB
加密模式,PKCS5Padding
填充 - Js 中,
mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7
;
所以采用的是ESB
加密模式,PKCS7Padding
填充 - 因为
PKCS5Padding
与PKCS7Padding
封装的DES
算法默认都是8字节
,所以可以认为他们一样。 - 所以如上面demo所示,我们发现 Java 与 Js 采用同样的
密钥key
与明文
, 最终加解密得到同样的密文。 - 这样就可以满足
前端 Js 加密,后台 Java 解密
和后台 Java 加密,前端 Js 解密
的一整个请求+返回过程的信息加密。
网友评论