简体   繁体   中英

How to programmatically load a Java card applet ( .cap file ) using java or java Applet

How to programmatically load a Java card applet ( .cap file ) using java or java Applet.

I'm trying to install an applet (.cap file) into a smart card. I read that can be done using APDU. I created my applet using Netbeans.

I have already created a .CAP file using Netbeans for my applet which I would now like to install/load into the physical smart card. I would appreciate assistance on how or what tool I could use to install the .CAP file to the card. Also, what else do I need to install into the card. And I have two devices HID OMNIKEY CARDMAN 5x21 1 and HID OMNIKEY CARDMAN 3x21 0 java smart card reader and also I have two kinds of cards like java card (J2A.. or J3A..) and basics cards(ZC..) Note: I don't want to use any third party software or tools And my applet code is: package smartCard; import javacard.framework.*;

/** * * @author patidar */ public class SmartCard extends Applet {

/**
 * Installs this applet.
 * 
 * @param bArray
 *            the array containing installation parameters
 * @param bOffset
 *            the starting offset in bArray
 * @param bLength
 *            the length in bytes of the parameter data in bArray
 */
/**
 * Only this class's install method should create the applet object.
 */
protected SmartCard() {
    register();
}
/**
 * Processes an incoming APDU.
 * 
 * @see APDU
 * @param apdu
 *            the incoming APDU
 */
/* constants declaration */
// code of CLA byte in the command APDU header
final static byte Wallet_CLA =(byte)0x80;
// 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;
// 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;

// 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;
// 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 SmartCard (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

    // The installation parameters contain the PIN
    // initialization value
    pin.update(bArray, (short)(bOffset+1), aLen);
    register();

} // end of the constructor

public static void install(byte[] bArray, short bOffset, byte bLength) {
    // create a Wallet applet instance
    new SmartCard(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;
    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)2);

} // end of getBalance method

private void verify(APDU apdu) {

    byte[] buffer = apdu.getBuffer();
    // 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

} // end of class SmartCard

With this information can anyone help me to build the correct APDU to install my cap file into a real smart card? Thank you.

I also stuck with the same issue and I found the solution which I am going to share with you.

Please follow the below steps:

1: Please click here and download the gp.exe

2: Open your windows command prompt.

3: Go to the location/directory which contains the gp.exe file.

4: Now connect your card reader into machine and insert card into reader.

5: Than type the

cmd > gp.exe
cmd > gp –help

And if everything is fine than you will see the all supported commands listed there:

a cmd > gp –info This will list all the card information.

b cmd > gp –list This will list all the applets installed in the cards.

c: cmd > gp –delete AID(of applet ) This will delete the installed applet.

d: cmd > gp –install xyz.cap (copy the .cap file in same directory where gp.exe is placed and select in place of xyz.cap ) This will install your applet onto the physical smart card.

Now you need the APDU commands to communicate with the card.

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