Reading done, writing almost

This commit is contained in:
2026-05-21 21:11:46 +02:00
parent 7f9df9db91
commit 61cce57401
3 changed files with 173 additions and 25 deletions

View File

@@ -1,4 +1,4 @@
from fastapi import APIRouter, Depends, HTTPException
from fastapi import APIRouter, Depends, HTTPException, status
from sqlmodel import Session, select
from typing import List
@@ -6,12 +6,16 @@ from ..model.models import Card
from ..services.database import engine, get_session, add_and_refresh
from ..services.auth import auth_is_admin
import uuid as gen_uuid
from app.services.scanner import WriteNewCard
card_router = APIRouter(prefix="/cards", tags=["Card"])
def register_card(group_id: int):
uuid = str(gen_uuid.uuid4()) #hier code für mifare registrierung
card = Card(group_id=group_id, uuid=uuid)
key = WriteNewCard()
if key == None:
print("No card registered. Check logs!")
raise HTTPException(status.HTTP_417_EXPECTATION_FAILED, detail="No card registered. Check logs!")
card = Card(group_id=group_id, uuid=key)
return card
@card_router.post("/{group_id}", response_model=Card)

View File

@@ -9,6 +9,7 @@ from .services.auth import token_router, create_first_user
from app.services.scanner import BackgroundScanner
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
scanner = BackgroundScanner(db=get_session())
@asynccontextmanager
async def lifespan(app: FastAPI):
@@ -16,10 +17,9 @@ async def lifespan(app: FastAPI):
create_db_and_tables()
create_first_user()
print("Database created and tables initialized.")
scanner = BackgroundScanner(db=get_session())
scanner.start()
yield
scanner.stop()
#scanner.stop()
app = FastAPI(lifespan=lifespan)

View File

@@ -2,6 +2,7 @@ import logging
import threading
import time
import os
import secrets
from typing import Optional
from sqlmodel import Session
@@ -15,6 +16,7 @@ from desfire import DESFire, DESFireKey, PCSCDevice, diversify_key, get_list, to
from desfire.enums import DESFireCommunicationMode, DESFireFileType, DESFireKeySettings, DESFireKeyType
from desfire.schemas import FilePermissions, FileSettings, KeySettings
#ENV vars
load_dotenv()
MIFARE_APP_MASTER_KEY = os.getenv('MIFARE_APP_MASTER_KEY')
@@ -34,7 +36,129 @@ logger = logging.getLogger(__name__)
if MIFARE_APP_MASTER_KEY == None:
logger.critical("NO MASTER KEY LOADED")
exit(1)
#exit(1)
##ADD DELETING APP
##
def WriteNewCard():
try:
from app.main import scanner as scannerThread
scannerThread.stop()
cardtype = AnyCardType()
cardrequest = CardRequest(timeout=10, cardType=cardtype)
print("Please present DESfire tag...")
try:
cardservice = cardrequest.waitforcard()
except CardRequestTimeoutException:
logger.error("No tag detected within the timeout.")
return None
cardservice.connection.connect()
# Create Desfire object
desfire = DESFire(PCSCDevice(cardservice.connection.component))
# Create Key objects
AES_NULL_KEY_DATA = "00" * 16
aes_keysettings = KeySettings(
key_type=DESFireKeyType.DF_KEY_AES,
)
aes_null_key = DESFireKey(aes_keysettings, AES_NULL_KEY_DATA)
aes_master_key = DESFireKey(aes_keysettings, MIFARE_APP_MASTER_KEY)
# Authenticate with default DES key
print("Authenticating with default DES key...")
key_settings = desfire.get_key_setting()
mk = DESFireKey(key_settings, "00" * 8)
desfire.authenticate(0x0, mk)
#get uid
uid = desfire.get_real_uid()
# Set default key
print("Setting default key...")
desfire.change_default_key(aes_master_key, 0x0)
# Create application
print("Creating application...")
app_settings = KeySettings(
settings=[
DESFireKeySettings.KS_ALLOW_CHANGE_MK,
DESFireKeySettings.KS_LISTING_WITHOUT_MK,
DESFireKeySettings.KS_CREATE_DELETE_WITHOUT_MK,
DESFireKeySettings.KS_CONFIGURATION_CHANGEABLE,
],
key_type=DESFireKeyType.DF_KEY_AES,
)
desfire.create_application(MIFARE_APP_ID, app_settings, 4)
# Verify application creation
applications = desfire.get_application_ids()
assert len(applications) == 1
assert applications[0] == get_list(MIFARE_APP_ID)
print(" - Application created successfully.")
# Select application
print("Selecting application...")
desfire.select_application(MIFARE_APP_ID)
#Auth again as 0key
desfire.authenticate(0x0, mk)
#change to master
desfire.change_key(0x0, mk, aes_master_key, 0x1)
# Authenticate with AES key, as this has been set as the default key
print("Authenticating with master key...")
desfire.authenticate(0x0, aes_master_key)
#generate div data
diversification_data = [0x01] + uid + get_list(MIFARE_APP_ID) + get_list(MIFARE_SYS_ID)
read_div_key_bytes = diversify_key(get_list(MIFARE_ACL_READ_BASE_KEY), diversification_data, pad_to_32=False)
write_div_key_bytes = diversify_key(get_list(MIFARE_ACL_WRITE_BASE_KEY), diversification_data, pad_to_32=False)
print("Changing file read key...")
aes_file_read_key = DESFireKey(aes_keysettings, read_div_key_bytes)
desfire.change_key(MIFARE_ACL_READ_BASE_KEY_ID, aes_master_key, aes_file_read_key, 0x1)
print("Changing file write key...")
aes_file_write_key = DESFireKey(aes_keysettings, write_div_key_bytes)
desfire.change_key(MIFARE_ACL_WRITE_BASE_KEY_ID, aes_master_key, aes_file_write_key, 0x1)
print("Create encrypted file containing UUID...")
file_settings = FileSettings(
file_size=32,
encryption=DESFireCommunicationMode.ENCRYPTED,
permissions=FilePermissions(
read_key=MIFARE_ACL_READ_BASE_KEY_ID,
write_key=MIFARE_ACL_WRITE_BASE_KEY_ID,
),
file_type=DESFireFileType.MDFT_STANDARD_DATA_FILE,
)
desfire.create_standard_file(MIFARE_ENCRYPTED_FILE_ID, file_settings)
print("Read and verify file settings again...")
file_data = desfire.get_file_settings(MIFARE_ENCRYPTED_FILE_ID)
assert file_data.file_size == 16
assert file_data.encryption == DESFireCommunicationMode.ENCRYPTED
assert file_data.permissions is not None
assert file_data.permissions.read_access == MIFARE_ACL_READ_BASE_KEY_ID
assert file_data.permissions.write_access == MIFARE_ACL_WRITE_BASE_KEY_ID
assert file_data.file_type == DESFireFileType.MDFT_STANDARD_DATA_FILE
print(" - File created successfully.")
print("Writing UID to encrypted file...")
key = secrets.token_hex(16)
desfire.write_file_data(MIFARE_ENCRYPTED_FILE_ID, 0x0, file_data.encryption, get_list(key))
print("Reading from encrypted file...")
rdata = desfire.read_file_data(MIFARE_ENCRYPTED_FILE_ID, file_data)
assert rdata == key
print(" - Data written successfully.")
return key
except Exception as e:
logger.error(f"Error in write function: {e}", exc_info=True)
class BackgroundScanner:
def __init__(self, db):
@@ -83,25 +207,45 @@ class BackgroundScanner:
logger.debug("No tag detected within the timeout.")
return
cardservice.connection.connect()
# Create Desfire object
desfire = DESFire(PCSCDevice(cardservice.connection.component))
aes_keysettings = KeySettings(
key_type=DESFireKeyType.DF_KEY_AES,
)
try:
cardservice.connection.connect()
#Auth
logger.info("Start auth")
aes_app_mk = DESFireKey(aes_keysettings, MIFARE_APP_MASTER_KEY)
# Create Desfire object
desfire = DESFire(PCSCDevice(cardservice.connection.component))
aes_keysettings = KeySettings(
key_type=DESFireKeyType.DF_KEY_AES,
)
apps = desfire.get_application_ids()
logger.info(f"app id's are: {apps}")
desfire.select_application(MIFARE_APP_ID)
# Get real UID
mk = DESFireKey(desfire.get_key_setting(), "00" * 8)
desfire.authenticate(0x0, mk)
#To get the uid you have to auth with an empty (default) key
uid = desfire.get_real_uid()
applications = desfire.get_application_ids()
try:
assert len(applications) == 1
assert applications[0] == get_list(MIFARE_APP_ID)
except AssertionError:
logger.error("No application found!")
time.sleep(4)
return None
#Then use the key derivation with that uid, the appid, the sysid
diversification_data = [0x01] + uid + get_list(MIFARE_APP_ID) + get_list(MIFARE_SYS_ID)
read_div_key_bytes = diversify_key(get_list(MIFARE_ACL_READ_BASE_KEY), diversification_data, pad_to_32=True)
#Log in with derived read key
logger.info("Start auth")
aes_app_read_key = DESFireKey(aes_keysettings, read_div_key_bytes)
desfire.select_application(MIFARE_APP_ID)
desfire.authenticate(0x0, aes_app_mk)
logger.info("Read data")
file_data = desfire.get_file_settings(MIFARE_ENCRYPTED_FILE_ID)
logger.info(f"File settings: {file_data}")
rdata = desfire.read_file_data(MIFARE_ENCRYPTED_FILE_ID, file_data)
return rdata
desfire.authenticate(MIFARE_ACL_READ_BASE_KEY_ID, aes_app_read_key)
logger.info("Read data")
file_data = desfire.get_file_settings(MIFARE_ENCRYPTED_FILE_ID)
logger.info(f"File settings: {file_data}")
rdata = desfire.read_file_data(MIFARE_ENCRYPTED_FILE_ID, file_data)
return rdata
except Exception as e:
logger.error(f"something went wrong: {e}")
time.sleep(5)