mirror of
https://github.com/Neo-Desktop/WindowsXPKg
synced 2024-11-22 05:41:01 +02:00
refactor project to use classes (#19)
This commit is contained in:
parent
f6755b0c22
commit
0b94791ee1
@ -25,6 +25,6 @@ CONFIGURE_FILE(keys.json keys.json COPYONLY)
|
|||||||
|
|
||||||
#SET(BUILD_SHARED_LIBS OFF)
|
#SET(BUILD_SHARED_LIBS OFF)
|
||||||
#SET(CMAKE_EXE_LINKER_FLAGS "-static")
|
#SET(CMAKE_EXE_LINKER_FLAGS "-static")
|
||||||
ADD_EXECUTABLE(xpkey src/main.cpp src/server.cpp src/xp.cpp src/key.cpp src/util.cpp src/cli.cpp src/confid.cpp)
|
ADD_EXECUTABLE(xpkey src/main.cpp src/BINK2002.cpp src/BINK1998.cpp src/key.cpp src/util.cpp src/cli.cpp src/confid.cpp)
|
||||||
TARGET_INCLUDE_DIRECTORIES(xpkey PUBLIC crypto)
|
TARGET_INCLUDE_DIRECTORIES(xpkey PUBLIC crypto)
|
||||||
TARGET_LINK_LIBRARIES(xpkey PUBLIC OpenSSL::Crypto nlohmann_json::nlohmann_json fmt)
|
TARGET_LINK_LIBRARIES(xpkey PUBLIC OpenSSL::Crypto nlohmann_json::nlohmann_json fmt)
|
@ -2,10 +2,10 @@
|
|||||||
// Created by Andrew on 01/06/2023.
|
// Created by Andrew on 01/06/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "header.h"
|
#include "BINK1998.h"
|
||||||
|
|
||||||
/* Unpacks the Windows XP-like Product Key. */
|
/* Unpacks the Windows XP-like Product Key. */
|
||||||
void unpackXP(
|
void BINK1998::Unpack(
|
||||||
QWORD (&pRaw)[2],
|
QWORD (&pRaw)[2],
|
||||||
DWORD &pSerial,
|
DWORD &pSerial,
|
||||||
DWORD &pHash,
|
DWORD &pHash,
|
||||||
@ -25,7 +25,7 @@ void unpackXP(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Packs the Windows XP-like Product Key. */
|
/* Packs the Windows XP-like Product Key. */
|
||||||
void packXP(
|
void BINK1998::Pack(
|
||||||
QWORD (&pRaw)[2],
|
QWORD (&pRaw)[2],
|
||||||
DWORD pSerial,
|
DWORD pSerial,
|
||||||
DWORD pHash,
|
DWORD pHash,
|
||||||
@ -41,7 +41,7 @@ void packXP(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Verifies the Windows XP-like Product Key. */
|
/* Verifies the Windows XP-like Product Key. */
|
||||||
bool verifyXPKey(
|
bool BINK1998::Verify(
|
||||||
EC_GROUP *eCurve,
|
EC_GROUP *eCurve,
|
||||||
EC_POINT *basePoint,
|
EC_POINT *basePoint,
|
||||||
EC_POINT *publicKey,
|
EC_POINT *publicKey,
|
||||||
@ -59,7 +59,7 @@ bool verifyXPKey(
|
|||||||
unbase24((BYTE *)pRaw, pKey);
|
unbase24((BYTE *)pRaw, pKey);
|
||||||
|
|
||||||
// Extract RPK, hash and signature from bytecode.
|
// Extract RPK, hash and signature from bytecode.
|
||||||
unpackXP(pRaw, pSerial, pHash, pSignature);
|
Unpack(pRaw, pSerial, pHash, pSignature);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
@ -133,7 +133,7 @@ bool verifyXPKey(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Generate a valid Product Key. */
|
/* Generate a valid Product Key. */
|
||||||
void generateXPKey(
|
void BINK1998::Generate(
|
||||||
EC_GROUP *eCurve,
|
EC_GROUP *eCurve,
|
||||||
EC_POINT *basePoint,
|
EC_POINT *basePoint,
|
||||||
BIGNUM *genOrder,
|
BIGNUM *genOrder,
|
||||||
@ -216,7 +216,7 @@ void generateXPKey(
|
|||||||
BN_bn2lebinpad(s, (BYTE *)&pSignature, BN_num_bytes(s));
|
BN_bn2lebinpad(s, (BYTE *)&pSignature, BN_num_bytes(s));
|
||||||
|
|
||||||
// Pack product key.
|
// Pack product key.
|
||||||
packXP(pRaw, pSerial, pHash, pSignature);
|
Pack(pRaw, pSerial, pHash, pSignature);
|
||||||
|
|
||||||
if (options.verbose) {
|
if (options.verbose) {
|
||||||
fmt::print("Generation results:\n");
|
fmt::print("Generation results:\n");
|
19
src/BINK1998.h
Normal file
19
src/BINK1998.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by neo on 6/6/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef WINDOWSXPKG_BINK1998_H
|
||||||
|
#define WINDOWSXPKG_BINK1998_H
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
class BINK1998 {
|
||||||
|
static void Unpack (QWORD (&pRaw)[2], DWORD &pSerial, DWORD &pHash, QWORD &pSignature);
|
||||||
|
static void Pack (QWORD (&pRaw)[2], DWORD pSerial, DWORD pHash, 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, BIGNUM *genOrder, BIGNUM *privateKey, DWORD pSerial, char (&pKey)[25]);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //WINDOWSXPKG_BINK1998_H
|
@ -2,10 +2,10 @@
|
|||||||
// Created by Andrew on 01/06/2023.
|
// Created by Andrew on 01/06/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "header.h"
|
#include "BINK2002.h"
|
||||||
|
|
||||||
/* Unpacks the Windows Server 2003-like Product Key. */
|
/* Unpacks the Windows Server 2003-like Product Key. */
|
||||||
void unpackServer(
|
void BINK2002::Unpack(
|
||||||
QWORD (&pRaw)[2],
|
QWORD (&pRaw)[2],
|
||||||
DWORD &pChannelID,
|
DWORD &pChannelID,
|
||||||
DWORD &pHash,
|
DWORD &pHash,
|
||||||
@ -31,7 +31,7 @@ void unpackServer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Packs the Windows Server 2003-like Product Key. */
|
/* Packs the Windows Server 2003-like Product Key. */
|
||||||
void packServer(
|
void BINK2002::Pack(
|
||||||
QWORD (&pRaw)[2],
|
QWORD (&pRaw)[2],
|
||||||
DWORD pChannelID,
|
DWORD pChannelID,
|
||||||
DWORD pHash,
|
DWORD pHash,
|
||||||
@ -44,7 +44,7 @@ void packServer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Verifies the Windows Server 2003-like Product Key. */
|
/* Verifies the Windows Server 2003-like Product Key. */
|
||||||
bool verifyServerKey(
|
bool BINK2002::Verify(
|
||||||
EC_GROUP *eCurve,
|
EC_GROUP *eCurve,
|
||||||
EC_POINT *basePoint,
|
EC_POINT *basePoint,
|
||||||
EC_POINT *publicKey,
|
EC_POINT *publicKey,
|
||||||
@ -63,7 +63,7 @@ bool verifyServerKey(
|
|||||||
unbase24((BYTE *)bKey, cdKey);
|
unbase24((BYTE *)bKey, cdKey);
|
||||||
|
|
||||||
// Extract product key segments from bytecode.
|
// Extract product key segments from bytecode.
|
||||||
unpackServer(bKey, pChannelID, pHash, pSignature, pAuthInfo);
|
Unpack(bKey, pChannelID, pHash, pSignature, pAuthInfo);
|
||||||
|
|
||||||
if (options.verbose) {
|
if (options.verbose) {
|
||||||
fmt::print("Validation results:\n");
|
fmt::print("Validation results:\n");
|
||||||
@ -171,7 +171,7 @@ bool verifyServerKey(
|
|||||||
return compHash == pHash;
|
return compHash == pHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
void generateServerKey(
|
void BINK2002::Generate(
|
||||||
EC_GROUP *eCurve,
|
EC_GROUP *eCurve,
|
||||||
EC_POINT *basePoint,
|
EC_POINT *basePoint,
|
||||||
BIGNUM *genOrder,
|
BIGNUM *genOrder,
|
||||||
@ -320,7 +320,7 @@ void generateServerKey(
|
|||||||
BN_bn2lebinpad(s, (BYTE *)&pSignature, BN_num_bytes(s));
|
BN_bn2lebinpad(s, (BYTE *)&pSignature, BN_num_bytes(s));
|
||||||
|
|
||||||
// Pack product key.
|
// Pack product key.
|
||||||
packServer(pRaw, pChannelID, pHash, pSignature, pAuthInfo);
|
Pack(pRaw, pChannelID, pHash, pSignature, pAuthInfo);
|
||||||
|
|
||||||
if (options.verbose) {
|
if (options.verbose) {
|
||||||
fmt::print("Generation results:\n");
|
fmt::print("Generation results:\n");
|
19
src/BINK2002.h
Normal file
19
src/BINK2002.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by neo on 6/6/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef WINDOWSXPKG_BINK2002_H
|
||||||
|
#define WINDOWSXPKG_BINK2002_H
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
class BINK2002 {
|
||||||
|
static void Unpack (QWORD (&pRaw)[2], DWORD &pChannelID, DWORD &pHash, QWORD &pSignature, DWORD &pAuthInfo);
|
||||||
|
static void Pack (QWORD (&pRaw)[2], DWORD pChannelID, DWORD pHash, QWORD &pSignature, 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, BIGNUM *genOrder, BIGNUM *privateKey, DWORD pChannelID, DWORD pAuthInfo, char (&pKey)[25]);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //WINDOWSXPKG_BINK2002_H
|
172
src/cli.cpp
172
src/cli.cpp
@ -2,9 +2,12 @@
|
|||||||
// Created by Andrew on 01/06/2023.
|
// Created by Andrew on 01/06/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "header.h"
|
#include "cli.h"
|
||||||
|
#include "confid.h"
|
||||||
|
#include "BINK1998.h"
|
||||||
|
#include "BINK2002.h"
|
||||||
|
|
||||||
bool loadJSON(const fs::path& filename, json *output) {
|
bool CLI::loadJSON(const fs::path& filename, json *output) {
|
||||||
if (!fs::exists(filename)) {
|
if (!fs::exists(filename)) {
|
||||||
fmt::print("ERROR: File {} does not exist\n", filename.string());
|
fmt::print("ERROR: File {} does not exist\n", filename.string());
|
||||||
return false;
|
return false;
|
||||||
@ -22,7 +25,7 @@ bool loadJSON(const fs::path& filename, json *output) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void showHelp(char *argv[]) {
|
void CLI::showHelp(char *argv[]) {
|
||||||
fmt::print("usage: {} \n", argv[0]);
|
fmt::print("usage: {} \n", argv[0]);
|
||||||
fmt::print("\t-h --help\tshow this message\n");
|
fmt::print("\t-h --help\tshow this message\n");
|
||||||
fmt::print("\t-v --verbose\tenable verbose output\n");
|
fmt::print("\t-v --verbose\tenable verbose output\n");
|
||||||
@ -35,20 +38,20 @@ void showHelp(char *argv[]) {
|
|||||||
fmt::print("\n\n");
|
fmt::print("\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int parseCommandLine(int argc, char* argv[], Options* options) {
|
int CLI::parseCommandLine(int argc, char* argv[], Options* options) {
|
||||||
// set default options
|
|
||||||
*options = Options {
|
*options = Options {
|
||||||
"2E",
|
"2E",
|
||||||
640,
|
|
||||||
"keys.json",
|
"keys.json",
|
||||||
1,
|
|
||||||
"",
|
"",
|
||||||
|
640,
|
||||||
|
1,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false
|
MODE_BINK1998
|
||||||
};
|
};
|
||||||
|
// set default options
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
std::string arg = argv[i];
|
std::string arg = argv[i];
|
||||||
@ -117,7 +120,7 @@ int parseCommandLine(int argc, char* argv[], Options* options) {
|
|||||||
return !options->error;
|
return !options->error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int validateCommandLine(Options* options, char *argv[], json *keys) {
|
int CLI::validateCommandLine(Options* options, char *argv[], json *keys) {
|
||||||
if (options->verbose) {
|
if (options->verbose) {
|
||||||
fmt::print("Loading keys file {}\n", options->keysFilename);
|
fmt::print("Loading keys file {}\n", options->keysFilename);
|
||||||
}
|
}
|
||||||
@ -155,18 +158,18 @@ int 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->isBink2002 = true;
|
options->applicationMode = MODE_BINK2002;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options->channelID > 999) {
|
if (options->channelID > 999) {
|
||||||
fmt::print("ERROR: refusing to create a key with a siteID greater than 999\n");
|
fmt::print("ERROR: refusing to create a key with a Channel ID greater than 999\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_product_id(DWORD *pid)
|
void CLI::print_product_id(DWORD *pid)
|
||||||
{
|
{
|
||||||
char raw[12];
|
char raw[12];
|
||||||
char b[6], c[8];
|
char b[6], c[8];
|
||||||
@ -196,7 +199,7 @@ void print_product_id(DWORD *pid)
|
|||||||
fmt::print("Product ID: PPPPP-{}-{}-23xxx\n", b, c);
|
fmt::print("Product ID: PPPPP-{}-{}-23xxx\n", b, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_product_key(char *pk) {
|
void CLI::print_product_key(char *pk) {
|
||||||
assert(strlen(pk) == 25);
|
assert(strlen(pk) == 25);
|
||||||
|
|
||||||
std::string spk = pk;
|
std::string spk = pk;
|
||||||
@ -207,3 +210,146 @@ void print_product_key(char *pk) {
|
|||||||
spk.substr(15,5),
|
spk.substr(15,5),
|
||||||
spk.substr(20,5));
|
spk.substr(20,5));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLI::CLI(Options options, json keys) {
|
||||||
|
BINKID = options.binkid.c_str();
|
||||||
|
|
||||||
|
// We cannot produce a valid key without knowing the private key k. The reason for this is that
|
||||||
|
// we need the result of the function K(x; y) = kG(x; y).
|
||||||
|
privateKey = BN_new();
|
||||||
|
|
||||||
|
// We can, however, validate any given key using the available public key: {p, a, b, G, K}.
|
||||||
|
// genOrder the order of the generator G, a value we have to reverse -> Schoof's Algorithm.
|
||||||
|
genOrder = BN_new();
|
||||||
|
|
||||||
|
/* Computed data */
|
||||||
|
BN_dec2bn(&genOrder, keys["BINK"][BINKID]["n"].get<std::string>().c_str());
|
||||||
|
BN_dec2bn(&privateKey, keys["BINK"][BINKID]["priv"].get<std::string>().c_str());
|
||||||
|
|
||||||
|
if (options.verbose) {
|
||||||
|
fmt::print("----------------------------------------------------------- \n");
|
||||||
|
fmt::print("Loaded the following curve constraints: BINK[{}]\n", BINKID);
|
||||||
|
fmt::print("----------------------------------------------------------- \n");
|
||||||
|
fmt::print(" P: {}\n", keys["BINK"][BINKID]["p"].get<std::string>());
|
||||||
|
fmt::print(" a: {}\n", keys["BINK"][BINKID]["a"].get<std::string>());
|
||||||
|
fmt::print(" b: {}\n", keys["BINK"][BINKID]["b"].get<std::string>());
|
||||||
|
fmt::print("Gx: {}\n", keys["BINK"][BINKID]["g"]["x"].get<std::string>());
|
||||||
|
fmt::print("Gy: {}\n", keys["BINK"][BINKID]["g"]["y"].get<std::string>());
|
||||||
|
fmt::print("Kx: {}\n", keys["BINK"][BINKID]["pub"]["x"].get<std::string>());
|
||||||
|
fmt::print("Ky: {}\n", keys["BINK"][BINKID]["pub"]["y"].get<std::string>());
|
||||||
|
fmt::print(" n: {}\n", keys["BINK"][BINKID]["n"].get<std::string>());
|
||||||
|
fmt::print(" k: {}\n", keys["BINK"][BINKID]["priv"].get<std::string>());
|
||||||
|
fmt::print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
eCurve = initializeEllipticCurve(
|
||||||
|
keys["BINK"][BINKID]["p"].get<std::string>(),
|
||||||
|
keys["BINK"][BINKID]["a"].get<std::string>(),
|
||||||
|
keys["BINK"][BINKID]["b"].get<std::string>(),
|
||||||
|
keys["BINK"][BINKID]["g"]["x"].get<std::string>(),
|
||||||
|
keys["BINK"][BINKID]["g"]["y"].get<std::string>(),
|
||||||
|
keys["BINK"][BINKID]["pub"]["x"].get<std::string>(),
|
||||||
|
keys["BINK"][BINKID]["pub"]["y"].get<std::string>(),
|
||||||
|
genPoint,
|
||||||
|
pubPoint
|
||||||
|
);
|
||||||
|
|
||||||
|
total = options.numKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CLI::BINK1998() {
|
||||||
|
DWORD nRaw = options.channelID * 1000000 ; /* <- change */
|
||||||
|
|
||||||
|
BIGNUM *bnrand = BN_new();
|
||||||
|
BN_rand(bnrand, 19, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY);
|
||||||
|
|
||||||
|
int oRaw;
|
||||||
|
char *cRaw = BN_bn2dec(bnrand);
|
||||||
|
|
||||||
|
sscanf(cRaw, "%d", &oRaw);
|
||||||
|
nRaw += (oRaw &= 0xF423F); // ensure our serial is less than 999999
|
||||||
|
|
||||||
|
if (options.verbose) {
|
||||||
|
fmt::print("> PID: {:09d}\n", nRaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate a key
|
||||||
|
BN_sub(privateKey, genOrder, privateKey);
|
||||||
|
nRaw <<= 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < total; i++) {
|
||||||
|
BINK1998::Generate(eCurve, genPoint, genOrder, privateKey, nRaw, pKey);
|
||||||
|
CLI::print_product_key(pKey);
|
||||||
|
fmt::print("\n\n");
|
||||||
|
|
||||||
|
// verify the key
|
||||||
|
count += BINK1998::Verify(eCurve, genPoint, pubPoint, pKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt::print("Success count: {}/{}\n", count, total);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CLI::BINK2002() {
|
||||||
|
DWORD pChannelID = options.channelID << 1;
|
||||||
|
|
||||||
|
if (options.verbose) {
|
||||||
|
fmt::print("> Channel ID: {:03d}\n", options.channelID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate a key
|
||||||
|
for (int i = 0; i < total; i++) {
|
||||||
|
DWORD pAuthInfo;
|
||||||
|
RAND_bytes((BYTE *)&pAuthInfo, 4);
|
||||||
|
pAuthInfo &= 0x3ff;
|
||||||
|
|
||||||
|
if (options.verbose) {
|
||||||
|
fmt::print("> AuthInfo: {}\n", pAuthInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
BINK2002::Generate(eCurve, genPoint, genOrder, privateKey, pChannelID, pAuthInfo, pKey);
|
||||||
|
CLI::print_product_key(pKey);
|
||||||
|
fmt::print("\n\n");
|
||||||
|
|
||||||
|
// verify a key
|
||||||
|
count += BINK2002::Verify(eCurve, genPoint, pubPoint, pKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt::print("Success count: {}/{}\n", count, total);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CLI::ConfirmationID() {
|
||||||
|
char confirmation_id[49];
|
||||||
|
int err = ConfirmationID::Generate(options.instid.c_str(), confirmation_id);
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
|
case ERR_TOO_SHORT:
|
||||||
|
fmt::print("ERROR: Installation ID is too short.\n");
|
||||||
|
return 1;
|
||||||
|
case ERR_TOO_LARGE:
|
||||||
|
fmt::print("ERROR: Installation ID is too long.\n");
|
||||||
|
return 1;
|
||||||
|
case ERR_INVALID_CHARACTER:
|
||||||
|
fmt::print("ERROR: Invalid character in installation ID.\n");
|
||||||
|
return 1;
|
||||||
|
case ERR_INVALID_CHECK_DIGIT:
|
||||||
|
fmt::print("ERROR: Installation ID checksum failed. Please check that it is typed correctly.\n");
|
||||||
|
return 1;
|
||||||
|
case ERR_UNKNOWN_VERSION:
|
||||||
|
fmt::print("ERROR: Unknown installation ID version.\n");
|
||||||
|
return 1;
|
||||||
|
case ERR_UNLUCKY:
|
||||||
|
fmt::print("ERROR: Unable to generate valid confirmation ID.\n");
|
||||||
|
return 1;
|
||||||
|
case SUCCESS:
|
||||||
|
fmt::print("Confirmation ID: {}\n", confirmation_id);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fmt::print("Unknown error occurred during Confirmation ID generation: {}\n", err);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
35
src/cli.h
Normal file
35
src/cli.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
//
|
||||||
|
// Created by neo on 6/6/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef WINDOWSXPKG_CLI_H
|
||||||
|
#define WINDOWSXPKG_CLI_H
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
class CLI {
|
||||||
|
Options options;
|
||||||
|
json keys;
|
||||||
|
const char* BINKID;
|
||||||
|
BIGNUM *privateKey, *genOrder;
|
||||||
|
EC_POINT *genPoint, *pubPoint;
|
||||||
|
EC_GROUP *eCurve;
|
||||||
|
char pKey[25];
|
||||||
|
int count, total;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CLI(Options options, json keys);
|
||||||
|
|
||||||
|
static bool loadJSON(const fs::path& filename, json *output);
|
||||||
|
static void showHelp(char *argv[]);
|
||||||
|
static int parseCommandLine(int argc, char* argv[], Options *options);
|
||||||
|
static int validateCommandLine(Options* options, char *argv[], json *keys);
|
||||||
|
static void print_product_id(DWORD *pid);
|
||||||
|
static void print_product_key(char *pk);
|
||||||
|
|
||||||
|
int BINK1998();
|
||||||
|
int BINK2002();
|
||||||
|
int ConfirmationID();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //WINDOWSXPKG_CLI_H
|
284
src/confid.cpp
284
src/confid.cpp
@ -2,32 +2,24 @@
|
|||||||
// Created by WitherOrNot on 06/02/2023.
|
// Created by WitherOrNot on 06/02/2023.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "header.h"
|
#include "confid.h"
|
||||||
|
|
||||||
typedef int64_t i64;
|
|
||||||
typedef uint64_t ui64;
|
|
||||||
|
|
||||||
#define MOD 0x16A6B036D7F2A79ULL
|
#define MOD 0x16A6B036D7F2A79ULL
|
||||||
#define NON_RESIDUE 43
|
#define NON_RESIDUE 43
|
||||||
static const ui64 f[6] = {0, 0x21840136C85381ULL, 0x44197B83892AD0ULL, 0x1400606322B3B04ULL, 0x1400606322B3B04ULL, 1};
|
static const QWORD f[6] = {0, 0x21840136C85381ULL, 0x44197B83892AD0ULL, 0x1400606322B3B04ULL, 0x1400606322B3B04ULL, 1};
|
||||||
|
|
||||||
typedef struct {
|
QWORD ConfirmationID::residue_add(QWORD x, QWORD y)
|
||||||
ui64 u[2];
|
|
||||||
ui64 v[2];
|
|
||||||
} TDivisor;
|
|
||||||
|
|
||||||
static ui64 residue_add(ui64 x, ui64 y)
|
|
||||||
{
|
{
|
||||||
ui64 z = x + y;
|
QWORD z = x + y;
|
||||||
//z = z - (z >= MOD ? MOD : 0);
|
//z = z - (z >= MOD ? MOD : 0);
|
||||||
if (z >= MOD)
|
if (z >= MOD)
|
||||||
z -= MOD;
|
z -= MOD;
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ui64 residue_sub(ui64 x, ui64 y)
|
QWORD ConfirmationID::residue_sub(QWORD x, QWORD y)
|
||||||
{
|
{
|
||||||
ui64 z = x - y;
|
QWORD z = x - y;
|
||||||
//z += (x < y ? MOD : 0);
|
//z += (x < y ? MOD : 0);
|
||||||
if (x < y)
|
if (x < y)
|
||||||
z += MOD;
|
z += MOD;
|
||||||
@ -36,82 +28,82 @@ static ui64 residue_sub(ui64 x, ui64 y)
|
|||||||
|
|
||||||
#if defined(__x86_64__) || defined(_M_AMD64) || defined(__aarch64__) || (defined(__arm64__) && defined(__APPLE__))
|
#if defined(__x86_64__) || defined(_M_AMD64) || defined(__aarch64__) || (defined(__arm64__) && defined(__APPLE__))
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
static inline uint64_t __umul128(uint64_t a, uint64_t b, uint64_t* hi)
|
inline QWORD ConfirmationID::__umul128(QWORD a, QWORD b, QWORD* hi)
|
||||||
{
|
{
|
||||||
unsigned __int128 r = (unsigned __int128) a * (unsigned __int128) b;
|
DQWORD r = (DQWORD)a * (DQWORD)b;
|
||||||
*hi = r >> 64;
|
*hi = r >> 64;
|
||||||
return (uint64_t) r;
|
return (QWORD) r;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define __umul128 _umul128
|
#define __umul128 _umul128
|
||||||
#endif
|
#endif
|
||||||
#elif defined(__i386__) || defined(_M_IX86) || defined(__arm__)
|
#elif defined(__i386__) || defined(_M_IX86) || defined(__arm__)
|
||||||
static inline uint64_t __umul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi) {
|
inline QWORD ConfirmationID::__umul128(QWORD multiplier, QWORD multiplicand, QWORD *product_hi) {
|
||||||
// multiplier = ab = a * 2^32 + b
|
// multiplier = ab = a * 2^32 + b
|
||||||
// multiplicand = cd = c * 2^32 + d
|
// multiplicand = cd = c * 2^32 + d
|
||||||
// ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
|
// ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
|
||||||
uint64_t a = multiplier >> 32;
|
QWORD a = multiplier >> 32;
|
||||||
uint64_t b = multiplier & 0xFFFFFFFF;
|
QWORD b = multiplier & 0xFFFFFFFF;
|
||||||
uint64_t c = multiplicand >> 32;
|
QWORD c = multiplicand >> 32;
|
||||||
uint64_t d = multiplicand & 0xFFFFFFFF;
|
QWORD d = multiplicand & 0xFFFFFFFF;
|
||||||
|
|
||||||
//uint64_t ac = a * c;
|
//QWORD ac = a * c;
|
||||||
uint64_t ad = a * d;
|
QWORD ad = a * d;
|
||||||
//uint64_t bc = b * c;
|
//QWORD bc = b * c;
|
||||||
uint64_t bd = b * d;
|
QWORD bd = b * d;
|
||||||
|
|
||||||
uint64_t adbc = ad + (b * c);
|
QWORD adbc = ad + (b * c);
|
||||||
uint64_t adbc_carry = adbc < ad ? 1 : 0;
|
QWORD adbc_carry = adbc < ad ? 1 : 0;
|
||||||
|
|
||||||
// multiplier * multiplicand = product_hi * 2^64 + product_lo
|
// multiplier * multiplicand = product_hi * 2^64 + product_lo
|
||||||
uint64_t product_lo = bd + (adbc << 32);
|
QWORD product_lo = bd + (adbc << 32);
|
||||||
uint64_t product_lo_carry = product_lo < bd ? 1 : 0;
|
QWORD product_lo_carry = product_lo < bd ? 1 : 0;
|
||||||
*product_hi = (a * c) + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
|
*product_hi = (a * c) + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
|
||||||
|
|
||||||
return product_lo;
|
return product_lo;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static ui64 ui128_quotient_mod(ui64 lo, ui64 hi)
|
QWORD ConfirmationID::ui128_quotient_mod(QWORD lo, QWORD hi)
|
||||||
{
|
{
|
||||||
// hi:lo * ceil(2**170/MOD) >> (64 + 64 + 42)
|
// hi:lo * ceil(2**170/MOD) >> (64 + 64 + 42)
|
||||||
ui64 prod1;
|
QWORD prod1;
|
||||||
__umul128(lo, 0x604fa6a1c6346a87, &prod1);
|
__umul128(lo, 0x604fa6a1c6346a87, &prod1);
|
||||||
ui64 part1hi;
|
QWORD part1hi;
|
||||||
ui64 part1lo = __umul128(lo, 0x2d351c6d04f8b, &part1hi);
|
QWORD part1lo = __umul128(lo, 0x2d351c6d04f8b, &part1hi);
|
||||||
ui64 part2hi;
|
QWORD part2hi;
|
||||||
ui64 part2lo = __umul128(hi, 0x604fa6a1c6346a87, &part2hi);
|
QWORD part2lo = __umul128(hi, 0x604fa6a1c6346a87, &part2hi);
|
||||||
ui64 sum1 = part1lo + part2lo;
|
QWORD sum1 = part1lo + part2lo;
|
||||||
unsigned sum1carry = (sum1 < part1lo);
|
unsigned sum1carry = (sum1 < part1lo);
|
||||||
sum1 += prod1;
|
sum1 += prod1;
|
||||||
sum1carry += (sum1 < prod1);
|
sum1carry += (sum1 < prod1);
|
||||||
ui64 prod2 = part1hi + part2hi + sum1carry;
|
QWORD prod2 = part1hi + part2hi + sum1carry;
|
||||||
ui64 prod3hi;
|
QWORD prod3hi;
|
||||||
ui64 prod3lo = __umul128(hi, 0x2d351c6d04f8b, &prod3hi);
|
QWORD prod3lo = __umul128(hi, 0x2d351c6d04f8b, &prod3hi);
|
||||||
prod3lo += prod2;
|
prod3lo += prod2;
|
||||||
prod3hi += (prod3lo < prod2);
|
prod3hi += (prod3lo < prod2);
|
||||||
return (prod3lo >> 42) | (prod3hi << 22);
|
return (prod3lo >> 42) | (prod3hi << 22);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ui64 residue_mul(ui64 x, ui64 y)
|
QWORD ConfirmationID::residue_mul(QWORD x, QWORD y)
|
||||||
{
|
{
|
||||||
// * ceil(2**170/MOD) = 0x2d351 c6d04f8b|604fa6a1 c6346a87 for (p-1)*(p-1) max
|
// * ceil(2**170/MOD) = 0x2d351 c6d04f8b|604fa6a1 c6346a87 for (p-1)*(p-1) max
|
||||||
ui64 hi;
|
QWORD hi;
|
||||||
ui64 lo = __umul128(x, y, &hi);
|
QWORD lo = __umul128(x, y, &hi);
|
||||||
ui64 quotient = ui128_quotient_mod(lo, hi);
|
QWORD quotient = ui128_quotient_mod(lo, hi);
|
||||||
return lo - quotient * MOD;
|
return lo - quotient * MOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ui64 residue_pow(ui64 x, ui64 y)
|
QWORD ConfirmationID::residue_pow(QWORD x, QWORD y)
|
||||||
{
|
{
|
||||||
if (y == 0)
|
if (y == 0)
|
||||||
return 1;
|
return 1;
|
||||||
ui64 cur = x;
|
QWORD cur = x;
|
||||||
while (!(y & 1)) {
|
while (!(y & 1)) {
|
||||||
cur = residue_mul(cur, cur);
|
cur = residue_mul(cur, cur);
|
||||||
y >>= 1;
|
y >>= 1;
|
||||||
}
|
}
|
||||||
ui64 res = cur;
|
QWORD res = cur;
|
||||||
while ((y >>= 1) != 0) {
|
while ((y >>= 1) != 0) {
|
||||||
cur = residue_mul(cur, cur);
|
cur = residue_mul(cur, cur);
|
||||||
if (y & 1)
|
if (y & 1)
|
||||||
@ -120,14 +112,14 @@ static ui64 residue_pow(ui64 x, ui64 y)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ui64 inverse(ui64 u, ui64 v)
|
QWORD ConfirmationID::inverse(QWORD u, QWORD v)
|
||||||
{
|
{
|
||||||
//assert(u);
|
//assert(u);
|
||||||
i64 tmp;
|
int64_t tmp;
|
||||||
i64 xu = 1, xv = 0;
|
int64_t xu = 1, xv = 0;
|
||||||
ui64 v0 = v;
|
QWORD v0 = v;
|
||||||
while (u > 1) {
|
while (u > 1) {
|
||||||
ui64 d = v / u; ui64 remainder = v % u;
|
QWORD d = v / u; QWORD remainder = v % u;
|
||||||
tmp = u; u = remainder; v = tmp;
|
tmp = u; u = remainder; v = tmp;
|
||||||
tmp = xu; xu = xv - d * xu; xv = tmp;
|
tmp = xu; xu = xv - d * xu; xv = tmp;
|
||||||
}
|
}
|
||||||
@ -135,20 +127,27 @@ static ui64 inverse(ui64 u, ui64 v)
|
|||||||
return xu;
|
return xu;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ui64 residue_inv(ui64 x)
|
QWORD ConfirmationID::residue_inv(QWORD x)
|
||||||
{ return inverse(x, MOD); }
|
{
|
||||||
//{ return residue_pow(x, MOD - 2); }
|
return inverse(x, MOD);
|
||||||
|
// return residue_pow(x, MOD - 2);
|
||||||
|
}
|
||||||
|
|
||||||
#define BAD 0xFFFFFFFFFFFFFFFFull
|
#define BAD 0xFFFFFFFFFFFFFFFFull
|
||||||
|
|
||||||
static ui64 residue_sqrt(ui64 what)
|
QWORD ConfirmationID::residue_sqrt(QWORD what)
|
||||||
{
|
{
|
||||||
if (!what)
|
if (!what) {
|
||||||
return 0;
|
return 0;
|
||||||
ui64 g = NON_RESIDUE, z, y, r, x, b, t;
|
}
|
||||||
ui64 e = 0, q = MOD - 1;
|
|
||||||
while (!(q & 1))
|
QWORD g = NON_RESIDUE, z, y, r, x, b, t;
|
||||||
|
QWORD e = 0, q = MOD - 1;
|
||||||
|
|
||||||
|
while (!(q & 1)) {
|
||||||
e++, q >>= 1;
|
e++, q >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
z = residue_pow(g, q);
|
z = residue_pow(g, q);
|
||||||
y = z;
|
y = z;
|
||||||
r = e;
|
r = e;
|
||||||
@ -156,39 +155,46 @@ static ui64 residue_sqrt(ui64 what)
|
|||||||
b = residue_mul(residue_mul(what, x), x);
|
b = residue_mul(residue_mul(what, x), x);
|
||||||
x = residue_mul(what, x);
|
x = residue_mul(what, x);
|
||||||
while (b != 1) {
|
while (b != 1) {
|
||||||
ui64 m = 0, b2 = b;
|
QWORD m = 0, b2 = b;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
m++;
|
m++;
|
||||||
b2 = residue_mul(b2, b2);
|
b2 = residue_mul(b2, b2);
|
||||||
} while (b2 != 1);
|
} while (b2 != 1);
|
||||||
if (m == r)
|
|
||||||
|
if (m == r) {
|
||||||
return BAD;
|
return BAD;
|
||||||
|
}
|
||||||
|
|
||||||
t = residue_pow(y, 1 << (r - m - 1));
|
t = residue_pow(y, 1 << (r - m - 1));
|
||||||
y = residue_mul(t, t);
|
y = residue_mul(t, t);
|
||||||
r = m;
|
r = m;
|
||||||
x = residue_mul(x, t);
|
x = residue_mul(x, t);
|
||||||
b = residue_mul(b, y);
|
b = residue_mul(b, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (residue_mul(x, x) != what) {
|
if (residue_mul(x, x) != what) {
|
||||||
//printf("internal error in sqrt\n");
|
//printf("internal error in sqrt\n");
|
||||||
return BAD;
|
return BAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
int find_divisor_v(TDivisor* d)
|
int ConfirmationID::find_divisor_v(TDivisor* d)
|
||||||
{
|
{
|
||||||
// u | v^2 - f
|
// u | v^2 - f
|
||||||
// u = u0 + u1*x + x^2
|
// u = u0 + u1*x + x^2
|
||||||
// f%u = f0 + f1*x
|
// f%u = f0 + f1*x
|
||||||
ui64 v1;
|
QWORD v1, f2[6];
|
||||||
ui64 f2[6];
|
|
||||||
int i, j;
|
for (int i = 0; i < 6; i++) {
|
||||||
for (i = 0; i < 6; i++)
|
|
||||||
f2[i] = f[i];
|
f2[i] = f[i];
|
||||||
const ui64 u0 = d->u[0];
|
}
|
||||||
const ui64 u1 = d->u[1];
|
|
||||||
for (j = 4; j--; ) {
|
const QWORD u0 = d->u[0];
|
||||||
|
const QWORD u1 = d->u[1];
|
||||||
|
for (int j = 4; j--; ) {
|
||||||
f2[j] = residue_sub(f2[j], residue_mul(u0, f2[j + 2]));
|
f2[j] = residue_sub(f2[j], residue_mul(u0, f2[j + 2]));
|
||||||
f2[j + 1] = residue_sub(f2[j + 1], residue_mul(u1, f2[j + 2]));
|
f2[j + 1] = residue_sub(f2[j + 1], residue_mul(u1, f2[j + 2]));
|
||||||
f2[j + 2] = 0;
|
f2[j + 2] = 0;
|
||||||
@ -200,11 +206,11 @@ int find_divisor_v(TDivisor* d)
|
|||||||
// v0^2 = f0 + u0*v1^2 = (f1 + u1*v1^2)^2 / (2*v1)^2
|
// v0^2 = f0 + u0*v1^2 = (f1 + u1*v1^2)^2 / (2*v1)^2
|
||||||
// (f1^2) + 2*(f1*u1-2*f0) * v1^2 + (u1^2-4*u0) * v1^4 = 0
|
// (f1^2) + 2*(f1*u1-2*f0) * v1^2 + (u1^2-4*u0) * v1^4 = 0
|
||||||
// v1^2 = ((2*f0-f1*u1) +- 2*sqrt(-f0*f1*u1 + f0^2 + f1^2*u0))) / (u1^2-4*u0)
|
// v1^2 = ((2*f0-f1*u1) +- 2*sqrt(-f0*f1*u1 + f0^2 + f1^2*u0))) / (u1^2-4*u0)
|
||||||
const ui64 f0 = f2[0];
|
const QWORD f0 = f2[0];
|
||||||
const ui64 f1 = f2[1];
|
const QWORD f1 = f2[1];
|
||||||
const ui64 u0double = residue_add(u0, u0);
|
const QWORD u0double = residue_add(u0, u0);
|
||||||
const ui64 coeff2 = residue_sub(residue_mul(u1, u1), residue_add(u0double, u0double));
|
const QWORD coeff2 = residue_sub(residue_mul(u1, u1), residue_add(u0double, u0double));
|
||||||
const ui64 coeff1 = residue_sub(residue_add(f0, f0), residue_mul(f1, u1));
|
const QWORD coeff1 = residue_sub(residue_add(f0, f0), residue_mul(f1, u1));
|
||||||
if (coeff2 == 0) {
|
if (coeff2 == 0) {
|
||||||
if (coeff1 == 0) {
|
if (coeff1 == 0) {
|
||||||
if (f1 == 0) {
|
if (f1 == 0) {
|
||||||
@ -213,34 +219,39 @@ int find_divisor_v(TDivisor* d)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ui64 sqr = residue_mul(residue_mul(f1, f1), residue_inv(residue_add(coeff1, coeff1)));
|
QWORD sqr = residue_mul(residue_mul(f1, f1), residue_inv(residue_add(coeff1, coeff1)));
|
||||||
v1 = residue_sqrt(sqr);
|
v1 = residue_sqrt(sqr);
|
||||||
if (v1 == BAD)
|
if (v1 == BAD) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ui64 d = residue_add(residue_mul(f0, f0), residue_mul(f1, residue_sub(residue_mul(f1, u0), residue_mul(f0, u1))));
|
QWORD d = residue_add(residue_mul(f0, f0), residue_mul(f1, residue_sub(residue_mul(f1, u0), residue_mul(f0, u1))));
|
||||||
d = residue_sqrt(d);
|
d = residue_sqrt(d);
|
||||||
if (d == BAD)
|
if (d == BAD) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
d = residue_add(d, d);
|
d = residue_add(d, d);
|
||||||
ui64 inv = residue_inv(coeff2);
|
QWORD inv = residue_inv(coeff2);
|
||||||
ui64 root = residue_mul(residue_add(coeff1, d), inv);
|
QWORD root = residue_mul(residue_add(coeff1, d), inv);
|
||||||
v1 = residue_sqrt(root);
|
v1 = residue_sqrt(root);
|
||||||
if (v1 == BAD) {
|
if (v1 == BAD) {
|
||||||
root = residue_mul(residue_sub(coeff1, d), inv);
|
root = residue_mul(residue_sub(coeff1, d), inv);
|
||||||
v1 = residue_sqrt(root);
|
v1 = residue_sqrt(root);
|
||||||
if (v1 == BAD)
|
if (v1 == BAD) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ui64 v0 = residue_mul(residue_add(f1, residue_mul(u1, residue_mul(v1, v1))), residue_inv(residue_add(v1, v1)));
|
}
|
||||||
|
|
||||||
|
QWORD v0 = residue_mul(residue_add(f1, residue_mul(u1, residue_mul(v1, v1))), residue_inv(residue_add(v1, v1)));
|
||||||
d->v[0] = v0;
|
d->v[0] = v0;
|
||||||
d->v[1] = v1;
|
d->v[1] = v1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// generic short slow code
|
// generic short slow code
|
||||||
static int polynomial_mul(int adeg, const ui64 a[], int bdeg, const ui64 b[], int resultprevdeg, ui64 result[])
|
int ConfirmationID::polynomial_mul(int adeg, const QWORD a[], int bdeg, const QWORD b[], int resultprevdeg, QWORD result[])
|
||||||
{
|
{
|
||||||
if (adeg < 0 || bdeg < 0)
|
if (adeg < 0 || bdeg < 0)
|
||||||
return resultprevdeg;
|
return resultprevdeg;
|
||||||
@ -255,13 +266,14 @@ static int polynomial_mul(int adeg, const ui64 a[], int bdeg, const ui64 b[], in
|
|||||||
--resultprevdeg;
|
--resultprevdeg;
|
||||||
return resultprevdeg;
|
return resultprevdeg;
|
||||||
}
|
}
|
||||||
static int polynomial_div_monic(int adeg, ui64 a[], int bdeg, const ui64 b[], ui64* quotient)
|
|
||||||
|
int ConfirmationID::polynomial_div_monic(int adeg, QWORD a[], int bdeg, const QWORD b[], QWORD* quotient)
|
||||||
{
|
{
|
||||||
assert(bdeg >= 0);
|
assert(bdeg >= 0);
|
||||||
assert(b[bdeg] == 1);
|
assert(b[bdeg] == 1);
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = adeg - bdeg; i >= 0; i--) {
|
for (i = adeg - bdeg; i >= 0; i--) {
|
||||||
ui64 q = a[i + bdeg];
|
QWORD q = a[i + bdeg];
|
||||||
if (quotient)
|
if (quotient)
|
||||||
quotient[i] = q;
|
quotient[i] = q;
|
||||||
for (j = 0; j < bdeg; j++)
|
for (j = 0; j < bdeg; j++)
|
||||||
@ -273,18 +285,18 @@ static int polynomial_div_monic(int adeg, ui64 a[], int bdeg, const ui64 b[], ui
|
|||||||
i--;
|
i--;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
static void polynomial_xgcd(int adeg, const ui64 a[3], int bdeg, const ui64 b[3], int* pgcddeg, ui64 gcd[3], int* pmult1deg, ui64 mult1[3], int* pmult2deg, ui64 mult2[3])
|
void ConfirmationID::polynomial_xgcd(int adeg, const QWORD a[3], int bdeg, const QWORD b[3], int* pgcddeg, QWORD gcd[3], int* pmult1deg, QWORD mult1[3], int* pmult2deg, QWORD mult2[3])
|
||||||
{
|
{
|
||||||
int sdeg = -1;
|
int sdeg = -1;
|
||||||
ui64 s[3] = {0, 0, 0};
|
QWORD s[3] = {0, 0, 0};
|
||||||
int mult1deg = 0;
|
int mult1deg = 0;
|
||||||
mult1[0] = 1; mult1[1] = 0; mult1[2] = 0;
|
mult1[0] = 1; mult1[1] = 0; mult1[2] = 0;
|
||||||
int tdeg = 0;
|
int tdeg = 0;
|
||||||
ui64 t[3] = {1, 0, 0};
|
QWORD t[3] = {1, 0, 0};
|
||||||
int mult2deg = -1;
|
int mult2deg = -1;
|
||||||
mult2[0] = 0; mult2[1] = 0; mult2[2] = 0;
|
mult2[0] = 0; mult2[1] = 0; mult2[2] = 0;
|
||||||
int rdeg = bdeg;
|
int rdeg = bdeg;
|
||||||
ui64 r[3] = {b[0], b[1], b[2]};
|
QWORD r[3] = {b[0], b[1], b[2]};
|
||||||
int gcddeg = adeg;
|
int gcddeg = adeg;
|
||||||
gcd[0] = a[0]; gcd[1] = a[1]; gcd[2] = a[2];
|
gcd[0] = a[0]; gcd[1] = a[1]; gcd[2] = a[2];
|
||||||
// s*u1 + t*u2 = r
|
// s*u1 + t*u2 = r
|
||||||
@ -296,7 +308,7 @@ static void polynomial_xgcd(int adeg, const ui64 a[3], int bdeg, const ui64 b[3]
|
|||||||
tmp = rdeg; rdeg = gcddeg; gcddeg = tmp;
|
tmp = rdeg; rdeg = gcddeg; gcddeg = tmp;
|
||||||
tmpi = sdeg; sdeg = mult1deg; mult1deg = tmpi;
|
tmpi = sdeg; sdeg = mult1deg; mult1deg = tmpi;
|
||||||
tmpi = tdeg; tdeg = mult2deg; mult2deg = tmpi;
|
tmpi = tdeg; tdeg = mult2deg; mult2deg = tmpi;
|
||||||
ui64 tmp2;
|
QWORD tmp2;
|
||||||
tmp2 = r[0]; r[0] = gcd[0]; gcd[0] = tmp2;
|
tmp2 = r[0]; r[0] = gcd[0]; gcd[0] = tmp2;
|
||||||
tmp2 = r[1]; r[1] = gcd[1]; gcd[1] = tmp2;
|
tmp2 = r[1]; r[1] = gcd[1]; gcd[1] = tmp2;
|
||||||
tmp2 = r[2]; r[2] = gcd[2]; gcd[2] = tmp2;
|
tmp2 = r[2]; r[2] = gcd[2]; gcd[2] = tmp2;
|
||||||
@ -309,7 +321,7 @@ static void polynomial_xgcd(int adeg, const ui64 a[3], int bdeg, const ui64 b[3]
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int delta = gcddeg - rdeg;
|
int delta = gcddeg - rdeg;
|
||||||
ui64 mult = residue_mul(gcd[gcddeg], residue_inv(r[rdeg]));
|
QWORD mult = residue_mul(gcd[gcddeg], residue_inv(r[rdeg]));
|
||||||
// quotient = mult * x**delta
|
// quotient = mult * x**delta
|
||||||
assert(rdeg + delta < 3);
|
assert(rdeg + delta < 3);
|
||||||
for (int i = 0; i <= rdeg; i++)
|
for (int i = 0; i <= rdeg; i++)
|
||||||
@ -336,7 +348,8 @@ static void polynomial_xgcd(int adeg, const ui64 a[3], int bdeg, const ui64 b[3]
|
|||||||
*pmult1deg = mult1deg;
|
*pmult1deg = mult1deg;
|
||||||
*pmult2deg = mult2deg;
|
*pmult2deg = mult2deg;
|
||||||
}
|
}
|
||||||
static int u2poly(const TDivisor* src, ui64 polyu[3], ui64 polyv[2])
|
|
||||||
|
int ConfirmationID::u2poly(const TDivisor* src, QWORD polyu[3], QWORD polyv[2])
|
||||||
{
|
{
|
||||||
if (src->u[1] != BAD) {
|
if (src->u[1] != BAD) {
|
||||||
polyu[0] = src->u[0];
|
polyu[0] = src->u[0];
|
||||||
@ -358,27 +371,28 @@ static int u2poly(const TDivisor* src, ui64 polyu[3], ui64 polyv[2])
|
|||||||
polyv[1] = 0;
|
polyv[1] = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static void divisor_add(const TDivisor* src1, const TDivisor* src2, TDivisor* dst)
|
|
||||||
|
void ConfirmationID::divisor_add(const TDivisor* src1, const TDivisor* src2, TDivisor* dst)
|
||||||
{
|
{
|
||||||
ui64 u1[3], u2[3], v1[2], v2[2];
|
QWORD u1[3], u2[3], v1[2], v2[2];
|
||||||
int u1deg = u2poly(src1, u1, v1);
|
int u1deg = u2poly(src1, u1, v1);
|
||||||
int u2deg = u2poly(src2, u2, v2);
|
int u2deg = u2poly(src2, u2, v2);
|
||||||
// extended gcd: d1 = gcd(u1, u2) = e1*u1 + e2*u2
|
// extended gcd: d1 = gcd(u1, u2) = e1*u1 + e2*u2
|
||||||
int d1deg, e1deg, e2deg;
|
int d1deg, e1deg, e2deg;
|
||||||
ui64 d1[3], e1[3], e2[3];
|
QWORD d1[3], e1[3], e2[3];
|
||||||
polynomial_xgcd(u1deg, u1, u2deg, u2, &d1deg, d1, &e1deg, e1, &e2deg, e2);
|
polynomial_xgcd(u1deg, u1, u2deg, u2, &d1deg, d1, &e1deg, e1, &e2deg, e2);
|
||||||
assert(e1deg <= 1);
|
assert(e1deg <= 1);
|
||||||
assert(e2deg <= 1);
|
assert(e2deg <= 1);
|
||||||
// extended gcd again: d = gcd(d1, v1+v2) = c1*d1 + c2*(v1+v2)
|
// extended gcd again: d = gcd(d1, v1+v2) = c1*d1 + c2*(v1+v2)
|
||||||
ui64 b[3] = {residue_add(v1[0], v2[0]), residue_add(v1[1], v2[1]), 0};
|
QWORD b[3] = {residue_add(v1[0], v2[0]), residue_add(v1[1], v2[1]), 0};
|
||||||
int bdeg = (b[1] == 0 ? (b[0] == 0 ? -1 : 0) : 1);
|
int bdeg = (b[1] == 0 ? (b[0] == 0 ? -1 : 0) : 1);
|
||||||
int ddeg, c1deg, c2deg;
|
int ddeg, c1deg, c2deg;
|
||||||
ui64 d[3], c1[3], c2[3];
|
QWORD d[3], c1[3], c2[3];
|
||||||
polynomial_xgcd(d1deg, d1, bdeg, b, &ddeg, d, &c1deg, c1, &c2deg, c2);
|
polynomial_xgcd(d1deg, d1, bdeg, b, &ddeg, d, &c1deg, c1, &c2deg, c2);
|
||||||
assert(c1deg <= 0);
|
assert(c1deg <= 0);
|
||||||
assert(c2deg <= 1);
|
assert(c2deg <= 1);
|
||||||
assert(ddeg >= 0);
|
assert(ddeg >= 0);
|
||||||
ui64 dmult = residue_inv(d[ddeg]);
|
QWORD dmult = residue_inv(d[ddeg]);
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < ddeg; i++)
|
for (i = 0; i < ddeg; i++)
|
||||||
d[i] = residue_mul(d[i], dmult);
|
d[i] = residue_mul(d[i], dmult);
|
||||||
@ -387,10 +401,10 @@ static void divisor_add(const TDivisor* src1, const TDivisor* src2, TDivisor* ds
|
|||||||
c1[i] = residue_mul(c1[i], dmult);
|
c1[i] = residue_mul(c1[i], dmult);
|
||||||
for (i = 0; i <= c2deg; i++)
|
for (i = 0; i <= c2deg; i++)
|
||||||
c2[i] = residue_mul(c2[i], dmult);
|
c2[i] = residue_mul(c2[i], dmult);
|
||||||
ui64 u[5];
|
QWORD u[5];
|
||||||
int udeg = polynomial_mul(u1deg, u1, u2deg, u2, -1, u);
|
int udeg = polynomial_mul(u1deg, u1, u2deg, u2, -1, u);
|
||||||
// u is monic
|
// u is monic
|
||||||
ui64 v[7], tmp[7];
|
QWORD v[7], tmp[7];
|
||||||
int vdeg, tmpdeg;
|
int vdeg, tmpdeg;
|
||||||
// c1*(e1*u1*v2 + e2*u2*v1) + c2*(v1*v2 + f)
|
// c1*(e1*u1*v2 + e2*u2*v1) + c2*(v1*v2 + f)
|
||||||
// c1*(e1*u1*(v2-v1) + d1*v1) + c2*(v1*v2 + f)
|
// c1*(e1*u1*(v2-v1) + d1*v1) + c2*(v1*v2 + f)
|
||||||
@ -407,7 +421,7 @@ static void divisor_add(const TDivisor* src1, const TDivisor* src2, TDivisor* ds
|
|||||||
vdeg = polynomial_mul(c2deg, c2, tmpdeg, tmp, vdeg, v);
|
vdeg = polynomial_mul(c2deg, c2, tmpdeg, tmp, vdeg, v);
|
||||||
if (ddeg > 0) {
|
if (ddeg > 0) {
|
||||||
assert(udeg >= 2*ddeg);
|
assert(udeg >= 2*ddeg);
|
||||||
ui64 udiv[5];
|
QWORD udiv[5];
|
||||||
polynomial_div_monic(udeg, u, ddeg, d, udiv); udeg -= ddeg;
|
polynomial_div_monic(udeg, u, ddeg, d, udiv); udeg -= ddeg;
|
||||||
polynomial_div_monic(udeg, udiv, ddeg, d, u); udeg -= ddeg;
|
polynomial_div_monic(udeg, udiv, ddeg, d, u); udeg -= ddeg;
|
||||||
if (vdeg >= 0) {
|
if (vdeg >= 0) {
|
||||||
@ -429,10 +443,10 @@ static void divisor_add(const TDivisor* src1, const TDivisor* src2, TDivisor* ds
|
|||||||
for (; i <= 5; i++)
|
for (; i <= 5; i++)
|
||||||
tmp[i] = f[i];
|
tmp[i] = f[i];
|
||||||
tmpdeg = i - 1;
|
tmpdeg = i - 1;
|
||||||
ui64 udiv[5];
|
QWORD udiv[5];
|
||||||
polynomial_div_monic(tmpdeg, tmp, udeg, u, udiv);
|
polynomial_div_monic(tmpdeg, tmp, udeg, u, udiv);
|
||||||
udeg = tmpdeg - udeg;
|
udeg = tmpdeg - udeg;
|
||||||
ui64 mult = residue_inv(udiv[udeg]);
|
QWORD mult = residue_inv(udiv[udeg]);
|
||||||
for (i = 0; i < udeg; i++)
|
for (i = 0; i < udeg; i++)
|
||||||
u[i] = residue_mul(udiv[i], mult);
|
u[i] = residue_mul(udiv[i], mult);
|
||||||
u[i] = 1;
|
u[i] = 1;
|
||||||
@ -458,9 +472,10 @@ static void divisor_add(const TDivisor* src1, const TDivisor* src2, TDivisor* ds
|
|||||||
dst->v[1] = BAD;
|
dst->v[1] = BAD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define divisor_double(src, dst) divisor_add(src, src, dst)
|
#define divisor_double(src, dst) divisor_add(src, src, dst)
|
||||||
|
|
||||||
static void divisor_mul(const TDivisor* src, ui64 mult, TDivisor* dst)
|
void ConfirmationID::divisor_mul(const TDivisor* src, QWORD mult, TDivisor* dst)
|
||||||
{
|
{
|
||||||
if (mult == 0) {
|
if (mult == 0) {
|
||||||
dst->u[0] = BAD;
|
dst->u[0] = BAD;
|
||||||
@ -482,7 +497,7 @@ static void divisor_mul(const TDivisor* src, ui64 mult, TDivisor* dst)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void divisor_mul128(const TDivisor* src, ui64 mult_lo, ui64 mult_hi, TDivisor* dst)
|
void ConfirmationID::divisor_mul128(const TDivisor* src, QWORD mult_lo, QWORD mult_hi, TDivisor* dst)
|
||||||
{
|
{
|
||||||
if (mult_lo == 0 && mult_hi == 0) {
|
if (mult_lo == 0 && mult_hi == 0) {
|
||||||
dst->u[0] = BAD;
|
dst->u[0] = BAD;
|
||||||
@ -513,13 +528,13 @@ static void divisor_mul128(const TDivisor* src, ui64 mult_lo, ui64 mult_hi, TDiv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rol(unsigned x, int shift)
|
unsigned ConfirmationID::rol(unsigned x, int shift)
|
||||||
{
|
{
|
||||||
//assert(shift > 0 && shift < 32);
|
//assert(shift > 0 && shift < 32);
|
||||||
return (x << shift) | (x >> (32 - shift));
|
return (x << shift) | (x >> (32 - shift));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sha1_single_block(unsigned char input[64], unsigned char output[20])
|
void ConfirmationID::sha1_single_block(unsigned char input[64], unsigned char output[20])
|
||||||
{
|
{
|
||||||
unsigned a, b, c, d, e;
|
unsigned a, b, c, d, e;
|
||||||
a = 0x67452301;
|
a = 0x67452301;
|
||||||
@ -577,7 +592,7 @@ static void sha1_single_block(unsigned char input[64], unsigned char output[20])
|
|||||||
output[16] = e >> 24; output[17] = e >> 16; output[18] = e >> 8; output[19] = e;
|
output[16] = e >> 24; output[17] = e >> 16; output[18] = e >> 8; output[19] = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Mix(unsigned char* buffer, size_t bufSize, const unsigned char* key, size_t keySize)
|
void ConfirmationID::Mix(unsigned char* buffer, size_t bufSize, const unsigned char* key, size_t keySize)
|
||||||
{
|
{
|
||||||
unsigned char sha1_input[64];
|
unsigned char sha1_input[64];
|
||||||
unsigned char sha1_result[20];
|
unsigned char sha1_result[20];
|
||||||
@ -603,7 +618,7 @@ static void Mix(unsigned char* buffer, size_t bufSize, const unsigned char* key,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Unmix(unsigned char* buffer, size_t bufSize, const unsigned char* key, size_t keySize)
|
void ConfirmationID::Unmix(unsigned char* buffer, size_t bufSize, const unsigned char* key, size_t keySize)
|
||||||
{
|
{
|
||||||
unsigned char sha1_input[64];
|
unsigned char sha1_input[64];
|
||||||
unsigned char sha1_result[20];
|
unsigned char sha1_result[20];
|
||||||
@ -629,7 +644,7 @@ static void Unmix(unsigned char* buffer, size_t bufSize, const unsigned char* ke
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int generateConfId(const char* installation_id_str, char confirmation_id[49])
|
int ConfirmationID::Generate(const char* installation_id_str, char confirmation_id[49])
|
||||||
{
|
{
|
||||||
unsigned char installation_id[19]; // 10**45 < 256**19
|
unsigned char installation_id[19]; // 10**45 < 256**19
|
||||||
size_t installation_id_len = 0;
|
size_t installation_id_len = 0;
|
||||||
@ -679,8 +694,8 @@ int generateConfId(const char* installation_id_str, char confirmation_id[49])
|
|||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct {
|
struct {
|
||||||
ui64 HardwareID;
|
QWORD HardwareID;
|
||||||
ui64 ProductIDLow;
|
QWORD ProductIDLow;
|
||||||
unsigned char ProductIDHigh;
|
unsigned char ProductIDHigh;
|
||||||
unsigned short KeySHA1;
|
unsigned short KeySHA1;
|
||||||
} parsed;
|
} parsed;
|
||||||
@ -697,7 +712,7 @@ int generateConfId(const char* installation_id_str, char confirmation_id[49])
|
|||||||
|
|
||||||
unsigned char keybuf[16];
|
unsigned char keybuf[16];
|
||||||
memcpy(keybuf, &parsed.HardwareID, 8);
|
memcpy(keybuf, &parsed.HardwareID, 8);
|
||||||
ui64 productIdMixed = (ui64)productId1 << 41 | (ui64)productId2 << 58 | (ui64)productId3 << 17 | productId4;
|
QWORD productIdMixed = (QWORD)productId1 << 41 | (QWORD)productId2 << 58 | (QWORD)productId3 << 17 | productId4;
|
||||||
memcpy(keybuf + 8, &productIdMixed, 8);
|
memcpy(keybuf + 8, &productIdMixed, 8);
|
||||||
|
|
||||||
TDivisor d;
|
TDivisor d;
|
||||||
@ -706,16 +721,16 @@ int generateConfId(const char* installation_id_str, char confirmation_id[49])
|
|||||||
union {
|
union {
|
||||||
unsigned char buffer[14];
|
unsigned char buffer[14];
|
||||||
struct {
|
struct {
|
||||||
ui64 lo;
|
QWORD lo;
|
||||||
ui64 hi;
|
QWORD hi;
|
||||||
};
|
};
|
||||||
} u;
|
} u;
|
||||||
u.lo = 0;
|
u.lo = 0;
|
||||||
u.hi = 0;
|
u.hi = 0;
|
||||||
u.buffer[7] = attempt;
|
u.buffer[7] = attempt;
|
||||||
Mix(u.buffer, 14, keybuf, 16);
|
Mix(u.buffer, 14, keybuf, 16);
|
||||||
ui64 x2 = ui128_quotient_mod(u.lo, u.hi);
|
QWORD x2 = ui128_quotient_mod(u.lo, u.hi);
|
||||||
ui64 x1 = u.lo - x2 * MOD;
|
QWORD x1 = u.lo - x2 * MOD;
|
||||||
x2++;
|
x2++;
|
||||||
d.u[0] = residue_sub(residue_mul(x1, x1), residue_mul(NON_RESIDUE, residue_mul(x2, x2)));
|
d.u[0] = residue_sub(residue_mul(x1, x1), residue_mul(NON_RESIDUE, residue_mul(x2, x2)));
|
||||||
d.u[1] = residue_add(x1, x1);
|
d.u[1] = residue_add(x1, x1);
|
||||||
@ -727,7 +742,7 @@ int generateConfId(const char* installation_id_str, char confirmation_id[49])
|
|||||||
divisor_mul128(&d, 0x04e21b9d10f127c1, 0x40da7c36d44c, &d);
|
divisor_mul128(&d, 0x04e21b9d10f127c1, 0x40da7c36d44c, &d);
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
ui64 encoded_lo, encoded_hi;
|
QWORD encoded_lo, encoded_hi;
|
||||||
};
|
};
|
||||||
struct {
|
struct {
|
||||||
uint32_t encoded[4];
|
uint32_t encoded[4];
|
||||||
@ -743,9 +758,9 @@ int generateConfId(const char* installation_id_str, char confirmation_id[49])
|
|||||||
e.encoded_lo += MOD;
|
e.encoded_lo += MOD;
|
||||||
e.encoded_hi += (e.encoded_lo < MOD);
|
e.encoded_hi += (e.encoded_lo < MOD);
|
||||||
} else {
|
} else {
|
||||||
ui64 x1 = (d.u[1] % 2 ? d.u[1] + MOD : d.u[1]) / 2;
|
QWORD x1 = (d.u[1] % 2 ? d.u[1] + MOD : d.u[1]) / 2;
|
||||||
ui64 x2sqr = residue_sub(residue_mul(x1, x1), d.u[0]);
|
QWORD x2sqr = residue_sub(residue_mul(x1, x1), d.u[0]);
|
||||||
ui64 x2 = residue_sqrt(x2sqr);
|
QWORD x2 = residue_sqrt(x2sqr);
|
||||||
if (x2 == BAD) {
|
if (x2 == BAD) {
|
||||||
x2 = residue_sqrt(residue_mul(x2sqr, residue_inv(NON_RESIDUE)));
|
x2 = residue_sqrt(residue_mul(x2sqr, residue_inv(NON_RESIDUE)));
|
||||||
assert(x2 != BAD);
|
assert(x2 != BAD);
|
||||||
@ -754,17 +769,17 @@ int generateConfId(const char* installation_id_str, char confirmation_id[49])
|
|||||||
e.encoded_hi += (e.encoded_lo < x1);
|
e.encoded_hi += (e.encoded_lo < x1);
|
||||||
} else {
|
} else {
|
||||||
// points (-x1+x2, v(-x1+x2)) and (-x1-x2, v(-x1-x2))
|
// points (-x1+x2, v(-x1+x2)) and (-x1-x2, v(-x1-x2))
|
||||||
ui64 x1a = residue_sub(x1, x2);
|
QWORD x1a = residue_sub(x1, x2);
|
||||||
ui64 y1 = residue_sub(d.v[0], residue_mul(d.v[1], x1a));
|
QWORD y1 = residue_sub(d.v[0], residue_mul(d.v[1], x1a));
|
||||||
ui64 x2a = residue_add(x1, x2);
|
QWORD x2a = residue_add(x1, x2);
|
||||||
ui64 y2 = residue_sub(d.v[0], residue_mul(d.v[1], x2a));
|
QWORD y2 = residue_sub(d.v[0], residue_mul(d.v[1], x2a));
|
||||||
if (x1a > x2a) {
|
if (x1a > x2a) {
|
||||||
ui64 tmp = x1a;
|
QWORD tmp = x1a;
|
||||||
x1a = x2a;
|
x1a = x2a;
|
||||||
x2a = tmp;
|
x2a = tmp;
|
||||||
}
|
}
|
||||||
if ((y1 ^ y2) & 1) {
|
if ((y1 ^ y2) & 1) {
|
||||||
ui64 tmp = x1a;
|
QWORD tmp = x1a;
|
||||||
x1a = x2a;
|
x1a = x2a;
|
||||||
x2a = tmp;
|
x2a = tmp;
|
||||||
}
|
}
|
||||||
@ -777,14 +792,15 @@ int generateConfId(const char* installation_id_str, char confirmation_id[49])
|
|||||||
for (i = 0; i < 35; i++) {
|
for (i = 0; i < 35; i++) {
|
||||||
unsigned c = e.encoded[3] % 10;
|
unsigned c = e.encoded[3] % 10;
|
||||||
e.encoded[3] /= 10;
|
e.encoded[3] /= 10;
|
||||||
unsigned c2 = ((ui64)c << 32 | e.encoded[2]) % 10;
|
unsigned c2 = ((QWORD)c << 32 | e.encoded[2]) % 10;
|
||||||
e.encoded[2] = ((ui64)c << 32 | e.encoded[2]) / 10;
|
e.encoded[2] = ((QWORD)c << 32 | e.encoded[2]) / 10;
|
||||||
unsigned c3 = ((ui64)c2 << 32 | e.encoded[1]) % 10;
|
unsigned c3 = ((QWORD)c2 << 32 | e.encoded[1]) % 10;
|
||||||
e.encoded[1] = ((ui64)c2 << 32 | e.encoded[1]) / 10;
|
e.encoded[1] = ((QWORD)c2 << 32 | e.encoded[1]) / 10;
|
||||||
unsigned c4 = ((ui64)c3 << 32 | e.encoded[0]) % 10;
|
unsigned c4 = ((QWORD)c3 << 32 | e.encoded[0]) % 10;
|
||||||
e.encoded[0] = ((ui64)c3 << 32 | e.encoded[0]) / 10;
|
e.encoded[0] = ((QWORD)c3 << 32 | e.encoded[0]) / 10;
|
||||||
decimal[34 - i] = c4;
|
decimal[34 - i] = c4;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(e.encoded[0] == 0 && e.encoded[1] == 0 && e.encoded[2] == 0 && e.encoded[3] == 0);
|
assert(e.encoded[0] == 0 && e.encoded[1] == 0 && e.encoded[2] == 0 && e.encoded[3] == 0);
|
||||||
char* q = confirmation_id;
|
char* q = confirmation_id;
|
||||||
for (i = 0; i < 7; i++) {
|
for (i = 0; i < 7; i++) {
|
||||||
|
53
src/confid.h
Normal file
53
src/confid.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
//
|
||||||
|
// Created by neo on 6/6/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef WINDOWSXPKG_CONFID_H
|
||||||
|
#define WINDOWSXPKG_CONFID_H
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
// Confirmation ID generator constants
|
||||||
|
#define SUCCESS 0
|
||||||
|
#define ERR_TOO_SHORT 1
|
||||||
|
#define ERR_TOO_LARGE 2
|
||||||
|
#define ERR_INVALID_CHARACTER 3
|
||||||
|
#define ERR_INVALID_CHECK_DIGIT 4
|
||||||
|
#define ERR_UNKNOWN_VERSION 5
|
||||||
|
#define ERR_UNLUCKY 6
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
QWORD u[2];
|
||||||
|
QWORD v[2];
|
||||||
|
} TDivisor;
|
||||||
|
|
||||||
|
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);
|
||||||
|
static QWORD ui128_quotient_mod(QWORD lo, QWORD hi);
|
||||||
|
static QWORD residue_mul(QWORD x, QWORD y);
|
||||||
|
static QWORD residue_pow(QWORD x, QWORD y);
|
||||||
|
static QWORD inverse(QWORD u, QWORD v);
|
||||||
|
static QWORD residue_inv(QWORD x);
|
||||||
|
static QWORD residue_sqrt(QWORD what);
|
||||||
|
static int find_divisor_v(TDivisor* d);
|
||||||
|
static int polynomial_mul(int adeg, const QWORD a[], int bdeg, const QWORD b[], int resultprevdeg, QWORD result[]);
|
||||||
|
static int polynomial_div_monic(int adeg, QWORD a[], int bdeg, const QWORD b[], QWORD* quotient);
|
||||||
|
static void polynomial_xgcd(int adeg, const QWORD a[3], int bdeg, const QWORD b[3], int* pgcddeg, QWORD gcd[3], int* pmult1deg, QWORD mult1[3], int* pmult2deg, QWORD mult2[3]);
|
||||||
|
static int u2poly(const TDivisor* src, QWORD polyu[3], QWORD polyv[2]);
|
||||||
|
static void divisor_add(const TDivisor* src1, const TDivisor* src2, TDivisor* dst);
|
||||||
|
static void divisor_mul(const TDivisor* src, QWORD mult, TDivisor* dst);
|
||||||
|
static void divisor_mul128(const TDivisor* src, QWORD mult_lo, QWORD mult_hi, TDivisor* dst);
|
||||||
|
static unsigned rol(unsigned x, int shift);
|
||||||
|
static void sha1_single_block(unsigned char input[64], unsigned char output[20]);
|
||||||
|
static void Mix(unsigned char* buffer, size_t bufSize, const unsigned char* key, size_t keySize);
|
||||||
|
static void Unmix(unsigned char* buffer, size_t bufSize, const unsigned char* key, size_t keySize);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static int Generate(const char* installation_id_str, char confirmation_id[49]);
|
||||||
|
static int CLIRun();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //WINDOWSXPKG_CONFID_H
|
94
src/header.h
94
src/header.h
@ -57,14 +57,27 @@
|
|||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
// Confirmation ID generator constants
|
enum MODE {
|
||||||
#define SUCCESS 0
|
MODE_BINK1998 = 0,
|
||||||
#define ERR_TOO_SHORT 1
|
MODE_BINK2002 = 1,
|
||||||
#define ERR_TOO_LARGE 2
|
MODE_CONFIRMATION_ID = 2,
|
||||||
#define ERR_INVALID_CHARACTER 3
|
};
|
||||||
#define ERR_INVALID_CHECK_DIGIT 4
|
|
||||||
#define ERR_UNKNOWN_VERSION 5
|
struct Options {
|
||||||
#define ERR_UNLUCKY 6
|
std::string binkid;
|
||||||
|
std::string keysFilename;
|
||||||
|
std::string instid;
|
||||||
|
int channelID;
|
||||||
|
int numKeys;
|
||||||
|
bool verbose;
|
||||||
|
bool help;
|
||||||
|
bool error;
|
||||||
|
bool list;
|
||||||
|
|
||||||
|
MODE applicationMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Options options;
|
||||||
|
|
||||||
// Type definitions
|
// Type definitions
|
||||||
typedef bool BOOL;
|
typedef bool BOOL;
|
||||||
@ -73,8 +86,11 @@ typedef uint16_t WORD;
|
|||||||
typedef uint32_t DWORD;
|
typedef uint32_t DWORD;
|
||||||
typedef uint64_t QWORD;
|
typedef uint64_t QWORD;
|
||||||
|
|
||||||
|
#ifdef __SIZEOF_INT128__
|
||||||
|
typedef unsigned __int128 DQWORD;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Global variables
|
// Global variables
|
||||||
extern char pCharset[];
|
|
||||||
|
|
||||||
// util.cpp
|
// util.cpp
|
||||||
int BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen); // Hello OpenSSL developers, please tell me, where is this function at?
|
int BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen); // Hello OpenSSL developers, please tell me, where is this function at?
|
||||||
@ -96,65 +112,5 @@ EC_GROUP *initializeEllipticCurve(
|
|||||||
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);
|
||||||
|
|
||||||
// cli.cpp
|
|
||||||
void print_product_key(char *pk);
|
|
||||||
void print_product_id(DWORD *pid);
|
|
||||||
|
|
||||||
struct Options {
|
|
||||||
std::string binkid;
|
|
||||||
int channelID;
|
|
||||||
std::string keysFilename;
|
|
||||||
int numKeys;
|
|
||||||
std::string instid;
|
|
||||||
bool help;
|
|
||||||
bool list;
|
|
||||||
bool isBink2002;
|
|
||||||
bool verbose;
|
|
||||||
bool error;
|
|
||||||
};
|
|
||||||
extern Options options;
|
|
||||||
|
|
||||||
int parseCommandLine(int argc, char* argv[], Options* output);
|
|
||||||
int validateCommandLine(Options* options, char* argv[], json* output);
|
|
||||||
void showHelp(char* argv[]);
|
|
||||||
bool loadJSON(const fs::path& filename, json *output);
|
|
||||||
|
|
||||||
// xp.cpp
|
|
||||||
bool verifyXPKey(
|
|
||||||
EC_GROUP *eCurve,
|
|
||||||
EC_POINT *basePoint,
|
|
||||||
EC_POINT *publicKey,
|
|
||||||
char (&pKey)[25]
|
|
||||||
);
|
|
||||||
|
|
||||||
void generateXPKey(
|
|
||||||
EC_GROUP *eCurve,
|
|
||||||
EC_POINT *basePoint,
|
|
||||||
BIGNUM *genOrder,
|
|
||||||
BIGNUM *privateKey,
|
|
||||||
DWORD pSerial,
|
|
||||||
char (&pKey)[25]
|
|
||||||
);
|
|
||||||
|
|
||||||
// server.cpp
|
|
||||||
bool verifyServerKey(
|
|
||||||
EC_GROUP *eCurve,
|
|
||||||
EC_POINT *basePoint,
|
|
||||||
EC_POINT *publicKey,
|
|
||||||
char (&cdKey)[25]
|
|
||||||
);
|
|
||||||
|
|
||||||
void generateServerKey(
|
|
||||||
EC_GROUP *eCurve,
|
|
||||||
EC_POINT *basePoint,
|
|
||||||
BIGNUM *genOrder,
|
|
||||||
BIGNUM *privateKey,
|
|
||||||
DWORD pChannelID,
|
|
||||||
DWORD pAuthInfo,
|
|
||||||
char (&pKey)[25]
|
|
||||||
);
|
|
||||||
|
|
||||||
// confid.cpp
|
|
||||||
int generateConfId(const char* installation_id_str, char confirmation_id[49]);
|
|
||||||
|
|
||||||
#endif //WINDOWSXPKG_HEADER_H
|
#endif //WINDOWSXPKG_HEADER_H
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include "header.h"
|
#include "header.h"
|
||||||
|
|
||||||
|
char pCharset[] = "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) {
|
||||||
BYTE pDecodedKey[PK_LENGTH + NULL_TERMINATOR]{};
|
BYTE pDecodedKey[PK_LENGTH + NULL_TERMINATOR]{};
|
||||||
|
150
src/main.cpp
150
src/main.cpp
@ -3,163 +3,37 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "header.h"
|
#include "header.h"
|
||||||
|
#include "cli.h"
|
||||||
|
|
||||||
char pCharset[] = "BCDFGHJKMPQRTVWXY2346789";
|
|
||||||
Options options;
|
Options options;
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (!parseCommandLine(argc, argv, &options)) {
|
if (!CLI::parseCommandLine(argc, argv, &options)) {
|
||||||
fmt::print("error parsing command line options\n");
|
fmt::print("error parsing command line options\n");
|
||||||
showHelp(argv);
|
CLI::showHelp(argv);
|
||||||
return !options.error ? 0 : 1;
|
return !options.error ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
json keys;
|
json keys;
|
||||||
int status = validateCommandLine(&options, argv, &keys);
|
|
||||||
|
|
||||||
|
int status = CLI::validateCommandLine(&options, argv, &keys);
|
||||||
if (status > 0) {
|
if (status > 0) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* BINKID = options.binkid.c_str();
|
CLI* run = new CLI(options, keys);
|
||||||
|
|
||||||
// We cannot produce a valid key without knowing the private key k. The reason for this is that
|
switch(options.applicationMode) {
|
||||||
// we need the result of the function K(x; y) = kG(x; y).
|
case MODE_BINK1998:
|
||||||
BIGNUM *privateKey = BN_new();
|
return run->BINK1998();
|
||||||
|
|
||||||
// We can, however, validate any given key using the available public key: {p, a, b, G, K}.
|
case MODE_BINK2002:
|
||||||
// genOrder the order of the generator G, a value we have to reverse -> Schoof's Algorithm.
|
return run->BINK2002();
|
||||||
BIGNUM *genOrder = BN_new();
|
|
||||||
|
|
||||||
/* Computed data */
|
case MODE_CONFIRMATION_ID:
|
||||||
BN_dec2bn(&genOrder, keys["BINK"][BINKID]["n"].get<std::string>().c_str());
|
return run->ConfirmationID();
|
||||||
BN_dec2bn(&privateKey, keys["BINK"][BINKID]["priv"].get<std::string>().c_str());
|
|
||||||
|
|
||||||
if (options.verbose) {
|
|
||||||
fmt::print("----------------------------------------------------------- \n");
|
|
||||||
fmt::print("Loaded the following curve constraints: BINK[{}]\n", BINKID);
|
|
||||||
fmt::print("----------------------------------------------------------- \n");
|
|
||||||
fmt::print(" P: {}\n", keys["BINK"][BINKID]["p"].get<std::string>());
|
|
||||||
fmt::print(" a: {}\n", keys["BINK"][BINKID]["a"].get<std::string>());
|
|
||||||
fmt::print(" b: {}\n", keys["BINK"][BINKID]["b"].get<std::string>());
|
|
||||||
fmt::print("Gx: {}\n", keys["BINK"][BINKID]["g"]["x"].get<std::string>());
|
|
||||||
fmt::print("Gy: {}\n", keys["BINK"][BINKID]["g"]["y"].get<std::string>());
|
|
||||||
fmt::print("Kx: {}\n", keys["BINK"][BINKID]["pub"]["x"].get<std::string>());
|
|
||||||
fmt::print("Ky: {}\n", keys["BINK"][BINKID]["pub"]["y"].get<std::string>());
|
|
||||||
fmt::print(" n: {}\n", keys["BINK"][BINKID]["n"].get<std::string>());
|
|
||||||
fmt::print(" k: {}\n", keys["BINK"][BINKID]["priv"].get<std::string>());
|
|
||||||
}
|
|
||||||
|
|
||||||
EC_POINT *genPoint, *pubPoint;
|
|
||||||
EC_GROUP *eCurve = initializeEllipticCurve(
|
|
||||||
keys["BINK"][BINKID]["p"].get<std::string>(),
|
|
||||||
keys["BINK"][BINKID]["a"].get<std::string>(),
|
|
||||||
keys["BINK"][BINKID]["b"].get<std::string>(),
|
|
||||||
keys["BINK"][BINKID]["g"]["x"].get<std::string>(),
|
|
||||||
keys["BINK"][BINKID]["g"]["y"].get<std::string>(),
|
|
||||||
keys["BINK"][BINKID]["pub"]["x"].get<std::string>(),
|
|
||||||
keys["BINK"][BINKID]["pub"]["y"].get<std::string>(),
|
|
||||||
genPoint,
|
|
||||||
pubPoint
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!options.instid.empty()) {
|
|
||||||
char confirmation_id[49];
|
|
||||||
int err = generateConfId(options.instid.c_str(), confirmation_id);
|
|
||||||
|
|
||||||
switch (err) {
|
|
||||||
case ERR_TOO_SHORT:
|
|
||||||
fmt::print("ERROR: Installation ID is too short.\n");
|
|
||||||
return 1;
|
|
||||||
case ERR_TOO_LARGE:
|
|
||||||
fmt::print("ERROR: Installation ID is too long.\n");
|
|
||||||
return 1;
|
|
||||||
case ERR_INVALID_CHARACTER:
|
|
||||||
fmt::print("ERROR: Invalid character in installation ID.\n");
|
|
||||||
return 1;
|
|
||||||
case ERR_INVALID_CHECK_DIGIT:
|
|
||||||
fmt::print("ERROR: Installation ID checksum failed. Please check that it is typed correctly.\n");
|
|
||||||
return 1;
|
|
||||||
case ERR_UNKNOWN_VERSION:
|
|
||||||
fmt::print("ERROR: Unknown installation ID version.\n");
|
|
||||||
return 1;
|
|
||||||
case ERR_UNLUCKY:
|
|
||||||
fmt::print("ERROR: Unable to generate valid confirmation ID.\n");
|
|
||||||
return 1;
|
|
||||||
case SUCCESS:
|
|
||||||
fmt::print("Confirmation ID: {}\n", confirmation_id);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fmt::print("Unknown error occurred during Confirmation ID generation: {}\n", err);
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculation
|
|
||||||
char pKey[25];
|
|
||||||
int count = 0, total = options.numKeys;
|
|
||||||
|
|
||||||
// BINK2002 Generation
|
|
||||||
if (options.isBink2002) {
|
|
||||||
DWORD pChannelID = options.channelID << 1;
|
|
||||||
|
|
||||||
if (options.verbose) {
|
|
||||||
fmt::print("> Channel ID: {:03d}\n", options.channelID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate a key
|
|
||||||
for (int i = 0; i < total; i++) {
|
|
||||||
DWORD pAuthInfo;
|
|
||||||
RAND_bytes((BYTE *)&pAuthInfo, 4);
|
|
||||||
pAuthInfo &= 0x3ff;
|
|
||||||
|
|
||||||
if (options.verbose) {
|
|
||||||
fmt::print("> AuthInfo: {}\n", pAuthInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
generateServerKey(eCurve, genPoint, genOrder, privateKey, pChannelID, pAuthInfo, pKey);
|
|
||||||
print_product_key(pKey);
|
|
||||||
fmt::print("\n\n");
|
|
||||||
|
|
||||||
// verify a key
|
|
||||||
count += verifyServerKey(eCurve, genPoint, pubPoint, pKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt::print("Success count: {}/{}\n", count, total);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// BINK1998 Generation
|
|
||||||
|
|
||||||
DWORD nRaw = options.channelID * 1000000 ; /* <- change */
|
|
||||||
|
|
||||||
BIGNUM *bnrand = BN_new();
|
|
||||||
BN_rand(bnrand, 19, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY);
|
|
||||||
|
|
||||||
int oRaw;
|
|
||||||
char *cRaw = BN_bn2dec(bnrand);
|
|
||||||
|
|
||||||
sscanf(cRaw, "%d", &oRaw);
|
|
||||||
nRaw += (oRaw &= 0xF423F); // ensure our serial is less than 999999
|
|
||||||
|
|
||||||
if (options.verbose) {
|
|
||||||
fmt::print("> PID: {:09d}\n", nRaw);
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate a key
|
|
||||||
BN_sub(privateKey, genOrder, privateKey);
|
|
||||||
nRaw <<= 1;
|
|
||||||
|
|
||||||
for (int i = 0; i < total; i++) {
|
|
||||||
generateXPKey(eCurve, genPoint, genOrder, privateKey, nRaw, pKey);
|
|
||||||
print_product_key(pKey);
|
|
||||||
fmt::print("\n\n");
|
|
||||||
|
|
||||||
// verify the key
|
|
||||||
count += verifyXPKey(eCurve, genPoint, pubPoint, pKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt::print("Success count: {}/{}\n", count, total);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user