2013-06-21 22 views
13

Tôi nhận được một lỗi giải mã trong lớp java:javax.crypto.IllegalBlockSizeException: chiều dài đầu vào phải là bội số của 16 khi giải mã với đệm mật mã

javax.crypto.IllegalBlockSizeException : 
    Input length must be multiple of 16 when decrypting with padded cipher. 

Tôi có thể làm gì để giải quyết vấn đề này?

UPDATE:

tôi quên đề cập đến nó đang làm việc một lần và khi thời gian im thứ hai cố gắng để thực hiện nó một lần nữa ném các lỗi nêu trên của nó.

package com.tb.module.service; 
import java.security.Key; 
import java.security.spec.InvalidKeySpecException; 

import javax.crypto.Cipher; 
import javax.crypto.spec.SecretKeySpec; 

import sun.misc.*; 

/** 
* This class is used for encrypt and decrypt the password field. 
* 
*/ 
public class PswdEnc { 

    private static final String ALGO = "AES"; 
    private static final byte[] keyValue = new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' }; 

    public static String encrypt(String Data) throws Exception { 
     Key key = generateKey(); 
     Cipher c = Cipher.getInstance(ALGO); 
     c.init(Cipher.ENCRYPT_MODE, key); 
     byte[] encVal = c.doFinal(Data.getBytes()); 
     String encryptedValue = new BASE64Encoder().encode(encVal); 
     return encryptedValue; 
    } 

    public static String decrypt(String encryptedData) throws Exception { 
     Key key = generateKey(); 
     Cipher c = Cipher.getInstance(ALGO); 
     c.init(Cipher.DECRYPT_MODE, key); 
     byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData); 
     byte[] decValue = c.doFinal(decordedValue); 
     String decryptedValue = new String(decValue); 
     return decryptedValue; 
    } 


    private static Key generateKey() throws Exception { 
     Key key = new SecretKeySpec(keyValue, ALGO); 
     return key; 
    } 

} 
+0

Bất cứ điều gì bạn giải mã đều sai kích thước. Nó cần phải là bội số của kích thước khối (16) hoặc nếu không nó không thể được giải mã. Làm thế nào bạn nhận được dữ liệu đã giải mã của bạn? – thegrinner

+0

thực sự tôi đang mã hóa mật khẩu trước khi lưu nó vào sql db. sau đó trong khi lấy tôi đang cố giải mã nó. – baburao113

+0

Bạn có chắc chắn dữ liệu bạn đang lưu và dữ liệu bạn đang đọc có cùng độ dài không? – thegrinner

Trả lời

2

Một vài ý kiến:

import sun.misc.*; Đừng làm điều này. Nó không chuẩn và không được bảo đảm giống nhau giữa các triển khai. Có sẵn các thư viện khác với chuyển đổi Base64.

byte[] encVal = c.doFinal(Data.getBytes()); Bạn đang dựa vào mã hóa ký tự mặc định tại đây. Luôn chỉ định mã hóa ký tự bạn đang sử dụng: byte[] encVal = c.doFinal(Data.getBytes("UTF-8")); Mặc định có thể khác nhau ở những nơi khác nhau.

Khi @thegrinner chỉ ra, bạn cần kiểm tra rõ ràng độ dài của mảng byte của bạn. Nếu có sự khác biệt, sau đó so sánh chúng theo byte để xem sự khác biệt đang ở đâu.

+0

* Có các thư viện khác có chuyển đổi Base64 *> Kể từ Java 6, hãy thử 'DatatypeConverter'. –

57

Thuật toán bạn đang sử dụng, "AES", là viết tắt của "AES/ECB/NoPadding". Điều này có nghĩa là bạn đang sử dụng AES algorithm với kích thước khóa 128 bit và block size, với ECBmode of operationno padding.

Nói cách khác: bạn chỉ có thể mã hóa dữ liệu theo khối 128 bit hoặc 16 byte. Đó là lý do tại sao bạn nhận được rằng ngoại lệ IllegalBlockSizeException.

Nếu bạn muốn mã hóa dữ liệu ở kích thước không nhiều 16 byte, bạn sẽ phải sử dụng một số loại đệm hoặc một dòng mã. Ví dụ, bạn có thể sử dụng CBC mode (một phương thức hoạt động có hiệu quả chuyển đổi mật mã khối thành stream cipher) bằng cách chỉ định "AES/CBC/NoPadding" làm thuật toán hoặc đệm PKCS5 bằng cách chỉ định "AES/ECB/PKCS5", tự động thêm một số byte vào cuối dữ liệu của bạn theo một định dạng rất cụ thể để làm cho kích thước của bản mã có nhiều là 16 byte và theo cách mà thuật toán giải mã sẽ hiểu rằng nó phải bỏ qua một số dữ liệu.

Trong mọi trường hợp, tôi đặc biệt khuyên bạn nên dừng ngay bây giờ những gì bạn đang làm và nghiên cứu một số tài liệu giới thiệu về mật mã. Ví dụ: kiểm tra Crypto I on Coursera. Bạn nên hiểu rất rõ ý nghĩa của việc lựa chọn một chế độ này hay cách khác, điểm mạnh của chúng là gì và quan trọng nhất là điểm yếu của chúng. Nếu không có kiến ​​thức này, nó rất dễ dàng để xây dựng các hệ thống rất dễ phá vỡ.


Cập nhật: dựa trên ý kiến ​​của bạn về vấn đề, đừng bao giờ mã hóa mật khẩu khi lưu trữ chúng vào một cơ sở dữ liệu !!!!! Bạn không bao giờ nên làm điều này. Bạn phải HASH mật khẩu, được muối đúng cách, hoàn toàn khác với mã hóa. Thực sự, làm ơn, đừng làm những gì bạn đang cố gắng làm ... Bằng cách mã hóa mật khẩu, chúng có thể được giải mã. Điều này có nghĩa là bạn, là người quản lý cơ sở dữ liệu và ai biết khóa bí mật, bạn sẽ có thể đọc mọi mật khẩu được lưu trữ trong cơ sở dữ liệu của bạn.Hoặc bạn biết điều này và đang làm điều gì đó rất, rất xấu, hoặc bạn không biết điều này, và nên bị sốc và ngăn chặn nó.

+0

Tôi đã không nhận thức được thực tế là tôi không nên mã hóa mật khẩu và lưu trữ nó trong cơ sở dữ liệu. Cảm ơn bạn về thông tin. – baburao113

+0

@ baburao113 sau đó bạn thực sự nên chấp nhận câu trả lời –

+6

+1 để đề xuất băm trên mã hóa –

2

Để giải quyết một số vấn đề bạn phải thực hiện trong mã của mình, chỉ cần tạo kiểu trả về mã hóa() API của lớp của bạn là mảng byte [] và trong decrypt() API của mảng byte [] lớp của bạn để thực hiện điều này bạn có thể giải quyết nhiều chiều dài đầu vào của 16 ngoại lệ.

Vui lòng tham khảo dưới đây đang làm việc:

public static byte[] encrypt(String value) { 
     byte[] encrypted = null; 
     try { 

      byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'}; 
      Key skeySpec = new SecretKeySpec(raw, "AES"); 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      byte[] iv = new byte[cipher.getBlockSize()]; 

      IvParameterSpec ivParams = new IvParameterSpec(iv); 
      cipher.init(Cipher.ENCRYPT_MODE, skeySpec,ivParams); 
      encrypted = cipher.doFinal(value.getBytes()); 
      System.out.println("encrypted string:" + encrypted.length); 

     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     return encrypted; 
    } 

    public static byte[] decrypt(byte[] encrypted) { 
     byte[] original = null; 
     Cipher cipher = null; 
     try { 
      byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'}; 
      Key key = new SecretKeySpec(raw, "AES"); 
      cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      //the block size (in bytes), or 0 if the underlying algorithm is not a block cipher 
      byte[] ivByte = new byte[cipher.getBlockSize()]; 
      //This class specifies an initialization vector (IV). Examples which use 
      //IVs are ciphers in feedback mode, e.g., DES in CBC mode and RSA ciphers with OAEP encoding operation. 
      IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte); 
      cipher.init(Cipher.DECRYPT_MODE, key, ivParamsSpec); 
      original= cipher.doFinal(encrypted); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     return original; 
    } 
0

Vâng đó là Do

bạn chỉ có thể mã hóa dữ liệu trong khối 128 bit hoặc 16 byte. Đó là lý do tại sao bạn nhận được ngoại lệ IllegalBlockSizeException. và một cách là mã hóa dữ liệu đó trực tiếp vào chuỗi.

xem nội dung này. Hãy thử và u sẽ có thể giải quyết điều này

public static String decrypt(String encryptedData) throws Exception { 

    Key key = generateKey(); 
    Cipher c = Cipher.getInstance(ALGO); 
    c.init(Cipher.DECRYPT_MODE, key); 
    String decordedValue = new BASE64Decoder().decodeBuffer(encryptedData).toString().trim(); 
    System.out.println("This is Data to be Decrypted" + decordedValue); 
    return decordedValue; 
} 

hy vọng điều đó sẽ hữu ích.

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