proxmark3/client/cmdhfepa.c

182 lines
6.8 KiB
C
Raw Normal View History

//-----------------------------------------------------------------------------
// 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
//-----------------------------------------------------------------------------
2017-07-28 07:47:21 +08:00
#include "cmdhfepa.h"
static int CmdHelp(const char *Cmd);
// Perform (part of) the PACE protocol
static int CmdHFEPACollectPACENonces(const char *Cmd) {
2019-03-10 06:35:06 +08:00
// 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);
2019-03-10 07:00:59 +08:00
PrintAndLogEx(NORMAL, "Start: %" PRIu64, msclock() / 1000);
2019-03-10 06:35:06 +08:00
// repeat n times
for (uint32_t i = 0; i < n; i++) {
// execute PACE
clearCommandBuffer();
SendCommandMIX(CMD_EPA_PACE_COLLECT_NONCE, (int)m, 0, 0, NULL, 0);
2019-04-18 18:43:35 +08:00
PacketResponseNG resp;
2019-03-10 07:00:59 +08:00
WaitForResponse(CMD_ACK, &resp);
2019-03-10 06:35:06 +08:00
// check if command failed
2019-04-18 05:44:48 +08:00
if (resp.oldarg[0] != 0) {
PrintAndLogEx(FAILED, "Error in step %d, Return code: %d", resp.oldarg[0], (int)resp.oldarg[1]);
2019-03-10 06:35:06 +08:00
} else {
2019-04-18 05:44:48 +08:00
size_t nonce_length = resp.oldarg[1];
2019-03-10 06:35:06 +08:00
char *nonce = (char *) calloc(2 * nonce_length + 1, sizeof(uint8_t));
2019-03-10 07:00:59 +08:00
for (int j = 0; j < nonce_length; j++) {
2019-04-18 05:44:48 +08:00
sprintf(nonce + (2 * j), "%02X", resp.data.asBytes[j]);
2019-03-10 06:35:06 +08:00
}
// print nonce
PrintAndLogEx(NORMAL, "Length: %d, Nonce: %s", nonce_length, nonce);
free(nonce);
}
if (i < n - 1) {
sleep(d);
}
}
2019-03-10 07:00:59 +08:00
PrintAndLogEx(NORMAL, "End: %" PRIu64, msclock() / 1000);
2019-03-10 06:35:06 +08:00
return 1;
}
// perform the PACE protocol by replaying APDUs
static int CmdHFEPAPACEReplay(const char *Cmd) {
2019-03-10 06:35:06 +08:00
// the 4 APDUs which are replayed + their lengths
2019-04-07 22:30:02 +08:00
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};
2019-03-10 06:35:06 +08:00
// 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
2019-04-18 18:43:35 +08:00
PacketResponseNG resp;
2019-03-10 06:35:06 +08:00
2019-04-07 22:30:02 +08:00
int skip = 0, skip_add = 0, scan_return;
2019-03-10 06:35:06 +08:00
// 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
2019-04-07 22:30:02 +08:00
scan_return = sscanf(Cmd + skip,
2019-04-10 15:38:33 +08:00
"%2X%n",
2019-03-10 07:00:59 +08:00
(unsigned int *)(apdus[i] + apdu_lengths[i]),
2019-04-07 22:30:02 +08:00
&skip_add
2019-04-10 15:38:33 +08:00
);
2019-03-10 06:35:06 +08:00
if (scan_return < 1) {
PrintAndLogEx(NORMAL, (char *)usage_msg);
PrintAndLogEx(WARNING, "Not enough APDUs! Try again!");
return 0;
}
skip += skip_add;
apdu_lengths[i]++;
2019-03-10 06:35:06 +08:00
}
// 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
uint8_t data[PM3_CMD_DATA_SIZE];
2019-05-09 02:13:07 +08:00
// fast push mode
conn.block_after_ACK = true;
2019-03-10 06:35:06 +08:00
for (int i = 0; i < sizeof(apdu_lengths); i++) {
// transfer the APDU in several parts if necessary
for (int j = 0; j * sizeof(data) < apdu_lengths[i]; j++) {
2019-03-10 06:35:06 +08:00
// amount of data in this packet
int packet_length = apdu_lengths[i] - (j * sizeof(data));
if (packet_length > sizeof(data)) {
packet_length = sizeof(data);
2019-03-10 06:35:06 +08:00
}
2019-05-09 02:13:07 +08:00
if ((i == sizeof(apdu_lengths)-1) && (j * sizeof(data) >= apdu_lengths[i] - 1)) {
// Disable fast mode on last packet
conn.block_after_ACK = false;
}
memcpy(data, // + (j * sizeof(data)),
apdus[i] + (j * sizeof(data)),
2019-03-10 06:35:06 +08:00
packet_length);
clearCommandBuffer();
// arg0: APDU number
// arg1: offset into the APDU
SendCommandOLD(CMD_EPA_PACE_REPLAY, i + 1, j * sizeof(data), packet_length, data, packet_length);
2019-03-10 06:35:06 +08:00
WaitForResponse(CMD_ACK, &resp);
2019-04-18 05:44:48 +08:00
if (resp.oldarg[0] != 0) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx(WARNING, "Transfer of APDU #%d Part %d failed!", i, j);
return 0;
}
}
}
// now perform the replay
clearCommandBuffer();
SendCommandNG(CMD_EPA_PACE_REPLAY, NULL, 0);
2019-03-10 06:35:06 +08:00
WaitForResponse(CMD_ACK, &resp);
2019-04-18 05:44:48 +08:00
if (resp.oldarg[0] != 0) {
PrintAndLogEx(NORMAL, "\nPACE replay failed in step %u!", (uint32_t)resp.oldarg[0]);
2019-03-10 06:35:06 +08:00
PrintAndLogEx(NORMAL, "Measured times:");
2019-04-18 05:44:48 +08:00
PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.data.asDwords[0]);
PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.data.asDwords[1]);
PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.data.asDwords[2]);
PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]);
PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]);
2019-03-10 06:35:06 +08:00
} else {
PrintAndLogEx(NORMAL, "PACE replay successfull!");
2019-04-18 05:44:48 +08:00
PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.data.asDwords[0]);
PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.data.asDwords[1]);
PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.data.asDwords[2]);
PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]);
PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]);
2019-03-10 06:35:06 +08:00
}
return 1;
}
2017-09-29 04:33:55 +08:00
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"cnonces", CmdHFEPACollectPACENonces, IfPm3Iso14443, "<m> <n> <d> Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses"},
{"preplay", CmdHFEPAPACEReplay, IfPm3Iso14443, "<mse> <get> <map> <pka> <ma> Perform PACE protocol by replaying given APDUs"},
{NULL, NULL, NULL, NULL}
};
static int CmdHelp(const char *Cmd) {
2019-04-10 18:23:40 +08:00
(void)Cmd; // Cmd is not used so far
2019-03-10 06:35:06 +08:00
CmdsHelp(CommandTable);
return 0;
}
int CmdHFEPA(const char *Cmd) {
2019-03-10 06:35:06 +08:00
clearCommandBuffer();
2019-04-19 06:47:51 +08:00
return CmdsParse(CommandTable, Cmd);
2019-03-12 07:12:26 +08:00
}