views:

234

answers:

2

How do encrypt/decrypt a long or int using the Bouncy Castle crypto routines for BlackBerry? I know how to encrypt/decrypt a String. I can encrypt a long but can't get a long to decrypt properly.

Some of this is poorly done, but I'm just trying stuff out at the moment.

I've included my entire crypto engine here:

import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;

public class CryptoEngine
{

    // Global Variables

    // Global Objects
    private static AESFastEngine engine;

    private static BufferedBlockCipher cipher;

    private static KeyParameter key;

    public static boolean setEncryptionKey(String keyText)
    {
        // adding in spaces to force a proper key
        keyText += "                  ";

        // cutting off at 128 bits (16 characters)
        keyText = keyText.substring(0, 16);

        keyText = HelperMethods.cleanUpNullString(keyText);
        byte[] keyBytes = keyText.getBytes();
        key = new KeyParameter(keyBytes);
        engine = new AESFastEngine();
        cipher = new PaddedBufferedBlockCipher(engine);

        // just for now
        return true;
    }

    public static String encryptString(String plainText)
    {
        try
        {
            byte[] plainArray = plainText.getBytes();
            cipher.init(true, key);
            byte[] cipherBytes = new byte[cipher.getOutputSize(plainArray.length)];
            int cipherLength = cipher.processBytes(plainArray, 0, plainArray.length, cipherBytes, 0);
            cipher.doFinal(cipherBytes, cipherLength);
            String cipherString = new String(cipherBytes);
            return cipherString;
        }
        catch (DataLengthException e)
        {
            Logger.logToConsole(e);
        }
        catch (IllegalArgumentException e)
        {
            Logger.logToConsole(e);
        }
        catch (IllegalStateException e)
        {
            Logger.logToConsole(e);
        }
        catch (InvalidCipherTextException e)
        {
            Logger.logToConsole(e);
        }
        catch (Exception ex)
        {
            Logger.logToConsole(ex);
        }
        // else
        return "";// default bad value
    }

    public static String decryptString(String encryptedText)
    {
        try
        {
            byte[] cipherBytes = encryptedText.getBytes();
            cipher.init(false, key);
            byte[] decryptedBytes = new byte[cipher.getOutputSize(cipherBytes.length)];
            int decryptedLength = cipher.processBytes(cipherBytes, 0, cipherBytes.length, decryptedBytes, 0);
            cipher.doFinal(decryptedBytes, decryptedLength);
            String decryptedString = new String(decryptedBytes);

            // crop accordingly
            int index = decryptedString.indexOf("\u0000");
            if (index >= 0)
            {
                decryptedString = decryptedString.substring(0, index);
            }
            return decryptedString;
        }
        catch (DataLengthException e)
        {
            Logger.logToConsole(e);
        }
        catch (IllegalArgumentException e)
        {
            Logger.logToConsole(e);
        }
        catch (IllegalStateException e)
        {
            Logger.logToConsole(e);
        }
        catch (InvalidCipherTextException e)
        {
            Logger.logToConsole(e);
        }
        catch (Exception ex)
        {
            Logger.logToConsole(ex);
        }
        // else
        return "";// default bad value
    }

    private static byte[] convertLongToByteArray(long longToConvert)
    {
        return new byte[] { (byte) (longToConvert >>> 56), (byte) (longToConvert >>> 48), (byte) (longToConvert >>> 40), (byte) (longToConvert >>> 32), (byte) (longToConvert >>> 24), (byte) (longToConvert >>> 16), (byte) (longToConvert >>> 8), (byte) (longToConvert) };
    }

    private static long convertByteArrayToLong(byte[] byteArrayToConvert)
    {
        long returnable = 0;
        for (int counter = 0; counter < byteArrayToConvert.length; counter++)
        {
            returnable += ((byteArrayToConvert[byteArrayToConvert.length - counter - 1] & 0xFF) << counter * 8);
        }
        if (returnable < 0)
        {
            returnable++;
        }
        return returnable;
    }

    public static long encryptLong(long plainLong)
    {
        try
        {
            String plainString = String.valueOf(plainLong);
            String cipherString = encryptString(plainString);
            byte[] cipherBytes = cipherString.getBytes();
            long returnable = convertByteArrayToLong(cipherBytes);
            return returnable;
        }
        catch (Exception e)
        {
            Logger.logToConsole(e);
        }
        // else
        return Integer.MIN_VALUE;// default bad value
    }

    public static long decryptLong(long encryptedLong)
    {
        byte[] cipherBytes = convertLongToByteArray(encryptedLong);
        cipher.init(false, key);
        byte[] decryptedBytes = new byte[cipher.getOutputSize(cipherBytes.length)];
        int decryptedLength = cipherBytes.length;
        try
        {
            cipher.doFinal(decryptedBytes, decryptedLength);
        }
        catch (DataLengthException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IllegalStateException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (InvalidCipherTextException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        long plainLong = convertByteArrayToLong(decryptedBytes);

        return plainLong;
    }

    public static boolean encryptBoolean(int plainBoolean)
    {
        return false;
    }

    public static boolean decryptBoolean(int encryptedBoolean)
    {
        return false;
    }

    public static boolean testLongToByteArrayConversion()
    {
        boolean returnable = true;
        // fails out of the bounds of an integer, the conversion to long from byte
        // array does not hold, need to figure out a better solution
        for (long counter = -1000000; counter < 1000000; counter++)
        {
            long test = counter;
            byte[] bytes = convertLongToByteArray(test);
            long result = convertByteArrayToLong(bytes);
            if (result != test)
            {
                returnable = false;
                Logger.logToConsole("long conversion failed");
                Logger.logToConsole("test = " + test + "\n result = " + result);
            }
            // regardless
        }
        // the end
        Logger.logToConsole("final returnable result = " + returnable);
        return returnable;
    }
}
+1  A: 

It's probably the conversion from long -> byte[] -> String, in particular the conversion from String back into byte[]. You don't pass in an encoding for String.getBytes() so it's going to be using the default character encoding, which may be altering your data.

My suggestion is to expose encrypt/decrypt methods that take byte[] as an argument, to avoid String/byte[] conversion.

Also, you may want to take a look at the native RIM AES classes, AESEncryptorEngine and AESDecryptorEngine which may be faster than BouncyCastle (since they're native APIs) and require less code.

Marc Novakowski
I have methods which convert the long directly into a byte array, and the resulting cipher array is often longer than 64 bytes. I can't put the cipher array back into a long. Does this make sense?
DanG
Also, you know a lot about J2ME/BlackBerry programming. Thanks.
DanG
Also, I've found the RIM libraries to be MUCH slower (by over 30%), and also buggier.
DanG
It might be adding padding to the data so that it matches the encryption block size. It may not be possible to put the encrypted bytes back into a long.
Marc Novakowski
A: 

I just realized that with strong ciphers, the result length is usually/always greater than the length of the original. If it wasn't, a lookup table could be used. As such, its not possible to encrypt a long into a long every time, especially if it uses all 64 bits. If this doesn't make sense, see me for more info:

http://stackoverflow.com/questions/985830/how-do-i-encrypt-a-string-and-get-a-equal-length-encrypted-string

DanG