Skip to content
Open
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
73 changes: 36 additions & 37 deletions client/src/cmdhfseos.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ static uint8_t zeros[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
static int CmdHelp(const char *Cmd);

typedef struct {
uint8_t nonce[8];
uint8_t keyslot;
uint8_t privEncKey[16];
uint8_t privMacKey[16];
uint8_t readKey[16];
Expand All @@ -57,31 +57,31 @@ typedef struct {

keyset_t keys[] = {
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Nonce
0x01, // Keyslot
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // privEncKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // privMacKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // readKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // writeKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // adminKey
},
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Nonce
0x01, // Keyslot
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // privEncKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // privMacKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // readKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // writeKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // adminKey
},
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Nonce
0x02, // Keyslot
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // privEncKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // privMacKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // readKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // writeKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // adminKey
},
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Nonce
0x09, // Keyslot
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // privEncKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // privMacKey
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // readKey
Expand Down Expand Up @@ -469,7 +469,7 @@ static int seos_challenge_get(uint8_t *RNDICC, uint8_t RNDICC_len, uint8_t keysl

// const char keyslot_str[3] = "01";
//strcat(getChallengePre, keyslot_str);
snprintf(getChallengePre + strlen(getChallengePre), 3, "%02u", keyslot);
snprintf(getChallengePre + strlen(getChallengePre), 3, "%02X", keyslot);
strcat(getChallengePre, "047c02810000");

uint8_t aGET_CHALLENGE[12];
Expand Down Expand Up @@ -1091,7 +1091,7 @@ static int seos_pacs_adf_select(char *oid, int oid_len, uint8_t *data_tag, int d

resplen -= 2;

uint8_t keyslot = 0x01;
uint8_t keyslot = keys[key_index].keyslot;
seos_challenge_get(RNDICC, sizeof(RNDICC), keyslot);
select_df_decode(response, resplen, &ALGORITHM_INFO_value1, &ALGORITHM_INFO_value2, CRYPTOGRAM_encrypted_data, MAC_value);
res = select_DF_verify(response, resplen, MAC_value, sizeof(MAC_value), ALGORITHM_INFO_value1, key_index);
Expand Down Expand Up @@ -1201,7 +1201,7 @@ static int seos_adf_select(char *oid, int oid_len, int key_index) {

resplen -= 2;

seos_challenge_get(RNDICC, sizeof(RNDICC), 0x01);
seos_challenge_get(RNDICC, sizeof(RNDICC), keys[key_index].keyslot);
select_df_decode(response, resplen, &ALGORITHM_INFO_value1, &ALGORITHM_INFO_value2, CRYPTOGRAM_encrypted_data, MAC_value);
select_DF_verify(response, resplen, MAC_value, sizeof(MAC_value), ALGORITHM_INFO_value1, key_index);
return PM3_SUCCESS;
Expand Down Expand Up @@ -1244,7 +1244,7 @@ static int seos_gdf_select(int key_index) {
uint8_t MAC_value[8] = {0}; // MAC Value
uint8_t RNDICC[8] = {0};

seos_challenge_get(RNDICC, sizeof(RNDICC), 0x09);
seos_challenge_get(RNDICC, sizeof(RNDICC), keys[key_index].keyslot);
select_df_decode(response, (resplen - 2), &ALGORITHM_INFO_value1, &ALGORITHM_INFO_value2, CRYPTOGRAM_encrypted_data, MAC_value);
select_DF_verify(response, resplen, MAC_value, sizeof(MAC_value), ALGORITHM_INFO_value1, key_index);

Expand Down Expand Up @@ -1291,7 +1291,7 @@ static int seos_print_keys(bool verbose) {
if (verbose) {
for (int i = 0; i < ARRAYLEN(keys); i++) {
PrintAndLogEx(INFO, "Key Index........................ " _YELLOW_("%u"), i);
PrintAndLogEx(INFO, "Nonce............................ " _YELLOW_("%s"), sprint_hex(keys[i].nonce, 8));
PrintAndLogEx(INFO, "Keyslot.......................... " _YELLOW_("%u"), keys[i].keyslot);
PrintAndLogEx(INFO, "Privacy Encryption Key........... " _YELLOW_("%s"), sprint_hex(keys[i].privEncKey, 16));
PrintAndLogEx(INFO, "Privacy MAC Key.................. " _YELLOW_("%s"), sprint_hex(keys[i].privMacKey, 16));
PrintAndLogEx(INFO, "Read Key......................... " _YELLOW_("%s"), sprint_hex(keys[i].readKey, 16));
Expand All @@ -1300,15 +1300,15 @@ static int seos_print_keys(bool verbose) {
PrintAndLogEx(INFO, "----------------------------");
}
} else {
PrintAndLogEx(INFO, "idx| key");
PrintAndLogEx(INFO, "---+------------------------");
PrintAndLogEx(INFO, "idx|slot| key");
PrintAndLogEx(INFO, "---+----+------------------------");
for (uint8_t i = 0; i < ARRAYLEN(keys); i++) {
if (memcmp(keys[i].privEncKey, zeros, sizeof(zeros)) == 0)
PrintAndLogEx(INFO, " %u |", i);
PrintAndLogEx(INFO, " %u | |", i);
else
PrintAndLogEx(INFO, " %u | " _YELLOW_("%s"), i, sprint_hex(keys[i].nonce, 8));
PrintAndLogEx(INFO, " %u | " _YELLOW_("% 2u") " | " _YELLOW_("%s"), i, keys[i].keyslot, sprint_hex(keys[i].readKey, 8));
}
PrintAndLogEx(INFO, "---+------------------------");
PrintAndLogEx(INFO, "---+----+------------------------");
Comment on lines -1303 to +1311
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured also showing an actual key would be useful, rather than just the slot number. Should there be logic here to show a different key based on the selected keyslot, or maybe show one of the privacy keys instead?

};
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
Expand All @@ -1335,12 +1335,12 @@ static int seos_load_keys(char *filename) {

size_t i = 0;
for (; i < bytes_read / kn; i++) {
memcpy(keys[i].nonce, dump + (i * kn), 8);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could also be done like:
keys[i].nonce = *(dump + (i * kn));
I did it this way to keep it more similar to the rest of the block, but let me know if you'd rather change it.

memcpy(keys[i].privEncKey, dump + ((i * kn) + 8), 16);
memcpy(keys[i].privMacKey, dump + ((i * kn) + 24), 16);
memcpy(keys[i].readKey, dump + ((i * kn) + 40), 16);
memcpy(keys[i].writeKey, dump + ((i * kn) + 56), 16);
memcpy(keys[i].adminKey, dump + ((i * kn) + 72), 16);
memcpy(&keys[i].keyslot, dump + (i * kn), 1);
memcpy(keys[i].privEncKey, dump + ((i * kn) + 1), 16);
memcpy(keys[i].privMacKey, dump + ((i * kn) + 17), 16);
memcpy(keys[i].readKey, dump + ((i * kn) + 33), 16);
memcpy(keys[i].writeKey, dump + ((i * kn) + 49), 16);
memcpy(keys[i].adminKey, dump + ((i * kn) + 65), 16);
Comment on lines +1338 to +1343
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not as relevant to this PR, but maybe it would make sense to have the offsets instead stored as a variable and incremented by each memcpy since these odd numbers look weird?

Alternatively, does it make more sense to move the keyslot to the end of the struct so all the rest of the values are nice even multiples of 8?

}

free(dump);
Expand Down Expand Up @@ -1375,9 +1375,9 @@ static int CmdHfSeosGDF(const char *Cmd) {
CLIParserInit(&ctx, "hf seos gdf",
"Get Global Data File (GDF) from SEOS card\n\n"
"By default:\n"
" - Key Index: 0\n",
" - Key Index: 3\n",
"hf seos gdf"
"hf seos gdf --ki 0"
"hf seos gdf --ki 3"
);
void *argtable[] = {
arg_param_begin,
Expand All @@ -1386,7 +1386,7 @@ static int CmdHfSeosGDF(const char *Cmd) {
};
CLIExecWithReturn(ctx, Cmd, argtable, true);

int key_index = arg_get_int_def(ctx, 1, 0);
int key_index = arg_get_int_def(ctx, 1, 3);

CLIParserFree(ctx);
return seos_global_df(key_index);
Expand Down Expand Up @@ -1513,15 +1513,16 @@ static int CmdHfSeosManageKeys(const char *Cmd) {
"Manage SEOS Keys in client memory, keys are required to authenticate with SEOS cards\n",
"hf seos managekeys -p\n"
"hf seos managekeys -p -v\n"
"hf seos managekeys --ki 0 --nonce 0102030405060708 -> Set nonce value at key index 0\n"
"hf seos managekeys --load -f mykeys.bin -p -> load from file and prints keys\n"
"hf seos managekeys --save -f mykeys.bin -> saves keys to file\n"
"hf seos managekeys --ki 0 --keyslot 1 -> Set keyslot value at key index 0\n"
"hf seos managekeys --ki 1 --read 0102030405060708 -> Set read key value at key index 1\n"
Comment on lines +1516 to +1517
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured I'd switch the line over to the read key, since it's more similar to the original message (showing how you can input a hex string) and it applies to more values. I added an additional line for the keyslot, but I'm not sure if this is actually necessary.

"hf seos managekeys --load -f mykeys.bin -p -> load from file and prints keys\n"
"hf seos managekeys --save -f mykeys.bin -> saves keys to file\n"
);

void *argtable[] = {
arg_param_begin,
arg_int0(NULL, "ki", "<dec>", "Specify key index to set key in memory"),
arg_str0(NULL, "nonce", "<hex>", "Nonce value as 8 hex bytes"),
arg_int0(NULL, "keyslot", "<dec>", "Keyslot value"),
arg_str0(NULL, "privenc", "<hex>", "Privacy Encryption key as 16 hex bytes"),
arg_str0(NULL, "privmac", "<hex>", "Privacy MAC key as 16 hex bytes"),
arg_str0(NULL, "read", "<hex>", "Undiversified Read key as 16 hex bytes"),
Expand All @@ -1542,22 +1543,20 @@ static int CmdHfSeosManageKeys(const char *Cmd) {
char filename[FILE_PATH_SIZE] = {0};
uint8_t operation = 0;

uint8_t nonce[8] = {0};
uint8_t privenc[16] = {0};
uint8_t privmac[16] = {0};
uint8_t read[16] = {0};
uint8_t write[16] = {0};
uint8_t admin[16] = {0};
int nonce_len = 0;
int privenc_len = 0;
int privmac_len = 0;
int read_len = 0;
int write_len = 0;
int admin_len = 0;

int key_index = arg_get_int_def(ctx, 1, -1);
int keyslot = arg_get_int_def(ctx, 2, -1);

CLIGetHexWithReturn(ctx, 2, nonce, &nonce_len);
CLIGetHexWithReturn(ctx, 3, privenc, &privenc_len);
CLIGetHexWithReturn(ctx, 4, privmac, &privmac_len);
CLIGetHexWithReturn(ctx, 5, read, &read_len);
Expand All @@ -1569,8 +1568,8 @@ static int CmdHfSeosManageKeys(const char *Cmd) {
if (key_index >= 0) {
operation += 3;
if (key_index < 4) {
if (nonce_len != 0) {
PrintAndLogEx(SUCCESS, "Current value for nonce[%d] " _GREEN_("%s"), key_index, sprint_hex_inrow(keys[key_index].nonce, 8));
if (keyslot != -1) {
PrintAndLogEx(SUCCESS, "Current value for keyslot[%d] " _GREEN_("%u"), key_index, keys[key_index].keyslot);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everywhere the keyslot is used internally, it's fetched with a %02X format string, but I think it's better displayed to the user in decimal. Is this actually true or should I swap it back to hex everywhere?

}
if (privenc_len != 0) {
PrintAndLogEx(SUCCESS, "Current value for Priv Enc[%d] " _GREEN_("%s"), key_index, sprint_hex_inrow(keys[key_index].privEncKey, 16));
Expand Down Expand Up @@ -1620,16 +1619,16 @@ static int CmdHfSeosManageKeys(const char *Cmd) {
PrintAndLogEx(ERR, "You must enter a filename when loading or saving\n");
return PM3_EINVARG;
}
if (((nonce_len > 0) || (privenc_len > 0) || (privmac_len > 0) || (read_len > 0) || (write_len > 0) || (admin_len > 0)) && key_index == -1) {
if (((keyslot != -1) || (privenc_len > 0) || (privmac_len > 0) || (read_len > 0) || (write_len > 0) || (admin_len > 0)) && key_index == -1) {
PrintAndLogEx(ERR, "Please specify key index when specifying key");
return PM3_EINVARG;
}

switch (operation) {
case 3:
if (nonce_len != 0) {
memcpy(keys[key_index].nonce, nonce, 8);
PrintAndLogEx(SUCCESS, "New value for nonce[%d] " _GREEN_("%s"), key_index, sprint_hex_inrow(keys[key_index].nonce, 8));
if (keyslot != -1) {
keys[key_index].keyslot = keyslot;
PrintAndLogEx(SUCCESS, "New value for keyslot[%d] " _GREEN_("%u"), key_index, keys[key_index].keyslot);
}
if (privenc_len != 0) {
memcpy(keys[key_index].privEncKey, privenc, 16);
Expand Down
Loading