|
@@ -6,6 +6,9 @@
|
|
|
#define APDU_HEADER_LEN 5
|
|
#define APDU_HEADER_LEN 5
|
|
|
#define ASN1_PREFIX 6
|
|
#define ASN1_PREFIX 6
|
|
|
#define ASN1_DEBUG true
|
|
#define ASN1_DEBUG true
|
|
|
|
|
+#define SEADER_ICLASS_SR_SIO_BASE_BLOCK 10
|
|
|
|
|
+
|
|
|
|
|
+const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78};
|
|
|
|
|
|
|
|
static char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0};
|
|
static char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0};
|
|
|
char asn1_log[SEADER_UART_RX_BUF_SIZE] = {0};
|
|
char asn1_log[SEADER_UART_RX_BUF_SIZE] = {0};
|
|
@@ -23,63 +26,48 @@ void* calloc(size_t count, size_t size) {
|
|
|
|
|
|
|
|
// Forward declarations
|
|
// Forward declarations
|
|
|
void seader_send_nfc_rx(SeaderUartBridge* seader_uart, uint8_t* buffer, size_t len);
|
|
void seader_send_nfc_rx(SeaderUartBridge* seader_uart, uint8_t* buffer, size_t len);
|
|
|
-PicopassError seader_worker_fake_epurse_update(BitBuffer* tx_buffer, BitBuffer* rx_buffer);
|
|
|
|
|
|
|
|
|
|
-void seader_picopass_state_machine(Seader* seader, uint8_t* buffer, size_t len) {
|
|
|
|
|
- SeaderWorker* seader_worker = seader->worker;
|
|
|
|
|
- SeaderUartBridge* seader_uart = seader_worker->uart;
|
|
|
|
|
|
|
+PicopassError seader_worker_fake_epurse_update(BitBuffer* tx_buffer, BitBuffer* rx_buffer) {
|
|
|
|
|
+ const uint8_t* buffer = bit_buffer_get_data(tx_buffer);
|
|
|
|
|
+ uint8_t fake_response[8];
|
|
|
|
|
+ memset(fake_response, 0, sizeof(fake_response));
|
|
|
|
|
+ memcpy(fake_response + 0, buffer + 6, 4);
|
|
|
|
|
+ memcpy(fake_response + 4, buffer + 2, 4);
|
|
|
|
|
+
|
|
|
|
|
+ bit_buffer_append_bytes(rx_buffer, fake_response, sizeof(fake_response));
|
|
|
|
|
+ iso13239_crc_append(Iso13239CrcTypePicopass, rx_buffer);
|
|
|
|
|
|
|
|
memset(display, 0, sizeof(display));
|
|
memset(display, 0, sizeof(display));
|
|
|
- for(uint8_t i = 0; i < len; i++) {
|
|
|
|
|
- snprintf(display + (i * 2), sizeof(display), "%02x", buffer[i]);
|
|
|
|
|
|
|
+ for(uint8_t i = 0; i < bit_buffer_get_size_bytes(rx_buffer); i++) {
|
|
|
|
|
+ snprintf(display + (i * 2), sizeof(display), "%02x", bit_buffer_get_data(rx_buffer)[i]);
|
|
|
}
|
|
}
|
|
|
- FURI_LOG_D(TAG, "Picopass State Macine %d: %s", len, display);
|
|
|
|
|
|
|
+ FURI_LOG_I(TAG, "Fake update E-Purse response: %s", display);
|
|
|
|
|
+
|
|
|
|
|
+ return PicopassErrorNone;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void seader_picopass_state_machine(Seader* seader, uint8_t* buffer, size_t len) {
|
|
|
|
|
+ SeaderWorker* seader_worker = seader->worker;
|
|
|
|
|
+ SeaderUartBridge* seader_uart = seader_worker->uart;
|
|
|
|
|
|
|
|
BitBuffer* tx_buffer = bit_buffer_alloc(len);
|
|
BitBuffer* tx_buffer = bit_buffer_alloc(len);
|
|
|
bit_buffer_append_bytes(tx_buffer, buffer, len);
|
|
bit_buffer_append_bytes(tx_buffer, buffer, len);
|
|
|
BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
|
|
BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
|
|
|
- // TODO: have this come from the actual saved card
|
|
|
|
|
- uint8_t csn[PICOPASS_BLOCK_LEN] = {0xf8, 0x7c, 0xd7, 0x12, 0xff, 0xff, 0x12, 0xe0};
|
|
|
|
|
|
|
+
|
|
|
uint8_t sr_aia[PICOPASS_BLOCK_LEN] = {0xFF, 0xff, 0xff, 0xff, 0xFF, 0xFf, 0xff, 0xFF};
|
|
uint8_t sr_aia[PICOPASS_BLOCK_LEN] = {0xFF, 0xff, 0xff, 0xff, 0xFF, 0xFf, 0xff, 0xFF};
|
|
|
uint8_t epurse[PICOPASS_BLOCK_LEN] = {0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff};
|
|
uint8_t epurse[PICOPASS_BLOCK_LEN] = {0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff};
|
|
|
uint8_t pacs_sr_cfg[PICOPASS_BLOCK_LEN] = {0xA3, 0x03, 0x03, 0x03, 0x00, 0x03, 0xe0, 0x14};
|
|
uint8_t pacs_sr_cfg[PICOPASS_BLOCK_LEN] = {0xA3, 0x03, 0x03, 0x03, 0x00, 0x03, 0xe0, 0x14};
|
|
|
|
|
|
|
|
- /*
|
|
|
|
|
-30 33 81 05 01 87 BC 0F
|
|
|
|
|
-45 A5 02 05 00 A6 08 81
|
|
|
|
|
-01 01 04 03 03 00 08 A7
|
|
|
|
|
-18 85 16 E0 8C 96 D4 1E
|
|
|
|
|
-26 55 12 79 6A 65 00 21
|
|
|
|
|
-C1 7D 19 27 CA 9F 80 35
|
|
|
|
|
-98 A9 02 05 00 05 00 00
|
|
|
|
|
- */
|
|
|
|
|
-
|
|
|
|
|
- uint8_t sio_first[PICOPASS_BLOCK_LEN * 4] = {
|
|
|
|
|
- 0x30, 0x33, 0x81, 0x05, 0x01, 0x87, 0xbc, 0x0f,
|
|
|
|
|
- 0x45, 0xa5, 0x02, 0x05, 0x00, 0xa6, 0x08, 0x81,
|
|
|
|
|
- 0x01, 0x01, 0x04, 0x03, 0x03, 0x00, 0x08, 0xa7,
|
|
|
|
|
- 0x18, 0x85, 0x16, 0xe0, 0x8c, 0x96, 0xd4, 0x1e
|
|
|
|
|
- };
|
|
|
|
|
- // NOTE: 8 byte overlap
|
|
|
|
|
- uint8_t sio_second[PICOPASS_BLOCK_LEN * 4] = {
|
|
|
|
|
- 0x18, 0x85, 0x16, 0xe0, 0x8c, 0x96, 0xd4, 0x1e,
|
|
|
|
|
- 0x26, 0x55, 0x12, 0x79, 0x6a, 0x65, 0x00, 0x21,
|
|
|
|
|
- 0xc1, 0x7d, 0x19, 0x27, 0xca, 0x9f, 0x80, 0x35,
|
|
|
|
|
- 0x98, 0xa9, 0x02, 0x05, 0x00, 0x05, 0x00, 0x00
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78};
|
|
|
|
|
-
|
|
|
|
|
uint8_t tmac[4] = {};
|
|
uint8_t tmac[4] = {};
|
|
|
uint8_t div_key[PICOPASS_BLOCK_LEN] = {};
|
|
uint8_t div_key[PICOPASS_BLOCK_LEN] = {};
|
|
|
|
|
+ uint8_t offset; // for READ4
|
|
|
|
|
|
|
|
do {
|
|
do {
|
|
|
switch(buffer[0]) {
|
|
switch(buffer[0]) {
|
|
|
case RFAL_PICOPASS_CMD_READ_OR_IDENTIFY:
|
|
case RFAL_PICOPASS_CMD_READ_OR_IDENTIFY:
|
|
|
- // append_bytes(rx, seader->[picopass]->AA1[buffer[1]].data, PICOPASS_BLOCK_LEN);
|
|
|
|
|
- if(buffer[1] == AIA_INDEX) { // TODO: _INDEX
|
|
|
|
|
|
|
+ if(buffer[1] == AIA_INDEX) {
|
|
|
bit_buffer_append_bytes(rx_buffer, sr_aia, sizeof(sr_aia));
|
|
bit_buffer_append_bytes(rx_buffer, sr_aia, sizeof(sr_aia));
|
|
|
- } else if (buffer[1] == PACS_CFG_INDEX) {
|
|
|
|
|
|
|
+ } else if(buffer[1] == PACS_CFG_INDEX) {
|
|
|
bit_buffer_append_bytes(rx_buffer, pacs_sr_cfg, sizeof(pacs_sr_cfg));
|
|
bit_buffer_append_bytes(rx_buffer, pacs_sr_cfg, sizeof(pacs_sr_cfg));
|
|
|
}
|
|
}
|
|
|
iso13239_crc_append(Iso13239CrcTypePicopass, rx_buffer);
|
|
iso13239_crc_append(Iso13239CrcTypePicopass, rx_buffer);
|
|
@@ -88,26 +76,23 @@ C1 7D 19 27 CA 9F 80 35
|
|
|
seader_worker_fake_epurse_update(tx_buffer, rx_buffer);
|
|
seader_worker_fake_epurse_update(tx_buffer, rx_buffer);
|
|
|
break;
|
|
break;
|
|
|
case RFAL_PICOPASS_CMD_READCHECK_KD:
|
|
case RFAL_PICOPASS_CMD_READCHECK_KD:
|
|
|
- if(buffer[1] == 2) { // TODO: _INDEX
|
|
|
|
|
|
|
+ if(buffer[1] == EPURSE_INDEX) {
|
|
|
bit_buffer_append_bytes(rx_buffer, epurse, sizeof(epurse));
|
|
bit_buffer_append_bytes(rx_buffer, epurse, sizeof(epurse));
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
case RFAL_PICOPASS_CMD_CHECK:
|
|
case RFAL_PICOPASS_CMD_CHECK:
|
|
|
- //memcpy(cc, data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data, sizeof(PicopassBlock));
|
|
|
|
|
- loclass_iclass_calc_div_key(csn, picopass_iclass_key, div_key, false);
|
|
|
|
|
|
|
+ loclass_iclass_calc_div_key(
|
|
|
|
|
+ seader->credential->diversifier, picopass_iclass_key, div_key, false);
|
|
|
LoclassState_t cipher_state = loclass_opt_doTagMAC_1(epurse, div_key);
|
|
LoclassState_t cipher_state = loclass_opt_doTagMAC_1(epurse, div_key);
|
|
|
- // loclass_opt_doBothMAC_2(cipher_state, rx_buffer+1, rmac, tmac, div_key);
|
|
|
|
|
-
|
|
|
|
|
loclass_opt_doTagMAC_2(cipher_state, buffer + 1, tmac, div_key);
|
|
loclass_opt_doTagMAC_2(cipher_state, buffer + 1, tmac, div_key);
|
|
|
bit_buffer_append_bytes(rx_buffer, tmac, sizeof(tmac));
|
|
bit_buffer_append_bytes(rx_buffer, tmac, sizeof(tmac));
|
|
|
break;
|
|
break;
|
|
|
case RFAL_PICOPASS_CMD_READ4:
|
|
case RFAL_PICOPASS_CMD_READ4:
|
|
|
- if(buffer[1] == 10) {
|
|
|
|
|
- bit_buffer_append_bytes(rx_buffer, sio_first, sizeof(sio_first));
|
|
|
|
|
- }
|
|
|
|
|
- if(buffer[1] == 13) {
|
|
|
|
|
- bit_buffer_append_bytes(rx_buffer, sio_second, sizeof(sio_second));
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ offset = buffer[1] - SEADER_ICLASS_SR_SIO_BASE_BLOCK;
|
|
|
|
|
+ bit_buffer_append_bytes(
|
|
|
|
|
+ rx_buffer,
|
|
|
|
|
+ seader->credential->sio + (PICOPASS_BLOCK_LEN * offset),
|
|
|
|
|
+ PICOPASS_BLOCK_LEN * 4);
|
|
|
iso13239_crc_append(Iso13239CrcTypePicopass, rx_buffer);
|
|
iso13239_crc_append(Iso13239CrcTypePicopass, rx_buffer);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
@@ -462,25 +447,6 @@ void seader_capture_sio(BitBuffer* tx_buffer, BitBuffer* rx_buffer, SeaderCreden
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-PicopassError seader_worker_fake_epurse_update(BitBuffer* tx_buffer, BitBuffer* rx_buffer) {
|
|
|
|
|
- const uint8_t* buffer = bit_buffer_get_data(tx_buffer);
|
|
|
|
|
- uint8_t fake_response[8];
|
|
|
|
|
- memset(fake_response, 0, sizeof(fake_response));
|
|
|
|
|
- memcpy(fake_response + 0, buffer + 6, 4);
|
|
|
|
|
- memcpy(fake_response + 4, buffer + 2, 4);
|
|
|
|
|
-
|
|
|
|
|
- bit_buffer_append_bytes(rx_buffer, fake_response, sizeof(fake_response));
|
|
|
|
|
- iso13239_crc_append(Iso13239CrcTypePicopass, rx_buffer);
|
|
|
|
|
-
|
|
|
|
|
- memset(display, 0, sizeof(display));
|
|
|
|
|
- for(uint8_t i = 0; i < bit_buffer_get_size_bytes(rx_buffer); i++) {
|
|
|
|
|
- snprintf(display + (i * 2), sizeof(display), "%02x", bit_buffer_get_data(rx_buffer)[i]);
|
|
|
|
|
- }
|
|
|
|
|
- FURI_LOG_I(TAG, "Fake update E-Purse response: %s", display);
|
|
|
|
|
-
|
|
|
|
|
- return PicopassErrorNone;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
void seader_iso15693_transmit(
|
|
void seader_iso15693_transmit(
|
|
|
Seader* seader,
|
|
Seader* seader,
|
|
|
PicopassPoller* picopass_poller,
|
|
PicopassPoller* picopass_poller,
|