#!/usr/bin/python # # Copyright (c) 2019 Clementine Computing LLC. # # This file is part of PopuFare. # # PopuFare is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # PopuFare is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with PopuFare. If not, see . # # The output format is `|`, where the # and field are in ascii hex. # # Input is expected to come from stdin and as the result of the # `proxmark3` LUA script setup for low frequency read. # Input text is seached for a matching prefix of: # # #db# TAG ID: # # Once found, the ascii hex string is read, it's converted to binary # and parsed. # The first run of two '1' bits is removed from the 'left'. # The remaing number of bits is the bit length and the remaining # bit string is converted back to ascii. # Note the 'paylaod' can be a non exact multiple of 4 or 2. # # For example, if the following string was found: # # #db# TAG ID: 200712054a (677) # # This is converted to: # # 2 0 0 7 1 2 0 5 4 a # 0010 0000 0000 01 11 0001 0010 0000 0101 0100 1010 # | | # ----------------------------------- # 26 bits # # To evenually give the final result: # # 23|43F6311B2 # import os import re import sys import time rate_limit_ms = 1500.0 def convert_tagid(s): binstr = "" for c in s: v = int(c, 16) _b = bin(int(c, 16))[2:] __b = "0"*(4-len(_b)) + _b binstr = binstr + __b #print("c:", c, "v:", v, "_b:", _b, "binstr:", binstr) #print("binstr:", binstr) f, s, = -1, -1 for idx, b in enumerate(binstr): if (b == '1') and (f < 0): f = idx elif (b == '1') and (s < 0): s = idx break #print("first:", f, "second:", s) filt_binstr = binstr[s+1:] n = len(filt_binstr) bitlen = n fin_hex = "" while n >= 4: _b = filt_binstr[n-4:n] fin_hex = hex(int(_b, 2))[2:] + fin_hex #print("n:", n, "_b:", _b, "fin_hex:", fin_hex) n -= 4 if n>0: _b = filt_binstr[0:n] fin_hex = hex(int(_b, 2))[2:] + fin_hex #print("n:", n, "_b:", _b, "fin_hex:", fin_hex) #print("bitlen:", bitlen) #print("binstr:", binstr) #print("fin_hex:", fin_hex) return hex(bitlen)[2:] + "|" + fin_hex t_prv = time.time()*1000.0 t_now = t_prv last_tok = "" while True: line = sys.stdin.readline() line = line.strip() m = re.match("#db# TAG ID: ([^ ]*)", line) if m: #print("match:", m.group(1)) t_now = time.time()*1000.0 tok = convert_tagid(m.group(1)).upper() if last_tok != tok: print(tok) sys.stdout.flush() t_prv = t_now last_tok = tok elif (t_now - t_prv) >= rate_limit_ms: print(tok) sys.stdout.flush() t_prv = t_now last_tok = tok else: #print("#ignore") pass