cee5a30d |
1 | //----------------------------------------------------------------------------- |
2 | // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch |
3 | // Copyright (C) 2011 Gerhard de Koning Gans |
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 iClass commands |
10 | //----------------------------------------------------------------------------- |
11 | |
12 | #include <stdio.h> |
13 | #include <stdlib.h> |
14 | #include <string.h> |
15 | #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type |
16 | #include "data.h" |
28fdb04f |
17 | //#include "proxusb.h" |
902cb3c0 |
18 | #include "proxmark3.h" |
cee5a30d |
19 | #include "ui.h" |
20 | #include "cmdparser.h" |
21 | #include "cmdhficlass.h" |
22 | #include "common.h" |
14006804 |
23 | #include "util.h" |
cee5a30d |
24 | |
25 | static int CmdHelp(const char *Cmd); |
26 | |
27 | int CmdHFiClassList(const char *Cmd) |
28 | { |
29 | uint8_t got[1920]; |
db09cb3a |
30 | GetFromBigBuf(got,sizeof(got),0); |
cee5a30d |
31 | |
32 | PrintAndLog("recorded activity:"); |
33 | PrintAndLog(" ETU :rssi: who bytes"); |
34 | PrintAndLog("---------+----+----+-----------"); |
35 | |
36 | int i = 0; |
37 | int prev = -1; |
38 | |
39 | for (;;) { |
40 | if(i >= 1900) { |
41 | break; |
42 | } |
43 | |
44 | bool isResponse; |
45 | int timestamp = *((uint32_t *)(got+i)); |
46 | if (timestamp & 0x80000000) { |
47 | timestamp &= 0x7fffffff; |
48 | isResponse = 1; |
49 | } else { |
50 | isResponse = 0; |
51 | } |
52 | |
53 | int metric = 0; |
54 | int parityBits = *((uint32_t *)(got+i+4)); |
55 | // 4 bytes of additional information... |
56 | // maximum of 32 additional parity bit information |
57 | // |
58 | // TODO: |
59 | // at each quarter bit period we can send power level (16 levels) |
60 | // or each half bit period in 256 levels. |
61 | |
62 | |
63 | int len = got[i+8]; |
64 | |
65 | if (len > 100) { |
66 | break; |
67 | } |
68 | if (i + len >= 1900) { |
69 | break; |
70 | } |
71 | |
72 | uint8_t *frame = (got+i+9); |
73 | |
74 | // Break and stick with current result if buffer was not completely full |
75 | if (frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; } |
76 | |
77 | char line[1000] = ""; |
78 | int j; |
79 | for (j = 0; j < len; j++) { |
80 | int oddparity = 0x01; |
81 | int k; |
82 | |
83 | for (k=0;k<8;k++) { |
84 | oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); |
85 | } |
86 | |
87 | //if((parityBits >> (len - j - 1)) & 0x01) { |
88 | if (isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) { |
89 | sprintf(line+(j*4), "%02x! ", frame[j]); |
90 | } |
91 | else { |
92 | sprintf(line+(j*4), "%02x ", frame[j]); |
93 | } |
94 | } |
95 | |
96 | char *crc; |
97 | crc = ""; |
98 | if (len > 2) { |
99 | uint8_t b1, b2; |
100 | for (j = 0; j < (len - 1); j++) { |
101 | // gives problems... search for the reason.. |
102 | /*if(frame[j] == 0xAA) { |
103 | switch(frame[j+1]) { |
104 | case 0x01: |
105 | crc = "[1] Two drops close after each other"; |
106 | break; |
107 | case 0x02: |
108 | crc = "[2] Potential SOC with a drop in second half of bitperiod"; |
109 | break; |
110 | case 0x03: |
111 | crc = "[3] Segment Z after segment X is not possible"; |
112 | break; |
113 | case 0x04: |
114 | crc = "[4] Parity bit of a fully received byte was wrong"; |
115 | break; |
116 | default: |
117 | crc = "[?] Unknown error"; |
118 | break; |
119 | } |
120 | break; |
121 | }*/ |
122 | } |
123 | |
124 | if (strlen(crc)==0) { |
125 | if(!isResponse && len == 4) { |
126 | // Rough guess that this is a command from the reader |
127 | // For iClass the command byte is not part of the CRC |
128 | ComputeCrc14443(CRC_ICLASS, &frame[1], len-3, &b1, &b2); |
129 | } |
130 | else { |
131 | // For other data.. CRC might not be applicable (UPDATE commands etc.) |
132 | ComputeCrc14443(CRC_ICLASS, frame, len-2, &b1, &b2); |
133 | } |
134 | //printf("%1x %1x",(unsigned)b1,(unsigned)b2); |
135 | if (b1 != frame[len-2] || b2 != frame[len-1]) { |
136 | crc = (isResponse & (len < 8)) ? "" : " !crc"; |
137 | } else { |
138 | crc = ""; |
139 | } |
140 | } |
141 | } else { |
142 | crc = ""; // SHORT |
143 | } |
144 | |
145 | char metricString[100]; |
146 | if (isResponse) { |
147 | sprintf(metricString, "%3d", metric); |
148 | } else { |
149 | strcpy(metricString, " "); |
150 | } |
151 | |
152 | PrintAndLog(" +%7d: %s: %s %s %s", |
153 | (prev < 0 ? 0 : (timestamp - prev)), |
154 | metricString, |
155 | (isResponse ? "TAG" : " "), line, crc); |
156 | |
157 | prev = timestamp; |
158 | i += (len + 9); |
159 | } |
160 | return 0; |
161 | } |
162 | |
163 | /*void iso14a_set_timeout(uint32_t timeout) { |
164 | UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_SET_TIMEOUT, 0, timeout}}; |
165 | SendCommand(&c); |
166 | }*/ |
167 | |
168 | int CmdHFiClassSnoop(const char *Cmd) |
169 | { |
170 | UsbCommand c = {CMD_SNOOP_ICLASS}; |
171 | SendCommand(&c); |
172 | return 0; |
173 | } |
174 | |
1e262141 |
175 | int CmdHFiClassSim(const char *Cmd) |
176 | { |
177 | uint8_t simType = 0; |
178 | uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0}; |
179 | |
180 | if (strlen(Cmd)<2) { |
181 | PrintAndLog("Usage: hf iclass sim <sim type> <CSN (16 hex symbols)>"); |
182 | PrintAndLog(" sample: hf iclass sim 0 031FEC8AF7FF12E0"); |
183 | return 0; |
184 | } |
185 | |
186 | simType = param_get8(Cmd, 0); |
187 | if (param_gethex(Cmd, 1, CSN, 16)) { |
188 | PrintAndLog("A CSN should consist of 16 HEX symbols"); |
189 | return 1; |
190 | } |
191 | PrintAndLog("--simtype:%02x csn:%s", simType, sprint_hex(CSN, 8)); |
192 | |
193 | UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType}}; |
194 | memcpy(c.d.asBytes, CSN, 8); |
195 | SendCommand(&c); |
196 | |
197 | /*UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); |
198 | if (resp != NULL) { |
199 | uint8_t isOK = resp->arg[0] & 0xff; |
200 | PrintAndLog("isOk:%02x", isOK); |
201 | } else { |
202 | PrintAndLog("Command execute timeout"); |
203 | }*/ |
204 | |
205 | return 0; |
206 | } |
207 | |
208 | int CmdHFiClassReader(const char *Cmd) |
209 | { |
210 | uint8_t readerType = 0; |
211 | |
212 | if (strlen(Cmd)<1) { |
213 | PrintAndLog("Usage: hf iclass reader <reader type>"); |
214 | PrintAndLog(" sample: hf iclass reader 0"); |
215 | return 0; |
216 | } |
217 | |
218 | readerType = param_get8(Cmd, 0); |
219 | PrintAndLog("--readertype:%02x", readerType); |
220 | |
221 | UsbCommand c = {CMD_READER_ICLASS, {readerType}}; |
222 | //memcpy(c.d.asBytes, CSN, 8); |
223 | SendCommand(&c); |
224 | |
225 | /*UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); |
226 | if (resp != NULL) { |
227 | uint8_t isOK = resp->arg[0] & 0xff; |
228 | PrintAndLog("isOk:%02x", isOK); |
229 | } else { |
230 | PrintAndLog("Command execute timeout"); |
231 | }*/ |
232 | |
233 | return 0; |
234 | } |
235 | |
cee5a30d |
236 | static command_t CommandTable[] = |
237 | { |
238 | {"help", CmdHelp, 1, "This help"}, |
239 | {"list", CmdHFiClassList, 0, "List iClass history"}, |
240 | {"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"}, |
1e262141 |
241 | {"sim", CmdHFiClassSim, 0, "Simulate iClass tag"}, |
242 | {"reader", CmdHFiClassReader, 0, "Read an iClass tag"}, |
cee5a30d |
243 | {NULL, NULL, 0, NULL} |
244 | }; |
245 | |
246 | int CmdHFiClass(const char *Cmd) |
247 | { |
248 | CmdsParse(CommandTable, Cmd); |
249 | return 0; |
250 | } |
251 | |
252 | int CmdHelp(const char *Cmd) |
253 | { |
254 | CmdsHelp(CommandTable); |
255 | return 0; |
256 | } |