mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-11-10 17:49:32 +08:00
183 lines
6.7 KiB
C
183 lines
6.7 KiB
C
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 2012 Frederik Möllers
|
|
//
|
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
|
// the license.
|
|
//-----------------------------------------------------------------------------
|
|
// Commands related to the German electronic Identification Card
|
|
//-----------------------------------------------------------------------------
|
|
#include "cmdhfepa.h"
|
|
|
|
static int CmdHelp(const char *Cmd);
|
|
|
|
// Perform (part of) the PACE protocol
|
|
static int CmdHFEPACollectPACENonces(const char *Cmd) {
|
|
// requested nonce size
|
|
uint32_t m = 0;
|
|
// requested number of Nonces
|
|
uint32_t n = 0;
|
|
// delay between requests
|
|
uint32_t d = 0;
|
|
|
|
sscanf(Cmd, "%u %u %u", &m, &n, &d);
|
|
|
|
// values are expected to be > 0
|
|
m = m > 0 ? m : 1;
|
|
n = n > 0 ? n : 1;
|
|
|
|
PrintAndLogEx(NORMAL, "Collecting %u %u byte nonces", n, m);
|
|
PrintAndLogEx(NORMAL, "Start: %" PRIu64, msclock() / 1000);
|
|
// repeat n times
|
|
for (uint32_t i = 0; i < n; i++) {
|
|
// execute PACE
|
|
UsbCommand c = {CMD_EPA_PACE_COLLECT_NONCE, {(int)m, 0, 0}, {{0}}};
|
|
clearCommandBuffer();
|
|
SendCommand(&c);
|
|
UsbCommand resp;
|
|
WaitForResponse(CMD_ACK, &resp);
|
|
|
|
// check if command failed
|
|
if (resp.arg[0] != 0) {
|
|
PrintAndLogEx(FAILED, "Error in step %d, Return code: %d", resp.arg[0], (int)resp.arg[1]);
|
|
} else {
|
|
size_t nonce_length = resp.arg[1];
|
|
char *nonce = (char *) calloc(2 * nonce_length + 1, sizeof(uint8_t));
|
|
for (int j = 0; j < nonce_length; j++) {
|
|
sprintf(nonce + (2 * j), "%02X", resp.d.asBytes[j]);
|
|
}
|
|
// print nonce
|
|
PrintAndLogEx(NORMAL, "Length: %d, Nonce: %s", nonce_length, nonce);
|
|
free(nonce);
|
|
}
|
|
if (i < n - 1) {
|
|
sleep(d);
|
|
}
|
|
}
|
|
PrintAndLogEx(NORMAL, "End: %" PRIu64, msclock() / 1000);
|
|
return 1;
|
|
}
|
|
|
|
// perform the PACE protocol by replaying APDUs
|
|
static int CmdHFEPAPACEReplay(const char *Cmd) {
|
|
// the 4 APDUs which are replayed + their lengths
|
|
uint8_t msesa_apdu[41] = {0}, gn_apdu[8] = {0}, map_apdu[75] = {0};
|
|
uint8_t pka_apdu[75] = {0}, ma_apdu[18] = {0}, apdu_lengths[5] = {0};
|
|
// pointers to the arrays to be able to iterate
|
|
uint8_t *apdus[] = {msesa_apdu, gn_apdu, map_apdu, pka_apdu, ma_apdu};
|
|
|
|
// usage message
|
|
static const char *usage_msg =
|
|
"Please specify 5 APDUs separated by spaces. "
|
|
"Example:\n preplay 0022C1A4 1068000000 1086000002 1234ABCDEF 1A2B3C4D";
|
|
|
|
// Proxmark response
|
|
UsbCommand resp;
|
|
|
|
int skip = 0, skip_add = 0, scan_return;
|
|
// for each APDU
|
|
for (int i = 0; i < sizeof(apdu_lengths); i++) {
|
|
// scan to next space or end of string
|
|
while (Cmd[skip] != ' ' && Cmd[skip] != '\0') {
|
|
// convert
|
|
scan_return = sscanf(Cmd + skip,
|
|
"%2X%n",
|
|
(unsigned int *)(apdus[i] + apdu_lengths[i]),
|
|
&skip_add
|
|
);
|
|
|
|
if (scan_return < 1) {
|
|
PrintAndLogEx(NORMAL, (char *)usage_msg);
|
|
PrintAndLogEx(WARNING, "Not enough APDUs! Try again!");
|
|
return 0;
|
|
}
|
|
skip += skip_add;
|
|
apdu_lengths[i]++;
|
|
}
|
|
|
|
// break on EOF
|
|
if (Cmd[skip] == '\0') {
|
|
if (i < sizeof(apdu_lengths) - 1) {
|
|
|
|
PrintAndLogEx(NORMAL, (char *)usage_msg);
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
// skip the space
|
|
skip++;
|
|
}
|
|
|
|
// transfer the APDUs to the Proxmark
|
|
UsbCommand usb_cmd;
|
|
usb_cmd.cmd = CMD_EPA_PACE_REPLAY;
|
|
for (int i = 0; i < sizeof(apdu_lengths); i++) {
|
|
// APDU number
|
|
usb_cmd.arg[0] = i + 1;
|
|
// transfer the APDU in several parts if necessary
|
|
for (int j = 0; j * sizeof(usb_cmd.d.asBytes) < apdu_lengths[i]; j++) {
|
|
// offset into the APDU
|
|
usb_cmd.arg[1] = j * sizeof(usb_cmd.d.asBytes);
|
|
// amount of data in this packet
|
|
int packet_length = apdu_lengths[i] - (j * sizeof(usb_cmd.d.asBytes));
|
|
if (packet_length > sizeof(usb_cmd.d.asBytes)) {
|
|
packet_length = sizeof(usb_cmd.d.asBytes);
|
|
}
|
|
usb_cmd.arg[2] = packet_length;
|
|
|
|
memcpy(usb_cmd.d.asBytes, // + (j * sizeof(usb_cmd.d.asBytes)),
|
|
apdus[i] + (j * sizeof(usb_cmd.d.asBytes)),
|
|
packet_length);
|
|
|
|
clearCommandBuffer();
|
|
SendCommand(&usb_cmd);
|
|
WaitForResponse(CMD_ACK, &resp);
|
|
if (resp.arg[0] != 0) {
|
|
PrintAndLogEx(WARNING, "Transfer of APDU #%d Part %d failed!", i, j);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// now perform the replay
|
|
usb_cmd.arg[0] = 0;
|
|
clearCommandBuffer();
|
|
SendCommand(&usb_cmd);
|
|
WaitForResponse(CMD_ACK, &resp);
|
|
if (resp.arg[0] != 0) {
|
|
PrintAndLogEx(NORMAL, "\nPACE replay failed in step %u!", (uint32_t)resp.arg[0]);
|
|
PrintAndLogEx(NORMAL, "Measured times:");
|
|
PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.d.asDwords[0]);
|
|
PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.d.asDwords[1]);
|
|
PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.d.asDwords[2]);
|
|
PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.d.asDwords[3]);
|
|
PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.d.asDwords[4]);
|
|
} else {
|
|
PrintAndLogEx(NORMAL, "PACE replay successfull!");
|
|
PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.d.asDwords[0]);
|
|
PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.d.asDwords[1]);
|
|
PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.d.asDwords[2]);
|
|
PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.d.asDwords[3]);
|
|
PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.d.asDwords[4]);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static command_t CommandTable[] = {
|
|
{"help", CmdHelp, 1, "This help"},
|
|
{"cnonces", CmdHFEPACollectPACENonces, 0, "<m> <n> <d> Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses"},
|
|
{"preplay", CmdHFEPAPACEReplay, 0, "<mse> <get> <map> <pka> <ma> Perform PACE protocol by replaying given APDUs"},
|
|
{NULL, NULL, 0, NULL}
|
|
};
|
|
|
|
static int CmdHelp(const char *Cmd) {
|
|
(void)Cmd; // Cmd is not used so far
|
|
CmdsHelp(CommandTable);
|
|
return 0;
|
|
}
|
|
|
|
int CmdHFEPA(const char *Cmd) {
|
|
clearCommandBuffer();
|
|
CmdsParse(CommandTable, Cmd);
|
|
return 0;
|
|
}
|