Skip to content

Commit

Permalink
Preliminary (partial) support for more CommModes -- This is going to …
Browse files Browse the repository at this point in the history
…need substantial testing -- III
  • Loading branch information
maxieds committed Feb 13, 2022
1 parent 74f216f commit a24fbe8
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 173 deletions.
30 changes: 15 additions & 15 deletions Firmware/Chameleon-Mini/Application/CryptoAES128.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,8 @@ uint8_t CryptoAESDecryptBuffer(uint16_t Count, uint8_t *Plaintext, uint8_t *Ciph
// This routine performs the CBC "send" mode chaining: C = E(P ^ IV); IV = C
static void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t *IV, uint8_t *Key, CryptoAES_CBCSpec_t CryptoSpec);
static void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext,
uint8_t *IV, uint8_t *Key,
CryptoAES_CBCSpec_t CryptoSpec) {
uint8_t *IV, uint8_t *Key,
CryptoAES_CBCSpec_t CryptoSpec) {
uint16_t numBlocks = CRYPTO_BYTES_TO_BLOCKS(Count, CryptoSpec.blockSize);
uint16_t blockIndex = 0;
uint8_t *ptBuf = (uint8_t *) Plaintext, *ctBuf = (uint8_t *) Ciphertext;
Expand All @@ -323,8 +323,8 @@ static void CryptoAES_CBCSend(uint16_t Count, void *Plaintext, void *Ciphertext,
// This routine performs the CBC "receive" mode chaining: C = E(P) ^ IV; IV = P
static void CryptoAES_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext, uint8_t *IV, uint8_t *Key, CryptoAES_CBCSpec_t CryptoSpec);
static void CryptoAES_CBCRecv(uint16_t Count, void *Plaintext, void *Ciphertext,
uint8_t *IV, uint8_t *Key,
CryptoAES_CBCSpec_t CryptoSpec) {
uint8_t *IV, uint8_t *Key,
CryptoAES_CBCSpec_t CryptoSpec) {
uint16_t numBlocks = CRYPTO_BYTES_TO_BLOCKS(Count, CryptoSpec.blockSize);
uint16_t blockIndex = 0;
uint8_t *ptBuf = (uint8_t *) Plaintext, *ctBuf = (uint8_t *) Ciphertext;
Expand Down Expand Up @@ -389,18 +389,18 @@ uint16_t appendBufferCRC32C(uint8_t *bufferData, uint16_t bufferSize) {
uint32_t workingCRC = INIT_CRC32C_VALUE;
for (int i = 0; i < bufferSize; i++) {
workingCRC = workingCRC ^ *(bufferData++);
for (int j = 0; j < 8; j++) {
for (int j = 0; j < 8; j++) {
if (workingCRC & 1) {
workingCRC = (workingCRC >> 1) ^ LE_CRC32C_POLYNOMIAL;
} else {
workingCRC = workingCRC >> 1;
}
}
workingCRC = (workingCRC >> 1) ^ LE_CRC32C_POLYNOMIAL;
} else {
workingCRC = workingCRC >> 1;
}
}
}
// Append the CRC32C bytes in little endian byte order to the end of the buffer:
bufferData[bufferSize] = (uint8_t) (workingCRC & 0x000000FF);
bufferData[bufferSize + 1] = (uint8_t) ((workingCRC & 0x0000FF00) >> 8);
bufferData[bufferSize + 2] = (uint8_t) ((workingCRC & 0x00FF0000) >> 16);
bufferData[bufferSize + 4] = (uint8_t) ((workingCRC & 0xFF000000) >> 24);
// Append the CRC32C bytes in little endian byte order to the end of the buffer:
bufferData[bufferSize] = (uint8_t)(workingCRC & 0x000000FF);
bufferData[bufferSize + 1] = (uint8_t)((workingCRC & 0x0000FF00) >> 8);
bufferData[bufferSize + 2] = (uint8_t)((workingCRC & 0x00FF0000) >> 16);
bufferData[bufferSize + 4] = (uint8_t)((workingCRC & 0xFF000000) >> 24);
return bufferSize + 4;
}
114 changes: 82 additions & 32 deletions Firmware/Chameleon-Mini/Application/CryptoCMAC.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ static void getCMACSubK1(const uint8_t *bufferL, uint8_t blockSize, uint8_t poly
RotateArrayLeft(bufferL, bufferOut, blockSize);
if ((bufferL[0] & 0x80) != 0) {
for (int kidx = 0; kidx < blockSize; kidx++) {
bufferOut[kidx] = (uint8_t) (bufferOut[kidx] ^ _cmac_RB[kidx]);
}
bufferOut[kidx] = (uint8_t)(bufferOut[kidx] ^ _cmac_RB[kidx]);
}
}
}

Expand All @@ -56,8 +56,8 @@ static void getCMACSubK2(const uint8_t *bufferK1, uint8_t blockSize, uint8_t pol
RotateArrayLeft(bufferK1, bufferOut, blockSize);
if ((bufferK1[0] & 0x80) != 0) {
for (int kidx = 0; kidx < blockSize; kidx++) {
bufferOut[kidx] = (uint8_t) (bufferOut[kidx] ^ _cmac_RB[kidx]);
}
bufferOut[kidx] = (uint8_t)(bufferOut[kidx] ^ _cmac_RB[kidx]);
}
}
}

Expand All @@ -66,32 +66,32 @@ static bool appendBufferCMACSubroutine(uint8_t cryptoType, const uint8_t *keyDat
uint16_t newBlockSize = bufferSize;
if (bufferSize == 0) {
memset(bufferOut, 0x00, blockSize);
bufferOut[0] = (uint8_t) 0x80;
newBlockSize = blockSize;
bufferOut[0] = (uint8_t) 0x80;
newBlockSize = blockSize;
} else if ((bufferSize % blockSize) != 0) {
newBlockSize = bufferSize - (bufferSize % blockSize) + blockSize;
newBlockSize = bufferSize - (bufferSize % blockSize) + blockSize;
bufferOut[bufferSize] = (uint8_t) 0x80;
}
if (bufferSize != 0 && (bufferSize % blockSize) == 0) {
// Complete block (use K1):
for (int i = bufferSize - blockSize; i < bufferSize; i++) {
for (int i = bufferSize - blockSize; i < bufferSize; i++) {
bufferOut[i] ^= bufferK1[i - bufferSize + blockSize];
}
}
} else {
// Incomplete block (use K2):
for (int i = bufferSize - blockSize; i < bufferSize; i++) {
for (int i = bufferSize - blockSize; i < bufferSize; i++) {
bufferOut[i] ^= bufferK2[i - bufferSize + blockSize];
}
}
}
switch (cryptoType) {
case CRYPTO_TYPE_3K3DES:
Encrypt3DESBuffer(newBlockSize, bufferOut, bufferOut + bufferSize, keyData, bufferIV);
break;
case CRYPTO_TYPE_AES128:
CryptoAESEncryptBuffer(newBlockSize, bufferOut, bufferOut + bufferSize, keyData, bufferIV);
break;
Encrypt3DESBuffer(newBlockSize, bufferOut, &bufferOut[bufferSize], keyData, bufferIV);
break;
case CRYPTO_TYPE_AES128:
CryptoAESEncryptBuffer(newBlockSize, bufferOut, &bufferOut[bufferSize], keyData, bufferIV);
break;
default:
return false;
return false;
}
memmove(&bufferOut[0], &bufferOut[newBlockSize], newBlockSize);
memcpy(_cmac_final, &bufferOut[newBlockSize - blockSize], blockSize);
Expand All @@ -103,40 +103,90 @@ bool appendBufferCMAC(uint8_t cryptoType, const uint8_t *keyData, uint8_t *buffe
uint8_t blockSize, rb;
uint8_t *nistL = _cmac_K2;
switch (cryptoType) {
case CRYPTO_TYPE_3K3DES:
case CRYPTO_TYPE_3K3DES:
blockSize = CRYPTO_3KTDEA_BLOCK_SIZE;
rb = CRYPTO_CMAC_RB64;
memset(_cmac_zeros, 0x00, blockSize);
Encrypt3DESBuffer(blockSize, _cmac_zeros, nistL, _cmac_zeros, keyData);
break;
case CRYPTO_TYPE_AES128:
rb = CRYPTO_CMAC_RB64;
memset(_cmac_zeros, 0x00, blockSize);
Encrypt3DESBuffer(blockSize, _cmac_zeros, nistL, _cmac_zeros, keyData);
break;
case CRYPTO_TYPE_AES128:
blockSize = CRYPTO_AES_BLOCK_SIZE;
rb = CRYPTO_CMAC_RB128;
memset(_cmac_zeros, 0x00, blockSize);
CryptoAESEncryptBuffer(blockSize, _cmac_zeros, nistL, _cmac_zeros, keyData);
break;
rb = CRYPTO_CMAC_RB128;
memset(_cmac_zeros, 0x00, blockSize);
CryptoAESEncryptBuffer(blockSize, _cmac_zeros, nistL, _cmac_zeros, keyData);
break;
default:
return false;
return false;
}
getCMACSubK1(nistL, blockSize, rb, _cmac_K1);
getCMACSubK2(_cmac_K1, blockSize, rb, _cmac_K2);
if (IV == NULL) {
IV = _cmac_zeros;
memset(IV, 0x00, blockSize);
return appendBufferCMACSubroutine(cryptoType, keyData, _cmac_K1, _cmac_K2, IV, blockSize, bufferData, bufferSize);
memset(IV, 0x00, blockSize);
return appendBufferCMACSubroutine(cryptoType, keyData, _cmac_K1, _cmac_K2, IV, blockSize, bufferData, bufferSize);
} else {
return appendBufferCMACSubroutine(cryptoType, keyData, _cmac_K1, _cmac_K2, IV, blockSize, bufferData, bufferSize);
}
}

bool checkBufferCMAC(uint8_t *bufferData, uint16_t bufferSize, uint16_t checksumSize) {
if (checksumSize > bufferSize) {
return false;
}
if (checksumSize == CRYPTO_3KTDEA_BLOCK_SIZE) {
appendBufferCMAC(CRYPTO_TYPE_3K3DES, SessionKey, &bufferData[bufferSize], bufferSize - checksumSize, SessionIV);
memcpy(_cmac_zeros, &bufferData[bufferSize], checksumSize);
if (memcmp(_cmac_zeros, &bufferData[bufferSize - checksumSize], checksumSize)) {
return false;
}
return true;
} else if (checksumSize == CRYPTO_AES_BLOCK_SIZE) {
appendBufferCMAC(CRYPTO_TYPE_AES128, SessionKey, &bufferData[bufferSize], bufferSize - checksumSize, SessionIV);
memcpy(_cmac_zeros, &bufferData[bufferSize], checksumSize);
if (memcmp(_cmac_zeros, &bufferData[bufferSize - checksumSize], checksumSize)) {
return false;
}
return true;
}
return false;
}

uint16_t appendBufferMAC(const uint8_t *keyData, uint8_t *bufferData, uint16_t bufferSize) {
memcpy(&_mac_key24[2 * CRYPTO_DES_BLOCK_SIZE], keyData, CRYPTO_DES_BLOCK_SIZE);
memcpy(&_mac_key24[CRYPTO_DES_BLOCK_SIZE], keyData, CRYPTO_DES_BLOCK_SIZE);
memcpy(&_mac_key24[0], keyData, CRYPTO_DES_BLOCK_SIZE);
memset(&_cmac_zeros[0], 0x00, CRYPTO_DES_BLOCK_SIZE);
Encrypt3DESBuffer(bufferSize, bufferData, &bufferData[3 * CRYPTO_DES_BLOCK_SIZE], _cmac_zeros, keyData);
uint16_t paddedBufferSize = bufferSize;
if ((bufferSize % CRYPTO_DES_BLOCK_SIZE) != 0) {
paddedBufferSize = bufferSize + CRYPTO_DES_BLOCK_SIZE - (bufferSize % CRYPTO_DES_BLOCK_SIZE);
memset(&bufferData[bufferSize], 0x00, paddedBufferSize - bufferSize);
}
Encrypt3DESBuffer(paddedBufferSize, bufferData, &bufferData[paddedBufferSize], _cmac_zeros, keyData);
// Copy the 4-byte MAC from the ciphertext (end of the bufferData array):
memcpy(&_cmac_zeros[0], &bufferData[3 * CRYPTO_DES_BLOCK_SIZE + bufferSize - CRYPTO_DES_BLOCK_SIZE], 4);
memcpy(&_cmac_zeros[0], &bufferData[paddedBufferSize - CRYPTO_DES_BLOCK_SIZE], 4);
memcpy(&bufferData[bufferSize], &_cmac_zeros[0], 4);
return bufferSize + 4;
}

bool checkBufferMAC(uint8_t *bufferData, uint16_t bufferSize, uint16_t checksumSize) {
if (checksumSize > bufferSize) {
return false;
}
const uint8_t *keyData = SessionKey;
memcpy(&_mac_key24[2 * CRYPTO_DES_BLOCK_SIZE], keyData, CRYPTO_DES_BLOCK_SIZE);
memcpy(&_mac_key24[CRYPTO_DES_BLOCK_SIZE], keyData, CRYPTO_DES_BLOCK_SIZE);
memcpy(&_mac_key24[0], keyData, CRYPTO_DES_BLOCK_SIZE);
memset(&_cmac_zeros[0], 0x00, CRYPTO_DES_BLOCK_SIZE);
uint16_t paddedBufferSize = bufferSize;
if ((bufferSize % CRYPTO_DES_BLOCK_SIZE) != 0) {
paddedBufferSize = bufferSize + CRYPTO_DES_BLOCK_SIZE - (bufferSize % CRYPTO_DES_BLOCK_SIZE);
memset(&bufferData[bufferSize], 0x00, paddedBufferSize - bufferSize);
}
Encrypt3DESBuffer(paddedBufferSize, bufferData, &bufferData[paddedBufferSize], _cmac_zeros, keyData);
// Copy the 4-byte MAC from the ciphertext (end of the bufferData array):
memcpy(&_cmac_zeros[0], &bufferData[paddedBufferSize - CRYPTO_DES_BLOCK_SIZE], 4);
if (memcmp(&bufferData[bufferSize - checksumSize], &_cmac_zeros[0], 4)) {
return false;
}
return true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -226,19 +226,19 @@ CommandStatusIdType CommandDESFireSetCommMode(char *OutParam, const char *InPara
if (!strcasecmp_P(valueStr, PSTR("Plaintext"))) {
DesfireCommMode = DESFIRE_COMMS_PLAINTEXT;
DesfireCommandState.ActiveCommMode = DesfireCommMode;
return COMMAND_INFO_OK;
return COMMAND_INFO_OK;
} else if (!strcasecmp_P(valueStr, PSTR("Plaintext:MAC"))) {
DesfireCommMode = DESFIRE_COMMS_PLAINTEXT_MAC;
DesfireCommandState.ActiveCommMode = DesfireCommMode;
return COMMAND_INFO_OK;
} else if (!strcasecmp_P(valueStr, PSTR("Enciphered:3K3DES"))) {
DesfireCommMode = DESFIRE_COMMS_CIPHERTEXT_DES;
DesfireCommandState.ActiveCommMode = DesfireCommMode;
return COMMAND_INFO_OK;
return COMMAND_INFO_OK;
} else if (!strcasecmp_P(valueStr, PSTR("Enciphered:AES128"))) {
DesfireCommMode = DESFIRE_COMMS_CIPHERTEXT_AES128;
DesfireCommandState.ActiveCommMode = DesfireCommMode;
return COMMAND_INFO_OK;
return COMMAND_INFO_OK;
}
snprintf_P(OutParam, TERMINAL_BUFFER_SIZE, PSTR("Options are: Plaintext|Plaintext:MAC|Enciphered:3K3DES|Enciphered:AES128"));
return COMMAND_ERR_INVALID_USAGE_ID;
Expand Down
16 changes: 8 additions & 8 deletions Firmware/Chameleon-Mini/Application/DESFire/DESFirePICCControl.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings) {
TransferState.WriteData.Encryption.Func = &CryptoAESEncrypt_CBCSend;
memset(SessionIV, 0, sizeof(SessionIVByteSize));
SessionIVByteSize = CRYPTO_AES_KEY_SIZE;
default:
default:
return STATUS_PARAMETER_ERROR;
}
return STATUS_OPERATION_OK;
Expand All @@ -160,12 +160,12 @@ uint8_t ReadDataFilterSetup(uint8_t CommSettings) {
uint8_t WriteDataFilterSetup(uint8_t CommSettings) {
switch (CommSettings) {
case DESFIRE_COMMS_PLAINTEXT:
TransferState.Checksums.UpdateFunc = NULL;
TransferState.Checksums.FinalFunc = NULL;
TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = NULL;
TransferState.Checksums.UpdateFunc = NULL;
TransferState.Checksums.FinalFunc = NULL;
TransferState.Checksums.MACData.CryptoChecksumFunc.TDEAFunc = NULL;
memset(SessionIV, 0, sizeof(SessionIVByteSize));
SessionIVByteSize = 0;
break;
SessionIVByteSize = 0;
break;
case DESFIRE_COMMS_PLAINTEXT_MAC:
TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateMACTDEA;
TransferState.Checksums.FinalFunc = &TransferChecksumFinalMACTDEA;
Expand All @@ -181,8 +181,8 @@ uint8_t WriteDataFilterSetup(uint8_t CommSettings) {
memset(SessionIV, 0, sizeof(SessionIVByteSize));
SessionIVByteSize = CRYPTO_AES_KEY_SIZE;
break;
case DESFIRE_COMMS_CIPHERTEXT_AES128:
// A.k.a., CommMode=FULL from NXP application note AN12343:
case DESFIRE_COMMS_CIPHERTEXT_AES128:
// A.k.a., CommMode=FULL from NXP application note AN12343:
TransferState.Checksums.UpdateFunc = &TransferChecksumUpdateCMAC;
TransferState.Checksums.FinalFunc = &TransferChecksumFinalCMAC;
TransferState.Checksums.MACData.CRCA = ISO14443A_CRCA_INIT; // TODO ???
Expand Down
Loading

0 comments on commit a24fbe8

Please sign in to comment.