protocol_ioprox.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #include "protocol_ioprox.h"
  2. #include <furi.h>
  3. #include <cli/cli.h>
  4. /**
  5. * Writes a bit into the output buffer.
  6. */
  7. static void write_bit(bool bit, uint8_t position, uint8_t* data) {
  8. if(bit) {
  9. data[position / 8] |= 1UL << (7 - (position % 8));
  10. } else {
  11. data[position / 8] &= ~(1UL << (7 - (position % 8)));
  12. }
  13. }
  14. /**
  15. * Writes up to eight contiguous bits into the output buffer.
  16. */
  17. static void write_bits(uint8_t byte, uint8_t position, uint8_t* data, uint8_t length) {
  18. furi_check(length <= 8);
  19. furi_check(length > 0);
  20. for(uint8_t i = 0; i < length; ++i) {
  21. uint8_t shift = 7 - i;
  22. write_bit((byte >> shift) & 1, position + i, data);
  23. }
  24. }
  25. uint8_t ProtocolIoProx::get_encoded_data_size() {
  26. return 8;
  27. }
  28. uint8_t ProtocolIoProx::get_decoded_data_size() {
  29. return 4;
  30. }
  31. void ProtocolIoProx::encode(
  32. const uint8_t* decoded_data,
  33. const uint8_t decoded_data_size,
  34. uint8_t* encoded_data,
  35. const uint8_t encoded_data_size) {
  36. furi_check(decoded_data_size >= get_decoded_data_size());
  37. furi_check(encoded_data_size >= get_encoded_data_size());
  38. // Packet to transmit:
  39. //
  40. // 0 10 20 30 40 50 60
  41. // v v v v v v v
  42. // 01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23
  43. // -----------------------------------------------------------------------------
  44. // 00000000 0 11110000 1 facility 1 version_ 1 code-one 1 code-two 1 checksum 11
  45. // Preamble.
  46. write_bits(0b00000000, 0, encoded_data, 8);
  47. write_bit(0, 8, encoded_data);
  48. write_bits(0b11110000, 9, encoded_data, 8);
  49. write_bit(1, 17, encoded_data);
  50. // Facility code.
  51. write_bits(decoded_data[0], 18, encoded_data, 8);
  52. write_bit(1, 26, encoded_data);
  53. // Version
  54. write_bits(decoded_data[1], 27, encoded_data, 8);
  55. write_bit(1, 35, encoded_data);
  56. // Code one
  57. write_bits(decoded_data[2], 36, encoded_data, 8);
  58. write_bit(1, 44, encoded_data);
  59. // Code two
  60. write_bits(decoded_data[3], 45, encoded_data, 8);
  61. write_bit(1, 53, encoded_data);
  62. // Checksum
  63. write_bits(compute_checksum(encoded_data, 8), 54, encoded_data, 8);
  64. write_bit(1, 62, encoded_data);
  65. write_bit(1, 63, encoded_data);
  66. }
  67. void ProtocolIoProx::decode(
  68. const uint8_t* encoded_data,
  69. const uint8_t encoded_data_size,
  70. uint8_t* decoded_data,
  71. const uint8_t decoded_data_size) {
  72. furi_check(decoded_data_size >= get_decoded_data_size());
  73. furi_check(encoded_data_size >= get_encoded_data_size());
  74. // Packet structure:
  75. // (Note: the second word seems fixed; but this may not be a guarantee;
  76. // it currently has no meaning.)
  77. //
  78. //0 1 2 3 4 5 6 7
  79. //v v v v v v v v
  80. //01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF
  81. //-----------------------------------------------------------------------
  82. //00000000 01111000 01FFFFFF FF1VVVVV VVV1CCCC CCCC1CCC CCCCC1XX XXXXXX11
  83. //
  84. // F = facility code
  85. // V = version
  86. // C = code
  87. // X = checksum
  88. // Facility code
  89. decoded_data[0] = (encoded_data[2] << 2) | (encoded_data[3] >> 6);
  90. // Version code.
  91. decoded_data[1] = (encoded_data[3] << 3) | (encoded_data[4] >> 5);
  92. // Code bytes.
  93. decoded_data[2] = (encoded_data[4] << 4) | (encoded_data[5] >> 4);
  94. decoded_data[3] = (encoded_data[5] << 5) | (encoded_data[6] >> 3);
  95. }
  96. bool ProtocolIoProx::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) {
  97. furi_check(encoded_data_size >= get_encoded_data_size());
  98. // Packet framing
  99. //
  100. //0 1 2 3 4 5 6 7
  101. //v v v v v v v v
  102. //01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF
  103. //-----------------------------------------------------------------------
  104. //00000000 01______ _1______ __1_____ ___1____ ____1___ _____1XX XXXXXX11
  105. //
  106. // _ = variable data
  107. // 0 = preamble 0
  108. // 1 = framing 1
  109. // X = checksum
  110. // Validate the packet preamble is there...
  111. if(encoded_data[0] != 0b00000000) {
  112. return false;
  113. }
  114. if((encoded_data[1] >> 6) != 0b01) {
  115. return false;
  116. }
  117. // ... check for known ones...
  118. if((encoded_data[2] & 0b01000000) == 0) {
  119. return false;
  120. }
  121. if((encoded_data[3] & 0b00100000) == 0) {
  122. return false;
  123. }
  124. if((encoded_data[4] & 0b00010000) == 0) {
  125. return false;
  126. }
  127. if((encoded_data[5] & 0b00001000) == 0) {
  128. return false;
  129. }
  130. if((encoded_data[6] & 0b00000100) == 0) {
  131. return false;
  132. }
  133. if((encoded_data[7] & 0b00000011) == 0) {
  134. return false;
  135. }
  136. // ... and validate our checksums.
  137. uint8_t checksum = compute_checksum(encoded_data, 8);
  138. uint8_t checkval = (encoded_data[6] << 6) | (encoded_data[7] >> 2);
  139. if(checksum != checkval) {
  140. return false;
  141. }
  142. return true;
  143. }
  144. uint8_t ProtocolIoProx::compute_checksum(const uint8_t* data, const uint8_t data_size) {
  145. furi_check(data_size == get_encoded_data_size());
  146. // Packet structure:
  147. //
  148. //0 1 2 3 4 5 6 7
  149. //v v v v v v v v
  150. //01234567 8 9ABCDEF0 1 23456789 A BCDEF012 3 456789AB C DEF01234 5 6789ABCD EF
  151. //00000000 0 VVVVVVVV 1 WWWWWWWW 1 XXXXXXXX 1 YYYYYYYY 1 ZZZZZZZZ 1 CHECKSUM 11
  152. //
  153. // algorithm as observed by the proxmark3 folks
  154. // CHECKSUM == 0xFF - (V + W + X + Y + Z)
  155. uint8_t checksum = 0;
  156. checksum += (data[1] << 1) | (data[2] >> 7); // VVVVVVVVV
  157. checksum += (data[2] << 2) | (data[3] >> 6); // WWWWWWWWW
  158. checksum += (data[3] << 3) | (data[4] >> 5); // XXXXXXXXX
  159. checksum += (data[4] << 4) | (data[5] >> 4); // YYYYYYYYY
  160. checksum += (data[5] << 5) | (data[6] >> 3); // ZZZZZZZZZ
  161. return 0xFF - checksum;
  162. }