added rudimentary functions for doing AES authentication against MIFARE UL AES tags. (wip)

This commit is contained in:
iceman1001 2024-02-15 16:20:47 +01:00
commit c4c1601446
11 changed files with 330 additions and 27 deletions

View file

@ -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... 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] ## [unreleased][unreleased]
- Changed `hf mfu info` - should not try pwd against a UL-AES (@iceman1001)
- Fixed `hf mfu info` - tag type identification now properly handles 64bits (@iceman1001) - Fixed `hf mfu info` - tag type identification now properly handles 64bits (@iceman1001)
- Changed `hf st info` - reworked the output (@iceman1001) - Changed `hf st info` - reworked the output (@iceman1001)
- Rename `smart relay` to `smart pcsc` and add support for contact interface (@gm3197) - Rename `smart relay` to `smart pcsc` and add support for contact interface (@gm3197)

View file

@ -1639,6 +1639,7 @@ static void PacketReceived(PacketCommandNG *packet) {
break; break;
} }
case CMD_HF_MIFAREU_READBL: { case CMD_HF_MIFAREU_READBL: {
MifareUReadBlock(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); MifareUReadBlock(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
break; break;
} }
@ -1646,6 +1647,16 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareUC_Auth(packet->oldarg[0], packet->data.asBytes); MifareUC_Auth(packet->oldarg[0], packet->data.asBytes);
break; break;
} }
case CMD_HF_MIFAREULAES_AUTH: {
struct p {
bool turn_off_field;
uint8_t keyno;
uint8_t key[18];
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
MifareUL_AES_Auth(payload->turn_off_field, payload->keyno, payload->key);
break;
}
case CMD_HF_MIFAREU_READCARD: { case CMD_HF_MIFAREU_READCARD: {
MifareUReadCard(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); MifareUReadCard(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
break; break;
@ -1801,8 +1812,6 @@ static void PacketReceived(PacketCommandNG *packet) {
break; break;
} }
case CMD_HF_MIFARE_CIDENT: { case CMD_HF_MIFARE_CIDENT: {
struct p { struct p {
uint8_t is_mfc; uint8_t is_mfc;
uint8_t keytype; uint8_t keytype;
@ -2025,7 +2034,7 @@ static void PacketReceived(PacketCommandNG *packet) {
uint8_t skipMode; uint8_t skipMode;
uint8_t skipRatio; uint8_t skipRatio;
} PACKED; } PACKED;
struct p *payload = (struct p *)packet->data.asBytes; struct p *payload = (struct p *) packet->data.asBytes;
uint16_t len = 0; uint16_t len = 0;
int res = HfSniff(payload->samplesToSkip, payload->triggersToSkip, &len, payload->skipMode, payload->skipRatio); int res = HfSniff(payload->samplesToSkip, payload->triggersToSkip, &len, payload->skipMode, payload->skipRatio);
@ -2059,12 +2068,12 @@ static void PacketReceived(PacketCommandNG *packet) {
struct p { struct p {
uint32_t new_clk; uint32_t new_clk;
} PACKED; } PACKED;
struct p *payload = (struct p *)packet->data.asBytes; struct p *payload = (struct p *) packet->data.asBytes;
SmartCardSetClock(payload->new_clk); SmartCardSetClock(payload->new_clk);
break; break;
} }
case CMD_SMART_RAW: { case CMD_SMART_RAW: {
SmartCardRaw((smart_card_raw_t *)packet->data.asBytes); SmartCardRaw((smart_card_raw_t *) packet->data.asBytes);
break; break;
} }
case CMD_SMART_UPLOAD: { case CMD_SMART_UPLOAD: {
@ -2075,7 +2084,7 @@ static void PacketReceived(PacketCommandNG *packet) {
uint16_t crc; uint16_t crc;
uint8_t data[400]; uint8_t data[400];
} PACKED; } PACKED;
struct p *payload = (struct p *)packet->data.asBytes; struct p *payload = (struct p *) packet->data.asBytes;
uint8_t *mem = BigBuf_get_addr(); uint8_t *mem = BigBuf_get_addr();
memcpy(mem + payload->idx, payload->data, payload->bytes_in_packet); memcpy(mem + payload->idx, payload->data, payload->bytes_in_packet);
@ -2094,7 +2103,7 @@ static void PacketReceived(PacketCommandNG *packet) {
uint16_t fw_size; uint16_t fw_size;
uint16_t crc; uint16_t crc;
} PACKED; } PACKED;
struct p *payload = (struct p *)packet->data.asBytes; struct p *payload = (struct p *) packet->data.asBytes;
uint8_t *fwdata = BigBuf_get_addr(); uint8_t *fwdata = BigBuf_get_addr();
uint8_t a = 0, b = 0; uint8_t a = 0, b = 0;
@ -2139,7 +2148,7 @@ static void PacketReceived(PacketCommandNG *packet) {
struct p { struct p {
uint32_t waittime; uint32_t waittime;
} PACKED; } PACKED;
struct p *payload = (struct p *) &packet->data.asBytes; struct p *payload = (struct p *) packet->data.asBytes;
uint16_t available; uint16_t available;
uint16_t pre_available = 0; uint16_t pre_available = 0;
@ -2182,7 +2191,7 @@ static void PacketReceived(PacketCommandNG *packet) {
uint32_t waittime; uint32_t waittime;
uint8_t data[]; uint8_t data[];
} PACKED; } PACKED;
struct p *payload = (struct p *) &packet->data.asBytes; struct p *payload = (struct p *) packet->data.asBytes;
usart_writebuffer_sync(payload->data, packet->length - sizeof(payload)); usart_writebuffer_sync(payload->data, packet->length - sizeof(payload));
uint16_t available; uint16_t available;
@ -2226,7 +2235,7 @@ static void PacketReceived(PacketCommandNG *packet) {
uint32_t baudrate; uint32_t baudrate;
uint8_t parity; uint8_t parity;
} PACKED; } PACKED;
struct p *payload = (struct p *) &packet->data.asBytes; struct p *payload = (struct p *) packet->data.asBytes;
usart_init(payload->baudrate, payload->parity); usart_init(payload->baudrate, payload->parity);
reply_ng(CMD_USART_CONFIG, PM3_SUCCESS, NULL, 0); reply_ng(CMD_USART_CONFIG, PM3_SUCCESS, NULL, 0);
break; break;
@ -2350,7 +2359,7 @@ static void PacketReceived(PacketCommandNG *packet) {
uint16_t offset; uint16_t offset;
uint8_t data[PM3_CMD_DATA_SIZE - sizeof(uint8_t) - sizeof(uint16_t)]; uint8_t data[PM3_CMD_DATA_SIZE - sizeof(uint8_t) - sizeof(uint16_t)];
} PACKED; } PACKED;
struct p *payload = (struct p *)packet->data.asBytes; struct p *payload = (struct p *) packet->data.asBytes;
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaDownloadAndGo(FPGA_BITSTREAM_LF);

View file

@ -119,7 +119,56 @@ void tdes_nxp_send(const void *in, void *out, size_t length, const void *key, un
} }
} }
void aes128_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[8]) {
if (length % 8) return;
mbedtls_aes_setkey_dec(&actx, key, 128);
uint8_t i;
unsigned char temp[8];
uint8_t *tin = (uint8_t *) in;
uint8_t *tout = (uint8_t *) out;
while (length > 0) {
memcpy(temp, tin, 8);
mbedtls_aes_crypt_ecb(&actx, MBEDTLS_AES_DECRYPT, tin, tout);
for (i = 0; i < 8; i++) {
tout[i] = (unsigned char)(tout[i] ^ iv[i]);
}
memcpy(iv, temp, 8);
tin += 8;
tout += 8;
length -= 8;
}
}
void aes128_nxp_send(const void *in, void *out, size_t length, const void *key, unsigned char iv[8]) {
if (length % 8) return;
mbedtls_aes_setkey_enc(&actx, key, 128);
uint8_t i;
uint8_t *tin = (uint8_t *) in;
uint8_t *tout = (uint8_t *) out;
while (length > 0) {
for (i = 0; i < 8; i++) {
tin[i] = (unsigned char)(tin[i] ^ iv[i]);
}
mbedtls_aes_crypt_ecb(&actx, MBEDTLS_AES_ENCRYPT, tin, tout);
memcpy(iv, tout, 8);
tin += 8;
tout += 8;
length -= 8;
}
}
void Desfire_des_key_new(const uint8_t value[8], desfirekey_t key) { void Desfire_des_key_new(const uint8_t value[8], desfirekey_t key) {
uint8_t data[8]; uint8_t data[8];

View file

@ -179,6 +179,10 @@ void des_encrypt(void *out, const void *in, const void *key);
void des_decrypt(void *out, const void *in, const void *key); void des_decrypt(void *out, const void *in, const void *key);
void tdes_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode); void tdes_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode);
void tdes_nxp_send(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode); void tdes_nxp_send(const void *in, void *out, size_t length, const void *key, unsigned char iv[8], int keymode);
void aes128_nxp_receive(const void *in, void *out, size_t length, const void *key, unsigned char iv[8]);
void aes128_nxp_send(const void *in, void *out, size_t length, const void *key, unsigned char iv[8]);
void Desfire_des_key_new(const uint8_t value[8], desfirekey_t key); void Desfire_des_key_new(const uint8_t value[8], desfirekey_t key);
void Desfire_3des_key_new(const uint8_t value[16], desfirekey_t key); void Desfire_3des_key_new(const uint8_t value[16], desfirekey_t key);
void Desfire_des_key_new_with_version(const uint8_t value[8], desfirekey_t key); void Desfire_des_key_new_with_version(const uint8_t value[8], desfirekey_t key);

View file

@ -281,6 +281,36 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes) {
reply_mix(CMD_ACK, 1, 0, 0, 0, 0); reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
} }
void MifareUL_AES_Auth(bool turn_off_field, uint8_t keyno, uint8_t *keybytes) {
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card");
reply_ng(CMD_HF_MIFAREULAES_AUTH, PM3_ESOFT, NULL, 0);
return;
};
if (!mifare_ultra_aes_auth(keyno, keybytes)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Authentication failed");
reply_ng(CMD_HF_MIFAREULAES_AUTH, PM3_ESOFT, NULL, 0);
return;
}
if (turn_off_field) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
reply_ng(CMD_HF_MIFAREULAES_AUTH, PM3_SUCCESS, NULL, 0);
}
// Arg0 = BlockNo, // Arg0 = BlockNo,
// Arg1 = UsePwd bool // Arg1 = UsePwd bool
// datain = PWD bytes, // datain = PWD bytes,
@ -361,8 +391,8 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
// params // params
uint8_t blockNo = arg0; uint8_t blockNo = arg0;
uint16_t blocks = arg1; uint16_t blocks = arg1;
bool useKey = (arg2 == 1); //UL_C bool useKey = (arg2 == 1); // UL_C
bool usePwd = (arg2 == 2); //UL_EV1/NTAG bool usePwd = (arg2 == 2); // UL_EV1/NTAG
uint32_t countblocks = 0; uint32_t countblocks = 0;
uint8_t *dataout = BigBuf_malloc(CARD_MEMORY_SIZE); uint8_t *dataout = BigBuf_malloc(CARD_MEMORY_SIZE);
if (dataout == NULL) { if (dataout == NULL) {
@ -407,7 +437,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
break; break;
} }
len = mifare_ultra_readblock(blockNo + i, dataout + 4 * i); len = mifare_ultra_readblock(blockNo + i, dataout + (4 * i));
if (len) { if (len) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Read block %d error", i); if (g_dbglevel >= DBG_ERROR) Dbprintf("Read block %d error", i);

View file

@ -27,6 +27,8 @@ void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes); void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes);
void MifareUL_AES_Auth(bool turn_off_field, uint8_t keyno, uint8_t *keybytes);
void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain); void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);

View file

@ -378,6 +378,92 @@ int mifare_ultra_auth(uint8_t *keybytes) {
return 1; return 1;
} }
int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes) {
/// aes-128
uint8_t random_a[8] = {1, 1, 1, 1, 1, 1, 1, 1};
uint8_t random_b[8] = {0x00};
uint8_t enc_random_b[8] = {0x00};
uint8_t rnd_ab[16] = {0x00};
uint8_t IV[8] = {0x00};
uint8_t key[16] = {0x00};
memcpy(key, keybytes, sizeof(key));
uint16_t len = 0;
uint8_t resp[19] = {0x00};
uint8_t respPar[3] = {0, 0, 0};
// REQUEST AUTHENTICATION
len = mifare_sendcmd_short(NULL, CRYPT_NONE, MIFARE_ULAES_AUTH_1, keyno, resp, respPar, NULL);
if (len != 11) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]);
return 0;
}
// tag nonce.
memcpy(enc_random_b, resp + 1, 8);
// decrypt nonce.
aes128_nxp_receive((void *)enc_random_b, (void *)random_b, sizeof(random_b), (const void *)key, IV);
rol(random_b, 8);
memcpy(rnd_ab, random_a, 8);
memcpy(rnd_ab + 8, random_b, 8);
if (g_dbglevel >= DBG_EXTENDED) {
Dbprintf("enc_B: %02x %02x %02x %02x %02x %02x %02x %02x",
enc_random_b[0], enc_random_b[1], enc_random_b[2], enc_random_b[3], enc_random_b[4], enc_random_b[5], enc_random_b[6], enc_random_b[7]);
Dbprintf(" B: %02x %02x %02x %02x %02x %02x %02x %02x",
random_b[0], random_b[1], random_b[2], random_b[3], random_b[4], random_b[5], random_b[6], random_b[7]);
Dbprintf("rnd_ab: %02x %02x %02x %02x %02x %02x %02x %02x",
rnd_ab[0], rnd_ab[1], rnd_ab[2], rnd_ab[3], rnd_ab[4], rnd_ab[5], rnd_ab[6], rnd_ab[7]);
Dbprintf("rnd_ab: %02x %02x %02x %02x %02x %02x %02x %02x",
rnd_ab[8], rnd_ab[9], rnd_ab[10], rnd_ab[11], rnd_ab[12], rnd_ab[13], rnd_ab[14], rnd_ab[15]);
}
// encrypt out, in, length, key, iv
aes128_nxp_send(rnd_ab, rnd_ab, sizeof(rnd_ab), key, enc_random_b);
len = mifare_sendcmd(MIFARE_ULAES_AUTH_2, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL);
if (len != 11) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]);
return 0;
}
uint8_t enc_resp[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t resp_random_a[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
memcpy(enc_resp, resp + 1, 8);
// decrypt out, in, length, key, iv
aes128_nxp_receive(enc_resp, resp_random_a, 8, key, enc_random_b);
if (memcmp(resp_random_a, random_a, 8) != 0) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("failed authentication");
return 0;
}
if (g_dbglevel >= DBG_EXTENDED) {
Dbprintf("e_AB: %02x %02x %02x %02x %02x %02x %02x %02x",
rnd_ab[0], rnd_ab[1], rnd_ab[2], rnd_ab[3],
rnd_ab[4], rnd_ab[5], rnd_ab[6], rnd_ab[7]);
Dbprintf("e_AB: %02x %02x %02x %02x %02x %02x %02x %02x",
rnd_ab[8], rnd_ab[9], rnd_ab[10], rnd_ab[11],
rnd_ab[12], rnd_ab[13], rnd_ab[14], rnd_ab[15]);
Dbprintf("a: %02x %02x %02x %02x %02x %02x %02x %02x",
random_a[0], random_a[1], random_a[2], random_a[3],
random_a[4], random_a[5], random_a[6], random_a[7]);
Dbprintf("b: %02x %02x %02x %02x %02x %02x %02x %02x",
resp_random_a[0], resp_random_a[1], resp_random_a[2], resp_random_a[3],
resp_random_a[4], resp_random_a[5], resp_random_a[6], resp_random_a[7]);
}
return 1;
}
static int mifare_ultra_readblockEx(uint8_t blockNo, uint8_t *blockData) { static int mifare_ultra_readblockEx(uint8_t blockNo, uint8_t *blockData) {
uint16_t len = 0; uint16_t len = 0;
uint8_t bt[2] = {0x00, 0x00}; uint8_t bt[2] = {0x00, 0x00};

View file

@ -87,6 +87,7 @@ int mifare_classic_value(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blo
// Ultralight/NTAG... // Ultralight/NTAG...
int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack); int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack);
int mifare_ultra_auth(uint8_t *keybytes); int mifare_ultra_auth(uint8_t *keybytes);
int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes);
int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData); int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData);
int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData); int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData);
int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData); int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData);

View file

@ -56,6 +56,16 @@
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static uint8_t default_aes_keys[][16] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // all zeroes
{ 0x42, 0x52, 0x45, 0x41, 0x4b, 0x4d, 0x45, 0x49, 0x46, 0x59, 0x4f, 0x55, 0x43, 0x41, 0x4e, 0x21 }, // 3des std key
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, // 0x00-0x0F
{ 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 }, // NFC-key
{ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // all ones
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, // all FF
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF } // 11 22 33
};
static uint8_t default_3des_keys[][16] = { static uint8_t default_3des_keys[][16] = {
{ 0x42, 0x52, 0x45, 0x41, 0x4b, 0x4d, 0x45, 0x49, 0x46, 0x59, 0x4f, 0x55, 0x43, 0x41, 0x4e, 0x21 }, // 3des std key { 0x42, 0x52, 0x45, 0x41, 0x4b, 0x4d, 0x45, 0x49, 0x46, 0x59, 0x4f, 0x55, 0x43, 0x41, 0x4e, 0x21 }, // 3des std key
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // all zeroes { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // all zeroes
@ -295,14 +305,56 @@ static int ulc_requestAuthentication(uint8_t *nonce, uint16_t nonceLength) {
return len; return len;
} }
static int ulev1_requestAuthentication(uint8_t *pwd, uint8_t *pack, uint16_t packLength) {
uint8_t cmd[] = {MIFARE_ULEV1_AUTH, pwd[0], pwd[1], pwd[2], pwd[3]};
int len = ul_send_cmd_raw(cmd, sizeof(cmd), pack, packLength);
// NACK tables different tags, but between 0-9 is a NEGATIVE response.
// ACK == 0xA
if (len == 1 && pack[0] <= 0x09)
return -1;
return len;
}
/*
Default AES key is 00-00h. Both the data and UID one.
Data key is 00, UID is 01. Authenticity is 02h
Auth is 1A[Key ID][CRC] - AF[RndB] - AF[RndA][RndB'] - 00[RndA']
*/
static int ulaes_requestAuthentication(uint8_t *key, uint8_t keyno, bool switch_off_field) {
struct p {
bool turn_off_field;
uint8_t keyno;
uint8_t key[16];
} PACKED payload;
payload.turn_off_field = switch_off_field;
payload.keyno = keyno;
memcpy(payload.key, key, sizeof(payload.key));
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFAREULAES_AUTH, (uint8_t*)&payload, sizeof(payload));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFAREULAES_AUTH, &resp, 1500) == false) {
return PM3_ETIMEOUT;
}
if (resp.status != PM3_SUCCESS) {
return resp.status;
}
return PM3_SUCCESS;
}
static int ulc_authentication(uint8_t *key, bool switch_off_field) { static int ulc_authentication(uint8_t *key, bool switch_off_field) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFAREUC_AUTH, switch_off_field, 0, 0, key, 16); SendCommandMIX(CMD_HF_MIFAREUC_AUTH, switch_off_field, 0, 0, key, 16);
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return 0; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
if (resp.oldarg[0] == 1) return 1; return 0;
}
if (resp.oldarg[0] == 1) {
return 1;
}
return 0; return 0;
} }
@ -394,17 +446,59 @@ static int try_default_3des_keys(uint8_t **correct_key) {
return res; return res;
} }
static int ulev1_requestAuthentication(uint8_t *pwd, uint8_t *pack, uint16_t packLength) { static int try_default_aes_keys(void) {
uint8_t cmd[] = {MIFARE_ULEV1_AUTH, pwd[0], pwd[1], pwd[2], pwd[3]}; uint8_t dbg_curr = DBG_NONE;
int len = ul_send_cmd_raw(cmd, sizeof(cmd), pack, packLength); if (getDeviceDebugLevel(&dbg_curr) != PM3_SUCCESS) {
// NACK tables different tags, but between 0-9 is a NEGATIVE response. return PM3_ESOFT;
// ACK == 0xA }
if (len == 1 && pack[0] <= 0x09)
return -1; if (setDeviceDebugLevel(DBG_NONE, false) != PM3_SUCCESS) {
return len; return PM3_ESOFT;
}
int res = PM3_ESOFT;
PrintAndLogEx(INFO, "");
PrintAndLogEx(SUCCESS, "--- " _CYAN_("Known UL-AES keys"));
for (uint8_t i = 0; i < ARRAYLEN(default_aes_keys); ++i) {
uint8_t *key = default_aes_keys[i];
for (uint8_t keyno = 0; keyno < 2; keyno++) {
if (ulaes_requestAuthentication(key, keyno, true) == PM3_SUCCESS) {
char keystr[20] = {0};
switch(keyno) {
case 0:
sprintf(keystr, "Data key");
break;
case 1:
sprintf(keystr, "UID key");
break;
case 2:
sprintf(keystr, "Authenticity key");
break;
default:
break;
}
PrintAndLogEx(SUCCESS, "Found %s keyno %02X - %s ( "_GREEN_("ok") " )"
, keystr
, keyno
, sprint_hex_inrow(key, 16)
);
res = PM3_SUCCESS;
}
}
}
setDeviceDebugLevel(dbg_curr, false);
return res;
} }
static int ul_auth_select(iso14a_card_select_t *card, uint64_t tagtype, bool hasAuthKey, uint8_t *authkey, uint8_t *pack, uint8_t packSize) { static int ul_auth_select(iso14a_card_select_t *card, uint64_t tagtype, bool hasAuthKey, uint8_t *authkey, uint8_t *pack, uint8_t packSize) {
if (hasAuthKey && (tagtype & MFU_TT_UL_C)) { if (hasAuthKey && (tagtype & MFU_TT_UL_C)) {
//will select card automatically and close connection on error //will select card automatically and close connection on error
@ -2026,6 +2120,23 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
} }
} }
// Specific UL-AES
if (tagtype & MFU_TT_UL_AES) {
// print AES configuration etc..
DropField();
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "--- " _CYAN_("Known AES keys"));
// also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys
if (try_default_aes_keys() != PM3_SUCCESS) {
PrintAndLogEx(INFO, "n/a");
}
PrintAndLogEx(INFO, "Done!");
}
// do counters and signature first (don't neet auth) // do counters and signature first (don't neet auth)
// ul counters are different than ntag counters // ul counters are different than ntag counters
@ -2119,6 +2230,11 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
} }
} }
// Don't check passwords for Ul AES :)
if (tagtype == MFU_TT_UL_AES) {
goto out;
}
// AUTHLIMIT, (number of failed authentications) // AUTHLIMIT, (number of failed authentications)
// 0 = limitless. // 0 = limitless.
// 1-7 = limit. No automatic tries then. // 1-7 = limit. No automatic tries then.

View file

@ -692,9 +692,11 @@ typedef struct {
#define CMD_HF_MIFARE_MFKEY 0x0631 #define CMD_HF_MIFARE_MFKEY 0x0631
#define CMD_HF_MIFARE_PERSONALIZE_UID 0x0632 #define CMD_HF_MIFARE_PERSONALIZE_UID 0x0632
//ultralightC // ultralight-C
#define CMD_HF_MIFAREUC_AUTH 0x0724 #define CMD_HF_MIFAREUC_AUTH 0x0724
//0x0725 and 0x0726 no longer used // Ultralight AES
#define CMD_HF_MIFAREULAES_AUTH 0x0725
// 0x0726 no longer used
#define CMD_HF_MIFAREUC_SETPWD 0x0727 #define CMD_HF_MIFAREUC_SETPWD 0x0727
// mifare desfire // mifare desfire

View file

@ -224,6 +224,9 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MIFARE_ULNANO_WRITESIG 0xA9 #define MIFARE_ULNANO_WRITESIG 0xA9
#define MIFARE_ULNANO_LOCKSIG 0xAC #define MIFARE_ULNANO_LOCKSIG 0xAC
#define MIFARE_ULAES_AUTH_1 0x1A
#define MIFARE_ULAES_AUTH_2 0xAF
// NTAG i2k 2K uses sector 0, and sector 1 to have access to // NTAG i2k 2K uses sector 0, and sector 1 to have access to
// block 0x00-0xFF. // block 0x00-0xFF.
#define NTAG_I2C_SELECT_SECTOR 0xC2 #define NTAG_I2C_SELECT_SECTOR 0xC2