2012-05-03 32 views
14

Tôi phải giải mã một khung trên máy chủ của tôi. Khung được mã hóa đến từ thiết bị khách thông qua GPRS trên ổ cắm. Mã hóa được thực hiện với TripleDes và bằng khóa đã cho.I sử dụng cùng một thuật toán và khóa ở phía máy chủ. Frame là sự kết hợp của Hex và Ascii String. Bây giờ vấn đề là: Khi tôi pad mảng byte của tôi với số không, tôi nhận được ngoại lệ sau đây.javax.crypto.BadPaddingException: Cho khối cuối cùng không được đệm đúng cách

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

Tiếp theo là mã của tôi:

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); 

Sau đây là các chức năng mà tôi đang sử dụng bên trong các mã:

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; 
     } 

đây là mã trong c sử dụng để mã hóa ở phía khách hàng .

#include <svc_sec.h> 
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 < Count_Input_Data) 
{ 
Temp_Byte_Count = Count_Input_Data- Counter_Input_Data; 
if(Temp_Byte_Count > 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; 
} 

Tôi mới trong java Cryptography. Vui lòng cho tôi biết cách thực hiện? Ai có thể đăng mã có thể hoạt động đúng cách để giải mã khung của tôi. Cảm ơn trước.

Trả lời

6

(3) DES mã hóa/giải mã khối 8 byte. Vì không phải tất cả các văn bản đều chính xác 8 byte, khối cuối cùng phải chứa các byte không phải là bản gốc từ văn bản thuần túy.

Bí quyết là tìm hiểu xem chữ nào là ký tự cuối cùng của văn bản thuần tuý. Đôi khi chiều dài của văn bản thuần túy được biết trước - sau đó các ký tự đệm có thể là bất cứ điều gì thực sự.

Nếu độ dài của văn bản thuần túy không được biết thì thuật toán đệm xác định phải được sử dụng, ví dụ: PKCS5Padding. PKCS5Padding luôn thực hiện padding, ngay cả khi plaintext là N * blockize theo byte. Lý do cho điều này là đơn giản: nếu không nó không biết nếu byte cuối cùng là văn bản thuần hoặc đệm.

Tôi sẽ cố gắng đi kèm với mã làm việc sau ... phải kiểm tra. Trong khi chờ đợi, hãy thử sử dụng các thuật toán đệm.

+0

thanks.i đã làm việc với PKCS5Padding nhưng không có sự khác biệt nào tôi thấy trong trường hợp của mình. – java2485

3

Tôi đã xem xét phương pháp stringToHex của bạn và dường như không chính xác. Hãy thử cái này thay thế:

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

Tôi cũng tìm thấy ví dụ này TripleDes with Padding; bạn có thể thử với thuật toán và chuyển đổi ví dụ sử dụng.

4

Nếu tài liệu không cho bạn biết padding nào đang được sử dụng trên cyphertext đến, sau đó giải mã bằng "NoPadding", sẽ chấp nhận bất kỳ loại đệm nào trên khối cuối cùng. Sau đó, có một cái nhìn tại hex của khối cuối cùng của bạn. Điều đó sẽ cho bạn biết những gì padding đang được sử dụng ở cuối mã hóa. Sửa đổi mã của bạn để mong đợi loại đệm đúng. Các loại đệm khác nhau được che phủ here.

10

Vấn đề chính với mã của bạn là bạn đang giải mã bằng cách sử dụng mặc định PKCS5Padding. "TripleDES" sẽ dẫn đến "TripleDES/ECB/PKCS5Padding" nội bộ. Điều này là vì nó được thực hiện trong nhà cung cấp Sun JCE; hầu hết các nhà cung cấp khác sao chép mặc định này.

Có vẻ như bạn đang mong đợi không có đệm, có nghĩa là bạn nên sử dụng "DESede/ECB/NoPadding" để thay thế. Sau đó, bạn có thể sử dụng một hàm ngoài để tính toán kích thước văn bản thuần túy (loại bỏ không đệm có thể loại bỏ văn bản thuần có giá trị bằng 0 ở cuối nếu bạn không cẩn thận).

Các vấn đề khác:

  • cố gắng để dữ liệu pad trước khi giải mã (bạn nên unpad dữ liệu sau giải mã)
  • mã hóa và mã hóa ký tự vấn đề, chẳng hạn như cố gắng để pad với giá trị đặc trưng của "0", có thể là sai

Tôi đã chỉ định "ECB" vì tôi không biết thực tế chế độ được sử dụng. Bạn có thể sửa đổi câu hỏi của mình bằng thuật toán đúng và chế độ đệm nếu bạn có thể tìm hiểu. Bạn cũng có thể muốn thử chế độ CBC nếu ECB không hoạt động.

Lưu ý rằng chế độ ECB không an toàn để sử dụng ngoại trừ trường hợp rất cụ thể. Sử dụng CBC với một IV ngẫu nhiên là một yêu cầu tối thiểu.

+1

cảm ơn rất nhiều. bây giờ tôi đã nói với anh chàng khách hàng để gửi khung mã hóa với đệm. và tôi đã sử dụng DES/CBC/NoPadding và nó được giải mã tốt. – java2485

+0

Vui vì nó hoạt động, hy vọng tôi đã giúp giải quyết vấn đề ... –

Các vấn đề liên quan