X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/292fe7253596b98901fd8162bab82dd1ba394237..refs/pull/185/head:/client/cmdhfmf.c

diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c
index 2b5a5b87..36c8e6c3 100644
--- a/client/cmdhfmf.c
+++ b/client/cmdhfmf.c
@@ -9,6 +9,7 @@
 //-----------------------------------------------------------------------------
 
 #include "cmdhfmf.h"
+#include "./nonce2key/nonce2key.h"
 
 static int CmdHelp(const char *Cmd);
 
@@ -17,19 +18,18 @@ int CmdHF14AMifare(const char *Cmd)
 	uint32_t uid = 0;
 	uint32_t nt = 0, nr = 0;
 	uint64_t par_list = 0, ks_list = 0, r_key = 0;
-	uint8_t isOK = 0;
-	uint8_t keyBlock[8] = {0};
+	int16_t isOK = 0;
 
 	UsbCommand c = {CMD_READER_MIFARE, {true, 0, 0}};
 
 	// message
 	printf("-------------------------------------------------------------------------\n");
 	printf("Executing command. Expected execution time: 25sec on average  :-)\n");
-	printf("Press the key on the proxmark3 device to abort both proxmark3 and client.\n");
+	printf("Press button on the proxmark3 device to abort both proxmark3 and client.\n");
 	printf("-------------------------------------------------------------------------\n");
 
 	
-start:
+ start:
     clearCommandBuffer();
     SendCommand(&c);
 	
@@ -47,15 +47,22 @@ start:
 		}
 		
 		UsbCommand resp;
-		if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
-			isOK  = resp.arg[0] & 0xff;
+		if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
+			isOK  = resp.arg[0];
 			uid = (uint32_t)bytes_to_num(resp.d.asBytes +  0, 4);
 			nt =  (uint32_t)bytes_to_num(resp.d.asBytes +  4, 4);
 			par_list = bytes_to_num(resp.d.asBytes +  8, 8);
 			ks_list = bytes_to_num(resp.d.asBytes +  16, 8);
 			nr = bytes_to_num(resp.d.asBytes + 24, 4);
 			printf("\n\n");
-			if (!isOK) PrintAndLog("Proxmark can't get statistic info. Execution aborted.\n");
+			switch (isOK) {
+				case -1 : PrintAndLog("Button pressed. Aborted.\n"); break;
+				case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).\n"); break;
+				case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable).\n"); break;
+				case -4 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown");
+							PrintAndLog("generating polynomial with 16 effective bits only, but shows unexpected behaviour.\n"); break;
+				default: ;
+			}
 			break;
 		}
 	}	
@@ -69,22 +76,13 @@ start:
 	if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) {
 		isOK = 2;
 		PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt);	
-	} else {
-		printf("------------------------------------------------------------------\n");
-		PrintAndLog("Key found:%012"llx" \n", r_key);
-
-		num_to_bytes(r_key, 6, keyBlock);
-		isOK = mfCheckKeys(0, 0, 1, keyBlock, &r_key);
-	}
-	
-	if (!isOK) 
-		PrintAndLog("Found valid key:%012"llx, r_key);
-	else
-	{
-		if (isOK != 2) PrintAndLog("Found invalid key. ");	
 		PrintAndLog("Failing is expected to happen in 25%% of all cases. Trying again with a different reader nonce...");
 		c.arg[0] = false;
 		goto start;
+	} else {
+		isOK = 0;
+		printf("------------------------------------------------------------------\n");
+		PrintAndLog("Found valid key:%012"llx" \n", r_key);
 	}
 	
 	PrintAndLog("");
@@ -622,8 +620,14 @@ int CmdHF14AMfNested(const char *Cmd)
 	
 	if (cmdp == 'o') {
 		PrintAndLog("--target block no:%3d, target key type:%c ", trgBlockNo, trgKeyType?'B':'A');
-		if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true)) {
-			PrintAndLog("Nested error.");
+		int16_t isOK = mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true);
+		if (isOK) {
+			switch (isOK) {
+				case -1 : PrintAndLog("Error: No response from Proxmark.\n"); break;
+				case -2 : PrintAndLog("Button pressed. Aborted.\n"); break;
+				case -3 : PrintAndLog("Tag isn't vulnerable to Nested Attack (random numbers are not predictable).\n"); break;
+				default : PrintAndLog("Unknown Error.\n");
+			}
 			return 2;
 		}
 		key64 = bytes_to_num(keyBlock, 6);
@@ -678,7 +682,7 @@ int CmdHF14AMfNested(const char *Cmd)
 			for (j = 0; j < 2; j++) {
 				if (e_sector[i].foundKey[j]) continue;
 				
-				res = mfCheckKeys(FirstBlockOfSector(i), j, 6, keyBlock, &key64);
+				res = mfCheckKeys(FirstBlockOfSector(i), j, true, 6, keyBlock, &key64);
 				
 				if (!res) {
 					e_sector[i].Key[j] = key64;
@@ -696,11 +700,17 @@ int CmdHF14AMfNested(const char *Cmd)
 				for (trgKeyType = 0; trgKeyType < 2; trgKeyType++) { 
 					if (e_sector[sectorNo].foundKey[trgKeyType]) continue;
 					PrintAndLog("-----------------------------------------------");
-					if(mfnested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock, calibrate)) {
-						PrintAndLog("Nested error.\n");
+					int16_t isOK = mfnested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock, calibrate);
+					if(isOK) {
+						switch (isOK) {
+							case -1 : PrintAndLog("Error: No response from Proxmark.\n"); break;
+							case -2 : PrintAndLog("Button pressed. Aborted.\n"); break;
+							case -3 : PrintAndLog("Tag isn't vulnerable to Nested Attack (random numbers are not predictable).\n"); break;
+							default : PrintAndLog("Unknown Error.\n");
+						}
 						free(e_sector);
-						return 2;					}
-					else {
+						return 2;
+					} else {
 						calibrate = false;
 					}
 					
@@ -956,7 +966,7 @@ int CmdHF14AMfChk(const char *Cmd)
 			uint32_t max_keys = keycnt>USB_CMD_DATA_SIZE/6?USB_CMD_DATA_SIZE/6:keycnt;
 			for (uint32_t c = 0; c < keycnt; c+=max_keys) {
 				uint32_t size = keycnt-c>max_keys?max_keys:keycnt-c;
-				res = mfCheckKeys(b, t, size, &keyBlock[6*c], &key64);
+				res = mfCheckKeys(b, t, true, size, &keyBlock[6*c], &key64);
 				if (res != 1) {
 					if (!res) {
 						PrintAndLog("Found valid key:[%012"llx"]",key64);
@@ -1006,72 +1016,273 @@ int CmdHF14AMfChk(const char *Cmd)
 	return 0;
 }
 
-int CmdHF14AMf1kSim(const char *Cmd)
-{
-	uint8_t uid[7] = {0, 0, 0, 0, 0, 0, 0};
+void readerAttack(nonces_t ar_resp[], bool setEmulatorMem) {
+	#define ATTACK_KEY_COUNT 8 // keep same as define in iso14443a.c -> Mifare1ksim()
+	uint64_t key = 0;
+	typedef struct {
+			uint64_t keyA;
+			uint64_t keyB;
+	} st_t;
+	st_t sector_trailer[ATTACK_KEY_COUNT];
+	memset(sector_trailer, 0x00, sizeof(sector_trailer));
+
+	uint8_t	stSector[ATTACK_KEY_COUNT];
+	memset(stSector, 0x00, sizeof(stSector));
+	uint8_t key_cnt[ATTACK_KEY_COUNT];
+	memset(key_cnt, 0x00, sizeof(key_cnt));
+
+	for (uint8_t i = 0; i<ATTACK_KEY_COUNT; i++) {
+		if (ar_resp[i].ar2 > 0) {
+			//PrintAndLog("DEBUG: Trying sector %d, cuid %08x, nt %08x, ar %08x, nr %08x, ar2 %08x, nr2 %08x",ar_resp[i].sector, ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2);
+			if (mfkey32(ar_resp[i], &key)) {
+				PrintAndLog("  Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF));
+
+				for (uint8_t ii = 0; ii<ATTACK_KEY_COUNT; ii++) {
+					if (key_cnt[ii]==0 || stSector[ii]==ar_resp[i].sector) {
+						if (ar_resp[i].keytype==0) {
+							//keyA
+							sector_trailer[ii].keyA = key;
+							stSector[ii] = ar_resp[i].sector;
+							key_cnt[ii]++;
+							break;
+						} else {
+							//keyB
+							sector_trailer[ii].keyB = key;
+							stSector[ii] = ar_resp[i].sector;
+							key_cnt[ii]++;
+							break;
+						}
+					}
+				}
+			}
+		}
+	}
+	//set emulator memory for keys
+	if (setEmulatorMem) {
+		for (uint8_t i = 0; i<ATTACK_KEY_COUNT; i++) {
+			if (key_cnt[i]>0) {
+				uint8_t	memBlock[16];
+				memset(memBlock, 0x00, sizeof(memBlock));
+				char cmd1[36];
+				memset(cmd1,0x00,sizeof(cmd1));
+				snprintf(cmd1,sizeof(cmd1),"%04x%08xFF078069%04x%08x",(uint32_t) (sector_trailer[i].keyA>>32), (uint32_t) (sector_trailer[i].keyA &0xFFFFFFFF),(uint32_t) (sector_trailer[i].keyB>>32), (uint32_t) (sector_trailer[i].keyB &0xFFFFFFFF));
+				PrintAndLog("Setting Emulator Memory Block %02d: [%s]",stSector[i]*4+3, cmd1);
+				if (param_gethex(cmd1, 0, memBlock, 32)) {
+					PrintAndLog("block data must include 32 HEX symbols");
+					return;
+				}
+				
+				UsbCommand c = {CMD_MIFARE_EML_MEMSET, {(stSector[i]*4+3), 1, 0}};
+				memcpy(c.d.asBytes, memBlock, 16);
+				clearCommandBuffer();
+				SendCommand(&c);			
+			}
+		}
+	}
+	/*
+	//un-comment to use as well moebius attack
+	for (uint8_t i = ATTACK_KEY_COUNT; i<ATTACK_KEY_COUNT*2; i++) {
+		if (ar_resp[i].ar2 > 0) {
+			if (tryMfk32_moebius(ar_resp[i], &key)) {
+				PrintAndLog("M-Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF));
+			}
+		}
+	}*/
+}
+
+int usage_hf14_mf1ksim(void) {
+	PrintAndLog("Usage:  hf mf sim h u <uid (8, 14, or 20 hex symbols)> n <numreads> i x");
+	PrintAndLog("options:");
+	PrintAndLog("      h    this help");
+	PrintAndLog("      u    (Optional) UID 4,7 or 10 bytes. If not specified, the UID 4B from emulator memory will be used");
+	PrintAndLog("      n    (Optional) Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite");
+	PrintAndLog("      i    (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted");
+	PrintAndLog("      x    (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)");
+	PrintAndLog("      e    (Optional) set keys found from 'reader attack' to emulator memory (implies x and i)");
+	PrintAndLog("      f    (Optional) get UIDs to use for 'reader attack' from file 'f <filename.txt>' (implies x and i)");
+	PrintAndLog("samples:");
+	PrintAndLog("           hf mf sim u 0a0a0a0a");
+	PrintAndLog("           hf mf sim u 11223344556677");
+	PrintAndLog("           hf mf sim u 112233445566778899AA");
+	PrintAndLog("           hf mf sim f uids.txt");
+	PrintAndLog("           hf mf sim u 0a0a0a0a e");
+		
+	return 0;
+}
+
+int CmdHF14AMf1kSim(const char *Cmd) {
+	UsbCommand resp;
+	uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 	uint8_t exitAfterNReads = 0;
 	uint8_t flags = 0;
-
-	uint8_t cmdp = param_getchar(Cmd, 0);
-	
-	if (cmdp == 'h' || cmdp == 'H') {
-		PrintAndLog("Usage:  hf mf sim  u <uid (8 hex symbols)> n <numreads> i x");
-		PrintAndLog("           h    this help");
-		PrintAndLog("           u    (Optional) UID. If not specified, the UID from emulator memory will be used");
-		PrintAndLog("           n    (Optional) Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite");
-		PrintAndLog("           i    (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted");
-		PrintAndLog("           x    (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)");
-		PrintAndLog("");
-		PrintAndLog("           sample: hf mf sim u 0a0a0a0a ");
-		return 0;
-	}
+	int uidlen = 0;
 	uint8_t pnr = 0;
-	if (param_getchar(Cmd, pnr) == 'u') {
-		if(param_gethex(Cmd, pnr+1, uid, 8) == 0)
-		{
-			flags |= FLAG_4B_UID_IN_DATA; // UID from packet
-		} else if(param_gethex(Cmd,pnr+1,uid,14) == 0) {
-			flags |= FLAG_7B_UID_IN_DATA;// UID from packet
-		} else {
-			PrintAndLog("UID, if specified, must include 8 or 14 HEX symbols");
-			return 1;
+	bool setEmulatorMem = false;
+	bool attackFromFile = false;
+	FILE *f;
+	char filename[FILE_PATH_SIZE];
+	memset(filename, 0x00, sizeof(filename));
+	int len = 0;
+	char buf[64];
+
+	uint8_t cmdp = 0;
+	bool errors = false;
+
+	while(param_getchar(Cmd, cmdp) != 0x00) {
+		switch(param_getchar(Cmd, cmdp)) {
+		case 'e':
+		case 'E':
+			setEmulatorMem = true;
+			//implies x and i
+			flags |= FLAG_INTERACTIVE;
+			flags |= FLAG_NR_AR_ATTACK;
+			cmdp++;
+			break;
+		case 'f':
+		case 'F':
+			len = param_getstr(Cmd, cmdp+1, filename);
+			if (len < 1) {
+				PrintAndLog("error no filename found");
+				return 0;
+			}
+			attackFromFile = true;
+			//implies x and i
+			flags |= FLAG_INTERACTIVE;
+			flags |= FLAG_NR_AR_ATTACK;
+			cmdp += 2;
+			break;
+		case 'h':
+		case 'H':
+			return usage_hf14_mf1ksim();
+		case 'i':
+		case 'I':
+			flags |= FLAG_INTERACTIVE;
+			cmdp++;
+			break;
+		case 'n':
+		case 'N':
+			exitAfterNReads = param_get8(Cmd, pnr+1);
+			cmdp += 2;
+			break;
+		case 'u':
+		case 'U':
+			param_gethex_ex(Cmd, cmdp+1, uid, &uidlen);
+			switch(uidlen) {
+				case 20: flags = FLAG_10B_UID_IN_DATA;	break; //not complete
+				case 14: flags = FLAG_7B_UID_IN_DATA; break;
+				case  8: flags = FLAG_4B_UID_IN_DATA; break;
+				default: return usage_hf14_mf1ksim();
+			}
+			cmdp += 2;
+			break;
+		case 'x':
+		case 'X':
+			flags |= FLAG_NR_AR_ATTACK;
+			cmdp++;
+			break;
+		default:
+			PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
+			errors = true;
+			break;
 		}
-		pnr +=2;
-	}
-	if (param_getchar(Cmd, pnr) == 'n') {
-		exitAfterNReads = param_get8(Cmd,pnr+1);
-		pnr += 2;
-	}
-	if (param_getchar(Cmd, pnr) == 'i' ) {
-		//Using a flag to signal interactiveness, least significant bit
-		flags |= FLAG_INTERACTIVE;
-		pnr++;
+		if(errors) break;
 	}
+	//Validations
+	if(errors) return usage_hf14_mf1ksim();
 
-	if (param_getchar(Cmd, pnr) == 'x' ) {
-		//Using a flag to signal interactiveness, least significant bit
-		flags |= FLAG_NR_AR_ATTACK;
-	}
-	PrintAndLog(" uid:%s, numreads:%d, flags:%d (0x%02x) ",
-				flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4):
-											  flags & FLAG_7B_UID_IN_DATA	? sprint_hex(uid,7): "N/A"
-				, exitAfterNReads, flags,flags);
+	//get uid from file
+	if (attackFromFile) {
+		int count = 0;
+		// open file
+		f = fopen(filename, "r");
+		if (f == NULL) {
+			PrintAndLog("File %s not found or locked", filename);
+			return 1;
+		}
+		PrintAndLog("Loading file and simulating. Press keyboard to abort");
+		while(!feof(f) && !ukbhit()){
+			memset(buf, 0, sizeof(buf));
+			memset(uid, 0, sizeof(uid));
 
+			if (fgets(buf, sizeof(buf), f) == NULL) {			
+				if (count > 0) break;
+				
+				PrintAndLog("File reading error.");
+				fclose(f);
+				return 2;
+			}
+			if(!strlen(buf) && feof(f)) break;
+
+			uidlen = strlen(buf)-1;
+			switch(uidlen) {
+				case 20: flags |= FLAG_10B_UID_IN_DATA;	break; //not complete
+				case 14: flags |= FLAG_7B_UID_IN_DATA; break;
+				case  8: flags |= FLAG_4B_UID_IN_DATA; break;
+				default: 
+					PrintAndLog("uid in file wrong length at %d (length: %d) [%s]",count, uidlen, buf);
+					fclose(f);
+					return 2;
+			}
 
-	UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}};
-	memcpy(c.d.asBytes, uid, sizeof(uid));
-	SendCommand(&c);
+			for (uint8_t i = 0; i < uidlen; i += 2) {
+				sscanf(&buf[i], "%02x", (unsigned int *)&uid[i / 2]);
+			}
+			
+			PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) - press button to abort",
+					flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4):
+						flags & FLAG_7B_UID_IN_DATA	? sprint_hex(uid,7): 
+							flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A"
+					, exitAfterNReads, flags, flags);
+
+			UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}};
+			memcpy(c.d.asBytes, uid, sizeof(uid));
+			clearCommandBuffer();
+			SendCommand(&c);
 
-	if(flags & FLAG_INTERACTIVE)
-	{
-		UsbCommand resp;
-		PrintAndLog("Press pm3-button to abort simulation");
-		while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
-			//We're waiting only 1.5 s at a time, otherwise we get the
-			// annoying message about "Waiting for a response... "
+			while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+				//We're waiting only 1.5 s at a time, otherwise we get the
+				// annoying message about "Waiting for a response... "
+			}
+			//got a response
+			nonces_t ar_resp[ATTACK_KEY_COUNT*2];
+			memcpy(ar_resp, resp.d.asBytes, sizeof(ar_resp));
+			readerAttack(ar_resp, setEmulatorMem);
+			if ((bool)resp.arg[1]) {
+				PrintAndLog("Device button pressed - quitting");
+				fclose(f);
+				return 4;
+			}
+			count++;
+		}
+		fclose(f);
+	} else { //not from file
+
+		PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) ",
+				flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4):
+					flags & FLAG_7B_UID_IN_DATA	? sprint_hex(uid,7): 
+						flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A"
+				, exitAfterNReads, flags, flags);
+
+		UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}};
+		memcpy(c.d.asBytes, uid, sizeof(uid));
+		clearCommandBuffer();
+		SendCommand(&c);
+
+		if(flags & FLAG_INTERACTIVE) {
+			PrintAndLog("Press pm3-button to abort simulation");
+			while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+				//We're waiting only 1.5 s at a time, otherwise we get the
+				// annoying message about "Waiting for a response... "
+			}
+			//got a response
+			if (flags & FLAG_NR_AR_ATTACK) {
+				nonces_t ar_resp[ATTACK_KEY_COUNT*2];
+				memcpy(ar_resp, resp.d.asBytes, sizeof(ar_resp));
+				readerAttack(ar_resp, setEmulatorMem);
+			}
 		}
 	}
-	
+
 	return 0;
 }
 
@@ -1750,10 +1961,13 @@ int CmdHF14AMfCSave(const char *Cmd) {
 			// get filename
 			if (mfCGetBlock(0, buf, CSETBLOCK_SINGLE_OPER)) {
 				PrintAndLog("Cant get block: %d", 0);
-				return 1;
+				len = sprintf(fnameptr, "dump");
+				fnameptr += len;
+			}
+			else {
+				for (j = 0; j < 7; j++, fnameptr += 2)
+					sprintf(fnameptr, "%02x", buf[j]); 
 			}
-			for (j = 0; j < 7; j++, fnameptr += 2)
-				sprintf(fnameptr, "%02x", buf[j]); 
 		} else {
 			memcpy(filename, Cmd, len);
 			fnameptr += len;
@@ -1939,6 +2153,13 @@ int CmdHF14AMfSniff(const char *Cmd){
 	return 0;
 }
 
+//needs nt, ar, at, Data to decrypt
+int CmdDecryptTraceCmds(const char *Cmd){
+	uint8_t data[50];
+	int len = 0;
+	param_gethex_ex(Cmd,3,data,&len);
+	return tryDecryptWord(param_get32ex(Cmd,0,0,16),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),data,len/2);
+}
 
 static command_t CommandTable[] =
 {
@@ -1967,6 +2188,7 @@ static command_t CommandTable[] =
   {"cgetsc",	CmdHF14AMfCGetSc,		0, "Read sector - Magic Chinese card"},
   {"cload",		CmdHF14AMfCLoad,		0, "Load dump into magic Chinese card"},
   {"csave",		CmdHF14AMfCSave,		0, "Save dump from magic Chinese card into file or emulator"},
+  {"decrypt", CmdDecryptTraceCmds,1, "[nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace"},
   {NULL, NULL, 0, NULL}
 };