From bde10a5057cb280e5f08365502ec4a3f79301863 Mon Sep 17 00:00:00 2001 From: "roel@libnfc.org" Date: Tue, 16 Oct 2012 15:18:13 +0000 Subject: [PATCH] added hitag2 reading in crypto mode functionality --- armsrc/hitag2.c | 133 ++++++++++++++++++++++++++++++++++++-------- client/cmdlfhitag.c | 7 ++- include/hitag2.h | 12 +++- 3 files changed, 126 insertions(+), 26 deletions(-) diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 90a95b5a..59f29eae 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -25,6 +25,7 @@ static bool bQuiet; bool bCrypto; +bool bAuthenticating; bool bPwd; struct hitag2_tag { @@ -41,8 +42,7 @@ struct hitag2_tag { byte_t sectors[12][4]; }; -static struct hitag2_tag tag; -static const struct hitag2_tag resetdata = { +static struct hitag2_tag tag = { .state = TAG_STATE_RESET, .sectors = { // Password mode: | Crypto mode: [0] = { 0x02, 0x4e, 0x02, 0x20}, // UID | UID @@ -73,6 +73,8 @@ size_t auth_table_len = AUTH_TABLE_LENGTH; byte_t password[4]; byte_t NrAr[8]; +byte_t key[8]; +uint64_t cipher_state; /* Following is a modified version of cryptolib.com/ciphers/hitag2/ */ // Software optimized 48-bit Philips/NXP Mifare Hitag2 PCF7936/46/47/52 stream cipher algorithm by I.C. Wiener 2006-2007. @@ -163,23 +165,23 @@ int hitag2_reset(void) int hitag2_init(void) { - memcpy(&tag, &resetdata, sizeof(tag)); +// memcpy(&tag, &resetdata, sizeof(tag)); hitag2_reset(); return 0; } static void hitag2_cipher_reset(struct hitag2_tag *tag, const byte_t *iv) { - uint64_t key = ((uint64_t)tag->sectors[2][2]) | - ((uint64_t)tag->sectors[2][3] << 8) | - ((uint64_t)tag->sectors[1][0] << 16) | - ((uint64_t)tag->sectors[1][1] << 24) | - ((uint64_t)tag->sectors[1][2] << 32) | - ((uint64_t)tag->sectors[1][3] << 40); - uint32_t uid = ((uint32_t)tag->sectors[0][0]) | - ((uint32_t)tag->sectors[0][1] << 8) | - ((uint32_t)tag->sectors[0][2] << 16) | - ((uint32_t)tag->sectors[0][3] << 24); + uint64_t key = ((uint64_t)tag->sectors[2][2]) | + ((uint64_t)tag->sectors[2][3] << 8) | + ((uint64_t)tag->sectors[1][0] << 16) | + ((uint64_t)tag->sectors[1][1] << 24) | + ((uint64_t)tag->sectors[1][2] << 32) | + ((uint64_t)tag->sectors[1][3] << 40); + uint32_t uid = ((uint32_t)tag->sectors[0][0]) | + ((uint32_t)tag->sectors[0][1] << 8) | + ((uint32_t)tag->sectors[0][2] << 16) | + ((uint32_t)tag->sectors[0][3] << 24); uint32_t iv_ = (((uint32_t)(iv[0]))) | (((uint32_t)(iv[1])) << 8) | (((uint32_t)(iv[2])) << 16) | @@ -489,7 +491,7 @@ bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) } break; // Unexpected response - default: { + default: { Dbprintf("Uknown frame length: %d",rxlen); return false; } break; @@ -497,6 +499,78 @@ bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) return true; } +bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { + // Reset the transmission frame length + *txlen = 0; + + if(bCrypto) { + hitag2_cipher_transcrypt(&cipher_state,rx,rxlen/8,rxlen%8); + } + + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // No answer, try to resurrect + case 0: { + // Stop if there is no answer while we are in crypto mode (after sending NrAr) + if (bCrypto) { + DbpString("Authentication failed!"); + return false; + } + *txlen = 5; + memcpy(tx,"\xc0",nbytes(*txlen)); + } break; + + // Received UID, crypto tag answer + case 32: { + if (!bCrypto) { + uint64_t ui64key = key[0] | ((uint64_t)key[1]) << 8 | ((uint64_t)key[2]) << 16 | ((uint64_t)key[3]) << 24 | ((uint64_t)key[4]) << 32 | ((uint64_t)key[5]) << 40; + uint32_t ui32uid = rx[0] | ((uint32_t)rx[1]) << 8 | ((uint32_t)rx[2]) << 16 | ((uint32_t)rx[3]) << 24; + cipher_state = _hitag2_init(rev64(ui64key), rev32(ui32uid), 0); + memset(tx,0x00,4); + memset(tx+4,0xff,4); + hitag2_cipher_transcrypt(&cipher_state,tx+4,4,0); + *txlen = 64; + bCrypto = true; + bAuthenticating = true; + } else { + // Check if we received answer tag (at) + if (bAuthenticating) { + bAuthenticating = false; + } else { + // Store the received block + memcpy(tag.sectors[blocknr],rx,4); + blocknr++; + } + if (blocknr > 7) { + DbpString("Read succesful!"); + // We are done... for now + return false; + } + *txlen = 10; + tx[0] = 0xc0 | (blocknr << 3) | ((blocknr^7) >> 2); + tx[1] = ((blocknr^7) << 6); + } + } break; + + // Unexpected response + default: { + Dbprintf("Uknown frame length: %d",rxlen); + return false; + } break; + } + + + if(bCrypto) { + // We have to return now to avoid double encryption + if (!bAuthenticating) { + hitag2_cipher_transcrypt(&cipher_state,tx,*txlen/8,*txlen%8); + } + } + + return true; +} + + bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { // Reset the transmission frame length *txlen = 0; @@ -521,7 +595,7 @@ bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txl memcpy(tx,NrAr,8); bCrypto = true; } else { - DbpString("Read succesful!"); + DbpString("Authentication succesful!"); // We are done... for now return false; } @@ -807,8 +881,8 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { bQuiet = false; // Clean up trace and prepare it for storing frames - iso14a_set_tracing(TRUE); - iso14a_clear_trace(); + iso14a_set_tracing(TRUE); + iso14a_clear_trace(); auth_table_len = 0; auth_table_pos = 0; memset(auth_table, 0x00, AUTH_TABLE_LENGTH); @@ -992,27 +1066,39 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { bool bQuitTraceFull = false; // Clean up trace and prepare it for storing frames - iso14a_set_tracing(TRUE); - iso14a_clear_trace(); + iso14a_set_tracing(TRUE); + iso14a_clear_trace(); DbpString("Starting Hitag reader family"); // Check configuration switch(htf) { case RHT2F_PASSWORD: { - Dbprintf("List identifier in password mode"); + Dbprintf("List identifier in password mode"); memcpy(password,htd->pwd.password,4); blocknr = 0; bQuitTraceFull = false; bQuiet = false; bPwd = false; } break; + case RHT2F_AUTHENTICATE: { - DbpString("Authenticating in crypto mode"); + DbpString("Authenticating using nr,ar pair:"); memcpy(NrAr,htd->auth.NrAr,8); - Dbprintf("Reader-challenge:"); Dbhexdump(8,NrAr,false); bQuiet = false; bCrypto = false; + bAuthenticating = false; + bQuitTraceFull = true; + } break; + + case RHT2F_CRYPTO: { + DbpString("Authenticating using key:"); + memcpy(key,htd->crypto.key,6); + Dbhexdump(6,key,false); + blocknr = 0; + bQuiet = false; + bCrypto = false; + bAuthenticating = false; bQuitTraceFull = true; } break; @@ -1125,6 +1211,9 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { case RHT2F_AUTHENTICATE: { bStop = !hitag2_authenticate(rx,rxlen,tx,&txlen); } break; + case RHT2F_CRYPTO: { + bStop = !hitag2_crypto(rx,rxlen,tx,&txlen); + } break; case RHT2F_TEST_AUTH_ATTEMPTS: { bStop = !hitag2_test_auth_attempts(rx,rxlen,tx,&txlen); } break; diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index 61a7d3b3..bdabe5e4 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -143,7 +143,7 @@ int CmdLFHitagSnoop(const char *Cmd) { int CmdLFHitagSim(const char *Cmd) { UsbCommand c = {CMD_SIMULATE_HITAG}; - char filename[256]; + char filename[256] = { 0x00 }; FILE* pf; bool tag_mem_supplied; @@ -184,6 +184,10 @@ int CmdLFHitagReader(const char *Cmd) { num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); } break; + case RHT2F_CRYPTO: { + num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); +// num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); + } break; case RHT2F_TEST_AUTH_ATTEMPTS: { // No additional parameters needed } break; @@ -195,6 +199,7 @@ int CmdLFHitagReader(const char *Cmd) { PrintAndLog(" Hitag2 (2*)",htf); PrintAndLog(" 21 (password mode)",htf); PrintAndLog(" 22 (authentication)",htf); + PrintAndLog(" 23 (authentication)",htf); PrintAndLog(" 25 (test recorded authentications)",htf); return 1; } break; diff --git a/include/hitag2.h b/include/hitag2.h index 3ed2b9fc..713c2cb8 100644 --- a/include/hitag2.h +++ b/include/hitag2.h @@ -12,9 +12,10 @@ #define _HITAG2_H_ typedef enum { - RHT2F_PASSWORD = 21, - RHT2F_AUTHENTICATE = 22, - RHT2F_TEST_AUTH_ATTEMPTS = 25, + RHT2F_PASSWORD = 21, + RHT2F_AUTHENTICATE = 22, + RHT2F_CRYPTO = 23, + RHT2F_TEST_AUTH_ATTEMPTS = 25, } hitag_function; typedef struct { @@ -25,9 +26,14 @@ typedef struct { byte_t NrAr[8]; } PACKED rht2d_authenticate; +typedef struct { + byte_t key[4]; +} PACKED rht2d_crypto; + typedef union { rht2d_password pwd; rht2d_authenticate auth; + rht2d_crypto crypto; } hitag_data; #endif -- 2.39.2