EZGG-LAN-NFC-Tools/card_reader.py
David Rodenkirchen ddc60f80fb initial commit
2026-02-26 08:18:45 +01:00

101 lines
2.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import hashlib
import hmac
import struct
from typing import Optional
from smartcard.CardRequest import CardRequest
from smartcard.CardConnection import CardConnection
from secret import SECRET
def read_page(connection, page):
apdu = [0xFF, 0xB0, 0x00, page, 0x04]
data, sw1, sw2 = connection.transmit(apdu)
if sw1 == 0x90 and sw2 == 0x00:
return data[:4]
return None
def extract_user_id(raw: bytes) -> int | None:
try:
# Must be exactly 10 bytes (2 ID + 8 MAC)
if len(raw) != 10:
return None
user_bytes = raw[:2]
stored_mac = raw[2:]
expected_mac = hmac.new(
SECRET,
user_bytes,
hashlib.sha256
).digest()[:8]
# Constant-time comparison
if not hmac.compare_digest(stored_mac, expected_mac):
return None
# Decode big-endian unsigned short
user_id = struct.unpack(">H", user_bytes)[0]
return user_id
except Exception as e:
print("Error extracting user id:", e)
return None
def read_card(connection) -> Optional[int]:
# Read pages 415
try:
raw = []
for page in range(4, 16):
data = read_page(connection, page)
if data:
raw.extend(data)
# Parse NDEF
if raw[0] == 0x03: # NDEF TLV
length = raw[1]
ndef = raw[2:2 + length]
if ndef[0] == 0xD1 and ndef[3] == 0x54:
lang_len = ndef[4]
payload_hex = bytes(ndef[5 + lang_len:]).decode("utf-8")
payload_bytes = bytes.fromhex(payload_hex)
return extract_user_id(payload_bytes)
except Exception as e:
print("Error reading card:", e)
return None
return None
def perform_single_console_read() -> None:
""" Prints the user ID of the card to console """
print("Auf Ticket warten...")
card_request = CardRequest(timeout=None)
card_service = card_request.waitforcard()
connection = card_service.connection
connection.connect(CardConnection.T1_protocol)
user_id = read_card(connection)
if user_id is not None:
print("User ID:", user_id)
else:
print("User ID nicht auf Ticket gefunden")
def main():
print("Auf Ticket warten...")
card_request = CardRequest(timeout=None)
card_service = card_request.waitforcard()
connection = card_service.connection
connection.connect(CardConnection.T1_protocol)
user_id = read_card(connection)
if user_id is not None:
print("User ID:", user_id)
else:
print("User ID nicht auf Ticket gefunden")
if __name__ == "__main__":
perform_single_console_read()