phStatus_t phalMfc_Sw_Authenticate( phalMfc_Sw_DataParams_t * pDataParams, uint8_t bBlockNo, uint8_t bKeyType, uint16_t wKeyNo, uint16_t wKeyVersion, uint8_t * pUid, uint8_t bUidLength ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aKey[PHHAL_HW_MFC_KEY_LENGTH * 2]; uint8_t * PH_MEMLOC_REM pKey; uint16_t PH_MEMLOC_REM bKeystoreKeyType; /* check if software key store is available. */ if (pDataParams->pKeyStoreDataParams == NULL) { /* There is no software keystore available. */ return phpalMifare_MfcAuthenticateKeyNo( pDataParams->pPalMifareDataParams, bBlockNo, bKeyType, wKeyNo, wKeyVersion, &pUid[bUidLength - 4]); } else { /* Software key store found. */ /* Bail out if we haven't got a keystore */ if (pDataParams->pKeyStoreDataParams == NULL) { return PH_ADD_COMPCODE(PH_ERR_KEY, PH_COMP_HAL); } /* retrieve KeyA & KeyB from keystore */ PH_CHECK_SUCCESS_FCT(statusTmp, phKeyStore_GetKey( pDataParams->pKeyStoreDataParams, wKeyNo, wKeyVersion, sizeof(aKey), aKey, &bKeystoreKeyType)); /* check key type */ if (bKeystoreKeyType != PH_KEYSTORE_KEY_TYPE_MIFARE) { return PH_ADD_COMPCODE(PH_ERR_INVALID_PARAMETER, PH_COMP_HAL); } /* Evaluate which key to use */ if ((bKeyType & 0x7F) == PHHAL_HW_MFC_KEYA) { /* Use KeyA */ pKey = aKey; } else if ((bKeyType & 0x7F) == PHHAL_HW_MFC_KEYB) { /* Use KeyB */ pKey = &aKey[PHHAL_HW_MFC_KEY_LENGTH]; } else { return PH_ADD_COMPCODE(PH_ERR_INVALID_PARAMETER, PH_COMP_HAL); } return phpalMifare_MfcAuthenticate( pDataParams->pPalMifareDataParams, bBlockNo, bKeyType, pKey, &pUid[bUidLength - 4]); } }
phStatus_t phalVca_Sw_SelectVc( phalVca_Sw_DataParams_t * pDataParams, uint16_t wValidIidIndex, uint16_t wKeyNumber, uint16_t wKeyVersion ) { phStatus_t PH_MEMLOC_REM statusTmp, status; uint8_t PH_MEMLOC_REM aTxBuffer[PHAL_VCA_IID_SIZE + 1]; uint8_t * PH_MEMLOC_REM pResponse; uint16_t PH_MEMLOC_REM wRxLength; uint8_t PH_MEMLOC_REM aKey[PH_CRYPTOSYM_AES128_KEY_SIZE]; uint16_t PH_MEMLOC_REM wKeyType; uint8_t PH_MEMLOC_REM bMacLength; /* Prepare command header */ aTxBuffer[0] = PHAL_VCA_CMD_SVC; aTxBuffer[1] = PHAL_VCA_CMD_SVC; /* Resolve Iid index */ status = phalVca_Sw_Int_ResolveValidIndex( pDataParams, wValidIidIndex, &wValidIidIndex); /* for the case of an overflow we generate random data */ /* Prepare MAC data */ if ((status & PH_ERR_MASK) == PH_ERR_INVALID_PARAMETER) { wValidIidIndex = 0; PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoRng_Rnd(pDataParams->pCryptoRngDataParams, PHAL_VCA_IID_SIZE-1, &aTxBuffer[2])); } else { PH_CHECK_SUCCESS(status); memcpy(&aTxBuffer[2], &pDataParams->pCardTable[wValidIidIndex].pCardData[1], PHAL_VCA_IID_SIZE-1); /* PRQA S 3200 */ } /* Get MAC Key */ PH_CHECK_SUCCESS_FCT(statusTmp, phKeyStore_GetKey( pDataParams->pKeyStoreDataParams, wKeyNumber, wKeyVersion, sizeof(aKey), aKey, &wKeyType)); /* Check key type */ if (wKeyType != PH_CRYPTOSYM_KEY_TYPE_AES128) { return PH_ADD_COMPCODE(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_VCA); } /* Load key */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_LoadKeyDirect( pDataParams->pCryptoDataParams, aKey, PH_CRYPTOSYM_KEY_TYPE_AES128)); /* Calculate MAC */ /* CMAC with Padding */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_CalculateMac( pDataParams->pCryptoDataParams, PH_CRYPTOSYM_MAC_MODE_CMAC, &aTxBuffer[1], PHAL_VCA_IID_SIZE, &aTxBuffer[1], &bMacLength)); /* Truncate MAC */ phalVca_Sw_Int_TruncateMac(&aTxBuffer[1], &aTxBuffer[1]); /* command exchange */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_DEFAULT, aTxBuffer, 1 + PHAL_VCA_TRUNCATED_MAC_SIZE, &pResponse, &wRxLength)); /* check response */ PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_ComputeErrorResponse(wRxLength, pResponse[0])); /* check response length */ if (wRxLength != 1 /* STATUS */) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_VCA); } return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_VCA); }
phStatus_t phalVca_Sw_Cmd_VerifyProximityCheck( phalVca_Sw_DataParams_t * pDataParams, uint8_t* pRndRC, uint8_t bPps1, uint16_t wKeyNumber, uint16_t wKeyVersion ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t * PH_MEMLOC_REM pResponse; uint16_t PH_MEMLOC_REM wRxLength; uint8_t PH_MEMLOC_REM aTmpBuf[2 + PHAL_VCA_PC_RND_LEN * 2]; uint8_t PH_MEMLOC_REM aKey[PH_CRYPTOSYM_AES128_KEY_SIZE]; uint16_t PH_MEMLOC_REM wKeyType; uint8_t PH_MEMLOC_REM bMac[PH_CRYPTOSYM_AES_BLOCK_SIZE]; uint8_t PH_MEMLOC_REM bMacLength; /* prepare "Verify Proximity Check" command */ aTmpBuf[0] = PHAL_VCA_CMD_VPC; aTmpBuf[1] = bPps1; memcpy(&aTmpBuf[2], pRndRC, PHAL_VCA_PC_RND_LEN * 2); /* PRQA S 3200 */ /* Get Proximity Check Key */ PH_CHECK_SUCCESS_FCT(statusTmp, phKeyStore_GetKey( pDataParams->pKeyStoreDataParams, wKeyNumber, wKeyVersion, sizeof(aKey), aKey, &wKeyType)); /* Check key type */ if (wKeyType != PH_CRYPTOSYM_KEY_TYPE_AES128) { return PH_ADD_COMPCODE(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_VCA); } /* Load Proximity Check Key */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_LoadKeyDirect( pDataParams->pCryptoDataParams, aKey, PH_CRYPTOSYM_KEY_TYPE_AES128)); /* CMAC with Padding */ /* mac calculation: CMAC(CMD || PPS1 || (RndRC1 || ... || RndRC14)) */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_CalculateMac( pDataParams->pCryptoDataParams, PH_CRYPTOSYM_MAC_MODE_CMAC, aTmpBuf, (2 + PHAL_VCA_PC_RND_LEN * 2), bMac, &bMacLength)); /* perform MAC truncation */ phalVca_Sw_Int_TruncateMac(bMac, bMac); /* buffer the command code */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, aTmpBuf, 1, &pResponse, &wRxLength)); /* append the MAC and exchange frame */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, bMac, PHAL_VCA_TRUNCATED_MAC_SIZE, &pResponse, &wRxLength)); /* check response */ PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_ComputeErrorResponse(wRxLength, pResponse[0])); /* check response length */ if (wRxLength != 1 /* Status */ + 8 /* MAC */) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_VCA); } /* Calculate MAC */ aTmpBuf[0] = pResponse[0]; PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_CalculateMac( pDataParams->pCryptoDataParams, PH_CRYPTOSYM_MAC_MODE_CMAC, aTmpBuf, (2 + PHAL_VCA_PC_RND_LEN * 2), bMac, &bMacLength)); /* perform MAC truncation */ phalVca_Sw_Int_TruncateMac(bMac, bMac); /* Compare MAC */ if (memcmp(bMac, &pResponse[1], PHAL_VCA_TRUNCATED_MAC_SIZE) != 0) { return PH_ADD_COMPCODE(PHAL_VCA_ERR_AUTH, PH_COMP_AL_VCA); } return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_VCA); }
phStatus_t phalVca_Sw_VcSupportLast( phalVca_Sw_DataParams_t * pDataParams, uint8_t * pIid, uint8_t bLenCap, uint8_t * pPcdCapabilities, uint16_t wKeyEncNumber, uint16_t wKeyEncVersion, uint16_t wKeyMacNumber, uint16_t wKeyMacVersion ) { phStatus_t PH_MEMLOC_REM statusTmp; uint8_t PH_MEMLOC_REM aTmpBuf[PH_CRYPTOSYM_AES_BLOCK_SIZE * 2]; uint8_t PH_MEMLOC_REM aTxBuffer[1]; uint8_t * PH_MEMLOC_REM pResponse; uint16_t PH_MEMLOC_REM wRxLength; uint8_t PH_MEMLOC_REM aKey[PH_CRYPTOSYM_AES128_KEY_SIZE]; uint16_t PH_MEMLOC_REM wKeyType; uint8_t PH_MEMLOC_REM bMac[PH_CRYPTOSYM_AES_BLOCK_SIZE]; uint8_t PH_MEMLOC_REM bMacLength; phalVca_Sw_CardTableEntry_t PH_MEMLOC_REM pDummyCardData; phalVca_Sw_CardTableEntry_t * PH_MEMLOC_REM pCardDataStorage; uint16_t PH_MEMLOC_REM wIndex; /* Build the command frame */ aTxBuffer[0] = PHAL_VCA_CMD_VCSL; /* Copy PCD Caps */ memset(aTmpBuf, 0x00, 4); /* PRQA S 3200 */ if (bLenCap) { if (bLenCap > 3) { bLenCap = 3; } aTmpBuf[0] = bLenCap; memcpy(&aTmpBuf[1], pPcdCapabilities, bLenCap); /* PRQA S 3200 */ } /* Check available space in key duos list */ if (pDataParams->wCurrentIidTablePos >= pDataParams->wNumIidTableEntries) { return PH_ADD_COMPCODE(PH_ERR_BUFFER_OVERFLOW, PH_COMP_AL_VCA); } /* Check available space in card table */ if (pDataParams->wCurrentCardTablePos >= pDataParams->wNumCardTableEntries) { return PH_ADD_COMPCODE(PH_ERR_BUFFER_OVERFLOW, PH_COMP_AL_VCA); } /* Add keys and iids to the iid table list */ pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wIidIndex = pDataParams->wCurrentIidIndex; pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wKeyEncNumber = wKeyEncNumber; pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wKeyEncVersion = wKeyEncVersion; pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wKeyMacNumber = wKeyMacNumber; pDataParams->pIidTable[pDataParams->wCurrentIidTablePos].wKeyMacVersion = wKeyMacVersion; pDataParams->wCurrentIidTablePos++; pDataParams->wCurrentIidIndex++; /* Generate RNDQ */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoRng_Rnd(pDataParams->pCryptoRngDataParams, 12, &aTmpBuf[PHAL_VCA_POS_RNDQ])); /* buffer command frame */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_FIRST, aTxBuffer, 1, &pResponse, &wRxLength)); /* buffer installation identifier */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, pIid, PHAL_VCA_IID_SIZE, &pResponse, &wRxLength)); /* buffer RNDQ identifier */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_CONT, &aTmpBuf[PHAL_VCA_POS_RNDQ], 12, &pResponse, &wRxLength)); /* append PCDCaps and transmit the command */ PH_CHECK_SUCCESS_FCT(statusTmp, phpalMifare_ExchangeL4( pDataParams->pPalMifareDataParams, PH_EXCHANGE_BUFFER_LAST, &aTmpBuf[0], 1+ bLenCap, &pResponse, &wRxLength)); PH_CHECK_SUCCESS_FCT(statusTmp, phalVca_Int_ComputeErrorResponse(wRxLength, pResponse[0])); /* check response length */ if (wRxLength != 1 /*Status */ + 16 /* Cryptogram */ + 8 /*MAC */) { return PH_ADD_COMPCODE(PH_ERR_PROTOCOL_ERROR, PH_COMP_AL_VCA); } /* Prepare MAC data */ aTmpBuf[0] = pResponse[0]; memcpy(&aTmpBuf[PHAL_VCA_POS_PAYLOAD], &pResponse[1], 16); /* PRQA S 3200 */ /* Iterate over all available key pairs and try to find a match */ for (wIndex = pDataParams->wCurrentIidTablePos; wIndex > 0; --wIndex) { /* Retrieve MAC key */ PH_CHECK_SUCCESS_FCT(statusTmp, phKeyStore_GetKey( pDataParams->pKeyStoreDataParams, pDataParams->pIidTable[(wIndex-1)].wKeyMacNumber, pDataParams->pIidTable[(wIndex-1)].wKeyMacVersion, sizeof(aKey), aKey, &wKeyType)); /* Check key type */ if (wKeyType != PH_CRYPTOSYM_KEY_TYPE_AES128) { return PH_ADD_COMPCODE(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_VCA); } /* Load the key */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_LoadKeyDirect( pDataParams->pCryptoDataParams, aKey, PH_CRYPTOSYM_KEY_TYPE_AES128)); /* Set the correct MAC calculation mode */ /* CMAC with Padding */ /* Calculate the MAC */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_CalculateMac( pDataParams->pCryptoDataParams, PH_CRYPTOSYM_MAC_MODE_CMAC, aTmpBuf, 32, bMac, &bMacLength)); /* Truncate the MAC */ phalVca_Sw_Int_TruncateMac(bMac, bMac); /* Compare the MACs */ if (memcmp(&pResponse[17], bMac, PHAL_VCA_TRUNCATED_MAC_SIZE) == 0) { pCardDataStorage = &pDataParams->pCardTable[pDataParams->wCurrentCardTablePos]; } else { pCardDataStorage = &pDummyCardData; } /* In any case, we need to decrypt */ pCardDataStorage->bValid = PHAL_VCA_CARD_TABLE_ENTRY_VALID; /* Retrieve ENC key */ PH_CHECK_SUCCESS_FCT(statusTmp, phKeyStore_GetKey( pDataParams->pKeyStoreDataParams, pDataParams->pIidTable[(wIndex-1)].wKeyEncNumber, pDataParams->pIidTable[(wIndex-1)].wKeyEncVersion, sizeof(aKey), aKey, &wKeyType)); /* Check key type */ if (wKeyType != PH_CRYPTOSYM_KEY_TYPE_AES128) { return PH_ADD_COMPCODE(PH_ERR_INVALID_PARAMETER, PH_COMP_AL_VCA); } /* Load the key */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_LoadKeyDirect( pDataParams->pCryptoDataParams, aKey, PH_CRYPTOSYM_KEY_TYPE_AES128)); /* Load first IV*/ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_LoadIv( pDataParams->pCryptoDataParams, phalVca_Sw_FirstIv, PH_CRYPTOSYM_AES_BLOCK_SIZE)); /* Perform decryption */ PH_CHECK_SUCCESS_FCT(statusTmp, phCryptoSym_Decrypt( pDataParams->pCryptoDataParams, PH_CRYPTOSYM_CIPHER_MODE_CBC, &pResponse[1], PHAL_VCA_IID_SIZE, pCardDataStorage->pCardData )); /* Copy the found IID Index */ pCardDataStorage->wIidIndex = pDataParams->pIidTable[(wIndex-1)].wIidIndex; } pDataParams->wCurrentIidTablePos = 0; ++pDataParams->wCurrentCardTablePos; return PH_ADD_COMPCODE(PH_ERR_SUCCESS, PH_COMP_AL_VCA); }