proxmark3/client/amiitool/amiitool.c

175 lines
3.8 KiB
C

/*
* (c) 2015-2017 Marcos Del Sol Vives
* (c) 2016 javiMaD
*
* SPDX-License-Identifier: MIT
*/
#include <amiibo.h>
#include <stdio.h>
#include <string.h>
#include "../loclass/fileutil.h"
#define NTAG215_SIZE 540
static char * self;
void amiitool_usage() {
fprintf(stderr,
"amiitool build %i (commit %s-%08x)\n"
"by Marcos Del Sol Vives <marcos@dracon.es>\n"
"\n"
"Usage: %s (-e|-d|-c) -k keyfile [-i input] [-s input2] [-o output]\n"
" -e encrypt and sign amiibo\n"
" -d decrypt and test amiibo\n"
" -c decrypt, copy AppData and encrypt amiibo\n"
" -k key set file. For retail amiibo, use \"retail unfixed\" key set\n"
" -i input file. If not specified, stdin will be used.\n"
" -s input save file, save from this file will replace input file ones.\n"
" -o output file. If not specified, stdout will be used.\n"
" -l decrypt files with invalid signatures.\n",
, self
);
}
static bool LoadAmiikey(nfc3d_amiibo_keys keys, char* keyfile) {
if (!nfc3d_amiibo_load_keys(&keys, keyfile)) {
PrintAndLogEx(ERR, "Could not load keys from '%s'", keyfile);
return false;
}
return true;
}
int main(int argc, char ** argv) {
self = argv[0];
char * infile = NULL;
char * savefile = NULL;
char * outfile = NULL;
char * keyfile = NULL;
char op = '\0';
bool lenient = false;
char c;
while ((c = getopt(argc, argv, "edci:s:o:k:l")) != -1) {
switch (c) {
case 'e':
case 'd':
case 'c':
op = c;
break;
case 'i':
infile = optarg;
break;
case 's':
savefile = optarg;
break;
case 'o':
outfile = optarg;
break;
case 'l':
lenient = true;
break;
default:
amiitool_usage();
return 2;
}
}
if (op == '\0' || keyfile == NULL) {
amiitool_usage();
return 1;
}
nfc3d_amiibo_keys amiiboKeys;
uint8_t original[NTAG215_SIZE];
uint8_t modified[NFC3D_AMIIBO_SIZE];
FILE * f = stdin;
if (infile) {
f = fopen(infile, "rb");
if (!f) {
fprintf(stderr, "Could not open input file\n");
return 3;
}
}
size_t readPages = fread(original, 4, NTAG215_SIZE / 4, f);
if (readPages < NFC3D_AMIIBO_SIZE / 4) {
fprintf(stderr, "Could not read from input\n");
fclose(f);
return 3;
}
fclose(f);
if (op == 'e') {
nfc3d_amiibo_pack(&amiiboKeys, original, modified);
} else if (op == 'd') {
if (!nfc3d_amiibo_unpack(&amiiboKeys, original, modified)) {
fprintf(stderr, "!!! WARNING !!!: Tag signature was NOT valid\n");
if (!lenient) {
return 6;
}
}
} else { /* copy */
uint8_t plain_base[NFC3D_AMIIBO_SIZE];
uint8_t plain_save[NFC3D_AMIIBO_SIZE];
if (!nfc3d_amiibo_unpack(&amiiboKeys, original, plain_base)) {
fprintf(stderr, "!!! WARNING !!!: Tag signature was NOT valid\n");
if (!lenient) {
return 6;
}
}
if (savefile) {
f = fopen(savefile, "rb");
if (!f) {
fprintf(stderr, "Could not open save file\n");
return 3;
}
}
size_t readPages = fread(original, 4, NTAG215_SIZE / 4, f);
if (readPages < NFC3D_AMIIBO_SIZE / 4) {
fprintf(stderr, "Could not read from save\n");
fclose(f);
return 3;
}
fclose(f);
if (!nfc3d_amiibo_unpack(&amiiboKeys, original, plain_save)) {
fprintf(stderr, "!!! WARNING !!!: Tag signature was NOT valid\n");
if (!lenient) {
return 6;
}
}
nfc3d_amiibo_copy_app_data(plain_save, plain_base);
nfc3d_amiibo_pack(&amiiboKeys, plain_base, modified);
}
f = stdout;
if (outfile) {
f = fopen(outfile, "wb");
if (!f) {
fprintf(stderr, "Could not open output file\n");
return 4;
}
}
if (fwrite(modified, NFC3D_AMIIBO_SIZE, 1, f) != 1) {
fprintf(stderr, "Could not write to output\n");
fclose(f);
return 4;
}
if (readPages > NFC3D_AMIIBO_SIZE / 4) {
if (fwrite(original + NFC3D_AMIIBO_SIZE, readPages * 4 - NFC3D_AMIIBO_SIZE, 1, f) != 1) {
fprintf(stderr, "Could not write to output:\n");
fclose(f);
return 4;
}
}
fclose(f);
return 0;
}