8

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);
}
OlivierH
  • 3,875
  • 1
  • 19
  • 32
kangalert
  • 341
  • 2
  • 5
  • 7

3 Answers3

5

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();
}
mtraut
  • 4,720
  • 3
  • 24
  • 33
  • 1
    Thanks. But I have an error in bos.write(cipher.update(bytes[i])); cipher.update is accept byte array only. – kangalert Jan 04 '11 at 08:01
  • @kangalert did you notice the method signature? bytes[i] **is** a byte array. Maybe you adapt the signature to you needs, use array of array or list... – mtraut Jan 04 '11 at 08:29
1

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.

Yann Ramin
  • 32,895
  • 3
  • 59
  • 82
  • Sorry, abit confuse on your question, Is your padding preserved when stored in your String object?-> How could I check? Is your string object a 1:1 match with the bytes output by the cipher?-> You mean the string I enter for encrypt must be match with the bytes output? In general, String is inappropriate for passing binary data, such as a cipher output.-> Why say so?Once I get the cipher text I have converted it using ASCII.Even I reconvert it to byte array it get back exactly the same value. – kangalert Dec 30 '10 at 07:02
  • You can check if the bytes in the string match your first byte[] array. I seriously doubt they would. "US-ASCII" != binary data. – Yann Ramin Dec 30 '10 at 19:08
0

In your case cipher uses padding, that means in other words input data will be padded/rounded into blocks with some predefined size (which depends on padding algorithm). Let's say you have supplied 500 bytes to encrypt, padding block size is 16 bytes, so encrypted data will have size of 512 bytes (32 blocks) - 12 bytes will be padded.

In your code you're expecting encrypted array of the same size as input array, which causes exception. You need to recalculate output array size keeping in mind padding.

Barmaley
  • 16,638
  • 18
  • 73
  • 146