Skip to content

Commit

Permalink
Debugging ISO authenticate command (0x1a)
Browse files Browse the repository at this point in the history
  • Loading branch information
maxieds committed Jan 30, 2022
1 parent 88ff788 commit fba0ee3
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 8 deletions.
4 changes: 2 additions & 2 deletions Firmware/Chameleon-Mini/Application/CryptoTDEA.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* CryptoDES.h
*
* Created on: 18.10.2016
Expand Down Expand Up @@ -35,7 +35,7 @@ PCD's side.
typedef uint8_t Crypto2KTDEAKeyType[CRYPTO_2KTDEA_KEY_SIZE];
typedef uint8_t Crypto3KTDEAKeyType[CRYPTO_3KTDEA_KEY_SIZE];

#define CRYPTO_DES_BLOCK_SIZE 8 /* Bytes */
#define CRYPTO_DES_BLOCK_SIZE 8 /* Bytes */
#define CRYPTO_2KTDEA_BLOCK_SIZE (CRYPTO_DES_BLOCK_SIZE)
#define CRYPTO_3KTDEA_BLOCK_SIZE (CRYPTO_DES_BLOCK_SIZE)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1685,13 +1685,14 @@ uint16_t DesfireCmdAuthenticate3KTDEA1(uint8_t *Buffer, uint16_t ByteCount) {
Buffer[0] = STATUS_PARAMETER_ERROR;
return DESFIRE_STATUS_RESPONSE_SIZE;
}
/* Make sure that this key is AES, and figure out its byte size */
/* Make sure that this key is 3DES, and figure out its byte size */
BYTE cryptoKeyType = ReadKeyCryptoType(SelectedApp.Slot, KeyId);
if (!CryptoType3KTDEA(cryptoKeyType)) {
Buffer[0] = STATUS_NO_SUCH_KEY;
return DESFIRE_STATUS_RESPONSE_SIZE;
}

/* The next calls just zero out the key buffers (not specific to AES): */
InitAESCryptoKeyData(&AESCryptoSessionKey);
InitAESCryptoKeyData(&AESCryptoIVBuffer);

Expand Down Expand Up @@ -1748,7 +1749,7 @@ uint16_t DesfireCmdAuthenticate3KTDEA2(uint8_t *Buffer, uint16_t ByteCount) {
/* Set status for the next incoming command on error */
DesfireState = DESFIRE_IDLE;
/* Validate command length */
if (ByteCount != CRYPTO_AES_BLOCK_SIZE + 1) {
if (ByteCount != CRYPTO_DES_BLOCK_SIZE + 1) {
Buffer[0] = STATUS_LENGTH_ERROR;
return DESFIRE_STATUS_RESPONSE_SIZE;
}
Expand Down
5 changes: 3 additions & 2 deletions Firmware/Chameleon-Mini/Application/MifareDESFire.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ uint16_t MifareDesfireProcess(uint8_t *Buffer, uint16_t BitCount) {
size_t ByteCount = (BitCount + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
DesfireCmdCLA = Buffer[0];
if ((ByteCount >= 8 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 &&
Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) || Iso7816CLA(DesfireCmdCLA)) { // Wrapped native command structure:
Buffer[3] == 0x00 && Buffer[4] == ByteCount - 8) || Iso7816CLA(DesfireCmdCLA)) {
// Wrapped native command structure:
/* Unwrap the PDU from ISO 7816-4 */
// Check CRC bytes appended to the buffer:
// -- Actually, just ignore parity problems if they exist,
Expand Down Expand Up @@ -218,7 +219,7 @@ uint16_t MifareDesfireAppProcess(uint8_t *Buffer, uint16_t BitCount) {
} else if (ByteCount >= 6 && DesfireCLA(Buffer[0]) && Buffer[2] == 0x00 &&
Buffer[3] == 0x00 && Buffer[4] == ByteCount - 6) {
// Native wrapped command send without CRCA checksum bytes appended:
return MifareDesfireProcess(Buffer, BitCount);
return MAX(0, MifareDesfireProcess(Buffer, BitCount) - 2 * BITS_PER_BYTE);
} else if (IsWrappedISO7816CommandType(Buffer, ByteCount)) {
uint8_t ISO7816PrologueBytes[2];
memcpy(&ISO7816PrologueBytes[0], Buffer, 2);
Expand Down
68 changes: 68 additions & 0 deletions Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <string.h>
#include <stdint.h>

#include <openssl/des.h>
#include <openssl/rand.h>

#include <ArduinoCryptoLib-SingleSource.c>
Expand Down Expand Up @@ -124,6 +125,30 @@ static inline size_t DecryptAES128(const uint8_t *encSrcBuf, size_t bufSize,
return bufSize;
}

static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize,
uint8_t *encDestBuf, CryptoData_t cdata) {
DES_key_schedule keySched1, keySched2, keySched3;
DES_cblock IV;
DES_set_key(cdata.keyData, &keySched1);
DES_set_key(&cdata.keyData[8], &keySched2);
DES_set_key(&cdata.keyData[16], &keySched3);
memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE);
DES_ede3_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_ENCRYPT);
return bufSize;
}

static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize,
uint8_t *plainDestBuf, CryptoData_t cdata) {
DES_key_schedule keySched1, keySched2, keySched3;
DES_cblock IV;
DES_set_key(cdata.keyData, &keySched1);
DES_set_key(&cdata.keyData[8], &keySched2);
DES_set_key(&cdata.keyData[16], &keySched3);
memset(IV, 0x00, CRYPTO_DES_BLOCK_SIZE);
DES_ede3_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_DECRYPT);
return bufSize;
}

static inline bool TestAESEncyptionRoutines(void) {
fprintf(stdout, ">>> TestAESEncryptionRoutines [non-DESFire command]:\n");
const uint8_t keyData[] = {
Expand Down Expand Up @@ -167,6 +192,49 @@ static inline bool TestAESEncyptionRoutines(void) {
return status;
}

static inline bool Test3DESEncyptionRoutines(void) {
fprintf(stdout, ">>> TestAESEncryptionRoutines [non-DESFire command]:\n");
const uint8_t keyData[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
};
const uint8_t ptData[] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
const uint8_t ctData[] = {
0x3e, 0xf0, 0xa8, 0x91, 0xcf, 0x8e, 0xd9, 0x90,
0xc4, 0x77, 0xeb, 0x09, 0x02, 0xf0, 0xc5, 0x4a
};
CryptoData_t cdata;
cdata.keyData = keyData;
cdata.keySize = 3 * 8;
uint8_t pt[16], pt2[16], ct[16];
Encrypt3DES(ptData, 16, ct, cdata);
Decrypt3DES(ct, 16, pt2, cdata);
fprintf(stdout, " -- : PT = "); print_hex(ptData, 16);
fprintf(stdout, " -- : CT = "); print_hex(ctData, 16);
fprintf(stdout, " -- : CT = "); print_hex(ct, 16);
fprintf(stdout, " -- : PT = "); print_hex(pt2, 16);
bool status = true;
if(memcmp(ct, ctData, 16)) {
fprintf(stdout, " -- CT does NOT match !!\n");
status = false;
}
else {
fprintf(stdout, " -- CT matches.\n");
}
if(memcmp(pt2, ptData, 16)) {
fprintf(stdout, " -- Decrypted PT from CT does NOT match !!\n");
status = false;
}
else {
fprintf(stdout, " -- Decrypted PT from CT matches.\n");
}
fprintf(stdout, "\n");
return status;
}
static inline int GenerateRandomBytes(uint8_t *destBuf, size_t numBytes) {
return RAND_pseudo_bytes(destBuf, numBytes);
}
Expand Down
106 changes: 105 additions & 1 deletion Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,108 @@ static inline int AuthenticateAES128(nfc_device *nfcConnDev, uint8_t keyIndex, c
}
}

static inline int AuthenticateISO(nfc_device *nfcConnDev, uint8_t keyIndex, const uint8_t *keyData) {

if(nfcConnDev == NULL || keyData == NULL) {
return INVALID_PARAMS_ERROR;
}

// Start AES authentication (default key, blank setting of all zeros):
uint8_t AUTHENTICATE_ISO_CMD[] = {
0x90, 0x1a, 0x00, 0x00, 0x01, 0x00, 0x00
};
AUTHENTICATE_ISO_CMD[5] = keyIndex;
if(PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, ">>> Start AES Authenticate:\n");
fprintf(stdout, " -> ");
print_hex(AUTHENTICATE_ISO_CMD, sizeof(AUTHENTICATE_ISO_CMD));
}
RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH);
bool rxDataStatus = false;
rxDataStatus = libnfcTransmitBytes(nfcConnDev, AUTHENTICATE_ISO_CMD, sizeof(AUTHENTICATE_ISO_CMD), rxDataStorage);
if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " <- ");
print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx);
}
else {
if(PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " -- !! Unable to transfer bytes !!\n");
}
FreeRxDataStruct(rxDataStorage, true);
return EXIT_FAILURE;
}

// Now need to decrypt the challenge response sent back as rndB (8 bytes),
// rotate it left, generate a random 8 byte rndA, concat rndA+rotatedRndB,
// encrypt this 16 byte result, and send it forth to the PICC:
uint8_t encryptedRndB[16], plainTextRndB[16], rotatedRndB[8];
uint8_t rndA[8], challengeResponse[16], challengeResponseCipherText[16];
int8_t IVBuf[16];
memcpy(encryptedRndB, rxDataStorage->rxDataBuf, 16);
CryptoData_t desCryptoData = { 0 };
desCryptoData.keySize = 8;
desCryptoData.keyData = keyData;
desCryptoData.ivSize = 8;
Decrypt3DES(encryptedRndB, 16, plainTextRndB, desCryptoData);
RotateArrayLeft(plainTextRndB, rotatedRndB, 8);
memset(IVBuf, 0x00, 16);
desCryptoData.ivData = IVBuf;
GenerateRandomBytes(rndA, 8);
ConcatByteArrays(rndA, 8, rotatedRndB, 8, challengeResponse);
Encrypt3DES(challengeResponse, 16, challengeResponseCipherText, desCryptoData);

uint8_t sendBytesBuf[22];
memset(sendBytesBuf, 0x00, 22);
sendBytesBuf[0] = 0x90;
sendBytesBuf[1] = 0xaf;
sendBytesBuf[4] = 0x10;
memcpy(sendBytesBuf + 5, challengeResponseCipherText, 16);

if(PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " -- RNDA = "); print_hex(rndA, 8);
fprintf(stdout, " -- RNDB = "); print_hex(plainTextRndB, 8);
fprintf(stdout, " -- CHAL = "); print_hex(challengeResponse, 16);
fprintf(stdout, " -> ");
print_hex(sendBytesBuf, sizeof(sendBytesBuf));
}
rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 22, rxDataStorage);
if(rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " <- ");
print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx);
}
else {
if(PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " -- !! Unable to transfer bytes !!\n");
}
FreeRxDataStruct(rxDataStorage, true);
return EXIT_FAILURE;
}

// Finally, to finish up the auth process:
// decrypt rndA sent by PICC, compare it to our original randomized rndA computed above,
// and report back whether they match:
uint8_t decryptedRndAFromPICCRotated[16], decryptedRndA[16];
Decrypt3DES(rxDataStorage->rxDataBuf, 16, decryptedRndAFromPICCRotated, desCryptoData);
RotateArrayRight(decryptedRndAFromPICCRotated, decryptedRndA, 8);
if(!memcmp(rndA, decryptedRndA, 8)) {
if(PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " ... AUTH OK! :)\n\n");
}
AUTHENTICATED = true;
AUTHENTICATED_PROTO = DESFIRE_CRYPTO_AUTHTYPE_ISODES;
memcpy(CRYPTO_RNDB_STATE, plainTextRndB, 8);
FreeRxDataStruct(rxDataStorage, true);
return EXIT_SUCCESS;
}
else {
if(PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " ... AUTH FAILED -- X; :(\n\n");
}
FreeRxDataStruct(rxDataStorage, true);
return EXIT_FAILURE;
}
}

static inline int Authenticate(nfc_device *nfcConnDev, int authType, uint8_t keyIndex, const uint8_t *keyData) {
InvalidateAuthState();
if(nfcConnDev == NULL || keyData == NULL) {
Expand All @@ -127,7 +229,9 @@ static inline int Authenticate(nfc_device *nfcConnDev, int authType, uint8_t key
switch(authType) {
case DESFIRE_CRYPTO_AUTHTYPE_AES128:
return AuthenticateAES128(nfcConnDev, keyIndex, keyData);
default:
case DESFIRE_CRYPTO_AUTHTYPE_ISODES:
return AuthenticateISO(nfcConnDev, keyIndex, keyData);
default:
break;
}
return EXIT_FAILURE;
Expand Down
2 changes: 1 addition & 1 deletion Software/DESFireLibNFCTesting/LocalInclude/LibNFCWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ static inline nfc_device * GetNFCDeviceDriver(nfc_context **context) {
return NULL;
}
// Configure some convenient common settings:
nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false);
//nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false);
nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true);
nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true);
nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, true);
Expand Down
2 changes: 2 additions & 0 deletions Software/DESFireLibNFCTesting/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ LIBNFC_SUPPORTED_DRIVERS= -DDRIVER_PN53X_USB_ENABLED \
-DDRIVER_PN532_SPI_ENABLED \
-DDRIVER_PN532_I2C_ENABLED \
-DDRIVER_PN71XX_ENABLED
#LIBNFC_SUPPORTED_DRIVERS= -DDRIVER_ACR122_PCSC_ENABLED
LIBNFC_CUSTOM_CONFIG= -DLIBNFC_LOGLEVEL=NFC_LOG_PRIORITY_DEBUG \
-ULOG_CATEGORY -DLOG_CATEGORY=\"DESFireTesting.libnfc.general\" \
-ULOG_GROUP -DLOG_GROUP=NFC_LOG_GROUP_GENERAL
CFLAGS+= $(LIBNFC_SUPPORTED_DRIVERS) $(LIBNFC_CUSTOM_CONFIG)

FILE_BASENAMES=NFCAntiCollisionMod \
TestAuthenticateAES128 \
TestAuthenticateISO \
TestGeneralCommands \
TestKeyManagementCommands \
TestApplicationManagementCommands \
Expand Down
39 changes: 39 additions & 0 deletions Software/DESFireLibNFCTesting/Source/TestAuthenticateISO.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* TestAuthenticateAES128.c */

#include "LibNFCUtils.h"
#include "LibNFCWrapper.h"
#include "DesfireUtils.h"
#include "CryptoUtils.h"

/*
* See Notes: https://stackoverflow.com/questions/52520044/desfire-ev1-communication-how-to-assign-iv
*/

int main(int argc, char **argv) {

if(!Test3DESEncyptionRoutines()) {
return EXIT_FAILURE;
}

nfc_context *nfcCtxt;
nfc_device *nfcPnd = GetNFCDeviceDriver(&nfcCtxt);
if(nfcPnd == NULL) {
return EXIT_FAILURE;
}

// Select AID application 0x000000:
if(SelectApplication(nfcPnd, MASTER_APPLICATION_AID, APPLICATION_AID_LENGTH)) {
return EXIT_FAILURE;
}

// Start AES authentication (default key, blank setting of all zeros):
if(Authenticate(nfcPnd, DESFIRE_CRYPTO_AUTHTYPE_ISODES,
MASTER_KEY_INDEX, ZERO_KEY)) {
return EXIT_FAILURE;
}

FreeNFCDeviceDriver(&nfcCtxt, &nfcPnd);
return EXIT_SUCCESS;

}

0 comments on commit fba0ee3

Please sign in to comment.