keys.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. #include "../metroflip_i.h"
  2. #include "keys.h"
  3. #include <bit_lib.h>
  4. #include <nfc/protocols/mf_classic/mf_classic.h>
  5. #include <nfc/protocols/mf_classic/mf_classic_poller.h>
  6. #include <nfc/nfc.h>
  7. #include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
  8. #include <string.h>
  9. #define TAG "keys_check"
  10. const MfClassicKeyPair troika_1k_keys[16] = {
  11. {.a = 0xa0a1a2a3a4a5, .b = 0xfbf225dc5d58},
  12. {.a = 0xa82607b01c0d, .b = 0x2910989b6880},
  13. {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99},
  14. {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99},
  15. {.a = 0x73068f118c13, .b = 0x2b7f3253fac5},
  16. {.a = 0xfbc2793d540b, .b = 0xd3a297dc2698},
  17. {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99},
  18. {.a = 0xae3d65a3dad4, .b = 0x0f1c63013dba},
  19. {.a = 0xa73f5dc1d333, .b = 0xe35173494a81},
  20. {.a = 0x69a32f1c2f19, .b = 0x6b8bd9860763},
  21. {.a = 0x9becdf3d9273, .b = 0xf8493407799d},
  22. {.a = 0x08b386463229, .b = 0x5efbaecef46b},
  23. {.a = 0xcd4c61c26e3d, .b = 0x31c7610de3b0},
  24. {.a = 0xa82607b01c0d, .b = 0x2910989b6880},
  25. {.a = 0x0e8f64340ba4, .b = 0x4acec1205d75},
  26. {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99},
  27. };
  28. const MfClassicKeyPair troika_4k_keys[40] = {
  29. {.a = 0xEC29806D9738, .b = 0xFBF225DC5D58}, //1
  30. {.a = 0xA0A1A2A3A4A5, .b = 0x7DE02A7F6025}, //2
  31. {.a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, //3
  32. {.a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, //4
  33. {.a = 0x73068F118C13, .b = 0x2B7F3253FAC5}, //5
  34. {.a = 0xFBC2793D540B, .b = 0xD3A297DC2698}, //6
  35. {.a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, //7
  36. {.a = 0xAE3D65A3DAD4, .b = 0x0F1C63013DBA}, //8
  37. {.a = 0xA73F5DC1D333, .b = 0xE35173494A81}, //9
  38. {.a = 0x69A32F1C2F19, .b = 0x6B8BD9860763}, //10
  39. {.a = 0x9BECDF3D9273, .b = 0xF8493407799D}, //11
  40. {.a = 0x08B386463229, .b = 0x5EFBAECEF46B}, //12
  41. {.a = 0xCD4C61C26E3D, .b = 0x31C7610DE3B0}, //13
  42. {.a = 0xA82607B01C0D, .b = 0x2910989B6880}, //14
  43. {.a = 0x0E8F64340BA4, .b = 0x4ACEC1205D75}, //15
  44. {.a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, //16
  45. {.a = 0x6B02733BB6EC, .b = 0x7038CD25C408}, //17
  46. {.a = 0x403D706BA880, .b = 0xB39D19A280DF}, //18
  47. {.a = 0xC11F4597EFB5, .b = 0x70D901648CB9}, //19
  48. {.a = 0x0DB520C78C1C, .b = 0x73E5B9D9D3A4}, //20
  49. {.a = 0x3EBCE0925B2F, .b = 0x372CC880F216}, //21
  50. {.a = 0x16A27AF45407, .b = 0x9868925175BA}, //22
  51. {.a = 0xABA208516740, .b = 0xCE26ECB95252}, //23
  52. {.a = 0xCD64E567ABCD, .b = 0x8F79C4FD8A01}, //24
  53. {.a = 0x764CD061F1E6, .b = 0xA74332F74994}, //25
  54. {.a = 0x1CC219E9FEC1, .b = 0xB90DE525CEB6}, //26
  55. {.a = 0x2FE3CB83EA43, .b = 0xFBA88F109B32}, //27
  56. {.a = 0x07894FFEC1D6, .b = 0xEFCB0E689DB3}, //28
  57. {.a = 0x04C297B91308, .b = 0xC8454C154CB5}, //29
  58. {.a = 0x7A38E3511A38, .b = 0xAB16584C972A}, //30
  59. {.a = 0x7545DF809202, .b = 0xECF751084A80}, //31
  60. {.a = 0x5125974CD391, .b = 0xD3EAFB5DF46D}, //32
  61. {.a = 0x7A86AA203788, .b = 0xE41242278CA2}, //33
  62. {.a = 0xAFCEF64C9913, .b = 0x9DB96DCA4324}, //34
  63. {.a = 0x04EAA462F70B, .b = 0xAC17B93E2FAE}, //35
  64. {.a = 0xE734C210F27E, .b = 0x29BA8C3E9FDA}, //36
  65. {.a = 0xD5524F591EED, .b = 0x5DAF42861B4D}, //37
  66. {.a = 0xE4821A377B75, .b = 0xE8709E486465}, //38
  67. {.a = 0x518DC6EEA089, .b = 0x97C64AC98CA4}, //39
  68. {.a = 0xBB52F8CCE07F, .b = 0x6B6119752C70}, //40
  69. };
  70. const uint8_t SMARTRIDER_STANDARD_KEYS[3][6] = {
  71. {0x20, 0x31, 0xD1, 0xE5, 0x7A, 0x3B},
  72. {0x4C, 0xA6, 0x02, 0x9F, 0x94, 0x73},
  73. {0x19, 0x19, 0x53, 0x98, 0xE3, 0x2F}};
  74. const MfClassicKeyPair charliecard_1k_keys[16] = {
  75. {.a = 0x3060206F5B0A, .b = 0xF1B9F5669CC8},
  76. {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
  77. {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
  78. {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
  79. {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
  80. {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
  81. {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
  82. {.a = 0x5EC39B022F2B, .b = 0xF662248E7E89},
  83. {.a = 0x3A09594C8587, .b = 0x62387B8D250D},
  84. {.a = 0xF238D78FF48F, .b = 0x9DC282D46217},
  85. {.a = 0xAFD0BA94D624, .b = 0x92EE4DC87191},
  86. {.a = 0xB35A0E4ACC09, .b = 0x756EF55E2507},
  87. {.a = 0x447AB7FD5A6B, .b = 0x932B9CB730EF},
  88. {.a = 0x1F1A0A111B5B, .b = 0xAD9E0A1CA2F7},
  89. {.a = 0xD58023BA2BDC, .b = 0x62CED42A6D87},
  90. {.a = 0x2548A443DF28, .b = 0x2ED3B15E7C0F},
  91. };
  92. const MfClassicKeyPair bip_1k_keys[16] = {
  93. {.a = 0x3a42f33af429, .b = 0x1fc235ac1309},
  94. {.a = 0x6338a371c0ed, .b = 0x243f160918d1},
  95. {.a = 0xf124c2578ad0, .b = 0x9afc42372af1},
  96. {.a = 0x32ac3b90ac13, .b = 0x682d401abb09},
  97. {.a = 0x4ad1e273eaf1, .b = 0x067db45454a9},
  98. {.a = 0xe2c42591368a, .b = 0x15fc4c7613fe},
  99. {.a = 0x2a3c347a1200, .b = 0x68d30288910a},
  100. {.a = 0x16f3d5ab1139, .b = 0xf59a36a2546d},
  101. {.a = 0x937a4fff3011, .b = 0x64e3c10394c2},
  102. {.a = 0x35c3d2caee88, .b = 0xb736412614af},
  103. {.a = 0x693143f10368, .b = 0x324f5df65310},
  104. {.a = 0xa3f97428dd01, .b = 0x643fb6de2217},
  105. {.a = 0x63f17a449af0, .b = 0x82f435dedf01},
  106. {.a = 0xc4652c54261c, .b = 0x0263de1278f3},
  107. {.a = 0xd49e2826664f, .b = 0x51284c3686a6},
  108. {.a = 0x3df14c8000a1, .b = 0x6a470d54127c},
  109. };
  110. const MfClassicKeyPair metromoney_1k_keys[16] = {
  111. {.a = 0x2803BCB0C7E1, .b = 0x4FA9EB49F75E},
  112. {.a = 0x9C616585E26D, .b = 0xD1C71E590D16},
  113. {.a = 0x9C616585E26D, .b = 0xA160FCD5EC4C},
  114. {.a = 0x9C616585E26D, .b = 0xA160FCD5EC4C},
  115. {.a = 0x9C616585E26D, .b = 0xA160FCD5EC4C},
  116. {.a = 0x9C616585E26D, .b = 0xA160FCD5EC4C},
  117. {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
  118. {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
  119. {.a = 0x112233445566, .b = 0x361A62F35BC9},
  120. {.a = 0x112233445566, .b = 0x361A62F35BC9},
  121. {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
  122. {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
  123. {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
  124. {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
  125. {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
  126. {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF},
  127. };
  128. static bool charliecard_verify(Nfc* nfc) {
  129. bool verified = false;
  130. FURI_LOG_I(TAG, "verifying charliecard..");
  131. do {
  132. const uint8_t verify_sector = 1;
  133. const uint8_t verify_block = mf_classic_get_first_block_num_of_sector(verify_sector) + 1;
  134. FURI_LOG_I(TAG, "Verifying sector %u", verify_sector);
  135. MfClassicKey key = {0};
  136. bit_lib_num_to_bytes_be(
  137. charliecard_1k_keys[verify_sector].a, COUNT_OF(key.data), key.data);
  138. MfClassicAuthContext auth_context;
  139. MfClassicError error =
  140. mf_classic_poller_sync_auth(nfc, verify_block, &key, MfClassicKeyTypeA, &auth_context);
  141. if(error != MfClassicErrorNone) {
  142. FURI_LOG_I(TAG, "Failed to read block %u: %d", verify_block, error);
  143. break;
  144. }
  145. verified = true;
  146. } while(false);
  147. return verified;
  148. }
  149. bool bip_verify(Nfc* nfc) {
  150. bool verified = false;
  151. do {
  152. const uint8_t verify_sector = 0;
  153. uint8_t block_num = mf_classic_get_first_block_num_of_sector(verify_sector);
  154. FURI_LOG_I(TAG, "Verifying sector %u", verify_sector);
  155. MfClassicKey key = {};
  156. bit_lib_num_to_bytes_be(bip_1k_keys[0].a, COUNT_OF(key.data), key.data);
  157. MfClassicAuthContext auth_ctx = {};
  158. MfClassicError error =
  159. mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx);
  160. if(error != MfClassicErrorNone) {
  161. FURI_LOG_I(TAG, "Failed to read block %u: %d", block_num, error);
  162. break;
  163. }
  164. verified = true;
  165. } while(false);
  166. return verified;
  167. }
  168. static bool metromoney_verify(Nfc* nfc) {
  169. bool verified = false;
  170. do {
  171. const uint8_t ticket_sector_number = 1;
  172. const uint8_t ticket_block_number =
  173. mf_classic_get_first_block_num_of_sector(ticket_sector_number) + 1;
  174. FURI_LOG_D(TAG, "Verifying sector %u", ticket_sector_number);
  175. MfClassicKey key = {0};
  176. bit_lib_num_to_bytes_be(
  177. metromoney_1k_keys[ticket_sector_number].a, COUNT_OF(key.data), key.data);
  178. MfClassicAuthContext auth_context;
  179. MfClassicError error = mf_classic_poller_sync_auth(
  180. nfc, ticket_block_number, &key, MfClassicKeyTypeA, &auth_context);
  181. if(error != MfClassicErrorNone) {
  182. FURI_LOG_D(TAG, "Failed to read block %u: %d", ticket_block_number, error);
  183. break;
  184. }
  185. verified = true;
  186. } while(false);
  187. return verified;
  188. }
  189. static bool smartrider_authenticate_and_read(
  190. Nfc* nfc,
  191. uint8_t sector,
  192. const uint8_t* key,
  193. MfClassicKeyType key_type,
  194. MfClassicBlock* block_data) {
  195. MfClassicKey mf_key;
  196. memcpy(mf_key.data, key, 6);
  197. uint8_t block = mf_classic_get_first_block_num_of_sector(sector);
  198. if(mf_classic_poller_sync_auth(nfc, block, &mf_key, key_type, NULL) != MfClassicErrorNone) {
  199. FURI_LOG_D(TAG, "Authentication failed for sector %d key type %d", sector, key_type);
  200. return false;
  201. }
  202. if(mf_classic_poller_sync_read_block(nfc, block, &mf_key, key_type, block_data) !=
  203. MfClassicErrorNone) {
  204. FURI_LOG_D(TAG, "Read failed for sector %d", sector);
  205. return false;
  206. }
  207. return true;
  208. }
  209. static bool smartrider_verify(Nfc* nfc) {
  210. furi_assert(nfc);
  211. MfClassicBlock block_data;
  212. for(int i = 0; i < 3; i++) {
  213. if(!smartrider_authenticate_and_read(
  214. nfc,
  215. i * 6,
  216. SMARTRIDER_STANDARD_KEYS[i],
  217. i % 2 == 0 ? MfClassicKeyTypeA : MfClassicKeyTypeB,
  218. &block_data) ||
  219. memcmp(block_data.data, SMARTRIDER_STANDARD_KEYS[i], 6) != 0) {
  220. FURI_LOG_D(TAG, "Authentication or key mismatch for key %d", i);
  221. return false;
  222. }
  223. }
  224. FURI_LOG_I(TAG, "SmartRider card verified");
  225. return true;
  226. }
  227. static bool troika_get_card_config(TroikaCardConfig* config, MfClassicType type) {
  228. bool success = true;
  229. if(type == MfClassicType1k) {
  230. config->data_sector = 11;
  231. config->keys = troika_1k_keys;
  232. } else if(type == MfClassicType4k) {
  233. config->data_sector = 8; // Further testing needed
  234. config->keys = troika_4k_keys;
  235. } else {
  236. success = false;
  237. }
  238. return success;
  239. }
  240. static bool troika_verify_type(Nfc* nfc, MfClassicType type) {
  241. bool verified = false;
  242. do {
  243. TroikaCardConfig cfg = {};
  244. if(!troika_get_card_config(&cfg, type)) break;
  245. const uint8_t block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector);
  246. FURI_LOG_D(TAG, "Verifying sector %lu", cfg.data_sector);
  247. MfClassicKey key = {0};
  248. bit_lib_num_to_bytes_be(cfg.keys[cfg.data_sector].a, COUNT_OF(key.data), key.data);
  249. MfClassicAuthContext auth_context;
  250. MfClassicError error =
  251. mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context);
  252. if(error != MfClassicErrorNone) {
  253. FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error);
  254. break;
  255. }
  256. FURI_LOG_D(TAG, "Verify success!");
  257. verified = true;
  258. } while(false);
  259. return verified;
  260. }
  261. static bool troika_verify(Nfc* nfc) {
  262. return troika_verify_type(nfc, MfClassicType1k) || troika_verify_type(nfc, MfClassicType4k);
  263. }
  264. CardType determine_card_type(Nfc* nfc) {
  265. FURI_LOG_I(TAG, "checking keys..");
  266. UNUSED(bip_verify);
  267. if(bip_verify(nfc)) {
  268. return CARD_TYPE_METROMONEY;
  269. } else if(metromoney_verify(nfc)) {
  270. return CARD_TYPE_METROMONEY;
  271. } else if(smartrider_verify(nfc)) {
  272. return CARD_TYPE_SMARTRIDER;
  273. } else if(troika_verify(nfc)) {
  274. return CARD_TYPE_TROIKA;
  275. } else if(charliecard_verify(nfc)) {
  276. return CARD_TYPE_CHARLIECARD;
  277. } else {
  278. FURI_LOG_I(TAG, "its unknown");
  279. return CARD_TYPE_UNKNOWN;
  280. }
  281. }