Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions src/nfc/crypto/aes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@

#include <M5Utility.hpp>
#include <cstring>
#include <mbedtls/version.h>

#if MBEDTLS_VERSION_MAJOR >= 4
#include <psa/crypto.h>
#include <vector>
#else
#include <mbedtls/aes.h>
#endif

namespace m5 {
namespace nfc {
Expand All @@ -29,13 +36,55 @@ void left_shift_128(const uint8_t in[16], uint8_t out[16])
}
}

#if MBEDTLS_VERSION_MAJOR >= 4
bool psa_import_aes_key(psa_key_id_t& key_id, const uint8_t key[16], const psa_algorithm_t alg,
const psa_key_usage_t usage)
{
if (psa_crypto_init() != PSA_SUCCESS) {
M5_LIB_LOGE("PSA crypto init failed");
return false;
}

psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
psa_set_key_bits(&attributes, 128);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_usage_flags(&attributes, usage);

const psa_status_t status = psa_import_key(&attributes, key, 16, &key_id);
psa_reset_key_attributes(&attributes);
if (status != PSA_SUCCESS) {
M5_LIB_LOGE("PSA AES import failed: %d", static_cast<int>(status));
return false;
}
return true;
}
#endif

} // namespace

bool aes_ecb_encrypt(uint8_t out[16], const uint8_t key[16], const uint8_t in[16])
{
if (!out || !key || !in) {
return false;
}
#if MBEDTLS_VERSION_MAJOR >= 4
psa_key_id_t key_id = PSA_KEY_ID_NULL;
if (!psa_import_aes_key(key_id, key, PSA_ALG_ECB_NO_PADDING, PSA_KEY_USAGE_ENCRYPT)) {
std::memset(out, 0, 16);
return false;
}

size_t out_len = 0;
const psa_status_t status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, in, 16, out, 16, &out_len);
psa_destroy_key(key_id);
if (status != PSA_SUCCESS || out_len != 16) {
M5_LIB_LOGE("PSA AES ECB encrypt failed: %d", static_cast<int>(status));
std::memset(out, 0, 16);
return false;
}
return true;
#else
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
if (mbedtls_aes_setkey_enc(&aes, key, 128) != 0) {
Expand All @@ -52,6 +101,7 @@ bool aes_ecb_encrypt(uint8_t out[16], const uint8_t key[16], const uint8_t in[16
}
mbedtls_aes_free(&aes);
return true;
#endif
}

bool aes_cbc_crypt(uint8_t* out, const uint8_t key[16], const uint8_t iv_in[16], const uint8_t* in, const size_t len,
Expand All @@ -60,6 +110,50 @@ bool aes_cbc_crypt(uint8_t* out, const uint8_t key[16], const uint8_t iv_in[16],
if (!out || !key || !iv_in || (!in && len)) {
return false;
}
if (len % 16 != 0) {
return false;
}
if (len == 0) {
return true;
}
#if MBEDTLS_VERSION_MAJOR >= 4
psa_key_id_t key_id = PSA_KEY_ID_NULL;
if (!psa_import_aes_key(key_id, key, PSA_ALG_CBC_NO_PADDING,
encrypt ? PSA_KEY_USAGE_ENCRYPT : PSA_KEY_USAGE_DECRYPT)) {
std::memset(out, 0, len);
return false;
}

std::vector<uint8_t> tmp(len + PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE);

psa_cipher_operation_t operation = psa_cipher_operation_init();
psa_status_t status = encrypt ? psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CBC_NO_PADDING)
: psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CBC_NO_PADDING);
if (status == PSA_SUCCESS) {
status = psa_cipher_set_iv(&operation, iv_in, 16);
}

size_t update_len = 0;
if (status == PSA_SUCCESS) {
status = psa_cipher_update(&operation, in, len, tmp.data(), len, &update_len);
}

size_t finish_len = 0;
if (status == PSA_SUCCESS) {
status = psa_cipher_finish(&operation, tmp.data() + update_len, tmp.size() - update_len, &finish_len);
}

psa_cipher_abort(&operation);
psa_destroy_key(key_id);

if (status != PSA_SUCCESS || update_len + finish_len != len) {
M5_LIB_LOGE("PSA AES CBC crypt failed: %d", static_cast<int>(status));
std::memset(out, 0, len);
return false;
}
std::memcpy(out, tmp.data(), len);
return true;
#else
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
if (encrypt) {
Expand Down Expand Up @@ -87,6 +181,7 @@ bool aes_cbc_crypt(uint8_t* out, const uint8_t key[16], const uint8_t iv_in[16],
}
mbedtls_aes_free(&aes);
return true;
#endif
}

bool cmac_subkeys(uint8_t k1[16], uint8_t k2[16], const uint8_t key[16])
Expand Down
37 changes: 3 additions & 34 deletions src/nfc/isoDEP/desfire_file_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include "nfc/apdu/apdu.hpp"
#include <cassert>
#include <cstring>
#include <mbedtls/aes.h>
#include <esp_random.h>
#include <M5Utility.hpp>
#include <algorithm>
Expand Down Expand Up @@ -1362,22 +1361,12 @@ bool DESFireFileSystem::authenticateAES(const uint8_t key_no, const uint8_t key[
m5::nfc::crypto::secure_zero(ek_AB, sizeof(ek_AB));
};
{
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
if (mbedtls_aes_setkey_dec(&aes, key, 128) != 0) {
M5_LIB_LOGE("AuthAES setkey_dec failed");
mbedtls_aes_free(&aes);
wipe();
return false;
}
uint8_t iv[16]{};
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, 16, iv, ek_rndB, rndB) != 0) {
if (!aes_cbc_crypt(rndB, key, iv, ek_rndB, 16, false)) {
M5_LIB_LOGE("AuthAES crypt_cbc failed");
mbedtls_aes_free(&aes);
wipe();
return false;
}
mbedtls_aes_free(&aes);
}

for (int i = 0; i < 15; ++i) {
Expand All @@ -1393,23 +1382,13 @@ bool DESFireFileSystem::authenticateAES(const uint8_t key_no, const uint8_t key[
std::memcpy(plain_AB + 16, rndB_rot, 16);

{
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
if (mbedtls_aes_setkey_enc(&aes, key, 128) != 0) {
M5_LIB_LOGE("AuthAES setkey_enc failed");
mbedtls_aes_free(&aes);
wipe();
return false;
}
uint8_t iv[16]{};
std::memcpy(iv, ek_rndB, 16);
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, sizeof(plain_AB), iv, plain_AB, ek_AB) != 0) {
if (!aes_cbc_crypt(ek_AB, key, iv, plain_AB, sizeof(plain_AB), true)) {
M5_LIB_LOGE("AuthAES crypt_cbc failed");
mbedtls_aes_free(&aes);
wipe();
return false;
}
mbedtls_aes_free(&aes);
}

auto cmd2 = make_native_wrap_command(0xAF, ek_AB, sizeof(ek_AB));
Expand All @@ -1427,23 +1406,13 @@ bool DESFireFileSystem::authenticateAES(const uint8_t key_no, const uint8_t key[

uint8_t rndA_rot_from_card[16]{};
{
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
if (mbedtls_aes_setkey_dec(&aes, key, 128) != 0) {
M5_LIB_LOGE("AuthAES setkey_dec failed");
mbedtls_aes_free(&aes);
wipe();
return false;
}
uint8_t iv[16]{};
std::memcpy(iv, ek_AB + 16, 16);
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, 16, iv, rx.data(), rndA_rot_from_card) != 0) {
if (!aes_cbc_crypt(rndA_rot_from_card, key, iv, rx.data(), 16, false)) {
M5_LIB_LOGE("AuthAES crypt_cbc failed");
mbedtls_aes_free(&aes);
wipe();
return false;
}
mbedtls_aes_free(&aes);
}

uint8_t rndA_rot[16]{};
Expand Down
73 changes: 8 additions & 65 deletions src/nfc/layer/a/nfc_layer_a.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include <inttypes.h>
#include <M5Utility.hpp>
#include <algorithm>
#include <mbedtls/aes.h>
#include <esp_random.h>
#include <cstring>

Expand All @@ -30,6 +29,8 @@ using namespace m5::nfc::ndef;

namespace {

using m5::nfc::crypto::aes_cbc_crypt;

constexpr char dump_sector_header[] =
"Sec[Blk]:00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F [Access]\n"
"-----------------------------------------------------------------";
Expand Down Expand Up @@ -2247,21 +2248,11 @@ bool NFCLayerA::mifare_plus_authenticateAES(const uint16_t key_no, const mifare:
uint8_t rndB[16]{};
{
uint8_t iv[16]{};
mbedtls_aes_context aes{};
mbedtls_aes_init(&aes);
if (mbedtls_aes_setkey_dec(&aes, key.data(), 128) != 0) {
M5_LIB_LOGE("AuthAES setkey_dec failed");
mbedtls_aes_free(&aes);
m5::nfc::crypto::secure_zero(rndB, sizeof(rndB));
return false;
}
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, sizeof(rndB), iv, step1_payload, rndB) != 0) {
if (!aes_cbc_crypt(rndB, key.data(), iv, step1_payload, sizeof(rndB), false)) {
M5_LIB_LOGE("AuthAES crypt_cbc failed");
mbedtls_aes_free(&aes);
m5::nfc::crypto::secure_zero(rndB, sizeof(rndB));
return false;
}
mbedtls_aes_free(&aes);
}

uint8_t rndA[16]{};
Expand All @@ -2281,27 +2272,14 @@ bool NFCLayerA::mifare_plus_authenticateAES(const uint16_t key_no, const mifare:
cmd2[0] = 0x72;
{
uint8_t iv[16]{};
mbedtls_aes_context aes{};
mbedtls_aes_init(&aes);
if (mbedtls_aes_setkey_enc(&aes, key.data(), 128) != 0) {
M5_LIB_LOGE("AuthAES setkey_enc failed");
mbedtls_aes_free(&aes);
m5::nfc::crypto::secure_zero(rndA, sizeof(rndA));
m5::nfc::crypto::secure_zero(rndB, sizeof(rndB));
m5::nfc::crypto::secure_zero(rndB_rot, sizeof(rndB_rot));
m5::nfc::crypto::secure_zero(ab_plain, sizeof(ab_plain));
return false;
}
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, sizeof(ab_plain), iv, ab_plain, cmd2 + 1) != 0) {
if (!aes_cbc_crypt(cmd2 + 1, key.data(), iv, ab_plain, sizeof(ab_plain), true)) {
M5_LIB_LOGE("AuthAES crypt_cbc failed");
mbedtls_aes_free(&aes);
m5::nfc::crypto::secure_zero(rndA, sizeof(rndA));
m5::nfc::crypto::secure_zero(rndB, sizeof(rndB));
m5::nfc::crypto::secure_zero(rndB_rot, sizeof(rndB_rot));
m5::nfc::crypto::secure_zero(ab_plain, sizeof(ab_plain));
return false;
}
mbedtls_aes_free(&aes);
}

rx_len = sizeof(rx);
Expand Down Expand Up @@ -2341,29 +2319,15 @@ bool NFCLayerA::mifare_plus_authenticateAES(const uint16_t key_no, const mifare:
uint8_t ab_resp[32]{};
{
uint8_t iv[16]{};
mbedtls_aes_context aes{};
mbedtls_aes_init(&aes);
if (mbedtls_aes_setkey_dec(&aes, key.data(), 128) != 0) {
M5_LIB_LOGE("AuthAES setkey_dec failed");
mbedtls_aes_free(&aes);
m5::nfc::crypto::secure_zero(rndA, sizeof(rndA));
m5::nfc::crypto::secure_zero(rndB, sizeof(rndB));
m5::nfc::crypto::secure_zero(rndB_rot, sizeof(rndB_rot));
m5::nfc::crypto::secure_zero(ab_plain, sizeof(ab_plain));
m5::nfc::crypto::secure_zero(ab_resp, sizeof(ab_resp));
return false;
}
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, sizeof(ab_resp), iv, step2_payload, ab_resp) != 0) {
if (!aes_cbc_crypt(ab_resp, key.data(), iv, step2_payload, sizeof(ab_resp), false)) {
M5_LIB_LOGE("AuthAES crypt_cbc failed");
mbedtls_aes_free(&aes);
m5::nfc::crypto::secure_zero(rndA, sizeof(rndA));
m5::nfc::crypto::secure_zero(rndB, sizeof(rndB));
m5::nfc::crypto::secure_zero(rndB_rot, sizeof(rndB_rot));
m5::nfc::crypto::secure_zero(ab_plain, sizeof(ab_plain));
m5::nfc::crypto::secure_zero(ab_resp, sizeof(ab_resp));
return false;
}
mbedtls_aes_free(&aes);
}

uint8_t rndA_rot[16]{};
Expand Down Expand Up @@ -2397,31 +2361,19 @@ bool NFCLayerA::mifare_plus_authenticateAES(const uint16_t key_no, const mifare:

{
uint8_t iv[16]{};
mbedtls_aes_context aes{};
mbedtls_aes_init(&aes);
if (mbedtls_aes_setkey_enc(&aes, key.data(), 128) != 0) {
M5_LIB_LOGE("AuthAES setkey_enc failed");
mbedtls_aes_free(&aes);
m5::nfc::crypto::secure_zero(kenc, sizeof(kenc));
m5::nfc::crypto::secure_zero(kmac, sizeof(kmac));
return false;
}
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, sizeof(kenc), iv, kenc, kenc) != 0) {
if (!aes_cbc_crypt(kenc, key.data(), iv, kenc, sizeof(kenc), true)) {
M5_LIB_LOGE("AuthAES crypt_cbc failed");
mbedtls_aes_free(&aes);
m5::nfc::crypto::secure_zero(kenc, sizeof(kenc));
m5::nfc::crypto::secure_zero(kmac, sizeof(kmac));
return false;
}
memset(iv, 0, sizeof(iv));
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, sizeof(kmac), iv, kmac, kmac) != 0) {
if (!aes_cbc_crypt(kmac, key.data(), iv, kmac, sizeof(kmac), true)) {
M5_LIB_LOGE("AuthAES crypt_cbc failed");
mbedtls_aes_free(&aes);
m5::nfc::crypto::secure_zero(kenc, sizeof(kenc));
m5::nfc::crypto::secure_zero(kmac, sizeof(kmac));
return false;
}
mbedtls_aes_free(&aes);
}

_mfp_session.authenticated = true;
Expand Down Expand Up @@ -2562,13 +2514,6 @@ bool NFCLayerA::mifare_plus_read_plain_mac(const uint16_t block, const uint8_t c

std::vector<uint8_t> payload(rx + 1, rx + 1 + data_len);
if (!plain) {
mbedtls_aes_context aes{};
mbedtls_aes_init(&aes);
if (mbedtls_aes_setkey_dec(&aes, _mfp_session.kenc.data(), 128) != 0) {
M5_LIB_LOGE("AES setkey_dec failed");
mbedtls_aes_free(&aes);
return false;
}
for (uint8_t i = 0; i < count; ++i) {
uint8_t iv[16]{};
const uint8_t ctr = (uint8_t)(r_ctr & 0xFF);
Expand All @@ -2577,13 +2522,11 @@ bool NFCLayerA::mifare_plus_read_plain_mac(const uint16_t block, const uint8_t c
iv[8] = ctr;
memcpy(&iv[12], _mfp_session.ti.data(), 4);
uint8_t* blk = payload.data() + i * 16;
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, 16, iv, blk, blk) != 0) {
if (!aes_cbc_crypt(blk, _mfp_session.kenc.data(), iv, blk, 16, false)) {
M5_LIB_LOGE("AES crypt_cbc failed");
mbedtls_aes_free(&aes);
return false;
}
}
mbedtls_aes_free(&aes);
}

out.insert(out.end(), payload.begin(), payload.end());
Expand Down
Loading