1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // Routines to support Picopass <-> SAM communication
17 //-----------------------------------------------------------------------------
18 #include "sam_picopass.h"
21 #include "proxmark3_arm.h"
24 #include "commonutil.h"
29 #include "protocols.h"
30 #include "optimized_cipher.h"
31 #include "fpgaloader.h"
33 static int sam_rxtx(const uint8_t *data
, uint16_t n
, uint8_t *resp
, uint16_t *resplen
) {
37 bool res
= I2C_BufferWrite(data
, n
, I2C_DEVICE_CMD_SEND_T0
, I2C_DEVICE_ADDRESS_MAIN
);
39 DbpString("failed to send to SIM CARD");
43 *resplen
= ISO7816_MAX_FRAME
;
45 res
= sc_rx_bytes(resp
, resplen
, SIM_WAIT_DELAY
);
47 DbpString("failed to receive from SIM CARD");
52 DbpString("received too few bytes from SIM CARD");
57 uint16_t more_len
= 0;
59 if (resp
[*resplen
- 2] == 0x61 || resp
[*resplen
- 2] == 0x9F) {
60 more_len
= resp
[*resplen
- 1];
66 // Don't discard data we already received except the SW code.
67 // If we only received 1 byte, this is the echo of INS, we discard it.
73 uint8_t cmd_getresp
[] = {0x00, ISO7816_GET_RESPONSE
, 0x00, 0x00, more_len
};
75 res
= I2C_BufferWrite(cmd_getresp
, sizeof(cmd_getresp
), I2C_DEVICE_CMD_SEND_T0
, I2C_DEVICE_ADDRESS_MAIN
);
77 DbpString("failed to send to SIM CARD 2");
81 more_len
= 255 - *resplen
;
83 res
= sc_rx_bytes(resp
+ *resplen
, &more_len
, SIM_WAIT_DELAY
);
85 DbpString("failed to receive from SIM CARD 2");
96 // using HID SAM to authenticate w PICOPASS
97 int sam_picopass_get_pacs(void) {
99 static uint8_t act_all
[] = { ICLASS_CMD_ACTALL
};
100 static uint8_t identify
[] = { ICLASS_CMD_READ_OR_IDENTIFY
, 0x00, 0x73, 0x33 };
101 static uint8_t read_conf
[] = { ICLASS_CMD_READ_OR_IDENTIFY
, 0x01, 0xfa, 0x22 };
102 uint8_t select
[] = { 0x80 | ICLASS_CMD_SELECT
, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
103 uint8_t read_aia
[] = { ICLASS_CMD_READ_OR_IDENTIFY
, 0x05, 0xde, 0x64};
104 uint8_t read_check_cc
[] = { 0x80 | ICLASS_CMD_READCHECK
, 0x02 };
106 picopass_hdr_t hdr
= {0};
107 // Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used
109 // if (use_credit_key)
110 // read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK;
112 BigBuf_free_keep_EM();
116 I2C_Reset_EnterMainProgram();
119 uint8_t *resp
= BigBuf_calloc(ISO7816_MAX_FRAME
);
121 bool shallow_mod
= false;
122 uint16_t resp_len
= 0;
124 uint32_t eof_time
= 0;
127 Iso15693InitReader();
129 uint32_t start_time
= GetCountSspClk();
130 iclass_send_as_reader(act_all
, 1, &start_time
, &eof_time
, shallow_mod
);
132 res
= GetIso15693AnswerFromTag(resp
, ISO7816_MAX_FRAME
, ICLASS_READER_TIMEOUT_ACTALL
, &eof_time
, false, true, &resp_len
);
133 if (res
!= PM3_SUCCESS
) {
134 res
= PM3_ECARDEXCHANGE
;
139 start_time
= eof_time
+ DELAY_ICLASS_VICC_TO_VCD_READER
;
140 iclass_send_as_reader(identify
, 1, &start_time
, &eof_time
, shallow_mod
);
142 // expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC
143 res
= GetIso15693AnswerFromTag(resp
, ISO7816_MAX_FRAME
, ICLASS_READER_TIMEOUT_OTHERS
, &eof_time
, false, true, &resp_len
);
144 if (res
!= PM3_SUCCESS
|| resp_len
!= 10) {
145 res
= PM3_ECARDEXCHANGE
;
149 // copy the Anti-collision CSN to our select-packet
150 memcpy(&select
[1], resp
, 8);
153 start_time
= eof_time
+ DELAY_ICLASS_VICC_TO_VCD_READER
;
154 iclass_send_as_reader(select
, sizeof(select
), &start_time
, &eof_time
, shallow_mod
);
156 // expect a 10-byte response here, 8 byte CSN and 2 byte CRC
157 res
= GetIso15693AnswerFromTag(resp
, ISO7816_MAX_FRAME
, ICLASS_READER_TIMEOUT_OTHERS
, &eof_time
, false, true, &resp_len
);
158 if (res
!= PM3_SUCCESS
|| resp_len
!= 10) {
159 res
= PM3_ECARDEXCHANGE
;
164 memcpy(hdr
.csn
, resp
, sizeof(hdr
.csn
));
166 // card selected, now read config (block1) (only 8 bytes no CRC)
167 start_time
= eof_time
+ DELAY_ICLASS_VICC_TO_VCD_READER
;
168 iclass_send_as_reader(read_conf
, sizeof(read_conf
), &start_time
, &eof_time
, shallow_mod
);
170 // expect a 8-byte response here
171 res
= GetIso15693AnswerFromTag(resp
, ISO7816_MAX_FRAME
, ICLASS_READER_TIMEOUT_OTHERS
, &eof_time
, false, true, &resp_len
);
172 if (res
!= PM3_SUCCESS
|| resp_len
!= 10) {
173 res
= PM3_ECARDEXCHANGE
;
178 memcpy((uint8_t *)&hdr
.conf
, resp
, sizeof(hdr
.conf
));
180 uint8_t pagemap
= get_pagemap(&hdr
);
181 if (pagemap
== PICOPASS_NON_SECURE_PAGEMODE
) {
182 res
= PM3_EWRONGANSWER
;
186 // read App Issuer Area block 5
187 start_time
= eof_time
+ DELAY_ICLASS_VICC_TO_VCD_READER
;
188 iclass_send_as_reader(read_aia
, sizeof(read_aia
), &start_time
, &eof_time
, shallow_mod
);
190 // expect a 10-byte response here
191 res
= GetIso15693AnswerFromTag(resp
, ISO7816_MAX_FRAME
, ICLASS_READER_TIMEOUT_OTHERS
, &eof_time
, false, true, &resp_len
);
192 if (res
!= PM3_SUCCESS
|| resp_len
!= 10) {
193 res
= PM3_ECARDEXCHANGE
;
198 memcpy(hdr
.app_issuer_area
, resp
, sizeof(hdr
.app_issuer_area
));
200 // card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
201 start_time
= eof_time
+ DELAY_ICLASS_VICC_TO_VCD_READER
;
202 iclass_send_as_reader(read_check_cc
, sizeof(read_check_cc
), &start_time
, &eof_time
, shallow_mod
);
204 // expect a 8-byte response here
205 res
= GetIso15693AnswerFromTag(resp
, ISO7816_MAX_FRAME
, ICLASS_READER_TIMEOUT_OTHERS
, &eof_time
, false, true, &resp_len
);
206 if (res
!= PM3_SUCCESS
|| resp_len
!= 8) {
207 res
= PM3_ECARDEXCHANGE
;
212 memcpy(hdr
.epurse
, resp
, sizeof(hdr
.epurse
));
214 // -----------------------------------------------------------------------------
216 // -----------------------------------------------------------------------------
218 uint8_t *sam_apdu
= BigBuf_calloc(ISO7816_MAX_FRAME
);
220 // -----------------------------------------------------------------------------
222 // a0 da 02 63 1a 44 0a 44 00 00 00 a0 12 ad 10 a0 0e 80 02 00 04 81 08 9b fc a4 00 fb ff 12 e0
223 hexstr_to_byte_array("a0da02631a440a44000000a012ad10a00e800200048108", sam_apdu
, &sam_len
);
224 memcpy(sam_apdu
+ sam_len
, hdr
.csn
, sizeof(hdr
.csn
));
225 sam_len
+= sizeof(hdr
.csn
);
227 if (sam_rxtx(sam_apdu
, sam_len
, resp
, &resp_len
) == false) {
228 res
= PM3_ECARDEXCHANGE
;
231 print_dbg("-- 1", resp
, resp_len
);
233 // -----------------------------------------------------------------------------
235 // a0 da 02 63 0d 44 0a 44 00 00 00 a0 05 a1 03 80 01 04
236 hexstr_to_byte_array("a0da02630d440a44000000a005a103800104", sam_apdu
, &sam_len
);
237 if (sam_rxtx(sam_apdu
, sam_len
, resp
, &resp_len
) == false) {
238 res
= PM3_ECARDEXCHANGE
;
241 print_dbg("-- 2", resp
, resp_len
);
244 // -- 0c 05 de64 // read block 5
245 // Tag|c00a140a000000a110a10e8004 0c05de64 8102 0004 820201f4
247 // -----------------------------------------------------------------------------
249 // a0da02631c140a00000000bd14a012a010800a ffffff0006fffffff88e 81020000
250 // picopass legacy is fixed. wants AIA and crc. ff ff ff ff ff ff ff ff ea f5
251 // picpoasss SE ff ff ff 00 06 ff ff ff f8 8e
252 hexstr_to_byte_array("a0da02631c140a00000000bd14a012a010800affffff0006fffffff88e81020000", sam_apdu
, &sam_len
);
253 memcpy(sam_apdu
+ 19, hdr
.app_issuer_area
, sizeof(hdr
.app_issuer_area
));
254 AddCrc(sam_apdu
+ 19, 8);
256 if (sam_rxtx(sam_apdu
, sam_len
, resp
, &resp_len
) == false) {
257 res
= PM3_ECARDEXCHANGE
;
260 print_dbg("-- 3", resp
, resp_len
);
262 // 88 02 -- readcheck (block2 epurse, start of auth)
263 // Tag|c00a140a000000a10ea10c8002 8802 8102 0004 820201f4 9000
264 // 61 16 f5 0a140a000000a10ea10c 8002 8802 8102 0004 820201f4 9000
266 // -----------------------------------------------------------------------------
268 // a0da02631a140a00000000bd12a010a00e8008 ffffffffedffffff 81020000
269 hexstr_to_byte_array("a0da02631a140a00000000bd12a010a00e8008ffffffffedffffff81020000", sam_apdu
, &sam_len
);
270 memcpy(sam_apdu
+ 19, hdr
.epurse
, sizeof(hdr
.epurse
));
272 if (sam_rxtx(sam_apdu
, sam_len
, resp
, &resp_len
) == false) {
273 res
= PM3_ECARDEXCHANGE
;
276 print_dbg("-- 4", resp
, resp_len
);
278 uint8_t nr_mac
[9] = {0};
279 memcpy(nr_mac
, resp
+ 11, sizeof(nr_mac
));
280 // resp here hold the whole NR/MAC
281 // 05 9bcd475e965ee20e // CHECK (w key)
282 print_dbg("NR/MAC", nr_mac
, sizeof(nr_mac
));
284 // c00a140a000000a115a1138009 059bcd475e965ee20e 8102 0004 820201f4 9000
287 // uint8_t cc_nr[] = {0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0};
288 uint8_t div_key
[8] = {0};
289 static uint8_t legacy_aa1_key
[] = {0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78};
290 iclass_calc_div_key(hdr
.csn
, legacy_aa1_key
, div_key
, false);
292 uint8_t mac
[4] = {0};
293 if (g_dbglevel
== DBG_DEBUG
) {
294 uint8_t wb
[16] = {0};
295 memcpy(wb
, hdr
.epurse
, sizeof(hdr
.epurse
));
296 memcpy(wb
+ sizeof(hdr
.epurse
), nr_mac
+ 1, 4);
297 print_dbg("cc_nr...", wb
, sizeof(wb
));
298 doMAC_N(wb
, sizeof(wb
), div_key
, mac
);
299 print_dbg("Calc MAC...", mac
, sizeof(mac
));
302 // start ssp clock again...
305 // NOW we auth against tag
306 uint8_t cmd_check
[9] = { ICLASS_CMD_CHECK
};
307 memcpy(cmd_check
+ 1, nr_mac
+ 1, 8);
309 start_time
= GetCountSspClk();
310 iclass_send_as_reader(cmd_check
, sizeof(cmd_check
), &start_time
, &eof_time
, shallow_mod
);
312 // expect a 10-byte response here
313 res
= GetIso15693AnswerFromTag(resp
, ISO7816_MAX_FRAME
, ICLASS_READER_TIMEOUT_OTHERS
, &eof_time
, false, true, &resp_len
);
314 if (res
!= PM3_SUCCESS
|| resp_len
!= 4) {
315 res
= PM3_ECARDEXCHANGE
;
319 memcpy(mac
, resp
, sizeof(mac
));
320 print_dbg("Got MAC", mac
, sizeof(mac
));
322 // -----------------------------------------------------------------------------
323 // fifth send received MAC
324 // A0DA026316140A00000000BD0EA00CA00A8004 311E32E9 81020000
325 hexstr_to_byte_array("A0DA026316140A00000000BD0EA00CA00A8004311E32E981020000", sam_apdu
, &sam_len
);
326 memcpy(sam_apdu
+ 19, mac
, sizeof(mac
));
328 if (sam_rxtx(sam_apdu
, sam_len
, resp
, &resp_len
) == false) {
329 res
= PM3_ECARDEXCHANGE
;
332 print_dbg("-- 5", resp
, resp_len
);
334 uint8_t tmp_p1
[4] = {0};
335 uint8_t tmp_p2
[4] = {0};
337 // c161c10000a11aa118800e8702 ffffffff88ffffff 0a914eb981020004820236b09000
339 memcpy(tmp_p1
, resp
+ 13, sizeof(tmp_p1
));
340 memcpy(tmp_p2
, resp
+ 13 + 4, sizeof(tmp_p2
));
341 // -----------------------------------------------------------------------------
342 // sixth send fake epurse update
343 // A0DA02631C140A00000000BD14A012A010800A 88FFFFFFFFFFFFFF9DE1 81020000
344 hexstr_to_byte_array("A0DA02631C140A00000000BD14A012A010800A88FFFFFFFFFFFFFF9DE181020000", sam_apdu
, &sam_len
);
346 memcpy(sam_apdu
+ 19, tmp_p2
, sizeof(tmp_p1
));
347 memcpy(sam_apdu
+ 19 + 4, tmp_p1
, sizeof(tmp_p1
));
348 AddCrc(sam_apdu
+ 19, 8);
350 if (sam_rxtx(sam_apdu
, sam_len
, resp
, &resp_len
) == false) {
351 res
= PM3_ECARDEXCHANGE
;
354 print_dbg("-- 6", resp
, resp_len
);
355 // c1 61 c1 00 00 a1 10 a1 0e 80 04 0c 06 45 56 81 02 00 04 82 02 01 f4 90 00
359 start_time
= GetCountSspClk();
360 iclass_send_as_reader(resp
+ 11, 4, &start_time
, &eof_time
, shallow_mod
);
362 // expect a 10-byte response here
363 res
= GetIso15693AnswerFromTag(resp
, ISO7816_MAX_FRAME
, ICLASS_READER_TIMEOUT_OTHERS
, &eof_time
, false, true, &resp_len
);
364 if (res
!= PM3_SUCCESS
|| resp_len
!= 10) {
365 res
= PM3_ECARDEXCHANGE
;
368 print_dbg("Block 6 from Picopass", resp
, resp_len
);
370 // -----------------------------------------------------------------------------
371 // eight send block 6 config to SAM
372 // A0DA02631C140A00000000BD14A012A010800A 030303030003E0174323 81020000
373 hexstr_to_byte_array("A0DA02631C140A00000000BD14A012A010800A030303030003E017432381020000", sam_apdu
, &sam_len
);
374 memcpy(sam_apdu
+ 19, resp
, resp_len
);
376 if (sam_rxtx(sam_apdu
, sam_len
, resp
, &resp_len
) == false) {
377 res
= PM3_ECARDEXCHANGE
;
380 print_dbg("-- 7", resp
, resp_len
);
382 // c161c10000a110a10e8004 0606455681020004820201f49000
384 // read the credential blocks
386 start_time
= GetCountSspClk();
387 iclass_send_as_reader(resp
+ 11, 4, &start_time
, &eof_time
, shallow_mod
);
389 // expect a 10-byte response here
390 res
= GetIso15693AnswerFromTag(resp
, ISO7816_MAX_FRAME
, ICLASS_READER_TIMEOUT_OTHERS
, &eof_time
, false, true, &resp_len
);
391 if (res
!= PM3_SUCCESS
) {
392 res
= PM3_ECARDEXCHANGE
;
395 print_dbg("Block 6-9 from Picopass", resp
, resp_len
);
397 // -----------------------------------------------------------------------------
398 // nine send credential blocks to SAM
399 // A0DA026334140A00000000BD2CA02AA0288022 030303030003E017769CB4A198E0DEC82AD4C8211F9968712BE7393CF8E71D7E804C 81020000
400 hexstr_to_byte_array("A0DA026334140A00000000BD2CA02AA0288022030303030003E017769CB4A198E0DEC82AD4C8211F9968712BE7393CF8E71D7E804C81020000", sam_apdu
, &sam_len
);
401 memcpy(sam_apdu
+ 19, resp
, resp_len
);
403 if (sam_rxtx(sam_apdu
, sam_len
, resp
, &resp_len
) == false) {
404 res
= PM3_ECARDEXCHANGE
;
407 print_dbg("-- 8", resp
, resp_len
);
410 // -----------------------------------------------------------------------------
411 // TEN ask for PACS data
412 // A0DA02630C440A00000000BD04A0028200
413 hexstr_to_byte_array("A0DA02630C440A00000000BD04A0028200", sam_apdu
, &sam_len
);
414 memcpy(sam_apdu
+ 19, resp
, resp_len
);
416 if (sam_rxtx(sam_apdu
, sam_len
, resp
, &resp_len
) == false) {
417 res
= PM3_ECARDEXCHANGE
;
421 print_dbg("-- 9 response", resp
, resp_len
);
422 if (memcmp(resp
, "\xc1\x64\x00\x00\x00\xbd\x17\x8a\x15", 9) == 0) {
427 // c164000000bd098a07 030506951f9a00 9000
428 uint8_t *pacs
= BigBuf_calloc(resp
[8]);
429 memcpy(pacs
, resp
+ 9, resp
[8]);
431 print_dbg("-- 10 PACS data", pacs
, resp
[8]);
433 reply_ng(CMD_HF_SAM_PICOPASS
, PM3_SUCCESS
, pacs
, resp
[8]);
438 reply_ng(CMD_HF_SAM_PICOPASS
, res
, NULL
, 0);