Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Data not block size aligned in codenameone BouncyCastle (No Padding)

I am trying to encrypt an ISO-0 pinblock using the codenameone BouncyCastle lib. The methods I use to achieve this is as follows:

private static byte[] performEncrypt(byte[] key, String plainText, boolean padding) {
    byte[] ptBytes = plainText.getBytes();

    BufferedBlockCipher cipher;
    if (padding) {
        cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESedeEngine()));
    } else {
        cipher = new BufferedBlockCipher(new CBCBlockCipher(new DESedeEngine()));
    }
    cipher.init(true, new KeyParameter(key));
    byte[] rv = new byte[cipher.getOutputSize(ptBytes.length)];
    int oLen = cipher.processBytes(ptBytes, 0, ptBytes.length, rv, 0);
    try {
        cipher.doFinal(rv, oLen);
    } catch (CryptoException ce) {
        LoggingUtil.error(TAG, ce, "Unexpected Exception");
    }
    return rv;
}

private static String createIso0PinBlock(String pin, String number) {
    ...
}

private static String getPaddedData(String data, byte padCharacter) {
    String paddedData = ByteUtil.pad(data, (char) padCharacter, 8).toString();
    return paddedData;
}

public static String createPinBlockAndEncrypt(String pin, String number) {
    LoggingUtil.debug("SecurityUtil", "CREAT PIN BLOCK AND ENCRYPT.. PIN: " + pin + " NUMBER: " + number);
    String pb = createIso0PinBlock(pin, number.substring(0, number.length() - 1));
    LoggingUtil.debug("SecurityUtil", "PINBLOCK: " + pb);
    String padded = getPaddedData(pb, (byte) 0x00);
    LoggingUtil.debug("SecurityUtil", "PADDED: " + padded);
    byte[] encrypted = performEncrypt(Hex.decode(KEY.getBytes()), new String(ByteUtil.hex2byte(padded)), false);
    return ByteUtil.byte2hex(encrypted);
}

In ByteUtil:

public static StringBuilder pad(String data, char padCharacter, int multiplier) {
    StringBuilder text = new StringBuilder();
    text.append(data);
    while (text.length() % multiplier != 0) {
        text.append(padCharacter);
    }
    return text;
}

To give example Log outputs:

[SecurityUtil] CREAT PIN BLOCK AND ENCRYPT.. PIN: 2255 NUMBER: 6284734104205417486
[SecurityUtil] PINBLOCK: 042214FBDFABE8B7
[SecurityUtil] PADDED: 042214FBDFABE8B7

When I run this through a public static void main method, it works as expected, however, when I build this for Android via Codenameone, I get the following error in logcat:

org.bouncycastle.crypto.DataLengthException: data not block size aligned
org.bouncycastle.crypto.BufferedBlockCipher.doFinal(BufferedBlockCipher.java:275)

Despite the padded pinblock being 16 in length (a multiple of 8).

Any help regarding this issue would be appreciated.

like image 307
Propagandian Avatar asked Oct 29 '22 23:10

Propagandian


1 Answers

Encryption works on binary data, and your pinblock is binary, so keep it that way.

When calling performEncrypt(..) you convert your hex encoded pinblock to a string with new String(ByteUtil.hex2byte(padded)), and inside performEncrypt(...) you convert it to a byte array with byte[] ptBytes = plainText.getBytes();. The problem with this is that not all byte sequences can be mapped correctly back and forth through a string, and you might end up with different data and even different length etc. take a look here

Change your signature of you performEncrypt(..) to:

private static byte[] performEncrypt(byte[] key, byte[] plainText, boolean padding) {

and avoid converting through a string altogether.

like image 172
Ebbe M. Pedersen Avatar answered Nov 08 '22 03:11

Ebbe M. Pedersen