1
|
/***************************************************************
|
2
|
*
|
3
|
* OpenPICC - ISO 14443 Layer 3 response pretender,
|
4
|
* proof of concept
|
5
|
*
|
6
|
* Copyright 2008 Henryk Plötz <henryk@ploetzli.ch>
|
7
|
*
|
8
|
***************************************************************
|
9
|
|
10
|
This program is free software; you can redistribute it and/or modify
|
11
|
it under the terms of the GNU General Public License as published by
|
12
|
the Free Software Foundation; version 2.
|
13
|
|
14
|
This program is distributed in the hope that it will be useful,
|
15
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
GNU General Public License for more details.
|
18
|
|
19
|
You should have received a copy of the GNU General Public License along
|
20
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
21
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
22
|
|
23
|
*/
|
24
|
|
25
|
#include <FreeRTOS.h>
|
26
|
#include <board.h>
|
27
|
#include <task.h>
|
28
|
#include <errno.h>
|
29
|
#include <string.h>
|
30
|
#include <stdlib.h>
|
31
|
|
32
|
#include "openpicc.h"
|
33
|
#include "ssc_buffer.h"
|
34
|
#include "iso14443.h"
|
35
|
#include "iso14443_layer2a.h"
|
36
|
#include "iso14443a_pretender.h"
|
37
|
#include "iso14443a_manchester.h"
|
38
|
#include "usb_print.h"
|
39
|
#include "cmd.h"
|
40
|
extern volatile int fdt_offset;
|
41
|
#include "led.h"
|
42
|
|
43
|
struct challenge_response {
|
44
|
u_int8_t UID[5];
|
45
|
u_int8_t nonce[4];
|
46
|
u_int8_t waiting_for_response;
|
47
|
struct {
|
48
|
u_int8_t data[8];
|
49
|
u_int8_t parity[2];
|
50
|
size_t len;
|
51
|
} response;
|
52
|
};
|
53
|
|
54
|
struct challenge_response challenge_response;
|
55
|
|
56
|
static const iso14443_frame ATQA_FRAME = {
|
57
|
TYPE_A,
|
58
|
FRAME_PREFILLED,
|
59
|
{{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE, CRC_UNCALCULATED}},
|
60
|
2,
|
61
|
0, 0,
|
62
|
{4, 0},
|
63
|
{}
|
64
|
};
|
65
|
|
66
|
static const iso14443_frame ATS_FRAME = {
|
67
|
TYPE_A,
|
68
|
FRAME_PREFILLED,
|
69
|
{{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE, CRC_UNCALCULATED}},
|
70
|
3,
|
71
|
0, 0,
|
72
|
{0x08, 0xB6, 0xDD},
|
73
|
{}
|
74
|
};
|
75
|
|
76
|
static iso14443_frame UID_FRAME, NONCE_FRAME;
|
77
|
//static u_int8_t UID[] = {0xF4, 0xAC, 0xF9, 0xD7}; // bcc = 0x76
|
78
|
static u_int8_t UID[] = {0x00, 0x00, 0x00, 0x00};
|
79
|
static u_int8_t nonce[] = {0x00, 0x00, 0x00, 0x00};
|
80
|
|
81
|
#define FRAME_SIZE(bytes) (2* (1+(9*bytes)+1) )
|
82
|
#define BYTES_AND_BITS(bytes,bits) (bytes*9+bits)
|
83
|
#define GET_BASE_SIZE(type) ((size_t) &(((type*)0)->data))
|
84
|
|
85
|
static ssc_dma_tx_buffer_t *ATQA_BUFFER, *UID_BUFFER, *ATS_BUFFER, *NONCE_BUFFER;
|
86
|
|
87
|
static ssc_dma_tx_buffer_t *alloc_buffer_for_frame(const iso14443_frame *frame)
|
88
|
{
|
89
|
int datalen = FRAME_SIZE( BYTES_AND_BITS(frame->numbytes, frame->numbits) );
|
90
|
ssc_dma_tx_buffer_t *dst = pvPortMalloc( GET_BASE_SIZE(typeof(*dst)) + datalen );
|
91
|
if(dst == NULL) return NULL;
|
92
|
dst->len = datalen;
|
93
|
return dst;
|
94
|
}
|
95
|
|
96
|
static void fast_receive_callback(ssc_dma_rx_buffer_t *buffer, iso14443_frame *frame, u_int8_t in_irq)
|
97
|
{
|
98
|
(void)buffer; (void)in_irq;
|
99
|
u_int32_t cv = *AT91C_TC2_CV;
|
100
|
|
101
|
ssc_dma_tx_buffer_t *tx_buffer=NULL;
|
102
|
int fdt = 0;
|
103
|
|
104
|
switch(frame->parameters.a.last_bit) {
|
105
|
case ISO14443A_LAST_BIT_0:
|
106
|
fdt = 20;
|
107
|
break;
|
108
|
case ISO14443A_LAST_BIT_1:
|
109
|
fdt = 84;
|
110
|
break;
|
111
|
case ISO14443A_LAST_BIT_NONE:
|
112
|
fdt = 0;
|
113
|
break;
|
114
|
}
|
115
|
|
116
|
|
117
|
if(cv < 870) /* Anticollision is time-critical, do not even try to send if we're too late anyway */
|
118
|
switch(BYTES_AND_BITS(frame->numbytes,frame->numbits)) {
|
119
|
case BYTES_AND_BITS(0, 7): /* REQA or WUPA (7 bits) */
|
120
|
if(frame->data[0] == 0x26 || frame->data[0] == 0x52)
|
121
|
tx_buffer = ATQA_BUFFER;
|
122
|
fdt += 9*128;
|
123
|
break;
|
124
|
case BYTES_AND_BITS(2, 0): /* ANTICOL (2 bytes) */
|
125
|
if(frame->data[0] == 0x93 && frame->data[1] == 0x20)
|
126
|
tx_buffer = UID_BUFFER;
|
127
|
fdt += 9*128;
|
128
|
break;
|
129
|
case BYTES_AND_BITS(9, 0): /* SELECT (9 bytes) */
|
130
|
if(frame->data[0] == 0x93 && frame->data[1] == 0x70 && frame->parameters.a.crc &&
|
131
|
( *((u_int32_t*)&frame->data[2]) == *((u_int32_t*)&UID) ) )
|
132
|
tx_buffer = ATS_BUFFER;
|
133
|
fdt += 9*128;
|
134
|
break;
|
135
|
}
|
136
|
|
137
|
if(tx_buffer == NULL)
|
138
|
switch(BYTES_AND_BITS(frame->numbytes, frame->numbits)) {
|
139
|
case BYTES_AND_BITS(4, 0):
|
140
|
if( (frame->data[0] & 0xfe) == 0x60 && frame->parameters.a.crc) {
|
141
|
/* AUTH1A or AUTH1B */
|
142
|
if(NONCE_BUFFER == NULL) {
|
143
|
NONCE_BUFFER = alloc_buffer_for_frame(&NONCE_FRAME);
|
144
|
}
|
145
|
if(NONCE_BUFFER != NULL) {
|
146
|
int ret = manchester_encode(NONCE_BUFFER->data, NONCE_BUFFER->len, &NONCE_FRAME);
|
147
|
if(ret < 0) {
|
148
|
} else {
|
149
|
NONCE_BUFFER->len = ret;
|
150
|
tx_buffer = NONCE_BUFFER;
|
151
|
}
|
152
|
}
|
153
|
|
154
|
/*fdt += ((cv / 128) + 10) * 128;*/
|
155
|
fdt += 50*128; /* 52 ok, 26 not, 39 not, 45 not, 48 not, 50 ok, 49 not */
|
156
|
}
|
157
|
break;
|
158
|
}
|
159
|
|
160
|
/* Add some extra room to the fdt for testing */
|
161
|
//fdt += 3*128;
|
162
|
fdt += fdt_offset;
|
163
|
|
164
|
if(tx_buffer != NULL) {
|
165
|
tx_buffer->state = SSC_FULL;
|
166
|
if( iso14443_transmit(tx_buffer, fdt, 1, 0) < 0) {
|
167
|
usb_print_string_f("Tx failed ", 0);
|
168
|
}
|
169
|
}
|
170
|
|
171
|
#if 0
|
172
|
u_int32_t cv2 = *AT91C_TC2_CV;
|
173
|
usb_print_string_f("\r\n",0);
|
174
|
if(tx_buffer == &NONCE_BUFFER) usb_print_string_f("---> ",0);
|
175
|
int old=usb_print_set_default_flush(0);
|
176
|
DumpUIntToUSB(cv);
|
177
|
DumpStringToUSB(":");
|
178
|
DumpUIntToUSB(cv2);
|
179
|
usb_print_set_default_flush(old);
|
180
|
#endif
|
181
|
|
182
|
switch(BYTES_AND_BITS(frame->numbytes,frame->numbits)) {
|
183
|
case BYTES_AND_BITS(4, 0):
|
184
|
if(frame->parameters.a.crc && frame->data[0] == 0x50 && frame->data[1] == 0x00) {
|
185
|
/* HLTA */
|
186
|
UID[3]++;
|
187
|
if(UID[3]==0) {
|
188
|
UID[2]++;
|
189
|
if(UID[2]==0) {
|
190
|
UID[1]++;
|
191
|
if(UID[1]==0) {
|
192
|
UID[0]++;
|
193
|
}
|
194
|
}
|
195
|
}
|
196
|
set_UID(UID, sizeof(UID));
|
197
|
}
|
198
|
break;
|
199
|
}
|
200
|
|
201
|
if(tx_buffer) usb_print_string_f("\r\n",0);
|
202
|
if(tx_buffer == UID_BUFFER) {
|
203
|
memcpy(&challenge_response.UID, UID_FRAME.data, 5);
|
204
|
usb_print_string_f("uid", 0);
|
205
|
} else if(tx_buffer == NONCE_BUFFER) {
|
206
|
memcpy(&challenge_response.nonce, NONCE_FRAME.data, 4);
|
207
|
challenge_response.waiting_for_response = 1;
|
208
|
usb_print_string_f("nonce", 0);
|
209
|
} else if(challenge_response.waiting_for_response) {
|
210
|
challenge_response.waiting_for_response = 0;
|
211
|
if(frame->numbytes != 8) {
|
212
|
usb_print_string_f("tilt ",0);
|
213
|
}
|
214
|
challenge_response.response.len = frame->numbytes + (frame->numbits+7)/8;
|
215
|
memcpy(&challenge_response.response.data, frame->data, challenge_response.response.len);
|
216
|
memcpy(&challenge_response.response.parity, frame->parity, 1);
|
217
|
|
218
|
int old=usb_print_set_default_flush(0);
|
219
|
DumpStringToUSB("[[");
|
220
|
DumpBufferToUSB((char*)challenge_response.UID, 5);
|
221
|
DumpStringToUSB(" ");
|
222
|
DumpBufferToUSB((char*)challenge_response.nonce, 4);
|
223
|
DumpStringToUSB(" ");
|
224
|
DumpBufferToUSB((char*)challenge_response.response.data, challenge_response.response.len);
|
225
|
DumpStringToUSB("]]");
|
226
|
usb_print_set_default_flush(old);
|
227
|
}
|
228
|
//usb_print_string_f("%", 0);
|
229
|
}
|
230
|
|
231
|
static void prepare_frame(iso14443_frame *frame, int len)
|
232
|
{
|
233
|
memset(frame, 0, sizeof(*frame));
|
234
|
frame->type = TYPE_A;
|
235
|
frame->parameters.a.format = STANDARD_FRAME;
|
236
|
frame->parameters.a.parity = PARITY;
|
237
|
frame->parameters.a.last_bit = ISO14443A_LAST_BIT_NONE;
|
238
|
frame->parameters.a.crc = CRC_UNCALCULATED;
|
239
|
|
240
|
frame->numbytes = len;
|
241
|
}
|
242
|
|
243
|
int set_UID(u_int8_t *uid, size_t len)
|
244
|
{
|
245
|
prepare_frame(&UID_FRAME, len+1);
|
246
|
|
247
|
u_int8_t bcc = 0;
|
248
|
unsigned int i;
|
249
|
for(i=0; i<len; i++) {
|
250
|
UID_FRAME.data[i] = uid[i];
|
251
|
bcc ^= uid[i];
|
252
|
}
|
253
|
UID_FRAME.data[i] = bcc;
|
254
|
UID_FRAME.state = FRAME_PREFILLED;
|
255
|
memcpy(UID, uid, len);
|
256
|
|
257
|
if(UID_BUFFER == NULL) {
|
258
|
UID_BUFFER = alloc_buffer_for_frame(&UID_FRAME);
|
259
|
if(UID_BUFFER == NULL) return -ENOMEM;
|
260
|
}
|
261
|
memset(UID_BUFFER->data, 0, UID_BUFFER->len);
|
262
|
|
263
|
int ret = manchester_encode(UID_BUFFER->data, UID_BUFFER->len, &UID_FRAME);
|
264
|
if(ret < 0) return ret;
|
265
|
else UID_BUFFER->len = ret;
|
266
|
return 0;
|
267
|
}
|
268
|
|
269
|
int get_UID(u_int8_t *uid, size_t len)
|
270
|
{
|
271
|
if(len < 4 || len > 4) return -1;
|
272
|
memcpy(uid, UID, len);
|
273
|
return 0;
|
274
|
}
|
275
|
|
276
|
int set_nonce(u_int8_t *_nonce, size_t len)
|
277
|
{
|
278
|
prepare_frame(&NONCE_FRAME, len);
|
279
|
|
280
|
memcpy(&NONCE_FRAME.data, _nonce, len);
|
281
|
NONCE_FRAME.state = FRAME_PREFILLED;
|
282
|
memcpy(nonce, _nonce, len);
|
283
|
|
284
|
if(NONCE_BUFFER == NULL) {
|
285
|
NONCE_BUFFER = alloc_buffer_for_frame(&NONCE_FRAME);
|
286
|
if(NONCE_BUFFER == NULL) return -ENOMEM;
|
287
|
}
|
288
|
memset(NONCE_BUFFER->data, 0, NONCE_BUFFER->len);
|
289
|
|
290
|
int ret = manchester_encode(NONCE_BUFFER->data, NONCE_BUFFER->len, &NONCE_FRAME);
|
291
|
if(ret < 0) return ret;
|
292
|
else NONCE_BUFFER->len = ret;
|
293
|
return 0;
|
294
|
}
|
295
|
|
296
|
int get_nonce(u_int8_t *_nonce, size_t len)
|
297
|
{
|
298
|
if(len < 4 || len > 4) return -1;
|
299
|
memcpy(_nonce, nonce, len);
|
300
|
return 0;
|
301
|
}
|
302
|
|
303
|
void iso14443a_pretender (void *pvParameters)
|
304
|
{
|
305
|
(void)pvParameters;
|
306
|
int res;
|
307
|
|
308
|
/* Delay until USB print etc. are ready */
|
309
|
int i;
|
310
|
for(i=0; i<=1000; i++) {
|
311
|
vLedSetBrightness(LED_RED, i);
|
312
|
vLedSetBrightness(LED_GREEN, i);
|
313
|
vTaskDelay(1*portTICK_RATE_MS);
|
314
|
}
|
315
|
|
316
|
for(i=0; i<=1000; i+=4) {
|
317
|
vLedSetBrightness(LED_GREEN, 1000-i);
|
318
|
vTaskDelay(1*portTICK_RATE_MS);
|
319
|
}
|
320
|
|
321
|
int ret;
|
322
|
#define PREFILL_BUFFER(dst, src) dst = alloc_buffer_for_frame(&src); \
|
323
|
if(dst == 0) goto prefill_failed; \
|
324
|
ret = manchester_encode(dst->data, dst->len, &src); \
|
325
|
if(ret < 0) goto prefill_failed; else dst->len = ret;
|
326
|
|
327
|
PREFILL_BUFFER(ATQA_BUFFER, ATQA_FRAME);
|
328
|
//PREFILL_BUFFER(UID_BUFFER, UID_FRAME);
|
329
|
PREFILL_BUFFER(ATS_BUFFER, ATS_FRAME);
|
330
|
//PREFILL_BUFFER(NONCE_BUFFER, NONCE_FRAME);
|
331
|
|
332
|
set_UID(UID, sizeof(UID));
|
333
|
set_nonce(nonce, sizeof(nonce));
|
334
|
|
335
|
if(0) {
|
336
|
prefill_failed:
|
337
|
usb_print_string("Buffer prefilling failed\n\r");
|
338
|
while(1) {
|
339
|
for(i=1000; i<=3000; i++) {
|
340
|
vLedSetBrightness(LED_GREEN, abs(1000-(i%2000)));
|
341
|
vTaskDelay(1*portTICK_RATE_MS);
|
342
|
}
|
343
|
}
|
344
|
}
|
345
|
|
346
|
do {
|
347
|
res = iso14443_layer2a_init(1);
|
348
|
if(res < 0) {
|
349
|
usb_print_string("Pretender: Initialization failed: -");
|
350
|
DumpUIntToUSB(-res);
|
351
|
usb_print_string("\n\r");
|
352
|
for(i=0; i<=10000; i++) {
|
353
|
vLedSetBrightness(LED_RED, abs(1000-(i%2000)));
|
354
|
vTaskDelay(1*portTICK_RATE_MS);
|
355
|
}
|
356
|
}
|
357
|
} while(res < 0);
|
358
|
|
359
|
|
360
|
usb_print_string("Waiting for carrier. ");
|
361
|
while(iso14443_wait_for_carrier(1000 * portTICK_RATE_MS) != 0) {
|
362
|
}
|
363
|
usb_print_string("Carrier detected.\n\r");
|
364
|
|
365
|
for(i=0; i<=1000; i+=4) {
|
366
|
vLedSetBrightness(LED_RED, 1000-i);
|
367
|
vTaskDelay(1*portTICK_RATE_MS);
|
368
|
}
|
369
|
|
370
|
vTaskDelay(250*portTICK_RATE_MS);
|
371
|
vLedSetGreen(0);
|
372
|
vLedSetRed(0);
|
373
|
|
374
|
int current_detected = 0, last_detected = 0;
|
375
|
portTickType last_switched = 0;
|
376
|
#define DETECTED_14443A_3 1
|
377
|
#define DETECTED_14443A_4 2
|
378
|
#define DETECTED_MIFARE 4
|
379
|
|
380
|
while(true) {
|
381
|
iso14443_frame *frame = 0;
|
382
|
res = iso14443_receive(fast_receive_callback, &frame, 1000 * portTICK_RATE_MS);
|
383
|
if(res >= 0) {
|
384
|
switch(BYTES_AND_BITS(frame->numbytes, frame->numbits) ) {
|
385
|
case BYTES_AND_BITS(0, 7): /* REQA (7 bits) */
|
386
|
current_detected |= DETECTED_14443A_3;
|
387
|
break;
|
388
|
case BYTES_AND_BITS(2, 0): /* ANTICOL (2 bytes) */
|
389
|
case BYTES_AND_BITS(9, 0): /* SELECT (9 bytes) */
|
390
|
current_detected |= DETECTED_14443A_3;
|
391
|
break;
|
392
|
case BYTES_AND_BITS(4, 0): /* AUTH1A (or any other four byte frame) */
|
393
|
case BYTES_AND_BITS(8, 0): /* AUTH2 (8 bytes) */
|
394
|
current_detected |= DETECTED_MIFARE;
|
395
|
break;
|
396
|
}
|
397
|
|
398
|
portENTER_CRITICAL();
|
399
|
frame->state = FRAME_FREE;
|
400
|
portEXIT_CRITICAL();
|
401
|
} else {
|
402
|
if(res != -ETIMEDOUT) {
|
403
|
usb_print_string("Receive error: ");
|
404
|
switch(res) {
|
405
|
case -ENETDOWN: usb_print_string("PLL is not locked or PLL lock lost\n\r"); break;
|
406
|
case -EBUSY: usb_print_string("A Tx is currently running or pending, can't receive\n\r"); break;
|
407
|
case -EALREADY: usb_print_string("There's already an iso14443_receive() invocation running\n\r"); break;
|
408
|
}
|
409
|
vTaskDelay(1000 * portTICK_RATE_MS); // FIXME Proper error handling, e.g. wait for Tx end in case of EBUSY
|
410
|
} else if(0) {
|
411
|
DumpStringToUSB("\n\r");
|
412
|
DumpTimeToUSB(xTaskGetTickCount());
|
413
|
usb_print_string(": -- Mark --");
|
414
|
}
|
415
|
}
|
416
|
|
417
|
if( last_switched < xTaskGetTickCount()-(1000*portTICK_RATE_MS) ) {
|
418
|
last_detected = current_detected;
|
419
|
current_detected = 0;
|
420
|
last_switched = xTaskGetTickCount();
|
421
|
}
|
422
|
|
423
|
#if 0
|
424
|
if(last_detected & (DETECTED_14443A_3 | DETECTED_14443A_4 | DETECTED_MIFARE)) {
|
425
|
if(last_detected & DETECTED_MIFARE) {
|
426
|
vLedSetGreen(0);
|
427
|
vLedSetRed(1);
|
428
|
} else if(last_detected & DETECTED_14443A_4) {
|
429
|
vLedSetGreen(1);
|
430
|
vLedSetRed(0);
|
431
|
} else {
|
432
|
vLedSetGreen(1);
|
433
|
vLedSetRed(1);
|
434
|
}
|
435
|
} else {
|
436
|
vLedSetGreen(0);
|
437
|
vLedSetRed(0);
|
438
|
}
|
439
|
#endif
|
440
|
}
|
441
|
}
|