From fba0ee3f633cb91e54e70487f3f181ebe49a0658 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sun, 30 Jan 2022 12:34:25 -0500 Subject: [PATCH 01/68] Debugging ISO authenticate command (0x1a) --- .../Chameleon-Mini/Application/CryptoTDEA.h | 4 +- .../Application/DESFire/DESFireInstructions.c | 5 +- .../Application/MifareDESFire.c | 5 +- .../LocalInclude/CryptoUtils.h | 68 +++++++++++ .../LocalInclude/DesfireUtils.h | 106 +++++++++++++++++- .../LocalInclude/LibNFCWrapper.h | 2 +- Software/DESFireLibNFCTesting/Makefile | 2 + .../Source/TestAuthenticateISO.c | 39 +++++++ 8 files changed, 223 insertions(+), 8 deletions(-) create mode 100644 Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h index 11eef88b..ddc9fbe5 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h @@ -1,4 +1,4 @@ -/* + /* * CryptoDES.h * * Created on: 18.10.2016 @@ -35,7 +35,7 @@ PCD's side. typedef uint8_t Crypto2KTDEAKeyType[CRYPTO_2KTDEA_KEY_SIZE]; typedef uint8_t Crypto3KTDEAKeyType[CRYPTO_3KTDEA_KEY_SIZE]; -#define CRYPTO_DES_BLOCK_SIZE 8 /* Bytes */ +#define CRYPTO_DES_BLOCK_SIZE 8 /* Bytes */ #define CRYPTO_2KTDEA_BLOCK_SIZE (CRYPTO_DES_BLOCK_SIZE) #define CRYPTO_3KTDEA_BLOCK_SIZE (CRYPTO_DES_BLOCK_SIZE) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 313ba6a5..bbbaa7ab 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -1685,13 +1685,14 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { Buffer[0] = STATUS_PARAMETER_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } - /* Make sure that this key is AES, and figure out its byte size */ + /* Make sure that this key is 3DES, and figure out its byte size */ BYTE cryptoKeyType = ReadKeyCryptoType(SelectedApp.Slot, KeyId); if (!CryptoType3KTDEA(cryptoKeyType)) { Buffer[0] = STATUS_NO_SUCH_KEY; return DESFIRE_STATUS_RESPONSE_SIZE; } + /* The next calls just zero out the key buffers (not specific to AES): */ InitAESCryptoKeyData(&AESCryptoSessionKey); InitAESCryptoKeyData(&AESCryptoIVBuffer); @@ -1748,7 +1749,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; /* Validate command length */ - if (ByteCount != CRYPTO_AES_BLOCK_SIZE + 1) { + if (ByteCount != CRYPTO_DES_BLOCK_SIZE + 1) { Buffer[0] = STATUS_LENGTH_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 6cbc4c78..11ec4beb 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -163,7 +163,8 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { size_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; DesfireCmdCLA = Buffer[0]; if ((ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) || Iso7816CLA(DesfireCmdCLA)) { // Wrapped native command structure: + Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) || Iso7816CLA(DesfireCmdCLA)) { + // Wrapped native command structure: /* Unwrap the PDU from ISO 7816-4 */ // Check CRC bytes appended to the buffer: // -- Actually, just ignore parity problems if they exist, @@ -218,7 +219,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { } else if (ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 6) { // Native wrapped command send without CRCA checksum bytes appended: - return MifareDesfireProcess(Buffer, BitCount); + return MAX(0, MifareDesfireProcess(Buffer, BitCount) - 2 * BITS_PER_BYTE); } else if (IsWrappedISO7816CommandType(Buffer, ByteCount)) { uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], Buffer, 2); diff --git a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h index d2323085..9cd34992 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -124,6 +125,30 @@ static inline size_t DecryptAES128(const uint8_t *encSrcBuf, size_t bufSize, return bufSize; } +static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize, + uint8_t *encDestBuf, CryptoData_t cdata) { + DES_key_schedule keySched1, keySched2, keySched3; + DES_cblock IV; + DES_set_key(cdata.keyData, &keySched1); + DES_set_key(&cdata.keyData[8], &keySched2); + DES_set_key(&cdata.keyData[16], &keySched3); + memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + DES_ede3_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_ENCRYPT); + return bufSize; +} + +static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize, + uint8_t *plainDestBuf, CryptoData_t cdata) { + DES_key_schedule keySched1, keySched2, keySched3; + DES_cblock IV; + DES_set_key(cdata.keyData, &keySched1); + DES_set_key(&cdata.keyData[8], &keySched2); + DES_set_key(&cdata.keyData[16], &keySched3); + memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + DES_ede3_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_DECRYPT); + return bufSize; +} + static inline bool TestAESEncyptionRoutines(void) { fprintf(stdout, ">>> TestAESEncryptionRoutines [non-DESFire command]:\n"); const uint8_t keyData[] = { @@ -167,6 +192,49 @@ static inline bool TestAESEncyptionRoutines(void) { return status; } +static inline bool Test3DESEncyptionRoutines(void) { + fprintf(stdout, ">>> TestAESEncryptionRoutines [non-DESFire command]:\n"); + const uint8_t keyData[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + }; + const uint8_t ptData[] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF + }; + const uint8_t ctData[] = { + 0x3e, 0xf0, 0xa8, 0x91, 0xcf, 0x8e, 0xd9, 0x90, + 0xc4, 0x77, 0xeb, 0x09, 0x02, 0xf0, 0xc5, 0x4a + }; + CryptoData_t cdata; + cdata.keyData = keyData; + cdata.keySize = 3 * 8; + uint8_t pt[16], pt2[16], ct[16]; + Encrypt3DES(ptData, 16, ct, cdata); + Decrypt3DES(ct, 16, pt2, cdata); + fprintf(stdout, " -- : PT = "); print_hex(ptData, 16); + fprintf(stdout, " -- : CT = "); print_hex(ctData, 16); + fprintf(stdout, " -- : CT = "); print_hex(ct, 16); + fprintf(stdout, " -- : PT = "); print_hex(pt2, 16); + bool status = true; + if(memcmp(ct, ctData, 16)) { + fprintf(stdout, " -- CT does NOT match !!\n"); + status = false; + } + else { + fprintf(stdout, " -- CT matches.\n"); + } + if(memcmp(pt2, ptData, 16)) { + fprintf(stdout, " -- Decrypted PT from CT does NOT match !!\n"); + status = false; + } + else { + fprintf(stdout, " -- Decrypted PT from CT matches.\n"); + } + fprintf(stdout, "\n"); + return status; +} static inline int GenerateRandomBytes(uint8_t *destBuf, size_t numBytes) { return RAND_pseudo_bytes(destBuf, numBytes); } diff --git a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h index 1e5526e5..969c46a1 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h @@ -119,6 +119,108 @@ static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, c } } +static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, const uint8_t *keyData) { + + if(nfcConnDev == NULL || keyData == NULL) { + return INVALID_PARAMS_ERROR; + } + + // Start AES authentication (default key, blank setting of all zeros): + uint8_t AUTHENTICATE_ISO_CMD[] = { + 0x90, 0x1a, 0x00, 0x00, 0x01, 0x00, 0x00 + }; + AUTHENTICATE_ISO_CMD[5] = keyIndex; + if(PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, ">>> Start AES Authenticate:\n"); + fprintf(stdout, " -> "); + print_hex(AUTHENTICATE_ISO_CMD, sizeof(AUTHENTICATE_ISO_CMD)); + } + RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); + bool rxDataStatus = false; + rxDataStatus = libnfcTransmitBytes(nfcConnDev, AUTHENTICATE_ISO_CMD, sizeof(AUTHENTICATE_ISO_CMD), rxDataStorage); + if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " <- "); + print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); + } + else { + if(PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); + } + FreeRxDataStruct(rxDataStorage, true); + return EXIT_FAILURE; + } + + // Now need to decrypt the challenge response sent back as rndB (8 bytes), + // rotate it left, generate a random 8 byte rndA, concat rndA+rotatedRndB, + // encrypt this 16 byte result, and send it forth to the PICC: + uint8_t encryptedRndB[16], plainTextRndB[16], rotatedRndB[8]; + uint8_t rndA[8], challengeResponse[16], challengeResponseCipherText[16]; + int8_t IVBuf[16]; + memcpy(encryptedRndB, rxDataStorage->rxDataBuf, 16); + CryptoData_t desCryptoData = { 0 }; + desCryptoData.keySize = 8; + desCryptoData.keyData = keyData; + desCryptoData.ivSize = 8; + Decrypt3DES(encryptedRndB, 16, plainTextRndB, desCryptoData); + RotateArrayLeft(plainTextRndB, rotatedRndB, 8); + memset(IVBuf, 0x00, 16); + desCryptoData.ivData = IVBuf; + GenerateRandomBytes(rndA, 8); + ConcatByteArrays(rndA, 8, rotatedRndB, 8, challengeResponse); + Encrypt3DES(challengeResponse, 16, challengeResponseCipherText, desCryptoData); + + uint8_t sendBytesBuf[22]; + memset(sendBytesBuf, 0x00, 22); + sendBytesBuf[0] = 0x90; + sendBytesBuf[1] = 0xaf; + sendBytesBuf[4] = 0x10; + memcpy(sendBytesBuf + 5, challengeResponseCipherText, 16); + + if(PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " -- RNDA = "); print_hex(rndA, 8); + fprintf(stdout, " -- RNDB = "); print_hex(plainTextRndB, 8); + fprintf(stdout, " -- CHAL = "); print_hex(challengeResponse, 16); + fprintf(stdout, " -> "); + print_hex(sendBytesBuf, sizeof(sendBytesBuf)); + } + rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 22, rxDataStorage); + if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " <- "); + print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); + } + else { + if(PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); + } + FreeRxDataStruct(rxDataStorage, true); + return EXIT_FAILURE; + } + + // Finally, to finish up the auth process: + // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, + // and report back whether they match: + uint8_t decryptedRndAFromPICCRotated[16], decryptedRndA[16]; + Decrypt3DES(rxDataStorage->rxDataBuf, 16, decryptedRndAFromPICCRotated, desCryptoData); + RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, 8); + if(!memcmp(rndA, decryptedRndA, 8)) { + if(PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " ... AUTH OK! :)\n\n"); + } + AUTHENTICATED = true; + AUTHENTICATED_PROTO = DESFIRE_CRYPTO_AUTHTYPE_ISODES; + memcpy(CRYPTO_RNDB_STATE, plainTextRndB, 8); + FreeRxDataStruct(rxDataStorage, true); + return EXIT_SUCCESS; + } + else { + if(PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " ... AUTH FAILED -- X; :(\n\n"); + } + FreeRxDataStruct(rxDataStorage, true); + return EXIT_FAILURE; + } +} + static inline int Authenticate(nfc_device *nfcConnDev, int authType, uint8_t keyIndex, const uint8_t *keyData) { InvalidateAuthState(); if(nfcConnDev == NULL || keyData == NULL) { @@ -127,7 +229,9 @@ static inline int Authenticate(nfc_device *nfcConnDev, int authType, uint8_t key switch(authType) { case DESFIRE_CRYPTO_AUTHTYPE_AES128: return AuthenticateAES128(nfcConnDev, keyIndex, keyData); - default: + case DESFIRE_CRYPTO_AUTHTYPE_ISODES: + return AuthenticateISO(nfcConnDev, keyIndex, keyData); + default: break; } return EXIT_FAILURE; diff --git a/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h b/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h index 41d20f1f..530adb94 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h @@ -39,7 +39,7 @@ static inline nfc_device * GetNFCDeviceDriver(nfc_context **context) { return NULL; } // Configure some convenient common settings: - nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false); + //nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false); nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true); nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, true); diff --git a/Software/DESFireLibNFCTesting/Makefile b/Software/DESFireLibNFCTesting/Makefile index 83c587cd..86b5db4c 100644 --- a/Software/DESFireLibNFCTesting/Makefile +++ b/Software/DESFireLibNFCTesting/Makefile @@ -28,6 +28,7 @@ LIBNFC_SUPPORTED_DRIVERS= -DDRIVER_PN53X_USB_ENABLED \ -DDRIVER_PN532_SPI_ENABLED \ -DDRIVER_PN532_I2C_ENABLED \ -DDRIVER_PN71XX_ENABLED +#LIBNFC_SUPPORTED_DRIVERS= -DDRIVER_ACR122_PCSC_ENABLED LIBNFC_CUSTOM_CONFIG= -DLIBNFC_LOGLEVEL=NFC_LOG_PRIORITY_DEBUG \ -ULOG_CATEGORY -DLOG_CATEGORY=\"DESFireTesting.libnfc.general\" \ -ULOG_GROUP -DLOG_GROUP=NFC_LOG_GROUP_GENERAL @@ -35,6 +36,7 @@ CFLAGS+= $(LIBNFC_SUPPORTED_DRIVERS) $(LIBNFC_CUSTOM_CONFIG) FILE_BASENAMES=NFCAntiCollisionMod \ TestAuthenticateAES128 \ + TestAuthenticateISO \ TestGeneralCommands \ TestKeyManagementCommands \ TestApplicationManagementCommands \ diff --git a/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c b/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c new file mode 100644 index 00000000..d4435b60 --- /dev/null +++ b/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c @@ -0,0 +1,39 @@ +/* TestAuthenticateAES128.c */ + +#include "LibNFCUtils.h" +#include "LibNFCWrapper.h" +#include "DesfireUtils.h" +#include "CryptoUtils.h" + +/* + * See Notes: https://stackoverflow.com/questions/52520044/desfire-ev1-communication-how-to-assign-iv + */ + +int main(int argc, char **argv) { + + if(!Test3DESEncyptionRoutines()) { + return EXIT_FAILURE; + } + + nfc_context *nfcCtxt; + nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); + if(nfcPnd == NULL) { + return EXIT_FAILURE; + } + + // Select AID application 0x000000: + if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + return EXIT_FAILURE; + } + + // Start AES authentication (default key, blank setting of all zeros): + if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_ISODES, + MASTER_KEY_INDEX, ZERO_KEY)) { + return EXIT_FAILURE; + } + + FreeNFCDeviceDriver(&nfcCtxt, &nfcPnd); + return EXIT_SUCCESS; + +} + From 1e542ecf69522913b53db3113f035161c8217f04 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sun, 30 Jan 2022 14:53:16 -0500 Subject: [PATCH 02/68] Re-implementing the 3DES crypto with CBC --- .../Chameleon-Mini/Application/CryptoTDEA.c | 54 +++++++++++++++++++ .../DESFire/DESFireApplicationDirectory.h | 2 +- .../Application/DESFire/DESFireCrypto.c | 3 ++ .../Application/DESFire/DESFireInstructions.c | 11 ++-- .../DESFire/DESFirePICCHeaderLayout.h | 2 +- .../Application/MifareDESFire.c | 1 + .../LocalInclude/DesfireUtils.h | 2 +- .../Source/TestAuthenticateISO.c | 6 +-- 8 files changed, 69 insertions(+), 12 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c index a25f8973..62683d24 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c @@ -41,6 +41,8 @@ void DecryptDESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, c } } +/* OLD: 3DES ECB (Now done with CBC): */ +#if 0 void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *Keys) { CryptoTDEA_CBCSpec CryptoSpec = { .cryptFunc = &CryptoEncrypt3KTDEA, @@ -72,3 +74,55 @@ void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, blockIndex++; } } +#endif + +#include +#include "CryptoAES128.h" + +void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *Keys) { + CryptoTDEA_CBCSpec CryptoSpec = { + .cryptFunc = &CryptoEncrypt3KTDEA, + .blockSize = CRYPTO_3KTDEA_BLOCK_SIZE + }; + uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; + uint8_t *ctBuf = (uint8_t *) Ciphertext; + uint16_t blockIndex = 0; + uint8_t inputBlock[CRYPTO_3KTDEA_BLOCK_SIZE]; + uint8_t IV[CRYPTO_3KTDEA_BLOCK_SIZE]; + memset(IV, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); + while (blockIndex < numBlocks) { + if (blockIndex == 0) { + memcpy(inputBlock, &Plaintext[0], CRYPTO_3KTDEA_BLOCK_SIZE); + CryptoMemoryXOR(IV, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); + } else { + memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], CRYPTO_3KTDEA_BLOCK_SIZE); + CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE], inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); + } + CryptoSpec.cryptFunc(inputBlock, ctBuf, Keys); + ctBuf += CryptoSpec.blockSize; + blockIndex++; + } +} + +void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *Keys) { + CryptoTDEA_CBCSpec CryptoSpec = { + .cryptFunc = &CryptoDecrypt3KTDEA, + .blockSize = CRYPTO_3KTDEA_BLOCK_SIZE + }; + uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; + uint16_t blockIndex = 0; + uint8_t inputBlock[CRYPTO_3KTDEA_BLOCK_SIZE]; + uint8_t IV[CRYPTO_3KTDEA_BLOCK_SIZE]; + memset(IV, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); + while (blockIndex < numBlocks) { + CryptoSpec.cryptFunc(inputBlock, Ciphertext + blockIndex, Keys); + if (blockIndex == 0) { + memcpy(Plaintext, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); + CryptoMemoryXOR(IV, Plaintext, CRYPTO_3KTDEA_BLOCK_SIZE); + } else { + memcpy(Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); + CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, CRYPTO_3KTDEA_BLOCK_SIZE); + } + blockIndex++; + } +} diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h index 1f1424aa..0eb201bb 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h @@ -43,7 +43,7 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_MAX_APPS (28) #endif -#define DESFIRE_MAX_SLOTS (DESFIRE_MAX_APPS + 1) +#define DESFIRE_MAX_SLOTS (DESFIRE_MAX_APPS + 1) #if defined(DESFIRE_MEMORY_LIMITED_TESTING) && !defined(DESFIRE_CUSTOM_MAX_FILES) #define DESFIRE_MAX_FILES (6) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c index 5d29b96b..e4a30395 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c @@ -140,7 +140,10 @@ BYTE GetCryptoKeyTypeFromAuthenticateMethod(BYTE authCmdMethod) { void InitAESCryptoKeyData(DesfireAESCryptoKey *cryptoKeyData) { memset(cryptoKeyData, 0x00, sizeof(DesfireAESCryptoKey)); + memset(&SessionKey[0], 0x00, CRYPTO_MAX_KEY_SIZE); + memset(&SessionIV[0], 0x00, CRYPTO_MAX_BLOCK_SIZE); } + uint8_t CryptoAESTransferEncryptSend(uint8_t *Buffer, uint8_t Count, const uint8_t *Key) { uint8_t AvailablePlaintext = TransferState.ReadData.Encryption.AvailablePlaintext; uint8_t TempBuffer[(DESFIRE_MAX_PAYLOAD_AES_BLOCKS + 1) * CRYPTO_DES_BLOCK_SIZE]; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index bbbaa7ab..be559612 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -1693,8 +1693,8 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { } /* The next calls just zero out the key buffers (not specific to AES): */ - InitAESCryptoKeyData(&AESCryptoSessionKey); - InitAESCryptoKeyData(&AESCryptoIVBuffer); + //InitAESCryptoKeyData(&SessionKey); + //InitAESCryptoKeyData(&SessionIV); keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); Key = &SessionKey; @@ -1749,12 +1749,13 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; /* Validate command length */ - if (ByteCount != CRYPTO_DES_BLOCK_SIZE + 1) { + if (ByteCount != CRYPTO_3KTDEA_BLOCK_SIZE + 1) { Buffer[0] = STATUS_LENGTH_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } /* Reset parameters for authentication from the first exchange */ + Key = &SessionKey; KeyId = DesfireCommandState.KeyId; cryptoKeyType = DesfireCommandState.CryptoMethodType; keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); @@ -1772,7 +1773,8 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Check that the returned RndB matches what we sent in the previous round */ if (memcmp(DesfireCommandState.RndB, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES)) { - Buffer[0] = STATUS_AUTHENTICATION_ERROR; + LogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, (const void *) challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + Buffer[0] = STATUS_AUTHENTICATION_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } @@ -1890,6 +1892,7 @@ uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount) { } /* Reset parameters for authentication from the first exchange */ + Key = &AESCryptoSessionKey; keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_AES128); KeyId = DesfireCommandState.KeyId; cryptoKeyType = DesfireCommandState.CryptoMethodType; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index 72dc158d..ba5c2142 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -37,7 +37,7 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_ISO7816_CLA 0x00 /* Storage allocation constants */ -#define DESFIRE_EEPROM_BLOCK_SIZE 16 //32 /* Bytes */ +#define DESFIRE_EEPROM_BLOCK_SIZE 32 // 16 /* Bytes */ #define DESFIRE_BYTES_TO_BLOCKS(x) \ ( ((x) + DESFIRE_EEPROM_BLOCK_SIZE - 1) / DESFIRE_EEPROM_BLOCK_SIZE ) diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 11ec4beb..4df4940f 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -121,6 +121,7 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { /* Expecting further data here */ if (Buffer[0] != STATUS_ADDITIONAL_FRAME) { + DesfireState = DESFIRE_IDLE; return ISO14443A_APP_NO_RESPONSE; } diff --git a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h index 969c46a1..11db5518 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h @@ -131,7 +131,7 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons }; AUTHENTICATE_ISO_CMD[5] = keyIndex; if(PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, ">>> Start AES Authenticate:\n"); + fprintf(stdout, ">>> Start ISO Authenticate:\n"); fprintf(stdout, " -> "); print_hex(AUTHENTICATE_ISO_CMD, sizeof(AUTHENTICATE_ISO_CMD)); } diff --git a/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c b/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c index d4435b60..fb5a0482 100644 --- a/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c +++ b/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c @@ -5,10 +5,6 @@ #include "DesfireUtils.h" #include "CryptoUtils.h" -/* - * See Notes: https://stackoverflow.com/questions/52520044/desfire-ev1-communication-how-to-assign-iv - */ - int main(int argc, char **argv) { if(!Test3DESEncyptionRoutines()) { @@ -26,7 +22,7 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } - // Start AES authentication (default key, blank setting of all zeros): + // Start ISO authentication (default key, blank setting of all zeros): if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_ISODES, MASTER_KEY_INDEX, ZERO_KEY)) { return EXIT_FAILURE; From d20cac46c29fb90fa87e06429dfa9040323c9b0b Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sun, 30 Jan 2022 15:45:27 -0500 Subject: [PATCH 03/68] More testing (still doesn't make it through round2 on the Chameleon) --- Firmware/Chameleon-Mini/Application/CryptoTDEA.c | 3 ++- .../Chameleon-Mini/Application/DESFire/DESFireInstructions.c | 2 +- Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h | 4 ++-- Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c | 4 ++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c index 62683d24..734aa237 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c @@ -121,7 +121,8 @@ void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, CryptoMemoryXOR(IV, Plaintext, CRYPTO_3KTDEA_BLOCK_SIZE); } else { memcpy(Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); - CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, CRYPTO_3KTDEA_BLOCK_SIZE); + CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], + Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, CRYPTO_3KTDEA_BLOCK_SIZE); } blockIndex++; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index be559612..665e32b5 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -1749,7 +1749,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; /* Validate command length */ - if (ByteCount != CRYPTO_3KTDEA_BLOCK_SIZE + 1) { + if (ByteCount != 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES + 1) { Buffer[0] = STATUS_LENGTH_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } diff --git a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h index 9cd34992..d29f8aba 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h @@ -128,7 +128,7 @@ static inline size_t DecryptAES128(const uint8_t *encSrcBuf, size_t bufSize, static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize, uint8_t *encDestBuf, CryptoData_t cdata) { DES_key_schedule keySched1, keySched2, keySched3; - DES_cblock IV; + uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; DES_set_key(cdata.keyData, &keySched1); DES_set_key(&cdata.keyData[8], &keySched2); DES_set_key(&cdata.keyData[16], &keySched3); @@ -140,7 +140,7 @@ static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize, static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize, uint8_t *plainDestBuf, CryptoData_t cdata) { DES_key_schedule keySched1, keySched2, keySched3; - DES_cblock IV; + uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; DES_set_key(cdata.keyData, &keySched1); DES_set_key(&cdata.keyData[8], &keySched2); DES_set_key(&cdata.keyData[16], &keySched3); diff --git a/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c b/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c index fb5a0482..04a7f82d 100644 --- a/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c +++ b/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c @@ -22,6 +22,10 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } + // Get list of application IDs: + if(GetApplicationIds(nfcPnd)) { + return EXIT_FAILURE; + } // Start ISO authentication (default key, blank setting of all zeros): if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_ISODES, MASTER_KEY_INDEX, ZERO_KEY)) { From 6ee19583512fd946a85521b7811603d5fb057d88 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sun, 30 Jan 2022 23:03:07 -0500 Subject: [PATCH 04/68] AuthISO(0x1A) works tentatively (a little slowly) with the LibNFC test code --- .../Chameleon-Mini/Application/CryptoTDEA.c | 18 ++-- .../Chameleon-Mini/Application/CryptoTDEA.h | 4 +- .../Application/DESFire/DESFireInstructions.c | 12 +-- Firmware/Chameleon-Mini/Makefile | 7 +- .../Chameleon-Mini/Tests/ChameleonTerminal.c | 11 ++- Firmware/Chameleon-Mini/Tests/CryptoTests.c | 50 +++++++++++ Firmware/Chameleon-Mini/Tests/CryptoTests.h | 9 ++ .../LocalInclude/CryptoUtils.h | 85 +++++++++++++------ .../LocalInclude/DesfireUtils.h | 6 +- .../LocalInclude/LibNFCWrapper.h | 14 ++- Software/DESFireLibNFCTesting/Makefile | 1 - .../Source/TestAuthenticateISO.c | 4 +- 12 files changed, 167 insertions(+), 54 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c index 734aa237..7b0613c9 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c @@ -79,7 +79,7 @@ void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, #include #include "CryptoAES128.h" -void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *Keys) { +void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { CryptoTDEA_CBCSpec CryptoSpec = { .cryptFunc = &CryptoEncrypt3KTDEA, .blockSize = CRYPTO_3KTDEA_BLOCK_SIZE @@ -89,7 +89,11 @@ void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, uint16_t blockIndex = 0; uint8_t inputBlock[CRYPTO_3KTDEA_BLOCK_SIZE]; uint8_t IV[CRYPTO_3KTDEA_BLOCK_SIZE]; - memset(IV, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); + if (IVIn == NULL) { + memset(IV, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, CRYPTO_3KTDEA_BLOCK_SIZE); + } while (blockIndex < numBlocks) { if (blockIndex == 0) { memcpy(inputBlock, &Plaintext[0], CRYPTO_3KTDEA_BLOCK_SIZE); @@ -104,7 +108,7 @@ void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, } } -void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *Keys) { +void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { CryptoTDEA_CBCSpec CryptoSpec = { .cryptFunc = &CryptoDecrypt3KTDEA, .blockSize = CRYPTO_3KTDEA_BLOCK_SIZE @@ -113,9 +117,13 @@ void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, uint16_t blockIndex = 0; uint8_t inputBlock[CRYPTO_3KTDEA_BLOCK_SIZE]; uint8_t IV[CRYPTO_3KTDEA_BLOCK_SIZE]; - memset(IV, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); + if (IVIn == NULL) { + memset(IV, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, CRYPTO_3KTDEA_BLOCK_SIZE); + } while (blockIndex < numBlocks) { - CryptoSpec.cryptFunc(inputBlock, Ciphertext + blockIndex, Keys); + CryptoSpec.cryptFunc(inputBlock, Ciphertext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, Keys); if (blockIndex == 0) { memcpy(Plaintext, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); CryptoMemoryXOR(IV, Plaintext, CRYPTO_3KTDEA_BLOCK_SIZE); diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h index ddc9fbe5..8de08b6e 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h @@ -60,8 +60,8 @@ void CryptoDecrypt2KTDEA(const void *Plaintext, void *Ciphertext, const uint8_t void CryptoEncrypt3KTDEA(void *Plaintext, void *Ciphertext, const uint8_t *Keys); void CryptoDecrypt3KTDEA(void *Plaintext, void *Ciphertext, const uint8_t *Keys); -void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *Keys); -void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *Keys); +void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IV, const uint8_t *Keys); +void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IV, const uint8_t *Keys); /** Performs the 2-key Triple DES en/deciphering in the CBC "send" mode (xor-then-crypt) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 665e32b5..57a5c3ed 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -452,7 +452,7 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { LogEntry(LOG_APP_AUTH_KEY, (const void *) *Key, keySize); /* Generate the nonce B (RndB / Challenge response) */ - if (LocalTestingMode != 0) { + if (LocalTestingMode == 0) { RandomGetBuffer(DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); } else { /* Fixed nonce for testing */ @@ -1709,7 +1709,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { LogEntry(LOG_APP_AUTH_KEY, (const void *) *Key, keySize); /* Generate the nonce B (RndB / Challenge response) */ - if (LocalTestingMode != 0) { + if (LocalTestingMode == 0) { RandomGetBuffer(DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); } else { /* Fixed nonce for testing */ @@ -1729,7 +1729,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { memset(rndBPadded, 0x00, CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(rndBPadded, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, rndBPadded, - &Buffer[1], *Key); + &Buffer[1], NULL, *Key); /* Scrub the key */ memset(*Key, 0, keySize); @@ -1766,7 +1766,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { BYTE challengeRndA[CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndB[CRYPTO_CHALLENGE_RESPONSE_BYTES]; Decrypt3DESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, - &Buffer[1], *Key); + &Buffer[1], NULL, *Key); RotateArrayRight(challengeRndAB + CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); @@ -1787,7 +1787,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Encrypt and send back the once rotated RndA buffer to the PCD */ RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, - &Buffer[1], *Key); + &Buffer[1], NULL, *Key); /* Scrub the key */ memset(*Key, 0, keySize); @@ -1843,7 +1843,7 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { CryptoAESInitContext(&AESCryptoContext); /* Generate the nonce B (RndB / Challenge response) */ - if (LocalTestingMode != 0) { + if (LocalTestingMode == 0) { RandomGetBuffer(&(DesfireCommandState.RndB[0]), CRYPTO_CHALLENGE_RESPONSE_BYTES); } else { /* Fixed nonce for testing */ diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 3c55cb97..986e175b 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -81,6 +81,9 @@ SETTINGS += -DENABLE_EEPROM_SETTINGS #Enable tests for DES/2KTDEA/3DES/AES128 crypto schemes: #SETTINGS += -DENABLE_CRYPTO_TESTS +#SETTINGS += -DENABLE_CRYPTO_TDEA_TESTS +#SETTINGS += -DENABLE_CRYPTO_3DES_TESTS +#SETTINGS += -DENABLE_CRYPTO_AES_TESTS #Enable a command to run any tests added by developers, e.g., the #crypto scheme tests that can be enabled above: @@ -97,8 +100,8 @@ SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING #SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF #Set a default testing mode setting (0 = OFF, non-NULL = ON): -SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 -#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 +#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 +SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 #Feature: Use randomized UIDs that mask the actual secret UID until #the tag has been issued a successful authentication sequence: diff --git a/Firmware/Chameleon-Mini/Tests/ChameleonTerminal.c b/Firmware/Chameleon-Mini/Tests/ChameleonTerminal.c index a4584025..c55c41f9 100644 --- a/Firmware/Chameleon-Mini/Tests/ChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Tests/ChameleonTerminal.c @@ -8,10 +8,17 @@ CommandStatusIdType CommandRunTests(char *OutParam) { const ChameleonTestType testCases[] = { #ifdef ENABLE_CRYPTO_TESTS - &CryptoTDEATestCase1, +#ifdef ENABLE_CRYPTO_TDEA_TESTS + &CryptoTDEATestCase1, &CryptoTDEATestCase2, - &CryptoAESTestCase1, +#endif +#ifdef ENABLE_CRYPTO_3DES_TESTS + &Crypto3DESTestCase1, +#endif +#ifdef ENABLE_CRYPTO_AES_TESTS + &CryptoAESTestCase1, &CryptoAESTestCase2, +#endif #endif }; uint32_t t; diff --git a/Firmware/Chameleon-Mini/Tests/CryptoTests.c b/Firmware/Chameleon-Mini/Tests/CryptoTests.c index bb4e41f9..5ce35fdf 100644 --- a/Firmware/Chameleon-Mini/Tests/CryptoTests.c +++ b/Firmware/Chameleon-Mini/Tests/CryptoTests.c @@ -4,6 +4,7 @@ #include "CryptoTests.h" +#ifdef ENABLE_CRYPTO_TDEA_TESTS bool CryptoTDEATestCase1(char *OutParam, uint16_t MaxOutputLength) { const uint8_t ZeroBlock[CRYPTO_DES_BLOCK_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -53,7 +54,55 @@ bool CryptoTDEATestCase2(char *OutParam, uint16_t MaxOutputLength) { } return true; } +#endif +#ifdef ENABLE_CRYPTO_3DES_TESTS +// Data from: +// https://boringssl.googlesource.com/boringssl/+/2490/crypto/cipher/test/cipher_test.txt#33 +bool Crypto3DESTestCase1(char *OutParam, uint16_t MaxOutputLength) { + const uint8_t KeyData[3 * CRYPTO_DES_BLOCK_SIZE] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xf1, 0xe0, 0xd3, 0xc2, 0xb5, 0xa4, 0x97, 0x86, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 + }; + const uint8_t PlainText[4 * CRYPTO_DES_BLOCK_SIZE] = { + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20, + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x00, 0x00, 0x00, 0x00 + }; + const uint8_t CipherText[4 * CRYPTO_DES_BLOCK_SIZE] = { + 0x3F, 0xE3, 0x01, 0xC9, 0x62, 0xAC, 0x01, 0xD0, + 0x22, 0x13, 0x76, 0x3C, 0x1C, 0xBD, 0x4C, 0xDC, + 0x79, 0x96, 0x57, 0xC0, 0x64, 0xEC, 0xF5, 0xD4, + 0x1C, 0x67, 0x38, 0x12, 0xCF, 0xDE, 0x96, 0x75 + }; + const uint8_t IV[CRYPTO_DES_BLOCK_SIZE] = { + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 + }; + uint8_t tempBuffer[4 * CRYPTO_DES_BLOCK_SIZE]; + uint16_t dataBytes = 4 * CRYPTO_DES_BLOCK_SIZE; + Encrypt3DESBuffer(dataBytes, PlainText, tempBuffer, IV, KeyData); + if (memcmp(tempBuffer, CipherText, dataBytes)) { + strcat_P(OutParam, PSTR("> ENC: ")); + OutParam += 7; + BufferToHexString(OutParam, MaxOutputLength - 7, tempBuffer, dataBytes); + strcat_P(OutParam, PSTR("\r\n")); + return false; + } + Decrypt3DESBuffer(dataBytes, tempBuffer, CipherText, IV, KeyData); + if (memcmp(tempBuffer, PlainText, dataBytes)) { + strcat_P(OutParam, PSTR("> DEC: ")); + OutParam += 7; + BufferToHexString(OutParam, MaxOutputLength - 7, tempBuffer, dataBytes); + strcat_P(OutParam, PSTR("\r\n")); + return false; + } + return true; +} +#endif + +#ifdef ENABLE_CRYPTO_AES_TESTS bool CryptoAESTestCase1(char *OutParam, uint16_t MaxOutputLength) { // Key from FIPS-197: 00010203 04050607 08090A0B 0C0D0E0 const uint8_t KeyData[CRYPTO_AES_KEY_SIZE] = { @@ -136,5 +185,6 @@ bool CryptoAESTestCase2(char *OutParam, uint16_t MaxOutputLength) { } return true; } +#endif #endif /* ENABLE_CRYPTO_TESTS */ diff --git a/Firmware/Chameleon-Mini/Tests/CryptoTests.h b/Firmware/Chameleon-Mini/Tests/CryptoTests.h index 1900ce31..4e5f1630 100644 --- a/Firmware/Chameleon-Mini/Tests/CryptoTests.h +++ b/Firmware/Chameleon-Mini/Tests/CryptoTests.h @@ -17,14 +17,22 @@ /* DES crypto test cases: */ +#ifdef ENABLE_CRYPTO_TDEA_TESTS /* Test 2KTDEA encryption, ECB mode: */ bool CryptoTDEATestCase1(char *OutParam, uint16_t MaxOutputLength); /* Test 2KTDEA encryption, CBC receive mode: */ bool CryptoTDEATestCase2(char *OutParam, uint16_t MaxOutputLength); +#endif + +#ifdef ENABLE_CRYPTO_3DES_TESTS +/* Test 3DES encryption, CBC for DESFire AuthISO (0x1a): */ +bool Crypto3DESTestCase1(char *OutParam, uint16_t MaxOutputLength); +#endif /* AES-128 crypto test cases: */ +#ifdef ENABLE_CRYPTO_AES_TESTS /* Test AES-128 encrypt/decrypt for a single block (ECB mode): */ bool CryptoAESTestCase1(char *OutParam, uint16_t MaxOutputLength); @@ -32,6 +40,7 @@ bool CryptoAESTestCase1(char *OutParam, uint16_t MaxOutputLength); * Adapted from: https://github.com/eewiki/asf/blob/master/xmega/drivers/aes/example2/aes_example2.c */ bool CryptoAESTestCase2(char *OutParam, uint16_t MaxOutputLength); +#endif #endif /* __CRYPTO_TESTS_H__ */ diff --git a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h index d29f8aba..153c1c4b 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h @@ -126,25 +126,35 @@ static inline size_t DecryptAES128(const uint8_t *encSrcBuf, size_t bufSize, } static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize, - uint8_t *encDestBuf, CryptoData_t cdata) { + uint8_t *encDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { DES_key_schedule keySched1, keySched2, keySched3; uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; - DES_set_key(cdata.keyData, &keySched1); - DES_set_key(&cdata.keyData[8], &keySched2); - DES_set_key(&cdata.keyData[16], &keySched3); - memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[8]), *kd3 = &(cdata.keyData[16]); + DES_set_key(kd1, &keySched1); + DES_set_key(kd2, &keySched2); + DES_set_key(kd3, &keySched3); + if (IVIn == NULL) { + memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + } DES_ede3_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_ENCRYPT); return bufSize; } static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize, - uint8_t *plainDestBuf, CryptoData_t cdata) { + uint8_t *plainDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { DES_key_schedule keySched1, keySched2, keySched3; uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; - DES_set_key(cdata.keyData, &keySched1); - DES_set_key(&cdata.keyData[8], &keySched2); - DES_set_key(&cdata.keyData[16], &keySched3); - memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[8]), *kd3 = &(cdata.keyData[16]); + DES_set_key(kd1, &keySched1); + DES_set_key(kd2, &keySched2); + DES_set_key(kd3, &keySched3); + if (IVIn == NULL) { + memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + } DES_ede3_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_DECRYPT); return bufSize; } @@ -194,38 +204,59 @@ static inline bool TestAESEncyptionRoutines(void) { static inline bool Test3DESEncyptionRoutines(void) { fprintf(stdout, ">>> TestAESEncryptionRoutines [non-DESFire command]:\n"); - const uint8_t keyData[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + //const uint8_t keyData[] = { + // 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + // 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + // 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + //}; + //const uint8_t ptData[] = { + // 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + // 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF + //}; + //const uint8_t ctData[] = { + // 0x3e, 0xf0, 0xa8, 0x91, 0xcf, 0x8e, 0xd9, 0x90, + // 0xc4, 0x77, 0xeb, 0x09, 0x02, 0xf0, 0xc5, 0x4a + //}; + const uint8_t keyData[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xf1, 0xe0, 0xd3, 0xc2, 0xb5, 0xa4, 0x97, 0x86, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }; const uint8_t ptData[] = { - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20, + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x00, 0x00, 0x00, 0x00 }; const uint8_t ctData[] = { - 0x3e, 0xf0, 0xa8, 0x91, 0xcf, 0x8e, 0xd9, 0x90, - 0xc4, 0x77, 0xeb, 0x09, 0x02, 0xf0, 0xc5, 0x4a + 0x3F, 0xE3, 0x01, 0xC9, 0x62, 0xAC, 0x01, 0xD0, + 0x22, 0x13, 0x76, 0x3C, 0x1C, 0xBD, 0x4C, 0xDC, + 0x79, 0x96, 0x57, 0xC0, 0x64, 0xEC, 0xF5, 0xD4, + 0x1C, 0x67, 0x38, 0x12, 0xCF, 0xDE, 0x96, 0x75 + }; + const uint8_t IV[] = { + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }; CryptoData_t cdata; cdata.keyData = keyData; cdata.keySize = 3 * 8; - uint8_t pt[16], pt2[16], ct[16]; - Encrypt3DES(ptData, 16, ct, cdata); - Decrypt3DES(ct, 16, pt2, cdata); - fprintf(stdout, " -- : PT = "); print_hex(ptData, 16); - fprintf(stdout, " -- : CT = "); print_hex(ctData, 16); - fprintf(stdout, " -- : CT = "); print_hex(ct, 16); - fprintf(stdout, " -- : PT = "); print_hex(pt2, 16); + const uint16_t testDataSize = 4 * 8; + uint8_t pt[testDataSize], ct[testDataSize]; + Encrypt3DES(ptData, testDataSize, ct, IV, cdata); + Decrypt3DES(ctData, testDataSize, pt, IV, cdata); + fprintf(stdout, " -- : PT [FIXED] = "); print_hex(ptData, testDataSize); + fprintf(stdout, " -- : CT [FIXED] = "); print_hex(ctData, testDataSize); + fprintf(stdout, " -- : CT [ENC] = "); print_hex(ct, testDataSize); + fprintf(stdout, " -- : PT [DEC] = "); print_hex(pt, testDataSize); bool status = true; - if(memcmp(ct, ctData, 16)) { + if(memcmp(ct, ctData, testDataSize)) { fprintf(stdout, " -- CT does NOT match !!\n"); status = false; } else { fprintf(stdout, " -- CT matches.\n"); } - if(memcmp(pt2, ptData, 16)) { + if(memcmp(pt, ptData, testDataSize)) { fprintf(stdout, " -- Decrypted PT from CT does NOT match !!\n"); status = false; } diff --git a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h index 11db5518..591e32e7 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h @@ -161,13 +161,13 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons desCryptoData.keySize = 8; desCryptoData.keyData = keyData; desCryptoData.ivSize = 8; - Decrypt3DES(encryptedRndB, 16, plainTextRndB, desCryptoData); + Decrypt3DES(encryptedRndB, 16, plainTextRndB, NULL, desCryptoData); RotateArrayLeft(plainTextRndB, rotatedRndB, 8); memset(IVBuf, 0x00, 16); desCryptoData.ivData = IVBuf; GenerateRandomBytes(rndA, 8); ConcatByteArrays(rndA, 8, rotatedRndB, 8, challengeResponse); - Encrypt3DES(challengeResponse, 16, challengeResponseCipherText, desCryptoData); + Encrypt3DES(challengeResponse, 16, challengeResponseCipherText, NULL, desCryptoData); uint8_t sendBytesBuf[22]; memset(sendBytesBuf, 0x00, 22); @@ -200,7 +200,7 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, // and report back whether they match: uint8_t decryptedRndAFromPICCRotated[16], decryptedRndA[16]; - Decrypt3DES(rxDataStorage->rxDataBuf, 16, decryptedRndAFromPICCRotated, desCryptoData); + Decrypt3DES(rxDataStorage->rxDataBuf, 16, decryptedRndAFromPICCRotated, NULL, desCryptoData); RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, 8); if(!memcmp(rndA, decryptedRndA, 8)) { if(PRINT_STATUS_EXCHANGE_MESSAGES) { diff --git a/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h b/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h index 530adb94..c4dba322 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h @@ -30,16 +30,18 @@ static inline nfc_device * GetNFCDeviceDriver(nfc_context **context) { if(pnd == NULL) { ERR("Error opening NFC reader"); nfc_exit(context); - return NULL; + *context = NULL; + return NULL; } if(nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); nfc_close(pnd); nfc_exit(context); + *context = NULL; return NULL; } // Configure some convenient common settings: - //nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false); + nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false); nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true); nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, true); @@ -50,8 +52,12 @@ static inline nfc_device * GetNFCDeviceDriver(nfc_context **context) { } static inline void FreeNFCDeviceDriver(nfc_context **context, nfc_device **device) { - nfc_close(*device); - nfc_exit(*context); + if (*device != NULL) { + nfc_close(*device); + } + if (*context != NULL) { + nfc_exit(*context); + } } #endif diff --git a/Software/DESFireLibNFCTesting/Makefile b/Software/DESFireLibNFCTesting/Makefile index 86b5db4c..389d5e62 100644 --- a/Software/DESFireLibNFCTesting/Makefile +++ b/Software/DESFireLibNFCTesting/Makefile @@ -28,7 +28,6 @@ LIBNFC_SUPPORTED_DRIVERS= -DDRIVER_PN53X_USB_ENABLED \ -DDRIVER_PN532_SPI_ENABLED \ -DDRIVER_PN532_I2C_ENABLED \ -DDRIVER_PN71XX_ENABLED -#LIBNFC_SUPPORTED_DRIVERS= -DDRIVER_ACR122_PCSC_ENABLED LIBNFC_CUSTOM_CONFIG= -DLIBNFC_LOGLEVEL=NFC_LOG_PRIORITY_DEBUG \ -ULOG_CATEGORY -DLOG_CATEGORY=\"DESFireTesting.libnfc.general\" \ -ULOG_GROUP -DLOG_GROUP=NFC_LOG_GROUP_GENERAL diff --git a/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c b/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c index 04a7f82d..c843235d 100644 --- a/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c +++ b/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c @@ -1,4 +1,4 @@ -/* TestAuthenticateAES128.c */ +/* TestAuthenticateISO.c */ #include "LibNFCUtils.h" #include "LibNFCWrapper.h" @@ -14,7 +14,7 @@ int main(int argc, char **argv) { nfc_context *nfcCtxt; nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); if(nfcPnd == NULL) { - return EXIT_FAILURE; + return EXIT_FAILURE; } // Select AID application 0x000000: From 195e60018cadf5e6060bbfdaddc6122fd36c901d Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Mon, 31 Jan 2022 01:22:07 -0500 Subject: [PATCH 05/68] AuthLegacy(0x0A) works using 3DES enc/dec modes --- .../Chameleon-Mini/Application/CryptoTDEA.c | 90 +++++++-------- .../Chameleon-Mini/Application/CryptoTDEA.h | 4 +- .../Application/DESFire/DESFireInstructions.c | 29 +++-- .../LocalInclude/CryptoUtils.h | 90 ++++++++++++--- .../LocalInclude/DesfireUtils.h | 105 +++++++++++++++++- .../LocalInclude/LibNFCWrapper.h | 2 +- Software/DESFireLibNFCTesting/Makefile | 1 + .../Source/TestAuthenticateLegacy.c | 39 +++++++ 8 files changed, 274 insertions(+), 86 deletions(-) create mode 100644 Software/DESFireLibNFCTesting/Source/TestAuthenticateLegacy.c diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c index 7b0613c9..97f1b3af 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c @@ -2,82 +2,68 @@ * Author: Maxie D. Schmidt (@maxieds) */ +#include + #include "../Common.h" #include "CryptoTDEA.h" +#include "CryptoAES128.h" -//__asm__( -// STRINGIFY(#include "CryptoTDEA.S") -//); - -void EncryptDESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *Keys) { +void EncryptDESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { CryptoTDEA_CBCSpec CryptoSpec = { .cryptFunc = &CryptoEncryptDEA, .blockSize = CRYPTO_DES_BLOCK_SIZE }; uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; uint16_t blockIndex = 0; - uint8_t *ptBuf = (uint8_t *) Plaintext, *ctBuf = (uint8_t *) Ciphertext; + uint8_t *ctBuf = (uint8_t *) Ciphertext; + uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE]; + uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + if (IVIn == NULL) { + memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + } while (blockIndex < numBlocks) { - CryptoSpec.cryptFunc(ptBuf, ctBuf, Keys); - ptBuf += CryptoSpec.blockSize; - ctBuf += CryptoSpec.blockSize; - blockIndex++; + if (blockIndex == 0) { + memcpy(inputBlock, &Plaintext[0], CRYPTO_DES_BLOCK_SIZE); + CryptoMemoryXOR(IV, inputBlock, CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_DES_BLOCK_SIZE], inputBlock, CRYPTO_DES_BLOCK_SIZE); + } + CryptoSpec.cryptFunc(inputBlock, ctBuf, Keys); + ctBuf += CryptoSpec.blockSize; + blockIndex++; } } -void DecryptDESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *Keys) { +void DecryptDESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { CryptoTDEA_CBCSpec CryptoSpec = { .cryptFunc = &CryptoDecryptDEA, .blockSize = CRYPTO_DES_BLOCK_SIZE }; uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; uint16_t blockIndex = 0; - uint8_t *ptBuf = (uint8_t *) Plaintext, *ctBuf = (uint8_t *) Ciphertext; - while (blockIndex < numBlocks) { - CryptoSpec.cryptFunc(ptBuf, ctBuf, Keys); - ptBuf += CryptoSpec.blockSize; - ctBuf += CryptoSpec.blockSize; - blockIndex++; - } -} - -/* OLD: 3DES ECB (Now done with CBC): */ -#if 0 -void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *Keys) { - CryptoTDEA_CBCSpec CryptoSpec = { - .cryptFunc = &CryptoEncrypt3KTDEA, - .blockSize = CRYPTO_3KTDEA_BLOCK_SIZE - }; - uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; - uint16_t blockIndex = 0; - uint8_t *ptBuf = (uint8_t *) Plaintext, *ctBuf = (uint8_t *) Ciphertext; - while (blockIndex < numBlocks) { - CryptoSpec.cryptFunc(ptBuf, ctBuf, Keys); - ptBuf += CryptoSpec.blockSize; - ctBuf += CryptoSpec.blockSize; - blockIndex++; + uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE]; + uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + if (IVIn == NULL) { + memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); } -} - -void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *Keys) { - CryptoTDEA_CBCSpec CryptoSpec = { - .cryptFunc = &CryptoDecrypt3KTDEA, - .blockSize = CRYPTO_3KTDEA_BLOCK_SIZE - }; - uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; - uint16_t blockIndex = 0; - uint8_t *ptBuf = (uint8_t *) Plaintext, *ctBuf = (uint8_t *) Ciphertext; while (blockIndex < numBlocks) { - CryptoSpec.cryptFunc(ptBuf, ctBuf, Keys); - ptBuf += CryptoSpec.blockSize; - ctBuf += CryptoSpec.blockSize; + CryptoSpec.cryptFunc(inputBlock, Ciphertext + blockIndex * CRYPTO_DES_BLOCK_SIZE, Keys); + if (blockIndex == 0) { + memcpy(Plaintext, inputBlock, CRYPTO_DES_BLOCK_SIZE); + CryptoMemoryXOR(IV, Plaintext, CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(Plaintext + blockIndex * CRYPTO_DES_BLOCK_SIZE, inputBlock, CRYPTO_DES_BLOCK_SIZE); + CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], + Plaintext + blockIndex * CRYPTO_DES_BLOCK_SIZE, CRYPTO_DES_BLOCK_SIZE); + } blockIndex++; } } -#endif - -#include -#include "CryptoAES128.h" void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { CryptoTDEA_CBCSpec CryptoSpec = { diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h index 8de08b6e..90b90573 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h @@ -45,8 +45,8 @@ typedef void (*CryptoTDEAFuncType)(const void *PlainText, void *Ciphertext, cons void CryptoEncryptDEA(void *Plaintext, void *Ciphertext, const uint8_t *Keys); void CryptoDecryptDEA(void *Plaintext, void *Ciphertext, const uint8_t *Keys); -void EncryptDESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *Keys); -void DecryptDESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *Keys); +void EncryptDESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IV, const uint8_t *Keys); +void DecryptDESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IV, const uint8_t *Keys); /** Performs the Triple DEA enciphering in ECB mode (single block) * diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 57a5c3ed..f02dd883 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -441,8 +441,9 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { return DESFIRE_STATUS_RESPONSE_SIZE; } - /* Indicate that we are in AES key authentication land */ - keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_DES); + /* Indicate that we are in DES key authentication land */ + Key = &SessionKey; + keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); DesfireCommandState.KeyId = KeyId; DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); @@ -471,8 +472,8 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { uint8_t rndBPadded[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; memset(rndBPadded, 0x00, 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(rndBPadded, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - EncryptDESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, rndBPadded, - &Buffer[1], *Key); + Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, rndBPadded, + &Buffer[1], NULL, *Key); /* Scrub the key */ memset(*Key, 0, keySize); @@ -490,13 +491,15 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; + /* Validate command length */ - if (ByteCount != 2 * CRYPTO_DES_BLOCK_SIZE + 1) { + if (ByteCount != 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES + 1) { Buffer[0] = STATUS_LENGTH_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } /* Reset parameters for authentication from the first exchange */ + Key = &SessionKey; KeyId = DesfireCommandState.KeyId; cryptoKeyType = DesfireCommandState.CryptoMethodType; keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); @@ -506,8 +509,8 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { BYTE challengeRndAB[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndA[CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndB[CRYPTO_CHALLENGE_RESPONSE_BYTES]; - DecryptDESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, - &Buffer[1], *Key); + Decrypt3DESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, + &Buffer[1], NULL, *Key); RotateArrayRight(challengeRndAB + CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); @@ -515,7 +518,7 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { /* Check that the returned RndB matches what we sent in the previous round */ if (memcmp(DesfireCommandState.RndB, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES)) { Buffer[0] = STATUS_AUTHENTICATION_ERROR; - return DESFIRE_STATUS_RESPONSE_SIZE; + return DESFIRE_STATUS_RESPONSE_SIZE; } /* Authenticated successfully */ @@ -526,10 +529,8 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { /* Encrypt and send back the once rotated RndA buffer to the PCD */ RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - //memset(challengeRndAB, 0x00, 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES); - //memcpy(challengeRndAB, challengeRndA, CRYPTO_CHALLENGE_RESPONSE_BYTES); - EncryptDESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, - &Buffer[1], *Key); + Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, + &Buffer[1], NULL, *Key); /* Scrub the key */ memset(*Key, 0, keySize); @@ -1692,10 +1693,6 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { return DESFIRE_STATUS_RESPONSE_SIZE; } - /* The next calls just zero out the key buffers (not specific to AES): */ - //InitAESCryptoKeyData(&SessionKey); - //InitAESCryptoKeyData(&SessionIV); - keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); Key = &SessionKey; diff --git a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h index 153c1c4b..aa31e6b1 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h @@ -159,6 +159,37 @@ static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize, return bufSize; } +static inline size_t EncryptDES(const uint8_t *plainSrcBuf, size_t bufSize, + uint8_t *encDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { + DES_key_schedule keySched; + uint8_t *kd = cdata.keyData; + DES_set_key(kd, &keySched); + uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + if (IVIn == NULL) { + memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + } + DES_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched, &IV, DES_ENCRYPT); + return bufSize; +} + +static inline size_t DecryptDES(const uint8_t *encSrcBuf, size_t bufSize, + uint8_t *plainDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { + DES_key_schedule keySched; + uint8_t *kd = cdata.keyData; + DES_set_key(kd, &keySched); + uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + if (IVIn == NULL) { + memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + } + DES_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched, &IV, DES_DECRYPT); + return bufSize; +} + + static inline bool TestAESEncyptionRoutines(void) { fprintf(stdout, ">>> TestAESEncryptionRoutines [non-DESFire command]:\n"); const uint8_t keyData[] = { @@ -203,20 +234,7 @@ static inline bool TestAESEncyptionRoutines(void) { } static inline bool Test3DESEncyptionRoutines(void) { - fprintf(stdout, ">>> TestAESEncryptionRoutines [non-DESFire command]:\n"); - //const uint8_t keyData[] = { - // 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - // 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - // 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - //}; - //const uint8_t ptData[] = { - // 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - // 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF - //}; - //const uint8_t ctData[] = { - // 0x3e, 0xf0, 0xa8, 0x91, 0xcf, 0x8e, 0xd9, 0x90, - // 0xc4, 0x77, 0xeb, 0x09, 0x02, 0xf0, 0xc5, 0x4a - //}; + fprintf(stdout, ">>> Test3DESEncryptionRoutines [non-DESFire command]:\n"); const uint8_t keyData[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xf1, 0xe0, 0xd3, 0xc2, 0xb5, 0xa4, 0x97, 0x86, @@ -266,6 +284,50 @@ static inline bool Test3DESEncyptionRoutines(void) { fprintf(stdout, "\n"); return status; } + +static inline bool TestLegacyDESEncyptionRoutines(void) { + fprintf(stdout, ">>> TestLegacyDESEncryptionRoutines [non-DESFire command]:\n"); + const uint8_t keyData[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + }; + const uint8_t ptData[] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF + }; + const uint8_t ctData[] = { + 0x3e, 0xf0, 0xa8, 0x91, 0xcf, 0x8e, 0xd9, 0x90, + 0xc4, 0x77, 0xeb, 0x09, 0x02, 0xf0, 0xc5, 0x4a + }; + CryptoData_t cdata; + cdata.keyData = keyData; + cdata.keySize = 8; + const uint16_t testDataSize = 2 * 8; + uint8_t pt[testDataSize], ct[testDataSize]; + EncryptDES(ptData, testDataSize, ct, NULL, cdata); + DecryptDES(ctData, testDataSize, pt, NULL, cdata); + fprintf(stdout, " -- : PT [FIXED] = "); print_hex(ptData, testDataSize); + fprintf(stdout, " -- : CT [FIXED] = "); print_hex(ctData, testDataSize); + fprintf(stdout, " -- : CT [ENC] = "); print_hex(ct, testDataSize); + fprintf(stdout, " -- : PT [DEC] = "); print_hex(pt, testDataSize); + bool status = true; + if(memcmp(ct, ctData, testDataSize)) { + fprintf(stdout, " -- CT does NOT match !!\n"); + status = false; + } + else { + fprintf(stdout, " -- CT matches.\n"); + } + if(memcmp(pt, ptData, testDataSize)) { + fprintf(stdout, " -- Decrypted PT from CT does NOT match !!\n"); + status = false; + } + else { + fprintf(stdout, " -- Decrypted PT from CT matches.\n"); + } + fprintf(stdout, "\n"); + return status; +} + static inline int GenerateRandomBytes(uint8_t *destBuf, size_t numBytes) { return RAND_pseudo_bytes(destBuf, numBytes); } diff --git a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h index 591e32e7..e3f0ebf7 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h @@ -158,7 +158,7 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons int8_t IVBuf[16]; memcpy(encryptedRndB, rxDataStorage->rxDataBuf, 16); CryptoData_t desCryptoData = { 0 }; - desCryptoData.keySize = 8; + desCryptoData.keySize = 3 * 8; desCryptoData.keyData = keyData; desCryptoData.ivSize = 8; Decrypt3DES(encryptedRndB, 16, plainTextRndB, NULL, desCryptoData); @@ -221,6 +221,107 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons } } +static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, const uint8_t *keyData) { + + if(nfcConnDev == NULL || keyData == NULL) { + return INVALID_PARAMS_ERROR; + } + + // Start AES authentication (default key, blank setting of all zeros): + uint8_t AUTHENTICATE_LEGACY_CMD[] = { + 0x90, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00 + }; + AUTHENTICATE_LEGACY_CMD[5] = keyIndex; + if(PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, ">>> Start Legacy DES Authenticate:\n"); + fprintf(stdout, " -> "); + print_hex(AUTHENTICATE_LEGACY_CMD, sizeof(AUTHENTICATE_LEGACY_CMD)); + } + RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); + bool rxDataStatus = false; + rxDataStatus = libnfcTransmitBytes(nfcConnDev, AUTHENTICATE_LEGACY_CMD, sizeof(AUTHENTICATE_LEGACY_CMD), rxDataStorage); + if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " <- "); + print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); + } + else { + if(PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); + } + FreeRxDataStruct(rxDataStorage, true); + return EXIT_FAILURE; + } + + // Now need to decrypt the challenge response sent back as rndB (8 bytes), + // rotate it left, generate a random 8 byte rndA, concat rndA+rotatedRndB, + // encrypt this 16 byte result, and send it forth to the PICC: + uint8_t encryptedRndB[16], plainTextRndB[16], rotatedRndB[8]; + uint8_t rndA[8], challengeResponse[16], challengeResponseCipherText[16]; + int8_t IVBuf[16]; + memcpy(encryptedRndB, rxDataStorage->rxDataBuf, 16); + CryptoData_t desCryptoData = { 0 }; + desCryptoData.keySize = 3 * 8; + desCryptoData.keyData = keyData; + desCryptoData.ivSize = 8; + Decrypt3DES(encryptedRndB, 16, plainTextRndB, NULL, desCryptoData); + RotateArrayLeft(plainTextRndB, rotatedRndB, 8); + memset(IVBuf, 0x00, 16); + desCryptoData.ivData = IVBuf; + GenerateRandomBytes(rndA, 8); + ConcatByteArrays(rndA, 8, rotatedRndB, 8, challengeResponse); + Encrypt3DES(challengeResponse, 16, challengeResponseCipherText, NULL, desCryptoData); + + uint8_t sendBytesBuf[22]; + memset(sendBytesBuf, 0x00, 22); + sendBytesBuf[0] = 0x90; + sendBytesBuf[1] = 0xaf; + sendBytesBuf[4] = 0x10; + memcpy(sendBytesBuf + 5, challengeResponseCipherText, 16); + + if(PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " -- RNDA = "); print_hex(rndA, 8); + fprintf(stdout, " -- RNDB = "); print_hex(plainTextRndB, 8); + fprintf(stdout, " -- CHAL = "); print_hex(challengeResponse, 16); + fprintf(stdout, " -> "); + print_hex(sendBytesBuf, sizeof(sendBytesBuf)); + } + rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 22, rxDataStorage); + if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " <- "); + print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); + } + else { + if(PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); + } + FreeRxDataStruct(rxDataStorage, true); + return EXIT_FAILURE; + } + + // Finally, to finish up the auth process: + // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, + // and report back whether they match: + uint8_t decryptedRndAFromPICCRotated[16], decryptedRndA[16]; + Decrypt3DES(rxDataStorage->rxDataBuf, 16, decryptedRndAFromPICCRotated, NULL, desCryptoData); + RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, 8); + if(!memcmp(rndA, decryptedRndA, 8)) { + if(PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " ... AUTH OK! :)\n\n"); + } + AUTHENTICATED = true; + AUTHENTICATED_PROTO = DESFIRE_CRYPTO_AUTHTYPE_ISODES; + memcpy(CRYPTO_RNDB_STATE, plainTextRndB, 8); + FreeRxDataStruct(rxDataStorage, true); + return EXIT_SUCCESS; + } + else { + if(PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " ... AUTH FAILED -- X; :(\n\n"); + } + FreeRxDataStruct(rxDataStorage, true); + return EXIT_FAILURE; + } +} static inline int Authenticate(nfc_device *nfcConnDev, int authType, uint8_t keyIndex, const uint8_t *keyData) { InvalidateAuthState(); if(nfcConnDev == NULL || keyData == NULL) { @@ -231,6 +332,8 @@ static inline int Authenticate(nfc_device *nfcConnDev, int authType, uint8_t key return AuthenticateAES128(nfcConnDev, keyIndex, keyData); case DESFIRE_CRYPTO_AUTHTYPE_ISODES: return AuthenticateISO(nfcConnDev, keyIndex, keyData); + case DESFIRE_CRYPTO_AUTHTYPE_LEGACY: + return AuthenticateLegacy(nfcConnDev, keyIndex, keyData); default: break; } diff --git a/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h b/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h index c4dba322..1311bf27 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h @@ -47,7 +47,7 @@ static inline nfc_device * GetNFCDeviceDriver(nfc_context **context) { nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, true); nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, true); nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false); - //nfc_device_set_property_int(pnd, NP_TIMEOUT_COMMAND, 0); + nfc_device_set_property_int(pnd, NP_TIMEOUT_COMMAND, 0); return pnd; } diff --git a/Software/DESFireLibNFCTesting/Makefile b/Software/DESFireLibNFCTesting/Makefile index 389d5e62..f6adabfe 100644 --- a/Software/DESFireLibNFCTesting/Makefile +++ b/Software/DESFireLibNFCTesting/Makefile @@ -34,6 +34,7 @@ LIBNFC_CUSTOM_CONFIG= -DLIBNFC_LOGLEVEL=NFC_LOG_PRIORITY_DEBUG \ CFLAGS+= $(LIBNFC_SUPPORTED_DRIVERS) $(LIBNFC_CUSTOM_CONFIG) FILE_BASENAMES=NFCAntiCollisionMod \ + TestAuthenticateLegacy \ TestAuthenticateAES128 \ TestAuthenticateISO \ TestGeneralCommands \ diff --git a/Software/DESFireLibNFCTesting/Source/TestAuthenticateLegacy.c b/Software/DESFireLibNFCTesting/Source/TestAuthenticateLegacy.c new file mode 100644 index 00000000..04a2b910 --- /dev/null +++ b/Software/DESFireLibNFCTesting/Source/TestAuthenticateLegacy.c @@ -0,0 +1,39 @@ +/* TestAuthenticateLegacy.c */ + +#include "LibNFCUtils.h" +#include "LibNFCWrapper.h" +#include "DesfireUtils.h" +#include "CryptoUtils.h" + +int main(int argc, char **argv) { + + if(!Test3DESEncyptionRoutines()) { + return EXIT_FAILURE; + } + + nfc_context *nfcCtxt; + nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); + if(nfcPnd == NULL) { + return EXIT_FAILURE; + } + + // Select AID application 0x000000: + if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + return EXIT_FAILURE; + } + + // Get list of application IDs: + if(GetApplicationIds(nfcPnd)) { + return EXIT_FAILURE; + } + // Start ISO authentication (default key, blank setting of all zeros): + if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_LEGACY, + MASTER_KEY_INDEX, ZERO_KEY)) { + return EXIT_FAILURE; + } + + FreeNFCDeviceDriver(&nfcCtxt, &nfcPnd); + return EXIT_SUCCESS; + +} + From 281d3c7de8211a7481633e152ad7c7d9d90426f6 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Mon, 31 Jan 2022 01:23:50 -0500 Subject: [PATCH 06/68] AuthLegacy(0x0A) works using 3DES enc/dec modes -- Makefile no testing -- For #313 --- Firmware/Chameleon-Mini/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 986e175b..5e79f6c4 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -100,8 +100,8 @@ SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING #SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF #Set a default testing mode setting (0 = OFF, non-NULL = ON): -#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 -SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 +SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 +#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 #Feature: Use randomized UIDs that mask the actual secret UID until #the tag has been issued a successful authentication sequence: From ca0afad50f4efac9365ac1f617462373db5da455 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Mon, 31 Jan 2022 10:54:37 -0500 Subject: [PATCH 07/68] Adding support for non-wrapped native commands (I believe) --- .../Application/DESFire/DESFireInstructions.c | 299 +++++++++--------- .../Application/DESFire/DESFireInstructions.h | 64 ++-- .../Application/MifareDESFire.c | 12 +- 3 files changed, 192 insertions(+), 183 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index f02dd883..fcb7ba22 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -45,61 +45,92 @@ This notice must be retained at the top of all source files where indicated. DesfireSavedCommandStateType DesfireCommandState = { 0 }; +/* NOTE: The order of the structures in this buffer MUST be kept in + * ascending sorted order by the INS code. This property of the + * array has to be maintained as new commands and functions are + * added to keep CallInstructionHandler(uint8_t*, uint16_t) + * operating correctly. The instruction handler performs a + * binary search on the array to save time locating the correct + * C function to call to execute the command -- and this speedup + * helps keep timing issues at bay. DO NOT just append new command + * handlers to the end of the array, or insert them haphazardly in + * the middle !!! + */ const __flash DESFireCommand DESFireCommandSet[] = { { .insCode = CMD_AUTHENTICATE, .insDesc = (const __flash char[]) { "Authenicate_Legacy" }, .insFunc = &EV0CmdAuthenticateLegacy1 }, + { + .insCode = CMD_CREDIT, + .insDesc = (const __flash char[]) { "Credit" }, + .insFunc = &EV0CmdCredit + }, { .insCode = CMD_AUTHENTICATE_ISO, .insDesc = (const __flash char[]) { "Authenticate_ISO" }, .insFunc = &DesfireCmdAuthenticate3KTDEA1 }, { - .insCode = CMD_AUTHENTICATE_AES, - .insDesc = (const __flash char[]) { "Authenticate_AES" }, - .insFunc = &DesfireCmdAuthenticateAES1 + .insCode = CMD_LIMITED_CREDIT, + .insDesc = (const __flash char[]) { "Limited_Credit" }, + .insFunc = &EV0CmdLimitedCredit }, { - .insCode = CMD_AUTHENTICATE_EV2_FIRST, - .insDesc = (const __flash char[]) { "Authenticate_AES_EV2_First" }, - .insFunc = NULL + .insCode = CMD_WRITE_RECORD, + .insDesc = (const __flash char[]) { "Write_Record" }, + .insFunc = &EV0CmdWriteRecord }, { - .insCode = CMD_AUTHENTICATE_EV2_NONFIRST, - .insDesc = (const __flash char[]) { "Authenticate_AES_EV2_NonFirst" }, - .insFunc = NULL + .insCode = CMD_WRITE_DATA, + .insDesc = (const __flash char[]) { "Write_Data" }, + .insFunc = &EV0CmdWriteData + }, + { + .insCode = CMD_GET_KEY_SETTINGS, + .insDesc = (const __flash char[]) { "Get_Key_Settings" }, + .insFunc = &EV0CmdGetKeySettings + }, + { + .insCode = CMD_GET_CARD_UID, + .insDesc = (const __flash char[]) { "Get_Card_UID" }, + .insFunc = &DesfireCmdGetCardUID }, { .insCode = CMD_CHANGE_KEY_SETTINGS, .insDesc = (const __flash char[]) { "Change_Key_Settings" }, .insFunc = &EV0CmdChangeKeySettings }, + { + .insCode = CMD_SELECT_APPLICATION, + .insDesc = (const __flash char[]) { "Select_Application" }, + .insFunc = &EV0CmdSelectApplication + }, { .insCode = CMD_SET_CONFIGURATION, .insDesc = (const __flash char[]) { "Set_Configuration" }, .insFunc = NULL //&DesfireCmdSetConfiguration }, { - .insCode = CMD_CHANGE_KEY, - .insDesc = (const __flash char[]) { "Change_Key" }, - .insFunc = &EV0CmdChangeKey + .insCode = CMD_CHANGE_FILE_SETTINGS, + .insDesc = (const __flash char[]) { "Change_File_Settings" }, + .insFunc = &EV0CmdChangeFileSettings }, { - .insCode = CMD_GET_KEY_VERSION, - .insDesc = (const __flash char[]) { "Get_Key_Version" }, - .insFunc = &DesfireCmdGetKeyVersion + .insCode = CMD_GET_VERSION, + .insDesc = (const __flash char[]) { "Get_Version" }, + .insFunc = &EV0CmdGetVersion1 }, { - .insCode = CMD_CREATE_APPLICATION, - .insDesc = (const __flash char[]) { "Create_Application" }, - .insFunc = &EV0CmdCreateApplication + .insCode = CMD_GET_ISO_FILE_IDS, + .insDesc = (const __flash char[]) { "Get_ISO_File_IDs" }, + .insFunc = &EV0CmdGetFileIds }, { - .insCode = CMD_DELETE_APPLICATION, - .insDesc = (const __flash char[]) { "Delete_Application" }, - .insFunc = &EV0CmdDeleteApplication + .insCode = CMD_GET_KEY_VERSION, + .insDesc = (const __flash char[]) { "Get_Key_Version" }, + .insFunc = &DesfireCmdGetKeyVersion }, { .insCode = CMD_GET_APPLICATION_IDS, @@ -107,9 +138,9 @@ const __flash DESFireCommand DESFireCommandSet[] = { .insFunc = &EV0CmdGetApplicationIds1 }, { - .insCode = CMD_FREE_MEMORY, - .insDesc = (const __flash char[]) { "Free_Memory" }, - .insFunc = &DesfireCmdFreeMemory + .insCode = CMD_GET_VALUE, + .insDesc = (const __flash char[]) { "Get_Value" }, + .insFunc = &EV0CmdGetValue }, { .insCode = CMD_GET_DF_NAMES, @@ -117,79 +148,69 @@ const __flash DESFireCommand DESFireCommandSet[] = { .insFunc = &DesfireCmdGetDFNames }, { - .insCode = CMD_GET_KEY_SETTINGS, - .insDesc = (const __flash char[]) { "Get_Key_Settings" }, - .insFunc = &EV0CmdGetKeySettings - }, - { - .insCode = CMD_SELECT_APPLICATION, - .insDesc = (const __flash char[]) { "Select_Application" }, - .insFunc = &EV0CmdSelectApplication - }, - { - .insCode = CMD_FORMAT_PICC, - .insDesc = (const __flash char[]) { "Format_PICC" }, - .insFunc = &EV0CmdFormatPicc + .insCode = CMD_FREE_MEMORY, + .insDesc = (const __flash char[]) { "Free_Memory" }, + .insFunc = &DesfireCmdFreeMemory }, { - .insCode = CMD_GET_VERSION, - .insDesc = (const __flash char[]) { "Get_Version" }, - .insFunc = &EV0CmdGetVersion1 + .insCode = CMD_GET_FILE_IDS, + .insDesc = (const __flash char[]) { "Get_File_IDs" }, + .insFunc = &EV0CmdGetFileIds }, { - .insCode = CMD_GET_CARD_UID, - .insDesc = (const __flash char[]) { "Get_Card_UID" }, - .insFunc = &DesfireCmdGetCardUID + .insCode = CMD_AUTHENTICATE_EV2_FIRST, + .insDesc = (const __flash char[]) { "Authenticate_AES_EV2_First" }, + .insFunc = NULL }, { - .insCode = CMD_GET_FILE_IDS, - .insDesc = (const __flash char[]) { "Get_File_IDs" }, - .insFunc = &EV0CmdGetFileIds + .insCode = CMD_AUTHENTICATE_EV2_NONFIRST, + .insDesc = (const __flash char[]) { "Authenticate_AES_EV2_NonFirst" }, + .insFunc = NULL }, { - .insCode = CMD_GET_FILE_SETTINGS, - .insDesc = (const __flash char[]) { "Get_File_Settings" }, - .insFunc = &EV0CmdGetFileSettings + .insCode = CMD_ISO7816_EXTERNAL_AUTHENTICATE, + .insDesc = (const __flash char[]) { "ISO7816_External_Authenticate" }, + .insFunc = &ISO7816CmdExternalAuthenticate }, { - .insCode = CMD_CHANGE_FILE_SETTINGS, - .insDesc = (const __flash char[]) { "Change_File_Settings" }, - .insFunc = &EV0CmdChangeFileSettings + .insCode = CMD_ISO7816_GET_CHALLENGE, + .insDesc = (const __flash char[]) { "ISO7816_Get_Challenge" }, + .insFunc = &ISO7816CmdGetChallenge }, { - .insCode = CMD_CREATE_STDDATA_FILE, - .insDesc = (const __flash char[]) { "Create_Data_File" }, - .insFunc = &EV0CmdCreateStandardDataFile + .insCode = CMD_ISO7816_SELECT, + .insDesc = (const __flash char[]) { "ISO7816_Select" }, + .insFunc = &ISO7816CmdSelect }, { - .insCode = CMD_CREATE_BACKUPDATA_FILE, - .insDesc = (const __flash char[]) { "Create_Backup_File" }, - .insFunc = &EV0CmdCreateBackupDataFile + .insCode = CMD_ISO7816_INTERNAL_AUTHENTICATE, + .insDesc = (const __flash char[]) { "ISO7816_Internal_Authenticate" }, + .insFunc = &ISO7816CmdInternalAuthenticate }, { - .insCode = CMD_CREATE_VALUE_FILE, - .insDesc = (const __flash char[]) { "Create_Value_File" }, - .insFunc = &EV0CmdCreateValueFile + .insCode = CMD_ABORT_TRANSACTION, + .insDesc = (const __flash char[]) { "Abort_Transaction" }, + .insFunc = &EV0CmdAbortTransaction }, { - .insCode = CMD_CREATE_LINEAR_RECORD_FILE, - .insDesc = (const __flash char[]) { "Create_Linear_Record_File" }, - .insFunc = &EV0CmdCreateLinearRecordFile + .insCode = CMD_AUTHENTICATE_AES, + .insDesc = (const __flash char[]) { "Authenticate_AES" }, + .insFunc = &DesfireCmdAuthenticateAES1 }, { - .insCode = CMD_CREATE_CYCLIC_RECORD_FILE, - .insDesc = (const __flash char[]) { "Create_Cyclic_Record_File" }, - .insFunc = &EV0CmdCreateCyclicRecordFile + .insCode = CMD_ISO7816_READ_BINARY, + .insDesc = (const __flash char[]) { "ISO7816_Read_Binary" }, + .insFunc = &ISO7816CmdReadBinary }, { - .insCode = CMD_DELETE_FILE, - .insDesc = (const __flash char[]) { "Delete_File" }, - .insFunc = &EV0CmdDeleteFile + .insCode = CMD_ISO7816_READ_RECORDS, + .insDesc = (const __flash char[]) { "ISO7816_Read_Records" }, + .insFunc = &ISO7816CmdReadRecords }, { - .insCode = CMD_GET_ISO_FILE_IDS, - .insDesc = (const __flash char[]) { "Get_ISO_File_IDs" }, - .insFunc = &EV0CmdGetFileIds + .insCode = CMD_READ_RECORDS, + .insDesc = (const __flash char[]) { "Read_Records" }, + .insFunc = &EV0CmdReadRecords }, { .insCode = CMD_READ_DATA, @@ -197,44 +218,39 @@ const __flash DESFireCommand DESFireCommandSet[] = { .insFunc = &EV0CmdReadData }, { - .insCode = CMD_WRITE_DATA, - .insDesc = (const __flash char[]) { "Write_Data" }, - .insFunc = &EV0CmdWriteData - }, - { - .insCode = CMD_GET_VALUE, - .insDesc = (const __flash char[]) { "Get_Value" }, - .insFunc = &EV0CmdGetValue + .insCode = CMD_CREATE_CYCLIC_RECORD_FILE, + .insDesc = (const __flash char[]) { "Create_Cyclic_Record_File" }, + .insFunc = &EV0CmdCreateCyclicRecordFile }, { - .insCode = CMD_CREDIT, - .insDesc = (const __flash char[]) { "Credit" }, - .insFunc = &EV0CmdCredit + .insCode = CMD_CREATE_LINEAR_RECORD_FILE, + .insDesc = (const __flash char[]) { "Create_Linear_Record_File" }, + .insFunc = &EV0CmdCreateLinearRecordFile }, { - .insCode = CMD_DEBIT, - .insDesc = (const __flash char[]) { "Debit" }, - .insFunc = &EV0CmdDebit + .insCode = CMD_CHANGE_KEY, + .insDesc = (const __flash char[]) { "Change_Key" }, + .insFunc = &EV0CmdChangeKey }, { - .insCode = CMD_LIMITED_CREDIT, - .insDesc = (const __flash char[]) { "Limited_Credit" }, - .insFunc = &EV0CmdLimitedCredit + .insCode = CMD_CREATE_APPLICATION, + .insDesc = (const __flash char[]) { "Create_Application" }, + .insFunc = &EV0CmdCreateApplication }, { - .insCode = CMD_WRITE_RECORD, - .insDesc = (const __flash char[]) { "Write_Record" }, - .insFunc = &EV0CmdWriteRecord + .insCode = CMD_CREATE_BACKUPDATA_FILE, + .insDesc = (const __flash char[]) { "Create_Backup_File" }, + .insFunc = &EV0CmdCreateBackupDataFile }, { - .insCode = CMD_READ_RECORDS, - .insDesc = (const __flash char[]) { "Read_Records" }, - .insFunc = &EV0CmdReadRecords + .insCode = CMD_CREATE_VALUE_FILE, + .insDesc = (const __flash char[]) { "Create_Value_File" }, + .insFunc = &EV0CmdCreateValueFile }, { - .insCode = CMD_CLEAR_RECORD_FILE, - .insDesc = (const __flash char[]) { "Clear_Record_File" }, - .insFunc = &EV0CmdClearRecords + .insCode = CMD_CREATE_STDDATA_FILE, + .insDesc = (const __flash char[]) { "Create_Data_File" }, + .insFunc = &EV0CmdCreateStandardDataFile }, { .insCode = CMD_COMMIT_TRANSACTION, @@ -242,50 +258,45 @@ const __flash DESFireCommand DESFireCommandSet[] = { .insFunc = &EV0CmdCommitTransaction }, { - .insCode = CMD_ABORT_TRANSACTION, - .insDesc = (const __flash char[]) { "Abort_Transaction" }, - .insFunc = &EV0CmdAbortTransaction + .insCode = CMD_ISO7816_UPDATE_BINARY, + .insDesc = (const __flash char[]) { "ISO7816_Update_Binary" }, + .insFunc = &ISO7816CmdUpdateBinary }, { - .insCode = CMD_ISO7816_SELECT, - .insDesc = (const __flash char[]) { "ISO7816_Select" }, - .insFunc = &ISO7816CmdSelect + .insCode = CMD_DELETE_APPLICATION, + .insDesc = (const __flash char[]) { "Delete_Application" }, + .insFunc = &EV0CmdDeleteApplication }, { - .insCode = CMD_ISO7816_GET_CHALLENGE, - .insDesc = (const __flash char[]) { "ISO7816_Get_Challenge" }, - .insFunc = &ISO7816CmdGetChallenge + .insCode = CMD_DEBIT, + .insDesc = (const __flash char[]) { "Debit" }, + .insFunc = &EV0CmdDebit }, { - .insCode = CMD_ISO7816_EXTERNAL_AUTHENTICATE, - .insDesc = (const __flash char[]) { "ISO7816_External_Authenticate" }, - .insFunc = &ISO7816CmdExternalAuthenticate + .insCode = CMD_DELETE_FILE, + .insDesc = (const __flash char[]) { "Delete_File" }, + .insFunc = &EV0CmdDeleteFile }, { - .insCode = CMD_ISO7816_INTERNAL_AUTHENTICATE, - .insDesc = (const __flash char[]) { "ISO7816_Internal_Authenticate" }, - .insFunc = &ISO7816CmdInternalAuthenticate + .insCode = CMD_ISO7816_APPEND_RECORD, + .insDesc = (const __flash char[]) { "ISO7816_Append_Record" }, + .insFunc = &ISO7816CmdAppendRecord }, { - .insCode = CMD_ISO7816_READ_BINARY, - .insDesc = (const __flash char[]) { "ISO7816_Read_Binary" }, - .insFunc = &ISO7816CmdReadBinary + .insCode = CMD_CLEAR_RECORD_FILE, + .insDesc = (const __flash char[]) { "Clear_Record_File" }, + .insFunc = &EV0CmdClearRecords }, { - .insCode = CMD_ISO7816_UPDATE_BINARY, - .insDesc = (const __flash char[]) { "ISO7816_Update_Binary" }, - .insFunc = &ISO7816CmdUpdateBinary + .insCode = CMD_FORMAT_PICC, + .insDesc = (const __flash char[]) { "Format_PICC" }, + .insFunc = &EV0CmdFormatPicc }, { - .insCode = CMD_ISO7816_READ_RECORDS, - .insDesc = (const __flash char[]) { "ISO7816_Read_Records" }, - .insFunc = &ISO7816CmdReadRecords + .insCode = CMD_GET_FILE_SETTINGS, + .insDesc = (const __flash char[]) { "Get_File_Settings" }, + .insFunc = &EV0CmdGetFileSettings }, - { - .insCode = CMD_ISO7816_APPEND_RECORD, - .insDesc = (const __flash char[]) { "ISO7816_Append_Record" }, - .insFunc = &ISO7816CmdAppendRecord - } }; uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount) { @@ -293,24 +304,24 @@ uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount) { Buffer[0] = STATUS_PARAMETER_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } - uint8_t callingInsCode = Buffer[0]; + uint8_t insCode = Buffer[0]; uint32_t insLookupTableBuf = &DESFireCommandSet[0]; - uint8_t cmdSetLength = sizeof(DESFireCommandSet) / sizeof(DESFireCommand); - uint8_t curInsIndex = 0; - while (curInsIndex < cmdSetLength) { - DESFireCommand dfCmd; + uint16_t curInsLower = 0, curInsUpper = sizeof(DESFireCommandSet) / sizeof(DESFireCommand) - 1; + uint16_t curInsIndex; + DESFireCommand dfCmd; + while(curInsUpper >= curInsLower) { + curInsIndex = curInsLower + (curInsUpper + 1 - curInsLower) / 2; memcpy_P(&dfCmd, insLookupTableBuf + curInsIndex * sizeof(DESFireCommand), sizeof(DESFireCommand)); - if (dfCmd.insCode == callingInsCode) { - if (dfCmd.insFunc == NULL) { - snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, PSTR("NOT IMPLEMENTED: %s!"), dfCmd.insDesc); - __InternalStringBuffer[STRING_BUFFER_SIZE - 1] = '\0'; - uint8_t bufSize = StringLength(__InternalStringBuffer, STRING_BUFFER_SIZE); - LogEntry(LOG_INFO_DESFIRE_DEBUGGING_OUTPUT, (void *) __InternalStringBuffer, bufSize); - return CmdNotImplemented(Buffer, ByteCount); - } - return dfCmd.insFunc(Buffer, ByteCount); - } - curInsIndex += 1; + if (dfCmd.insCode == insCode) { + if (dfCmd.insFunc == NULL) { + return CmdNotImplemented(Buffer, ByteCount); + } + return dfCmd.insFunc(Buffer, ByteCount); + } else if (dfCmd.insCode < insCode) { + curInsLower = curInsIndex + 1; + } else { + curInsUpper = curInsIndex - 1; + } } return ISO14443A_APP_NO_RESPONSE; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h index fca0dd60..fe6ea521 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h @@ -53,55 +53,55 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { /* DESFire native command support: */ NO_COMMAND_TO_CONTINUE = 0x00, CMD_AUTHENTICATE = 0x0A, /* Authenticate Legacy */ + CMD_CREDIT = 0x0C, CMD_AUTHENTICATE_ISO = 0x1A, - CMD_AUTHENTICATE_AES = 0xAA, - CMD_AUTHENTICATE_EV2_FIRST = 0x71, /* See page 32 of AN12343.pdf */ - CMD_AUTHENTICATE_EV2_NONFIRST = 0x77, /* See page 32 of AN12343.pdf */ + CMD_LIMITED_CREDIT = 0x1C, + CMD_WRITE_RECORD = 0x3B, + CMD_WRITE_DATA = 0x3D, + CMD_GET_KEY_SETTINGS = 0x45, + CMD_GET_CARD_UID = 0x51, CMD_CHANGE_KEY_SETTINGS = 0x54, + CMD_SELECT_APPLICATION = 0x5A, CMD_SET_CONFIGURATION = 0x5C, - CMD_CHANGE_KEY = 0xC4, + CMD_CHANGE_FILE_SETTINGS = 0x5F, + CMD_GET_VERSION = 0x60, + CMD_GET_ISO_FILE_IDS = 0x61, CMD_GET_KEY_VERSION = 0x64, - CMD_CREATE_APPLICATION = 0xCA, - CMD_DELETE_APPLICATION = 0xDA, CMD_GET_APPLICATION_IDS = 0x6A, - CMD_FREE_MEMORY = 0x6E, + CMD_GET_VALUE = 0x6C, CMD_GET_DF_NAMES = 0x6D, - CMD_GET_KEY_SETTINGS = 0x45, - CMD_SELECT_APPLICATION = 0x5A, - CMD_FORMAT_PICC = 0xFC, - CMD_GET_VERSION = 0x60, - CMD_GET_CARD_UID = 0x51, + CMD_FREE_MEMORY = 0x6E, CMD_GET_FILE_IDS = 0x6F, - CMD_GET_FILE_SETTINGS = 0xF5, - CMD_CHANGE_FILE_SETTINGS = 0x5F, - CMD_CREATE_STDDATA_FILE = 0xCD, + CMD_AUTHENTICATE_EV2_FIRST = 0x71, /* See page 32 of AN12343.pdf */ + CMD_AUTHENTICATE_EV2_NONFIRST = 0x77, /* See page 32 of AN12343.pdf */ + CMD_ABORT_TRANSACTION = 0xA7, + CMD_AUTHENTICATE_AES = 0xAA, + CMD_CONTINUE = 0xAF, + CMD_READ_RECORDS = 0xBB, + CMD_READ_DATA = 0xBD, + CMD_CREATE_CYCLIC_RECORD_FILE = 0xC0, + CMD_CREATE_LINEAR_RECORD_FILE = 0xC1, + CMD_CHANGE_KEY = 0xC4, + CMD_CREATE_APPLICATION = 0xCA, CMD_CREATE_BACKUPDATA_FILE = 0xCB, CMD_CREATE_VALUE_FILE = 0xCC, - CMD_CREATE_LINEAR_RECORD_FILE = 0xC1, - CMD_CREATE_CYCLIC_RECORD_FILE = 0xC0, - CMD_DELETE_FILE = 0xDF, - CMD_GET_ISO_FILE_IDS = 0x61, - CMD_READ_DATA = 0xBD, - CMD_WRITE_DATA = 0x3D, - CMD_GET_VALUE = 0x6C, - CMD_CREDIT = 0x0C, + CMD_CREATE_STDDATA_FILE = 0xCD, + CMD_COMMIT_TRANSACTION = 0xC7, + CMD_DELETE_APPLICATION = 0xDA, CMD_DEBIT = 0xDC, - CMD_LIMITED_CREDIT = 0x1C, - CMD_WRITE_RECORD = 0x3B, - CMD_READ_RECORDS = 0xBB, + CMD_DELETE_FILE = 0xDF, CMD_CLEAR_RECORD_FILE = 0xEB, - CMD_COMMIT_TRANSACTION = 0xC7, - CMD_ABORT_TRANSACTION = 0xA7, - CMD_CONTINUE = 0xAF, + CMD_FORMAT_PICC = 0xFC, + CMD_GET_FILE_SETTINGS = 0xF5, /* ISO7816 Command Set Support: */ - CMD_ISO7816_SELECT = 0xA4, - CMD_ISO7816_GET_CHALLENGE = 0x84, CMD_ISO7816_EXTERNAL_AUTHENTICATE = 0x82, + CMD_ISO7816_GET_CHALLENGE = 0x84, CMD_ISO7816_INTERNAL_AUTHENTICATE = 0x88, + CMD_ISO7816_SELECT = 0xA4, CMD_ISO7816_READ_BINARY = 0xB0, - CMD_ISO7816_UPDATE_BINARY = 0xD6, CMD_ISO7816_READ_RECORDS = 0xB2, + CMD_ISO7816_UPDATE_BINARY = 0xD6, CMD_ISO7816_APPEND_RECORD = 0xE2, /* Space for undocumented command codes -- diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 4df4940f..6390460a 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -213,7 +213,8 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { } uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { - size_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + uint16_t ReturnedBytes = 0; if (ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) { return MifareDesfireProcess(Buffer, BitCount); @@ -233,13 +234,10 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { ISO14443AAppendCRCA(Buffer, ProcessedByteCount); ProcessedBitCount += 2 * BITS_PER_BYTE; return ProcessedBitCount; + } else if((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { + return ReturnedBytes; } else { - uint16_t ProcessedBitCount = ISO144433APiccProcess(Buffer, BitCount); - if (ProcessedBitCount == ISO14443A_APP_NO_RESPONSE) { - const char *debugNoResponse = PSTR("APP_NO_RESP"); - LogDebuggingMsg(debugNoResponse); - } - return ProcessedBitCount; + return ISO144433APiccProcess(Buffer, BitCount); } } From 71762595efc9e655aecdee45af12087c0a7bdd12 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Mon, 31 Jan 2022 12:54:23 -0500 Subject: [PATCH 08/68] Stashing incremental testing release code --- .../Chameleon-Mini/Application/CryptoMAC.h | 38 ++++++++++++++++++ .../Application/DESFire/DESFireInstructions.c | 6 +-- .../Application/DESFire/DESFireKeyUtils.h | 39 +++++++++++++++++++ Firmware/Chameleon-Mini/Makefile | 6 +-- 4 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 Firmware/Chameleon-Mini/Application/CryptoMAC.h create mode 100644 Firmware/Chameleon-Mini/Application/DESFire/DESFireKeyUtils.h diff --git a/Firmware/Chameleon-Mini/Application/CryptoMAC.h b/Firmware/Chameleon-Mini/Application/CryptoMAC.h new file mode 100644 index 00000000..c36db1ce --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/CryptoMAC.h @@ -0,0 +1,38 @@ +/* +The DESFire stack portion of this firmware source +is free software written by Maxie Dion Schmidt (@maxieds): +You can redistribute it and/or modify +it under the terms of this license. + +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. + +The complete source distribution of +this firmware is available at the following link: +https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack. + +Based in part on the original DESFire code created by +@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at +https://github.com/dev-zzo/ChameleonMini/tree/desfire. + +This notice must be retained at the top of all source files where indicated. +*/ + +/* + * CryptoMAC.h : + * Maxie D. Schmidt (github.com/maxieds) + */ + +#ifndef __CRYPTO_MAC_H__ +#define __CRYPTO_MAC_H__ + +#include "DESFire/DESFireCrypto.h" +#include "CryptoTDEA.h" +#include "CryptoAES128.h" + + + + + +#endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index fcb7ba22..257b2675 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -453,8 +453,8 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { } /* Indicate that we are in DES key authentication land */ - Key = &SessionKey; keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); + Key = &SessionKey; DesfireCommandState.KeyId = KeyId; DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); @@ -510,10 +510,10 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { } /* Reset parameters for authentication from the first exchange */ - Key = &SessionKey; KeyId = DesfireCommandState.KeyId; cryptoKeyType = DesfireCommandState.CryptoMethodType; keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); + Key = &SessionKey; ReadAppKey(SelectedApp.Slot, KeyId, *Key, keySize); /* Decrypt the challenge sent back to get RndA and a shifted RndB */ @@ -1763,10 +1763,10 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { } /* Reset parameters for authentication from the first exchange */ - Key = &SessionKey; KeyId = DesfireCommandState.KeyId; cryptoKeyType = DesfireCommandState.CryptoMethodType; keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); + Key = &SessionKey; ReadAppKey(SelectedApp.Slot, KeyId, *Key, keySize); /* Decrypt the challenge sent back to get RndA and a shifted RndB */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireKeyUtils.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireKeyUtils.h new file mode 100644 index 00000000..502235e1 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireKeyUtils.h @@ -0,0 +1,39 @@ +/* +The DESFire stack portion of this firmware source +is free software written by Maxie Dion Schmidt (@maxieds): +You can redistribute it and/or modify +it under the terms of this license. + +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. + +The complete source distribution of +this firmware is available at the following link: +https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack. + +Based in part on the original DESFire code created by +@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at +https://github.com/dev-zzo/ChameleonMini/tree/desfire. + +This notice must be retained at the top of all source files where indicated. +*/ + +/* + * DESFireKeyUtils.h : + * Maxie D. Schmidt (github.com/maxieds) + */ + +#ifndef __DESFIRE_KEY_UTILS_H__ +#define __DESFIRE_KEY_UTILS_H__ + +#include "DESFireCrypto.h" + +/* TODO: Placeholder for: + * => Key (re)initialization + * => Configuring the session key on the fly + * => CommSettings: PLAIN | MACED | ENCIPHERD + * => Possibly others + */ + +#endif diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 5e79f6c4..aaf43b80 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -100,8 +100,8 @@ SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING #SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF #Set a default testing mode setting (0 = OFF, non-NULL = ON): -SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 -#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 +#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 +SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 #Feature: Use randomized UIDs that mask the actual secret UID until #the tag has been issued a successful authentication sequence: @@ -133,7 +133,7 @@ SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=1 #Option to save space with the "Application/Crypto1.c" code by storing large tables #in PROGMEM. Note that this will slow down the read times when accessing these tables: -#SETTINGS += -DDESFIRE_CRYPTO1_SAVE_SPACE +SETTINGS += -DDESFIRE_CRYPTO1_SAVE_SPACE DESFIRE_MAINSRC = Application/DESFire From b451e1212be5410566a3f43414f43288c8d7c0a1 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Thu, 3 Feb 2022 06:52:33 -0500 Subject: [PATCH 09/68] Working AES128 auth ; Nearly working ISO auth (still debugging) -- Stashing copy for reference --- Doc/DESFireSupportReadme.md | 7 + .../Chameleon-Mini/Application/Application.h | 9 +- .../Chameleon-Mini/Application/CryptoMAC.h | 9 + .../DESFire/DESFireApplicationDirectory.c | 32 +++- .../DESFire/DESFireApplicationDirectory.h | 12 +- .../DESFire/DESFireChameleonTerminal.c | 45 ++++- .../DESFire/DESFireChameleonTerminal.h | 4 + .../DESFire/DESFireChameleonTerminalInclude.c | 7 + .../Application/DESFire/DESFireCrypto.c | 40 +++- .../Application/DESFire/DESFireCrypto.h | 14 +- .../DESFire/DESFireFirmwareSettings.h | 20 +- .../Application/DESFire/DESFireInstructions.c | 75 +++++--- .../Application/DESFire/DESFireKeyUtils.h | 39 ---- .../DESFire/DESFireMemoryOperations.c | 73 +++---- .../DESFire/DESFireMemoryOperations.h | 4 +- .../Application/DESFire/DESFirePICCControl.c | 30 +-- .../Application/DESFire/DESFirePICCControl.h | 4 +- .../DESFire/DESFirePICCHeaderLayout.h | 7 +- .../Application/MifareDESFire.c | 68 ++++--- .../Application/MifareDESFire.h | 4 + Firmware/Chameleon-Mini/Common.h | 10 + Firmware/Chameleon-Mini/Configuration.c | 143 +++++++++++--- Firmware/Chameleon-Mini/Configuration.h | 13 +- Firmware/Chameleon-Mini/Log.h | 4 + Firmware/Chameleon-Mini/Makefile | 13 +- Firmware/Chameleon-Mini/Memory.h | 4 +- Firmware/Chameleon-Mini/Settings.c | 2 +- Firmware/Chameleon-Mini/Settings.h | 5 + Firmware/Chameleon-Mini/Terminal/Commands.c | 6 +- Firmware/Chameleon-Mini/Terminal/Terminal.h | 4 + .../LocalInclude/CryptoUtils.h | 2 + .../LocalInclude/DesfireUtils.h | 180 +++++++++--------- 32 files changed, 562 insertions(+), 327 deletions(-) delete mode 100644 Firmware/Chameleon-Mini/Application/DESFire/DESFireKeyUtils.h diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index c11322bd..b8782f9a 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -237,6 +237,13 @@ Syntax: DF_TESTMODE? DF_TESTMODE=<0|1|TRUE|FALSE|OFF|ON> ``` +#### DF_COMM_MODE + +Syntax: +```bash +DF_COMM_MODE? +DF_COMM_MODE= +``` ### Links to public datasheets and online specs diff --git a/Firmware/Chameleon-Mini/Application/Application.h b/Firmware/Chameleon-Mini/Application/Application.h index e4265294..c655ac64 100644 --- a/Firmware/Chameleon-Mini/Application/Application.h +++ b/Firmware/Chameleon-Mini/Application/Application.h @@ -29,6 +29,14 @@ INLINE void ApplicationInit(void) { ActiveConfiguration.ApplicationInitFunc(); } +INLINE void ApplicationInitRunOnce(void) { + if (ActiveConfiguration.ApplicationInitRunOnceFunc != NULL) { + ActiveConfiguration.ApplicationInitRunOnceFunc(); + } else { + ActiveConfiguration.ApplicationInitFunc(); + } +} + INLINE void ApplicationTask(void) { ActiveConfiguration.ApplicationTaskFunc(); } @@ -43,7 +51,6 @@ INLINE uint16_t ApplicationProcess(uint8_t *ByteBuffer, uint16_t ByteCount) { INLINE void ApplicationReset(void) { ActiveConfiguration.ApplicationResetFunc(); - //LogEntry(LOG_INFO_RESET_APP, NULL, 0); } INLINE void ApplicationGetUid(ConfigurationUidType Uid) { diff --git a/Firmware/Chameleon-Mini/Application/CryptoMAC.h b/Firmware/Chameleon-Mini/Application/CryptoMAC.h index c36db1ce..1d50da02 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoMAC.h +++ b/Firmware/Chameleon-Mini/Application/CryptoMAC.h @@ -31,8 +31,17 @@ This notice must be retained at the top of all source files where indicated. #include "CryptoTDEA.h" #include "CryptoAES128.h" +/* MAC and CMAC source code based on github/andrade/nfcjlib */ +#define CRYPTO_CMAC_RB64 (0x1B) +#define CRYPTO_CMAC_RB128 ((uint8_t) 0x87) +void getCMACSubK1(uint8_t *bufferL, uint16_t blockSize, uint8_t polyByte, uint8_t *bufferOut); +void getCMACSubK2(uint8_t *bufferK1, uint16_t blockSize, uint8_t polyByte, uint8_t *bufferOut); +bool computeBufferCMACFull(uint8_t *keyData, uint8_t *bufferK1, uint8_t *bufferK2, uint8_t *bufferIV, uint16_t blockSize, uint16_t cryptoType); +bool computeBufferCMAC(uint16_t cryptoType, uint8_t *keyData, uint8_t *bufferData, uint8_t *aesIV); + +bool computeMac(uint8_t *bufferData, uint16_t dataLength, uint8_t *keyData, uint16_t cryptoKeyType); #endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c index e97f78b4..dc2e2a19 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c @@ -42,8 +42,6 @@ This notice must be retained at the top of all source files where indicated. void SynchronizeAppDir(void) { WriteBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); - //SIZET appCacheSelectedBlockId = AppDir.AppCacheStructBlockOffset[SelectedApp.Slot]; - //WriteBlockBytes(&SelectedApp, appCacheSelectedBlockId, sizeof(SelectedAppCacheType)); } BYTE PMKConfigurationChangeable(void) { @@ -210,6 +208,8 @@ void SetAppProperty(DesfireCardLayout propId, BYTE AppSlot, SIZET Value) { bool KeyIdValid(uint8_t AppSlot, uint8_t KeyId) { if (KeyId >= DESFIRE_MAX_KEYS || KeyId >= ReadMaxKeyCount(AppSlot)) { + const char *debugMsg = PSTR("INVKEY-KeyId(%02x)-RdMax(%02x)"); + DEBUG_PRINT_P(debugMsg, KeyId, ReadMaxKeyCount(AppSlot)); return false; } return true; @@ -308,6 +308,16 @@ void ReadAppKey(uint8_t AppSlot, uint8_t KeyId, uint8_t *Key, SIZET KeySize) { SIZET keyStorageArray[DESFIRE_MAX_KEYS]; ReadBlockBytes(keyStorageArray, keyStorageArrayBlockId, 2 * DESFIRE_MAX_KEYS); ReadBlockBytes(Key, keyStorageArray[KeyId], KeySize); + /*if (KeySize > DESFIRE_EEPROM_BLOCK_SIZE) { + ReadBlockBytes(Key, keyStorageArray[KeyId], DESFIRE_EEPROM_BLOCK_SIZE); + uint8_t fullBlock[DESFIRE_EEPROM_BLOCK_SIZE]; + ReadBlockBytes(fullBlock, keyStorageArray[KeyId] + 1, DESFIRE_EEPROM_BLOCK_SIZE); + memcpy(Key + DESFIRE_EEPROM_BLOCK_SIZE, fullBlock, KeySize - DESFIRE_EEPROM_BLOCK_SIZE); + } else { + uint8_t fullBlock[DESFIRE_EEPROM_BLOCK_SIZE]; + ReadBlockBytes(fullBlock, keyStorageArray[KeyId], DESFIRE_EEPROM_BLOCK_SIZE); + memcpy(Key, fullBlock, KeySize); + }*/ } void WriteAppKey(uint8_t AppSlot, uint8_t KeyId, const uint8_t *Key, SIZET KeySize) { @@ -319,6 +329,7 @@ void WriteAppKey(uint8_t AppSlot, uint8_t KeyId, const uint8_t *Key, SIZET KeySi SIZET keyStorageArrayBlockId = ReadKeyStorageAddress(AppSlot); SIZET keyStorageArray[DESFIRE_MAX_KEYS]; ReadBlockBytes(keyStorageArray, keyStorageArrayBlockId, 2 * DESFIRE_MAX_KEYS); + // TODO: WriteBlockBytes(Key, keyStorageArray[KeyId], KeySize); } @@ -556,8 +567,7 @@ uint16_t CreateApp(const DESFireAidType Aid, uint8_t KeyCount, uint8_t KeySettin bool initMasterApp = false; /* Verify this AID has not been allocated yet */ - if ((Aid[0] == 0x00) && (Aid[1] == 0x00) && (Aid[2] == 0x00) && - AppDir.FirstFreeSlot == 0) { + if ((Aid[0] == 0x00) && (Aid[1] == 0x00) && (Aid[2] == 0x00) && AppDir.FirstFreeSlot == 0) { Slot = 0; initMasterApp = true; } else if ((Aid[0] == 0x00) && (Aid[1] == 0x00) && (Aid[2] == 0x00)) { @@ -584,6 +594,8 @@ uint16_t CreateApp(const DESFireAidType Aid, uint8_t KeyCount, uint8_t KeySettin /* Allocate storage for the application structure itself */ AppDir.AppCacheStructBlockOffset[Slot] = AllocateBlocks(SELECTED_APP_CACHE_TYPE_BLOCK_SIZE); if (AppDir.AppCacheStructBlockOffset[Slot] == 0) { + const char *debugMsg = PSTR("X - alloc blks, slot = %d"); + DEBUG_PRINT_P(debugMsg, Slot); return STATUS_OUT_OF_EEPROM_ERROR; } /* Allocate storage for the application components */ @@ -639,9 +651,9 @@ uint16_t CreateApp(const DESFireAidType Aid, uint8_t KeyCount, uint8_t KeySettin if (appCacheData.KeyTypesArray == 0) { return STATUS_OUT_OF_EEPROM_ERROR; } else { - BYTE keyTypesData[DESFIRE_MAX_KEYS]; - memset(keyTypesData, 0x00, DESFIRE_MAX_KEYS); - WriteBlockBytes(keyTypesData, appCacheData.KeyTypesArray, DESFIRE_MAX_KEYS); + BYTE keyTypesData[APP_CACHE_KEY_TYPES_ARRAY_BLOCK_SIZE * DESFIRE_EEPROM_BLOCK_SIZE]; + memset(keyTypesData, 0x00, APP_CACHE_KEY_TYPES_ARRAY_BLOCK_SIZE * DESFIRE_EEPROM_BLOCK_SIZE); + WriteBlockBytes(keyTypesData, appCacheData.KeyTypesArray, APP_CACHE_KEY_TYPES_ARRAY_BLOCK_SIZE * DESFIRE_EEPROM_BLOCK_SIZE); } appCacheData.FilesAddress = AllocateBlocks(APP_CACHE_FILE_BLOCKIDS_ARRAY_BLOCK_SIZE); if (appCacheData.FilesAddress == 0) { @@ -664,8 +676,10 @@ uint16_t CreateApp(const DESFireAidType Aid, uint8_t KeyCount, uint8_t KeySettin } BYTE cryptoBlankKeyData[CRYPTO_MAX_KEY_SIZE]; memset(cryptoBlankKeyData, 0x00, CRYPTO_MAX_KEY_SIZE); - WriteBlockBytes(cryptoBlankKeyData, keyAddresses[0], CRYPTO_MAX_KEY_SIZE); - WriteBlockBytes(keyAddresses, appCacheData.KeyAddress, sizeof(SIZET) * DESFIRE_MAX_KEYS); + //WriteBlockBytes(cryptoBlankKeyData, keyAddresses[0], DESFIRE_EEPROM_BLOCK_SIZE); + //WriteBlockBytes(cryptoBlankKeyData, keyAddresses[0] + 1, CRYPTO_MAX_KEY_SIZE - DESFIRE_EEPROM_BLOCK_SIZE); + WriteBlockBytes(cryptoBlankKeyData, keyAddresses[0], CRYPTO_MAX_KEY_SIZE); + WriteBlockBytes(keyAddresses, appCacheData.KeyAddress, sizeof(SIZET) * DESFIRE_MAX_KEYS); } SIZET appCacheDataBlockId = AppDir.AppCacheStructBlockOffset[Slot]; WriteBlockBytes(&appCacheData, appCacheDataBlockId, sizeof(SelectedAppCacheType)); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h index 0eb201bb..64abbed7 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h @@ -35,8 +35,8 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_MAX_FILES_EV0 16 #define DESFIRE_MAX_FILES_EV1 32 -#if defined(DESFIRE_MEMORY_LIMITED_TESTING) && !defined(DESFIRE_CUSTOM_MAX_APPS) -#define DESFIRE_MAX_APPS (6) +#if defined(MEMORY_LIMITED_TESTING) && !defined(DESFIRE_CUSTOM_MAX_APPS) +#define DESFIRE_MAX_APPS (3) #elif defined(DESFIRE_CUSTOM_MAX_APPS) #define DESFIRE_MAX_APPS (DESFIRE_CUSTOM_MAX_APPS) #else @@ -45,16 +45,16 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_MAX_SLOTS (DESFIRE_MAX_APPS + 1) -#if defined(DESFIRE_MEMORY_LIMITED_TESTING) && !defined(DESFIRE_CUSTOM_MAX_FILES) -#define DESFIRE_MAX_FILES (6) +#if defined(MEMORY_LIMITED_TESTING) && !defined(DESFIRE_CUSTOM_MAX_FILES) +#define DESFIRE_MAX_FILES (4) #elif defined(DESFIRE_CUSTOM_MAX_FILES) #define DESFIRE_MAX_FILES (DESFIRE_CUSTOM_MAX_FILES) #else #define DESFIRE_MAX_FILES (DESFIRE_MAX_FILES_EV1) #endif -#if defined(DESFIRE_MEMORY_LIMITED_TESTING) && !defined(DESFIRE_CUSTOM_MAX_KEYS) -#define DESFIRE_MAX_KEYS (4) +#if defined(MEMORY_LIMITED_TESTING) && !defined(DESFIRE_CUSTOM_MAX_KEYS) +#define DESFIRE_MAX_KEYS (2) #elif defined(DESFIRE_CUSTOM_MAX_KEYS) #define DESFIRE_MAX_KEYS (DESFIRE_CUSTOM_MAX_KEYS) #else diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c index 1b526288..efdbaa9d 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c @@ -148,7 +148,7 @@ CommandStatusIdType CommandDESFireFirmwareInfo(char *OutParam) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Chameleon-Mini DESFire enabled firmware built on %s " "based on %s from \r\n" - "https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack.\r\n" + "https://github.com/maxieds/ChameleonMini.\r\n" "Revision: %s\r\n"), DESFIRE_FIRMWARE_BUILD_TIMESTAMP, DESFIRE_FIRMWARE_GIT_COMMIT_ID, @@ -239,4 +239,47 @@ CommandStatusIdType CommandDESFireSetTestingMode(char *OutParam, const char *InP return COMMAND_ERR_INVALID_USAGE_ID; } +CommandStatusIdType CommandDESFireGetCommMode(char *OutParam) { + if (!IsDESFireConfiguration()) { + ExitOnInvalidConfigurationError(OutParam); + } else if(DesfireCommMode == DESFIRE_COMMS_PLAINTEXT) { + snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Plaintext")); + } else if(DesfireCommMode == DESFIRE_COMMS_PLAINTEXT_MAC) { + snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Plaintext/MAC")); + } else if(DesfireCommMode == DESFIRE_COMMS_CIPHERTEXT_DES) { + snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Enciphered/DES")); + } else if(DesfireCommMode == DESFIRE_COMMS_CIPHERTEXT_AES128) { + snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Enciphered/AES128")); + } else { + snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Unknown")); + } + return COMMAND_INFO_OK_WITH_TEXT_ID; +} + +CommandStatusIdType CommandDESFireSetCommMode(char *OutParam, const char *InParams) { + if (!IsDESFireConfiguration()) { + ExitOnInvalidConfigurationError(OutParam); + } + char valueStr[16]; + if (!sscanf_P(InParams, PSTR("%15s"), valueStr)) { + return COMMAND_ERR_INVALID_PARAM_ID; + } + valueStr[15] = '\0'; + if (!strcasecmp_P(valueStr, PSTR("Plaintext"))) { + DesfireCommMode = DESFIRE_COMMS_PLAINTEXT; + return COMMAND_INFO_OK; + } else if (!strcasecmp_P(valueStr, PSTR("Plaintext:MAC"))) { + DesfireCommMode = DESFIRE_COMMS_PLAINTEXT_MAC; + return COMMAND_INFO_OK; + } else if (!strcasecmp_P(valueStr, PSTR("Enciphered:3K3DES"))) { + DesfireCommMode = DESFIRE_COMMS_CIPHERTEXT_DES; + return COMMAND_INFO_OK; + } else if (!strcasecmp_P(valueStr, PSTR("Enciphered:AES128"))) { + DesfireCommMode = DESFIRE_COMMS_CIPHERTEXT_AES128; + return COMMAND_INFO_OK; + } + snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Options are: Plaintext|Plaintext:MAC|Enciphered:3K3DES|Enciphered:AES128")); + return COMMAND_ERR_INVALID_USAGE_ID; +} + #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h index 5e354927..1c5664f6 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h @@ -56,6 +56,10 @@ CommandStatusIdType CommandDESFireSetLoggingMode(char *OutMessage, const char *I CommandStatusIdType CommandDESFireGetTestingMode(char *OutParam); CommandStatusIdType CommandDESFireSetTestingMode(char *OutMessage, const char *InParams); +#define DFCOMMAND_COMM_MODE "DF_COMM_MODE" +CommandStatusIdType CommandDESFireGetCommMode(char *OutParam); +CommandStatusIdType CommandDESFireSetCommMode(char *OutMessage, const char *InParams); + #endif #endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c index c802dc7e..08962633 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c @@ -58,7 +58,14 @@ This notice must be retained at the top of all source files where indicated. .ExecParamFunc = NO_FUNCTION, .SetFunc = CommandDESFireSetTestingMode, .GetFunc = CommandDESFireGetTestingMode +}, { + .Command = DFCOMMAND_COMM_MODE, + .ExecFunc = NO_FUNCTION, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = CommandDESFireSetCommMode, + .GetFunc = CommandDESFireGetCommMode }, + #endif #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c index e4a30395..3ba04aaf 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c @@ -40,12 +40,11 @@ This notice must be retained at the top of all source files where indicated. CryptoKeyBufferType SessionKey = { 0 }; CryptoIVBufferType SessionIV = { 0 }; -BYTE SessionIVByteSize = { 0 }; +BYTE SessionIVByteSize = 0; +BYTE DesfireCommMode = DESFIRE_DEFAULT_COMMS_STANDARD; uint16_t AESCryptoKeySizeBytes = 0; CryptoAESConfig_t AESCryptoContext = { 0 }; -DesfireAESCryptoKey AESCryptoSessionKey = { 0 }; -DesfireAESCryptoKey AESCryptoIVBuffer = { 0 }; uint8_t Authenticated = 0x00; uint8_t AuthenticatedWithKey = DESFIRE_NOT_AUTHENTICATED; @@ -121,6 +120,38 @@ const char *GetCommSettingsDesc(uint8_t cryptoType) { } } +/* Code is adapted from @github/andrade/nfcjlib */ +bool generateSessionKey(uint8_t *sessionKey, uint8_t *rndA, uint8_t *rndB, uint16_t cryptoType) { + switch(cryptoType) { + case CRYPTO_TYPE_DES: + memcpy(sessionKey, rndA, 4); + memcpy(sessionKey + 4, rndB, 4); + break; + case CRYPTO_TYPE_2KTDEA: + memcpy(sessionKey, rndA, 4); + memcpy(sessionKey + 4, rndB, 4); + memcpy(sessionKey + 8, rndA + 4, 4); + memcpy(sessionKey + 12, rndB + 4, 4); + break; + case CRYPTO_TYPE_3K3DES: + memcpy(sessionKey, rndA, 4); + memcpy(sessionKey + 4, rndB, 4); + memcpy(sessionKey + 8, rndA + 6, 4); + memcpy(sessionKey + 12, rndB + 6, 4); + memcpy(sessionKey + 16, rndA + 12, 4); + memcpy(sessionKey + 20, rndB + 12, 4); + break; + case CRYPTO_TYPE_AES128: + memcpy(sessionKey, rndA, 4); + memcpy(sessionKey + 4, rndB, 4); + memcpy(sessionKey + 8, rndA + 12, 4); + memcpy(sessionKey + 12, rndB + 12, 4); + break; + default: + return false; + } + return true; +} BYTE GetCryptoKeyTypeFromAuthenticateMethod(BYTE authCmdMethod) { switch (authCmdMethod) { @@ -138,8 +169,7 @@ BYTE GetCryptoKeyTypeFromAuthenticateMethod(BYTE authCmdMethod) { } } -void InitAESCryptoKeyData(DesfireAESCryptoKey *cryptoKeyData) { - memset(cryptoKeyData, 0x00, sizeof(DesfireAESCryptoKey)); +void InitAESCryptoKeyData(void) { memset(&SessionKey[0], 0x00, CRYPTO_MAX_KEY_SIZE); memset(&SessionIV[0], 0x00, CRYPTO_MAX_BLOCK_SIZE); } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h index 1a651c25..2dbf77ae 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h @@ -45,6 +45,8 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_COMMS_CIPHERTEXT_AES128 (0x04) #define DESFIRE_DEFAULT_COMMS_STANDARD (DESFIRE_COMMS_PLAINTEXT) +extern BYTE DesfireCommMode; + #define CRYPTO_TYPE_ANY (0x00) #define CRYPTO_TYPE_DES (0x01) #define CRYPTO_TYPE_2KTDEA (0x0A) @@ -62,11 +64,11 @@ This notice must be retained at the top of all source files where indicated. /* Key sizes, block sizes (in bytes): */ #define CRYPTO_AES_KEY_SIZE (16) -#define CRYPTO_MAX_KEY_SIZE (24) +#define CRYPTO_MAX_KEY_SIZE (24) // (32) // Make it a multiple of the EEPROM_BLOCK_SIZE #define CRYPTO_MAX_BLOCK_SIZE (16) #define DESFIRE_AES_IV_SIZE (CRYPTO_AES_BLOCK_SIZE) #define DESFIRE_SESSION_KEY_SIZE (CRYPTO_3KTDEA_KEY_SIZE) -#define CRYPTO_CHALLENGE_RESPONSE_BYTES (8) +#define CRYPTO_CHALLENGE_RESPONSE_BYTES (16) typedef BYTE CryptoKeyBufferType[CRYPTO_MAX_KEY_SIZE]; typedef BYTE CryptoIVBufferType[CRYPTO_MAX_BLOCK_SIZE]; @@ -94,6 +96,8 @@ BYTE GetCryptoMethodCommSettings(uint8_t cryptoType); const char *GetCryptoMethodDesc(uint8_t cryptoType); const char *GetCommSettingsDesc(uint8_t cryptoType); +bool generateSessionKey(uint8_t *sessionKey, uint8_t *rndA, uint8_t *rndB, uint16_t cryptoType); + #define DESFIRE_MAC_LENGTH 4 #define DESFIRE_CMAC_LENGTH 8 // in bytes @@ -118,13 +122,9 @@ BYTE GetCryptoKeyTypeFromAuthenticateMethod(BYTE authCmdMethod); #include "../CryptoAES128.h" -typedef uint8_t DesfireAESCryptoKey[CRYPTO_AES_KEY_SIZE]; - extern CryptoAESConfig_t AESCryptoContext; -extern DesfireAESCryptoKey AESCryptoSessionKey; -extern DesfireAESCryptoKey AESCryptoIVBuffer; -void InitAESCryptoKeyData(DesfireAESCryptoKey *cryptoKeyData); +void InitAESCryptoKeyData(void); typedef void (*CryptoAESCBCFuncType)(uint16_t, void *, void *, uint8_t *, uint8_t *); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h index ec9bd6fa..2f80825c 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h @@ -34,20 +34,20 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_FIRMWARE_DEBUGGING (1) -#define DESFIRE_FIRMWARE_BUILD_TIMESTAMP (BUILD_DATE) -#define DESFIRE_FIRMWARE_GIT_COMMIT_ID (COMMIT_ID) -#define DESFIRE_FIRMWARE_REVISION ("0.0.2") -#define DESFIRE_FIRMWARE_PICC_LAYOUT_REVISION (0x02) +#define DESFIRE_FIRMWARE_BUILD_TIMESTAMP PSTR(BUILD_DATE) +#define DESFIRE_FIRMWARE_GIT_COMMIT_ID PSTR(COMMIT_ID) +#define DESFIRE_FIRMWARE_REVISION PSTR("1.0.0-testing") +#define DESFIRE_FIRMWARE_PICC_LAYOUT_REVISION (0x03) #define DESFIRE_LITTLE_ENDIAN (1) -#define DESFIRE_PICC_STRUCT_PACKING //__attribute__((aligned(1))) +#define DESFIRE_PICC_STRUCT_PACKING __attribute__((aligned(4))) #define DESFIRE_FIRMWARE_PACKING __attribute__((packed)) -#define DESFIRE_FIRMWARE_ALIGNAT __attribute__((aligned(1))) -#define DESFIRE_PICC_ARRAY_ALIGNAT //__attribute__((aligned(1))) -#define DESFIRE_FIRMWARE_ARRAY_ALIGNAT //__attribute__((aligned(1))) -#define DESFIRE_FIRMWARE_ENUM_PACKING //__attribute__((aligned(1))) -#define DESFIRE_FIRMWARE_NOINIT //__attribute__ ((section (".noinit"))) +#define DESFIRE_FIRMWARE_ALIGNAT __attribute__((aligned(4))) +#define DESFIRE_PICC_ARRAY_ALIGNAT __attribute__((aligned(4))) +#define DESFIRE_FIRMWARE_ARRAY_ALIGNAT __attribute__((aligned(4))) +#define DESFIRE_FIRMWARE_ENUM_PACKING __attribute__((aligned(4))) +#define DESFIRE_FIRMWARE_NOINIT __attribute__ ((section (".noinit"))) /* Some standard boolean interpreted and other values for types and return values: */ typedef int BOOL; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 257b2675..0e654cca 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -430,7 +430,7 @@ uint16_t DesfireCmdFreeMemory(uint8_t *Buffer, uint16_t ByteCount) { uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId, Status; BYTE keySize; - BYTE **Key, **IVBuffer; + BYTE **Key; /* Reset authentication state right away */ InvalidateAuthState(SelectedApp.Slot == DESFIRE_PICC_APP_SLOT); @@ -476,6 +476,14 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { DesfireCommandState.RndB[5] = 0x11; DesfireCommandState.RndB[6] = 0x22; DesfireCommandState.RndB[7] = 0x33; + DesfireCommandState.RndB[8] = 0xCA; + DesfireCommandState.RndB[9] = 0xFE; + DesfireCommandState.RndB[10] = 0xBA; + DesfireCommandState.RndB[11] = 0xBE; + DesfireCommandState.RndB[12] = 0x00; + DesfireCommandState.RndB[13] = 0x11; + DesfireCommandState.RndB[14] = 0x22; + DesfireCommandState.RndB[15] = 0x33; } LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); @@ -483,7 +491,7 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { uint8_t rndBPadded[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; memset(rndBPadded, 0x00, 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(rndBPadded, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, rndBPadded, + Encrypt3DESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, rndBPadded, &Buffer[1], NULL, *Key); /* Scrub the key */ @@ -492,13 +500,13 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { /* Done */ DesfireState = DESFIRE_LEGACY_AUTHENTICATE2; Buffer[0] = STATUS_ADDITIONAL_FRAME; - return DESFIRE_STATUS_RESPONSE_SIZE + CRYPTO_CHALLENGE_RESPONSE_BYTES; + return DESFIRE_STATUS_RESPONSE_SIZE + 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES; } uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId; BYTE cryptoKeyType, keySize; - BYTE **Key, **IVBuffer; + BYTE **Key; /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; @@ -543,8 +551,7 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, *Key); - /* Scrub the key */ - memset(*Key, 0, keySize); + generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_3K3DES); /* Return the status on success */ Buffer[0] = STATUS_OPERATION_OK; @@ -1682,7 +1689,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId, Status; BYTE keySize; - BYTE **Key, **IVBuffer; + BYTE **Key; /* Reset authentication state right away */ InvalidateAuthState(SelectedApp.Slot == DESFIRE_PICC_APP_SLOT); @@ -1729,14 +1736,22 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { DesfireCommandState.RndB[5] = 0x11; DesfireCommandState.RndB[6] = 0x22; DesfireCommandState.RndB[7] = 0x33; + DesfireCommandState.RndB[8] = 0xCA; + DesfireCommandState.RndB[9] = 0xFE; + DesfireCommandState.RndB[10] = 0xBA; + DesfireCommandState.RndB[11] = 0xBE; + DesfireCommandState.RndB[12] = 0x00; + DesfireCommandState.RndB[13] = 0x11; + DesfireCommandState.RndB[14] = 0x22; + DesfireCommandState.RndB[15] = 0x33; } LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Encrypt RndB with the selected key and transfer it back to the PCD */ - uint8_t rndBPadded[CRYPTO_CHALLENGE_RESPONSE_BYTES]; - memset(rndBPadded, 0x00, CRYPTO_CHALLENGE_RESPONSE_BYTES); + uint8_t rndBPadded[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; + memset(rndBPadded, 0x00, 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(rndBPadded, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, rndBPadded, + Encrypt3DESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, rndBPadded, &Buffer[1], NULL, *Key); /* Scrub the key */ @@ -1745,14 +1760,14 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { /* Done */ DesfireState = DESFIRE_ISO_AUTHENTICATE2; Buffer[0] = STATUS_ADDITIONAL_FRAME; - return DESFIRE_STATUS_RESPONSE_SIZE + CRYPTO_CHALLENGE_RESPONSE_BYTES; + return DESFIRE_STATUS_RESPONSE_SIZE + 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES; } uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId; BYTE cryptoKeyType, keySize; - BYTE **Key, **IVBuffer; + BYTE **Key; /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; @@ -1796,9 +1811,8 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, *Key); - - /* Scrub the key */ - memset(*Key, 0, keySize); + + generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_3K3DES); /* Return the status on success */ Buffer[0] = STATUS_OPERATION_OK; @@ -1832,12 +1846,11 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { return DESFIRE_STATUS_RESPONSE_SIZE; } - InitAESCryptoKeyData(&AESCryptoSessionKey); - InitAESCryptoKeyData(&AESCryptoIVBuffer); + InitAESCryptoKeyData(); keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_AES128); - *Key = AESCryptoSessionKey; - *IVBuffer = AESCryptoIVBuffer; + *Key = SessionKey; + *IVBuffer = SessionIV; /* Indicate that we are in AES key authentication land */ DesfireCommandState.KeyId = KeyId; @@ -1863,8 +1876,16 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { DesfireCommandState.RndB[5] = 0x11; DesfireCommandState.RndB[6] = 0x22; DesfireCommandState.RndB[7] = 0x33; + DesfireCommandState.RndB[8] = 0xCA; + DesfireCommandState.RndB[9] = 0xFE; + DesfireCommandState.RndB[10] = 0xBA; + DesfireCommandState.RndB[11] = 0xBE; + DesfireCommandState.RndB[12] = 0x00; + DesfireCommandState.RndB[13] = 0x11; + DesfireCommandState.RndB[14] = 0x22; + DesfireCommandState.RndB[15] = 0x33; } - //LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Encrypt RndB with the selected key and transfer it back to the PCD */ uint8_t rndBPadded[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; @@ -1889,18 +1910,18 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId; BYTE cryptoKeyType, keySize; - BYTE **Key, **IVBuffer; + BYTE **Key; /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; /* Validate command length */ - if (ByteCount != CRYPTO_AES_BLOCK_SIZE + 1) { + if (ByteCount != 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES + 1) { Buffer[0] = STATUS_LENGTH_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } /* Reset parameters for authentication from the first exchange */ - Key = &AESCryptoSessionKey; + Key = &SessionKey; keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_AES128); KeyId = DesfireCommandState.KeyId; cryptoKeyType = DesfireCommandState.CryptoMethodType; @@ -1928,20 +1949,18 @@ uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount) { AuthenticatedWithKey = KeyId; AuthenticatedWithPICCMasterKey = (SelectedApp.Slot == DESFIRE_PICC_APP_SLOT) && (KeyId == DESFIRE_MASTER_KEY_ID); - memcpy(SessionKey, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Encrypt and send back the once rotated RndA buffer to the PCD */ memset(challengeRndAB, 0x00, CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(challengeRndAB, challengeRndA, CRYPTO_CHALLENGE_RESPONSE_BYTES); RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - CryptoAESEncryptBuffer(CRYPTO_AES_BLOCK_SIZE, challengeRndAB, &Buffer[1], NULL, *Key); + CryptoAESEncryptBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, *Key); - /* Scrub the key */ - memset(*Key, 0, keySize); + generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_AES128); /* Return the status on success */ Buffer[0] = STATUS_OPERATION_OK; - return DESFIRE_STATUS_RESPONSE_SIZE + CRYPTO_AES_BLOCK_SIZE; + return DESFIRE_STATUS_RESPONSE_SIZE + CRYPTO_CHALLENGE_RESPONSE_BYTES; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireKeyUtils.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireKeyUtils.h deleted file mode 100644 index 502235e1..00000000 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireKeyUtils.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -The DESFire stack portion of this firmware source -is free software written by Maxie Dion Schmidt (@maxieds): -You can redistribute it and/or modify -it under the terms of this license. - -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. - -The complete source distribution of -this firmware is available at the following link: -https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack. - -Based in part on the original DESFire code created by -@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at -https://github.com/dev-zzo/ChameleonMini/tree/desfire. - -This notice must be retained at the top of all source files where indicated. -*/ - -/* - * DESFireKeyUtils.h : - * Maxie D. Schmidt (github.com/maxieds) - */ - -#ifndef __DESFIRE_KEY_UTILS_H__ -#define __DESFIRE_KEY_UTILS_H__ - -#include "DESFireCrypto.h" - -/* TODO: Placeholder for: - * => Key (re)initialization - * => Configuring the session key on the fly - * => CommSettings: PLAIN | MACED | ENCIPHERD - * => Possibly others - */ - -#endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c index bdb8d304..3218995c 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c @@ -26,6 +26,7 @@ This notice must be retained at the top of all source files where indicated. #ifdef CONFIG_MF_DESFIRE_SUPPORT +#include "../../Common.h" #include "../../Memory.h" #include "DESFireMemoryOperations.h" @@ -33,33 +34,55 @@ This notice must be retained at the top of all source files where indicated. #include "DESFireFile.h" #include "DESFireLogging.h" +#define BLOCKWISE_IO_MULTIPLIER (DESFIRE_EEPROM_BLOCK_SIZE) +#define BLOCK_TRANSFER_SIZE (DESFIRE_EEPROM_BLOCK_SIZE) + volatile char __InternalStringBuffer[STRING_BUFFER_SIZE] = { 0 }; char __InternalStringBuffer2[DATA_BUFFER_SIZE_SMALL] = { 0 }; void ReadBlockBytes(void *Buffer, SIZET StartBlock, SIZET Count) { - if (StartBlock * DESFIRE_EEPROM_BLOCK_SIZE >= MEMORY_SIZE_PER_SETTING) { - const char *rbbLogMsg = PSTR("RBB Start Block Too Large -- %d -- %d"); - DEBUG_PRINT_P(rbbLogMsg, StartBlock, StartBlock * DESFIRE_EEPROM_BLOCK_SIZE); + if (StartBlock >= MEMORY_SIZE_PER_SETTING) { + const char *rbbLogMsg = PSTR("RBB Too Lg - %d / %d"); + DEBUG_PRINT_P(rbbLogMsg, StartBlock, MEMORY_SIZE_PER_SETTING); return; } - //else if(StartBlock == 0) { - // const char *logWarningMsg = PSTR("WARNING: Reading NULL Address!"); - // DEBUG_PRINT_P(logWarningMsg); - //} - MemoryReadBlockInSetting(Buffer, StartBlock * DESFIRE_EEPROM_BLOCK_SIZE, Count); + uint16_t numBlocks = DESFIRE_BYTES_TO_BLOCKS(Count); + uint16_t blockModDiff = Count % BLOCK_TRANSFER_SIZE; + if (blockModDiff == 0) { + MemoryReadBlockInSetting(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count); + } else { + if (Count > blockModDiff) { + MemoryReadBlockInSetting(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count - blockModDiff); + } + StartBlock += numBlocks - 1; + uint8_t fullBlock[BLOCK_TRANSFER_SIZE]; + MemoryReadBlockInSetting(fullBlock, StartBlock * BLOCKWISE_IO_MULTIPLIER, BLOCK_TRANSFER_SIZE); + // TODO: Reverse Mod buf when read ??? + //ReverseBuffer(fullBlock, BLOCK_TRANSFER_SIZE); + memcpy(Buffer + Count - blockModDiff, fullBlock, blockModDiff); + } } void WriteBlockBytesMain(const void *Buffer, SIZET StartBlock, SIZET Count) { - if (StartBlock * DESFIRE_EEPROM_BLOCK_SIZE >= MEMORY_SIZE_PER_SETTING) { - const char *wbbLogMsg = PSTR("WBB Start Block Too Large -- %d -- %s"); - DEBUG_PRINT_P(wbbLogMsg, StartBlock, __InternalStringBuffer2); + if (StartBlock >= MEMORY_SIZE_PER_SETTING) { + const char *wbbLogMsg = PSTR("WBB Too Lg - %d / %d"); + DEBUG_PRINT_P(wbbLogMsg, StartBlock, MEMORY_SIZE_PER_SETTING); return; } - //else if(StartBlock == 0) { - // const char *logWarningMsg = PSTR("WARNING: Writing NULL! -- %s"); - // DEBUG_PRINT_P(logWarningMsg, __InternalStringBuffer2); - //} - MemoryWriteBlockInSetting(Buffer, StartBlock * DESFIRE_EEPROM_BLOCK_SIZE, Count); + uint16_t numBlocks = DESFIRE_BYTES_TO_BLOCKS(Count); + uint16_t blockModDiff = Count % BLOCK_TRANSFER_SIZE; + if (blockModDiff == 0) { + MemoryWriteBlockInSetting(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count); + } else { + if (Count > blockModDiff) { + MemoryWriteBlockInSetting(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count - blockModDiff); + } + StartBlock += numBlocks - 1; + uint8_t fullBlock[BLOCK_TRANSFER_SIZE]; + memcpy(fullBlock, Buffer + Count - blockModDiff, blockModDiff); + memset(fullBlock + blockModDiff, 0x00, BLOCK_TRANSFER_SIZE - blockModDiff); + MemoryWriteBlockInSetting(fullBlock, StartBlock * BLOCKWISE_IO_MULTIPLIER, BLOCK_TRANSFER_SIZE); + } } void CopyBlockBytes(SIZET DestBlock, SIZET SrcBlock, SIZET Count) { @@ -80,7 +103,7 @@ uint16_t AllocateBlocksMain(uint16_t BlockCount) { uint16_t Block; /* Check if we have space */ Block = Picc.FirstFreeBlock; - if (Block + BlockCount < Block || Block + BlockCount >= MEMORY_SIZE_PER_SETTING / DESFIRE_EEPROM_BLOCK_SIZE) { + if (Block + BlockCount < Block || Block + BlockCount >= MEMORY_SIZE_PER_SETTING / BLOCKWISE_IO_MULTIPLIER) { return 0; } Picc.FirstFreeBlock = Block + BlockCount; @@ -89,22 +112,6 @@ uint16_t AllocateBlocksMain(uint16_t BlockCount) { return Block; } -/* TODO: Why doesn't this work ??? -- It freezes the AVR chip when run !! */ -void MemsetBlockBytes(uint8_t initValue, SIZET startBlock, SIZET byteCount) { - BYTE fillerBuf[DESFIRE_EEPROM_BLOCK_SIZE]; - memset(fillerBuf, initValue, DESFIRE_EEPROM_BLOCK_SIZE); - SIZET writeAddr = startBlock; - while (byteCount > 0) { - WriteBlockBytes(&fillerBuf[0], writeAddr, MIN(DESFIRE_EEPROM_BLOCK_SIZE, byteCount)); - ++writeAddr; - if (byteCount > DESFIRE_EEPROM_BLOCK_SIZE) { - byteCount -= DESFIRE_EEPROM_BLOCK_SIZE; - } else { - break; - } - } -} - uint8_t GetCardCapacityBlocks(void) { uint8_t MaxFreeBlocks; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h index d3c625b9..9f077430 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h @@ -33,8 +33,8 @@ This notice must be retained at the top of all source files where indicated. /* Reserve some space on the stack (text / data segment) for intermediate storage of strings and data we need to write so we do not have to rely on a bothersome heap-based scheme for passing pointers to functions: */ -#define DATA_BUFFER_SIZE_SMALL (32) -#define STRING_BUFFER_SIZE (92) +#define DATA_BUFFER_SIZE_SMALL (16) +#define STRING_BUFFER_SIZE (32) extern volatile char __InternalStringBuffer[STRING_BUFFER_SIZE]; extern char __InternalStringBuffer2[DATA_BUFFER_SIZE_SMALL]; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index 83c9376b..20660c30 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -55,7 +55,6 @@ BYTE APP_CACHE_MAX_KEY_BLOCK_SIZE = DESFIRE_BYTES_TO_BLOCKS(CRYPTO_MAX_KEY_SIZE) SIZET DESFIRE_PICC_INFO_BLOCK_ID = 0; SIZET DESFIRE_APP_DIR_BLOCK_ID = 0; -SIZET DESFIRE_APP_CACHE_DATA_ARRAY_BLOCK_ID = 0; SIZET DESFIRE_INITIAL_FIRST_FREE_BLOCK_ID = 0; SIZET DESFIRE_FIRST_FREE_BLOCK_ID = 0; SIZET CardCapacityBlocks = 0; @@ -64,9 +63,8 @@ void InitBlockSizes(void) { DESFIRE_PICC_INFO_BLOCK_ID = 0; DESFIRE_APP_DIR_BLOCK_ID = DESFIRE_PICC_INFO_BLOCK_ID + DESFIRE_BYTES_TO_BLOCKS(sizeof(DESFirePICCInfoType)); - DESFIRE_APP_CACHE_DATA_ARRAY_BLOCK_ID = DESFIRE_APP_DIR_BLOCK_ID + - DESFIRE_BYTES_TO_BLOCKS(sizeof(DESFireAppDirType)); - DESFIRE_FIRST_FREE_BLOCK_ID = DESFIRE_APP_CACHE_DATA_ARRAY_BLOCK_ID; + DESFIRE_FIRST_FREE_BLOCK_ID = DESFIRE_APP_DIR_BLOCK_ID + + DESFIRE_BYTES_TO_BLOCKS(sizeof(DESFireAppDirType)); DESFIRE_INITIAL_FIRST_FREE_BLOCK_ID = DESFIRE_FIRST_FREE_BLOCK_ID; } @@ -80,7 +78,6 @@ TransferStateType TransferState = { 0 }; void SynchronizePICCInfo(void) { WriteBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); - //MemoryStore(); } /* TODO: Currently, everything is transfered in plaintext, without checksums */ @@ -183,41 +180,43 @@ uint8_t WriteDataFilterSetup(uint8_t CommSettings) { * PICC management routines */ -void InitialisePiccBackendEV0(uint8_t StorageSize) { +void InitialisePiccBackendEV0(uint8_t StorageSize, bool formatPICC) { #ifdef DESFIRE_RUN_CRYPTO_TESTING_PROCEDURE RunCryptoUnitTests(); #endif /* Init backend */ InitBlockSizes(); CardCapacityBlocks = StorageSize; + MemoryRecall(); ReadBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); - if (Picc.Uid[0] == PICC_FORMAT_BYTE && Picc.Uid[1] == PICC_FORMAT_BYTE && - Picc.Uid[2] == PICC_FORMAT_BYTE && Picc.Uid[3] == PICC_FORMAT_BYTE) { - snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, PSTR("Factory resetting the device")); + if (formatPICC) { + snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, PSTR("Factory reset -- EV0")); LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) __InternalStringBuffer, StringLength(__InternalStringBuffer, STRING_BUFFER_SIZE)); FactoryFormatPiccEV0(); } else { ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); + SelectPiccApp(); } } -void InitialisePiccBackendEV1(uint8_t StorageSize) { +void InitialisePiccBackendEV1(uint8_t StorageSize, bool formatPICC) { #ifdef DESFIRE_RUN_CRYPTO_TESTING_PROCEDURE RunCryptoUnitTests(); #endif /* Init backend */ InitBlockSizes(); CardCapacityBlocks = StorageSize; + MemoryRecall(); ReadBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); - if (Picc.Uid[0] == PICC_FORMAT_BYTE && Picc.Uid[1] == PICC_FORMAT_BYTE && - Picc.Uid[2] == PICC_FORMAT_BYTE && Picc.Uid[3] == PICC_FORMAT_BYTE) { - snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, PSTR("Factory resetting the device")); + if (formatPICC) { + snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, PSTR("Factory reset -- EV1")); LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) __InternalStringBuffer, StringLength(__InternalStringBuffer, STRING_BUFFER_SIZE)); FactoryFormatPiccEV1(StorageSize); } else { ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); + SelectPiccApp(); } } @@ -274,6 +273,7 @@ void FormatPicc(void) { SynchronizeAppDir(); /* Initialize the root app data */ CreatePiccApp(); + MemoryStore(); } void CreatePiccApp(void) { @@ -321,6 +321,10 @@ void FactoryFormatPiccEV1(uint8_t StorageSize) { BYTE uidData[DESFIRE_UID_SIZE]; RandomGetBuffer(uidData, DESFIRE_UID_SIZE); memcpy(&Picc.Uid[0], uidData, DESFIRE_UID_SIZE); + /* Conform to NXP Application Note AN10927 about the first + * byte of a randomly generated UID (refer to section 2.1.1). + */ + Picc.Uid[0] = ISO14443A_UID0_RANDOM; /* Initialize params to look like EV1 */ Picc.StorageSize = StorageSize; Picc.HwVersionMajor = DESFIRE_HW_MAJOR_EV1; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.h index e657537d..8ddfb0ff 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.h @@ -114,8 +114,8 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings); uint8_t WriteDataFilterSetup(uint8_t CommSettings); /* PICC management */ -void InitialisePiccBackendEV0(uint8_t StorageSize); -void InitialisePiccBackendEV1(uint8_t StorageSize); +void InitialisePiccBackendEV0(uint8_t StorageSize, bool formatPICC); +void InitialisePiccBackendEV1(uint8_t StorageSize, bool formatPICC); void ResetPiccBackend(void); bool IsEmulatingEV1(void); void GetPiccHardwareVersionInfo(uint8_t *Buffer); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index ba5c2142..9233ae30 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -37,13 +37,13 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_ISO7816_CLA 0x00 /* Storage allocation constants */ -#define DESFIRE_EEPROM_BLOCK_SIZE 32 // 16 /* Bytes */ +#define DESFIRE_EEPROM_BLOCK_SIZE (4) // (8) // (16) /* Bytes */ #define DESFIRE_BYTES_TO_BLOCKS(x) \ ( ((x) + DESFIRE_EEPROM_BLOCK_SIZE - 1) / DESFIRE_EEPROM_BLOCK_SIZE ) #define DESFIRE_UID_SIZE ISO14443A_UID_SIZE_DOUBLE -#define DESFIRE_MAX_PAYLOAD_SIZE 55 // 64 /* Bytes */ +#define DESFIRE_MAX_PAYLOAD_SIZE (64) /* Bytes */ /* * Definitions pertaining to on-card data @@ -145,7 +145,7 @@ This notice must be retained at the top of all source files where indicated. * Defines the global PICC configuration. * This is located in the very first block on the card. */ -#define PICC_FORMAT_BYTE (0xff) +#define PICC_FORMAT_BYTE (0xff) // (0xf7) #define PICC_EMPTY_BYTE (0x00) typedef struct DESFIRE_FIRMWARE_PACKING { @@ -201,7 +201,6 @@ extern BYTE APP_CACHE_MAX_KEY_BLOCK_SIZE; extern SIZET DESFIRE_PICC_INFO_BLOCK_ID; extern SIZET DESFIRE_APP_DIR_BLOCK_ID; -extern SIZET DESFIRE_APP_CACHE_DATA_ARRAY_BLOCK_ID; extern SIZET DESFIRE_INITIAL_FIRST_FREE_BLOCK_ID; extern SIZET DESFIRE_FIRST_FREE_BLOCK_ID; extern SIZET CardCapacityBlocks; diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 6390460a..c6335aab 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -43,6 +43,10 @@ This notice must be retained at the top of all source files where indicated. #include "DESFire/DESFireLogging.h" #include "DESFire/DESFireUtils.h" +#define MIFARE_DESFIRE_EV0 (0x00) +#define MIFARE_DESFIRE_EV1 (0x01) +#define MIFARE_DESFIRE_EV2 (0x02) + DesfireStateType DesfireState = DESFIRE_HALT; DesfireStateType DesfirePreviousState = DESFIRE_IDLE; bool DesfireFromHalt = false; @@ -51,43 +55,52 @@ BYTE DesfireCmdCLA = DESFIRE_NATIVE_CLA; /* Dispatching routines */ void MifareDesfireReset(void) {} -void MifareDesfireEV0AppInit(void) { - /* Init lower layers: nothing for now */ +static void MifareDesfireAppInitLocal(uint8_t StorageSize, uint8_t Version, bool FormatPICC) { ResetLocalStructureData(); DesfireState = DESFIRE_IDLE; DesfireFromHalt = false; - InitialisePiccBackendEV0(DESFIRE_STORAGE_SIZE_4K); - /* The rest is handled in reset */ + switch (Version) { + case MIFARE_DESFIRE_EV0: + InitialisePiccBackendEV1(StorageSize, FormatPICC); + break; + case MIFARE_DESFIRE_EV1: + default: /* Fall through */ + InitialisePiccBackendEV0(StorageSize, FormatPICC); + break; + } + DesfireCommMode = DESFIRE_DEFAULT_COMMS_STANDARD; } -static void MifareDesfireEV1AppInit(uint8_t StorageSize) { - /* Init lower layers: nothing for now */ - ResetLocalStructureData(); - DesfireState = DESFIRE_IDLE; - DesfireFromHalt = false; - InitialisePiccBackendEV1(StorageSize); - /* The rest is handled in reset */ +void MifareDesfireEV0AppInit(void) { + MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_4K, MIFARE_DESFIRE_EV0, false); +} + +void MifareDesfireEV0AppInitRunOnce(void) { + MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_4K, MIFARE_DESFIRE_EV0, true); } void MifareDesfire2kEV1AppInit(void) { - ResetLocalStructureData(); - DesfireState = DESFIRE_IDLE; - DesfireFromHalt = false; - MifareDesfireEV1AppInit(DESFIRE_STORAGE_SIZE_2K); + MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_2K, MIFARE_DESFIRE_EV1, false); +} + +void MifareDesfire2kEV1AppInitRunOnce(void) { + MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_2K, MIFARE_DESFIRE_EV1, true); } void MifareDesfire4kEV1AppInit(void) { - ResetLocalStructureData(); - DesfireState = DESFIRE_IDLE; - DesfireFromHalt = false; - MifareDesfireEV1AppInit(DESFIRE_STORAGE_SIZE_4K); + MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_4K, MIFARE_DESFIRE_EV1, false); +} + +void MifareDesfire4kEV1AppInitRunOnce(void) { + MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_4K, MIFARE_DESFIRE_EV1, true); } void MifareDesfire8kEV1AppInit(void) { - ResetLocalStructureData(); - DesfireState = DESFIRE_IDLE; - DesfireFromHalt = false; - MifareDesfireEV1AppInit(DESFIRE_STORAGE_SIZE_8K); + MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_8K, MIFARE_DESFIRE_EV1, false); +} + +void MifareDesfire8kEV1AppInitRunOnce(void) { + MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_8K, MIFARE_DESFIRE_EV1, true); } void MifareDesfireAppReset(void) { @@ -164,8 +177,8 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { size_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; DesfireCmdCLA = Buffer[0]; if ((ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) || Iso7816CLA(DesfireCmdCLA)) { - // Wrapped native command structure: + Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) || Iso7816CLA(DesfireCmdCLA)) { + // Wrapped native command structure: /* Unwrap the PDU from ISO 7816-4 */ // Check CRC bytes appended to the buffer: // -- Actually, just ignore parity problems if they exist, @@ -197,9 +210,6 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { ByteCount += 2; } else { /* Re-wrap into ISO 7816-4 */ - //Buffer[ByteCount] = Buffer[0]; - //Buffer[ByteCount + 1] = Buffer[1]; - //memmove(&Buffer[0], &Buffer[2], ByteCount - 2); ISO14443AAppendCRCA(Buffer, ByteCount); ByteCount += 2; } @@ -252,8 +262,6 @@ void ResetLocalStructureData(void) { memset(&SessionKey, 0x00, sizeof(CryptoKeyBufferType)); memset(&SessionIV, 0x00, sizeof(CryptoIVBufferType)); SessionIVByteSize = 0x00; - memset(&AESCryptoSessionKey, 0x00, sizeof(DesfireAESCryptoKey)); - memset(&AESCryptoIVBuffer, 0x00, sizeof(DesfireAESCryptoKey)); } void MifareDesfireGetUid(ConfigurationUidType Uid) { diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.h b/Firmware/Chameleon-Mini/Application/MifareDESFire.h index 2465b4d4..add26775 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.h +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.h @@ -43,9 +43,13 @@ This notice must be retained at the top of all source files where indicated. void ResetLocalStructureData(void); void MifareDesfireReset(void); void MifareDesfireEV0AppInit(void); +void MifareDesfireEV0AppInitRunOnce(void); void MifareDesfire2kEV1AppInit(void); +void MifareDesfire2kEV1AppInitRunOnce(void); void MifareDesfire4kEV1AppInit(void); +void MifareDesfire4kEV1AppInitRunOnce(void); void MifareDesfire8kEV1AppInit(void); +void MifareDesfire8kEV1AppInitRunOnce(void); void MifareDesfireAppReset(void); void MifareDesfireAppTick(void); void MifareDesfireAppTask(void); diff --git a/Firmware/Chameleon-Mini/Common.h b/Firmware/Chameleon-Mini/Common.h index d9472807..0581956b 100644 --- a/Firmware/Chameleon-Mini/Common.h +++ b/Firmware/Chameleon-Mini/Common.h @@ -70,4 +70,14 @@ INLINE uint8_t StringLength(const char *Str, uint8_t MaxLen) { return StrLen; } +INLINE void ReverseBuffer(uint8_t *Buffer, uint16_t ByteCount) { + uint16_t BufferIndex = 0; + while(BufferIndex < ByteCount) { + uint8_t NextByte = Buffer[BufferIndex]; + Buffer[BufferIndex] = Buffer[ByteCount - 1 - BufferIndex]; + Buffer[ByteCount - 1 - BufferIndex] = NextByte; + ++BufferIndex; + } +} + #endif /* COMMON_H_ */ diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index a4ec6054..e74ff203 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -69,7 +69,10 @@ static const MapEntryType PROGMEM ConfigurationMap[] = { { .Id = CONFIG_EM4233, .Text = "EM4233" }, #endif #ifdef CONFIG_MF_DESFIRE_SUPPORT - { .Id = CONFIG_MF_DESFIRE, .Text = "MF_DESFIRE" }, + { .Id = CONFIG_MF_DESFIRE, .Text = "MF_DESFIRE" }, + { .Id = CONFIG_MF_DESFIRE_2KEV1, .Text = "MF_DESFIRE_2KEV1" }, + { .Id = CONFIG_MF_DESFIRE_4KEV1, .Text = "MF_DESFIRE_4KEV1" }, + { .Id = CONFIG_MF_DESFIRE_8KEV1, .Text = "MF_DESFIRE_8KEV1" }, #endif }; @@ -88,14 +91,14 @@ static uint16_t ApplicationProcessDummy(uint8_t *ByteBuffer, uint16_t ByteCount) static void ApplicationGetUidDummy(ConfigurationUidType Uid) { } static void ApplicationSetUidDummy(ConfigurationUidType Uid) { } - static const PROGMEM ConfigurationType ConfigurationTable[] = { [CONFIG_NONE] = { .CodecInitFunc = CodecInitDummy, .CodecDeInitFunc = CodecDeInitDummy, .CodecTaskFunc = CodecTaskDummy, .ApplicationInitFunc = ApplicationInitDummy, - .ApplicationResetFunc = ApplicationResetDummy, + .ApplicationInitRunOnceFunc = ApplicationInitDummy, + .ApplicationResetFunc = ApplicationResetDummy, .ApplicationTaskFunc = ApplicationTaskDummy, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = ApplicationProcessDummy, @@ -112,7 +115,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareUltralightAppInit, - .ApplicationResetFunc = MifareUltralightAppReset, + .ApplicationInitRunOnceFunc = MifareUltralightAppInit, + .ApplicationResetFunc = MifareUltralightAppReset, .ApplicationTaskFunc = MifareUltralightAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareUltralightAppProcess, @@ -128,7 +132,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareUltralightCAppInit, - .ApplicationResetFunc = MifareUltralightCAppReset, + .ApplicationInitRunOnceFunc = MifareUltralightCAppInit, + .ApplicationResetFunc = MifareUltralightCAppReset, .ApplicationTaskFunc = MifareUltralightAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareUltralightAppProcess, @@ -144,7 +149,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareUltralightEV11AppInit, - .ApplicationResetFunc = MifareUltralightAppReset, + .ApplicationInitRunOnceFunc = MifareUltralightEV11AppInit, + .ApplicationResetFunc = MifareUltralightAppReset, .ApplicationTaskFunc = MifareUltralightAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareUltralightAppProcess, @@ -160,7 +166,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareUltralightEV12AppInit, - .ApplicationResetFunc = MifareUltralightAppReset, + .ApplicationInitRunOnceFunc = MifareUltralightEV12AppInit, + .ApplicationResetFunc = MifareUltralightAppReset, .ApplicationTaskFunc = MifareUltralightAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareUltralightAppProcess, @@ -178,7 +185,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareClassicAppInitMini4B, - .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationInitRunOnceFunc = MifareClassicAppInitMini4B, + .ApplicationResetFunc = MifareClassicAppReset, .ApplicationTaskFunc = MifareClassicAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareClassicAppProcess, @@ -196,7 +204,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareClassicAppInit1K, - .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationInitRunOnceFunc = MifareClassicAppInit1K, + .ApplicationResetFunc = MifareClassicAppReset, .ApplicationTaskFunc = MifareClassicAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareClassicAppProcess, @@ -214,7 +223,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareClassicAppInit1K7B, - .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationInitRunOnceFunc = MifareClassicAppInit1K7B, + .ApplicationResetFunc = MifareClassicAppReset, .ApplicationTaskFunc = MifareClassicAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareClassicAppProcess, @@ -232,7 +242,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareClassicAppInit4K, - .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationInitRunOnceFunc = MifareClassicAppInit4K, + .ApplicationResetFunc = MifareClassicAppReset, .ApplicationTaskFunc = MifareClassicAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareClassicAppProcess, @@ -250,7 +261,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareClassicAppInit4K7B, - .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationInitRunOnceFunc = MifareClassicAppInit4K7B, + .ApplicationResetFunc = MifareClassicAppReset, .ApplicationTaskFunc = MifareClassicAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareClassicAppProcess, @@ -268,7 +280,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = Sniff14443ACodecDeInit, .CodecTaskFunc = Sniff14443ACodecTask, .ApplicationInitFunc = Sniff14443AAppInit, - .ApplicationResetFunc = Sniff14443AAppReset, + .ApplicationInitRunOnceFunc = Sniff14443AAppInit, + .ApplicationResetFunc = Sniff14443AAppReset, .ApplicationTaskFunc = Sniff14443AAppTask, .ApplicationTickFunc = Sniff14443AAppTick, .ApplicationProcessFunc = Sniff14443AAppProcess, @@ -286,7 +299,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = Reader14443ACodecDeInit, .CodecTaskFunc = Reader14443ACodecTask, .ApplicationInitFunc = Reader14443AAppInit, - .ApplicationResetFunc = Reader14443AAppReset, + .ApplicationInitRunOnceFunc = Reader14443AAppInit, + .ApplicationResetFunc = Reader14443AAppReset, .ApplicationTaskFunc = Reader14443AAppTask, .ApplicationTickFunc = Reader14443AAppTick, .ApplicationProcessFunc = Reader14443AAppProcess, @@ -304,7 +318,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, .ApplicationInitFunc = VicinityAppInit, - .ApplicationResetFunc = VicinityAppReset, + .ApplicationInitRunOnceFunc = VicinityAppInit, + .ApplicationResetFunc = VicinityAppReset, .ApplicationTaskFunc = VicinityAppTask, .ApplicationTickFunc = VicinityAppTick, .ApplicationProcessFunc = VicinityAppProcess, @@ -322,7 +337,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, .ApplicationInitFunc = ApplicationInitDummy, - .ApplicationResetFunc = ApplicationResetDummy, + .ApplicationInitRunOnceFunc = ApplicationInitDummy, + .ApplicationResetFunc = ApplicationResetDummy, .ApplicationTaskFunc = ApplicationTaskDummy, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = ApplicationProcessDummy, @@ -340,7 +356,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, .ApplicationInitFunc = Sl2s2002AppInit, - .ApplicationResetFunc = Sl2s2002AppReset, + .ApplicationInitRunOnceFunc = Sl2s2002AppInit, + .ApplicationResetFunc = Sl2s2002AppReset, .ApplicationTaskFunc = Sl2s2002AppTask, .ApplicationTickFunc = Sl2s2002AppTick, .ApplicationProcessFunc = Sl2s2002AppProcess, @@ -358,7 +375,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, .ApplicationInitFunc = TITagitstandardAppInit, - .ApplicationResetFunc = TITagitstandardAppReset, + .ApplicationInitRunOnceFunc = TITagitstandardAppInit, + .ApplicationResetFunc = TITagitstandardAppReset, .ApplicationTaskFunc = TITagitstandardAppTask, .ApplicationTickFunc = TITagitstandardAppTick, .ApplicationProcessFunc = TITagitstandardAppProcess, @@ -376,7 +394,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, .ApplicationInitFunc = TITagitplusAppInit, - .ApplicationResetFunc = TITagitplusAppReset, + .ApplicationInitRunOnceFunc = TITagitplusAppInit, + .ApplicationResetFunc = TITagitplusAppReset, .ApplicationTaskFunc = TITagitplusAppTask, .ApplicationTickFunc = TITagitplusAppTick, .ApplicationProcessFunc = TITagitplusAppProcess, @@ -394,7 +413,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, .ApplicationInitFunc = EM4233AppInit, - .ApplicationResetFunc = EM4233AppReset, + .ApplicationInitRunOnceFunc = EM4233AppInit, + .ApplicationResetFunc = EM4233AppReset, .ApplicationTaskFunc = EM4233AppTask, .ApplicationTickFunc = EM4233AppTick, .ApplicationProcessFunc = EM4233AppProcess, @@ -412,7 +432,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = NTAG215AppInit, - .ApplicationResetFunc = NTAG215AppReset, + .ApplicationInitRunOnceFunc = NTAG215AppInit, + .ApplicationResetFunc = NTAG215AppReset, .ApplicationTaskFunc = NTAG215AppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = NTAG215AppProcess, @@ -429,7 +450,40 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareDesfireEV0AppInit, - .ApplicationResetFunc = MifareDesfireAppReset, + .ApplicationInitRunOnceFunc = MifareDesfireEV0AppInitRunOnce, + .ApplicationResetFunc = MifareDesfireAppReset, + .ApplicationTaskFunc = MifareDesfireAppTask, + .ApplicationTickFunc = MifareDesfireAppTick, + .ApplicationProcessFunc = MifareDesfireAppProcess, + .ApplicationGetUidFunc = MifareDesfireGetUid, + .ApplicationSetUidFunc = MifareDesfireSetUid, + .UidSize = ISO14443A_UID_SIZE_DOUBLE, + .MemorySize = MIFARE_CLASSIC_4K_MEM_SIZE, + .ReadOnly = false + }, + [CONFIG_MF_DESFIRE_2KEV1] = { + .CodecInitFunc = ISO14443ACodecInit, + .CodecDeInitFunc = ISO14443ACodecDeInit, + .CodecTaskFunc = ISO14443ACodecTask, + .ApplicationInitFunc = MifareDesfire2kEV1AppInit, + .ApplicationInitRunOnceFunc = MifareDesfire2kEV1AppInitRunOnce, + .ApplicationResetFunc = MifareDesfireAppReset, + .ApplicationTaskFunc = MifareDesfireAppTask, + .ApplicationTickFunc = MifareDesfireAppTick, + .ApplicationProcessFunc = MifareDesfireAppProcess, + .ApplicationGetUidFunc = MifareDesfireGetUid, + .ApplicationSetUidFunc = MifareDesfireSetUid, + .UidSize = ISO14443A_UID_SIZE_DOUBLE, + .MemorySize = 2 * MIFARE_CLASSIC_1K_MEM_SIZE, + .ReadOnly = false + }, + [CONFIG_MF_DESFIRE_4KEV1] = { + .CodecInitFunc = ISO14443ACodecInit, + .CodecDeInitFunc = ISO14443ACodecDeInit, + .CodecTaskFunc = ISO14443ACodecTask, + .ApplicationInitFunc = MifareDesfire4kEV1AppInit, + .ApplicationInitRunOnceFunc = MifareDesfire4kEV1AppInitRunOnce, + .ApplicationResetFunc = MifareDesfireAppReset, .ApplicationTaskFunc = MifareDesfireAppTask, .ApplicationTickFunc = MifareDesfireAppTick, .ApplicationProcessFunc = MifareDesfireAppProcess, @@ -439,6 +493,22 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .MemorySize = MIFARE_CLASSIC_4K_MEM_SIZE, .ReadOnly = false }, + [CONFIG_MF_DESFIRE_8KEV1] = { + .CodecInitFunc = ISO14443ACodecInit, + .CodecDeInitFunc = ISO14443ACodecDeInit, + .CodecTaskFunc = ISO14443ACodecTask, + .ApplicationInitFunc = MifareDesfire8kEV1AppInit, + .ApplicationInitRunOnceFunc = MifareDesfire8kEV1AppInitRunOnce, + .ApplicationResetFunc = MifareDesfireAppReset, + .ApplicationTaskFunc = MifareDesfireAppTask, + .ApplicationTickFunc = MifareDesfireAppTick, + .ApplicationProcessFunc = MifareDesfireAppProcess, + .ApplicationGetUidFunc = MifareDesfireGetUid, + .ApplicationSetUidFunc = MifareDesfireSetUid, + .UidSize = ISO14443A_UID_SIZE_DOUBLE, + .MemorySize = 2 * MIFARE_CLASSIC_4K_MEM_SIZE, + .ReadOnly = false + }, #endif }; @@ -448,25 +518,36 @@ void ConfigurationInit(void) { memcpy_P(&ActiveConfiguration, &ConfigurationTable[CONFIG_NONE], sizeof(ConfigurationType)); - ConfigurationSetById(GlobalSettings.ActiveSettingPtr->Configuration); + ConfigurationSetById(GlobalSettings.ActiveSettingPtr->Configuration, false); } -void ConfigurationSetById(ConfigurationEnum Configuration) { +void ConfigurationSetById(ConfigurationEnum Configuration, bool appInitRunOnce) { CodecDeInit(); CommandLinePendingTaskBreak(); // break possibly pending task GlobalSettings.ActiveSettingPtr->Configuration = Configuration; - + + /* Blank memory scape slate for the newly set configuration */ + MemoryClear(); + /* Copy struct from PROGMEM to RAM */ memcpy_P(&ActiveConfiguration, &ConfigurationTable[Configuration], sizeof(ConfigurationType)); CodecInit(); - ApplicationInit(); - /* Notify LED. blink according to current setting */ - LEDHook(LED_SETTING_CHANGE, LED_BLINK + Configuration); + if (appInitRunOnce) { + ApplicationInitRunOnce(); + /* Notify LED. blink according to current setting */ + LEDHook(LED_SETTING_CHANGE, LED_BLINK_3X + Configuration); + + } else { + ApplicationInit(); + /* Notify LED. blink according to current setting */ + LEDHook(LED_SETTING_CHANGE, LED_BLINK + Configuration); + } + } void ConfigurationGetByName(char *Configuration, uint16_t BufferSize) { @@ -481,12 +562,12 @@ MapIdType ConfigurationCheckByName(const char *Configuration) { return 0xff; } -bool ConfigurationSetByName(const char *Configuration) { +bool ConfigurationSetByName(const char *Configuration, bool appInitRunOnce) { MapIdType Id; if (MapTextToId(ConfigurationMap, ARRAY_COUNT(ConfigurationMap), Configuration, &Id)) { - ConfigurationSetById(Id); - LogEntry(LOG_INFO_CONFIG_SET, Configuration, StringLength(Configuration, CONFIGURATION_NAME_LENGTH_MAX - 1)); + ConfigurationSetById(Id, appInitRunOnce); + LogEntry(LOG_INFO_CONFIG_SET, Configuration, StringLength(Configuration, CONFIGURATION_NAME_LENGTH_MAX - 1)); return true; } else { return false; diff --git a/Firmware/Chameleon-Mini/Configuration.h b/Firmware/Chameleon-Mini/Configuration.h index 9ec28e60..4c7fa876 100644 --- a/Firmware/Chameleon-Mini/Configuration.h +++ b/Firmware/Chameleon-Mini/Configuration.h @@ -72,6 +72,9 @@ typedef enum { #endif #ifdef CONFIG_MF_DESFIRE_SUPPORT CONFIG_MF_DESFIRE, + CONFIG_MF_DESFIRE_2KEV1, + CONFIG_MF_DESFIRE_4KEV1, + CONFIG_MF_DESFIRE_8KEV1, #endif /* This HAS to be the last element */ CONFIG_COUNT @@ -112,6 +115,12 @@ typedef struct { */ /** Function that initializes the application. */ void (*ApplicationInitFunc)(void); + /** Function to initialize one-time-only data in the application + * (like the filesystem for `CONFIG=MF_DESFIRE`). This function does not + * get called when changing slots to run a preexisting configuration or when the + * device is powered on and reinitializes the last loaded slot. + */ + void (*ApplicationInitRunOnceFunc)(void); /** Function that resets the application. */ void (*ApplicationResetFunc)(void); /** Function that is called on every iteration of the main loop. Application work that is independent from the codec layer can be done here. */ @@ -171,10 +180,10 @@ typedef struct { extern ConfigurationType ActiveConfiguration; void ConfigurationInit(void); -void ConfigurationSetById(ConfigurationEnum Configuration); +void ConfigurationSetById(ConfigurationEnum Configuration, bool appInitRunOnce); MapIdType ConfigurationCheckByName(const char *Configuration); void ConfigurationGetByName(char *Configuration, uint16_t BufferSize); -bool ConfigurationSetByName(const char *Configuration); +bool ConfigurationSetByName(const char *Configuration, bool appInitRunOnce); void ConfigurationGetList(char *ConfigurationList, uint16_t BufferSize); #endif /* STANDARDS_H_ */ diff --git a/Firmware/Chameleon-Mini/Log.h b/Firmware/Chameleon-Mini/Log.h index 0ed475a7..22d58fb5 100644 --- a/Firmware/Chameleon-Mini/Log.h +++ b/Firmware/Chameleon-Mini/Log.h @@ -3,7 +3,11 @@ /** @file */ #include "Common.h" +#ifdef MEMORY_LIMITED_TESTING +#define LOG_SIZE 1024 +#else #define LOG_SIZE 2048 +#endif #define FRAM_LOG_ADDR_ADDR 0x4000 // start of the second half of FRAM #define FRAM_LOG_START_ADDR 0x4002 // directly after the address #define FRAM_LOG_SIZE 0x3FFE // the whole second half (minus the 2 Bytes of Address) diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index aaf43b80..4e818807 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -71,7 +71,7 @@ SETTINGS += -DLOG_SETTING_GLOBAL SETTINGS += -DDEFAULT_SETTING=SETTINGS_FIRST #Default pending task timeout -SETTINGS += -DDEFAULT_PENDING_TASK_TIMEOUT=50 #* 100ms +SETTINGS += -DDEFAULT_PENDING_TASK_TIMEOUT=65 #50 #* 100ms #Default reader threshold SETTINGS += -DDEFAULT_READER_THRESHOLD=400 @@ -111,11 +111,11 @@ SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 #maximum storage allocations for the number of possible keys per #application directory, and/or the total number of AID numbered #directory slots, the following options will tweak this limitation: -# -> Set DESFIRE_MEMORY_LIMITED_TESTING to shrink the defaults +# -> Set MEMORY_LIMITED_TESTING to shrink the defaults # -> Or explicitly define DESFIRE_CUSTOM_MAX_KEYS=##UINT## (per AID), # -> And/Or define DESFIRE_CUSTOM_MAX_APPS=##UINT## # (total number of AID spaces available, not including the master 0x00) -SETTINGS += -DDESFIRE_MEMORY_LIMITED_TESTING +SETTINGS += -DMEMORY_LIMITED_TESTING #SETTINGS += -DDESFIRE_CUSTOM_MAX_APPS=8 #SETTINGS += -DDESFIRE_CUSTOM_MAX_KEYS=6 #SETTINGS += -DDESFIRE_CUSTOM_MAX_FILES=6 @@ -133,7 +133,7 @@ SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=1 #Option to save space with the "Application/Crypto1.c" code by storing large tables #in PROGMEM. Note that this will slow down the read times when accessing these tables: -SETTINGS += -DDESFIRE_CRYPTO1_SAVE_SPACE +#SETTINGS += -DDESFIRE_CRYPTO1_SAVE_SPACE DESFIRE_MAINSRC = Application/DESFire @@ -193,7 +193,7 @@ CC_FLAGS = -g0 -DUSE_LUFA_CONFIG_HEADER -DFLASH_DATA_ADDR=$(FLASH_DATA_ADDR) -D__AVR_ATxmega128A4U__ -D__PROG_TYPES_COMPAT__ -DMAX_ENDPOINT_INDEX=4 \ -std=gnu99 -Werror=implicit-function-declaration \ -fno-inline-small-functions -fshort-enums -fpack-struct \ - -ffunction-sections -Wl,--gc-sections --data-sections -ffunction-sections \ + -Wl,--gc-sections --data-sections -ffunction-sections -fdata-sections \ -Wl,-relax -fno-split-wide-types -fno-tree-scev-cprop \ -fno-aggressive-loop-optimizations LD_FLAGS = $(CC_FLAGS) -Wl,--section-start=.flashdata=$(FLASH_DATA_ADDR) -Wl,--section-start=.spmhelper=$(SPM_HELPER_ADDR) @@ -311,6 +311,3 @@ desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep @avr-size $(TARGET).elf desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -DDEFAULT_CONFIGURATION=CONFIG_NONE desfire: desfire-build -desfire-dev: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -DDEFAULT_CONFIGURATION=CONFIG_MF_DESFIRE_SUPPORT -desfire-dev: desfire-build - diff --git a/Firmware/Chameleon-Mini/Memory.h b/Firmware/Chameleon-Mini/Memory.h index dfca5055..cc9447d6 100644 --- a/Firmware/Chameleon-Mini/Memory.h +++ b/Firmware/Chameleon-Mini/Memory.h @@ -8,8 +8,8 @@ #ifndef MEMORY_H_ #define MEMORY_H_ -#define MEMORY_SIZE (FLASH_DATA_SIZE) /* From makefile */ -#define MEMORY_INIT_VALUE 0x00 +#define MEMORY_SIZE (FLASH_DATA_SIZE) /* From Makefile */ +#define MEMORY_INIT_VALUE 0x00 #define MEMORY_SIZE_PER_SETTING 8192 #ifndef __ASSEMBLER__ diff --git a/Firmware/Chameleon-Mini/Settings.c b/Firmware/Chameleon-Mini/Settings.c index 19c02ffa..12bd19f2 100644 --- a/Firmware/Chameleon-Mini/Settings.c +++ b/Firmware/Chameleon-Mini/Settings.c @@ -77,7 +77,7 @@ bool SettingsSetActiveById(uint8_t Setting) { MemoryRecall(); /* Settings have changed. Progress changes through system */ - ConfigurationSetById(GlobalSettings.ActiveSettingPtr->Configuration); + ConfigurationSetById(GlobalSettings.ActiveSettingPtr->Configuration, false); LogSetModeById(GlobalSettings.ActiveSettingPtr->LogMode); diff --git a/Firmware/Chameleon-Mini/Settings.h b/Firmware/Chameleon-Mini/Settings.h index a1eb20e1..fbe658b2 100644 --- a/Firmware/Chameleon-Mini/Settings.h +++ b/Firmware/Chameleon-Mini/Settings.h @@ -15,7 +15,12 @@ #include "Memory.h" #include +#ifdef CONFIG_MF_DESFIRE_SUPPORT +#define SETTINGS_COUNT (MEMORY_SIZE / MEMORY_SIZE_PER_SETTING / 2) +#else #define SETTINGS_COUNT (MEMORY_SIZE / MEMORY_SIZE_PER_SETTING) +#endif + #define SETTINGS_FIRST 1 #define SETTINGS_LAST (SETTINGS_FIRST + SETTINGS_COUNT - 1) diff --git a/Firmware/Chameleon-Mini/Terminal/Commands.c b/Firmware/Chameleon-Mini/Terminal/Commands.c index 9ee1b3b0..f13ee67f 100644 --- a/Firmware/Chameleon-Mini/Terminal/Commands.c +++ b/Firmware/Chameleon-Mini/Terminal/Commands.c @@ -44,11 +44,9 @@ CommandStatusIdType CommandSetConfig(char *OutMessage, const char *InParam) { if (COMMAND_IS_SUGGEST_STRING(InParam)) { ConfigurationGetList(OutMessage, TERMINAL_BUFFER_SIZE); return COMMAND_INFO_OK_WITH_TEXT_ID; - } else if (ConfigurationSetByName(InParam)) { - MemoryClear(); - ConfigurationSetByName(InParam); + } else if (ConfigurationSetByName(InParam, true)) { SETTING_UPDATE(GlobalSettings.ActiveSettingPtr->Configuration); - return COMMAND_INFO_OK_ID; + return COMMAND_INFO_OK_ID; } else { return COMMAND_ERR_INVALID_PARAM_ID; } diff --git a/Firmware/Chameleon-Mini/Terminal/Terminal.h b/Firmware/Chameleon-Mini/Terminal/Terminal.h index 36217c1c..94f942e5 100644 --- a/Firmware/Chameleon-Mini/Terminal/Terminal.h +++ b/Firmware/Chameleon-Mini/Terminal/Terminal.h @@ -16,7 +16,11 @@ #define TERMINAL_VBUS_PORT PORTD #define TERMINAL_VBUS_MASK PIN5_bm +#ifdef MEMORY_LIMITED_TESTING +#define TERMINAL_BUFFER_SIZE 128 +#else #define TERMINAL_BUFFER_SIZE 512 +#endif typedef enum { TERMINAL_UNINITIALIZED, diff --git a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h index aa31e6b1..366eb6b0 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h @@ -24,6 +24,8 @@ #define CRYPTO_3KTDEA_BLOCK_SIZE (CRYPTO_DES_BLOCK_SIZE) #define AES128_BLOCK_SIZE (16) +#define CRYPTO_CHALLENGE_RESPONSE_SIZE (16) + static const inline uint8_t ZERO_KEY[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h index e3f0ebf7..c276ad44 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h @@ -47,41 +47,40 @@ static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, c return EXIT_FAILURE; } - // Now need to decrypt the challenge response sent back as rndB (8 bytes), - // rotate it left, generate a random 8 byte rndA, concat rndA+rotatedRndB, - // encrypt this 16 byte result, and send it forth to the PICC: - uint8_t encryptedRndB[16], plainTextRndB[16], rotatedRndB[8]; - uint8_t rndA[8], challengeResponse[16], challengeResponseCipherText[16]; - int8_t IVBuf[16]; - memcpy(encryptedRndB, rxDataStorage->rxDataBuf, 16); + // Now need to decrypt the challenge response sent back as rndB, + // rotate it left, generate a random rndA, concat rndA+rotatedRndB, + // encrypt this result, and send it forth to the PICC: + uint8_t encryptedRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE], plainTextRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE], rotatedRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE]; + uint8_t rndA[CRYPTO_CHALLENGE_RESPONSE_SIZE], challengeResponse[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE], challengeResponseCipherText[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE]; + int8_t IVBuf[CRYPTO_CHALLENGE_RESPONSE_SIZE]; + memcpy(encryptedRndB, rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE); CryptoData_t aesCryptoData = { 0 }; aesCryptoData.keySize = 16; aesCryptoData.keyData = keyData; - aesCryptoData.ivSize = 16; - DecryptAES128(encryptedRndB, 16, plainTextRndB, aesCryptoData); - RotateArrayLeft(plainTextRndB, rotatedRndB, 8); - //memcpy(IVBuf, rxDataStorage->rxDataBuf, 8); - memset(IVBuf, 0x00, 16); + aesCryptoData.ivSize = CRYPTO_CHALLENGE_RESPONSE_SIZE; + DecryptAES128(encryptedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, plainTextRndB, aesCryptoData); + RotateArrayLeft(plainTextRndB, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); + memset(IVBuf, 0x00, CRYPTO_CHALLENGE_RESPONSE_SIZE); aesCryptoData.ivData = IVBuf; - GenerateRandomBytes(rndA, 8); - ConcatByteArrays(rndA, 8, rotatedRndB, 8, challengeResponse); - EncryptAES128(challengeResponse, 16, challengeResponseCipherText, aesCryptoData); + GenerateRandomBytes(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + ConcatByteArrays(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, challengeResponse); + EncryptAES128(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE, challengeResponseCipherText, aesCryptoData); - uint8_t sendBytesBuf[22]; - memset(sendBytesBuf, 0x00, 22); + uint8_t sendBytesBuf[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6]; + memset(sendBytesBuf, 0x00, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6); sendBytesBuf[0] = 0x90; sendBytesBuf[1] = 0xaf; - sendBytesBuf[4] = 0x10; - memcpy(sendBytesBuf + 5, challengeResponseCipherText, 16); + sendBytesBuf[4] = 0x20; + memcpy(sendBytesBuf + 5, challengeResponseCipherText, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); if(PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " -- RNDA = "); print_hex(rndA, 8); - fprintf(stdout, " -- RNDB = "); print_hex(plainTextRndB, 8); - fprintf(stdout, " -- CHAL = "); print_hex(challengeResponse, 16); + fprintf(stdout, " -- RNDA = "); print_hex(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " -- RNDB = "); print_hex(plainTextRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " -- CHAL = "); print_hex(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); fprintf(stdout, " -> "); print_hex(sendBytesBuf, sizeof(sendBytesBuf)); } - rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 22, rxDataStorage); + rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6, rxDataStorage); if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); @@ -97,10 +96,10 @@ static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, c // Finally, to finish up the auth process: // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, // and report back whether they match: - uint8_t decryptedRndAFromPICCRotated[16], decryptedRndA[16]; - DecryptAES128(rxDataStorage->rxDataBuf, 16, decryptedRndAFromPICCRotated, aesCryptoData); - RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, 8); - if(!memcmp(rndA, decryptedRndA, 8)) { + uint8_t decryptedRndAFromPICCRotated[CRYPTO_CHALLENGE_RESPONSE_SIZE], decryptedRndA[CRYPTO_CHALLENGE_RESPONSE_SIZE]; + DecryptAES128(rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE, decryptedRndAFromPICCRotated, aesCryptoData); + RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + if(!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { if(PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " ... AUTH OK! :)\n\n"); } @@ -112,7 +111,8 @@ static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, c } else { if(PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " ... AUTH FAILED -- X; :(\n\n"); + fprintf(stdout, " ... AUTH FAILED -- X; :(\n"); + fprintf(stdout, " ... "); print_hex(decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; @@ -125,7 +125,7 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons return INVALID_PARAMS_ERROR; } - // Start AES authentication (default key, blank setting of all zeros): + // Start 3K3DES authentication (default key, blank setting of all zeros): uint8_t AUTHENTICATE_ISO_CMD[] = { 0x90, 0x1a, 0x00, 0x00, 0x01, 0x00, 0x00 }; @@ -150,40 +150,40 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons return EXIT_FAILURE; } - // Now need to decrypt the challenge response sent back as rndB (8 bytes), - // rotate it left, generate a random 8 byte rndA, concat rndA+rotatedRndB, - // encrypt this 16 byte result, and send it forth to the PICC: - uint8_t encryptedRndB[16], plainTextRndB[16], rotatedRndB[8]; - uint8_t rndA[8], challengeResponse[16], challengeResponseCipherText[16]; - int8_t IVBuf[16]; - memcpy(encryptedRndB, rxDataStorage->rxDataBuf, 16); + // Now need to decrypt the challenge response sent back as rndB, + // rotate it left, generate a random rndA, concat rndA+rotatedRndB, + // encrypt this result, and send it forth to the PICC: + uint8_t encryptedRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE], plainTextRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE], rotatedRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE]; + uint8_t rndA[CRYPTO_CHALLENGE_RESPONSE_SIZE], challengeResponse[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE], challengeResponseCipherText[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE]; + int8_t IVBuf[CRYPTO_CHALLENGE_RESPONSE_SIZE]; + memcpy(encryptedRndB, rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE); CryptoData_t desCryptoData = { 0 }; desCryptoData.keySize = 3 * 8; desCryptoData.keyData = keyData; - desCryptoData.ivSize = 8; - Decrypt3DES(encryptedRndB, 16, plainTextRndB, NULL, desCryptoData); - RotateArrayLeft(plainTextRndB, rotatedRndB, 8); - memset(IVBuf, 0x00, 16); + desCryptoData.ivSize = CRYPTO_CHALLENGE_RESPONSE_SIZE; + Decrypt3DES(encryptedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, plainTextRndB, NULL, desCryptoData); + RotateArrayLeft(plainTextRndB, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); + memset(IVBuf, 0x00, CRYPTO_CHALLENGE_RESPONSE_SIZE); desCryptoData.ivData = IVBuf; - GenerateRandomBytes(rndA, 8); - ConcatByteArrays(rndA, 8, rotatedRndB, 8, challengeResponse); - Encrypt3DES(challengeResponse, 16, challengeResponseCipherText, NULL, desCryptoData); + GenerateRandomBytes(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + ConcatByteArrays(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, challengeResponse); + Encrypt3DES(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE, challengeResponseCipherText, NULL, desCryptoData); - uint8_t sendBytesBuf[22]; - memset(sendBytesBuf, 0x00, 22); + uint8_t sendBytesBuf[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6]; + memset(sendBytesBuf, 0x00, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6); sendBytesBuf[0] = 0x90; sendBytesBuf[1] = 0xaf; - sendBytesBuf[4] = 0x10; - memcpy(sendBytesBuf + 5, challengeResponseCipherText, 16); + sendBytesBuf[4] = 0x20; + memcpy(sendBytesBuf + 5, challengeResponseCipherText, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); if(PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " -- RNDA = "); print_hex(rndA, 8); - fprintf(stdout, " -- RNDB = "); print_hex(plainTextRndB, 8); - fprintf(stdout, " -- CHAL = "); print_hex(challengeResponse, 16); + fprintf(stdout, " -- RNDA = "); print_hex(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " -- RNDB = "); print_hex(plainTextRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " -- CHAL = "); print_hex(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); fprintf(stdout, " -> "); print_hex(sendBytesBuf, sizeof(sendBytesBuf)); } - rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 22, rxDataStorage); + rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6, rxDataStorage); if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); @@ -199,23 +199,24 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons // Finally, to finish up the auth process: // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, // and report back whether they match: - uint8_t decryptedRndAFromPICCRotated[16], decryptedRndA[16]; - Decrypt3DES(rxDataStorage->rxDataBuf, 16, decryptedRndAFromPICCRotated, NULL, desCryptoData); - RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, 8); - if(!memcmp(rndA, decryptedRndA, 8)) { + uint8_t decryptedRndAFromPICCRotated[CRYPTO_CHALLENGE_RESPONSE_SIZE], decryptedRndA[CRYPTO_CHALLENGE_RESPONSE_SIZE]; + Decrypt3DES(rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE, decryptedRndAFromPICCRotated, NULL, desCryptoData); + RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + if(!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { if(PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " ... AUTH OK! :)\n\n"); } AUTHENTICATED = true; - AUTHENTICATED_PROTO = DESFIRE_CRYPTO_AUTHTYPE_ISODES; + AUTHENTICATED_PROTO = DESFIRE_CRYPTO_AUTHTYPE_AES128; memcpy(CRYPTO_RNDB_STATE, plainTextRndB, 8); FreeRxDataStruct(rxDataStorage, true); return EXIT_SUCCESS; } else { if(PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " ... AUTH FAILED -- X; :(\n\n"); - } + fprintf(stdout, " ... AUTH FAILED -- X; :(\n"); + fprintf(stdout, " ... "); print_hex(decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; } @@ -227,13 +228,13 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c return INVALID_PARAMS_ERROR; } - // Start AES authentication (default key, blank setting of all zeros): + // Start 3K3DES authentication (default key, blank setting of all zeros): uint8_t AUTHENTICATE_LEGACY_CMD[] = { 0x90, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00 }; AUTHENTICATE_LEGACY_CMD[5] = keyIndex; if(PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, ">>> Start Legacy DES Authenticate:\n"); + fprintf(stdout, ">>> Start Legacy 3K3DES Authenticate:\n"); fprintf(stdout, " -> "); print_hex(AUTHENTICATE_LEGACY_CMD, sizeof(AUTHENTICATE_LEGACY_CMD)); } @@ -252,40 +253,40 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c return EXIT_FAILURE; } - // Now need to decrypt the challenge response sent back as rndB (8 bytes), - // rotate it left, generate a random 8 byte rndA, concat rndA+rotatedRndB, - // encrypt this 16 byte result, and send it forth to the PICC: - uint8_t encryptedRndB[16], plainTextRndB[16], rotatedRndB[8]; - uint8_t rndA[8], challengeResponse[16], challengeResponseCipherText[16]; - int8_t IVBuf[16]; - memcpy(encryptedRndB, rxDataStorage->rxDataBuf, 16); + // Now need to decrypt the challenge response sent back as rndB, + // rotate it left, generate a random rndA, concat rndA+rotatedRndB, + // encrypt this result, and send it forth to the PICC: + uint8_t encryptedRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE], plainTextRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE], rotatedRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE]; + uint8_t rndA[CRYPTO_CHALLENGE_RESPONSE_SIZE], challengeResponse[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE], challengeResponseCipherText[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE]; + int8_t IVBuf[CRYPTO_CHALLENGE_RESPONSE_SIZE]; + memcpy(encryptedRndB, rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE); CryptoData_t desCryptoData = { 0 }; desCryptoData.keySize = 3 * 8; desCryptoData.keyData = keyData; - desCryptoData.ivSize = 8; - Decrypt3DES(encryptedRndB, 16, plainTextRndB, NULL, desCryptoData); - RotateArrayLeft(plainTextRndB, rotatedRndB, 8); - memset(IVBuf, 0x00, 16); + desCryptoData.ivSize = CRYPTO_CHALLENGE_RESPONSE_SIZE; + Decrypt3DES(encryptedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, plainTextRndB, NULL, desCryptoData); + RotateArrayLeft(plainTextRndB, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); + memset(IVBuf, 0x00, CRYPTO_CHALLENGE_RESPONSE_SIZE); desCryptoData.ivData = IVBuf; - GenerateRandomBytes(rndA, 8); - ConcatByteArrays(rndA, 8, rotatedRndB, 8, challengeResponse); - Encrypt3DES(challengeResponse, 16, challengeResponseCipherText, NULL, desCryptoData); + GenerateRandomBytes(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + ConcatByteArrays(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, challengeResponse); + Encrypt3DES(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE, challengeResponseCipherText, NULL, desCryptoData); - uint8_t sendBytesBuf[22]; - memset(sendBytesBuf, 0x00, 22); + uint8_t sendBytesBuf[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6]; + memset(sendBytesBuf, 0x00, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6); sendBytesBuf[0] = 0x90; sendBytesBuf[1] = 0xaf; - sendBytesBuf[4] = 0x10; - memcpy(sendBytesBuf + 5, challengeResponseCipherText, 16); + sendBytesBuf[4] = 0x20; + memcpy(sendBytesBuf + 5, challengeResponseCipherText, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); if(PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " -- RNDA = "); print_hex(rndA, 8); - fprintf(stdout, " -- RNDB = "); print_hex(plainTextRndB, 8); - fprintf(stdout, " -- CHAL = "); print_hex(challengeResponse, 16); + fprintf(stdout, " -- RNDA = "); print_hex(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " -- RNDB = "); print_hex(plainTextRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " -- CHAL = "); print_hex(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); fprintf(stdout, " -> "); print_hex(sendBytesBuf, sizeof(sendBytesBuf)); } - rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 22, rxDataStorage); + rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6, rxDataStorage); if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); @@ -301,23 +302,24 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c // Finally, to finish up the auth process: // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, // and report back whether they match: - uint8_t decryptedRndAFromPICCRotated[16], decryptedRndA[16]; - Decrypt3DES(rxDataStorage->rxDataBuf, 16, decryptedRndAFromPICCRotated, NULL, desCryptoData); - RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, 8); - if(!memcmp(rndA, decryptedRndA, 8)) { + uint8_t decryptedRndAFromPICCRotated[CRYPTO_CHALLENGE_RESPONSE_SIZE], decryptedRndA[CRYPTO_CHALLENGE_RESPONSE_SIZE]; + Decrypt3DES(rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE, decryptedRndAFromPICCRotated, NULL, desCryptoData); + RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + if(!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { if(PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " ... AUTH OK! :)\n\n"); } AUTHENTICATED = true; - AUTHENTICATED_PROTO = DESFIRE_CRYPTO_AUTHTYPE_ISODES; + AUTHENTICATED_PROTO = DESFIRE_CRYPTO_AUTHTYPE_AES128; memcpy(CRYPTO_RNDB_STATE, plainTextRndB, 8); FreeRxDataStruct(rxDataStorage, true); return EXIT_SUCCESS; } else { if(PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " ... AUTH FAILED -- X; :(\n\n"); - } + fprintf(stdout, " ... AUTH FAILED -- X; :(\n"); + fprintf(stdout, " ... "); print_hex(decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; } From a02f2141e5e5c7ed4231ac1e79c6b19e5524b819 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Fri, 4 Feb 2022 22:17:00 -0500 Subject: [PATCH 10/68] Working AES128 auth and ISO auth ; Still need to debug the legacy auth --- .../DESFire/DESFireApplicationDirectory.c | 35 ++-- .../DESFire/DESFireApplicationDirectory.h | 34 ++-- .../Application/DESFire/DESFireCrypto.h | 7 +- .../Application/DESFire/DESFireFile.c | 2 +- .../Application/DESFire/DESFireInstructions.c | 151 ++++++++---------- .../DESFire/DESFireMemoryOperations.c | 54 +------ .../DESFire/DESFireMemoryOperations.h | 4 - .../Application/DESFire/DESFirePICCControl.c | 2 + .../DESFire/DESFirePICCHeaderLayout.h | 17 +- .../Application/MifareDESFire.c | 19 +-- .../Chameleon-Mini/Application/Reader14443A.c | 4 +- Firmware/Chameleon-Mini/Common.h | 10 -- Firmware/Chameleon-Mini/Configuration.c | 27 +--- Firmware/Chameleon-Mini/Configuration.h | 2 +- Firmware/Chameleon-Mini/Log.h | 4 - Firmware/Chameleon-Mini/Makefile | 8 +- Firmware/Chameleon-Mini/Memory.c | 15 -- Firmware/Chameleon-Mini/Memory.h | 3 +- Firmware/Chameleon-Mini/Settings.c | 3 +- Firmware/Chameleon-Mini/Settings.h | 5 - Firmware/Chameleon-Mini/Terminal/Commands.c | 9 +- Firmware/Chameleon-Mini/Terminal/Terminal.h | 2 +- 22 files changed, 146 insertions(+), 271 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c index dc2e2a19..df512633 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c @@ -121,7 +121,7 @@ BYTE AMKAllKeysFrozen(void) { } SIZET GetAppProperty(DesfireCardLayout propId, BYTE AppSlot) { - if (AppSlot >= DESFIRE_MAX_SLOTS) { + if (AppSlot >= AppDir.FirstFreeSlot || AppSlot >= DESFIRE_MAX_SLOTS) { return 0x00; } SelectedAppCacheType appCache; @@ -157,7 +157,7 @@ SIZET GetAppProperty(DesfireCardLayout propId, BYTE AppSlot) { } void SetAppProperty(DesfireCardLayout propId, BYTE AppSlot, SIZET Value) { - if (AppSlot >= DESFIRE_MAX_SLOTS) { + if (AppSlot >= AppDir.FirstFreeSlot || AppSlot >= DESFIRE_MAX_SLOTS) { return; } SelectedAppCacheType appCache; @@ -308,16 +308,6 @@ void ReadAppKey(uint8_t AppSlot, uint8_t KeyId, uint8_t *Key, SIZET KeySize) { SIZET keyStorageArray[DESFIRE_MAX_KEYS]; ReadBlockBytes(keyStorageArray, keyStorageArrayBlockId, 2 * DESFIRE_MAX_KEYS); ReadBlockBytes(Key, keyStorageArray[KeyId], KeySize); - /*if (KeySize > DESFIRE_EEPROM_BLOCK_SIZE) { - ReadBlockBytes(Key, keyStorageArray[KeyId], DESFIRE_EEPROM_BLOCK_SIZE); - uint8_t fullBlock[DESFIRE_EEPROM_BLOCK_SIZE]; - ReadBlockBytes(fullBlock, keyStorageArray[KeyId] + 1, DESFIRE_EEPROM_BLOCK_SIZE); - memcpy(Key + DESFIRE_EEPROM_BLOCK_SIZE, fullBlock, KeySize - DESFIRE_EEPROM_BLOCK_SIZE); - } else { - uint8_t fullBlock[DESFIRE_EEPROM_BLOCK_SIZE]; - ReadBlockBytes(fullBlock, keyStorageArray[KeyId], DESFIRE_EEPROM_BLOCK_SIZE); - memcpy(Key, fullBlock, KeySize); - }*/ } void WriteAppKey(uint8_t AppSlot, uint8_t KeyId, const uint8_t *Key, SIZET KeySize) { @@ -329,7 +319,6 @@ void WriteAppKey(uint8_t AppSlot, uint8_t KeyId, const uint8_t *Key, SIZET KeySi SIZET keyStorageArrayBlockId = ReadKeyStorageAddress(AppSlot); SIZET keyStorageArray[DESFIRE_MAX_KEYS]; ReadBlockBytes(keyStorageArray, keyStorageArrayBlockId, 2 * DESFIRE_MAX_KEYS); - // TODO: WriteBlockBytes(Key, keyStorageArray[KeyId], KeySize); } @@ -519,8 +508,10 @@ void SelectAppBySlot(uint8_t AppSlot) { if (appCacheSelectedBlockId == 0) { return; } - SIZET prevAppCacheSelectedBlockId = AppDir.AppCacheStructBlockOffset[SelectedApp.Slot]; - WriteBlockBytes(&SelectedApp, prevAppCacheSelectedBlockId, sizeof(SelectedAppCacheType)); + if (SelectedApp.Slot != (uint8_t) -1) { + SIZET prevAppCacheSelectedBlockId = AppDir.AppCacheStructBlockOffset[SelectedApp.Slot]; + WriteBlockBytes(&SelectedApp, prevAppCacheSelectedBlockId, sizeof(SelectedAppCacheType)); + } ReadBlockBytes(&SelectedApp, appCacheSelectedBlockId, sizeof(SelectedAppCacheType)); SelectedApp.Slot = AppSlot; SynchronizeAppDir(); @@ -605,7 +596,7 @@ uint16_t CreateApp(const DESFireAidType Aid, uint8_t KeyCount, uint8_t KeySettin appCacheData.KeyCount = 1; // Master Key appCacheData.MaxKeyCount = KeyCount; appCacheData.FileCount = 0; - appCacheData.CryptoCommStandard = DESFIRE_DEFAULT_COMMS_STANDARD; + appCacheData.CryptoCommStandard = DesfireCommMode; appCacheData.KeySettings = AllocateBlocks(APP_CACHE_KEY_SETTINGS_ARRAY_BLOCK_SIZE); if (appCacheData.KeySettings == 0) { return STATUS_OUT_OF_EEPROM_ERROR; @@ -636,7 +627,9 @@ uint16_t CreateApp(const DESFireAidType Aid, uint8_t KeyCount, uint8_t KeySettin return STATUS_OUT_OF_EEPROM_ERROR; } else { SIZET fileAccessRightsData[DESFIRE_MAX_FILES]; - memset(fileAccessRightsData, 0x0f, sizeof(SIZET) * DESFIRE_MAX_FILES); + for (int fidx = 0; fidx < DESFIRE_MAX_FILES; fidx++) { + fileAccessRightsData[fidx] = 0x000f; + } WriteBlockBytes(fileAccessRightsData, appCacheData.FileAccessRights, sizeof(SIZET) * DESFIRE_MAX_FILES); } appCacheData.KeyVersionsArray = AllocateBlocks(APP_CACHE_KEY_VERSIONS_ARRAY_BLOCK_SIZE); @@ -651,9 +644,9 @@ uint16_t CreateApp(const DESFireAidType Aid, uint8_t KeyCount, uint8_t KeySettin if (appCacheData.KeyTypesArray == 0) { return STATUS_OUT_OF_EEPROM_ERROR; } else { - BYTE keyTypesData[APP_CACHE_KEY_TYPES_ARRAY_BLOCK_SIZE * DESFIRE_EEPROM_BLOCK_SIZE]; - memset(keyTypesData, 0x00, APP_CACHE_KEY_TYPES_ARRAY_BLOCK_SIZE * DESFIRE_EEPROM_BLOCK_SIZE); - WriteBlockBytes(keyTypesData, appCacheData.KeyTypesArray, APP_CACHE_KEY_TYPES_ARRAY_BLOCK_SIZE * DESFIRE_EEPROM_BLOCK_SIZE); + BYTE keyTypesData[APP_CACHE_KEY_TYPES_ARRAY_BLOCK_SIZE * DESFIRE_BLOCK_SIZE]; + memset(keyTypesData, 0x00, APP_CACHE_KEY_TYPES_ARRAY_BLOCK_SIZE * DESFIRE_BLOCK_SIZE); + WriteBlockBytes(keyTypesData, appCacheData.KeyTypesArray, APP_CACHE_KEY_TYPES_ARRAY_BLOCK_SIZE * DESFIRE_BLOCK_SIZE); } appCacheData.FilesAddress = AllocateBlocks(APP_CACHE_FILE_BLOCKIDS_ARRAY_BLOCK_SIZE); if (appCacheData.FilesAddress == 0) { @@ -676,8 +669,6 @@ uint16_t CreateApp(const DESFireAidType Aid, uint8_t KeyCount, uint8_t KeySettin } BYTE cryptoBlankKeyData[CRYPTO_MAX_KEY_SIZE]; memset(cryptoBlankKeyData, 0x00, CRYPTO_MAX_KEY_SIZE); - //WriteBlockBytes(cryptoBlankKeyData, keyAddresses[0], DESFIRE_EEPROM_BLOCK_SIZE); - //WriteBlockBytes(cryptoBlankKeyData, keyAddresses[0] + 1, CRYPTO_MAX_KEY_SIZE - DESFIRE_EEPROM_BLOCK_SIZE); WriteBlockBytes(cryptoBlankKeyData, keyAddresses[0], CRYPTO_MAX_KEY_SIZE); WriteBlockBytes(keyAddresses, appCacheData.KeyAddress, sizeof(SIZET) * DESFIRE_MAX_KEYS); } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h index 64abbed7..aa7e962e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h @@ -35,46 +35,36 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_MAX_FILES_EV0 16 #define DESFIRE_MAX_FILES_EV1 32 -#if defined(MEMORY_LIMITED_TESTING) && !defined(DESFIRE_CUSTOM_MAX_APPS) +#ifdef MEMORY_LIMITED_TESTING #define DESFIRE_MAX_APPS (3) -#elif defined(DESFIRE_CUSTOM_MAX_APPS) +#else +#ifdef DESFIRE_CUSTOM_MAX_APPS #define DESFIRE_MAX_APPS (DESFIRE_CUSTOM_MAX_APPS) #else #define DESFIRE_MAX_APPS (28) #endif +#endif #define DESFIRE_MAX_SLOTS (DESFIRE_MAX_APPS + 1) -#if defined(MEMORY_LIMITED_TESTING) && !defined(DESFIRE_CUSTOM_MAX_FILES) +#ifdef MEMORY_LIMITED_TESTING #define DESFIRE_MAX_FILES (4) -#elif defined(DESFIRE_CUSTOM_MAX_FILES) +#else +#ifdef DESFIRE_CUSTOM_MAX_FILES #define DESFIRE_MAX_FILES (DESFIRE_CUSTOM_MAX_FILES) #else -#define DESFIRE_MAX_FILES (DESFIRE_MAX_FILES_EV1) +#define DESFIRE_MAX_FILES (DESFIRE_MAX_FILES_EV0) +#endif #endif -#if defined(MEMORY_LIMITED_TESTING) && !defined(DESFIRE_CUSTOM_MAX_KEYS) +#ifdef MEMORY_LIMITED_TESTING #define DESFIRE_MAX_KEYS (2) -#elif defined(DESFIRE_CUSTOM_MAX_KEYS) +#else +#ifdef DESFIRE_CUSTOM_MAX_KEYS #define DESFIRE_MAX_KEYS (DESFIRE_CUSTOM_MAX_KEYS) #else #define DESFIRE_MAX_KEYS (14) #endif - -#ifdef DESFIRE_USE_FACTORY_SIZES -#undef DESFIRE_CUSTOM_MAX_APPS -#define DESFIRE_CUSTOM_MAX_APPS (28) -#undef DESFIRE_CUSTOM_MAX_KEYS -#define DESFIRE_CUSTOM_MAX_KEYS (14) -#undef DESFIRE_CUSTOM_MAX_FILES -#define DESFIRE_CUSTOM_MAX_FILES (DESFIRE_MAX_FILES_EV1) -#elif defined(DESFIRE_MAXIMIZE_SIZES_FOR_STORAGE) -#undef DESFIRE_CUSTOM_MAX_APPS -#define DESFIRE_CUSTOM_MAX_APPS (DESFIRE_EEPROM_BLOCK_SIZE - 1) -#undef DESFIRE_CUSTOM_MAX_KEYS -#define DESFIRE_CUSTOM_MAX_KEYS (DESFIRE_EEPROM_BLOCK_SIZE) -#undef DESFIRE_CUSTOM_MAX_FILES -#define DESFIRE_CUSTOM_MAX_FILES (DESFIRE_EEPROM_BLOCK_SIZE) #endif /* Mifare DESFire EV1 Application crypto operations */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h index 2dbf77ae..a21ceebb 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h @@ -53,21 +53,20 @@ extern BYTE DesfireCommMode; #define CRYPTO_TYPE_3K3DES (0x1A) #define CRYPTO_TYPE_AES128 (0x4A) -#define CryptoTypeDES(ct) \ +#define CryptoTypeDES(ct) \ ((ct == CRYPTO_TYPE_DES) || (ct == CRYPTO_TYPE_ANY)) #define CryptoType2KTDEA(ct) \ ((ct == CRYPTO_TYPE_2KTDEA) || (ct == CRYPTO_TYPE_ANY)) #define CryptoType3KTDEA(ct) \ ((ct == CRYPTO_TYPE_3K3DES) || (ct == CRYPTO_TYPE_ANY)) -#define CryptoTypeAES(ct) \ +#define CryptoTypeAES(ct) \ ((ct == CRYPTO_TYPE_AES128) || (ct == CRYPTO_TYPE_ANY)) /* Key sizes, block sizes (in bytes): */ #define CRYPTO_AES_KEY_SIZE (16) -#define CRYPTO_MAX_KEY_SIZE (24) // (32) // Make it a multiple of the EEPROM_BLOCK_SIZE +#define CRYPTO_MAX_KEY_SIZE (24) #define CRYPTO_MAX_BLOCK_SIZE (16) #define DESFIRE_AES_IV_SIZE (CRYPTO_AES_BLOCK_SIZE) -#define DESFIRE_SESSION_KEY_SIZE (CRYPTO_3KTDEA_KEY_SIZE) #define CRYPTO_CHALLENGE_RESPONSE_BYTES (16) typedef BYTE CryptoKeyBufferType[CRYPTO_MAX_KEY_SIZE]; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.c index 32bd12ac..8e252495 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.c @@ -48,7 +48,7 @@ uint16_t GetFileSizeFromFileType(DESFireFileTypeSettings *File) { case DESFIRE_FILE_VALUE_DATA: return sizeof(int32_t); // 4 case DESFIRE_FILE_LINEAR_RECORDS: - return (File->RecordFile.BlockCount) * DESFIRE_EEPROM_BLOCK_SIZE; + return (File->RecordFile.BlockCount) * DESFIRE_BLOCK_SIZE; case DESFIRE_FILE_CIRCULAR_RECORDS: default: break; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 0e654cca..b6c9c039 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -416,7 +416,7 @@ uint16_t DesfireCmdFreeMemory(uint8_t *Buffer, uint16_t ByteCount) { // practical working space is less than N: uint16_t cardCapacityBlocks = GetCardCapacityBlocks(); cardCapacityBlocks -= Picc.FirstFreeBlock; - uint16_t freeMemoryBytes = cardCapacityBlocks * DESFIRE_EEPROM_BLOCK_SIZE; + uint16_t freeMemoryBytes = cardCapacityBlocks * DESFIRE_BLOCK_SIZE; Buffer[0] = (uint8_t)(freeMemoryBytes >> 8); Buffer[1] = (uint8_t)(freeMemoryBytes >> 0); Buffer[2] = STATUS_OPERATION_OK; @@ -430,7 +430,7 @@ uint16_t DesfireCmdFreeMemory(uint8_t *Buffer, uint16_t ByteCount) { uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId, Status; BYTE keySize; - BYTE **Key; + BYTE *Key; /* Reset authentication state right away */ InvalidateAuthState(SelectedApp.Slot == DESFIRE_PICC_APP_SLOT); @@ -454,14 +454,14 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { /* Indicate that we are in DES key authentication land */ keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); - Key = &SessionKey; + Key = SessionKey; DesfireCommandState.KeyId = KeyId; DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); /* Fetch the key */ - ReadAppKey(SelectedApp.Slot, KeyId, *Key, keySize); - LogEntry(LOG_APP_AUTH_KEY, (const void *) *Key, keySize); + ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + LogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); /* Generate the nonce B (RndB / Challenge response) */ if (LocalTestingMode == 0) { @@ -488,11 +488,8 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Encrypt RndB with the selected key and transfer it back to the PCD */ - uint8_t rndBPadded[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; - memset(rndBPadded, 0x00, 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES); - memcpy(rndBPadded, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - Encrypt3DESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, rndBPadded, - &Buffer[1], NULL, *Key); + Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, DesfireCommandState.RndB, + &Buffer[1], NULL, Key); /* Scrub the key */ memset(*Key, 0, keySize); @@ -500,13 +497,13 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { /* Done */ DesfireState = DESFIRE_LEGACY_AUTHENTICATE2; Buffer[0] = STATUS_ADDITIONAL_FRAME; - return DESFIRE_STATUS_RESPONSE_SIZE + 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES; + return DESFIRE_STATUS_RESPONSE_SIZE + CRYPTO_CHALLENGE_RESPONSE_BYTES; } uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId; BYTE cryptoKeyType, keySize; - BYTE **Key; + BYTE *Key; /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; @@ -521,15 +518,15 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { KeyId = DesfireCommandState.KeyId; cryptoKeyType = DesfireCommandState.CryptoMethodType; keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); - Key = &SessionKey; - ReadAppKey(SelectedApp.Slot, KeyId, *Key, keySize); + Key = SessionKey; + ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); /* Decrypt the challenge sent back to get RndA and a shifted RndB */ BYTE challengeRndAB[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndA[CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndB[CRYPTO_CHALLENGE_RESPONSE_BYTES]; Decrypt3DESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, - &Buffer[1], NULL, *Key); + &Buffer[1], NULL, Key); RotateArrayRight(challengeRndAB + CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); @@ -549,7 +546,7 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { /* Encrypt and send back the once rotated RndA buffer to the PCD */ RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, - &Buffer[1], NULL, *Key); + &Buffer[1], NULL, Key); generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_3K3DES); @@ -1573,7 +1570,7 @@ uint16_t EV0CmdWriteRecord(uint8_t *Buffer, uint16_t ByteCount) { if (offsetBlocks > 0) { --offsetBlocks; } - uint16_t effectiveOffset = Offset % DESFIRE_EEPROM_BLOCK_SIZE; + uint16_t effectiveOffset = Offset % DESFIRE_BLOCK_SIZE; uint8_t dataWriteAddr = GetFileDataAreaBlockId(fileIndex) + offsetBlocks; memmove(&Buffer[effectiveOffset], &Buffer[8], dataXferLength); if (effectiveOffset > 0) { @@ -1689,7 +1686,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId, Status; BYTE keySize; - BYTE **Key; + BYTE *Key; /* Reset authentication state right away */ InvalidateAuthState(SelectedApp.Slot == DESFIRE_PICC_APP_SLOT); @@ -1712,7 +1709,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { } keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); - Key = &SessionKey; + Key = SessionKey; /* Indicate that we are in AES key authentication land */ DesfireCommandState.KeyId = KeyId; @@ -1720,8 +1717,8 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); /* Fetch the key */ - ReadAppKey(SelectedApp.Slot, KeyId, *Key, keySize); - LogEntry(LOG_APP_AUTH_KEY, (const void *) *Key, keySize); + ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + LogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); /* Generate the nonce B (RndB / Challenge response) */ if (LocalTestingMode == 0) { @@ -1748,26 +1745,23 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Encrypt RndB with the selected key and transfer it back to the PCD */ - uint8_t rndBPadded[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; - memset(rndBPadded, 0x00, 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES); - memcpy(rndBPadded, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - Encrypt3DESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, rndBPadded, - &Buffer[1], NULL, *Key); + Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, DesfireCommandState.RndB, + &Buffer[1], NULL, Key); /* Scrub the key */ - memset(*Key, 0, keySize); + memset(Key, 0, keySize); /* Done */ DesfireState = DESFIRE_ISO_AUTHENTICATE2; Buffer[0] = STATUS_ADDITIONAL_FRAME; - return DESFIRE_STATUS_RESPONSE_SIZE + 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES; + return DESFIRE_STATUS_RESPONSE_SIZE + CRYPTO_CHALLENGE_RESPONSE_BYTES; } uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId; BYTE cryptoKeyType, keySize; - BYTE **Key; + BYTE *Key; /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; @@ -1781,15 +1775,15 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { KeyId = DesfireCommandState.KeyId; cryptoKeyType = DesfireCommandState.CryptoMethodType; keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); - Key = &SessionKey; - ReadAppKey(SelectedApp.Slot, KeyId, *Key, keySize); + Key = SessionKey; + ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); /* Decrypt the challenge sent back to get RndA and a shifted RndB */ BYTE challengeRndAB[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndA[CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndB[CRYPTO_CHALLENGE_RESPONSE_BYTES]; Decrypt3DESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, - &Buffer[1], NULL, *Key); + &Buffer[1], NULL, Key); RotateArrayRight(challengeRndAB + CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); @@ -1810,7 +1804,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Encrypt and send back the once rotated RndA buffer to the PCD */ RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, - &Buffer[1], NULL, *Key); + &Buffer[1], NULL, Key); generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_3K3DES); @@ -1824,7 +1818,7 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId, Status; BYTE keySize; - BYTE **Key, **IVBuffer; + BYTE *Key, *IVBuffer; /* Reset authentication state right away */ InvalidateAuthState(SelectedApp.Slot == DESFIRE_PICC_APP_SLOT); @@ -1849,8 +1843,8 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { InitAESCryptoKeyData(); keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_AES128); - *Key = SessionKey; - *IVBuffer = SessionIV; + Key = SessionKey; + IVBuffer = SessionIV; /* Indicate that we are in AES key authentication land */ DesfireCommandState.KeyId = KeyId; @@ -1858,8 +1852,8 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_AES128); /* Fetch the key */ - ReadAppKey(SelectedApp.Slot, KeyId, *Key, keySize); - LogEntry(LOG_APP_AUTH_KEY, (const void *) *Key, keySize); + ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + LogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); CryptoAESGetConfigDefaults(&AESCryptoContext); CryptoAESInitContext(&AESCryptoContext); @@ -1888,29 +1882,26 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Encrypt RndB with the selected key and transfer it back to the PCD */ - uint8_t rndBPadded[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; - memset(rndBPadded, 0x00, 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES); - memcpy(rndBPadded, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - Status = CryptoAESEncryptBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, rndBPadded, &Buffer[1], NULL, *Key); + Status = CryptoAESEncryptBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, DesfireCommandState.RndB, &Buffer[1], NULL, Key); if (Status != STATUS_OPERATION_OK) { Buffer[0] = Status; return DESFIRE_STATUS_RESPONSE_SIZE; } /* Scrub the key */ - memset(*Key, 0, keySize); + memset(Key, 0, keySize); /* Done */ DesfireState = DESFIRE_AES_AUTHENTICATE2; Buffer[0] = STATUS_ADDITIONAL_FRAME; - return DESFIRE_STATUS_RESPONSE_SIZE + 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES; + return DESFIRE_STATUS_RESPONSE_SIZE + CRYPTO_CHALLENGE_RESPONSE_BYTES; } uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId; BYTE cryptoKeyType, keySize; - BYTE **Key; + BYTE *Key; /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; @@ -1921,17 +1912,17 @@ uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount) { } /* Reset parameters for authentication from the first exchange */ - Key = &SessionKey; + Key = SessionKey; keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_AES128); KeyId = DesfireCommandState.KeyId; cryptoKeyType = DesfireCommandState.CryptoMethodType; - ReadAppKey(SelectedApp.Slot, KeyId, *Key, keySize); + ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); /* Decrypt the challenge sent back to get RndA and a shifted RndB */ BYTE challengeRndAB[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndA[CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndB[CRYPTO_CHALLENGE_RESPONSE_BYTES]; - CryptoAESDecryptBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, *Key); + CryptoAESDecryptBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, Key); RotateArrayRight(challengeRndAB + CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); @@ -1954,7 +1945,7 @@ uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount) { memset(challengeRndAB, 0x00, CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(challengeRndAB, challengeRndA, CRYPTO_CHALLENGE_RESPONSE_BYTES); RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - CryptoAESEncryptBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, *Key); + CryptoAESEncryptBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, Key); generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_AES128); @@ -2129,19 +2120,19 @@ uint16_t ISO7816CmdReadBinary(uint8_t *Buffer, uint16_t ByteCount) { maxBytesToRead = SelectedFile.File.FileSize - Iso7816FileOffset; } /* Handle fetching bits in the cases where the file offset is not a multiple of - * DESFIRE_EEPROM_BLOCK_SIZE, which is required to address the data read out of the + * DESFIRE_BLOCK_SIZE, which is required to address the data read out of the * file using ReadBlockBytes */ uint8_t fileDataReadAddr = SelectedFile.File.FileDataAddress + MIN(0, DESFIRE_BYTES_TO_BLOCKS(Iso7816FileOffset) - 1); uint8_t *storeDataBufStart = &Buffer[2]; - if ((Iso7816FileOffset % DESFIRE_EEPROM_BLOCK_SIZE) != 0) { - uint8_t blockPriorByteCount = Iso7816FileOffset % DESFIRE_EEPROM_BLOCK_SIZE; - uint8_t blockData[DESFIRE_EEPROM_BLOCK_SIZE]; - ReadBlockBytes(blockData, fileDataReadAddr, DESFIRE_EEPROM_BLOCK_SIZE); - memcpy(storeDataBufStart + blockPriorByteCount, blockData, DESFIRE_EEPROM_BLOCK_SIZE); + if ((Iso7816FileOffset % DESFIRE_BLOCK_SIZE) != 0) { + uint8_t blockPriorByteCount = Iso7816FileOffset % DESFIRE_BLOCK_SIZE; + uint8_t blockData[DESFIRE_BLOCK_SIZE]; + ReadBlockBytes(blockData, fileDataReadAddr, DESFIRE_BLOCK_SIZE); + memcpy(storeDataBufStart + blockPriorByteCount, blockData, DESFIRE_BLOCK_SIZE); fileDataReadAddr += 1; - storeDataBufStart += DESFIRE_EEPROM_BLOCK_SIZE - blockPriorByteCount; - maxBytesToRead -= DESFIRE_EEPROM_BLOCK_SIZE - blockPriorByteCount; + storeDataBufStart += DESFIRE_BLOCK_SIZE - blockPriorByteCount; + maxBytesToRead -= DESFIRE_BLOCK_SIZE - blockPriorByteCount; } ReadBlockBytes(storeDataBufStart, fileDataReadAddr, maxBytesToRead); Buffer[0] = ISO7816_CMD_NO_ERROR; @@ -2219,20 +2210,20 @@ uint16_t ISO7816CmdUpdateBinary(uint8_t *Buffer, uint16_t ByteCount) { maxBytesToRead = SelectedFile.File.FileSize - Iso7816FileOffset; } /* Handle fetching bits in the cases where the file offset is not a multiple of - * DESFIRE_EEPROM_BLOCK_SIZE, which is required to address the data read out of the + * DESFIRE_BLOCK_SIZE, which is required to address the data read out of the * file using ReadBlockBytes */ uint8_t fileDataWriteAddr = SelectedFile.File.FileDataAddress + MIN(0, DESFIRE_BYTES_TO_BLOCKS(Iso7816FileOffset) - 1); uint8_t *updateDataBufStart = &Buffer[1]; - if ((Iso7816FileOffset % DESFIRE_EEPROM_BLOCK_SIZE) != 0) { - uint8_t blockPriorByteCount = Iso7816FileOffset % DESFIRE_EEPROM_BLOCK_SIZE; - uint8_t blockData[DESFIRE_EEPROM_BLOCK_SIZE]; + if ((Iso7816FileOffset % DESFIRE_BLOCK_SIZE) != 0) { + uint8_t blockPriorByteCount = Iso7816FileOffset % DESFIRE_BLOCK_SIZE; + uint8_t blockData[DESFIRE_BLOCK_SIZE]; ReadBlockBytes(blockData, fileDataWriteAddr, blockPriorByteCount); - memcpy(blockData + blockPriorByteCount, updateDataBufStart, DESFIRE_EEPROM_BLOCK_SIZE - blockPriorByteCount); - WriteBlockBytes(blockData, fileDataWriteAddr, DESFIRE_EEPROM_BLOCK_SIZE); + memcpy(blockData + blockPriorByteCount, updateDataBufStart, DESFIRE_BLOCK_SIZE - blockPriorByteCount); + WriteBlockBytes(blockData, fileDataWriteAddr, DESFIRE_BLOCK_SIZE); fileDataWriteAddr += 1; - updateDataBufStart += DESFIRE_EEPROM_BLOCK_SIZE - blockPriorByteCount; - maxBytesToRead -= DESFIRE_EEPROM_BLOCK_SIZE - blockPriorByteCount; + updateDataBufStart += DESFIRE_BLOCK_SIZE - blockPriorByteCount; + maxBytesToRead -= DESFIRE_BLOCK_SIZE - blockPriorByteCount; } WriteBlockBytes(updateDataBufStart, fileDataWriteAddr, maxBytesToRead); Buffer[0] = ISO7816_CMD_NO_ERROR; @@ -2312,19 +2303,19 @@ uint16_t ISO7816CmdReadRecords(uint8_t *Buffer, uint16_t ByteCount) { cyclicRecordOffsetDiff = maxBytesToRead + Iso7816FileOffset - SelectedFile.File.FileSize; } /* Handle fetching bits in the cases where the file offset is not a multiple of - * DESFIRE_EEPROM_BLOCK_SIZE, which is required to address the data read out of the + * DESFIRE_BLOCK_SIZE, which is required to address the data read out of the * file using ReadBlockBytes */ uint8_t initFileReadDataAddr = SelectedFile.File.FileDataAddress + MIN(0, DESFIRE_BYTES_TO_BLOCKS(Iso7816FileOffset) - 1); uint8_t *storeDataBufStart = &Buffer[2]; - if ((Iso7816FileOffset % DESFIRE_EEPROM_BLOCK_SIZE) != 0) { - uint8_t blockPriorByteCount = Iso7816FileOffset % DESFIRE_EEPROM_BLOCK_SIZE; - uint8_t blockData[DESFIRE_EEPROM_BLOCK_SIZE]; - ReadBlockBytes(blockData, initFileReadDataAddr, DESFIRE_EEPROM_BLOCK_SIZE); - memcpy(storeDataBufStart + blockPriorByteCount, blockData, DESFIRE_EEPROM_BLOCK_SIZE); + if ((Iso7816FileOffset % DESFIRE_BLOCK_SIZE) != 0) { + uint8_t blockPriorByteCount = Iso7816FileOffset % DESFIRE_BLOCK_SIZE; + uint8_t blockData[DESFIRE_BLOCK_SIZE]; + ReadBlockBytes(blockData, initFileReadDataAddr, DESFIRE_BLOCK_SIZE); + memcpy(storeDataBufStart + blockPriorByteCount, blockData, DESFIRE_BLOCK_SIZE); initFileReadDataAddr += 1; - storeDataBufStart += DESFIRE_EEPROM_BLOCK_SIZE - blockPriorByteCount; - maxBytesToRead -= DESFIRE_EEPROM_BLOCK_SIZE - blockPriorByteCount; + storeDataBufStart += DESFIRE_BLOCK_SIZE - blockPriorByteCount; + maxBytesToRead -= DESFIRE_BLOCK_SIZE - blockPriorByteCount; } /* Now, read the specified file contents into the Buffer: * Cases to handle separately: @@ -2398,20 +2389,20 @@ uint16_t ISO7816CmdAppendRecord(uint8_t *Buffer, uint16_t ByteCount) { nextRecordPointer = (SelectedFile.File.RecordFile.RecordPointer + appendRecordLength) % fileMaxRecords; } uint16_t nextRecordIndexToAppend = SelectedFile.File.RecordFile.RecordPointer % fileMaxRecords; - uint16_t priorBlockBytesToCopy = DESFIRE_EEPROM_BLOCK_SIZE - (nextRecordIndexToAppend % DESFIRE_EEPROM_BLOCK_SIZE); - if ((priorBlockBytesToCopy == DESFIRE_EEPROM_BLOCK_SIZE) || (nextRecordIndexToAppend < DESFIRE_EEPROM_BLOCK_SIZE)) { + uint16_t priorBlockBytesToCopy = DESFIRE_BLOCK_SIZE - (nextRecordIndexToAppend % DESFIRE_BLOCK_SIZE); + if ((priorBlockBytesToCopy == DESFIRE_BLOCK_SIZE) || (nextRecordIndexToAppend < DESFIRE_BLOCK_SIZE)) { priorBlockBytesToCopy = 0; } uint16_t fileDataWriteAddr = SelectedFile.File.FileDataAddress + MIN(0, DESFIRE_BYTES_TO_BLOCKS(nextRecordIndexToAppend) - 1); uint8_t *writeDataBufStart = &Buffer[1]; if (priorBlockBytesToCopy > 0) { - uint8_t firstBlockData[DESFIRE_EEPROM_BLOCK_SIZE]; + uint8_t firstBlockData[DESFIRE_BLOCK_SIZE]; ReadBlockBytes(firstBlockData, fileDataWriteAddr, priorBlockBytesToCopy); - memcpy(firstBlockData + priorBlockBytesToCopy, writeDataBufStart, DESFIRE_EEPROM_BLOCK_SIZE - 1 - priorBlockBytesToCopy); - WriteBlockBytes(firstBlockData, fileDataWriteAddr, DESFIRE_EEPROM_BLOCK_SIZE); + memcpy(firstBlockData + priorBlockBytesToCopy, writeDataBufStart, DESFIRE_BLOCK_SIZE - 1 - priorBlockBytesToCopy); + WriteBlockBytes(firstBlockData, fileDataWriteAddr, DESFIRE_BLOCK_SIZE); fileDataWriteAddr += 1; - appendRecordLength -= DESFIRE_EEPROM_BLOCK_SIZE - priorBlockBytesToCopy; - writeDataBufStart += DESFIRE_EEPROM_BLOCK_SIZE - priorBlockBytesToCopy; + appendRecordLength -= DESFIRE_BLOCK_SIZE - priorBlockBytesToCopy; + writeDataBufStart += DESFIRE_BLOCK_SIZE - priorBlockBytesToCopy; } WriteBlockBytes(writeDataBufStart, fileDataWriteAddr, appendRecordLength); SelectedFile.File.RecordFile.RecordPointer = nextRecordPointer; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c index 3218995c..1c6cc7e2 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c @@ -34,69 +34,27 @@ This notice must be retained at the top of all source files where indicated. #include "DESFireFile.h" #include "DESFireLogging.h" -#define BLOCKWISE_IO_MULTIPLIER (DESFIRE_EEPROM_BLOCK_SIZE) -#define BLOCK_TRANSFER_SIZE (DESFIRE_EEPROM_BLOCK_SIZE) +#define BLOCKWISE_IO_MULTIPLIER (DESFIRE_BLOCK_SIZE) volatile char __InternalStringBuffer[STRING_BUFFER_SIZE] = { 0 }; char __InternalStringBuffer2[DATA_BUFFER_SIZE_SMALL] = { 0 }; void ReadBlockBytes(void *Buffer, SIZET StartBlock, SIZET Count) { - if (StartBlock >= MEMORY_SIZE_PER_SETTING) { + if (StartBlock * BLOCKWISE_IO_MULTIPLIER >= MEMORY_SIZE_PER_SETTING) { const char *rbbLogMsg = PSTR("RBB Too Lg - %d / %d"); DEBUG_PRINT_P(rbbLogMsg, StartBlock, MEMORY_SIZE_PER_SETTING); return; } - uint16_t numBlocks = DESFIRE_BYTES_TO_BLOCKS(Count); - uint16_t blockModDiff = Count % BLOCK_TRANSFER_SIZE; - if (blockModDiff == 0) { - MemoryReadBlockInSetting(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count); - } else { - if (Count > blockModDiff) { - MemoryReadBlockInSetting(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count - blockModDiff); - } - StartBlock += numBlocks - 1; - uint8_t fullBlock[BLOCK_TRANSFER_SIZE]; - MemoryReadBlockInSetting(fullBlock, StartBlock * BLOCKWISE_IO_MULTIPLIER, BLOCK_TRANSFER_SIZE); - // TODO: Reverse Mod buf when read ??? - //ReverseBuffer(fullBlock, BLOCK_TRANSFER_SIZE); - memcpy(Buffer + Count - blockModDiff, fullBlock, blockModDiff); - } + MemoryDownloadBlock(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count); } void WriteBlockBytesMain(const void *Buffer, SIZET StartBlock, SIZET Count) { - if (StartBlock >= MEMORY_SIZE_PER_SETTING) { + if (StartBlock * BLOCKWISE_IO_MULTIPLIER >= MEMORY_SIZE_PER_SETTING) { const char *wbbLogMsg = PSTR("WBB Too Lg - %d / %d"); DEBUG_PRINT_P(wbbLogMsg, StartBlock, MEMORY_SIZE_PER_SETTING); return; } - uint16_t numBlocks = DESFIRE_BYTES_TO_BLOCKS(Count); - uint16_t blockModDiff = Count % BLOCK_TRANSFER_SIZE; - if (blockModDiff == 0) { - MemoryWriteBlockInSetting(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count); - } else { - if (Count > blockModDiff) { - MemoryWriteBlockInSetting(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count - blockModDiff); - } - StartBlock += numBlocks - 1; - uint8_t fullBlock[BLOCK_TRANSFER_SIZE]; - memcpy(fullBlock, Buffer + Count - blockModDiff, blockModDiff); - memset(fullBlock + blockModDiff, 0x00, BLOCK_TRANSFER_SIZE - blockModDiff); - MemoryWriteBlockInSetting(fullBlock, StartBlock * BLOCKWISE_IO_MULTIPLIER, BLOCK_TRANSFER_SIZE); - } -} - -void CopyBlockBytes(SIZET DestBlock, SIZET SrcBlock, SIZET Count) { - uint8_t Buffer[DESFIRE_EEPROM_BLOCK_SIZE]; - uint16_t SrcOffset = SrcBlock; - uint16_t DestOffset = DestBlock; - while (Count > 0) { - SIZET bytesToWrite = MIN(Count, DESFIRE_EEPROM_BLOCK_SIZE); - ReadBlockBytes(Buffer, SrcOffset, bytesToWrite); - WriteBlockBytes(Buffer, DestOffset, bytesToWrite); - SrcOffset += 1; - DestOffset += 1; - Count -= DESFIRE_EEPROM_BLOCK_SIZE; - } + MemoryUploadBlock(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count); } uint16_t AllocateBlocksMain(uint16_t BlockCount) { @@ -107,7 +65,7 @@ uint16_t AllocateBlocksMain(uint16_t BlockCount) { return 0; } Picc.FirstFreeBlock = Block + BlockCount; - DESFIRE_INITIAL_FIRST_FREE_BLOCK_ID = Picc.FirstFreeBlock; + DESFIRE_FIRST_FREE_BLOCK_ID = Picc.FirstFreeBlock; SynchronizePICCInfo(); return Block; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h index 9f077430..f4231604 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h @@ -47,16 +47,12 @@ void WriteBlockBytesMain(const void *Buffer, SIZET StartBlock, SIZET Count); #define WriteBlockBytes(Buffer, StartBlock, Count) \ WriteBlockBytesMain(Buffer, StartBlock, Count); -void CopyBlockBytes(SIZET DestBlock, SIZET SrcBlock, SIZET Count); - uint16_t AllocateBlocksMain(uint16_t BlockCount); #define AllocateBlocks(BlockCount) \ AllocateBlocksMain(BlockCount); BYTE GetCardCapacityBlocks(void); -void MemsetBlockBytes(uint8_t initValue, SIZET startBlock, SIZET byteCount); - /* File data transfer related routines: */ void ReadDataEEPROMSource(uint8_t *Buffer, uint8_t Count); void WriteDataEEPROMSink(uint8_t *Buffer, uint8_t Count); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index 20660c30..19c4b839 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -331,6 +331,8 @@ void FactoryFormatPiccEV1(uint8_t StorageSize) { Picc.HwVersionMinor = DESFIRE_HW_MINOR_EV1; Picc.SwVersionMajor = DESFIRE_SW_MAJOR_EV1; Picc.SwVersionMinor = DESFIRE_SW_MINOR_EV1; + /* Reset the free block pointer */ + Picc.FirstFreeBlock = DESFIRE_FIRST_FREE_BLOCK_ID; /* Continue with user data initialization */ SynchronizePICCInfo(); FormatPicc(); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index 9233ae30..d1c6b144 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -37,13 +37,11 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_ISO7816_CLA 0x00 /* Storage allocation constants */ -#define DESFIRE_EEPROM_BLOCK_SIZE (4) // (8) // (16) /* Bytes */ -#define DESFIRE_BYTES_TO_BLOCKS(x) \ - ( ((x) + DESFIRE_EEPROM_BLOCK_SIZE - 1) / DESFIRE_EEPROM_BLOCK_SIZE ) +#define DESFIRE_BLOCK_SIZE (4) /* Bytes */ +#define DESFIRE_BYTES_TO_BLOCKS(x) ( ((x) + DESFIRE_BLOCK_SIZE - 1) / DESFIRE_BLOCK_SIZE ) -#define DESFIRE_UID_SIZE ISO14443A_UID_SIZE_DOUBLE - -#define DESFIRE_MAX_PAYLOAD_SIZE (64) /* Bytes */ +#define DESFIRE_UID_SIZE ISO14443A_UID_SIZE_DOUBLE +#define DESFIRE_MAX_PAYLOAD_SIZE (64) /* Bytes */ /* * Definitions pertaining to on-card data @@ -84,8 +82,7 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_SW_MAJOR_EV0 0x00 #define DESFIRE_SW_MINOR_EV0 0x01 -#define IsPiccEV0(picc) \ - (picc.HwVersionMajor == DESFIRE_HW_MAJOR_EV0 && picc.SwVersionMajor == DESFIRE_SW_MAJOR_EV0) +#define IsPiccEV0(picc) (picc.HwVersionMajor == DESFIRE_HW_MAJOR_EV0 && picc.SwVersionMajor == DESFIRE_SW_MAJOR_EV0) /* DESFire EV1 versions */ #define DESFIRE_HW_MAJOR_EV1 0x01 @@ -145,10 +142,10 @@ This notice must be retained at the top of all source files where indicated. * Defines the global PICC configuration. * This is located in the very first block on the card. */ -#define PICC_FORMAT_BYTE (0xff) // (0xf7) +#define PICC_FORMAT_BYTE (0x00) #define PICC_EMPTY_BYTE (0x00) -typedef struct DESFIRE_FIRMWARE_PACKING { +typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT{ /* Static data: does not change during the PICC's lifetime. * We will add Chameleon Mini terminal commands to enable * resetting this data so tags can be emulated authentically. diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index c6335aab..822174e8 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -60,10 +60,10 @@ static void MifareDesfireAppInitLocal(uint8_t StorageSize, uint8_t Version, bool DesfireState = DESFIRE_IDLE; DesfireFromHalt = false; switch (Version) { - case MIFARE_DESFIRE_EV0: + case MIFARE_DESFIRE_EV1: InitialisePiccBackendEV1(StorageSize, FormatPICC); break; - case MIFARE_DESFIRE_EV1: + case MIFARE_DESFIRE_EV0: default: /* Fall through */ InitialisePiccBackendEV0(StorageSize, FormatPICC); break; @@ -128,14 +128,9 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { (DesfireCmdCLA != DESFIRE_ISO7816_CLA)) { return ISO14443A_APP_NO_RESPONSE; } else if (Buffer[0] != STATUS_ADDITIONAL_FRAME) { - uint16_t ReturnBytes = CallInstructionHandler(Buffer, ByteCount); - return ReturnBytes; - } - - /* Expecting further data here */ - if (Buffer[0] != STATUS_ADDITIONAL_FRAME) { DesfireState = DESFIRE_IDLE; - return ISO14443A_APP_NO_RESPONSE; + uint16_t ReturnBytes = CallInstructionHandler(Buffer, ByteCount); + return ReturnBytes; } uint16_t ReturnBytes = 0; @@ -230,8 +225,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { return MifareDesfireProcess(Buffer, BitCount); } else if (ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 6) { - // Native wrapped command send without CRCA checksum bytes appended: - return MAX(0, MifareDesfireProcess(Buffer, BitCount) - 2 * BITS_PER_BYTE); + return MifareDesfireProcess(Buffer, BitCount); } else if (IsWrappedISO7816CommandType(Buffer, ByteCount)) { uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], Buffer, 2); @@ -256,12 +250,15 @@ void ResetLocalStructureData(void) { DesfireState = DESFIRE_HALT; InvalidateAuthState(0x00); memset(&Picc, PICC_FORMAT_BYTE, sizeof(Picc)); + memset(&AppDir, 0x00, sizeof(AppDir)); memset(&SelectedApp, 0x00, sizeof(SelectedApp)); memset(&SelectedFile, 0x00, sizeof(SelectedFile)); memset(&TransferState, 0x00, sizeof(TransferState)); memset(&SessionKey, 0x00, sizeof(CryptoKeyBufferType)); memset(&SessionIV, 0x00, sizeof(CryptoIVBufferType)); SessionIVByteSize = 0x00; + SelectedApp.Slot = 0; + SelectedFile.Num = -1; } void MifareDesfireGetUid(ConfigurationUidType Uid) { diff --git a/Firmware/Chameleon-Mini/Application/Reader14443A.c b/Firmware/Chameleon-Mini/Application/Reader14443A.c index c5d3b872..a0485a04 100644 --- a/Firmware/Chameleon-Mini/Application/Reader14443A.c +++ b/Firmware/Chameleon-Mini/Application/Reader14443A.c @@ -743,7 +743,7 @@ uint16_t Reader14443AAppProcess(uint8_t *Buffer, uint16_t BitCount) { CodecReaderFieldStop(); MemoryUploadBlock(&MFUContents, 0, 64); CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, "Card Cloned to Slot"); - ConfigurationSetById(CONFIG_MF_ULTRALIGHT); + ConfigurationSetById(CONFIG_MF_ULTRALIGHT, false); MemoryStore(); SettingsSave(); } @@ -871,7 +871,7 @@ uint16_t Reader14443AAppProcess(uint8_t *Buffer, uint16_t BitCount) { CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, "Cloned OK!"); /* Notify LED. blink when clone is done - ToDo: maybe use other LEDHook */ LEDHook(LED_SETTING_CHANGE, LED_BLINK_2X); - ConfigurationSetById(cfgid); + ConfigurationSetById(cfgid, false); ApplicationReset(); ApplicationSetUid(CardCharacteristics.UID); MemoryStore(); diff --git a/Firmware/Chameleon-Mini/Common.h b/Firmware/Chameleon-Mini/Common.h index 0581956b..d9472807 100644 --- a/Firmware/Chameleon-Mini/Common.h +++ b/Firmware/Chameleon-Mini/Common.h @@ -70,14 +70,4 @@ INLINE uint8_t StringLength(const char *Str, uint8_t MaxLen) { return StrLen; } -INLINE void ReverseBuffer(uint8_t *Buffer, uint16_t ByteCount) { - uint16_t BufferIndex = 0; - while(BufferIndex < ByteCount) { - uint8_t NextByte = Buffer[BufferIndex]; - Buffer[BufferIndex] = Buffer[ByteCount - 1 - BufferIndex]; - Buffer[ByteCount - 1 - BufferIndex] = NextByte; - ++BufferIndex; - } -} - #endif /* COMMON_H_ */ diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index e74ff203..a319aba4 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -72,7 +72,6 @@ static const MapEntryType PROGMEM ConfigurationMap[] = { { .Id = CONFIG_MF_DESFIRE, .Text = "MF_DESFIRE" }, { .Id = CONFIG_MF_DESFIRE_2KEV1, .Text = "MF_DESFIRE_2KEV1" }, { .Id = CONFIG_MF_DESFIRE_4KEV1, .Text = "MF_DESFIRE_4KEV1" }, - { .Id = CONFIG_MF_DESFIRE_8KEV1, .Text = "MF_DESFIRE_8KEV1" }, #endif }; @@ -493,22 +492,6 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .MemorySize = MIFARE_CLASSIC_4K_MEM_SIZE, .ReadOnly = false }, - [CONFIG_MF_DESFIRE_8KEV1] = { - .CodecInitFunc = ISO14443ACodecInit, - .CodecDeInitFunc = ISO14443ACodecDeInit, - .CodecTaskFunc = ISO14443ACodecTask, - .ApplicationInitFunc = MifareDesfire8kEV1AppInit, - .ApplicationInitRunOnceFunc = MifareDesfire8kEV1AppInitRunOnce, - .ApplicationResetFunc = MifareDesfireAppReset, - .ApplicationTaskFunc = MifareDesfireAppTask, - .ApplicationTickFunc = MifareDesfireAppTick, - .ApplicationProcessFunc = MifareDesfireAppProcess, - .ApplicationGetUidFunc = MifareDesfireGetUid, - .ApplicationSetUidFunc = MifareDesfireSetUid, - .UidSize = ISO14443A_UID_SIZE_DOUBLE, - .MemorySize = 2 * MIFARE_CLASSIC_4K_MEM_SIZE, - .ReadOnly = false - }, #endif }; @@ -541,7 +524,6 @@ void ConfigurationSetById(ConfigurationEnum Configuration, bool appInitRunOnce) ApplicationInitRunOnce(); /* Notify LED. blink according to current setting */ LEDHook(LED_SETTING_CHANGE, LED_BLINK_3X + Configuration); - } else { ApplicationInit(); /* Notify LED. blink according to current setting */ @@ -562,9 +544,16 @@ MapIdType ConfigurationCheckByName(const char *Configuration) { return 0xff; } -bool ConfigurationSetByName(const char *Configuration, bool appInitRunOnce) { +bool ConfigurationByNameIsValid(const char *Configuration) { MapIdType Id; + if (MapTextToId(ConfigurationMap, ARRAY_COUNT(ConfigurationMap), Configuration, &Id)) { + return true; + } + return false; +} +bool ConfigurationSetByName(const char *Configuration, bool appInitRunOnce) { + MapIdType Id; if (MapTextToId(ConfigurationMap, ARRAY_COUNT(ConfigurationMap), Configuration, &Id)) { ConfigurationSetById(Id, appInitRunOnce); LogEntry(LOG_INFO_CONFIG_SET, Configuration, StringLength(Configuration, CONFIGURATION_NAME_LENGTH_MAX - 1)); diff --git a/Firmware/Chameleon-Mini/Configuration.h b/Firmware/Chameleon-Mini/Configuration.h index 4c7fa876..3e5f82fe 100644 --- a/Firmware/Chameleon-Mini/Configuration.h +++ b/Firmware/Chameleon-Mini/Configuration.h @@ -74,7 +74,6 @@ typedef enum { CONFIG_MF_DESFIRE, CONFIG_MF_DESFIRE_2KEV1, CONFIG_MF_DESFIRE_4KEV1, - CONFIG_MF_DESFIRE_8KEV1, #endif /* This HAS to be the last element */ CONFIG_COUNT @@ -183,6 +182,7 @@ void ConfigurationInit(void); void ConfigurationSetById(ConfigurationEnum Configuration, bool appInitRunOnce); MapIdType ConfigurationCheckByName(const char *Configuration); void ConfigurationGetByName(char *Configuration, uint16_t BufferSize); +bool ConfigurationByNameIsValid(const char *Configuration); bool ConfigurationSetByName(const char *Configuration, bool appInitRunOnce); void ConfigurationGetList(char *ConfigurationList, uint16_t BufferSize); diff --git a/Firmware/Chameleon-Mini/Log.h b/Firmware/Chameleon-Mini/Log.h index 22d58fb5..0ed475a7 100644 --- a/Firmware/Chameleon-Mini/Log.h +++ b/Firmware/Chameleon-Mini/Log.h @@ -3,11 +3,7 @@ /** @file */ #include "Common.h" -#ifdef MEMORY_LIMITED_TESTING -#define LOG_SIZE 1024 -#else #define LOG_SIZE 2048 -#endif #define FRAM_LOG_ADDR_ADDR 0x4000 // start of the second half of FRAM #define FRAM_LOG_START_ADDR 0x4002 // directly after the address #define FRAM_LOG_SIZE 0x3FFE // the whole second half (minus the 2 Bytes of Address) diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 4e818807..31d1ecf2 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -45,8 +45,8 @@ SETTINGS += -DSUPPORT_FIRMWARE_UPGRADE #SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_UID_RIGHT_INCREMENT #SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_UID_LEFT_DECREMENT #SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_UID_RIGHT_DECREMENT -SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_CYCLE_SETTINGS -#SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_STORE_MEM +#SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_CYCLE_SETTINGS +SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_STORE_MEM SETTINGS += -DDEFAULT_LBUTTON_ACTION=BUTTON_ACTION_RECALL_MEM #Define if button action setting should be independent of active setting @@ -115,7 +115,7 @@ SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 # -> Or explicitly define DESFIRE_CUSTOM_MAX_KEYS=##UINT## (per AID), # -> And/Or define DESFIRE_CUSTOM_MAX_APPS=##UINT## # (total number of AID spaces available, not including the master 0x00) -SETTINGS += -DMEMORY_LIMITED_TESTING +#SETTINGS += -DMEMORY_LIMITED_TESTING #SETTINGS += -DDESFIRE_CUSTOM_MAX_APPS=8 #SETTINGS += -DDESFIRE_CUSTOM_MAX_KEYS=6 #SETTINGS += -DDESFIRE_CUSTOM_MAX_FILES=6 @@ -137,7 +137,7 @@ SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=1 DESFIRE_MAINSRC = Application/DESFire -DESFIRE_CONFIG_SETTINGS_BASE = $(SETTINGS) -DCONFIG_MF_DESFIRE_SUPPORT -DDESFIRE_CRYPTO1_SAVE_SPACE -UDEFAULT_CONFIGURATION +DESFIRE_CONFIG_SETTINGS_BASE = $(SETTINGS) -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_LIMITED_TESTING -DDESFIRE_CRYPTO1_SAVE_SPACE -UDEFAULT_CONFIGURATION #Memory definitions and objcopy flags to include sections in binaries FLASH_DATA_ADDR = 0x10000 #Start of data section in flash diff --git a/Firmware/Chameleon-Mini/Memory.c b/Firmware/Chameleon-Mini/Memory.c index 55f7aefb..c4cbd520 100644 --- a/Firmware/Chameleon-Mini/Memory.c +++ b/Firmware/Chameleon-Mini/Memory.c @@ -362,13 +362,6 @@ void MemoryReadBlock(void *Buffer, uint16_t Address, uint16_t ByteCount) { FRAMRead(Buffer, Address, ByteCount); } -void MemoryReadBlockInSetting(void *Buffer, uint16_t Address, uint16_t ByteCount) { - if (ByteCount == 0 || Address >= MEMORY_SIZE_PER_SETTING) - return; - uint16_t ActualFRAMAddress = Address + GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING; - FRAMRead(Buffer, ActualFRAMAddress, ByteCount); -} - void MemoryWriteBlock(const void *Buffer, uint16_t Address, uint16_t ByteCount) { if (ByteCount == 0) return; @@ -377,14 +370,6 @@ void MemoryWriteBlock(const void *Buffer, uint16_t Address, uint16_t ByteCount) LEDHook(LED_MEMORY_CHANGED, LED_ON); } -void MemoryWriteBlockInSetting(const void *Buffer, uint16_t Address, uint16_t ByteCount) { - if (ByteCount == 0 || Address >= MEMORY_SIZE_PER_SETTING) - return; - uint16_t ActualFRAMAddress = Address + GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING; - FRAMWrite(Buffer, ActualFRAMAddress, ByteCount); - LEDHook(LED_MEMORY_CHANGED, LED_ON); -} - void MemoryClear(void) { FlashErase((uint32_t) GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING, MEMORY_SIZE_PER_SETTING); diff --git a/Firmware/Chameleon-Mini/Memory.h b/Firmware/Chameleon-Mini/Memory.h index cc9447d6..35163009 100644 --- a/Firmware/Chameleon-Mini/Memory.h +++ b/Firmware/Chameleon-Mini/Memory.h @@ -10,6 +10,7 @@ #define MEMORY_SIZE (FLASH_DATA_SIZE) /* From Makefile */ #define MEMORY_INIT_VALUE 0x00 + #define MEMORY_SIZE_PER_SETTING 8192 #ifndef __ASSEMBLER__ @@ -17,9 +18,7 @@ void MemoryInit(void); void MemoryReadBlock(void *Buffer, uint16_t Address, uint16_t ByteCount); -void MemoryReadBlockInSetting(void *Buffer, uint16_t Address, uint16_t ByteCount); void MemoryWriteBlock(const void *Buffer, uint16_t Address, uint16_t ByteCount); -void MemoryWriteBlockInSetting(const void *Buffer, uint16_t Address, uint16_t ByteCount); void MemoryClear(void); void MemoryRecall(void); diff --git a/Firmware/Chameleon-Mini/Settings.c b/Firmware/Chameleon-Mini/Settings.c index 12bd19f2..98f7c8a2 100644 --- a/Firmware/Chameleon-Mini/Settings.c +++ b/Firmware/Chameleon-Mini/Settings.c @@ -70,8 +70,7 @@ bool SettingsSetActiveById(uint8_t Setting) { MemoryStore(); GlobalSettings.ActiveSettingIdx = SettingIdx; - GlobalSettings.ActiveSettingPtr = - &GlobalSettings.Settings[SettingIdx]; + GlobalSettings.ActiveSettingPtr = &GlobalSettings.Settings[SettingIdx]; /* Recall new memory contents ( Moved this to allow for Access to new Memory in Application init())*/ MemoryRecall(); diff --git a/Firmware/Chameleon-Mini/Settings.h b/Firmware/Chameleon-Mini/Settings.h index fbe658b2..a1eb20e1 100644 --- a/Firmware/Chameleon-Mini/Settings.h +++ b/Firmware/Chameleon-Mini/Settings.h @@ -15,12 +15,7 @@ #include "Memory.h" #include -#ifdef CONFIG_MF_DESFIRE_SUPPORT -#define SETTINGS_COUNT (MEMORY_SIZE / MEMORY_SIZE_PER_SETTING / 2) -#else #define SETTINGS_COUNT (MEMORY_SIZE / MEMORY_SIZE_PER_SETTING) -#endif - #define SETTINGS_FIRST 1 #define SETTINGS_LAST (SETTINGS_FIRST + SETTINGS_COUNT - 1) diff --git a/Firmware/Chameleon-Mini/Terminal/Commands.c b/Firmware/Chameleon-Mini/Terminal/Commands.c index f13ee67f..501813c0 100644 --- a/Firmware/Chameleon-Mini/Terminal/Commands.c +++ b/Firmware/Chameleon-Mini/Terminal/Commands.c @@ -44,8 +44,9 @@ CommandStatusIdType CommandSetConfig(char *OutMessage, const char *InParam) { if (COMMAND_IS_SUGGEST_STRING(InParam)) { ConfigurationGetList(OutMessage, TERMINAL_BUFFER_SIZE); return COMMAND_INFO_OK_WITH_TEXT_ID; - } else if (ConfigurationSetByName(InParam, true)) { - SETTING_UPDATE(GlobalSettings.ActiveSettingPtr->Configuration); + } else if (ConfigurationByNameIsValid(InParam)) { + ConfigurationSetByName(InParam, true); + SETTING_UPDATE(GlobalSettings.ActiveSettingPtr->Configuration); return COMMAND_INFO_OK_ID; } else { return COMMAND_ERR_INVALID_PARAM_ID; @@ -526,7 +527,7 @@ CommandStatusIdType CommandExecCloneMFU(char *OutMessage) { #ifndef CONFIG_ISO14443A_READER_SUPPORT return COMMAND_ERR_INVALID_USAGE_ID; #else - ConfigurationSetById(CONFIG_ISO14443A_READER); + ConfigurationSetById(CONFIG_ISO14443A_READER, false); ApplicationReset(); Reader14443CurrentCommand = Reader14443_Clone_MF_Ultralight; @@ -662,7 +663,7 @@ CommandStatusIdType CommandExecClone(char *OutMessage) { #ifndef CONFIG_ISO14443A_READER_SUPPORT return COMMAND_ERR_INVALID_USAGE_ID; #else - ConfigurationSetById(CONFIG_ISO14443A_READER); + ConfigurationSetById(CONFIG_ISO14443A_READER, false); ApplicationReset(); diff --git a/Firmware/Chameleon-Mini/Terminal/Terminal.h b/Firmware/Chameleon-Mini/Terminal/Terminal.h index 94f942e5..8aa06f01 100644 --- a/Firmware/Chameleon-Mini/Terminal/Terminal.h +++ b/Firmware/Chameleon-Mini/Terminal/Terminal.h @@ -17,7 +17,7 @@ #define TERMINAL_VBUS_MASK PIN5_bm #ifdef MEMORY_LIMITED_TESTING -#define TERMINAL_BUFFER_SIZE 128 +#define TERMINAL_BUFFER_SIZE 256 #else #define TERMINAL_BUFFER_SIZE 512 #endif From ba3c73629ce83ca791c9b926c2999fbb6614c4d2 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Fri, 11 Feb 2022 17:42:20 -0500 Subject: [PATCH 11/68] Bug fixes to observations in #313 --- .../Application/DESFire/DESFireInstructions.c | 4 ++-- .../DESFire/DESFireMemoryOperations.c | 4 ++-- Firmware/Chameleon-Mini/Log.h | 2 +- Firmware/Chameleon-Mini/Memory.c | 18 ++++++++++++++++++ Firmware/Chameleon-Mini/Memory.h | 2 ++ Firmware/Chameleon-Mini/Terminal/Terminal.h | 4 ---- 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index b6c9c039..b836f5bd 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -447,7 +447,7 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { } /* Make sure that this key is AES, and figure out its byte size */ BYTE cryptoKeyType = ReadKeyCryptoType(SelectedApp.Slot, KeyId); - if (!CryptoTypeDES(cryptoKeyType)) { + if (!CryptoType3KTDEA(cryptoKeyType)) { Buffer[0] = STATUS_NO_SUCH_KEY; return DESFIRE_STATUS_RESPONSE_SIZE; } @@ -492,7 +492,7 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { &Buffer[1], NULL, Key); /* Scrub the key */ - memset(*Key, 0, keySize); + memset(Key, 0, keySize); /* Done */ DesfireState = DESFIRE_LEGACY_AUTHENTICATE2; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c index 1c6cc7e2..ddb0c8da 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c @@ -45,7 +45,7 @@ void ReadBlockBytes(void *Buffer, SIZET StartBlock, SIZET Count) { DEBUG_PRINT_P(rbbLogMsg, StartBlock, MEMORY_SIZE_PER_SETTING); return; } - MemoryDownloadBlock(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count); + MemoryReadBlockInSetting(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count); } void WriteBlockBytesMain(const void *Buffer, SIZET StartBlock, SIZET Count) { @@ -54,7 +54,7 @@ void WriteBlockBytesMain(const void *Buffer, SIZET StartBlock, SIZET Count) { DEBUG_PRINT_P(wbbLogMsg, StartBlock, MEMORY_SIZE_PER_SETTING); return; } - MemoryUploadBlock(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count); + MemoryWriteBlockInSetting(Buffer, StartBlock * BLOCKWISE_IO_MULTIPLIER, Count); } uint16_t AllocateBlocksMain(uint16_t BlockCount) { diff --git a/Firmware/Chameleon-Mini/Log.h b/Firmware/Chameleon-Mini/Log.h index 0ed475a7..39828d1f 100644 --- a/Firmware/Chameleon-Mini/Log.h +++ b/Firmware/Chameleon-Mini/Log.h @@ -3,7 +3,7 @@ /** @file */ #include "Common.h" -#define LOG_SIZE 2048 +#define LOG_SIZE 2048 #define FRAM_LOG_ADDR_ADDR 0x4000 // start of the second half of FRAM #define FRAM_LOG_START_ADDR 0x4002 // directly after the address #define FRAM_LOG_SIZE 0x3FFE // the whole second half (minus the 2 Bytes of Address) diff --git a/Firmware/Chameleon-Mini/Memory.c b/Firmware/Chameleon-Mini/Memory.c index c4cbd520..d0800210 100644 --- a/Firmware/Chameleon-Mini/Memory.c +++ b/Firmware/Chameleon-Mini/Memory.c @@ -366,7 +366,25 @@ void MemoryWriteBlock(const void *Buffer, uint16_t Address, uint16_t ByteCount) if (ByteCount == 0) return; FRAMWrite(Buffer, Address, ByteCount); + LEDHook(LED_MEMORY_CHANGED, LED_ON); +} +void MemoryReadBlockInSetting(void *Buffer, uint16_t Address, uint16_t ByteCount) { + if (ByteCount == 0 || ByteCount >= MEMORY_SIZE_PER_SETTING) + return; + uint16_t ShiftedAddress = Address + GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING; + if (ShiftedAddress < Address) + return; + FRAMRead(Buffer, ShiftedAddress, ByteCount); +} + +void MemoryWriteBlockInSetting(const void *Buffer, uint16_t Address, uint16_t ByteCount) { + if (ByteCount == 0 || ByteCount >= MEMORY_SIZE_PER_SETTING) + return; + uint16_t ShiftedAddress = Address + GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING; + if (ShiftedAddress < Address) + return; + FRAMWrite(Buffer, ShiftedAddress, ByteCount); LEDHook(LED_MEMORY_CHANGED, LED_ON); } diff --git a/Firmware/Chameleon-Mini/Memory.h b/Firmware/Chameleon-Mini/Memory.h index 35163009..eb58c4a3 100644 --- a/Firmware/Chameleon-Mini/Memory.h +++ b/Firmware/Chameleon-Mini/Memory.h @@ -19,6 +19,8 @@ void MemoryInit(void); void MemoryReadBlock(void *Buffer, uint16_t Address, uint16_t ByteCount); void MemoryWriteBlock(const void *Buffer, uint16_t Address, uint16_t ByteCount); +void MemoryReadBlockInSetting(void *Buffer, uint16_t Address, uint16_t ByteCount); +void MemoryWriteBlockInSetting(const void *Buffer, uint16_t Address, uint16_t ByteCount); void MemoryClear(void); void MemoryRecall(void); diff --git a/Firmware/Chameleon-Mini/Terminal/Terminal.h b/Firmware/Chameleon-Mini/Terminal/Terminal.h index 8aa06f01..36217c1c 100644 --- a/Firmware/Chameleon-Mini/Terminal/Terminal.h +++ b/Firmware/Chameleon-Mini/Terminal/Terminal.h @@ -16,11 +16,7 @@ #define TERMINAL_VBUS_PORT PORTD #define TERMINAL_VBUS_MASK PIN5_bm -#ifdef MEMORY_LIMITED_TESTING -#define TERMINAL_BUFFER_SIZE 256 -#else #define TERMINAL_BUFFER_SIZE 512 -#endif typedef enum { TERMINAL_UNINITIALIZED, From e22b286c9eff4428629760a3d5031cd8bdc7de91 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Fri, 11 Feb 2022 17:43:41 -0500 Subject: [PATCH 12/68] Removing default testing nonce B from auth commands ; Running make style --- .../Chameleon-Mini/Application/CryptoTDEA.c | 58 ++++++------ .../Chameleon-Mini/Application/CryptoTDEA.h | 12 +-- .../DESFire/DESFireApplicationDirectory.c | 14 +-- .../DESFire/DESFireApplicationDirectory.h | 6 +- .../DESFire/DESFireChameleonTerminal.c | 8 +- .../Application/DESFire/DESFireCrypto.c | 50 +++++----- .../Application/DESFire/DESFireCrypto.h | 2 +- .../Application/DESFire/DESFireInstructions.c | 46 ++++----- .../DESFire/DESFirePICCHeaderLayout.h | 2 +- .../Application/MifareDESFire.c | 22 ++--- Firmware/Chameleon-Mini/Configuration.c | 94 +++++++++---------- Firmware/Chameleon-Mini/Configuration.h | 8 +- Firmware/Chameleon-Mini/Makefile | 4 +- Firmware/Chameleon-Mini/Memory.c | 2 +- Firmware/Chameleon-Mini/Terminal/Commands.c | 4 +- .../Chameleon-Mini/Tests/ChameleonTerminal.c | 4 +- Firmware/Chameleon-Mini/Tests/CryptoTests.c | 28 +++--- 17 files changed, 182 insertions(+), 182 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c index 97f1b3af..11314ec2 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c @@ -21,19 +21,19 @@ void EncryptDESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, c if (IVIn == NULL) { memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); } else { - memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); } while (blockIndex < numBlocks) { if (blockIndex == 0) { memcpy(inputBlock, &Plaintext[0], CRYPTO_DES_BLOCK_SIZE); - CryptoMemoryXOR(IV, inputBlock, CRYPTO_DES_BLOCK_SIZE); - } else { + CryptoMemoryXOR(IV, inputBlock, CRYPTO_DES_BLOCK_SIZE); + } else { memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); - CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_DES_BLOCK_SIZE], inputBlock, CRYPTO_DES_BLOCK_SIZE); - } - CryptoSpec.cryptFunc(inputBlock, ctBuf, Keys); - ctBuf += CryptoSpec.blockSize; - blockIndex++; + CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_DES_BLOCK_SIZE], inputBlock, CRYPTO_DES_BLOCK_SIZE); + } + CryptoSpec.cryptFunc(inputBlock, ctBuf, Keys); + ctBuf += CryptoSpec.blockSize; + blockIndex++; } } @@ -49,18 +49,18 @@ void DecryptDESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, c if (IVIn == NULL) { memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); } else { - memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); } while (blockIndex < numBlocks) { - CryptoSpec.cryptFunc(inputBlock, Ciphertext + blockIndex * CRYPTO_DES_BLOCK_SIZE, Keys); + CryptoSpec.cryptFunc(inputBlock, Ciphertext + blockIndex * CRYPTO_DES_BLOCK_SIZE, Keys); if (blockIndex == 0) { memcpy(Plaintext, inputBlock, CRYPTO_DES_BLOCK_SIZE); - CryptoMemoryXOR(IV, Plaintext, CRYPTO_DES_BLOCK_SIZE); - } else { + CryptoMemoryXOR(IV, Plaintext, CRYPTO_DES_BLOCK_SIZE); + } else { memcpy(Plaintext + blockIndex * CRYPTO_DES_BLOCK_SIZE, inputBlock, CRYPTO_DES_BLOCK_SIZE); - CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], - Plaintext + blockIndex * CRYPTO_DES_BLOCK_SIZE, CRYPTO_DES_BLOCK_SIZE); - } + CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], + Plaintext + blockIndex * CRYPTO_DES_BLOCK_SIZE, CRYPTO_DES_BLOCK_SIZE); + } blockIndex++; } } @@ -78,19 +78,19 @@ void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, if (IVIn == NULL) { memset(IV, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); } else { - memcpy(IV, IVIn, CRYPTO_3KTDEA_BLOCK_SIZE); + memcpy(IV, IVIn, CRYPTO_3KTDEA_BLOCK_SIZE); } while (blockIndex < numBlocks) { if (blockIndex == 0) { memcpy(inputBlock, &Plaintext[0], CRYPTO_3KTDEA_BLOCK_SIZE); - CryptoMemoryXOR(IV, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); - } else { + CryptoMemoryXOR(IV, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); + } else { memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], CRYPTO_3KTDEA_BLOCK_SIZE); - CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE], inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); - } - CryptoSpec.cryptFunc(inputBlock, ctBuf, Keys); + CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE], inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); + } + CryptoSpec.cryptFunc(inputBlock, ctBuf, Keys); ctBuf += CryptoSpec.blockSize; - blockIndex++; + blockIndex++; } } @@ -106,18 +106,18 @@ void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, if (IVIn == NULL) { memset(IV, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); } else { - memcpy(IV, IVIn, CRYPTO_3KTDEA_BLOCK_SIZE); + memcpy(IV, IVIn, CRYPTO_3KTDEA_BLOCK_SIZE); } while (blockIndex < numBlocks) { - CryptoSpec.cryptFunc(inputBlock, Ciphertext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, Keys); + CryptoSpec.cryptFunc(inputBlock, Ciphertext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, Keys); if (blockIndex == 0) { memcpy(Plaintext, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); - CryptoMemoryXOR(IV, Plaintext, CRYPTO_3KTDEA_BLOCK_SIZE); - } else { + CryptoMemoryXOR(IV, Plaintext, CRYPTO_3KTDEA_BLOCK_SIZE); + } else { memcpy(Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); - CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], - Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, CRYPTO_3KTDEA_BLOCK_SIZE); - } + CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], + Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, CRYPTO_3KTDEA_BLOCK_SIZE); + } blockIndex++; } } diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h index 90b90573..e6b28b1c 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h @@ -1,9 +1,9 @@ - /* - * CryptoDES.h - * - * Created on: 18.10.2016 - * Author: dev_zzo - */ +/* +* CryptoDES.h +* +* Created on: 18.10.2016 +* Author: dev_zzo +*/ #ifndef CRYPTODES_H_ #define CRYPTODES_H_ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c index df512633..d66cc85a 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c @@ -209,7 +209,7 @@ void SetAppProperty(DesfireCardLayout propId, BYTE AppSlot, SIZET Value) { bool KeyIdValid(uint8_t AppSlot, uint8_t KeyId) { if (KeyId >= DESFIRE_MAX_KEYS || KeyId >= ReadMaxKeyCount(AppSlot)) { const char *debugMsg = PSTR("INVKEY-KeyId(%02x)-RdMax(%02x)"); - DEBUG_PRINT_P(debugMsg, KeyId, ReadMaxKeyCount(AppSlot)); + DEBUG_PRINT_P(debugMsg, KeyId, ReadMaxKeyCount(AppSlot)); return false; } return true; @@ -585,8 +585,8 @@ uint16_t CreateApp(const DESFireAidType Aid, uint8_t KeyCount, uint8_t KeySettin /* Allocate storage for the application structure itself */ AppDir.AppCacheStructBlockOffset[Slot] = AllocateBlocks(SELECTED_APP_CACHE_TYPE_BLOCK_SIZE); if (AppDir.AppCacheStructBlockOffset[Slot] == 0) { - const char *debugMsg = PSTR("X - alloc blks, slot = %d"); - DEBUG_PRINT_P(debugMsg, Slot); + const char *debugMsg = PSTR("X - alloc blks, slot = %d"); + DEBUG_PRINT_P(debugMsg, Slot); return STATUS_OUT_OF_EEPROM_ERROR; } /* Allocate storage for the application components */ @@ -628,8 +628,8 @@ uint16_t CreateApp(const DESFireAidType Aid, uint8_t KeyCount, uint8_t KeySettin } else { SIZET fileAccessRightsData[DESFIRE_MAX_FILES]; for (int fidx = 0; fidx < DESFIRE_MAX_FILES; fidx++) { - fileAccessRightsData[fidx] = 0x000f; - } + fileAccessRightsData[fidx] = 0x000f; + } WriteBlockBytes(fileAccessRightsData, appCacheData.FileAccessRights, sizeof(SIZET) * DESFIRE_MAX_FILES); } appCacheData.KeyVersionsArray = AllocateBlocks(APP_CACHE_KEY_VERSIONS_ARRAY_BLOCK_SIZE); @@ -669,8 +669,8 @@ uint16_t CreateApp(const DESFireAidType Aid, uint8_t KeyCount, uint8_t KeySettin } BYTE cryptoBlankKeyData[CRYPTO_MAX_KEY_SIZE]; memset(cryptoBlankKeyData, 0x00, CRYPTO_MAX_KEY_SIZE); - WriteBlockBytes(cryptoBlankKeyData, keyAddresses[0], CRYPTO_MAX_KEY_SIZE); - WriteBlockBytes(keyAddresses, appCacheData.KeyAddress, sizeof(SIZET) * DESFIRE_MAX_KEYS); + WriteBlockBytes(cryptoBlankKeyData, keyAddresses[0], CRYPTO_MAX_KEY_SIZE); + WriteBlockBytes(keyAddresses, appCacheData.KeyAddress, sizeof(SIZET) * DESFIRE_MAX_KEYS); } SIZET appCacheDataBlockId = AppDir.AppCacheStructBlockOffset[Slot]; WriteBlockBytes(&appCacheData, appCacheDataBlockId, sizeof(SelectedAppCacheType)); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h index aa7e962e..3c501617 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.h @@ -37,7 +37,7 @@ This notice must be retained at the top of all source files where indicated. #ifdef MEMORY_LIMITED_TESTING #define DESFIRE_MAX_APPS (3) -#else +#else #ifdef DESFIRE_CUSTOM_MAX_APPS #define DESFIRE_MAX_APPS (DESFIRE_CUSTOM_MAX_APPS) #else @@ -49,7 +49,7 @@ This notice must be retained at the top of all source files where indicated. #ifdef MEMORY_LIMITED_TESTING #define DESFIRE_MAX_FILES (4) -#else +#else #ifdef DESFIRE_CUSTOM_MAX_FILES #define DESFIRE_MAX_FILES (DESFIRE_CUSTOM_MAX_FILES) #else @@ -59,7 +59,7 @@ This notice must be retained at the top of all source files where indicated. #ifdef MEMORY_LIMITED_TESTING #define DESFIRE_MAX_KEYS (2) -#else +#else #ifdef DESFIRE_CUSTOM_MAX_KEYS #define DESFIRE_MAX_KEYS (DESFIRE_CUSTOM_MAX_KEYS) #else diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c index efdbaa9d..92e202af 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c @@ -242,13 +242,13 @@ CommandStatusIdType CommandDESFireSetTestingMode(char *OutParam, const char *InP CommandStatusIdType CommandDESFireGetCommMode(char *OutParam) { if (!IsDESFireConfiguration()) { ExitOnInvalidConfigurationError(OutParam); - } else if(DesfireCommMode == DESFIRE_COMMS_PLAINTEXT) { + } else if (DesfireCommMode == DESFIRE_COMMS_PLAINTEXT) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Plaintext")); - } else if(DesfireCommMode == DESFIRE_COMMS_PLAINTEXT_MAC) { + } else if (DesfireCommMode == DESFIRE_COMMS_PLAINTEXT_MAC) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Plaintext/MAC")); - } else if(DesfireCommMode == DESFIRE_COMMS_CIPHERTEXT_DES) { + } else if (DesfireCommMode == DESFIRE_COMMS_CIPHERTEXT_DES) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Enciphered/DES")); - } else if(DesfireCommMode == DESFIRE_COMMS_CIPHERTEXT_AES128) { + } else if (DesfireCommMode == DESFIRE_COMMS_CIPHERTEXT_AES128) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Enciphered/AES128")); } else { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Unknown")); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c index 3ba04aaf..fa0abeb3 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c @@ -122,32 +122,32 @@ const char *GetCommSettingsDesc(uint8_t cryptoType) { /* Code is adapted from @github/andrade/nfcjlib */ bool generateSessionKey(uint8_t *sessionKey, uint8_t *rndA, uint8_t *rndB, uint16_t cryptoType) { - switch(cryptoType) { - case CRYPTO_TYPE_DES: + switch (cryptoType) { + case CRYPTO_TYPE_DES: + memcpy(sessionKey, rndA, 4); + memcpy(sessionKey + 4, rndB, 4); + break; + case CRYPTO_TYPE_2KTDEA: + memcpy(sessionKey, rndA, 4); + memcpy(sessionKey + 4, rndB, 4); + memcpy(sessionKey + 8, rndA + 4, 4); + memcpy(sessionKey + 12, rndB + 4, 4); + break; + case CRYPTO_TYPE_3K3DES: + memcpy(sessionKey, rndA, 4); + memcpy(sessionKey + 4, rndB, 4); + memcpy(sessionKey + 8, rndA + 6, 4); + memcpy(sessionKey + 12, rndB + 6, 4); + memcpy(sessionKey + 16, rndA + 12, 4); + memcpy(sessionKey + 20, rndB + 12, 4); + break; + case CRYPTO_TYPE_AES128: memcpy(sessionKey, rndA, 4); - memcpy(sessionKey + 4, rndB, 4); - break; - case CRYPTO_TYPE_2KTDEA: - memcpy(sessionKey, rndA, 4); - memcpy(sessionKey + 4, rndB, 4); - memcpy(sessionKey + 8, rndA + 4, 4); - memcpy(sessionKey + 12, rndB + 4, 4); - break; - case CRYPTO_TYPE_3K3DES: - memcpy(sessionKey, rndA, 4); - memcpy(sessionKey + 4, rndB, 4); - memcpy(sessionKey + 8, rndA + 6, 4); - memcpy(sessionKey + 12, rndB + 6, 4); - memcpy(sessionKey + 16, rndA + 12, 4); - memcpy(sessionKey + 20, rndB + 12, 4); - break; - case CRYPTO_TYPE_AES128: - memcpy(sessionKey, rndA, 4); - memcpy(sessionKey + 4, rndB, 4); - memcpy(sessionKey + 8, rndA + 12, 4); - memcpy(sessionKey + 12, rndB + 12, 4); - break; - default: + memcpy(sessionKey + 4, rndB, 4); + memcpy(sessionKey + 8, rndA + 12, 4); + memcpy(sessionKey + 12, rndB + 12, 4); + break; + default: return false; } return true; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h index a21ceebb..10e637be 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h @@ -64,7 +64,7 @@ extern BYTE DesfireCommMode; /* Key sizes, block sizes (in bytes): */ #define CRYPTO_AES_KEY_SIZE (16) -#define CRYPTO_MAX_KEY_SIZE (24) +#define CRYPTO_MAX_KEY_SIZE (24) #define CRYPTO_MAX_BLOCK_SIZE (16) #define DESFIRE_AES_IV_SIZE (CRYPTO_AES_BLOCK_SIZE) #define CRYPTO_CHALLENGE_RESPONSE_BYTES (16) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index b836f5bd..222e9d98 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -45,15 +45,15 @@ This notice must be retained at the top of all source files where indicated. DesfireSavedCommandStateType DesfireCommandState = { 0 }; -/* NOTE: The order of the structures in this buffer MUST be kept in - * ascending sorted order by the INS code. This property of the - * array has to be maintained as new commands and functions are - * added to keep CallInstructionHandler(uint8_t*, uint16_t) - * operating correctly. The instruction handler performs a - * binary search on the array to save time locating the correct - * C function to call to execute the command -- and this speedup - * helps keep timing issues at bay. DO NOT just append new command - * handlers to the end of the array, or insert them haphazardly in +/* NOTE: The order of the structures in this buffer MUST be kept in + * ascending sorted order by the INS code. This property of the + * array has to be maintained as new commands and functions are + * added to keep CallInstructionHandler(uint8_t*, uint16_t) + * operating correctly. The instruction handler performs a + * binary search on the array to save time locating the correct + * C function to call to execute the command -- and this speedup + * helps keep timing issues at bay. DO NOT just append new command + * handlers to the end of the array, or insert them haphazardly in * the middle !!! */ const __flash DESFireCommand DESFireCommandSet[] = { @@ -309,19 +309,19 @@ uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount) { uint16_t curInsLower = 0, curInsUpper = sizeof(DESFireCommandSet) / sizeof(DESFireCommand) - 1; uint16_t curInsIndex; DESFireCommand dfCmd; - while(curInsUpper >= curInsLower) { + while (curInsUpper >= curInsLower) { curInsIndex = curInsLower + (curInsUpper + 1 - curInsLower) / 2; memcpy_P(&dfCmd, insLookupTableBuf + curInsIndex * sizeof(DESFireCommand), sizeof(DESFireCommand)); if (dfCmd.insCode == insCode) { - if (dfCmd.insFunc == NULL) { - return CmdNotImplemented(Buffer, ByteCount); - } - return dfCmd.insFunc(Buffer, ByteCount); - } else if (dfCmd.insCode < insCode) { - curInsLower = curInsIndex + 1; - } else { - curInsUpper = curInsIndex - 1; - } + if (dfCmd.insFunc == NULL) { + return CmdNotImplemented(Buffer, ByteCount); + } + return dfCmd.insFunc(Buffer, ByteCount); + } else if (dfCmd.insCode < insCode) { + curInsLower = curInsIndex + 1; + } else { + curInsUpper = curInsIndex - 1; + } } return ISO14443A_APP_NO_RESPONSE; } @@ -507,7 +507,7 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; - + /* Validate command length */ if (ByteCount != 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES + 1) { Buffer[0] = STATUS_LENGTH_ERROR; @@ -534,7 +534,7 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { /* Check that the returned RndB matches what we sent in the previous round */ if (memcmp(DesfireCommandState.RndB, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES)) { Buffer[0] = STATUS_AUTHENTICATION_ERROR; - return DESFIRE_STATUS_RESPONSE_SIZE; + return DESFIRE_STATUS_RESPONSE_SIZE; } /* Authenticated successfully */ @@ -1791,7 +1791,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Check that the returned RndB matches what we sent in the previous round */ if (memcmp(DesfireCommandState.RndB, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES)) { LogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, (const void *) challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - Buffer[0] = STATUS_AUTHENTICATION_ERROR; + Buffer[0] = STATUS_AUTHENTICATION_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } @@ -1805,7 +1805,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, Key); - + generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_3K3DES); /* Return the status on success */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index d1c6b144..be0479ac 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -145,7 +145,7 @@ This notice must be retained at the top of all source files where indicated. #define PICC_FORMAT_BYTE (0x00) #define PICC_EMPTY_BYTE (0x00) -typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT{ +typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT { /* Static data: does not change during the PICC's lifetime. * We will add Chameleon Mini terminal commands to enable * resetting this data so tags can be emulated authentically. diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 822174e8..e05ba826 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -61,12 +61,12 @@ static void MifareDesfireAppInitLocal(uint8_t StorageSize, uint8_t Version, bool DesfireFromHalt = false; switch (Version) { case MIFARE_DESFIRE_EV1: - InitialisePiccBackendEV1(StorageSize, FormatPICC); - break; - case MIFARE_DESFIRE_EV0: - default: /* Fall through */ - InitialisePiccBackendEV0(StorageSize, FormatPICC); - break; + InitialisePiccBackendEV1(StorageSize, FormatPICC); + break; + case MIFARE_DESFIRE_EV0: + default: /* Fall through */ + InitialisePiccBackendEV0(StorageSize, FormatPICC); + break; } DesfireCommMode = DESFIRE_DEFAULT_COMMS_STANDARD; } @@ -129,7 +129,7 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { return ISO14443A_APP_NO_RESPONSE; } else if (Buffer[0] != STATUS_ADDITIONAL_FRAME) { DesfireState = DESFIRE_IDLE; - uint16_t ReturnBytes = CallInstructionHandler(Buffer, ByteCount); + uint16_t ReturnBytes = CallInstructionHandler(Buffer, ByteCount); return ReturnBytes; } @@ -172,8 +172,8 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { size_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; DesfireCmdCLA = Buffer[0]; if ((ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) || Iso7816CLA(DesfireCmdCLA)) { - // Wrapped native command structure: + Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) || Iso7816CLA(DesfireCmdCLA)) { + // Wrapped native command structure: /* Unwrap the PDU from ISO 7816-4 */ // Check CRC bytes appended to the buffer: // -- Actually, just ignore parity problems if they exist, @@ -238,8 +238,8 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { ISO14443AAppendCRCA(Buffer, ProcessedByteCount); ProcessedBitCount += 2 * BITS_PER_BYTE; return ProcessedBitCount; - } else if((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { - return ReturnedBytes; + } else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { + return ReturnedBytes; } else { return ISO144433APiccProcess(Buffer, BitCount); } diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index a319aba4..cdc5ac86 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -96,8 +96,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = CodecDeInitDummy, .CodecTaskFunc = CodecTaskDummy, .ApplicationInitFunc = ApplicationInitDummy, - .ApplicationInitRunOnceFunc = ApplicationInitDummy, - .ApplicationResetFunc = ApplicationResetDummy, + .ApplicationInitRunOnceFunc = ApplicationInitDummy, + .ApplicationResetFunc = ApplicationResetDummy, .ApplicationTaskFunc = ApplicationTaskDummy, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = ApplicationProcessDummy, @@ -114,8 +114,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareUltralightAppInit, - .ApplicationInitRunOnceFunc = MifareUltralightAppInit, - .ApplicationResetFunc = MifareUltralightAppReset, + .ApplicationInitRunOnceFunc = MifareUltralightAppInit, + .ApplicationResetFunc = MifareUltralightAppReset, .ApplicationTaskFunc = MifareUltralightAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareUltralightAppProcess, @@ -131,8 +131,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareUltralightCAppInit, - .ApplicationInitRunOnceFunc = MifareUltralightCAppInit, - .ApplicationResetFunc = MifareUltralightCAppReset, + .ApplicationInitRunOnceFunc = MifareUltralightCAppInit, + .ApplicationResetFunc = MifareUltralightCAppReset, .ApplicationTaskFunc = MifareUltralightAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareUltralightAppProcess, @@ -148,8 +148,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareUltralightEV11AppInit, - .ApplicationInitRunOnceFunc = MifareUltralightEV11AppInit, - .ApplicationResetFunc = MifareUltralightAppReset, + .ApplicationInitRunOnceFunc = MifareUltralightEV11AppInit, + .ApplicationResetFunc = MifareUltralightAppReset, .ApplicationTaskFunc = MifareUltralightAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareUltralightAppProcess, @@ -165,8 +165,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareUltralightEV12AppInit, - .ApplicationInitRunOnceFunc = MifareUltralightEV12AppInit, - .ApplicationResetFunc = MifareUltralightAppReset, + .ApplicationInitRunOnceFunc = MifareUltralightEV12AppInit, + .ApplicationResetFunc = MifareUltralightAppReset, .ApplicationTaskFunc = MifareUltralightAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareUltralightAppProcess, @@ -184,8 +184,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareClassicAppInitMini4B, - .ApplicationInitRunOnceFunc = MifareClassicAppInitMini4B, - .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationInitRunOnceFunc = MifareClassicAppInitMini4B, + .ApplicationResetFunc = MifareClassicAppReset, .ApplicationTaskFunc = MifareClassicAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareClassicAppProcess, @@ -203,8 +203,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareClassicAppInit1K, - .ApplicationInitRunOnceFunc = MifareClassicAppInit1K, - .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationInitRunOnceFunc = MifareClassicAppInit1K, + .ApplicationResetFunc = MifareClassicAppReset, .ApplicationTaskFunc = MifareClassicAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareClassicAppProcess, @@ -222,8 +222,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareClassicAppInit1K7B, - .ApplicationInitRunOnceFunc = MifareClassicAppInit1K7B, - .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationInitRunOnceFunc = MifareClassicAppInit1K7B, + .ApplicationResetFunc = MifareClassicAppReset, .ApplicationTaskFunc = MifareClassicAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareClassicAppProcess, @@ -241,8 +241,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareClassicAppInit4K, - .ApplicationInitRunOnceFunc = MifareClassicAppInit4K, - .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationInitRunOnceFunc = MifareClassicAppInit4K, + .ApplicationResetFunc = MifareClassicAppReset, .ApplicationTaskFunc = MifareClassicAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareClassicAppProcess, @@ -260,8 +260,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareClassicAppInit4K7B, - .ApplicationInitRunOnceFunc = MifareClassicAppInit4K7B, - .ApplicationResetFunc = MifareClassicAppReset, + .ApplicationInitRunOnceFunc = MifareClassicAppInit4K7B, + .ApplicationResetFunc = MifareClassicAppReset, .ApplicationTaskFunc = MifareClassicAppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = MifareClassicAppProcess, @@ -279,8 +279,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = Sniff14443ACodecDeInit, .CodecTaskFunc = Sniff14443ACodecTask, .ApplicationInitFunc = Sniff14443AAppInit, - .ApplicationInitRunOnceFunc = Sniff14443AAppInit, - .ApplicationResetFunc = Sniff14443AAppReset, + .ApplicationInitRunOnceFunc = Sniff14443AAppInit, + .ApplicationResetFunc = Sniff14443AAppReset, .ApplicationTaskFunc = Sniff14443AAppTask, .ApplicationTickFunc = Sniff14443AAppTick, .ApplicationProcessFunc = Sniff14443AAppProcess, @@ -298,8 +298,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = Reader14443ACodecDeInit, .CodecTaskFunc = Reader14443ACodecTask, .ApplicationInitFunc = Reader14443AAppInit, - .ApplicationInitRunOnceFunc = Reader14443AAppInit, - .ApplicationResetFunc = Reader14443AAppReset, + .ApplicationInitRunOnceFunc = Reader14443AAppInit, + .ApplicationResetFunc = Reader14443AAppReset, .ApplicationTaskFunc = Reader14443AAppTask, .ApplicationTickFunc = Reader14443AAppTick, .ApplicationProcessFunc = Reader14443AAppProcess, @@ -317,8 +317,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, .ApplicationInitFunc = VicinityAppInit, - .ApplicationInitRunOnceFunc = VicinityAppInit, - .ApplicationResetFunc = VicinityAppReset, + .ApplicationInitRunOnceFunc = VicinityAppInit, + .ApplicationResetFunc = VicinityAppReset, .ApplicationTaskFunc = VicinityAppTask, .ApplicationTickFunc = VicinityAppTick, .ApplicationProcessFunc = VicinityAppProcess, @@ -336,8 +336,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, .ApplicationInitFunc = ApplicationInitDummy, - .ApplicationInitRunOnceFunc = ApplicationInitDummy, - .ApplicationResetFunc = ApplicationResetDummy, + .ApplicationInitRunOnceFunc = ApplicationInitDummy, + .ApplicationResetFunc = ApplicationResetDummy, .ApplicationTaskFunc = ApplicationTaskDummy, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = ApplicationProcessDummy, @@ -355,8 +355,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, .ApplicationInitFunc = Sl2s2002AppInit, - .ApplicationInitRunOnceFunc = Sl2s2002AppInit, - .ApplicationResetFunc = Sl2s2002AppReset, + .ApplicationInitRunOnceFunc = Sl2s2002AppInit, + .ApplicationResetFunc = Sl2s2002AppReset, .ApplicationTaskFunc = Sl2s2002AppTask, .ApplicationTickFunc = Sl2s2002AppTick, .ApplicationProcessFunc = Sl2s2002AppProcess, @@ -374,8 +374,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, .ApplicationInitFunc = TITagitstandardAppInit, - .ApplicationInitRunOnceFunc = TITagitstandardAppInit, - .ApplicationResetFunc = TITagitstandardAppReset, + .ApplicationInitRunOnceFunc = TITagitstandardAppInit, + .ApplicationResetFunc = TITagitstandardAppReset, .ApplicationTaskFunc = TITagitstandardAppTask, .ApplicationTickFunc = TITagitstandardAppTick, .ApplicationProcessFunc = TITagitstandardAppProcess, @@ -393,8 +393,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, .ApplicationInitFunc = TITagitplusAppInit, - .ApplicationInitRunOnceFunc = TITagitplusAppInit, - .ApplicationResetFunc = TITagitplusAppReset, + .ApplicationInitRunOnceFunc = TITagitplusAppInit, + .ApplicationResetFunc = TITagitplusAppReset, .ApplicationTaskFunc = TITagitplusAppTask, .ApplicationTickFunc = TITagitplusAppTick, .ApplicationProcessFunc = TITagitplusAppProcess, @@ -412,8 +412,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, .ApplicationInitFunc = EM4233AppInit, - .ApplicationInitRunOnceFunc = EM4233AppInit, - .ApplicationResetFunc = EM4233AppReset, + .ApplicationInitRunOnceFunc = EM4233AppInit, + .ApplicationResetFunc = EM4233AppReset, .ApplicationTaskFunc = EM4233AppTask, .ApplicationTickFunc = EM4233AppTick, .ApplicationProcessFunc = EM4233AppProcess, @@ -431,8 +431,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = NTAG215AppInit, - .ApplicationInitRunOnceFunc = NTAG215AppInit, - .ApplicationResetFunc = NTAG215AppReset, + .ApplicationInitRunOnceFunc = NTAG215AppInit, + .ApplicationResetFunc = NTAG215AppReset, .ApplicationTaskFunc = NTAG215AppTask, .ApplicationTickFunc = ApplicationTickDummy, .ApplicationProcessFunc = NTAG215AppProcess, @@ -449,8 +449,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareDesfireEV0AppInit, - .ApplicationInitRunOnceFunc = MifareDesfireEV0AppInitRunOnce, - .ApplicationResetFunc = MifareDesfireAppReset, + .ApplicationInitRunOnceFunc = MifareDesfireEV0AppInitRunOnce, + .ApplicationResetFunc = MifareDesfireAppReset, .ApplicationTaskFunc = MifareDesfireAppTask, .ApplicationTickFunc = MifareDesfireAppTick, .ApplicationProcessFunc = MifareDesfireAppProcess, @@ -465,8 +465,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareDesfire2kEV1AppInit, - .ApplicationInitRunOnceFunc = MifareDesfire2kEV1AppInitRunOnce, - .ApplicationResetFunc = MifareDesfireAppReset, + .ApplicationInitRunOnceFunc = MifareDesfire2kEV1AppInitRunOnce, + .ApplicationResetFunc = MifareDesfireAppReset, .ApplicationTaskFunc = MifareDesfireAppTask, .ApplicationTickFunc = MifareDesfireAppTick, .ApplicationProcessFunc = MifareDesfireAppProcess, @@ -481,8 +481,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecDeInitFunc = ISO14443ACodecDeInit, .CodecTaskFunc = ISO14443ACodecTask, .ApplicationInitFunc = MifareDesfire4kEV1AppInit, - .ApplicationInitRunOnceFunc = MifareDesfire4kEV1AppInitRunOnce, - .ApplicationResetFunc = MifareDesfireAppReset, + .ApplicationInitRunOnceFunc = MifareDesfire4kEV1AppInitRunOnce, + .ApplicationResetFunc = MifareDesfireAppReset, .ApplicationTaskFunc = MifareDesfireAppTask, .ApplicationTickFunc = MifareDesfireAppTick, .ApplicationProcessFunc = MifareDesfireAppProcess, @@ -510,10 +510,10 @@ void ConfigurationSetById(ConfigurationEnum Configuration, bool appInitRunOnce) CommandLinePendingTaskBreak(); // break possibly pending task GlobalSettings.ActiveSettingPtr->Configuration = Configuration; - + /* Blank memory scape slate for the newly set configuration */ MemoryClear(); - + /* Copy struct from PROGMEM to RAM */ memcpy_P(&ActiveConfiguration, &ConfigurationTable[Configuration], sizeof(ConfigurationType)); @@ -556,7 +556,7 @@ bool ConfigurationSetByName(const char *Configuration, bool appInitRunOnce) { MapIdType Id; if (MapTextToId(ConfigurationMap, ARRAY_COUNT(ConfigurationMap), Configuration, &Id)) { ConfigurationSetById(Id, appInitRunOnce); - LogEntry(LOG_INFO_CONFIG_SET, Configuration, StringLength(Configuration, CONFIGURATION_NAME_LENGTH_MAX - 1)); + LogEntry(LOG_INFO_CONFIG_SET, Configuration, StringLength(Configuration, CONFIGURATION_NAME_LENGTH_MAX - 1)); return true; } else { return false; diff --git a/Firmware/Chameleon-Mini/Configuration.h b/Firmware/Chameleon-Mini/Configuration.h index 3e5f82fe..2ed04938 100644 --- a/Firmware/Chameleon-Mini/Configuration.h +++ b/Firmware/Chameleon-Mini/Configuration.h @@ -114,10 +114,10 @@ typedef struct { */ /** Function that initializes the application. */ void (*ApplicationInitFunc)(void); - /** Function to initialize one-time-only data in the application - * (like the filesystem for `CONFIG=MF_DESFIRE`). This function does not - * get called when changing slots to run a preexisting configuration or when the - * device is powered on and reinitializes the last loaded slot. + /** Function to initialize one-time-only data in the application + * (like the filesystem for `CONFIG=MF_DESFIRE`). This function does not + * get called when changing slots to run a preexisting configuration or when the + * device is powered on and reinitializes the last loaded slot. */ void (*ApplicationInitRunOnceFunc)(void); /** Function that resets the application. */ diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 31d1ecf2..20f987d9 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -100,8 +100,8 @@ SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING #SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF #Set a default testing mode setting (0 = OFF, non-NULL = ON): -#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 -SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 +SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 +#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 #Feature: Use randomized UIDs that mask the actual secret UID until #the tag has been issued a successful authentication sequence: diff --git a/Firmware/Chameleon-Mini/Memory.c b/Firmware/Chameleon-Mini/Memory.c index d0800210..889a4ea9 100644 --- a/Firmware/Chameleon-Mini/Memory.c +++ b/Firmware/Chameleon-Mini/Memory.c @@ -374,7 +374,7 @@ void MemoryReadBlockInSetting(void *Buffer, uint16_t Address, uint16_t ByteCount return; uint16_t ShiftedAddress = Address + GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING; if (ShiftedAddress < Address) - return; + return; FRAMRead(Buffer, ShiftedAddress, ByteCount); } diff --git a/Firmware/Chameleon-Mini/Terminal/Commands.c b/Firmware/Chameleon-Mini/Terminal/Commands.c index 501813c0..6db401a8 100644 --- a/Firmware/Chameleon-Mini/Terminal/Commands.c +++ b/Firmware/Chameleon-Mini/Terminal/Commands.c @@ -46,8 +46,8 @@ CommandStatusIdType CommandSetConfig(char *OutMessage, const char *InParam) { return COMMAND_INFO_OK_WITH_TEXT_ID; } else if (ConfigurationByNameIsValid(InParam)) { ConfigurationSetByName(InParam, true); - SETTING_UPDATE(GlobalSettings.ActiveSettingPtr->Configuration); - return COMMAND_INFO_OK_ID; + SETTING_UPDATE(GlobalSettings.ActiveSettingPtr->Configuration); + return COMMAND_INFO_OK_ID; } else { return COMMAND_ERR_INVALID_PARAM_ID; } diff --git a/Firmware/Chameleon-Mini/Tests/ChameleonTerminal.c b/Firmware/Chameleon-Mini/Tests/ChameleonTerminal.c index c55c41f9..ec3d112c 100644 --- a/Firmware/Chameleon-Mini/Tests/ChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Tests/ChameleonTerminal.c @@ -9,14 +9,14 @@ CommandStatusIdType CommandRunTests(char *OutParam) { const ChameleonTestType testCases[] = { #ifdef ENABLE_CRYPTO_TESTS #ifdef ENABLE_CRYPTO_TDEA_TESTS - &CryptoTDEATestCase1, + &CryptoTDEATestCase1, &CryptoTDEATestCase2, #endif #ifdef ENABLE_CRYPTO_3DES_TESTS &Crypto3DESTestCase1, #endif #ifdef ENABLE_CRYPTO_AES_TESTS - &CryptoAESTestCase1, + &CryptoAESTestCase1, &CryptoAESTestCase2, #endif #endif diff --git a/Firmware/Chameleon-Mini/Tests/CryptoTests.c b/Firmware/Chameleon-Mini/Tests/CryptoTests.c index 5ce35fdf..8b364b1f 100644 --- a/Firmware/Chameleon-Mini/Tests/CryptoTests.c +++ b/Firmware/Chameleon-Mini/Tests/CryptoTests.c @@ -57,25 +57,25 @@ bool CryptoTDEATestCase2(char *OutParam, uint16_t MaxOutputLength) { #endif #ifdef ENABLE_CRYPTO_3DES_TESTS -// Data from: +// Data from: // https://boringssl.googlesource.com/boringssl/+/2490/crypto/cipher/test/cipher_test.txt#33 bool Crypto3DESTestCase1(char *OutParam, uint16_t MaxOutputLength) { const uint8_t KeyData[3 * CRYPTO_DES_BLOCK_SIZE] = { - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, - 0xf1, 0xe0, 0xd3, 0xc2, 0xb5, 0xa4, 0x97, 0x86, - 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xf1, 0xe0, 0xd3, 0xc2, 0xb5, 0xa4, 0x97, 0x86, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }; const uint8_t PlainText[4 * CRYPTO_DES_BLOCK_SIZE] = { - 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20, - 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, - 0x66, 0x6F, 0x72, 0x20, 0x00, 0x00, 0x00, 0x00 + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20, + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x00, 0x00, 0x00, 0x00 }; const uint8_t CipherText[4 * CRYPTO_DES_BLOCK_SIZE] = { - 0x3F, 0xE3, 0x01, 0xC9, 0x62, 0xAC, 0x01, 0xD0, - 0x22, 0x13, 0x76, 0x3C, 0x1C, 0xBD, 0x4C, 0xDC, - 0x79, 0x96, 0x57, 0xC0, 0x64, 0xEC, 0xF5, 0xD4, - 0x1C, 0x67, 0x38, 0x12, 0xCF, 0xDE, 0x96, 0x75 + 0x3F, 0xE3, 0x01, 0xC9, 0x62, 0xAC, 0x01, 0xD0, + 0x22, 0x13, 0x76, 0x3C, 0x1C, 0xBD, 0x4C, 0xDC, + 0x79, 0x96, 0x57, 0xC0, 0x64, 0xEC, 0xF5, 0xD4, + 0x1C, 0x67, 0x38, 0x12, 0xCF, 0xDE, 0x96, 0x75 }; const uint8_t IV[CRYPTO_DES_BLOCK_SIZE] = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 @@ -85,7 +85,7 @@ bool Crypto3DESTestCase1(char *OutParam, uint16_t MaxOutputLength) { Encrypt3DESBuffer(dataBytes, PlainText, tempBuffer, IV, KeyData); if (memcmp(tempBuffer, CipherText, dataBytes)) { strcat_P(OutParam, PSTR("> ENC: ")); - OutParam += 7; + OutParam += 7; BufferToHexString(OutParam, MaxOutputLength - 7, tempBuffer, dataBytes); strcat_P(OutParam, PSTR("\r\n")); return false; @@ -93,7 +93,7 @@ bool Crypto3DESTestCase1(char *OutParam, uint16_t MaxOutputLength) { Decrypt3DESBuffer(dataBytes, tempBuffer, CipherText, IV, KeyData); if (memcmp(tempBuffer, PlainText, dataBytes)) { strcat_P(OutParam, PSTR("> DEC: ")); - OutParam += 7; + OutParam += 7; BufferToHexString(OutParam, MaxOutputLength - 7, tempBuffer, dataBytes); strcat_P(OutParam, PSTR("\r\n")); return false; From e15f8c71d7863bd6065bf396f92dc03bf2abc116 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Fri, 11 Feb 2022 22:51:37 -0500 Subject: [PATCH 13/68] Fixing bug where we must first auth with the legacy command mentioned in #313 --- .../Application/DESFire/DESFireCrypto.c | 8 +- .../Application/DESFire/DESFireCrypto.h | 4 +- .../Application/DESFire/DESFireInstructions.c | 55 +- .../ArduinoCryptoLib-SingleSource.c | 14 +- .../Libs/ArduinoCryptoLib/aes/aes-common.c | 56 +- .../Libs/ArduinoCryptoLib/aes/aes128.c | 41 +- .../LocalInclude/Config.h | 4 +- .../LocalInclude/CryptoUtils.h | 341 ++++---- .../LocalInclude/DesfireUtils.h | 760 +++++++++--------- .../LocalInclude/ErrorHandling.h | 30 +- .../LocalInclude/GeneralUtils.h | 24 +- .../LocalInclude/LibNFCUtils.h | 193 +++-- .../LocalInclude/LibNFCWrapper.h | 20 +- Software/DESFireLibNFCTesting/Makefile | 16 +- .../Source/NFCAntiCollisionMod.c | 466 ++++++----- .../TestApplicationManagementCommands.c | 65 +- .../Source/TestAuthenticateAES128.c | 22 +- .../Source/TestAuthenticateISO.c | 21 +- .../Source/TestAuthenticateLegacy.c | 14 +- .../TestDataManipulationCommandsSupport.c | 60 +- .../TestDataManipulationCommandsSupport2.c | 98 +-- .../TestDataManipulationCommandsSupport3.c | 42 +- .../TestFileManagementCommandsSupport.c | 59 +- .../Source/TestGeneralCommands.c | 27 +- .../Source/TestKeyManagementCommands.c | 34 +- 25 files changed, 1207 insertions(+), 1267 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c index fa0abeb3..edb5cc50 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c @@ -46,9 +46,9 @@ BYTE DesfireCommMode = DESFIRE_DEFAULT_COMMS_STANDARD; uint16_t AESCryptoKeySizeBytes = 0; CryptoAESConfig_t AESCryptoContext = { 0 }; -uint8_t Authenticated = 0x00; +bool Authenticated = false; uint8_t AuthenticatedWithKey = DESFIRE_NOT_AUTHENTICATED; -uint8_t AuthenticatedWithPICCMasterKey = 0x00; +bool AuthenticatedWithPICCMasterKey = false; uint8_t CryptoAuthMethod = CRYPTO_TYPE_ANY; uint8_t ActiveCommMode = DESFIRE_DEFAULT_COMMS_STANDARD; @@ -56,9 +56,9 @@ void InvalidateAuthState(BYTE keepPICCAuthData) { if (!keepPICCAuthData) { AuthenticatedWithPICCMasterKey = DESFIRE_NOT_AUTHENTICATED; } - Authenticated = 0x00; + Authenticated = false; AuthenticatedWithKey = DESFIRE_NOT_AUTHENTICATED; - AuthenticatedWithPICCMasterKey = 0x00; + AuthenticatedWithPICCMasterKey = false; Iso7816FileSelected = false; CryptoAuthMethod = CRYPTO_TYPE_ANY; ActiveCommMode = DESFIRE_DEFAULT_COMMS_STANDARD; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h index 10e637be..3a2ad219 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h @@ -76,9 +76,9 @@ extern CryptoKeyBufferType SessionKey; extern CryptoIVBufferType SessionIV; extern BYTE SessionIVByteSize; -extern uint8_t Authenticated; +extern bool Authenticated; extern uint8_t AuthenticatedWithKey; -extern uint8_t AuthenticatedWithPICCMasterKey; +extern bool AuthenticatedWithPICCMasterKey; extern uint8_t CryptoAuthMethod; extern uint8_t ActiveCommMode; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 222e9d98..4f0ba6f5 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -537,19 +537,22 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { return DESFIRE_STATUS_RESPONSE_SIZE; } - /* Authenticated successfully */ - Authenticated = 0x01; - AuthenticatedWithKey = KeyId; - AuthenticatedWithPICCMasterKey = (SelectedApp.Slot == DESFIRE_PICC_APP_SLOT) && - (KeyId == DESFIRE_MASTER_KEY_ID); - /* Encrypt and send back the once rotated RndA buffer to the PCD */ RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, Key); + /* Create the session key based on the previous exchange */ generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_3K3DES); + /* Now that we have auth'ed with the legacy command, a ChangeKey command will + * allow for subsequent authentication with the ISO or AES routines + */ + Authenticated = true; + AuthenticatedWithKey = KeyId; + AuthenticatedWithPICCMasterKey = (SelectedApp.Slot == DESFIRE_PICC_APP_SLOT) && + (KeyId == DESFIRE_MASTER_KEY_ID); + /* Return the status on success */ Buffer[0] = STATUS_OPERATION_OK; return DESFIRE_STATUS_RESPONSE_SIZE + CRYPTO_CHALLENGE_RESPONSE_BYTES; @@ -1688,15 +1691,30 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { BYTE keySize; BYTE *Key; - /* Reset authentication state right away */ - InvalidateAuthState(SelectedApp.Slot == DESFIRE_PICC_APP_SLOT); /* Validate command length */ if (ByteCount != 2) { Buffer[0] = STATUS_LENGTH_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } - /* Validate number of keys: less than max */ + + /* Reset authentication state right away: + * Check that we have first authenticated with the legacy auth command, and that the + * key we are using matches (may require a call to ChangeKey after the legacy auth). + * Note that we keep the status flag that we have already auth'ed with the legacy command + * in the event of an error. + */ KeyId = Buffer[1]; + if (!Authenticated || !AuthenticatedWithPICCMasterKey) { + Buffer[0] = STATUS_PERMISSION_DENIED; + return DESFIRE_STATUS_RESPONSE_SIZE; + } else if (AuthenticatedWithKey != KeyId) { + Buffer[0] = STATUS_NO_SUCH_KEY; + return DESFIRE_STATUS_RESPONSE_SIZE; + } else { + InvalidateAuthState(SelectedApp.Slot == DESFIRE_PICC_APP_SLOT); + } + + /* Validate number of keys: less than max */ if (!KeyIdValid(SelectedApp.Slot, KeyId)) { Buffer[0] = STATUS_PARAMETER_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; @@ -1820,14 +1838,29 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { BYTE keySize; BYTE *Key, *IVBuffer; - /* Reset authentication state right away */ - InvalidateAuthState(SelectedApp.Slot == DESFIRE_PICC_APP_SLOT); /* Validate command length */ if (ByteCount != 2) { Buffer[0] = STATUS_LENGTH_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } + + /* Reset authentication state right away: + * Check that we have first authenticated with the legacy auth command, and that the + * key we are using matches (may require a call to ChangeKey after the legacy auth). + * Note that we keep the status flag that we have already auth'ed with the legacy command + * in the event of an error. + */ KeyId = Buffer[1]; + if (!Authenticated || !AuthenticatedWithPICCMasterKey) { + Buffer[0] = STATUS_PERMISSION_DENIED; + return DESFIRE_STATUS_RESPONSE_SIZE; + } else if (AuthenticatedWithKey != KeyId) { + Buffer[0] = STATUS_NO_SUCH_KEY; + return DESFIRE_STATUS_RESPONSE_SIZE; + } else { + InvalidateAuthState(SelectedApp.Slot == DESFIRE_PICC_APP_SLOT); + } + /* Validate number of keys: less than max */ if (!KeyIdValid(SelectedApp.Slot, KeyId)) { Buffer[0] = STATUS_PARAMETER_ERROR; diff --git a/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/ArduinoCryptoLib-SingleSource.c b/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/ArduinoCryptoLib-SingleSource.c index c680a0d4..7ea353b5 100644 --- a/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/ArduinoCryptoLib-SingleSource.c +++ b/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/ArduinoCryptoLib-SingleSource.c @@ -1,22 +1,22 @@ /* -The DESFire stack portion of this firmware source -is free software written by Maxie Dion Schmidt (@maxieds): +The DESFire stack portion of this firmware source +is free software written by Maxie Dion Schmidt (@maxieds): You can redistribute it and/or modify it under the terms of this license. 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. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -The complete source distribution of +The complete source distribution of this firmware is available at the following link: https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack. -Based in part on the original DESFire code created by -@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at +Based in part on the original DESFire code created by +@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at https://github.com/dev-zzo/ChameleonMini/tree/desfire. -This notice must be retained at the top of all source files where indicated. +This notice must be retained at the top of all source files where indicated. */ /* ArduinoCryptoLib-SingleSource.c : Include all sources in one file. */ diff --git a/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/aes/aes-common.c b/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/aes/aes-common.c index f104645e..4ff8ce19 100644 --- a/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/aes/aes-common.c +++ b/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/aes/aes-common.c @@ -1,22 +1,22 @@ /* -The DESFire stack portion of this firmware source -is free software written by Maxie Dion Schmidt (@maxieds): +The DESFire stack portion of this firmware source +is free software written by Maxie Dion Schmidt (@maxieds): You can redistribute it and/or modify it under the terms of this license. 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. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -The complete source distribution of +The complete source distribution of this firmware is available at the following link: https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack. -Based in part on the original DESFire code created by -@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at +Based in part on the original DESFire code created by +@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at https://github.com/dev-zzo/ChameleonMini/tree/desfire. -This notice must be retained at the top of all source files where indicated. +This notice must be retained at the top of all source files where indicated. */ /* @@ -26,7 +26,7 @@ This notice must be retained at the top of all source files where indicated. * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the + * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included @@ -34,7 +34,7 @@ This notice must be retained at the top of all source files where indicated. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER @@ -44,10 +44,10 @@ This notice must be retained at the top of all source files where indicated. /* aes-common.c : Common utilities for AES encryption. */ #ifdef HOST_BUILD - #undef pgm_read_byte - #define pgm_read_byte(addr) ((uint8_t) *(addr)) - #undef PROGMEM - #define PROGMEM +#undef pgm_read_byte +#define pgm_read_byte(addr) ((uint8_t) *(addr)) +#undef PROGMEM +#define PROGMEM #endif /** @@ -150,12 +150,11 @@ static uint8_t const K[8] = { (0x1B << 1) ^ 0x1B, (0x1B << 2), (0x1B << 2) ^ 0x1B, - (0x1B << 2) ^ (0x1B << 1), - (0x1B << 2) ^ (0x1B << 1) ^ 0x1B + (0x1B << 2) ^(0x1B << 1), + (0x1B << 2) ^(0x1B << 1) ^ 0x1B }; -void cleanContext(void *dest, size_t size) -{ +void cleanContext(void *dest, size_t size) { // Force the use of volatile so that we actually clear the memory. // Otherwise the compiler might optimise the entire contents of this // function away, which will not be secure. @@ -163,11 +162,10 @@ void cleanContext(void *dest, size_t size) while (size > 0) { *d++ = 0; --size; - } + } } -bool secure_compare(const void *data1, const void *data2, size_t len) -{ +bool secure_compare(const void *data1, const void *data2, size_t len) { uint8_t result = 0; const uint8_t *d1 = (const uint8_t *)data1; const uint8_t *d2 = (const uint8_t *)data2; @@ -178,8 +176,7 @@ bool secure_compare(const void *data1, const void *data2, size_t len) return (bool)((((uint16_t)0x0100) - result) >> 8); } -void subBytesAndShiftRows(uint8_t *output, const uint8_t *input) -{ +void subBytesAndShiftRows(uint8_t *output, const uint8_t *input) { OUT(0, 0) = pgm_read_byte(sbox + IN(0, 0)); OUT(0, 1) = pgm_read_byte(sbox + IN(1, 1)); OUT(0, 2) = pgm_read_byte(sbox + IN(2, 2)); @@ -198,8 +195,7 @@ void subBytesAndShiftRows(uint8_t *output, const uint8_t *input) OUT(3, 3) = pgm_read_byte(sbox + IN(2, 3)); } -void inverseShiftRowsAndSubBytes(uint8_t *output, const uint8_t *input) -{ +void inverseShiftRowsAndSubBytes(uint8_t *output, const uint8_t *input) { OUT(0, 0) = pgm_read_byte(sbox_inverse + IN(0, 0)); OUT(0, 1) = pgm_read_byte(sbox_inverse + IN(3, 1)); OUT(0, 2) = pgm_read_byte(sbox_inverse + IN(2, 2)); @@ -218,8 +214,7 @@ void inverseShiftRowsAndSubBytes(uint8_t *output, const uint8_t *input) OUT(3, 3) = pgm_read_byte(sbox_inverse + IN(0, 3)); } -void mixColumn(uint8_t *output, uint8_t *input) -{ +void mixColumn(uint8_t *output, uint8_t *input) { uint16_t t; // Needed by the gmul2 macro. uint8_t a = input[0]; uint8_t b = input[1]; @@ -235,8 +230,7 @@ void mixColumn(uint8_t *output, uint8_t *input) output[3] = a2 ^ a ^ b ^ c ^ d2; } -void inverseMixColumn(uint8_t *output, const uint8_t *input) -{ +void inverseMixColumn(uint8_t *output, const uint8_t *input) { uint16_t t; // Needed by the gmul2, gmul4, and gmul8 macros. uint8_t a = input[0]; uint8_t b = input[1]; @@ -260,8 +254,7 @@ void inverseMixColumn(uint8_t *output, const uint8_t *input) output[3] = a8 ^ a2 ^ a ^ b8 ^ b4 ^ b ^ c8 ^ c ^ d8 ^ d4 ^ d2; } -void keyScheduleCore(uint8_t *output, const uint8_t *input, uint8_t iteration) -{ +void keyScheduleCore(uint8_t *output, const uint8_t *input, uint8_t iteration) { // Rcon(i), 2^i in the Rijndael finite field, for i = 0..10. // http://en.wikipedia.org/wiki/Rijndael_key_schedule static uint8_t const rcon[11] PROGMEM = { @@ -274,8 +267,7 @@ void keyScheduleCore(uint8_t *output, const uint8_t *input, uint8_t iteration) output[3] = pgm_read_byte(sbox + input[0]); } -void applySbox(uint8_t *output, const uint8_t *input) -{ +void applySbox(uint8_t *output, const uint8_t *input) { output[0] = pgm_read_byte(sbox + input[0]); output[1] = pgm_read_byte(sbox + input[1]); output[2] = pgm_read_byte(sbox + input[2]); diff --git a/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/aes/aes128.c b/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/aes/aes128.c index c05847ca..275d4740 100644 --- a/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/aes/aes128.c +++ b/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/aes/aes128.c @@ -1,22 +1,22 @@ /* -The DESFire stack portion of this firmware source -is free software written by Maxie Dion Schmidt (@maxieds): +The DESFire stack portion of this firmware source +is free software written by Maxie Dion Schmidt (@maxieds): You can redistribute it and/or modify it under the terms of this license. 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. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -The complete source distribution of +The complete source distribution of this firmware is available at the following link: https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack. -Based in part on the original DESFire code created by -@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at +Based in part on the original DESFire code created by +@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at https://github.com/dev-zzo/ChameleonMini/tree/desfire. -This notice must be retained at the top of all source files where indicated. +This notice must be retained at the top of all source files where indicated. */ /* @@ -26,7 +26,7 @@ This notice must be retained at the top of all source files where indicated. * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the + * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included @@ -34,7 +34,7 @@ This notice must be retained at the top of all source files where indicated. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER @@ -46,7 +46,7 @@ This notice must be retained at the top of all source files where indicated. #include const uint8_t zeroBlock[AES128_BLOCK_SIZE] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -64,18 +64,17 @@ void aes128ClearContext(AES128Context *ctx) { cleanContext(ctx->reverse, (AES128_CRYPTO_ROUNDS + 1) * AES128_CRYPTO_SCHEDULE_SIZE); } -bool aes128SetKey(AES128Context *ctx, const uint8_t *keyData, size_t keySize) -{ +bool aes128SetKey(AES128Context *ctx, const uint8_t *keyData, size_t keySize) { if (keySize != AES128_KEY_SIZE) { return false; } - + // Copy the key itself into the first 16 bytes of the schedule. uint8_t *schedule = ctx->sched; memcpy(schedule, keyData, 16); // Expand the key schedule until we have 176 bytes of expanded key. uint8_t iteration = 1; - uint8_t n = 16; + uint8_t n = 16; uint8_t w = 4; while (n < 176) { if (w == 4) { @@ -93,22 +92,21 @@ bool aes128SetKey(AES128Context *ctx, const uint8_t *keyData, size_t keySize) schedule[17] = schedule[13] ^ schedule[1]; schedule[18] = schedule[14] ^ schedule[2]; schedule[19] = schedule[15] ^ schedule[3]; - } + } // Advance to the next word in the schedule. schedule += 4; n += 4; ++w; - } - + } + return true; } static void aes128DecryptBuildKey(AES128Context *ctx, uint8_t *tempOutputBuf) { - aes128EncryptBlock(ctx, tempOutputBuf, zeroBlock); + aes128EncryptBlock(ctx, tempOutputBuf, zeroBlock); } -void aes128EncryptBlock(AES128Context *ctx, uint8_t *output, const uint8_t *input) -{ +void aes128EncryptBlock(AES128Context *ctx, uint8_t *output, const uint8_t *input) { // Reset the key data: aes128SetKey(ctx, ctx->keyData, AES128_KEY_SIZE); @@ -142,8 +140,7 @@ void aes128EncryptBlock(AES128Context *ctx, uint8_t *output, const uint8_t *inpu } -void aes128DecryptBlock(AES128Context *ctx, uint8_t *output, const uint8_t *input) -{ +void aes128DecryptBlock(AES128Context *ctx, uint8_t *output, const uint8_t *input) { // Setup the key data as though we have already been through an encryption round: aes128DecryptBuildKey(ctx, output); diff --git a/Software/DESFireLibNFCTesting/LocalInclude/Config.h b/Software/DESFireLibNFCTesting/LocalInclude/Config.h index c20720ae..b25ad036 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/Config.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/Config.h @@ -7,13 +7,13 @@ #define APPLICATION_AID_LENGTH (3) static const inline uint8_t MASTER_APPLICATION_AID[] = { - 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00 }; static const inline uint8_t MASTER_KEY_INDEX = 0x00; static inline uint8_t CRYPTO_RNDB_STATE[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static inline bool AUTHENTICATED = false; diff --git a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h index 366eb6b0..a0f870b9 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h @@ -20,7 +20,7 @@ #define CRYPTO_DES_KEY_SIZE (8) #define CRYPTO_3KTDEA_KEY_SIZE (3 * CRYPTO_DES_KEY_SIZE) -#define CRYPTO_DES_BLOCK_SIZE (8) +#define CRYPTO_DES_BLOCK_SIZE (8) #define CRYPTO_3KTDEA_BLOCK_SIZE (CRYPTO_DES_BLOCK_SIZE) #define AES128_BLOCK_SIZE (16) @@ -45,11 +45,11 @@ static const inline uint8_t TEST_KEY1_INDEX = 0x01; typedef AES128Context DesfireAESCryptoContext; typedef struct { - uint8_t *keyData; - size_t keySize; - uint8_t *ivData; - size_t ivSize; - DesfireAESCryptoContext cryptoCtx; + uint8_t *keyData; + size_t keySize; + uint8_t *ivData; + size_t ivSize; + DesfireAESCryptoContext cryptoCtx; } CryptoData_t; #define CryptoMemoryXOR(inputBuf, destBuf, bufSize) ({ \ @@ -61,140 +61,141 @@ typedef struct { } \ }) -static inline void DesfireAESCryptoInit(uint8_t *initKeyBuffer, uint16_t bufSize, +static inline void DesfireAESCryptoInit(uint8_t *initKeyBuffer, uint16_t bufSize, DesfireAESCryptoContext *cryptoCtx) { - if(initKeyBuffer == NULL || cryptoCtx == NULL) { - return; - } - aes128InitContext(cryptoCtx); - aes128SetKey(cryptoCtx, initKeyBuffer, bufSize); + if (initKeyBuffer == NULL || cryptoCtx == NULL) { + return; + } + aes128InitContext(cryptoCtx); + aes128SetKey(cryptoCtx, initKeyBuffer, bufSize); } static inline void PrintAESCryptoContext(DesfireAESCryptoContext *cryptoCtx) { - if(cryptoCtx == NULL) { + if (cryptoCtx == NULL) { return; } - fprintf(stdout, " -- SCHED = "); print_hex(cryptoCtx->schedule, 16); - fprintf(stdout, " -- REV = "); print_hex(cryptoCtx->reverse, 16); - fprintf(stdout, " -- KEY = "); print_hex(cryptoCtx->keyData, 16); + fprintf(stdout, " -- SCHED = "); + print_hex(cryptoCtx->schedule, 16); + fprintf(stdout, " -- REV = "); + print_hex(cryptoCtx->reverse, 16); + fprintf(stdout, " -- KEY = "); + print_hex(cryptoCtx->keyData, 16); } -static inline size_t EncryptAES128(const uint8_t *plainSrcBuf, size_t bufSize, +static inline size_t EncryptAES128(const uint8_t *plainSrcBuf, size_t bufSize, uint8_t *encDestBuf, CryptoData_t cdata) { - DesfireAESCryptoContext *cryptoCtx = &(cdata.cryptoCtx); - DesfireAESCryptoInit(cdata.keyData, cdata.keySize, cryptoCtx); - size_t bufBlocks = bufSize / AES128_BLOCK_SIZE; - bool padLastBlock = (bufSize % AES128_BLOCK_SIZE) != 0; - uint8_t IV[AES128_BLOCK_SIZE]; - memset(IV, 0x00, AES128_BLOCK_SIZE); - for(int blk = 0; blk < bufBlocks; blk++) { - uint8_t inputBlock[AES128_BLOCK_SIZE]; - if(blk == 0) { - memcpy(inputBlock, &plainSrcBuf[0], AES128_BLOCK_SIZE); - CryptoMemoryXOR(IV, inputBlock, AES128_BLOCK_SIZE); - } - else { - memcpy(inputBlock, &encDestBuf[(blk - 1) * AES128_BLOCK_SIZE], AES128_BLOCK_SIZE); - CryptoMemoryXOR(&plainSrcBuf[blk * AES128_BLOCK_SIZE], inputBlock, AES128_BLOCK_SIZE); - } - aes128EncryptBlock(cryptoCtx, encDestBuf + blk * AES128_BLOCK_SIZE, - inputBlock); - } - return bufSize; + DesfireAESCryptoContext *cryptoCtx = &(cdata.cryptoCtx); + DesfireAESCryptoInit(cdata.keyData, cdata.keySize, cryptoCtx); + size_t bufBlocks = bufSize / AES128_BLOCK_SIZE; + bool padLastBlock = (bufSize % AES128_BLOCK_SIZE) != 0; + uint8_t IV[AES128_BLOCK_SIZE]; + memset(IV, 0x00, AES128_BLOCK_SIZE); + for (int blk = 0; blk < bufBlocks; blk++) { + uint8_t inputBlock[AES128_BLOCK_SIZE]; + if (blk == 0) { + memcpy(inputBlock, &plainSrcBuf[0], AES128_BLOCK_SIZE); + CryptoMemoryXOR(IV, inputBlock, AES128_BLOCK_SIZE); + } else { + memcpy(inputBlock, &encDestBuf[(blk - 1) * AES128_BLOCK_SIZE], AES128_BLOCK_SIZE); + CryptoMemoryXOR(&plainSrcBuf[blk * AES128_BLOCK_SIZE], inputBlock, AES128_BLOCK_SIZE); + } + aes128EncryptBlock(cryptoCtx, encDestBuf + blk * AES128_BLOCK_SIZE, + inputBlock); + } + return bufSize; } -static inline size_t DecryptAES128(const uint8_t *encSrcBuf, size_t bufSize, +static inline size_t DecryptAES128(const uint8_t *encSrcBuf, size_t bufSize, uint8_t *plainDestBuf, CryptoData_t cdata) { - DesfireAESCryptoContext *cryptoCtx = &(cdata.cryptoCtx); - DesfireAESCryptoInit(cdata.keyData, cdata.keySize, cryptoCtx); - size_t bufBlocks = (bufSize + AES128_BLOCK_SIZE - 1) / AES128_BLOCK_SIZE; - bool padLastBlock = (bufSize % AES128_BLOCK_SIZE) != 0; - uint8_t IV[AES128_BLOCK_SIZE]; - memset(IV, 0x00, AES128_BLOCK_SIZE); - for(int blk = 0; blk < bufBlocks; blk++) { - uint8_t inputBlock[AES128_BLOCK_SIZE]; - aes128DecryptBlock(cryptoCtx, inputBlock, encSrcBuf + blk * AES128_BLOCK_SIZE); - if(blk == 0) { - memcpy(plainDestBuf + blk * AES128_BLOCK_SIZE, inputBlock, AES128_BLOCK_SIZE); - CryptoMemoryXOR(IV, plainDestBuf + blk * AES128_BLOCK_SIZE, AES128_BLOCK_SIZE); - } - else { - memcpy(plainDestBuf + blk * AES128_BLOCK_SIZE, inputBlock, AES128_BLOCK_SIZE); - CryptoMemoryXOR(&encSrcBuf[(blk - 1) * AES128_BLOCK_SIZE], - plainDestBuf + blk * AES128_BLOCK_SIZE, AES128_BLOCK_SIZE); - } - } - return bufSize; + DesfireAESCryptoContext *cryptoCtx = &(cdata.cryptoCtx); + DesfireAESCryptoInit(cdata.keyData, cdata.keySize, cryptoCtx); + size_t bufBlocks = (bufSize + AES128_BLOCK_SIZE - 1) / AES128_BLOCK_SIZE; + bool padLastBlock = (bufSize % AES128_BLOCK_SIZE) != 0; + uint8_t IV[AES128_BLOCK_SIZE]; + memset(IV, 0x00, AES128_BLOCK_SIZE); + for (int blk = 0; blk < bufBlocks; blk++) { + uint8_t inputBlock[AES128_BLOCK_SIZE]; + aes128DecryptBlock(cryptoCtx, inputBlock, encSrcBuf + blk * AES128_BLOCK_SIZE); + if (blk == 0) { + memcpy(plainDestBuf + blk * AES128_BLOCK_SIZE, inputBlock, AES128_BLOCK_SIZE); + CryptoMemoryXOR(IV, plainDestBuf + blk * AES128_BLOCK_SIZE, AES128_BLOCK_SIZE); + } else { + memcpy(plainDestBuf + blk * AES128_BLOCK_SIZE, inputBlock, AES128_BLOCK_SIZE); + CryptoMemoryXOR(&encSrcBuf[(blk - 1) * AES128_BLOCK_SIZE], + plainDestBuf + blk * AES128_BLOCK_SIZE, AES128_BLOCK_SIZE); + } + } + return bufSize; } -static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize, +static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize, uint8_t *encDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { - DES_key_schedule keySched1, keySched2, keySched3; - uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; - uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[8]), *kd3 = &(cdata.keyData[16]); - DES_set_key(kd1, &keySched1); - DES_set_key(kd2, &keySched2); - DES_set_key(kd3, &keySched3); - if (IVIn == NULL) { - memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); - } else { - memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); - } - DES_ede3_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_ENCRYPT); - return bufSize; + DES_key_schedule keySched1, keySched2, keySched3; + uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[8]), *kd3 = &(cdata.keyData[16]); + DES_set_key(kd1, &keySched1); + DES_set_key(kd2, &keySched2); + DES_set_key(kd3, &keySched3); + if (IVIn == NULL) { + memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + } + DES_ede3_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_ENCRYPT); + return bufSize; } -static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize, +static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize, uint8_t *plainDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { - DES_key_schedule keySched1, keySched2, keySched3; - uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; - uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[8]), *kd3 = &(cdata.keyData[16]); - DES_set_key(kd1, &keySched1); - DES_set_key(kd2, &keySched2); - DES_set_key(kd3, &keySched3); - if (IVIn == NULL) { - memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); - } else { - memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); - } - DES_ede3_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_DECRYPT); - return bufSize; + DES_key_schedule keySched1, keySched2, keySched3; + uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[8]), *kd3 = &(cdata.keyData[16]); + DES_set_key(kd1, &keySched1); + DES_set_key(kd2, &keySched2); + DES_set_key(kd3, &keySched3); + if (IVIn == NULL) { + memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + } + DES_ede3_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_DECRYPT); + return bufSize; } -static inline size_t EncryptDES(const uint8_t *plainSrcBuf, size_t bufSize, +static inline size_t EncryptDES(const uint8_t *plainSrcBuf, size_t bufSize, uint8_t *encDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { - DES_key_schedule keySched; - uint8_t *kd = cdata.keyData; - DES_set_key(kd, &keySched); - uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; - if (IVIn == NULL) { - memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); - } else { - memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); - } - DES_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched, &IV, DES_ENCRYPT); - return bufSize; + DES_key_schedule keySched; + uint8_t *kd = cdata.keyData; + DES_set_key(kd, &keySched); + uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + if (IVIn == NULL) { + memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + } + DES_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched, &IV, DES_ENCRYPT); + return bufSize; } -static inline size_t DecryptDES(const uint8_t *encSrcBuf, size_t bufSize, +static inline size_t DecryptDES(const uint8_t *encSrcBuf, size_t bufSize, uint8_t *plainDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { - DES_key_schedule keySched; - uint8_t *kd = cdata.keyData; - DES_set_key(kd, &keySched); - uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; - if (IVIn == NULL) { - memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); - } else { - memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); - } - DES_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched, &IV, DES_DECRYPT); - return bufSize; + DES_key_schedule keySched; + uint8_t *kd = cdata.keyData; + DES_set_key(kd, &keySched); + uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + if (IVIn == NULL) { + memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + } + DES_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched, &IV, DES_DECRYPT); + return bufSize; } static inline bool TestAESEncyptionRoutines(void) { fprintf(stdout, ">>> TestAESEncryptionRoutines [non-DESFire command]:\n"); - const uint8_t keyData[] = { + const uint8_t keyData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; @@ -212,23 +213,25 @@ static inline bool TestAESEncyptionRoutines(void) { uint8_t pt[16], pt2[16], ct[16]; EncryptAES128(ptData, 16, ct, cdata); DecryptAES128(ct, 16, pt2, cdata); - fprintf(stdout, " -- : PT = "); print_hex(ptData, 16); - fprintf(stdout, " -- : CT = "); print_hex(ctData, 16); - fprintf(stdout, " -- : CT = "); print_hex(ct, 16); - fprintf(stdout, " -- : PT = "); print_hex(pt2, 16); + fprintf(stdout, " -- : PT = "); + print_hex(ptData, 16); + fprintf(stdout, " -- : CT = "); + print_hex(ctData, 16); + fprintf(stdout, " -- : CT = "); + print_hex(ct, 16); + fprintf(stdout, " -- : PT = "); + print_hex(pt2, 16); bool status = true; - if(memcmp(ct, ctData, 16)) { + if (memcmp(ct, ctData, 16)) { fprintf(stdout, " -- CT does NOT match !!\n"); status = false; - } - else { + } else { fprintf(stdout, " -- CT matches.\n"); } - if(memcmp(pt2, ptData, 16)) { + if (memcmp(pt2, ptData, 16)) { fprintf(stdout, " -- Decrypted PT from CT does NOT match !!\n"); status = false; - } - else { + } else { fprintf(stdout, " -- Decrypted PT from CT matches.\n"); } fprintf(stdout, "\n"); @@ -238,21 +241,21 @@ static inline bool TestAESEncyptionRoutines(void) { static inline bool Test3DESEncyptionRoutines(void) { fprintf(stdout, ">>> Test3DESEncryptionRoutines [non-DESFire command]:\n"); const uint8_t keyData[] = { - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, - 0xf1, 0xe0, 0xd3, 0xc2, 0xb5, 0xa4, 0x97, 0x86, - 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xf1, 0xe0, 0xd3, 0xc2, 0xb5, 0xa4, 0x97, 0x86, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }; const uint8_t ptData[] = { - 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20, - 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, - 0x66, 0x6F, 0x72, 0x20, 0x00, 0x00, 0x00, 0x00 + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20, + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x00, 0x00, 0x00, 0x00 }; const uint8_t ctData[] = { - 0x3F, 0xE3, 0x01, 0xC9, 0x62, 0xAC, 0x01, 0xD0, - 0x22, 0x13, 0x76, 0x3C, 0x1C, 0xBD, 0x4C, 0xDC, - 0x79, 0x96, 0x57, 0xC0, 0x64, 0xEC, 0xF5, 0xD4, - 0x1C, 0x67, 0x38, 0x12, 0xCF, 0xDE, 0x96, 0x75 + 0x3F, 0xE3, 0x01, 0xC9, 0x62, 0xAC, 0x01, 0xD0, + 0x22, 0x13, 0x76, 0x3C, 0x1C, 0xBD, 0x4C, 0xDC, + 0x79, 0x96, 0x57, 0xC0, 0x64, 0xEC, 0xF5, 0xD4, + 0x1C, 0x67, 0x38, 0x12, 0xCF, 0xDE, 0x96, 0x75 }; const uint8_t IV[] = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 @@ -264,23 +267,25 @@ static inline bool Test3DESEncyptionRoutines(void) { uint8_t pt[testDataSize], ct[testDataSize]; Encrypt3DES(ptData, testDataSize, ct, IV, cdata); Decrypt3DES(ctData, testDataSize, pt, IV, cdata); - fprintf(stdout, " -- : PT [FIXED] = "); print_hex(ptData, testDataSize); - fprintf(stdout, " -- : CT [FIXED] = "); print_hex(ctData, testDataSize); - fprintf(stdout, " -- : CT [ENC] = "); print_hex(ct, testDataSize); - fprintf(stdout, " -- : PT [DEC] = "); print_hex(pt, testDataSize); + fprintf(stdout, " -- : PT [FIXED] = "); + print_hex(ptData, testDataSize); + fprintf(stdout, " -- : CT [FIXED] = "); + print_hex(ctData, testDataSize); + fprintf(stdout, " -- : CT [ENC] = "); + print_hex(ct, testDataSize); + fprintf(stdout, " -- : PT [DEC] = "); + print_hex(pt, testDataSize); bool status = true; - if(memcmp(ct, ctData, testDataSize)) { + if (memcmp(ct, ctData, testDataSize)) { fprintf(stdout, " -- CT does NOT match !!\n"); status = false; - } - else { + } else { fprintf(stdout, " -- CT matches.\n"); } - if(memcmp(pt, ptData, testDataSize)) { + if (memcmp(pt, ptData, testDataSize)) { fprintf(stdout, " -- Decrypted PT from CT does NOT match !!\n"); status = false; - } - else { + } else { fprintf(stdout, " -- Decrypted PT from CT matches.\n"); } fprintf(stdout, "\n"); @@ -289,7 +294,7 @@ static inline bool Test3DESEncyptionRoutines(void) { static inline bool TestLegacyDESEncyptionRoutines(void) { fprintf(stdout, ">>> TestLegacyDESEncryptionRoutines [non-DESFire command]:\n"); - const uint8_t keyData[] = { + const uint8_t keyData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, }; const uint8_t ptData[] = { @@ -297,8 +302,8 @@ static inline bool TestLegacyDESEncyptionRoutines(void) { 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }; const uint8_t ctData[] = { - 0x3e, 0xf0, 0xa8, 0x91, 0xcf, 0x8e, 0xd9, 0x90, - 0xc4, 0x77, 0xeb, 0x09, 0x02, 0xf0, 0xc5, 0x4a + 0x3e, 0xf0, 0xa8, 0x91, 0xcf, 0x8e, 0xd9, 0x90, + 0xc4, 0x77, 0xeb, 0x09, 0x02, 0xf0, 0xc5, 0x4a }; CryptoData_t cdata; cdata.keyData = keyData; @@ -307,23 +312,25 @@ static inline bool TestLegacyDESEncyptionRoutines(void) { uint8_t pt[testDataSize], ct[testDataSize]; EncryptDES(ptData, testDataSize, ct, NULL, cdata); DecryptDES(ctData, testDataSize, pt, NULL, cdata); - fprintf(stdout, " -- : PT [FIXED] = "); print_hex(ptData, testDataSize); - fprintf(stdout, " -- : CT [FIXED] = "); print_hex(ctData, testDataSize); - fprintf(stdout, " -- : CT [ENC] = "); print_hex(ct, testDataSize); - fprintf(stdout, " -- : PT [DEC] = "); print_hex(pt, testDataSize); + fprintf(stdout, " -- : PT [FIXED] = "); + print_hex(ptData, testDataSize); + fprintf(stdout, " -- : CT [FIXED] = "); + print_hex(ctData, testDataSize); + fprintf(stdout, " -- : CT [ENC] = "); + print_hex(ct, testDataSize); + fprintf(stdout, " -- : PT [DEC] = "); + print_hex(pt, testDataSize); bool status = true; - if(memcmp(ct, ctData, testDataSize)) { + if (memcmp(ct, ctData, testDataSize)) { fprintf(stdout, " -- CT does NOT match !!\n"); status = false; - } - else { + } else { fprintf(stdout, " -- CT matches.\n"); } - if(memcmp(pt, ptData, testDataSize)) { + if (memcmp(pt, ptData, testDataSize)) { fprintf(stdout, " -- Decrypted PT from CT does NOT match !!\n"); status = false; - } - else { + } else { fprintf(stdout, " -- Decrypted PT from CT matches.\n"); } fprintf(stdout, "\n"); @@ -331,27 +338,27 @@ static inline bool TestLegacyDESEncyptionRoutines(void) { } static inline int GenerateRandomBytes(uint8_t *destBuf, size_t numBytes) { - return RAND_pseudo_bytes(destBuf, numBytes); + return RAND_pseudo_bytes(destBuf, numBytes); } static inline void RotateArrayRight(uint8_t *srcBuf, uint8_t *destBuf, size_t bufSize) { - destBuf[bufSize - 1] = srcBuf[0]; - for(int bidx = 0; bidx < bufSize - 1; bidx++) { - destBuf[bidx] = srcBuf[bidx + 1]; - } + destBuf[bufSize - 1] = srcBuf[0]; + for (int bidx = 0; bidx < bufSize - 1; bidx++) { + destBuf[bidx] = srcBuf[bidx + 1]; + } } static inline void RotateArrayLeft(uint8_t *srcBuf, uint8_t *destBuf, size_t bufSize) { - for(int bidx = 1; bidx < bufSize; bidx++) { - destBuf[bidx] = srcBuf[bidx - 1]; - } - destBuf[0] = srcBuf[bufSize - 1]; + for (int bidx = 1; bidx < bufSize; bidx++) { + destBuf[bidx] = srcBuf[bidx - 1]; + } + destBuf[0] = srcBuf[bufSize - 1]; } -static inline void ConcatByteArrays(uint8_t *arrA, size_t arrASize, +static inline void ConcatByteArrays(uint8_t *arrA, size_t arrASize, uint8_t *arrB, size_t arrBSize, uint8_t *destArr) { - memcpy(destArr, arrA, arrASize); - memcpy(destArr + arrASize, arrB, arrBSize); + memcpy(destArr, arrA, arrASize); + memcpy(destArr + arrASize, arrB, arrBSize); } #endif diff --git a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h index c276ad44..98dc0ec7 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h @@ -17,8 +17,8 @@ #include "GeneralUtils.h" static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, const uint8_t *keyData) { - - if(nfcConnDev == NULL || keyData == NULL) { + + if (nfcConnDev == NULL || keyData == NULL) { return INVALID_PARAMS_ERROR; } @@ -27,7 +27,7 @@ static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, c 0x90, 0xaa, 0x00, 0x00, 0x01, 0x00, 0x00 }; AUTHENTICATE_AES_CMD[5] = keyIndex; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> Start AES Authenticate:\n"); fprintf(stdout, " -> "); print_hex(AUTHENTICATE_AES_CMD, sizeof(AUTHENTICATE_AES_CMD)); @@ -35,20 +35,19 @@ static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, c RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, AUTHENTICATE_AES_CMD, sizeof(AUTHENTICATE_AES_CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; } - // Now need to decrypt the challenge response sent back as rndB, - // rotate it left, generate a random rndA, concat rndA+rotatedRndB, + // Now need to decrypt the challenge response sent back as rndB, + // rotate it left, generate a random rndA, concat rndA+rotatedRndB, // encrypt this result, and send it forth to the PICC: uint8_t encryptedRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE], plainTextRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE], rotatedRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE]; uint8_t rndA[CRYPTO_CHALLENGE_RESPONSE_SIZE], challengeResponse[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE], challengeResponseCipherText[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE]; @@ -73,34 +72,36 @@ static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, c sendBytesBuf[4] = 0x20; memcpy(sendBytesBuf + 5, challengeResponseCipherText, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " -- RNDA = "); print_hex(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); - fprintf(stdout, " -- RNDB = "); print_hex(plainTextRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); - fprintf(stdout, " -- CHAL = "); print_hex(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); + if (PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " -- RNDA = "); + print_hex(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " -- RNDB = "); + print_hex(plainTextRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " -- CHAL = "); + print_hex(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); fprintf(stdout, " -> "); print_hex(sendBytesBuf, sizeof(sendBytesBuf)); } rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6, rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; } - // Finally, to finish up the auth process: - // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, - // and report back whether they match: + // Finally, to finish up the auth process: + // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, + // and report back whether they match: uint8_t decryptedRndAFromPICCRotated[CRYPTO_CHALLENGE_RESPONSE_SIZE], decryptedRndA[CRYPTO_CHALLENGE_RESPONSE_SIZE]; DecryptAES128(rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE, decryptedRndAFromPICCRotated, aesCryptoData); RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); - if(!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " ... AUTH OK! :)\n\n"); } AUTHENTICATED = true; @@ -108,11 +109,11 @@ static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, c memcpy(CRYPTO_RNDB_STATE, plainTextRndB, 8); FreeRxDataStruct(rxDataStorage, true); return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " ... AUTH FAILED -- X; :(\n"); - fprintf(stdout, " ... "); print_hex(decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " ... "); + print_hex(decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; @@ -120,8 +121,8 @@ static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, c } static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, const uint8_t *keyData) { - - if(nfcConnDev == NULL || keyData == NULL) { + + if (nfcConnDev == NULL || keyData == NULL) { return INVALID_PARAMS_ERROR; } @@ -130,7 +131,7 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons 0x90, 0x1a, 0x00, 0x00, 0x01, 0x00, 0x00 }; AUTHENTICATE_ISO_CMD[5] = keyIndex; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> Start ISO Authenticate:\n"); fprintf(stdout, " -> "); print_hex(AUTHENTICATE_ISO_CMD, sizeof(AUTHENTICATE_ISO_CMD)); @@ -138,20 +139,19 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, AUTHENTICATE_ISO_CMD, sizeof(AUTHENTICATE_ISO_CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; } - // Now need to decrypt the challenge response sent back as rndB, - // rotate it left, generate a random rndA, concat rndA+rotatedRndB, + // Now need to decrypt the challenge response sent back as rndB, + // rotate it left, generate a random rndA, concat rndA+rotatedRndB, // encrypt this result, and send it forth to the PICC: uint8_t encryptedRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE], plainTextRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE], rotatedRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE]; uint8_t rndA[CRYPTO_CHALLENGE_RESPONSE_SIZE], challengeResponse[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE], challengeResponseCipherText[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE]; @@ -176,34 +176,36 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons sendBytesBuf[4] = 0x20; memcpy(sendBytesBuf + 5, challengeResponseCipherText, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " -- RNDA = "); print_hex(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); - fprintf(stdout, " -- RNDB = "); print_hex(plainTextRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); - fprintf(stdout, " -- CHAL = "); print_hex(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); + if (PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " -- RNDA = "); + print_hex(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " -- RNDB = "); + print_hex(plainTextRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " -- CHAL = "); + print_hex(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); fprintf(stdout, " -> "); print_hex(sendBytesBuf, sizeof(sendBytesBuf)); } rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6, rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; } - // Finally, to finish up the auth process: - // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, - // and report back whether they match: + // Finally, to finish up the auth process: + // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, + // and report back whether they match: uint8_t decryptedRndAFromPICCRotated[CRYPTO_CHALLENGE_RESPONSE_SIZE], decryptedRndA[CRYPTO_CHALLENGE_RESPONSE_SIZE]; Decrypt3DES(rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE, decryptedRndAFromPICCRotated, NULL, desCryptoData); RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); - if(!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " ... AUTH OK! :)\n\n"); } AUTHENTICATED = true; @@ -211,20 +213,20 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons memcpy(CRYPTO_RNDB_STATE, plainTextRndB, 8); FreeRxDataStruct(rxDataStorage, true); return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " ... AUTH FAILED -- X; :(\n"); - fprintf(stdout, " ... "); print_hex(decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); - } + fprintf(stdout, " ... "); + print_hex(decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; } } static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, const uint8_t *keyData) { - - if(nfcConnDev == NULL || keyData == NULL) { + + if (nfcConnDev == NULL || keyData == NULL) { return INVALID_PARAMS_ERROR; } @@ -233,7 +235,7 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c 0x90, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00 }; AUTHENTICATE_LEGACY_CMD[5] = keyIndex; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> Start Legacy 3K3DES Authenticate:\n"); fprintf(stdout, " -> "); print_hex(AUTHENTICATE_LEGACY_CMD, sizeof(AUTHENTICATE_LEGACY_CMD)); @@ -241,20 +243,19 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, AUTHENTICATE_LEGACY_CMD, sizeof(AUTHENTICATE_LEGACY_CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; } - // Now need to decrypt the challenge response sent back as rndB, - // rotate it left, generate a random rndA, concat rndA+rotatedRndB, + // Now need to decrypt the challenge response sent back as rndB, + // rotate it left, generate a random rndA, concat rndA+rotatedRndB, // encrypt this result, and send it forth to the PICC: uint8_t encryptedRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE], plainTextRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE], rotatedRndB[CRYPTO_CHALLENGE_RESPONSE_SIZE]; uint8_t rndA[CRYPTO_CHALLENGE_RESPONSE_SIZE], challengeResponse[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE], challengeResponseCipherText[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE]; @@ -279,34 +280,36 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c sendBytesBuf[4] = 0x20; memcpy(sendBytesBuf + 5, challengeResponseCipherText, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " -- RNDA = "); print_hex(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); - fprintf(stdout, " -- RNDB = "); print_hex(plainTextRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); - fprintf(stdout, " -- CHAL = "); print_hex(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); + if (PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " -- RNDA = "); + print_hex(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " -- RNDB = "); + print_hex(plainTextRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); + fprintf(stdout, " -- CHAL = "); + print_hex(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE); fprintf(stdout, " -> "); print_hex(sendBytesBuf, sizeof(sendBytesBuf)); } rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6, rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; } - // Finally, to finish up the auth process: - // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, - // and report back whether they match: + // Finally, to finish up the auth process: + // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, + // and report back whether they match: uint8_t decryptedRndAFromPICCRotated[CRYPTO_CHALLENGE_RESPONSE_SIZE], decryptedRndA[CRYPTO_CHALLENGE_RESPONSE_SIZE]; Decrypt3DES(rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE, decryptedRndAFromPICCRotated, NULL, desCryptoData); RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); - if(!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " ... AUTH OK! :)\n\n"); } AUTHENTICATED = true; @@ -314,36 +317,36 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c memcpy(CRYPTO_RNDB_STATE, plainTextRndB, 8); FreeRxDataStruct(rxDataStorage, true); return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " ... AUTH FAILED -- X; :(\n"); - fprintf(stdout, " ... "); print_hex(decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); - } + fprintf(stdout, " ... "); + print_hex(decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; } } static inline int Authenticate(nfc_device *nfcConnDev, int authType, uint8_t keyIndex, const uint8_t *keyData) { InvalidateAuthState(); - if(nfcConnDev == NULL || keyData == NULL) { + if (nfcConnDev == NULL || keyData == NULL) { return INVALID_PARAMS_ERROR; } - switch(authType) { + switch (authType) { case DESFIRE_CRYPTO_AUTHTYPE_AES128: return AuthenticateAES128(nfcConnDev, keyIndex, keyData); - case DESFIRE_CRYPTO_AUTHTYPE_ISODES: - return AuthenticateISO(nfcConnDev, keyIndex, keyData); - case DESFIRE_CRYPTO_AUTHTYPE_LEGACY: - return AuthenticateLegacy(nfcConnDev, keyIndex, keyData); - default: + case DESFIRE_CRYPTO_AUTHTYPE_ISODES: + return AuthenticateISO(nfcConnDev, keyIndex, keyData); + case DESFIRE_CRYPTO_AUTHTYPE_LEGACY: + return AuthenticateLegacy(nfcConnDev, keyIndex, keyData); + default: break; } return EXIT_FAILURE; } static inline int GetVersionCommand(nfc_device *nfcConnDev) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t GET_VERSION_CMD_INIT[] = { @@ -352,39 +355,37 @@ static inline int GetVersionCommand(nfc_device *nfcConnDev) { uint8_t CONTINUE_CMD[] = { 0x90, 0xaf, 0x00, 0x00, 0x00, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> GetVersion command:\n"); fprintf(stdout, " -> "); print_hex(GET_VERSION_CMD_INIT, sizeof(GET_VERSION_CMD_INIT)); - } + } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; - rxDataStatus = libnfcTransmitBytes(nfcConnDev, GET_VERSION_CMD_INIT, + rxDataStatus = libnfcTransmitBytes(nfcConnDev, GET_VERSION_CMD_INIT, sizeof(GET_VERSION_CMD_INIT), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; - } - for(int extraCmd = 0; extraCmd < 2; extraCmd++) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } + for (int extraCmd = 0; extraCmd < 2; extraCmd++) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -> "); print_hex(CONTINUE_CMD, sizeof(CONTINUE_CMD)); - } - rxDataStatus = libnfcTransmitBytes(nfcConnDev, CONTINUE_CMD, + } + rxDataStatus = libnfcTransmitBytes(nfcConnDev, CONTINUE_CMD, sizeof(CONTINUE_CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -396,27 +397,26 @@ static inline int GetVersionCommand(nfc_device *nfcConnDev) { } static inline int FormatPiccCommand(nfc_device *nfcConnDev) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t FORMAT_PICC_CMD[] = { 0x90, 0xfc, 0x00, 0x00, 0x00, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> FormatPICC command:\n"); fprintf(stdout, " -> "); print_hex(FORMAT_PICC_CMD, sizeof(FORMAT_PICC_CMD)); } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; - rxDataStatus = libnfcTransmitBytes(nfcConnDev, FORMAT_PICC_CMD, + rxDataStatus = libnfcTransmitBytes(nfcConnDev, FORMAT_PICC_CMD, sizeof(FORMAT_PICC_CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -427,27 +427,26 @@ static inline int FormatPiccCommand(nfc_device *nfcConnDev) { } static inline int GetCardUIDCommand(nfc_device *nfcConnDev) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[] = { 0x90, 0x51, 0x00, 0x00, 0x00, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> GetCardUID command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; - rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, + rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -458,28 +457,27 @@ static inline int GetCardUIDCommand(nfc_device *nfcConnDev) { } static inline int SetConfigurationCommand(nfc_device *nfcConnDev) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[] = { 0x90, 0x5c, 0x00, 0x00, 0x00, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> SetConfiguration command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; - rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, + rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); fprintf(stdout, " -- !! TODO: NOT IMPLEMENTED !!\n"); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -490,27 +488,26 @@ static inline int SetConfigurationCommand(nfc_device *nfcConnDev) { } static inline int FreeMemoryCommand(nfc_device *nfcConnDev) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[] = { 0x90, 0x6e, 0x00, 0x00, 0x00, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> FreeMemory command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; - rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, + rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -521,10 +518,9 @@ static inline int FreeMemoryCommand(nfc_device *nfcConnDev) { } static inline int ChangeKeyCommand(nfc_device *nfcConnDev, uint8_t keyNo, const uint8_t *keyData, int keyType) { - if(nfcConnDev == NULL || keyData == NULL) { + if (nfcConnDev == NULL || keyData == NULL) { return INVALID_PARAMS_ERROR; - } - else if(keyType != DESFIRE_CRYPTO_AUTHTYPE_AES128 && keyType != DESFIRE_CRYPTO_AUTHTYPE_ISODES) { + } else if (keyType != DESFIRE_CRYPTO_AUTHTYPE_AES128 && keyType != DESFIRE_CRYPTO_AUTHTYPE_ISODES) { return INVALID_PARAMS_ERROR; } uint8_t keySize = keyType == DESFIRE_CRYPTO_AUTHTYPE_AES128 ? 16 : 24; @@ -536,7 +532,7 @@ static inline int ChangeKeyCommand(nfc_device *nfcConnDev, uint8_t keyNo, const CMD[4] = keySize + 1; CMD[5] = keyNo; memcpy(CMD + 6, keyData, keySize); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> ChangeKey command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); @@ -545,12 +541,11 @@ static inline int ChangeKeyCommand(nfc_device *nfcConnDev, uint8_t keyNo, const bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -561,13 +556,13 @@ static inline int ChangeKeyCommand(nfc_device *nfcConnDev, uint8_t keyNo, const } static inline int GetKeySettingsCommand(nfc_device *nfcConnDev) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[] = { 0x90, 0x45, 0x00, 0x00, 0x00, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> GetKeySettings command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); @@ -576,12 +571,11 @@ static inline int GetKeySettingsCommand(nfc_device *nfcConnDev) { bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -592,7 +586,7 @@ static inline int GetKeySettingsCommand(nfc_device *nfcConnDev) { } static inline int ChangeKeySettingsCommand(nfc_device *nfcConnDev, const uint8_t keySettingsData) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[7]; @@ -601,7 +595,7 @@ static inline int ChangeKeySettingsCommand(nfc_device *nfcConnDev, const uint8_t memset(CMD + 2, 0x00, 5); CMD[4] = 1; CMD[5] = keySettingsData; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> ChangeKeySettings command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); @@ -610,12 +604,11 @@ static inline int ChangeKeySettingsCommand(nfc_device *nfcConnDev, const uint8_t bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -626,13 +619,13 @@ static inline int ChangeKeySettingsCommand(nfc_device *nfcConnDev, const uint8_t } static inline int GetKeyVersionCommand(nfc_device *nfcConnDev, uint8_t keyNo) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[] = { 0x90, 0x64, 0x00, 0x00, 0x01, keyNo, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> GetKeyVersion command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); @@ -641,12 +634,11 @@ static inline int GetKeyVersionCommand(nfc_device *nfcConnDev, uint8_t keyNo) { bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -657,32 +649,31 @@ static inline int GetKeyVersionCommand(nfc_device *nfcConnDev, uint8_t keyNo) { } static inline int GetApplicationIds(nfc_device *nfcConnDev) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } - uint8_t GET_APPLICATION_AID_LIST_CMD[] = { - 0x90, 0x6a, 0x00, 0x00, 0x00, 0x00 + uint8_t GET_APPLICATION_AID_LIST_CMD[] = { + 0x90, 0x6a, 0x00, 0x00, 0x00, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> GetApplicationIds command:\n"); fprintf(stdout, " -> "); print_hex(GET_APPLICATION_AID_LIST_CMD, sizeof(GET_APPLICATION_AID_LIST_CMD)); } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); - bool rxDataStatus = false; - rxDataStatus = libnfcTransmitBytes(nfcConnDev, GET_APPLICATION_AID_LIST_CMD, + bool rxDataStatus = false; + rxDataStatus = libnfcTransmitBytes(nfcConnDev, GET_APPLICATION_AID_LIST_CMD, sizeof(GET_APPLICATION_AID_LIST_CMD), rxDataStorage); - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); fprintf(stdout, "\n"); } FreeRxDataStruct(rxDataStorage, true); return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); fprintf(stdout, "\n"); } @@ -691,9 +682,9 @@ static inline int GetApplicationIds(nfc_device *nfcConnDev) { } } -static inline int CreateApplication(nfc_device *nfcConnDev, uint8_t *aidBytes, +static inline int CreateApplication(nfc_device *nfcConnDev, uint8_t *aidBytes, uint8_t keySettings, uint8_t numKeys) { - if(nfcConnDev == NULL || aidBytes == NULL) { + if (nfcConnDev == NULL || aidBytes == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[11]; @@ -704,7 +695,7 @@ static inline int CreateApplication(nfc_device *nfcConnDev, uint8_t *aidBytes, memcpy(CMD + 5, aidBytes, 3); CMD[8] = keySettings; CMD[9] = numKeys; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> CreateApplication command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); @@ -712,12 +703,11 @@ static inline int CreateApplication(nfc_device *nfcConnDev, uint8_t *aidBytes, RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -728,7 +718,7 @@ static inline int CreateApplication(nfc_device *nfcConnDev, uint8_t *aidBytes, } static inline int DeleteApplication(nfc_device *nfcConnDev, uint8_t *aidBytes) { - if(nfcConnDev == NULL || aidBytes == NULL) { + if (nfcConnDev == NULL || aidBytes == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[9]; @@ -737,7 +727,7 @@ static inline int DeleteApplication(nfc_device *nfcConnDev, uint8_t *aidBytes) { memset(CMD + 2, 0x00, 7); CMD[4] = 3; memcpy(CMD + 5, aidBytes, 3); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> DeleteApplication command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); @@ -745,12 +735,11 @@ static inline int DeleteApplication(nfc_device *nfcConnDev, uint8_t *aidBytes) { RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -761,7 +750,7 @@ static inline int DeleteApplication(nfc_device *nfcConnDev, uint8_t *aidBytes) { } static inline int SelectApplication(nfc_device *nfcConnDev, uint8_t *aidBytes, size_t aidLength) { - if(nfcConnDev == NULL || aidBytes == NULL || aidLength < APPLICATION_AID_LENGTH) { + if (nfcConnDev == NULL || aidBytes == NULL || aidLength < APPLICATION_AID_LENGTH) { return INVALID_PARAMS_ERROR; } size_t cmdBufSize = 6 + aidLength; @@ -771,7 +760,7 @@ static inline int SelectApplication(nfc_device *nfcConnDev, uint8_t *aidBytes, s memset(CMD + 2, 0x00, cmdBufSize - 2); CMD[4] = aidLength; memcpy(CMD + 5, aidBytes, aidLength); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> Select Application By AID:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); @@ -779,16 +768,15 @@ static inline int SelectApplication(nfc_device *nfcConnDev, uint8_t *aidBytes, s RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); fprintf(stdout, "\n"); } return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); fprintf(stdout, "\n"); } @@ -797,57 +785,56 @@ static inline int SelectApplication(nfc_device *nfcConnDev, uint8_t *aidBytes, s } static inline int GetDFNamesCommand(nfc_device *nfcConnDev) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! GetDFNames command NOT IMPLEMENTED !!\n"); } return EXIT_SUCCESS; } -static inline int CreateStandardDataFile(nfc_device *nfcConnDev, uint8_t fileNo, uint8_t commSettings, +static inline int CreateStandardDataFile(nfc_device *nfcConnDev, uint8_t fileNo, uint8_t commSettings, uint16_t accessRights, uint16_t fileSize) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } size_t cmdBufSize = 6 + 1 + 1 + 2 + 3; uint8_t CMD[cmdBufSize]; CMD[0] = 0x90; CMD[1] = 0xcd; - memset(CMD + 2, 0x00, cmdBufSize - 2); + memset(CMD + 2, 0x00, cmdBufSize - 2); CMD[4] = cmdBufSize - 6; CMD[5] = fileNo; CMD[6] = commSettings; - CMD[7] = (uint8_t) (accessRights & 0x00ff); - CMD[8] = (uint8_t) ((accessRights >> 8) & 0x00ff); - CMD[9] = (uint8_t) (fileSize & 0x00ff); - CMD[10] = (uint8_t) ((fileSize >> 8) & 0x00ff); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + CMD[7] = (uint8_t)(accessRights & 0x00ff); + CMD[8] = (uint8_t)((accessRights >> 8) & 0x00ff); + CMD[9] = (uint8_t)(fileSize & 0x00ff); + CMD[10] = (uint8_t)((fileSize >> 8) & 0x00ff); + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> CreateStdDataFile command:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); - } + } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); fprintf(stdout, "\n"); - } + } return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); fprintf(stdout, "\n"); - } + } return EXIT_FAILURE; - } + } } static inline int CreateBackupDataFile(nfc_device *nfcConnDev, uint8_t fileNo, uint8_t commSettings, - uint16_t accessRights, uint16_t fileSize) { - if(nfcConnDev == NULL) { + uint16_t accessRights, uint16_t fileSize) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } size_t cmdBufSize = 6 + 1 + 1 + 2 + 3; @@ -858,39 +845,38 @@ static inline int CreateBackupDataFile(nfc_device *nfcConnDev, uint8_t fileNo, u CMD[4] = cmdBufSize - 6; CMD[5] = fileNo; CMD[6] = commSettings; - CMD[7] = (uint8_t) (accessRights & 0x00ff); - CMD[8] = (uint8_t) ((accessRights >> 8) & 0x00ff); - CMD[9] = (uint8_t) (fileSize & 0x00ff); - CMD[10] = (uint8_t) ((fileSize >> 8) & 0x00ff); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + CMD[7] = (uint8_t)(accessRights & 0x00ff); + CMD[8] = (uint8_t)((accessRights >> 8) & 0x00ff); + CMD[9] = (uint8_t)(fileSize & 0x00ff); + CMD[10] = (uint8_t)((fileSize >> 8) & 0x00ff); + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> CreateBackupDataFile command:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); - } + } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); fprintf(stdout, "\n"); - } + } return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); fprintf(stdout, "\n"); - } + } return EXIT_FAILURE; } } -static inline int CreateValueFile(nfc_device *nfcConnDev, uint8_t fileNo, uint8_t CommSettings, - uint16_t AccessRights, uint32_t LowerLimit, uint32_t UpperLimit, +static inline int CreateValueFile(nfc_device *nfcConnDev, uint8_t fileNo, uint8_t CommSettings, + uint16_t AccessRights, uint32_t LowerLimit, uint32_t UpperLimit, uint32_t Value, uint8_t LimitedCreditEnabled) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } size_t cmdBufSize = 6 + 1 + 1 + 2 + 4 + 4 + 4 + 1; @@ -901,41 +887,40 @@ static inline int CreateValueFile(nfc_device *nfcConnDev, uint8_t fileNo, uint8_ CMD[4] = cmdBufSize - 6; CMD[5] = fileNo; CMD[6] = CommSettings; - CMD[7] = (uint8_t) (AccessRights & 0x00ff); - CMD[8] = (uint8_t) ((AccessRights >> 8) & 0x00ff); + CMD[7] = (uint8_t)(AccessRights & 0x00ff); + CMD[8] = (uint8_t)((AccessRights >> 8) & 0x00ff); Int32ToByteBuffer(CMD + 9, LowerLimit); Int32ToByteBuffer(CMD + 13, UpperLimit); Int32ToByteBuffer(CMD + 17, Value); CMD[21] = LimitedCreditEnabled; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> CreateValueFile command:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); - } + } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); fprintf(stdout, "\n"); - } + } return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); fprintf(stdout, "\n"); - } + } return EXIT_FAILURE; } } -static inline int CreateLinearRecordFile(nfc_device *nfcConnDev, uint8_t fileNo, - uint8_t commSettings, uint16_t accessRights, +static inline int CreateLinearRecordFile(nfc_device *nfcConnDev, uint8_t fileNo, + uint8_t commSettings, uint16_t accessRights, uint16_t recordSize, uint16_t maxRecords) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } size_t cmdBufSize = 6 + 1 + 1 + 2 + 3 + 3; @@ -946,39 +931,38 @@ static inline int CreateLinearRecordFile(nfc_device *nfcConnDev, uint8_t fileNo, CMD[4] = cmdBufSize - 6; CMD[5] = fileNo; CMD[6] = commSettings; - CMD[7] = (uint8_t) (accessRights & 0x00ff); - CMD[8] = (uint8_t) ((accessRights >> 8) & 0x00ff); + CMD[7] = (uint8_t)(accessRights & 0x00ff); + CMD[8] = (uint8_t)((accessRights >> 8) & 0x00ff); Int24ToByteBuffer(CMD + 9, recordSize); Int24ToByteBuffer(CMD + 12, maxRecords); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> CreateLinearRecordFile command:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); - } + } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); fprintf(stdout, "\n"); - } + } return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); fprintf(stdout, "\n"); - } + } return EXIT_FAILURE; } } -static inline int CreateCyclicRecordFile(nfc_device *nfcConnDev, uint8_t fileNo, - uint8_t commSettings, uint16_t accessRights, +static inline int CreateCyclicRecordFile(nfc_device *nfcConnDev, uint8_t fileNo, + uint8_t commSettings, uint16_t accessRights, uint16_t recordSize, uint16_t maxRecords) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } size_t cmdBufSize = 6 + 1 + 1 + 2 + 3 + 3; @@ -989,43 +973,42 @@ static inline int CreateCyclicRecordFile(nfc_device *nfcConnDev, uint8_t fileNo, CMD[4] = cmdBufSize - 6; CMD[5] = fileNo; CMD[6] = commSettings; - CMD[7] = (uint8_t) (accessRights & 0x00ff); - CMD[8] = (uint8_t) ((accessRights >> 8) & 0x00ff); + CMD[7] = (uint8_t)(accessRights & 0x00ff); + CMD[8] = (uint8_t)((accessRights >> 8) & 0x00ff); Int24ToByteBuffer(CMD + 9, recordSize); Int24ToByteBuffer(CMD + 12, maxRecords); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> CreateCyclicRecordFile command:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); - } + } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); fprintf(stdout, "\n"); - } + } return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); fprintf(stdout, "\n"); - } + } return EXIT_FAILURE; } } static inline int DeleteFile(nfc_device *nfcConnDev, uint8_t fileNo) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[] = { 0x90, 0xdf, 0x00, 0x00, 0x01, fileNo, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> DeleteFile command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); @@ -1034,12 +1017,11 @@ static inline int DeleteFile(nfc_device *nfcConnDev, uint8_t fileNo) { bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " <- "); + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -1050,13 +1032,13 @@ static inline int DeleteFile(nfc_device *nfcConnDev, uint8_t fileNo) { } static inline int GetFileIds(nfc_device *nfcConnDev) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[] = { 0x90, 0x6f, 0x00, 0x00, 0x00, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> GetFileIds command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); @@ -1065,12 +1047,11 @@ static inline int GetFileIds(nfc_device *nfcConnDev) { bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -1081,46 +1062,45 @@ static inline int GetFileIds(nfc_device *nfcConnDev) { } static inline int GetFileSettings(nfc_device *nfcConnDev, uint8_t fileNo) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; - } + } uint8_t CMD[] = { - 0x90, 0xf5, 0x00, 0x00, 0x01, fileNo, 0x00 - }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + 0x90, 0xf5, 0x00, 0x00, 0x01, fileNo, 0x00 + }; + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> GetFileSettings command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); - } + } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; - rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, + rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " <- "); + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); - } + } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; - } + } FreeRxDataStruct(rxDataStorage, true); return EXIT_SUCCESS; } static inline int ChangeFileSettings(nfc_device *nfcConnDev) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! ChangeFileSettings command NOT IMPLEMENTED !!\n"); } return EXIT_FAILURE; } -static inline int ReadDataCommand(nfc_device *nfcConnDev, uint8_t fileNo, +static inline int ReadDataCommand(nfc_device *nfcConnDev, uint8_t fileNo, uint16_t fileReadOffset, uint16_t readLength) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } size_t cmdBufSize = 6 + 1 + 3 + 3; @@ -1130,11 +1110,11 @@ static inline int ReadDataCommand(nfc_device *nfcConnDev, uint8_t fileNo, memset(CMD + 2, 0x00, cmdBufSize - 2); CMD[4] = cmdBufSize - 6; CMD[5] = fileNo; - CMD[6] = (uint8_t) (fileReadOffset & 0x00ff); - CMD[7] = (uint8_t) ((fileReadOffset >> 8) & 0x00ff); - CMD[9] = (uint8_t) (readLength & 0x00ff); - CMD[10] = (uint8_t) ((readLength >> 8) & 0x00ff); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + CMD[6] = (uint8_t)(fileReadOffset & 0x00ff); + CMD[7] = (uint8_t)((fileReadOffset >> 8) & 0x00ff); + CMD[9] = (uint8_t)(readLength & 0x00ff); + CMD[10] = (uint8_t)((readLength >> 8) & 0x00ff); + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> ReadData command:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); @@ -1142,28 +1122,26 @@ static inline int ReadDataCommand(nfc_device *nfcConnDev, uint8_t fileNo, RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); } return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } return EXIT_FAILURE; } } -static inline int WriteDataCommand(nfc_device *nfcConnDev, uint8_t fileNo, - uint16_t writeDataOffset, uint16_t writeDataLength, +static inline int WriteDataCommand(nfc_device *nfcConnDev, uint8_t fileNo, + uint16_t writeDataOffset, uint16_t writeDataLength, uint8_t *writeDataBuf) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; - } - else if(writeDataLength > 52 || writeDataOffset > 52) { + } else if (writeDataLength > 52 || writeDataOffset > 52) { return DATA_LENGTH_ERROR; } size_t cmdBufSize = 6 + 1 + 3 + 3 + writeDataLength; @@ -1176,7 +1154,7 @@ static inline int WriteDataCommand(nfc_device *nfcConnDev, uint8_t fileNo, Int24ToByteBuffer(CMD + 6, writeDataOffset); Int24ToByteBuffer(CMD + 9, writeDataLength); memcpy(CMD + 12, writeDataBuf, writeDataLength); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> WriteData command:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); @@ -1184,15 +1162,14 @@ static inline int WriteDataCommand(nfc_device *nfcConnDev, uint8_t fileNo, RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); } return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } return EXIT_FAILURE; @@ -1200,38 +1177,37 @@ static inline int WriteDataCommand(nfc_device *nfcConnDev, uint8_t fileNo, } static inline int GetValueCommand(nfc_device *nfcConnDev, uint8_t fileNo) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; - } + } uint8_t CMD[] = { - 0x90, 0x6c, 0x00, 0x00, 0x01, fileNo, 0x00 - }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + 0x90, 0x6c, 0x00, 0x00, 0x01, fileNo, 0x00 + }; + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> GetValue command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); - } + } RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; - rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, + rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " <- "); + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); - } + } FreeRxDataStruct(rxDataStorage, true); return EXIT_FAILURE; - } + } FreeRxDataStruct(rxDataStorage, true); return EXIT_SUCCESS; } static inline int CreditValueFileCommand(nfc_device *nfcConnDev, uint8_t fileNo, uint32_t creditAmount) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } size_t cmdBufSize = 6 + 1 + 4; @@ -1242,7 +1218,7 @@ static inline int CreditValueFileCommand(nfc_device *nfcConnDev, uint8_t fileNo, CMD[4] = cmdBufSize - 6; CMD[5] = fileNo; Int32ToByteBuffer(CMD + 6, creditAmount); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> Credit(ValueFile) command:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); @@ -1250,15 +1226,14 @@ static inline int CreditValueFileCommand(nfc_device *nfcConnDev, uint8_t fileNo, RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); } return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } return EXIT_FAILURE; @@ -1266,7 +1241,7 @@ static inline int CreditValueFileCommand(nfc_device *nfcConnDev, uint8_t fileNo, } static inline int DebitValueFileCommand(nfc_device *nfcConnDev, uint8_t fileNo, uint32_t debitAmount) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } size_t cmdBufSize = 6 + 1 + 4; @@ -1277,7 +1252,7 @@ static inline int DebitValueFileCommand(nfc_device *nfcConnDev, uint8_t fileNo, CMD[4] = cmdBufSize - 6; CMD[5] = fileNo; Int32ToByteBuffer(CMD + 6, debitAmount); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> Debit(ValueFile) command:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); @@ -1285,15 +1260,14 @@ static inline int DebitValueFileCommand(nfc_device *nfcConnDev, uint8_t fileNo, RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); } return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } return EXIT_FAILURE; @@ -1301,7 +1275,7 @@ static inline int DebitValueFileCommand(nfc_device *nfcConnDev, uint8_t fileNo, } static inline int LimitedCreditValueFileCommand(nfc_device *nfcConnDev, uint8_t fileNo, uint32_t creditAmount) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } size_t cmdBufSize = 6 + 1 + 4; @@ -1312,7 +1286,7 @@ static inline int LimitedCreditValueFileCommand(nfc_device *nfcConnDev, uint8_t CMD[4] = cmdBufSize - 6; CMD[5] = fileNo; Int32ToByteBuffer(CMD + 6, creditAmount); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> LimitedCredit(ValueFile) command:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); @@ -1320,15 +1294,14 @@ static inline int LimitedCreditValueFileCommand(nfc_device *nfcConnDev, uint8_t RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH); bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); } return EXIT_SUCCESS; - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } return EXIT_FAILURE; @@ -1336,13 +1309,13 @@ static inline int LimitedCreditValueFileCommand(nfc_device *nfcConnDev, uint8_t } static inline int CommitTransaction(nfc_device *nfcConnDev) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[] = { 0x90, 0xc7, 0x00, 0x00, 0x00, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> CommitTransaction command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); @@ -1351,12 +1324,11 @@ static inline int CommitTransaction(nfc_device *nfcConnDev) { bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " <- "); + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -1367,13 +1339,13 @@ static inline int CommitTransaction(nfc_device *nfcConnDev) { } static inline int AbortTransaction(nfc_device *nfcConnDev) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[] = { 0x90, 0xa7, 0x00, 0x00, 0x00, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> AbortTransaction command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); @@ -1382,12 +1354,11 @@ static inline int AbortTransaction(nfc_device *nfcConnDev) { bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " <- "); + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); @@ -1397,9 +1368,9 @@ static inline int AbortTransaction(nfc_device *nfcConnDev) { return EXIT_SUCCESS; } -static inline int ReadRecordsCommand(nfc_device *nfcConnDev, uint8_t fileNo, +static inline int ReadRecordsCommand(nfc_device *nfcConnDev, uint8_t fileNo, uint32_t offset, uint32_t dataLength) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } size_t cmdBufSize = 6 + 1 + 3 + 3; @@ -1411,7 +1382,7 @@ static inline int ReadRecordsCommand(nfc_device *nfcConnDev, uint8_t fileNo, CMD[5] = fileNo; Int24ToByteBuffer(CMD + 6, offset); Int24ToByteBuffer(CMD + 9, dataLength); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> ReadRecords command:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); @@ -1421,34 +1392,33 @@ static inline int ReadRecordsCommand(nfc_device *nfcConnDev, uint8_t fileNo, bool continueFrame = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); do { - if(continueFrame) { + if (continueFrame) { uint8_t CMDCONT[] = { 0x90, 0xaf, 0x00, 0x00, 0x00, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -> "); print_hex(CMDCONT, sizeof(CMDCONT)); - } + } rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMDCONT, sizeof(CMDCONT), rxDataStorage); } - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); } - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } return EXIT_FAILURE; } continueFrame = (rxDataStorage->rxDataBuf[rxDataStorage->recvSzRx - 1] == 0xaf); - } while(continueFrame); + } while (continueFrame); return EXIT_SUCCESS; } -static inline int WriteRecordsCommand(nfc_device *nfcConnDev, uint8_t fileNo, +static inline int WriteRecordsCommand(nfc_device *nfcConnDev, uint8_t fileNo, uint32_t offset, uint32_t dataLength, uint8_t *dataBuf) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } size_t cmdBufSize = 6 + 1 + 3 + 3 + MIN(dataLength, 52); @@ -1461,7 +1431,7 @@ static inline int WriteRecordsCommand(nfc_device *nfcConnDev, uint8_t fileNo, Int24ToByteBuffer(CMD + 6, offset); Int24ToByteBuffer(CMD + 9, dataLength); memcpy(CMD + 12, dataBuf, MIN(dataLength, 52)); - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> WriteRecords command:\n"); fprintf(stdout, " -> "); print_hex(CMD, cmdBufSize); @@ -1473,9 +1443,9 @@ static inline int WriteRecordsCommand(nfc_device *nfcConnDev, uint8_t fileNo, bool continueFrame = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, cmdBufSize, rxDataStorage); do { - if(continueFrame && remDataBytes > 0) { + if (continueFrame && remDataBytes > 0) { cmdBufSize = 6 + MIN(remDataBytes, 59); - uint8_t CMDCONT[cmdBufSize]; + uint8_t CMDCONT[cmdBufSize]; CMDCONT[0] = 0x90; CMDCONT[1] = 0xaf; memset(CMDCONT + 2, 0x00, cmdBufSize - 2); @@ -1483,37 +1453,36 @@ static inline int WriteRecordsCommand(nfc_device *nfcConnDev, uint8_t fileNo, memcpy(CMDCONT + 5, remDataBytesBuf, MIN(remDataBytes, 59)); remDataBytes = MAX(0, remDataBytes - 59); remDataBytesBuf += 59; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -> "); print_hex(CMDCONT, cmdBufSize); - } + } rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMDCONT, sizeof(CMDCONT), rxDataStorage); } - if(rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); } - } - else { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } return EXIT_FAILURE; } continueFrame = (rxDataStorage->rxDataBuf[rxDataStorage->recvSzRx - 1] == 0xaf); - } while(continueFrame); + } while (continueFrame); return EXIT_SUCCESS; } static inline int ClearRecordsCommand(nfc_device *nfcConnDev, uint8_t fileNo) { - if(nfcConnDev == NULL) { + if (nfcConnDev == NULL) { return INVALID_PARAMS_ERROR; } uint8_t CMD[] = { 0x90, 0xeb, 0x00, 0x00, 0x01, fileNo, 0x00 }; - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, ">>> ClearRecords command:\n"); fprintf(stdout, " -> "); print_hex(CMD, sizeof(CMD)); @@ -1522,12 +1491,11 @@ static inline int ClearRecordsCommand(nfc_device *nfcConnDev, uint8_t fileNo) { bool rxDataStatus = false; rxDataStatus = libnfcTransmitBytes(nfcConnDev, CMD, sizeof(CMD), rxDataStorage); - if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, " <- "); + if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) { + fprintf(stdout, " <- "); print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx); - } - else if(!rxDataStatus) { - if(PRINT_STATUS_EXCHANGE_MESSAGES) { + } else if (!rxDataStatus) { + if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " -- !! Unable to transfer bytes !!\n"); } FreeRxDataStruct(rxDataStorage, true); diff --git a/Software/DESFireLibNFCTesting/LocalInclude/ErrorHandling.h b/Software/DESFireLibNFCTesting/LocalInclude/ErrorHandling.h index 90c5644e..6723f727 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/ErrorHandling.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/ErrorHandling.h @@ -38,24 +38,24 @@ static inline char __InternalLoggingStringBuffer[STRING_BUFFER_SIZE] = { '\0' }; }) typedef enum { - NO_ERROR = 0, - LIBC_ERROR, - LIBNFC_ERROR, - GENERIC_OTHER_ERROR, - INVALID_PARAMS_ERROR, - AES_AUTH_FAILED, - DATA_LENGTH_ERROR, - LAST_ERROR, + NO_ERROR = 0, + LIBC_ERROR, + LIBNFC_ERROR, + GENERIC_OTHER_ERROR, + INVALID_PARAMS_ERROR, + AES_AUTH_FAILED, + DATA_LENGTH_ERROR, + LAST_ERROR, } ErrorType_t; static inline const char *LOCAL_ERROR_MSGS[] = { - [NO_ERROR] = "No error", - [LIBC_ERROR] = "Libc function error", - [GENERIC_OTHER_ERROR] = "Unspecified (generic) error", - [INVALID_PARAMS_ERROR] = "Invalid parameters", - [AES_AUTH_FAILED] = "AES auth procedure failed (generic)", - [DATA_LENGTH_ERROR] = "Data length error (buffer size too large)", - [LAST_ERROR] = NULL, + [NO_ERROR] = "No error", + [LIBC_ERROR] = "Libc function error", + [GENERIC_OTHER_ERROR] = "Unspecified (generic) error", + [INVALID_PARAMS_ERROR] = "Invalid parameters", + [AES_AUTH_FAILED] = "AES auth procedure failed (generic)", + [DATA_LENGTH_ERROR] = "Data length error (buffer size too large)", + [LAST_ERROR] = NULL, }; static inline bool RUNTIME_QUIET_MODE = false; diff --git a/Software/DESFireLibNFCTesting/LocalInclude/GeneralUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/GeneralUtils.h index acf00274..3b715754 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/GeneralUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/GeneralUtils.h @@ -11,26 +11,26 @@ static inline void InvalidateAuthState(void) { memset(CRYPTO_RNDB_STATE, 0x00, 8); AUTHENTICATED = false; - AUTHENTICATED_PROTO = 0; + AUTHENTICATED_PROTO = 0; } static inline void Int32ToByteBuffer(uint8_t *byteBuffer, int32_t int32Value) { - if(byteBuffer == NULL) { + if (byteBuffer == NULL) { return; - } - byteBuffer[0] = (uint8_t) (int32Value & 0x000000ff); - byteBuffer[1] = (uint8_t) ((int32Value >> 8) & 0x000000ff); - byteBuffer[2] = (uint8_t) ((int32Value >> 16) & 0x000000ff); - byteBuffer[3] = (uint8_t) ((int32Value >> 24) & 0x000000ff); + } + byteBuffer[0] = (uint8_t)(int32Value & 0x000000ff); + byteBuffer[1] = (uint8_t)((int32Value >> 8) & 0x000000ff); + byteBuffer[2] = (uint8_t)((int32Value >> 16) & 0x000000ff); + byteBuffer[3] = (uint8_t)((int32Value >> 24) & 0x000000ff); } void Int24ToByteBuffer(uint8_t *byteBuffer, uint32_t int24Value) { - if(byteBuffer == NULL) { + if (byteBuffer == NULL) { return; - } - byteBuffer[0] = (uint8_t) (int24Value & 0x0000ff); - byteBuffer[1] = (uint8_t) ((int24Value >> 8) & 0x0000ff); - byteBuffer[2] = (uint8_t) ((int24Value >> 16) & 0x0000ff); + } + byteBuffer[0] = (uint8_t)(int24Value & 0x0000ff); + byteBuffer[1] = (uint8_t)((int24Value >> 8) & 0x0000ff); + byteBuffer[2] = (uint8_t)((int24Value >> 16) & 0x0000ff); } #endif diff --git a/Software/DESFireLibNFCTesting/LocalInclude/LibNFCUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/LibNFCUtils.h index 21a9c1ba..e0af5e45 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/LibNFCUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/LibNFCUtils.h @@ -104,135 +104,132 @@ #endif static inline uint8_t oddparity(const uint8_t bt) { - // cf http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel - return (0x9669 >> ((bt ^ (bt >> 4)) & 0xF)) & 1; + // cf http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel + return (0x9669 >> ((bt ^ (bt >> 4)) & 0xF)) & 1; } static inline void oddparity_bytes_ts(const uint8_t *pbtData, const size_t szLen, uint8_t *pbtPar) { - size_t szByteNr; - // Calculate the parity bits for the command - for (szByteNr = 0; szByteNr < szLen; szByteNr++) { - pbtPar[szByteNr] = oddparity(pbtData[szByteNr]); - } + size_t szByteNr; + // Calculate the parity bits for the command + for (szByteNr = 0; szByteNr < szLen; szByteNr++) { + pbtPar[szByteNr] = oddparity(pbtData[szByteNr]); + } } static inline void print_hex(const uint8_t *pbtData, const size_t szLen) { - size_t szPos; - for (szPos = 0; szPos < szLen; szPos++) { - if((szPos > 0) && (szPos % 8) == 0) { - printf("| "); + size_t szPos; + for (szPos = 0; szPos < szLen; szPos++) { + if ((szPos > 0) && (szPos % 8) == 0) { + printf("| "); + } + printf("%02x ", pbtData[szPos]); } - printf("%02x ", pbtData[szPos]); - } - printf("\n"); + printf("\n"); } static inline void print_hex_bits(const uint8_t *pbtData, const size_t szBits) { - uint8_t uRemainder; - size_t szPos; - size_t szBytes = szBits / 8; - for (szPos = 0; szPos < szBytes; szPos++) { - printf("%02x ", pbtData[szPos]); - } - uRemainder = szBits % 8; - // Print the rest bits - if (uRemainder != 0) { - if (uRemainder < 5) - printf("%01x (%d bits)", pbtData[szBytes], uRemainder); - else - printf("%02x (%d bits)", pbtData[szBytes], uRemainder); - } - printf("\n"); + uint8_t uRemainder; + size_t szPos; + size_t szBytes = szBits / 8; + for (szPos = 0; szPos < szBytes; szPos++) { + printf("%02x ", pbtData[szPos]); + } + uRemainder = szBits % 8; + // Print the rest bits + if (uRemainder != 0) { + if (uRemainder < 5) + printf("%01x (%d bits)", pbtData[szBytes], uRemainder); + else + printf("%02x (%d bits)", pbtData[szBytes], uRemainder); + } + printf("\n"); } static inline void print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar) { - uint8_t uRemainder; - size_t szPos; - size_t szBytes = szBits / 8; - for (szPos = 0; szPos < szBytes; szPos++) { - printf("%02x", pbtData[szPos]); - if (oddparity(pbtData[szPos]) != pbtDataPar[szPos]) { - printf("! "); - } else { - printf(" "); + uint8_t uRemainder; + size_t szPos; + size_t szBytes = szBits / 8; + for (szPos = 0; szPos < szBytes; szPos++) { + printf("%02x", pbtData[szPos]); + if (oddparity(pbtData[szPos]) != pbtDataPar[szPos]) { + printf("! "); + } else { + printf(" "); + } } - } - uRemainder = szBits % 8; - // Print the rest bits, these cannot have parity bit - if (uRemainder != 0) { - if (uRemainder < 5) - printf("%01x (%d bits)", pbtData[szBytes], uRemainder); - else - printf("%02x (%d bits)", pbtData[szBytes], uRemainder); - } - printf("\n"); + uRemainder = szBits % 8; + // Print the rest bits, these cannot have parity bit + if (uRemainder != 0) { + if (uRemainder < 5) + printf("%01x (%d bits)", pbtData[szBytes], uRemainder); + else + printf("%02x (%d bits)", pbtData[szBytes], uRemainder); + } + printf("\n"); } static inline void print_nfc_target(const nfc_target *pnt, bool verbose) { - char *s; - str_nfc_target(&s, pnt, verbose); - printf("%s", s); - nfc_free(s); + char *s; + str_nfc_target(&s, pnt, verbose); + printf("%s", s); + nfc_free(s); } typedef struct { - size_t recvSzRx; - uint8_t *rxDataBuf; - size_t maxRxDataSize; + size_t recvSzRx; + uint8_t *rxDataBuf; + size_t maxRxDataSize; } RxData_t; -static inline RxData_t * InitRxDataStruct(size_t bufSize) { - RxData_t *rxData = malloc(sizeof(RxData_t)); - if(rxData == NULL) { - return NULL; - } - rxData->recvSzRx = 0; - rxData->rxDataBuf = malloc(bufSize); - memset(rxData->rxDataBuf, 0x00, bufSize); - if(rxData->rxDataBuf == NULL) { - free(rxData); - return NULL; - } - rxData->maxRxDataSize = bufSize; +static inline RxData_t *InitRxDataStruct(size_t bufSize) { + RxData_t *rxData = malloc(sizeof(RxData_t)); + if (rxData == NULL) { + return NULL; + } + rxData->recvSzRx = 0; + rxData->rxDataBuf = malloc(bufSize); + memset(rxData->rxDataBuf, 0x00, bufSize); + if (rxData->rxDataBuf == NULL) { + free(rxData); + return NULL; + } + rxData->maxRxDataSize = bufSize; } static inline void FreeRxDataStruct(RxData_t *rxData, bool freeInputPtr) { - if(rxData != NULL) { - free(rxData->rxDataBuf); - if(freeInputPtr) { - free(rxData); - } - else { - rxData->recvSzRx = 0; - rxData->maxRxDataSize = 0; - rxData->rxDataBuf = NULL; - } - } + if (rxData != NULL) { + free(rxData->rxDataBuf); + if (freeInputPtr) { + free(rxData); + } else { + rxData->recvSzRx = 0; + rxData->maxRxDataSize = 0; + rxData->rxDataBuf = NULL; + } + } } static inline bool -libnfcTransmitBits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, RxData_t *rxData) -{ - uint32_t cycles = 0; - if ((rxData->recvSzRx = nfc_initiator_transceive_bits(pnd, pbtTx, szTxBits, NULL, - rxData->rxDataBuf, rxData->maxRxDataSize, NULL)) < 0) { - fprintf(stderr, " -- Error transceiving Bits: %s\n", nfc_strerror(pnd)); - return false; - } - return true; +libnfcTransmitBits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, RxData_t *rxData) { + uint32_t cycles = 0; + if ((rxData->recvSzRx = nfc_initiator_transceive_bits(pnd, pbtTx, szTxBits, NULL, + rxData->rxDataBuf, rxData->maxRxDataSize, NULL)) < 0) { + fprintf(stderr, " -- Error transceiving Bits: %s\n", nfc_strerror(pnd)); + return false; + } + return true; } static inline bool -libnfcTransmitBytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, RxData_t *rxData) -{ - uint32_t cycles = 0; - int res; - if ((res = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, rxData->rxDataBuf, rxData->maxRxDataSize, 0)) < 0) { - fprintf(stderr, " -- Error transceiving Bytes: %s\n", nfc_strerror(pnd)); - return false; - } - rxData->recvSzRx = res; - return true; +libnfcTransmitBytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, RxData_t *rxData) { + uint32_t cycles = 0; + int res; + if ((res = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, rxData->rxDataBuf, rxData->maxRxDataSize, 0)) < 0) { + fprintf(stderr, " -- Error transceiving Bytes: %s\n", nfc_strerror(pnd)); + return false; + } + rxData->recvSzRx = res; + return true; } #endif diff --git a/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h b/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h index 1311bf27..98cf8454 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h @@ -20,33 +20,33 @@ # include "config.h" #endif // HAVE_CONFIG_H -static inline nfc_device * GetNFCDeviceDriver(nfc_context **context) { +static inline nfc_device *GetNFCDeviceDriver(nfc_context **context) { nfc_init(context); - if(*context == NULL) { + if (*context == NULL) { ERR("Unable to init libnfc (malloc)"); return NULL; - } + } nfc_device *pnd = nfc_open(*context, NULL); - if(pnd == NULL) { + if (pnd == NULL) { ERR("Error opening NFC reader"); nfc_exit(context); *context = NULL; - return NULL; - } - if(nfc_initiator_init(pnd) < 0) { + return NULL; + } + if (nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); nfc_close(pnd); nfc_exit(context); - *context = NULL; + *context = NULL; return NULL; - } + } // Configure some convenient common settings: nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false); nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true); nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, true); nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, true); - nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false); + nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false); nfc_device_set_property_int(pnd, NP_TIMEOUT_COMMAND, 0); return pnd; } diff --git a/Software/DESFireLibNFCTesting/Makefile b/Software/DESFireLibNFCTesting/Makefile index f6adabfe..99648973 100644 --- a/Software/DESFireLibNFCTesting/Makefile +++ b/Software/DESFireLibNFCTesting/Makefile @@ -66,5 +66,19 @@ prelims: @mkdir -p ./Obj ./Bin clean: - @rm -f $(OBJDIR)/* $(BINDIR)/* + @rm -f $(OBJDIR)/* $(BINDIR)/* *.code +style: + # Make sure astyle is installed + @which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 ) + # Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, Makefile + find . \( -name "*.[ch]" -or -name "Makefile" \) \ + -exec perl -pi -e 's/[ \t]+$$//' {} \; \ + -exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \ + -exec sh -c "echo >> {}" \; + # Apply astyle on *.c, *.h + find . -name "*.[ch]" -exec astyle --formatted --mode=c --suffix=none \ + --indent=spaces=4 --indent-switches \ + --keep-one-line-blocks --max-instatement-indent=60 \ + --style=google --pad-oper --unpad-paren --pad-header \ + --align-pointer=name {} \; diff --git a/Software/DESFireLibNFCTesting/Source/NFCAntiCollisionMod.c b/Software/DESFireLibNFCTesting/Source/NFCAntiCollisionMod.c index d9cf3e31..1e9c46a3 100644 --- a/Software/DESFireLibNFCTesting/Source/NFCAntiCollisionMod.c +++ b/Software/DESFireLibNFCTesting/Source/NFCAntiCollisionMod.c @@ -82,282 +82,278 @@ uint8_t abtRats[4] = { 0xe0, 0x50, 0x00, 0x00 }; uint8_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 }; static bool -transmit_bits(const uint8_t *pbtTx, const size_t szTxBits) -{ - uint32_t cycles = 0; - if (!quiet_output) { - printf("Sent bits: "); - print_hex_bits(pbtTx, szTxBits); - } - if (timed) { - if ((szRxBits = nfc_initiator_transceive_bits_timed(pnd, pbtTx, szTxBits, NULL, abtRx, sizeof(abtRx), NULL, &cycles)) < 0) { - fprintf(stderr, "Error transceiving Bits: %s\n", nfc_strerror(pnd)); - return false; - } - if ((!quiet_output) && (szRxBits > 0)) { - printf("Response after %u cycles\n", cycles); - } - } else { - if ((szRxBits = nfc_initiator_transceive_bits(pnd, pbtTx, szTxBits, NULL, abtRx, sizeof(abtRx), NULL)) < 0) { - fprintf(stderr, "Error transceiving Bits: %s\n", nfc_strerror(pnd)); - return false; - } - } - if (!quiet_output) { - printf("Received bits: "); - print_hex_bits(abtRx, szRxBits); - } - return true; +transmit_bits(const uint8_t *pbtTx, const size_t szTxBits) { + uint32_t cycles = 0; + if (!quiet_output) { + printf("Sent bits: "); + print_hex_bits(pbtTx, szTxBits); + } + if (timed) { + if ((szRxBits = nfc_initiator_transceive_bits_timed(pnd, pbtTx, szTxBits, NULL, abtRx, sizeof(abtRx), NULL, &cycles)) < 0) { + fprintf(stderr, "Error transceiving Bits: %s\n", nfc_strerror(pnd)); + return false; + } + if ((!quiet_output) && (szRxBits > 0)) { + printf("Response after %u cycles\n", cycles); + } + } else { + if ((szRxBits = nfc_initiator_transceive_bits(pnd, pbtTx, szTxBits, NULL, abtRx, sizeof(abtRx), NULL)) < 0) { + fprintf(stderr, "Error transceiving Bits: %s\n", nfc_strerror(pnd)); + return false; + } + } + if (!quiet_output) { + printf("Received bits: "); + print_hex_bits(abtRx, szRxBits); + } + return true; } static bool -transmit_bytes(const uint8_t *pbtTx, const size_t szTx) -{ - uint32_t cycles = 0; - if (!quiet_output) { - printf("Sent bits: "); - print_hex(pbtTx, szTx); - } - int res; - if (timed) { - if ((res = nfc_initiator_transceive_bytes_timed(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), &cycles)) < 0) { - fprintf(stderr, "Error transceiving Bytes: %s\n", nfc_strerror(pnd)); - return false; +transmit_bytes(const uint8_t *pbtTx, const size_t szTx) { + uint32_t cycles = 0; + if (!quiet_output) { + printf("Sent bits: "); + print_hex(pbtTx, szTx); } - if ((!quiet_output) && (res > 0)) { - printf("Response after %u cycles\n", cycles); + int res; + if (timed) { + if ((res = nfc_initiator_transceive_bytes_timed(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), &cycles)) < 0) { + fprintf(stderr, "Error transceiving Bytes: %s\n", nfc_strerror(pnd)); + return false; + } + if ((!quiet_output) && (res > 0)) { + printf("Response after %u cycles\n", cycles); + } + } else { + if ((res = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), 0)) < 0) { + fprintf(stderr, "Error transceiving Bytes: %s\n", nfc_strerror(pnd)); + return false; + } } - } else { - if ((res = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), 0)) < 0) { - fprintf(stderr, "Error transceiving Bytes: %s\n", nfc_strerror(pnd)); - return false; + szRx = res; + if (!quiet_output) { + printf("Received bits: "); + print_hex(abtRx, szRx); } - } - szRx = res; - if (!quiet_output) { - printf("Received bits: "); - print_hex(abtRx, szRx); - } - return true; + return true; } static void -print_usage(char *argv[]) -{ - printf("Usage: %s [OPTIONS]\n", argv[0]); - printf("Options:\n"); - printf("\t-h\tHelp. Print this message.\n"); - printf("\t-q\tQuiet mode. Suppress output of READER and EMULATOR data (improves timing).\n"); - printf("\t-f\tForce RATS.\n"); - printf("\t-t\tMeasure response time (in cycles).\n"); +print_usage(char *argv[]) { + printf("Usage: %s [OPTIONS]\n", argv[0]); + printf("Options:\n"); + printf("\t-h\tHelp. Print this message.\n"); + printf("\t-q\tQuiet mode. Suppress output of READER and EMULATOR data (improves timing).\n"); + printf("\t-f\tForce RATS.\n"); + printf("\t-t\tMeasure response time (in cycles).\n"); } int -main(int argc, char *argv[]) -{ - int arg; - - // Get commandline options - for (arg = 1; arg < argc; arg++) { - if (0 == strcmp(argv[arg], "-h")) { - print_usage(argv); - exit(EXIT_SUCCESS); - } else if (0 == strcmp(argv[arg], "-q")) { - quiet_output = true; - } else if (0 == strcmp(argv[arg], "-f")) { - force_rats = true; - } else if (0 == strcmp(argv[arg], "-t")) { - timed = true; - } else { - ERR("%s is not supported option.", argv[arg]); - print_usage(argv); - exit(EXIT_FAILURE); +main(int argc, char *argv[]) { + int arg; + + // Get commandline options + for (arg = 1; arg < argc; arg++) { + if (0 == strcmp(argv[arg], "-h")) { + print_usage(argv); + exit(EXIT_SUCCESS); + } else if (0 == strcmp(argv[arg], "-q")) { + quiet_output = true; + } else if (0 == strcmp(argv[arg], "-f")) { + force_rats = true; + } else if (0 == strcmp(argv[arg], "-t")) { + timed = true; + } else { + ERR("%s is not supported option.", argv[arg]); + print_usage(argv); + exit(EXIT_FAILURE); + } } - } - nfc_context *context; - nfc_init(&context); - if (context == NULL) { - ERR("Unable to init libnfc (malloc)"); - exit(EXIT_FAILURE); - } + nfc_context *context; + nfc_init(&context); + if (context == NULL) { + ERR("Unable to init libnfc (malloc)"); + exit(EXIT_FAILURE); + } - // Try to open the NFC reader - pnd = nfc_open(context, NULL); + // Try to open the NFC reader + pnd = nfc_open(context, NULL); - if (pnd == NULL) { - ERR("Error opening NFC reader"); - nfc_exit(context); - exit(EXIT_FAILURE); - } + if (pnd == NULL) { + ERR("Error opening NFC reader"); + nfc_exit(context); + exit(EXIT_FAILURE); + } - // Initialise NFC device as "initiator" - if (nfc_initiator_init(pnd) < 0) { - nfc_perror(pnd, "nfc_initiator_init"); - nfc_close(pnd); - nfc_exit(context); - exit(EXIT_FAILURE); - } + // Initialise NFC device as "initiator" + if (nfc_initiator_init(pnd) < 0) { + nfc_perror(pnd, "nfc_initiator_init"); + nfc_close(pnd); + nfc_exit(context); + exit(EXIT_FAILURE); + } - // Configure the CRC - if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) { - nfc_perror(pnd, "nfc_device_set_property_bool"); - nfc_close(pnd); - nfc_exit(context); - exit(EXIT_FAILURE); - } - // Use raw send/receive methods - if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) { - nfc_perror(pnd, "nfc_device_set_property_bool"); - nfc_close(pnd); - nfc_exit(context); - exit(EXIT_FAILURE); - } - // Disable 14443-4 autoswitching - if (nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, false) < 0) { - nfc_perror(pnd, "nfc_device_set_property_bool"); - nfc_close(pnd); - nfc_exit(context); - exit(EXIT_FAILURE); - } - - printf("NFC reader: %s opened\n\n", nfc_device_get_name(pnd)); - - // Send the 7 bits request command specified in ISO 14443A (0x26) - if (!transmit_bits(abtReqa, 7)) { - printf("Error: No tag available\n"); - nfc_close(pnd); - nfc_exit(context); - exit(EXIT_FAILURE); - } - memcpy(abtAtqa, abtRx, 2); - - // Anti-collision - transmit_bytes(abtSelectAll, 2); - - // Check answer - if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { - printf("WARNING: BCC check failed!\n"); - } - - // Save the UID CL1 - memcpy(abtRawUid, abtRx, 4); - print_hex(abtRawUid, 4); - - //Prepare and send CL1 Select-Command - memcpy(abtSelectTag + 2, abtRx, 5); - iso14443a_crc_append(abtSelectTag, 7); - transmit_bytes(abtSelectTag, 9); - abtSak = abtRx[0]; - - // Test if we are dealing with a CL2 - if (abtSak & CASCADE_BIT) { - szCL = 2; //or more - // Check answer - if (abtRawUid[0] != 0x88) { - printf("WARNING: Cascade bit set but CT != 0x88!\n"); + // Configure the CRC + if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) { + nfc_perror(pnd, "nfc_device_set_property_bool"); + nfc_close(pnd); + nfc_exit(context); + exit(EXIT_FAILURE); + } + // Use raw send/receive methods + if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) { + nfc_perror(pnd, "nfc_device_set_property_bool"); + nfc_close(pnd); + nfc_exit(context); + exit(EXIT_FAILURE); + } + // Disable 14443-4 autoswitching + if (nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, false) < 0) { + nfc_perror(pnd, "nfc_device_set_property_bool"); + nfc_close(pnd); + nfc_exit(context); + exit(EXIT_FAILURE); } - } - if (szCL == 2) { - // We have to do the anti-collision for cascade level 2 + printf("NFC reader: %s opened\n\n", nfc_device_get_name(pnd)); - // Prepare CL2 commands - abtSelectAll[0] = 0x95; + // Send the 7 bits request command specified in ISO 14443A (0x26) + if (!transmit_bits(abtReqa, 7)) { + printf("Error: No tag available\n"); + nfc_close(pnd); + nfc_exit(context); + exit(EXIT_FAILURE); + } + memcpy(abtAtqa, abtRx, 2); // Anti-collision transmit_bytes(abtSelectAll, 2); // Check answer if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { - printf("WARNING: BCC check failed!\n"); + printf("WARNING: BCC check failed!\n"); } - // Save UID CL2 - memcpy(abtRawUid + 4, abtRx, 4); + // Save the UID CL1 + memcpy(abtRawUid, abtRx, 4); + print_hex(abtRawUid, 4); - // Selection - abtSelectTag[0] = 0x95; + //Prepare and send CL1 Select-Command memcpy(abtSelectTag + 2, abtRx, 5); iso14443a_crc_append(abtSelectTag, 7); transmit_bytes(abtSelectTag, 9); abtSak = abtRx[0]; - // Test if we are dealing with a CL3 + // Test if we are dealing with a CL2 if (abtSak & CASCADE_BIT) { - szCL = 3; - // Check answer - if (abtRawUid[0] != 0x88) { - printf("WARNING: Cascade bit set but CT != 0x88!\n"); - } + szCL = 2; //or more + // Check answer + if (abtRawUid[0] != 0x88) { + printf("WARNING: Cascade bit set but CT != 0x88!\n"); + } } - if (szCL == 3) { - // We have to do the anti-collision for cascade level 3 - - // Prepare and send CL3 AC-Command - abtSelectAll[0] = 0x97; - transmit_bytes(abtSelectAll, 2); - - // Check answer - if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { - printf("WARNING: BCC check failed!\n"); - } - - // Save UID CL3 - memcpy(abtRawUid + 8, abtRx, 4); + if (szCL == 2) { + // We have to do the anti-collision for cascade level 2 + + // Prepare CL2 commands + abtSelectAll[0] = 0x95; + + // Anti-collision + transmit_bytes(abtSelectAll, 2); + + // Check answer + if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { + printf("WARNING: BCC check failed!\n"); + } + + // Save UID CL2 + memcpy(abtRawUid + 4, abtRx, 4); + + // Selection + abtSelectTag[0] = 0x95; + memcpy(abtSelectTag + 2, abtRx, 5); + iso14443a_crc_append(abtSelectTag, 7); + transmit_bytes(abtSelectTag, 9); + abtSak = abtRx[0]; + + // Test if we are dealing with a CL3 + if (abtSak & CASCADE_BIT) { + szCL = 3; + // Check answer + if (abtRawUid[0] != 0x88) { + printf("WARNING: Cascade bit set but CT != 0x88!\n"); + } + } + + if (szCL == 3) { + // We have to do the anti-collision for cascade level 3 + + // Prepare and send CL3 AC-Command + abtSelectAll[0] = 0x97; + transmit_bytes(abtSelectAll, 2); + + // Check answer + if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { + printf("WARNING: BCC check failed!\n"); + } + + // Save UID CL3 + memcpy(abtRawUid + 8, abtRx, 4); + + // Prepare and send final Select-Command + abtSelectTag[0] = 0x97; + memcpy(abtSelectTag + 2, abtRx, 5); + iso14443a_crc_append(abtSelectTag, 7); + transmit_bytes(abtSelectTag, 9); + abtSak = abtRx[0]; + } + } - // Prepare and send final Select-Command - abtSelectTag[0] = 0x97; - memcpy(abtSelectTag + 2, abtRx, 5); - iso14443a_crc_append(abtSelectTag, 7); - transmit_bytes(abtSelectTag, 9); - abtSak = abtRx[0]; + // Request ATS, this only applies to tags that support ISO 14443A-4 + if (abtRx[0] & SAK_FLAG_ATS_SUPPORTED) { + iso_ats_supported = true; } - } - - // Request ATS, this only applies to tags that support ISO 14443A-4 - if (abtRx[0] & SAK_FLAG_ATS_SUPPORTED) { - iso_ats_supported = true; - } - if ((abtRx[0] & SAK_FLAG_ATS_SUPPORTED) || force_rats) { - iso14443a_crc_append(abtRats, 2); - if (transmit_bytes(abtRats, 4)) { - memcpy(abtAts, abtRx, szRx); - szAts = szRx; + if ((abtRx[0] & SAK_FLAG_ATS_SUPPORTED) || force_rats) { + iso14443a_crc_append(abtRats, 2); + if (transmit_bytes(abtRats, 4)) { + memcpy(abtAts, abtRx, szRx); + szAts = szRx; + } } - } - - // Done, halt the tag now - iso14443a_crc_append(abtHalt, 2); - transmit_bytes(abtHalt, 4); - - printf("\nFound tag with\n UID: "); - switch (szCL) { - case 1: - printf("%02x%02x%02x%02x", abtRawUid[0], abtRawUid[1], abtRawUid[2], abtRawUid[3]); - break; - case 2: - printf("%02x%02x%02x", abtRawUid[1], abtRawUid[2], abtRawUid[3]); - printf("%02x%02x%02x%02x", abtRawUid[4], abtRawUid[5], abtRawUid[6], abtRawUid[7]); - break; - case 3: - printf("%02x%02x%02x", abtRawUid[1], abtRawUid[2], abtRawUid[3]); - printf("%02x%02x%02x", abtRawUid[5], abtRawUid[6], abtRawUid[7]); - printf("%02x%02x%02x%02x", abtRawUid[8], abtRawUid[9], abtRawUid[10], abtRawUid[11]); - break; - } - printf("\n"); - printf("ATQA: %02x%02x\n SAK: %02x\n", abtAtqa[1], abtAtqa[0], abtSak); - if (szAts > 1) { // if = 1, it's not actual ATS but error code - if (force_rats && ! iso_ats_supported) { - printf(" RATS forced\n"); + + // Done, halt the tag now + iso14443a_crc_append(abtHalt, 2); + transmit_bytes(abtHalt, 4); + + printf("\nFound tag with\n UID: "); + switch (szCL) { + case 1: + printf("%02x%02x%02x%02x", abtRawUid[0], abtRawUid[1], abtRawUid[2], abtRawUid[3]); + break; + case 2: + printf("%02x%02x%02x", abtRawUid[1], abtRawUid[2], abtRawUid[3]); + printf("%02x%02x%02x%02x", abtRawUid[4], abtRawUid[5], abtRawUid[6], abtRawUid[7]); + break; + case 3: + printf("%02x%02x%02x", abtRawUid[1], abtRawUid[2], abtRawUid[3]); + printf("%02x%02x%02x", abtRawUid[5], abtRawUid[6], abtRawUid[7]); + printf("%02x%02x%02x%02x", abtRawUid[8], abtRawUid[9], abtRawUid[10], abtRawUid[11]); + break; + } + printf("\n"); + printf("ATQA: %02x%02x\n SAK: %02x\n", abtAtqa[1], abtAtqa[0], abtSak); + if (szAts > 1) { // if = 1, it's not actual ATS but error code + if (force_rats && ! iso_ats_supported) { + printf(" RATS forced\n"); + } + printf(" ATS: "); + print_hex(abtAts, szAts); } - printf(" ATS: "); - print_hex(abtAts, szAts); - } - nfc_close(pnd); - nfc_exit(context); - exit(EXIT_SUCCESS); + nfc_close(pnd); + nfc_exit(context); + exit(EXIT_SUCCESS); } diff --git a/Software/DESFireLibNFCTesting/Source/TestApplicationManagementCommands.c b/Software/DESFireLibNFCTesting/Source/TestApplicationManagementCommands.c index 7cabe799..e5c50c3e 100644 --- a/Software/DESFireLibNFCTesting/Source/TestApplicationManagementCommands.c +++ b/Software/DESFireLibNFCTesting/Source/TestApplicationManagementCommands.c @@ -14,78 +14,65 @@ int main(int argc, char **argv) { nfc_context *nfcCtxt; nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); - if(nfcPnd == NULL) { - return EXIT_FAILURE; - } + if (nfcPnd == NULL) { + return EXIT_FAILURE; + } - if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + if (SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting PICC (Master) AID by default !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES !!\n"); return EXIT_FAILURE; - } + } uint8_t aidToCreateList1[] = { - 0x77, 0x88, 0x99 + 0x77, 0x88, 0x99 }; - uint8_t aidToCreateList2[] = { + uint8_t aidToCreateList2[] = { 0x01, 0x00, 0x34 }; - if(GetApplicationIds(nfcPnd)) { + if (GetApplicationIds(nfcPnd)) { fprintf(stdout, " -- !! Error listing existing AIDs !!\n"); return EXIT_FAILURE; - } - else if(CreateApplication(nfcPnd, aidToCreateList1, 0x0f, 3) || GetApplicationIds(nfcPnd) || - CreateApplication(nfcPnd, aidToCreateList2, 0x0f, 3) || GetApplicationIds(nfcPnd) || - CreateApplication(nfcPnd, aidToCreateList1, 0x0f, 3) || GetApplicationIds(nfcPnd)) { + } else if (CreateApplication(nfcPnd, aidToCreateList1, 0x0f, 3) || GetApplicationIds(nfcPnd) || + CreateApplication(nfcPnd, aidToCreateList2, 0x0f, 3) || GetApplicationIds(nfcPnd) || + CreateApplication(nfcPnd, aidToCreateList1, 0x0f, 3) || GetApplicationIds(nfcPnd)) { fprintf(stdout, " -- !! Error creating new AID !!\n"); return EXIT_FAILURE; - } - else if(SelectApplication(nfcPnd, aidToCreateList1, APPLICATION_AID_LENGTH)) { + } else if (SelectApplication(nfcPnd, aidToCreateList1, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting newly created AID !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES!!\n"); return EXIT_FAILURE; - } - else if(DeleteApplication(nfcPnd, aidToCreateList1)) { + } else if (DeleteApplication(nfcPnd, aidToCreateList1)) { fprintf(stdout, " -- !! Error deleting newly created AID !!\n"); return EXIT_FAILURE; - } - else if(GetApplicationIds(nfcPnd)) { + } else if (GetApplicationIds(nfcPnd)) { fprintf(stdout, " -- !! Error listing existing AIDs !!\n"); return EXIT_FAILURE; - } - else if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + } else if (SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting PICC app !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES!!\n"); return EXIT_FAILURE; - } - else if(DeleteApplication(nfcPnd, aidToCreateList2)) { + } else if (DeleteApplication(nfcPnd, aidToCreateList2)) { fprintf(stdout, " -- !! Error deleting second new AID !!\n"); return EXIT_FAILURE; - } - else if(GetApplicationIds(nfcPnd)) { + } else if (GetApplicationIds(nfcPnd)) { fprintf(stdout, " -- !! Error listing existing AIDs !!\n"); return EXIT_FAILURE; - } - else if(DeleteApplication(nfcPnd, MASTER_APPLICATION_AID)) { + } else if (DeleteApplication(nfcPnd, MASTER_APPLICATION_AID)) { fprintf(stdout, " -- !! Error trying to verify no success at deleting PICC app !!\n"); - } - else if(GetApplicationIds(nfcPnd)) { + } else if (GetApplicationIds(nfcPnd)) { fprintf(stdout, " -- !! Error listing existing AIDs !!\n"); return EXIT_FAILURE; - } - else if(GetDFNamesCommand(nfcPnd)) { + } else if (GetDFNamesCommand(nfcPnd)) { fprintf(stdout, " -- !! Error listing DF names !!\n"); return EXIT_FAILURE; } diff --git a/Software/DESFireLibNFCTesting/Source/TestAuthenticateAES128.c b/Software/DESFireLibNFCTesting/Source/TestAuthenticateAES128.c index f2b843ec..1da9cb54 100644 --- a/Software/DESFireLibNFCTesting/Source/TestAuthenticateAES128.c +++ b/Software/DESFireLibNFCTesting/Source/TestAuthenticateAES128.c @@ -11,31 +11,37 @@ int main(int argc, char **argv) { - if(!TestAESEncyptionRoutines()) { + if (!TestAESEncyptionRoutines()) { return EXIT_FAILURE; } nfc_context *nfcCtxt; nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); - if(nfcPnd == NULL) { - return EXIT_FAILURE; + if (nfcPnd == NULL) { + return EXIT_FAILURE; } // Select AID application 0x000000: - if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + if (SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { return EXIT_FAILURE; } // Get list of application IDs: - if(GetApplicationIds(nfcPnd)) { + if (GetApplicationIds(nfcPnd)) { + return EXIT_FAILURE; + } + + // First, authenticate with the legacy command (PICC master key): + if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_LEGACY, + MASTER_KEY_INDEX, ZERO_KEY)) { return EXIT_FAILURE; } // Start AES authentication (default key, blank setting of all zeros): - if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { return EXIT_FAILURE; - } + } FreeNFCDeviceDriver(&nfcCtxt, &nfcPnd); return EXIT_SUCCESS; diff --git a/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c b/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c index c843235d..1f6243e0 100644 --- a/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c +++ b/Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c @@ -7,30 +7,37 @@ int main(int argc, char **argv) { - if(!Test3DESEncyptionRoutines()) { + if (!Test3DESEncyptionRoutines()) { return EXIT_FAILURE; } nfc_context *nfcCtxt; nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); - if(nfcPnd == NULL) { + if (nfcPnd == NULL) { return EXIT_FAILURE; } // Select AID application 0x000000: - if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + if (SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { return EXIT_FAILURE; } // Get list of application IDs: - if(GetApplicationIds(nfcPnd)) { + if (GetApplicationIds(nfcPnd)) { return EXIT_FAILURE; } + + // First, authenticate with the legacy command (PICC master key): + if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_LEGACY, + MASTER_KEY_INDEX, ZERO_KEY)) { + return EXIT_FAILURE; + } + // Start ISO authentication (default key, blank setting of all zeros): - if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_ISODES, - MASTER_KEY_INDEX, ZERO_KEY)) { + if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_ISODES, + MASTER_KEY_INDEX, ZERO_KEY)) { return EXIT_FAILURE; - } + } FreeNFCDeviceDriver(&nfcCtxt, &nfcPnd); return EXIT_SUCCESS; diff --git a/Software/DESFireLibNFCTesting/Source/TestAuthenticateLegacy.c b/Software/DESFireLibNFCTesting/Source/TestAuthenticateLegacy.c index 04a2b910..0667bc93 100644 --- a/Software/DESFireLibNFCTesting/Source/TestAuthenticateLegacy.c +++ b/Software/DESFireLibNFCTesting/Source/TestAuthenticateLegacy.c @@ -7,30 +7,30 @@ int main(int argc, char **argv) { - if(!Test3DESEncyptionRoutines()) { + if (!Test3DESEncyptionRoutines()) { return EXIT_FAILURE; } nfc_context *nfcCtxt; nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); - if(nfcPnd == NULL) { + if (nfcPnd == NULL) { return EXIT_FAILURE; } // Select AID application 0x000000: - if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + if (SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { return EXIT_FAILURE; } // Get list of application IDs: - if(GetApplicationIds(nfcPnd)) { + if (GetApplicationIds(nfcPnd)) { return EXIT_FAILURE; } // Start ISO authentication (default key, blank setting of all zeros): - if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_LEGACY, - MASTER_KEY_INDEX, ZERO_KEY)) { + if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_LEGACY, + MASTER_KEY_INDEX, ZERO_KEY)) { return EXIT_FAILURE; - } + } FreeNFCDeviceDriver(&nfcCtxt, &nfcPnd); return EXIT_SUCCESS; diff --git a/Software/DESFireLibNFCTesting/Source/TestDataManipulationCommandsSupport.c b/Software/DESFireLibNFCTesting/Source/TestDataManipulationCommandsSupport.c index 2df4be20..1bc9cc41 100644 --- a/Software/DESFireLibNFCTesting/Source/TestDataManipulationCommandsSupport.c +++ b/Software/DESFireLibNFCTesting/Source/TestDataManipulationCommandsSupport.c @@ -14,84 +14,70 @@ int main(int argc, char **argv) { nfc_context *nfcCtxt; nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); - if(nfcPnd == NULL) { - return EXIT_FAILURE; - } + if (nfcPnd == NULL) { + return EXIT_FAILURE; + } - if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + if (SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting new AID by default !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES !!\n"); return EXIT_FAILURE; } uint8_t aidToCreate[] = { 0x01, 0x00, 0x34 }; - if(CreateApplication(nfcPnd, aidToCreate, 0x0f, 0x03)) { + if (CreateApplication(nfcPnd, aidToCreate, 0x0f, 0x03)) { fprintf(stdout, " -- !! Error creating new AID !!\n"); return EXIT_FAILURE; - } - else if(SelectApplication(nfcPnd, aidToCreate, APPLICATION_AID_LENGTH)) { + } else if (SelectApplication(nfcPnd, aidToCreate, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting new AID by default !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES !!\n"); return EXIT_FAILURE; - } + } uint8_t srcDataBuffer[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; - if(CreateStandardDataFile(nfcPnd, 0x00, 0x00, 0x0f, 4)) { + if (CreateStandardDataFile(nfcPnd, 0x00, 0x00, 0x0f, 4)) { fprintf(stdout, " -- !! Error creating standard data file !!\n"); return EXIT_FAILURE; - } - else if(CreateBackupDataFile(nfcPnd, 0x01, 0x00, 0x0f, 8)) { + } else if (CreateBackupDataFile(nfcPnd, 0x01, 0x00, 0x0f, 8)) { fprintf(stdout, " -- !! Error creating backup data file !!\n"); return EXIT_FAILURE; - } - else if(GetFileIds(nfcPnd)) { + } else if (GetFileIds(nfcPnd)) { fprintf(stdout, " -- !! Error listing the file IDs !!\n"); return EXIT_FAILURE; - } - else if(ReadDataCommand(nfcPnd, 0x00, 0, 4)) { + } else if (ReadDataCommand(nfcPnd, 0x00, 0, 4)) { fprintf(stdout, " -- !! Error reading initial contents of file !!\n"); return EXIT_FAILURE; - } - else if(DeleteFile(nfcPnd, 0x01)) { + } else if (DeleteFile(nfcPnd, 0x01)) { fprintf(stdout, " -- !! Error deleting newly created file !!\n"); return EXIT_FAILURE; - } - else if(GetFileIds(nfcPnd)) { + } else if (GetFileIds(nfcPnd)) { fprintf(stdout, " -- !! Error listing the file IDs !!\n"); return EXIT_FAILURE; - } - else if(ReadDataCommand(nfcPnd, 0x00, 0, 4)) { + } else if (ReadDataCommand(nfcPnd, 0x00, 0, 4)) { fprintf(stdout, " -- !! Error reading initial contents of file !!\n"); return EXIT_FAILURE; - } - else if(ReadDataCommand(nfcPnd, 0x00, 2, 2)) { + } else if (ReadDataCommand(nfcPnd, 0x00, 2, 2)) { fprintf(stdout, " -- !! Error reading initial contents of file !!\n"); return EXIT_FAILURE; - } - else if(WriteDataCommand(nfcPnd, 0x00, 0, 4, srcDataBuffer)) { + } else if (WriteDataCommand(nfcPnd, 0x00, 0, 4, srcDataBuffer)) { fprintf(stdout, " -- !! Error write data command !!\n"); return EXIT_FAILURE; - } - else if(ReadDataCommand(nfcPnd, 0x00, 0, 4)) { + } else if (ReadDataCommand(nfcPnd, 0x00, 0, 4)) { fprintf(stdout, " -- !! Error reading initial contents of file !!\n"); return EXIT_FAILURE; - } - else if(WriteDataCommand(nfcPnd, 0x00, 2, 2, srcDataBuffer + 12)) { + } else if (WriteDataCommand(nfcPnd, 0x00, 2, 2, srcDataBuffer + 12)) { fprintf(stdout, " -- !! Error write data command !!\n"); return EXIT_FAILURE; - } - else if(ReadDataCommand(nfcPnd, 0x00, 0, 4)) { + } else if (ReadDataCommand(nfcPnd, 0x00, 0, 4)) { fprintf(stdout, " -- !! Error reading initial contents of file !!\n"); return EXIT_FAILURE; } diff --git a/Software/DESFireLibNFCTesting/Source/TestDataManipulationCommandsSupport2.c b/Software/DESFireLibNFCTesting/Source/TestDataManipulationCommandsSupport2.c index 340c208e..86e0df4b 100644 --- a/Software/DESFireLibNFCTesting/Source/TestDataManipulationCommandsSupport2.c +++ b/Software/DESFireLibNFCTesting/Source/TestDataManipulationCommandsSupport2.c @@ -14,127 +14,103 @@ int main(int argc, char **argv) { nfc_context *nfcCtxt; nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); - if(nfcPnd == NULL) { - return EXIT_FAILURE; - } + if (nfcPnd == NULL) { + return EXIT_FAILURE; + } - if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + if (SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting new AID by default !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES !!\n"); return EXIT_FAILURE; } uint8_t aidToCreate[] = { 0xf3, 0x12, 0x34 }; - if(CreateApplication(nfcPnd, aidToCreate, 0x0f, 0x03)) { + if (CreateApplication(nfcPnd, aidToCreate, 0x0f, 0x03)) { fprintf(stdout, " -- !! Error creating new AID !!\n"); return EXIT_FAILURE; - } - else if(SelectApplication(nfcPnd, aidToCreate, APPLICATION_AID_LENGTH)) { + } else if (SelectApplication(nfcPnd, aidToCreate, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting new AID by default !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES !!\n"); return EXIT_FAILURE; - } + } - if(CreateValueFile(nfcPnd, 0x02, 0x00, 0x0f, 0, 256, 128, 0x01)) { + if (CreateValueFile(nfcPnd, 0x02, 0x00, 0x0f, 0, 256, 128, 0x01)) { fprintf(stdout, " -- !! Error creating value file !!\n"); return EXIT_FAILURE; - } - else if(GetFileIds(nfcPnd)) { + } else if (GetFileIds(nfcPnd)) { fprintf(stdout, " -- !! Error listing the file IDs !!\n"); return EXIT_FAILURE; - } - else if(GetValueCommand(nfcPnd, 0x02)) { + } else if (GetValueCommand(nfcPnd, 0x02)) { fprintf(stdout, " -- !! Error fetching value from file !!\n"); return EXIT_FAILURE; - } - else if(CreditValueFileCommand(nfcPnd, 0x02, 64)) { + } else if (CreditValueFileCommand(nfcPnd, 0x02, 64)) { fprintf(stdout, " -- !! Error crediting value file !!\n"); return EXIT_FAILURE; - } - else if(GetValueCommand(nfcPnd, 0x02)) { + } else if (GetValueCommand(nfcPnd, 0x02)) { fprintf(stdout, " -- !! Error fetching value from file !!\n"); return EXIT_FAILURE; - } - else if(DebitValueFileCommand(nfcPnd, 0x02, 64)) { + } else if (DebitValueFileCommand(nfcPnd, 0x02, 64)) { fprintf(stdout, " -- !! Error debiting value file !!\n"); return EXIT_FAILURE; - } - else if(GetValueCommand(nfcPnd, 0x02)) { + } else if (GetValueCommand(nfcPnd, 0x02)) { fprintf(stdout, " -- !! Error fetching value from file !!\n"); return EXIT_FAILURE; - } - else if(LimitedCreditValueFileCommand(nfcPnd, 0x02, 32)) { + } else if (LimitedCreditValueFileCommand(nfcPnd, 0x02, 32)) { fprintf(stdout, " -- !! Error applying limited credit !!\n"); return EXIT_FAILURE; - } - else if(GetValueCommand(nfcPnd, 0x02)) { + } else if (GetValueCommand(nfcPnd, 0x02)) { fprintf(stdout, " -- !! Error fetching value from file !!\n"); return EXIT_FAILURE; - } - else if(CommitTransaction(nfcPnd)) { + } else if (CommitTransaction(nfcPnd)) { fprintf(stdout, " -- !! Error committing transaction !!\n"); return EXIT_FAILURE; - } - else if(GetValueCommand(nfcPnd, 0x02)) { + } else if (GetValueCommand(nfcPnd, 0x02)) { fprintf(stdout, " -- !! Error fetching value from file !!\n"); return EXIT_FAILURE; - } - else if(DebitValueFileCommand(nfcPnd, 0x02, 200) || - CommitTransaction(nfcPnd) || - GetValueCommand(nfcPnd, 0x02)) { + } else if (DebitValueFileCommand(nfcPnd, 0x02, 200) || + CommitTransaction(nfcPnd) || + GetValueCommand(nfcPnd, 0x02)) { fprintf(stdout, " -- !! Error trying to remove more than available !!\n"); return EXIT_FAILURE; } - - if(CreateValueFile(nfcPnd, 0x03, 0x00, 0x0f, 0, 256, 128, 0x00)) { + + if (CreateValueFile(nfcPnd, 0x03, 0x00, 0x0f, 0, 256, 128, 0x00)) { fprintf(stdout, " -- !! Error creating value file !!\n"); return EXIT_FAILURE; - } - else if(GetFileIds(nfcPnd)) { + } else if (GetFileIds(nfcPnd)) { fprintf(stdout, " -- !! Error listing the file IDs !!\n"); return EXIT_FAILURE; - } - else if(GetValueCommand(nfcPnd, 0x03)) { + } else if (GetValueCommand(nfcPnd, 0x03)) { fprintf(stdout, " -- !! Error fetching value from file !!\n"); return EXIT_FAILURE; - } - else if(CreditValueFileCommand(nfcPnd, 0x03, 64)) { + } else if (CreditValueFileCommand(nfcPnd, 0x03, 64)) { fprintf(stdout, " -- !! Error crediting value file !!\n"); return EXIT_FAILURE; - } - else if(GetValueCommand(nfcPnd, 0x03)) { + } else if (GetValueCommand(nfcPnd, 0x03)) { fprintf(stdout, " -- !! Error fetching value from file !!\n"); return EXIT_FAILURE; - } - else if(DebitValueFileCommand(nfcPnd, 0x03, 64)) { + } else if (DebitValueFileCommand(nfcPnd, 0x03, 64)) { fprintf(stdout, " -- !! Error debiting value file !!\n"); return EXIT_FAILURE; - } - else if(GetValueCommand(nfcPnd, 0x03)) { + } else if (GetValueCommand(nfcPnd, 0x03)) { fprintf(stdout, " -- !! Error fetching value from file !!\n"); return EXIT_FAILURE; - } - else if(LimitedCreditValueFileCommand(nfcPnd, 0x03, 32)) { + } else if (LimitedCreditValueFileCommand(nfcPnd, 0x03, 32)) { fprintf(stdout, " -- !! Error applying limited credit !!\n"); return EXIT_FAILURE; - } - else if(GetValueCommand(nfcPnd, 0x03)) { + } else if (GetValueCommand(nfcPnd, 0x03)) { fprintf(stdout, " -- !! Error fetching value from file !!\n"); return EXIT_FAILURE; - } - else if(AbortTransaction(nfcPnd)) { + } else if (AbortTransaction(nfcPnd)) { fprintf(stdout, " -- !! Error committing transaction !!\n"); return EXIT_FAILURE; - } - else if(GetValueCommand(nfcPnd, 0x03)) { + } else if (GetValueCommand(nfcPnd, 0x03)) { fprintf(stdout, " -- !! Error fetching value from file !!\n"); return EXIT_FAILURE; } diff --git a/Software/DESFireLibNFCTesting/Source/TestDataManipulationCommandsSupport3.c b/Software/DESFireLibNFCTesting/Source/TestDataManipulationCommandsSupport3.c index 8063b9d8..233c1d6f 100644 --- a/Software/DESFireLibNFCTesting/Source/TestDataManipulationCommandsSupport3.c +++ b/Software/DESFireLibNFCTesting/Source/TestDataManipulationCommandsSupport3.c @@ -14,41 +14,38 @@ int main(int argc, char **argv) { nfc_context *nfcCtxt; nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); - if(nfcPnd == NULL) { - return EXIT_FAILURE; - } + if (nfcPnd == NULL) { + return EXIT_FAILURE; + } - if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + if (SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting new AID by default !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES !!\n"); return EXIT_FAILURE; } - + uint8_t aidToCreate[] = { 0xf4, 0xa5, 0x34 }; - if(CreateApplication(nfcPnd, aidToCreate, 0x0f, 0x03)) { + if (CreateApplication(nfcPnd, aidToCreate, 0x0f, 0x03)) { fprintf(stdout, " -- !! Error creating new AID !!\n"); return EXIT_FAILURE; - } - else if(SelectApplication(nfcPnd, aidToCreate, APPLICATION_AID_LENGTH)) { + } else if (SelectApplication(nfcPnd, aidToCreate, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting new AID by default !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES !!\n"); return EXIT_FAILURE; - } + } uint8_t dataBuf[16]; memset(dataBuf, 0x00, 16); uint8_t dataBufLarge[84]; memset(dataBufLarge, 0x00, 84); - if(CreateLinearRecordFile(nfcPnd, 0x01, 0x00, 0x0f, 2, 6)) { + if (CreateLinearRecordFile(nfcPnd, 0x01, 0x00, 0x0f, 2, 6)) { fprintf(stdout, " -- !! Error creating linear record file !!\n"); return EXIT_FAILURE; } @@ -56,19 +53,16 @@ int main(int argc, char **argv) { // fprintf(stdout, " -- !! Error creating cyclic record file !!\n"); // return EXIT_FAILURE; //} - else if(GetFileIds(nfcPnd)) { + else if (GetFileIds(nfcPnd)) { fprintf(stdout, " -- !! Error listing file IDs !!\n"); return EXIT_FAILURE; - } - else if(ReadRecordsCommand(nfcPnd, 0x01, 0, 6)) { + } else if (ReadRecordsCommand(nfcPnd, 0x01, 0, 6)) { fprintf(stdout, " -- !! Error reading records !!\n"); return EXIT_FAILURE; - } - else if(WriteRecordsCommand(nfcPnd, 0x01, 0, 3, dataBuf)) { + } else if (WriteRecordsCommand(nfcPnd, 0x01, 0, 3, dataBuf)) { fprintf(stdout, " -- !! Error writing records !!\n"); return EXIT_FAILURE; - } - else if(ReadRecordsCommand(nfcPnd, 0x01, 0, 6)) { + } else if (ReadRecordsCommand(nfcPnd, 0x01, 0, 6)) { fprintf(stdout, " -- !! Error reading records !!\n"); return EXIT_FAILURE; } @@ -80,7 +74,7 @@ int main(int argc, char **argv) { fprintf(stdout, " -- !! Error reading large records !!\n"); return EXIT_FAILURE; }*/ - // TODO: Still need to test the ClearRecordFile command ... + // TODO: Still need to test the ClearRecordFile command ... FreeNFCDeviceDriver(&nfcCtxt, &nfcPnd); return EXIT_SUCCESS; diff --git a/Software/DESFireLibNFCTesting/Source/TestFileManagementCommandsSupport.c b/Software/DESFireLibNFCTesting/Source/TestFileManagementCommandsSupport.c index 653bc557..d79570c6 100644 --- a/Software/DESFireLibNFCTesting/Source/TestFileManagementCommandsSupport.c +++ b/Software/DESFireLibNFCTesting/Source/TestFileManagementCommandsSupport.c @@ -14,71 +14,60 @@ int main(int argc, char **argv) { nfc_context *nfcCtxt; nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); - if(nfcPnd == NULL) { - return EXIT_FAILURE; - } + if (nfcPnd == NULL) { + return EXIT_FAILURE; + } - if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + if (SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting new AID by default !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES !!\n"); return EXIT_FAILURE; } - + uint8_t aidToCreate[] = { 0x01, 0x00, 0x34 }; - if(CreateApplication(nfcPnd, aidToCreate, 0x0f, 0x03)) { + if (CreateApplication(nfcPnd, aidToCreate, 0x0f, 0x03)) { fprintf(stdout, " -- !! Error creating new AID !!\n"); return EXIT_FAILURE; - } - else if(SelectApplication(nfcPnd, aidToCreate, APPLICATION_AID_LENGTH)) { + } else if (SelectApplication(nfcPnd, aidToCreate, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting new AID by default !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES !!\n"); return EXIT_FAILURE; - } + } - if(CreateStandardDataFile(nfcPnd, 0x00, 0x00, 0x0f, 4)) { + if (CreateStandardDataFile(nfcPnd, 0x00, 0x00, 0x0f, 4)) { fprintf(stdout, " -- !! Error creating standard data file !!\n"); return EXIT_FAILURE; - } - else if(CreateBackupDataFile(nfcPnd, 0x01, 0x00, 0x0f, 8)) { + } else if (CreateBackupDataFile(nfcPnd, 0x01, 0x00, 0x0f, 8)) { fprintf(stdout, " -- !! Error creating backup data file !!\n"); return EXIT_FAILURE; - } - else if(CreateValueFile(nfcPnd, 0x02, 0x00, 0x0f, 0, 256, 128, 0x01)) { + } else if (CreateValueFile(nfcPnd, 0x02, 0x00, 0x0f, 0, 256, 128, 0x01)) { fprintf(stdout, " -- !! Error creating value file !!\n"); return EXIT_FAILURE; - } - else if(CreateLinearRecordFile(nfcPnd, 0x03, 0x00, 0x0f, 4, 12)) { + } else if (CreateLinearRecordFile(nfcPnd, 0x03, 0x00, 0x0f, 4, 12)) { fprintf(stdout, " -- !! Error creating linear record file !!\n"); return EXIT_FAILURE; - } - else if(CreateCyclicRecordFile(nfcPnd, 0x04, 0x00, 0x0f, 1, 5)) { + } else if (CreateCyclicRecordFile(nfcPnd, 0x04, 0x00, 0x0f, 1, 5)) { fprintf(stdout, " -- !! Error creating cyclic record file !!\n"); return EXIT_FAILURE; - } - else if(GetFileIds(nfcPnd)) { + } else if (GetFileIds(nfcPnd)) { fprintf(stdout, " -- !! Error listing the file IDs !!\n"); return EXIT_FAILURE; - } - else if(DeleteFile(nfcPnd, 0x01)) { + } else if (DeleteFile(nfcPnd, 0x01)) { fprintf(stdout, " -- !! Error deleting newly created file !!\n"); return EXIT_FAILURE; - } - else if(GetFileIds(nfcPnd)) { + } else if (GetFileIds(nfcPnd)) { fprintf(stdout, " -- !! Error listing the file IDs !!\n"); return EXIT_FAILURE; - } - else if(GetFileSettings(nfcPnd, 0x00) || - GetFileSettings(nfcPnd, 0x02) || - GetFileSettings(nfcPnd, 0x03) || - GetFileSettings(nfcPnd, 0x04)) { + } else if (GetFileSettings(nfcPnd, 0x00) || + GetFileSettings(nfcPnd, 0x02) || + GetFileSettings(nfcPnd, 0x03) || + GetFileSettings(nfcPnd, 0x04)) { fprintf(stdout, " -- !! Error retrieving file settings !!\n"); return EXIT_FAILURE; } diff --git a/Software/DESFireLibNFCTesting/Source/TestGeneralCommands.c b/Software/DESFireLibNFCTesting/Source/TestGeneralCommands.c index 1cac3099..5f929c2c 100644 --- a/Software/DESFireLibNFCTesting/Source/TestGeneralCommands.c +++ b/Software/DESFireLibNFCTesting/Source/TestGeneralCommands.c @@ -14,37 +14,32 @@ int main(int argc, char **argv) { nfc_context *nfcCtxt; nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); - if(nfcPnd == NULL) { - return EXIT_FAILURE; - } + if (nfcPnd == NULL) { + return EXIT_FAILURE; + } - if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + if (SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting PICC (Master) AID by default !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES !!\n"); return EXIT_FAILURE; } - if(GetVersionCommand(nfcPnd)) { + if (GetVersionCommand(nfcPnd)) { fprintf(stdout, " -- !! GetVersion failed !!\n"); return EXIT_FAILURE; - } - else if(FormatPiccCommand(nfcPnd)) { + } else if (FormatPiccCommand(nfcPnd)) { fprintf(stdout, " -- !! FormatPICC failed !!\n"); return EXIT_FAILURE; - } - else if(GetCardUIDCommand(nfcPnd)) { + } else if (GetCardUIDCommand(nfcPnd)) { fprintf(stdout, " -- !! GetCardUID failed !!\n"); return EXIT_FAILURE; - } - else if(SetConfigurationCommand(nfcPnd)) { + } else if (SetConfigurationCommand(nfcPnd)) { fprintf(stdout, " -- !! SetConfiguration failed !!\n"); return EXIT_FAILURE; - } - else if(FreeMemoryCommand(nfcPnd)) { + } else if (FreeMemoryCommand(nfcPnd)) { fprintf(stdout, " -- !! FreeMemory failed !!\n"); return EXIT_FAILURE; } diff --git a/Software/DESFireLibNFCTesting/Source/TestKeyManagementCommands.c b/Software/DESFireLibNFCTesting/Source/TestKeyManagementCommands.c index 66575252..b5b00a74 100644 --- a/Software/DESFireLibNFCTesting/Source/TestKeyManagementCommands.c +++ b/Software/DESFireLibNFCTesting/Source/TestKeyManagementCommands.c @@ -14,44 +14,40 @@ int main(int argc, char **argv) { nfc_context *nfcCtxt; nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); - if(nfcPnd == NULL) { - return EXIT_FAILURE; - } + if (nfcPnd == NULL) { + return EXIT_FAILURE; + } - if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + if (SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting PICC (Master) AID by default !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES !!\n"); return EXIT_FAILURE; } - if(ChangeKeyCommand(nfcPnd, 0x00, ZERO_KEY, DESFIRE_CRYPTO_AUTHTYPE_AES128)) { + if (ChangeKeyCommand(nfcPnd, 0x00, ZERO_KEY, DESFIRE_CRYPTO_AUTHTYPE_AES128)) { fprintf(stdout, " -- !! GetVersion failed !!\n"); return EXIT_FAILURE; } - - if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { + + if (SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) { fprintf(stdout, " -- !! Error selecting PICC (Master) AID by default !!\n"); return EXIT_FAILURE; - } - else if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, - MASTER_KEY_INDEX, ZERO_KEY)) { + } else if (Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_AES128, + MASTER_KEY_INDEX, ZERO_KEY)) { fprintf(stdout, " -- !! Error authenticating with AES !!\n"); return EXIT_FAILURE; } - - if(GetKeySettingsCommand(nfcPnd)) { + + if (GetKeySettingsCommand(nfcPnd)) { fprintf(stdout, " -- !! GetKeySettings failed !!\n"); return EXIT_FAILURE; - } - else if(ChangeKeySettingsCommand(nfcPnd, 0x0f)) { + } else if (ChangeKeySettingsCommand(nfcPnd, 0x0f)) { fprintf(stdout, " -- !! ChangeKeySettings failed !!\n"); return EXIT_FAILURE; - } - else if(GetKeyVersionCommand(nfcPnd, 0x00)) { + } else if (GetKeyVersionCommand(nfcPnd, 0x00)) { fprintf(stdout, " -- !! GetKeyVersion failed !!\n"); return EXIT_FAILURE; } From bcf68d068763ff6914632d1b7fc50eabcae45a13 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 00:27:24 -0500 Subject: [PATCH 14/68] Last minute modifications to DES/3DES enc/dec routines for data that is not a multiple of the resp. block size --- .../Chameleon-Mini/Application/CryptoTDEA.c | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c index 11314ec2..f309a74c 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c @@ -14,6 +14,7 @@ void EncryptDESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, c .blockSize = CRYPTO_DES_BLOCK_SIZE }; uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; + bool dataNeedsPadding = (Count % CryptoSpec.blockSize) != 0; uint16_t blockIndex = 0; uint8_t *ctBuf = (uint8_t *) Ciphertext; uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE]; @@ -25,8 +26,13 @@ void EncryptDESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, c } while (blockIndex < numBlocks) { if (blockIndex == 0) { + memset(inputBlock, 0x00, CRYPTO_DES_BLOCK_SIZE); memcpy(inputBlock, &Plaintext[0], CRYPTO_DES_BLOCK_SIZE); CryptoMemoryXOR(IV, inputBlock, CRYPTO_DES_BLOCK_SIZE); + } else if (dataNeedsPadding && blockIndex + 1 == numBlocks) { + memset(inputBlock, 0x00, CRYPTO_DES_BLOCK_SIZE); + memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], Count % CryptoSpec.blockSize); + CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_DES_BLOCK_SIZE], inputBlock, CRYPTO_DES_BLOCK_SIZE); } else { memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_DES_BLOCK_SIZE], inputBlock, CRYPTO_DES_BLOCK_SIZE); @@ -43,6 +49,7 @@ void DecryptDESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, c .blockSize = CRYPTO_DES_BLOCK_SIZE }; uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; + bool dataNeedsPadding = (Count % CryptoSpec.blockSize) != 0; uint16_t blockIndex = 0; uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE]; uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; @@ -53,9 +60,16 @@ void DecryptDESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, c } while (blockIndex < numBlocks) { CryptoSpec.cryptFunc(inputBlock, Ciphertext + blockIndex * CRYPTO_DES_BLOCK_SIZE, Keys); - if (blockIndex == 0) { + if (blockIndex == 0 && !dataNeedsPadding) { memcpy(Plaintext, inputBlock, CRYPTO_DES_BLOCK_SIZE); CryptoMemoryXOR(IV, Plaintext, CRYPTO_DES_BLOCK_SIZE); + } else if (blockIndex == 0 && dataNeedsPadding && numBlocks == 0x01) { + memcpy(Plaintext, inputBlock, Count % CryptoSpec.blockSize); + CryptoMemoryXOR(IV, Plaintext, Count % CryptoSpec.blockSize); + } else if (dataNeedsPadding && blockIndex + 1 == numBlocks) { + memcpy(Plaintext + blockIndex * CRYPTO_DES_BLOCK_SIZE, inputBlock, Count % CryptoSpec.blockSize); + CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], + Plaintext + blockIndex * CRYPTO_DES_BLOCK_SIZE, Count % CryptoSpec.blockSize); } else { memcpy(Plaintext + blockIndex * CRYPTO_DES_BLOCK_SIZE, inputBlock, CRYPTO_DES_BLOCK_SIZE); CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], @@ -71,6 +85,7 @@ void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, .blockSize = CRYPTO_3KTDEA_BLOCK_SIZE }; uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; + bool dataNeedsPadding = (Count % CryptoSpec.blockSize) != 0; uint8_t *ctBuf = (uint8_t *) Ciphertext; uint16_t blockIndex = 0; uint8_t inputBlock[CRYPTO_3KTDEA_BLOCK_SIZE]; @@ -82,8 +97,13 @@ void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, } while (blockIndex < numBlocks) { if (blockIndex == 0) { + memset(inputBlock, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); memcpy(inputBlock, &Plaintext[0], CRYPTO_3KTDEA_BLOCK_SIZE); CryptoMemoryXOR(IV, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); + } else if (dataNeedsPadding && blockIndex + 1 == numBlocks) { + memset(inputBlock, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); + memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], Count % CryptoSpec.blockSize); + CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE], inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); } else { memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], CRYPTO_3KTDEA_BLOCK_SIZE); CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE], inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); @@ -100,6 +120,7 @@ void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, .blockSize = CRYPTO_3KTDEA_BLOCK_SIZE }; uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; + bool dataNeedsPadding = (Count % CryptoSpec.blockSize) != 0; uint16_t blockIndex = 0; uint8_t inputBlock[CRYPTO_3KTDEA_BLOCK_SIZE]; uint8_t IV[CRYPTO_3KTDEA_BLOCK_SIZE]; @@ -110,9 +131,16 @@ void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, } while (blockIndex < numBlocks) { CryptoSpec.cryptFunc(inputBlock, Ciphertext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, Keys); - if (blockIndex == 0) { + if (blockIndex == 0 && !dataNeedsPadding) { memcpy(Plaintext, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); CryptoMemoryXOR(IV, Plaintext, CRYPTO_3KTDEA_BLOCK_SIZE); + } else if (blockIndex == 0 && dataNeedsPadding && numBlocks == 0x01) { + memcpy(Plaintext, inputBlock, Count % CryptoSpec.blockSize); + CryptoMemoryXOR(IV, Plaintext, Count % CryptoSpec.blockSize); + } else if (dataNeedsPadding && blockIndex + 1 == numBlocks) { + memcpy(Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, inputBlock, Count % CryptoSpec.blockSize); + CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], + Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, Count % CryptoSpec.blockSize); } else { memcpy(Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], From 1644a9e0aeaaedba0e169215f152ee0b37a80b7f Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 00:40:13 -0500 Subject: [PATCH 15/68] Making sure the auth AES and auth ISO handlers keep the chain of prior legacy auths intact --- .../Application/DESFire/DESFireInstructions.c | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 4f0ba6f5..1c407bb1 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -1813,19 +1813,22 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { return DESFIRE_STATUS_RESPONSE_SIZE; } - /* Authenticated successfully */ - Authenticated = 0x01; - AuthenticatedWithKey = KeyId; - AuthenticatedWithPICCMasterKey = (SelectedApp.Slot == DESFIRE_PICC_APP_SLOT) && - (KeyId == DESFIRE_MASTER_KEY_ID); - /* Encrypt and send back the once rotated RndA buffer to the PCD */ RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, Key); + /* Create the session key based on the previous exchange */ generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_3K3DES); + /* Now that we have auth'ed with the legacy command, a ChangeKey command will + * allow for subsequent authentication with the ISO or AES routines + */ + Authenticated = true; + AuthenticatedWithKey = KeyId; + AuthenticatedWithPICCMasterKey = (SelectedApp.Slot == DESFIRE_PICC_APP_SLOT) && + (KeyId == DESFIRE_MASTER_KEY_ID); + /* Return the status on success */ Buffer[0] = STATUS_OPERATION_OK; return DESFIRE_STATUS_RESPONSE_SIZE + CRYPTO_CHALLENGE_RESPONSE_BYTES; @@ -1968,20 +1971,23 @@ uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount) { return DESFIRE_STATUS_RESPONSE_SIZE; } - /* Authenticated successfully */ - Authenticated = 0x01; - AuthenticatedWithKey = KeyId; - AuthenticatedWithPICCMasterKey = (SelectedApp.Slot == DESFIRE_PICC_APP_SLOT) && - (KeyId == DESFIRE_MASTER_KEY_ID); - /* Encrypt and send back the once rotated RndA buffer to the PCD */ memset(challengeRndAB, 0x00, CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(challengeRndAB, challengeRndA, CRYPTO_CHALLENGE_RESPONSE_BYTES); RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); CryptoAESEncryptBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, Key); + /* Create the session key based on the previous exchange */ generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_AES128); + /* Now that we have auth'ed with the legacy command, a ChangeKey command will + * allow for subsequent authentication with the ISO or AES routines + */ + Authenticated = true; + AuthenticatedWithKey = KeyId; + AuthenticatedWithPICCMasterKey = (SelectedApp.Slot == DESFIRE_PICC_APP_SLOT) && + (KeyId == DESFIRE_MASTER_KEY_ID); + /* Return the status on success */ Buffer[0] = STATUS_OPERATION_OK; return DESFIRE_STATUS_RESPONSE_SIZE + CRYPTO_CHALLENGE_RESPONSE_BYTES; From 20a6960fcad7e00e95e152396e8fb4e6fd6be59b Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 04:41:40 -0500 Subject: [PATCH 16/68] Fixing legacy auth algorithm from 3K3DES -> 2K3DES (cf. #313) --- .../Chameleon-Mini/Application/CryptoTDEA.c | 171 ++++++++---------- .../Chameleon-Mini/Application/CryptoTDEA.h | 3 + .../DESFire/DESFireFirmwareSettings.h | 10 +- .../Application/DESFire/DESFireInstructions.c | 32 ++-- .../DESFire/DESFirePICCHeaderLayout.h | 2 +- .../LocalInclude/CryptoUtils.h | 37 +++- .../LocalInclude/DesfireUtils.h | 8 +- .../Source/TestAuthenticateLegacy.c | 4 - 8 files changed, 140 insertions(+), 127 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c index f309a74c..78145671 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c @@ -8,110 +8,109 @@ #include "CryptoTDEA.h" #include "CryptoAES128.h" -void EncryptDESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { - CryptoTDEA_CBCSpec CryptoSpec = { - .cryptFunc = &CryptoEncryptDEA, - .blockSize = CRYPTO_DES_BLOCK_SIZE - }; - uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; - bool dataNeedsPadding = (Count % CryptoSpec.blockSize) != 0; +static void CryptoEncryptCBCBuffer(CryptoTDEA_CBCSpec *CryptoSpec, uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys); +static void CryptoEncryptCBCBuffer(CryptoTDEA_CBCSpec *CryptoSpec, uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { + uint16_t numBlocks = (Count + CryptoSpec->blockSize - 1) / CryptoSpec->blockSize; + bool dataNeedsPadding = (Count % CryptoSpec->blockSize) != 0; uint16_t blockIndex = 0; uint8_t *ctBuf = (uint8_t *) Ciphertext; - uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE]; - uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + uint8_t inputBlock[CryptoSpec->blockSize]; + uint8_t IV[CryptoSpec->blockSize]; if (IVIn == NULL) { - memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + memset(IV, 0x00, CryptoSpec->blockSize); } else { - memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + memcpy(IV, IVIn, CryptoSpec->blockSize); } while (blockIndex < numBlocks) { if (blockIndex == 0) { - memset(inputBlock, 0x00, CRYPTO_DES_BLOCK_SIZE); - memcpy(inputBlock, &Plaintext[0], CRYPTO_DES_BLOCK_SIZE); - CryptoMemoryXOR(IV, inputBlock, CRYPTO_DES_BLOCK_SIZE); + memset(inputBlock, 0x00, CryptoSpec->blockSize); + memcpy(inputBlock, &Plaintext[0], CryptoSpec->blockSize); + CryptoMemoryXOR(IV, inputBlock, CryptoSpec->blockSize); } else if (dataNeedsPadding && blockIndex + 1 == numBlocks) { - memset(inputBlock, 0x00, CRYPTO_DES_BLOCK_SIZE); - memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], Count % CryptoSpec.blockSize); - CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_DES_BLOCK_SIZE], inputBlock, CRYPTO_DES_BLOCK_SIZE); + memset(inputBlock, 0x00, CryptoSpec->blockSize); + memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CryptoSpec->blockSize], Count % CryptoSpec->blockSize); + CryptoMemoryXOR(&Plaintext[blockIndex * CryptoSpec->blockSize], inputBlock, CryptoSpec->blockSize); } else { - memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); - CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_DES_BLOCK_SIZE], inputBlock, CRYPTO_DES_BLOCK_SIZE); + memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CryptoSpec->blockSize], CryptoSpec->blockSize); + CryptoMemoryXOR(&Plaintext[blockIndex * CryptoSpec->blockSize], inputBlock, CryptoSpec->blockSize); } - CryptoSpec.cryptFunc(inputBlock, ctBuf, Keys); - ctBuf += CryptoSpec.blockSize; + CryptoSpec->cryptFunc(inputBlock, ctBuf, Keys); + ctBuf += CryptoSpec->blockSize; blockIndex++; } } -void DecryptDESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { - CryptoTDEA_CBCSpec CryptoSpec = { - .cryptFunc = &CryptoDecryptDEA, - .blockSize = CRYPTO_DES_BLOCK_SIZE - }; - uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; - bool dataNeedsPadding = (Count % CryptoSpec.blockSize) != 0; +static void CryptoDecryptCBCBuffer(CryptoTDEA_CBCSpec *CryptoSpec, uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys); +static void CryptoDecryptCBCBuffer(CryptoTDEA_CBCSpec *CryptoSpec, uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { + uint16_t numBlocks = (Count + CryptoSpec->blockSize - 1) / CryptoSpec->blockSize; + bool dataNeedsPadding = (Count % CryptoSpec->blockSize) != 0; uint16_t blockIndex = 0; - uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE]; - uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + uint8_t inputBlock[CryptoSpec->blockSize]; + uint8_t IV[CryptoSpec->blockSize]; if (IVIn == NULL) { - memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); + memset(IV, 0x00, CryptoSpec->blockSize); } else { - memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); + memcpy(IV, IVIn, CryptoSpec->blockSize); } while (blockIndex < numBlocks) { - CryptoSpec.cryptFunc(inputBlock, Ciphertext + blockIndex * CRYPTO_DES_BLOCK_SIZE, Keys); + CryptoSpec->cryptFunc(inputBlock, Ciphertext + blockIndex * CryptoSpec->blockSize, Keys); if (blockIndex == 0 && !dataNeedsPadding) { - memcpy(Plaintext, inputBlock, CRYPTO_DES_BLOCK_SIZE); - CryptoMemoryXOR(IV, Plaintext, CRYPTO_DES_BLOCK_SIZE); + memcpy(Plaintext, inputBlock, CryptoSpec->blockSize); + CryptoMemoryXOR(IV, Plaintext, CryptoSpec->blockSize); } else if (blockIndex == 0 && dataNeedsPadding && numBlocks == 0x01) { - memcpy(Plaintext, inputBlock, Count % CryptoSpec.blockSize); - CryptoMemoryXOR(IV, Plaintext, Count % CryptoSpec.blockSize); + memcpy(Plaintext, inputBlock, Count % CryptoSpec->blockSize); + CryptoMemoryXOR(IV, Plaintext, Count % CryptoSpec->blockSize); } else if (dataNeedsPadding && blockIndex + 1 == numBlocks) { - memcpy(Plaintext + blockIndex * CRYPTO_DES_BLOCK_SIZE, inputBlock, Count % CryptoSpec.blockSize); - CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], - Plaintext + blockIndex * CRYPTO_DES_BLOCK_SIZE, Count % CryptoSpec.blockSize); + memcpy(Plaintext + blockIndex * CryptoSpec->blockSize, inputBlock, Count % CryptoSpec->blockSize); + CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CryptoSpec->blockSize], + Plaintext + blockIndex * CryptoSpec->blockSize, Count % CryptoSpec->blockSize); } else { - memcpy(Plaintext + blockIndex * CRYPTO_DES_BLOCK_SIZE, inputBlock, CRYPTO_DES_BLOCK_SIZE); - CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_DES_BLOCK_SIZE], - Plaintext + blockIndex * CRYPTO_DES_BLOCK_SIZE, CRYPTO_DES_BLOCK_SIZE); + memcpy(Plaintext + blockIndex * CryptoSpec->blockSize, inputBlock, CryptoSpec->blockSize); + CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CryptoSpec->blockSize], + Plaintext + blockIndex * CryptoSpec->blockSize, CryptoSpec->blockSize); } blockIndex++; } } +void EncryptDESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { + CryptoTDEA_CBCSpec CryptoSpec = { + .cryptFunc = &CryptoEncryptDEA, + .blockSize = CRYPTO_DES_BLOCK_SIZE + }; + CryptoEncryptCBCBuffer(&CryptoSpec, Count, Plaintext, Ciphertext, IVIn, Keys); +} + +void DecryptDESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { + CryptoTDEA_CBCSpec CryptoSpec = { + .cryptFunc = &CryptoDecryptDEA, + .blockSize = CRYPTO_DES_BLOCK_SIZE + }; + CryptoDecryptCBCBuffer(&CryptoSpec, Count, Plaintext, Ciphertext, IVIn, Keys); +} + +void Encrypt2K3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { + CryptoTDEA_CBCSpec CryptoSpec = { + .cryptFunc = &CryptoEncrypt2KTDEA, + .blockSize = CRYPTO_2KTDEA_BLOCK_SIZE + }; + CryptoEncryptCBCBuffer(&CryptoSpec, Count, Plaintext, Ciphertext, IVIn, Keys); +} + +void Decrypt2K3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { + CryptoTDEA_CBCSpec CryptoSpec = { + .cryptFunc = &CryptoDecrypt2KTDEA, + .blockSize = CRYPTO_2KTDEA_BLOCK_SIZE + }; + CryptoDecryptCBCBuffer(&CryptoSpec, Count, Plaintext, Ciphertext, IVIn, Keys); +} + void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { CryptoTDEA_CBCSpec CryptoSpec = { .cryptFunc = &CryptoEncrypt3KTDEA, .blockSize = CRYPTO_3KTDEA_BLOCK_SIZE }; - uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; - bool dataNeedsPadding = (Count % CryptoSpec.blockSize) != 0; - uint8_t *ctBuf = (uint8_t *) Ciphertext; - uint16_t blockIndex = 0; - uint8_t inputBlock[CRYPTO_3KTDEA_BLOCK_SIZE]; - uint8_t IV[CRYPTO_3KTDEA_BLOCK_SIZE]; - if (IVIn == NULL) { - memset(IV, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); - } else { - memcpy(IV, IVIn, CRYPTO_3KTDEA_BLOCK_SIZE); - } - while (blockIndex < numBlocks) { - if (blockIndex == 0) { - memset(inputBlock, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); - memcpy(inputBlock, &Plaintext[0], CRYPTO_3KTDEA_BLOCK_SIZE); - CryptoMemoryXOR(IV, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); - } else if (dataNeedsPadding && blockIndex + 1 == numBlocks) { - memset(inputBlock, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); - memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], Count % CryptoSpec.blockSize); - CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE], inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); - } else { - memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], CRYPTO_3KTDEA_BLOCK_SIZE); - CryptoMemoryXOR(&Plaintext[blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE], inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); - } - CryptoSpec.cryptFunc(inputBlock, ctBuf, Keys); - ctBuf += CryptoSpec.blockSize; - blockIndex++; - } + CryptoEncryptCBCBuffer(&CryptoSpec, Count, Plaintext, Ciphertext, IVIn, Keys); } void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { @@ -119,33 +118,5 @@ void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, .cryptFunc = &CryptoDecrypt3KTDEA, .blockSize = CRYPTO_3KTDEA_BLOCK_SIZE }; - uint16_t numBlocks = (Count + CryptoSpec.blockSize - 1) / CryptoSpec.blockSize; - bool dataNeedsPadding = (Count % CryptoSpec.blockSize) != 0; - uint16_t blockIndex = 0; - uint8_t inputBlock[CRYPTO_3KTDEA_BLOCK_SIZE]; - uint8_t IV[CRYPTO_3KTDEA_BLOCK_SIZE]; - if (IVIn == NULL) { - memset(IV, 0x00, CRYPTO_3KTDEA_BLOCK_SIZE); - } else { - memcpy(IV, IVIn, CRYPTO_3KTDEA_BLOCK_SIZE); - } - while (blockIndex < numBlocks) { - CryptoSpec.cryptFunc(inputBlock, Ciphertext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, Keys); - if (blockIndex == 0 && !dataNeedsPadding) { - memcpy(Plaintext, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); - CryptoMemoryXOR(IV, Plaintext, CRYPTO_3KTDEA_BLOCK_SIZE); - } else if (blockIndex == 0 && dataNeedsPadding && numBlocks == 0x01) { - memcpy(Plaintext, inputBlock, Count % CryptoSpec.blockSize); - CryptoMemoryXOR(IV, Plaintext, Count % CryptoSpec.blockSize); - } else if (dataNeedsPadding && blockIndex + 1 == numBlocks) { - memcpy(Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, inputBlock, Count % CryptoSpec.blockSize); - CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], - Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, Count % CryptoSpec.blockSize); - } else { - memcpy(Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, inputBlock, CRYPTO_3KTDEA_BLOCK_SIZE); - CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CRYPTO_3KTDEA_BLOCK_SIZE], - Plaintext + blockIndex * CRYPTO_3KTDEA_BLOCK_SIZE, CRYPTO_3KTDEA_BLOCK_SIZE); - } - blockIndex++; - } + CryptoDecryptCBCBuffer(&CryptoSpec, Count, Plaintext, Ciphertext, IVIn, Keys); } diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h index e6b28b1c..b8b1a0a7 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h @@ -57,6 +57,9 @@ void DecryptDESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, c void CryptoEncrypt2KTDEA(const void *Plaintext, void *Ciphertext, const uint8_t *Keys); void CryptoDecrypt2KTDEA(const void *Plaintext, void *Ciphertext, const uint8_t *Keys); +void Encrypt2K3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IV, const uint8_t *Keys); +void Decrypt2K3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IV, const uint8_t *Keys); + void CryptoEncrypt3KTDEA(void *Plaintext, void *Ciphertext, const uint8_t *Keys); void CryptoDecrypt3KTDEA(void *Plaintext, void *Ciphertext, const uint8_t *Keys); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h index 2f80825c..894c7511 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h @@ -41,12 +41,12 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_LITTLE_ENDIAN (1) -#define DESFIRE_PICC_STRUCT_PACKING __attribute__((aligned(4))) +#define DESFIRE_PICC_STRUCT_PACKING __attribute__((aligned(1))) #define DESFIRE_FIRMWARE_PACKING __attribute__((packed)) -#define DESFIRE_FIRMWARE_ALIGNAT __attribute__((aligned(4))) -#define DESFIRE_PICC_ARRAY_ALIGNAT __attribute__((aligned(4))) -#define DESFIRE_FIRMWARE_ARRAY_ALIGNAT __attribute__((aligned(4))) -#define DESFIRE_FIRMWARE_ENUM_PACKING __attribute__((aligned(4))) +#define DESFIRE_FIRMWARE_ALIGNAT __attribute__((aligned(1))) +#define DESFIRE_PICC_ARRAY_ALIGNAT __attribute__((aligned(1))) +#define DESFIRE_FIRMWARE_ARRAY_ALIGNAT __attribute__((aligned(1))) +#define DESFIRE_FIRMWARE_ENUM_PACKING __attribute__((aligned(1))) #define DESFIRE_FIRMWARE_NOINIT __attribute__ ((section (".noinit"))) /* Some standard boolean interpreted and other values for types and return values: */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 1c407bb1..1dec3626 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -447,20 +447,25 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { } /* Make sure that this key is AES, and figure out its byte size */ BYTE cryptoKeyType = ReadKeyCryptoType(SelectedApp.Slot, KeyId); - if (!CryptoType3KTDEA(cryptoKeyType)) { + if (!CryptoTypeDES(cryptoKeyType) && !CryptoType2KTDEA(cryptoKeyType)) { Buffer[0] = STATUS_NO_SUCH_KEY; return DESFIRE_STATUS_RESPONSE_SIZE; } /* Indicate that we are in DES key authentication land */ - keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); + keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_2KTDEA); Key = SessionKey; DesfireCommandState.KeyId = KeyId; DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); /* Fetch the key */ - ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + if (cryptoKeyType == CRYPTO_TYPE_DES) { + ReadAppKey(SelectedApp.Slot, KeyId, Key, CRYPTO_DES_KEY_SIZE); + memcpy(Key + CRYPTO_DES_KEY_SIZE, Key, CRYPTO_DES_KEY_SIZE); + } else { + ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + } LogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); /* Generate the nonce B (RndB / Challenge response) */ @@ -488,8 +493,8 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Encrypt RndB with the selected key and transfer it back to the PCD */ - Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, DesfireCommandState.RndB, - &Buffer[1], NULL, Key); + Encrypt2K3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, DesfireCommandState.RndB, + &Buffer[1], NULL, Key); /* Scrub the key */ memset(Key, 0, keySize); @@ -519,14 +524,19 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { cryptoKeyType = DesfireCommandState.CryptoMethodType; keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); Key = SessionKey; - ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + if (cryptoKeyType == CRYPTO_TYPE_DES) { + ReadAppKey(SelectedApp.Slot, KeyId, Key, CRYPTO_DES_KEY_SIZE); + memcpy(Key + CRYPTO_DES_KEY_SIZE, Key, CRYPTO_DES_KEY_SIZE); + } else { + ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + } /* Decrypt the challenge sent back to get RndA and a shifted RndB */ BYTE challengeRndAB[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndA[CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndB[CRYPTO_CHALLENGE_RESPONSE_BYTES]; - Decrypt3DESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, - &Buffer[1], NULL, Key); + Decrypt2K3DESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, + &Buffer[1], NULL, Key); RotateArrayRight(challengeRndAB + CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); @@ -539,11 +549,11 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { /* Encrypt and send back the once rotated RndA buffer to the PCD */ RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, - &Buffer[1], NULL, Key); + Encrypt2K3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, + &Buffer[1], NULL, Key); /* Create the session key based on the previous exchange */ - generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_3K3DES); + generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_2KTDEA); /* Now that we have auth'ed with the legacy command, a ChangeKey command will * allow for subsequent authentication with the ISO or AES routines diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index be0479ac..61e57b7d 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -37,7 +37,7 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_ISO7816_CLA 0x00 /* Storage allocation constants */ -#define DESFIRE_BLOCK_SIZE (4) /* Bytes */ +#define DESFIRE_BLOCK_SIZE (1) /* Bytes */ #define DESFIRE_BYTES_TO_BLOCKS(x) ( ((x) + DESFIRE_BLOCK_SIZE - 1) / DESFIRE_BLOCK_SIZE ) #define DESFIRE_UID_SIZE ISO14443A_UID_SIZE_DOUBLE diff --git a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h index a0f870b9..c2e3b4a5 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h @@ -128,11 +128,43 @@ static inline size_t DecryptAES128(const uint8_t *encSrcBuf, size_t bufSize, return bufSize; } +static inline size_t Encrypt2K3DES(const uint8_t *plainSrcBuf, size_t bufSize, + uint8_t *encDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { + DES_key_schedule keySched1, keySched2; + uint8_t IV[2 * CRYPTO_DES_BLOCK_SIZE]; + uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[CRYPTO_DES_BLOCK_SIZE]); + DES_set_key(kd1, &keySched1); + DES_set_key(kd2, &keySched2); + if (IVIn == NULL) { + memset(IV, 0x00, 2 * CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, 2 * CRYPTO_DES_BLOCK_SIZE); + } + DES_ede2_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched1, &keySched2, &IV, DES_ENCRYPT); + return bufSize; +} + +static inline size_t Decrypt2K3DES(const uint8_t *encSrcBuf, size_t bufSize, + uint8_t *plainDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { + DES_key_schedule keySched1, keySched2; + uint8_t IV[2 * CRYPTO_DES_BLOCK_SIZE]; + uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[CRYPTO_DES_BLOCK_SIZE]); + DES_set_key(kd1, &keySched1); + DES_set_key(kd2, &keySched2); + if (IVIn == NULL) { + memset(IV, 0x00, 2 * CRYPTO_DES_BLOCK_SIZE); + } else { + memcpy(IV, IVIn, 2 * CRYPTO_DES_BLOCK_SIZE); + } + DES_ede2_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched1, &keySched2, &IV, DES_DECRYPT); + return bufSize; +} + static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize, uint8_t *encDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { DES_key_schedule keySched1, keySched2, keySched3; uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; - uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[8]), *kd3 = &(cdata.keyData[16]); + uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[CRYPTO_DES_BLOCK_SIZE]), *kd3 = &(cdata.keyData[2 * CRYPTO_DES_BLOCK_SIZE]); DES_set_key(kd1, &keySched1); DES_set_key(kd2, &keySched2); DES_set_key(kd3, &keySched3); @@ -149,7 +181,7 @@ static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize, uint8_t *plainDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { DES_key_schedule keySched1, keySched2, keySched3; uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; - uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[8]), *kd3 = &(cdata.keyData[16]); + uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[CRYPTO_DES_BLOCK_SIZE]), *kd3 = &(cdata.keyData[2 * CRYPTO_DES_BLOCK_SIZE]); DES_set_key(kd1, &keySched1); DES_set_key(kd2, &keySched2); DES_set_key(kd3, &keySched3); @@ -162,6 +194,7 @@ static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize, return bufSize; } + static inline size_t EncryptDES(const uint8_t *plainSrcBuf, size_t bufSize, uint8_t *encDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { DES_key_schedule keySched; diff --git a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h index 98dc0ec7..18d442fd 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h @@ -236,7 +236,7 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c }; AUTHENTICATE_LEGACY_CMD[5] = keyIndex; if (PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, ">>> Start Legacy 3K3DES Authenticate:\n"); + fprintf(stdout, ">>> Start Legacy 2K3DES (EEE/DDD) Authenticate:\n"); fprintf(stdout, " -> "); print_hex(AUTHENTICATE_LEGACY_CMD, sizeof(AUTHENTICATE_LEGACY_CMD)); } @@ -265,13 +265,13 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c desCryptoData.keySize = 3 * 8; desCryptoData.keyData = keyData; desCryptoData.ivSize = CRYPTO_CHALLENGE_RESPONSE_SIZE; - Decrypt3DES(encryptedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, plainTextRndB, NULL, desCryptoData); + Decrypt2K3DES(encryptedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, plainTextRndB, NULL, desCryptoData); RotateArrayLeft(plainTextRndB, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); memset(IVBuf, 0x00, CRYPTO_CHALLENGE_RESPONSE_SIZE); desCryptoData.ivData = IVBuf; GenerateRandomBytes(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); ConcatByteArrays(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, challengeResponse); - Encrypt3DES(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE, challengeResponseCipherText, NULL, desCryptoData); + Encrypt2K3DES(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE, challengeResponseCipherText, NULL, desCryptoData); uint8_t sendBytesBuf[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6]; memset(sendBytesBuf, 0x00, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + 6); @@ -306,7 +306,7 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c // decrypt rndA sent by PICC, compare it to our original randomized rndA computed above, // and report back whether they match: uint8_t decryptedRndAFromPICCRotated[CRYPTO_CHALLENGE_RESPONSE_SIZE], decryptedRndA[CRYPTO_CHALLENGE_RESPONSE_SIZE]; - Decrypt3DES(rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE, decryptedRndAFromPICCRotated, NULL, desCryptoData); + Decrypt2K3DES(rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE, decryptedRndAFromPICCRotated, NULL, desCryptoData); RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); if (!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { if (PRINT_STATUS_EXCHANGE_MESSAGES) { diff --git a/Software/DESFireLibNFCTesting/Source/TestAuthenticateLegacy.c b/Software/DESFireLibNFCTesting/Source/TestAuthenticateLegacy.c index 0667bc93..09b70c9c 100644 --- a/Software/DESFireLibNFCTesting/Source/TestAuthenticateLegacy.c +++ b/Software/DESFireLibNFCTesting/Source/TestAuthenticateLegacy.c @@ -7,10 +7,6 @@ int main(int argc, char **argv) { - if (!Test3DESEncyptionRoutines()) { - return EXIT_FAILURE; - } - nfc_context *nfcCtxt; nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt); if (nfcPnd == NULL) { From b6be1b815999a15de364ad616702626435c02547 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 05:32:37 -0500 Subject: [PATCH 17/68] Space saving defines to remove currently unused crypto exchange functionality (will revisit when get to this subproject) --- Firmware/Chameleon-Mini/Application/CryptoAES128.c | 2 ++ Firmware/Chameleon-Mini/Application/CryptoAES128.h | 11 +++++++---- Firmware/Chameleon-Mini/Application/CryptoTDEA.h | 5 ++++- .../Application/DESFire/DESFireCrypto.c | 4 ++++ .../Application/DESFire/DESFireCrypto.h | 3 +++ .../Application/DESFire/DESFireFirmwareSettings.h | 2 +- .../Application/DESFire/DESFirePICCControl.c | 8 ++++---- .../DESFireLibNFCTesting/LocalInclude/DesfireUtils.h | 2 +- 8 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoAES128.c b/Firmware/Chameleon-Mini/Application/CryptoAES128.c index 90071361..f825d451 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoAES128.c +++ b/Firmware/Chameleon-Mini/Application/CryptoAES128.c @@ -289,6 +289,7 @@ uint8_t CryptoAESDecryptBuffer(uint16_t Count, uint8_t *Plaintext, uint8_t *Ciph return 0; } +#ifdef ENABLE_CRYPTO_TESTS // This routine performs the CBC "send" mode chaining: C = E(P ^ IV); IV = C void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t *IV, uint8_t *Key, @@ -376,3 +377,4 @@ void CryptoAESDecrypt_CBCReceive(uint16_t Count, uint8_t *PlainText, uint8_t *Ci }; CryptoAES_CBCRecv(Count, PlainText, CipherText, IV, Key, CryptoSpec); } +#endif diff --git a/Firmware/Chameleon-Mini/Application/CryptoAES128.h b/Firmware/Chameleon-Mini/Application/CryptoAES128.h index 7483ca5a..4fa9a57a 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoAES128.h +++ b/Firmware/Chameleon-Mini/Application/CryptoAES128.h @@ -99,18 +99,20 @@ typedef enum aes_intlvl { /* AES interrupt callback function pointer. */ typedef void (*aes_callback_t)(void); +#define CRYPTO_AES128_STRUCT_ATTR __attribute((aligned(1))) + typedef struct { CryptoAESDec_t ProcessingMode; uint8_t ProcessingDelay; // [0,15] CryptoAESAuto_t StartMode; unsigned char OpMode; // 0 = ECB, 1 = CBC, 2 = OFB, 3 = CFB, 4 = CTR CryptoAESXor_t XorMode; -} CryptoAESConfig_t; +} CryptoAESConfig_t CRYPTO_AES128_STRUCT_ATTR; typedef struct { unsigned char datrdy; // ENABLE/DISABLE; Data ready interrupt unsigned char urad; // ENABLE/DISABLE; Unspecified Register Access Detection -} CryptoAES_ISRConfig_t; +} CryptoAES_ISRConfig_t CRYPTO_AES128_STRUCT_ATTR; /* AES encryption complete. */ #define AES_ENCRYPTION_COMPLETE (1UL << 0) @@ -149,15 +151,15 @@ typedef uint8_t (*CryptoAESFuncType)(uint8_t *, uint8_t *, uint8_t *); typedef struct { CryptoAESFuncType cryptFunc; uint16_t blockSize; -} CryptoAES_CBCSpec_t; +} CryptoAES_CBCSpec_t CRYPTO_AES128_STRUCT_ATTR; +#ifdef ENABLE_CRYPTO_TESTS void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t *IV, uint8_t *Key, CryptoAES_CBCSpec_t CryptoSpec); void CryptoAES_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t *IV, uint8_t *Key, CryptoAES_CBCSpec_t CryptoSpec); - void CryptoAESEncrypt_CBCSend(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, uint8_t *Key, uint8_t *IV); void CryptoAESDecrypt_CBCSend(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, @@ -166,6 +168,7 @@ void CryptoAESEncrypt_CBCReceive(uint16_t Count, uint8_t *PlainText, uint8_t *Ci uint8_t *Key, uint8_t *IV); void CryptoAESDecrypt_CBCReceive(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, uint8_t *Key, uint8_t *IV); +#endif /* Crypto utility functions: */ #define CRYPTO_BYTES_TO_BLOCKS(numBytes, blockSize) \ diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h index b8b1a0a7..d6572c32 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h @@ -66,7 +66,7 @@ void CryptoDecrypt3KTDEA(void *Plaintext, void *Ciphertext, const uint8_t *Keys) void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IV, const uint8_t *Keys); void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IV, const uint8_t *Keys); - +#ifdef ENABLE_CRYPTO_TESTS /** Performs the 2-key Triple DES en/deciphering in the CBC "send" mode (xor-then-crypt) * * \param Count Block count, expected to be >= 1 @@ -100,6 +100,7 @@ void CryptoDecrypt2KTDEA_CBCReceive(uint16_t Count, const void *Input, void *Out */ void CryptoEncrypt3KTDEA_CBCSend(uint16_t Count, const void *Plaintext, void *Ciphertext, void *IV, const uint8_t *Keys); void CryptoDecrypt3KTDEA_CBCReceive(uint16_t Count, const void *Plaintext, void *Ciphertext, void *IV, const uint8_t *Keys); +#endif /* Spec for more generic send/recv encrypt/decrypt schemes: */ typedef struct { @@ -107,6 +108,7 @@ typedef struct { uint16_t blockSize; } CryptoTDEA_CBCSpec; +#ifdef ENABLE_CRYPTO_TESTS void CryptoTDEA_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, void *IV, const uint8_t *Keys, CryptoTDEA_CBCSpec CryptoSpec); void CryptoTDEA_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, @@ -114,6 +116,7 @@ void CryptoTDEA_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t TransferEncryptTDEASend(uint8_t *Buffer, uint8_t Count); uint8_t TransferEncryptTDEAReceive(uint8_t *Buffer, uint8_t Count); +#endif /** Applies padding to the data within the buffer * diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c index edb5cc50..cb64d0c2 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c @@ -174,6 +174,7 @@ void InitAESCryptoKeyData(void) { memset(&SessionIV[0], 0x00, CRYPTO_MAX_BLOCK_SIZE); } +#ifdef ENABLE_CRYPTO_TESTS uint8_t CryptoAESTransferEncryptSend(uint8_t *Buffer, uint8_t Count, const uint8_t *Key) { uint8_t AvailablePlaintext = TransferState.ReadData.Encryption.AvailablePlaintext; uint8_t TempBuffer[(DESFIRE_MAX_PAYLOAD_AES_BLOCKS + 1) * CRYPTO_DES_BLOCK_SIZE]; @@ -213,6 +214,7 @@ uint8_t CryptoAESTransferEncryptReceive(uint8_t *Buffer, uint8_t Count, const ui LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA_ENC, Buffer, Count); return STATUS_OPERATION_OK; } +#endif /* Checksum routines */ @@ -281,6 +283,7 @@ uint8_t TransferChecksumFinalMACTDEA(uint8_t *Buffer) { /* Encryption routines */ +#ifdef ENABLE_CRYPTO_TESTS uint8_t TransferEncryptTDEASend(uint8_t *Buffer, uint8_t Count) { uint8_t AvailablePlaintext = TransferState.ReadData.Encryption.AvailablePlaintext; uint8_t TempBuffer[(DESFIRE_MAX_PAYLOAD_TDEA_BLOCKS + 1) * CRYPTO_DES_BLOCK_SIZE]; @@ -312,5 +315,6 @@ uint8_t TransferEncryptTDEAReceive(uint8_t *Buffer, uint8_t Count) { LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA_ENC, Buffer, Count); return 0; } +#endif #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h index 3a2ad219..ee9bbe95 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h @@ -129,8 +129,11 @@ typedef void (*CryptoAESCBCFuncType)(uint16_t, void *, void *, uint8_t *, uint8_ typedef uint8_t (*CryptoTransferSendFunc)(uint8_t *, uint8_t); typedef uint8_t (*CryptoTransferReceiveFunc)(uint8_t *, uint8_t); + +#ifdef ENABLE_CRYPTO_TESTS uint8_t CryptoAESTransferEncryptSend(uint8_t *Buffer, uint8_t Count, const uint8_t *Key); uint8_t CryptoAESTransferEncryptReceive(uint8_t *Buffer, uint8_t Count, const uint8_t *Key); +#endif #define DESFIRE_MAX_PAYLOAD_AES_BLOCKS (DESFIRE_MAX_PAYLOAD_SIZE / CRYPTO_AES_BLOCK_SIZE) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h index 894c7511..fa08e466 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h @@ -47,7 +47,7 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_PICC_ARRAY_ALIGNAT __attribute__((aligned(1))) #define DESFIRE_FIRMWARE_ARRAY_ALIGNAT __attribute__((aligned(1))) #define DESFIRE_FIRMWARE_ENUM_PACKING __attribute__((aligned(1))) -#define DESFIRE_FIRMWARE_NOINIT __attribute__ ((section (".noinit"))) +#define DESFIRE_FIRMWARE_NOINIT __attribute__((section(".noinit"))) /* Some standard boolean interpreted and other values for types and return values: */ typedef int BOOL; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index 19c4b839..7b82f2bb 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -131,7 +131,7 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings) { case DESFIRE_COMMS_PLAINTEXT_MAC: TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateMACTDEA; TransferState.Checksums.FinalFunc = &TransferChecksumFinalMACTDEA; - TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = &CryptoEncrypt2KTDEA_CBCSend; + //TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = &CryptoEncrypt2KTDEA_CBCSend; memset(SessionIV, PICC_EMPTY_BYTE, sizeof(SessionIV)); SessionIVByteSize = CRYPTO_2KTDEA_KEY_SIZE; break; @@ -139,7 +139,7 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings) { TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateCRCA; TransferState.Checksums.FinalFunc = &TransferChecksumFinalCRCA; TransferState.Checksums.MACData.CRCA = ISO14443A_CRCA_INIT; - TransferState.ReadData.Encryption.Func = &TransferEncryptTDEASend; + //TransferState.ReadData.Encryption.Func = &TransferEncryptTDEASend; memset(SessionIV, PICC_EMPTY_BYTE, sizeof(SessionIV)); SessionIVByteSize = CRYPTO_3KTDEA_KEY_SIZE; break; @@ -157,7 +157,7 @@ uint8_t WriteDataFilterSetup(uint8_t CommSettings) { case DESFIRE_COMMS_PLAINTEXT_MAC: TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateMACTDEA; TransferState.Checksums.FinalFunc = &TransferChecksumFinalMACTDEA; - TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = &CryptoEncrypt2KTDEA_CBCReceive; + //TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = &CryptoEncrypt2KTDEA_CBCReceive; memset(SessionIV, 0, sizeof(SessionIVByteSize)); SessionIVByteSize = CRYPTO_2KTDEA_KEY_SIZE; break; @@ -165,7 +165,7 @@ uint8_t WriteDataFilterSetup(uint8_t CommSettings) { TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateCRCA; TransferState.Checksums.FinalFunc = &TransferChecksumFinalCRCA; TransferState.Checksums.MACData.CRCA = ISO14443A_CRCA_INIT; - TransferState.WriteData.Encryption.Func = &TransferEncryptTDEAReceive; + //TransferState.WriteData.Encryption.Func = &TransferEncryptTDEAReceive; memset(SessionIV, 0, sizeof(SessionIVByteSize)); SessionIVByteSize = CRYPTO_3KTDEA_KEY_SIZE; break; diff --git a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h index 18d442fd..33b55f37 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h @@ -236,7 +236,7 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c }; AUTHENTICATE_LEGACY_CMD[5] = keyIndex; if (PRINT_STATUS_EXCHANGE_MESSAGES) { - fprintf(stdout, ">>> Start Legacy 2K3DES (EEE/DDD) Authenticate:\n"); + fprintf(stdout, ">>> Start Legacy 2K3DES Authenticate:\n"); fprintf(stdout, " -> "); print_hex(AUTHENTICATE_LEGACY_CMD, sizeof(AUTHENTICATE_LEGACY_CMD)); } From 9ee32362b214940c86ae79d40c99318575f03bf1 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 08:02:54 -0500 Subject: [PATCH 18/68] Addressing the ACK/NAK keep-alive exchanges from some NXP readers noted by \@lvandenb in #313 --- .../Application/DESFire/DESFireInstructions.c | 2 +- Firmware/Chameleon-Mini/Application/MifareDESFire.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 1dec3626..19108d23 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -2020,7 +2020,7 @@ uint16_t ISO7816CmdSelect(uint8_t *Buffer, uint16_t ByteCount) { return ISO7816CmdSelectDF(Buffer, ByteCount); } Buffer[0] = ISO7816_ERROR_SW1_INS_UNSUPPORTED; - Buffer[1] = ISO7816_ERROR_SW2_INS_UNSUPPORTED; + Buffer[1] = ISO7816_ERROR_SW2_FUNC_UNSUPPORTED; return ISO7816_STATUS_RESPONSE_SIZE; } diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index e05ba826..822bc49b 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -226,6 +226,13 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { } else if (ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 6) { return MifareDesfireProcess(Buffer, BitCount); + } else if (ByteCount == 4 && Buffer[2] == 0x37 && Buffer[3] == 0xC8) { + // NXP-based PCD sent a "keep alive" response of ACK, + // so we respond with a corresponding NAK (with CRCA bytes appended): + Buffer[2] = 0x7E; + Buffer[3] = 0x44; + ISO14443AAppendCRCA(Buffer, 4); + return 6 * BITS_PER_BYTE; } else if (IsWrappedISO7816CommandType(Buffer, ByteCount)) { uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], Buffer, 2); From a4672ffd1edb2f80729faf858470ab70a3711664 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 08:34:27 -0500 Subject: [PATCH 19/68] Finding other places to squeeze space for the DESFire config (Log and terminal buffers stored on the stack) --- Firmware/Chameleon-Mini/Application/CryptoTDEA.h | 4 +--- .../Application/DESFire/DESFireCrypto.c | 2 -- .../Application/DESFire/DESFirePICCControl.c | 9 +++++---- Firmware/Chameleon-Mini/Application/MifareDESFire.c | 12 ++++++------ Firmware/Chameleon-Mini/Log.c | 2 +- Firmware/Chameleon-Mini/Log.h | 4 ++++ Firmware/Chameleon-Mini/Terminal/Terminal.h | 4 ++++ 7 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h index d6572c32..6397e900 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h @@ -66,7 +66,6 @@ void CryptoDecrypt3KTDEA(void *Plaintext, void *Ciphertext, const uint8_t *Keys) void Encrypt3DESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IV, const uint8_t *Keys); void Decrypt3DESBuffer(uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IV, const uint8_t *Keys); -#ifdef ENABLE_CRYPTO_TESTS /** Performs the 2-key Triple DES en/deciphering in the CBC "send" mode (xor-then-crypt) * * \param Count Block count, expected to be >= 1 @@ -90,6 +89,7 @@ void CryptoEncrypt2KTDEA_CBCReceive(uint16_t Count, const void *Input, void *Out void CryptoDecrypt2KTDEA_CBCReceive(uint16_t Count, const void *Input, void *Output, void *IV, const uint8_t *Keys); +#ifdef ENABLE_CRYPTO_TESTS /** Performs the 3-key Triple DES en/deciphering in the CBC "send" or "receive" mode * * \param Count Block count, expected to be >= 1 @@ -108,7 +108,6 @@ typedef struct { uint16_t blockSize; } CryptoTDEA_CBCSpec; -#ifdef ENABLE_CRYPTO_TESTS void CryptoTDEA_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, void *IV, const uint8_t *Keys, CryptoTDEA_CBCSpec CryptoSpec); void CryptoTDEA_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, @@ -116,7 +115,6 @@ void CryptoTDEA_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t TransferEncryptTDEASend(uint8_t *Buffer, uint8_t Count); uint8_t TransferEncryptTDEAReceive(uint8_t *Buffer, uint8_t Count); -#endif /** Applies padding to the data within the buffer * diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c index cb64d0c2..8ab76767 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c @@ -283,7 +283,6 @@ uint8_t TransferChecksumFinalMACTDEA(uint8_t *Buffer) { /* Encryption routines */ -#ifdef ENABLE_CRYPTO_TESTS uint8_t TransferEncryptTDEASend(uint8_t *Buffer, uint8_t Count) { uint8_t AvailablePlaintext = TransferState.ReadData.Encryption.AvailablePlaintext; uint8_t TempBuffer[(DESFIRE_MAX_PAYLOAD_TDEA_BLOCKS + 1) * CRYPTO_DES_BLOCK_SIZE]; @@ -315,6 +314,5 @@ uint8_t TransferEncryptTDEAReceive(uint8_t *Buffer, uint8_t Count) { LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA_ENC, Buffer, Count); return 0; } -#endif #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index 7b82f2bb..e5cbe9db 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -131,7 +131,7 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings) { case DESFIRE_COMMS_PLAINTEXT_MAC: TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateMACTDEA; TransferState.Checksums.FinalFunc = &TransferChecksumFinalMACTDEA; - //TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = &CryptoEncrypt2KTDEA_CBCSend; + TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = &CryptoEncrypt2KTDEA_CBCSend; memset(SessionIV, PICC_EMPTY_BYTE, sizeof(SessionIV)); SessionIVByteSize = CRYPTO_2KTDEA_KEY_SIZE; break; @@ -139,7 +139,7 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings) { TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateCRCA; TransferState.Checksums.FinalFunc = &TransferChecksumFinalCRCA; TransferState.Checksums.MACData.CRCA = ISO14443A_CRCA_INIT; - //TransferState.ReadData.Encryption.Func = &TransferEncryptTDEASend; + TransferState.ReadData.Encryption.Func = &TransferEncryptTDEASend; memset(SessionIV, PICC_EMPTY_BYTE, sizeof(SessionIV)); SessionIVByteSize = CRYPTO_3KTDEA_KEY_SIZE; break; @@ -157,7 +157,7 @@ uint8_t WriteDataFilterSetup(uint8_t CommSettings) { case DESFIRE_COMMS_PLAINTEXT_MAC: TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateMACTDEA; TransferState.Checksums.FinalFunc = &TransferChecksumFinalMACTDEA; - //TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = &CryptoEncrypt2KTDEA_CBCReceive; + TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = &CryptoEncrypt2KTDEA_CBCReceive; memset(SessionIV, 0, sizeof(SessionIVByteSize)); SessionIVByteSize = CRYPTO_2KTDEA_KEY_SIZE; break; @@ -165,11 +165,12 @@ uint8_t WriteDataFilterSetup(uint8_t CommSettings) { TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateCRCA; TransferState.Checksums.FinalFunc = &TransferChecksumFinalCRCA; TransferState.Checksums.MACData.CRCA = ISO14443A_CRCA_INIT; - //TransferState.WriteData.Encryption.Func = &TransferEncryptTDEAReceive; + TransferState.WriteData.Encryption.Func = &TransferEncryptTDEAReceive; memset(SessionIV, 0, sizeof(SessionIVByteSize)); SessionIVByteSize = CRYPTO_3KTDEA_KEY_SIZE; break; case DESFIRE_COMMS_CIPHERTEXT_AES128: + // TODO default: return STATUS_PARAMETER_ERROR; } diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 822bc49b..37694857 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -226,13 +226,13 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { } else if (ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 6) { return MifareDesfireProcess(Buffer, BitCount); - } else if (ByteCount == 4 && Buffer[2] == 0x37 && Buffer[3] == 0xC8) { - // NXP-based PCD sent a "keep alive" response of ACK, - // so we respond with a corresponding NAK (with CRCA bytes appended): - Buffer[2] = 0x7E; - Buffer[3] = 0x44; + } else if (ByteCount == 4 && Buffer[2] == 0x37 && Buffer[3] == 0xC8) { + // NXP-based PCD sent a "keep alive" response of ACK, + // so we respond with a corresponding NAK (with CRCA bytes appended): + Buffer[2] = 0x7E; + Buffer[3] = 0x44; ISO14443AAppendCRCA(Buffer, 4); - return 6 * BITS_PER_BYTE; + return 6 * BITS_PER_BYTE; } else if (IsWrappedISO7816CommandType(Buffer, ByteCount)) { uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], Buffer, 2); diff --git a/Firmware/Chameleon-Mini/Log.c b/Firmware/Chameleon-Mini/Log.c index 89aa5855..e2d59efb 100644 --- a/Firmware/Chameleon-Mini/Log.c +++ b/Firmware/Chameleon-Mini/Log.c @@ -229,7 +229,7 @@ void LogSRAMToFRAM(void) { LogFRAMAddr += FRAM_Free; MemoryWriteBlock(&LogFRAMAddr, FRAM_LOG_ADDR_ADDR, 2); } else { - // TODO handle the case in which the FRAM is full + // TODO: handle the case in which the FRAM is full } } } diff --git a/Firmware/Chameleon-Mini/Log.h b/Firmware/Chameleon-Mini/Log.h index 39828d1f..026c0734 100644 --- a/Firmware/Chameleon-Mini/Log.h +++ b/Firmware/Chameleon-Mini/Log.h @@ -3,7 +3,11 @@ /** @file */ #include "Common.h" +#ifdef MEMORY_LIMITED_TESTING +#define LOG_SIZE 1536 +#else #define LOG_SIZE 2048 +#endif #define FRAM_LOG_ADDR_ADDR 0x4000 // start of the second half of FRAM #define FRAM_LOG_START_ADDR 0x4002 // directly after the address #define FRAM_LOG_SIZE 0x3FFE // the whole second half (minus the 2 Bytes of Address) diff --git a/Firmware/Chameleon-Mini/Terminal/Terminal.h b/Firmware/Chameleon-Mini/Terminal/Terminal.h index 36217c1c..b6e8c4a1 100644 --- a/Firmware/Chameleon-Mini/Terminal/Terminal.h +++ b/Firmware/Chameleon-Mini/Terminal/Terminal.h @@ -16,7 +16,11 @@ #define TERMINAL_VBUS_PORT PORTD #define TERMINAL_VBUS_MASK PIN5_bm +#ifdef MEMORY_LIMITED_TESTING +#define TERMINAL_BUFFER_SIZE 384 +#else #define TERMINAL_BUFFER_SIZE 512 +#endif typedef enum { TERMINAL_UNINITIALIZED, From 397478608e107d37db61e67cf0e9d19542850162 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 08:47:04 -0500 Subject: [PATCH 20/68] Finding other places to squeeze space for the DESFire config (Log and terminal buffers stored on the stack -- adding buffer full messages for INFO) --- Firmware/Chameleon-Mini/Log.c | 7 ++++--- Firmware/Chameleon-Mini/Terminal/CommandLine.c | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Firmware/Chameleon-Mini/Log.c b/Firmware/Chameleon-Mini/Log.c index e2d59efb..5cec3e31 100644 --- a/Firmware/Chameleon-Mini/Log.c +++ b/Firmware/Chameleon-Mini/Log.c @@ -213,7 +213,6 @@ void LogGetModeList(char *List, uint16_t BufferSize) { void LogSRAMToFRAM(void) { if (LogMemLeft < LOG_SIZE) { uint16_t FRAM_Free = FRAM_LOG_SIZE - (LogFRAMAddr - FRAM_LOG_START_ADDR); - if (FRAM_Free >= LOG_SIZE - LogMemLeft) { MemoryWriteBlock(LogMem, LogFRAMAddr, LOG_SIZE - LogMemLeft); LogFRAMAddr += LOG_SIZE - LogMemLeft; @@ -223,13 +222,15 @@ void LogSRAMToFRAM(void) { // not everything fits in FRAM, simply write as much as possible to FRAM MemoryWriteBlock(LogMem, LogFRAMAddr, FRAM_Free); memmove(LogMem, LogMem + FRAM_Free, LOG_SIZE - FRAM_Free); // FRAM_Free is < LOG_SIZE - LogMemLeft and thus also < LOG_SIZE - LogMemPtr -= FRAM_Free; LogMemLeft += FRAM_Free; LogFRAMAddr += FRAM_Free; MemoryWriteBlock(&LogFRAMAddr, FRAM_LOG_ADDR_ADDR, 2); } else { - // TODO: handle the case in which the FRAM is full + // TODO: handle the case in which the FRAM is full ??? + // Notify the user by repeatedly blinking the LED: + LEDHook(LED_LOG_MEM_FULL, LED_BLINK_8X); + LEDHook(LED_LOG_MEM_FULL, LED_BLINK_8X); } } } diff --git a/Firmware/Chameleon-Mini/Terminal/CommandLine.c b/Firmware/Chameleon-Mini/Terminal/CommandLine.c index f538dddb..ea7d92f3 100644 --- a/Firmware/Chameleon-Mini/Terminal/CommandLine.c +++ b/Firmware/Chameleon-Mini/Terminal/CommandLine.c @@ -482,6 +482,13 @@ static void DecodeCommand(void) { /* Send optional answer */ TerminalSendString(pTerminalBuffer); TerminalSendStringP(PSTR(OPTIONAL_ANSWER_TRAILER)); + if (StringLength(pTerminalBuffer, TERMINAL_BUFFER_SIZE) + 1 >= TERMINAL_BUFFER_SIZE) { + // Notify the user that the command line output is truncated. This can come up in the + // 'CONFIG=MF_DESFIRE' variants where the Makefile setting 'MEMORY_LIMITED_TESTING' is + // enabled by default to save space for other necessary components. + TerminalSendStringP(PSTR("-- OUTPUT TRUNCATED --")); + TerminalSendStringP(PSTR(OPTIONAL_ANSWER_TRAILER)); + } } } From 583bb9362b062c115f829b9f4fb13f454f1bbe21 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 10:07:37 -0500 Subject: [PATCH 21/68] Adding in preliminary AES transfer functions -- Trying to save space for more where it can be pruned --- .../Chameleon-Mini/Application/CryptoAES128.c | 40 +++++++++------- .../Chameleon-Mini/Application/CryptoAES128.h | 18 ++----- .../Chameleon-Mini/Application/CryptoCMAC.h | 47 +++++++++++++++++++ .../DESFire/DESFireChameleonTerminal.c | 2 + .../DESFire/DESFireChameleonTerminal.h | 8 ++-- .../DESFire/DESFireChameleonTerminalInclude.c | 24 +++++----- .../Application/DESFire/DESFireCrypto.c | 6 +++ .../Application/DESFire/DESFireCrypto.h | 7 ++- .../Application/DESFire/DESFirePICCControl.c | 29 ++++++++++-- .../DESFire/DESFirePICCHeaderLayout.h | 14 +++--- Firmware/Chameleon-Mini/Log.h | 2 +- Firmware/Chameleon-Mini/Makefile | 24 ++++++---- Firmware/Chameleon-Mini/Terminal/Terminal.h | 2 +- 13 files changed, 152 insertions(+), 71 deletions(-) create mode 100644 Firmware/Chameleon-Mini/Application/CryptoCMAC.h diff --git a/Firmware/Chameleon-Mini/Application/CryptoAES128.c b/Firmware/Chameleon-Mini/Application/CryptoAES128.c index f825d451..5d992e00 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoAES128.c +++ b/Firmware/Chameleon-Mini/Application/CryptoAES128.c @@ -99,6 +99,9 @@ void aes_get_key(uint8_t *key_out) { } } +static void CryptoAESEncryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_t *Key, bool XorModeOn); +static void CryptoAESDecryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_t *Key); + static bool aes_lastsubkey_generate(uint8_t *key, uint8_t *last_sub_key) { bool keygen_ok; aes_software_reset(); @@ -178,7 +181,8 @@ void CryptoAESInitContext(CryptoAESConfig_t *ctx) { aes_set_callback(&int_callback_aes); } -uint16_t CryptoAESGetPaddedBufferSize(uint16_t bufSize) { +static uint16_t CryptoAESGetPaddedBufferSize(uint16_t bufSize); +static uint16_t CryptoAESGetPaddedBufferSize(uint16_t bufSize) { uint16_t spareBytes = (bufSize % CRYPTO_AES_BLOCK_SIZE); if (spareBytes == 0) { return bufSize; @@ -186,7 +190,7 @@ uint16_t CryptoAESGetPaddedBufferSize(uint16_t bufSize) { return bufSize + CRYPTO_AES_BLOCK_SIZE - spareBytes; } -void CryptoAESEncryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_t *Key, bool XorModeOn) { +static void CryptoAESEncryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_t *Key, bool XorModeOn) { aes_software_reset(); AES.CTRL = AES_RESET_bm; NOP(); @@ -207,7 +211,7 @@ void CryptoAESEncryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_ aes_clear_error_flag(); } -void CryptoAESDecryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_t *Key) { +static void CryptoAESDecryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_t *Key) { AES.CTRL = AES_RESET_bm; NOP(); AES.CTRL = 0; @@ -289,9 +293,9 @@ uint8_t CryptoAESDecryptBuffer(uint16_t Count, uint8_t *Plaintext, uint8_t *Ciph return 0; } -#ifdef ENABLE_CRYPTO_TESTS // This routine performs the CBC "send" mode chaining: C = E(P ^ IV); IV = C -void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, +static void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t *IV, uint8_t *Key, CryptoAES_CBCSpec_t CryptoSpec); +static void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t *IV, uint8_t *Key, CryptoAES_CBCSpec_t CryptoSpec) { uint16_t numBlocks = CRYPTO_BYTES_TO_BLOCKS(Count, CryptoSpec.blockSize); @@ -317,7 +321,8 @@ void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, } // This routine performs the CBC "receive" mode chaining: C = E(P) ^ IV; IV = P -void CryptoAES_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, +static void CryptoAES_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t *IV, uint8_t *Key, CryptoAES_CBCSpec_t CryptoSpec); +static void CryptoAES_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t *IV, uint8_t *Key, CryptoAES_CBCSpec_t CryptoSpec) { uint16_t numBlocks = CRYPTO_BYTES_TO_BLOCKS(Count, CryptoSpec.blockSize); @@ -342,39 +347,40 @@ void CryptoAES_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, } } -void CryptoAESEncrypt_CBCSend(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, +#ifdef ENABLE_CRYPTO_TESTS +void CryptoAESDecrypt_CBCSend(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, uint8_t *Key, uint8_t *IV) { CryptoAES_CBCSpec_t CryptoSpec = { - .cryptFunc = &CryptoAESEncryptBlock, + .cryptFunc = &CryptoAESDecryptBlock, .blockSize = CRYPTO_AES_BLOCK_SIZE }; CryptoAES_CBCSend(Count, PlainText, CipherText, IV, Key, CryptoSpec); } -void CryptoAESDecrypt_CBCSend(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, - uint8_t *Key, uint8_t *IV) { +void CryptoAESDecrypt_CBCReceive(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, + uint8_t *Key, uint8_t *IV) { CryptoAES_CBCSpec_t CryptoSpec = { .cryptFunc = &CryptoAESDecryptBlock, .blockSize = CRYPTO_AES_BLOCK_SIZE }; - CryptoAES_CBCSend(Count, PlainText, CipherText, IV, Key, CryptoSpec); + CryptoAES_CBCRecv(Count, PlainText, CipherText, IV, Key, CryptoSpec); } +#endif -void CryptoAESEncrypt_CBCReceive(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, - uint8_t *Key, uint8_t *IV) { +void CryptoAESEncrypt_CBCSend(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, + uint8_t *Key, uint8_t *IV) { CryptoAES_CBCSpec_t CryptoSpec = { .cryptFunc = &CryptoAESEncryptBlock, .blockSize = CRYPTO_AES_BLOCK_SIZE }; - CryptoAES_CBCRecv(Count, PlainText, CipherText, IV, Key, CryptoSpec); + CryptoAES_CBCSend(Count, PlainText, CipherText, IV, Key, CryptoSpec); } -void CryptoAESDecrypt_CBCReceive(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, +void CryptoAESEncrypt_CBCReceive(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, uint8_t *Key, uint8_t *IV) { CryptoAES_CBCSpec_t CryptoSpec = { - .cryptFunc = &CryptoAESDecryptBlock, + .cryptFunc = &CryptoAESEncryptBlock, .blockSize = CRYPTO_AES_BLOCK_SIZE }; CryptoAES_CBCRecv(Count, PlainText, CipherText, IV, Key, CryptoSpec); } -#endif diff --git a/Firmware/Chameleon-Mini/Application/CryptoAES128.h b/Firmware/Chameleon-Mini/Application/CryptoAES128.h index 4fa9a57a..75844ce7 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoAES128.h +++ b/Firmware/Chameleon-Mini/Application/CryptoAES128.h @@ -138,10 +138,7 @@ void aes_set_callback(const aes_callback_t callback); void CryptoAESGetConfigDefaults(CryptoAESConfig_t *ctx); void CryptoAESInitContext(CryptoAESConfig_t *ctx); -uint16_t CryptoAESGetPaddedBufferSize(uint16_t bufSize); -void CryptoAESEncryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_t *Key, bool); -void CryptoAESDecryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_t *Key); uint8_t CryptoAESEncryptBuffer(uint16_t Count, uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_t *IV, const uint8_t *Key); uint8_t CryptoAESDecryptBuffer(uint16_t Count, uint8_t *Plaintext, uint8_t *Ciphertext, @@ -154,22 +151,17 @@ typedef struct { } CryptoAES_CBCSpec_t CRYPTO_AES128_STRUCT_ATTR; #ifdef ENABLE_CRYPTO_TESTS -void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, - uint8_t *IV, uint8_t *Key, - CryptoAES_CBCSpec_t CryptoSpec); -void CryptoAES_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, - uint8_t *IV, uint8_t *Key, - CryptoAES_CBCSpec_t CryptoSpec); -void CryptoAESEncrypt_CBCSend(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, - uint8_t *Key, uint8_t *IV); void CryptoAESDecrypt_CBCSend(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, uint8_t *Key, uint8_t *IV); -void CryptoAESEncrypt_CBCReceive(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, - uint8_t *Key, uint8_t *IV); void CryptoAESDecrypt_CBCReceive(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, uint8_t *Key, uint8_t *IV); #endif +void CryptoAESEncrypt_CBCReceive(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, + uint8_t *Key, uint8_t *IV); +void CryptoAESEncrypt_CBCSend(uint16_t Count, uint8_t *PlainText, uint8_t *CipherText, + uint8_t *Key, uint8_t *IV); + /* Crypto utility functions: */ #define CRYPTO_BYTES_TO_BLOCKS(numBytes, blockSize) \ ( ((numBytes) + (blockSize) - 1) / (blockSize) ) diff --git a/Firmware/Chameleon-Mini/Application/CryptoCMAC.h b/Firmware/Chameleon-Mini/Application/CryptoCMAC.h new file mode 100644 index 00000000..ab590467 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/CryptoCMAC.h @@ -0,0 +1,47 @@ +/* +The DESFire stack portion of this firmware source +is free software written by Maxie Dion Schmidt (@maxieds): +You can redistribute it and/or modify +it under the terms of this license. + +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. + +The complete source distribution of +this firmware is available at the following link: +https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack. + +Based in part on the original DESFire code created by +@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at +https://github.com/dev-zzo/ChameleonMini/tree/desfire. + +This notice must be retained at the top of all source files where indicated. +*/ + +/* + * CryptoCMAC.h : + * Maxie D. Schmidt (github.com/maxieds) + */ + +#ifndef __CRYPTO_CMAC_H__ +#define __CRYPTO_CMAC_H__ + +#include "DESFire/DESFireCrypto.h" +#include "CryptoTDEA.h" +#include "CryptoAES128.h" + +/* MAC and CMAC source code based on github/andrade/nfcjlib */ + +#define CRYPTO_CMAC_RB64 (0x1B) +#define CRYPTO_CMAC_RB128 ((uint8_t) 0x87) + +void getCMACSubK1(uint8_t *bufferL, uint16_t blockSize, uint8_t polyByte, uint8_t *bufferOut); +void getCMACSubK2(uint8_t *bufferK1, uint16_t blockSize, uint8_t polyByte, uint8_t *bufferOut); + +bool computeBufferCMACFull(uint8_t *keyData, uint8_t *bufferK1, uint8_t *bufferK2, uint8_t *bufferIV, uint16_t blockSize, uint16_t cryptoType); +bool computeBufferCMAC(uint16_t cryptoType, uint8_t *keyData, uint8_t *bufferData, uint8_t *aesIV); + +bool computeMac(uint8_t *bufferData, uint16_t dataLength, uint8_t *keyData, uint16_t cryptoKeyType); + +#endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c index 92e202af..ac7b8e59 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c @@ -114,6 +114,7 @@ CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutParam, const char * } #endif /* DISABLE_PERMISSIVE_DESFIRE_SETTINGS */ +#if 0 CommandStatusIdType CommandDESFireLayoutPPrint(char *OutParam, const char *InParams) { if (!IsDESFireConfiguration()) { ExitOnInvalidConfigurationError(OutParam); @@ -155,6 +156,7 @@ CommandStatusIdType CommandDESFireFirmwareInfo(char *OutParam) { DESFIRE_FIRMWARE_REVISION); return COMMAND_INFO_OK_WITH_TEXT_ID; } +#endif CommandStatusIdType CommandDESFireGetLoggingMode(char *OutParam) { if (!IsDESFireConfiguration()) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h index 1c5664f6..82b61a18 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h @@ -42,11 +42,11 @@ CommandStatusIdType CommandDESFireGetHeaderProperty(char *OutParam); CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutMessage, const char *InParams); #endif -#define DFCOMMAND_LAYOUT_PPRINT "DF_PPRINT_PICC" -CommandStatusIdType CommandDESFireLayoutPPrint(char *OutParam, const char *InParams); +//#define DFCOMMAND_LAYOUT_PPRINT "DF_PPRINT_PICC" +//CommandStatusIdType CommandDESFireLayoutPPrint(char *OutParam, const char *InParams); -#define DFCOMMAND_FIRMWARE_INFO "DF_FWINFO" -CommandStatusIdType CommandDESFireFirmwareInfo(char *OutParam); +//#define DFCOMMAND_FIRMWARE_INFO "DF_FWINFO" +//CommandStatusIdType CommandDESFireFirmwareInfo(char *OutParam); #define DFCOMMAND_LOGGING_MODE "DF_LOGMODE" CommandStatusIdType CommandDESFireGetLoggingMode(char *OutParam); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c index 08962633..fcded7d3 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c @@ -35,18 +35,18 @@ This notice must be retained at the top of all source files where indicated. .SetFunc = CommandDESFireSetHeaderProperty, .GetFunc = CommandDESFireGetHeaderProperty }, { - .Command = DFCOMMAND_LAYOUT_PPRINT, - .ExecFunc = NO_FUNCTION, - .ExecParamFunc = CommandDESFireLayoutPPrint, - .SetFunc = NO_FUNCTION, - .GetFunc = NO_FUNCTION -}, { - .Command = DFCOMMAND_FIRMWARE_INFO, - .ExecFunc = CommandDESFireFirmwareInfo, - .ExecParamFunc = NO_FUNCTION, - .SetFunc = NO_FUNCTION, - .GetFunc = NO_FUNCTION -}, { +// .Command = DFCOMMAND_LAYOUT_PPRINT, +// .ExecFunc = NO_FUNCTION, +// .ExecParamFunc = CommandDESFireLayoutPPrint, +// .SetFunc = NO_FUNCTION, +// .GetFunc = NO_FUNCTION +//}, { +// .Command = DFCOMMAND_FIRMWARE_INFO, +// .ExecFunc = CommandDESFireFirmwareInfo, +// .ExecParamFunc = NO_FUNCTION, +// .SetFunc = NO_FUNCTION, +// .GetFunc = NO_FUNCTION +//}, { .Command = DFCOMMAND_LOGGING_MODE, .ExecFunc = NO_FUNCTION, .ExecParamFunc = NO_FUNCTION, diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c index 8ab76767..e2654d98 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c @@ -281,6 +281,12 @@ uint8_t TransferChecksumFinalMACTDEA(uint8_t *Buffer) { return 4; } +void TransferChecksumUpdateCMAC(const uint8_t *Buffer, uint8_t Count) {} // TODO + +uint8_t TransferChecksumFinalCMAC(uint8_t *Buffer) { + return 0x00; // TODO +} + /* Encryption routines */ uint8_t TransferEncryptTDEASend(uint8_t *Buffer, uint8_t Count) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h index ee9bbe95..dcd51625 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.h @@ -28,6 +28,7 @@ This notice must be retained at the top of all source files where indicated. #define __DESFIRE_CRYPTO_H__ #include "../../Common.h" +#include "../CryptoAES128.h" #include "DESFireFirmwareSettings.h" @@ -63,7 +64,6 @@ extern BYTE DesfireCommMode; ((ct == CRYPTO_TYPE_AES128) || (ct == CRYPTO_TYPE_ANY)) /* Key sizes, block sizes (in bytes): */ -#define CRYPTO_AES_KEY_SIZE (16) #define CRYPTO_MAX_KEY_SIZE (24) #define CRYPTO_MAX_BLOCK_SIZE (16) #define DESFIRE_AES_IV_SIZE (CRYPTO_AES_BLOCK_SIZE) @@ -153,4 +153,9 @@ uint8_t TransferChecksumFinalCRCA(uint8_t *Buffer); void TransferChecksumUpdateMACTDEA(const uint8_t *Buffer, uint8_t Count); uint8_t TransferChecksumFinalMACTDEA(uint8_t *Buffer); +#include "../CryptoCMAC.h" + +void TransferChecksumUpdateCMAC(const uint8_t *Buffer, uint8_t Count); +uint8_t TransferChecksumFinalCMAC(uint8_t *Buffer); + #endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index e5cbe9db..8021d40f 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -144,7 +144,14 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings) { SessionIVByteSize = CRYPTO_3KTDEA_KEY_SIZE; break; case DESFIRE_COMMS_CIPHERTEXT_AES128: - default: + // A.k.a., CommMode=FULL from NXP application note AN12343: + TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateCMAC; + TransferState.Checksums.FinalFunc = &TransferChecksumFinalCMAC; + TransferState.Checksums.MACData.CRCA = ISO14443A_CRCA_INIT; // TODO ??? + TransferState.WriteData.Encryption.Func = &CryptoAESEncrypt_CBCSend; + memset(SessionIV, 0, sizeof(SessionIVByteSize)); + SessionIVByteSize = CRYPTO_AES_KEY_SIZE; + default: return STATUS_PARAMETER_ERROR; } return STATUS_OPERATION_OK; @@ -153,7 +160,12 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings) { uint8_t WriteDataFilterSetup(uint8_t CommSettings) { switch (CommSettings) { case DESFIRE_COMMS_PLAINTEXT: - break; + TransferState.Checksums.UpdateFunc = NULL; + TransferState.Checksums.FinalFunc = NULL; + TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = NULL; + memset(SessionIV, 0, sizeof(SessionIVByteSize)); + SessionIVByteSize = 0; + break; case DESFIRE_COMMS_PLAINTEXT_MAC: TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateMACTDEA; TransferState.Checksums.FinalFunc = &TransferChecksumFinalMACTDEA; @@ -167,10 +179,17 @@ uint8_t WriteDataFilterSetup(uint8_t CommSettings) { TransferState.Checksums.MACData.CRCA = ISO14443A_CRCA_INIT; TransferState.WriteData.Encryption.Func = &TransferEncryptTDEAReceive; memset(SessionIV, 0, sizeof(SessionIVByteSize)); - SessionIVByteSize = CRYPTO_3KTDEA_KEY_SIZE; + SessionIVByteSize = CRYPTO_AES_KEY_SIZE; + break; + case DESFIRE_COMMS_CIPHERTEXT_AES128: + // A.k.a., CommMode=FULL from NXP application note AN12343: + TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateCMAC; + TransferState.Checksums.FinalFunc = &TransferChecksumFinalCMAC; + TransferState.Checksums.MACData.CRCA = ISO14443A_CRCA_INIT; // TODO ??? + TransferState.WriteData.Encryption.Func = &CryptoAESEncrypt_CBCReceive; + memset(SessionIV, 0, sizeof(SessionIVByteSize)); + SessionIVByteSize = CRYPTO_AES_KEY_SIZE; break; - case DESFIRE_COMMS_CIPHERTEXT_AES128: - // TODO default: return STATUS_PARAMETER_ERROR; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index 61e57b7d..5d5c06e7 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -145,7 +145,7 @@ This notice must be retained at the top of all source files where indicated. #define PICC_FORMAT_BYTE (0x00) #define PICC_EMPTY_BYTE (0x00) -typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT { +typedef struct { /* Static data: does not change during the PICC's lifetime. * We will add Chameleon Mini terminal commands to enable * resetting this data so tags can be emulated authentically. @@ -164,11 +164,11 @@ typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT { uint8_t ATSBytes[5]; /* Dynamic data: changes during the PICC's lifetime */ uint16_t FirstFreeBlock; - uint8_t TransactionStarted; // USED ??? - uint8_t Spare[9] DESFIRE_FIRMWARE_ALIGNAT; // USED ??? -} DESFirePICCInfoType; + uint8_t TransactionStarted; + //uint8_t Spare[9] DESFIRE_FIRMWARE_ALIGNAT; // USED ANYWHERE ??? +} DESFirePICCInfoType DESFIRE_FIRMWARE_PACKING; -typedef struct DESFIRE_FIRMWARE_PACKING { +typedef struct { BYTE Slot; BYTE KeyCount; BYTE MaxKeyCount; @@ -182,8 +182,8 @@ typedef struct DESFIRE_FIRMWARE_PACKING { SIZET KeyVersionsArray; /* Block offset in FRAM */ SIZET KeyTypesArray; /* Block offset in FRAM */ SIZET KeyAddress; /* Block offset in FRAM */ - UINT DirtyFlags; // USED ??? -} SelectedAppCacheType; + //UINT DirtyFlags; // USED ANYWHERE ??? +} SelectedAppCacheType DESFIRE_FIRMWARE_PACKING; extern BYTE SELECTED_APP_CACHE_TYPE_BLOCK_SIZE; extern BYTE APP_CACHE_KEY_SETTINGS_ARRAY_BLOCK_SIZE; diff --git a/Firmware/Chameleon-Mini/Log.h b/Firmware/Chameleon-Mini/Log.h index 026c0734..9c27562e 100644 --- a/Firmware/Chameleon-Mini/Log.h +++ b/Firmware/Chameleon-Mini/Log.h @@ -4,7 +4,7 @@ #include "Common.h" #ifdef MEMORY_LIMITED_TESTING -#define LOG_SIZE 1536 +#define LOG_SIZE 1284 // 1536 #else #define LOG_SIZE 2048 #endif diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 20f987d9..7b5495cd 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -96,8 +96,8 @@ SETTINGS += -DENABLE_EEPROM_SETTINGS #Set a default logging mode for debugging with the DESFire #emulation code: -SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING -#SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF +#SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING +SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF #Set a default testing mode setting (0 = OFF, non-NULL = ON): SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 @@ -141,8 +141,7 @@ DESFIRE_CONFIG_SETTINGS_BASE = $(SETTINGS) -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_ #Memory definitions and objcopy flags to include sections in binaries FLASH_DATA_ADDR = 0x10000 #Start of data section in flash -FLASH_DATA_SIZE = 0x10000 #Size of data section in flash -#FLASH_DATA_SIZE = 0x0FFFF #Size of data section in flash +FLASH_DATA_SIZE = 0x10000 #Size of data section in flash FLASH_DATA_OBJCOPY = --set-section-flags=.flashdata="alloc,load" SPM_HELPER_ADDR = 0x21FE0 #Start of SPM helper section. Should be last 32Byte in bootloader section SPM_HELPER_OBJCOPY = --set-section-flags=.spmhelper="alloc,load" @@ -172,7 +171,7 @@ SRC += Application/MifareUltralight.c Application/MifareClassic.c Applic SRC += Application/NTAG215.c SRC += Codec/ISO15693.c SRC += Application/Vicinity.c Application/Sl2s2002.c Application/TITagitstandard.c Application/TITagitplus.c Application/ISO15693-A.c Application/EM4233.c -SRC += $(DESFIRE_MAINSRC)/../MifareDESFire.c \ +SRC += $(DESFIRE_MAINSRC)/../MifareDESFire.c \ $(DESFIRE_MAINSRC)/DESFireApplicationDirectory.c \ $(DESFIRE_MAINSRC)/DESFireChameleonTerminal.c \ $(DESFIRE_MAINSRC)/DESFireCrypto.c \ @@ -193,9 +192,10 @@ CC_FLAGS = -g0 -DUSE_LUFA_CONFIG_HEADER -DFLASH_DATA_ADDR=$(FLASH_DATA_ADDR) -D__AVR_ATxmega128A4U__ -D__PROG_TYPES_COMPAT__ -DMAX_ENDPOINT_INDEX=4 \ -std=gnu99 -Werror=implicit-function-declaration \ -fno-inline-small-functions -fshort-enums -fpack-struct \ - -Wl,--gc-sections --data-sections -ffunction-sections -fdata-sections \ + -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden \ + -Wl,-strip-all -Wl,--gc-sections --data-sections \ -Wl,-relax -fno-split-wide-types -fno-tree-scev-cprop \ - -fno-aggressive-loop-optimizations + -fno-aggressive-loop-optimizations #-fno-jump-tables -fno-common LD_FLAGS = $(CC_FLAGS) -Wl,--section-start=.flashdata=$(FLASH_DATA_ADDR) -Wl,--section-start=.spmhelper=$(SPM_HELPER_ADDR) OBJDIR = Bin OBJECT_FILES = @@ -252,7 +252,7 @@ program-latest: check_size avrdude $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_APP_LATEST) $(AVRDUDE_WRITE_EEPROM_LATEST) # Program the device using batchisp and the DFU bootloader -# Note that the device has to be in bootloader mode already +# Note that the device has to be in bootloader mode already-ffunction-sections -fdata-sections dfu-flip: $(TARGET).hex $(TARGET).eep check_size cp $(TARGET).eep EEPROM.hex batchisp -hardware usb -device $(MCU) -operation erase f memory FLASH loadbuffer $(TARGET).hex program verify memory EEPROM loadbuffer EEPROM.hex program verify start reset 0 @@ -305,9 +305,13 @@ git-add-dev: ## Defining custom targets for the DESFire build (normal/user mode) and ## developer mode for use with the Android CMLD application that enables ## the printing of LIVE logs to the phone's console by default: -desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep +desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep check_size @cp $(TARGET).hex $(TARGET)-DESFire.hex @cp $(TARGET).eep $(TARGET)-DESFire.eep - @avr-size $(TARGET).elf + @echo -e "\n" + @avr-size -A -x $(TARGET).elf + @avr-size -B -x $(TARGET).elf + @echo -e "\n" + @avr-size -C -x $(TARGET).elf desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -DDEFAULT_CONFIGURATION=CONFIG_NONE desfire: desfire-build diff --git a/Firmware/Chameleon-Mini/Terminal/Terminal.h b/Firmware/Chameleon-Mini/Terminal/Terminal.h index b6e8c4a1..5351e923 100644 --- a/Firmware/Chameleon-Mini/Terminal/Terminal.h +++ b/Firmware/Chameleon-Mini/Terminal/Terminal.h @@ -17,7 +17,7 @@ #define TERMINAL_VBUS_MASK PIN5_bm #ifdef MEMORY_LIMITED_TESTING -#define TERMINAL_BUFFER_SIZE 384 +#define TERMINAL_BUFFER_SIZE 256 // 384 #else #define TERMINAL_BUFFER_SIZE 512 #endif From a0cb74cac8eea0c2b6e881e67d717df5f09aea1d Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 10:20:10 -0500 Subject: [PATCH 22/68] Adding in preliminary AES transfer functions -- Trying to save space for more where it can be pruned -- II --- Firmware/Chameleon-Mini/Log.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/Chameleon-Mini/Log.h b/Firmware/Chameleon-Mini/Log.h index 9c27562e..7b6b5241 100644 --- a/Firmware/Chameleon-Mini/Log.h +++ b/Firmware/Chameleon-Mini/Log.h @@ -4,7 +4,7 @@ #include "Common.h" #ifdef MEMORY_LIMITED_TESTING -#define LOG_SIZE 1284 // 1536 +#define LOG_SIZE 764 // 1536 #else #define LOG_SIZE 2048 #endif From de798fb01fcfe1a55e27b287f07b153178fd70e8 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 10:59:20 -0500 Subject: [PATCH 23/68] Adding in preliminary AES transfer functions -- Trying to save space for more where it can be pruned -- III -- cf. #313 --- Doc/DESFireSupportReadme.md | 17 -- .../DESFire/DESFireChameleonTerminal.c | 44 ---- .../DESFire/DESFireChameleonTerminal.h | 6 - .../DESFire/DESFireChameleonTerminalInclude.c | 12 - .../Application/DESFire/DESFireInstructions.c | 62 +++++ .../Application/DESFire/DESFireInstructions.h | 62 +---- .../DESFire/DESFirePICCHeaderLayout.c | 248 ------------------ .../DESFire/DESFirePICCHeaderLayout.h | 13 - .../Application/MifareDESFire.c | 15 +- Firmware/Chameleon-Mini/Makefile | 1 - 10 files changed, 75 insertions(+), 405 deletions(-) delete mode 100644 Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.c diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index b8782f9a..76981c55 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -204,23 +204,6 @@ DF_SETHDR=ATS 0675f7b102 ``` Note that the UID for the tag can be set using separate Chameleon terminal commands. -#### DF_PPRINT_PICC -- Visualize tag contents - -This lets users pretty print the tag layout in several different ways, and with -a couple of options for verbosity. This helps with visualizing the landscape that -we are programming. The syntax include: -```bash -DF_PPRINT_PICC FullImage -DF_PPRINT_PICC HeaderData -``` - -#### DF_FWINFO -- Print firmware revision information - -Self explanatory and similar to the familiar ``VERSION`` command. Syntax: -```bash -DF_FWINFO -``` - #### DF_LOGMODE -- Sets the depth of (LIVE) logging messages printed at runtime Syntax -- not guaranteeing that all of these are meaningful or distinct just yet: diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c index ac7b8e59..30dc9022 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c @@ -114,50 +114,6 @@ CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutParam, const char * } #endif /* DISABLE_PERMISSIVE_DESFIRE_SETTINGS */ -#if 0 -CommandStatusIdType CommandDESFireLayoutPPrint(char *OutParam, const char *InParams) { - if (!IsDESFireConfiguration()) { - ExitOnInvalidConfigurationError(OutParam); - } - char pprintListSpecStr[32]; - BYTE StatusError = 0x00; - if (!sscanf_P(InParams, PSTR("%31s"), pprintListSpecStr)) { - StatusError = 0x01; - } else { - pprintListSpecStr[31] = '\0'; - if (!strcasecmp_P(pprintListSpecStr, PSTR("FullImage"))) { - PrettyPrintPICCImageData((BYTE *) OutParam, TERMINAL_BUFFER_SIZE, 0x01); - } else if (!strcasecmp_P(pprintListSpecStr, PSTR("HeaderData"))) { - PrettyPrintPICCHeaderData((BYTE *) OutParam, TERMINAL_BUFFER_SIZE, 0x01); - } else { - StatusError = 0x01; - } - } - if (StatusError) { - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, - PSTR("%s "), - DFCOMMAND_LAYOUT_PPRINT); - return COMMAND_ERR_INVALID_USAGE_ID; - } - return COMMAND_INFO_OK_WITH_TEXT_ID; -} - -CommandStatusIdType CommandDESFireFirmwareInfo(char *OutParam) { - if (!IsDESFireConfiguration()) { - ExitOnInvalidConfigurationError(OutParam); - } - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, - PSTR("Chameleon-Mini DESFire enabled firmware built on %s " - "based on %s from \r\n" - "https://github.com/maxieds/ChameleonMini.\r\n" - "Revision: %s\r\n"), - DESFIRE_FIRMWARE_BUILD_TIMESTAMP, - DESFIRE_FIRMWARE_GIT_COMMIT_ID, - DESFIRE_FIRMWARE_REVISION); - return COMMAND_INFO_OK_WITH_TEXT_ID; -} -#endif - CommandStatusIdType CommandDESFireGetLoggingMode(char *OutParam) { if (!IsDESFireConfiguration()) { ExitOnInvalidConfigurationError(OutParam); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h index 82b61a18..22d8f19c 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h @@ -42,12 +42,6 @@ CommandStatusIdType CommandDESFireGetHeaderProperty(char *OutParam); CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutMessage, const char *InParams); #endif -//#define DFCOMMAND_LAYOUT_PPRINT "DF_PPRINT_PICC" -//CommandStatusIdType CommandDESFireLayoutPPrint(char *OutParam, const char *InParams); - -//#define DFCOMMAND_FIRMWARE_INFO "DF_FWINFO" -//CommandStatusIdType CommandDESFireFirmwareInfo(char *OutParam); - #define DFCOMMAND_LOGGING_MODE "DF_LOGMODE" CommandStatusIdType CommandDESFireGetLoggingMode(char *OutParam); CommandStatusIdType CommandDESFireSetLoggingMode(char *OutMessage, const char *InParams); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c index fcded7d3..41935c15 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c @@ -35,18 +35,6 @@ This notice must be retained at the top of all source files where indicated. .SetFunc = CommandDESFireSetHeaderProperty, .GetFunc = CommandDESFireGetHeaderProperty }, { -// .Command = DFCOMMAND_LAYOUT_PPRINT, -// .ExecFunc = NO_FUNCTION, -// .ExecParamFunc = CommandDESFireLayoutPPrint, -// .SetFunc = NO_FUNCTION, -// .GetFunc = NO_FUNCTION -//}, { -// .Command = DFCOMMAND_FIRMWARE_INFO, -// .ExecFunc = CommandDESFireFirmwareInfo, -// .ExecParamFunc = NO_FUNCTION, -// .SetFunc = NO_FUNCTION, -// .GetFunc = NO_FUNCTION -//}, { .Command = DFCOMMAND_LOGGING_MODE, .ExecFunc = NO_FUNCTION, .ExecParamFunc = NO_FUNCTION, diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 19108d23..89883f4e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -45,6 +45,68 @@ This notice must be retained at the top of all source files where indicated. DesfireSavedCommandStateType DesfireCommandState = { 0 }; +/* Helper and batch process functions */ +static uint16_t ExitWithStatus(uint8_t *Buffer, uint8_t StatusCode, uint16_t DefaultReturnValue); +uint16_t CmdNotImplemented(uint8_t *Buffer, uint16_t ByteCount); + +/* General commands */ +static uint16_t EV0CmdFormatPicc(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t DesfireCmdGetCardUID(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t DesfireCmdSetConfiguration(uint8_t *Buffer, uint16_t ByteCount); // ?? Docs ?? +static uint16_t DesfireCmdFreeMemory(uint8_t *Buffer, uint16_t ByteCount); // returns free memory on the tag + +/* Key management commands */ +static uint16_t EV0CmdChangeKey(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdGetKeySettings(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdChangeKeySettings(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t DesfireCmdGetKeyVersion(uint8_t *Buffer, uint16_t ByteCount); + +/* Application management commands */ +static uint16_t EV0CmdGetApplicationIds1(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdCreateApplication(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdDeleteApplication(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdSelectApplication(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t DesfireCmdGetDFNames(uint8_t *Buffer, uint16_t ByteCount); + +/* File management commands */ +static uint16_t EV0CmdCreateStandardDataFile(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdCreateBackupDataFile(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdCreateValueFile(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdCreateLinearRecordFile(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdCreateCyclicRecordFile(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdDeleteFile(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdGetFileIds(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdGetFileSettings(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdChangeFileSettings(uint8_t *Buffer, uint16_t ByteCount); + +/* Data manipulation commands */ +// NOTE: Page 57: Read file functions: +static uint16_t EV0CmdReadData(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdWriteData(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdGetValue(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdCredit(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdDebit(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdLimitedCredit(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdReadRecords(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdWriteRecord(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdClearRecords(uint8_t *Buffer, uint16_t ByteCount); + +/* Transaction handling commands */ +static uint16_t EV0CmdCommitTransaction(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t EV0CmdAbortTransaction(uint8_t *Buffer, uint16_t ByteCount); + +/* ISO7816 command handling */ +static uint16_t ISO7816CmdSelect(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t ISO7816CmdSelectEF(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t ISO7816CmdSelectDF(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t ISO7816CmdGetChallenge(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t ISO7816CmdExternalAuthenticate(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t ISO7816CmdInternalAuthenticate(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t ISO7816CmdReadBinary(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t ISO7816CmdUpdateBinary(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t ISO7816CmdReadRecords(uint8_t *Buffer, uint16_t ByteCount); +static uint16_t ISO7816CmdAppendRecord(uint8_t *Buffer, uint16_t ByteCount); + /* NOTE: The order of the structures in this buffer MUST be kept in * ascending sorted order by the INS code. This property of the * array has to be maintained as new commands and functions are diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h index fe6ea521..106a7dbb 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h @@ -122,81 +122,21 @@ extern const __flash DESFireCommand DESFireCommandSet[]; /* Helper and batch process functions */ uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount); -uint16_t ExitWithStatus(uint8_t *Buffer, uint8_t StatusCode, uint16_t DefaultReturnValue); -uint16_t CmdNotImplemented(uint8_t *Buffer, uint16_t ByteCount); /* * The following section implements: * DESFire EV0 / D40 specific commands */ -/* General commands */ uint16_t EV0CmdGetVersion1(uint8_t *Buffer, uint16_t ByteCount); uint16_t EV0CmdGetVersion2(uint8_t *Buffer, uint16_t ByteCount); uint16_t EV0CmdGetVersion3(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdFormatPicc(uint8_t *Buffer, uint16_t ByteCount); -uint16_t DesfireCmdGetCardUID(uint8_t *Buffer, uint16_t ByteCount); -uint16_t DesfireCmdSetConfiguration(uint8_t *Buffer, uint16_t ByteCount); // ?? Docs ?? -uint16_t DesfireCmdFreeMemory(uint8_t *Buffer, uint16_t ByteCount); // returns free memory on the tag - -/* Key management commands */ -uint16_t EV0CmdChangeKey(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdGetKeySettings(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdChangeKeySettings(uint8_t *Buffer, uint16_t ByteCount); -uint16_t DesfireCmdGetKeyVersion(uint8_t *Buffer, uint16_t ByteCount); - -/* Application management commands */ -uint16_t EV0CmdGetApplicationIds1(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdCreateApplication(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdDeleteApplication(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdSelectApplication(uint8_t *Buffer, uint16_t ByteCount); -uint16_t DesfireCmdGetDFNames(uint8_t *Buffer, uint16_t ByteCount); - -/* File management commands */ -uint16_t EV0CmdCreateStandardDataFile(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdCreateBackupDataFile(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdCreateValueFile(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdCreateLinearRecordFile(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdCreateCyclicRecordFile(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdDeleteFile(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdGetFileIds(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdGetFileSettings(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdChangeFileSettings(uint8_t *Buffer, uint16_t ByteCount); - -/* Data manipulation commands */ -// NOTE: Page 57: Read file functions: -uint16_t EV0CmdReadData(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdWriteData(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdGetValue(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdCredit(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdDebit(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdLimitedCredit(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdReadRecords(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdWriteRecord(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdClearRecords(uint8_t *Buffer, uint16_t ByteCount); - -/* Transaction handling commands */ -uint16_t EV0CmdCommitTransaction(uint8_t *Buffer, uint16_t ByteCount); -uint16_t EV0CmdAbortTransaction(uint8_t *Buffer, uint16_t ByteCount); - -/* EV1/EV2 supported commands */ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount); uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount); + uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount); uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount); uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount); uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount); -/* ISO7816 command handling */ -uint16_t ISO7816CmdSelect(uint8_t *Buffer, uint16_t ByteCount); -uint16_t ISO7816CmdSelectEF(uint8_t *Buffer, uint16_t ByteCount); -uint16_t ISO7816CmdSelectDF(uint8_t *Buffer, uint16_t ByteCount); -uint16_t ISO7816CmdGetChallenge(uint8_t *Buffer, uint16_t ByteCount); -uint16_t ISO7816CmdExternalAuthenticate(uint8_t *Buffer, uint16_t ByteCount); -uint16_t ISO7816CmdInternalAuthenticate(uint8_t *Buffer, uint16_t ByteCount); -uint16_t ISO7816CmdReadBinary(uint8_t *Buffer, uint16_t ByteCount); -uint16_t ISO7816CmdUpdateBinary(uint8_t *Buffer, uint16_t ByteCount); -uint16_t ISO7816CmdReadRecords(uint8_t *Buffer, uint16_t ByteCount); -uint16_t ISO7816CmdAppendRecord(uint8_t *Buffer, uint16_t ByteCount); - #endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.c deleted file mode 100644 index f0ab5439..00000000 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.c +++ /dev/null @@ -1,248 +0,0 @@ -/* -The DESFire stack portion of this firmware source -is free software written by Maxie Dion Schmidt (@maxieds): -You can redistribute it and/or modify -it under the terms of this license. - -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. - -The complete source distribution of -this firmware is available at the following link: -https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack. - -Based in part on the original DESFire code created by -@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at -https://github.com/dev-zzo/ChameleonMini/tree/desfire. - -This notice must be retained at the top of all source files where indicated. -*/ - -/* - * DESFirePICCHeaderLayout.c - * Maxie D. Schmidt (github.com/maxieds) - */ - -#ifdef CONFIG_MF_DESFIRE_SUPPORT - -#include "../../Common.h" - -#include "DESFirePICCHeaderLayout.h" -#include "DESFirePICCControl.h" -#include "DESFireFile.h" -#include "DESFireLogging.h" -#include "DESFireStatusCodes.h" - -SIZET PrettyPrintPICCHeaderData(BYTE *outputBuffer, SIZET maxLength, BYTE verbose) { - SIZET charsWritten = 0x00; - charsWritten = snprintf_P(outputBuffer, maxLength, - PSTR("(UID) %s\r\n"), - GetHexBytesString(Picc.Uid, DESFIRE_UID_SIZE)); - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR("(VERSION) HW=%02x.%02x, SW=%02x.%02x\r\n"), - Picc.HwVersionMajor, Picc.HwVersionMinor, - Picc.SwVersionMajor, Picc.SwVersionMinor); - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR("(BATCH) %s\r\n"), - GetHexBytesString(Picc.BatchNumber, 5)); - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR("(DATE) %02x/%02x\r\n"), - Picc.ProductionWeek, Picc.ProductionYear); - BYTE atsBytes[6]; - memcpy(&atsBytes[0], Picc.ATSBytes, 5); - atsBytes[5] = 0x80; - BufferToHexString(__InternalStringBuffer, STRING_BUFFER_SIZE, atsBytes, 6); - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR("(ATS) %s\r\n"), __InternalStringBuffer); - return charsWritten; -} - -SIZET PrettyPrintFileContentsData(BYTE *outputBuffer, SIZET maxLength, BYTE fileNumber) { - DESFireFileTypeSettings *fileData; - if (ReadFileControlBlock(fileNumber, &SelectedFile) != STATUS_OPERATION_OK) { - return 0; - } - fileData = &SelectedFile; - switch (fileData->FileType) { - case DESFIRE_FILE_STANDARD_DATA: - return snprintf_P(outputBuffer, maxLength, - PSTR(" STD-DATA @ % 3d bytes\r\n"), - fileData->FileSize); - case DESFIRE_FILE_BACKUP_DATA: - return snprintf_P(outputBuffer, maxLength, - PSTR(" BKUP-DATA @ % 3d bytes -- BlkCount = %d\r\n"), - fileData->FileSize, fileData->BackupFile.BlockCount); - case DESFIRE_FILE_VALUE_DATA: - return snprintf_P(outputBuffer, maxLength, - PSTR(" VALUE @ Cln=%d|Dty=%d (PrevDebit=%d) in [%d, %d] with LimitedCredit=%c\r\n"), - fileData->ValueFile.CleanValue, fileData->ValueFile.DirtyValue, fileData->ValueFile.PreviousDebit, - fileData->ValueFile.LowerLimit, fileData->ValueFile.UpperLimit, - fileData->ValueFile.LimitedCreditEnabled == 0 ? 'N' : 'Y'); - case DESFIRE_FILE_LINEAR_RECORDS: - case DESFIRE_FILE_CIRCULAR_RECORDS: - return snprintf_P(outputBuffer, maxLength, - PSTR(" RECORD @ [Type=%c] RcdSize=0x%06x|CurNumRcds=0x%06x|MaxRcds=0x%06x\r\n"), - fileData->FileType == DESFIRE_FILE_LINEAR_RECORDS ? 'L' : 'C', - GET_LE24(fileData->RecordFile.RecordSize), - GET_LE24(fileData->RecordFile.CurrentNumRecords), - GET_LE24(fileData->RecordFile.MaxRecordCount)); - default: - break; - } - return 0; -} - -SIZET PrettyPrintPICCFile(SelectedAppCacheType *appData, uint8_t fileIndex, - BYTE *outputBuffer, SIZET maxLength, BYTE verbose) { - BYTE charsWritten = 0x00; - BYTE fileNumber = LookupFileNumberByIndex(appData->Slot, fileIndex); - if (fileNumber >= DESFIRE_MAX_FILES) { - return charsWritten; - } - if (verbose) { - BYTE fileCommSettings = ReadFileCommSettings(appData->Slot, fileIndex); - SIZET fileAccessRights = ReadFileAccessRights(appData->Slot, fileIndex); - strncpy_P(__InternalStringBuffer2, GetCommSettingsDesc(fileCommSettings), DATA_BUFFER_SIZE_SMALL); - __InternalStringBuffer2[DATA_BUFFER_SIZE_SMALL - 1] = '\0'; - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR(" -> No. %02x [Comm=%s -- Perms=%s]\r\n"), - fileNumber, __InternalStringBuffer2, - GetFileAccessPermissionsDesc(fileAccessRights)); - //charsWritten += PrettyPrintFileContentsData(outputBuffer + charsWritten, maxLength - charsWritten, fileIndex); - } else { - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR(" -> No. %02x\r\n"), - fileNumber); - } - return charsWritten; -} - -SIZET PrettyPrintPICCFilesFull(SelectedAppCacheType *appData, BYTE *outputBuffer, SIZET maxLength, BYTE verbose) { - SIZET charsWritten = 0x00; - BYTE fileIndex; - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR(" [FILES -- %d of %d]\r\n"), - appData->FileCount, DESFIRE_MAX_FILES); - uint8_t fileNumberIndexMap[DESFIRE_MAX_FILES]; - ReadBlockBytes(&fileNumberIndexMap, appData->FileNumbersArrayMap, DESFIRE_MAX_FILES); - for (fileIndex = 0; fileIndex < DESFIRE_MAX_FILES; fileIndex++) { - if (fileNumberIndexMap[fileIndex] == DESFIRE_FILE_NOFILE_INDEX) { - continue; - } - charsWritten += PrettyPrintPICCFile(appData, fileIndex, outputBuffer + charsWritten, - maxLength - charsWritten, verbose); - } - return charsWritten; -} - -SIZET PrettyPrintPICCKey(SelectedAppCacheType *appData, uint8_t keyIndex, - BYTE *outputBuffer, SIZET maxLength, BYTE verbose) { - if (!KeyIdValid(appData->Slot, keyIndex)) { - return 0x00; - } - BYTE charsWritten = 0x00; - BYTE keySettings = ReadKeySettings(appData->Slot, keyIndex); - BYTE keyVersion = ReadKeyVersion(appData->Slot, keyIndex); - BYTE keyType = ReadKeyCryptoType(appData->Slot, keyIndex); - strncpy_P(__InternalStringBuffer, GetCryptoMethodDesc(keyType), STRING_BUFFER_SIZE); - __InternalStringBuffer[STRING_BUFFER_SIZE - 1] = '\0'; - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR(" -> No. %02x (%s) [v% 2d"), - keyIndex, __InternalStringBuffer, keyVersion); - if ((appData->Slot == DESFIRE_PICC_APP_SLOT) && (keyIndex == DESFIRE_MASTER_KEY_ID)) { - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR(" -- PMK")); - if (verbose) { - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR(" -- S=%02x"), keySettings); - } - } else if (keyIndex == DESFIRE_MASTER_KEY_ID) { - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR(" -- AMK")); - if (verbose) { - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR(" -- S=%02x"), keySettings); - } - } else if (verbose) { - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR(" -- %02d"), keySettings); - } - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR("]\r\n")); - /*if(verbose) { - uint8_t keySize = GetDefaultCryptoMethodKeySize(keyType); - uint8_t keyData[keySize]; - ReadAppKey(appData->Slot, keyIndex, &keyData[0], keySize); - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR(" KeyData @ % 2 bytes = "), - keySize); - charsWritten += BufferToHexString(outputBuffer + charsWritten, maxLength - charsWritten, keyData, keySize); - charsWritten += snprintf(outputBuffer + charsWritten, maxLength - charsWritten, PSTR("\r\n")); - }*/ - return charsWritten; -} - -SIZET PrettyPrintPICCKeysFull(SelectedAppCacheType *appData, BYTE *outputBuffer, SIZET maxLength, BYTE verbose) { - SIZET charsWritten = 0x00; - BYTE keyIndex; - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR(" [KEYS -- %d of %d]\r\n"), - appData->KeyCount, appData->MaxKeyCount); - uint16_t keyDataAddresses[DESFIRE_MAX_KEYS]; - ReadBlockBytes(&keyDataAddresses, ReadKeyStorageAddress(appData->Slot), 2 * DESFIRE_MAX_KEYS); - for (keyIndex = 0; keyIndex < DESFIRE_MAX_KEYS; keyIndex++) { - if (keyDataAddresses[keyIndex] == 0) { - continue; - } - charsWritten += PrettyPrintPICCKey(appData, keyIndex, outputBuffer + charsWritten, - maxLength - charsWritten, verbose); - } - return charsWritten; -} - -SIZET PrettyPrintPICCAppDir(uint8_t appIndex, BYTE *outputBuffer, SIZET maxLength, BYTE verbose) { - SIZET charsWritten = 0x00; - BYTE keyIndex, fileIndex; - SelectedAppCacheType appData; - if (!GetAppData(appIndex, &appData)) { - return charsWritten; - } - appData.Slot = appIndex; - charsWritten += PrettyPrintPICCKeysFull(&appData, outputBuffer + charsWritten, - maxLength - charsWritten, verbose); - if (appIndex == 0) { // master - return charsWritten; - } - charsWritten += PrettyPrintPICCFilesFull(&appData, outputBuffer + charsWritten, - maxLength - charsWritten, verbose); - return charsWritten; -} - -SIZET PrettyPrintPICCAppDirsFull(BYTE *outputBuffer, SIZET maxLength, BYTE verbose) { - SIZET charsWritten = 0x00; - BYTE appDirIndex; - for (appDirIndex = 0; appDirIndex < DESFIRE_MAX_SLOTS; appDirIndex++) { - DESFireAidType curAID; - memcpy(curAID, AppDir.AppIds[appDirIndex], MAX_AID_SIZE); - if ((curAID[0] | curAID[1] | curAID[2]) == 0x00 && appDirIndex > 0) { - continue; - } - charsWritten += snprintf_P(outputBuffer + charsWritten, maxLength - charsWritten, - PSTR("== AID 0x%02x%02x%02x\r\n"), - curAID[0], curAID[1], curAID[2]); - charsWritten += PrettyPrintPICCAppDir(appDirIndex, outputBuffer + charsWritten, - maxLength - charsWritten, verbose); - } - return charsWritten; -} - -SIZET PrettyPrintPICCImageData(BYTE *outputBuffer, SIZET maxLength, BYTE verbose) { - BYTE charsWritten = 0x00; - charsWritten += PrettyPrintPICCHeaderData(outputBuffer + charsWritten, maxLength - charsWritten, verbose); - charsWritten += PrettyPrintPICCAppDirsFull(outputBuffer + charsWritten, maxLength - charsWritten, verbose); - outputBuffer[maxLength - 1] = '\0'; - return charsWritten; -} - -#endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index 5d5c06e7..db6abd1b 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -228,17 +228,4 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { DESFIRE_APP_KEYS_PTR_BLOCK_ID, } DesfireCardLayout; -SIZET PrettyPrintPICCHeaderData(BYTE *outputBuffer, SIZET maxLength, BYTE verbose); -SIZET PrettyPrintFileContentsData(BYTE *outputBuffer, SIZET maxLength, BYTE fileNumber); -SIZET PrettyPrintPICCFile(SelectedAppCacheType *appData, uint8_t fileIndex, - BYTE *outputBuffer, SIZET maxLength, BYTE verbose); -SIZET PrettyPrintPICCFilesFull(SelectedAppCacheType *appData, BYTE *outputBuffer, SIZET maxLength, BYTE verbose); -SIZET PrettyPrintPICCKey(SelectedAppCacheType *appData, uint8_t keyIndex, - BYTE *outputBuffer, SIZET maxLength, BYTE verbose); -SIZET PrettyPrintPICCKeysFull(SelectedAppCacheType *appData, BYTE *outputBuffer, SIZET maxLength, BYTE verbose); -SIZET PrettyPrintPICCAppDir(uint8_t appIndex, - BYTE *outputBuffer, SIZET maxLength, BYTE verbose); -SIZET PrettyPrintPICCAppDirsFull(BYTE *outputBuffer, SIZET maxLength, BYTE verbose); -SIZET PrettyPrintPICCImageData(BYTE *outputBuffer, SIZET maxLength, BYTE verbose); - #endif diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 37694857..3f9f2712 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -51,9 +51,12 @@ DesfireStateType DesfireState = DESFIRE_HALT; DesfireStateType DesfirePreviousState = DESFIRE_IDLE; bool DesfireFromHalt = false; BYTE DesfireCmdCLA = DESFIRE_NATIVE_CLA; +static bool AnticolNoResp = false; /* Dispatching routines */ -void MifareDesfireReset(void) {} +void MifareDesfireReset(void) { + AnticolNoResp = false; +} static void MifareDesfireAppInitLocal(uint8_t StorageSize, uint8_t Version, bool FormatPICC) { ResetLocalStructureData(); @@ -247,12 +250,18 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { return ProcessedBitCount; } else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { return ReturnedBytes; - } else { - return ISO144433APiccProcess(Buffer, BitCount); + } else if (!AnticolNoResp) { + uint16_t PiccProcessRespBytes = ISO144433APiccProcess(Buffer, BitCount); + if (PiccProcessRespBytes == ISO14443A_APP_NO_RESPONSE) { + AnticolNoResp = true; + } + return PiccProcessRespBytes; } + return ISO14443A_APP_NO_RESPONSE; } void ResetLocalStructureData(void) { + AnticolNoResp = false; DesfirePreviousState = DESFIRE_IDLE; DesfireState = DESFIRE_HALT; InvalidateAuthState(0x00); diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 7b5495cd..1a08f417 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -182,7 +182,6 @@ SRC += $(DESFIRE_MAINSRC)/../MifareDESFire.c \ $(DESFIRE_MAINSRC)/DESFireLogging.c \ $(DESFIRE_MAINSRC)/DESFireMemoryOperations.c \ $(DESFIRE_MAINSRC)/DESFirePICCControl.c \ - $(DESFIRE_MAINSRC)/DESFirePICCHeaderLayout.c \ $(DESFIRE_MAINSRC)/DESFireUtils.c SRC += $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) LUFA_PATH = ../LUFA From e9ce4ac76607354bf22574e80636c9ead13486d1 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 14:43:01 -0500 Subject: [PATCH 24/68] Untested CMAC implementation for CommMode=FULL exchanges (Enciphered+CMAC'ed data) --- .../Chameleon-Mini/Application/CryptoCMAC.c | 129 ++++++++++++++++++ .../Chameleon-Mini/Application/CryptoCMAC.h | 10 +- Firmware/Chameleon-Mini/Makefile | 2 +- 3 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 Firmware/Chameleon-Mini/Application/CryptoCMAC.c diff --git a/Firmware/Chameleon-Mini/Application/CryptoCMAC.c b/Firmware/Chameleon-Mini/Application/CryptoCMAC.c new file mode 100644 index 00000000..63b0cda0 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/CryptoCMAC.c @@ -0,0 +1,129 @@ +/* +The DESFire stack portion of this firmware source +is free software written by Maxie Dion Schmidt (@maxieds): +You can redistribute it and/or modify +it under the terms of this license. + +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. + +The complete source distribution of +this firmware is available at the following link: +https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack. + +Based in part on the original DESFire code created by +@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at +https://github.com/dev-zzo/ChameleonMini/tree/desfire. + +This notice must be retained at the top of all source files where indicated. +*/ + +/* + * CryptoCMAC.h : + * Maxie D. Schmidt (github.com/maxieds) + */ + +#include + +#include "CryptoCMAC.h" +#include "DESFire/DESFireUtils.h" +#include "DESFire/DESFireCrypto.h" +#include "CryptoTDEA.h" +#include "CryptoAES128.h" + +static uint8_t _cmac_K1[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; +static uint8_t _cmac_K2[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; +static uint8_t _cmac_RB[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; +static uint8_t _cmac_final[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; +static uint8_t _cmac_zeros[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; + +static void getCMACSubK1(const uint8_t *bufferL, uint8_t blockSize, uint8_t polyByte, uint8_t *bufferOut); +static void getCMACSubK1(const uint8_t *bufferL, uint8_t blockSize, uint8_t polyByte, uint8_t *bufferOut) { + _cmac_RB[blockSize - 1] = polyByte; + RotateArrayLeft(bufferL, bufferOut, blockSize); + if ((bufferL[0] & 0x80) != 0) { + for (int kidx = 0; kidx < blockSize; kidx++) { + bufferOut[kidx] = (uint8_t) (bufferOut[kidx] ^ _cmac_RB[kidx]); + } + } +} + +static void getCMACSubK2(const uint8_t *bufferK1, uint8_t blockSize, uint8_t polyByte, uint8_t *bufferOut); +static void getCMACSubK2(const uint8_t *bufferK1, uint8_t blockSize, uint8_t polyByte, uint8_t *bufferOut) { + _cmac_RB[blockSize - 1] = polyByte; + RotateArrayLeft(bufferK1, bufferOut, blockSize); + if ((bufferK1[0] & 0x80) != 0) { + for (int kidx = 0; kidx < blockSize; kidx++) { + bufferOut[kidx] = (uint8_t) (bufferOut[kidx] ^ _cmac_RB[kidx]); + } + } +} + +static bool appendBufferCMACSubroutine(uint8_t cryptoType, const uint8_t *keyData, uint8_t *bufferK1, uint8_t *bufferK2, uint8_t *bufferIV, uint8_t blockSize, uint8_t *bufferOut, uint16_t bufferSize); +static bool appendBufferCMACSubroutine(uint8_t cryptoType, const uint8_t *keyData, uint8_t *bufferK1, uint8_t *bufferK2, uint8_t *bufferIV, uint8_t blockSize, uint8_t *bufferOut, uint16_t bufferSize) { + uint16_t newBlockSize = bufferSize; + if (bufferSize == 0) { + memset(bufferOut, 0x00, blockSize); + bufferOut[0] = (uint8_t) 0x80; + newBlockSize = blockSize; + } else if ((bufferSize % blockSize) != 0) { + newBlockSize = bufferSize - (bufferSize % blockSize) + blockSize; + bufferOut[bufferSize] = (uint8_t) 0x80; + } + if (bufferSize != 0 && (bufferSize % blockSize) == 0) { + // Complete block (use K1): + for (int i = bufferSize - blockSize; i < bufferSize; i++) { + bufferOut[i] ^= bufferK1[i - bufferSize + blockSize]; + } + } else { + // Incomplete block (use K2): + for (int i = bufferSize - blockSize; i < bufferSize; i++) { + bufferOut[i] ^= bufferK2[i - bufferSize + blockSize]; + } + } + switch (cryptoType) { + case CRYPTO_TYPE_3K3DES: + Encrypt3DESBuffer(newBlockSize, bufferOut, bufferOut + bufferSize, keyData, bufferIV); + break; + case CRYPTO_TYPE_AES128: + CryptoAESEncryptBuffer(newBlockSize, bufferOut, bufferOut + bufferSize, keyData, bufferIV); + break; + default: + return false; + } + memmove(&bufferOut[0], &bufferOut[newBlockSize], newBlockSize); + memcpy(_cmac_final, &bufferOut[newBlockSize - blockSize], blockSize); + memcpy(&bufferOut[newBlockSize], _cmac_final, blockSize); + return true; +} + +bool appendBufferCMAC(uint8_t cryptoType, const uint8_t *keyData, uint8_t *bufferData, uint16_t bufferSize, uint8_t *IV) { + uint8_t blockSize, rb; + uint8_t *nistL = _cmac_K2; + switch (cryptoType) { + case CRYPTO_TYPE_3K3DES: + blockSize = CRYPTO_3KTDEA_BLOCK_SIZE; + rb = CRYPTO_CMAC_RB64; + memset(_cmac_zeros, 0x00, blockSize); + Encrypt3DESBuffer(blockSize, _cmac_zeros, nistL, _cmac_zeros, keyData); + break; + case CRYPTO_TYPE_AES128: + blockSize = CRYPTO_AES_BLOCK_SIZE; + rb = CRYPTO_CMAC_RB128; + memset(_cmac_zeros, 0x00, blockSize); + CryptoAESEncryptBuffer(blockSize, _cmac_zeros, nistL, _cmac_zeros, keyData); + break; + default: + return false; + } + getCMACSubK1(nistL, blockSize, rb, _cmac_K1); + getCMACSubK2(_cmac_K1, blockSize, rb, _cmac_K2); + if (IV == NULL) { + IV = _cmac_zeros; + memset(IV, 0x00, blockSize); + return appendBufferCMACSubroutine(cryptoType, keyData, _cmac_K1, _cmac_K2, IV, blockSize, bufferData, bufferSize); + } else { + return appendBufferCMACSubroutine(cryptoType, keyData, _cmac_K1, _cmac_K2, IV, blockSize, bufferData, bufferSize); + } +} diff --git a/Firmware/Chameleon-Mini/Application/CryptoCMAC.h b/Firmware/Chameleon-Mini/Application/CryptoCMAC.h index ab590467..d909ab40 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoCMAC.h +++ b/Firmware/Chameleon-Mini/Application/CryptoCMAC.h @@ -31,17 +31,11 @@ This notice must be retained at the top of all source files where indicated. #include "CryptoTDEA.h" #include "CryptoAES128.h" -/* MAC and CMAC source code based on github/andrade/nfcjlib */ +/* MAC and CMAC source code based on @github/andrade/nfcjlib */ #define CRYPTO_CMAC_RB64 (0x1B) #define CRYPTO_CMAC_RB128 ((uint8_t) 0x87) -void getCMACSubK1(uint8_t *bufferL, uint16_t blockSize, uint8_t polyByte, uint8_t *bufferOut); -void getCMACSubK2(uint8_t *bufferK1, uint16_t blockSize, uint8_t polyByte, uint8_t *bufferOut); - -bool computeBufferCMACFull(uint8_t *keyData, uint8_t *bufferK1, uint8_t *bufferK2, uint8_t *bufferIV, uint16_t blockSize, uint16_t cryptoType); -bool computeBufferCMAC(uint16_t cryptoType, uint8_t *keyData, uint8_t *bufferData, uint8_t *aesIV); - -bool computeMac(uint8_t *bufferData, uint16_t dataLength, uint8_t *keyData, uint16_t cryptoKeyType); +bool appendBufferCMAC(uint8_t cryptoType, const uint8_t *keyData, uint8_t *bufferData, uint16_t bufferSize, uint8_t *IV); #endif diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 1a08f417..b879f71c 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -166,7 +166,7 @@ SRC += Terminal/Terminal.c Terminal/Commands.c Terminal/XModem.c Termina 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 \ - Application/CryptoTDEA-HWAccelerated.S Application/CryptoTDEA.c Application/CryptoAES128.c \ + Application/CryptoTDEA-HWAccelerated.S Application/CryptoTDEA.c Application/CryptoAES128.c Application/CryptoCMAC.c \ Tests/CryptoTests.c Tests/ChameleonTerminal.c SRC += Application/NTAG215.c SRC += Codec/ISO15693.c From e9437a67391b1900fff780c45b89c1a2022ae366 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 18:52:10 -0500 Subject: [PATCH 25/68] Preliminary (partial) support for more CommModes -- This is going to need substantial testing --- Doc/DESFireSupportReadme.md | 23 ++++++ .../Chameleon-Mini/Application/CryptoAES128.c | 20 +++++ .../Chameleon-Mini/Application/CryptoAES128.h | 10 ++- .../Chameleon-Mini/Application/CryptoCMAC.c | 13 +++ .../Chameleon-Mini/Application/CryptoCMAC.h | 4 +- .../DESFire/DESFireChameleonTerminal.c | 10 ++- .../Application/DESFire/DESFireUtils.c | 81 +++++++++++++++++++ .../Application/DESFire/DESFireUtils.h | 19 +++++ .../Application/MifareDESFire.c | 48 ++++++----- 9 files changed, 205 insertions(+), 23 deletions(-) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index 76981c55..c771d56e 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -204,6 +204,29 @@ DF_SETHDR=ATS 0675f7b102 ``` Note that the UID for the tag can be set using separate Chameleon terminal commands. +#### DF_COMM_MODE -- Manually sets the communication mode of the current session + +The supported (work in progress) DESFire communication modes include: +PLAINTEXT, PLAINTEXT-MAC, ENCIPHERED-CMAC-3DES, and ENCIPHERED-CMAC-AES128. +It should be clear from the prior commands issued in the session which ``CommMode`` +congiguration we are supposed to be working within. This command let's the user +reset it intentionally at will for testing and debugging purposes. + +The syntax is as follows: +```bash +DF_COMM_MODE? +DF_COMM_MODE=Plaintext +DF_COMM_MODE=Plaintext:MAC +DF_COMM_MODE=Enciphered:3K3DES +DF_COMM_MODE=Enciphered:AES128 +``` +Use of this experimental command may cause unexpected results, vulnerabilities exposing +your keys and sensitive (a priori) protected data to hackers and sniffers, and is +discouraged unless you know what you are doing :) Try not to report bugs with the +DESFire emulation if things suddenly fail after a call to this terminal command. +Putting the Chameleon through a full power recycle (battery off) should reset the setting +to the defaults. + #### DF_LOGMODE -- Sets the depth of (LIVE) logging messages printed at runtime Syntax -- not guaranteeing that all of these are meaningful or distinct just yet: diff --git a/Firmware/Chameleon-Mini/Application/CryptoAES128.c b/Firmware/Chameleon-Mini/Application/CryptoAES128.c index 5d992e00..c931d838 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoAES128.c +++ b/Firmware/Chameleon-Mini/Application/CryptoAES128.c @@ -384,3 +384,23 @@ void CryptoAESEncrypt_CBCReceive(uint16_t Count, uint8_t *PlainText, uint8_t *Ci }; CryptoAES_CBCRecv(Count, PlainText, CipherText, IV, Key, CryptoSpec); } + +uint16_t appendBufferCRC32C(uint8_t *bufferData, uint16_t bufferSize) { + uint32_t workingCRC = INIT_CRC32C_VALUE; + for (int i = 0; i < bufferSize; i++) { + workingCRC = workingCRC ^ *(bufferData++); + for (int j = 0; j < 8; j++) { + if (workingCRC & 1) { + workingCRC = (workingCRC >> 1) ^ LE_CRC32C_POLYNOMIAL; + } else { + workingCRC = workingCRC >> 1; + } + } + } + // Append the CRC32C bytes in little endian byte order to the end of the buffer: + bufferData[bufferSize] = (uint8_t) (workingCRC & 0x000000FF); + bufferData[bufferSize + 1] = (uint8_t) ((workingCRC & 0x0000FF00) >> 8); + bufferData[bufferSize + 2] = (uint8_t) ((workingCRC & 0x00FF0000) >> 16); + bufferData[bufferSize + 4] = (uint8_t) ((workingCRC & 0xFF000000) >> 24); + return bufferSize + 4; +} diff --git a/Firmware/Chameleon-Mini/Application/CryptoAES128.h b/Firmware/Chameleon-Mini/Application/CryptoAES128.h index 75844ce7..20ccca8c 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoAES128.h +++ b/Firmware/Chameleon-Mini/Application/CryptoAES128.h @@ -163,7 +163,7 @@ void CryptoAESEncrypt_CBCSend(uint16_t Count, uint8_t *PlainText, uint8_t *Ciphe uint8_t *Key, uint8_t *IV); /* Crypto utility functions: */ -#define CRYPTO_BYTES_TO_BLOCKS(numBytes, blockSize) \ +#define CRYPTO_BYTES_TO_BLOCKS(numBytes, blockSize) \ ( ((numBytes) + (blockSize) - 1) / (blockSize) ) #define CryptoMemoryXOR(inputBuf, destBuf, bufSize) ({ \ @@ -175,4 +175,12 @@ void CryptoAESEncrypt_CBCSend(uint16_t Count, uint8_t *PlainText, uint8_t *Ciphe } \ }) +/* The initial value is (-1) in one's complement: */ +#define INIT_CRC32C_VALUE ((uint32_t) 0xFFFFFFFF) + +/* The CCITT CRC-32 polynomial (modulo 2) in little endian (lsb-first) byte order: */ +#define LE_CRC32C_POLYNOMIAL ((uint32_t) 0xEDB88320) + +uint16_t appendBufferCRC32C(uint8_t *bufferData, uint16_t bufferSize); + #endif diff --git a/Firmware/Chameleon-Mini/Application/CryptoCMAC.c b/Firmware/Chameleon-Mini/Application/CryptoCMAC.c index 63b0cda0..c78526df 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoCMAC.c +++ b/Firmware/Chameleon-Mini/Application/CryptoCMAC.c @@ -37,6 +37,7 @@ static uint8_t _cmac_K2[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; static uint8_t _cmac_RB[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; static uint8_t _cmac_final[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; static uint8_t _cmac_zeros[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; +static uint8_t _mac_key24[CRYPTO_MAX_KEY_SIZE] = { 0x00 }; static void getCMACSubK1(const uint8_t *bufferL, uint8_t blockSize, uint8_t polyByte, uint8_t *bufferOut); static void getCMACSubK1(const uint8_t *bufferL, uint8_t blockSize, uint8_t polyByte, uint8_t *bufferOut) { @@ -127,3 +128,15 @@ bool appendBufferCMAC(uint8_t cryptoType, const uint8_t *keyData, uint8_t *buffe return appendBufferCMACSubroutine(cryptoType, keyData, _cmac_K1, _cmac_K2, IV, blockSize, bufferData, bufferSize); } } + +uint16_t appendBufferMAC(const uint8_t *keyData, uint8_t *bufferData, uint16_t bufferSize) { + memcpy(&_mac_key24[2 * CRYPTO_DES_BLOCK_SIZE], keyData, CRYPTO_DES_BLOCK_SIZE); + memcpy(&_mac_key24[CRYPTO_DES_BLOCK_SIZE], keyData, CRYPTO_DES_BLOCK_SIZE); + memcpy(&_mac_key24[0], keyData, CRYPTO_DES_BLOCK_SIZE); + memset(&_cmac_zeros[0], 0x00, CRYPTO_DES_BLOCK_SIZE); + Encrypt3DESBuffer(bufferSize, bufferData, &bufferData[3 * CRYPTO_DES_BLOCK_SIZE], _cmac_zeros, keyData); + // Copy the 4-byte MAC from the ciphertext (end of the bufferData array): + memcpy(&_cmac_zeros[0], &bufferData[3 * CRYPTO_DES_BLOCK_SIZE + bufferSize - CRYPTO_DES_BLOCK_SIZE], 4); + memcpy(&bufferData[bufferSize], &_cmac_zeros[0], 4); + return bufferSize + 4; +} diff --git a/Firmware/Chameleon-Mini/Application/CryptoCMAC.h b/Firmware/Chameleon-Mini/Application/CryptoCMAC.h index d909ab40..aaf9e5a0 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoCMAC.h +++ b/Firmware/Chameleon-Mini/Application/CryptoCMAC.h @@ -31,11 +31,13 @@ This notice must be retained at the top of all source files where indicated. #include "CryptoTDEA.h" #include "CryptoAES128.h" -/* MAC and CMAC source code based on @github/andrade/nfcjlib */ +/* CMAC and MAC source code based on @github/andrade/nfcjlib */ #define CRYPTO_CMAC_RB64 (0x1B) #define CRYPTO_CMAC_RB128 ((uint8_t) 0x87) bool appendBufferCMAC(uint8_t cryptoType, const uint8_t *keyData, uint8_t *bufferData, uint16_t bufferSize, uint8_t *IV); +uint16_t appendBufferMAC(const uint8_t *keyData, uint8_t *bufferData, uint16_t bufferSize); + #endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c index 30dc9022..f8997814 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c @@ -225,16 +225,20 @@ CommandStatusIdType CommandDESFireSetCommMode(char *OutParam, const char *InPara valueStr[15] = '\0'; if (!strcasecmp_P(valueStr, PSTR("Plaintext"))) { DesfireCommMode = DESFIRE_COMMS_PLAINTEXT; - return COMMAND_INFO_OK; + DesfireCommandState.ActiveCommMode = DesfireCommMode; + return COMMAND_INFO_OK; } else if (!strcasecmp_P(valueStr, PSTR("Plaintext:MAC"))) { DesfireCommMode = DESFIRE_COMMS_PLAINTEXT_MAC; + DesfireCommandState.ActiveCommMode = DesfireCommMode; return COMMAND_INFO_OK; } else if (!strcasecmp_P(valueStr, PSTR("Enciphered:3K3DES"))) { DesfireCommMode = DESFIRE_COMMS_CIPHERTEXT_DES; - return COMMAND_INFO_OK; + DesfireCommandState.ActiveCommMode = DesfireCommMode; + return COMMAND_INFO_OK; } else if (!strcasecmp_P(valueStr, PSTR("Enciphered:AES128"))) { DesfireCommMode = DESFIRE_COMMS_CIPHERTEXT_AES128; - return COMMAND_INFO_OK; + DesfireCommandState.ActiveCommMode = DesfireCommMode; + return COMMAND_INFO_OK; } snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Options are: Plaintext|Plaintext:MAC|Enciphered:3K3DES|Enciphered:AES128")); return COMMAND_ERR_INVALID_USAGE_ID; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c index c29c3361..97edf1b3 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c @@ -146,4 +146,85 @@ bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount) { return true; } +uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) { + switch (CommMode) { + case DESFIRE_COMMS_PLAINTEXT: + // Remove the CRCA bytes at the end of the buffer: + return MAX(0, BufferSize - 2); + case DESFIRE_COMMS_PLAINTEXT_MAC: { + // TODO: We are not checking the MAC/CMAC bytes for consistency yet ... + uint16_t ChecksumBytes = 0; + if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { + ChecksumBytes = 4; + } + else if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_3K3DES) { + ChecksumBytes = CRYPTO_3KTDEA_BLOCK_SIZE; + } else { + ChecksumBytes = CRYPTO_AES128_BLOCK_SIZE; + } + return MAX(0, BufferSize - ChecksumBytes); + } + case DESFIRE_COMMS_CIPHERTEXT_DES: { + // TODO ... + break; + } + case DESFIRE_COMMS_CIPHERTEXT_AES128: { + // TODO ... + break; + } + default: + break; + } + return BufferSize; +} + +uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) { + switch (CommMode) { + case DESFIRE_COMMS_PLAINTEXT: + ISO14443AAppendCRCA(Buffer, BufferSize); + return BufferSize + 2; + case DESFIRE_COMMS_PLAINTEXT_MAC: { + if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { + return appendBufferMAC(SessionKey, Buffer, BufferSize); + } else { + // AES-128 or 3DES: + uint16_t MacedBytes = appendBufferCMAC(DesfireCommandState.CryptoMethodType, SessionKey, Buffer, BufferSize, SessionIV); + memcpy(SessionIV, &Buffer[BufferSize], MacedBytes - BufferSize); + return MacedBytes; + } + break; + } + case DESFIRE_COMMS_CIPHERTEXT_DES: { + // TripleDES: + uint16_t CryptoBlockSize = CRYPTO_3KTDEA_BLOCK_SIZE; + uint16_t BlockPadding = 0; + if ((BufferSize % CryptoBlockSize) != 0) { + BlockPadding = CryptoBlockSize - (BufferSize % CryptoBlockSize); + } + uint16_t MacedBytes = appendBufferCMAC(CRYPTO_TYPE_3K3DES, SessionKey, Buffer, BufferSize, SessionIV); + memset(&Buffer[MacedBytes], 0x00, BlockPadding); + uint16_t XferBytes = MacedBytes + BlockPadding; + Encrypt3DESBuffer(XferBytes, Buffer, &Buffer[XferBytes], SessionIV, SessionKey); + memmove(&Buffer[0], &Buffer[XferBytes], XferBytes); + return XferBytes; + } + case DESFIRE_COMMS_CIPHERTEXT_AES128: { + uint16_t CryptoBlockSize = CRYPTO_AES_BLOCK_SIZE; + uint16_t BlockPadding = 0; + if ((BufferSize % CryptoBlockSize) != 0) { + BlockPadding = CryptoBlockSize - (BufferSize % CryptoBlockSize); + } + uint16_t MacedBytes = appendBufferCMAC(CRYPTO_TYPE_AES128, SessionKey, Buffer, BufferSize, SessionIV); + memset(&Buffer[MacedBytes], 0x00, BlockPadding); + uint16_t XferBytes = MacedBytes + BlockPadding; + CryptoAESEncryptBuffer(XferBytes, Buffer, &Buffer[XferBytes], SessionIV, SessionKey); + memmove(&Buffer[0], &Buffer[XferBytes], XferBytes); + return XferBytes; + } + default: + break; + } + return BufferSize; +} + #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h index 9622772e..0b81298e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h @@ -53,4 +53,23 @@ uint16_t DesfireAddParityBits(uint8_t *Buffer, uint16_t bits); uint16_t DesfireRemoveParityBits(uint8_t *Buffer, uint16_t BitCount); bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount); +/* Add utility wrapper functions to perform pre and postprocessing on + * the raw input APDU commands sent by the PCD depending on which + * CommMode (PLAINTEXT|PLAINTEXT-MAC|ENCIPHERED-CMAC-3DES|ECIPHERED-CMAC-AES128) + * setting is active. + * + * The implementation is adapted from the Java sources at + * @github/andrade/nfcjlib (in the DESFireEV1 source files). + * We will use the conventions in that library to update the SessionIV buffer + * when the next rounds of data are exchanged. Note that the SessionIV and + * SessionKey arrays are initialized in the Authenticate(Legacy|ISO|AES) commands + * used to initiate the working session from PCD <--> PICC. + * + * Helper methods to format and encode quirky or pathological cases of the + * CommSettings and wrapped APDU format combinations are defined statically in the + * C source file to save space in the symbol table for the firmware (ELF) binary. + */ +uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize); +uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize); + #endif diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 3f9f2712..1e5ffbc9 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -194,22 +194,15 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[0] = Buffer[1]; memmove(&Buffer[1], &Buffer[5], ByteCount); /* Process the command */ - /* TODO: Where are we deciphering wrapped payload data? - * This should depend on the CommMode standard? - */ ByteCount = MifareDesfireProcessCommand(Buffer, ByteCount + 1); - /* TODO: Where are we re-wrapping the data according to the CommMode standards? */ if ((ByteCount != 0 && !Iso7816CLA(DesfireCmdCLA)) || (ByteCount == 1)) { /* Re-wrap into padded APDU form */ Buffer[ByteCount] = Buffer[0]; memmove(&Buffer[0], &Buffer[1], ByteCount - 1); Buffer[ByteCount - 1] = 0x91; - ISO14443AAppendCRCA(Buffer, ++ByteCount); - ByteCount += 2; + ++ByteCount; } else { /* Re-wrap into ISO 7816-4 */ - ISO14443AAppendCRCA(Buffer, ByteCount); - ByteCount += 2; } //LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); return ByteCount * BITS_PER_BYTE; @@ -223,12 +216,19 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; uint16_t ReturnedBytes = 0; - if (ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) { - return MifareDesfireProcess(Buffer, BitCount); - } else if (ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && + /* Is this first case really just a padded ISO7816 APDU with 2-byte prologue ??? */ + //if (ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && + // Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) { + // return MifareDesfireProcess(Buffer, BitCount); + //} + if (ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 6) { - return MifareDesfireProcess(Buffer, BitCount); + uint16_t IncomingByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(DesfireCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; + uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); + uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + ProcessedBitCount = DesfirePostprocessAPDU(DesfireCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE; + return ProcessedBitCount; } else if (ByteCount == 4 && Buffer[2] == 0x37 && Buffer[3] == 0xC8) { // NXP-based PCD sent a "keep alive" response of ACK, // so we respond with a corresponding NAK (with CRCA bytes appended): @@ -240,19 +240,31 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], Buffer, 2); memmove(&Buffer[0], &Buffer[2], ByteCount - 2); - uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, BitCount); + uint16_t IncomingByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(DesfireCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; + uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* Append the same ISO7816 prologue bytes to the response: */ memmove(&Buffer[2], &Buffer[0], ProcessedByteCount); memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); - ISO14443AAppendCRCA(Buffer, ProcessedByteCount); - ProcessedBitCount += 2 * BITS_PER_BYTE; + ProcessedBitCount = DesfirePostprocessAPDU(DesfireCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE; return ProcessedBitCount; } else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { - return ReturnedBytes; + /* This case should handle non-wrappped native commands. No pre/postprocessing afterwards: */ + return ReturnedBytes; } else if (!AnticolNoResp) { - uint16_t PiccProcessRespBytes = ISO144433APiccProcess(Buffer, BitCount); + /* This case is to exchange anticollision loop and RATS data. No need to pre/postprocess it depending + * on the CommMode, which has not been set yet if we reach this point: + */ + uint16_t PiccProcessRespBytes = ISO144433APiccProcess(Buffer, BitCount); if (PiccProcessRespBytes == ISO14443A_APP_NO_RESPONSE) { + // Stop pesky USB readers trying to autodetect all tag types by brute-force enumeration + // from interfering with making it into the command exchange (DESFIRE_IDLE) states. + // Once the anticollision and/or RATS has completed, set this flag to keep it from + // resending that initial handshaking until the AppReset() function is called on a timeout. + // N.b., the ACR-122 reader does this repeatedly when trying to run the LibNFC testing code + // even when the reader has not been put in scan mode -- + // and it really screws things up timing-wise! AnticolNoResp = true; } return PiccProcessRespBytes; From 74f216f51aef16e69668f4eb467aa1a69e77807c Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 19:15:57 -0500 Subject: [PATCH 26/68] Preliminary (partial) support for more CommModes -- This is going to need substantial testing -- II --- .../Chameleon-Mini/Application/CryptoCMAC.h | 2 ++ .../Application/DESFire/DESFireUtils.c | 34 ++++++++++++++----- .../Application/MifareDESFire.c | 6 ++-- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoCMAC.h b/Firmware/Chameleon-Mini/Application/CryptoCMAC.h index aaf9e5a0..06fae00a 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoCMAC.h +++ b/Firmware/Chameleon-Mini/Application/CryptoCMAC.h @@ -37,7 +37,9 @@ This notice must be retained at the top of all source files where indicated. #define CRYPTO_CMAC_RB128 ((uint8_t) 0x87) bool appendBufferCMAC(uint8_t cryptoType, const uint8_t *keyData, uint8_t *bufferData, uint16_t bufferSize, uint8_t *IV); +bool checkBufferMAC(uint8_t *bufferData, uint16_t bufferSize, uint16_t checksumSize); uint16_t appendBufferMAC(const uint8_t *keyData, uint8_t *bufferData, uint16_t bufferSize); +bool checkBufferCMAC(uint8_t *bufferData, uint16_t bufferSize, uint16_t checksumSize); #endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c index 97edf1b3..5283956b 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c @@ -152,30 +152,48 @@ uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buffe // Remove the CRCA bytes at the end of the buffer: return MAX(0, BufferSize - 2); case DESFIRE_COMMS_PLAINTEXT_MAC: { - // TODO: We are not checking the MAC/CMAC bytes for consistency yet ... uint16_t ChecksumBytes = 0; if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { ChecksumBytes = 4; + if (!checkBufferMAC(Buffer, BufferSize, ChecksumBytes)) { + return 0; + } } else if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_3K3DES) { ChecksumBytes = CRYPTO_3KTDEA_BLOCK_SIZE; + if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { + return 0; + } } else { - ChecksumBytes = CRYPTO_AES128_BLOCK_SIZE; + ChecksumBytes = CRYPTO_AES_BLOCK_SIZE; + if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { + return 0; + } } return MAX(0, BufferSize - ChecksumBytes); } case DESFIRE_COMMS_CIPHERTEXT_DES: { - // TODO ... - break; + Decrypt3DESBuffer(BufferSize, Buffer, &Buffer[BufferSize], SessionIV, SessionKey); + memmove(&Buffer[0], &Buffer[BufferSize], BufferSize); + uint16_t ChecksumBytes = CRYPTO_3KTDEA_BLOCK_SIZE; + if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { + return 0; + } + return MAX(0, BufferSize - ChecksumBytes); } case DESFIRE_COMMS_CIPHERTEXT_AES128: { - // TODO ... - break; + CryptoAESDecryptBuffer(BufferSize, Buffer, &Buffer[BufferSize], SessionIV, SessionKey); + memmove(&Buffer[0], &Buffer[BufferSize], BufferSize); + uint16_t ChecksumBytes = CRYPTO_AES_BLOCK_SIZE; + if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { + return 0; + } + return MAX(0, BufferSize - ChecksumBytes); } default: break; } - return BufferSize; + return 0; } uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) { @@ -224,7 +242,7 @@ uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buff default: break; } - return BufferSize; + return 0; } #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 1e5ffbc9..01c61834 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -126,7 +126,7 @@ void MifareDesfireAppTask(void) { uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { if (ByteCount == 0) { - return ISO14443A_APP_NO_RESPONSE;// + return ISO14443A_APP_NO_RESPONSE; } else if ((DesfireCmdCLA != DESFIRE_NATIVE_CLA) && (DesfireCmdCLA != DESFIRE_ISO7816_CLA)) { return ISO14443A_APP_NO_RESPONSE; @@ -174,7 +174,9 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { size_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; DesfireCmdCLA = Buffer[0]; - if ((ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && + if (BitCount == 0) { + return ISO14443A_APP_NO_RESPONSE; + } else if ((ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) || Iso7816CLA(DesfireCmdCLA)) { // Wrapped native command structure: /* Unwrap the PDU from ISO 7816-4 */ From a24fbe85c0d088a04989a1b15cd3cec23fd7e3bb Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 12 Feb 2022 21:47:54 -0500 Subject: [PATCH 27/68] Preliminary (partial) support for more CommModes -- This is going to need substantial testing -- III --- .../Chameleon-Mini/Application/CryptoAES128.c | 30 ++-- .../Chameleon-Mini/Application/CryptoCMAC.c | 114 +++++++++---- .../DESFire/DESFireChameleonTerminal.c | 6 +- .../Application/DESFire/DESFirePICCControl.c | 16 +- .../Application/DESFire/DESFireUtils.c | 153 +++++++++--------- .../Application/DESFire/DESFireUtils.h | 24 +-- .../Application/MifareDESFire.c | 50 +++--- Firmware/Chameleon-Mini/Makefile | 2 +- 8 files changed, 222 insertions(+), 173 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoAES128.c b/Firmware/Chameleon-Mini/Application/CryptoAES128.c index c931d838..321b0273 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoAES128.c +++ b/Firmware/Chameleon-Mini/Application/CryptoAES128.c @@ -296,8 +296,8 @@ uint8_t CryptoAESDecryptBuffer(uint16_t Count, uint8_t *Plaintext, uint8_t *Ciph // This routine performs the CBC "send" mode chaining: C = E(P ^ IV); IV = C static void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t *IV, uint8_t *Key, CryptoAES_CBCSpec_t CryptoSpec); static void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, - uint8_t *IV, uint8_t *Key, - CryptoAES_CBCSpec_t CryptoSpec) { + uint8_t *IV, uint8_t *Key, + CryptoAES_CBCSpec_t CryptoSpec) { uint16_t numBlocks = CRYPTO_BYTES_TO_BLOCKS(Count, CryptoSpec.blockSize); uint16_t blockIndex = 0; uint8_t *ptBuf = (uint8_t *) Plaintext, *ctBuf = (uint8_t *) Ciphertext; @@ -323,8 +323,8 @@ static void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, // This routine performs the CBC "receive" mode chaining: C = E(P) ^ IV; IV = P static void CryptoAES_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t *IV, uint8_t *Key, CryptoAES_CBCSpec_t CryptoSpec); static void CryptoAES_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, - uint8_t *IV, uint8_t *Key, - CryptoAES_CBCSpec_t CryptoSpec) { + uint8_t *IV, uint8_t *Key, + CryptoAES_CBCSpec_t CryptoSpec) { uint16_t numBlocks = CRYPTO_BYTES_TO_BLOCKS(Count, CryptoSpec.blockSize); uint16_t blockIndex = 0; uint8_t *ptBuf = (uint8_t *) Plaintext, *ctBuf = (uint8_t *) Ciphertext; @@ -389,18 +389,18 @@ uint16_t appendBufferCRC32C(uint8_t *bufferData, uint16_t bufferSize) { uint32_t workingCRC = INIT_CRC32C_VALUE; for (int i = 0; i < bufferSize; i++) { workingCRC = workingCRC ^ *(bufferData++); - for (int j = 0; j < 8; j++) { + for (int j = 0; j < 8; j++) { if (workingCRC & 1) { - workingCRC = (workingCRC >> 1) ^ LE_CRC32C_POLYNOMIAL; - } else { - workingCRC = workingCRC >> 1; - } - } + workingCRC = (workingCRC >> 1) ^ LE_CRC32C_POLYNOMIAL; + } else { + workingCRC = workingCRC >> 1; + } + } } - // Append the CRC32C bytes in little endian byte order to the end of the buffer: - bufferData[bufferSize] = (uint8_t) (workingCRC & 0x000000FF); - bufferData[bufferSize + 1] = (uint8_t) ((workingCRC & 0x0000FF00) >> 8); - bufferData[bufferSize + 2] = (uint8_t) ((workingCRC & 0x00FF0000) >> 16); - bufferData[bufferSize + 4] = (uint8_t) ((workingCRC & 0xFF000000) >> 24); + // Append the CRC32C bytes in little endian byte order to the end of the buffer: + bufferData[bufferSize] = (uint8_t)(workingCRC & 0x000000FF); + bufferData[bufferSize + 1] = (uint8_t)((workingCRC & 0x0000FF00) >> 8); + bufferData[bufferSize + 2] = (uint8_t)((workingCRC & 0x00FF0000) >> 16); + bufferData[bufferSize + 4] = (uint8_t)((workingCRC & 0xFF000000) >> 24); return bufferSize + 4; } diff --git a/Firmware/Chameleon-Mini/Application/CryptoCMAC.c b/Firmware/Chameleon-Mini/Application/CryptoCMAC.c index c78526df..dbdaff9f 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoCMAC.c +++ b/Firmware/Chameleon-Mini/Application/CryptoCMAC.c @@ -45,8 +45,8 @@ static void getCMACSubK1(const uint8_t *bufferL, uint8_t blockSize, uint8_t poly RotateArrayLeft(bufferL, bufferOut, blockSize); if ((bufferL[0] & 0x80) != 0) { for (int kidx = 0; kidx < blockSize; kidx++) { - bufferOut[kidx] = (uint8_t) (bufferOut[kidx] ^ _cmac_RB[kidx]); - } + bufferOut[kidx] = (uint8_t)(bufferOut[kidx] ^ _cmac_RB[kidx]); + } } } @@ -56,8 +56,8 @@ static void getCMACSubK2(const uint8_t *bufferK1, uint8_t blockSize, uint8_t pol RotateArrayLeft(bufferK1, bufferOut, blockSize); if ((bufferK1[0] & 0x80) != 0) { for (int kidx = 0; kidx < blockSize; kidx++) { - bufferOut[kidx] = (uint8_t) (bufferOut[kidx] ^ _cmac_RB[kidx]); - } + bufferOut[kidx] = (uint8_t)(bufferOut[kidx] ^ _cmac_RB[kidx]); + } } } @@ -66,32 +66,32 @@ static bool appendBufferCMACSubroutine(uint8_t cryptoType, const uint8_t *keyDat uint16_t newBlockSize = bufferSize; if (bufferSize == 0) { memset(bufferOut, 0x00, blockSize); - bufferOut[0] = (uint8_t) 0x80; - newBlockSize = blockSize; + bufferOut[0] = (uint8_t) 0x80; + newBlockSize = blockSize; } else if ((bufferSize % blockSize) != 0) { - newBlockSize = bufferSize - (bufferSize % blockSize) + blockSize; + newBlockSize = bufferSize - (bufferSize % blockSize) + blockSize; bufferOut[bufferSize] = (uint8_t) 0x80; } if (bufferSize != 0 && (bufferSize % blockSize) == 0) { // Complete block (use K1): - for (int i = bufferSize - blockSize; i < bufferSize; i++) { + for (int i = bufferSize - blockSize; i < bufferSize; i++) { bufferOut[i] ^= bufferK1[i - bufferSize + blockSize]; - } + } } else { // Incomplete block (use K2): - for (int i = bufferSize - blockSize; i < bufferSize; i++) { + for (int i = bufferSize - blockSize; i < bufferSize; i++) { bufferOut[i] ^= bufferK2[i - bufferSize + blockSize]; - } + } } switch (cryptoType) { case CRYPTO_TYPE_3K3DES: - Encrypt3DESBuffer(newBlockSize, bufferOut, bufferOut + bufferSize, keyData, bufferIV); - break; - case CRYPTO_TYPE_AES128: - CryptoAESEncryptBuffer(newBlockSize, bufferOut, bufferOut + bufferSize, keyData, bufferIV); - break; + Encrypt3DESBuffer(newBlockSize, bufferOut, &bufferOut[bufferSize], keyData, bufferIV); + break; + case CRYPTO_TYPE_AES128: + CryptoAESEncryptBuffer(newBlockSize, bufferOut, &bufferOut[bufferSize], keyData, bufferIV); + break; default: - return false; + return false; } memmove(&bufferOut[0], &bufferOut[newBlockSize], newBlockSize); memcpy(_cmac_final, &bufferOut[newBlockSize - blockSize], blockSize); @@ -103,40 +103,90 @@ bool appendBufferCMAC(uint8_t cryptoType, const uint8_t *keyData, uint8_t *buffe uint8_t blockSize, rb; uint8_t *nistL = _cmac_K2; switch (cryptoType) { - case CRYPTO_TYPE_3K3DES: + case CRYPTO_TYPE_3K3DES: blockSize = CRYPTO_3KTDEA_BLOCK_SIZE; - rb = CRYPTO_CMAC_RB64; - memset(_cmac_zeros, 0x00, blockSize); - Encrypt3DESBuffer(blockSize, _cmac_zeros, nistL, _cmac_zeros, keyData); - break; - case CRYPTO_TYPE_AES128: + rb = CRYPTO_CMAC_RB64; + memset(_cmac_zeros, 0x00, blockSize); + Encrypt3DESBuffer(blockSize, _cmac_zeros, nistL, _cmac_zeros, keyData); + break; + case CRYPTO_TYPE_AES128: blockSize = CRYPTO_AES_BLOCK_SIZE; - rb = CRYPTO_CMAC_RB128; - memset(_cmac_zeros, 0x00, blockSize); - CryptoAESEncryptBuffer(blockSize, _cmac_zeros, nistL, _cmac_zeros, keyData); - break; + rb = CRYPTO_CMAC_RB128; + memset(_cmac_zeros, 0x00, blockSize); + CryptoAESEncryptBuffer(blockSize, _cmac_zeros, nistL, _cmac_zeros, keyData); + break; default: - return false; + return false; } getCMACSubK1(nistL, blockSize, rb, _cmac_K1); getCMACSubK2(_cmac_K1, blockSize, rb, _cmac_K2); if (IV == NULL) { IV = _cmac_zeros; - memset(IV, 0x00, blockSize); - return appendBufferCMACSubroutine(cryptoType, keyData, _cmac_K1, _cmac_K2, IV, blockSize, bufferData, bufferSize); + memset(IV, 0x00, blockSize); + return appendBufferCMACSubroutine(cryptoType, keyData, _cmac_K1, _cmac_K2, IV, blockSize, bufferData, bufferSize); } else { return appendBufferCMACSubroutine(cryptoType, keyData, _cmac_K1, _cmac_K2, IV, blockSize, bufferData, bufferSize); } } +bool checkBufferCMAC(uint8_t *bufferData, uint16_t bufferSize, uint16_t checksumSize) { + if (checksumSize > bufferSize) { + return false; + } + if (checksumSize == CRYPTO_3KTDEA_BLOCK_SIZE) { + appendBufferCMAC(CRYPTO_TYPE_3K3DES, SessionKey, &bufferData[bufferSize], bufferSize - checksumSize, SessionIV); + memcpy(_cmac_zeros, &bufferData[bufferSize], checksumSize); + if (memcmp(_cmac_zeros, &bufferData[bufferSize - checksumSize], checksumSize)) { + return false; + } + return true; + } else if (checksumSize == CRYPTO_AES_BLOCK_SIZE) { + appendBufferCMAC(CRYPTO_TYPE_AES128, SessionKey, &bufferData[bufferSize], bufferSize - checksumSize, SessionIV); + memcpy(_cmac_zeros, &bufferData[bufferSize], checksumSize); + if (memcmp(_cmac_zeros, &bufferData[bufferSize - checksumSize], checksumSize)) { + return false; + } + return true; + } + return false; +} + uint16_t appendBufferMAC(const uint8_t *keyData, uint8_t *bufferData, uint16_t bufferSize) { memcpy(&_mac_key24[2 * CRYPTO_DES_BLOCK_SIZE], keyData, CRYPTO_DES_BLOCK_SIZE); memcpy(&_mac_key24[CRYPTO_DES_BLOCK_SIZE], keyData, CRYPTO_DES_BLOCK_SIZE); memcpy(&_mac_key24[0], keyData, CRYPTO_DES_BLOCK_SIZE); memset(&_cmac_zeros[0], 0x00, CRYPTO_DES_BLOCK_SIZE); - Encrypt3DESBuffer(bufferSize, bufferData, &bufferData[3 * CRYPTO_DES_BLOCK_SIZE], _cmac_zeros, keyData); + uint16_t paddedBufferSize = bufferSize; + if ((bufferSize % CRYPTO_DES_BLOCK_SIZE) != 0) { + paddedBufferSize = bufferSize + CRYPTO_DES_BLOCK_SIZE - (bufferSize % CRYPTO_DES_BLOCK_SIZE); + memset(&bufferData[bufferSize], 0x00, paddedBufferSize - bufferSize); + } + Encrypt3DESBuffer(paddedBufferSize, bufferData, &bufferData[paddedBufferSize], _cmac_zeros, keyData); // Copy the 4-byte MAC from the ciphertext (end of the bufferData array): - memcpy(&_cmac_zeros[0], &bufferData[3 * CRYPTO_DES_BLOCK_SIZE + bufferSize - CRYPTO_DES_BLOCK_SIZE], 4); + memcpy(&_cmac_zeros[0], &bufferData[paddedBufferSize - CRYPTO_DES_BLOCK_SIZE], 4); memcpy(&bufferData[bufferSize], &_cmac_zeros[0], 4); return bufferSize + 4; } + +bool checkBufferMAC(uint8_t *bufferData, uint16_t bufferSize, uint16_t checksumSize) { + if (checksumSize > bufferSize) { + return false; + } + const uint8_t *keyData = SessionKey; + memcpy(&_mac_key24[2 * CRYPTO_DES_BLOCK_SIZE], keyData, CRYPTO_DES_BLOCK_SIZE); + memcpy(&_mac_key24[CRYPTO_DES_BLOCK_SIZE], keyData, CRYPTO_DES_BLOCK_SIZE); + memcpy(&_mac_key24[0], keyData, CRYPTO_DES_BLOCK_SIZE); + memset(&_cmac_zeros[0], 0x00, CRYPTO_DES_BLOCK_SIZE); + uint16_t paddedBufferSize = bufferSize; + if ((bufferSize % CRYPTO_DES_BLOCK_SIZE) != 0) { + paddedBufferSize = bufferSize + CRYPTO_DES_BLOCK_SIZE - (bufferSize % CRYPTO_DES_BLOCK_SIZE); + memset(&bufferData[bufferSize], 0x00, paddedBufferSize - bufferSize); + } + Encrypt3DESBuffer(paddedBufferSize, bufferData, &bufferData[paddedBufferSize], _cmac_zeros, keyData); + // Copy the 4-byte MAC from the ciphertext (end of the bufferData array): + memcpy(&_cmac_zeros[0], &bufferData[paddedBufferSize - CRYPTO_DES_BLOCK_SIZE], 4); + if (memcmp(&bufferData[bufferSize - checksumSize], &_cmac_zeros[0], 4)) { + return false; + } + return true; +} diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c index f8997814..24f824aa 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c @@ -226,7 +226,7 @@ CommandStatusIdType CommandDESFireSetCommMode(char *OutParam, const char *InPara if (!strcasecmp_P(valueStr, PSTR("Plaintext"))) { DesfireCommMode = DESFIRE_COMMS_PLAINTEXT; DesfireCommandState.ActiveCommMode = DesfireCommMode; - return COMMAND_INFO_OK; + return COMMAND_INFO_OK; } else if (!strcasecmp_P(valueStr, PSTR("Plaintext:MAC"))) { DesfireCommMode = DESFIRE_COMMS_PLAINTEXT_MAC; DesfireCommandState.ActiveCommMode = DesfireCommMode; @@ -234,11 +234,11 @@ CommandStatusIdType CommandDESFireSetCommMode(char *OutParam, const char *InPara } else if (!strcasecmp_P(valueStr, PSTR("Enciphered:3K3DES"))) { DesfireCommMode = DESFIRE_COMMS_CIPHERTEXT_DES; DesfireCommandState.ActiveCommMode = DesfireCommMode; - return COMMAND_INFO_OK; + return COMMAND_INFO_OK; } else if (!strcasecmp_P(valueStr, PSTR("Enciphered:AES128"))) { DesfireCommMode = DESFIRE_COMMS_CIPHERTEXT_AES128; DesfireCommandState.ActiveCommMode = DesfireCommMode; - return COMMAND_INFO_OK; + return COMMAND_INFO_OK; } snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Options are: Plaintext|Plaintext:MAC|Enciphered:3K3DES|Enciphered:AES128")); return COMMAND_ERR_INVALID_USAGE_ID; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index 8021d40f..b108d47f 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -151,7 +151,7 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings) { TransferState.WriteData.Encryption.Func = &CryptoAESEncrypt_CBCSend; memset(SessionIV, 0, sizeof(SessionIVByteSize)); SessionIVByteSize = CRYPTO_AES_KEY_SIZE; - default: + default: return STATUS_PARAMETER_ERROR; } return STATUS_OPERATION_OK; @@ -160,12 +160,12 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings) { uint8_t WriteDataFilterSetup(uint8_t CommSettings) { switch (CommSettings) { case DESFIRE_COMMS_PLAINTEXT: - TransferState.Checksums.UpdateFunc = NULL; - TransferState.Checksums.FinalFunc = NULL; - TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = NULL; + TransferState.Checksums.UpdateFunc = NULL; + TransferState.Checksums.FinalFunc = NULL; + TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = NULL; memset(SessionIV, 0, sizeof(SessionIVByteSize)); - SessionIVByteSize = 0; - break; + SessionIVByteSize = 0; + break; case DESFIRE_COMMS_PLAINTEXT_MAC: TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateMACTDEA; TransferState.Checksums.FinalFunc = &TransferChecksumFinalMACTDEA; @@ -181,8 +181,8 @@ uint8_t WriteDataFilterSetup(uint8_t CommSettings) { memset(SessionIV, 0, sizeof(SessionIVByteSize)); SessionIVByteSize = CRYPTO_AES_KEY_SIZE; break; - case DESFIRE_COMMS_CIPHERTEXT_AES128: - // A.k.a., CommMode=FULL from NXP application note AN12343: + case DESFIRE_COMMS_CIPHERTEXT_AES128: + // A.k.a., CommMode=FULL from NXP application note AN12343: TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateCMAC; TransferState.Checksums.FinalFunc = &TransferChecksumFinalCMAC; TransferState.Checksums.MACData.CRCA = ISO14443A_CRCA_INIT; // TODO ??? diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c index 5283956b..8abec899 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c @@ -149,49 +149,48 @@ bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount) { uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) { switch (CommMode) { case DESFIRE_COMMS_PLAINTEXT: - // Remove the CRCA bytes at the end of the buffer: - return MAX(0, BufferSize - 2); - case DESFIRE_COMMS_PLAINTEXT_MAC: { - uint16_t ChecksumBytes = 0; + // Remove the CRCA bytes at the end of the buffer: + return MAX(0, BufferSize - 2); + case DESFIRE_COMMS_PLAINTEXT_MAC: { + uint16_t ChecksumBytes = 0; if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { ChecksumBytes = 4; - if (!checkBufferMAC(Buffer, BufferSize, ChecksumBytes)) { - return 0; - } - } - else if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_3K3DES) { - ChecksumBytes = CRYPTO_3KTDEA_BLOCK_SIZE; - if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { - return 0; - } - } else { - ChecksumBytes = CRYPTO_AES_BLOCK_SIZE; - if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { - return 0; - } - } - return MAX(0, BufferSize - ChecksumBytes); - } + if (!checkBufferMAC(Buffer, BufferSize, ChecksumBytes)) { + return 0; + } + } else if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_3K3DES) { + ChecksumBytes = CRYPTO_3KTDEA_BLOCK_SIZE; + if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { + return 0; + } + } else { + ChecksumBytes = CRYPTO_AES_BLOCK_SIZE; + if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { + return 0; + } + } + return MAX(0, BufferSize - ChecksumBytes); + } case DESFIRE_COMMS_CIPHERTEXT_DES: { - Decrypt3DESBuffer(BufferSize, Buffer, &Buffer[BufferSize], SessionIV, SessionKey); + Decrypt3DESBuffer(BufferSize, Buffer, &Buffer[BufferSize], SessionIV, SessionKey); memmove(&Buffer[0], &Buffer[BufferSize], BufferSize); - uint16_t ChecksumBytes = CRYPTO_3KTDEA_BLOCK_SIZE; - if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { - return 0; - } - return MAX(0, BufferSize - ChecksumBytes); - } - case DESFIRE_COMMS_CIPHERTEXT_AES128: { - CryptoAESDecryptBuffer(BufferSize, Buffer, &Buffer[BufferSize], SessionIV, SessionKey); + uint16_t ChecksumBytes = CRYPTO_3KTDEA_BLOCK_SIZE; + if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { + return 0; + } + return MAX(0, BufferSize - ChecksumBytes); + } + case DESFIRE_COMMS_CIPHERTEXT_AES128: { + CryptoAESDecryptBuffer(BufferSize, Buffer, &Buffer[BufferSize], SessionIV, SessionKey); memmove(&Buffer[0], &Buffer[BufferSize], BufferSize); - uint16_t ChecksumBytes = CRYPTO_AES_BLOCK_SIZE; - if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { - return 0; - } - return MAX(0, BufferSize - ChecksumBytes); - } - default: - break; + uint16_t ChecksumBytes = CRYPTO_AES_BLOCK_SIZE; + if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { + return 0; + } + return MAX(0, BufferSize - ChecksumBytes); + } + default: + break; } return 0; } @@ -199,48 +198,48 @@ uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buffe uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) { switch (CommMode) { case DESFIRE_COMMS_PLAINTEXT: - ISO14443AAppendCRCA(Buffer, BufferSize); - return BufferSize + 2; - case DESFIRE_COMMS_PLAINTEXT_MAC: { - if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { - return appendBufferMAC(SessionKey, Buffer, BufferSize); - } else { - // AES-128 or 3DES: - uint16_t MacedBytes = appendBufferCMAC(DesfireCommandState.CryptoMethodType, SessionKey, Buffer, BufferSize, SessionIV); - memcpy(SessionIV, &Buffer[BufferSize], MacedBytes - BufferSize); + ISO14443AAppendCRCA(Buffer, BufferSize); + return BufferSize + 2; + case DESFIRE_COMMS_PLAINTEXT_MAC: { + if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { + return appendBufferMAC(SessionKey, Buffer, BufferSize); + } else { + // AES-128 or 3DES: + uint16_t MacedBytes = appendBufferCMAC(DesfireCommandState.CryptoMethodType, SessionKey, Buffer, BufferSize, SessionIV); + memcpy(SessionIV, &Buffer[BufferSize], MacedBytes - BufferSize); return MacedBytes; - } - break; - } - case DESFIRE_COMMS_CIPHERTEXT_DES: { - // TripleDES: - uint16_t CryptoBlockSize = CRYPTO_3KTDEA_BLOCK_SIZE; - uint16_t BlockPadding = 0; - if ((BufferSize % CryptoBlockSize) != 0) { - BlockPadding = CryptoBlockSize - (BufferSize % CryptoBlockSize); - } - uint16_t MacedBytes = appendBufferCMAC(CRYPTO_TYPE_3K3DES, SessionKey, Buffer, BufferSize, SessionIV); + } + break; + } + case DESFIRE_COMMS_CIPHERTEXT_DES: { + // TripleDES: + uint16_t CryptoBlockSize = CRYPTO_3KTDEA_BLOCK_SIZE; + uint16_t BlockPadding = 0; + if ((BufferSize % CryptoBlockSize) != 0) { + BlockPadding = CryptoBlockSize - (BufferSize % CryptoBlockSize); + } + uint16_t MacedBytes = appendBufferCMAC(CRYPTO_TYPE_3K3DES, SessionKey, Buffer, BufferSize, SessionIV); memset(&Buffer[MacedBytes], 0x00, BlockPadding); - uint16_t XferBytes = MacedBytes + BlockPadding; - Encrypt3DESBuffer(XferBytes, Buffer, &Buffer[XferBytes], SessionIV, SessionKey); - memmove(&Buffer[0], &Buffer[XferBytes], XferBytes); - return XferBytes; - } - case DESFIRE_COMMS_CIPHERTEXT_AES128: { - uint16_t CryptoBlockSize = CRYPTO_AES_BLOCK_SIZE; - uint16_t BlockPadding = 0; - if ((BufferSize % CryptoBlockSize) != 0) { - BlockPadding = CryptoBlockSize - (BufferSize % CryptoBlockSize); - } - uint16_t MacedBytes = appendBufferCMAC(CRYPTO_TYPE_AES128, SessionKey, Buffer, BufferSize, SessionIV); + uint16_t XferBytes = MacedBytes + BlockPadding; + Encrypt3DESBuffer(XferBytes, Buffer, &Buffer[XferBytes], SessionIV, SessionKey); + memmove(&Buffer[0], &Buffer[XferBytes], XferBytes); + return XferBytes; + } + case DESFIRE_COMMS_CIPHERTEXT_AES128: { + uint16_t CryptoBlockSize = CRYPTO_AES_BLOCK_SIZE; + uint16_t BlockPadding = 0; + if ((BufferSize % CryptoBlockSize) != 0) { + BlockPadding = CryptoBlockSize - (BufferSize % CryptoBlockSize); + } + uint16_t MacedBytes = appendBufferCMAC(CRYPTO_TYPE_AES128, SessionKey, Buffer, BufferSize, SessionIV); memset(&Buffer[MacedBytes], 0x00, BlockPadding); - uint16_t XferBytes = MacedBytes + BlockPadding; - CryptoAESEncryptBuffer(XferBytes, Buffer, &Buffer[XferBytes], SessionIV, SessionKey); - memmove(&Buffer[0], &Buffer[XferBytes], XferBytes); - return XferBytes; - } - default: - break; + uint16_t XferBytes = MacedBytes + BlockPadding; + CryptoAESEncryptBuffer(XferBytes, Buffer, &Buffer[XferBytes], SessionIV, SessionKey); + memmove(&Buffer[0], &Buffer[XferBytes], XferBytes); + return XferBytes; + } + default: + break; } return 0; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h index 0b81298e..0f48759f 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h @@ -53,21 +53,21 @@ uint16_t DesfireAddParityBits(uint8_t *Buffer, uint16_t bits); uint16_t DesfireRemoveParityBits(uint8_t *Buffer, uint16_t BitCount); bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount); -/* Add utility wrapper functions to perform pre and postprocessing on - * the raw input APDU commands sent by the PCD depending on which - * CommMode (PLAINTEXT|PLAINTEXT-MAC|ENCIPHERED-CMAC-3DES|ECIPHERED-CMAC-AES128) - * setting is active. +/* Add utility wrapper functions to perform pre and postprocessing on + * the raw input APDU commands sent by the PCD depending on which + * CommMode (PLAINTEXT|PLAINTEXT-MAC|ENCIPHERED-CMAC-3DES|ECIPHERED-CMAC-AES128) + * setting is active. * - * The implementation is adapted from the Java sources at - * @github/andrade/nfcjlib (in the DESFireEV1 source files). - * We will use the conventions in that library to update the SessionIV buffer - * when the next rounds of data are exchanged. Note that the SessionIV and - * SessionKey arrays are initialized in the Authenticate(Legacy|ISO|AES) commands + * The implementation is adapted from the Java sources at + * @github/andrade/nfcjlib (in the DESFireEV1 source files). + * We will use the conventions in that library to update the SessionIV buffer + * when the next rounds of data are exchanged. Note that the SessionIV and + * SessionKey arrays are initialized in the Authenticate(Legacy|ISO|AES) commands * used to initiate the working session from PCD <--> PICC. * - * Helper methods to format and encode quirky or pathological cases of the - * CommSettings and wrapped APDU format combinations are defined statically in the - * C source file to save space in the symbol table for the firmware (ELF) binary. + * Helper methods to format and encode quirky or pathological cases of the + * CommSettings and wrapped APDU format combinations are defined statically in the + * C source file to save space in the symbol table for the firmware (ELF) binary. */ uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize); uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize); diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 01c61834..1a4ec777 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -175,9 +175,9 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { size_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; DesfireCmdCLA = Buffer[0]; if (BitCount == 0) { - return ISO14443A_APP_NO_RESPONSE; + return ISO14443A_APP_NO_RESPONSE; } else if ((ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) || Iso7816CLA(DesfireCmdCLA)) { + Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) || Iso7816CLA(DesfireCmdCLA)) { // Wrapped native command structure: /* Unwrap the PDU from ISO 7816-4 */ // Check CRC bytes appended to the buffer: @@ -224,13 +224,13 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { // return MifareDesfireProcess(Buffer, BitCount); //} if (ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - Buffer[3] == 0x00 && Buffer[4] == ByteCount - 6) { + Buffer[3] == 0x00 && Buffer[4] == ByteCount - 6) { uint16_t IncomingByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(DesfireCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; - uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); + uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - ProcessedBitCount = DesfirePostprocessAPDU(DesfireCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE; - return ProcessedBitCount; + ProcessedBitCount = DesfirePostprocessAPDU(DesfireCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE; + return ProcessedBitCount; } else if (ByteCount == 4 && Buffer[2] == 0x37 && Buffer[3] == 0xC8) { // NXP-based PCD sent a "keep alive" response of ACK, // so we respond with a corresponding NAK (with CRCA bytes appended): @@ -243,33 +243,33 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { memcpy(&ISO7816PrologueBytes[0], Buffer, 2); memmove(&Buffer[0], &Buffer[2], ByteCount - 2); uint16_t IncomingByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(DesfireCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; - uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); + uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(DesfireCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; + uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* Append the same ISO7816 prologue bytes to the response: */ memmove(&Buffer[2], &Buffer[0], ProcessedByteCount); memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); - ProcessedBitCount = DesfirePostprocessAPDU(DesfireCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE; + ProcessedBitCount = DesfirePostprocessAPDU(DesfireCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE; return ProcessedBitCount; } else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { /* This case should handle non-wrappped native commands. No pre/postprocessing afterwards: */ - return ReturnedBytes; + return ReturnedBytes; } else if (!AnticolNoResp) { - /* This case is to exchange anticollision loop and RATS data. No need to pre/postprocess it depending - * on the CommMode, which has not been set yet if we reach this point: - */ - uint16_t PiccProcessRespBytes = ISO144433APiccProcess(Buffer, BitCount); - if (PiccProcessRespBytes == ISO14443A_APP_NO_RESPONSE) { - // Stop pesky USB readers trying to autodetect all tag types by brute-force enumeration - // from interfering with making it into the command exchange (DESFIRE_IDLE) states. - // Once the anticollision and/or RATS has completed, set this flag to keep it from - // resending that initial handshaking until the AppReset() function is called on a timeout. - // N.b., the ACR-122 reader does this repeatedly when trying to run the LibNFC testing code - // even when the reader has not been put in scan mode -- - // and it really screws things up timing-wise! - AnticolNoResp = true; - } - return PiccProcessRespBytes; + /* This case is to exchange anticollision loop and RATS data. No need to pre/postprocess it depending + * on the CommMode, which has not been set yet if we reach this point: + */ + uint16_t PiccProcessRespBytes = ISO144433APiccProcess(Buffer, BitCount); + if (PiccProcessRespBytes == ISO14443A_APP_NO_RESPONSE) { + // Stop pesky USB readers trying to autodetect all tag types by brute-force enumeration + // from interfering with making it into the command exchange (DESFIRE_IDLE) states. + // Once the anticollision and/or RATS has completed, set this flag to keep it from + // resending that initial handshaking until the AppReset() function is called on a timeout. + // N.b., the ACR-122 reader does this repeatedly when trying to run the LibNFC testing code + // even when the reader has not been put in scan mode -- + // and it really screws things up timing-wise! + AnticolNoResp = true; + } + return PiccProcessRespBytes; } return ISO14443A_APP_NO_RESPONSE; } diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index b879f71c..93324f1a 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -251,7 +251,7 @@ program-latest: check_size avrdude $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_APP_LATEST) $(AVRDUDE_WRITE_EEPROM_LATEST) # Program the device using batchisp and the DFU bootloader -# Note that the device has to be in bootloader mode already-ffunction-sections -fdata-sections +# Note that the device has to be in bootloader mode already-ffunction-sections -fdata-sections dfu-flip: $(TARGET).hex $(TARGET).eep check_size cp $(TARGET).eep EEPROM.hex batchisp -hardware usb -device $(MCU) -operation erase f memory FLASH loadbuffer $(TARGET).hex program verify memory EEPROM loadbuffer EEPROM.hex program verify start reset 0 From bf1eadc337c39b75793472c2dd24ff7ee81868b1 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sun, 13 Feb 2022 00:29:24 -0500 Subject: [PATCH 28/68] Making a sane backup point while prfusely debugging --- .../Application/DESFire/DESFireCrypto.c | 1 + .../Application/DESFire/DESFireInstructions.c | 15 ++---- .../Application/DESFire/DESFireUtils.c | 20 ++++---- .../Application/MifareDESFire.c | 48 ++++++++----------- .../Libs/ArduinoCryptoLib/aes/aes128.h | 22 ++++----- 5 files changed, 46 insertions(+), 60 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c index e2654d98..6c671beb 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c @@ -62,6 +62,7 @@ void InvalidateAuthState(BYTE keepPICCAuthData) { Iso7816FileSelected = false; CryptoAuthMethod = CRYPTO_TYPE_ANY; ActiveCommMode = DESFIRE_DEFAULT_COMMS_STANDARD; + DesfireCommMode = ActiveCommMode; } bool IsAuthenticated(void) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 89883f4e..c390be55 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -518,8 +518,6 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_2KTDEA); Key = SessionKey; DesfireCommandState.KeyId = KeyId; - DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; - DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); /* Fetch the key */ if (cryptoKeyType == CRYPTO_TYPE_DES) { @@ -583,15 +581,10 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { /* Reset parameters for authentication from the first exchange */ KeyId = DesfireCommandState.KeyId; - cryptoKeyType = DesfireCommandState.CryptoMethodType; - keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); + cryptoKeyType = CRYPTO_TYPE_2KTDEA; + keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_2KTDEA); Key = SessionKey; - if (cryptoKeyType == CRYPTO_TYPE_DES) { - ReadAppKey(SelectedApp.Slot, KeyId, Key, CRYPTO_DES_KEY_SIZE); - memcpy(Key + CRYPTO_DES_KEY_SIZE, Key, CRYPTO_DES_KEY_SIZE); - } else { - ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); - } + ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); /* Decrypt the challenge sent back to get RndA and a shifted RndB */ BYTE challengeRndAB[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; @@ -624,6 +617,8 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { AuthenticatedWithKey = KeyId; AuthenticatedWithPICCMasterKey = (SelectedApp.Slot == DESFIRE_PICC_APP_SLOT) && (KeyId == DESFIRE_MASTER_KEY_ID); + DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_2KTDEA; + DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_2KTDEA); /* Return the status on success */ Buffer[0] = STATUS_OPERATION_OK; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c index 8abec899..e9d18d42 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c @@ -30,6 +30,7 @@ This notice must be retained at the top of all source files where indicated. #include "DESFireUtils.h" #include "DESFirePICCControl.h" +#include "DESFireLogging.h" void RotateArrayRight(BYTE *srcBuf, BYTE *destBuf, SIZET bufSize) { destBuf[bufSize - 1] = srcBuf[0]; @@ -147,10 +148,8 @@ bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount) { } uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) { + DEBUG_PRINT_P(PSTR("PRE -- CommMode -- 0x%02x"), CommMode); switch (CommMode) { - case DESFIRE_COMMS_PLAINTEXT: - // Remove the CRCA bytes at the end of the buffer: - return MAX(0, BufferSize - 2); case DESFIRE_COMMS_PLAINTEXT_MAC: { uint16_t ChecksumBytes = 0; if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { @@ -189,17 +188,16 @@ uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buffe } return MAX(0, BufferSize - ChecksumBytes); } + case DESFIRE_COMMS_PLAINTEXT: default: - break; + // Leave the CRCA bytes intact: + return BufferSize; } - return 0; } uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) { + DEBUG_PRINT_P(PSTR("POST -- CommMode -- 0x%02x"), CommMode); switch (CommMode) { - case DESFIRE_COMMS_PLAINTEXT: - ISO14443AAppendCRCA(Buffer, BufferSize); - return BufferSize + 2; case DESFIRE_COMMS_PLAINTEXT_MAC: { if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { return appendBufferMAC(SessionKey, Buffer, BufferSize); @@ -238,10 +236,12 @@ uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buff memmove(&Buffer[0], &Buffer[XferBytes], XferBytes); return XferBytes; } + case DESFIRE_COMMS_PLAINTEXT: default: - break; + //ISO14443AAppendCRCA(Buffer, BufferSize); + //return BufferSize + 2; + return BufferSize; } - return 0; } #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 1a4ec777..a71a600c 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -174,25 +174,22 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { size_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; DesfireCmdCLA = Buffer[0]; + LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); if (BitCount == 0) { return ISO14443A_APP_NO_RESPONSE; - } else if ((ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && + } else if ((ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) || Iso7816CLA(DesfireCmdCLA)) { - // Wrapped native command structure: - /* Unwrap the PDU from ISO 7816-4 */ - // Check CRC bytes appended to the buffer: - // -- Actually, just ignore parity problems if they exist, + /* Wrapped native command structure or ISO7816: */ if (Iso7816CLA(DesfireCmdCLA)) { uint16_t iso7816ParamsStatus = SetIso7816WrappedParametersType(Buffer, ByteCount); if (iso7816ParamsStatus != ISO7816_CMD_NO_ERROR) { Buffer[0] = (uint8_t)((iso7816ParamsStatus >> 8) & 0x00ff); Buffer[1] = (uint8_t)(iso7816ParamsStatus & 0x00ff); - ISO14443AAppendCRCA(Buffer, 2); - ByteCount = 2 + 2; - return ByteCount * BITS_PER_BYTE; + ByteCount = 2; + return ByteCount * BITS_PER_BYTE; } } - ByteCount = Buffer[4]; // also removing the trailing two parity bytes + ByteCount = Buffer[4]; Buffer[0] = Buffer[1]; memmove(&Buffer[1], &Buffer[5], ByteCount); /* Process the command */ @@ -206,7 +203,7 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { } else { /* Re-wrap into ISO 7816-4 */ } - //LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); + LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); return ByteCount * BITS_PER_BYTE; } else { /* ISO/IEC 14443-4 PDUs: No extra work */ @@ -218,43 +215,36 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; uint16_t ReturnedBytes = 0; - /* Is this first case really just a padded ISO7816 APDU with 2-byte prologue ??? */ - //if (ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - // Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) { - // return MifareDesfireProcess(Buffer, BitCount); - //} if (ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - Buffer[3] == 0x00 && Buffer[4] == ByteCount - 6) { + Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) { uint16_t IncomingByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(DesfireCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; + uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - ProcessedBitCount = DesfirePostprocessAPDU(DesfireCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE; + ProcessedBitCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE; return ProcessedBitCount; - } else if (ByteCount == 4 && Buffer[2] == 0x37 && Buffer[3] == 0xC8) { + } else if (BitCount == 4 && (Buffer[0] & 0xF0) == 0xA0) { // NXP-based PCD sent a "keep alive" response of ACK, // so we respond with a corresponding NAK (with CRCA bytes appended): - Buffer[2] = 0x7E; - Buffer[3] = 0x44; - ISO14443AAppendCRCA(Buffer, 4); - return 6 * BITS_PER_BYTE; + Buffer[0] = 0x00; + return 4; } else if (IsWrappedISO7816CommandType(Buffer, ByteCount)) { uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], Buffer, 2); - memmove(&Buffer[0], &Buffer[2], ByteCount - 2); - uint16_t IncomingByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(DesfireCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; - uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); + uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount); + memmove(&Buffer[0], &Buffer[2], IncomingByteCount - 2); + uint16_t UnwrappedBitCount = (IncomingByteCount - 2) * BITS_PER_BYTE; + uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* Append the same ISO7816 prologue bytes to the response: */ memmove(&Buffer[2], &Buffer[0], ProcessedByteCount); memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); - ProcessedBitCount = DesfirePostprocessAPDU(DesfireCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE; + ProcessedBitCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2) * BITS_PER_BYTE; return ProcessedBitCount; } else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { /* This case should handle non-wrappped native commands. No pre/postprocessing afterwards: */ return ReturnedBytes; - } else if (!AnticolNoResp) { + } else { // if (!AnticolNoResp) { /* This case is to exchange anticollision loop and RATS data. No need to pre/postprocess it depending * on the CommMode, which has not been set yet if we reach this point: */ diff --git a/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/aes/aes128.h b/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/aes/aes128.h index 6d3e528a..a9f69634 100644 --- a/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/aes/aes128.h +++ b/Software/DESFireLibNFCTesting/Libs/ArduinoCryptoLib/aes/aes128.h @@ -1,22 +1,22 @@ /* -The DESFire stack portion of this firmware source -is free software written by Maxie Dion Schmidt (@maxieds): +The DESFire stack portion of this firmware source +is free software written by Maxie Dion Schmidt (@maxieds): You can redistribute it and/or modify it under the terms of this license. 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. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -The complete source distribution of +The complete source distribution of this firmware is available at the following link: https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack. -Based in part on the original DESFire code created by -@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at +Based in part on the original DESFire code created by +@dev-zzo (GitHub handle) [Dmitry Janushkevich] available at https://github.com/dev-zzo/ChameleonMini/tree/desfire. -This notice must be retained at the top of all source files where indicated. +This notice must be retained at the top of all source files where indicated. */ /* @@ -26,7 +26,7 @@ This notice must be retained at the top of all source files where indicated. * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the + * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included @@ -34,15 +34,15 @@ This notice must be retained at the top of all source files where indicated. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -/* aes128.h : Standalone C library adapted from the ArduinoCryptoLib source to - * implement AES128 encryption with a small foorprint. +/* aes128.h : Standalone C library adapted from the ArduinoCryptoLib source to + * implement AES128 encryption with a small foorprint. */ #ifndef __AES128_CRYPTO_H__ From 65766e1ee401433e7b26cf42aa7d3cd2d6009d48 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sun, 13 Feb 2022 02:41:53 -0500 Subject: [PATCH 29/68] Incremental backup -- Auth schemes should be working -- New CommMode checksum functions DO NOT fit into text/data (yet) --- .../Chameleon-Mini/Application/CryptoCMAC.c | 2 + .../DESFire/DESFireISO14443Support.c | 17 +++++++- .../DESFire/DESFireISO14443Support.h | 22 ++++++++-- .../Application/DESFire/DESFireInstructions.c | 15 ++++--- .../Application/DESFire/DESFireUtils.c | 21 +++++----- .../Application/MifareDESFire.c | 42 +++++++++---------- Firmware/Chameleon-Mini/Makefile | 2 +- 7 files changed, 77 insertions(+), 44 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoCMAC.c b/Firmware/Chameleon-Mini/Application/CryptoCMAC.c index dbdaff9f..54608891 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoCMAC.c +++ b/Firmware/Chameleon-Mini/Application/CryptoCMAC.c @@ -32,6 +32,7 @@ This notice must be retained at the top of all source files where indicated. #include "CryptoTDEA.h" #include "CryptoAES128.h" +#if 0 static uint8_t _cmac_K1[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; static uint8_t _cmac_K2[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; 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 } return true; } +#endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index 820c326d..13452427 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -44,6 +44,9 @@ uint8_t Iso144434LastBlockLength = 0x00; uint8_t StateRetryCount = 0x00; uint8_t LastReaderSentCmd = 0x00; +uint8_t ISO14443ALastDataFrame[MAX_DATA_FRAME_XFER_SIZE] = { 0x00 }; +uint16_t ISO14443ALastDataFrameBits = 0; + bool CheckStateRetryCount2(bool resetByDefault, bool performLogging) { if (resetByDefault || ++StateRetryCount >= MAX_STATE_RETRY_COUNT) { ISO144434SwitchState2(Iso144433AIdleState, performLogging); @@ -74,6 +77,7 @@ void ISO144434Reset(void) { /* No logging -- spams the log */ Iso144434State = ISO14443_4_STATE_EXPECT_RATS; Iso144434BlockNumber = 1; + ISO14443ALastDataFrameBits = 0; } 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 /* 7.5.4.3, rule 12 */ /* This is a NAK. Send an ACK back */ Buffer[0] = ISO14443_PCB_R_BLOCK_STATIC | ISO14443_PCB_R_BLOCK_ACK | MyBlockNumber; - ByteCount = 1; + //ByteCount = 1; + // Per the NXP data sheet MF1S50YYX_V1 (Table 10: ACK / NAK), we should return 4 bits: + return 4; } else { /* This is an ACK */ /* NOTE: Chaining is not supported yet. */ const char *debugPrintStr = PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"); DEBUG_PRINT_P(debugPrintStr, __LINE__); - return ISO14443A_APP_NO_RESPONSE; + // Resend the data from the last frame: + if (ISO14443ALastDataFrameBits > 0) { + memcpy(&Buffer[0], &ISO14443ALastDataFrame[0], (ISO14443ALastDataFrameBits + BITS_PER_BYTE - 1) / BITS_PER_BYTE); + return ISO14443ALastDataFrameBits; + } else { + return ISO14443A_APP_NO_RESPONSE; + } } const char *debugPrintStr6 = PSTR("ISO14443-4: R-BLK"); LogDebuggingMsg(debugPrintStr6); @@ -272,6 +284,7 @@ void ISO144433AReset(void) { /* No logging -- spams the log */ Iso144433AState = ISO14443_3A_STATE_IDLE; Iso144433AIdleState = ISO14443_3A_STATE_IDLE; + ISO14443ALastDataFrameBits = 0; } void ISO144433AHalt(void) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index e24ff42e..11be3e0a 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -41,9 +41,9 @@ This notice must be retained at the top of all source files where indicated. */ #define ISO14443A_CMD_RATS 0xE0 -#define ISO14443A_RATS_FRAME_SIZE (6 * BITS_PER_BYTE) //(4 * 8) /* Bit */ +#define ISO14443A_RATS_FRAME_SIZE (6 * BITS_PER_BYTE) /* Bit */ #define ISO14443A_CMD_RNAK 0xB2 -#define ISO14443A_CRC_FRAME_SIZE (ISO14443A_CRCA_SIZE * BITS_PER_BYTE) +#define ISO14443A_CRC_FRAME_SIZE (ISO14443A_CRCA_SIZE * BITS_PER_BYTE) #define ISO14443_PCB_BLOCK_TYPE_MASK 0xC0 #define ISO14443_PCB_I_BLOCK 0x00 @@ -92,13 +92,29 @@ extern uint8_t Iso144434BlockNumber; extern uint8_t Iso144434CardID; extern uint8_t LastReaderSentCmd; +/* Configure saving last data frame state so can resend on ACK from the PCD */ + +#define MAX_DATA_FRAME_XFER_SIZE (64) +extern uint8_t ISO14443ALastDataFrame[MAX_DATA_FRAME_XFER_SIZE]; +extern uint16_t ISO14443ALastDataFrameBits; + +INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t BufferBitCount) { + uint16_t ISO14443ALastDataFrameBytes = MIN((BufferBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE, MAX_DATA_FRAME_XFER_SIZE); + if (ISO14443ALastDataFrameBytes > 0) { + memcpy(ISO14443ALastDataFrame, &Buffer[0], ISO14443ALastDataFrameBytes); + } + ISO14443ALastDataFrameBits = BufferBitCount; + return BufferBitCount; +} + /* Setup some fuzzy response handling for problematic readers like the ACR122U */ + #define MAX_STATE_RETRY_COUNT (4) extern uint8_t StateRetryCount; bool CheckStateRetryCount(bool resetByDefault); bool CheckStateRetryCount2(bool resetByDefault, bool performLogging); -#define IGNORE_ACK_BYTE (0x92) +//#define IGNORE_ACK_BYTE (0x92) /* Support functions */ void ISO144434SwitchState(Iso144434StateType NewState); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index c390be55..89883f4e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -518,6 +518,8 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_2KTDEA); Key = SessionKey; DesfireCommandState.KeyId = KeyId; + DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; + DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); /* Fetch the key */ if (cryptoKeyType == CRYPTO_TYPE_DES) { @@ -581,10 +583,15 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { /* Reset parameters for authentication from the first exchange */ KeyId = DesfireCommandState.KeyId; - cryptoKeyType = CRYPTO_TYPE_2KTDEA; - keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_2KTDEA); + cryptoKeyType = DesfireCommandState.CryptoMethodType; + keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); Key = SessionKey; - ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + if (cryptoKeyType == CRYPTO_TYPE_DES) { + ReadAppKey(SelectedApp.Slot, KeyId, Key, CRYPTO_DES_KEY_SIZE); + memcpy(Key + CRYPTO_DES_KEY_SIZE, Key, CRYPTO_DES_KEY_SIZE); + } else { + ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + } /* Decrypt the challenge sent back to get RndA and a shifted RndB */ BYTE challengeRndAB[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; @@ -617,8 +624,6 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { AuthenticatedWithKey = KeyId; AuthenticatedWithPICCMasterKey = (SelectedApp.Slot == DESFIRE_PICC_APP_SLOT) && (KeyId == DESFIRE_MASTER_KEY_ID); - DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_2KTDEA; - DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_2KTDEA); /* Return the status on success */ Buffer[0] = STATUS_OPERATION_OK; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c index e9d18d42..6297d70e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c @@ -148,9 +148,9 @@ bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount) { } uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) { - DEBUG_PRINT_P(PSTR("PRE -- CommMode -- 0x%02x"), CommMode); + //DEBUG_PRINT_P(PSTR("PRE -- CommMode -- 0x%02x"), CommMode); switch (CommMode) { - case DESFIRE_COMMS_PLAINTEXT_MAC: { + /*case DESFIRE_COMMS_PLAINTEXT_MAC: { uint16_t ChecksumBytes = 0; if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { ChecksumBytes = 4; @@ -187,18 +187,18 @@ uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buffe return 0; } return MAX(0, BufferSize - ChecksumBytes); - } + }*/ case DESFIRE_COMMS_PLAINTEXT: default: - // Leave the CRCA bytes intact: - return BufferSize; + // Leave the CRCA bytes intact: + return BufferSize; } } uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) { - DEBUG_PRINT_P(PSTR("POST -- CommMode -- 0x%02x"), CommMode); + //DEBUG_PRINT_P(PSTR("POST -- CommMode -- 0x%02x"), CommMode); switch (CommMode) { - case DESFIRE_COMMS_PLAINTEXT_MAC: { + /*case DESFIRE_COMMS_PLAINTEXT_MAC: { if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { return appendBufferMAC(SessionKey, Buffer, BufferSize); } else { @@ -235,12 +235,11 @@ uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buff CryptoAESEncryptBuffer(XferBytes, Buffer, &Buffer[XferBytes], SessionIV, SessionKey); memmove(&Buffer[0], &Buffer[XferBytes], XferBytes); return XferBytes; - } + }*/ case DESFIRE_COMMS_PLAINTEXT: default: - //ISO14443AAppendCRCA(Buffer, BufferSize); - //return BufferSize + 2; - return BufferSize; + ISO14443AAppendCRCA(Buffer, BufferSize); + return BufferSize + 2; } } diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index a71a600c..13ed9684 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -174,10 +174,11 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { size_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; DesfireCmdCLA = Buffer[0]; - LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); + //LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); if (BitCount == 0) { + LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); return ISO14443A_APP_NO_RESPONSE; - } else if ((ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && + } else if ((ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) || Iso7816CLA(DesfireCmdCLA)) { /* Wrapped native command structure or ISO7816: */ if (Iso7816CLA(DesfireCmdCLA)) { @@ -186,7 +187,7 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[0] = (uint8_t)((iso7816ParamsStatus >> 8) & 0x00ff); Buffer[1] = (uint8_t)(iso7816ParamsStatus & 0x00ff); ByteCount = 2; - return ByteCount * BITS_PER_BYTE; + return ByteCount * BITS_PER_BYTE; } } ByteCount = Buffer[4]; @@ -203,7 +204,7 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { } else { /* Re-wrap into ISO 7816-4 */ } - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); + //LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); return ByteCount * BITS_PER_BYTE; } else { /* ISO/IEC 14443-4 PDUs: No extra work */ @@ -215,41 +216,37 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; uint16_t ReturnedBytes = 0; - if (ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) { + if (ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && + Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) { + DesfireCmdCLA = Buffer[0]; uint16_t IncomingByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - ProcessedBitCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE; - return ProcessedBitCount; - } else if (BitCount == 4 && (Buffer[0] & 0xF0) == 0xA0) { - // NXP-based PCD sent a "keep alive" response of ACK, - // so we respond with a corresponding NAK (with CRCA bytes appended): - Buffer[0] = 0x00; - return 4; + return ISO14443AStoreLastDataFrameAndReturn(Buffer, DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE); } else if (IsWrappedISO7816CommandType(Buffer, ByteCount)) { + DesfireCmdCLA = Buffer[2]; uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], Buffer, 2); uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount); - memmove(&Buffer[0], &Buffer[2], IncomingByteCount - 2); + memmove(&Buffer[0], &Buffer[2], IncomingByteCount - 2); uint16_t UnwrappedBitCount = (IncomingByteCount - 2) * BITS_PER_BYTE; - uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); + uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* Append the same ISO7816 prologue bytes to the response: */ memmove(&Buffer[2], &Buffer[0], ProcessedByteCount); memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); ProcessedBitCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2) * BITS_PER_BYTE; - return ProcessedBitCount; + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedBitCount); } else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { /* This case should handle non-wrappped native commands. No pre/postprocessing afterwards: */ - return ReturnedBytes; - } else { // if (!AnticolNoResp) { + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ReturnedBytes * BITS_PER_BYTE); + } else if (!AnticolNoResp || BitCount < BITS_PER_BYTE) { /* This case is to exchange anticollision loop and RATS data. No need to pre/postprocess it depending - * on the CommMode, which has not been set yet if we reach this point: + * on the CommMode, which has not been set yet if we reach this point: */ - uint16_t PiccProcessRespBytes = ISO144433APiccProcess(Buffer, BitCount); - if (PiccProcessRespBytes == ISO14443A_APP_NO_RESPONSE) { + uint16_t PiccProcessRespBits = ISO144433APiccProcess(Buffer, BitCount); + if (PiccProcessRespBits == ISO14443A_APP_NO_RESPONSE) { // Stop pesky USB readers trying to autodetect all tag types by brute-force enumeration // from interfering with making it into the command exchange (DESFIRE_IDLE) states. // 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) { // and it really screws things up timing-wise! AnticolNoResp = true; } - return PiccProcessRespBytes; + return ISO14443AStoreLastDataFrameAndReturn(Buffer, PiccProcessRespBits); } + LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); return ISO14443A_APP_NO_RESPONSE; } diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 93324f1a..6a4b79f1 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -191,7 +191,7 @@ CC_FLAGS = -g0 -DUSE_LUFA_CONFIG_HEADER -DFLASH_DATA_ADDR=$(FLASH_DATA_ADDR) -D__AVR_ATxmega128A4U__ -D__PROG_TYPES_COMPAT__ -DMAX_ENDPOINT_INDEX=4 \ -std=gnu99 -Werror=implicit-function-declaration \ -fno-inline-small-functions -fshort-enums -fpack-struct \ - -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden \ + -ffunction-sections -fdata-sections -fvisibility=hidden \ -Wl,-strip-all -Wl,--gc-sections --data-sections \ -Wl,-relax -fno-split-wide-types -fno-tree-scev-cprop \ -fno-aggressive-loop-optimizations #-fno-jump-tables -fno-common From ac265b4ca6626a8f19f9d6960287b9852397bfe3 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sun, 13 Feb 2022 03:54:01 -0500 Subject: [PATCH 30/68] Out of hell ... Everything seems to be working again with the MEMORY_LIMITED_TESTING define set in the Makefile :) --- Firmware/Chameleon-Mini/Application/CryptoCMAC.c | 2 -- .../Chameleon-Mini/Application/DESFire/DESFireUtils.c | 10 ++++------ Firmware/Chameleon-Mini/Map.h | 4 ++++ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoCMAC.c b/Firmware/Chameleon-Mini/Application/CryptoCMAC.c index 54608891..dbdaff9f 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoCMAC.c +++ b/Firmware/Chameleon-Mini/Application/CryptoCMAC.c @@ -32,7 +32,6 @@ This notice must be retained at the top of all source files where indicated. #include "CryptoTDEA.h" #include "CryptoAES128.h" -#if 0 static uint8_t _cmac_K1[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; static uint8_t _cmac_K2[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; static uint8_t _cmac_RB[CRYPTO_MAX_BLOCK_SIZE] = { 0x00 }; @@ -191,4 +190,3 @@ bool checkBufferMAC(uint8_t *bufferData, uint16_t bufferSize, uint16_t checksumS } return true; } -#endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c index 6297d70e..811ef8ef 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c @@ -148,9 +148,8 @@ bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount) { } uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) { - //DEBUG_PRINT_P(PSTR("PRE -- CommMode -- 0x%02x"), CommMode); switch (CommMode) { - /*case DESFIRE_COMMS_PLAINTEXT_MAC: { + case DESFIRE_COMMS_PLAINTEXT_MAC: { uint16_t ChecksumBytes = 0; if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { ChecksumBytes = 4; @@ -187,7 +186,7 @@ uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buffe return 0; } return MAX(0, BufferSize - ChecksumBytes); - }*/ + } case DESFIRE_COMMS_PLAINTEXT: default: // Leave the CRCA bytes intact: @@ -196,9 +195,8 @@ uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buffe } uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) { - //DEBUG_PRINT_P(PSTR("POST -- CommMode -- 0x%02x"), CommMode); switch (CommMode) { - /*case DESFIRE_COMMS_PLAINTEXT_MAC: { + case DESFIRE_COMMS_PLAINTEXT_MAC: { if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { return appendBufferMAC(SessionKey, Buffer, BufferSize); } else { @@ -235,7 +233,7 @@ uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buff CryptoAESEncryptBuffer(XferBytes, Buffer, &Buffer[XferBytes], SessionIV, SessionKey); memmove(&Buffer[0], &Buffer[XferBytes], XferBytes); return XferBytes; - }*/ + } case DESFIRE_COMMS_PLAINTEXT: default: ISO14443AAppendCRCA(Buffer, BufferSize); diff --git a/Firmware/Chameleon-Mini/Map.h b/Firmware/Chameleon-Mini/Map.h index 17b8e79a..62dc5281 100644 --- a/Firmware/Chameleon-Mini/Map.h +++ b/Firmware/Chameleon-Mini/Map.h @@ -12,7 +12,11 @@ #include #include +#ifdef MEMORY_LIMITED_TESTING +#define MAP_TEXT_BUF_SIZE 24 +#else #define MAP_TEXT_BUF_SIZE 32 +#endif #define MAP_MAX_TEXT_SIZE (MAP_TEXT_BUF_SIZE - 1) typedef uint8_t MapIdType; From 138a174e56f0e076e307c4c200724005d7d0f7a0 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Mon, 14 Feb 2022 08:19:23 -0500 Subject: [PATCH 31/68] Swapping out previous __flash settings for commands lookup table into last half of LOG_FRAM (code and Makefile defines -- may still need to extract this new section using avr-objcopy -- pending testing) --- .../DESFire/DESFireFirmwareSettings.h | 1 + .../Application/DESFire/DESFireInstructions.c | 60 +++---------------- .../Application/DESFire/DESFireInstructions.h | 5 +- Firmware/Chameleon-Mini/Log.h | 13 +++- Firmware/Chameleon-Mini/Makefile | 16 +++-- Firmware/Chameleon-Mini/Memory.c | 2 - 6 files changed, 34 insertions(+), 63 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h index fa08e466..bf516d5c 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFirmwareSettings.h @@ -48,6 +48,7 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_FIRMWARE_ARRAY_ALIGNAT __attribute__((aligned(1))) #define DESFIRE_FIRMWARE_ENUM_PACKING __attribute__((aligned(1))) #define DESFIRE_FIRMWARE_NOINIT __attribute__((section(".noinit"))) +#define DESFIRE_DFFRAM_SECTION __attribute__((section(DESFIRE_DFFRAM_SECTION_NAME))) /* Some standard boolean interpreted and other values for types and return values: */ typedef int BOOL; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 89883f4e..e77ffb90 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -34,6 +34,7 @@ This notice must be retained at the top of all source files where indicated. #include "../../Common.h" #include "../../Random.h" +#include "DESFireFirmwareSettings.h" #include "DESFireInstructions.h" #include "DESFirePICCControl.h" #include "DESFireCrypto.h" @@ -118,245 +119,197 @@ static uint16_t ISO7816CmdAppendRecord(uint8_t *Buffer, uint16_t ByteCount); * handlers to the end of the array, or insert them haphazardly in * the middle !!! */ -const __flash DESFireCommand DESFireCommandSet[] = { +const DESFIRE_DFFRAM_SECTION DESFIRE_FIRMWARE_ALIGNAT DESFireCommand DESFireCommandSet[] = { { .insCode = CMD_AUTHENTICATE, - .insDesc = (const __flash char[]) { "Authenicate_Legacy" }, .insFunc = &EV0CmdAuthenticateLegacy1 }, { .insCode = CMD_CREDIT, - .insDesc = (const __flash char[]) { "Credit" }, .insFunc = &EV0CmdCredit }, { .insCode = CMD_AUTHENTICATE_ISO, - .insDesc = (const __flash char[]) { "Authenticate_ISO" }, .insFunc = &DesfireCmdAuthenticate3KTDEA1 }, { .insCode = CMD_LIMITED_CREDIT, - .insDesc = (const __flash char[]) { "Limited_Credit" }, .insFunc = &EV0CmdLimitedCredit }, { .insCode = CMD_WRITE_RECORD, - .insDesc = (const __flash char[]) { "Write_Record" }, .insFunc = &EV0CmdWriteRecord }, { .insCode = CMD_WRITE_DATA, - .insDesc = (const __flash char[]) { "Write_Data" }, .insFunc = &EV0CmdWriteData }, { .insCode = CMD_GET_KEY_SETTINGS, - .insDesc = (const __flash char[]) { "Get_Key_Settings" }, .insFunc = &EV0CmdGetKeySettings }, { .insCode = CMD_GET_CARD_UID, - .insDesc = (const __flash char[]) { "Get_Card_UID" }, .insFunc = &DesfireCmdGetCardUID }, { .insCode = CMD_CHANGE_KEY_SETTINGS, - .insDesc = (const __flash char[]) { "Change_Key_Settings" }, .insFunc = &EV0CmdChangeKeySettings }, { .insCode = CMD_SELECT_APPLICATION, - .insDesc = (const __flash char[]) { "Select_Application" }, .insFunc = &EV0CmdSelectApplication }, { .insCode = CMD_SET_CONFIGURATION, - .insDesc = (const __flash char[]) { "Set_Configuration" }, - .insFunc = NULL //&DesfireCmdSetConfiguration + .insFunc = NULL }, { .insCode = CMD_CHANGE_FILE_SETTINGS, - .insDesc = (const __flash char[]) { "Change_File_Settings" }, .insFunc = &EV0CmdChangeFileSettings }, { .insCode = CMD_GET_VERSION, - .insDesc = (const __flash char[]) { "Get_Version" }, .insFunc = &EV0CmdGetVersion1 }, { .insCode = CMD_GET_ISO_FILE_IDS, - .insDesc = (const __flash char[]) { "Get_ISO_File_IDs" }, .insFunc = &EV0CmdGetFileIds }, { .insCode = CMD_GET_KEY_VERSION, - .insDesc = (const __flash char[]) { "Get_Key_Version" }, .insFunc = &DesfireCmdGetKeyVersion }, { .insCode = CMD_GET_APPLICATION_IDS, - .insDesc = (const __flash char[]) { "Get_Application_IDs" }, .insFunc = &EV0CmdGetApplicationIds1 }, { .insCode = CMD_GET_VALUE, - .insDesc = (const __flash char[]) { "Get_Value" }, .insFunc = &EV0CmdGetValue }, { .insCode = CMD_GET_DF_NAMES, - .insDesc = (const __flash char[]) { "Get_DF_Names" }, .insFunc = &DesfireCmdGetDFNames }, { .insCode = CMD_FREE_MEMORY, - .insDesc = (const __flash char[]) { "Free_Memory" }, .insFunc = &DesfireCmdFreeMemory }, { .insCode = CMD_GET_FILE_IDS, - .insDesc = (const __flash char[]) { "Get_File_IDs" }, .insFunc = &EV0CmdGetFileIds }, { .insCode = CMD_AUTHENTICATE_EV2_FIRST, - .insDesc = (const __flash char[]) { "Authenticate_AES_EV2_First" }, .insFunc = NULL }, { .insCode = CMD_AUTHENTICATE_EV2_NONFIRST, - .insDesc = (const __flash char[]) { "Authenticate_AES_EV2_NonFirst" }, .insFunc = NULL }, { .insCode = CMD_ISO7816_EXTERNAL_AUTHENTICATE, - .insDesc = (const __flash char[]) { "ISO7816_External_Authenticate" }, .insFunc = &ISO7816CmdExternalAuthenticate }, { .insCode = CMD_ISO7816_GET_CHALLENGE, - .insDesc = (const __flash char[]) { "ISO7816_Get_Challenge" }, .insFunc = &ISO7816CmdGetChallenge }, { .insCode = CMD_ISO7816_SELECT, - .insDesc = (const __flash char[]) { "ISO7816_Select" }, .insFunc = &ISO7816CmdSelect }, { .insCode = CMD_ISO7816_INTERNAL_AUTHENTICATE, - .insDesc = (const __flash char[]) { "ISO7816_Internal_Authenticate" }, .insFunc = &ISO7816CmdInternalAuthenticate }, { .insCode = CMD_ABORT_TRANSACTION, - .insDesc = (const __flash char[]) { "Abort_Transaction" }, .insFunc = &EV0CmdAbortTransaction }, { .insCode = CMD_AUTHENTICATE_AES, - .insDesc = (const __flash char[]) { "Authenticate_AES" }, .insFunc = &DesfireCmdAuthenticateAES1 }, { .insCode = CMD_ISO7816_READ_BINARY, - .insDesc = (const __flash char[]) { "ISO7816_Read_Binary" }, .insFunc = &ISO7816CmdReadBinary }, { .insCode = CMD_ISO7816_READ_RECORDS, - .insDesc = (const __flash char[]) { "ISO7816_Read_Records" }, .insFunc = &ISO7816CmdReadRecords }, { .insCode = CMD_READ_RECORDS, - .insDesc = (const __flash char[]) { "Read_Records" }, .insFunc = &EV0CmdReadRecords }, { .insCode = CMD_READ_DATA, - .insDesc = (const __flash char[]) { "Read_Data" }, .insFunc = &EV0CmdReadData }, { .insCode = CMD_CREATE_CYCLIC_RECORD_FILE, - .insDesc = (const __flash char[]) { "Create_Cyclic_Record_File" }, .insFunc = &EV0CmdCreateCyclicRecordFile }, { .insCode = CMD_CREATE_LINEAR_RECORD_FILE, - .insDesc = (const __flash char[]) { "Create_Linear_Record_File" }, .insFunc = &EV0CmdCreateLinearRecordFile }, { .insCode = CMD_CHANGE_KEY, - .insDesc = (const __flash char[]) { "Change_Key" }, .insFunc = &EV0CmdChangeKey }, { .insCode = CMD_CREATE_APPLICATION, - .insDesc = (const __flash char[]) { "Create_Application" }, .insFunc = &EV0CmdCreateApplication }, { .insCode = CMD_CREATE_BACKUPDATA_FILE, - .insDesc = (const __flash char[]) { "Create_Backup_File" }, .insFunc = &EV0CmdCreateBackupDataFile }, { .insCode = CMD_CREATE_VALUE_FILE, - .insDesc = (const __flash char[]) { "Create_Value_File" }, .insFunc = &EV0CmdCreateValueFile }, { .insCode = CMD_CREATE_STDDATA_FILE, - .insDesc = (const __flash char[]) { "Create_Data_File" }, .insFunc = &EV0CmdCreateStandardDataFile }, { .insCode = CMD_COMMIT_TRANSACTION, - .insDesc = (const __flash char[]) { "Commit_Transaction" }, .insFunc = &EV0CmdCommitTransaction }, { .insCode = CMD_ISO7816_UPDATE_BINARY, - .insDesc = (const __flash char[]) { "ISO7816_Update_Binary" }, .insFunc = &ISO7816CmdUpdateBinary }, { .insCode = CMD_DELETE_APPLICATION, - .insDesc = (const __flash char[]) { "Delete_Application" }, .insFunc = &EV0CmdDeleteApplication }, { .insCode = CMD_DEBIT, - .insDesc = (const __flash char[]) { "Debit" }, .insFunc = &EV0CmdDebit }, { .insCode = CMD_DELETE_FILE, - .insDesc = (const __flash char[]) { "Delete_File" }, .insFunc = &EV0CmdDeleteFile }, { .insCode = CMD_ISO7816_APPEND_RECORD, - .insDesc = (const __flash char[]) { "ISO7816_Append_Record" }, .insFunc = &ISO7816CmdAppendRecord }, { .insCode = CMD_CLEAR_RECORD_FILE, - .insDesc = (const __flash char[]) { "Clear_Record_File" }, .insFunc = &EV0CmdClearRecords }, { .insCode = CMD_FORMAT_PICC, - .insDesc = (const __flash char[]) { "Format_PICC" }, .insFunc = &EV0CmdFormatPicc }, { .insCode = CMD_GET_FILE_SETTINGS, - .insDesc = (const __flash char[]) { "Get_File_Settings" }, .insFunc = &EV0CmdGetFileSettings }, }; @@ -367,14 +320,15 @@ uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount) { return DESFIRE_STATUS_RESPONSE_SIZE; } uint8_t insCode = Buffer[0]; - uint32_t insLookupTableBuf = &DESFireCommandSet[0]; uint16_t curInsLower = 0, curInsUpper = sizeof(DESFireCommandSet) / sizeof(DESFireCommand) - 1; uint16_t curInsIndex; + uint16_t nextDESFireFRAMBaseAddr = DESFIRE_DFFRAM_SECTION_START; DESFireCommand dfCmd; while (curInsUpper >= curInsLower) { curInsIndex = curInsLower + (curInsUpper + 1 - curInsLower) / 2; - memcpy_P(&dfCmd, insLookupTableBuf + curInsIndex * sizeof(DESFireCommand), sizeof(DESFireCommand)); - if (dfCmd.insCode == insCode) { + MemoryReadBlock(&dfCmd, nextDESFireFRAMBaseAddr, sizeof(DESFireCommand)); + nextDESFireFRAMBaseAddr += sizeof(DESFireCommand); + if (dfCmd.insCode == insCode) { if (dfCmd.insFunc == NULL) { return CmdNotImplemented(Buffer, ByteCount); } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h index 106a7dbb..1a17375d 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h @@ -115,10 +115,9 @@ typedef uint16_t (*InsCodeHandlerFunc)(uint8_t *Buffer, uint16_t ByteCount); typedef struct { DESFireCommandType insCode; InsCodeHandlerFunc insFunc; - const __flash char *insDesc; -} DESFireCommand; +} DESFireCommand DESFIRE_FIRMWARE_ALIGNAT; -extern const __flash DESFireCommand DESFireCommandSet[]; +extern const DESFIRE_DFFRAM_SECTION DESFIRE_FIRMWARE_ALIGNAT DESFireCommand DESFireCommandSet[]; /* Helper and batch process functions */ uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount); diff --git a/Firmware/Chameleon-Mini/Log.h b/Firmware/Chameleon-Mini/Log.h index 7b6b5241..3ae2943b 100644 --- a/Firmware/Chameleon-Mini/Log.h +++ b/Firmware/Chameleon-Mini/Log.h @@ -4,13 +4,24 @@ #include "Common.h" #ifdef MEMORY_LIMITED_TESTING -#define LOG_SIZE 764 // 1536 +#define LOG_SIZE 1024 #else #define LOG_SIZE 2048 #endif +#ifdef DESFIRE_FRAM_LOG_START +/* This is separated so we can store the large DESFire (native) and ISO7816 command subset + * oragnized in a sorted lookup table by command (byte) ID in the FRAM memory space. + * It is too large to fit in .data, and storing it in the FLASH space causes collision problems + * with the memory settings data storage (and probably slower access times). + */ +#define FRAM_LOG_ADDR_ADDR DESFIRE_FRAM_LOG_START // start of the second half of FRAM +#define FRAM_LOG_START_ADDR (DESFIRE_FRAM_LOG_START + 0x002) // directly after the address +#define FRAM_LOG_SIZE (DESFIRE_FRAM_LOG_SIZE) // the whole second half (minus the 2 Bytes of Address) +#else #define FRAM_LOG_ADDR_ADDR 0x4000 // start of the second half of FRAM #define FRAM_LOG_START_ADDR 0x4002 // directly after the address #define FRAM_LOG_SIZE 0x3FFE // the whole second half (minus the 2 Bytes of Address) +#endif extern uint8_t LogMem[LOG_SIZE]; extern uint8_t *LogMemPtr; diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 6a4b79f1..676c26c4 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -137,7 +137,15 @@ SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=1 DESFIRE_MAINSRC = Application/DESFire -DESFIRE_CONFIG_SETTINGS_BASE = $(SETTINGS) -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_LIMITED_TESTING -DDESFIRE_CRYPTO1_SAVE_SPACE -UDEFAULT_CONFIGURATION +DESFIRE_FRAM_LOG_START=0x4000 +DESFIRE_FRAM_LOG_SIZE=0x2046 +DESFIRE_DFFRAM_SECTION_START=0x6048 +DESFIRE_DFFRAM_SECTION_NAME=\".dffram\" +DESFIRE_CONFIG_SETTINGS_BASE=$(SETTINGS) -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_LIMITED_TESTING -DDESFIRE_CRYPTO1_SAVE_SPACE -UDEFAULT_CONFIGURATION \ + -DDESFIRE_FRAM_LOG_START=$(DESFIRE_FRAM_LOG_START) -DDESFIRE_FRAM_LOG_SIZE=$(DESFIRE_FRAM_LOG_SIZE) \ + -DDESFIRE_DFFRAM_SECTION_START=$(DESFIRE_DFFRAM_SECTION_START) \ + -Wl,--section-start=$(DESFIRE_DFFRAM_SECTION_NAME)=$(DESFIRE_DFFRAM_SECTION_START) \ + -DDESFIRE_DFFRAM_SECTION_NAME=$(DESFIRE_DFFRAM_SECTION_NAME) #Memory definitions and objcopy flags to include sections in binaries FLASH_DATA_ADDR = 0x10000 #Start of data section in flash @@ -192,9 +200,9 @@ CC_FLAGS = -g0 -DUSE_LUFA_CONFIG_HEADER -DFLASH_DATA_ADDR=$(FLASH_DATA_ADDR) -std=gnu99 -Werror=implicit-function-declaration \ -fno-inline-small-functions -fshort-enums -fpack-struct \ -ffunction-sections -fdata-sections -fvisibility=hidden \ - -Wl,-strip-all -Wl,--gc-sections --data-sections \ + -Wl,--gc-sections --data-sections \ -Wl,-relax -fno-split-wide-types -fno-tree-scev-cprop \ - -fno-aggressive-loop-optimizations #-fno-jump-tables -fno-common + -fno-aggressive-loop-optimizations -fno-jump-tables -fno-common LD_FLAGS = $(CC_FLAGS) -Wl,--section-start=.flashdata=$(FLASH_DATA_ADDR) -Wl,--section-start=.spmhelper=$(SPM_HELPER_ADDR) OBJDIR = Bin OBJECT_FILES = @@ -312,5 +320,5 @@ desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep check_size @avr-size -B -x $(TARGET).elf @echo -e "\n" @avr-size -C -x $(TARGET).elf -desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -DDEFAULT_CONFIGURATION=CONFIG_NONE +desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -DDEFAULT_CONFIGURATION=CONFIG_NONE -fno-inline-small-functions desfire: desfire-build diff --git a/Firmware/Chameleon-Mini/Memory.c b/Firmware/Chameleon-Mini/Memory.c index 889a4ea9..82b571ec 100644 --- a/Firmware/Chameleon-Mini/Memory.c +++ b/Firmware/Chameleon-Mini/Memory.c @@ -390,14 +390,12 @@ void MemoryWriteBlockInSetting(const void *Buffer, uint16_t Address, uint16_t By void MemoryClear(void) { FlashErase((uint32_t) GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING, MEMORY_SIZE_PER_SETTING); - MemoryRecall(); } void MemoryRecall(void) { /* Recall memory from permanent flash */ FlashToFRAM((uint32_t) GlobalSettings.ActiveSettingIdx * MEMORY_SIZE_PER_SETTING, MEMORY_SIZE_PER_SETTING); - SystemTickClearFlag(); } From 2d547404c28f24d988d0b36066042ae55fd2d1f2 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Mon, 14 Feb 2022 12:32:10 -0500 Subject: [PATCH 32/68] Separate section to store in flash not working -- Beginning new approach to put reduced size massive structure into plain old data mem --- .../Application/DESFire/DESFireInstructions.c | 7 +++-- .../Application/DESFire/DESFireInstructions.h | 2 +- Firmware/Chameleon-Mini/Log.h | 4 +-- Firmware/Chameleon-Mini/Makefile | 26 ++++++++++++------- Firmware/Chameleon-Mini/MemoryAsm.S | 6 +++++ 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index e77ffb90..ecec8abb 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -119,7 +119,7 @@ static uint16_t ISO7816CmdAppendRecord(uint8_t *Buffer, uint16_t ByteCount); * handlers to the end of the array, or insert them haphazardly in * the middle !!! */ -const DESFIRE_DFFRAM_SECTION DESFIRE_FIRMWARE_ALIGNAT DESFireCommand DESFireCommandSet[] = { +const DESFIRE_FIRMWARE_ALIGNAT DESFireCommand DESFireCommandSet[] DESFIRE_DFFRAM_SECTION = { { .insCode = CMD_AUTHENTICATE, .insFunc = &EV0CmdAuthenticateLegacy1 @@ -322,12 +322,11 @@ uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount) { uint8_t insCode = Buffer[0]; uint16_t curInsLower = 0, curInsUpper = sizeof(DESFireCommandSet) / sizeof(DESFireCommand) - 1; uint16_t curInsIndex; - uint16_t nextDESFireFRAMBaseAddr = DESFIRE_DFFRAM_SECTION_START; DESFireCommand dfCmd; while (curInsUpper >= curInsLower) { curInsIndex = curInsLower + (curInsUpper + 1 - curInsLower) / 2; - MemoryReadBlock(&dfCmd, nextDESFireFRAMBaseAddr, sizeof(DESFireCommand)); - nextDESFireFRAMBaseAddr += sizeof(DESFireCommand); + MemoryReadBlock(&dfCmd, DESFireCommandSet[curInsIndex], sizeof(DESFireCommand)); + nextDESFireFRAMBaseAddr += sizeof(DESFireCommand); if (dfCmd.insCode == insCode) { if (dfCmd.insFunc == NULL) { return CmdNotImplemented(Buffer, ByteCount); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h index 1a17375d..8149fe3c 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h @@ -117,7 +117,7 @@ typedef struct { InsCodeHandlerFunc insFunc; } DESFireCommand DESFIRE_FIRMWARE_ALIGNAT; -extern const DESFIRE_DFFRAM_SECTION DESFIRE_FIRMWARE_ALIGNAT DESFireCommand DESFireCommandSet[]; +extern const DESFIRE_FIRMWARE_ALIGNAT DESFireCommand DESFireCommandSet[]; /* Helper and batch process functions */ uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount); diff --git a/Firmware/Chameleon-Mini/Log.h b/Firmware/Chameleon-Mini/Log.h index 3ae2943b..19c60e82 100644 --- a/Firmware/Chameleon-Mini/Log.h +++ b/Firmware/Chameleon-Mini/Log.h @@ -10,9 +10,7 @@ #endif #ifdef DESFIRE_FRAM_LOG_START /* This is separated so we can store the large DESFire (native) and ISO7816 command subset - * oragnized in a sorted lookup table by command (byte) ID in the FRAM memory space. - * It is too large to fit in .data, and storing it in the FLASH space causes collision problems - * with the memory settings data storage (and probably slower access times). + * oragnized in a sorted lookup table by command (byte) ID in the FLASH -> FRAM memory space. */ #define FRAM_LOG_ADDR_ADDR DESFIRE_FRAM_LOG_START // start of the second half of FRAM #define FRAM_LOG_START_ADDR (DESFIRE_FRAM_LOG_START + 0x002) // directly after the address diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 676c26c4..c993d4e6 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -140,16 +140,22 @@ DESFIRE_MAINSRC = Application/DESFire DESFIRE_FRAM_LOG_START=0x4000 DESFIRE_FRAM_LOG_SIZE=0x2046 DESFIRE_DFFRAM_SECTION_START=0x6048 +DESFIRE_DFFRAM_DATA_ADDR=0x16048 +DESFIRE_DFFRAM_MAX_SIZE=0x0FFF DESFIRE_DFFRAM_SECTION_NAME=\".dffram\" DESFIRE_CONFIG_SETTINGS_BASE=$(SETTINGS) -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_LIMITED_TESTING -DDESFIRE_CRYPTO1_SAVE_SPACE -UDEFAULT_CONFIGURATION \ -DDESFIRE_FRAM_LOG_START=$(DESFIRE_FRAM_LOG_START) -DDESFIRE_FRAM_LOG_SIZE=$(DESFIRE_FRAM_LOG_SIZE) \ + -DDESFIRE_DFFRAM_MAX_SIZE=$(DESFIRE_DFFRAM_MAX_SIZE) \ -DDESFIRE_DFFRAM_SECTION_START=$(DESFIRE_DFFRAM_SECTION_START) \ - -Wl,--section-start=$(DESFIRE_DFFRAM_SECTION_NAME)=$(DESFIRE_DFFRAM_SECTION_START) \ + -DDESFIRE_DFFRAM_DATA_ADDR=$(DESFIRE_DFFRAM_DATA_ADDR) \ -DDESFIRE_DFFRAM_SECTION_NAME=$(DESFIRE_DFFRAM_SECTION_NAME) +DESFIRE_DFFRAM_OBJCOPY= --set-section-flags=.dffram="alloc,load,readonly" #Memory definitions and objcopy flags to include sections in binaries FLASH_DATA_ADDR = 0x10000 #Start of data section in flash FLASH_DATA_SIZE = 0x10000 #Size of data section in flash +#FLASH_DATA_ADDR = 0x12046 +#FLASH_DATA_SIZE = 0xF001 FLASH_DATA_OBJCOPY = --set-section-flags=.flashdata="alloc,load" SPM_HELPER_ADDR = 0x21FE0 #Start of SPM helper section. Should be last 32Byte in bootloader section SPM_HELPER_OBJCOPY = --set-section-flags=.spmhelper="alloc,load" @@ -194,7 +200,7 @@ SRC += $(DESFIRE_MAINSRC)/../MifareDESFire.c \ SRC += $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) LUFA_PATH = ../LUFA CC_FLAGS = -g0 -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) \ + -DSPM_HELPER_ADDR=$(SPM_HELPER_ADDR) -DBUILD_DATE=$(BUILD_DATE) -DCOMMIT_ID=\"$(COMMIT_ID)\" \ $(CONFIG_SETTINGS) $(SETTINGS) \ -D__AVR_ATxmega128A4U__ -D__PROG_TYPES_COMPAT__ -DMAX_ENDPOINT_INDEX=4 \ -std=gnu99 -Werror=implicit-function-declaration \ @@ -203,7 +209,8 @@ CC_FLAGS = -g0 -DUSE_LUFA_CONFIG_HEADER -DFLASH_DATA_ADDR=$(FLASH_DATA_ADDR) -Wl,--gc-sections --data-sections \ -Wl,-relax -fno-split-wide-types -fno-tree-scev-cprop \ -fno-aggressive-loop-optimizations -fno-jump-tables -fno-common -LD_FLAGS = $(CC_FLAGS) -Wl,--section-start=.flashdata=$(FLASH_DATA_ADDR) -Wl,--section-start=.spmhelper=$(SPM_HELPER_ADDR) +LD_FLAGS = $(CC_FLAGS) -Wl,--section-start=.flashdata=$(FLASH_DATA_ADDR) -Wl,--section-start=.spmhelper=$(SPM_HELPER_ADDR) \ + -Wl,--section-start=.dffram=$(DESFIRE_DFFRAM_DATA_ADDR) OBJDIR = Bin OBJECT_FILES = @@ -230,11 +237,6 @@ include $(LUFA_PATH)/Build/lufa_core.mk include $(LUFA_PATH)/Build/lufa_sources.mk include $(LUFA_PATH)/Build/lufa_build.mk include $(LUFA_PATH)/Build/lufa_cppcheck.mk -# include $(LUFA_PATH)/Build/lufa_doxygen.mk -# include $(LUFA_PATH)/Build/lufa_dfu.mk -# include $(LUFA_PATH)/Build/lufa_hid.mk -# include $(LUFA_PATH)/Build/lufa_avrdude.mk -# include $(LUFA_PATH)/Build/lufa_atprogram.mk #Overwrite the LUFA versions of hex/bin file generation to include spmhelper and flashdata sections %.hex: %.elf @@ -312,9 +314,15 @@ git-add-dev: ## Defining custom targets for the DESFire build (normal/user mode) and ## developer mode for use with the Android CMLD application that enables ## the printing of LIVE logs to the phone's console by default: -desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep check_size +desfire-objcopy: $(TARGET).elf + @echo $(MSG_OBJCPY_CMD) RE-Extracting HEX file data from \"$<\" + $(CROSS)-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature $(FLASH_DATA_OBJCOPY) $(DESFIRE_DFFRAM_OBJCOPY) $< $(TARGET).hex + @echo $(MSG_OBJCPY_CMD) RE-Extracting BIN file data from \"$<\" + $(CROSS)-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature $(FLASH_DATA_OBJCOPY) $< $(TARGET).bin @cp $(TARGET).hex $(TARGET)-DESFire.hex @cp $(TARGET).eep $(TARGET)-DESFire.eep + @cp $(TARGET).bin $(TARGET)-DESFire.bin +desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bin desfire-objcopy check_size @echo -e "\n" @avr-size -A -x $(TARGET).elf @avr-size -B -x $(TARGET).elf diff --git a/Firmware/Chameleon-Mini/MemoryAsm.S b/Firmware/Chameleon-Mini/MemoryAsm.S index 1821302e..da1a3ebf 100644 --- a/Firmware/Chameleon-Mini/MemoryAsm.S +++ b/Firmware/Chameleon-Mini/MemoryAsm.S @@ -223,3 +223,9 @@ FlashCommonSPM: .section .flashdata .align 1 .skip MEMORY_SIZE, MEMORY_INIT_VALUE + +#ifdef DESFIRE_FRAM_LOG_SIZE +.section .dffram +.align 1 +.skip DESFIRE_FRAM_LOG_SIZE, MEMORY_INIT_VALUE +#endif From 8f5053f7b9598a6b26869920650f2fe54cfb8eb5 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Mon, 14 Feb 2022 12:54:05 -0500 Subject: [PATCH 33/68] *Should* finally be working now -- Problem was that the SETTINGS memory remapped the FLASH memory space used by avr-gcc\'s __flash to a custom .flashdata section after the LUFA build by a second call to avr-objcopy -- Clever way to maximize slot space, but the previous code was not aware of that causing apparently quasi-non-deterministic behavior with some readers -- Cf. #313 and #315 --- .../Application/DESFire/DESFireInstructions.c | 5 ++--- .../Application/DESFire/DESFireInstructions.h | 2 -- Firmware/Chameleon-Mini/Log.h | 9 --------- Firmware/Chameleon-Mini/Makefile | 16 ++-------------- Firmware/Chameleon-Mini/MemoryAsm.S | 6 ------ 5 files changed, 4 insertions(+), 34 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index ecec8abb..8383fdbf 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -119,7 +119,7 @@ static uint16_t ISO7816CmdAppendRecord(uint8_t *Buffer, uint16_t ByteCount); * handlers to the end of the array, or insert them haphazardly in * the middle !!! */ -const DESFIRE_FIRMWARE_ALIGNAT DESFireCommand DESFireCommandSet[] DESFIRE_DFFRAM_SECTION = { +static const DESFireCommand DESFireCommandSet[] = { { .insCode = CMD_AUTHENTICATE, .insFunc = &EV0CmdAuthenticateLegacy1 @@ -325,8 +325,7 @@ uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount) { DESFireCommand dfCmd; while (curInsUpper >= curInsLower) { curInsIndex = curInsLower + (curInsUpper + 1 - curInsLower) / 2; - MemoryReadBlock(&dfCmd, DESFireCommandSet[curInsIndex], sizeof(DESFireCommand)); - nextDESFireFRAMBaseAddr += sizeof(DESFireCommand); + dfCmd = DESFireCommandSet[curInsIndex]; if (dfCmd.insCode == insCode) { if (dfCmd.insFunc == NULL) { return CmdNotImplemented(Buffer, ByteCount); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h index 8149fe3c..a31bf770 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h @@ -117,8 +117,6 @@ typedef struct { InsCodeHandlerFunc insFunc; } DESFireCommand DESFIRE_FIRMWARE_ALIGNAT; -extern const DESFIRE_FIRMWARE_ALIGNAT DESFireCommand DESFireCommandSet[]; - /* Helper and batch process functions */ uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount); diff --git a/Firmware/Chameleon-Mini/Log.h b/Firmware/Chameleon-Mini/Log.h index 19c60e82..c833d4d4 100644 --- a/Firmware/Chameleon-Mini/Log.h +++ b/Firmware/Chameleon-Mini/Log.h @@ -8,18 +8,9 @@ #else #define LOG_SIZE 2048 #endif -#ifdef DESFIRE_FRAM_LOG_START -/* This is separated so we can store the large DESFire (native) and ISO7816 command subset - * oragnized in a sorted lookup table by command (byte) ID in the FLASH -> FRAM memory space. - */ -#define FRAM_LOG_ADDR_ADDR DESFIRE_FRAM_LOG_START // start of the second half of FRAM -#define FRAM_LOG_START_ADDR (DESFIRE_FRAM_LOG_START + 0x002) // directly after the address -#define FRAM_LOG_SIZE (DESFIRE_FRAM_LOG_SIZE) // the whole second half (minus the 2 Bytes of Address) -#else #define FRAM_LOG_ADDR_ADDR 0x4000 // start of the second half of FRAM #define FRAM_LOG_START_ADDR 0x4002 // directly after the address #define FRAM_LOG_SIZE 0x3FFE // the whole second half (minus the 2 Bytes of Address) -#endif extern uint8_t LogMem[LOG_SIZE]; extern uint8_t *LogMemPtr; diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index c993d4e6..cd8a5bcf 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -143,19 +143,12 @@ DESFIRE_DFFRAM_SECTION_START=0x6048 DESFIRE_DFFRAM_DATA_ADDR=0x16048 DESFIRE_DFFRAM_MAX_SIZE=0x0FFF DESFIRE_DFFRAM_SECTION_NAME=\".dffram\" -DESFIRE_CONFIG_SETTINGS_BASE=$(SETTINGS) -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_LIMITED_TESTING -DDESFIRE_CRYPTO1_SAVE_SPACE -UDEFAULT_CONFIGURATION \ - -DDESFIRE_FRAM_LOG_START=$(DESFIRE_FRAM_LOG_START) -DDESFIRE_FRAM_LOG_SIZE=$(DESFIRE_FRAM_LOG_SIZE) \ - -DDESFIRE_DFFRAM_MAX_SIZE=$(DESFIRE_DFFRAM_MAX_SIZE) \ - -DDESFIRE_DFFRAM_SECTION_START=$(DESFIRE_DFFRAM_SECTION_START) \ - -DDESFIRE_DFFRAM_DATA_ADDR=$(DESFIRE_DFFRAM_DATA_ADDR) \ - -DDESFIRE_DFFRAM_SECTION_NAME=$(DESFIRE_DFFRAM_SECTION_NAME) +DESFIRE_CONFIG_SETTINGS_BASE=$(SETTINGS) -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_LIMITED_TESTING -DDESFIRE_CRYPTO1_SAVE_SPACE -UDEFAULT_CONFIGURATION DESFIRE_DFFRAM_OBJCOPY= --set-section-flags=.dffram="alloc,load,readonly" #Memory definitions and objcopy flags to include sections in binaries FLASH_DATA_ADDR = 0x10000 #Start of data section in flash FLASH_DATA_SIZE = 0x10000 #Size of data section in flash -#FLASH_DATA_ADDR = 0x12046 -#FLASH_DATA_SIZE = 0xF001 FLASH_DATA_OBJCOPY = --set-section-flags=.flashdata="alloc,load" SPM_HELPER_ADDR = 0x21FE0 #Start of SPM helper section. Should be last 32Byte in bootloader section SPM_HELPER_OBJCOPY = --set-section-flags=.spmhelper="alloc,load" @@ -314,15 +307,10 @@ git-add-dev: ## Defining custom targets for the DESFire build (normal/user mode) and ## developer mode for use with the Android CMLD application that enables ## the printing of LIVE logs to the phone's console by default: -desfire-objcopy: $(TARGET).elf - @echo $(MSG_OBJCPY_CMD) RE-Extracting HEX file data from \"$<\" - $(CROSS)-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature $(FLASH_DATA_OBJCOPY) $(DESFIRE_DFFRAM_OBJCOPY) $< $(TARGET).hex - @echo $(MSG_OBJCPY_CMD) RE-Extracting BIN file data from \"$<\" - $(CROSS)-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature $(FLASH_DATA_OBJCOPY) $< $(TARGET).bin +desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bin check_size @cp $(TARGET).hex $(TARGET)-DESFire.hex @cp $(TARGET).eep $(TARGET)-DESFire.eep @cp $(TARGET).bin $(TARGET)-DESFire.bin -desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bin desfire-objcopy check_size @echo -e "\n" @avr-size -A -x $(TARGET).elf @avr-size -B -x $(TARGET).elf diff --git a/Firmware/Chameleon-Mini/MemoryAsm.S b/Firmware/Chameleon-Mini/MemoryAsm.S index da1a3ebf..1821302e 100644 --- a/Firmware/Chameleon-Mini/MemoryAsm.S +++ b/Firmware/Chameleon-Mini/MemoryAsm.S @@ -223,9 +223,3 @@ FlashCommonSPM: .section .flashdata .align 1 .skip MEMORY_SIZE, MEMORY_INIT_VALUE - -#ifdef DESFIRE_FRAM_LOG_SIZE -.section .dffram -.align 1 -.skip DESFIRE_FRAM_LOG_SIZE, MEMORY_INIT_VALUE -#endif From 64d1fff60c8237363c37193b5f329fc4023eb8ac Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Tue, 15 Mar 2022 17:48:29 -0400 Subject: [PATCH 34/68] Stashing incremental changes from Arch for compilation on Mac --- .../Application/DESFire/DESFireISO14443Support.c | 5 ++--- .../Application/DESFire/DESFireISO14443Support.h | 3 --- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index 13452427..80043722 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -317,9 +317,8 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { back a response, so that we should not reset. */ decrementRetryCount = false; } else if (Cmd == ISO14443A_CMD_REQA || Cmd == ISO14443A_CMD_WUPA) { - ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); - CheckStateRetryCount(true); ISO144434Reset(); + ISO144433ASwitchState(ISO14443_3A_STATE_READY1); decrementRetryCount = false; } else if (ISO144433AIsHalt(Buffer, BitCount)) { LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); @@ -365,7 +364,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { return ISO14443A_ATQA_FRAME_SIZE_BYTES * BITS_PER_BYTE; case ISO14443_3A_STATE_READY1: - if (Cmd == ISO14443A_CMD_SELECT_CL1) { + if (Cmd == ISO14443A_CMD_SELECT_CL1 || Cmd == ISO14443A_CMD_REQA || Cmd == ISO14443A_CMD_WUPA) { /* Load UID CL1 and perform anticollision. */ ConfigurationUidType Uid; ApplicationGetUid(Uid); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index 11be3e0a..b7c02096 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -114,8 +114,6 @@ extern uint8_t StateRetryCount; bool CheckStateRetryCount(bool resetByDefault); bool CheckStateRetryCount2(bool resetByDefault, bool performLogging); -//#define IGNORE_ACK_BYTE (0x92) - /* Support functions */ void ISO144434SwitchState(Iso144434StateType NewState); void ISO144434SwitchState2(Iso144434StateType NewState, bool performLogging); @@ -134,7 +132,6 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 fullReturnBits = ByteCount * BITS_PER_BYTE + ISO14443A_CRC_FRAME_SIZE; \ fullReturnBits; \ }) -/* TODO: Should we return CRC bytes when giving a NO_RESPONSE ??? ... Apparently "No". */ #define GetAndSetNoResponseCRCA(Buffer) ({ \ uint16_t fullReturnBits = 0; \ ISO14443AAppendCRCA(Buffer, 0); \ From aafc5ab2e24a484eecb80df4459ba9c2b16346a6 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Wed, 16 Mar 2022 03:03:03 -0400 Subject: [PATCH 35/68] Stashing more incremental updates to the code to get/verify PM3 compatibility --- .../DESFire/DESFireISO14443Support.c | 23 +++++++++---------- .../DESFire/DESFireISO14443Support.h | 5 +++- .../DESFire/DESFireISO7816Support.c | 10 ++++---- .../DESFire/DESFireISO7816Support.h | 7 ++++++ .../Application/MifareDESFire.c | 20 ++++++++++++---- .../Application/MifareDESFire.h | 1 + 6 files changed, 45 insertions(+), 21 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index 80043722..bac41854 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -127,7 +127,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 ISO144434SwitchState(ISO14443_4_STATE_ACTIVE); const char *debugPrintStr = PSTR("ISO14443-4: SEND RATS"); LogDebuggingMsg(debugPrintStr); - return GetAndSetBufferCRCA(Buffer, ByteCount); + return ByteCount * BITS_PER_BYTE; // PM3 expects no CRCA bytes } case ISO14443_4_STATE_ACTIVE: { /* See: ISO/IEC 14443-4; 7.1 Block format */ @@ -277,6 +277,7 @@ Iso144433AStateType Iso144433AIdleState = ISO14443_3A_STATE_IDLE; void ISO144433ASwitchState(Iso144433AStateType NewState) { Iso144433AState = NewState; + StateRetryCount = 0x00; DesfireLogISOStateChange(Iso144433AState, LOG_ISO14443_3A_STATE); } @@ -316,9 +317,9 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { REQA bytes, in between which we would have already sent back a response, so that we should not reset. */ decrementRetryCount = false; - } else if (Cmd == ISO14443A_CMD_REQA || Cmd == ISO14443A_CMD_WUPA) { + } else if (Cmd == ISO14443A_CMD_REQA || ISO14443ACmdIsWUPA(Cmd)) { ISO144434Reset(); - ISO144433ASwitchState(ISO14443_3A_STATE_READY1); + ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); decrementRetryCount = false; } else if (ISO144433AIsHalt(Buffer, BitCount)) { LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); @@ -339,7 +340,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* See: ISO/IEC 14443-3, clause 6.2 */ switch (Iso144433AState) { case ISO14443_3A_STATE_HALT: - if (Cmd != ISO14443A_CMD_WUPA) { + if (!ISO14443ACmdIsWUPA(Cmd)) { const char *debugPrintStr = PSTR("ISO14443-4: HALT / NOT WUPA"); LogDebuggingMsg(debugPrintStr); break; @@ -349,12 +350,6 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* Fall-through */ case ISO14443_3A_STATE_IDLE: - if (Cmd != ISO14443A_CMD_REQA && - Cmd != ISO14443A_CMD_WUPA) { - const char *debugPrintStr = PSTR("ISO14443-4: IDLE / NOT WUPA 0x%02x"); - DEBUG_PRINT_P(debugPrintStr); - break; - } Iso144433AIdleState = Iso144433AState; ISO144433ASwitchState(ISO14443_3A_STATE_READY1); Buffer[0] = (ATQA_VALUE) & 0x00FF; @@ -364,7 +359,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { return ISO14443A_ATQA_FRAME_SIZE_BYTES * BITS_PER_BYTE; case ISO14443_3A_STATE_READY1: - if (Cmd == ISO14443A_CMD_SELECT_CL1 || Cmd == ISO14443A_CMD_REQA || Cmd == ISO14443A_CMD_WUPA) { + if (Cmd == ISO14443A_CMD_SELECT_CL1 || Cmd == ISO14443A_CMD_REQA || ISO14443ACmdIsWUPA(Cmd)) { /* Load UID CL1 and perform anticollision. */ ConfigurationUidType Uid; ApplicationGetUid(Uid); @@ -414,10 +409,14 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* Recognise the HLTA command */ if (ISO144433AIsHalt(Buffer, BitCount)) { LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); - ISO144433ASwitchState(ISO14443_3A_STATE_HALT); + ISO144434SwitchState(ISO14443_3A_STATE_HALT); const char *logMsg = PSTR("ISO14443-3: Got HALT"); LogDebuggingMsg(logMsg); return ISO14443A_APP_NO_RESPONSE; + } else if(Cmd == ISO14443A_CMD_RATS) { + ISO144433ASwitchState(ISO14443_4_STATE_EXPECT_RATS); + const char *logMsg = PSTR("ISO14443-3/4: EXPECTING RATS"); + LogDebuggingMsg(logMsg); } /* Forward to ISO/IEC 14443-4 processing code */ uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index b7c02096..73931a75 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -45,6 +45,9 @@ This notice must be retained at the top of all source files where indicated. #define ISO14443A_CMD_RNAK 0xB2 #define ISO14443A_CRC_FRAME_SIZE (ISO14443A_CRCA_SIZE * BITS_PER_BYTE) +#define ISO14443ACmdIsPM3WUPA(cmd) ((cmd & 0x54) == 0x54) +#define ISO14443ACmdIsWUPA(cmd) ((cmd == ISO14443A_CMD_WUPA) || ISO14443ACmdIsPM3WUPA(cmd)) + #define ISO14443_PCB_BLOCK_TYPE_MASK 0xC0 #define ISO14443_PCB_I_BLOCK 0x00 #define ISO14443_PCB_R_BLOCK 0x80 @@ -109,7 +112,7 @@ INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t Buff /* Setup some fuzzy response handling for problematic readers like the ACR122U */ -#define MAX_STATE_RETRY_COUNT (4) +#define MAX_STATE_RETRY_COUNT (0x8f) /* For all intensive purposes, as many as necessary */ extern uint8_t StateRetryCount; bool CheckStateRetryCount(bool resetByDefault); bool CheckStateRetryCount2(bool resetByDefault, bool performLogging); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c index 52b2e547..749ce28d 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c @@ -36,13 +36,15 @@ uint8_t Iso7816EfIdNumber = ISO7816_EF_NOT_SPECIFIED; bool IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount) { if (ByteCount <= ISO7816_PROLOGUE_SIZE + ISO14443A_CRCA_SIZE + 2) { - return false; + return ISO7816_WRAPPED_CMD_TYPE_NONE; } else if (!ISO14443ACheckCRCA(Buffer, ByteCount - 2)) { - return false; + return ISO7816_WRAPPED_CMD_TYPE_NONE; + } else if (ByteCount >= 4 && Buffer[3] == ByteCount - 4) { + return ISO7816_WRAPPED_CMD_TYPE_PM3RAW; } else if (!Iso7816CLA(Buffer[2])) { - return false; + return ISO7816_WRAPPED_CMD_TYPE_NONE; } - return true; + return ISO7816_WRAPPED_CMD_TYPE_STANDARD; } uint16_t SetIso7816WrappedParametersType(uint8_t *Buffer, uint16_t ByteCount) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h index 4330d7f2..c24b82ca 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h @@ -83,6 +83,13 @@ extern bool Iso7816FileSelected; extern uint8_t Iso7816FileOffset; extern uint8_t Iso7816EfIdNumber; +typedef enum { + ISO7816_WRAPPED_CMD_TYPE_NONE = 0, + ISO7816_WRAPPED_CMD_TYPE_STANDARD, + ISO7816_WRAPPED_CMD_TYPE_PM3RAW, + /* Others ??? */ +} Iso7816WrappedCommandType_t; + bool IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount); uint16_t SetIso7816WrappedParametersType(uint8_t *Buffer, uint16_t ByteCount); diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 13ed9684..181a9585 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -51,6 +51,7 @@ DesfireStateType DesfireState = DESFIRE_HALT; DesfireStateType DesfirePreviousState = DESFIRE_IDLE; bool DesfireFromHalt = false; BYTE DesfireCmdCLA = DESFIRE_NATIVE_CLA; +Iso7816WrappedCommandType_t Iso7816CmdType; static bool AnticolNoResp = false; /* Dispatching routines */ @@ -223,13 +224,22 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - return ISO14443AStoreLastDataFrameAndReturn(Buffer, DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE); - } else if (IsWrappedISO7816CommandType(Buffer, ByteCount)) { - DesfireCmdCLA = Buffer[2]; + return ISO14443AStoreLastDataFrameAndReturn(Buffer, + DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE); + } else if ((Iso7816CmdType = IsWrappedISO7816CommandType(Buffer, ByteCount)) && Iso7816CmdType != ISO7816_WRAPPED_CMD_TYPE_NONE) { + DesfireCmdCLA = (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) ? Buffer[2] : DESFIRE_ISO7816_CLA; uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], Buffer, 2); uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount); - memmove(&Buffer[0], &Buffer[2], IncomingByteCount - 2); + if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) { + memmove(&Buffer[0], &Buffer[2], IncomingByteCount - 2); + } else if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_PM3RAW) { + Buffer[0] = DesfireCmdCLA; + Buffer[1] = Buffer[2]; + Buffer[2] = 0x04; + memmove(&Buffer[4], &Buffer[3], IncomingByteCount - 2); + Buffer[3] = 0x00; + } uint16_t UnwrappedBitCount = (IncomingByteCount - 2) * BITS_PER_BYTE; uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; @@ -255,6 +265,8 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { // even when the reader has not been put in scan mode -- // and it really screws things up timing-wise! AnticolNoResp = true; + const char *debugPrintStr = PSTR("DESFire: Anticol NO-RESP set"); + LogDebuggingMsg(debugPrintStr); } return ISO14443AStoreLastDataFrameAndReturn(Buffer, PiccProcessRespBits); } diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.h b/Firmware/Chameleon-Mini/Application/MifareDESFire.h index add26775..c865e2ab 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.h +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.h @@ -89,5 +89,6 @@ extern DesfireStateType DesfireState; extern DesfireStateType DesfirePreviousState; extern bool DesfireFromHalt; extern BYTE DesfireCmdCLA; +extern Iso7816WrappedCommandType_t Iso7816CmdType; #endif /* MIFAREDESFIRE_H_ */ From bb7d46f208082b1502296971595e09682bcf5bcc Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Mon, 21 Mar 2022 18:34:11 -0400 Subject: [PATCH 36/68] Adding more complete support for PM3 ISO auth (stashing incremental changes as reference point) --- .../DESFire/DESFireISO14443Support.c | 21 +++++++++++-------- .../DESFire/DESFireISO14443Support.h | 2 +- .../DESFire/DESFireISO7816Support.c | 4 ++-- .../Chameleon-Mini/Application/ISO14443-3A.c | 4 ++-- .../Application/MifareDESFire.c | 11 ++++++---- Firmware/Chameleon-Mini/Makefile | 12 ++++++----- 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index bac41854..eb84692b 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -48,7 +48,7 @@ uint8_t ISO14443ALastDataFrame[MAX_DATA_FRAME_XFER_SIZE] = { 0x00 }; uint16_t ISO14443ALastDataFrameBits = 0; bool CheckStateRetryCount2(bool resetByDefault, bool performLogging) { - if (resetByDefault || ++StateRetryCount >= MAX_STATE_RETRY_COUNT) { + if (resetByDefault || ++StateRetryCount > MAX_STATE_RETRY_COUNT) { ISO144434SwitchState2(Iso144433AIdleState, performLogging); StateRetryCount = 0x00; const char *debugStatusMsg = PSTR("RETRY-RESET"); @@ -311,16 +311,16 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* Wakeup and Request may occure in all states */ bool checkStateRetryStatus = CheckStateRetryCount(false); - bool decrementRetryCount = true; + bool incrementRetryCount = true; if ((Cmd == ISO14443A_CMD_REQA) && (LastReaderSentCmd == ISO14443A_CMD_REQA) && !checkStateRetryStatus) { /* Catch timing issues where the reader sends multiple - REQA bytes, in between which we would have already sent - back a response, so that we should not reset. */ - decrementRetryCount = false; + REQA bytes, in between which we would have already sent + back a response, so that we should not reset. */ + incrementRetryCount = false; } else if (Cmd == ISO14443A_CMD_REQA || ISO14443ACmdIsWUPA(Cmd)) { ISO144434Reset(); ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); - decrementRetryCount = false; + incrementRetryCount = false; } else if (ISO144433AIsHalt(Buffer, BitCount)) { LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); ISO144433ASwitchState(ISO14443_3A_STATE_HALT); @@ -332,8 +332,8 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { return ISO14443A_APP_NO_RESPONSE; } LastReaderSentCmd = Cmd; - if (decrementRetryCount && StateRetryCount > 0) { - StateRetryCount -= 1; + if (incrementRetryCount) { + StateRetryCount += 1; } /* This implements ISO 14443-3A state machine */ @@ -406,6 +406,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { break; case ISO14443_3A_STATE_ACTIVE: + StateRetryCount = MAX_STATE_RETRY_COUNT; /* Recognise the HLTA command */ if (ISO144433AIsHalt(Buffer, BitCount)) { LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); @@ -413,10 +414,12 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { const char *logMsg = PSTR("ISO14443-3: Got HALT"); LogDebuggingMsg(logMsg); return ISO14443A_APP_NO_RESPONSE; - } else if(Cmd == ISO14443A_CMD_RATS) { + } else if (Cmd == ISO14443A_CMD_RATS) { ISO144433ASwitchState(ISO14443_4_STATE_EXPECT_RATS); const char *logMsg = PSTR("ISO14443-3/4: EXPECTING RATS"); LogDebuggingMsg(logMsg); + } else if (Cmd == ISO14443A_CMD_SELECT_CL3) { + return ISO14443A_APP_NO_RESPONSE; } /* Forward to ISO/IEC 14443-4 processing code */ uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index 73931a75..bf56f7db 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -112,7 +112,7 @@ INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t Buff /* Setup some fuzzy response handling for problematic readers like the ACR122U */ -#define MAX_STATE_RETRY_COUNT (0x8f) /* For all intensive purposes, as many as necessary */ +#define MAX_STATE_RETRY_COUNT (0x04) /* For all intensive purposes, as many as necessary */ extern uint8_t StateRetryCount; bool CheckStateRetryCount(bool resetByDefault); bool CheckStateRetryCount2(bool resetByDefault, bool performLogging); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c index 749ce28d..bc3f59bc 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c @@ -37,9 +37,9 @@ uint8_t Iso7816EfIdNumber = ISO7816_EF_NOT_SPECIFIED; bool IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount) { if (ByteCount <= ISO7816_PROLOGUE_SIZE + ISO14443A_CRCA_SIZE + 2) { return ISO7816_WRAPPED_CMD_TYPE_NONE; - } else if (!ISO14443ACheckCRCA(Buffer, ByteCount - 2)) { + } else if (!ISO14443ACheckCRCA(&Buffer[0], ByteCount - 2)) { return ISO7816_WRAPPED_CMD_TYPE_NONE; - } else if (ByteCount >= 4 && Buffer[3] == ByteCount - 4) { + } else if (ByteCount >= 6 && Buffer[3] == ByteCount - 6) { return ISO7816_WRAPPED_CMD_TYPE_PM3RAW; } else if (!Iso7816CLA(Buffer[2])) { return ISO7816_WRAPPED_CMD_TYPE_NONE; diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c index 717e725d..cc7192b4 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c @@ -160,10 +160,10 @@ bool ISO14443ACheckCRCA(const void *Buffer, uint16_t ByteCount) { bool ISO14443ASelect(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t SAKValue) { uint8_t *DataPtr = (uint8_t *) Buffer; uint8_t NVB = DataPtr[1]; - //uint8_t CollisionByteCount = (NVB >> 4) & 0x0F; - //uint8_t CollisionBitCount = (NVB >> 0) & 0x0F; switch (NVB) { + case 0x00: + case ISO14443A_CMD_HLTA: case ISO14443A_NVB_AC_START: /* Start of anticollision procedure. * Send whole UID CLn + BCC */ diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 181a9585..2b57edad 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -111,6 +111,7 @@ void MifareDesfireAppReset(void) { /* This is called repeatedly, so limit the amount of work done */ ISO144433AReset(); ISO144434Reset(); + StateRetryCount = MAX_STATE_RETRY_COUNT; MifareDesfireReset(); } @@ -230,16 +231,18 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { DesfireCmdCLA = (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) ? Buffer[2] : DESFIRE_ISO7816_CLA; uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], Buffer, 2); - uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount); if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) { - memmove(&Buffer[0], &Buffer[2], IncomingByteCount - 2); + memmove(&Buffer[0], &Buffer[2], ByteCount - 2); } else if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_PM3RAW) { + /* Looks something like: 0a 00 1a 00 CRC1 CRC2 (for PM3 raw ISO auth) */ Buffer[0] = DesfireCmdCLA; Buffer[1] = Buffer[2]; - Buffer[2] = 0x04; - memmove(&Buffer[4], &Buffer[3], IncomingByteCount - 2); + memmove(&Buffer[5], &Buffer[3], ByteCount - 3); + Buffer[2] = 0x00; Buffer[3] = 0x00; + Buffer[4] = ByteCount - 5; } + uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount); uint16_t UnwrappedBitCount = (IncomingByteCount - 2) * BITS_PER_BYTE; uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index cd8a5bcf..abc12c3f 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -124,9 +124,9 @@ SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 #Set a minimum incoming/outgoing log size so we do not spam the #Chameleon Mini logs to much by logging everything: -SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=1 -SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=1 -#SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 +SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=0 +#SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=1 +SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 #Enable printing of crypto tests when a new DESFire emulation instance is started: #SETTINGS += -DDESFIRE_RUN_CRYPTO_TESTING_PROCEDURE @@ -303,6 +303,8 @@ local-clean: git-add-dev: @git add Makefile ./*.{c,h} ./*/*.{c,h} ./*/*/*.{c,h} + @cd ../../Software/DESFireLibNFCTesting && \ + git add Makefile LocalInclude/*.h Source/*.c SampleOutputDumps/*.dump ## Defining custom targets for the DESFire build (normal/user mode) and ## developer mode for use with the Android CMLD application that enables @@ -311,10 +313,10 @@ desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).b @cp $(TARGET).hex $(TARGET)-DESFire.hex @cp $(TARGET).eep $(TARGET)-DESFire.eep @cp $(TARGET).bin $(TARGET)-DESFire.bin - @echo -e "\n" + @echo "" @avr-size -A -x $(TARGET).elf @avr-size -B -x $(TARGET).elf - @echo -e "\n" + @echo "" @avr-size -C -x $(TARGET).elf desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -DDEFAULT_CONFIGURATION=CONFIG_NONE -fno-inline-small-functions desfire: desfire-build From 1be76882044528e4a9d5e53234c94713521e92bf Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Mon, 21 Mar 2022 21:05:16 -0400 Subject: [PATCH 37/68] Adding more complete support for PM3 ISO auth (stashing incremental changes as reference point -- II) --- .../DESFire/DESFireISO14443Support.c | 2 +- .../DESFire/DESFireISO14443Support.h | 2 +- .../Chameleon-Mini/Application/ISO14443-3A.c | 4 ++-- .../Chameleon-Mini/Application/ISO14443-3A.h | 6 ------ .../Application/MifareDESFire.c | 20 ++++++++++--------- 5 files changed, 15 insertions(+), 19 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index eb84692b..58345e88 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -359,7 +359,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { return ISO14443A_ATQA_FRAME_SIZE_BYTES * BITS_PER_BYTE; case ISO14443_3A_STATE_READY1: - if (Cmd == ISO14443A_CMD_SELECT_CL1 || Cmd == ISO14443A_CMD_REQA || ISO14443ACmdIsWUPA(Cmd)) { + if (Cmd == ISO14443A_CMD_SELECT_CL1) { /* Load UID CL1 and perform anticollision. */ ConfigurationUidType Uid; ApplicationGetUid(Uid); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index bf56f7db..9c68f63f 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -112,7 +112,7 @@ INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t Buff /* Setup some fuzzy response handling for problematic readers like the ACR122U */ -#define MAX_STATE_RETRY_COUNT (0x04) /* For all intensive purposes, as many as necessary */ +#define MAX_STATE_RETRY_COUNT (0x0a) /* For all intensive purposes, as many as necessary */ extern uint8_t StateRetryCount; bool CheckStateRetryCount(bool resetByDefault); bool CheckStateRetryCount2(bool resetByDefault, bool performLogging); diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c index cc7192b4..06812994 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c @@ -19,6 +19,8 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, ui uint8_t NVB = DataPtr[1]; switch (NVB) { + case 0x00: + case ISO14443A_CMD_HLTA: case ISO14443A_NVB_AC_START: /* Start of anticollision procedure. * Send whole UID CLn + BCC */ @@ -162,8 +164,6 @@ bool ISO14443ASelect(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t S uint8_t NVB = DataPtr[1]; switch (NVB) { - case 0x00: - case ISO14443A_CMD_HLTA: case ISO14443A_NVB_AC_START: /* Start of anticollision procedure. * Send whole UID CLn + BCC */ diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h index d83f0b66..cefe7dbd 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h @@ -25,12 +25,6 @@ #define ISO14443A_NVB_AC_START 0x20 #define ISO14443A_NVB_AC_END 0x70 -#define IsSelectCmd(Buffer) ((Buffer[0] == ISO14443A_CMD_SELECT_CL1) || \ - (Buffer[0] == ISO14443A_CMD_SELECT_CL2) || \ - (Buffer[0] == ISO14443A_CMD_SELECT_CL3)) -#define IsCmdSelectRound1(Buffer) (IsSelectCmd(Buffer) && (Buffer[1] == ISO14443A_NVB_AC_START)) -#define IsCmdSelectRound2(Buffer) (IsSelectCmd(Buffer) && (Buffer[1] == ISO14443A_NVB_AC_END)) - #define ISO14443A_CL_UID_OFFSET 0 #define ISO14443A_CL_UID_SIZE 4 #define ISO14443A_CL_BCC_OFFSET 4 diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 2b57edad..d7e1e8cc 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -111,15 +111,13 @@ void MifareDesfireAppReset(void) { /* This is called repeatedly, so limit the amount of work done */ ISO144433AReset(); ISO144434Reset(); - StateRetryCount = MAX_STATE_RETRY_COUNT; MifareDesfireReset(); } void MifareDesfireAppTick(void) { - if (!CheckStateRetryCount2(false, false)) { + if (CheckStateRetryCount2(false, true)) { MifareDesfireAppReset(); } - /* Empty */ } void MifareDesfireAppTask(void) { @@ -176,12 +174,13 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { size_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; DesfireCmdCLA = Buffer[0]; - //LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); + LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); if (BitCount == 0) { LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); return ISO14443A_APP_NO_RESPONSE; } else if ((ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) || Iso7816CLA(DesfireCmdCLA)) { + Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) || + Iso7816CLA(DesfireCmdCLA)) { /* Wrapped native command structure or ISO7816: */ if (Iso7816CLA(DesfireCmdCLA)) { uint16_t iso7816ParamsStatus = SetIso7816WrappedParametersType(Buffer, ByteCount); @@ -204,9 +203,9 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[ByteCount - 1] = 0x91; ++ByteCount; } else { - /* Re-wrap into ISO 7816-4 */ + /* Re-wrap into ISO 7816-4 -- Done below by prepending the prologue back to the buffer */ } - //LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); + LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); return ByteCount * BITS_PER_BYTE; } else { /* ISO/IEC 14443-4 PDUs: No extra work */ @@ -233,16 +232,19 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { memcpy(&ISO7816PrologueBytes[0], Buffer, 2); if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) { memmove(&Buffer[0], &Buffer[2], ByteCount - 2); + ByteCount = ByteCount - 2; } else if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_PM3RAW) { - /* Looks something like: 0a 00 1a 00 CRC1 CRC2 (for PM3 raw ISO auth) */ + /* Something like the following (for PM3 raw ISO auth): + * 0a 00 1a 00 CRC1 CRC2 -- first two are prologue -- last two are checksum */ Buffer[0] = DesfireCmdCLA; Buffer[1] = Buffer[2]; memmove(&Buffer[5], &Buffer[3], ByteCount - 3); Buffer[2] = 0x00; Buffer[3] = 0x00; Buffer[4] = ByteCount - 5; + ByteCount = ByteCount + 3; } - uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount); + uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, ByteCount); uint16_t UnwrappedBitCount = (IncomingByteCount - 2) * BITS_PER_BYTE; uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; From bccf5792d140597ca2f994f3c16256b8484d5242 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Tue, 22 Mar 2022 06:36:24 -0400 Subject: [PATCH 38/68] Proposed PM3 ISO auth compliant fwmod -- pending testing --- .../Application/MifareDESFire.c | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index d7e1e8cc..f41a55ab 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -235,7 +235,8 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { ByteCount = ByteCount - 2; } else if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_PM3RAW) { /* Something like the following (for PM3 raw ISO auth): - * 0a 00 1a 00 CRC1 CRC2 -- first two are prologue -- last two are checksum */ + * 0a 00 1a 00 CRC1 CRC2 -- first two are prologue -- last two are checksum + */ Buffer[0] = DesfireCmdCLA; Buffer[1] = Buffer[2]; memmove(&Buffer[5], &Buffer[3], ByteCount - 3); @@ -255,6 +256,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedBitCount); } else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { /* This case should handle non-wrappped native commands. No pre/postprocessing afterwards: */ + LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ReturnedBytes); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ReturnedBytes * BITS_PER_BYTE); } else if (!AnticolNoResp || BitCount < BITS_PER_BYTE) { /* This case is to exchange anticollision loop and RATS data. No need to pre/postprocess it depending @@ -262,20 +264,22 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { */ uint16_t PiccProcessRespBits = ISO144433APiccProcess(Buffer, BitCount); if (PiccProcessRespBits == ISO14443A_APP_NO_RESPONSE) { - // Stop pesky USB readers trying to autodetect all tag types by brute-force enumeration - // from interfering with making it into the command exchange (DESFIRE_IDLE) states. - // Once the anticollision and/or RATS has completed, set this flag to keep it from - // resending that initial handshaking until the AppReset() function is called on a timeout. - // N.b., the ACR-122 reader does this repeatedly when trying to run the LibNFC testing code - // even when the reader has not been put in scan mode -- - // and it really screws things up timing-wise! + /* Stop pesky USB readers trying to autodetect all tag types by brute-force enumeration + * from interfering with making it into the command exchange (DESFIRE_IDLE) states. + * Once the anticollision and/or RATS has completed, set this flag to keep it from + * resending that initial handshaking until the AppReset() function is called on a timeout. + * N.b., the ACR-122 reader does this repeatedly when trying to run the LibNFC testing code + * even when the reader has not been put in scan mode -- + * and it really screws things up timing-wise! + */ AnticolNoResp = true; const char *debugPrintStr = PSTR("DESFire: Anticol NO-RESP set"); LogDebuggingMsg(debugPrintStr); } + uint16_t PiccProcessRespBytes = (PiccProcessRespBits + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, PiccProcessRespBytes); return ISO14443AStoreLastDataFrameAndReturn(Buffer, PiccProcessRespBits); } - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); return ISO14443A_APP_NO_RESPONSE; } From b8732616d0958e92bd5cb3f62bec9718dc93024c Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 26 Mar 2022 10:23:55 -0400 Subject: [PATCH 39/68] More progress towards PM3 compatible auth --- .../DESFire/DESFireISO7816Support.c | 13 ++-- .../DESFire/DESFireISO7816Support.h | 8 +-- .../Application/DESFire/DESFireInstructions.c | 68 +++++++++++-------- .../Chameleon-Mini/Application/ISO14443-3A.c | 2 +- .../Application/MifareDESFire.c | 44 +++++++----- Firmware/Chameleon-Mini/Makefile | 15 ++-- 6 files changed, 86 insertions(+), 64 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c index bc3f59bc..52ecc69b 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c @@ -34,17 +34,16 @@ bool Iso7816FileSelected = false; uint8_t Iso7816FileOffset = 0; uint8_t Iso7816EfIdNumber = ISO7816_EF_NOT_SPECIFIED; -bool IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount) { - if (ByteCount <= ISO7816_PROLOGUE_SIZE + ISO14443A_CRCA_SIZE + 2) { - return ISO7816_WRAPPED_CMD_TYPE_NONE; - } else if (!ISO14443ACheckCRCA(&Buffer[0], ByteCount - 2)) { - return ISO7816_WRAPPED_CMD_TYPE_NONE; - } else if (ByteCount >= 6 && Buffer[3] == ByteCount - 6) { +Iso7816WrappedCommandType_t IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount) { + if (ByteCount >= 6 && Buffer[3] == ByteCount - 6) { return ISO7816_WRAPPED_CMD_TYPE_PM3RAW; + } else if (ByteCount <= ISO7816_PROLOGUE_SIZE + ISO14443A_CRCA_SIZE + 2) { + return ISO7816_WRAPPED_CMD_TYPE_NONE; } else if (!Iso7816CLA(Buffer[2])) { return ISO7816_WRAPPED_CMD_TYPE_NONE; + } else { + return ISO7816_WRAPPED_CMD_TYPE_STANDARD; } - return ISO7816_WRAPPED_CMD_TYPE_STANDARD; } uint16_t SetIso7816WrappedParametersType(uint8_t *Buffer, uint16_t ByteCount) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h index c24b82ca..e134a632 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h @@ -84,13 +84,13 @@ extern uint8_t Iso7816FileOffset; extern uint8_t Iso7816EfIdNumber; typedef enum { - ISO7816_WRAPPED_CMD_TYPE_NONE = 0, - ISO7816_WRAPPED_CMD_TYPE_STANDARD, - ISO7816_WRAPPED_CMD_TYPE_PM3RAW, + ISO7816_WRAPPED_CMD_TYPE_NONE = 0, + ISO7816_WRAPPED_CMD_TYPE_STANDARD = 1, + ISO7816_WRAPPED_CMD_TYPE_PM3RAW = 2, /* Others ??? */ } Iso7816WrappedCommandType_t; -bool IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount); +Iso7816WrappedCommandType_t IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount); uint16_t SetIso7816WrappedParametersType(uint8_t *Buffer, uint16_t ByteCount); #endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 8383fdbf..7fc00dba 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -326,7 +326,7 @@ uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount) { while (curInsUpper >= curInsLower) { curInsIndex = curInsLower + (curInsUpper + 1 - curInsLower) / 2; dfCmd = DESFireCommandSet[curInsIndex]; - if (dfCmd.insCode == insCode) { + if (dfCmd.insCode == insCode) { if (dfCmd.insFunc == NULL) { return CmdNotImplemented(Buffer, ByteCount); } @@ -1713,6 +1713,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId, Status; BYTE keySize; + BYTE CryptoChallengeResponseBytesSize; BYTE *Key; /* Validate command length */ @@ -1728,10 +1729,10 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { * in the event of an error. */ KeyId = Buffer[1]; - if (!Authenticated || !AuthenticatedWithPICCMasterKey) { + if (!AuthenticatedWithPICCMasterKey && KeyId != DESFIRE_MASTER_KEY_ID) { Buffer[0] = STATUS_PERMISSION_DENIED; return DESFIRE_STATUS_RESPONSE_SIZE; - } else if (AuthenticatedWithKey != KeyId) { + } else if ((Authenticated || AuthenticatedWithPICCMasterKey) && AuthenticatedWithKey != KeyId) { Buffer[0] = STATUS_NO_SUCH_KEY; return DESFIRE_STATUS_RESPONSE_SIZE; } else { @@ -1750,13 +1751,20 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { return DESFIRE_STATUS_RESPONSE_SIZE; } - keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); + /* Update state */ Key = SessionKey; - - /* Indicate that we are in AES key authentication land */ DesfireCommandState.KeyId = KeyId; - DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; - DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); + if (!AuthenticatedWithPICCMasterKey) { + keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_DES); + DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_DES; + DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_DES); + + } else { + keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); + DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; + DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); + } + CryptoChallengeResponseBytesSize = keySize; /* Fetch the key */ ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); @@ -1764,7 +1772,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { /* Generate the nonce B (RndB / Challenge response) */ if (LocalTestingMode == 0) { - RandomGetBuffer(DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + RandomGetBuffer(DesfireCommandState.RndB, CryptoChallengeResponseBytesSize); } else { /* Fixed nonce for testing */ DesfireCommandState.RndB[0] = 0xCA; @@ -1784,10 +1792,10 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { DesfireCommandState.RndB[14] = 0x22; DesfireCommandState.RndB[15] = 0x33; } - LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CryptoChallengeResponseBytesSize); /* Encrypt RndB with the selected key and transfer it back to the PCD */ - Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, DesfireCommandState.RndB, + Encrypt3DESBuffer(CryptoChallengeResponseBytesSize, DesfireCommandState.RndB, &Buffer[1], NULL, Key); /* Scrub the key */ @@ -1796,54 +1804,57 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { /* Done */ DesfireState = DESFIRE_ISO_AUTHENTICATE2; Buffer[0] = STATUS_ADDITIONAL_FRAME; - return DESFIRE_STATUS_RESPONSE_SIZE + CRYPTO_CHALLENGE_RESPONSE_BYTES; + return DESFIRE_STATUS_RESPONSE_SIZE + CryptoChallengeResponseBytesSize; } uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId; BYTE cryptoKeyType, keySize; + BYTE CryptoChallengeResponseBytesSize; BYTE *Key; + cryptoKeyType = DesfireCommandState.CryptoMethodType; + keySize = GetDefaultCryptoMethodKeySize(cryptoKeyType); + CryptoChallengeResponseBytesSize = keySize; + /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; /* Validate command length */ - if (ByteCount != 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES + 1) { + if (ByteCount != 2 * CryptoChallengeResponseBytesSize + 1) { Buffer[0] = STATUS_LENGTH_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } /* Reset parameters for authentication from the first exchange */ KeyId = DesfireCommandState.KeyId; - cryptoKeyType = DesfireCommandState.CryptoMethodType; - keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); Key = SessionKey; ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); /* Decrypt the challenge sent back to get RndA and a shifted RndB */ - BYTE challengeRndAB[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; - BYTE challengeRndA[CRYPTO_CHALLENGE_RESPONSE_BYTES]; - BYTE challengeRndB[CRYPTO_CHALLENGE_RESPONSE_BYTES]; - Decrypt3DESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, + BYTE challengeRndAB[2 * CryptoChallengeResponseBytesSize]; + BYTE challengeRndA[CryptoChallengeResponseBytesSize]; + BYTE challengeRndB[CryptoChallengeResponseBytesSize]; + Decrypt3DESBuffer(2 * CryptoChallengeResponseBytesSize, challengeRndAB, &Buffer[1], NULL, Key); - RotateArrayRight(challengeRndAB + CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndB, - CRYPTO_CHALLENGE_RESPONSE_BYTES); - memcpy(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + RotateArrayRight(challengeRndAB + CryptoChallengeResponseBytesSize, challengeRndB, + CryptoChallengeResponseBytesSize); + memcpy(challengeRndA, challengeRndAB, CryptoChallengeResponseBytesSize); /* Check that the returned RndB matches what we sent in the previous round */ - if (memcmp(DesfireCommandState.RndB, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES)) { - LogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, (const void *) challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + if (memcmp(DesfireCommandState.RndB, challengeRndB, CryptoChallengeResponseBytesSize)) { + LogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, (const void *) challengeRndB, CryptoChallengeResponseBytesSize); Buffer[0] = STATUS_AUTHENTICATION_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } /* Encrypt and send back the once rotated RndA buffer to the PCD */ - RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - Encrypt3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, + RotateArrayLeft(challengeRndA, challengeRndAB, CryptoChallengeResponseBytesSize); + Encrypt3DESBuffer(CryptoChallengeResponseBytesSize, challengeRndAB, &Buffer[1], NULL, Key); /* Create the session key based on the previous exchange */ - generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_3K3DES); + generateSessionKey(SessionKey, challengeRndA, challengeRndB, cryptoKeyType); /* Now that we have auth'ed with the legacy command, a ChangeKey command will * allow for subsequent authentication with the ISO or AES routines @@ -1855,7 +1866,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Return the status on success */ Buffer[0] = STATUS_OPERATION_OK; - return DESFIRE_STATUS_RESPONSE_SIZE + CRYPTO_CHALLENGE_RESPONSE_BYTES; + return DESFIRE_STATUS_RESPONSE_SIZE + CryptoChallengeResponseBytesSize; } @@ -1990,7 +2001,6 @@ uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount) { if (memcmp(DesfireCommandState.RndB, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES)) { memcpy(challengeRndAB, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(challengeRndAB + CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - LogEntry(LOG_APP_NONCE_B, challengeRndAB, 2 * CRYPTO_CHALLENGE_RESPONSE_BYTES); Buffer[0] = STATUS_AUTHENTICATION_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c index 06812994..ebdbed03 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c @@ -20,7 +20,7 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, ui switch (NVB) { case 0x00: - case ISO14443A_CMD_HLTA: + case ISO14443A_CMD_HLTA: case ISO14443A_NVB_AC_START: /* Start of anticollision procedure. * Send whole UID CLn + BCC */ diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index f41a55ab..09d5a3d0 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -57,6 +57,7 @@ static bool AnticolNoResp = false; /* Dispatching routines */ void MifareDesfireReset(void) { AnticolNoResp = false; + //DesfireState = DESFIRE_IDLE; } static void MifareDesfireAppInitLocal(uint8_t StorageSize, uint8_t Version, bool FormatPICC) { @@ -178,9 +179,9 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { if (BitCount == 0) { LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); return ISO14443A_APP_NO_RESPONSE; - } else if ((ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - Buffer[3] == 0x00 && (Buffer[4] == ByteCount - 6 || Buffer[4] == ByteCount - 8)) || - Iso7816CLA(DesfireCmdCLA)) { + } else if (((ByteCount >= 8 && Buffer[4] == ByteCount - 8) || (ByteCount >= 5 && Buffer[4] == ByteCount - 5)) && + DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && + Buffer[3] == 0x00 || Iso7816CLA(DesfireCmdCLA)) { /* Wrapped native command structure or ISO7816: */ if (Iso7816CLA(DesfireCmdCLA)) { uint16_t iso7816ParamsStatus = SetIso7816WrappedParametersType(Buffer, ByteCount); @@ -193,10 +194,12 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { } ByteCount = Buffer[4]; Buffer[0] = Buffer[1]; - memmove(&Buffer[1], &Buffer[5], ByteCount); + if (ByteCount > 0) { + memmove(&Buffer[1], &Buffer[5], ByteCount); + } /* Process the command */ ByteCount = MifareDesfireProcessCommand(Buffer, ByteCount + 1); - if ((ByteCount != 0 && !Iso7816CLA(DesfireCmdCLA)) || (ByteCount == 1)) { + if ((ByteCount != 0 && !Iso7816CLA(DesfireCmdCLA))) { /* Re-wrap into padded APDU form */ Buffer[ByteCount] = Buffer[0]; memmove(&Buffer[0], &Buffer[1], ByteCount - 1); @@ -205,7 +208,6 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { } else { /* Re-wrap into ISO 7816-4 -- Done below by prepending the prologue back to the buffer */ } - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); return ByteCount * BITS_PER_BYTE; } else { /* ISO/IEC 14443-4 PDUs: No extra work */ @@ -217,6 +219,7 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; uint16_t ReturnedBytes = 0; + LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); if (ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) { DesfireCmdCLA = Buffer[0]; @@ -224,18 +227,21 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - return ISO14443AStoreLastDataFrameAndReturn(Buffer, - DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount) * BITS_PER_BYTE); - } else if ((Iso7816CmdType = IsWrappedISO7816CommandType(Buffer, ByteCount)) && Iso7816CmdType != ISO7816_WRAPPED_CMD_TYPE_NONE) { - DesfireCmdCLA = (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) ? Buffer[2] : DESFIRE_ISO7816_CLA; + ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); + LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedByteCount * BITS_PER_BYTE); + } + Iso7816CmdType = IsWrappedISO7816CommandType(Buffer, ByteCount); + if (Iso7816CmdType != ISO7816_WRAPPED_CMD_TYPE_NONE) { + DesfireCmdCLA = (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) ? Buffer[2] : DESFIRE_NATIVE_CLA; uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], Buffer, 2); if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) { memmove(&Buffer[0], &Buffer[2], ByteCount - 2); ByteCount = ByteCount - 2; } else if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_PM3RAW) { - /* Something like the following (for PM3 raw ISO auth): - * 0a 00 1a 00 CRC1 CRC2 -- first two are prologue -- last two are checksum + /* Something like the following (for PM3 raw ISO auth): + * 0a 00 1a 00 CRC1 CRC2 -- first two are prologue -- last two are checksum */ Buffer[0] = DesfireCmdCLA; Buffer[1] = Buffer[2]; @@ -243,17 +249,23 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[2] = 0x00; Buffer[3] = 0x00; Buffer[4] = ByteCount - 5; - ByteCount = ByteCount + 3; } uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, ByteCount); - uint16_t UnwrappedBitCount = (IncomingByteCount - 2) * BITS_PER_BYTE; + uint16_t UnwrappedBitCount = IncomingByteCount * BITS_PER_BYTE; uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + /* Undo the leading 0x91 and shift for the PM3 raw wrapped commands: */ + if (Iso7816CmdType != ISO7816_WRAPPED_CMD_TYPE_NONE) { + memmove(&Buffer[1], &Buffer[0], ProcessedByteCount); + Buffer[0] = Buffer[ProcessedByteCount]; + --ProcessedByteCount; + } /* Append the same ISO7816 prologue bytes to the response: */ memmove(&Buffer[2], &Buffer[0], ProcessedByteCount); memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); - ProcessedBitCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2) * BITS_PER_BYTE; - return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedBitCount); + ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); + LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedByteCount * BITS_PER_BYTE); } else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { /* This case should handle non-wrappped native commands. No pre/postprocessing afterwards: */ LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ReturnedBytes); diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index abc12c3f..9ccde99a 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -96,12 +96,12 @@ SETTINGS += -DENABLE_EEPROM_SETTINGS #Set a default logging mode for debugging with the DESFire #emulation code: -#SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING -SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF +SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING +#SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF #Set a default testing mode setting (0 = OFF, non-NULL = ON): -SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 -#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 +#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 +SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 #Feature: Use randomized UIDs that mask the actual secret UID until #the tag has been issued a successful authentication sequence: @@ -173,7 +173,8 @@ SRC += Terminal/Terminal.c Terminal/Commands.c Terminal/XModem.c Termina 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 \ - Application/CryptoTDEA-HWAccelerated.S Application/CryptoTDEA.c Application/CryptoAES128.c Application/CryptoCMAC.c \ + Application/CryptoTDEA-HWAccelerated.S Application/CryptoTDEA.c \ + Application/CryptoAES128.c Application/CryptoCMAC.c \ Tests/CryptoTests.c Tests/ChameleonTerminal.c SRC += Application/NTAG215.c SRC += Codec/ISO15693.c @@ -302,8 +303,8 @@ local-clean: @mkdir $(OBJDIR) git-add-dev: - @git add Makefile ./*.{c,h} ./*/*.{c,h} ./*/*/*.{c,h} - @cd ../../Software/DESFireLibNFCTesting && \ + @make style && git add Makefile ./*.{c,h} ./*/*.{c,h} ./*/*/*.{c,h} + @cd ../../Software/DESFireLibNFCTesting && make style && \ git add Makefile LocalInclude/*.h Source/*.c SampleOutputDumps/*.dump ## Defining custom targets for the DESFire build (normal/user mode) and From fecf5cbea23ac9646ffa7dc8ec96a6c7950ec2df Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 26 Mar 2022 10:44:07 -0400 Subject: [PATCH 40/68] More progress towards PM3 compatible auth II --- .../Application/DESFire/DESFireInstructions.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 7fc00dba..a955e466 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -1754,16 +1754,9 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { /* Update state */ Key = SessionKey; DesfireCommandState.KeyId = KeyId; - if (!AuthenticatedWithPICCMasterKey) { - keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_DES); - DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_DES; - DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_DES); - - } else { - keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); - DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; - DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); - } + keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); + DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; + DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); CryptoChallengeResponseBytesSize = keySize; /* Fetch the key */ @@ -1865,8 +1858,9 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { (KeyId == DESFIRE_MASTER_KEY_ID); /* Return the status on success */ - Buffer[0] = STATUS_OPERATION_OK; - return DESFIRE_STATUS_RESPONSE_SIZE + CryptoChallengeResponseBytesSize; + Buffer[0] = (SW_NO_ERROR >> 8) & 0x00ff; + Buffer[1] = SW_NO_ERROR & 0x00ff; + return 2 * DESFIRE_STATUS_RESPONSE_SIZE; } From 7ecf3cb18cdaceadfbb1bdecb68e1eee346bc47d Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 26 Mar 2022 18:25:54 -0400 Subject: [PATCH 41/68] Stuck on debugging issue with PM3 -- Posted to discord -- awaiting fix before this can get fixed --- .../DESFire/DESFireISO14443Support.h | 2 +- .../Application/DESFire/DESFireInstructions.c | 65 +++++++++++++++---- .../Application/MifareDESFire.c | 12 ++-- Firmware/Chameleon-Mini/Makefile | 26 +++++--- 4 files changed, 76 insertions(+), 29 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index 9c68f63f..694b983f 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -112,7 +112,7 @@ INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t Buff /* Setup some fuzzy response handling for problematic readers like the ACR122U */ -#define MAX_STATE_RETRY_COUNT (0x0a) /* For all intensive purposes, as many as necessary */ +#define MAX_STATE_RETRY_COUNT (0x0a) extern uint8_t StateRetryCount; bool CheckStateRetryCount(bool resetByDefault); bool CheckStateRetryCount2(bool resetByDefault, bool performLogging); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index a955e466..1444c50e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -1754,13 +1754,32 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { /* Update state */ Key = SessionKey; DesfireCommandState.KeyId = KeyId; - keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); - DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; - DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); - CryptoChallengeResponseBytesSize = keySize; + BYTE selectedKeyCryptoType = ReadKeyCryptoType(SelectedApp.Slot, KeyId); + if (selectedKeyCryptoType == CRYPTO_TYPE_ANY || selectedKeyCryptoType == CRYPTO_TYPE_3K3DES) { + keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); + DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; + DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); + CryptoChallengeResponseBytesSize = CRYPTO_CHALLENGE_RESPONSE_BYTES; + } else if (selectedKeyCryptoType == CRYPTO_TYPE_AES128) { + return DesfireCmdAuthenticateAES1(Buffer, ByteCount); + } else if (selectedKeyCryptoType == CRYPTO_TYPE_DES) { + keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_DES); + DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_DES; + DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_DES); + CryptoChallengeResponseBytesSize = CRYPTO_DES_BLOCK_SIZE; + } else { + keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_2KTDEA); + DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_2KTDEA; + DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_2KTDEA); + CryptoChallengeResponseBytesSize = CRYPTO_DES_BLOCK_SIZE; + } /* Fetch the key */ ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + if (selectedKeyCryptoType == CRYPTO_TYPE_DES) { + memcpy(&Key[CRYPTO_DES_BLOCK_SIZE], &Key[0], CRYPTO_DES_BLOCK_SIZE); + memcpy(&Key[2 * CRYPTO_DES_BLOCK_SIZE], &Key[0], CRYPTO_DES_BLOCK_SIZE); + } LogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); /* Generate the nonce B (RndB / Challenge response) */ @@ -1788,8 +1807,13 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CryptoChallengeResponseBytesSize); /* Encrypt RndB with the selected key and transfer it back to the PCD */ - Encrypt3DESBuffer(CryptoChallengeResponseBytesSize, DesfireCommandState.RndB, - &Buffer[1], NULL, Key); + if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES) { + Encrypt3DESBuffer(CryptoChallengeResponseBytesSize, DesfireCommandState.RndB, + &Buffer[1], NULL, Key); + } else { + Encrypt2K3DESBuffer(CryptoChallengeResponseBytesSize, DesfireCommandState.RndB, + &Buffer[1], NULL, Key); + } /* Scrub the key */ memset(Key, 0, keySize); @@ -1809,7 +1833,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { cryptoKeyType = DesfireCommandState.CryptoMethodType; keySize = GetDefaultCryptoMethodKeySize(cryptoKeyType); - CryptoChallengeResponseBytesSize = keySize; + CryptoChallengeResponseBytesSize = CRYPTO_CHALLENGE_RESPONSE_BYTES; /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; @@ -1823,13 +1847,22 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { KeyId = DesfireCommandState.KeyId; Key = SessionKey; ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES) { + memcpy(&Key[CRYPTO_DES_BLOCK_SIZE], &Key[0], CRYPTO_DES_BLOCK_SIZE); + memcpy(&Key[2 * CRYPTO_DES_BLOCK_SIZE], &Key[0], CRYPTO_DES_BLOCK_SIZE); + } /* Decrypt the challenge sent back to get RndA and a shifted RndB */ BYTE challengeRndAB[2 * CryptoChallengeResponseBytesSize]; BYTE challengeRndA[CryptoChallengeResponseBytesSize]; BYTE challengeRndB[CryptoChallengeResponseBytesSize]; - Decrypt3DESBuffer(2 * CryptoChallengeResponseBytesSize, challengeRndAB, - &Buffer[1], NULL, Key); + if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES) { + Decrypt3DESBuffer(2 * CryptoChallengeResponseBytesSize, challengeRndAB, + &Buffer[1], NULL, Key); + } else { + Decrypt2K3DESBuffer(2 * CryptoChallengeResponseBytesSize, challengeRndAB, + &Buffer[1], NULL, Key); + } RotateArrayRight(challengeRndAB + CryptoChallengeResponseBytesSize, challengeRndB, CryptoChallengeResponseBytesSize); memcpy(challengeRndA, challengeRndAB, CryptoChallengeResponseBytesSize); @@ -1843,8 +1876,13 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Encrypt and send back the once rotated RndA buffer to the PCD */ RotateArrayLeft(challengeRndA, challengeRndAB, CryptoChallengeResponseBytesSize); - Encrypt3DESBuffer(CryptoChallengeResponseBytesSize, challengeRndAB, - &Buffer[1], NULL, Key); + if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES) { + Encrypt3DESBuffer(CryptoChallengeResponseBytesSize, challengeRndAB, + &Buffer[1], NULL, Key); + } else { + Encrypt2K3DESBuffer(CryptoChallengeResponseBytesSize, challengeRndAB, + &Buffer[1], NULL, Key); + } /* Create the session key based on the previous exchange */ generateSessionKey(SessionKey, challengeRndA, challengeRndB, cryptoKeyType); @@ -1858,9 +1896,8 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { (KeyId == DESFIRE_MASTER_KEY_ID); /* Return the status on success */ - Buffer[0] = (SW_NO_ERROR >> 8) & 0x00ff; - Buffer[1] = SW_NO_ERROR & 0x00ff; - return 2 * DESFIRE_STATUS_RESPONSE_SIZE; + Buffer[0] = STATUS_OPERATION_OK; + return DESFIRE_STATUS_RESPONSE_SIZE; } diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 09d5a3d0..e5bec20b 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -57,7 +57,7 @@ static bool AnticolNoResp = false; /* Dispatching routines */ void MifareDesfireReset(void) { AnticolNoResp = false; - //DesfireState = DESFIRE_IDLE; + DesfireState = DESFIRE_IDLE; } static void MifareDesfireAppInitLocal(uint8_t StorageSize, uint8_t Version, bool FormatPICC) { @@ -199,7 +199,7 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { } /* Process the command */ ByteCount = MifareDesfireProcessCommand(Buffer, ByteCount + 1); - if ((ByteCount != 0 && !Iso7816CLA(DesfireCmdCLA))) { + if (ByteCount != 0 && !Iso7816CLA(DesfireCmdCLA)) { /* Re-wrap into padded APDU form */ Buffer[ByteCount] = Buffer[0]; memmove(&Buffer[0], &Buffer[1], ByteCount - 1); @@ -254,14 +254,16 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t UnwrappedBitCount = IncomingByteCount * BITS_PER_BYTE; uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - /* Undo the leading 0x91 and shift for the PM3 raw wrapped commands: */ - if (Iso7816CmdType != ISO7816_WRAPPED_CMD_TYPE_NONE) { + /* Undo the leading 0x91 and shift for the PM3 raw wrapped commands: (TODO) */ + if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_PM3RAW && ProcessedByteCount > 0) { memmove(&Buffer[1], &Buffer[0], ProcessedByteCount); Buffer[0] = Buffer[ProcessedByteCount]; --ProcessedByteCount; } /* Append the same ISO7816 prologue bytes to the response: */ - memmove(&Buffer[2], &Buffer[0], ProcessedByteCount); + if (ProcessedByteCount > 0) { + memmove(&Buffer[2], &Buffer[0], ProcessedByteCount); + } memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 9ccde99a..04293397 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -96,12 +96,12 @@ SETTINGS += -DENABLE_EEPROM_SETTINGS #Set a default logging mode for debugging with the DESFire #emulation code: -SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING -#SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF +#SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING +SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF #Set a default testing mode setting (0 = OFF, non-NULL = ON): -#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 -SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 +SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 +#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 #Feature: Use randomized UIDs that mask the actual secret UID until #the tag has been issued a successful authentication sequence: @@ -124,9 +124,10 @@ SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 #Set a minimum incoming/outgoing log size so we do not spam the #Chameleon Mini logs to much by logging everything: -SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=0 +SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=1 +#SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=0 #SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=1 -SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 +#SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 #Enable printing of crypto tests when a new DESFire emulation instance is started: #SETTINGS += -DDESFIRE_RUN_CRYPTO_TESTING_PROCEDURE @@ -143,9 +144,9 @@ DESFIRE_DFFRAM_SECTION_START=0x6048 DESFIRE_DFFRAM_DATA_ADDR=0x16048 DESFIRE_DFFRAM_MAX_SIZE=0x0FFF DESFIRE_DFFRAM_SECTION_NAME=\".dffram\" -DESFIRE_CONFIG_SETTINGS_BASE=$(SETTINGS) -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_LIMITED_TESTING -DDESFIRE_CRYPTO1_SAVE_SPACE -UDEFAULT_CONFIGURATION DESFIRE_DFFRAM_OBJCOPY= --set-section-flags=.dffram="alloc,load,readonly" - +DESFIRE_CONFIG_SETTINGS_BASE=$(SETTINGS) -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_LIMITED_TESTING \ + -DDESFIRE_CRYPTO1_SAVE_SPACE -DDEFAULT_CONFIGURATION=CONFIG_NONE #Memory definitions and objcopy flags to include sections in binaries FLASH_DATA_ADDR = 0x10000 #Start of data section in flash FLASH_DATA_SIZE = 0x10000 #Size of data section in flash @@ -268,7 +269,7 @@ dfu-prog: $(TARGET).hex $(TARGET).eep check_size dfu-programmer $(MCU) flash $(TARGET).hex dfu-programmer $(MCU) reset -check_size: +check_size: SHELL:=$(shell which bash) @{ \ set -e; \ if [ ! -f $(TARGET).elf ]; then \ @@ -321,3 +322,10 @@ desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).b @avr-size -C -x $(TARGET).elf desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -DDEFAULT_CONFIGURATION=CONFIG_NONE -fno-inline-small-functions desfire: desfire-build + +desfire-dev: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -fno-inline-small-functions \ + -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ + -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ + -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING \ + -DDESFIRE_DEFAULT_TESTING_MODE=1 +desfire-dev: desfire-build From 45a6c3fb025187644a0b8f09e8c8b0aa73deee77 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Tue, 29 Mar 2022 23:30:46 -0400 Subject: [PATCH 42/68] Stashing more working code to test PM3 compatibility (ISO/EV1 auth) --- .../Application/DESFire/DESFireCrypto.c | 6 ++- .../DESFire/DESFireISO7816Support.c | 3 ++ .../DESFire/DESFireISO7816Support.h | 9 +++-- .../Application/DESFire/DESFireInstructions.c | 39 +++++++++---------- .../Application/MifareDESFire.c | 24 ++++++++++-- Firmware/Chameleon-Mini/Makefile | 18 ++++----- 6 files changed, 60 insertions(+), 39 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c index 6c671beb..8bd8db28 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c @@ -71,14 +71,16 @@ bool IsAuthenticated(void) { BYTE GetDefaultCryptoMethodKeySize(uint8_t cryptoType) { switch (cryptoType) { + case CRYPTO_TYPE_ANY: + return CRYPTO_3KTDEA_KEY_SIZE; case CRYPTO_TYPE_2KTDEA: return CRYPTO_2KTDEA_KEY_SIZE; case CRYPTO_TYPE_3K3DES: return CRYPTO_3KTDEA_KEY_SIZE; case CRYPTO_TYPE_AES128: - return 16; + return CRYPTO_AES_BLOCK_SIZE; default: - return 8; + return CRYPTO_DES_BLOCK_SIZE; } } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c index 52ecc69b..b3a196e9 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.c @@ -26,6 +26,7 @@ This notice must be retained at the top of all source files where indicated. #include "DESFirePICCHeaderLayout.h" #include "DESFireISO7816Support.h" #include "DESFireInstructions.h" +#include "DESFireStatusCodes.h" #include "../ISO14443-3A.h" Iso7816WrappedParams_t Iso7816P1Data = ISO7816_NO_DATA; @@ -37,6 +38,8 @@ uint8_t Iso7816EfIdNumber = ISO7816_EF_NOT_SPECIFIED; Iso7816WrappedCommandType_t IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount) { if (ByteCount >= 6 && Buffer[3] == ByteCount - 6) { return ISO7816_WRAPPED_CMD_TYPE_PM3RAW; + } else if (ByteCount >= 3 && Buffer[2] == STATUS_ADDITIONAL_FRAME) { + return ISO7816_WRAPPED_CMD_TYPE_PM3_ADDITIONAL_FRAME; } else if (ByteCount <= ISO7816_PROLOGUE_SIZE + ISO14443A_CRCA_SIZE + 2) { return ISO7816_WRAPPED_CMD_TYPE_NONE; } else if (!Iso7816CLA(Buffer[2])) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h index e134a632..bea09a96 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h @@ -84,10 +84,11 @@ extern uint8_t Iso7816FileOffset; extern uint8_t Iso7816EfIdNumber; typedef enum { - ISO7816_WRAPPED_CMD_TYPE_NONE = 0, - ISO7816_WRAPPED_CMD_TYPE_STANDARD = 1, - ISO7816_WRAPPED_CMD_TYPE_PM3RAW = 2, - /* Others ??? */ + ISO7816_WRAPPED_CMD_TYPE_NONE = 0, + ISO7816_WRAPPED_CMD_TYPE_STANDARD = 1, + ISO7816_WRAPPED_CMD_TYPE_PM3RAW = 2, + ISO7816_WRAPPED_CMD_TYPE_PM3_ADDITIONAL_FRAME = 3, + /* ??? Others ??? */ } Iso7816WrappedCommandType_t; Iso7816WrappedCommandType_t IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 1444c50e..73b6e1bf 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -1732,9 +1732,6 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { if (!AuthenticatedWithPICCMasterKey && KeyId != DESFIRE_MASTER_KEY_ID) { Buffer[0] = STATUS_PERMISSION_DENIED; return DESFIRE_STATUS_RESPONSE_SIZE; - } else if ((Authenticated || AuthenticatedWithPICCMasterKey) && AuthenticatedWithKey != KeyId) { - Buffer[0] = STATUS_NO_SUCH_KEY; - return DESFIRE_STATUS_RESPONSE_SIZE; } else { InvalidateAuthState(SelectedApp.Slot == DESFIRE_PICC_APP_SLOT); } @@ -1744,25 +1741,19 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { Buffer[0] = STATUS_PARAMETER_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } - /* Make sure that this key is 3DES, and figure out its byte size */ - BYTE cryptoKeyType = ReadKeyCryptoType(SelectedApp.Slot, KeyId); - if (!CryptoType3KTDEA(cryptoKeyType)) { - Buffer[0] = STATUS_NO_SUCH_KEY; - return DESFIRE_STATUS_RESPONSE_SIZE; - } /* Update state */ Key = SessionKey; DesfireCommandState.KeyId = KeyId; - BYTE selectedKeyCryptoType = ReadKeyCryptoType(SelectedApp.Slot, KeyId); - if (selectedKeyCryptoType == CRYPTO_TYPE_ANY || selectedKeyCryptoType == CRYPTO_TYPE_3K3DES) { + BYTE cryptoKeyType = ReadKeyCryptoType(SelectedApp.Slot, KeyId); + if (cryptoKeyType == CRYPTO_TYPE_ANY || cryptoKeyType == CRYPTO_TYPE_3K3DES) { keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_3K3DES); DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_3K3DES; DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_3K3DES); CryptoChallengeResponseBytesSize = CRYPTO_CHALLENGE_RESPONSE_BYTES; - } else if (selectedKeyCryptoType == CRYPTO_TYPE_AES128) { + } else if (cryptoKeyType == CRYPTO_TYPE_AES128) { return DesfireCmdAuthenticateAES1(Buffer, ByteCount); - } else if (selectedKeyCryptoType == CRYPTO_TYPE_DES) { + } else if (cryptoKeyType == CRYPTO_TYPE_DES) { keySize = GetDefaultCryptoMethodKeySize(CRYPTO_TYPE_DES); DesfireCommandState.CryptoMethodType = CRYPTO_TYPE_DES; DesfireCommandState.ActiveCommMode = GetCryptoMethodCommSettings(CRYPTO_TYPE_DES); @@ -1776,7 +1767,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { /* Fetch the key */ ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); - if (selectedKeyCryptoType == CRYPTO_TYPE_DES) { + if (cryptoKeyType == CRYPTO_TYPE_DES) { memcpy(&Key[CRYPTO_DES_BLOCK_SIZE], &Key[0], CRYPTO_DES_BLOCK_SIZE); memcpy(&Key[2 * CRYPTO_DES_BLOCK_SIZE], &Key[0], CRYPTO_DES_BLOCK_SIZE); } @@ -1807,7 +1798,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CryptoChallengeResponseBytesSize); /* Encrypt RndB with the selected key and transfer it back to the PCD */ - if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES) { + if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || cryptoKeyType == CRYPTO_TYPE_ANY) { Encrypt3DESBuffer(CryptoChallengeResponseBytesSize, DesfireCommandState.RndB, &Buffer[1], NULL, Key); } else { @@ -1833,14 +1824,22 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { cryptoKeyType = DesfireCommandState.CryptoMethodType; keySize = GetDefaultCryptoMethodKeySize(cryptoKeyType); - CryptoChallengeResponseBytesSize = CRYPTO_CHALLENGE_RESPONSE_BYTES; + if (cryptoKeyType == CRYPTO_TYPE_ANY || cryptoKeyType == CRYPTO_TYPE_3K3DES) { + CryptoChallengeResponseBytesSize = CRYPTO_CHALLENGE_RESPONSE_BYTES; + } else if (cryptoKeyType == CRYPTO_TYPE_DES) { + CryptoChallengeResponseBytesSize = CRYPTO_DES_BLOCK_SIZE; + } else { + CryptoChallengeResponseBytesSize = CRYPTO_DES_BLOCK_SIZE; + } /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; /* Validate command length */ if (ByteCount != 2 * CryptoChallengeResponseBytesSize + 1) { Buffer[0] = STATUS_LENGTH_ERROR; - return DESFIRE_STATUS_RESPONSE_SIZE; + Buffer[1] = ByteCount; + Buffer[2] = CryptoChallengeResponseBytesSize; + return 3 * DESFIRE_STATUS_RESPONSE_SIZE; } /* Reset parameters for authentication from the first exchange */ @@ -1856,7 +1855,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { BYTE challengeRndAB[2 * CryptoChallengeResponseBytesSize]; BYTE challengeRndA[CryptoChallengeResponseBytesSize]; BYTE challengeRndB[CryptoChallengeResponseBytesSize]; - if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES) { + if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || cryptoKeyType == CRYPTO_TYPE_ANY) { Decrypt3DESBuffer(2 * CryptoChallengeResponseBytesSize, challengeRndAB, &Buffer[1], NULL, Key); } else { @@ -1876,7 +1875,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Encrypt and send back the once rotated RndA buffer to the PCD */ RotateArrayLeft(challengeRndA, challengeRndAB, CryptoChallengeResponseBytesSize); - if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES) { + if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || cryptoKeyType == CRYPTO_TYPE_ANY) { Encrypt3DESBuffer(CryptoChallengeResponseBytesSize, challengeRndAB, &Buffer[1], NULL, Key); } else { @@ -1897,7 +1896,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Return the status on success */ Buffer[0] = STATUS_OPERATION_OK; - return DESFIRE_STATUS_RESPONSE_SIZE; + return DESFIRE_STATUS_RESPONSE_SIZE + CryptoChallengeResponseBytesSize; } diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index e5bec20b..82f267d1 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -239,6 +239,16 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) { memmove(&Buffer[0], &Buffer[2], ByteCount - 2); ByteCount = ByteCount - 2; + } else if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_PM3_ADDITIONAL_FRAME) { + Buffer[0] = DesfireCmdCLA; + Buffer[1] = STATUS_ADDITIONAL_FRAME; + if (ByteCount > 3) { + memmove(&Buffer[3], &Buffer[5], ByteCount - 3); + } + Buffer[2] = 0x00; + Buffer[3] = 0x00; + Buffer[4] = ByteCount - 3; + ByteCount += 1; } else if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_PM3RAW) { /* Something like the following (for PM3 raw ISO auth): * 0a 00 1a 00 CRC1 CRC2 -- first two are prologue -- last two are checksum @@ -250,12 +260,15 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[3] = 0x00; Buffer[4] = ByteCount - 5; } - uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, ByteCount); - uint16_t UnwrappedBitCount = IncomingByteCount * BITS_PER_BYTE; + uint16_t UnwrappedBitCount = ByteCount * BITS_PER_BYTE; + if (Iso7816CmdType != ISO7816_WRAPPED_CMD_TYPE_PM3_ADDITIONAL_FRAME) { + uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, ByteCount); + UnwrappedBitCount = IncomingByteCount * BITS_PER_BYTE; + } uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - /* Undo the leading 0x91 and shift for the PM3 raw wrapped commands: (TODO) */ - if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_PM3RAW && ProcessedByteCount > 0) { + /* Undo the leading 0x91 and shift for the PM3 raw wrapped commands: */ + if (Iso7816CmdType != ISO7816_WRAPPED_CMD_TYPE_STANDARD && ProcessedByteCount > 0) { memmove(&Buffer[1], &Buffer[0], ProcessedByteCount); Buffer[0] = Buffer[ProcessedByteCount]; --ProcessedByteCount; @@ -312,6 +325,9 @@ void ResetLocalStructureData(void) { SessionIVByteSize = 0x00; SelectedApp.Slot = 0; SelectedFile.Num = -1; + ISO144433AReset(); + ISO144434Reset(); + MifareDesfireReset(); } void MifareDesfireGetUid(ConfigurationUidType Uid) { diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 04293397..c43982f4 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -96,12 +96,12 @@ SETTINGS += -DENABLE_EEPROM_SETTINGS #Set a default logging mode for debugging with the DESFire #emulation code: -#SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING -SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF +#CONFIG_SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING +CONFIG_SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF #Set a default testing mode setting (0 = OFF, non-NULL = ON): -SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 -#SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 +CONFIG_SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 +#CONFIG_SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 #Feature: Use randomized UIDs that mask the actual secret UID until #the tag has been issued a successful authentication sequence: @@ -124,10 +124,10 @@ SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 #Set a minimum incoming/outgoing log size so we do not spam the #Chameleon Mini logs to much by logging everything: -SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=1 -#SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=0 -#SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=1 -#SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 +CONFIG_SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=1 +#CONFIG_SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=0 +#CONFIG_SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=1 +#CONFIG_SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 #Enable printing of crypto tests when a new DESFire emulation instance is started: #SETTINGS += -DDESFIRE_RUN_CRYPTO_TESTING_PROCEDURE @@ -320,7 +320,7 @@ desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).b @avr-size -B -x $(TARGET).elf @echo "" @avr-size -C -x $(TARGET).elf -desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -DDEFAULT_CONFIGURATION=CONFIG_NONE -fno-inline-small-functions +desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -fno-inline-small-functions desfire: desfire-build desfire-dev: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -fno-inline-small-functions \ From f4faaa75cb744a2af0ea73ee34042f2f8a270748 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Wed, 30 Mar 2022 10:00:26 -0400 Subject: [PATCH 43/68] Working ISO authentication on the PM3 : cf. #313 --- .../Chameleon-Mini/Application/CryptoAES128.c | 24 ++++-- .../Chameleon-Mini/Application/CryptoTDEA.c | 77 ++++++++++++------- .../Chameleon-Mini/Application/CryptoTDEA.h | 4 + .../Application/DESFire/DESFireCrypto.c | 2 + .../DESFire/DESFireISO14443Support.c | 3 +- .../Application/DESFire/DESFireInstructions.c | 58 +++++++------- .../Application/MifareDESFire.c | 10 ++- 7 files changed, 113 insertions(+), 65 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoAES128.c b/Firmware/Chameleon-Mini/Application/CryptoAES128.c index 321b0273..74b2ac2c 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoAES128.c +++ b/Firmware/Chameleon-Mini/Application/CryptoAES128.c @@ -45,7 +45,7 @@ static aes_callback_t __CryptoAESCallbackFunc = NULL; static CryptoAESBlock_t __CryptoAES_IVData = { 0 }; /* Set the last operation mode (ECB or CBC) init for the context */ -static uint8_t __CryptoAESOpMode = CRYPTO_AES_CBC_MODE; +static uint8_t __CryptoAESOpMode = CRYPTO_AES_ECB_MODE; void aes_start(void) { AES.CTRL |= AES_START_bm; @@ -238,16 +238,18 @@ static void CryptoAESDecryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_t CryptoAESEncryptBuffer(uint16_t Count, uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_t *IV, const uint8_t *Key) { + bool copyIVBuffer = true; if ((Count % CRYPTO_AES_BLOCK_SIZE) != 0) { return 0xBE; } else if (IV == NULL) { memset(__CryptoAES_IVData, 0x00, CRYPTO_AES_BLOCK_SIZE); IV = &__CryptoAES_IVData[0]; + copyIVBuffer = false; } + CryptoAESBlock_t inputBlock; size_t bufBlocks = (Count + CRYPTO_AES_BLOCK_SIZE - 1) / CRYPTO_AES_BLOCK_SIZE; for (int blk = 0; blk < bufBlocks; blk++) { if (__CryptoAESOpMode == CRYPTO_AES_CBC_MODE) { - CryptoAESBlock_t inputBlock; if (blk == 0) { memcpy(inputBlock, &Plaintext[0], CRYPTO_AES_BLOCK_SIZE); CryptoMemoryXOR(IV, inputBlock, CRYPTO_AES_BLOCK_SIZE); @@ -256,9 +258,14 @@ uint8_t CryptoAESEncryptBuffer(uint16_t Count, uint8_t *Plaintext, uint8_t *Ciph CryptoMemoryXOR(&Plaintext[blk * CRYPTO_AES_BLOCK_SIZE], inputBlock, CRYPTO_AES_BLOCK_SIZE); } CryptoAESEncryptBlock(inputBlock, Ciphertext + blk * CRYPTO_AES_BLOCK_SIZE, Key, true); + if (blk + 1 == bufBlocks && copyIVBuffer) { + memcpy(IV, inputBlock, CRYPTO_AES_BLOCK_SIZE); + } } else { - CryptoAESEncryptBlock(Plaintext + blk * CRYPTO_AES_BLOCK_SIZE, - Ciphertext + blk * CRYPTO_AES_BLOCK_SIZE, Key, true); + memcpy(inputBlock, Plaintext + blk * CRYPTO_AES_BLOCK_SIZE, CRYPTO_AES_BLOCK_SIZE); + CryptoMemoryXOR(IV, inputBlock, CRYPTO_AES_BLOCK_SIZE); + CryptoAESEncryptBlock(inputBlock, Ciphertext + blk * CRYPTO_AES_BLOCK_SIZE, Key, true); + memcpy(IV, Ciphertext + blk * CRYPTO_AES_BLOCK_SIZE, CRYPTO_AES_BLOCK_SIZE); } } return 0; @@ -266,16 +273,18 @@ uint8_t CryptoAESEncryptBuffer(uint16_t Count, uint8_t *Plaintext, uint8_t *Ciph uint8_t CryptoAESDecryptBuffer(uint16_t Count, uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_t *IV, const uint8_t *Key) { + bool copyIVBuffer = true; if ((Count % CRYPTO_AES_BLOCK_SIZE) != 0) { return 0xBE; } else if (IV == NULL) { memset(__CryptoAES_IVData, 0x00, CRYPTO_AES_BLOCK_SIZE); IV = &__CryptoAES_IVData[0]; + copyIVBuffer = false; } + CryptoAESBlock_t inputBlock; size_t bufBlocks = (Count + CRYPTO_AES_BLOCK_SIZE - 1) / CRYPTO_AES_BLOCK_SIZE; for (int blk = 0; blk < bufBlocks; blk++) { if (__CryptoAESOpMode == CRYPTO_AES_CBC_MODE) { - CryptoAESBlock_t inputBlock; CryptoAESDecryptBlock(inputBlock, Ciphertext + blk * CRYPTO_AES_BLOCK_SIZE, Key); if (blk == 0) { memcpy(Plaintext + blk * CRYPTO_AES_BLOCK_SIZE, inputBlock, CRYPTO_AES_BLOCK_SIZE); @@ -285,9 +294,14 @@ uint8_t CryptoAESDecryptBuffer(uint16_t Count, uint8_t *Plaintext, uint8_t *Ciph CryptoMemoryXOR(&Ciphertext[(blk - 1) * CRYPTO_AES_BLOCK_SIZE], Plaintext + blk * CRYPTO_AES_BLOCK_SIZE, CRYPTO_AES_BLOCK_SIZE); } + if (blk + 1 == bufBlocks && copyIVBuffer) { + memcpy(IV, inputBlock, CRYPTO_AES_BLOCK_SIZE); + } } else { CryptoAESDecryptBlock(Plaintext + blk * CRYPTO_AES_BLOCK_SIZE, Ciphertext + blk * CRYPTO_AES_BLOCK_SIZE, Key); + CryptoMemoryXOR(IV, Plaintext + blk * CRYPTO_AES_BLOCK_SIZE, CRYPTO_AES_BLOCK_SIZE); + memcpy(IV, Ciphertext + blk * CRYPTO_AES_BLOCK_SIZE, CRYPTO_AES_BLOCK_SIZE); } } return 0; diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c index 78145671..2b773186 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.c +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.c @@ -8,12 +8,14 @@ #include "CryptoTDEA.h" #include "CryptoAES128.h" +/* Set the last operation mode (ECB or CBC) init for the context */ +static uint8_t __CryptoDESOpMode = CRYPTO_DES_ECB_MODE; + static void CryptoEncryptCBCBuffer(CryptoTDEA_CBCSpec *CryptoSpec, uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys); static void CryptoEncryptCBCBuffer(CryptoTDEA_CBCSpec *CryptoSpec, uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { uint16_t numBlocks = (Count + CryptoSpec->blockSize - 1) / CryptoSpec->blockSize; bool dataNeedsPadding = (Count % CryptoSpec->blockSize) != 0; uint16_t blockIndex = 0; - uint8_t *ctBuf = (uint8_t *) Ciphertext; uint8_t inputBlock[CryptoSpec->blockSize]; uint8_t IV[CryptoSpec->blockSize]; if (IVIn == NULL) { @@ -22,22 +24,31 @@ static void CryptoEncryptCBCBuffer(CryptoTDEA_CBCSpec *CryptoSpec, uint16_t Coun memcpy(IV, IVIn, CryptoSpec->blockSize); } while (blockIndex < numBlocks) { - if (blockIndex == 0) { - memset(inputBlock, 0x00, CryptoSpec->blockSize); - memcpy(inputBlock, &Plaintext[0], CryptoSpec->blockSize); + if (__CryptoDESOpMode == CRYPTO_DES_CBC_MODE) { + if (blockIndex == 0) { + memset(inputBlock, 0x00, CryptoSpec->blockSize); + memcpy(inputBlock, &Plaintext[0], CryptoSpec->blockSize); + CryptoMemoryXOR(IV, inputBlock, CryptoSpec->blockSize); + } else if (dataNeedsPadding && blockIndex + 1 == numBlocks) { + memset(inputBlock, 0x00, CryptoSpec->blockSize); + memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CryptoSpec->blockSize], Count % CryptoSpec->blockSize); + CryptoMemoryXOR(&Plaintext[blockIndex * CryptoSpec->blockSize], inputBlock, CryptoSpec->blockSize); + } else { + memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CryptoSpec->blockSize], CryptoSpec->blockSize); + CryptoMemoryXOR(&Plaintext[blockIndex * CryptoSpec->blockSize], inputBlock, CryptoSpec->blockSize); + } + CryptoSpec->cryptFunc(inputBlock, &Ciphertext[blockIndex * CryptoSpec->blockSize], Keys); + } else { /* ECB mode */ + memcpy(inputBlock, &Plaintext[blockIndex * CryptoSpec->blockSize], CryptoSpec->blockSize); CryptoMemoryXOR(IV, inputBlock, CryptoSpec->blockSize); - } else if (dataNeedsPadding && blockIndex + 1 == numBlocks) { - memset(inputBlock, 0x00, CryptoSpec->blockSize); - memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CryptoSpec->blockSize], Count % CryptoSpec->blockSize); - CryptoMemoryXOR(&Plaintext[blockIndex * CryptoSpec->blockSize], inputBlock, CryptoSpec->blockSize); - } else { - memcpy(inputBlock, &Ciphertext[(blockIndex - 1) * CryptoSpec->blockSize], CryptoSpec->blockSize); - CryptoMemoryXOR(&Plaintext[blockIndex * CryptoSpec->blockSize], inputBlock, CryptoSpec->blockSize); + CryptoSpec->cryptFunc(inputBlock, &Ciphertext[blockIndex * CryptoSpec->blockSize], Keys); + memcpy(IV, &Ciphertext[blockIndex * CryptoSpec->blockSize], CryptoSpec->blockSize); } - CryptoSpec->cryptFunc(inputBlock, ctBuf, Keys); - ctBuf += CryptoSpec->blockSize; blockIndex++; } + if (IVIn != NULL) { + memcpy(IVIn, IV, CryptoSpec->blockSize); + } } static void CryptoDecryptCBCBuffer(CryptoTDEA_CBCSpec *CryptoSpec, uint16_t Count, void *Plaintext, const void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys); @@ -53,24 +64,34 @@ static void CryptoDecryptCBCBuffer(CryptoTDEA_CBCSpec *CryptoSpec, uint16_t Coun memcpy(IV, IVIn, CryptoSpec->blockSize); } while (blockIndex < numBlocks) { - CryptoSpec->cryptFunc(inputBlock, Ciphertext + blockIndex * CryptoSpec->blockSize, Keys); - if (blockIndex == 0 && !dataNeedsPadding) { - memcpy(Plaintext, inputBlock, CryptoSpec->blockSize); - CryptoMemoryXOR(IV, Plaintext, CryptoSpec->blockSize); - } else if (blockIndex == 0 && dataNeedsPadding && numBlocks == 0x01) { - memcpy(Plaintext, inputBlock, Count % CryptoSpec->blockSize); - CryptoMemoryXOR(IV, Plaintext, Count % CryptoSpec->blockSize); - } else if (dataNeedsPadding && blockIndex + 1 == numBlocks) { - memcpy(Plaintext + blockIndex * CryptoSpec->blockSize, inputBlock, Count % CryptoSpec->blockSize); - CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CryptoSpec->blockSize], - Plaintext + blockIndex * CryptoSpec->blockSize, Count % CryptoSpec->blockSize); - } else { - memcpy(Plaintext + blockIndex * CryptoSpec->blockSize, inputBlock, CryptoSpec->blockSize); - CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CryptoSpec->blockSize], - Plaintext + blockIndex * CryptoSpec->blockSize, CryptoSpec->blockSize); + if (__CryptoDESOpMode == CRYPTO_DES_CBC_MODE) { + CryptoSpec->cryptFunc(inputBlock, Ciphertext + blockIndex * CryptoSpec->blockSize, Keys); + if (blockIndex == 0 && !dataNeedsPadding) { + memcpy(Plaintext, inputBlock, CryptoSpec->blockSize); + CryptoMemoryXOR(IV, Plaintext, CryptoSpec->blockSize); + } else if (blockIndex == 0 && dataNeedsPadding && numBlocks == 0x01) { + memcpy(Plaintext, inputBlock, Count % CryptoSpec->blockSize); + CryptoMemoryXOR(IV, Plaintext, Count % CryptoSpec->blockSize); + } else if (dataNeedsPadding && blockIndex + 1 == numBlocks) { + memcpy(Plaintext + blockIndex * CryptoSpec->blockSize, inputBlock, Count % CryptoSpec->blockSize); + CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CryptoSpec->blockSize], + Plaintext + blockIndex * CryptoSpec->blockSize, Count % CryptoSpec->blockSize); + } else { + memcpy(Plaintext + blockIndex * CryptoSpec->blockSize, inputBlock, CryptoSpec->blockSize); + CryptoMemoryXOR(&Ciphertext[(blockIndex - 1) * CryptoSpec->blockSize], + Plaintext + blockIndex * CryptoSpec->blockSize, CryptoSpec->blockSize); + } + } else { /* ECB mode */ + CryptoSpec->cryptFunc(&Plaintext[blockIndex * CryptoSpec->blockSize], + &Ciphertext[blockIndex * CryptoSpec->blockSize], Keys); + CryptoMemoryXOR(IV, &Plaintext[blockIndex * CryptoSpec->blockSize], CryptoSpec->blockSize); + memcpy(IV, &Ciphertext[blockIndex * CryptoSpec->blockSize], CryptoSpec->blockSize); } blockIndex++; } + if (IVIn != NULL) { + memcpy(IVIn, IV, CryptoSpec->blockSize); + } } void EncryptDESBuffer(uint16_t Count, const void *Plaintext, void *Ciphertext, const uint8_t *IVIn, const uint8_t *Keys) { diff --git a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h index 6397e900..8eed3e47 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoTDEA.h +++ b/Firmware/Chameleon-Mini/Application/CryptoTDEA.h @@ -27,6 +27,10 @@ PCD's side. */ +/* DES Operation cipher mode */ +#define CRYPTO_DES_ECB_MODE 0 // Electronic Code Book mode +#define CRYPTO_DES_CBC_MODE 1 // Cipher Block Chaining mode + /* Key sizes, in bytes */ #define CRYPTO_DES_KEY_SIZE 8 /* Bytes */ #define CRYPTO_2KTDEA_KEY_SIZE (CRYPTO_DES_KEY_SIZE * 2) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c index 8bd8db28..268e86c7 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c @@ -63,6 +63,8 @@ void InvalidateAuthState(BYTE keepPICCAuthData) { CryptoAuthMethod = CRYPTO_TYPE_ANY; ActiveCommMode = DESFIRE_DEFAULT_COMMS_STANDARD; DesfireCommMode = ActiveCommMode; + memset(&SessionKey[0], 0x00, CRYPTO_MAX_BLOCK_SIZE); + memset(&SessionIV[0], 0x00, CRYPTO_MAX_BLOCK_SIZE); } bool IsAuthenticated(void) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index 58345e88..78d6b189 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -419,7 +419,8 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { const char *logMsg = PSTR("ISO14443-3/4: EXPECTING RATS"); LogDebuggingMsg(logMsg); } else if (Cmd == ISO14443A_CMD_SELECT_CL3) { - return ISO14443A_APP_NO_RESPONSE; + Buffer[0] = 0x00; + return 1 * BITS_PER_BYTE; } /* Forward to ISO/IEC 14443-4 processing code */ uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 73b6e1bf..cd746565 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -1714,7 +1714,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId, Status; BYTE keySize; BYTE CryptoChallengeResponseBytesSize; - BYTE *Key; + BYTE *Key, *IV; /* Validate command length */ if (ByteCount != 2) { @@ -1744,6 +1744,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { /* Update state */ Key = SessionKey; + IV = SessionIV; DesfireCommandState.KeyId = KeyId; BYTE cryptoKeyType = ReadKeyCryptoType(SelectedApp.Slot, KeyId); if (cryptoKeyType == CRYPTO_TYPE_ANY || cryptoKeyType == CRYPTO_TYPE_3K3DES) { @@ -1798,12 +1799,13 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CryptoChallengeResponseBytesSize); /* Encrypt RndB with the selected key and transfer it back to the PCD */ - if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || cryptoKeyType == CRYPTO_TYPE_ANY) { + if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || + cryptoKeyType == CRYPTO_TYPE_ANY) { Encrypt3DESBuffer(CryptoChallengeResponseBytesSize, DesfireCommandState.RndB, - &Buffer[1], NULL, Key); + &Buffer[1], IV, Key); } else { Encrypt2K3DESBuffer(CryptoChallengeResponseBytesSize, DesfireCommandState.RndB, - &Buffer[1], NULL, Key); + &Buffer[1], IV, Key); } /* Scrub the key */ @@ -1820,10 +1822,9 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId; BYTE cryptoKeyType, keySize; BYTE CryptoChallengeResponseBytesSize; - BYTE *Key; + BYTE *Key, *IV; cryptoKeyType = DesfireCommandState.CryptoMethodType; - keySize = GetDefaultCryptoMethodKeySize(cryptoKeyType); if (cryptoKeyType == CRYPTO_TYPE_ANY || cryptoKeyType == CRYPTO_TYPE_3K3DES) { CryptoChallengeResponseBytesSize = CRYPTO_CHALLENGE_RESPONSE_BYTES; } else if (cryptoKeyType == CRYPTO_TYPE_DES) { @@ -1837,15 +1838,15 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Validate command length */ if (ByteCount != 2 * CryptoChallengeResponseBytesSize + 1) { Buffer[0] = STATUS_LENGTH_ERROR; - Buffer[1] = ByteCount; - Buffer[2] = CryptoChallengeResponseBytesSize; - return 3 * DESFIRE_STATUS_RESPONSE_SIZE; + return DESFIRE_STATUS_RESPONSE_SIZE; } /* Reset parameters for authentication from the first exchange */ + keySize = GetDefaultCryptoMethodKeySize(cryptoKeyType); KeyId = DesfireCommandState.KeyId; Key = SessionKey; ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + IV = SessionIV; if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES) { memcpy(&Key[CRYPTO_DES_BLOCK_SIZE], &Key[0], CRYPTO_DES_BLOCK_SIZE); memcpy(&Key[2 * CRYPTO_DES_BLOCK_SIZE], &Key[0], CRYPTO_DES_BLOCK_SIZE); @@ -1855,32 +1856,35 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { BYTE challengeRndAB[2 * CryptoChallengeResponseBytesSize]; BYTE challengeRndA[CryptoChallengeResponseBytesSize]; BYTE challengeRndB[CryptoChallengeResponseBytesSize]; - if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || cryptoKeyType == CRYPTO_TYPE_ANY) { + if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || + cryptoKeyType == CRYPTO_TYPE_ANY) { Decrypt3DESBuffer(2 * CryptoChallengeResponseBytesSize, challengeRndAB, - &Buffer[1], NULL, Key); + &Buffer[1], IV, Key); } else { Decrypt2K3DESBuffer(2 * CryptoChallengeResponseBytesSize, challengeRndAB, - &Buffer[1], NULL, Key); + &Buffer[1], IV, Key); } - RotateArrayRight(challengeRndAB + CryptoChallengeResponseBytesSize, challengeRndB, - CryptoChallengeResponseBytesSize); + RotateArrayLeft(challengeRndAB + CryptoChallengeResponseBytesSize, challengeRndB, + CryptoChallengeResponseBytesSize); memcpy(challengeRndA, challengeRndAB, CryptoChallengeResponseBytesSize); /* Check that the returned RndB matches what we sent in the previous round */ if (memcmp(DesfireCommandState.RndB, challengeRndB, CryptoChallengeResponseBytesSize)) { - LogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, (const void *) challengeRndB, CryptoChallengeResponseBytesSize); + LogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, (const void *) challengeRndB, + CryptoChallengeResponseBytesSize); Buffer[0] = STATUS_AUTHENTICATION_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } /* Encrypt and send back the once rotated RndA buffer to the PCD */ - RotateArrayLeft(challengeRndA, challengeRndAB, CryptoChallengeResponseBytesSize); - if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || cryptoKeyType == CRYPTO_TYPE_ANY) { + RotateArrayRight(challengeRndA, challengeRndAB, CryptoChallengeResponseBytesSize); + if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || + cryptoKeyType == CRYPTO_TYPE_ANY) { Encrypt3DESBuffer(CryptoChallengeResponseBytesSize, challengeRndAB, - &Buffer[1], NULL, Key); + &Buffer[1], IV, Key); } else { Encrypt2K3DESBuffer(CryptoChallengeResponseBytesSize, challengeRndAB, - &Buffer[1], NULL, Key); + &Buffer[1], IV, Key); } /* Create the session key based on the previous exchange */ @@ -1983,7 +1987,8 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Encrypt RndB with the selected key and transfer it back to the PCD */ - Status = CryptoAESEncryptBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, DesfireCommandState.RndB, &Buffer[1], NULL, Key); + Status = CryptoAESEncryptBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, DesfireCommandState.RndB, + &Buffer[1], IVBuffer, Key); if (Status != STATUS_OPERATION_OK) { Buffer[0] = Status; return DESFIRE_STATUS_RESPONSE_SIZE; @@ -2002,7 +2007,7 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount) { BYTE KeyId; BYTE cryptoKeyType, keySize; - BYTE *Key; + BYTE *Key, *IVBuffer; /* Set status for the next incoming command on error */ DesfireState = DESFIRE_IDLE; @@ -2018,13 +2023,14 @@ uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount) { KeyId = DesfireCommandState.KeyId; cryptoKeyType = DesfireCommandState.CryptoMethodType; ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); + IVBuffer = SessionIV; /* Decrypt the challenge sent back to get RndA and a shifted RndB */ BYTE challengeRndAB[2 * CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndA[CRYPTO_CHALLENGE_RESPONSE_BYTES]; BYTE challengeRndB[CRYPTO_CHALLENGE_RESPONSE_BYTES]; - CryptoAESDecryptBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, Key); - RotateArrayRight(challengeRndAB + CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + CryptoAESDecryptBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], IVBuffer, Key); + RotateArrayLeft(challengeRndAB + CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Check that the returned RndB matches what we sent in the previous round */ @@ -2036,10 +2042,8 @@ uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount) { } /* Encrypt and send back the once rotated RndA buffer to the PCD */ - memset(challengeRndAB, 0x00, CRYPTO_CHALLENGE_RESPONSE_BYTES); - memcpy(challengeRndAB, challengeRndA, CRYPTO_CHALLENGE_RESPONSE_BYTES); - RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); - CryptoAESEncryptBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, Key); + RotateArrayRight(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + CryptoAESEncryptBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndA, &Buffer[1], IVBuffer, Key); /* Create the session key based on the previous exchange */ generateSessionKey(SessionKey, challengeRndA, challengeRndB, CRYPTO_TYPE_AES128); diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 82f267d1..5ffd057b 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -179,7 +179,9 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { if (BitCount == 0) { LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); return ISO14443A_APP_NO_RESPONSE; - } else if (((ByteCount >= 8 && Buffer[4] == ByteCount - 8) || (ByteCount >= 5 && Buffer[4] == ByteCount - 5)) && + } else if (((ByteCount >= 8 && Buffer[4] == ByteCount - 8) || + (ByteCount >= 5 && Buffer[4] == ByteCount - 5) || + (ByteCount >= 5 && Buffer[1] == STATUS_ADDITIONAL_FRAME)) && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 || Iso7816CLA(DesfireCmdCLA)) { /* Wrapped native command structure or ISO7816: */ @@ -243,12 +245,12 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[0] = DesfireCmdCLA; Buffer[1] = STATUS_ADDITIONAL_FRAME; if (ByteCount > 3) { - memmove(&Buffer[3], &Buffer[5], ByteCount - 3); + memmove(&Buffer[5], &Buffer[3], ByteCount - 3); } Buffer[2] = 0x00; Buffer[3] = 0x00; - Buffer[4] = ByteCount - 3; - ByteCount += 1; + Buffer[4] = ByteCount - 5; + ByteCount += 2; } else if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_PM3RAW) { /* Something like the following (for PM3 raw ISO auth): * 0a 00 1a 00 CRC1 CRC2 -- first two are prologue -- last two are checksum From 19e0d1cda43c8da7e6274ecd3dcae47cbfee31ba Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Wed, 30 Mar 2022 12:46:06 -0400 Subject: [PATCH 44/68] Stashing LibNFC external USB reader test code online to test on Linux (builds on MacOS) --- .../Chameleon-Mini/Application/CryptoAES128.h | 2 +- .../Application/DESFire/DESFireInstructions.c | 7 +- .../LocalInclude/Config.h | 10 +- .../LocalInclude/CryptoUtils.h | 169 ++++++++++++++---- .../LocalInclude/DesfireUtils.h | 12 +- .../LocalInclude/ErrorHandling.h | 8 +- Software/DESFireLibNFCTesting/Makefile | 18 +- 7 files changed, 169 insertions(+), 57 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoAES128.h b/Firmware/Chameleon-Mini/Application/CryptoAES128.h index 20ccca8c..3d2bc27f 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoAES128.h +++ b/Firmware/Chameleon-Mini/Application/CryptoAES128.h @@ -65,7 +65,7 @@ #define CRYPTO_AES_KEY_SIZE 16 typedef uint8_t CryptoAESKey_t[CRYPTO_AES_KEY_SIZE]; -#define CRYPTO_AES_BLOCK_SIZE 16 +#define CRYPTO_AES_BLOCK_SIZE 16 typedef uint8_t CryptoAESBlock_t[CRYPTO_AES_BLOCK_SIZE]; #define CryptoAESBytesToBlocks(byteCount) \ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index cd746565..6745ace7 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -551,8 +551,8 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { BYTE challengeRndB[CRYPTO_CHALLENGE_RESPONSE_BYTES]; Decrypt2K3DESBuffer(2 * CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, Key); - RotateArrayRight(challengeRndAB + CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndB, - CRYPTO_CHALLENGE_RESPONSE_BYTES); + RotateArrayLeft(challengeRndAB + CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndB, + CRYPTO_CHALLENGE_RESPONSE_BYTES); memcpy(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Check that the returned RndB matches what we sent in the previous round */ @@ -562,7 +562,7 @@ uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount) { } /* Encrypt and send back the once rotated RndA buffer to the PCD */ - RotateArrayLeft(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + RotateArrayRight(challengeRndA, challengeRndAB, CRYPTO_CHALLENGE_RESPONSE_BYTES); Encrypt2K3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, challengeRndAB, &Buffer[1], NULL, Key); @@ -845,7 +845,6 @@ uint16_t EV0CmdDeleteApplication(uint8_t *Buffer, uint16_t ByteCount) { } PiccKeySettings = GetPiccKeySettings(); const char *logMsg = PSTR("PICC key settings -- %02x"); - DEBUG_PRINT_P(logMsg, PiccKeySettings); /* Check the PICC key settings whether it is OK to delete using app master key */ if ((PiccKeySettings & DESFIRE_FREE_CREATE_DELETE) == 0x00) { Status = STATUS_AUTHENTICATION_ERROR; diff --git a/Software/DESFireLibNFCTesting/LocalInclude/Config.h b/Software/DESFireLibNFCTesting/LocalInclude/Config.h index b25ad036..0a313221 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/Config.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/Config.h @@ -6,17 +6,17 @@ #define MAX_FRAME_LENGTH (264) #define APPLICATION_AID_LENGTH (3) -static const inline uint8_t MASTER_APPLICATION_AID[] = { +static const uint8_t MASTER_APPLICATION_AID[] = { 0x00, 0x00, 0x00 }; -static const inline uint8_t MASTER_KEY_INDEX = 0x00; +static const uint8_t MASTER_KEY_INDEX = 0x00; -static inline uint8_t CRYPTO_RNDB_STATE[] = { +static uint8_t CRYPTO_RNDB_STATE[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static inline bool AUTHENTICATED = false; -static inline int AUTHENTICATED_PROTO = 0; +static bool AUTHENTICATED = false; +static int AUTHENTICATED_PROTO = 0; #endif diff --git a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h index c2e3b4a5..a09e8315 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h @@ -13,6 +13,14 @@ #include "LibNFCUtils.h" +/* DES Operation cipher mode */ +#define CRYPTO_DES_ECB_MODE 0 // Electronic Code Book mode +#define CRYPTO_DES_CBC_MODE 1 // Cipher Block Chaining mode + +/* AES Operation cipher mode */ +#define CRYPTO_AES_ECB_MODE 0 // Electronic Code Book mode +#define CRYPTO_AES_CBC_MODE 1 // Cipher Block Chaining mode + #define DESFIRE_CRYPTO_AUTHTYPE_AES128 (1) #define DESFIRE_CRYPTO_AUTHTYPE_ISODES (2) #define DESFIRE_CRYPTO_AUTHTYPE_LEGACY (3) @@ -23,24 +31,32 @@ #define CRYPTO_DES_BLOCK_SIZE (8) #define CRYPTO_3KTDEA_BLOCK_SIZE (CRYPTO_DES_BLOCK_SIZE) #define AES128_BLOCK_SIZE (16) +#define CRYPTO_MAX_BLOCK_SIZE (16) + +typedef uint8_t CryptoAESBlock_t[AES128_BLOCK_SIZE]; +static uint8_t SessionIV[CRYPTO_MAX_BLOCK_SIZE]; + +/* Key sizes, block sizes (in bytes): */ +#define CRYPTO_MAX_KEY_SIZE (24) +#define CRYPTO_MAX_BLOCK_SIZE (16) #define CRYPTO_CHALLENGE_RESPONSE_SIZE (16) -static const inline uint8_t ZERO_KEY[] = { +static const uint8_t ZERO_KEY[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const inline uint8_t TEST_KEY1[] = { +static const uint8_t TEST_KEY1[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }; -static const inline uint8_t TEST_KEY1_INDEX = 0x01; +static const uint8_t TEST_KEY1_INDEX = 0x01; typedef AES128Context DesfireAESCryptoContext; @@ -82,25 +98,34 @@ static inline void PrintAESCryptoContext(DesfireAESCryptoContext *cryptoCtx) { print_hex(cryptoCtx->keyData, 16); } +/* Set the last operation mode (ECB or CBC) init for the context */ +static uint8_t __CryptoAESOpMode = CRYPTO_AES_ECB_MODE; + static inline size_t EncryptAES128(const uint8_t *plainSrcBuf, size_t bufSize, uint8_t *encDestBuf, CryptoData_t cdata) { DesfireAESCryptoContext *cryptoCtx = &(cdata.cryptoCtx); DesfireAESCryptoInit(cdata.keyData, cdata.keySize, cryptoCtx); size_t bufBlocks = bufSize / AES128_BLOCK_SIZE; bool padLastBlock = (bufSize % AES128_BLOCK_SIZE) != 0; - uint8_t IV[AES128_BLOCK_SIZE]; + uint8_t *IV = SessionIV; + uint8_t inputBlock[AES128_BLOCK_SIZE]; memset(IV, 0x00, AES128_BLOCK_SIZE); for (int blk = 0; blk < bufBlocks; blk++) { - uint8_t inputBlock[AES128_BLOCK_SIZE]; - if (blk == 0) { - memcpy(inputBlock, &plainSrcBuf[0], AES128_BLOCK_SIZE); + if (__CryptoAESOpMode == CRYPTO_AES_CBC_MODE) { + if (blk == 0) { + memcpy(inputBlock, &plainSrcBuf[0], AES128_BLOCK_SIZE); + CryptoMemoryXOR(IV, inputBlock, AES128_BLOCK_SIZE); + } else { + memcpy(inputBlock, &encDestBuf[(blk - 1) * AES128_BLOCK_SIZE], AES128_BLOCK_SIZE); + CryptoMemoryXOR(&plainSrcBuf[blk * AES128_BLOCK_SIZE], inputBlock, AES128_BLOCK_SIZE); + } + aes128EncryptBlock(cryptoCtx, encDestBuf + blk * AES128_BLOCK_SIZE, inputBlock); + } else { /* ECB mode */ + memcpy(inputBlock, &plainSrcBuf[blk * AES128_BLOCK_SIZE], AES128_BLOCK_SIZE); CryptoMemoryXOR(IV, inputBlock, AES128_BLOCK_SIZE); - } else { - memcpy(inputBlock, &encDestBuf[(blk - 1) * AES128_BLOCK_SIZE], AES128_BLOCK_SIZE); - CryptoMemoryXOR(&plainSrcBuf[blk * AES128_BLOCK_SIZE], inputBlock, AES128_BLOCK_SIZE); + aes128EncryptBlock(cryptoCtx, encDestBuf + blk * AES128_BLOCK_SIZE, inputBlock); + memcpy(IV, encDestBuf + blk * AES128_BLOCK_SIZE, AES128_BLOCK_SIZE); } - aes128EncryptBlock(cryptoCtx, encDestBuf + blk * AES128_BLOCK_SIZE, - inputBlock); } return bufSize; } @@ -111,27 +136,36 @@ static inline size_t DecryptAES128(const uint8_t *encSrcBuf, size_t bufSize, DesfireAESCryptoInit(cdata.keyData, cdata.keySize, cryptoCtx); size_t bufBlocks = (bufSize + AES128_BLOCK_SIZE - 1) / AES128_BLOCK_SIZE; bool padLastBlock = (bufSize % AES128_BLOCK_SIZE) != 0; - uint8_t IV[AES128_BLOCK_SIZE]; + uint8_t *IV = SessionIV; + uint8_t inputBlock[AES128_BLOCK_SIZE]; memset(IV, 0x00, AES128_BLOCK_SIZE); for (int blk = 0; blk < bufBlocks; blk++) { - uint8_t inputBlock[AES128_BLOCK_SIZE]; - aes128DecryptBlock(cryptoCtx, inputBlock, encSrcBuf + blk * AES128_BLOCK_SIZE); - if (blk == 0) { - memcpy(plainDestBuf + blk * AES128_BLOCK_SIZE, inputBlock, AES128_BLOCK_SIZE); + if (__CryptoAESOpMode == CRYPTO_AES_CBC_MODE) { + aes128DecryptBlock(cryptoCtx, inputBlock, encSrcBuf + blk * AES128_BLOCK_SIZE); + if (blk == 0) { + memcpy(plainDestBuf + blk * AES128_BLOCK_SIZE, inputBlock, AES128_BLOCK_SIZE); + CryptoMemoryXOR(IV, plainDestBuf + blk * AES128_BLOCK_SIZE, AES128_BLOCK_SIZE); + } else { + memcpy(plainDestBuf + blk * AES128_BLOCK_SIZE, inputBlock, AES128_BLOCK_SIZE); + CryptoMemoryXOR(&encSrcBuf[(blk - 1) * AES128_BLOCK_SIZE], + plainDestBuf + blk * AES128_BLOCK_SIZE, AES128_BLOCK_SIZE); + } + } else { /* ECB mode */ + aes128DecryptBlock(cryptoCtx, plainDestBuf + blk * AES128_BLOCK_SIZE, encSrcBuf + blk * AES128_BLOCK_SIZE); CryptoMemoryXOR(IV, plainDestBuf + blk * AES128_BLOCK_SIZE, AES128_BLOCK_SIZE); - } else { - memcpy(plainDestBuf + blk * AES128_BLOCK_SIZE, inputBlock, AES128_BLOCK_SIZE); - CryptoMemoryXOR(&encSrcBuf[(blk - 1) * AES128_BLOCK_SIZE], - plainDestBuf + blk * AES128_BLOCK_SIZE, AES128_BLOCK_SIZE); + memcpy(IV, encSrcBuf + blk * AES128_BLOCK_SIZE, AES128_BLOCK_SIZE); } } return bufSize; } +/* Set the last operation mode (ECB or CBC) init for the context */ +static uint8_t __CryptoDESOpMode = CRYPTO_DES_ECB_MODE; + static inline size_t Encrypt2K3DES(const uint8_t *plainSrcBuf, size_t bufSize, uint8_t *encDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { DES_key_schedule keySched1, keySched2; - uint8_t IV[2 * CRYPTO_DES_BLOCK_SIZE]; + uint8_t *IV = SessionIV; uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[CRYPTO_DES_BLOCK_SIZE]); DES_set_key(kd1, &keySched1); DES_set_key(kd2, &keySched2); @@ -140,14 +174,26 @@ static inline size_t Encrypt2K3DES(const uint8_t *plainSrcBuf, size_t bufSize, } else { memcpy(IV, IVIn, 2 * CRYPTO_DES_BLOCK_SIZE); } - DES_ede2_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched1, &keySched2, &IV, DES_ENCRYPT); + if (__CryptoDESOpMode == CRYPTO_DES_CBC_MODE) { + DES_ede2_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched1, &keySched2, &IV, DES_ENCRYPT); + } else { + uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE]; + uint16_t numBlocks = bufSize / CRYPTO_DES_BLOCK_SIZE; + for (int blk = 0; blk < numBlocks; blk++) { + memcpy(inputBlock, &plainSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + CryptoMemoryXOR(IV, inputBlock, CRYPTO_DES_BLOCK_SIZE); + DES_ecb2_encrypt(&encDestBuf[blk * CRYPTO_DES_BLOCK_SIZE], + &plainSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], &keySched1, &keySched2, DES_ENCRYPT); + memcpy(IV, &encDestBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + } + } return bufSize; } static inline size_t Decrypt2K3DES(const uint8_t *encSrcBuf, size_t bufSize, uint8_t *plainDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { DES_key_schedule keySched1, keySched2; - uint8_t IV[2 * CRYPTO_DES_BLOCK_SIZE]; + uint8_t *IV = SessionIV; uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[CRYPTO_DES_BLOCK_SIZE]); DES_set_key(kd1, &keySched1); DES_set_key(kd2, &keySched2); @@ -156,14 +202,25 @@ static inline size_t Decrypt2K3DES(const uint8_t *encSrcBuf, size_t bufSize, } else { memcpy(IV, IVIn, 2 * CRYPTO_DES_BLOCK_SIZE); } - DES_ede2_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched1, &keySched2, &IV, DES_DECRYPT); + if (__CryptoDESOpMode == CRYPTO_DES_CBC_MODE) { + DES_ede2_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched1, &keySched2, &IV, DES_DECRYPT); + } else { + uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE]; + uint16_t numBlocks = bufSize / CRYPTO_DES_BLOCK_SIZE; + for (int blk = 0; blk < numBlocks; blk++) { + DES_ecb2_encrypt(&encSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], + &plainDestBuf[blk * CRYPTO_DES_BLOCK_SIZE], &keySched1, &keySched2, DES_DECRYPT); + CryptoMemoryXOR(IV, &plainDestBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + memcpy(IV, &encSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + } + } return bufSize; } static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize, uint8_t *encDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { DES_key_schedule keySched1, keySched2, keySched3; - uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + uint8_t *IV = SessionIV; uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[CRYPTO_DES_BLOCK_SIZE]), *kd3 = &(cdata.keyData[2 * CRYPTO_DES_BLOCK_SIZE]); DES_set_key(kd1, &keySched1); DES_set_key(kd2, &keySched2); @@ -173,14 +230,26 @@ static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize, } else { memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); } - DES_ede3_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_ENCRYPT); + if (__CryptoDESOpMode == CRYPTO_DES_CBC_MODE) { + DES_ede3_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_ENCRYPT); + } else { + uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE]; + uint16_t numBlocks = bufSize / CRYPTO_DES_BLOCK_SIZE; + for (int blk = 0; blk < numBlocks; blk++) { + memcpy(inputBlock, &plainSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + CryptoMemoryXOR(IV, inputBlock, CRYPTO_DES_BLOCK_SIZE); + DES_ecb3_encrypt(&encDestBuf[blk * CRYPTO_DES_BLOCK_SIZE], + &plainSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], &keySched1, &keySched2, &keySched3, DES_ENCRYPT); + memcpy(IV, &encDestBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + } + } return bufSize; } static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize, uint8_t *plainDestBuf, const uint8_t *IVIn, CryptoData_t cdata) { DES_key_schedule keySched1, keySched2, keySched3; - uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + uint8_t *IV = SessionIV; uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[CRYPTO_DES_BLOCK_SIZE]), *kd3 = &(cdata.keyData[2 * CRYPTO_DES_BLOCK_SIZE]); DES_set_key(kd1, &keySched1); DES_set_key(kd2, &keySched2); @@ -190,7 +259,18 @@ static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize, } else { memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); } - DES_ede3_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_DECRYPT); + if (__CryptoDESOpMode == CRYPTO_DES_CBC_MODE) { + DES_ede3_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_DECRYPT); + } else { + uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE]; + uint16_t numBlocks = bufSize / CRYPTO_DES_BLOCK_SIZE; + for (int blk = 0; blk < numBlocks; blk++) { + DES_ecb3_encrypt(&encSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], + &plainDestBuf[blk * CRYPTO_DES_BLOCK_SIZE], &keySched1, &keySched2, &keySched3, DES_DECRYPT); + CryptoMemoryXOR(IV, &plainDestBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + memcpy(IV, &encSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + } + } return bufSize; } @@ -200,13 +280,25 @@ static inline size_t EncryptDES(const uint8_t *plainSrcBuf, size_t bufSize, DES_key_schedule keySched; uint8_t *kd = cdata.keyData; DES_set_key(kd, &keySched); - uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + uint8_t *IV = SessionIV; if (IVIn == NULL) { memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); } else { memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); } - DES_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched, &IV, DES_ENCRYPT); + if (__CryptoDESOpMode == CRYPTO_DES_CBC_MODE) { + DES_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched, &IV, DES_ENCRYPT); + } else { + uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE]; + uint16_t numBlocks = bufSize / CRYPTO_DES_BLOCK_SIZE; + for (int blk = 0; blk < numBlocks; blk++) { + memcpy(inputBlock, &plainSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + CryptoMemoryXOR(IV, inputBlock, CRYPTO_DES_BLOCK_SIZE); + DES_ecb_encrypt(&encDestBuf[blk * CRYPTO_DES_BLOCK_SIZE], + &plainSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], &keySched, DES_ENCRYPT); + memcpy(IV, &encDestBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + } + } return bufSize; } @@ -215,13 +307,24 @@ static inline size_t DecryptDES(const uint8_t *encSrcBuf, size_t bufSize, DES_key_schedule keySched; uint8_t *kd = cdata.keyData; DES_set_key(kd, &keySched); - uint8_t IV[CRYPTO_DES_BLOCK_SIZE]; + uint8_t *IV = SessionIV; if (IVIn == NULL) { memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE); } else { memcpy(IV, IVIn, CRYPTO_DES_BLOCK_SIZE); } - DES_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched, &IV, DES_DECRYPT); + if (__CryptoDESOpMode == CRYPTO_DES_CBC_MODE) { + DES_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched, &IV, DES_DECRYPT); + } else { + uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE]; + uint16_t numBlocks = bufSize / CRYPTO_DES_BLOCK_SIZE; + for (int blk = 0; blk < numBlocks; blk++) { + DES_ecb_encrypt(&encSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], + &plainDestBuf[blk * CRYPTO_DES_BLOCK_SIZE], &keySched, DES_DECRYPT); + CryptoMemoryXOR(IV, &plainDestBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + memcpy(IV, &encSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE); + } + } return bufSize; } diff --git a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h index 33b55f37..6a96cc70 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h @@ -58,7 +58,7 @@ static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, c aesCryptoData.keyData = keyData; aesCryptoData.ivSize = CRYPTO_CHALLENGE_RESPONSE_SIZE; DecryptAES128(encryptedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, plainTextRndB, aesCryptoData); - RotateArrayLeft(plainTextRndB, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); + RotateArrayRight(plainTextRndB, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); memset(IVBuf, 0x00, CRYPTO_CHALLENGE_RESPONSE_SIZE); aesCryptoData.ivData = IVBuf; GenerateRandomBytes(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); @@ -99,7 +99,7 @@ static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, c // and report back whether they match: uint8_t decryptedRndAFromPICCRotated[CRYPTO_CHALLENGE_RESPONSE_SIZE], decryptedRndA[CRYPTO_CHALLENGE_RESPONSE_SIZE]; DecryptAES128(rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE, decryptedRndAFromPICCRotated, aesCryptoData); - RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + RotateArrayLeft(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); if (!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " ... AUTH OK! :)\n\n"); @@ -162,7 +162,7 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons desCryptoData.keyData = keyData; desCryptoData.ivSize = CRYPTO_CHALLENGE_RESPONSE_SIZE; Decrypt3DES(encryptedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, plainTextRndB, NULL, desCryptoData); - RotateArrayLeft(plainTextRndB, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); + RotateArrayRight(plainTextRndB, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); memset(IVBuf, 0x00, CRYPTO_CHALLENGE_RESPONSE_SIZE); desCryptoData.ivData = IVBuf; GenerateRandomBytes(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); @@ -203,7 +203,7 @@ static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, cons // and report back whether they match: uint8_t decryptedRndAFromPICCRotated[CRYPTO_CHALLENGE_RESPONSE_SIZE], decryptedRndA[CRYPTO_CHALLENGE_RESPONSE_SIZE]; Decrypt3DES(rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE, decryptedRndAFromPICCRotated, NULL, desCryptoData); - RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + RotateArrayLeft(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); if (!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " ... AUTH OK! :)\n\n"); @@ -266,7 +266,7 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c desCryptoData.keyData = keyData; desCryptoData.ivSize = CRYPTO_CHALLENGE_RESPONSE_SIZE; Decrypt2K3DES(encryptedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, plainTextRndB, NULL, desCryptoData); - RotateArrayLeft(plainTextRndB, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); + RotateArrayRight(plainTextRndB, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE); memset(IVBuf, 0x00, CRYPTO_CHALLENGE_RESPONSE_SIZE); desCryptoData.ivData = IVBuf; GenerateRandomBytes(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); @@ -307,7 +307,7 @@ static inline int AuthenticateLegacy(nfc_device *nfcConnDev, uint8_t keyIndex, c // and report back whether they match: uint8_t decryptedRndAFromPICCRotated[CRYPTO_CHALLENGE_RESPONSE_SIZE], decryptedRndA[CRYPTO_CHALLENGE_RESPONSE_SIZE]; Decrypt2K3DES(rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE, decryptedRndAFromPICCRotated, NULL, desCryptoData); - RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); + RotateArrayLeft(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE); if (!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) { if (PRINT_STATUS_EXCHANGE_MESSAGES) { fprintf(stdout, " ... AUTH OK! :)\n\n"); diff --git a/Software/DESFireLibNFCTesting/LocalInclude/ErrorHandling.h b/Software/DESFireLibNFCTesting/LocalInclude/ErrorHandling.h index 6723f727..4d068eb6 100644 --- a/Software/DESFireLibNFCTesting/LocalInclude/ErrorHandling.h +++ b/Software/DESFireLibNFCTesting/LocalInclude/ErrorHandling.h @@ -8,7 +8,7 @@ #include #define STRING_BUFFER_SIZE (256) -static inline char __InternalLoggingStringBuffer[STRING_BUFFER_SIZE] = { '\0' }; +static char __InternalLoggingStringBuffer[STRING_BUFFER_SIZE] = { '\0' }; #define GetSourceFileLoggingData(outputDataBuf, maxBufSize) ({ \ char *strBuffer; \ @@ -48,7 +48,7 @@ typedef enum { LAST_ERROR, } ErrorType_t; -static inline const char *LOCAL_ERROR_MSGS[] = { +static const char *LOCAL_ERROR_MSGS[] = { [NO_ERROR] = "No error", [LIBC_ERROR] = "Libc function error", [GENERIC_OTHER_ERROR] = "Unspecified (generic) error", @@ -58,8 +58,8 @@ static inline const char *LOCAL_ERROR_MSGS[] = { [LAST_ERROR] = NULL, }; -static inline bool RUNTIME_QUIET_MODE = false; -static inline bool RUNTIME_VERBOSE_MODE = true; +static bool RUNTIME_QUIET_MODE = false; +static bool RUNTIME_VERBOSE_MODE = true; static bool PRINT_STATUS_EXCHANGE_MESSAGES = true; #define STATUS_OK (0x00) diff --git a/Software/DESFireLibNFCTesting/Makefile b/Software/DESFireLibNFCTesting/Makefile index 99648973..3d0a6128 100644 --- a/Software/DESFireLibNFCTesting/Makefile +++ b/Software/DESFireLibNFCTesting/Makefile @@ -1,18 +1,28 @@ #### Makefile for the libnfc-based tests in C #### These tests are compiled for the local host system, not for AVR platforms -#CC=gcc-10 # for MacOS +#CC=gcc-10 # for MacOS CC=gcc -CFLAGS= -ILocalInclude -ISource \ +CFLAGS_BASE= -ILocalInclude -ISource \ -g -O0 -Wall -pedantic -Wextra -std=c99 -Du_int8_t=uint8_t -Du_int16_t=uint16_t \ `pkg-config libnfc --cflags` -I/usr/local/opt/openssl/include \ -DHOST_BUILD -DCRYPTO_AES_DEFAULT=1 \ -ILibs/ArduinoCryptoLib -#LD=gcc-10 +#LD=gcc-10 # for MacOS LD=gcc -LDFLAGS= $(CFLAGS) -lc `pkg-config libnfc --libs` \ +LDFLAGS_BASE= $(CFLAGS) -lc `pkg-config libnfc --libs` \ -L/usr/local/opt/openssl/lib -lssl -lcrypto +ifeq ("$(shell uname -s)", "Darwin") + CC=/usr/local/opt/llvm/bin/clang-13 + CFLAGS=$(CFLAGS_BASE) -I/usr/local/opt/llvm/include + LD=/usr/local/opt/llvm/bin/clang-13 + LDFLAGS=$(LDFLAGS_BASE) -L/usr/local/opt/llvm/lib +else + CFLAGS=$(CFLAGS_BASE) + LDFLAGS=$(LDFLAGS_BASE) +endif + BINDIR=./Bin BINEXT=exe OBJDIR=./Obj From 453678907cab17ade7037480bc5e1f93f9ff0bef Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Fri, 22 Apr 2022 13:43:40 -0400 Subject: [PATCH 45/68] Incorporating bug fixes by @colinoflynn at https://github.com/colinoflynn/ChameleonMini/commits/desfire-fixes (see message in #313) --- Firmware/Chameleon-Mini/Application/CryptoAES128.c | 4 ++-- .../Application/DESFire/DESFireISO14443Support.c | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/CryptoAES128.c b/Firmware/Chameleon-Mini/Application/CryptoAES128.c index 74b2ac2c..ae6c3990 100644 --- a/Firmware/Chameleon-Mini/Application/CryptoAES128.c +++ b/Firmware/Chameleon-Mini/Application/CryptoAES128.c @@ -196,7 +196,7 @@ static void CryptoAESEncryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const NOP(); AES.CTRL = 0; aes_configure_encrypt(AES_MANUAL, XorModeOn ? AES_XOR_ON : AES_XOR_OFF); - aes_isr_configure(AES_INTLVL_LO); + aes_isr_configure(AES_INTLVL_OFF); aes_set_key(Key); for (uint8_t i = 0; i < CRYPTO_AES_BLOCK_SIZE; i++) { AES.STATE = 0x00; @@ -221,7 +221,7 @@ static void CryptoAESDecryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const NOP(); AES.CTRL = 0; aes_configure_decrypt(AES_MANUAL, AES_XOR_OFF); - aes_isr_configure(AES_INTLVL_LO); + aes_isr_configure(AES_INTLVL_OFF); aes_set_key(lastSubKey); for (uint8_t i = 0; i < CRYPTO_AES_BLOCK_SIZE; i++) { AES.STATE = 0x00; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index 78d6b189..4a3d717f 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -151,6 +151,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 return ISO14443A_APP_NO_RESPONSE; } } + break; } case ISO14443_4_STATE_LAST: { return ISO14443A_APP_NO_RESPONSE; @@ -184,7 +185,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 } Buffer[0] = PCB; /* Let the DESFire application code process the input data */ - ByteCount = MifareDesfireProcess(Buffer + PrologueLength, ByteCount - PrologueLength); + ByteCount = MifareDesfireProcessCommand(Buffer + PrologueLength, ByteCount - PrologueLength); /* Short-circuit in case the app decides not to respond at all */ if (ByteCount == ISO14443A_APP_NO_RESPONSE) { const char *debugPrintStr = PSTR("ISO14443-4: APP_NO_RESP"); @@ -194,7 +195,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 ByteCount += PrologueLength; const char *debugPrintStr = PSTR("ISO14443-4: I-BLK"); LogDebuggingMsg(debugPrintStr); - break; + return GetAndSetBufferCRCA(Buffer, ByteCount); } case ISO14443_PCB_R_BLOCK: { @@ -227,7 +228,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 } const char *debugPrintStr6 = PSTR("ISO14443-4: R-BLK"); LogDebuggingMsg(debugPrintStr6); - break; + return GetAndSetBufferCRCA(Buffer, ByteCount); } case ISO14443_PCB_S_BLOCK: { From 83ce182cb8f748ff9dd774b11e7356fd3c98ad6d Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Wed, 11 May 2022 00:43:28 -0400 Subject: [PATCH 46/68] Fix Makefile bugs noticed in #313 --- Firmware/Chameleon-Mini/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index c43982f4..9b377866 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -270,6 +270,7 @@ dfu-prog: $(TARGET).hex $(TARGET).eep check_size dfu-programmer $(MCU) reset check_size: SHELL:=$(shell which bash) +check_size: @{ \ set -e; \ if [ ! -f $(TARGET).elf ]; then \ From 8e25538d83bf5119a1b8f62e7c65e55506b06fc9 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Fri, 13 May 2022 08:27:42 -0400 Subject: [PATCH 47/68] Attempt to fix bug with `pm3 --> hf mfdes info` reported in #313 --- Firmware/Chameleon-Mini/Application/MifareDESFire.c | 11 +++++++++++ Firmware/Chameleon-Mini/Makefile | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 5ffd057b..d53181ee 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -232,6 +232,17 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedByteCount * BITS_PER_BYTE); + } else if (ByteCount >= 8 && DesfireCLA(Buffer[1]) && Buffer[3] == 0x00 && + Buffer[4] == 0x00 && Buffer[5] == ByteCount - 8) { + DesfireCmdCLA = Buffer[1]; + uint16_t IncomingByteCount = MAX(0, (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE - 1); + memmove(&Buffer[0], &Buffer[1], IncomingByteCount); + uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; + uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); + uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); + LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedByteCount * BITS_PER_BYTE); } Iso7816CmdType = IsWrappedISO7816CommandType(Buffer, ByteCount); if (Iso7816CmdType != ISO7816_WRAPPED_CMD_TYPE_NONE) { diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 9b377866..46dd9b52 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -269,7 +269,7 @@ dfu-prog: $(TARGET).hex $(TARGET).eep check_size dfu-programmer $(MCU) flash $(TARGET).hex dfu-programmer $(MCU) reset -check_size: SHELL:=$(shell which bash) +#check_size: SHELL:=$(shell which bash) check_size: @{ \ set -e; \ From 8a823c80c60fb3e217b0e019f3c77b9416d35bf9 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Wed, 1 Jun 2022 00:39:24 -0400 Subject: [PATCH 48/68] A few improvements to Makefile and build scripts (cf. previous issue #283) --- .../BuildScripts/custom_build_targets.mk | 106 ++++++ Firmware/Chameleon-Mini/Makefile | 344 ++++++++++-------- 2 files changed, 303 insertions(+), 147 deletions(-) create mode 100644 Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk new file mode 100644 index 00000000..19cd66de --- /dev/null +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -0,0 +1,106 @@ +## : Include several standardized custom build target variants: +custom-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bin check_size + @cp $(TARGET).hex $(TARGET)-$(TARGET_CUSTOM_BUILD).hex + @cp $(TARGET).eep $(TARGET)-$(TARGET_CUSTOM_BUILD).eep + @cp $(TARGET).bin $(TARGET)-$(TARGET_CUSTOM_BUILD).bin + @echo "" + @avr-size -A -x $(TARGET).elf + @avr-size -B -x $(TARGET).elf + @echo "" + @avr-size -C -x $(TARGET).elf + @echo "" + @echo " ==== SUCCESS BUILDING CUSTOM FIRMWARE -- $(TARGET)-$(TARGET_CUSTOM_BUILD) ====" + @echo "" + +default_config_support: DEFAULT_TAG_SUPPORT:= \ + -DCONFIG_ISO14443A_SNIFF_SUPPORT \ + -DCONFIG_ISO14443A_READER_SUPPORT +nodefault_config_support: DEFAULT_TAG_SUPPORT:= + +## : Define a few other useful custom build targets: +mifare: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ + -DCONFIG_MF_CLASSIC_MINI_4B_SUPPORT \ + -DCONFIG_MF_CLASSIC_1K_SUPPORT \ + -DCONFIG_MF_CLASSIC_1K_7B_SUPPORT \ + -DCONFIG_MF_CLASSIC_4K_SUPPORT \ + -DCONFIG_MF_CLASSIC_4K_7B_SUPPORT \ + -DCONFIG_MF_ULTRALIGHT_SUPPORTmifare: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE +mifare: TARGET_CUSTOM_BUILD:=CustomBuild_MifareDefaultSupport +mifare: custom-build + +mifare-classic: nodefault_config_support +mifare-classic: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ + -DCONFIG_MF_CLASSIC_MINI_4B_SUPPORT \ + -DCONFIG_MF_CLASSIC_1K_SUPPORT \ + -DCONFIG_MF_CLASSIC_1K_7B_SUPPORT \ + -DCONFIG_MF_CLASSIC_4K_SUPPORT \ + -DCONFIG_MF_CLASSIC_4K_7B_SUPPORT +mifare-classic: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE +mifare-classic: TARGET_CUSTOM_BUILD:=CustomBuild_MifareClassicSupport +mifare-classic: custom-build + +iso-modes: nodefault_config_support +iso-modes: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ + -DCONFIG_ISO14443A_SNIFF_SUPPORT \ + -DCONFIG_ISO14443A_READER_SUPPORT \ + -DCONFIG_ISO15693_SNIFF_SUPPORT +iso-modes: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE +iso-modes: TARGET_CUSTOM_BUILD:=CustomBuild_ISOSniffReaderModeSupport +iso-modes: custom-build + +ntag215: default_config_support +ntag215: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ + -DCONFIG_NTAG215_SUPPORT +ntag215: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE +ntag215: TARGET_CUSTOM_BUILD:=CustomBuild_NTAG215Support +ntag215: custom-build + +vicinity: default_config_support +vicinity: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ + -DCONFIG_VICINITY_SUPPORT +vicinity: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE +vicinity: TARGET_CUSTOM_BUILD:=CustomBuild_VicinitySupport +vicinity: custom-build + +sl2s2002: default_config_support +sl2s2002: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ + -DCONFIG_SL2S2002_SUPPORT +sl2s2002: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE +sl2s2002: TARGET_CUSTOM_BUILD:=CustomBuild_SL2S2002Support +sl2s2002: custom-build + +tagatit: default_config_support +tagatit: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ + -DCONFIG_TITAGITSTANDARD_SUPPORT \ + -DCONFIG_TITAGITPLUS_SUPPORT +tagatit: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE +tagatit: TARGET_CUSTOM_BUILD:=CustomBuild_TagatitSupport +tagatit: custom-build + +em4233: default_config_support +em4233: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ + -DCONFIG_EM4233_SUPPORT +em4233: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE +em4233: TARGET_CUSTOM_BUILD:=CustomBuild_EM4233Support +em4233: custom-build + +## : Define custom targets for the DESFire build (normal/user mode) and +## : developer mode for use with the Android CMLD application that enables +## : the printing of LIVE logs to the phone's console by default: +desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bin check_size + @cp $(TARGET).hex $(TARGET)-DESFire.hex + @cp $(TARGET).eep $(TARGET)-DESFire.eep + @cp $(TARGET).bin $(TARGET)-DESFire.bin + @echo "" + @avr-size -A -x $(TARGET).elf + @avr-size -B -x $(TARGET).elf + @echo "" + @avr-size -C -x $(TARGET).elf +desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -fno-inline-small-functions +desfire: desfire-build +desfire-dev: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -fno-inline-small-functions \ + -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ + -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ + -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING \ + -DDESFIRE_DEFAULT_TESTING_MODE=1 +desfire-dev: desfire-build diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 46dd9b52..5980293e 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -1,10 +1,14 @@ -# This makefile uses sh in order to build the project. -# Note when using AVR-Toolchain, you have to install cygwin and -# append cygwin's bin directory to the PATH environment variable -# because Atmel does not ship sh.exe anymore with the toolchain. +## : This makefile uses sh in order to build the project. +## : Note when using AVR-Toolchain, you have to install cygwin and +## : append cygwin's bin directory to the PATH environment variable +## : because Atmel does not ship sh.exe anymore with the toolchain. SHELL = /bin/sh -#Supported configurations +## : Supported configurations: +## : CAUTION: Enabling too many configurations in the firmware +## : can/will/has been known to eat up too much memory +## : on the Chameleon integrated AVR and lead to stability +## : problems ... CONFIG_SETTINGS += -DCONFIG_MF_CLASSIC_MINI_4B_SUPPORT CONFIG_SETTINGS += -DCONFIG_MF_CLASSIC_1K_SUPPORT #CONFIG_SETTINGS += -DCONFIG_MF_CLASSIC_1K_7B_SUPPORT @@ -22,7 +26,7 @@ CONFIG_SETTINGS += -DCONFIG_ISO14443A_READER_SUPPORT #CONFIG_SETTINGS += -DCONFIG_EM4233_SUPPORT #CONFIG_SETTINGS += -DCONFIG_MF_DESFIRE_SUPPORT -#Default configuration +## : Default configuration #CONFIG_SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_MF_CLASSIC_MINI_4B #CONFIG_SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_MF_CLASSIC_1K #CONFIG_SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_MF_CLASSIC_4K @@ -30,16 +34,16 @@ CONFIG_SETTINGS += -DCONFIG_ISO14443A_READER_SUPPORT #CONFIG_SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_ISO14443A_READER CONFIG_SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_NONE -#Support magic mode on mifare classic configuration +## : Support magic mode on mifare classic configuration SETTINGS += -DSUPPORT_MF_CLASSIC_MAGIC_MODE -#Don't touch manufacturer byte with BUTTON_ACTION_UID_LEFT_(DE/IN)CREMENT +## : Don't touch manufacturer byte with BUTTON_ACTION_UID_LEFT_(DE/IN)CREMENT SETTINGS += -DSUPPORT_UID7_FIX_MANUFACTURER_BYTE -#Support activating firmware upgrade mode through command-line +## : Support activating firmware upgrade mode through command-line SETTINGS += -DSUPPORT_FIRMWARE_UPGRADE -#Default button actions +## : Default button actions #SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_UID_RANDOM #SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_UID_LEFT_INCREMENT #SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_UID_RIGHT_INCREMENT @@ -49,72 +53,72 @@ SETTINGS += -DSUPPORT_FIRMWARE_UPGRADE SETTINGS += -DDEFAULT_RBUTTON_ACTION=BUTTON_ACTION_STORE_MEM SETTINGS += -DDEFAULT_LBUTTON_ACTION=BUTTON_ACTION_RECALL_MEM -#Define if button action setting should be independent of active setting +## : Define if button action setting should be independent of active setting SETTINGS += -DBUTTON_SETTING_GLOBAL -#Default LED functions +## : Default LED functions SETTINGS += -DDEFAULT_RED_LED_ACTION=LED_SETTING_CHANGE SETTINGS += -DDEFAULT_GREEN_LED_ACTION=LED_POWERED -#Define if LED function setting should be independent of active setting +## : Define if LED function setting should be independent of active setting SETTINGS += -DLED_SETTING_GLOBAL -#Default logging mode +## : Default logging mode SETTINGS += -DDEFAULT_LOG_MODE=LOG_MODE_OFF #SETTINGS += -DDEFAULT_LOG_MODE=LOG_MODE_MEMORY #SETTINGS += -DDEFAULT_LOG_MODE=LOG_MODE_LIVE -#Define if log settings should be global +## : Define if log settings should be global SETTINGS += -DLOG_SETTING_GLOBAL -#Default setting +## : Default setting SETTINGS += -DDEFAULT_SETTING=SETTINGS_FIRST -#Default pending task timeout +## : Default pending task timeout SETTINGS += -DDEFAULT_PENDING_TASK_TIMEOUT=65 #50 #* 100ms -#Default reader threshold +## : Default reader threshold SETTINGS += -DDEFAULT_READER_THRESHOLD=400 -#Use EEPROM to store settings +## : Use EEPROM to store settings SETTINGS += -DENABLE_EEPROM_SETTINGS -#Enable tests for DES/2KTDEA/3DES/AES128 crypto schemes: +## : Enable tests for DES/2KTDEA/3DES/AES128 crypto schemes: #SETTINGS += -DENABLE_CRYPTO_TESTS #SETTINGS += -DENABLE_CRYPTO_TDEA_TESTS #SETTINGS += -DENABLE_CRYPTO_3DES_TESTS #SETTINGS += -DENABLE_CRYPTO_AES_TESTS -#Enable a command to run any tests added by developers, e.g., the -#crypto scheme tests that can be enabled above: +## : Enable a command to run any tests added by developers, e.g., the +## : crypto scheme tests that can be enabled above: #SETTINGS += -DENABLE_RUNTESTS_TERMINAL_COMMAND -#Whether or not to allow users Chameleon terminal access to change the DESFire configuration's -#sensitive settings like manufacturer, serial number, etc. +## : Whether or not to allow users Chameleon terminal access to change the DESFire configuration's +## : sensitive settings like manufacturer, serial number, etc. #SETTINGS += -DDISABLE_PERMISSIVE_DESFIRE_SETTINGS #SETTINGS += -DDISABLE_DESFIRE_TERMINAL_COMMANDS -#Set a default logging mode for debugging with the DESFire -#emulation code: +## : Set a default logging mode for debugging with the DESFire +## : emulation code: #CONFIG_SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING CONFIG_SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF -#Set a default testing mode setting (0 = OFF, non-NULL = ON): +## : Set a default testing mode setting (0 = OFF, non-NULL = ON): CONFIG_SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 #CONFIG_SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 -#Feature: Use randomized UIDs that mask the actual secret UID until -#the tag has been issued a successful authentication sequence: +## : Feature: Use randomized UIDs that mask the actual secret UID until +## : the tag has been issued a successful authentication sequence: #SETTINGS += -DDESFIRE_RANDOMIZE_UIDS_PREAUTH -#Anticipating that the implementation overhead is high with the -#maximum storage allocations for the number of possible keys per -#application directory, and/or the total number of AID numbered -#directory slots, the following options will tweak this limitation: -# -> Set MEMORY_LIMITED_TESTING to shrink the defaults -# -> Or explicitly define DESFIRE_CUSTOM_MAX_KEYS=##UINT## (per AID), -# -> And/Or define DESFIRE_CUSTOM_MAX_APPS=##UINT## -# (total number of AID spaces available, not including the master 0x00) +## : Anticipating that the implementation overhead is high with the +## : maximum storage allocations for the number of possible keys per +## : application directory, and/or the total number of AID numbered +## : directory slots, the following options will tweak this limitation: +## : -> Set MEMORY_LIMITED_TESTING to shrink the defaults +## : -> Or explicitly define DESFIRE_CUSTOM_MAX_KEYS=##UINT## : (per AID), +## : -> And/Or define DESFIRE_CUSTOM_MAX_APPS=##UINT## +## : (total number of AID spaces available, not including the master 0x00) #SETTINGS += -DMEMORY_LIMITED_TESTING #SETTINGS += -DDESFIRE_CUSTOM_MAX_APPS=8 #SETTINGS += -DDESFIRE_CUSTOM_MAX_KEYS=6 @@ -122,118 +126,177 @@ CONFIG_SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 #SETTINGS += -DDESFIRE_USE_FACTORY_SIZES #SETTINGS += -DDESFIRE_MAXIMIZE_SIZES_FOR_STORAGE -#Set a minimum incoming/outgoing log size so we do not spam the -#Chameleon Mini logs to much by logging everything: +## : Set a minimum incoming/outgoing log size so we do not spam the +## : Chameleon Mini logs to much by logging everything: CONFIG_SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=1 #CONFIG_SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=0 #CONFIG_SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=1 #CONFIG_SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 -#Enable printing of crypto tests when a new DESFire emulation instance is started: +## : Enable printing of crypto tests when a new DESFire emulation instance is started: #SETTINGS += -DDESFIRE_RUN_CRYPTO_TESTING_PROCEDURE -#Option to save space with the "Application/Crypto1.c" code by storing large tables -#in PROGMEM. Note that this will slow down the read times when accessing these tables: +## : Option to save space with the "Application/Crypto1.c" code by storing large tables +## : in PROGMEM. Note that this will slow down the read times when accessing these tables: #SETTINGS += -DDESFIRE_CRYPTO1_SAVE_SPACE DESFIRE_MAINSRC = Application/DESFire +DESFIRE_CONFIG_SETTINGS_BASE= -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_LIMITED_TESTING \ + -DDESFIRE_CRYPTO1_SAVE_SPACE -DDEFAULT_CONFIGURATION=CONFIG_NONE -DESFIRE_FRAM_LOG_START=0x4000 -DESFIRE_FRAM_LOG_SIZE=0x2046 -DESFIRE_DFFRAM_SECTION_START=0x6048 -DESFIRE_DFFRAM_DATA_ADDR=0x16048 -DESFIRE_DFFRAM_MAX_SIZE=0x0FFF -DESFIRE_DFFRAM_SECTION_NAME=\".dffram\" -DESFIRE_DFFRAM_OBJCOPY= --set-section-flags=.dffram="alloc,load,readonly" -DESFIRE_CONFIG_SETTINGS_BASE=$(SETTINGS) -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_LIMITED_TESTING \ - -DDESFIRE_CRYPTO1_SAVE_SPACE -DDEFAULT_CONFIGURATION=CONFIG_NONE -#Memory definitions and objcopy flags to include sections in binaries -FLASH_DATA_ADDR = 0x10000 #Start of data section in flash -FLASH_DATA_SIZE = 0x10000 #Size of data section in flash +#include BuildScripts/generate_build_settings_from_config.mk + +## : Fix some issues with standard Makefile targets on MacOS +## : where non-GNU versions of coreutils (and Unix commands like +## : grep, sed, awk) lead to unexpected behavior: +CHECK_SIZE_GREP_CMD=grep -oP "\d+" +ifeq "$(shell uname -s)" "Darwin" + CHECK_SIZE_GREP_CMD=grep -Eo "[[:digit:]]+" +endif + +## : Memory definitions and objcopy flags to include sections in binaries +## : ++ Start of data section in flash +FLASH_DATA_ADDR = 0x10000 +## : ++ Size of data section in flash +FLASH_DATA_SIZE = 0x10000 FLASH_DATA_OBJCOPY = --set-section-flags=.flashdata="alloc,load" -SPM_HELPER_ADDR = 0x21FE0 #Start of SPM helper section. Should be last 32Byte in bootloader section +## : ++ Start of SPM helper section. Should be last 32Byte in bootloader section +SPM_HELPER_ADDR = 0x21FE0 SPM_HELPER_OBJCOPY = --set-section-flags=.spmhelper="alloc,load" -#Build configuration +## : Build configuration ifeq ($(OS),Windows_NT) -BUILD_DATE = "\"$(shell date /t)\"" + BUILD_DATE = "\"$(shell date /t)\"" else -BUILD_DATE = $(shell date +'\"%y%m%d\"') + BUILD_DATE = $(shell date +'\"%Y-%m-%d\"') endif + COMMIT_ID = $(shell git rev-parse --short HEAD) MCU = atxmega128a4u ARCH = XMEGA BOARD = NONE F_CPU = 27120000 F_USB = 48000000 -TARGET = Chameleon-Mini +TARGET ?= Chameleon-Mini OPTIMIZATION = s -SRC += $(TARGET).c LUFADescriptors.c System.c ISRSharing.S Configuration.c Random.c Common.c \ - Memory.c MemoryAsm.S Button.c Log.c Settings.c LED.c Pin.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/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 \ - Application/CryptoTDEA-HWAccelerated.S Application/CryptoTDEA.c \ - Application/CryptoAES128.c Application/CryptoCMAC.c \ - Tests/CryptoTests.c Tests/ChameleonTerminal.c -SRC += Application/NTAG215.c -SRC += Codec/ISO15693.c -SRC += Application/Vicinity.c Application/Sl2s2002.c Application/TITagitstandard.c Application/TITagitplus.c Application/ISO15693-A.c Application/EM4233.c -SRC += $(DESFIRE_MAINSRC)/../MifareDESFire.c \ - $(DESFIRE_MAINSRC)/DESFireApplicationDirectory.c \ - $(DESFIRE_MAINSRC)/DESFireChameleonTerminal.c \ - $(DESFIRE_MAINSRC)/DESFireCrypto.c \ - $(DESFIRE_MAINSRC)/DESFireFile.c \ - $(DESFIRE_MAINSRC)/DESFireISO14443Support.c \ - $(DESFIRE_MAINSRC)/DESFireISO7816Support.c \ - $(DESFIRE_MAINSRC)/DESFireInstructions.c \ - $(DESFIRE_MAINSRC)/DESFireLogging.c \ - $(DESFIRE_MAINSRC)/DESFireMemoryOperations.c \ - $(DESFIRE_MAINSRC)/DESFirePICCControl.c \ - $(DESFIRE_MAINSRC)/DESFireUtils.c -SRC += $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) -LUFA_PATH = ../LUFA -CC_FLAGS = -g0 -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)\" \ - $(CONFIG_SETTINGS) $(SETTINGS) \ - -D__AVR_ATxmega128A4U__ -D__PROG_TYPES_COMPAT__ -DMAX_ENDPOINT_INDEX=4 \ - -std=gnu99 -Werror=implicit-function-declaration \ - -fno-inline-small-functions -fshort-enums -fpack-struct \ - -ffunction-sections -fdata-sections -fvisibility=hidden \ - -Wl,--gc-sections --data-sections \ - -Wl,-relax -fno-split-wide-types -fno-tree-scev-cprop \ - -fno-aggressive-loop-optimizations -fno-jump-tables -fno-common -LD_FLAGS = $(CC_FLAGS) -Wl,--section-start=.flashdata=$(FLASH_DATA_ADDR) -Wl,--section-start=.spmhelper=$(SPM_HELPER_ADDR) \ - -Wl,--section-start=.dffram=$(DESFIRE_DFFRAM_DATA_ADDR) +SRC += $(TARGET).c \ + LUFADescriptors.c \ + System.c \ + ISRSharing.S \ + Configuration.c \ + Random.c \ + Common.c \ + Memory.c \ + MemoryAsm.S \ + Button.c \ + Log.c \ + Settings.c \ + LED.c \ + Pin.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/SniffISO14443-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/Sniff14443A.c \ + Application/CryptoTDEA-HWAccelerated.S \ + Application/CryptoTDEA.c \ + Application/CryptoAES128.c \ + Application/CryptoCMAC.c +SRC += Application/NTAG215.c +SRC += Application/Vicinity.c \ + Application/Sl2s2002.c \ + Application/TITagitstandard.c \ + Application/TITagitplus.c \ + Application/ISO15693-A.c \ + Application/EM4233.c +SRC += $(DESFIRE_MAINSRC)/../MifareDESFire.c \ + $(DESFIRE_MAINSRC)/DESFireApplicationDirectory.c \ + $(DESFIRE_MAINSRC)/DESFireChameleonTerminal.c \ + $(DESFIRE_MAINSRC)/DESFireCrypto.c \ + $(DESFIRE_MAINSRC)/DESFireFile.c \ + $(DESFIRE_MAINSRC)/DESFireISO14443Support.c \ + $(DESFIRE_MAINSRC)/DESFireISO7816Support.c \ + $(DESFIRE_MAINSRC)/DESFireInstructions.c \ + $(DESFIRE_MAINSRC)/DESFireLogging.c \ + $(DESFIRE_MAINSRC)/DESFireMemoryOperations.c \ + $(DESFIRE_MAINSRC)/DESFirePICCControl.c \ + $(DESFIRE_MAINSRC)/DESFireUtils.c +SRC += Tests/CryptoTests.c \ + Tests/ChameleonTerminal.c +SRC += $(LUFA_SRC_USB) \ + $(LUFA_SRC_USBCLASS) +LUFA_PATH = ../LUFA +CC_FLAGS = -g0 \ + -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)\" \ + $(CONFIG_SETTINGS) \ + $(SETTINGS) \ + -D__AVR_ATxmega128A4U__ \ + -D__PROG_TYPES_COMPAT__ \ + -DMAX_ENDPOINT_INDEX=4 \ + -std=gnu99 \ + -Werror=implicit-function-declaration \ + -fno-inline-small-functions \ + -fshort-enums \ + -fpack-struct \ + -ffunction-sections \ + -fdata-sections \ + -fvisibility=hidden \ + -Wl,--gc-sections \ + --data-sections \ + -Wl,-relax \ + -fno-split-wide-types \ + -fno-tree-scev-cprop \ + -fno-aggressive-loop-optimizations \ + -fno-jump-tables \ + -fno-common +LD_FLAGS = $(CC_FLAGS) \ + -Wl,--section-start=.flashdata=$(FLASH_DATA_ADDR) \ + -Wl,--section-start=.spmhelper=$(SPM_HELPER_ADDR) OBJDIR = Bin OBJECT_FILES = - -#AVRDUDE settings +## : AVRDUDE settings AVRDUDE_PROGRAMMER = flip2 -AVRDUDE_MCU = atxmega128a4u +AVRDUDE_MCU = $(MCU) AVRDUDE_PORT = usb AVRDUDE_WRITE_APP = -U application:w:$(TARGET).hex AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep AVRDUDE_FLAGS = -p $(AVRDUDE_MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) -#AVRDUDE settings to program the precompiled firmware -AVRDUDE_WRITE_APP_LATEST = -U application:w:Latest/Chameleon-Mini.hex -AVRDUDE_WRITE_EEPROM_LATEST = -U eeprom:w:Latest/Chameleon-Mini.eep +## : AVRDUDE settings to program the precompiled firmware +AVRDUDE_WRITE_APP_LATEST = -U application:w:Latest/$(TARGET).hex +AVRDUDE_WRITE_EEPROM_LATEST = -U eeprom:w:Latest/$(TARGET).eep -.PHONY: program program-latest dfu-flip dfu-prog check_size style +.PHONY: clean program program-latest dfu-flip dfu-prog check_size style -# Default target +## : Default target all: -# Include LUFA build script makefiles +## : Include LUFA build script makefiles include $(LUFA_PATH)/Build/lufa_core.mk include $(LUFA_PATH)/Build/lufa_sources.mk include $(LUFA_PATH)/Build/lufa_build.mk include $(LUFA_PATH)/Build/lufa_cppcheck.mk -#Overwrite the LUFA versions of hex/bin file generation to include spmhelper and flashdata sections +## : Overwrite the LUFA versions of hex/bin file generation to include spmhelper and flashdata sections %.hex: %.elf @echo $(MSG_OBJCPY_CMD) Extracting HEX file data from \"$<\" $(CROSS)-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature $(FLASH_DATA_OBJCOPY) $< $@ @@ -242,57 +305,61 @@ include $(LUFA_PATH)/Build/lufa_cppcheck.mk @echo $(MSG_OBJCPY_CMD) Extracting BIN file data from \"$<\" $(CROSS)-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature $(FLASH_DATA_OBJCOPY) $< $@ -# Extract SPMHelper in the last 32 Byte of the bootloader section to externally combine it with any bootloader +## : Extract SPMHelper in the last 32 Byte of the bootloader section to externally combine it with any bootloader spmhelper: $(TARGET).elf @echo $(MSG_OBJCPY_CMD) Extracting SPM helper HEX file from $(TARGET).elf $(CROSS)-objcopy -O ihex -j .spmhelper $(SPM_HELPER_OBJCOPY) $(TARGET).elf $(TARGET).hex -# Program the device using avrdude +## : Program the device using avrdude program: $(TARGET).hex $(TARGET).eep check_size avrdude $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_APP) $(AVRDUDE_WRITE_EEPROM) -# Program the device using avrdude with the latest official firmware +## : Program the device using avrdude with the latest official firmware program-latest: check_size avrdude $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_APP_LATEST) $(AVRDUDE_WRITE_EEPROM_LATEST) -# Program the device using batchisp and the DFU bootloader -# Note that the device has to be in bootloader mode already-ffunction-sections -fdata-sections +## : Program the device using batchisp and the DFU bootloader +## : Note that the device has to be in bootloader mode already-ffunction-sections -fdata-sections dfu-flip: $(TARGET).hex $(TARGET).eep check_size cp $(TARGET).eep EEPROM.hex - batchisp -hardware usb -device $(MCU) -operation erase f memory FLASH loadbuffer $(TARGET).hex program verify memory EEPROM loadbuffer EEPROM.hex program verify start reset 0 + batchisp -hardware usb -device $(MCU) -operation erase f memory FLASH loadbuffer $(TARGET).hex \ + program verify memory EEPROM loadbuffer EEPROM.hex \ + program verify start reset 0 rm EEPROM.hex -# Program the device using dfu-programmer +## : Program the device using dfu-programmer dfu-prog: $(TARGET).hex $(TARGET).eep check_size dfu-programmer $(MCU) erase dfu-programmer $(MCU) flash-eeprom $(TARGET).eep dfu-programmer $(MCU) flash $(TARGET).hex dfu-programmer $(MCU) reset -#check_size: SHELL:=$(shell which bash) -check_size: - @{ \ +check_size: SHELL:=$(shell which bash) +check_size: SHELL_SCRIPT_EXEC_LINES:='\ set -e; \ if [ ! -f $(TARGET).elf ]; then \ exit 0; \ fi; \ - PROGMEM_SIZE=$$(avr-size $(TARGET).elf | grep -oP "\d+" | sed -n 4p); \ + PROGMEM_SIZE=$$(avr-size $(TARGET).elf | $(CHECK_SIZE_GREP_CMD) | sed -n 4p); \ MAX_PRGMEM_SIZE=$$(printf "%d\n" $(FLASH_DATA_ADDR)); \ if [ $$PROGMEM_SIZE -gt $$MAX_PRGMEM_SIZE ]; then \ - echo "make: *** $(TARGET).elf Application Section size $$PROGMEM_SIZE excedes maximum allowed $$MAX_PRGMEM_SIZE. Please disable some features in Makefile"; \ + echo "make: *** $(TARGET).elf Application Section size $$PROGMEM_SIZE " \ + echo "excedes maximum allowed $$MAX_PRGMEM_SIZE. Please disable some features in Makefile"; \ exit 1; \ fi; \ - } + ' +check_size: + @$(SHELL) -c $(SHELL_SCRIPT_EXEC_LINES) style: - # Make sure astyle is installed + ## : Make sure astyle is installed @which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 ) - # Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, Makefile + ## : Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, Makefile find . \( -name "*.[ch]" -or -name "Makefile" \) \ -exec perl -pi -e 's/[ \t]+$$//' {} \; \ -exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \ -exec sh -c "echo >> {}" \; - # Apply astyle on *.c, *.h + ## : Apply astyle on *.c, *.h find . -name "*.[ch]" -exec astyle --formatted --mode=c --suffix=none \ --indent=spaces=4 --indent-switches \ --keep-one-line-blocks --max-instatement-indent=60 \ @@ -304,29 +371,12 @@ local-clean: @rm -rf $(OBJDIR) @mkdir $(OBJDIR) +clean: local-clean + git-add-dev: - @make style && git add Makefile ./*.{c,h} ./*/*.{c,h} ./*/*/*.{c,h} + @make style && git add Makefile BuildScripts/custom_build_targets.mk ./*.{c,h} ./*/*.{c,h} ./*/*/*.{c,h} @cd ../../Software/DESFireLibNFCTesting && make style && \ - git add Makefile LocalInclude/*.h Source/*.c SampleOutputDumps/*.dump - -## Defining custom targets for the DESFire build (normal/user mode) and -## developer mode for use with the Android CMLD application that enables -## the printing of LIVE logs to the phone's console by default: -desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bin check_size - @cp $(TARGET).hex $(TARGET)-DESFire.hex - @cp $(TARGET).eep $(TARGET)-DESFire.eep - @cp $(TARGET).bin $(TARGET)-DESFire.bin - @echo "" - @avr-size -A -x $(TARGET).elf - @avr-size -B -x $(TARGET).elf - @echo "" - @avr-size -C -x $(TARGET).elf -desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -fno-inline-small-functions -desfire: desfire-build - -desfire-dev: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -fno-inline-small-functions \ - -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ - -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ - -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING \ - -DDESFIRE_DEFAULT_TESTING_MODE=1 -desfire-dev: desfire-build + git add Makefile LocalInclude/*.h Source/*.c SampleOutputDumps/*.dump + +## : Define custom targets +include BuildScripts/custom_build_targets.mk From 8e77d7877a0fb9913473f27167de17f6e2b57555 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Wed, 1 Jun 2022 09:04:53 -0400 Subject: [PATCH 49/68] More refinements and efforts to make build output cleaner to read --- .../Chameleon-Mini/BuildScripts/.gitignore | 2 + .../BuildScripts/custom_build_targets.mk | 118 +++-- .../BuildScripts/lufa_build_extra.mk | 417 ++++++++++++++++++ Firmware/Chameleon-Mini/Makefile | 198 ++++++--- 4 files changed, 612 insertions(+), 123 deletions(-) create mode 100644 Firmware/Chameleon-Mini/BuildScripts/.gitignore create mode 100644 Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk diff --git a/Firmware/Chameleon-Mini/BuildScripts/.gitignore b/Firmware/Chameleon-Mini/BuildScripts/.gitignore new file mode 100644 index 00000000..c166b3c5 --- /dev/null +++ b/Firmware/Chameleon-Mini/BuildScripts/.gitignore @@ -0,0 +1,2 @@ +*.mk +*.cfg diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index 19cd66de..0fb6d2fa 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -1,106 +1,102 @@ +SHELL := $(if $(SHELL), $(SHELL), /bin/sh) +BASH := $(if $(shell which bash), $(shell which bash), /bin/bash) + +TARGET_CUSTOM_BUILD_NAME = +TARGET_CUSTOM_BUILD = $(TARGET)-$(strip $(if $(TARGET_CUSTOM_BUILD_NAME), "CustomBuild_$(TARGET_CUSTOM_BUILD_NAME)", "DefaultBuild")) +DEFAULT_TAG_SUPPORT_BASE = -DCONFIG_ISO14443A_SNIFF_SUPPORT \ + -DCONFIG_ISO14443A_READER_SUPPORT +SUPPORTED_TAGS ?= +SUPPORTED_TAGS_BUILD := $(SUPPORTED_TAGS) +CUSTOM_CONFIG_SETTINGS_BASE := $(DEFAULT_TAG_SUPPORT) $(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE + ## : Include several standardized custom build target variants: +custom-build: CONFIG_SETTINGS:=$(CUSTOM_CONFIG_SETTINGS_BASE) custom-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bin check_size - @cp $(TARGET).hex $(TARGET)-$(TARGET_CUSTOM_BUILD).hex - @cp $(TARGET).eep $(TARGET)-$(TARGET_CUSTOM_BUILD).eep - @cp $(TARGET).bin $(TARGET)-$(TARGET_CUSTOM_BUILD).bin - @echo "" + @cp $(TARGET).hex $(TARGET_CUSTOM_BUILD).hex + @cp $(TARGET).eep $(TARGET_CUSTOM_BUILD).eep + @cp $(TARGET).elf $(TARGET_CUSTOM_BUILD).elf + @cp $(TARGET).bin $(TARGET_CUSTOM_BUILD).bin + @echo $(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)"\n" @avr-size -A -x $(TARGET).elf + @echo $(MSG_TIDY_ENDSEP)"\n" @avr-size -B -x $(TARGET).elf - @echo "" + @echo "\n"$(MSG_TIDY_ENDSEP)"\n" @avr-size -C -x $(TARGET).elf - @echo "" - @echo " ==== SUCCESS BUILDING CUSTOM FIRMWARE -- $(TARGET)-$(TARGET_CUSTOM_BUILD) ====" - @echo "" + @echo $(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)"\n" + @echo $(FMT_ANSIC_BOLD)$(FMT_ANSIC_EXCLAIM)"[!!!]"$(FMT_ANSIC_END) \ + $(FMT_ANSIC_BOLD)$(FMT_ANSIC_UNDERLINE)"SUCCESS BUILDING CUSTOM FIRMWARE:"$(FMT_ANSIC_END) + @echo $(FMT_ANSIC_BOLD)$(FMT_ANSIC_EXCLAIM)"[!!!]"$(FMT_ANSIC_END) \ + $(FMT_ANSIC_BOLD)"$(TARGET_CUSTOM_BUILD).{hex/eep/elf/bin}"$(FMT_ANSIC_END) + @echo "\n" -default_config_support: DEFAULT_TAG_SUPPORT:= \ - -DCONFIG_ISO14443A_SNIFF_SUPPORT \ - -DCONFIG_ISO14443A_READER_SUPPORT +default_config_support: DEFAULT_TAG_SUPPORT:=$(DEFAULT_TAG_SUPPORT_BASE) nodefault_config_support: DEFAULT_TAG_SUPPORT:= -## : Define a few other useful custom build targets: -mifare: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ +mifare: SUPPORTED_TAGS_BUILD:=\ -DCONFIG_MF_CLASSIC_MINI_4B_SUPPORT \ -DCONFIG_MF_CLASSIC_1K_SUPPORT \ -DCONFIG_MF_CLASSIC_1K_7B_SUPPORT \ -DCONFIG_MF_CLASSIC_4K_SUPPORT \ -DCONFIG_MF_CLASSIC_4K_7B_SUPPORT \ - -DCONFIG_MF_ULTRALIGHT_SUPPORTmifare: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE -mifare: TARGET_CUSTOM_BUILD:=CustomBuild_MifareDefaultSupport + -DCONFIG_MF_ULTRALIGHT_SUPPORT +mifare: TARGET_CUSTOM_BUILD_NAME:=MifareDefaultSupport mifare: custom-build mifare-classic: nodefault_config_support -mifare-classic: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ +mifare-classic: SUPPORTED_TAGS_BUILD:=\ -DCONFIG_MF_CLASSIC_MINI_4B_SUPPORT \ -DCONFIG_MF_CLASSIC_1K_SUPPORT \ -DCONFIG_MF_CLASSIC_1K_7B_SUPPORT \ -DCONFIG_MF_CLASSIC_4K_SUPPORT \ -DCONFIG_MF_CLASSIC_4K_7B_SUPPORT -mifare-classic: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE -mifare-classic: TARGET_CUSTOM_BUILD:=CustomBuild_MifareClassicSupport +mifare-classic: TARGET_CUSTOM_BUILD_NAME:=MifareClassicSupport mifare-classic: custom-build +desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) \ + -fno-inline-small-functions +desfire: TARGET_CUSTOM_BUILD_NAME:=DESFire +desfire: custom-build + +desfire-dev: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) \ + -fno-inline-small-functions \ + -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ + -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ + -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING \ + -DDESFIRE_DEFAULT_TESTING_MODE=1 +desfire-dev: TARGET_CUSTOM_BUILD_NAME:=DESFire_DEV +desfire-dev: custom-build + iso-modes: nodefault_config_support -iso-modes: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ +iso-modes: SUPPORTED_TAGS_BUILD:=\ -DCONFIG_ISO14443A_SNIFF_SUPPORT \ -DCONFIG_ISO14443A_READER_SUPPORT \ -DCONFIG_ISO15693_SNIFF_SUPPORT -iso-modes: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE -iso-modes: TARGET_CUSTOM_BUILD:=CustomBuild_ISOSniffReaderModeSupport +iso-modes: TARGET_CUSTOM_BUILD_NAME:=ISOSniffReaderModeSupport iso-modes: custom-build ntag215: default_config_support -ntag215: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ - -DCONFIG_NTAG215_SUPPORT -ntag215: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE -ntag215: TARGET_CUSTOM_BUILD:=CustomBuild_NTAG215Support +ntag215: SUPPORTED_TAGS_BUILD:=-DCONFIG_NTAG215_SUPPORT +ntag215: TARGET_CUSTOM_BUILD_NAME:=NTAG215Support ntag215: custom-build vicinity: default_config_support -vicinity: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ - -DCONFIG_VICINITY_SUPPORT -vicinity: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE -vicinity: TARGET_CUSTOM_BUILD:=CustomBuild_VicinitySupport +vicinity: SUPPORTED_TAGS_BUILD:=-DCONFIG_VICINITY_SUPPORT +vicinity: TARGET_CUSTOM_BUILD_NAME:=VicinitySupport vicinity: custom-build sl2s2002: default_config_support -sl2s2002: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ - -DCONFIG_SL2S2002_SUPPORT -sl2s2002: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE -sl2s2002: TARGET_CUSTOM_BUILD:=CustomBuild_SL2S2002Support +sl2s2002: SUPPORTED_TAGS_BUILD:=-DCONFIG_SL2S2002_SUPPORT +sl2s2002: TARGET_CUSTOM_BUILD_NAME:=SL2S2002Support sl2s2002: custom-build tagatit: default_config_support -tagatit: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ +tagatit: SUPPORTED_TAGS_BUILD:=\ -DCONFIG_TITAGITSTANDARD_SUPPORT \ -DCONFIG_TITAGITPLUS_SUPPORT -tagatit: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE -tagatit: TARGET_CUSTOM_BUILD:=CustomBuild_TagatitSupport +tagatit: TARGET_CUSTOM_BUILD_NAME:=TagatitSupport tagatit: custom-build em4233: default_config_support -em4233: SUPPORTED_TAGS:=$(DEFAULT_TAG_SUPPORT) \ - -DCONFIG_EM4233_SUPPORT -em4233: CONFIG_SETTINGS:= $(SUPPORTED_TAGS) -DDEFAULT_CONFIGURATION=CONFIG_NONE -em4233: TARGET_CUSTOM_BUILD:=CustomBuild_EM4233Support +em4233: SUPPORTED_TAGS_BUILD:=-DCONFIG_EM4233_SUPPORT +em4233: TARGET_CUSTOM_BUILD_NAME:=EM4233Support em4233: custom-build - -## : Define custom targets for the DESFire build (normal/user mode) and -## : developer mode for use with the Android CMLD application that enables -## : the printing of LIVE logs to the phone's console by default: -desfire-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bin check_size - @cp $(TARGET).hex $(TARGET)-DESFire.hex - @cp $(TARGET).eep $(TARGET)-DESFire.eep - @cp $(TARGET).bin $(TARGET)-DESFire.bin - @echo "" - @avr-size -A -x $(TARGET).elf - @avr-size -B -x $(TARGET).elf - @echo "" - @avr-size -C -x $(TARGET).elf -desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -fno-inline-small-functions -desfire: desfire-build -desfire-dev: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) -fno-inline-small-functions \ - -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ - -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ - -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING \ - -DDESFIRE_DEFAULT_TESTING_MODE=1 -desfire-dev: desfire-build diff --git a/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk b/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk new file mode 100644 index 00000000..a386d468 --- /dev/null +++ b/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk @@ -0,0 +1,417 @@ +# +# LUFA Library +# Copyright (C) Dean Camera, 2015. +# +# dean [at] fourwalledcubicle [dot] com +# www.lufa-lib.org +# + +LUFA_BUILD_MODULES += BUILD +LUFA_BUILD_TARGETS += size symbol-sizes all lib elf bin hex lss clean mostlyclean +LUFA_BUILD_MANDATORY_VARS += TARGET ARCH MCU SRC F_USB LUFA_PATH +LUFA_BUILD_OPTIONAL_VARS += BOARD OPTIMIZATION C_STANDARD CPP_STANDARD F_CPU C_FLAGS CPP_FLAGS ASM_FLAGS CC_FLAGS LD_FLAGS OBJDIR OBJECT_FILES DEBUG_TYPE DEBUG_LEVEL LINKER_RELAXATIONS COMPILER_PATH +LUFA_BUILD_PROVIDED_VARS += +LUFA_BUILD_PROVIDED_MACROS += + +# ----------------------------------------------------------------------------- +# LUFA GCC Compiler Buildsystem Makefile Module. +# ----------------------------------------------------------------------------- +# DESCRIPTION: +# Provides a set of targets to build a C, C++ and/or Assembly application +# via the AVR-GCC compiler. +# ----------------------------------------------------------------------------- +# TARGETS: +# +# size - List built application size +# symbol-sizes - Print application symbols from the binary ELF +# file as a list sorted by size in bytes +# all - Build application and list size +# lib - Build and archive source files into a library +# elf - Build application ELF debug object file +# bin - Build application BIN binary object file +# hex - Build application HEX object file +# lss - Build application LSS assembly listing file +# clean - Remove all project intermediary and binary +# output files +# mostlyclean - Remove intermediary output files, but +# preserve binaries +# .s - Compile C/C++ source file into an assembly file +# for manual code inspection +# +# MANDATORY PARAMETERS: +# +# TARGET - Application name +# ARCH - Device architecture name +# MCU - Microcontroller device model name +# SRC - List of input source files (*.c, *.cpp, *.S) +# F_USB - Speed of the input clock of the USB controller +# in Hz +# LUFA_PATH - Path to the LUFA library core +# +# OPTIONAL PARAMETERS: +# +# BOARD - LUFA board hardware +# OPTIMIZATION - Optimization level +# C_STANDARD - C Language Standard to use +# CPP_STANDARD - C++ Language Standard to use +# F_CPU - Speed of the CPU, in Hz +# C_FLAGS - Flags to pass to the C compiler only +# CPP_FLAGS - Flags to pass to the C++ compiler only +# ASM_FLAGS - Flags to pass to the assembler only +# CC_FLAGS - Common flags to pass to the C/C++ compiler and +# assembler +# LD_FLAGS - Flags to pass to the linker +# LINKER_RELAXATIONS - Enable or disable linker relaxations to +# decrease binary size (note: can cause link +# failures on systems with an unpatched binutils) +# OBJDIR - Directory for the output object and dependency +# files; if equal to ".", the output files will +# be generated in the same folder as the sources +# OBJECT_FILES - Extra object files to link in to the binaries +# DEBUG_FORMAT - Format of the debugging information to +# generate in the compiled object files +# DEBUG_LEVEL - Level the debugging information to generate in +# the compiled object files +# COMPILER_PATH - Location of the GCC toolchain to use +# +# PROVIDED VARIABLES: +# +# (None) +# +# PROVIDED MACROS: +# +# (None) +# +# ----------------------------------------------------------------------------- + +SHELL = /bin/sh + +ERROR_IF_UNSET ?= $(if $(filter undefined, $(origin $(strip $(1)))), $(error Makefile $(strip $(1)) value not set)) +ERROR_IF_EMPTY ?= $(if $(strip $($(strip $(1)))), , $(error Makefile $(strip $(1)) option cannot be blank)) +ERROR_IF_NONBOOL ?= $(if $(filter Y N, $($(strip $(1)))), , $(error Makefile $(strip $(1)) option must be Y or N)) + +# Default values of optionally user-supplied variables +COMPILER_PATH ?= +BOARD ?= NONE +OPTIMIZATION ?= s +F_CPU ?= +C_STANDARD ?= gnu99 +CPP_STANDARD ?= gnu++98 +C_FLAGS ?= +CPP_FLAGS ?= +ASM_FLAGS ?= +CC_FLAGS ?= +OBJDIR ?= . +OBJECT_FILES ?= +DEBUG_FORMAT ?= dwarf-2 +DEBUG_LEVEL ?= 2 +LINKER_RELAXATIONS ?= Y + +# Sanity check user supplied values +$(foreach MANDATORY_VAR, $(LUFA_BUILD_MANDATORY_VARS), $(call ERROR_IF_UNSET, $(MANDATORY_VAR))) +$(call ERROR_IF_EMPTY, MCU) +$(call ERROR_IF_EMPTY, TARGET) +$(call ERROR_IF_EMPTY, ARCH) +$(call ERROR_IF_EMPTY, F_USB) +$(call ERROR_IF_EMPTY, LUFA_PATH) +$(call ERROR_IF_EMPTY, BOARD) +$(call ERROR_IF_EMPTY, OPTIMIZATION) +$(call ERROR_IF_EMPTY, C_STANDARD) +$(call ERROR_IF_EMPTY, CPP_STANDARD) +$(call ERROR_IF_EMPTY, OBJDIR) +$(call ERROR_IF_EMPTY, DEBUG_FORMAT) +$(call ERROR_IF_EMPTY, DEBUG_LEVEL) +$(call ERROR_IF_NONBOOL, LINKER_RELAXATIONS) + +# Determine the utility prefix to use for the selected architecture +ifeq ($(ARCH), AVR8) + CROSS := $(COMPILER_PATH)avr +else ifeq ($(ARCH), XMEGA) + CROSS := $(COMPILER_PATH)avr + $(warning The XMEGA device support is currently EXPERIMENTAL (incomplete and/or non-functional), and is included for preview purposes only.) +else ifeq ($(ARCH), UC3) + CROSS := $(COMPILER_PATH)avr32 + $(warning The UC3 device support is currently EXPERIMENTAL (incomplete and/or non-functional), and is included for preview purposes only.) +else + $(error Unsupported architecture "$(ARCH)") +endif + +# ANSI colored formatting +FMT_ANSIC_UNDERLINE := "\033[4m" +FMT_ANSIC_BOLD := "\033[1m" +FMT_ANSIC_GREEN := "\033[92m" +FMT_ANSIC_CYAN := "\033[46;97m" +FMT_ANSIC_MAGENTA := "\033[95m" +FMT_ANSIC_EXCLAIM := "\033[31;43;93m" +FMT_ANSIC_BW := "\033[90;30;47m" +FMT_ANSIC_BW_V2 := "\033[97;30;48m" +FMT_ANSIC_RESET := "\033[0m" +FMT_ANSIC_END := "\033[0m" +FMT_CMDHL_BEGIN := $(FMT_ANSIC_UNDERLINE)$(FMT_ANSIC_BOLD)$(FMT_ANSIC_GREEN) +FMT_CMDSEP_BEGIN := $(FMT_ANSIC_BOLD)$(FMT_ANSIC_CYAN) +FMT_CMDSEP_V2_BEGIN := $(FMT_ANSIC_BOLD)$(FMT_ANSIC_BW_V2) +FMT_FILENAME_BEGIN := $(FMT_ANSIC_BOLD)$(FMT_ANSIC_MAGENTA) +FMT_NEWLINE := $(FMT_ANSIC_RESET)$(FMT_ANSIC_END) + +# Output Messages +MSG_INFO_MESSAGE := ' ['$(FMT_CMDHL_BEGIN)'INFO'$(FMT_ANSIC_END)'] :' +MSG_COMPILE_CMD := ' ['$(FMT_CMDHL_BEGIN)'GCC'$(FMT_ANSIC_END)'] :' +MSG_ASSEMBLE_CMD := ' ['$(FMT_CMDHL_BEGIN)'GAS'$(FMT_ANSIC_END)'] :' +MSG_NM_CMD := ' ['$(FMT_CMDHL_BEGIN)'NM'$(FMT_ANSIC_END)'] :' +MSG_REMOVE_CMD := ' ['$(FMT_CMDHL_BEGIN)'RM'$(FMT_ANSIC_END)'] :' +MSG_LINK_CMD := ' ['$(FMT_CMDHL_BEGIN)'LNK'$(FMT_ANSIC_END)'] :' +MSG_ARCHIVE_CMD := ' ['$(FMT_CMDHL_BEGIN)'AR'$(FMT_ANSIC_END)'] :' +MSG_SIZE_CMD := ' ['$(FMT_CMDHL_BEGIN)'SIZE'$(FMT_ANSIC_END)'] :' +MSG_OBJCPY_CMD := ' ['$(FMT_CMDHL_BEGIN)'OBJCPY'$(FMT_ANSIC_END)'] :' +MSG_OBJDMP_CMD := ' ['$(FMT_CMDHL_BEGIN)'OBJDMP'$(FMT_ANSIC_END)'] :' +MSG_NEWLINE := $(FMT_NEWLINE)"\n" +MSG_CMDSEP_LINE := ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ' +MSG_CMDSEP_LINE_V2 := ' :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ' +MSG_CMDSEP_LINE_V3 := ' ================================================================================ ' +MSG_TIDY_PRE_FORMATTING := $(FMT_CMDSEP_BEGIN)$(MSG_CMDSEP_LINE)$(MSG_NEWLINE) +MSG_TIDY_INTERMED_FORMATTING := $(FMT_CMDSEP_V2_BEGIN)$(MSG_CMDSEP_LINE_V2)$(MSG_NEWLINE) +MSG_TIDY_POST_FORMATTING := $(FMT_NEWLINE) +MSG_TIDY_ENDSEP := $(FMT_ANSIC_BOLD)$(FMT_ANSIC_BW)$(MSG_CMDSEP_LINE_V3)$(MSG_NEWLINE) + +# Convert input source file list to differentiate them by type +FULL_SOURCE := $(SRC) $(LUFA_SRC) +C_SOURCE := $(filter %.c, $(FULL_SOURCE)) +CPP_SOURCE := $(filter %.cpp, $(FULL_SOURCE)) +ASM_SOURCE := $(filter %.S, $(FULL_SOURCE)) + +# Create a list of unknown source file types, if any are found throw an error +UNKNOWN_SOURCE := $(filter-out $(C_SOURCE) $(CPP_SOURCE) $(ASM_SOURCE), $(FULL_SOURCE)) +ifneq ($(UNKNOWN_SOURCE),) + $(error Unknown input source file formats: $(UNKNOWN_SOURCE)) +endif + +# Convert input source filenames into a list of required output object files +FWSRC_OBJECT_FILES := $(addsuffix .o, $(basename $(FULL_SOURCE))) +OBJECT_FILES += $(sort $(FWSRC_OBJECT_FILES)) +LUFA_OBJECT_FILES := $(addsuffix .o, $(shell basename $(LUFA_SRC))) + +# Check if an output object file directory was specified instead of the input file location +ifneq ($(OBJDIR),.) + # Prefix all the object filenames with the output object file directory path + OBJECT_FILES := $(addprefix $(patsubst %/,%,$(OBJDIR))/, $(notdir $(OBJECT_FILES))) + + # Check if any object file (without path) appears more than once in the object file list + ifneq ($(words $(sort $(OBJECT_FILES))), $(words $(OBJECT_FILES))) + $(error Cannot build with OBJDIR parameter set - one or more object file name is not unique) + endif + + # Create the output object file directory if it does not exist and add it to the virtual path list + $(shell mkdir $(OBJDIR) 2> /dev/null) + $(shell mkdir $(LUFA_OBJDIR) 2> /dev/null) + $(shell mkdir $(TEMPDIR) 2> /dev/null) + VPATH += $(dir $(FULL_SOURCE)) +endif + +# Create a list of dependency files from the list of object files +DEPENDENCY_FILES := $(OBJECT_FILES:%.o=%.d) + +# Create a list of common flags to pass to the compiler/linker/assembler +BASE_CC_FLAGS := -pipe -g$(DEBUG_FORMAT) -g$(DEBUG_LEVEL) +ifeq ($(ARCH), AVR8) + BASE_CC_FLAGS += -mmcu=$(MCU) -fshort-enums -fno-inline-small-functions -fpack-struct +else ifeq ($(ARCH), XMEGA) + BASE_CC_FLAGS += -mmcu=$(MCU) -fshort-enums -fno-inline-small-functions -fpack-struct +else ifeq ($(ARCH), UC3) + BASE_CC_FLAGS += -mpart=$(MCU:at32%=%) -masm-addr-pseudos +endif +BASE_CC_FLAGS += -Wall -fno-strict-aliasing -funsigned-char -funsigned-bitfields -ffunction-sections +BASE_CC_FLAGS += -I. -I$(patsubst %/,%,$(LUFA_PATH))/.. +BASE_CC_FLAGS += -DARCH=ARCH_$(ARCH) -DBOARD=BOARD_$(BOARD) -DF_USB=$(F_USB)UL +ifneq ($(F_CPU),) + BASE_CC_FLAGS += -DF_CPU=$(F_CPU)UL +endif +ifeq ($(LINKER_RELAXATIONS), Y) +BASE_CC_FLAGS += -mrelax +endif + +# This flag is required for bootloaders as GCC will emit invalid jump table +# assembly code for devices with large amounts of flash; the jump table target +# is extracted from FLASH without using the correct ELPM instruction, resulting +# in a pseudo-random jump target. +BASE_CC_FLAGS += -fno-jump-tables + +# Additional language specific compiler flags +BASE_C_FLAGS := -x c -O$(OPTIMIZATION) -std=$(C_STANDARD) -Wstrict-prototypes +BASE_CPP_FLAGS := -x c++ -O$(OPTIMIZATION) -std=$(CPP_STANDARD) +BASE_ASM_FLAGS := -x assembler-with-cpp + +# Create a list of flags to pass to the linker +BASE_LD_FLAGS := -lm -Wl,-Map=$(TARGET).map,--cref -Wl,--gc-sections +ifeq ($(LINKER_RELAXATIONS), Y) + BASE_LD_FLAGS += -Wl,--relax +endif +ifeq ($(ARCH), AVR8) + BASE_LD_FLAGS += -mmcu=$(MCU) +else ifeq ($(ARCH), XMEGA) + BASE_LD_FLAGS += -mmcu=$(MCU) +else ifeq ($(ARCH), UC3) + BASE_LD_FLAGS += -mpart=$(MCU:at32%=%) --rodata-writable --direct-data +endif + +# Determine flags to pass to the size utility based on its reported features (only invoke if size target required) +# and on an architecture where this non-standard patch is available +ifneq ($(ARCH), UC3) +size: SIZE_MCU_FLAG := $(shell $(CROSS)-size --help | grep -- --mcu > /dev/null && echo --mcu=$(MCU) ) +size: SIZE_FORMAT_FLAG := $(shell $(CROSS)-size --help | grep -- --format=.*avr > /dev/null && echo --format=avr ) +endif + +# Pre-build informational target, to give compiler and project name information when building +build_begin: + @echo $(MSG_INFO_MESSAGE) Begin compilation of project \"$(TARGET)\"... + @echo "" + @$(CROSS)-gcc --version + +# Post-build informational target, to project name information when building has completed +build_end: + @echo $(MSG_INFO_MESSAGE) Finished building project \"$(TARGET)\". + +# Prints size information of a compiled application (FLASH, RAM and EEPROM usages) +size: $(TARGET).elf + @echo $(MSG_SIZE_CMD) Determining size of \"$<\" + @echo "" + $(CROSS)-size $(SIZE_MCU_FLAG) $(SIZE_FORMAT_FLAG) $< + +# Prints size information on the symbols within a compiled application in decimal bytes +symbol-sizes: $(TARGET).elf + @echo $(MSG_NM_CMD) Extracting \"$<\" symbols with decimal byte sizes + $(CROSS)-nm --size-sort --demangle --radix=d $< + +# Cleans intermediary build files, leaving only the compiled application files +mostlyclean: + @echo $(MSG_REMOVE_CMD) Removing object files of \"$(TARGET)\" + rm -f $(OBJECT_FILES) + @echo $(MSG_REMOVE_CMD) Removing dependency files of \"$(TARGET)\" + rm -f $(DEPENDENCY_FILES) + +# Cleans all build files, leaving only the original source code +clean: mostlyclean + @echo $(MSG_REMOVE_CMD) Removing output files of \"$(TARGET)\" + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).bin $(TARGET).eep $(TARGET).map $(TARGET).lss $(TARGET).sym lib$(TARGET).a + +# Performs a complete build of the user application and prints size information afterwards +all: build_begin elf hex bin lss sym size build_end + +# Helper targets, to build a specific type of output file without having to know the project target name +lib: lib$(TARGET).a +elf: $(TARGET).elf +hex: $(TARGET).hex $(TARGET).eep +bin: $(TARGET).bin +lss: $(TARGET).lss +sym: $(TARGET).sym + +# Default target to *create* the user application's specified source files; if this rule is executed by +# make, the input source file doesn't exist and an error needs to be presented to the user +$(FULL_SOURCE): + $(error Source file does not exist: $@) + +# Compiles an input C source file and generates an assembly listing for it +%.s: %.c $(MAKEFILE_LIST) + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_COMPILE_CMD) Generating assembly from C file $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) + $(CROSS)-gcc -S $(BASE_CC_FLAGS) $(BASE_C_FLAGS) $(CC_FLAGS) $(C_FLAGS) $< -o $@ + @echo $(MSG_TIDY_POST_FORMATTING) + +# Compiles an input C++ source file and generates an assembly listing for it +%.s: %.cpp $(MAKEFILE_LIST) + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_COMPILE_CMD) Generating assembly from C++ file $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) + $(CROSS)-gcc -S $(BASE_CC_FLAGS) $(BASE_CPP_FLAGS) $(CC_FLAGS) $(CPP_FLAGS) $< -o $@ + @echo $(MSG_TIDY_POST_FORMATTING) + +# Compiles an input C source file and generates a linkable object file for it +$(OBJDIR)*/%.o: %.c $(MAKEFILE_LIST) + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_COMPILE_CMD) Compiling C file $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) + $(CROSS)-gcc -c $(BASE_CC_FLAGS) $(BASE_C_FLAGS) $(CC_FLAGS) $(C_FLAGS) -MMD -MP -MF $(@:%.o=%.d) $< -o $@ + @echo $(MSG_TIDY_POST_FORMATTING) + +# Compiles an input C++ source file and generates a linkable object file for it +$(OBJDIR)*/%.o: %.cpp $(MAKEFILE_LIST) + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_COMPILE_CMD) Compiling C++ file $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) + $(CROSS)-gcc -c $(BASE_CC_FLAGS) $(BASE_CPP_FLAGS) $(CC_FLAGS) $(CPP_FLAGS) -MMD -MP -MF $(@:%.o=%.d) $< -o $@ + @echo $(MSG_TIDY_POST_FORMATTING) + +# Assembles an input ASM source file and generates a linkable object file for it +$(OBJDIR)*/%.o: %.S $(MAKEFILE_LIST) + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_ASSEMBLE_CMD) Assembling $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) + $(CROSS)-gcc -c $(BASE_CC_FLAGS) $(BASE_ASM_FLAGS) $(CC_FLAGS) $(ASM_FLAGS) -MMD -MP -MF $(@:%.o=%.d) $< -o $@ + @echo $(MSG_TIDY_POST_FORMATTING) + +# Generates a library archive file from the user application, which can be linked into other applications +.PRECIOUS : $(OBJECT_FILES) +.SECONDARY : %.a +%.a: $(OBJECT_FILES) + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_ARCHIVE_CMD) Archiving object files into $(FMT_FILENAME_BEGIN)\"$@\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) + $(CROSS)-ar rcs $@ $(OBJECT_FILES) + @echo $(MSG_TIDY_POST_FORMATTING) + +# Generates an ELF debug file from the user application, which can be further processed for FLASH and EEPROM data +# files, or used for programming and debugging directly +.PRECIOUS : $(OBJECT_FILES) +.SECONDARY : %.elf +%.elf: $(OBJECT_FILES) + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_LINK_CMD) Linking object files into $(FMT_FILENAME_BEGIN)\"$@\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) + $(CROSS)-gcc $^ -o $@ $(BASE_LD_FLAGS) $(LD_FLAGS) + @echo $(MSG_TIDY_POST_FORMATTING) + +# Extracts out the loadable FLASH memory data from the project ELF file, and creates an Intel HEX format file of it +%.hex: %.elf + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_OBJCPY_CMD) Extracting HEX file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) + $(CROSS)-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature $< $@ + @echo $(MSG_TIDY_POST_FORMATTING) + +# Extracts out the loadable FLASH memory data from the project ELF file, and creates an Binary format file of it +%.bin: %.elf + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_OBJCPY_CMD) Extracting BIN file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) + $(CROSS)-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature $< $@ + @echo $(MSG_TIDY_POST_FORMATTING) + +# Extracts out the loadable EEPROM memory data from the project ELF file, and creates an Intel HEX format file of it +%.eep: %.elf + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_OBJCPY_CMD) Extracting EEP file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) + $(CROSS)-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings $< $@ || exit 0 + @echo $(MSG_TIDY_POST_FORMATTING) + +# Creates an assembly listing file from an input project ELF file, containing interleaved assembly and source data +%.lss: %.elf + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_OBJDMP_CMD) Extracting LSS file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) + $(CROSS)-objdump -h -d -S -z $< > $@ + @echo $(MSG_TIDY_POST_FORMATTING) + +# Creates a symbol file listing the loadable and discarded symbols from an input project ELF file +%.sym: %.elf + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_NM_CMD) Extracting SYM file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) + $(CROSS)-nm -n $< > $@ + @echo $(MSG_TIDY_POST_FORMATTING) + +# Include build dependency files +-include $(DEPENDENCY_FILES) + +# Phony build targets for this module +.PHONY: build_begin build_end size symbol-sizes lib elf hex lss clean mostlyclean diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 5980293e..6de09283 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -2,7 +2,9 @@ ## : Note when using AVR-Toolchain, you have to install cygwin and ## : append cygwin's bin directory to the PATH environment variable ## : because Atmel does not ship sh.exe anymore with the toolchain. -SHELL = /bin/sh +SHELL = /bin/sh +CONFIG_SETTINGS ?= +SETTINGS ?= ## : Supported configurations: ## : CAUTION: Enabling too many configurations in the firmware @@ -144,41 +146,42 @@ DESFIRE_MAINSRC = Application/DESFire DESFIRE_CONFIG_SETTINGS_BASE= -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_LIMITED_TESTING \ -DDESFIRE_CRYPTO1_SAVE_SPACE -DDEFAULT_CONFIGURATION=CONFIG_NONE -#include BuildScripts/generate_build_settings_from_config.mk - ## : Fix some issues with standard Makefile targets on MacOS ## : where non-GNU versions of coreutils (and Unix commands like ## : grep, sed, awk) lead to unexpected behavior: -CHECK_SIZE_GREP_CMD=grep -oP "\d+" -ifeq "$(shell uname -s)" "Darwin" - CHECK_SIZE_GREP_CMD=grep -Eo "[[:digit:]]+" -endif +CHECK_SIZE_GREP_ARGS=$(if $(filter "$(shell uname -s)", "Darwin"), -Eo "[[:digit:]]+", -oP "\d+") ## : Memory definitions and objcopy flags to include sections in binaries -## : ++ Start of data section in flash -FLASH_DATA_ADDR = 0x10000 -## : ++ Size of data section in flash -FLASH_DATA_SIZE = 0x10000 -FLASH_DATA_OBJCOPY = --set-section-flags=.flashdata="alloc,load" -## : ++ Start of SPM helper section. Should be last 32Byte in bootloader section -SPM_HELPER_ADDR = 0x21FE0 -SPM_HELPER_OBJCOPY = --set-section-flags=.spmhelper="alloc,load" +## ++ Start of data section in flash +FLASH_DATA_ADDR = 0x10000 +## ++ Size of data section in flash +FLASH_DATA_SIZE = 0x10000 +FLASH_DATA_SECTION_NAME = .flashdata +FLASH_DATA_OBJCOPY = --set-section-flags=$(FLASH_DATA_SECTION_NAME)="alloc,load" +## ++ Start of SPM helper section. +## ++ Should be last 32 bytes in bootloader section +SPM_HELPER_ADDR = 0x21FE0 +SPM_HELPER_OBJCOPY = --set-section-flags=.spmhelper="alloc,load,readonly" ## : Build configuration -ifeq ($(OS),Windows_NT) - BUILD_DATE = "\"$(shell date /t)\"" -else - BUILD_DATE = $(shell date +'\"%Y-%m-%d\"') -endif - COMMIT_ID = $(shell git rev-parse --short HEAD) -MCU = atxmega128a4u -ARCH = XMEGA -BOARD = NONE -F_CPU = 27120000 -F_USB = 48000000 +BUILD_DATE = $(strip $(if $(filter $(OS), Windows_NT), "\"$(shell date /t)\"", $(shell date +'\"%Y-%m-%d\"'))) + +## : Adding the '?=' before the `MCU` variable definition lets it be reset by an environment variable, +## : so that the following works (may be useful for those users working with a RevE generation +## : Chameleon device): +## : $ TARGET=atxmega32a4u make +## : ... OR ... +## : $ TARGET=atxmega32a4u make +MCU ?= atxmega128a4u + +ARCH = XMEGA +BOARD = NONE +F_CPU = 27120000 +F_USB = 48000000 TARGET ?= Chameleon-Mini -OPTIMIZATION = s +OPTIMIZATION = s +SRC = SRC += $(TARGET).c \ LUFADescriptors.c \ System.c \ @@ -236,7 +239,7 @@ SRC += $(DESFIRE_MAINSRC)/../MifareDESFire.c \ $(DESFIRE_MAINSRC)/DESFireUtils.c SRC += Tests/CryptoTests.c \ Tests/ChameleonTerminal.c -SRC += $(LUFA_SRC_USB) \ +LUFA_SRC = $(LUFA_SRC_USB) \ $(LUFA_SRC_USBCLASS) LUFA_PATH = ../LUFA CC_FLAGS = -g0 \ @@ -271,7 +274,11 @@ LD_FLAGS = $(CC_FLAGS) \ -Wl,--section-start=.flashdata=$(FLASH_DATA_ADDR) \ -Wl,--section-start=.spmhelper=$(SPM_HELPER_ADDR) OBJDIR = Bin +LUFA_OBJDIR = LUFABin +TEMPDIR = $(OBJDIR)/Temp OBJECT_FILES = +FWROOT = ../.. +BUILD_SCR = ./BuildScripts ## : AVRDUDE settings AVRDUDE_PROGRAMMER = flip2 @@ -288,27 +295,38 @@ AVRDUDE_WRITE_EEPROM_LATEST = -U eeprom:w:Latest/$(TARGET).eep .PHONY: clean program program-latest dfu-flip dfu-prog check_size style ## : Default target -all: +.DEFAULT all: ## : Include LUFA build script makefiles include $(LUFA_PATH)/Build/lufa_core.mk include $(LUFA_PATH)/Build/lufa_sources.mk -include $(LUFA_PATH)/Build/lufa_build.mk +include $(BUILD_SCR)/lufa_build_extra.mk include $(LUFA_PATH)/Build/lufa_cppcheck.mk ## : Overwrite the LUFA versions of hex/bin file generation to include spmhelper and flashdata sections %.hex: %.elf - @echo $(MSG_OBJCPY_CMD) Extracting HEX file data from \"$<\" + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_OBJCPY_CMD) Extracting $(FMT_ANSIC_LIGHTRED)HEX$(FMT_ANSIC_END) file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature $(FLASH_DATA_OBJCOPY) $< $@ + @echo $(MSG_TIDY_POST_FORMATTING) %.bin: %.elf - @echo $(MSG_OBJCPY_CMD) Extracting BIN file data from \"$<\" + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_OBJCPY_CMD) Extracting $(FMT_ANSIC_LIGHTRED)BIN$(FMT_ANSIC_END) file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature $(FLASH_DATA_OBJCOPY) $< $@ + @echo $(MSG_TIDY_POST_FORMATTING) ## : Extract SPMHelper in the last 32 Byte of the bootloader section to externally combine it with any bootloader spmhelper: $(TARGET).elf - @echo $(MSG_OBJCPY_CMD) Extracting SPM helper HEX file from $(TARGET).elf + @echo $(MSG_TIDY_PRE_FORMATTING) + @echo $(MSG_OBJCPY_CMD) Extracting $(FMT_ANSIC_LIGHTRED)SPM$(FMT_ANSIC_END) helper \ + $(FMT_ANSIC_LIGHTRED)HEX$(FMT_ANSIC_END) file \ + from $(FMT_FILENAME_BEGIN)$(TARGET).elf$(MSG_NEWLINE) + @echo $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-objcopy -O ihex -j .spmhelper $(SPM_HELPER_OBJCOPY) $(TARGET).elf $(TARGET).hex + @echo $(MSG_TIDY_POST_FORMATTING) ## : Program the device using avrdude program: $(TARGET).hex $(TARGET).eep check_size @@ -334,49 +352,105 @@ dfu-prog: $(TARGET).hex $(TARGET).eep check_size dfu-programmer $(MCU) flash $(TARGET).hex dfu-programmer $(MCU) reset -check_size: SHELL:=$(shell which bash) -check_size: SHELL_SCRIPT_EXEC_LINES:='\ - set -e; \ - if [ ! -f $(TARGET).elf ]; then \ - exit 0; \ - fi; \ - PROGMEM_SIZE=$$(avr-size $(TARGET).elf | $(CHECK_SIZE_GREP_CMD) | sed -n 4p); \ - MAX_PRGMEM_SIZE=$$(printf "%d\n" $(FLASH_DATA_ADDR)); \ - if [ $$PROGMEM_SIZE -gt $$MAX_PRGMEM_SIZE ]; then \ - echo "make: *** $(TARGET).elf Application Section size $$PROGMEM_SIZE " \ - echo "excedes maximum allowed $$MAX_PRGMEM_SIZE. Please disable some features in Makefile"; \ - exit 1; \ - fi; \ +check_size: BASH:=$(if $(shell which bash), $(shell which bash), /bin/bash) +check_size: BASH_SCRIPT_EXEC_LINES:=' \ + set -e; \ + if [[ ! -f $(TARGET).elf ]]; then \ + exit 0; \ + fi; \ + PROGMEM_SIZE=$$(avr-size $(TARGET).elf | grep $(CHECK_SIZE_GREP_ARGS) | sed -n 4p); \ + MAX_PRGMEM_SIZE=$$(printf "%d\n" $(FLASH_DATA_ADDR)); \ + if [[ $$PROGMEM_SIZE -gt $$MAX_PRGMEM_SIZE ]]; then \ + echo \"make: *** $(TARGET).elf Application Section size $$PROGMEM_SIZE \" \ + echo \"excedes maximum allowed $$MAX_PRGMEM_SIZE. Please disable some features in Makefile\"; \ + exit 1; \ + fi; \ ' check_size: - @$(SHELL) -c $(SHELL_SCRIPT_EXEC_LINES) + @$(BASH) -c $(BASH_SCRIPT_EXEC_LINES) || $(SHELL) -c $(BASH_SCRIPT_EXEC_LINES) style: ## : Make sure astyle is installed @which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 ) ## : Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, Makefile - find . \( -name "*.[ch]" -or -name "Makefile" \) \ - -exec perl -pi -e 's/[ \t]+$$//' {} \; \ + find . \( -name "*.[ch]" -or -name "Makefile" \) \ + -exec perl -pi -e 's/[ \t]+$$//' {} \; \ -exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \ -exec sh -c "echo >> {}" \; ## : Apply astyle on *.c, *.h find . -name "*.[ch]" -exec astyle --formatted --mode=c --suffix=none \ - --indent=spaces=4 --indent-switches \ - --keep-one-line-blocks --max-instatement-indent=60 \ - --style=google --pad-oper --unpad-paren --pad-header \ + --indent=spaces=4 --indent-switches \ + --keep-one-line-blocks --max-instatement-indent=60 \ + --style=google --pad-oper --unpad-paren --pad-header \ --align-pointer=name {} \; +local-clean: BASH:=$(if $(shell which bash), $(shell which bash), /bin/bash) +local-clean: BASH_SCRIPT_EXEC_LINES:=' \ + for lufaobj in $$(ls $(LUFA_OBJDIR)); do \ + lobj_basename=$$(basename $$lufaobj); \ + ln -s $(LUFA_OBJDIR)/$$lobj_basename $(OBJDIR)/$$lobj_basename; \ + done \ + ' local-clean: - @rm -f $(TARGET)*.{elf,hex,eep,bin,lss,map} - @rm -rf $(OBJDIR) - @mkdir $(OBJDIR) + @rm -f $(TARGET)*.{elf,hex,eep,bin,lss,map} + @rm -rf $(OBJDIR) $(LUFA_OBJ) + @mkdir -p $(OBJDIR) $(LUFA_OBJDIR) + @$(BASH) -c $(BASH_SCRIPT_EXEC_LINES) || $(SHELL) -c $(BASH_SCRIPT_EXEC_LINES) -clean: local-clean +local-clean-skip: -git-add-dev: - @make style && git add Makefile BuildScripts/custom_build_targets.mk ./*.{c,h} ./*/*.{c,h} ./*/*/*.{c,h} - @cd ../../Software/DESFireLibNFCTesting && make style && \ - git add Makefile LocalInclude/*.h Source/*.c SampleOutputDumps/*.dump +ifdef $(NOCLEAN) + clean: local-clean-skip +else + clean: local-clean +endif -## : Define custom targets -include BuildScripts/custom_build_targets.mk +git-add-dev: LOCALFW_SOURCE_FILES:=Makefile ./*.{c,h} ./*/*.{c,h} ./*/*/*.{c,h} +git-add-dev: LOCALFW_BUILD_SCRIPT_FILES:=.gitignore custom_build_targets.mk lufa_build_custom.mk +git-add-dev: TESTING_SOURCE_FILES:=Makefile LocalInclude/*.h Source/*.c SampleOutputDumps/*.dump +git-add-dev: BASH:=$(if $(shell which bash), $(shell which bash), /bin/bash) +git-add-dev: BASH_GITCOMMIT_SCRIPT_EXEC_LINES:=' \ + if [ -z \"$(M)\" ]; then \ + git commit -m \"$(M)\"; \ + git push origin; \ + elif [ -z \"$(MSG)\" ]; then \ + git commit -m "$(MSG)"; \ + git push origin; \ + elif [ -z \"$(MESSAGE)\" ]; then \ + git commit -m \"$(MESSAGE)\"; \ + git push origin; \ + fi \ + exit 0; \ + ' +git-add-dev: + @make style && git add $(LOCALFW_SOURCE_FILES) + @cd $(BUILD_SCR) && make style && git add -f $(LOCALFW_BUILD_SCRIPT_FILES) + @cd $(FWROOT)/Software/DESFireLibNFCTesting && make style && git add $(TESTING_SOURCE_FILES) + @$(BASH) -c $(BASH_GITCOMMIT_SCRIPT_LINES) || $(SHELL) -c $(BASH_GITCOMMIT_SCRIPT_LINES) + +configure-chameleon-usb: UDEV_RULES_CONFIG_LINES:='\n \ + \# ChameleonMini (RevG)\n \ + SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"16d0\", ATTRS{idProduct}==\"04b2\", GROUP=\"users\", \ + MODE=\"0666\", SYMLINK+=\"ChameleonMini\", ENV{ID_MM_DEVICE_IGNORE}=\"1\"\n \ + \# ChameleonMini (RevE)\n \ + SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"03eb\", ATTRS{idProduct}==\"2044\", GROUP=\"users\", \ + MODE=\"0666\", SYMLINK+=\"ChameleonMiniE\", ENV{ID_MM_DEVICE_IGNORE}=\"1\"\n \ + \# ChameleonMini DFU mode\n \ + SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"03eb\", ATTRS{idProduct}==\"2fde\", GROUP=\"users\", \ + MODE=\"0666\" \ + ' +configure-chameleon-usb: + @mkdir -p $(TEMPDIR) && echo $(UDEV_RULES_CONFIG_LINES) > $(TEMPDIR)/98-ChameleonMini.rules + @echo "" + @echo "TO CONFIGURE THE CHAMELEON OVER USB, RUN THE FOLLOWING COMMANDS:" + @echo " $$ sudo cp $(TEMPDIR)/98-ChameleonMini.rules /etc/udev/rules.d/" + @echo " $$ sudo service udev restart" + @echo " $$ sudo udevadm control --reload" + @echo "" + @echo "FOR HELP TROUBLESHOOTING THE CHAMELEON USB CONNECTION, LOOK AT THE FOLLOWING OUTPUT:" + @echo " $$ dmesg | tail | grep -i dev" + @echo " $$ dmesg | tail | grep -i usb" + @echo " $$ sudo udevadm monitor" + +## : Define custom targets and standard build variants +include $(BUILD_SCR)/custom_build_targets.mk From f9c1dabf3c8d3bda98f6127d7cf43daa5b1a4f50 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Thu, 2 Jun 2022 00:40:53 -0400 Subject: [PATCH 50/68] Updates to make/build scripts ; Partial fixes to @colinoflynn\'s notes in #313 (success with \'hf mfdes info -- Still debugging auth exchanges) --- .../DESFire/DESFireISO14443Support.c | 5 +- .../DESFire/DESFirePICCHeaderLayout.h | 6 +- .../Chameleon-Mini/Application/ISO14443-3A.c | 113 ++--------------- .../Chameleon-Mini/Application/ISO14443-3A.h | 12 +- .../Application/MifareDESFire.c | 21 +++- .../BuildScripts/custom_build_targets.mk | 67 +++++----- Firmware/Chameleon-Mini/Makefile | 115 +++++++----------- 7 files changed, 126 insertions(+), 213 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index 4a3d717f..40ca6ae1 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -420,8 +420,9 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { const char *logMsg = PSTR("ISO14443-3/4: EXPECTING RATS"); LogDebuggingMsg(logMsg); } else if (Cmd == ISO14443A_CMD_SELECT_CL3) { - Buffer[0] = 0x00; - return 1 * BITS_PER_BYTE; + Buffer[0] = ISO14443A_SAK_COMPLETE_NOT_COMPLIANT; + ISO14443AAppendCRCA(Buffer, 1); + return ISO14443A_SAK_FRAME_SIZE; } /* Forward to ISO/IEC 14443-4 processing code */ uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index db6abd1b..d36df834 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -49,9 +49,13 @@ This notice must be retained at the top of all source files where indicated. /* Anticollision parameters */ #define ATQA_VALUE 0x0344 +#ifndef FORCE_SAK_NOT_COMPLIANT #define SAK_CL1_VALUE (ISO14443A_SAK_INCOMPLETE) #define SAK_CL2_VALUE (ISO14443A_SAK_COMPLETE_COMPLIANT) -#define SAK_UID_NOT_FINISHED 0x04 +#else +#define SAK_CL1_VALUE (ISO14443A_SAK_INCOMPLETE_NOT_COMPLIANT) +#define SAK_CL2_VALUE (ISO14443A_SAK_COMPLETE_NOT_COMPLIANT) +#endif #define STATUS_FRAME_SIZE (1 * 8) /* Bits */ diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c index ebdbed03..6a2d0ffd 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c @@ -1,26 +1,22 @@ /* - * ISO14443A.c + * ISO14443A.c * * Created on: 19.03.2013 - * Author: skuser + * Author: skuser */ #include "ISO14443-3A.h" -#define CRC_INIT 0x6363 -#define CRC_INIT_R 0xC6C6 /* Bit reversed */ - #ifdef CONFIG_MF_DESFIRE_SUPPORT - #include "DESFire/DESFireISO14443Support.h" bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t SAKValue) { + uint8_t *DataPtr = (uint8_t *) Buffer; uint8_t NVB = DataPtr[1]; switch (NVB) { - case 0x00: - case ISO14443A_CMD_HLTA: + case ISO14443A_NVB_AC_START: /* Start of anticollision procedure. * Send whole UID CLn + BCC */ @@ -31,7 +27,6 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, ui DataPtr[ISO14443A_CL_BCC_OFFSET] = ISO14443A_CALC_BCC(DataPtr); *BitCount = ISO14443A_CL_FRAME_SIZE; return false; - case ISO14443A_NVB_AC_END: /* End of anticollision procedure. * Send SAK CLn if we are selected. */ @@ -40,47 +35,21 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, ui (DataPtr[4] == UidCL[2]) && (DataPtr[5] == UidCL[3])) { DataPtr[0] = SAKValue; - ISO14443AUpdateCRCA(Buffer, 1, ISO14443A_CRCA_INIT); - *BitCount = 3 * BITS_PER_BYTE; + ISO14443AAppendCRCA(Buffer, 1); + *BitCount = ISO14443A_SAK_FRAME_SIZE; return true; } else { /* We have not been selected. Don't send anything. */ *BitCount = 0; return false; } - default: { - uint8_t CollisionByteCount = ((NVB >> 4) & 0x0f) - 2; - uint8_t CollisionBitCount = (NVB >> 0) & 0x0f; - uint8_t mask = 0xFF >> (8 - CollisionBitCount); - // Since the UidCL does not contain the BCC, we have to distinguish here - if ( - ((CollisionByteCount == 5 || (CollisionByteCount == 4 && CollisionBitCount > 0)) && - memcmp(UidCL, &DataPtr[2], 4) == 0 && (ISO14443A_CALC_BCC(UidCL) & mask) == (DataPtr[6] & mask)) - || - (CollisionByteCount == 4 && CollisionBitCount == 0 && memcmp(UidCL, &DataPtr[2], 4) == 0) - || - (CollisionByteCount < 4 && memcmp(UidCL, &DataPtr[2], CollisionByteCount) == 0 && - (UidCL[CollisionByteCount] & mask) == (DataPtr[CollisionByteCount + 2] & mask)) - ) { - DataPtr[0] = UidCL[0]; - DataPtr[1] = UidCL[1]; - DataPtr[2] = UidCL[2]; - DataPtr[3] = UidCL[3]; - DataPtr[4] = ISO14443A_CALC_BCC(DataPtr); - - *BitCount = ISO14443A_CL_FRAME_SIZE; - } else { - *BitCount = 0; - } - return false; - } + default: /* No anticollision supported */ - *BitCount = 0; - return false; + *BitCount = 0; + return false; } } - -#endif +#endif /* CONFIG_MF_DESFIRE_SUPPORT */ #define USE_HW_CRC #ifdef USE_HW_CRC @@ -157,65 +126,3 @@ bool ISO14443ACheckCRCA(const void *Buffer, uint16_t ByteCount) { return (DataPtr[0] == ((Checksum >> 0) & 0xFF)) && (DataPtr[1] == ((Checksum >> 8) & 0xFF)); } #endif - -#if 0 -bool ISO14443ASelect(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t SAKValue) { - uint8_t *DataPtr = (uint8_t *) Buffer; - uint8_t NVB = DataPtr[1]; - - switch (NVB) { - case ISO14443A_NVB_AC_START: - /* Start of anticollision procedure. - * Send whole UID CLn + BCC */ - DataPtr[0] = UidCL[0]; - DataPtr[1] = UidCL[1]; - DataPtr[2] = UidCL[2]; - DataPtr[3] = UidCL[3]; - DataPtr[4] = ISO14443A_CALC_BCC(DataPtr); - - *BitCount = ISO14443A_CL_FRAME_SIZE; - - return false; - - case ISO14443A_NVB_AC_END: - /* End of anticollision procedure. - * Send SAK CLn if we are selected. */ - if ((DataPtr[2] == UidCL[0]) && - (DataPtr[3] == UidCL[1]) && - (DataPtr[4] == UidCL[2]) && - (DataPtr[5] == UidCL[3])) { - - DataPtr[0] = SAKValue; - ISO14443AAppendCRCA(Buffer, 1); - - *BitCount = ISO14443A_SAK_FRAME_SIZE; - return true; - } else { - /* We have not been selected. Don't send anything. */ - *BitCount = 0; - return false; - } - default: - /* TODO: No anticollision supported */ - *BitCount = 0; - return false; - } -} - -bool ISO14443AWakeUp(void *Buffer, uint16_t *BitCount, uint16_t ATQAValue, bool FromHalt) { - uint8_t *DataPtr = (uint8_t *) Buffer; - - if (((! FromHalt) && (DataPtr[0] == ISO14443A_CMD_REQA)) || - (DataPtr[0] == ISO14443A_CMD_WUPA)) { - DataPtr[0] = (ATQAValue >> 0) & 0x00FF; - DataPtr[1] = (ATQAValue >> 8) & 0x00FF; - - *BitCount = ISO14443A_ATQA_FRAME_SIZE; - - return true; - } else { - return false; - } -} - -#endif diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h index cefe7dbd..5ff66fb7 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h @@ -30,7 +30,8 @@ #define ISO14443A_CL_BCC_OFFSET 4 #define ISO14443A_CL_BCC_SIZE 1 /* Byte */ #define ISO14443A_CL_FRAME_SIZE ((ISO14443A_CL_UID_SIZE + ISO14443A_CL_BCC_SIZE) * 8) /* UID[N...N+3] || BCCN */ -#define ISO14443A_SAK_INCOMPLETE 0x24 // 0x04 +#define ISO14443A_SAK_INCOMPLETE 0x24 +#define ISO14443A_SAK_INCOMPLETE_NOT_COMPLIANT 0x04 #define ISO14443A_SAK_COMPLETE_COMPLIANT 0x20 #define ISO14443A_SAK_COMPLETE_NOT_COMPLIANT 0x00 @@ -39,17 +40,20 @@ #define ISO14443A_SAK_FRAME_SIZE (3 * BITS_PER_BYTE) /* in Bits */ #define ISO14443A_HLTA_FRAME_SIZE (2 * BITS_PER_BYTE) /* in Bits */ -#define ISO14443A_UID0_RANDOM 0x08 -#define ISO14443A_UID0_CT 0x88 - #define ISO14443A_CRCA_SIZE 2 +#define CRC_INIT 0x6363 +#define CRC_INIT_R 0xC6C6 /* Bit reversed */ + #define ISO14443A_CALC_BCC(ByteBuffer) \ ( ByteBuffer[0] ^ ByteBuffer[1] ^ ByteBuffer[2] ^ ByteBuffer[3] ) void ISO14443AAppendCRCA(void *Buffer, uint16_t ByteCount); bool ISO14443ACheckCRCA(const void *Buffer, uint16_t ByteCount); +#define ISO14443A_UID0_RANDOM 0x08 +#define ISO14443A_UID0_CT 0x88 + INLINE bool ISO14443ASelect(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t SAKValue); INLINE bool ISO14443AWakeUp(void *Buffer, uint16_t *BitCount, uint16_t ATQAValue, bool FromHalt); diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index d53181ee..d4abf06c 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -179,9 +179,21 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { if (BitCount == 0) { LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); return ISO14443A_APP_NO_RESPONSE; + } else if (ByteCount >= 2 && Buffer[1] == STATUS_ADDITIONAL_FRAME && + DesfireCLA(Buffer[0])) { + ByteCount -= 1; + memmove(&Buffer[0], &Buffer[1], ByteCount); + uint16_t ProcessedByteCount = MifareDesfireProcessCommand(Buffer, ByteCount); + if (ProcessedByteCount != 0) { + /* Re-wrap into padded APDU form */ + Buffer[ProcessedByteCount] = Buffer[0]; + memmove(&Buffer[0], &Buffer[1], ProcessedByteCount - 1); + Buffer[ProcessedByteCount - 1] = 0x91; + ++ProcessedByteCount; + } + return ProcessedByteCount * BITS_PER_BYTE; } else if (((ByteCount >= 8 && Buffer[4] == ByteCount - 8) || - (ByteCount >= 5 && Buffer[4] == ByteCount - 5) || - (ByteCount >= 5 && Buffer[1] == STATUS_ADDITIONAL_FRAME)) && + (ByteCount >= 5 && Buffer[4] == ByteCount - 5)) && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 || Iso7816CLA(DesfireCmdCLA)) { /* Wrapped native command structure or ISO7816: */ @@ -234,12 +246,17 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedByteCount * BITS_PER_BYTE); } else if (ByteCount >= 8 && DesfireCLA(Buffer[1]) && Buffer[3] == 0x00 && Buffer[4] == 0x00 && Buffer[5] == ByteCount - 8) { + uint8_t hf14AScanPrologue = Buffer[0]; DesfireCmdCLA = Buffer[1]; uint16_t IncomingByteCount = MAX(0, (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE - 1); memmove(&Buffer[0], &Buffer[1], IncomingByteCount); uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + if (ProcessedByteCount++ > 0) { + memmove(&Buffer[1], &Buffer[0], ProcessedByteCount); + } + Buffer[0] = hf14AScanPrologue; ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedByteCount * BITS_PER_BYTE); diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index 0fb6d2fa..e3b5bdea 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -1,16 +1,13 @@ -SHELL := $(if $(SHELL), $(SHELL), /bin/sh) -BASH := $(if $(shell which bash), $(shell which bash), /bin/bash) +.PHONY: mifare mifare-classic desfire desfire-dev iso-modes ntag215 vicinity sl2s2002 tagatit em4233 +.SECONDARY: custom-build TARGET_CUSTOM_BUILD_NAME = -TARGET_CUSTOM_BUILD = $(TARGET)-$(strip $(if $(TARGET_CUSTOM_BUILD_NAME), "CustomBuild_$(TARGET_CUSTOM_BUILD_NAME)", "DefaultBuild")) DEFAULT_TAG_SUPPORT_BASE = -DCONFIG_ISO14443A_SNIFF_SUPPORT \ -DCONFIG_ISO14443A_READER_SUPPORT -SUPPORTED_TAGS ?= -SUPPORTED_TAGS_BUILD := $(SUPPORTED_TAGS) -CUSTOM_CONFIG_SETTINGS_BASE := $(DEFAULT_TAG_SUPPORT) $(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE +SUPPORTED_TAGS_BUILD = +EXTRA_CONFIG_SETTINGS = -## : Include several standardized custom build target variants: -custom-build: CONFIG_SETTINGS:=$(CUSTOM_CONFIG_SETTINGS_BASE) +custom-build: TARGET_CUSTOM_BUILD:=$(TARGET)-$(strip $(if $(TARGET_CUSTOM_BUILD_NAME), "CustomBuild_$(TARGET_CUSTOM_BUILD_NAME)", "DefaultBuild")) custom-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bin check_size @cp $(TARGET).hex $(TARGET_CUSTOM_BUILD).hex @cp $(TARGET).eep $(TARGET_CUSTOM_BUILD).eep @@ -26,12 +23,9 @@ custom-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bi @echo $(FMT_ANSIC_BOLD)$(FMT_ANSIC_EXCLAIM)"[!!!]"$(FMT_ANSIC_END) \ $(FMT_ANSIC_BOLD)$(FMT_ANSIC_UNDERLINE)"SUCCESS BUILDING CUSTOM FIRMWARE:"$(FMT_ANSIC_END) @echo $(FMT_ANSIC_BOLD)$(FMT_ANSIC_EXCLAIM)"[!!!]"$(FMT_ANSIC_END) \ - $(FMT_ANSIC_BOLD)"$(TARGET_CUSTOM_BUILD).{hex/eep/elf/bin}"$(FMT_ANSIC_END) + $(FMT_ANSIC_BOLD)"$(TARGET_CUSTOM_BUILD).(HEX|EEP|ELF|BIN)"$(FMT_ANSIC_END) @echo "\n" -default_config_support: DEFAULT_TAG_SUPPORT:=$(DEFAULT_TAG_SUPPORT_BASE) -nodefault_config_support: DEFAULT_TAG_SUPPORT:= - mifare: SUPPORTED_TAGS_BUILD:=\ -DCONFIG_MF_CLASSIC_MINI_4B_SUPPORT \ -DCONFIG_MF_CLASSIC_1K_SUPPORT \ @@ -40,9 +34,9 @@ mifare: SUPPORTED_TAGS_BUILD:=\ -DCONFIG_MF_CLASSIC_4K_7B_SUPPORT \ -DCONFIG_MF_ULTRALIGHT_SUPPORT mifare: TARGET_CUSTOM_BUILD_NAME:=MifareDefaultSupport +mifare: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) mifare: custom-build -mifare-classic: nodefault_config_support mifare-classic: SUPPORTED_TAGS_BUILD:=\ -DCONFIG_MF_CLASSIC_MINI_4B_SUPPORT \ -DCONFIG_MF_CLASSIC_1K_SUPPORT \ @@ -50,53 +44,62 @@ mifare-classic: SUPPORTED_TAGS_BUILD:=\ -DCONFIG_MF_CLASSIC_4K_SUPPORT \ -DCONFIG_MF_CLASSIC_4K_7B_SUPPORT mifare-classic: TARGET_CUSTOM_BUILD_NAME:=MifareClassicSupport +mifare-classic: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) mifare-classic: custom-build -desfire: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) \ - -fno-inline-small-functions +desfire: FLASH_DATA_SIZE:=0x0E000 +desfire: SUPPORTED_TAGS_BUILD:=-DCONFIG_MF_DESFIRE_SUPPORT +desfire: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ + -DDESFIRE_CRYPTO1_SAVE_SPACE \ + -f-inline-small-functions desfire: TARGET_CUSTOM_BUILD_NAME:=DESFire +desfire: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) desfire: custom-build -desfire-dev: CONFIG_SETTINGS:=$(DESFIRE_CONFIG_SETTINGS_BASE) \ - -fno-inline-small-functions \ - -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ - -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ - -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING \ - -DDESFIRE_DEFAULT_TESTING_MODE=1 +desfire-dev: FLASH_DATA_SIZE:=0x0E000 +desfire-dev: SUPPORTED_TAGS_BUILD:=-DCONFIG_MF_DESFIRE_SUPPORT +desfire-dev: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ + -DDESFIRE_CRYPTO1_SAVE_SPACE \ + -finline-small-functions \ + -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ + -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ + -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING \ + -DDESFIRE_DEFAULT_TESTING_MODE=1 desfire-dev: TARGET_CUSTOM_BUILD_NAME:=DESFire_DEV +desfire-dev: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) desfire-dev: custom-build -iso-modes: nodefault_config_support iso-modes: SUPPORTED_TAGS_BUILD:=\ -DCONFIG_ISO14443A_SNIFF_SUPPORT \ -DCONFIG_ISO14443A_READER_SUPPORT \ -DCONFIG_ISO15693_SNIFF_SUPPORT iso-modes: TARGET_CUSTOM_BUILD_NAME:=ISOSniffReaderModeSupport +iso-modes: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) iso-modes: custom-build -ntag215: default_config_support -ntag215: SUPPORTED_TAGS_BUILD:=-DCONFIG_NTAG215_SUPPORT +ntag215: SUPPORTED_TAGS_BUILD:=$(DEFAULT_TAG_SUPPORT_BASE) -DCONFIG_NTAG215_SUPPORT ntag215: TARGET_CUSTOM_BUILD_NAME:=NTAG215Support +ntag215: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) ntag215: custom-build -vicinity: default_config_support -vicinity: SUPPORTED_TAGS_BUILD:=-DCONFIG_VICINITY_SUPPORT +vicinity: SUPPORTED_TAGS_BUILD:=$(DEFAULT_TAG_SUPPORT_BASE) -DCONFIG_VICINITY_SUPPORT vicinity: TARGET_CUSTOM_BUILD_NAME:=VicinitySupport +vicinity: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) vicinity: custom-build -sl2s2002: default_config_support -sl2s2002: SUPPORTED_TAGS_BUILD:=-DCONFIG_SL2S2002_SUPPORT +sl2s2002: SUPPORTED_TAGS_BUILD:=$(DEFAULT_TAG_SUPPORT_BASE) -DCONFIG_SL2S2002_SUPPORT sl2s2002: TARGET_CUSTOM_BUILD_NAME:=SL2S2002Support +sl2s2002: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) sl2s2002: custom-build -tagatit: default_config_support -tagatit: SUPPORTED_TAGS_BUILD:=\ +tagatit: SUPPORTED_TAGS_BUILD:=$(DEFAULT_TAG_SUPPORT_BASE) \ -DCONFIG_TITAGITSTANDARD_SUPPORT \ -DCONFIG_TITAGITPLUS_SUPPORT tagatit: TARGET_CUSTOM_BUILD_NAME:=TagatitSupport +tagatit: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) tagatit: custom-build -em4233: default_config_support -em4233: SUPPORTED_TAGS_BUILD:=-DCONFIG_EM4233_SUPPORT +em4233: SUPPORTED_TAGS_BUILD:=$(DEFAULT_TAG_SUPPORT_BASE) -DCONFIG_EM4233_SUPPORT em4233: TARGET_CUSTOM_BUILD_NAME:=EM4233Support +em4233: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) em4233: custom-build diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 6de09283..bca10f0a 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -3,14 +3,15 @@ ## : append cygwin's bin directory to the PATH environment variable ## : because Atmel does not ship sh.exe anymore with the toolchain. SHELL = /bin/sh -CONFIG_SETTINGS ?= +CONFIG_SETTINGS ?= SETTINGS ?= ## : Supported configurations: -## : CAUTION: Enabling too many configurations in the firmware -## : can/will/has been known to eat up too much memory -## : on the Chameleon integrated AVR and lead to stability -## : problems ... +## : CAUTION: Enabling too many configurations in the firmware +## : can/will/has been known to eat up too much memory +## : on the Chameleon integrated AVR and lead to stability +## : problems. Proceed carefully, or use one of the +## : custom build targets found in the BuildScripts/* directory CONFIG_SETTINGS += -DCONFIG_MF_CLASSIC_MINI_4B_SUPPORT CONFIG_SETTINGS += -DCONFIG_MF_CLASSIC_1K_SUPPORT #CONFIG_SETTINGS += -DCONFIG_MF_CLASSIC_1K_7B_SUPPORT @@ -77,7 +78,7 @@ SETTINGS += -DLOG_SETTING_GLOBAL SETTINGS += -DDEFAULT_SETTING=SETTINGS_FIRST ## : Default pending task timeout -SETTINGS += -DDEFAULT_PENDING_TASK_TIMEOUT=65 #50 #* 100ms +SETTINGS += -DDEFAULT_PENDING_TASK_TIMEOUT=65 ## : Default reader threshold SETTINGS += -DDEFAULT_READER_THRESHOLD=400 @@ -121,7 +122,7 @@ CONFIG_SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 ## : -> Or explicitly define DESFIRE_CUSTOM_MAX_KEYS=##UINT## : (per AID), ## : -> And/Or define DESFIRE_CUSTOM_MAX_APPS=##UINT## ## : (total number of AID spaces available, not including the master 0x00) -#SETTINGS += -DMEMORY_LIMITED_TESTING +#SETTINGS += -DMEMORY_LIMITED_TESTING #SETTINGS += -DDESFIRE_CUSTOM_MAX_APPS=8 #SETTINGS += -DDESFIRE_CUSTOM_MAX_KEYS=6 #SETTINGS += -DDESFIRE_CUSTOM_MAX_FILES=6 @@ -131,8 +132,6 @@ CONFIG_SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 ## : Set a minimum incoming/outgoing log size so we do not spam the ## : Chameleon Mini logs to much by logging everything: CONFIG_SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=1 -#CONFIG_SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=0 -#CONFIG_SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=1 #CONFIG_SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 ## : Enable printing of crypto tests when a new DESFire emulation instance is started: @@ -142,36 +141,36 @@ CONFIG_SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=1 ## : in PROGMEM. Note that this will slow down the read times when accessing these tables: #SETTINGS += -DDESFIRE_CRYPTO1_SAVE_SPACE -DESFIRE_MAINSRC = Application/DESFire -DESFIRE_CONFIG_SETTINGS_BASE= -DCONFIG_MF_DESFIRE_SUPPORT -DMEMORY_LIMITED_TESTING \ - -DDESFIRE_CRYPTO1_SAVE_SPACE -DDEFAULT_CONFIGURATION=CONFIG_NONE - -## : Fix some issues with standard Makefile targets on MacOS -## : where non-GNU versions of coreutils (and Unix commands like -## : grep, sed, awk) lead to unexpected behavior: +## : Fix some issues with standard Makefile targets on MacOS +## : where non-GNU versions of coreutils (and Unix commands like +## : grep, sed, awk) lead to unexpected behavior: CHECK_SIZE_GREP_ARGS=$(if $(filter "$(shell uname -s)", "Darwin"), -Eo "[[:digit:]]+", -oP "\d+") ## : Memory definitions and objcopy flags to include sections in binaries ## ++ Start of data section in flash FLASH_DATA_ADDR = 0x10000 ## ++ Size of data section in flash +## ++ Each setting is 8192 bytes ... This gives eight total settings to store tag config data +## ++ Conservative settings of FLASH_DATA_SIZE:=0x0E000 yield seven total settings +## ++ Unused area in the .flashdata section can be commandered to store secret data on the +## Chameleon that can be accessed via the flash memory functions for firmware mods FLASH_DATA_SIZE = 0x10000 FLASH_DATA_SECTION_NAME = .flashdata FLASH_DATA_OBJCOPY = --set-section-flags=$(FLASH_DATA_SECTION_NAME)="alloc,load" -## ++ Start of SPM helper section. +## ++ Start of SPM helper section. ## ++ Should be last 32 bytes in bootloader section SPM_HELPER_ADDR = 0x21FE0 -SPM_HELPER_OBJCOPY = --set-section-flags=.spmhelper="alloc,load,readonly" +SPM_HELPER_OBJCOPY = --set-section-flags=.spmhelper="alloc,load" ## : Build configuration COMMIT_ID = $(shell git rev-parse --short HEAD) BUILD_DATE = $(strip $(if $(filter $(OS), Windows_NT), "\"$(shell date /t)\"", $(shell date +'\"%Y-%m-%d\"'))) -## : Adding the '?=' before the `MCU` variable definition lets it be reset by an environment variable, -## : so that the following works (may be useful for those users working with a RevE generation -## : Chameleon device): -## : $ TARGET=atxmega32a4u make -## : ... OR ... +## : Adding the '?=' before the `MCU` variable definition lets it be reset by an environment variable, +## : so that the following works (may be useful for those users working with a RevE generation +## : Chameleon device): +## : $ TARGET=atxmega32a4u make +## : ... OR ... ## : $ TARGET=atxmega32a4u make MCU ?= atxmega128a4u @@ -217,7 +216,7 @@ SRC += Application/MifareUltralight.c \ Application/CryptoTDEA-HWAccelerated.S \ Application/CryptoTDEA.c \ Application/CryptoAES128.c \ - Application/CryptoCMAC.c + Application/CryptoCMAC.c SRC += Application/NTAG215.c SRC += Application/Vicinity.c \ Application/Sl2s2002.c \ @@ -225,18 +224,18 @@ SRC += Application/Vicinity.c \ Application/TITagitplus.c \ Application/ISO15693-A.c \ Application/EM4233.c -SRC += $(DESFIRE_MAINSRC)/../MifareDESFire.c \ - $(DESFIRE_MAINSRC)/DESFireApplicationDirectory.c \ - $(DESFIRE_MAINSRC)/DESFireChameleonTerminal.c \ - $(DESFIRE_MAINSRC)/DESFireCrypto.c \ - $(DESFIRE_MAINSRC)/DESFireFile.c \ - $(DESFIRE_MAINSRC)/DESFireISO14443Support.c \ - $(DESFIRE_MAINSRC)/DESFireISO7816Support.c \ - $(DESFIRE_MAINSRC)/DESFireInstructions.c \ - $(DESFIRE_MAINSRC)/DESFireLogging.c \ - $(DESFIRE_MAINSRC)/DESFireMemoryOperations.c \ - $(DESFIRE_MAINSRC)/DESFirePICCControl.c \ - $(DESFIRE_MAINSRC)/DESFireUtils.c +SRC += Application/DESFire/../MifareDESFire.c \ + Application/DESFire/DESFireApplicationDirectory.c \ + Application/DESFire/DESFireChameleonTerminal.c \ + Application/DESFire/DESFireCrypto.c \ + Application/DESFire/DESFireFile.c \ + Application/DESFire/DESFireISO14443Support.c \ + Application/DESFire/DESFireISO7816Support.c \ + Application/DESFire/DESFireInstructions.c \ + Application/DESFire/DESFireLogging.c \ + Application/DESFire/DESFireMemoryOperations.c \ + Application/DESFire/DESFirePICCControl.c \ + Application/DESFire/DESFireUtils.c SRC += Tests/CryptoTests.c \ Tests/ChameleonTerminal.c LUFA_SRC = $(LUFA_SRC_USB) \ @@ -249,8 +248,8 @@ CC_FLAGS = -g0 \ -DSPM_HELPER_ADDR=$(SPM_HELPER_ADDR) \ -DBUILD_DATE=$(BUILD_DATE) \ -DCOMMIT_ID=\"$(COMMIT_ID)\" \ - $(CONFIG_SETTINGS) \ $(SETTINGS) \ + $(CONFIG_SETTINGS) \ -D__AVR_ATxmega128A4U__ \ -D__PROG_TYPES_COMPAT__ \ -DMAX_ENDPOINT_INDEX=4 \ @@ -270,7 +269,7 @@ CC_FLAGS = -g0 \ -fno-aggressive-loop-optimizations \ -fno-jump-tables \ -fno-common -LD_FLAGS = $(CC_FLAGS) \ +LD_FLAGS = $(CC_FLAGS) \ -Wl,--section-start=.flashdata=$(FLASH_DATA_ADDR) \ -Wl,--section-start=.spmhelper=$(SPM_HELPER_ADDR) OBJDIR = Bin @@ -300,9 +299,12 @@ AVRDUDE_WRITE_EEPROM_LATEST = -U eeprom:w:Latest/$(TARGET).eep ## : Include LUFA build script makefiles include $(LUFA_PATH)/Build/lufa_core.mk include $(LUFA_PATH)/Build/lufa_sources.mk -include $(BUILD_SCR)/lufa_build_extra.mk include $(LUFA_PATH)/Build/lufa_cppcheck.mk +## : Define custom targets and standard build variants +include $(BUILD_SCR)/lufa_build_extra.mk +include $(BUILD_SCR)/custom_build_targets.mk + ## : Overwrite the LUFA versions of hex/bin file generation to include spmhelper and flashdata sections %.hex: %.elf @echo $(MSG_TIDY_PRE_FORMATTING) @@ -396,37 +398,15 @@ local-clean: @rm -rf $(OBJDIR) $(LUFA_OBJ) @mkdir -p $(OBJDIR) $(LUFA_OBJDIR) @$(BASH) -c $(BASH_SCRIPT_EXEC_LINES) || $(SHELL) -c $(BASH_SCRIPT_EXEC_LINES) - -local-clean-skip: - -ifdef $(NOCLEAN) - clean: local-clean-skip -else - clean: local-clean -endif +clean: local-clean git-add-dev: LOCALFW_SOURCE_FILES:=Makefile ./*.{c,h} ./*/*.{c,h} ./*/*/*.{c,h} -git-add-dev: LOCALFW_BUILD_SCRIPT_FILES:=.gitignore custom_build_targets.mk lufa_build_custom.mk +git-add-dev: LOCALFW_BUILD_SCRIPT_FILES:=.gitignore custom_build_targets.mk lufa_build_extra.mk git-add-dev: TESTING_SOURCE_FILES:=Makefile LocalInclude/*.h Source/*.c SampleOutputDumps/*.dump -git-add-dev: BASH:=$(if $(shell which bash), $(shell which bash), /bin/bash) -git-add-dev: BASH_GITCOMMIT_SCRIPT_EXEC_LINES:=' \ - if [ -z \"$(M)\" ]; then \ - git commit -m \"$(M)\"; \ - git push origin; \ - elif [ -z \"$(MSG)\" ]; then \ - git commit -m "$(MSG)"; \ - git push origin; \ - elif [ -z \"$(MESSAGE)\" ]; then \ - git commit -m \"$(MESSAGE)\"; \ - git push origin; \ - fi \ - exit 0; \ - ' git-add-dev: - @make style && git add $(LOCALFW_SOURCE_FILES) - @cd $(BUILD_SCR) && make style && git add -f $(LOCALFW_BUILD_SCRIPT_FILES) + @make style && git add $(LOCALFW_SOURCE_FILES) + @cd $(BUILD_SCR) && git add -f $(LOCALFW_BUILD_SCRIPT_FILES) @cd $(FWROOT)/Software/DESFireLibNFCTesting && make style && git add $(TESTING_SOURCE_FILES) - @$(BASH) -c $(BASH_GITCOMMIT_SCRIPT_LINES) || $(SHELL) -c $(BASH_GITCOMMIT_SCRIPT_LINES) configure-chameleon-usb: UDEV_RULES_CONFIG_LINES:='\n \ \# ChameleonMini (RevG)\n \ @@ -447,10 +427,7 @@ configure-chameleon-usb: @echo " $$ sudo service udev restart" @echo " $$ sudo udevadm control --reload" @echo "" - @echo "FOR HELP TROUBLESHOOTING THE CHAMELEON USB CONNECTION, LOOK AT THE FOLLOWING OUTPUT:" + @echo "FOR HELP TROUBLESHOOTING THE CHAMELEON USB CONNECTION, CONSIDER THE FOLLOWING OUTPUT:" @echo " $$ dmesg | tail | grep -i dev" @echo " $$ dmesg | tail | grep -i usb" @echo " $$ sudo udevadm monitor" - -## : Define custom targets and standard build variants -include $(BUILD_SCR)/custom_build_targets.mk From 024c699df66c90bea4160449c45d692a86f386e3 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Sat, 4 Jun 2022 16:13:01 -0400 Subject: [PATCH 51/68] Finalizing the fixes to #313 to verify PM3 support --- Doc/DESFireSupportReadme.md | 614 +++++++++--------- .../DESFire/DESFireChameleonTerminal.c | 18 +- .../DESFire/DESFireISO14443Support.c | 31 +- .../DESFire/DESFireISO14443Support.h | 7 +- .../Application/DESFire/DESFireInstructions.c | 8 +- .../Application/DESFire/DESFirePICCControl.c | 35 +- .../DESFire/DESFirePICCHeaderLayout.h | 40 +- .../Application/DESFire/DESFireUtils.c | 35 +- .../Application/DESFire/DESFireUtils.h | 9 +- .../Chameleon-Mini/Application/ISO14443-3A.c | 8 +- .../Chameleon-Mini/Application/ISO14443-3A.h | 2 +- .../Application/MifareDESFire.c | 154 +++-- .../Application/MifareDESFire.h | 10 + .../BuildScripts/custom_build_targets.mk | 14 +- .../BuildScripts/lufa_build_extra.mk | 21 +- Firmware/Chameleon-Mini/Makefile | 5 +- 16 files changed, 525 insertions(+), 486 deletions(-) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index c771d56e..f5f3cd9b 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -15,15 +15,6 @@ Android logger application, and with ``libnfc`` via a USB NFC tag reader (host-based testing code is [available here](https://github.com/maxieds/ChameleonMiniDESFireStack/tree/master/Firmware/Chameleon-Mini/Application/DESFire/Testing)). -Support for DESFire tag emulation on the Chameleon Mini is complicated for at least a couple of reasons: -1. The hardware (onboard AVR) has a small memory footprint available. Thus with all of the new tag support, - storage needs for cryptographic data structures, and storage needs for large tables finding space - was challenging. Much of this is resolved by storing data needed for operation using a linked, flat file type - design for structures where a small amount of buffer space is needed at a time and can be filled by - fetching the data from FRAM / settings space. -2. There is only limited public information available about the precise expectations and runtime - conditions needed to write a perfect, standards-compliant DESFire tag implementation. - The firmware has been tested and known to work with the KAOS manufactured RevG Chameleon devices. Unfortunately, formative RevE device support is not available due to the memory requirements to run this firmware emulation. The device responds well using the ``libnfc``-based utility @@ -61,106 +52,82 @@ Proxmark3 NFC devices: [+] SAK: 20 [1] [+] ATS: 75 77 81 02 80 [=] field dropped. -``` -The DESFire configuration mode has been known to see recognition problems -using ``libfreefare``. - -## Supported functionality -### Tables of tested support for active commands - -#### Native DESFire command support (mixed EV0/EV1/EV2 instruction sets) - -| Instruction | Cmd Byte | Description | Testing Status | Implementation Notes | -| :--- | :----: | :----: | :----: | :-- | -| CMD_AUTHENTICATE | 0x0A | Authenticate legacy | :ballot_box_with_check: | Works with the ``-DDESFIRE_QUICK_DES_CRYPTO`` Makefile ``SETTINGS`` compiler flag set to enable "quicker" DES crypto. | -| CMD_AUTHENTICATE_ISO | 0x1A | ISO / 3DES auth | :question: | This implementation is too slow! Need hardware support for 3DES crypto? | -| CMD_AUTHENTICATE_AES | 0xAA | Standard AES auth | :ballot_box_with_check: | | -| CMD_AUTHENTICATE_EV2_FIRST | 0x71 | Newer spec auth variant | :x: | | -| CMD_AUTHENTICATE_EV2_NONFIRST | 0x77 | Newer spec auth variant | :x: | See page 32 of AN12343.pdf | -| CMD_CHANGE_KEY_SETTINGS | 0x54 | | :ballot_box_with_check: | | -| CMD_SET_CONFIGURATION | 0x5C | | :x: | | -| CMD_CHANGE_KEY | 0xC4 | | :ballot_box_with_check: | | -| CMD_GET_KEY_VERSION | 0x64 | | :ballot_box_with_check: | | -| CMD_CREATE_APPLICATION | 0xCA | | :ballot_box_with_check: | | -| CMD_DELETE_APPLICATION | 0xDA | | :ballot_box_with_check: | | -| CMD_GET_APPLICATION_IDS | 0x6A | | :ballot_box_with_check: | | -| CMD_FREE_MEMORY | 0x6E | | :ballot_box_with_check: | | -| CMD_GET_DF_NAMES | 0x6D | | :x: | =Need docs for what this command does! | -| CMD_GET_KEY_SETTINGS | 0x45 | | :ballot_box_with_check: | | -| CMD_SELECT_APPLICATION | 0x5A | | :ballot_box_with_check: | | -| CMD_FORMAT_PICC | 0xFC | | :ballot_box_with_check: | | -| CMD_GET_VERSION | 0x60 | | :ballot_box_with_check: | | -| CMD_GET_CARD_UID | 0x51 | | :ballot_box_with_check: | | -| CMD_GET_FILE_IDS | 0x6F | | :ballot_box_with_check: | | -| CMD_GET_FILE_SETTINGS | 0xF5 | | :ballot_box_with_check: | | -| CMD_CHANGE_FILE_SETTINGS | 0x5F | | :x: | | -| CMD_CREATE_STDDATA_FILE | 0xCD | | :ballot_box_with_check: | | -| CMD_CREATE_BACKUPDATA_FILE | 0xCB | | :ballot_box_with_check: | | -| CMD_CREATE_VALUE_FILE | 0xCC | | :ballot_box_with_check: | | -| CMD_CREATE_LINEAR_RECORD_FILE | 0xC1 | | :wavy_dash: | GetFileSettings still not returning correct data | -| CMD_CREATE_CYCLIC_RECORD_FILE | 0xC0 | | :wavy_dash: | GetFileSettings still not returning correct data | -| CMD_DELETE_FILE | 0xDF | | :ballot_box_with_check: | | -| CMD_GET_ISO_FILE_IDS | 0x61 | | :x: | | -| CMD_READ_DATA | 0xBD | | :ballot_box_with_check: | The data for std/backup files is uninitialized (any bits) until the user sets the data with WriteData | -| CMD_WRITE_DATA | 0x3D | | :ballot_box_with_check: | Only supports write command operations with <= 52 bytes of data at a time. Offset parameters can be used to write lengthier files. | -| CMD_GET_VALUE | 0x6C | | :ballot_box_with_check: | | -| CMD_CREDIT | 0x0C | | :ballot_box_with_check: | | -| CMD_DEBIT | 0xDC | | :ballot_box_with_check: | | -| CMD_LIMITED_CREDIT | 0x1C | | :ballot_box_with_check: | | -| CMD_WRITE_RECORD | 0x3B | | :question: | | -| CMD_READ_RECORDS | 0xBB | | :ballot_box_with_check: :wavy_dash: | | -| CMD_CLEAR_RECORD_FILE | 0xEB | | :question: | | -| CMD_COMMIT_TRANSACTION | 0xC7 | | :ballot_box_with_check: | | -| CMD_ABORT_TRANSACTION | 0xA7 | | :ballot_box_with_check: | | | - -#### ISO7816 command support - -| Instruction | Cmd Byte | Description | Testing Status | Implementation Notes | -| :--- | :----: | :----: | :----: | :-- | -| CMD_ISO7816_SELECT | 0xa4 | A more nuanced ISO7816 version of EF/DF selection. | :wavy_dash: :question: | See the implementation notes [in this spec](https://cardwerk.com/smart-card-standard-iso7816-4-section-6-basic-interindustry-commands/#chap6_11). We only support EF selection with ``P1=00000000|000000010`` and DF(AID) with ``P1=00000100``. | -| CMD_ISO7816_GET_CHALLENGE | 0x84 | | :wavy_dash: :question: | | -| CMD_ISO7816_EXTERNAL_AUTHENTICATE | 0x82 | | :x: | | -| CMD_ISO7816_INTERNAL_AUTHENTICATE | 0x88 | | :x: | | -| CMD_ISO7816_READ_BINARY | 0xb0 | | :wavy_dash: :question: | Needs testing. | -| CMD_ISO7816_UPDATE_BINARY | 0xd6 | | :wavy_dash: :question: | Needs testing. | -| CMD_ISO7816_READ_RECORDS | 0xb2 | | :wavy_dash: :question: | Needs testing. | -| CMD_ISO7816_APPEND_RECORD | 0xe2 | | :wavy_dash: :question: | Especially needs testing for corner case checks. | - -### TODO list: Suggestions for updates to the code and unsupported functionality - -* Check to figure out where possibly encrypted transfers (AES CMAC) come into play after the initial - authentication procedure? -* Need to handle encrypted transfer modes invoked after authenticate (term: SAM?)? -* Need to replace the DES/3DES encryption library for something faster? -* When setting the key data via a set command, need to initialize the key addresses, update the - key count in the AID, and other accounting details ... -* Currently, all of the file transfers (read/write) are done in plaintext ... -* The ``ReadData`` command ``offset`` input has no action at this point (TODO later) ... -* How to accurately handle BackupDataFile types? - -```cpp -case DESFIRE_FILE_BACKUP_DATA: - if (Rollback) { - CopyBlockBytes(DataAreaBlockId, DataAreaBlockId + File.BackupFile.BlockCount, File.BackupFile.BlockCount); - } - else { - CopyBlockBytes(DataAreaBlockId + File.BackupFile.BlockCount, DataAreaBlockId, File.BackupFile.BlockCount); - } - break; +[usb] pm3 --> script run debug.cmd +[+] executing Cmd debug.cmd +[+] args '' +[usb|script] pm3 --> hw dbg -4 +[usb|script] pm3 --> prefs set clientdebug --full +[=] client debug........... full +[usb|script] pm3 --> data setdebugmode -2 +[=] client debug level... 2 ( verbose debug messages ) + +[#] Debug log level......... 4 ( extended ) + +[usb] pm3 --> hf mfdes info +[#] pcb_blocknum 0 == 2 +[#] [WCMD <--: : 08/08] 02 90 60 00 00 00 14 98 +[#] pcb_blocknum 1 == 3 +[#] [WCMD <--: : 08/08] 03 90 af 00 00 00 1f 15 +[#] pcb_blocknum 0 == 2 +[#] [WCMD <--: : 08/08] 02 90 af 00 00 00 34 11 + +[=] ---------------------------------- Tag Information ---------------------------------- +[+] UID: 08 4F 8A 44 7D AE 83 +[+] Batch number: AE 83 CE E4 A5 +[+] Production date: week db / 20f1 + +[=] --- Hardware Information +[=] raw: 04010100011805 +[=] Vendor Id: NXP Semiconductors Germany +[=] Type: 0x01 +[=] Subtype: 0x01 +[=] Version: 0.1 ( DESFire MF3ICD40 ) +[=] Storage size: 0x18 ( 4096 bytes ) +[=] Protocol: 0x05 ( ISO 14443-2, 14443-3 ) + +[=] --- Software Information +[=] raw: 90AF0401010001 +[=] Vendor Id: no tag-info available +[=] Type: 0xAF +[=] Subtype: 0x04 +[=] Version: 1.1 +[=] Storage size: 0x00 ( 1 bytes ) +[=] Protocol: 0x01 ( Unknown ) + +[=] --------------------------------- Card capabilities --------------------------------- +[#] switch_off + +[usb] pm3 --> hf mfdes auth -n 0 -t 3tdea -k 000000000000000000000000000000000000000000000000 -v -c native -a +[=] Key num: 0 Key algo: 3tdea Key[24]: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[=] Secure channel: n/a Command set: native Communication mode: plain +[+] Setting ISODEP -> inactive +[+] Setting ISODEP -> NFC-A +[=] AID 000000 is selected +[=] Auth: cmd: 0x1a keynum: 0x00 +[+] raw>> 1A 00 +[+] raw<< AF EE 91 30 1E E8 F5 84 D6 C7 85 1D 05 65 13 90 A6 C6 D5 +[#] encRndB: EE 91 30 1E E8 F5 84 D6 +[#] RndB: CA FE BA BE 00 11 22 33 +[#] rotRndB: FE BA BE 00 11 22 33 CA FE BA BE 00 11 22 33 CA +[#] Both : 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 FE BA BE 00 11 22 33 CA FE BA BE 00 11 22 33 CA +[+] raw>> AF 30 EB 55 F3 29 39 04 96 77 88 CE EF 33 A3 C8 7B 18 66 1A F1 62 78 A0 28 53 84 67 98 7C BB DB 03 +[+] raw<< 00 9B 71 57 8F FB DF 80 A8 F6 EF 33 4A C6 CD F9 7A 7D BE +[=] Session key : 01 02 03 04 CA FE BA BE 07 08 09 10 22 33 CA FE 13 14 15 16 00 11 22 33 +[=] Desfire authenticated +[+] PICC selected and authenticated succesfully +[+] Context: +[=] Key num: 0 Key algo: 3tdea Key[24]: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[=] Secure channel: ev1 Command set: native Communication mode: plain +[=] Session key [24]: 01 02 03 04 CA FE BA BE 07 08 09 10 22 33 CA FE 13 14 15 16 00 11 22 33 +[=] IV [8]: 00 00 00 00 00 00 00 00 +[+] Setting ISODEP -> inactive ``` +The DESFire configuration mode has been known to see recognition problems +using the ``libfreefare`` commands ``mifare-*``. This issue may be gradually +resolved as the work to bring compatibility with the PM3 devices continues. -* Handle how to write values directly to value files (without credit/debit type actions)? -* WriteRecordFile only handles/reads off continued chunks in round block sizes. -* **BIG Q:** Does calling ``MemoryStore()`` to frequently cause problems? This should be rare-ish when - data on the tag changes? -* Have an action where a (long) push of a button allows for - 1. A dump of the stored internal logging data to get written LIVE-style to the serial USB - 2. A dump of the pretty-printed DESFire tag layout to get written to the serial USB -* Store some compile-time randomized system bits (from openssl) to get stored to a special - small enough segment within the EEPROM for reference (sort of like a secret UID data, or even - unique serial number that should get reprogrammed everytime the firmware is re-compiled ... - 1. ``#define EEPROM_ATTR __attribute__ ((section (".eeprom")))`` +## Quick configuration of cloned DESFire tags ### Chameleon Mini terminal addons to support ``CONFIG=MF_DESFIRE`` modes @@ -179,30 +146,187 @@ CONFIG=MF_DESFIRE #### DF_SETHDR -- Set PICC header information -Since the UID and other precious manufacturer data are supposed to be unique to -tags and sacred ground upon which only manufacturers shall walk, we are going to upheave -this notion and hack our tag "roll your own" (tag) style. This means we can pick and -choose the components used to identify the tag by calling a few Chameleon terminal -command variants. The syntax is varied -- the numbers after the parameter name are -indicators for the number of bytes to include as arguments: +The UID for the tag can be set using separate Chameleon terminal commands as +usual for all other configurations. ```bash DF_SETHDR? 101:OK WITH TEXT -DF_SETHDR +DF_SETHDR ``` -Likewise, as promised, we can modify the tag header information emulated by the tag as follows: +We can modify the tag header information emulated by the tag as follows: ```bash DF_SETHDR=ATS xxxxxxxxxx -DF_SETHDR=HardwareVersion xxxx -DF_SETHDR=SoftwareVersion xxxx +DF_SETHDR=ManuID xx +DF_SETHDR=HardwareVersion mmMM +DF_SETHDR=SoftwareVersion mmMM DF_SETHDR=BatchNumber xxxxxxxxxx -DF_SETHDR=ProductionDate xxxx +DF_SETHDR=ProductionDate WWYY ``` -For example, to set the ATS bytes reported to emulate a JCOP tag: + +##### Examples: + +The default ATS bytes for a DESFire tag are the same as specifying: +```bash +DF_SETHDR=ATS 067577810280 +``` +To set the ATS bytes reported to emulate a JCOP tag: ```bash DF_SETHDR=ATS 0675f7b102 ``` -Note that the UID for the tag can be set using separate Chameleon terminal commands. + +##### Documentation for cloning specific tag types + +```cpp +/* Other HW product types for DESFire tags: See page 7 of + * https://www.nxp.com/docs/en/application-note/AN12343.pdf + */ +// typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { +// NATIVEIC_PHYS_CARD = 0x01, +// LIGHT_NATIVEIC_PHYS_CARD = 0x08, +// MICROCONTROLLER_PHYS_CARDI = 0x81, +// MICROCONTROLLER_PHYS_CARDII = 0x83, +// JAVACARD_SECURE_ELEMENT_PHYS_CARD = 0x91, +// HCE_MIFARE_2GO = 0xa1, +// } DESFireHWProductCodes; +``` +An up-to-date listing of bytes that indicate the tag manufacturer ID is +found in the [Proxmark3 client source](https://github.com/RfidResearchGroup/proxmark3/blob/65b9a9fb769541f5d3e255ccf2c17d1cb77ac126/client/src/cmdhf14a.c#L48): +```cpp +static const manufactureName_t manufactureMapping[] = { + // ID, "Vendor Country" + { 0x01, "Motorola UK" }, + { 0x02, "ST Microelectronics SA France" }, + { 0x03, "Hitachi, Ltd Japan" }, + { 0x04, "NXP Semiconductors Germany" }, + { 0x05, "Infineon Technologies AG Germany" }, + { 0x06, "Cylink USA" }, + { 0x07, "Texas Instrument France" }, + { 0x08, "Fujitsu Limited Japan" }, + { 0x09, "Matsushita Electronics Corporation, Semiconductor Company Japan" }, + { 0x0A, "NEC Japan" }, + { 0x0B, "Oki Electric Industry Co. Ltd Japan" }, + { 0x0C, "Toshiba Corp. Japan" }, + { 0x0D, "Mitsubishi Electric Corp. Japan" }, + { 0x0E, "Samsung Electronics Co. Ltd Korea" }, + { 0x0F, "Hynix / Hyundai, Korea" }, + { 0x10, "LG-Semiconductors Co. Ltd Korea" }, + { 0x11, "Emosyn-EM Microelectronics USA" }, + { 0x12, "INSIDE Technology France" }, + { 0x13, "ORGA Kartensysteme GmbH Germany" }, + { 0x14, "SHARP Corporation Japan" }, + { 0x15, "ATMEL France" }, + { 0x16, "EM Microelectronic-Marin SA Switzerland" }, + { 0x17, "KSW Microtec GmbH Germany" }, + { 0x18, "ZMD AG Germany" }, + { 0x19, "XICOR, Inc. USA" }, + { 0x1A, "Sony Corporation Japan" }, + { 0x1B, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" }, + { 0x1C, "Emosyn USA" }, + { 0x1D, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" }, + { 0x1E, "Magellan Technology Pty Limited Australia" }, + { 0x1F, "Melexis NV BO Switzerland" }, + { 0x20, "Renesas Technology Corp. Japan" }, + { 0x21, "TAGSYS France" }, + { 0x22, "Transcore USA" }, + { 0x23, "Shanghai belling corp., ltd. China" }, + { 0x24, "Masktech Germany Gmbh Germany" }, + { 0x25, "Innovision Research and Technology Plc UK" }, + { 0x26, "Hitachi ULSI Systems Co., Ltd. Japan" }, + { 0x27, "Cypak AB Sweden" }, + { 0x28, "Ricoh Japan" }, + { 0x29, "ASK France" }, + { 0x2A, "Unicore Microsystems, LLC Russian Federation" }, + { 0x2B, "Dallas Semiconductor/Maxim USA" }, + { 0x2C, "Impinj, Inc. USA" }, + { 0x2D, "RightPlug Alliance USA" }, + { 0x2E, "Broadcom Corporation USA" }, + { 0x2F, "MStar Semiconductor, Inc Taiwan, ROC" }, + { 0x30, "BeeDar Technology Inc. USA" }, + { 0x31, "RFIDsec Denmark" }, + { 0x32, "Schweizer Electronic AG Germany" }, + { 0x33, "AMIC Technology Corp Taiwan" }, + { 0x34, "Mikron JSC Russia" }, + { 0x35, "Fraunhofer Institute for Photonic Microsystems Germany" }, + { 0x36, "IDS Microchip AG Switzerland" }, + { 0x37, "Thinfilm - Kovio USA" }, + { 0x38, "HMT Microelectronic Ltd Switzerland" }, + { 0x39, "Silicon Craft Technology Thailand" }, + { 0x3A, "Advanced Film Device Inc. Japan" }, + { 0x3B, "Nitecrest Ltd UK" }, + { 0x3C, "Verayo Inc. USA" }, + { 0x3D, "HID Global USA" }, + { 0x3E, "Productivity Engineering Gmbh Germany" }, + { 0x3F, "Austriamicrosystems AG (reserved) Austria" }, + { 0x40, "Gemalto SA France" }, + { 0x41, "Renesas Electronics Corporation Japan" }, + { 0x42, "3Alogics Inc Korea" }, + { 0x43, "Top TroniQ Asia Limited Hong Kong" }, + { 0x44, "Gentag Inc. USA" }, + { 0x45, "Invengo Information Technology Co.Ltd China" }, + { 0x46, "Guangzhou Sysur Microelectronics, Inc China" }, + { 0x47, "CEITEC S.A. Brazil" }, + { 0x48, "Shanghai Quanray Electronics Co. Ltd. China" }, + { 0x49, "MediaTek Inc Taiwan" }, + { 0x4A, "Angstrem PJSC Russia" }, + { 0x4B, "Celisic Semiconductor (Hong Kong) Limited China" }, + { 0x4C, "LEGIC Identsystems AG Switzerland" }, + { 0x4D, "Balluff GmbH Germany" }, + { 0x4E, "Oberthur Technologies France" }, + { 0x4F, "Silterra Malaysia Sdn. Bhd. Malaysia" }, + { 0x50, "DELTA Danish Electronics, Light & Acoustics Denmark" }, + { 0x51, "Giesecke & Devrient GmbH Germany" }, + { 0x52, "Shenzhen China Vision Microelectronics Co., Ltd. China" }, + { 0x53, "Shanghai Feiju Microelectronics Co. Ltd. China" }, + { 0x54, "Intel Corporation USA" }, + { 0x55, "Microsensys GmbH Germany" }, + { 0x56, "Sonix Technology Co., Ltd. Taiwan" }, + { 0x57, "Qualcomm Technologies Inc USA" }, + { 0x58, "Realtek Semiconductor Corp Taiwan" }, + { 0x59, "Freevision Technologies Co. Ltd China" }, + { 0x5A, "Giantec Semiconductor Inc. China" }, + { 0x5B, "JSC Angstrem-T Russia" }, + { 0x5C, "STARCHIP France" }, + { 0x5D, "SPIRTECH France" }, + { 0x5E, "GANTNER Electronic GmbH Austria" }, + { 0x5F, "Nordic Semiconductor Norway" }, + { 0x60, "Verisiti Inc USA" }, + { 0x61, "Wearlinks Technology Inc. China" }, + { 0x62, "Userstar Information Systems Co., Ltd Taiwan" }, + { 0x63, "Pragmatic Printing Ltd. UK" }, + { 0x64, "Associacao do Laboratorio de Sistemas Integraveis Tecnologico - LSI-TEC Brazil" }, + { 0x65, "Tendyron Corporation China" }, + { 0x66, "MUTO Smart Co., Ltd. Korea" }, + { 0x67, "ON Semiconductor USA" }, + { 0x68, "TUBITAK BILGEM Turkey" }, + { 0x69, "Huada Semiconductor Co., Ltd China" }, + { 0x6A, "SEVENEY France" }, + { 0x6B, "ISSM France" }, + { 0x6C, "Wisesec Ltd Israel" }, + { 0x7C, "DB HiTek Co Ltd Korea" }, + { 0x7D, "SATO Vicinity Australia" }, + { 0x7E, "Holtek Taiwan" }, + { 0x00, "no tag-info available" } // must be the last entry +}; +``` +Similarly, the PM3 source maintains the authoritative way to +fingerprint the DESFire tag subtype in the +[client source files](https://github.com/RfidResearchGroup/proxmark3/blob/65b9a9fb769541f5d3e255ccf2c17d1cb77ac126/client/src/cmdhfmfp.c#L92): +```cpp + if (major == 0x00) + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire MF3ICD40") ")", major, minor); + else if (major == 0x01 && minor == 0x00) + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV1") ")", major, minor); + else if (major == 0x12 && minor == 0x00) + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV2") ")", major, minor); + else if (major == 0x33 && minor == 0x00) + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV3") ")", major, minor); + else if (major == 0x30 && minor == 0x00) + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire Light") ")", major, minor); + else if (major == 0x11 && minor == 0x00) + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("Plus EV1") ")", major, minor); + else + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("Unknown") ")", major, minor); +``` #### DF_COMM_MODE -- Manually sets the communication mode of the current session @@ -251,6 +375,68 @@ DF_COMM_MODE? DF_COMM_MODE= ``` +## Supported functionality + +### Tables of tested support for active commands + +#### Native DESFire command support (mixed EV0/EV1/EV2 instruction sets) + +| Instruction | Cmd Byte | Description | Testing Status | Implementation Notes | +| :--- | :----: | :----: | :----: | :-- | +| CMD_AUTHENTICATE | 0x0A | Authenticate legacy | :ballot_box_with_check: | Works with the ``-DDESFIRE_QUICK_DES_CRYPTO`` Makefile ``SETTINGS`` compiler flag set to enable "quicker" DES crypto. | +| CMD_AUTHENTICATE_ISO | 0x1A | ISO / 3DES auth | :question: | This implementation is too slow! Need hardware support for 3DES crypto? | +| CMD_AUTHENTICATE_AES | 0xAA | Standard AES auth | :ballot_box_with_check: | | +| CMD_AUTHENTICATE_EV2_FIRST | 0x71 | Newer spec auth variant | :x: | | +| CMD_AUTHENTICATE_EV2_NONFIRST | 0x77 | Newer spec auth variant | :x: | See page 32 of AN12343.pdf | +| CMD_CHANGE_KEY_SETTINGS | 0x54 | | :ballot_box_with_check: | | +| CMD_SET_CONFIGURATION | 0x5C | | :x: | | +| CMD_CHANGE_KEY | 0xC4 | | :ballot_box_with_check: | | +| CMD_GET_KEY_VERSION | 0x64 | | :ballot_box_with_check: | | +| CMD_CREATE_APPLICATION | 0xCA | | :ballot_box_with_check: | | +| CMD_DELETE_APPLICATION | 0xDA | | :ballot_box_with_check: | | +| CMD_GET_APPLICATION_IDS | 0x6A | | :ballot_box_with_check: | | +| CMD_FREE_MEMORY | 0x6E | | :ballot_box_with_check: | | +| CMD_GET_DF_NAMES | 0x6D | | :x: | =Need docs for what this command does! | +| CMD_GET_KEY_SETTINGS | 0x45 | | :ballot_box_with_check: | | +| CMD_SELECT_APPLICATION | 0x5A | | :ballot_box_with_check: | | +| CMD_FORMAT_PICC | 0xFC | | :ballot_box_with_check: | | +| CMD_GET_VERSION | 0x60 | | :ballot_box_with_check: | | +| CMD_GET_CARD_UID | 0x51 | | :ballot_box_with_check: | | +| CMD_GET_FILE_IDS | 0x6F | | :ballot_box_with_check: | | +| CMD_GET_FILE_SETTINGS | 0xF5 | | :ballot_box_with_check: | | +| CMD_CHANGE_FILE_SETTINGS | 0x5F | | :x: | | +| CMD_CREATE_STDDATA_FILE | 0xCD | | :ballot_box_with_check: | | +| CMD_CREATE_BACKUPDATA_FILE | 0xCB | | :ballot_box_with_check: | | +| CMD_CREATE_VALUE_FILE | 0xCC | | :ballot_box_with_check: | | +| CMD_CREATE_LINEAR_RECORD_FILE | 0xC1 | | :wavy_dash: | GetFileSettings still not returning correct data | +| CMD_CREATE_CYCLIC_RECORD_FILE | 0xC0 | | :wavy_dash: | GetFileSettings still not returning correct data | +| CMD_DELETE_FILE | 0xDF | | :ballot_box_with_check: | | +| CMD_GET_ISO_FILE_IDS | 0x61 | | :x: | | +| CMD_READ_DATA | 0xBD | | :ballot_box_with_check: | The data for std/backup files is uninitialized (any bits) until the user sets the data with WriteData | +| CMD_WRITE_DATA | 0x3D | | :ballot_box_with_check: | Only supports write command operations with <= 52 bytes of data at a time. Offset parameters can be used to write lengthier files. | +| CMD_GET_VALUE | 0x6C | | :ballot_box_with_check: | | +| CMD_CREDIT | 0x0C | | :ballot_box_with_check: | | +| CMD_DEBIT | 0xDC | | :ballot_box_with_check: | | +| CMD_LIMITED_CREDIT | 0x1C | | :ballot_box_with_check: | | +| CMD_WRITE_RECORD | 0x3B | | :question: | | +| CMD_READ_RECORDS | 0xBB | | :ballot_box_with_check: :wavy_dash: | | +| CMD_CLEAR_RECORD_FILE | 0xEB | | :question: | | +| CMD_COMMIT_TRANSACTION | 0xC7 | | :ballot_box_with_check: | | +| CMD_ABORT_TRANSACTION | 0xA7 | | :ballot_box_with_check: | | | + +#### ISO7816 command support + +| Instruction | Cmd Byte | Description | Testing Status | Implementation Notes | +| :--- | :----: | :----: | :----: | :-- | +| CMD_ISO7816_SELECT | 0xa4 | A more nuanced ISO7816 version of EF/DF selection. | :wavy_dash: :question: | See the implementation notes [in this spec](https://cardwerk.com/smart-card-standard-iso7816-4-section-6-basic-interindustry-commands/#chap6_11). We only support EF selection with ``P1=00000000|000000010`` and DF(AID) with ``P1=00000100``. | +| CMD_ISO7816_GET_CHALLENGE | 0x84 | | :wavy_dash: :question: | | +| CMD_ISO7816_EXTERNAL_AUTHENTICATE | 0x82 | | :x: | | +| CMD_ISO7816_INTERNAL_AUTHENTICATE | 0x88 | | :x: | | +| CMD_ISO7816_READ_BINARY | 0xb0 | | :wavy_dash: :question: | Needs testing. | +| CMD_ISO7816_UPDATE_BINARY | 0xd6 | | :wavy_dash: :question: | Needs testing. | +| CMD_ISO7816_READ_RECORDS | 0xb2 | | :wavy_dash: :question: | Needs testing. | +| CMD_ISO7816_APPEND_RECORD | 0xe2 | | :wavy_dash: :question: | Especially needs testing for corner case checks. | + ### Links to public datasheets and online specs The following links are the original online resource links are @@ -260,187 +446,11 @@ archived here for documentation on how this firmware operates: * [NXP Application Note AN12343](https://www.nxp.com/docs/en/application-note/AN12343.pdf) * [TI DESFire EV1 Tag AES Auth Specs (sloa213.pdf)](https://www.ti.com/lit/an/sloa213/sloa213.pdf) * [NXP Application Note AN10833](https://www.nxp.com/docs/en/application-note/AN10833.pdf) - -### Makefile support to enable special functionality - -```make -#Whether or not to customize the USB identifier settings in the firmware: -SETTINGS += -DENABLE_LUFAUSB_CUSTOM_VERSIONS - -#Whether or not to allow users Chameleon terminal access to change the DESFire configuration's -#sensitive settings like manufacturer, serial number, etc. -SETTINGS += -DENABLE_PERMISSIVE_DESFIRE_SETTINGS -SETTINGS += -DALLOW_DESFIRE_TERMINAL_COMMANDS - -#Set a default logging mode for debugging with the DESFire -#emulation code: -SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING -#SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF - -#Set a default testing mode setting (0 = OFF, non-NULL = ON): -SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 - -#Feature: Use randomized UIDs that mask the actual secret UID until -#the tag has been issued a successful authentication sequence: -SETTINGS += -DDESFIRE_RANDOMIZE_UIDS_PREAUTH - -#Anticipating that the implementation overhead is high with the -#maximum storage allocations for the number of possible keys per -#application directory, and/or the total number of AID numbered -#directory slots, the following options will tweak this limitation: -# -> Set DESFIRE_MEMORY_LIMITED_TESTING to shrink the defaults -# -> Or explicitly define DESFIRE_CUSTOM_MAX_KEYS=##UINT## (per AID), -# -> And/Or define DESFIRE_CUSTOM_MAX_APPS=##UINT## -# (total number of AID spaces available, not including the master 0x00) -SETTINGS += -DDESFIRE_MEMORY_LIMITED_TESTING -#SETTINGS += -DDESFIRE_CUSTOM_MAX_APPS=8 -#SETTINGS += -DDESFIRE_CUSTOM_MAX_KEYS=6 -#SETTINGS += -DDESFIRE_CUSTOM_MAX_FILES=6 -#SETTINGS += -DDESFIRE_USE_FACTORY_SIZES -#SETTINGS += -DDESFIRE_MAXIMIZE_SIZES_FOR_STORAGE - -#Set a minimum incoming/outgoing log size so we do not spam the -#Chameleon Mini logs to much by logging everything: -SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=0 -SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 - -#Enable printing of crypto tests when a new DESFire emulation instance is started: -#SETTINGS += -DDESFIRE_RUN_CRYPTO_TESTING_PROCEDURE - -#Option to save space with the "Application/Crypto1.c" code by storing large tables -#in PROGMEM. Note that this will slow down the read times when accessing these tables: -SETTINGS += -DDESFIRE_CRYPTO1_SAVE_SPACE -``` - -### Hacking the source - -For Chameleon firmware hackers and prospective modders that want to hack on and improve the DESFire -emulation support sources, the next points are helpful to understanding the local details of -how data storage is handled, and other implementation notes that should save you some time. -:smile: - -#### Description of the FRAM storage scheme of the DESFire tag data and file system - -The scheme involves nested or linked pointers to data stored in FRAM. The following -source code snippets are useful to understanding how to load and process this storage: -```cpp -typedef struct DESFIRE_FIRMWARE_PACKING { - /* Static data: does not change during the PICC's lifetime. - * We will add Chameleon Mini terminal commands to enable - * resetting this data so tags can be emulated authentically. - * This structure is stored verbatim (using memcpy) at the - * start of the FRAM setting space for the configuration. - */ - uint8_t Uid[DESFIRE_UID_SIZE] DESFIRE_FIRMWARE_ALIGNAT; - uint8_t StorageSize; - uint8_t HwVersionMajor; - uint8_t HwVersionMinor; - uint8_t SwVersionMajor; - uint8_t SwVersionMinor; - uint8_t BatchNumber[5] DESFIRE_FIRMWARE_ALIGNAT; - uint8_t ProductionWeek; - uint8_t ProductionYear; - uint8_t ATSBytes[5]; - /* Dynamic data: changes during the PICC's lifetime */ - uint16_t FirstFreeBlock; - uint8_t TransactionStarted; // USED ??? - uint8_t Spare[9] DESFIRE_FIRMWARE_ALIGNAT; // USED ??? -} DESFirePICCInfoType; - -typedef struct DESFIRE_FIRMWARE_PACKING { - BYTE Slot; - BYTE KeyCount; - BYTE MaxKeyCount; - BYTE FileCount; - BYTE CryptoCommStandard; - SIZET KeySettings; /* Block offset in FRAM */ - SIZET FileNumbersArrayMap; /* Block offset in FRAM */ - SIZET FileCommSettings; /* Block offset in FRAM */ - SIZET FileAccessRights; /* Block offset in FRAM */ - SIZET FilesAddress; /* Block offset in FRAM */ - SIZET KeyVersionsArray; /* Block offset in FRAM */ - SIZET KeyTypesArray; /* Block offset in FRAM */ - SIZET KeyAddress; /* Block offset in FRAM */ - UINT DirtyFlags; // USED ??? -} SelectedAppCacheType; - -BYTE SELECTED_APP_CACHE_TYPE_BLOCK_SIZE = DESFIRE_BYTES_TO_BLOCKS(sizeof(SelectedAppCacheType)); -BYTE APP_CACHE_KEY_SETTINGS_ARRAY_BLOCK_SIZE = DESFIRE_BYTES_TO_BLOCKS(DESFIRE_MAX_KEYS); -BYTE APP_CACHE_FILE_NUMBERS_HASHMAP_BLOCK_SIZE = DESFIRE_BYTES_TO_BLOCKS(DESFIRE_MAX_FILES); -BYTE APP_CACHE_FILE_COMM_SETTINGS_ARRAY_BLOCK_SIZE = DESFIRE_BYTES_TO_BLOCKS(DESFIRE_MAX_FILES); -BYTE APP_CACHE_FILE_ACCESS_RIGHTS_ARRAY_BLOCK_SIZE = DESFIRE_BYTES_TO_BLOCKS(DESFIRE_MAX_FILES); -BYTE APP_CACHE_KEY_VERSIONS_ARRAY_BLOCK_SIZE = DESFIRE_BYTES_TO_BLOCKS(DESFIRE_MAX_KEYS); -BYTE APP_CACHE_KEY_TYPES_ARRAY_BLOCK_SIZE = DESFIRE_BYTES_TO_BLOCKS(DESFIRE_MAX_KEYS); -BYTE APP_CACHE_KEY_BLOCKIDS_ARRAY_BLOCK_SIZE = DESFIRE_BYTES_TO_BLOCKS(2 * DESFIRE_MAX_KEYS); -BYTE APP_CACHE_FILE_BLOCKIDS_ARRAY_BLOCK_SIZE = DESFIRE_BYTES_TO_BLOCKS(2 * DESFIRE_MAX_KEYS); -BYTE APP_CACHE_MAX_KEY_BLOCK_SIZE = DESFIRE_BYTES_TO_BLOCKS(CRYPTO_MAX_KEY_SIZE); - -/* - * Defines the application directory contents. - * The application directory maps AIDs to application slots: - * the AID's index in `AppIds` is the slot number. - * - * This is the "global" structure that gets stored in the header - * data for the directory. To see the actual byte-for-byte storage - * of the accounting data for each instantiated AID slot, refer to the - * `DesfireApplicationDataType` structure from above. - */ -typedef struct DESFIRE_FIRMWARE_PACKING { - BYTE FirstFreeSlot; - DESFireAidType AppIds[DESFIRE_MAX_SLOTS] DESFIRE_FIRMWARE_ARRAY_ALIGNAT; - SIZET AppCacheStructBlockOffset[DESFIRE_MAX_SLOTS]; -} DESFireAppDirType; - -void InitBlockSizes(void) { - DESFIRE_PICC_INFO_BLOCK_ID = 0; - DESFIRE_APP_DIR_BLOCK_ID = DESFIRE_PICC_INFO_BLOCK_ID + - DESFIRE_BYTES_TO_BLOCKS(sizeof(DESFirePICCInfoType)); - DESFIRE_APP_CACHE_DATA_ARRAY_BLOCK_ID = DESFIRE_APP_DIR_BLOCK_ID + - DESFIRE_BYTES_TO_BLOCKS(sizeof(DESFireAppDirType)); - DESFIRE_FIRST_FREE_BLOCK_ID = DESFIRE_APP_CACHE_DATA_ARRAY_BLOCK_ID; - DESFIRE_INITIAL_FIRST_FREE_BLOCK_ID = DESFIRE_FIRST_FREE_BLOCK_ID; -} - -/* Data about an application's file is currently kept in this structure. - * The location of these structures is defined by the file index. - */ -typedef struct DESFIRE_FIRMWARE_PACKING { - uint8_t FileType; - uint8_t FileNumber; - uint16_t FileSize; - uint16_t FileDataAddress; /* FRAM address of the storage of the data for the file */ - union DESFIRE_FIRMWARE_ALIGNAT { - struct DESFIRE_FIRMWARE_ALIGNAT { - uint16_t FileSize; - } StandardFile; - struct DESFIRE_FIRMWARE_ALIGNAT { - uint16_t FileSize; - uint8_t BlockCount; - } BackupFile; - struct DESFIRE_FIRMWARE_ALIGNAT { - int32_t CleanValue; - int32_t DirtyValue; - int32_t LowerLimit; - int32_t UpperLimit; - uint8_t LimitedCreditEnabled; - int32_t PreviousDebit; - } ValueFile; - struct DESFIRE_FIRMWARE_ALIGNAT { - uint16_t BlockCount; - uint16_t RecordPointer; - //uint8_t ClearPending; // USED ??? - uint8_t RecordSize[3]; - uint8_t CurrentNumRecords[3]; - uint8_t MaxRecordCount[3]; - } RecordFile; - }; -} DESFireFileTypeSettings; - -typedef struct DESFIRE_FIRMWARE_PACKING { - BYTE Num; - DESFireFileTypeSettings File; -} SelectedFileCacheType; -``` +* My favorite conference submission in grad school is (by far) about this project -- even though I did not present my talk that year. + In rare form, the [presentation slides (tentative; see uploads)](https://archive.org/details/@maxiedschmidt) and the + [accepted manuscript](https://archive.org/download/ftc2021-presentation-slides-with-notes/schmidt-ftc2021-submission.pdf) (published in print form by Springer) + effectively document the scarce details of the DESFire spec and command sets gleaned while working on this project as a conference proceedings article. + Grace Hopper would have approved :) ## Credits @@ -451,7 +461,9 @@ for development of this project: * Professor [Josephine Yu](http://people.math.gatech.edu/~jyu67/) and the [School of Mathematics](https://math.gatech.edu) at the Georgia Institute of Technology for allowing me to work on this as a secondary - project as a Ph.D. candidate over the Summer and Fall of 2020. + project as a Ph.D. candidate over the Summer and Fall of 2020. +* More work to improve and add compatibility with the PM3 devices over the Spring of 2022 was supported by + Georgia Tech to work as a RA through the university COVID-19 relief funding. * The [KAOS manufacturers](https://shop.kasper.it) for providing support in the form of discounted Chameleon RevG devices to support my active development on the project. diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c index 24f824aa..dad96169 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c @@ -71,39 +71,45 @@ CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutParam, const char * dataByteCount = HexStringToBuffer(propSpecBytes, 16, propSpecBytesStr); if (!strcasecmp_P(hdrPropSpecStr, PSTR("ATS"))) { if (dataByteCount != 5) { - StatusError = 0x01; + StatusError = 1; } else { memcpy(&Picc.ATSBytes[0], propSpecBytes, dataByteCount); } + } else if (!strcasecmp_P(hdrPropSpecStr, PSTR("ManuID"))) { + if (dataByteCount != 1) { + StatusError = 1; + } else { + Picc.ManufacturerID = propSpecBytes[0]; + } } else if (!strcasecmp_P(hdrPropSpecStr, PSTR("HardwareVersion"))) { if (dataByteCount != 2) { - StatusError = 0x01; + StatusError = 1; } else { Picc.HwVersionMajor = propSpecBytes[0]; Picc.HwVersionMinor = propSpecBytes[1]; } } else if (!strcasecmp_P(hdrPropSpecStr, PSTR("SoftwareVersion"))) { if (dataByteCount != 2) { - StatusError = 0x01; + StatusError = 1; } else { Picc.SwVersionMajor = propSpecBytes[0]; Picc.SwVersionMinor = propSpecBytes[1]; } } else if (!strcasecmp_P(hdrPropSpecStr, PSTR("BatchNumber"))) { if (dataByteCount != 5) { - StatusError = 0x01; + StatusError = 1; } else { memcpy(Picc.BatchNumber, propSpecBytes, 5); } } else if (!strcasecmp_P(hdrPropSpecStr, PSTR("ProductionDate"))) { if (dataByteCount != 2) { - StatusError = 0x01; + StatusError = 1; } else { Picc.ProductionWeek = propSpecBytes[0]; Picc.ProductionYear = propSpecBytes[1]; } } else { - StatusError = 0x01; + StatusError = 1; } if (StatusError) { CommandDESFireGetHeaderProperty(OutParam); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index 40ca6ae1..246dbab2 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -78,6 +78,7 @@ void ISO144434Reset(void) { Iso144434State = ISO14443_4_STATE_EXPECT_RATS; Iso144434BlockNumber = 1; ISO14443ALastDataFrameBits = 0; + LastReaderSentCmd = 0x00; } static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount) { @@ -100,9 +101,9 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 if (!ISO14443ACheckCRCA(Buffer, ByteCount)) { LogEntry(LOG_ERR_APP_CHECKSUM_FAIL, Buffer, ByteCount); /* ISO/IEC 14443-4, clause 7.5.5. The PICC does not attempt any error recovery. */ - const char *debugPrintStr = PSTR("ISO14443-4: CRC fail; %04X vs %04X"); + const char *debugPrintStr = PSTR("WARN: 14443-4: CRC fail; %04X vs %04X"); DEBUG_PRINT_P(debugPrintStr, *(uint16_t *)&Buffer[ByteCount], - ISO14443AUpdateCRCA(Buffer, ByteCount, 0x00)); + ISO14443AAppendCRCA(Buffer, ByteCount)); return ISO14443A_APP_NO_RESPONSE; } @@ -127,7 +128,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 ISO144434SwitchState(ISO14443_4_STATE_ACTIVE); const char *debugPrintStr = PSTR("ISO14443-4: SEND RATS"); LogDebuggingMsg(debugPrintStr); - return ByteCount * BITS_PER_BYTE; // PM3 expects no CRCA bytes + return ASBITS(ByteCount); // PM3 expects no CRCA bytes } case ISO14443_4_STATE_ACTIVE: { /* See: ISO/IEC 14443-4; 7.1 Block format */ @@ -210,7 +211,6 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 /* 7.5.4.3, rule 12 */ /* This is a NAK. Send an ACK back */ Buffer[0] = ISO14443_PCB_R_BLOCK_STATIC | ISO14443_PCB_R_BLOCK_ACK | MyBlockNumber; - //ByteCount = 1; // Per the NXP data sheet MF1S50YYX_V1 (Table 10: ACK / NAK), we should return 4 bits: return 4; } else { @@ -220,7 +220,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 DEBUG_PRINT_P(debugPrintStr, __LINE__); // Resend the data from the last frame: if (ISO14443ALastDataFrameBits > 0) { - memcpy(&Buffer[0], &ISO14443ALastDataFrame[0], (ISO14443ALastDataFrameBits + BITS_PER_BYTE - 1) / BITS_PER_BYTE); + memcpy(&Buffer[0], &ISO14443ALastDataFrame[0], ASBYTES(ISO14443ALastDataFrameBits)); return ISO14443ALastDataFrameBits; } else { return ISO14443A_APP_NO_RESPONSE; @@ -249,6 +249,9 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 return ISO14443A_APP_NO_RESPONSE; } + default: + break; + } /* Fall through (default handling when there is no response to register/return to the sender): */ @@ -296,15 +299,17 @@ void ISO144433AHalt(void) { } bool ISO144433AIsHalt(const uint8_t *Buffer, uint16_t BitCount) { - return BitCount == ISO14443A_HLTA_FRAME_SIZE + ISO14443A_CRCA_SIZE * BITS_PER_BYTE + return BitCount == ISO14443A_HLTA_FRAME_SIZE + ASBITS(ISO14443A_CRCA_SIZE) && Buffer[0] == ISO14443A_CMD_HLTA && Buffer[1] == 0x00 - && ISO14443ACheckCRCA(Buffer, (ISO14443A_HLTA_FRAME_SIZE + BITS_PER_BYTE - 1) / BITS_PER_BYTE); + && ISO14443ACheckCRCA(Buffer, ASBYTES(ISO14443A_HLTA_FRAME_SIZE)); } uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { if (BitCount == 0) { + ISO144434Reset(); + ISO144433AHalt(); return ISO14443A_APP_NO_RESPONSE; } @@ -324,12 +329,10 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { incrementRetryCount = false; } else if (ISO144433AIsHalt(Buffer, BitCount)) { LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); - ISO144433ASwitchState(ISO14443_3A_STATE_HALT); - LastReaderSentCmd = Cmd; - CheckStateRetryCount(true); - ISO144434Reset(); const char *logMsg = PSTR("ISO14443-3: HALTING"); LogDebuggingMsg(logMsg); + ISO144434Reset(); + ISO144433AHalt(); return ISO14443A_APP_NO_RESPONSE; } LastReaderSentCmd = Cmd; @@ -357,7 +360,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[1] = (ATQA_VALUE >> 8) & 0x00FF; const char *debugPrintStr = PSTR("ISO14443-4 (IDLE): ATQA"); LogDebuggingMsg(debugPrintStr); - return ISO14443A_ATQA_FRAME_SIZE_BYTES * BITS_PER_BYTE; + return ASBITS(ISO14443A_ATQA_FRAME_SIZE_BYTES); case ISO14443_3A_STATE_READY1: if (Cmd == ISO14443A_CMD_SELECT_CL1) { @@ -425,7 +428,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { return ISO14443A_SAK_FRAME_SIZE; } /* Forward to ISO/IEC 14443-4 processing code */ - uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + uint16_t ByteCount = ASBYTES(BitCount); uint16_t ReturnBits = ISO144434ProcessBlock(Buffer, ByteCount, BitCount); const char *debugPrintStr2 = PSTR("ISO14443-4: ACTIVE RET"); LogDebuggingMsg(debugPrintStr2); @@ -437,7 +440,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { } /* Unknown command. Reset back to idle/halt state. */ - bool defaultReset = false; //Iso144433AState != ISO14443_3A_STATE_IDLE; + bool defaultReset = false; if (!CheckStateRetryCount(defaultReset)) { const char *logMsg = PSTR("ISO14443-3: RESET TO IDLE 0x%02x"); DEBUG_PRINT_P(logMsg, Cmd); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index 694b983f..06ae029b 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -28,6 +28,7 @@ This notice must be retained at the top of all source files where indicated. #define __DESFIRE_ISO14443_SUPPORT_H__ #include "DESFireFirmwareSettings.h" +#include "DESFireUtils.h" #include "../ISO14443-3A.h" #include "../../Codec/ISO14443-2A.h" @@ -41,9 +42,9 @@ This notice must be retained at the top of all source files where indicated. */ #define ISO14443A_CMD_RATS 0xE0 -#define ISO14443A_RATS_FRAME_SIZE (6 * BITS_PER_BYTE) /* Bit */ +#define ISO14443A_RATS_FRAME_SIZE ASBITS(6) /* Bit */ #define ISO14443A_CMD_RNAK 0xB2 -#define ISO14443A_CRC_FRAME_SIZE (ISO14443A_CRCA_SIZE * BITS_PER_BYTE) +#define ISO14443A_CRC_FRAME_SIZE ASBITS(ISO14443A_CRCA_SIZE) #define ISO14443ACmdIsPM3WUPA(cmd) ((cmd & 0x54) == 0x54) #define ISO14443ACmdIsWUPA(cmd) ((cmd == ISO14443A_CMD_WUPA) || ISO14443ACmdIsPM3WUPA(cmd)) @@ -132,7 +133,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 #define GetAndSetBufferCRCA(Buffer, ByteCount) ({ \ uint16_t fullReturnBits = 0; \ ISO14443AAppendCRCA(Buffer, ByteCount); \ - fullReturnBits = ByteCount * BITS_PER_BYTE + ISO14443A_CRC_FRAME_SIZE; \ + fullReturnBits = ASBITS(ByteCount) + ISO14443A_CRC_FRAME_SIZE; \ fullReturnBits; \ }) #define GetAndSetNoResponseCRCA(Buffer) ({ \ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 6745ace7..bf933c25 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -356,7 +356,7 @@ uint16_t CmdNotImplemented(uint8_t *Buffer, uint16_t ByteCount) { uint16_t EV0CmdGetVersion1(uint8_t *Buffer, uint16_t ByteCount) { Buffer[0] = STATUS_ADDITIONAL_FRAME; - Buffer[1] = DESFIRE_MANUFACTURER_ID; + Buffer[1] = Picc.ManufacturerID; Buffer[2] = DESFIRE_TYPE; Buffer[3] = DESFIRE_SUBTYPE; GetPiccHardwareVersionInfo(&Buffer[4]); @@ -367,7 +367,7 @@ uint16_t EV0CmdGetVersion1(uint8_t *Buffer, uint16_t ByteCount) { uint16_t EV0CmdGetVersion2(uint8_t *Buffer, uint16_t ByteCount) { Buffer[0] = STATUS_ADDITIONAL_FRAME; - Buffer[1] = DESFIRE_MANUFACTURER_ID; + Buffer[1] = Picc.ManufacturerID; Buffer[2] = DESFIRE_TYPE; Buffer[3] = DESFIRE_SUBTYPE; GetPiccSoftwareVersionInfo(&Buffer[4]); @@ -1798,8 +1798,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CryptoChallengeResponseBytesSize); /* Encrypt RndB with the selected key and transfer it back to the PCD */ - if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || - cryptoKeyType == CRYPTO_TYPE_ANY) { + if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || cryptoKeyType == CRYPTO_TYPE_ANY) { Encrypt3DESBuffer(CryptoChallengeResponseBytesSize, DesfireCommandState.RndB, &Buffer[1], IV, Key); } else { @@ -1836,6 +1835,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { DesfireState = DESFIRE_IDLE; /* Validate command length */ if (ByteCount != 2 * CryptoChallengeResponseBytesSize + 1) { + LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); Buffer[0] = STATUS_LENGTH_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index b108d47f..8d5ce194 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -281,6 +281,23 @@ void FormatPicc(void) { /* Wipe application directory */ memset(&AppDir, 0x00, sizeof(DESFireAppDirType)); memset(&SelectedApp, 0x00, sizeof(SelectedAppCacheType)); + /* Set a random new UID */ + BYTE uidData[DESFIRE_UID_SIZE]; + RandomGetBuffer(uidData, DESFIRE_UID_SIZE); + memcpy(&Picc.Uid[0], uidData, DESFIRE_UID_SIZE); + /* Conform to NXP Application Note AN10927 about the first + * byte of a randomly generated UID (refer to section 2.1.1). + */ + Picc.Uid[0] = ISO14443A_UID0_RANDOM; + /* Randomize the initial batch number data: */ + BYTE batchNumberData[5]; + RandomGetBuffer(batchNumberData, 5); + memcpy(&Picc.BatchNumber[0], batchNumberData, 5); + /* Production dates should be obvious until the user changes them: */ + Picc.ProductionWeek = 0x44; + Picc.ProductionYear = 0x7c; + /* Assign the default manufacturer ID: */ + Picc.ManufacturerID = DESFIRE_MANUFACTURER_ID; /* Set the ATS bytes to defaults: */ Picc.ATSBytes[0] = DESFIRE_EV0_ATS_TL_BYTE; Picc.ATSBytes[1] = DESFIRE_EV0_ATS_T0_BYTE; @@ -313,16 +330,8 @@ void CreatePiccApp(void) { void FactoryFormatPiccEV0(void) { /* Wipe PICC data */ memset(&Picc, PICC_FORMAT_BYTE, sizeof(Picc)); - /* Set a random new UID */ - BYTE uidData[DESFIRE_UID_SIZE]; - RandomGetBuffer(uidData, DESFIRE_UID_SIZE); - memcpy(&Picc.Uid[0], uidData, DESFIRE_UID_SIZE); - /* Conform to NXP Application Note AN10927 about the first - * byte of a randomly generated UID (refer to section 2.1.1). - */ - Picc.Uid[0] = ISO14443A_UID0_RANDOM; /* Initialize params to look like EV0 */ - Picc.StorageSize = DESFIRE_STORAGE_SIZE_4K; + Picc.StorageSize = CardCapacityBlocks; Picc.HwVersionMajor = DESFIRE_HW_MAJOR_EV0; Picc.HwVersionMinor = DESFIRE_HW_MINOR_EV0; Picc.SwVersionMajor = DESFIRE_SW_MAJOR_EV0; @@ -337,14 +346,6 @@ void FactoryFormatPiccEV0(void) { void FactoryFormatPiccEV1(uint8_t StorageSize) { /* Wipe PICC data */ memset(&Picc, PICC_FORMAT_BYTE, sizeof(Picc)); - /* Set a random new UID */ - BYTE uidData[DESFIRE_UID_SIZE]; - RandomGetBuffer(uidData, DESFIRE_UID_SIZE); - memcpy(&Picc.Uid[0], uidData, DESFIRE_UID_SIZE); - /* Conform to NXP Application Note AN10927 about the first - * byte of a randomly generated UID (refer to section 2.1.1). - */ - Picc.Uid[0] = ISO14443A_UID0_RANDOM; /* Initialize params to look like EV1 */ Picc.StorageSize = StorageSize; Picc.HwVersionMajor = DESFIRE_HW_MAJOR_EV1; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index d36df834..592b542f 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -100,44 +100,6 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_SW_MAJOR_EV2 0x12 #define DESFIRE_SW_MINOR_EV2 0x01 -/* Other HW product types for DESFire tags: See page 7 of - * https://www.nxp.com/docs/en/application-note/AN12343.pdf - */ -// typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { -// NATIVEIC_PHYS_CARD = 0x01, -// LIGHT_NATIVEIC_PHYS_CARD = 0x08, -// MICROCONTROLLER_PHYS_CARDI = 0x81, -// MICROCONTROLLER_PHYS_CARDII = 0x83, -// JAVACARD_SECURE_ELEMENT_PHYS_CARD = 0x91, -// HCE_MIFARE_2GO = 0xa1, -// } DESFireHWProductCodes; -// -// const BYTE DefaultDESFireATS[] = { -// 0x06, 0x75, 0x77, 0x81, 0x02, 0x80 -// }; -// const BYTE DefaultJCOPDESFireATS[] = { -// 0x06, 0x75, 0xf7, 0xb1, 0x02, 0x80 -// }; -// -// const BYTE DEFAULT_SELECT_DESFIRE_AID[] = { -// 0xd2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x00 -// }; -// const BYTE DEFAULT_SELECT_ISO7816_AID[] = { -// 0xa0, 0x00, 0x00, 0x00, 0x03, 0x96 -// }; -// -// const BYTE VERSION1[] = { -// 0x04, 0x01, 0x01, 0x01, 0x00, 0x1a, 0x05 -// }; -// const BYTE VERSION2[] = { -// 0x04, 0x01, 0x01, 0x01, 0x03, 0x1a, 0x05 -// }; -// const BYTE VERSION3[] = { -// // Expected Response: 00 04 91 3a 29 93 26 80 00 00 00 00 00 39 08 91 00 -// 0x04, (BYTE) 0x91, 0x3a, 0x29, (BYTE) 0x93, -// 0x26, (BYTE) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x08 -// }; - #define DESFIRE_STORAGE_SIZE_2K 0x16 #define DESFIRE_STORAGE_SIZE_4K 0x18 #define DESFIRE_STORAGE_SIZE_8K 0x1A @@ -158,6 +120,7 @@ typedef struct { */ uint8_t Uid[DESFIRE_UID_SIZE] DESFIRE_FIRMWARE_ALIGNAT; uint8_t StorageSize; + uint8_t ManufacturerID; uint8_t HwVersionMajor; uint8_t HwVersionMinor; uint8_t SwVersionMajor; @@ -169,7 +132,6 @@ typedef struct { /* Dynamic data: changes during the PICC's lifetime */ uint16_t FirstFreeBlock; uint8_t TransactionStarted; - //uint8_t Spare[9] DESFIRE_FIRMWARE_ALIGNAT; // USED ANYWHERE ??? } DESFirePICCInfoType DESFIRE_FIRMWARE_PACKING; typedef struct { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c index 811ef8ef..abce8a30 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c @@ -147,50 +147,55 @@ bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount) { return true; } -uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize) { +uint16_t DesfirePreprocessAPDUWrapper(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize, bool TruncateChecksumBytes) { switch (CommMode) { - case DESFIRE_COMMS_PLAINTEXT_MAC: { uint16_t ChecksumBytes = 0; + case DESFIRE_COMMS_PLAINTEXT_MAC: { if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { ChecksumBytes = 4; - if (!checkBufferMAC(Buffer, BufferSize, ChecksumBytes)) { + if (BufferSize <= ChecksumBytes || !checkBufferMAC(Buffer, BufferSize, ChecksumBytes)) { return 0; } } else if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_3K3DES) { ChecksumBytes = CRYPTO_3KTDEA_BLOCK_SIZE; - if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { + if (BufferSize <= ChecksumBytes || !checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { return 0; } } else { ChecksumBytes = CRYPTO_AES_BLOCK_SIZE; - if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { + if (BufferSize <= ChecksumBytes || !checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { return 0; } } - return MAX(0, BufferSize - ChecksumBytes); + return (TruncateChecksumBytes ? MAX(0, BufferSize - ChecksumBytes) : BufferSize); } case DESFIRE_COMMS_CIPHERTEXT_DES: { Decrypt3DESBuffer(BufferSize, Buffer, &Buffer[BufferSize], SessionIV, SessionKey); memmove(&Buffer[0], &Buffer[BufferSize], BufferSize); - uint16_t ChecksumBytes = CRYPTO_3KTDEA_BLOCK_SIZE; - if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { + ChecksumBytes = CRYPTO_3KTDEA_BLOCK_SIZE; + if (BufferSize <= ChecksumBytes || !checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { return 0; } - return MAX(0, BufferSize - ChecksumBytes); + return (TruncateChecksumBytes ? MAX(0, BufferSize - ChecksumBytes) : BufferSize); } case DESFIRE_COMMS_CIPHERTEXT_AES128: { CryptoAESDecryptBuffer(BufferSize, Buffer, &Buffer[BufferSize], SessionIV, SessionKey); memmove(&Buffer[0], &Buffer[BufferSize], BufferSize); - uint16_t ChecksumBytes = CRYPTO_AES_BLOCK_SIZE; - if (!checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { + ChecksumBytes = CRYPTO_AES_BLOCK_SIZE; + if (BufferSize <= ChecksumBytes || !checkBufferCMAC(Buffer, BufferSize, ChecksumBytes)) { return 0; } - return MAX(0, BufferSize - ChecksumBytes); + return (TruncateChecksumBytes ? MAX(0, BufferSize - ChecksumBytes) : BufferSize); + } + case DESFIRE_COMMS_PLAINTEXT: { + ChecksumBytes = 2; + if (BufferSize <= ChecksumBytes || !ISO14443ACheckCRCA(Buffer, BufferSize - ChecksumBytes)) { + return 0; + } + return (TruncateChecksumBytes ? MAX(0, BufferSize - ChecksumBytes) : BufferSize); } - case DESFIRE_COMMS_PLAINTEXT: default: - // Leave the CRCA bytes intact: - return BufferSize; + return (TruncateChecksumBytes ? MAX(0, BufferSize - ChecksumBytes) : BufferSize); } } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h index 0f48759f..e2eb91a4 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h @@ -31,6 +31,9 @@ This notice must be retained at the top of all source files where indicated. #include "DESFireFirmwareSettings.h" +#define ASBYTES(bc) (((bc) + BITS_PER_BYTE - 1) / BITS_PER_BYTE) +#define ASBITS(bc) ((bc) * BITS_PER_BYTE) + #define UnsignedTypeToUINT(typeValue) \ ((UINT) typeValue) #define ExtractLSBLE(ui) \ @@ -69,7 +72,11 @@ bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount); * CommSettings and wrapped APDU format combinations are defined statically in the * C source file to save space in the symbol table for the firmware (ELF) binary. */ -uint16_t DesfirePreprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize); +uint16_t DesfirePreprocessAPDUWrapper(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize, bool TruncateChecksumBytes); +#define DesfirePreprocessAPDU(CommMode, Buffer, BufferSize) \ + DesfirePreprocessAPDUWrapper(CommMode, Buffer, BufferSize, false) +#define DesfirePreprocessAPDUAndTruncate(CommMode, Buffer, BufferSize) \ + DesfirePreprocessAPDUWrapper(CommMode, Buffer, BufferSize, true) uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize); #endif diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c index 6a2d0ffd..2ba520e7 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c @@ -53,7 +53,7 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, ui #define USE_HW_CRC #ifdef USE_HW_CRC -void ISO14443AAppendCRCA(void *Buffer, uint16_t ByteCount) { +uint16_t ISO14443AAppendCRCA(void *Buffer, uint16_t ByteCount) { uint8_t *DataPtr = (uint8_t *) Buffer; CRC.CTRL = CRC_RESET0_bm; @@ -72,10 +72,12 @@ void ISO14443AAppendCRCA(void *Buffer, uint16_t ByteCount) { DataPtr[1] = BitReverseByte(CRC.CHECKSUM0); CRC.CTRL = CRC_SOURCE_DISABLE_gc; + + return (uint16_t)(((DataPtr[0] << 8) & 0x00FF00) | (DataPtr[1] & 0x00FF)); } #else #include -void ISO14443AAppendCRCA(void *Buffer, uint16_t ByteCount) { +uint16_t ISO14443AAppendCRCA(void *Buffer, uint16_t ByteCount) { uint16_t Checksum = CRC_INIT; uint8_t *DataPtr = (uint8_t *) Buffer; @@ -86,6 +88,8 @@ void ISO14443AAppendCRCA(void *Buffer, uint16_t ByteCount) { DataPtr[0] = (Checksum >> 0) & 0x00FF; DataPtr[1] = (Checksum >> 8) & 0x00FF; + + return Checksum; } #endif diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h index 5ff66fb7..3faee877 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h @@ -48,7 +48,7 @@ #define ISO14443A_CALC_BCC(ByteBuffer) \ ( ByteBuffer[0] ^ ByteBuffer[1] ^ ByteBuffer[2] ^ ByteBuffer[3] ) -void ISO14443AAppendCRCA(void *Buffer, uint16_t ByteCount); +uint16_t ISO14443AAppendCRCA(void *Buffer, uint16_t ByteCount); bool ISO14443ACheckCRCA(const void *Buffer, uint16_t ByteCount); #define ISO14443A_UID0_RANDOM 0x08 diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index d4abf06c..bec1e62e 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -52,11 +52,9 @@ DesfireStateType DesfirePreviousState = DESFIRE_IDLE; bool DesfireFromHalt = false; BYTE DesfireCmdCLA = DESFIRE_NATIVE_CLA; Iso7816WrappedCommandType_t Iso7816CmdType; -static bool AnticolNoResp = false; /* Dispatching routines */ void MifareDesfireReset(void) { - AnticolNoResp = false; DesfireState = DESFIRE_IDLE; } @@ -126,11 +124,9 @@ void MifareDesfireAppTask(void) { } uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { + if (ByteCount == 0) { return ISO14443A_APP_NO_RESPONSE; - } else if ((DesfireCmdCLA != DESFIRE_NATIVE_CLA) && - (DesfireCmdCLA != DESFIRE_ISO7816_CLA)) { - return ISO14443A_APP_NO_RESPONSE; } else if (Buffer[0] != STATUS_ADDITIONAL_FRAME) { DesfireState = DESFIRE_IDLE; uint16_t ReturnBytes = CallInstructionHandler(Buffer, ByteCount); @@ -173,14 +169,12 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { } uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { - size_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; DesfireCmdCLA = Buffer[0]; + size_t ByteCount = ASBYTES(BitCount); LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); - if (BitCount == 0) { - LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); + if (ByteCount == 0) { return ISO14443A_APP_NO_RESPONSE; - } else if (ByteCount >= 2 && Buffer[1] == STATUS_ADDITIONAL_FRAME && - DesfireCLA(Buffer[0])) { + } else if (ByteCount >= 2 && Buffer[1] == STATUS_ADDITIONAL_FRAME && DesfireCLA(Buffer[0])) { ByteCount -= 1; memmove(&Buffer[0], &Buffer[1], ByteCount); uint16_t ProcessedByteCount = MifareDesfireProcessCommand(Buffer, ByteCount); @@ -191,11 +185,9 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[ProcessedByteCount - 1] = 0x91; ++ProcessedByteCount; } - return ProcessedByteCount * BITS_PER_BYTE; - } else if (((ByteCount >= 8 && Buffer[4] == ByteCount - 8) || - (ByteCount >= 5 && Buffer[4] == ByteCount - 5)) && - DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - Buffer[3] == 0x00 || Iso7816CLA(DesfireCmdCLA)) { + return ASBITS(ProcessedByteCount); + } else if ((ByteCount >= 5 && DesfireCLA(Buffer[0]) && + Buffer[2] == 0x00 && Buffer[3] == 0x00) || Iso7816CLA(DesfireCmdCLA)) { /* Wrapped native command structure or ISO7816: */ if (Iso7816CLA(DesfireCmdCLA)) { uint16_t iso7816ParamsStatus = SetIso7816WrappedParametersType(Buffer, ByteCount); @@ -203,7 +195,7 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[0] = (uint8_t)((iso7816ParamsStatus >> 8) & 0x00ff); Buffer[1] = (uint8_t)(iso7816ParamsStatus & 0x00ff); ByteCount = 2; - return ByteCount * BITS_PER_BYTE; + return ASBITS(ByteCount); } } ByteCount = Buffer[4]; @@ -222,51 +214,105 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { } else { /* Re-wrap into ISO 7816-4 -- Done below by prepending the prologue back to the buffer */ } - return ByteCount * BITS_PER_BYTE; + return ASBITS(ByteCount); } else { /* ISO/IEC 14443-4 PDUs: No extra work */ - return MifareDesfireProcessCommand(Buffer, ByteCount) * BITS_PER_BYTE; + return ASBITS(MifareDesfireProcessCommand(Buffer, ByteCount)); } } uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { - uint16_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; uint16_t ReturnedBytes = 0; + uint16_t ByteCount = ASBYTES(BitCount); LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); - if (ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && - Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) { + if (ByteCount >= 3 && Buffer[2] == STATUS_ADDITIONAL_FRAME && + DesfireStateExpectingAdditionalFrame(DesfireState)) { + /* [PM3-V1] : Handle the ISO-prologue-only-wrapped version of the additional frame data: */ + uint8_t ISO7816PrologueBytes[2]; + memcpy(&ISO7816PrologueBytes[0], &Buffer[0], 2); + uint16_t IncomingByteCount = DesfirePreprocessAPDUAndTruncate(ActiveCommMode, Buffer, ByteCount); + if (IncomingByteCount == 0) { + return ISO14443A_APP_NO_RESPONSE; + } + ByteCount = IncomingByteCount - 2; + memmove(&Buffer[0], &Buffer[2], ByteCount); + uint16_t ProcessedByteCount = MifareDesfireProcessCommand(Buffer, ByteCount); + if (ProcessedByteCount > 0) { + memmove(&Buffer[2], &Buffer[0], ProcessedByteCount); + } + memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); + ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); + LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); + } else if (ByteCount >= 5 && DesfireCLA(Buffer[0]) && Buffer[1] == STATUS_ADDITIONAL_FRAME && + Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 9 && + DesfireStateExpectingAdditionalFrame(DesfireState)) { + /* [PM3-V2] : Handle the native-wrapped version of the additional frame data: */ + uint16_t checkSumPostVerifyBytes = DesfirePreprocessAPDUAndTruncate(ActiveCommMode, Buffer, ByteCount); + if (checkSumPostVerifyBytes == 0) { + return ISO14443A_APP_NO_RESPONSE; + } + Buffer[0] = Buffer[1]; + ByteCount = Buffer[4]; + if (ByteCount > 0) { + memmove(&Buffer[1], &Buffer[5], ByteCount); + } + uint16_t ProcessedByteCount = MifareDesfireProcessCommand(Buffer, ByteCount + 1); + if (ProcessedByteCount == 0) { + return ISO14443A_APP_NO_RESPONSE; + } + /* Re-wrap into padded APDU form */ + Buffer[ProcessedByteCount] = Buffer[0]; + memmove(&Buffer[0], &Buffer[1], ProcessedByteCount - 1); + Buffer[ProcessedByteCount - 1] = 0x91; + ++ProcessedByteCount; + ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); + LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); + } else if (ByteCount >= 8 && DesfireCLA(Buffer[0]) && + Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) { DesfireCmdCLA = Buffer[0]; - uint16_t IncomingByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; + uint16_t IncomingByteCount = ASBYTES(BitCount); + uint16_t UnwrappedBitCount = ASBITS(DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount)); uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); - uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + uint16_t ProcessedByteCount = ASBYTES(ProcessedBitCount); + if (ProcessedByteCount == 0) { + return ISO14443A_APP_NO_RESPONSE; + } ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); - return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedByteCount * BITS_PER_BYTE); - } else if (ByteCount >= 8 && DesfireCLA(Buffer[1]) && Buffer[3] == 0x00 && - Buffer[4] == 0x00 && Buffer[5] == ByteCount - 8) { + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); + } else if (ByteCount >= 8 && DesfireCLA(Buffer[1]) && + Buffer[3] == 0x00 && Buffer[4] == 0x00 && Buffer[5] == ByteCount - 8) { + uint16_t UnwrappedByteCount = DesfirePreprocessAPDUAndTruncate(ActiveCommMode, Buffer, ByteCount); + if (UnwrappedByteCount == 0) { + return ISO14443A_APP_NO_RESPONSE; + } uint8_t hf14AScanPrologue = Buffer[0]; DesfireCmdCLA = Buffer[1]; - uint16_t IncomingByteCount = MAX(0, (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE - 1); - memmove(&Buffer[0], &Buffer[1], IncomingByteCount); - uint16_t UnwrappedBitCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, IncomingByteCount) * BITS_PER_BYTE; + memmove(&Buffer[0], &Buffer[1], UnwrappedByteCount - 1); + uint16_t UnwrappedBitCount = ASBITS(UnwrappedByteCount - 1); uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); - uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - if (ProcessedByteCount++ > 0) { - memmove(&Buffer[1], &Buffer[0], ProcessedByteCount); + uint16_t ProcessedByteCount = ASBYTES(ProcessedBitCount); + if (ProcessedByteCount++ == 0) { + return ISO14443A_APP_NO_RESPONSE; } + memmove(&Buffer[1], &Buffer[0], ProcessedByteCount); Buffer[0] = hf14AScanPrologue; ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); - return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedByteCount * BITS_PER_BYTE); + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } Iso7816CmdType = IsWrappedISO7816CommandType(Buffer, ByteCount); if (Iso7816CmdType != ISO7816_WRAPPED_CMD_TYPE_NONE) { DesfireCmdCLA = (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) ? Buffer[2] : DESFIRE_NATIVE_CLA; uint8_t ISO7816PrologueBytes[2]; - memcpy(&ISO7816PrologueBytes[0], Buffer, 2); - if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) { + memcpy(&ISO7816PrologueBytes[0], &Buffer[0], 2); + ByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, ByteCount); + if (ByteCount == 0) { + return ISO14443A_APP_NO_RESPONSE; + } else if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_STANDARD) { memmove(&Buffer[0], &Buffer[2], ByteCount - 2); ByteCount = ByteCount - 2; } else if (Iso7816CmdType == ISO7816_WRAPPED_CMD_TYPE_PM3_ADDITIONAL_FRAME) { @@ -290,13 +336,9 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[3] = 0x00; Buffer[4] = ByteCount - 5; } - uint16_t UnwrappedBitCount = ByteCount * BITS_PER_BYTE; - if (Iso7816CmdType != ISO7816_WRAPPED_CMD_TYPE_PM3_ADDITIONAL_FRAME) { - uint16_t IncomingByteCount = DesfirePreprocessAPDU(ActiveCommMode, Buffer, ByteCount); - UnwrappedBitCount = IncomingByteCount * BITS_PER_BYTE; - } + uint16_t UnwrappedBitCount = ASBITS(ByteCount); uint16_t ProcessedBitCount = MifareDesfireProcess(Buffer, UnwrappedBitCount); - uint16_t ProcessedByteCount = (ProcessedBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + uint16_t ProcessedByteCount = ASBYTES(ProcessedBitCount); /* Undo the leading 0x91 and shift for the PM3 raw wrapped commands: */ if (Iso7816CmdType != ISO7816_WRAPPED_CMD_TYPE_STANDARD && ProcessedByteCount > 0) { memmove(&Buffer[1], &Buffer[0], ProcessedByteCount); @@ -310,38 +352,24 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); - return ISO14443AStoreLastDataFrameAndReturn(Buffer, ProcessedByteCount * BITS_PER_BYTE); + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { /* This case should handle non-wrappped native commands. No pre/postprocessing afterwards: */ LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ReturnedBytes); - return ISO14443AStoreLastDataFrameAndReturn(Buffer, ReturnedBytes * BITS_PER_BYTE); - } else if (!AnticolNoResp || BitCount < BITS_PER_BYTE) { - /* This case is to exchange anticollision loop and RATS data. No need to pre/postprocess it depending - * on the CommMode, which has not been set yet if we reach this point: - */ + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ReturnedBytes)); + } else { uint16_t PiccProcessRespBits = ISO144433APiccProcess(Buffer, BitCount); - if (PiccProcessRespBits == ISO14443A_APP_NO_RESPONSE) { - /* Stop pesky USB readers trying to autodetect all tag types by brute-force enumeration - * from interfering with making it into the command exchange (DESFIRE_IDLE) states. - * Once the anticollision and/or RATS has completed, set this flag to keep it from - * resending that initial handshaking until the AppReset() function is called on a timeout. - * N.b., the ACR-122 reader does this repeatedly when trying to run the LibNFC testing code - * even when the reader has not been put in scan mode -- - * and it really screws things up timing-wise! - */ - AnticolNoResp = true; - const char *debugPrintStr = PSTR("DESFire: Anticol NO-RESP set"); - LogDebuggingMsg(debugPrintStr); + uint16_t PiccProcessRespBytesCeil = ASBYTES(PiccProcessRespBits); + if (PiccProcessRespBits >= BITS_PER_BYTE) { + PiccProcessRespBits = ASBITS(PiccProcessRespBytesCeil); } - uint16_t PiccProcessRespBytes = (PiccProcessRespBits + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, PiccProcessRespBytes); + LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, PiccProcessRespBytesCeil); return ISO14443AStoreLastDataFrameAndReturn(Buffer, PiccProcessRespBits); } return ISO14443A_APP_NO_RESPONSE; } void ResetLocalStructureData(void) { - AnticolNoResp = false; DesfirePreviousState = DESFIRE_IDLE; DesfireState = DESFIRE_HALT; InvalidateAuthState(0x00); diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.h b/Firmware/Chameleon-Mini/Application/MifareDESFire.h index c865e2ab..9c2974c0 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.h +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.h @@ -85,6 +85,16 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { DESFIRE_WRITE_DATA_FILE, } DesfireStateType; +#define DesfireStateExpectingAdditionalFrame(dfState) \ + ((dfState == DESFIRE_GET_VERSION2) || \ + (dfState == DESFIRE_GET_VERSION3) || \ + (dfState == DESFIRE_GET_APPLICATION_IDS2) || \ + (dfState == DESFIRE_LEGACY_AUTHENTICATE2) || \ + (dfState == DESFIRE_ISO_AUTHENTICATE2) || \ + (dfState == DESFIRE_AES_AUTHENTICATE2) || \ + (dfState == DESFIRE_READ_DATA_FILE) || \ + (dfState == DESFIRE_WRITE_DATA_FILE)) + extern DesfireStateType DesfireState; extern DesfireStateType DesfirePreviousState; extern bool DesfireFromHalt; diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index e3b5bdea..a8644ef2 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -13,17 +13,15 @@ custom-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bi @cp $(TARGET).eep $(TARGET_CUSTOM_BUILD).eep @cp $(TARGET).elf $(TARGET_CUSTOM_BUILD).elf @cp $(TARGET).bin $(TARGET_CUSTOM_BUILD).bin - @echo $(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)"\n" - @avr-size -A -x $(TARGET).elf - @echo $(MSG_TIDY_ENDSEP)"\n" - @avr-size -B -x $(TARGET).elf - @echo "\n"$(MSG_TIDY_ENDSEP)"\n" + @echo $(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP) @avr-size -C -x $(TARGET).elf - @echo $(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)"\n" + @echo $(MSG_TIDY_ENDSEP) + @avr-size -B -x $(TARGET).elf + @echo "\n"$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)"\n" @echo $(FMT_ANSIC_BOLD)$(FMT_ANSIC_EXCLAIM)"[!!!]"$(FMT_ANSIC_END) \ - $(FMT_ANSIC_BOLD)$(FMT_ANSIC_UNDERLINE)"SUCCESS BUILDING CUSTOM FIRMWARE:"$(FMT_ANSIC_END) + " 💬 "$(FMT_ANSIC_BOLD)$(FMT_ANSIC_UNDERLINE)"SUCCESS BUILDING CUSTOM FIRMWARE:"$(FMT_ANSIC_END) @echo $(FMT_ANSIC_BOLD)$(FMT_ANSIC_EXCLAIM)"[!!!]"$(FMT_ANSIC_END) \ - $(FMT_ANSIC_BOLD)"$(TARGET_CUSTOM_BUILD).(HEX|EEP|ELF|BIN)"$(FMT_ANSIC_END) + " 💯 "$(FMT_ANSIC_BOLD)"$(TARGET_CUSTOM_BUILD).(HEX|EEP|ELF|BIN)"$(FMT_ANSIC_END) @echo "\n" mifare: SUPPORTED_TAGS_BUILD:=\ diff --git a/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk b/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk index a386d468..4b6d1db9 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk @@ -148,22 +148,23 @@ FMT_ANSIC_BW_V2 := "\033[97;30;48m" FMT_ANSIC_RESET := "\033[0m" FMT_ANSIC_END := "\033[0m" FMT_CMDHL_BEGIN := $(FMT_ANSIC_UNDERLINE)$(FMT_ANSIC_BOLD)$(FMT_ANSIC_GREEN) +FMT_CMDHL_END := $(FMT_ANSIC_END) FMT_CMDSEP_BEGIN := $(FMT_ANSIC_BOLD)$(FMT_ANSIC_CYAN) FMT_CMDSEP_V2_BEGIN := $(FMT_ANSIC_BOLD)$(FMT_ANSIC_BW_V2) FMT_FILENAME_BEGIN := $(FMT_ANSIC_BOLD)$(FMT_ANSIC_MAGENTA) FMT_NEWLINE := $(FMT_ANSIC_RESET)$(FMT_ANSIC_END) # Output Messages -MSG_INFO_MESSAGE := ' ['$(FMT_CMDHL_BEGIN)'INFO'$(FMT_ANSIC_END)'] :' -MSG_COMPILE_CMD := ' ['$(FMT_CMDHL_BEGIN)'GCC'$(FMT_ANSIC_END)'] :' -MSG_ASSEMBLE_CMD := ' ['$(FMT_CMDHL_BEGIN)'GAS'$(FMT_ANSIC_END)'] :' -MSG_NM_CMD := ' ['$(FMT_CMDHL_BEGIN)'NM'$(FMT_ANSIC_END)'] :' -MSG_REMOVE_CMD := ' ['$(FMT_CMDHL_BEGIN)'RM'$(FMT_ANSIC_END)'] :' -MSG_LINK_CMD := ' ['$(FMT_CMDHL_BEGIN)'LNK'$(FMT_ANSIC_END)'] :' -MSG_ARCHIVE_CMD := ' ['$(FMT_CMDHL_BEGIN)'AR'$(FMT_ANSIC_END)'] :' -MSG_SIZE_CMD := ' ['$(FMT_CMDHL_BEGIN)'SIZE'$(FMT_ANSIC_END)'] :' -MSG_OBJCPY_CMD := ' ['$(FMT_CMDHL_BEGIN)'OBJCPY'$(FMT_ANSIC_END)'] :' -MSG_OBJDMP_CMD := ' ['$(FMT_CMDHL_BEGIN)'OBJDMP'$(FMT_ANSIC_END)'] :' +MSG_INFO_MESSAGE := '🧞 ['$(FMT_CMDHL_BEGIN)'INFO'$(FMT_CMDHL_END)'] :' +MSG_COMPILE_CMD := '🪛 ['$(FMT_CMDHL_BEGIN)'GCC'$(FMT_CMDHL_END)'] :' +MSG_ASSEMBLE_CMD := '🪛 ['$(FMT_CMDHL_BEGIN)'GAS'$(FMT_CMDHL_END)'] :' +MSG_NM_CMD := '🪛 [$(FMT_CMDHL_BEGIN)'NM'$(FMT_CMDHL_END)'] :' +MSG_REMOVE_CMD := '🧞 ['$(FMT_CMDHL_BEGIN)'RM'$(FMT_CMDHL_END)'] :' +MSG_SIZE_CMD := '🧞 ['$(FMT_CMDHL_BEGIN)'SIZE'$(FMT_CMDHL_END)'] :' +MSG_LINK_CMD := '🪛 ['$(FMT_CMDHL_BEGIN)'LNK'$(FMT_CMDHL_END)'] :' +MSG_ARCHIVE_CMD := '🪛 ['$(FMT_CMDHL_BEGIN)'AR'$(FMT_CMDHL_END)'] :' +MSG_OBJCPY_CMD := '🧞 ['$(FMT_CMDHL_BEGIN)'OBJCPY'$(FMT_CMDHL_END)'] :' +MSG_OBJDMP_CMD := '🧞 ['$(FMT_CMDHL_BEGIN)'OBJDMP'$(FMT_CMDHL_END)'] :' MSG_NEWLINE := $(FMT_NEWLINE)"\n" MSG_CMDSEP_LINE := ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ' MSG_CMDSEP_LINE_V2 := ' :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ' diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index bca10f0a..db597840 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -131,8 +131,8 @@ CONFIG_SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 ## : Set a minimum incoming/outgoing log size so we do not spam the ## : Chameleon Mini logs to much by logging everything: -CONFIG_SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=1 -#CONFIG_SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 +CONFIG_SETTINGS += -DDESFIRE_MIN_INCOMING_LOGSIZE=0 +CONFIG_SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 ## : Enable printing of crypto tests when a new DESFire emulation instance is started: #SETTINGS += -DDESFIRE_RUN_CRYPTO_TESTING_PROCEDURE @@ -407,6 +407,7 @@ git-add-dev: @make style && git add $(LOCALFW_SOURCE_FILES) @cd $(BUILD_SCR) && git add -f $(LOCALFW_BUILD_SCRIPT_FILES) @cd $(FWROOT)/Software/DESFireLibNFCTesting && make style && git add $(TESTING_SOURCE_FILES) + @git add $(FWROOT)/Doc/DESFireSupportReadme.md configure-chameleon-usb: UDEV_RULES_CONFIG_LINES:='\n \ \# ChameleonMini (RevG)\n \ From 7b4cdd86d137d82fd9a5b235dd166fdceff13649 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Tue, 7 Jun 2022 21:56:24 -0400 Subject: [PATCH 52/68] Fixing some make build script bugs --- .../BuildScripts/custom_build_targets.mk | 14 ++++++-------- .../BuildScripts/lufa_build_extra.mk | 4 ++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index a8644ef2..89c1c473 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -1,18 +1,16 @@ .PHONY: mifare mifare-classic desfire desfire-dev iso-modes ntag215 vicinity sl2s2002 tagatit em4233 .SECONDARY: custom-build -TARGET_CUSTOM_BUILD_NAME = DEFAULT_TAG_SUPPORT_BASE = -DCONFIG_ISO14443A_SNIFF_SUPPORT \ -DCONFIG_ISO14443A_READER_SUPPORT SUPPORTED_TAGS_BUILD = EXTRA_CONFIG_SETTINGS = -custom-build: TARGET_CUSTOM_BUILD:=$(TARGET)-$(strip $(if $(TARGET_CUSTOM_BUILD_NAME), "CustomBuild_$(TARGET_CUSTOM_BUILD_NAME)", "DefaultBuild")) custom-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bin check_size - @cp $(TARGET).hex $(TARGET_CUSTOM_BUILD).hex - @cp $(TARGET).eep $(TARGET_CUSTOM_BUILD).eep - @cp $(TARGET).elf $(TARGET_CUSTOM_BUILD).elf - @cp $(TARGET).bin $(TARGET_CUSTOM_BUILD).bin + @cp $(TARGET).hex $(TARGET)-CustomBuild_$(TARGET_CUSTOM_BUILD_NAME).hex + @cp $(TARGET).eep $(TARGET)-CustomBuild_$(TARGET_CUSTOM_BUILD_NAME).eep + @cp $(TARGET).elf $(TARGET)-CustomBuild_$(TARGET_CUSTOM_BUILD_NAME).elf + @cp $(TARGET).bin $(TARGET)-CustomBuild_$(TARGET_CUSTOM_BUILD_NAME).bin @echo $(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP) @avr-size -C -x $(TARGET).elf @echo $(MSG_TIDY_ENDSEP) @@ -21,7 +19,7 @@ custom-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bi @echo $(FMT_ANSIC_BOLD)$(FMT_ANSIC_EXCLAIM)"[!!!]"$(FMT_ANSIC_END) \ " 💬 "$(FMT_ANSIC_BOLD)$(FMT_ANSIC_UNDERLINE)"SUCCESS BUILDING CUSTOM FIRMWARE:"$(FMT_ANSIC_END) @echo $(FMT_ANSIC_BOLD)$(FMT_ANSIC_EXCLAIM)"[!!!]"$(FMT_ANSIC_END) \ - " 💯 "$(FMT_ANSIC_BOLD)"$(TARGET_CUSTOM_BUILD).(HEX|EEP|ELF|BIN)"$(FMT_ANSIC_END) + " 💯 "$(FMT_ANSIC_BOLD)"$(TARGET)-CustomBuild_$(TARGET_CUSTOM_BUILD_NAME).(HEX|EEP|ELF|BIN)"$(FMT_ANSIC_END) @echo "\n" mifare: SUPPORTED_TAGS_BUILD:=\ @@ -49,7 +47,7 @@ desfire: FLASH_DATA_SIZE:=0x0E000 desfire: SUPPORTED_TAGS_BUILD:=-DCONFIG_MF_DESFIRE_SUPPORT desfire: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ -DDESFIRE_CRYPTO1_SAVE_SPACE \ - -f-inline-small-functions + -finline-small-functions desfire: TARGET_CUSTOM_BUILD_NAME:=DESFire desfire: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) desfire: custom-build diff --git a/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk b/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk index 4b6d1db9..9a4d9032 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk @@ -187,9 +187,9 @@ ifneq ($(UNKNOWN_SOURCE),) endif # Convert input source filenames into a list of required output object files -FWSRC_OBJECT_FILES := $(addsuffix .o, $(basename $(FULL_SOURCE))) +FWSRC_OBJECT_FILES := $(addsuffix .o, $(basename $(FULL_SOURCE))) OBJECT_FILES += $(sort $(FWSRC_OBJECT_FILES)) -LUFA_OBJECT_FILES := $(addsuffix .o, $(shell basename $(LUFA_SRC))) +LUFA_OBJECT_FILES := $(addsuffix .o, $(basename $(LUFA_SRC))) # Check if an output object file directory was specified instead of the input file location ifneq ($(OBJDIR),.) From 68a12e673c362b8b153db39658bba77b0ef88511 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Wed, 15 Jun 2022 11:42:43 -0400 Subject: [PATCH 53/68] Fixing Linux build errors noticed by @colinoflynn in \#313 --- .../BuildScripts/custom_build_targets.mk | 18 ++- .../BuildScripts/lufa_build_extra.mk | 147 +++++++++--------- 2 files changed, 88 insertions(+), 77 deletions(-) diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index 89c1c473..41c5c9e9 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -1,6 +1,12 @@ .PHONY: mifare mifare-classic desfire desfire-dev iso-modes ntag215 vicinity sl2s2002 tagatit em4233 .SECONDARY: custom-build +ECHOFLAGS=-e +ECHO = $(shell which echo) $(ECHOFLAGS) +ifeq ("$(shell uname -s)", "Darwin") + ECHOFLAGS= +endif + DEFAULT_TAG_SUPPORT_BASE = -DCONFIG_ISO14443A_SNIFF_SUPPORT \ -DCONFIG_ISO14443A_READER_SUPPORT SUPPORTED_TAGS_BUILD = @@ -11,16 +17,16 @@ custom-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bi @cp $(TARGET).eep $(TARGET)-CustomBuild_$(TARGET_CUSTOM_BUILD_NAME).eep @cp $(TARGET).elf $(TARGET)-CustomBuild_$(TARGET_CUSTOM_BUILD_NAME).elf @cp $(TARGET).bin $(TARGET)-CustomBuild_$(TARGET_CUSTOM_BUILD_NAME).bin - @echo $(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP) + @$(ECHO) $(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP) @avr-size -C -x $(TARGET).elf - @echo $(MSG_TIDY_ENDSEP) + @$(ECHO) $(MSG_TIDY_ENDSEP) @avr-size -B -x $(TARGET).elf - @echo "\n"$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)"\n" - @echo $(FMT_ANSIC_BOLD)$(FMT_ANSIC_EXCLAIM)"[!!!]"$(FMT_ANSIC_END) \ + @$(ECHO) "\n"$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)$(MSG_TIDY_ENDSEP)"\n" + @$(ECHO) $(FMT_ANSIC_BOLD)$(FMT_ANSIC_EXCLAIM)"[!!!]"$(FMT_ANSIC_END) \ " 💬 "$(FMT_ANSIC_BOLD)$(FMT_ANSIC_UNDERLINE)"SUCCESS BUILDING CUSTOM FIRMWARE:"$(FMT_ANSIC_END) - @echo $(FMT_ANSIC_BOLD)$(FMT_ANSIC_EXCLAIM)"[!!!]"$(FMT_ANSIC_END) \ + @$(ECHO) $(FMT_ANSIC_BOLD)$(FMT_ANSIC_EXCLAIM)"[!!!]"$(FMT_ANSIC_END) \ " 💯 "$(FMT_ANSIC_BOLD)"$(TARGET)-CustomBuild_$(TARGET_CUSTOM_BUILD_NAME).(HEX|EEP|ELF|BIN)"$(FMT_ANSIC_END) - @echo "\n" + @$(ECHO) "\n" mifare: SUPPORTED_TAGS_BUILD:=\ -DCONFIG_MF_CLASSIC_MINI_4B_SUPPORT \ diff --git a/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk b/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk index 9a4d9032..318b17d4 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk @@ -85,6 +85,11 @@ LUFA_BUILD_PROVIDED_MACROS += # ----------------------------------------------------------------------------- SHELL = /bin/sh +ECHOFLAGS=-e +ECHO = $(shell which echo) $(ECHOFLAGS) +ifeq ("$(shell uname -s)", "Darwin") + ECHOFLAGS= +endif ERROR_IF_UNSET ?= $(if $(filter undefined, $(origin $(strip $(1)))), $(error Makefile $(strip $(1)) value not set)) ERROR_IF_EMPTY ?= $(if $(strip $($(strip $(1)))), , $(error Makefile $(strip $(1)) option cannot be blank)) @@ -155,16 +160,16 @@ FMT_FILENAME_BEGIN := $(FMT_ANSIC_BOLD)$(FMT_ANSIC_MAGENTA) FMT_NEWLINE := $(FMT_ANSIC_RESET)$(FMT_ANSIC_END) # Output Messages -MSG_INFO_MESSAGE := '🧞 ['$(FMT_CMDHL_BEGIN)'INFO'$(FMT_CMDHL_END)'] :' -MSG_COMPILE_CMD := '🪛 ['$(FMT_CMDHL_BEGIN)'GCC'$(FMT_CMDHL_END)'] :' -MSG_ASSEMBLE_CMD := '🪛 ['$(FMT_CMDHL_BEGIN)'GAS'$(FMT_CMDHL_END)'] :' -MSG_NM_CMD := '🪛 [$(FMT_CMDHL_BEGIN)'NM'$(FMT_CMDHL_END)'] :' -MSG_REMOVE_CMD := '🧞 ['$(FMT_CMDHL_BEGIN)'RM'$(FMT_CMDHL_END)'] :' -MSG_SIZE_CMD := '🧞 ['$(FMT_CMDHL_BEGIN)'SIZE'$(FMT_CMDHL_END)'] :' -MSG_LINK_CMD := '🪛 ['$(FMT_CMDHL_BEGIN)'LNK'$(FMT_CMDHL_END)'] :' -MSG_ARCHIVE_CMD := '🪛 ['$(FMT_CMDHL_BEGIN)'AR'$(FMT_CMDHL_END)'] :' -MSG_OBJCPY_CMD := '🧞 ['$(FMT_CMDHL_BEGIN)'OBJCPY'$(FMT_CMDHL_END)'] :' -MSG_OBJDMP_CMD := '🧞 ['$(FMT_CMDHL_BEGIN)'OBJDMP'$(FMT_CMDHL_END)'] :' +MSG_INFO_MESSAGE := '🧞'' ['$(FMT_CMDHL_BEGIN)'INFO'$(FMT_CMDHL_END)'] :' +MSG_COMPILE_CMD := '🪛'' ['$(FMT_CMDHL_BEGIN)'GCC'$(FMT_CMDHL_END)'] :' +MSG_ASSEMBLE_CMD := '🪛'' ['$(FMT_CMDHL_BEGIN)'GAS'$(FMT_CMDHL_END)'] :' +MSG_NM_CMD := '🪛'' ['$(FMT_CMDHL_BEGIN)'NM'$(FMT_CMDHL_END)'] :' +MSG_REMOVE_CMD := '🧞'' ['$(FMT_CMDHL_BEGIN)'RM'$(FMT_CMDHL_END)'] :' +MSG_SIZE_CMD := '🧞'' ['$(FMT_CMDHL_BEGIN)'SIZE'$(FMT_CMDHL_END)'] :' +MSG_LINK_CMD := '🪛'' ['$(FMT_CMDHL_BEGIN)'LNK'$(FMT_CMDHL_END)'] :' +MSG_ARCHIVE_CMD := '🪛'' ['$(FMT_CMDHL_BEGIN)'AR'$(FMT_CMDHL_END)'] :' +MSG_OBJCPY_CMD := '🧞'' ['$(FMT_CMDHL_BEGIN)'OBJCPY'$(FMT_CMDHL_END)'] :' +MSG_OBJDMP_CMD := '🧞'' ['$(FMT_CMDHL_BEGIN)'OBJDMP'$(FMT_CMDHL_END)'] :' MSG_NEWLINE := $(FMT_NEWLINE)"\n" MSG_CMDSEP_LINE := ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ' MSG_CMDSEP_LINE_V2 := ' :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ' @@ -192,7 +197,7 @@ OBJECT_FILES += $(sort $(FWSRC_OBJECT_FILES)) LUFA_OBJECT_FILES := $(addsuffix .o, $(basename $(LUFA_SRC))) # Check if an output object file directory was specified instead of the input file location -ifneq ($(OBJDIR),.) +ifneq ("$(OBJDIR)",".") # Prefix all the object filenames with the output object file directory path OBJECT_FILES := $(addprefix $(patsubst %/,%,$(OBJDIR))/, $(notdir $(OBJECT_FILES))) @@ -263,35 +268,35 @@ endif # Pre-build informational target, to give compiler and project name information when building build_begin: - @echo $(MSG_INFO_MESSAGE) Begin compilation of project \"$(TARGET)\"... - @echo "" + @$(ECHO) $(MSG_INFO_MESSAGE) Begin compilation of project \"$(TARGET)\"... + @$(ECHO) "" @$(CROSS)-gcc --version # Post-build informational target, to project name information when building has completed build_end: - @echo $(MSG_INFO_MESSAGE) Finished building project \"$(TARGET)\". + @$(ECHO) $(MSG_INFO_MESSAGE) Finished building project \"$(TARGET)\". # Prints size information of a compiled application (FLASH, RAM and EEPROM usages) size: $(TARGET).elf - @echo $(MSG_SIZE_CMD) Determining size of \"$<\" - @echo "" + @$(ECHO) $(MSG_SIZE_CMD) Determining size of \"$<\" + @$(ECHO) "" $(CROSS)-size $(SIZE_MCU_FLAG) $(SIZE_FORMAT_FLAG) $< # Prints size information on the symbols within a compiled application in decimal bytes symbol-sizes: $(TARGET).elf - @echo $(MSG_NM_CMD) Extracting \"$<\" symbols with decimal byte sizes + @$(ECHO) $(MSG_NM_CMD) Extracting \"$<\" symbols with decimal byte sizes $(CROSS)-nm --size-sort --demangle --radix=d $< # Cleans intermediary build files, leaving only the compiled application files mostlyclean: - @echo $(MSG_REMOVE_CMD) Removing object files of \"$(TARGET)\" + @$(ECHO) $(MSG_REMOVE_CMD) Removing object files of \"$(TARGET)\" rm -f $(OBJECT_FILES) - @echo $(MSG_REMOVE_CMD) Removing dependency files of \"$(TARGET)\" + @$(ECHO) $(MSG_REMOVE_CMD) Removing dependency files of \"$(TARGET)\" rm -f $(DEPENDENCY_FILES) # Cleans all build files, leaving only the original source code clean: mostlyclean - @echo $(MSG_REMOVE_CMD) Removing output files of \"$(TARGET)\" + @$(ECHO) $(MSG_REMOVE_CMD) Removing output files of \"$(TARGET)\" rm -f $(TARGET).elf $(TARGET).hex $(TARGET).bin $(TARGET).eep $(TARGET).map $(TARGET).lss $(TARGET).sym lib$(TARGET).a # Performs a complete build of the user application and prints size information afterwards @@ -312,104 +317,104 @@ $(FULL_SOURCE): # Compiles an input C source file and generates an assembly listing for it %.s: %.c $(MAKEFILE_LIST) - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_COMPILE_CMD) Generating assembly from C file $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_COMPILE_CMD) Generating assembly from C file $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-gcc -S $(BASE_CC_FLAGS) $(BASE_C_FLAGS) $(CC_FLAGS) $(C_FLAGS) $< -o $@ - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) # Compiles an input C++ source file and generates an assembly listing for it %.s: %.cpp $(MAKEFILE_LIST) - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_COMPILE_CMD) Generating assembly from C++ file $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_COMPILE_CMD) Generating assembly from C++ file $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-gcc -S $(BASE_CC_FLAGS) $(BASE_CPP_FLAGS) $(CC_FLAGS) $(CPP_FLAGS) $< -o $@ - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) # Compiles an input C source file and generates a linkable object file for it -$(OBJDIR)*/%.o: %.c $(MAKEFILE_LIST) - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_COMPILE_CMD) Compiling C file $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) +$(OBJDIR)/%.o: %.c $(MAKEFILE_LIST) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_COMPILE_CMD) Compiling C file $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-gcc -c $(BASE_CC_FLAGS) $(BASE_C_FLAGS) $(CC_FLAGS) $(C_FLAGS) -MMD -MP -MF $(@:%.o=%.d) $< -o $@ - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) # Compiles an input C++ source file and generates a linkable object file for it -$(OBJDIR)*/%.o: %.cpp $(MAKEFILE_LIST) - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_COMPILE_CMD) Compiling C++ file $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) +$(OBJDIR)/%.o: %.cpp $(MAKEFILE_LIST) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_COMPILE_CMD) Compiling C++ file $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-gcc -c $(BASE_CC_FLAGS) $(BASE_CPP_FLAGS) $(CC_FLAGS) $(CPP_FLAGS) -MMD -MP -MF $(@:%.o=%.d) $< -o $@ - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) # Assembles an input ASM source file and generates a linkable object file for it -$(OBJDIR)*/%.o: %.S $(MAKEFILE_LIST) - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_ASSEMBLE_CMD) Assembling $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) +$(OBJDIR)/%.o: %.S $(MAKEFILE_LIST) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_ASSEMBLE_CMD) Assembling $(FMT_FILENAME_BEGIN)\"$(notdir $<)\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-gcc -c $(BASE_CC_FLAGS) $(BASE_ASM_FLAGS) $(CC_FLAGS) $(ASM_FLAGS) -MMD -MP -MF $(@:%.o=%.d) $< -o $@ - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) # Generates a library archive file from the user application, which can be linked into other applications .PRECIOUS : $(OBJECT_FILES) .SECONDARY : %.a %.a: $(OBJECT_FILES) - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_ARCHIVE_CMD) Archiving object files into $(FMT_FILENAME_BEGIN)\"$@\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_ARCHIVE_CMD) Archiving object files into $(FMT_FILENAME_BEGIN)\"$@\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-ar rcs $@ $(OBJECT_FILES) - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) # Generates an ELF debug file from the user application, which can be further processed for FLASH and EEPROM data # files, or used for programming and debugging directly .PRECIOUS : $(OBJECT_FILES) .SECONDARY : %.elf %.elf: $(OBJECT_FILES) - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_LINK_CMD) Linking object files into $(FMT_FILENAME_BEGIN)\"$@\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_LINK_CMD) Linking object files into $(FMT_FILENAME_BEGIN)\"$@\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-gcc $^ -o $@ $(BASE_LD_FLAGS) $(LD_FLAGS) - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) # Extracts out the loadable FLASH memory data from the project ELF file, and creates an Intel HEX format file of it %.hex: %.elf - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_OBJCPY_CMD) Extracting HEX file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_OBJCPY_CMD) Extracting HEX file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature $< $@ - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) # Extracts out the loadable FLASH memory data from the project ELF file, and creates an Binary format file of it %.bin: %.elf - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_OBJCPY_CMD) Extracting BIN file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_OBJCPY_CMD) Extracting BIN file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature $< $@ - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) # Extracts out the loadable EEPROM memory data from the project ELF file, and creates an Intel HEX format file of it %.eep: %.elf - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_OBJCPY_CMD) Extracting EEP file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_OBJCPY_CMD) Extracting EEP file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings $< $@ || exit 0 - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) # Creates an assembly listing file from an input project ELF file, containing interleaved assembly and source data %.lss: %.elf - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_OBJDMP_CMD) Extracting LSS file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_OBJDMP_CMD) Extracting LSS file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-objdump -h -d -S -z $< > $@ - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) # Creates a symbol file listing the loadable and discarded symbols from an input project ELF file %.sym: %.elf - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_NM_CMD) Extracting SYM file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_NM_CMD) Extracting SYM file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-nm -n $< > $@ - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) # Include build dependency files -include $(DEPENDENCY_FILES) From 1ce7b55ac18b357d04c8920c7dc0872a7233c163 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Wed, 15 Jun 2022 12:20:25 -0400 Subject: [PATCH 54/68] Fixing the terminal (echo) printing on MacOS following the last commit for Linux users --- .../BuildScripts/custom_build_targets.mk | 5 +- .../BuildScripts/lufa_build_extra.mk | 5 +- Firmware/Chameleon-Mini/Makefile | 53 +++++++++++-------- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index 41c5c9e9..a22884cf 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -1,10 +1,11 @@ .PHONY: mifare mifare-classic desfire desfire-dev iso-modes ntag215 vicinity sl2s2002 tagatit em4233 .SECONDARY: custom-build -ECHOFLAGS=-e -ECHO = $(shell which echo) $(ECHOFLAGS) +ECHO = echo $(ECHOFLAGS) ifeq ("$(shell uname -s)", "Darwin") ECHOFLAGS= +else + ECHOFLAGS=-e endif DEFAULT_TAG_SUPPORT_BASE = -DCONFIG_ISO14443A_SNIFF_SUPPORT \ diff --git a/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk b/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk index 318b17d4..740d8b9e 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk @@ -85,10 +85,11 @@ LUFA_BUILD_PROVIDED_MACROS += # ----------------------------------------------------------------------------- SHELL = /bin/sh -ECHOFLAGS=-e -ECHO = $(shell which echo) $(ECHOFLAGS) +ECHO = echo $(ECHOFLAGS) ifeq ("$(shell uname -s)", "Darwin") ECHOFLAGS= +else + ECHOFLAGS=-e endif ERROR_IF_UNSET ?= $(if $(filter undefined, $(origin $(strip $(1)))), $(error Makefile $(strip $(1)) value not set)) diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index db597840..92955746 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -146,6 +146,15 @@ CONFIG_SETTINGS += -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 ## : grep, sed, awk) lead to unexpected behavior: CHECK_SIZE_GREP_ARGS=$(if $(filter "$(shell uname -s)", "Darwin"), -Eo "[[:digit:]]+", -oP "\d+") +## Support 'fancy' ANSI terminal colors and unicode emojis +## (idea from the PM3 command line utilities): +ECHO = echo $(ECHOFLAGS) +ifeq ("$(shell uname -s)", "Darwin") + ECHOFLAGS= +else + ECHOFLAGS=-e +endif + ## : Memory definitions and objcopy flags to include sections in binaries ## ++ Start of data section in flash FLASH_DATA_ADDR = 0x10000 @@ -307,28 +316,28 @@ include $(BUILD_SCR)/custom_build_targets.mk ## : Overwrite the LUFA versions of hex/bin file generation to include spmhelper and flashdata sections %.hex: %.elf - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_OBJCPY_CMD) Extracting $(FMT_ANSIC_LIGHTRED)HEX$(FMT_ANSIC_END) file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_OBJCPY_CMD) Extracting $(FMT_ANSIC_LIGHTRED)HEX$(FMT_ANSIC_END) file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature $(FLASH_DATA_OBJCOPY) $< $@ - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) %.bin: %.elf - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_OBJCPY_CMD) Extracting $(FMT_ANSIC_LIGHTRED)BIN$(FMT_ANSIC_END) file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_OBJCPY_CMD) Extracting $(FMT_ANSIC_LIGHTRED)BIN$(FMT_ANSIC_END) file data from $(FMT_FILENAME_BEGIN)\"$<\"$(MSG_NEWLINE) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature $(FLASH_DATA_OBJCOPY) $< $@ - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) ## : Extract SPMHelper in the last 32 Byte of the bootloader section to externally combine it with any bootloader spmhelper: $(TARGET).elf - @echo $(MSG_TIDY_PRE_FORMATTING) - @echo $(MSG_OBJCPY_CMD) Extracting $(FMT_ANSIC_LIGHTRED)SPM$(FMT_ANSIC_END) helper \ + @$(ECHO) $(MSG_TIDY_PRE_FORMATTING) + @$(ECHO) $(MSG_OBJCPY_CMD) Extracting $(FMT_ANSIC_LIGHTRED)SPM$(FMT_ANSIC_END) helper \ $(FMT_ANSIC_LIGHTRED)HEX$(FMT_ANSIC_END) file \ from $(FMT_FILENAME_BEGIN)$(TARGET).elf$(MSG_NEWLINE) - @echo $(MSG_TIDY_INTERMED_FORMATTING) + @$(ECHO) $(MSG_TIDY_INTERMED_FORMATTING) $(CROSS)-objcopy -O ihex -j .spmhelper $(SPM_HELPER_OBJCOPY) $(TARGET).elf $(TARGET).hex - @echo $(MSG_TIDY_POST_FORMATTING) + @$(ECHO) $(MSG_TIDY_POST_FORMATTING) ## : Program the device using avrdude program: $(TARGET).hex $(TARGET).eep check_size @@ -422,13 +431,13 @@ configure-chameleon-usb: UDEV_RULES_CONFIG_LINES:='\n ' configure-chameleon-usb: @mkdir -p $(TEMPDIR) && echo $(UDEV_RULES_CONFIG_LINES) > $(TEMPDIR)/98-ChameleonMini.rules - @echo "" - @echo "TO CONFIGURE THE CHAMELEON OVER USB, RUN THE FOLLOWING COMMANDS:" - @echo " $$ sudo cp $(TEMPDIR)/98-ChameleonMini.rules /etc/udev/rules.d/" - @echo " $$ sudo service udev restart" - @echo " $$ sudo udevadm control --reload" - @echo "" - @echo "FOR HELP TROUBLESHOOTING THE CHAMELEON USB CONNECTION, CONSIDER THE FOLLOWING OUTPUT:" - @echo " $$ dmesg | tail | grep -i dev" - @echo " $$ dmesg | tail | grep -i usb" - @echo " $$ sudo udevadm monitor" + @$(ECHO) "" + @$(ECHO) "TO CONFIGURE THE CHAMELEON OVER USB, RUN THE FOLLOWING COMMANDS:" + @$(ECHO) " $$ sudo cp $(TEMPDIR)/98-ChameleonMini.rules /etc/udev/rules.d/" + @$(ECHO) " $$ sudo service udev restart" + @$(ECHO) " $$ sudo udevadm control --reload" + @$(ECHO) "" + @$(ECHO) "FOR HELP TROUBLESHOOTING THE CHAMELEON USB CONNECTION, CONSIDER THE FOLLOWING OUTPUT:" + @$(ECHO) " $$ dmesg | tail | grep -i dev" + @$(ECHO) " $$ dmesg | tail | grep -i usb" + @$(ECHO) " $$ sudo udevadm monitor" From 39de8cc51c4d5b949166749fac9ec839a9ac4967 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Wed, 15 Jun 2022 18:54:58 -0400 Subject: [PATCH 55/68] ACR122U USB/PCSC reader stopped being responsive after all of the PM3 compat changes: Attempt to fix this problem (PM3 command support verified as still working) -- Cf. #313 --- Firmware/Chameleon-Mini/.gitignore | 19 ++++--- .../DESFire/DESFireISO14443Support.c | 49 +++++++++++++----- .../DESFire/DESFireISO14443Support.h | 6 ++- .../Application/DESFire/DESFireInstructions.h | 4 -- .../Application/DESFire/DESFireLogging.h | 12 +++++ .../Application/MifareDESFire.c | 34 +++++++++++++ .../Application/MifareDESFire.h | 24 ++++++--- .../BuildScripts/lufa_build_extra.mk | 11 ++-- Firmware/Chameleon-Mini/Log.h | 51 ++++++++++--------- Firmware/Chameleon-Mini/Makefile | 15 ++---- Software/ChamTool/Chameleon/Log.py | 5 +- 11 files changed, 157 insertions(+), 73 deletions(-) diff --git a/Firmware/Chameleon-Mini/.gitignore b/Firmware/Chameleon-Mini/.gitignore index 11e4750f..ec42b485 100644 --- a/Firmware/Chameleon-Mini/.gitignore +++ b/Firmware/Chameleon-Mini/.gitignore @@ -1,8 +1,11 @@ -/Chameleon-Mini.eep -/Chameleon-Mini.hex -/Chameleon-Mini.elf -/Chameleon-Mini.map -/Chameleon-Mini.bin -/Chameleon-Mini.lss -/Chameleon-Mini.sym -/Bin/ +Chameleon-Mini.eep +Chameleon-Mini.hex +Chameleon-Mini.elf +Chameleon-Mini.map +Chameleon-Mini.bin +Chameleon-Mini.lss +Chameleon-Mini.sym +Bin/ +Bin/* +Latest/ +Latest/* diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index 246dbab2..d91b7d0c 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -46,6 +46,8 @@ uint8_t LastReaderSentCmd = 0x00; uint8_t ISO14443ALastDataFrame[MAX_DATA_FRAME_XFER_SIZE] = { 0x00 }; uint16_t ISO14443ALastDataFrameBits = 0; +uint8_t ISO14443ALastIncomingDataFrame[MAX_DATA_FRAME_XFER_SIZE] = { 0x00 }; +uint16_t ISO14443ALastIncomingDataFrameBits = 0; bool CheckStateRetryCount2(bool resetByDefault, bool performLogging) { if (resetByDefault || ++StateRetryCount > MAX_STATE_RETRY_COUNT) { @@ -157,6 +159,8 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 case ISO14443_4_STATE_LAST: { return ISO14443A_APP_NO_RESPONSE; } + default: + break; } switch (PCB & ISO14443_PCB_BLOCK_TYPE_MASK) { @@ -186,9 +190,9 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 } Buffer[0] = PCB; /* Let the DESFire application code process the input data */ - ByteCount = MifareDesfireProcessCommand(Buffer + PrologueLength, ByteCount - PrologueLength); + ByteCount = MifareDesfireProcessCommand(&Buffer[PrologueLength], ByteCount - PrologueLength); /* Short-circuit in case the app decides not to respond at all */ - if (ByteCount == ISO14443A_APP_NO_RESPONSE) { + if (ByteCount == 0) { const char *debugPrintStr = PSTR("ISO14443-4: APP_NO_RESP"); LogDebuggingMsg(debugPrintStr); return ISO14443A_APP_NO_RESPONSE; @@ -295,6 +299,7 @@ void ISO144433AReset(void) { void ISO144433AHalt(void) { ISO144433ASwitchState(ISO14443_3A_STATE_HALT); Iso144433AIdleState = ISO14443_3A_STATE_HALT; + ISO144433AReset(); StateRetryCount = 0x00; } @@ -318,23 +323,25 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* Wakeup and Request may occure in all states */ bool checkStateRetryStatus = CheckStateRetryCount(false); bool incrementRetryCount = true; - if ((Cmd == ISO14443A_CMD_REQA) && (LastReaderSentCmd == ISO14443A_CMD_REQA) && !checkStateRetryStatus) { - /* Catch timing issues where the reader sends multiple - REQA bytes, in between which we would have already sent - back a response, so that we should not reset. */ + if (Cmd == ISO14443A_CMD_REQA) { + LOG_AT_LEVEL(LogEntry(LOG_INFO_APP_CMD_REQA, NULL, 0), VERBOSE); + //ISO144434Reset(); + ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); incrementRetryCount = false; - } else if (Cmd == ISO14443A_CMD_REQA || ISO14443ACmdIsWUPA(Cmd)) { - ISO144434Reset(); + } else if (ISO14443ACmdIsWUPA(Cmd)) { + LOG_AT_LEVEL(LogEntry(LOG_INFO_APP_CMD_WUPA, NULL, 0), VERBOSE); + //ISO144434Reset(); ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); incrementRetryCount = false; + //return ISO14443A_APP_NO_RESPONSE; } else if (ISO144433AIsHalt(Buffer, BitCount)) { - LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); + LOG_AT_LEVEL(LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0), VERBOSE); const char *logMsg = PSTR("ISO14443-3: HALTING"); LogDebuggingMsg(logMsg); - ISO144434Reset(); ISO144433AHalt(); return ISO14443A_APP_NO_RESPONSE; } + LastReaderSentCmd = Cmd; if (incrementRetryCount) { StateRetryCount += 1; @@ -424,8 +431,26 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { LogDebuggingMsg(logMsg); } else if (Cmd == ISO14443A_CMD_SELECT_CL3) { Buffer[0] = ISO14443A_SAK_COMPLETE_NOT_COMPLIANT; - ISO14443AAppendCRCA(Buffer, 1); + ISO14443AAppendCRCA(&Buffer[0], 1); return ISO14443A_SAK_FRAME_SIZE; + } else if (Cmd == ISO14443A_CMD_DESELECT) { + LOG_AT_LEVEL(LogEntry(LOG_INFO_APP_CMD_DESELECT, NULL, 0), VERBOSE); + /* See if the process can make sense of the first byte: */ + //uint16_t ByteCount = ASBYTES(BitCount); + //uint16_t ReturnBits = ISO144434ProcessBlock(Buffer, ByteCount, BitCount); + //if (ReturnBits > 0) { + // return ReturnBits; + //} + /* Otherwise (doesn't seem to work): Return a HALT frame to the reader: */ + //Buffer[0] = ISO14443A_CMD_HLTA; + //Buffer[1] = 0x00; + //ISO14443AAppendCRCA(&Buffer[0], 2); + //ISO144434SwitchState(ISO14443_3A_STATE_HALT); + //return ISO14443A_DESELECT_FRAME_SIZE; + /* Otherwise: Return a WUPA frame to the reader to reset: */ + //Buffer[0] = ISO14443A_CMD_WUPA; + //ISO144434SwitchState(ISO14443_3A_STATE_HALT); + //return ASBITS(1); } /* Forward to ISO/IEC 14443-4 processing code */ uint16_t ByteCount = ASBYTES(BitCount); @@ -439,7 +464,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { } - /* Unknown command. Reset back to idle/halt state. */ + /* Fallthrough: Unknown command. Reset back to idle/halt state. */ bool defaultReset = false; if (!CheckStateRetryCount(defaultReset)) { const char *logMsg = PSTR("ISO14443-3: RESET TO IDLE 0x%02x"); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index 06ae029b..c2a75a83 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -45,6 +45,8 @@ This notice must be retained at the top of all source files where indicated. #define ISO14443A_RATS_FRAME_SIZE ASBITS(6) /* Bit */ #define ISO14443A_CMD_RNAK 0xB2 #define ISO14443A_CRC_FRAME_SIZE ASBITS(ISO14443A_CRCA_SIZE) +#define ISO14443A_CMD_DESELECT 0xC2 +#define ISO14443A_DESELECT_FRAME_SIZE (ISO14443A_HLTA_FRAME_SIZE + ASBITS(ISO14443A_CRCA_SIZE)) #define ISO14443ACmdIsPM3WUPA(cmd) ((cmd & 0x54) == 0x54) #define ISO14443ACmdIsWUPA(cmd) ((cmd == ISO14443A_CMD_WUPA) || ISO14443ACmdIsPM3WUPA(cmd)) @@ -101,6 +103,8 @@ extern uint8_t LastReaderSentCmd; #define MAX_DATA_FRAME_XFER_SIZE (64) extern uint8_t ISO14443ALastDataFrame[MAX_DATA_FRAME_XFER_SIZE]; extern uint16_t ISO14443ALastDataFrameBits; +extern uint8_t ISO14443ALastIncomingDataFrame[MAX_DATA_FRAME_XFER_SIZE]; +extern uint16_t ISO14443ALastIncomingDataFrameBits; INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t BufferBitCount) { uint16_t ISO14443ALastDataFrameBytes = MIN((BufferBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE, MAX_DATA_FRAME_XFER_SIZE); @@ -113,7 +117,7 @@ INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t Buff /* Setup some fuzzy response handling for problematic readers like the ACR122U */ -#define MAX_STATE_RETRY_COUNT (0x0a) +#define MAX_STATE_RETRY_COUNT (0x0b) extern uint8_t StateRetryCount; bool CheckStateRetryCount(bool resetByDefault); bool CheckStateRetryCount2(bool resetByDefault, bool performLogging); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h index a31bf770..4dfe556c 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h @@ -104,10 +104,6 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { CMD_ISO7816_UPDATE_BINARY = 0xD6, CMD_ISO7816_APPEND_RECORD = 0xE2, - /* Space for undocumented command codes -- - * Need command codes and parameters to make these work moving forward: */ - //CMD_READ_SIGNATURE /* See page 87 of AN12343.pdf (for Mifare DESFire Light tags) */ - } DESFireCommandType; typedef uint16_t (*InsCodeHandlerFunc)(uint8_t *Buffer, uint16_t ByteCount); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h index 4385fd95..bf40b82d 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h @@ -52,6 +52,18 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { DEBUGGING = 3, } DESFireLoggingMode; +#ifndef DESFIRE_DEFAULT_LOGGING_MODE +#define DESFIRE_DEFAULT_LOGGING_MODE (OFF) +#endif + +#define LOG_AT_LEVEL(cmdToRun, loggingThreshold) ({ \ + do { \ + if (loggingThreshold >= DESFIRE_DEFAULT_LOGGING_MODE) { \ + cmdToRun; \ + } \ + } while(0); \ + }) + extern DESFireLoggingMode LocalLoggingMode; /* diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index bec1e62e..a266a482 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -47,6 +47,11 @@ This notice must be retained at the top of all source files where indicated. #define MIFARE_DESFIRE_EV1 (0x01) #define MIFARE_DESFIRE_EV2 (0x02) +#define IsControlCmd(Buffer, BitCount) \ + (BitCount > 0 && \ + ((Buffer[0] == ISO14443A_CMD_WUPA) || \ + (Buffer[0] == ISO14443A_CMD_REQA))) + DesfireStateType DesfireState = DESFIRE_HALT; DesfireStateType DesfirePreviousState = DESFIRE_IDLE; bool DesfireFromHalt = false; @@ -127,10 +132,15 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { if (ByteCount == 0) { return ISO14443A_APP_NO_RESPONSE; + } else if (MutualAuthenticateCmd(Buffer[0])) { + LastReaderSentCmd = Buffer[0]; } else if (Buffer[0] != STATUS_ADDITIONAL_FRAME) { DesfireState = DESFIRE_IDLE; + LastReaderSentCmd = Buffer[0]; uint16_t ReturnBytes = CallInstructionHandler(Buffer, ByteCount); return ReturnBytes; + } else { + LastReaderSentCmd = Buffer[0]; } uint16_t ReturnBytes = 0; @@ -153,6 +163,18 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { case DESFIRE_AES_AUTHENTICATE2: ReturnBytes = DesfireCmdAuthenticateAES2(Buffer, ByteCount); break; + case DESFIRE_ISO7816_EXT_AUTH: + DEBUG_PRINT_P(PSTR("TODO -- ISO7816-ExtAuth")); + ReturnBytes = ISO14443A_APP_NO_RESPONSE; + break; + case DESFIRE_ISO7816_INT_AUTH: + DEBUG_PRINT_P(PSTR("TODO -- ISO7816-IntAuth")); + ReturnBytes = ISO14443A_APP_NO_RESPONSE; + break; + case DESFIRE_ISO7816_GET_CHALLENGE: + DEBUG_PRINT_P(PSTR("TODO -- ISO7816-GetChall")); + ReturnBytes = ISO14443A_APP_NO_RESPONSE; + break; case DESFIRE_READ_DATA_FILE: ReturnBytes = ReadDataFileIterator(Buffer); break; @@ -226,6 +248,18 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t ReturnedBytes = 0; uint16_t ByteCount = ASBYTES(BitCount); LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); + if (ByteCount > 1 && + !memcmp(&Buffer[0], &ISO14443ALastIncomingDataFrame[0], MIN(ASBYTES(ISO14443ALastIncomingDataFrameBits), ByteCount))) { + /* The PCD resent the same data frame (probably a synchronization issue): + * Send out the same data as last time: + */ + memcpy(&Buffer[0], &ISO14443ALastDataFrame[0], ASBYTES(ISO14443ALastDataFrameBits)); + return ISO14443ALastDataFrameBits; + } else { + memcpy(&ISO14443ALastIncomingDataFrame[0], &Buffer[0], ByteCount); + ISO14443ALastIncomingDataFrameBits = BitCount; + LastReaderSentCmd = Buffer[0]; + } if (ByteCount >= 3 && Buffer[2] == STATUS_ADDITIONAL_FRAME && DesfireStateExpectingAdditionalFrame(DesfireState)) { /* [PM3-V1] : Handle the ISO-prologue-only-wrapped version of the additional frame data: */ diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.h b/Firmware/Chameleon-Mini/Application/MifareDESFire.h index 9c2974c0..59792dc8 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.h +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.h @@ -81,20 +81,28 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { DESFIRE_ISO_AUTHENTICATE2, DESFIRE_AES_AUTHENTICATE, DESFIRE_AES_AUTHENTICATE2, + DESFIRE_ISO7816_EXT_AUTH, + DESFIRE_ISO7816_INT_AUTH, + DESFIRE_ISO7816_GET_CHALLENGE, DESFIRE_READ_DATA_FILE, DESFIRE_WRITE_DATA_FILE, } DesfireStateType; -#define DesfireStateExpectingAdditionalFrame(dfState) \ - ((dfState == DESFIRE_GET_VERSION2) || \ - (dfState == DESFIRE_GET_VERSION3) || \ - (dfState == DESFIRE_GET_APPLICATION_IDS2) || \ - (dfState == DESFIRE_LEGACY_AUTHENTICATE2) || \ - (dfState == DESFIRE_ISO_AUTHENTICATE2) || \ - (dfState == DESFIRE_AES_AUTHENTICATE2) || \ - (dfState == DESFIRE_READ_DATA_FILE) || \ +#define DesfireStateExpectingAdditionalFrame(dfState) \ + ((dfState == DESFIRE_GET_VERSION2) || \ + (dfState == DESFIRE_GET_VERSION3) || \ + (dfState == DESFIRE_GET_APPLICATION_IDS2) || \ + (dfState == DESFIRE_LEGACY_AUTHENTICATE2) || \ + (dfState == DESFIRE_ISO_AUTHENTICATE2) || \ + (dfState == DESFIRE_AES_AUTHENTICATE2) || \ + (dfState == DESFIRE_READ_DATA_FILE) || \ (dfState == DESFIRE_WRITE_DATA_FILE)) +#define MutualAuthenticateCmd(cmdCode) \ + ((cmdCode == CMD_ISO7816_EXTERNAL_AUTHENTICATE) || \ + (cmdCode == CMD_ISO7816_INTERNAL_AUTHENTICATE) || \ + (cmdCode == CMD_ISO7816_GET_CHALLENGE)) + extern DesfireStateType DesfireState; extern DesfireStateType DesfirePreviousState; extern bool DesfireFromHalt; diff --git a/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk b/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk index 740d8b9e..bea9177c 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/lufa_build_extra.mk @@ -193,14 +193,17 @@ ifneq ($(UNKNOWN_SOURCE),) endif # Convert input source filenames into a list of required output object files -FWSRC_OBJECT_FILES := $(addsuffix .o, $(basename $(FULL_SOURCE))) -OBJECT_FILES += $(sort $(FWSRC_OBJECT_FILES)) -LUFA_OBJECT_FILES := $(addsuffix .o, $(basename $(LUFA_SRC))) +FWSRC_OBJECT_FILES := $(addsuffix .o, $(basename $(FULL_SOURCE))) +OBJECT_FILES += $(sort $(FWSRC_OBJECT_FILES)) +CHAMELEON_OBJECT_FILES := $(addsuffix .o, $(basename $(SRC))) +LUFA_OBJECT_FILES := $(addsuffix .o, $(basename $(LUFA_SRC))) # Check if an output object file directory was specified instead of the input file location ifneq ("$(OBJDIR)",".") # Prefix all the object filenames with the output object file directory path - OBJECT_FILES := $(addprefix $(patsubst %/,%,$(OBJDIR))/, $(notdir $(OBJECT_FILES))) + OBJECT_FILES := $(addprefix $(patsubst %/,%,$(OBJDIR))/, $(notdir $(OBJECT_FILES))) + CHAMELEON_OBJECT_FILES := $(addprefix $(patsubst %/,%,$(OBJDIR))/, $(notdir $(CHAMELEON_OBJECT_FILES))) + LUFA_OBJECT_FILES := $(addprefix $(patsubst %/,%,$(OBJDIR))/, $(notdir $(LUFA_OBJECT_FILES))) # Check if any object file (without path) appears more than once in the object file list ifneq ($(words $(sort $(OBJECT_FILES))), $(words $(OBJECT_FILES))) diff --git a/Firmware/Chameleon-Mini/Log.h b/Firmware/Chameleon-Mini/Log.h index c833d4d4..757ac6e6 100644 --- a/Firmware/Chameleon-Mini/Log.h +++ b/Firmware/Chameleon-Mini/Log.h @@ -19,38 +19,41 @@ extern uint16_t LogMemLeft; /** Enum for log entry type. \note Every entry type has a specific integer value, which can be found in the source code. */ typedef enum { /* Generic */ - LOG_INFO_GENERIC = 0x10, ///< Unspecific log entry. - LOG_INFO_CONFIG_SET = 0x11, ///< Configuration change. - LOG_INFO_SETTING_SET = 0x12, ///< Setting change. - LOG_INFO_UID_SET = 0x13, ///< UID change. - LOG_INFO_RESET_APP = 0x20, ///< Application reset. + LOG_INFO_GENERIC = 0x10, ///< Unspecific log entry. + LOG_INFO_CONFIG_SET = 0x11, ///< Configuration change. + LOG_INFO_SETTING_SET = 0x12, ///< Setting change. + LOG_INFO_UID_SET = 0x13, ///< UID change. + LOG_INFO_RESET_APP = 0x20, ///< Application reset. /* Codec */ - LOG_INFO_CODEC_RX_DATA = 0x40, ///< Currently active codec received data. - LOG_INFO_CODEC_TX_DATA = 0x41, ///< Currently active codec sent data. - 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 - LOG_INFO_CODEC_READER_FIELD_DETECTED = 0x48, ///< Add logging of the LEDHook case for FIELD_DETECTED + LOG_INFO_CODEC_RX_DATA = 0x40, ///< Currently active codec received data. + LOG_INFO_CODEC_TX_DATA = 0x41, ///< Currently active codec sent data. + 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 + LOG_INFO_CODEC_READER_FIELD_DETECTED = 0x48, ///< Add logging of the LEDHook case for FIELD_DETECTED /* App */ - LOG_INFO_APP_CMD_READ = 0x80, ///< Application processed read command. - LOG_INFO_APP_CMD_WRITE = 0x81, ///< Application processed write command. - LOG_INFO_APP_CMD_INC = 0x84, ///< Application processed increment command. - LOG_INFO_APP_CMD_DEC = 0x85, ///< Application processed decrement command. + LOG_INFO_APP_CMD_READ = 0x80, ///< Application processed read command. + LOG_INFO_APP_CMD_WRITE = 0x81, ///< Application processed write command. + LOG_INFO_APP_CMD_INC = 0x84, ///< Application processed increment command. + LOG_INFO_APP_CMD_DEC = 0x85, ///< Application processed decrement command. LOG_INFO_APP_CMD_TRANSFER = 0x86, ///< Application processed transfer command. LOG_INFO_APP_CMD_RESTORE = 0x87, ///< Application processed restore command. - LOG_INFO_APP_CMD_AUTH = 0x90, ///< Application processed authentication command. - LOG_INFO_APP_CMD_HALT = 0x91, ///< Application processed halt command. + LOG_INFO_APP_CMD_AUTH = 0x90, ///< Application processed authentication command. + LOG_INFO_APP_CMD_HALT = 0x91, ///< Application processed halt command. LOG_INFO_APP_CMD_UNKNOWN = 0x92, ///< Application processed an unknown command. - LOG_INFO_APP_AUTHING = 0xA0, ///< Application is in `authing` state. - LOG_INFO_APP_AUTHED = 0xA1, ///< Application is in `auth` state. - LOG_ERR_APP_AUTH_FAIL = 0xC0, ///< Application authentication failed. + LOG_INFO_APP_CMD_REQA = 0x93, ///< Application (ISO14443A handler) processed REQA. + LOG_INFO_APP_CMD_WUPA = 0x94, ///< Application (ISO14443A handler) processed WUPA. + LOG_INFO_APP_CMD_DESELECT = 0x95, ///< Application (ISO14443A handler) processed DESELECT. + LOG_INFO_APP_AUTHING = 0xA0, ///< Application is in `authing` state. + LOG_INFO_APP_AUTHED = 0xA1, ///< Application is in `auth` state. + LOG_ERR_APP_AUTH_FAIL = 0xC0, ///< Application authentication failed. LOG_ERR_APP_CHECKSUM_FAIL = 0xC1, ///< Application had a checksum fail. - LOG_ERR_APP_NOT_AUTHED = 0xC2, ///< Application is not authenticated. + LOG_ERR_APP_NOT_AUTHED = 0xC2, ///< Application is not authenticated. /* DESFire emulation and development related logging messages (0xEx): */ #ifdef CONFIG_MF_DESFIRE_SUPPORT diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 92955746..758de75d 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -282,7 +282,6 @@ LD_FLAGS = $(CC_FLAGS) \ -Wl,--section-start=.flashdata=$(FLASH_DATA_ADDR) \ -Wl,--section-start=.spmhelper=$(SPM_HELPER_ADDR) OBJDIR = Bin -LUFA_OBJDIR = LUFABin TEMPDIR = $(OBJDIR)/Temp OBJECT_FILES = FWROOT = ../.. @@ -395,18 +394,11 @@ style: --style=google --pad-oper --unpad-paren --pad-header \ --align-pointer=name {} \; -local-clean: BASH:=$(if $(shell which bash), $(shell which bash), /bin/bash) -local-clean: BASH_SCRIPT_EXEC_LINES:=' \ - for lufaobj in $$(ls $(LUFA_OBJDIR)); do \ - lobj_basename=$$(basename $$lufaobj); \ - ln -s $(LUFA_OBJDIR)/$$lobj_basename $(OBJDIR)/$$lobj_basename; \ - done \ - ' local-clean: @rm -f $(TARGET)*.{elf,hex,eep,bin,lss,map} - @rm -rf $(OBJDIR) $(LUFA_OBJ) - @mkdir -p $(OBJDIR) $(LUFA_OBJDIR) - @$(BASH) -c $(BASH_SCRIPT_EXEC_LINES) || $(SHELL) -c $(BASH_SCRIPT_EXEC_LINES) + ## : Try to avoid rebuilding the LUFA objects that rarely change: + @rm -f $(CHAMELEON_OBJECT_FILES) + @mkdir -p $(OBJDIR) clean: local-clean git-add-dev: LOCALFW_SOURCE_FILES:=Makefile ./*.{c,h} ./*/*.{c,h} ./*/*/*.{c,h} @@ -417,6 +409,7 @@ git-add-dev: @cd $(BUILD_SCR) && git add -f $(LOCALFW_BUILD_SCRIPT_FILES) @cd $(FWROOT)/Software/DESFireLibNFCTesting && make style && git add $(TESTING_SOURCE_FILES) @git add $(FWROOT)/Doc/DESFireSupportReadme.md + @cd $(FWROOT)/Software/ChamTool && git add ./*.py ./*/*.py configure-chameleon-usb: UDEV_RULES_CONFIG_LINES:='\n \ \# ChameleonMini (RevG)\n \ diff --git a/Software/ChamTool/Chameleon/Log.py b/Software/ChamTool/Chameleon/Log.py index 92043be0..18951ded 100644 --- a/Software/ChamTool/Chameleon/Log.py +++ b/Software/ChamTool/Chameleon/Log.py @@ -86,7 +86,10 @@ def binaryParityDecoder(data): 0x90: { 'name': 'APP AUTH', 'decoder': binaryDecoder }, 0x91: { 'name': 'APP HALT', 'decoder': binaryDecoder }, 0x92: { 'name': 'APP UNKNOWN', 'decoder': binaryDecoder }, - + 0x93: { 'name': 'APP REQA', 'decoder': binaryDecoser }, + 0x94: { 'name': 'APP WUPA', 'decoder': binaryDecoser }, + 0x95: { 'name': 'APP DESELECT', 'decoder': binaryDecoser }, + 0xA0: { 'name': 'APP AUTHING' , 'decoder': binaryDecoder }, 0xA1: { 'name': 'APP AUTHED', 'decoder': binaryDecoder }, From bbc489ee10425c0d0110ff8cf51f3cc6c1796042 Mon Sep 17 00:00:00 2001 From: "Maxie D. Schmidt" Date: Thu, 16 Jun 2022 02:31:32 -0400 Subject: [PATCH 56/68] Typo corrected --- Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h index bf40b82d..f4115bf9 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h @@ -58,7 +58,7 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { #define LOG_AT_LEVEL(cmdToRun, loggingThreshold) ({ \ do { \ - if (loggingThreshold >= DESFIRE_DEFAULT_LOGGING_MODE) { \ + if (loggingThreshold <= DESFIRE_DEFAULT_LOGGING_MODE) { \ cmdToRun; \ } \ } while(0); \ From 149599e2ac38d7caa26055ffdee1920beda5b3ca Mon Sep 17 00:00:00 2001 From: "Maxie D. Schmidt" Date: Thu, 16 Jun 2022 02:32:57 -0400 Subject: [PATCH 57/68] Cleaning up some old commented out macro definitions --- .../Application/DESFire/DESFireLogging.h | 62 ------------------- 1 file changed, 62 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h index f4115bf9..5dc8684f 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h @@ -150,68 +150,6 @@ void DebugPrintP(const char *fmt, ...); #define LogDebuggingMsg(msg) ({}) #endif -/*#define DesfireLogIncoming(incBuf, bitCount) ({ \ - uint8_t logLength = 0; \ - do { \ - logLength = BufferToHexString(__InternalStringBuffer, STRING_BUFFER_SIZE, \ - incBuf, (bitCount + 7) / 8); \ - snprintf_P(__InternalStringBuffer + logLength, PSTR(" [#=%d] <-- IN"), \ - bitCount); \ - logLength = StringLength(__InternalStringBuffer, STRING_BUFFER_SIZE); \ - DesfireLogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, __InternalStringBuffer, logLength); \ - } while(0); \ - }) - -#define DesfireLogOutgoing(incBuf, bitCount) ({ \ - uint8_t logLength = 0; \ - do { \ - logLength = BufferToHexString(__InternalStringBuffer, STRING_BUFFER_SIZE, \ - incBuf, (bitCount + 7) / 8); \ - snprintf_P(__InternalStringBuffer + logLength, PSTR(" [#=%d] --> OUT"), \ - bitCount); \ - logLength = StringLength(__InternalStringBuffer, STRING_BUFFER_SIZE); \ - DesfireLogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, __InternalStringBuffer, logLength); \ - } while(0); \ - }) -*/ - #define DesfireLogISOStateChange(state, logCode) ({}) -/*#define DesfireLogISOStateChange(state, logCode) ({ \ - const char *stateSymbName = NULL; \ - uint8_t logLength = 0x00; \ - do { \ - switch(state) { \ - case ISO14443_3A_STATE_IDLE: \ - stateSymbName = PSTR("ISO14443_3A_STATE_IDLE"); \ - break; \ - case ISO14443_3A_STATE_READY1: \ - stateSymbName = PSTR("ISO14443_3A_STATE_READY1"); \ - break; \ - case ISO14443_3A_STATE_READY2: \ - stateSymbName = PSTR("ISO14443_3A_STATE_READY2"); \ - break; \ - case ISO14443_3A_STATE_ACTIVE: \ - stateSymbName = PSTR("ISO14443_3A_STATE_ACTIVE"); \ - break; \ - case ISO14443_3A_STATE_HALT: \ - stateSymbName = PSTR("ISO14443_3A_STATE_HALT"); \ - break; \ - case ISO14443_4_STATE_EXPECT_RATS: \ - stateSymbName = PSTR("ISO14443_4_STATE_EXPECT_RATS"); \ - break; \ - case ISO14443_4_STATE_ACTIVE: \ - stateSymbName = PSTR("ISO14443_4_STATE_ACTIVE"); \ - break; \ - default: \ - stateSymbName = PSTR("UNKNOWN_STATE"); \ - break; \ - } \ - snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, PSTR(" => ")); \ - strcat_P(__InternalStringBuffer, stateSymbName); \ - logLength = StringLength(__InternalStringBuffer, STRING_BUFFER_SIZE); \ - DesfireLogEntry(logCode, __InternalStringBuffer, logLength); \ - } while(0); \ - }) -*/ #endif From 3806bcf05a2001732f73effcabbc543d98f78714 Mon Sep 17 00:00:00 2001 From: "Maxie D. Schmidt" Date: Wed, 22 Jun 2022 21:00:08 -0400 Subject: [PATCH 58/68] Delete DESFire_example.dmp This image is out of date -- Created using much older firmware sources. It eventually would be nice to replace it with a better dump using PR #319 sources (or more recent). --- Dumps/DESFire_example.dmp | Bin 4096 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Dumps/DESFire_example.dmp diff --git a/Dumps/DESFire_example.dmp b/Dumps/DESFire_example.dmp deleted file mode 100644 index 7c5741b2375c3d213c287f257bfa2b9d6538e273..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4096 zcmeHEZEnIa41H+>0tPEWd~|F=lQvBt_{k}_2q!@NWe3<#PK31M>Z0-P4_-i%F8EEie}7p^pI`@Q5KsD4aBi z3PP%H{`;}9%6b7;nUC!6xu4;6bjjIrzc;#vfp7CL= Date: Wed, 22 Jun 2022 21:00:18 -0400 Subject: [PATCH 59/68] Delete DESFire_example.contents This image is out of date -- Created using much older firmware sources. It eventually would be nice to replace it with a better dump using PR #319 sources (or more recent). --- Dumps/DESFire_example.contents | 72 ---------------------------------- 1 file changed, 72 deletions(-) delete mode 100644 Dumps/DESFire_example.contents diff --git a/Dumps/DESFire_example.contents b/Dumps/DESFire_example.contents deleted file mode 100644 index 0d09b264..00000000 --- a/Dumps/DESFire_example.contents +++ /dev/null @@ -1,72 +0,0 @@ ->>> Select Application By AID: - -> 90 5a 00 00 03 00 00 00 | 00 - <- 91 00 - ->>> Start AES Authenticate: - -> 90 aa 00 00 01 00 00 - <- 35 a1 bf c7 9b e3 3b 29 | 35 9b 37 57 ed 35 88 b9 | 91 af - -- RNDA = f4 2d 68 bf bb 3e 87 12 - -- RNDB = 0d 3e 90 75 5c 6d d5 22 - -- CHAL = f4 2d 68 bf bb 3e 87 12 | 22 0d 3e 90 75 5c 6d d5 - -> 90 af 00 00 10 72 15 a8 | 83 46 4c 69 f9 50 c4 7b | a8 e7 30 a7 68 00 - <- 0d b4 4f 21 52 89 bc 84 | 25 3b ef bc 54 15 90 11 | 91 00 - ... AUTH OK! :) - ->>> CreateApplication command: - -> 90 ca 00 00 05 01 00 34 | 0f 03 00 - <- 91 00 ->>> Select Application By AID: - -> 90 5a 00 00 03 01 00 34 | 00 - <- 91 00 - ->>> Start AES Authenticate: - -> 90 aa 00 00 01 00 00 - <- b0 82 2a 30 c2 b6 1f d0 | f9 68 33 c9 4b 26 24 20 | 91 af - -- RNDA = c3 70 32 58 4c 06 ef f2 - -- RNDB = 2e 7d 6c 67 ae 32 cc f7 - -- CHAL = c3 70 32 58 4c 06 ef f2 | f7 2e 7d 6c 67 ae 32 cc - -> 90 af 00 00 10 68 49 4a | c5 1d 75 02 f2 79 23 18 | b8 15 18 21 32 00 - <- 6a 61 d5 7e 97 09 35 89 | 7d 10 87 d3 04 8e 20 47 | 91 00 - ... AUTH OK! :) - ->>> CreateStdDataFile command: - -> 90 cd 00 00 07 00 00 0f | 00 04 00 00 00 - <- 91 00 - ->>> CreateBackupDataFile command: - -> 90 cb 00 00 07 01 00 0f | 00 08 00 00 00 - <- 91 00 - ->>> CreateValueFile command: - -> 90 cc 00 00 11 02 00 0f | 00 00 00 00 00 00 01 00 | 00 80 00 00 00 01 00 - <- 91 00 - ->>> CreateLinearRecordFile command: - -> 90 c1 00 00 0a 03 00 0f | 00 04 00 00 0c 00 00 00 - <- 91 00 - ->>> CreateCyclicRecordFile command: - -> 90 c0 00 00 0a 04 00 0f | 00 01 00 00 05 00 00 00 - <- 91 00 - ->>> GetFileIds command: - -> 90 6f 00 00 00 00 - <- 00 01 02 03 04 91 00 ->>> DeleteFile command: - -> 90 df 00 00 01 01 00 - <- 91 00 ->>> GetFileIds command: - -> 90 6f 00 00 00 00 - <- 00 02 03 04 91 00 ->>> GetFileSettings command: - -> 90 f5 00 00 01 00 00 - <- 00 00 0f 00 04 00 00 91 | 00 ->>> GetFileSettings command: - -> 90 f5 00 00 01 02 00 - <- 02 00 0f 00 00 00 00 00 | 00 01 00 00 80 00 00 00 | 01 91 00 ->>> GetFileSettings command: - -> 90 f5 00 00 01 03 00 - <- 03 00 0f 00 04 00 00 0c | 00 00 00 00 00 91 00 ->>> GetFileSettings command: - -> 90 f5 00 00 01 04 00 - <- 04 00 0f 00 01 00 00 05 | 00 00 00 00 00 91 00 From 7f37bfb43719043d230b49d2185a921a7f086fe0 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Tue, 28 Jun 2022 11:59:03 -0400 Subject: [PATCH 60/68] Updating source after the feedback from @fptrs in PR #319 --- .../Chameleon-Mini/Application/Sniff15693.c | 62 +++++++++---------- .../Chameleon-Mini/Application/Sniff15693.h | 2 +- .../BuildScripts/custom_build_targets.mk | 2 +- .../Chameleon-Mini/Codec/SniffISO14443-2A.c | 2 +- Firmware/Chameleon-Mini/Codec/SniffISO15693.c | 28 ++++----- Firmware/Chameleon-Mini/Configuration.c | 12 ++-- Firmware/Chameleon-Mini/Terminal/Commands.c | 12 ++-- 7 files changed, 57 insertions(+), 63 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/Sniff15693.c b/Firmware/Chameleon-Mini/Application/Sniff15693.c index db4e218a..c84ba6f7 100644 --- a/Firmware/Chameleon-Mini/Application/Sniff15693.c +++ b/Firmware/Chameleon-Mini/Application/Sniff15693.c @@ -66,41 +66,36 @@ static uint16_t recent_th = 0; static bool last_cycle_successful = false; -void SniffISO15693AppTimeout(void) -{ +void SniffISO15693AppTimeout(void) { CodecThresholdSet(recent_th); SniffISO15693AppReset(); } -void SniffISO15693AppInit(void) -{ +void SniffISO15693AppInit(void) { Sniff15693CurrentCommand = Sniff15693_Do_Nothing; autocalib_state = AUTOCALIB_INIT; } -void SniffISO15693AppReset(void) -{ +void SniffISO15693AppReset(void) { SniffISO15693AppInit(); } -void SniffISO15693AppTask(void) -{ - +void SniffISO15693AppTask(void) { + } -void SniffISO15693AppTick(void) -{ +void SniffISO15693AppTick(void) { } -INLINE void SniffISO15693InitAutocalib(void){ +INLINE void SniffISO15693InitAutocalib(void) { uint16_t floor_noise = SniffISO15693GetFloorNoise(); /* We search b/w: */ /* 0.5 * DemodFloorNoiseLevel --> 1.5 * DemodFloorNoiseLevel */ min_th = floor_noise >> 1; max_th = floor_noise + (floor_noise >> 1); - if(min_th >= max_th) { + if (min_th >= max_th) { min_th = 0; max_th = 0xFFF; } @@ -125,10 +120,10 @@ INLINE void SniffISO15693InitAutocalib(void){ return; } -INLINE void SniffISO15693FinishAutocalib(void){ +INLINE void SniffISO15693FinishAutocalib(void) { uint16_t new_th; CommandStatusIdType ReturnStatusID = COMMAND_ERR_INVALID_USAGE_ID; - if(min_succ_th > 0) { + if (min_succ_th > 0) { /* In this case AUTOCALIBRATION was successfull */ new_th = (min_succ_th + max_succ_th) >> 1; CodecThresholdSet(new_th); @@ -140,7 +135,7 @@ INLINE void SniffISO15693FinishAutocalib(void){ } #endif /*#ifdef ISO15693_DEBUG_LOG*/ ReturnStatusID = COMMAND_INFO_OK_WITH_TEXT_ID; - }else{ + } else { /* This means we never received a valid frame - Error*/ CodecThresholdSet(recent_th); /* ReturnStatusID already set to error code */ @@ -149,7 +144,7 @@ INLINE void SniffISO15693FinishAutocalib(void){ CommandLinePendingTaskFinished(ReturnStatusID, NULL); } -INLINE void SniffISO15693IncrementThreshold(void){ +INLINE void SniffISO15693IncrementThreshold(void) { /* So increment the threshold */ /* Steps of 3*16=48 are sufficient for us */ @@ -162,17 +157,16 @@ INLINE void SniffISO15693IncrementThreshold(void){ LogEntry(LOG_INFO_GENERIC, str, strlen(str)); } #endif /*#ifdef ISO15693_DEBUG_LOG*/ - if(curr_th >= max_th) { + if (curr_th >= max_th) { /* We are finished now */ /* Evaluate the results */ SniffISO15693FinishAutocalib(); } } -uint16_t SniffISO15693AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) -{ +uint16_t SniffISO15693AppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) { - bool crc_chk = ISO15693CheckCRC(FrameBuf, FrameBytes-ISO15693_CRC16_SIZE); + bool crc_chk = ISO15693CheckCRC(FrameBuf, FrameBytes - ISO15693_CRC16_SIZE); #ifdef ISO15693_DEBUG_LOG char str[64]; @@ -185,31 +179,31 @@ uint16_t SniffISO15693AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) return 0; } case Sniff15693_Autocalibrate: { - switch(autocalib_state){ - case(AUTOCALIB_INIT): + switch (autocalib_state) { + case (AUTOCALIB_INIT): SniffISO15693InitAutocalib(); - if(SniffTrafficSource == TRAFFIC_CARD) + if (SniffTrafficSource == TRAFFIC_CARD) autocalib_state = AUTOCALIB_CARD_DATA; else autocalib_state = AUTOCALIB_READER_DATA; break; - case(AUTOCALIB_READER_DATA): /* Means last time we have received reader data */ - if(SniffTrafficSource == TRAFFIC_READER){ + case (AUTOCALIB_READER_DATA): /* Means last time we have received reader data */ + if (SniffTrafficSource == TRAFFIC_READER) { /* Second time Reader Data received */ /* This means no card data received */ /* If we had successful tries before */ /* we need to record it as threshold max here */ - if(last_cycle_successful == true){ + if (last_cycle_successful == true) { max_succ_th = GlobalSettings.ActiveSettingPtr->ReaderThreshold - - CODEC_THRESHOLD_CALIBRATE_STEPS; + CODEC_THRESHOLD_CALIBRATE_STEPS; #ifdef ISO15693_DEBUG_LOG sprintf(str, "Sniff15693: Updated max_succ_th (%d) ", max_succ_th); LogEntry(LOG_INFO_GENERIC, str, strlen(str)); #endif /*#ifdef ISO15693_DEBUG_LOG*/ } last_cycle_successful = false; - }else{ - if (crc_chk){ + } else { + if (crc_chk) { /* We have received card data now */ /* Threshold is in a good range */ /* if min_succ_th was never set ( == 0) */ @@ -226,9 +220,9 @@ uint16_t SniffISO15693AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) } SniffISO15693IncrementThreshold(); break; - case(AUTOCALIB_CARD_DATA): /* Means last time we have received card data */ - if(SniffTrafficSource == TRAFFIC_CARD){ - if (crc_chk){ + case (AUTOCALIB_CARD_DATA): /* Means last time we have received card data */ + if (SniffTrafficSource == TRAFFIC_CARD) { + if (crc_chk) { /* We have received card data now */ /* Threshold is in a good range */ /* if min_succ_th was never set ( == 0) */ @@ -242,7 +236,7 @@ uint16_t SniffISO15693AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) LogEntry(LOG_INFO_GENERIC, str, strlen(str)); #endif /*#ifdef ISO15693_DEBUG_LOG*/ SniffISO15693IncrementThreshold(); - }else{ + } else { autocalib_state = AUTOCALIB_READER_DATA; } break; diff --git a/Firmware/Chameleon-Mini/Application/Sniff15693.h b/Firmware/Chameleon-Mini/Application/Sniff15693.h index f809a67c..e8662a04 100644 --- a/Firmware/Chameleon-Mini/Application/Sniff15693.h +++ b/Firmware/Chameleon-Mini/Application/Sniff15693.h @@ -15,7 +15,7 @@ void SniffISO15693AppInit(void); void SniffISO15693AppReset(void); void SniffISO15693AppTask(void); void SniffISO15693AppTick(void); -uint16_t SniffISO15693AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes); +uint16_t SniffISO15693AppProcess(uint8_t *FrameBuf, uint16_t FrameBytes); void SniffISO15693AppTimeout(void); typedef enum { diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index a22884cf..0c048e68 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -10,7 +10,7 @@ endif DEFAULT_TAG_SUPPORT_BASE = -DCONFIG_ISO14443A_SNIFF_SUPPORT \ -DCONFIG_ISO14443A_READER_SUPPORT -SUPPORTED_TAGS_BUILD = +SUPPORTED_TAGS_BUILD = $(DEFAULT_TAG_SUPPORT_BASE) EXTRA_CONFIG_SETTINGS = custom-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bin check_size diff --git a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c index f0f1367f..5a33692d 100644 --- a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c +++ b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c @@ -342,7 +342,7 @@ INLINE void Insert1(void) { } // This interrupt find Card -> Reader SOC -ISR_SHARED isr_SniffISO14443_2A_ACA_AC0_VECT (void) { // this interrupt either finds the SOC or gets triggered before +ISR_SHARED isr_SniffISO14443_2A_ACA_AC0_VECT(void) { // this interrupt either finds the SOC or gets triggered before ACA.AC0CTRL &= ~AC_INTLVL_HI_gc; // disable this interrupt // enable the pause-finding timer CODEC_TIMER_LOADMOD.CTRLD = TC_EVACT_RESTART_gc | TC_EVSEL_CH2_gc; diff --git a/Firmware/Chameleon-Mini/Codec/SniffISO15693.c b/Firmware/Chameleon-Mini/Codec/SniffISO15693.c index 60026db0..5a02fc23 100644 --- a/Firmware/Chameleon-Mini/Codec/SniffISO15693.c +++ b/Firmware/Chameleon-Mini/Codec/SniffISO15693.c @@ -275,10 +275,10 @@ INLINE void SNIFF_ISO15693_READER_EOC_VCD(void) { /* Inline function to set the threshold, if bAutoThreshold is enabled*/ -INLINE void SetDacCh0Data(uint16_t ch0data){ +INLINE void SetDacCh0Data(uint16_t ch0data) { /* TODO: Check if either of the branches can be avoided */ /* to optimize the performance */ - if(bAutoThreshold){ + if (bAutoThreshold) { if (ch0data < 0xFFF) DACB.CH0DATA = ch0data; else @@ -642,14 +642,14 @@ ISR_SHARED isr_SNIFF_ISO15693_CODEC_TIMER_LOADMOD_OVF_VECT(void) { CardSniffDeinit(); } else { - DataRegister = ( (SampleRegisterL & 0b00000011) == 0b00000001) << 3; - DataRegister |= ( (SampleRegisterL & 0b00001100) == 0b00000100) << 2; - DataRegister |= ( (SampleRegisterL & 0b00110000) == 0b00010000) << 1; - DataRegister |= ( (SampleRegisterL & 0b11000000) == 0b01000000); /* Bottom 2 bits */ - DataRegister |= ( (SampleRegisterH & 0b00000011) == 0b00000001) << 7; - DataRegister |= ( (SampleRegisterH & 0b00001100) == 0b00000100) << 6; - DataRegister |= ( (SampleRegisterH & 0b00110000) == 0b00010000) << 5; - DataRegister |= ( (SampleRegisterH & 0b11000000) == 0b01000000) << 4; + DataRegister = ((SampleRegisterL & 0b00000011) == 0b00000001) << 3; + DataRegister |= ((SampleRegisterL & 0b00001100) == 0b00000100) << 2; + DataRegister |= ((SampleRegisterL & 0b00110000) == 0b00010000) << 1; + DataRegister |= ((SampleRegisterL & 0b11000000) == 0b01000000); /* Bottom 2 bits */ + DataRegister |= ((SampleRegisterH & 0b00000011) == 0b00000001) << 7; + DataRegister |= ((SampleRegisterH & 0b00001100) == 0b00000100) << 6; + DataRegister |= ((SampleRegisterH & 0b00110000) == 0b00010000) << 5; + DataRegister |= ((SampleRegisterH & 0b11000000) == 0b01000000) << 4; *CodecBufferPtr = DataRegister; CodecBufferPtr++; @@ -710,7 +710,7 @@ void SniffISO15693CodecInit(void) { Function used by the Terminal command to display (GET) the state of the Autothreshold Feature. ************************************************************/ -bool SniffISO15693GetAutoThreshold(void){ +bool SniffISO15693GetAutoThreshold(void) { return bAutoThreshold; } @@ -720,7 +720,7 @@ bool SniffISO15693GetAutoThreshold(void){ If it is disabled: The threshold will be taken from GlobalSettings.ActiveSettingPtr->ReaderThreshold ************************************************************/ -void SniffISO15693CtrlAutoThreshold(bool enable){ +void SniffISO15693CtrlAutoThreshold(bool enable) { bAutoThreshold = enable; return; } @@ -730,7 +730,7 @@ void SniffISO15693CtrlAutoThreshold(bool enable){ FloorNoise can be used to define the scanning range for the Autocalibration. ************************************************************/ -uint16_t SniffISO15693GetFloorNoise(void){ +uint16_t SniffISO15693GetFloorNoise(void) { return DemodFloorNoiseLevel; } @@ -784,7 +784,7 @@ void SniffISO15693CodecTask(void) { } - if(Flags.CardDemodFinished) { + if (Flags.CardDemodFinished) { Flags.CardDemodFinished = 0; if (CardByteCount > 0) { diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index cdc5ac86..79c18f50 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -335,12 +335,12 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .CodecInitFunc = ISO15693CodecInit, .CodecDeInitFunc = ISO15693CodecDeInit, .CodecTaskFunc = ISO15693CodecTask, - .ApplicationInitFunc = ApplicationInitDummy, - .ApplicationInitRunOnceFunc = ApplicationInitDummy, - .ApplicationResetFunc = ApplicationResetDummy, - .ApplicationTaskFunc = ApplicationTaskDummy, - .ApplicationTickFunc = ApplicationTickDummy, - .ApplicationProcessFunc = ApplicationProcessDummy, + .ApplicationInitFunc = SniffISO15693AppInit, + .ApplicationInitRunOnceFunc = SniffISO15693AppInit, + .ApplicationResetFunc = SniffISO15693AppReset, + .ApplicationTaskFunc = SniffISO15693AppTask, + .ApplicationTickFunc = SniffISO15693AppTick, + .ApplicationProcessFunc = SniffISO15693AppProcess, .ApplicationGetUidFunc = ApplicationGetUidDummy, .ApplicationSetUidFunc = ApplicationSetUidDummy, .UidSize = 0, diff --git a/Firmware/Chameleon-Mini/Terminal/Commands.c b/Firmware/Chameleon-Mini/Terminal/Commands.c index 9cb10167..7b5ccb28 100644 --- a/Firmware/Chameleon-Mini/Terminal/Commands.c +++ b/Firmware/Chameleon-Mini/Terminal/Commands.c @@ -663,7 +663,7 @@ CommandStatusIdType CommandExecAutocalibrate(char *OutMessage) { /* Only execute autocalibration if the codec does not use autothreshold */ /* It needs to be disabled by the AUTOTHRESHOLD=DISABLE command */ if ((GlobalSettings.ActiveSettingPtr->Configuration == CONFIG_ISO15693_SNIFF) && - (SniffISO15693GetAutoThreshold() == false)){ + (SniffISO15693GetAutoThreshold() == false)) { ApplicationReset(); Sniff15693CurrentCommand = Sniff15693_Autocalibrate; @@ -694,25 +694,25 @@ CommandStatusIdType CommandExecClone(char *OutMessage) { #endif #ifdef CONFIG_ISO15693_SNIFF_SUPPORT -CommandStatusIdType CommandGetAutoThreshold(char *OutParam){ +CommandStatusIdType CommandGetAutoThreshold(char *OutParam) { /* Only Execute the command if the current configuration is CONFIG_ISO15693_SNIFF */ if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO15693_SNIFF) return COMMAND_ERR_INVALID_USAGE_ID; /* Get Autothreshold mode */ - if(SniffISO15693GetAutoThreshold()) + if (SniffISO15693GetAutoThreshold()) snprintf(OutParam, TERMINAL_BUFFER_SIZE, "%c (enabled)", COMMAND_CHAR_TRUE); else snprintf(OutParam, TERMINAL_BUFFER_SIZE, "%c - (disabled)", COMMAND_CHAR_FALSE); /* In case of overflow, snprintf does not write the terminating '\0' */ /* so we should make sure it gets terminated */ - OutParam[TERMINAL_BUFFER_SIZE-1] = '\0'; + OutParam[TERMINAL_BUFFER_SIZE - 1] = '\0'; return COMMAND_INFO_OK_WITH_TEXT_ID; } -CommandStatusIdType CommandSetAutoThreshold(char *OutMessage, const char *InParam){ +CommandStatusIdType CommandSetAutoThreshold(char *OutMessage, const char *InParam) { /* Only Execute the command if the current configuration is CONFIG_ISO15693_SNIFF */ if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO15693_SNIFF) @@ -722,7 +722,7 @@ CommandStatusIdType CommandSetAutoThreshold(char *OutMessage, const char *InPara snprintf(OutMessage, TERMINAL_BUFFER_SIZE, "%c (enable), %c (disable)", COMMAND_CHAR_TRUE, COMMAND_CHAR_FALSE); /* In case of overflow, snprintf does not write the terminating '\0' */ /* so we should make sure it gets terminated */ - OutMessage[TERMINAL_BUFFER_SIZE-1] = '\0'; + OutMessage[TERMINAL_BUFFER_SIZE - 1] = '\0'; return COMMAND_INFO_OK_WITH_TEXT_ID; } else if (InParam[0] == COMMAND_CHAR_TRUE) { SniffISO15693CtrlAutoThreshold(true); From 688b4942b4452b5626fc50f98ea8010bb9c93ff9 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Wed, 29 Jun 2022 04:50:39 -0400 Subject: [PATCH 61/68] More typ corrections and build script bug fixes annotated in #319 --- .../BuildScripts/custom_build_targets.mk | 48 ++++++++++--------- Firmware/Chameleon-Mini/Configuration.c | 6 +-- Software/ChamTool/Chameleon/Log.py | 2 +- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index 0c048e68..963887ea 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -8,9 +8,10 @@ else ECHOFLAGS=-e endif -DEFAULT_TAG_SUPPORT_BASE = -DCONFIG_ISO14443A_SNIFF_SUPPORT \ - -DCONFIG_ISO14443A_READER_SUPPORT -SUPPORTED_TAGS_BUILD = $(DEFAULT_TAG_SUPPORT_BASE) +DEFAULT_TAG_SUPPORT_BASE = -DCONFIG_ISO14443A_SNIFF_SUPPORT \ + -DCONFIG_ISO14443A_READER_SUPPORT \ + -DCONFIG_MF_ULTRALIGHT_SUPPORT +SUPPORTED_TAGS_BUILD = EXTRA_CONFIG_SETTINGS = custom-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bin check_size @@ -29,22 +30,22 @@ custom-build: local-clean $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).bi " 💯 "$(FMT_ANSIC_BOLD)"$(TARGET)-CustomBuild_$(TARGET_CUSTOM_BUILD_NAME).(HEX|EEP|ELF|BIN)"$(FMT_ANSIC_END) @$(ECHO) "\n" -mifare: SUPPORTED_TAGS_BUILD:=\ +mifare: SUPPORTED_TAGS_BUILD:= \ -DCONFIG_MF_CLASSIC_MINI_4B_SUPPORT \ - -DCONFIG_MF_CLASSIC_1K_SUPPORT \ - -DCONFIG_MF_CLASSIC_1K_7B_SUPPORT \ - -DCONFIG_MF_CLASSIC_4K_SUPPORT \ - -DCONFIG_MF_CLASSIC_4K_7B_SUPPORT \ + -DCONFIG_MF_CLASSIC_1K_SUPPORT \ + -DCONFIG_MF_CLASSIC_1K_7B_SUPPORT \ + -DCONFIG_MF_CLASSIC_4K_SUPPORT \ + -DCONFIG_MF_CLASSIC_4K_7B_SUPPORT \ -DCONFIG_MF_ULTRALIGHT_SUPPORT mifare: TARGET_CUSTOM_BUILD_NAME:=MifareDefaultSupport mifare: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) mifare: custom-build -mifare-classic: SUPPORTED_TAGS_BUILD:=\ +mifare-classic: SUPPORTED_TAGS_BUILD:= \ -DCONFIG_MF_CLASSIC_MINI_4B_SUPPORT \ - -DCONFIG_MF_CLASSIC_1K_SUPPORT \ - -DCONFIG_MF_CLASSIC_1K_7B_SUPPORT \ - -DCONFIG_MF_CLASSIC_4K_SUPPORT \ + -DCONFIG_MF_CLASSIC_1K_SUPPORT \ + -DCONFIG_MF_CLASSIC_1K_7B_SUPPORT \ + -DCONFIG_MF_CLASSIC_4K_SUPPORT \ -DCONFIG_MF_CLASSIC_4K_7B_SUPPORT mifare-classic: TARGET_CUSTOM_BUILD_NAME:=MifareClassicSupport mifare-classic: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) @@ -52,30 +53,31 @@ mifare-classic: custom-build desfire: FLASH_DATA_SIZE:=0x0E000 desfire: SUPPORTED_TAGS_BUILD:=-DCONFIG_MF_DESFIRE_SUPPORT -desfire: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ +desfire: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ -DDESFIRE_CRYPTO1_SAVE_SPACE \ - -finline-small-functions + -finline-small-functions desfire: TARGET_CUSTOM_BUILD_NAME:=DESFire desfire: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) desfire: custom-build desfire-dev: FLASH_DATA_SIZE:=0x0E000 desfire-dev: SUPPORTED_TAGS_BUILD:=-DCONFIG_MF_DESFIRE_SUPPORT -desfire-dev: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ - -DDESFIRE_CRYPTO1_SAVE_SPACE \ - -finline-small-functions \ - -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ - -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ +desfire-dev: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ + -DDESFIRE_CRYPTO1_SAVE_SPACE \ + -finline-small-functions \ + -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ + -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING \ -DDESFIRE_DEFAULT_TESTING_MODE=1 desfire-dev: TARGET_CUSTOM_BUILD_NAME:=DESFire_DEV desfire-dev: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) desfire-dev: custom-build -iso-modes: SUPPORTED_TAGS_BUILD:=\ - -DCONFIG_ISO14443A_SNIFF_SUPPORT \ +iso-modes: SUPPORTED_TAGS_BUILD:= \ + -DCONFIG_ISO14443A_SNIFF_SUPPORT \ -DCONFIG_ISO14443A_READER_SUPPORT \ - -DCONFIG_ISO15693_SNIFF_SUPPORT + -DCONFIG_ISO15693_SNIFF_SUPPORT \ + -DCONFIG_MF_ULTRALIGHT_SUPPORT iso-modes: TARGET_CUSTOM_BUILD_NAME:=ISOSniffReaderModeSupport iso-modes: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) iso-modes: custom-build @@ -96,7 +98,7 @@ sl2s2002: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFI sl2s2002: custom-build tagatit: SUPPORTED_TAGS_BUILD:=$(DEFAULT_TAG_SUPPORT_BASE) \ - -DCONFIG_TITAGITSTANDARD_SUPPORT \ + -DCONFIG_TITAGITSTANDARD_SUPPORT \ -DCONFIG_TITAGITPLUS_SUPPORT tagatit: TARGET_CUSTOM_BUILD_NAME:=TagatitSupport tagatit: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index 79c18f50..fe804ab4 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -332,9 +332,9 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { #endif #ifdef CONFIG_ISO15693_SNIFF_SUPPORT [CONFIG_ISO15693_SNIFF] = { - .CodecInitFunc = ISO15693CodecInit, - .CodecDeInitFunc = ISO15693CodecDeInit, - .CodecTaskFunc = ISO15693CodecTask, + .CodecInitFunc = SniffISO15693CodecInit, + .CodecDeInitFunc = SniffISO15693CodecDeInit, + .CodecTaskFunc = SniffISO15693CodecTask, .ApplicationInitFunc = SniffISO15693AppInit, .ApplicationInitRunOnceFunc = SniffISO15693AppInit, .ApplicationResetFunc = SniffISO15693AppReset, diff --git a/Software/ChamTool/Chameleon/Log.py b/Software/ChamTool/Chameleon/Log.py index 60273993..3fd0c466 100644 --- a/Software/ChamTool/Chameleon/Log.py +++ b/Software/ChamTool/Chameleon/Log.py @@ -87,7 +87,7 @@ def binaryParityDecoder(data): 0x90: { 'name': 'APP AUTH', 'decoder': binaryDecoder }, 0x91: { 'name': 'APP HALT', 'decoder': binaryDecoder }, 0x92: { 'name': 'APP UNKNOWN', 'decoder': binaryDecoder }, - 0x93: { 'name': 'APP REQA', 'decoder': binaryDecoser }, + 0x93: { 'name': 'APP REQA', 'decoder': binaryDecoder }, 0x94: { 'name': 'APP WUPA', 'decoder': binaryDecoser }, 0x95: { 'name': 'APP DESELECT', 'decoder': binaryDecoser }, From 40da00ae69f3b77327e3c4aa61c194fdccf8f2b0 Mon Sep 17 00:00:00 2001 From: fptrs <48245105+fptrs@users.noreply.github.com> Date: Wed, 29 Jun 2022 11:12:29 +0200 Subject: [PATCH 62/68] fix typos --- Software/ChamTool/Chameleon/Log.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Software/ChamTool/Chameleon/Log.py b/Software/ChamTool/Chameleon/Log.py index 3fd0c466..4b0fdb81 100644 --- a/Software/ChamTool/Chameleon/Log.py +++ b/Software/ChamTool/Chameleon/Log.py @@ -88,8 +88,8 @@ def binaryParityDecoder(data): 0x91: { 'name': 'APP HALT', 'decoder': binaryDecoder }, 0x92: { 'name': 'APP UNKNOWN', 'decoder': binaryDecoder }, 0x93: { 'name': 'APP REQA', 'decoder': binaryDecoder }, - 0x94: { 'name': 'APP WUPA', 'decoder': binaryDecoser }, - 0x95: { 'name': 'APP DESELECT', 'decoder': binaryDecoser }, + 0x94: { 'name': 'APP WUPA', 'decoder': binaryDecoder }, + 0x95: { 'name': 'APP DESELECT', 'decoder': binaryDecoder }, 0xA0: { 'name': 'APP AUTHING' , 'decoder': binaryDecoder }, 0xA1: { 'name': 'APP AUTHED', 'decoder': binaryDecoder }, From b6f40946c59fa9695327ea39c8de268db070eaef Mon Sep 17 00:00:00 2001 From: fptrs <48245105+fptrs@users.noreply.github.com> Date: Wed, 29 Jun 2022 11:36:35 +0200 Subject: [PATCH 63/68] add missing sources for ISO15693_SNIFF --- Firmware/Chameleon-Mini/Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 758de75d..3965ffe6 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -215,7 +215,8 @@ SRC += Codec/Codec.c \ Codec/Reader14443-2A.c \ Codec/SniffISO14443-2A.c \ Codec/Reader14443-ISR.S \ - Codec/ISO15693.c + Codec/ISO15693.c \ + Codec/SniffISO15693.c SRC += Application/MifareUltralight.c \ Application/MifareClassic.c \ Application/ISO14443-3A.c \ @@ -232,7 +233,8 @@ SRC += Application/Vicinity.c \ Application/TITagitstandard.c \ Application/TITagitplus.c \ Application/ISO15693-A.c \ - Application/EM4233.c + Application/EM4233.c \ + Application/Sniff15693.c SRC += Application/DESFire/../MifareDESFire.c \ Application/DESFire/DESFireApplicationDirectory.c \ Application/DESFire/DESFireChameleonTerminal.c \ From c3e1dab8f6c2bd0dc4a2a1c0a0809ef5b4523185 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Wed, 29 Jun 2022 05:44:22 -0400 Subject: [PATCH 64/68] Updating the FLASH_DATA_ADDR value to the correct value for 6 slots (versus standard 8) --- .../BuildScripts/custom_build_targets.mk | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index 963887ea..8f41d4e0 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -51,7 +51,10 @@ mifare-classic: TARGET_CUSTOM_BUILD_NAME:=MifareClassicSupport mifare-classic: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) mifare-classic: custom-build -desfire: FLASH_DATA_SIZE:=0x0E000 +desfire: FLASH_DATA_SIZE_CONST:=0C000 # Six settings (save some space): 6 * 0x2000 +desfire: FLASH_DATA_SIZE:=0x$(FLASH_DATA_SIZE_CONST) +desfire: FLASH_DATA_SIZE_UPPER_CONST:=20000 +desfire: FLASH_DATA_ADDR:=0x$(shell echo "obase=16;ibase=16;$(FLASH_DATA_SIZE_UPPER_CONST)-$(FLASH_DATA_SIZE_CONST)" | bc) desfire: SUPPORTED_TAGS_BUILD:=-DCONFIG_MF_DESFIRE_SUPPORT desfire: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ -DDESFIRE_CRYPTO1_SAVE_SPACE \ @@ -60,7 +63,10 @@ desfire: TARGET_CUSTOM_BUILD_NAME:=DESFire desfire: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) desfire: custom-build -desfire-dev: FLASH_DATA_SIZE:=0x0E000 +desfire-dev: FLASH_DATA_SIZE_CONST:=0C000 # Six settings (save some space): 6 * 0x2000 +desfire-dev: FLASH_DATA_SIZE:=0x$(FLASH_DATA_SIZE_CONST) +desfire-dev: FLASH_DATA_SIZE_UPPER_CONST:=20000 +desfire-dev: FLASH_DATA_ADDR:=0x$(shell echo "obase=16;ibase=16;$(FLASH_DATA_SIZE_UPPER_CONST)-$(FLASH_DATA_SIZE_CONST)" | bc) desfire-dev: SUPPORTED_TAGS_BUILD:=-DCONFIG_MF_DESFIRE_SUPPORT desfire-dev: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ -DDESFIRE_CRYPTO1_SAVE_SPACE \ From 05eeda659d0f140287df9311e76e1f2e5289b39e Mon Sep 17 00:00:00 2001 From: fptrs <48245105+fptrs@users.noreply.github.com> Date: Wed, 29 Jun 2022 13:12:55 +0200 Subject: [PATCH 65/68] Update Log.py change DESFire Generic Error decoder --- Software/ChamTool/Chameleon/Log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Software/ChamTool/Chameleon/Log.py b/Software/ChamTool/Chameleon/Log.py index 4b0fdb81..82d0ff15 100644 --- a/Software/ChamTool/Chameleon/Log.py +++ b/Software/ChamTool/Chameleon/Log.py @@ -102,7 +102,7 @@ def binaryParityDecoder(data): 0xD1: { 'name': 'APP DESFIRE NONCE B', 'decoder': binaryDecoder }, 0xD2: { 'name': 'APP DESFIRE NONCE AB', 'decoder': binaryDecoder }, - 0xE0: { 'name': 'APP DESFIRE GENERIC ERROR', 'decoder': binaryDecoder }, + 0xE0: { 'name': 'APP DESFIRE GENERIC ERROR', 'decoder': textDecoder }, 0xE1: { 'name': 'APP DESFIRE STATUS INFO', 'decoder': binaryDecoder }, 0xE2: { 'name': 'APP DESFIRE DEBUG OUTPUT', 'decoder': binaryDecoder }, 0xE3: { 'name': 'APP DESFIRE INCOMING', 'decoder': binaryDecoder }, From 807d4ac37e83fa24c4678f2828ea688e5eaa7303 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Thu, 30 Jun 2022 22:24:07 -0400 Subject: [PATCH 66/68] Stashing DESFire updates before tinkering with saving space with PSTR wrappers around the terminal command names --- Doc/DESFireSupportReadme.md | 201 +++--------------- .../DESFire/DESFireChameleonTerminal.c | 11 +- .../DESFire/DESFireISO14443Support.c | 169 ++++++--------- .../DESFire/DESFireISO14443Support.h | 21 +- .../DESFire/DESFireISO7816Support.h | 4 +- .../Application/DESFire/DESFireInstructions.c | 5 - .../Application/DESFire/DESFireLogging.c | 80 ++++--- .../Application/DESFire/DESFireLogging.h | 76 ++----- .../Application/DESFire/DESFirePICCControl.c | 60 ++++-- .../Application/DESFire/DESFirePICCControl.h | 16 +- .../DESFire/DESFirePICCHeaderLayout.h | 87 ++++---- .../Application/DESFire/DESFireUtils.h | 6 +- .../Chameleon-Mini/Application/ISO14443-3A.c | 7 +- .../Application/MifareDESFire.c | 87 ++++---- .../Application/MifareDESFire.h | 40 ++-- .../BuildScripts/custom_build_targets.mk | 5 +- Firmware/Chameleon-Mini/Configuration.c | 16 ++ Firmware/Chameleon-Mini/Configuration.h | 1 + Firmware/Chameleon-Mini/Makefile | 10 +- 19 files changed, 386 insertions(+), 516 deletions(-) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index f5f3cd9b..e054c478 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -1,132 +1,5 @@ # Chameleon Mini firmware support for DESFire tag emulation -The project began based on a few open source Java-based emulation projects (Android based) and the -prior initial work to add this support on the Chameleon Mini by **@dev-zzo**. -The starting point of the current firmware code for this project was compiled from -[this firmware mod fork](https://github.com/dev-zzo/ChameleonMini/tree/desfire) as -were the known instruction (command) and status codes from the -[Android HCE (Java based code)](https://github.com/jekkos/android-hce-desfire) -repository maintained by **@jekkos**. -After that point, **@maxieds** reorganized and began work modifying and debugging the -compiled source base in [this repository](https://github.com/maxieds/ChameleonMiniDESFireStack). -Most of the preliminary testing of these firmware mods was done using the -[Chameleon Mini Live Debugger](https://github.com/maxieds/ChameleonMiniLiveDebugger) -Android logger application, and with ``libnfc`` via a -USB NFC tag reader (host-based testing code is -[available here](https://github.com/maxieds/ChameleonMiniDESFireStack/tree/master/Firmware/Chameleon-Mini/Application/DESFire/Testing)). - -The firmware has been tested and known to work with the KAOS manufactured RevG Chameleon devices. -Unfortunately, formative RevE device support is not available due to the memory requirements to -run this firmware emulation. The device responds well using the ``libnfc``-based utility -``nfc-anticol``: -```bash -NFC reader: SCM Micro / SCL3711-NFC&RW opened - -Sent bits: 26 (7 bits) -Received bits: 03 44 -Sent bits: 93 20 -Received bits: 88 23 77 00 dc -Sent bits: 93 70 88 23 77 00 dc 4b b3 -Received bits: 04 -Sent bits: 95 20 -Received bits: 0b 99 bf 98 b5 -Sent bits: 95 70 0b 99 bf 98 b5 2f 24 -Received bits: 20 -Sent bits: e0 50 bc a5 -Received bits: 75 77 81 02 80 -Sent bits: 50 00 57 cd - -Found tag with - UID: 2377000b99bf98 -ATQA: 4403 - SAK: 20 - ATS: 75 77 81 02 80 -``` -More testing needs to be done to fine tune support for interfacing the Chameleon -with live, in-the-wild DESFire tag readers in practice. It has been verified to work with the -Proxmark3 NFC devices: -```bash -[usb] pm3 --> hf 14a read -[+] UID: 4A D9 BA 11 B9 97 57 -[+] ATQA: 44 03 -[+] SAK: 20 [1] -[+] ATS: 75 77 81 02 80 -[=] field dropped. - -[usb] pm3 --> script run debug.cmd -[+] executing Cmd debug.cmd -[+] args '' -[usb|script] pm3 --> hw dbg -4 -[usb|script] pm3 --> prefs set clientdebug --full -[=] client debug........... full -[usb|script] pm3 --> data setdebugmode -2 -[=] client debug level... 2 ( verbose debug messages ) - -[#] Debug log level......... 4 ( extended ) - -[usb] pm3 --> hf mfdes info -[#] pcb_blocknum 0 == 2 -[#] [WCMD <--: : 08/08] 02 90 60 00 00 00 14 98 -[#] pcb_blocknum 1 == 3 -[#] [WCMD <--: : 08/08] 03 90 af 00 00 00 1f 15 -[#] pcb_blocknum 0 == 2 -[#] [WCMD <--: : 08/08] 02 90 af 00 00 00 34 11 - -[=] ---------------------------------- Tag Information ---------------------------------- -[+] UID: 08 4F 8A 44 7D AE 83 -[+] Batch number: AE 83 CE E4 A5 -[+] Production date: week db / 20f1 - -[=] --- Hardware Information -[=] raw: 04010100011805 -[=] Vendor Id: NXP Semiconductors Germany -[=] Type: 0x01 -[=] Subtype: 0x01 -[=] Version: 0.1 ( DESFire MF3ICD40 ) -[=] Storage size: 0x18 ( 4096 bytes ) -[=] Protocol: 0x05 ( ISO 14443-2, 14443-3 ) - -[=] --- Software Information -[=] raw: 90AF0401010001 -[=] Vendor Id: no tag-info available -[=] Type: 0xAF -[=] Subtype: 0x04 -[=] Version: 1.1 -[=] Storage size: 0x00 ( 1 bytes ) -[=] Protocol: 0x01 ( Unknown ) - -[=] --------------------------------- Card capabilities --------------------------------- -[#] switch_off - -[usb] pm3 --> hf mfdes auth -n 0 -t 3tdea -k 000000000000000000000000000000000000000000000000 -v -c native -a -[=] Key num: 0 Key algo: 3tdea Key[24]: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[=] Secure channel: n/a Command set: native Communication mode: plain -[+] Setting ISODEP -> inactive -[+] Setting ISODEP -> NFC-A -[=] AID 000000 is selected -[=] Auth: cmd: 0x1a keynum: 0x00 -[+] raw>> 1A 00 -[+] raw<< AF EE 91 30 1E E8 F5 84 D6 C7 85 1D 05 65 13 90 A6 C6 D5 -[#] encRndB: EE 91 30 1E E8 F5 84 D6 -[#] RndB: CA FE BA BE 00 11 22 33 -[#] rotRndB: FE BA BE 00 11 22 33 CA FE BA BE 00 11 22 33 CA -[#] Both : 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 FE BA BE 00 11 22 33 CA FE BA BE 00 11 22 33 CA -[+] raw>> AF 30 EB 55 F3 29 39 04 96 77 88 CE EF 33 A3 C8 7B 18 66 1A F1 62 78 A0 28 53 84 67 98 7C BB DB 03 -[+] raw<< 00 9B 71 57 8F FB DF 80 A8 F6 EF 33 4A C6 CD F9 7A 7D BE -[=] Session key : 01 02 03 04 CA FE BA BE 07 08 09 10 22 33 CA FE 13 14 15 16 00 11 22 33 -[=] Desfire authenticated -[+] PICC selected and authenticated succesfully -[+] Context: -[=] Key num: 0 Key algo: 3tdea Key[24]: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -[=] Secure channel: ev1 Command set: native Communication mode: plain -[=] Session key [24]: 01 02 03 04 CA FE BA BE 07 08 09 10 22 33 CA FE 13 14 15 16 00 11 22 33 -[=] IV [8]: 00 00 00 00 00 00 00 00 -[+] Setting ISODEP -> inactive -``` -The DESFire configuration mode has been known to see recognition problems -using the ``libfreefare`` commands ``mifare-*``. This issue may be gradually -resolved as the work to bring compatibility with the PM3 devices continues. - ## Quick configuration of cloned DESFire tags ### Chameleon Mini terminal addons to support ``CONFIG=MF_DESFIRE`` modes @@ -142,20 +15,19 @@ run these commands. ```bash CONFIG=? CONFIG=MF_DESFIRE +CONFIG=MF_DESFIRE_2KEV1 +CONFIG=MF_DESFIRE_4KEV1 +CONFIG=MF_DESFIRE_4KEV2 ``` #### DF_SETHDR -- Set PICC header information The UID for the tag can be set using separate Chameleon terminal commands as usual for all other configurations. -```bash -DF_SETHDR? -101:OK WITH TEXT -DF_SETHDR -``` -We can modify the tag header information emulated by the tag as follows: +We can modify the remaining tag header information emulated by the tag as follows: ```bash DF_SETHDR=ATS xxxxxxxxxx +DF_SETHDR=ATQA xxxx DF_SETHDR=ManuID xx DF_SETHDR=HardwareVersion mmMM DF_SETHDR=SoftwareVersion mmMM @@ -173,6 +45,10 @@ To set the ATS bytes reported to emulate a JCOP tag: ```bash DF_SETHDR=ATS 0675f7b102 ``` +To reset the ATQA value returned in the anticollision loop handshaking: +``` +DF_SETHDR=ATQA 2838 +``` ##### Documentation for cloning specific tag types @@ -338,7 +214,6 @@ reset it intentionally at will for testing and debugging purposes. The syntax is as follows: ```bash -DF_COMM_MODE? DF_COMM_MODE=Plaintext DF_COMM_MODE=Plaintext:MAC DF_COMM_MODE=Enciphered:3K3DES @@ -355,24 +230,8 @@ to the defaults. Syntax -- not guaranteeing that all of these are meaningful or distinct just yet: ```bash -DF_LOGMODE? -DF_LOGMODE= -DF_LOGMODE=<0|1|TRUE|FALSE> -``` - -#### DF_TESTMODE -- Sets whether the firmware emulation is run in testing/debugging mode - -Syntax: -```bash -DF_TESTMODE? -DF_TESTMODE=<0|1|TRUE|FALSE|OFF|ON> -``` -#### DF_COMM_MODE - -Syntax: -```bash -DF_COMM_MODE? -DF_COMM_MODE= +DF_LOGMODE=0 +DF_LOGMODE=1 ``` ## Supported functionality @@ -469,6 +328,21 @@ for development of this project: ### Sources of external code and open information about the DESFire specs +The project began based on a few open source Java-based emulation projects (Android based) and the +prior initial work to add this support on the Chameleon Mini by **@dev-zzo**. +The starting point of the current firmware code for this project was compiled from +[this firmware mod fork](https://github.com/dev-zzo/ChameleonMini/tree/desfire) as +were the known instruction (command) and status codes from the +[Android HCE (Java based code)](https://github.com/jekkos/android-hce-desfire) +repository maintained by **@jekkos**. +After that point, **@maxieds** reorganized and began work modifying and debugging the +compiled source base in [this repository](https://github.com/maxieds/ChameleonMiniDESFireStack). +Most of the preliminary testing of these firmware mods was done using the +[Chameleon Mini Live Debugger](https://github.com/maxieds/ChameleonMiniLiveDebugger) +Android logger application, and with ``libnfc`` via a +USB NFC tag reader (host-based testing code is +[available here](https://github.com/maxieds/ChameleonMiniDESFireStack/tree/master/Firmware/Chameleon-Mini/Application/DESFire/Testing)). + The source code for much of this implementation has been directly adapted, or modified, from mostly Java language open source code for Android using several primary sources. Where possible, the license and credits for the original sources for this ``avr-gcc``-compatible C language code are as specified in the next @@ -478,26 +352,3 @@ repositories and code bases: * [Android HCE Framework Library (kevinvalk)](https://github.com/kevinvalk/android-hce-framework) * [AVRCryptoLib in C](https://github.com/cantora/avr-crypto-lib) * [LibFreefare DESFire Code (mostly as a reference and check point)](https://github.com/nfc-tools/libfreefare/tree/master/libfreefare) - -### Clarification: Where the local licenses apply - -The code that is not already under direct license (see below) is released according to the normal -[license for the firmware](https://github.com/emsec/ChameleonMini/blob/master/LICENSE.txt). -Additional licenses that apply only to the code used within this DESFire stack implementation, -or to the open source libraries used to derive this code, -are indicated within the local firmware directories. - -### DESFire sources header comments - -``` -The DESFire stack portion of this firmware source is free software written by Maxie Dion Schmidt (@maxieds): You can redistribute it and/or modify it under the terms of this license. - -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. - -The complete source distribution of this firmware is available at the following link: https://github.com/maxieds/ChameleonMiniFirmwareDESFireStack. - -Based in part on the original DESFire code created by @dev-zzo (GitHub handle) [Dmitry Janushkevich] available at https://github.com/dev-zzo/ChameleonMini/tree/desfire. - -This notice must be retained at the top of all source files where indicated. -``` - diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c index dad96169..948604f2 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c @@ -29,7 +29,6 @@ This notice must be retained at the top of all source files where indicated. #include "../../Terminal/Terminal.h" #include "../../Terminal/Commands.h" #include "../../Settings.h" - #include "DESFireChameleonTerminal.h" #include "DESFireFirmwareSettings.h" #include "DESFirePICCControl.h" @@ -49,7 +48,7 @@ CommandStatusIdType ExitOnInvalidConfigurationError(char *OutParam) { #ifndef DISABLE_PERMISSIVE_DESFIRE_SETTINGS CommandStatusIdType CommandDESFireGetHeaderProperty(char *OutParam) { snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, - PSTR("%s "), + PSTR("%s "), DFCOMMAND_SET_HEADER); return COMMAND_INFO_OK_WITH_TEXT_ID; } @@ -75,6 +74,14 @@ CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutParam, const char * } else { memcpy(&Picc.ATSBytes[0], propSpecBytes, dataByteCount); } + } + if (!strcasecmp_P(hdrPropSpecStr, PSTR("ATQA"))) { + if (dataByteCount != 2) { + StatusError = 1; + } else { + DesfireATQAValue = ((propSpecBytes[0] << 8) & 0xFF00) | (propSpecBytes[1] & 0x00FF); + memcpy(&Picc.ATSBytes[0], propSpecBytes, dataByteCount); + } } else if (!strcasecmp_P(hdrPropSpecStr, PSTR("ManuID"))) { if (dataByteCount != 1) { StatusError = 1; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index d91b7d0c..ac6002df 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -38,6 +38,7 @@ This notice must be retained at the top of all source files where indicated. * ISO/IEC 14443-4 implementation */ Iso144434StateType Iso144434State = ISO14443_4_STATE_EXPECT_RATS; + uint8_t Iso144434BlockNumber = 0x00; uint8_t Iso144434CardID = 0x00; uint8_t Iso144434LastBlockLength = 0x00; @@ -49,34 +50,35 @@ uint16_t ISO14443ALastDataFrameBits = 0; uint8_t ISO14443ALastIncomingDataFrame[MAX_DATA_FRAME_XFER_SIZE] = { 0x00 }; uint16_t ISO14443ALastIncomingDataFrameBits = 0; -bool CheckStateRetryCount2(bool resetByDefault, bool performLogging) { +bool CheckStateRetryCountWithLogging(bool resetByDefault, bool performLogging) { if (resetByDefault || ++StateRetryCount > MAX_STATE_RETRY_COUNT) { - ISO144434SwitchState2(Iso144433AIdleState, performLogging); + ISO144434SwitchStateWithLogging(Iso144433AIdleState, performLogging); StateRetryCount = 0x00; - const char *debugStatusMsg = PSTR("RETRY-RESET"); - LogDebuggingMsg(debugStatusMsg); + DEBUG_PRINT_P(PSTR("RETRY-RESET")); return true; } return false; } bool CheckStateRetryCount(bool resetByDefault) { - return CheckStateRetryCount2(resetByDefault, true); + return CheckStateRetryCountWithLogging(resetByDefault, true); } -void ISO144434SwitchState2(Iso144434StateType NewState, bool performLogging) { +void ISO144434SwitchStateWithLogging(Iso144434StateType NewState, bool performLogging) { Iso144434State = NewState; StateRetryCount = 0x00; +#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 if (performLogging) { - DesfireLogISOStateChange(Iso144434State, LOG_ISO14443_4_STATE); + RUN_ON_DESFIRE_DEBUG(DesfireLogISOStateChange(Iso144434State, LOG_ISO14443_4_STATE)); } +#endif } void ISO144434SwitchState(Iso144434StateType NewState) { - ISO144434SwitchState2(NewState, true); + ISO144434SwitchStateWithLogging(NewState, true); } void ISO144434Reset(void) { - /* No logging -- spams the log */ + /* No logging here -- spams the log and slows things way down! */ Iso144434State = ISO14443_4_STATE_EXPECT_RATS; Iso144434BlockNumber = 1; ISO14443ALastDataFrameBits = 0; @@ -92,9 +94,8 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 /* Verify the block's length: at the very least PCB + CRCA */ if (ByteCount < (1 + ISO14443A_CRCA_SIZE)) { - /* Huh? Broken frame? */ - const char *debugPrintStr = PSTR("ISO14443-4: length fail"); - LogDebuggingMsg(debugPrintStr); + /* Broken frame -- Respond error by returning an empty frame */ + DEBUG_PRINT_P(PSTR("ISO14443-4: length fail")); return ISO14443A_APP_NO_RESPONSE; } ByteCount -= 2; @@ -103,8 +104,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 if (!ISO14443ACheckCRCA(Buffer, ByteCount)) { LogEntry(LOG_ERR_APP_CHECKSUM_FAIL, Buffer, ByteCount); /* ISO/IEC 14443-4, clause 7.5.5. The PICC does not attempt any error recovery. */ - const char *debugPrintStr = PSTR("WARN: 14443-4: CRC fail; %04X vs %04X"); - DEBUG_PRINT_P(debugPrintStr, *(uint16_t *)&Buffer[ByteCount], + DEBUG_PRINT_P(PSTR("WARN: 14443-4: CRC fail; %04X vs %04X"), *(uint16_t *)&Buffer[ByteCount], ISO14443AAppendCRCA(Buffer, ByteCount)); return ISO14443A_APP_NO_RESPONSE; } @@ -114,8 +114,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 /* See: ISO/IEC 14443-4, clause 5.6.1.2 */ if (Buffer[0] != ISO14443A_CMD_RATS) { /* Ignore blocks other than RATS and HLTA */ - const char *debugPrintStr = PSTR("ISO14443-4: NOT RATS"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: NOT RATS")); return ISO14443A_APP_NO_RESPONSE; } /* Process RATS. @@ -128,8 +127,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 Buffer[5] = 0x80; /* T1: dummy value for historical bytes */ ByteCount = 6; // NOT including CRC ISO144434SwitchState(ISO14443_4_STATE_ACTIVE); - const char *debugPrintStr = PSTR("ISO14443-4: SEND RATS"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: SEND RATS")); return ASBITS(ByteCount); // PM3 expects no CRCA bytes } case ISO14443_4_STATE_ACTIVE: { @@ -148,9 +146,8 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 PrologueLength++; /* Verify the card ID */ if ((Buffer[1] & 0xF) != Iso144434CardID) { - /* Different card ID => the frame is ignored */ - const char *debugPrintStr = PSTR("ISO14443-4: NEW CARD ID"); - LogDebuggingMsg(debugPrintStr); + /* Different card ID -- the frame is ignored */ + DEBUG_PRINT_P(PSTR("ISO14443-4: NEW CARD ID %02d"), Iso144434CardID); return ISO14443A_APP_NO_RESPONSE; } } @@ -168,16 +165,14 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 HaveNAD = PCB & ISO14443_PCB_HAS_NAD_MASK; if (HaveNAD) { PrologueLength++; - /* Not currently supported => the frame is ignored */ - const char *debugPrintStr = PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK -- %d"); - DEBUG_PRINT_P(debugPrintStr, __LINE__); + /* Not currently supported -- the frame is ignored */ + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK -- %d"), __LINE__); } /* 7.5.3.2, rule D: toggle on each I-block */ Iso144434BlockNumber = MyBlockNumber = !MyBlockNumber; if (PCB & ISO14443_PCB_I_BLOCK_CHAINING_MASK) { - /* Currently not supported => the frame is ignored */ - const char *debugPrintStr = PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK -- %d"); - DEBUG_PRINT_P(debugPrintStr, __LINE__); + /* Currently not supported -- the frame is ignored */ + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK -- %d"), __LINE__); return ISO14443A_APP_NO_RESPONSE; } @@ -193,35 +188,30 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 ByteCount = MifareDesfireProcessCommand(&Buffer[PrologueLength], ByteCount - PrologueLength); /* Short-circuit in case the app decides not to respond at all */ if (ByteCount == 0) { - const char *debugPrintStr = PSTR("ISO14443-4: APP_NO_RESP"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: APP_NO_RESP")); return ISO14443A_APP_NO_RESPONSE; } ByteCount += PrologueLength; - const char *debugPrintStr = PSTR("ISO14443-4: I-BLK"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: I-BLK")); return GetAndSetBufferCRCA(Buffer, ByteCount); } case ISO14443_PCB_R_BLOCK: { /* 7.5.4.3, rule 11 */ if ((PCB & ISO14443_PCB_BLOCK_NUMBER_MASK) == MyBlockNumber) { - /* NOTE: This already includes the CRC */ - const char *debugPrintStr = PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"); - DEBUG_PRINT_P(debugPrintStr, __LINE__); + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"), __LINE__); return ISO14443A_APP_NO_RESPONSE; } if (PCB & ISO14443_PCB_R_BLOCK_ACKNAK_MASK) { /* 7.5.4.3, rule 12 */ /* This is a NAK. Send an ACK back */ Buffer[0] = ISO14443_PCB_R_BLOCK_STATIC | ISO14443_PCB_R_BLOCK_ACK | MyBlockNumber; - // Per the NXP data sheet MF1S50YYX_V1 (Table 10: ACK / NAK), we should return 4 bits: + /* The NXP data sheet MF1S50YYX_V1 (Table 10: ACK / NAK) says we should return 4 bits: */ return 4; } else { - /* This is an ACK */ + /* This is an ACK: */ /* NOTE: Chaining is not supported yet. */ - const char *debugPrintStr = PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"); - DEBUG_PRINT_P(debugPrintStr, __LINE__); + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"), __LINE__); // Resend the data from the last frame: if (ISO14443ALastDataFrameBits > 0) { memcpy(&Buffer[0], &ISO14443ALastDataFrame[0], ASBYTES(ISO14443ALastDataFrameBits)); @@ -230,8 +220,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 return ISO14443A_APP_NO_RESPONSE; } } - const char *debugPrintStr6 = PSTR("ISO14443-4: R-BLK"); - LogDebuggingMsg(debugPrintStr6); + DEBUG_PRINT_P(PSTR("ISO14443-4: R-BLK")); return GetAndSetBufferCRCA(Buffer, ByteCount); } @@ -244,12 +233,10 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 ISO144433AHalt(); /* Answer with S(DESELECT) -- just send the copy of the message */ ByteCount = PrologueLength; - const char *debugPrintStr = PSTR("ISO14443-4: S-BLK"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: S-BLK")); return GetAndSetBufferCRCA(Buffer, ByteCount); } - const char *debugPrintStr5 = PSTR("ISO14443-4: PCB_S_BLK NO_RESP"); - LogDebuggingMsg(debugPrintStr5); + DEBUG_PRINT_P(PSTR("ISO14443-4: PCB_S_BLK NO_RESP")); return ISO14443A_APP_NO_RESPONSE; } @@ -286,11 +273,11 @@ Iso144433AStateType Iso144433AIdleState = ISO14443_3A_STATE_IDLE; void ISO144433ASwitchState(Iso144433AStateType NewState) { Iso144433AState = NewState; StateRetryCount = 0x00; - DesfireLogISOStateChange(Iso144433AState, LOG_ISO14443_3A_STATE); + RUN_ON_DESFIRE_DEBUG(DesfireLogISOStateChange(Iso144433AState, LOG_ISO14443_3A_STATE)); } void ISO144433AReset(void) { - /* No logging -- spams the log */ + /* No logging performed -- spams the log and slows things way down! */ Iso144433AState = ISO14443_3A_STATE_IDLE; Iso144433AIdleState = ISO14443_3A_STATE_IDLE; ISO14443ALastDataFrameBits = 0; @@ -304,10 +291,10 @@ void ISO144433AHalt(void) { } bool ISO144433AIsHalt(const uint8_t *Buffer, uint16_t BitCount) { - return BitCount == ISO14443A_HLTA_FRAME_SIZE + ASBITS(ISO14443A_CRCA_SIZE) - && Buffer[0] == ISO14443A_CMD_HLTA - && Buffer[1] == 0x00 - && ISO14443ACheckCRCA(Buffer, ASBYTES(ISO14443A_HLTA_FRAME_SIZE)); + return BitCount == ISO14443A_HLTA_FRAME_SIZE + ASBITS(ISO14443A_CRCA_SIZE) && + Buffer[0] == ISO14443A_CMD_HLTA && + Buffer[1] == 0x00 && + ISO14443ACheckCRCA(Buffer, ASBYTES(ISO14443A_HLTA_FRAME_SIZE)); } uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { @@ -324,20 +311,16 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { bool checkStateRetryStatus = CheckStateRetryCount(false); bool incrementRetryCount = true; if (Cmd == ISO14443A_CMD_REQA) { - LOG_AT_LEVEL(LogEntry(LOG_INFO_APP_CMD_REQA, NULL, 0), VERBOSE); - //ISO144434Reset(); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_REQA, NULL, 0)); ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); incrementRetryCount = false; } else if (ISO14443ACmdIsWUPA(Cmd)) { - LOG_AT_LEVEL(LogEntry(LOG_INFO_APP_CMD_WUPA, NULL, 0), VERBOSE); - //ISO144434Reset(); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_WUPA, NULL, 0)); ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); incrementRetryCount = false; - //return ISO14443A_APP_NO_RESPONSE; } else if (ISO144433AIsHalt(Buffer, BitCount)) { - LOG_AT_LEVEL(LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0), VERBOSE); - const char *logMsg = PSTR("ISO14443-3: HALTING"); - LogDebuggingMsg(logMsg); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0)); + DEBUG_PRINT_P(PSTR("ISO14443-3: HALTING")); ISO144433AHalt(); return ISO14443A_APP_NO_RESPONSE; } @@ -352,8 +335,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { switch (Iso144433AState) { case ISO14443_3A_STATE_HALT: if (!ISO14443ACmdIsWUPA(Cmd)) { - const char *debugPrintStr = PSTR("ISO14443-4: HALT / NOT WUPA"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: HALT -- NOT WUPA")); break; } else { ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); @@ -363,10 +345,9 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { case ISO14443_3A_STATE_IDLE: Iso144433AIdleState = Iso144433AState; ISO144433ASwitchState(ISO14443_3A_STATE_READY1); - Buffer[0] = (ATQA_VALUE) & 0x00FF; - Buffer[1] = (ATQA_VALUE >> 8) & 0x00FF; - const char *debugPrintStr = PSTR("ISO14443-4 (IDLE): ATQA"); - LogDebuggingMsg(debugPrintStr); + Buffer[0] = DesfireATQAValue & 0x00FF; + Buffer[1] = (DesfireATQAValue >> 8) & 0x00FF; + DEBUG_PRINT_P(PSTR("ISO14443-4 (IDLE): ATQA -- %04x"), DesfireATQAValue); return ASBITS(ISO14443A_ATQA_FRAME_SIZE_BYTES); case ISO14443_3A_STATE_READY1: @@ -382,17 +363,14 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { } if (ISO14443ASelectDesfire(Buffer, &BitCount, Uid, SAK_CL1_VALUE)) { /* CL1 stage has ended successfully */ - const char *debugPrintStr = PSTR("ISO14443-4: Select OK"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: Select OK")); ISO144433ASwitchState(ISO14443_3A_STATE_READY2); } else { - const char *debugPrintStr = PSTR("ISO14443-4: Select NAK"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: Select NAK")); } return BitCount; } - const char *debugPrintStr4 = PSTR("ISO14443-4: RDY1, NOT SLCT CMD"); - LogDebuggingMsg(debugPrintStr4); + DEBUG_PRINT_P(PSTR("ISO14443-4: RDY1 -- NOT SLCT CMD")); break; case ISO14443_3A_STATE_READY2: @@ -404,59 +382,39 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* CL2 stage has ended successfully. This means * our complete UID has been sent to the reader. */ ISO144433ASwitchState(ISO14443_3A_STATE_ACTIVE); - const char *debugPrintStr = PSTR("INTO ACTIVE!"); - LogDebuggingMsg(debugPrintStr); } else { - const char *debugPrintStr = PSTR("Incorrect Select value (R2)"); - LogDebuggingMsg(debugPrintStr); + DEBUG_PRINT_P(PSTR("ISO14443-4: Incorrect select value (R2)")); } return BitCount; } - const char *debugPrintStr3 = PSTR("RDY2, NOT SLCT CMD"); - LogDebuggingMsg(debugPrintStr3); + DEBUG_PRINT_P(PSTR("ISO14443-4: RDY2 -- NOT SLCT CMD")); break; case ISO14443_3A_STATE_ACTIVE: StateRetryCount = MAX_STATE_RETRY_COUNT; - /* Recognise the HLTA command */ if (ISO144433AIsHalt(Buffer, BitCount)) { - LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); + /* Recognise the HLTA command: */ + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0)); ISO144434SwitchState(ISO14443_3A_STATE_HALT); - const char *logMsg = PSTR("ISO14443-3: Got HALT"); - LogDebuggingMsg(logMsg); + DEBUG_PRINT_P(PSTR("ISO14443-3: Got HALT")); return ISO14443A_APP_NO_RESPONSE; } else if (Cmd == ISO14443A_CMD_RATS) { ISO144433ASwitchState(ISO14443_4_STATE_EXPECT_RATS); - const char *logMsg = PSTR("ISO14443-3/4: EXPECTING RATS"); - LogDebuggingMsg(logMsg); + DEBUG_PRINT_P(PSTR("ISO14443-3/4: Expecting RATS")); } else if (Cmd == ISO14443A_CMD_SELECT_CL3) { Buffer[0] = ISO14443A_SAK_COMPLETE_NOT_COMPLIANT; ISO14443AAppendCRCA(&Buffer[0], 1); return ISO14443A_SAK_FRAME_SIZE; } else if (Cmd == ISO14443A_CMD_DESELECT) { - LOG_AT_LEVEL(LogEntry(LOG_INFO_APP_CMD_DESELECT, NULL, 0), VERBOSE); - /* See if the process can make sense of the first byte: */ - //uint16_t ByteCount = ASBYTES(BitCount); - //uint16_t ReturnBits = ISO144434ProcessBlock(Buffer, ByteCount, BitCount); - //if (ReturnBits > 0) { - // return ReturnBits; - //} - /* Otherwise (doesn't seem to work): Return a HALT frame to the reader: */ - //Buffer[0] = ISO14443A_CMD_HLTA; - //Buffer[1] = 0x00; - //ISO14443AAppendCRCA(&Buffer[0], 2); - //ISO144434SwitchState(ISO14443_3A_STATE_HALT); - //return ISO14443A_DESELECT_FRAME_SIZE; - /* Otherwise: Return a WUPA frame to the reader to reset: */ - //Buffer[0] = ISO14443A_CMD_WUPA; - //ISO144434SwitchState(ISO14443_3A_STATE_HALT); - //return ASBITS(1); + /* This has been observed to happen at this stage when swiping the + * Chameleon running CONFIG=MF_DESFIRE on an ACR122 USB external reader. + */ + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_DESELECT, NULL, 0)); } /* Forward to ISO/IEC 14443-4 processing code */ uint16_t ByteCount = ASBYTES(BitCount); uint16_t ReturnBits = ISO144434ProcessBlock(Buffer, ByteCount, BitCount); - const char *debugPrintStr2 = PSTR("ISO14443-4: ACTIVE RET"); - LogDebuggingMsg(debugPrintStr2); + DEBUG_PRINT_P(PSTR("ISO14443-4: ACTIVE RET")); return ReturnBits; default: @@ -467,13 +425,12 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* Fallthrough: Unknown command. Reset back to idle/halt state. */ bool defaultReset = false; if (!CheckStateRetryCount(defaultReset)) { - const char *logMsg = PSTR("ISO14443-3: RESET TO IDLE 0x%02x"); - DEBUG_PRINT_P(logMsg, Cmd); + DEBUG_PRINT_P(PSTR("ISO14443-3: Fall through -- RESET TO IDLE 0x%02x"), Cmd); + return ISO14443A_APP_NO_RESPONSE; + } else { + DEBUG_PRINT_P(PSTR("ISO14443-4: UNK-CMD NO RESP")); return ISO14443A_APP_NO_RESPONSE; } - const char *debugPrintStr = PSTR("ISO14443-4: UNK-CMD NO_RESP"); - LogDebuggingMsg(debugPrintStr); - return ISO14443A_APP_NO_RESPONSE; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index c2a75a83..a5cacd61 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -115,16 +115,14 @@ INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t Buff return BufferBitCount; } -/* Setup some fuzzy response handling for problematic readers like the ACR122U */ - -#define MAX_STATE_RETRY_COUNT (0x0b) +#define MAX_STATE_RETRY_COUNT (0x04) extern uint8_t StateRetryCount; bool CheckStateRetryCount(bool resetByDefault); -bool CheckStateRetryCount2(bool resetByDefault, bool performLogging); +bool CheckStateRetryCountWithLogging(bool resetByDefault, bool performLogging); /* Support functions */ void ISO144434SwitchState(Iso144434StateType NewState); -void ISO144434SwitchState2(Iso144434StateType NewState, bool performLogging); +void ISO144434SwitchStateWithLogging(Iso144434StateType NewState, bool performLogging); void ISO144434Reset(void); static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount); @@ -133,6 +131,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 * ISO/IEC 14443-3A implementation */ #define ISO14443A_CRCA_INIT ((uint16_t) 0x6363) +uint16_t ISO14443AUpdateCRCA(const uint8_t *Buffer, uint16_t ByteCount, uint16_t InitCRCA); #define GetAndSetBufferCRCA(Buffer, ByteCount) ({ \ uint16_t fullReturnBits = 0; \ @@ -147,17 +146,15 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 fullReturnBits; \ }) -uint16_t ISO14443AUpdateCRCA(const uint8_t *Buffer, uint16_t ByteCount, uint16_t InitCRCA); - typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { - /* The card is powered up but not selected */ - ISO14443_3A_STATE_IDLE = ISO14443_4_STATE_LAST, - /* Entered on REQA or WUPA; anticollision is being performed */ + /* The card is powered up but not selected: */ + ISO14443_3A_STATE_IDLE = ISO14443_4_STATE_LAST + 1, + /* Entered on REQA or WUP -- anticollision is being performed: */ ISO14443_3A_STATE_READY1, ISO14443_3A_STATE_READY2, - /* Entered when the card has been selected */ + /* Entered when the card has been selected: */ ISO14443_3A_STATE_ACTIVE, - /* Something went wrong or we've received a halt command */ + /* Something went wrong or we've received a halt command: */ ISO14443_3A_STATE_HALT, } Iso144433AStateType; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h index bea09a96..eb7474df 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h @@ -88,9 +88,11 @@ typedef enum { ISO7816_WRAPPED_CMD_TYPE_STANDARD = 1, ISO7816_WRAPPED_CMD_TYPE_PM3RAW = 2, ISO7816_WRAPPED_CMD_TYPE_PM3_ADDITIONAL_FRAME = 3, - /* ??? Others ??? */ + /* TODO -- Others ??? */ } Iso7816WrappedCommandType_t; +extern Iso7816WrappedCommandType_t Iso7816CmdType; + Iso7816WrappedCommandType_t IsWrappedISO7816CommandType(uint8_t *Buffer, uint16_t ByteCount); uint16_t SetIso7816WrappedParametersType(uint8_t *Buffer, uint16_t ByteCount); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index bf933c25..09774cb7 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -1155,7 +1155,6 @@ uint16_t EV0CmdGetFileSettings(uint8_t *Buffer, uint16_t ByteCount) { } uint16_t EV0CmdChangeFileSettings(uint8_t *Buffer, uint16_t ByteCount) { - DESFireLogSourceCodeTODO("", GetSourceFileLoggingData()); Buffer[0] = STATUS_ILLEGAL_COMMAND_CODE; // TODO return DESFIRE_STATUS_RESPONSE_SIZE; } @@ -1618,10 +1617,6 @@ uint16_t EV0CmdClearRecords(uint8_t *Buffer, uint16_t ByteCount) { Status = STATUS_LENGTH_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); } - - - - DESFireLogSourceCodeTODO("", GetSourceFileLoggingData()); Buffer[0] = STATUS_ILLEGAL_COMMAND_CODE; // TODO return DESFIRE_STATUS_RESPONSE_SIZE; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c index 5e2247b1..1285797e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c @@ -28,7 +28,7 @@ This notice must be retained at the top of all source files where indicated. #include "../../Log.h" #include "../../Terminal/Terminal.h" - +#include "DESFireISO14443Support.h" #include "DESFireLogging.h" #ifdef DESFIRE_DEFAULT_DEBUGGING_MODE @@ -43,34 +43,60 @@ BYTE LocalTestingMode = DESFIRE_DEFAULT_TESTING_MODE; BYTE LocalTestingMode = 0x00; #endif -void DESFireLogErrorMessage(char *fmtMsg, ...) { - char Format[80]; - char Buffer[80]; - va_list args; - strcpy_P(Format, fmtMsg); - va_start(args, fmtMsg); - vsnprintf(Buffer, sizeof(Buffer), Format, args); - va_end(args); - LogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, Buffer, StringLength(Buffer, 80) + 1); -} - -void DESFireLogSourceCodeTODO(char *implNoteMsg, char *srcFileLoggingData) { - char *bigDataBuffer = (char *) __InternalStringBuffer; - snprintf_P(bigDataBuffer, STRING_BUFFER_SIZE, PSTR("%s: %s"), - implNoteMsg, srcFileLoggingData); - SIZET logMsgBufferSize = StringLength(bigDataBuffer, STRING_BUFFER_SIZE); - LogEntry(LOG_INFO_DESFIRE_DEBUGGING_OUTPUT, bigDataBuffer, logMsgBufferSize + 1); +#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 +void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize) { + if (BufSize >= DESFIRE_MIN_OUTGOING_LOGSIZE) { + LogEntry(LogCode, (void *) LogDataBuffer, BufSize); + } } +#else +void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize) {} +#endif -void DebugPrintP(const char *fmt, ...) { - char Format[80]; - char Buffer[80]; - va_list args; - strcpy_P(Format, fmt); - va_start(args, fmt); - vsnprintf(Buffer, sizeof(Buffer), Format, args); - va_end(args); - TerminalSendString(Buffer); +#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 +void DesfireLogISOStateChange(int state, int logCode) { + const char *statePrintName; + int logLength = 0; + do { + switch (logCode) { + case ISO14443_4_STATE_EXPECT_RATS: + statePrintName = PSTR("ISO14443_4_STATE_EXPECT_RATS"); + break; + case ISO14443_4_STATE_ACTIVE: + statePrintName = PSTR("ISO14443_4_STATE_ACTIVE"); + break; + case ISO14443_4_STATE_LAST: + statePrintName = PSTR("ISO14443_4_STATE_LAST"); + break; + case ISO14443_3A_STATE_IDLE: + statePrintName = PSTR("ISO14443_3A_STATE_IDLE"); + break; + case ISO14443_3A_STATE_READY1: + statePrintName = PSTR("ISO14443_3A_STATE_READY1"); + break; + case ISO14443_3A_STATE_READY2: + statePrintName = PSTR("ISO14443_3A_STATE_READY2"); + break; + case ISO14443_3A_STATE_ACTIVE: + statePrintName = PSTR("ISO14443_3A_STATE_ACTIVE"); + break; + case ISO14443_3A_STATE_HALT: + statePrintName = PSTR("ISO14443_3A_STATE_HALT"); + break; + default: + statePrintName = PSTR("Unknown state"); + break; + } + } while (0); + snprintf_P(STRING_BUFFER_SIZE, (char *) __InternalStringBuffer, + PSTR("State CHG -- %s"), statePrintName); + logLength = StringLength((char *) __InternalStringBuffer, + STRING_BUFFER_SIZE); + DesfireLogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, + (char *) __InternalStringBuffer, logLength); } +#else +void DesfireLogISOStateChange(int state, int logCode) {} +#endif #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h index 5dc8684f..87c94192 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h @@ -39,12 +39,6 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_MIN_OUTGOING_LOGSIZE (1) #endif -INLINE void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize) { - if (DESFIRE_MIN_OUTGOING_LOGSIZE <= BufSize) { - LogEntry(LogCode, (void *) LogDataBuffer, BufSize); - } -} - typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { OFF = 0, NORMAL = 1, @@ -56,14 +50,6 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { #define DESFIRE_DEFAULT_LOGGING_MODE (OFF) #endif -#define LOG_AT_LEVEL(cmdToRun, loggingThreshold) ({ \ - do { \ - if (loggingThreshold <= DESFIRE_DEFAULT_LOGGING_MODE) { \ - cmdToRun; \ - } \ - } while(0); \ - }) - extern DESFireLoggingMode LocalLoggingMode; /* @@ -75,41 +61,40 @@ extern DESFireLoggingMode LocalLoggingMode; */ extern BYTE LocalTestingMode; -void DESFireLogErrorMessage(char *fmtMsg, ...); -void DESFireLogStatus(BYTE *bufMsg, SIZET bufSize); -void DESFireLogDebuggingMessage(char *fmtMsg, ...); -void DESFireLogSourceCodeTODO(char *implNoteMsg, char *srcFileLoggingData); -void DESFireLogIncomingData(BYTE *byteBuf, SIZET bufLength); -void DESFireLogOutgoingData(BYTE *byteBuf, SIZET bufLength); -void DESFireLogNativeCommand(BYTE *Buffer, SIZET ByteCount); -void DESFireLogISO1443Command(BYTE *Buffer, SIZET ByteCount); -void DESFireLogISO7816Command(BYTE *Buffer, SIZET ByteCount); -void DESFireLogSetProtectedData(BYTE *pdataBuf, SIZET byteBufSize); -void DESFireLogPICCHardReset(BYTE *strBuf, SIZET strLength); -void DESFireLogPICCSoftReset(BYTE *strBuf, SIZET strLength); - -void DebugPrintP(const char *fmt, ...); -#define DEBUG_PRINT(fmt, ...) DebugPrintP(PSTR(fmt), ##__VA_ARGS__) +void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize); +void DesfireLogISOStateChange(int state, int logCode); +#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 #define DEBUG_PRINT_P(fmtStr, ...) ({ \ uint8_t logLength = 0; \ do { \ snprintf_P((char *) __InternalStringBuffer, STRING_BUFFER_SIZE, \ - fmtStr, ##__VA_ARGS__); \ - logLength = StringLength((char *) __InternalStringBuffer, \ - STRING_BUFFER_SIZE); \ - DesfireLogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, \ - (char *) __InternalStringBuffer, logLength); \ + fmtStr, ##__VA_ARGS__); \ + logLength = StringLength((char *) __InternalStringBuffer, \ + STRING_BUFFER_SIZE); \ + DesfireLogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, \ + (char *) __InternalStringBuffer, logLength); \ } while(0); \ }) +#else +#define DEBUG_PRINT_P(fmtStr, ...) ({}) +#endif + +#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 +#define RUN_ON_DESFIRE_DEBUG(cppStmtToRun) ({ \ + cppStmtToRun; \ + }) +#else +#define RUN_ON_DESFIRE_DEBUG(cppStmtToRun) ({}) +#endif #define GetSourceFileLoggingData() ({ \ char *strBuffer; \ do { \ - snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, \ - PSTR("@@ LINE #%d in *%s @@"), \ - __LINE__, __FILE__); \ - __InternalStringBuffer[STRING_BUFFER_SIZE - 1] = '\0'; \ + snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, \ + PSTR(" @@ LINE #%d in *%s @@"), \ + __LINE__, __FILE__); \ + __InternalStringBuffer[STRING_BUFFER_SIZE - 1] = '\0'; \ } while(0); \ strBuffer = __InternalStringBuffer; \ strBuffer; \ @@ -137,19 +122,4 @@ void DebugPrintP(const char *fmt, ...); strBuffer; \ }) -#if defined(DESFIRE_DEFAULT_LOGGING_MODE) && DESFIRE_DEFAULT_LOGGING_MODE != 0 -#define LogDebuggingMsg(msg) ({ \ - do { \ - strncpy_P((char *) __InternalStringBuffer, msg, STRING_BUFFER_SIZE); \ - uint8_t sbufLength = StringLength((char *) __InternalStringBuffer, STRING_BUFFER_SIZE); \ - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, (void *) __InternalStringBuffer, \ - sbufLength); \ - } while(0); \ - }) -#else -#define LogDebuggingMsg(msg) ({}) -#endif - -#define DesfireLogISOStateChange(state, logCode) ({}) - #endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index 8d5ce194..cf04ccf6 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -59,6 +59,8 @@ SIZET DESFIRE_INITIAL_FIRST_FREE_BLOCK_ID = 0; SIZET DESFIRE_FIRST_FREE_BLOCK_ID = 0; SIZET CardCapacityBlocks = 0; +uint16_t DesfireATQAValue = DESFIRE_DEFAULT_ATQA_VALUE; + void InitBlockSizes(void) { DESFIRE_PICC_INFO_BLOCK_ID = 0; DESFIRE_APP_DIR_BLOCK_ID = DESFIRE_PICC_INFO_BLOCK_ID + @@ -103,13 +105,13 @@ TransferStatus PiccToPcdTransfer(uint8_t *Buffer) { //} /* Encrypt */ //Status.BytesProcessed = TransferState.ReadData.Encryption.Func(Buffer, XferBytes); - //Status.IsComplete = TransferState.ReadData.Encryption.AvailablePlaintext == 0; + Status.IsComplete = TransferState.ReadData.Encryption.AvailablePlaintext == 0; Status.BytesProcessed = XferBytes; Status.IsComplete = TransferState.ReadData.BytesLeft == 0; } else { /* Final encryption block */ //Status.BytesProcessed = TransferState.ReadData.Encryption.Func(Buffer, 0); - //Status.IsComplete = true; + Status.IsComplete = true; Status.BytesProcessed = 0; Status.IsComplete = true; } @@ -144,7 +146,7 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings) { SessionIVByteSize = CRYPTO_3KTDEA_KEY_SIZE; break; case DESFIRE_COMMS_CIPHERTEXT_AES128: - // A.k.a., CommMode=FULL from NXP application note AN12343: + /* A.k.a., CommMode=FULL from NXP application note AN12343: */ TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateCMAC; TransferState.Checksums.FinalFunc = &TransferChecksumFinalCMAC; TransferState.Checksums.MACData.CRCA = ISO14443A_CRCA_INIT; // TODO ??? @@ -210,9 +212,8 @@ void InitialisePiccBackendEV0(uint8_t StorageSize, bool formatPICC) { MemoryRecall(); ReadBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); if (formatPICC) { - snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, PSTR("Factory reset -- EV0")); - LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) __InternalStringBuffer, - StringLength(__InternalStringBuffer, STRING_BUFFER_SIZE)); + DEBUG_PRINT_P(PSTR("Factory reset -- EV0")); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0)); FactoryFormatPiccEV0(); } else { ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); @@ -230,9 +231,8 @@ void InitialisePiccBackendEV1(uint8_t StorageSize, bool formatPICC) { MemoryRecall(); ReadBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); if (formatPICC) { - snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, PSTR("Factory reset -- EV1")); - LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) __InternalStringBuffer, - StringLength(__InternalStringBuffer, STRING_BUFFER_SIZE)); + DEBUG_PRINT_P(PSTR("Factory reset -- EV1")); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0)); FactoryFormatPiccEV1(StorageSize); } else { ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); @@ -240,6 +240,26 @@ void InitialisePiccBackendEV1(uint8_t StorageSize, bool formatPICC) { } } +void InitialisePiccBackendEV2(uint8_t StorageSize, bool formatPICC) { +#ifdef DESFIRE_RUN_CRYPTO_TESTING_PROCEDURE + RunCryptoUnitTests(); +#endif + /* Init backend */ + InitBlockSizes(); + CardCapacityBlocks = StorageSize; + MemoryRecall(); + ReadBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); + if (formatPICC) { + DEBUG_PRINT_P(PSTR("Factory reset -- EV1")); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0)); + FactoryFormatPiccEV2(StorageSize); + } else { + ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); + SelectPiccApp(); + } + +} + void ResetPiccBackend(void) { InitBlockSizes(); SelectPiccApp(); @@ -293,9 +313,9 @@ void FormatPicc(void) { BYTE batchNumberData[5]; RandomGetBuffer(batchNumberData, 5); memcpy(&Picc.BatchNumber[0], batchNumberData, 5); - /* Production dates should be obvious until the user changes them: */ - Picc.ProductionWeek = 0x44; - Picc.ProductionYear = 0x7c; + /* Default production date -- until the user changes them: */ + Picc.ProductionWeek = 0x00; + Picc.ProductionYear = 0x00; /* Assign the default manufacturer ID: */ Picc.ManufacturerID = DESFIRE_MANUFACTURER_ID; /* Set the ATS bytes to defaults: */ @@ -359,6 +379,22 @@ void FactoryFormatPiccEV1(uint8_t StorageSize) { FormatPicc(); } +void FactoryFormatPiccEV2(uint8_t StorageSize) { + /* Wipe PICC data */ + memset(&Picc, PICC_FORMAT_BYTE, sizeof(Picc)); + /* Initialize params to look like EV1 */ + Picc.StorageSize = StorageSize; + Picc.HwVersionMajor = DESFIRE_HW_MAJOR_EV2; + Picc.HwVersionMinor = DESFIRE_HW_MINOR_EV2; + Picc.SwVersionMajor = DESFIRE_SW_MAJOR_EV2; + Picc.SwVersionMinor = DESFIRE_SW_MINOR_EV2; + /* Reset the free block pointer */ + Picc.FirstFreeBlock = DESFIRE_FIRST_FREE_BLOCK_ID; + /* Continue with user data initialization */ + SynchronizePICCInfo(); + FormatPicc(); +} + void GetPiccUid(ConfigurationUidType Uid) { memcpy(Uid, Picc.Uid, DESFIRE_UID_SIZE); } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.h index 8ddfb0ff..919e4d5d 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.h @@ -114,18 +114,26 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings); uint8_t WriteDataFilterSetup(uint8_t CommSettings); /* PICC management */ +void FormatPicc(void); +void CreatePiccApp(void); + void InitialisePiccBackendEV0(uint8_t StorageSize, bool formatPICC); void InitialisePiccBackendEV1(uint8_t StorageSize, bool formatPICC); +void InitialisePiccBackendEV2(uint8_t StorageSize, bool formatPICC); + +void FactoryFormatPiccEV0(void); +void FactoryFormatPiccEV1(uint8_t StorageSize); +void FactoryFormatPiccEV2(uint8_t StorageSize); + void ResetPiccBackend(void); + bool IsEmulatingEV1(void); + void GetPiccHardwareVersionInfo(uint8_t *Buffer); void GetPiccSoftwareVersionInfo(uint8_t *Buffer); void GetPiccManufactureInfo(uint8_t *Buffer); uint8_t GetPiccKeySettings(void); -void FormatPicc(void); -void CreatePiccApp(void); -void FactoryFormatPiccEV0(void); -void FactoryFormatPiccEV1(uint8_t StorageSize); + void GetPiccUid(ConfigurationUidType Uid); void SetPiccUid(ConfigurationUidType Uid); diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index 592b542f..c3866e20 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -30,44 +30,42 @@ This notice must be retained at the top of all source files where indicated. #include "DESFireFirmwareSettings.h" #include "DESFireISO14443Support.h" -#define DESFIRE_PICC_APP_SLOT 0x00 -#define DESFIRE_MASTER_KEY_ID 0x00 +#define DESFIRE_PICC_APP_SLOT 0x00 +#define DESFIRE_MASTER_KEY_ID 0x00 -#define DESFIRE_NATIVE_CLA 0x90 -#define DESFIRE_ISO7816_CLA 0x00 +#define DESFIRE_NATIVE_CLA 0x90 +#define DESFIRE_ISO7816_CLA 0x00 /* Storage allocation constants */ -#define DESFIRE_BLOCK_SIZE (1) /* Bytes */ -#define DESFIRE_BYTES_TO_BLOCKS(x) ( ((x) + DESFIRE_BLOCK_SIZE - 1) / DESFIRE_BLOCK_SIZE ) +#define DESFIRE_BLOCK_SIZE (1) /* Bytes */ +#define DESFIRE_BYTES_TO_BLOCKS(x) (((x) + DESFIRE_BLOCK_SIZE - 1) / DESFIRE_BLOCK_SIZE) -#define DESFIRE_UID_SIZE ISO14443A_UID_SIZE_DOUBLE -#define DESFIRE_MAX_PAYLOAD_SIZE (64) /* Bytes */ +#define DESFIRE_UID_SIZE ISO14443A_UID_SIZE_DOUBLE +#define DESFIRE_MAX_PAYLOAD_SIZE (64) /* Bytes */ /* * Definitions pertaining to on-card data */ /* Anticollision parameters */ -#define ATQA_VALUE 0x0344 +#define DESFIRE_DEFAULT_ATQA_VALUE 0x0344 +extern uint16_t DesfireATQAValue; + #ifndef FORCE_SAK_NOT_COMPLIANT -#define SAK_CL1_VALUE (ISO14443A_SAK_INCOMPLETE) -#define SAK_CL2_VALUE (ISO14443A_SAK_COMPLETE_COMPLIANT) +#define SAK_CL1_VALUE (ISO14443A_SAK_INCOMPLETE) +#define SAK_CL2_VALUE (ISO14443A_SAK_COMPLETE_COMPLIANT) #else -#define SAK_CL1_VALUE (ISO14443A_SAK_INCOMPLETE_NOT_COMPLIANT) -#define SAK_CL2_VALUE (ISO14443A_SAK_COMPLETE_NOT_COMPLIANT) +#define SAK_CL1_VALUE (ISO14443A_SAK_INCOMPLETE_NOT_COMPLIANT) +#define SAK_CL2_VALUE (ISO14443A_SAK_COMPLETE_NOT_COMPLIANT) #endif -#define STATUS_FRAME_SIZE (1 * 8) /* Bits */ - -#define DESFIRE_EV0_ATS_TL_BYTE 0x06 /* TL: ATS length, 6 bytes */ -#define DESFIRE_EV0_ATS_T0_BYTE 0x75 /* T0: TA, TB, TC present; max accepted frame is 64 bytes */ -#define DESFIRE_EV0_ATS_TA_BYTE 0x00 /* TA: Only the lowest bit rate is supported (normal is 0x77) */ -#define DESFIRE_EV0_ATS_TB_BYTE 0x81 /* TB: taken from the DESFire spec */ -#define DESFIRE_EV0_ATS_TC_BYTE 0x02 /* TC: taken from the DESFire spec */ +#define STATUS_FRAME_SIZE (1 * 8) /* Bits */ -#define GET_LE16(p) (*((uint16_t*)&(p)[0])) -#define GET_LE24(p) (*((__uint24*)&(p)[0])) -#define GET_LE32(p) (*((uint32_t*)&(p)[0])) +#define DESFIRE_EV0_ATS_TL_BYTE 0x06 /* TL: ATS length, 6 bytes */ +#define DESFIRE_EV0_ATS_T0_BYTE 0x75 /* T0: TA, TB, TC present; max accepted frame is 64 bytes */ +#define DESFIRE_EV0_ATS_TA_BYTE 0x00 /* TA: Only the lowest bit rate is supported (normal is 0x77) */ +#define DESFIRE_EV0_ATS_TB_BYTE 0x81 /* TB: taken from the DESFire spec */ +#define DESFIRE_EV0_ATS_TC_BYTE 0x02 /* TC: taken from the DESFire spec */ /* Defines for GetVersion */ #define ID_PHILIPS_NXP 0x04 @@ -80,36 +78,42 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_SW_PROTOCOL_TYPE 0x05 /** Source: http://www.proxmark.org/forum/viewtopic.php?id=2982 **/ +#define MIFARE_DESFIRE_EV0 0x00 +#define MIFARE_DESFIRE_EV1 0x01 +#define MIFARE_DESFIRE_EV2 0x02 + /* DESFire EV0 versions */ -#define DESFIRE_HW_MAJOR_EV0 0x00 -#define DESFIRE_HW_MINOR_EV0 0x01 -#define DESFIRE_SW_MAJOR_EV0 0x00 -#define DESFIRE_SW_MINOR_EV0 0x01 +#define DESFIRE_HW_MAJOR_EV0 0x00 +#define DESFIRE_HW_MINOR_EV0 0x01 +#define DESFIRE_SW_MAJOR_EV0 0x00 +#define DESFIRE_SW_MINOR_EV0 0x01 -#define IsPiccEV0(picc) (picc.HwVersionMajor == DESFIRE_HW_MAJOR_EV0 && picc.SwVersionMajor == DESFIRE_SW_MAJOR_EV0) +#define IsPiccEV0(picc) \ + (picc.HwVersionMajor == DESFIRE_HW_MAJOR_EV0 && \ + picc.SwVersionMajor == DESFIRE_SW_MAJOR_EV0) /* DESFire EV1 versions */ -#define DESFIRE_HW_MAJOR_EV1 0x01 -#define DESFIRE_HW_MINOR_EV1 0x01 -#define DESFIRE_SW_MAJOR_EV1 0x01 -#define DESFIRE_SW_MINOR_EV1 0x01 +#define DESFIRE_HW_MAJOR_EV1 0x01 +#define DESFIRE_HW_MINOR_EV1 0x01 +#define DESFIRE_SW_MAJOR_EV1 0x01 +#define DESFIRE_SW_MINOR_EV1 0x01 /* DESFire EV2 versions */ -#define DESFIRE_HW_MAJOR_EV2 0x12 -#define DESFIRE_HW_MINOR_EV2 0x01 -#define DESFIRE_SW_MAJOR_EV2 0x12 -#define DESFIRE_SW_MINOR_EV2 0x01 +#define DESFIRE_HW_MAJOR_EV2 0x12 +#define DESFIRE_HW_MINOR_EV2 0x01 +#define DESFIRE_SW_MAJOR_EV2 0x12 +#define DESFIRE_SW_MINOR_EV2 0x01 -#define DESFIRE_STORAGE_SIZE_2K 0x16 -#define DESFIRE_STORAGE_SIZE_4K 0x18 -#define DESFIRE_STORAGE_SIZE_8K 0x1A +#define DESFIRE_STORAGE_SIZE_2K 0x16 +#define DESFIRE_STORAGE_SIZE_4K 0x18 +#define DESFIRE_STORAGE_SIZE_8K 0x1A /* * Defines the global PICC configuration. * This is located in the very first block on the card. */ -#define PICC_FORMAT_BYTE (0x00) -#define PICC_EMPTY_BYTE (0x00) +#define PICC_FORMAT_BYTE 0x00 +#define PICC_EMPTY_BYTE 0x00 typedef struct { /* Static data: does not change during the PICC's lifetime. @@ -148,7 +152,6 @@ typedef struct { SIZET KeyVersionsArray; /* Block offset in FRAM */ SIZET KeyTypesArray; /* Block offset in FRAM */ SIZET KeyAddress; /* Block offset in FRAM */ - //UINT DirtyFlags; // USED ANYWHERE ??? } SelectedAppCacheType DESFIRE_FIRMWARE_PACKING; extern BYTE SELECTED_APP_CACHE_TYPE_BLOCK_SIZE; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h index e2eb91a4..25cc6f0e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h @@ -34,6 +34,10 @@ This notice must be retained at the top of all source files where indicated. #define ASBYTES(bc) (((bc) + BITS_PER_BYTE - 1) / BITS_PER_BYTE) #define ASBITS(bc) ((bc) * BITS_PER_BYTE) +#define GET_LE16(p) (*((uint16_t*)&(p)[0])) +#define GET_LE24(p) (*((__uint24*)&(p)[0])) +#define GET_LE32(p) (*((uint32_t*)&(p)[0])) + #define UnsignedTypeToUINT(typeValue) \ ((UINT) typeValue) #define ExtractLSBLE(ui) \ @@ -68,7 +72,7 @@ bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount); * SessionKey arrays are initialized in the Authenticate(Legacy|ISO|AES) commands * used to initiate the working session from PCD <--> PICC. * - * Helper methods to format and encode quirky or pathological cases of the + * Helper methods to format and encode quirky cases of the * CommSettings and wrapped APDU format combinations are defined statically in the * C source file to save space in the symbol table for the firmware (ELF) binary. */ diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c index 2ba520e7..067a04f6 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c @@ -11,10 +11,8 @@ #include "DESFire/DESFireISO14443Support.h" bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, uint8_t SAKValue) { - uint8_t *DataPtr = (uint8_t *) Buffer; uint8_t NVB = DataPtr[1]; - switch (NVB) { case ISO14443A_NVB_AC_START: @@ -30,10 +28,7 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, ui case ISO14443A_NVB_AC_END: /* End of anticollision procedure. * Send SAK CLn if we are selected. */ - if ((DataPtr[2] == UidCL[0]) && - (DataPtr[3] == UidCL[1]) && - (DataPtr[4] == UidCL[2]) && - (DataPtr[5] == UidCL[3])) { + if (!memcmp(&DataPtr[2], &UidCL[0], 4)) { DataPtr[0] = SAKValue; ISO14443AAppendCRCA(Buffer, 1); *BitCount = ISO14443A_SAK_FRAME_SIZE; diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index a266a482..9941797a 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -43,36 +43,32 @@ This notice must be retained at the top of all source files where indicated. #include "DESFire/DESFireLogging.h" #include "DESFire/DESFireUtils.h" -#define MIFARE_DESFIRE_EV0 (0x00) -#define MIFARE_DESFIRE_EV1 (0x01) -#define MIFARE_DESFIRE_EV2 (0x02) - -#define IsControlCmd(Buffer, BitCount) \ - (BitCount > 0 && \ +#define IsControlCmd(Buffer, BitCount) \ + (BitCount > 0 && \ ((Buffer[0] == ISO14443A_CMD_WUPA) || \ (Buffer[0] == ISO14443A_CMD_REQA))) DesfireStateType DesfireState = DESFIRE_HALT; DesfireStateType DesfirePreviousState = DESFIRE_IDLE; -bool DesfireFromHalt = false; -BYTE DesfireCmdCLA = DESFIRE_NATIVE_CLA; + Iso7816WrappedCommandType_t Iso7816CmdType; -/* Dispatching routines */ -void MifareDesfireReset(void) { - DesfireState = DESFIRE_IDLE; -} +bool DesfireFromHalt = false; +BYTE DesfireCmdCLA = DESFIRE_NATIVE_CLA; static void MifareDesfireAppInitLocal(uint8_t StorageSize, uint8_t Version, bool FormatPICC) { ResetLocalStructureData(); DesfireState = DESFIRE_IDLE; DesfireFromHalt = false; switch (Version) { + case MIFARE_DESFIRE_EV2: + InitialisePiccBackendEV1(StorageSize, FormatPICC); + break; case MIFARE_DESFIRE_EV1: InitialisePiccBackendEV1(StorageSize, FormatPICC); break; case MIFARE_DESFIRE_EV0: - default: /* Fall through */ + default: /* Fall through: */ InitialisePiccBackendEV0(StorageSize, FormatPICC); break; } @@ -103,33 +99,30 @@ void MifareDesfire4kEV1AppInitRunOnce(void) { MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_4K, MIFARE_DESFIRE_EV1, true); } -void MifareDesfire8kEV1AppInit(void) { - MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_8K, MIFARE_DESFIRE_EV1, false); +void MifareDesfire4kEV2AppInit(void) { + MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_4K, MIFARE_DESFIRE_EV2, false); } -void MifareDesfire8kEV1AppInitRunOnce(void) { - MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_8K, MIFARE_DESFIRE_EV1, true); +void MifareDesfire4kEV2AppInitRunOnce(void) { + MifareDesfireAppInitLocal(DESFIRE_STORAGE_SIZE_4K, MIFARE_DESFIRE_EV2, true); } void MifareDesfireAppReset(void) { - /* This is called repeatedly, so limit the amount of work done */ - ISO144433AReset(); - ISO144434Reset(); + /* This is called repeatedly -- limit the amount of work done */ MifareDesfireReset(); } void MifareDesfireAppTick(void) { - if (CheckStateRetryCount2(false, true)) { - MifareDesfireAppReset(); - } + /* EMPTY -- Do nothing. */ } void MifareDesfireAppTask(void) { - /* Empty */ + /* EMPTY -- Do nothing. */ } uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount)); if (ByteCount == 0) { return ISO14443A_APP_NO_RESPONSE; } else if (MutualAuthenticateCmd(Buffer[0])) { @@ -164,15 +157,15 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { ReturnBytes = DesfireCmdAuthenticateAES2(Buffer, ByteCount); break; case DESFIRE_ISO7816_EXT_AUTH: - DEBUG_PRINT_P(PSTR("TODO -- ISO7816-ExtAuth")); + DEBUG_PRINT_P(PSTR("Not Implemented -- ISO7816-ExtAuth")); ReturnBytes = ISO14443A_APP_NO_RESPONSE; break; case DESFIRE_ISO7816_INT_AUTH: - DEBUG_PRINT_P(PSTR("TODO -- ISO7816-IntAuth")); + DEBUG_PRINT_P(PSTR("Not Implemented -- ISO7816-IntAuth")); ReturnBytes = ISO14443A_APP_NO_RESPONSE; break; case DESFIRE_ISO7816_GET_CHALLENGE: - DEBUG_PRINT_P(PSTR("TODO -- ISO7816-GetChall")); + DEBUG_PRINT_P(PSTR("Not Implemented -- ISO7816-GetChal")); ReturnBytes = ISO14443A_APP_NO_RESPONSE; break; case DESFIRE_READ_DATA_FILE: @@ -183,6 +176,7 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { break; default: /* Should not happen. */ + DEBUG_PRINT_P(PSTR("ERROR -- Unexpected state!")); Buffer[0] = STATUS_PICC_INTEGRITY_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } @@ -193,7 +187,8 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { DesfireCmdCLA = Buffer[0]; size_t ByteCount = ASBYTES(BitCount); - LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount)); + ResetISOState(); if (ByteCount == 0) { return ISO14443A_APP_NO_RESPONSE; } else if (ByteCount >= 2 && Buffer[1] == STATUS_ADDITIONAL_FRAME && DesfireCLA(Buffer[0])) { @@ -247,12 +242,11 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { uint16_t ReturnedBytes = 0; uint16_t ByteCount = ASBYTES(BitCount); - LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount); - if (ByteCount > 1 && - !memcmp(&Buffer[0], &ISO14443ALastIncomingDataFrame[0], MIN(ASBYTES(ISO14443ALastIncomingDataFrameBits), ByteCount))) { + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount)); + if (ByteCount > 1 && !memcmp(&Buffer[0], &ISO14443ALastIncomingDataFrame[0], MIN(ASBYTES(ISO14443ALastIncomingDataFrameBits), ByteCount))) { /* The PCD resent the same data frame (probably a synchronization issue): * Send out the same data as last time: - */ + */ memcpy(&Buffer[0], &ISO14443ALastDataFrame[0], ASBYTES(ISO14443ALastDataFrameBits)); return ISO14443ALastDataFrameBits; } else { @@ -260,8 +254,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { ISO14443ALastIncomingDataFrameBits = BitCount; LastReaderSentCmd = Buffer[0]; } - if (ByteCount >= 3 && Buffer[2] == STATUS_ADDITIONAL_FRAME && - DesfireStateExpectingAdditionalFrame(DesfireState)) { + if (ByteCount >= 3 && Buffer[2] == STATUS_ADDITIONAL_FRAME && DesfireStateExpectingAdditionalFrame(DesfireState)) { /* [PM3-V1] : Handle the ISO-prologue-only-wrapped version of the additional frame data: */ uint8_t ISO7816PrologueBytes[2]; memcpy(&ISO7816PrologueBytes[0], &Buffer[0], 2); @@ -277,7 +270,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { } memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } else if (ByteCount >= 5 && DesfireCLA(Buffer[0]) && Buffer[1] == STATUS_ADDITIONAL_FRAME && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 9 && @@ -302,7 +295,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[ProcessedByteCount - 1] = 0x91; ++ProcessedByteCount; ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } else if (ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) { @@ -315,7 +308,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { return ISO14443A_APP_NO_RESPONSE; } ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } else if (ByteCount >= 8 && DesfireCLA(Buffer[1]) && Buffer[3] == 0x00 && Buffer[4] == 0x00 && Buffer[5] == ByteCount - 8) { @@ -335,7 +328,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { memmove(&Buffer[1], &Buffer[0], ProcessedByteCount); Buffer[0] = hf14AScanPrologue; ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } Iso7816CmdType = IsWrappedISO7816CommandType(Buffer, ByteCount); @@ -385,11 +378,12 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { } memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { /* This case should handle non-wrappped native commands. No pre/postprocessing afterwards: */ - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ReturnedBytes); + ResetISOState(); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ReturnedBytes)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ReturnedBytes)); } else { uint16_t PiccProcessRespBits = ISO144433APiccProcess(Buffer, BitCount); @@ -397,12 +391,17 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { if (PiccProcessRespBits >= BITS_PER_BYTE) { PiccProcessRespBits = ASBITS(PiccProcessRespBytesCeil); } - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, PiccProcessRespBytesCeil); + RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, PiccProcessRespBytesCeil)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, PiccProcessRespBits); } return ISO14443A_APP_NO_RESPONSE; } +void MifareDesfireReset(void) { + ResetISOState(); + DesfireState = DESFIRE_IDLE; +} + void ResetLocalStructureData(void) { DesfirePreviousState = DESFIRE_IDLE; DesfireState = DESFIRE_HALT; @@ -417,11 +416,15 @@ void ResetLocalStructureData(void) { SessionIVByteSize = 0x00; SelectedApp.Slot = 0; SelectedFile.Num = -1; + MifareDesfireReset(); +} + +void ResetISOState(void) { ISO144433AReset(); ISO144434Reset(); - MifareDesfireReset(); } + void MifareDesfireGetUid(ConfigurationUidType Uid) { GetPiccUid(Uid); } diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.h b/Firmware/Chameleon-Mini/Application/MifareDESFire.h index 59792dc8..c4c6a2cf 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.h +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.h @@ -37,19 +37,15 @@ This notice must be retained at the top of all source files where indicated. #include "DESFire/DESFireISO7816Support.h" #include "DESFire/DESFireInstructions.h" -/* The core functions used outside of this implementation - * to describe the DESFire emulation to the Chameleon firmware: - */ -void ResetLocalStructureData(void); -void MifareDesfireReset(void); void MifareDesfireEV0AppInit(void); void MifareDesfireEV0AppInitRunOnce(void); void MifareDesfire2kEV1AppInit(void); void MifareDesfire2kEV1AppInitRunOnce(void); void MifareDesfire4kEV1AppInit(void); void MifareDesfire4kEV1AppInitRunOnce(void); -void MifareDesfire8kEV1AppInit(void); -void MifareDesfire8kEV1AppInitRunOnce(void); +void MifareDesfire4kEV2AppInit(void); +void MifareDesfire4kEV2AppInitRunOnce(void); + void MifareDesfireAppReset(void); void MifareDesfireAppTick(void); void MifareDesfireAppTask(void); @@ -58,18 +54,15 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount); uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t ByteCount); uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount); +void MifareDesfireReset(void); +void ResetLocalStructureData(void); +void ResetISOState(void); + void MifareDesfireGetUid(ConfigurationUidType Uid); void MifareDesfireSetUid(ConfigurationUidType Uid); -/* Helper function definitions since we need them - * elsewhere in the backend, and so we do not need to - * declare them as static in the source. - */ -#define DesfireCLA(cmdCode) \ - ((cmdCode == DESFIRE_NATIVE_CLA) || Iso7816CLA(cmdCode)) - typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { - DESFIRE_HALT, + DESFIRE_HALT = ISO14443_3A_STATE_HALT + 1, DESFIRE_IDLE, DESFIRE_IDLE2, DESFIRE_GET_VERSION2, @@ -88,6 +81,17 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { DESFIRE_WRITE_DATA_FILE, } DesfireStateType; +extern DesfireStateType DesfireState; +extern DesfireStateType DesfirePreviousState; + +extern Iso7816WrappedCommandType_t Iso7816CmdType; + +extern bool DesfireFromHalt; +extern BYTE DesfireCmdCLA; + +#define DesfireCLA(cmdCode) \ + ((cmdCode == DESFIRE_NATIVE_CLA) || Iso7816CLA(cmdCode)) + #define DesfireStateExpectingAdditionalFrame(dfState) \ ((dfState == DESFIRE_GET_VERSION2) || \ (dfState == DESFIRE_GET_VERSION3) || \ @@ -103,10 +107,4 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { (cmdCode == CMD_ISO7816_INTERNAL_AUTHENTICATE) || \ (cmdCode == CMD_ISO7816_GET_CHALLENGE)) -extern DesfireStateType DesfireState; -extern DesfireStateType DesfirePreviousState; -extern bool DesfireFromHalt; -extern BYTE DesfireCmdCLA; -extern Iso7816WrappedCommandType_t Iso7816CmdType; - #endif /* MIFAREDESFIRE_H_ */ diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index 8f41d4e0..17dcb327 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -63,7 +63,7 @@ desfire: TARGET_CUSTOM_BUILD_NAME:=DESFire desfire: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) desfire: custom-build -desfire-dev: FLASH_DATA_SIZE_CONST:=0C000 # Six settings (save some space): 6 * 0x2000 +desfire-dev: FLASH_DATA_SIZE_CONST:=08000 # Four settings (save some space): 4 * 0x2000 desfire-dev: FLASH_DATA_SIZE:=0x$(FLASH_DATA_SIZE_CONST) desfire-dev: FLASH_DATA_SIZE_UPPER_CONST:=20000 desfire-dev: FLASH_DATA_ADDR:=0x$(shell echo "obase=16;ibase=16;$(FLASH_DATA_SIZE_UPPER_CONST)-$(FLASH_DATA_SIZE_CONST)" | bc) @@ -74,7 +74,8 @@ desfire-dev: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING \ - -DDESFIRE_DEFAULT_TESTING_MODE=1 + -DDESFIRE_DEFAULT_TESTING_MODE=1 \ + -DDESFIRE_DEBUGGING=1 desfire-dev: TARGET_CUSTOM_BUILD_NAME:=DESFire_DEV desfire-dev: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) desfire-dev: custom-build diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index fe804ab4..8a314be8 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -492,6 +492,22 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .MemorySize = MIFARE_CLASSIC_4K_MEM_SIZE, .ReadOnly = false }, + [CONFIG_MF_DESFIRE_4KEV2] = { + .CodecInitFunc = ISO14443ACodecInit, + .CodecDeInitFunc = ISO14443ACodecDeInit, + .CodecTaskFunc = ISO14443ACodecTask, + .ApplicationInitFunc = MifareDesfire4kEV2AppInit, + .ApplicationInitRunOnceFunc = MifareDesfire4kEV2AppInitRunOnce, + .ApplicationResetFunc = MifareDesfireAppReset, + .ApplicationTaskFunc = MifareDesfireAppTask, + .ApplicationTickFunc = MifareDesfireAppTick, + .ApplicationProcessFunc = MifareDesfireAppProcess, + .ApplicationGetUidFunc = MifareDesfireGetUid, + .ApplicationSetUidFunc = MifareDesfireSetUid, + .UidSize = ISO14443A_UID_SIZE_DOUBLE, + .MemorySize = MIFARE_CLASSIC_4K_MEM_SIZE, + .ReadOnly = false + }, #endif }; diff --git a/Firmware/Chameleon-Mini/Configuration.h b/Firmware/Chameleon-Mini/Configuration.h index 2ed04938..9a0f5aba 100644 --- a/Firmware/Chameleon-Mini/Configuration.h +++ b/Firmware/Chameleon-Mini/Configuration.h @@ -74,6 +74,7 @@ typedef enum { CONFIG_MF_DESFIRE, CONFIG_MF_DESFIRE_2KEV1, CONFIG_MF_DESFIRE_4KEV1, + CONFIG_MF_DESFIRE_4KEV2, #endif /* This HAS to be the last element */ CONFIG_COUNT diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 3965ffe6..d184bcb7 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -365,17 +365,17 @@ dfu-prog: $(TARGET).hex $(TARGET).eep check_size dfu-programmer $(MCU) reset check_size: BASH:=$(if $(shell which bash), $(shell which bash), /bin/bash) -check_size: BASH_SCRIPT_EXEC_LINES:=' \ +check_size: BASH_SCRIPT_EXEC_LINES:=' \ set -e; \ if [[ ! -f $(TARGET).elf ]]; then \ - exit 0; \ + exit 0; \ fi; \ PROGMEM_SIZE=$$(avr-size $(TARGET).elf | grep $(CHECK_SIZE_GREP_ARGS) | sed -n 4p); \ MAX_PRGMEM_SIZE=$$(printf "%d\n" $(FLASH_DATA_ADDR)); \ if [[ $$PROGMEM_SIZE -gt $$MAX_PRGMEM_SIZE ]]; then \ - echo \"make: *** $(TARGET).elf Application Section size $$PROGMEM_SIZE \" \ - echo \"excedes maximum allowed $$MAX_PRGMEM_SIZE. Please disable some features in Makefile\"; \ - exit 1; \ + $(ECHO) \"make: *** $(TARGET).elf Application Section size $$PROGMEM_SIZE \" \ + $(ECHO) \"excedes maximum allowed $$MAX_PRGMEM_SIZE. Please disable some features in Makefile\"; \ + exit 1; \ fi; \ ' check_size: From 93e77a27cdbac96b34a84a3fae0049f73d797f67 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Thu, 30 Jun 2022 22:42:22 -0400 Subject: [PATCH 67/68] Stashing changes to DESFire code -- No PSTR wrappers on command names as this doesn't change the ELF application size --- Doc/DESFireSupportReadme.md | 8 -- .../DESFire/DESFireChameleonTerminal.c | 126 +----------------- .../DESFire/DESFireChameleonTerminal.h | 18 +-- .../DESFire/DESFireChameleonTerminalInclude.c | 16 +-- .../Chameleon-Mini/Application/Reader14443A.c | 7 +- Firmware/Chameleon-Mini/Configuration.c | 7 +- .../Chameleon-Mini/Terminal/CommandLine.c | 14 +- Firmware/Chameleon-Mini/Terminal/Commands.c | 1 + Firmware/Chameleon-Mini/Terminal/Commands.h | 68 +++++----- 9 files changed, 62 insertions(+), 203 deletions(-) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index e054c478..11f94670 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -226,14 +226,6 @@ DESFire emulation if things suddenly fail after a call to this terminal command. Putting the Chameleon through a full power recycle (battery off) should reset the setting to the defaults. -#### DF_LOGMODE -- Sets the depth of (LIVE) logging messages printed at runtime - -Syntax -- not guaranteeing that all of these are meaningful or distinct just yet: -```bash -DF_LOGMODE=0 -DF_LOGMODE=1 -``` - ## Supported functionality ### Tables of tested support for active commands diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c index 948604f2..0fedeffa 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.c @@ -35,27 +35,16 @@ This notice must be retained at the top of all source files where indicated. #include "DESFireLogging.h" bool IsDESFireConfiguration(void) { - return GlobalSettings.ActiveSettingPtr->Configuration == CONFIG_MF_DESFIRE; -} - -CommandStatusIdType ExitOnInvalidConfigurationError(char *OutParam) { - if (OutParam != NULL) { - sprintf_P(OutParam, PSTR("Invalid Configuration: Set `CONFIG=MF_DESFIRE`.\r\n")); - } - return COMMAND_ERR_INVALID_USAGE_ID; + return GlobalSettings.ActiveSettingPtr->Configuration == CONFIG_MF_DESFIRE || + GlobalSettings.ActiveSettingPtr->Configuration == CONFIG_MF_DESFIRE_2KEV1 || + GlobalSettings.ActiveSettingPtr->Configuration == CONFIG_MF_DESFIRE_4KEV1 || + GlobalSettings.ActiveSettingPtr->Configuration == CONFIG_MF_DESFIRE_4KEV2; } #ifndef DISABLE_PERMISSIVE_DESFIRE_SETTINGS -CommandStatusIdType CommandDESFireGetHeaderProperty(char *OutParam) { - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, - PSTR("%s "), - DFCOMMAND_SET_HEADER); - return COMMAND_INFO_OK_WITH_TEXT_ID; -} - CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutParam, const char *InParams) { if (!IsDESFireConfiguration()) { - ExitOnInvalidConfigurationError(OutParam); + return COMMAND_ERR_INVALID_USAGE_ID; } char hdrPropSpecStr[24]; char propSpecBytesStr[16]; @@ -63,7 +52,6 @@ CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutParam, const char * SIZET dataByteCount = 0x00; BYTE StatusError = 0x00; if (!sscanf_P(InParams, PSTR("%24s %12s"), hdrPropSpecStr, propSpecBytesStr)) { - CommandDESFireGetHeaderProperty(OutParam); return COMMAND_ERR_INVALID_PARAM_ID; } hdrPropSpecStr[23] = propSpecBytesStr[15] = '\0'; @@ -119,7 +107,6 @@ CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutParam, const char * StatusError = 1; } if (StatusError) { - CommandDESFireGetHeaderProperty(OutParam); return COMMAND_ERR_INVALID_USAGE_ID; } SynchronizePICCInfo(); @@ -127,109 +114,9 @@ CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutParam, const char * } #endif /* DISABLE_PERMISSIVE_DESFIRE_SETTINGS */ -CommandStatusIdType CommandDESFireGetLoggingMode(char *OutParam) { - if (!IsDESFireConfiguration()) { - ExitOnInvalidConfigurationError(OutParam); - } - switch (LocalLoggingMode) { - case OFF: - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("OFF")); - break; - case NORMAL: - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("NORMAL")); - break; - case VERBOSE: - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("VERBOSE")); - break; - case DEBUGGING: - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("DEBUGGING")); - break; - default: - break; - } - return COMMAND_INFO_OK_WITH_TEXT_ID; -} - -CommandStatusIdType CommandDESFireSetLoggingMode(char *OutParam, const char *InParams) { - if (!IsDESFireConfiguration()) { - ExitOnInvalidConfigurationError(OutParam); - } - char valueStr[16]; - if (!sscanf_P(InParams, PSTR("%15s"), valueStr)) { - return COMMAND_ERR_INVALID_PARAM_ID; - } - valueStr[15] = '\0'; - if (!strcasecmp_P(valueStr, PSTR("1")) || !strcasecmp_P(valueStr, PSTR("TRUE")) || - !strcasecmp_P(valueStr, PSTR("ON"))) { - LocalLoggingMode = NORMAL; - return COMMAND_INFO_OK_ID; - } else if (!strcasecmp_P(valueStr, PSTR("0")) || !strcasecmp_P(valueStr, PSTR("FALSE")) || - !strcasecmp_P(valueStr, PSTR("OFF"))) { - LocalLoggingMode = OFF; - return COMMAND_INFO_OK_ID; - } else if (!strcasecmp_P(valueStr, PSTR("VERBOSE"))) { - LocalLoggingMode = VERBOSE; - return COMMAND_INFO_OK_ID; - } else if (!strcasecmp_P(valueStr, PSTR("DEBUGGING"))) { - LocalLoggingMode = DEBUGGING; - return COMMAND_INFO_OK_ID; - } else { - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("%s "), - DFCOMMAND_LOGGING_MODE); - return COMMAND_ERR_INVALID_USAGE_ID; - } -} - -CommandStatusIdType CommandDESFireGetTestingMode(char *OutParam) { - if (!IsDESFireConfiguration()) { - ExitOnInvalidConfigurationError(OutParam); - } else if (LocalTestingMode) { - return COMMAND_INFO_TRUE_ID; - } - return COMMAND_INFO_FALSE_ID; -} - -CommandStatusIdType CommandDESFireSetTestingMode(char *OutParam, const char *InParams) { - if (!IsDESFireConfiguration()) { - ExitOnInvalidConfigurationError(OutParam); - } - char valueStr[16]; - if (!sscanf_P(InParams, PSTR("%15s"), valueStr)) { - return COMMAND_ERR_INVALID_PARAM_ID; - } - valueStr[15] = '\0'; - if (!strcasecmp_P(valueStr, PSTR("1")) || !strcasecmp_P(valueStr, PSTR("TRUE")) || - !strcasecmp_P(valueStr, PSTR("ON"))) { - LocalTestingMode = 0x01; - return COMMAND_INFO_TRUE_ID; - } else if (!strcasecmp_P(valueStr, PSTR("0")) || !strcasecmp_P(valueStr, PSTR("FALSE")) || - !strcasecmp_P(valueStr, PSTR("OFF"))) { - LocalTestingMode = 0x00; - return COMMAND_INFO_FALSE_ID; - } - return COMMAND_ERR_INVALID_USAGE_ID; -} - -CommandStatusIdType CommandDESFireGetCommMode(char *OutParam) { - if (!IsDESFireConfiguration()) { - ExitOnInvalidConfigurationError(OutParam); - } else if (DesfireCommMode == DESFIRE_COMMS_PLAINTEXT) { - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Plaintext")); - } else if (DesfireCommMode == DESFIRE_COMMS_PLAINTEXT_MAC) { - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Plaintext/MAC")); - } else if (DesfireCommMode == DESFIRE_COMMS_CIPHERTEXT_DES) { - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Enciphered/DES")); - } else if (DesfireCommMode == DESFIRE_COMMS_CIPHERTEXT_AES128) { - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Enciphered/AES128")); - } else { - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Unknown")); - } - return COMMAND_INFO_OK_WITH_TEXT_ID; -} - CommandStatusIdType CommandDESFireSetCommMode(char *OutParam, const char *InParams) { if (!IsDESFireConfiguration()) { - ExitOnInvalidConfigurationError(OutParam); + return COMMAND_ERR_INVALID_USAGE_ID; } char valueStr[16]; if (!sscanf_P(InParams, PSTR("%15s"), valueStr)) { @@ -253,7 +140,6 @@ CommandStatusIdType CommandDESFireSetCommMode(char *OutParam, const char *InPara DesfireCommandState.ActiveCommMode = DesfireCommMode; return COMMAND_INFO_OK; } - snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Options are: Plaintext|Plaintext:MAC|Enciphered:3K3DES|Enciphered:AES128")); return COMMAND_ERR_INVALID_USAGE_ID; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h index 22d8f19c..dd97ec42 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminal.h @@ -38,22 +38,12 @@ bool IsDESFireConfiguration(void); #ifndef DISABLE_PERMISSIVE_DESFIRE_SETTINGS #define DFCOMMAND_SET_HEADER "DF_SETHDR" -CommandStatusIdType CommandDESFireGetHeaderProperty(char *OutParam); CommandStatusIdType CommandDESFireSetHeaderProperty(char *OutMessage, const char *InParams); -#endif +#endif /* DISABLE_PERMISSIVE_DESFIRE_SETTINGS */ -#define DFCOMMAND_LOGGING_MODE "DF_LOGMODE" -CommandStatusIdType CommandDESFireGetLoggingMode(char *OutParam); -CommandStatusIdType CommandDESFireSetLoggingMode(char *OutMessage, const char *InParams); - -#define DFCOMMAND_TESTING_MODE "DF_TESTMODE" -CommandStatusIdType CommandDESFireGetTestingMode(char *OutParam); -CommandStatusIdType CommandDESFireSetTestingMode(char *OutMessage, const char *InParams); - -#define DFCOMMAND_COMM_MODE "DF_COMM_MODE" -CommandStatusIdType CommandDESFireGetCommMode(char *OutParam); +#define DFCOMMAND_COMM_MODE "DF_COMM_MODE" CommandStatusIdType CommandDESFireSetCommMode(char *OutMessage, const char *InParams); -#endif +#endif /* DESFire Support */ -#endif +#endif /* __DESFIRE_CHAMELEON_TERMINAL_H__ */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c index 41935c15..4ec11316 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireChameleonTerminalInclude.c @@ -33,25 +33,13 @@ This notice must be retained at the top of all source files where indicated. .ExecFunc = NO_FUNCTION, .ExecParamFunc = NO_FUNCTION, .SetFunc = CommandDESFireSetHeaderProperty, - .GetFunc = CommandDESFireGetHeaderProperty -}, { - .Command = DFCOMMAND_LOGGING_MODE, - .ExecFunc = NO_FUNCTION, - .ExecParamFunc = NO_FUNCTION, - .SetFunc = CommandDESFireSetLoggingMode, - .GetFunc = CommandDESFireGetLoggingMode -}, { - .Command = DFCOMMAND_TESTING_MODE, - .ExecFunc = NO_FUNCTION, - .ExecParamFunc = NO_FUNCTION, - .SetFunc = CommandDESFireSetTestingMode, - .GetFunc = CommandDESFireGetTestingMode + .GetFunc = NO_FUNCTION }, { .Command = DFCOMMAND_COMM_MODE, .ExecFunc = NO_FUNCTION, .ExecParamFunc = NO_FUNCTION, .SetFunc = CommandDESFireSetCommMode, - .GetFunc = CommandDESFireGetCommMode + .GetFunc = NO_FUNCTION }, #endif diff --git a/Firmware/Chameleon-Mini/Application/Reader14443A.c b/Firmware/Chameleon-Mini/Application/Reader14443A.c index a0485a04..988c0566 100644 --- a/Firmware/Chameleon-Mini/Application/Reader14443A.c +++ b/Firmware/Chameleon-Mini/Application/Reader14443A.c @@ -1,5 +1,4 @@ -#if defined(CONFIG_ISO14443A_READER_SUPPORT) || \ - defined(CONFIG_ISO14443A_SNIFF_SUPPORT) +#if defined(CONFIG_ISO14443A_READER_SUPPORT) || defined(CONFIG_ISO14443A_SNIFF_SUPPORT) #include "Reader14443A.h" #include "LEDHook.h" @@ -99,8 +98,8 @@ static const CardIdentificationType PROGMEM CardIdentificationList[] = { [CardType_NXP_MIFARE_Classic_1k] = { .ATQA = 0x0004, .ATQARelevant = true, .SAK = 0x08, .SAKRelevant = true, .ATSRelevant = false, .Manufacturer = "NXP", .Type = "MIFARE Classic 1k" }, [CardType_NXP_MIFARE_Classic_4k] = { .ATQA = 0x0002, .ATQARelevant = true, .SAK = 0x18, .SAKRelevant = true, .ATSRelevant = false, .Manufacturer = "NXP", .Type = "MIFARE Classic 4k" }, [CardType_NXP_MIFARE_Ultralight] = { .ATQA = 0x0044, .ATQARelevant = true, .SAK = 0x00, .SAKRelevant = true, .ATSRelevant = false, .Manufacturer = "NXP", .Type = "MIFARE Ultralight" }, -// [CardType_NXP_MIFARE_Ultralight_C] = { .ATQA=0x0044, .ATQARelevant=true, .SAK=0x00, .SAKRelevant=true, .ATSRelevant=false, .Manufacturer="NXP", .Type="MIFARE Ultralight C" }, -// [CardType_NXP_MIFARE_Ultralight_EV1] = { .ATQA=0x0044, .ATQARelevant=true, .SAK=0x00, .SAKRelevant=false, .ATSRelevant=false, .Manufacturer="NXP", .Type="MIFARE Ultralight EV1" }, + //[CardType_NXP_MIFARE_Ultralight_C] = { .ATQA=0x0044, .ATQARelevant=true, .SAK=0x00, .SAKRelevant=true, .ATSRelevant=false, .Manufacturer="NXP", .Type="MIFARE Ultralight C" }, + //[CardType_NXP_MIFARE_Ultralight_EV1] = { .ATQA=0x0044, .ATQARelevant=true, .SAK=0x00, .SAKRelevant=false, .ATSRelevant=false, .Manufacturer="NXP", .Type="MIFARE Ultralight EV1" }, // for the following two, setting ATSRelevant to true would cause checking the ATS value, but the NXP paper for distinguishing cards does not recommend this [CardType_NXP_MIFARE_DESFire] = { .ATQA = 0x0344, .ATQARelevant = true, .SAK = 0x20, .SAKRelevant = true, .ATSRelevant = false, .ATSSize = 5, .ATS = {0x75, 0x77, 0x81, 0x02, 0x80}, .Manufacturer = "NXP", .Type = "MIFARE DESFire" }, [CardType_NXP_MIFARE_DESFire_EV1] = { .ATQA = 0x0344, .ATQARelevant = true, .SAK = 0x20, .SAKRelevant = true, .ATSRelevant = false, .ATSSize = 5, .ATS = {0x75, 0x77, 0x81, 0x02, 0x80}, .Manufacturer = "NXP", .Type = "MIFARE DESFire EV1" }, diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index 8a314be8..b7f7b951 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -69,9 +69,10 @@ static const MapEntryType PROGMEM ConfigurationMap[] = { { .Id = CONFIG_EM4233, .Text = "EM4233" }, #endif #ifdef CONFIG_MF_DESFIRE_SUPPORT - { .Id = CONFIG_MF_DESFIRE, .Text = "MF_DESFIRE" }, - { .Id = CONFIG_MF_DESFIRE_2KEV1, .Text = "MF_DESFIRE_2KEV1" }, - { .Id = CONFIG_MF_DESFIRE_4KEV1, .Text = "MF_DESFIRE_4KEV1" }, + { .Id = CONFIG_MF_DESFIRE, .Text = "MF_DESFIRE" }, + { .Id = CONFIG_MF_DESFIRE_2KEV1, .Text = "MF_DESFIRE_2KEV1" }, + { .Id = CONFIG_MF_DESFIRE_4KEV1, .Text = "MF_DESFIRE_4KEV1" }, + { .Id = CONFIG_MF_DESFIRE_4KEV2, .Text = "MF_DESFIRE_4KEV2" }, #endif }; diff --git a/Firmware/Chameleon-Mini/Terminal/CommandLine.c b/Firmware/Chameleon-Mini/Terminal/CommandLine.c index f318493e..1f402ec4 100644 --- a/Firmware/Chameleon-Mini/Terminal/CommandLine.c +++ b/Firmware/Chameleon-Mini/Terminal/CommandLine.c @@ -12,7 +12,7 @@ #define CHAR_GET_MODE '?' /* ? */ #define CHAR_SET_MODE '=' /* = */ #define CHAR_EXEC_MODE '\0' /* */ -#define CHAR_EXEC_MODE_PARAM ' ' /* ... */ +#define CHAR_EXEC_MODE_PARAM ' ' /* ... */ #define IS_COMMAND_DELIMITER(c) ( \ ((c) == CHAR_EXEC_MODE) || ((c) == CHAR_GET_MODE) || ((c) == CHAR_SET_MODE) || ((c) == CHAR_EXEC_MODE_PARAM) \ @@ -34,7 +34,7 @@ #define NO_FUNCTION ((void*) 0) #define STATUS_MESSAGE_TRAILER "\r\n" -#define OPTIONAL_ANSWER_TRAILER "\r\n" +#define OPTIONAL_ANSWER_TRAILER "\r\n" /* Include all command functions */ #include "Commands.h" @@ -492,10 +492,12 @@ static void DecodeCommand(void) { TerminalSendString(pTerminalBuffer); TerminalSendStringP(PSTR(OPTIONAL_ANSWER_TRAILER)); if (StringLength(pTerminalBuffer, TERMINAL_BUFFER_SIZE) + 1 >= TERMINAL_BUFFER_SIZE) { - // Notify the user that the command line output is truncated. This can come up in the - // 'CONFIG=MF_DESFIRE' variants where the Makefile setting 'MEMORY_LIMITED_TESTING' is - // enabled by default to save space for other necessary components. - TerminalSendStringP(PSTR("-- OUTPUT TRUNCATED --")); + /* + * Notify the user that the command line output is truncated. This can come up in the + * 'CONFIG=MF_DESFIRE' variants where the Makefile setting 'MEMORY_LIMITED_TESTING' is + * enabled by default to save space for other necessary components. + */ + TerminalSendStringP(PSTR("--TRUNCATED OUTPUT--")); TerminalSendStringP(PSTR(OPTIONAL_ANSWER_TRAILER)); } } diff --git a/Firmware/Chameleon-Mini/Terminal/Commands.c b/Firmware/Chameleon-Mini/Terminal/Commands.c index 7b5ccb28..0f389d48 100644 --- a/Firmware/Chameleon-Mini/Terminal/Commands.c +++ b/Firmware/Chameleon-Mini/Terminal/Commands.c @@ -21,6 +21,7 @@ #ifdef CONFIG_ISO15693_SNIFF_SUPPORT #include "../Codec/SniffISO15693.h" #endif /*#ifdef CONFIG_ISO15693_SNIFF_SUPPORT*/ + extern Reader14443Command Reader14443CurrentCommand; extern Sniff14443Command Sniff14443CurrentCommand; diff --git a/Firmware/Chameleon-Mini/Terminal/Commands.h b/Firmware/Chameleon-Mini/Terminal/Commands.h index fd5e4dc1..caf2b504 100644 --- a/Firmware/Chameleon-Mini/Terminal/Commands.h +++ b/Firmware/Chameleon-Mini/Terminal/Commands.h @@ -16,23 +16,23 @@ #define COMMAND_INFO_XMODEM_WAIT_ID 110 #define COMMAND_INFO_XMODEM_WAIT "WAITING FOR XMODEM" #define COMMAND_INFO_FALSE_ID 120 -#define COMMAND_INFO_FALSE "FALSE" +#define COMMAND_INFO_FALSE "FALSE" #define COMMAND_INFO_TRUE_ID 121 -#define COMMAND_INFO_TRUE "TRUE" +#define COMMAND_INFO_TRUE "TRUE" #define COMMAND_ERR_UNKNOWN_CMD_ID 200 #define COMMAND_ERR_UNKNOWN_CMD "UNKNOWN COMMAND" #define COMMAND_ERR_INVALID_USAGE_ID 201 #define COMMAND_ERR_INVALID_USAGE "INVALID COMMAND USAGE" #define COMMAND_ERR_INVALID_PARAM_ID 202 #define COMMAND_ERR_INVALID_PARAM "INVALID PARAMETER" -#define COMMAND_ERR_TIMEOUT_ID 203 -#define COMMAND_ERR_TIMEOUT "TIMEOUT" -#define TIMEOUT_COMMAND 255 // this is just for the CommandLine module to know that this is a timeout command +#define COMMAND_ERR_TIMEOUT_ID 203 +#define COMMAND_ERR_TIMEOUT "TIMEOUT" +#define TIMEOUT_COMMAND 255 // this is just for the CommandLine module to know that this is a timeout command #define COMMAND_CHAR_TRUE '1' #define COMMAND_CHAR_FALSE '0' -#define COMMAND_CHAR_SUGGEST '?' /* =? for help */ +#define COMMAND_CHAR_SUGGEST '?' /* =? for help */ #define COMMAND_UID_BUFSIZE 32 @@ -54,58 +54,58 @@ typedef struct { CommandGetFuncType GetFunc; } CommandEntryType; -#define COMMAND_VERSION "VERSION" +#define COMMAND_VERSION "VERSION" CommandStatusIdType CommandGetVersion(char *OutParam); -#define COMMAND_CONFIG "CONFIG" +#define COMMAND_CONFIG "CONFIG" CommandStatusIdType CommandGetConfig(char *OutParam); CommandStatusIdType CommandSetConfig(char *OutMessage, const char *InParam); -#define COMMAND_UID "UID" -#define COMMAND_UID_RANDOM "RANDOM" +#define COMMAND_UID "UID" +#define COMMAND_UID_RANDOM "RANDOM" CommandStatusIdType CommandGetUid(char *OutParam); CommandStatusIdType CommandSetUid(char *OutMessage, const char *InParam); -#define COMMAND_READONLY "READONLY" +#define COMMAND_READONLY "READONLY" CommandStatusIdType CommandGetReadOnly(char *OutParam); CommandStatusIdType CommandSetReadOnly(char *OutMessage, const char *InParam); -#define COMMAND_UPLOAD "UPLOAD" +#define COMMAND_UPLOAD "UPLOAD" CommandStatusIdType CommandExecUpload(char *OutMessage); -#define COMMAND_DOWNLOAD "DOWNLOAD" +#define COMMAND_DOWNLOAD "DOWNLOAD" CommandStatusIdType CommandExecDownload(char *OutMessage); -#define COMMAND_RESET "RESET" +#define COMMAND_RESET "RESET" CommandStatusIdType CommandExecReset(char *OutMessage); -#define COMMAND_UPGRADE "UPGRADE" +#define COMMAND_UPGRADE "UPGRADE" CommandStatusIdType CommandExecUpgrade(char *OutMessage); -#define COMMAND_MEMSIZE "MEMSIZE" +#define COMMAND_MEMSIZE "MEMSIZE" CommandStatusIdType CommandGetMemSize(char *OutParam); -#define COMMAND_UIDSIZE "UIDSIZE" +#define COMMAND_UIDSIZE "UIDSIZE" CommandStatusIdType CommandGetUidSize(char *OutParam); -#define COMMAND_RBUTTON "RBUTTON" +#define COMMAND_RBUTTON "RBUTTON" CommandStatusIdType CommandGetRButton(char *OutParam); CommandStatusIdType CommandSetRButton(char *OutMessage, const char *InParam); -#define COMMAND_RBUTTON_LONG "RBUTTON_LONG" +#define COMMAND_RBUTTON_LONG "RBUTTON_LONG" CommandStatusIdType CommandGetRButtonLong(char *OutParam); CommandStatusIdType CommandSetRButtonLong(char *OutMessage, const char *InParam); -#define COMMAND_LBUTTON "LBUTTON" +#define COMMAND_LBUTTON "LBUTTON" CommandStatusIdType CommandGetLButton(char *OutParam); CommandStatusIdType CommandSetLButton(char *OutMessage, const char *InParam); -#define COMMAND_LBUTTON_LONG "LBUTTON_LONG" +#define COMMAND_LBUTTON_LONG "LBUTTON_LONG" CommandStatusIdType CommandGetLButtonLong(char *OutParam); CommandStatusIdType CommandSetLButtonLong(char *OutMessage, const char *InParam); -#define COMMAND_LEDGREEN "LEDGREEN" +#define COMMAND_LEDGREEN "LEDGREEN" CommandStatusIdType CommandGetLedGreen(char *OutParam); CommandStatusIdType CommandSetLedGreen(char *OutMessage, const char *InParam); @@ -113,24 +113,24 @@ CommandStatusIdType CommandSetLedGreen(char *OutMessage, const char *InParam); CommandStatusIdType CommandGetLedRed(char *OutParam); CommandStatusIdType CommandSetLedRed(char *OutMessage, const char *InParam); -#define COMMAND_PIN "PIN" +#define COMMAND_PIN "PIN" CommandStatusIdType CommandGetPin(char *OutParam); CommandStatusIdType CommandSetPin(char *OutMessage, const char *InParam); -#define COMMAND_LOGMODE "LOGMODE" +#define COMMAND_LOGMODE "LOGMODE" CommandStatusIdType CommandGetLogMode(char *OutParam); CommandStatusIdType CommandSetLogMode(char *OutMessage, const char *InParam); -#define COMMAND_LOGMEM "LOGMEM" +#define COMMAND_LOGMEM "LOGMEM" CommandStatusIdType CommandGetLogMem(char *OutParam); #define COMMAND_LOGDOWNLOAD "LOGDOWNLOAD" CommandStatusIdType CommandExecLogDownload(char *OutMessage); -#define COMMAND_STORELOG "LOGSTORE" +#define COMMAND_STORELOG "LOGSTORE" CommandStatusIdType CommandExecStoreLog(char *OutMessage); -#define COMMAND_LOGCLEAR "LOGCLEAR" +#define COMMAND_LOGCLEAR "LOGCLEAR" CommandStatusIdType CommandExecLogClear(char *OutMessage); #define COMMAND_SETTING "SETTING" @@ -149,7 +149,7 @@ CommandStatusIdType CommandExecRecall(char *OutMessage); #define COMMAND_CHARGING "CHARGING" CommandStatusIdType CommandGetCharging(char *OutParam); -#define COMMAND_HELP "HELP" +#define COMMAND_HELP "HELP" CommandStatusIdType CommandExecHelp(char *OutMessage); #define COMMAND_RSSI "RSSI" @@ -158,7 +158,7 @@ CommandStatusIdType CommandGetRssi(char *OutParam); #define COMMAND_SYSTICK "SYSTICK" CommandStatusIdType CommandGetSysTick(char *OutParam); -#define COMMAND_SEND_RAW "SEND_RAW" +#define COMMAND_SEND_RAW "SEND_RAW" CommandStatusIdType CommandExecParamSendRaw(char *OutMessage, const char *InParams); #define COMMAND_SEND "SEND" @@ -167,7 +167,7 @@ CommandStatusIdType CommandExecParamSend(char *OutMessage, const char *InParams) #define COMMAND_GETUID "GETUID" CommandStatusIdType CommandExecGetUid(char *OutMessage); -#define COMMAND_DUMP_MFU "DUMP_MFU" +#define COMMAND_DUMP_MFU "DUMP_MFU" CommandStatusIdType CommandExecDumpMFU(char *OutMessage); #define COMMAND_CLONE_MFU "CLONE_MFU" @@ -184,18 +184,18 @@ CommandStatusIdType CommandSetTimeout(char *OutMessage, const char *InParam); CommandStatusIdType CommandGetThreshold(char *OutParam); CommandStatusIdType CommandSetThreshold(char *OutMessage, const char *InParam); -#define COMMAND_AUTOCALIBRATE "AUTOCALIBRATE" +#define COMMAND_AUTOCALIBRATE "AUTOCALIBRATE" CommandStatusIdType CommandExecAutocalibrate(char *OutMessage); -#define COMMAND_FIELD "FIELD" +#define COMMAND_FIELD "FIELD" CommandStatusIdType CommandSetField(char *OutMessage, const char *InParam); CommandStatusIdType CommandGetField(char *OutMessage); -#define COMMAND_CLONE "CLONE" +#define COMMAND_CLONE "CLONE" CommandStatusIdType CommandExecClone(char *OutMessage); #ifdef CONFIG_ISO15693_SNIFF_SUPPORT -#define COMMAND_AUTOTHRESHOLD "AUTOTHRESHOLD" +#define COMMAND_AUTOTHRESHOLD "AUTOTHRESHOLD" CommandStatusIdType CommandGetAutoThreshold(char *OutParam); CommandStatusIdType CommandSetAutoThreshold(char *OutMessage, const char *InParam); #endif /*#ifdef CONFIG_ISO15693_SNIFF_SUPPORT*/ From bc8057bfe7c5f1972c94204c3bfaadaf444006da Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Fri, 1 Jul 2022 08:44:21 -0400 Subject: [PATCH 68/68] Several fixes to responsiveness and frozen behavior noted in PR #319 --- Doc/DESFireSupportReadme.md | 9 +- Firmware/Chameleon-Mini/AntennaLevel.c | 2 +- .../DESFire/DESFireApplicationDirectory.c | 8 +- .../Application/DESFire/DESFireCrypto.c | 4 +- .../Application/DESFire/DESFireFile.c | 27 --- .../Application/DESFire/DESFireFile.h | 6 +- .../DESFire/DESFireISO14443Support.c | 157 +++++++++--------- .../DESFire/DESFireISO14443Support.h | 30 ++-- .../DESFire/DESFireISO7816Support.h | 1 - .../Application/DESFire/DESFireInstructions.c | 63 +++---- .../Application/DESFire/DESFireInstructions.h | 12 +- .../Application/DESFire/DESFireLogging.c | 39 ++--- .../Application/DESFire/DESFireLogging.h | 44 +---- .../DESFire/DESFireMemoryOperations.c | 1 - .../DESFire/DESFireMemoryOperations.h | 4 +- .../Application/DESFire/DESFirePICCControl.c | 24 +-- .../DESFire/DESFirePICCHeaderLayout.h | 8 +- .../Application/DESFire/DESFireUtils.c | 19 +-- .../Application/DESFire/DESFireUtils.h | 6 + .../Chameleon-Mini/Application/ISO14443-3A.c | 37 +++-- .../Chameleon-Mini/Application/ISO14443-3A.h | 6 +- .../Application/MifareDESFire.c | 116 +++++++------ .../Application/MifareDESFire.h | 23 ++- .../Chameleon-Mini/Application/Reader14443A.c | 2 +- .../BuildScripts/custom_build_targets.mk | 2 - Firmware/Chameleon-Mini/Chameleon-Mini.c | 5 +- Firmware/Chameleon-Mini/Common.c | 1 - Firmware/Chameleon-Mini/Common.h | 5 +- Firmware/Chameleon-Mini/LiveLogTick.h | 13 +- Firmware/Chameleon-Mini/Log.c | 22 +-- Firmware/Chameleon-Mini/Makefile | 10 +- 31 files changed, 323 insertions(+), 383 deletions(-) diff --git a/Doc/DESFireSupportReadme.md b/Doc/DESFireSupportReadme.md index 11f94670..7433bb75 100644 --- a/Doc/DESFireSupportReadme.md +++ b/Doc/DESFireSupportReadme.md @@ -2,13 +2,7 @@ ## Quick configuration of cloned DESFire tags -### Chameleon Mini terminal addons to support ``CONFIG=MF_DESFIRE`` modes - -Note that these commands are only compiled into the firmware when the compiler -option ``-DALLOW_DESFIRE_TERMINAL_COMMANDS`` and ``-DCONFIG_MF_DESFIRE_SUPPORT`` are -specified. If you do not at miniumum have a configuration, ``CONFIG=MF_DESFIRE``, then -these commands will not work. Note that LIVE logging should be disabled before attempting to -run these commands. +### Chameleon Mini terminal addons to support DESFire tag configurations #### Selecting a DESFire configuration @@ -47,6 +41,7 @@ DF_SETHDR=ATS 0675f7b102 ``` To reset the ATQA value returned in the anticollision loop handshaking: ``` +DF_SETHDR=ATQA 0344 DF_SETHDR=ATQA 2838 ``` diff --git a/Firmware/Chameleon-Mini/AntennaLevel.c b/Firmware/Chameleon-Mini/AntennaLevel.c index 834d18de..499ad922 100644 --- a/Firmware/Chameleon-Mini/AntennaLevel.c +++ b/Firmware/Chameleon-Mini/AntennaLevel.c @@ -11,7 +11,7 @@ void AntennaLevelTick(void) { if (rssi < FIELD_MIN_RSSI) { LEDHook(LED_FIELD_DETECTED, LED_OFF); if (ActiveConfiguration.UidSize != 0) // this implies that we are emulating right now - ApplicationReset(); // reset the application just like a real card gets reset when there is no field + ApplicationReset(); // reset the application just like a real card gets reset when there is no field } else { LEDHook(LED_FIELD_DETECTED, LED_ON); AntennaLevelLogReaderDetectCount = (++AntennaLevelLogReaderDetectCount) % ANTENNA_LEVEL_LOG_RDRDETECT_INTERVAL; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c index d66cc85a..afa6c51c 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireApplicationDirectory.c @@ -703,7 +703,7 @@ uint16_t DeleteApp(const DESFireAidType Aid) { AppDir.FirstFreeSlot = MIN(Slot, AppDir.FirstFreeSlot); SynchronizeAppDir(); if (!IsPiccAppSelected()) { - InvalidateAuthState(0x00); + InvalidateAuthState(0); } SelectAppBySlot(DESFIRE_PICC_APP_SLOT); return STATUS_OPERATION_OK; @@ -720,11 +720,11 @@ TransferStatus GetApplicationIdsTransfer(uint8_t *Buffer) { Status.BytesProcessed = 0; for (EntryIndex = TransferState.GetApplicationIds.NextIndex; EntryIndex < DESFIRE_MAX_SLOTS; ++EntryIndex) { - if ((AppDir.AppIds[EntryIndex][0] | AppDir.AppIds[EntryIndex][1] | - AppDir.AppIds[EntryIndex][2]) == 0) + if ((AppDir.AppIds[EntryIndex][0] | AppDir.AppIds[EntryIndex][1] | AppDir.AppIds[EntryIndex][2]) == 0) { continue; + } /* If it won't fit -- remember and return */ - if (Status.BytesProcessed >= TERMINAL_BUFFER_SIZE) { // TODO ??? 19 / Magic Number ??? + if (Status.BytesProcessed >= TERMINAL_BUFFER_SIZE) { TransferState.GetApplicationIds.NextIndex = EntryIndex; Status.IsComplete = false; return Status; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c index 268e86c7..92b526d9 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireCrypto.c @@ -216,7 +216,7 @@ uint8_t CryptoAESTransferEncryptSend(uint8_t *Buffer, uint8_t Count, const uint8 } uint8_t CryptoAESTransferEncryptReceive(uint8_t *Buffer, uint8_t Count, const uint8_t *Key) { - LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA_ENC, Buffer, Count); + DesfireLogEntry(LOG_INFO_DESFIRE_INCOMING_DATA_ENC, Buffer, Count); return STATUS_OPERATION_OK; } #endif @@ -322,7 +322,7 @@ uint8_t TransferEncryptTDEASend(uint8_t *Buffer, uint8_t Count) { } uint8_t TransferEncryptTDEAReceive(uint8_t *Buffer, uint8_t Count) { - LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA_ENC, Buffer, Count); + DesfireLogEntry(LOG_INFO_DESFIRE_INCOMING_DATA_ENC, Buffer, Count); return 0; } diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.c index 8e252495..b0478fa7 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.c @@ -370,31 +370,4 @@ uint8_t ValidateAuthentication(uint16_t AccessRights, uint16_t CheckMask) { return VALIDATED_ACCESS_DENIED; } -const char *GetFileAccessPermissionsDesc(uint16_t fileAccessRights) { - __InternalStringBuffer[0] = '\0'; - BYTE removeTrailingText = 0x00; - if (GetReadPermissions(fileAccessRights) != DESFIRE_ACCESS_DENY) { - strcat_P(__InternalStringBuffer, PSTR("R/")); - removeTrailingText = 0x01; - } - if (GetWritePermissions(fileAccessRights) != DESFIRE_ACCESS_DENY) { - strcat_P(__InternalStringBuffer, PSTR("W/")); - removeTrailingText = 0x01; - - } - if (GetReadWritePermissions(fileAccessRights) != DESFIRE_ACCESS_DENY) { - strcat_P(__InternalStringBuffer, PSTR("RW/")); - removeTrailingText = 0x01; - } - if (GetChangePermissions(fileAccessRights) != DESFIRE_ACCESS_DENY) { - strcat_P(__InternalStringBuffer, PSTR("CHG")); - removeTrailingText = 0x00; - } - if (removeTrailingText) { - BYTE bufSize = StringLength(__InternalStringBuffer, STRING_BUFFER_SIZE); - __InternalStringBuffer[bufSize - 1] = '\0'; - } - return __InternalStringBuffer; -} - #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.h index 2e91b65c..974b0723 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireFile.h @@ -52,7 +52,7 @@ This notice must be retained at the top of all source files where indicated. /* Data about an application's file is currently kept in this structure. * The location of these structures is defined by the file index. */ -typedef struct DESFIRE_FIRMWARE_PACKING { +typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT { uint8_t FileType; uint8_t FileNumber; uint16_t FileSize; @@ -86,7 +86,7 @@ typedef struct DESFIRE_FIRMWARE_PACKING { uint16_t GetFileSizeFromFileType(DESFireFileTypeSettings *File); -typedef struct DESFIRE_FIRMWARE_PACKING { +typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT { BYTE Num; DESFireFileTypeSettings File; } SelectedFileCacheType; @@ -149,8 +149,6 @@ uint16_t WriteDataFileIterator(uint8_t *Buffer, uint16_t ByteCount); #define GetChangePermissions(AccessRights) \ (BYTE) (((0xf000 & AccessRights) >> 12) & 0x000f) -const char *GetFileAccessPermissionsDesc(uint16_t fileAccessRights); - /* * There are also command/instruction-wise * citations given from file's access permissions. This data is taken diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c index ac6002df..3be3a17b 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.c @@ -39,10 +39,10 @@ This notice must be retained at the top of all source files where indicated. */ Iso144434StateType Iso144434State = ISO14443_4_STATE_EXPECT_RATS; -uint8_t Iso144434BlockNumber = 0x00; -uint8_t Iso144434CardID = 0x00; -uint8_t Iso144434LastBlockLength = 0x00; -uint8_t StateRetryCount = 0x00; +uint8_t Iso144434BlockNumber = 0; +uint8_t Iso144434CardID = 1; +uint8_t Iso144434LastBlockLength = 0; +uint8_t StateRetryCount = 0; uint8_t LastReaderSentCmd = 0x00; uint8_t ISO14443ALastDataFrame[MAX_DATA_FRAME_XFER_SIZE] = { 0x00 }; @@ -53,8 +53,7 @@ uint16_t ISO14443ALastIncomingDataFrameBits = 0; bool CheckStateRetryCountWithLogging(bool resetByDefault, bool performLogging) { if (resetByDefault || ++StateRetryCount > MAX_STATE_RETRY_COUNT) { ISO144434SwitchStateWithLogging(Iso144433AIdleState, performLogging); - StateRetryCount = 0x00; - DEBUG_PRINT_P(PSTR("RETRY-RESET")); + StateRetryCount = 0; return true; } return false; @@ -65,12 +64,10 @@ bool CheckStateRetryCount(bool resetByDefault) { void ISO144434SwitchStateWithLogging(Iso144434StateType NewState, bool performLogging) { Iso144434State = NewState; - StateRetryCount = 0x00; -#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 - if (performLogging) { - RUN_ON_DESFIRE_DEBUG(DesfireLogISOStateChange(Iso144434State, LOG_ISO14443_4_STATE)); + StateRetryCount = 0; + if (DesfireDebuggingOn && performLogging) { + DesfireLogISOStateChange(Iso144434State, LOG_ISO14443_4_STATE); } -#endif } void ISO144434SwitchState(Iso144434StateType NewState) { @@ -82,15 +79,16 @@ void ISO144434Reset(void) { Iso144434State = ISO14443_4_STATE_EXPECT_RATS; Iso144434BlockNumber = 1; ISO14443ALastDataFrameBits = 0; + ISO14443ALastDataFrame[0] = 0x00; LastReaderSentCmd = 0x00; } -static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount) { +uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount) { uint8_t PCB = Buffer[0]; uint8_t MyBlockNumber = Iso144434BlockNumber; - uint8_t PrologueLength; - uint8_t HaveCID, HaveNAD; + uint8_t PrologueLength = 0; + uint8_t HaveCID = 0, HaveNAD = 0; /* Verify the block's length: at the very least PCB + CRCA */ if (ByteCount < (1 + ISO14443A_CRCA_SIZE)) { @@ -102,14 +100,14 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 /* Verify the checksum; fail if doesn't match */ if (!ISO14443ACheckCRCA(Buffer, ByteCount)) { - LogEntry(LOG_ERR_APP_CHECKSUM_FAIL, Buffer, ByteCount); + DesfireLogEntry(LOG_ERR_APP_CHECKSUM_FAIL, (uint8_t *) NULL, 0); /* ISO/IEC 14443-4, clause 7.5.5. The PICC does not attempt any error recovery. */ - DEBUG_PRINT_P(PSTR("WARN: 14443-4: CRC fail; %04X vs %04X"), *(uint16_t *)&Buffer[ByteCount], - ISO14443AAppendCRCA(Buffer, ByteCount)); + DEBUG_PRINT_P(PSTR("WARN: 14443-4: CRC fail")); return ISO14443A_APP_NO_RESPONSE; } switch (Iso144434State) { + case ISO14443_4_STATE_EXPECT_RATS: { /* See: ISO/IEC 14443-4, clause 5.6.1.2 */ if (Buffer[0] != ISO14443A_CMD_RATS) { @@ -121,14 +119,14 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 * NOTE: ATS bytes are tailored to Chameleon implementation and differ from DESFire spec. * NOTE: Some PCD implementations do a memcmp() over ATS bytes, which is completely wrong. */ + //DEBUG_PRINT_P(PSTR("ISO14443-4: SEND RATS")); Iso144434CardID = Buffer[1] & 0x0F; Buffer[0] = 0x06; memcpy(&Buffer[1], &Picc.ATSBytes[1], 4); Buffer[5] = 0x80; /* T1: dummy value for historical bytes */ - ByteCount = 6; // NOT including CRC + ByteCount = 6; /* NOT including CRC */ ISO144434SwitchState(ISO14443_4_STATE_ACTIVE); - DEBUG_PRINT_P(PSTR("ISO14443-4: SEND RATS")); - return ASBITS(ByteCount); // PM3 expects no CRCA bytes + return ASBITS(ByteCount); /* PM3 expects no CRCA bytes */ } case ISO14443_4_STATE_ACTIVE: { /* See: ISO/IEC 14443-4; 7.1 Block format */ @@ -161,18 +159,19 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 } switch (PCB & ISO14443_PCB_BLOCK_TYPE_MASK) { + case ISO14443_PCB_I_BLOCK: { HaveNAD = PCB & ISO14443_PCB_HAS_NAD_MASK; if (HaveNAD) { PrologueLength++; /* Not currently supported -- the frame is ignored */ - DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK -- %d"), __LINE__); + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK")); } /* 7.5.3.2, rule D: toggle on each I-block */ Iso144434BlockNumber = MyBlockNumber = !MyBlockNumber; if (PCB & ISO14443_PCB_I_BLOCK_CHAINING_MASK) { /* Currently not supported -- the frame is ignored */ - DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK -- %d"), __LINE__); + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_I_BLOCK")); return ISO14443A_APP_NO_RESPONSE; } @@ -199,7 +198,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 case ISO14443_PCB_R_BLOCK: { /* 7.5.4.3, rule 11 */ if ((PCB & ISO14443_PCB_BLOCK_NUMBER_MASK) == MyBlockNumber) { - DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"), __LINE__); + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK")); return ISO14443A_APP_NO_RESPONSE; } if (PCB & ISO14443_PCB_R_BLOCK_ACKNAK_MASK) { @@ -211,7 +210,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 } else { /* This is an ACK: */ /* NOTE: Chaining is not supported yet. */ - DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK -- %d"), __LINE__); + DEBUG_PRINT_P(PSTR("ISO144434ProcessBlock: ISO14443_PCB_R_BLOCK")); // Resend the data from the last frame: if (ISO14443ALastDataFrameBits > 0) { memcpy(&Buffer[0], &ISO14443ALastDataFrame[0], ASBYTES(ISO14443ALastDataFrameBits)); @@ -245,7 +244,7 @@ static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint1 } - /* Fall through (default handling when there is no response to register/return to the sender): */ + /* Fall through: */ return ISO14443A_APP_NO_RESPONSE; } @@ -272,14 +271,15 @@ Iso144433AStateType Iso144433AIdleState = ISO14443_3A_STATE_IDLE; void ISO144433ASwitchState(Iso144433AStateType NewState) { Iso144433AState = NewState; - StateRetryCount = 0x00; - RUN_ON_DESFIRE_DEBUG(DesfireLogISOStateChange(Iso144433AState, LOG_ISO14443_3A_STATE)); + DesfireLogISOStateChange(Iso144433AState, LOG_ISO14443_3A_STATE); } void ISO144433AReset(void) { /* No logging performed -- spams the log and slows things way down! */ Iso144433AState = ISO14443_3A_STATE_IDLE; Iso144433AIdleState = ISO14443_3A_STATE_IDLE; + StateRetryCount = 0; + ISO14443ALastDataFrame[0] = 0x00; ISO14443ALastDataFrameBits = 0; } @@ -287,7 +287,6 @@ void ISO144433AHalt(void) { ISO144433ASwitchState(ISO14443_3A_STATE_HALT); Iso144433AIdleState = ISO14443_3A_STATE_HALT; ISO144433AReset(); - StateRetryCount = 0x00; } bool ISO144433AIsHalt(const uint8_t *Buffer, uint16_t BitCount) { @@ -300,39 +299,33 @@ bool ISO144433AIsHalt(const uint8_t *Buffer, uint16_t BitCount) { uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { if (BitCount == 0) { - ISO144434Reset(); - ISO144433AHalt(); + //ISO144434Reset(); + //ISO144433AHalt(); return ISO14443A_APP_NO_RESPONSE; } uint8_t Cmd = Buffer[0]; /* Wakeup and Request may occure in all states */ - bool checkStateRetryStatus = CheckStateRetryCount(false); - bool incrementRetryCount = true; if (Cmd == ISO14443A_CMD_REQA) { - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_REQA, NULL, 0)); + DesfireLogEntry(LOG_INFO_APP_CMD_REQA, NULL, 0); ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); - incrementRetryCount = false; + StateRetryCount = 0; } else if (ISO14443ACmdIsWUPA(Cmd)) { - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_WUPA, NULL, 0)); + DesfireLogEntry(LOG_INFO_APP_CMD_WUPA, NULL, 0); ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); - incrementRetryCount = false; + StateRetryCount = 0; } else if (ISO144433AIsHalt(Buffer, BitCount)) { - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0)); + DesfireLogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); DEBUG_PRINT_P(PSTR("ISO14443-3: HALTING")); ISO144433AHalt(); return ISO14443A_APP_NO_RESPONSE; } - LastReaderSentCmd = Cmd; - if (incrementRetryCount) { - StateRetryCount += 1; - } - /* This implements ISO 14443-3A state machine */ /* See: ISO/IEC 14443-3, clause 6.2 */ switch (Iso144433AState) { + case ISO14443_3A_STATE_HALT: if (!ISO14443ACmdIsWUPA(Cmd)) { DEBUG_PRINT_P(PSTR("ISO14443-4: HALT -- NOT WUPA")); @@ -340,68 +333,81 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { } else { ISO144433ASwitchState(ISO14443_3A_STATE_IDLE); } - /* Fall-through */ case ISO14443_3A_STATE_IDLE: Iso144433AIdleState = Iso144433AState; - ISO144433ASwitchState(ISO14443_3A_STATE_READY1); + ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL1); Buffer[0] = DesfireATQAValue & 0x00FF; Buffer[1] = (DesfireATQAValue >> 8) & 0x00FF; - DEBUG_PRINT_P(PSTR("ISO14443-4 (IDLE): ATQA -- %04x"), DesfireATQAValue); return ASBITS(ISO14443A_ATQA_FRAME_SIZE_BYTES); - case ISO14443_3A_STATE_READY1: + case ISO14443_3A_STATE_READY_CL1: + case ISO14443_3A_STATE_READY_CL1_NVB_END: if (Cmd == ISO14443A_CMD_SELECT_CL1) { - /* Load UID CL1 and perform anticollision. */ + /* Load UID CL1 and perform anticollisio: */ ConfigurationUidType Uid; ApplicationGetUid(Uid); if (ActiveConfiguration.UidSize >= ISO14443A_UID_SIZE_DOUBLE) { - Uid[3] = Uid[2]; - Uid[2] = Uid[1]; - Uid[1] = Uid[0]; Uid[0] = ISO14443A_UID0_CT; } - if (ISO14443ASelectDesfire(Buffer, &BitCount, Uid, SAK_CL1_VALUE)) { - /* CL1 stage has ended successfully */ - DEBUG_PRINT_P(PSTR("ISO14443-4: Select OK")); - ISO144433ASwitchState(ISO14443_3A_STATE_READY2); + uint8_t cl1SAKValue = IS_ISO14443A_4_COMPLIANT(Buffer[1]) ? ISO14443A_SAK_INCOMPLETE : ISO14443A_SAK_INCOMPLETE_NOT_COMPLIANT; + Buffer[1] = MAKE_ISO14443A_4_COMPLIANT(Buffer[1]); + if (Buffer[1] == ISO14443A_NVB_AC_START && !ISO14443ASelectDesfire(Buffer, &BitCount, Uid, cl1SAKValue) && BitCount > 0) { + //DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL1 NVB START -- OK")); + ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL1_NVB_END); + return BitCount; + } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(Buffer, &BitCount, Uid, cl1SAKValue)) { + //DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL1 NVB END -- OK")); + ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL2); + return BitCount; + } else { - DEBUG_PRINT_P(PSTR("ISO14443-4: Select NAK")); + DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL1 NOT OK")); } - return BitCount; + } else { + DEBUG_PRINT_P(PSTR("ISO14443-4: RDY1 -- NOT SLCT CMD")); } - DEBUG_PRINT_P(PSTR("ISO14443-4: RDY1 -- NOT SLCT CMD")); - break; + CheckStateRetryCount(false); + return ISO14443A_APP_NO_RESPONSE; - case ISO14443_3A_STATE_READY2: + case ISO14443_3A_STATE_READY_CL2: + case ISO14443_3A_STATE_READY_CL2_NVB_END: if (Cmd == ISO14443A_CMD_SELECT_CL2 && ActiveConfiguration.UidSize >= ISO14443A_UID_SIZE_DOUBLE) { - /* Load UID CL2 and perform anticollision */ + /* Load UID CL2 and perform anticollision: */ ConfigurationUidType Uid; ApplicationGetUid(Uid); - if (ISO14443ASelectDesfire(Buffer, &BitCount, &Uid[3], SAK_CL2_VALUE)) { - /* CL2 stage has ended successfully. This means - * our complete UID has been sent to the reader. */ + uint8_t cl2SAKValue = IS_ISO14443A_4_COMPLIANT(Buffer[1]) ? ISO14443A_SAK_COMPLETE_COMPLIANT : ISO14443A_SAK_COMPLETE_NOT_COMPLIANT; + Buffer[1] = MAKE_ISO14443A_4_COMPLIANT(Buffer[1]); + if (Buffer[1] == ISO14443A_NVB_AC_START && !ISO14443ASelectDesfire(Buffer, &BitCount, &Uid[4], cl2SAKValue) && BitCount > 0) { + //DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL2 NVB START -- OK")); + ISO144433ASwitchState(ISO14443_3A_STATE_READY_CL2_NVB_END); + return BitCount; + } else if (Buffer[1] == ISO14443A_NVB_AC_END && ISO14443ASelectDesfire(Buffer, &BitCount, &Uid[4], cl2SAKValue)) { + //DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL2 NVB END -- OK")); ISO144433ASwitchState(ISO14443_3A_STATE_ACTIVE); + return BitCount; + } else { - DEBUG_PRINT_P(PSTR("ISO14443-4: Incorrect select value (R2)")); + DEBUG_PRINT_P(PSTR("ISO14443-4: Select CL2 NOT OK")); } - return BitCount; + } else { + DEBUG_PRINT_P(PSTR("ISO14443-4: RDY2 -- NOT SLCT CMD")); } - DEBUG_PRINT_P(PSTR("ISO14443-4: RDY2 -- NOT SLCT CMD")); - break; + CheckStateRetryCount(false); + return ISO14443A_APP_NO_RESPONSE; case ISO14443_3A_STATE_ACTIVE: StateRetryCount = MAX_STATE_RETRY_COUNT; if (ISO144433AIsHalt(Buffer, BitCount)) { /* Recognise the HLTA command: */ - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0)); - ISO144434SwitchState(ISO14443_3A_STATE_HALT); - DEBUG_PRINT_P(PSTR("ISO14443-3: Got HALT")); + DesfireLogEntry(LOG_INFO_APP_CMD_HALT, NULL, 0); + ISO144433AHalt(); return ISO14443A_APP_NO_RESPONSE; } else if (Cmd == ISO14443A_CMD_RATS) { - ISO144433ASwitchState(ISO14443_4_STATE_EXPECT_RATS); - DEBUG_PRINT_P(PSTR("ISO14443-3/4: Expecting RATS")); + //DEBUG_PRINT_P(PSTR("ISO14443-3/4: Expecting RATS")); + ISO144434SwitchState(ISO14443_4_STATE_EXPECT_RATS); } else if (Cmd == ISO14443A_CMD_SELECT_CL3) { + /* DESFire UID size is of insufficient size to support this: */ Buffer[0] = ISO14443A_SAK_COMPLETE_NOT_COMPLIANT; ISO14443AAppendCRCA(&Buffer[0], 1); return ISO14443A_SAK_FRAME_SIZE; @@ -409,12 +415,12 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { /* This has been observed to happen at this stage when swiping the * Chameleon running CONFIG=MF_DESFIRE on an ACR122 USB external reader. */ - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_APP_CMD_DESELECT, NULL, 0)); + DesfireLogEntry(LOG_INFO_APP_CMD_DESELECT, NULL, 0); } /* Forward to ISO/IEC 14443-4 processing code */ + //DEBUG_PRINT_P(PSTR("ISO14443-4: ACTIVE RET")); uint16_t ByteCount = ASBYTES(BitCount); uint16_t ReturnBits = ISO144434ProcessBlock(Buffer, ByteCount, BitCount); - DEBUG_PRINT_P(PSTR("ISO14443-4: ACTIVE RET")); return ReturnBits; default: @@ -423,8 +429,7 @@ uint16_t ISO144433APiccProcess(uint8_t *Buffer, uint16_t BitCount) { } /* Fallthrough: Unknown command. Reset back to idle/halt state. */ - bool defaultReset = false; - if (!CheckStateRetryCount(defaultReset)) { + if (!CheckStateRetryCount(false)) { DEBUG_PRINT_P(PSTR("ISO14443-3: Fall through -- RESET TO IDLE 0x%02x"), Cmd); return ISO14443A_APP_NO_RESPONSE; } else { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h index a5cacd61..5bd7909e 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO14443Support.h @@ -75,8 +75,8 @@ This notice must be retained at the top of all source files where indicated. #define ISO14443_PCB_S_WTX (ISO14443_PCB_S_BLOCK_STATIC | 0x30) #define ISO14443A_CMD_PPS 0xD0 -#define IS_ISO14443A_4_COMPLIANT(buf) (buf[0] & 0x20) -#define MAKE_ISO14443A_4_COMPLIANT(buf) (buf[0] |= 0x20) +#define IS_ISO14443A_4_COMPLIANT(bufByte) (bufByte & 0x20) +#define MAKE_ISO14443A_4_COMPLIANT(bufByte) (bufByte |= 0x20) /* * ISO/IEC 14443-4 implementation @@ -100,22 +100,14 @@ extern uint8_t LastReaderSentCmd; /* Configure saving last data frame state so can resend on ACK from the PCD */ -#define MAX_DATA_FRAME_XFER_SIZE (64) +#define MAX_DATA_FRAME_XFER_SIZE (72) extern uint8_t ISO14443ALastDataFrame[MAX_DATA_FRAME_XFER_SIZE]; extern uint16_t ISO14443ALastDataFrameBits; extern uint8_t ISO14443ALastIncomingDataFrame[MAX_DATA_FRAME_XFER_SIZE]; extern uint16_t ISO14443ALastIncomingDataFrameBits; +uint16_t ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t BufferBitCount); -INLINE ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t BufferBitCount) { - uint16_t ISO14443ALastDataFrameBytes = MIN((BufferBitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE, MAX_DATA_FRAME_XFER_SIZE); - if (ISO14443ALastDataFrameBytes > 0) { - memcpy(ISO14443ALastDataFrame, &Buffer[0], ISO14443ALastDataFrameBytes); - } - ISO14443ALastDataFrameBits = BufferBitCount; - return BufferBitCount; -} - -#define MAX_STATE_RETRY_COUNT (0x04) +#define MAX_STATE_RETRY_COUNT (0x0B) extern uint8_t StateRetryCount; bool CheckStateRetryCount(bool resetByDefault); bool CheckStateRetryCountWithLogging(bool resetByDefault, bool performLogging); @@ -125,12 +117,12 @@ void ISO144434SwitchState(Iso144434StateType NewState); void ISO144434SwitchStateWithLogging(Iso144434StateType NewState, bool performLogging); void ISO144434Reset(void); -static uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount); +uint16_t ISO144434ProcessBlock(uint8_t *Buffer, uint16_t ByteCount, uint16_t BitCount); /* * ISO/IEC 14443-3A implementation */ -#define ISO14443A_CRCA_INIT ((uint16_t) 0x6363) +#define ISO14443A_CRCA_INIT ((uint16_t) 0x6363) uint16_t ISO14443AUpdateCRCA(const uint8_t *Buffer, uint16_t ByteCount, uint16_t InitCRCA); #define GetAndSetBufferCRCA(Buffer, ByteCount) ({ \ @@ -141,7 +133,7 @@ uint16_t ISO14443AUpdateCRCA(const uint8_t *Buffer, uint16_t ByteCount, uint16_t }) #define GetAndSetNoResponseCRCA(Buffer) ({ \ uint16_t fullReturnBits = 0; \ - ISO14443AAppendCRCA(Buffer, 0); \ + ISO14443AUpdateCRCA(Buffer, 0, ISO14443A_CRCA_INIT); \ fullReturnBits = ISO14443A_CRC_FRAME_SIZE; \ fullReturnBits; \ }) @@ -150,8 +142,10 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { /* The card is powered up but not selected: */ ISO14443_3A_STATE_IDLE = ISO14443_4_STATE_LAST + 1, /* Entered on REQA or WUP -- anticollision is being performed: */ - ISO14443_3A_STATE_READY1, - ISO14443_3A_STATE_READY2, + ISO14443_3A_STATE_READY_CL1, + ISO14443_3A_STATE_READY_CL1_NVB_END, + ISO14443_3A_STATE_READY_CL2, + ISO14443_3A_STATE_READY_CL2_NVB_END, /* Entered when the card has been selected: */ ISO14443_3A_STATE_ACTIVE, /* Something went wrong or we've received a halt command: */ diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h index eb7474df..9fe78979 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireISO7816Support.h @@ -88,7 +88,6 @@ typedef enum { ISO7816_WRAPPED_CMD_TYPE_STANDARD = 1, ISO7816_WRAPPED_CMD_TYPE_PM3RAW = 2, ISO7816_WRAPPED_CMD_TYPE_PM3_ADDITIONAL_FRAME = 3, - /* TODO -- Others ??? */ } Iso7816WrappedCommandType_t; extern Iso7816WrappedCommandType_t Iso7816CmdType; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c index 09774cb7..68c261c8 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.c @@ -100,9 +100,6 @@ static uint16_t EV0CmdAbortTransaction(uint8_t *Buffer, uint16_t ByteCount); static uint16_t ISO7816CmdSelect(uint8_t *Buffer, uint16_t ByteCount); static uint16_t ISO7816CmdSelectEF(uint8_t *Buffer, uint16_t ByteCount); static uint16_t ISO7816CmdSelectDF(uint8_t *Buffer, uint16_t ByteCount); -static uint16_t ISO7816CmdGetChallenge(uint8_t *Buffer, uint16_t ByteCount); -static uint16_t ISO7816CmdExternalAuthenticate(uint8_t *Buffer, uint16_t ByteCount); -static uint16_t ISO7816CmdInternalAuthenticate(uint8_t *Buffer, uint16_t ByteCount); static uint16_t ISO7816CmdReadBinary(uint8_t *Buffer, uint16_t ByteCount); static uint16_t ISO7816CmdUpdateBinary(uint8_t *Buffer, uint16_t ByteCount); static uint16_t ISO7816CmdReadRecords(uint8_t *Buffer, uint16_t ByteCount); @@ -442,7 +439,7 @@ uint16_t DesfireCmdFreeMemory(uint8_t *Buffer, uint16_t ByteCount) { */ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { - BYTE KeyId, Status; + BYTE KeyId; BYTE keySize; BYTE *Key; @@ -480,10 +477,10 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { } else { ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); } - LogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); + DesfireLogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); /* Generate the nonce B (RndB / Challenge response) */ - if (LocalTestingMode == 0) { + if (DesfireDebuggingOn) { RandomGetBuffer(DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); } else { /* Fixed nonce for testing */ @@ -504,7 +501,7 @@ uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount) { DesfireCommandState.RndB[14] = 0x22; DesfireCommandState.RndB[15] = 0x33; } - LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + DesfireLogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Encrypt RndB with the selected key and transfer it back to the PCD */ Encrypt2K3DESBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, DesfireCommandState.RndB, @@ -635,15 +632,13 @@ uint16_t EV0CmdChangeKey(uint8_t *Buffer, uint16_t ByteCount) { /* Figure out the key size, and the crypto type from it: */ uint8_t keySize = ByteCount - 2; - uint8_t cryptoCommsTypeFromKey, cryptoType; + uint8_t cryptoType; if ((keySize != CRYPTO_3KTDEA_KEY_SIZE) && (keySize != CRYPTO_AES_KEY_SIZE)) { Buffer[0] = STATUS_NO_SUCH_KEY; return DESFIRE_STATUS_RESPONSE_SIZE; } else if (keySize == CRYPTO_3KTDEA_KEY_SIZE) { - cryptoCommsTypeFromKey = DESFIRE_COMMS_CIPHERTEXT_DES; cryptoType = CRYPTO_TYPE_3K3DES; } else { - cryptoCommsTypeFromKey = DESFIRE_COMMS_CIPHERTEXT_AES128; cryptoType = CRYPTO_TYPE_AES128; } uint8_t nextKeyVersion = ReadKeyVersion(SelectedApp.Slot, KeyId) + 1; @@ -844,7 +839,6 @@ uint16_t EV0CmdDeleteApplication(uint8_t *Buffer, uint16_t ByteCount) { return DESFIRE_STATUS_RESPONSE_SIZE; } PiccKeySettings = GetPiccKeySettings(); - const char *logMsg = PSTR("PICC key settings -- %02x"); /* Check the PICC key settings whether it is OK to delete using app master key */ if ((PiccKeySettings & DESFIRE_FREE_CREATE_DELETE) == 0x00) { Status = STATUS_AUTHENTICATION_ERROR; @@ -860,8 +854,9 @@ uint16_t EV0CmdDeleteApplication(uint8_t *Buffer, uint16_t ByteCount) { uint16_t EV0CmdSelectApplication(uint8_t *Buffer, uint16_t ByteCount) { InvalidateAuthState(0x00); - // handle a special case with EV1: - // https://stackoverflow.com/questions/38232695/m4m-mifare-desfire-ev1-which-mifare-aid-needs-to-be-added-to-nfc-routing-table + /* Handle a special case with EV1: + * See https://stackoverflow.com/questions/38232695/m4m-mifare-desfire-ev1-which-mifare-aid-needs-to-be-added-to-nfc-routing-table + */ if (ByteCount == 8) { const uint8_t DesfireEV1SelectPICCAid[] = { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x00 }; if (!memcmp(&Buffer[1], DesfireEV1SelectPICCAid, sizeof(DesfireEV1SelectPICCAid))) { @@ -1148,7 +1143,7 @@ uint16_t EV0CmdGetFileSettings(uint8_t *Buffer, uint16_t ByteCount) { appendedFileDataSize = 1 + 1 + 2 + 3 + 3 + 3; } else { Buffer[0] = STATUS_PICC_INTEGRITY_ERROR; - return ; + return DESFIRE_STATUS_RESPONSE_SIZE; } Buffer[0] = STATUS_OPERATION_OK; return DESFIRE_STATUS_RESPONSE_SIZE + appendedFileDataSize; @@ -1299,9 +1294,7 @@ uint16_t EV0CmdWriteData(uint8_t *Buffer, uint16_t ByteCount) { uint16_t EV0CmdGetValue(uint8_t *Buffer, uint16_t ByteCount) { uint8_t Status; uint8_t FileNum; - uint8_t CommSettings; uint16_t AccessRights; - TransferStatus XferStatus; /* Validate command length */ if (ByteCount != 1 + 1) { Status = STATUS_LENGTH_ERROR; @@ -1314,14 +1307,12 @@ uint16_t EV0CmdGetValue(uint8_t *Buffer, uint16_t ByteCount) { return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); } AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); - CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); /* Verify authentication: read or read&write required */ switch (ValidateAuthentication(AccessRights, VALIDATE_ACCESS_READWRITE | VALIDATE_ACCESS_READ)) { case VALIDATED_ACCESS_DENIED: Status = STATUS_AUTHENTICATION_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); case VALIDATED_ACCESS_GRANTED_PLAINTEXT: - CommSettings = DESFIRE_COMMS_PLAINTEXT; case VALIDATED_ACCESS_GRANTED: break; } @@ -1358,14 +1349,13 @@ uint16_t EV0CmdCredit(uint8_t *Buffer, uint16_t ByteCount) { return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); } uint16_t AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); - uint8_t CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); + //uint8_t CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); /* Verify authentication: read or read&write required */ switch (ValidateAuthentication(AccessRights, VALIDATE_ACCESS_READWRITE)) { case VALIDATED_ACCESS_DENIED: Status = STATUS_AUTHENTICATION_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); case VALIDATED_ACCESS_GRANTED_PLAINTEXT: - CommSettings = DESFIRE_COMMS_PLAINTEXT; case VALIDATED_ACCESS_GRANTED: break; } @@ -1410,7 +1400,6 @@ uint16_t EV0CmdDebit(uint8_t *Buffer, uint16_t ByteCount) { return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); } uint16_t AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); - uint8_t CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); /* Verify authentication: read or read&write required */ switch (ValidateAuthentication(AccessRights, VALIDATE_ACCESS_READWRITE | VALIDATE_ACCESS_READ | VALIDATE_ACCESS_WRITE)) { @@ -1418,7 +1407,6 @@ uint16_t EV0CmdDebit(uint8_t *Buffer, uint16_t ByteCount) { Status = STATUS_AUTHENTICATION_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); case VALIDATED_ACCESS_GRANTED_PLAINTEXT: - CommSettings = DESFIRE_COMMS_PLAINTEXT; case VALIDATED_ACCESS_GRANTED: break; } @@ -1463,8 +1451,8 @@ uint16_t EV0CmdLimitedCredit(uint8_t *Buffer, uint16_t ByteCount) { Status = STATUS_PARAMETER_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); } - uint16_t AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); - uint8_t CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); + //uint16_t AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); + //uint8_t CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); /* Validate the file type */ uint8_t fileType = ReadFileType(SelectedApp.Slot, fileIndex); if (fileType != DESFIRE_FILE_VALUE_DATA) { @@ -1547,6 +1535,7 @@ uint16_t EV0CmdReadRecords(uint8_t *Buffer, uint16_t ByteCount) { uint16_t EV0CmdWriteRecord(uint8_t *Buffer, uint16_t ByteCount) { uint8_t Status; + uint16_t AccessRights; if (ByteCount < 1 + 1 + 3 + 3) { Status = STATUS_LENGTH_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); @@ -1559,15 +1548,13 @@ uint16_t EV0CmdWriteRecord(uint8_t *Buffer, uint16_t ByteCount) { } __uint24 Offset = GET_LE24(&Buffer[2]); __uint24 Length = GET_LE24(&Buffer[5]); - uint16_t AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); - uint8_t CommSettings = ReadFileCommSettings(SelectedApp.Slot, fileIndex); + AccessRights = ReadFileAccessRights(SelectedApp.Slot, fileIndex); /* Verify authentication: read or read&write required */ switch (ValidateAuthentication(AccessRights, VALIDATE_ACCESS_READWRITE | VALIDATE_ACCESS_WRITE)) { case VALIDATED_ACCESS_DENIED: Status = STATUS_AUTHENTICATION_ERROR; return ExitWithStatus(Buffer, Status, DESFIRE_STATUS_RESPONSE_SIZE); case VALIDATED_ACCESS_GRANTED_PLAINTEXT: - CommSettings = DESFIRE_COMMS_PLAINTEXT; case VALIDATED_ACCESS_GRANTED: break; } @@ -1766,10 +1753,10 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { memcpy(&Key[CRYPTO_DES_BLOCK_SIZE], &Key[0], CRYPTO_DES_BLOCK_SIZE); memcpy(&Key[2 * CRYPTO_DES_BLOCK_SIZE], &Key[0], CRYPTO_DES_BLOCK_SIZE); } - LogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); + DesfireLogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); /* Generate the nonce B (RndB / Challenge response) */ - if (LocalTestingMode == 0) { + if (DesfireDebuggingOn) { RandomGetBuffer(DesfireCommandState.RndB, CryptoChallengeResponseBytesSize); } else { /* Fixed nonce for testing */ @@ -1790,7 +1777,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) { DesfireCommandState.RndB[14] = 0x22; DesfireCommandState.RndB[15] = 0x33; } - LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CryptoChallengeResponseBytesSize); + DesfireLogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CryptoChallengeResponseBytesSize); /* Encrypt RndB with the selected key and transfer it back to the PCD */ if (cryptoKeyType == CRYPTO_TYPE_DES || cryptoKeyType == CRYPTO_TYPE_3K3DES || cryptoKeyType == CRYPTO_TYPE_ANY) { @@ -1830,7 +1817,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { DesfireState = DESFIRE_IDLE; /* Validate command length */ if (ByteCount != 2 * CryptoChallengeResponseBytesSize + 1) { - LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); + DesfireLogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ByteCount); Buffer[0] = STATUS_LENGTH_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } @@ -1864,8 +1851,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { /* Check that the returned RndB matches what we sent in the previous round */ if (memcmp(DesfireCommandState.RndB, challengeRndB, CryptoChallengeResponseBytesSize)) { - LogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, (const void *) challengeRndB, - CryptoChallengeResponseBytesSize); + DesfireLogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, (const void *) challengeRndB, CryptoChallengeResponseBytesSize); Buffer[0] = STATUS_AUTHENTICATION_ERROR; return DESFIRE_STATUS_RESPONSE_SIZE; } @@ -1900,9 +1886,10 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) { uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { - BYTE KeyId, Status; + BYTE KeyId; BYTE keySize; BYTE *Key, *IVBuffer; + BYTE Status; /* Validate command length */ if (ByteCount != 2) { @@ -1952,12 +1939,12 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { /* Fetch the key */ ReadAppKey(SelectedApp.Slot, KeyId, Key, keySize); - LogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); + DesfireLogEntry(LOG_APP_AUTH_KEY, (const void *) Key, keySize); CryptoAESGetConfigDefaults(&AESCryptoContext); CryptoAESInitContext(&AESCryptoContext); /* Generate the nonce B (RndB / Challenge response) */ - if (LocalTestingMode == 0) { + if (DesfireDebuggingOn) { RandomGetBuffer(&(DesfireCommandState.RndB[0]), CRYPTO_CHALLENGE_RESPONSE_BYTES); } else { /* Fixed nonce for testing */ @@ -1978,7 +1965,7 @@ uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount) { DesfireCommandState.RndB[14] = 0x22; DesfireCommandState.RndB[15] = 0x33; } - LogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); + DesfireLogEntry(LOG_APP_NONCE_B, DesfireCommandState.RndB, CRYPTO_CHALLENGE_RESPONSE_BYTES); /* Encrypt RndB with the selected key and transfer it back to the PCD */ Status = CryptoAESEncryptBuffer(CRYPTO_CHALLENGE_RESPONSE_BYTES, DesfireCommandState.RndB, @@ -2137,7 +2124,7 @@ uint16_t ISO7816CmdGetChallenge(uint8_t *Buffer, uint16_t ByteCount) { } const uint8_t challengeRespDefaultBytes = 8; RandomGetBuffer(&Buffer[2], challengeRespDefaultBytes); - // TODO: Should store this value somewhere for the next commands / auth routines ... + /* TODO: Should store this value somewhere for the next commands / auth routines ... */ Buffer[0] = ISO7816_CMD_NO_ERROR; Buffer[1] = ISO7816_CMD_NO_ERROR; return ISO7816_STATUS_RESPONSE_SIZE + challengeRespDefaultBytes; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h index 4dfe556c..228114cf 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireInstructions.h @@ -116,20 +116,22 @@ typedef struct { /* Helper and batch process functions */ uint16_t CallInstructionHandler(uint8_t *Buffer, uint16_t ByteCount); -/* - * The following section implements: - * DESFire EV0 / D40 specific commands - */ - +/* DESFire EV0 / D40 specific commands: */ uint16_t EV0CmdGetVersion1(uint8_t *Buffer, uint16_t ByteCount); uint16_t EV0CmdGetVersion2(uint8_t *Buffer, uint16_t ByteCount); uint16_t EV0CmdGetVersion3(uint8_t *Buffer, uint16_t ByteCount); uint16_t EV0CmdAuthenticateLegacy1(uint8_t *Buffer, uint16_t ByteCount); uint16_t EV0CmdAuthenticateLegacy2(uint8_t *Buffer, uint16_t ByteCount); +/* Other authenticate commands: */ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount); uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount); uint16_t DesfireCmdAuthenticateAES1(uint8_t *Buffer, uint16_t ByteCount); uint16_t DesfireCmdAuthenticateAES2(uint8_t *Buffer, uint16_t ByteCount); +/* ISO7816 authenticate commands: */ +uint16_t ISO7816CmdGetChallenge(uint8_t *Buffer, uint16_t ByteCount); +uint16_t ISO7816CmdExternalAuthenticate(uint8_t *Buffer, uint16_t ByteCount); +uint16_t ISO7816CmdInternalAuthenticate(uint8_t *Buffer, uint16_t ByteCount); + #endif diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c index 1285797e..f84426ab 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.c @@ -31,19 +31,7 @@ This notice must be retained at the top of all source files where indicated. #include "DESFireISO14443Support.h" #include "DESFireLogging.h" -#ifdef DESFIRE_DEFAULT_DEBUGGING_MODE -DESFireLoggingMode LocalLoggingMode = DESFIRE_DEFAULT_LOGGING_MODE; -#else -DESFireLoggingMode LocalLoggingMode = DEBUGGING; -#endif - -#ifdef DESFIRE_DEFAULT_TESTING_MODE -BYTE LocalTestingMode = DESFIRE_DEFAULT_TESTING_MODE; -#else -BYTE LocalTestingMode = 0x00; -#endif - -#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 +#ifdef DESFIRE_DEBUGGING void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize) { if (BufSize >= DESFIRE_MIN_OUTGOING_LOGSIZE) { LogEntry(LogCode, (void *) LogDataBuffer, BufSize); @@ -53,12 +41,12 @@ void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize) {} #endif -#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 +#ifdef DESFIRE_DEBUGGING void DesfireLogISOStateChange(int state, int logCode) { const char *statePrintName; int logLength = 0; do { - switch (logCode) { + switch (state) { case ISO14443_4_STATE_EXPECT_RATS: statePrintName = PSTR("ISO14443_4_STATE_EXPECT_RATS"); break; @@ -71,11 +59,17 @@ void DesfireLogISOStateChange(int state, int logCode) { case ISO14443_3A_STATE_IDLE: statePrintName = PSTR("ISO14443_3A_STATE_IDLE"); break; - case ISO14443_3A_STATE_READY1: - statePrintName = PSTR("ISO14443_3A_STATE_READY1"); + case ISO14443_3A_STATE_READY_CL1: + statePrintName = PSTR("ISO14443_3A_STATE_READY_CL1"); + break; + case ISO14443_3A_STATE_READY_CL1_NVB_END: + statePrintName = PSTR("ISO14443_3A_STATE_READY_CL1_NVB_END"); + break; + case ISO14443_3A_STATE_READY_CL2: + statePrintName = PSTR("ISO14443_3A_STATE_READY_CL2"); break; - case ISO14443_3A_STATE_READY2: - statePrintName = PSTR("ISO14443_3A_STATE_READY2"); + case ISO14443_3A_STATE_READY_CL2_NVB_END: + statePrintName = PSTR("ISO14443_3A_STATE_READY_CL2_NVB_END"); break; case ISO14443_3A_STATE_ACTIVE: statePrintName = PSTR("ISO14443_3A_STATE_ACTIVE"); @@ -88,12 +82,11 @@ void DesfireLogISOStateChange(int state, int logCode) { break; } } while (0); - snprintf_P(STRING_BUFFER_SIZE, (char *) __InternalStringBuffer, - PSTR("State CHG -- %s"), statePrintName); + snprintf_P((char *) __InternalStringBuffer, STRING_BUFFER_SIZE, PSTR("")); + strcat_P((char *) __InternalStringBuffer, statePrintName); logLength = StringLength((char *) __InternalStringBuffer, STRING_BUFFER_SIZE); - DesfireLogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, - (char *) __InternalStringBuffer, logLength); + DesfireLogEntry(logCode, (char *) __InternalStringBuffer, logLength); } #else void DesfireLogISOStateChange(int state, int logCode) {} diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h index 87c94192..fc45993a 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireLogging.h @@ -39,40 +39,18 @@ This notice must be retained at the top of all source files where indicated. #define DESFIRE_MIN_OUTGOING_LOGSIZE (1) #endif -typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { - OFF = 0, - NORMAL = 1, - VERBOSE = 2, - DEBUGGING = 3, -} DESFireLoggingMode; - -#ifndef DESFIRE_DEFAULT_LOGGING_MODE -#define DESFIRE_DEFAULT_LOGGING_MODE (OFF) -#endif - -extern DESFireLoggingMode LocalLoggingMode; - -/* - * This variable can be toggled to indicated whether to employ - * testable pseudo-randomness in the encrypted transfers. - * When this value id non-zero, then any random session numbers - * (e.g., RndB) and IV salt vectors should default back to - * predictable constant values for testing purposes. - */ -extern BYTE LocalTestingMode; - void DesfireLogEntry(LogEntryEnum LogCode, void *LogDataBuffer, uint16_t BufSize); void DesfireLogISOStateChange(int state, int logCode); -#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 +#ifdef DESFIRE_DEBUGGING #define DEBUG_PRINT_P(fmtStr, ...) ({ \ uint8_t logLength = 0; \ do { \ snprintf_P((char *) __InternalStringBuffer, STRING_BUFFER_SIZE, \ - fmtStr, ##__VA_ARGS__); \ + (const char *) fmtStr, ##__VA_ARGS__); \ logLength = StringLength((char *) __InternalStringBuffer, \ STRING_BUFFER_SIZE); \ - DesfireLogEntry(LOG_ERR_DESFIRE_GENERIC_ERROR, \ + DesfireLogEntry(LOG_INFO_DESFIRE_DEBUGGING_OUTPUT, \ (char *) __InternalStringBuffer, logLength); \ } while(0); \ }) @@ -80,19 +58,11 @@ void DesfireLogISOStateChange(int state, int logCode); #define DEBUG_PRINT_P(fmtStr, ...) ({}) #endif -#ifdef DESFIRE_DEBUGGING && DESFIRE_DEBUGGING != 0 -#define RUN_ON_DESFIRE_DEBUG(cppStmtToRun) ({ \ - cppStmtToRun; \ - }) -#else -#define RUN_ON_DESFIRE_DEBUG(cppStmtToRun) ({}) -#endif - #define GetSourceFileLoggingData() ({ \ char *strBuffer; \ do { \ snprintf_P(__InternalStringBuffer, STRING_BUFFER_SIZE, \ - PSTR(" @@ LINE #%d in *%s @@"), \ + PSTR("@@ LINE #%d in \"%s\" @@"), \ __LINE__, __FILE__); \ __InternalStringBuffer[STRING_BUFFER_SIZE - 1] = '\0'; \ } while(0); \ @@ -103,10 +73,10 @@ void DesfireLogISOStateChange(int state, int logCode); #define GetSymbolNameString(symbolName) ({ \ char *strBuffer; \ do { \ - strncpy_P(__InternalStringBuffer2, PSTR(#symbolName), \ - DATA_BUFFER_SIZE_SMALL); \ + strncpy_P(__InternalStringBuffer, PSTR(#symbolName), \ + STRING_BUFFER_SIZE); \ } while(0); \ - strBuffer = __InternalStringBuffer2; \ + strBuffer = __InternalStringBuffer; \ strBuffer; \ }) diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c index ddb0c8da..22d29e61 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.c @@ -37,7 +37,6 @@ This notice must be retained at the top of all source files where indicated. #define BLOCKWISE_IO_MULTIPLIER (DESFIRE_BLOCK_SIZE) volatile char __InternalStringBuffer[STRING_BUFFER_SIZE] = { 0 }; -char __InternalStringBuffer2[DATA_BUFFER_SIZE_SMALL] = { 0 }; void ReadBlockBytes(void *Buffer, SIZET StartBlock, SIZET Count) { if (StartBlock * BLOCKWISE_IO_MULTIPLIER >= MEMORY_SIZE_PER_SETTING) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h index f4231604..714ee150 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireMemoryOperations.h @@ -33,10 +33,8 @@ This notice must be retained at the top of all source files where indicated. /* Reserve some space on the stack (text / data segment) for intermediate storage of strings and data we need to write so we do not have to rely on a bothersome heap-based scheme for passing pointers to functions: */ -#define DATA_BUFFER_SIZE_SMALL (16) -#define STRING_BUFFER_SIZE (32) +#define STRING_BUFFER_SIZE (48) extern volatile char __InternalStringBuffer[STRING_BUFFER_SIZE]; -extern char __InternalStringBuffer2[DATA_BUFFER_SIZE_SMALL]; /* * EEPROM and FRAM memory management routines: diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c index cf04ccf6..ab2b896c 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c @@ -213,7 +213,7 @@ void InitialisePiccBackendEV0(uint8_t StorageSize, bool formatPICC) { ReadBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); if (formatPICC) { DEBUG_PRINT_P(PSTR("Factory reset -- EV0")); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0)); + DesfireLogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0); FactoryFormatPiccEV0(); } else { ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); @@ -232,7 +232,7 @@ void InitialisePiccBackendEV1(uint8_t StorageSize, bool formatPICC) { ReadBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); if (formatPICC) { DEBUG_PRINT_P(PSTR("Factory reset -- EV1")); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0)); + DesfireLogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0); FactoryFormatPiccEV1(StorageSize); } else { ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); @@ -251,7 +251,7 @@ void InitialisePiccBackendEV2(uint8_t StorageSize, bool formatPICC) { ReadBlockBytes(&Picc, DESFIRE_PICC_INFO_BLOCK_ID, sizeof(DESFirePICCInfoType)); if (formatPICC) { DEBUG_PRINT_P(PSTR("Factory reset -- EV1")); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0)); + DesfireLogEntry(LOG_INFO_DESFIRE_PICC_RESET, (void *) NULL, 0); FactoryFormatPiccEV2(StorageSize); } else { ReadBlockBytes(&AppDir, DESFIRE_APP_DIR_BLOCK_ID, sizeof(DESFireAppDirType)); @@ -278,7 +278,9 @@ void GetPiccHardwareVersionInfo(uint8_t *Buffer) { void GetPiccSoftwareVersionInfo(uint8_t *Buffer) { Buffer[0] = Picc.SwVersionMajor; Buffer[1] = Picc.SwVersionMinor; - Buffer[2] = Picc.StorageSize; + uint16_t cardCapacityBlocks = GetCardCapacityBlocks(); + uint8_t freeMemoryBytes = (uint8_t)(cardCapacityBlocks * DESFIRE_BLOCK_SIZE); + Buffer[2] = freeMemoryBytes; } void GetPiccManufactureInfo(uint8_t *Buffer) { @@ -302,9 +304,9 @@ void FormatPicc(void) { memset(&AppDir, 0x00, sizeof(DESFireAppDirType)); memset(&SelectedApp, 0x00, sizeof(SelectedAppCacheType)); /* Set a random new UID */ - BYTE uidData[DESFIRE_UID_SIZE]; - RandomGetBuffer(uidData, DESFIRE_UID_SIZE); - memcpy(&Picc.Uid[0], uidData, DESFIRE_UID_SIZE); + BYTE uidData[DESFIRE_UID_SIZE - 1]; + RandomGetBuffer(uidData, DESFIRE_UID_SIZE - 1); + memcpy(&Picc.Uid[1], uidData, DESFIRE_UID_SIZE - 1); /* Conform to NXP Application Note AN10927 about the first * byte of a randomly generated UID (refer to section 2.1.1). */ @@ -314,8 +316,8 @@ void FormatPicc(void) { RandomGetBuffer(batchNumberData, 5); memcpy(&Picc.BatchNumber[0], batchNumberData, 5); /* Default production date -- until the user changes them: */ - Picc.ProductionWeek = 0x00; - Picc.ProductionYear = 0x00; + Picc.ProductionWeek = 0x01; + Picc.ProductionYear = 0x01; /* Assign the default manufacturer ID: */ Picc.ManufacturerID = DESFIRE_MANUFACTURER_ID; /* Set the ATS bytes to defaults: */ @@ -338,13 +340,13 @@ void CreatePiccApp(void) { BYTE MasterAppAID[] = { 0x00, 0x00, 0x00 }; BYTE statusCode = CreateApp(MasterAppAID, DESFIRE_MAX_KEYS, 0x0f); if (statusCode != STATUS_OPERATION_OK) { - const char *loggingMsg = PSTR("CreateApp returned -- %d\n"); - DEBUG_PRINT_P(loggingMsg, statusCode); + DEBUG_PRINT_P(PSTR("CreateApp returned -- %d\n"), statusCode); } SelectPiccApp(); memset(&Key, 0x00, sizeof(CryptoKeyBufferType)); WriteAppKey(0x00, 0x00, Key, sizeof(CryptoKeyBufferType)); SynchronizeAppDir(); + SynchronizePICCInfo(); } void FactoryFormatPiccEV0(void) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h index c3866e20..c5168fab 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCHeaderLayout.h @@ -115,7 +115,7 @@ extern uint16_t DesfireATQAValue; #define PICC_FORMAT_BYTE 0x00 #define PICC_EMPTY_BYTE 0x00 -typedef struct { +typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT { /* Static data: does not change during the PICC's lifetime. * We will add Chameleon Mini terminal commands to enable * resetting this data so tags can be emulated authentically. @@ -136,9 +136,9 @@ typedef struct { /* Dynamic data: changes during the PICC's lifetime */ uint16_t FirstFreeBlock; uint8_t TransactionStarted; -} DESFirePICCInfoType DESFIRE_FIRMWARE_PACKING; +} DESFirePICCInfoType; -typedef struct { +typedef struct DESFIRE_FIRMWARE_PACKING DESFIRE_FIRMWARE_ALIGNAT { BYTE Slot; BYTE KeyCount; BYTE MaxKeyCount; @@ -152,7 +152,7 @@ typedef struct { SIZET KeyVersionsArray; /* Block offset in FRAM */ SIZET KeyTypesArray; /* Block offset in FRAM */ SIZET KeyAddress; /* Block offset in FRAM */ -} SelectedAppCacheType DESFIRE_FIRMWARE_PACKING; +} SelectedAppCacheType; extern BYTE SELECTED_APP_CACHE_TYPE_BLOCK_SIZE; extern BYTE APP_CACHE_KEY_SETTINGS_ARRAY_BLOCK_SIZE; diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c index abce8a30..172870db 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.c @@ -74,10 +74,10 @@ int32_t Int32FromByteBuffer(uint8_t *byteBuffer) { if (byteBuffer == NULL) { return 0; } - int32_t b0 = byteBuffer[0]; - int32_t b1 = (byteBuffer[1] << 8) & 0x0000ff00; - int32_t b2 = (byteBuffer[2] << 16) & 0x00ff0000; - int32_t b3 = (byteBuffer[3] << 24) & 0xff000000; + int32_t b0 = (int32_t) byteBuffer[0]; + int32_t b1 = ((int32_t) byteBuffer[1] << 8) & 0x0000ff00; + int32_t b2 = ((int32_t) byteBuffer[2] << 16) & 0x00ff0000; + int32_t b3 = ((int32_t) byteBuffer[3] << 24) & 0xff000000; return b0 | b1 | b2 | b3; } @@ -94,8 +94,7 @@ uint16_t DesfireAddParityBits(uint8_t *Buffer, uint16_t BitCount) { if (BitCount % 8) return BitCount; uint8_t *currByte, * tmpByte; - uint8_t *const lastByte = Buffer + BitCount / 8 + BitCount / 64; // starting address + number of bytes + - // number of parity bytes + uint8_t *const lastByte = Buffer + BitCount / 8 + BitCount / 64; // starting address + number of bytes + number of parity bytes currByte = Buffer + BitCount / 8 - 1; uint8_t parity; memset(currByte + 1, 0, lastByte - currByte); // zeroize all bytes used for parity bits @@ -116,7 +115,7 @@ uint16_t DesfireAddParityBits(uint8_t *Buffer, uint16_t BitCount) { } uint16_t DesfireRemoveParityBits(uint8_t *Buffer, uint16_t BitCount) { - // Short frame, no parity bit is added + /* Short frame, no parity bit is added: */ if (BitCount == 7) return 7; @@ -148,8 +147,8 @@ bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount) { } uint16_t DesfirePreprocessAPDUWrapper(uint8_t CommMode, uint8_t *Buffer, uint16_t BufferSize, bool TruncateChecksumBytes) { + uint16_t ChecksumBytes = 0; switch (CommMode) { - uint16_t ChecksumBytes = 0; case DESFIRE_COMMS_PLAINTEXT_MAC: { if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { ChecksumBytes = 4; @@ -205,7 +204,7 @@ uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buff if (DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_DES || DesfireCommandState.CryptoMethodType == CRYPTO_TYPE_2KTDEA) { return appendBufferMAC(SessionKey, Buffer, BufferSize); } else { - // AES-128 or 3DES: + /* AES-128 or 3DES: */ uint16_t MacedBytes = appendBufferCMAC(DesfireCommandState.CryptoMethodType, SessionKey, Buffer, BufferSize, SessionIV); memcpy(SessionIV, &Buffer[BufferSize], MacedBytes - BufferSize); return MacedBytes; @@ -213,7 +212,7 @@ uint16_t DesfirePostprocessAPDU(uint8_t CommMode, uint8_t *Buffer, uint16_t Buff break; } case DESFIRE_COMMS_CIPHERTEXT_DES: { - // TripleDES: + /* TripleDES: */ uint16_t CryptoBlockSize = CRYPTO_3KTDEA_BLOCK_SIZE; uint16_t BlockPadding = 0; if ((BufferSize % CryptoBlockSize) != 0) { diff --git a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h index 25cc6f0e..d4dd0e86 100644 --- a/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h +++ b/Firmware/Chameleon-Mini/Application/DESFire/DESFireUtils.h @@ -60,6 +60,12 @@ uint16_t DesfireAddParityBits(uint8_t *Buffer, uint16_t bits); uint16_t DesfireRemoveParityBits(uint8_t *Buffer, uint16_t BitCount); bool DesfireCheckParityBits(uint8_t *Buffer, uint16_t BitCount); +#ifdef DESFIRE_DEBUGGING +#define DesfireDebuggingOn (DESFIRE_DEBUGGING != 0) +#else +#define DesfireDebuggingOn (false) +#endif + /* Add utility wrapper functions to perform pre and postprocessing on * the raw input APDU commands sent by the PCD depending on which * CommMode (PLAINTEXT|PLAINTEXT-MAC|ENCIPHERED-CMAC-3DES|ECIPHERED-CMAC-AES128) diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c index 067a04f6..32e71215 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.c +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.c @@ -14,20 +14,18 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, ui uint8_t *DataPtr = (uint8_t *) Buffer; uint8_t NVB = DataPtr[1]; switch (NVB) { - case ISO14443A_NVB_AC_START: /* Start of anticollision procedure. - * Send whole UID CLn + BCC */ - DataPtr[0] = UidCL[0]; - DataPtr[1] = UidCL[1]; - DataPtr[2] = UidCL[2]; - DataPtr[3] = UidCL[3]; + * Send whole UID CLn + BCC + */ + memcpy(&DataPtr[0], &UidCL[0], 4); DataPtr[ISO14443A_CL_BCC_OFFSET] = ISO14443A_CALC_BCC(DataPtr); *BitCount = ISO14443A_CL_FRAME_SIZE; return false; case ISO14443A_NVB_AC_END: /* End of anticollision procedure. - * Send SAK CLn if we are selected. */ + * Send SAK CLn if we are selected. + */ if (!memcmp(&DataPtr[2], &UidCL[0], 4)) { DataPtr[0] = SAKValue; ISO14443AAppendCRCA(Buffer, 1); @@ -38,11 +36,28 @@ bool ISO14443ASelectDesfire(void *Buffer, uint16_t *BitCount, uint8_t *UidCL, ui *BitCount = 0; return false; } - default: - /* No anticollision supported */ - *BitCount = 0; - return false; + default: { + uint8_t CollisionByteCount = ((NVB >> 4) & 0x0f) - 2; + uint8_t CollisionBitCount = (NVB >> 0) & 0x0f; + uint8_t mask = 0xFF >> (8 - CollisionBitCount); + // Since the UidCL does not contain the BCC, we have to distinguish here + if ( + ((CollisionByteCount == 5 || (CollisionByteCount == 4 && CollisionBitCount > 0)) && memcmp(UidCL, &DataPtr[2], 4) == 0 && (ISO14443A_CALC_BCC(UidCL) & mask) == (DataPtr[6] & mask)) + || + (CollisionByteCount == 4 && CollisionBitCount == 0 && memcmp(UidCL, &DataPtr[2], 4) == 0) + || + (CollisionByteCount < 4 && memcmp(UidCL, &DataPtr[2], CollisionByteCount) == 0 && (UidCL[CollisionByteCount] & mask) == (DataPtr[CollisionByteCount + 2] & mask)) + ) { + memcpy(&DataPtr[0], &UidCL[0], 4); + DataPtr[ISO14443A_CL_BCC_OFFSET] = ISO14443A_CALC_BCC(DataPtr); + *BitCount = ISO14443A_CL_FRAME_SIZE; + return false; + } + } } + /* No anticollision supported */ + *BitCount = 0; + return false; } #endif /* CONFIG_MF_DESFIRE_SUPPORT */ diff --git a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h index 3faee877..d127b60b 100644 --- a/Firmware/Chameleon-Mini/Application/ISO14443-3A.h +++ b/Firmware/Chameleon-Mini/Application/ISO14443-3A.h @@ -11,7 +11,7 @@ #include "../Common.h" #include -#define ISO14443A_UID_SIZE_SINGLE 4 /* bytes */ +#define ISO14443A_UID_SIZE_SINGLE 4 #define ISO14443A_UID_SIZE_DOUBLE 7 #define ISO14443A_UID_SIZE_TRIPLE 10 @@ -28,8 +28,8 @@ #define ISO14443A_CL_UID_OFFSET 0 #define ISO14443A_CL_UID_SIZE 4 #define ISO14443A_CL_BCC_OFFSET 4 -#define ISO14443A_CL_BCC_SIZE 1 /* Byte */ -#define ISO14443A_CL_FRAME_SIZE ((ISO14443A_CL_UID_SIZE + ISO14443A_CL_BCC_SIZE) * 8) /* UID[N...N+3] || BCCN */ +#define ISO14443A_CL_BCC_SIZE 1 +#define ISO14443A_CL_FRAME_SIZE ((ISO14443A_CL_UID_SIZE + ISO14443A_CL_BCC_SIZE) * BITS_PER_BYTE) /* UID[N...N+3] || BCCN */ #define ISO14443A_SAK_INCOMPLETE 0x24 #define ISO14443A_SAK_INCOMPLETE_NOT_COMPLIANT 0x04 #define ISO14443A_SAK_COMPLETE_COMPLIANT 0x20 diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.c b/Firmware/Chameleon-Mini/Application/MifareDESFire.c index 9941797a..6f5d8f74 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.c +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.c @@ -43,11 +43,6 @@ This notice must be retained at the top of all source files where indicated. #include "DESFire/DESFireLogging.h" #include "DESFire/DESFireUtils.h" -#define IsControlCmd(Buffer, BitCount) \ - (BitCount > 0 && \ - ((Buffer[0] == ISO14443A_CMD_WUPA) || \ - (Buffer[0] == ISO14443A_CMD_REQA))) - DesfireStateType DesfireState = DESFIRE_HALT; DesfireStateType DesfirePreviousState = DESFIRE_IDLE; @@ -56,9 +51,18 @@ Iso7816WrappedCommandType_t Iso7816CmdType; bool DesfireFromHalt = false; BYTE DesfireCmdCLA = DESFIRE_NATIVE_CLA; +uint16_t ISO14443AStoreLastDataFrameAndReturn(const uint8_t *Buffer, uint16_t BufferBitCount) { + if (BufferBitCount > 0) { + uint16_t ISO14443ALastDataFrameBytes = MIN(ASBYTES(BufferBitCount), MAX_DATA_FRAME_XFER_SIZE); + memcpy(&ISO14443ALastDataFrame[0], &Buffer[0], ISO14443ALastDataFrameBytes); + ISO14443ALastDataFrameBits = BufferBitCount; + } + return BufferBitCount; +} + static void MifareDesfireAppInitLocal(uint8_t StorageSize, uint8_t Version, bool FormatPICC) { ResetLocalStructureData(); - DesfireState = DESFIRE_IDLE; + DesfireState = DESFIRE_HALT; DesfireFromHalt = false; switch (Version) { case MIFARE_DESFIRE_EV2: @@ -108,12 +112,14 @@ void MifareDesfire4kEV2AppInitRunOnce(void) { } void MifareDesfireAppReset(void) { - /* This is called repeatedly -- limit the amount of work done */ - MifareDesfireReset(); + /* EMPTY: This is called repeatedly -- limit the amount of work done */ } void MifareDesfireAppTick(void) { - /* EMPTY -- Do nothing. */ + if (!CheckStateRetryCount(false)) { + ResetISOState(); + MifareDesfireReset(); + } } void MifareDesfireAppTask(void) { @@ -122,22 +128,18 @@ void MifareDesfireAppTask(void) { uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount)); if (ByteCount == 0) { return ISO14443A_APP_NO_RESPONSE; - } else if (MutualAuthenticateCmd(Buffer[0])) { - LastReaderSentCmd = Buffer[0]; } else if (Buffer[0] != STATUS_ADDITIONAL_FRAME) { DesfireState = DESFIRE_IDLE; - LastReaderSentCmd = Buffer[0]; - uint16_t ReturnBytes = CallInstructionHandler(Buffer, ByteCount); - return ReturnBytes; - } else { - LastReaderSentCmd = Buffer[0]; } + LastReaderSentCmd = Buffer[0]; uint16_t ReturnBytes = 0; switch (DesfireState) { + case DESFIRE_IDLE: + ReturnBytes = CallInstructionHandler(Buffer, ByteCount); + break; case DESFIRE_GET_VERSION2: ReturnBytes = EV0CmdGetVersion2(Buffer, ByteCount); break; @@ -157,16 +159,13 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { ReturnBytes = DesfireCmdAuthenticateAES2(Buffer, ByteCount); break; case DESFIRE_ISO7816_EXT_AUTH: - DEBUG_PRINT_P(PSTR("Not Implemented -- ISO7816-ExtAuth")); - ReturnBytes = ISO14443A_APP_NO_RESPONSE; + ReturnBytes = ISO7816CmdExternalAuthenticate(Buffer, ByteCount); break; case DESFIRE_ISO7816_INT_AUTH: - DEBUG_PRINT_P(PSTR("Not Implemented -- ISO7816-IntAuth")); - ReturnBytes = ISO14443A_APP_NO_RESPONSE; + ReturnBytes = ISO7816CmdInternalAuthenticate(Buffer, ByteCount); break; case DESFIRE_ISO7816_GET_CHALLENGE: - DEBUG_PRINT_P(PSTR("Not Implemented -- ISO7816-GetChal")); - ReturnBytes = ISO14443A_APP_NO_RESPONSE; + ReturnBytes = ISO7816CmdExternalAuthenticate(Buffer, ByteCount); break; case DESFIRE_READ_DATA_FILE: ReturnBytes = ReadDataFileIterator(Buffer); @@ -175,10 +174,9 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { ReturnBytes = WriteDataFileInternal(&Buffer[1], ByteCount - 1); break; default: - /* Should not happen. */ - DEBUG_PRINT_P(PSTR("ERROR -- Unexpected state!")); Buffer[0] = STATUS_PICC_INTEGRITY_ERROR; - return DESFIRE_STATUS_RESPONSE_SIZE; + ReturnBytes = DESFIRE_STATUS_RESPONSE_SIZE; + break; } return ReturnBytes; @@ -187,8 +185,6 @@ uint16_t MifareDesfireProcessCommand(uint8_t *Buffer, uint16_t ByteCount) { uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { DesfireCmdCLA = Buffer[0]; size_t ByteCount = ASBYTES(BitCount); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount)); - ResetISOState(); if (ByteCount == 0) { return ISO14443A_APP_NO_RESPONSE; } else if (ByteCount >= 2 && Buffer[1] == STATUS_ADDITIONAL_FRAME && DesfireCLA(Buffer[0])) { @@ -240,10 +236,10 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) { } uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { - uint16_t ReturnedBytes = 0; + uint16_t ReturnBytes = 0; uint16_t ByteCount = ASBYTES(BitCount); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_INCOMING_DATA, Buffer, ByteCount)); - if (ByteCount > 1 && !memcmp(&Buffer[0], &ISO14443ALastIncomingDataFrame[0], MIN(ASBYTES(ISO14443ALastIncomingDataFrameBits), ByteCount))) { + if (ByteCount >= 1 && BitCount == ISO14443ALastIncomingDataFrameBits && ISO14443ALastDataFrameBits > 0 && + !memcmp(&Buffer[0], &ISO14443ALastIncomingDataFrame[0], ByteCount)) { /* The PCD resent the same data frame (probably a synchronization issue): * Send out the same data as last time: */ @@ -270,7 +266,6 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { } memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } else if (ByteCount >= 5 && DesfireCLA(Buffer[0]) && Buffer[1] == STATUS_ADDITIONAL_FRAME && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 9 && @@ -295,7 +290,6 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { Buffer[ProcessedByteCount - 1] = 0x91; ++ProcessedByteCount; ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } else if (ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 && Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) { @@ -308,10 +302,11 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { return ISO14443A_APP_NO_RESPONSE; } ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); - } else if (ByteCount >= 8 && DesfireCLA(Buffer[1]) && - Buffer[3] == 0x00 && Buffer[4] == 0x00 && Buffer[5] == ByteCount - 8) { + } else if ((ByteCount >= 8 && DesfireCLA(Buffer[1]) && + Buffer[3] == 0x00 && Buffer[4] == 0x00 && Buffer[5] == ByteCount - 8) || + (ByteCount >= 9 && DesfireCLA(Buffer[1]) && + Buffer[3] == 0x00 && Buffer[4] == 0x00 && Buffer[5] == ByteCount - 9)) { uint16_t UnwrappedByteCount = DesfirePreprocessAPDUAndTruncate(ActiveCommMode, Buffer, ByteCount); if (UnwrappedByteCount == 0) { return ISO14443A_APP_NO_RESPONSE; @@ -328,7 +323,6 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { memmove(&Buffer[1], &Buffer[0], ProcessedByteCount); Buffer[0] = hf14AScanPrologue; ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); } Iso7816CmdType = IsWrappedISO7816CommandType(Buffer, ByteCount); @@ -378,34 +372,45 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) { } memcpy(&Buffer[0], &ISO7816PrologueBytes[0], 2); ProcessedByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ProcessedByteCount + 2); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ProcessedByteCount)); return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ProcessedByteCount)); - } else if ((ReturnedBytes = CallInstructionHandler(Buffer, ByteCount)) != ISO14443A_APP_NO_RESPONSE) { + } else if (ByteCount >= 5 && (Iso144433AState == ISO14443_3A_STATE_IDLE || Iso144433AState == ISO14443_3A_STATE_ACTIVE) && + Buffer[0] != ISO14443A_CMD_RATS && Buffer[0] != ISO14443A_CMD_REQA && + !ISO14443ACmdIsWUPA(Buffer[0]) && !ISO144433AIsHalt(Buffer, BitCount)) { + uint16_t IncomingByteCount = DesfirePreprocessAPDUAndTruncate(ActiveCommMode, Buffer, ByteCount); + if (IncomingByteCount > 2) { + IncomingByteCount -= 2; + ReturnBytes = CallInstructionHandler(&Buffer[2], IncomingByteCount); + if (ReturnBytes != ISO14443A_APP_NO_RESPONSE) { + uint16_t OutgoingByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ReturnBytes + 2); + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(OutgoingByteCount)); + } + } + } else if (BitCount >= BITS_PER_BYTE && (Iso144433AState == ISO14443_3A_STATE_IDLE || Iso144433AState == ISO14443_3A_STATE_ACTIVE) && + Buffer[0] != ISO14443A_CMD_RATS && Buffer[0] != ISO14443A_CMD_REQA && + !ISO14443ACmdIsWUPA(Buffer[0]) && !ISO144433AIsHalt(Buffer, BitCount)) { /* This case should handle non-wrappped native commands. No pre/postprocessing afterwards: */ - ResetISOState(); - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, ReturnedBytes)); - return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(ReturnedBytes)); - } else { - uint16_t PiccProcessRespBits = ISO144433APiccProcess(Buffer, BitCount); - uint16_t PiccProcessRespBytesCeil = ASBYTES(PiccProcessRespBits); - if (PiccProcessRespBits >= BITS_PER_BYTE) { - PiccProcessRespBits = ASBITS(PiccProcessRespBytesCeil); + ReturnBytes = CallInstructionHandler(Buffer, ByteCount); + if (ReturnBytes != ISO14443A_APP_NO_RESPONSE) { + uint16_t OutgoingByteCount = DesfirePostprocessAPDU(ActiveCommMode, Buffer, ReturnBytes); + return ISO14443AStoreLastDataFrameAndReturn(Buffer, ASBITS(OutgoingByteCount)); } - RUN_ON_DESFIRE_DEBUG(LogEntry(LOG_INFO_DESFIRE_OUTGOING_DATA, Buffer, PiccProcessRespBytesCeil)); - return ISO14443AStoreLastDataFrameAndReturn(Buffer, PiccProcessRespBits); } - return ISO14443A_APP_NO_RESPONSE; + /* Default / Fall through -- No other cases matched -- Send it through the ISO14443A PICC handler: */ + uint16_t PiccProcessRespBits = ISO144433APiccProcess(Buffer, BitCount); + uint16_t PiccProcessRespBytesCeil = ASBYTES(PiccProcessRespBits); + if (PiccProcessRespBits >= BITS_PER_BYTE) { + PiccProcessRespBits = ASBITS(PiccProcessRespBytesCeil); + } + return ISO14443AStoreLastDataFrameAndReturn(Buffer, PiccProcessRespBits); } void MifareDesfireReset(void) { - ResetISOState(); DesfireState = DESFIRE_IDLE; } void ResetLocalStructureData(void) { - DesfirePreviousState = DESFIRE_IDLE; - DesfireState = DESFIRE_HALT; - InvalidateAuthState(0x00); + DesfireState = DesfirePreviousState = DESFIRE_IDLE; + InvalidateAuthState(0); memset(&Picc, PICC_FORMAT_BYTE, sizeof(Picc)); memset(&AppDir, 0x00, sizeof(AppDir)); memset(&SelectedApp, 0x00, sizeof(SelectedApp)); @@ -413,9 +418,10 @@ void ResetLocalStructureData(void) { memset(&TransferState, 0x00, sizeof(TransferState)); memset(&SessionKey, 0x00, sizeof(CryptoKeyBufferType)); memset(&SessionIV, 0x00, sizeof(CryptoIVBufferType)); - SessionIVByteSize = 0x00; + SessionIVByteSize = 0; SelectedApp.Slot = 0; SelectedFile.Num = -1; + ResetISOState(); MifareDesfireReset(); } diff --git a/Firmware/Chameleon-Mini/Application/MifareDESFire.h b/Firmware/Chameleon-Mini/Application/MifareDESFire.h index c4c6a2cf..05a16706 100644 --- a/Firmware/Chameleon-Mini/Application/MifareDESFire.h +++ b/Firmware/Chameleon-Mini/Application/MifareDESFire.h @@ -37,6 +37,9 @@ This notice must be retained at the top of all source files where indicated. #include "DESFire/DESFireISO7816Support.h" #include "DESFire/DESFireInstructions.h" +#define DesfireCLA(cmdCode) \ + ((cmdCode == DESFIRE_NATIVE_CLA) || Iso7816CLA(cmdCode)) + void MifareDesfireEV0AppInit(void); void MifareDesfireEV0AppInitRunOnce(void); void MifareDesfire2kEV1AppInit(void); @@ -64,7 +67,6 @@ void MifareDesfireSetUid(ConfigurationUidType Uid); typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { DESFIRE_HALT = ISO14443_3A_STATE_HALT + 1, DESFIRE_IDLE, - DESFIRE_IDLE2, DESFIRE_GET_VERSION2, DESFIRE_GET_VERSION3, DESFIRE_GET_APPLICATION_IDS2, @@ -81,17 +83,6 @@ typedef enum DESFIRE_FIRMWARE_ENUM_PACKING { DESFIRE_WRITE_DATA_FILE, } DesfireStateType; -extern DesfireStateType DesfireState; -extern DesfireStateType DesfirePreviousState; - -extern Iso7816WrappedCommandType_t Iso7816CmdType; - -extern bool DesfireFromHalt; -extern BYTE DesfireCmdCLA; - -#define DesfireCLA(cmdCode) \ - ((cmdCode == DESFIRE_NATIVE_CLA) || Iso7816CLA(cmdCode)) - #define DesfireStateExpectingAdditionalFrame(dfState) \ ((dfState == DESFIRE_GET_VERSION2) || \ (dfState == DESFIRE_GET_VERSION3) || \ @@ -107,4 +98,12 @@ extern BYTE DesfireCmdCLA; (cmdCode == CMD_ISO7816_INTERNAL_AUTHENTICATE) || \ (cmdCode == CMD_ISO7816_GET_CHALLENGE)) +extern DesfireStateType DesfireState; +extern DesfireStateType DesfirePreviousState; + +extern Iso7816WrappedCommandType_t Iso7816CmdType; + +extern bool DesfireFromHalt; +extern BYTE DesfireCmdCLA; + #endif /* MIFAREDESFIRE_H_ */ diff --git a/Firmware/Chameleon-Mini/Application/Reader14443A.c b/Firmware/Chameleon-Mini/Application/Reader14443A.c index 988c0566..4ff8f083 100644 --- a/Firmware/Chameleon-Mini/Application/Reader14443A.c +++ b/Firmware/Chameleon-Mini/Application/Reader14443A.c @@ -866,7 +866,7 @@ uint16_t Reader14443AAppProcess(uint8_t *Buffer, uint16_t BitCount) { cfgid = -1; } - if (cfgid > -1) { + if (cfgid > -1) { /* TODO: Consider wrapping strings with PSTR(...): */ CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, "Cloned OK!"); /* Notify LED. blink when clone is done - ToDo: maybe use other LEDHook */ LEDHook(LED_SETTING_CHANGE, LED_BLINK_2X); diff --git a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk index 17dcb327..7345bdab 100644 --- a/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk +++ b/Firmware/Chameleon-Mini/BuildScripts/custom_build_targets.mk @@ -73,8 +73,6 @@ desfire-dev: EXTRA_CONFIG_SETTINGS:=-DMEMORY_LIMITED_TESTING \ -finline-small-functions \ -DDESFIRE_MIN_OUTGOING_LOGSIZE=0 \ -DDESFIRE_MIN_INCOMING_LOGSIZE=0 \ - -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING \ - -DDESFIRE_DEFAULT_TESTING_MODE=1 \ -DDESFIRE_DEBUGGING=1 desfire-dev: TARGET_CUSTOM_BUILD_NAME:=DESFire_DEV desfire-dev: CONFIG_SETTINGS:=$(SUPPORTED_TAGS_BUILD) -DDEFAULT_CONFIGURATION=CONFIG_NONE $(EXTRA_CONFIG_SETTINGS) diff --git a/Firmware/Chameleon-Mini/Chameleon-Mini.c b/Firmware/Chameleon-Mini/Chameleon-Mini.c index 54d87ba8..54501d4d 100644 --- a/Firmware/Chameleon-Mini/Chameleon-Mini.c +++ b/Firmware/Chameleon-Mini/Chameleon-Mini.c @@ -17,8 +17,9 @@ int main(void) { while (1) { if (SystemTick100ms()) { - LEDTick(); // this has to be the first function called here, since it is time-critical - - // the functions below may have non-negligible runtimes! + LEDTick(); /* This has to be the first function called here, since it is time-critical - + * the functions below may have non-negligible runtimes! + */ PinTick(); RandomTick(); TerminalTick(); diff --git a/Firmware/Chameleon-Mini/Common.c b/Firmware/Chameleon-Mini/Common.c index 99066a6d..e333fb3b 100644 --- a/Firmware/Chameleon-Mini/Common.c +++ b/Firmware/Chameleon-Mini/Common.c @@ -81,4 +81,3 @@ uint16_t HexStringToBuffer(void *Buffer, uint16_t MaxBytes, const char *HexIn) { return ByteCount; } - diff --git a/Firmware/Chameleon-Mini/Common.h b/Firmware/Chameleon-Mini/Common.h index d9472807..74fff7e6 100644 --- a/Firmware/Chameleon-Mini/Common.h +++ b/Firmware/Chameleon-Mini/Common.h @@ -15,10 +15,11 @@ #include #include -#define ODD_PARITY(Value) OddParityBit(Value)//(parity_even_bit(Value) ? 0 : 1) +#define ODD_PARITY(Value) OddParityBit(Value) +/* This function type has to be used for all the interrupt handlers that have to be changed at runtime: */ #define ISR_SHARED \ - void __attribute__((signal)) // This function type has to be used for all the interrupt handlers that have to be changed at runtime + void __attribute__((signal)) #define INLINE \ static inline __attribute__((always_inline)) diff --git a/Firmware/Chameleon-Mini/LiveLogTick.h b/Firmware/Chameleon-Mini/LiveLogTick.h index 6076c7e2..743c3df6 100644 --- a/Firmware/Chameleon-Mini/LiveLogTick.h +++ b/Firmware/Chameleon-Mini/LiveLogTick.h @@ -23,7 +23,7 @@ #define sei_memory() __asm volatile( "sei" ::: "memory" ) #ifndef FLUSH_LOGS_ON_SPACE_ERROR -#define FLUSH_LOGS_ON_SPACE_ERROR (1) +#define FLUSH_LOGS_ON_SPACE_ERROR (1) #endif typedef struct LogBlockListNode { uint8_t *logBlockDataStart; @@ -36,7 +36,7 @@ extern LogBlockListNode *LogBlockListBegin; extern LogBlockListNode *LogBlockListEnd; extern uint8_t LogBlockListElementCount; -#define LIVE_LOGGER_POST_TICKS (6) +#define LIVE_LOGGER_POST_TICKS (7) extern uint8_t LiveLogModePostTickCount; INLINE bool AtomicAppendLogBlock(LogEntryEnum logCode, uint16_t sysTickTime, const uint8_t *logData, uint8_t logDataSize); @@ -46,6 +46,7 @@ INLINE bool LiveLogTick(void); INLINE bool AtomicAppendLogBlock(LogEntryEnum logCode, uint16_t sysTickTime, const uint8_t *logData, uint8_t logDataSize) { + cli_memory(); bool status = true; if ((logDataSize + 4 + 3 + LOG_BLOCK_LIST_NODE_SIZE > LogMemLeft) && (LogMemPtr != LogMem)) { if (FLUSH_LOGS_ON_SPACE_ERROR) { @@ -80,6 +81,7 @@ AtomicAppendLogBlock(LogEntryEnum logCode, uint16_t sysTickTime, const uint8_t * } else { status = false; } + sei_memory(); return status; } @@ -93,7 +95,10 @@ FreeLogBlocks(void) { INLINE bool AtomicLiveLogTick(void) { - return LiveLogTick(); + //cli_memory(); + bool opStatus = LiveLogTick(); + //sei_memory(); + return opStatus; } INLINE bool @@ -103,7 +108,6 @@ LiveLogTick(void) { while (LogBlockListElementCount > 0) { TerminalFlushBuffer(); TerminalSendBlock(logBlockCurrent.logBlockDataStart, logBlockCurrent.logBlockDataSize); - TerminalFlushBuffer(); tempBlockPtr = logBlockCurrent.nextBlock; if (tempBlockPtr != NULL) { memcpy(&logBlockCurrent, tempBlockPtr, sizeof(LogBlockListNode)); @@ -114,6 +118,7 @@ LiveLogTick(void) { } FreeLogBlocks(); LiveLogModePostTickCount = 0; + TerminalFlushBuffer(); return true; } diff --git a/Firmware/Chameleon-Mini/Log.c b/Firmware/Chameleon-Mini/Log.c index 5cec3e31..5635ce27 100644 --- a/Firmware/Chameleon-Mini/Log.c +++ b/Firmware/Chameleon-Mini/Log.c @@ -76,21 +76,23 @@ void LogInit(void) { result = true; WriteEEPBlock((uint16_t) &LogFRAMAddrValid, &result, 1); } - LogEntry(LOG_INFO_SYSTEM_BOOT, NULL, 0); } void LogTick(void) { - // The logging functionality slows down the timings of data exchanges between - // Chameleon emulated tags and readers, so schedule the logging writes to - // happen only on intervals that will be outside of timing windows for individual xfers - // initiated from PICC <--> PCD (e.g., currently approximately every 600ms): - if ((++LiveLogModePostTickCount % LIVE_LOGGER_POST_TICKS) == 0) { - if (GlobalSettings.ActiveSettingPtr->LogMode == LOG_MODE_LIVE) + /* + * The logging functionality slows down the timings of data exchanges between + * Chameleon emulated tags and readers, so schedule the logging writes to + * happen only on intervals that will be outside of timing windows for individual xfers + * initiated from PICC <--> PCD (e.g., currently approximately every 600ms): + */ + if (GlobalSettings.ActiveSettingPtr->LogMode == LOG_MODE_LIVE) { + if ((++LiveLogModePostTickCount % LIVE_LOGGER_POST_TICKS) == 0) { AtomicLiveLogTick(); - if (EnableLogSRAMtoFRAM) - LogSRAMToFRAM(); - LiveLogModePostTickCount = 0; + LiveLogModePostTickCount = 0; + } + } else if (EnableLogSRAMtoFRAM) { + LogSRAMToFRAM(); } } diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index d184bcb7..48bb86cc 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -101,14 +101,8 @@ SETTINGS += -DENABLE_EEPROM_SETTINGS #SETTINGS += -DDISABLE_PERMISSIVE_DESFIRE_SETTINGS #SETTINGS += -DDISABLE_DESFIRE_TERMINAL_COMMANDS -## : Set a default logging mode for debugging with the DESFire -## : emulation code: -#CONFIG_SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=DEBUGGING -CONFIG_SETTINGS += -DDESFIRE_DEFAULT_LOGGING_MODE=OFF - -## : Set a default testing mode setting (0 = OFF, non-NULL = ON): -CONFIG_SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=0 -#CONFIG_SETTINGS += -DDESFIRE_DEFAULT_TESTING_MODE=1 +## : Enable extra verbose logging messages for debugging: +#CONFIG_SETTINGS += -DDESFIRE_DEBUGGING=1 ## : Feature: Use randomized UIDs that mask the actual secret UID until ## : the tag has been issued a successful authentication sequence: