//////////////////////////////////////////////////////////////////// // // Mifare Card Explorer for Mac // // Created by Francesco Germinara // // Freeware (c) 2005-2006 SofTech di F.Germinara - www.germinara.it. // // For information please contact me at info@germinara.it //////////////////////////////////////////////////////////////////// // History: // // Description: // //////////////////////////////////////////////////////////////////// #include "FGMifareObj.h" @implementation FGMifareObj - (id) init { self = [super init]; if (self != nil) { [self initialize]; } return self; } - (void) dealloc { [msgErr release]; [saGemini2kReader removeAllObjects]; [saGemini2kReader release]; [saMifareCardTypes removeAllObjects]; [saMifareCardTypes release]; [paCards removeAllObjects]; [paCards release]; [super dealloc]; } //Standard constructor for CFGMifareObj object -(void)initialize{ hSess=NULL; //Session handle nIDGemini2kReader=X501; bIsDebug=TRUE; nDelayWaitCard=100; nCardsInRF=0; msgErr=[[NSString alloc] initWithString:@""]; saGemini2kReader=[[NSMutableArray alloc] init]; saMifareCardTypes=[[NSMutableArray alloc] init]; paCards=[[NSMutableArray alloc] init]; [saGemini2kReader addObject:@"X501"]; [saGemini2kReader addObject:@"X701"]; [saMifareCardTypes addObject:@"MIFARE ultralight"]; [saMifareCardTypes addObject:@"MIFARE Standard 1K"]; [saMifareCardTypes addObject:@"MIFARE Standard 4K"]; [saMifareCardTypes addObject:@"MIFARE DESFire"]; } -(void) SetReaderToUse:(int) nIndex{ if(nIndex == 0) nIDGemini2kReader=X501; if(nIndex == 1) nIDGemini2kReader=X701; } -(void) SetDebugMode:(BOOL) bSts{ bIsDebug=bSts; } -(void) SetDelayForWaitCard:(int) nMilliSec{ nDelayWaitCard=nMilliSec; } -(int) DelayForWaitCard{ return nDelayWaitCard; } -(void) SetErrorMsg:(NSString*) newMsg{ [newMsg retain]; [msgErr release]; msgErr=newMsg; } -(void) DisplayMsgErr{ if(bIsDebug) NSRunAlertPanel(@"Informazioni",msgErr,@"OK",nil,nil); } //Always display error message, also if not in Debug Mode -(void) ForceDisplayMsgErr{ if(bIsDebug) return; int oldDebugState=bIsDebug; bIsDebug=TRUE; [self DisplayMsgErr]; bIsDebug=oldDebugState; } -(void) ClearData{ [paCards removeAllObjects]; nCardsInRF=0; } -(bool) ConnectToReader:(int)nIDGemini2k withPort:(NSString*) usbPortName { //Clean Up old data card [self ClearData]; nIDGemini2kReader=nIDGemini2k; bool sts=false; int err=0; if(hSess == NULL){ hSess=CreateSession(0); //Create the communication session if(!hSess){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ConnectToReader -> Error: Can not get session."]]; [self DisplayMsgErr]; }else{//Ok, now try to connect the reader on USB_0 err= ConnectReader(hSess,USB_INTERFACE,usbPortName,nIDGemini2kReader); if(err){//Error, release connection [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ConnectToReader -> Error: Cannot connect the reader %s",GetErrorText(err)]]; [self DisplayMsgErr]; ReleaseSession(hSess,0); hSess=NULL; }else{ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ConnectToReader ->Reader %X connected on USB_0.",nIDGemini2kReader]]; [self DisplayMsgErr]; sts=true; //All work fine } } }else{ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ConnectToReader ->Reader %X already connected on USB_0.",nIDGemini2kReader]]; [self DisplayMsgErr]; sts=true; //Connection alredy exist. } return sts; } -(bool) ConnectToReader{ //Clean Up old data card [self ClearData]; bool sts=false; int err=0; if(hSess == NULL){ hSess=CreateSession(0); //Create the communication session if(!hSess){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ConnectToReader -> Error: Can not get session."]]; [self DisplayMsgErr]; }else{//Ok, now try to connect the reader on USB_0 err= ConnectReader(hSess,USB_INTERFACE,"USB_0",nIDGemini2kReader); if(err){//Error, release connection [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ConnectToReader -> Error: Cannot connect the reader %s",GetErrorText(err)]]; [self DisplayMsgErr]; ReleaseSession(hSess,0); hSess=NULL; }else{ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ConnectToReader ->Reader %X connected on USB_0.",nIDGemini2kReader]]; [self DisplayMsgErr]; sts=true; //All work fine } } }else{ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ConnectToReader ->Reader %X already connected on USB_0.",nIDGemini2kReader]]; [self DisplayMsgErr]; sts=true; //Connection alredy exist. } return sts; } -(void) DisconnectToReader{ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::DisconnectToReader ->Reader %X disconnected on USB_0",nIDGemini2kReader]]; [self DisplayMsgErr]; DisconnectReader(hSess); ReleaseSession(hSess,0); hSess=NULL; } -(int) SelectAidleCard{ int sts=0; BOOL cardAlreadyRegistered=FALSE; ChipIDSize = (unsigned char)(sizeof(ChipID)); sts=SelectIdleCard(hSess,ChipID,&ChipIDSize,ATQ,&ATS); if(sts==0){ paCard = [[FGMifareCard alloc] init]; [paCard ClearData]; [self FillCFGMifareCardInfo]; cardAlreadyRegistered=[self SearchCard:paCard]; if(!cardAlreadyRegistered){ [paCards addObject:paCard]; [paCard release]; nCardsInRF++; }else{ [paCard release]; } } return sts; } //Fill Card Info -(void) FillCFGMifareCardInfo{ NSMutableString *strTmp; NSMutableString *strCardUID; unsigned char i = 0; strTmp=[[NSMutableString alloc] init]; strCardUID=[[NSMutableString alloc] init]; [strTmp appendString:@"Card ID: "]; for( i = 0; i < ChipIDSize;i++){ [strCardUID appendFormat:@"%0.2X", ChipID[i]]; } [strTmp appendString:strCardUID]; [paCard SetUid:strCardUID]; [strTmp appendFormat:@"ATQ is %0X%02 %0X%02\n",ATQ[0],ATQ[1]]; switch(((ATQ[1] << 8)|ATQ[0])) { case 0x0044: [strTmp appendFormat:@"Assuming MIFARE ultralight\n"]; [paCard GetCardInfo]->BlocksCount = 4; [paCard GetCardInfo]->SectorsCount = 1; [paCard GetCardInfo]->Method = ULTRA_LIGTH_METHOD; [paCard SetCardType:@"Mifare Ultralight"]; break; case 0x004: [strTmp appendFormat:@"Assuming MIFARE 1K\n"]; [paCard GetCardInfo]->BlocksCount = 64; [paCard GetCardInfo]->SectorsCount = 16; [paCard GetCardInfo]->Method = MIFARE_1K_METHOD; memcpy([paCard GetCardInfo]->ChipID.Mif_UID,ChipID,SINGLE_UID_BYTES); [paCard SetCardType:@"Mifare 1K"]; break; case 0x0002: [strTmp appendFormat:@"Assuming MIFARE 4K\n"]; [paCard GetCardInfo]->BlocksCount = 256; [paCard GetCardInfo]->SectorsCount = 40; [paCard GetCardInfo]->Method = MIFARE_4K_METHOD; memcpy([paCard GetCardInfo]->ChipID.Mif_UID,ChipID,SINGLE_UID_BYTES); [paCard SetCardType:@"Mifare 4K"]; break; case 0x0344: [strTmp appendFormat:@"Assuming DESFire\n"]; [paCard SetCardType:@"Mifare DESFire"]; break; [paCard GetCardInfo]->Method = MIFARE_DES_FIRE_METHOD; default: [strTmp appendFormat:@"Assuming non MIFARE\n"]; [paCard SetCardType:@"Non Mifare Card"]; break; } [strTmp appendFormat:@"SAK is %0X%02\n",ATS]; if(((ATS >> 5) & 1)) { [strTmp appendFormat:@"T=CL supported\n",ATS]; [paCard GetCardInfo]->Method = T_CL_METHOD; } else [strTmp appendFormat:@"T=CL NOT supported\n",ATS]; [self SetErrorMsg:strTmp]; [strTmp release]; [strCardUID release]; [self DisplayMsgErr]; } //Halt communication with the card -(void) HaltTheCard{ HaltCard(hSess); } //Return Number of registered card -(int) NumberOfRegisteredCards{ return nCardsInRF; } //Check if a card was already registered. -(BOOL) SearchCard:(FGMifareCard *)pSelectedCard { int nIndex=0; for(nIndex=0; nIndex < [paCards count]; nIndex++){ if([pSelectedCard equalTo:[paCards objectAtIndex:nIndex]]){ return TRUE; } } return FALSE; } //Select a Card -(int) SelectACard:(FGMifareCard *)pSelectedCard{ int sts=0x00; int nMaxTimeOut=20; for(;;){ ChipIDSize = (unsigned char)(sizeof(ChipID)); sts=SelectIdleCard(hSess,ChipID,&ChipIDSize,ATQ,&ATS); if(sts == 0x00 && pSelectedCard->cardInfo.ChipID.Mif_UID[0] == ChipID[0] && pSelectedCard->cardInfo.ChipID.Mif_UID[1] == ChipID[1] && pSelectedCard->cardInfo.ChipID.Mif_UID[2] == ChipID[2] && pSelectedCard->cardInfo.ChipID.Mif_UID[3] == ChipID[3]) return 0x00; else{ nMaxTimeOut --; if(!nMaxTimeOut) break; } } return sts; //No Card } //Remove specified card from internal list -(void) RemoveCard:(FGMifareCard *)pSelectedCard { int nIndex=0; for(nIndex=0; nIndex < [paCards count]; nIndex++){ if([pSelectedCard equalTo:[paCards objectAtIndex:nIndex]]){ [paCards removeObjectAtIndex:nIndex]; nCardsInRF--; return; } } return; } //Read a single Block -(int) ReadBlock:(FGMifareCard *) pSelectedCard forBlock:(int) nBlock usingKeyNum:(int) usingKey dataRead:(unsigned char *)BlockData { int sts=0; if(nBlock >= [pSelectedCard GetCardInfo]->BlocksCount){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ReadBlock -> Error: Invalid block number! Max Blocks: %d - Block request to read: %d",[pSelectedCard GetCardInfo]->BlocksCount,nBlock]]; [self DisplayMsgErr]; return -1; } if(usingKey != USE_KEY_A && usingKey != USE_KEY_B){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ReadBlock -> Error: Invalid Key! Must be USE_KEY_A or USE_KEY_B"]]; [self DisplayMsgErr]; return -1; } memset(BlockData,0x00,MIF_BLOCK_SIZE); //Empty data in the buffer MIF_KEY accessKey; accessKey.KeyType=usingKey; if(usingKey == USE_KEY_A){ memcpy(accessKey.KeyValue,pSelectedCard->KeyA,MIF_KEY_VALUE_LEN); }else{ memcpy(accessKey.KeyValue,pSelectedCard->KeyB,MIF_KEY_VALUE_LEN); } sts = MifC_ReadBlockAuth(hSess,&accessKey,&pSelectedCard->cardInfo.ChipID,(unsigned char)nBlock,BlockData); return sts; } //Write a single Block -(int) WriteBlock:(FGMifareCard *) pSelectedCard forBlock:(int) nBlock usingKeyNum:(int) usingKey dataToWrite:(unsigned char *)BlockData{ int sts=0; if(nBlock >= [pSelectedCard GetCardInfo]->BlocksCount){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::WriteBlock -> Error: Invalid block number! Max Blocks: %d - Block request to write: %d",[pSelectedCard GetCardInfo]->BlocksCount,nBlock]]; [self DisplayMsgErr]; return -1; } if(usingKey != USE_KEY_A && usingKey != USE_KEY_B){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::WriteBlock -> Error: Invalid Key! Must be USE_KEY_A or USE_KEY_B"]]; [self DisplayMsgErr]; return -1; } MIF_KEY accessKey; accessKey.KeyType=usingKey; if(usingKey == USE_KEY_A){ memcpy(accessKey.KeyValue,pSelectedCard->KeyA,MIF_KEY_VALUE_LEN); }else{ memcpy(accessKey.KeyValue,pSelectedCard->KeyB,MIF_KEY_VALUE_LEN); } sts = MifC_WriteBlockAuth(hSess,&accessKey,&pSelectedCard->cardInfo.ChipID,(unsigned char)nBlock,BlockData); return sts; } //Erase a single Block -(int) EraseBlock:(FGMifareCard *) pSelectedCard forBlock:(int) nBlock usingKeyNum:(int) usingKey { unsigned char BlockData[MIF_BLOCK_SIZE]; memset(BlockData,0x00,MIF_BLOCK_SIZE); //Empty data in the buffer return [self WriteBlock:pSelectedCard forBlock:nBlock usingKeyNum:usingKey dataToWrite:BlockData]; //Write Nul Data } //Read a single sector -(int) ReadSector:(FGMifareCard *) pSelectedCard forSector:(int) nSector usingKeyNum:(int) usingKey dataRead:(unsigned char *)SecData numBytes:(int*) bytesRead { //Mifare 4k is 32 sector with 4 block each of 16 bytes // 8 sector with 16 block each og 16 bytes unsigned char SecDataLen; //Set the correct data sector lenght if( nSector < 32) SecDataLen=48; else SecDataLen = 240; int sts=0; if(nSector >= [pSelectedCard GetCardInfo]->SectorsCount){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ReadSector -> Error: Invalid sector number! Max Sectors: %d - Sector request to read: %d",[pSelectedCard GetCardInfo]->SectorsCount,nSector]]; [self DisplayMsgErr]; return -1; } if(usingKey != USE_KEY_A && usingKey != USE_KEY_B){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ReadSector -> Error: Invalid Key! Must be USE_KEY_A or USE_KEY_B"]]; [self DisplayMsgErr]; return -1; } memset(SecData,0x00,SecDataLen); //Empty data in the buffer MIF_KEY accessKey; accessKey.KeyType=usingKey; if(usingKey == USE_KEY_A){ memcpy(accessKey.KeyValue,pSelectedCard->KeyA,MIF_KEY_VALUE_LEN); }else{ memcpy(accessKey.KeyValue,pSelectedCard->KeyB,MIF_KEY_VALUE_LEN); } sts = MifC_ReadSectorDataAuth(hSess,&accessKey,&pSelectedCard->cardInfo.ChipID,SecData,SecDataLen,nSector); *bytesRead=SecDataLen; return sts; } //Write a single sector -(int) WriteSector:(FGMifareCard *) pSelectedCard forSector:(int) nSector usingKeyNum:(int) usingKey dataToWrite:(unsigned char *)SecData { //Mifare 4k is 32 sector with 4 block each of 16 bytes // 8 sector with 16 block each og 16 bytes unsigned char SecDataLen; //Set the correct data sector lenght if( nSector < 32) SecDataLen=48; else SecDataLen = 240; int sts=0; if(nSector >= [pSelectedCard GetCardInfo]->SectorsCount){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::WriteSector -> Error: Invalid sector number! Max Sectors: %d - Sector request to read: %d",[pSelectedCard GetCardInfo]->SectorsCount,nSector]]; [self DisplayMsgErr]; return -1; } if(usingKey != USE_KEY_A && usingKey != USE_KEY_B){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::WriteSector -> Error: Invalid Key! Must be USE_KEY_A or USE_KEY_B"]]; [self DisplayMsgErr]; return -1; } MIF_KEY accessKey; accessKey.KeyType=usingKey; if(usingKey == USE_KEY_A){ memcpy(accessKey.KeyValue,pSelectedCard->KeyA,MIF_KEY_VALUE_LEN); }else{ memcpy(accessKey.KeyValue,pSelectedCard->KeyB,MIF_KEY_VALUE_LEN); } sts = MifC_WriteSectorDataAuth(hSess,&accessKey,&pSelectedCard->cardInfo.ChipID,SecData,SecDataLen,nSector); return sts; } //Erase a single Block -(int) EraseSector:(FGMifareCard *) pSelectedCard forSector:(int) nSector usingKeyNum:(int) usingKey { unsigned char aSecData[255]; memset(aSecData,0x00,255); //Empty data in the buffer return [self WriteSector:pSelectedCard forSector:nSector usingKeyNum:usingKey dataToWrite:aSecData]; } //Read all sector data -(int) ReadAllSector:(FGMifareCard *) pSelectedCard dataRead:(NSMutableData*) dataOnCard usingKeyNum:(int) usingKey { [dataOnCard setLength:0]; int sts=0; int nSectorToRead=[pSelectedCard GetCardInfo]->SectorsCount; int nSector=0; unsigned char aSecData[255]; int bytesRead=0; for(nSector=0; nSectorSectorsCount; int nSector=0; unsigned char aSecData[255]; unsigned char SecDataLen; int posBuffer=0; for(nSector=0; nSector=[pSelectedCard GetCardInfo]->SectorsCount){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::ReadACL -> Error: Invalid sector number! Max Sectors: %d - Sector request to read: %d",[pSelectedCard GetCardInfo]->SectorsCount,nSector]]; [self DisplayMsgErr]; return -1; } if(usingKey != USE_KEY_A && usingKey != USE_KEY_B){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::WriteSector -> Error: Invalid Key! Must be USE_KEY_A or USE_KEY_B"]]; [self DisplayMsgErr]; return -1; } memset(pACL,0x00,4); //Empty data in the buffer MIF_KEY accessKey; accessKey.KeyType=usingKey; if(usingKey == USE_KEY_A){ memcpy(accessKey.KeyValue,pSelectedCard->KeyA,MIF_KEY_VALUE_LEN); }else{ memcpy(accessKey.KeyValue,pSelectedCard->KeyB,MIF_KEY_VALUE_LEN); } sts=MifC_GetSectorTrailerAuth2(hSess,&accessKey,&pSelectedCard->cardInfo.ChipID,nSector,pACL,&theKeyA,theKeyB); return sts; } //Write 4 BYTES ACL -(int) WriteACL:(FGMifareCard *) pSelectedCard forSector:(int) nSector withKey:(MIF_KEY*) theWriteKey dataWrite:(unsigned char *)pACL keyA:(MIF_KEY*) theKeyA keyB:(MIF_KEY*) theKeyB { int sts=0; if(nSector >= [pSelectedCard GetCardInfo]->SectorsCount){ [self SetErrorMsg:[NSString stringWithFormat:@"FGMifareObj::WriteACL -> Error: Invalid sector number! Max Sectors: %d - Sector request to read: %d",[pSelectedCard GetCardInfo]->SectorsCount,nSector]]; [self DisplayMsgErr]; return -1; } sts=MifC_WriteSectorTrailerAuth(hSess,nSector,theWriteKey,&pSelectedCard->cardInfo.ChipID,pACL,theKeyA,theKeyB); return sts; } @end