ADD: added identification for Mifare TNP3xxx tags.

ADD: MD5-lua functionality
ADD: AES 128 decrypt lua functionality
ADD: test luc script for reading TNP3xxx tags
CHG: testing some changes for "hf 14b sim" / "lf em4x 410xsim"
This commit is contained in:
iceman1001 2014-11-03 13:49:19 +01:00
commit c15d2bdc9b
15 changed files with 971 additions and 65 deletions

View file

@ -463,28 +463,15 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int
AT91C_BASE_SSC->SSC_THR = 0x43;
}
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
int8_t b;
b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
int8_t b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
// The samples are correlations against I and Q versions of the
// tone that the tag AM-modulates, so every other sample is I,
// every other is Q. We just want power, so abs(I) + abs(Q) is
// close to what we want.
if(getNext) {
int8_t r;
if (getNext) {
if(b < 0) {
r = -b;
} else {
r = b;
}
if(prev < 0) {
r -= prev;
} else {
r += prev;
}
dest[c++] = (uint8_t)r;
dest[c++] = abs(b) + abs(prev);
if(c >= 20000) {
break;
@ -837,27 +824,27 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber )
// Now the VICC>VCD responses when we are simulating a tag
static void BuildInventoryResponse( uint8_t *uid)
{
uint8_t cmd[13];
uint8_t cmd[12];
uint16_t crc;
// one sub-carrier, inventory, 1 slot, fast rate
// AFI is at bit 5 (1<<4) when doing an INVENTORY
cmd[0] = 0x0d; // COM LEN? Data 8 + 4 //(1 << 2) | (1 << 5) | (1 << 1);
cmd[1] = 0; // com_Adr
cmd[2] = 0; // status 00 = success
//(1 << 2) | (1 << 5) | (1 << 1);
cmd[0] = 0; //
cmd[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported
// 64-bit UID
cmd[3] = uid[7]; //0x32;
cmd[4] = uid[6]; //0x4b;
cmd[5] = uid[5]; //0x03;
cmd[6] = uid[4]; //0x01;
cmd[7] = uid[3]; //0x00;
cmd[8] = uid[2]; //0x10;
cmd[9] = uid[1]; //0x05;
cmd[10] = uid[0]; //0xe0;
cmd[2] = uid[7]; //0x32;
cmd[3] = uid[6]; //0x4b;
cmd[4] = uid[5]; //0x03;
cmd[5] = uid[4]; //0x01;
cmd[6] = uid[3]; //0x00;
cmd[7] = uid[2]; //0x10;
cmd[8] = uid[1]; //0x05;
cmd[9] = uid[0]; //0xe0;
//Now the CRC
crc = Crc(cmd, 10);
cmd[11] = crc & 0xff;
cmd[12] = crc >> 8;
cmd[10] = crc & 0xff;
cmd[11] = crc >> 8;
CodeIso15693AsReader(cmd, sizeof(cmd));
}
@ -1124,9 +1111,6 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid)
memset(buf, 0x00, 100);
// Inventory response
BuildInventoryResponse(uid);
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
@ -1149,6 +1133,9 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid)
{
// Build a suitable reponse to the reader INVENTORY cocmmand
// not so obsvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below.
BuildInventoryResponse(uid);
TransmitTo15693Reader(ToSend, ToSendMax, &tsamples, &wait);
}
@ -1156,6 +1143,10 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid)
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6], buf[7], buf[8]);
Dbprintf("Simulationg uid: %x %x %x %x %x %x %x %x",
uid[0], uid[1], uid[2], uid[3],
uid[4], uid[5], uid[6], uid[7]);
LED_A_OFF();
LED_B_OFF();
LED_C_OFF();

View file

@ -456,21 +456,30 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol)
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT);
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
//FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);
// Connect the A/D to the peak-detected low-frequency path.
//SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// Configure output and enable pin that is connected to the FPGA (for modulating)
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK;
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK;
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; // (PIO_PER) PIO Enable Register ,
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; // (PIO_OER) Output Enable Register
AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; // (PIO_ODR) Output Disable Register
// Give it a bit of time for the resonant antenna to settle.
SpinDelay(30);
SpinDelay(150);
for(;;) {
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high
while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) {
while(!BUTTON_PRESS()) {
WDT_HIT();
// PIO_PDSR = Pin Data Status Register
// GPIO_SSC_CLK = SSC Transmit Clock
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { // wait for ssp_clk to go high
if(BUTTON_PRESS()) {
DbpString("Stopped at 0");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
@ -479,12 +488,21 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol)
WDT_HIT();
}
if ( buff[i] )
OPEN_COIL();
else
SHORT_COIL();
// PIO_CODR = Clear Output Data Register
// PIO_SODR = Set Output Data Register
//#define LOW(x) AT91C_BASE_PIOA->PIO_CODR = (x)
//#define HIGH(x) AT91C_BASE_PIOA->PIO_SODR = (x)
while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) {
if ( buff[i] > 0 ){
HIGH(GPIO_SSC_DOUT);
//FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
//FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);
} else {
LOW(GPIO_SSC_DOUT);
//FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
}
while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { // wait for ssp_clk to go low
if(BUTTON_PRESS()) {
DbpString("Stopped at 1");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
@ -493,17 +511,22 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol)
WDT_HIT();
}
//SpinDelayUs(512);
++i;
if(i == period) {
i = 0;
if (gap) {
// turn of modulation
SHORT_COIL();
LOW(GPIO_SSC_DOUT);
// wait
SpinDelay(gap);
}
}
}
DbpString("Stopped");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return;
}
#define DEBUG_FRAME_CONTENTS 1

View file

@ -21,6 +21,7 @@
#include "cmdmain.h"
#include "cmddata.h"
static int CmdHelp(const char *Cmd);
int CmdAmp(const char *Cmd)
@ -670,7 +671,9 @@ int CmdManchesterDemod(const char *Cmd)
// At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
// Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful
// to stop output at the final bitidx2 value, not bitidx
for (i = 0; i < bitidx; i += 2) {
//http://www.proxmark.org/forum/viewtopic.php?id=403
for (i = 1; i < bitidx; i += 2) {
if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) {
BitStream[bit2idx++] = 1 ^ invert;
} else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) {
@ -713,7 +716,7 @@ int CmdManchesterDemod(const char *Cmd)
BitStream[i+14],
BitStream[i+15]);
}
return 0;
return bit2idx;
}
/* Modulate our data into manchester */
@ -884,7 +887,7 @@ static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"amp", CmdAmp, 1, "Amplify peaks"},
{"askdemod", Cmdaskdemod, 1, "<0 or 1> -- Attempt to demodulate simple ASK tags"},
{"askdemod", Cmdaskdemod, 1, "<0|1> -- Attempt to demodulate simple ASK tags"},
{"autocorr", CmdAutoCorr, 1, "<window length> -- Autocorrelation over window"},
{"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"},
{"bitstream", CmdBitstream, 1, "[clock rate] -- Convert waveform into a bitstream"},

View file

@ -202,6 +202,7 @@ int CmdHF14AReader(const char *Cmd)
switch (card->sak) {
case 0x00: PrintAndLog("TYPE : NXP MIFARE Ultralight | Ultralight C"); break;
case 0x01: PrintAndLog("TYPE : NXP TNP3xxx Activision Game Appliance"); break;
case 0x04: PrintAndLog("TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); break;
case 0x08: PrintAndLog("TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1"); break;
case 0x09: PrintAndLog("TYPE : NXP MIFARE Mini 0.3k"); break;

View file

@ -127,7 +127,7 @@ retest:
PrintAndLog("Thought we had a valid tag but failed at word %d (i=%d)", rows + 1, i);
/* Start back rows * 5 + 9 header bits, -1 to not start at same place */
i -= 9 + (5 * rows) -2;
i -= 9 + (5 * rows) -5;
rows = header = 0;
}
@ -220,11 +220,11 @@ int CmdEM410xSim(const char *Cmd)
int clock = 64;
/* clear our graph */
ClearGraph(1);
ClearGraph(0);
/* write it out a few times */
for (h = 0; h < 4; h++)
{
//for (h = 0; h < 4; h++)
//{
/* write 9 start bits */
for (i = 0; i < 9; i++)
AppendGraph(0, clock, 1);
@ -262,10 +262,10 @@ int CmdEM410xSim(const char *Cmd)
/* stop bit */
AppendGraph(0, clock, 0);
}
//}
/* modulate that biatch */
CmdManchesterMod("64");
//CmdManchesterMod("64");
/* booyah! */
RepaintGraphWindow();
@ -295,7 +295,7 @@ int CmdEM410xWatch(const char *Cmd)
}
CmdLFRead(read_h ? "h" : "");
CmdSamples("16000");
CmdSamples("6000");
} while (
!CmdEM410xRead("")
@ -654,8 +654,10 @@ int CmdWriteWordPWD(const char *Cmd)
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"},
{"410xsim", CmdEM410xSim, 0, "<UID> -- Simulate EM410x tag"},
{"replay", MWRem4xReplay, 0, "Watches for tag and simulates manchester encoded em4x tag"},
{"410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
{"410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
{"410xwrite", CmdEM410xWrite, 1, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
@ -667,6 +669,265 @@ static command_t CommandTable[] =
{NULL, NULL, 0, NULL}
};
//Confirms the parity of a bitstream as well as obtaining the data (TagID) from within the appropriate memory space.
//Arguments:
// Pointer to a string containing the desired bitsream
// Pointer to a string that will receive the decoded tag ID
// Length of the bitsream pointed at in the first argument, char* _strBitStream
//Retuns:
//1 Parity confirmed
//0 Parity not confirmed
int ConfirmEm410xTagParity( char* _strBitStream, char* pID, int LengthOfBitstream )
{
int i = 0;
int rows = 0;
int Parity[4] = {0x00};
char ID[11] = {0x00};
int k = 0;
int BitStream[70] = {0x00};
int counter = 0;
//prepare variables
for ( i = 0; i <= LengthOfBitstream; i++)
{
if (_strBitStream[i] == '1')
{
k =1;
memcpy(&BitStream[i], &k,4);
}
else if (_strBitStream[i] == '0')
{
k = 0;
memcpy(&BitStream[i], &k,4);
}
}
while ( counter < 2 )
{
//set/reset variables and counters
memset(ID,0x00,sizeof(ID));
memset(Parity,0x00,sizeof(Parity));
rows = 0;
for ( i = 9; i <= LengthOfBitstream; i++)
{
if ( rows < 10 )
{
if ((BitStream[i] ^ BitStream[i+1] ^ BitStream[i+2] ^ BitStream[i+3]) == BitStream[i+4])
{
sprintf(ID+rows, "%x", (8 * BitStream[i]) + (4 * BitStream[i+1]) + (2 * BitStream[i+2]) + (1 * BitStream[i+3]));
rows++;
/* Keep parity info and move four bits ahead*/
Parity[0] ^= BitStream[i];
Parity[1] ^= BitStream[i+1];
Parity[2] ^= BitStream[i+2];
Parity[3] ^= BitStream[i+3];
i += 4;
}
}
if ( rows == 10 )
{
if ( BitStream[i] == Parity[0] && BitStream[i+1] == Parity[1] &&
BitStream[i+2] == Parity[2] && BitStream[i+3] == Parity[3] &&
BitStream[i+4] == 0)
{
memcpy(pID,ID,strlen(ID));
return 1;
}
}
}
printf("[PARITY ->]Failed. Flipping Bits, and rechecking parity for bitstream:\n[PARITY ->]");
for (k = 0; k < LengthOfBitstream; k++)
{
BitStream[k] ^= 1;
printf("%i", BitStream[k]);
}
puts(" ");
counter++;
}
return 0;
}
//Reads and demodulates an em410x RFID tag. It further allows slight modification to the decoded bitstream
//Once a suitable bitstream has been identified, and if needed, modified, it is replayed. Allowing emulation of the
//"stolen" rfid tag.
//No meaningful returns or arguments.
int MWRem4xReplay(const char* Cmd)
{
// //header traces
// static char ArrayTraceZero[] = { '0','0','0','0','0','0','0','0','0' };
// static char ArrayTraceOne[] = { '1','1','1','1','1','1','1','1','1' };
// //local string variables
// char strClockRate[10] = {0x00};
// char strAnswer[4] = {0x00};
// char strTempBufferMini[2] = {0x00};
// //our outbound bit-stream
// char strSimulateBitStream[65] = {0x00};
// //integers
// int iClockRate = 0;
// int needle = 0;
// int j = 0;
// int iFirstHeaderOffset = 0x00000000;
// int numManchesterDemodBits=0;
// //boolean values
// bool bInverted = false;
// //pointers to strings. memory will be allocated.
// char* pstrInvertBitStream = 0x00000000;
// char* pTempBuffer = 0x00000000;
// char* pID = 0x00000000;
// char* strBitStreamBuffer = 0x00000000;
// puts("###################################");
// puts("#### Em4x Replay ##");
// puts("#### R.A.M. June 2013 ##");
// puts("###################################");
// //initialize
// CmdLFRead("");
// //Collect ourselves 10,000 samples
// CmdSamples("10000");
// puts("[->]preforming ASK demodulation\n");
// //demodulate ask
// Cmdaskdemod("0");
// iClockRate = DetectClock(0);
// sprintf(strClockRate, "%i\n",iClockRate);
// printf("[->]Detected ClockRate: %s\n", strClockRate);
// //If detected clock rate is something completely unreasonable, dont go ahead
// if ( iClockRate < 0xFFFE )
// {
// pTempBuffer = (char*)malloc(MAX_GRAPH_TRACE_LEN);
// if (pTempBuffer == 0x00000000)
// return 0;
// memset(pTempBuffer,0x00,MAX_GRAPH_TRACE_LEN);
// //Preform manchester de-modulation and display in a single line.
// numManchesterDemodBits = CmdManchesterDemod( strClockRate );
// //note: numManchesterDemodBits is set above in CmdManchesterDemod()
// if ( numManchesterDemodBits == 0 )
// return 0;
// strBitStreamBuffer = malloc(numManchesterDemodBits+1);
// if ( strBitStreamBuffer == 0x00000000 )
// return 0;
// memset(strBitStreamBuffer, 0x00, (numManchesterDemodBits+1));
// //fill strBitStreamBuffer with demodulated, string formatted bits.
// for ( j = 0; j <= numManchesterDemodBits; j++ )
// {
// sprintf(strTempBufferMini, "%i",BitStream[j]);
// strcat(strBitStreamBuffer,strTempBufferMini);
// }
// printf("[->]Demodulated Bitstream: \n%s\n", strBitStreamBuffer);
// //Reset counter and select most probable bit stream
// j = 0;
// while ( j < numManchesterDemodBits )
// {
// memset(strSimulateBitStream,0x00,64);
// //search for header of nine (9) 0's : 000000000 or nine (9) 1's : 1111 1111 1
// if ( ( strncmp(strBitStreamBuffer+j, ArrayTraceZero, sizeof(ArrayTraceZero)) == 0 ) ||
// ( strncmp(strBitStreamBuffer+j, ArrayTraceOne, sizeof(ArrayTraceOne)) == 0 ) )
// {
// iFirstHeaderOffset = j;
// memcpy(strSimulateBitStream, strBitStreamBuffer+j,64);
// printf("[->]Offset of Header");
// if ( strncmp(strBitStreamBuffer+iFirstHeaderOffset, "0", 1) == 0 )
// printf("'%s'", ArrayTraceZero );
// else
// printf("'%s'", ArrayTraceOne );
// printf(": %i\nHighlighted string : %s\n",iFirstHeaderOffset,strSimulateBitStream);
// //allow us to escape loop or choose another frame
// puts("[<-]Are we happy with this sample? [Y]es/[N]o");
// gets(strAnswer);
// if ( ( strncmp(strAnswer,"y",1) == 0 ) || ( strncmp(strAnswer,"Y",1) == 0 ) )
// {
// j = numManchesterDemodBits+1;
// break;
// }
// }
// j++;
// }
// }
// else return 0;
// //Do we want the buffer inverted?
// memset(strAnswer, 0x00, sizeof(strAnswer));
// printf("[<-]Do you wish to invert the highlighted bitstream? [Y]es/[N]o\n");
// gets(strAnswer);
// if ( ( strncmp("y", strAnswer,1) == 0 ) || ( strncmp("Y", strAnswer, 1 ) == 0 ) )
// {
// //allocate heap memory
// pstrInvertBitStream = (char*)malloc(numManchesterDemodBits);
// if ( pstrInvertBitStream != 0x00000000 )
// {
// memset(pstrInvertBitStream,0x00,numManchesterDemodBits);
// bInverted = true;
// //Invert Bitstream
// for ( needle = 0; needle <= numManchesterDemodBits; needle++ )
// {
// if (strSimulateBitStream[needle] == '0')
// strcat(pstrInvertBitStream,"1");
// else if (strSimulateBitStream[needle] == '1')
// strcat(pstrInvertBitStream,"0");
// }
// printf("[->]Inverted bitstream: %s\n", pstrInvertBitStream);
// }
// }
// //Confirm parity of selected string
// pID = (char*)malloc(11);
// if (pID != 0x00000000)
// {
// memset(pID, 0x00, 11);
// if (ConfirmEm410xTagParity(strSimulateBitStream,pID, 64) == 1)
// {
// printf("[->]Parity confirmed for selected bitstream!\n");
// printf("[->]Tag ID was detected as: [hex]:%s\n",pID );
// }
// else
// printf("[->]Parity check failed for the selected bitstream!\n");
// }
// //Spoof
// memset(strAnswer, 0x00, sizeof(strAnswer));
// printf("[<-]Do you wish to continue with the EM4x simulation? [Y]es/[N]o\n");
// gets(strAnswer);
// if ( ( strncmp(strAnswer,"y",1) == 0 ) || ( strncmp(strAnswer,"Y",1) == 0 ) )
// {
// strcat(pTempBuffer, strClockRate);
// strcat(pTempBuffer, " ");
// if (bInverted == true)
// strcat(pTempBuffer,pstrInvertBitStream);
// if (bInverted == false)
// strcat(pTempBuffer,strSimulateBitStream);
// //inform the user
// puts("[->]Starting simulation now: \n");
// //Simulate tag with prepared buffer.
// CmdLFSimManchester(pTempBuffer);
// }
// else if ( ( strcmp("n", strAnswer) == 0 ) || ( strcmp("N", strAnswer ) == 0 ) )
// printf("[->]Exiting procedure now...\n");
// else
// printf("[->]Erroneous selection\nExiting procedure now....\n");
// //Clean up -- Exit function
// //clear memory, then release pointer.
// if ( pstrInvertBitStream != 0x00000000 )
// {
// memset(pstrInvertBitStream,0x00,numManchesterDemodBits);
// free(pstrInvertBitStream);
// }
// if ( pTempBuffer != 0x00000000 )
// {
// memset(pTempBuffer,0x00,MAX_GRAPH_TRACE_LEN);
// free(pTempBuffer);
// }
// if ( pID != 0x00000000 )
// {
// memset(pID,0x00,11);
// free(pID);
// }
// if ( strBitStreamBuffer != 0x00000000 )
// {
// memset(strBitStreamBuffer,0x00,numManchesterDemodBits);
// free(strBitStreamBuffer);
// }
return 0;
}
int CmdLFEM4X(const char *Cmd)
{
CmdsParse(CommandTable, Cmd);

View file

@ -22,5 +22,6 @@ int CmdReadWord(const char *Cmd);
int CmdReadWordPWD(const char *Cmd);
int CmdWriteWord(const char *Cmd);
int CmdWriteWordPWD(const char *Cmd);
int MWRem4xReplay(const char* Cmd);
#endif

View file

@ -89,6 +89,9 @@ int DetectClock(int peak)
case 1: clock--; break;
case 2: clock -= 2; break;
}
if ( clock < 32)
clock = 32;
printf("- adjusted it to %d \n", clock);
return clock;
}

View file

@ -55,6 +55,7 @@ local skel_1 = [[
return "UNKNOWN"
}
add("04,,,Mifare TNP3xxx Activision 1K,0f01,01");
add("04,,,Mifare Mini,0004,09");
add("04,,,Mifare Classic 1k/Mifare Plus(4 byte UID) 2K SL1,0004,08");
add("04,,,Mifare Plus (4 byte UID) 2K SL2,0004,10");

384
client/lualibs/md5.lua Normal file
View file

@ -0,0 +1,384 @@
local md5 = {
_VERSION = "md5.lua 0.5.0",
_DESCRIPTION = "MD5 computation in Lua (5.1)",
_URL = "https://github.com/kikito/md5.lua",
_LICENSE = [[
MIT LICENSE
Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
}
-- bit lib implementions
local floor, abs, max = math.floor, math.abs, math.max
local char, byte, format, rep, sub =
string.char, string.byte, string.format, string.rep, string.sub
local function check_int(n)
-- checking not float
if(n - floor(n) > 0) then
error("trying to use bitwise operation on non-integer!")
end
end
local function tbl2number(tbl)
local n = #tbl
local rslt = 0
local power = 1
for i = 1, n do
rslt = rslt + tbl[i]*power
power = power*2
end
return rslt
end
local function expand(tbl_m, tbl_n)
local big = {}
local small = {}
if(#tbl_m > #tbl_n) then
big = tbl_m
small = tbl_n
else
big = tbl_n
small = tbl_m
end
-- expand small
for i = #small + 1, #big do
small[i] = 0
end
end
local to_bits -- needs to be declared before bit_not
local function bit_not(n)
local tbl = to_bits(n)
local size = max(#tbl, 32)
for i = 1, size do
if(tbl[i] == 1) then
tbl[i] = 0
else
tbl[i] = 1
end
end
return tbl2number(tbl)
end
-- defined as local above
to_bits = function (n)
check_int(n)
if(n < 0) then
-- negative
return to_bits(bit_not(abs(n)) + 1)
end
-- to bits table
local tbl = {}
local cnt = 1
while (n > 0) do
local last = math.fmod(n,2)
if(last == 1) then
tbl[cnt] = 1
else
tbl[cnt] = 0
end
n = (n-last)/2
cnt = cnt + 1
end
return tbl
end
local function bit_or(m, n)
local tbl_m = to_bits(m)
local tbl_n = to_bits(n)
expand(tbl_m, tbl_n)
local tbl = {}
local rslt = max(#tbl_m, #tbl_n)
for i = 1, rslt do
if(tbl_m[i]== 0 and tbl_n[i] == 0) then
tbl[i] = 0
else
tbl[i] = 1
end
end
return tbl2number(tbl)
end
local function bit_and(m, n)
local tbl_m = to_bits(m)
local tbl_n = to_bits(n)
expand(tbl_m, tbl_n)
local tbl = {}
local rslt = max(#tbl_m, #tbl_n)
for i = 1, rslt do
if(tbl_m[i]== 0 or tbl_n[i] == 0) then
tbl[i] = 0
else
tbl[i] = 1
end
end
return tbl2number(tbl)
end
local function bit_xor(m, n)
local tbl_m = to_bits(m)
local tbl_n = to_bits(n)
expand(tbl_m, tbl_n)
local tbl = {}
local rslt = max(#tbl_m, #tbl_n)
for i = 1, rslt do
if(tbl_m[i] ~= tbl_n[i]) then
tbl[i] = 1
else
tbl[i] = 0
end
end
return tbl2number(tbl)
end
local function bit_rshift(n, bits)
check_int(n)
local high_bit = 0
if(n < 0) then
-- negative
n = bit_not(abs(n)) + 1
high_bit = 2147483648 -- 0x80000000
end
for i=1, bits do
n = n/2
n = bit_or(floor(n), high_bit)
end
return floor(n)
end
local function bit_lshift(n, bits)
check_int(n)
if(n < 0) then
-- negative
n = bit_not(abs(n)) + 1
end
for i=1, bits do
n = n*2
end
return bit_and(n, 4294967295) -- 0xFFFFFFFF
end
-- convert little-endian 32-bit int to a 4-char string
local function lei2str(i)
local f=function (s) return char( bit_and( bit_rshift(i, s), 255)) end
return f(0)..f(8)..f(16)..f(24)
end
-- convert raw string to big-endian int
local function str2bei(s)
local v=0
for i=1, #s do
v = v * 256 + byte(s, i)
end
return v
end
-- convert raw string to little-endian int
local function str2lei(s)
local v=0
for i = #s,1,-1 do
v = v*256 + byte(s, i)
end
return v
end
-- cut up a string in little-endian ints of given size
local function cut_le_str(s,...)
local o, r = 1, {}
local args = {...}
for i=1, #args do
table.insert(r, str2lei(sub(s, o, o + args[i] - 1)))
o = o + args[i]
end
return r
end
local swap = function (w) return str2bei(lei2str(w)) end
local function hex2binaryaux(hexval)
return char(tonumber(hexval, 16))
end
local function hex2binary(hex)
local result, _ = hex:gsub('..', hex2binaryaux)
return result
end
-- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh)
-- 10/02/2001 jcw@equi4.com
local FF = 0xffffffff
local CONSTS = {
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
}
local f=function (x,y,z) return bit_or(bit_and(x,y),bit_and(-x-1,z)) end
local g=function (x,y,z) return bit_or(bit_and(x,z),bit_and(y,-z-1)) end
local h=function (x,y,z) return bit_xor(x,bit_xor(y,z)) end
local i=function (x,y,z) return bit_xor(y,bit_or(x,-z-1)) end
local z=function (f,a,b,c,d,x,s,ac)
a=bit_and(a+f(b,c,d)+x+ac,FF)
-- be *very* careful that left shift does not cause rounding!
return bit_or(bit_lshift(bit_and(a,bit_rshift(FF,s)),s),bit_rshift(a,32-s))+b
end
local function transform(A,B,C,D,X)
local a,b,c,d=A,B,C,D
local t=CONSTS
a=z(f,a,b,c,d,X[ 0], 7,t[ 1])
d=z(f,d,a,b,c,X[ 1],12,t[ 2])
c=z(f,c,d,a,b,X[ 2],17,t[ 3])
b=z(f,b,c,d,a,X[ 3],22,t[ 4])
a=z(f,a,b,c,d,X[ 4], 7,t[ 5])
d=z(f,d,a,b,c,X[ 5],12,t[ 6])
c=z(f,c,d,a,b,X[ 6],17,t[ 7])
b=z(f,b,c,d,a,X[ 7],22,t[ 8])
a=z(f,a,b,c,d,X[ 8], 7,t[ 9])
d=z(f,d,a,b,c,X[ 9],12,t[10])
c=z(f,c,d,a,b,X[10],17,t[11])
b=z(f,b,c,d,a,X[11],22,t[12])
a=z(f,a,b,c,d,X[12], 7,t[13])
d=z(f,d,a,b,c,X[13],12,t[14])
c=z(f,c,d,a,b,X[14],17,t[15])
b=z(f,b,c,d,a,X[15],22,t[16])
a=z(g,a,b,c,d,X[ 1], 5,t[17])
d=z(g,d,a,b,c,X[ 6], 9,t[18])
c=z(g,c,d,a,b,X[11],14,t[19])
b=z(g,b,c,d,a,X[ 0],20,t[20])
a=z(g,a,b,c,d,X[ 5], 5,t[21])
d=z(g,d,a,b,c,X[10], 9,t[22])
c=z(g,c,d,a,b,X[15],14,t[23])
b=z(g,b,c,d,a,X[ 4],20,t[24])
a=z(g,a,b,c,d,X[ 9], 5,t[25])
d=z(g,d,a,b,c,X[14], 9,t[26])
c=z(g,c,d,a,b,X[ 3],14,t[27])
b=z(g,b,c,d,a,X[ 8],20,t[28])
a=z(g,a,b,c,d,X[13], 5,t[29])
d=z(g,d,a,b,c,X[ 2], 9,t[30])
c=z(g,c,d,a,b,X[ 7],14,t[31])
b=z(g,b,c,d,a,X[12],20,t[32])
a=z(h,a,b,c,d,X[ 5], 4,t[33])
d=z(h,d,a,b,c,X[ 8],11,t[34])
c=z(h,c,d,a,b,X[11],16,t[35])
b=z(h,b,c,d,a,X[14],23,t[36])
a=z(h,a,b,c,d,X[ 1], 4,t[37])
d=z(h,d,a,b,c,X[ 4],11,t[38])
c=z(h,c,d,a,b,X[ 7],16,t[39])
b=z(h,b,c,d,a,X[10],23,t[40])
a=z(h,a,b,c,d,X[13], 4,t[41])
d=z(h,d,a,b,c,X[ 0],11,t[42])
c=z(h,c,d,a,b,X[ 3],16,t[43])
b=z(h,b,c,d,a,X[ 6],23,t[44])
a=z(h,a,b,c,d,X[ 9], 4,t[45])
d=z(h,d,a,b,c,X[12],11,t[46])
c=z(h,c,d,a,b,X[15],16,t[47])
b=z(h,b,c,d,a,X[ 2],23,t[48])
a=z(i,a,b,c,d,X[ 0], 6,t[49])
d=z(i,d,a,b,c,X[ 7],10,t[50])
c=z(i,c,d,a,b,X[14],15,t[51])
b=z(i,b,c,d,a,X[ 5],21,t[52])
a=z(i,a,b,c,d,X[12], 6,t[53])
d=z(i,d,a,b,c,X[ 3],10,t[54])
c=z(i,c,d,a,b,X[10],15,t[55])
b=z(i,b,c,d,a,X[ 1],21,t[56])
a=z(i,a,b,c,d,X[ 8], 6,t[57])
d=z(i,d,a,b,c,X[15],10,t[58])
c=z(i,c,d,a,b,X[ 6],15,t[59])
b=z(i,b,c,d,a,X[13],21,t[60])
a=z(i,a,b,c,d,X[ 4], 6,t[61])
d=z(i,d,a,b,c,X[11],10,t[62])
c=z(i,c,d,a,b,X[ 2],15,t[63])
b=z(i,b,c,d,a,X[ 9],21,t[64])
return A+a,B+b,C+c,D+d
end
----------------------------------------------------------------
function md5.sumhexa(s)
local msgLen = #s
local padLen = 56 - msgLen % 64
if msgLen % 64 > 56 then padLen = padLen + 64 end
if padLen == 0 then padLen = 64 end
s = s .. char(128) .. rep(char(0),padLen-1) .. lei2str(8*msgLen) .. lei2str(0)
assert(#s % 64 == 0)
local t = CONSTS
local a,b,c,d = t[65],t[66],t[67],t[68]
for i=1,#s,64 do
local X = cut_le_str(sub(s,i,i+63),4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4)
assert(#X == 16)
X[0] = table.remove(X,1) -- zero based!
a,b,c,d = transform(a,b,c,d,X)
end
return format("%08x%08x%08x%08x",swap(a),swap(b),swap(c),swap(d))
end
function md5.sum(s)
return hex2binary(md5.sumhexa(s))
end
return md5

View file

@ -141,7 +141,13 @@ local _keys = {
'200000000000',
'a00000000000',
'b00000000000',
}
--[[
Should be for Mifare TNP3xxx tags A KEY.
--]]
'4b0b20107ccb',
}
---
-- The keys above have just been pasted in, for completeness sake. They contain duplicates.

View file

@ -25,6 +25,7 @@ local ISO14A_COMMAND = {
local ISO14443a_TYPES = {}
ISO14443a_TYPES[0x00] = "NXP MIFARE Ultralight | Ultralight C"
ISO14443a_TYPES[0x01] = "NXP MIFARE TNP3xxx Activision Game Appliance"
ISO14443a_TYPES[0x04] = "NXP MIFARE (various !DESFire !DESFire EV1)"
ISO14443a_TYPES[0x08] = "NXP MIFARE CLASSIC 1k | Plus 2k"
ISO14443a_TYPES[0x09] = "NXP MIFARE Mini 0.3k"

View file

@ -18,6 +18,7 @@
#include "util.h"
#include "nonce2key/nonce2key.h"
#include "../common/iso15693tools.h"
#include <openssl/aes.h>
/**
* The following params expected:
* UsbCommand c
@ -224,6 +225,44 @@ static int l_iso15693_crc(lua_State *L)
return 1;
}
/*
Simple AES 128 cbc hook up to OpenSSL.
params: key, input
*/
static int l_aes(lua_State *L)
{
//Check number of arguments
int i;
size_t size;
const char *p_key = luaL_checklstring(L, 1, &size);
if(size != 32) return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size);
const char *p_encTxt = luaL_checklstring(L, 2, &size);
unsigned char indata[AES_BLOCK_SIZE] = {0x00};
unsigned char outdata[AES_BLOCK_SIZE] = {0x00};
unsigned char aes_key[AES_BLOCK_SIZE] = {0x00};
unsigned char iv[AES_BLOCK_SIZE] = {0x00};
// convert key to bytearray
for (i = 0; i < 32; i += 2) {
sscanf(&p_encTxt[i], "%02x", (unsigned int *)&indata[i / 2]);
}
// convert input to bytearray
for (i = 0; i < 32; i += 2) {
sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]);
}
AES_KEY key;
AES_set_decrypt_key(aes_key, 128, &key);
AES_cbc_encrypt(indata, outdata, sizeof(indata), &key, iv, AES_DECRYPT);
//Push decrypted array as a string
lua_pushlstring(L,(const char *)&outdata, sizeof(outdata));
return 1;// return 1 to signal one return value
}
/**
* @brief Sets the lua path to include "./lualibs/?.lua", in order for a script to be
* able to do "require('foobar')" if foobar.lua is within lualibs folder.
@ -261,6 +300,7 @@ int set_pm3_libraries(lua_State *L)
{"clearCommandBuffer", l_clearCommandBuffer},
{"console", l_CmdConsole},
{"iso15693_crc", l_iso15693_crc},
{"aes", l_aes},
{NULL, NULL}
};

View file

@ -133,6 +133,8 @@ function nested(key,sak)
typ = 0
elseif 0x10 == sak then-- "NXP MIFARE Plus 2k"
typ = 2
elseif 0x01 == sak then-- "NXP MIFARE TNP3xxx 1K"
typ = 1
else
print("I don't know how many sectors there are on this type of card, defaulting to 16")
end

189
client/scripts/tnp3.lua Normal file
View file

@ -0,0 +1,189 @@
local cmds = require('commands')
local getopt = require('getopt')
local bin = require('bin')
local lib14a = require('read14a')
local utils = require('utils')
local md5 = require('md5')
example =[[
1. script run tnp3
2. script run tnp3 -k aabbccddeeff
]]
author = "Iceman"
usage = "script run tnp3 -k <key>"
desc =[[
This script will try to dump the contents of a Mifare TNP3xxx card.
It will need a valid KeyA in order to find the other keys and decode the card.
Arguments:
-h - this help
-k <key> - Sector 0 Key A.
]]
local hashconstant = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds
local DEBUG = true -- the debug flag
local numBlocks = 64
local numSectors = 16
---
-- A debug printout-function
function dbg(args)
if not DEBUG then
return
end
if type(args) == "table" then
local i = 1
while result[i] do
dbg(result[i])
i = i+1
end
else
print("###", args)
end
end
---
-- This is only meant to be used when errors occur
function oops(err)
print("ERROR: ",err)
end
---
-- Usage help
function help()
print(desc)
print("Example usage")
print(example)
end
--
-- Exit message
function ExitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
local function show(data)
if DEBUG then
local formatString = ("H%d"):format(string.len(data))
local _,hexdata = bin.unpack(formatString, data)
dbg("Hexdata" , hexdata)
end
end
function waitCmd()
local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)
if response then
local count,cmd,arg0 = bin.unpack('LL',response)
if(arg0==1) then
local count,arg1,arg2,data = bin.unpack('LLH511',response,count)
return data:sub(1,32)
else
return nil, "Couldn't read block.."
end
end
return nil, "No response from device"
end
local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
print()
local keyA
local cmd
local err
local cmdReadBlockString = 'hf mf rdbl %d A %s'
-- Arguments for the script
for o, a in getopt.getopt(args, 'hk:') do
if o == "h" then return help() end
if o == "k" then keyA = a end
end
-- validate input args.
keyA = keyA or '4b0b20107ccb'
if #(keyA) ~= 12 then
return oops( string.format('Wrong length of write key (was %d) expected 12', #keyA))
end
result, err = lib14a.read1443a(false)
if not result then
print(err)
return
end
print((" Found tag : %s"):format(result.name))
core.clearCommandBuffer()
if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx
print("This is not a TNP3xxx tag. aborting.")
return
end
-- Show info
print(('Using keyA : %s'):format(keyA))
print( string.rep('--',20) )
local cmdNestedString = 'hf mf nested 1 0 A %s d'
local cmdDumpString = 'hf mf dump'
--core.console(cmdNestedString.format(keyA) )
--core.console(cmdDumpString)
print('Reading data need to dump data')
-- Read block 0
cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0,arg2 = 0,arg3 = 0, data = keyA}
err = core.SendCommand(cmd:getBytes())
if err then return oops(err) end
local block0, err = waitCmd()
if err then return oops(err) end
-- Read block 1
cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 1,arg2 = 0,arg3 = 0, data = keyA}
local err = core.SendCommand(cmd:getBytes())
if err then return oops(err) end
local block1, err = waitCmd()
if err then return oops(err) end
-- Read block 9
cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 9,arg2 = 0,arg3 = 0, data = '56f6313550f9'}
local err = core.SendCommand(cmd:getBytes())
if err then return oops(err) end
local block9, err = waitCmd()
if err then return oops(err) end
-- main loop
print('BLOCK MD5 DECRYPTED ASCII' )
for block=0,numBlocks-1,1 do
if math.fmod(block,4) then
end
local base = ('%s%s%02d%s'):format(block0, block1, block, hashconstant)
local md5hash = md5.sumhexa(base)
local aestest = core.aes(md5hash, block9 )
local _,hex = bin.unpack(("H%d"):format(16),aestest)
local hexascii = string.gsub(hex, '(%x%x)',
function(value)
return string.char(tonumber(value, 16))
end
)
print( block .. ' :: ' .. md5hash .. ' :: ' .. hex .. ' :: ' .. hexascii )
-- if core.ukbhit() then
-- print("aborted by user")
-- break
-- end
end
end
main(args)

View file

@ -428,7 +428,7 @@ typedef struct _AT91S_PIO {
#define PIO_PDR (AT91_CAST(AT91_REG *) 0x00000004) // (PIO_PDR) PIO Disable Register
#define PIO_PSR (AT91_CAST(AT91_REG *) 0x00000008) // (PIO_PSR) PIO Status Register
#define PIO_OER (AT91_CAST(AT91_REG *) 0x00000010) // (PIO_OER) Output Enable Register
#define PIO_ODR (AT91_CAST(AT91_REG *) 0x00000014) // (PIO_ODR) Output Disable Registerr
#define PIO_ODR (AT91_CAST(AT91_REG *) 0x00000014) // (PIO_ODR) Output Disable Register
#define PIO_OSR (AT91_CAST(AT91_REG *) 0x00000018) // (PIO_OSR) Output Status Register
#define PIO_IFER (AT91_CAST(AT91_REG *) 0x00000020) // (PIO_IFER) Input Filter Enable Register
#define PIO_IFDR (AT91_CAST(AT91_REG *) 0x00000024) // (PIO_IFDR) Input Filter Disable Register