Skip to content

Commit

Permalink
Refactor originality checks. Notes:
Browse files Browse the repository at this point in the history
- removed pk "NTAG424DNA, NTAG424DNATT, DESFire Light Ev2", "04B304...3B" which is a typo of "DESFire Ev2", "04B3...3A"},
- MIKRON pk currently not used because I don't know if it's for MFC, MFUL or sth else
- ST25TN pk added but currently not used, need to be implemented/tested
- ST25TV pk currently not used, need to be implemented/tested
  • Loading branch information
doegox committed Dec 14, 2024
1 parent 93639e1 commit f26727e
Show file tree
Hide file tree
Showing 12 changed files with 261 additions and 423 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...

## [unreleased][unreleased]
- Changed originality checks handling to refactor code and pk data (@doegox)
- Changed `uniq.yaml` workflow to be case-insensitive (@iceman1001)
- Fixed `mem load --mfc` not erasing all SPI flash blocks after extending to 4095 keys (@piotrva)
- Extended area for Mifare keys in SPI flash to hold 4095 keys (@piotrva)
Expand Down
1 change: 1 addition & 0 deletions client/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/crypto/asn1dump.c
${PM3_ROOT}/client/src/crypto/asn1utils.c
${PM3_ROOT}/client/src/crypto/libpcrypto.c
${PM3_ROOT}/client/src/crypto/originality.c
${PM3_ROOT}/client/src/emv/test/cda_test.c
${PM3_ROOT}/client/src/emv/test/crypto_test.c
${PM3_ROOT}/client/src/emv/test/cryptotest.c
Expand Down
1 change: 1 addition & 0 deletions client/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,7 @@ SRCS = mifare/aiddesfire.c \
crypto/asn1dump.c \
crypto/asn1utils.c\
crypto/libpcrypto.c\
crypto/originality.c\
emv/cmdemv.c \
emv/crypto.c\
emv/crypto_polarssl.c\
Expand Down
1 change: 1 addition & 0 deletions client/experimental_lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/crypto/asn1dump.c
${PM3_ROOT}/client/src/crypto/asn1utils.c
${PM3_ROOT}/client/src/crypto/libpcrypto.c
${PM3_ROOT}/client/src/crypto/originality.c
${PM3_ROOT}/client/src/emv/test/cda_test.c
${PM3_ROOT}/client/src/emv/test/crypto_test.c
${PM3_ROOT}/client/src/emv/test/cryptotest.c
Expand Down
131 changes: 23 additions & 108 deletions client/src/cmdhf15.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "cliparser.h"
#include "util_posix.h" // msleep
#include "iso15.h" // typedef structs / enum
#include "crypto/originality.h"

#define FrameSOF Iso15693FrameSOF
#define Logic0 Iso15693Logic0
Expand Down Expand Up @@ -281,121 +282,35 @@ static const productName_t uidmapping[] = {
static int CmdHF15Help(const char *Cmd);

static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {

#define PUBLIC_ECDA_KEYLEN 33
const ecdsa_publickey_t nxp_15693_public_keys[] = {
{"NXP MIFARE Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"},
{"MIFARE Classic / QL88", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"},
{"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"},
{"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"},
{"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"},
{"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"},
{"MIKRON Public key", "04F971EDA742A4A80D32DCF6A814A707CC3DC396D35902F72929FDCD698B3468F2"},
{"VivoKey Spark1 Public key", "04D64BB732C0D214E7EC580736ACF847284B502C25C0F7F2FA86AACE1DADA4387A"},
{"TruST25 (ST) key 01?", "041D92163650161A2548D33881C235D0FB2315C2C31A442F23C87ACF14497C0CBA"},
{"TruST25 (ST) key 04?", "04101E188A8B4CDDBC62D5BC3E0E6850F0C2730E744B79765A0E079907FBDB01BC"},
};
/*
uint8_t nxp_15693_public_keys[][PUBLIC_ECDA_KEYLEN] = {
// ICODE SLIX2 / DNA
{
0x04, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3,
0x36, 0xB4, 0xF2, 0x61, 0xA0, 0x82, 0xBD, 0x71,
0xF9, 0xBE, 0x11, 0xC4, 0xE2, 0xE8, 0x96, 0x64,
0x8B, 0x32, 0xEF, 0xA5, 0x9C, 0xEA, 0x6E, 0x59, 0xF0
},
// unknown. Needs identification
{
0x04, 0x4F, 0x6D, 0x3F, 0x29, 0x4D, 0xEA, 0x57,
0x37, 0xF0, 0xF4, 0x6F, 0xFE, 0xE8, 0x8A, 0x35,
0x6E, 0xED, 0x95, 0x69, 0x5D, 0xD7, 0xE0, 0xC2,
0x7A, 0x59, 0x1E, 0x6F, 0x6F, 0x65, 0x96, 0x2B, 0xAF
},
// unknown. Needs identification
{
0x04, 0xA7, 0x48, 0xB6, 0xA6, 0x32, 0xFB, 0xEE,
0x2C, 0x08, 0x97, 0x70, 0x2B, 0x33, 0xBE, 0xA1,
0xC0, 0x74, 0x99, 0x8E, 0x17, 0xB8, 0x4A, 0xCA,
0x04, 0xFF, 0x26, 0x7E, 0x5D, 0x2C, 0x91, 0xF6, 0xDC
},
// manufacturer public key
{
0x04, 0x6F, 0x70, 0xAC, 0x55, 0x7F, 0x54, 0x61,
0xCE, 0x50, 0x52, 0xC8, 0xE4, 0xA7, 0x83, 0x8C,
0x11, 0xC7, 0xA2, 0x36, 0x79, 0x7E, 0x8A, 0x07,
0x30, 0xA1, 0x01, 0x83, 0x7C, 0x00, 0x40, 0x39, 0xC2
},
// MIKRON public key.
{
0x04, 0xf9, 0x71, 0xed, 0xa7, 0x42, 0xa4, 0xa8,
0x0d, 0x32, 0xdc, 0xf6, 0xa8, 0x14, 0xa7, 0x07,
0xcc, 0x3d, 0xc3, 0x96, 0xd3, 0x59, 0x02, 0xf7,
0x29, 0x29, 0xfd, 0xcd, 0x69, 0x8b, 0x34, 0x68, 0xf2
}
};
*/

uint8_t revuid[HF15_UID_LENGTH] = {0};
reverse_array_copy(uid, sizeof(revuid), revuid);

uint8_t revsign[32] = {0};
reverse_array_copy(signature, sizeof(revsign), revsign);

uint8_t i;
int reason = 0;
bool is_valid = false;
for (i = 0; i < ARRAYLEN(nxp_15693_public_keys); i++) {

int dl = 0;
uint8_t key[PUBLIC_ECDA_KEYLEN];
param_gethex_to_eol(nxp_15693_public_keys[i].value, 0, key, PUBLIC_ECDA_KEYLEN, &dl);

int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 8, signature, 32, false);
is_valid = (res == 0);
if (is_valid) {
reason = 1;
break;
}

int index = -1;
index = originality_check_verify(uid, 8, signature, 32, PK_MFC);
if (index >= 0) {
reason = 1;
} else {
// try with sha256
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 8, signature, 32, true);
is_valid = (res == 0);
if (is_valid) {
index = originality_check_verify_ex(uid, 8, signature, 32, PK_MFC, false, true);
if (index >= 0) {
reason = 2;
break;
}

// try with reversed uid / signature
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, revuid, sizeof(revuid), revsign, sizeof(revsign), false);
is_valid = (res == 0);
if (is_valid) {
reason = 3;
break;
}

// try with sha256
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, revuid, sizeof(revuid), revsign, sizeof(revsign), true);
is_valid = (res == 0);
if (is_valid) {
reason = 4;
break;
} else {
// try with reversed uid / signature
index = originality_check_verify_ex(uid, 8, signature, 32, PK_MFC, true, false);
if (index >= 0) {
reason = 3;
} else {
// try with sha256 and reversed uid / signature
index = originality_check_verify_ex(uid, 8, signature, 32, PK_MFC, true, true);
if (index >= 0) {
reason = 3;
}
}
}
}

PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
if (is_valid == false || i == ARRAYLEN(nxp_15693_public_keys)) {
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32));
PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed"));
return PM3_ESOFT;
int ret = originality_check_print(signature, 32, index);
if (ret != PM3_SUCCESS) {
return ret;
}

PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_15693_public_keys[i].desc);
PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_15693_public_keys[i].value);
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32));
PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful"));
switch (reason) {
case 1:
PrintAndLogEx(INFO, " Params used: UID and signature, plain");
Expand Down
50 changes: 4 additions & 46 deletions client/src/cmdhfmf.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "generator.h" // keygens.
#include "fpga.h"
#include "mifare/mifarehost.h"
#include "crypto/originality.h"

static int CmdHelp(const char *Cmd);

Expand All @@ -68,52 +69,9 @@ static int usage_hf14_keybrute(void) {
*/

int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) {

// ref: MIFARE Classic EV1 Originality Signature Validation
#define PUBLIC_MFCEV1_ECDA_KEYLEN 33
const ecdsa_publickey_t nxp_mfc_public_keys[] = {
{"NXP MIFARE Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"},
{"MIFARE Classic / QL88", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"},
{"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"},
{"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"},
{"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"},
{"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"},
{"MIKRON Public key", "04F971EDA742A4A80D32DCF6A814A707CC3DC396D35902F72929FDCD698B3468F2"},
{"VivoKey Spark1 Public key", "04D64BB732C0D214E7EC580736ACF847284B502C25C0F7F2FA86AACE1DADA4387A"},
{"TruST25 (ST) key 01?", "041D92163650161A2548D33881C235D0FB2315C2C31A442F23C87ACF14497C0CBA"},
{"TruST25 (ST) key 04?", "04101E188A8B4CDDBC62D5BC3E0E6850F0C2730E744B79765A0E079907FBDB01BC"},
};

uint8_t i;
bool is_valid = false;

for (i = 0; i < ARRAYLEN(nxp_mfc_public_keys); i++) {

int dl = 0;
uint8_t key[PUBLIC_MFCEV1_ECDA_KEYLEN];
param_gethex_to_eol(nxp_mfc_public_keys[i].value, 0, key, PUBLIC_MFCEV1_ECDA_KEYLEN, &dl);

int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, uidlen, signature, signature_len, false);
is_valid = (res == 0);
if (is_valid)
break;
}

PrintAndLogEx(INFO, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
if (is_valid == false || i == ARRAYLEN(nxp_mfc_public_keys)) {
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32));
PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed"));
return PM3_ESOFT;
}

PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_mfc_public_keys[i].desc);
PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfc_public_keys[i].value);
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32));
PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful"));
return PM3_SUCCESS;
int index = originality_check_verify(uid, uidlen, signature, signature_len, PK_MFC);
PrintAndLogEx(NORMAL, "");
return originality_check_print(signature, signature_len, index);
}

static int mf_read_uid(uint8_t *uid, int *uidlen, int *nxptype) {
Expand Down
58 changes: 4 additions & 54 deletions client/src/cmdhfmfdes.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "generator.h"
#include "mifare/aiddesfire.h"
#include "util.h"
#include "crypto/originality.h"

#define MAX_KEY_LEN 24
#define MAX_KEYS_LIST_LEN 1024
Expand Down Expand Up @@ -442,61 +443,10 @@ int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, si
PrintAndLogEx(DEBUG, "SIGNATURE=NULL");
return PM3_EINVARG;
}
// ref: MIFARE Desfire Originality Signature Validation
// See tools/recover_pk.py to recover Pk from UIDs and signatures
#define PUBLIC_DESFIRE_ECDA_KEYLEN 57
const ecdsa_publickey_t nxp_desfire_public_keys[] = {
{"NTAG424DNA, DESFire Ev2", "048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410"},
{"NTAG413DNA, DESFire Ev1", "04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD"},
{"DESFire Ev2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"},
{"DESFire Ev3", "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743"},
{"NTAG424DNA, NTAG424DNATT, DESFire Light Ev2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"},
{"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"},
{"MIFARE Plus Ev1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"},
{"MIFARE Plus Ev2", "04BB49AE4447E6B1B6D21C098C1538B594A11A4A1DBF3D5E673DEACDEB3CC512D1C08AFA1A2768CE20A200BACD2DC7804CD7523A0131ABF607"},
{"DESFire Ev2 XL", "04CD5D45E50B1502F0BA4656FF37669597E7E183251150F9574CC8DA56BF01C7ABE019E29FEA48F9CE22C3EA4029A765E1BC95A89543BAD1BC"},
{"MIFARE Plus Troika", "040F732E0EA7DF2B38F791BF89425BF7DCDF3EE4D976669E3831F324FF15751BD52AFF1782F72FF2731EEAD5F63ABE7D126E03C856FFB942AF"},
};


uint32_t i;
bool is_valid = false;

for (i = 0; i < ARRAYLEN(nxp_desfire_public_keys); i++) {

int dl = 0;
uint8_t key[PUBLIC_DESFIRE_ECDA_KEYLEN];
param_gethex_to_eol(nxp_desfire_public_keys[i].value, 0, key, PUBLIC_DESFIRE_ECDA_KEYLEN, &dl);

int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP224R1, key, uid, uidlen, signature, signature_len, false);
is_valid = (res == 0);
if (is_valid)
break;
}
// PrintAndLogEx(NORMAL, "");
// PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
if (is_valid == false || i == ARRAYLEN(nxp_desfire_public_keys)) {
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp224r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48));
PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed"));
return PM3_ESOFT;
}

PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_desfire_public_keys[i].desc);
PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_desfire_public_keys[i].value);
PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 32);
PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 64);
PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 96);
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp224r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48));
PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful"));
return PM3_SUCCESS;
int index = originality_check_verify(uid, uidlen, signature, signature_len, PK_MFDES);
PrintAndLogEx(NORMAL, "");
return originality_check_print(signature, signature_len, index);
}

static void swap24(uint8_t *data) {
Expand Down
Loading

0 comments on commit f26727e

Please sign in to comment.