javax.crypto.BadPaddingException:给定最终块未正确填充

我必须在我的服务器上解密一个帧。 加密帧来自客户端设备通过套接字上的GPRS。 使用TripleDes和给定密钥进行加密。我在服务器端使用相同的算法和密钥。 Frame是Hex和Ascii String的组合。 现在的问题是:当我用零填充我的字节数组时,我得到以下exception。

javax.crypto.BadPaddingException: Given final block not properly padded 

以下是我的代码:

 byte[] key = new byte[]{31, 30, 31, 36, 32, 11, 11, 11, 22, 26, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}; myKeySpec = new DESedeKeySpec(key); mySecretKeyFactory = SecretKeyFactory.getInstance("TripleDES"); de = mySecretKeyFactory.generateSecret(myKeySpec); Cipher c = Cipher.getInstance("TripleDES"); c.init(Cipher.DECRYPT_MODE, key); int l = completeHexStr.length(); if (l%8==1){ completeHexStr = completeHexStr + "0000000"; }else if (l%8==7){ completeHexStr = completeHexStr + "0"; } byte decordedValue[] =completeHexString.getBytes(); byte[] decValue = c.doFinal(decordedValue); String decryptedValue = new String(decValue); System.out.println("decryptedValue= " + decryptedValue); 

以下是我在代码中使用的函数:

  public String stringToHex(String base) { StringBuffer buffer = new StringBuffer(); int intValue = 0; for (int x = 0; x < base.length(); x++) { intValue = base.charAt(x); String hex = Integer.toHexString(intValue); if (hex.length() == 1) { buffer.append("0" + hex + ""); } else { buffer.append(hex + ""); } } return buffer.toString(); } public String byteToAscii(byte[] b, int length) { String returnString = ""; for (int i = 0; i < length; i++) { returnString += (char) (b[i] & 0xff); } return returnString; } 

这是用于客户端加密的c中的代码。

 #include  const unsigned char fixed_key[] = { 0x31, 0x30, 0x31, 0x36, 0x32, 0x11, 0x11, 0x11, 0x22, 0x26, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}; int Comm_Encrypt_Data(unsigned char *Test_Input_Data, int Len_Input_Data) { int Count_Input_Data, Counter_Input_Data; unsigned long Timer_1; unsigned char Init_Vector[8]; int Counter_Init_Vector, Temp_Byte_Count; unsigned char *Temp_Dst_Ptr, *Temp_Src_Ptr; unsigned char Temp_Input_Frame[9], Temp_Output_Frame[9]; unsigned char Test_Output_Data[500]; unsigned char Test_Key_Arr[9]; memset(&Init_Vector[0], '\0', sizeof(Init_Vector)); memset(Test_Key_Arr, '0', sizeof(Test_Key_Arr)); memcpy(Test_Key_Arr, &fixed_key[0], 8); Test_Key_Arr[sizeof(Test_Key_Arr)-1] = '\0'; Display_Data("KEY: ", Test_Key_Arr, sizeof(Test_Key_Arr)-1); memset(Test_Output_Data, '\0', sizeof(Test_Output_Data)); memcpy(Test_Output_Data, Test_Input_Data, 48); Count_Input_Data = Len_Input_Data -48 -3; //minus Data before payload, 3 bytes of '|' and CRC Counter_Input_Data = 0; while(Counter_Input_Data  8) Temp_Byte_Count = 8; memcpy(Temp_Input_Frame, &Test_Input_Data[48+Counter_Input_Data], Temp_Byte_Count); //succeeding bytes to be 0 if(Temp_Byte_Count < 8) { memset(&Temp_Input_Frame[Temp_Byte_Count], '0', (8-Temp_Byte_Count)); } Display_Data("InPut Data Before Init",Temp_Input_Frame, Temp_Byte_Count); //============Initialize the data Temp_Dst_Ptr = (unsigned char *)Temp_Input_Frame; Temp_Src_Ptr = (unsigned char *)&Init_Vector[0]; for(Counter_Init_Vector =0;Counter_Init_Vector < 8; Counter_Init_Vector++) *Temp_Dst_Ptr++ ^= *Temp_Src_Ptr++; //============Initializing data ends DES(DESE, (unsigned char *)&Test_Key_Arr[0], (unsigned char *)&Temp_Input_Frame[0], (unsigned char *)&Temp_Output_Frame[0]); //DES(TDES3KE, (unsigned char *)&Test_Key_Arr[0], // (unsigned char *)&Temp_Input_Frame[0], (unsigned char *)&Temp_Output_Frame[0]); Display_Data("AFTER DES::::", Temp_Output_Frame, Temp_Byte_Count); memcpy(&Test_Output_Data[48+Counter_Input_Data], Temp_Output_Frame, Temp_Byte_Count); Counter_Input_Data += Temp_Byte_Count; if(Counter_Input_Data < Count_Input_Data) { memcpy(Init_Vector, Temp_Output_Frame, 8); } } { memset(Test_Input_Data, '\0', Len_Input_Data); memcpy(&Test_Input_Data[0], &Test_Output_Data[48], Counter_Input_Data); //1 Separator + 2 CRCs } Display_Data("Final Output Frame", Test_Input_Data, Counter_Input_Data); return Counter_Input_Data; } 

我是java Cryptography新手。 请告诉我怎么做? 任何人都可以发布可以正常工作的代码来解密我的框架。 提前致谢。

您的代码的主要问题是您使用默认的PKCS5Padding进行解密。 "TripleDES"将在内部产生"TripleDES/ECB/PKCS5Padding" 。 这是在Sun JCE提供商中实现的; 大多数其他提供商复制此默认值

看起来你期望零填充,这意味着你应该使用"DESede/ECB/NoPadding" 。 之后,您可以使用外部函数来计算纯文本大小(如果您不小心,删除零填充可能会删除末尾的零值纯文本)。

其他问题:

  • 尝试在解密之前填充数据(解密应该取消填充数据)
  • 编码和字符编码问题,例如尝试使用字符值"0"填充,这可能是错误的

我已经指出"ECB"因为我不知道实际使用的模式。 如果你能找到答案,你可以使用正确的模式和填充算法修改你的问题。 如果ECB不起作用,您可能也想尝试CBC模式。

请注意,除非特定情况,否则ECB模式不可安全使用。 使用随机IV的CBC是最低要求。

(3)DES加密/解密8字节的块。 由于并非所有文本都精确地为8个字节,因此最后一个块必须包含非纯文本字节的字节。

诀窍是找出哪一个是纯文本的最后一个字符。 有时预先知道纯文本的长度 – 然后填充字符可以是任何真实的。

如果未知纯文本的长度,则必须使用确定性填充算法,例如PKCS5Padding。 PKCS5Padding总是执行填充,即使明文是以字节为单位的N * blocksize。 原因很简单:否则它不知道最后一个字节是纯文本还是填充。

我稍后会尝试使用工作代码…必须测试它。 在此期间尝试使用填充算法。

如果文档没有告诉您在传入的密文上使用了什么填充,则使用“NoPadding”进行解密,这将接受最后一个块上的任何填充。 然后看看你最后一个块的hex。 这将告诉你在加密端使用了什么填充。 修改您的代码以期望正确的填充类型。 这里介绍了不同类型的填充。

我看了一下你的stringToHex方法,看起来似乎不对。 试试这个:

  StringBuilder rep = new StringBuilder(); for (byte b : base.getBytes) { rep.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1)); } System.out.println(rep); 

我还发现这个带有Padding示例的TripleDes ; 您可以尝试使用算法和转换示例使用。