wiegand.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include "interface.h"
  2. #include <lib/bit_lib/bit_lib.h>
  3. #include <flipper_application/flipper_application.h>
  4. /*
  5. * Huge thanks to the proxmark codebase:
  6. * https://github.com/RfidResearchGroup/proxmark3/blob/master/client/src/wiegand_formats.c
  7. */
  8. // Structure for packed wiegand messages
  9. // Always align lowest value (last transmitted) bit to ordinal position 0 (lowest valued bit bottom)
  10. typedef struct {
  11. uint8_t Length; // Number of encoded bits in wiegand message (excluding headers and preamble)
  12. uint32_t Top; // Bits in x<<64 positions
  13. uint32_t Mid; // Bits in x<<32 positions
  14. uint32_t Bot; // Lowest ordinal positions
  15. } wiegand_message_t;
  16. static inline uint8_t oddparity32(uint32_t x) {
  17. return bit_lib_test_parity_32(x, BitLibParityOdd);
  18. }
  19. static inline uint8_t evenparity32(uint32_t x) {
  20. return bit_lib_test_parity_32(x, BitLibParityEven);
  21. }
  22. static int wiegand_C1k35s_parse(uint8_t bit_length, uint64_t bits, FuriString* description) {
  23. if(bit_length != 35) {
  24. return 0;
  25. }
  26. wiegand_message_t value;
  27. value.Mid = bits >> 32;
  28. value.Bot = bits;
  29. wiegand_message_t* packed = &value;
  30. uint32_t cn = (packed->Bot >> 1) & 0x000FFFFF;
  31. uint32_t fc = ((packed->Mid & 1) << 11) | ((packed->Bot >> 21));
  32. bool valid = (evenparity32((packed->Mid & 0x1) ^ (packed->Bot & 0xB6DB6DB6)) ==
  33. ((packed->Mid >> 1) & 1)) &&
  34. (oddparity32((packed->Mid & 0x3) ^ (packed->Bot & 0x6DB6DB6C)) ==
  35. ((packed->Bot >> 0) & 1)) &&
  36. (oddparity32((packed->Mid & 0x3) ^ (packed->Bot & 0xFFFFFFFF)) ==
  37. ((packed->Mid >> 2) & 1));
  38. if(valid) {
  39. furi_string_cat_printf(description, "C1k35s\nFC: %ld CN: %ld\n", fc, cn);
  40. return 1;
  41. }
  42. return 0;
  43. }
  44. static int wiegand_h10301_parse(uint8_t bit_length, uint64_t bits, FuriString* description) {
  45. if(bit_length != 26) {
  46. return 0;
  47. }
  48. //E XXXX XXXX XXXX
  49. //XXXX XXXX XXXX O
  50. uint32_t eBitMask = 0x02000000;
  51. uint32_t oBitMask = 0x00000001;
  52. uint32_t eParityMask = 0x01FFE000;
  53. uint32_t oParityMask = 0x00001FFE;
  54. uint8_t eBit = (eBitMask & bits) >> 25;
  55. uint8_t oBit = (oBitMask & bits) >> 0;
  56. bool eParity = bit_lib_test_parity_32((bits & eParityMask) >> 13, BitLibParityEven) ==
  57. (eBit == 1);
  58. bool oParity = bit_lib_test_parity_32((bits & oParityMask) >> 1, BitLibParityOdd) ==
  59. (oBit == 1);
  60. FURI_LOG_D(
  61. PLUGIN_APP_ID,
  62. "eBit: %d, oBit: %d, eParity: %d, oParity: %d",
  63. eBit,
  64. oBit,
  65. eParity,
  66. oParity);
  67. if(eParity && oParity) {
  68. uint32_t cnMask = 0x1FFFE;
  69. uint16_t cn = ((bits & cnMask) >> 1);
  70. uint32_t fcMask = 0x1FE0000;
  71. uint16_t fc = ((bits & fcMask) >> 17);
  72. furi_string_cat_printf(description, "H10301\nFC: %d CN: %d\n", fc, cn);
  73. return 1;
  74. }
  75. return 0;
  76. }
  77. static int wiegand_format_count(uint8_t bit_length, uint64_t bits) {
  78. UNUSED(bit_length);
  79. UNUSED(bits);
  80. int count = 0;
  81. FuriString* ignore = furi_string_alloc();
  82. count += wiegand_h10301_parse(bit_length, bits, ignore);
  83. count += wiegand_C1k35s_parse(bit_length, bits, ignore);
  84. furi_string_free(ignore);
  85. FURI_LOG_I(PLUGIN_APP_ID, "count: %i", count);
  86. return count;
  87. }
  88. static void wiegand_format_description(
  89. uint8_t bit_length,
  90. uint64_t bits,
  91. size_t index,
  92. FuriString* description) {
  93. FURI_LOG_I(PLUGIN_APP_ID, "description %d", index);
  94. UNUSED(bit_length);
  95. UNUSED(bits);
  96. size_t i = 0;
  97. i += wiegand_h10301_parse(bit_length, bits, description);
  98. if(i - 1 == index) {
  99. return;
  100. }
  101. i += wiegand_C1k35s_parse(bit_length, bits, description);
  102. if(i - 1 == index) {
  103. return;
  104. }
  105. furi_string_cat_printf(description, "[%i] <name> FC: CN:", index);
  106. }
  107. /* Actual implementation of app<>plugin interface */
  108. static const PluginWiegand plugin_wiegand = {
  109. .name = "Plugin Wiegand",
  110. .count = &wiegand_format_count,
  111. .description = &wiegand_format_description,
  112. };
  113. /* Plugin descriptor to comply with basic plugin specification */
  114. static const FlipperAppPluginDescriptor plugin_wiegand_descriptor = {
  115. .appid = PLUGIN_APP_ID,
  116. .ep_api_version = PLUGIN_API_VERSION,
  117. .entry_point = &plugin_wiegand,
  118. };
  119. /* Plugin entry point - must return a pointer to const descriptor */
  120. const FlipperAppPluginDescriptor* plugin_wiegand_ep(void) {
  121. return &plugin_wiegand_descriptor;
  122. }