├── emv
├── .classpath
├── .jcop
├── .project
└── src
│ └── smart
│ ├── Pin.java
│ ├── Log.java
│ ├── ProtocolState.java
│ ├── Emv.java
│ ├── Crypto.java
│ └── FileSystem.java
├── LICENSE
└── README.md
/emv/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/emv/.jcop:
--------------------------------------------------------------------------------
1 | 1.000000000001.0
--------------------------------------------------------------------------------
/emv/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | emv
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | com.ibm.bluez.jcop.eclipse.jcopbuilder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | com.ibm.bluez.jcop.eclipse.jcopnature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Leandro Machado
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EMV Applet for Javacard 2.2.1
2 |
3 | This is a fully working EMV applet for javacard 2.2.1.
4 |
5 | Current STANDARD features are:
6 | - Data access and basic instructions (SELECT, PIN VERIFY, PROCESSING OPTIONS, GENERATE AC)
7 |
8 | Current CUSTOM features are:
9 | - Received APDU logging (for debugging purposes);
10 | - PIN VERIFY always return OK (9000);
11 | - Fixed IAD and AC output (can be "hot swapped" without having to reflash the cap file, using PUT DATA commands);
12 |
13 | Unfortunately, no personalization commands are implemented. You will need to edit the source code to change the EF data. You can also use my other tool, [ArrayEdit](https://github.com/tiosolid/array_edit), to make this task a lot easier.
14 |
15 | # Notice
16 |
17 | This applet was stitched using source code from all over the internet and a lot of my own code. The `Crypto.java` file was entirely made by another person, but I don't remember where I found it, sorry :(
18 |
19 | # Building
20 |
21 | This applet must be built using a very ancient version of Eclipse (INDIGO SR2 3.7.2) and JCOP Tools from IBM (Google is your friend for this one) since I didn't have access to newer jcop cards while testing this.
22 |
23 | # Disclaimer
24 |
25 | Use this applet at your own risk. Im not responsible for anything you do with it.
--------------------------------------------------------------------------------
/emv/src/smart/Pin.java:
--------------------------------------------------------------------------------
1 | package smart;
2 |
3 | import javacard.framework.APDU;
4 | import javacard.framework.ISO7816;
5 | import javacard.framework.ISOException;
6 | import javacard.framework.OwnerPIN;
7 |
8 | public class Pin {
9 | private final OwnerPIN pinObject;
10 | final static byte PIN_TRY_LIMIT = (byte) 0x03;
11 | final static byte PIN_SIZE = (byte) 0x02;
12 |
13 | public Pin() {
14 | pinObject = new OwnerPIN(PIN_TRY_LIMIT, PIN_SIZE);
15 | pinObject.update(new byte[] { (byte) 0x12, (byte) 0x34 }, (short) 0,
16 | (byte) 2);
17 | }
18 |
19 | public void verify(APDU apdu) {
20 | byte[] buf = apdu.getBuffer();
21 |
22 | // ALWAYS return 9000
23 | apdu.setOutgoingAndSend((short) 0, (short) 0); // return 9000
24 |
25 | if (buf[ISO7816.OFFSET_P2] != (byte) (0x80)) {
26 | ISOException.throwIt(ISO7816.SW_WRONG_P1P2); // we only support
27 | // transaction_data
28 | // PIN
29 | }
30 | if (pinObject.getTriesRemaining() == 0) {
31 | ISOException.throwIt((short) 0x6983); // PIN blocked
32 | return;
33 | }
34 |
35 | /*
36 | * EP: For the code below to be correct, digits in the PIN object need
37 | * to be coded in the same way as in the APDU, ie. using 4 bit words.
38 | */
39 |
40 | if (pinObject.check(buf, (short) (ISO7816.OFFSET_CDATA + 1), PIN_SIZE)) {
41 | // protocolState.setCVMPerformed(PLAINTEXT_PIN);
42 | apdu.setOutgoingAndSend((short) 0, (short) 0); // return 9000
43 | } else {
44 | ISOException.throwIt((short) ((short) (0x63C0) + (short) pinObject
45 | .getTriesRemaining()));
46 | }
47 | }
48 |
49 | public void update(APDU apdu) {
50 | byte[] buf = apdu.getBuffer();
51 | if ((buf[ISO7816.OFFSET_P1] != (byte) 0x00)
52 | || (buf[ISO7816.OFFSET_P2] != (byte) 0x01)) {
53 | ISOException.throwIt((short) 0x6A86); // '86': Incorrect parameters
54 | // P1-P2
55 | }
56 | // TODO: Check Data size (cant be smaller than 2 bytes)
57 | pinObject.update(buf, (short) (ISO7816.OFFSET_CDATA), (byte) 2);
58 | apdu.setOutgoingAndSend((short) 0, (short) 0); // return 9000
59 | }
60 |
61 | public void update(byte[] pin, short offset, byte length) {
62 | pinObject.update(pin, offset, length);
63 | }
64 |
65 | public byte getTriesRemaining() {
66 | return (byte) 0x03;
67 | // return pinObject.getTriesRemaining();
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/emv/src/smart/Log.java:
--------------------------------------------------------------------------------
1 | package smart;
2 |
3 | import javacard.framework.Util;
4 | import javacard.framework.ISO7816;
5 |
6 | public class Log {
7 | private boolean log_enabled;
8 | public final static short MAX_LOG_SIZE = 255;
9 | private final byte[] log_array;
10 | private short log_size;
11 |
12 | public Log() {
13 | log_enabled = true;
14 | log_array = new byte[MAX_LOG_SIZE];
15 | log_size = 0;
16 | }
17 |
18 | // Append data to the end of the log
19 | public void write(byte[] buffer) {
20 | if (!isEnabled() || isLogFull()) {
21 | return;
22 | } // Do nothing if log is disabled or full
23 |
24 | short apdu_size = 4; // CLA - INS - P1 - P2, minimum
25 | if (buffer[ISO7816.OFFSET_LC] != 0x00) {
26 | apdu_size = (short) (apdu_size + buffer[ISO7816.OFFSET_LC] + 1);
27 | } // LC != 0 means we have a data body
28 |
29 | // Check if the message fits in the remaining log space
30 | if (apdu_size > getFreeSpace()) {
31 | return;
32 | }
33 |
34 | // Prepare the message to be inserted atomically
35 | byte[] entry = new byte[apdu_size + 1]; // Extra byte for the length
36 | entry[0] = (byte) apdu_size;
37 | Util.arrayCopy(buffer, (short) 0, entry, (short) 1, apdu_size);
38 |
39 | // Finally, add the message to the log
40 | Util.arrayCopy(entry, (short) 0, log_array, getSize(),
41 | (short) entry.length);
42 |
43 | // Increment the log size
44 | log_size = (short) (log_size + entry.length);
45 | }
46 |
47 | /** Read all the entries in the log */
48 | public byte[] read() {
49 | return log_array;
50 | }
51 |
52 | // Clear all the log entries
53 | public void clear() {
54 | Util.arrayFillNonAtomic(log_array, (short) 0, MAX_LOG_SIZE, (byte) 0x00);
55 | log_size = (short) 0;
56 | }
57 |
58 | /** Return the actual log size */
59 | public short getSize() {
60 | return log_size;
61 | }
62 |
63 | /** Return log free space */
64 | public short getFreeSpace() {
65 | return (short) (MAX_LOG_SIZE - getSize());
66 | }
67 |
68 | /** Check if the log is full */
69 | public boolean isLogFull() {
70 | if (log_size < MAX_LOG_SIZE) {
71 | return false;
72 | }
73 |
74 | return true;
75 | }
76 |
77 | // Get if the log facility is enabled or not
78 | public boolean isEnabled() {
79 | return log_enabled;
80 | }
81 |
82 | public void enable() {
83 | log_enabled = true;
84 | }
85 |
86 | public void disable() {
87 | log_enabled = false;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/emv/src/smart/ProtocolState.java:
--------------------------------------------------------------------------------
1 | package smart;
2 |
3 | import javacard.framework.APDU;
4 | import javacard.framework.ISO7816;
5 | import javacard.framework.ISOException;
6 | import javacard.framework.JCSystem;
7 | import javacard.framework.Util;
8 |
9 | public class ProtocolState {
10 | private short atc;
11 | private short lastOnlineATC;
12 |
13 | // constants to record the (persistent) lifecycle state
14 | public static byte PERSONALISATION = (byte) 0x00;
15 | public static byte READY = (byte) 0x01;
16 | public static byte BLOCKED = (byte) 0x02;
17 |
18 | /**
19 | * Volatile protocol state; records if CVM has been performed, and if ACs
20 | * have been generated
21 | */
22 | private final byte volatileState[];
23 |
24 | /**
25 | * 2 byte Card Verification Results
26 | */
27 | private final byte[] cvr;
28 |
29 | public byte getFirstACGenerated() {
30 | return volatileState[1];
31 | }
32 |
33 | public void setFirstACGenerated(byte ACType) {
34 | volatileState[1] = ACType;
35 | }
36 |
37 | public byte getSecondACGenerated() {
38 | return volatileState[2];
39 | }
40 |
41 | public void setSecondACGenerated(byte ACType) {
42 | volatileState[2] = ACType;
43 | }
44 |
45 | public byte getCVMPerformed() {
46 | return volatileState[0];
47 | }
48 |
49 | public void setCVMPerformed(byte CVMType) {
50 | volatileState[0] = CVMType;
51 | }
52 |
53 | public short getATC() {
54 | return (short) 0x00C3;
55 | // return atc;
56 | }
57 |
58 | public void setATC(short newATC) {
59 | atc = newATC;
60 | }
61 |
62 | private void increaseATC() {
63 | // if (atc == MAX) { BLOCK THIS CARD!! }, but we ignore security here
64 | atc = (short) (atc + 1);
65 | }
66 |
67 | public short getLastOnlineATC() {
68 | return lastOnlineATC;
69 | }
70 |
71 | public void setLastOnlineATC(short newLOATC) {
72 | lastOnlineATC = newLOATC;
73 | }
74 |
75 | public ProtocolState() {
76 | volatileState = JCSystem.makeTransientByteArray((short) 3,
77 | JCSystem.CLEAR_ON_DESELECT);
78 | cvr = JCSystem.makeTransientByteArray((short) 2,
79 | JCSystem.CLEAR_ON_DESELECT);
80 | atc = (short) 0x0005;
81 | lastOnlineATC = (short) 0x0005;
82 | }
83 |
84 | /*
85 | * Starts a new session. This resets all session data and increases the ATC,
86 | * but does not generate a session key yet.
87 | */
88 | public void startNewSession() {
89 | setFirstACGenerated(smart.Emv.NONE);
90 | setSecondACGenerated(smart.Emv.NONE);
91 | setCVMPerformed(smart.Emv.NONE);
92 | increaseATC();
93 | }
94 |
95 | /*
96 | * Sets the last online ATC equal to the current ATC
97 | */
98 | public void onlineSessionCompleted() {
99 | lastOnlineATC = atc;
100 | }
101 |
102 | /*
103 | * Returns the 4 byte CVR (Card Verification Results). Details are described
104 | * in Book 3, Annex C7.3
105 | */
106 | public byte[] getCVR() {
107 | return null;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/emv/src/smart/Emv.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package smart;
5 |
6 | import javacard.framework.Applet;
7 | import javacard.framework.ISOException;
8 | import javacard.framework.ISO7816;
9 | import javacard.framework.APDU;
10 | import javacard.framework.Util;
11 | import javacard.framework.JCSystem;
12 |
13 | /**
14 | * @author EMV
15 | *
16 | */
17 |
18 | public class Emv extends Applet {
19 | // Constants for the Supported CLAs (afaik, 00 and 80 are a must)
20 | final static byte EMV_CLA = (byte) 0x80;
21 |
22 | // Constants for supported INS (ISO7816)
23 | // Bare minimum
24 | final static byte INS_VERIFY = (byte) 0x20; // EMV
25 | final static byte INS_PUT_DATA = (byte) 0xDA;
26 | final static byte INS_GET_DATA = (byte) 0xCA; // EMV
27 | final static byte INS_SELECT_FILE = (byte) 0xA4;
28 | final static byte INS_READ_RECORD = (byte) 0xB2; // EMV
29 | final static byte INS_WRITE_RECORD = (byte) 0xD2;
30 | final static byte INS_APPEND_RECORD = (byte) 0xE2;
31 | final static byte INS_PIN_UNBLOCK = (byte) 0x24; // EMV
32 |
33 | // Must be supported according to a commercial EMV applet, not sure for
34 | // current application
35 | final static byte INS_EXTERNAL_AUTH = (byte) 0x82; // EMV
36 | final static byte INS_INTERNAL_AUTH = (byte) 0x88; // EMV
37 | final static byte INS_GENERATE_AC = (byte) 0xAE; // Page 57 - EMV Book
38 | final static byte INS_GET_CHALLENGE = (byte) 0x84; // Page 60 - EMV Book
39 | final static byte INS_GET_PROC_OPTIONS = (byte) 0xA8; // Page 63 - EMV Book
40 |
41 | // Custom Instructions
42 | // TODO Add support to an INS to block ATC / LOATC incrementing?
43 | final static byte INS_UPDATE_AC = (byte) 0x72;
44 | final static byte INS_DISABLE_AC_REP = (byte) 0x74;
45 | final static byte INS_CLEAR_LOG = (byte) 0x76;
46 | final static byte INS_DISABLE_IAD_REP = (byte) 0x78;
47 |
48 | /* codes for cryptogram types used in P1 */
49 | final static byte ARQC_CODE = (byte) 0x80;
50 | final static byte TC_CODE = (byte) 0x40;
51 | final static byte AAC_CODE = (byte) 0x00;
52 | final static byte RFU_CODE = (byte) 0xC0;
53 |
54 | /* types of AC */
55 | final static byte NONE = (byte) 0x00;
56 | final static byte ARQC = (byte) 0x01;
57 | final static byte TC = (byte) 0x02;
58 | final static byte AAC = (byte) 0x03;
59 |
60 | final Pin pin;
61 | final ProtocolState protocolState;
62 | final FileSystem fileSystem;
63 | final Crypto crypto;
64 | final Log log;
65 |
66 | private final byte[] response;
67 |
68 | private Emv() {
69 | pin = new Pin();
70 | protocolState = new ProtocolState();
71 | fileSystem = new FileSystem();
72 | crypto = new Crypto(this);
73 | log = new Log();
74 |
75 | response = JCSystem.makeTransientByteArray((short) 256,
76 | JCSystem.CLEAR_ON_DESELECT);
77 | }
78 |
79 | public static void install(byte[] bArray, short bOffset, byte bLength) {
80 | // GP-complaint JavaCard applet registration
81 | new Emv().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
82 | }
83 |
84 | public void process(APDU apdu) {
85 | byte[] buf = apdu.getBuffer();
86 |
87 | // Good practice: Return 9000 on SELECT
88 | if (selectingApplet()) {
89 | log.write(buf); // Log applet selection
90 | // When selecting the application, returns it description (FCI)
91 | Util.arrayCopyNonAtomic(FileSystem.fci, (byte) 0, buf,
92 | ISO7816.OFFSET_CDATA, (short) FileSystem.fci.length);
93 | apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA,
94 | (short) FileSystem.fci.length);
95 | return;
96 | }
97 |
98 | if (buf[ISO7816.OFFSET_INS] != INS_SELECT_FILE) {
99 | log.write(buf);
100 | } // for now only log non select commands to make the log smaller
101 |
102 | // Switch the INS parameter from the APDU
103 | switch (buf[ISO7816.OFFSET_INS]) {
104 | case INS_APPEND_RECORD:
105 | ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
106 | break;
107 | case INS_EXTERNAL_AUTH:
108 | ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
109 | break;
110 | case INS_GENERATE_AC:
111 | // get remaining data
112 | short len = (short) (buf[ISO7816.OFFSET_LC] & 0xFF);
113 | if (len != apdu.setIncomingAndReceive()) {
114 | ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
115 | }
116 | // check for request of CDA signature
117 | if ((buf[ISO7816.OFFSET_P1] & 0x10) == 0x10) {
118 | // CDA signature requested, which we don't support (yet)
119 | ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
120 | }
121 | if (protocolState.getFirstACGenerated() == NONE) {
122 | generateFirstAC(apdu, buf);
123 | } else if (protocolState.getSecondACGenerated() == NONE) {
124 | generateSecondAC(apdu, buf);
125 | } else
126 | // trying to generate a third AC
127 | ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
128 | break;
129 | case INS_GET_CHALLENGE:
130 | ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
131 | break;
132 | case INS_GET_DATA:
133 | getData(apdu);
134 | break;
135 | case INS_GET_PROC_OPTIONS:
136 | getProcessingOptions(apdu);
137 | break;
138 | case INS_INTERNAL_AUTH:
139 | ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
140 | break;
141 | case INS_PIN_UNBLOCK:
142 | pin.update(apdu);
143 | break;
144 | case INS_PUT_DATA:
145 | putData(apdu);
146 | break;
147 | case INS_READ_RECORD:
148 | FileSystem.readRecord(apdu);
149 | break;
150 | case INS_SELECT_FILE:
151 | ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
152 | // FileSystem.selectFile();
153 | break;
154 | case INS_VERIFY:
155 | pin.verify(apdu);
156 | break;
157 | case INS_WRITE_RECORD:
158 | ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
159 | break;
160 | case INS_DISABLE_AC_REP:
161 | crypto.disableAcReplication();
162 | break;
163 | case INS_DISABLE_IAD_REP:
164 | crypto.disableIadReplication();
165 | case INS_CLEAR_LOG:
166 | log.clear();
167 | break;
168 | case (byte) 0x00:
169 | break;
170 | default:
171 | // good practice: If you don't know the INStruction, say so:
172 | ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
173 | }
174 | }
175 |
176 | /*
177 | * Process the PUT DATA APDU (INS=DA) PUT DATA is used to store primitive
178 | * data (like values) can be used, for example, to store a new pin retry
179 | * count (if it could be altered via APDUs)
180 | */
181 | public void putData(APDU apdu) {
182 | /*
183 | * buf[OFFSET_P1..OFFSET_P2] should contains of the following tags 9F36
184 | * - ATC 9F13 - Last online ATC 9F4F - Log Format 9F70 - AC to be
185 | * replicated 9F74 - IAD to be replicated See: EMV BOOK - Page 61
186 | */
187 | byte[] buf = apdu.getBuffer();
188 |
189 | if (buf[ISO7816.OFFSET_P1] == (byte) 0x9F) {
190 | // TODO: Check data length (cant be smaller than 2 bytes)
191 | switch (buf[ISO7816.OFFSET_P2]) {
192 | case 0x36: // ATC
193 | protocolState.setATC(Util.makeShort(buf[ISO7816.OFFSET_CDATA],
194 | buf[ISO7816.OFFSET_CDATA + 1]));
195 | apdu.setOutgoingAndSend((short) 0, (short) 0); // return 9000
196 | break;
197 | case 0x13: // Last online ATC
198 | protocolState.setLastOnlineATC(Util.makeShort(
199 | buf[ISO7816.OFFSET_CDATA],
200 | buf[ISO7816.OFFSET_CDATA + 1]));
201 | apdu.setOutgoingAndSend((short) 0, (short) 0); // return 9000
202 | break;
203 | case 0x70: // AC Replication
204 | crypto.setAc(apdu);
205 | break;
206 | case 0x74: // IAD replication
207 | setIad(apdu);
208 | break;
209 | case 0x4F: // Log Format - not supported yet
210 | default:
211 | ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
212 | break;
213 | }
214 | }
215 | }
216 |
217 | /*
218 | * Process the GET DATA APDU (CLA=80 INS=CA) GET DATA is used to read
219 | * primitive data (like the PIN try counter value)
220 | */
221 | private void getData(APDU apdu) {
222 | /*
223 | * buf[OFFSET_P1..OFFSET_P2] should contains of the following tags 9F36
224 | * - ATC 9F17 - PIN Try Counter 9F13 - Last online ATC 9F4F - Log Format
225 | * 9F72 - Log Data See: EMV BOOK - Page 61
226 | */
227 | byte[] buf = apdu.getBuffer();
228 |
229 | if (buf[ISO7816.OFFSET_P1] == (byte) 0x9F) {
230 | buf[0] = (byte) 0x9F;
231 | buf[1] = buf[ISO7816.OFFSET_P2];
232 | switch (buf[ISO7816.OFFSET_P2]) {
233 | // The buf[ISO7816.OFFSET_P1,ISO7816.OFFSET_P2] already contains the
234 | // right Tag,
235 | // so we can write the Length and Value to the next bytes in the buf
236 | // and then send this.
237 | case 0x36: // ATC
238 | buf[ISO7816.OFFSET_P2 + 1] = (byte) 0x02; // length 2 bytes
239 | Util.setShort(buf, (short) (ISO7816.OFFSET_P2 + 2),
240 | protocolState.getATC()); // value
241 | // send the 5 byte long TLV for ATC
242 | apdu.setOutgoingAndSend(ISO7816.OFFSET_P1, (short) 5);
243 | break;
244 |
245 | case 0x17: // PIN Try Counter
246 | buf[ISO7816.OFFSET_P2 + 1] = (byte) 0x01; // length 1 byte
247 | buf[ISO7816.OFFSET_P2 + 2] = pin.getTriesRemaining(); // value
248 | // send the 4 byte TLV for PIN Try counter
249 | apdu.setOutgoingAndSend(ISO7816.OFFSET_P1, (short) 4);
250 | break;
251 |
252 | case 0x13: // Last online ATC
253 | buf[ISO7816.OFFSET_P2 + 1] = (byte) 0x02; // length 2 bytes
254 | Util.setShort(buf, (short) (ISO7816.OFFSET_P2 + 2),
255 | protocolState.getLastOnlineATC()); // value
256 | // send the 5 byte long TLV for last online ATC
257 | apdu.setOutgoingAndSend(ISO7816.OFFSET_P1, (short) 5);
258 | break;
259 | case 0x72: // Log Data
260 | apdu.setOutgoing();
261 | apdu.setOutgoingLength(log.getSize());
262 | apdu.sendBytesLong(log.read(), (short) 0, log.getSize());
263 | break;
264 | case 0x4F: // Log Format - not supported yet
265 | default:
266 | ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
267 | break;
268 | }
269 | } else {
270 | ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
271 | }
272 | }
273 |
274 | /*
275 | * Process the GET PROCESSING OPTIONS APDU (CLA=80 INS=A8) returns the
276 | * Application Interchange Profile (AIP) and the Application File Locator
277 | * (AFL) See Page 63 - EMV BOOK
278 | */
279 | public void getProcessingOptions(APDU apdu) {
280 | byte[] buf = apdu.getBuffer();
281 | short readCount;
282 | readCount = apdu.setIncomingAndReceive();
283 | Util.arrayCopyNonAtomic(FileSystem.aip_afl, (byte) 0, buf,
284 | ISO7816.OFFSET_CDATA, (short) FileSystem.aip_afl.length);
285 | apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA,
286 | (short) FileSystem.aip_afl.length);
287 | }
288 |
289 | public void generateFirstAC(APDU apdu, byte[] apduBuffer) {
290 | // First 2 bits of P1 specify the type
291 | // These bits also have to be returned, as the Cryptogram Information
292 | // Data (CID);
293 | // See Book 3, Annex C6.5.5.4
294 | byte cid = (byte) (apduBuffer[ISO7816.OFFSET_P1] & 0xC0);
295 | if (cid == RFU_CODE || cid == AAC_CODE) {
296 | // not a request for TC or ARQC
297 | ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
298 | }
299 |
300 | crypto.generateFirstACReponse(cid, apduBuffer,
301 | fileSystem.getCDOL1DataLength(), null, (short) 0, response,
302 | (short) 0);
303 | protocolState.setFirstACGenerated(cid);
304 |
305 | apdu.setOutgoing();
306 | apdu.setOutgoingLength((short) (response[1] + 2));
307 | apdu.sendBytesLong(response, (short) 0, (short) (response[1] + 2));
308 | }
309 |
310 | public void generateSecondAC(APDU apdu, byte[] apduBuffer) {
311 | // First 2 bits of P1 specify the type
312 | // These bits also have to be returned, as the Cryptogram Information
313 | // Data (CID);
314 | // See Book 3, Sect 6.5.5.4 of the Common Core Definitions.
315 | byte cid = (byte) (apduBuffer[ISO7816.OFFSET_P1] & 0xC0);
316 | if (cid == RFU_CODE || cid == ARQC_CODE) {
317 | // not a request for TC or AAC
318 | ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
319 | }
320 |
321 | crypto.generateSecondACReponse(cid, apduBuffer,
322 | fileSystem.getCDOL2DataLength(), null, (short) 0, response,
323 | (short) 0);
324 | protocolState.setSecondACGenerated(cid);
325 |
326 | apdu.setOutgoing();
327 | apdu.setOutgoingLength((short) (response[1] + 2));
328 | apdu.sendBytesLong(response, (short) 0, (short) (response[1] + 2));
329 | }
330 |
331 | public void setIad(APDU apdu) {
332 | byte[] buf = apdu.getBuffer();
333 | if (buf[ISO7816.OFFSET_LC] > (byte) 0x12) { // Max IAD size is 18 bytes
334 | ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
335 | }
336 |
337 | crypto.setIad(buf);
338 | apdu.setOutgoingAndSend((short) 0, (short) 0); // return 9000
339 | }
340 | }
--------------------------------------------------------------------------------
/emv/src/smart/Crypto.java:
--------------------------------------------------------------------------------
1 | package smart;
2 |
3 | import javacard.framework.ISO7816;
4 | import javacard.framework.JCSystem;
5 | import javacard.framework.Util;
6 | import javacard.security.DESKey;
7 | import javacard.security.KeyBuilder;
8 | import javacard.security.Signature;
9 | import javacardx.crypto.Cipher;
10 | import javacard.framework.APDU;
11 |
12 | public class Crypto {
13 |
14 | /* Reference back to the applet that uses this EMVCrypto object */
15 | private final Emv theApplet;
16 |
17 | private final byte[] sessionkey;
18 |
19 | /** 3DESKey ICC Master Key, shared with the bank */
20 | private final DESKey mk;
21 |
22 | private final Cipher desCipher;
23 | private final Signature desMAC;
24 |
25 | /** 3DESKey session keys, derived from Master Key mk */
26 | private final DESKey sk;
27 |
28 | /**
29 | * Scratchpad transient byte array for diversification data used to build
30 | * session key
31 | */
32 | private final byte[] diversification_data;
33 |
34 | /** Transient byte array for storing ac transaction_data */
35 | byte[] transaction_data;
36 |
37 | // Used to store an injected ac for replication
38 | private final byte[] replicated_ac;
39 | private boolean replicateAc;
40 |
41 | // Used to store an injected IAD for replication
42 | private final byte[] replicated_iad;
43 | private boolean replicate_iad;
44 | private short replicated_iad_length;
45 |
46 | public Crypto(Emv x) {
47 | theApplet = x; // reference back to the applet
48 |
49 | diversification_data = JCSystem.makeTransientByteArray((short) 8,
50 | JCSystem.CLEAR_ON_DESELECT);
51 | sessionkey = JCSystem.makeTransientByteArray((short) 16,
52 | JCSystem.CLEAR_ON_DESELECT);
53 | transaction_data = JCSystem.makeTransientByteArray((short) 256,
54 | JCSystem.CLEAR_ON_DESELECT);
55 |
56 | desCipher = Cipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M2, false);
57 | desMAC = Signature
58 | .getInstance(Signature.ALG_DES_MAC8_ISO9797_M2, false);
59 |
60 | mk = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES,
61 | KeyBuilder.LENGTH_DES3_2KEY, false);
62 | mk.setKey(new byte[] { 0x11, 0x0C, 0x1D, 0x02, 0x03, 0x04, 0x0C,
63 | (byte) 0xDA, (byte) 0xFA, (byte) 0xCA, 0x04, 0x11, 0x12, 0x14,
64 | (byte) 0xCA, 0x16 }, (short) 0);
65 | sk = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES,
66 | KeyBuilder.LENGTH_DES3_2KEY, false);
67 |
68 | replicated_ac = new byte[] { (byte) 0x4D, (byte) 0xE1, (byte) 0x4B,
69 | (byte) 0xFC, (byte) 0x2F, (byte) 0x73, (byte) 0xBA, (byte) 0xC4 };
70 | replicateAc = true;
71 |
72 | replicated_iad = new byte[] { (byte) 0x02, (byte) 0x10, (byte) 0xA0,
73 | (byte) 0x00, (byte) 0x03, (byte) 0x22, (byte) 0x00,
74 | (byte) 0x00, (byte) 0x27, (byte) 0x11, (byte) 0x00,
75 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
76 | (byte) 0x00, (byte) 0x00, (byte) 0xFF };
77 | replicate_iad = true;
78 | replicated_iad_length = (short) 18;
79 | }
80 |
81 | /*
82 | * Sets the current 3DES session key, based on the Application Transaction
83 | * Counter (ATC).
84 | *
85 | * It is done as described in Book 2, Annex A1.3.1, by encrypting ATC || F0
86 | * || 00 || 00 || 00 || 00 || 00 with the card's 3DES Master Key to obtain
87 | * the left 8 bytes, and encrypting ATC || OF || 00 || 00 || 00 || 00 || 00
88 | * with the card's 3DES Master Key to obtain the right 8 bytes.
89 | */
90 | private void setSessionKey() {
91 | // as 8-byte diversification data we take the ATC followed by all zeroes
92 | Util.setShort(diversification_data, (short) 0,
93 | theApplet.protocolState.getATC());
94 | Util.arrayFillNonAtomic(diversification_data, (short) 2, (short) 6,
95 | (byte) 0);
96 |
97 | desCipher.init(mk, Cipher.MODE_ENCRYPT);
98 |
99 | // compute left 8 bytes of the session key
100 | diversification_data[2] = (byte) 0xF0;
101 | desCipher.doFinal(diversification_data, (short) 0, (short) 8,
102 | sessionkey, (short) 0);
103 |
104 | // compute right 8 byte of the session key
105 | diversification_data[2] = (byte) 0x0F;
106 | desCipher.doFinal(diversification_data, (short) 0, (short) 8,
107 | sessionkey, (short) 0);
108 |
109 | sk.setKey(sessionkey, (short) 0);
110 | }
111 |
112 | /*
113 | * Computes a cryptogram, as described in Book 2, Sec 8.1, and stores it in
114 | * the given response buffer at the given offset.
115 | *
116 | * The cryptogram is an 8 byte MAC over data supplied by the terminal (as
117 | * specified by the CDOL1 or CDOL2) and data provided by the ICC.
118 | *
119 | * The data supplied by the terminal is in the ADPU buffer. This method does
120 | * not need to know what this data is, ie. does not need to know the CDOLs,
121 | * but only needs to know the total length of these data elements.
122 | *
123 | * As data provided by the ICC this method just uses the minimum recommended
124 | * set of data elements, ie the AIP and ATC (see Book 2, Sect 8.1.1), for
125 | * both the first and the second AC. Hence one method can be used for both.
126 | *
127 | * @requires apduBuffer != response, to avoid problems overwriting the
128 | * apduBuffer??
129 | *
130 | * @param cid the type of AC, ie. AAC_CODE, TC_CODE, or ARCQ_CODE
131 | *
132 | * @param apduBuffer contains the terminal-supplied data to be signed in the
133 | * AC
134 | *
135 | * @param length length of the terminal-supplied data
136 | *
137 | * @param response the destination array where the AC is stored at given
138 | * offset
139 | *
140 | * @param offset offset in this response array
141 | */
142 | private void computeAC(byte cid, byte[] apduBuffer, short length,
143 | byte[] response, short offset) {
144 |
145 | // Check if replicated AC func is enabled and act accordingly
146 | if (replicateAc == true) {
147 | Util.arrayCopy(replicated_ac, (short) 0, response, offset,
148 | (short) 8);
149 | } else {
150 | /* Collect the data to be MAC-ed in the array transaction_data */
151 |
152 | // Copy CDOL from the APDU buffer, at offset 0:
153 | Util.arrayCopy(apduBuffer, ISO7816.OFFSET_CDATA, transaction_data,
154 | (short) 0, length);
155 | // 2 bytes AIP, at offset length:
156 | Util.setShort(transaction_data, length,
157 | theApplet.fileSystem.getAIP());
158 | // 2 bytes ATC, at offset length + 2:
159 | Util.setShort(transaction_data, (short) (length + 2),
160 | theApplet.protocolState.getATC());
161 |
162 | // TODO What is the following data?
163 | transaction_data[(short) (length + 4)] = (byte) 0x80;
164 | transaction_data[(short) (length + 5)] = (byte) 0x0;
165 | transaction_data[(short) (length + 6)] = (byte) 0x0;
166 |
167 | // MAC is a CBC-MAC computed according to ISO/IEC 9797-1, padding
168 | // method 2
169 | desMAC.init(sk, Signature.MODE_SIGN);
170 | desMAC.sign(transaction_data, (short) 0, (short) (length + 7),
171 | response, offset);
172 | }
173 | }
174 |
175 | public void disableAcReplication() {
176 | replicateAc = false;
177 | }
178 |
179 | public void setAc(APDU apdu) {
180 | byte[] buf = apdu.getBuffer();
181 |
182 | // Store the new AC to be replicated later and enable the functionality
183 | // TODO: Validate the new AC length before trying to save it (array out
184 | // of bounds)
185 | Util.arrayCopy(buf, (short) (ISO7816.OFFSET_CDATA), replicated_ac,
186 | (short) 0, (short) 8);
187 | replicateAc = true;
188 |
189 | apdu.setOutgoingAndSend((short) 0, (short) 0); // return 9000
190 | }
191 |
192 | public void disableIadReplication(APDU apdu) {
193 | replicate_iad = false;
194 | apdu.setOutgoingAndSend((short) 0, (short) 0); // return 9000
195 | }
196 |
197 | public void setIad(byte[] buf) {
198 | // Store the new IAD to be replicated later and enable the functionality
199 | if (buf[ISO7816.OFFSET_LC] > (byte) 0x12) {
200 | Util.arrayCopy(buf, (short) (ISO7816.OFFSET_CDATA), replicated_iad,
201 | (short) 0, (short) 18);
202 | replicated_iad_length = (short) 18;
203 | } else {
204 | Util.arrayCopy(buf, (short) (ISO7816.OFFSET_CDATA), replicated_iad,
205 | (short) 0, (short) buf[ISO7816.OFFSET_LC]);
206 | replicated_iad_length = (short) buf[ISO7816.OFFSET_LC];
207 | }
208 |
209 | replicate_iad = true;
210 | }
211 |
212 | public void disableIadReplication() {
213 | replicate_iad = false;
214 | }
215 |
216 | /*
217 | * Compute the first AC response APDU using Format 1. (See Book 3, Section
218 | * 6.5.5.4.) This method also sets the session key.
219 | *
220 | * The response contains the - CID: Cryptogram Information Data, 1 byte long
221 | * - ATC Application Transaction Counter, 2 bytes long - AC: Application
222 | * Cryptogram, 8 bytes long - optionally, IAD: Issuer Application Data, 30
223 | * bytes long
224 | *
225 | * @param cid the type of AC, ie. AAC_CODE, TC_CODE, or ARCQ_CODE
226 | *
227 | * @param apduBuffer contains the terminal-supplied data
228 | *
229 | * @param length length of the terminal-supplied data
230 | *
231 | * @param iad the IAD, or null, if IAD is omitted
232 | *
233 | * @param response the destination array where the response is stored, at
234 | * given offset
235 | */
236 | public void generateFirstACReponse(byte cid, byte[] apduBuffer,
237 | short length, byte[] iad, short iad_length, byte[] response,
238 | short offset) {
239 | setSessionKey();
240 | generateSecondACReponse(cid, apduBuffer, length, iad, iad_length,
241 | response, offset);
242 | }
243 |
244 | /*
245 | * Compute the second AC response APDU using Format 1. (See Book 3, Section
246 | * 6.5.5.4.)
247 | */
248 | public void generateSecondACReponse(byte cid, byte[] apduBuffer,
249 | short length, byte[] iad, short iad_length, byte[] response,
250 | short offset) {
251 |
252 | // ARQC with CDA - Book 3, page 57, table 11
253 | // if (cid == (byte) 0x90) {
254 | if (true) {
255 | response[offset] = (byte) 0x77; // Tag for Format 2 cryptogram
256 | response[(short) offset + 1] = (byte) 0x00; // Base Length
257 |
258 | // 1 byte CID, the type of AC returned - TAG 9F27 length 01
259 | response[(short) offset + 1] = (byte) (response[(short) offset + 1] + (byte) 4); // Base
260 | // Length
261 | Util.setShort(response, (short) (offset + 2), (short) 0x9F27); // Tag
262 | response[(short) (offset + 4)] = (byte) 0x01; // Length
263 | response[(short) (offset + 5)] = cid; // Value
264 |
265 | // 2 byte ATC - Tag 9F36 length 02
266 | response[(short) offset + 1] = (byte) (response[(short) offset + 1] + (byte) 5); // Base
267 | // Length
268 | Util.setShort(response, (short) (offset + 6), (short) 0x9F36); // Tag
269 | response[(short) (offset + 8)] = (byte) 0x02; // Length
270 | Util.setShort(response, (short) (offset + 9),
271 | theApplet.protocolState.getATC()); // Value
272 |
273 | // the AC itself - Tag 9F26 - length 08
274 | response[(short) offset + 1] = (byte) (response[(short) offset + 1] + (byte) 11); // Base
275 | // Length
276 | Util.setShort(response, (short) (offset + 11), (short) 0x9F26); // Tag
277 | response[(short) (offset + 13)] = (byte) 0x08; // Length
278 | computeAC(cid, apduBuffer, length, response, (short) (offset + 14));
279 |
280 | // finally we get the IAD - 9F10 - length 18
281 | Util.setShort(response, (short) (offset + 22), (short) 0x9F10); // Tag
282 | if (iad != null) {
283 | response[(short) (offset + 24)] = (byte) iad.length; // Length
284 | Util.arrayCopy(iad, (short) 0, response, (short) (offset + 25),
285 | (short) iad.length);
286 | response[(short) offset + 1] = (byte) (response[(short) offset + 1]
287 | + (byte) 0x03 + (byte) iad.length); // Base Length
288 | } else {
289 | if (replicate_iad == true) {
290 | // We use the IAD set for replication
291 | response[(short) (offset + 24)] = (byte) replicated_iad_length; // Length
292 | Util.arrayCopy(replicated_iad, (short) 0, response,
293 | (short) (offset + 25), replicated_iad_length);
294 | response[(short) offset + 1] = (byte) (response[(short) offset + 1]
295 | + (byte) 0x03 + (byte) replicated_iad_length); // Base
296 | // Length
297 | } else {
298 | // Force an IAD of 18 bytes consisting of all 0s
299 | response[(short) (offset + 24)] = (byte) 0x12; // Length
300 | Util.arrayFillNonAtomic(response, (short) (offset + 25),
301 | (short) 18, (byte) 0x0);
302 | response[(short) offset + 1] = (byte) (response[(short) offset + 1]
303 | + (byte) 0x03 + (byte) 18); // Base Length
304 | }
305 | }
306 | }
307 | // ARQC without CDA (cid 80) - Book 3, page 57, table 11
308 | else {
309 | // Code for old Tag format 80 response
310 | response[offset] = (byte) 0x80; // Tag for Format 1 cryptogram
311 |
312 | if (iad == null) { // Length: 1 byte CID + 2 byte ATC + 8 byte AC =
313 | // 11
314 | response[(short) (offset + 1)] = (byte) 11;
315 | } else { // Length: 1 byte CID + 2 byte ATC + 8 byte AC + iad_length
316 | // byte IAD
317 | response[(short) (offset + 1)] = (byte) (11 + iad_length);
318 | }
319 | // 1 byte CID, ie the type of AC returned - TAG 9F27
320 | response[(short) (offset + 2)] = cid;
321 |
322 | // 2 byte ATC, at offset 3: - 9F36
323 | Util.setShort(response, (short) (offset + 3),
324 | theApplet.protocolState.getATC());
325 |
326 | // the AC itself - 9F26
327 | computeAC(cid, apduBuffer, length, response, (short) (offset + 5));
328 |
329 | // finally we get the (optional) IAD - 9F10
330 | if (iad != null) {
331 | Util.arrayCopy(iad, (short) 0, response, (short) (offset + 13),
332 | (short) 18);
333 | }
334 |
335 | // Force an IAD of 18 bytes consisting of all 0s - Needed for
336 | // EMV-CAP reader
337 | response[(short) (offset + 1)] = (byte) 29;
338 | Util.arrayFillNonAtomic(response, (short) (offset + 13),
339 | (short) 18, (byte) 0x0);
340 | }
341 | }
342 | }
343 |
--------------------------------------------------------------------------------
/emv/src/smart/FileSystem.java:
--------------------------------------------------------------------------------
1 | package smart;
2 |
3 | import javacard.framework.APDU;
4 | import javacard.framework.ISO7816;
5 | import javacard.framework.ISOException;
6 |
7 | //import javacard.framework.JCSystem;
8 |
9 | public class FileSystem {
10 | /*
11 | * Usual Structure: MF | |-+ EF 01 | --- Record 01 |-+ EF 02 | --- Record 01
12 | * | --- Record 02 |-+ EF 03 | --- Record 01 (for offline data / EMV reader
13 | * different icon) | --- Record 02
14 | */
15 |
16 | // File Allocation Table (for now, use a fixed EF limit)
17 | private static final byte EF_1_ID = 1;
18 | private static final byte EF_2_ID = 2;
19 | private static final byte EF_3_ID = 3;
20 |
21 | // Dynamic EFs (will contain the Record Files (as array of bytes too)
22 | private static byte[] ef_1_data;
23 | private static byte[] ef_2_data;
24 | private static byte[] ef_3_data;
25 |
26 | private final static byte[] ef01_r01 = { (byte) 0x70, (byte) 0x33, (byte) 0x57, (byte) 0x13, (byte) 0x41, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0xD2, (byte) 0x10, (byte) 0x72, (byte) 0x06, (byte) 0x14, (byte) 0x71, (byte) 0x09, (byte) 0x40, (byte) 0x90, (byte) 0x87, (byte) 0x0F, (byte) 0x5F, (byte) 0x20, (byte) 0x08, (byte) 0x4A, (byte) 0x4F, (byte) 0x45, (byte) 0x20, (byte) 0x54, (byte) 0x45, (byte) 0x53, (byte) 0x54, (byte) 0x9F, (byte) 0x1F, (byte) 0x10, (byte) 0x31, (byte) 0x34, (byte) 0x37, (byte) 0x31, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x39, (byte) 0x34, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30 };
27 |
28 | private final static byte[] ef01_r02 = { (byte) 0x70, (byte) 0x13, (byte) 0x9F, (byte) 0x08, (byte) 0x02, (byte) 0x00, (byte) 0x8D, (byte) 0x5F, (byte) 0x30, (byte) 0x02, (byte) 0x02, (byte) 0x06, (byte) 0x9F, (byte) 0x42, (byte) 0x02, (byte) 0x09, (byte) 0x86, (byte) 0x9F, (byte) 0x44, (byte) 0x01, (byte) 0x02 };
29 |
30 | private final static byte[] ef01_r03 = { (byte) 0x70, (byte) 0x30, (byte) 0x8C, (byte) 0x15, (byte) 0x9F, (byte) 0x02, (byte) 0x06, (byte) 0x9F, (byte) 0x03, (byte) 0x06, (byte) 0x9F, (byte) 0x1A, (byte) 0x02, (byte) 0x95, (byte) 0x05, (byte) 0x5F, (byte) 0x2A, (byte) 0x02, (byte) 0x9A, (byte) 0x03, (byte) 0x9C, (byte) 0x01, (byte) 0x9F, (byte) 0x37, (byte) 0x04, (byte) 0x8D, (byte) 0x17, (byte) 0x8A, (byte) 0x02, (byte) 0x9F, (byte) 0x02, (byte) 0x06, (byte) 0x9F, (byte) 0x03, (byte) 0x06, (byte) 0x9F, (byte) 0x1A, (byte) 0x02, (byte) 0x95, (byte) 0x05, (byte) 0x5F, (byte) 0x2A, (byte) 0x02, (byte) 0x9A, (byte) 0x03, (byte) 0x9C, (byte) 0x01, (byte) 0x9F, (byte) 0x37, (byte) 0x04 };
31 |
32 | private final static byte[] ef01_r04 = { (byte) 0x00 };
33 |
34 | private final static byte[] ef01_r05 = { (byte) 0x00 };
35 |
36 | private final static byte[] ef01_r06 = { (byte) 0x00 };
37 |
38 | private final static byte[] ef02_r01 = { (byte) 0x70, (byte) 0x0E, (byte) 0x5A, (byte) 0x08, (byte) 0x41, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x5F, (byte) 0x34, (byte) 0x01, (byte) 0x00 };
39 |
40 | private final static byte[] ef02_r02 = { (byte) 0x70, (byte) 0x16, (byte) 0x5F, (byte) 0x24, (byte) 0x03, (byte) 0x21, (byte) 0x07, (byte) 0x31, (byte) 0x9F, (byte) 0x07, (byte) 0x02, (byte) 0xFF, (byte) 0x80, (byte) 0x5F, (byte) 0x28, (byte) 0x02, (byte) 0x00, (byte) 0x76, (byte) 0x5F, (byte) 0x25, (byte) 0x03, (byte) 0x15, (byte) 0x07, (byte) 0x23 };
41 |
42 | private final static byte[] ef02_r03 = { (byte) 0x70, (byte) 0x81, (byte) 0xE0, (byte) 0x8F, (byte) 0x01, (byte) 0x08, (byte) 0x90, (byte) 0x81, (byte) 0xB0, (byte) 0xBF, (byte) 0x63, (byte) 0xBF, (byte) 0xF5, (byte) 0x61, (byte) 0x97, (byte) 0x0C, (byte) 0x85, (byte) 0xA8, (byte) 0x27, (byte) 0xAD, (byte) 0xAB, (byte) 0xF8, (byte) 0x56, (byte) 0x68, (byte) 0x0B, (byte) 0xD6, (byte) 0x81, (byte) 0xD0, (byte) 0x99, (byte) 0xDD, (byte) 0xDD, (byte) 0x9F, (byte) 0xD4, (byte) 0xD9, (byte) 0xAB, (byte) 0xE5, (byte) 0x85, (byte) 0x09, (byte) 0xEC, (byte) 0x65, (byte) 0x38, (byte) 0x0C, (byte) 0xA5, (byte) 0xEE, (byte) 0x87, (byte) 0x3C, (byte) 0xA4, (byte) 0x9A, (byte) 0x15, (byte) 0x68, (byte) 0xEA, (byte) 0x77, (byte) 0x8B, (byte) 0x0A, (byte) 0x29, (byte) 0x9A, (byte) 0x83, (byte) 0x45, (byte) 0x8A, (byte) 0x8A, (byte) 0x0D, (byte) 0x70, (byte) 0x47, (byte) 0x3F, (byte) 0xE3, (byte) 0x5E, (byte) 0xF1, (byte) 0x36, (byte) 0x98, (byte) 0xBA, (byte) 0x6F, (byte) 0x94, (byte) 0xDF, (byte) 0xAB, (byte) 0x19, (byte) 0x43, (byte) 0xD9, (byte) 0xEF, (byte) 0x75, (byte) 0xAC, (byte) 0x3B, (byte) 0xFE, (byte) 0xC1, (byte) 0x6B, (byte) 0x47, (byte) 0x74, (byte) 0x4D, (byte) 0x32, (byte) 0x02, (byte) 0xA6, (byte) 0x03, (byte) 0x78, (byte) 0x31, (byte) 0x96, (byte) 0x0E, (byte) 0x1A, (byte) 0x2A, (byte) 0xF4, (byte) 0x30, (byte) 0xAE, (byte) 0x41, (byte) 0xDB, (byte) 0xD3, (byte) 0xE9, (byte) 0x63, (byte) 0xE0, (byte) 0x08, (byte) 0xD7, (byte) 0x91, (byte) 0xE7, (byte) 0xDC, (byte) 0x8F, (byte) 0x46, (byte) 0xC2, (byte) 0x54, (byte) 0x24, (byte) 0xFF, (byte) 0xF8, (byte) 0x08, (byte) 0xB5, (byte) 0xE3, (byte) 0xEE, (byte) 0xBC, (byte) 0x96, (byte) 0x0F, (byte) 0x80, (byte) 0xBD, (byte) 0x8E, (byte) 0x0F, (byte) 0x82, (byte) 0xD6, (byte) 0xC1, (byte) 0x98, (byte) 0x14, (byte) 0x00, (byte) 0xA9, (byte) 0xC7, (byte) 0x32, (byte) 0x3E, (byte) 0xE3, (byte) 0x38, (byte) 0x8D, (byte) 0xA4, (byte) 0xFA, (byte) 0xFF, (byte) 0x7B, (byte) 0xFE, (byte) 0x53, (byte) 0xA5, (byte) 0x98, (byte) 0xDA, (byte) 0x10, (byte) 0xC1, (byte) 0xB1, (byte) 0xDE, (byte) 0xF7, (byte) 0x5A, (byte) 0x6F, (byte) 0x7D, (byte) 0xE7, (byte) 0xC8, (byte) 0x71, (byte) 0x25, (byte) 0xC7, (byte) 0xB3, (byte) 0x74, (byte) 0x15, (byte) 0x86, (byte) 0x5F, (byte) 0x6B, (byte) 0xE0, (byte) 0x48, (byte) 0xDB, (byte) 0x66, (byte) 0x0F, (byte) 0x9D, (byte) 0x50, (byte) 0xC9, (byte) 0xB2, (byte) 0x5C, (byte) 0xF8, (byte) 0x1A, (byte) 0xBB, (byte) 0x96, (byte) 0x73, (byte) 0x9F, (byte) 0x32, (byte) 0x01, (byte) 0x03, (byte) 0x92, (byte) 0x24, (byte) 0xF8, (byte) 0xE1, (byte) 0x75, (byte) 0x61, (byte) 0x48, (byte) 0x32, (byte) 0x33, (byte) 0xFA, (byte) 0x5B, (byte) 0x36, (byte) 0x40, (byte) 0xBA, (byte) 0xE1, (byte) 0xCD, (byte) 0x7D, (byte) 0xA5, (byte) 0xEC, (byte) 0x55, (byte) 0xF4, (byte) 0xC4, (byte) 0xB3, (byte) 0x24, (byte) 0x61, (byte) 0xC6, (byte) 0x87, (byte) 0x39, (byte) 0xF8, (byte) 0x79, (byte) 0xBC, (byte) 0x9F, (byte) 0xB8, (byte) 0xD8, (byte) 0xEE, (byte) 0xA9, (byte) 0x0D, (byte) 0x2D };
43 |
44 | private final static byte[] ef02_r04 = { (byte) 0x70, (byte) 0x1C, (byte) 0x9F, (byte) 0x0E, (byte) 0x05, (byte) 0x2C, (byte) 0x10, (byte) 0x98, (byte) 0x00, (byte) 0x00, (byte) 0x9F, (byte) 0x0F, (byte) 0x05, (byte) 0xD0, (byte) 0x68, (byte) 0x24, (byte) 0xF8, (byte) 0x00, (byte) 0x9F, (byte) 0x0D, (byte) 0x05, (byte) 0xD0, (byte) 0x68, (byte) 0x24, (byte) 0xA8, (byte) 0x00, (byte) 0x9F, (byte) 0x4A, (byte) 0x01, (byte) 0x82 };
45 |
46 | private final static byte[] ef02_r05 = { (byte) 0x70, (byte) 0x16, (byte) 0x8E, (byte) 0x14, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x42, (byte) 0x01, (byte) 0x41, (byte) 0x03, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
47 |
48 | private final static byte[] ef02_r06 = { (byte) 0x70, (byte) 0x81, (byte) 0xB3, (byte) 0x93, (byte) 0x81, (byte) 0xB0, (byte) 0x8E, (byte) 0x69, (byte) 0xF5, (byte) 0xFA, (byte) 0x9C, (byte) 0xBC, (byte) 0xB6, (byte) 0x5B, (byte) 0x1C, (byte) 0x97, (byte) 0xCE, (byte) 0x3A, (byte) 0xB3, (byte) 0xBC, (byte) 0x5E, (byte) 0xE6, (byte) 0x3C, (byte) 0xB4, (byte) 0x0C, (byte) 0x7A, (byte) 0xF4, (byte) 0x5B, (byte) 0xFE, (byte) 0xED, (byte) 0x4C, (byte) 0x5E, (byte) 0xB7, (byte) 0x1A, (byte) 0xE1, (byte) 0x10, (byte) 0x57, (byte) 0x10, (byte) 0x62, (byte) 0x24, (byte) 0xFD, (byte) 0x78, (byte) 0x24, (byte) 0x80, (byte) 0x8E, (byte) 0xA1, (byte) 0x8B, (byte) 0x38, (byte) 0xF9, (byte) 0x79, (byte) 0x9F, (byte) 0x3C, (byte) 0xF8, (byte) 0x66, (byte) 0x41, (byte) 0xB2, (byte) 0xB0, (byte) 0x8B, (byte) 0xED, (byte) 0x29, (byte) 0x22, (byte) 0xB4, (byte) 0xB3, (byte) 0x77, (byte) 0x31, (byte) 0x3F, (byte) 0x6D, (byte) 0xF1, (byte) 0x19, (byte) 0x13, (byte) 0x3D, (byte) 0xBD, (byte) 0xC9, (byte) 0x3B, (byte) 0x14, (byte) 0x31, (byte) 0x09, (byte) 0xAD, (byte) 0x26, (byte) 0xCE, (byte) 0xBC, (byte) 0x7B, (byte) 0xB4, (byte) 0xF7, (byte) 0x10, (byte) 0x1F, (byte) 0x53, (byte) 0xE4, (byte) 0x99, (byte) 0xCA, (byte) 0x05, (byte) 0x22, (byte) 0x0D, (byte) 0x3C, (byte) 0xC6, (byte) 0xF6, (byte) 0xE3, (byte) 0xE0, (byte) 0x37, (byte) 0x86, (byte) 0xBC, (byte) 0x27, (byte) 0x47, (byte) 0x27, (byte) 0x42, (byte) 0x0D, (byte) 0x3A, (byte) 0x91, (byte) 0x00, (byte) 0xB0, (byte) 0x5F, (byte) 0xE8, (byte) 0x51, (byte) 0x41, (byte) 0x65, (byte) 0x8D, (byte) 0xA7, (byte) 0xD0, (byte) 0x68, (byte) 0x9C, (byte) 0x7C, (byte) 0x20, (byte) 0xF2, (byte) 0x82, (byte) 0xAE, (byte) 0x21, (byte) 0x58, (byte) 0x0F, (byte) 0xC4, (byte) 0x25, (byte) 0x2E, (byte) 0x30, (byte) 0xC6, (byte) 0xFA, (byte) 0x60, (byte) 0xF1, (byte) 0x80, (byte) 0x56, (byte) 0x93, (byte) 0xFB, (byte) 0xEF, (byte) 0x5D, (byte) 0xFF, (byte) 0xEF, (byte) 0xB0, (byte) 0x9A, (byte) 0x11, (byte) 0x04, (byte) 0xEC, (byte) 0x22, (byte) 0x5A, (byte) 0xB7, (byte) 0x9D, (byte) 0xD4, (byte) 0xC8, (byte) 0xCA, (byte) 0xCC, (byte) 0x25, (byte) 0x34, (byte) 0xF6, (byte) 0xEF, (byte) 0x1B, (byte) 0x2D, (byte) 0xB6, (byte) 0xA1, (byte) 0x96, (byte) 0xE2, (byte) 0x1B, (byte) 0x40, (byte) 0xB6, (byte) 0xD3, (byte) 0xAD, (byte) 0x8A, (byte) 0xC0, (byte) 0x99, (byte) 0xA6, (byte) 0x4C, (byte) 0x8C, (byte) 0x70, (byte) 0xBE, (byte) 0xD2, (byte) 0x8C };
49 |
50 | private final static byte[] ef02_r07 = { (byte) 0x70, (byte) 0x1C, (byte) 0x9F, (byte) 0x0E, (byte) 0x05, (byte) 0x2C, (byte) 0x10, (byte) 0x98, (byte) 0x00, (byte) 0x00, (byte) 0x9F, (byte) 0x0F, (byte) 0x05, (byte) 0xD0, (byte) 0x68, (byte) 0x24, (byte) 0xF8, (byte) 0x00, (byte) 0x9F, (byte) 0x0D, (byte) 0x05, (byte) 0xD0, (byte) 0x68, (byte) 0x24, (byte) 0xA8, (byte) 0x00, (byte) 0x9F, (byte) 0x4A, (byte) 0x01, (byte) 0x82 };
51 |
52 | private final static byte[] ef02_r08 = { (byte) (byte) 0x70, (byte) 0x16, (byte) 0x8E, (byte) 0x14, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x42, (byte) 0x03, (byte) 0x41, (byte) 0x03, (byte) 0x1E, (byte) 0x03, (byte) 0x1F, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
53 |
54 | private final static byte[] ef02_r09 = { (byte) 0x70, (byte) 0x81, (byte) 0xB3, (byte) 0x93, (byte) 0x81, (byte) 0xB0, (byte) 0x9F, (byte) 0x06, (byte) 0x1E, (byte) 0xEF, (byte) 0x4A, (byte) 0x23, (byte) 0xD0, (byte) 0x1B, (byte) 0x46, (byte) 0x5E, (byte) 0x86, (byte) 0x42, (byte) 0x3C, (byte) 0xBA, (byte) 0xD1, (byte) 0x88, (byte) 0x87, (byte) 0xE2, (byte) 0x43, (byte) 0x02, (byte) 0x9D, (byte) 0x79, (byte) 0x69, (byte) 0x54, (byte) 0x90, (byte) 0xA3, (byte) 0xC2, (byte) 0x1C, (byte) 0xB1, (byte) 0x4E, (byte) 0xFD, (byte) 0x8D, (byte) 0xAC, (byte) 0xAD, (byte) 0x94, (byte) 0x22, (byte) 0x77, (byte) 0x34, (byte) 0xB1, (byte) 0x6D, (byte) 0xCE, (byte) 0x2C, (byte) 0xA3, (byte) 0x65, (byte) 0x0B, (byte) 0x5C, (byte) 0xA0, (byte) 0xC9, (byte) 0x21, (byte) 0x88, (byte) 0x0A, (byte) 0x24, (byte) 0x8E, (byte) 0x04, (byte) 0x40, (byte) 0x15, (byte) 0xA6, (byte) 0x0D, (byte) 0xDA, (byte) 0x42, (byte) 0x08, (byte) 0x03, (byte) 0x57, (byte) 0x1A, (byte) 0x03, (byte) 0x42, (byte) 0x2D, (byte) 0x59, (byte) 0x5F, (byte) 0xD3, (byte) 0xB5, (byte) 0x91, (byte) 0x43, (byte) 0x75, (byte) 0x5B, (byte) 0xD5, (byte) 0x32, (byte) 0x77, (byte) 0x7C, (byte) 0x3A, (byte) 0x25, (byte) 0xAB, (byte) 0x1C, (byte) 0x95, (byte) 0x32, (byte) 0x18, (byte) 0xBF, (byte) 0xF8, (byte) 0xEC, (byte) 0x0E, (byte) 0xFA, (byte) 0xA0, (byte) 0x41, (byte) 0x1B, (byte) 0x6E, (byte) 0x62, (byte) 0xF0, (byte) 0x67, (byte) 0xED, (byte) 0x21, (byte) 0x35, (byte) 0x49, (byte) 0xA1, (byte) 0x27, (byte) 0x30, (byte) 0xCB, (byte) 0x47, (byte) 0x0A, (byte) 0xAE, (byte) 0x59, (byte) 0xB7, (byte) 0x01, (byte) 0x1E, (byte) 0xDE, (byte) 0x7D, (byte) 0x43, (byte) 0x1E, (byte) 0x66, (byte) 0x04, (byte) 0xBF, (byte) 0x72, (byte) 0x97, (byte) 0xD6, (byte) 0x86, (byte) 0x42, (byte) 0x0F, (byte) 0xBF, (byte) 0xB5, (byte) 0x4D, (byte) 0xBE, (byte) 0x44, (byte) 0x74, (byte) 0x95, (byte) 0x67, (byte) 0xE6, (byte) 0x1A, (byte) 0x98, (byte) 0xC1, (byte) 0x7B, (byte) 0x10, (byte) 0x8A, (byte) 0xB8, (byte) 0xF2, (byte) 0x59, (byte) 0xA1, (byte) 0x2E, (byte) 0xAD, (byte) 0x14, (byte) 0xA6, (byte) 0xF7, (byte) 0x00, (byte) 0x06, (byte) 0x31, (byte) 0xB6, (byte) 0x42, (byte) 0x7C, (byte) 0xAD, (byte) 0xFE, (byte) 0x49, (byte) 0xAC, (byte) 0xE9, (byte) 0x71, (byte) 0xBD, (byte) 0xCA, (byte) 0xE6, (byte) 0xAD, (byte) 0x7C, (byte) 0x23, (byte) 0x67, (byte) 0xE3, (byte) 0x58, (byte) 0xA9, (byte) 0x05, (byte) 0xD2, (byte) 0xAD, (byte) 0x7C };
55 |
56 | private final static byte[] ef04_r01 = { (byte) 0x00 };
57 |
58 | private static byte[] selectFile; // Will hold the ID of the selected EF (probably not supported for now)
59 |
60 | public final static byte[] fci = { (byte) 0x6F, (byte) 0x81, (byte) 0x88, (byte) 0x84, (byte) 0x07, (byte) 0xA0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x20, (byte) 0x10, (byte) 0xA5, (byte) 0x29, (byte) 0x87, (byte) 0x01, (byte) 0x02, (byte) 0x50, (byte) 0x0C, (byte) 0x56, (byte) 0x49, (byte) 0x53, (byte) 0x41, (byte) 0x45, (byte) 0x4C, (byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x52, (byte) 0x4F, (byte) 0x4E, (byte) 0x9F, (byte) 0x38, (byte) 0x03, (byte) 0x9F, (byte) 0x1A, (byte) 0x02, (byte) 0x5F, (byte) 0x2D, (byte) 0x02, (byte) 0x70, (byte) 0x74, (byte) 0x9F, (byte) 0x11, (byte) 0x01, (byte) 0x01, (byte) 0x9F, (byte) 0x12, (byte) 0x06, (byte) 0x44, (byte) 0x45, (byte) 0x42, (byte) 0x49, (byte) 0x54, (byte) 0x4F, (byte) 0x87, (byte) 0x01, (byte) 0x02, (byte) 0x50, (byte) 0x0C, (byte) 0x56, (byte) 0x49, (byte) 0x53, (byte) 0x41, (byte) 0x45, (byte) 0x4C, (byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x52, (byte) 0x4F, (byte) 0x4E, (byte) 0x9F, (byte) 0x38, (byte) 0x03, (byte) 0x9F, (byte) 0x1A, (byte) 0x02, (byte) 0x5F, (byte) 0x2D, (byte) 0x02, (byte) 0x70, (byte) 0x74, (byte) 0x9F, (byte) 0x11, (byte) 0x01, (byte) 0x01, (byte) 0x9F, (byte) 0x12, (byte) 0x06, (byte) 0x44, (byte) 0x45, (byte) 0x42, (byte) 0x49, (byte) 0x54, (byte) 0x4F, (byte) 0x87, (byte) 0x01, (byte) 0x02, (byte) 0x50, (byte) 0x0C, (byte) 0x56, (byte) 0x49, (byte) 0x53, (byte) 0x41, (byte) 0x45, (byte) 0x4C, (byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x52, (byte) 0x4F, (byte) 0x4E, (byte) 0x9F, (byte) 0x38, (byte) 0x03, (byte) 0x9F, (byte) 0x1A, (byte) 0x02, (byte) 0x5F, (byte) 0x2D, (byte) 0x04, (byte) 0x70, (byte) 0x74, (byte) 0x65, (byte) 0x6E, (byte) 0x9F, (byte) 0x11, (byte) 0x01, (byte) 0x01, (byte) 0x9F, (byte) 0x12, (byte) 0x06, (byte) 0x44, (byte) 0x45, (byte) 0x42, (byte) 0x49, (byte) 0x54, (byte) 0x4F };
61 |
62 | public final static byte[] aip_afl = { (byte) 0x80, (byte) 0x0E,
63 | (byte) 0x5C, (byte) 0x00, (byte) 0x08, (byte) 0x01, (byte) 0x03,
64 | (byte) 0x00, (byte) 0x10, (byte) 0x01, (byte) 0x03, (byte) 0x02,
65 | (byte) 0x10, (byte) 0x04, (byte) 0x05, (byte) 0x01 }; // AIP
66 |
67 | /*
68 | * AIP - TAG 82 5800 (01011000) ---- 4000 SDA supported 1000 Cardholder
69 | * verification supported 0800 Terminal risk management is to be performed
70 | */
71 | public final short aip = (short) 0x5800;
72 |
73 | /*
74 | * AFL: TAG 94 For now, use a static / fixed AFL TODO: Change the AFL based
75 | * in the actual card data structure
76 | */
77 | public final static byte[] afl = {
78 | // 080101001001020018010201 = 08010100 10010200 18010201
79 | (byte) 0x08, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x10,
80 | (byte) 0x01, (byte) 0x02, (byte) 0x00, (byte) 0x18, (byte) 0x01,
81 | (byte) 0x02, (byte) 0x01 };
82 |
83 | // "THE" INS (E2). Append a record (SIMPLE-TLV data) to the end of an EF
84 | public static void appendRecord(byte p2, byte[] data) {
85 | /*
86 | * P2 = EF identifier in SFI format data = record to be appended
87 | */
88 |
89 | }
90 |
91 | public static void writeRecord(APDU apdu) {
92 | // For now, receives the data and writes it to the EF without any
93 | // validation
94 | byte[] buf = apdu.getBuffer();
95 | byte data = buf[ISO7816.OFFSET_CDATA];
96 |
97 | }
98 |
99 | public short getAIP() {
100 | return aip;
101 | }
102 |
103 | public void setAIP(short newAip) {
104 |
105 | }
106 |
107 | public static void selectFile() {
108 | // In theory, a direct select file (instead of an AID) is never used
109 | // When used, should select an EF / DF to read its information
110 | // Comercial EMV suport only the "native" SELECT command
111 | // TODO: Must return somenthing here but it cant be function not
112 | // supported since select is supported (but only and AID)
113 | }
114 |
115 | // TODO: Support only fixed size / quantity of EFs first
116 | public static void createFile() {
117 |
118 | }
119 |
120 | public static void readRecord(APDU apdu) {
121 | // TODO: Change this case to an array of EFs so we can address them by
122 | // position instead of switching
123 |
124 | /*
125 | * TODO: Se voce passa o read como 00B2010C o campo LE "nao existe" e o
126 | * bytesleft = 0, trigando o primeiro condicional do if se voce passa
127 | * qualquer outro campo (mesmo 00, que � "leia tudo que puder") o else �
128 | * trigado a unica forma de trigar bytesleft = 0 � NAO PASSANDO NADA, o
129 | * que � invalido (deveria ser considerado como passado 00 Ou seja:
130 | * colocado um 1 no if para sempre trigar o segundo, mas arrumar
131 | * corretamente para a le esperada
132 | */
133 |
134 | byte[] buf = apdu.getBuffer();
135 | short bytesLeft;
136 | short record = buf[ISO7816.OFFSET_P1];
137 | byte ef = (byte) ((buf[ISO7816.OFFSET_P2] ^ 4) >> 3);
138 |
139 | switch (ef) {
140 | case (byte) 0x01: // three records
141 | switch (record) {
142 | /*
143 | * CASE ANTIGO, ANTES N�O LIDO case (byte)0x01: //three records
144 | * switch (record) { case (byte) 0x01: bytesLeft =
145 | * apdu.setOutgoing(); if (bytesLeft == (short) 1) {
146 | * apdu.setOutgoingLength((short) 0); apdu.sendBytesLong
147 | * (ef01_r01,(short)0,(short)0); } else {
148 | * apdu.setOutgoingLength((short)ef01_r01.length);
149 | * apdu.sendBytesLong (ef01_r01,(short)0,(short)ef01_r01.length); }
150 | */
151 | case (byte) 0x01:
152 | bytesLeft = apdu.setOutgoing();
153 | apdu.setOutgoingLength((short) ef01_r01.length);
154 | apdu.sendBytesLong(ef01_r01, (short) 0, (short) ef01_r01.length);
155 |
156 | break;
157 | case (byte) 0x02:
158 | bytesLeft = apdu.setOutgoing();
159 | apdu.setOutgoingLength((short) ef01_r02.length);
160 | apdu.sendBytesLong(ef01_r02, (short) 0, (short) ef01_r02.length);
161 |
162 | break;
163 | case (byte) 0x03:
164 | bytesLeft = apdu.setOutgoing();
165 | apdu.setOutgoingLength((short) ef01_r03.length);
166 | apdu.sendBytesLong(ef01_r03, (short) 0, (short) ef01_r03.length);
167 |
168 | break;
169 | case (byte) 0x04:
170 | bytesLeft = apdu.setOutgoing();
171 | apdu.setOutgoingLength((short) ef01_r04.length);
172 | apdu.sendBytesLong(ef01_r04, (short) 0, (short) ef01_r04.length);
173 |
174 | break;
175 | case (byte) 0x05:
176 | bytesLeft = apdu.setOutgoing();
177 | apdu.setOutgoingLength((short) ef01_r05.length);
178 | apdu.sendBytesLong(ef01_r05, (short) 0, (short) ef01_r05.length);
179 |
180 | break;
181 | case (byte) 0x06:
182 | bytesLeft = apdu.setOutgoing();
183 | apdu.setOutgoingLength((short) ef01_r06.length);
184 | apdu.sendBytesLong(ef01_r06, (short) 0, (short) ef01_r06.length);
185 |
186 | break;
187 | }
188 | break;
189 |
190 | case (byte) 0x02: // five records
191 | switch (record) {
192 | case (byte) 0x01:
193 | bytesLeft = apdu.setOutgoing();
194 | apdu.setOutgoingLength((short) ef02_r01.length);
195 | apdu.sendBytesLong(ef02_r01, (short) 0, (short) ef02_r01.length);
196 | break;
197 | case (byte) 0x02:
198 | bytesLeft = apdu.setOutgoing();
199 | apdu.setOutgoingLength((short) ef02_r02.length);
200 | apdu.sendBytesLong(ef02_r02, (short) 0, (short) ef02_r02.length);
201 | break;
202 | case (byte) 0x03:
203 | bytesLeft = apdu.setOutgoing();
204 | apdu.setOutgoingLength((short) ef02_r03.length);
205 | apdu.sendBytesLong(ef02_r03, (short) 0, (short) ef02_r03.length);
206 |
207 | break;
208 | case (byte) 0x04:
209 | bytesLeft = apdu.setOutgoing();
210 | apdu.setOutgoingLength((short) ef02_r04.length);
211 | apdu.sendBytesLong(ef02_r04, (short) 0, (short) ef02_r04.length);
212 |
213 | break;
214 | case (byte) 0x05:
215 | bytesLeft = apdu.setOutgoing();
216 | apdu.setOutgoingLength((short) ef02_r05.length);
217 | apdu.sendBytesLong(ef02_r05, (short) 0, (short) ef02_r05.length);
218 |
219 | break;
220 | case (byte) 0x06:
221 | bytesLeft = apdu.setOutgoing();
222 | apdu.setOutgoingLength((short) ef02_r06.length);
223 | apdu.sendBytesLong(ef02_r06, (short) 0, (short) ef02_r06.length);
224 |
225 | break;
226 | case (byte) 0x07:
227 | bytesLeft = apdu.setOutgoing();
228 | apdu.setOutgoingLength((short) ef02_r07.length);
229 | apdu.sendBytesLong(ef02_r07, (short) 0, (short) ef02_r07.length);
230 |
231 | break;
232 |
233 | case (byte) 0x08:
234 | bytesLeft = apdu.setOutgoing();
235 | apdu.setOutgoingLength((short) ef02_r08.length);
236 | apdu.sendBytesLong(ef02_r08, (short) 0, (short) ef02_r08.length);
237 |
238 | break;
239 |
240 | case (byte) 0x09:
241 | bytesLeft = apdu.setOutgoing();
242 | apdu.setOutgoingLength((short) ef02_r09.length);
243 | apdu.sendBytesLong(ef02_r09, (short) 0, (short) ef02_r09.length);
244 |
245 | break;
246 | }
247 |
248 | break;
249 | case (byte) 0x04: // mostra o pan
250 | bytesLeft = apdu.setOutgoing();
251 | apdu.setOutgoingLength((short) ef04_r01.length);
252 | apdu.sendBytesLong(ef04_r01, (short) 0, (short) ef04_r01.length);
253 |
254 | break;
255 | }
256 |
257 | /*
258 | * try { bytesLeft = apdu.setOutgoing(); if (bytesLeft == (short) 0) {
259 | * apdu.setOutgoingLength((short) 0); apdu.sendBytesLong
260 | * (fs[ef][record],(short)0,(short)0); } else {
261 | * apdu.setOutgoingLength((short)fs[ef][record].length);
262 | * apdu.sendBytesLong
263 | * (fs[ef][record],(short)0,(short)fs[ef][record].length); } } catch
264 | * (Exception e) { ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND); }
265 | */
266 |
267 | /*
268 | * switch (buf[ISO7816.OFFSET_P1]) { case (byte) 0x01: bytesLeft =
269 | * apdu.setOutgoing(); if (bytesLeft == (short) 1) {
270 | * apdu.setOutgoingLength((short) 0); apdu.sendBytesLong
271 | * (ef01_r01,(short)0,(short)0); } else {
272 | * apdu.setOutgoingLength((short)ef01_r01.length); apdu.sendBytesLong
273 | * (ef01_r01,(short)0,(short)ef01_r01.length); } break;
274 | *
275 | * case (short) 0x02: bytesLeft = apdu.setOutgoing(); if (bytesLeft ==
276 | * (short) 1) { apdu.setOutgoingLength((short) 0); apdu.sendBytesLong
277 | * (ef01_r02,(short)0,(short)0); } else {
278 | * apdu.setOutgoingLength((short)ef01_r02.length); apdu.sendBytesLong
279 | * (ef01_r02,(short)0,(short)ef01_r02.length); } break; case (short)
280 | * 0x03: bytesLeft = apdu.setOutgoing(); if (bytesLeft == (short) 1) {
281 | * apdu.setOutgoingLength((short) 0); apdu.sendBytesLong
282 | * (ef01_r03,(short)0,(short)0); } else {
283 | * apdu.setOutgoingLength((short)ef01_r03.length); apdu.sendBytesLong
284 | * (ef01_r03,(short)0,(short)ef01_r03.length); } break; case (short)
285 | * 0x04: bytesLeft = apdu.setOutgoing(); if (bytesLeft == (short) 1) {
286 | * apdu.setOutgoingLength((short) 0); apdu.sendBytesLong
287 | * (ef01_r04,(short)0,(short)0); } else {
288 | * apdu.setOutgoingLength((short)ef01_r04.length); apdu.sendBytesLong
289 | * (ef01_r04,(short)0,(short)ef01_r04.length); } break; case (short)
290 | * 0x05: bytesLeft = apdu.setOutgoing(); if (bytesLeft == (short) 1) {
291 | * apdu.setOutgoingLength((short) 0); apdu.sendBytesLong
292 | * (ef01_r05,(short)0,(short)0); } else {
293 | * apdu.setOutgoingLength((short)ef01_r05.length); apdu.sendBytesLong
294 | * (ef01_r05,(short)0,(short)ef01_r05.length); } break; case (short)
295 | * 0x06: bytesLeft = apdu.setOutgoing(); if (bytesLeft == (short) 1) {
296 | * apdu.setOutgoingLength((short) 0); apdu.sendBytesLong
297 | * (ef01_r06,(short)0,(short)0); } else {
298 | * apdu.setOutgoingLength((short)ef01_r06.length); apdu.sendBytesLong
299 | * (ef01_r06,(short)0,(short)ef01_r06.length); } break; default:
300 | * ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); }
301 | */
302 | }
303 |
304 | public short getCDOL2DataLength() {
305 | // TODO Check DOL Length Dinamically (TAG / LENGTH - no value)
306 | return 0x11; // 17 bytes
307 | }
308 |
309 | public short getCDOL1DataLength() {
310 | // TODO Check DOL Length Dinamically (TAG / LENGTH - no value)
311 | return 0x20; // 32 bytes
312 | }
313 | }
--------------------------------------------------------------------------------