use fmt.dev's fmt::print functions, factor out command line functions from main to cli.cpp

This commit is contained in:
Neo 2023-06-05 08:43:31 -07:00
parent 29465ffb37
commit cd3cc31cd6
5 changed files with 141 additions and 98 deletions

View File

@ -19,18 +19,20 @@ CPMAddPackage(
VERSION 3.11.2
)
CPMAddPackage("gh:fmtlib/fmt#7.1.3")
CONFIGURE_FILE(keys.json keys.json COPYONLY)
#SET(BUILD_SHARED_LIBS OFF)
#SET(CMAKE_EXE_LINKER_FLAGS "-static")
ADD_EXECUTABLE(xpkey src/main.cpp src/xp.cpp src/key.cpp src/util.cpp src/cli.cpp)
TARGET_INCLUDE_DIRECTORIES(xpkey PUBLIC crypto)
TARGET_LINK_LIBRARIES(xpkey PUBLIC OpenSSL::Crypto nlohmann_json::nlohmann_json)
TARGET_LINK_LIBRARIES(xpkey PUBLIC OpenSSL::Crypto nlohmann_json::nlohmann_json fmt)
ADD_EXECUTABLE(srv2003key src/server.cpp src/key.cpp src/util.cpp src/cli.cpp)
TARGET_INCLUDE_DIRECTORIES(srv2003key PUBLIC crypto)
TARGET_LINK_LIBRARIES(srv2003key PUBLIC OpenSSL::Crypto nlohmann_json::nlohmann_json)
TARGET_LINK_LIBRARIES(srv2003key PUBLIC OpenSSL::Crypto nlohmann_json::nlohmann_json fmt)
ADD_EXECUTABLE(xpactivate src/confid.cpp)
TARGET_INCLUDE_DIRECTORIES(xpactivate PUBLIC crypto)
TARGET_LINK_LIBRARIES(xpactivate PUBLIC OpenSSL::Crypto nlohmann_json::nlohmann_json)
TARGET_LINK_LIBRARIES(xpactivate PUBLIC OpenSSL::Crypto nlohmann_json::nlohmann_json fmt)

View File

@ -4,20 +4,36 @@
#include "header.h"
void showHelp(char *argv[]) {
std::cout << "usage: " << argv[0] << std::endl << std::endl
<< "\t-h --help\tshow this message" << std::endl
<< "\t-v --verbose\tenable verbose output" << std::endl
<< "\t-b --binkid\tspecify which BINK identifier to load (defaults to 2E)" << std::endl
<< "\t-l --list\tshow which products/binks can be loaded" << std::endl
<< "\t-c --channelid\tspecify which Channel Identifier to use (defaults to 640)" << std::endl
<< std::endl << std::endl;
bool loadJSON(const fs::path& filename, json *output) {
if (!fs::exists(filename)) {
fmt::print("{} does not exist", filename.string());
return false;
}
std::ifstream f(filename);
*output = json::parse(f);
return true;
}
Options parseCommandLine(int argc, char* argv[]) {
Options options = {
void showHelp(char *argv[]) {
fmt::print("usage: {} \n", argv[0]);
fmt::print("\t-h --help\tshow this message\n");
fmt::print("\t-v --verbose\tenable verbose output\n");
fmt::print("\t-f --file\tspecify which keys file to load (defaults to keys.json)\n");
fmt::print("\t-b --binkid\tspecify which BINK identifier to load (defaults to 2E)\n");
fmt::print("\t-l --list\tshow which products/binks can be loaded\n");
fmt::print("\t-c --channelid\tspecify which Channel Identifier to use (defaults to 640)\n");
fmt::print("\n\n");
}
int parseCommandLine(int argc, char* argv[], Options* options) {
// set default options
*options = Options {
"2E",
640,
"keys.json",
false,
false,
false
@ -27,28 +43,84 @@ Options parseCommandLine(int argc, char* argv[]) {
std::string arg = argv[i];
if (arg == "-v" || arg == "--verbose") {
options.verbose = true;
options->verbose = true;
} else if (arg == "-h" || arg == "--help") {
options.help = true;
options->help = true;
} else if (arg == "-b" || arg == "--bink") {
options.binkid = argv[i+1];
options->binkid = argv[i+1];
i++;
} else if (arg == "-l" || arg == "--list") {
options.list = true;
options->list = true;
} else if (arg == "-c" || arg == "--channelid") {
int siteID;
if (!sscanf(argv[i+1], "%d", &siteID)) {
options.error = true;
options->error = true;
} else {
options.channelID = siteID;
options->channelID = siteID;
}
i++;
} else if (arg == "-f" || arg == "--file") {
options->keysFilename = argv[i+1];
i++;
} else {
options.error = true;
options->error = true;
}
}
return options;
return !options->error;
}
int validateCommandLine(Options* options, char *argv[], json *keys) {
if (options->help || options->error) {
if (options->error) {
fmt::print("error parsing command line options\n");
}
showHelp(argv);
return 1;
}
if (options->verbose) {
fmt::print("loading {}\n", options->keysFilename);
}
if (!loadJSON(options->keysFilename, keys)) {
return 2;
}
if (options->verbose) {
fmt::print("loaded {} successfully\n",options->keysFilename);
}
if (options->list) {
for (auto el : (*keys)["Products"].items()) {
int id;
sscanf((el.value()["BINK"][0]).get<std::string>().c_str(), "%x", &id);
if (id >= 0x50) {
continue;
}
std::cout << el.key() << ": " << el.value()["BINK"] << std::endl;
}
fmt::print("\n\n");
fmt::print("** Please note: any BINK ID other than 2E is considered experimental at this time **\n");
fmt::print("\n");
return 1;
}
int intBinkID;
sscanf(options->binkid.c_str(), "%x", &intBinkID);
if (intBinkID >= 0x50) {
std::cout << "ERROR: BINK2002 and beyond is not supported in this application at this time" << std::endl;
return 1;
}
if (options->channelID > 999) {
std::cout << "ERROR: refusing to create a key with a siteID greater than 999" << std::endl;
return 1;
}
return 0;
}
void print_product_id(DWORD *pid)
@ -57,7 +129,7 @@ void print_product_id(DWORD *pid)
char b[6], c[8];
int i, digit = 0;
// Cut a away last bit of pid and convert it to an accii-number (=raw)
// Cut away last bit of pid and convert it to an accii-number (=raw)
sprintf(raw, "%iu", pid[0] >> 1);
// Make b-part {640-....}
@ -66,7 +138,7 @@ void print_product_id(DWORD *pid)
// Make c-part {...-123456X...}
strcpy(c, raw + 3);
printf("> %s\n", c);
fmt::print("> {}\n", c);
// Make checksum digit-part {...56X-}
assert(strlen(c) == 6);
@ -78,14 +150,17 @@ void print_product_id(DWORD *pid)
c[6] = digit + '0';
c[7] = 0;
printf("Product ID: PPPPP-%s-%s-23xxx\n", b, c);
fmt::print("Product ID: PPPPP-{}-{}-23xxx\n", b, c);
}
void print_product_key(char *pk) {
int i;
assert(strlen(pk) == 25);
for (i = 0; i < 25; i++) {
putchar(pk[i]);
if (i != 24 && i % 5 == 4) putchar('-');
}
std::string spk = pk;
fmt::print("{}-{}-{}-{}-{}",
spk.substr(0,5),
spk.substr(5,5),
spk.substr(10,5),
spk.substr(15,5),
spk.substr(20,5));
}

View File

@ -19,10 +19,12 @@
#include <random>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <string>
#include <vector>
#include <unordered_map>
#include <fmt/core.h>
#include <nlohmann/json.hpp>
#include <openssl/bn.h>
@ -52,6 +54,9 @@
#define BYDWORD(n) (DWORD)(*((n) + 0) | *((n) + 1) << 8 | *((n) + 2) << 16 | *((n) + 3) << 24)
#define BITMASK(n) ((1ULL << (n)) - 1)
using json = nlohmann::json;
namespace fs = std::filesystem;
// Confirmation ID generator constants
#define SUCCESS 0
#define ERR_TOO_SHORT 1
@ -98,14 +103,17 @@ void print_product_id(DWORD *pid);
struct Options {
std::string binkid;
int channelID;
std::string keysFilename;
bool verbose;
bool help;
bool list;
bool error;
};
Options parseCommandLine(int argc, char* argv[]);
void showHelp(char *argv[]);
int parseCommandLine(int argc, char* argv[], Options* output);
int validateCommandLine(Options* options, char* argv[], json* output);
void showHelp(char* argv[]);
bool loadJSON(const fs::path& filename, json *output);
// xp.cpp
bool verifyXPKey(

View File

@ -5,58 +5,17 @@
#include "header.h"
char pCharset[] = "BCDFGHJKMPQRTVWXY2346789";
const std::string filename = "keys.json";
using json = nlohmann::json;
int main(int argc, char *argv[]) {
Options options = parseCommandLine(argc, argv);
Options options;
if (options.help || options.error) {
if (options.error) {
std::cout << "error parsing command line options" << std::endl;
}
showHelp(argv);
return 0;
if (!parseCommandLine(argc, argv, &options)) {
fmt::print("error parsing command line\n");
return !options.error ? 0 : 1;
}
if (options.verbose) {
std::cout << "loading " << filename << std::endl;
}
std::ifstream f(filename);
json keys = json::parse(f);
if (options.verbose) {
std::cout << "loaded " << filename << " successfully" << std::endl;
}
if (options.list) {
for (auto el : keys["Products"].items()) {
int id;
sscanf((el.value()["BINK"][0]).get<std::string>().c_str(), "%x", &id);
if (id >= 0x50) {
continue;
}
std::cout << el.key() << ": " << el.value()["BINK"] << std::endl;
}
std::cout << std::endl << std::endl
<< "** Please note: any BINK ID other than 2E is considered experimental at this time **"
<< std::endl;
return 0;
}
int intBinkID;
sscanf(options.binkid.c_str(), "%x", &intBinkID);
if (intBinkID >= 0x50) {
std::cout << "ERROR: BINK2002 and beyond is not supported in this application at this time" << std::endl;
return 1;
}
if (options.channelID > 999) {
std::cout << "ERROR: refusing to create a key with a siteID greater than 999" << std::endl;
json keys;
if (validateCommandLine(&options, argv, &keys) < 0) {
return 1;
}
@ -75,19 +34,18 @@ int main(int argc, char *argv[]) {
BN_dec2bn(&privateKey, keys["BINK"][BINKID]["priv"].get<std::string>().c_str());
if (options.verbose) {
std::cout << "-----------------------------------------------------------" << std::endl
<< "Loaded the following curve constraints: BINK[" << BINKID << "]" << std::endl
<< "-----------------------------------------------------------" << std::endl
<< " P: " << keys["BINK"][BINKID]["p"].get<std::string>() << std::endl
<< " a: " << keys["BINK"][BINKID]["a"].get<std::string>() << std::endl
<< " b: " << keys["BINK"][BINKID]["b"].get<std::string>() << std::endl
<< "Gx: " << keys["BINK"][BINKID]["g"]["x"].get<std::string>() << std::endl
<< "Gy: " << keys["BINK"][BINKID]["g"]["y"].get<std::string>() << std::endl
<< "Kx: " << keys["BINK"][BINKID]["pub"]["x"].get<std::string>() << std::endl
<< "Ky: " << keys["BINK"][BINKID]["pub"]["y"].get<std::string>() << std::endl
<< " n: " << keys["BINK"][BINKID]["n"].get<std::string>() << std::endl
<< " k: " << keys["BINK"][BINKID]["priv"].get<std::string>() << std::endl
<< std::endl << std::endl;
fmt::print("----------------------------------------------------------- \n");
fmt::print("Loaded the following curve constraints: BINK[{}]\n", BINKID);
fmt::print("----------------------------------------------------------- \n");
fmt::print(" P: {}\n", keys["BINK"][BINKID]["p"].get<std::string>());
fmt::print(" a: {}\n", keys["BINK"][BINKID]["a"].get<std::string>());
fmt::print(" b: {}\n", keys["BINK"][BINKID]["b"].get<std::string>());
fmt::print("Gx: {}\n", keys["BINK"][BINKID]["g"]["x"].get<std::string>());
fmt::print("Gy: {}\n", keys["BINK"][BINKID]["g"]["y"].get<std::string>());
fmt::print("Kx: {}\n", keys["BINK"][BINKID]["pub"]["x"].get<std::string>());
fmt::print("Ky: {}\n", keys["BINK"][BINKID]["pub"]["y"].get<std::string>());
fmt::print(" n: {}\n", keys["BINK"][BINKID]["n"].get<std::string>());
fmt::print(" k: {}\n", keys["BINK"][BINKID]["priv"].get<std::string>());
}
EC_POINT *genPoint, *pubPoint;
@ -118,7 +76,7 @@ int main(int argc, char *argv[]) {
nRaw += (oRaw &= 0xF423F); // ensure our serial is less than 999999
if (options.verbose) {
std::cout << "> PID: " << std::setw(9) << std::setfill('0') << nRaw << std::endl;
fmt::print("> PID: {:09d}\n", nRaw);
}
// generate a key
@ -129,13 +87,13 @@ int main(int argc, char *argv[]) {
for (int i = 0; i < total; i++) {
generateXPKey(eCurve, genPoint, genOrder, privateKey, nRaw, pKey);
print_product_key(pKey);
std::cout << std::endl << std::endl;
fmt::print("\n\n");
// verify the key
count += verifyXPKey(eCurve, genPoint, pubPoint, pKey);
}
std::cout << "Success count: " << std::dec << count << "/" << total << std::endl;
fmt::print("Success count: {}/{}\n", count, total);
return 0;
}

View File

@ -219,10 +219,10 @@ void generateXPKey(
// Pack product key.
packXP(pRaw, pSerial, pHash, pSignature);
std::cout << " Serial: 0x" << std::hex << std::setw(8) << std::setfill('0') << pSerial << std::endl
<< " Hash: 0x" << std::hex << std::setw(8) << std::setfill('0') << pHash << std::endl
<< " Signature: 0x" << std::hex << std::setw(8) << std::setfill('0') << pSignature << std::endl
<< std::endl;
fmt::print(" Serial: 0x{:08x}\n", pSerial);
fmt::print(" Hash: 0x{:08x}\n", pHash);
fmt::print(" Signature: 0x{:08x}\n", pSignature);
fmt::print("\n");
EC_POINT_free(r);
} while (pRaw[1] > BITMASK(50));