0

I want to convert 4 byte hex number to decimal number using java card 2.2.1.

E.g.: 50ef7f19 -> 1357872921

For this conversion i need to use 32 bit numbers so it is better to use the data type as integer. But i am not sure about usage of 'int' in java card. In the specification 'optional' is expressed for integer. What is the restriction of using it? If i don't use int, is there any other way to make calculations with big numbers?

Emel Uras
  • 394
  • 2
  • 13
  • Optional means that your JavaCard may or may not support `int` type. If you need int you have to make sure you buy the right card that has support for it. – Robert Jan 21 '14 at 08:50

2 Answers2

2

The biggest restriction on using int on Java Card Classic is that it simply is not supported on most smart cards implementing Java Card Classic. The other big restriction is that the API has almost no support for integers. So even if you could use integer arithmetic, the API only accepts bytes or shorts.

I've created a special class, JCInteger that also is able to perform 32 bit arithmetic if you're interested. I still haven't posted my test cases though, so use with care. You can of course create similar methods to perform integer arithmetic. If you're (extremely) lucky your chip may also implement BigNumber.

Note that initially you could just go from bytes representing hexadecimal characters (in ASCII or ASCII compatible encoding) to bytes. Only afterwards should you use integers, when required. Normally hex to byte conversion is performed at the terminal, not within the smart card.


If you are interested, here is a fast (minimal number of branches) but byte code intensive method of generating bytes from hexadecimals. Don't forget to feed it an even number of bytes, possibly add an offset and length parameter into the mix.

WARNING: Untested array handling (decoding is tested)

public static short fromHex(final byte[] hex, short hexOff, final short hexLen, final byte[] bin, short binOff) {

    // reuses offsets parameters for reasons of (unproven) optimization 

    // === check hex input parameters ===
    if (hexOff < 0 || hexOff >= hex.length) {
        CardRuntimeException.throwIt((short) 'H');
    }

    final short hexEnd = (short) (hexOff + hexLen);
    if (hexLen < 0 || hexEnd > hex.length || hexEnd < 0 || hexLen % 2 != 0) {
        CardRuntimeException.throwIt((short) 'H');
    }

    // === calculate final output size ===
    final short binLen = (short) (hex.length / 2);

    // === check bin output parameters ===
    if (binOff < 0 || binOff > bin.length) {
        CardRuntimeException.throwIt((short) 'H');
    }

    if (binOff + binLen > bin.length || binOff + binLen < 0) {
        CardRuntimeException.throwIt((short) 'H');
    }

    // === main loop ===

    // pre-create the array
    // set validity = 0 (0 = valid, anything else is not valid)
    short validity = 0;
    short c, isLetter, value, validDigitStruct, validDigit, validLetterStruct, validLetter;
    while (hexOff < hexEnd) {

        // --- calculate the value of the higher (more significant) tuple ---

        c = hex[hexOff];

        // check using calculation over bits to see if first char is a letter
        // isLetter is zero if it is a digit, 1 if it is a letter (upper & lowercase)
        isLetter = (short) ((c >> 6) & 1); 

        // calculate the tuple value using a multiplication to make up the difference between
        // a digit character and an alpha-numerical character
        // minus 1 for the fact that the letters are not zero based
        value = (short) (((c & 0xF) + isLetter * (-1 + 10)) << 4); 

        // check validity of all the other bits
        validity |= c >>> 7;

        validDigitStruct = (short) ((c & 0x30) ^ 0x30);
        validDigit = (short) (((c & 0x8) >> 3) * (c & 0x6)); 
        validity |= (isLetter ^ 1) * (validDigitStruct | validDigit); 

        validLetterStruct = (short) (c & 0x18);
        validLetter = (short) ((((c - 1) & 0x4) >> 2) * ((c - 1) & 0x2));
        validity |= isLetter * (validLetterStruct | validLetter); 

        // --- do the same with the lower (less significant) tuple ---

        c = hex[(short) (hexOff + 1)];
        isLetter = (short) ((c >> 6) & 1);
        value ^= (c & 0xF) + isLetter * (-1 + 10);
        bin[binOff] = (byte) value;

        // check validity of all the other bits
        validity |= c >>> 7;

        validDigitStruct = (short) ((c & 0x30) ^ 0x30);
        validDigit = (short) (((c & 0x8) >> 3) * (c & 0x6)); 
        validity |= (isLetter ^ 1) * (validDigitStruct | validDigit); 

        validLetterStruct = (short) (c & 0x18);
        validLetter = (short) ((((c - 1) & 0x4) >> 2) * ((c - 1) & 0x2));
        validity |= isLetter * (validLetterStruct | validLetter);

        // --- update offsets ---

        hexOff += 2;
        binOff++;
    }

    if (validity != 0) {
        // rewrite this for java card using e.g. CardRuntimeException.throwIt(short reason)
        CardRuntimeException.throwIt((short) 'H');
    }

    return binLen;
}
Community
  • 1
  • 1
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
1

If you only want to convert the hexadecimal bytes into decimal string (in byte array), then you can use the following code:

static byte[] output = new byte[10];
static short[] input = new short[4];

// the weights table for hex byte: 256^1 = 256, 256^2 = 65536, and 256^3 = 16777216
// 256^0 is moved outside the table for optimization (assigned as initial result value)
public static byte[] weight = {
      6, 6, 6,
      1, 3, 5,
      2, 5, 2,
      7, 5, 0,
      7, 6, 0,
      7, 0, 0,
      6, 0, 0,
      1, 0, 0,
      0, 0, 0,
      0, 0, 0
};

// the method to convert 4 bytes of hex into decimal string (10 byte arrays)
// final result is stored in output byte array
public static void convertHexToDecimalString(byte[] hex) {

    // convert input to positive (byte array to short array)
    for (byte i = 0; i < 4; i++) {
        input[i] = (short) (hex[i] & 0x00FF);
    }

    // assign the least significant hex byte to result
    short result = input[3];
    byte offset = 0;

    // loop to calculate and assign each decimal digit    
    for (byte i = 0; i < 10; i++) {
        result = (short) ((weight[offset] * input[0])
                + (weight[offset + 1] * input[1])
                + (weight[offset + 2] * input[2]) + result);
        output[9 - i] = (byte) (0x30 + result % 10);
        result /= 10;

        offset += 3;
    }
}
David
  • 3,957
  • 2
  • 28
  • 52
  • Not that my code is perfect (as I've mentioned by now in my answer), but writing into a static byte array in Java card is not such a good idea (because it is illegal according to the Java Card standards, and because the array will be in persistent memory (EEPROM of flash). – Maarten Bodewes Jan 28 '14 at 00:16
  • Static byte array generally produces more efficient code, and if applet deletion is one of the problem then we can nullify the byte array in uninstall method. Of course it is free to modify above code, e.g. if one would like to use RAM byte array for faster and more frequent calculation. – David Jan 28 '14 at 03:28