2010-12-30 28 views
5

Tôi có mã sau đây.Lỗi giải mã: Khối đệm bị lỗi

byte[] input = etInput.getText().toString().getBytes(); 
    byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
     0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }; 

    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); 

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 

    // encryption pass 
    cipher.init(Cipher.ENCRYPT_MODE, key); 

    byte[] cipherText = new byte[cipher.getOutputSize(input.length)]; 
    int ctLength = cipher.update(input, 0, input.length, cipherText, 0); 
    ctLength += cipher.doFinal(cipherText, ctLength); 

    cipher.init(Cipher.DECRYPT_MODE, key); 
    byte[] plainText = new byte[cipher.getOutputSize(ctLength)]; 
    int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0); 

    String strLength = new String(cipherText,"US-ASCII"); 
    byte[] byteCiphterText = strLength.getBytes("US-ASCII"); 
    Log.e("Decrypt", Integer.toString(byteCiphterText.length)); 

    etOutput.setText(new String(cipherText,"US-ASCII")); 

    cipherText = etOutput.getText().toString().getBytes("US-ASCII"); 
    Log.e("Decrypt", Integer.toString(cipherText.length)); 

    ptLength += cipher.doFinal(plainText, ptLength); 
    Log.e("Decrypt", new String(plainText)); 
    Log.e("Decrypt", Integer.toString(ptLength)); 

Nó hoạt động hoàn hảo. Nhưng một khi tôi chuyển nó sang lớp. Nó luôn luôn nhấn lỗi trong dòng này.

ptLength += cipher.doFinal(plainText, ptLength); 

Error:Pad block corrupted 

Tôi đã kiểm tra và cả hai mã đều giống nhau. Ngay cả giá trị được chuyển trong chuỗi chuyển đổi thành byte đều không khác với mã ở trên. Bất kỳ ý tưởng có gì sai với mã?

public String Encrypt(String strPlainText) throws Exception, NoSuchProviderException, 
     NoSuchPaddingException { 
    byte[] input = strPlainText.getBytes(); 
    byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 
      0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }; 

    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); 

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 

    // encryption pass 
    cipher.init(Cipher.ENCRYPT_MODE, key); 

    byte[] cipherText = new byte[cipher.getOutputSize(input.length)]; 
    int ctLength = cipher.update(input, 0, input.length, cipherText, 0); 
    ctLength += cipher.doFinal(cipherText, ctLength); 

    return new String(cipherText, "US-ASCII"); 
} 

public String Decrypt(String strCipherText) throws Exception, 
     NoSuchProviderException, NoSuchPaddingException { 
    byte[] cipherText = strCipherText.getBytes("US-ASCII"); 
    int ctLength = cipherText.length; 
    byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 
      0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
      0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }; 

    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); 

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 

    // decryption pass 
    cipher.init(Cipher.DECRYPT_MODE, key); 
    byte[] plainText = new byte[cipher.getOutputSize(ctLength)]; 
    int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0); 
    ptLength += cipher.doFinal(plainText, ptLength); 

    return new String(plainText); 
} 
+0

Trừ khi bạn là hoàn toàn chắc chắn, hoặc chỉ làm việc trên một khối tại một thời điểm, bạn không bao giờ nên sử dụng chế độ ECB. Không bao giờ. –

+0

Sử dụng CBC thay vì – Codefor

Trả lời

1

Bạn đã chỉ định Đệm PKCS7. Padding của bạn được bảo quản khi được lưu trữ trong đối tượng String của bạn? Chuỗi của bạn có đối sánh 1: 1 với đầu ra byte bằng mật mã không? Nói chung, String không thích hợp để truyền dữ liệu nhị phân, chẳng hạn như đầu ra mã hóa.

+0

Xin lỗi, abit nhầm lẫn về câu hỏi của bạn, padding của bạn có được lưu giữ khi được lưu trữ trong đối tượng String của bạn không? -> Làm cách nào tôi có thể kiểm tra? Chuỗi của bạn có đối sánh 1: 1 với đầu ra byte bằng mật mã không? -> Bạn có nghĩa là chuỗi tôi nhập để mã hóa phải khớp với đầu ra byte? Nói chung, String là không thích hợp để truyền dữ liệu nhị phân, chẳng hạn như đầu ra mật mã .-> Tại sao lại nói như vậy? Khi tôi nhận được văn bản mật mã, tôi đã chuyển đổi nó bằng ASCII.Even Tôi reconvert nó thành mảng byte nó lấy lại chính xác cùng một giá trị . – kangalert

+0

Bạn có thể kiểm tra xem các byte trong chuỗi có khớp với mảng byte [] đầu tiên của bạn hay không. Tôi nghiêm túc nghi ngờ họ sẽ. "US-ASCII"! = Dữ liệu nhị phân. –

0

Trong trường hợp mật mã của bạn sử dụng đệm, điều đó có nghĩa là các dữ liệu đầu vào khác sẽ được đệm/làm tròn thành khối với một số kích thước được xác định trước (phụ thuộc vào thuật toán đệm). Giả sử bạn đã cung cấp 500 byte để mã hóa, kích thước khối đệm là 16 byte, vì vậy dữ liệu được mã hóa sẽ có kích thước 512 byte (32 khối) - 12 byte sẽ được đệm.

Trong mã của bạn, bạn đang mong đợi mảng được mã hóa có cùng kích thước với mảng nhập, điều này gây ra ngoại lệ. Bạn cần phải tính toán lại kích thước mảng đầu ra lưu ý trong phần đệm.

+0

Bạn có nghĩa là chuỗi tôi mã hóa phải có cùng kích thước của khối đệm của tôi? – kangalert

+0

Không, chuỗi (thực tế không phải chuỗi nhưng mảng byte []) phải được làm tròn thành khối đệm kích thước – barmaley

3

Như Yann Ramin đã nói, việc sử dụng String là một sự thất bại cho mật mã vào/ra. Đây là dữ liệu nhị phân

  • thể chứa 0x00
  • có thể chứa các giá trị mà không phải xác định hoặc ánh xạ tới nơi lạ trong mã hóa sử dụng

Sử dụng đồng bằng byte [] như trong ví dụ đầu tiên của bạn hoặc đi mã hóa hex hoặc mã hóa base64 byte [].

// this is a quick example - dont use sun.misc inproduction 
// - go for some open source implementation 
String encryptedString = new sun.misc.BASE64Encoder.encodeBuffer(encryptedBytes); 

Chuỗi này có thể được vận chuyển và lập bản đồ một cách an toàn về byte.

EDIT

cách Có lẽ an toàn nhất để đối phó với các vấn đề chiều dài là luôn luôn sử dụng trực tuyến thực hiện (IMHO):

Ví dụ

static public byte[] decrypt(Cipher cipher, SecretKey key, byte[]... bytes) 
     throws GeneralSecurityException, IOException { 
    cipher.init(Cipher.DECRYPT_MODE, key); 
    ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
    for (int i = 0; i < bytes.length; i++) { 
     bos.write(cipher.update(bytes[i])); 
    } 
    bos.write(cipher.doFinal()); 
    return bos.toByteArray(); 
} 
+1

Cảm ơn. Nhưng tôi có một lỗi trong bos.write (cipher.update (byte [i])); cipher.update chỉ chấp nhận mảng byte. – kangalert

+0

@kangalert bạn có nhận thấy chữ ký phương pháp không? byte [i] ** là một mảng byte. Có thể bạn thích ứng chữ ký với nhu cầu của bạn, sử dụng mảng mảng hoặc danh sách ... – mtraut

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