開発環境構築
こちらを参照 smartcardguy.hatenablog.jp
Java Card Wallet
Walletアプリ
簡易ATMカードのような機能を提供するアプリ。 預金(CREDIT)、引き出し(DEBIT)、残高照会(GET_BALANCE)などを行う。
Source code
/** * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * */ /* */ /* * @(#)Wallet.java 1.11 06/01/03 */ package com.sun.jcclassic.samples.wallet; import javacard.framework.APDU; import javacard.framework.Applet; import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.OwnerPIN; public class Wallet extends Applet { /* 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; // Comments by ASJ // 0x7FFF => 32,767 // 127 => 0x7F, // 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 Wallet(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 Wallet(bArray, bOffset, bLength); } // end of install method @Override 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 @Override public void deselect() { // reset the pin value pin.reset(); } @Override 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; } 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 = (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 Wallet
wallet.scr
output on; // create wallet applet 0x80 0xB8 0x00 0x00 0x14 0x0a 0xa0 0x0 0x0 0x0 0x62 0x3 0x1 0xc 0x6 0x1 0x08 0x0 0x0 0x05 0x01 0x02 0x03 0x04 0x05 0x7F; ///////////////////////////////////////////////////////////////////// // Initialize Wallet ///////////////////////////////////////////////////////////////////// //Select Wallet 0x00 0xA4 0x04 0x00 0x0a 0xa0 0x0 0x0 0x0 0x62 0x3 0x1 0xc 0x6 0x1 0x7F; // 90 00 = SW_NO_ERROR //Verify user pin 0x80 0x20 0x00 0x00 0x05 0x01 0x02 0x03 0x04 0x05 0x7F; //90 00 = SW_NO_ERROR //Get wallet balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x00 0x00 0x00 0x90 0x00 = Balance = 0 and SW_ON_ERROR //Attempt to debit from an empty account 0x80 0x40 0x00 0x00 0x01 0x64 0x7F; //0x6A85 = SW_NEGATIVE_BALANCE //Credit $100 to the empty account 0x80 0x30 0x00 0x00 0x01 0x64 0x7F; //0x9000 = SW_NO_ERROR //Get Balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x64 0x9000 = Balance = 100 and SW_NO_ERROR //Debit $50 from the account 0x80 0x40 0x00 0x00 0x01 0x32 0x7F; //0x9000 = SW_NO_ERROR //Get Balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR //Credit $128 to the account 0x80 0x30 0x00 0x00 0x01 0x80 0x7F; //0x6A83 = SW_INVALID_TRANSACTION_AMOUNT //Get Balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR //Debit $51 from the account 0x80 0x40 0x00 0x00 0x01 0x33 0x7F; //0x6A85 = SW_NEGATIVE_BALANCE //Get Balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR //Debit $128 from the account 0x80 0x40 0x00 0x00 0x01 0x80 0x7F; //0x6A83 = SW_INVALID_TRANSACTION_AMOUNT //Get Balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR //Reselect Wallet applet so that userpin is reset 0x00 0xA4 0x04 0x00 0x0a 0xa0 0x0 0x0 0x0 0x62 0x3 0x1 0xc 0x6 0x1 0x7F; // 90 00 = SW_NO_ERROR //Credit $127 to the account before pin verification 0x80 0x30 0x00 0x00 0x01 0x7F 0x7F; //0x6301 = SW_PIN_VERIFICATION_REQUIRED //Verify User pin with wrong pin value 0x80 0x20 0x00 0x00 0x04 0x01 0x03 0x02 0x66 0x7F; //0x6300 = SW_VERIFICATION_FAILED //Verify user pin again with correct pin value //0x80 0x20 0x00 0x00 0x08 0xF2 0x34 0x12 0x34 0x56 0x10 0x01 0x01 0x7F; 0x80 0x20 0x00 0x00 0x05 0x01 0x02 0x03 0x04 0x05 0x7F; //0x9000 = SW_NO_ERROR //Get balance with incorrect LE value 0x80 0x50 0x00 0x00 0x00 0x01; //0x6700 = ISO7816.SW_WRONG_LENGTH //Get balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR
実行
1. Sample_Device設定
- Java Card ViewからSample_Deviceをダブルクリック
- Properties画面からCREFタブを選択
- 「Input file with EEPROM data」、「Output file for EEPROM data」、 「Combined (input and output) file for EEPROM data」は空白に設定
- 「Do not open APDU console」はチェックを外す
2. Sample_DeviceのStart
Sample_DeviceをStart。 最後にCMD> が表示される。
3. cap-com.sun.jcclassic.samples.walletを実行
ConsoleのToolbarからcap-com.sun.jcclassic.samples.walletを実行
4. wallet.scr実行
- Package Explorerからwallet.scrを開き、全テキストをコピ。
- Sample_Device consoleのCMDプロンプトへペースト
実行結果
CMD>output on; // create wallet applet 0x80 0xB8 0x00 0x00 0x14 0x0a 0xa0 0x0 0x0 0x0 0x62 0x3 0x1 0xc 0x6 0x1 0x08 0x0 0x0 0x05 0x01 0x02 0x03 0x04 0x05 0x7F; ///////////////////////////////////////////////////////////////////// // Initialize Wallet ///////////////////////////////////////////////////////////////////// //Select Wallet 0x00 0xA4 0x04 0x00 0x0a 0xa0 0x0 0x0 0x0 0x62 0x3 0x1 0xc 0x6 0x1 0x7F; // 90 00 = SW_NO_ERROR //Verify user pin 0x80 0x20 0x00 0x00 0x05 0x01 0x02 0x03 0x04 0x05 0x7F; //90 00 = SW_NO_ERROR //Get wallet balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x00 0x00 0x00 0x90 0x00 = Balance = 0 and SW_ON_ERROR //Attempt to debit from an empty account 0x80 0x40 0x00 0x00 0x01 0x64 0x7F; //0x6A85 = SW_NEGATIVE_BALANCE //Credit $100 to the empty account 0x80 0x30 0x00 0x00 0x01 0x64 0x7F; //0x9000 = SW_NO_ERROR //Get Balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x64 0x9000 = Balance = 100 and SW_NO_ERROR //Debit $50 from the account 0x80 0x40 0x00 0x00 0x01 0x32 0x7F; //0x9000 = SW_NO_ERROR //Get Balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR //Credit $128 to the account 0x80 0x30 0x00 0x00 0x01 0x80 0x7F; //0x6A83 = SW_INVALID_TRANSACTION_AMOUNT //Get Balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR //Debit $51 from the account 0x80 0x40 0x00 0x00 0x01 0x33 0x7F; //0x6A85 = SW_NEGATIVE_BALANCE //Get Balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR //Debit $128 from the account 0x80 0x40 0x00 0x00 0x01 0x80 0x7F; //0x6A83 = SW_INVALID_TRANSACTION_AMOUNT //Get Balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR //Reselect Wallet applet so that userpin is reset 0x00 0xA4 0x04 0x00 0x0a 0xa0 0x0 0x0 0x0 0x62 0x3 0x1 0xc 0x6 0x1 0x7F; // 90 00 = SW_NO_ERROR //Credit $127 to the account before pin verification 0x80 0x30 0x00 0x00 0x01 0x7F 0x7F; //0x6301 = SW_PIN_VERIFICATION_REQUIRED //Verify User pin with wrong pin value 0x80 0x20 0x00 0x00 0x04 0x01 0x03 0x02 0x66 0x7F; //0x6300 = SW_VERIFICATION_FAILED //Verify user pin again with correct pin value //0x80 0x20 0x00 0x00 0x08 0xF2 0x34 0x12 0x34 0x56 0x10 0x01 0x01 0x7F; 0x80 0x20 0x00 0x00 0x05 0x01 0x02 0x03 0x04 0x05 0x7F; //0x9000 = SW_NO_ERROR //Get balance with incorrect LE value 0x80 0x50 0x00 0x00 0x00 0x01; //0x6700 = ISO7816.SW_WRONG_LENGTH //Get balance 0x80 0x50 0x00 0x00 0x00 0x02; //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR APDU|OUTPUT ON; APDU|CLA: 80, INS: b8, P1: 00, P2: 00, Lc: 14, 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 06, 01, 08, 00, 00, 05, 01, 02, 03, 04, 05, Le: 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 06, 01, SW1: 90, SW2: 00 APDU|CLA: 00, INS: a4, P1: 04, P2: 00, Lc: 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 06, 01, Le: 00, SW1: 90, SW2: 00 APDU|CLA: 80, INS: 20, P1: 00, P2: 00, Lc: 05, 01, 02, 03, 04, 05, Le: 00, SW1: 90, SW2: 00 APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 00, SW1: 90, SW2: 00 APDU|CLA: 80, INS: 40, P1: 00, P2: 00, Lc: 01, 64, Le: 00, SW1: 6a, SW2: 85 APDU|CLA: 80, INS: 30, P1: 00, P2: 00, Lc: 01, 64, Le: 00, SW1: 90, SW2: 00 APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 64, SW1: 90, SW2: 00 APDU|CLA: 80, INS: 40, P1: 00, P2: 00, Lc: 01, 32, Le: 00, SW1: 90, SW2: 00 APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 32, SW1: 90, SW2: 00 APDU|CLA: 80, INS: 30, P1: 00, P2: 00, Lc: 01, 80, Le: 00, SW1: 6a, SW2: 83 APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 32, SW1: 90, SW2: 00 APDU|CLA: 80, INS: 40, P1: 00, P2: 00, Lc: 01, 33, Le: 00, SW1: 6a, SW2: 85 APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 32, SW1: 90, SW2: 00 APDU|CLA: 80, INS: 40, P1: 00, P2: 00, Lc: 01, 80, Le: 00, SW1: 6a, SW2: 83 APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 32, SW1: 90, SW2: 00 APDU|CLA: 00, INS: a4, P1: 04, P2: 00, Lc: 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 06, 01, Le: 00, SW1: 90, SW2: 00 APDU|CLA: 80, INS: 30, P1: 00, P2: 00, Lc: 01, 7f, Le: 00, SW1: 63, SW2: 01 APDU|CLA: 80, INS: 20, P1: 00, P2: 00, Lc: 04, 01, 03, 02, 66, Le: 00, SW1: 63, SW2: 00 APDU|CLA: 80, INS: 20, P1: 00, P2: 00, Lc: 05, 01, 02, 03, 04, 05, Le: 00, SW1: 90, SW2: 00 APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 00, SW1: 67, SW2: 00 APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 32, SW1: 90, SW2: 00 CMD>
OUTPUTの解析
// create wallet applet APDU|CLA: 80, INS: b8, P1: 00, P2: 00, Lc: 14, 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 06, 01, 08, 00, 00, 05, 01, 02, 03, 04, 05, Le: 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 06, 01, SW1: 90, SW2: 00 //Select Wallet APDU|CLA: 00, INS: a4, P1: 04, P2: 00, Lc: 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 06, 01, Le: 00, SW1: 90, SW2: 00 //Verify user pin APDU|CLA: 80, INS: 20, P1: 00, P2: 00, Lc: 05, 01, 02, 03, 04, 05, Le: 00, SW1: 90, SW2: 00 //Get wallet balance APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 00, SW1: 90, SW2: 00 //0x00 0x00 0x00 0x00 0x90 0x00 = Balance = 0 and SW_ON_ERROR //Attempt to debit from an empty account APDU|CLA: 80, INS: 40, P1: 00, P2: 00, Lc: 01, 64, Le: 00, SW1: 6a, SW2: 85 //0x6A85 = SW_NEGATIVE_BALANCE //Credit $100 to the empty account APDU|CLA: 80, INS: 30, P1: 00, P2: 00, Lc: 01, 64, Le: 00, SW1: 90, SW2: 00 //0x9000 = SW_NO_ERROR //Get Balance APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 64, SW1: 90, SW2: 00 //0x00 0x64 0x9000 = Balance = 100 and SW_NO_ERROR //Debit $50 from the account APDU|CLA: 80, INS: 40, P1: 00, P2: 00, Lc: 01, 32, Le: 00, SW1: 90, SW2: 00 //0x9000 = SW_NO_ERROR //Get Balance APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 32, SW1: 90, SW2: 00 //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR //Credit $128 to the account APDU|CLA: 80, INS: 30, P1: 00, P2: 00, Lc: 01, 80, Le: 00, SW1: 6a, SW2: 83 //0x6A83 = SW_INVALID_TRANSACTION_AMOUNT //Get Balance APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 32, SW1: 90, SW2: 00 //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR //Debit $51 from the account APDU|CLA: 80, INS: 40, P1: 00, P2: 00, Lc: 01, 33, Le: 00, SW1: 6a, SW2: 85 //0x6A85 = SW_NEGATIVE_BALANCE //Get Balance APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 32, SW1: 90, SW2: 00 //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR //Debit $128 from the account APDU|CLA: 80, INS: 40, P1: 00, P2: 00, Lc: 01, 80, Le: 00, SW1: 6a, SW2: 83 //0x6A83 = SW_INVALID_TRANSACTION_AMOUNT //Get Balance APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 32, SW1: 90, SW2: 00 //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR //Reselect Wallet applet so that userpin is reset APDU|CLA: 00, INS: a4, P1: 04, P2: 00, Lc: 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 06, 01, Le: 00, SW1: 90, SW2: 00 // 90 00 = SW_NO_ERROR //Credit $127 to the account before pin verification APDU|CLA: 80, INS: 30, P1: 00, P2: 00, Lc: 01, 7f, Le: 00, SW1: 63, SW2: 01 //0x6301 = SW_PIN_VERIFICATION_REQUIRED //Credit $127 to the account before pin verification APDU|CLA: 80, INS: 20, P1: 00, P2: 00, Lc: 04, 01, 03, 02, 66, Le: 00, SW1: 63, SW2: 00 //Verify user pin again with correct pin value //0x80 0x20 0x00 0x00 0x08 0xF2 0x34 0x12 0x34 0x56 0x10 0x01 0x01 0x7F; APDU|CLA: 80, INS: 20, P1: 00, P2: 00, Lc: 05, 01, 02, 03, 04, 05, Le: 00, SW1: 90, SW2: 00 //Get balance with incorrect LE value APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 00, SW1: 67, SW2: 00 // C-APDUは「0x80 0x50 0x00 0x00 0x00 0x01;」 //0x6700 = ISO7816.SW_WRONG_LENGTH //Get balance APDU|CLA: 80, INS: 50, P1: 00, P2: 00, Lc: 00, Le: 02, 00, 32, SW1: 90, SW2: 00 //0x00 0x32 0x9000 = Balance = 50 and SW_NO_ERROR