First check in.

This commit is contained in:
iceman1001 2014-09-11 23:23:46 +02:00
parent 4a79e52c0b
commit f38a152863
103 changed files with 10544 additions and 508 deletions

View file

@ -6,7 +6,7 @@
// LCD code
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
#include "LCD.h"
#include "fonts.h"

View file

@ -10,7 +10,7 @@ APP_INCLUDES = apps.h
#remove one of the following defines and comment out the relevant line
#in the next section to remove that particular feature from compilation
APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG
APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG -DWITH_CRC -fno-strict-aliasing
#-DWITH_LCD
#SRC_LCD = fonts.c LCD.c
@ -18,13 +18,15 @@ SRC_LF = lfops.c hitag2.c
SRC_ISO15693 = iso15693.c iso15693tools.c
SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c
SRC_ISO14443b = iso14443.c
SRC_CRAPTO1 = crapto1.c crypto1.c
SRC_CRAPTO1 = crapto1.c crypto1.c des.c aes.c
SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c
THUMBSRC = start.c \
$(SRC_LCD) \
$(SRC_ISO15693) \
$(SRC_LF) \
appmain.c printf.c \
appmain.c \
printf.c \
util.c \
string.c \
usb_cdc.c \
@ -33,14 +35,15 @@ THUMBSRC = start.c \
# These are to be compiled in ARM mode
ARMSRC = fpgaloader.c \
legicrf.c \
iso14443crc.c \
crc16.c \
$(SRC_ISO14443a) \
$(SRC_ISO14443b) \
$(SRC_CRAPTO1) \
$(SRC_CRC) \
legic_prng.c \
iclass.c \
crc.c
mifaredesfire.c \
desfire_crypto.c \
desfire_key.c
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
APP_CFLAGS += -I.

1168
armsrc/aes.c Normal file

File diff suppressed because it is too large Load diff

30
armsrc/aes.h Normal file
View file

@ -0,0 +1,30 @@
/*
* AES Cryptographic Algorithm Header File. Include this header file in
* your source which uses these given APIs. (This source is kept under
* public domain)
*/
// AES context structure
typedef struct {
unsigned int Ek[60];
unsigned int Dk[60];
unsigned int Iv[4];
unsigned char Nr;
unsigned char Mode;
} AesCtx;
// key length in bytes
#define KEY128 16
#define KEY192 24
#define KEY256 32
// block size in bytes
#define BLOCKSZ 16
// mode
#define EBC 0
#define CBC 1
// AES API function prototype
int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode);
int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen);
int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen);

View file

@ -10,10 +10,10 @@
// executes.
//-----------------------------------------------------------------------------
#include "usb_cdc.h"
#include "cmd.h"
#include "../common/usb_cdc.h"
#include "../common/cmd.h"
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "printf.h"
@ -22,7 +22,7 @@
#include <stdarg.h>
#include "legicrf.h"
#include <hitag2.h>
#include "../include/hitag2.h"
#ifdef WITH_LCD
#include "LCD.h"
@ -81,40 +81,12 @@ void DbpString(char *str)
{
byte_t len = strlen(str);
cmd_send(CMD_DEBUG_PRINT_STRING,len,0,0,(byte_t*)str,len);
// /* this holds up stuff unless we're connected to usb */
// if (!UsbConnected())
// return;
//
// UsbCommand c;
// c.cmd = CMD_DEBUG_PRINT_STRING;
// c.arg[0] = strlen(str);
// if(c.arg[0] > sizeof(c.d.asBytes)) {
// c.arg[0] = sizeof(c.d.asBytes);
// }
// memcpy(c.d.asBytes, str, c.arg[0]);
//
// UsbSendPacket((uint8_t *)&c, sizeof(c));
// // TODO fix USB so stupid things like this aren't req'd
// SpinDelay(50);
}
#if 0
void DbpIntegers(int x1, int x2, int x3)
{
cmd_send(CMD_DEBUG_PRINT_INTEGERS,x1,x2,x3,0,0);
// /* this holds up stuff unless we're connected to usb */
// if (!UsbConnected())
// return;
//
// UsbCommand c;
// c.cmd = CMD_DEBUG_PRINT_INTEGERS;
// c.arg[0] = x1;
// c.arg[1] = x2;
// c.arg[2] = x3;
//
// UsbSendPacket((uint8_t *)&c, sizeof(c));
// // XXX
// SpinDelay(50);
}
#endif
@ -199,8 +171,6 @@ void MeasureAntennaTuning(void)
int i, adcval = 0, peak = 0, peakv = 0, peakf = 0; //ptr = 0
int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV
// UsbCommand c;
LED_B_ON();
DbpString("Measuring antenna characteristics, please wait...");
memset(dest,0,sizeof(FREE_BUFFER_SIZE));
@ -692,7 +662,6 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_PCF7931_READ: // Read PCF7931 tag
ReadPCF7931();
cmd_send(CMD_ACK,0,0,0,0,0);
// UsbSendPacket((uint8_t*)&ack, sizeof(ack));
break;
case CMD_EM4X_READ_WORD:
EM4xReadWord(c->arg[1], c->arg[2],c->d.asBytes[0]);
@ -800,8 +769,17 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_MIFAREU_READBL:
MifareUReadBlock(c->arg[0],c->d.asBytes);
break;
case CMD_MIFAREUC_AUTH1:
MifareUC_Auth1(c->arg[0],c->d.asBytes);
break;
case CMD_MIFAREUC_AUTH2:
MifareUC_Auth2(c->arg[0],c->d.asBytes);
break;
case CMD_MIFAREU_READCARD:
MifareUReadCard(c->arg[0],c->d.asBytes);
MifareUReadCard(c->arg[0],c->arg[1],c->d.asBytes);
break;
case CMD_MIFAREUC_READCARD:
MifareUReadCard(c->arg[0],c->arg[1],c->d.asBytes);
break;
case CMD_MIFARE_READSC:
MifareReadSector(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
@ -854,6 +832,24 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_MIFARE_SNIFFER:
SniffMifare(c->arg[0]);
break;
// mifare desfire
case CMD_MIFARE_DESFIRE_READBL:
break;
case CMD_MIFARE_DESFIRE_WRITEBL:
break;
case CMD_MIFARE_DESFIRE_AUTH1:
MifareDES_Auth1(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break;
case CMD_MIFARE_DESFIRE_AUTH2:
MifareDES_Auth2(c->arg[0],c->d.asBytes);
break;
// case CMD_MIFARE_DES_READER:
// ReaderMifareDES(c->arg[0], c->arg[1], c->d.asBytes);
break;
case CMD_MIFARE_DESFIRE_INFO:
MifareDesfireGetInformation();
break;
#endif
#ifdef WITH_ICLASS
@ -867,6 +863,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_READER_ICLASS:
ReaderIClass(c->arg[0]);
break;
case CMD_READER_ICLASS_REPLAY:
ReaderIClass_Replay(c->arg[0], c->d.asBytes);
break;
#endif
case CMD_SIMULATE_TAG_HF_LISTEN:
@ -896,18 +895,6 @@ void UsbPacketReceived(uint8_t *packet, int len)
break;
case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K:
// UsbCommand n;
// if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) {
// n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K;
// } else {
// n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE;
// }
// n.arg[0] = c->arg[0];
// memcpy(n.d.asBytes, BigBuf+c->arg[0], 48); // 12*sizeof(uint32_t)
// LED_B_ON();
// usb_write((uint8_t *)&n, sizeof(n));
// UsbSendPacket((uint8_t *)&n, sizeof(n));
// LED_B_OFF();
LED_B_ON();
for(size_t i=0; i<c->arg[1]; i += USB_CMD_DATA_SIZE) {
@ -923,7 +910,6 @@ void UsbPacketReceived(uint8_t *packet, int len)
uint8_t *b = (uint8_t *)BigBuf;
memcpy(b+c->arg[0], c->d.asBytes, 48);
//Dbprintf("copied 48 bytes to %i",b+c->arg[0]);
// UsbSendPacket((uint8_t*)&ack, sizeof(ack));
cmd_send(CMD_ACK,0,0,0,0,0);
break;
}
@ -981,7 +967,6 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_DEVICE_INFO: {
uint32_t dev_info = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS;
if(common_area.flags.bootrom_present) dev_info |= DEVICE_INFO_FLAG_BOOTROM_PRESENT;
// UsbSendPacket((uint8_t*)&c, sizeof(c));
cmd_send(CMD_DEVICE_INFO,dev_info,0,0,0,0);
break;
}
@ -1010,7 +995,6 @@ void __attribute__((noreturn)) AppMain(void)
// Init USB device`
usb_enable();
// UsbStart();
// The FPGA gets its clock from us from PCK0 output, so set that up.
AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0;
@ -1046,8 +1030,6 @@ void __attribute__((noreturn)) AppMain(void)
UsbPacketReceived(rx,rx_len);
}
}
// UsbPoll(FALSE);
WDT_HIT();
#ifdef WITH_LF

View file

@ -14,9 +14,27 @@
#include <stdint.h>
#include <stddef.h>
#include "common.h"
#include "hitag2.h"
#include "mifare.h"
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "../include/common.h"
#include "../include/hitag2.h"
#include "../include/mifare.h"
//#include <openssl/des.h>
//#include <openssl/aes.h>
//#include "des.h"
//#include "aes.h"
#include "../common/desfire.h"
#include "../common/crc32.h"
//#include "desfire_crypto.h"
//#include "desfire_key.h"
// The large multi-purpose buffer, typically used to hold A/D samples,
// maybe processed in some way.
@ -172,7 +190,9 @@ void ReaderMifare(bool first_try);
int32_t dist_nt(uint32_t nt1, uint32_t nt2);
void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data);
void MifareUReadBlock(uint8_t arg0,uint8_t *datain);
void MifareUReadCard(uint8_t arg0,uint8_t *datain);
void MifareUC_Auth1(uint8_t arg0, uint8_t *datain);
void MifareUC_Auth2(uint32_t arg0, uint8_t *datain);
void MifareUReadCard(uint8_t arg0,int Pages,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);
@ -188,6 +208,47 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
// mifaredesfire.h
void MifareDesfireGetInformation();
void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain);
void MifareDES_Auth2(uint32_t arg0, uint8_t *datain);
int mifare_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData);
void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain);
int SendDesfireCommand(enum DESFIRE_CMD desfire_cmd, uint8_t *dataout, uint8_t fromscratch);
uint8_t* CreateAPDU( uint8_t *datain, size_t len);
void OnSuccess();
void OnError();
// desfire_key.h
desfirekey_t Desfire_des_key_new (const uint8_t value[8]);
desfirekey_t Desfire_3des_key_new (const uint8_t value[16]);
desfirekey_t Desfire_des_key_new_with_version (const uint8_t value[8]);
desfirekey_t Desfire_3des_key_new_with_version (const uint8_t value[16]);
desfirekey_t Desfire_3k3des_key_new (const uint8_t value[24]);
desfirekey_t Desfire_3k3des_key_new_with_version (const uint8_t value[24]);
desfirekey_t Desfire_aes_key_new (const uint8_t value[16]);
desfirekey_t Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version);
uint8_t Desfire_key_get_version (desfirekey_t key);
void Desfire_key_set_version (desfirekey_t key, uint8_t version);
desfirekey_t Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey);
// desfire_crypto.h
void *mifare_cryto_preprocess_data (desfiretag_t tag, void *data, size_t *nbytes, off_t offset, int communication_settings);
void *mifare_cryto_postprocess_data (desfiretag_t tag, void *data, ssize_t *nbytes, int communication_settings);
void mifare_cypher_single_block (desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size);
void mifare_cypher_blocks_chained (desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation);
size_t key_block_size (const desfirekey_t key);
size_t padded_data_length (const size_t nbytes, const size_t block_size);
size_t maced_data_length (const desfirekey_t key, const size_t nbytes);
size_t enciphered_data_length (const desfiretag_t tag, const size_t nbytes, int communication_settings);
void cmac_generate_subkeys (desfirekey_t key);
void cmac (const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac);
/// iso15693.h
void RecordRawAdcSamplesIso15693(void);
void AcquireRawAdcSamplesIso15693(void);
@ -201,7 +262,9 @@ void SetDebugIso15693(uint32_t flag);
void RAMFUNC SnoopIClass(void);
void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void ReaderIClass(uint8_t arg0);
//int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived);
void ReaderIClass_Replay(uint8_t arg0,uint8_t *MAC);
void IClass_iso14443A_GetPublic(uint8_t arg0);
// hitag2.h
void SnoopHitag(uint32_t type);
void SimulateHitagTag(bool tag_mem_supplied, byte_t* data);

383
armsrc/des.c Normal file
View file

@ -0,0 +1,383 @@
/* des.c */
/*
This file is part of the ARM-Crypto-Lib.
Copyright (C) 2006-2010 Daniel Otte (daniel.otte@rub.de)
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/**
* \file des.c
* \author Daniel Otte
* \email daniel.otte@rub.de
* \date 2007-06-16
* \brief DES and EDE-DES implementation
* \license GPLv3 or later
*
*/
#include <stdint.h>
#include <string.h>
const uint8_t sbox[256] = {
/* S-box 1 */
0xE4, 0xD1, 0x2F, 0xB8, 0x3A, 0x6C, 0x59, 0x07,
0x0F, 0x74, 0xE2, 0xD1, 0xA6, 0xCB, 0x95, 0x38,
0x41, 0xE8, 0xD6, 0x2B, 0xFC, 0x97, 0x3A, 0x50,
0xFC, 0x82, 0x49, 0x17, 0x5B, 0x3E, 0xA0, 0x6D,
/* S-box 2 */
0xF1, 0x8E, 0x6B, 0x34, 0x97, 0x2D, 0xC0, 0x5A,
0x3D, 0x47, 0xF2, 0x8E, 0xC0, 0x1A, 0x69, 0xB5,
0x0E, 0x7B, 0xA4, 0xD1, 0x58, 0xC6, 0x93, 0x2F,
0xD8, 0xA1, 0x3F, 0x42, 0xB6, 0x7C, 0x05, 0xE9,
/* S-box 3 */
0xA0, 0x9E, 0x63, 0xF5, 0x1D, 0xC7, 0xB4, 0x28,
0xD7, 0x09, 0x34, 0x6A, 0x28, 0x5E, 0xCB, 0xF1,
0xD6, 0x49, 0x8F, 0x30, 0xB1, 0x2C, 0x5A, 0xE7,
0x1A, 0xD0, 0x69, 0x87, 0x4F, 0xE3, 0xB5, 0x2C,
/* S-box 4 */
0x7D, 0xE3, 0x06, 0x9A, 0x12, 0x85, 0xBC, 0x4F,
0xD8, 0xB5, 0x6F, 0x03, 0x47, 0x2C, 0x1A, 0xE9,
0xA6, 0x90, 0xCB, 0x7D, 0xF1, 0x3E, 0x52, 0x84,
0x3F, 0x06, 0xA1, 0xD8, 0x94, 0x5B, 0xC7, 0x2E,
/* S-box 5 */
0x2C, 0x41, 0x7A, 0xB6, 0x85, 0x3F, 0xD0, 0xE9,
0xEB, 0x2C, 0x47, 0xD1, 0x50, 0xFA, 0x39, 0x86,
0x42, 0x1B, 0xAD, 0x78, 0xF9, 0xC5, 0x63, 0x0E,
0xB8, 0xC7, 0x1E, 0x2D, 0x6F, 0x09, 0xA4, 0x53,
/* S-box 6 */
0xC1, 0xAF, 0x92, 0x68, 0x0D, 0x34, 0xE7, 0x5B,
0xAF, 0x42, 0x7C, 0x95, 0x61, 0xDE, 0x0B, 0x38,
0x9E, 0xF5, 0x28, 0xC3, 0x70, 0x4A, 0x1D, 0xB6,
0x43, 0x2C, 0x95, 0xFA, 0xBE, 0x17, 0x60, 0x8D,
/* S-box 7 */
0x4B, 0x2E, 0xF0, 0x8D, 0x3C, 0x97, 0x5A, 0x61,
0xD0, 0xB7, 0x49, 0x1A, 0xE3, 0x5C, 0x2F, 0x86,
0x14, 0xBD, 0xC3, 0x7E, 0xAF, 0x68, 0x05, 0x92,
0x6B, 0xD8, 0x14, 0xA7, 0x95, 0x0F, 0xE2, 0x3C,
/* S-box 8 */
0xD2, 0x84, 0x6F, 0xB1, 0xA9, 0x3E, 0x50, 0xC7,
0x1F, 0xD8, 0xA3, 0x74, 0xC5, 0x6B, 0x0E, 0x92,
0x7B, 0x41, 0x9C, 0xE2, 0x06, 0xAD, 0xF3, 0x58,
0x21, 0xE7, 0x4A, 0x8D, 0xFC, 0x90, 0x35, 0x6B
};
const uint8_t e_permtab[] ={
4, 6, /* 4 bytes in 6 bytes out*/
32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13,
12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21,
20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1
};
const uint8_t p_permtab[] ={
4, 4, /* 32 bit -> 32 bit */
16, 7, 20, 21,
29, 12, 28, 17,
1, 15, 23, 26,
5, 18, 31, 10,
2, 8, 24, 14,
32, 27, 3, 9,
19, 13, 30, 6,
22, 11, 4, 25
};
const uint8_t ip_permtab[] ={
8, 8, /* 64 bit -> 64 bit */
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7
};
const uint8_t inv_ip_permtab[] ={
8, 8, /* 64 bit -> 64 bit */
40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25
};
const uint8_t pc1_permtab[] ={
8, 7, /* 64 bit -> 56 bit*/
57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4
};
const uint8_t pc2_permtab[] ={
7, 6, /* 56 bit -> 48 bit */
14, 17, 11, 24, 1, 5,
3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8,
16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55,
30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53,
46, 42, 50, 36, 29, 32
};
const uint8_t splitin6bitword_permtab[] = {
8, 8, /* 64 bit -> 64 bit */
64, 64, 1, 6, 2, 3, 4, 5,
64, 64, 7, 12, 8, 9, 10, 11,
64, 64, 13, 18, 14, 15, 16, 17,
64, 64, 19, 24, 20, 21, 22, 23,
64, 64, 25, 30, 26, 27, 28, 29,
64, 64, 31, 36, 32, 33, 34, 35,
64, 64, 37, 42, 38, 39, 40, 41,
64, 64, 43, 48, 44, 45, 46, 47
};
const uint8_t shiftkey_permtab[] = {
7, 7, /* 56 bit -> 56 bit */
2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 1,
30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 29
};
const uint8_t shiftkeyinv_permtab[] = {
7, 7,
28, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27,
56, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55
};
/*
1 0
1 0
2 1
2 1
2 1
2 1
2 1
2 1
----
1 0
2 1
2 1
2 1
2 1
2 1
2 1
1 0
*/
#define ROTTABLE 0x7EFC
#define ROTTABLE_INV 0x3F7E
/******************************************************************************/
void permute(const uint8_t *ptable, const uint8_t *in, uint8_t *out){
uint8_t ob; /* in-bytes and out-bytes */
uint8_t byte, bit; /* counter for bit and byte */
ob = ptable[1];
ptable = &(ptable[2]);
for(byte=0; byte<ob; ++byte){
uint8_t x,t=0;
for(bit=0; bit<8; ++bit){
x=*ptable++ -1 ;
t<<=1;
if((in[x/8]) & (0x80>>(x%8)) ){
t|=0x01;
}
}
out[byte]=t;
}
}
/******************************************************************************/
void changeendian32(uint32_t * a){
*a = (*a & 0x000000FF) << 24 |
(*a & 0x0000FF00) << 8 |
(*a & 0x00FF0000) >> 8 |
(*a & 0xFF000000) >> 24;
}
/******************************************************************************/
static inline
void shiftkey(uint8_t *key){
uint8_t k[7];
memcpy(k, key, 7);
permute((uint8_t*)shiftkey_permtab, k, key);
}
/******************************************************************************/
static inline
void shiftkey_inv(uint8_t *key){
uint8_t k[7];
memcpy(k, key, 7);
permute((uint8_t*)shiftkeyinv_permtab, k, key);
}
/******************************************************************************/
static inline
uint64_t splitin6bitwords(uint64_t a){
uint64_t ret=0;
a &= 0x0000ffffffffffffLL;
permute((uint8_t*)splitin6bitword_permtab, (uint8_t*)&a, (uint8_t*)&ret);
return ret;
}
/******************************************************************************/
static inline
uint8_t substitute(uint8_t a, uint8_t * sbp){
uint8_t x;
x = sbp[a>>1];
x = (a&1)?x&0x0F:x>>4;
return x;
}
/******************************************************************************/
uint32_t des_f(uint32_t r, uint8_t* kr){
uint8_t i;
uint32_t t=0,ret;
uint64_t data;
uint8_t *sbp; /* sboxpointer */
permute((uint8_t*)e_permtab, (uint8_t*)&r, (uint8_t*)&data);
for(i=0; i<7; ++i)
((uint8_t*)&data)[i] ^= kr[i];
/* Sbox substitution */
data = splitin6bitwords(data);
sbp=(uint8_t*)sbox;
for(i=0; i<8; ++i){
uint8_t x;
x = substitute(((uint8_t*)&data)[i], sbp);
t<<=4;
t |= x;
sbp += 32;
}
changeendian32(&t);
permute((uint8_t*)p_permtab,(uint8_t*)&t, (uint8_t*)&ret);
return ret;
}
/******************************************************************************/
void des_enc(void* out, const void* in, const void* key){
#define R *((uint32_t*)&(data[4]))
#define L *((uint32_t*)&(data[0]))
uint8_t data[8],kr[6],k[7];
uint8_t i;
permute((uint8_t*)ip_permtab, (uint8_t*)in, data);
permute((uint8_t*)pc1_permtab, (const uint8_t*)key, k);
for(i=0; i<8; ++i){
shiftkey(k);
if(ROTTABLE&((1<<((i<<1)+0))) )
shiftkey(k);
permute((uint8_t*)pc2_permtab, k, kr);
L ^= des_f(R, kr);
shiftkey(k);
if(ROTTABLE&((1<<((i<<1)+1))) )
shiftkey(k);
permute((uint8_t*)pc2_permtab, k, kr);
R ^= des_f(L, kr);
}
/* L <-> R*/
R ^= L;
L ^= R;
R ^= L;
permute((uint8_t*)inv_ip_permtab, data, (uint8_t*)out);
}
/******************************************************************************/
void des_dec(void* out, const void* in, const uint8_t* key){
#define R *((uint32_t*)&(data[4]))
#define L *((uint32_t*)&(data[0]))
uint8_t data[8],kr[6],k[7];
int8_t i;
permute((uint8_t*)ip_permtab, (uint8_t*)in, data);
permute((uint8_t*)pc1_permtab, (const uint8_t*)key, k);
for(i=7; i>=0; --i){
permute((uint8_t*)pc2_permtab, k, kr);
L ^= des_f(R, kr);
shiftkey_inv(k);
if(ROTTABLE&((1<<((i<<1)+1))) ){
shiftkey_inv(k);
}
permute((uint8_t*)pc2_permtab, k, kr);
R ^= des_f(L, kr);
shiftkey_inv(k);
if(ROTTABLE&((1<<((i<<1)+0))) ){
shiftkey_inv(k);
}
}
/* L <-> R*/
R ^= L;
L ^= R;
R ^= L;
permute((uint8_t*)inv_ip_permtab, data, (uint8_t*)out);
}
/******************************************************************************/
void tdes_enc(void* out, void* in, const void* key){
des_enc(out, in, (uint8_t*)key + 0);
des_dec(out, out, (uint8_t*)key + 8);
des_enc(out, out, (uint8_t*)key +16);
}
/******************************************************************************/
void tdes_dec(void* out, void* in, const uint8_t* key){
des_dec(out, in, (uint8_t*)key +16);
des_enc(out, out, (uint8_t*)key + 8);
des_dec(out, out, (uint8_t*)key + 0);
}
/******************************************************************************/

107
armsrc/des.h Normal file
View file

@ -0,0 +1,107 @@
/* des.h */
/*
This file is part of the ARM-Crypto-Lib.
Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de)
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 3 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, see <http://www.gnu.org/licenses/>.
*/
/**
* \file des.h
* \author Daniel Otte
* \date 2007-06-16
* \brief des and tdes declarations
* \license GPLv3 or later
*
*/
#ifndef DES_H_
#define DES_H_
/* the FIPS 46-3 (1999-10-25) name for triple DES is triple data encryption algorithm so TDEA.
* Also we only implement the three key mode */
/** \def tdea_enc
* \brief defining an alias for void tdes_enc(void* out, const void* in, const void* key)
*/
/** \def tdea_dec
* \brief defining an alias for void tdes_dec(void* out, const void* in, const void* key)
*/
#define tdea_enc tdes_enc
#define tdea_dec tdes_dec
/** \fn void des_enc(void* out, const void* in, const void* key)
* \brief encrypt a block with DES
*
* This function encrypts a block of 64 bits (8 bytes) with the DES algorithm.
* Key expansion is done automatically. The key is 64 bits long, but note that
* only 56 bits are used (the LSB of each byte is dropped). The input and output
* blocks may overlap.
*
* \param out pointer to the block (64 bit = 8 byte) where the ciphertext is written to
* \param in pointer to the block (64 bit = 8 byte) where the plaintext is read from
* \param key pointer to the key (64 bit = 8 byte)
*/
void des_enc(void* out, const void* in, const void* key);
/** \fn void des_dec(void* out, const void* in, const void* key)
* \brief decrypt a block with DES
*
* This function decrypts a block of 64 bits (8 bytes) with the DES algorithm.
* Key expansion is done automatically. The key is 64 bits long, but note that
* only 56 bits are used (the LSB of each byte is dropped). The input and output
* blocks may overlap.
*
* \param out pointer to the block (64 bit = 8 byte) where the plaintext is written to
* \param in pointer to the block (64 bit = 8 byte) where the ciphertext is read from
* \param key pointer to the key (64 bit = 8 byte)
*/
void des_dec(void* out, const void* in, const void* key);
/** \fn void tdes_enc(void* out, const void* in, const void* key)
* \brief encrypt a block with Tripple-DES
*
* This function encrypts a block of 64 bits (8 bytes) with the Tripple-DES (EDE)
* algorithm. Key expansion is done automatically. The key is 192 bits long, but
* note that only 178 bits are used (the LSB of each byte is dropped). The input
* and output blocks may overlap.
*
* \param out pointer to the block (64 bit = 8 byte) where the ciphertext is written to
* \param in pointer to the block (64 bit = 8 byte) where the plaintext is read from
* \param key pointer to the key (192 bit = 24 byte)
*/
void tdes_enc(void* out, const void* in, const void* key);
/** \fn void tdes_dec(void* out, const void* in, const void* key)
* \brief decrypt a block with Tripple-DES
*
* This function decrypts a block of 64 bits (8 bytes) with the Tripple-DES (EDE)
* algorithm. Key expansion is done automatically. The key is 192 bits long, but
* note that only 178 bits are used (the LSB of each byte is dropped). The input
* and output blocks may overlap.
*
* \param out pointer to the block (64 bit = 8 byte) where the plaintext is written to
* \param in pointer to the block (64 bit = 8 byte) where the ciphertext is read from
* \param key pointer to the key (192 bit = 24 byte)
*/
void tdes_dec(void* out, const void* in, const void* key);
#endif /*DES_H_*/
// Copied from des.h in desfire imp.
typedef unsigned long DES_KS[16][2]; /* Single-key DES key schedule */
typedef unsigned long DES3_KS[48][2]; /* Triple-DES key schedule */
extern int Asmversion; /* 1 if we're linked with an asm version, 0 if C */

642
armsrc/desfire_crypto.c Normal file
View file

@ -0,0 +1,642 @@
/*-
* Copyright (C) 2010, Romain Tartiere.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 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 Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
* $Id$
*/
/*
* This implementation was written based on information provided by the
* following documents:
*
* NIST Special Publication 800-38B
* Recommendation for Block Cipher Modes of Operation: The CMAC Mode for Authentication
* May 2005
*/
#include "desfire_crypto.h"
static void xor (const uint8_t *ivect, uint8_t *data, const size_t len);
static size_t key_macing_length (desfirekey_t key);
static void xor (const uint8_t *ivect, uint8_t *data, const size_t len) {
for (size_t i = 0; i < len; i++) {
data[i] ^= ivect[i];
}
}
void cmac_generate_subkeys ( desfirekey_t key) {
int kbs = key_block_size (key);
const uint8_t R = (kbs == 8) ? 0x1B : 0x87;
uint8_t l[kbs];
memset (l, 0, kbs);
uint8_t ivect[kbs];
memset (ivect, 0, kbs);
mifare_cypher_blocks_chained (NULL, key, ivect, l, kbs, MCD_RECEIVE, MCO_ENCYPHER);
bool xor = false;
// Used to compute CMAC on complete blocks
memcpy (key->cmac_sk1, l, kbs);
xor = l[0] & 0x80;
lsl (key->cmac_sk1, kbs);
if (xor)
key->cmac_sk1[kbs-1] ^= R;
// Used to compute CMAC on the last block if non-complete
memcpy (key->cmac_sk2, key->cmac_sk1, kbs);
xor = key->cmac_sk1[0] & 0x80;
lsl (key->cmac_sk2, kbs);
if (xor)
key->cmac_sk2[kbs-1] ^= R;
}
void cmac (const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac) {
int kbs = key_block_size (key);
uint8_t *buffer = malloc (padded_data_length (len, kbs));
memcpy (buffer, data, len);
if ((!len) || (len % kbs)) {
buffer[len++] = 0x80;
while (len % kbs) {
buffer[len++] = 0x00;
}
xor (key->cmac_sk2, buffer + len - kbs, kbs);
} else {
xor (key->cmac_sk1, buffer + len - kbs, kbs);
}
mifare_cypher_blocks_chained (NULL, key, ivect, buffer, len, MCD_SEND, MCO_ENCYPHER);
memcpy (cmac, ivect, kbs);
}
size_t key_block_size (const desfirekey_t key) {
size_t block_size = 8;
switch (key->type) {
case T_DES:
case T_3DES:
case T_3K3DES:
block_size = 8;
break;
case T_AES:
block_size = 16;
break;
}
return block_size;
}
/*
* Size of MACing produced with the key.
*/
static size_t key_macing_length (const desfirekey_t key) {
size_t mac_length = MAC_LENGTH;
switch (key->type) {
case T_DES:
case T_3DES:
mac_length = MAC_LENGTH;
break;
case T_3K3DES:
case T_AES:
mac_length = CMAC_LENGTH;
break;
}
return mac_length;
}
/*
* Size required to store nbytes of data in a buffer of size n*block_size.
*/
size_t padded_data_length (const size_t nbytes, const size_t block_size) {
if ((!nbytes) || (nbytes % block_size))
return ((nbytes / block_size) + 1) * block_size;
else
return nbytes;
}
/*
* Buffer size required to MAC nbytes of data
*/
size_t maced_data_length (const desfirekey_t key, const size_t nbytes) {
return nbytes + key_macing_length (key);
}
/*
* Buffer size required to encipher nbytes of data and a two bytes CRC.
*/
size_t enciphered_data_length (const desfiretag_t tag, const size_t nbytes, int communication_settings) {
size_t crc_length = 0;
if (!(communication_settings & NO_CRC)) {
switch (DESFIRE(tag)->authentication_scheme) {
case AS_LEGACY:
crc_length = 2;
break;
case AS_NEW:
crc_length = 4;
break;
}
}
size_t block_size = DESFIRE(tag)->session_key ? key_block_size (DESFIRE(tag)->session_key) : 1;
return padded_data_length (nbytes + crc_length, block_size);
}
void* mifare_cryto_preprocess_data (desfiretag_t tag, void *data, size_t *nbytes, off_t offset, int communication_settings) {
uint8_t *res = data;
uint8_t mac[4];
size_t edl;
bool append_mac = true;
desfirekey_t key = DESFIRE(tag)->session_key;
if (!key)
return data;
switch (communication_settings & MDCM_MASK) {
case MDCM_PLAIN:
if (AS_LEGACY == DESFIRE(tag)->authentication_scheme)
break;
/*
* When using new authentication methods, PLAIN data transmission from
* the PICC to the PCD are CMACed, so we have to maintain the
* cryptographic initialisation vector up-to-date to check data
* integrity later.
*
* The only difference with CMACed data transmission is that the CMAC
* is not apended to the data send by the PCD to the PICC.
*/
append_mac = false;
/* pass through */
case MDCM_MACED:
switch (DESFIRE(tag)->authentication_scheme) {
case AS_LEGACY:
if (!(communication_settings & MAC_COMMAND))
break;
/* pass through */
edl = padded_data_length (*nbytes - offset, key_block_size (DESFIRE(tag)->session_key)) + offset;
// Fill in the crypto buffer with data ...
memcpy (res, data, *nbytes);
// ... and 0 padding
memset (res + *nbytes, 0, edl - *nbytes);
mifare_cypher_blocks_chained (tag, NULL, NULL, res + offset, edl - offset, MCD_SEND, MCO_ENCYPHER);
memcpy (mac, res + edl - 8, 4);
// Copy again provided data (was overwritten by mifare_cypher_blocks_chained)
memcpy (res, data, *nbytes);
if (!(communication_settings & MAC_COMMAND))
break;
// Append MAC
size_t bla = maced_data_length (DESFIRE(tag)->session_key, *nbytes - offset) + offset;
bla++;
memcpy (res + *nbytes, mac, 4);
*nbytes += 4;
break;
case AS_NEW:
if (!(communication_settings & CMAC_COMMAND))
break;
cmac (key, DESFIRE (tag)->ivect, res, *nbytes, DESFIRE (tag)->cmac);
if (append_mac) {
maced_data_length (key, *nbytes);
memcpy (res, data, *nbytes);
memcpy (res + *nbytes, DESFIRE (tag)->cmac, CMAC_LENGTH);
*nbytes += CMAC_LENGTH;
}
break;
}
break;
case MDCM_ENCIPHERED:
/* |<-------------- data -------------->|
* |<--- offset -->| |
* +---------------+--------------------+-----+---------+
* | CMD + HEADERS | DATA TO BE SECURED | CRC | PADDING |
* +---------------+--------------------+-----+---------+ ----------------
* | |<~~~~v~~~~~~~~~~~~~>| ^ | | (DES / 3DES)
* | | `---- crc16() ----' | |
* | | | ^ | | ----- *or* -----
* |<~~~~~~~~~~~~~~~~~~~~v~~~~~~~~~~~~~>| ^ | | (3K3DES / AES)
* | `---- crc32() ----' | |
* | | ---- *then* ----
* |<---------------------------------->|
* encypher()/decypher()
*/
if (!(communication_settings & ENC_COMMAND))
break;
edl = enciphered_data_length (tag, *nbytes - offset, communication_settings) + offset;
// Fill in the crypto buffer with data ...
memcpy (res, data, *nbytes);
if (!(communication_settings & NO_CRC)) {
// ... CRC ...
switch (DESFIRE (tag)->authentication_scheme) {
case AS_LEGACY:
AppendCrc14443a(res + offset, *nbytes - offset);
*nbytes += 2;
break;
case AS_NEW:
crc32_append (res, *nbytes);
*nbytes += 4;
break;
}
}
// ... and padding
memset (res + *nbytes, 0, edl - *nbytes);
*nbytes = edl;
mifare_cypher_blocks_chained (tag, NULL, NULL, res + offset, *nbytes - offset, MCD_SEND, (AS_NEW == DESFIRE(tag)->authentication_scheme) ? MCO_ENCYPHER : MCO_DECYPHER);
break;
default:
*nbytes = -1;
res = NULL;
break;
}
return res;
}
void* mifare_cryto_postprocess_data (desfiretag_t tag, void *data, ssize_t *nbytes, int communication_settings)
{
void *res = data;
size_t edl;
void *edata = NULL;
uint8_t first_cmac_byte = 0x00;
desfirekey_t key = DESFIRE(tag)->session_key;
if (!key)
return data;
// Return directly if we just have a status code.
if (1 == *nbytes)
return res;
switch (communication_settings & MDCM_MASK) {
case MDCM_PLAIN:
if (AS_LEGACY == DESFIRE(tag)->authentication_scheme)
break;
/* pass through */
case MDCM_MACED:
switch (DESFIRE (tag)->authentication_scheme) {
case AS_LEGACY:
if (communication_settings & MAC_VERIFY) {
*nbytes -= key_macing_length (key);
if (*nbytes <= 0) {
*nbytes = -1;
res = NULL;
#ifdef WITH_DEBUG
printf ("No room for MAC!");
#endif
break;
}
edl = enciphered_data_length (tag, *nbytes - 1, communication_settings);
edata = malloc (edl);
memcpy (edata, data, *nbytes - 1);
memset ((uint8_t *)edata + *nbytes - 1, 0, edl - *nbytes + 1);
mifare_cypher_blocks_chained (tag, NULL, NULL, edata, edl, MCD_SEND, MCO_ENCYPHER);
if (0 != memcmp ((uint8_t *)data + *nbytes - 1, (uint8_t *)edata + edl - 8, 4)) {
#ifdef WITH_DEBUG
printf ("MACing not verified");
hexdump ((uint8_t *)data + *nbytes - 1, key_macing_length (key), "Expect ", 0);
hexdump ((uint8_t *)edata + edl - 8, key_macing_length (key), "Actual ", 0);
#endif
DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
*nbytes = -1;
res = NULL;
}
}
break;
case AS_NEW:
if (!(communication_settings & CMAC_COMMAND))
break;
if (communication_settings & CMAC_VERIFY) {
if (*nbytes < 9) {
*nbytes = -1;
res = NULL;
break;
}
first_cmac_byte = ((uint8_t *)data)[*nbytes - 9];
((uint8_t *)data)[*nbytes - 9] = ((uint8_t *)data)[*nbytes-1];
}
int n = (communication_settings & CMAC_VERIFY) ? 8 : 0;
cmac (key, DESFIRE (tag)->ivect, ((uint8_t *)data), *nbytes - n, DESFIRE (tag)->cmac);
if (communication_settings & CMAC_VERIFY) {
((uint8_t *)data)[*nbytes - 9] = first_cmac_byte;
if (0 != memcmp (DESFIRE (tag)->cmac, (uint8_t *)data + *nbytes - 9, 8)) {
#ifdef WITH_DEBUG
printf ("CMAC NOT verified :-(");
hexdump ((uint8_t *)data + *nbytes - 9, 8, "Expect ", 0);
hexdump (DESFIRE (tag)->cmac, 8, "Actual ", 0);
#endif
DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
*nbytes = -1;
res = NULL;
} else {
*nbytes -= 8;
}
}
break;
}
free (edata);
break;
case MDCM_ENCIPHERED:
(*nbytes)--;
bool verified = false;
int crc_pos = 0x00;
int end_crc_pos = 0x00;
uint8_t x;
/*
* AS_LEGACY:
* ,-----------------+-------------------------------+--------+
* \ BLOCK n-1 | BLOCK n | STATUS |
* / PAYLOAD | CRC0 | CRC1 | 0x80? | 0x000000000000 | 0x9100 |
* `-----------------+-------------------------------+--------+
*
* <------------ DATA ------------>
* FRAME = PAYLOAD + CRC(PAYLOAD) + PADDING
*
* AS_NEW:
* ,-------------------------------+-----------------------------------------------+--------+
* \ BLOCK n-1 | BLOCK n | STATUS |
* / PAYLOAD | CRC0 | CRC1 | CRC2 | CRC3 | 0x80? | 0x0000000000000000000000000000 | 0x9100 |
* `-------------------------------+-----------------------------------------------+--------+
* <----------------------------------- DATA ------------------------------------->|
*
* <----------------- DATA ---------------->
* FRAME = PAYLOAD + CRC(PAYLOAD + STATUS) + PADDING + STATUS
* `------------------'
*/
mifare_cypher_blocks_chained (tag, NULL, NULL, res, *nbytes, MCD_RECEIVE, MCO_DECYPHER);
/*
* Look for the CRC and ensure it is followed by NULL padding. We
* can't start by the end because the CRC is supposed to be 0 when
* verified, and accumulating 0's in it should not change it.
*/
switch (DESFIRE (tag)->authentication_scheme) {
case AS_LEGACY:
crc_pos = *nbytes - 8 - 1; // The CRC can be over two blocks
if (crc_pos < 0) {
/* Single block */
crc_pos = 0;
}
break;
case AS_NEW:
/* Move status between payload and CRC */
res = DESFIRE (tag)->crypto_buffer;
memcpy (res, data, *nbytes);
crc_pos = (*nbytes) - 16 - 3;
if (crc_pos < 0) {
/* Single block */
crc_pos = 0;
}
memcpy ((uint8_t *)res + crc_pos + 1, (uint8_t *)res + crc_pos, *nbytes - crc_pos);
((uint8_t *)res)[crc_pos] = 0x00;
crc_pos++;
*nbytes += 1;
break;
}
do {
uint16_t crc16 =0x00;
uint32_t crc;
switch (DESFIRE (tag)->authentication_scheme) {
case AS_LEGACY:
end_crc_pos = crc_pos + 2;
AppendCrc14443a (res, end_crc_pos);
//
crc = crc16;
break;
case AS_NEW:
end_crc_pos = crc_pos + 4;
crc32 (res, end_crc_pos, (uint8_t *)&crc);
break;
}
if (!crc) {
verified = true;
for (int n = end_crc_pos; n < *nbytes - 1; n++) {
uint8_t byte = ((uint8_t *)res)[n];
if (!( (0x00 == byte) || ((0x80 == byte) && (n == end_crc_pos)) ))
verified = false;
}
}
if (verified) {
*nbytes = crc_pos;
switch (DESFIRE (tag)->authentication_scheme) {
case AS_LEGACY:
((uint8_t *)data)[(*nbytes)++] = 0x00;
break;
case AS_NEW:
/* The status byte was already before the CRC */
break;
}
} else {
switch (DESFIRE (tag)->authentication_scheme) {
case AS_LEGACY:
break;
case AS_NEW:
x = ((uint8_t *)res)[crc_pos - 1];
((uint8_t *)res)[crc_pos - 1] = ((uint8_t *)res)[crc_pos];
((uint8_t *)res)[crc_pos] = x;
break;
}
crc_pos++;
}
} while (!verified && (end_crc_pos < *nbytes));
if (!verified) {
#ifdef WITH_DEBUG
/* FIXME In some configurations, the file is transmitted PLAIN */
Dbprintf("CRC not verified in decyphered stream");
#endif
DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
*nbytes = -1;
res = NULL;
}
break;
default:
Dbprintf("Unknown communication settings");
*nbytes = -1;
res = NULL;
break;
}
return res;
}
void mifare_cypher_single_block (desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size)
{
uint8_t ovect[MAX_CRYPTO_BLOCK_SIZE];
if (direction == MCD_SEND) {
xor (ivect, data, block_size);
} else {
memcpy (ovect, data, block_size);
}
uint8_t edata[MAX_CRYPTO_BLOCK_SIZE];
switch (key->type) {
case T_DES:
switch (operation) {
case MCO_ENCYPHER:
//DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
des_enc(edata, data, key->data);
break;
case MCO_DECYPHER:
//DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
des_dec(edata, data, key->data);
break;
}
break;
case T_3DES:
switch (operation) {
case MCO_ENCYPHER:
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
// DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT);
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
tdes_enc(edata,data, key->data);
break;
case MCO_DECYPHER:
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
// DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT);
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
tdes_dec(data, edata, key->data);
break;
}
break;
case T_3K3DES:
switch (operation) {
case MCO_ENCYPHER:
tdes_enc(edata,data, key->data);
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
// DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT);
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_ENCRYPT);
break;
case MCO_DECYPHER:
tdes_dec(data, edata, key->data);
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_DECRYPT);
// DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT);
// DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
break;
}
break;
case T_AES:
switch (operation)
{
case MCO_ENCYPHER:
{
AesCtx ctx;
AesCtxIni(&ctx, ivect, key->data, KEY128,CBC);
AesEncrypt(&ctx, data, edata, sizeof(data) );
break;
}
case MCO_DECYPHER:
{
AesCtx ctx;
AesCtxIni(&ctx, ivect, key->data, KEY128,CBC);
AesDecrypt(&ctx, edata, data, sizeof(edata));
break;
}
}
break;
}
memcpy (data, edata, block_size);
if (direction == MCD_SEND) {
memcpy (ivect, data, block_size);
} else {
xor (ivect, data, block_size);
memcpy (ivect, ovect, block_size);
}
}
/*
* This function performs all CBC cyphering / deciphering.
*
* The tag argument may be NULL, in which case both key and ivect shall be set.
* When using the tag session_key and ivect for processing data, these
* arguments should be set to NULL.
*
* Because the tag may contain additional data, one may need to call this
* function with tag, key and ivect defined.
*/
void mifare_cypher_blocks_chained (desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation) {
size_t block_size;
if (tag) {
if (!key)
key = DESFIRE (tag)->session_key;
if (!ivect)
ivect = DESFIRE (tag)->ivect;
switch (DESFIRE (tag)->authentication_scheme) {
case AS_LEGACY:
memset (ivect, 0, MAX_CRYPTO_BLOCK_SIZE);
break;
case AS_NEW:
break;
}
}
block_size = key_block_size (key);
size_t offset = 0;
while (offset < data_size) {
mifare_cypher_single_block (key, data + offset, ivect, direction, operation, block_size);
offset += block_size;
}
}

15
armsrc/desfire_crypto.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef __DESFIRE_CRYPTO_H
#define __DESFIRE_CRYPTO_H
#include <string.h>
#include <strings.h>
#include <stdarg.h>
#include "printf.h"
#include "iso14443a.h"
#include "../common/desfire.h"
#include "des.h"
//#include "aes.h"
#endif

158
armsrc/desfire_key.c Normal file
View file

@ -0,0 +1,158 @@
/*-
* Copyright (C) 2010, Romain Tartiere.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 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 Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include "desfire_key.h"
static inline void update_key_schedules (desfirekey_t key);
static inline void update_key_schedules (desfirekey_t key) {
// DES_set_key ((DES_cblock *)key->data, &(key->ks1));
// DES_set_key ((DES_cblock *)(key->data + 8), &(key->ks2));
// if (T_3K3DES == key->type) {
// DES_set_key ((DES_cblock *)(key->data + 16), &(key->ks3));
// }
}
desfirekey_t Desfire_des_key_new (const uint8_t value[8]) {
uint8_t data[8];
memcpy (data, value, 8);
for (int n=0; n < 8; n++)
data[n] &= 0xfe;
return Desfire_des_key_new_with_version (data);
}
desfirekey_t Desfire_des_key_new_with_version (const uint8_t value[8]) {
desfirekey_t key = NULL;
key->type = T_DES;
memcpy (key->data, value, 8);
memcpy (key->data+8, value, 8);
update_key_schedules (key);
return key;
}
desfirekey_t Desfire_3des_key_new (const uint8_t value[16]) {
uint8_t data[16];
memcpy (data, value, 16);
for (int n=0; n < 8; n++)
data[n] &= 0xfe;
for (int n=8; n < 16; n++)
data[n] |= 0x01;
return Desfire_3des_key_new_with_version (data);
}
desfirekey_t Desfire_3des_key_new_with_version (const uint8_t value[16]) {
desfirekey_t key = NULL;
key->type = T_3DES;
memcpy (key->data, value, 16);
update_key_schedules (key);
return key;
}
desfirekey_t Desfire_3k3des_key_new (const uint8_t value[24]) {
uint8_t data[24];
memcpy (data, value, 24);
for (int n=0; n < 8; n++)
data[n] &= 0xfe;
return Desfire_3k3des_key_new_with_version (data);
}
desfirekey_t Desfire_3k3des_key_new_with_version (const uint8_t value[24]) {
desfirekey_t key = NULL;
key->type = T_3K3DES;
memcpy (key->data, value, 24);
update_key_schedules (key);
return key;
}
desfirekey_t Desfire_aes_key_new (const uint8_t value[16]) {
return Desfire_aes_key_new_with_version (value, 0);
}
desfirekey_t Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version) {
desfirekey_t key = NULL;
memcpy (key->data, value, 16);
key->type = T_AES;
key->aes_version = version;
return key;
}
uint8_t Desfire_key_get_version (desfirekey_t key) {
uint8_t version = 0;
for (int n = 0; n < 8; n++) {
version |= ((key->data[n] & 1) << (7 - n));
}
return version;
}
void Desfire_key_set_version (desfirekey_t key, uint8_t version)
{
for (int n = 0; n < 8; n++) {
uint8_t version_bit = ((version & (1 << (7-n))) >> (7-n));
key->data[n] &= 0xfe;
key->data[n] |= version_bit;
if (key->type == T_DES) {
key->data[n+8] = key->data[n];
} else {
// Write ~version to avoid turning a 3DES key into a DES key
key->data[n+8] &= 0xfe;
key->data[n+8] |= ~version_bit;
}
}
}
desfirekey_t Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey) {
desfirekey_t key = NULL;
uint8_t buffer[24];
switch (authkey->type) {
case T_DES:
memcpy (buffer, rnda, 4);
memcpy (buffer+4, rndb, 4);
key = Desfire_des_key_new_with_version (buffer);
break;
case T_3DES:
memcpy (buffer, rnda, 4);
memcpy (buffer+4, rndb, 4);
memcpy (buffer+8, rnda+4, 4);
memcpy (buffer+12, rndb+4, 4);
key = Desfire_3des_key_new_with_version (buffer);
break;
case T_3K3DES:
memcpy (buffer, rnda, 4);
memcpy (buffer+4, rndb, 4);
memcpy (buffer+8, rnda+6, 4);
memcpy (buffer+12, rndb+6, 4);
memcpy (buffer+16, rnda+12, 4);
memcpy (buffer+20, rndb+12, 4);
key = Desfire_3k3des_key_new (buffer);
break;
case T_AES:
memcpy (buffer, rnda, 4);
memcpy (buffer+4, rndb, 4);
memcpy (buffer+8, rnda+12, 4);
memcpy (buffer+12, rndb+12, 4);
key = Desfire_aes_key_new (buffer);
break;
}
return key;
}

10
armsrc/desfire_key.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef __DESFIRE_KEY_H
#define __DESFIRE_KEY_H
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include "iso14443a.h"
#include "../common/desfire.h"
#endif

View file

@ -13,7 +13,7 @@
#include "iso14443a.h"
#include "epa.h"
#include "cmd.h"
#include "../common/cmd.h"
// Protocol and Parameter Selection Request
// use regular (1x) speed in both directions

View file

@ -9,7 +9,8 @@
// Routines to load the FPGA image, and then to configure the FPGA's major
// mode once it is configured.
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"

View file

@ -16,10 +16,10 @@
// (c) 2012 Roel Verdult
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "hitag2.h"
#include "../include/hitag2.h"
#include "string.h"
static bool bQuiet;

View file

@ -36,15 +36,18 @@
//
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "common.h"
#include "cmd.h"
// Needed for CRC in emulation mode;
// same construction as in ISO 14443;
// different initial value (CRC_ICLASS)
#include "iso14443crc.h"
#include "../common/iso14443crc.h"
#include "../common/iso15693tools.h"
static int timeout = 4096;
@ -1167,12 +1170,11 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader
} else if(receivedCmd[0] == 0x05) {
// Reader random and reader MAC!!!
// Do not respond
// We do not know what to answer, so lets keep quit
// We do not know what to answer, so lets keep quiet
resp = resp1; respLen = 0; //order = 5;
respdata = NULL;
respsize = 0;
if (breakAfterMacReceived){
// TODO, actually return this to the caller instead of just
// dbprintf:ing ...
Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x",csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]);
Dbprintf("RDR: (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x",len,
@ -1465,38 +1467,138 @@ int ReaderReceiveIClass(uint8_t* receivedAnswer)
return Demod.len;
}
void setupIclassReader()
{
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Reset trace buffer
iso14a_set_tracing(TRUE);
iso14a_clear_trace();
// Setup SSC
FpgaSetupSsc();
// Start from off (no field generated)
// Signal field is off with the appropriate LED
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Now give it time to spin up.
// Signal field is on with the appropriate LED
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
SpinDelay(200);
LED_A_ON();
}
// Reader iClass Anticollission
void ReaderIClass(uint8_t arg0) {
uint8_t act_all[] = { 0x0a };
uint8_t identify[] = { 0x0c };
uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t readcheck_cc[]= { 0x88, 0x02 };
uint8_t card_data[24]={0};
uint8_t last_csn[8]={0};
uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
int read_status= 0;
bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE;
// Reset trace buffer
memset(trace, 0x44, RECV_CMD_OFFSET);
traceLen = 0;
setupIclassReader();
// Setup SSC
FpgaSetupSsc();
// Start from off (no field generated)
// Signal field is off with the appropriate LED
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
size_t datasize = 0;
while(!BUTTON_PRESS())
{
WDT_HIT();
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Send act_all
ReaderTransmitIClass(act_all, 1);
// Card present?
if(ReaderReceiveIClass(resp)) {
// Now give it time to spin up.
// Signal field is on with the appropriate LED
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
SpinDelay(200);
ReaderTransmitIClass(identify, 1);
LED_A_ON();
if(ReaderReceiveIClass(resp) == 10) {
//Copy the Anti-collision CSN to our select-packet
memcpy(&select[1],resp,8);
//Dbprintf("Anti-collision CSN: %02x %02x %02x %02x %02x %02x %02x %02x",resp[0], resp[1], resp[2],
// resp[3], resp[4], resp[5],
// resp[6], resp[7]);
//Select the card
ReaderTransmitIClass(select, sizeof(select));
for(;;) {
if(ReaderReceiveIClass(resp) == 10) {
//Save CSN in response data
memcpy(card_data,resp,8);
datasize += 8;
//Flag that we got to at least stage 1, read CSN
read_status = 1;
// Card selected
//Dbprintf("Readcheck on Sector 2");
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
if(ReaderReceiveIClass(resp) == 8) {
//Save CC (e-purse) in response data
memcpy(card_data+8,resp,8);
datasize += 8;
//Got both
read_status = 2;
}
LED_B_ON();
//Send back to client, but don't bother if we already sent this
if(memcmp(last_csn, card_data, 8) != 0)
cmd_send(CMD_ACK,read_status,0,0,card_data,datasize);
//Save that we already sent this....
if(read_status == 2)
memcpy(last_csn, card_data, 8);
LED_B_OFF();
if(abort_after_read) break;
}
}
}
if(traceLen > TRACE_SIZE) {
DbpString("Trace full");
break;
}
}
LED_A_OFF();
}
void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
uint8_t act_all[] = { 0x0a };
uint8_t identify[] = { 0x0c };
uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t readcheck_cc[]= { 0x88, 0x02 };
uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 };
uint16_t crc = 0;
uint8_t cardsize=0;
bool read_success=false;
uint8_t mem=0;
static struct memory_t{
int k16;
int book;
int k2;
int lockauth;
int keyaccess;
} memory;
uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes
setupIclassReader();
for(int i=0;i<1;i++) {
if(traceLen > TRACE_SIZE) {
DbpString("Trace full");
@ -1521,7 +1623,72 @@ void ReaderIClass(uint8_t arg0) {
resp[3], resp[4], resp[5],
resp[6], resp[7]);
}
// Card selected, whats next... ;-)
// Card selected
Dbprintf("Readcheck on Sector 2");
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
if(ReaderReceiveIClass(resp) == 8) {
Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x",
resp[0], resp[1], resp[2],
resp[3], resp[4], resp[5],
resp[6], resp[7]);
}else return;
Dbprintf("Authenticate");
//for now replay captured auth (as cc not updated)
memcpy(check+5,MAC,4);
//Dbprintf(" AA: %02x %02x %02x %02x",
// check[5], check[6], check[7],check[8]);
ReaderTransmitIClass(check, sizeof(check));
if(ReaderReceiveIClass(resp) == 4) {
Dbprintf(" AR: %02x %02x %02x %02x",
resp[0], resp[1], resp[2],resp[3]);
}else {
Dbprintf("Error: Authentication Fail!");
return;
}
Dbprintf("Dump Contents");
//first get configuration block
read_success=false;
read[1]=1;
uint8_t *blockno=&read[1];
crc = iclass_crc16((char *)blockno,1);
read[2] = crc >> 8;
read[3] = crc & 0xff;
while(!read_success){
ReaderTransmitIClass(read, sizeof(read));
if(ReaderReceiveIClass(resp) == 10) {
read_success=true;
mem=resp[5];
memory.k16= (mem & 0x80);
memory.book= (mem & 0x20);
memory.k2= (mem & 0x8);
memory.lockauth= (mem & 0x2);
memory.keyaccess= (mem & 0x1);
}
}
if (memory.k16){
cardsize=255;
}else cardsize=32;
//then loop around remaining blocks
for(uint8_t j=0; j<cardsize; j++){
read_success=false;
uint8_t *blockno=&j;
//crc_data[0]=j;
read[1]=j;
crc = iclass_crc16((char *)blockno,1);
read[2] = crc >> 8;
read[3] = crc & 0xff;
while(!read_success){
ReaderTransmitIClass(read, sizeof(read));
if(ReaderReceiveIClass(resp) == 10) {
read_success=true;
Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x",
j, resp[0], resp[1], resp[2],
resp[3], resp[4], resp[5],
resp[6], resp[7]);
}
}
}
}
}
WDT_HIT();
@ -1530,4 +1697,130 @@ void ReaderIClass(uint8_t arg0) {
LED_A_OFF();
}
//2. Create Read method (cut-down from above) based off responses from 1.
// Since we have the MAC could continue to use replay function.
//3. Create Write method
/*
void IClass_iso14443A_write(uint8_t arg0, uint8_t blockNo, uint8_t *data, uint8_t *MAC) {
uint8_t act_all[] = { 0x0a };
uint8_t identify[] = { 0x0c };
uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t readcheck_cc[]= { 0x88, 0x02 };
uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 };
uint8_t write[] = { 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint16_t crc = 0;
uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes
// Reset trace buffer
memset(trace, 0x44, RECV_CMD_OFFSET);
traceLen = 0;
// Setup SSC
FpgaSetupSsc();
// Start from off (no field generated)
// Signal field is off with the appropriate LED
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Now give it time to spin up.
// Signal field is on with the appropriate LED
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
SpinDelay(200);
LED_A_ON();
for(int i=0;i<1;i++) {
if(traceLen > TRACE_SIZE) {
DbpString("Trace full");
break;
}
if (BUTTON_PRESS()) break;
// Send act_all
ReaderTransmitIClass(act_all, 1);
// Card present?
if(ReaderReceiveIClass(resp)) {
ReaderTransmitIClass(identify, 1);
if(ReaderReceiveIClass(resp) == 10) {
// Select card
memcpy(&select[1],resp,8);
ReaderTransmitIClass(select, sizeof(select));
if(ReaderReceiveIClass(resp) == 10) {
Dbprintf(" Selected CSN: %02x %02x %02x %02x %02x %02x %02x %02x",
resp[0], resp[1], resp[2],
resp[3], resp[4], resp[5],
resp[6], resp[7]);
}
// Card selected
Dbprintf("Readcheck on Sector 2");
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
if(ReaderReceiveIClass(resp) == 8) {
Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x",
resp[0], resp[1], resp[2],
resp[3], resp[4], resp[5],
resp[6], resp[7]);
}else return;
Dbprintf("Authenticate");
//for now replay captured auth (as cc not updated)
memcpy(check+5,MAC,4);
Dbprintf(" AA: %02x %02x %02x %02x",
check[5], check[6], check[7],check[8]);
ReaderTransmitIClass(check, sizeof(check));
if(ReaderReceiveIClass(resp) == 4) {
Dbprintf(" AR: %02x %02x %02x %02x",
resp[0], resp[1], resp[2],resp[3]);
}else {
Dbprintf("Error: Authentication Fail!");
return;
}
Dbprintf("Write Block");
//read configuration for max block number
read_success=false;
read[1]=1;
uint8_t *blockno=&read[1];
crc = iclass_crc16((char *)blockno,1);
read[2] = crc >> 8;
read[3] = crc & 0xff;
while(!read_success){
ReaderTransmitIClass(read, sizeof(read));
if(ReaderReceiveIClass(resp) == 10) {
read_success=true;
mem=resp[5];
memory.k16= (mem & 0x80);
memory.book= (mem & 0x20);
memory.k2= (mem & 0x8);
memory.lockauth= (mem & 0x2);
memory.keyaccess= (mem & 0x1);
}
}
if (memory.k16){
cardsize=255;
}else cardsize=32;
//check card_size
memcpy(write+1,blockNo,1);
memcpy(write+2,data,8);
memcpy(write+10,mac,4);
while(!send_success){
ReaderTransmitIClass(write, sizeof(write));
if(ReaderReceiveIClass(resp) == 10) {
write_success=true;
}
}//
}
WDT_HIT();
}
LED_A_OFF();
}*/

View file

@ -10,12 +10,12 @@
// supported.
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "iso14443crc.h"
#include "../common/iso14443crc.h"
//static void GetSamplesFor14443(int weTx, int n);

View file

@ -10,13 +10,12 @@
// Routines to support ISO 14443 type A.
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "cmd.h"
#include "iso14443crc.h"
#include "../common/cmd.h"
#include "../common/iso14443crc.h"
#include "iso14443a.h"
#include "crapto1.h"
#include "mifareutil.h"
@ -1616,6 +1615,13 @@ int ReaderReceive(uint8_t* receivedAnswer)
return ReaderReceiveOffset(receivedAnswer, 0);
}
int ReaderReceiveDesfiresAuthTiming(uint8_t *receivedAnswer, uint32_t *elapsedTime)
{
int len = ReaderReceiveOffset(receivedAnswer, 0);
*elapsedTime = (Demod.endTime*16 - DELAY_AIR2ARM_AS_READER) - (Demod.startTime*16 - DELAY_AIR2ARM_AS_READER);
return len;
}
int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr)
{
if (!GetIso14443aAnswerFromTag(receivedAnswer,0,160)) return FALSE;
@ -1787,7 +1793,7 @@ void iso14443a_setup(uint8_t fpga_minor_mode) {
DemodReset();
UartReset();
NextTransferTime = 2*DELAY_ARM2AIR_AS_READER;
iso14a_set_timeout(1050); // 10ms default
iso14a_set_timeout(1050); // 10ms default 10*105 =
}
int iso14_apdu(uint8_t * cmd, size_t cmd_len, void * data) {
@ -1825,8 +1831,8 @@ void ReaderIso14443a(UsbCommand *c)
{
iso14a_command_t param = c->arg[0];
uint8_t *cmd = c->d.asBytes;
size_t len = c->arg[1];
size_t lenbits = c->arg[2];
size_t len = c->arg[1] & 0xFFFF;
size_t lenbits = c->arg[1] >> 16;
uint32_t arg0 = 0;
byte_t buf[USB_CMD_DATA_SIZE];
@ -1862,9 +1868,10 @@ void ReaderIso14443a(UsbCommand *c)
if(param & ISO14A_APPEND_CRC) {
AppendCrc14443a(cmd,len);
len += 2;
if (lenbits) lenbits += 16;
lenbits += 16;
}
if(lenbits>0) {
ReaderTransmitBitsPar(cmd,lenbits,GetParity(cmd,lenbits/8), NULL);
} else {
ReaderTransmit(cmd,len, NULL);
@ -2206,12 +2213,9 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
if (MF_DBGLEVEL >= 1) {
if (!_7BUID) {
Dbprintf("4B UID: %02x%02x%02x%02x",
rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3]);
Dbprintf("4B UID: %02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3]);
} else {
Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x",
rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3],
rUIDBCC2[0], rUIDBCC2[1] ,rUIDBCC2[2], rUIDBCC2[3]);
Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3],rUIDBCC2[0],rUIDBCC2[1] ,rUIDBCC2[2] , rUIDBCC2[3]);
}
}
@ -2321,9 +2325,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
// test if auth OK
if (cardRr != prng_successor(nonce, 64)){
if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x",
cardAUTHSC, cardAUTHKEY == 0 ? 'A' : 'B',
cardRr, prng_successor(nonce, 64));
if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED. cardRr=%08x, succ=%08x",cardRr, prng_successor(nonce, 64));
// Shouldn't we respond anything here?
// Right now, we don't nack or anything, which causes the
// reader to do a WUPA after a while. /Martin

View file

@ -12,7 +12,7 @@
#ifndef __ISO14443A_H
#define __ISO14443A_H
#include "common.h"
#include "../include/common.h"
#include "mifaresniff.h"
// mifare reader over DMA buffer (SnoopIso14443a())!!!
@ -84,6 +84,7 @@ extern void ReaderTransmitBitsPar(uint8_t *frame, int bits, uint32_t par, uint32
extern void ReaderTransmitPar(uint8_t *frame, int len, uint32_t par, uint32_t *timing);
extern int ReaderReceive(uint8_t *receivedAnswer);
extern int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr);
extern int ReaderReceiveDesfiresAuthTiming(uint8_t *receivedAnswer, uint32_t *elapsedTime);
extern void iso14443a_setup(uint8_t fpga_minor_mode);
extern int iso14_apdu(uint8_t *cmd, size_t cmd_len, void *data);

View file

@ -58,12 +58,12 @@
// *) document all the functions
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "util.h"
#include "apps.h"
#include "string.h"
#include "iso15693tools.h"
#include "cmd.h"
#include "../common/iso15693tools.h"
#include "../common/cmd.h"
#define arraylen(x) (sizeof(x)/sizeof((x)[0]))
@ -1275,12 +1275,8 @@ void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8
recvlen=SendDataTag(data,datalen,1,speed,(recv?&recvbuf:NULL));
if (recv) {
// n.cmd=/* CMD_ISO_15693_COMMAND_DONE */ CMD_ACK;
// n.arg[0]=recvlen>48?48:recvlen;
// memcpy(n.d.asBytes, recvbuf, 48);
LED_B_ON();
cmd_send(CMD_ACK,recvlen>48?48:recvlen,0,0,recvbuf,48);
// UsbSendPacket((uint8_t *)&n, sizeof(n));
LED_B_OFF();
if (DEBUG) {

View file

@ -8,14 +8,14 @@
// LEGIC RF simulation code
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "legicrf.h"
#include "legic_prng.h"
#include "crc.h"
#include "../include/legic_prng.h"
#include "../common/crc.h"
static struct legic_frame {
int bits;

View file

@ -8,12 +8,14 @@
// Also routines for raw mode reading/simulating of LF waveform
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "hitag2.h"
#include "crc16.h"
#include "../include/hitag2.h"
#include "../common/crc16.h"
#include "string.h"
#include "crapto1.h"
#include "mifareutil.h"
void LFSetupFPGAForADC(int divisor, bool lf_field)
{
@ -1146,6 +1148,15 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol)
#define WRITE_0 144 // 192
#define WRITE_1 400 // 432 for T55x7; 448 for E5550
// VALUES TAKEN FROM EM4x function: SendForward
// START_GAP = 440; //(55*8)
// WRITE_GAP = 128; //(16*8)
// WRITE_1 = 256 32*8; //32 cycles at 125Khz (8us each) 1
// //These timings work for 4469/4269/4305 (with the 55*8 above)
// WRITE_0 = 23*8 , 9*8 SpinDelayUs(23*8); // (8us each) 0
// Write one bit to card
void T55xxWriteBit(int bit)
{
@ -1207,13 +1218,15 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMod
// Read one card block in page 0
void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode)
{
uint8_t *dest = (uint8_t *)BigBuf;
int m=0, i=0;
uint8_t *dest = mifare_get_bigbufptr();
uint16_t bufferlength = 16000;
uint32_t i = 0;
// Clear destination buffer before sending the command 0x80 = average.
memset(dest, 0x80, bufferlength);
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
m = sizeof(BigBuf);
// Clear destination buffer before sending the command
memset(dest, 128, m);
// Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// Now set up the SSC to get the ADC samples that are now streaming at us.
@ -1254,31 +1267,33 @@ void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode)
for(;;) {
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
AT91C_BASE_SSC->SSC_THR = 0x43;
LED_D_ON();
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
// we don't care about actual value, only if it's more or less than a
// threshold essentially we capture zero crossings for later analysis
// if(dest[i] < 127) dest[i] = 0; else dest[i] = 1;
i++;
if (i >= m) break;
LED_D_OFF();
++i;
if (i > bufferlength) break;
}
}
cmd_send(CMD_ACK,0,0,0,0,0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
LED_D_OFF();
DbpString("DONE!");
}
// Read card traceability data (page 1)
void T55xxReadTrace(void){
uint8_t *dest = (uint8_t *)BigBuf;
int m=0, i=0;
uint8_t *dest = mifare_get_bigbufptr();
uint16_t bufferlength = 16000;
int i=0;
// Clear destination buffer before sending the command 0x80 = average
memset(dest, 0x80, bufferlength);
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
m = sizeof(BigBuf);
// Clear destination buffer before sending the command
memset(dest, 128, m);
// Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// Now set up the SSC to get the ADC samples that are now streaming at us.
@ -1309,17 +1324,20 @@ void T55xxReadTrace(void){
for(;;) {
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
AT91C_BASE_SSC->SSC_THR = 0x43;
LED_D_ON();
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
i++;
if (i >= m) break;
LED_D_OFF();
++i;
if (i >= bufferlength) break;
}
}
cmd_send(CMD_ACK,0,0,0,0,0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
LED_D_OFF();
DbpString("DONE!");
}
/*-------------- Cloning routines -----------*/
@ -1763,7 +1781,6 @@ int IsBlock1PCF7931(uint8_t *Block) {
return 0;
}
#define ALLOC 16
void ReadPCF7931() {
@ -2023,6 +2040,7 @@ void SendForward(uint8_t fwd_bit_count) {
}
}
void EM4xLogin(uint32_t Password) {
uint8_t fwd_bit_count;
@ -2040,9 +2058,14 @@ void EM4xLogin(uint32_t Password) {
void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
uint8_t *dest = mifare_get_bigbufptr();
uint16_t bufferlength = 16000;
uint32_t i = 0;
// Clear destination buffer before sending the command 0x80 = average.
memset(dest, 0x80, bufferlength);
uint8_t fwd_bit_count;
uint8_t *dest = (uint8_t *)BigBuf;
int m=0, i=0;
//If password mode do login
if (PwdMode == 1) EM4xLogin(Pwd);
@ -2051,9 +2074,6 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
fwd_bit_count = Prepare_Cmd( FWD_CMD_READ );
fwd_bit_count += Prepare_Addr( Address );
m = sizeof(BigBuf);
// Clear destination buffer before sending the command
memset(dest, 128, m);
// Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// Now set up the SSC to get the ADC samples that are now streaming at us.
@ -2069,10 +2089,12 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
i++;
if (i >= m) break;
++i;
if (i >= bufferlength) break;
}
}
cmd_send(CMD_ACK,0,0,0,0,0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
LED_D_OFF();
}

View file

@ -2,6 +2,9 @@
// Merlok - June 2011, 2012
// Gerhard de Koning Gans - May 2008
// Hagen Fritsch - June 2010
// Midnitesnake - Dec 2013
// Andy Davies - Apr 2014
// Iceman - May 2014
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
@ -12,9 +15,12 @@
#include "mifarecmd.h"
#include "apps.h"
#include "util.h"
#include "desfire.h"
#include "../common/crc.h"
//-----------------------------------------------------------------------------
// Select, Authenticate, Read a MIFARE tag.
// Select, Authenticaate, Read an MIFARE tag.
// read block
//-----------------------------------------------------------------------------
void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
@ -78,7 +84,72 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
void MifareUC_Auth1(uint8_t arg0, uint8_t *datain){
// variables
byte_t isOK = 0;
byte_t dataoutbuf[16];
uint8_t uid[10];
uint32_t cuid;
// clear trace
iso14a_clear_trace();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card, something went wrong before auth");
};
if(mifare_ultra_auth1(cuid, dataoutbuf)){
if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part1: Fail.");
}
isOK=1;
if (MF_DBGLEVEL >= 2) DbpString("AUTH 1 FINISHED");
LED_B_ON();
cmd_send(CMD_ACK,isOK,cuid,0,dataoutbuf,11);
LED_B_OFF();
// Thats it...
LEDsoff();
}
void MifareUC_Auth2(uint32_t arg0, uint8_t *datain){
// params
uint32_t cuid = arg0;
uint8_t key[16]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
// variables
byte_t isOK = 0;
byte_t dataoutbuf[16];
memcpy(key, datain, 16);
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
if(mifare_ultra_auth2(cuid, key, dataoutbuf)){
if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part2: Fail...");
}
isOK=1;
if (MF_DBGLEVEL >= 2) DbpString("AUTH 2 FINISHED");
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,11);
LED_B_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
void MifareUReadBlock(uint8_t arg0,uint8_t *datain)
@ -129,7 +200,6 @@ void MifareUReadBlock(uint8_t arg0,uint8_t *datain)
LEDsoff();
}
//-----------------------------------------------------------------------------
// Select, Authenticate, Read a MIFARE tag.
// read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes)
@ -198,15 +268,15 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
LEDsoff();
}
void MifareUReadCard(uint8_t arg0, uint8_t *datain)
void MifareUReadCard(uint8_t arg0, int arg1, uint8_t *datain)
{
// params
uint8_t sectorNo = arg0;
int Pages=arg1;
int count_Pages=0;
// variables
byte_t isOK = 0;
byte_t dataoutbuf[16 * 4];
byte_t dataoutbuf[44 * 4];
uint8_t uid[10];
uint32_t cuid;
@ -218,16 +288,18 @@ void MifareUReadCard(uint8_t arg0, uint8_t *datain)
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
Dbprintf("Pages %d",Pages);
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
for(int sec=0;sec<16;sec++){
for(int sec=0;sec<Pages;sec++){
if(mifare_ultra_readblock(cuid, sectorNo * 4 + sec, dataoutbuf + 4 * sec)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block %d error",sec);
break;
}else{
count_Pages++;
};
}
if(mifare_ultra_halt(cuid)) {
@ -238,11 +310,13 @@ void MifareUReadCard(uint8_t arg0, uint8_t *datain)
isOK = 1;
break;
}
Dbprintf("Pages read %d",count_Pages);
if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED");
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64);
if (Pages==16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64);
if (Pages==44 && count_Pages==16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64);
if (Pages==44 && count_Pages>16) cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,176);
LED_B_OFF();
// Thats it...

View file

@ -13,16 +13,15 @@
#ifndef __MIFARECMD_H
#define __MIFARECMD_H
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "iso14443crc.h"
#include "../common/iso14443crc.h"
#include "iso14443a.h"
#include "crapto1.h"
#include "mifareutil.h"
#include "common.h"
#include "../include/common.h"
#endif

568
armsrc/mifaredesfire.c Normal file
View file

@ -0,0 +1,568 @@
#include "mifaredesfire.h"
#define MAX_APPLICATION_COUNT 28
#define MAX_FILE_COUNT 16
#define MAX_FRAME_SIZE 60
#define NOT_YET_AUTHENTICATED 255
#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5)
//static uint8_t __msg[MAX_FRAME_SIZE] = { 0x0A, 0x00, 0x00, /* ..., */ 0x00 };
/* PCB CID CMD PAYLOAD */
//static uint8_t __res[MAX_FRAME_SIZE];
void MifareDesfireGetInformation(){
uint8_t len = 0;
uint8_t resp[RECV_RES_SIZE];
uint8_t dataout[RECV_CMD_SIZE];
byte_t buf[RECV_RES_SIZE];
memset(resp,0,sizeof(resp));
memset(dataout,0, sizeof(dataout));
memset(buf,0,sizeof(buf));
/*
1 = PCB 1
2 = cid 2
3 = desfire command 3
4-5 = crc 4 key
5-6 crc
PCB == 0x0A because sending CID byte.
CID == 0x00 first card?
*/
uint8_t cmd1[] = {0x0a,0x00,GET_VERSION, 0x00, 0x00 };
uint8_t cmd2[] = {0x0a,0x00,GET_KEY_VERSION, 0x00, 0x00, 0x00 };
iso14a_clear_trace();
iso14a_set_tracing(TRUE);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// card select - information
iso14a_card_select_t *card = (iso14a_card_select_t*)buf;
byte_t isOK = iso14443a_select_card(NULL, card, NULL);
if (isOK != 1) {
if (MF_DBGLEVEL >= 1) {
Dbprintf("Can't select card");
}
OnError();
return;
}
memcpy(dataout,card->uid,7);
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
// GET INFORMATION
AppendCrc14443a(cmd1, 3);
ReaderTransmit(cmd1, sizeof(cmd1), NULL);
len = ReaderReceive(resp);
if ( resp[2] != ADDITIONAL_FRAME) {
print_result("ERROR <--: ", resp, len);
OnError();
return;
}
memcpy(dataout+7,resp+3,7);
// ADDITION_FRAME 1
++cmd1[0];
cmd1[2] = ADDITIONAL_FRAME;
AppendCrc14443a(cmd1, 3);
ReaderTransmit(cmd1, sizeof(cmd1), NULL);
len = ReaderReceive(resp);
if ( resp[2] != ADDITIONAL_FRAME) {
print_result("ERROR <--: ", resp, len);
OnError();
return;
}
memcpy(dataout+7+7,resp+3,7);
// ADDITION_FRAME 2
--cmd1[0];
AppendCrc14443a(cmd1, 3);
ReaderTransmit(cmd1, sizeof(cmd1), NULL);
len = ReaderReceive(resp);
if ( resp[2] != OPERATION_OK) {
print_result("ERROR <--: ", resp, len);
OnError();
return;
}
memcpy(dataout+7+7+7,resp+3,14);
// GET MASTER KEYSETTINGS
cmd1[2] = GET_KEY_SETTINGS;
AppendCrc14443a(cmd1, 3);
ReaderTransmit(cmd1, sizeof(cmd1), NULL);
len = ReaderReceive(resp);
if (len){
memcpy(dataout+7+7+7+14,resp+3,2);
}
// GET MASTER KEY VERSION
AppendCrc14443a(cmd2, 4);
ReaderTransmit(cmd2, sizeof(cmd2), NULL);
len = ReaderReceive(resp);
if (len){
memcpy(dataout+7+7+7+14+2,resp+3,1);
}
// GET FREE MEMORY
cmd1[2] = GET_FREE_MEMORY;
AppendCrc14443a(cmd1, 3);
ReaderTransmit(cmd1, sizeof(cmd1), NULL);
len = ReaderReceive(resp);
if (len){
memcpy(dataout+7+7+7+14+2+1,resp+3,3);
}
cmd_send(CMD_ACK,1,0,0,dataout,sizeof(dataout));
OnSuccess();
}
void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain){
uint8_t null_key_data[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t new_key_data[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
int res;
MifareDESFireKey default_key = mifare_desfire_des_key_new_with_version (null_key_data);
res = mifare_desfire_select_application (tags[i], aid);
if (res < 0) {
freefare_perror (tags[i], "mifare_desfire_select_application");
error = EXIT_FAILURE;
break;
}
return;
// pcb cid cmd key crc1 cr2
//uint8_t cmd2[] = {0x02,0x00,GET_KEY_VERSION, 0x00, 0x00, 0x00 };
//uint8_t* bigbuffer = mifare_get_bigbufptr();
byte_t isOK = 1;
uint8_t resp[256];
uint8_t key[24];
uint8_t IV[16];
// första byten håller keylength.
uint8_t keylen = datain[0];
memcpy(key, datain+1, keylen);
if (MF_DBGLEVEL >= 1) {
Dbprintf("MODE: %d", mode);
Dbprintf("ALGO: %d", algo);
Dbprintf("KEYNO: %d", keyno);
Dbprintf("KEYLEN: %d", keylen);
print_result("KEY", key, keylen);
}
// card select - information
byte_t buf[USB_CMD_DATA_SIZE];
iso14a_card_select_t *card = (iso14a_card_select_t*)buf;
// test of DES on ARM side.
/*
if ( mode == 1){
uint8_t IV[8];
uint8_t plain[16];
uint8_t encData[16];
uint8_t tmpData[8];
uint8_t tmpPlain[8];
memset(IV, 0, 8);
memset(tmpData, 0 ,8);
memset(tmpPlain,0 ,8);
memcpy(key, datain, 8);
memcpy(plain, datain+30, 16);
for(uint8_t i=0; i< sizeof(plain); i=i+8 ){
memcpy(tmpPlain, plain+i, 8);
des_enc( &tmpData, &tmpPlain, &key);
memcpy(encData+i, tmpData, 8);
}
}
*/
iso14a_clear_trace();
iso14a_set_tracing(TRUE);
// power up the field
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// select the card
isOK = iso14443a_select_card(resp, card, NULL);
if (isOK != 1) {
if (MF_DBGLEVEL >= 1) {
Dbprintf("CAN'T SELECT CARD, SOMETHING WENT WRONG BEFORE AUTH");
}
OnError();
return;
}
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
// 3 olika sätt att authenticera. AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
// 4 olika crypto algo DES, 3DES, 3K3DES, AES
// 3 olika kommunikations sätt, PLAIN,MAC,CRYPTO
// des, nyckel 0,
switch (mode){
case 1:
// if ( SendDesfireCommand(AUTHENTICATE, &keyno, resp) > 0 ){
// // fick nonce från kortet
// }
break;
case 2:
//SendDesfireCommand(AUTHENTICATE_ISO, &keyno, resp);
break;
case 3:{
AesCtx ctx;
if ( AesCtxIni(&ctx, IV, key, KEY128, CBC) < 0 ){
if (MF_DBGLEVEL >= 1) {
Dbprintf("AES context failed to init");
}
OnError();
return;
}
uint8_t real_cmd[6];
real_cmd[0] = 0x90;
real_cmd[1] = 0x02;
real_cmd[2] = AUTHENTICATE_AES;
real_cmd[3] = keyno;
AppendCrc14443a(real_cmd, 2);
ReaderTransmit(real_cmd, sizeof(real_cmd), NULL);
int len = ReaderReceive(resp);
if(!len) {
OnError();
return;
}
print_result("RX:", resp, len);
enum DESFIRE_STATUS status = resp[1];
if ( status != ADDITIONAL_FRAME) {
OnError();
return;
}
// tags enc nonce
uint8_t encRndB[16];
uint8_t decRndB[16];
uint8_t nonce[16];
uint8_t both[32];
uint8_t encBoth[32];
memset(nonce, 0, 16);
memcpy( encRndB, resp+2, 16);
// dekryptera tagnonce.
AesDecrypt(&ctx, encRndB, decRndB, 16);
rol(decRndB,16);
memcpy(both, nonce,16);
memcpy(both+16, decRndB ,16 );
AesEncrypt(&ctx, both, encBoth, 32 );
uint8_t real_cmd_A[36];
real_cmd_A[0] = 0x03;
real_cmd_A[1] = ADDITIONAL_FRAME;
memcpy(real_cmd_A+2, encBoth, sizeof(encBoth) );
AppendCrc14443a(real_cmd_A, sizeof(real_cmd_A));
ReaderTransmit(real_cmd_A, sizeof(real_cmd_A), NULL);
len = ReaderReceive(resp);
print_result("Auth1a ", resp, 36);
status = resp[1];
if ( status != OPERATION_OK) {
Dbprintf("Cmd Error: %02x Len: %d", status,len);
OnError();
return;
}
break;
}
}
OnSuccess(resp);
}
// desfire_cmd = enum DESFIRE_CMD in desfire.h
// cmd = pointer to
// dataout = point to array for response data.
int SendDesfireCommand(enum DESFIRE_CMD desfire_cmd,uint8_t *dataout, uint8_t fromscratch){
uint8_t resp[80];
uint8_t len;
if ( fromscratch){
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// power up the field
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// select the card
iso14443a_select_card(NULL, NULL, NULL);
}
// 3 olika ISO sätt att skicka data till DESFIRE (direkt, inkapslat, inkapslat ISO)
uint8_t real_cmd[4];
real_cmd[0] = 0x02;
real_cmd[1] = desfire_cmd;
AppendCrc14443a(real_cmd, 2);
ReaderTransmit(real_cmd, sizeof(real_cmd), NULL);
len = ReaderReceive(resp);
if(!len)
return -1; //DATA LINK ERROR
if ( fromscratch){
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
}
enum DESFIRE_STATUS status = resp[1];
//1 bytes iso, 1 byte status, in the end: 2 bytes crc
if ( status == OPERATION_OK || status == ADDITIONAL_FRAME) {
memcpy(dataout, resp+2, 2);
return len;
}
else {
Dbprintf("unexpected desfire response: %X (to %X)", status, desfire_cmd);
return -status;
}
}
// crc_update(&desfire_crc32, 0, 1); /* CMD_WRITE */
// crc_update(&desfire_crc32, addr, addr_sz);
// crc_update(&desfire_crc32, byte, 8);
// uint32_t crc = crc_finish(&desfire_crc32);
/* Version
//uint8_t versionCmd1[] = {0x02, 0x60};
//uint8_t versionCmd2[] = {0x03, 0xaf};
//uint8_t versionCmd3[] = {0x02, 0xaf};
// AUTH 1 - CMD: 0x02, 0x0A, 0x00 = Auth
// 0x02 = status byte för simpla svar?!?
// 0x0a = krypto typ
// 0x00 = key nr
//uint8_t initAuthCmdDES[] = {0x02, 0x0a, 0x00}; // DES
//uint8_t initAuthCmd3DES[] = {0x02, 0x1a, 0x00}; // 3DES
//uint8_t initAuthCmdAES[] = {0x02, 0xaa, 0x00}; // AES
// auth 1 - answer command
// 0x03 = status byte för komplexa typer?
// 0xaf = additional frame
// LEN = 1+1+32+2 = 36
//uint8_t answerAuthCmd[34] = {0x03, 0xaf};
// Lägg till CRC
//AppendCrc14443a(versionCmd1,sizeof(versionCmd1));
*/
// Sending commands
/*ReaderTransmit(versionCmd1,sizeof(versionCmd1)+2, NULL);
len = ReaderReceive(buffer);
print_result("Get Version 3", buffer, 9);
*/
// for( int i = 0; i < 8; i++){
// // Auth 1 - Request authentication
// ReaderTransmit(initAuthCmdAES,sizeof(initAuthCmdAES)+2, NULL);
// //len = ReaderReceive(buffer);
// // 0xAE = authentication error
// if (buffer[1] == 0xae) {
// Dbprintf("Cmd Error: %02x", buffer[1]);
// OnError();
// return;
// }
// // tags enc nonce
// memcpy(encRndB, buffer+2, 16);
// // dekryptera svaret från tag.
// AesDecrypt(&ctx, encRndB, decRndB, 16);
// rol8(decRndB,16);
// memcpy(RndARndB, RndA,16);
// memcpy(RndARndB+16, decRndB ,16 );
// AesEncrypt(&ctx, RndARndB, encRndARndB, 32 );
// memcpy(answerAuthCmd+2, encRndARndB, 32);
// AppendCrc14443a(answerAuthCmd,sizeof(answerAuthCmd));
// ReaderTransmit(answerAuthCmd,sizeof(answerAuthCmd)+2, NULL);
// len = ReaderReceive(buffer);
// print_result("Auth1a ", buffer, 8);
// Dbprintf("Rx len: %02x", len);
// if (buffer[1] == 0xCA) {
// Dbprintf("Cmd Error: %02x Len: %d", buffer[1],len);
// cmd_send(CMD_ACK,0,0,0,0,0);
// key[1] = i;
// AesCtxIni(&ctx, iv, key, KEY128, CBC);
// }
// }
//des_dec(decRndB, encRndB, key);
//Do crypto magic
/*
DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0);
memcpy(RndARndB,RndA,8);
memcpy(RndARndB+8,RndB,8);
PrintAndLog(" RA+B:%s",sprint_hex(RndARndB, 16));
DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1);
PrintAndLog("enc(RA+B):%s",sprint_hex(RndARndB, 16));
*/
int mifare_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){
uint8_t* buffer = mifare_get_bigbufptr();
uint8_t dcmd[19];
dcmd[0] = 0xAF;
memcpy(dcmd+1,key,16);
AppendCrc14443a(dcmd, 17);
ReaderTransmit(dcmd, sizeof(dcmd), NULL);
int len = ReaderReceive(buffer);
if(!len) {
if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout.");
len = ReaderReceive(buffer);
}
if(len==1) {
if (MF_DBGLEVEL >= 1) {
Dbprintf("NAK - Authentication failed.");
Dbprintf("Cmd Error: %02x", buffer[0]);
}
return 1;
}
if (len == 11){
if (MF_DBGLEVEL >= 1) {
Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],
buffer[5],buffer[6],buffer[7],buffer[8],buffer[9],
buffer[10]);
}
return 0;
}
return 1;
}
void MifareDES_Auth2(uint32_t arg0, uint8_t *datain){
return;
uint32_t cuid = arg0;
uint8_t key[16];
byte_t isOK = 0;
byte_t dataoutbuf[16];
memset(key, 0, 16);
memcpy(key, datain, 16);
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
if(mifare_des_auth2(cuid, key, dataoutbuf)){
if (MF_DBGLEVEL >= 1) Dbprintf("Authentication part2: Fail...");
}
isOK=1;
if (MF_DBGLEVEL >= 2) DbpString("AUTH 2 FINISHED");
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,11);
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
// CreateAPDU
uint8_t* CreateAPDU( uint8_t *datain, size_t len){
len = MIN(len, USB_CMD_DATA_SIZE);
uint8_t tmpcmd[len];
uint8_t *cmd = tmpcmd;
memset(cmd, 0, len);
cmd[0] = 0x0a;
cmd[1] = 0x00;
memcpy(cmd, datain,len);
AppendCrc14443a(cmd, len+2);
return cmd;
}
void SelectCard(){
uint8_t resp[RECV_RES_SIZE];
byte_t buf[RECV_RES_SIZE];
memset(resp,0,sizeof(resp));
memset(buf,0,sizeof(buf));
iso14a_clear_trace();
iso14a_set_tracing(TRUE);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// card select - information
iso14a_card_select_t *card = (iso14a_card_select_t*)buf;
byte_t isOK = iso14443a_select_card(NULL, card, NULL);
if (isOK != 1) {
if (MF_DBGLEVEL >= 1) {
Dbprintf("Can't select card");
}
OnError();
return;
}
}
void OnSuccess(){
// Deselect card by sending a s-block. the crc is precalced for speed
uint8_t cmd[] = {0xc2,0xe0,0xb4};
ReaderTransmit(cmd, sizeof(cmd), NULL);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
void OnError(){
cmd_send(CMD_ACK,0,0,0,0,0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}

16
armsrc/mifaredesfire.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef __MIFAREDESFIRE_H
#define __MIFAREDESFIRE_H
#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "../common/iso14443crc.h"
#include "iso14443a.h"
#include "crapto1.h"
#include "mifareutil.h"
#include "../include/common.h"
#endif

View file

@ -11,16 +11,16 @@
#ifndef __MIFARESNIFF_H
#define __MIFARESNIFF_H
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "iso14443crc.h"
#include "../common/iso14443crc.h"
#include "iso14443a.h"
#include "crapto1.h"
#include "mifareutil.h"
#include "common.h"
#include "../include/common.h"
#define SNF_INIT 0
#define SNF_NO_FIELD 1

View file

@ -9,12 +9,12 @@
// Work with mifare cards.
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "iso14443crc.h"
#include "../common/iso14443crc.h"
#include "iso14443a.h"
#include "crapto1.h"
#include "mifareutil.h"
@ -84,26 +84,36 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd,
int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *timing)
{
uint8_t dcmd[8];//, ecmd[4];
//uint32_t par=0;
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];
memcpy(dcmd+1,data,5);
AppendCrc14443a(dcmd, 6);
//Dbprintf("Data command: %02x", dcmd[0]);
//Dbprintf("Data R: %02x %02x %02x %02x %02x %02x %02x", dcmd[1],dcmd[2],dcmd[3],dcmd[4],dcmd[5],dcmd[6],dcmd[7]);
//memcpy(ecmd, dcmd, sizeof(dcmd));
ReaderTransmit(dcmd, sizeof(dcmd), NULL);
int len = ReaderReceive(answer);
if(!len)
{
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, 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);
if(!len) {
if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout.");
len = ReaderReceive(answer);
}
if(len==1) {
if (MF_DBGLEVEL >= 1) Dbprintf("NAK - Authentication failed.");
return 1;
}
return len;
}
@ -280,6 +290,55 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo
memcpy(blockData, receivedAnswer, 16);
return 0;
}
int mifare_ultra_auth1(uint32_t uid, uint8_t *blockData){
// variables
int len;
uint8_t* receivedAnswer = mifare_get_bigbufptr();
// command MIFARE_CLASSIC_READBLOCK
len = mifare_sendcmd_short(NULL, 1, 0x1A, 0x00, receivedAnswer,NULL);
if (len == 1) {
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1;
}
if (len == 11) {
if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4],
receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9],
receivedAnswer[10]);
memcpy(blockData, receivedAnswer, 11);
return 0;
}
//else something went wrong???
return 1;
}
int mifare_ultra_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){
// variables
int len;
uint8_t* receivedAnswer = mifare_get_bigbufptr();
// command MIFARE_CLASSIC_READBLOCK
len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, key, receivedAnswer,NULL);
if (len == 1) {
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1;
}
if (len == 11){
if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4],
receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9],
receivedAnswer[10]);
memcpy(blockData, receivedAnswer, 11);
return 0;
}
//something went wrong?
return 1;
}
int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData)

View file

@ -56,6 +56,7 @@ extern int MF_DBGLEVEL;
uint8_t* mifare_get_bigbufptr(void);
int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t *timing);
int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* amswer, uint8_t *timing);
int mifare_sendcmd_short_mfucauth(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* amswer, uint32_t *timing);
int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr, uint32_t *timing);
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, \
@ -63,6 +64,8 @@ int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, \
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, \
uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_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_ultra_auth1(uint32_t cuid, uint8_t *blockData);
int mifare_ultra_auth2(uint32_t cuid, uint8_t *key, uint8_t *blockData);
int mifare_ultra_readblock(uint32_t uid, 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(uint32_t uid, uint8_t blockNo, uint8_t *blockData);

View file

@ -9,7 +9,7 @@
// with the linker script.
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "apps.h"
extern char __data_start__, __data_src_start__, __data_end__, __bss_start__, __bss_end__;

View file

@ -48,6 +48,11 @@ int memcmp(const void *av, const void *bv, int len)
return 0;
}
void memxor(uint8_t * dest, uint8_t * src, size_t len) {
for( ; len > 0; len--,dest++,src++)
*dest ^= *src;
}
int strlen(const char *str)
{
int l = 0;

View file

@ -12,10 +12,14 @@
#ifndef __STRING_H
#define __STRING_H
#include <stdint.h>
#include <util.h>
int strlen(const char *str);
void *memcpy(void *dest, const void *src, int len);
void *memset(void *dest, int c, int len);
int memcmp(const void *av, const void *bv, int len);
void memxor(uint8_t * dest, uint8_t * src, size_t len);
char *strncat(char *dest, const char *src, unsigned int n);
char *strcat(char *dest, const char *src);
void strreverse(char s[]);

View file

@ -8,11 +8,31 @@
// Utility functions used in many places, not specific to any piece of code.
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include "util.h"
#include "string.h"
#include "apps.h"
void print_result(char *name, uint8_t *buf, size_t len) {
uint8_t *p = buf;
if ( len % 16 == 0 ) {
for(; p-buf < len; p += 16)
Dbprintf("[%s:%02x/%02x] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
name,
p-buf,
len,
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]
);
}
else {
for(; p-buf < len; p += 8)
Dbprintf("[%s:%02x/%02x] %02x %02x %02x %02x %02x %02x %02x %02x", name, p-buf, len, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
}
}
size_t nbytes(size_t nbits) {
return (nbits/8)+((nbits%8)>0);
}
@ -45,6 +65,26 @@ uint64_t bytes_to_num(uint8_t* src, size_t len)
return num;
}
// RotateLeft - Ultralight, Desfire
void rol(uint8_t *data, const size_t len){
uint8_t first = data[0];
for (size_t i = 0; i < len-1; i++) {
data[i] = data[i+1];
}
data[len-1] = first;
}
void lsl (uint8_t *data, size_t len) {
for (size_t n = 0; n < len - 1; n++) {
data[n] = (data[n] << 1) | (data[n+1] >> 7);
}
data[len - 1] <<= 1;
}
int32_t le24toh (uint8_t data[3])
{
return (data[2] << 16) | (data[1] << 8) | data[0];
}
void LEDsoff()
{
LED_A_OFF();

View file

@ -13,7 +13,7 @@
#include <stddef.h>
#include <stdint.h>
#include <common.h>
#include "../include/common.h"
#define BYTEx(x, n) (((x) >> (n * 8)) & 0xff )
@ -27,10 +27,14 @@
#define BUTTON_DOUBLE_CLICK -2
#define BUTTON_ERROR -99
void print_result(char *name, uint8_t *buf, size_t len);
size_t nbytes(size_t nbits);
uint32_t SwapBits(uint32_t value, int nrbits);
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t bytes_to_num(uint8_t* src, size_t len);
void rol(uint8_t *data, const size_t len);
void lsl (uint8_t *data, size_t len);
int32_t le24toh (uint8_t data[3]);
void SpinDelay(int ms);
void SpinDelayUs(int us);

View file

@ -13,23 +13,16 @@ CXX=g++
VPATH = ../common
OBJDIR = obj
LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread ../liblua/liblua.a
LDLIBS = -L/mingw/lib -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lreadline -lpthread -lcrypto -lgdi32
LDFLAGS = $(COMMON_FLAGS)
CFLAGS = -std=c99 -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4
CFLAGS = -std=c99 -I. -I../include -I../common -I/mingw/include -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 $(ICE_FLAGS)
LUAPLATFORM = generic
ifneq (,$(findstring MINGW,$(platform)))
CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui
QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4
CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui -I$(QTDIR)/include/QtWidgets
QTLDLIBS = -L$(QTDIR)/lib -lQt5Core -lQt5Gui -lQt5Widgets
MOC = $(QTDIR)/bin/moc
LUAPLATFORM = mingw
else ifeq ($(platform),Darwin)
#CXXFLAGS = -I/Library/Frameworks/QtGui.framework/Versions/Current/Headers -I/Library/Frameworks/QtCore.framework/Versions/Current/Headers
#QTLDLIBS = -framework QtGui -framework QtCore
CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui
QTLDLIBS = -F/opt/local/Library/Frameworks -framework QtGui -framework QtCore
MOC = moc
LUAPLATFORM = macosx
else
CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4
QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null)
@ -58,6 +51,12 @@ CORESRCS = uart.c \
CMDSRCS = nonce2key/crapto1.c\
nonce2key/crypto1.c\
nonce2key/nonce2key.c\
loclass/cipher.c \
loclass/cipherutils.c \
loclass/des.c \
loclass/ikeys.c \
loclass/elite_crack.c\
loclass/fileutils.c\
mifarehost.c\
crc16.c \
iso14443crc.c \
@ -74,6 +73,9 @@ CMDSRCS = nonce2key/crapto1.c\
cmdhflegic.c \
cmdhficlass.c \
cmdhfmf.c \
cmdhfmfu.c \
cmdhfmfdes.c \
cmdhfdes.c \
cmdhw.c \
cmdlf.c \
cmdlfhid.c \

View file

@ -22,6 +22,9 @@
#include "cmdhflegic.h"
#include "cmdhficlass.h"
#include "cmdhfmf.h"
#include "cmdhfmfu.h"
#include "cmdhfmfdes.h"
#include "cmdhfdes.h"
static int CmdHelp(const char *Cmd);
@ -42,6 +45,9 @@ static command_t CommandTable[] =
{"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"},
{"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"},
{"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"},
{"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"},
{"mfdes", CmdHFMFDes, 1, "{ MIFARE Desfire RFIDs... }"},
{"des", CmdHFDES, 0, "{ MIFARE DESfire}"},
{"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"},
{NULL, NULL, 0, NULL}
};

View file

@ -14,15 +14,15 @@
#include <string.h>
#include <unistd.h>
#include "util.h"
#include "iso14443crc.h"
#include "../common/iso14443crc.h"
#include "data.h"
#include "proxmark3.h"
#include "ui.h"
#include "cmdparser.h"
#include "cmdhf14a.h"
#include "common.h"
#include "../include/common.h"
#include "cmdmain.h"
#include "mifare.h"
#include "../include/mifare.h"
static int CmdHelp(const char *Cmd);
static void waitCmd(uint8_t iLen);
@ -183,27 +183,24 @@ void iso14a_set_timeout(uint32_t timeout) {
int CmdHF14AReader(const char *Cmd)
{
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
iso14a_card_select_t *card = (iso14a_card_select_t *)resp.d.asBytes;
uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS
if(select_status == 0) {
if(resp.arg[0] == 0) {
PrintAndLog("iso14443a card select failed");
return 0;
}
PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen));
PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]);
PrintAndLog("ATQA : %02x %02x", card->atqa[0], card->atqa[1]);
PrintAndLog(" UID : %s", sprint_hex(card->uid, card->uidlen));
PrintAndLog(" SAK : %02x [%d]", card->sak, resp.arg[0]);
switch (card.sak) {
switch (card->sak) {
case 0x00: PrintAndLog("TYPE : NXP MIFARE Ultralight | Ultralight C"); break;
case 0x04: PrintAndLog("TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); break;
case 0x08: PrintAndLog("TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1"); break;
@ -219,107 +216,67 @@ int CmdHF14AReader(const char *Cmd)
case 0x98: PrintAndLog("TYPE : Gemplus MPCOS"); break;
default: ;
}
// try to request ATS even if tag claims not to support it
if (select_status == 2) {
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT;
c.arg[1] = 2;
c.arg[2] = 0;
memcpy(c.d.asBytes, rats, 2);
SendCommand(&c);
WaitForResponse(CMD_ACK,&resp);
memcpy(&card.ats, resp.d.asBytes, resp.arg[0]);
card.ats_len = resp.arg[0]; // note: ats_len includes CRC Bytes
}
// disconnect
c.arg[0] = 0;
c.arg[1] = 0;
c.arg[2] = 0;
SendCommand(&c);
if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
if(resp.arg[0] == 1) {
bool ta1 = 0, tb1 = 0, tc1 = 0;
int pos;
if (select_status == 2) {
PrintAndLog("SAK incorrectly claims that card doesn't support RATS");
PrintAndLog(" ATS : %s", sprint_hex(card->ats, card->ats_len));
if (card->ats_len > 0) {
PrintAndLog(" - TL : length is %d bytes", card->ats[0]);
}
PrintAndLog(" ATS : %s", sprint_hex(card.ats, card.ats_len));
PrintAndLog(" - TL : length is %d bytes", card.ats[0]);
if (card.ats[0] != card.ats_len - 2) {
PrintAndLog("ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len);
}
if (card.ats[0] > 1) { // there is a format byte (T0)
ta1 = (card.ats[1] & 0x10) == 0x10;
tb1 = (card.ats[1] & 0x20) == 0x20;
tc1 = (card.ats[1] & 0x40) == 0x40;
int16_t fsci = card.ats[1] & 0x0f;
if (card->ats_len > 1) {
ta1 = (card->ats[1] & 0x10) == 0x10;
tb1 = (card->ats[1] & 0x20) == 0x20;
tc1 = (card->ats[1] & 0x40) == 0x40;
PrintAndLog(" - T0 : TA1 is%s present, TB1 is%s present, "
"TC1 is%s present, FSCI is %d (FSC = %ld)",
"TC1 is%s present, FSCI is %d",
(ta1 ? "" : " NOT"), (tb1 ? "" : " NOT"), (tc1 ? "" : " NOT"),
fsci,
fsci < 5 ? (fsci - 2) * 8 :
fsci < 8 ? (fsci - 3) * 32 :
fsci == 8 ? 256 :
-1
);
(card->ats[1] & 0x0f));
}
pos = 2;
if (ta1) {
if (ta1 && card->ats_len > pos) {
char dr[16], ds[16];
dr[0] = ds[0] = '\0';
if (card.ats[pos] & 0x10) strcat(ds, "2, ");
if (card.ats[pos] & 0x20) strcat(ds, "4, ");
if (card.ats[pos] & 0x40) strcat(ds, "8, ");
if (card.ats[pos] & 0x01) strcat(dr, "2, ");
if (card.ats[pos] & 0x02) strcat(dr, "4, ");
if (card.ats[pos] & 0x04) strcat(dr, "8, ");
if (card->ats[pos] & 0x10) strcat(ds, "2, ");
if (card->ats[pos] & 0x20) strcat(ds, "4, ");
if (card->ats[pos] & 0x40) strcat(ds, "8, ");
if (card->ats[pos] & 0x01) strcat(dr, "2, ");
if (card->ats[pos] & 0x02) strcat(dr, "4, ");
if (card->ats[pos] & 0x04) strcat(dr, "8, ");
if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0';
if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0';
PrintAndLog(" - TA1 : different divisors are%s supported, "
"DR: [%s], DS: [%s]",
(card.ats[pos] & 0x80 ? " NOT" : ""), dr, ds);
(card->ats[pos] & 0x80 ? " NOT" : ""), dr, ds);
pos++;
}
if (tb1) {
uint32_t sfgi = card.ats[pos] & 0x0F;
uint32_t fwi = card.ats[pos] >> 4;
PrintAndLog(" - TB1 : SFGI = %d (SFGT = %s%ld/fc), FWI = %d (FWT = %ld/fc)",
(sfgi),
sfgi ? "" : "(not needed) ",
sfgi ? (1 << 12) << sfgi : 0,
fwi,
(1 << 12) << fwi
);
if (tb1 && card->ats_len > pos) {
PrintAndLog(" - TB1 : SFGI = %d, FWI = %d",
(card->ats[pos] & 0x08),
(card->ats[pos] & 0x80) >> 4);
pos++;
}
if (tc1) {
if (tc1 && card->ats_len > pos) {
PrintAndLog(" - TC1 : NAD is%s supported, CID is%s supported",
(card.ats[pos] & 0x01) ? "" : " NOT",
(card.ats[pos] & 0x02) ? "" : " NOT");
(card->ats[pos] & 0x01) ? "" : " NOT",
(card->ats[pos] & 0x02) ? "" : " NOT");
pos++;
}
if (card.ats[0] > pos) {
if (card->ats_len > pos) {
char *tip = "";
if (card.ats[0] - pos >= 7) {
if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
if (card->ats_len - pos > 7) {
if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
tip = "-> MIFARE Plus X 2K or 4K";
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
} else if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
tip = "-> MIFARE Plus S 2K or 4K";
}
}
PrintAndLog(" - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip);
if (card.ats[pos] == 0xC1) {
PrintAndLog(" - HB : %s%s", sprint_hex(card->ats + pos, card->ats_len - pos - 2), tip);
if (card->ats[pos] == 0xC1) {
PrintAndLog(" c1 -> Mifare or (multiple) virtual cards of various type");
PrintAndLog(" %02x -> Length is %d bytes",
card.ats[pos + 1], card.ats[pos + 1]);
switch (card.ats[pos + 2] & 0xf0) {
card->ats[pos + 1], card->ats[pos + 1]);
switch (card->ats[pos + 2] & 0xf0) {
case 0x10:
PrintAndLog(" 1x -> MIFARE DESFire");
break;
@ -327,7 +284,7 @@ int CmdHF14AReader(const char *Cmd)
PrintAndLog(" 2x -> MIFARE Plus");
break;
}
switch (card.ats[pos + 2] & 0x0f) {
switch (card->ats[pos + 2] & 0x0f) {
case 0x00:
PrintAndLog(" x0 -> <1 kByte");
break;
@ -344,7 +301,7 @@ int CmdHF14AReader(const char *Cmd)
PrintAndLog(" x0 -> 8 kByte");
break;
}
switch (card.ats[pos + 3] & 0xf0) {
switch (card->ats[pos + 3] & 0xf0) {
case 0x00:
PrintAndLog(" 0x -> Engineering sample");
break;
@ -352,7 +309,7 @@ int CmdHF14AReader(const char *Cmd)
PrintAndLog(" 2x -> Released");
break;
}
switch (card.ats[pos + 3] & 0x0f) {
switch (card->ats[pos + 3] & 0x0f) {
case 0x00:
PrintAndLog(" x0 -> Generation 1");
break;
@ -363,7 +320,7 @@ int CmdHF14AReader(const char *Cmd)
PrintAndLog(" x2 -> Generation 3");
break;
}
switch (card.ats[pos + 4] & 0x0f) {
switch (card->ats[pos + 4] & 0x0f) {
case 0x00:
PrintAndLog(" x0 -> Only VCSL supported");
break;
@ -377,10 +334,10 @@ int CmdHF14AReader(const char *Cmd)
}
}
} else {
PrintAndLog("proprietary non iso14443-4 card found, RATS not supported");
PrintAndLog("proprietary non iso14443a-4 card found, RATS not supported");
}
return select_status;
return resp.arg[0];
}
// Collect ISO14443 Type A UIDs
@ -402,17 +359,20 @@ int CmdHF14ACUIDs(const char *Cmd)
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
iso14a_card_select_t *card = (iso14a_card_select_t *) resp.d.asBytes;
uint8_t *uid = resp.d.asBytes;
iso14a_card_select_t *card = (iso14a_card_select_t *)(uid + 12);
// check if command failed
if (resp.arg[0] == 0) {
PrintAndLog("Card select failed.");
} else {
char uid_string[20];
for (uint16_t i = 0; i < card->uidlen; i++) {
sprintf(&uid_string[2*i], "%02X", card->uid[i]);
// check if UID is 4 bytes
if ((card->atqa[1] & 0xC0) == 0) {
PrintAndLog("%02X%02X%02X%02X",
*uid, *(uid + 1), *(uid + 2), *(uid + 3));
} else {
PrintAndLog("UID longer than 4 bytes");
}
PrintAndLog("%s", uid_string);
}
}
PrintAndLog("End: %u", time(NULL));
@ -466,10 +426,6 @@ int CmdHF14ASim(const char *Cmd)
// At lease save the mandatory first part of the UID
c.arg[0] = long_uid & 0xffffffff;
// At lease save the mandatory first part of the UID
c.arg[0] = long_uid & 0xffffffff;
if (c.arg[1] == 0) {
PrintAndLog("Emulating ISO/IEC 14443 type A tag with UID %01d %08x %08x",c.arg[0],c.arg[1],c.arg[2]);
}
@ -537,19 +493,22 @@ int CmdHF14ACmdRaw(const char *cmd) {
uint8_t active=0;
uint8_t active_select=0;
uint16_t numbits=0;
uint16_t timeout=0;
uint8_t bTimeout=0;
char buf[5]="";
int i=0;
uint8_t data[100];
uint8_t data[USB_CMD_DATA_SIZE];
unsigned int datalen=0, temp;
if (strlen(cmd)<2) {
PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] <number of bits> <0A 0B 0C ... hex>");
PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] [-t] <number of bits> <0A 0B 0C ... hex>");
PrintAndLog(" -r do not read response");
PrintAndLog(" -c calculate and append CRC");
PrintAndLog(" -p leave the signal field ON after receive");
PrintAndLog(" -a active signal field ON without select");
PrintAndLog(" -s active signal field ON with select");
PrintAndLog(" -b number of bits to send. Useful for send partial byte");
PrintAndLog(" -t timeout");
return 0;
}
@ -582,6 +541,14 @@ int CmdHF14ACmdRaw(const char *cmd) {
while(cmd[i]!=' ' && cmd[i]!='\0') { i++; }
i-=2;
break;
case 't':
bTimeout=1;
sscanf(cmd+i+2,"%d",&temp);
timeout = temp & 0xFFFF;
i+=3;
while(cmd[i]!=' ' && cmd[i]!='\0') { i++; }
i+=2;
break;
default:
PrintAndLog("Invalid option");
return 0;
@ -599,15 +566,19 @@ int CmdHF14ACmdRaw(const char *cmd) {
if (strlen(buf)>=2) {
sscanf(buf,"%x",&temp);
data[datalen]=(uint8_t)(temp & 0xff);
datalen++;
*buf=0;
if (++datalen>sizeof(data)){
if (crc)
PrintAndLog("Buffer is full, we can't add CRC to your data");
break;
}
}
continue;
}
PrintAndLog("Invalid char on input");
return 0;
}
if(crc && datalen>0)
if(crc && datalen>0 && datalen<sizeof(data)-2)
{
uint8_t first, second;
ComputeCrc14443(CRC_14443_A, data, datalen, &first, &second);
@ -621,13 +592,22 @@ int CmdHF14ACmdRaw(const char *cmd) {
if(active)
c.arg[0] |= ISO14A_NO_SELECT;
}
if(bTimeout){
#define MAX_TIMEOUT 624*105 // max timeout is 624 ms
c.arg[0] |= ISO14A_SET_TIMEOUT;
c.arg[2] = timeout * 105; // each bit is about 9.4 us
if(c.arg[2]>MAX_TIMEOUT) {
c.arg[2] = MAX_TIMEOUT;
PrintAndLog("Set timeout to 624 ms. The max we can wait for response");
}
}
if(power)
c.arg[0] |= ISO14A_NO_DISCONNECT;
if(datalen>0)
c.arg[0] |= ISO14A_RAW;
c.arg[1] = datalen;
c.arg[2] = numbits;
// Max buffer is USB_CMD_DATA_SIZE
c.arg[1] = (datalen & 0xFFFF) | (numbits << 16);
memcpy(c.d.asBytes,data,datalen);
SendCommand(&c);

View file

@ -13,8 +13,7 @@
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include "iso14443crc.h"
//#include "proxusb.h"
#include "../common/iso14443crc.h"
#include "proxmark3.h"
#include "data.h"
#include "graph.h"

View file

@ -33,7 +33,7 @@
#include "ui.h"
#include "cmdparser.h"
#include "cmdhf15.h"
#include "iso15693tools.h"
#include "../common/iso15693tools.h"
#include "cmdmain.h"
#define FrameSOF Iso15693FrameSOF

69
client/cmdhfdes.c Normal file
View file

@ -0,0 +1,69 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2012 nuit
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE DESfire commands
//-----------------------------------------------------------------------------
#include "cmdhfdes.h"
#include "proxmark3.h"
#include "cmdmain.h"
static int CmdHelp(const char *Cmd);
int CmdHFDESReader(const char *Cmd)
{
UsbCommand c ={CMD_MIFARE_DES_READER, {3, 0x60, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponseTimeout(CMD_ACK,&resp,2000);
return 0;
}
int CmdHFDESDbg(const char *Cmd)
{
int dbgMode = param_get32ex(Cmd, 0, 0, 10);
if (dbgMode > 4) {
PrintAndLog("Max debud mode parameter is 4 \n");
}
if (strlen(Cmd) < 1 || !param_getchar(Cmd, 0) || dbgMode > 4) {
PrintAndLog("Usage: hf des dbg <debug level>");
PrintAndLog(" 0 - no debug messages");
PrintAndLog(" 1 - error messages");
PrintAndLog(" 2 - all messages");
PrintAndLog(" 4 - extended debug mode");
return 0;
}
UsbCommand c = {CMD_MIFARE_SET_DBGMODE, {dbgMode, 0, 0}};
SendCommand(&c);
return 0;
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"dbg", CmdHFDESDbg, 0, "Set default debug mode"},
{"reader", CmdHFDESReader, 0, "Reader"},
{NULL, NULL, 0, NULL}
};
int CmdHFDES(const char *Cmd)
{
//flush
WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd);
return 0;
}
int CmdHelp(const char *Cmd)
{
CmdsHelp(CommandTable);
return 0;
}

27
client/cmdhfdes.h Normal file
View file

@ -0,0 +1,27 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2012 nuit
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE DESfire commands
//-----------------------------------------------------------------------------
#ifndef CMDHFDES_H__
#define CMDHFDES_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "proxmark3.h"
#include "data.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
#include "util.h"
int CmdHFDES(const char *Cmd);
int CmdHFDESReader(const char *Cmd);
int CmdHFDESDbg(const char *Cmd);
#endif

View file

@ -13,7 +13,7 @@
#include "proxmark3.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
#include "../include/common.h"
#include "cmdmain.h"
#include "sleep.h"
#include "cmdhfepa.h"

View file

@ -1,6 +1,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
// Copyright (C) 2011 Gerhard de Koning Gans
// Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
@ -15,14 +16,19 @@
#include <sys/stat.h>
#include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
#include "data.h"
//#include "proxusb.h"
#include "proxmark3.h"
#include "ui.h"
#include "cmdparser.h"
#include "cmdhficlass.h"
#include "common.h"
#include "../include/common.h"
#include "util.h"
#include "cmdmain.h"
#include "loclass/des.h"
#include "loclass/cipherutils.h"
#include "loclass/cipher.h"
#include "loclass/ikeys.h"
#include "loclass/elite_crack.h"
#include "loclass/fileutils.h"
static int CmdHelp(const char *Cmd);
@ -290,11 +296,6 @@ int CmdHFiClassListOld(const char *Cmd)
return 0;
}
/*void iso14a_set_timeout(uint32_t timeout) {
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_SET_TIMEOUT, 0, timeout}};
SendCommand(&c);
}*/
int CmdHFiClassSnoop(const char *Cmd)
{
UsbCommand c = {CMD_SNOOP_ICLASS};
@ -393,37 +394,255 @@ int CmdHFiClassSim(const char *Cmd)
memcpy(c.d.asBytes, CSN, 8);
SendCommand(&c);
}
return 0;
}
int CmdHFiClassReader(const char *Cmd)
{
uint8_t readerType = 0;
if (strlen(Cmd)<1) {
PrintAndLog("Usage: hf iclass reader <reader type>");
PrintAndLog(" sample: hf iclass reader 0");
return 0;
}
readerType = param_get8(Cmd, 0);
PrintAndLog("--readertype:%02x", readerType);
UsbCommand c = {CMD_READER_ICLASS, {readerType}};
//memcpy(c.d.asBytes, CSN, 8);
UsbCommand c = {CMD_READER_ICLASS, {0}};
SendCommand(&c);
UsbCommand resp;
while(!ukbhit()){
if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
uint8_t isOK = resp.arg[0] & 0xff;
uint8_t * data = resp.d.asBytes;
/*UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500);
if (resp != NULL) {
uint8_t isOK = resp->arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}*/
PrintAndLog("isOk:%02x", isOK);
if(isOK > 0)
{
PrintAndLog("CSN: %s",sprint_hex(data,8));
}
if(isOK >= 1)
{
PrintAndLog("CC: %s",sprint_hex(data+8,8));
}else{
PrintAndLog("No CC obtained");
}
} else {
PrintAndLog("Command execute timeout");
}
}
return 0;
}
int CmdHFiClassReader_Replay(const char *Cmd)
{
uint8_t readerType = 0;
uint8_t MAC[4]={0x00, 0x00, 0x00, 0x00};
if (strlen(Cmd)<1) {
PrintAndLog("Usage: hf iclass replay <MAC>");
PrintAndLog(" sample: hf iclass replay 00112233");
return 0;
}
if (param_gethex(Cmd, 0, MAC, 8)) {
PrintAndLog("MAC must include 8 HEX symbols");
return 1;
}
UsbCommand c = {CMD_READER_ICLASS_REPLAY, {readerType}};
memcpy(c.d.asBytes, MAC, 4);
SendCommand(&c);
return 0;
}
int CmdHFiClassReader_Dump(const char *Cmd)
{
uint8_t readerType = 0;
uint8_t MAC[4]={0x00,0x00,0x00,0x00};
uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t CCNR[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
//uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t keytable[128] = {0};
int elite = 0;
uint8_t *used_key;
int i;
if (strlen(Cmd)<1)
{
PrintAndLog("Usage: hf iclass dump <Key> [e]");
PrintAndLog(" Key - A 16 byte master key");
PrintAndLog(" e - If 'e' is specified, the key is interpreted as the 16 byte");
PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack");
PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
PrintAndLog(" sample: hf iclass dump 0011223344556677");
return 0;
}
if (param_gethex(Cmd, 0, KEY, 16)) {
PrintAndLog("KEY must include 16 HEX symbols");
return 1;
}
if (param_getchar(Cmd, 1) == 'e')
{
PrintAndLog("Elite switch on");
elite = 1;
//calc h2
hash2(KEY, keytable);
printarr_human_readable("keytable", keytable, 128);
}
UsbCommand c = {CMD_READER_ICLASS, {0}};
c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE;
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
uint8_t isOK = resp.arg[0] & 0xff;
uint8_t * data = resp.d.asBytes;
memcpy(CSN,data,8);
memcpy(CCNR,data+8,8);
PrintAndLog("isOk:%02x", isOK);
if(isOK > 0)
{
PrintAndLog("CSN: %s",sprint_hex(CSN,8));
}
if(isOK > 1)
{
if(elite)
{
uint8_t key_sel[8] = {0};
uint8_t key_sel_p[8] = { 0 };
//Get the key index (hash1)
uint8_t key_index[8] = {0};
hash1(CSN, key_index);
printvar("hash1", key_index,8);
for(i = 0; i < 8 ; i++)
key_sel[i] = keytable[key_index[i]] & 0xFF;
printvar("k_sel", key_sel,8);
//Permute from iclass format to standard format
permutekey_rev(key_sel,key_sel_p);
used_key = key_sel_p;
}else{
//Perhaps this should also be permuted to std format?
// Something like the code below? I have no std system
// to test this with /Martin
//uint8_t key_sel_p[8] = { 0 };
//permutekey_rev(KEY,key_sel_p);
//used_key = key_sel_p;
used_key = KEY;
}
printvar("Used key",used_key,8);
diversifyKey(CSN,used_key, div_key);
printvar("Div key", div_key, 8);
printvar("CC_NR:",CCNR,12);
doMAC(CCNR,12,div_key, MAC);
printvar("MAC", MAC, 4);
UsbCommand d = {CMD_READER_ICLASS_REPLAY, {readerType}};
memcpy(d.d.asBytes, MAC, 4);
SendCommand(&d);
}else{
PrintAndLog("Failed to obtain CC! Aborting");
}
} else {
PrintAndLog("Command execute timeout");
}
return 0;
}
int CmdHFiClass_iso14443A_write(const char *Cmd)
{
uint8_t readerType = 0;
uint8_t MAC[4]={0x00,0x00,0x00,0x00};
uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t CCNR[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t blockNo=0;
uint8_t bldata[8]={0};
if (strlen(Cmd)<3)
{
PrintAndLog("Usage: hf iclass write <Key> <Block> <Data>");
PrintAndLog(" sample: hf iclass write 0011223344556677 10 AAAAAAAAAAAAAAAA");
return 0;
}
if (param_gethex(Cmd, 0, KEY, 16))
{
PrintAndLog("KEY must include 16 HEX symbols");
return 1;
}
blockNo = param_get8(Cmd, 1);
if (blockNo>32)
{
PrintAndLog("Error: Maximum number of blocks is 32 for iClass 2K Cards!");
return 1;
}
if (param_gethex(Cmd, 2, bldata, 8))
{
PrintAndLog("Block data must include 8 HEX symbols");
return 1;
}
UsbCommand c = {CMD_ICLASS_ISO14443A_WRITE, {0}};
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
uint8_t isOK = resp.arg[0] & 0xff;
uint8_t * data = resp.d.asBytes;
memcpy(CSN,data,8);
memcpy(CCNR,data+8,8);
PrintAndLog("DEBUG: %s",sprint_hex(CSN,8));
PrintAndLog("DEBUG: %s",sprint_hex(CCNR,8));
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}
diversifyKey(CSN,KEY, div_key);
PrintAndLog("Div Key: %s",sprint_hex(div_key,8));
doMAC(CCNR, 12,div_key, MAC);
UsbCommand c2 = {CMD_ICLASS_ISO14443A_WRITE, {readerType,blockNo}};
memcpy(c2.d.asBytes, bldata, 8);
memcpy(c2.d.asBytes+8, MAC, 4);
SendCommand(&c2);
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
uint8_t * data = resp.d.asBytes;
if (isOK)
PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4));
else
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}
return 0;
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
@ -431,6 +650,9 @@ static command_t CommandTable[] =
{"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"},
{"sim", CmdHFiClassSim, 0, "Simulate iClass tag"},
{"reader", CmdHFiClassReader, 0, "Read an iClass tag"},
{"replay", CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"},
{"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"},
{"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"},
{NULL, NULL, 0, NULL}
};
@ -443,55 +665,5 @@ int CmdHFiClass(const char *Cmd)
int CmdHelp(const char *Cmd)
{
CmdsHelp(CommandTable);
return 0;
}
/**
* @brief checks if a file exists
* @param filename
* @return
*/
int fileExists(const char *filename) {
struct stat st;
int result = stat(filename, &st);
return result == 0;
}
/**
* @brief Utility function to save data to a file. This method takes a preferred name, but if that
* file already exists, it tries with another name until it finds something suitable.
* E.g. dumpdata-15.txt
* @param preferredName
* @param suffix the file suffix. Leave out the ".".
* @param data The binary data to write to the file
* @param datalen the length of the data
* @return 0 for ok, 1 for failz
*/
int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen)
{
FILE *f = fopen(preferredName, "wb");
int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5);
char * fileName = malloc(size);
memset(fileName,0,size);
int num = 1;
sprintf(fileName,"%s.%s", preferredName, suffix);
while(fileExists(fileName))
{
sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
num++;
}
/* We should have a valid filename now, e.g. dumpdata-3.bin */
/*Opening file for writing in binary mode*/
FILE *fileHandle=fopen(fileName,"wb");
if(!f) {
PrintAndLog("Failed to write to file '%s'", fileName);
return 0;
}
fwrite(data, 1, datalen, fileHandle);
fclose(fileHandle);
PrintAndLog("Saved data to '%s'", fileName);
free(fileName);
return 0;
}

View file

@ -18,6 +18,6 @@ int CmdHFiClassSnoop(const char *Cmd);
int CmdHFiClassSim(const char *Cmd);
int CmdHFiClassList(const char *Cmd);
int CmdHFiClassReader(const char *Cmd);
int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen);
int CmdHFiClassReader_Replay(const char *Cmd);
#endif

View file

@ -10,7 +10,6 @@
#include <stdio.h>
#include <string.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "data.h"
#include "ui.h"

View file

@ -7,7 +7,7 @@
//-----------------------------------------------------------------------------
// High frequency MIFARE commands
//-----------------------------------------------------------------------------
#include "../include/mifare.h"
#include "cmdhfmf.h"
static int CmdHelp(const char *Cmd);
@ -140,6 +140,7 @@ int CmdHF14AMfWrBl(const char *Cmd)
return 0;
}
/* dublett finns i CMDHFMFU.C
int CmdHF14AMfUWrBl(const char *Cmd)
{
uint8_t blockNo = 0;
@ -249,8 +250,7 @@ int CmdHF14AMfUWrBl(const char *Cmd)
}
return 0;
}
*/
int CmdHF14AMfRdBl(const char *Cmd)
{
uint8_t blockNo = 0;
@ -299,6 +299,7 @@ int CmdHF14AMfRdBl(const char *Cmd)
return 0;
}
/* dublett finns i CMDHFMFU.C
int CmdHF14AMfURdBl(const char *Cmd)
{
uint8_t blockNo = 0;
@ -330,8 +331,9 @@ int CmdHF14AMfURdBl(const char *Cmd)
return 0;
}
*/
/* dublett finns i CMDHFMFU.C
int CmdHF14AMfURdCard(const char *Cmd)
{
int i;
@ -422,7 +424,7 @@ int CmdHF14AMfURdCard(const char *Cmd)
}
return 0;
}
*/
int CmdHF14AMfRdSc(const char *Cmd)
{
@ -516,7 +518,16 @@ int CmdHF14AMfDump(const char *Cmd)
UsbCommand resp;
int size = GetCardSize();
char cmdp = param_getchar(Cmd, 0);
PrintAndLog("Got %d",size);
return;
if ( size > -1)
cmdp = (char)48+size;
switch (cmdp) {
case '0' : numSectors = 5; break;
case '1' :
@ -545,8 +556,7 @@ int CmdHF14AMfDump(const char *Cmd)
return 1;
}
// Read key file
// Read keys A from file
for (sectorNo=0; sectorNo<numSectors; sectorNo++) {
if (fread( keyA[sectorNo], 1, 6, fin ) == 0) {
PrintAndLog("File reading error.");
@ -554,6 +564,7 @@ int CmdHF14AMfDump(const char *Cmd)
}
}
// Read keys B from file
for (sectorNo=0; sectorNo<numSectors; sectorNo++) {
if (fread( keyB[sectorNo], 1, 6, fin ) == 0) {
PrintAndLog("File reading error.");
@ -561,8 +572,6 @@ int CmdHF14AMfDump(const char *Cmd)
}
}
// Read access rights to sectors
PrintAndLog("|-----------------------------------------|");
PrintAndLog("|------ Reading sector access bits...-----|");
PrintAndLog("|-----------------------------------------|");
@ -588,16 +597,14 @@ int CmdHF14AMfDump(const char *Cmd)
}
}
// Read blocks and print to file
PrintAndLog("|-----------------------------------------|");
PrintAndLog("|----- Dumping all blocks to file... -----|");
PrintAndLog("|-----------------------------------------|");
for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
for (blockNo = 0; blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
bool received = false;
if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A.
UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}};
memcpy(c.d.asBytes, keyA[sectorNo], 6);
@ -639,7 +646,7 @@ int CmdHF14AMfDump(const char *Cmd)
}
if (isOK) {
fwrite ( data, 1, 16, fout );
PrintAndLog("Dumped block %2d of sector %2d into 'dumpdata.bin'");
PrintAndLog("Dumped block %2d of sector %2d into 'dumpdata.bin'", blockNo, sectorNo);
} else {
PrintAndLog("Could not read block %2d of sector %2d", blockNo, sectorNo);
}
@ -648,7 +655,6 @@ int CmdHF14AMfDump(const char *Cmd)
PrintAndLog("Command execute timeout");
}
}
}
fclose(fin);
@ -801,11 +807,15 @@ int CmdHF14AMfNested(const char *Cmd)
cmdp = param_getchar(Cmd, 0);
blockNo = param_get8(Cmd, 1);
ctmp = param_getchar(Cmd, 2);
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
PrintAndLog("Key type must be A or B");
return 1;
}
if (ctmp != 'A' && ctmp != 'a') keyType = 1;
if (ctmp != 'A' && ctmp != 'a')
keyType = 1;
if (param_gethex(Cmd, 3, key, 12)) {
PrintAndLog("Key must include 12 HEX symbols");
return 1;
@ -819,8 +829,12 @@ int CmdHF14AMfNested(const char *Cmd)
PrintAndLog("Target key type must be A or B");
return 1;
}
if (ctmp != 'A' && ctmp != 'a') trgKeyType = 1;
if (ctmp != 'A' && ctmp != 'a')
trgKeyType = 1;
} else {
switch (cmdp) {
case '0': SectorsCnt = 05; break;
case '1': SectorsCnt = 16; break;
@ -2011,30 +2025,121 @@ int CmdHF14AMfSniff(const char *Cmd){
FillFileNameByUID(logHexFileName, uid + (7 - uid_len), ".log", uid_len);
AddLogCurrentDT(logHexFileName);
}
if (wantDecrypt) mfTraceInit(uid, atqa, sak, wantSaveToEmlFile);
if (wantDecrypt)
mfTraceInit(uid, atqa, sak, wantSaveToEmlFile);
} else {
PrintAndLog("%s(%d):%s", isTag ? "TAG":"RDR", num, sprint_hex(bufPtr, len));
if (wantLogToFile) AddLogHex(logHexFileName, isTag ? "TAG: ":"RDR: ", bufPtr, len);
if (wantDecrypt) mfTraceDecode(bufPtr, len, parity, wantSaveToEmlFile);
if (wantLogToFile)
AddLogHex(logHexFileName, isTag ? "TAG: ":"RDR: ", bufPtr, len);
if (wantDecrypt)
mfTraceDecode(bufPtr, len, parity, wantSaveToEmlFile);
}
bufPtr += len;
num++;
}
}
} // resp not NILL
} // resp not NULL
} // while (true)
return 0;
}
// Tries to identify cardsize.
// Returns <num> where num is:
// -1 unidentified
// 0 - MINI (320bytes)
// 1 - 1K
// 2 - 2K
// 4 - 4K
int GetCardSize()
{
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
if(resp.arg[0] == 0) {
PrintAndLog("iso14443a card select failed");
return -1;
}
iso14a_card_select_t *card = (iso14a_card_select_t *)resp.d.asBytes;
PrintAndLog("Trying to detect card size.");
uint16_t atqa = 0;
uint8_t sak = 0;
atqa = (card->atqa[1] & 0xff) << 8;
atqa += card->atqa[0] & 0xff;
sak = card->sak;
// https://code.google.com/p/libnfc/source/browse/libnfc/target-subr.c
PrintAndLog("found ATAQ: %04X SAK: %02X", atqa, sak);
// NXP MIFARE Mini 0.3k
if ( (atqa && 0xff0f == 0x0004) && (sak == 0x09) ) return 0;
// MIFARE Classic 1K
if ( (atqa && 0xff0f == 0x0004) && (sak == 0x08) ) return 1;
// MIFARE Classik 4K
if ( (atqa && 0xff0f == 0x0002) && (sak == 0x18) ) return 4;
// SmartMX with MIFARE 1K emulation
if ( (atqa && 0xf0ff == 0x0004) ) return 1;
// SmartMX with MIFARE 4K emulation
if ( (atqa && 0xf0ff == 0x0002) ) return 4;
// Infineon MIFARE CLASSIC 1K
if ( (atqa && 0xffff == 0x0004) && (sak == 0x88) ) return 1;
// MFC 4K emulated by Nokia 6212 Classic
if ( (atqa && 0xffff == 0x0002) && (sak == 0x38) ) return 4;
// MFC 4K emulated by Nokia 6131 NFC
if ( (atqa && 0xffff == 0x0008) && (sak == 0x38) ) return 4;
// MIFARE Plus (4 Byte UID or 4 Byte RID)
// MIFARE Plus (7 Byte UID)
if (
(atqa && 0xffff == 0x0002) ||
(atqa && 0xffff == 0x0004) ||
(atqa && 0xffff == 0x0042) ||
(atqa && 0xffff == 0x0044)
)
{
switch(sak){
case 0x08:
case 0x10:
//case 0x20:
return 2;
break;
case 0x11:
case 0x18:
//case 0x20:
return 4;
break;
}
}
return -1;
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"},
{"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"},
{"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"},
{"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"},
{"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"},
//{"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"},
//{"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"},
//{"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"},
{"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"},
{"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"},
{"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"},

View file

@ -16,12 +16,11 @@
#include <string.h>
#include <ctype.h>
#include "proxmark3.h"
#include "iso14443crc.h"
#include "../common/iso14443crc.h"
#include "data.h"
//#include "proxusb.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
#include "../include/common.h"
#include "util.h"
#include "mifarehost.h"
@ -54,5 +53,5 @@ int CmdHF14AMfCGetBlk(const char* cmd);
int CmdHF14AMfCGetSc(const char* cmd);
int CmdHF14AMfCLoad(const char* cmd);
int CmdHF14AMfCSave(const char* cmd);
int GetCardSize();
#endif

436
client/cmdhfmfdes.c Normal file
View file

@ -0,0 +1,436 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2014 Iceman
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE Desfire commands
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <openssl/des.h>
#include "cmdmain.h"
#include "proxmark3.h"
#include "../include/common.h"
#include "../include/mifare.h"
#include "../common/iso14443crc.h"
#include "data.h"
#include "ui.h"
#include "cmdparser.h"
#include "util.h"
#include "cmdhfmfdes.h"
uint8_t key_zero_data[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
uint8_t key_defa_data[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f };
uint8_t key_ones_data[16] = { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 };
static int CmdHelp(const char *Cmd);
static void xor(unsigned char * dst, unsigned char * src, size_t len);
static int32_t le24toh (uint8_t data[3]);
int CmdHF14ADesWb(const char *Cmd)
{
/* uint8_t blockNo = 0;
uint8_t keyType = 0;
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
char cmdp = 0x00;
if (strlen(Cmd)<3) {
PrintAndLog("Usage: hf mf wrbl <block number> <key A/B> <key (12 hex symbols)> <block data (32 hex symbols)>");
PrintAndLog(" sample: hf mf wrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F");
return 0;
}
blockNo = param_get8(Cmd, 0);
cmdp = param_getchar(Cmd, 1);
if (cmdp == 0x00) {
PrintAndLog("Key type must be A or B");
return 1;
}
if (cmdp != 'A' && cmdp != 'a') keyType = 1;
if (param_gethex(Cmd, 2, key, 12)) {
PrintAndLog("Key must include 12 HEX symbols");
return 1;
}
if (param_gethex(Cmd, 3, bldata, 32)) {
PrintAndLog("Block data must include 32 HEX symbols");
return 1;
}
PrintAndLog("--block no:%02x key type:%02x key:%s", blockNo, keyType, sprint_hex(key, 6));
PrintAndLog("--data: %s", sprint_hex(bldata, 16));
UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}};
memcpy(c.d.asBytes, key, 6);
memcpy(c.d.asBytes + 10, bldata, 16);
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}
*/
return 0;
}
int CmdHF14ADesRb(const char *Cmd)
{
// uint8_t blockNo = 0;
// uint8_t keyType = 0;
// uint8_t key[6] = {0, 0, 0, 0, 0, 0};
// char cmdp = 0x00;
// if (strlen(Cmd)<3) {
// PrintAndLog("Usage: hf mf rdbl <block number> <key A/B> <key (12 hex symbols)>");
// PrintAndLog(" sample: hf mf rdbl 0 A FFFFFFFFFFFF ");
// return 0;
// }
// blockNo = param_get8(Cmd, 0);
// cmdp = param_getchar(Cmd, 1);
// if (cmdp == 0x00) {
// PrintAndLog("Key type must be A or B");
// return 1;
// }
// if (cmdp != 'A' && cmdp != 'a') keyType = 1;
// if (param_gethex(Cmd, 2, key, 12)) {
// PrintAndLog("Key must include 12 HEX symbols");
// return 1;
// }
// PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6));
// UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}};
// memcpy(c.d.asBytes, key, 6);
// SendCommand(&c);
// UsbCommand resp;
// if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
// uint8_t isOK = resp.arg[0] & 0xff;
// uint8_t * data = resp.d.asBytes;
// if (isOK)
// PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 16));
// else
// PrintAndLog("isOk:%02x", isOK);
// } else {
// PrintAndLog("Command execute timeout");
// }
return 0;
}
int CmdHF14ADesInfo(const char *Cmd){
UsbCommand c = {CMD_MIFARE_DESFIRE_INFO, { 0x00 }};
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
return 0;
}
PrintAndLog("---Desfire Information---------------------------------------");
PrintAndLog("-------------------------------------------------------------");
PrintAndLog(" UID : %s",sprint_hex(resp.d.asBytes, 7));
PrintAndLog(" Batch number : %s",sprint_hex(resp.d.asBytes+28,5));
PrintAndLog(" Production date : week %02x, 20%02x",resp.d.asBytes[33], resp.d.asBytes[34]);
PrintAndLog("-------------------------------------------------------------");
PrintAndLog(" Hardware Information");
PrintAndLog(" Vendor Id : %s", GetVendorStr(resp.d.asBytes[7]));
PrintAndLog(" Type : 0x%02X",resp.d.asBytes[8]);
PrintAndLog(" Subtype : 0x%02X",resp.d.asBytes[9]);
PrintAndLog(" Version : %d.%d",resp.d.asBytes[10], resp.d.asBytes[11]);
PrintAndLog(" Storage size : %s",GetCardSizeStr(resp.d.asBytes[12]));
PrintAndLog(" Protocol : %s",GetProtocolStr(resp.d.asBytes[13]));
PrintAndLog("-------------------------------------------------------------");
PrintAndLog(" Software Information");
PrintAndLog(" Vendor Id : %s",GetVendorStr(resp.d.asBytes[14]));
PrintAndLog(" Type : 0x%02X",resp.d.asBytes[15]);
PrintAndLog(" Subtype : 0x%02X",resp.d.asBytes[16]);
PrintAndLog(" Version : %d.%d",resp.d.asBytes[17], resp.d.asBytes[18]);
PrintAndLog(" storage size : %s", GetCardSizeStr(resp.d.asBytes[19]));
PrintAndLog(" Protocol : %s", GetProtocolStr(resp.d.asBytes[20]));
PrintAndLog("-------------------------------------------------------------");
PrintAndLog(" Master Key settings");
if ( resp.d.asBytes[35] & (1 << 3 ) )
PrintAndLog(" 0x08 Configuration changeable;");
else
PrintAndLog(" 0x08 Configuration NOT changeable;");
if ( resp.d.asBytes[35] & (1 << 2 ) )
PrintAndLog(" 0x04 PICC Master Key not required for create / delete;");
else
PrintAndLog(" 0x04 PICC Master Key required for create / delete;");
if ( resp.d.asBytes[35] & (1 << 1 ) )
PrintAndLog(" 0x02 Free directory list access without PICC Master Key;");
else
PrintAndLog(" 0x02 Directory list access with PICC Master Key;");
if ( resp.d.asBytes[35] & (1 << 0 ) )
PrintAndLog(" 0x01 Allow changing the Master Key;");
else
PrintAndLog(" 0x01 Master Key is not changeable anymore;");
PrintAndLog("");
PrintAndLog(" Max number of keys : %d", resp.d.asBytes[36]);
PrintAndLog(" Master key Version : %d (0x%02x)", resp.d.asBytes[37], resp.d.asBytes[37]);
PrintAndLog("-------------------------------------------------------------");
uint8_t tmp[3];
memcpy(tmp, resp.d.asBytes+38,3);
PrintAndLog(" Free memory on card : %d bytes", le24toh( tmp ));
PrintAndLog("-------------------------------------------------------------");
/*
Card Master key (CMK) 0x00 on AID = 00 00 00 (card level)
0x1
Application Master Key (AMK) 0x00 on AID != 00 00 00
Application keys (APK) = 0x01-0x0D
Application free = 0x0E
Application never = 0x0F
ACCESS RIGHTS:
keys 0,1,2,3 C
keys 4,5,6,7 RW
keys 8,9,10,11 W
keys 12,13,14,15 R
KEY Versioning.
Se GetKeyVersion (samma nyckel kan ha olika versionen?)
Session key:
16 : RndA(byte0-byte3) + RndB(byte0-byte3) + RndA(byte4-byte7) + RndB(byte4-byte7)
8 : RndA(byte0-byte3) + RndB(byte0-byte3)
AES 16 : RndA(byte0-byte3) + RndB(byte0-byte3) + RndA(byte12-byte15) + RndB(byte12-byte15)
*/
PrintAndLog(" RX :%s",sprint_hex(resp.d.asBytes, 40));
return 1;
}
char * GetVendorStr( uint8_t id){
static char buf[30];
char *retStr = buf;
if ( id == 0x04 )
sprintf(retStr, "0x%02X (NXP)",id);
else
sprintf(retStr,"0x%02X (Unknown)",id);
return buf;
}
/*
The 7 MSBits (= n) code the storage size itself based on 2^n,
the LSBit is set to '0' if the size is exactly 2^n
and set to '1' if the storage size is between 2^n and 2^(n+1).
For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'.
*/
char * GetCardSizeStr( uint8_t fsize ){
static char buf[30];
char *retStr = buf;
uint16_t usize = 1 << ((fsize >>1) + 1);
uint16_t lsize = 1 << (fsize >>1);
// is LSB set?
if ( fsize & (1 << 0 ) )
sprintf(retStr, "0x%02X (%d - %d bytes)",fsize, usize, lsize);
else
sprintf(retStr, "0x%02X (%d bytes)", fsize, lsize);
return buf;
}
char * GetProtocolStr(uint8_t id){
static char buf[30];
char *retStr = buf;
if ( id == 0x05)
sprintf(retStr,"0x%02X (ISO 14443-3, 14443-4)", id);
else
sprintf(retStr,"0x%02X", id);
return buf;
}
int CmdHF14ADesEnumApplications(const char *Cmd){
return 1;
}
int CmdHF14ADesNonces(const char *Cmd){
return 1;
}
//
// MIAFRE DesFire Authentication
//
#define BUFSIZE 64
int CmdHF14ADesAuth(const char *Cmd){
// NR DESC KEYLENGHT
// ------------------------
// 1 = DES 8
// 2 = 3DES 16
// 3 = 3K 3DES 24
// 4 = AES 16
// AUTHENTICTION MODES:
// 1 Normal
// 2 ISO
// 3 AES
uint8_t keylength = 8;
//unsigned char testinput[] = { 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00};
unsigned char key[24]; // = { 0x75,0x28,0x78,0x39,0x74,0x93,0xCB,0x70};
if (strlen(Cmd)<3) {
PrintAndLog("Usage: hf mfdes auth <1|2|3> <1|2|3|4> <keyno> <key> ");
PrintAndLog(" AUTH modes 1 = normal, 2 = iso, 3 = aes");
PrintAndLog(" Crypto: 1 = DES 2 = 3DES 3 = 3K3DES 4 = AES");
PrintAndLog(" keynumber");
PrintAndLog(" sample: hf mfdes auth 1 1 0 11223344");
return 0;
}
uint8_t cmdAuthMode = param_get8(Cmd,0);
uint8_t cmdAuthAlgo = param_get8(Cmd,1);
uint8_t cmdKeyNo = param_get8(Cmd,2);
switch (cmdAuthMode)
{
case 1:
if ( cmdAuthAlgo != 1 && cmdAuthAlgo != 2) {
PrintAndLog("Crypto algo not valid for the auth mode");
return 1;
}
break;
case 2:
if ( cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) {
PrintAndLog("Crypto algo not valid for the auth mode");
return 1;
}
break;
case 3:
if ( cmdAuthAlgo != 4) {
PrintAndLog("Crypto algo not valid for the auth mode");
return 1;
}
break;
default:
PrintAndLog("Wrong Auth mode");
return 1;
break;
}
switch (cmdAuthAlgo){
case 2:
keylength = 16;
PrintAndLog("3DES selected");
break;
case 3:
keylength = 24;
PrintAndLog("3 key 3DES selected");
break;
case 4:
keylength = 16;
PrintAndLog("AES selected");
break;
default:
cmdAuthAlgo = 1;
keylength = 8;
PrintAndLog("DES selected");
break;
}
// key
if (param_gethex(Cmd, 3, key, keylength*2)) {
PrintAndLog("Key must include %d HEX symbols", keylength);
return 1;
}
// algo, nyckellängd,
UsbCommand c = {CMD_MIFARE_DESFIRE_AUTH1, { cmdAuthMode, cmdAuthAlgo, cmdKeyNo }};
c.d.asBytes[0] = keylength;
memcpy(c.d.asBytes+1, key, keylength);
//memcpy(c.d.asBytes + 30, testinput, keylength);
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,3000)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
return 0;
}
uint8_t * data= resp.d.asBytes;
// PrintAndLog("-------------------------------------------------------------");
PrintAndLog(" Key :%s",sprint_hex(key, keylength));
// PrintAndLog(" Plain :%s",sprint_hex(testinput, keylength));
PrintAndLog(" Encoded :%s",sprint_hex(data, keylength));
PrintAndLog("-------------------------------------------------------------");
//PrintAndLog(" Expected :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56");
return 1;
}
static void xor(unsigned char * dst, unsigned char * src, size_t len) {
for( ; len > 0; len--,dst++,src++)
*dst ^= *src;
}
static int32_t le24toh (uint8_t data[3]) {
return (data[2] << 16) | (data[1] << 8) | data[0];
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"auth", CmdHF14ADesAuth, 0, "Tries a MIFARE DesFire Authentication"},
{"rb", CmdHF14ADesRb, 0, "Read MIFARE DesFire block"},
{"wb", CmdHF14ADesWb, 0, "write MIFARE DesFire block"},
{"info", CmdHF14ADesInfo, 0, "Get MIFARE DesFire information"},
{"enum", CmdHF14ADesEnumApplications,0, "Tries enumerate all applications"},
{"nonce", CmdHF14ADesNonces, 0, "<n> Collect n>0 nonces"},
{NULL, NULL, 0, NULL}
};
int CmdHFMFDes(const char *Cmd)
{
// flush
WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd);
return 0;
}
int CmdHelp(const char *Cmd)
{
CmdsHelp(CommandTable);
return 0;
}

20
client/cmdhfmfdes.h Normal file
View file

@ -0,0 +1,20 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2014 Iceman
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE Desfire commands
//-----------------------------------------------------------------------------
int CmdHFMFDes(const char *Cmd);
int CmdHF14ADesAuth(const char* cmd);
int CmdHF14ADesRb(const char* cmd);
int CmdHF14ADesWb(const char* cmd);
int CmdHF14ADesInfo(const char *Cmd);
int CmdHF14ADesEnumApplications(const char *Cmd);
int CmdHF14ADesNonces(const char *Cmd);
char * GetCardSizeStr( uint8_t fsize );
char * GetVendorStr( uint8_t id);
char * GetProtocolStr(uint8_t id);

1159
client/cmdhfmfu.c Normal file

File diff suppressed because it is too large Load diff

16
client/cmdhfmfu.h Normal file
View file

@ -0,0 +1,16 @@
#include "cmdhfmf.h"
//standard ultralight
int CmdHF14AMfUWrBl(const char *Cmd);
int CmdHF14AMfURdBl(const char *Cmd);
int CmdHF14AMfURdCard(const char *Cmd);
int CmdHF14AMfUDump(const char *Cmd);
//Crypto Cards
int CmdHF14AMfUCRdBl(const char *Cmd);
int CmdHF14AMfUCRdCard(const char *Cmd);
int CmdHF14AMfUCDump(const char *Cmd);
int CmdHF14AMfucAuth(const char *Cmd);
void rol (uint8_t *data, const size_t len);
//general stuff
int CmdHFMFUltra(const char *Cmd);

View file

@ -13,7 +13,6 @@
#include <string.h>
#include <limits.h>
#include "ui.h"
//#include "proxusb.h"
#include "proxmark3.h"
#include "cmdparser.h"
#include "cmdhw.h"

View file

@ -12,7 +12,6 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "data.h"
#include "graph.h"

View file

@ -11,14 +11,18 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "ui.h"
#include "graph.h"
#include "cmdmain.h"
#include "cmdparser.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "cmdlfem4x.h"
#include "util.h"
#include "data.h"
char *global_em410xId;
static int CmdHelp(const char *Cmd);
@ -139,6 +143,8 @@ retest:
PrintAndLog("EM410x Tag ID: %s", id);
PrintAndLog("Unique Tag ID: %s", id2);
global_em410xId = id;
/* Stop any loops */
return 1;
}
@ -167,8 +173,9 @@ retest:
}
/* if we've already retested after flipping bits, return */
if (retested++)
if (retested++){
return 0;
}
/* if this didn't work, try flipping bits */
for (i = 0; i < bit2idx; i++)
@ -252,6 +259,7 @@ int CmdEM410xSim(const char *Cmd)
int CmdEM410xWatch(const char *Cmd)
{
int read_h = (*Cmd == 'h');
//char k;
do
{
CmdLFRead(read_h ? "h" : "");
@ -264,7 +272,22 @@ int CmdEM410xWatch(const char *Cmd)
// Changed by martin, 4000 x 4 = 16000,
// see http://www.proxmark.org/forum/viewtopic.php?pid=7235#p7235
CmdSamples("16000");
} while (
!CmdEM410xRead("")
);
return 0;
}
int CmdEM410xWatchnSpoof(const char *Cmd)
{
int read_h = (*Cmd == 'h');
do
{
CmdLFRead(read_h ? "h" : "");
CmdSamples("16000");
} while ( ! CmdEM410xRead(""));
PrintAndLog("# Replaying : %s",global_em410xId);
CmdEM410xSim(global_em410xId);
return 0;
}
@ -482,12 +505,12 @@ int CmdEM410xWrite(const char *Cmd)
int CmdReadWord(const char *Cmd)
{
int Word = 16; //default to invalid word
int Word = -1; //default to invalid word
UsbCommand c;
sscanf(Cmd, "%d", &Word);
if (Word > 15) {
if ( (Word > 15) | (Word < 0) ) {
PrintAndLog("Word must be between 0 and 15");
return 1;
}
@ -500,18 +523,37 @@ int CmdReadWord(const char *Cmd)
c.arg[1] = Word;
c.arg[2] = 0;
SendCommand(&c);
WaitForResponse(CMD_ACK, NULL);
size_t bytelength = 4096;
uint8_t data[bytelength];
memset(data, 0x00, bytelength);
GetFromBigBuf(data,bytelength,3560); //3560 -- should be offset..
WaitForResponseTimeout(CMD_ACK,NULL, 1500);
for (int j = 0; j < bytelength; j++) {
GraphBuffer[j] = ((int)data[j]) - 128;
}
GraphTraceLen = bytelength;
RepaintGraphWindow();
manchester_decode(data, bytelength);
free(data);
return 0;
}
int CmdReadWordPWD(const char *Cmd)
{
int Word = 16; //default to invalid word
int Word = -1; //default to invalid word
int Password = 0xFFFFFFFF; //default to blank password
UsbCommand c;
sscanf(Cmd, "%d %x", &Word, &Password);
if (Word > 15) {
if ( (Word > 15) | (Word < 0) ) {
PrintAndLog("Word must be between 0 and 15");
return 1;
}
@ -524,6 +566,24 @@ int CmdReadWordPWD(const char *Cmd)
c.arg[1] = Word;
c.arg[2] = Password;
SendCommand(&c);
WaitForResponse(CMD_ACK, NULL);
size_t bytelength = 4096;
uint8_t data[bytelength];
memset(data, 0x00, bytelength);
GetFromBigBuf(data,bytelength,3560); //3560 -- should be offset..
WaitForResponseTimeout(CMD_ACK,NULL, 1500);
for (int j = 0; j < bytelength; j++) {
GraphBuffer[j] = ((int)data[j]) - 128;
}
GraphTraceLen = bytelength;
RepaintGraphWindow();
manchester_decode(data, bytelength);
free(data);
return 0;
}
@ -581,15 +641,16 @@ int CmdWriteWordPWD(const char *Cmd)
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"em410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"},
{"em410xsim", CmdEM410xSim, 0, "<UID> -- Simulate EM410x tag"},
{"em410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
{"em410xwrite", CmdEM410xWrite, 1, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
{"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"},
{"readword", CmdReadWord, 1, "<Word> -- Read EM4xxx word data"},
{"readwordPWD", CmdReadWordPWD, 1, "<Word> <Password> -- Read EM4xxx word data in password mode"},
{"writeword", CmdWriteWord, 1, "<Data> <Word> -- Write EM4xxx word data"},
{"writewordPWD", CmdWriteWordPWD, 1, "<Data> <Word> <Password> -- Write EM4xxx word data in password mode"},
{"410read", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"},
{"410sim", CmdEM410xSim, 0, "<UID> -- Simulate EM410x tag"},
{"410watch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
{"410spoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
{"410write", CmdEM410xWrite, 1, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
{"4xread", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"},
{"rd", CmdReadWord, 1, "<Word 1-15> -- Read EM4xxx word data"},
{"rdpwd", CmdReadWordPWD, 1, "<Word 1-15> <Password> -- Read EM4xxx word data in password mode "},
{"wr", CmdWriteWord, 1, "<Data> <Word 1-15> -- Write EM4xxx word data"},
{"wrpwd", CmdWriteWordPWD, 1, "<Data> <Word 1-15> <Password> -- Write EM4xxx word data in password mode"},
{NULL, NULL, 0, NULL}
};

View file

@ -10,7 +10,6 @@
#include <stdio.h>
#include <string.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "ui.h"
#include "graph.h"

View file

@ -12,13 +12,12 @@
#include <stdlib.h>
#include <string.h>
#include "data.h"
//#include "proxusb.h"
#include "proxmark3.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
#include "../include/common.h"
#include "util.h"
#include "hitag2.h"
#include "../include/hitag2.h"
#include "sleep.h"
#include "cmdmain.h"

View file

@ -3,7 +3,6 @@
#include <string.h>
#include <inttypes.h>
#include <limits.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "data.h"
#include "graph.h"

View file

@ -10,7 +10,6 @@
#include <stdio.h>
#include <string.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "ui.h"
#include "graph.h"

View file

@ -10,55 +10,88 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "ui.h"
#include "graph.h"
#include "cmdmain.h"
#include "cmdparser.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "cmdlft55xx.h"
#include "util.h"
#include "data.h"
#define LF_TRACE_BUFF_SIZE 16000
static int CmdHelp(const char *Cmd);
int CmdReadBlk(const char *Cmd)
{
int Block = 8; //default to invalid block
//default to invalid block
int Block = -1;
UsbCommand c;
sscanf(Cmd, "%d", &Block);
if (Block > 7) {
if ((Block > 7) | (Block < 0)) {
PrintAndLog("Block must be between 0 and 7");
return 1;
}
PrintAndLog("Reading block %d", Block);
PrintAndLog(" Reading page 0 block : %d", Block);
// this command fills up BigBuff
//
c.cmd = CMD_T55XX_READ_BLOCK;
c.d.asBytes[0] = 0x0; //Normal mode
c.d.asBytes[0] = 0x00;
c.arg[0] = 0;
c.arg[1] = Block;
c.arg[2] = 0;
SendCommand(&c);
WaitForResponse(CMD_ACK, NULL);
uint8_t data[LF_TRACE_BUFF_SIZE];
memset(data, 0x00, LF_TRACE_BUFF_SIZE);
GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset..
WaitForResponseTimeout(CMD_ACK,NULL, 1500);
for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) {
GraphBuffer[j] = ((int)data[j]) - 128;
}
GraphTraceLen = LF_TRACE_BUFF_SIZE;
// BiDirectional
CmdDirectionalThreshold("70 -60");
// Askdemod
Cmdaskdemod("1");
uint8_t bits[1000];
uint8_t * bitstream = bits;
uint8_t len = 0;
len = manchester_decode(data, LF_TRACE_BUFF_SIZE, bitstream);
if ( len > 0 )
PrintPaddedManchester(bitstream, len, 32);
return 0;
}
int CmdReadBlkPWD(const char *Cmd)
{
int Block = 8; //default to invalid block
int Block = -1; //default to invalid block
int Password = 0xFFFFFFFF; //default to blank Block 7
UsbCommand c;
sscanf(Cmd, "%d %x", &Block, &Password);
if (Block > 7) {
if ((Block > 7) | (Block < 0)) {
PrintAndLog("Block must be between 0 and 7");
return 1;
}
PrintAndLog("Reading block %d with password %08X", Block, Password);
PrintAndLog("Reading page 0 block %d pwd %08X", Block, Password);
c.cmd = CMD_T55XX_READ_BLOCK;
c.d.asBytes[0] = 0x1; //Password mode
@ -66,9 +99,35 @@ int CmdReadBlkPWD(const char *Cmd)
c.arg[1] = Block;
c.arg[2] = Password;
SendCommand(&c);
WaitForResponse(CMD_ACK, NULL);
uint8_t data[LF_TRACE_BUFF_SIZE];
memset(data, 0x00, LF_TRACE_BUFF_SIZE);
GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset..
WaitForResponseTimeout(CMD_ACK,NULL, 1500);
for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) {
GraphBuffer[j] = ((int)data[j]) - 128;
}
GraphTraceLen = LF_TRACE_BUFF_SIZE;
// BiDirectional
CmdDirectionalThreshold("70 -60");
// Askdemod
Cmdaskdemod("1");
uint8_t bits[1000];
uint8_t len = 0;
len = manchester_decode(data, LF_TRACE_BUFF_SIZE, bits);
if ( len > 0 )
PrintPaddedManchester(bits, len, 32);
return 0;
}
int CmdWriteBlk(const char *Cmd)
{
int Block = 8; //default to invalid block
@ -120,11 +179,35 @@ int CmdWriteBlkPWD(const char *Cmd)
int CmdReadTrace(const char *Cmd)
{
PrintAndLog("Reading traceability data");
PrintAndLog(" Reading page 1 - tracedata");
UsbCommand c = {CMD_T55XX_READ_TRACE, {0, 0, 0}};
SendCommand(&c);
WaitForResponse(CMD_ACK, NULL);
uint8_t data[LF_TRACE_BUFF_SIZE];
memset(data, 0x00, LF_TRACE_BUFF_SIZE);
GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset..
WaitForResponseTimeout(CMD_ACK,NULL, 1500);
for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) {
GraphBuffer[j] = ((int)data[j]) - 128;
}
GraphTraceLen = LF_TRACE_BUFF_SIZE;
// BiDirectional
CmdDirectionalThreshold("70 -60");
// Askdemod
Cmdaskdemod("1");
uint8_t bits[512];
uint8_t len = 0;
len = manchester_decode(data,LF_TRACE_BUFF_SIZE,bits);
if ( len > 0 )
PrintPaddedManchester(bits, len, 64);
return 0;
}

View file

@ -11,7 +11,6 @@
#include <stdio.h>
#include <stdlib.h>
#include "crc16.h"
//#include "proxusb.h"
#include "proxmark3.h"
#include "data.h"
#include "ui.h"

View file

@ -16,7 +16,7 @@
#include "cmdparser.h"
#include "proxmark3.h"
#include "data.h"
#include "usb_cmd.h"
#include "../include/usb_cmd.h"
#include "ui.h"
#include "cmdhf.h"
#include "cmddata.h"

View file

@ -11,7 +11,7 @@
#ifndef CMDMAIN_H__
#define CMDMAIN_H__
#include "usb_cmd.h"
#include "../include/usb_cmd.h"
#include "cmdparser.h"
void UsbCommandReceived(UsbCommand *UC);
void CommandReceived(char *Cmd);

View file

@ -12,7 +12,6 @@
#include <stdint.h>
#include "data.h"
#include "ui.h"
//#include "proxusb.h"
#include "proxmark3.h"
#include "cmdmain.h"

View file

@ -13,11 +13,10 @@
#include <stdlib.h>
#include "proxmark3.h"
#include "sleep.h"
//#include "proxusb.h"
#include "flash.h"
#include "elf.h"
#include "proxendian.h"
#include "usb_cmd.h"
#include "../include/usb_cmd.h"
void SendCommand(UsbCommand* txcmd);
void ReceiveCommand(UsbCommand* rxcmd);

View file

@ -13,7 +13,7 @@
#include "proxmark3.h"
#include "flash.h"
#include "uart.h"
#include "usb_cmd.h"
#include "../include/usb_cmd.h"
#ifdef _WIN32
# define unlink(x)

255
client/loclass/cipher.c Normal file
View file

@ -0,0 +1,255 @@
/*****************************************************************************
* This file is part of iClassCipher. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file 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 IClassCipher. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "cipher.h"
#include "cipherutils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <time.h>
#include "fileutils.h"
uint8_t keytable[] = { 0,0,0,0,0,0,0,0};
/**
* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2
* consisting of the following four components:
* 1. the left register l = (l 0 . . . l 7 ) F 8/2 ;
* 2. the right register r = (r 0 . . . r 7 ) F 8/2 ;
* 3. the top register t = (t 0 . . . t 15 ) F 16/2 .
* 4. the bottom register b = (b 0 . . . b 7 ) F 8/2 .
**/
typedef struct {
uint8_t l;
uint8_t r;
uint8_t b;
uint16_t t;
} State;
/**
* Definition 2. The feedback function for the top register T : F 16/2 F 2
* is defined as
* T (x 0 x 1 . . . . . . x 15 ) = x 0 x 1 x 5 x 7 x 10 x 11 x 14 x 15 .
**/
bool T(State state)
{
bool x0 = state.t & 0x8000;
bool x1 = state.t & 0x4000;
bool x5 = state.t & 0x0400;
bool x7 = state.t & 0x0100;
bool x10 = state.t & 0x0020;
bool x11 = state.t & 0x0010;
bool x14 = state.t & 0x0002;
bool x15 = state.t & 0x0001;
return x0 ^ x1 ^ x5 ^ x7 ^ x10 ^ x11 ^ x14 ^ x15;
}
/**
* Similarly, the feedback function for the bottom register B : F 8/2 F 2 is defined as
* B(x 0 x 1 . . . x 7 ) = x 1 x 2 x 3 x 7 .
**/
bool B(State state)
{
bool x1 = state.b & 0x40;
bool x2 = state.b & 0x20;
bool x3 = state.b & 0x10;
bool x7 = state.b & 0x01;
return x1 ^ x2 ^ x3 ^ x7;
}
/**
* Definition 3 (Selection function). The selection function select : F 2 × F 2 ×
* F 8/2 F 3/2 is defined as select(x, y, r) = z 0 z 1 z 2 where
* z 0 = (r 0 r 2 ) (r 1 r 3 ) (r 2 r 4 )
* z 1 = (r 0 r 2 ) (r 5 r 7 ) r 1 r 6 x y
* z 2 = (r 3 r 5 ) (r 4 r 6 ) r 7 x
**/
uint8_t _select(bool x, bool y, uint8_t r)
{
bool r0 = r >> 7 & 0x1;
bool r1 = r >> 6 & 0x1;
bool r2 = r >> 5 & 0x1;
bool r3 = r >> 4 & 0x1;
bool r4 = r >> 3 & 0x1;
bool r5 = r >> 2 & 0x1;
bool r6 = r >> 1 & 0x1;
bool r7 = r & 0x1;
bool z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4);
bool z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y;
bool z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x;
// The three bitz z0.. z1 are packed into a uint8_t:
// 00000ZZZ
//Return value is a uint8_t
uint8_t retval = 0;
retval |= (z0 << 2) & 4;
retval |= (z1 << 1) & 2;
retval |= z2 & 1;
// Return value 0 <= retval <= 7
return retval;
}
/**
* Definition 4 (Successor state). Let s = l, r, t, b be a cipher state, k (F 82 ) 8
* be a key and y F 2 be the input bit. Then, the successor cipher state s =
* l , r , t , b is defined as
* t := (T (t) r 0 r 4 )t 0 . . . t 14 l := (k [select(T (t),y,r)] b ) l r
* b := (B(b) r 7 )b 0 . . . b 6 r := (k [select(T (t),y,r)] b ) l
*
* @param s - state
* @param k - array containing 8 bytes
**/
State successor(uint8_t* k, State s, bool y)
{
bool r0 = s.r >> 7 & 0x1;
bool r4 = s.r >> 3 & 0x1;
bool r7 = s.r & 0x1;
State successor = {0,0,0,0};
successor.t = s.t >> 1;
successor.t |= (T(s) ^ r0 ^ r4) << 15;
successor.b = s.b >> 1;
successor.b |= (B(s) ^ r7) << 7;
bool Tt = T(s);
successor.l = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l+s.r ) & 0xFF;
successor.r = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l ) & 0xFF;
return successor;
}
/**
* We define the successor function suc which takes a key k (F 82 ) 8 , a state s and
* an input y F 2 and outputs the successor state s . We overload the function suc
* to multiple bit input x F n 2 which we define as
* @param k - array containing 8 bytes
**/
State suc(uint8_t* k,State s, BitstreamIn *bitstream)
{
if(bitsLeft(bitstream) == 0)
{
return s;
}
bool lastbit = tailBit(bitstream);
return successor(k,suc(k,s,bitstream), lastbit);
}
/**
* Definition 5 (Output). Define the function output which takes an internal
* state s =< l, r, t, b > and returns the bit r 5 . We also define the function output
* on multiple bits input which takes a key k, a state s and an input x F n 2 as
* output(k, s, ǫ) = ǫ
* output(k, s, x 0 . . . x n ) = output(s) · output(k, s , x 1 . . . x n )
* where s = suc(k, s, x 0 ).
**/
void output(uint8_t* k,State s, BitstreamIn* in, BitstreamOut* out)
{
if(bitsLeft(in) == 0)
{
return;
}
pushBit(out,(s.r >> 2) & 1);
//Remove first bit
uint8_t x0 = headBit(in);
State ss = successor(k,s,x0);
output(k,ss,in, out);
}
/**
* Definition 6 (Initial state). Define the function init which takes as input a
* key k (F 82 ) 8 and outputs the initial cipher state s =< l, r, t, b >
**/
State init(uint8_t* k)
{
State s = {
((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((k[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
return s;
}
void MAC(uint8_t* k, BitstreamIn input, BitstreamOut out)
{
uint8_t zeroes_32[] = {0,0,0,0};
BitstreamIn input_32_zeroes = {zeroes_32,sizeof(zeroes_32)*8,0};
State initState = suc(k,init(k),&input);
output(k,initState,&input_32_zeroes,&out);
}
void doMAC(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t mac[4])
{
uint8_t *cc_nr;
uint8_t div_key[8];
cc_nr=(uint8_t*)malloc(length+1);
memcpy(cc_nr,cc_nr_p,length);
memcpy(div_key,div_key_p,8);
reverse_arraybytes(cc_nr,length);
BitstreamIn bitstream = {cc_nr,length * 8,0};
uint8_t dest []= {0,0,0,0,0,0,0,0};
BitstreamOut out = { dest, sizeof(dest)*8, 0 };
MAC(div_key,bitstream, out);
//The output MAC must also be reversed
reverse_arraybytes(dest, sizeof(dest));
memcpy(mac,dest,4);
//printf("Calculated_MAC\t%02x%02x%02x%02x\n", dest[0],dest[1],dest[2],dest[3]);
free(cc_nr);
return;
}
int testMAC()
{
prnlog("[+] Testing MAC calculation...");
//From the "dismantling.IClass" paper:
uint8_t cc_nr[] = {0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0};
//From the paper
uint8_t div_key[8] = {0xE0,0x33,0xCA,0x41,0x9A,0xEE,0x43,0xF9};
uint8_t correct_MAC[4] = {0x1d,0x49,0xC9,0xDA};
uint8_t calculated_mac[4] = {0};
doMAC(cc_nr, 12,div_key, calculated_mac);
if(memcmp(calculated_mac, correct_MAC,4) == 0)
{
prnlog("[+] MAC calculation OK!");
}else
{
prnlog("[+] FAILED: MAC calculation failed:");
printarr(" Calculated_MAC", calculated_mac, 4);
printarr(" Correct_MAC ", correct_MAC, 4);
return 1;
}
return 0;
}

31
client/loclass/cipher.h Normal file
View file

@ -0,0 +1,31 @@
/*****************************************************************************
* This file is part of iClassCipher. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file 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 IClassCipher. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef CIPHER_H
#define CIPHER_H
#include <stdint.h>
void doMAC(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t mac[4]);
int testMAC();
#endif // CIPHER_H

View file

@ -0,0 +1,273 @@
/*****************************************************************************
* This file is part of iClassCipher. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file 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 IClassCipher. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "fileutils.h"
#include "cipherutils.h"
/**
*
* @brief Return and remove the first bit (x0) in the stream : <x0 x1 x2 x3 ... xn >
* @param stream
* @return
*/
bool headBit( BitstreamIn *stream)
{
int bytepos = stream->position >> 3; // divide by 8
int bitpos = (stream->position++) & 7; // mask out 00000111
return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
}
/**
* @brief Return and remove the last bit (xn) in the stream: <x0 x1 x2 ... xn>
* @param stream
* @return
*/
bool tailBit( BitstreamIn *stream)
{
int bitpos = stream->numbits -1 - (stream->position++);
int bytepos= bitpos >> 3;
bitpos &= 7;
return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
}
/**
* @brief Pushes bit onto the stream
* @param stream
* @param bit
*/
void pushBit( BitstreamOut* stream, bool bit)
{
int bytepos = stream->position >> 3; // divide by 8
int bitpos = stream->position & 7;
*(stream->buffer+bytepos) |= (bit & 1) << (7 - bitpos);
stream->position++;
stream->numbits++;
}
/**
* @brief Pushes the lower six bits onto the stream
* as b0 b1 b2 b3 b4 b5 b6
* @param stream
* @param bits
*/
void push6bits( BitstreamOut* stream, uint8_t bits)
{
pushBit(stream, bits & 0x20);
pushBit(stream, bits & 0x10);
pushBit(stream, bits & 0x08);
pushBit(stream, bits & 0x04);
pushBit(stream, bits & 0x02);
pushBit(stream, bits & 0x01);
}
/**
* @brief bitsLeft
* @param stream
* @return number of bits left in stream
*/
int bitsLeft( BitstreamIn *stream)
{
return stream->numbits - stream->position;
}
/**
* @brief numBits
* @param stream
* @return Number of bits stored in stream
*/
int numBits(BitstreamOut *stream)
{
return stream->numbits;
}
void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
{
while (len--) {
dest[len] = (uint8_t) n;
n >>= 8;
}
}
uint64_t x_bytes_to_num(uint8_t* src, size_t len)
{
uint64_t num = 0;
while (len--)
{
num = (num << 8) | (*src);
src++;
}
return num;
}
uint8_t reversebytes(uint8_t b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
void reverse_arraybytes(uint8_t* arr, size_t len)
{
uint8_t i;
for( i =0; i< len ; i++)
{
arr[i] = reversebytes(arr[i]);
}
}
void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len)
{
uint8_t i;
for( i =0; i< len ; i++)
{
dest[i] = reversebytes(arr[i]);
}
}
void printarr(char * name, uint8_t* arr, int len)
{
int cx;
size_t outsize = 40+strlen(name)+len*5;
char* output = malloc(outsize);
memset(output, 0,outsize);
int i ;
cx = snprintf(output,outsize, "uint8_t %s[] = {", name);
for(i =0 ; i< len ; i++)
{
cx += snprintf(output+cx,outsize-cx,"0x%02x,",*(arr+i));//5 bytes per byte
}
cx += snprintf(output+cx,outsize-cx,"};");
prnlog(output);
}
void printvar(char * name, uint8_t* arr, int len)
{
int cx;
size_t outsize = 40+strlen(name)+len*2;
char* output = malloc(outsize);
memset(output, 0,outsize);
int i ;
cx = snprintf(output,outsize,"%s = ", name);
for(i =0 ; i< len ; i++)
{
cx += snprintf(output+cx,outsize-cx,"%02x",*(arr+i));//2 bytes per byte
}
prnlog(output);
}
void printarr_human_readable(char * title, uint8_t* arr, int len)
{
int cx;
size_t outsize = 100+strlen(title)+len*4;
char* output = malloc(outsize);
memset(output, 0,outsize);
int i;
cx = snprintf(output,outsize, "\n\t%s\n", title);
for(i =0 ; i< len ; i++)
{
if(i % 16 == 0)
cx += snprintf(output+cx,outsize-cx,"\n%02x| ", i );
cx += snprintf(output+cx,outsize-cx, "%02x ",*(arr+i));
}
prnlog(output);
}
//-----------------------------
// Code for testing below
//-----------------------------
int testBitStream()
{
uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
uint8_t output [] = {0,0,0,0,0,0,0,0};
BitstreamIn in = { input, sizeof(input) * 8,0};
BitstreamOut out ={ output, 0,0}
;
while(bitsLeft(&in) > 0)
{
pushBit(&out, headBit(&in));
//printf("Bits left: %d\n", bitsLeft(&in));
//printf("Bits out: %d\n", numBits(&out));
}
if(memcmp(input, output, sizeof(input)) == 0)
{
prnlog(" Bitstream test 1 ok");
}else
{
prnlog(" Bitstream test 1 failed");
uint8_t i;
for(i = 0 ; i < sizeof(input) ; i++)
{
prnlog(" IN %02x, OUT %02x", input[i], output[i]);
}
return 1;
}
return 0;
}
int testReversedBitstream()
{
uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
uint8_t reverse [] = {0,0,0,0,0,0,0,0};
uint8_t output [] = {0,0,0,0,0,0,0,0};
BitstreamIn in = { input, sizeof(input) * 8,0};
BitstreamOut out ={ output, 0,0};
BitstreamIn reversed_in ={ reverse, sizeof(input)*8,0};
BitstreamOut reversed_out ={ reverse,0 ,0};
while(bitsLeft(&in) > 0)
{
pushBit(&reversed_out, tailBit(&in));
}
while(bitsLeft(&reversed_in) > 0)
{
pushBit(&out, tailBit(&reversed_in));
}
if(memcmp(input, output, sizeof(input)) == 0)
{
prnlog(" Bitstream test 2 ok");
}else
{
prnlog(" Bitstream test 2 failed");
uint8_t i;
for(i = 0 ; i < sizeof(input) ; i++)
{
prnlog(" IN %02x, MIDDLE: %02x, OUT %02x", input[i],reverse[i], output[i]);
}
return 1;
}
return 0;
}
int testCipherUtils(void)
{
prnlog("[+] Testing some internals...");
int retval = 0;
retval |= testBitStream();
retval |= testReversedBitstream();
return retval;
}

View file

@ -0,0 +1,59 @@
/*****************************************************************************
* This file is part of iClassCipher. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file 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 IClassCipher. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef CIPHERUTILS_H
#define CIPHERUTILS_H
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
typedef struct {
uint8_t * buffer;
uint8_t numbits;
uint8_t position;
} BitstreamIn;
typedef struct {
uint8_t * buffer;
uint8_t numbits;
uint8_t position;
}BitstreamOut;
bool headBit( BitstreamIn *stream);
bool tailBit( BitstreamIn *stream);
void pushBit( BitstreamOut *stream, bool bit);
int bitsLeft( BitstreamIn *stream);
int testCipherUtils(void);
int testMAC();
void push6bits( BitstreamOut* stream, uint8_t bits);
void EncryptDES(bool key[56], bool outBlk[64], bool inBlk[64], int verbose) ;
void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t x_bytes_to_num(uint8_t* src, size_t len);
uint8_t reversebytes(uint8_t b);
void reverse_arraybytes(uint8_t* arr, size_t len);
void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len);
void printarr(char * name, uint8_t* arr, int len);
void printvar(char * name, uint8_t* arr, int len);
void printarr_human_readable(char * title, uint8_t* arr, int len);
#endif // CIPHERUTILS_H

1014
client/loclass/des.c Normal file

File diff suppressed because it is too large Load diff

256
client/loclass/des.h Normal file
View file

@ -0,0 +1,256 @@
/**
* \file des.h
*
* \brief DES block cipher
*
* Copyright (C) 2006-2013, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* 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_DES_H
#define POLARSSL_DES_H
//#include "config.h"
#include <string.h>
#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
#include <basetsd.h>
typedef UINT32 uint32_t;
#else
#include <inttypes.h>
#endif
#define DES_ENCRYPT 1
#define DES_DECRYPT 0
#define POLARSSL_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */
#define DES_KEY_SIZE 8
#if !defined(POLARSSL_DES_ALT)
// Regular implementation
//
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief DES context structure
*/
typedef struct
{
int mode; /*!< encrypt/decrypt */
uint32_t sk[32]; /*!< DES subkeys */
}
des_context;
/**
* \brief Triple-DES context structure
*/
typedef struct
{
int mode; /*!< encrypt/decrypt */
uint32_t sk[96]; /*!< 3DES subkeys */
}
des3_context;
/**
* \brief Set key parity on the given key to odd.
*
* DES keys are 56 bits long, but each byte is padded with
* a parity bit to allow verification.
*
* \param key 8-byte secret key
*/
void des_key_set_parity( unsigned char key[DES_KEY_SIZE] );
/**
* \brief Check that key parity on the given key is odd.
*
* DES keys are 56 bits long, but each byte is padded with
* a parity bit to allow verification.
*
* \param key 8-byte secret key
*
* \return 0 is parity was ok, 1 if parity was not correct.
*/
int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] );
/**
* \brief Check that key is not a weak or semi-weak DES key
*
* \param key 8-byte secret key
*
* \return 0 if no weak key was found, 1 if a weak key was identified.
*/
int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] );
/**
* \brief DES key schedule (56-bit, encryption)
*
* \param ctx DES context to be initialized
* \param key 8-byte secret key
*
* \return 0
*/
int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] );
/**
* \brief DES key schedule (56-bit, decryption)
*
* \param ctx DES context to be initialized
* \param key 8-byte secret key
*
* \return 0
*/
int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] );
/**
* \brief Triple-DES key schedule (112-bit, encryption)
*
* \param ctx 3DES context to be initialized
* \param key 16-byte secret key
*
* \return 0
*/
int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] );
/**
* \brief Triple-DES key schedule (112-bit, decryption)
*
* \param ctx 3DES context to be initialized
* \param key 16-byte secret key
*
* \return 0
*/
int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] );
/**
* \brief Triple-DES key schedule (168-bit, encryption)
*
* \param ctx 3DES context to be initialized
* \param key 24-byte secret key
*
* \return 0
*/
int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] );
/**
* \brief Triple-DES key schedule (168-bit, decryption)
*
* \param ctx 3DES context to be initialized
* \param key 24-byte secret key
*
* \return 0
*/
int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] );
/**
* \brief DES-ECB block encryption/decryption
*
* \param ctx DES context
* \param input 64-bit input block
* \param output 64-bit output block
*
* \return 0 if successful
*/
int des_crypt_ecb( des_context *ctx,
const unsigned char input[8],
unsigned char output[8] );
#if defined(POLARSSL_CIPHER_MODE_CBC)
/**
* \brief DES-CBC buffer encryption/decryption
*
* \param ctx DES context
* \param mode DES_ENCRYPT or DES_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*/
int des_crypt_cbc( des_context *ctx,
int mode,
size_t length,
unsigned char iv[8],
const unsigned char *input,
unsigned char *output );
#endif /* POLARSSL_CIPHER_MODE_CBC */
/**
* \brief 3DES-ECB block encryption/decryption
*
* \param ctx 3DES context
* \param input 64-bit input block
* \param output 64-bit output block
*
* \return 0 if successful
*/
int des3_crypt_ecb( des3_context *ctx,
const unsigned char input[8],
unsigned char output[8] );
#if defined(POLARSSL_CIPHER_MODE_CBC)
/**
* \brief 3DES-CBC buffer encryption/decryption
*
* \param ctx 3DES context
* \param mode DES_ENCRYPT or DES_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful, or POLARSSL_ERR_DES_INVALID_INPUT_LENGTH
*/
int des3_crypt_cbc( des3_context *ctx,
int mode,
size_t length,
unsigned char iv[8],
const unsigned char *input,
unsigned char *output );
#endif /* POLARSSL_CIPHER_MODE_CBC */
#ifdef __cplusplus
}
#endif
#else /* POLARSSL_DES_ALT */
#include "des_alt.h"
#endif /* POLARSSL_DES_ALT */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int des_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* des.h */

View file

@ -0,0 +1,656 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "cipherutils.h"
#include "cipher.h"
#include "ikeys.h"
#include "elite_crack.h"
#include "fileutils.h"
#include "des.h"
/**
* @brief Permutes a key from standard NIST format to Iclass specific format
* from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220
*
* If you permute [6c 8d 44 f9 2a 2d 01 bf] you get [8a 0d b9 88 bb a7 90 ea] as shown below.
*
* 1 0 1 1 1 1 1 1 bf
* 0 0 0 0 0 0 0 1 01
* 0 0 1 0 1 1 0 1 2d
* 0 0 1 0 1 0 1 0 2a
* 1 1 1 1 1 0 0 1 f9
* 0 1 0 0 0 1 0 0 44
* 1 0 0 0 1 1 0 1 8d
* 0 1 1 0 1 1 0 0 6c
*
* 8 0 b 8 b a 9 e
* a d 9 8 b 7 0 a
*
* @param key
* @param dest
*/
void permutekey(uint8_t key[8], uint8_t dest[8])
{
int i;
for(i = 0 ; i < 8 ; i++)
{
dest[i] = (((key[7] & (0x80 >> i)) >> (7-i)) << 7) |
(((key[6] & (0x80 >> i)) >> (7-i)) << 6) |
(((key[5] & (0x80 >> i)) >> (7-i)) << 5) |
(((key[4] & (0x80 >> i)) >> (7-i)) << 4) |
(((key[3] & (0x80 >> i)) >> (7-i)) << 3) |
(((key[2] & (0x80 >> i)) >> (7-i)) << 2) |
(((key[1] & (0x80 >> i)) >> (7-i)) << 1) |
(((key[0] & (0x80 >> i)) >> (7-i)) << 0);
}
return;
}
/**
* Permutes a key from iclass specific format to NIST format
* @brief permutekey_rev
* @param key
* @param dest
*/
void permutekey_rev(uint8_t key[8], uint8_t dest[8])
{
int i;
for(i = 0 ; i < 8 ; i++)
{
dest[7-i] = (((key[0] & (0x80 >> i)) >> (7-i)) << 7) |
(((key[1] & (0x80 >> i)) >> (7-i)) << 6) |
(((key[2] & (0x80 >> i)) >> (7-i)) << 5) |
(((key[3] & (0x80 >> i)) >> (7-i)) << 4) |
(((key[4] & (0x80 >> i)) >> (7-i)) << 3) |
(((key[5] & (0x80 >> i)) >> (7-i)) << 2) |
(((key[6] & (0x80 >> i)) >> (7-i)) << 1) |
(((key[7] & (0x80 >> i)) >> (7-i)) << 0);
}
}
/**
* Helper function for hash1
* @brief rr
* @param val
* @return
*/
uint8_t rr(uint8_t val)
{
return val >> 1 | (( val & 1) << 7);
}
/**
* Helper function for hash1
* @brief rl
* @param val
* @return
*/
uint8_t rl(uint8_t val)
{
return val << 1 | (( val & 0x80) >> 7);
}
/**
* Helper function for hash1
* @brief swap
* @param val
* @return
*/
uint8_t swap(uint8_t val)
{
return ((val >> 4) & 0xFF) | ((val &0xFF) << 4);
}
/**
* Hash1 takes CSN as input, and determines what bytes in the keytable will be used
* when constructing the K_sel.
* @param csn the CSN used
* @param k output
*/
void hash1(uint8_t csn[] , uint8_t k[])
{
k[0] = csn[0]^csn[1]^csn[2]^csn[3]^csn[4]^csn[5]^csn[6]^csn[7];
k[1] = csn[0]+csn[1]+csn[2]+csn[3]+csn[4]+csn[5]+csn[6]+csn[7];
k[2] = rr(swap( csn[2]+k[1] ));
k[3] = rr(swap( csn[3]+k[0] ));
k[4] = ~rr(swap( csn[4]+k[2] ))+1;
k[5] = ~rr(swap( csn[5]+k[3] ))+1;
k[6] = rr( csn[6]+(k[4]^0x3c) );
k[7] = rl( csn[7]+(k[5]^0xc3) );
int i;
for(i = 7; i >=0; i--)
k[i] = k[i] & 0x7F;
}
/**
Definition 14. Define the rotate key function rk : (F 82 ) 8 × N (F 82 ) 8 as
rk(x [0] . . . x [7] , 0) = x [0] . . . x [7]
rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n)
**/
void rk(uint8_t *key, uint8_t n, uint8_t *outp_key)
{
memcpy(outp_key, key, 8);
uint8_t j;
while(n-- > 0)
for(j=0; j < 8 ; j++)
outp_key[j] = rl(outp_key[j]);
return;
}
static des_context ctx_enc = {DES_ENCRYPT,{0}};
static des_context ctx_dec = {DES_DECRYPT,{0}};
void desdecrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output)
{
uint8_t key_std_format[8] = {0};
permutekey_rev(iclass_key, key_std_format);
des_setkey_dec( &ctx_dec, key_std_format);
des_crypt_ecb(&ctx_dec,input,output);
}
void desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output)
{
uint8_t key_std_format[8] = {0};
permutekey_rev(iclass_key, key_std_format);
des_setkey_enc( &ctx_enc, key_std_format);
des_crypt_ecb(&ctx_enc,input,output);
}
/**
* @brief Insert uint8_t[8] custom master key to calculate hash2 and return key_select.
* @param key unpermuted custom key
* @param hash1 hash1
* @param key_sel output key_sel=h[hash1[i]]
*/
void hash2(uint8_t *key64, uint8_t *outp_keytable)
{
/**
*Expected:
* High Security Key Table
00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ******/
uint8_t key64_negated[8] = {0};
uint8_t z[8][8]={{0},{0}};
uint8_t temp_output[8]={0};
//calculate complement of key
int i;
for(i=0;i<8;i++)
key64_negated[i]= ~key64[i];
// Once again, key is on iclass-format
desencrypt_iclass(key64, key64_negated, z[0]);
prnlog("\nHigh security custom key (Kcus):");
printvar("z0 ", z[0],8);
uint8_t y[8][8]={{0},{0}};
// y[0]=DES_dec(z[0],~key)
// Once again, key is on iclass-format
desdecrypt_iclass(z[0], key64_negated, y[0]);
printvar("y0 ", y[0],8);
for(i=1; i<8; i++)
{
// z [i] = DES dec (rk(K cus , i), z [i1] )
rk(key64, i, temp_output);
//y [i] = DES enc (rk(K cus , i), y [i1] )
desdecrypt_iclass(temp_output,z[i-1], z[i]);
desencrypt_iclass(temp_output,y[i-1], y[i]);
}
if(outp_keytable != NULL)
{
for(i = 0 ; i < 8 ; i++)
{
memcpy(outp_keytable+i*16,y[i],8);
memcpy(outp_keytable+8+i*16,z[i],8);
}
}else
{
printarr_human_readable("hash2", outp_keytable,128);
}
}
/**
* @brief Reads data from the iclass-reader-attack dump file.
* @param dump, data from a iclass reader attack dump. The format of the dumpdata is expected to be as follows:
* <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC><8 byte HASH1><1 byte NUM_BYTES_TO_RECOVER><3 bytes BYTES_TO_RECOVER>
* .. N times...
*
* So the first attack, with 3 bytes to recover would be : ... 03000145
* And a later attack, with 1 byte to recover (byte 0x5)would be : ...01050000
* And an attack, with 2 bytes to recover (byte 0x5 and byte 0x07 )would be : ...02050700
*
* @param cc_nr an array to store cc_nr into (12 bytes)
* @param csn an arracy ot store CSN into (8 bytes)
* @param received_mac an array to store MAC into (4 bytes)
* @param i the number to read. Should be less than 127, or something is wrong...
* @return
*/
int _readFromDump(uint8_t dump[], dumpdata* item, uint8_t i)
{
size_t itemsize = sizeof(dumpdata);
//dumpdata item = {0};
memcpy(item,dump+i*itemsize, itemsize);
if(true)
{
printvar("csn", item->csn,8);
printvar("cc_nr", item->cc_nr,12);
printvar("mac", item->mac,4);
}
return 0;
}
static uint32_t startvalue = 0;
/**
* @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac.
*This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced
*on the fly. If it finds that more than three bytes need to be bruteforced, it aborts.
*It updates the keytable with the findings, also using the upper half of the 16-bit ints
*to signal if the particular byte has been cracked or not.
*
* @param dump The dumpdata from iclass reader attack.
* @param keytable where to write found values.
* @return
*/
int bruteforceItem(dumpdata item, uint16_t keytable[])
{
int errors = 0;
uint8_t key_sel_p[8] = { 0 };
uint8_t div_key[8] = {0};
int found = false;
uint8_t key_sel[8] = {0};
uint8_t calculated_MAC[4] = { 0 };
//Get the key index (hash1)
uint8_t key_index[8] = {0};
hash1(item.csn, key_index);
/*
* Determine which bytes to retrieve. A hash is typically
* 01010000454501
* We go through that hash, and in the corresponding keytable, we put markers
* on what state that particular index is:
* - CRACKED (this has already been cracked)
* - BEING_CRACKED (this is being bruteforced now)
* - CRACK_FAILED (self-explaining...)
*
* The markers are placed in the high area of the 16 bit key-table.
* Only the lower eight bits correspond to the (hopefully cracked) key-value.
**/
uint8_t bytes_to_recover[3] = {0};
uint8_t numbytes_to_recover = 0 ;
int i;
for(i =0 ; i < 8 ; i++)
{
if(keytable[key_index[i]] & (CRACKED | BEING_CRACKED)) continue;
bytes_to_recover[numbytes_to_recover++] = key_index[i];
keytable[key_index[i]] |= BEING_CRACKED;
if(numbytes_to_recover > 3)
{
prnlog("The CSN requires > 3 byte bruteforce, not supported");
printvar("CSN", item.csn,8);
printvar("HASH1", key_index,8);
//Before we exit, reset the 'BEING_CRACKED' to zero
keytable[bytes_to_recover[0]] &= ~BEING_CRACKED;
keytable[bytes_to_recover[1]] &= ~BEING_CRACKED;
keytable[bytes_to_recover[2]] &= ~BEING_CRACKED;
return 1;
}
}
/*
*A uint32 has room for 4 bytes, we'll only need 24 of those bits to bruteforce up to three bytes,
*/
uint32_t brute = startvalue;
/*
Determine where to stop the bruteforce. A 1-byte attack stops after 256 tries,
(when brute reaches 0x100). And so on...
bytes_to_recover = 1 --> endmask = 0x0000100
bytes_to_recover = 2 --> endmask = 0x0010000
bytes_to_recover = 3 --> endmask = 0x1000000
*/
uint32_t endmask = 1 << 8*numbytes_to_recover;
for(i =0 ; i < numbytes_to_recover && numbytes_to_recover > 1; i++)
prnlog("Bruteforcing byte %d", bytes_to_recover[i]);
while(!found && !(brute & endmask))
{
//Update the keytable with the brute-values
for(i =0 ; i < numbytes_to_recover; i++)
{
keytable[bytes_to_recover[i]] &= 0xFF00;
keytable[bytes_to_recover[i]] |= (brute >> (i*8) & 0xFF);
}
// Piece together the key
key_sel[0] = keytable[key_index[0]] & 0xFF;key_sel[1] = keytable[key_index[1]] & 0xFF;
key_sel[2] = keytable[key_index[2]] & 0xFF;key_sel[3] = keytable[key_index[3]] & 0xFF;
key_sel[4] = keytable[key_index[4]] & 0xFF;key_sel[5] = keytable[key_index[5]] & 0xFF;
key_sel[6] = keytable[key_index[6]] & 0xFF;key_sel[7] = keytable[key_index[7]] & 0xFF;
//Permute from iclass format to standard format
permutekey_rev(key_sel,key_sel_p);
//Diversify
diversifyKey(item.csn, key_sel_p, div_key);
//Calc mac
doMAC(item.cc_nr,12, div_key,calculated_MAC);
if(memcmp(calculated_MAC, item.mac, 4) == 0)
{
for(i =0 ; i < numbytes_to_recover; i++)
prnlog("=> %d: 0x%02x", bytes_to_recover[i],0xFF & keytable[bytes_to_recover[i]]);
found = true;
break;
}
brute++;
if((brute & 0xFFFF) == 0)
{
printf("%d",(brute >> 16) & 0xFF);
fflush(stdout);
}
}
if(! found)
{
prnlog("Failed to recover %d bytes using the following CSN",numbytes_to_recover);
printvar("CSN",item.csn,8);
errors++;
//Before we exit, reset the 'BEING_CRACKED' to zero
for(i =0 ; i < numbytes_to_recover; i++)
{
keytable[bytes_to_recover[i]] &= 0xFF;
keytable[bytes_to_recover[i]] |= CRACK_FAILED;
}
}else
{
for(i =0 ; i < numbytes_to_recover; i++)
{
keytable[bytes_to_recover[i]] &= 0xFF;
keytable[bytes_to_recover[i]] |= CRACKED;
}
}
return errors;
}
/**
* From dismantling iclass-paper:
* Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] .
* Then he can simply recover the master custom key K_cus by computing
* K_cus = ~DES(z[0] , y[0] ) .
*
* Furthermore, the adversary is able to verify that he has the correct K cus by
* checking whether z [0] = DES enc (K_cus , ~K_cus ).
* @param keytable an array (128 bytes) of hash2(kcus)
* @param master_key where to put the master key
* @return 0 for ok, 1 for failz
*/
int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] )
{
des_context ctx_e = {DES_ENCRYPT,{0}};
uint8_t z_0[8] = {0};
uint8_t y_0[8] = {0};
uint8_t z_0_rev[8] = {0};
uint8_t key64[8] = {0};
uint8_t key64_negated[8] = {0};
uint8_t result[8] = {0};
// y_0 and z_0 are the first 16 bytes of the keytable
memcpy(y_0,first16bytes,8);
memcpy(z_0,first16bytes+8,8);
// Our DES-implementation uses the standard NIST
// format for keys, thus must translate from iclass
// format to NIST-format
permutekey_rev(z_0, z_0_rev);
// ~K_cus = DESenc(z[0], y[0])
des_setkey_enc( &ctx_e, z_0_rev );
des_crypt_ecb(&ctx_e, y_0, key64_negated);
int i;
for(i = 0; i < 8 ; i++)
{
key64[i] = ~key64_negated[i];
}
// Can we verify that the key is correct?
// Once again, key is on iclass-format
uint8_t key64_stdformat[8] = {0};
permutekey_rev(key64, key64_stdformat);
des_setkey_enc( &ctx_e, key64_stdformat );
des_crypt_ecb(&ctx_e, key64_negated, result);
prnlog("\nHigh security custom key (Kcus):");
printvar("Std format ", key64_stdformat,8);
printvar("Iclass format", key64,8);
if(master_key != NULL)
memcpy(master_key, key64, 8);
if(memcmp(z_0,result,4) != 0)
{
prnlog("Failed to verify calculated master key (k_cus)! Something is wrong.");
return 1;
}else{
prnlog("Key verified ok!\n");
}
return 0;
}
/**
* @brief Same as bruteforcefile, but uses a an array of dumpdata instead
* @param dump
* @param dumpsize
* @param keytable
* @return
*/
int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[])
{
uint8_t i;
int errors = 0;
size_t itemsize = sizeof(dumpdata);
clock_t t1 = clock();
dumpdata* attack = (dumpdata* ) malloc(itemsize);
for(i = 0 ; i * itemsize < dumpsize ; i++ )
{
memcpy(attack,dump+i*itemsize, itemsize);
errors += bruteforceItem(*attack, keytable);
}
free(attack);
clock_t t2 = clock();
float diff = (((float)t2 - (float)t1) / CLOCKS_PER_SEC );
prnlog("\nPerformed full crack in %f seconds",diff);
// Pick out the first 16 bytes of the keytable.
// The keytable is now in 16-bit ints, where the upper 8 bits
// indicate crack-status. Those must be discarded for the
// master key calculation
uint8_t first16bytes[16] = {0};
for(i = 0 ; i < 16 ; i++)
{
first16bytes[i] = keytable[i] & 0xFF;
if(!(keytable[i] & CRACKED))
{
prnlog("Error, we are missing byte %d, custom key calculation will fail...", i);
}
}
errors += calculateMasterKey(first16bytes, NULL);
return errors;
}
/**
* Perform a bruteforce against a file which has been saved by pm3
*
* @brief bruteforceFile
* @param filename
* @return
*/
int bruteforceFile(const char *filename, uint16_t keytable[])
{
FILE *f = fopen(filename, "rb");
if(!f) {
prnlog("Failed to read from file '%s'", filename);
return 1;
}
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
uint8_t *dump = malloc(fsize);
size_t bytes_read = fread(dump, fsize, 1, f);
fclose(f);
if (bytes_read < fsize)
{
prnlog("Error, could only read %d bytes (should be %d)",bytes_read, fsize );
}
return bruteforceDump(dump,fsize,keytable);
}
/**
*
* @brief Same as above, if you don't care about the returned keytable (results only printed on screen)
* @param filename
* @return
*/
int bruteforceFileNoKeys(const char *filename)
{
uint16_t keytable[128] = {0};
return bruteforceFile(filename, keytable);
}
// ---------------------------------------------------------------------------------
// ALL CODE BELOW THIS LINE IS PURELY TESTING
// ---------------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// TEST CODE BELOW
// ----------------------------------------------------------------------------
int _testBruteforce()
{
int errors = 0;
if(true){
// First test
prnlog("[+] Testing crack from dumpfile...");
/**
Expected values for the dumpfile:
High Security Key Table
00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ****
**/
uint16_t keytable[128] = {0};
//save some time...
startvalue = 0x7B0000;
errors |= bruteforceFile("iclass_dump.bin",keytable);
}
return errors;
}
int _test_iclass_key_permutation()
{
uint8_t testcase[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
uint8_t testcase_output[8] = {0};
uint8_t testcase_output_correct[8] = {0x8a,0x0d,0xb9,0x88,0xbb,0xa7,0x90,0xea};
uint8_t testcase_output_rev[8] = {0};
permutekey(testcase, testcase_output);
permutekey_rev(testcase_output, testcase_output_rev);
if(memcmp(testcase_output, testcase_output_correct,8) != 0)
{
prnlog("Error with iclass key permute!");
printarr("testcase_output", testcase_output, 8);
printarr("testcase_output_correct", testcase_output_correct, 8);
return 1;
}
if(memcmp(testcase, testcase_output_rev, 8) != 0)
{
prnlog("Error with reverse iclass key permute");
printarr("testcase", testcase, 8);
printarr("testcase_output_rev", testcase_output_rev, 8);
return 1;
}
prnlog("[+] Iclass key permutation OK!");
return 0;
}
int testElite()
{
prnlog("[+] Testing iClass Elite functinality...");
prnlog("[+] Testing hash2");
uint8_t k_cus[8] = {0x5B,0x7C,0x62,0xC4,0x91,0xC1,0x1B,0x39};
/**
*Expected:
* High Security Key Table
00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ****
*/
uint8_t keytable[128] = {0};
hash2(k_cus, keytable);
printarr_human_readable("Hash2", keytable, 128);
if(keytable[3] == 0xA1 && keytable[0x30] == 0xA3 && keytable[0x6F] == 0x95)
{
prnlog("[+] Hash2 looks fine...");
}
prnlog("[+] Testing key diversification ...");
int errors = 0 ;
errors +=_test_iclass_key_permutation();
errors += _testBruteforce();
return errors;
}

View file

@ -0,0 +1,108 @@
#ifndef ELITE_CRACK_H
#define ELITE_CRACK_H
void permutekey(uint8_t key[8], uint8_t dest[8]);
/**
* Permutes a key from iclass specific format to NIST format
* @brief permutekey_rev
* @param key
* @param dest
*/
void permutekey_rev(uint8_t key[8], uint8_t dest[8]);
//Crack status, see below
#define CRACKED 0x0100
#define BEING_CRACKED 0x0200
#define CRACK_FAILED 0x0400
/**
* Perform a bruteforce against a file which has been saved by pm3
*
* @brief bruteforceFile
* @param filename
* @param keytable an arrah (128 x 16 bit ints). This is where the keydata is stored.
* OBS! the upper part of the 16 bits store crack-status,
* @return
*/
int bruteforceFile(const char *filename, uint16_t keytable[]);
/**
*
* @brief Same as above, if you don't care about the returned keytable (results only printed on screen)
* @param filename
* @return
*/
int bruteforceFileNoKeys(const char *filename);
/**
* @brief Same as bruteforcefile, but uses a an array of dumpdata instead
* @param dump
* @param dumpsize
* @param keytable
* @return
*/
int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]);
/**
This is how we expect each 'entry' in a dumpfile to look
**/
typedef struct {
uint8_t csn[8];
uint8_t cc_nr[12];
uint8_t mac[4];
}dumpdata;
/**
* @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac.
*This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced
*on the fly. If it finds that more than three bytes need to be bruteforced, it aborts.
*It updates the keytable with the findings, also using the upper half of the 16-bit ints
*to signal if the particular byte has been cracked or not.
*
* @param dump The dumpdata from iclass reader attack.
* @param keytable where to write found values.
* @return
*/
int bruteforceItem(dumpdata item, uint16_t keytable[]);
/**
* Hash1 takes CSN as input, and determines what bytes in the keytable will be used
* when constructing the K_sel.
* @param csn the CSN used
* @param k output
*/
void hash1(uint8_t csn[] , uint8_t k[]);
void hash2(uint8_t *key64, uint8_t *outp_keytable);
/**
* From dismantling iclass-paper:
* Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] .
* Then he can simply recover the master custom key K_cus by computing
* K_cus = ~DES(z[0] , y[0] ) .
*
* Furthermore, the adversary is able to verify that he has the correct K cus by
* checking whether z [0] = DES enc (K_cus , ~K_cus ).
* @param keytable an array (128 bytes) of hash2(kcus)
* @param master_key where to put the master key
* @return 0 for ok, 1 for failz
*/
int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] );
/**
* @brief Test function
* @return
*/
int testElite();
/**
Here are some pretty optimal values that can be used to recover necessary data in only
eight auth attempts.
// CSN HASH1 Bytes recovered //
{ {0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0} , {0x01,0x01,0x00,0x00,0x45,0x01,0x45,0x45 } ,{0,1 }},
{ {0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0} , {0x02,0x0c,0x01,0x00,0x45,0x01,0x45,0x45} , {2,12}},
{ {0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0} , {0x07,0x45,0x0b,0x00,0x45,0x01,0x45,0x45} , {7,11}},
{ {0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0} , {0x03,0x0f,0x00,0x00,0x45,0x01,0x45,0x45} , {3,15}},
{ {0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0} , {0x04,0x00,0x08,0x00,0x45,0x01,0x45,0x45} , {4,8}},
{ {0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0} , {0x0e,0x06,0x08,0x00,0x45,0x01,0x45,0x45} , {6,14}},
{ {0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0} , {0x0b,0x09,0x0f,0x00,0x45,0x01,0x05,0x45} , {9,5}},
{ {0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0} , {0x0d,0x0f,0x0a,0x00,0x45,0x01,0x05,0x45} , {10,13}},
**/
#endif

View file

@ -0,0 +1,65 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <stdarg.h>
#include "fileutils.h"
#include "ui.h"
/**
* @brief checks if a file exists
* @param filename
* @return
*/
int fileExists(const char *filename) {
struct _stat st;
int result = stat(filename, &st);
return result == 0;
}
int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen)
{
int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5);
char * fileName = malloc(size);
memset(fileName,0,size);
int num = 1;
sprintf(fileName,"%s.%s", preferredName, suffix);
while(fileExists(fileName))
{
sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
num++;
}
/* We should have a valid filename now, e.g. dumpdata-3.bin */
/*Opening file for writing in binary mode*/
FILE *fileHandle=fopen(fileName,"wb");
if(!fileHandle) {
prnlog("Failed to write to file '%s'", fileName);
return 1;
}
fwrite(data, 1, datalen, fileHandle);
fclose(fileHandle);
prnlog("Saved data to '%s'", fileName);
free(fileName);
return 0;
}
/**
* Utility function to print to console. This is used consistently within the library instead
* of printf, but it actually only calls printf (and adds a linebreak).
* The reason to have this method is to
* make it simple to plug this library into proxmark, which has this function already to
* write also to a logfile. When doing so, just delete this function.
* @param fmt
*/
void prnlog(char *fmt, ...)
{
va_list args;
va_start(args,fmt);
PrintAndLog(fmt, args);
//vprintf(fmt,args);
va_end(args);
//printf("\n");
}

View file

@ -0,0 +1,24 @@
#ifndef FILEUTILS_H
#define FILEUTILS_H
/**
* @brief Utility function to save data to a file. This method takes a preferred name, but if that
* file already exists, it tries with another name until it finds something suitable.
* E.g. dumpdata-15.txt
* @param preferredName
* @param suffix the file suffix. Leave out the ".".
* @param data The binary data to write to the file
* @param datalen the length of the data
* @return 0 for ok, 1 for failz
*/
int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen);
/**
* Utility function to print to console. This is used consistently within the library instead
* of printf, but it actually only calls printf. The reason to have this method is to
*make it simple to plug this library into proxmark, which has this function already to
* write also to a logfile. When doing so, just point this function to use PrintAndLog
* @param fmt
*/
void prnlog(char *fmt, ...);
#endif // FILEUTILS_H

878
client/loclass/ikeys.c Normal file
View file

@ -0,0 +1,878 @@
/*****************************************************************************
* This file is part of iClassCipher. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* This is a reference implementation of iclass key diversification. I'm sure it can be
* optimized heavily. It is written for ease of understanding and correctness, please take it
* and tweak it and make a super fast version instead, using this for testing and verification.
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file 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 IClassCipher. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
/**
From "Dismantling iclass":
This section describes in detail the built-in key diversification algorithm of iClass.
Besides the obvious purpose of deriving a card key from a master key, this
algorithm intends to circumvent weaknesses in the cipher by preventing the
usage of certain weak keys. In order to compute a diversified key, the iClass
reader first encrypts the card identity id with the master key K, using single
DES. The resulting ciphertext is then input to a function called hash0 which
outputs the diversified key k.
k = hash0(DES enc (id, K))
Here the DES encryption of id with master key K outputs a cryptogram c
of 64 bits. These 64 bits are divided as c = x, y, z [0] , . . . , z [7] F 82 × F 82 × (F 62 ) 8
which is used as input to the hash0 function. This function introduces some
obfuscation by performing a number of permutations, complement and modulo
operations, see Figure 2.5. Besides that, it checks for and removes patterns like
similar key bytes, which could produce a strong bias in the cipher. Finally, the
output of hash0 is the diversified card key k = k [0] , . . . , k [7] (F 82 ) 8 .
**/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
#include "fileutils.h"
#include "cipherutils.h"
#include "des.h"
uint8_t pi[35] = {0x0F,0x17,0x1B,0x1D,0x1E,0x27,0x2B,0x2D,0x2E,0x33,0x35,0x39,0x36,0x3A,0x3C,0x47,0x4B,0x4D,0x4E,0x53,0x55,0x56,0x59,0x5A,0x5C,0x63,0x65,0x66,0x69,0x6A,0x6C,0x71,0x72,0x74,0x78};
static des_context ctx_enc = {DES_ENCRYPT,{0}};
static des_context ctx_dec = {DES_DECRYPT,{0}};
static int debug_print = 0;
/**
* @brief The key diversification algorithm uses 6-bit bytes.
* This implementation uses 64 bit uint to pack seven of them into one
* variable. When they are there, they are placed as follows:
* XXXX XXXX N0 .... N7, occupying the lsat 48 bits.
*
* This function picks out one from such a collection
* @param all
* @param n bitnumber
* @return
*/
uint8_t getSixBitByte(uint64_t c, int n)
{
return (c >> (42-6*n)) & 0x3F;
}
/**
* @brief Puts back a six-bit 'byte' into a uint64_t.
* @param c buffer
* @param z the value to place there
* @param n bitnumber.
*/
void pushbackSixBitByte(uint64_t *c, uint8_t z, int n)
{
//0x XXXX YYYY ZZZZ ZZZZ ZZZZ
// ^z0 ^z7
//z0: 1111 1100 0000 0000
uint64_t masked = z & 0x3F;
uint64_t eraser = 0x3F;
masked <<= 42-6*n;
eraser <<= 42-6*n;
//masked <<= 6*n;
//eraser <<= 6*n;
eraser = ~eraser;
(*c) &= eraser;
(*c) |= masked;
}
/**
* @brief Swaps the z-values.
* If the input value has format XYZ0Z1...Z7, the output will have the format
* XYZ7Z6...Z0 instead
* @param c
* @return
*/
uint64_t swapZvalues(uint64_t c)
{
uint64_t newz = 0;
pushbackSixBitByte(&newz, getSixBitByte(c,0),7);
pushbackSixBitByte(&newz, getSixBitByte(c,1),6);
pushbackSixBitByte(&newz, getSixBitByte(c,2),5);
pushbackSixBitByte(&newz, getSixBitByte(c,3),4);
pushbackSixBitByte(&newz, getSixBitByte(c,4),3);
pushbackSixBitByte(&newz, getSixBitByte(c,5),2);
pushbackSixBitByte(&newz, getSixBitByte(c,6),1);
pushbackSixBitByte(&newz, getSixBitByte(c,7),0);
newz |= (c & 0xFFFF000000000000);
return newz;
}
/**
* @return 4 six-bit bytes chunked into a uint64_t,as 00..00a0a1a2a3
*/
uint64_t ck(int i, int j, uint64_t z)
{
if(i == 1 && j == -1)
{
// ck(1, 1, z [0] . . . z [3] ) = z [0] . . . z [3]
return z;
}else if( j == -1)
{
// ck(i, 1, z [0] . . . z [3] ) = ck(i 1, i 2, z [0] . . . z [3] )
return ck(i-1,i-2, z);
}
if(getSixBitByte(z,i) == getSixBitByte(z,j))
{
//ck(i, j 1, z [0] . . . z [i] ← j . . . z [3] )
uint64_t newz = 0;
int c;
for(c = 0; c < 4 ;c++)
{
uint8_t val = getSixBitByte(z,c);
if(c == i)
{
pushbackSixBitByte(&newz, j, c);
}else
{
pushbackSixBitByte(&newz, val, c);
}
}
return ck(i,j-1,newz);
}else
{
return ck(i,j-1,z);
}
}
/**
Definition 8.
Let the function check : (F 62 ) 8 (F 62 ) 8 be defined as
check(z [0] . . . z [7] ) = ck(3, 2, z [0] . . . z [3] ) · ck(3, 2, z [4] . . . z [7] )
where ck : N × N × (F 62 ) 4 (F 62 ) 4 is defined as
ck(1, 1, z [0] . . . z [3] ) = z [0] . . . z [3]
ck(i, 1, z [0] . . . z [3] ) = ck(i 1, i 2, z [0] . . . z [3] )
ck(i, j, z [0] . . . z [3] ) =
ck(i, j 1, z [0] . . . z [i] j . . . z [3] ), if z [i] = z [j] ;
ck(i, j 1, z [0] . . . z [3] ), otherwise
otherwise.
**/
uint64_t check(uint64_t z)
{
//These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
// ck(3, 2, z [0] . . . z [3] )
uint64_t ck1 = ck(3,2, z );
// ck(3, 2, z [4] . . . z [7] )
uint64_t ck2 = ck(3,2, z << 24);
//The ck function will place the values
// in the middle of z.
ck1 &= 0x00000000FFFFFF000000;
ck2 &= 0x00000000FFFFFF000000;
return ck1 | ck2 >> 24;
}
void permute(BitstreamIn *p_in, uint64_t z,int l,int r, BitstreamOut* out)
{
if(bitsLeft(p_in) == 0)
{
return;
}
bool pn = tailBit(p_in);
if( pn ) // pn = 1
{
uint8_t zl = getSixBitByte(z,l);
push6bits(out, zl+1);
permute(p_in, z, l+1,r, out);
}else // otherwise
{
uint8_t zr = getSixBitByte(z,r);
push6bits(out, zr);
permute(p_in,z,l,r+1,out);
}
}
void printbegin()
{
if(debug_print <2)
return ;
prnlog(" | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
}
void printState(char* desc, uint64_t c)
{
if(debug_print < 2)
return ;
printf("%s : ", desc);
uint8_t x = (c & 0xFF00000000000000 ) >> 56;
uint8_t y = (c & 0x00FF000000000000 ) >> 48;
printf(" %02x %02x", x,y);
int i ;
for(i =0 ; i < 8 ; i++)
{
printf(" %02x", getSixBitByte(c,i));
}
printf("\n");
}
/**
* @brief
*Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 (F 82 ) 8 be defined as
* hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
* z'[i] = (z[i] mod (63-i)) + i i = 0...3
* z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3
* = check(z');
* @param c
* @param k this is where the diversified key is put (should be 8 bytes)
* @return
*/
void hash0(uint64_t c, uint8_t k[8])
{
c = swapZvalues(c);
printbegin();
printState("origin",c);
//These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
// x = 8 bits
// y = 8 bits
// z0-z7 6 bits each : 48 bits
uint8_t x = (c & 0xFF00000000000000 ) >> 56;
uint8_t y = (c & 0x00FF000000000000 ) >> 48;
int n;
uint8_t zn, zn4, _zn, _zn4;
uint64_t zP = 0;
for(n = 0; n < 4 ; n++)
{
zn = getSixBitByte(c,n);
zn4 = getSixBitByte(c,n+4);
_zn = (zn % (63-n)) + n;
_zn4 = (zn4 % (64-n)) + n;
pushbackSixBitByte(&zP, _zn,n);
pushbackSixBitByte(&zP, _zn4,n+4);
}
printState("0|0|z'",zP);
uint64_t zCaret = check(zP);
printState("0|0|z^",zP);
uint8_t p = pi[x % 35];
if(x & 1) //Check if x7 is 1
{
p = ~p;
}
if(debug_print >= 2) prnlog("p:%02x", p);
BitstreamIn p_in = { &p, 8,0 };
uint8_t outbuffer[] = {0,0,0,0,0,0,0,0};
BitstreamOut out = {outbuffer,0,0};
permute(&p_in,zCaret,0,4,&out);//returns 48 bits? or 6 8-bytes
//Out is now a buffer containing six-bit bytes, should be 48 bits
// if all went well
//Shift z-values down onto the lower segment
uint64_t zTilde = x_bytes_to_num(outbuffer,8);
zTilde >>= 16;
printState("0|0|z~", zTilde);
int i;
int zerocounter =0 ;
for(i =0 ; i < 8 ; i++)
{
// the key on index i is first a bit from y
// then six bits from z,
// then a bit from p
// Init with zeroes
k[i] = 0;
// First, place yi leftmost in k
//k[i] |= (y << i) & 0x80 ;
// First, place y(7-i) leftmost in k
k[i] |= (y << (7-i)) & 0x80 ;
uint8_t zTilde_i = getSixBitByte(zTilde, i);
// zTildeI is now on the form 00XXXXXX
// with one leftshift, it'll be
// 0XXXXXX0
// So after leftshift, we can OR it into k
// However, when doing complement, we need to
// again MASK 0XXXXXX0 (0x7E)
zTilde_i <<= 1;
//Finally, add bit from p or p-mod
//Shift bit i into rightmost location (mask only after complement)
uint8_t p_i = p >> i & 0x1;
if( k[i] )// yi = 1
{
//printf("k[%d] +1\n", i);
k[i] |= ~zTilde_i & 0x7E;
k[i] |= p_i & 1;
k[i] += 1;
}else // otherwise
{
k[i] |= zTilde_i & 0x7E;
k[i] |= (~p_i) & 1;
}
if((k[i] & 1 )== 0)
{
zerocounter ++;
}
}
}
/**
* @brief Performs Elite-class key diversification
* @param csn
* @param key
* @param div_key
*/
void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8])
{
// Prepare the DES key
des_setkey_enc( &ctx_enc, key);
uint8_t crypted_csn[8] = {0};
// Calculate DES(CSN, KEY)
des_crypt_ecb(&ctx_enc,csn, crypted_csn);
//Calculate HASH0(DES))
uint64_t crypt_csn = x_bytes_to_num(crypted_csn, 8);
//uint64_t crypted_csn_swapped = swapZvalues(crypt_csn);
hash0(crypt_csn,div_key);
}
void testPermute()
{
uint64_t x = 0;
pushbackSixBitByte(&x,0x00,0);
pushbackSixBitByte(&x,0x01,1);
pushbackSixBitByte(&x,0x02,2);
pushbackSixBitByte(&x,0x03,3);
pushbackSixBitByte(&x,0x04,4);
pushbackSixBitByte(&x,0x05,5);
pushbackSixBitByte(&x,0x06,6);
pushbackSixBitByte(&x,0x07,7);
uint8_t mres[8] = { getSixBitByte(x, 0),
getSixBitByte(x, 1),
getSixBitByte(x, 2),
getSixBitByte(x, 3),
getSixBitByte(x, 4),
getSixBitByte(x, 5),
getSixBitByte(x, 6),
getSixBitByte(x, 7)};
printarr("input_perm", mres,8);
uint8_t p = ~pi[0];
BitstreamIn p_in = { &p, 8,0 };
uint8_t outbuffer[] = {0,0,0,0,0,0,0,0};
BitstreamOut out = {outbuffer,0,0};
permute(&p_in, x,0,4, &out);
uint64_t permuted = x_bytes_to_num(outbuffer,8);
//printf("zTilde 0x%"PRIX64"\n", zTilde);
permuted >>= 16;
uint8_t res[8] = { getSixBitByte(permuted, 0),
getSixBitByte(permuted, 1),
getSixBitByte(permuted, 2),
getSixBitByte(permuted, 3),
getSixBitByte(permuted, 4),
getSixBitByte(permuted, 5),
getSixBitByte(permuted, 6),
getSixBitByte(permuted, 7)};
printarr("permuted", res, 8);
}
//These testcases are
//{ UID , TEMP_KEY, DIV_KEY} using the specific key
typedef struct
{
uint8_t uid[8];
uint8_t t_key[8];
uint8_t div_key[8];
} Testcase;
int testDES(Testcase testcase, des_context ctx_enc, des_context ctx_dec)
{
uint8_t des_encrypted_csn[8] = {0};
uint8_t decrypted[8] = {0};
uint8_t div_key[8] = {0};
int retval = des_crypt_ecb(&ctx_enc,testcase.uid,des_encrypted_csn);
retval |= des_crypt_ecb(&ctx_dec,des_encrypted_csn,decrypted);
if(memcmp(testcase.uid,decrypted,8) != 0)
{
//Decryption fail
prnlog("Encryption <-> Decryption FAIL");
printarr("Input", testcase.uid, 8);
printarr("Decrypted", decrypted, 8);
retval = 1;
}
if(memcmp(des_encrypted_csn,testcase.t_key,8) != 0)
{
//Encryption fail
prnlog("Encryption != Expected result");
printarr("Output", des_encrypted_csn, 8);
printarr("Expected", testcase.t_key, 8);
retval = 1;
}
uint64_t crypted_csn = x_bytes_to_num(des_encrypted_csn,8);
hash0(crypted_csn, div_key);
if(memcmp(div_key, testcase.div_key ,8) != 0)
{
//Key diversification fail
prnlog("Div key != expected result");
printarr(" csn ", testcase.uid,8);
printarr("{csn} ", des_encrypted_csn,8);
printarr("hash0 ", div_key, 8);
printarr("Expected", testcase.div_key, 8);
retval = 1;
}
return retval;
}
bool des_getParityBitFromKey(uint8_t key)
{//The top 7 bits is used
bool parity = ((key & 0x80) >> 7)
^ ((key & 0x40) >> 6) ^ ((key & 0x20) >> 5)
^ ((key & 0x10) >> 4) ^ ((key & 0x08) >> 3)
^ ((key & 0x04) >> 2) ^ ((key & 0x02) >> 1);
return !parity;
}
void des_checkParity(uint8_t* key)
{
int i;
int fails =0;
for(i =0 ; i < 8 ; i++)
{
bool parity = des_getParityBitFromKey(key[i]);
if(parity != (key[i] & 0x1))
{
fails++;
prnlog("[+] parity1 fail, byte %d [%02x] was %d, should be %d",i,key[i],(key[i] & 0x1),parity);
}
}
if(fails)
{
prnlog("[+] parity fails: %d", fails);
}else
{
prnlog("[+] Key syntax is with parity bits inside each byte");
}
}
Testcase testcases[] ={
{{0x8B,0xAC,0x60,0x1F,0x53,0xB8,0xED,0x11},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0xAE,0x51,0xE5,0x62,0xE7,0x9A,0x99,0x39},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01},{0x04,0x02,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x9B,0x21,0xE4,0x31,0x6A,0x00,0x29,0x62},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02},{0x06,0x04,0x02,0x08,0x01,0x03,0x05,0x07}},
{{0x65,0x24,0x0C,0x41,0x4F,0xC2,0x21,0x93},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04},{0x0A,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x7F,0xEB,0xAE,0x93,0xE5,0x30,0x08,0xBD},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08},{0x12,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x49,0x7B,0x70,0x74,0x9B,0x35,0x1B,0x83},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10},{0x22,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x02,0x3C,0x15,0x6B,0xED,0xA5,0x64,0x6C},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20},{0x42,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0xE8,0x37,0xE0,0xE2,0xC6,0x45,0x24,0xF3},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40},{0x02,0x06,0x04,0x08,0x01,0x03,0x05,0x07}},
{{0xAB,0xBD,0x30,0x05,0x29,0xC8,0xF7,0x12},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},{0x02,0x08,0x06,0x04,0x01,0x03,0x05,0x07}},
{{0x17,0xE8,0x97,0xF0,0x99,0xB6,0x79,0x31},{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00},{0x02,0x0C,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x49,0xA4,0xF0,0x8F,0x5F,0x96,0x83,0x16},{0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00},{0x02,0x14,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x60,0xF5,0x7E,0x54,0xAA,0x41,0x83,0xD4},{0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00},{0x02,0x24,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x1D,0xF6,0x3B,0x6B,0x85,0x55,0xF0,0x4B},{0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00},{0x02,0x44,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x1F,0xDC,0x95,0x1A,0xEA,0x6B,0x4B,0xB4},{0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00},{0x02,0x04,0x08,0x06,0x01,0x03,0x05,0x07}},
{{0xEC,0x93,0x72,0xF0,0x3B,0xA9,0xF5,0x0B},{0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00},{0x02,0x04,0x0A,0x08,0x01,0x03,0x05,0x07}},
{{0xDE,0x57,0x5C,0xBE,0x2D,0x55,0x03,0x12},{0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00},{0x02,0x04,0x0E,0x08,0x01,0x03,0x05,0x07}},
{{0x1E,0xD2,0xB5,0xCE,0x90,0xC9,0xC1,0xCC},{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00},{0x02,0x04,0x16,0x08,0x01,0x03,0x05,0x07}},
{{0xD8,0x65,0x96,0x4E,0xE7,0x74,0x99,0xB8},{0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00},{0x02,0x04,0x26,0x08,0x01,0x03,0x05,0x07}},
{{0xE3,0x7A,0x29,0x83,0x31,0xD5,0x3A,0x54},{0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00},{0x02,0x04,0x46,0x08,0x01,0x03,0x05,0x07}},
{{0x3A,0xB5,0x1A,0x34,0x34,0x25,0x12,0xF0},{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00},{0x02,0x04,0x06,0x0A,0x01,0x03,0x05,0x07}},
{{0xF2,0x88,0xEE,0x6F,0x70,0x6F,0xC2,0x52},{0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00},{0x02,0x04,0x06,0x0C,0x01,0x03,0x05,0x07}},
{{0x76,0xEF,0xEB,0x80,0x52,0x43,0x83,0x57},{0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00},{0x02,0x04,0x06,0x10,0x01,0x03,0x05,0x07}},
{{0x1C,0x09,0x8E,0x3B,0x23,0x23,0x52,0xB5},{0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00},{0x02,0x04,0x06,0x18,0x01,0x03,0x05,0x07}},
{{0xA9,0x13,0xA2,0xBE,0xCF,0x1A,0xC4,0x9A},{0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00},{0x02,0x04,0x06,0x28,0x01,0x03,0x05,0x07}},
{{0x25,0x56,0x4B,0xB0,0xC8,0x2A,0xD4,0x27},{0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00},{0x02,0x04,0x06,0x48,0x01,0x03,0x05,0x07}},
{{0xB1,0x04,0x57,0x3F,0xA7,0x16,0x62,0xD4},{0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x03,0x01,0x05,0x07}},
{{0x45,0x46,0xED,0xCC,0xE7,0xD3,0x8E,0xA3},{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x05,0x03,0x01,0x07}},
{{0x22,0x6D,0xB5,0x35,0xE0,0x5A,0xE0,0x90},{0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x09,0x03,0x05,0x07}},
{{0xB8,0xF5,0xE5,0x44,0xC5,0x98,0x4A,0xBD},{0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x11,0x03,0x05,0x07}},
{{0xAC,0x78,0x0A,0x23,0x9E,0xF6,0xBC,0xA0},{0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x21,0x03,0x05,0x07}},
{{0x46,0x6B,0x2D,0x70,0x41,0x17,0xBF,0x3D},{0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x41,0x03,0x05,0x07}},
{{0x64,0x44,0x24,0x71,0xA2,0x56,0xDF,0xB5},{0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x05,0x03,0x07}},
{{0xC4,0x00,0x52,0x24,0xA2,0xD6,0x16,0x7A},{0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x07,0x05,0x03}},
{{0xD8,0x4A,0x80,0x1E,0x95,0x5B,0x70,0xC4},{0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x0B,0x05,0x07}},
{{0x08,0x56,0x6E,0xB5,0x64,0xD6,0x47,0x4E},{0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x13,0x05,0x07}},
{{0x41,0x6F,0xBA,0xA4,0xEB,0xAE,0xA0,0x55},{0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x23,0x05,0x07}},
{{0x62,0x9D,0xDE,0x72,0x84,0x4A,0x53,0xD5},{0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x43,0x05,0x07}},
{{0x39,0xD3,0x2B,0x66,0xB8,0x08,0x40,0x2E},{0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x07,0x05}},
{{0xAF,0x67,0xA9,0x18,0x57,0x21,0xAF,0x8D},{0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x09,0x07}},
{{0x34,0xBC,0x9D,0xBC,0xC4,0xC2,0x3B,0xC8},{0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x0D,0x07}},
{{0xB6,0x50,0xF9,0x81,0xF6,0xBF,0x90,0x3C},{0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x15,0x07}},
{{0x71,0x41,0x93,0xA1,0x59,0x81,0xA5,0x52},{0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x25,0x07}},
{{0x6B,0x00,0xBD,0x74,0x1C,0x3C,0xE0,0x1A},{0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x45,0x07}},
{{0x76,0xFD,0x0B,0xD0,0x41,0xD2,0x82,0x5D},{0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x09}},
{{0xC6,0x3A,0x1C,0x25,0x63,0x5A,0x2F,0x0E},{0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x0B}},
{{0xD9,0x0E,0xD7,0x30,0xE2,0xAD,0xA9,0x87},{0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x0F}},
{{0x6B,0x81,0xC6,0xD1,0x05,0x09,0x87,0x1E},{0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x17}},
{{0xB4,0xA7,0x1E,0x02,0x54,0x37,0x43,0x35},{0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x27}},
{{0x45,0x14,0x7C,0x7F,0xE0,0xDE,0x09,0x65},{0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x47}},
{{0x78,0xB0,0xF5,0x20,0x8B,0x7D,0xF3,0xDD},{0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00},{0xFE,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x88,0xB3,0x3C,0xE1,0xF7,0x87,0x42,0xA1},{0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0xFC,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x11,0x2F,0xB2,0xF7,0xE2,0xB2,0x4F,0x6E},{0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0xFA,0x08,0x01,0x03,0x05,0x07}},
{{0x25,0x56,0x4E,0xC6,0xEB,0x2D,0x74,0x5B},{0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0xF8,0x01,0x03,0x05,0x07}},
{{0x7E,0x98,0x37,0xF9,0x80,0x8F,0x09,0x82},{0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0xFF,0x03,0x05,0x07}},
{{0xF9,0xB5,0x62,0x3B,0xD8,0x7B,0x3C,0x3F},{0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0xFD,0x05,0x07}},
{{0x29,0xC5,0x2B,0xFA,0xD1,0xFC,0x5C,0xC7},{0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0xFB,0x07}},
{{0xC1,0xA3,0x09,0x71,0xBD,0x8E,0xAF,0x2F},{0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0xF9}},
{{0xB6,0xDD,0xD1,0xAD,0xAA,0x15,0x6F,0x29},{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x03,0x05,0x02,0x07,0x04,0x06,0x08}},
{{0x65,0x34,0x03,0x19,0x17,0xB3,0xA3,0x96},{0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x01,0x06,0x08,0x03,0x05,0x07}},
{{0xF9,0x38,0x43,0x56,0x52,0xE5,0xB1,0xA9},{0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x04,0x06,0x08,0x03,0x05,0x07}},
{{0xA4,0xA0,0xAF,0xDA,0x48,0xB0,0xA1,0x10},{0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x04,0x06,0x03,0x08,0x05,0x07}},
{{0x55,0x15,0x8A,0x0D,0x48,0x29,0x01,0xD8},{0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x01,0x06,0x03,0x05,0x08,0x07}},
{{0xC4,0x81,0x96,0x7D,0xA3,0xB7,0x73,0x50},{0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x05,0x04,0x06,0x08,0x07}},
{{0x36,0x73,0xDF,0xC1,0x1B,0x98,0xA8,0x1D},{0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x04,0x05,0x06,0x08,0x07}},
{{0xCE,0xE0,0xB3,0x1B,0x41,0xEB,0x15,0x12},{0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x04,0x06,0x05,0x08,0x07}},
{{0},{0},{0}}
};
int testKeyDiversificationWithMasterkeyTestcases()
{
int error = 0;
int i;
uint8_t empty[8]={0};
prnlog("[+} Testing encryption/decryption");
for (i = 0; memcmp(testcases+i,empty,8) ; i++) {
error += testDES(testcases[i],ctx_enc, ctx_dec);
}
if(error)
{
prnlog("[+] %d errors occurred (%d testcases)", error, i);
}else
{
prnlog("[+] Hashing seems to work (%d testcases)", i);
}
return error;
}
void print64bits(char*name, uint64_t val)
{
printf("%s%08x%08x\n",name,(uint32_t) (val >> 32) ,(uint32_t) (val & 0xFFFFFFFF));
}
uint64_t testCryptedCSN(uint64_t crypted_csn, uint64_t expected)
{
int retval = 0;
uint8_t result[8] = {0};
if(debug_print) prnlog("debug_print %d", debug_print);
if(debug_print) print64bits(" {csn} ", crypted_csn );
uint64_t crypted_csn_swapped = swapZvalues(crypted_csn);
if(debug_print) print64bits(" {csn-revz} ", crypted_csn_swapped);
hash0(crypted_csn, result);
uint64_t resultbyte = x_bytes_to_num(result,8 );
if(debug_print) print64bits(" hash0 " , resultbyte );
if(resultbyte != expected )
{
if(debug_print) {
prnlog("\n[+] FAIL!");
print64bits(" expected " , expected );
}
retval = 1;
}else
{
if(debug_print) prnlog(" [OK]");
}
return retval;
}
int testDES2(uint64_t csn, uint64_t expected)
{
uint8_t result[8] = {0};
uint8_t input[8] = {0};
print64bits(" csn ", csn);
x_num_to_bytes(csn, 8,input);
des_crypt_ecb(&ctx_enc,input, result);
uint64_t crypt_csn = x_bytes_to_num(result, 8);
print64bits(" {csn} ", crypt_csn );
print64bits(" expected ", expected );
if( expected == crypt_csn )
{
prnlog("[+] OK");
return 0;
}else
{
return 1;
}
}
/**
* These testcases come from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977
* @brief doTestsWithKnownInputs
* @return
*/
int doTestsWithKnownInputs()
{
// KSel from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977
int errors = 0;
prnlog("[+] Testing DES encryption");
// uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
prnlog("[+] Testing foo");
uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
des_setkey_enc( &ctx_enc, key);
testDES2(0xbbbbaaaabbbbeeee,0xd6ad3ca619659e6b);
prnlog("[+] Testing hashing algorithm");
errors += testCryptedCSN(0x0102030405060708,0x0bdd6512073c460a);
errors += testCryptedCSN(0x1020304050607080,0x0208211405f3381f);
errors += testCryptedCSN(0x1122334455667788,0x2bee256d40ac1f3a);
errors += testCryptedCSN(0xabcdabcdabcdabcd,0xa91c9ec66f7da592);
errors += testCryptedCSN(0xbcdabcdabcdabcda,0x79ca5796a474e19b);
errors += testCryptedCSN(0xcdabcdabcdabcdab,0xa8901b9f7ec76da4);
errors += testCryptedCSN(0xdabcdabcdabcdabc,0x357aa8e0979a5b8d);
errors += testCryptedCSN(0x21ba6565071f9299,0x34e80f88d5cf39ea);
errors += testCryptedCSN(0x14e2adfc5bb7e134,0x6ac90c6508bd9ea3);
if(errors)
{
prnlog("[+] %d errors occurred (9 testcases)", errors);
}else
{
prnlog("[+] Hashing seems to work (9 testcases)" );
}
return errors;
}
int readKeyFile(uint8_t key[8])
{
FILE *f;
f = fopen("iclass_key.bin", "rb");
if (f)
{
if(fread(key, sizeof(key), 1, f) == 1) return 0;
}
return 1;
}
int doKeyTests(uint8_t debuglevel)
{
debug_print = debuglevel;
prnlog("[+] Checking if the master key is present (iclass_key.bin)...");
uint8_t key[8] = {0};
if(readKeyFile(key))
{
prnlog("[+] Master key not present, will not be able to do all testcases");
}else
{
//Test if it's the right key...
uint8_t i;
uint8_t j = 0;
for(i =0 ; i < sizeof(key) ; i++)
j += key[i];
if(j != 185)
{
prnlog("[+] A key was loaded, but it does not seem to be the correct one. Aborting these tests");
}else
{
prnlog("[+] Key present");
prnlog("[+] Checking key parity...");
des_checkParity(key);
des_setkey_enc( &ctx_enc, key);
des_setkey_dec( &ctx_dec, key);
// Test hashing functions
prnlog("[+] The following tests require the correct 8-byte master key");
testKeyDiversificationWithMasterkeyTestcases();
}
}
prnlog("[+] Testing key diversification with non-sensitive keys...");
doTestsWithKnownInputs();
return 0;
}
/**
void checkParity2(uint8_t* key)
{
uint8_t stored_parity = key[7];
printf("Parity byte: 0x%02x\n", stored_parity);
int i;
int byte;
int fails =0;
BitstreamIn bits = {key, 56, 0};
bool parity = 0;
for(i =0 ; i < 56; i++)
{
if ( i > 0 && i % 7 == 0)
{
parity = !parity;
bool pbit = stored_parity & (0x80 >> (byte));
if(parity != pbit)
{
printf("parity2 fail byte %d, should be %d, was %d\n", (i / 7), parity, pbit);
fails++;
}
parity =0 ;
byte = i / 7;
}
parity = parity ^ headBit(&bits);
}
if(fails)
{
printf("parity2 fails: %d\n", fails);
}else
{
printf("Key syntax is with parity bits grouped in the last byte!\n");
}
}
void modifyKey_put_parity_last(uint8_t * key, uint8_t* output)
{
uint8_t paritybits = 0;
bool parity =0;
BitstreamOut out = { output, 0,0};
unsigned int bbyte, bbit;
for(bbyte=0; bbyte <8 ; bbyte++ )
{
for(bbit =0 ; bbit< 7 ; bbit++)
{
bool bit = *(key+bbyte) & (1 << (7-bbit));
pushBit(&out,bit);
parity ^= bit;
}
bool paritybit = *(key+bbyte) & 1;
paritybits |= paritybit << (7-bbyte);
parity = 0;
}
output[7] = paritybits;
printf("Parity byte: %02x\n", paritybits);
}
* @brief Modifies a key with parity bits last, so that it is formed with parity
* bits inside each byte
* @param key
* @param output
void modifyKey_put_parity_allover(uint8_t * key, uint8_t* output)
{
bool parity =0;
BitstreamOut out = { output, 0,0};
BitstreamIn in = {key, 0,0};
unsigned int bbyte, bbit;
for(bbit =0 ; bbit < 56 ; bbit++)
{
if( bbit > 0 && bbit % 7 == 0)
{
pushBit(&out,!parity);
parity = 0;
}
bool bit = headBit(&in);
pushBit(&out,bit );
parity ^= bit;
}
pushBit(&out, !parity);
if( des_key_check_key_parity(output))
{
printf("modifyKey_put_parity_allover fail, DES key invalid parity!");
}
}
*/

32
client/loclass/ikeys.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef IKEYS_H
#define IKEYS_H
/**
* @brief
*Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 ? (F 82 ) 8 be defined as
* hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
* z'[i] = (z[i] mod (63-i)) + i i = 0...3
* z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3
* ? = check(z');
* @param c
* @param k this is where the diversified key is put (should be 8 bytes)
* @return
*/
void hash0(uint64_t c, uint8_t k[8]);
int doKeyTests(uint8_t debuglevel);
/**
* @brief Performs Elite-class key diversification
* @param csn
* @param key
* @param div_key
*/
void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]);
/**
* @brief Permutes a key from standard NIST format to Iclass specific format
* @param key
* @param dest
*/
#endif // IKEYS_H

96
client/loclass/main.c Normal file
View file

@ -0,0 +1,96 @@
/*****************************************************************************
* This file is part of iClassCipher. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file 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 IClassCipher. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <stdio.h>
#include <cipherutils.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "cipherutils.h"
#include "cipher.h"
#include "ikeys.h"
#include "fileutils.h"
#include "elite_crack.h"
int unitTests()
{
int errors = testCipherUtils();
errors += testMAC();
errors += doKeyTests(0);
errors += testElite();
return errors;
}
int showHelp()
{
prnlog("Usage: iclazz [options]");
prnlog("Options:");
prnlog("-t Perform self-test");
prnlog("-h Show this help");
prnlog("-f <filename> Bruteforce iclass dumpfile");
prnlog(" An iclass dumpfile is assumed to consist of an arbitrary number of malicious CSNs, and their protocol responses");
prnlog(" The the binary format of the file is expected to be as follows: ");
prnlog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
prnlog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
prnlog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
prnlog(" ... totalling N*24 bytes");
prnlog(" Check iclass_dump.bin for an example");
return 0;
}
int main (int argc, char **argv)
{
prnlog("IClass Cipher version 1.2, Copyright (C) 2014 Martin Holst Swende\n");
prnlog("Comes with ABSOLUTELY NO WARRANTY");
prnlog("This is free software, and you are welcome to use, abuse and repackage, please keep the credits\n");
char *fileName = NULL;
int c;
while ((c = getopt (argc, argv, "thf:")) != -1)
switch (c)
{
case 't':
return unitTests();
case 'h':
return showHelp();
case 'f':
fileName = optarg;
return bruteforceFileNoKeys(fileName);
case '?':
if (optopt == 'f')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
//default:
//showHelp();
}
showHelp();
return 0;
}

View file

@ -15,7 +15,6 @@
#include "cmdmain.h"
#include "ui.h"
#include "data.h"
//#include "proxusb.h"
#include "util.h"
#include "nonce2key/nonce2key.h"
#include "nonce2key/crapto1.h"

View file

@ -62,21 +62,6 @@ struct main_loop_arg {
char *script_cmds_file;
};
//static void *usb_receiver(void *targ) {
// struct receiver_arg *arg = (struct receiver_arg*)targ;
// UsbCommand cmdbuf;
//
// while (arg->run) {
// if (ReceiveCommandPoll(&cmdbuf)) {
// UsbCommandReceived(&cmdbuf);
// fflush(NULL);
// }
// }
//
// pthread_exit(NULL);
// return NULL;
//}
byte_t rx[0x1000000];
byte_t* prx = rx;
@ -207,14 +192,6 @@ static void *main_loop(void *targ) {
return NULL;
}
//static void dumpHelp(char *parent, ...)
//{
// printf("## %s\n\n", parent);
// CommandReceived(parent);
//
// printf("\n");
//}
static void dumpAllHelp(int markdown)
{
printf("\n%sProxmark3 command dump%s\n\n",markdown?"# ":"",markdown?"":"\n======================");
@ -254,17 +231,6 @@ int main(int argc, char* argv[]) {
};
pthread_t main_loop_t;
/*
usb_init();
if (!OpenProxmark(1)) {
fprintf(stderr,"PROXMARK3: NOT FOUND!\n");
marg.usb_present = 0;
offline = 1;
} else {
marg.usb_present = 1;
offline = 0;
}
*/
sp = uart_open(argv[1]);
if (sp == INVALID_SERIAL_PORT) {
@ -305,10 +271,6 @@ int main(int argc, char* argv[]) {
pthread_join(main_loop_t, NULL);
// if (marg.usb_present == 1) {
// CloseProxmark();
// }
// Clean up the port
uart_close(sp);

View file

@ -20,7 +20,7 @@
#include "usb_cmd.h"
#define PROXPROMPT "proxmark3> "
#define PROXPROMPT "pm3 --> "
void SendCommand(UsbCommand *c);

View file

@ -90,3 +90,195 @@ void SetLogFilename(char *fn)
{
logfilename = fn;
}
uint8_t manchester_decode(const uint8_t * data, const size_t len, uint8_t * dataout){
size_t bytelength = len;
uint8_t bitStream[bytelength];
memset(bitStream, 0x00, bytelength);
int clock,high, low, bit, hithigh, hitlow, first, bit2idx, lastpeak;
int i,invert, lastval;
int bitidx = 0;
int lc = 0;
int warnings = 0;
high = 1;
low = bit = bit2idx = lastpeak = invert = lastval = hithigh = hitlow = first = 0;
clock = 0xFFFF;
/* Detect high and lows */
for (i = 0; i < bytelength; i++) {
if (data[i] > high)
high = data[i];
else if (data[i] < low)
low = data[i];
}
/* get clock */
int j=0;
for (i = 1; i < bytelength; i++) {
/* if this is the beginning of a peak */
j = i-1;
if ( data[j] != data[i] &&
data[i] == high)
{
/* find lowest difference between peaks */
if (lastpeak && i - lastpeak < clock)
clock = i - lastpeak;
lastpeak = i;
}
}
int tolerance = clock/4;
PrintAndLog(" Detected clock: %d",clock);
/* Detect first transition */
/* Lo-Hi (arbitrary) */
/* skip to the first high */
for (i= 0; i < bytelength; i++)
if (data[i] == high)
break;
/* now look for the first low */
for (; i < bytelength; i++) {
if (data[i] == low) {
lastval = i;
break;
}
}
/* If we're not working with 1/0s, demod based off clock */
if (high != 1)
{
bit = 0; /* We assume the 1st bit is zero, it may not be
* the case: this routine (I think) has an init problem.
* Ed.
*/
for (; i < (int)(bytelength / clock); i++)
{
hithigh = 0;
hitlow = 0;
first = 1;
/* Find out if we hit both high and low peaks */
for (j = 0; j < clock; j++)
{
if (data[(i * clock) + j] == high)
hithigh = 1;
else if (data[(i * clock) + j] == low)
hitlow = 1;
/* it doesn't count if it's the first part of our read
because it's really just trailing from the last sequence */
if (first && (hithigh || hitlow))
hithigh = hitlow = 0;
else
first = 0;
if (hithigh && hitlow)
break;
}
/* If we didn't hit both high and low peaks, we had a bit transition */
if (!hithigh || !hitlow)
bit ^= 1;
bitStream[bit2idx++] = bit ^ invert;
}
}
/* standard 1/0 bitstream */
else {
/* Then detect duration between 2 successive transitions */
for (bitidx = 1; i < bytelength; i++) {
if (data[i-1] != data[i]) {
lc = i-lastval;
lastval = i;
// Error check: if bitidx becomes too large, we do not
// have a Manchester encoded bitstream or the clock is really
// wrong!
if (bitidx > (bytelength*2/clock+8) ) {
PrintAndLog("Error: the clock you gave is probably wrong, aborting.");
return 0;
}
// Then switch depending on lc length:
// Tolerance is 1/4 of clock rate (arbitrary)
if (abs(lc-clock/2) < tolerance) {
// Short pulse : either "1" or "0"
bitStream[bitidx++] = data[i-1];
} else if (abs(lc-clock) < tolerance) {
// Long pulse: either "11" or "00"
bitStream[bitidx++] = data[i-1];
bitStream[bitidx++] = data[i-1];
} else {
// Error
warnings++;
PrintAndLog("Warning: Manchester decode error for pulse width detection.");
if (warnings > 10) {
PrintAndLog("Error: too many detection errors, aborting.");
return 0;
}
}
}
}
}
// 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) {
if ((bitStream[i] == 0) && (bitStream[i+1] == 1)) {
bitStream[bit2idx++] = 1 ^ invert;
}
else if ((bitStream[i] == 1) && (bitStream[i+1] == 0)) {
bitStream[bit2idx++] = 0 ^ invert;
}
else {
// We cannot end up in this state, this means we are unsynchronized,
// move up 1 bit:
i++;
warnings++;
PrintAndLog("Unsynchronized, resync...");
if (warnings > 10) {
PrintAndLog("Error: too many decode errors, aborting.");
return 0;
}
}
}
// PrintAndLog(" Manchester decoded bitstream : %d bits", (bit2idx-16));
// uint8_t mod = (bit2idx-16) % blocksize;
// uint8_t div = (bit2idx-16) / blocksize;
// // Now output the bitstream to the scrollback by line of 16 bits
// for (i = 0; i < div*blocksize; i+=blocksize) {
// PrintAndLog(" %s", sprint_bin(bitStream+i,blocksize) );
// }
// if ( mod > 0 ){
// PrintAndLog(" %s", sprint_bin(bitStream+i, mod) );
// }
if ( bit2idx > 0 )
memcpy(dataout, bitStream, bit2idx);
free(bitStream);
return bit2idx;
}
void PrintPaddedManchester( uint8_t* bitStream, size_t len, size_t blocksize){
PrintAndLog(" Manchester decoded bitstream : %d bits", len);
uint8_t mod = len % blocksize;
uint8_t div = len / blocksize;
int i;
// Now output the bitstream to the scrollback by line of 16 bits
for (i = 0; i < div*blocksize; i+=blocksize) {
PrintAndLog(" %s", sprint_bin(bitStream+i,blocksize) );
}
if ( mod > 0 ){
PrintAndLog(" %s", sprint_bin(bitStream+i, mod) );
}
}

View file

@ -11,6 +11,8 @@
#ifndef UI_H__
#define UI_H__
#include "util.h"
void ShowGui(void);
void HideGraphWindow(void);
void ShowGraphWindow(void);
@ -23,4 +25,6 @@ extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault;
extern int offline;
extern int flushAfterWrite; //buzzy
uint8_t manchester_decode(const uint8_t * data, const size_t len, uint8_t * dataout);
void PrintPaddedManchester( uint8_t * bitStream, size_t len, size_t blocksize);
#endif

View file

@ -13,6 +13,7 @@
#ifndef _WIN32
#include <termios.h>
#include <sys/ioctl.h>
int ukbhit(void)
{
int cnt = 0;
@ -112,6 +113,17 @@ char * sprint_hex(const uint8_t * data, const size_t len) {
return buf;
}
char * sprint_bin(const uint8_t * data, const size_t len) {
static char buf[1024];
char * tmp = buf;
size_t i;
for (i=0; i < len && i < 1024; i++, tmp++)
sprintf(tmp, "%u", data[i]);
return buf;
}
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
{
while (len--) {
@ -131,6 +143,28 @@ uint64_t bytes_to_num(uint8_t* src, size_t len)
return num;
}
//assumes little endian
char * printBits(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
static char buf[1024];
char * tmp = buf;
int i, j;
for (i=size-1;i>=0;i--)
{
for (j=7;j>=0;j--)
{
byte = b[i] & (1<<j);
byte >>= j;
sprintf(tmp, "%u", byte);
tmp++;
}
}
return buf;
}
// -------------------------------------------------------------------------
// string parameters lib
// -------------------------------------------------------------------------

View file

@ -33,9 +33,11 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount);
void print_hex(const uint8_t * data, const size_t len);
char * sprint_hex(const uint8_t * data, const size_t len);
char * sprint_bin(const uint8_t * data, const size_t len);
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t bytes_to_num(uint8_t* src, size_t len);
char * printBits(size_t const size, void const * const ptr);
char param_getchar(const char *line, int paramnum);
uint8_t param_get8(const char *line, int paramnum);
@ -45,3 +47,4 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base);
int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt);
int param_getstr(const char *line, int paramnum, char * str);

View file

@ -54,7 +54,8 @@ DELETE=del /q
MOVE=ren
COPY=copy
PATHSEP=\\#
FLASH_TOOL=winsrc\\prox.exe
#FLASH_TOOL=winsrc\\prox.exe
FLASH_TOOL=winsrc\\flash.exe
DETECTED_OS=Windows
endif
@ -67,6 +68,7 @@ INCLUDES = ../include/proxmark3.h ../include/at91sam7s512.h ../include/config_gp
CFLAGS = -c $(INCLUDE) -Wall -Werror -pedantic -std=c99 $(APP_CFLAGS) -Os
LDFLAGS = -nostartfiles -nodefaultlibs -Wl,-gc-sections -n
LIBS = -lgcc
THUMBOBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(THUMBSRC))

View file

@ -32,7 +32,7 @@
#include "cmd.h"
#include "string.h"
#include "proxmark3.h"
#include "../include/proxmark3.h"
//static UsbCommand txcmd;

View file

@ -33,8 +33,8 @@
#ifndef _PROXMARK_CMD_H_
#define _PROXMARK_CMD_H_
#include <common.h>
#include <usb_cmd.h>
#include "../include/common.h"
#include "../include/usb_cmd.h"
#include "usb_cdc.h"
bool cmd_receive(UsbCommand* cmd);

35
common/crc32.c Normal file
View file

@ -0,0 +1,35 @@
#include <stdint.h>
#include <stddef.h>
#include "crc32.h"
#define htole32(x) (x)
#define CRC32_PRESET 0xFFFFFFFF
static void crc32_byte (uint32_t *crc, const uint8_t value);
static void crc32_byte (uint32_t *crc, const uint8_t value) {
/* x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 */
const uint32_t poly = 0xEDB88320;
*crc ^= value;
for (int current_bit = 7; current_bit >= 0; current_bit--) {
int bit_out = (*crc) & 0x00000001;
*crc >>= 1;
if (bit_out)
*crc ^= poly;
}
}
void crc32 (const uint8_t *data, const size_t len, uint8_t *crc) {
uint32_t desfire_crc = CRC32_PRESET;
for (size_t i = 0; i < len; i++) {
crc32_byte (&desfire_crc, data[i]);
}
*((uint32_t *)(crc)) = htole32 (desfire_crc);
}
void crc32_append (uint8_t *data, const size_t len) {
crc32 (data, len, data + len);
}

15
common/crc32.h Normal file
View file

@ -0,0 +1,15 @@
//-----------------------------------------------------------------------------
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// CRC32
//-----------------------------------------------------------------------------
#ifndef __CRC32_H
#define __CRC32_H
void crc32 (const uint8_t *data, const size_t len, uint8_t *crc);
void crc32_append (uint8_t *data, const size_t len);
#endif

177
common/desfire.h Normal file
View file

@ -0,0 +1,177 @@
#ifndef __DESFIRE_H
#define __DESFIRE_H
#include "aes.h"
#define DESFIRE(tag) ((struct desfire_tag *) tag)
#define DESFIRE_KEY(key) ((struct desfire_key *) key)
#define MAX_CRYPTO_BLOCK_SIZE 16
/* Mifare DESFire EV1 Application crypto operations */
#define APPLICATION_CRYPTO_DES 0x00
#define APPLICATION_CRYPTO_3K3DES 0x40
#define APPLICATION_CRYPTO_AES 0x80
#define MAC_LENGTH 4
#define CMAC_LENGTH 8
typedef enum {
MCD_SEND,
MCD_RECEIVE
} MifareCryptoDirection;
typedef enum {
MCO_ENCYPHER,
MCO_DECYPHER
} MifareCryptoOperation;
#define MDCM_MASK 0x000F
#define CMAC_NONE 0
// Data send to the PICC is used to update the CMAC
#define CMAC_COMMAND 0x010
// Data received from the PICC is used to update the CMAC
#define CMAC_VERIFY 0x020
// MAC the command (when MDCM_MACED)
#define MAC_COMMAND 0x100
// The command returns a MAC to verify (when MDCM_MACED)
#define MAC_VERIFY 0x200
#define ENC_COMMAND 0x1000
#define NO_CRC 0x2000
#define MAC_MASK 0x0F0
#define CMAC_MACK 0xF00
/* Communication mode */
#define MDCM_PLAIN 0x00
#define MDCM_MACED 0x01
#define MDCM_ENCIPHERED 0x03
/* Error code managed by the library */
#define CRYPTO_ERROR 0x01
enum DESFIRE_AUTH_SCHEME {
AS_LEGACY,
AS_NEW
};
enum DESFIRE_CRYPTOALGO {
T_DES = 0x00,
T_3DES = 0x01,
T_3K3DES = 0x02,
T_AES = 0x03
};
struct desfire_key {
enum DESFIRE_CRYPTOALGO type;
uint8_t data[24];
// DES_key_schedule ks1;
// DES_key_schedule ks2;
// DES_key_schedule ks3;
AesCtx aes_ks;
uint8_t cmac_sk1[24];
uint8_t cmac_sk2[24];
uint8_t aes_version;
};
typedef struct desfire_key *desfirekey_t;
struct desfire_tag {
iso14a_card_select_t info;
int active;
uint8_t last_picc_error;
uint8_t last_internal_error;
uint8_t last_pcd_error;
desfirekey_t session_key;
enum DESFIRE_AUTH_SCHEME authentication_scheme;
uint8_t authenticated_key_no;
uint8_t ivect[MAX_CRYPTO_BLOCK_SIZE];
uint8_t cmac[16];
uint8_t *crypto_buffer;
size_t crypto_buffer_size;
uint32_t selected_application;
};
typedef struct desfire_tag *desfiretag_t;
/* File types */
enum DESFIRE_FILE_TYPES {
MDFT_STANDARD_DATA_FILE = 0x00,
MDFT_BACKUP_DATA_FILE = 0x01,
MDFT_VALUE_FILE_WITH_BACKUP = 0x02,
MDFT_LINEAR_RECORD_FILE_WITH_BACKUP = 0x03,
MDFT_CYCLIC_RECORD_FILE_WITH_BACKUP = 0x04
};
enum DESFIRE_STATUS {
OPERATION_OK = 0x00,
NO_CHANGES = 0x0c,
OUT_OF_EEPROM_ERROR = 0x0e,
ILLEGAL_COMMAND_CODE = 0x1c,
INTEGRITY_ERROR = 0x1e,
NO_SUCH_KEY = 0x40,
LENGTH_ERROR = 0x7e,
PERMISSION_DENIED = 0x9d,
PARAMETER_ERROR = 0x9e,
APPLICATION_NOT_FOUND = 0xa0,
APPL_INTEGRITY_ERROR = 0xa1,
AUTHENTICATION_ERROR = 0xae,
ADDITIONAL_FRAME = 0xaf,
BOUNDARY_ERROR = 0xbe,
PICC_INTEGRITY_ERROR = 0xc1,
COMMAND_ABORTED = 0xca,
PICC_DISABLED_ERROR = 0xcd,
COUNT_ERROR = 0xce,
DUPLICATE_ERROR = 0xde,
EEPROM_ERROR = 0xee,
FILE_NOT_FOUND = 0xf0,
FILE_INTEGRITY_ERROR = 0xf1
};
enum DESFIRE_CMD {
CREATE_APPLICATION = 0xca,
DELETE_APPLICATION = 0xda,
GET_APPLICATION_IDS = 0x6a,
SELECT_APPLICATION = 0x5a,
FORMAT_PICC = 0xfc,
GET_VERSION = 0x60,
READ_DATA = 0xbd,
WRITE_DATA = 0x3d,
GET_VALUE = 0x6c,
CREDIT = 0x0c,
DEBIT = 0xdc,
LIMITED_CREDIT = 0x1c,
WRITE_RECORD = 0x3b,
READ_RECORDS = 0xbb,
CLEAR_RECORD_FILE = 0xeb,
COMMIT_TRANSACTION = 0xc7,
ABORT_TRANSACTION = 0xa7,
GET_FREE_MEMORY = 0x6e,
GET_FILE_IDS = 0x6f,
GET_FILE_SETTINGS = 0xf5,
CHANGE_FILE_SETTINGS = 0x5f,
CREATE_STD_DATA_FILE = 0xcd,
CREATE_BACKUP_DATA_FILE = 0xcb,
CREATE_VALUE_FILE = 0xcc,
CREATE_LINEAR_RECORD_FILE = 0xc1,
CREATE_CYCLIC_RECORD_FILE = 0xc0,
DELETE_FILE = 0xdf,
AUTHENTICATE = 0x0a, // AUTHENTICATE_NATIVE
AUTHENTICATE_ISO = 0x1a, // AUTHENTICATE_STANDARD
AUTHENTICATE_AES = 0xaa,
CHANGE_KEY_SETTINGS = 0x54,
GET_KEY_SETTINGS = 0x45,
CHANGE_KEY = 0xc4,
GET_KEY_VERSION = 0x64,
AUTHENTICATION_FRAME = 0xAF
};
#endif

View file

@ -6,7 +6,7 @@
// ISO14443 CRC calculation code.
//-----------------------------------------------------------------------------
#include "iso14443crc.h"
#include "../common/iso14443crc.h"
static unsigned short UpdateCrc14443(unsigned char ch, unsigned short *lpwCrc)
{

View file

@ -8,7 +8,7 @@
#ifndef __ISO14443CRC_H
#define __ISO14443CRC_H
#include "common.h"
#include "../include/common.h"
//-----------------------------------------------------------------------------
// Routines to compute the CRCs (two different flavours, just for confusion)

View file

@ -7,11 +7,14 @@
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "../include/proxmark3.h"
#include <stdint.h>
#include <stdlib.h>
//#include "iso15693tools.h"
#define POLY 0x8408
// The CRC as described in ISO 15693-Part 3-Annex C
// v buffer with data
// n length
@ -63,5 +66,31 @@ char* Iso15693sprintUID(char *target,uint8_t *uid) {
return target;
}
unsigned short iclass_crc16(char *data_p, unsigned short length)
{
unsigned char i;
unsigned int data;
unsigned int crc = 0xffff;
if (length == 0)
return (~crc);
do
{
for (i=0, data=(unsigned int)0xff & *data_p++;
i < 8;
i++, data >>= 1)
{
if ((crc & 0x0001) ^ (data & 0x0001))
crc = (crc >> 1) ^ POLY;
else crc >>= 1;
}
} while (--length);
crc = ~crc;
data = crc;
crc = (crc << 8) | (data >> 8 & 0xff);
crc = crc ^ 0xBC3;
return (crc);
}

View file

@ -70,6 +70,7 @@
uint16_t Iso15693Crc(uint8_t *v, int n);
int Iso15693AddCrc(uint8_t *req, int n);
char* Iso15693sprintUID(char *target,uint8_t *uid);
unsigned short iclass_crc16(char *data_p, unsigned short length);
//-----------------------------------------------------------------------------
// Map a sequence of octets (~layer 2 command) into the set of bits to feed

View file

@ -6,7 +6,7 @@
// LEFIC's obfuscation function
//-----------------------------------------------------------------------------
#include "legic_prng.h"
#include "../include/legic_prng.h"
struct lfsr {
uint8_t a;

View file

@ -33,7 +33,7 @@
*/
#include "usb_cdc.h"
#include "config_gpio.h"
#include "../include/config_gpio.h"
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))

View file

@ -35,7 +35,7 @@
#ifndef _USB_CDC_H_
#define _USB_CDC_H_
#include <common.h>
#include "../include/common.h"
void usb_disable();
void usb_enable();

48
include/crc.h.old Normal file
View file

@ -0,0 +1,48 @@
//-----------------------------------------------------------------------------
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Generic CRC calculation code.
//-----------------------------------------------------------------------------
#ifndef __CRC_H
#define __CRC_H
#include <stdint.h>
typedef struct crc {
uint32_t state;
int order;
uint32_t polynom;
uint32_t initial_value;
uint32_t final_xor;
uint32_t mask;
} crc_t;
/* Initialize a crc structure. order is the order of the polynom, e.g. 32 for a CRC-32
* polynom is the CRC polynom. initial_value is the initial value of a clean state.
* final_xor is XORed onto the state before returning it from crc_result(). */
extern void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor);
/* Update the crc state. data is the data of length data_width bits (only the the
* data_width lower-most bits are used).
*/
extern void crc_update(crc_t *crc, uint32_t data, int data_width);
/* Clean the crc state, e.g. reset it to initial_value */
extern void crc_clear(crc_t *crc);
/* Get the result of the crc calculation */
extern uint32_t crc_finish(crc_t *crc);
/* Static initialization of a crc structure */
#define CRC_INITIALIZER(_order, _polynom, _initial_value, _final_xor) { \
.state = ((_initial_value) & ((1L<<(_order))-1)), \
.order = (_order), \
.polynom = (_polynom), \
.initial_value = (_initial_value), \
.final_xor = (_final_xor), \
.mask = ((1L<<(_order))-1) }
#endif /* __CRC_H */

Some files were not shown because too many files have changed in this diff Show more