Skip to content

Commit

Permalink
Verified ISODES and legacy DES auth schemes work ; AES-128 auth suppo…
Browse files Browse the repository at this point in the history
…rt is verified with the PM3
  • Loading branch information
maxieds committed Jul 20, 2022
1 parent a050d04 commit 126189a
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 269 deletions.
82 changes: 2 additions & 80 deletions Software/DESFireLibNFCTesting/LocalInclude/CryptoUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@
#include <string.h>
#include <stdint.h>

#include <openssl/conf.h>
#include <openssl/rand.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/des.h>

#include "LibNFCUtils.h"
Expand Down Expand Up @@ -78,78 +74,6 @@ typedef struct {
} \
})

/* Set the last operation mode (ECB or CBC) init for the context */
static uint8_t __CryptoAESOpMode = CRYPTO_AES_ECB_MODE;

static inline size_t EncryptAES128(const uint8_t *plainSrcBuf, size_t bufSize,
uint8_t *encDestBuf, CryptoData_t cdata) {
size_t bufBlocks = bufSize / AES128_BLOCK_SIZE;
bool padLastBlock = (bufSize % AES128_BLOCK_SIZE) != 0;
uint8_t IV[AES128_BLOCK_SIZE], inputBlock[AES128_BLOCK_SIZE];
if (cdata.ivData != NULL) {
memcpy(&IV[0], &cdata.ivData[0], AES128_BLOCK_SIZE);
} else {
memset(&IV[0], 0x00, AES128_BLOCK_SIZE);
}
if ((bufSize % AES128_BLOCK_SIZE) != 0) {
return 0xBE;
}
EVP_CIPHER_CTX *aesCtx = EVP_CIPHER_CTX_new();
int aesOpInitStatus = 1;
if (__CryptoAESOpMode == CRYPTO_AES_CBC_MODE) {
aesOpInitStatus = EVP_EncryptInit_ex(aesCtx, EVP_aes_128_cbc(), NULL, cdata.keyData, cdata.ivData);
} else { /* ECB mode */
aesOpInitStatus = EVP_EncryptInit_ex(aesCtx, EVP_aes_128_ecb(), NULL, cdata.keyData, cdata.ivData);
}
int ctextLength = 0, ctextInitLength = 0;
if (aesOpInitStatus != 1) {
ctextLength = 0xBE00 | aesOpInitStatus;
} else if (EVP_EncryptUpdate(aesCtx, encDestBuf, &ctextInitLength, plainSrcBuf, bufSize) != 1) {
ctextLength = 0;
} else {
ctextLength = ctextInitLength;
if (EVP_EncryptFinal_ex(aesCtx, &encDestBuf[ctextInitLength], &ctextInitLength) != 1) {
ctextLength += ctextInitLength;
}
}
EVP_CIPHER_CTX_free(aesCtx);
return ctextLength;
}

static inline size_t DecryptAES128(const uint8_t *encSrcBuf, size_t bufSize,
uint8_t *plainDestBuf, CryptoData_t cdata) {
size_t bufBlocks = bufSize / AES128_BLOCK_SIZE;
bool padLastBlock = (bufSize % AES128_BLOCK_SIZE) != 0;
uint8_t IV[AES128_BLOCK_SIZE], inputBlock[AES128_BLOCK_SIZE];
if (cdata.ivData != NULL) {
memcpy(&IV[0], &cdata.ivData[0], AES128_BLOCK_SIZE);
} else {
memset(&IV[0], 0x00, AES128_BLOCK_SIZE);
}
if ((bufSize % AES128_BLOCK_SIZE) != 0) {
return 0xBE;
}
EVP_CIPHER_CTX *aesCtx = EVP_CIPHER_CTX_new();
int aesOpInitStatus = 1;
if (__CryptoAESOpMode == CRYPTO_AES_CBC_MODE) {
aesOpInitStatus = EVP_DecryptInit_ex(aesCtx, EVP_aes_128_cbc(), NULL, cdata.keyData, cdata.ivData);
} else { /* ECB mode */
aesOpInitStatus = EVP_DecryptInit_ex(aesCtx, EVP_aes_128_ecb(), NULL, cdata.keyData, cdata.ivData);
}
int ctextLength = 0, ctextInitLength = 0;
if (aesOpInitStatus != 1) {
ctextLength = 0xBE00 | aesOpInitStatus;
} else if (EVP_DecryptUpdate(aesCtx, plainDestBuf, &ctextInitLength, encSrcBuf, bufSize) != 1) {
ctextLength = 0;
} else {
ctextLength = ctextInitLength;
if (EVP_DecryptFinal_ex(aesCtx, &plainDestBuf[ctextInitLength], &ctextInitLength) != 1) {
ctextLength += ctextInitLength;
}
}
EVP_CIPHER_CTX_free(aesCtx);
return ctextLength;
}

/* Set the last operation mode (ECB or CBC) init for the context */
static uint8_t __CryptoDESOpMode = CRYPTO_DES_ECB_MODE;
Expand Down Expand Up @@ -211,7 +135,7 @@ static inline size_t Decrypt2K3DES(const uint8_t *encSrcBuf, size_t bufSize,
static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize,
uint8_t *encDestBuf, const uint8_t *IVIn, CryptoData_t cdata) {
DES_key_schedule keySched1, keySched2, keySched3;
uint8_t IV[CRYPTO_DES_BLOCK_SIZE];
uint8_t IV[CRYPTO_DES_BLOCK_SIZE], inputBlock[CRYPTO_DES_BLOCK_SIZE];
uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[CRYPTO_DES_BLOCK_SIZE]), *kd3 = &(cdata.keyData[2 * CRYPTO_DES_BLOCK_SIZE]);
DES_set_key(kd1, &keySched1);
DES_set_key(kd2, &keySched2);
Expand All @@ -224,7 +148,6 @@ static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize,
if (__CryptoDESOpMode == CRYPTO_DES_CBC_MODE) {
DES_ede3_cbc_encrypt(plainSrcBuf, encDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_ENCRYPT);
} else {
uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE];
uint16_t numBlocks = bufSize / CRYPTO_DES_BLOCK_SIZE;
for (int blk = 0; blk < numBlocks; blk++) {
memcpy(inputBlock, &plainSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE], CRYPTO_DES_BLOCK_SIZE);
Expand All @@ -242,7 +165,7 @@ static inline size_t Encrypt3DES(const uint8_t *plainSrcBuf, size_t bufSize,
static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize,
uint8_t *plainDestBuf, const uint8_t *IVIn, CryptoData_t cdata) {
DES_key_schedule keySched1, keySched2, keySched3;
uint8_t IV[CRYPTO_DES_BLOCK_SIZE];
uint8_t IV[CRYPTO_DES_BLOCK_SIZE], inputBlock[CRYPTO_DES_BLOCK_SIZE];
uint8_t *kd1 = cdata.keyData, *kd2 = &(cdata.keyData[CRYPTO_DES_BLOCK_SIZE]), *kd3 = &(cdata.keyData[2 * CRYPTO_DES_BLOCK_SIZE]);
DES_set_key(kd1, &keySched1);
DES_set_key(kd2, &keySched2);
Expand All @@ -255,7 +178,6 @@ static inline size_t Decrypt3DES(const uint8_t *encSrcBuf, size_t bufSize,
if (__CryptoDESOpMode == CRYPTO_DES_CBC_MODE) {
DES_ede3_cbc_encrypt(encSrcBuf, plainDestBuf, bufSize, &keySched1, &keySched2, &keySched3, &IV, DES_DECRYPT);
} else {
uint8_t inputBlock[CRYPTO_DES_BLOCK_SIZE];
uint16_t numBlocks = bufSize / CRYPTO_DES_BLOCK_SIZE;
for (int blk = 0; blk < numBlocks; blk++) {
DES_ecb3_encrypt(&encSrcBuf[blk * CRYPTO_DES_BLOCK_SIZE],
Expand Down
124 changes: 1 addition & 123 deletions Software/DESFireLibNFCTesting/LocalInclude/DesfireUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,127 +25,6 @@ static inline void InvalidateAuthenticationStatus(void) {
memset(ActiveCryptoIVBuffer, 0x00, CRYPTO_CHALLENGE_RESPONSE_SIZE);
}

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

if (nfcConnDev == NULL || keyData == NULL) {
InvalidateAuthenticationStatus();
return INVALID_PARAMS_ERROR;
} else if (!AUTHENTICATED) {
InvalidateAuthenticationStatus();
}

// Start AES authentication (default key, blank setting of all zeros):
CryptoData_t aesCryptoData;
memset(&aesCryptoData, 0x00, sizeof(CryptoData_t));
aesCryptoData.keySize = CRYPTO_AES128_KEY_SIZE;
aesCryptoData.keyData = keyData;
aesCryptoData.ivData = ActiveCryptoIVBuffer;
aesCryptoData.ivSize = CRYPTO_CHALLENGE_RESPONSE_SIZE;

uint8_t AUTHENTICATE_AES_CMD[] = {
0x90, 0xaa, 0x00, 0x00, 0x01, 0x00, 0x00
};
AUTHENTICATE_AES_CMD[5] = keyIndex;
if (PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, ">>> Start AES Authenticate:\n");
fprintf(stdout, " -> ");
print_hex(AUTHENTICATE_AES_CMD, sizeof(AUTHENTICATE_AES_CMD));
fprintf(stdout, " -- IV = ");
print_hex(aesCryptoData.ivData, AES128_BLOCK_SIZE);
}
RxData_t *rxDataStorage = InitRxDataStruct(MAX_FRAME_LENGTH);
bool rxDataStatus = false;
rxDataStatus = libnfcTransmitBytes(nfcConnDev, AUTHENTICATE_AES_CMD, sizeof(AUTHENTICATE_AES_CMD), rxDataStorage);
if (rxDataStatus && PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " <- ");
print_hex(rxDataStorage->rxDataBuf, rxDataStorage->recvSzRx);
} else {
if (PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " -- !! Unable to transfer bytes !!\n");
}
FreeRxDataStruct(rxDataStorage, true);
InvalidateAuthenticationStatus();
return EXIT_FAILURE;
}

// 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];
memcpy(encryptedRndB, rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE);
DecryptAES128(encryptedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE, plainTextRndB, aesCryptoData);
if (PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " -- IV = ");
print_hex(aesCryptoData.ivData, AES128_BLOCK_SIZE);
}
RotateArrayRight(plainTextRndB, rotatedRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE);
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);
uint16_t nonDataPaddingSize = 6;
uint8_t sendBytesBuf[2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + nonDataPaddingSize];
memset(sendBytesBuf, 0x00, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + nonDataPaddingSize);
sendBytesBuf[0] = 0x90;
sendBytesBuf[1] = 0xaf;
sendBytesBuf[4] = 0x20;
memcpy(&sendBytesBuf[5], challengeResponseCipherText, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE);

if (PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " -- RNDA = ");
print_hex(rndA, CRYPTO_CHALLENGE_RESPONSE_SIZE);
fprintf(stdout, " -- RNDB = ");
print_hex(plainTextRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE);
fprintf(stdout, " -- CHAL = ");
print_hex(challengeResponse, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE);
fprintf(stdout, " -- ENC-CHAL = ");
print_hex(challengeResponseCipherText, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE);
fprintf(stdout, " -> ");
print_hex(sendBytesBuf, sizeof(sendBytesBuf));
fprintf(stdout, " -- IV = ");
print_hex(aesCryptoData.ivData, AES128_BLOCK_SIZE);
}
rxDataStatus = libnfcTransmitBytes(nfcConnDev, sendBytesBuf, 2 * CRYPTO_CHALLENGE_RESPONSE_SIZE + nonDataPaddingSize, 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);
InvalidateAuthenticationStatus();
return EXIT_FAILURE;
}

uint8_t decryptedRndAFromPICCRotated[CRYPTO_CHALLENGE_RESPONSE_SIZE], decryptedRndA[CRYPTO_CHALLENGE_RESPONSE_SIZE];
DecryptAES128(rxDataStorage->rxDataBuf, CRYPTO_CHALLENGE_RESPONSE_SIZE, decryptedRndAFromPICCRotated, aesCryptoData);
if (PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " -- IV = ");
print_hex(aesCryptoData.ivData, AES128_BLOCK_SIZE);
}
RotateArrayLeft(decryptedRndAFromPICCRotated, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE);
if (!memcmp(rndA, decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE)) {
if (PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " ... AUTH OK! :)\n\n");
}
AUTHENTICATED = true;
AUTHENTICATED_PROTO = DESFIRE_CRYPTO_AUTHTYPE_AES128;
memcpy(CRYPTO_RNDB_STATE, plainTextRndB, CRYPTO_CHALLENGE_RESPONSE_SIZE);
FreeRxDataStruct(rxDataStorage, true);
return EXIT_SUCCESS;
} else {
if (PRINT_STATUS_EXCHANGE_MESSAGES) {
fprintf(stdout, " ... AUTH FAILED -- X; :(\n");
fprintf(stdout, " ... ");
print_hex(decryptedRndA, CRYPTO_CHALLENGE_RESPONSE_SIZE);
}
FreeRxDataStruct(rxDataStorage, true);
InvalidateAuthenticationStatus();
return EXIT_FAILURE;
}
}

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

if (nfcConnDev == NULL || keyData == NULL) {
Expand Down Expand Up @@ -405,12 +284,11 @@ static inline int Authenticate(nfc_device *nfcConnDev, int authType, uint8_t key
return INVALID_PARAMS_ERROR;
}
switch (authType) {
case DESFIRE_CRYPTO_AUTHTYPE_AES128:
return AuthenticateAES128(nfcConnDev, keyIndex, keyData);
case DESFIRE_CRYPTO_AUTHTYPE_ISODES:
return AuthenticateISO(nfcConnDev, keyIndex, keyData);
case DESFIRE_CRYPTO_AUTHTYPE_LEGACY:
return AuthenticateLegacy(nfcConnDev, keyIndex, keyData);
case DESFIRE_CRYPTO_AUTHTYPE_AES128:
default:
break;
}
Expand Down
1 change: 0 additions & 1 deletion Software/DESFireLibNFCTesting/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ UTILS_SOURCE=LocalInclude/Config.h \

FILE_BASENAMES=NFCAntiCollisionMod \
TestAuthenticateLegacy \
TestAuthenticateAES128 \
TestAuthenticateISO \
TestGeneralCommands \
TestKeyManagementCommands \
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
>>> Select Application By AID:
-> 90 5a 00 00 03 00 00 00 | 00
<- 91 00

>>> GetApplicationIds command:
-> 90 6a 00 00 00 00
<- 91 00

>>> Start Legacy DES Authenticate:
-> 90 0a 00 00 01 00 00
-- IV = 00 00 00 00 00 00 00 00
<- ee 91 30 1e e8 f5 84 d6 | 91 af
-- IV = ee 91 30 1e e8 f5 84 d6
-- RNDA = fa df a6 a3 18 78 ec f5
-- RNDB = ca fe ba be 00 11 22 33
-- CHAL = fa df a6 a3 18 78 ec f5 | fe ba be 00 11 22 33 ca
-- ENC-CHAL = db 12 5c 5a a6 56 a4 20 | af b0 0a 05 ac c2 ed 51
-> 90 af 00 00 10 db 12 5c | 5a a6 56 a4 20 af b0 0a | 05 ac c2 ed 51 00
-- IV = af b0 0a 05 ac c2 ed 51
<- c1 ce 0a 26 d3 d1 4e d3 | 91 00 b0 0a
-- IV = c1 ce 0a 26 d3 d1 4e d3
... AUTH OK! :)

39 changes: 0 additions & 39 deletions Software/DESFireLibNFCTesting/Source/TestAuthenticateAES128.c

This file was deleted.

0 comments on commit 126189a

Please sign in to comment.