有没有办法在Java卡2.2.1中使用大(32位或更多)数字进行计算?

时间:2014-01-20 12:28:23

标签: size hex decimal type-conversion javacard

我想使用java卡2.2.1将4字节十六进制数转换为十进制数。

例如:50ef7f19 - > 1357872921

对于此转换,我需要使用32位数字,因此最好将数据类型用作整数。但我不确定在Java卡中使用'int'。在规范中,'optional'表示整数。使用它有什么限制?如果我不使用int,还有其他方法可以用大数字进行计算吗?

2 个答案:

答案 0 :(得分:2)

在Java Card Classic上使用int的最大限制是,大多数实施Java Card Classic的智能卡都不支持它。另一个重要的限制是API几乎不支持整数。因此,即使您可以使用整数运算,API也只接受字节或短路。

我已经创建了一个特殊的类JCInteger,如果你感兴趣的话,它也可以执行32位算术。我仍然没有发布我的测试用例,所以要小心使用。您当然可以创建类似的方法来执行整数运算。如果你(非常)幸运,你的芯片也可以实现BigNumber

请注意,最初您可以从表示十六进制字符(ASCII或ASCII兼容编码)的字节转换为字节。之后,只有在需要时才能使用整数。通常,在终端上执行十六进制到字节转换,而不是在智能卡内。


如果您感兴趣,这里是一个快速(最小数量的分支)但字节码密集的方法从十六进制生成字节。不要忘记为它提供偶数个字节,可能会在混合中添加offsetlength参数。

警告:未经测试的数组处理(已测试解码)

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

答案 1 :(得分:1)

如果您只想将十六进制字节转换为十进制字符串(在字节数组中),那么您可以使用以下代码:

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