Skip to content

Commit 65766e1

Browse files
committed
Incremental backup -- Auth schemes should be working -- New CommMode checksum functions DO NOT fit into text/data (yet)
1 parent bf1eadc commit 65766e1

File tree

7 files changed

+77
-44
lines changed

7 files changed

+77
-44
lines changed

Firmware/Chameleon-Mini/Application/CryptoCMAC.c

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ This notice must be retained at the top of all source files where indicated.
3232
#include "CryptoTDEA.h"
3333
#include "CryptoAES128.h"
3434

35+
#if 0
3536
static uint8_t _cmac_K1[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 };
3637
static uint8_t _cmac_K2[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 };
3738
static uint8_t _cmac_RB[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 };
@@ -190,3 +191,4 @@ bool checkBufferMAC(uint8_t *bufferData, uint16_t bufferSize, uint16_t checksumS
190191
}
191192
return true;
192193
}
194+
#endif

Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c

+15-2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ uint8_t Iso144434LastBlockLength = 0x00;
4444
uint8_t StateRetryCount = 0x00;
4545
uint8_t LastReaderSentCmd = 0x00;
4646

47+
uint8_t ISO14443ALastDataFrame[MAX_DATA_FRAME_XFER_SIZE] = { 0x00 };
48+
uint16_t ISO14443ALastDataFrameBits = 0;
49+
4750
bool CheckStateRetryCount2(bool resetByDefault, bool performLogging) {
4851
if (resetByDefault || ++StateRetryCount >= MAX_STATE_RETRY_COUNT) {
4952
ISO144434SwitchState2(Iso144433AIdleState, performLogging);
@@ -74,6 +77,7 @@ void ISO144434Reset(void) {
7477
/* No logging -- spams the log */
7578
Iso144434State = ISO14443_4_STATE_EXPECT_RATS;
7679
Iso144434BlockNumber = 1;
80+
ISO14443ALastDataFrameBits = 0;
7781
}
7882

7983
static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount) {
@@ -205,13 +209,21 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1
205209
/* 7.5.4.3, rule 12 */
206210
/* This is a NAK. Send an ACK back */
207211
Buffer[0] = ISO14443_PCB_R_BLOCK_STATIC | ISO14443_PCB_R_BLOCK_ACK | MyBlockNumber;
208-
ByteCount = 1;
212+
//ByteCount = 1;
213+
// Per the NXP data sheet MF1S50YYX_V1 (Table 10: ACK / NAK), we should return 4 bits:
214+
return 4;
209215
} else {
210216
/* This is an ACK */
211217
/* NOTE: Chaining is not supported yet. */
212218
const char *debugPrintStr = PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d");
213219
DEBUG_PRINT_P(debugPrintStr, __LINE__);
214-
return ISO14443A_APP_NO_RESPONSE;
220+
// Resend the data from the last frame:
221+
if (ISO14443ALastDataFrameBits > 0) {
222+
memcpy(&Buffer[0], &ISO14443ALastDataFrame[0], (ISO14443ALastDataFrameBits + BITS_PER_BYTE - 1) / BITS_PER_BYTE);
223+
return ISO14443ALastDataFrameBits;
224+
} else {
225+
return ISO14443A_APP_NO_RESPONSE;
226+
}
215227
}
216228
const char *debugPrintStr6 = PSTR("ISO14443-4: R-BLK");
217229
LogDebuggingMsg(debugPrintStr6);
@@ -272,6 +284,7 @@ void ISO144433AReset(void) {
272284
/* No logging -- spams the log */
273285
Iso144433AState = ISO14443_3A_STATE_IDLE;
274286
Iso144433AIdleState = ISO14443_3A_STATE_IDLE;
287+
ISO14443ALastDataFrameBits = 0;
275288
}
276289

277290
void ISO144433AHalt(void) {

Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h

+19-3
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ This notice must be retained at the top of all source files where indicated.
4141
*/
4242

4343
#define ISO14443A_CMD_RATS 0xE0
44-
#define ISO14443A_RATS_FRAME_SIZE (6 * BITS_PER_BYTE) //(4 * 8) /* Bit */
44+
#define ISO14443A_RATS_FRAME_SIZE (6 * BITS_PER_BYTE) /* Bit */
4545
#define ISO14443A_CMD_RNAK 0xB2
46-
#define ISO14443A_CRC_FRAME_SIZE (ISO14443A_CRCA_SIZE * BITS_PER_BYTE)
46+
#define ISO14443A_CRC_FRAME_SIZE (ISO14443A_CRCA_SIZE * BITS_PER_BYTE)
4747

4848
#define ISO14443_PCB_BLOCK_TYPE_MASK 0xC0
4949
#define ISO14443_PCB_I_BLOCK 0x00
@@ -92,13 +92,29 @@ extern uint8_t Iso144434BlockNumber;
9292
extern uint8_t Iso144434CardID;
9393
extern uint8_t LastReaderSentCmd;
9494

95+
/* Configure saving last data frame state so can resend on ACK from the PCD */
96+
97+
#define MAX_DATA_FRAME_XFER_SIZE (64)
98+
extern uint8_t ISO14443ALastDataFrame[MAX_DATA_FRAME_XFER_SIZE];
99+
extern uint16_t ISO14443ALastDataFrameBits;
100+
101+
INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t BufferBitCount) {
102+
uint16_t ISO14443ALastDataFrameBytes = MIN((BufferBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE, MAX_DATA_FRAME_XFER_SIZE);
103+
if (ISO14443ALastDataFrameBytes > 0) {
104+
memcpy(ISO14443ALastDataFrame, &Buffer[0], ISO14443ALastDataFrameBytes);
105+
}
106+
ISO14443ALastDataFrameBits = BufferBitCount;
107+
return BufferBitCount;
108+
}
109+
95110
/* Setup some fuzzy response handling for problematic readers like the ACR122U */
111+
96112
#define MAX_STATE_RETRY_COUNT (4)
97113
extern uint8_t StateRetryCount;
98114
bool CheckStateRetryCount(bool resetByDefault);
99115
bool CheckStateRetryCount2(bool resetByDefault, bool performLogging);
100116

101-
#define IGNORE_ACK_BYTE (0x92)
117+
//#define IGNORE_ACK_BYTE (0x92)
102118

103119
/* Support functions */
104120
void ISO144434SwitchState(Iso144434StateType NewState);

Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c

+10-5
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,8 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) {
518518
keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_2KTDEA);
519519
Key = SessionKey;
520520
DesfireCommandState.KeyId = KeyId;
521+
DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES;
522+
DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES);
521523

522524
/* Fetch the key */
523525
if (cryptoKeyType == CRYPTO_TYPE_DES) {
@@ -581,10 +583,15 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) {
581583

582584
/* Reset parameters for authentication from the first exchange */
583585
KeyId = DesfireCommandState.KeyId;
584-
cryptoKeyType = CRYPTO_TYPE_2KTDEA;
585-
keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_2KTDEA);
586+
cryptoKeyType = DesfireCommandState.CryptoMethodType;
587+
keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES);
586588
Key = SessionKey;
587-
ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize);
589+
if (cryptoKeyType == CRYPTO_TYPE_DES) {
590+
ReadAppKey(SelectedApp.Slot, KeyId, Key, CRYPTO_DES_KEY_SIZE);
591+
memcpy(Key + CRYPTO_DES_KEY_SIZE, Key, CRYPTO_DES_KEY_SIZE);
592+
} else {
593+
ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize);
594+
}
588595

589596
/* Decrypt the challenge sent back to get RndA and a shifted RndB */
590597
BYTE challengeRndAB[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES];
@@ -617,8 +624,6 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) {
617624
AuthenticatedWithKey = KeyId;
618625
AuthenticatedWithPICCMasterKey = (SelectedApp.Slot == DESFIRE_PICC_APP_SLOT) &&
619626
(KeyId == DESFIRE_MASTER_KEY_ID);
620-
DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_2KTDEA;
621-
DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_2KTDEA);
622627

623628
/* Return the status on success */
624629
Buffer[0] = STATUS_OPERATION_OK;

Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c

+10-11
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount) {
148148
}
149149

150150
uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) {
151-
DEBUG_PRINT_P(PSTR("PRE -- CommMode -- 0x%02x"), CommMode);
151+
//DEBUG_PRINT_P(PSTR("PRE -- CommMode -- 0x%02x"), CommMode);
152152
switch (CommMode) {
153-
case DESFIRE_COMMS_PLAINTEXT_MAC: {
153+
/*case DESFIRE_COMMS_PLAINTEXT_MAC: {
154154
uint16_t ChecksumBytes = 0;
155155
if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) {
156156
ChecksumBytes = 4;
@@ -187,18 +187,18 @@ uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buffe
187187
return 0;
188188
}
189189
return MAX(0, BufferSize - ChecksumBytes);
190-
}
190+
}*/
191191
case DESFIRE_COMMS_PLAINTEXT:
192192
default:
193-
// Leave the CRCA bytes intact:
194-
return BufferSize;
193+
// Leave the CRCA bytes intact:
194+
return BufferSize;
195195
}
196196
}
197197

198198
uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) {
199-
DEBUG_PRINT_P(PSTR("POST -- CommMode -- 0x%02x"), CommMode);
199+
//DEBUG_PRINT_P(PSTR("POST -- CommMode -- 0x%02x"), CommMode);
200200
switch (CommMode) {
201-
case DESFIRE_COMMS_PLAINTEXT_MAC: {
201+
/*case DESFIRE_COMMS_PLAINTEXT_MAC: {
202202
if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) {
203203
return appendBufferMAC(SessionKey, Buffer, BufferSize);
204204
} else {
@@ -235,12 +235,11 @@ uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buff
235235
CryptoAESEncryptBuffer(XferBytes, Buffer, &Buffer[XferBytes], SessionIV, SessionKey);
236236
memmove(&Buffer[0], &Buffer[XferBytes], XferBytes);
237237
return XferBytes;
238-
}
238+
}*/
239239
case DESFIRE_COMMS_PLAINTEXT:
240240
default:
241-
//ISO14443AAppendCRCA(Buffer, BufferSize);
242-
//return BufferSize + 2;
243-
return BufferSize;
241+
ISO14443AAppendCRCA(Buffer, BufferSize);
242+
return BufferSize + 2;
244243
}
245244
}
246245

Firmware/Chameleon-Mini/Application/MifareDESFire.c

+20-22
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,11 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) {
174174
uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) {
175175
size_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
176176
DesfireCmdCLA = Buffer[0];
177-
LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount);
177+
//LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount);
178178
if (BitCount == 0) {
179+
LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount);
179180
return ISO14443A_APP_NO_RESPONSE;
180-
} else if ((ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 &&
181+
} else if ((ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 &&
181182
Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) || Iso7816CLA(DesfireCmdCLA)) {
182183
/* Wrapped native command structure or ISO7816: */
183184
if (Iso7816CLA(DesfireCmdCLA)) {
@@ -186,7 +187,7 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) {
186187
Buffer[0] = (uint8_t)((iso7816ParamsStatus >> 8) & 0x00ff);
187188
Buffer[1] = (uint8_t)(iso7816ParamsStatus & 0x00ff);
188189
ByteCount = 2;
189-
return ByteCount * BITS_PER_BYTE;
190+
return ByteCount * BITS_PER_BYTE;
190191
}
191192
}
192193
ByteCount = Buffer[4];
@@ -203,7 +204,7 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) {
203204
} else {
204205
/* Re-wrap into ISO 7816-4 */
205206
}
206-
LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount);
207+
//LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount);
207208
return ByteCount * BITS_PER_BYTE;
208209
} else {
209210
/* ISO/IEC 14443-4 PDUs: No extra work */
@@ -215,41 +216,37 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) {
215216
uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) {
216217
uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
217218
uint16_t ReturnedBytes = 0;
218-
if (ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 &&
219-
Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) {
219+
if (ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 &&
220+
Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) {
221+
DesfireCmdCLA = Buffer[0];
220222
uint16_t IncomingByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
221223
uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE;
222224
uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount);
223225
uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
224-
ProcessedBitCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE;
225-
return ProcessedBitCount;
226-
} else if (BitCount == 4 && (Buffer[0] & 0xF0) == 0xA0) {
227-
// NXP-based PCD sent a "keep alive" response of ACK,
228-
// so we respond with a corresponding NAK (with CRCA bytes appended):
229-
Buffer[0] = 0x00;
230-
return 4;
226+
return ISO14443AStoreLastDataFrameAndReturn(Buffer, DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE);
231227
} else if (IsWrappedISO7816CommandType(Buffer, ByteCount)) {
228+
DesfireCmdCLA = Buffer[2];
232229
uint8_t ISO7816PrologueBytes[2];
233230
memcpy(&ISO7816PrologueBytes[0], Buffer, 2);
234231
uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount);
235-
memmove(&Buffer[0], &Buffer[2], IncomingByteCount - 2);
232+
memmove(&Buffer[0], &Buffer[2], IncomingByteCount - 2);
236233
uint16_t UnwrappedBitCount = (IncomingByteCount - 2) * BITS_PER_BYTE;
237-
uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount);
234+
uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount);
238235
uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
239236
/* Append the same ISO7816 prologue bytes to the response: */
240237
memmove(&Buffer[2], &Buffer[0], ProcessedByteCount);
241238
memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2);
242239
ProcessedBitCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2) * BITS_PER_BYTE;
243-
return ProcessedBitCount;
240+
return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedBitCount);
244241
} else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) {
245242
/* This case should handle non-wrappped native commands. No pre/postprocessing afterwards: */
246-
return ReturnedBytes;
247-
} else { // if (!AnticolNoResp) {
243+
return ISO14443AStoreLastDataFrameAndReturn(Buffer, ReturnedBytes * BITS_PER_BYTE);
244+
} else if (!AnticolNoResp || BitCount < BITS_PER_BYTE) {
248245
/* This case is to exchange anticollision loop and RATS data. No need to pre/postprocess it depending
249-
* on the CommMode, which has not been set yet if we reach this point:
246+
* on the CommMode, which has not been set yet if we reach this point:
250247
*/
251-
uint16_t PiccProcessRespBytes = ISO144433APiccProcess(Buffer, BitCount);
252-
if (PiccProcessRespBytes == ISO14443A_APP_NO_RESPONSE) {
248+
uint16_t PiccProcessRespBits = ISO144433APiccProcess(Buffer, BitCount);
249+
if (PiccProcessRespBits == ISO14443A_APP_NO_RESPONSE) {
253250
// Stop pesky USB readers trying to autodetect all tag types by brute-force enumeration
254251
// from interfering with making it into the command exchange (DESFIRE_IDLE) states.
255252
// Once the anticollision and/or RATS has completed, set this flag to keep it from
@@ -259,8 +256,9 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) {
259256
// and it really screws things up timing-wise!
260257
AnticolNoResp = true;
261258
}
262-
return PiccProcessRespBytes;
259+
return ISO14443AStoreLastDataFrameAndReturn(Buffer, PiccProcessRespBits);
263260
}
261+
LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount);
264262
return ISO14443A_APP_NO_RESPONSE;
265263
}
266264

Firmware/Chameleon-Mini/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ CC_FLAGS = -g0 -DUSE_LUFA_CONFIG_HEADER -DFLASH_DATA_ADDR=$(FLASH_DATA_ADDR)
191191
-D__AVR_ATxmega128A4U__ -D__PROG_TYPES_COMPAT__ -DMAX_ENDPOINT_INDEX=4 \
192192
-std=gnu99 -Werror=implicit-function-declaration \
193193
-fno-inline-small-functions -fshort-enums -fpack-struct \
194-
-ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden \
194+
-ffunction-sections -fdata-sections -fvisibility=hidden \
195195
-Wl,-strip-all -Wl,--gc-sections --data-sections \
196196
-Wl,-relax -fno-split-wide-types -fno-tree-scev-cprop \
197197
-fno-aggressive-loop-optimizations #-fno-jump-tables -fno-common

0 commit comments

Comments
 (0)