From 9d923c81f0845b1ac1123d3f9ff30ef91116e312 Mon Sep 17 00:00:00 2001 From: Adam Jon Foster Date: Wed, 18 Mar 2026 13:17:40 +0800 Subject: [PATCH] Fixing the SEOS GET Data logic to allow for tags values longer than 255 There was an issue inside of the GET Data response where if the response was longer than 255 bytes (such as the FF41 tag on NVX's Zero Key format), it would fail to parse. I've added some extra wrapping to clean this up, but longer term we would need to refactor how we parse SM responses anyway. Signed-off-by: Adam Jon Foster --- client/src/cmdhfseos.c | 110 +++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 37 deletions(-) diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index 8021b7375..b3a7129ee 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -259,7 +259,7 @@ static void generate_command_wrapping(uint8_t *command_Header, int command_heade //return; } -static int seos_get_data(uint8_t *rndICC, uint8_t *rndIFD, uint8_t *diversified_enc_key, uint8_t *diversified_mac_key, uint8_t *sioOutput, int *sio_size, int encryption_algorithm, uint8_t *data_tag, int data_tag_len) { +static int seos_get_data(uint8_t *rndICC, uint8_t *rndIFD, uint8_t *diversified_enc_key, uint8_t *diversified_mac_key, uint8_t *sioOutput, int *tag_size, int encryption_algorithm, uint8_t *data_tag, int data_tag_len) { // Intergrating our command generation with the GetData request to make my life easier in the future // Command Header is for the Get Data Command using @@ -307,7 +307,7 @@ static int seos_get_data(uint8_t *rndICC, uint8_t *rndIFD, uint8_t *diversified_ for (int i = 0; i < command_len; i++) { snprintf(&completedCommandChar[i * 2], 3, "%02X", command_convert[i]); } - // PrintAndLogEx(SUCCESS, "Command.......................... " _YELLOW_("%s"), completedCommandChar); + //PrintAndLogEx(SUCCESS, "Command.......................... " _YELLOW_("%s"), completedCommandChar); // ------------------- Send Command ------------------- uint8_t response[PM3_CMD_DATA_SIZE]; @@ -337,46 +337,82 @@ static int seos_get_data(uint8_t *rndICC, uint8_t *rndIFD, uint8_t *diversified_ // 99 is our status word response (2 bytes) // 8E is our MAC response (8 bytes) // PrintAndLogEx(SUCCESS, "Raw Response..................... " _YELLOW_("%s"), sprint_hex_inrow(response, (resplen - 2))); - - uint8_t responseCode[2]; - uint8_t tag[2] = {0x00, 0x00}; - int getDataSize = 0; - + uint8_t cryptogram[256] = {0}; + uint8_t responseCode[2] = {0}; + uint8_t mac[8] = {0}; + size_t cryptogram_length = 0; + + // Parse the response to extract the three tags + for (int i = 0; i < resplen - 2; ) { + if (response[i] == 0x85) { + // Cryptogram tag + size_t offset = i + 1; + asn1_get_tag_length(response, &cryptogram_length, &offset, resplen); + memcpy(cryptogram, response + offset, cryptogram_length); + i += offset + cryptogram_length; + } else if (response[i] == 0x99) { + // Response code tag + size_t len = response[i + 1]; + memcpy(responseCode, response + i + 2, len); + i += 2 + len; + } else if (response[i] == 0x8E) { + // MAC tag + size_t len = response[i + 1]; + memcpy(mac, response + i + 2, len); + i += 2 + len; + } else { + i += 2 + response[i + 1]; + } + } + // ------------------- Cryptogram Response ------------------- - if (resplen >= 2 && response[0] == 0x85) { - uint8_t cryptogram_length = response[1]; - uint8_t cryptogram[cryptogram_length]; + if (cryptogram_length > 0) { uint8_t decrypted[cryptogram_length]; - memcpy(cryptogram, response + 2, cryptogram_length); - memcpy(responseCode, response + cryptogram_length + 4, 2); + int getDataSize = 0; // Decrypt the response - decrypt_cryptogram(diversified_enc_key, cryptogram, decrypted, sizeof(cryptogram), encryption_algorithm); - - // Response Format - // FF0038302F8102578CA5020500A6088101010403030008A7178515D65ED945996AB9107CD6D3E6011F56FFDD9CFFC780A9020500050000000000008000000000 - - // FF00 is our inputed tag value - // 38 is our len - - // PrintAndLogEx(SUCCESS, "Cryptogram....................... " _YELLOW_("%s"), sprint_hex_inrow(cryptogram, sizeof(cryptogram))); - // PrintAndLogEx(SUCCESS, "Decrypted........................ " _YELLOW_("%s"), sprint_hex_inrow(decrypted, sizeof(decrypted))); - - getDataSize = decrypted[2]; - memcpy(tag, decrypted, ARRAYLEN(tag)); - memmove(decrypted, decrypted + 1, sizeof(decrypted) - 1); - memmove(sioOutput, decrypted + 2, getDataSize); - *sio_size = getDataSize; - memcpy(responseCode, response + cryptogram_length + 4, 2); - - PrintAndLogEx(SUCCESS, "Response Code.................... " _YELLOW_("%s"), sprint_hex_inrow(responseCode, (ARRAYLEN(responseCode)))); - PrintAndLogEx(SUCCESS, "Output........................... " _YELLOW_("%s"), sprint_hex_inrow(sioOutput, getDataSize)); - } else if (resplen >= 2 && response[0] == 0x99) { - memcpy(responseCode, response + 2, 2); - // PrintAndLogEx(SUCCESS, "Raw Response..................... " _YELLOW_("%s"), sprint_hex_inrow(response, (resplen - 2))); - PrintAndLogEx(SUCCESS, "Response Code.................... " _YELLOW_("%s"), sprint_hex_inrow(responseCode, (ARRAYLEN(responseCode)))); + decrypt_cryptogram(diversified_enc_key, cryptogram, decrypted, cryptogram_length, encryption_algorithm); + + //PrintAndLogEx(SUCCESS, "Cryptogram....................... " _YELLOW_("%s"), sprint_hex_inrow(cryptogram, cryptogram_length)); + //PrintAndLogEx(SUCCESS, "Decrypted........................ " _YELLOW_("%s"), sprint_hex_inrow(decrypted, cryptogram_length)); + + // Parse TLV: tag can be 1 or 2 bytes + int offset = 0; + uint8_t tag[2] = {0x00, 0x00}; + int tag_len = 1; + + // Check if it's a 2-byte tag (first byte has bits 5-1 all set to 1) + if ((decrypted[offset] & 0x1F) == 0x1F) { + tag[0] = decrypted[offset]; + tag[1] = decrypted[offset + 1]; + tag_len = 2; + offset += 2; + } else { + tag[0] = decrypted[offset]; + offset += 1; + } + + // Get length byte + uint8_t length_byte = decrypted[offset]; + offset += 1; + + // Extract the value + getDataSize = length_byte; + memcpy(sioOutput, decrypted + offset, getDataSize); + *tag_size = getDataSize; + + PrintAndLogEx(SUCCESS, "Tag.............................. " _YELLOW_("%s"), sprint_hex_inrow(tag, tag_len)); + PrintAndLogEx(SUCCESS, "Value............................ " _YELLOW_("%s"), sprint_hex_inrow(sioOutput, getDataSize)); } - + + if (responseCode[0] != 0x00 || responseCode[1] != 0x00) { + PrintAndLogEx(SUCCESS, "Response Code.................... " _YELLOW_("%s"), sprint_hex_inrow(responseCode, ARRAYLEN(responseCode))); + } + + // if (mac[0] != 0x00) { + // PrintAndLogEx(SUCCESS, "MAC.............................. " _YELLOW_("%s"), sprint_hex_inrow(mac, sizeof(mac))); + // } + return PM3_SUCCESS; };