#!/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