3DES加解密报错 Invalid key length: 32 bytes
程序员文章站
2022-05-15 16:56:43
...
开发过程中用到3DES对敏感信息进行加密,秘钥用的是32位的,报出如下异常
Exception in thread "main" java.security.InvalidKeyException: Invalid key length: 32 bytes
at com.sun.crypto.provider.DESedeCipher.engineGetKeySize(DESedeCipher.java:370)
at javax.crypto.Cipher.passCryptoPermCheck(Cipher.java:1067)
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1025)
at javax.crypto.Cipher.implInit(Cipher.java:801)
at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
at javax.crypto.Cipher.init(Cipher.java:1249)
at javax.crypto.Cipher.init(Cipher.java:1186)
at com.adtec.des.des_temp.encryptThreeDESECB(des_temp.java:33)
at com.adtec.des.des_temp.main(des_temp.java:61)
加密代码如下:
/**
*
* @param src 加密内容
* @param key 秘钥 32位长度
* @return 加密后的内容
* @throws Exception
*/
public static byte[] encryptThreeDESECB(final String src, final String key) throws Exception {
SecretKey securekey = new SecretKeySpec(key.getBytes(), "DESede");
final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, securekey);
final byte[] b = cipher.doFinal(src.getBytes());
return b;
}
测试用例
public static void main(String[] args) throws Exception {
String key = "11112222333344445555666677778888";
// 加密流程
String telePhone = "123456";
byte[] telePhone_encrypt = null;
telePhone_encrypt = encryptThreeDESECB(URLEncoder.encode(telePhone, "UTF-8"), key);
System.out.println(new String(telePhone_encrypt));
// 解密流程
String tele_decrypt = decryptThreeDESECB(telePhone_encrypt, key);
System.out.println("解密:" + tele_decrypt);
}
感觉不应该有问题啊???
试着将秘钥长度减为24位
这就可以了,但这是不可以的,系统不是我一个人操作,我用前24位加密,别人不知道,用后24位解密,就会导致结果不一致,无法解密。
知道我看见了另外一个方法:
/**
*
* @param src 加密内容
* @param key 秘钥 32位长度
* @return 加密后的内容
* @throws Exception
*/
public static byte[] encryptThreeDESECB(final String src, final String key) throws Exception {
final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
final SecretKey securekey = keyFactory.generateSecret(dks);
final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, securekey);
final byte[] b = cipher.doFinal(src.getBytes());
return b;
}
其他的一模一样
解密代码也一样
/**
*
* @param telePhone_encrypt 密文
* @param key 秘钥 32位长度
* @return 解密后明文
* @throws Exception
*/
public static String decryptThreeDESECB(byte[] telePhone_encrypt, final String key) throws Exception {
// --解密的key
final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
final SecretKey securekey = keyFactory.generateSecret(dks);
// --Chipher对象解密
final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, securekey);
final byte[] retByte = cipher.doFinal(telePhone_encrypt);
return new String(retByte);
}
仔细看了一下有一行代码有重大嫌疑
final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
看一眼源码
大概说的是,它用前24位构建DESedeKeySpec对象
再看看其DESedeKeySpec内部是如何实现的,打卡jdk的源码
/**
* Uses the first 24 bytes in <code>key</code>, beginning at
* <code>offset</code>, as the DES-EDE key
*
* @param key the buffer with the DES-EDE key
* @param offset the offset in <code>key</code>, where the DES-EDE key
* starts
*
* @exception InvalidKeyException if the given key has a wrong size
*/
DESedeKey(byte[] key, int offset) throws InvalidKeyException {
if (key==null || ((key.length-offset)<DESedeKeySpec.DES_EDE_KEY_LEN)) {
throw new InvalidKeyException("Wrong key size");
}
this.key = new byte[DESedeKeySpec.DES_EDE_KEY_LEN];
System.arraycopy(key, offset, this.key, 0,
DESedeKeySpec.DES_EDE_KEY_LEN);
DESKeyGenerator.setParityBit(this.key, 0);
DESKeyGenerator.setParityBit(this.key, 8);
DESKeyGenerator.setParityBit(this.key, 16);
// Use the cleaner to zero the key when no longer referenced
final byte[] k = this.key;
CleanerFactory.cleaner().register(this,
() -> java.util.Arrays.fill(k, (byte)0x00));
}
看到一个关键的东西:DESedeKeySpec.DES_EDE_KEY_LEN
果然长度是24
从底层源码
if (key==null || ((key.length-offset)<DESedeKeySpec.DES_EDE_KEY_LEN)) {
throw new InvalidKeyException("Wrong key size");
}
可以看出,如果秘钥为空或者小于24位会抛出Wrong key size,试一下
再试一下超过32位的
至此就可以发现了,后面这张加密方法,秘钥长度不能小于24,可以大于24,但是其实现的时候只截取了前24位
总结,推荐使用第二中加密方法,因为是底层截取的,不是我们手动截取的,无论是加密方还是解密方都遵循这个规则