mirror of
https://github.com/Neo-Desktop/WindowsXPKg
synced 2024-12-22 20:40:16 +02:00
Add -V/--validate command line switch (#31)
* add -V/--validate command line switch * Return success/failure bool on CLI::stripKey --------- Co-authored-by: Neo <321592+Neo-Desktop@users.noreply.github.com>
This commit is contained in:
parent
bc23fc5233
commit
4b60737bb4
@ -94,6 +94,15 @@ bool BINK1998::Verify(
|
|||||||
// Extract RPK, hash and signature from bytecode.
|
// Extract RPK, hash and signature from bytecode.
|
||||||
Unpack(pRaw, pUpgrade, pSerial, pHash, pSignature);
|
Unpack(pRaw, pUpgrade, pSerial, pHash, pSignature);
|
||||||
|
|
||||||
|
if (options.verbose) {
|
||||||
|
fmt::print("Validation results:\n");
|
||||||
|
fmt::print(" Upgrade: 0x{:08x}\n", pUpgrade);
|
||||||
|
fmt::print(" Serial: 0x{:08x}\n", pSerial);
|
||||||
|
fmt::print(" Hash: 0x{:08x}\n", pHash);
|
||||||
|
fmt::print(" Signature: 0x{:08x}\n", pSignature);
|
||||||
|
fmt::print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
pData = pSerial << 1 | pUpgrade;
|
pData = pSerial << 1 | pUpgrade;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
85
src/cli.cpp
85
src/cli.cpp
@ -53,6 +53,7 @@ void CLI::showHelp(char *argv[]) {
|
|||||||
fmt::print("\t-b --binkid\tspecify which BINK identifier to load (defaults to 2E)\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-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("\t-c --channelid\tspecify which Channel Identifier to use (defaults to 640)\n");
|
||||||
|
fmt::print("\t-V --validate\tproduct key to validate signature\n");
|
||||||
fmt::print("\n\n");
|
fmt::print("\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,13 +62,14 @@ int CLI::parseCommandLine(int argc, char* argv[], Options* options) {
|
|||||||
"2E",
|
"2E",
|
||||||
"keys.json",
|
"keys.json",
|
||||||
"",
|
"",
|
||||||
|
"",
|
||||||
640,
|
640,
|
||||||
1,
|
1,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
MODE_BINK1998
|
MODE_BINK1998_GENERATE
|
||||||
};
|
};
|
||||||
// set default options
|
// set default options
|
||||||
|
|
||||||
@ -131,6 +133,15 @@ int CLI::parseCommandLine(int argc, char* argv[], Options* options) {
|
|||||||
options->instid = argv[i+1];
|
options->instid = argv[i+1];
|
||||||
options->applicationMode = MODE_CONFIRMATION_ID;
|
options->applicationMode = MODE_CONFIRMATION_ID;
|
||||||
i++;
|
i++;
|
||||||
|
} 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++;
|
||||||
} else {
|
} else {
|
||||||
options->error = true;
|
options->error = true;
|
||||||
}
|
}
|
||||||
@ -177,7 +188,8 @@ int CLI::validateCommandLine(Options* options, char *argv[], json *keys) {
|
|||||||
sscanf(options->binkid.c_str(), "%x", &intBinkID);
|
sscanf(options->binkid.c_str(), "%x", &intBinkID);
|
||||||
|
|
||||||
if (intBinkID >= 0x40) {
|
if (intBinkID >= 0x40) {
|
||||||
options->applicationMode = MODE_BINK2002;
|
// set bink2002 validate mode if in bink1998 validate mode, else set bink2002 generate mode
|
||||||
|
options->applicationMode = (options->applicationMode == MODE_BINK1998_VALIDATE) ? MODE_BINK2002_VALIDATE : MODE_BINK2002_GENERATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options->channelID > 999) {
|
if (options->channelID > 999) {
|
||||||
@ -219,7 +231,7 @@ void CLI::printID(DWORD *pid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CLI::printKey(char *pk) {
|
void CLI::printKey(char *pk) {
|
||||||
assert(strlen(pk) == 25);
|
assert(strlen(pk) >= PK_LENGTH);
|
||||||
|
|
||||||
std::string spk = pk;
|
std::string spk = pk;
|
||||||
fmt::print("{}-{}-{}-{}-{}",
|
fmt::print("{}-{}-{}-{}-{}",
|
||||||
@ -230,6 +242,29 @@ void CLI::printKey(char *pk) {
|
|||||||
spk.substr(20,5));
|
spk.substr(20,5));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
for (int j = 0; j < strlen(pKeyCharset); j++) {
|
||||||
|
if (toupper(*p) == pKeyCharset[j]) {
|
||||||
|
out_key[i++] = toupper(*p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// only return true if we've handled exactly PK_LENGTH chars
|
||||||
|
return (i == PK_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
CLI::CLI(Options options, json keys) {
|
CLI::CLI(Options options, json keys) {
|
||||||
this->options = options;
|
this->options = options;
|
||||||
this->keys = keys;
|
this->keys = keys;
|
||||||
@ -280,7 +315,7 @@ CLI::CLI(Options options, json keys) {
|
|||||||
this->total = this->options.numKeys;
|
this->total = this->options.numKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CLI::BINK1998() {
|
int CLI::BINK1998Generate() {
|
||||||
DWORD nRaw = this->options.channelID * 1'000'000 ; /* <- change */
|
DWORD nRaw = this->options.channelID * 1'000'000 ; /* <- change */
|
||||||
|
|
||||||
BIGNUM *bnrand = BN_new();
|
BIGNUM *bnrand = BN_new();
|
||||||
@ -335,7 +370,7 @@ int CLI::BINK1998() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CLI::BINK2002() {
|
int CLI::BINK2002Generate() {
|
||||||
DWORD pChannelID = this->options.channelID;
|
DWORD pChannelID = this->options.channelID;
|
||||||
|
|
||||||
if (this->options.verbose) {
|
if (this->options.verbose) {
|
||||||
@ -353,6 +388,8 @@ int CLI::BINK2002() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BINK2002::Generate(this->eCurve, this->genPoint, this->genOrder, this->privateKey, pChannelID, pAuthInfo, false, this->pKey);
|
BINK2002::Generate(this->eCurve, this->genPoint, this->genOrder, this->privateKey, pChannelID, pAuthInfo, false, this->pKey);
|
||||||
|
CLI::printKey(this->pKey);
|
||||||
|
fmt::print("\n");
|
||||||
|
|
||||||
bool isValid = BINK2002::Verify(this->eCurve, this->genPoint, this->pubPoint, this->pKey);
|
bool isValid = BINK2002::Verify(this->eCurve, this->genPoint, this->pubPoint, this->pKey);
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
@ -384,6 +421,44 @@ int CLI::BINK2002() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
if (!BINK1998::Verify(this->eCurve, this->genPoint, this->pubPoint, product_key)) {
|
||||||
|
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");
|
||||||
|
if (!BINK2002::Verify(this->eCurve, this->genPoint, this->pubPoint, product_key)) {
|
||||||
|
fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt::print("Key validated successfully!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int CLI::ConfirmationID() {
|
int CLI::ConfirmationID() {
|
||||||
char confirmation_id[49];
|
char confirmation_id[49];
|
||||||
int err = ConfirmationID::Generate(this->options.instid.c_str(), confirmation_id);
|
int err = ConfirmationID::Generate(this->options.instid.c_str(), confirmation_id);
|
||||||
|
@ -44,9 +44,12 @@ public:
|
|||||||
static int validateCommandLine(Options* options, char *argv[], json *keys);
|
static int validateCommandLine(Options* options, char *argv[], json *keys);
|
||||||
static void printID(DWORD *pid);
|
static void printID(DWORD *pid);
|
||||||
static void printKey(char *pk);
|
static void printKey(char *pk);
|
||||||
|
static bool stripKey(const char *in_key, char out_key[PK_LENGTH]);
|
||||||
|
|
||||||
int BINK1998();
|
int BINK1998Generate();
|
||||||
int BINK2002();
|
int BINK2002Generate();
|
||||||
|
int BINK1998Validate();
|
||||||
|
int BINK2002Validate();
|
||||||
int ConfirmationID();
|
int ConfirmationID();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,15 +76,18 @@ using json = nlohmann::json;
|
|||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
enum MODE {
|
enum MODE {
|
||||||
MODE_BINK1998 = 0,
|
MODE_BINK1998_GENERATE = 0,
|
||||||
MODE_BINK2002 = 1,
|
MODE_BINK2002_GENERATE = 1,
|
||||||
MODE_CONFIRMATION_ID = 2,
|
MODE_CONFIRMATION_ID = 2,
|
||||||
|
MODE_BINK1998_VALIDATE = 3,
|
||||||
|
MODE_BINK2002_VALIDATE = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Options {
|
struct Options {
|
||||||
std::string binkid;
|
std::string binkid;
|
||||||
std::string keysFilename;
|
std::string keysFilename;
|
||||||
std::string instid;
|
std::string instid;
|
||||||
|
std::string keyToCheck;
|
||||||
int channelID;
|
int channelID;
|
||||||
int numKeys;
|
int numKeys;
|
||||||
bool verbose;
|
bool verbose;
|
||||||
@ -126,6 +129,7 @@ EC_GROUP *initializeEllipticCurve(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// key.cpp
|
// key.cpp
|
||||||
|
extern char pKeyCharset[];
|
||||||
void unbase24(BYTE *byteSeq, const char *cdKey);
|
void unbase24(BYTE *byteSeq, const char *cdKey);
|
||||||
void base24(char *cdKey, BYTE *byteSeq);
|
void base24(char *cdKey, BYTE *byteSeq);
|
||||||
|
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
|
|
||||||
#include "header.h"
|
#include "header.h"
|
||||||
|
|
||||||
char pCharset[] = "BCDFGHJKMPQRTVWXY2346789";
|
/* The allowed character set in a product key. */
|
||||||
|
char pKeyCharset[] = "BCDFGHJKMPQRTVWXY2346789";
|
||||||
|
|
||||||
/* Converts from CD-key to a byte sequence. */
|
/* Converts from CD-key to a byte sequence. */
|
||||||
void unbase24(BYTE *byteSeq, const char *cdKey) {
|
void unbase24(BYTE *byteSeq, const char *cdKey) {
|
||||||
@ -34,7 +35,7 @@ void unbase24(BYTE *byteSeq, const char *cdKey) {
|
|||||||
// Remove dashes from the CD-key and put it into a Base24 byte array.
|
// Remove dashes from the CD-key and put it into a Base24 byte array.
|
||||||
for (int i = 0, k = 0; i < strlen(cdKey) && k < PK_LENGTH; i++) {
|
for (int i = 0, k = 0; i < strlen(cdKey) && k < PK_LENGTH; i++) {
|
||||||
for (int j = 0; j < 24; j++) {
|
for (int j = 0; j < 24; j++) {
|
||||||
if (cdKey[i] != '-' && cdKey[i] == pCharset[j]) {
|
if (cdKey[i] != '-' && cdKey[i] == pKeyCharset[j]) {
|
||||||
pDecodedKey[k++] = j;
|
pDecodedKey[k++] = j;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -82,7 +83,7 @@ void base24(char *cdKey, BYTE *byteSeq) {
|
|||||||
cdKey[25] = 0;
|
cdKey[25] = 0;
|
||||||
|
|
||||||
for (int i = 24; i >= 0; i--)
|
for (int i = 24; i >= 0; i--)
|
||||||
cdKey[i] = pCharset[BN_div_word(z, 24)];
|
cdKey[i] = pKeyCharset[BN_div_word(z, 24)];
|
||||||
|
|
||||||
BN_free(z);
|
BN_free(z);
|
||||||
}
|
}
|
14
src/main.cpp
14
src/main.cpp
@ -42,11 +42,17 @@ int main(int argc, char *argv[]) {
|
|||||||
CLI* run = new CLI(options, keys);
|
CLI* run = new CLI(options, keys);
|
||||||
|
|
||||||
switch(options.applicationMode) {
|
switch(options.applicationMode) {
|
||||||
case MODE_BINK1998:
|
case MODE_BINK1998_GENERATE:
|
||||||
return run->BINK1998();
|
return run->BINK1998Generate();
|
||||||
|
|
||||||
case MODE_BINK2002:
|
case MODE_BINK2002_GENERATE:
|
||||||
return run->BINK2002();
|
return run->BINK2002Generate();
|
||||||
|
|
||||||
|
case MODE_BINK1998_VALIDATE:
|
||||||
|
return run->BINK1998Validate();
|
||||||
|
|
||||||
|
case MODE_BINK2002_VALIDATE:
|
||||||
|
return run->BINK2002Validate();
|
||||||
|
|
||||||
case MODE_CONFIRMATION_ID:
|
case MODE_CONFIRMATION_ID:
|
||||||
return run->ConfirmationID();
|
return run->ConfirmationID();
|
||||||
|
Loading…
Reference in New Issue
Block a user