rfid_filter 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. #!/usr/bin/python
  2. #
  3. # Copyright (c) 2019 Clementine Computing LLC.
  4. #
  5. # This file is part of PopuFare.
  6. #
  7. # PopuFare is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # PopuFare is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
  19. #
  20. # The output format is `<bit-length>|<payload>`, where the
  21. # <bit-length> and <payload> field are in ascii hex.
  22. #
  23. # Input is expected to come from stdin and as the result of the
  24. # `proxmark3` LUA script setup for low frequency read.
  25. # Input text is seached for a matching prefix of:
  26. #
  27. # #db# TAG ID:
  28. #
  29. # Once found, the ascii hex string is read, it's converted to binary
  30. # and parsed.
  31. # The first run of two '1' bits is removed from the 'left'.
  32. # The remaing number of bits is the bit length and the remaining
  33. # bit string is converted back to ascii.
  34. # Note the 'paylaod' can be a non exact multiple of 4 or 2.
  35. #
  36. # For example, if the following string was found:
  37. #
  38. # #db# TAG ID: 200712054a (677)
  39. #
  40. # This is converted to:
  41. #
  42. # 2 0 0 7 1 2 0 5 4 a
  43. # 0010 0000 0000 01 11 0001 0010 0000 0101 0100 1010
  44. # | |
  45. # -----------------------------------
  46. # 26 bits
  47. #
  48. # To evenually give the final result:
  49. #
  50. # 23|43F6311B2
  51. #
  52. import os
  53. import re
  54. import sys
  55. import time
  56. rate_limit_ms = 3000.0
  57. def convert_tagid(s):
  58. binstr = ""
  59. for c in s:
  60. v = int(c, 16)
  61. _b = bin(int(c, 16))[2:]
  62. __b = "0"*(4-len(_b)) + _b
  63. binstr = binstr + __b
  64. #print("c:", c, "v:", v, "_b:", _b, "binstr:", binstr)
  65. #print("binstr:", binstr)
  66. f, s, = -1, -1
  67. for idx, b in enumerate(binstr):
  68. if (b == '1') and (f < 0):
  69. f = idx
  70. elif (b == '1') and (s < 0):
  71. s = idx
  72. break
  73. #print("first:", f, "second:", s)
  74. filt_binstr = binstr[s+1:]
  75. n = len(filt_binstr)
  76. bitlen = n
  77. fin_hex = ""
  78. while n >= 4:
  79. _b = filt_binstr[n-4:n]
  80. fin_hex = hex(int(_b, 2))[2:] + fin_hex
  81. #print("n:", n, "_b:", _b, "fin_hex:", fin_hex)
  82. n -= 4
  83. if n>0:
  84. _b = filt_binstr[0:n]
  85. fin_hex = hex(int(_b, 2))[2:] + fin_hex
  86. #print("n:", n, "_b:", _b, "fin_hex:", fin_hex)
  87. #print("bitlen:", bitlen)
  88. #print("binstr:", binstr)
  89. #print("fin_hex:", fin_hex)
  90. return hex(bitlen)[2:] + "|" + fin_hex
  91. t_prv = time.time()*1000.0
  92. t_now = t_prv
  93. last_tok = ""
  94. while True:
  95. line = sys.stdin.readline()
  96. line = line.strip()
  97. m = re.match("#db# TAG ID: ([^ ]*)", line)
  98. if m:
  99. #print("match:", m.group(1))
  100. t_now = time.time()*1000.0
  101. tok = convert_tagid(m.group(1)).upper()
  102. if last_tok != tok:
  103. print(tok)
  104. sys.stdout.flush()
  105. t_prv = t_now
  106. last_tok = tok
  107. elif (t_now - t_prv) >= rate_limit_ms:
  108. print(tok)
  109. sys.stdout.flush()
  110. t_prv = t_now
  111. last_tok = tok
  112. else:
  113. #print("#ignore")
  114. pass