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;
}