]>
Commit | Line | Data |
---|---|---|
1 | //----------------------------------------------------------------------------- | |
2 | // Copyright (C) 2014 Peter Fillmore | |
3 | // 2017 iceman | |
4 | // | |
5 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, | |
6 | // at your option, any later version. See the LICENSE.txt file for the text of | |
7 | // the license. | |
8 | //----------------------------------------------------------------------------- | |
9 | // High frequency EMV commands | |
10 | //----------------------------------------------------------------------------- | |
11 | #include "cmdhfemv.h" | |
12 | ||
13 | static int CmdHelp(const char *Cmd); | |
14 | ||
15 | int usage_hf_emv_test(void){ | |
16 | PrintAndLog("EMV test "); | |
17 | PrintAndLog("Usage: hf emv test [h]"); | |
18 | PrintAndLog("Options:"); | |
19 | PrintAndLog(" h : this help"); | |
20 | PrintAndLog(""); | |
21 | PrintAndLog("Samples:"); | |
22 | PrintAndLog(" hf emv test"); | |
23 | return 0; | |
24 | } | |
25 | int usage_hf_emv_readrecord(void){ | |
26 | PrintAndLog("Read a EMV record "); | |
27 | PrintAndLog("Usage: hf emv readrecord [h] <records> <sfi>"); | |
28 | PrintAndLog("Options:"); | |
29 | PrintAndLog(" h : this help"); | |
30 | PrintAndLog(" <records> : number of records"); | |
31 | PrintAndLog(" <sfi> : number of SFI records"); | |
32 | PrintAndLog(""); | |
33 | PrintAndLog("Samples:"); | |
34 | PrintAndLog(" hf emv readrecord 1 1"); | |
35 | return 0; | |
36 | } | |
37 | int usage_hf_emv_clone(void){ | |
38 | PrintAndLog("Usage: hf emv clone [h] <records> <SFI> "); | |
39 | PrintAndLog("Options:"); | |
40 | PrintAndLog(" h : this help"); | |
41 | PrintAndLog(" <records> : number of records"); | |
42 | PrintAndLog(" <sfi> : number of SFI records"); | |
43 | PrintAndLog(""); | |
44 | PrintAndLog("Samples:"); | |
45 | PrintAndLog(" hf emv clone 10 10"); | |
46 | return 0; | |
47 | } | |
48 | int usage_hf_emv_transaction(void){ | |
49 | PrintAndLog("Performs EMV reader transaction"); | |
50 | PrintAndLog("Usage: hf emv trans [h]"); | |
51 | PrintAndLog("Options:"); | |
52 | PrintAndLog(" h : this help"); | |
53 | PrintAndLog(""); | |
54 | PrintAndLog("Samples:"); | |
55 | PrintAndLog(" hf emv trans"); | |
56 | return 0; | |
57 | } | |
58 | int usage_hf_emv_getrnd(void){ | |
59 | PrintAndLog("retrieve the UN number from a terminal"); | |
60 | PrintAndLog("Usage: hf emv getrnd [h]"); | |
61 | PrintAndLog("Options:"); | |
62 | PrintAndLog(" h : this help"); | |
63 | PrintAndLog(""); | |
64 | PrintAndLog("Samples:"); | |
65 | PrintAndLog(" hf emv getrnd"); | |
66 | return 0; | |
67 | } | |
68 | int usage_hf_emv_eload(void){ | |
69 | PrintAndLog("set EMV tags in the device to use in a transaction"); | |
70 | PrintAndLog("Usage: hf emv eload [h] o <filename w/o .bin>"); | |
71 | PrintAndLog("Options:"); | |
72 | PrintAndLog(" h : this help"); | |
73 | PrintAndLog(" o <filename> : filename w/o '.bin'"); | |
74 | PrintAndLog(""); | |
75 | PrintAndLog("Samples:"); | |
76 | PrintAndLog(" hf emv eload o myfile"); | |
77 | return 0; | |
78 | } | |
79 | int usage_hf_emv_dump(void){ | |
80 | PrintAndLog("Gets EMV contactless tag values."); | |
81 | PrintAndLog("and saves binary dump into the file `filename.bin` or `cardUID.bin`"); | |
82 | PrintAndLog("Usage: hf emv dump [h] o <filename w/o .bin>"); | |
83 | PrintAndLog("Options:"); | |
84 | PrintAndLog(" h : this help"); | |
85 | PrintAndLog(" o <filename> : filename w/o '.bin' to dump bytes"); | |
86 | PrintAndLog(""); | |
87 | PrintAndLog("Samples:"); | |
88 | PrintAndLog(" hf emv dump"); | |
89 | PrintAndLog(" hf emv dump o myfile"); | |
90 | return 0; | |
91 | } | |
92 | int usage_hf_emv_sim(void){ | |
93 | PrintAndLog("Simulates a EMV contactless card"); | |
94 | PrintAndLog("Usage: hf emv sim [h]"); | |
95 | PrintAndLog("Options:"); | |
96 | PrintAndLog(" h : this help"); | |
97 | PrintAndLog(""); | |
98 | PrintAndLog("Samples:"); | |
99 | PrintAndLog(" hf emv sim"); | |
100 | return 0; | |
101 | } | |
102 | ||
103 | int CmdHfEmvTest(const char *Cmd) { | |
104 | char cmdp = param_getchar(Cmd, 0); | |
105 | if ( cmdp == 'h' || cmdp == 'H') return usage_hf_emv_test(); | |
106 | ||
107 | UsbCommand c = {CMD_EMV_TEST, {0, 0, 0}}; | |
108 | clearCommandBuffer(); | |
109 | SendCommand(&c); | |
110 | UsbCommand resp; | |
111 | if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { | |
112 | PrintAndLog("Command execute time-out"); | |
113 | return 1; | |
114 | } | |
115 | uint8_t isOK = resp.arg[0] & 0xff; | |
116 | PrintAndLog("isOk: %02x", isOK); | |
117 | return 0; | |
118 | } | |
119 | ||
120 | int CmdHfEmvReadRecord(const char *Cmd) { | |
121 | char cmdp = param_getchar(Cmd, 0); | |
122 | if ((strlen(Cmd)<3) || cmdp == 'h' || cmdp == 'H') return usage_hf_emv_readrecord(); | |
123 | ||
124 | uint8_t record = param_get8(Cmd, 0); | |
125 | uint8_t sfi = param_getchar(Cmd, 1); | |
126 | if(record > 32){ | |
127 | PrintAndLog("Record must be less than 32"); | |
128 | return 1; | |
129 | } | |
130 | PrintAndLog("--record no:%02x SFI:%02x ", record, sfi); | |
131 | ||
132 | UsbCommand c = {CMD_EMV_READ_RECORD, {record, sfi, 0}}; | |
133 | clearCommandBuffer(); | |
134 | SendCommand(&c); | |
135 | UsbCommand resp; | |
136 | if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { | |
137 | PrintAndLog("Command execute timeout"); | |
138 | return 1; | |
139 | } | |
140 | uint8_t isOK = resp.arg[0] & 0xff; | |
141 | PrintAndLog("isOk:%02x", isOK); | |
142 | return 0; | |
143 | } | |
144 | ||
145 | int CmdHfEmvClone(const char *Cmd) { | |
146 | char cmdp = param_getchar(Cmd, 0); | |
147 | if ((strlen(Cmd)<3) || cmdp == 'h' || cmdp == 'H') return usage_hf_emv_clone(); | |
148 | ||
149 | uint8_t record = param_get8(Cmd, 0); | |
150 | uint8_t sfi = param_get8(Cmd, 1); | |
151 | if(record > 32){ | |
152 | PrintAndLog("Record must be less than 32"); | |
153 | return 1; | |
154 | } | |
155 | UsbCommand c = {CMD_EMV_CLONE, {sfi, record, 0}}; | |
156 | clearCommandBuffer(); | |
157 | SendCommand(&c); | |
158 | UsbCommand resp; | |
159 | if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { | |
160 | PrintAndLog("Command execute timeout"); | |
161 | return 1; | |
162 | } | |
163 | uint8_t isOK = resp.arg[0] & 0xff; | |
164 | PrintAndLog("isOk:%02x", isOK); | |
165 | return 0; | |
166 | } | |
167 | ||
168 | int CmdHfEmvTrans(const char *Cmd) { | |
169 | char cmdp = param_getchar(Cmd, 0); | |
170 | if ( cmdp == 'h' || cmdp == 'H') return usage_hf_emv_transaction(); | |
171 | ||
172 | UsbCommand c = {CMD_EMV_TRANSACTION, {0, 0, 0}}; | |
173 | clearCommandBuffer(); | |
174 | SendCommand(&c); | |
175 | UsbCommand resp; | |
176 | if (WaitForResponseTimeout(CMD_ACK, &resp, 5000)) { | |
177 | PrintAndLog("Command execute time-out"); | |
178 | return 1; | |
179 | } | |
180 | uint8_t isOK = resp.arg[0] & 0xff; | |
181 | PrintAndLog("isOk: %02x", isOK); | |
182 | print_hex_break(resp.d.asBytes, 512, 32); | |
183 | return 0; | |
184 | } | |
185 | //retrieve the UN number from a terminal | |
186 | int CmdHfEmvGetrng(const char *Cmd) { | |
187 | char cmdp = param_getchar(Cmd, 0); | |
188 | if ( cmdp == 'h' || cmdp == 'H') return usage_hf_emv_getrnd(); | |
189 | UsbCommand c = {CMD_EMV_GET_RANDOM_NUM, {0, 0, 0}}; | |
190 | clearCommandBuffer(); | |
191 | SendCommand(&c); | |
192 | return 0; | |
193 | } | |
194 | //Load a dumped EMV tag on to emulator memory | |
195 | int CmdHfEmvELoad(const char *Cmd) { | |
196 | FILE * f; | |
197 | char filename[FILE_PATH_SIZE]; | |
198 | char *fnameptr = filename; | |
199 | int len; | |
200 | bool errors = false; | |
201 | uint8_t cmdp = 0; | |
202 | ||
203 | while(param_getchar(Cmd, cmdp) != 0x00) { | |
204 | switch(param_getchar(Cmd, cmdp)) { | |
205 | case 'h': | |
206 | case 'H': | |
207 | return usage_hf_emv_eload(); | |
208 | case 'o': | |
209 | case 'O': | |
210 | len = param_getstr(Cmd, cmdp+1, filename); | |
211 | if (!len) | |
212 | errors = true; | |
213 | if (len > FILE_PATH_SIZE-5) | |
214 | len = FILE_PATH_SIZE-5; | |
215 | sprintf(fnameptr + len,".bin"); | |
216 | cmdp += 2; | |
217 | break; | |
218 | default: | |
219 | PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); | |
220 | errors = true; | |
221 | break; | |
222 | } | |
223 | if(errors) break; | |
224 | } | |
225 | ||
226 | //Validations | |
227 | if(errors) return usage_hf_emv_eload(); | |
228 | ||
229 | // open file | |
230 | f = fopen(filename,"r"); | |
231 | if (!f) { | |
232 | PrintAndLog("File %s not found or locked", filename); | |
233 | return 1; | |
234 | } | |
235 | ||
236 | char line[512]; | |
237 | char *token; | |
238 | uint16_t tag; | |
239 | ||
240 | UsbCommand c = {CMD_EMV_LOAD_VALUE, {0,0,0}}; | |
241 | ||
242 | // transfer to device | |
243 | while (fgets(line, sizeof (line), f)) { | |
244 | printf("LINE = %s\n", line); | |
245 | ||
246 | token = strtok(line, ":"); | |
247 | tag = (uint16_t)strtol(token, NULL, 0); | |
248 | token = strtok(NULL,""); | |
249 | ||
250 | c.arg[0] = tag; | |
251 | memcpy(c.d.asBytes, token, strlen(token)); | |
252 | ||
253 | clearCommandBuffer(); | |
254 | SendCommand(&c); | |
255 | ||
256 | printf("Loaded TAG = %04x\n", tag); | |
257 | printf("Loaded VALUE = %s\n", token); | |
258 | } | |
259 | ||
260 | fclose(f); | |
261 | PrintAndLog("loaded %s", filename); | |
262 | //PrintAndLog("\nLoaded %d bytes from file: %s to emulator memory", numofbytes, filename); | |
263 | return 0; | |
264 | } | |
265 | ||
266 | int CmdHfEmvDump(const char *Cmd){ | |
267 | ||
268 | bool errors = false; | |
269 | uint8_t cmdp = 0; | |
270 | while(param_getchar(Cmd, cmdp) != 0x00) { | |
271 | switch(param_getchar(Cmd, cmdp)) { | |
272 | case 'h': | |
273 | case 'H': | |
274 | return usage_hf_emv_dump(); | |
275 | default: | |
276 | PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); | |
277 | errors = true; | |
278 | break; | |
279 | } | |
280 | if(errors) break; | |
281 | } | |
282 | ||
283 | //Validations | |
284 | if(errors) return usage_hf_emv_dump(); | |
285 | ||
286 | UsbCommand c = {CMD_EMV_DUMP_CARD, {0, 0, 0}}; | |
287 | clearCommandBuffer(); | |
288 | SendCommand(&c); | |
289 | UsbCommand resp; | |
290 | if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) { | |
291 | PrintAndLog("Command execute time-out"); | |
292 | return 1; | |
293 | } | |
294 | return 0; | |
295 | } | |
296 | ||
297 | int CmdHfEmvSim(const char *Cmd) { | |
298 | ||
299 | bool errors = false; | |
300 | uint8_t cmdp = 0; | |
301 | while(param_getchar(Cmd, cmdp) != 0x00) { | |
302 | switch(param_getchar(Cmd, cmdp)) { | |
303 | case 'h': | |
304 | case 'H': | |
305 | return usage_hf_emv_sim(); | |
306 | default: | |
307 | PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); | |
308 | errors = true; | |
309 | break; | |
310 | } | |
311 | if(errors) break; | |
312 | } | |
313 | ||
314 | //Validations | |
315 | if(errors) return usage_hf_emv_sim(); | |
316 | ||
317 | UsbCommand c = {CMD_EMV_SIM, {0,0,0}}; | |
318 | clearCommandBuffer(); | |
319 | SendCommand(&c); | |
320 | UsbCommand resp; | |
321 | if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { | |
322 | PrintAndLog("Command execute time-out"); | |
323 | return 1; | |
324 | } | |
325 | uint8_t isOK = resp.arg[0] & 0xff; | |
326 | PrintAndLog("isOk:%02x", isOK); | |
327 | return 0; | |
328 | } | |
329 | ||
330 | int CmdHfEmvList(const char *Cmd) { | |
331 | return CmdHFList("7816"); | |
332 | } | |
333 | ||
334 | static command_t CommandTable[] = { | |
335 | {"help", CmdHelp, 1, "This help"}, | |
336 | {"readrecord", CmdHfEmvReadRecord, 0, "EMV Read Record"}, | |
337 | {"transaction", CmdHfEmvTrans, 0, "Perform EMV Transaction"}, | |
338 | {"getrng", CmdHfEmvGetrng, 0, "get random number from terminal"}, | |
339 | {"eload", CmdHfEmvELoad, 0, "load EMV tag into device"}, | |
340 | {"dump", CmdHfEmvDump, 0, "dump EMV tag values"}, | |
341 | {"sim", CmdHfEmvSim, 0, "simulate EMV tag"}, | |
342 | {"clone", CmdHfEmvClone, 0, "clone an EMV tag"}, | |
343 | {"list", CmdHfEmvList, 0, "[Deprecated] List ISO7816 history"}, | |
344 | {"test", CmdHfEmvTest, 0, "Test Function"}, | |
345 | {NULL, NULL, 0, NULL} | |
346 | }; | |
347 | ||
348 | int CmdHFEmv(const char *Cmd) { | |
349 | clearCommandBuffer(); | |
350 | CmdsParse(CommandTable, Cmd); | |
351 | return 0; | |
352 | } | |
353 | ||
354 | int CmdHelp(const char *Cmd) { | |
355 | CmdsHelp(CommandTable); | |
356 | return 0; | |
357 | } |