前后端DES加解密及Wrong key size错误处理
前端使用 CryptoJS 进行DES加密,后端Java进行解密。
前端
function encryptByDES(message, key) {
var keyHex = CryptoJS.enc.Utf8.parse(key);
var encrypted = CryptoJS.DES.encrypt(message, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}
function decryptByDES(ciphertext, key) {
var keyHex = CryptoJS.enc.Utf8.parse(key);
var decrypted = CryptoJS.DES.decrypt({
ciphertext: CryptoJS.enc.Base64.parse(ciphertext)
}, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
Java
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
@Slf4j
public class DesUtil {
private static String CHARSETNAME="UTF-8";
private static String ALGORITHM="DES";
/**
* 加密数据
* @param data 待加密数据
* @param key 密钥
* @return 加密后的数据
*/
public static String getEncryptString(String data, String key) {
try {
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(getKeyBytes(key));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
SecretKey securekey = keyFactory.generateSecret(desKey);
//Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance(ALGORITHM);
//用密匙初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
byte[] temp = org.apache.commons.codec.binary.Base64.encodeBase64(cipher.doFinal(data.getBytes()));
return IOUtils.toString(temp, CHARSETNAME);
} catch (Exception e) {
log.info("加密异常: {}", ExceptionUtils.getFullStackTrace(e));
throw new RuntimeException(e);
}
}
private static byte[] getKeyBytes(String key) throws UnsupportedEncodingException {
byte[] keyBytes = key.getBytes(CHARSETNAME);
if (keyBytes.length < 8) {
byte[] bytes = new byte[8];
System.arraycopy(keyBytes, 0, bytes, 0, keyBytes.length);
keyBytes = bytes;
}
return keyBytes;
}
/**
* 解密数据
* @param data 待解密数据
* @param key 密钥
* @return 解密后的数据
*/
public static String getDecryptString(String data, String key) {
try {
// DES算法要求有一个可信任的随机数源
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(getKeyBytes(key));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
// 将DESKeySpec对象转换成SecretKey对象
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 用密匙初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, securekey, random);
return IOUtils.toString(cipher.doFinal(Base64.decodeBase64(data)),CHARSETNAME);
} catch (Exception e) {
log.info("解密异常: {}", ExceptionUtils.getFullStackTrace(e));
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
System.out.println(getEncryptString("12321", "vip"));
}
}
当keyBytes数组的长度小于8时,上面代码块中的私有方法getKeyBytes()对其进行了长度补齐。这是因为DESKeySpec的构造方法会只取keyBytes数组的前8位:
public DESKeySpec(byte[] var1) throws InvalidKeyException {
this(var1, 0);
}
public DESKeySpec(byte[] var1, int var2) throws InvalidKeyException {
if (var1.length - var2 < 8) {
throw new InvalidKeyException("Wrong key size");
} else {
this.key = new byte[8];
System.arraycopy(var1, var2, this.key, 0, 8);
}
}
可以看出,当key.getBytes()的长度大于等于8时只取前8位;当其长度小于8时,会抛异常:
Caused by: java.security.InvalidKeyException: Wrong key size
at javax.crypto.spec.DESKeySpec.<init>(DESKeySpec.java:155)
at javax.crypto.spec.DESKeySpec.<init>(DESKeySpec.java:131)
at com.prild.common.util.DesUtil.getEncryptString(DesUtil.java:38)
... 1 more