简体   繁体   中英

How can i credit or debit more than 1 byte to/from card?

I am newbie applets and i used from this link: working with Java Card Wallet for creating an Wallet project. I before could credit card amount by this command : 80 30 00 00 01 1A 00 .

I now want add '5000' to the present amount. As you know 5000 in hex equals

with '1388' that is 2 byte. So i must send 2 byte data 13 and 88 to the card.

I create bellow command and sent it to card but i get '67 00 Wrong lenght' as

response.

80 30 00 00 02 13 88 00

How can i credit or debit more than 1 byte to/from card?

You'll have to change the code of the Applet you're pointing to of course:

if ((numBytes != 1) || (byteRead != 1)) {
    ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); // constant with value 0x6700
}

So you must make sure that it allows for 2 bytes to be send, then you can use the Util.getShort method to convert to the bytes to a 16 bit signed value (using big endian two complement notation, as usual).

Replace the creadit() method, with this one. But remember that you must use two byte value for crediting you walled henceforth. (even for values less than 255 or 0xFF. ie you must use 0x00FF to debit you wallet with 255$ )

private void credit(APDU apdu) {

    // access authentication
    if (!pin.isValidated()) {
        ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
    }

    byte[] buffer = apdu.getBuffer();

    // Lc byte denotes the number of bytes in the
    // data field of the command APDU
    byte numBytes = buffer[ISO7816.OFFSET_LC];

    // indicate that this APDU has incoming data
    // and receive data starting from the offset
    // ISO7816.OFFSET_CDATA following the 5 header
    // bytes.
    byte byteRead = (byte) (apdu.setIncomingAndReceive());

    // it is an error if the number of data bytes
    // read does not match the number in Lc byte
    if ((numBytes != 2) || (byteRead != 2)) {
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    }

    // get the creditBytes
    byte[] creditBytes = new byte[2];
    creditBytes[0]=buffer[ISO7816.OFFSET_CDATA];
    creditBytes[1]=buffer[ISO7816.OFFSET_CDATA+1];

    // convert 2 byte of creatBytes to a single short value.
    short creditAmount = Util.getShort(creditBytes,(short)0);

    // check the credit amount
    if ((creditAmount > MAX_TRANSACTION_AMOUNT) || (creditAmount < 0)) {
        ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
    }

    // check the new balance
    if ((short) (balance + creditAmount) > MAX_BALANCE) {
        ISOException.throwIt(SW_EXCEED_MAXIMUM_BALANCE);
    }

    // credit the amount
    balance = (short) (balance + creditAmount);

}

I propose using BCD addition and BCD subtraction, as follow:

  1. Each byte represent two BCD, eg 0x99 represent 99 instead of 153.
  2. All data included in the addition and subtraction shall have the same length, eg 6 bytes will represents 12 digits. This should cover most cases, but if you need more, simply change your constant.
  3. Your applet performs loop through the bytes to do the addition or subtraction. Encode and decode operation from BCD to the value and vice versa are needed before and after the operation.

Here is sample for the implementation. It is not tested yet, but should give you idea of how it works:

public class BCD {

    public static final short NUMBER_OF_BYTES = 6;

    static void add(byte[] augend, byte[] addend, byte[] result) {
        byte carry = 0;
        short temp = 0;
        for (short i = (short) (NUMBER_OF_BYTES - 1); i >= 0; i--) {
            temp = (short) (decode(augend[i]) + decode(addend[i]) + carry);
            carry = (byte) ((temp > 100) ? 1 : 0);
            result[i] = encode((byte) temp);
        }

        if (carry == 1) {
            // TODO: result more than maximum
            // you can set all digits to 9 or throw exception
        }
    }

    static void subtract(byte[] minuend, byte[] subtrahend, byte[] result) {
        byte borrow = 0;
        short temp = 0;
        for (short i = (short) (NUMBER_OF_BYTES - 1); i >= 0; i--) {
            temp = (short) (100 + decode(minuend[i]) - decode(subtrahend[i]) - borrow);
            borrow = (byte) ((temp < 100) ? 1 : 0);
            result[i] = encode((byte) temp);
        }

        if (borrow == 1) {
            // TODO: subtrahend > minuend, 
            // you can set all digits to 0 or throw exception
        }
    }

    static byte encode(byte value) {
        value %= 100; // only convert two digits, ignore borrow/carry
        return (byte) (((value / 10) << 4) | (value % 10));
    }

    static byte decode(byte bcdByte) {
        byte highNibble = (byte) ((bcdByte >> 4) & 0x0F);
        byte lowNibble = (byte) (bcdByte & 0x0F);

        if ((highNibble > 9) || (lowNibble > 9)) {
            // found 'A' to 'F' character which should be invalid
            // you can change this line, e.g. throwing exception
            return 0;
        }

        return (byte) ((highNibble * 10) + lowNibble);
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM