在进行3DES加密时当最后一位不足64时会自动补上,导致解密时报错
javax.crypto.BadPaddingException: Given final block not properly padded
大致逻辑:对原文进行3DES加密,由于存在最后一位不足64位时会自动填充,导致解密时会报错,所以对可能进行了填充(也可能没填充,看最后一位)的3DES密文进行Base64编码,这时可以直接把Base64编码结果转为String进行传输,在其它地方接收到该String,利用getBytes("UTF-8"),得到byte[],进行Base64解码,对解码得到的byte数组进行3DES解密就可以得到原文了。
package com.server.model;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.*;
import javax.crypto.spec.*;
public class SecretTools {
//3DES
private static final String algorithm = "DESede";
private static final String pass_secretkey = "ThisIsAnExampleSecretKeyTest";
//Base64
private static final Base64.Decoder decoder = Base64.getDecoder();
private static final Base64.Encoder encoder = Base64.getEncoder();
//Test
public static void main(String[] args){
//待加密密文
String data = "ddbfdskfdsfslksjkffj";
System.out.println("原始报文内容:"+data);
//加密结果
//加密结果转为了String进行传输,
//调用加密的方法,得到了String形式的Base64密文
//此处Encryption方法中对3DES结果进行了Base64编码
String b = SecretTools.Encryption(data.getBytes());
//测试点,测试转为String是否导致byte填补丢失
//传输结果转为byte[]进行解密
//Decrypt方法中先进行了Base64解码
//再进行了3DES解密
//doFinal最终得到一个byte[],转为String输出即可得知与原文相同
byte[] c = SecretTools.Decrypt(b);
try {
System.out.println("最终解密报文:"+new String(c,"UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//加密算法
public static String Encryption(byte[] data){
try {
SecretKey deskey = new SecretKeySpec(creatdeskey(pass_secretkey),algorithm);
Cipher ch = Cipher.getInstance(algorithm);
ch.init(Cipher.ENCRYPT_MODE, deskey);
byte[] result = ch.doFinal(data);
System.out.println("3DES对原报文进行加密加密报文:"+new String(result));
//返回报文经过base64编码
return SecretTools.aBase64_encript(result);
} catch (NoSuchAlgorithmException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (NoSuchPaddingException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}catch(Exception e3){
e3.printStackTrace();
}
return null;
}
//解密算法
public static byte[] Decrypt(String data){
try {
//先进行base64解码
byte[] da = SecretTools.aBase64_decritp(data);
SecretKey deskey = new SecretKeySpec(creatdeskey(pass_secretkey),algorithm);
Cipher ch = Cipher.getInstance(algorithm);
ch.init(Cipher.DECRYPT_MODE, deskey);
byte[] des = ch.doFinal(da);
System.out.println("3DES解密获得原报文:"+new String(des));
return des;
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (NoSuchPaddingException e2) {
e2.printStackTrace();
}catch (Exception e3) {
e3.printStackTrace();
}
return null;
}
//Base64解码方法
public static byte[] aBase64_decritp(String encodedText){
//Base64解碼
try {
byte[] textByte = encodedText.getBytes("UTF-8");
byte[] str = decoder.decode(encodedText);
System.out.println("Base64解码,得到原始的3DES编码结果:"+new String(str));
//返回解码结果用于3DES解码
return str;
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//返回解码结果
return null;
}
//Base64编码方法
public static String aBase64_encript(byte[] textByte){
String encodedText = encoder.encodeToString(textByte);
//输出对应编码结果
System.out.println("Base64编码用于传输,编码结果:"+encodedText);
//把编码结果返回
//此编码结果已经转化为string型
return encodedText;
}
//把密钥约定为24位
public static byte[] creatdeskey(String passkey)throws UnsupportedEncodingException{
byte[] temp = passkey.getBytes();
byte[] truekey = new byte[24];
if(temp.length < truekey.length){
System.arraycopy(temp, 0, truekey, 0, temp.length);
}
else{
System.arraycopy(temp, 0, truekey, 0, truekey.length);
}
return truekey;
}
}
原始报文内容:ddbfdskfdsfslksjkffj
3DES对原报文进行加密加密报文:夁匽啸qb塟昩&u駄c7猔蝴
Base64编码用于传输,编码结果:id+FXdClcWKJWpViJhwPdfFqYzeqYLr7
Base64解码,得到原始的3DES编码结果:夁匽啸qb塟昩&u駄c7猔蝴
3DES解密获得原报文:ddbfdskfdsfslksjkffj
最终解密报文:ddbfdskfdsfslksjkffj
可能会存在因为版本问题导致java.util.Base64不能使用,这种情况你可以使用Apache Commons Codec进行base64编码
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
总结:3DES加密报文进行Base64编码,然后转为String传输,接收到的Sring转为byte[],先进行Base64解码,再进行3DES解码,就可以解决这个问题了。