Skip to content

Commit

Permalink
Merge pull request #319 from maxieds/DESFire-AuthISO-Patch
Browse files Browse the repository at this point in the history
DESFire emulation support: Bug, stability and reliability fixes and PM3 compatible ISO authentication
  • Loading branch information
fptrs authored Jul 8, 2022
2 parents 99dceff + 37be68d commit bc333f9
Show file tree
Hide file tree
Showing 95 changed files with 5,258 additions and 3,827 deletions.
607 changes: 235 additions & 372 deletions Doc/DESFireSupportReadme.md

Large diffs are not rendered by default.

72 changes: 0 additions & 72 deletions Dumps/DESFire_example.contents

This file was deleted.

Binary file removed Dumps/DESFire_example.dmp
Binary file not shown.
19 changes: 11 additions & 8 deletions Firmware/Chameleon-Mini/.gitignore
Original file line number Diff line number Diff line change
@@ -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/*
2 changes: 1 addition & 1 deletion Firmware/Chameleon-Mini/AntennaLevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 8 additions & 1 deletion Firmware/Chameleon-Mini/Application/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,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();
}
Expand All @@ -44,7 +52,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) {
Expand Down
94 changes: 68 additions & 26 deletions Firmware/Chameleon-Mini/Application/CryptoAES128.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -178,21 +181,22 @@ 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;
}
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();
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;
Expand All @@ -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;
Expand All @@ -217,7 +221,7 @@ void CryptoAESDecryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_
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;
Expand All @@ -234,16 +238,18 @@ void CryptoAESDecryptBlock(uint8_t *Plaintext, uint8_t *Ciphertext, const uint8_

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);
Expand All @@ -252,26 +258,33 @@ 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;
}

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);
Expand All @@ -281,18 +294,24 @@ 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;
}

// 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,
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);
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);
uint16_t blockIndex = 0;
uint8_t *ptBuf = (uint8_t *) Plaintext, *ctBuf = (uint8_t *) Ciphertext;
Expand All @@ -316,9 +335,10 @@ 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,
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);
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);
uint16_t blockIndex = 0;
uint8_t *ptBuf = (uint8_t *) Plaintext, *ctBuf = (uint8_t *) Ciphertext;
Expand All @@ -341,38 +361,60 @@ 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);
}

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;
}
Loading

0 comments on commit bc333f9

Please sign in to comment.