-1

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?

Community
  • 1
  • 1

3 Answers3

2

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).

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • +1 for `Util.getShort`. Thank you, I didn't know it. But, doesn't it convert 2 bytes to a short value? I think it's output is a 16 bit singed value.Right? – Ebrahim Ghasemi Mar 08 '15 at 16:52
1

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. i.e. 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);

}
Ebrahim Ghasemi
  • 5,850
  • 10
  • 52
  • 113
  • But this code works only and only for 2 byte data. I told in my question that i want send 2 byte or more to the card. For example if i want send 100000 , it take 3 byte :186A0. I tried this code but even for 2 byte data could not work! – soheyla abbbb Mar 09 '15 at 06:06
  • I send this : 8030000002138800. But when i get balance , debug shell showed to me : 00 13 90 00, that means is considered first byte(13) only. – soheyla abbbb Mar 09 '15 at 06:12
  • Also i replace your method but gives this error: found : byte required: byte[] byte[] creditBytes = buffer[ISO7816.OFFSET_CDATA]; – soheyla abbbb Mar 09 '15 at 06:52
  • @soheylaabbbb I edited it. It must work fine for 65535$ now. And about the value greater than 65535: **You must specify a maximum value and then write a program for it**. What is the maximum money? If you need a three byte value, change the above code. Do a Google search for Hex to Decimal converting,it must be useful. moreover, use **I** instead of **i** :))) – Ebrahim Ghasemi Mar 09 '15 at 08:49
  • Can you give me some explanation about Util.getShort? This method what does operqation? Because it was marvelous for you. I guess it be marvelous for me too!! :))) – soheyla abbbb Mar 09 '15 at 09:19
  • And i have in top of my code 2 fields include : // maximum balance 'final static short MAX_BALANCE = 0x7FFF;' and // maximum transaction amount 'final static byte MAX_TRANSACTION_AMOUNT = 127; ' . Dont need i change those? – soheyla abbbb Mar 09 '15 at 09:27
  • This fails, gives this error: 6A 83 which means :final static short SW_INVALID_TRANSACTION_AMOUNT = 0x6A83; as defined this filed at first of my code. How can i resolve error? – soheyla abbbb Mar 09 '15 at 09:38
  • 1-Take a look at documentations. 2- OMG! It's obvious bro! try to find it yourself! As you said It is related to `MAX_TRANSACTION_AMOUNT` – Ebrahim Ghasemi Mar 09 '15 at 09:52
  • I think value of MAX_TRANSACTION_AMOUNT = 127 must changed to 32767. Yes? But in 32767 cant indwells in in the a field from type byte. Yes? I am to endeavor – soheyla abbbb Mar 09 '15 at 10:00
  • Yes, you are right. replace `byte` with `short` also – Ebrahim Ghasemi Mar 09 '15 at 10:02
  • Start begin of the sentenses by BIG letters please. Write Replace instead of replace!Thanks. – soheyla abbbb Mar 09 '15 at 10:06
0

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

  1. Each byte represent two BCD, e.g. 0x99 represent 99 instead of 153.
  2. All data included in the addition and subtraction shall have the same length, e.g. 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);
    }

}
David
  • 3,957
  • 2
  • 28
  • 52