From b451e1212be5410566a3f43414f43288c8d7c0a1 Mon Sep 17 00:00:00 2001 From: Maxie Dion Schmidt Date: Thu, 3 Feb 2022 06:52:33 -0500 Subject: [PATCH] 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; }