-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
[hf seos] Make keyslot configurable #3044
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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]; | ||
|
|
@@ -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 | ||
|
|
@@ -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]; | ||
|
|
@@ -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); | ||
|
|
@@ -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; | ||
|
|
@@ -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); | ||
|
|
||
|
|
@@ -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)); | ||
|
|
@@ -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, "---+----+------------------------"); | ||
| }; | ||
| PrintAndLogEx(NORMAL, ""); | ||
| return PM3_SUCCESS; | ||
|
|
@@ -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); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could also be done like: |
||
| 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
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
|
|
@@ -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, | ||
|
|
@@ -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); | ||
|
|
@@ -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
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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"), | ||
|
|
@@ -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); | ||
|
|
@@ -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); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Everywhere the keyslot is used internally, it's fetched with a |
||
| } | ||
| if (privenc_len != 0) { | ||
| PrintAndLogEx(SUCCESS, "Current value for Priv Enc[%d] " _GREEN_("%s"), key_index, sprint_hex_inrow(keys[key_index].privEncKey, 16)); | ||
|
|
@@ -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); | ||
|
|
||
There was a problem hiding this comment.
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?