问题
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?
回答1:
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).
回答2:
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);
}
回答3:
I propose using BCD addition and BCD subtraction, as follow:
- Each byte represent two BCD, e.g. 0x99 represent 99 instead of 153.
- 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.
- 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);
}
}
来源:https://stackoverflow.com/questions/28925504/how-can-i-credit-or-debit-more-than-1-byte-to-from-card