2023-06-16 22:38:10 +03:00
|
|
|
/**
|
2023-06-17 00:58:22 +03:00
|
|
|
* This file is a part of the UMSKT Project
|
2023-06-16 22:38:10 +03:00
|
|
|
*
|
2023-06-17 00:58:22 +03:00
|
|
|
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
|
2023-06-16 22:38:10 +03:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
* @FileCreated by Andrew on 01/06/2023
|
|
|
|
* @Maintainer Neo
|
|
|
|
*/
|
2023-06-01 16:09:22 +03:00
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
#include "cli.h"
|
2023-06-01 16:09:22 +03:00
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
bool CLI::loadJSON(const fs::path& filename, json *output) {
|
2023-07-09 06:08:43 +03:00
|
|
|
if (!filename.empty() && !fs::exists(filename)) {
|
2023-06-07 01:04:39 +03:00
|
|
|
fmt::print("ERROR: File {} does not exist\n", filename.string());
|
2023-06-05 18:43:31 +03:00
|
|
|
return false;
|
|
|
|
}
|
2023-07-09 06:08:43 +03:00
|
|
|
else if (fs::exists(filename)) {
|
|
|
|
std::ifstream f(filename);
|
|
|
|
*output = json::parse(f, nullptr, false, false);
|
|
|
|
}
|
|
|
|
else if (filename.empty()) {
|
|
|
|
cmrc::embedded_filesystem fs = cmrc::umskt::get_filesystem();
|
|
|
|
cmrc::file keys = fs.open("keys.json");
|
|
|
|
*output = json::parse(keys, nullptr, false, false);
|
|
|
|
}
|
2023-06-07 01:04:39 +03:00
|
|
|
|
|
|
|
if (output->is_discarded()) {
|
|
|
|
fmt::print("ERROR: Unable to parse keys from {}\n", filename.string());
|
|
|
|
return false;
|
|
|
|
}
|
2023-06-05 18:43:31 +03:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
void CLI::showHelp(char *argv[]) {
|
2023-06-05 18:43:31 +03:00
|
|
|
fmt::print("usage: {} \n", argv[0]);
|
|
|
|
fmt::print("\t-h --help\tshow this message\n");
|
|
|
|
fmt::print("\t-v --verbose\tenable verbose output\n");
|
2023-06-07 01:04:39 +03:00
|
|
|
fmt::print("\t-n --number\tnumber of keys to generate (defaults to 1)\n");
|
2023-07-09 06:08:43 +03:00
|
|
|
fmt::print("\t-f --file\tspecify which keys file to load\n");
|
2023-06-07 01:04:39 +03:00
|
|
|
fmt::print("\t-i --instid\tinstallation ID used to generate confirmation ID\n");
|
2023-06-05 18:43:31 +03:00
|
|
|
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");
|
2023-07-04 13:20:17 +03:00
|
|
|
fmt::print("\t-s --serial\tspecifies a serial to use in the product ID (defaults to random, BINK1998 only)\n");
|
2023-06-19 22:41:27 +03:00
|
|
|
fmt::print("\t-V --validate\tproduct key to validate signature\n");
|
2023-07-09 06:08:43 +03:00
|
|
|
fmt::print("\n");
|
2023-06-02 07:25:43 +03:00
|
|
|
}
|
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
int CLI::parseCommandLine(int argc, char* argv[], Options* options) {
|
2023-07-09 06:08:43 +03:00
|
|
|
// set default options
|
2023-06-05 18:43:31 +03:00
|
|
|
*options = Options {
|
2023-06-07 22:23:59 +03:00
|
|
|
"2E",
|
2023-07-09 06:08:43 +03:00
|
|
|
"",
|
2023-06-07 22:23:59 +03:00
|
|
|
"",
|
2023-06-19 22:41:27 +03:00
|
|
|
"",
|
2023-06-07 22:23:59 +03:00
|
|
|
640,
|
2023-07-04 13:20:17 +03:00
|
|
|
0,
|
2023-06-07 22:23:59 +03:00
|
|
|
1,
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
false,
|
2023-07-09 06:08:43 +03:00
|
|
|
false,
|
2023-06-19 22:41:27 +03:00
|
|
|
MODE_BINK1998_GENERATE
|
2023-06-02 07:25:43 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
|
|
std::string arg = argv[i];
|
|
|
|
|
|
|
|
if (arg == "-v" || arg == "--verbose") {
|
2023-06-05 18:43:31 +03:00
|
|
|
options->verbose = true;
|
2023-07-09 06:08:43 +03:00
|
|
|
UMSKT::setDebugOutput(stderr);
|
2023-06-02 07:25:43 +03:00
|
|
|
} else if (arg == "-h" || arg == "--help") {
|
2023-06-05 18:43:31 +03:00
|
|
|
options->help = true;
|
2023-06-07 01:04:39 +03:00
|
|
|
} else if (arg == "-n" || arg == "--number") {
|
|
|
|
if (i == argc - 1) {
|
|
|
|
options->error = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nKeys;
|
|
|
|
if (!sscanf(argv[i+1], "%d", &nKeys)) {
|
|
|
|
options->error = true;
|
|
|
|
} else {
|
|
|
|
options->numKeys = nKeys;
|
|
|
|
}
|
|
|
|
i++;
|
2023-06-02 07:25:43 +03:00
|
|
|
} else if (arg == "-b" || arg == "--bink") {
|
2023-06-07 01:04:39 +03:00
|
|
|
if (i == argc - 1) {
|
|
|
|
options->error = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-06-05 18:43:31 +03:00
|
|
|
options->binkid = argv[i+1];
|
2023-06-02 07:25:43 +03:00
|
|
|
i++;
|
|
|
|
} else if (arg == "-l" || arg == "--list") {
|
2023-06-05 18:43:31 +03:00
|
|
|
options->list = true;
|
2023-06-02 07:25:43 +03:00
|
|
|
} else if (arg == "-c" || arg == "--channelid") {
|
2023-06-07 01:04:39 +03:00
|
|
|
if (i == argc - 1) {
|
|
|
|
options->error = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-06-02 07:25:43 +03:00
|
|
|
int siteID;
|
|
|
|
if (!sscanf(argv[i+1], "%d", &siteID)) {
|
2023-06-05 18:43:31 +03:00
|
|
|
options->error = true;
|
2023-06-02 07:25:43 +03:00
|
|
|
} else {
|
2023-06-05 18:43:31 +03:00
|
|
|
options->channelID = siteID;
|
2023-06-02 07:25:43 +03:00
|
|
|
}
|
|
|
|
i++;
|
2023-07-04 13:20:17 +03:00
|
|
|
} else if (arg == "-s" || arg == "--serial") {
|
|
|
|
if (i == argc - 1) {
|
|
|
|
options->error = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
int serial_val;
|
|
|
|
if (!sscanf(argv[i+1], "%d", &serial_val)) {
|
|
|
|
options->error = true;
|
|
|
|
} else {
|
|
|
|
options->serialSet = true;
|
|
|
|
options->serial = serial_val;
|
|
|
|
}
|
|
|
|
i++;
|
2023-06-05 18:43:31 +03:00
|
|
|
} else if (arg == "-f" || arg == "--file") {
|
2023-06-07 01:04:39 +03:00
|
|
|
if (i == argc - 1) {
|
|
|
|
options->error = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-06-05 18:43:31 +03:00
|
|
|
options->keysFilename = argv[i+1];
|
|
|
|
i++;
|
2023-06-07 01:04:39 +03:00
|
|
|
} else if (arg == "-i" || arg == "--instid") {
|
|
|
|
if (i == argc - 1) {
|
|
|
|
options->error = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
options->instid = argv[i+1];
|
2023-06-08 21:40:11 +03:00
|
|
|
options->applicationMode = MODE_CONFIRMATION_ID;
|
2023-06-07 01:04:39 +03:00
|
|
|
i++;
|
2023-06-19 22:41:27 +03:00
|
|
|
} else if (arg == "-V" || arg == "--validate") {
|
|
|
|
if (i == argc - 1) {
|
|
|
|
options->error = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
options->keyToCheck = argv[i+1];
|
|
|
|
options->applicationMode = MODE_BINK1998_VALIDATE;
|
|
|
|
i++;
|
2023-06-02 07:25:43 +03:00
|
|
|
} else {
|
2023-06-05 18:43:31 +03:00
|
|
|
options->error = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return !options->error;
|
|
|
|
}
|
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
int CLI::validateCommandLine(Options* options, char *argv[], json *keys) {
|
2023-07-09 06:08:43 +03:00
|
|
|
if (options->help || options->error) {
|
|
|
|
if (options->error) {
|
|
|
|
fmt::print("error parsing command line options\n");
|
|
|
|
}
|
|
|
|
showHelp(argv);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-06-05 18:43:31 +03:00
|
|
|
if (options->verbose) {
|
2023-07-09 06:08:43 +03:00
|
|
|
if(options->keysFilename.empty()) {
|
|
|
|
fmt::print("Loading internal keys file\n");
|
|
|
|
} else {
|
|
|
|
fmt::print("Loading keys file {}\n", options->keysFilename);
|
|
|
|
}
|
2023-06-05 18:43:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!loadJSON(options->keysFilename, keys)) {
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options->verbose) {
|
2023-07-09 06:08:43 +03:00
|
|
|
if(options->keysFilename.empty()) {
|
|
|
|
fmt::print("Loaded internal keys file successfully\n");
|
|
|
|
} else {
|
|
|
|
fmt::print("Loaded keys from {} successfully\n",options->keysFilename);
|
2023-06-07 01:04:39 +03:00
|
|
|
}
|
2023-06-05 18:43:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (options->list) {
|
|
|
|
for (auto el : (*keys)["Products"].items()) {
|
|
|
|
int id;
|
|
|
|
sscanf((el.value()["BINK"][0]).get<std::string>().c_str(), "%x", &id);
|
2023-06-07 01:31:31 +03:00
|
|
|
std::cout << el.key() << ": " << el.value()["BINK"] << std::endl;
|
2023-06-02 07:25:43 +03:00
|
|
|
}
|
2023-06-05 18:43:31 +03:00
|
|
|
|
|
|
|
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;
|
2023-06-02 07:25:43 +03:00
|
|
|
}
|
|
|
|
|
2023-06-05 18:43:31 +03:00
|
|
|
int intBinkID;
|
|
|
|
sscanf(options->binkid.c_str(), "%x", &intBinkID);
|
|
|
|
|
2023-07-29 02:15:37 +03:00
|
|
|
if (intBinkID >= 0x40 && intBinkID < 0xFE ) { // FE and FF are BINK 1998
|
2023-07-29 02:16:31 +03:00
|
|
|
// set bink2002 validate mode if in bink1998 validate mode, else set bink2002 generate mode
|
2023-07-29 02:15:37 +03:00
|
|
|
options->applicationMode = (options->applicationMode == MODE_BINK1998_VALIDATE) ? MODE_BINK2002_VALIDATE : MODE_BINK2002_GENERATE;
|
2023-06-05 18:43:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (options->channelID > 999) {
|
2023-06-07 22:23:59 +03:00
|
|
|
fmt::print("ERROR: refusing to create a key with a Channel ID greater than 999\n");
|
2023-06-05 18:43:31 +03:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-07-04 13:20:17 +03:00
|
|
|
// don't allow any serial not between 0 and 999999
|
|
|
|
if (options->serial > 999999 || options->serial < 0) {
|
|
|
|
fmt::print("ERROR: refusing to create a key with a Serial not between 000000 and 999999\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-06-05 18:43:31 +03:00
|
|
|
return 0;
|
2023-06-02 07:25:43 +03:00
|
|
|
}
|
|
|
|
|
2023-07-09 06:08:43 +03:00
|
|
|
void CLI::printID(DWORD *pid) {
|
2023-06-01 16:09:22 +03:00
|
|
|
char raw[12];
|
|
|
|
char b[6], c[8];
|
|
|
|
int i, digit = 0;
|
|
|
|
|
2023-07-04 13:20:17 +03:00
|
|
|
// Convert PID to ascii-number (=raw)
|
2023-07-25 09:53:42 +03:00
|
|
|
snprintf(raw, sizeof(raw), "%09u", pid[0]);
|
2023-06-01 16:09:22 +03:00
|
|
|
|
|
|
|
// Make b-part {640-....}
|
|
|
|
strncpy(b, raw, 3);
|
|
|
|
b[3] = 0;
|
|
|
|
|
|
|
|
// Make c-part {...-123456X...}
|
|
|
|
strcpy(c, raw + 3);
|
|
|
|
|
|
|
|
// Make checksum digit-part {...56X-}
|
|
|
|
assert(strlen(c) == 6);
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
digit -= c[i] - '0'; // Sum digits
|
|
|
|
|
|
|
|
while (digit < 0)
|
|
|
|
digit += 7;
|
|
|
|
c[6] = digit + '0';
|
|
|
|
c[7] = 0;
|
|
|
|
|
2023-07-04 13:20:17 +03:00
|
|
|
fmt::print("> Product ID: PPPPP-{}-{}-23xxx\n", b, c);
|
2023-06-01 16:09:22 +03:00
|
|
|
}
|
|
|
|
|
2023-06-10 20:52:32 +03:00
|
|
|
void CLI::printKey(char *pk) {
|
2023-06-19 22:41:27 +03:00
|
|
|
assert(strlen(pk) >= PK_LENGTH);
|
2023-06-05 18:43:31 +03:00
|
|
|
|
|
|
|
std::string spk = pk;
|
2023-06-18 11:28:20 +03:00
|
|
|
fmt::print("{}-{}-{}-{}-{}",
|
2023-06-05 18:43:31 +03:00
|
|
|
spk.substr(0,5),
|
|
|
|
spk.substr(5,5),
|
|
|
|
spk.substr(10,5),
|
|
|
|
spk.substr(15,5),
|
|
|
|
spk.substr(20,5));
|
2023-06-07 22:23:59 +03:00
|
|
|
}
|
|
|
|
|
2023-06-19 22:41:27 +03:00
|
|
|
bool CLI::stripKey(const char *in_key, char out_key[PK_LENGTH]) {
|
|
|
|
// copy out the product key stripping out extraneous characters
|
|
|
|
const char *p = in_key;
|
|
|
|
size_t i = 0;
|
|
|
|
for (; *p; p++) {
|
|
|
|
// strip out space or dash
|
|
|
|
if (*p == ' ' || *p == '-')
|
|
|
|
continue;
|
|
|
|
// check if we've passed the product key length to avoid overflow
|
|
|
|
if (i >= PK_LENGTH)
|
|
|
|
return false;
|
|
|
|
// convert to uppercase - if character allowed, copy into array
|
2023-07-09 06:08:43 +03:00
|
|
|
for (int j = 0; j < strlen(PIDGEN3::pKeyCharset); j++) {
|
|
|
|
if (toupper(*p) == PIDGEN3::pKeyCharset[j]) {
|
2023-06-19 22:41:27 +03:00
|
|
|
out_key[i++] = toupper(*p);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// only return true if we've handled exactly PK_LENGTH chars
|
|
|
|
return (i == PK_LENGTH);
|
|
|
|
}
|
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
CLI::CLI(Options options, json keys) {
|
2023-06-07 22:43:45 +03:00
|
|
|
this->options = options;
|
2023-06-11 17:03:24 +03:00
|
|
|
this->keys = keys;
|
2023-06-07 22:43:45 +03:00
|
|
|
|
2023-06-11 17:03:24 +03:00
|
|
|
this->BINKID = options.binkid.c_str();
|
2023-06-07 22:23:59 +03:00
|
|
|
|
|
|
|
// We cannot produce a valid key without knowing the private key k. The reason for this is that
|
|
|
|
// we need the result of the function K(x; y) = kG(x; y).
|
2023-06-11 17:03:24 +03:00
|
|
|
this->privateKey = BN_new();
|
2023-06-07 22:23:59 +03:00
|
|
|
|
|
|
|
// We can, however, validate any given key using the available public key: {p, a, b, G, K}.
|
|
|
|
// genOrder the order of the generator G, a value we have to reverse -> Schoof's Algorithm.
|
2023-06-11 17:03:24 +03:00
|
|
|
this->genOrder = BN_new();
|
2023-06-07 22:23:59 +03:00
|
|
|
|
|
|
|
/* Computed data */
|
2023-06-11 17:03:24 +03:00
|
|
|
BN_dec2bn(&this->genOrder, this->keys["BINK"][this->BINKID]["n"]. get<std::string>().c_str());
|
|
|
|
BN_dec2bn(&this->privateKey, this->keys["BINK"][this->BINKID]["priv"].get<std::string>().c_str());
|
2023-06-07 22:23:59 +03:00
|
|
|
|
|
|
|
if (options.verbose) {
|
|
|
|
fmt::print("----------------------------------------------------------- \n");
|
2023-06-11 17:03:24 +03:00
|
|
|
fmt::print("Loaded the following elliptic curve parameters: BINK[{}]\n", this->BINKID);
|
2023-06-07 22:23:59 +03:00
|
|
|
fmt::print("----------------------------------------------------------- \n");
|
2023-06-11 17:03:24 +03:00
|
|
|
fmt::print(" P: {}\n", this->keys["BINK"][this->BINKID]["p"].get<std::string>());
|
|
|
|
fmt::print(" a: {}\n", this->keys["BINK"][this->BINKID]["a"].get<std::string>());
|
|
|
|
fmt::print(" b: {}\n", this->keys["BINK"][this->BINKID]["b"].get<std::string>());
|
|
|
|
fmt::print("Gx: {}\n", this->keys["BINK"][this->BINKID]["g"]["x"].get<std::string>());
|
|
|
|
fmt::print("Gy: {}\n", this->keys["BINK"][this->BINKID]["g"]["y"].get<std::string>());
|
|
|
|
fmt::print("Kx: {}\n", this->keys["BINK"][this->BINKID]["pub"]["x"].get<std::string>());
|
|
|
|
fmt::print("Ky: {}\n", this->keys["BINK"][this->BINKID]["pub"]["y"].get<std::string>());
|
|
|
|
fmt::print(" n: {}\n", this->keys["BINK"][this->BINKID]["n"].get<std::string>());
|
|
|
|
fmt::print(" k: {}\n", this->keys["BINK"][this->BINKID]["priv"].get<std::string>());
|
2023-06-07 22:23:59 +03:00
|
|
|
fmt::print("\n");
|
|
|
|
}
|
|
|
|
|
2023-07-09 06:08:43 +03:00
|
|
|
|
|
|
|
eCurve = PIDGEN3::initializeEllipticCurve(
|
2023-06-11 17:03:24 +03:00
|
|
|
this->keys["BINK"][this->BINKID]["p"].get<std::string>(),
|
|
|
|
this->keys["BINK"][this->BINKID]["a"].get<std::string>(),
|
|
|
|
this->keys["BINK"][this->BINKID]["b"].get<std::string>(),
|
|
|
|
this->keys["BINK"][this->BINKID]["g"]["x"].get<std::string>(),
|
|
|
|
this->keys["BINK"][this->BINKID]["g"]["y"].get<std::string>(),
|
|
|
|
this->keys["BINK"][this->BINKID]["pub"]["x"].get<std::string>(),
|
|
|
|
this->keys["BINK"][this->BINKID]["pub"]["y"].get<std::string>(),
|
|
|
|
this->genPoint,
|
|
|
|
this->pubPoint
|
2023-06-07 22:23:59 +03:00
|
|
|
);
|
|
|
|
|
2023-06-11 17:03:24 +03:00
|
|
|
this->count = 0;
|
|
|
|
this->total = this->options.numKeys;
|
2023-06-07 22:23:59 +03:00
|
|
|
}
|
|
|
|
|
2023-06-19 22:41:27 +03:00
|
|
|
int CLI::BINK1998Generate() {
|
2023-07-04 13:20:17 +03:00
|
|
|
// raw PID/serial value
|
2023-06-11 17:03:24 +03:00
|
|
|
DWORD nRaw = this->options.channelID * 1'000'000 ; /* <- change */
|
2023-06-07 22:23:59 +03:00
|
|
|
|
2023-07-04 13:20:17 +03:00
|
|
|
// using user-provided serial
|
|
|
|
if (this->options.serialSet) {
|
|
|
|
// just in case, make sure it's less than 999999
|
|
|
|
int serialRnd = (this->options.serial % 999999);
|
|
|
|
nRaw += serialRnd;
|
|
|
|
} else {
|
|
|
|
// generate a random number to use as a serial
|
|
|
|
BIGNUM *bnrand = BN_new();
|
|
|
|
BN_rand(bnrand, 19, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY);
|
|
|
|
|
|
|
|
int oRaw;
|
|
|
|
char *cRaw = BN_bn2dec(bnrand);
|
|
|
|
|
|
|
|
sscanf(cRaw, "%d", &oRaw);
|
|
|
|
nRaw += (oRaw % 999999); // ensure our serial is less than 999999
|
|
|
|
}
|
2023-06-07 22:23:59 +03:00
|
|
|
|
2023-06-11 17:03:24 +03:00
|
|
|
if (this->options.verbose) {
|
2023-07-04 13:20:17 +03:00
|
|
|
// print the resulting Product ID
|
|
|
|
// PID value is printed in BINK1998::Generate
|
|
|
|
printID(&nRaw);
|
2023-06-07 22:23:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// generate a key
|
2023-06-11 17:03:24 +03:00
|
|
|
BN_sub(this->privateKey, this->genOrder, this->privateKey);
|
2023-06-10 19:38:22 +03:00
|
|
|
|
|
|
|
// Specify whether an upgrade version or not
|
|
|
|
bool bUpgrade = false;
|
2023-06-07 22:23:59 +03:00
|
|
|
|
2023-06-11 17:03:24 +03:00
|
|
|
for (int i = 0; i < this->total; i++) {
|
2023-07-09 06:08:43 +03:00
|
|
|
PIDGEN3::BINK1998::Generate(this->eCurve, this->genPoint, this->genOrder, this->privateKey, nRaw, bUpgrade, this->pKey);
|
2023-06-07 22:23:59 +03:00
|
|
|
|
2023-07-09 06:08:43 +03:00
|
|
|
bool isValid = PIDGEN3::BINK1998::Verify(this->eCurve, this->genPoint, this->pubPoint, this->pKey);
|
2023-06-18 11:28:20 +03:00
|
|
|
if (isValid) {
|
|
|
|
CLI::printKey(this->pKey);
|
|
|
|
if (i < this->total - 1 || this->options.verbose) {
|
|
|
|
fmt::print("\n");
|
|
|
|
}
|
|
|
|
this->count += isValid;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (this->options.verbose) {
|
|
|
|
CLI::printKey(this->pKey);
|
|
|
|
fmt::print(" [Invalid]");
|
|
|
|
if (i < this->total - 1) {
|
|
|
|
fmt::print("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this->total++; // queue a redo, basically
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->options.verbose) {
|
|
|
|
fmt::print("\nSuccess count: {}/{}", this->count, this->total);
|
2023-06-07 22:23:59 +03:00
|
|
|
}
|
2023-06-18 11:28:20 +03:00
|
|
|
#ifndef _WIN32
|
|
|
|
fmt::print("\n");
|
|
|
|
#endif
|
2023-06-07 22:23:59 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-06-19 22:41:27 +03:00
|
|
|
int CLI::BINK2002Generate() {
|
2023-06-11 17:03:24 +03:00
|
|
|
DWORD pChannelID = this->options.channelID;
|
2023-06-07 22:23:59 +03:00
|
|
|
|
2023-06-11 17:03:24 +03:00
|
|
|
if (this->options.verbose) {
|
|
|
|
fmt::print("> Channel ID: {:03d}\n", this->options.channelID);
|
2023-06-07 22:23:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// generate a key
|
2023-06-11 17:03:24 +03:00
|
|
|
for (int i = 0; i < this->total; i++) {
|
2023-06-07 22:23:59 +03:00
|
|
|
DWORD pAuthInfo;
|
|
|
|
RAND_bytes((BYTE *)&pAuthInfo, 4);
|
2023-06-10 19:38:22 +03:00
|
|
|
pAuthInfo &= BITMASK(10);
|
2023-06-07 22:23:59 +03:00
|
|
|
|
2023-06-11 17:03:24 +03:00
|
|
|
if (this->options.verbose) {
|
2023-06-07 22:23:59 +03:00
|
|
|
fmt::print("> AuthInfo: {}\n", pAuthInfo);
|
|
|
|
}
|
|
|
|
|
2023-07-09 06:08:43 +03:00
|
|
|
PIDGEN3::BINK2002::Generate(this->eCurve, this->genPoint, this->genOrder, this->privateKey, pChannelID, pAuthInfo, false, this->pKey);
|
2023-06-07 22:23:59 +03:00
|
|
|
|
2023-07-09 06:08:43 +03:00
|
|
|
bool isValid = PIDGEN3::BINK2002::Verify(this->eCurve, this->genPoint, this->pubPoint, this->pKey);
|
2023-06-18 11:28:20 +03:00
|
|
|
if (isValid) {
|
|
|
|
CLI::printKey(this->pKey);
|
2023-07-29 00:50:40 +03:00
|
|
|
if (i < this->total - 1 || this->options.verbose) { // check if end of list or verbose
|
2023-06-18 11:28:20 +03:00
|
|
|
fmt::print("\n");
|
|
|
|
}
|
2023-07-29 00:50:40 +03:00
|
|
|
this->count += isValid; // add to count
|
2023-06-18 11:28:20 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (this->options.verbose) {
|
2023-07-29 00:50:40 +03:00
|
|
|
CLI::printKey(this->pKey); // print the key
|
|
|
|
fmt::print(" [Invalid]"); // and add " [Invalid]" to the key
|
|
|
|
if (i < this->total - 1) { // check if end of list
|
2023-06-18 11:28:20 +03:00
|
|
|
fmt::print("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this->total++; // queue a redo, basically
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->options.verbose) {
|
|
|
|
fmt::print("\nSuccess count: {}/{}", this->count, this->total);
|
2023-06-07 22:23:59 +03:00
|
|
|
}
|
2023-06-18 11:28:20 +03:00
|
|
|
#ifndef _WIN32
|
|
|
|
fmt::print("\n");
|
|
|
|
#endif
|
2023-06-07 22:23:59 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-06-19 22:41:27 +03:00
|
|
|
int CLI::BINK1998Validate() {
|
|
|
|
char product_key[PK_LENGTH]{};
|
|
|
|
|
|
|
|
if (!CLI::stripKey(this->options.keyToCheck.c_str(), product_key)) {
|
|
|
|
fmt::print("ERROR: Product key is in an incorrect format!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
CLI::printKey(product_key);
|
|
|
|
fmt::print("\n");
|
2023-07-09 06:08:43 +03:00
|
|
|
if (!PIDGEN3::BINK1998::Verify(this->eCurve, this->genPoint, this->pubPoint, product_key)) {
|
2023-06-19 22:41:27 +03:00
|
|
|
fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt::print("Key validated successfully!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CLI::BINK2002Validate() {
|
|
|
|
char product_key[PK_LENGTH]{};
|
|
|
|
|
|
|
|
if (!CLI::stripKey(this->options.keyToCheck.c_str(), product_key)) {
|
|
|
|
fmt::print("ERROR: Product key is in an incorrect format!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
CLI::printKey(product_key);
|
|
|
|
fmt::print("\n");
|
2023-07-09 06:08:43 +03:00
|
|
|
if (!PIDGEN3::BINK2002::Verify(this->eCurve, this->genPoint, this->pubPoint, product_key)) {
|
2023-06-19 22:41:27 +03:00
|
|
|
fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt::print("Key validated successfully!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
int CLI::ConfirmationID() {
|
|
|
|
char confirmation_id[49];
|
2023-06-11 17:03:24 +03:00
|
|
|
int err = ConfirmationID::Generate(this->options.instid.c_str(), confirmation_id);
|
2023-06-07 22:23:59 +03:00
|
|
|
|
|
|
|
switch (err) {
|
|
|
|
case ERR_TOO_SHORT:
|
|
|
|
fmt::print("ERROR: Installation ID is too short.\n");
|
|
|
|
return 1;
|
2023-06-11 17:03:24 +03:00
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
case ERR_TOO_LARGE:
|
|
|
|
fmt::print("ERROR: Installation ID is too long.\n");
|
|
|
|
return 1;
|
2023-06-11 17:03:24 +03:00
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
case ERR_INVALID_CHARACTER:
|
|
|
|
fmt::print("ERROR: Invalid character in installation ID.\n");
|
|
|
|
return 1;
|
2023-06-11 17:03:24 +03:00
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
case ERR_INVALID_CHECK_DIGIT:
|
|
|
|
fmt::print("ERROR: Installation ID checksum failed. Please check that it is typed correctly.\n");
|
|
|
|
return 1;
|
2023-06-11 17:03:24 +03:00
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
case ERR_UNKNOWN_VERSION:
|
|
|
|
fmt::print("ERROR: Unknown installation ID version.\n");
|
|
|
|
return 1;
|
2023-06-11 17:03:24 +03:00
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
case ERR_UNLUCKY:
|
|
|
|
fmt::print("ERROR: Unable to generate valid confirmation ID.\n");
|
|
|
|
return 1;
|
2023-06-11 17:03:24 +03:00
|
|
|
|
2023-06-07 22:23:59 +03:00
|
|
|
case SUCCESS:
|
2023-06-18 11:28:20 +03:00
|
|
|
fmt::print(confirmation_id);
|
|
|
|
#ifndef _WIN32
|
|
|
|
fmt::print("\n");
|
|
|
|
#endif
|
2023-06-07 22:23:59 +03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fmt::print("Unknown error occurred during Confirmation ID generation: {}\n", err);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|