fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / cmdhfepa.c
blob21b8960327fef269d4243893d018cd7b48a18760
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2012 Frederik Möllers
3 //
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
6 // the license.
7 //-----------------------------------------------------------------------------
8 // Commands related to the German electronic Identification Card
9 //-----------------------------------------------------------------------------
10 #include "cmdhfepa.h"
12 #include <string.h>
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <inttypes.h>
16 #include <stdlib.h>
17 #include <ctype.h> // tolower
18 #include "cliparser.h"
19 #include "cmdparser.h" // command_t
20 #include "commonutil.h" // ARRAYLEN
21 #include "comms.h" // clearCommandBuffer
22 #include "ui.h"
23 #include "util_posix.h"
25 static int CmdHelp(const char *Cmd);
27 // Perform (part of) the PACE protocol
28 static int CmdHFEPACollectPACENonces(const char *Cmd) {
29 CLIParserContext *ctx;
30 CLIParserInit(&ctx, "hf epa cnonces",
31 "Tries to collect nonces when doing part of PACE protocol.",
32 "hf epa cnonces --size 4 --num 4 --delay 1");
34 void *argtable[] = {
35 arg_param_begin,
36 arg_int1(NULL, "size", "<dec>", "nonce size"),
37 arg_int1(NULL, "num", "<dec>", "number of nonces to collect"),
38 arg_int1("d", "delay", "<dec>", "delay between attempts"),
39 arg_param_end
41 CLIExecWithReturn(ctx, Cmd, argtable, false);
44 int m = arg_get_int_def(ctx, 1, 0);
45 int n = arg_get_int_def(ctx, 2, 0);
46 int d = arg_get_int_def(ctx, 3, 0);
48 CLIParserFree(ctx);
50 // values are expected to be > 0
51 m = m > 0 ? m : 1;
52 n = n > 0 ? n : 1;
54 PrintAndLogEx(SUCCESS, "Collecting %u %u byte nonces", n, m);
55 PrintAndLogEx(SUCCESS, "Start: %" PRIu64, msclock() / 1000);
57 struct p {
58 uint32_t m;
59 } PACKED payload;
60 payload.m = m;
62 for (uint32_t i = 0; i < n; i++) {
63 // execute PACE
65 PacketResponseNG resp;
66 clearCommandBuffer();
67 SendCommandNG(CMD_HF_EPA_COLLECT_NONCE, (uint8_t *)&payload, sizeof(payload));
69 WaitForResponse(CMD_HF_EPA_COLLECT_NONCE, &resp);
71 // check if command failed
72 if (resp.oldarg[0] != 0) {
73 PrintAndLogEx(FAILED, "Error in step %" PRId64 ", Return code: %" PRId64, resp.oldarg[0], resp.oldarg[1]);
74 } else {
75 size_t nonce_length = resp.oldarg[1];
76 char *nonce = (char *) calloc(2 * nonce_length + 1, sizeof(uint8_t));
77 for (int j = 0; j < nonce_length; j++) {
78 sprintf(nonce + (2 * j), "%02X", resp.data.asBytes[j]);
80 // print nonce
81 PrintAndLogEx(SUCCESS, "Length: %zu, Nonce: %s", nonce_length, nonce);
82 free(nonce);
84 if (i < n - 1) {
85 sleep(d);
89 PrintAndLogEx(SUCCESS, "End: %" PRIu64, msclock() / 1000);
90 return PM3_SUCCESS;
93 // perform the PACE protocol by replaying APDUs
94 static int CmdHFEPAPACEReplay(const char *Cmd) {
95 CLIParserContext *ctx;
96 CLIParserInit(&ctx, "hf epa preplay",
97 "Perform PACE protocol by replaying given APDUs",
98 "hf epa preplay --mse 0022C1A4 --get 1068000000 --map 1086000002 --pka 1234ABCDEF --ma 1A2B3C4D");
100 void *argtable[] = {
101 arg_param_begin,
102 arg_str1(NULL, "mse", "<hex>", "msesa APDU"),
103 arg_str1(NULL, "get", "<hex>", "gn APDU"),
104 arg_str1(NULL, "map", "<hex>", "map APDU"),
105 arg_str1(NULL, "pka", "<hex>", "pka APDU"),
106 arg_str1(NULL, "ma", "<hex>", "ma APDU"),
107 arg_param_end
109 CLIExecWithReturn(ctx, Cmd, argtable, false);
111 int msesa_len = 0;
112 uint8_t msesa_apdu[41] = {0};
113 CLIGetHexWithReturn(ctx, 1, msesa_apdu, &msesa_len);
115 int gn_len = 0;
116 uint8_t gn_apdu[8] = {0};
117 CLIGetHexWithReturn(ctx, 2, gn_apdu, &gn_len);
119 int map_len = 0;
120 uint8_t map_apdu[75] = {0};
121 CLIGetHexWithReturn(ctx, 3, map_apdu, &map_len);
123 int pka_len = 0;
124 uint8_t pka_apdu[75] = {0};
125 CLIGetHexWithReturn(ctx, 4, pka_apdu, &pka_len);
127 int ma_len = 0;
128 uint8_t ma_apdu[18] = {0};
129 CLIGetHexWithReturn(ctx, 5, ma_apdu, &ma_len);
131 CLIParserFree(ctx);
133 uint8_t apdu_lengths[5] = {msesa_len, gn_len, map_len, pka_len, ma_len};
134 // pointers to the arrays to be able to iterate
135 uint8_t *apdus[] = {msesa_apdu, gn_apdu, map_apdu, pka_apdu, ma_apdu};
137 // Proxmark response
138 PacketResponseNG resp;
140 // transfer the APDUs to the Proxmark
141 uint8_t data[PM3_CMD_DATA_SIZE];
142 // fast push mode
143 conn.block_after_ACK = true;
144 for (int i = 0; i < ARRAYLEN(apdu_lengths); i++) {
145 // transfer the APDU in several parts if necessary
146 for (int j = 0; j * sizeof(data) < apdu_lengths[i]; j++) {
147 // amount of data in this packet
148 int packet_length = apdu_lengths[i] - (j * sizeof(data));
149 if (packet_length > sizeof(data)) {
150 packet_length = sizeof(data);
152 if ((i == ARRAYLEN(apdu_lengths) - 1) && (j * sizeof(data) >= apdu_lengths[i] - 1)) {
153 // Disable fast mode on last packet
154 conn.block_after_ACK = false;
156 memcpy(data, // + (j * sizeof(data)),
157 apdus[i] + (j * sizeof(data)),
158 packet_length);
160 clearCommandBuffer();
161 // arg0: APDU number
162 // arg1: offset into the APDU
163 SendCommandOLD(CMD_HF_EPA_REPLAY, i + 1, j * sizeof(data), packet_length, data, packet_length);
164 WaitForResponse(CMD_ACK, &resp);
165 if (resp.oldarg[0] != 0) {
166 PrintAndLogEx(WARNING, "Transfer of APDU #%d Part %d failed!", i, j);
167 return PM3_ESOFT;
172 // now perform the replay
173 clearCommandBuffer();
174 SendCommandMIX(CMD_HF_EPA_REPLAY, 0, 0, 0, NULL, 0);
175 WaitForResponse(CMD_ACK, &resp);
177 if (resp.oldarg[0] != 0) {
178 PrintAndLogEx(SUCCESS, "\nPACE replay failed in step %u!", (uint32_t)resp.oldarg[0]);
179 PrintAndLogEx(SUCCESS, "Measured times:");
180 PrintAndLogEx(SUCCESS, "MSE Set AT: %u us", resp.data.asDwords[0]);
181 PrintAndLogEx(SUCCESS, "GA Get Nonce: %u us", resp.data.asDwords[1]);
182 PrintAndLogEx(SUCCESS, "GA Map Nonce: %u us", resp.data.asDwords[2]);
183 PrintAndLogEx(SUCCESS, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]);
184 PrintAndLogEx(SUCCESS, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]);
185 } else {
186 PrintAndLogEx(SUCCESS, "PACE replay successful!");
187 PrintAndLogEx(SUCCESS, "MSE Set AT: %u us", resp.data.asDwords[0]);
188 PrintAndLogEx(SUCCESS, "GA Get Nonce: %u us", resp.data.asDwords[1]);
189 PrintAndLogEx(SUCCESS, "GA Map Nonce: %u us", resp.data.asDwords[2]);
190 PrintAndLogEx(SUCCESS, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]);
191 PrintAndLogEx(SUCCESS, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]);
193 return PM3_SUCCESS;
196 static command_t CommandTable[] = {
197 {"help", CmdHelp, AlwaysAvailable, "This help"},
198 {"cnonces", CmdHFEPACollectPACENonces, IfPm3Iso14443, "Acquire encrypted PACE nonces of specific size"},
199 {"preplay", CmdHFEPAPACEReplay, IfPm3Iso14443, "Perform PACE protocol by replaying given APDUs"},
200 {NULL, NULL, NULL, NULL}
203 static int CmdHelp(const char *Cmd) {
204 (void)Cmd; // Cmd is not used so far
205 CmdsHelp(CommandTable);
206 return PM3_SUCCESS;
209 int CmdHFEPA(const char *Cmd) {
210 clearCommandBuffer();
211 return CmdsParse(CommandTable, Cmd);