X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/d19929cbe8d681b60496ca6d9d9cbd806822e163..db132ea0e8bef786f8f1741fed1cbc082e084c8a:/armsrc/hitag2.c

diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c
index 75513232..1a0e9b56 100644
--- a/armsrc/hitag2.c
+++ b/armsrc/hitag2.c
@@ -25,7 +25,33 @@
 static bool bQuiet;
 
 bool bCrypto;
+bool bAuthenticating;
 bool bPwd;
+bool bSuccessful;
+
+int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int bReader)
+{
+  // Return when trace is full
+  if (traceLen >= TRACE_SIZE) return FALSE;
+  
+  // Trace the random, i'm curious
+  rsamples += iSamples;
+  trace[traceLen++] = ((rsamples >> 0) & 0xff);
+  trace[traceLen++] = ((rsamples >> 8) & 0xff);
+  trace[traceLen++] = ((rsamples >> 16) & 0xff);
+  trace[traceLen++] = ((rsamples >> 24) & 0xff);
+  if (!bReader) {
+    trace[traceLen - 1] |= 0x80;
+  }
+  trace[traceLen++] = ((dwParity >> 0) & 0xff);
+  trace[traceLen++] = ((dwParity >> 8) & 0xff);
+  trace[traceLen++] = ((dwParity >> 16) & 0xff);
+  trace[traceLen++] = ((dwParity >> 24) & 0xff);
+  trace[traceLen++] = iBits;
+  memcpy(trace + traceLen, btBytes, nbytes(iBits));
+  traceLen += nbytes(iBits);
+  return TRUE;
+}
 
 struct hitag2_tag {
 	uint32_t uid;
@@ -41,8 +67,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 +98,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.
@@ -150,10 +177,6 @@ static u32 _hitag2_byte (u64 * x)
 	return c;
 }
 
-size_t nbytes(size_t nbits) {
-	return (nbits/8)+((nbits%8)>0);
-}
-
 int hitag2_reset(void)
 {
 	tag.state = TAG_STATE_RESET;
@@ -163,23 +186,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) |
@@ -396,8 +419,8 @@ void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* tx, si
 		break;
 	}
 
-//	LogTrace(rx,nbytes(rxlen),0,0,false);
-//	LogTrace(tx,nbytes(*txlen),0,0,true);
+//	LogTraceHitag(rx,rxlen,0,0,false);
+//	LogTraceHitag(tx,*txlen,0,0,true);
 	
 	if(tag.crypto_active) {
 		hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen/8, *txlen%8);
@@ -450,6 +473,8 @@ static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len)
 	LOW(GPIO_SSC_DOUT);
 }
 
+size_t blocknr;
+
 bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) {
 	// Reset the transmission frame length
 	*txlen = 0;
@@ -473,22 +498,131 @@ bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen)
 				*txlen = 32;
 				memcpy(tx,password,4);
 				bPwd = true;
+        memcpy(tag.sectors[blocknr],rx,4);
+        blocknr++;
 			} else {
-				DbpString("Password succesful!");
-				// We are done... for now
-				return false;
+				
+			if(blocknr == 1){
+				//store password in block1, the TAG answers with Block3, but we need the password in memory
+				memcpy(tag.sectors[blocknr],tx,4);
+			}else{
+				memcpy(tag.sectors[blocknr],rx,4);
+			}
+			
+			blocknr++;
+			if (blocknr > 7) {
+			  DbpString("Read succesful!");
+        bSuccessful = true;
+			  return false;
+			}
+			*txlen = 10;
+			tx[0] = 0xc0 | (blocknr << 3) | ((blocknr^7) >> 2);
+			tx[1] = ((blocknr^7) << 6);
 			}
 		} break;
 			
 		// Unexpected response
-        default: {
+    default: {
+			Dbprintf("Uknown frame length: %d",rxlen);
+			return false;
+		} break;
+	}
+	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) {
+        // Failed during authentication
+        if (bAuthenticating) {
+          DbpString("Authentication failed!");
+          return false;
+        } else {
+          // Failed reading a block, could be (read/write) locked, skip block and re-authenticate
+          if (blocknr == 1) {
+            // Write the low part of the key in memory
+            memcpy(tag.sectors[1],key+2,4);
+          } else if (blocknr == 2) {
+            // Write the high part of the key in memory
+            tag.sectors[2][0] = 0x00;
+            tag.sectors[2][1] = 0x00;
+            tag.sectors[2][2] = key[0];
+            tag.sectors[2][3] = key[1];
+          } else {
+            // Just put zero's in the memory (of the unreadable block)
+            memset(tag.sectors[blocknr],0x00,4);
+          }
+          blocknr++;
+          bCrypto = false;
+        }
+			} else {
+        *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!");
+          bSuccessful = true;
+          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;
@@ -539,12 +673,19 @@ bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx, size_
 		case 0: {
 			// Stop if there is no answer while we are in crypto mode (after sending NrAr)
 			if (bCrypto) {
-				Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed!",NrAr[0],NrAr[1],NrAr[2],NrAr[3],NrAr[4],NrAr[5],NrAr[6],NrAr[7]);
+				Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed, removed entry!",NrAr[0],NrAr[1],NrAr[2],NrAr[3],NrAr[4],NrAr[5],NrAr[6],NrAr[7]);
+
+        // Removing failed entry from authentiations table
+        memcpy(auth_table+auth_table_pos,auth_table+auth_table_pos+8,8);
+        auth_table_len -= 8;
+
+        // Return if we reached the end of the authentiactions table
 				bCrypto = false;
-				if ((auth_table_pos+8) == auth_table_len) {
+				if (auth_table_pos == auth_table_len) {
 					return false;
 				}
-				auth_table_pos += 8;
+        
+        // Copy the next authentication attempt in row (at the same position, b/c we removed last failed entry)
 				memcpy(NrAr,auth_table+auth_table_pos,8);
 			}
 			*txlen = 5;
@@ -590,8 +731,8 @@ void SnoopHitag(uint32_t type) {
 	size_t rxlen=0;
 	
 	// 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;
@@ -739,7 +880,7 @@ void SnoopHitag(uint32_t type) {
 		// Check if frame was captured
 		if(rxlen > 0) {
 			frame_count++;
-			if (!LogTrace(rx,nbytes(rxlen),response,0,reader_frame)) {
+			if (!LogTraceHitag(rx,rxlen,response,0,reader_frame)) {
 				DbpString("Trace full");
 				break;
 			}
@@ -799,8 +940,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);
@@ -902,7 +1043,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) {
 		if(rxlen > 4) {
 			frame_count++;
 			if (!bQuiet) {
-				if (!LogTrace(rx,nbytes(rxlen),response,0,true)) {
+				if (!LogTraceHitag(rx,rxlen,response,0,true)) {
 					DbpString("Trace full");
 					if (bQuitTraceFull) {
 						break;
@@ -931,7 +1072,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) {
 				hitag_send_frame(tx,txlen);
 				// Store the frame in the trace
 				if (!bQuiet) {
-					if (!LogTrace(tx,nbytes(txlen),0,0,false)) {
+					if (!LogTraceHitag(tx,txlen,0,0,false)) {
 						DbpString("Trace full");
 						if (bQuitTraceFull) {
 							break;
@@ -982,28 +1123,44 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
 	int t_wait = HITAG_T_WAIT_MAX;
 	bool bStop;
 	bool bQuitTraceFull = false;
-	
+  
+  // Reset the return status
+  bSuccessful = 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;
 
@@ -1067,26 +1224,26 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
 	lastbit = 1;
 	bStop = false;
 
-	// Tag specific configuration settings (sof, timings, etc.)
-	if (htf < 10){
-		// hitagS settings
-		reset_sof = 1;
-		t_wait = 200;
-		DbpString("Configured for hitagS reader");
-	} else if (htf < 20) {
-		// hitag1 settings
-		reset_sof = 1;
-		t_wait = 200;
-		DbpString("Configured for hitag1 reader");
-	} else if (htf < 30) {
-		// hitag2 settings
-		reset_sof = 4;
-		t_wait = HITAG_T_WAIT_2;
-		DbpString("Configured for hitag2 reader");
+  // Tag specific configuration settings (sof, timings, etc.)
+  if (htf < 10){
+    // hitagS settings
+    reset_sof = 1;
+    t_wait = 200;
+    DbpString("Configured for hitagS reader");
+  } else if (htf < 20) {
+    // hitag1 settings
+    reset_sof = 1;
+    t_wait = 200;
+    DbpString("Configured for hitag1 reader");
+  } else if (htf < 30) {
+    // hitag2 settings
+    reset_sof = 4;
+    t_wait = HITAG_T_WAIT_2;
+    DbpString("Configured for hitag2 reader");
 	} else {
-        Dbprintf("Error, unknown hitag reader type: %d",htf);
-        return;
-    }
+    Dbprintf("Error, unknown hitag reader type: %d",htf);
+    return;
+  }
 		
 	while(!bStop && !BUTTON_PRESS()) {
 		// Watchdog hit
@@ -1096,7 +1253,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
 		if(rxlen > 0) {
 			frame_count++;
 			if (!bQuiet) {
-				if (!LogTrace(rx,nbytes(rxlen),response,0,false)) {
+				if (!LogTraceHitag(rx,rxlen,response,0,false)) {
 					DbpString("Trace full");
 					if (bQuitTraceFull) {
 						break;
@@ -1116,6 +1273,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;
@@ -1147,7 +1307,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
 			frame_count++;
 			if (!bQuiet) {
 				// Store the frame in the trace
-				if (!LogTrace(tx,nbytes(txlen),HITAG_T_WAIT_2,0,true)) {
+				if (!LogTraceHitag(tx,txlen,HITAG_T_WAIT_2,0,true)) {
 					if (bQuitTraceFull) {
 						break;
 					} else {
@@ -1228,7 +1388,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
 	AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
 	AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
 	FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
-	
-//	Dbprintf("frame received: %d",frame_count);
-//	DbpString("All done");
+	Dbprintf("frame received: %d",frame_count);
+  DbpString("All done");
+  cmd_send(CMD_ACK,bSuccessful,0,0,(byte_t*)tag.sectors,48);
 }