diff --git a/app/controllers/cardManager.py b/app/controllers/cardManager.py index 2ac1cb5..762a13b 100644 --- a/app/controllers/cardManager.py +++ b/app/controllers/cardManager.py @@ -6,7 +6,7 @@ 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 +from app.services.scanner import WriteNewCard, DeleteCard card_router = APIRouter(prefix="/cards", tags=["Card"]) @@ -23,14 +23,15 @@ def add_card(*, db: Session = Depends(get_session), group_id: int, admin: bool = card = register_card(group_id) return add_and_refresh(db, card) -@card_router.delete("/{card_id}") -def del_card(*, db: Session = Depends(get_session), card_id: int, admin: bool = Depends(auth_is_admin)): - card = db.get(Card, card_id) - if card is None: - raise HTTPException(status_code=404, detail="Card not found") - db.delete(card) - db.commit() - return {"message": "Card deleted successfully"} +@card_router.get("/delete") +def del_card(*, db: Session = Depends(get_session), admin: bool = Depends(auth_is_admin)): + key = DeleteCard() + # card = db.get(Card, card_id) + # if card is None: + # raise HTTPException(status_code=404, detail="Card not found") + # db.delete(card) + # db.commit() + # return {"message": "Card deleted successfully"} ##TBH not a big fan of having creation using group_id but deletion using card_id @card_router.get("/{group_id}", response_model=List[Card]) def get_cards(*, db: Session = Depends(get_session), group_id: int, admin: bool = Depends(auth_is_admin)): diff --git a/app/services/scanner.py b/app/services/scanner.py index feef85f..3c7df49 100644 --- a/app/services/scanner.py +++ b/app/services/scanner.py @@ -7,6 +7,7 @@ import secrets from typing import Optional from sqlmodel import Session from dotenv import load_dotenv +from fastapi import HTTPException, status from smartcard.CardRequest import CardRequest from smartcard.CardType import AnyCardType @@ -15,6 +16,7 @@ from smartcard.Exceptions import CardRequestTimeoutException from desfire import DESFire, DESFireKey, PCSCDevice, diversify_key, get_list, to_hex_string from desfire.enums import DESFireCommunicationMode, DESFireFileType, DESFireKeySettings, DESFireKeyType from desfire.schemas import FilePermissions, FileSettings, KeySettings +import desfire.exceptions as desExceptions #ENV vars @@ -34,14 +36,62 @@ MIFARE_ENCRYPTED_FILE_ID = 0x1 logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) -if MIFARE_APP_MASTER_KEY == None: - logger.critical("NO MASTER KEY LOADED") - #exit(1) -##ADD DELETING APP -## +def checkForKey(): + if MIFARE_APP_MASTER_KEY == None: + logger.critical("NO MASTER KEY LOADED") + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="No key loaded! Check application.") + +def getCardService(timeout: int = 10): + cardtype = AnyCardType() + cardrequest = CardRequest(timeout=timeout, cardType=cardtype) + print("Please present DESfire tag...") + try: + cardservice = cardrequest.waitforcard() + except CardRequestTimeoutException: + logger.error("No tag detected within the timeout.") + raise Exception + return cardservice + +def DeleteCard(): + try: + checkForKey() + from app.main import scanner as scannerThread + scannerThread.stop() + cardservice = getCardService(15) + cardservice.connection.connect() + + # Create Desfire object + desfire = DESFire(PCSCDevice(cardservice.connection.component)) + + # Create Key objects + AES_NULL_KEY_DATA = "00" * 8 + aes_keysettings = KeySettings( + key_type=DESFireKeyType.DF_KEY_AES, + ) + key_settings = desfire.get_key_setting() + aes_null_key = DESFireKey(key_settings, AES_NULL_KEY_DATA) + aes_master_key = DESFireKey(aes_keysettings, MIFARE_APP_MASTER_KEY) + desfire.authenticate(0x0, aes_null_key) + applications = desfire.get_application_ids() + logger.debug(f"Applications: {applications}") + if len(applications) == 0: + raise HTTPException(status_code=status.HTTP_410_GONE, detail="No applications on card") + + desfire.select_application(MIFARE_APP_ID) + desfire.authenticate(0x0, aes_master_key) + try: + desfire.delete_application(MIFARE_APP_ID) + except Exception: + pass + scannerThread.start() + + except Exception as e: + logger.error(f"Error in deletion function: {e}", exc_info=True) + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error: {e}") def WriteNewCard(): try: + checkForKey() from app.main import scanner as scannerThread scannerThread.stop() @@ -66,19 +116,19 @@ def WriteNewCard(): ) aes_null_key = DESFireKey(aes_keysettings, AES_NULL_KEY_DATA) aes_master_key = DESFireKey(aes_keysettings, MIFARE_APP_MASTER_KEY) + keysetting = desfire.get_key_setting() + desKey = DESFireKey(keysetting, "00" * 8) # 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) + desfire.authenticate(0x0, desKey) #get uid uid = desfire.get_real_uid() # Set default key print("Setting default key...") - desfire.change_default_key(aes_master_key, 0x0) + desfire.change_default_key(aes_null_key, 0x0) # Create application print("Creating application...") @@ -100,16 +150,16 @@ def WriteNewCard(): 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) - + aes_null_auth_key = DESFireKey(aes_keysettings, AES_NULL_KEY_DATA) + desfire.authenticate(0x0, aes_null_auth_key) # Authenticate with AES key, as this has been set as the default key - print("Authenticating with master key...") - desfire.authenticate(0x0, aes_master_key) + aes_app_mk = DESFireKey(aes_keysettings, MIFARE_APP_MASTER_KEY) + desfire.change_key(0x0, aes_null_key, aes_app_mk, 0x1) + + print("new key auth") + desfire.authenticate(0x0, aes_app_mk) #generate div data diversification_data = [0x01] + uid + get_list(MIFARE_APP_ID) + get_list(MIFARE_SYS_ID) @@ -118,15 +168,15 @@ def WriteNewCard(): 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) + desfire.change_key(MIFARE_ACL_READ_BASE_KEY_ID, aes_null_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) + desfire.change_key(MIFARE_ACL_WRITE_BASE_KEY_ID, aes_null_key, aes_file_write_key, 0x1) print("Create encrypted file containing UUID...") file_settings = FileSettings( - file_size=32, + file_size=16, encryption=DESFireCommunicationMode.ENCRYPTED, permissions=FilePermissions( read_key=MIFARE_ACL_READ_BASE_KEY_ID, @@ -152,12 +202,14 @@ def WriteNewCard(): print("Reading from encrypted file...") rdata = desfire.read_file_data(MIFARE_ENCRYPTED_FILE_ID, file_data) - assert rdata == key + assert rdata == get_list(key) print(" - Data written successfully.") + scannerThread.start() return key except Exception as e: logger.error(f"Error in write function: {e}", exc_info=True) + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error: {e}") class BackgroundScanner: @@ -231,7 +283,7 @@ class BackgroundScanner: 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) + read_div_key_bytes = diversify_key(get_list(MIFARE_ACL_READ_BASE_KEY), diversification_data, pad_to_32=False) #Log in with derived read key logger.info("Start auth") diff --git a/test.py b/test.py index efa32ed..17c4a87 100644 --- a/test.py +++ b/test.py @@ -13,6 +13,7 @@ It performs the following steps: """ import logging +import os from smartcard.CardRequest import CardRequest from smartcard.CardType import AnyCardType