From: Martin Holst Swende <martin@swende.se>
Date: Sun, 31 May 2015 11:08:36 +0000 (+0200)
Subject: Merge pull request #112 from marshmellow42/master
X-Git-Tag: v2.1.0~8
X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/6cb08550c40e94e1662ca8351dcca5139615ee66?hp=96c4f5517eea0b14fa2452d94053244110058a62

Merge pull request #112 from marshmellow42/master

combine mfu read/write commands + various bug/typo fixes
---

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 85e7f915..3c016c3d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 
 ## [Unreleased][unreleased]
 ### Changed
+- Added ultralight/ntag tag type detection to `hf 14a read` (marshmellow)
+- Improved ultralight dump command to auto detect tag type, take authentication, and dump full memory (or subset specified) of known tag types (iceman1001 / marshmellow)
+- Combined ultralight read/write commands and added authentication (iceman1001)
 - Improved LF manchester and biphase demodulation and ask clock detection especially for reads with heavy clipping. (marshmellow)
 - Iclass read, `hf iclass read` now also reads tag config and prints configuration. (holiman)
 - *bootrom* needs to be flashed, due to new address boundaries between os and fpga, after a size optimization (piwi)
@@ -13,6 +16,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 - Fixed issue #19, problems with LF T55xx commands (iceman1001, marshmellow)
 
 ### Added
+- Added `hf search` - currently tests for 14443a tags, iclass tags, and 15693 tags (marshmellow) 
+- Added `hf mfu info` Ultralight/NTAG info command - reads tag configuration and info, allows authentication if needed (iceman1001, marshmellow)
+- Added Mifare Ultralight C and Ultralight EV1/NTAG authentication. (iceman1001)
 - Added changelog
 
 ## [2.0.0] - 2015-03-25
diff --git a/armsrc/appmain.c b/armsrc/appmain.c
index 96644b9a..c226c726 100644
--- a/armsrc/appmain.c
+++ b/armsrc/appmain.c
@@ -841,11 +841,11 @@ void UsbPacketReceived(uint8_t *packet, int len)
 		case CMD_MIFARE_WRITEBL:
 			MifareWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
 			break;
-		case CMD_MIFAREU_WRITEBL_COMPAT:
-			MifareUWriteBlock(c->arg[0], c->d.asBytes);
-			break;
+		//case CMD_MIFAREU_WRITEBL_COMPAT:
+			//MifareUWriteBlockCompat(c->arg[0], c->d.asBytes);
+			//break;
 		case CMD_MIFAREU_WRITEBL:
-			MifareUWriteBlock_Special(c->arg[0], c->d.asBytes);
+			MifareUWriteBlock(c->arg[0], c->arg[1], c->d.asBytes);
 			break;
 		case CMD_MIFARE_NESTED:
 			MifareNested(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
diff --git a/armsrc/apps.h b/armsrc/apps.h
index 57fb55fd..6360b664 100644
--- a/armsrc/apps.h
+++ b/armsrc/apps.h
@@ -170,8 +170,8 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *datain);
 void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
 void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
 void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
-void MifareUWriteBlock(uint8_t arg0,uint8_t *datain);
-void MifareUWriteBlock_Special(uint8_t arg0,uint8_t *datain);
+//void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain);
+void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
 void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
 void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
 void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c
index 64bbcbf5..cf64da2f 100644
--- a/armsrc/iso14443a.c
+++ b/armsrc/iso14443a.c
@@ -2510,13 +2510,13 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
 						|| receivedCmd[0] == 0xB0) { // transfer
 					if (receivedCmd[1] >= 16 * 4) {
 						EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
-						if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02) on out of range block: %d (0x%02x), nacking",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
+						if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
 						break;
 					}
 
 					if (receivedCmd[1] / 4 != cardAUTHSC) {
 						EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
-						if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd[0],receivedCmd[1],cardAUTHSC);
+						if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd[0],receivedCmd[1],cardAUTHSC);
 						break;
 					}
 				}
diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c
index 8355cd19..939c9002 100644
--- a/armsrc/mifarecmd.c
+++ b/armsrc/mifarecmd.c
@@ -16,7 +16,6 @@
 #include "mifarecmd.h"
 #include "apps.h"
 #include "util.h"
-
 #include "crc.h"
 
 // the block number for the ISO14443-4 PCB
@@ -24,7 +23,6 @@ uint8_t pcb_blocknum = 0;
 // Deselect card by sending a s-block. the crc is precalced for speed
 static  uint8_t deselect_cmd[] = {0xc2,0xe0,0xb4};
 
-
 //-----------------------------------------------------------------------------
 // Select, Authenticate, Read a MIFARE tag. 
 // read block
@@ -248,11 +246,14 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
 	LEDsoff();
 }
 
+// arg0 = blockNo (start)
+// arg1 = Pages (number of blocks)
+// arg2 = useKey
+// datain = KEY bytes
 void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
 {
 	// free eventually allocated BigBuf memory
 	BigBuf_free();
-	// clear trace
 	clear_trace();
 
 	// params
@@ -303,7 +304,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
 	}
 
 	for (int i = 0; i < blocks; i++){
-		if ((i*4) + 4 > CARD_MEMORY_SIZE) {
+		if ((i*4) + 4 >= CARD_MEMORY_SIZE) {
 			Dbprintf("Data exceeds buffer!!");
 			break;
 		}
@@ -335,9 +336,11 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
 	if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Blocks read %d", countblocks);
 
 	countblocks *= 4;
+
 	cmd_send(CMD_ACK, 1, countblocks, BigBuf_max_traceLen(), 0, 0);
 	FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
 	LEDsoff();
+	BigBuf_free();
 }
 
 //-----------------------------------------------------------------------------
@@ -412,7 +415,8 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
 	LEDsoff();
 }
 
-void MifareUWriteBlock(uint8_t arg0, uint8_t *datain)
+/* // Command not needed but left for future testing 
+void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain)
 {
 	uint8_t blockNo = arg0;
 	byte_t blockdata[16] = {0x00};
@@ -432,7 +436,7 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t *datain)
 		return;
 	};
 
-	if(mifare_ultra_writeblock(blockNo, blockdata)) {
+	if(mifare_ultra_writeblock_compat(blockNo, blockdata)) {
 		if (MF_DBGLEVEL >= 1)   Dbprintf("Write block error");
 		OnError(0);
 		return;	};
@@ -449,10 +453,19 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t *datain)
 	FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
 	LEDsoff();
 }
-
-void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain)
+*/
+
+// Arg0   : Block to write to.
+// Arg1   : 0 = use no authentication.
+//          1 = use 0x1A authentication.
+//          2 = use 0x1B authentication.
+// datain : 4 first bytes is data to be written.
+//        : 4/16 next bytes is authentication key.
+void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
 {
 	uint8_t blockNo = arg0;
+	bool useKey = (arg1 == 1); //UL_C
+	bool usePwd = (arg1 == 2); //UL_EV1/NTAG
 	byte_t blockdata[4] = {0x00};
 
 	memcpy(blockdata, datain,4);
@@ -468,7 +481,29 @@ void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain)
 		return;
 	};
 
-	if(mifare_ultra_special_writeblock(blockNo, blockdata)) {
+	// UL-C authentication
+	if ( useKey ) {
+		uint8_t key[16] = {0x00};
+		memcpy(key, datain+4, sizeof(key) );
+
+		if ( !mifare_ultra_auth(key) ) {
+			OnError(1);
+			return;
+		}
+	}
+	
+	// UL-EV1 / NTAG authentication
+	if (usePwd) {
+		uint8_t pwd[4] = {0x00};
+		memcpy(pwd, datain+4, 4);
+		uint8_t pack[4] = {0,0,0,0};
+		if (!mifare_ul_ev1_auth(pwd, pack)) {
+			OnError(1);
+			return;
+		}
+	}
+
+	if(mifare_ultra_writeblock(blockNo, blockdata)) {
 		if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
 		OnError(0);
 		return;
@@ -508,7 +543,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){
 	blockdata[1] = pwd[6];
 	blockdata[2] = pwd[5];
 	blockdata[3] = pwd[4];
-	if(mifare_ultra_special_writeblock( 44, blockdata)) {
+	if(mifare_ultra_writeblock( 44, blockdata)) {
 		if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
 		OnError(44);
 		return;
@@ -518,7 +553,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){
 	blockdata[1] = pwd[2];
 	blockdata[2] = pwd[1];
 	blockdata[3] = pwd[0];
-	if(mifare_ultra_special_writeblock( 45, blockdata)) {
+	if(mifare_ultra_writeblock( 45, blockdata)) {
 		if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
 		OnError(45);
 		return;
@@ -528,7 +563,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){
 	blockdata[1] = pwd[14];
 	blockdata[2] = pwd[13];
 	blockdata[3] = pwd[12];
-	if(mifare_ultra_special_writeblock( 46, blockdata)) {
+	if(mifare_ultra_writeblock( 46, blockdata)) {
 		if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
 		OnError(46);
 		return;
@@ -538,7 +573,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){
 	blockdata[1] = pwd[10];
 	blockdata[2] = pwd[9];
 	blockdata[3] = pwd[8];
-	if(mifare_ultra_special_writeblock( 47, blockdata)) {
+	if(mifare_ultra_writeblock( 47, blockdata)) {
 		if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
 		OnError(47);
 		return;
@@ -682,7 +717,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
 		LED_B_OFF();
 	
 	}
-//  -------------------------------------------------------------------------------------------------	
+	//  -------------------------------------------------------------------------------------------------	
 	
 	LED_C_ON();
 
@@ -711,7 +746,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
 
 			// nested authentication
 			auth2_time = auth1_time + delta_time;
-			len = mifare_sendcmd_shortex(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time);
+			len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time);
 			if (len != 4) {
 				if (MF_DBGLEVEL >= 1)	Dbprintf("Nested: Auth2 error len=%d", len);
 				continue;
@@ -1231,14 +1266,12 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){
 	isOK = mifare_desfire_des_auth2(cuid, key, dataout);
 	
 	if( isOK) {
-	    if (MF_DBGLEVEL >= MF_DBG_EXTENDED) 
-			Dbprintf("Authentication part2: Failed");  
-		//OnError(4);
+		if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Authentication part2: Failed");  
+		OnError(4);
 		return;
 	}
 
-	if (MF_DBGLEVEL >= MF_DBG_EXTENDED) 
-		DbpString("AUTH 2 FINISHED");
+	if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 2 FINISHED");
 
 	cmd_send(CMD_ACK, isOK, 0, 0, dataout, sizeof(dataout));
 	FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c
index 2f84797b..8ef364c2 100644
--- a/armsrc/mifareutil.c
+++ b/armsrc/mifareutil.c
@@ -65,74 +65,25 @@ uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) {
 	return bt;
 }
 
-// send commands
-int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing)
+// send X byte basic commands
+int mifare_sendcmd(uint8_t cmd, uint8_t* data, uint8_t data_size, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing)
 {
-	return mifare_sendcmd_shortex(pcs, crypted, cmd, data, answer, answer_parity, timing);
-}
-
-int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing)
-{
-	uint8_t dcmd[8];
-    dcmd[0] = cmd;
-    dcmd[1] = data[0];
-	dcmd[2] = data[1];
-	dcmd[3] = data[2];
-	dcmd[4] = data[3];
-	dcmd[5] = data[4];
-	AppendCrc14443a(dcmd, 6);
-	ReaderTransmit(dcmd, sizeof(dcmd), NULL);
-	int len = ReaderReceive(answer, answer_parity);
-	if(!len) {
-                if (MF_DBGLEVEL >= 1)   Dbprintf("Authentication failed. Card timeout.");
-                return 2;
-    }
-	return len;
-}
-
-int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing)
-{
-    uint8_t dcmd[19];
-	int len; 
-    dcmd[0] = cmd;
-    memcpy(dcmd+1,data,16);
-	AppendCrc14443a(dcmd, 17);
-	
-	ReaderTransmit(dcmd, sizeof(dcmd), timing);
-	len = ReaderReceive(answer, answer_parity);
-	if(!len) {
-        if (MF_DBGLEVEL >= MF_DBG_ERROR)   Dbprintf("Authentication failed. Card timeout.");
-        len = ReaderReceive(answer,answer_parity);
-    }
-    if(len==1)	{
-		if (MF_DBGLEVEL >= MF_DBG_ERROR)   Dbprintf("NAK - Authentication failed.");
-		return 1;
-        }
-	return len;
-}
-
-int mifare_sendcmd_short_mfuev1auth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing)
-{
-    uint8_t dcmd[7];
-	int len; 
-    dcmd[0] = cmd;
-    memcpy(dcmd+1,data,4);
-	AppendCrc14443a(dcmd, 5);
-	
+	uint8_t dcmd[data_size+3];
+	dcmd[0] = cmd;
+	memcpy(dcmd+1,data,data_size);
+	AppendCrc14443a(dcmd, data_size+1);
 	ReaderTransmit(dcmd, sizeof(dcmd), timing);
-	len = ReaderReceive(answer, answer_parity);
+	int len = ReaderReceive(answer, answer_parity);
 	if(!len) {
-        if (MF_DBGLEVEL >= MF_DBG_ERROR)   Dbprintf("Authentication failed. Card timeout.");
-        len = ReaderReceive(answer,answer_parity);
-    }
-    if(len==1)	{
-		if (MF_DBGLEVEL >= MF_DBG_ERROR)   Dbprintf("NAK - Authentication failed.");
-		return 1;
-        }
+		if (MF_DBGLEVEL >= MF_DBG_ERROR)   Dbprintf("%02X Cmd failed. Card timeout.", cmd);
+			len = ReaderReceive(answer,answer_parity);
+		//return 0;
+	}
 	return len;
 }
 
-int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing)
+// send 2 byte commands
+int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing)
 {
 	uint8_t dcmd[4], ecmd[4];
 	uint16_t pos, res;
@@ -318,8 +269,10 @@ int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack){
 	uint8_t key[4] = {0x00};
 	memcpy(key, keybytes, 4);
 
-	Dbprintf("EV1 Auth : %02x%02x%02x%02x",	key[0], key[1], key[2], key[3]);
-	len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL);
+	if (MF_DBGLEVEL >= MF_DBG_EXTENDED)
+		Dbprintf("EV1 Auth : %02x%02x%02x%02x",	key[0], key[1], key[2], key[3]);
+	len = mifare_sendcmd(0x1B, key, sizeof(key), resp, respPar, NULL);
+	//len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL);
 	if (len != 4) {
 		if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x %u", resp[0], len);
 		return 0;
@@ -380,8 +333,8 @@ int mifare_ultra_auth(uint8_t *keybytes){
 
 	// encrypt    out, in, length, key, iv
 	tdes_2key_enc(rnd_ab, rnd_ab, sizeof(rnd_ab), key, enc_random_b);
-
-	len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL);
+	//len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL);
+	len = mifare_sendcmd(0xAF, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL);
 	if (len != 11) {
 		if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]);
 		return 0;
@@ -425,6 +378,7 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData)
 	uint8_t receivedAnswer[MAX_FRAME_SIZE];
 	uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
 	
+
 	len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL);
 	if (len == 1) {
 		if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
@@ -493,7 +447,8 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl
 	return 0;
 }
 
-int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) 
+/* // command not needed, but left for future testing
+int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) 
 {
 	uint16_t len;
 	uint8_t par[3] = {0};  // enough for 18 parity bits
@@ -501,7 +456,6 @@ int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData)
 	uint8_t receivedAnswer[MAX_FRAME_SIZE];
 	uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
 
-	// command MIFARE_CLASSIC_WRITEBLOCK
 	len = mifare_sendcmd_short(NULL, true, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL);
 
 	if ((len != 1) || (receivedAnswer[0] != 0x0A)) {   //  0x0a - ACK
@@ -524,20 +478,21 @@ int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData)
 	}
 	return 0;
 }
+*/
 
-int mifare_ultra_special_writeblock(uint8_t blockNo, uint8_t *blockData)
+int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData)
 {
 	uint16_t len;
-	uint8_t d_block[8] = {0x00};
+	uint8_t d_block[5] = {0x00};
 	uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
 	uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
 
 	// command MIFARE_CLASSIC_WRITEBLOCK
 	d_block[0]= blockNo;
 	memcpy(d_block+1,blockData,4);
-	AppendCrc14443a(d_block, 6);
+	//AppendCrc14443a(d_block, 6);
 
-	len = mifare_sendcmd_short_special(NULL, 1, 0xA2, d_block, receivedAnswer, receivedAnswerPar, NULL);
+	len = mifare_sendcmd(0xA2, d_block, sizeof(d_block), receivedAnswer, receivedAnswerPar, NULL);
 
 	if (receivedAnswer[0] != 0x0A) {   //  0x0a - ACK
 		if (MF_DBGLEVEL >= MF_DBG_ERROR)
diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h
index d4fcd818..85a34ef6 100644
--- a/armsrc/mifareutil.h
+++ b/armsrc/mifareutil.h
@@ -53,23 +53,22 @@ extern int MF_DBGLEVEL;
 #define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF();
 
 //functions
+int mifare_sendcmd(uint8_t cmd, uint8_t *data, uint8_t data_size, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);
 int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);
-int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);
-
-int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing);
-int mifare_sendcmd_short_mfuev1auth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing);
-int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);
 
+// mifare classic
 int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested);
 int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t * ntptr, uint32_t *timing);
 int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
+int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid); 
+int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
+
+// Ultralight/NTAG...
 int mifare_ul_ev1_auth(uint8_t *key, uint8_t *pack);
 int mifare_ultra_auth(uint8_t *key);
 int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData);
-int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
+//int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData);
 int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData);
-int mifare_ultra_special_writeblock(uint8_t blockNo, uint8_t *blockData);
-int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid); 
 int mifare_ultra_halt();
 
 // desfire
diff --git a/client/Makefile b/client/Makefile
index 7954d1ea..d7126da6 100644
--- a/client/Makefile
+++ b/client/Makefile
@@ -102,6 +102,7 @@ CMDSRCS = 	nonce2key/crapto1.c\
 			pm3_bitlib.c\
 			aes.c\
 			protocols.c\
+			sha1.c\
 
 
 COREOBJS = $(CORESRCS:%.c=$(OBJDIR)/%.o)
diff --git a/client/cmddata.c b/client/cmddata.c
index b9069bc1..76552351 100644
--- a/client/cmddata.c
+++ b/client/cmddata.c
@@ -55,6 +55,15 @@ int CmdSetDebugMode(const char *Cmd)
 	return 1;
 }
 
+int usage_data_printdemodbuf(){
+		PrintAndLog("Usage: data printdemodbuffer x o <offset>");
+		PrintAndLog("Options:        ");
+		PrintAndLog("       h          This help");
+		PrintAndLog("       x          output in hex (omit for binary output)");
+		PrintAndLog("       o <offset> enter offset in # of bits");
+		return 0;	
+}
+
 //by marshmellow
 void printDemodBuff(void)
 {
@@ -73,23 +82,50 @@ void printDemodBuff(void)
 
 int CmdPrintDemodBuff(const char *Cmd)
 {
-	char hex;
-	char printBuff[512]={0x00};
-	uint8_t numBits = DemodBufferLen & 0xFFFC;
-	sscanf(Cmd, "%c", &hex);
-	if (hex == 'h'){
-		PrintAndLog("Usage: data printdemodbuffer [x]");
-		PrintAndLog("Options:        ");
-		PrintAndLog("       h       This help");
-		PrintAndLog("       x       output in hex (omit for binary output)");
-		return 0;
+	char hex[512]={0x00};
+	bool hexMode = false;
+	bool errors = false;
+	uint8_t offset = 0;
+	char cmdp = 0;
+	while(param_getchar(Cmd, cmdp) != 0x00)
+	{
+		switch(param_getchar(Cmd, cmdp))
+		{
+		case 'h':
+		case 'H':
+			return usage_data_printdemodbuf();
+		case 'x':
+		case 'X':
+			hexMode = true;
+			cmdp++;
+			break;
+		case 'o':
+		case 'O':
+			offset = param_get8(Cmd, cmdp+1);
+			if (!offset) errors = true;
+			cmdp += 2;
+			break;
+		default:
+			PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
+			errors = true;
+			break;
+		}
+		if(errors) break;
 	}
-	if (hex == 'x'){
-		numBits = binarraytohex(printBuff, (char *)DemodBuffer, numBits);
+	//Validations
+	if(errors) return usage_data_printdemodbuf();
+
+	int numBits = (DemodBufferLen-offset) & 0x7FC; //make sure we don't exceed our string
+
+	if (hexMode){
+		char *buf = (char *) (DemodBuffer + offset);
+		numBits = binarraytohex(hex, buf, numBits);
 		if (numBits==0) return 0;
-		PrintAndLog("DemodBuffer: %s",printBuff);
+		PrintAndLog("DemodBuffer: %s",hex);		
 	} else {
-		printDemodBuff();
+		//setDemodBuf(DemodBuffer, DemodBufferLen-offset, offset);
+		char *bin = sprint_bin_break(DemodBuffer+offset,numBits,16);
+		PrintAndLog("DemodBuffer:\n%s",bin);
 	}
 	return 1;
 }
@@ -2182,7 +2218,7 @@ static command_t CommandTable[] =
 	{"manrawdecode",    Cmdmandecoderaw,    1, "[invert] [maxErr] -- Manchester decode binary stream in DemodBuffer"},
 	{"norm",            CmdNorm,            1, "Normalize max/min to +/-128"},
 	{"plot",            CmdPlot,            1, "Show graph window (hit 'h' in window for keystroke help)"},
-	{"printdemodbuffer",CmdPrintDemodBuff,  1, "[x] -- print the data in the DemodBuffer - 'x' for hex output"},
+	{"printdemodbuffer",CmdPrintDemodBuff,  1, "[x] [o] <offset> -- print the data in the DemodBuffer - 'x' for hex output"},
 	{"pskindalademod",  CmdIndalaDecode,    1, "[clock] [invert<0|1>] -- Demodulate an indala tag (PSK1) from GraphBuffer (args optional)"},
 	{"psknexwatchdemod",CmdPSKNexWatch,     1, "Demodulate a NexWatch tag (nexkey, quadrakey) (PSK1) from GraphBuffer"},
 	{"rawdemod",        CmdRawDemod,        1, "[modulation] ... <options> -see help (h option) -- Demodulate the data in the GraphBuffer and output binary"},  
diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c
index 19103298..5d211558 100644
--- a/client/cmdhfmfu.c
+++ b/client/cmdhfmfu.c
@@ -102,17 +102,20 @@ char *getUlev1CardSizeStr( uint8_t fsize ){
 
 static void ul_switch_on_field(void) {
 	UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
+	clearCommandBuffer();
 	SendCommand(&c);
 }
 
 void ul_switch_off_field(void) {
 	UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
+	clearCommandBuffer();
 	SendCommand(&c);
 }
 
 static int ul_send_cmd_raw( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength ) {
 	UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_APPEND_CRC, cmdlen, 0}};
 	memcpy(c.d.asBytes, cmd, cmdlen);
+	clearCommandBuffer();
 	SendCommand(&c);
 	UsbCommand resp;
 	if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return -1;
@@ -129,6 +132,7 @@ static int ul_send_cmd_raw_crc( uint8_t *cmd, uint8_t cmdlen, uint8_t *response,
 		c.arg[0] |= ISO14A_APPEND_CRC;
 
 	memcpy(c.d.asBytes, cmd, cmdlen);	
+	clearCommandBuffer();
 	SendCommand(&c);
 	UsbCommand resp;
 	if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return -1;
@@ -193,6 +197,7 @@ static int ulc_authentication( uint8_t *key, bool switch_off_field ){
 
 	UsbCommand c = {CMD_MIFAREUC_AUTH, {switch_off_field}};
 	memcpy(c.d.asBytes, key, 16);
+	clearCommandBuffer();
 	SendCommand(&c);
 	UsbCommand resp;
 	if ( !WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) return 0;
@@ -279,7 +284,7 @@ static int ul_print_default( uint8_t *data){
 	uid[6] = data[7];
 
 	PrintAndLog("       UID : %s ", sprint_hex(uid, 7));
-	PrintAndLog("    UID[0] : %02X, Manufacturer: %s",  uid[0], getTagInfo(uid[0]) );
+	PrintAndLog("    UID[0] : %02X, %s",  uid[0], getTagInfo(uid[0]) );
 	if ( uid[0] == 0x05 ) {
 		uint8_t chip = (data[8] & 0xC7); // 11000111  mask, bit 3,4,5 RFU
 		switch (chip){
@@ -839,105 +844,243 @@ int CmdHF14AMfUInfo(const char *Cmd){
 }
 
 //
-//  Mifare Ultralight Write Single Block
+//  Write Single Block
 //
 int CmdHF14AMfUWrBl(const char *Cmd){
-	uint8_t blockNo    = -1;
-	bool chinese_card  = FALSE;
-	uint8_t bldata[16] = {0x00};
-	UsbCommand resp;
 
-	char cmdp = param_getchar(Cmd, 0);
-	if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') {
-		PrintAndLog("Usage:  hf mfu wrbl <block number> <block data (8 hex symbols)> [w]");
-		PrintAndLog("       [block number]");
-		PrintAndLog("       [block data] - (8 hex symbols)");
-		PrintAndLog("       [w] - Chinese magic ultralight tag");
-		PrintAndLog("");
-		PrintAndLog("        sample: hf mfu wrbl 0 01020304");
-		PrintAndLog("");		
-		return 0;
-	}       
-	
-	blockNo = param_get8(Cmd, 0);
+	int blockNo = -1;
+	bool errors = false;
+	bool hasAuthKey = false;
+	bool hasPwdKey = false;
+	bool swapEndian = false;
 
-	if (blockNo > MAX_UL_BLOCKS){
-		PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight Cards!");
-		return 1;
+	uint8_t cmdp = 0;
+	uint8_t keylen = 0;
+	uint8_t blockdata[20] = {0x00};
+	uint8_t data[16] = {0x00};
+	uint8_t authenticationkey[16] = {0x00};
+	uint8_t *authKeyPtr = authenticationkey;
+
+	// starting with getting tagtype
+	TagTypeUL_t tagtype = GetHF14AMfU_Type();
+	if (tagtype == UL_ERROR) return -1;
+
+	while(param_getchar(Cmd, cmdp) != 0x00)
+	{
+		switch(param_getchar(Cmd, cmdp))
+		{
+			case 'h':
+			case 'H':
+				return usage_hf_mfu_wrbl();
+			case 'k':
+			case 'K':
+				// EV1/NTAG size key
+				keylen = param_gethex(Cmd, cmdp+1, data, 8);
+				if ( !keylen ) {
+					memcpy(authenticationkey, data, 4);
+					cmdp += 2;
+					hasPwdKey = true;
+					break;
+				}
+				// UL-C size key	
+				keylen = param_gethex(Cmd, cmdp+1, data, 32);
+				if (!keylen){
+					memcpy(authenticationkey, data, 16);
+					cmdp += 2;
+					hasAuthKey = true;
+					break;
+				}
+				PrintAndLog("\nERROR: Key is incorrect length\n");
+				errors = true; 
+				break;
+			case 'b':
+			case 'B':
+				blockNo = param_get8(Cmd, cmdp+1);
+				
+				uint8_t maxblockno = 0;
+				for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){
+					if (tagtype & UL_TYPES_ARRAY[idx])
+						maxblockno = UL_MEMORY_ARRAY[idx];
+				}
+		
+				if (blockNo < 0) {
+					PrintAndLog("Wrong block number");
+					errors = true;
+				}
+				if (blockNo > maxblockno){
+					PrintAndLog("block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno);
+					errors = true;
+				}
+				cmdp += 2;
+				break;
+			case 'l':
+			case 'L':
+				swapEndian = true;
+				cmdp++;	
+				break;
+			case 'd':
+			case 'D':
+				if ( param_gethex(Cmd, cmdp+1, blockdata, 8) ) {
+					PrintAndLog("Block data must include 8 HEX symbols");
+					errors = true;
+					break;
+				}
+				cmdp += 2;
+				break;
+			default:
+				PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
+				errors = true;
+				break;
+		}
+		//Validations
+		if(errors) return usage_hf_mfu_wrbl();
 	}
-	
-	if (param_gethex(Cmd, 1, bldata, 8)) {
-		PrintAndLog("Block data must include 8 HEX symbols");
-		return 1;
+
+	if ( blockNo == -1 ) return usage_hf_mfu_wrbl();
+
+	// Swap endianness 
+	if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8);
+	if (swapEndian && hasPwdKey)  authKeyPtr = SwapEndian64(authenticationkey, 4, 4);
+
+	if ( blockNo <= 3)
+		PrintAndLog("Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4));
+	else
+		PrintAndLog("Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4));
+
+	//Send write Block
+	UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}};
+	memcpy(c.d.asBytes,blockdata,4);
+
+	if ( hasAuthKey ) {
+		c.arg[1] = 1;
+		memcpy(c.d.asBytes+4,authKeyPtr,16);
 	}
-	
-	if (strchr(Cmd,'w') != 0  || strchr(Cmd,'W') != 0 ) {
-		chinese_card = TRUE; 
+	else if ( hasPwdKey ) {
+		c.arg[1] = 2;
+		memcpy(c.d.asBytes+4,authKeyPtr,4);
 	}
-	
-	if ( blockNo <= 3) {
-		if (!chinese_card){
-			PrintAndLog("Access Denied");
-		} else {
-			PrintAndLog("--specialblock no:%02x", blockNo);
-			PrintAndLog("--data: %s", sprint_hex(bldata, 4));
-			UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}};
-			memcpy(d.d.asBytes,bldata, 4);
-			SendCommand(&d);
-			if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
-				uint8_t isOK  = resp.arg[0] & 0xff;
-				PrintAndLog("isOk:%02x", isOK);
-			} else {
-				PrintAndLog("Command execute timeout");
-			}  
-		}
+
+	clearCommandBuffer();
+	SendCommand(&c);
+	UsbCommand resp;
+	if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+		uint8_t isOK  = resp.arg[0] & 0xff;
+		PrintAndLog("isOk:%02x", isOK);
 	} else {
-		PrintAndLog("--block no:%02x", blockNo);
-		PrintAndLog("--data: %s", sprint_hex(bldata, 4));        	
-		UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}};
-		memcpy(e.d.asBytes,bldata, 4);
-		SendCommand(&e);
-		if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
-			uint8_t isOK  = resp.arg[0] & 0xff;
-			PrintAndLog("isOk:%02x", isOK);
-		} else {
-			PrintAndLog("Command execute timeout");
-		}
+		PrintAndLog("Command execute timeout");
 	}
+
 	return 0;
 }
-
 //
-//  Mifare Ultralight Read Single Block
+//  Read Single Block
 //
 int CmdHF14AMfURdBl(const char *Cmd){
 
-	UsbCommand resp;
-	uint8_t blockNo = -1;	
-	char cmdp = param_getchar(Cmd, 0);
-	
-	if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') {	
-		PrintAndLog("Usage:  hf mfu rdbl <block number>");
-		PrintAndLog("        sample: hfu mfu rdbl 0");
-		return 0;
-	}
+	int blockNo = -1;	
+	bool errors = false;
+	bool hasAuthKey = false;
+	bool hasPwdKey = false;
+	bool swapEndian = false;
+	uint8_t cmdp = 0;
+	uint8_t keylen = 0;
+	uint8_t data[16] = {0x00};
+	uint8_t authenticationkey[16] = {0x00};
+	uint8_t *authKeyPtr = authenticationkey;
 
-	blockNo = param_get8(Cmd, 0);
+	// starting with getting tagtype
+	TagTypeUL_t tagtype = GetHF14AMfU_Type();
+	if (tagtype == UL_ERROR) return -1;
 
-	if (blockNo > MAX_UL_BLOCKS){
-		PrintAndLog("Error: Maximum number of blocks is 15 for Ultralight");
-		return 1;
+	while(param_getchar(Cmd, cmdp) != 0x00)
+	{
+		switch(param_getchar(Cmd, cmdp))
+		{
+			case 'h':
+			case 'H':
+				return usage_hf_mfu_rdbl();
+			case 'k':
+			case 'K':
+				// EV1/NTAG size key
+				keylen = param_gethex(Cmd, cmdp+1, data, 8);
+				if ( !keylen ) {
+					memcpy(authenticationkey, data, 4);
+					cmdp += 2;
+					hasPwdKey = true;
+					break;
+				}
+				// UL-C size key	
+				keylen = param_gethex(Cmd, cmdp+1, data, 32);
+				if (!keylen){
+					memcpy(authenticationkey, data, 16);
+					cmdp += 2;
+					hasAuthKey = true;
+					break;
+				}
+				PrintAndLog("\nERROR: Key is incorrect length\n");
+				errors = true; 
+				break;
+			case 'b':
+			case 'B':
+				blockNo = param_get8(Cmd, cmdp+1);
+
+				uint8_t maxblockno = 0;
+				for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){
+					if (tagtype & UL_TYPES_ARRAY[idx])
+						maxblockno = UL_MEMORY_ARRAY[idx];
+				}
+
+				if (blockNo < 0) {
+					PrintAndLog("Wrong block number");
+					errors = true;
+				}
+				if (blockNo > maxblockno){
+					PrintAndLog("block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno);
+					errors = true;
+				}
+				cmdp += 2;
+				break;
+			case 'l':
+			case 'L':
+				swapEndian = true;
+				cmdp++;
+				break;
+			default:
+				PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
+				errors = true;
+				break;
+		}
+		//Validations
+		if(errors) return usage_hf_mfu_rdbl();
 	}
 
-	UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}};
-	SendCommand(&c);
+	if ( blockNo == -1 ) return usage_hf_mfu_rdbl();
+
+	// Swap endianness 
+	if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8);
+	if (swapEndian && hasPwdKey)  authKeyPtr = SwapEndian64(authenticationkey, 4, 4);
 
+	//Read Block
+	UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}};
+	if ( hasAuthKey ){
+		c.arg[1] = 1;
+		memcpy(c.d.asBytes,authKeyPtr,16);
+	}
+	else if ( hasPwdKey ) {
+		c.arg[1] = 2;
+		memcpy(c.d.asBytes,authKeyPtr,4);
+	}
 
+	clearCommandBuffer();
+	SendCommand(&c);
+	UsbCommand resp;
 	if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
 		uint8_t isOK = resp.arg[0] & 0xff;
 		if (isOK) {
 			uint8_t *data = resp.d.asBytes;
-			PrintAndLog("Block: %0d (0x%02X) [ %s]", (int)blockNo, blockNo, sprint_hex(data, 4));
+			PrintAndLog("\nBlock#  | Data        | Ascii");
+			PrintAndLog("-----------------------------");
+			PrintAndLog("%02d/0x%02X | %s| %.4s\n", blockNo, blockNo, sprint_hex(data, 4), data);
 		}
 		else {
 			PrintAndLog("Failed reading block: (%02x)", isOK);
@@ -945,7 +1088,6 @@ int CmdHF14AMfURdBl(const char *Cmd){
 	} else {
 		PrintAndLog("Command execute time-out");
 	}
-
 	return 0;
 }
 
@@ -988,6 +1130,34 @@ int usage_hf_mfu_dump(void) {
 	return 0;
 }
 
+int usage_hf_mfu_rdbl(void) {
+	PrintAndLog("Read a block and print. It autodetects card type.\n");	
+	PrintAndLog("Usage:  hf mfu rdbl b <block number> k <key> l\n");
+	PrintAndLog("  Options:");
+	PrintAndLog("  b <no>  : block to read");
+	PrintAndLog("  k <key> : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]");
+	PrintAndLog("  l       : (optional) swap entered key's endianness");	
+	PrintAndLog("");
+	PrintAndLog("   sample : hf mfu rdbl b 0");
+	PrintAndLog("          : hf mfu rdbl b 0 k 00112233445566778899AABBCCDDEEFF");
+	PrintAndLog("          : hf mfu rdbl b 0 k AABBCCDDD\n");
+	return 0;
+}
+
+int usage_hf_mfu_wrbl(void) {
+	PrintAndLog("Write a block. It autodetects card type.\n");		
+	PrintAndLog("Usage:  hf mfu wrbl b <block number> d <data> k <key> l\n");
+	PrintAndLog("  Options:");
+	PrintAndLog("  b <no>   : block to write");
+	PrintAndLog("  d <data> : block data - (8 hex symbols)");
+	PrintAndLog("  k <key>  : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]");
+	PrintAndLog("  l        : (optional) swap entered key's endianness");	
+	PrintAndLog("");
+	PrintAndLog("    sample : hf mfu wrbl b 0 d 01234567");
+	PrintAndLog("           : hf mfu wrbl b 0 d 01234567 k AABBCCDDD\n");
+	return 0;
+}
+
 //
 //  Mifare Ultralight / Ultralight-C / Ultralight-EV1
 //  Read and Dump Card Contents,  using auto detection of tag size.
@@ -1079,10 +1249,10 @@ int CmdHF14AMfUDump(const char *Cmd){
 	TagTypeUL_t tagtype = GetHF14AMfU_Type();
 	if (tagtype == UL_ERROR) return -1;
 
-	if (!manualPages)
+	if (!manualPages) //get number of pages to read
 		for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++)
 			if (tagtype & UL_TYPES_ARRAY[idx])
-				Pages = UL_MEMORY_ARRAY[idx]+1;
+				Pages = UL_MEMORY_ARRAY[idx]+1; //add one as maxblks starts at 0
 
 	ul_print_type(tagtype, 0);
 	PrintAndLog("Reading tag memory...");
@@ -1095,6 +1265,8 @@ int CmdHF14AMfUDump(const char *Cmd){
 
 		memcpy(c.d.asBytes, authKeyPtr, dataLen);
 	}
+
+	clearCommandBuffer();
 	SendCommand(&c);
 	UsbCommand resp;
 	if (!WaitForResponseTimeout(CMD_ACK, &resp,1500)) {
@@ -1153,9 +1325,11 @@ int CmdHF14AMfUDump(const char *Cmd){
 		}
 	}
 
+	PrintAndLog("\nBlock#  | Data        |lck| Ascii");
+	PrintAndLog("---------------------------------");
 	for (i = 0; i < Pages; ++i) {
 		if ( i < 3 ) {
-			PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4));
+			PrintAndLog("%02d/0x%02X | %s|   | ", i+startPage, i+startPage, sprint_hex(data + i * 4, 4));
 			continue;
 		}
 		switch(i){
@@ -1202,8 +1376,9 @@ int CmdHF14AMfUDump(const char *Cmd){
 			case 43: tmplockbit = bit2[9]; break;  //auth1
 			default: break;
 		}
-		PrintAndLog("Block %02X:%s [%d] {%.4s}", i, sprint_hex(data + i * 4, 4), tmplockbit, data+i*4);
+		PrintAndLog("%02d/0x%02X | %s| %d | %.4s", i+startPage, i+startPage, sprint_hex(data + i * 4, 4), tmplockbit, data+i*4);
 	}
+	PrintAndLog("---------------------------------");
 
 	// user supplied filename?
 	if (fileNlen < 1) {
@@ -1369,142 +1544,6 @@ int CmdTestDES(const char * cmd)
 }
 **/
 
-//
-// Ultralight C Read Single Block
-//
-int CmdHF14AMfUCRdBl(const char *Cmd)
-{
-	UsbCommand resp;
-	bool hasPwd = FALSE;
-	uint8_t blockNo = -1;
-	uint8_t key[16];
-	char cmdp = param_getchar(Cmd, 0);
-
-	if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') {
-		PrintAndLog("Usage:  hf mfu crdbl  <block number> <key>");
-		PrintAndLog("");
-		PrintAndLog("sample: hf mfu crdbl 0");
-		PrintAndLog("        hf mfu crdbl 0 00112233445566778899AABBCCDDEEFF");
-		return 0;
-	}
-
-	blockNo = param_get8(Cmd, 0);
-	if (blockNo < 0) {
-		PrintAndLog("Wrong block number");
-		return 1;
-	}
-
-	if (blockNo > MAX_ULC_BLOCKS ){
-		PrintAndLog("Error: Maximum number of blocks is 47 for Ultralight-C");
-		return 1;
-	} 
-	
-	// key
-	if ( strlen(Cmd) > 3){
-		if (param_gethex(Cmd, 1, key, 32)) {
-			PrintAndLog("Key must include %d HEX symbols", 32);
-			return 1;
-		} else {
-			hasPwd = TRUE;
-		}	
-	}	
-
-	//Read Block
-	UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}};
-	if ( hasPwd ) {
-		c.arg[1] = 1;
-		memcpy(c.d.asBytes,key,16);
-	}
-	SendCommand(&c);
-
-	if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
-		uint8_t isOK = resp.arg[0] & 0xff;
-		if (isOK) {
-			uint8_t *data = resp.d.asBytes;
-			PrintAndLog("Block: %0d (0x%02X) [ %s]", (int)blockNo, blockNo, sprint_hex(data, 4));
-		}
-		else {
-			PrintAndLog("Failed reading block: (%02x)", isOK);
-		}
-	} else {
-		PrintAndLog("Command execute time-out");
-	}
-	return 0;
-}
-
-//
-//  Mifare Ultralight C Write Single Block
-//
-int CmdHF14AMfUCWrBl(const char *Cmd){
-	
-	uint8_t blockNo = -1;
-	bool chinese_card = FALSE;
-	uint8_t bldata[16] = {0x00};
-	UsbCommand resp;
-
-	char cmdp = param_getchar(Cmd, 0);
-	
-	if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') {	
-		PrintAndLog("Usage:  hf mfu cwrbl <block number> <block data (8 hex symbols)> [w]");
-		PrintAndLog("       [block number]");
-		PrintAndLog("       [block data] - (8 hex symbols)");
-		PrintAndLog("       [w] - Chinese magic ultralight tag");
-		PrintAndLog("");
-		PrintAndLog("        sample: hf mfu cwrbl 0 01020304");
-		PrintAndLog("");
-		return 0;
-	}
-	
-	blockNo = param_get8(Cmd, 0);
-	if (blockNo > MAX_ULC_BLOCKS ){
-		PrintAndLog("Error: Maximum number of blocks is 47 for Ultralight-C Cards!");
-		return 1;
-	}
-	
-	if (param_gethex(Cmd, 1, bldata, 8)) {
-		PrintAndLog("Block data must include 8 HEX symbols");
-		return 1;
-	}
-
-	if (strchr(Cmd,'w') != 0  || strchr(Cmd,'W') != 0 ) {
-		chinese_card = TRUE; 
-	}
-
-	if ( blockNo <= 3 ) {
-		if (!chinese_card){
-			PrintAndLog("Access Denied");  
-			return 1;
-		} else {
-			PrintAndLog("--Special block no: 0x%02x", blockNo);
-			PrintAndLog("--Data: %s", sprint_hex(bldata, 4));
-			UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}};
-			memcpy(d.d.asBytes,bldata, 4);
-			SendCommand(&d);
-			if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
-				uint8_t isOK  = resp.arg[0] & 0xff;
-				PrintAndLog("isOk:%02x", isOK);
-			} else {
-				PrintAndLog("Command execute timeout");
-				return 1;
-			}
-		}
-	} else {
-			PrintAndLog("--Block no : 0x%02x", blockNo);
-			PrintAndLog("--Data: %s", sprint_hex(bldata, 4));        	
-			UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}};
-			memcpy(e.d.asBytes,bldata, 4);
-			SendCommand(&e);
-			if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
-				uint8_t isOK  = resp.arg[0] & 0xff;
-				PrintAndLog("isOk : %02x", isOK);
-			} else {
-				PrintAndLog("Command execute timeout");
-				return 1;
-			}
-	}
-	return 0;
-}
-
 // 
 // Mifare Ultralight C - Set password
 //
@@ -1530,6 +1569,7 @@ int CmdHF14AMfucSetPwd(const char *Cmd){
 	
 	UsbCommand c = {CMD_MIFAREUC_SETPWD};	
 	memcpy( c.d.asBytes, pwd, 16);
+	clearCommandBuffer();
 	SendCommand(&c);
 
 	UsbCommand resp;
@@ -1578,6 +1618,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){
 	// read block2. 
 	c.cmd = CMD_MIFAREU_READBL;
 	c.arg[0] = 2;
+	clearCommandBuffer();
 	SendCommand(&c);
 	if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
 		PrintAndLog("Command execute timeout");
@@ -1595,6 +1636,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){
 	c.d.asBytes[1] = uid[1];
 	c.d.asBytes[2] = uid[2];
 	c.d.asBytes[3] =  0x88 ^ uid[0] ^ uid[1] ^ uid[2];
+	clearCommandBuffer();
 	SendCommand(&c);
 	if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
 		PrintAndLog("Command execute timeout");
@@ -1607,6 +1649,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){
 	c.d.asBytes[1] = uid[4];
 	c.d.asBytes[2] = uid[5];
 	c.d.asBytes[3] = uid[6];
+	clearCommandBuffer();
 	SendCommand(&c);
 	if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) {
 		PrintAndLog("Command execute timeout");
@@ -1619,6 +1662,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){
 	c.d.asBytes[1] = oldblock2[1];
 	c.d.asBytes[2] = oldblock2[2];
 	c.d.asBytes[3] = oldblock2[3];
+	clearCommandBuffer();
 	SendCommand(&c);
 	if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) {
 		PrintAndLog("Command execute timeout");
@@ -1629,10 +1673,10 @@ int CmdHF14AMfucSetUid(const char *Cmd){
 }
 
 int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
-	
+
 	uint8_t iv[8] = { 0x00 };
 	uint8_t block = 0x07;
-	
+
 	// UL-EV1
 	//04 57 b6 e2 05 3f 80 UID
 	//4a f8 4b 19   PWD
@@ -1646,14 +1690,14 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
 	
 	uint8_t mix[8] = { 0x00 };
 	uint8_t divkey[8] = { 0x00 };
-	
+
 	memcpy(mix, mifarekeyA, 4);
-	
+
 	mix[4] = mifarekeyA[4] ^ uid[0];
 	mix[5] = mifarekeyA[5] ^ uid[1];
 	mix[6] = block ^ uid[2];
 	mix[7] = uid[3];
-	
+
 	des3_context ctx = { 0x00 };
 	des3_set2key_enc(&ctx, masterkey);
 
@@ -1672,9 +1716,9 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
 	PrintAndLog("Mifare key   :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA)));
 	PrintAndLog("Message      :\t %s", sprint_hex(mix, sizeof(mix)));
 	PrintAndLog("Diversified key: %s", sprint_hex(divkey+1, 6));
-		
+
 	PrintAndLog("\n DES version");
-	
+
 	for (int i=0; i < sizeof(mifarekeyA); ++i){
 		dkeyA[i] = (mifarekeyA[i] << 1) & 0xff;
 		dkeyA[6] |=  ((mifarekeyA[i] >> 7) & 1) << (i+1);
@@ -1692,7 +1736,7 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){
 	memcpy(dmkey+8, dkeyB, 8);
 	memcpy(dmkey+16, dkeyA, 8);
 	memset(iv, 0x00, 8);
-	
+
 	des3_set3key_enc(&ctx, dmkey);
 
 	des3_crypt_cbc(&ctx  // des3_context
@@ -1735,11 +1779,9 @@ static command_t CommandTable[] =
 	{"help",	CmdHelp,			1, "This help"},
 	{"dbg",		CmdHF14AMfDbg,		0, "Set default debug mode"},
 	{"info",	CmdHF14AMfUInfo,	0, "Tag information"},
-	{"dump",	CmdHF14AMfUDump,	0, "Dump Ultralight / Ultralight-C tag to binary file"},
-	{"rdbl",	CmdHF14AMfURdBl,	0, "Read block  - Ultralight"},
-	{"wrbl",	CmdHF14AMfUWrBl,	0, "Write block - Ultralight"},    
-	{"crdbl",	CmdHF14AMfUCRdBl,	0, "Read block        - Ultralight C"},
-	{"cwrbl",	CmdHF14AMfUCWrBl,	0, "Write block       - Ultralight C"},
+	{"dump",	CmdHF14AMfUDump,	0, "Dump Ultralight / Ultralight-C / NTAG tag to binary file"},
+	{"rdbl",	CmdHF14AMfURdBl,	0, "Read block"},
+	{"wrbl",	CmdHF14AMfUWrBl,	0, "Write block"},
 	{"cauth",	CmdHF14AMfucAuth,	0, "Authentication    - Ultralight C"},
 	{"setpwd",	CmdHF14AMfucSetPwd, 1, "Set 3des password - Ultralight-C"},
 	{"setuid",	CmdHF14AMfucSetUid, 1, "Set UID - MAGIC tags only"},
diff --git a/client/cmdhfmfu.h b/client/cmdhfmfu.h
index 83f28403..4ec48ff9 100644
--- a/client/cmdhfmfu.h
+++ b/client/cmdhfmfu.h
@@ -4,25 +4,24 @@
 #ifndef CMDHFMFU_H__
 #define CMDHFMFU_H__
 
-//standard ultralight
 int CmdHF14AMfUWrBl(const char *Cmd);
 int CmdHF14AMfURdBl(const char *Cmd);
 
 //Crypto Cards
-int CmdHF14AMfUCRdBl(const char *Cmd);
-int CmdHF14AMfUCRdCard(const char *Cmd);
 int CmdHF14AMfucAuth(const char *Cmd);
 
 //general stuff
 int CmdHF14AMfUDump(const char *Cmd);
 int CmdHF14AMfUInfo(const char *Cmd);
-uint32_t GetHF14AMfU_Type(void);
 
+uint32_t GetHF14AMfU_Type(void);
 int ul_print_type(uint32_t tagtype, uint8_t spacer);
 void ul_switch_off_field(void);
 
 int usage_hf_mfu_dump(void);
 int usage_hf_mfu_info(void);
+int usage_hf_mfu_rdbl(void);
+int usage_hf_mfu_wrbl(void);
 
 int CmdHFMFUltra(const char *Cmd);
 
diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c
index d4b72b32..b357e71c 100644
--- a/client/cmdlft55xx.c
+++ b/client/cmdlft55xx.c
@@ -50,24 +50,24 @@ int usage_t55xx_config(){
 }
 int usage_t55xx_read(){
 	PrintAndLog("Usage:  lf t55xx read <block> <password>");
-    PrintAndLog("     <block>, block number to read. Between 0-7");
-    PrintAndLog("     <password>, OPTIONAL password (8 hex characters)");
-    PrintAndLog("");
+	PrintAndLog("     <block>, block number to read. Between 0-7");
+	PrintAndLog("     <password>, OPTIONAL password (8 hex characters)");
+	PrintAndLog("");
 	PrintAndLog("Examples:");
-    PrintAndLog("      lf t55xx read 0           - read data from block 0");
+	PrintAndLog("      lf t55xx read 0           - read data from block 0");
 	PrintAndLog("      lf t55xx read 0 feedbeef  - read data from block 0 password feedbeef");
 	PrintAndLog("");
 	return 0;
 }
 int usage_t55xx_write(){
 	PrintAndLog("Usage:  lf t55xx wr <block> <data> [password]");
-    PrintAndLog("     <block>, block number to read. Between 0-7");
+	PrintAndLog("     <block>, block number to write. Between 0-7");
 	PrintAndLog("     <data>,  4 bytes of data to write (8 hex characters)");
-    PrintAndLog("     [password], OPTIONAL password 4bytes (8 hex characters)");
-    PrintAndLog("");
+	PrintAndLog("     [password], OPTIONAL password 4bytes (8 hex characters)");
+	PrintAndLog("");
 	PrintAndLog("Examples:");
-    PrintAndLog("      lf t55xx wd 3 11223344           - write 11223344 to block 3");
-	PrintAndLog("      lf t55xx wd 3 11223344 feedbeef  - write 11223344 to block 3 password feedbeef");
+	PrintAndLog("      lf t55xx wr 3 11223344           - write 11223344 to block 3");
+	PrintAndLog("      lf t55xx wr 3 11223344 feedbeef  - write 11223344 to block 3 password feedbeef");
 	PrintAndLog("");
 	return 0;
 }
diff --git a/client/lualibs/utils.lua b/client/lualibs/utils.lua
index a968fde2..592d0477 100644
--- a/client/lualibs/utils.lua
+++ b/client/lualibs/utils.lua
@@ -99,6 +99,32 @@ local Utils =
 		end
 		return nil
 	end,
+
+	------------ SHA1 hash
+	-- Takes a string and calculates a SHA1 hash
+	Sha1 = function(s)
+		if s == nil then return nil end
+		if #s == 0 then return nil end
+		if  type(s) == 'string' then
+			local utils = require('utils')
+			--local asc = utils.ConvertHexToAscii(s)
+			local hash = core.sha1(s)
+			return hash
+		end
+		return nil
+	end,
+	-- Takes a hex string and calculates a SHA1 hash
+	Sha1Hex = function(s)
+		if s == nil then return nil end
+		if #s == 0 then return nil end
+		if  type(s) == 'string' then
+			local utils = require('utils')
+			local asc = utils.ConvertHexToAscii(s)
+			local hash = core.sha1(asc)
+			return hash
+		end
+		return nil
+	end,
 	
 	
 	-- input parameter is a string
@@ -288,4 +314,4 @@ local Utils =
 -- end
 
 }
-return Utils
\ No newline at end of file
+return Utils
diff --git a/client/scripting.c b/client/scripting.c
index 152fd9d4..6b26ec59 100644
--- a/client/scripting.c
+++ b/client/scripting.c
@@ -20,6 +20,7 @@
 #include "../common/iso15693tools.h"
 #include "../common/crc16.h"
 #include "../common/crc64.h"
+#include "../common/sha1.h"
 #include "aes.h"
 /**
  * The following params expected:
@@ -231,7 +232,7 @@ static int l_iso15693_crc(lua_State *L)
  Simple AES 128 cbc hook up to OpenSSL.
  params:  key, input
 */
-static int l_aes128decrypt(lua_State *L)
+static int l_aes128decrypt_cbc(lua_State *L)
 {
 	//Check number of arguments
 	int i;
@@ -260,7 +261,36 @@ static int l_aes128decrypt(lua_State *L)
 	lua_pushlstring(L,(const char *)&outdata, sizeof(outdata));
 	return 1;// return 1 to signal one return value
 }
-static int l_aes128encrypt(lua_State *L)
+static int l_aes128decrypt_ecb(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[16] = {0x00};
+	unsigned char outdata[16] = {0x00};
+	unsigned char aes_key[16] = {0x00};
+
+	// convert key to bytearray and convert input to bytearray
+	for (i = 0; i < 32; i += 2) {
+		sscanf(&p_encTxt[i], "%02x", (unsigned int *)&indata[i / 2]);
+		sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]);
+	}
+	aes_context ctx;
+	aes_init(&ctx);
+	aes_setkey_dec(&ctx, aes_key, 128);
+	aes_crypt_ecb(&ctx, AES_DECRYPT, indata, outdata );
+
+	//Push decrypted array as a string
+	lua_pushlstring(L,(const char *)&outdata, sizeof(outdata));
+	return 1;// return 1 to signal one return value
+}
+
+static int l_aes128encrypt_cbc(lua_State *L)
 {
 	//Check number of arguments
 	int i;
@@ -289,6 +319,33 @@ static int l_aes128encrypt(lua_State *L)
 	return 1;// return 1 to signal one return value
 }
 
+static int l_aes128encrypt_ecb(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_txt = luaL_checklstring(L, 2, &size);
+
+	unsigned char indata[16] = {0x00};
+	unsigned char outdata[16] = {0x00};
+	unsigned char aes_key[16] = {0x00};
+
+	for (i = 0; i < 32; i += 2) {
+		sscanf(&p_txt[i], "%02x", (unsigned int *)&indata[i / 2]);
+		sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]);
+	}
+	aes_context ctx;
+	aes_init(&ctx);
+	aes_setkey_enc(&ctx, aes_key, 128);
+	aes_crypt_ecb(&ctx, AES_ENCRYPT, indata, outdata );
+	//Push encrypted array as a string
+	lua_pushlstring(L,(const char *)&outdata, sizeof(outdata));
+	return 1;// return 1 to signal one return value
+}
+
 static int l_crc16(lua_State *L)
 {
 	size_t size;
@@ -321,6 +378,16 @@ static int l_crc64(lua_State *L)
 	return 1;
 }
 
+static int l_sha1(lua_State *L)
+{
+	size_t size;
+	const char *p_str = luaL_checklstring(L, 1, &size);
+	unsigned char outdata[20] = {0x00};
+	sha1( (uint8_t*) p_str, size, outdata);
+	lua_pushlstring(L,(const char *)&outdata, sizeof(outdata));
+	return 1;
+}
+
 /**
  * @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.
@@ -359,10 +426,13 @@ int set_pm3_libraries(lua_State *L)
 		{"clearCommandBuffer",          l_clearCommandBuffer},
 		{"console",                     l_CmdConsole},
 		{"iso15693_crc",                l_iso15693_crc},
-		{"aes128_decrypt",              l_aes128decrypt},
-		{"aes128_encrypt",              l_aes128encrypt},
+		{"aes128_decrypt",              l_aes128decrypt_cbc},
+		{"aes128_decrypt_ecb",          l_aes128decrypt_ecb},
+		{"aes128_encrypt",              l_aes128encrypt_cbc},
+		{"aes128_encrypt_ecb",          l_aes128encrypt_ecb},
 		{"crc16",                       l_crc16},
 		{"crc64",                       l_crc64},
+		{"sha1",                        l_sha1},
 		{NULL, NULL}
 	};
 
diff --git a/client/scripts/dumptoemul.lua b/client/scripts/dumptoemul.lua
index f9b71509..f8cc11d4 100644
--- a/client/scripts/dumptoemul.lua
+++ b/client/scripts/dumptoemul.lua
@@ -73,7 +73,8 @@ local function convert_to_emulform(hexdata)
 	for i = 1, string.len(hexdata),32 do
 		ascii = ascii  ..string.sub(hexdata,i,i+31).."\n"
 	end
-	return ascii
+	
+	return string.sub(ascii,1,-1)
 end
 
 local function main(args)
diff --git a/client/util.c b/client/util.c
index cea9f7d7..9f2142c6 100644
--- a/client/util.c
+++ b/client/util.c
@@ -108,12 +108,12 @@ void print_hex(const uint8_t * data, const size_t len)
 	printf("\n");
 }
 
-char * sprint_hex(const uint8_t * data, const size_t len) {
+char *sprint_hex(const uint8_t *data, const size_t len) {
 	
 	int maxLen = ( len > 1024/3) ? 1024/3 : len;
 	static char buf[1024];
 	memset(buf, 0x00, 1024);
-	char * tmp = buf;
+	char *tmp = buf;
 	size_t i;
 
 	for (i=0; i < maxLen; ++i, tmp += 3)
@@ -394,7 +394,7 @@ int hextobinstring(char *target, char *source)
 
 // convert binary array of 0x00/0x01 values to hex (safe to do in place as target will always be shorter than source)
 // return number of bits converted
-int binarraytohex(char *target, char *source, int length)
+int binarraytohex(char *target,char *source, int length)
 {
     unsigned char i, x;
     int j = length;
@@ -444,3 +444,12 @@ void wiegand_add_parity(char *target, char *source, char length)
     target += length;
     *(target)= GetParity(source + length / 2, ODD, length / 2);
 }
+
+void xor(unsigned char *dst, unsigned char *src, size_t len) {
+   for( ; len > 0; len--,dst++,src++)
+       *dst ^= *src;
+}
+
+int32_t le24toh (uint8_t data[3]) {
+    return (data[2] << 16) | (data[1] << 8) | data[0];
+}
diff --git a/client/util.h b/client/util.h
index f58f64cb..2d2beaf4 100644
--- a/client/util.h
+++ b/client/util.h
@@ -63,3 +63,5 @@ void binarraytobinstring(char *target,  char *source,  int length);
 uint8_t GetParity( char *string, uint8_t type,  int length);
 void wiegand_add_parity(char *target, char *source, char length);
 
+void xor(unsigned char *dst, unsigned char *src, size_t len);
+int32_t le24toh(uint8_t data[3]);
diff --git a/common/sha1.c b/common/sha1.c
new file mode 100644
index 00000000..d20c54a4
--- /dev/null
+++ b/common/sha1.c
@@ -0,0 +1,665 @@
+/*
+ *  FIPS-180-1 compliant SHA-1 implementation
+ *
+ *  Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
+ *  This file is part of mbed TLS (https://tls.mbed.org)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  The SHA-1 standard was published by NIST in 1993.
+ *
+ *  http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ */
+
+#if !defined(POLARSSL_CONFIG_FILE)
+//#include "polarssl/config.h"
+#define POLARSSL_SHA1_C
+
+#else
+#include POLARSSL_CONFIG_FILE
+#endif
+
+#if defined(POLARSSL_SHA1_C)
+
+#include "sha1.h"
+
+#include <string.h>
+
+#if defined(POLARSSL_FS_IO)
+#include <stdio.h>
+#endif
+
+#if defined(POLARSSL_SELF_TEST)
+#if defined(POLARSSL_PLATFORM_C)
+#include "polarssl/platform.h"
+#else
+#include <stdio.h>
+#define polarssl_printf printf
+#endif /* POLARSSL_PLATFORM_C */
+#endif /* POLARSSL_SELF_TEST */
+
+/* Implementation that should never be optimized out by the compiler */
+static void polarssl_zeroize( void *v, size_t n ) {
+    volatile unsigned char *p = v; while( n-- ) *p++ = 0;
+}
+
+#if !defined(POLARSSL_SHA1_ALT)
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i)                            \
+{                                                       \
+    (n) = ( (uint32_t) (b)[(i)    ] << 24 )             \
+        | ( (uint32_t) (b)[(i) + 1] << 16 )             \
+        | ( (uint32_t) (b)[(i) + 2] <<  8 )             \
+        | ( (uint32_t) (b)[(i) + 3]       );            \
+}
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i)                            \
+{                                                       \
+    (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+    (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+    (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+    (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+void sha1_init( sha1_context *ctx )
+{
+    memset( ctx, 0, sizeof( sha1_context ) );
+}
+
+void sha1_free( sha1_context *ctx )
+{
+    if( ctx == NULL )
+        return;
+
+    polarssl_zeroize( ctx, sizeof( sha1_context ) );
+}
+
+/*
+ * SHA-1 context setup
+ */
+void sha1_starts( sha1_context *ctx )
+{
+    ctx->total[0] = 0;
+    ctx->total[1] = 0;
+
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+}
+
+void sha1_process( sha1_context *ctx, const unsigned char data[64] )
+{
+    uint32_t temp, W[16], A, B, C, D, E;
+
+    GET_UINT32_BE( W[ 0], data,  0 );
+    GET_UINT32_BE( W[ 1], data,  4 );
+    GET_UINT32_BE( W[ 2], data,  8 );
+    GET_UINT32_BE( W[ 3], data, 12 );
+    GET_UINT32_BE( W[ 4], data, 16 );
+    GET_UINT32_BE( W[ 5], data, 20 );
+    GET_UINT32_BE( W[ 6], data, 24 );
+    GET_UINT32_BE( W[ 7], data, 28 );
+    GET_UINT32_BE( W[ 8], data, 32 );
+    GET_UINT32_BE( W[ 9], data, 36 );
+    GET_UINT32_BE( W[10], data, 40 );
+    GET_UINT32_BE( W[11], data, 44 );
+    GET_UINT32_BE( W[12], data, 48 );
+    GET_UINT32_BE( W[13], data, 52 );
+    GET_UINT32_BE( W[14], data, 56 );
+    GET_UINT32_BE( W[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t)                                            \
+(                                                       \
+    temp = W[( t -  3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \
+           W[( t - 14 ) & 0x0F] ^ W[  t       & 0x0F],  \
+    ( W[t & 0x0F] = S(temp,1) )                         \
+)
+
+#define P(a,b,c,d,e,x)                                  \
+{                                                       \
+    e += S(a,5) + F(b,c,d) + K + x; b = S(b,30);        \
+}
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+    P( A, B, C, D, E, W[0]  );
+    P( E, A, B, C, D, W[1]  );
+    P( D, E, A, B, C, W[2]  );
+    P( C, D, E, A, B, W[3]  );
+    P( B, C, D, E, A, W[4]  );
+    P( A, B, C, D, E, W[5]  );
+    P( E, A, B, C, D, W[6]  );
+    P( D, E, A, B, C, W[7]  );
+    P( C, D, E, A, B, W[8]  );
+    P( B, C, D, E, A, W[9]  );
+    P( A, B, C, D, E, W[10] );
+    P( E, A, B, C, D, W[11] );
+    P( D, E, A, B, C, W[12] );
+    P( C, D, E, A, B, W[13] );
+    P( B, C, D, E, A, W[14] );
+    P( A, B, C, D, E, W[15] );
+    P( E, A, B, C, D, R(16) );
+    P( D, E, A, B, C, R(17) );
+    P( C, D, E, A, B, R(18) );
+    P( B, C, D, E, A, R(19) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+    P( A, B, C, D, E, R(20) );
+    P( E, A, B, C, D, R(21) );
+    P( D, E, A, B, C, R(22) );
+    P( C, D, E, A, B, R(23) );
+    P( B, C, D, E, A, R(24) );
+    P( A, B, C, D, E, R(25) );
+    P( E, A, B, C, D, R(26) );
+    P( D, E, A, B, C, R(27) );
+    P( C, D, E, A, B, R(28) );
+    P( B, C, D, E, A, R(29) );
+    P( A, B, C, D, E, R(30) );
+    P( E, A, B, C, D, R(31) );
+    P( D, E, A, B, C, R(32) );
+    P( C, D, E, A, B, R(33) );
+    P( B, C, D, E, A, R(34) );
+    P( A, B, C, D, E, R(35) );
+    P( E, A, B, C, D, R(36) );
+    P( D, E, A, B, C, R(37) );
+    P( C, D, E, A, B, R(38) );
+    P( B, C, D, E, A, R(39) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+    P( A, B, C, D, E, R(40) );
+    P( E, A, B, C, D, R(41) );
+    P( D, E, A, B, C, R(42) );
+    P( C, D, E, A, B, R(43) );
+    P( B, C, D, E, A, R(44) );
+    P( A, B, C, D, E, R(45) );
+    P( E, A, B, C, D, R(46) );
+    P( D, E, A, B, C, R(47) );
+    P( C, D, E, A, B, R(48) );
+    P( B, C, D, E, A, R(49) );
+    P( A, B, C, D, E, R(50) );
+    P( E, A, B, C, D, R(51) );
+    P( D, E, A, B, C, R(52) );
+    P( C, D, E, A, B, R(53) );
+    P( B, C, D, E, A, R(54) );
+    P( A, B, C, D, E, R(55) );
+    P( E, A, B, C, D, R(56) );
+    P( D, E, A, B, C, R(57) );
+    P( C, D, E, A, B, R(58) );
+    P( B, C, D, E, A, R(59) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+    P( A, B, C, D, E, R(60) );
+    P( E, A, B, C, D, R(61) );
+    P( D, E, A, B, C, R(62) );
+    P( C, D, E, A, B, R(63) );
+    P( B, C, D, E, A, R(64) );
+    P( A, B, C, D, E, R(65) );
+    P( E, A, B, C, D, R(66) );
+    P( D, E, A, B, C, R(67) );
+    P( C, D, E, A, B, R(68) );
+    P( B, C, D, E, A, R(69) );
+    P( A, B, C, D, E, R(70) );
+    P( E, A, B, C, D, R(71) );
+    P( D, E, A, B, C, R(72) );
+    P( C, D, E, A, B, R(73) );
+    P( B, C, D, E, A, R(74) );
+    P( A, B, C, D, E, R(75) );
+    P( E, A, B, C, D, R(76) );
+    P( D, E, A, B, C, R(77) );
+    P( C, D, E, A, B, R(78) );
+    P( B, C, D, E, A, R(79) );
+
+#undef K
+#undef F
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+/*
+ * SHA-1 process buffer
+ */
+void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen )
+{
+    size_t fill;
+    uint32_t left;
+
+    if( ilen == 0 )
+        return;
+
+    left = ctx->total[0] & 0x3F;
+    fill = 64 - left;
+
+    ctx->total[0] += (uint32_t) ilen;
+    ctx->total[0] &= 0xFFFFFFFF;
+
+    if( ctx->total[0] < (uint32_t) ilen )
+        ctx->total[1]++;
+
+    if( left && ilen >= fill )
+    {
+        memcpy( (void *) (ctx->buffer + left), input, fill );
+        sha1_process( ctx, ctx->buffer );
+        input += fill;
+        ilen  -= fill;
+        left = 0;
+    }
+
+    while( ilen >= 64 )
+    {
+        sha1_process( ctx, input );
+        input += 64;
+        ilen  -= 64;
+    }
+
+    if( ilen > 0 )
+        memcpy( (void *) (ctx->buffer + left), input, ilen );
+}
+
+static const unsigned char sha1_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-1 final digest
+ */
+void sha1_finish( sha1_context *ctx, unsigned char output[20] )
+{
+    uint32_t last, padn;
+    uint32_t high, low;
+    unsigned char msglen[8];
+
+    high = ( ctx->total[0] >> 29 )
+         | ( ctx->total[1] <<  3 );
+    low  = ( ctx->total[0] <<  3 );
+
+    PUT_UINT32_BE( high, msglen, 0 );
+    PUT_UINT32_BE( low,  msglen, 4 );
+
+    last = ctx->total[0] & 0x3F;
+    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+    sha1_update( ctx, sha1_padding, padn );
+    sha1_update( ctx, msglen, 8 );
+
+    PUT_UINT32_BE( ctx->state[0], output,  0 );
+    PUT_UINT32_BE( ctx->state[1], output,  4 );
+    PUT_UINT32_BE( ctx->state[2], output,  8 );
+    PUT_UINT32_BE( ctx->state[3], output, 12 );
+    PUT_UINT32_BE( ctx->state[4], output, 16 );
+}
+
+#endif /* !POLARSSL_SHA1_ALT */
+
+/*
+ * output = SHA-1( input buffer )
+ */
+void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] )
+{
+    sha1_context ctx;
+
+    sha1_init( &ctx );
+    sha1_starts( &ctx );
+    sha1_update( &ctx, input, ilen );
+    sha1_finish( &ctx, output );
+    sha1_free( &ctx );
+}
+
+#if defined(POLARSSL_FS_IO)
+/*
+ * output = SHA-1( file contents )
+ */
+int sha1_file( const char *path, unsigned char output[20] )
+{
+    FILE *f;
+    size_t n;
+    sha1_context ctx;
+    unsigned char buf[1024];
+
+    if( ( f = fopen( path, "rb" ) ) == NULL )
+        return( POLARSSL_ERR_SHA1_FILE_IO_ERROR );
+
+    sha1_init( &ctx );
+    sha1_starts( &ctx );
+
+    while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+        sha1_update( &ctx, buf, n );
+
+    sha1_finish( &ctx, output );
+    sha1_free( &ctx );
+
+    if( ferror( f ) != 0 )
+    {
+        fclose( f );
+        return( POLARSSL_ERR_SHA1_FILE_IO_ERROR );
+    }
+
+    fclose( f );
+    return( 0 );
+}
+#endif /* POLARSSL_FS_IO */
+
+/*
+ * SHA-1 HMAC context setup
+ */
+void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key,
+                       size_t keylen )
+{
+    size_t i;
+    unsigned char sum[20];
+
+    if( keylen > 64 )
+    {
+        sha1( key, keylen, sum );
+        keylen = 20;
+        key = sum;
+    }
+
+    memset( ctx->ipad, 0x36, 64 );
+    memset( ctx->opad, 0x5C, 64 );
+
+    for( i = 0; i < keylen; i++ )
+    {
+        ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
+        ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
+    }
+
+    sha1_starts( ctx );
+    sha1_update( ctx, ctx->ipad, 64 );
+
+    polarssl_zeroize( sum, sizeof( sum ) );
+}
+
+/*
+ * SHA-1 HMAC process buffer
+ */
+void sha1_hmac_update( sha1_context *ctx, const unsigned char *input,
+                       size_t ilen )
+{
+    sha1_update( ctx, input, ilen );
+}
+
+/*
+ * SHA-1 HMAC final digest
+ */
+void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] )
+{
+    unsigned char tmpbuf[20];
+
+    sha1_finish( ctx, tmpbuf );
+    sha1_starts( ctx );
+    sha1_update( ctx, ctx->opad, 64 );
+    sha1_update( ctx, tmpbuf, 20 );
+    sha1_finish( ctx, output );
+
+    polarssl_zeroize( tmpbuf, sizeof( tmpbuf ) );
+}
+
+/*
+ * SHA1 HMAC context reset
+ */
+void sha1_hmac_reset( sha1_context *ctx )
+{
+    sha1_starts( ctx );
+    sha1_update( ctx, ctx->ipad, 64 );
+}
+
+/*
+ * output = HMAC-SHA-1( hmac key, input buffer )
+ */
+void sha1_hmac( const unsigned char *key, size_t keylen,
+                const unsigned char *input, size_t ilen,
+                unsigned char output[20] )
+{
+    sha1_context ctx;
+
+    sha1_init( &ctx );
+    sha1_hmac_starts( &ctx, key, keylen );
+    sha1_hmac_update( &ctx, input, ilen );
+    sha1_hmac_finish( &ctx, output );
+    sha1_free( &ctx );
+}
+
+#if defined(POLARSSL_SELF_TEST)
+/*
+ * FIPS-180-1 test vectors
+ */
+static const unsigned char sha1_test_buf[3][57] =
+{
+    { "abc" },
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+    { "" }
+};
+
+static const int sha1_test_buflen[3] =
+{
+    3, 56, 1000
+};
+
+static const unsigned char sha1_test_sum[3][20] =
+{
+    { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E,
+      0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D },
+    { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE,
+      0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 },
+    { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E,
+      0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F }
+};
+
+/*
+ * RFC 2202 test vectors
+ */
+static const unsigned char sha1_hmac_test_key[7][26] =
+{
+    { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
+      "\x0B\x0B\x0B\x0B" },
+    { "Jefe" },
+    { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+      "\xAA\xAA\xAA\xAA" },
+    { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
+      "\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
+    { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
+      "\x0C\x0C\x0C\x0C" },
+    { "" }, /* 0xAA 80 times */
+    { "" }
+};
+
+static const int sha1_hmac_test_keylen[7] =
+{
+    20, 4, 20, 25, 20, 80, 80
+};
+
+static const unsigned char sha1_hmac_test_buf[7][74] =
+{
+    { "Hi There" },
+    { "what do ya want for nothing?" },
+    { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
+    { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
+    { "Test With Truncation" },
+    { "Test Using Larger Than Block-Size Key - Hash Key First" },
+    { "Test Using Larger Than Block-Size Key and Larger"
+      " Than One Block-Size Data" }
+};
+
+static const int sha1_hmac_test_buflen[7] =
+{
+    8, 28, 50, 50, 20, 54, 73
+};
+
+static const unsigned char sha1_hmac_test_sum[7][20] =
+{
+    { 0xB6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xE2, 0x8B,
+      0xC0, 0xB6, 0xFB, 0x37, 0x8C, 0x8E, 0xF1, 0x46, 0xBE, 0x00 },
+    { 0xEF, 0xFC, 0xDF, 0x6A, 0xE5, 0xEB, 0x2F, 0xA2, 0xD2, 0x74,
+      0x16, 0xD5, 0xF1, 0x84, 0xDF, 0x9C, 0x25, 0x9A, 0x7C, 0x79 },
+    { 0x12, 0x5D, 0x73, 0x42, 0xB9, 0xAC, 0x11, 0xCD, 0x91, 0xA3,
+      0x9A, 0xF4, 0x8A, 0xA1, 0x7B, 0x4F, 0x63, 0xF1, 0x75, 0xD3 },
+    { 0x4C, 0x90, 0x07, 0xF4, 0x02, 0x62, 0x50, 0xC6, 0xBC, 0x84,
+      0x14, 0xF9, 0xBF, 0x50, 0xC8, 0x6C, 0x2D, 0x72, 0x35, 0xDA },
+    { 0x4C, 0x1A, 0x03, 0x42, 0x4B, 0x55, 0xE0, 0x7F, 0xE7, 0xF2,
+      0x7B, 0xE1 },
+    { 0xAA, 0x4A, 0xE5, 0xE1, 0x52, 0x72, 0xD0, 0x0E, 0x95, 0x70,
+      0x56, 0x37, 0xCE, 0x8A, 0x3B, 0x55, 0xED, 0x40, 0x21, 0x12 },
+    { 0xE8, 0xE9, 0x9D, 0x0F, 0x45, 0x23, 0x7D, 0x78, 0x6D, 0x6B,
+      0xBA, 0xA7, 0x96, 0x5C, 0x78, 0x08, 0xBB, 0xFF, 0x1A, 0x91 }
+};
+
+/*
+ * Checkup routine
+ */
+int sha1_self_test( int verbose )
+{
+    int i, j, buflen, ret = 0;
+    unsigned char buf[1024];
+    unsigned char sha1sum[20];
+    sha1_context ctx;
+
+    sha1_init( &ctx );
+
+    /*
+     * SHA-1
+     */
+    for( i = 0; i < 3; i++ )
+    {
+        if( verbose != 0 )
+            polarssl_printf( "  SHA-1 test #%d: ", i + 1 );
+
+        sha1_starts( &ctx );
+
+        if( i == 2 )
+        {
+            memset( buf, 'a', buflen = 1000 );
+
+            for( j = 0; j < 1000; j++ )
+                sha1_update( &ctx, buf, buflen );
+        }
+        else
+            sha1_update( &ctx, sha1_test_buf[i],
+                               sha1_test_buflen[i] );
+
+        sha1_finish( &ctx, sha1sum );
+
+        if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 )
+        {
+            if( verbose != 0 )
+                polarssl_printf( "failed\n" );
+
+            ret = 1;
+            goto exit;
+        }
+
+        if( verbose != 0 )
+            polarssl_printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        polarssl_printf( "\n" );
+
+    for( i = 0; i < 7; i++ )
+    {
+        if( verbose != 0 )
+            polarssl_printf( "  HMAC-SHA-1 test #%d: ", i + 1 );
+
+        if( i == 5 || i == 6 )
+        {
+            memset( buf, 0xAA, buflen = 80 );
+            sha1_hmac_starts( &ctx, buf, buflen );
+        }
+        else
+            sha1_hmac_starts( &ctx, sha1_hmac_test_key[i],
+                                    sha1_hmac_test_keylen[i] );
+
+        sha1_hmac_update( &ctx, sha1_hmac_test_buf[i],
+                                sha1_hmac_test_buflen[i] );
+
+        sha1_hmac_finish( &ctx, sha1sum );
+
+        buflen = ( i == 4 ) ? 12 : 20;
+
+        if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 )
+        {
+            if( verbose != 0 )
+                polarssl_printf( "failed\n" );
+
+            ret = 1;
+            goto exit;
+        }
+
+        if( verbose != 0 )
+            polarssl_printf( "passed\n" );
+    }
+
+    if( verbose != 0 )
+        polarssl_printf( "\n" );
+
+exit:
+    sha1_free( &ctx );
+
+    return( ret );
+}
+
+#endif /* POLARSSL_SELF_TEST */
+
+#endif /* POLARSSL_SHA1_C */
+
diff --git a/common/sha1.h b/common/sha1.h
new file mode 100644
index 00000000..056bba7e
--- /dev/null
+++ b/common/sha1.h
@@ -0,0 +1,213 @@
+/**
+ * \file sha1.h
+ *
+ * \brief SHA-1 cryptographic hash function
+ *
+ *  Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
+ *
+ *  This file is part of mbed TLS (https://tls.mbed.org)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef POLARSSL_SHA1_H
+#define POLARSSL_SHA1_H
+
+#if !defined(POLARSSL_CONFIG_FILE)
+//#include "config.h"
+/**
+ * \def POLARSSL_SHA1_C
+ *
+ * Enable the SHA1 cryptographic hash algorithm.
+ *
+ * Module:  library/sha1.c
+ * Caller:  library/md.c
+ *          library/ssl_cli.c
+ *          library/ssl_srv.c
+ *          library/ssl_tls.c
+ *          library/x509write_crt.c
+ *
+ * This module is required for SSL/TLS and SHA1-signed certificates.
+ */
+#define POLARSSL_SHA1_C
+
+#else
+#include POLARSSL_CONFIG_FILE
+#endif
+
+#include <stddef.h>
+
+#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
+#include <basetsd.h>
+typedef UINT32 uint32_t;
+#else
+#include <inttypes.h>
+#endif
+
+#define POLARSSL_ERR_SHA1_FILE_IO_ERROR                -0x0076  /**< Read/write error in file. */
+
+#if !defined(POLARSSL_SHA1_ALT)
+// Regular implementation
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          SHA-1 context structure
+ */
+typedef struct
+{
+    uint32_t total[2];          /*!< number of bytes processed  */
+    uint32_t state[5];          /*!< intermediate digest state  */
+    unsigned char buffer[64];   /*!< data block being processed */
+
+    unsigned char ipad[64];     /*!< HMAC: inner padding        */
+    unsigned char opad[64];     /*!< HMAC: outer padding        */
+}
+sha1_context;
+
+/**
+ * \brief          Initialize SHA-1 context
+ *
+ * \param ctx      SHA-1 context to be initialized
+ */
+void sha1_init( sha1_context *ctx );
+
+/**
+ * \brief          Clear SHA-1 context
+ *
+ * \param ctx      SHA-1 context to be cleared
+ */
+void sha1_free( sha1_context *ctx );
+
+/**
+ * \brief          SHA-1 context setup
+ *
+ * \param ctx      context to be initialized
+ */
+void sha1_starts( sha1_context *ctx );
+
+/**
+ * \brief          SHA-1 process buffer
+ *
+ * \param ctx      SHA-1 context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen );
+
+/**
+ * \brief          SHA-1 final digest
+ *
+ * \param ctx      SHA-1 context
+ * \param output   SHA-1 checksum result
+ */
+void sha1_finish( sha1_context *ctx, unsigned char output[20] );
+
+/* Internal use */
+void sha1_process( sha1_context *ctx, const unsigned char data[64] );
+
+#ifdef __cplusplus
+}
+#endif
+
+#else  /* POLARSSL_SHA1_ALT */
+#include "sha1_alt.h"
+#endif /* POLARSSL_SHA1_ALT */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Output = SHA-1( input buffer )
+ *
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   SHA-1 checksum result
+ */
+void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] );
+
+/**
+ * \brief          Output = SHA-1( file contents )
+ *
+ * \param path     input file name
+ * \param output   SHA-1 checksum result
+ *
+ * \return         0 if successful, or POLARSSL_ERR_SHA1_FILE_IO_ERROR
+ */
+int sha1_file( const char *path, unsigned char output[20] );
+
+/**
+ * \brief          SHA-1 HMAC context setup
+ *
+ * \param ctx      HMAC context to be initialized
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ */
+void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key,
+                       size_t keylen );
+
+/**
+ * \brief          SHA-1 HMAC process buffer
+ *
+ * \param ctx      HMAC context
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ */
+void sha1_hmac_update( sha1_context *ctx, const unsigned char *input,
+                       size_t ilen );
+
+/**
+ * \brief          SHA-1 HMAC final digest
+ *
+ * \param ctx      HMAC context
+ * \param output   SHA-1 HMAC checksum result
+ */
+void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] );
+
+/**
+ * \brief          SHA-1 HMAC context reset
+ *
+ * \param ctx      HMAC context to be reset
+ */
+void sha1_hmac_reset( sha1_context *ctx );
+
+/**
+ * \brief          Output = HMAC-SHA-1( hmac key, input buffer )
+ *
+ * \param key      HMAC secret key
+ * \param keylen   length of the HMAC key
+ * \param input    buffer holding the  data
+ * \param ilen     length of the input data
+ * \param output   HMAC-SHA-1 result
+ */
+void sha1_hmac( const unsigned char *key, size_t keylen,
+                const unsigned char *input, size_t ilen,
+                unsigned char output[20] );
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int sha1_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* sha1.h */