Merge branch 'master' into ISO15693_base

This commit is contained in:
Thorsten
2018-10-17 00:29:09 +02:00
committed by GitHub
25 changed files with 4727 additions and 2810 deletions
@@ -18,7 +18,7 @@
#include "Reader14443A.h"
#include "Vicinity.h"
#include "Sl2s2002.h"
#include "Sniff14443A.h"
/* Function wrappers */
INLINE void ApplicationInit(void) {
@@ -141,6 +141,7 @@ uint16_t addParityBits(uint8_t * Buffer, uint16_t BitCount)
uint16_t removeParityBits(uint8_t * Buffer, uint16_t BitCount)
{
// Short frame, no parity bit is added
if (BitCount == 7)
return 7;
@@ -0,0 +1,173 @@
//
// Created by Zitai Chen on 25/07/2018.
// Application layer for sniffing
// Currently only support Autocalibrate
//
#include <stdbool.h>
#include <LED.h>
#include "Sniff14443A.h"
#include "Codec/SniffISO14443-2A.h"
extern bool checkParityBits(uint8_t * Buffer, uint16_t BitCount);
Sniff14443Command Sniff14443CurrentCommand = Sniff14443_Do_Nothing;
//bool selected = false;
static enum {
STATE_IDLE,
STATE_REQA,
STATE_ATQA,
STATE_ANTICOLLI,
STATE_SELECT,
STATE_UID,
STATE_SAK,
} SniffState = STATE_IDLE;
static uint16_t tmp_th = CODEC_THRESHOLD_CALIBRATE_MIN;
static uint8_t Thresholds[(CODEC_THRESHOLD_CALIBRATE_MAX - CODEC_THRESHOLD_CALIBRATE_MIN) /
CODEC_THRESHOLD_CALIBRATE_STEPS] = {0};
void Sniff14443AAppInit(void){
SniffState = STATE_REQA;
// Get current threshold and continue searching from here
tmp_th = GlobalSettings.ActiveSettingPtr->ReaderThreshold;
}
void Sniff14443AAppReset(void){
SniffState = STATE_IDLE;
Sniff14443CurrentCommand = Sniff14443_Do_Nothing;
}
// Currently APPTask and AppTick is not being used
void Sniff14443AAppTask(void){/* Empty */}
void Sniff14443AAppTick(void){/* Empty */}
void Sniff14443AAppTimeout(void){
Sniff14443AAppReset();
}
INLINE void reset2REQA(void){
SniffState = STATE_REQA;
LED_PORT.OUTCLR = LED_RED;
// Mark the current threshold as fail and continue
if(tmp_th < CODEC_THRESHOLD_CALIBRATE_MAX){
Thresholds[(tmp_th - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS] = 0;
tmp_th = CodecThresholdIncrement();
} else{
// mark finish
CommandLinePendingTaskFinished(COMMAND_INFO_FALSE, NULL);
}
}
uint16_t Sniff14443AAppProcess(uint8_t* Buffer, uint16_t BitCount){
switch (Sniff14443CurrentCommand){
case Sniff14443_Do_Nothing: {
return 0;
}
case Sniff14443_Autocalibrate: {
switch (SniffState) {
case STATE_REQA:
LED_PORT.OUTCLR = LED_RED;
// If received Reader REQA or WUPA
if (TrafficSource == TRAFFIC_READER &&
(Buffer[0] == 0x26 || Buffer[0] == 0x52)) {
SniffState = STATE_ATQA;
} else {
// Stay in this state, do noting
}
break;
case STATE_ATQA:
// ATQA: P RRRR XXXX P XXRX XXXX
if (TrafficSource == TRAFFIC_CARD &&
BitCount == 2 * 9 &&
(Buffer[0] & 0x20) == 0x00 && // Bit6 RFU shall be 0
(Buffer[1] & 0xE0) == 0x00 && // bit13-16 RFU shall be 0
(Buffer[2] & 0x01) == 0x00 &&
checkParityBits(Buffer, BitCount)) {
// Assume this is a good ATQA
SniffState = STATE_ANTICOLLI;
} else {
// If not ATQA, but REQA, then stay on this state,
// Reset to REQA, save the counter and reset the counter
if (TrafficSource == TRAFFIC_READER &&
(Buffer[0] == 0x26 || Buffer[0] == 0x52)) {
} else {
// If not ATQA and not REQA then reset to REQA
reset2REQA();
}
}
break;
case STATE_ANTICOLLI:
// SEL: 93/95/97
if (TrafficSource == TRAFFIC_READER &&
BitCount == 2 * 8 &&
(Buffer[0] & 0xf0) == 0x90 &&
(Buffer[0] & 0x09) == 0x01) {
SniffState = STATE_UID;
} else {
reset2REQA();
}
break;
case STATE_UID:
if (TrafficSource == TRAFFIC_CARD &&
BitCount == 5 * 9 &&
checkParityBits(Buffer, BitCount)) {
SniffState = STATE_SELECT;
} else {
reset2REQA();
}
break;
case STATE_SELECT:
// SELECT: 9 bytes, SEL = 93/95/97, NVB=70
if (TrafficSource == TRAFFIC_READER &&
BitCount == 9 * 8 &&
(Buffer[0] & 0xf0) == 0x90 &&
(Buffer[0] & 0x09) == 0x01 &&
Buffer[1] == 0x70) {
SniffState = STATE_SAK;
} else {
// Not valid, reset
reset2REQA();
}
break;
case STATE_SAK:
// SAK: 1Byte SAK + CRC
if (TrafficSource == TRAFFIC_CARD &&
BitCount == 3 * 9 &&
checkParityBits(Buffer, BitCount)) {
if ((Buffer[0] & 0x04) == 0x00) {
// UID complete, success SELECTED,
// Mark the current threshold as ok and finish
// reset
SniffState = STATE_REQA;
LED_PORT.OUTSET = LED_RED;
Thresholds[(tmp_th - CODEC_THRESHOLD_CALIBRATE_MIN) / CODEC_THRESHOLD_CALIBRATE_STEPS] += 1;
CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, NULL);
// Send this threshold to terminal
char tmpBuf[10];
snprintf(tmpBuf, 10, "%4" PRIu16 ": ", tmp_th);
TerminalSendString(tmpBuf);
// Save value to EEPROM
SETTING_UPDATE(GlobalSettings.ActiveSettingPtr->ReaderThreshold);
Sniff14443AAppReset();
} else {
// UID not complete, goto ANTICOLLI
SniffState = STATE_ANTICOLLI;
}
} else {
reset2REQA();
}
break;
default:
break;
}
break;
}
default:
return 0;
}
}
@@ -0,0 +1,24 @@
//
// Created by Zitai Chen on 25/07/2018.
//
#ifndef CHAMELEON_MINI_SNIFF14443A_H
#define CHAMELEON_MINI_SNIFF14443A_H
#include <stdint.h>
void Sniff14443AAppInit(void);
void Sniff14443AAppReset(void);
void Sniff14443AAppTask(void);
void Sniff14443AAppTick(void);
void Sniff14443AAppTimeout(void);
uint16_t Sniff14443AAppProcess(uint8_t* Buffer, uint16_t BitCount);
typedef enum {
Sniff14443_Do_Nothing,
Sniff14443_Autocalibrate,
} Sniff14443Command;
#endif //CHAMELEON_MINI_SNIFF14443A_H
+1 -1
View File
@@ -23,7 +23,7 @@ static volatile struct {
} ReaderFieldFlags = { false };
uint8_t CodecBuffer[CODEC_BUFFER_SIZE];
uint8_t CodecBuffer2[CODEC_BUFFER_SIZE];
// the following three functions prevent sending data directly after turning on the reader field
void CodecReaderFieldStart(void) // DO NOT CALL THIS FUNCTION INSIDE APPLICATION!
{
+18 -5
View File
@@ -17,6 +17,7 @@
#include "ISO14443-2A.h"
#include "Reader14443-2A.h"
#include "SniffISO14443-2A.h"
#include "ISO15693.h"
/* Timing definitions for ISO14443A */
@@ -25,7 +26,7 @@
#define ISO14443A_BIT_RATE_CYCLES 128
#define ISO14443A_FRAME_DELAY_PREV1 1236
#define ISO14443A_FRAME_DELAY_PREV0 1172
#define ISO14443A_RX_PENDING_TIMEOUT 1 // ms
#define ISO14443A_RX_PENDING_TIMEOUT 4 // ms
/* Peripheral definitions */
#define CODEC_DEMOD_POWER_PORT PORTB
@@ -38,8 +39,8 @@
#define CODEC_DEMOD_IN_PINCTRL1 PIN2CTRL
#define CODEC_DEMOD_IN_EVMUX0 EVSYS_CHMUX_PORTB_PIN1_gc
#define CODEC_DEMOD_IN_EVMUX1 EVSYS_CHMUX_PORTB_PIN2_gc
#define CODEC_DEMOD_IN_INT0_VECT PORTB_INT0_vect
#define CODEC_DEMOD_IN_INT1_VECT PORTB_INT1_vect
#define CODEC_DEMOD_IN_INT0_VECT PORTB_INT0_vect
#define CODEC_DEMOD_IN_INT1_VECT PORTB_INT1_vect
#define CODEC_LOADMOD_PORT PORTC
#define CODEC_LOADMOD_MASK PIN6_bm
#define CODEC_CARRIER_IN_PORT PORTC
@@ -58,8 +59,9 @@
#define CODEC_SUBCARRIER_CCEN_OOK TC1_CCBEN_bm
#define CODEC_TIMER_SAMPLING TCD0
#define CODEC_TIMER_SAMPLING_CCA_VECT TCD0_CCA_vect
#define CODEC_TIMER_SAMPLING_CCB_VECT TCD0_CCB_vect
#define CODEC_TIMER_SAMPLING_CCB_VECT TCD0_CCB_vect
#define CODEC_TIMER_SAMPLING_CCC_VECT TCD0_CCC_vect
#define CODEC_TIMER_SAMPLING_CCD_VECT TCD0_CCD_vect
#define CODEC_TIMER_LOADMOD TCE0
#define CODEC_TIMER_LOADMOD_OVF_VECT TCE0_OVF_vect
#define CODEC_TIMER_LOADMOD_CCA_VECT TCE0_CCA_vect
@@ -83,6 +85,8 @@
#define CODEC_THRESHOLD_CALIBRATE_STEPS 16
#define CODEC_TIMER_TIMESTAMPS TCD1
#define CODEC_TIMER_TIMESTAMPS_CCA_VECT TCD1_CCA_vect
#define CODEC_TIMER_TIMESTAMPS_CCB_VECT TCD1_CCB_vect
#define CODEC_BUFFER_SIZE 256
@@ -93,9 +97,11 @@
#define Codec8Reg2 GPIOR2
#define Codec8Reg3 GPIOR3
#define CodecCount16Register1 (*((volatile uint16_t*) &GPIOR4)) /* GPIOR4 & GPIOR5 */
#define CodecCount16Register2 (*((volatile uint16_t*) &GPIOR6)) /* GPIOR4 & GPIOR5 */
#define CodecCount16Register2 (*((volatile uint16_t*) &GPIOR6)) /* GPIOR6 & GPIOR7 */
#define CodecPtrRegister1 (*((volatile uint8_t**) &GPIOR8))
#define CodecPtrRegister2 (*((volatile uint8_t**) &GPIORA))
#define CodecPtrRegister3 (*((volatile uint8_t**) &GPIORC))
extern uint16_t Reader_FWT;
@@ -107,6 +113,7 @@ typedef enum {
} SubcarrierModType;
extern uint8_t CodecBuffer[CODEC_BUFFER_SIZE];
extern uint8_t CodecBuffer2[CODEC_BUFFER_SIZE];
volatile void (*isr_func_TCD0_CCC_vect)(void);
void isr_Reader14443_2A_TCD0_CCC_vect(void);
@@ -150,10 +157,14 @@ INLINE void CodecInitCommon(void)
CODEC_DEMOD_IN_PORT.CODEC_DEMOD_IN_PINCTRL0 = PORT_ISC_RISING_gc;
CODEC_DEMOD_IN_PORT.CODEC_DEMOD_IN_PINCTRL1 = PORT_ISC_FALLING_gc;
CODEC_DEMOD_IN_PORT.INT0MASK = 0;
CODEC_DEMOD_IN_PORT.INT1MASK = 0;
CODEC_DEMOD_IN_PORT.INTCTRL = PORT_INT0LVL_HI_gc | PORT_INT1LVL_HI_gc;
EVSYS.CH0MUX = CODEC_DEMOD_IN_EVMUX0;
EVSYS.CH1MUX = CODEC_DEMOD_IN_EVMUX1;
EVSYS.CH2MUX = CODEC_DEMOD_IN_EVMUX0;
/* Configure loadmod pin configuration and use a virtual port configuration
* for single instruction cycle access */
CODEC_LOADMOD_PORT.DIRSET = CODEC_LOADMOD_MASK;
@@ -246,6 +257,7 @@ INLINE void CodecSetLoadmodState(bool bOnOff) {
}
}
// Turn on and off the codec Reader field
INLINE void CodecSetReaderField(bool bOnOff) { // this is the function for turning on/off the reader field dumbly; before using this function, please consider to use CodecReaderField{Start,Stop}
if (bOnOff) {
@@ -259,6 +271,7 @@ INLINE void CodecSetReaderField(bool bOnOff) { // this is the function for turni
}
}
// Get the status of the reader field
INLINE bool CodecGetReaderField(void) {
return (CODEC_READER_TIMER.CTRLA == TC_CLKSEL_DIV1_gc) && (AWEXC.OUTOVEN == CODEC_READER_MASK);
}
+7 -3
View File
@@ -66,8 +66,8 @@ static void StartDemod(void) {
StateRegister = DEMOD_DATA_BIT;
/* Configure sampling-timer free running and sync to first modulation-pause. */
CODEC_TIMER_SAMPLING.CNT = 0;
CODEC_TIMER_SAMPLING.PER = SAMPLE_RATE_SYSTEM_CYCLES - 1;
CODEC_TIMER_SAMPLING.CNT = 0; // Reset the timer count
CODEC_TIMER_SAMPLING.PER = SAMPLE_RATE_SYSTEM_CYCLES - 1; // Set Period regisiter
CODEC_TIMER_SAMPLING.CCA = 0xFFFF; /* CCA Interrupt is not active! */
CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_DIV1_gc;
CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_RESTART_gc | CODEC_TIMER_MODSTART_EVSEL;
@@ -75,7 +75,7 @@ static void StartDemod(void) {
CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCAINTLVL_HI_gc;
/* Start looking out for modulation pause via interrupt. */
CODEC_DEMOD_IN_PORT.INTFLAGS = 0x03;
CODEC_DEMOD_IN_PORT.INTFLAGS = PORT_INT0IF_bm;
CODEC_DEMOD_IN_PORT.INT0MASK = CODEC_DEMOD_IN_MASK0;
}
@@ -85,6 +85,7 @@ ISR (CODEC_DEMOD_IN_INT0_VECT)
}
// ISR(CODEC_DEMOD_IN_INT0_VECT)
// Find first pause and start sampling
void isr_ISO14443_2A_TCD0_CCC_vect(void)
{
/* This is the first edge of the first modulation-pause after StartDemod.
@@ -119,6 +120,7 @@ void isr_ISO14443_2A_TCD0_CCC_vect(void)
CODEC_DEMOD_IN_PORT.INT0MASK = 0;
}
// Sampling with timer and demod
ISR(CODEC_TIMER_SAMPLING_CCA_VECT) {
/* This interrupt gets called twice for every bit to sample it. */
uint8_t SamplePin = CODEC_DEMOD_IN_PORT.IN & CODEC_DEMOD_IN_MASK;
@@ -227,6 +229,7 @@ ISR(CODEC_TIMER_SAMPLING_CCA_VECT) {
CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_RESTART_gc | CODEC_TIMER_MODSTART_EVSEL;
}
// Enumulate as a card to send card responds
ISR(CODEC_TIMER_LOADMOD_OVF_VECT) {
/* Bit rate timer. Output a half bit on the output. */
@@ -427,6 +430,7 @@ void ISO14443ACodecTask(void) {
uint16_t AnswerBitCount = ISO14443A_APP_NO_RESPONSE;
if (DemodBitCount >= ISO14443A_MIN_BITS_PER_FRAME) {
// For logging data
LogEntry(LOG_INFO_CODEC_RX_DATA, CodecBuffer, (DemodBitCount+7)/8);
LEDHook(LED_CODEC_RX, LED_PULSE);
+16 -2
View File
@@ -95,6 +95,8 @@ INLINE void Insert1(void)
*CodecBufferPtr++ = SampleRegister;
}
// End of Card-> reader communication and enter frame delay time
INLINE void Reader14443A_EOC(void)
{
CODEC_TIMER_LOADMOD.INTCTRLB = 0;
@@ -139,6 +141,7 @@ INLINE void BufferToSequence(void)
uint8_t * Buffer = CodecBuffer + CODEC_BUFFER_SIZE / 2;
CodecBufferPtr = CodecBuffer;
// Modified Miller Coding ISO14443-2 8.1.3
Insert1(); // SOC
Insert0();
@@ -176,8 +179,8 @@ INLINE void BufferToSequence(void)
if (BitCount % 8)
CodecBuffer[BitCount / 8] = SampleRegister >> (8 - (BitCount % 8));
}
ISR (TCD0_CCC_vect)
// Frame Delay Time PCD to PICC ends
ISR (CODEC_TIMER_SAMPLING_CCC_VECT)
{
isr_func_TCD0_CCC_vect();
}
@@ -209,6 +212,8 @@ void isr_Reader14443_2A_TCD0_CCC_vect(void)
PORTE.OUTTGL = PIN3_bm;
}
// Reader -> card send bits finished
// Start Frame delay time PCD to PICC
void Reader14443AMillerEOC(void)
{
CODEC_TIMER_SAMPLING.PER = 5*SAMPLE_RATE_SYSTEM_CYCLES - 1;
@@ -218,11 +223,13 @@ void Reader14443AMillerEOC(void)
PORTE.OUTTGL = PIN3_bm;
}
// EOC of Card->Reader found
ISR(CODEC_TIMER_TIMESTAMPS_CCA_VECT) // EOC found
{
Reader14443A_EOC();
}
// This interrupt find Card -> Reader SOC
ISR(ACA_AC1_vect) // this interrupt either finds the SOC or gets triggered before
{
ACA.AC1CTRL &= ~AC_INTLVL_HI_gc; // disable this interrupt
@@ -231,6 +238,10 @@ ISR(ACA_AC1_vect) // this interrupt either finds the SOC or gets triggered befor
CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_DIV1_gc;
}
// Decode the Card -> Reader signal
// according to the pause and modulated period
// if the half bit duration is modulated, then add 1 to buffer
// if the half bit duration is not modulated, then add 0 to buffer
ISR(CODEC_TIMER_LOADMOD_CCA_VECT) // pause found
{
uint8_t tmp = CODEC_TIMER_TIMESTAMPS.CNTL;
@@ -303,6 +314,8 @@ void Reader14443ACodecTask(void)
bool breakflag = false;
TmpCodecBuffer[0] >>= 2; // with this (and BitCountTmp = 2), the SOC is ignored
// Manchester Code ISO14443-2 8.2.5
while (!breakflag && BitCountTmp < TotalBitCount)
{
uint8_t Bit = TmpCodecBuffer[BitCountTmp / 8] & 0x03;
@@ -382,6 +395,7 @@ void Reader14443ACodecTask(void)
LogEntry(LOG_INFO_CODEC_TX_DATA_W_PARITY, CodecBuffer, (BitCount + 7) / 8);
/* Set state and start timer for Miller encoding. */
// Send bits to card using TCD0_CCB interrupt (See Reader14443-ISR.S)
BufferToSequence();
State = STATE_MILLER_SEND;
CodecBufferPtr = CodecBuffer;
@@ -15,6 +15,7 @@
#define AWEXC__OUTOVEN 0x088C
#define CODEC_READER_TIMER__CTRLA 0x0800
; For sending reader bits to cards
.global TCD0_CCB_vect, Reader14443AMillerEOC
TCD0_CCB_vect:
push Zero ; 1
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,20 @@
//
// Created by Zitai Chen on 05/07/2018.
//
#ifndef CHAMELEON_MINI_SNIFFISO14443_2A_H
#define CHAMELEON_MINI_SNIFFISO14443_2A_H
#include "Codec.h"
#include "Terminal/CommandLine.h"
enum RCTraffic {TRAFFIC_READER, TRAFFIC_CARD} TrafficSource;
/* Codec Interface */
void Sniff14443ACodecInit(void);
void Sniff14443ACodecDeInit(void);
void Sniff14443ACodecTask(void);
#endif //CHAMELEON_MINI_SNIFFISO14443_2A_H
+8 -8
View File
@@ -197,14 +197,14 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = {
#endif
#ifdef CONFIG_ISO14443A_SNIFF_SUPPORT
[CONFIG_ISO14443A_SNIFF] = {
.CodecInitFunc = ISO14443ACodecInit,
.CodecDeInitFunc = ISO14443ACodecDeInit,
.CodecTaskFunc = ISO14443ACodecTask,
.ApplicationInitFunc = ApplicationInitDummy,
.ApplicationResetFunc = ApplicationResetDummy,
.ApplicationTaskFunc = ApplicationTaskDummy,
.ApplicationTickFunc = ApplicationTickDummy,
.ApplicationProcessFunc = ApplicationProcessDummy,
.CodecInitFunc = Sniff14443ACodecInit,
.CodecDeInitFunc = Sniff14443ACodecDeInit,
.CodecTaskFunc = Sniff14443ACodecTask,
.ApplicationInitFunc = Sniff14443AAppInit,
.ApplicationResetFunc = Sniff14443AAppReset,
.ApplicationTaskFunc = Sniff14443AAppTask,
.ApplicationTickFunc = Sniff14443AAppTick,
.ApplicationProcessFunc = Sniff14443AAppProcess,
.ApplicationGetUidFunc = ApplicationGetUidDummy,
.ApplicationSetUidFunc = ApplicationSetUidDummy,
.UidSize = 0,
@@ -1,4 +1,4 @@
:100000000000B32E0606080800000401320090012B
:100000000000402F0606080800000401320090019D
:1000100006060808000004013200900106060808E0
:1000200000000401320090010606080800000401E7
:100030003200900106060808000004013200900119
File diff suppressed because it is too large Load Diff
+8
View File
@@ -23,6 +23,14 @@ typedef enum {
LOG_INFO_CODEC_RX_DATA_W_PARITY = 0x42, ///< Currently active codec received data.
LOG_INFO_CODEC_TX_DATA_W_PARITY = 0x43, ///< Currently active codec sent data.
LOG_INFO_CODEC_SNI_READER_DATA = 0x44, //< Sniffing codec receive data from reader
LOG_INFO_CODEC_SNI_READER_DATA_W_PARITY = 0x45, //< Sniffing codec receive data from reader
LOG_INFO_CODEC_SNI_CARD_DATA = 0x46, //< Sniffing codec receive data from card
LOG_INFO_CODEC_SNI_CARD_DATA_W_PARITY = 0x47, //< Sniffing codec receive data from card
/* App */
LOG_INFO_APP_CMD_READ = 0x80, ///< Application processed read command.
LOG_INFO_APP_CMD_WRITE = 0x81, ///< Application processed write command.
+4 -2
View File
@@ -95,8 +95,10 @@ TARGET = Chameleon-Mini
OPTIMIZATION = s
SRC += $(TARGET).c LUFADescriptors.c System.c Configuration.c Random.c Common.c Memory.c MemoryAsm.S Button.c Log.c Settings.c LED.c Map.c AntennaLevel.c
SRC += Terminal/Terminal.c Terminal/Commands.c Terminal/XModem.c Terminal/CommandLine.c
SRC += Codec/Codec.c Codec/ISO14443-2A.c Codec/Reader14443-2A.c Codec/Reader14443-ISR.S Codec/ISO15693.c
SRC += Application/MifareUltralight.c Application/MifareClassic.c Application/ISO14443-3A.c Application/Crypto1.c Application/Reader14443A.c Application/Vicinity.c Application/Sl2s2002.c Application/ISO15693-A.c
SRC += Codec/Codec.c Codec/ISO14443-2A.c Codec/Reader14443-2A.c Codec/SniffISO14443-2A.c Codec/Reader14443-ISR.S
SRC += Application/MifareUltralight.c Application/MifareClassic.c Application/ISO14443-3A.c Application/Crypto1.c Application/Reader14443A.c Application/Sniff14443A.c
SRC += Codec/ISO15693.c
SRC += Application/Vicinity.c Application/Sl2s2002.c Application/ISO15693-A.c
SRC += $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS)
LUFA_PATH = ../LUFA
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -DFLASH_DATA_ADDR=$(FLASH_DATA_ADDR) -DFLASH_DATA_SIZE=$(FLASH_DATA_SIZE) -DSPM_HELPER_ADDR=$(SPM_HELPER_ADDR) -DBUILD_DATE=$(BUILD_DATE) -DCOMMIT_ID=\"$(COMMIT_ID)\" $(SETTINGS)
+21 -7
View File
@@ -2,6 +2,7 @@
#include "Commands.h"
#include <stdio.h>
#include <avr/pgmspace.h>
#include <Settings.h>
#include "XModem.h"
#include "../Settings.h"
#include "../Chameleon-Mini.h"
@@ -16,6 +17,7 @@
#include "../Codec/Codec.h"
extern Reader14443Command Reader14443CurrentCommand;
extern Sniff14443Command Sniff14443CurrentCommand;
extern const PROGMEM CommandEntryType CommandTable[];
@@ -629,15 +631,27 @@ CommandStatusIdType CommandGetField(char* OutMessage)
CommandStatusIdType CommandExecAutocalibrate(char* OutMessage)
{
if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER)
if (GlobalSettings.ActiveSettingPtr->Configuration == CONFIG_ISO14443A_READER){
ApplicationReset();
Reader14443CurrentCommand = Reader14443_Autocalibrate;
Reader14443AAppInit();
Reader14443ACodecStart();
CommandLinePendingTaskTimeout = &Reader14443AAppTimeout;
return TIMEOUT_COMMAND;
}
else if (GlobalSettings.ActiveSettingPtr->Configuration == CONFIG_ISO14443A_SNIFF){
ApplicationReset();
Sniff14443CurrentCommand = Sniff14443_Autocalibrate;
Sniff14443AAppInit();
CommandLinePendingTaskTimeout = &Sniff14443AAppTimeout;
return TIMEOUT_COMMAND;
}
else {
return COMMAND_ERR_INVALID_USAGE_ID;
ApplicationReset();
}
Reader14443CurrentCommand = Reader14443_Autocalibrate;
Reader14443AAppInit();
Reader14443ACodecStart();
CommandLinePendingTaskTimeout = &Reader14443AAppTimeout;
return TIMEOUT_COMMAND;
}
CommandStatusIdType CommandExecClone(char *OutMessage)
+66 -24
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python3
import serial
import serial.tools.list_ports
@@ -13,15 +13,22 @@ class Device:
COMMAND_DOWNLOAD = "DOWNLOAD"
COMMAND_SETTING = "SETTING"
COMMAND_UID = "UID"
COMMAND_GETUID = "GETUID"
COMMAND_IDENTIFY = "IDENTIFY"
COMMAND_DUMPMFU = "DUMP_MFU"
COMMAND_CONFIG = "CONFIG"
COMMAND_LOG_DOWNLOAD = "LOGDOWNLOAD"
COMMAND_LOG_CLEAR = "LOGCLEAR"
COMMAND_LOGMODE = "LOGMODE"
COMMAND_LBUTTON = "LBUTTON"
COMMAND_LBUTTONLONG = "LBUTTON_LONG"
COMMAND_RBUTTON = "RBUTTON"
COMMAND_RBUTTONLONG = "RBUTTON_LONG"
COMMAND_GREEN_LED = "LEDGREEN"
COMMAND_RED_LED = "LEDRED"
COMMAND_THRESHOLD = "THRESHOLD"
COMMAND_UPGRADE = "upgrade"
STATUS_CODE_OK = 100
STATUS_CODE_OK_WITH_TEXT = 101
STATUS_CODE_WAITING_FOR_XMODEM = 110
@@ -49,33 +56,32 @@ class Device:
SUGGEST_CHAR = "?"
SET_CHAR = "="
GET_CHAR = "?"
def __init__(self, verboseFunc = None):
self.verboseFunc = verboseFunc
self.serial = serial.Serial(None, 9600, timeout=5.0)
self.versionString = ""
self.supportedConfs = []
def verboseLog(self, text):
if (self.verboseFunc):
self.verboseFunc(text)
def listDevices():
devices = []
for port in serial.tools.list_ports.grep("({0:04x}:{1:04x})|({0:04X}:{1:04X})".format(Chameleon.USB_VID, Chameleon.USB_PID)):
devices.append(port[0])
return devices
def connect(self, comport):
return devices
def connect(self, comport):
self.serial.port = comport
try:
self.serial.open()
except:
pass
if (self.serial.isOpen()):
# Send escape key to force clearing the Chameleon's input buffer
self.serial.write(b"\x1B")
@@ -94,20 +100,20 @@ class Device:
return False
result = self.getCmdSuggestions(self.COMMAND_CONFIG)
if (result['statusCode'] == self.STATUS_CODE_OK_WITH_TEXT):
self.supportedConfs = result['response'].split(",")
else:
return False
else:
return False
return True
def disconnect(self):
self.verboseLog("Closing serial port")
self.serial.close()
def isConnected(self):
return self.serial.isOpen()
@@ -116,7 +122,7 @@ class Device:
data = self.serial.read(size)
self.serial.timeout = 5.0
return data
def writeCmd(self, cmd):
# Execute command
cmdLine = cmd + self.LINE_ENDING
@@ -130,19 +136,19 @@ class Device:
return None
else:
self.verboseLog("Executing <{}>: {}".format(cmd, status))
statusCode, statusText = status.split(":")
statusCode = int(statusCode)
result = {'statusCode': statusCode, 'statusText': statusText, 'response': None}
if (statusCode == self.STATUS_CODE_OK_WITH_TEXT):
result['response'] = self.readResponse()
elif (statusCode == self.STATUS_CODE_TRUE):
result['response'] = True
elif (statusCode == self.STATUS_CODE_FALSE):
result['response'] = False
return result
def readResponse(self):
@@ -150,27 +156,30 @@ class Device:
response = self.serial.readline().decode('ascii').rstrip()
self.verboseLog("Response: {}".format(response))
return response
def execCmd(self, cmd, args=None):
if (args is None):
return self.writeCmd("{}".format(cmd))
else:
return self.writeCmd("{} {}".format(cmd, args))
def getSetCmd(self, cmd, arg=None):
# Determine if set or get mode
if (arg is None):
return self.writeCmd("{}{}".format(cmd, self.GET_CHAR))
else:
return self.writeCmd("{}{}{}".format(cmd, self.SET_CHAR, arg))
def returnCmd(self, cmd, arg=None):
return self.writeCmd("{}".format(cmd))
def getCmdSuggestions(self, cmd):
result = self.getSetCmd(cmd, self.SUGGEST_CHAR)
if (result['response'] is not None):
result['suggestions'] = result['response'].split(",")
return result
def cmdUploadDump(self, dataStream):
if (self.execCmd(self.COMMAND_UPLOAD)['statusCode'] == self.STATUS_CODE_WAITING_FOR_XMODEM):
# XMODEM started
@@ -201,7 +210,7 @@ class Device:
def cmdLogMode(self, newLogMode):
return self.getSetCmd(self.COMMAND_LOGMODE, newLogMode)
def cmdVersion(self):
return self.getSetCmd(self.COMMAND_VERSION)
@@ -211,6 +220,15 @@ class Device:
def cmdUID(self, newUID = None):
return self.getSetCmd(self.COMMAND_UID, newUID)
def cmdGetUID(self):
return self.returnCmd(self.COMMAND_GETUID)
def cmdIdentify(self):
return self.returnCmd(self.COMMAND_IDENTIFY)
def cmdDumpMFU(self):
return self.returnCmd(self.COMMAND_DUMPMFU)
def cmdConfig(self, newConfig = None):
if (newConfig == self.SUGGEST_CHAR):
return self.getCmdSuggestions(self.COMMAND_CONFIG)
@@ -223,20 +241,44 @@ class Device:
else:
return self.getSetCmd(self.COMMAND_LBUTTON, newAction)
def cmdLButtonLong(self, newAction = None):
if (newAction == self.SUGGEST_CHAR):
return self.getCmdSuggestions(self.COMMAND_LBUTTONLONG)
else:
return self.getSetCmd(self.COMMAND_LBUTTONLONG, newAction)
def cmdRButton(self, newAction = None):
if (newAction == self.SUGGEST_CHAR):
return self.getCmdSuggestions(self.COMMAND_RBUTTON)
else:
return self.getSetCmd(self.COMMAND_RBUTTON, newAction)
def cmdRButtonLong(self, newAction = None):
if (newAction == self.SUGGEST_CHAR):
return self.getCmdSuggestions(self.COMMAND_RBUTTONLONG)
else:
return self.getSetCmd(self.COMMAND_RBUTTONLONG, newAction)
def cmdGreenLED(self, newFunction = None):
if (newFunction == self.SUGGEST_CHAR):
return self.getCmdSuggestions(self.COMMAND_GREEN_LED)
else:
return self.getSetCmd(self.COMMAND_GREEN_LED, newFunction)
def cmdRedLED(self, newFunction = None):
if (newFunction == self.SUGGEST_CHAR):
return self.getCmdSuggestions(self.COMMAND_RED_LED)
else:
return self.getSetCmd(self.COMMAND_RED_LED, newFunction)
def cmdThreshold(self, value):
if(value == self.SUGGEST_CHAR):
return self.getCmdSuggestions(self.COMMAND_THRESHOLD)
else:
return self.getSetCmd(self.COMMAND_THRESHOLD, value)
def cmdUpgrade(self):
# Execute command
cmdLine = self.COMMAND_UPGRADE + self.LINE_ENDING
self.serial.write(cmdLine.encode('ascii'))
return 0
+343
View File
@@ -0,0 +1,343 @@
import binascii
import crcmod
from enum import Enum
from Chameleon.MFDESFire import MFDESFireDecode
from Chameleon.utils import TrafficSource
# Parameters for CRC_A
CRC_INIT = 0x6363
POLY = 0x11021
CRC_A_func = crcmod.mkCrcFun(POLY, initCrc=CRC_INIT, xorOut=0)
class ReaderCMD(Enum):
NONE = 0
SELECT = 1
RATS = 2
PPS = 3
readerCMD = ReaderCMD.NONE
# Map card types string to decoder
def DummyCardDecoder(data, source):
return ""
CardTypesMap = {
"None": {"ApplicationDecoder": DummyCardDecoder},
"MFDESFire": {"ApplicationDecoder": MFDESFireDecode},
}
class BlockData:
@staticmethod
def isBlockData(byteCount, data):
if(byteCount >= 3 and (data[0]& 0xE6) in ReaderTrafficTypes["PCB"]):
return True
else:
return False
def __init__(self, byteCount, data, source, Cardtype):
self.byteCount = byteCount
self.data = data
self.PCB = data[0]
self.type = ReaderTrafficTypes["PCB"][self.PCB & 0xE6]
self.CID = None
self.NAD = None
self.INF = None
self.source = source
self.CRCChecked = CRC_A_check(data)
self.CardApplicationDecoder = CardTypesMap[Cardtype]["ApplicationDecoder"]
if self.CRCChecked:
hasCID = self.PCB & 0x08 # PCB b4 indicate CID
hasNAD = 0
if (self.type == "IBlock"):
hasNAD = self.PCB & 0x04 # IBlock PCB b2 indicate NAD
byteNext = 1
# CID
if (hasCID):
self.CID = self.data[byteNext]
byteNext += 1
# NAD
if (hasNAD):
self.NAD = self.data[byteNext]
byteNext += 1
# INF field not empty
if(byteNext < byteCount -2):
self.INF = self.data[byteNext: byteCount-2]
def decode(self):
note = ""
# Prologue
# PCB
note += self.type + " "
# Block number
if ((self.type == "IBlock" or self.type == "RBlock") and self.PCB & 0x01):
note += "BlkNo:1 "
# Chaining?
if (self.type == "IBlock" and self.PCB & 0x10):
note += "Chaining "
# ACK/NAK? for R-Block
if (self.type == "RBlock"):
if (self.PCB & 0x10):
note += "NAK "
else:
note += "ACK "
# DESEL/WTX for SBlock
if (self.type == "SBlock"):
if (self.PCB & 0x30 == 0x00):
note += "DESEL "
elif (self.PCB & 0x30 == 0x30):
note += "WTX"
# CID
if (self.CID != None):
note += "CID:" + hex(self.CID) + " "
# NAD
if (self.NAD != None):
note += "NAD:" + hex(self.NAD) + " "
# INF
if (self.INF != None):
note += self.CardApplicationDecoder(self.INF, self.source)
# EDC CRC check
if not self.CRCChecked:
note += " WRONG CRC "
return note
ReaderTrafficTypes = {
"SEL":{
0x93: "SEL_CL1 ",
0x95: "SEL_CL2 ",
0x97: "SEL_CL3 ",
},
# 1 byte commands
"SHORTFRAME": {
0x26: "REQA",
0x52: "WUPA",
0x35: "Optional Timeslot Method",
# 40 - 4F Proprietary
# 78 - 7F proprietary
# Other RFU
},
"FSDI":{
0x0: "FSD:16 ",
0x1: "FSD:24 ",
0x2: "FSD:32 ",
0x3: "FSD:40 ",
0x4: "FSD:48 ",
0x5: "FSD:64 ",
0x6: "FSD:96 ",
0x7: "FSD:128 ",
0x8: "FSD:256 "
},
"PCB":{
# IBlock 000X XX1X
0x02: "IBlock", # 000X X01X
0x08: "IBlock", # 000X X11X
# RBlock 101X X01X
0xA2: "RBlock", # 101X X01X
# SBlock 11XX X010
0xC2: "SBlock", # 110X X010
0xE2: "SBlock" # 111X X010
}
}
CardTrafficTypes = {
"SAK":{
0x04: "UID NOT Complete ",
0x24: "UID NOT Complete, PICC compliant with 14443-4",
0x20: "UID complete, PICC compliant with 14443-4 ",
0x00: "UID complete, PICC NOT compliant with 14443-4"
},
"FSCI": {
0x0: "FSC:16 ",
0x1: "FSC:24 ",
0x2: "FSC:32 ",
0x3: "FSC:40 ",
0x4: "FSC:48 ",
0x5: "FSC:64 ",
0x6: "FSC:96 ",
0x7: "FSC:128 ",
0x8: "FSC:256 "
}
}
def CRC_A(data):
return CRC_A_func(data)
def CRC_A_check(data):
datalen = len(data)
# Short frame/SAK or no space for CRC skip check
if(datalen < 3 ):
return True
crc = CRC_A(bytearray(data[0:datalen-2])).to_bytes(2,'little')
if (data[datalen-2:datalen] == crc):
return True
else:
return False
def parseReader_3(data):
global readerCMD
byteCount = len(data)
note = ""
# short frame commands
if (byteCount == 1 and data[0] in ReaderTrafficTypes["SHORTFRAME"]):
note += ReaderTrafficTypes["SHORTFRAME"][data[0]]
# ANTICOLLISION command
elif (byteCount < 9 and byteCount > 1 and data[0] in ReaderTrafficTypes["SEL"] and data[1] & 0x88 == 0):
note += "ATCOLI - "
note += ReaderTrafficTypes["SEL"][data[0]]
# note += "UID_CLn:" + binascii.hexlify(data[2:7]).decode() + " "
# note += str((data[1] >> 4) & 0x0f) + "bytes + " + str(data[1] & 0x0f) + "bits "
# SELECT Command
elif (byteCount == 9 and data[0] in ReaderTrafficTypes["SEL"] and data[1] == 0x70):
readerCMD = ReaderCMD.SELECT
note += "SELECT - "
note += ReaderTrafficTypes["SEL"][data[0]]
note += "UID_CLn:" + binascii.hexlify(data[2:6]).decode() + " "
# Check CRC for SELECT
if (not CRC_A_check(data)):
note += " WRONG CRC "
# note += "7bytes + 0bits "
# note += "CRC_A:"+data[7:9]
# HALT Command
elif (byteCount == 4 and data[0] == 0x50 and data[1] == 0x00):
note += "HALT"
return note
def parseReader_4(data, Cardtype):
global readerCMD
byteCount = len(data)
note = ""
# RATS
if (byteCount == 4 and data[0] == 0xe0 and ((data[1] & 0x0f) < 15) and (
(data[1] & 0xf0 >> 8) in ReaderTrafficTypes["FSDI"])):
note += "RATS - "
note += ReaderTrafficTypes["FSDI"][data[1] >> 8]
note += "CID:" + hex(data[1] & 0x0f) + " "
if (not CRC_A_check(data)):
note += " WRONG CRC "
else:
readerCMD = ReaderCMD.RATS
# PPS Protocol and parameter selection request
# PSS0 only
elif (byteCount == 4 and (data[0] & 0xf0 == 0xd0) and (data[1] == 0x01)):
note += "PSS0 - "
note += "CID:" + str(data[1] & 0x0f) + " "
readerCMD = ReaderCMD.PPS
# PSS0+1
elif (byteCount == 5 and (data[0] & 0xf0 == 0xd0) and (data[1] == 0x11) and (data[2] & 0xf0 == 0x00)):
note += "PSS0+1 - "
note += "CID:" + str(data[1] & 0x0f) + " "
note += "DSI:" + str(pow(2, (data[2] >> 2) & 0x03)) + " "
note += "DRI:" + str(pow(2, data[2] & 0x03)) + " "
# Half-duplex block transmission
# PCB bit mask: 0b11100110
elif (BlockData.isBlockData(byteCount, data)):
blockData = BlockData(byteCount,data, TrafficSource.Reader, Cardtype)
note = blockData.decode()
return note
def parseCard_3(data):
byteCount = len(data)
note = ""
# ATQA: RRRR XXXX XXRX XXXX
if(byteCount == 2 and (data[0] & 0x20 == 0x00) and (data[1] & 0xf0 == 0x00)):
note += "ATQA - "
note += binascii.hexlify(data).decode()
# SAK
elif (byteCount == 3 and readerCMD == ReaderCMD.SELECT and ((data[0] & (0x24)) in CardTrafficTypes["SAK"])):
note += "SAK - "
note += CardTrafficTypes["SAK"][(data[2] & 0x24)]
if not CRC_A_check(data):
note += " WRONG CRC "
# UID
elif (byteCount == 5 and (data[0] ^ data[1] ^ data[2] ^ data[3]) == data[4] ):
note += "UID Resp - CLn "
return note
def parseCard_4(data, Cardtype):
global readerCMD
byteCount = len(data)
note = ""
# ATS
# TL + T0 + TA + TB + TC + T1 ... + CRC
# TL: length without CRC
# ATS without data
if(byteCount == 3 and readerCMD == ReaderCMD.RATS and data[0] == (byteCount-2)):
note += "ATS - NO DATA"
# ATS with data mush have T0, T0 b8=0
elif (byteCount > 3 and readerCMD == ReaderCMD.RATS and data[0] == (byteCount-2)
and data[1] & 0x80 == 0x00
and data[1] & 0x0f in CardTrafficTypes["FSCI"]):
note += "ATS - "
# Decode T0
hasTA = data[1] & 0x10
hasTB = data[1] & 0x20
hasTC = data[1] & 0x40
note += CardTrafficTypes["FSCI"][data[1] & 0x0f]
# Which byte to decode next
byteNext = 2 # T0 Decoded, next is TA/TB/TC
# TA b4=0
if (hasTA and data[byteNext] & 0x08 == 0x00):
note += "TA:" + hex(data[byteNext]) + " "
byteNext += 1
if (hasTB):
note += "TB:" + hex(data[byteNext]) + " "
byteNext += 1
# TC b3-8=0
if (hasTC and data[byteNext] & 0xFC == 0x00):
note += "TC:" + hex(data[byteNext]) + " "
byteNext += 1
# Check CRC_A
if not CRC_A_check(data):
note += " WRONG CRC "
# Application Data
elif (BlockData.isBlockData(byteCount, data)):
blockData = BlockData(byteCount,data, TrafficSource.Card, Cardtype)
note = blockData.decode()
readerCMD = ReaderCMD.NONE
return note
def parseReader(data, Cardtype):
return parseReader_3(data) + parseReader_4(data, Cardtype)
def parseCard(data, Cardtype):
return parseCard_3(data) + parseCard_4(data, Cardtype)
+60 -2
View File
@@ -2,6 +2,41 @@
import struct
import binascii
import math
import Chameleon.ISO14443 as iso14443_3
def checkParityBit(data):
byteCount = len(data)
# Short frame, no parityBit
if (byteCount == 1):
return (True, data)
# 9 bit is a group, validate bit count is calculated below
bitCount = int((byteCount*8)/9) * 9
parsedData = bytearray(int(bitCount/9))
oneCounter = 0 # Counter for count ones in a byte
for i in range(0, bitCount):
# Get bit i in data
byteIndex = math.floor(i/8)
bitIndex = i % 8
bit = (data[byteIndex] >> bitIndex) & 0x01
# Check parityBit
# Current bit is parityBit
if(i % 9 == 8):
# Even number of ones in current byte
if(oneCounter % 2 and bit == 1):
return (False, data)
# Odd number of ones in current byte
elif((not oneCounter % 2) and bit == 0):
return (False, data)
oneCounter = 0
# Current bit is normal bit
else:
oneCounter += bit
parsedData[int(i/9)] |= bit << (i%9)
return (True, parsedData)
def noDecoder(data):
return ""
@@ -12,6 +47,13 @@ def textDecoder(data):
def binaryDecoder(data):
return binascii.hexlify(data).decode()
def binaryParityDecoder(data):
isValid, checkedData = checkParityBit(data)
if(isValid):
return binascii.hexlify(checkedData).decode()
else:
return binascii.hexlify(checkedData).decode()+"!"
eventTypes = {
0x00: { 'name': 'EMPTY', 'decoder': noDecoder },
0x10: { 'name': 'GENERIC', 'decoder': textDecoder },
@@ -25,6 +67,12 @@ eventTypes = {
0x42: { 'name': 'CODEC RX W/PARITY', 'decoder': binaryDecoder },
0x43: { 'name': 'CODEC TX W/PARITY', 'decoder': binaryDecoder },
0x44: { 'name': 'CODEC RX SNI READER', 'decoder': binaryDecoder },
0x45: { 'name': 'CODEC RX SNI READER W/PARITY', 'decoder': binaryParityDecoder },
0x46: { 'name': 'CODEC RX SNI CARD', 'decoder': binaryDecoder },
0x47: { 'name': 'CODEC RX SNI CARD W/PARITY', 'decoder': binaryParityDecoder },
0x80: { 'name': 'APP READ', 'decoder': binaryDecoder },
0x81: { 'name': 'APP WRITE', 'decoder': binaryDecoder },
0x84: { 'name': 'APP INC', 'decoder': binaryDecoder },
@@ -49,7 +97,7 @@ eventTypes = {
TIMESTAMP_MAX = 65536
eventTypes = { i : ({'name': 'UNKNOWN', 'decoder': binaryDecoder} if i not in eventTypes.keys() else eventTypes[i]) for i in range(256) }
def parseBinary(binaryStream):
def parseBinary(binaryStream, decoder=None):
log = []
# Completely read file contents and process them byte by byte
@@ -88,13 +136,23 @@ def parseBinary(binaryStream):
if (deltaTimestamp < 0):
deltaTimestamp += TIMESTAMP_MAX;
note = ""
# If we need to decode the data and paritybit check success
if (decoder!=None and len(logData) >0 and logData[-1] != '!'):
# Decode the data from Reader
if(event == 0x44 or event == 0x45):
note = iso14443_3.parseReader(binascii.a2b_hex(logData), decoder)
elif (event == 0x46 or event == 0x47):
note = iso14443_3.parseCard(binascii.a2b_hex(logData), decoder)
# Create log entry as dict and append it to event list
logEntry = {
'eventName': eventTypes[event]['name'],
'dataLength': dataLength,
'timestamp': timestamp,
'deltaTimestamp': deltaTimestamp,
'data': logData
'data': logData,
'note': note
}
log.append(logEntry)

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