Page 1 of 1

[resolved]GET_BALANCE return 6E 00 or 6F 00

Posted: Mon Aug 31, 2020 5:28 pm
by andromeda92
Hi, i have an applet, running on simulator or on real card, method getbalance return always 6E00

veryfy pin i ok
credit is ok
debit is ok
change is ok

but getbalance return 6E00
the code:

Code: Select all

package PackageWallet ;

import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.OwnerPIN;



public class AppletWallet extends Applet {
 
    /* constants declaration */
    
    // code of CLA byte in the command APDU header
    final static byte Wallet_CLA =(byte)0xB0;
    
    // codes of INS byte in the command APDU header
    final static byte VERIFY = (byte) 0x20;
    final static byte CREDIT = (byte) 0x30;
    final static byte DEBIT = (byte) 0x40;
    final static byte GET_BALANCE = (byte) 0x50;
    final static byte CHANGE = (byte) 0x60;
    
    // maximum balance
    final static short MAX_BALANCE = 0x7FFF;
    // maximum transaction amount
    final static byte MAX_TRANSACTION_AMOUNT = 127;
    
    // maximum number of incorrect tries before the
    // PIN is blocked
    final static byte PIN_TRY_LIMIT =(byte)0x03;
    // maximum size PIN
    final static byte MAX_PIN_SIZE =(byte)0x08;
    final static byte MIN_PIN_SIZE = (byte)0x04;
    
    // signal that the PIN verification failed
    final static short SW_VERIFICATION_FAILED =
    0x6300;
    // signal the the PIN validation is required
    // for a credit or a debit transaction
    final static short SW_PIN_VERIFICATION_REQUIRED =
                                            0x6301;
	// pin is locked
	final static short SW_CARD_IS_LOCKED = 0x6304; 
	final static short SW_NEW_PIN_TOO_LONG = 0x6307;
	final static short SW_NEW_PIN_TOO_SHORT = 0x6308;  
	                                        
    // signal invalid transaction amount
    // amount > MAX_TRANSACTION_AMOUNT or amount < 0
    final static short SW_INVALID_TRANSACTION_AMOUNT = 0x6A83;
    
    // signal that the balance exceed the maximum
    final static short SW_EXCEED_MAXIMUM_BALANCE = 0x6A84;
    // signal the the balance becomes negative
    final static short SW_NEGATIVE_BALANCE = 0x6A85;
    
    /* instance variables declaration */
    OwnerPIN pin;
    short balance;
    
    private AppletWallet (byte[] bArray,short bOffset,byte bLength) {
      
        // It is good programming practice to allocate
        // all the memory that an applet needs during
        // its lifetime inside the constructor
        pin = new OwnerPIN(PIN_TRY_LIMIT,   MAX_PIN_SIZE);
        
        byte iLen = bArray[bOffset]; // aid length
        bOffset = (short) (bOffset+iLen+1);
        byte cLen = bArray[bOffset]; // info length
        bOffset = (short) (bOffset+cLen+1);
        byte aLen = bArray[bOffset]; // applet data length
        
		pin = new OwnerPIN(PIN_TRY_LIMIT, MAX_PIN_SIZE);
		pin.update(bArray, (short)(bOffset + 1), aLen);
		// Above command causes error.
				
		register();
    
    } // end of the constructor
    
    public static void install(byte[] bArray, short bOffset, byte bLength) {
        // create a Wallet applet instance
        new AppletWallet(bArray, bOffset, bLength);
    } // end of install method
    
    public boolean select() {
        
        // The applet declines to be selected
        // if the pin is blocked.
        if ( pin.getTriesRemaining() == 0 )
           return false;
        
        return true;
        
    }// end of select method
    
    public void deselect() {
        
        // reset the pin value
        pin.reset();
        
    }
    	
  
    public void process(APDU apdu) {
        
        // APDU object carries a byte array (buffer) to
        // transfer incoming and outgoing APDU header
        // and data bytes between card and CAD
        
        // At this point, only the first header bytes
        // [CLA, INS, P1, P2, P3] are available in
        // the APDU buffer.
        // The interface javacard.framework.ISO7816
        // declares constants to denote the offset of
        // these bytes in the APDU buffer
        
        byte[] buffer = apdu.getBuffer();
        // check SELECT APDU command
       
        if (apdu.isISOInterindustryCLA()) {
            if (buffer[ISO7816.OFFSET_INS] == (byte)(0xA4)) {
                return;
            } else {
                ISOException.throwIt (ISO7816.SW_CLA_NOT_SUPPORTED);
            }
        }
            
        // verify the reset of commands have the
        // correct CLA byte, which specifies the
        // command structure
        if (buffer[ISO7816.OFFSET_CLA] != Wallet_CLA)
            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
       
		switch (buffer[ISO7816.OFFSET_INS]) {
			case GET_BALANCE:
				getBalance(apdu);
				return;
			case DEBIT:
				debit(apdu);
				return;
			case CREDIT:
				credit(apdu);
				return;
			case VERIFY:
				verify(apdu);
				return;
			case CHANGE:
				change(apdu);
				return;
			default:
			ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
		}
        
    }   // end of process method
    
    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 != 1 ) || (byteRead != 1) )
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        
        // get the credit amount
        byte creditAmount = buffer[ISO7816.OFFSET_CDATA];
        
        // 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);
    
    } // end of deposit method
    
    private void debit(APDU apdu) {
    
        // access authentication
        if ( ! pin.isValidated() )
            ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
        
        byte[] buffer = apdu.getBuffer();
        
        byte numBytes =
            (byte)(buffer[ISO7816.OFFSET_LC]);
        
        byte byteRead =
            (byte)(apdu.setIncomingAndReceive());
        
        if ( ( numBytes != 1 ) || (byteRead != 1) )
           ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        
        // get debit amount
        byte debitAmount = buffer[ISO7816.OFFSET_CDATA];
        
        // check debit amount
        if ( ( debitAmount > MAX_TRANSACTION_AMOUNT)
             ||  ( debitAmount < 0 ) )
           ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
        
        // check the new balance
        if ( (short)( balance - debitAmount ) < (short)0 )
             ISOException.throwIt(SW_NEGATIVE_BALANCE);
        
        balance = (short) (balance - debitAmount);
    
    } // end of debit method
    
    private void getBalance(APDU apdu) {
        
        byte[] buffer = apdu.getBuffer();
        
        // inform system that the applet has finished
        // processing the command and the system should
        // now prepare to construct a response APDU
        // which contains data field
        short le = apdu.setOutgoing();
        
        if ( le < 2 )
           ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        
        //informs the CAD the actual number of bytes
        //returned
        apdu.setOutgoingLength((byte)2);
        
        // move the balance data into the APDU buffer
        // starting at the offset 0
        buffer[0] = (byte)(balance >> 8);
        buffer[1] = (byte)(balance & 0xFF);
        
        // send the 2-byte balance at the offset
        // 0 in the apdu buffer
        apdu.sendBytes((short)0, (short)4);
    
    } // end of getBalance method
    
    private void verify(APDU apdu) {
        
        byte[] buffer = apdu.getBuffer();
         if(pin.getTriesRemaining() == (byte)0)
           ISOException.throwIt(SW_CARD_IS_LOCKED);
           
        // retrieve the PIN data for validation.
        byte byteRead = (byte)(apdu.setIncomingAndReceive());
        
        // check pin
        // the PIN data is read into the APDU buffer
        // at the offset ISO7816.OFFSET_CDATA
        // the PIN data length = byteRead
        if ( pin.check(buffer, ISO7816.OFFSET_CDATA,
            byteRead) == false )
            ISOException.throwIt(SW_VERIFICATION_FAILED);
        
    } // end of validate method
    
    private void change(APDU apdu) {
        
       byte[] buffer = apdu.getBuffer();
       if(pin.getTriesRemaining() == (byte)0)
           ISOException.throwIt(SW_CARD_IS_LOCKED);
           
       if ( ! pin.isValidated() )
           ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
           
        // retrieve the PIN data for validation.
        byte byteRead = (byte)(apdu.setIncomingAndReceive());
        if(byteRead > MAX_PIN_SIZE)
           ISOException.throwIt(SW_NEW_PIN_TOO_LONG);
           
       if(byteRead < MIN_PIN_SIZE)
           ISOException.throwIt(SW_NEW_PIN_TOO_SHORT);
        
       pin.update(buffer, (short) ISO7816.OFFSET_CDATA, (byte)byteRead); 
        
    } // end of validate method
} // end of class Wallet
i use java card J2A040, JCD2.2.2
i don't undertand the problem.
Thanks for your help.

Re: GET_BALANCE return 6E 00 or 6F 00

Posted: Mon Aug 31, 2020 6:08 pm
by andromeda92
resolved, i have replaced this line

apdu.sendBytes((short)0, (short)4);

by

apdu.sendBytes((short)0, (short)2);

Re: [resolved]GET_BALANCE return 6E 00 or 6F 00

Posted: Tue Mar 23, 2021 4:16 am
by abuhelweh
Can you please share the APDU commands used to test this applet? I tried to debug but its not reaching the process method

Re: [resolved]GET_BALANCE return 6E 00 or 6F 00

Posted: Sun Apr 25, 2021 12:35 pm
by andromeda92
For example, for send sendpin the command is
for credit is 8030000001
get balance 8050000002
reset balance 8004000000
...
all depend to your program

Re: [resolved]GET_BALANCE return 6E 00 or 6F 00

Posted: Thu Jun 24, 2021 5:32 am
by faulknernolan
can i get your code?
moto x3m

Re: [resolved]GET_BALANCE return 6E 00 or 6F 00

Posted: Mon Jul 19, 2021 9:50 am
by andromeda92
the applet is developed with java card os but to test the applet I use eclipse with javacard and globalplatform. It's a whole environment, you have to install javacard under eclipse as well as globalplatform, swing, awt for the gui part. The principle is to send the INS command of the applet, and the card returns the response that must be analyzed in the client.


The source code of client with eclipse and javacard:
https://mega.nz/file/PB9SRZjL#tz5Jm5coM ... bCjsLfFv9M