1010#include <furi_hal_rtc.h>
1111#include <core/check.h>
1212
13- #define TAG "Social Moscow "
13+ #define TAG "Social_Moscow "
1414
1515typedef struct {
1616 uint64_t a ;
@@ -22,6 +22,24 @@ typedef struct {
2222 uint32_t data_sector ;
2323} SocialMoscowCardConfig ;
2424
25+ static const MfClassicKeyPair social_moscow_1k_keys [] = {
26+ {.a = 0xa0a1a2a3a4a5 , .b = 0x7de02a7f6025 },
27+ {.a = 0x2735fc181807 , .b = 0xbf23a53c1f63 },
28+ {.a = 0x2aba9519f574 , .b = 0xcb9a1f2d7368 },
29+ {.a = 0x84fd7f7a12b6 , .b = 0xc7c0adb3284f },
30+ {.a = 0x73068f118c13 , .b = 0x2b7f3253fac5 },
31+ {.a = 0x186d8c4b93f9 , .b = 0x9f131d8c2057 },
32+ {.a = 0x3a4bba8adaf0 , .b = 0x67362d90f973 },
33+ {.a = 0x8765b17968a2 , .b = 0x6202a38f69e2 },
34+ {.a = 0x40ead80721ce , .b = 0x100533b89331 },
35+ {.a = 0x0db5e6523f7c , .b = 0x653a87594079 },
36+ {.a = 0x51119dae5216 , .b = 0xd8a274b2e026 },
37+ {.a = 0x51119dae5216 , .b = 0xd8a274b2e026 },
38+ {.a = 0x51119dae5216 , .b = 0xd8a274b2e026 },
39+ {.a = 0x2aba9519f574 , .b = 0xcb9a1f2d7368 },
40+ {.a = 0x84fd7f7a12b6 , .b = 0xc7c0adb3284f },
41+ {.a = 0xa0a1a2a3a4a5 , .b = 0x7de02a7f6025 }};
42+
2543static const MfClassicKeyPair social_moscow_4k_keys [] = {
2644 {.a = 0xa0a1a2a3a4a5 , .b = 0x7de02a7f6025 }, {.a = 0x2735fc181807 , .b = 0xbf23a53c1f63 },
2745 {.a = 0x2aba9519f574 , .b = 0xcb9a1f2d7368 }, {.a = 0x84fd7f7a12b6 , .b = 0xc7c0adb3284f },
@@ -511,7 +529,7 @@ void from_minutes_to_datetime(uint32_t minutes, FuriHalRtcDateTime* datetime, ui
511529bool parse_transport_block (const MfClassicBlock * block , FuriString * result ) {
512530 uint16_t transport_departament = bit_lib_get_bits_16 (block -> data , 0 , 10 );
513531
514- FURI_LOG_D (TAG , "Transport departament: %x" , transport_departament );
532+ FURI_LOG_I (TAG , "Transport departament: %x" , transport_departament );
515533
516534 uint16_t layout_type = bit_lib_get_bits_16 (block -> data , 52 , 4 );
517535 if (layout_type == 0xE ) {
@@ -520,7 +538,7 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) {
520538 layout_type = bit_lib_get_bits_16 (block -> data , 52 , 14 );
521539 }
522540
523- FURI_LOG_D (TAG , "Layout type %x" , layout_type );
541+ FURI_LOG_I (TAG , "Layout type %x" , layout_type );
524542
525543 uint16_t card_view = 0 ;
526544 uint16_t card_type = 0 ;
@@ -1444,8 +1462,10 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) {
14441462
14451463static bool social_moscow_get_card_config (SocialMoscowCardConfig * config , MfClassicType type ) {
14461464 bool success = true;
1447-
1448- if (type == MfClassicType4k ) {
1465+ if (type == MfClassicType1k ) {
1466+ config -> data_sector = 15 ;
1467+ config -> keys = social_moscow_1k_keys ;
1468+ } else if (type == MfClassicType4k ) {
14491469 config -> data_sector = 15 ;
14501470 config -> keys = social_moscow_4k_keys ;
14511471 } else {
@@ -1475,7 +1495,7 @@ static bool social_moscow_verify_type(Nfc* nfc, MfClassicType type) {
14751495 FURI_LOG_D (TAG , "Failed to read block %u: %d" , block_num , error );
14761496 break ;
14771497 }
1478-
1498+ FURI_LOG_D ( TAG , "Verify success!" );
14791499 verified = true;
14801500 } while (false);
14811501
@@ -1497,7 +1517,7 @@ static bool social_moscow_read(Nfc* nfc, NfcDevice* device) {
14971517 nfc_device_copy_data (device , NfcProtocolMfClassic , data );
14981518
14991519 do {
1500- MfClassicType type = MfClassicTypeMini ;
1520+ MfClassicType type = MfClassicType4k ;
15011521 MfClassicError error = mf_classic_poller_sync_detect_type (nfc , & type );
15021522 if (error != MfClassicErrorNone ) break ;
15031523
@@ -1537,6 +1557,17 @@ static bool social_moscow_parse(const NfcDevice* device, FuriString* parsed_data
15371557 bool parsed = false;
15381558
15391559 do {
1560+ // Verify card type
1561+ SocialMoscowCardConfig cfg = {};
1562+ if (!social_moscow_get_card_config (& cfg , data -> type )) break ;
1563+
1564+ // Verify key
1565+ const MfClassicSectorTrailer * sec_tr =
1566+ mf_classic_get_sector_trailer_by_sector (data , cfg .data_sector );
1567+
1568+ const uint64_t key = nfc_util_bytes2num (sec_tr -> key_a .data , COUNT_OF (sec_tr -> key_a .data ));
1569+ if (key != cfg .keys [cfg .data_sector ].a ) break ;
1570+
15401571 uint32_t card_code = bit_lib_get_bits_32 (data -> block [60 ].data , 8 , 24 );
15411572 uint8_t card_region = bit_lib_get_bits (data -> block [60 ].data , 32 , 8 );
15421573 uint64_t card_number = bit_lib_get_bits_64 (data -> block [60 ].data , 40 , 40 );
@@ -1549,27 +1580,29 @@ static bool social_moscow_parse(const NfcDevice* device, FuriString* parsed_data
15491580 FuriString * ground_result = furi_string_alloc ();
15501581 bool result1 = parse_transport_block (& data -> block [4 ], metro_result );
15511582 bool result2 = parse_transport_block (& data -> block [16 ], ground_result );
1552- if (result1 || result2 ) {
1553- furi_string_printf (
1554- parsed_data ,
1555- "\e#Social \ecard\nNumber: %lx %x %llx %x\nOMC: %llx\nValid for: %02x/%02x %02x%02x\n\e#Metro\n%s\n\e#Ground\n%s" ,
1556- card_code ,
1557- card_region ,
1558- card_number ,
1559- card_control ,
1560- omc_number ,
1561- month ,
1562- year ,
1563- data -> block [60 ].data [13 ],
1564- data -> block [60 ].data [14 ],
1565- furi_string_get_cstr (metro_result ),
1566- furi_string_get_cstr (ground_result ));
1567- furi_string_free (metro_result );
1568- furi_string_free (ground_result );
1569- parsed = true;
1570- } else {
1571- return false;
1583+ furi_string_cat_printf (
1584+ parsed_data ,
1585+ "\e#Social \ecard\nNumber: %lx %x %llx %x\nOMC: %llx\nValid for: %02x/%02x %02x%02x\n" ,
1586+ card_code ,
1587+ card_region ,
1588+ card_number ,
1589+ card_control ,
1590+ omc_number ,
1591+ month ,
1592+ year ,
1593+ data -> block [60 ].data [13 ],
1594+ data -> block [60 ].data [14 ]);
1595+ if (result1 ) {
1596+ furi_string_cat_printf (
1597+ parsed_data , "\e#Metro\n%s\n" , furi_string_get_cstr (metro_result ));
1598+ }
1599+ if (result2 ) {
1600+ furi_string_cat_printf (
1601+ parsed_data , "\e#Ground\n%s\n" , furi_string_get_cstr (ground_result ));
15721602 }
1603+ furi_string_free (ground_result );
1604+ furi_string_free (metro_result );
1605+ parsed = result1 || result2 ;
15731606 } while (false);
15741607
15751608 return parsed ;
0 commit comments