101 lines
2.7 KiB
Python
101 lines
2.7 KiB
Python
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 4–15
|
||
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() |