java AES 加密,报javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decryp

java 使用AES解密报这个异常,字面理解很容易,就是解密的字符串的数组必须是16的倍数

javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:922)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:833)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at javax.crypto.Cipher.doFinal(Cipher.java:2165)
    at com.symmetric.aes.TestAES.testDecrpyt(TestAES.java:200)
    at com.symmetric.aes.TestAES.main(TestAES.java:48)

1.使用的代码:

package com.symmetric.aes;
 
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
 
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
 
public class TestAES2 {
 
	private static final String enType_AES = "AES";
	private static final String pathStr = "D://aes.key";
	private static final String testStr = "AES tips you shoutld try again";
	
	
	public static void main(String[] args) {
		SecretKey genSecretKey = testGenerateKey();
		String string = genSecretKey.toString();
		
//		byte[] testEncryptBytes = testEncryptBytes(testStr, genSecretKey);
//		String testDecode = testDecrptBytes(testEncryptBytes, genSecretKey);
//		System.out.println(testDecode);  //直接操作数组,加密解密正常
		String testEncrypt = testEncrypt(testStr, genSecretKey);
		String testDecode2 = testDecrpt(testEncrypt, genSecretKey);
		System.out.println(testDecode2);
	}
	
	/**
	 * 生成密钥
	 * 通过传递SecureRandom对象进行初始化
	 * 不指定种子或密钥
	 * @return
	 */
	public static SecretKey testGenerateKey(){
		SecretKey genSecretKey = null;
		try {
			KeyGenerator kGenerator = KeyGenerator.getInstance(enType_AES);
			SecureRandom sRandom = new SecureRandom();
			kGenerator.init(sRandom);//不使用种子,每次生成的都不同
			genSecretKey = kGenerator.generateKey();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return genSecretKey;
	}
	
	
	/**
	 * 加密
	 * @param str
	 * @param genSecretKey
	 * @return
	 */
	public static byte[] testEncryptBytes(String str,SecretKey genSecretKey){
		byte encrypt [] = null;
		try {
			Cipher cipher = Cipher.getInstance(enType_AES);
			cipher.init(Cipher.ENCRYPT_MODE, genSecretKey);//加密模式,密钥
			//cipher.update(str.getBytes());
			encrypt = cipher.doFinal(str.getBytes());
		} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) {
			e.printStackTrace();
		}
		return encrypt;
	}
	
	public static String testEncrypt(String str,SecretKey genSecretKey){
		byte[] testEncryptBytes = testEncryptBytes(str, genSecretKey);
		System.out.println(Arrays.toString(testEncryptBytes));
		System.out.println("加密后的数组长度"+testEncryptBytes.length);
		return (new String(testEncryptBytes));
	}
	
	
	
	
	/**
	 * 解密
	 * @param str
	 * @param genSecretKey
	 * @return
	 */
	public static String testDecrptBytes(byte[] bytes,SecretKey genSecretKey){
		String decoderStr = null;
		try {
			Cipher cipher = Cipher.getInstance(enType_AES);
			cipher.init(Cipher.DECRYPT_MODE, genSecretKey);//解密模式
			//cipher.update(str.getBytes());
			byte[] doFinal = cipher.doFinal(bytes);
			decoderStr = new String(doFinal);
		} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
			e.printStackTrace();
		}
		return decoderStr;
	}
	
	public static String testDecrpt(String str,SecretKey genSecretKey){
		System.out.println(Arrays.toString(str.getBytes()));
		System.out.println("数组的大小"+str.getBytes().length);
		return testDecrptBytes(str.getBytes(), genSecretKey);
	}
}

2.分析出现此异常的情况:

如果不把加密后的数组拼接为字符串,直接返回,然后使用这个加密后的数组进行解密没有任何错误
但是把加密后的数组拼接为字符串,然后解密时在把此字符串转为数组,就会出现此异常

3.具体分析:

发现当把字节数组转为字符串后,在把字符串.getBytes()获得数组,发现两个字节数组前后不一样了,这是报错的位置所在声明:new String(byte[]),和"str".getBytes(),两个方法使用的编码一样,然后换成其他编码也出现这样情况
原因:

3.1. 为什么数组转字符串,字符串然后转数组会出现,前后两个字节数组的值会不同,因为并不是每个字节数和编码集上的字符都有对应关系,如果一个字节数在编码集上没有对应,编码new String(byte[]) 后,往往解出来的会是一些乱码无意义的符号:例如:��,

但是解码的时候,�这个字符也是一个字符在编码表中也有固定的字节数用来表示,所有解码出来的值必定是编码表中对应的值,除非你的字节数组中的字节数正好在编码表中有对应的值,否则编码,解码后的字节数组会不一样

误区: 误以为所有的字节数组都可以new String(),然后在通过String.getBytes()还原

3.2.再说这个异常报:解密的字节数组必须是16的倍数,这得从AES的原理说起,AES是把数据按16字节分组加密的,所有如果数组长度不是16的倍数会报错

AES原理
AES是对数据按128位,也就是16个字节进行分组进行加密的,每次对一组数据加密需要运行多轮。而输入密钥的长度可以为128、192和256位,也就是16个字节、24个字节和32个字节,如果用户输入的密钥长度不是这几种长度,也会补成这几种长度。无论输入密钥是多少字节,加密还是以16字节的数据一组来进行的,密钥长度的不同仅仅影响加密运行的轮数。

4.解决的办法:
4.1 可以用base64对参生的数组进行编码,然后在解码,这样不会像new String(byte[]),getBytes()那样造成数组前后不一致,一开始,我看到大部分人都是用base64,我也只是以为多一层编码看起来安全一些而已,没想到base64对数组的处理是不会造成误差的

4.2 就是直接返回数组,然后再用数组解密咯

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用中的错误提示"javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher"是在解密过程中出现的异常。这个异常的意思是解密的输入长度必须是8的倍数才能使用填充模式进行解密。同样的,引用中的异常提示"javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher"是在AES解密过程中出现的异常。这个异常的意思是解密的输入长度必须是16的倍数才能使用填充模式进行解密。而引用中的异常提示"java.lang.RuntimeException: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher"也是在解密过程中出现的异常,意思与前两个异常相同,都是解密的输入长度必须是16的倍数才能使用填充模式进行解密。所以,解决这个问题的方法就是确保解密的输入长度是符合要求的,即是8的倍数或是16的倍数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padd](https://blog.csdn.net/weixin_45915335/article/details/124152930)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with pad](https://blog.csdn.net/qq_30624649/article/details/114937740)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [java javax.crypto.IllegalBlockSizeException: Data must not be longer than 245 bytes](https://blog.csdn.net/weixin_38081382/article/details/125485124)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值