#!/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
import datetime
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
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
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
n -= 4
if n>0:
_b = filt_binstr[0:n]
fin_hex = hex(int(_b, 2))[2:] + 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:
t_now = time.time()*1000.0
tok = convert_tagid(m.group(1)).upper()
if LAST_TOK != tok:
#sys.stdout.write( str(datetime.datetime.now()) + ": " + str(tok) + "\n")
sys.stdout.write( str(int(time.time())) + ": " + str(tok) + "\n")
sys.stdout.flush()
t_prv = t_now
LAST_TOK = tok
elif (t_now - t_prv) >= RATE_LIMIT_MS:
#sys.stdout.write( str(datetime.datetime.now()) + ": " + str(tok) + "\n")
sys.stdout.write( str(int(time.time())) + ": " + str(tok) + "\n")
sys.stdout.flush()
t_prv = t_now
LAST_TOK = tok
else:
pass