diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index 1a37f8b19..ee5484fc9 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -1186,38 +1186,36 @@ static int CmdEM4x70AutoRecover(const char *Cmd) { // 1. Verify passed parameters authenticate with the tag (safety check) // lf em 4x70 auth --rnd --frn - if (PM3_SUCCESS == result) { - PrintAndLogEx(INFO, "Step 1. Verifying passed parameters authenticate with the tag (safety check)"); - PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 auth --rnd %s --frn %s"), rnd_string, frn_string); + PrintAndLogEx(INFO, "Step 1. Verifying passed parameters authenticate with the tag (safety check)"); + PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 auth --rnd %s --frn %s"), rnd_string, frn_string); - em4x70_cmd_input_auth_t opts_auth = { - .use_parity = opts.parity, - .rn = opts.nonce, - .frn = opts.frn, - }; + em4x70_cmd_input_auth_t opts_auth = { + .use_parity = opts.parity, + .rn = opts.nonce, + .frn = opts.frn, + }; - em4x70_cmd_output_auth_t tag_grn; + em4x70_cmd_output_auth_t tag_grn; - result = auth_em4x70(&opts_auth, &tag_grn); + result = auth_em4x70(&opts_auth, &tag_grn); - if (PM3_ETIMEOUT == result) { - PrintAndLogEx(WARNING, "timeout while waiting for reply"); - return result; - } else if (PM3_SUCCESS != result) { - PrintAndLogEx(FAILED, "Authenticating with provided values ( " _RED_("fail") " )"); - return result; - } else if (memcmp(&opts.grn, &tag_grn, sizeof(ID48LIB_GRN)) != 0) { - PrintAndLogEx(FAILED, "Authenticating with new key returned %02x %02x %02x" - , tag_grn.grn.grn[0] - , tag_grn.grn.grn[1] - , tag_grn.grn.grn[2] - ); - PrintAndLogEx(FAILED, "Expected %s [maybe 5 lsb of key wrong?] ( " _RED_("fail") " )", grn_string); - result = PM3_EWRONGANSWER; - return result; - } - last_successful_step = 1; + if (PM3_ETIMEOUT == result) { + PrintAndLogEx(WARNING, "timeout while waiting for reply"); + return result; + } else if (PM3_SUCCESS != result) { + PrintAndLogEx(FAILED, "Authenticating with provided values ( " _RED_("fail") " )"); + return result; + } else if (memcmp(&opts.grn, &tag_grn, sizeof(ID48LIB_GRN)) != 0) { + PrintAndLogEx(FAILED, "Authenticating with new key returned %02x %02x %02x" + , tag_grn.grn.grn[0] + , tag_grn.grn.grn[1] + , tag_grn.grn.grn[2] + ); + PrintAndLogEx(FAILED, "Expected %s [maybe 5 lsb of key wrong?] ( " _RED_("fail") " )", grn_string); + result = PM3_EWRONGANSWER; + return result; } + last_successful_step = 1; // 2/3/4. Brute force the key bits in block 7,8,9 // lf em 4x70 write -b N -d 0000 @@ -1232,98 +1230,88 @@ static int CmdEM4x70AutoRecover(const char *Cmd) { em4x70_cmd_output_brute_t brute = {0}; // lf em 4x70 write -b N -d 0000 - if (PM3_SUCCESS == result) { - PrintAndLogEx(INFO, "Step %d. Brute force the key bits in block %d", step, block); - PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 write -b %d -d 0000"), block); + PrintAndLogEx(INFO, "Step %d. Brute force the key bits in block %d", step, block); + PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 write -b %d -d 0000"), block); - em4x70_cmd_input_writeblock_t opt_write_zeros = { - .use_parity = opts.parity, - .block = block, - .value = {0x00, 0x00}, - }; + em4x70_cmd_input_writeblock_t opt_write_zeros = { + .use_parity = opts.parity, + .block = block, + .value = {0x00, 0x00}, + }; - result = writeblock_em4x70(&opt_write_zeros, &tag_info); + result = writeblock_em4x70(&opt_write_zeros, &tag_info); - if (PM3_ETIMEOUT == result) { - PrintAndLogEx(FAILED, "timeout while waiting for reply"); - PrintAndLogEx(HINT, "Hint: Block %d data may have been overwritten. Manually restart at step %d", block, step); - return result; - } else if (PM3_SUCCESS != result) { - PrintAndLogEx(FAILED, "Writing block %d ( " _RED_("fail") " )", block); - PrintAndLogEx(HINT, "Hint: Block %d data was overwritten. Manually restart at step %d", block, step); - return result; - } + if (PM3_ETIMEOUT == result) { + PrintAndLogEx(FAILED, "timeout while waiting for reply"); + PrintAndLogEx(HINT, "Hint: Block %d data may have been overwritten. Manually restart at step %d", block, step); + return result; + } else if (PM3_SUCCESS != result) { + PrintAndLogEx(FAILED, "Writing block %d ( " _RED_("fail") " )", block); + PrintAndLogEx(HINT, "Hint: Block %d data was overwritten. Manually restart at step %d", block, step); + return result; } // lf em 4x70 brute -b N --rnd --frn - if (PM3_SUCCESS == result) { - PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 brute -b %d --rnd %s --frn %s"), block, rnd_string, frn_string); + PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 brute -b %d --rnd %s --frn %s"), block, rnd_string, frn_string); - em4x70_cmd_input_brute_t opts_brute = { - .use_parity = opts.parity, - .block = block, - .rn = opts.nonce, - .frn = opts.frn, - .partial_key_start = {0}, - }; + em4x70_cmd_input_brute_t opts_brute = { + .use_parity = opts.parity, + .block = block, + .rn = opts.nonce, + .frn = opts.frn, + .partial_key_start = {0}, + }; - result = brute_em4x70(&opts_brute, &brute); + result = brute_em4x70(&opts_brute, &brute); - if (PM3_ETIMEOUT == result) { - PrintAndLogEx(FAILED, "timeout while waiting for reply"); - PrintAndLogEx(HINT, "Hint: Block %d data was overwritten. Manually restart at step %d", block, step); - return result; - } else if (PM3_SUCCESS != result) { - PrintAndLogEx(FAILED, "Writing block %d ( " _RED_("fail") " )", block); - PrintAndLogEx(HINT, "Hint: Block %d data was overwritten. Manually restart at step %d", block, step); - return result; - } else { - PrintAndLogEx(INFO, " Found: Partial key in block %d is " _GREEN_("%02X%02X") - , block - , brute.partial_key[0] - , brute.partial_key[1] - ); - // Save the partial key... - if (block == 9) { - opts.key.k[0] = brute.partial_key[0]; - opts.key.k[1] = brute.partial_key[1]; - } else if (block == 8) { - opts.key.k[2] = brute.partial_key[0]; - opts.key.k[3] = brute.partial_key[1]; - } else if (block == 7) { - opts.key.k[4] = brute.partial_key[0]; - opts.key.k[5] = brute.partial_key[1]; - } + if (PM3_ETIMEOUT == result) { + PrintAndLogEx(FAILED, "timeout while waiting for reply"); + PrintAndLogEx(HINT, "Hint: Block %d data was overwritten. Manually restart at step %d", block, step); + return result; + } else if (PM3_SUCCESS != result) { + PrintAndLogEx(FAILED, "Writing block %d ( " _RED_("fail") " )", block); + PrintAndLogEx(HINT, "Hint: Block %d data was overwritten. Manually restart at step %d", block, step); + return result; + } else { + PrintAndLogEx(INFO, " Found: Partial key in block %d is " _GREEN_("%02X%02X") + , block + , brute.partial_key[0] + , brute.partial_key[1] + ); + // Save the partial key... + if (block == 9) { + opts.key.k[0] = brute.partial_key[0]; + opts.key.k[1] = brute.partial_key[1]; + } else if (block == 8) { + opts.key.k[2] = brute.partial_key[0]; + opts.key.k[3] = brute.partial_key[1]; + } else if (block == 7) { + opts.key.k[4] = brute.partial_key[0]; + opts.key.k[5] = brute.partial_key[1]; } } // lf em 4x70 write -b N -d - if (PM3_SUCCESS == result) { - PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 write -b %d -d %02X%02X"), block, brute.partial_key[0], brute.partial_key[1]); + PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 write -b %d -d %02X%02X"), block, brute.partial_key[0], brute.partial_key[1]); - em4x70_cmd_input_writeblock_t opt_write_zeros = { - .use_parity = opts.parity, - .block = block, - .value = {brute.partial_key[0], brute.partial_key[1]}, - }; + em4x70_cmd_input_writeblock_t opt_write_zeros2 = { + .use_parity = opts.parity, + .block = block, + .value = {brute.partial_key[0], brute.partial_key[1]}, + }; - result = writeblock_em4x70(&opt_write_zeros, &tag_info); + result = writeblock_em4x70(&opt_write_zeros2, &tag_info); - if (PM3_ETIMEOUT == result) { - PrintAndLogEx(FAILED, "timeout while waiting for reply"); - PrintAndLogEx(HINT, "Hint: Block %d data (" _GREEN_("%02X%02X") ") may need to be rewritten", block, brute.partial_key[0], brute.partial_key[1]); - return result; - } else if (PM3_SUCCESS != result) { - PrintAndLogEx(FAILED, "Writing block %d ( " _RED_("fail") " )", block); - PrintAndLogEx(HINT, "Hint: Block %d data (" _GREEN_("%02X%02X") ") may need to be rewritten", block, brute.partial_key[0], brute.partial_key[1]); - return result; - } + if (PM3_ETIMEOUT == result) { + PrintAndLogEx(FAILED, "timeout while waiting for reply"); + PrintAndLogEx(HINT, "Hint: Block %d data (" _GREEN_("%02X%02X") ") may need to be rewritten", block, brute.partial_key[0], brute.partial_key[1]); + return result; + } else if (PM3_SUCCESS != result) { + PrintAndLogEx(FAILED, "Writing block %d ( " _RED_("fail") " )", block); + PrintAndLogEx(HINT, "Hint: Block %d data (" _GREEN_("%02X%02X") ") may need to be rewritten", block, brute.partial_key[0], brute.partial_key[1]); + return result; } - if (PM3_SUCCESS == result) { - last_successful_step = step; - } else { - break; - } + last_successful_step = step; } // The good news is that, if the above succeeded, then from this point forward, the tag remains in a known-good state. @@ -1332,108 +1320,102 @@ static int CmdEM4x70AutoRecover(const char *Cmd) { // 5. Recover potential values of the lower 48 bits of the key // lf em 4x70 recover --key --rnd --frn - if (PM3_SUCCESS == result) { - PrintAndLogEx(INFO, "Step 5. Recover potential values of the lower 48 bits of the key"); - PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 recover --key %s --rnd %s --frn %s --grn %s"), key_string, rnd_string, frn_string, grn_string); + PrintAndLogEx(INFO, "Step 5. Recover potential values of the lower 48 bits of the key"); + PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 recover --key %s --rnd %s --frn %s --grn %s"), key_string, rnd_string, frn_string, grn_string); - result = recover_em4x70(&opts, &data); + result = recover_em4x70(&opts, &data); - if (PM3_EOVFLOW == result) { - PrintAndLogEx(ERR, "Found more than %d potential keys. This is unexpected and likely a code failure.", MAXIMUM_ID48_RECOVERED_KEY_COUNT); - return result; - } else if (PM3_SUCCESS != result) { - PrintAndLogEx(ERR, "No potential keys recovered. This is unexpected and likely a code failure."); - return result; - } else { - PrintAndLogEx(INFO, " Found " _GREEN_("%d") " potential keys", data.potential_key_count); - for (uint8_t idx = 0; idx < data.potential_key_count; ++idx) { - ID48LIB_KEY q = data.potential_keys[idx]; - PrintAndLogEx(DEBUG, " Potential Key %d: %s %02X%02X%02X%02X%02X%02X" - , idx - , key_string - , q.k[ 6] - , q.k[ 7] - , q.k[ 8] - , q.k[ 9] - , q.k[10] - , q.k[11] - ); - } - last_successful_step = 5; + if (PM3_EOVFLOW == result) { + PrintAndLogEx(ERR, "Found more than %d potential keys. This is unexpected and likely a code failure.", MAXIMUM_ID48_RECOVERED_KEY_COUNT); + return result; + } else if (PM3_SUCCESS != result) { + PrintAndLogEx(ERR, "No potential keys recovered. This is unexpected and likely a code failure."); + return result; + } else { + PrintAndLogEx(INFO, " Found " _GREEN_("%d") " potential keys", data.potential_key_count); + for (uint8_t idx = 0; idx < data.potential_key_count; ++idx) { + ID48LIB_KEY q = data.potential_keys[idx]; + PrintAndLogEx(DEBUG, " Potential Key %d: %s %02X%02X%02X%02X%02X%02X" + , idx + , key_string + , q.k[ 6] + , q.k[ 7] + , q.k[ 8] + , q.k[ 9] + , q.k[10] + , q.k[11] + ); } + last_successful_step = 5; } // 6. Verify which potential key is actually on the tag (using a different rnd/frn combination) // lf em 4x70 auth --rnd --frn - if (PM3_SUCCESS == result) { - PrintAndLogEx(INFO, "Step 6. Verify which potential key is actually on the tag"); + PrintAndLogEx(INFO, "Step 6. Verify which potential key is actually on the tag"); - em4x70_cmd_input_verify_auth_t opts_v = { - .use_parity = opts.parity, - //.rn = {{0}}, - //.frn = {{0}}, - //.grn = {{0}}, - }; + em4x70_cmd_input_verify_auth_t opts_v = { + .use_parity = opts.parity, + //.rn = {{0}}, + //.frn = {{0}}, + //.grn = {{0}}, + }; - // TODO: retry a few time, if >1 key validated with the new nonce - bool continue_loop = true; - bool found_one_key = false; - bool found_more_than_one_key = false; - uint8_t first_validated_key_idx = 0xFF; + // TODO: retry a few time, if >1 key validated with the new nonce + bool continue_loop = true; + bool found_one_key = false; + bool found_more_than_one_key = false; + uint8_t first_validated_key_idx = 0xFF; - for (uint8_t attempt = 0; continue_loop && (attempt < 10); ++attempt) { - continue_loop = false; - found_one_key = false; - found_more_than_one_key = false; - first_validated_key_idx = 0xFF; - fill_buffer_prng_bytes(&opts_v.rn, sizeof(ID48LIB_NONCE)); + for (uint8_t attempt = 0; continue_loop && (attempt < 10); ++attempt) { + continue_loop = false; + found_one_key = false; + found_more_than_one_key = false; + first_validated_key_idx = 0xFF; + fill_buffer_prng_bytes(&opts_v.rn, sizeof(ID48LIB_NONCE)); - for (uint8_t i = 0; i < data.potential_key_count; ++i) { - // generate the alternate frn/grn for this key + nonce combo - id48lib_generator(&data.potential_keys[i], &opts_v.rn, &opts_v.frn, &opts_v.grn); + for (uint8_t i = 0; i < data.potential_key_count; ++i) { + // generate the alternate frn/grn for this key + nonce combo + id48lib_generator(&data.potential_keys[i], &opts_v.rn, &opts_v.frn, &opts_v.grn); - int tmpResult = verify_auth_em4x70(&opts_v); - if (PM3_SUCCESS == tmpResult) { - if (!found_one_key) { - first_validated_key_idx = i; - found_one_key = true; - } else { - found_more_than_one_key = true; - } + int tmpResult = verify_auth_em4x70(&opts_v); + if (PM3_SUCCESS == tmpResult) { + if (!found_one_key) { + first_validated_key_idx = i; + found_one_key = true; + } else { + found_more_than_one_key = true; } } - - if (found_one_key == false) { - PrintAndLogEx(WARNING, "No potential keys validated. Will try again with different nonce"); - continue_loop = true; - msleep(2000); // delay 2 seconds ... in case tag was bumped, etc. - } else if (found_more_than_one_key) { - PrintAndLogEx(WARNING, "Multiple potential keys validated. Will try different nonce"); - continue_loop = true; - msleep(2000); // delay 2 seconds ... in case tag was bumped, etc. - } else { - last_successful_step = 6; - } } - if ((found_one_key == false) || found_more_than_one_key) { - PrintAndLogEx(FAILED, "Unable to recover any of the multiple potential keys"); - PrintAndLogEx(FAILED, "Check tag for good coupling / position!"); - return PM3_EFAILED; + if (found_one_key == false) { + PrintAndLogEx(WARNING, "No potential keys validated. Will try again with different nonce"); + continue_loop = true; + msleep(2000); // delay 2 seconds ... in case tag was bumped, etc. + } else if (found_more_than_one_key) { + PrintAndLogEx(WARNING, "Multiple potential keys validated. Will try different nonce"); + continue_loop = true; + msleep(2000); // delay 2 seconds ... in case tag was bumped, etc. } else { - // print the validated key to the string buffer (for step 7) - ID48LIB_KEY q = data.potential_keys[first_validated_key_idx]; - snprintf(key_string, 25, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - q.k[ 0], q.k[ 1], q.k[ 2], q.k[ 3], q.k[ 4], q.k[ 5], - q.k[ 6], q.k[ 7], q.k[ 8], q.k[ 9], q.k[10], q.k[11] - ); + last_successful_step = 6; } } + + if ((found_one_key == false) || found_more_than_one_key) { + PrintAndLogEx(FAILED, "Unable to recover any of the multiple potential keys"); + PrintAndLogEx(FAILED, "Check tag for good coupling / position!"); + return PM3_EFAILED; + } else { + // print the validated key to the string buffer (for step 7) + ID48LIB_KEY q = data.potential_keys[first_validated_key_idx]; + snprintf(key_string, 25, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + q.k[ 0], q.k[ 1], q.k[ 2], q.k[ 3], q.k[ 4], q.k[ 5], + q.k[ 6], q.k[ 7], q.k[ 8], q.k[ 9], q.k[10], q.k[11] + ); + } // 7. Print the validated key - if (PM3_SUCCESS == result) { - PrintAndLogEx(SUCCESS, "Recovered key... " _GREEN_("%s"), key_string); - last_successful_step = 7; - } + PrintAndLogEx(SUCCESS, "Recovered key... " _GREEN_("%s"), key_string); + last_successful_step = 7; // For posterity, step 7 used to do the following: // 7. Print the validated key --OR-- Print that the tag is still OK --OR-- Print instructions on what to retry to recover tag to a good state