Skip to content

Commit 4321676

Browse files
authored
Merge pull request #17 from bettse/mfc
MFC SE
2 parents 498f971 + 70548ac commit 4321676

9 files changed

+312
-16
lines changed

application.fam

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ App(
99
requires=[
1010
"gui", "storage", "nfc",
1111
],
12-
stack_size=7 * 1024,
12+
stack_size=5 * 1024,
1313
order=20,
1414
sources=[
1515
"*.c",

sam_api.c

+180-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
#include "sam_api.h"
33
#include <toolbox/path.h>
4+
#include <bit_lib/bit_lib.h>
45

56
#define TAG "SAMAPI"
67

@@ -728,6 +729,161 @@ void seader_iso14443a_transmit(
728729
bit_buffer_free(rx_buffer);
729730
}
730731

732+
/* Assumes this is called in the context of the NFC API callback */
733+
#define MF_CLASSIC_FWT_FC (60000)
734+
void seader_mfc_transmit(
735+
Seader* seader,
736+
MfClassicPoller* mfc_poller,
737+
uint8_t* buffer,
738+
size_t len,
739+
uint16_t timeout,
740+
uint8_t format[3]) {
741+
UNUSED(timeout);
742+
743+
furi_assert(seader);
744+
furi_assert(buffer);
745+
furi_assert(mfc_poller);
746+
SeaderWorker* seader_worker = seader->worker;
747+
SeaderUartBridge* seader_uart = seader_worker->uart;
748+
749+
BitBuffer* tx_buffer = bit_buffer_alloc(len);
750+
BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
751+
752+
do {
753+
if(format[0] == 0x00 && format[1] == 0xC0 && format[2] == 0x00) {
754+
bit_buffer_append_bytes(tx_buffer, buffer, len);
755+
MfClassicError error =
756+
mf_classic_poller_send_frame(mfc_poller, tx_buffer, rx_buffer, MF_CLASSIC_FWT_FC);
757+
if(error != MfClassicErrorNone) {
758+
FURI_LOG_W(TAG, "mf_classic_poller_send_frame error %d", error);
759+
seader_worker->stage = SeaderPollerEventTypeFail;
760+
break;
761+
}
762+
} else if(
763+
(format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x40) ||
764+
(format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x24) ||
765+
(format[0] == 0x00 && format[1] == 0x00 && format[2] == 0x44)) {
766+
memset(display, 0, sizeof(display));
767+
for(uint8_t i = 0; i < len; i++) {
768+
snprintf(display + (i * 2), sizeof(display), "%02x", buffer[i]);
769+
}
770+
FURI_LOG_D(TAG, "NFC Send with parity %d: %s", len, display);
771+
772+
// Only handles message up to 8 data bytes
773+
uint8_t tx_parity = 0;
774+
uint8_t len_without_parity = len - 1;
775+
776+
// Don't forget to swap the bits of buffer[8]
777+
for(size_t i = 0; i < len; i++) {
778+
bit_lib_reverse_bits(buffer + i, 0, 8);
779+
}
780+
781+
// Pull out parity bits
782+
for(size_t i = 0; i < len_without_parity; i++) {
783+
bool val = bit_lib_get_bit(buffer + i + 1, i);
784+
bit_lib_set_bit(&tx_parity, i, val);
785+
}
786+
787+
for(size_t i = 0; i < len_without_parity; i++) {
788+
buffer[i] = (buffer[i] << i) | (buffer[i + 1] >> (8 - i));
789+
}
790+
bit_buffer_append_bytes(tx_buffer, buffer, len_without_parity);
791+
792+
for(size_t i = 0; i < len_without_parity; i++) {
793+
bit_lib_reverse_bits(buffer + i, 0, 8);
794+
bit_buffer_set_byte_with_parity(
795+
tx_buffer, i, buffer[i], bit_lib_get_bit(&tx_parity, i));
796+
}
797+
798+
memset(display, 0, sizeof(display));
799+
for(uint8_t i = 0; i < bit_buffer_get_size_bytes(tx_buffer); i++) {
800+
snprintf(
801+
display + (i * 2), sizeof(display), "%02x", bit_buffer_get_byte(tx_buffer, i));
802+
}
803+
FURI_LOG_D(
804+
TAG,
805+
"NFC Send without parity %d: %s [%02x]",
806+
bit_buffer_get_size_bytes(tx_buffer),
807+
display,
808+
tx_parity);
809+
810+
MfClassicError error = mf_classic_poller_send_custom_parity_frame(
811+
mfc_poller, tx_buffer, rx_buffer, MF_CLASSIC_FWT_FC);
812+
if(error != MfClassicErrorNone) {
813+
FURI_LOG_W(TAG, "mf_classic_poller_send_encrypted_frame error %d", error);
814+
seader_worker->stage = SeaderPollerEventTypeFail;
815+
break;
816+
}
817+
818+
size_t length = bit_buffer_get_size_bytes(rx_buffer);
819+
const uint8_t* rx_parity = bit_buffer_get_parity(rx_buffer);
820+
821+
memset(display, 0, sizeof(display));
822+
for(uint8_t i = 0; i < length; i++) {
823+
snprintf(
824+
display + (i * 2), sizeof(display), "%02x", bit_buffer_get_byte(rx_buffer, i));
825+
}
826+
FURI_LOG_D(
827+
TAG, "NFC Response without parity %d: %s [%02x]", length, display, rx_parity[0]);
828+
829+
uint8_t with_parity[SEADER_POLLER_MAX_BUFFER_SIZE];
830+
memset(with_parity, 0, sizeof(with_parity));
831+
832+
for(size_t i = 0; i < length; i++) {
833+
uint8_t b = bit_buffer_get_byte(rx_buffer, i);
834+
bit_lib_reverse_bits(&b, 0, 8);
835+
bit_buffer_set_byte(rx_buffer, i, b);
836+
}
837+
838+
length = length + (length / 8) + 1;
839+
840+
uint8_t parts = 1 + length / 9;
841+
for(size_t p = 0; p < parts; p++) {
842+
uint8_t doffset = p * 9;
843+
uint8_t soffset = p * 8;
844+
845+
for(size_t i = 0; i < 9; i++) {
846+
with_parity[i + doffset] = bit_buffer_get_byte(rx_buffer, i + soffset) >> i;
847+
if(i > 0) {
848+
with_parity[i + doffset] |= bit_buffer_get_byte(rx_buffer, i + soffset - 1)
849+
<< (9 - i);
850+
}
851+
852+
if(i > 0) {
853+
bool val = bit_lib_get_bit(rx_parity, i - 1);
854+
bit_lib_set_bit(with_parity + i, i - 1, val);
855+
}
856+
}
857+
}
858+
859+
for(size_t i = 0; i < length; i++) {
860+
bit_lib_reverse_bits(with_parity + i, 0, 8);
861+
}
862+
863+
bit_buffer_copy_bytes(rx_buffer, with_parity, length);
864+
865+
memset(display, 0, sizeof(display));
866+
for(uint8_t i = 0; i < length; i++) {
867+
snprintf(
868+
display + (i * 2), sizeof(display), "%02x", bit_buffer_get_byte(rx_buffer, i));
869+
}
870+
FURI_LOG_D(
871+
TAG, "NFC Response with parity %d: %s [%02x]", length, display, rx_parity[0]);
872+
873+
} else {
874+
FURI_LOG_W(TAG, "UNHANDLED FORMAT");
875+
}
876+
877+
seader_send_nfc_rx(
878+
seader_uart,
879+
(uint8_t*)bit_buffer_get_data(rx_buffer),
880+
bit_buffer_get_size_bytes(rx_buffer));
881+
882+
} while(false);
883+
bit_buffer_free(tx_buffer);
884+
bit_buffer_free(rx_buffer);
885+
}
886+
731887
void seader_parse_nfc_command_transmit(
732888
Seader* seader,
733889
NFCSend_t* nfcSend,
@@ -757,13 +913,23 @@ void seader_parse_nfc_command_transmit(
757913
seader_iso15693_transmit(
758914
seader, spc->picopass_poller, nfcSend->data.buf, nfcSend->data.size);
759915
} else if(frameProtocol == FrameProtocol_nfc) {
760-
seader_iso14443a_transmit(
761-
seader,
762-
spc->iso14443_4a_poller,
763-
nfcSend->data.buf,
764-
nfcSend->data.size,
765-
(uint16_t)timeOut,
766-
nfcSend->format->buf);
916+
if(spc->iso14443_4a_poller) {
917+
seader_iso14443a_transmit(
918+
seader,
919+
spc->iso14443_4a_poller,
920+
nfcSend->data.buf,
921+
nfcSend->data.size,
922+
(uint16_t)timeOut,
923+
nfcSend->format->buf);
924+
} else if(spc->mfc_poller) {
925+
seader_mfc_transmit(
926+
seader,
927+
spc->mfc_poller,
928+
nfcSend->data.buf,
929+
nfcSend->data.size,
930+
(uint16_t)timeOut,
931+
nfcSend->format->buf);
932+
}
767933
} else {
768934
FURI_LOG_W(TAG, "unknown frame protocol %lx", frameProtocol);
769935
}
@@ -911,18 +1077,22 @@ NfcCommand seader_worker_card_detect(
9111077
OCTET_STRING_t atqa_string = {.buf = atqa, .size = 2};
9121078
uint8_t protocol_bytes[] = {0x00, 0x00};
9131079

914-
if(sak == 0 && atqa == NULL) {
1080+
if(sak == 0 && atqa == NULL) { // picopass
9151081
protocol_bytes[1] = FrameProtocol_iclass;
9161082
OCTET_STRING_fromBuf(
9171083
&cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes));
9181084
memcpy(credential->diversifier, uid, uid_len);
9191085
credential->diversifier_len = uid_len;
9201086
credential->isDesfire = false;
921-
} else {
1087+
} else if(atqa == 0) { // MFC
1088+
protocol_bytes[1] = FrameProtocol_nfc;
1089+
OCTET_STRING_fromBuf(
1090+
&cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes));
1091+
cardDetails->sak = &sak_string;
1092+
} else { // type 4
9221093
protocol_bytes[1] = FrameProtocol_nfc;
9231094
OCTET_STRING_fromBuf(
9241095
&cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes));
925-
9261096
cardDetails->sak = &sak_string;
9271097
cardDetails->atqa = &atqa_string;
9281098
credential->isDesfire = seader_mf_df_check_card_type(atqa[0], atqa[1], sak);

scenes/seader_scene_config.h

+1
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ ADD_SCENE(seader, credential_info, CredentialInfo)
1616
ADD_SCENE(seader, sam_info, SamInfo)
1717
ADD_SCENE(seader, virtual_credential, VirtualCredential)
1818
ADD_SCENE(seader, formats, Formats)
19+
ADD_SCENE(seader, read_mfc, ReadMfc)

scenes/seader_scene_read_mfc.c

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#include "../seader_i.h"
2+
#include <dolphin/dolphin.h>
3+
4+
#define TAG "SceneReadNfc"
5+
6+
void seader_scene_read_mfc_on_enter(void* context) {
7+
Seader* seader = context;
8+
dolphin_deed(DolphinDeedNfcRead);
9+
10+
// Setup view
11+
Popup* popup = seader->popup;
12+
popup_set_header(popup, "Detecting\nMFC\ncard", 68, 30, AlignLeft, AlignTop);
13+
popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
14+
15+
// Start worker
16+
view_dispatcher_switch_to_view(seader->view_dispatcher, SeaderViewPopup);
17+
18+
seader->poller = nfc_poller_alloc(seader->nfc, NfcProtocolMfClassic);
19+
20+
seader->worker->stage = SeaderPollerEventTypeCardDetect;
21+
seader_credential_clear(seader->credential);
22+
seader->credential->type = SeaderCredentialTypeMifareClassic;
23+
24+
FURI_LOG_W(TAG, "Start poller");
25+
nfc_poller_start(seader->poller, seader_worker_poller_callback_mfc, seader);
26+
27+
seader_blink_start(seader);
28+
}
29+
30+
bool seader_scene_read_mfc_on_event(void* context, SceneManagerEvent event) {
31+
Seader* seader = context;
32+
bool consumed = false;
33+
34+
if(event.type == SceneManagerEventTypeCustom) {
35+
if(event.event == SeaderCustomEventWorkerExit) {
36+
seader->credential->type = SeaderCredentialTypeMifareClassic;
37+
scene_manager_next_scene(seader->scene_manager, SeaderSceneReadCardSuccess);
38+
consumed = true;
39+
} else if(event.event == SeaderCustomEventPollerSuccess) {
40+
seader->credential->type = SeaderCredentialTypeMifareClassic;
41+
scene_manager_next_scene(seader->scene_manager, SeaderSceneReadCardSuccess);
42+
consumed = true;
43+
}
44+
} else if(event.type == SceneManagerEventTypeBack) {
45+
scene_manager_search_and_switch_to_previous_scene(
46+
seader->scene_manager, SeaderSceneSamPresent);
47+
consumed = true;
48+
}
49+
50+
return consumed;
51+
}
52+
53+
void seader_scene_read_mfc_on_exit(void* context) {
54+
Seader* seader = context;
55+
56+
if(seader->poller) {
57+
nfc_poller_stop(seader->poller);
58+
nfc_poller_free(seader->poller);
59+
}
60+
61+
// Clear view
62+
popup_reset(seader->popup);
63+
64+
seader_blink_stop(seader);
65+
}

scenes/seader_scene_sam_present.c

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
enum SubmenuIndex {
33
SubmenuIndexReadPicopass,
44
SubmenuIndexRead14a,
5+
SubmenuIndexReadMfc,
56
SubmenuIndexSaved,
67
SubmenuIndexSamInfo,
78
SubmenuIndexFwVersion,
@@ -33,6 +34,12 @@ void seader_scene_sam_present_on_update(void* context) {
3334
SubmenuIndexRead14a,
3435
seader_scene_sam_present_submenu_callback,
3536
seader);
37+
submenu_add_item(
38+
submenu,
39+
"Read MFC",
40+
SubmenuIndexReadMfc,
41+
seader_scene_sam_present_submenu_callback,
42+
seader);
3643
submenu_add_item(
3744
submenu, "Saved", SubmenuIndexSaved, seader_scene_sam_present_submenu_callback, seader);
3845

@@ -75,6 +82,11 @@ bool seader_scene_sam_present_on_event(void* context, SceneManagerEvent event) {
7582
seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexRead14a);
7683
scene_manager_next_scene(seader->scene_manager, SeaderSceneRead14a);
7784
consumed = true;
85+
} else if(event.event == SubmenuIndexReadMfc) {
86+
scene_manager_set_scene_state(
87+
seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexReadMfc);
88+
scene_manager_next_scene(seader->scene_manager, SeaderSceneReadMfc);
89+
consumed = true;
7890
} else if(event.event == SubmenuIndexSamInfo) {
7991
scene_manager_set_scene_state(
8092
seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexSamInfo);

seader_bridge.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <furi.h>
1010
#include <furi_hal.h>
1111

12-
#define SEADER_UART_RX_BUF_SIZE (256)
12+
#define SEADER_UART_RX_BUF_SIZE (128)
1313

1414
typedef struct {
1515
uint8_t uart_ch;

seader_i.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@
2424
#include <input/input.h>
2525

2626
#include <lib/nfc/nfc.h>
27-
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a.h>
28-
2927
#include <nfc/nfc_poller.h>
30-
3128
#include <nfc/nfc_device.h>
3229
#include <nfc/helpers/nfc_data_generator.h>
3330

@@ -124,6 +121,7 @@ struct Seader {
124121

125122
struct SeaderPollerContainer {
126123
Iso14443_4aPoller* iso14443_4a_poller;
124+
MfClassicPoller* mfc_poller;
127125
PicopassPoller* picopass_poller;
128126
};
129127

0 commit comments

Comments
 (0)