Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decryption Error: Pad block corrupted

I have the following code.

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

It works perfectly. But once I convert it to the class. It always hit the error in this line.

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

 Error:Pad block corrupted

I have checked and both code are exactly the same. Even the value passed in conversion string to byte all is no different from the code above. Any idea what's wrong with the code?

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);
}
like image 919
kangalert Avatar asked Dec 30 '10 06:12

kangalert


2 Answers

As Yann Ramin said, using String is a failure for cipher in/output. This is binary data that

  • can contain 0x00
  • can contain values that are not defined or mapped to strange places in the encoding used

Use plain byte[] as in your first example or go for hex encoding or base64 encoding the 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);

This string can be safely transported and mapped back to bytes.

EDIT

Perhaps safest way to deal with the length issue is to always use streaming implementation (IMHO):

Example

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();
}
like image 145
mtraut Avatar answered Nov 06 '22 20:11

mtraut


You have specified PKCS7 Padding. Is your padding preserved when stored in your String object? Is your string object a 1:1 match with the bytes output by the cipher? In general, String is inappropriate for passing binary data, such as a cipher output.

like image 23
Yann Ramin Avatar answered Nov 06 '22 19:11

Yann Ramin