0

I am new to blackberry development and got to complete a task of encryption and decryption with AES/ECB/NoPadding. I used below code, from internet.

Encryption method:

public static byte[] encrypt( byte[] keyData,String message )
    throws Exception
{


        byte[] data = message.getBytes("UTF-8");

        // Create the AES key to use for encrypting the data.
        // This will create an AES key using as much of the keyData
        // as possible.


        if ((data.length % 16) != 0 ) {
            StringBuffer buffer = new StringBuffer(message);
            int moduleOut = data.length % 16;
            int padding =  16 - moduleOut;
            for(int i = 0 ; i < padding; i++){
                buffer.append(" ");
            }
            data = buffer.toString().getBytes("UTF-8");
        }

        AESKey key = new AESKey( keyData);

        NoCopyByteArrayOutputStream out = new NoCopyByteArrayOutputStream(data.length);
        AESEncryptorEngine engine = new AESEncryptorEngine(key);
        BlockEncryptor encryptor = new BlockEncryptor(engine, out);


        encryptor.write(data,0,data.length);
        int finalLength = out.size();
        byte[] cbytes = new byte[finalLength];
        System.arraycopy(out.toByteArray(), 0, cbytes, 0, finalLength);
//      encryptor.close();
//      out.close();
        return cbytes;

    }

Decryption method:

    public static byte[] decrypt(byte[] keyData, byte[] base64EncodedData)
    throws CryptoException, IOException 
    {

//      String base64EncodedData=new String(base64EncodedData);

        byte[] cipherText =Base64ToBytes(new String(base64EncodedData));
        // First, create the AESKey again.
        AESKey key = new AESKey(keyData);

        // Now, create the decryptor engine.
        AESDecryptorEngine engine = new AESDecryptorEngine(key);

        // Create the BlockDecryptor to hide the decryption details away.
        ByteArrayInputStream input = new ByteArrayInputStream(cipherText);
        BlockDecryptor decryptor = new BlockDecryptor(engine, input);

        // Now, read in the data.
        byte[] temp = new byte[100];
        DataBuffer buffer = new DataBuffer();

        for (;;) 
        {
            int bytesRead = decryptor.read(temp);
            buffer.write(temp, 0, bytesRead);

            if (bytesRead < 100) 
            {
                // We ran out of data.
                break;
            }
        }

        byte[] plaintext = buffer.getArray();       
        return plaintext;

        }

Base64 to Bytes convert method:

private static byte[] Base64ToBytes(String code) {

        byte[] aesString = null;
        try 
        {
            aesString = Base64InputStream.decode(code);
        }
        catch (IOException ioe)
        {
        }
        return aesString;
    }

Now the problem is when i encrypt my string with above method i get padded unicodes at the end of the string, which is not tolerable at Server side.

I know it is due to PKCS5FormatterEngine and its normal to have characters appended at end of the string while using this class.

But what if i want to encrypt and decrypt string with AES/ECB method and that too with NoPadding. I know ECB is not a secure mode and all that but server is with PHP and ready, works great in Android, and J2ME.

Please guide. How to bypass PKCS5FormatterEngine or encrypt without any padding.

Update:

I tried to use Cipher class in Blackberry as i used in Android and J2ME but it seems unavailable in net_rim_api.jar, even i tried downloading bouncy castle jar file and dependent class NoSuchAlogrithmException so java.security jar (org.osgi.foundation-1.0.0.jar), compiles but when i try to run it stops saying duplicate classes found. It has a problem with few duplicate classes in jar i have kept for java.security.

If you have solution towards this, please let me know.

Update for Answer: I have update my code with full encryption and decryption code and also check the answer for better understanding.

Ankit
  • 1,148
  • 3
  • 15
  • 31
  • Related: http://stackoverflow.com/questions/7615743/java-aes-without-padding, http://stackoverflow.com/questions/14210082/blackberry-encryption-aes-256-no-padding. And as you noted, ECB is one of the worst choices for AES. I'd rather change the server code to accept a more secure mode. – Mister Smith Sep 17 '13 at 08:33
  • @MisterSmith Hi thanks for your reply, please check the question again, i have updated it. – Ankit Sep 17 '13 at 09:01
  • 1
    AFAIK, you can't encrypt using AES without padding, AES requires data in 16 byte chunks. I suggest you are just using the wrong padding, or perhaps the Server does not expect any padding. The Server might be incorrect, but you might get away with it, for example you could pad XML data to a 16 byte boundary using spaces, and then the Server would be quite happy even though it does not remove the padding because the spaces are ignored by XML. – Peter Strange Sep 17 '13 at 09:12
  • 1
    @PeterStrange You can encrypt with AES without padding, provided the original data is aligned with the 16 byte block size. However, there are not many use cases where this is possible or sensible. – Duncan Jones Sep 17 '13 at 09:19
  • @PeterStrange Yes you are right, server is not expecting any padding. When i use PKCS5 in blackberry and send data, server has problem with the request as there are characters padded at the end. I agree that server is incorrect, but we have already setup our server and apps ready in Android and J2ME with this Cipher encryptor = Cipher.getInstance("AES/ECB/NoPadding"); What do you suggest in this case? – Ankit Sep 17 '13 at 09:21
  • @PeterStrange You mean to say AES without padding is possible but only with 16 byte block size not more that that. Can you please guide me how, i couldn't find way to do AES without padding in Blackberry. – Ankit Sep 17 '13 at 10:11
  • 1
    @Ankit - Look at the Arrays class in Blackberry Java to improve the efficiency of your padding code. – Peter Strange Sep 19 '13 at 11:27

1 Answers1

3

Not sure this is really an answer in general, but it might help in this specific case, so I am adding it as such.

You can't really use AES without some padding, because the AES processing does not wish to assume the data you supply will be a multiple of 16 bytes. However if you actually always supply a buffer that is a multiple of 16 bytes, then you can just encrypt your data with code like this:

        AESEncryptorEngine engine = new AESEncryptorEngine( key );
        for ( int j = 0; j < ciphertext.length - 15;  ) {
            engine.encrypt(plainText, j, ciphertext, j);
            j = j+16;
        }

So how do you make sure this works OK at the other end? It may or may not be possible to do this - it actually depends on what is being transferred.

But if, for example, you were passing XML data, then you can append spaces to make the data up to a 16 byte boundary and these will be decrypted as spaces by the Server, and then ignored by the parsing. You can add redundant padding bytes to a variety of file formats and the padding will be ignored, it all depends on the file format being processed.

Update

Given that the actual data is JSON and that I believe that JSON will ignore trailing spaces, the approach I would take is append spaces to the JSON data before encrypting it.

So convert the JSON string to bytes:

byte [] jsonBytes = jsonString.getBytes("UTF-8");

pad this if you need too:

if ( (jsonBytes.length % 16) != 0 ) {
// Now pad this with spaces
}

and you can encrypt the result with no worries about padding bytes.

Peter Strange
  • 2,640
  • 11
  • 11
  • It works great, but my data size is not fixed and not sure will be multiple of 16 bytes. So solution is not for me. But it made my concept clear how this characters are being added or padded at the end of string, it should be multiple of 16 bytes. If it is not then missing number will be padded with characters at the end of encrypted string. Thanks for your reply. – Ankit Sep 18 '13 at 11:51
  • Please let me know if you have any idea to solve even if i supply data that is not multiple of 16 bytes and varies. – Ankit Sep 18 '13 at 11:54
  • You said "even if i supply data that is not multiple of 16 bytes". Please re-read my answer - that is exactly what I was describing. You must add bytes that will ignored by the Server processing. The byte you add depends on the data you are sending. So what sort of data are you sending? XML? JSON? Tell us what this is and we can probably suggest a byte you can use to do the padding. But I'd like to think you can figure this out for yourself. – Peter Strange Sep 18 '13 at 13:51
  • I am sending JSON Object. Please suggest and we have a PHP server, which is not handling padded string, so responses with some error message. This works fine in Android and J2ME as it supports AES/ECB/NoPadding. – Ankit Sep 18 '13 at 14:26
  • To be precise, you are sending a JSON string, which is converted to bytes. I have updated my answer to demonstrate a possible solution. – Peter Strange Sep 18 '13 at 15:11
  • You made my day.. Its working great. This comment is to help others, i checked the differed number of 16 and output of (data.length % 16) and added the spaces, when i checked on the server client with new padded space encoded string, it worked like a charm. – Ankit Sep 19 '13 at 07:55