fix one too small
[RRG-proxmark3.git] / client / src / cmdhfvas.c
blob195a4ef76904aff0b5329c13bdf9e19eb1330e52
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // An implementation of the Value Added Service protocol
17 //-----------------------------------------------------------------------------
19 #include "cmdhfvas.h"
20 #include "cliparser.h"
21 #include "cmdparser.h"
22 #include "comms.h"
23 #include "ansi.h"
24 #include "cmdhf14a.h"
25 #include "emv/tlv.h"
26 #include "iso7816/apduinfo.h"
27 #include "ui.h"
28 #include "util.h"
29 #include "util_posix.h"
30 #include "iso7816/iso7816core.h"
31 #include <stddef.h>
32 #include <stdbool.h>
33 #include "mifare.h"
34 #include <stdlib.h>
35 #include <string.h>
36 #include "crypto/libpcrypto.h"
37 #include "fileutils.h"
38 #include "mbedtls/ecp.h"
39 #include "mbedtls/bignum.h"
40 #include "mbedtls/ecdh.h"
41 #include "mbedtls/ecc_point_compression.h"
42 #include "mbedtls/gcm.h"
44 static const iso14a_polling_frame_t WUPA_FRAME = {
45 .frame = { 0x52 },
46 .frame_length = 1,
47 .last_byte_bits = 7,
48 .extra_delay = 0,
51 static const iso14a_polling_frame_t ECP_VAS_ONLY_FRAME = {
52 .frame = {0x6a, 0x01, 0x00, 0x00, 0x02, 0xe4, 0xd2},
53 .frame_length = 7,
54 .last_byte_bits = 8,
55 .extra_delay = 0,
58 uint8_t aid[] = { 0x4f, 0x53, 0x45, 0x2e, 0x56, 0x41, 0x53, 0x2e, 0x30, 0x31 };
59 uint8_t getVasUrlOnlyP2 = 0x00;
60 uint8_t getVasFullReqP2 = 0x01;
62 static int ParseSelectVASResponse(const uint8_t *response, size_t resLen, bool verbose) {
63 struct tlvdb *tlvRoot = tlvdb_parse_multi(response, resLen);
65 const struct tlvdb *versionTlv = tlvdb_find_full(tlvRoot, 0x9F21);
66 if (versionTlv == NULL) {
67 tlvdb_free(tlvRoot);
68 return PM3_ECARDEXCHANGE;
70 const struct tlv *version = tlvdb_get_tlv(versionTlv);
71 if (version->len != 2) {
72 tlvdb_free(tlvRoot);
73 return PM3_ECARDEXCHANGE;
75 if (verbose) {
76 PrintAndLogEx(INFO, "Mobile VAS application version: %d.%d", version->value[0], version->value[1]);
78 if (version->value[0] != 0x01 || version->value[1] != 0x00) {
79 tlvdb_free(tlvRoot);
80 return PM3_ECARDEXCHANGE;
83 const struct tlvdb *capabilitiesTlv = tlvdb_find_full(tlvRoot, 0x9F23);
84 if (capabilitiesTlv == NULL) {
85 tlvdb_free(tlvRoot);
86 return PM3_ECARDEXCHANGE;
88 const struct tlv *capabilities = tlvdb_get_tlv(capabilitiesTlv);
89 if (capabilities->len != 4
90 || capabilities->value[0] != 0x00
91 || capabilities->value[1] != 0x00
92 || capabilities->value[2] != 0x00
93 || (capabilities->value[3] & 8) == 0) {
94 tlvdb_free(tlvRoot);
95 return PM3_ECARDEXCHANGE;
98 tlvdb_free(tlvRoot);
99 return PM3_SUCCESS;
102 static int CreateGetVASDataCommand(const uint8_t *pidHash, const char *url, size_t urlLen, uint8_t *out, int *outLen) {
103 if (pidHash == NULL && url == NULL) {
104 PrintAndLogEx(FAILED, "Must provide a Pass Type ID or a URL");
105 return PM3_EINVARG;
108 if (url != NULL && urlLen > 256) {
109 PrintAndLogEx(FAILED, "URL must be less than 256 characters");
110 return PM3_EINVARG;
113 uint8_t p2 = pidHash == NULL ? getVasUrlOnlyP2 : getVasFullReqP2;
115 size_t reqTlvLen = 19 + (pidHash != NULL ? 35 : 0) + (url != NULL ? 3 + urlLen : 0);
116 uint8_t *reqTlv = calloc(reqTlvLen, sizeof(uint8_t));
118 uint8_t version[] = {0x9F, 0x22, 0x02, 0x01, 0x00};
119 memcpy(reqTlv, version, sizeof(version));
121 uint8_t unknown[] = {0x9F, 0x28, 0x04, 0x00, 0x00, 0x00, 0x00};
122 memcpy(reqTlv + sizeof(version), unknown, sizeof(unknown));
124 uint8_t terminalCapabilities[] = {0x9F, 0x26, 0x04, 0x00, 0x00, 0x00, 0x02};
125 memcpy(reqTlv + sizeof(version) + sizeof(unknown), terminalCapabilities, sizeof(terminalCapabilities));
127 if (pidHash != NULL) {
128 size_t offset = sizeof(version) + sizeof(unknown) + sizeof(terminalCapabilities);
129 reqTlv[offset] = 0x9F;
130 reqTlv[offset + 1] = 0x25;
131 reqTlv[offset + 2] = 32;
132 memcpy(reqTlv + offset + 3, pidHash, 32);
135 if (url != NULL) {
136 size_t offset = sizeof(version) + sizeof(unknown) + sizeof(terminalCapabilities) + (pidHash != NULL ? 35 : 0);
137 reqTlv[offset] = 0x9F;
138 reqTlv[offset + 1] = 0x29;
139 reqTlv[offset + 2] = urlLen;
140 memcpy(reqTlv + offset + 3, url, urlLen);
143 out[0] = 0x80;
144 out[1] = 0xCA;
145 out[2] = 0x01;
146 out[3] = p2;
147 out[4] = reqTlvLen;
148 memcpy(out + 5, reqTlv, reqTlvLen);
149 out[5 + reqTlvLen] = 0x00;
151 *outLen = 6 + reqTlvLen;
153 free(reqTlv);
154 return PM3_SUCCESS;
157 static int ParseGetVASDataResponse(const uint8_t *res, size_t resLen, uint8_t *cryptogram, size_t *cryptogramLen) {
158 struct tlvdb *tlvRoot = tlvdb_parse_multi(res, resLen);
160 const struct tlvdb *cryptogramTlvdb = tlvdb_find_full(tlvRoot, 0x9F27);
161 if (cryptogramTlvdb == NULL) {
162 tlvdb_free(tlvRoot);
163 return PM3_ECARDEXCHANGE;
165 const struct tlv *cryptogramTlv = tlvdb_get_tlv(cryptogramTlvdb);
167 memcpy(cryptogram, cryptogramTlv->value, cryptogramTlv->len);
168 *cryptogramLen = cryptogramTlv->len;
170 tlvdb_free(tlvRoot);
171 return PM3_SUCCESS;
174 static int LoadReaderPrivateKey(const uint8_t *buf, size_t bufLen, mbedtls_ecp_keypair *privKey) {
175 struct tlvdb *derRoot = tlvdb_parse_multi(buf, bufLen);
177 const struct tlvdb *privkeyTlvdb = tlvdb_find_full(derRoot, 0x04);
178 if (privkeyTlvdb == NULL) {
179 tlvdb_free(derRoot);
180 return PM3_EINVARG;
182 const struct tlv *privkeyTlv = tlvdb_get_tlv(privkeyTlvdb);
184 if (mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, privKey, privkeyTlv->value, privkeyTlv->len)) {
185 tlvdb_free(derRoot);
186 PrintAndLogEx(FAILED, "Unable to parse private key file. Should be DER encoded ASN1");
187 return PM3_EINVARG;
190 const struct tlvdb *pubkeyCoordsTlvdb = tlvdb_find_full(derRoot, 0x03);
191 if (pubkeyCoordsTlvdb == NULL) {
192 tlvdb_free(derRoot);
193 PrintAndLogEx(FAILED, "Private key file should include public key component");
194 return PM3_EINVARG;
196 const struct tlv *pubkeyCoordsTlv = tlvdb_get_tlv(pubkeyCoordsTlvdb);
197 if (pubkeyCoordsTlv->len != 66 || pubkeyCoordsTlv->value[0] != 0x00 || pubkeyCoordsTlv->value[1] != 0x04) {
198 tlvdb_free(derRoot);
199 PrintAndLogEx(FAILED, "Invalid public key data");
200 return PM3_EINVARG;
203 if (mbedtls_ecp_point_read_binary(&privKey->grp, &privKey->Q, pubkeyCoordsTlv->value + 1, 65)) {
204 PrintAndLogEx(FAILED, "Failed to read in public key coordinates");
205 tlvdb_free(derRoot);
206 return PM3_EINVARG;
209 if (mbedtls_ecp_check_pubkey(&privKey->grp, &privKey->Q)) {
210 PrintAndLogEx(FAILED, "VAS protocol requires an elliptic key on the P-256 curve");
211 tlvdb_free(derRoot);
212 return PM3_EINVARG;
215 tlvdb_free(derRoot);
216 return PM3_SUCCESS;
219 static int GetPrivateKeyHint(mbedtls_ecp_keypair *privKey, uint8_t *keyHint) {
220 uint8_t xcoord[32] = {0};
221 if (mbedtls_mpi_write_binary(&privKey->Q.X, xcoord, sizeof(xcoord))) {
222 return PM3_EINVARG;
225 uint8_t hash[32] = {0};
226 sha256hash(xcoord, 32, hash);
228 memcpy(keyHint, hash, 4);
229 return PM3_SUCCESS;
232 static int LoadMobileEphemeralKey(const uint8_t *xcoordBuf, mbedtls_ecp_keypair *pubKey) {
233 uint8_t compressedEcKey[33] = {0};
234 compressedEcKey[0] = 0x02;
235 memcpy(compressedEcKey + 1, xcoordBuf, 32);
237 uint8_t decompressedEcKey[65] = {0};
238 size_t decompressedEcKeyLen = 0;
239 if (mbedtls_ecp_decompress(&pubKey->grp, compressedEcKey, sizeof(compressedEcKey), decompressedEcKey, &decompressedEcKeyLen, sizeof(decompressedEcKey))) {
240 return PM3_EINVARG;
243 if (mbedtls_ecp_point_read_binary(&pubKey->grp, &pubKey->Q, decompressedEcKey, decompressedEcKeyLen)) {
244 return PM3_EINVARG;
247 return PM3_SUCCESS;
250 static int internalVasDecrypt(uint8_t *cipherText, size_t cipherTextLen, uint8_t *sharedSecret,
251 uint8_t *ansiSharedInfo, size_t ansiSharedInfoLen,
252 const uint8_t *gcmAad, size_t gcmAadLen, uint8_t *out, size_t *outLen) {
253 uint8_t key[32] = {0};
254 if (ansi_x963_sha256(sharedSecret, 32, ansiSharedInfo, ansiSharedInfoLen, sizeof(key), key)) {
255 PrintAndLogEx(FAILED, "ANSI X9.63 key derivation failed");
256 return PM3_EINVARG;
259 uint8_t iv[16] = {0};
261 mbedtls_gcm_context gcmCtx;
262 mbedtls_gcm_init(&gcmCtx);
263 if (mbedtls_gcm_setkey(&gcmCtx, MBEDTLS_CIPHER_ID_AES, key, sizeof(key) * 8)) {
264 PrintAndLogEx(FAILED, "Unable to use key in GCM context");
265 return PM3_EINVARG;
268 if (mbedtls_gcm_auth_decrypt(&gcmCtx, cipherTextLen - 16, iv, sizeof(iv), gcmAad, gcmAadLen, cipherText + cipherTextLen - 16, 16, cipherText, out)) {
269 PrintAndLogEx(FAILED, "Failed to perform GCM decryption");
270 return PM3_EINVARG;
273 mbedtls_gcm_free(&gcmCtx);
275 *outLen = cipherTextLen - 16;
277 return PM3_SUCCESS;
280 static int DecryptVASCryptogram(uint8_t *pidHash, uint8_t *cryptogram, size_t cryptogramLen, mbedtls_ecp_keypair *privKey, uint8_t *out, size_t *outLen, uint32_t *timestamp) {
281 uint8_t keyHint[4] = {0};
282 if (GetPrivateKeyHint(privKey, keyHint) != PM3_SUCCESS) {
283 PrintAndLogEx(FAILED, "Unable to generate key hint");
284 return PM3_EINVARG;
287 if (memcmp(keyHint, cryptogram, 4) != 0) {
288 PrintAndLogEx(FAILED, "Private key does not match cryptogram");
289 return PM3_EINVARG;
292 mbedtls_ecp_keypair mobilePubKey;
293 mbedtls_ecp_keypair_init(&mobilePubKey);
294 mobilePubKey.grp = privKey->grp;
296 if (LoadMobileEphemeralKey(cryptogram + 4, &mobilePubKey) != PM3_SUCCESS) {
297 mbedtls_ecp_keypair_free(&mobilePubKey);
298 PrintAndLogEx(FAILED, "Unable to parse mobile ephemeral key from cryptogram");
299 return PM3_EINVARG;
302 mbedtls_mpi sharedSecret;
303 mbedtls_mpi_init(&sharedSecret);
305 if (mbedtls_ecdh_compute_shared(&privKey->grp, &sharedSecret, &mobilePubKey.Q, &privKey->d, NULL, NULL)) {
306 mbedtls_mpi_free(&sharedSecret);
307 mbedtls_ecp_keypair_free(&mobilePubKey);
308 PrintAndLogEx(FAILED, "Failed to generate ECDH shared secret");
309 return PM3_EINVARG;
311 mbedtls_ecp_keypair_free(&mobilePubKey);
313 uint8_t sharedSecretBytes[32] = {0};
314 if (mbedtls_mpi_write_binary(&sharedSecret, sharedSecretBytes, sizeof(sharedSecretBytes))) {
315 mbedtls_mpi_free(&sharedSecret);
316 PrintAndLogEx(FAILED, "Failed to generate ECDH shared secret");
317 return PM3_EINVARG;
319 mbedtls_mpi_free(&sharedSecret);
321 uint8_t string1[27] = "ApplePay encrypted VAS data";
322 uint8_t string2[13] = "id-aes256-GCM";
324 uint8_t method1SharedInfo[73] = {0};
325 method1SharedInfo[0] = 13;
326 memcpy(method1SharedInfo + 1, string2, sizeof(string2));
327 memcpy(method1SharedInfo + 1 + sizeof(string2), string1, sizeof(string1));
328 memcpy(method1SharedInfo + 1 + sizeof(string2) + sizeof(string1), pidHash, 32);
330 uint8_t decryptedData[68] = {0};
331 size_t decryptedDataLen = 0;
332 if (internalVasDecrypt(cryptogram + 4 + 32, cryptogramLen - 4 - 32, sharedSecretBytes, method1SharedInfo, sizeof(method1SharedInfo), NULL, 0, decryptedData, &decryptedDataLen)) {
333 if (internalVasDecrypt(cryptogram + 4 + 32, cryptogramLen - 4 - 32, sharedSecretBytes, string1, sizeof(string1), pidHash, 32, decryptedData, &decryptedDataLen)) {
334 return PM3_EINVARG;
338 memcpy(out, decryptedData + 4, decryptedDataLen - 4);
339 *outLen = decryptedDataLen - 4;
341 *timestamp = 0;
342 for (int i = 0; i < 4; ++i) {
343 *timestamp = (*timestamp << 8) | decryptedData[i];
346 return PM3_SUCCESS;
349 static int VASReader(uint8_t *pidHash, const char *url, size_t urlLen, uint8_t *cryptogram, size_t *cryptogramLen, bool verbose) {
350 clearCommandBuffer();
352 iso14a_polling_parameters_t polling_parameters = {
353 .frames = { WUPA_FRAME, ECP_VAS_ONLY_FRAME },
354 .frame_count = 2,
355 .extra_timeout = 250
358 if (SelectCard14443A_4_WithParameters(false, false, NULL, &polling_parameters) != PM3_SUCCESS) {
359 PrintAndLogEx(WARNING, "No ISO14443-A Card in field");
360 return PM3_ECARDEXCHANGE;
363 uint16_t status = 0;
364 size_t resLen = 0;
365 uint8_t selectResponse[APDU_RES_LEN] = {0};
366 Iso7816Select(CC_CONTACTLESS, false, true, aid, sizeof(aid), selectResponse, APDU_RES_LEN, &resLen, &status);
368 if (status != 0x9000) {
369 PrintAndLogEx(FAILED, "Card doesn't support VAS");
370 return PM3_ECARDEXCHANGE;
373 if (ParseSelectVASResponse(selectResponse, resLen, verbose) != PM3_SUCCESS) {
374 PrintAndLogEx(FAILED, "Card doesn't support VAS");
375 return PM3_ECARDEXCHANGE;
378 uint8_t getVasApdu[PM3_CMD_DATA_SIZE];
379 int getVasApduLen = 0;
381 int s = CreateGetVASDataCommand(pidHash, url, urlLen, getVasApdu, &getVasApduLen);
382 if (s != PM3_SUCCESS) {
383 return s;
386 uint8_t apduRes[APDU_RES_LEN] = {0};
387 int apduResLen = 0;
389 s = ExchangeAPDU14a(getVasApdu, getVasApduLen, false, false, apduRes, APDU_RES_LEN, &apduResLen);
390 if (s != PM3_SUCCESS) {
391 PrintAndLogEx(FAILED, "Failed to send APDU");
392 return s;
395 if (apduResLen == 2 && apduRes[0] == 0x62 && apduRes[1] == 0x87) {
396 PrintAndLogEx(WARNING, "Device returned error on GET VAS DATA. Either doesn't have pass with matching id, or requires user authentication.");
397 return PM3_ECARDEXCHANGE;
400 if (apduResLen == 0 || apduRes[0] != 0x70) {
401 PrintAndLogEx(FAILED, "Invalid response from peer");
404 return ParseGetVASDataResponse(apduRes, apduResLen, cryptogram, cryptogramLen);
407 static int CmdVASReader(const char *Cmd) {
408 CLIParserContext *ctx;
409 CLIParserInit(&ctx, "hf vas reader",
410 "Read and decrypt Value Added Services (VAS) message",
411 "hf vas reader --url https://example.com -> URL Only mode\n"
412 "hf vas reader --pid pass.com.passkit.pksamples.nfcdemo -f vas_privkey.der -@\n"
415 void *argtable[] = {
416 arg_param_begin,
417 arg_str0(NULL, "pid", "<str>", "PID, pass type id"),
418 arg_str0("f", "file", "<fn>", "path to terminal private key file"),
419 arg_str0(NULL, "url", "<str>", "a URL to provide to the mobile device"),
420 arg_lit0("@", NULL, "continuous mode"),
421 arg_lit0("v", "verbose", "Verbose output"),
422 arg_param_end
424 CLIExecWithReturn(ctx, Cmd, argtable, false);
426 int pidlen = 0;
427 char pid[512] = {0};
428 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)pid, 512, &pidlen);
430 int keyfnlen = 0;
431 char keyfn[FILE_PATH_SIZE] = {0};
432 CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)keyfn, FILE_PATH_SIZE, &keyfnlen);
434 if (keyfnlen == 0 && pidlen > 0) {
435 PrintAndLogEx(FAILED, "Must provide path to terminal private key if a pass type id is provided");
436 CLIParserFree(ctx);
437 return PM3_EINVARG;
440 int urllen = 0;
441 char url[512] = {0};
442 CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)url, 512, &urllen);
444 bool continuous = arg_get_lit(ctx, 4);
445 bool verbose = arg_get_lit(ctx, 5);
446 CLIParserFree(ctx);
448 // santity checks
449 uint8_t *key_data = NULL;
450 size_t key_datalen = 0;
451 if (loadFile_safe(keyfn, "", (void **)&key_data, &key_datalen) != PM3_SUCCESS) {
452 return PM3_EFILE;
455 mbedtls_ecp_keypair privKey;
456 mbedtls_ecp_keypair_init(&privKey);
458 if (LoadReaderPrivateKey(key_data, key_datalen, &privKey) != PM3_SUCCESS) {
459 free(key_data);
460 mbedtls_ecp_keypair_free(&privKey);
461 return PM3_ESOFT;
463 free(key_data);
465 PrintAndLogEx(INFO, "Requesting pass type id... " _GREEN_("%s"), sprint_ascii((uint8_t *) pid, pidlen));
467 if (continuous) {
468 PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
471 uint8_t pidhash[32] = {0};
472 sha256hash((uint8_t *) pid, pidlen, pidhash);
474 size_t clen = 0;
475 size_t mlen = 0;
476 uint8_t cryptogram[120] = {0};
477 uint8_t msg[64] = {0};
478 uint32_t timestamp = 0;
479 int res = PM3_SUCCESS;
481 do {
482 if (continuous && kbd_enter_pressed()) {
483 break;
486 res = VASReader((pidlen > 0) ? pidhash : NULL, url, urllen, cryptogram, &clen, verbose);
487 if (res == PM3_SUCCESS) {
489 res = DecryptVASCryptogram(pidhash, cryptogram, clen, &privKey, msg, &mlen, &timestamp);
490 if (res == PM3_SUCCESS) {
491 PrintAndLogEx(SUCCESS, "Timestamp... " _YELLOW_("%d") " (secs since Jan 1, 2001)", timestamp);
492 PrintAndLogEx(SUCCESS, "Message..... " _YELLOW_("%s"), sprint_ascii(msg, mlen));
493 // extra sleep after successfull read
494 if (continuous) {
495 msleep(3000);
499 msleep(300);
500 } while (continuous);
502 mbedtls_ecp_keypair_free(&privKey);
503 return res;
506 static int CmdVASDecrypt(const char *Cmd) {
507 CLIParserContext *ctx;
508 CLIParserInit(&ctx, "hf vas decrypt",
509 "Decrypt a previously captured cryptogram",
510 "hf vas decrypt --pid pass.com.passkit.pksamples.nfcdemo -f vas_privkey.der -d c0b77375eae416b79449347f9fe838c05cdb57dc7470b97b93b806cb348771d9bfbe29d58538c7c7d7c3d015fa205b68bfccd726058a62f7f44085ac98dbf877120fd9059f1507b956e0a6d56d0a\n"
513 void *argtable[] = {
514 arg_param_begin,
515 arg_str0(NULL, "pid", "<str>", "PID, pass type id"),
516 arg_str0("f", "file", "<fn>", "path to terminal private key file"),
517 arg_str0("d", "data", "<hex>", "cryptogram to decrypt"),
518 arg_param_end
520 CLIExecWithReturn(ctx, Cmd, argtable, false);
522 int pidlen = 0;
523 char pid[512] = {0};
524 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)pid, 512, &pidlen);
526 int keyfnlen = 0;
527 char keyfn[FILE_PATH_SIZE] = {0};
528 CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)keyfn, FILE_PATH_SIZE, &keyfnlen);
530 if (keyfnlen == 0 && pidlen > 0) {
531 PrintAndLogEx(FAILED, "Must provide path to terminal private key if a pass type id is provided");
532 CLIParserFree(ctx);
533 return PM3_EINVARG;
536 int clen = 0;
537 uint8_t cryptogram[120] = {0};
538 CLIGetHexWithReturn(ctx, 3, cryptogram, &clen);
539 CLIParserFree(ctx);
541 // santity checks
542 uint8_t *key_data = NULL;
543 size_t key_datalen = 0;
544 if (loadFile_safe(keyfn, "", (void **)&key_data, &key_datalen) != PM3_SUCCESS) {
545 return PM3_EFILE;
548 mbedtls_ecp_keypair privKey;
549 mbedtls_ecp_keypair_init(&privKey);
551 if (LoadReaderPrivateKey(key_data, key_datalen, &privKey) != PM3_SUCCESS) {
552 free(key_data);
553 mbedtls_ecp_keypair_free(&privKey);
554 return PM3_EFILE;
556 free(key_data);
558 uint8_t pidhash[32] = {0};
559 sha256hash((uint8_t *) pid, pidlen, pidhash);
561 size_t mlen = 0;
562 uint8_t msg[64] = {0};
563 uint32_t timestamp = 0;
565 int res = DecryptVASCryptogram(pidhash, cryptogram, clen, &privKey, msg, &mlen, &timestamp);
566 if (res == PM3_SUCCESS) {
567 PrintAndLogEx(SUCCESS, "Timestamp... " _YELLOW_("%d") " (secs since Jan 1, 2001)", timestamp);
568 PrintAndLogEx(SUCCESS, "Message..... " _YELLOW_("%s"), sprint_ascii(msg, mlen));
571 mbedtls_ecp_keypair_free(&privKey);
572 return res;
575 static int CmdHelp(const char *Cmd);
577 static command_t CommandTable[] = {
578 {"--------", CmdHelp, AlwaysAvailable, "----------- " _CYAN_("Value Added Service") " -----------"},
579 {"help", CmdHelp, AlwaysAvailable, "This help"},
580 {"--------", CmdHelp, AlwaysAvailable, "----------------- " _CYAN_("General") " -----------------"},
581 {"reader", CmdVASReader, IfPm3Iso14443a, "Read and decrypt VAS message"},
582 {"decrypt", CmdVASDecrypt, AlwaysAvailable, "Decrypt a previously captured VAS cryptogram"},
583 {NULL, NULL, NULL, NULL}
586 int CmdHFVAS(const char *Cmd) {
587 clearCommandBuffer();
588 return CmdsParse(CommandTable, Cmd);
591 static int CmdHelp(const char *Cmd) {
592 (void)Cmd; // Cmd is not used so far
593 CmdsHelp(CommandTable);
594 return PM3_SUCCESS;