2014-04-14 15 views
5

Tôi có một tệp khóa riêng được viết bằng DES/ECB/PKCS5Padding (khóa 56 bit DES được tạo bởi một cụm từ bí mật) và tôi muốn giải mã nó. Tôi không biết tại sao, nhưng mỗi lần tôi cố gắng decript, phương pháp doFinal của lớp mật mã của tôi là ném lỗi này:BadPaddingException: Cho khối cuối cùng không đúng đệm

javax.crypto.BadPaddingException: Given final block not properly padded at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com.sun.crypto.provider.DESCipher.engineDoFinal(DashoA13*..) at javax.crypto.Cipher.doFinal(DashoA13*..) at...

Đây là mã của tôi:

public static PrivateKey readPrivateKeyFromFile(File file, String chaveSecreta) { 
    try { 
     SecureRandom r = new SecureRandom(chaveSecreta.getBytes()); 
     KeyGenerator keyGen = KeyGenerator.getInstance("DES"); 
     keyGen.init(56, r); 
     Key key = keyGen.generateKey(); 

     byte[] privateKeyBytes = decryptPKFile(file, key); 

     KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
     EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes); 
     PrivateKey privateKey = null; 
     try { 
      privateKey = keyFactory.generatePrivate(privateKeySpec); 
     } catch (InvalidKeySpecException e) { 
      JOptionPane.showMessageDialog(null, "Erro 01, tente mais tarde"); 
     } 
     return privateKey; 
    } catch (NoSuchAlgorithmException e) { 
     JOptionPane.showMessageDialog(null, "Erro 02, tente mais tarde"); 
    } 
    return null; 
} 

public static byte[] decryptPKFile(File file, Key key){ 
    try{ 
     Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); 
     byte[] cipherText = readBytes(file); 
     cipher.init(Cipher.DECRYPT_MODE, key); 
     System.out.println(cipher); 
     System.out.println(cipherText); 
     byte[] text = cipher.doFinal(cipherText); 
     return text; 
    }catch(Exception e){ 
     e.printStackTrace(); 
     return null; 
    } 
} 

public static byte[] readBytes(File file) { 
    try { 
     FileInputStream fs = new FileInputStream(file); 
     byte content[] = new byte[(int) file.length()]; 
     fs.read(content); 
     return content; 
    } catch (FileNotFoundException e) { 
     System.out.println("Arquivo não encontrado!"); 
     e.printStackTrace(); 
    } catch (IOException ioe) { 
     System.out.println("Erro ao ler arquivo!"); 
     ioe.printStackTrace(); 
    } 
    return null; 
} 

Bất kỳ syggestions?

+0

Tôi đoán đầu vào bạn đọc từ tệp không phải là văn bản được mã hóa hợp lệ. Với DES là thuật toán khối, bạn nên kiểm tra xem chiều dài của tập tin là phép nhân của 64. Nếu không, nó sẽ có nghĩa là, tập tin đó bị hỏng. – markubik

+2

Bạn có nghĩa là bội số của 8? Đó là, tập tin không bị hỏng, tôi đã kiểm tra. –

+0

@markubik Đó là một khóa ngẫu nhiên: P –

Trả lời

8

Bạn đang cố gắng giải mã bản mã bằng trình tạo số ngẫu nhiên được tạo bằng cách sử dụng một hạt giống cụ thể. Tuy nhiên, bạn không chỉ định thuật toán và thuật toán cũng có thể thay đổi trong nội bộ. Android thậm chí còn được biết là tạo ra một giá trị hoàn toàn ngẫu nhiên thay cho một số phiên bản.

Bạn cần sử dụng SecretKeyFactory không phải là KeyGenerator. Và tất nhiên bạn sẽ cần dữ liệu khóa 8 byte. Cách duy nhất để truy xuất điều này trong trường hợp của bạn là tìm kiếm thuật toán/triển khai SecureRandom trước và tính lại khóa.

Giờ mọi bản mã sẽ giải mã bằng bất kỳ khóa nào. DES ECB chỉ cung cấp một số loại bảo mật, chứ không phải tính toàn vẹn. Vấn đề là nó sẽ giải mã thành rác. Bây giờ nếu bạn cố gắng để loại bỏ các padding từ rác, bạn sẽ có thể nhận được một lỗi padding.

Nếu bạn "may mắn" - một lần trong khoảng 256 lần - bạn sẽ nhận được kết quả. Điều này xảy ra khi khối được giải mã kết thúc bằng 01 hoặc 0202, đó là phần đệm hợp lệ. Kết quả sẽ - tất nhiên - là rác thải, nhưng nó sẽ không kết thúc với một BadPaddingException. Trong trường hợp của bạn, ví dụ SecureRandomcó khả năng để trả lại cùng một giá trị không chính xác, vì vậy điều này có thể không bao giờ xảy ra.

Trong tương lai, vui lòng sử dụng PBKDF2 và cấp cho nó mật khẩu được mã hóa. Lưu ý rõ ràng mã hóa ký tự được sử dụng, Java SE sử dụng 8 bit thấp nhất của mảng char. Không bao giờ sử dụng String.getBytes() vì mã hóa mặc định có thể khác nhau giữa các hệ thống.

+1

Phew, xin lỗi vì đã có nhiều chỉnh sửa, đã đến muộn. –

+2

Tôi đoán đó là vì hệ thống của tôi. Tất cả mọi thứ hoạt động khi sử dụng Windows, nhưng nó sẽ không hoạt động trên máy Mac của tôi. Đoán đó là điều String.getBytes() bạn đã nói .. –

+1

http://stackoverflow.com/questions/9312816/java-platforms-default-charset-on-different-platforms –

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