mirror of
https://github.com/Neo-Desktop/WindowsXPKg
synced 2024-11-22 05:41:01 +02:00
things are quite broken
This commit is contained in:
parent
bf6365916d
commit
5e68e1c8e1
142
src/cli.cpp
142
src/cli.cpp
@ -29,7 +29,7 @@ json CLI::keys;
|
|||||||
BYTE CLI::Init(int argcIn, char **argvIn)
|
BYTE CLI::Init(int argcIn, char **argvIn)
|
||||||
{
|
{
|
||||||
// set default options
|
// set default options
|
||||||
options = {argcIn, argvIn, "2E", "", "", "", "", "", "WINXPPVLK", 0,
|
options = {argcIn, argvIn, "", "", "", "", "", "", "WINXPPVLK", 0,
|
||||||
0, 1, false, false, false, false, false, false, false, STATE_BINK1998_GENERATE};
|
0, 1, false, false, false, false, false, false, false, STATE_BINK1998_GENERATE};
|
||||||
|
|
||||||
SetHelpText();
|
SetHelpText();
|
||||||
@ -140,6 +140,61 @@ BOOL CLI::processOptions()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!options.productCode.empty())
|
||||||
|
{
|
||||||
|
const char *productCode = &options.productCode[0];
|
||||||
|
auto product = keys["Products"][productCode];
|
||||||
|
|
||||||
|
if (options.verbose)
|
||||||
|
{
|
||||||
|
fmt::print("Selecting product: {}\n", productCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.oem)
|
||||||
|
{
|
||||||
|
options.binkid = product["BINK"][1].get<std::string>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
options.binkid = product["BINK"][0].get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.verbose)
|
||||||
|
{
|
||||||
|
fmt::print("Selected BINK: {}\n", options.binkid);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<json> filtered;
|
||||||
|
|
||||||
|
if (product.contains("DPC") && options.channelID == 0)
|
||||||
|
{
|
||||||
|
for (auto const &i : product["DPC"][options.binkid].items())
|
||||||
|
{
|
||||||
|
auto el = i.value();
|
||||||
|
if (!el["IsEvaluation"].get<bool>())
|
||||||
|
{
|
||||||
|
filtered.push_back(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// roll a die to choose which DPC entry to pick
|
||||||
|
auto rand = UMSKT::getRandom<BYTE>();
|
||||||
|
auto dpc = filtered[rand % filtered.size()];
|
||||||
|
auto min = dpc["Min"].get<WORD>(), max = dpc["Max"].get<WORD>();
|
||||||
|
options.channelID = min + (rand % (max - min));
|
||||||
|
|
||||||
|
if (options.verbose)
|
||||||
|
{
|
||||||
|
fmt::print("Selected channel ID: {} (DPC entry {})\n", options.channelID, rand % filtered.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.channelID == 0)
|
||||||
|
{
|
||||||
|
options.channelID = UMSKT::getRandom<WORD>() % 999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DWORD intBinkID;
|
DWORD intBinkID;
|
||||||
sscanf(&options.binkid[0], "%x", &intBinkID);
|
sscanf(&options.binkid[0], "%x", &intBinkID);
|
||||||
|
|
||||||
@ -195,7 +250,7 @@ void CLI::printID(DWORD *pid)
|
|||||||
*
|
*
|
||||||
* @param pk
|
* @param pk
|
||||||
*/
|
*/
|
||||||
void CLI::printKey(std::string pk)
|
void CLI::printKey(std::string &pk)
|
||||||
{
|
{
|
||||||
assert(pk.length() >= PK_LENGTH);
|
assert(pk.length() >= PK_LENGTH);
|
||||||
|
|
||||||
@ -249,57 +304,6 @@ BOOL CLI::stripKey(const std::string &in_key, std::string &out_key)
|
|||||||
*/
|
*/
|
||||||
BOOL CLI::InitPIDGEN3(PIDGEN3 *pidgen3)
|
BOOL CLI::InitPIDGEN3(PIDGEN3 *pidgen3)
|
||||||
{
|
{
|
||||||
if (!options.productCode.empty())
|
|
||||||
{
|
|
||||||
const char *productCode = &options.productCode[0];
|
|
||||||
auto product = keys["Products"][productCode];
|
|
||||||
|
|
||||||
if (options.verbose)
|
|
||||||
{
|
|
||||||
fmt::print("Selecting product: {}\n", productCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.oem)
|
|
||||||
{
|
|
||||||
options.binkid = product["BINK"][1].get<std::string>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
options.binkid = product["BINK"][0].get<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.verbose)
|
|
||||||
{
|
|
||||||
fmt::print("Selected BINK: {}\n", options.binkid);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<json> filtered;
|
|
||||||
|
|
||||||
if (product.contains("DPC") && options.channelID == 0)
|
|
||||||
{
|
|
||||||
for (auto const &i : product["DPC"][options.binkid].items())
|
|
||||||
{
|
|
||||||
auto el = i.value();
|
|
||||||
if (!el["IsEvaluation"].get<bool>())
|
|
||||||
{
|
|
||||||
filtered.push_back(el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// roll a die to choose which DPC entry to pick
|
|
||||||
auto rand = UMSKT::getRandom<BYTE>();
|
|
||||||
auto dpc = filtered[rand % filtered.size()];
|
|
||||||
auto min = dpc["Min"].get<WORD>(), max = dpc["Max"].get<WORD>();
|
|
||||||
options.channelID = min + (rand % (max - min));
|
|
||||||
if (options.verbose)
|
|
||||||
{
|
|
||||||
fmt::print("Selected channel ID: {} (DPC entry {})\n", options.channelID, rand % filtered.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *BINKID = &options.binkid[0];
|
const char *BINKID = &options.binkid[0];
|
||||||
auto bink = keys["BINK"][BINKID];
|
auto bink = keys["BINK"][BINKID];
|
||||||
|
|
||||||
@ -320,12 +324,10 @@ BOOL CLI::InitPIDGEN3(PIDGEN3 *pidgen3)
|
|||||||
fmt::print("\n");
|
fmt::print("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
pidgen3->LoadEllipticCurve(bink["p"].get<std::string>(), bink["a"].get<std::string>(), bink["b"].get<std::string>(),
|
pidgen3->LoadEllipticCurve(bink["p"], bink["a"], bink["b"], bink["g"]["x"], bink["g"]["y"], bink["pub"]["x"],
|
||||||
bink["g"]["x"].get<std::string>(), bink["g"]["y"].get<std::string>(),
|
bink["pub"]["y"], bink["n"], bink["priv"]);
|
||||||
bink["pub"]["x"].get<std::string>(), bink["pub"]["y"].get<std::string>(),
|
|
||||||
bink["n"].get<std::string>(), bink["priv"].get<std::string>());
|
|
||||||
|
|
||||||
pidgen3->setChannelID(options.channelID);
|
options.info.setChannelID(options.channelID);
|
||||||
if (options.verbose)
|
if (options.verbose)
|
||||||
{
|
{
|
||||||
fmt::print("> Channel ID: {:03d}\n", options.channelID);
|
fmt::print("> Channel ID: {:03d}\n", options.channelID);
|
||||||
@ -333,7 +335,7 @@ BOOL CLI::InitPIDGEN3(PIDGEN3 *pidgen3)
|
|||||||
|
|
||||||
if (options.serialSet)
|
if (options.serialSet)
|
||||||
{
|
{
|
||||||
pidgen3->setSerial(options.serial);
|
options.info.setSerial(options.serial);
|
||||||
if (options.verbose)
|
if (options.verbose)
|
||||||
{
|
{
|
||||||
fmt::print("> Serial {:#09d}\n", options.serial);
|
fmt::print("> Serial {:#09d}\n", options.serial);
|
||||||
@ -368,21 +370,22 @@ BOOL CLI::BINK1998Generate()
|
|||||||
|
|
||||||
// raw PID/serial value
|
// raw PID/serial value
|
||||||
DWORD nRaw = options.channelID * 1'000'000;
|
DWORD nRaw = options.channelID * 1'000'000;
|
||||||
|
DWORD serialRnd;
|
||||||
|
|
||||||
// using user-provided serial
|
|
||||||
if (options.serialSet)
|
if (options.serialSet)
|
||||||
{
|
{
|
||||||
// just in case, make sure it's less than 999999
|
// using user-provided serial
|
||||||
int serialRnd = (options.serial % 999999);
|
serialRnd = options.serial;
|
||||||
nRaw += serialRnd;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// generate a random number to use as a serial
|
// generate a random number to use as a serial
|
||||||
auto oRaw = UMSKT::getRandom<DWORD>();
|
serialRnd = UMSKT::getRandom<DWORD>();
|
||||||
nRaw += (oRaw % 999999); // ensure our serial is less than 999999
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure it's less than 999999
|
||||||
|
nRaw += (serialRnd % 999999);
|
||||||
|
|
||||||
if (options.verbose)
|
if (options.verbose)
|
||||||
{
|
{
|
||||||
// print the resulting Product ID
|
// print the resulting Product ID
|
||||||
@ -392,12 +395,13 @@ BOOL CLI::BINK1998Generate()
|
|||||||
|
|
||||||
for (int i = 0; i < total; i++)
|
for (int i = 0; i < total; i++)
|
||||||
{
|
{
|
||||||
bink1998.Generate(pKey);
|
options.info.setSerial(nRaw);
|
||||||
|
bink1998.Generate(options.info, pKey);
|
||||||
|
|
||||||
bool isValid = bink1998.Verify(pKey);
|
bool isValid = bink1998.Verify(pKey);
|
||||||
if (isValid)
|
if (isValid)
|
||||||
{
|
{
|
||||||
CLI::printKey(pKey);
|
printKey(pKey);
|
||||||
if (i < total - 1 || options.verbose)
|
if (i < total - 1 || options.verbose)
|
||||||
{
|
{
|
||||||
fmt::print("\n");
|
fmt::print("\n");
|
||||||
@ -408,7 +412,7 @@ BOOL CLI::BINK1998Generate()
|
|||||||
{
|
{
|
||||||
if (options.verbose)
|
if (options.verbose)
|
||||||
{
|
{
|
||||||
CLI::printKey(pKey);
|
printKey(pKey);
|
||||||
fmt::print(" [Invalid]");
|
fmt::print(" [Invalid]");
|
||||||
if (i < total - 1)
|
if (i < total - 1)
|
||||||
{
|
{
|
||||||
@ -448,7 +452,7 @@ BOOL CLI::BINK2002Generate()
|
|||||||
fmt::print("> AuthInfo: {}\n", pAuthInfo);
|
fmt::print("> AuthInfo: {}\n", pAuthInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
bink2002.Generate(pKey);
|
bink2002.Generate(options.info, pKey);
|
||||||
|
|
||||||
bool isValid = bink2002.Verify(pKey);
|
bool isValid = bink2002.Verify(pKey);
|
||||||
if (isValid)
|
if (isValid)
|
||||||
|
@ -82,6 +82,8 @@ struct Options
|
|||||||
BOOL error;
|
BOOL error;
|
||||||
BOOL list;
|
BOOL list;
|
||||||
|
|
||||||
|
PIDGEN3::KeyInfo info;
|
||||||
|
|
||||||
APPLICATION_STATE state;
|
APPLICATION_STATE state;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -105,7 +107,8 @@ class CLI
|
|||||||
static BYTE Init(int argv, char *argc[]);
|
static BYTE Init(int argv, char *argc[]);
|
||||||
static void SetHelpText();
|
static void SetHelpText();
|
||||||
|
|
||||||
static CLIHandlerFunc loadJSON;
|
static BOOL loadJSON(const fs::path &filename);
|
||||||
|
|
||||||
static CLIHandlerFunc DisplayHelp;
|
static CLIHandlerFunc DisplayHelp;
|
||||||
static CLIHandlerFunc DisplayErrorMessage;
|
static CLIHandlerFunc DisplayErrorMessage;
|
||||||
static CLIHandlerFunc SetVerboseOption;
|
static CLIHandlerFunc SetVerboseOption;
|
||||||
@ -126,7 +129,7 @@ class CLI
|
|||||||
static BOOL parseCommandLine();
|
static BOOL parseCommandLine();
|
||||||
static BOOL processOptions();
|
static BOOL processOptions();
|
||||||
static void printID(DWORD *pid);
|
static void printID(DWORD *pid);
|
||||||
static void printKey(std::string pk);
|
static void printKey(std::string &pk);
|
||||||
static BOOL stripKey(const std::string &in_key, std::string &out_key);
|
static BOOL stripKey(const std::string &in_key, std::string &out_key);
|
||||||
|
|
||||||
BOOL InitPIDGEN3(PIDGEN3 *pidgen3);
|
BOOL InitPIDGEN3(PIDGEN3 *pidgen3);
|
||||||
|
@ -34,8 +34,8 @@ std::FILE *UMSKT::debug = getFileStreamToNul();
|
|||||||
std::FILE *UMSKT::debug = std::fopen("/dev/null", "w");
|
std::FILE *UMSKT::debug = std::fopen("/dev/null", "w");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BOOL UMSKT::VERBOSE;
|
BOOL UMSKT::VERBOSE = false;
|
||||||
BOOL UMSKT::DEBUG;
|
BOOL UMSKT::DEBUG = false;
|
||||||
|
|
||||||
void UMSKT::setDebugOutput(std::FILE *input)
|
void UMSKT::setDebugOutput(std::FILE *input)
|
||||||
{
|
{
|
||||||
|
@ -108,7 +108,7 @@ FNEXPORT BOOL PIDGEN3_Generate(void *&ptrIn, char *&pKeyOut, int pKeySizeIn)
|
|||||||
auto *p3((PIDGEN3 *)ptrIn);
|
auto *p3((PIDGEN3 *)ptrIn);
|
||||||
|
|
||||||
std::string str;
|
std::string str;
|
||||||
BOOL retval = p3->Generate(str);
|
// BOOL retval = p3->Generate(str);
|
||||||
|
|
||||||
if (pKeySizeIn > str.length() + 1)
|
if (pKeySizeIn > str.length() + 1)
|
||||||
{
|
{
|
||||||
@ -118,7 +118,7 @@ FNEXPORT BOOL PIDGEN3_Generate(void *&ptrIn, char *&pKeyOut, int pKeySizeIn)
|
|||||||
memcpy(pKeyOut, &str[0], str.length());
|
memcpy(pKeyOut, &str[0], str.length());
|
||||||
pKeyOut[str.length()] = 0;
|
pKeyOut[str.length()] = 0;
|
||||||
|
|
||||||
return retval;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FNEXPORT BOOL PIDGEN3_Verify(void *&ptrIn, char *pKeyIn)
|
FNEXPORT BOOL PIDGEN3_Verify(void *&ptrIn, char *pKeyIn)
|
||||||
|
@ -66,6 +66,12 @@ class UMSKT
|
|||||||
static BOOL VERBOSE;
|
static BOOL VERBOSE;
|
||||||
static BOOL DEBUG;
|
static BOOL DEBUG;
|
||||||
|
|
||||||
|
static void DESTRUCT()
|
||||||
|
{
|
||||||
|
std::fclose(debug);
|
||||||
|
debug = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
static void setDebugOutput(std::FILE *input);
|
static void setDebugOutput(std::FILE *input);
|
||||||
template <typename T> static T getRandom()
|
template <typename T> static T getRandom()
|
||||||
{
|
{
|
||||||
|
@ -34,22 +34,22 @@
|
|||||||
*
|
*
|
||||||
* @param pRaw [out] *QWORD[2] raw product key output
|
* @param pRaw [out] *QWORD[2] raw product key output
|
||||||
**/
|
**/
|
||||||
BOOL BINK1998::Unpack(QWORD (&pRaw)[2])
|
BOOL BINK1998::Unpack(KeyInfo &info, QWORD *pRaw)
|
||||||
{
|
{
|
||||||
// We're assuming that the quantity of information within the product key is at most 114 bits.
|
// We're assuming that the quantity of information within the product key is at most 114 bits.
|
||||||
// log2(24^25) = 114.
|
// log2(24^25) = 114.
|
||||||
|
|
||||||
// Upgrade = Bit 0
|
// Upgrade = Bit 0
|
||||||
isUpgrade = FIRSTNBITS(pRaw[0], 1);
|
info.isUpgrade = FIRSTNBITS(pRaw[0], 1);
|
||||||
|
|
||||||
// Serial = Bits [1..30] -> 30 bits
|
// Serial = Bits [1..30] -> 30 bits
|
||||||
Serial = NEXTSNBITS(pRaw[0], 30, 1);
|
info.Serial = NEXTSNBITS(pRaw[0], 30, 1);
|
||||||
|
|
||||||
// Hash = Bits [31..58] -> 28 bits
|
// Hash = Bits [31..58] -> 28 bits
|
||||||
Hash = NEXTSNBITS(pRaw[0], 28, 31);
|
info.Hash = NEXTSNBITS(pRaw[0], 28, 31);
|
||||||
|
|
||||||
// Signature = Bits [59..113] -> 56 bits
|
// Signature = Bits [59..113] -> 56 bits
|
||||||
Signature = FIRSTNBITS(pRaw[1], 51) << 5 | NEXTSNBITS(pRaw[0], 5, 59);
|
info.Signature = FIRSTNBITS(pRaw[1], 51) << 5 | NEXTSNBITS(pRaw[0], 5, 59);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -59,15 +59,15 @@ BOOL BINK1998::Unpack(QWORD (&pRaw)[2])
|
|||||||
*
|
*
|
||||||
* @param pRaw [in] *QWORD[2] raw product key input
|
* @param pRaw [in] *QWORD[2] raw product key input
|
||||||
**/
|
**/
|
||||||
BOOL BINK1998::Pack(QWORD (&pRaw)[2])
|
BOOL BINK1998::Pack(const KeyInfo &info, QWORD *pRaw)
|
||||||
{
|
{
|
||||||
// The quantity of information the key provides is 114 bits.
|
// The quantity of information the key provides is 114 bits.
|
||||||
// We're storing it in 2 64-bit quad-words with 14 trailing bits.
|
// We're storing it in 2 64-bit quad-words with 14 trailing bits.
|
||||||
// 64 * 2 = 128
|
// 64 * 2 = 128
|
||||||
|
|
||||||
// Signature [114..59] <- Hash [58..31] <- Serial [30..1] <- Upgrade [0]
|
// Signature [114..59] <- Hash [58..31] <- Serial [30..1] <- Upgrade [0]
|
||||||
pRaw[0] = FIRSTNBITS(Signature, 5) << 59 | FIRSTNBITS(Hash, 28) << 31 | Serial << 1 | isUpgrade;
|
pRaw[0] = FIRSTNBITS(info.Signature, 5) << 59 | FIRSTNBITS(info.Hash, 28) << 31 | info.Serial << 1 | info.isUpgrade;
|
||||||
pRaw[1] = NEXTSNBITS(Signature, 51, 5);
|
pRaw[1] = NEXTSNBITS(info.Signature, 51, 5);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -87,23 +87,24 @@ BOOL BINK1998::Verify(std::string &pKey)
|
|||||||
}
|
}
|
||||||
|
|
||||||
BN_CTX *numContext = BN_CTX_new();
|
BN_CTX *numContext = BN_CTX_new();
|
||||||
|
KeyInfo info;
|
||||||
|
|
||||||
QWORD pRaw[2]{};
|
QWORD pRaw[2];
|
||||||
|
|
||||||
// Convert Base24 CD-key to bytecode.
|
// Convert Base24 CD-key to bytecode.
|
||||||
unbase24((BYTE *)pRaw, pKey);
|
unbase24((BYTE *)pRaw, pKey);
|
||||||
|
|
||||||
// Extract RPK, hash and signature from bytecode.
|
// Extract RPK, hash and signature from bytecode.
|
||||||
Unpack(pRaw);
|
Unpack(info, pRaw);
|
||||||
|
|
||||||
fmt::print(UMSKT::debug, "Validation results:\n");
|
fmt::print(UMSKT::debug, "Validation results:\n");
|
||||||
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", isUpgrade);
|
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", info.isUpgrade);
|
||||||
fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", Serial);
|
fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", info.Serial);
|
||||||
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", Hash);
|
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", info.Hash);
|
||||||
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", Signature);
|
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", info.Signature);
|
||||||
fmt::print(UMSKT::debug, "\n");
|
fmt::print(UMSKT::debug, "\n");
|
||||||
|
|
||||||
DWORD pData = Serial << 1 | isUpgrade;
|
DWORD pData = info.Serial << 1 | info.isUpgrade;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
@ -120,12 +121,13 @@ BOOL BINK1998::Verify(std::string &pKey)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
BIGNUM *e = BN_lebin2bn((BYTE *)&Hash, sizeof(Hash), nullptr),
|
BIGNUM *e = BN_lebin2bn((BYTE *)&info.Hash, sizeof(info.Hash), nullptr),
|
||||||
*s = BN_lebin2bn((BYTE *)&Signature, sizeof(Signature), nullptr), *x = BN_new(), *y = BN_new();
|
*s = BN_lebin2bn((BYTE *)&info.Hash, sizeof(info.Hash), nullptr);
|
||||||
|
|
||||||
|
BIGNUM *x = BN_CTX_get(numContext), *y = BN_CTX_get(numContext);
|
||||||
|
|
||||||
// Create 2 points on the elliptic curve.
|
// Create 2 points on the elliptic curve.
|
||||||
EC_POINT *t = EC_POINT_new(eCurve);
|
EC_POINT *t = EC_POINT_new(eCurve), *p = EC_POINT_new(eCurve);
|
||||||
EC_POINT *p = EC_POINT_new(eCurve);
|
|
||||||
|
|
||||||
// t = sG
|
// t = sG
|
||||||
EC_POINT_mul(eCurve, t, nullptr, basePoint, s, numContext);
|
EC_POINT_mul(eCurve, t, nullptr, basePoint, s, numContext);
|
||||||
@ -139,16 +141,16 @@ BOOL BINK1998::Verify(std::string &pKey)
|
|||||||
// x = P.x; y = P.y;
|
// x = P.x; y = P.y;
|
||||||
EC_POINT_get_affine_coordinates(eCurve, p, x, y, numContext);
|
EC_POINT_get_affine_coordinates(eCurve, p, x, y, numContext);
|
||||||
|
|
||||||
BYTE msgDigest[SHA_DIGEST_LENGTH]{}, msgBuffer[SHA_MSG_LENGTH_XP]{}, xBin[FIELD_BYTES]{}, yBin[FIELD_BYTES]{};
|
BYTE msgDigest[SHA_DIGEST_LENGTH], msgBuffer[SHA_MSG_LENGTH_XP], xBin[FIELD_BYTES], yBin[FIELD_BYTES];
|
||||||
|
|
||||||
// Convert resulting point coordinates to bytes.
|
// Convert resulting point coordinates to bytes.
|
||||||
BN_bn2lebin(x, xBin, FIELD_BYTES);
|
BN_bn2lebin(x, xBin, FIELD_BYTES);
|
||||||
BN_bn2lebin(y, yBin, FIELD_BYTES);
|
BN_bn2lebin(y, yBin, FIELD_BYTES);
|
||||||
|
|
||||||
// Assemble the SHA message.
|
// Assemble the SHA message.
|
||||||
memcpy((void *)&msgBuffer[0], (void *)&pData, 4);
|
memcpy(&msgBuffer[0], &pData, 4);
|
||||||
memcpy((void *)&msgBuffer[4], (void *)xBin, FIELD_BYTES);
|
memcpy(&msgBuffer[4], xBin, FIELD_BYTES);
|
||||||
memcpy((void *)&msgBuffer[4 + FIELD_BYTES], (void *)yBin, FIELD_BYTES);
|
memcpy(&msgBuffer[4 + FIELD_BYTES], yBin, FIELD_BYTES);
|
||||||
|
|
||||||
// compHash = SHA1(pSerial || P.x || P.y)
|
// compHash = SHA1(pSerial || P.x || P.y)
|
||||||
SHA1(msgBuffer, SHA_MSG_LENGTH_XP, msgDigest);
|
SHA1(msgBuffer, SHA_MSG_LENGTH_XP, msgDigest);
|
||||||
@ -159,8 +161,6 @@ BOOL BINK1998::Verify(std::string &pKey)
|
|||||||
|
|
||||||
BN_free(e);
|
BN_free(e);
|
||||||
BN_free(s);
|
BN_free(s);
|
||||||
BN_free(x);
|
|
||||||
BN_free(y);
|
|
||||||
|
|
||||||
BN_CTX_free(numContext);
|
BN_CTX_free(numContext);
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ BOOL BINK1998::Verify(std::string &pKey)
|
|||||||
EC_POINT_free(p);
|
EC_POINT_free(p);
|
||||||
|
|
||||||
// If the computed hash checks out, the key is valid.
|
// If the computed hash checks out, the key is valid.
|
||||||
return compHash == Hash;
|
return compHash == info.Hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,16 +178,17 @@ BOOL BINK1998::Verify(std::string &pKey)
|
|||||||
*
|
*
|
||||||
* @return true on success, false on fail
|
* @return true on success, false on fail
|
||||||
*/
|
*/
|
||||||
BOOL BINK1998::Generate(std::string &pKey)
|
BOOL BINK1998::Generate(KeyInfo &info, std::string &pKey)
|
||||||
{
|
{
|
||||||
BN_CTX *numContext = BN_CTX_new();
|
BN_CTX *numContext = BN_CTX_new();
|
||||||
|
|
||||||
BIGNUM *c = BN_new(), *s = BN_new(), *x = BN_new(), *y = BN_new();
|
BIGNUM *c = BN_CTX_get(numContext), *s = BN_CTX_get(numContext), *x = BN_CTX_get(numContext),
|
||||||
|
*y = BN_CTX_get(numContext);
|
||||||
|
|
||||||
QWORD pRaw[2]{};
|
QWORD pRaw[2]{};
|
||||||
|
|
||||||
// Data segment of the RPK.
|
// Data segment of the RPK.
|
||||||
DWORD pData = Serial << 1 | isUpgrade;
|
DWORD pData = info.Serial << 1 | info.isUpgrade;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -204,23 +205,24 @@ BOOL BINK1998::Generate(std::string &pKey)
|
|||||||
// x = R.x; y = R.y;
|
// x = R.x; y = R.y;
|
||||||
EC_POINT_get_affine_coordinates(eCurve, r, x, y, numContext);
|
EC_POINT_get_affine_coordinates(eCurve, r, x, y, numContext);
|
||||||
|
|
||||||
BYTE msgDigest[SHA_DIGEST_LENGTH]{}, msgBuffer[SHA_MSG_LENGTH_XP]{}, xBin[FIELD_BYTES]{}, yBin[FIELD_BYTES]{};
|
BYTE msgDigest[SHA_DIGEST_LENGTH]{}, msgBuffer[SHA_MSG_LENGTH_XP]{};
|
||||||
|
BYTE xBin[FIELD_BYTES]{}, yBin[FIELD_BYTES]{};
|
||||||
|
|
||||||
// Convert coordinates to bytes.
|
// Convert coordinates to bytes.
|
||||||
BN_bn2lebin(x, xBin, FIELD_BYTES);
|
BN_bn2lebin(x, xBin, FIELD_BYTES);
|
||||||
BN_bn2lebin(y, yBin, FIELD_BYTES);
|
BN_bn2lebin(y, yBin, FIELD_BYTES);
|
||||||
|
|
||||||
// Assemble the SHA message.
|
// Assemble the SHA message.
|
||||||
memcpy((void *)&msgBuffer[0], (void *)&pData, 4);
|
memcpy(&msgBuffer[0], &pData, 4);
|
||||||
memcpy((void *)&msgBuffer[4], (void *)xBin, FIELD_BYTES);
|
memcpy(&msgBuffer[4], xBin, FIELD_BYTES);
|
||||||
memcpy((void *)&msgBuffer[4 + FIELD_BYTES], (void *)yBin, FIELD_BYTES);
|
memcpy(&msgBuffer[4 + FIELD_BYTES], yBin, FIELD_BYTES);
|
||||||
|
|
||||||
// pHash = SHA1(pSerial || R.x || R.y)
|
// pHash = SHA1(pSerial || R.x || R.y)
|
||||||
SHA1(msgBuffer, SHA_MSG_LENGTH_XP, msgDigest);
|
SHA1(msgBuffer, SHA_MSG_LENGTH_XP, msgDigest);
|
||||||
|
|
||||||
// Translate the byte digest into a 32-bit integer - this is our computed pHash.
|
// Translate the byte digest into a 32-bit integer - this is our computed pHash.
|
||||||
// Truncate the pHash to 28 bits.
|
// Truncate the pHash to 28 bits.
|
||||||
DWORD pHash = BYDWORD(msgDigest) >> 4 & BITMASK(28);
|
info.Hash = BYDWORD(msgDigest) >> 4 & BITMASK(28);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
@ -243,26 +245,26 @@ BOOL BINK1998::Generate(std::string &pKey)
|
|||||||
|
|
||||||
// s = ek;
|
// s = ek;
|
||||||
BN_copy(s, privateKey);
|
BN_copy(s, privateKey);
|
||||||
BN_mul_word(s, pHash);
|
BN_mul_word(s, info.Hash);
|
||||||
|
|
||||||
// s += c (mod n)
|
// s += c (mod n)
|
||||||
BN_mod_add(s, s, c, genOrder, numContext);
|
BN_mod_add(s, s, c, genOrder, numContext);
|
||||||
|
|
||||||
// Translate resulting scalar into a 64-bit integer (the byte order is little-endian).
|
// Translate resulting scalar into a 64-bit integer (the byte order is little-endian).
|
||||||
BN_bn2lebinpad(s, (BYTE *)&Signature, BN_num_bytes(s));
|
BN_bn2lebinpad(s, (BYTE *)&info.Signature, BN_num_bytes(s));
|
||||||
|
|
||||||
// Pack product key.
|
// Pack product key.
|
||||||
Pack(pRaw);
|
Pack(info, pRaw);
|
||||||
|
|
||||||
fmt::print(UMSKT::debug, "Generation results:\n");
|
fmt::print(UMSKT::debug, "Generation results:\n");
|
||||||
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", isUpgrade);
|
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", info.isUpgrade);
|
||||||
fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", Serial);
|
fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", info.Serial);
|
||||||
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", Hash);
|
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", info.Hash);
|
||||||
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", Signature);
|
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", info.Signature);
|
||||||
fmt::print(UMSKT::debug, "\n");
|
fmt::print(UMSKT::debug, "\n");
|
||||||
|
|
||||||
EC_POINT_free(r);
|
EC_POINT_free(r);
|
||||||
} while (Signature > BITMASK(55));
|
} while (info.Signature > BITMASK(55));
|
||||||
// ↑ ↑ ↑
|
// ↑ ↑ ↑
|
||||||
// The signature can't be longer than 55 bits, else it will
|
// The signature can't be longer than 55 bits, else it will
|
||||||
// make the CD-key longer than 25 characters.
|
// make the CD-key longer than 25 characters.
|
||||||
@ -270,11 +272,6 @@ BOOL BINK1998::Generate(std::string &pKey)
|
|||||||
// Convert bytecode to Base24 CD-key.
|
// Convert bytecode to Base24 CD-key.
|
||||||
base24(pKey, (BYTE *)pRaw);
|
base24(pKey, (BYTE *)pRaw);
|
||||||
|
|
||||||
BN_free(c);
|
|
||||||
BN_free(s);
|
|
||||||
BN_free(x);
|
|
||||||
BN_free(y);
|
|
||||||
|
|
||||||
BN_CTX_free(numContext);
|
BN_CTX_free(numContext);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -27,12 +27,11 @@
|
|||||||
|
|
||||||
class BINK1998 : public PIDGEN3
|
class BINK1998 : public PIDGEN3
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BOOL Unpack(QWORD (&pRaw)[2]) override;
|
BOOL Unpack(KeyInfo &info, QWORD *pRaw) override;
|
||||||
BOOL Pack(QWORD (&pRaw)[2]) override;
|
BOOL Pack(const KeyInfo &info, QWORD *pRaw) override;
|
||||||
BOOL Verify(std::string &pKey) override;
|
BOOL Verify(std::string &pKey) override;
|
||||||
BOOL Generate(std::string &pKey) override;
|
BOOL Generate(KeyInfo &info, std::string &pKey) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // UMSKT_BINK1998_H
|
#endif // UMSKT_BINK1998_H
|
||||||
|
@ -34,27 +34,27 @@
|
|||||||
*
|
*
|
||||||
* @param pRaw *QWORD[2] raw product key input
|
* @param pRaw *QWORD[2] raw product key input
|
||||||
**/
|
**/
|
||||||
BOOL BINK2002::Unpack(QWORD (&pRaw)[2])
|
BOOL BINK2002::Unpack(KeyInfo &info, QWORD *pRaw)
|
||||||
{
|
{
|
||||||
// We're assuming that the quantity of information within the product key is at most 114 bits.
|
// We're assuming that the quantity of information within the product key is at most 114 bits.
|
||||||
// log2(24^25) = 114.
|
// log2(24^25) = 114.
|
||||||
|
|
||||||
// Upgrade = Bit 0
|
// Upgrade = Bit 0
|
||||||
isUpgrade = FIRSTNBITS(pRaw[0], 1);
|
info.isUpgrade = FIRSTNBITS(pRaw[0], 1);
|
||||||
|
|
||||||
// Channel ID = Bits [1..10] -> 10 bits
|
// Channel ID = Bits [1..10] -> 10 bits
|
||||||
ChannelID = NEXTSNBITS(pRaw[0], 10, 1);
|
info.ChannelID = NEXTSNBITS(pRaw[0], 10, 1);
|
||||||
|
|
||||||
// Hash = Bits [11..41] -> 31 bits
|
// Hash = Bits [11..41] -> 31 bits
|
||||||
Hash = NEXTSNBITS(pRaw[0], 31, 11);
|
info.Hash = NEXTSNBITS(pRaw[0], 31, 11);
|
||||||
|
|
||||||
// Signature = Bits [42..103] -> 62 bits
|
// Signature = Bits [42..103] -> 62 bits
|
||||||
// The quad-word signature overlaps AuthInfo in bits 104 and 105,
|
// The quad-word signature overlaps AuthInfo in bits 104 and 105,
|
||||||
// hence Microsoft employs a secret technique called: Signature = HIDWORD(Signature) >> 2 | LODWORD(Signature)
|
// hence Microsoft employs a secret technique called: Signature = HIDWORD(Signature) >> 2 | LODWORD(Signature)
|
||||||
Signature = NEXTSNBITS(pRaw[1], 30, 10) << 32 | FIRSTNBITS(pRaw[1], 10) << 22 | NEXTSNBITS(pRaw[0], 22, 42);
|
info.Signature = NEXTSNBITS(pRaw[1], 30, 10) << 32 | FIRSTNBITS(pRaw[1], 10) << 22 | NEXTSNBITS(pRaw[0], 22, 42);
|
||||||
|
|
||||||
// AuthInfo = Bits [104..113] -> 10 bits
|
// AuthInfo = Bits [104..113] -> 10 bits
|
||||||
AuthInfo = NEXTSNBITS(pRaw[1], 10, 40);
|
info.AuthInfo = NEXTSNBITS(pRaw[1], 10, 40);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -64,11 +64,11 @@ BOOL BINK2002::Unpack(QWORD (&pRaw)[2])
|
|||||||
*
|
*
|
||||||
* @param pRaw *QWORD[2] raw product key output
|
* @param pRaw *QWORD[2] raw product key output
|
||||||
**/
|
**/
|
||||||
BOOL BINK2002::Pack(QWORD (&pRaw)[2])
|
BOOL BINK2002::Pack(const KeyInfo &info, QWORD *pRaw)
|
||||||
{
|
{
|
||||||
// AuthInfo [113..104] <- Signature [103..42] <- Hash [41..11] <- Channel ID [10..1] <- Upgrade [0]
|
// AuthInfo [113..104] <- Signature [103..42] <- Hash [41..11] <- Channel ID [10..1] <- Upgrade [0]
|
||||||
pRaw[0] = FIRSTNBITS(Signature, 22) << 42 | (QWORD)Hash << 11 | ChannelID << 1 | isUpgrade;
|
pRaw[0] = FIRSTNBITS(info.Signature, 22) << 42 | (QWORD)info.Hash << 11 | info.ChannelID << 1 | info.isUpgrade;
|
||||||
pRaw[1] = FIRSTNBITS(AuthInfo, 10) << 40 | NEXTSNBITS(Signature, 40, 22);
|
pRaw[1] = FIRSTNBITS(info.AuthInfo, 10) << 40 | NEXTSNBITS(info.Signature, 40, 22);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -81,23 +81,24 @@ BOOL BINK2002::Pack(QWORD (&pRaw)[2])
|
|||||||
BOOL BINK2002::Verify(std::string &pKey)
|
BOOL BINK2002::Verify(std::string &pKey)
|
||||||
{
|
{
|
||||||
BN_CTX *context = BN_CTX_new();
|
BN_CTX *context = BN_CTX_new();
|
||||||
|
KeyInfo info;
|
||||||
|
|
||||||
QWORD bKey[2]{};
|
QWORD bKey[2];
|
||||||
|
|
||||||
// Convert Base24 CD-key to bytecode.
|
// Convert Base24 CD-key to bytecode.
|
||||||
unbase24((BYTE *)bKey, pKey.c_str());
|
unbase24((BYTE *)bKey, pKey.c_str());
|
||||||
|
|
||||||
// Extract product key segments from bytecode.
|
// Extract product key segments from bytecode.
|
||||||
Unpack(bKey);
|
Unpack(info, bKey);
|
||||||
|
|
||||||
DWORD pData = ChannelID << 1 | isUpgrade;
|
DWORD pData = info.ChannelID << 1 | info.isUpgrade;
|
||||||
|
|
||||||
fmt::print(UMSKT::debug, "Validation results:\n");
|
fmt::print(UMSKT::debug, "Validation results:\n");
|
||||||
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", isUpgrade);
|
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", info.isUpgrade);
|
||||||
fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", ChannelID);
|
fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", info.ChannelID);
|
||||||
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", Hash);
|
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", info.Hash);
|
||||||
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", Signature);
|
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", info.Signature);
|
||||||
fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", AuthInfo);
|
fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", info.AuthInfo);
|
||||||
fmt::print(UMSKT::debug, "\n");
|
fmt::print(UMSKT::debug, "\n");
|
||||||
|
|
||||||
BYTE msgDigest[SHA_DIGEST_LENGTH]{}, msgBuffer[SHA_MSG_LENGTH_2003]{}, xBin[FIELD_BYTES_2003]{},
|
BYTE msgDigest[SHA_DIGEST_LENGTH]{}, msgBuffer[SHA_MSG_LENGTH_2003]{}, xBin[FIELD_BYTES_2003]{},
|
||||||
@ -107,12 +108,12 @@ BOOL BINK2002::Verify(std::string &pKey)
|
|||||||
msgBuffer[0x00] = 0x5D;
|
msgBuffer[0x00] = 0x5D;
|
||||||
msgBuffer[0x01] = (pData & 0x00FF);
|
msgBuffer[0x01] = (pData & 0x00FF);
|
||||||
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
|
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
|
||||||
msgBuffer[0x03] = (Hash & 0x000000FF);
|
msgBuffer[0x03] = (info.Hash & 0x000000FF);
|
||||||
msgBuffer[0x04] = (Hash & 0x0000FF00) >> 8;
|
msgBuffer[0x04] = (info.Hash & 0x0000FF00) >> 8;
|
||||||
msgBuffer[0x05] = (Hash & 0x00FF0000) >> 16;
|
msgBuffer[0x05] = (info.Hash & 0x00FF0000) >> 16;
|
||||||
msgBuffer[0x06] = (Hash & 0xFF000000) >> 24;
|
msgBuffer[0x06] = (info.Hash & 0xFF000000) >> 24;
|
||||||
msgBuffer[0x07] = (AuthInfo & 0x00FF);
|
msgBuffer[0x07] = (info.AuthInfo & 0x00FF);
|
||||||
msgBuffer[0x08] = (AuthInfo & 0xFF00) >> 8;
|
msgBuffer[0x08] = (info.AuthInfo & 0xFF00) >> 8;
|
||||||
msgBuffer[0x09] = 0x00;
|
msgBuffer[0x09] = 0x00;
|
||||||
msgBuffer[0x0A] = 0x00;
|
msgBuffer[0x0A] = 0x00;
|
||||||
|
|
||||||
@ -140,7 +141,7 @@ BOOL BINK2002::Verify(std::string &pKey)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
BIGNUM *e = BN_lebin2bn((BYTE *)&iSignature, sizeof(iSignature), nullptr),
|
BIGNUM *e = BN_lebin2bn((BYTE *)&iSignature, sizeof(iSignature), nullptr),
|
||||||
*s = BN_lebin2bn((BYTE *)&Signature, sizeof(Signature), nullptr), *x = BN_new(), *y = BN_new();
|
*s = BN_lebin2bn((BYTE *)&info.Signature, sizeof(info.Signature), nullptr), *x = BN_new(), *y = BN_new();
|
||||||
|
|
||||||
// Create 2 points on the elliptic curve.
|
// Create 2 points on the elliptic curve.
|
||||||
EC_POINT *p = EC_POINT_new(eCurve), *t = EC_POINT_new(eCurve);
|
EC_POINT *p = EC_POINT_new(eCurve), *t = EC_POINT_new(eCurve);
|
||||||
@ -190,11 +191,11 @@ BOOL BINK2002::Verify(std::string &pKey)
|
|||||||
EC_POINT_free(t);
|
EC_POINT_free(t);
|
||||||
|
|
||||||
// If the computed hash checks out, the key is valid.
|
// If the computed hash checks out, the key is valid.
|
||||||
return compHash == Hash;
|
return compHash == info.Hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generates a Windows Server 2003-like Product Key. */
|
/* Generates a Windows Server 2003-like Product Key. */
|
||||||
BOOL BINK2002::Generate(std::string &pKey)
|
BOOL BINK2002::Generate(KeyInfo &info, std::string &pKey)
|
||||||
{
|
{
|
||||||
BN_CTX *numContext = BN_CTX_new();
|
BN_CTX *numContext = BN_CTX_new();
|
||||||
|
|
||||||
@ -203,7 +204,7 @@ BOOL BINK2002::Generate(std::string &pKey)
|
|||||||
QWORD pRaw[2]{};
|
QWORD pRaw[2]{};
|
||||||
|
|
||||||
// Data segment of the RPK.
|
// Data segment of the RPK.
|
||||||
DWORD pData = ChannelID << 1 | isUpgrade;
|
DWORD pData = info.ChannelID << 1 | info.isUpgrade;
|
||||||
|
|
||||||
BOOL noSquare;
|
BOOL noSquare;
|
||||||
|
|
||||||
@ -251,8 +252,8 @@ BOOL BINK2002::Generate(std::string &pKey)
|
|||||||
msgBuffer[0x04] = (pHash & 0x0000FF00) >> 8;
|
msgBuffer[0x04] = (pHash & 0x0000FF00) >> 8;
|
||||||
msgBuffer[0x05] = (pHash & 0x00FF0000) >> 16;
|
msgBuffer[0x05] = (pHash & 0x00FF0000) >> 16;
|
||||||
msgBuffer[0x06] = (pHash & 0xFF000000) >> 24;
|
msgBuffer[0x06] = (pHash & 0xFF000000) >> 24;
|
||||||
msgBuffer[0x07] = (AuthInfo & 0x00FF);
|
msgBuffer[0x07] = (info.AuthInfo & 0x00FF);
|
||||||
msgBuffer[0x08] = (AuthInfo & 0xFF00) >> 8;
|
msgBuffer[0x08] = (info.AuthInfo & 0xFF00) >> 8;
|
||||||
msgBuffer[0x09] = 0x00;
|
msgBuffer[0x09] = 0x00;
|
||||||
msgBuffer[0x0A] = 0x00;
|
msgBuffer[0x0A] = 0x00;
|
||||||
|
|
||||||
@ -331,21 +332,21 @@ BOOL BINK2002::Generate(std::string &pKey)
|
|||||||
BN_rshift1(s, s);
|
BN_rshift1(s, s);
|
||||||
|
|
||||||
// Translate resulting scalar into a 64-bit integer (the byte order is little-endian).
|
// Translate resulting scalar into a 64-bit integer (the byte order is little-endian).
|
||||||
BN_bn2lebinpad(s, (BYTE *)&Signature, BN_num_bytes(s));
|
BN_bn2lebinpad(s, (BYTE *)&info.Signature, BN_num_bytes(s));
|
||||||
|
|
||||||
// Pack product key.
|
// Pack product key.
|
||||||
Pack(pRaw);
|
Pack(info, pRaw);
|
||||||
|
|
||||||
fmt::print(UMSKT::debug, "Generation results:\n");
|
fmt::print(UMSKT::debug, "Generation results:\n");
|
||||||
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", isUpgrade);
|
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", info.isUpgrade);
|
||||||
fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", ChannelID);
|
fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", info.ChannelID);
|
||||||
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", Hash);
|
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", info.Hash);
|
||||||
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", Signature);
|
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", info.Signature);
|
||||||
fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", AuthInfo);
|
fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", info.AuthInfo);
|
||||||
fmt::print(UMSKT::debug, "\n");
|
fmt::print(UMSKT::debug, "\n");
|
||||||
|
|
||||||
EC_POINT_free(r);
|
EC_POINT_free(r);
|
||||||
} while (Signature > BITMASK(62) || noSquare);
|
} while (info.Signature > BITMASK(62) || noSquare);
|
||||||
// ↑ ↑ ↑
|
// ↑ ↑ ↑
|
||||||
// The signature can't be longer than 62 bits, else it will
|
// The signature can't be longer than 62 bits, else it will
|
||||||
// overlap with the AuthInfo segment next to it.
|
// overlap with the AuthInfo segment next to it.
|
||||||
|
@ -27,12 +27,11 @@
|
|||||||
|
|
||||||
class BINK2002 : public PIDGEN3
|
class BINK2002 : public PIDGEN3
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BOOL Unpack(QWORD (&pRaw)[2]) override;
|
BOOL Unpack(KeyInfo &info, QWORD *pRaw) override;
|
||||||
BOOL Pack(QWORD (&pRaw)[2]) override;
|
BOOL Pack(const KeyInfo &info, QWORD *pRaw) override;
|
||||||
BOOL Verify(std::string &pKey) override;
|
BOOL Verify(std::string &pKey) override;
|
||||||
BOOL Generate(std::string &pKey) override;
|
BOOL Generate(KeyInfo &info, std::string &pKey) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // UMSKT_BINK2002_H
|
#endif // UMSKT_BINK2002_H
|
||||||
|
@ -62,39 +62,36 @@ BOOL PIDGEN3::LoadEllipticCurve(const std::string pSel, const std::string aSel,
|
|||||||
// Initialize BIGNUM and BIGNUMCTX structures.
|
// Initialize BIGNUM and BIGNUMCTX structures.
|
||||||
// BIGNUM - Large numbers
|
// BIGNUM - Large numbers
|
||||||
// BIGNUMCTX - Context large numbers (temporary)
|
// BIGNUMCTX - Context large numbers (temporary)
|
||||||
BIGNUM *a, *b, *p, *generatorX, *generatorY, *publicKeyX, *publicKeyY;
|
|
||||||
BN_CTX *context;
|
// Context variable
|
||||||
|
BN_CTX *context = BN_CTX_new();
|
||||||
|
|
||||||
// We're presented with an elliptic curve, a multivariable function y(x; p; a; b), where
|
// We're presented with an elliptic curve, a multivariable function y(x; p; a; b), where
|
||||||
// y^2 % p = x^3 + ax + b % p.
|
// y^2 % p = x^3 + ax + b % p.
|
||||||
a = BN_new();
|
BIGNUM *a = BN_CTX_get(context), *b = BN_CTX_get(context), *p = BN_CTX_get(context);
|
||||||
b = BN_new();
|
|
||||||
p = BN_new();
|
|
||||||
|
|
||||||
// Public key will consist of the resulting (x; y) values.
|
// Public key will consist of the resulting (x; y) values.
|
||||||
publicKeyX = BN_new();
|
BIGNUM *publicKeyX = BN_CTX_get(context), *publicKeyY = BN_CTX_get(context);
|
||||||
publicKeyY = BN_new();
|
|
||||||
|
|
||||||
// G(x; y) is a generator function, its return value represents a point on the elliptic curve.
|
// G(x; y) is a generator function, its return value represents a point on the elliptic curve.
|
||||||
generatorX = BN_new();
|
BIGNUM *generatorX = BN_CTX_get(context), *generatorY = BN_CTX_get(context);
|
||||||
generatorY = BN_new();
|
|
||||||
|
|
||||||
// Context variable
|
genOrder = BN_new();
|
||||||
context = BN_CTX_new();
|
privateKey = BN_new();
|
||||||
|
|
||||||
/* Public data */
|
/* Public data */
|
||||||
BN_dec2bn(&p, pSel.c_str());
|
BN_dec2bn(&p, &pSel[0]);
|
||||||
BN_dec2bn(&a, aSel.c_str());
|
BN_dec2bn(&a, &aSel[0]);
|
||||||
BN_dec2bn(&b, bSel.c_str());
|
BN_dec2bn(&b, &bSel[0]);
|
||||||
BN_dec2bn(&generatorX, generatorXSel.c_str());
|
BN_dec2bn(&generatorX, &generatorXSel[0]);
|
||||||
BN_dec2bn(&generatorY, generatorYSel.c_str());
|
BN_dec2bn(&generatorY, &generatorYSel[0]);
|
||||||
|
|
||||||
BN_dec2bn(&publicKeyX, publicKeyXSel.c_str());
|
BN_dec2bn(&publicKeyX, &publicKeyXSel[0]);
|
||||||
BN_dec2bn(&publicKeyY, publicKeyYSel.c_str());
|
BN_dec2bn(&publicKeyY, &publicKeyYSel[0]);
|
||||||
|
|
||||||
/* Computed Data */
|
/* Computed Data */
|
||||||
BN_dec2bn(&genOrder, genOrderSel.c_str());
|
BN_dec2bn(&genOrder, &genOrderSel[0]);
|
||||||
BN_dec2bn(&privateKey, privateKeySel.c_str());
|
BN_dec2bn(&privateKey, &privateKeySel[0]);
|
||||||
BN_sub(privateKey, genOrder, privateKey);
|
BN_sub(privateKey, genOrder, privateKey);
|
||||||
|
|
||||||
/* Elliptic Curve calculations. */
|
/* Elliptic Curve calculations. */
|
||||||
@ -118,13 +115,6 @@ BOOL PIDGEN3::LoadEllipticCurve(const std::string pSel, const std::string aSel,
|
|||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
BN_CTX_free(context);
|
BN_CTX_free(context);
|
||||||
BN_free(p);
|
|
||||||
BN_free(a);
|
|
||||||
BN_free(b);
|
|
||||||
BN_free(generatorX);
|
|
||||||
BN_free(generatorY);
|
|
||||||
BN_free(publicKeyX);
|
|
||||||
BN_free(publicKeyY);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -182,7 +172,7 @@ int PIDGEN3::BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen)
|
|||||||
**/
|
**/
|
||||||
void PIDGEN3::base24(std::string &cdKey, BYTE *byteSeq)
|
void PIDGEN3::base24(std::string &cdKey, BYTE *byteSeq)
|
||||||
{
|
{
|
||||||
BYTE rbyteSeq[16];
|
BYTE rbyteSeq[16], output[26];
|
||||||
BIGNUM *z;
|
BIGNUM *z;
|
||||||
|
|
||||||
// Copy byte sequence to the reversed byte sequence.
|
// Copy byte sequence to the reversed byte sequence.
|
||||||
@ -204,9 +194,13 @@ void PIDGEN3::base24(std::string &cdKey, BYTE *byteSeq)
|
|||||||
// Divide z by 24 and convert the remainder to a CD-key char.
|
// Divide z by 24 and convert the remainder to a CD-key char.
|
||||||
for (int i = 24; i >= 0; i--)
|
for (int i = 24; i >= 0; i--)
|
||||||
{
|
{
|
||||||
cdKey[i] = pKeyCharset[BN_div_word(z, 24)];
|
output[i] = pKeyCharset[BN_div_word(z, 24)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output[25] = 0;
|
||||||
|
|
||||||
|
cdKey = (char *)output;
|
||||||
|
|
||||||
BN_free(z);
|
BN_free(z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +31,6 @@ class PIDGEN3
|
|||||||
EC_GROUP *eCurve;
|
EC_GROUP *eCurve;
|
||||||
EC_POINT *basePoint, *publicKey, *genPoint, *pubPoint;
|
EC_POINT *basePoint, *publicKey, *genPoint, *pubPoint;
|
||||||
BIGNUM *genOrder, *privateKey;
|
BIGNUM *genOrder, *privateKey;
|
||||||
DWORD Serial, AuthInfo, ChannelID, Hash;
|
|
||||||
QWORD Signature;
|
|
||||||
BOOL isUpgrade;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PIDGEN3()
|
PIDGEN3()
|
||||||
@ -49,28 +46,13 @@ class PIDGEN3
|
|||||||
EC_POINT_free(publicKey);
|
EC_POINT_free(publicKey);
|
||||||
BN_free(genOrder);
|
BN_free(genOrder);
|
||||||
BN_free(privateKey);
|
BN_free(privateKey);
|
||||||
BN_free(privateKey);
|
|
||||||
BN_free(genOrder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr char pKeyCharset[] = "BCDFGHJKMPQRTVWXY2346789";
|
struct KeyInfo
|
||||||
|
{
|
||||||
BOOL LoadEllipticCurve(std::string pSel, std::string aSel, std::string bSel, std::string generatorXSel,
|
DWORD Serial = 0, AuthInfo = 0, ChannelID = 0, Hash = 0;
|
||||||
std::string generatorYSel, std::string publicKeyXSel, std::string publicKeyYSel,
|
QWORD Signature = 0;
|
||||||
std::string genOrderSel, std::string privateKeySel);
|
BOOL isUpgrade = false;
|
||||||
|
|
||||||
virtual BOOL Unpack(QWORD (&pRaw)[2]) = 0;
|
|
||||||
virtual BOOL Pack(QWORD (&pRaw)[2]) = 0;
|
|
||||||
virtual BOOL Verify(std::string &pKey) = 0;
|
|
||||||
virtual BOOL Generate(std::string &pKey) = 0;
|
|
||||||
|
|
||||||
// PIDGEN3.cpp
|
|
||||||
// Hello OpenSSL developers, please tell me, where is this function at?
|
|
||||||
int BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen);
|
|
||||||
void endian(BYTE *data, int length);
|
|
||||||
|
|
||||||
void base24(std::string &cdKey, BYTE *byteSeq);
|
|
||||||
void unbase24(BYTE *byteSeq, std::string cdKey);
|
|
||||||
|
|
||||||
void setSerial(DWORD serialIn)
|
void setSerial(DWORD serialIn)
|
||||||
{
|
{
|
||||||
@ -86,6 +68,26 @@ class PIDGEN3
|
|||||||
{
|
{
|
||||||
ChannelID = ChannelIDIn;
|
ChannelID = ChannelIDIn;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr char pKeyCharset[] = "BCDFGHJKMPQRTVWXY2346789";
|
||||||
|
|
||||||
|
BOOL LoadEllipticCurve(std::string pSel, std::string aSel, std::string bSel, std::string generatorXSel,
|
||||||
|
std::string generatorYSel, std::string publicKeyXSel, std::string publicKeyYSel,
|
||||||
|
std::string genOrderSel, std::string privateKeySel);
|
||||||
|
|
||||||
|
virtual BOOL Unpack(KeyInfo &info, QWORD *pRaw) = 0;
|
||||||
|
virtual BOOL Pack(const KeyInfo &info, QWORD *pRaw) = 0;
|
||||||
|
virtual BOOL Verify(std::string &pKey) = 0;
|
||||||
|
virtual BOOL Generate(KeyInfo &info, std::string &pKey) = 0;
|
||||||
|
|
||||||
|
// PIDGEN3.cpp
|
||||||
|
// Hello OpenSSL developers, please tell me, where is this function at?
|
||||||
|
int BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen);
|
||||||
|
void endian(BYTE *data, int length);
|
||||||
|
|
||||||
|
void base24(std::string &cdKey, BYTE *byteSeq);
|
||||||
|
void unbase24(BYTE *byteSeq, std::string cdKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // UMSKT_PIDGEN3_H
|
#endif // UMSKT_PIDGEN3_H
|
||||||
|
@ -31,5 +31,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto cli = CLI();
|
auto cli = CLI();
|
||||||
return cli.Run();
|
status = cli.Run();
|
||||||
|
|
||||||
|
UMSKT::DESTRUCT();
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ void CLI::SetHelpText()
|
|||||||
true, "1", &SetNumberOption};
|
true, "1", &SetNumberOption};
|
||||||
|
|
||||||
helpOptions[OPTION_PRODUCT] = {"p", "product", "which product to generate keys for",
|
helpOptions[OPTION_PRODUCT] = {"p", "product", "which product to generate keys for",
|
||||||
true, options.productCode, nullptr};
|
true, options.productCode, &SetProductCodeOption};
|
||||||
|
|
||||||
helpOptions[OPTION_ACTIVATIONID] = {
|
helpOptions[OPTION_ACTIVATIONID] = {
|
||||||
"i", "instid", "(activation only) installation ID used to generate confirmation ID",
|
"i", "instid", "(activation only) installation ID used to generate confirmation ID",
|
||||||
@ -116,7 +116,8 @@ BOOL CLI::parseCommandLine()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nextarg = arg[i + 1];
|
i++;
|
||||||
|
nextarg = std::string(options.argv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,8 +312,18 @@ BOOL CLI::SetProductIDOption(int count, char *product)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL CLI::SetValidateOption(int count, char *product)
|
BOOL CLI::SetValidateOption(int count, char *productID)
|
||||||
{
|
{
|
||||||
options.keyToCheck = product;
|
options.keyToCheck = productID;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CLI::SetProductCodeOption(int, char *product)
|
||||||
|
{
|
||||||
|
if (options.verbose)
|
||||||
|
{
|
||||||
|
fmt::print("Setting product code to {}\n", product);
|
||||||
|
}
|
||||||
|
options.productCode = product;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user