2020-04-07 23:57:56 +08:00
#include "mifare.h"
2020-08-06 11:19:56 +08:00
const Mifare :: CardType Mifare :: card_mini =
{
0 ,
5 ,
20 ,
{ 4 , 4 , 4 , 4 , 4 },
2021-02-15 23:00:02 +08:00
{ 0 , 4 , 8 , 12 , 16 },
"mini"
2020-08-06 11:19:56 +08:00
};
const Mifare :: CardType Mifare :: card_1k =
{
1 ,
16 ,
64 ,
{ 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 },
2021-02-15 23:00:02 +08:00
{ 0 , 4 , 8 , 12 , 16 , 20 , 24 , 28 , 32 , 36 , 40 , 44 , 48 , 52 , 56 , 60 },
"1k"
2020-08-06 11:19:56 +08:00
};
const Mifare :: CardType Mifare :: card_2k =
{
2 ,
32 ,
128 ,
{ 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 },
2021-02-15 23:00:02 +08:00
{ 0 , 4 , 8 , 12 , 16 , 20 , 24 , 28 , 32 , 36 , 40 , 44 , 48 , 52 , 56 , 60 , 64 , 68 , 72 , 76 , 80 , 84 , 88 , 92 , 96 , 100 , 104 , 108 , 112 , 116 , 120 , 124 },
"2k"
2020-08-06 11:19:56 +08:00
};
const Mifare :: CardType Mifare :: card_4k =
{
4 ,
40 ,
256 ,
{ 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 },
2021-02-15 23:00:02 +08:00
{ 0 , 4 , 8 , 12 , 16 , 20 , 24 , 28 , 32 , 36 , 40 , 44 , 48 , 52 , 56 , 60 , 64 , 68 , 72 , 76 , 80 , 84 , 88 , 92 , 96 , 100 , 104 , 108 , 112 , 116 , 120 , 124 , 128 , 144 , 160 , 176 , 192 , 208 , 224 , 240 },
"4k"
2020-08-06 11:19:56 +08:00
};
const Mifare :: AccessType Mifare :: dataCondition [ 8 ][ 4 ] =
{
{ ACC_KEY_AB , ACC_KEY_AB , ACC_KEY_AB , ACC_KEY_AB },
{ ACC_KEY_AB , ACC_KEY_B , ACC_NEVER , ACC_NEVER },
2020-08-09 10:32:48 +08:00
{ ACC_KEY_AB , ACC_NEVER , ACC_NEVER , ACC_NEVER },
2020-08-06 11:19:56 +08:00
{ ACC_KEY_AB , ACC_KEY_B , ACC_KEY_B , ACC_KEY_AB },
{ ACC_KEY_AB , ACC_NEVER , ACC_NEVER , ACC_KEY_AB },
{ ACC_KEY_B , ACC_NEVER , ACC_NEVER , ACC_NEVER },
2020-08-09 10:32:48 +08:00
{ ACC_KEY_B , ACC_KEY_B , ACC_NEVER , ACC_NEVER },
2020-08-06 11:19:56 +08:00
{ ACC_NEVER , ACC_NEVER , ACC_NEVER , ACC_NEVER },
};
const Mifare :: AccessType Mifare :: trailerReadCondition [ 8 ][ 3 ] =
{
{ ACC_NEVER , ACC_KEY_A , ACC_KEY_A },
{ ACC_NEVER , ACC_KEY_AB , ACC_NEVER },
2020-08-09 10:32:48 +08:00
{ ACC_NEVER , ACC_KEY_A , ACC_KEY_A },
2020-08-06 11:19:56 +08:00
{ ACC_NEVER , ACC_KEY_AB , ACC_NEVER },
{ ACC_NEVER , ACC_KEY_A , ACC_KEY_A },
{ ACC_NEVER , ACC_KEY_AB , ACC_NEVER },
{ ACC_NEVER , ACC_KEY_AB , ACC_NEVER },
{ ACC_NEVER , ACC_KEY_AB , ACC_NEVER },
};
const Mifare :: AccessType Mifare :: trailerWriteCondition [ 8 ][ 3 ] =
{
{ ACC_KEY_A , ACC_NEVER , ACC_KEY_A },
{ ACC_KEY_B , ACC_NEVER , ACC_KEY_B },
{ ACC_NEVER , ACC_NEVER , ACC_NEVER },
2020-08-09 10:32:48 +08:00
{ ACC_NEVER , ACC_NEVER , ACC_NEVER },
2020-08-06 11:19:56 +08:00
{ ACC_KEY_A , ACC_KEY_A , ACC_KEY_A },
{ ACC_NEVER , ACC_KEY_B , ACC_NEVER },
2020-08-09 10:32:48 +08:00
{ ACC_KEY_B , ACC_KEY_B , ACC_KEY_B },
2020-08-06 11:19:56 +08:00
{ ACC_NEVER , ACC_NEVER , ACC_NEVER },
};
2020-04-30 21:00:57 +08:00
Mifare :: Mifare ( Ui :: MainWindow * ui , Util * addr , QWidget * parent ) : QObject ( parent )
2020-04-07 23:57:56 +08:00
{
2020-04-24 22:11:35 +08:00
this -> parent = parent ;
2020-04-22 23:13:00 +08:00
util = addr ;
this -> ui = ui ;
2020-04-24 16:25:52 +08:00
cardType = card_1k ;
2020-04-23 17:50:20 +08:00
keyAList = new QStringList ();
keyBList = new QStringList ();
dataList = new QStringList ();
2020-08-05 22:46:41 +08:00
data_clearKey (); // fill with blank QString
data_clearData (); // fill with blank QString
2020-08-06 00:38:44 +08:00
dataPattern = new QRegularExpression ( "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}" );
2021-02-16 01:17:50 +08:00
keyPattern_res = new QRegularExpression ( " \\ | \\ s* \\ d{3} \\ s* \\ | \\ s*.+? \\ s* \\ | \\ s*.+? \\ s* \\ | \\ s*.+? \\ s* \\ | \\ s*.+? \\ s* \\ |" );
keyPattern = new QRegularExpression ( " \\ | \\ s* \\ d{3} \\ s* \\ | \\ s*.+? \\ s* \\ | \\ s*.+? \\ s* \\ |" );
2020-04-07 23:57:56 +08:00
}
2020-04-29 14:47:40 +08:00
QString Mifare :: info ( bool isRequiringOutput )
2020-04-07 23:57:56 +08:00
{
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL || Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
2020-04-29 14:47:40 +08:00
{
2020-08-05 22:46:41 +08:00
if ( isRequiringOutput )
2020-04-29 14:47:40 +08:00
{
2020-08-05 22:46:41 +08:00
QString result = util -> execCMDWithOutput ( "hf 14a info" , 500 );
2021-02-16 01:17:50 +08:00
int begin , end ;
begin = result . indexOf ( "UID" );
if ( begin != - 1 )
2020-08-05 22:46:41 +08:00
{
2021-02-16 01:17:50 +08:00
end = result . indexOf ( "SAK" , begin );
end = result . indexOf ( " \n " , end );
return result . mid ( begin , end - begin + 1 );
2020-08-05 22:46:41 +08:00
}
2020-04-29 14:47:40 +08:00
}
else
2020-08-05 22:46:41 +08:00
{
util -> execCMD ( "hf 14a info" );
2021-02-13 23:58:11 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2020-08-05 22:46:41 +08:00
}
2020-04-29 14:47:40 +08:00
}
2021-02-17 01:26:14 +08:00
return "" ;
2020-04-22 23:13:00 +08:00
}
2020-04-07 23:57:56 +08:00
2020-04-22 23:13:00 +08:00
void Mifare :: chk ()
{
2020-08-05 22:46:41 +08:00
QRegularExpressionMatch reMatch ;
2021-02-13 23:58:11 +08:00
QString result ;
2020-04-24 16:25:52 +08:00
int offset = 0 ;
2020-08-05 22:46:41 +08:00
QString data ;
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL )
2020-04-22 23:13:00 +08:00
{
2021-02-13 23:58:11 +08:00
result = util -> execCMDWithOutput (
"hf mf chk *"
+ QString :: number ( cardType . type )
+ " ?" ,
2021-02-16 01:17:50 +08:00
Util :: ReturnTrigger ( 1000 + cardType . sector_size * 200 , { "No valid" , keyPattern -> pattern ()}));
qDebug () << result ;
2020-08-05 22:46:41 +08:00
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
{
reMatch = keyPattern -> match ( result , offset );
offset = reMatch . capturedStart ();
if ( reMatch . hasMatch ())
{
data = reMatch . captured (). toUpper ();
offset += data . length ();
QStringList cells = data . remove ( " " ). split ( "|" );
2020-08-07 17:30:48 +08:00
if ( ! cells [ 2 ]. contains ( "?" ))
2020-08-05 22:46:41 +08:00
{
2020-08-07 17:30:48 +08:00
keyAList -> replace ( i , cells [ 2 ]);
2020-08-05 22:46:41 +08:00
}
2020-08-07 17:30:48 +08:00
if ( ! cells [ 3 ]. contains ( "?" ))
2020-08-05 22:46:41 +08:00
{
2020-08-07 17:30:48 +08:00
keyBList -> replace ( i , cells [ 3 ]);
2020-08-05 22:46:41 +08:00
}
}
}
2020-04-07 23:57:56 +08:00
}
2021-02-16 13:52:04 +08:00
else if ( Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
2020-08-05 22:46:41 +08:00
{
2021-02-13 23:58:11 +08:00
result = util -> execCMDWithOutput (
2021-02-15 23:00:02 +08:00
"hf mf chk --"
+ cardType . typeText ,
Util :: ReturnTrigger ( 1000 + cardType . sector_size * 200 , { "No valid" , keyPattern_res -> pattern ()}));
qDebug () << "mf_chk_iceman_result" << result ;
2020-08-05 22:46:41 +08:00
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
{
reMatch = keyPattern_res -> match ( result , offset );
offset = reMatch . capturedStart ();
if ( reMatch . hasMatch ())
{
data = reMatch . captured (). toUpper ();
offset += data . length ();
QStringList cells = data . remove ( " " ). split ( "|" );
2020-08-07 17:30:48 +08:00
if ( cells [ 3 ] == "1" )
2020-08-05 22:46:41 +08:00
{
2020-08-07 17:30:48 +08:00
keyAList -> replace ( i , cells [ 2 ]);
2020-08-05 22:46:41 +08:00
}
2020-08-07 17:30:48 +08:00
if ( cells [ 5 ] == "1" )
2020-08-05 22:46:41 +08:00
{
2020-08-07 17:30:48 +08:00
keyBList -> replace ( i , cells [ 4 ]);
2020-08-05 22:46:41 +08:00
}
}
}
}
2020-04-23 17:50:20 +08:00
data_syncWithKeyWidget ();
2020-04-07 23:57:56 +08:00
}
2020-04-22 23:13:00 +08:00
void Mifare :: nested ()
2020-04-07 23:57:56 +08:00
{
2020-08-05 23:55:14 +08:00
QRegularExpressionMatch reMatch ;
QString result ;
int offset = 0 ;
QString data ;
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL )
2020-08-05 23:55:14 +08:00
{
result = util -> execCMDWithOutput (
"hf mf nested "
+ QString :: number ( cardType . type )
2020-08-12 12:30:15 +08:00
+ " *" ,
2021-02-15 23:00:02 +08:00
Util :: ReturnTrigger ( 15000 , { "Can't found" , " \\ |000 \\ |" }));
2020-08-05 23:55:14 +08:00
}
2021-02-16 13:52:04 +08:00
else if ( Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
2020-08-05 23:55:14 +08:00
{
QString knownKeyInfo = "" ;
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
{
if ( data_isKeyValid ( keyAList -> at ( i )))
{
2021-02-15 23:00:02 +08:00
knownKeyInfo = " --blk " + QString :: number ( i * 4 ) + " -a -k " + keyAList -> at ( i );
2020-08-05 23:55:14 +08:00
break ;
}
}
if ( knownKeyInfo == "" )
{
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
{
if ( data_isKeyValid ( keyBList -> at ( i )))
{
2021-02-15 23:00:02 +08:00
knownKeyInfo = " --blk " + QString :: number ( i * 4 ) + " -b -k " + keyBList -> at ( i );
2020-08-05 23:55:14 +08:00
break ;
}
}
}
if ( knownKeyInfo != "" )
{
result = util -> execCMDWithOutput (
2021-02-15 23:00:02 +08:00
"hf mf nested --"
+ cardType . typeText
2021-02-13 23:58:11 +08:00
+ knownKeyInfo ,
2021-02-15 23:00:02 +08:00
Util :: ReturnTrigger ( 15000 , { "Can't authenticate" , keyPattern_res -> pattern ()}));
2020-08-05 23:55:14 +08:00
}
else
{
QMessageBox :: information ( parent , tr ( "Info" ), tr ( "Plz provide at least one known key" ));
}
2020-04-24 16:25:52 +08:00
2020-08-05 23:55:14 +08:00
}
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
2020-04-07 23:57:56 +08:00
{
2020-08-05 23:55:14 +08:00
reMatch = keyPattern_res -> match ( result , offset );
offset = reMatch . capturedStart ();
if ( reMatch . hasMatch ())
{
data = reMatch . captured (). toUpper ();
offset += data . length ();
QStringList cells = data . remove ( " " ). split ( "|" );
2020-08-07 17:30:48 +08:00
if ( cells [ 3 ] == "1" )
2020-08-05 23:55:14 +08:00
{
2020-08-07 17:30:48 +08:00
keyAList -> replace ( i , cells [ 2 ]);
2020-08-05 23:55:14 +08:00
}
2020-08-07 17:30:48 +08:00
if ( cells [ 5 ] == "1" )
2020-08-05 23:55:14 +08:00
{
2020-08-07 17:30:48 +08:00
keyBList -> replace ( i , cells [ 4 ]);
2020-08-05 23:55:14 +08:00
}
}
2020-04-07 23:57:56 +08:00
}
2020-04-23 17:50:20 +08:00
data_syncWithKeyWidget ();
2020-08-05 23:55:14 +08:00
2020-04-22 23:13:00 +08:00
}
void Mifare :: hardnested ()
{
2020-08-04 16:05:21 +08:00
MF_Attack_hardnestedDialog dialog ( cardType . block_size );
2020-04-22 23:13:00 +08:00
connect ( & dialog , & MF_Attack_hardnestedDialog :: sendCMD , util , & Util :: execCMD );
2020-04-30 21:00:57 +08:00
if ( dialog . exec () == QDialog :: Accepted )
2021-02-13 23:58:11 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2020-04-22 23:13:00 +08:00
}
2021-02-12 23:45:25 +08:00
void Mifare :: darkside ()
{
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL )
2021-02-12 23:45:25 +08:00
util -> execCMD ( "hf mf mifare" );
2021-02-16 13:52:04 +08:00
else if ( Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
2021-02-12 23:45:25 +08:00
util -> execCMD ( "hf mf darkside" );
2021-02-16 13:52:04 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2021-02-12 23:45:25 +08:00
}
2020-04-22 23:13:00 +08:00
void Mifare :: sniff ()
{
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL )
util -> execCMD ( "hf mf sniff" );
else if ( Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
util -> execCMD ( "hf sniff" );
2021-02-13 23:58:11 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2020-04-22 23:13:00 +08:00
}
2021-02-16 13:52:04 +08:00
void Mifare :: sniff14a ()
2020-08-04 13:44:20 +08:00
{
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL )
util -> execCMD ( "hf 14a snoop" );
else if ( Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
util -> execCMD ( "hf 14a sniff" );
2021-02-13 23:58:11 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2020-08-04 13:44:20 +08:00
}
2020-04-22 23:13:00 +08:00
void Mifare :: list ()
{
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL )
util -> execCMD ( "hf list mf" );
else if ( Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
util -> execCMD ( "trace list -t mf" );
2021-02-13 23:58:11 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2020-04-22 23:13:00 +08:00
}
2020-08-08 21:04:09 +08:00
QString Mifare :: _readblk ( int blockId , KeyType keyType , const QString & key , TargetType targetType , int waitTime )
2020-08-01 21:30:55 +08:00
{
QString data ;
QString result ;
2021-02-15 23:46:05 +08:00
QRegularExpressionMatch currMatch ;
2020-08-11 11:30:33 +08:00
bool isTrailerBlock = ( blockId < 128 && (( blockId + 1 ) % 4 == 0 )) || (( blockId + 1 ) % 16 == 0 );
2020-08-04 13:44:20 +08:00
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL || Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
2020-08-01 21:30:55 +08:00
{
2020-08-08 17:41:08 +08:00
if ( targetType == TARGET_MIFARE )
2020-08-01 21:30:55 +08:00
{
2020-08-08 17:41:08 +08:00
if ( ! data_isKeyValid ( key ))
2020-04-22 23:13:00 +08:00
{
2020-08-08 17:41:08 +08:00
return "" ;
}
// use the given key type to read the target block
result = util -> execCMDWithOutput (
"hf mf rdbl "
+ QString :: number ( blockId )
+ " "
+ ( char ) keyType
+ " "
+ key ,
waitTime );
2021-02-15 23:46:05 +08:00
currMatch = dataPattern -> match ( result );
if ( currMatch . hasMatch ())
2020-08-08 17:41:08 +08:00
{
2021-02-15 23:46:05 +08:00
data = currMatch . captured (). toUpper ();
2020-08-08 17:41:08 +08:00
data . remove ( " " );
// when the target block is a key block and the given key type is KeyA, try to check whether the KeyB is valid(by Access Bits)
// if the given key type is KeyB, it will never get the KeyA from the key block
2020-08-11 11:30:33 +08:00
if ( isTrailerBlock && keyType == KEY_A ) // in this case, the Access Bits is always accessible
2020-08-08 17:41:08 +08:00
{
data . replace ( 0 , 12 , key );
QList < quint8 > ACBits = data_getACBits ( data . mid ( 12 , 8 ));
if ( ACBits [ 3 ] == 2 || ACBits [ 3 ] == 3 || ACBits [ 3 ] == 5 || ACBits [ 3 ] == 6 || ACBits [ 3 ] == 7 ) // in these cases, the KeyB cannot be read by KeyA
{
data . replace ( 20 , 12 , "????????????" );
}
}
2020-08-11 11:30:33 +08:00
else if ( isTrailerBlock && keyType == KEY_B )
2020-04-22 23:13:00 +08:00
{
2020-08-08 17:41:08 +08:00
data . replace ( 20 , 12 , key );;
data . replace ( 0 , 12 , "????????????" ); // fill the keyA part with ?
2020-04-22 23:13:00 +08:00
}
}
2020-08-08 17:41:08 +08:00
else
data = "" ;
}
else if ( targetType == TARGET_UID )
{
result = util -> execCMDWithOutput (
"hf mf cgetblk "
+ QString :: number ( blockId ),
waitTime );
2021-02-15 23:46:05 +08:00
currMatch = dataPattern -> match ( result );
if ( currMatch . hasMatch ())
2020-04-22 23:13:00 +08:00
{
2021-02-15 23:46:05 +08:00
data = currMatch . captured (). toUpper ();
2020-08-08 17:41:08 +08:00
data . remove ( " " );
2020-04-22 23:13:00 +08:00
}
2020-08-08 17:41:08 +08:00
else
data = "" ;
2020-04-22 23:13:00 +08:00
}
2021-02-15 23:46:05 +08:00
}
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL )
2021-02-15 23:46:05 +08:00
{
if ( targetType == TARGET_EMULATOR )
2020-04-22 23:13:00 +08:00
{
2020-08-08 17:41:08 +08:00
result = util -> execCMDWithOutput (
"hf mf eget "
+ QString :: number ( blockId ),
2020-08-08 21:04:09 +08:00
150 );
2020-08-08 17:41:08 +08:00
data = dataPattern -> match ( result ). captured (). toUpper ();
data . remove ( " " );
2020-08-04 13:44:20 +08:00
}
}
2021-02-16 13:52:04 +08:00
else if ( Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
2021-02-15 23:46:05 +08:00
{
if ( targetType == TARGET_EMULATOR )
{
result = util -> execCMDWithOutput (
"hf mf egetblk "
+ QString :: number ( blockId ),
150 );
data = dataPattern -> match ( result ). captured (). toUpper ();
data . remove ( " " );
}
}
2020-08-06 00:38:44 +08:00
return data ;
2020-08-04 13:44:20 +08:00
}
2020-08-08 21:04:09 +08:00
QStringList Mifare :: _readsec ( int sectorId , KeyType keyType , const QString & key , TargetType targetType , int waitTime )
2020-08-04 13:44:20 +08:00
{
QStringList data ;
QString result , tmp ;
2020-08-06 00:38:44 +08:00
QRegularExpressionMatch reMatch ;
2021-02-15 23:46:05 +08:00
int offset = - 1 ; // for targetType == TARGET_EMULATOR
2020-08-04 13:44:20 +08:00
2020-08-07 17:30:48 +08:00
for ( int i = 0 ; i < cardType . blk [ sectorId ]; i ++ )
{
data . append ( "" );
}
2020-08-04 13:44:20 +08:00
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL || Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
2020-08-04 13:44:20 +08:00
{
2020-08-07 17:30:48 +08:00
// try to read all blocks together
2020-08-08 21:04:09 +08:00
if ( targetType == TARGET_MIFARE )
{
if ( ! data_isKeyValid ( key ))
{
return data ;
}
result = util -> execCMDWithOutput (
"hf mf rdsc "
+ QString :: number ( sectorId )
+ " "
+ ( char ) keyType
+ " "
+ key ,
waitTime );
2021-02-15 23:46:05 +08:00
offset = result . indexOf ( "isOk:01" ); // find successful flag
2020-08-08 21:04:09 +08:00
}
else if ( targetType == TARGET_UID )
{
result = util -> execCMDWithOutput (
"hf mf cgetsc "
+ QString :: number ( sectorId ),
waitTime );
2021-02-15 23:46:05 +08:00
offset = result . indexOf ( "error" ) == - 1 ? 0 : - 1 ; // find failed flag
2020-08-08 21:04:09 +08:00
}
2020-08-04 13:44:20 +08:00
if ( offset != - 1 )
{
for ( int i = 0 ; i < cardType . blk [ sectorId ]; i ++ )
{
2020-08-06 00:38:44 +08:00
reMatch = dataPattern -> match ( result , offset );
offset = reMatch . capturedStart ();
if ( reMatch . hasMatch ())
{
tmp = reMatch . captured (). toUpper ();
offset += tmp . length ();
tmp . remove ( " " );
2020-08-07 17:30:48 +08:00
data [ i ] = tmp ;
}
}
}
// if failed, try to read them seperately.
// (when one of the block cannot be read, the rdsc will return nothing, so you need to read the rest of blocks manually)
2021-02-15 23:46:05 +08:00
else if ( targetType == TARGET_UID || targetType == TARGET_EMULATOR ) // if the targetType is Chinese Magic Card, then the result implies the backdoor command is invalid.
2020-08-07 17:30:48 +08:00
{
for ( int i = 0 ; i < cardType . blk [ sectorId ]; i ++ )
2020-08-08 21:04:09 +08:00
data [ i ] = _readblk ( cardType . blks [ sectorId ] + i , keyType , key , targetType , waitTime );
2020-08-07 17:30:48 +08:00
}
//process trailer(like _readblk())
QString trailer = data [ cardType . blk [ sectorId ] - 1 ];
2020-08-08 21:04:09 +08:00
if ( trailer != "" && targetType == TARGET_MIFARE )
2020-08-07 17:30:48 +08:00
{
if ( keyType == KEY_A ) // in this case, the Access Bits is always accessible
{
trailer . replace ( 0 , 12 , key );
QList < quint8 > ACBits = data_getACBits ( trailer . mid ( 12 , 8 ));
if ( ACBits [ 3 ] == 2 || ACBits [ 3 ] == 3 || ACBits [ 3 ] == 5 || ACBits [ 3 ] == 6 || ACBits [ 3 ] == 7 ) // in these cases, the KeyB cannot be read by KeyA
{
trailer . replace ( 20 , 12 , "????????????" );
2020-08-06 00:38:44 +08:00
}
2020-08-04 13:44:20 +08:00
}
2020-08-07 17:30:48 +08:00
else if ( keyType == KEY_B )
{
trailer . replace ( 20 , 12 , key );;
trailer . replace ( 0 , 12 , "????????????" ); // fill the keyA part with ?
}
data [ cardType . blk [ sectorId ] - 1 ] = trailer ;
2020-04-22 23:13:00 +08:00
}
2020-04-07 23:57:56 +08:00
}
2020-08-04 13:44:20 +08:00
return data ;
}
2020-08-08 17:41:08 +08:00
void Mifare :: readOne ( TargetType targetType )
2020-08-04 13:44:20 +08:00
{
int blockId = ui -> MF_RW_blockBox -> currentText (). toInt ();
Mifare :: KeyType keyType = ( Mifare :: KeyType )( ui -> MF_RW_keyTypeBox -> currentData (). toInt ());
2020-08-08 17:41:08 +08:00
QString result = _readblk ( blockId , keyType , ui -> MF_RW_keyEdit -> text (). toUpper (), targetType );
2020-08-04 13:44:20 +08:00
if ( result != "" )
{
ui -> MF_RW_dataEdit -> setText ( result );
}
else
{
2020-08-04 16:05:21 +08:00
ui -> MF_RW_dataEdit -> setText ( tr ( "Failed!" ));
2020-08-04 13:44:20 +08:00
}
2020-04-22 23:13:00 +08:00
}
2020-08-08 21:04:09 +08:00
void Mifare :: readSelected ( TargetType targetType )
2020-04-22 23:13:00 +08:00
{
2020-08-07 17:30:48 +08:00
QStringList data , dataA , dataB ;
QString trailerA , trailerB ;
2020-08-07 23:51:24 +08:00
QList < bool > selectedSectors ;
2020-08-08 21:04:09 +08:00
QList < int > selectedBlocks ;
for ( int i = 0 ; i < cardType . block_size ; i ++ )
{
if ( ui -> MF_dataWidget -> item ( i , 1 ) -> checkState () == Qt :: Checked )
selectedBlocks . append ( i );
}
2020-04-24 16:25:52 +08:00
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
2020-04-07 23:57:56 +08:00
{
2020-08-07 23:51:24 +08:00
selectedSectors . append ( false );
}
for ( int item : selectedBlocks )
{
2020-08-08 00:19:37 +08:00
selectedSectors [ data_b2s ( item )] = true ;
2020-08-07 23:51:24 +08:00
}
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
{
2020-04-22 23:13:00 +08:00
{
2020-08-08 21:04:09 +08:00
if ( ! selectedSectors [ i ])
{
continue ;
}
for ( int j = 0 ; j < cardType . blk [ i ]; j ++ )
{
// dataA is always filled with "" because of the _readsec()
data . append ( "" );
dataB . append ( "" );
}
2020-08-04 16:05:21 +08:00
2020-08-08 21:04:09 +08:00
dataA = _readsec ( i , Mifare :: KEY_A , keyAList -> at ( i ), targetType );
2020-08-07 17:30:48 +08:00
2020-08-08 21:04:09 +08:00
// in other situations, the key doesn't matters
if ( targetType == TARGET_MIFARE && ( dataA . contains ( "" ) || dataA [ cardType . blk [ i ] - 1 ]. right ( 12 ) == "????????????" ))
dataB = _readsec ( i , Mifare :: KEY_B , keyBList -> at ( i ), targetType );
2020-04-23 23:54:51 +08:00
2020-08-08 21:04:09 +08:00
for ( int j = 0 ; j < cardType . blk [ i ]; j ++ )
{
if ( dataA [ j ] != "" )
data [ j ] = dataA [ j ];
else
data [ j ] = dataB [ j ];
}
2020-08-04 16:05:21 +08:00
2020-08-08 21:04:09 +08:00
// process trailer block seperately
trailerA = dataA [ cardType . blk [ i ] - 1 ];
trailerB = dataB [ cardType . blk [ i ] - 1 ];
if ( trailerA != "" && trailerB != "" )
2020-08-07 23:51:24 +08:00
{
2020-08-08 21:04:09 +08:00
QString ACbits = trailerA . mid ( 12 , 8 );
QString key_A = trailerA . left ( 12 );
QString key_B = trailerA . at ( 31 ) != '?' ? trailerA . right ( 12 ) : trailerB . right ( 12 );
data [ cardType . blk [ i ] - 1 ] = key_A + ACbits + key_B ;
2020-08-07 23:51:24 +08:00
}
2020-04-24 22:11:35 +08:00
2020-08-08 21:04:09 +08:00
for ( int j = 0 ; j < cardType . blk [ i ]; j ++ )
{
if ( selectedBlocks . contains ( cardType . blks [ i ] + j ))
{
dataList -> replace ( cardType . blks [ i ] + j , data [ j ]);
data_syncWithDataWidget ( false , cardType . blks [ i ] + j );
}
}
if ( selectedBlocks . contains ( cardType . blks [ i ] + cardType . blk [ i ] - 1 ))
{
// data widget has been updated, so this is just a temporary varient.
if ( data [ cardType . blk [ i ] - 1 ] == "" )
data [ cardType . blk [ i ] - 1 ] = "????????????????????????????????" ;
// doesn't replace the existing key.
if ( ! data_isKeyValid ( keyAList -> at ( i )))
keyAList -> replace ( i , data [ cardType . blk [ i ] - 1 ]. left ( 12 ));
if ( ! data_isKeyValid ( keyBList -> at ( i )))
keyBList -> replace ( i , data [ cardType . blk [ i ] - 1 ]. right ( 12 ));
data_syncWithKeyWidget ( false , i , KEY_A );
data_syncWithKeyWidget ( false , i , KEY_B );
}
2020-04-22 23:13:00 +08:00
2020-08-08 21:04:09 +08:00
}
2020-08-07 23:51:24 +08:00
}
}
2020-08-08 17:41:08 +08:00
bool Mifare :: _writeblk ( int blockId , KeyType keyType , const QString & key , const QString & data , TargetType targetType , int waitTime )
2020-08-07 23:51:24 +08:00
{
2020-08-08 17:41:08 +08:00
QString result ;
2020-08-07 23:51:24 +08:00
QString input = data . toUpper ();
2020-08-11 11:30:33 +08:00
input . remove ( " " );
2020-08-08 17:41:08 +08:00
if ( data_isDataValid ( input ) != DATA_NOSPACE )
2020-08-07 23:51:24 +08:00
return false ;
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL || Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
2020-08-07 23:51:24 +08:00
{
2020-08-08 17:41:08 +08:00
if ( targetType == TARGET_MIFARE )
{
if ( ! data_isKeyValid ( key ))
return false ;
result = util -> execCMDWithOutput (
"hf mf wrbl "
+ QString :: number ( blockId )
+ " "
+ ( char ) keyType
+ " "
+ key
+ " "
+ input ,
waitTime );
return ( result . indexOf ( "isOk:01" ) != - 1 );
}
else if ( targetType == TARGET_UID )
{
result = util -> execCMDWithOutput (
"hf mf csetblk "
+ QString :: number ( blockId )
+ " "
+ input ,
waitTime );
2021-02-16 01:17:50 +08:00
return ( result . indexOf ( "error" ) == - 1 ); // failed flag
2020-08-08 17:41:08 +08:00
}
else if ( targetType == TARGET_EMULATOR )
{
2020-08-08 21:04:09 +08:00
util -> execCMD (
"hf mf eset "
+ QString :: number ( blockId )
+ " "
+ input );
util -> delay ( 5 );
2020-08-08 17:41:08 +08:00
return true ;
}
2020-04-07 23:57:56 +08:00
}
2021-02-17 01:26:14 +08:00
return false ;
2020-04-07 23:57:56 +08:00
}
2020-04-22 23:13:00 +08:00
2020-08-08 17:41:08 +08:00
void Mifare :: writeOne ( TargetType targetType )
2020-04-07 23:57:56 +08:00
{
2020-08-07 23:51:24 +08:00
int blockId = ui -> MF_RW_blockBox -> currentText (). toInt ();
Mifare :: KeyType keyType = ( Mifare :: KeyType )( ui -> MF_RW_keyTypeBox -> currentData (). toInt ());
2020-08-08 17:41:08 +08:00
bool isSuccessful = _writeblk ( blockId , keyType , ui -> MF_RW_keyEdit -> text (). toUpper (), ui -> MF_RW_dataEdit -> text (), targetType );
2020-08-07 23:51:24 +08:00
if ( isSuccessful )
2020-04-22 23:13:00 +08:00
{
2020-04-25 18:15:00 +08:00
QMessageBox :: information ( parent , tr ( "Info" ), tr ( "Success!" ));
2020-04-24 22:11:35 +08:00
}
else
{
2020-04-25 18:15:00 +08:00
QMessageBox :: information ( parent , tr ( "Info" ), tr ( "Failed!" ));
2020-04-22 23:13:00 +08:00
}
2020-04-07 23:57:56 +08:00
}
2020-04-22 21:14:33 +08:00
2020-08-09 10:32:48 +08:00
void Mifare :: writeSelected ( TargetType targetType )
2020-04-22 21:14:33 +08:00
{
2020-08-08 21:04:09 +08:00
QList < int > failedBlocks ;
QList < int > selectedBlocks ;
2020-08-11 11:30:33 +08:00
bool yes2All = false , no2All = false ;
2020-08-08 21:04:09 +08:00
for ( int i = 0 ; i < cardType . block_size ; i ++ )
2020-04-22 21:14:33 +08:00
{
2020-08-08 21:04:09 +08:00
if ( ui -> MF_dataWidget -> item ( i , 1 ) -> checkState () == Qt :: Checked )
selectedBlocks . append ( i );
2020-04-22 21:14:33 +08:00
}
2020-08-08 21:04:09 +08:00
for ( int item : selectedBlocks )
2020-04-25 00:57:28 +08:00
{
2020-08-08 21:04:09 +08:00
bool result = false ;
2020-08-11 11:30:33 +08:00
bool isTrailerBlock = ( item < 128 && (( item + 1 ) % 4 == 0 )) || (( item + 1 ) % 16 == 0 );
if ( isTrailerBlock && ! data_isACBitsValid ( dataList -> at ( item ). mid ( 12 , 8 ))) // trailer block is invalid
{
if ( ! yes2All && ! no2All )
{
QMessageBox :: StandardButton choice = QMessageBox :: information ( parent , tr ( "Info" ),
tr ( "The Access Bits is invalid! \n It could make the whole sector blocked irreversibly! \n Continue to write?" ),
QMessageBox :: Yes | QMessageBox :: YesToAll | QMessageBox :: No | QMessageBox :: NoToAll );
if ( choice == QMessageBox :: No )
continue ;
else if ( choice == QMessageBox :: YesToAll )
yes2All = true ;
2020-08-12 12:30:15 +08:00
else if ( choice == QMessageBox :: NoToAll )
2020-08-11 11:30:33 +08:00
{
no2All = true ;
continue ;
}
}
else if ( no2All )
continue ;
}
2020-08-08 21:04:09 +08:00
if ( targetType == TARGET_MIFARE )
2020-04-25 00:57:28 +08:00
{
2020-08-08 21:04:09 +08:00
result = _writeblk ( item , KEY_A , keyAList -> at ( data_b2s ( item )), dataList -> at ( item ), TARGET_MIFARE );
if ( ! result )
2020-04-25 00:57:28 +08:00
{
2020-08-08 21:04:09 +08:00
result = _writeblk ( item , KEY_B , keyBList -> at ( data_b2s ( item )), dataList -> at ( item ), TARGET_MIFARE );
}
if ( ! result )
{
result = _writeblk ( item , KEY_A , "FFFFFFFFFFFF" , dataList -> at ( item ), TARGET_MIFARE );
2020-04-25 00:57:28 +08:00
}
}
2020-08-08 21:04:09 +08:00
else // key doesn't matter when writing to Chinese Magic Card and Emulator Memory
2020-04-25 00:57:28 +08:00
{
2020-08-08 21:04:09 +08:00
result = _writeblk ( item , KEY_A , "FFFFFFFFFFFF" , dataList -> at ( item ), targetType );
}
if ( ! result )
{
failedBlocks . append ( item );
2020-04-25 00:57:28 +08:00
}
}
2020-08-09 10:32:48 +08:00
if ( failedBlocks . size () == 0 )
QMessageBox :: information ( parent , tr ( "Info" ), tr ( "Successful!" ));
else
{
QString suffix = "" ;
int counter = 0 ;
for ( int failedBlk : failedBlocks )
{
suffix += QString :: number ( failedBlk ) + " " ;
counter ++ ;
counter %= 20 ;
if ( counter == 0 )
suffix += " \n " ;
}
QMessageBox :: StandardButton res = QMessageBox :: information ( parent , tr ( "Info" ), tr ( "Failed to write to these blocks:" )
+ " \n "
+ suffix
+ " \n "
+ tr ( "Select them?" ),
QMessageBox :: Yes | QMessageBox :: No );
if ( res == QMessageBox :: Yes )
{
for ( int item : selectedBlocks )
{
ui -> MF_dataWidget -> item ( item , 1 ) -> setCheckState ( Qt :: Unchecked );
}
for ( int failedBlk : failedBlocks )
{
ui -> MF_dataWidget -> item ( failedBlk , 1 ) -> setCheckState ( Qt :: Checked );
}
}
}
2020-04-25 00:57:28 +08:00
}
2020-05-01 23:37:23 +08:00
void Mifare :: dump ()
{
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL || Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
util -> execCMD ( "hf mf dump" );
2021-02-13 23:58:11 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2020-05-01 23:37:23 +08:00
}
void Mifare :: restore ()
{
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL || Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
util -> execCMD ( "hf mf restore" );
2021-02-13 23:58:11 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2020-05-01 23:37:23 +08:00
}
2020-04-25 00:57:28 +08:00
void Mifare :: wipeC ()
{
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL )
2021-02-16 01:17:50 +08:00
{
util -> execCMD (
"hf mf cwipe "
+ QString :: number ( cardType . type )
+ " f" );
}
2021-02-16 13:52:04 +08:00
else if ( Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
2021-02-16 01:17:50 +08:00
{
util -> execCMD ( "hf mf cwipe" );
}
2021-02-13 23:58:11 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2020-04-25 00:57:28 +08:00
}
void Mifare :: setParameterC ()
{
2020-04-29 14:47:40 +08:00
QString result = info ( true );
2020-04-30 21:00:57 +08:00
if ( result == "" )
2020-04-29 14:47:40 +08:00
QMessageBox :: information ( parent , tr ( "Info" ), tr ( "Failed to read card." ));
else
{
2021-02-16 01:17:50 +08:00
result . replace ( " \r\n " , "" );
result . replace ( QRegularExpression ( " \\ [. \\ ]" ), "" );
result . replace ( "UID" , "" );
result . replace ( "ATQA" , "" );
result . replace ( "SAK" , "" );
result . replace ( " " , "" );
QStringList lis = result . split ( ':' );
qDebug () << lis ;
MF_UID_parameterDialog dialog ( lis [ 1 ]. toUpper (), lis [ 2 ]. toUpper (), lis [ 3 ]. toUpper ());
2020-04-29 14:47:40 +08:00
connect ( & dialog , & MF_UID_parameterDialog :: sendCMD , util , & Util :: execCMD );
2020-04-30 21:00:57 +08:00
if ( dialog . exec () == QDialog :: Accepted )
2021-02-13 23:58:11 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2020-04-29 14:47:40 +08:00
}
2020-04-25 00:57:28 +08:00
}
2020-04-29 14:47:40 +08:00
void Mifare :: lockC ()
{
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL )
2021-02-16 01:17:50 +08:00
{
util -> execCMD ( "hf 14a raw -pa -b7 40" );
util -> execCMD ( "hf 14a raw -pa 43" );
util -> execCMD ( "hf 14a raw -pa E0 00 39 F7" );
util -> execCMD ( "hf 14a raw -pa E1 00 E1 EE" );
util -> execCMD ( "hf 14a raw -pa 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47" );
util -> execCMD ( "hf 14a raw -a 52" );
}
2021-02-16 13:52:04 +08:00
else if ( Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
2021-02-16 01:17:50 +08:00
{
util -> execCMD ( "hf 14a raw -ak -b 7 40" );
util -> execCMD ( "hf 14a raw -ak 43" );
util -> execCMD ( "hf 14a raw -ak E0 00 39 F7" );
util -> execCMD ( "hf 14a raw -ak E1 00 E1 EE" );
util -> execCMD ( "hf 14a raw -ak 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47" );
util -> execCMD ( "hf 14a raw -a 52" );
}
2020-04-29 14:47:40 +08:00
}
2020-04-25 00:57:28 +08:00
2020-04-30 20:32:43 +08:00
void Mifare :: wipeE ()
{
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL || Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
util -> execCMD ( "hf mf eclr" );
2020-04-30 20:32:43 +08:00
}
2020-05-01 23:37:23 +08:00
void Mifare :: simulate ()
2020-04-22 23:35:24 +08:00
{
2021-02-16 13:52:04 +08:00
MF_Sim_simDialog dialog ( cardType . type , cardType . typeText );
2020-05-03 00:14:49 +08:00
connect ( & dialog , & MF_Sim_simDialog :: sendCMD , util , & Util :: execCMD );
if ( dialog . exec () == QDialog :: Accepted )
2021-02-13 23:58:11 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2020-04-22 23:35:24 +08:00
}
2020-05-03 23:40:09 +08:00
void Mifare :: loadSniff ( const QString & file )
{
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL )
util -> execCMD ( "hf list mf -l " + file );
else if ( Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
{
if ( util -> execCMDWithOutput ( "trace load -f " + file , Util :: ReturnTrigger ({ "loaded" })) != "" )
util -> execCMD ( "trace list -t mf" );
}
2021-02-13 23:58:11 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2020-05-03 23:40:09 +08:00
}
void Mifare :: saveSniff ( const QString & file )
{
2021-02-16 13:52:04 +08:00
if ( Util :: getClientType () == Util :: CLIENTTYPE_OFFICIAL )
util -> execCMD ( "hf list mf -s " + file );
else if ( Util :: getClientType () == Util :: CLIENTTYPE_ICEMAN )
util -> execCMD ( "trace save -f " + file );
2021-02-13 23:58:11 +08:00
ui -> funcTab -> setCurrentIndex ( Util :: rawTabIndex );
2020-05-03 23:40:09 +08:00
}
2020-04-23 17:50:20 +08:00
void Mifare :: data_syncWithDataWidget ( bool syncAll , int block )
{
2020-08-07 23:51:24 +08:00
ui -> MF_dataWidget -> blockSignals ( true );
2020-04-28 19:54:05 +08:00
QString tmp ;
2020-04-30 21:00:57 +08:00
if ( syncAll )
2020-04-23 17:50:20 +08:00
{
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . block_size ; i ++ )
2020-04-23 17:50:20 +08:00
{
2020-04-26 21:15:08 +08:00
tmp = "" ;
2020-04-30 21:00:57 +08:00
if ( dataList -> at ( i ) != "" )
2020-04-23 17:50:20 +08:00
{
2020-04-28 19:54:05 +08:00
tmp += dataList -> at ( i ). mid ( 0 , 2 );
2020-04-30 21:00:57 +08:00
for ( int j = 1 ; j < 16 ; j ++ )
2020-04-28 19:54:05 +08:00
{
tmp += " " ;
tmp += dataList -> at ( i ). mid ( j * 2 , 2 );
}
2020-04-23 17:50:20 +08:00
}
ui -> MF_dataWidget -> item ( i , 2 ) -> setText ( tmp );
}
}
else
{
2020-04-28 19:54:05 +08:00
tmp = "" ;
2020-04-30 21:00:57 +08:00
if ( dataList -> at ( block ) != "" )
2020-04-23 17:50:20 +08:00
{
2020-04-28 19:54:05 +08:00
tmp += dataList -> at ( block ). mid ( 0 , 2 );
2020-04-30 21:00:57 +08:00
for ( int j = 1 ; j < 16 ; j ++ )
2020-04-28 19:54:05 +08:00
{
tmp += " " ;
tmp += dataList -> at ( block ). mid ( j * 2 , 2 );
}
2020-04-23 17:50:20 +08:00
}
ui -> MF_dataWidget -> item ( block , 2 ) -> setText ( tmp );
}
2020-08-07 23:51:24 +08:00
ui -> MF_dataWidget -> blockSignals ( false );
2020-04-23 17:50:20 +08:00
}
2020-07-29 22:02:49 +08:00
void Mifare :: data_syncWithKeyWidget ( bool syncAll , int sector , KeyType keyType )
2020-04-23 17:50:20 +08:00
{
2020-08-07 23:51:24 +08:00
ui -> MF_keyWidget -> blockSignals ( true );
2020-04-30 21:00:57 +08:00
if ( syncAll )
2020-04-23 17:50:20 +08:00
{
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
2020-04-23 17:50:20 +08:00
{
ui -> MF_keyWidget -> item ( i , 1 ) -> setText ( keyAList -> at ( i ));
ui -> MF_keyWidget -> item ( i , 2 ) -> setText ( keyBList -> at ( i ));
}
}
else
{
2020-07-29 22:02:49 +08:00
if ( keyType == KEY_A )
2020-04-23 17:50:20 +08:00
ui -> MF_keyWidget -> item ( sector , 1 ) -> setText ( keyAList -> at ( sector ));
else
ui -> MF_keyWidget -> item ( sector , 2 ) -> setText ( keyBList -> at ( sector ));
}
2020-08-07 23:51:24 +08:00
ui -> MF_keyWidget -> blockSignals ( false );
2020-04-23 17:50:20 +08:00
}
2020-08-08 11:23:17 +08:00
void Mifare :: data_clearData ( bool clearAll )
2020-04-23 17:50:20 +08:00
{
2020-08-08 11:23:17 +08:00
if ( clearAll )
{
dataList -> clear ();
}
int delta = cardType . block_size - dataList -> length () ;
if ( delta >= 0 )
{
for ( int i = 0 ; i < delta ; i ++ )
dataList -> append ( "" );
}
else if ( delta < 0 )
{
for ( int i = 0 ; i < - delta ; i ++ )
dataList -> removeLast ();
}
2020-04-23 17:50:20 +08:00
}
2020-08-08 11:23:17 +08:00
void Mifare :: data_clearKey ( bool clearAll )
2020-04-23 17:50:20 +08:00
{
2020-08-08 11:23:17 +08:00
if ( clearAll )
2020-04-23 17:50:20 +08:00
{
2020-08-08 11:23:17 +08:00
keyAList -> clear ();
keyBList -> clear ();
}
int delta = cardType . sector_size - keyAList -> length () ;
if ( delta >= 0 )
{
for ( int i = 0 ; i < delta ; i ++ )
{
keyAList -> append ( "" );
keyBList -> append ( "" );
}
}
else if ( delta < 0 )
{
for ( int i = 0 ; i < - delta ; i ++ )
{
keyAList -> removeLast ();
keyBList -> removeLast ();
}
2020-04-23 17:50:20 +08:00
}
}
2020-08-13 09:30:47 +08:00
bool Mifare :: data_isKeyValid ( const QString & key )
2020-04-23 17:50:20 +08:00
{
2020-04-30 21:00:57 +08:00
if ( key . length () != 12 )
2020-04-23 17:50:20 +08:00
return false ;
2020-04-30 21:00:57 +08:00
for ( int i = 0 ; i < 12 ; i ++ )
2020-04-23 17:50:20 +08:00
{
2020-04-30 21:00:57 +08:00
if ( ! (( key [ i ] >= '0' && key [ i ] <= '9' ) || ( key [ i ] >= 'A' && key [ i ] <= 'F' )))
2020-04-23 17:50:20 +08:00
return false ;
}
return true ;
}
2020-08-06 14:53:49 +08:00
Mifare :: DataType Mifare :: data_isDataValid ( const QString & data ) // "?" will not been processd there
2020-04-23 17:50:20 +08:00
{
2020-04-30 21:00:57 +08:00
if ( data . length () == 47 )
2020-04-23 17:50:20 +08:00
{
2020-04-30 21:00:57 +08:00
for ( int i = 0 ; i < 47 ; i ++ )
2020-04-23 17:50:20 +08:00
{
2020-04-30 21:00:57 +08:00
if ( i % 3 != 0 )
2020-04-23 17:50:20 +08:00
{
2020-04-30 21:00:57 +08:00
if ( ! (( data [ i ] >= '0' && data [ i ] <= '9' ) || ( data [ i ] >= 'A' && data [ i ] <= 'F' ) || data [ i ] == '?' ))
2020-04-23 17:50:20 +08:00
return DATA_INVALID ;
}
else
{
2020-04-30 21:00:57 +08:00
if ( data [ i ] != ' ' )
2020-04-23 17:50:20 +08:00
return DATA_INVALID ;
}
}
2020-04-27 23:57:21 +08:00
return DATA_WITHSPACE ;
2020-04-23 17:50:20 +08:00
}
2020-04-30 21:00:57 +08:00
else if ( data . length () == 32 )
2020-04-23 17:50:20 +08:00
{
2020-04-30 21:00:57 +08:00
for ( int i = 0 ; i < 32 ; i ++ )
2020-04-23 17:50:20 +08:00
{
2020-04-30 21:00:57 +08:00
if ( ! (( data [ i ] >= '0' && data [ i ] <= '9' ) || ( data [ i ] >= 'A' && data [ i ] <= 'F' ) || data [ i ] == '?' ))
2020-04-23 17:50:20 +08:00
return DATA_INVALID ;
}
return DATA_NOSPACE ;
}
else
return DATA_INVALID ;
}
2020-04-24 22:11:35 +08:00
Mifare :: CardType Mifare :: getCardType ()
{
return cardType ;
}
void Mifare :: setCardType ( int type )
{
2020-04-30 21:00:57 +08:00
if ( type == 0 || type == 1 || type == 2 || type == 4 )
2020-04-24 22:11:35 +08:00
{
2020-04-30 21:00:57 +08:00
if ( type == 0 )
2020-04-24 22:11:35 +08:00
cardType = card_mini ;
2020-04-30 21:00:57 +08:00
else if ( type == 1 )
2020-04-24 22:11:35 +08:00
cardType = card_1k ;
2020-04-30 21:00:57 +08:00
else if ( type == 2 )
2020-04-24 22:11:35 +08:00
cardType = card_2k ;
2020-04-30 21:00:57 +08:00
else if ( type == 4 )
2020-04-24 22:11:35 +08:00
cardType = card_4k ;
2020-08-08 11:23:17 +08:00
data_clearKey ( false );
data_clearData ( false );
2020-04-24 22:11:35 +08:00
}
}
2020-04-26 21:15:08 +08:00
2020-08-13 09:30:47 +08:00
bool Mifare :: data_loadDataFile ( const QString & filename )
2020-04-26 21:15:08 +08:00
{
QFile file ( filename , this );
2020-04-30 21:00:57 +08:00
if ( file . open ( QIODevice :: ReadOnly ))
2020-04-26 21:15:08 +08:00
{
QByteArray buff ;
2020-04-29 17:12:35 +08:00
buff = file . read ( 10000 );
2020-04-26 21:15:08 +08:00
bool isBin = false ;
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . block_size * 16 ; i ++ ) // Detect the file type
2020-04-26 21:15:08 +08:00
{
2020-04-30 20:32:43 +08:00
// qDebug() << (unsigned char)buff[i];
2020-04-30 21:00:57 +08:00
if ( ! (( buff [ i ] >= 'A' && buff [ i ] <= 'F' ) || ( buff [ i ] >= 'a' && buff [ i ] <= 'f' ) || ( buff [ i ] >= '0' && buff [ i ] <= '9' ) || buff [ i ] == '\n' || buff [ i ] == '\r' ))
2020-04-26 21:15:08 +08:00
{
isBin = true ;
break ;
}
}
2020-04-30 21:00:57 +08:00
if ( isBin )
2020-04-26 21:15:08 +08:00
{
2020-08-04 16:05:21 +08:00
if ( file . size () < cardType . block_size * 16 )
2020-04-29 17:12:35 +08:00
return false ;
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . block_size ; i ++ )
2020-04-26 21:15:08 +08:00
{
2020-04-29 17:12:35 +08:00
QString tmp = bin2text ( buff , i , 16 );
2020-04-26 21:15:08 +08:00
dataList -> replace ( i , tmp . toUpper ());
}
}
else
{
2020-08-04 16:05:21 +08:00
QString tmp = buff . left ( cardType . block_size * 34 );
2020-04-26 21:15:08 +08:00
QStringList tmpList = tmp . split ( " \r\n " );
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . block_size ; i ++ )
2020-04-26 21:15:08 +08:00
{
dataList -> replace ( i , tmpList [ i ]. toUpper ());
qDebug () << tmpList [ i ];
}
}
file . close ();
data_syncWithDataWidget ();
return true ;
}
else
{
return false ;
}
}
2020-08-13 09:30:47 +08:00
bool Mifare :: data_loadKeyFile ( const QString & filename )
2020-04-26 21:15:08 +08:00
{
QFile file ( filename , this );
2020-04-30 21:00:57 +08:00
if ( file . open ( QIODevice :: ReadOnly ))
2020-04-26 21:15:08 +08:00
{
QByteArray buff ;
2020-04-29 17:12:35 +08:00
buff = file . read ( 10000 );
2020-08-04 16:05:21 +08:00
bool isKey = file . size () <= cardType . sector_size * 14 ;
2020-04-30 21:00:57 +08:00
if ( isKey )
2020-04-26 21:15:08 +08:00
{
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
2020-04-26 21:15:08 +08:00
{
2020-04-29 17:12:35 +08:00
QString tmp = bin2text ( buff , i , 12 );
keyAList -> replace ( i , tmp . left ( 12 ). toUpper ());
keyBList -> replace ( i , tmp . right ( 12 ). toUpper ());
}
}
else
{
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
2020-04-29 17:12:35 +08:00
{
int blk = cardType . blks [ i ] + cardType . blk [ i ] - 1 ;
QString tmp = bin2text ( buff , blk , 16 );
2020-04-26 21:15:08 +08:00
keyAList -> replace ( i , tmp . left ( 12 ). toUpper ());
keyBList -> replace ( i , tmp . right ( 12 ). toUpper ());
}
}
file . close ();
data_syncWithKeyWidget ();
return true ;
}
else
{
return false ;
}
}
2020-04-26 21:50:55 +08:00
2020-08-13 09:30:47 +08:00
QString Mifare :: bin2text ( const QByteArray & buff , int i , int length )
2020-04-29 17:12:35 +08:00
{
QString ret = "" ;
char LByte , RByte ;
2020-04-30 20:32:43 +08:00
char map [ 16 ] = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,
'8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F'
};
2020-04-30 21:00:57 +08:00
for ( int j = 0 ; j < length ; j ++ )
2020-04-29 17:12:35 +08:00
{
LByte = map [( unsigned char ) buff [ i * length + j ] >> 4 ];
RByte = map [( unsigned char ) buff [ i * length + j ] & 0xF ];
ret += LByte ;
ret += RByte ;
}
qDebug () << ret ;
return ret ;
}
2020-08-13 09:30:47 +08:00
bool Mifare :: data_saveDataFile ( const QString & filename , bool isBin )
2020-04-27 23:57:21 +08:00
{
QFile file ( filename , this );
2020-04-30 21:00:57 +08:00
if ( file . open ( QIODevice :: WriteOnly ))
2020-04-27 23:57:21 +08:00
{
QByteArray buff ;
QChar tmp ;
2020-04-30 21:00:57 +08:00
if ( isBin )
2020-04-27 23:57:21 +08:00
{
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . block_size ; i ++ )
2020-04-27 23:57:21 +08:00
{
2020-04-30 21:00:57 +08:00
for ( int j = 0 ; j < 16 ; j ++ )
2020-04-27 23:57:21 +08:00
{
2020-06-26 23:48:08 +08:00
unsigned char Byt [ 2 ] = { 0x0 , 0x0 };
2020-04-30 21:00:57 +08:00
for ( int k = 0 ; k < 2 ; k ++ )
2020-04-27 23:57:21 +08:00
{
2020-04-28 19:54:05 +08:00
tmp = dataList -> at ( i ). at ( j * 2 + k ). toUpper ();
2020-04-30 21:00:57 +08:00
if ( tmp >= '0' && tmp <= '9' )
2020-04-27 23:57:21 +08:00
Byt [ k ] = tmp . toLatin1 () - '0' ;
2020-04-30 21:00:57 +08:00
else if ( tmp >= 'A' && tmp <= 'F' )
2020-04-27 23:57:21 +08:00
Byt [ k ] = tmp . toLatin1 () - 'A' + 10 ;
}
2020-04-28 19:54:05 +08:00
buff += ( Byt [ 0 ] << 4 ) | Byt [ 1 ];
2020-04-27 23:57:21 +08:00
}
}
}
else
{
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . block_size ; i ++ )
2020-04-27 23:57:21 +08:00
{
buff += dataList -> at ( i );
buff += " \r\n " ;
}
}
bool ret = file . write ( buff ) != - 1 ;
file . close ();
return ret ;
}
else
{
return false ;
}
}
2020-08-13 09:30:47 +08:00
bool Mifare :: data_saveKeyFile ( const QString & filename , bool isBin )
2020-04-27 23:57:21 +08:00
{
QFile file ( filename , this );
2020-04-30 21:00:57 +08:00
if ( file . open ( QIODevice :: WriteOnly ))
2020-04-27 23:57:21 +08:00
{
QByteArray buff ;
QChar tmp ;
2020-04-30 21:00:57 +08:00
if ( isBin )
2020-04-27 23:57:21 +08:00
{
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
2020-04-27 23:57:21 +08:00
{
2020-04-30 21:00:57 +08:00
for ( int j = 0 ; j < 6 ; j ++ )
2020-04-27 23:57:21 +08:00
{
2020-06-26 23:48:08 +08:00
unsigned char Byt [ 2 ] = { 0x0 , 0x0 };
2020-04-30 21:00:57 +08:00
for ( int k = 0 ; k < 2 ; k ++ )
2020-04-27 23:57:21 +08:00
{
2020-04-28 19:54:05 +08:00
tmp = keyAList -> at ( i ). at ( j * 2 + k ). toUpper ();
2020-04-30 21:00:57 +08:00
if ( tmp >= '0' && tmp <= '9' )
2020-04-27 23:57:21 +08:00
Byt [ k ] = tmp . toLatin1 () - '0' ;
2020-04-30 21:00:57 +08:00
else if ( tmp >= 'A' && tmp <= 'F' )
2020-04-27 23:57:21 +08:00
Byt [ k ] = tmp . toLatin1 () - 'A' + 10 ;
}
2020-04-28 19:54:05 +08:00
buff += ( Byt [ 0 ] << 4 ) | Byt [ 1 ];
2020-04-27 23:57:21 +08:00
}
2020-04-30 21:00:57 +08:00
for ( int j = 0 ; j < 6 ; j ++ )
2020-04-27 23:57:21 +08:00
{
2020-06-26 23:48:08 +08:00
unsigned char Byt [ 2 ] = { 0x0 , 0x0 };
2020-04-30 21:00:57 +08:00
for ( int k = 0 ; k < 2 ; k ++ )
2020-04-27 23:57:21 +08:00
{
2020-04-28 19:54:05 +08:00
tmp = keyBList -> at ( i ). at ( j * 2 + k ). toUpper ();
2020-04-30 21:00:57 +08:00
if ( tmp >= '0' && tmp <= '9' )
2020-04-27 23:57:21 +08:00
Byt [ k ] = tmp . toLatin1 () - '0' ;
2020-04-30 21:00:57 +08:00
else if ( tmp >= 'A' && tmp <= 'F' )
2020-04-27 23:57:21 +08:00
Byt [ k ] = tmp . toLatin1 () - 'A' + 10 ;
}
2020-04-28 19:54:05 +08:00
buff += ( Byt [ 0 ] << 4 ) | Byt [ 1 ];
2020-04-27 23:57:21 +08:00
}
}
}
else
{
}
bool ret = file . write ( buff ) != - 1 ;
file . close ();
return ret ;
}
else
{
return false ;
}
}
2020-04-26 21:50:55 +08:00
void Mifare :: data_key2Data ()
{
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
2020-04-26 21:50:55 +08:00
{
QString tmp = "" ;
2020-04-30 21:00:57 +08:00
if ( data_isKeyValid ( keyAList -> at ( i )))
2020-04-26 21:50:55 +08:00
tmp += keyAList -> at ( i );
else
tmp += "????????????" ;
2020-04-30 21:00:57 +08:00
if ( dataList -> at ( cardType . blks [ i ] + cardType . blk [ i ] - 1 ) == "" )
2020-04-26 21:50:55 +08:00
tmp += "FF078069" ; // default control bytes
else
tmp += dataList -> at ( cardType . blks [ i ] + cardType . blk [ i ] - 1 ). mid ( 12 , 8 );
2020-04-30 21:00:57 +08:00
if ( data_isKeyValid ( keyBList -> at ( i )))
2020-04-26 21:50:55 +08:00
tmp += keyBList -> at ( i );
else
tmp += "????????????" ;
dataList -> replace ( cardType . blks [ i ] + cardType . blk [ i ] - 1 , tmp );
data_syncWithDataWidget ();
}
}
void Mifare :: data_data2Key ()
{
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
2020-04-26 21:50:55 +08:00
{
2020-04-30 21:00:57 +08:00
if ( dataList -> at ( cardType . blks [ i ] + cardType . blk [ i ] - 1 ) == "" )
2020-04-26 21:50:55 +08:00
{
keyAList -> replace ( i , "????????????" );
keyBList -> replace ( i , "????????????" );
}
else
{
2020-04-30 21:00:57 +08:00
keyAList -> replace ( i , dataList -> at ( cardType . blks [ i ] + cardType . blk [ i ] - 1 ). left ( 12 ));
keyBList -> replace ( i , dataList -> at ( cardType . blks [ i ] + cardType . blk [ i ] - 1 ). right ( 12 ));
2020-04-26 21:50:55 +08:00
}
data_syncWithKeyWidget ();
}
}
2020-04-28 19:54:05 +08:00
2020-08-13 09:30:47 +08:00
void Mifare :: data_setData ( int block , const QString & data )
2020-04-28 19:54:05 +08:00
{
dataList -> replace ( block , data );
}
2020-08-13 09:30:47 +08:00
void Mifare :: data_setKey ( int sector , KeyType keyType , const QString & key )
2020-04-28 19:54:05 +08:00
{
2020-07-29 22:02:49 +08:00
if ( keyType == KEY_A )
2020-04-28 19:54:05 +08:00
keyAList -> replace ( sector , key );
else
keyBList -> replace ( sector , key );
}
2020-08-01 22:04:30 +08:00
void Mifare :: data_fillKeys ()
{
2020-08-04 16:05:21 +08:00
for ( int i = 0 ; i < cardType . sector_size ; i ++ )
2020-08-01 22:04:30 +08:00
{
if ( ! data_isKeyValid ( keyAList -> at ( i )))
{
keyAList -> replace ( i , "FFFFFFFFFFFF" );
}
if ( ! data_isKeyValid ( keyBList -> at ( i )))
{
keyBList -> replace ( i , "FFFFFFFFFFFF" );
}
}
data_syncWithKeyWidget ();
}
2020-08-06 14:53:49 +08:00
2020-08-08 00:19:37 +08:00
int Mifare :: data_b2s ( int block )
{
if ( block >= 0 && block < 128 )
return block / 4 ;
else if ( block < 256 )
return ( block - 128 ) / 16 + 32 ;
else
return - 1 ;
}
2020-08-11 11:30:33 +08:00
bool Mifare :: data_isACBitsValid ( const QString & text , QList < quint8 >* returnHalfBytes )
2020-08-06 14:53:49 +08:00
{
QString input = text ;
input . remove ( " " );
if ( input . length () < 6 )
{
2020-08-11 11:30:33 +08:00
return false ;
2020-08-06 14:53:49 +08:00
}
input = input . left ( 6 );
quint32 val = input . toUInt ( nullptr , 16 );
2020-08-11 11:30:33 +08:00
QList < quint8 > halfBytes ;
2020-08-06 14:53:49 +08:00
for ( int i = 0 ; i < 6 ; i ++ )
{
2020-08-11 11:30:33 +08:00
halfBytes . append (( val >> (( 5 - i ) * 4 )) & 0xf );
2020-08-06 14:53:49 +08:00
}
qDebug () << val ;
if (( ~ halfBytes [ 0 ] & 0xf ) == halfBytes [ 5 ] && ( ~ halfBytes [ 1 ] & 0xf ) == halfBytes [ 2 ] && ( ~ halfBytes [ 3 ] & 0xf ) == halfBytes [ 4 ])
2020-08-11 11:30:33 +08:00
{
if ( returnHalfBytes != nullptr )
* returnHalfBytes = halfBytes ;
return true ;
}
else
return false ;
}
QList < quint8 > Mifare :: data_getACBits ( const QString & text ) //return empty QList if the text is invalid
{
QList < quint8 > halfBytes , result ;
if ( data_isACBitsValid ( text , & halfBytes ))
2020-08-06 14:53:49 +08:00
{
for ( int i = 0 ; i < 4 ; i ++ )
{
result . append (((( halfBytes [ 4 ] >> i ) & 1 ) << 2 ) | ((( halfBytes [ 5 ] >> i ) & 1 ) << 1 ) | ((( halfBytes [ 2 ] >> i ) & 1 ) << 0 ));
}
}
return result ;
}
2021-02-21 23:00:07 +08:00
QString Mifare :: data_getUID ()
{
if ( data_isDataValid ( dataList -> at ( 0 )))
return dataList -> at ( 0 ). left ( 8 );
else
return "" ;
}