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 <me@evildaemond.com>
This commit is contained in:
Adam Jon Foster
2026-03-18 13:17:40 +08:00
committed by GitHub
parent 3eac1861f6
commit 9d923c81f0
+73 -37
View File
@@ -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;
};