Refactor/Overhaul (#40)

* major refactor/overhaul
move generation implementation to libumskt/*
decouple CLI/Options (and JSON) from generation implementation
set groundwork for future shared library
use standardized PIDGEN2/PIDGEN3 naming convention
create a Windows Docker file for quick compilation
add Windows resouce file/header so we have an application icon on windows
use icon from @Endermanch (used with permission)
add support for fully-static linux/muslc-based compilation
add support for a dos/windows (i486+) binary using djgpp
add Dockerfile to compile gcc/djgpp/watt32/openssl to provide DOS (DPMI) binaries
add @Endermanch 's Vista+ documentation
update Readme for recent credits

* begin work on C linkage and emscripten buildpath

* Update CMake to include and build Crypto++

* move dllmain.cpp to the correct directory

* add rust port info to README.md

* re-add dropped changes from rebase

* update build config, specify windows XP version number for crypto++

* update dos-djgpp action to use new cmake builder and options

* update dos-djgpp to use UMSKT hosted forks

* update other workflows to include standard header

* remove crypto++ from build config for now

* use the new `shell` parameter in `threeal/cmake-action`
TODO: move to a stable version (v1.3.0) when ready

* use full commit hash because a shortened hash is unsupported

* add the required {0} parameter?

* add openssl 3.1.1 to windows github runners

* ensure linux matrix build compiles on the correct arch

---------

Co-authored-by: Neo <321592+Neo-Desktop@users.noreply.github.com>
This commit is contained in:
CONIGUERO
2023-07-09 00:08:43 -03:00
committed by GitHub
parent de04746c5e
commit 15cbe19006
35 changed files with 1520 additions and 242 deletions

View File

@@ -21,18 +21,21 @@
*/
#include "cli.h"
#include "confid.h"
#include "BINK1998.h"
#include "BINK2002.h"
bool CLI::loadJSON(const fs::path& filename, json *output) {
if (!fs::exists(filename)) {
if (!filename.empty() && !fs::exists(filename)) {
fmt::print("ERROR: File {} does not exist\n", filename.string());
return false;
}
std::ifstream f(filename);
*output = json::parse(f, nullptr, false, false);
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);
}
if (output->is_discarded()) {
fmt::print("ERROR: Unable to parse keys from {}\n", filename.string());
@@ -48,39 +51,40 @@ void CLI::showHelp(char *argv[]) {
fmt::print("\t-h --help\tshow this message\n");
fmt::print("\t-v --verbose\tenable verbose output\n");
fmt::print("\t-n --number\tnumber of keys to generate (defaults to 1)\n");
fmt::print("\t-f --file\tspecify which keys file to load (defaults to keys.json)\n");
fmt::print("\t-f --file\tspecify which keys file to load\n");
fmt::print("\t-i --instid\tinstallation ID used to generate confirmation ID\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("\t-s --serial\tspecifies a serial to use in the product ID (defaults to random, BINK1998 only)\n");
fmt::print("\t-V --validate\tproduct key to validate signature\n");
fmt::print("\n\n");
fmt::print("\n");
}
int CLI::parseCommandLine(int argc, char* argv[], Options* options) {
// set default options
*options = Options {
"2E",
"keys.json",
"",
"",
"",
640,
false,
0,
1,
false,
false,
false,
false,
false,
MODE_BINK1998_GENERATE
};
// set default options
for (int i = 1; i < argc; i++) {
std::string arg = argv[i];
if (arg == "-v" || arg == "--verbose") {
options->verbose = true;
UMSKT::setDebugOutput(stderr);
} else if (arg == "-h" || arg == "--help") {
options->help = true;
} else if (arg == "-n" || arg == "--number") {
@@ -168,8 +172,20 @@ int CLI::parseCommandLine(int argc, char* argv[], Options* options) {
}
int CLI::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 keys file {}\n", options->keysFilename);
if(options->keysFilename.empty()) {
fmt::print("Loading internal keys file\n");
} else {
fmt::print("Loading keys file {}\n", options->keysFilename);
}
}
if (!loadJSON(options->keysFilename, keys)) {
@@ -177,15 +193,11 @@ int CLI::validateCommandLine(Options* options, char *argv[], json *keys) {
}
if (options->verbose) {
fmt::print("Loaded keys from {} successfully\n",options->keysFilename);
}
if (options->help || options->error) {
if (options->error) {
fmt::print("error parsing command line options\n");
if(options->keysFilename.empty()) {
fmt::print("Loaded internal keys file successfully\n");
} else {
fmt::print("Loaded keys from {} successfully\n",options->keysFilename);
}
showHelp(argv);
return 1;
}
if (options->list) {
@@ -223,8 +235,7 @@ int CLI::validateCommandLine(Options* options, char *argv[], json *keys) {
return 0;
}
void CLI::printID(DWORD *pid)
{
void CLI::printID(DWORD *pid) {
char raw[12];
char b[6], c[8];
int i, digit = 0;
@@ -276,8 +287,8 @@ bool CLI::stripKey(const char *in_key, char out_key[PK_LENGTH]) {
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]) {
for (int j = 0; j < strlen(PIDGEN3::pKeyCharset); j++) {
if (toupper(*p) == PIDGEN3::pKeyCharset[j]) {
out_key[i++] = toupper(*p);
continue;
}
@@ -321,7 +332,8 @@ CLI::CLI(Options options, json keys) {
fmt::print("\n");
}
eCurve = initializeEllipticCurve(
eCurve = PIDGEN3::initializeEllipticCurve(
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>(),
@@ -371,9 +383,9 @@ int CLI::BINK1998Generate() {
bool bUpgrade = false;
for (int i = 0; i < this->total; i++) {
BINK1998::Generate(this->eCurve, this->genPoint, this->genOrder, this->privateKey, nRaw, bUpgrade, this->pKey);
PIDGEN3::BINK1998::Generate(this->eCurve, this->genPoint, this->genOrder, this->privateKey, nRaw, bUpgrade, this->pKey);
bool isValid = BINK1998::Verify(this->eCurve, this->genPoint, this->pubPoint, this->pKey);
bool isValid = PIDGEN3::BINK1998::Verify(this->eCurve, this->genPoint, this->pubPoint, this->pKey);
if (isValid) {
CLI::printKey(this->pKey);
if (i < this->total - 1 || this->options.verbose) {
@@ -420,11 +432,11 @@ int CLI::BINK2002Generate() {
fmt::print("> AuthInfo: {}\n", pAuthInfo);
}
BINK2002::Generate(this->eCurve, this->genPoint, this->genOrder, this->privateKey, pChannelID, pAuthInfo, false, this->pKey);
PIDGEN3::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 = PIDGEN3::BINK2002::Verify(this->eCurve, this->genPoint, this->pubPoint, this->pKey);
if (isValid) {
CLI::printKey(this->pKey);
if (i < this->total - 1 || this->options.verbose) {
@@ -464,7 +476,7 @@ int CLI::BINK1998Validate() {
CLI::printKey(product_key);
fmt::print("\n");
if (!BINK1998::Verify(this->eCurve, this->genPoint, this->pubPoint, product_key)) {
if (!PIDGEN3::BINK1998::Verify(this->eCurve, this->genPoint, this->pubPoint, product_key)) {
fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n");
return 1;
}
@@ -483,7 +495,7 @@ int CLI::BINK2002Validate() {
CLI::printKey(product_key);
fmt::print("\n");
if (!BINK2002::Verify(this->eCurve, this->genPoint, this->pubPoint, product_key)) {
if (!PIDGEN3::BINK2002::Verify(this->eCurve, this->genPoint, this->pubPoint, product_key)) {
fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n");
return 1;
}

View File

@@ -25,6 +25,42 @@
#include "header.h"
#include <cmrc/cmrc.hpp>
#include "libumskt/libumskt.h"
#include "libumskt/pidgen2/PIDGEN2.h"
#include "libumskt/pidgen3/PIDGEN3.h"
#include "libumskt/pidgen3/BINK1998.h"
#include "libumskt/pidgen3/BINK2002.h"
#include "libumskt/confid/confid.h"
CMRC_DECLARE(umskt);
enum MODE {
MODE_BINK1998_GENERATE = 0,
MODE_BINK2002_GENERATE = 1,
MODE_CONFIRMATION_ID = 2,
MODE_BINK1998_VALIDATE = 3,
MODE_BINK2002_VALIDATE = 4,
};
struct Options {
std::string binkid;
std::string keysFilename;
std::string instid;
std::string keyToCheck;
int channelID;
int serial;
int numKeys;
bool serialSet;
bool verbose;
bool help;
bool error;
bool list;
MODE applicationMode;
};
class CLI {
Options options;
json keys;

View File

@@ -23,18 +23,8 @@
#ifndef UMSKT_HEADER_H
#define UMSKT_HEADER_H
#ifdef DEBUG
#include <cassert>
#else
#define assert(x) /* nothing */
#endif
#include "typedefs.h"
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <random>
#include <iostream>
#include <fstream>
#include <filesystem>
@@ -45,95 +35,7 @@
#include <fmt/core.h>
#include <nlohmann/json.hpp>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
// Algorithm macros
#define PK_LENGTH 25
#define NULL_TERMINATOR 1
#define FIELD_BITS 384
#define FIELD_BYTES 48
#define FIELD_BITS_2003 512
#define FIELD_BYTES_2003 64
#define SHA_MSG_LENGTH_XP (4 + 2 * FIELD_BYTES)
#define SHA_MSG_LENGTH_2003 (3 + 2 * FIELD_BYTES_2003)
#define NEXTSNBITS(field, n, offset) (((QWORD)(field) >> (offset)) & ((1ULL << (n)) - 1))
#define FIRSTNBITS(field, n) NEXTSNBITS((field), (n), 0)
#define HIBYTES(field, bytes) NEXTSNBITS((QWORD)(field), ((bytes) * 8), ((bytes) * 8))
#define LOBYTES(field, bytes) FIRSTNBITS((QWORD)(field), ((bytes) * 8))
#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;
enum MODE {
MODE_BINK1998_GENERATE = 0,
MODE_BINK2002_GENERATE = 1,
MODE_CONFIRMATION_ID = 2,
MODE_BINK1998_VALIDATE = 3,
MODE_BINK2002_VALIDATE = 4,
};
struct Options {
std::string binkid;
std::string keysFilename;
std::string instid;
std::string keyToCheck;
int channelID;
bool serialSet;
int serial;
int numKeys;
bool verbose;
bool help;
bool error;
bool list;
MODE applicationMode;
};
// Type definitions
typedef bool BOOL;
typedef uint8_t BYTE;
typedef uint16_t WORD;
typedef uint32_t DWORD;
typedef uint64_t QWORD;
#ifdef __SIZEOF_INT128__
typedef unsigned __int128 OWORD;
#endif
// Global variables
extern Options options;
// util.cpp
int BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen); // Hello OpenSSL developers, please tell me, where is this function at?
void endian(BYTE *data, int length);
EC_GROUP *initializeEllipticCurve(
std::string pSel,
std::string aSel,
std::string bSel,
std::string generatorXSel,
std::string generatorYSel,
std::string publicKeyXSel,
std::string publicKeyYSel,
EC_POINT *&genPoint,
EC_POINT *&pubPoint
);
// key.cpp
extern char pKeyCharset[];
void unbase24(BYTE *byteSeq, const char *cdKey);
void base24(char *cdKey, BYTE *byteSeq);
#endif //UMSKT_HEADER_H

View File

@@ -62,7 +62,7 @@ inline QWORD ConfirmationID::__umul128(QWORD a, QWORD b, QWORD* hi)
#else
#define __umul128 _umul128
#endif
#elif defined(__i386__) || defined(_M_IX86) || defined(__arm__)
#elif defined(__i386__) || defined(_M_IX86) || defined(__arm__) || defined(__EMSCRIPTEN__)
inline QWORD ConfirmationID::__umul128(QWORD multiplier, QWORD multiplicand, QWORD *product_hi) {
// multiplier = ab = a * 2^32 + b
// multiplicand = cd = c * 2^32 + d
@@ -87,6 +87,8 @@ inline QWORD ConfirmationID::__umul128(QWORD multiplier, QWORD multiplicand, QWO
return product_lo;
}
#else
#error Unknown architecture detected - please edit confid.cpp to tailor __umul128() your architecture
#endif
QWORD ConfirmationID::ui128_quotient_mod(QWORD lo, QWORD hi)

View File

@@ -23,7 +23,7 @@
#ifndef UMSKT_CONFID_H
#define UMSKT_CONFID_H
#include "header.h"
#include "../libumskt.h"
// Confirmation ID generator constants
#define SUCCESS 0
@@ -40,7 +40,7 @@ typedef struct {
QWORD v[2];
} TDivisor;
class ConfirmationID {
EXPORT class ConfirmationID {
static QWORD residue_add(QWORD x, QWORD y);
static QWORD residue_sub(QWORD x, QWORD y);
static QWORD __umul128(QWORD a, QWORD b, QWORD* hi);
@@ -65,7 +65,7 @@ class ConfirmationID {
public:
static int Generate(const char* installation_id_str, char confirmation_id[49]);
static int CLIRun();
//EXPORT static int CLIRun();
};
#endif //UMSKT_CONFID_H

View File

@@ -0,0 +1,35 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* 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 Neo on 6/25/2023
* @Maintainer Neo
*/
#include "libumskt.h"
#ifdef _WIN32
std::FILE* UMSKT::debug = std::fopen("NUL:", "w");
#else
std::FILE* UMSKT::debug = std::fopen("/dev/null", "w");
#endif
void UMSKT::setDebugOutput(std::FILE* input) {
debug = input;
}

60
src/libumskt/libumskt.cpp Normal file
View File

@@ -0,0 +1,60 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* 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 Neo on 6/25/2023
* @Maintainer Neo
*/
#include "libumskt.h"
#include "confid/confid.h"
#include "pidgen3/PIDGEN3.h"
#include "pidgen3/BINK1998.h"
#include "pidgen3/BINK2002.h"
#include "pidgen2/PIDGEN2.h"
FNEXPORT int ConfirmationID_Generate(const char* installation_id_str, char confirmation_id[49]) {
return ConfirmationID::Generate(installation_id_str, confirmation_id);
}
FNEXPORT EC_GROUP* PIDGEN3_initializeEllipticCurve(char* pSel, char* aSel, char* bSel, char* generatorXSel, char* generatorYSel, char* publicKeyXSel, char* publicKeyYSel, EC_POINT *&genPoint, EC_POINT *&pubPoint) {
return PIDGEN3::initializeEllipticCurve(pSel, aSel, bSel, generatorXSel, generatorYSel, publicKeyXSel, publicKeyYSel, genPoint, pubPoint);
}
FNEXPORT bool PIDGEN3_BINK1998_Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *publicKey, char (&pKey)[25]) {
return PIDGEN3::BINK1998::Verify(eCurve, basePoint, publicKey, pKey);
}
FNEXPORT void PIDGEN3_BINK1998_Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *genOrder, BIGNUM *privateKey, DWORD pSerial, BOOL pUpgrade,char (&pKey)[25]) {
return PIDGEN3::BINK1998::Generate(eCurve, basePoint, genOrder, privateKey, pSerial, pUpgrade, pKey);
}
FNEXPORT bool PIDGEN3_BINK2002_Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *publicKey, char (&cdKey)[25]) {
return PIDGEN3::BINK2002::Verify(eCurve, basePoint, publicKey, cdKey);
}
FNEXPORT void PIDGEN3_BINK2002_Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *genOrder, BIGNUM *privateKey, DWORD pChannelID, DWORD pAuthInfo, BOOL pUpgrade, char (&pKey)[25]) {
return PIDGEN3::BINK2002::Generate(eCurve, basePoint, genOrder, privateKey, pChannelID, pAuthInfo, pUpgrade, pKey);
}
FNEXPORT int PIDGEN2_GenerateRetail(char* channelID, char* &keyout) {
return PIDGEN2::GenerateRetail(channelID, keyout);
}
FNEXPORT int PIDGEN2_GenerateOEM(char* year, char* day, char* oem, char* keyout) {
return PIDGEN2::GenerateOEM(year, day, oem, keyout);
}

73
src/libumskt/libumskt.h Normal file
View File

@@ -0,0 +1,73 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* 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 Neo on 6/24/2023
* @Maintainer Neo
*/
#ifndef UMSKT_LIBUMSKT_H
#define UMSKT_LIBUMSKT_H
#include "../typedefs.h"
#include <string>
#include <iostream>
#include <sstream>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <fmt/core.h>
#include <fmt/format.h>
// Algorithm macros
#define PK_LENGTH 25
#define NULL_TERMINATOR 1
#define FIELD_BITS 384
#define FIELD_BYTES 48
#define FIELD_BITS_2003 512
#define FIELD_BYTES_2003 64
#define SHA_MSG_LENGTH_XP (4 + 2 * FIELD_BYTES)
#define SHA_MSG_LENGTH_2003 (3 + 2 * FIELD_BYTES_2003)
#define NEXTSNBITS(field, n, offset) (((QWORD)(field) >> (offset)) & ((1ULL << (n)) - 1))
#define FIRSTNBITS(field, n) NEXTSNBITS((field), (n), 0)
#define HIBYTES(field, bytes) NEXTSNBITS((QWORD)(field), ((bytes) * 8), ((bytes) * 8))
#define LOBYTES(field, bytes) FIRSTNBITS((QWORD)(field), ((bytes) * 8))
#define BYDWORD(n) (DWORD)(*((n) + 0) | *((n) + 1) << 8 | *((n) + 2) << 16 | *((n) + 3) << 24)
#define BITMASK(n) ((1ULL << (n)) - 1)
class UMSKT {
public:
static std::FILE* debug;
class PIDGEN2;
class PIDGEN3;
class ConfigurationID;
static void setDebugOutput(std::FILE* input);
};
#endif //UMSKT_LIBUMSKT_H

View File

@@ -0,0 +1,135 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* 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 Neo on 06/17/2023
* @Maintainer Neo
*/
#include "PIDGEN2.h"
const char* channelIDBlacklist [7] = {"333", "444", "555", "666", "777", "888", "999"};
const char* validYears[8] = { "95", "96", "97", "98", "99", "00", "01", "02"};
bool PIDGEN2::isNumericString(char* input) {
for(int i = 0; i < strlen(input); i++) {
if (input[i] < '0' || input[i] > '9') {
return false;
}
}
return true;
}
int PIDGEN2::addDigits(char* input) {
int output = 0;
if (!isNumericString(input)) {
return -1;
}
for(int i = 0; i < strlen(input); i++) {
output += input[i] - '0';
}
return output;
}
bool PIDGEN2::isValidChannelID(char* channelID) {
if (strlen(channelID) > 3) {
return false;
}
for (int i = 0; i <= 6; i++) {
if (strcmp(channelID, channelIDBlacklist[i]) != 0) {
return false;
}
}
return true;
}
bool PIDGEN2::isValidOEMID(char* OEMID) {
if (!isNumericString(OEMID)) {
return false;
}
if (strlen(OEMID) > 5) {
if (OEMID[0] != '0' || OEMID[1] != '0') {
return false;
}
}
int mod = addDigits(OEMID);
return (mod % 21 == 0);
}
bool PIDGEN2::isValidYear(char* year) {
for (int i = 0; i <= 7; i++) {
if (year == validYears[i]) {
return false;
}
}
return true;
}
bool PIDGEN2::isValidDay(char* day) {
if (!isNumericString(day)) {
return false;
}
int iDay = std::stoi(day);
if (iDay == 0 || iDay >= 365) {
return false;
}
return true;
}
bool PIDGEN2::isValidRetailProductID(char* productID) {
return true;
}
int PIDGEN2::GenerateRetail(char* channelID, char* &keyout) {
if (!isValidChannelID(channelID)) {
return 1;
}
return 0;
}
int PIDGEN2::GenerateOEM(char* year, char* day, char* oem, char* &keyout) {
if (!isValidOEMID(oem)) {
int mod = addDigits(oem);
mod += mod % 21;
strcpy(oem, fmt::format("{:07d}", mod).c_str());
}
if (!isValidYear(year)) {
strcpy(year, validYears[0]);
}
if (!isValidDay(day)) {
int iday = std::stoi(day);
iday = (iday + 1) % 365;
}
strcpy(keyout, fmt::format("{}{}-OEM-{}-{}", year, day, oem, oem).c_str());
return 0;
}

View File

@@ -0,0 +1,41 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* 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 Neo on 06/17/2023
* @Maintainer Neo
*/
#ifndef UMSKT_PIDGEN2_H
#define UMSKT_PIDGEN2_H
#include "../libumskt.h"
EXPORT class PIDGEN2 {
public:
static bool isNumericString(char* input);
static bool isValidChannelID(char* channelID);
static bool isValidOEMID(char* OEMID);
static bool isValidYear(char* year);
static bool isValidDay(char* day);
static bool isValidRetailProductID(char* productID);
static int addDigits(char* input);
static int GenerateRetail(char* channelID, char* &keyout);
static int GenerateOEM(char* year, char* day, char* oem, char* &keyout);
};
#endif //UMSKT_PIDGEN2_H

View File

@@ -30,7 +30,7 @@
#include "BINK1998.h"
/* Unpacks a Windows XP-like Product Key. */
void BINK1998::Unpack(
void PIDGEN3::BINK1998::Unpack(
QWORD (&pRaw)[2],
BOOL &pUpgrade,
DWORD &pSerial,
@@ -54,7 +54,7 @@ void BINK1998::Unpack(
}
/* Packs a Windows XP-like Product Key. */
void BINK1998::Pack(
void PIDGEN3::BINK1998::Pack(
QWORD (&pRaw)[2],
BOOL pUpgrade,
DWORD pSerial,
@@ -71,7 +71,7 @@ void BINK1998::Pack(
}
/* Verifies a Windows XP-like Product Key. */
bool BINK1998::Verify(
bool PIDGEN3::BINK1998::Verify(
EC_GROUP *eCurve,
EC_POINT *basePoint,
EC_POINT *publicKey,
@@ -89,19 +89,17 @@ bool BINK1998::Verify(
BOOL pUpgrade;
// Convert Base24 CD-key to bytecode.
unbase24((BYTE *)pRaw, pKey);
PIDGEN3::unbase24((BYTE *)pRaw, pKey);
// Extract RPK, hash and signature from bytecode.
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");
}
fmt::print(UMSKT::debug, "Validation results:\n");
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", pSerial);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", pHash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", pSignature);
fmt::print(UMSKT::debug, "\n");
pData = pSerial << 1 | pUpgrade;
@@ -177,7 +175,7 @@ bool BINK1998::Verify(
}
/* Generates a Windows XP-like Product Key. */
void BINK1998::Generate(
void PIDGEN3::BINK1998::Generate(
EC_GROUP *eCurve,
EC_POINT *basePoint,
BIGNUM *genOrder,
@@ -266,14 +264,12 @@ void BINK1998::Generate(
// Pack product key.
Pack(pRaw, pUpgrade, pSerial, pHash, pSignature);
if (options.verbose) {
fmt::print("Generation 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");
}
fmt::print(UMSKT::debug, "Generation results:\n");
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", pSerial);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", pHash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", pSignature);
fmt::print(UMSKT::debug, "\n");
EC_POINT_free(r);
} while (pSignature > BITMASK(55));
@@ -290,4 +286,4 @@ void BINK1998::Generate(
BN_free(y);
BN_CTX_free(numContext);
}
}

View File

@@ -23,9 +23,10 @@
#ifndef UMSKT_BINK1998_H
#define UMSKT_BINK1998_H
#include "header.h"
#include "PIDGEN3.h"
class BINK1998 {
EXPORT class PIDGEN3::BINK1998 {
public:
static void Unpack(
QWORD (&pRaw)[2],
BOOL &pUpgrade,
@@ -33,6 +34,7 @@ class BINK1998 {
DWORD &pHash,
QWORD &pSignature
);
static void Pack(
QWORD (&pRaw)[2],
BOOL pUpgrade,
@@ -41,13 +43,13 @@ class BINK1998 {
QWORD pSignature
);
public:
static bool Verify(
EC_GROUP *eCurve,
EC_POINT *basePoint,
EC_POINT *publicKey,
char (&pKey)[25]
);
static void Generate(
EC_GROUP *eCurve,
EC_POINT *basePoint,

View File

@@ -30,7 +30,7 @@
#include "BINK2002.h"
/* Unpacks a Windows Server 2003-like Product Key. */
void BINK2002::Unpack(
void PIDGEN3::BINK2002::Unpack(
QWORD (&pRaw)[2],
BOOL &pUpgrade,
DWORD &pChannelID,
@@ -60,7 +60,7 @@ void BINK2002::Unpack(
}
/* Packs a Windows Server 2003-like Product Key. */
void BINK2002::Pack(
void PIDGEN3::BINK2002::Pack(
QWORD (&pRaw)[2],
BOOL pUpgrade,
DWORD pChannelID,
@@ -74,7 +74,7 @@ void BINK2002::Pack(
}
/* Verifies a Windows Server 2003-like Product Key. */
bool BINK2002::Verify(
bool PIDGEN3::BINK2002::Verify(
EC_GROUP *eCurve,
EC_POINT *basePoint,
EC_POINT *publicKey,
@@ -100,15 +100,13 @@ bool BINK2002::Verify(
pData = pChannelID << 1 | pUpgrade;
if (options.verbose) {
fmt::print("Validation results:\n");
fmt::print(" Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print("Channel ID: 0x{:08x}\n", pChannelID);
fmt::print(" Hash: 0x{:08x}\n", pHash);
fmt::print(" Signature: 0x{:08x}\n", pSignature);
fmt::print(" AuthInfo: 0x{:08x}\n", pAuthInfo);
fmt::print("\n");
}
fmt::print(UMSKT::debug, "Validation results:\n");
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", pChannelID);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", pHash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", pSignature);
fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", pAuthInfo);
fmt::print(UMSKT::debug, "\n");
BYTE msgDigest[SHA_DIGEST_LENGTH]{},
msgBuffer[SHA_MSG_LENGTH_2003]{},
@@ -208,7 +206,7 @@ bool BINK2002::Verify(
}
/* Generates a Windows Server 2003-like Product Key. */
void BINK2002::Generate(
void PIDGEN3::BINK2002::Generate(
EC_GROUP *eCurve,
EC_POINT *basePoint,
BIGNUM *genOrder,
@@ -361,15 +359,13 @@ void BINK2002::Generate(
// Pack product key.
Pack(pRaw, pUpgrade, pChannelID, pHash, pSignature, pAuthInfo);
if (options.verbose) {
fmt::print("Generation results:\n");
fmt::print(" Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print("Channel ID: 0x{:08x}\n", pChannelID);
fmt::print(" Hash: 0x{:08x}\n", pHash);
fmt::print(" Signature: 0x{:08x}\n", pSignature);
fmt::print(" AuthInfo: 0x{:08x}\n", pAuthInfo);
fmt::print("\n");
}
fmt::print(UMSKT::debug, "Generation results:\n");
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", pChannelID);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", pHash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", pSignature);
fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", pAuthInfo);
fmt::print(UMSKT::debug, "\n");
EC_POINT_free(r);
} while (pSignature > BITMASK(62) || noSquare);
@@ -387,4 +383,4 @@ void BINK2002::Generate(
BN_free(e);
BN_CTX_free(numContext);
}
}

View File

@@ -23,9 +23,10 @@
#ifndef UMSKT_BINK2002_H
#define UMSKT_BINK2002_H
#include "header.h"
#include "PIDGEN3.h"
class BINK2002 {
EXPORT class PIDGEN3::BINK2002 {
public:
static void Unpack(
QWORD (&pRaw)[2],
BOOL &pUpgrade,
@@ -34,6 +35,7 @@ class BINK2002 {
QWORD &pSignature,
DWORD &pAuthInfo
);
static void Pack(
QWORD (&pRaw)[2],
BOOL pUpgrade,
@@ -43,13 +45,13 @@ class BINK2002 {
DWORD pAuthInfo
);
public:
static bool Verify(
EC_GROUP *eCurve,
EC_POINT *basePoint,
EC_POINT *publicKey,
char (&cdKey)[25]
);
static void Generate(
EC_GROUP *eCurve,
EC_POINT *basePoint,

View File

@@ -0,0 +1,54 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* 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 Neo on 6/24/2023
* @Maintainer Neo
*/
#ifndef UMSKT_PIDGEN3_H
#define UMSKT_PIDGEN3_H
#include "../libumskt.h"
class PIDGEN3 {
public:
class BINK1998;
class BINK2002;
// util.cpp
static int BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen); // Hello OpenSSL developers, please tell me, where is this function at?
static void endian(BYTE *data, int length);
static EC_GROUP* initializeEllipticCurve(
std::string pSel,
std::string aSel,
std::string bSel,
std::string generatorXSel,
std::string generatorYSel,
std::string publicKeyXSel,
std::string publicKeyYSel,
EC_POINT *&genPoint,
EC_POINT *&pubPoint
);
// key.cpp
static constexpr char pKeyCharset[] = "BCDFGHJKMPQRTVWXY2346789";
static void unbase24(BYTE *byteSeq, const char *cdKey);
static void base24(char *cdKey, BYTE *byteSeq);
};
#endif //UMSKT_PIDGEN3_H

View File

@@ -20,13 +20,10 @@
* @Maintainer Andrew
*/
#include "header.h"
/* The allowed character set in a product key. */
char pKeyCharset[] = "BCDFGHJKMPQRTVWXY2346789";
#include "PIDGEN3.h"
/* Converts from CD-key to a byte sequence. */
void unbase24(BYTE *byteSeq, const char *cdKey) {
void PIDGEN3::unbase24(BYTE *byteSeq, const char *cdKey) {
BYTE pDecodedKey[PK_LENGTH + NULL_TERMINATOR]{};
BIGNUM *y = BN_new();
@@ -63,7 +60,7 @@ void unbase24(BYTE *byteSeq, const char *cdKey) {
}
/* Converts from byte sequence to the CD-key. */
void base24(char *cdKey, BYTE *byteSeq) {
void PIDGEN3::base24(char *cdKey, BYTE *byteSeq) {
BYTE rbyteSeq[16];
BIGNUM *z;
@@ -86,4 +83,4 @@ void base24(char *cdKey, BYTE *byteSeq) {
cdKey[i] = pKeyCharset[BN_div_word(z, 24)];
BN_free(z);
}
}

View File

@@ -20,7 +20,7 @@
* @Maintainer Andrew
*/
#include "header.h"
#include "PIDGEN3.h"
int randomRange() {
return 4; // chosen by fair dice roll
@@ -28,7 +28,7 @@ int randomRange() {
}
/* Convert data between endianness types. */
void endian(BYTE *data, int length) {
void PIDGEN3::endian(BYTE *data, int length) {
for (int i = 0; i < length / 2; i++) {
BYTE temp = data[i];
data[i] = data[length - i - 1];
@@ -37,7 +37,7 @@ void endian(BYTE *data, int length) {
}
/* Initializes the elliptic curve. */
EC_GROUP *initializeEllipticCurve(
EC_GROUP* PIDGEN3::initializeEllipticCurve(
const std::string pSel,
const std::string aSel,
const std::string bSel,
@@ -104,7 +104,7 @@ EC_GROUP *initializeEllipticCurve(
return eCurve;
}
int BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen) {
int PIDGEN3::BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen) {
if (a == nullptr || to == nullptr)
return 0;
@@ -117,4 +117,4 @@ int BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen) {
endian(to, tolen);
return len;
}
}

59
src/typedefs.h Normal file
View File

@@ -0,0 +1,59 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* 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 Neo on 6/24/2023
* @Maintainer Neo
*/
#ifndef UMSKT_TYPEDEFS_H
#define UMSKT_TYPEDEFS_H
#include <cstdint>
#include <cstdbool>
#ifdef DEBUG
#include <cassert>
#else
#define assert(x) /* nothing */
#endif
#ifdef _MSC_VER
#define EXPORT extern "C" __declspec(dllexport)
#else
#define EXPORT extern "C"
#endif
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#define FNEXPORT EMSCRIPTEN_KEEPALIVE EXPORT
#else
#define FNEXPORT EXPORT
#endif
// Type definitions
typedef bool BOOL;
typedef uint8_t BYTE;
typedef uint16_t WORD;
typedef uint32_t DWORD;
typedef uint64_t QWORD;
#ifdef __SIZEOF_INT128__
typedef unsigned __int128 OWORD;
#endif
#endif //UMSKT_TYPEDEFS_H

46
src/windows/dllmain.cpp Normal file
View File

@@ -0,0 +1,46 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* 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 Neo on 06/17/2023
* @Maintainer Neo
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "resource.h"
BOOLEAN WINAPI DllMain( IN HINSTANCE hDllHandle,
IN DWORD nReason,
IN LPVOID Reserved ) {
BOOLEAN bSuccess = TRUE;
// Perform global initialization.
switch (nReason) {
case DLL_PROCESS_ATTACH:
// For optimization.
DisableThreadLibraryCalls(hDllHandle);
break;
case DLL_PROCESS_DETACH:
break;
}
return bSuccess;
}
// end DllMain

BIN
src/windows/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

38
src/windows/resource.h Normal file
View File

@@ -0,0 +1,38 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* 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 Neo on 6/17/2023
* @Maintainer Neo
*/
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by umskt.rc
//
#define IDI_ICON1 101
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

BIN
src/windows/umskt.rc Normal file

Binary file not shown.