total refactor, happy new year, ground level code for automatic DPC selection, code is currently very much a work in progress, and very much broken, we'll work through it

This commit is contained in:
Neo-Desktop 2024-01-04 16:32:18 -08:00
parent c0a4c76b54
commit bf6365916d
41 changed files with 2571 additions and 1448 deletions

View File

@ -213,4 +213,8 @@ WhitespaceSensitiveMacros:
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...
---
Language: Json
BasedOnStyle: LLVM
...

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,22 +1,22 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# @FileCreated by techguy16 on 07/23/2023
# @Maintainer techguy16
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# @FileCreated by techguy16 on 07/23/2023
# @Maintainer techguy16
name: C/C++ CI (FreeBSD)

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

14
.idea/remote-targets.xml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteTargetsManager">
<option name="projectDefaultTargetUuid" value="36c80fd0-a122-4ef6-8ee6-1bd41007a378" />
<targets>
<target name="WSL - Ubuntu" type="wsl" uuid="36c80fd0-a122-4ef6-8ee6-1bd41007a378">
<config>
<option name="distributionMsId" value="Ubuntu" />
<option name="projectRootOnTarget" value="{exitCode=0, timeout=false, cancelled=false, stdout=/mnt/c/Users/neo/AppData/Local/Programs/CLion/jbr/bin&#10;, stderr=}/UMSKT" />
</config>
</target>
</targets>
</component>
</project>

25
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,25 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# @FileCreated by Neo on 01/03/2024
# @Maintainer Neo
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: 'v15.0.7' # Use the sha / tag you want to point at
hooks:
- id: clang-format

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -34,28 +34,27 @@ SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS})
SET(UMSKT_LINK_DIRS ${UMSKT_LINK_DIRS})
# macOS does not support static build
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
SET(UMSKT_USE_SHARED_OPENSSL ON)
endif()
ENDIF ()
# neither does dos idk i'm trying random stuff
if (DJGPP_WATT32)
IF (DJGPP_WATT32)
SET(UMSKT_USE_SHARED_OPENSSL ON)
endif()
ENDIF ()
IF(UMSKT_USE_SHARED_OPENSSL)
IF (UMSKT_USE_SHARED_OPENSSL)
SET(OPENSSL_USE_STATIC_LIBS FALSE)
SET(OPENSSL_MSVC_STATIC_RT FALSE)
MESSAGE(STATUS "[UMSKT] Requesting dynamic version of OpenSSL")
ELSE()
ELSE ()
SET(OPENSSL_USE_STATIC_LIBS TRUE)
SET(OPENSSL_MSVC_STATIC_RT TRUE)
MESSAGE(STATUS "[UMSKT] Requesting static version of OpenSSL")
ENDIF()
ENDIF ()
IF(DJGPP_WATT32)
IF (DJGPP_WATT32)
SET(CMAKE_SYSTEM_NAME MSDOS)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
@ -63,30 +62,30 @@ IF(DJGPP_WATT32)
SET(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} ${DJGPP_WATT32})
SET(UMSKT_LINK_DIRS ${UMSKT_LINK_DIRS} ${WATT_ROOT}/lib)
ENDIF()
ENDIF ()
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
SET(BUILD_SHARED_LIBS ON)
MESSAGE(STATUS "[UMSKT] macOS has no static library - Shared library forced on")
endif()
IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
SET(BUILD_SHARED_LIBS ON)
MESSAGE(STATUS "[UMSKT] macOS has no static library - Shared library forced on")
ENDIF ()
# if we're compiling with MSVC, respect the DEBUG compile option
IF(MSVC)
IF (MSVC)
SET(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
IF(NOT BUILD_SHARED_LIBS)
IF (NOT BUILD_SHARED_LIBS)
SET(CMAKE_CXX_FLAGS_RELEASE "/MT")
SET(CMAKE_CXX_FLAGS_DEBUG "/MTd")
ELSE()
ELSE ()
SET(CMAKE_CXX_FLAGS_RELEASE "/MD")
SET(CMAKE_CXX_FLAGS_DEBUG "/MDd")
ENDIF()
ENDIF ()
SET(CMAKE_EXE_LINKER_FLAGS "/INCREMENTAL:NO /NODEFAULTLIB:MSVCRT")
SET(CMAKE_ENABLE_EXPORTS ON)
SET(UMSKT_EXE_WINDOWS_EXTRA src/windows/umskt.rc)
SET(UMSKT_EXE_WINDOWS_DLL src/windows/dllmain.cpp)
ENDIF()
ENDIF ()
IF(MUSL_STATIC)
IF (MUSL_STATIC)
MESSAGE(STATUS "[UMSKT] Performing a fully static build using muslc")
SET(BUILD_SHARED_LIBS OFF)
SET(OPENSSL_USE_STATIC_LIBS TRUE)
@ -96,47 +95,47 @@ IF(MUSL_STATIC)
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc -static-libstdc++")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
ENDIF()
ENDIF ()
# find the system installed OpenSSL development library
FIND_PACKAGE(OpenSSL REQUIRED)
IF(NOT OPENSSL_FOUND)
IF (NOT OPENSSL_FOUND)
MESSAGE(SEND_ERROR "OpenSSL Development Libraries Not Found")
MESSAGE(SEND_ERROR "Please consult your package manager of choice to install the prerequisite")
MESSAGE(SEND_ERROR "The package name is commonly called libssl-dev or openssl-dev depending on distribution")
MESSAGE(FATAL_ERROR "Can not continue without OpenSSL")
ENDIF()
ENDIF ()
IF(NOT MUSL_STATIC)
IF (NOT MUSL_STATIC)
# if we found shared libraries - do the following:
IF (OPENSSL_USE_STATIC_LIBS)
MESSAGE(STATUS "[UMSKT] requested static version of OpenSSL")
if (NOT UMSKT_USE_SHARED_OPENSSL)
MESSAGE(STATUS "[UMSKT] not asked for shared version of OpenSSL")
ENDIF()
MESSAGE(STATUS "[UMSKT] requested static version of OpenSSL")
IF (NOT UMSKT_USE_SHARED_OPENSSL)
MESSAGE(STATUS "[UMSKT] not asked for shared version of OpenSSL")
ENDIF ()
IF(MSVC)
SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} "ws2_32.lib")
SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} "crypt32.lib")
MESSAGE(STATUS "[UMSKT] msvc adding ws2_32.lib crypt32.lib")
ENDIF()
ENDIF()
IF (MSVC)
SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} "ws2_32.lib")
SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} "crypt32.lib")
MESSAGE(STATUS "[UMSKT] msvc adding ws2_32.lib crypt32.lib")
ENDIF ()
ENDIF ()
STRING(REGEX MATCH "(\\.so|\\.dll|\\.dylib)$" OPENSSL_CRYPTO_SHARED "${OPENSSL_CRYPTO_LIBRARY}")
IF(OPENSSL_CRYPTO_SHARED)
MESSAGE(STATUS "[UMSKT] Detected Shared library version of OpenSSL")
ELSE()
MESSAGE(STATUS "[UMSKT] Detected Static Library version of OpenSSL")
IF (OPENSSL_CRYPTO_SHARED)
MESSAGE(STATUS "[UMSKT] Detected Shared library version of OpenSSL")
ELSE ()
MESSAGE(STATUS "[UMSKT] Detected Static Library version of OpenSSL")
# static libcrypto on Fedora needs -lz at link time
IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
FIND_PACKAGE(ZLIB REQUIRED)
IF (NOT ZLIB_FOUND)
MESSAGE(FATAL_ERROR "[UMSKT] linux static OpenSSL requires zlib")
ENDIF()
ENDIF()
ENDIF()
ENDIF()
# static libcrypto on Fedora needs -lz at link time
IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
FIND_PACKAGE(ZLIB REQUIRED)
IF (NOT ZLIB_FOUND)
MESSAGE(FATAL_ERROR "[UMSKT] linux static OpenSSL requires zlib")
ENDIF ()
ENDIF ()
ENDIF ()
ENDIF ()
# initalize cpm.CMake
INCLUDE(cmake/CPM.cmake)
@ -185,39 +184,43 @@ CPMAddPackage(
### Resource compilation
CMRC_ADD_RESOURCE_LIBRARY(umskt-rc ALIAS umskt::rc NAMESPACE umskt keys.json)
SET(LIBUMSKT_SRC src/libumskt/libumskt.cpp src/libumskt/pidgen3/BINK1998.cpp src/libumskt/pidgen3/BINK2002.cpp src/libumskt/pidgen3/key.cpp src/libumskt/pidgen3/util.cpp src/libumskt/confid/confid.cpp src/libumskt/confid/polynomial.cpp src/libumskt/confid/residue.cpp src/libumskt/confid/divisor.cpp src/libumskt/pidgen2/PIDGEN2.cpp src/libumskt/debugoutput.cpp)
SET(LIBUMSKT_PIDGEN2 src/libumskt/pidgen2/PIDGEN2.cpp)
SET(LIBUMSKT_PIDGEN3 src/libumskt/pidgen3/PIDGEN3.cpp src/libumskt/pidgen3/BINK1998.cpp src/libumskt/pidgen3/BINK2002.cpp)
SET(LIBUMSKT_CONFID src/libumskt/confid/confid.cpp src/libumskt/confid/polynomial.cpp src/libumskt/confid/residue.cpp src/libumskt/confid/divisor.cpp)
SET(LIBUMSKT_SRC src/libumskt/libumskt.cpp src/libumskt/debugoutput.cpp ${LIBUMSKT_PIDGEN2} ${LIBUMSKT_PIDGEN3} ${LIBUMSKT_CONFID})
SET(UMSKT_CLI_SRC src/main.cpp src/cli.cpp src/options.cpp)
#### Separate Build Path for emscripten
IF (EMSCRIPTEN)
ADD_EXECUTABLE(umskt ${LIBUMSKT_SRC})
ADD_EXECUTABLE(umskt ${UMSKT_CLI_SRC} ${LIBUMSKT_SRC})
TARGET_INCLUDE_DIRECTORIES(umskt PUBLIC ${OPENSSL_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(umskt -static OpenSSL::Crypto cryptopp::cryptopp fmt)
SET(CMAKE_EXECUTABLE_SUFFIX ".html")
SET_TARGET_PROPERTIES(umskt PROPERTIES COMPILE_FLAGS "-Os -sEXPORTED_RUNTIME_METHODS=ccall,cwrap")
SET_TARGET_PROPERTIES(umskt PROPERTIES LINK_FLAGS "-Os -sWASM=1 -sEXPORT_ALL=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap --no-entry")
ELSE()
SET_TARGET_PROPERTIES(umskt PROPERTIES LINK_FLAGS "-Os -sWASM=1 -sEXPORT_ALL=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap --no-entry")
ELSE ()
ADD_LIBRARY(_umskt ${LIBUMSKT_SRC} ${UMSKT_EXE_WINDOWS_EXTRA} ${UMSKT_EXE_WINDOWS_DLL})
TARGET_INCLUDE_DIRECTORIES(_umskt PUBLIC ${OPENSSL_INCLUDE_DIR})
TARGET_LINK_DIRECTORIES(_umskt PUBLIC ${UMSKT_LINK_DIRS})
TARGET_LINK_LIBRARIES(_umskt ${OPENSSL_CRYPTO_LIBRARIES} fmt ${UMSKT_LINK_LIBS})
### UMSKT executable compilation
ADD_EXECUTABLE(umskt src/main.cpp src/cli.cpp ${UMSKT_EXE_WINDOWS_EXTRA})
ADD_EXECUTABLE(umskt ${UMSKT_CLI_SRC} ${UMSKT_EXE_WINDOWS_EXTRA})
TARGET_INCLUDE_DIRECTORIES(umskt PUBLIC ${OPENSSL_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(umskt _umskt ${OPENSSL_CRYPTO_LIBRARIES} ${ZLIB_LIBRARIES} fmt nlohmann_json::nlohmann_json umskt::rc ${UMSKT_LINK_LIBS})
TARGET_LINK_DIRECTORIES(umskt PUBLIC ${UMSKT_LINK_DIRS})
IF(MSVC AND MSVC_MSDOS_STUB)
IF (MSVC AND MSVC_MSDOS_STUB)
SET_PROPERTY(TARGET umskt APPEND PROPERTY LINK_FLAGS /STUB:${MSVC_MSDOS_STUB})
ENDIF()
ENDIF ()
IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install(TARGETS umskt DESTINATION bin)
ENDIF()
INSTALL(TARGETS umskt DESTINATION bin)
ENDIF ()
### Copy Shared Libraries and dependency files
IF (OPENSSL_CRYPTO_SHARED)
GET_FILENAME_COMPONENT(OPENSSL_CRYPTO_LIBRARY_FILENAME ${OPENSSL_CRYPTO_LIBRARY} NAME)
CONFIGURE_FILE(${OPENSSL_CRYPTO_LIBRARY} "${CMAKE_CURRENT_BINARY_DIR}/${OPENSSL_CRYPTO_LIBRARY_FILENAME}" COPYONLY)
ENDIF()
ENDIF()
ENDIF ()
ENDIF ()

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -2,7 +2,7 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

932
keys.json

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -22,16 +22,39 @@
#include "cli.h"
CLI::~CLI()
// define static storage
Options CLI::options;
json CLI::keys;
BYTE CLI::Init(int argcIn, char **argvIn)
{
EC_GROUP_free(eCurve);
EC_POINT_free(genPoint);
EC_POINT_free(pubPoint);
BN_free(privateKey);
BN_free(genOrder);
// set default options
options = {argcIn, argvIn, "2E", "", "", "", "", "", "WINXPPVLK", 0,
0, 1, false, false, false, false, false, false, false, STATE_BINK1998_GENERATE};
SetHelpText();
BOOL success = parseCommandLine();
if (!success)
{
return options.error;
}
success = processOptions();
if (!success)
{
return 2;
}
return 0;
}
bool CLI::loadJSON(const fs::path &filename, json *output)
/**
*
* @param filename
* @return success
*/
BOOL CLI::loadJSON(const fs::path &filename)
{
if (!filename.empty() && !fs::exists(filename))
{
@ -41,16 +64,23 @@ bool CLI::loadJSON(const fs::path &filename, json *output)
else if (fs::exists(filename))
{
std::ifstream f(filename);
*output = json::parse(f, nullptr, false, false);
try
{
keys = json::parse(f, nullptr, false, false);
}
catch (const json::exception &e)
{
fmt::print("ERROR: Exception thrown while parsing {}: {}\n", filename.string(), e.what());
}
}
else if (filename.empty())
{
cmrc::embedded_filesystem fs = cmrc::umskt::get_filesystem();
cmrc::file keys = fs.open("keys.json");
*output = json::parse(keys, nullptr, false, false);
cmrc::file jsonFile = fs.open("keys.json");
keys = json::parse(jsonFile, nullptr, false, false);
}
if (output->is_discarded())
if (keys.is_discarded())
{
fmt::print("ERROR: Unable to parse keys from {}\n", filename.string());
return false;
@ -59,314 +89,80 @@ bool CLI::loadJSON(const fs::path &filename, json *output)
return true;
}
void CLI::showHelp(char *argv[])
/**
*
* @return success
*/
BOOL CLI::processOptions()
{
fmt::print("usage: {} \n", argv[0]);
fmt::print("\t-h --help\tshow this message\n");
fmt::print("\t-v --verbose\tenable verbose output\n");
fmt::print("\t-n --number\tnumber of keys to generate (defaults to 1)\n");
fmt::print("\t-f --file\tspecify which keys file to load\n");
fmt::print("\t-i --instid\tinstallation ID used to generate confirmation ID\n");
fmt::print("\t-m --mode\tproduct family to activate.\n\t\t\tvalid options are \"WINDOWS\", \"OFFICEXP\", "
"\"OFFICE2K3\", \"OFFICE2K7\" or \"PLUSDME\"\n\t\t\t(defaults to \"WINDOWS\")\n");
fmt::print("\t-p --productid\tthe product ID of the Program to activate. only required for Office 2K3 and Office "
"2K7 programs\n");
fmt::print("\t-b --binkid\tspecify which BINK identifier to load (defaults to 2E)\n");
fmt::print("\t-l --list\tshow which products/binks can be loaded\n");
fmt::print("\t-c --channelid\tspecify which Channel Identifier to use (defaults to 640)\n");
fmt::print("\t-s --serial\tspecifies a serial to use in the product ID (defaults to random, BINK1998 only)\n");
fmt::print("\t-u --upgrade\tspecifies the Product Key will be an \"Upgrade\" version\n");
fmt::print("\t-V --validate\tproduct key to validate signature\n");
fmt::print("\t-N --nonewlines\tdisables newlines (for easier embedding in other apps)\n");
fmt::print("\n");
}
int CLI::parseCommandLine(int argc, char *argv[], Options *options)
{
// set default options
*options = Options{"2E", "", "", "", "", 640, 0, 1,
false, false, false, false, false, false, false, MODE_BINK1998_GENERATE,
WINDOWS};
for (int i = 1; i < argc; i++)
if (options.verbose)
{
std::string arg = argv[i];
if (arg == "-v" || arg == "--verbose")
{
options->verbose = true;
UMSKT::setDebugOutput(stderr);
}
else if (arg == "-h" || arg == "--help")
{
options->help = true;
}
else if (arg == "-n" || arg == "--number")
{
if (i == argc - 1)
{
options->error = true;
break;
}
int nKeys;
if (!sscanf(argv[i + 1], "%d", &nKeys))
{
options->error = true;
}
else
{
options->numKeys = nKeys;
}
i++;
}
else if (arg == "-b" || arg == "--bink")
{
if (i == argc - 1)
{
options->error = true;
break;
}
options->binkid = argv[i + 1];
i++;
}
else if (arg == "-l" || arg == "--list")
{
options->list = true;
}
else if (arg == "-c" || arg == "--channelid")
{
if (i == argc - 1)
{
options->error = true;
break;
}
int siteID;
if (!sscanf(argv[i + 1], "%d", &siteID))
{
options->error = true;
}
else
{
options->channelID = siteID;
}
i++;
}
else if (arg == "-s" || arg == "--serial")
{
if (i == argc - 1)
{
options->error = true;
break;
}
int serial_val;
if (!sscanf(argv[i + 1], "%d", &serial_val))
{
options->error = true;
}
else
{
options->serialSet = true;
options->serial = serial_val;
}
i++;
}
else if (arg == "-u" || arg == "--upgrade")
{
options->upgrade = true;
}
else if (arg == "-f" || arg == "--file")
{
if (i == argc - 1)
{
options->error = true;
break;
}
options->keysFilename = argv[i + 1];
i++;
}
else if (arg == "-i" || arg == "--instid")
{
if (i == argc - 1)
{
options->error = true;
break;
}
options->instid = argv[i + 1];
options->applicationMode = MODE_CONFIRMATION_ID;
i++;
}
else if (arg == "-m" || arg == "--mode")
{
std::string mode = argv[i + 1];
char *p = &mode[0];
for (; *p; p++)
{
*p = toupper((unsigned char)*p);
}
p = &mode[0];
if (strcmp(p, "WINDOWS") == 0)
{
options->activationMode = WINDOWS;
}
else if (strcmp(p, "OFFICEXP") == 0)
{
options->activationMode = OFFICE_XP;
}
else if (strcmp(p, "OFFICE2K3") == 0)
{
options->activationMode = OFFICE_2K3;
}
else if (strcmp(p, "OFFICE2K7") == 0)
{
options->activationMode = OFFICE_2K7;
}
else if (strcmp(p, "PLUSDME") == 0)
{
options->activationMode = PLUS_DME;
}
i++;
}
else if (arg == "-p" || arg == "--productid")
{
if (i == argc - 1)
{
options->error = true;
break;
}
options->productid = argv[i + 1];
i++;
}
else if (arg == "-V" || arg == "--validate")
{
if (i == argc - 1)
{
options->error = true;
break;
}
options->keyToCheck = argv[i + 1];
options->applicationMode = MODE_BINK1998_VALIDATE;
i++;
}
else if (arg == "-N" || arg == "--nonewlines")
{
options->nonewlines = true;
}
else
{
options->error = true;
}
}
// make sure that a product id is entered for OFFICE_2K3 or OFFICE_2K7 IIDs
if ((options->activationMode == OFFICE_2K3 || options->activationMode == OFFICE_2K7) &&
(options->productid.empty() || options->instid.empty()))
{
return options->error = true;
}
return !options->error;
}
int CLI::validateCommandLine(Options *options, char *argv[], json *keys)
{
if (options->help || options->error)
{
if (options->error)
{
fmt::print("error parsing command line options\n");
}
showHelp(argv);
return 1;
}
if (options->verbose)
{
if (options->keysFilename.empty())
if (options.keysFilename.empty())
{
fmt::print("Loading internal keys file\n");
}
else
{
fmt::print("Loading keys file {}\n", options->keysFilename);
fmt::print("Loading keys file {}\n", options.keysFilename);
}
}
if (!loadJSON(options->keysFilename, keys))
if (!loadJSON(options.keysFilename))
{
return 2;
options.error = true;
return false;
}
if (options->verbose)
if (options.verbose)
{
if (options->keysFilename.empty())
if (options.keysFilename.empty())
{
fmt::print("Loaded internal keys file successfully\n");
}
else
{
fmt::print("Loaded keys from {} successfully\n", options->keysFilename);
fmt::print("Loaded keys from {} successfully\n", options.keysFilename);
}
}
if (options->list)
if (options.list)
{
for (auto const el : (*keys)["Products"].items())
for (auto const &i : keys["Products"].items())
{
auto el = i.value();
int id;
sscanf((el.value()["BINK"][0]).get<std::string>().c_str(), "%x", &id);
std::cout << el.key() << ": " << el.value()["BINK"] << std::endl;
sscanf(&(el["BINK"][0]).get<std::string>()[0], "%x", &id);
fmt::print("{}\n\tName: {}\n\tBINKs: ", i.key(), el["Name"].get<std::string>());
std::cout << el["BINK"] << std::endl << std::endl;
}
fmt::print("\n\n");
fmt::print("** Please note: any BINK ID other than 2E is considered experimental at this time **\n");
fmt::print("\n");
return 1;
return false;
}
int intBinkID;
sscanf(options->binkid.c_str(), "%x", &intBinkID);
DWORD intBinkID;
sscanf(&options.binkid[0], "%x", &intBinkID);
// FE and FF are BINK 1998, but do not generate valid keys, so we throw an error
if (intBinkID >= 0xFE)
{
fmt::print("ERROR: Terminal Services BINKs (FE and FF) are unsupported at this time\n");
return 1;
return false;
}
if (intBinkID >= 0x40)
{
// set bink2002 validate mode if in bink1998 validate mode, else set bink2002 generate mode
options->applicationMode =
(options->applicationMode == MODE_BINK1998_VALIDATE) ? MODE_BINK2002_VALIDATE : MODE_BINK2002_GENERATE;
options.state = (options.state == STATE_BINK1998_VALIDATE) ? STATE_BINK2002_VALIDATE : STATE_BINK2002_GENERATE;
}
if (options->channelID > 999)
{
fmt::print("ERROR: refusing to create a key with a Channel ID greater than 999\n");
return 1;
}
// don't allow any serial not between 0 and 999999
if (options->serial > 999999 || options->serial < 0)
{
fmt::print("ERROR: refusing to create a key with a Serial not between 000000 and 999999\n");
return 1;
}
return 0;
return true;
}
void CLI::printID(DWORD *pid)
{
char raw[12];
char b[6], c[8];
int i, digit = 0;
char raw[12], b[6], c[8];
char i, digit = 0;
// Convert PID to ascii-number (=raw)
snprintf(raw, sizeof(raw), "%09u", pid[0]);
@ -392,23 +188,33 @@ void CLI::printID(DWORD *pid)
c[6] = digit + '0';
c[7] = 0;
fmt::print("> Product ID: PPPPP-{}-{}-23xxx\n", b, c);
fmt::print("> Product ID: PPPPP-{}-{}-BBxxx\n", b, c);
}
void CLI::printKey(char *pk)
/**
*
* @param pk
*/
void CLI::printKey(std::string pk)
{
assert(strlen(pk) >= PK_LENGTH);
assert(pk.length() >= PK_LENGTH);
std::string spk = pk;
fmt::print("{}-{}-{}-{}-{}", spk.substr(0, 5), spk.substr(5, 5), spk.substr(10, 5), spk.substr(15, 5),
spk.substr(20, 5));
fmt::print("{}-{}-{}-{}-{}", pk.substr(0, 5), pk.substr(5, 5), pk.substr(10, 5), pk.substr(15, 5),
pk.substr(20, 5));
}
bool CLI::stripKey(const char *in_key, char out_key[PK_LENGTH])
/**
*
* @param in_key
* @param out_key
* @return
*/
BOOL CLI::stripKey(const std::string &in_key, std::string &out_key)
{
// copy out the product key stripping out extraneous characters
const char *p = in_key;
size_t i = 0;
const char *p = &in_key[0];
BYTE i = 0;
for (; *p; p++)
{
// strip out space or dash
@ -431,283 +237,388 @@ bool CLI::stripKey(const char *in_key, char out_key[PK_LENGTH])
}
}
}
// only return true if we've handled exactly PK_LENGTH chars
return (i == PK_LENGTH);
}
CLI::CLI(Options options, json keys)
/**
*
* @param pidgen3
* @return success
*/
BOOL CLI::InitPIDGEN3(PIDGEN3 *pidgen3)
{
this->options = options;
this->keys = keys;
if (!options.productCode.empty())
{
const char *productCode = &options.productCode[0];
auto product = keys["Products"][productCode];
this->BINKID = options.binkid.c_str();
if (options.verbose)
{
fmt::print("Selecting product: {}\n", productCode);
}
// 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).
this->privateKey = BN_new();
if (options.oem)
{
options.binkid = product["BINK"][1].get<std::string>();
}
else
{
options.binkid = product["BINK"][0].get<std::string>();
}
// 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.
this->genOrder = BN_new();
if (options.verbose)
{
fmt::print("Selected BINK: {}\n", options.binkid);
}
/* Computed data */
BN_dec2bn(&this->genOrder, this->keys["BINK"][this->BINKID]["n"].get<std::string>().c_str());
BN_dec2bn(&this->privateKey, this->keys["BINK"][this->BINKID]["priv"].get<std::string>().c_str());
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];
auto bink = keys["BINK"][BINKID];
if (options.verbose)
{
fmt::print("----------------------------------------------------------- \n");
fmt::print("Loaded the following elliptic curve parameters: BINK[{}]\n", this->BINKID);
fmt::print("Loaded the following elliptic curve parameters: BINK[{}]\n", BINKID);
fmt::print("----------------------------------------------------------- \n");
fmt::print(" P: {}\n", this->keys["BINK"][this->BINKID]["p"].get<std::string>());
fmt::print(" a: {}\n", this->keys["BINK"][this->BINKID]["a"].get<std::string>());
fmt::print(" b: {}\n", this->keys["BINK"][this->BINKID]["b"].get<std::string>());
fmt::print("Gx: {}\n", this->keys["BINK"][this->BINKID]["g"]["x"].get<std::string>());
fmt::print("Gy: {}\n", this->keys["BINK"][this->BINKID]["g"]["y"].get<std::string>());
fmt::print("Kx: {}\n", this->keys["BINK"][this->BINKID]["pub"]["x"].get<std::string>());
fmt::print("Ky: {}\n", this->keys["BINK"][this->BINKID]["pub"]["y"].get<std::string>());
fmt::print(" n: {}\n", this->keys["BINK"][this->BINKID]["n"].get<std::string>());
fmt::print(" k: {}\n", this->keys["BINK"][this->BINKID]["priv"].get<std::string>());
fmt::print(" P: {}\n", bink["p"].get<std::string>());
fmt::print(" a: {}\n", bink["a"].get<std::string>());
fmt::print(" b: {}\n", bink["b"].get<std::string>());
fmt::print("Gx: {}\n", bink["g"]["x"].get<std::string>());
fmt::print("Gy: {}\n", bink["g"]["y"].get<std::string>());
fmt::print("Kx: {}\n", bink["pub"]["x"].get<std::string>());
fmt::print("Ky: {}\n", bink["pub"]["y"].get<std::string>());
fmt::print(" n: {}\n", bink["n"].get<std::string>());
fmt::print(" k: {}\n", bink["priv"].get<std::string>());
fmt::print("\n");
}
eCurve = PIDGEN3::initializeEllipticCurve(this->keys["BINK"][this->BINKID]["p"].get<std::string>(),
this->keys["BINK"][this->BINKID]["a"].get<std::string>(),
this->keys["BINK"][this->BINKID]["b"].get<std::string>(),
this->keys["BINK"][this->BINKID]["g"]["x"].get<std::string>(),
this->keys["BINK"][this->BINKID]["g"]["y"].get<std::string>(),
this->keys["BINK"][this->BINKID]["pub"]["x"].get<std::string>(),
this->keys["BINK"][this->BINKID]["pub"]["y"].get<std::string>(),
this->genPoint, this->pubPoint);
pidgen3->LoadEllipticCurve(bink["p"].get<std::string>(), bink["a"].get<std::string>(), bink["b"].get<std::string>(),
bink["g"]["x"].get<std::string>(), bink["g"]["y"].get<std::string>(),
bink["pub"]["x"].get<std::string>(), bink["pub"]["y"].get<std::string>(),
bink["n"].get<std::string>(), bink["priv"].get<std::string>());
this->count = 0;
this->total = this->options.numKeys;
pidgen3->setChannelID(options.channelID);
if (options.verbose)
{
fmt::print("> Channel ID: {:03d}\n", options.channelID);
}
if (options.serialSet)
{
pidgen3->setSerial(options.serial);
if (options.verbose)
{
fmt::print("> Serial {:#09d}\n", options.serial);
}
}
return true;
}
int CLI::BINK1998Generate()
/**
*
* @param confid
* @return success
*/
BOOL CLI::InitConfirmationID(ConfirmationID *confid)
{
return true;
}
/**
*
* @return success
*/
BOOL CLI::BINK1998Generate()
{
auto bink1998 = BINK1998();
BOOL retval = InitPIDGEN3(&bink1998);
if (!retval)
{
return retval;
}
// raw PID/serial value
DWORD nRaw = this->options.channelID * 1'000'000; /* <- change */
DWORD nRaw = options.channelID * 1'000'000;
// using user-provided serial
if (this->options.serialSet)
if (options.serialSet)
{
// just in case, make sure it's less than 999999
int serialRnd = (this->options.serial % 999999);
int serialRnd = (options.serial % 999999);
nRaw += serialRnd;
}
else
{
// generate a random number to use as a serial
BIGNUM *bnrand = BN_new();
BN_rand(bnrand, 19, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY);
int oRaw;
char *cRaw = BN_bn2dec(bnrand);
sscanf(cRaw, "%d", &oRaw);
auto oRaw = UMSKT::getRandom<DWORD>();
nRaw += (oRaw % 999999); // ensure our serial is less than 999999
BN_free(bnrand);
}
if (this->options.verbose)
if (options.verbose)
{
// print the resulting Product ID
// PID value is printed in BINK1998::Generate
printID(&nRaw);
}
// generate a key
BN_sub(this->privateKey, this->genOrder, this->privateKey);
for (int i = 0; i < this->total; i++)
for (int i = 0; i < total; i++)
{
PIDGEN3::BINK1998::Generate(this->eCurve, this->genPoint, this->genOrder, this->privateKey, nRaw,
options.upgrade, this->pKey);
bink1998.Generate(pKey);
bool isValid = PIDGEN3::BINK1998::Verify(this->eCurve, this->genPoint, this->pubPoint, this->pKey);
bool isValid = bink1998.Verify(pKey);
if (isValid)
{
CLI::printKey(this->pKey);
if (i < this->total - 1 || this->options.verbose)
CLI::printKey(pKey);
if (i < total - 1 || options.verbose)
{
fmt::print("\n");
}
this->count += isValid;
count += isValid;
}
else
{
if (this->options.verbose)
if (options.verbose)
{
CLI::printKey(this->pKey);
CLI::printKey(pKey);
fmt::print(" [Invalid]");
if (i < this->total - 1)
if (i < total - 1)
{
fmt::print("\n");
}
}
this->total++; // queue a redo, basically
total++; // queue a redo, basically
}
}
if (this->options.verbose)
if (options.verbose)
{
fmt::print("\nSuccess count: {}/{}", this->count, this->total);
fmt::print("\nSuccess count: {}/{}\n", count, total);
}
if (!options.nonewlines)
{
fmt::print("\n");
}
return 0;
return true;
}
int CLI::BINK2002Generate()
/**
*
* @return success
*/
BOOL CLI::BINK2002Generate()
{
DWORD pChannelID = this->options.channelID;
if (this->options.verbose)
{
fmt::print("> Channel ID: {:03d}\n", this->options.channelID);
}
auto bink2002 = BINK2002();
InitPIDGEN3(&bink2002);
// generate a key
for (int i = 0; i < this->total; i++)
for (int i = 0; i < total; i++)
{
DWORD pAuthInfo;
RAND_bytes((BYTE *)&pAuthInfo, 4);
pAuthInfo &= BITMASK(10);
if (this->options.verbose)
if (options.verbose)
{
fmt::print("> AuthInfo: {}\n", pAuthInfo);
}
PIDGEN3::BINK2002::Generate(this->eCurve, this->genPoint, this->genOrder, this->privateKey, pChannelID,
pAuthInfo, options.upgrade, this->pKey);
bink2002.Generate(pKey);
bool isValid = PIDGEN3::BINK2002::Verify(this->eCurve, this->genPoint, this->pubPoint, this->pKey);
bool isValid = bink2002.Verify(pKey);
if (isValid)
{
CLI::printKey(this->pKey);
if (i < this->total - 1 || this->options.verbose)
CLI::printKey(pKey);
if (i < total - 1 || options.verbose)
{ // check if end of list or verbose
fmt::print("\n");
}
this->count += isValid; // add to count
count += isValid; // add to count
}
else
{
if (this->options.verbose)
if (options.verbose)
{
CLI::printKey(this->pKey); // print the key
fmt::print(" [Invalid]"); // and add " [Invalid]" to the key
CLI::printKey(pKey); // print the key
fmt::print(" [Invalid]"); // and add " [Invalid]" to the key
if (i < this->total - 1)
{ // check if end of list
fmt::print("\n");
}
}
this->total++; // queue a redo, basically
total++; // queue a redo, basically
}
}
if (this->options.verbose)
if (options.verbose)
{
fmt::print("\nSuccess count: {}/{}", this->count, this->total);
fmt::print("\nSuccess count: {}/{}\n", count, total);
}
if (!this->options.nonewlines)
{
fmt::print("\n");
}
return 0;
return true;
}
int CLI::BINK1998Validate()
/**
*
* @return success
*/
BOOL CLI::BINK1998Validate()
{
char product_key[PK_LENGTH]{};
auto bink1998 = BINK1998();
InitPIDGEN3(&bink1998);
if (!CLI::stripKey(this->options.keyToCheck.c_str(), product_key))
std::string product_key;
if (!CLI::stripKey(options.keyToCheck, product_key))
{
fmt::print("ERROR: Product key is in an incorrect format!\n");
return 1;
return false;
}
CLI::printKey(product_key);
fmt::print("\n");
if (!PIDGEN3::BINK1998::Verify(this->eCurve, this->genPoint, this->pubPoint, product_key))
if (!bink1998.Verify(product_key))
{
fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n");
return 1;
return false;
}
fmt::print("Key validated successfully!\n");
return 0;
return true;
}
int CLI::BINK2002Validate()
/**
*
* @return success
*/
BOOL CLI::BINK2002Validate()
{
char product_key[PK_LENGTH]{};
auto bink2002 = BINK2002();
InitPIDGEN3(&bink2002);
if (!CLI::stripKey(this->options.keyToCheck.c_str(), product_key))
std::string product_key;
if (!CLI::stripKey(options.keyToCheck, product_key))
{
fmt::print("ERROR: Product key is in an incorrect format!\n");
return 1;
return false;
}
CLI::printKey(product_key);
fmt::print("\n");
if (!PIDGEN3::BINK2002::Verify(this->eCurve, this->genPoint, this->pubPoint, product_key))
if (!bink2002.Verify(product_key))
{
fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n");
return 1;
return false;
}
fmt::print("Key validated successfully!\n");
return 0;
return true;
}
int CLI::ConfirmationID()
/**
*
* @return success
*/
BOOL CLI::ConfirmationIDGenerate()
{
char confirmation_id[49];
std::string confirmation_id;
auto confid = new class ConfirmationID();
int err = confid->Generate(this->options.instid.c_str(), confirmation_id, options.productid);
auto confid = ConfirmationID();
int err = confid.Generate(options.instid, confirmation_id, options.productid);
if (err == SUCCESS)
{
fmt::print(confirmation_id);
if (!this->options.nonewlines)
{
fmt::print("\n");
}
return 0;
fmt::print("{}\n", confirmation_id);
return true;
}
switch (err)
{
case ERR_TOO_SHORT:
fmt::print("ERROR: Installation ID is too short.\n");
break;
case ERR_TOO_LARGE:
fmt::print("ERROR: Installation ID is too long.\n");
break;
case ERR_INVALID_CHARACTER:
fmt::print("ERROR: Invalid character in installation ID.\n");
break;
case ERR_INVALID_CHECK_DIGIT:
fmt::print("ERROR: Installation ID checksum failed. Please check that it is typed correctly.\n");
break;
case ERR_UNKNOWN_VERSION:
fmt::print("ERROR: Unknown installation ID version.\n");
break;
case ERR_UNLUCKY:
fmt::print("ERROR: Unable to generate valid confirmation ID.\n");
break;
default:
fmt::print("Unknown error occurred during Confirmation ID generation: {}\n", err);
break;
}
return 1;
return false;
}
/**
*
* @return application status code
*/
int CLI::Run()
{
BINK1998Generate();
/*
switch (state)
{
case STATE_BINK1998_GENERATE:
return BINK1998Generate();
case STATE_BINK2002_GENERATE:
return BINK2002Generate();
case STATE_BINK1998_VALIDATE:
return BINK1998Validate();
case STATE_BINK2002_VALIDATE:
return BINK2002Validate();
case STATE_CONFIRMATION_ID:
return ConfirmationIDGenerate();
default:
return 1;
}
*/
return 0;
}

128
src/cli.h
View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,16 +16,28 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/6/2023
* @FileCreated by Neo on 06/06/2023
* @Maintainer Neo
*/
#ifndef UMSKT_CLI_H
#define UMSKT_CLI_H
#include "header.h"
#include "typedefs.h"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <cmrc/cmrc.hpp>
#include <fmt/core.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
namespace fs = std::filesystem;
#include "libumskt/confid/confid.h"
#include "libumskt/libumskt.h"
@ -33,68 +45,100 @@
#include "libumskt/pidgen3/BINK1998.h"
#include "libumskt/pidgen3/BINK2002.h"
#include "libumskt/pidgen3/PIDGEN3.h"
#include "options.h"
CMRC_DECLARE(umskt);
enum MODE
enum APPLICATION_STATE
{
MODE_BINK1998_GENERATE = 0,
MODE_BINK2002_GENERATE = 1,
MODE_CONFIRMATION_ID = 2,
MODE_BINK1998_VALIDATE = 3,
MODE_BINK2002_VALIDATE = 4,
STATE_BINK1998_GENERATE,
STATE_BINK2002_GENERATE,
STATE_CONFIRMATION_ID,
STATE_BINK1998_VALIDATE,
STATE_BINK2002_VALIDATE
};
struct Options
{
int argc;
char **argv;
std::string binkid;
std::string keysFilename;
std::string instid;
std::string keyToCheck;
std::string productid;
int channelID;
int serial;
int numKeys;
bool upgrade;
bool serialSet;
bool verbose;
bool help;
bool error;
bool list;
bool nonewlines;
std::string authInfo;
std::string productCode;
MODE applicationMode;
ACTIVATION_ALGORITHM activationMode;
DWORD channelID;
DWORD serial;
DWORD numKeys;
BOOL oem;
BOOL upgrade;
BOOL serialSet;
BOOL verbose;
BOOL help;
BOOL error;
BOOL list;
APPLICATION_STATE state;
};
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;
std::string pKey;
DWORD count, total;
static Options options;
public:
CLI(Options options, json keys);
~CLI();
CLI()
{
count = 0;
total = options.numKeys;
}
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 std::array<CLIHelpOptions, CLIHelpOptionID_END> helpOptions;
static json keys;
static BYTE Init(int argv, char *argc[]);
static void SetHelpText();
static CLIHandlerFunc loadJSON;
static CLIHandlerFunc DisplayHelp;
static CLIHandlerFunc DisplayErrorMessage;
static CLIHandlerFunc SetVerboseOption;
static CLIHandlerFunc SetDebugOption;
static CLIHandlerFunc SetListOption;
static CLIHandlerFunc SetOEMOption;
static CLIHandlerFunc SetUpgradeOption;
static CLIHandlerFunc SetFileOption;
static CLIHandlerFunc SetNumberOption;
static CLIHandlerFunc SetChannelIDOption;
static CLIHandlerFunc SetBINKOption;
static CLIHandlerFunc SetSerialOption;
static CLIHandlerFunc SetActivationIDOption;
static CLIHandlerFunc SetProductIDOption;
static CLIHandlerFunc SetValidateOption;
static CLIHandlerFunc SetProductCodeOption;
static BOOL parseCommandLine();
static BOOL processOptions();
static void printID(DWORD *pid);
static void printKey(char *pk);
static bool stripKey(const char *in_key, char out_key[PK_LENGTH]);
static void printKey(std::string pk);
static BOOL stripKey(const std::string &in_key, std::string &out_key);
int BINK1998Generate();
int BINK2002Generate();
int BINK1998Validate();
int BINK2002Validate();
int ConfirmationID();
BOOL InitPIDGEN3(PIDGEN3 *pidgen3);
BOOL InitConfirmationID(ConfirmationID *confid);
BOOL BINK1998Generate();
BOOL BINK2002Generate();
BOOL BINK1998Validate();
BOOL BINK2002Validate();
BOOL ConfirmationIDGenerate();
int Run();
};
#endif // UMSKT_CLI_H

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -29,74 +29,59 @@
#include "confid.h"
void ConfirmationID::setMod(QWORD mod)
BOOL ConfirmationID::LoadHyperellipticCurve(QWORD x0, QWORD x1, QWORD x2, QWORD x3, QWORD x4, QWORD x5, Q_OWORD priv,
QWORD modulous, QWORD nonresidue, BOOL isOffice, BOOL isXPBrand,
BYTE flagVersion)
{
MOD = mod;
}
curve[0] = x0;
curve[1] = x1;
curve[2] = x2;
curve[3] = x3;
curve[4] = x4;
curve[5] = x5;
void ConfirmationID::setNonResidue(QWORD nonResidue)
{
NON_RESIDUE = nonResidue;
}
memcpy(&privateKey, &priv, sizeof(Q_OWORD));
void ConfirmationID::setPValues(QWORD p0, QWORD p1, QWORD p2, QWORD p3)
{
p[0] = p0;
p[1] = p1;
p[2] = p2;
p[3] = p3;
}
void ConfirmationID::setPValues(QWORD pValues[4])
{
memcpy(p, pValues, sizeof(*pValues * 4));
}
void ConfirmationID::setFValues(QWORD f0, QWORD f1, QWORD f2, QWORD f3, QWORD f4, QWORD f5)
{
f[0] = f0;
f[1] = f1;
f[2] = f2;
f[3] = f3;
f[4] = f4;
f[5] = f5;
}
void ConfirmationID::setFValues(QWORD fValues[6])
{
memcpy(p, fValues, sizeof(*fValues * 6));
}
void ConfirmationID::setIsOffice(BOOL isOffice)
{
MOD = modulous;
NON_RESIDUE = nonresidue;
this->isOffice = isOffice;
this->isXPBrand = isXPBrand;
this->flagVersion = flagVersion;
return true;
}
void ConfirmationID::setIsXPBrand(BOOL isXpBrand)
BOOL ConfirmationID::LoadHyperellipticCurve(QWORD *f, Q_OWORD priv, QWORD modulous, QWORD nonresidue, BOOL isOffice,
BOOL isXPBrand, BYTE flagVersion)
{
this->isXPBrand = isXpBrand;
memcpy(&curve, f, sizeof(curve));
memcpy(&privateKey, &priv, sizeof(Q_OWORD));
MOD = modulous;
NON_RESIDUE = nonresidue;
this->isOffice = isOffice;
this->isXPBrand = isXPBrand;
this->flagVersion = flagVersion;
return true;
}
void ConfirmationID::setFlagVersion(unsigned int flagVersion)
DWORD ConfirmationID::calculateCheckDigit(DWORD pid)
{
ConfirmationID::flagVersion = flagVersion;
}
int ConfirmationID::calculateCheckDigit(int pid)
{
unsigned int i = 0, j = 0, k = 0;
DWORD i = 0, j = 0, k = 0;
for (j = pid; j; i += k)
{
k = j % 10;
j /= 10;
}
return ((10 * pid) - (i % 7)) + 7;
}
void ConfirmationID::decode_iid_new_version(unsigned char *iid, unsigned char *hwid, int *version)
void ConfirmationID::decode_iid_new_version(BYTE *iid, BYTE *hwid, DWORD *version)
{
QWORD buffer[5];
for (int i = 0; i < 5; i++)
for (BYTE i = 0; i < 5; i++)
{
memcpy(&buffer[i], (iid + (4 * i)), 4);
}
@ -104,7 +89,7 @@ void ConfirmationID::decode_iid_new_version(unsigned char *iid, unsigned char *h
DWORD v1 = (buffer[3] & 0xFFFFFFF8) | 2;
DWORD v2 = ((buffer[3] & 7) << 29) | (buffer[2] >> 3);
QWORD hardwareIDVal = ((QWORD)v1 << 32) | v2;
for (int i = 0; i < 8; ++i)
for (BYTE i = 0; i < 8; ++i)
{
hwid[i] = (hardwareIDVal >> (8 * i)) & 0xFF;
}
@ -112,13 +97,13 @@ void ConfirmationID::decode_iid_new_version(unsigned char *iid, unsigned char *h
*version = buffer[0] & 7;
}
void ConfirmationID::Mix(unsigned char *buffer, size_t bufSize, const unsigned char *key, size_t keySize)
void ConfirmationID::Mix(BYTE *buffer, BYTE bufSize, const BYTE *key, BYTE keySize)
{
unsigned char sha1_input[64], sha1_result[20];
size_t half = bufSize / 2;
BYTE sha1_input[64], sha1_result[20];
BYTE half = bufSize / 2;
// assert(half <= sizeof(sha1_result) && half + keySize <= sizeof(sha1_input) - 9);
for (int external_counter = 0; external_counter < 4; external_counter++)
for (BYTE external_counter = 0; external_counter < 4; external_counter++)
{
memset(sha1_input, 0, sizeof(sha1_input));
@ -144,12 +129,12 @@ void ConfirmationID::Mix(unsigned char *buffer, size_t bufSize, const unsigned c
SHA1(sha1_input, sizeof(sha1_input), sha1_result);
for (size_t i = half & ~3; i < half; i++)
for (BYTE i = half & ~3; i < half; i++)
{
sha1_result[i] = sha1_result[i + 4 - (half & 3)];
}
for (size_t i = 0; i < half; i++)
for (BYTE i = 0; i < half; i++)
{
unsigned char tmp = buffer[i + half];
buffer[i + half] = buffer[i] ^ sha1_result[i];
@ -158,14 +143,13 @@ void ConfirmationID::Mix(unsigned char *buffer, size_t bufSize, const unsigned c
}
}
void ConfirmationID::Unmix(unsigned char *buffer, size_t bufSize, const unsigned char key[4], size_t keySize)
void ConfirmationID::Unmix(BYTE *buffer, BYTE bufSize, const BYTE key[4], BYTE keySize)
{
unsigned char sha1_input[64];
unsigned char sha1_result[20];
size_t half = bufSize / 2;
BYTE sha1_input[64], sha1_result[20];
BYTE half = bufSize / 2;
// assert(half <= sizeof(sha1_result) && half + keySize <= sizeof(sha1_input) - 9);
for (int external_counter = 0; external_counter < 4; external_counter++)
for (BYTE external_counter = 0; external_counter < 4; external_counter++)
{
memset(sha1_input, 0, sizeof(sha1_input));
@ -189,12 +173,12 @@ void ConfirmationID::Unmix(unsigned char *buffer, size_t bufSize, const unsigned
SHA1(sha1_input, sizeof(sha1_input), sha1_result);
for (size_t i = half & ~3; i < half; i++)
for (BYTE i = half & ~3; i < half; i++)
{
sha1_result[i] = sha1_result[i + 4 - (half & 3)];
}
for (size_t i = 0; i < half; i++)
for (BYTE i = 0; i < half; i++)
{
unsigned char tmp = buffer[i];
buffer[i] = buffer[i + half] ^ sha1_result[i];
@ -203,20 +187,31 @@ void ConfirmationID::Unmix(unsigned char *buffer, size_t bufSize, const unsigned
}
}
int ConfirmationID::Generate(const char *installation_id_str, char confirmation_id[49], std::string productid)
/**
*
* @param installationIDIn
* @param confirmationIDOut
* @param productIDIn
* @return
*/
DWORD ConfirmationID::Generate(const std::string &installationIDIn, std::string &confirmationIDOut,
std::string &productIDIn)
{
int version;
unsigned char hardwareID[8];
unsigned char installation_id[19]; // 10**45 < 256**19
unsigned char productID[4];
DWORD version;
BYTE hardwareID[8];
BYTE installation_id[19]; // 10**45 < 256**19
BYTE productID[4];
size_t installation_id_len = 0;
const char *pid = installation_id_str;
BYTE installation_id_len = 0;
auto pid = installationIDIn.c_str();
size_t count = 0, totalCount = 0;
BYTE count = 0, totalCount = 0;
unsigned check = 0;
size_t i;
BYTE i;
Q_OWORD mod_inv;
memcpy(&mod_inv, &privateKey, sizeof(mod_inv));
for (; *pid; pid++)
{
@ -232,7 +227,7 @@ int ConfirmationID::Generate(const char *installation_id_str, char confirmation_
return ERR_INVALID_CHARACTER;
}
if (count == 5 || p[1] == 0)
if (count == 5 || mod_inv.qword[0] == 0)
{
if (!count)
{
@ -295,8 +290,8 @@ int ConfirmationID::Generate(const char *installation_id_str, char confirmation_
{
QWORD HardwareID;
QWORD ProductIDLow;
unsigned char ProductIDHigh;
unsigned short KeySHA1;
BYTE ProductIDHigh;
WORD KeySHA1;
} parsed;
#pragma pack(pop)
@ -331,9 +326,9 @@ int ConfirmationID::Generate(const char *installation_id_str, char confirmation_
}
memcpy(&parsed, hardwareID, 8);
productID[0] = stoi(productid.substr(0, 5));
productID[0] = stoi(productIDIn.substr(0, 5));
std::string channelid = productid.substr(6, 3);
auto channelid = productIDIn.substr(6, 3);
char *p = &channelid[0];
for (; *p; p++)
{
@ -342,21 +337,21 @@ int ConfirmationID::Generate(const char *installation_id_str, char confirmation_
if (strcmp(&channelid[0], "OEM") == 0)
{
productID[1] = stoi(productid.substr(12, 3));
productID[2] = (stoi(productid.substr(15, 1)) * 100000) + stoi(productid.substr(18, 5));
productID[1] = stoi(productIDIn.substr(12, 3));
productID[2] = (stoi(productIDIn.substr(15, 1)) * 100000) + stoi(productIDIn.substr(18, 5));
productID[2] = calculateCheckDigit(productID[2]);
productID[3] = ((stoi(productid.substr(10, 2))) * 1000) + productID[3];
productID[3] = ((stoi(productIDIn.substr(10, 2))) * 1000) + productID[3];
}
else
{
productID[1] = stoi(productid.substr(6, 3));
productID[2] = stoi(productid.substr(10, 7));
productID[3] = stoi(productid.substr(18, 5));
productID[1] = stoi(productIDIn.substr(6, 3));
productID[2] = stoi(productIDIn.substr(10, 7));
productID[3] = stoi(productIDIn.substr(18, 5));
}
// fmt::print("ProductID: {}-{}-{}-{} \n", productID[0], productID[1], productID[2], productID[3]);
}
unsigned char keybuf[16];
BYTE keybuf[16];
memcpy(keybuf, &parsed.HardwareID, 8);
QWORD productIdMixed =
@ -364,34 +359,25 @@ int ConfirmationID::Generate(const char *installation_id_str, char confirmation_
memcpy(keybuf + 8, &productIdMixed, 8);
TDivisor d;
unsigned char attempt;
BYTE attempt;
union {
unsigned char buffer[14];
struct
{
QWORD lo;
QWORD hi;
};
} ulowhi;
Q_OWORD ulowhi;
memset(&ulowhi, 0, sizeof(ulowhi));
for (attempt = 0; attempt <= 0x80; attempt++)
{
ulowhi.lo = this->u[0];
ulowhi.hi = this->u[1];
if (isXPBrand)
{
ulowhi.buffer[7] = attempt;
ulowhi.byte[7] = attempt;
}
else if (isOffice)
{
ulowhi.buffer[6] = attempt;
ulowhi.byte[6] = attempt;
}
Mix(ulowhi.buffer, 14, keybuf, 16);
QWORD x2 = residue->ui128_quotient_mod(ulowhi.lo, ulowhi.hi);
QWORD x1 = ulowhi.lo - x2 * MOD;
Mix(ulowhi.byte, 14, keybuf, 16);
QWORD x2 = residue->ui128_quotient_mod(ulowhi.qword[0], ulowhi.qword[1]);
QWORD x1 = ulowhi.qword[0] - x2 * MOD;
x2++;
d.u[0] = residue->sub(residue->mul(x1, x1), residue->mul(NON_RESIDUE, residue->mul(x2, x2)));
@ -407,31 +393,26 @@ int ConfirmationID::Generate(const char *installation_id_str, char confirmation_
return ERR_UNLUCKY;
}
divisor->mul128(&d, u[0], u[1], &d);
Q_OWORD priv;
memcpy(&priv, &privateKey, sizeof(priv));
union {
struct
{
QWORD encoded_lo, encoded_hi;
};
struct
{
uint32_t encoded[4];
};
} e;
divisor->mul128(&d, priv.qword[0], priv.qword[1], &d);
Q_OWORD e;
memset(&e, 0, sizeof(e));
if (d.u[0] == BAD)
{
// we can not get the zero divisor, actually...
e.encoded_lo = residue->__umul128(MOD + 2, MOD, &e.encoded_hi);
e.qword[0] = residue->__umul128(MOD + 2, MOD, &e.qword[1]);
}
else if (d.u[1] == BAD)
{
// O(1/MOD) chance
// encoded = (unsigned __int128)(MOD + 1) * d.u[0] + MOD; // * MOD + d.u[0] is fine too
e.encoded_lo = residue->__umul128(MOD + 1, d.u[0], &e.encoded_hi);
e.encoded_lo += MOD;
e.encoded_hi += (e.encoded_lo < MOD);
e.qword[0] = residue->__umul128(MOD + 1, d.u[0], &e.qword[1]);
e.qword[0] += MOD;
e.qword[1] += (e.qword[0] < MOD);
}
else
{
@ -443,9 +424,9 @@ int ConfirmationID::Generate(const char *installation_id_str, char confirmation_
{
x2 = residue->sqrt(residue->mul(x2sqr, residue->inv(NON_RESIDUE)));
assert(x2 != BAD);
e.encoded_lo = residue->__umul128(MOD + 1, MOD + x2, &e.encoded_hi);
e.encoded_lo += x1;
e.encoded_hi += (e.encoded_lo < x1);
e.qword[0] = residue->__umul128(MOD + 1, MOD + x2, &e.qword[1]);
e.qword[0] += x1;
e.qword[1] += (e.qword[0] < x1);
}
else
{
@ -468,28 +449,34 @@ int ConfirmationID::Generate(const char *installation_id_str, char confirmation_
x2a = tmp;
}
e.encoded_lo = residue->__umul128(MOD + 1, x1a, &e.encoded_hi);
e.encoded_lo += x2a;
e.encoded_hi += (e.encoded_lo < x2a);
e.qword[0] = residue->__umul128(MOD + 1, x1a, &e.qword[1]);
e.qword[0] += x2a;
e.qword[1] += (e.qword[0] < x2a);
}
}
unsigned char decimal[35];
BYTE decimal[35];
for (i = 0; i < 35; i++)
{
unsigned c = e.encoded[3] % 10;
e.encoded[3] /= 10;
unsigned c2 = ((QWORD)c << 32 | e.encoded[2]) % 10;
e.encoded[2] = ((QWORD)c << 32 | e.encoded[2]) / 10;
unsigned c3 = ((QWORD)c2 << 32 | e.encoded[1]) % 10;
e.encoded[1] = ((QWORD)c2 << 32 | e.encoded[1]) / 10;
unsigned c4 = ((QWORD)c3 << 32 | e.encoded[0]) % 10;
e.encoded[0] = ((QWORD)c3 << 32 | e.encoded[0]) / 10;
unsigned c = e.byte[3] % 10;
e.byte[3] /= 10;
unsigned c2 = ((QWORD)c << 32 | e.byte[2]) % 10;
e.byte[2] = ((QWORD)c << 32 | e.byte[2]) / 10;
unsigned c3 = ((QWORD)c2 << 32 | e.byte[1]) % 10;
e.byte[1] = ((QWORD)c2 << 32 | e.byte[1]) / 10;
unsigned c4 = ((QWORD)c3 << 32 | e.byte[0]) % 10;
e.byte[0] = ((QWORD)c3 << 32 | e.byte[0]) / 10;
decimal[34 - i] = c4;
}
assert(e.encoded[0] == 0 && e.encoded[1] == 0 && e.encoded[2] == 0 && e.encoded[3] == 0);
char *q = confirmation_id;
char *q = &confirmationIDOut[0];
for (i = 0; i < 7; i++)
{
if (i)
@ -506,6 +493,6 @@ int ConfirmationID::Generate(const char *installation_id_str, char confirmation_
q[5] = ((p[0] + p[1] * 2 + p[2] + p[3] * 2 + p[4]) % 7) + '0';
q += 6;
}
*q++ = 0;
return 0;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/6/2023
* @FileCreated by Neo on 06/06/2023
* @Maintainer Neo
*/
@ -45,121 +45,103 @@ typedef struct
QWORD v[2];
} TDivisor;
enum ACTIVATION_ALGORITHM
{
WINDOWS = 0,
OFFICE_XP = 1,
OFFICE_2K3 = 2,
OFFICE_2K7 = 3,
PLUS_DME = 4,
};
EXPORT class ConfirmationID
class ConfirmationID
{
QWORD MOD = 0, NON_RESIDUE = 0;
QWORD f[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
QWORD p[4] = {0x0, 0x0, 0x0, 0x0};
QWORD u[2] = {0x0, 0x0};
QWORD curve[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
Q_OWORD privateKey;
unsigned char iid_key[4] = {0x0, 0x0, 0x0, 0x0};
BYTE iid_key[4] = {0x0, 0x0, 0x0, 0x0};
BOOL isOffice = false, isXPBrand = false;
unsigned flagVersion = 0;
public:
void setFlagVersion(unsigned int flagVersion);
DWORD calculateCheckDigit(DWORD pid);
void decode_iid_new_version(BYTE *iid, BYTE *hwid, DWORD *version);
void Mix(BYTE *buffer, BYTE bufSize, const BYTE *key, BYTE keySize);
void Unmix(BYTE *buffer, BYTE bufSize, const BYTE *key, BYTE keySize);
private:
int calculateCheckDigit(int pid);
void decode_iid_new_version(unsigned char *iid, unsigned char *hwid, int *version);
void Mix(unsigned char *buffer, size_t bufSize, const unsigned char *key, size_t keySize);
void Unmix(unsigned char *buffer, size_t bufSize, const unsigned char *key, size_t keySize);
class Divisor
{
ConfirmationID *parent;
friend class Residue;
Residue *residue;
friend class Polynomial;
Polynomial *polynomial;
public:
explicit Divisor(ConfirmationID *p)
{
parent = p;
}
int find_divisor_v(TDivisor *d);
void add(const TDivisor *src1, const TDivisor *src2, TDivisor *dst);
void mul(const TDivisor *src, QWORD mult, TDivisor *dst);
void mul128(const TDivisor *src, QWORD mult_lo, QWORD mult_hi, TDivisor *dst);
int u2poly(const TDivisor *src, QWORD polyu[3], QWORD polyv[2]);
};
friend class Divisor;
class Residue
{
ConfirmationID *parent;
public:
explicit Residue(ConfirmationID *p)
{
parent = p;
}
QWORD add(QWORD x, QWORD y);
QWORD sub(QWORD x, QWORD y);
QWORD __umul128(QWORD a, QWORD b, QWORD *hi);
QWORD ui128_quotient_mod(QWORD lo, QWORD hi);
QWORD mul(QWORD x, QWORD y);
QWORD pow(QWORD x, QWORD y);
QWORD inverse(QWORD u, QWORD v);
QWORD inv(QWORD x);
QWORD sqrt(QWORD what);
};
friend class Residue;
class Polynomial
{
ConfirmationID *parent;
public:
explicit Polynomial(ConfirmationID *p)
{
parent = p;
}
int mul(int adeg, const QWORD a[], int bdeg, const QWORD b[], int resultprevdeg, QWORD result[]);
int div_monic(int adeg, QWORD a[], int bdeg, const QWORD b[], QWORD *quotient);
void 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]);
};
friend class Polynomial;
Residue *residue;
Polynomial *polynomial;
Divisor *divisor;
public:
int Generate(const char *installation_id_str, char confirmation_id[49], std::string productid);
void setMod(QWORD mod);
void setNonResidue(QWORD nonResidue);
void setPValues(QWORD p0, QWORD p1, QWORD p2, QWORD p3);
void setPValues(QWORD pValues[4]);
void setFValues(QWORD f0, QWORD f1, QWORD f2, QWORD f3, QWORD f4, QWORD f5);
void setFValues(QWORD fValues[6]);
void setIsOffice(BOOL isOffice);
void setIsXPBrand(BOOL isXpBrand);
ConfirmationID()
{
residue = new Residue(this);
polynomial = new Polynomial(this);
divisor = new Divisor(this);
privateKey.qword[0] = privateKey.qword[1] = 0x00;
}
BOOL LoadHyperellipticCurve(QWORD x0, QWORD x1, QWORD x2, QWORD x3, QWORD x4, QWORD x5, Q_OWORD priv,
QWORD modulous, QWORD nonresidue, BOOL isOffice, BOOL isXPBrand, BYTE flagVersion);
BOOL LoadHyperellipticCurve(QWORD *f, Q_OWORD priv, QWORD modulous, QWORD nonresidue, BOOL isOffice, BOOL isXPBrand,
BYTE flagVersion);
DWORD Generate(const std::string &installation_id_str, std::string &confirmation_id, std::string &productid);
~ConfirmationID()
{
delete residue, polynomial, divisor;
}
};
class Residue
{
ConfirmationID *parent;
public:
explicit Residue(ConfirmationID *in)
{
parent = in;
}
QWORD add(QWORD x, QWORD y);
QWORD sub(QWORD x, QWORD y);
QWORD __umul128(QWORD a, QWORD b, QWORD *hi);
QWORD ui128_quotient_mod(QWORD lo, QWORD hi);
QWORD mul(QWORD x, QWORD y);
QWORD pow(QWORD x, QWORD y);
QWORD inverse(QWORD u, QWORD v);
QWORD inv(QWORD x);
QWORD sqrt(QWORD what);
};
class Polynomial
{
ConfirmationID *parent;
public:
explicit Polynomial(ConfirmationID *in)
{
parent = in;
}
int mul(int adeg, const QWORD a[], int bdeg, const QWORD b[], int resultprevdeg, QWORD result[]);
int div_monic(int adeg, QWORD a[], int bdeg, const QWORD b[], QWORD *quotient);
void 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 u2poly(const TDivisor *src, QWORD polyu[3], QWORD polyv[2]);
};
class Divisor
{
ConfirmationID *parent;
public:
explicit Divisor(ConfirmationID *in)
{
parent = in;
}
int find_divisor_v(TDivisor *d);
void add(const TDivisor *src1, const TDivisor *src2, TDivisor *dst);
void mul(const TDivisor *src, QWORD mult, TDivisor *dst);
void mul128(const TDivisor *src, QWORD mult_lo, QWORD mult_hi, TDivisor *dst);
};
#endif // UMSKT_CONFID_H

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -22,21 +22,20 @@
#include "confid.h"
int Divisor::find_divisor_v(TDivisor *d)
int ConfirmationID::ConfirmationID::Divisor::find_divisor_v(TDivisor *d)
{
// u | v^2 - f
// u | v^2 - curve
// u = u0 + u1*x + x^2
// f%u = f0 + f1*x
// curve%u = f0 + f1*x
QWORD v1, f2[6];
for (int i = 0; i < 6; i++)
for (BYTE i = 0; i < 6; i++)
{
f2[i] = parent->f[i];
f2[i] = parent->curve[i];
}
const QWORD u0 = d->u[0];
const QWORD u1 = d->u[1];
for (int j = 4; j--;)
const QWORD u0 = d->u[0], u1 = d->u[1];
for (BYTE j = 4; j--;)
{
f2[j] = parent->residue->sub(f2[j], parent->residue->mul(u0, f2[j + 2]));
f2[j + 1] = parent->residue->sub(f2[j + 1], parent->residue->mul(u1, f2[j + 2]));
@ -50,8 +49,7 @@ int Divisor::find_divisor_v(TDivisor *d)
// 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
// v1^2 = ((2*f0-f1*u1) +- 2*sqrt(-f0*f1*u1 + f0^2 + f1^2*u0))) / (u1^2-4*u0)
const QWORD f0 = f2[0];
const QWORD f1 = f2[1];
const QWORD f0 = f2[0], f1 = f2[1];
const QWORD u0double = parent->residue->add(u0, u0);
const QWORD coeff2 = parent->residue->sub(parent->residue->mul(u1, u1), parent->residue->add(u0double, u0double));
const QWORD coeff1 = parent->residue->sub(parent->residue->add(f0, f0), parent->residue->mul(f1, u1));
@ -63,7 +61,7 @@ int Divisor::find_divisor_v(TDivisor *d)
if (f1 == 0)
{
// impossible
// printf("bad f(), double root detected\n");
// printf("bad curve(), double root detected\n");
}
return 0;
}
@ -109,15 +107,17 @@ int Divisor::find_divisor_v(TDivisor *d)
return 1;
}
int Divisor::u2poly(const TDivisor *src, QWORD polyu[3], QWORD polyv[2])
int ConfirmationID::ConfirmationID::Divisor::u2poly(const TDivisor *src, QWORD polyu[3], QWORD polyv[2])
{
if (src->u[1] != BAD)
{
polyu[0] = src->u[0];
polyu[1] = src->u[1];
polyu[2] = 1;
polyv[0] = src->v[0];
polyv[1] = src->v[1];
return 2;
}
@ -125,8 +125,10 @@ int Divisor::u2poly(const TDivisor *src, QWORD polyu[3], QWORD polyv[2])
{
polyu[0] = src->u[0];
polyu[1] = 1;
polyv[0] = src->v[0];
polyv[1] = 0;
return 1;
}
@ -136,7 +138,7 @@ int Divisor::u2poly(const TDivisor *src, QWORD polyu[3], QWORD polyv[2])
return 0;
}
void Divisor::add(const TDivisor *src1, const TDivisor *src2, TDivisor *dst)
void ConfirmationID::Divisor::add(const TDivisor *src1, const TDivisor *src2, TDivisor *dst)
{
QWORD u1[3], u2[3], v1[2], v2[2];
int u1deg = u2poly(src1, u1, v1);
@ -182,8 +184,8 @@ void Divisor::add(const TDivisor *src1, const TDivisor *src2, TDivisor *dst)
QWORD v[7], tmp[7];
int vdeg, tmpdeg;
// 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 + e2*u2*v1) + c2*(v1*v2 + curve)
// c1*(e1*u1*(v2-v1) + d1*v1) + c2*(v1*v2 + curve)
v[0] = parent->residue->sub(v2[0], v1[0]);
v[1] = parent->residue->sub(v2[1], v1[1]);
tmpdeg = parent->polynomial->mul(e1deg, e1, 1, v, -1, tmp);
@ -195,7 +197,7 @@ void Divisor::add(const TDivisor *src1, const TDivisor *src2, TDivisor *dst)
v[i] = parent->residue->mul(v[i], c1[0]);
}
memcpy(tmp, parent->f, 6 * sizeof(parent->f[0]));
memcpy(tmp, parent->curve, 6 * sizeof(parent->curve[0]));
tmpdeg = 5;
tmpdeg = parent->polynomial->mul(1, v1, 1, v2, tmpdeg, tmp);
vdeg = parent->polynomial->mul(c2deg, c2, tmpdeg, tmp, vdeg, v);
@ -223,11 +225,11 @@ void Divisor::add(const TDivisor *src1, const TDivisor *src2, TDivisor *dst)
{
assert(udeg <= 4);
assert(vdeg <= 3);
// u' = monic((f-v^2)/u), v'=-v mod u'
// u' = monic((curve-v^2)/u), v'=-v mod u'
tmpdeg = parent->polynomial->mul(vdeg, v, vdeg, v, -1, tmp);
for (i = 0; i <= tmpdeg && i <= 5; i++)
{
tmp[i] = parent->residue->sub(parent->f[i], tmp[i]);
tmp[i] = parent->residue->sub(parent->curve[i], tmp[i]);
}
for (; i <= tmpdeg; i++)
@ -237,7 +239,7 @@ void Divisor::add(const TDivisor *src1, const TDivisor *src2, TDivisor *dst)
for (; i <= 5; i++)
{
tmp[i] = parent->f[i];
tmp[i] = parent->curve[i];
}
tmpdeg = i - 1;
@ -288,7 +290,7 @@ void Divisor::add(const TDivisor *src1, const TDivisor *src2, TDivisor *dst)
#define divisor_double(src, dst) add(src, src, dst)
void Divisor::mul(const TDivisor *src, QWORD mult, TDivisor *dst)
void ConfirmationID::Divisor::mul(const TDivisor *src, QWORD mult, TDivisor *dst)
{
if (mult == 0)
{
@ -317,7 +319,7 @@ void Divisor::mul(const TDivisor *src, QWORD mult, TDivisor *dst)
}
}
void Divisor::mul128(const TDivisor *src, QWORD mult_lo, QWORD 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)
{

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -23,7 +23,8 @@
#include "confid.h"
// generic short slow code
int Polynomial::mul(int adeg, const QWORD a[], int bdeg, const QWORD b[], int resultprevdeg, QWORD result[])
int ConfirmationID::Polynomial::mul(int adeg, const QWORD a[], int bdeg, const QWORD b[], int resultprevdeg,
QWORD result[])
{
if (adeg < 0 || bdeg < 0)
{
@ -55,7 +56,7 @@ int Polynomial::mul(int adeg, const QWORD a[], int bdeg, const QWORD b[], int re
return resultprevdeg;
}
int Polynomial::div_monic(int adeg, QWORD a[], int bdeg, const QWORD b[], QWORD *quotient)
int ConfirmationID::Polynomial::div_monic(int adeg, QWORD a[], int bdeg, const QWORD b[], QWORD *quotient)
{
assert(bdeg >= 0);
assert(b[bdeg] == 1);
@ -84,8 +85,8 @@ int Polynomial::div_monic(int adeg, QWORD a[], int bdeg, const QWORD b[], QWORD
return i;
}
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])
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;
QWORD s[3] = {0, 0, 0};
@ -119,43 +120,56 @@ void Polynomial::xgcd(int adeg, const QWORD a[3], int bdeg, const QWORD b[3], in
{
unsigned tmp;
int tmpi;
tmp = rdeg;
rdeg = gcddeg;
gcddeg = tmp;
tmpi = sdeg;
sdeg = mult1deg;
mult1deg = tmpi;
tmpi = tdeg;
tdeg = mult2deg;
mult2deg = tmpi;
QWORD tmp2;
tmp2 = r[0];
r[0] = gcd[0];
gcd[0] = tmp2;
tmp2 = r[1];
r[1] = gcd[1];
gcd[1] = tmp2;
tmp2 = r[2];
r[2] = gcd[2];
gcd[2] = tmp2;
tmp2 = s[0];
s[0] = mult1[0];
mult1[0] = tmp2;
tmp2 = s[1];
s[1] = mult1[1];
mult1[1] = tmp2;
tmp2 = s[2];
s[2] = mult1[2];
mult1[2] = tmp2;
tmp2 = t[0];
t[0] = mult2[0];
mult2[0] = tmp2;
tmp2 = t[1];
t[1] = mult2[1];
mult2[1] = tmp2;
tmp2 = t[2];
t[2] = mult2[2];
mult2[2] = tmp2;
continue;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -24,17 +24,20 @@
#if defined(__x86_64__) || defined(_M_AMD64) || defined(__aarch64__) || (defined(__arm64__) && defined(__APPLE__))
#ifdef __GNUC__
inline QWORD Residue::__umul128(QWORD a, QWORD b, QWORD *hi)
inline QWORD ConfirmationID::Residue::__umul128(QWORD multiplier, QWORD multiplicand, QWORD *product_hi)
{
OWORD r = (OWORD)a * (OWORD)b;
*hi = r >> 64;
OWORD r = (OWORD)multiplier * (OWORD)multiplicand;
*product_hi = r >> 64;
return (QWORD)r;
}
#else
#define __umul128 _umul128
inline QWORD ConfirmationID::Residue::__umul128(QWORD multiplier, QWORD multiplicand, QWORD *product_hi)
{
return _umul128(multiplier, multiplicand, product_hi);
}
#endif
#elif defined(__i386__) || defined(_M_IX86) || defined(__arm__) || defined(__EMSCRIPTEN__)
inline QWORD Residue::__umul128(QWORD multiplier, QWORD multiplicand, QWORD *product_hi)
inline QWORD ConfirmationID::Residue::__umul128(QWORD multiplier, QWORD multiplicand, QWORD *product_hi)
{
// multiplier = ab = a * 2^32 + b
// multiplicand = cd = c * 2^32 + d
@ -63,17 +66,14 @@ inline QWORD Residue::__umul128(QWORD multiplier, QWORD multiplicand, QWORD *pro
#error Unknown architecture detected - please edit confid.cpp to tailor __umul128() your architecture
#endif
QWORD Residue::ui128_quotient_mod(QWORD lo, QWORD hi)
QWORD ConfirmationID::Residue::ui128_quotient_mod(QWORD lo, QWORD hi)
{
// hi:lo * ceil(2**170/MOD) >> (64 + 64 + 42)
QWORD prod1;
__umul128(lo, parent->p0, &prod1);
__umul128(lo, parent->privateKey.qword[0], &prod1);
QWORD part1hi, part1lo;
part1lo = __umul128(lo, parent->p1, &part1hi);
QWORD part2hi, part2lo;
part2lo = __umul128(hi, parent->p2, &part2hi);
QWORD part1hi, part1lo = __umul128(lo, parent->privateKey.qword[1], &part1hi);
QWORD part2hi, part2lo = __umul128(hi, parent->privateKey.qword[0], &part2hi);
QWORD sum1 = part1lo + part2lo;
unsigned sum1carry = (sum1 < part1lo);
@ -81,24 +81,22 @@ QWORD Residue::ui128_quotient_mod(QWORD lo, QWORD hi)
sum1carry += (sum1 < prod1);
QWORD prod2 = part1hi + part2hi + sum1carry;
QWORD prod3hi, prod3lo;
prod3lo = __umul128(hi, parent->p3, &prod3hi);
QWORD prod3hi, prod3lo = __umul128(hi, parent->privateKey.qword[1], &prod3hi);
prod3lo += prod2;
prod3hi += (prod3lo < prod2);
return (prod3lo >> 42) | (prod3hi << 22);
}
QWORD Residue::mul(QWORD x, QWORD y)
QWORD ConfirmationID::Residue::mul(QWORD x, QWORD y)
{
// * ceil(2**170/MOD) = 0x2d351 c6d04f8b|604fa6a1 c6346a87 for (p-1)*(p-1) max
QWORD hi;
QWORD lo = __umul128(x, y, &hi);
QWORD hi, lo = __umul128(x, y, &hi);
QWORD quotient = ui128_quotient_mod(lo, hi);
return lo - quotient * parent->MOD;
}
QWORD Residue::pow(QWORD x, QWORD y)
QWORD ConfirmationID::Residue::pow(QWORD x, QWORD y)
{
if (y == 0)
{
@ -125,7 +123,7 @@ QWORD Residue::pow(QWORD x, QWORD y)
return res;
}
QWORD Residue::add(QWORD x, QWORD y)
QWORD ConfirmationID::Residue::add(QWORD x, QWORD y)
{
QWORD z = x + y;
// z = z - (z >= MOD ? MOD : 0);
@ -136,7 +134,7 @@ QWORD Residue::add(QWORD x, QWORD y)
return z;
}
QWORD Residue::sub(QWORD x, QWORD y)
QWORD ConfirmationID::Residue::sub(QWORD x, QWORD y)
{
QWORD z = x - y;
// z += (x < y ? MOD : 0);
@ -147,7 +145,7 @@ QWORD Residue::sub(QWORD x, QWORD y)
return z;
}
QWORD Residue::inverse(QWORD u, QWORD v)
QWORD ConfirmationID::Residue::inverse(QWORD u, QWORD v)
{
// assert(u);
int64_t tmp;
@ -168,13 +166,13 @@ QWORD Residue::inverse(QWORD u, QWORD v)
return xu;
}
QWORD Residue::inv(QWORD x)
QWORD ConfirmationID::Residue::inv(QWORD x)
{
return inverse(x, parent->MOD);
// return residue_pow(x, MOD - 2);
}
QWORD Residue::sqrt(QWORD what)
QWORD ConfirmationID::Residue::sqrt(QWORD what)
{
if (!what)
{
@ -195,6 +193,7 @@ QWORD Residue::sqrt(QWORD what)
x = pow(what, (q - 1) / 2);
b = mul(mul(what, x), x);
x = mul(what, x);
while (b != 1)
{
QWORD m = 0, b2 = b;
@ -224,4 +223,4 @@ QWORD Residue::sqrt(QWORD what)
}
return x;
}
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,18 +16,27 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/25/2023
* @FileCreated by Neo on 06/25/2023
* @Maintainer Neo
*/
#include "libumskt.h"
#ifdef _WIN32
std::FILE *UMSKT::debug = std::fopen("NUL:", "w");
// this seems janky but it works, and doesn't use storage that would otherwise get clobbered
std::FILE *getFileStreamToNul()
{
fopen_s(&UMSKT::debug, "nul", "w");
return UMSKT::debug;
}
std::FILE *UMSKT::debug = getFileStreamToNul();
#else
std::FILE *UMSKT::debug = std::fopen("/dev/null", "w");
#endif
BOOL UMSKT::VERBOSE;
BOOL UMSKT::DEBUG;
void UMSKT::setDebugOutput(std::FILE *input)
{
debug = input;

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/25/2023
* @FileCreated by Neo on 06/25/2023
* @Maintainer Neo
*/
@ -27,48 +27,145 @@
#include "pidgen3/BINK2002.h"
#include "pidgen3/PIDGEN3.h"
FNEXPORT int ConfirmationID_Generate(const char *installation_id_str, char confirmation_id[49], int mode,
std::string productid)
FNEXPORT BOOL LIBUMSKT_SET_DEBUG_OUTPUT(void *filestream)
{
return ConfirmationID::Generate(installation_id_str, confirmation_id, mode, productid);
char buffer[7];
memcpy(buffer, filestream, 6);
buffer[6] = 0;
auto buff_string = std::string(buffer);
if (strcasecmp("STDOUT", &buffer[0]) != 0)
{
UMSKT::debug = stdout;
return true;
}
else if (strcasecmp("STDERR", &buffer[0]) != 0)
{
UMSKT::debug = stderr;
return true;
}
return false;
}
FNEXPORT EC_GROUP *PIDGEN3_initializeEllipticCurve(char *pSel, char *aSel, char *bSel, char *generatorXSel,
char *generatorYSel, char *publicKeyXSel, char *publicKeyYSel,
EC_POINT *&genPoint, EC_POINT *&pubPoint)
// ---------------------------------------------
FNEXPORT void *CONFID_INIT()
{
return PIDGEN3::initializeEllipticCurve(pSel, aSel, bSel, generatorXSel, generatorYSel, publicKeyXSel,
publicKeyYSel, genPoint, pubPoint);
auto cid = new ConfirmationID();
// cid->LoadHyperellipticCurve(0, 0, 0, 0, 0, 0, 0, 0, 0, false, false, 0);
return cid;
}
FNEXPORT bool PIDGEN3_BINK1998_Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *publicKey, char (&pKey)[25])
FNEXPORT BYTE CONFID_GENERATE(void *cidIn, const char *installation_id_str, char *&confirmation_id, char *productid)
{
return PIDGEN3::BINK1998::Verify(eCurve, basePoint, publicKey, pKey);
auto *cid((ConfirmationID *)cidIn);
std::string str, confid(confirmation_id), productids(productid);
auto retval = cid->Generate(str, confid, productids);
return retval;
}
FNEXPORT void PIDGEN3_BINK1998_Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *genOrder, BIGNUM *privateKey,
DWORD pSerial, BOOL pUpgrade, char (&pKey)[25])
FNEXPORT BYTE CONFID_END(void *cidIn)
{
return PIDGEN3::BINK1998::Generate(eCurve, basePoint, genOrder, privateKey, pSerial, pUpgrade, pKey);
auto *cid((ConfirmationID *)cidIn);
delete cid;
return true;
}
FNEXPORT bool PIDGEN3_BINK2002_Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *publicKey, char (&cdKey)[25])
// ---------------------------------------------
FNEXPORT void *PIDGEN3_BINK1998_INIT(const char *p, const char *a, const char *b, const char *generatorX,
const char *generatorY, const char *publicKeyX, const char *publicKeyY,
const char *genOrder, const char *privateKey)
{
return PIDGEN3::BINK2002::Verify(eCurve, basePoint, publicKey, cdKey);
auto *bink1998 = new BINK1998();
bink1998->LoadEllipticCurve(p, a, b, generatorX, generatorY, publicKeyX, publicKeyY, genOrder, privateKey);
return bink1998;
}
FNEXPORT void PIDGEN3_BINK2002_Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *genOrder, BIGNUM *privateKey,
DWORD pChannelID, DWORD pAuthInfo, BOOL pUpgrade, char (&pKey)[25])
FNEXPORT void *PIDGEN3_BINK2002_INIT(const char *p, const char *a, const char *b, const char *generatorX,
const char *generatorY, const char *publicKeyX, const char *publicKeyY,
const char *genOrder, const char *privateKey, const char *authinfo)
{
return PIDGEN3::BINK2002::Generate(eCurve, basePoint, genOrder, privateKey, pChannelID, pAuthInfo, pUpgrade, pKey);
auto bink2002 = new BINK2002();
bink2002->LoadEllipticCurve(p, a, b, generatorX, generatorY, publicKeyX, publicKeyY, genOrder, privateKey);
return bink2002;
}
FNEXPORT int PIDGEN2_GenerateRetail(char *channelID, char *&keyout)
FNEXPORT BOOL PIDGEN3_Generate(void *&ptrIn, char *&pKeyOut, int pKeySizeIn)
{
return PIDGEN2::GenerateRetail(channelID, keyout);
auto *p3((PIDGEN3 *)ptrIn);
std::string str;
BOOL retval = p3->Generate(str);
if (pKeySizeIn > str.length() + 1)
{
return false;
}
memcpy(pKeyOut, &str[0], str.length());
pKeyOut[str.length()] = 0;
return retval;
}
FNEXPORT int PIDGEN2_GenerateOEM(char *year, char *day, char *oem, char *keyout)
FNEXPORT BOOL PIDGEN3_Verify(void *&ptrIn, char *pKeyIn)
{
return PIDGEN2::GenerateOEM(year, day, oem, keyout);
auto *p3((PIDGEN3 *)ptrIn);
std::string str(pKeyIn);
BOOL retval = p3->Verify(str);
return retval;
}
FNEXPORT void PIDGEN3_END(void *ptrIn)
{
auto *p3((PIDGEN3 *)ptrIn);
delete p3;
}
// ---------------------------------------------
FNEXPORT BOOL PIDGEN2_INIT()
{
return true;
}
FNEXPORT BOOL PIDGEN2_GENERATE()
{
return true;
}
FNEXPORT BOOL PIDGEN2_END()
{
return true;
}
FNEXPORT BOOL PIDGEN2_GenerateRetail(char *channelID, char *&keyout)
{
auto P2 = new PIDGEN2();
BOOL retval = P2->GenerateRetail(channelID, keyout);
delete P2;
return retval;
}
FNEXPORT BOOL PIDGEN2_GenerateOEM(char *year, char *day, char *oem, char *&keyout)
{
auto P2 = new PIDGEN2();
BOOL retval = P2->GenerateOEM(year, day, oem, keyout);
delete P2;
return retval;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/24/2023
* @FileCreated by Neo on 06/24/2023
* @Maintainer Neo
*/
@ -63,11 +63,19 @@ class UMSKT
{
public:
static std::FILE *debug;
class PIDGEN2;
class PIDGEN3;
class ConfigurationID;
static BOOL VERBOSE;
static BOOL DEBUG;
static void setDebugOutput(std::FILE *input);
template <typename T> static T getRandom()
{
T retval;
BIGNUM *bnrand = BN_new();
BN_rand(bnrand, sizeof(T) * 8, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY);
BN_bn2lebinpad(bnrand, (unsigned char *)&retval, sizeof(T));
BN_free(bnrand);
return retval;
}
};
#endif // UMSKT_LIBUMSKT_H

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -22,9 +22,6 @@
#include "PIDGEN2.h"
const char *channelIDBlacklist[7] = {"333", "444", "555", "666", "777", "888", "999"};
const char *validYears[8] = {"95", "96", "97", "98", "99", "00", "01", "02"};
bool PIDGEN2::isNumericString(char *input)
{
for (int i = 0; i < strlen(input); i++)

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -25,18 +25,26 @@
#include "../libumskt.h"
EXPORT class PIDGEN2
class PIDGEN2
{
DWORD year;
DWORD day;
BOOL isOEM;
BOOL isOffice;
static constexpr char channelIDBlacklist[7][4] = {"333", "444", "555", "666", "777", "888", "999"};
static constexpr char validYears[8][3] = {"95", "96", "97", "98", "99", "00", "01", "02"};
public:
static bool isNumericString(char *input);
static bool isValidChannelID(char *channelID);
static bool isValidOEMID(char *OEMID);
static bool isValidYear(char *year);
static bool isValidDay(char *day);
static bool isValidRetailProductID(char *productID);
static int addDigits(char *input);
static int GenerateRetail(char *channelID, char *&keyout);
static int GenerateOEM(char *year, char *day, char *oem, char *&keyout);
BOOL isNumericString(char *input);
BOOL isValidChannelID(char *channelID);
BOOL isValidOEMID(char *OEMID);
BOOL isValidYear(char *year);
BOOL isValidDay(char *day);
BOOL isValidRetailProductID(char *productID);
int addDigits(char *input);
int GenerateRetail(char *channelID, char *&keyout);
int GenerateOEM(char *year, char *day, char *oem, char *&keyout);
};
#endif // UMSKT_PIDGEN2_H

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -29,62 +29,81 @@
#include "BINK1998.h"
/* Unpacks a Windows XP-like Product Key. */
void PIDGEN3::BINK1998::Unpack(QWORD (&pRaw)[2], BOOL &pUpgrade, DWORD &pSerial, DWORD &pHash, QWORD &pSignature)
/**
* Unpacks a Windows XP-like Product Key.
*
* @param pRaw [out] *QWORD[2] raw product key output
**/
BOOL BINK1998::Unpack(QWORD (&pRaw)[2])
{
// We're assuming that the quantity of information within the product key is at most 114 bits.
// log2(24^25) = 114.
// Upgrade = Bit 0
pUpgrade = FIRSTNBITS(pRaw[0], 1);
isUpgrade = FIRSTNBITS(pRaw[0], 1);
// Serial = Bits [1..30] -> 30 bits
pSerial = NEXTSNBITS(pRaw[0], 30, 1);
Serial = NEXTSNBITS(pRaw[0], 30, 1);
// Hash = Bits [31..58] -> 28 bits
pHash = NEXTSNBITS(pRaw[0], 28, 31);
Hash = NEXTSNBITS(pRaw[0], 28, 31);
// Signature = Bits [59..113] -> 56 bits
pSignature = FIRSTNBITS(pRaw[1], 51) << 5 | NEXTSNBITS(pRaw[0], 5, 59);
Signature = FIRSTNBITS(pRaw[1], 51) << 5 | NEXTSNBITS(pRaw[0], 5, 59);
return true;
}
/* Packs a Windows XP-like Product Key. */
void PIDGEN3::BINK1998::Pack(QWORD (&pRaw)[2], BOOL pUpgrade, DWORD pSerial, DWORD pHash, QWORD pSignature)
/**
* Packs a Windows XP-like Product Key.
*
* @param pRaw [in] *QWORD[2] raw product key input
**/
BOOL BINK1998::Pack(QWORD (&pRaw)[2])
{
// The quantity of information the key provides is 114 bits.
// We're storing it in 2 64-bit quad-words with 14 trailing bits.
// 64 * 2 = 128
// Signature [114..59] <- Hash [58..31] <- Serial [30..1] <- Upgrade [0]
pRaw[0] = FIRSTNBITS(pSignature, 5) << 59 | FIRSTNBITS(pHash, 28) << 31 | pSerial << 1 | pUpgrade;
pRaw[1] = NEXTSNBITS(pSignature, 51, 5);
pRaw[0] = FIRSTNBITS(Signature, 5) << 59 | FIRSTNBITS(Hash, 28) << 31 | Serial << 1 | isUpgrade;
pRaw[1] = NEXTSNBITS(Signature, 51, 5);
return true;
}
/* Verifies a Windows XP-like Product Key. */
bool PIDGEN3::BINK1998::Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *publicKey, char (&pKey)[25])
/**
* Verifies a Windows XP-like Product Key.
*
* @param pKey [in]
*
* @return true if provided key validates against loaded curve
*/
BOOL BINK1998::Verify(std::string &pKey)
{
if (pKey.length() != 25)
{
return false;
}
BN_CTX *numContext = BN_CTX_new();
QWORD pRaw[2]{}, pSignature;
DWORD pData, pSerial, pHash;
BOOL pUpgrade;
QWORD pRaw[2]{};
// Convert Base24 CD-key to bytecode.
PIDGEN3::unbase24((BYTE *)pRaw, pKey);
unbase24((BYTE *)pRaw, pKey);
// Extract RPK, hash and signature from bytecode.
Unpack(pRaw, pUpgrade, pSerial, pHash, pSignature);
Unpack(pRaw);
fmt::print(UMSKT::debug, "Validation results:\n");
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", pSerial);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", pHash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", pSignature);
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", isUpgrade);
fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", Serial);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", Hash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", Signature);
fmt::print(UMSKT::debug, "\n");
pData = pSerial << 1 | pUpgrade;
DWORD pData = Serial << 1 | isUpgrade;
/*
*
@ -101,8 +120,8 @@ bool PIDGEN3::BINK1998::Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *
*
*/
BIGNUM *e = BN_lebin2bn((BYTE *)&pHash, sizeof(pHash), nullptr),
*s = BN_lebin2bn((BYTE *)&pSignature, sizeof(pSignature), nullptr), *x = BN_new(), *y = BN_new();
BIGNUM *e = BN_lebin2bn((BYTE *)&Hash, sizeof(Hash), nullptr),
*s = BN_lebin2bn((BYTE *)&Signature, sizeof(Signature), nullptr), *x = BN_new(), *y = BN_new();
// Create 2 points on the elliptic curve.
EC_POINT *t = EC_POINT_new(eCurve);
@ -149,21 +168,26 @@ bool PIDGEN3::BINK1998::Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *
EC_POINT_free(p);
// If the computed hash checks out, the key is valid.
return compHash == pHash;
return compHash == Hash;
}
/* Generates a Windows XP-like Product Key. */
void PIDGEN3::BINK1998::Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *genOrder, BIGNUM *privateKey,
DWORD pSerial, BOOL pUpgrade, char (&pKey)[25])
/**
* Generates a Windows XP-like Product Key.
*
* @param pKey [out]
*
* @return true on success, false on fail
*/
BOOL BINK1998::Generate(std::string &pKey)
{
BN_CTX *numContext = BN_CTX_new();
BIGNUM *c = BN_new(), *s = BN_new(), *x = BN_new(), *y = BN_new();
QWORD pRaw[2]{}, pSignature = 0;
QWORD pRaw[2]{};
// Data segment of the RPK.
DWORD pData = pSerial << 1 | pUpgrade;
DWORD pData = Serial << 1 | isUpgrade;
do
{
@ -225,20 +249,20 @@ void PIDGEN3::BINK1998::Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *
BN_mod_add(s, s, c, genOrder, numContext);
// Translate resulting scalar into a 64-bit integer (the byte order is little-endian).
BN_bn2lebinpad(s, (BYTE *)&pSignature, BN_num_bytes(s));
BN_bn2lebinpad(s, (BYTE *)&Signature, BN_num_bytes(s));
// Pack product key.
Pack(pRaw, pUpgrade, pSerial, pHash, pSignature);
Pack(pRaw);
fmt::print(UMSKT::debug, "Generation results:\n");
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", pSerial);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", pHash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", pSignature);
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", isUpgrade);
fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", Serial);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", Hash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", Signature);
fmt::print(UMSKT::debug, "\n");
EC_POINT_free(r);
} while (pSignature > BITMASK(55));
} while (Signature > BITMASK(55));
// ↑ ↑ ↑
// The signature can't be longer than 55 bits, else it will
// make the CD-key longer than 25 characters.
@ -252,4 +276,6 @@ void PIDGEN3::BINK1998::Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *
BN_free(y);
BN_CTX_free(numContext);
return true;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/6/2023
* @FileCreated by Neo on 06/06/2023
* @Maintainer Neo
*/
@ -25,17 +25,14 @@
#include "PIDGEN3.h"
EXPORT class PIDGEN3::BINK1998
class BINK1998 : public PIDGEN3
{
public:
static void Unpack(QWORD (&pRaw)[2], BOOL &pUpgrade, DWORD &pSerial, DWORD &pHash, QWORD &pSignature);
static void Pack(QWORD (&pRaw)[2], BOOL pUpgrade, DWORD pSerial, DWORD pHash, QWORD pSignature);
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,
BOOL pUpgrade, char (&pKey)[25]);
BOOL Unpack(QWORD (&pRaw)[2]) override;
BOOL Pack(QWORD (&pRaw)[2]) override;
BOOL Verify(std::string &pKey) override;
BOOL Generate(std::string &pKey) override;
};
#endif // UMSKT_BINK1998_H

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -29,65 +29,75 @@
#include "BINK2002.h"
/* Unpacks a Windows Server 2003-like Product Key. */
void PIDGEN3::BINK2002::Unpack(QWORD (&pRaw)[2], BOOL &pUpgrade, DWORD &pChannelID, DWORD &pHash, QWORD &pSignature,
DWORD &pAuthInfo)
/**
* Unpacks a Windows Server 2003-like Product Key.
*
* @param pRaw *QWORD[2] raw product key input
**/
BOOL BINK2002::Unpack(QWORD (&pRaw)[2])
{
// We're assuming that the quantity of information within the product key is at most 114 bits.
// log2(24^25) = 114.
// Upgrade = Bit 0
pUpgrade = FIRSTNBITS(pRaw[0], 1);
isUpgrade = FIRSTNBITS(pRaw[0], 1);
// Channel ID = Bits [1..10] -> 10 bits
pChannelID = NEXTSNBITS(pRaw[0], 10, 1);
ChannelID = NEXTSNBITS(pRaw[0], 10, 1);
// Hash = Bits [11..41] -> 31 bits
pHash = NEXTSNBITS(pRaw[0], 31, 11);
Hash = NEXTSNBITS(pRaw[0], 31, 11);
// Signature = Bits [42..103] -> 62 bits
// The quad-word signature overlaps AuthInfo in bits 104 and 105,
// hence Microsoft employs a secret technique called: Signature = HIDWORD(Signature) >> 2 | LODWORD(Signature)
pSignature = NEXTSNBITS(pRaw[1], 30, 10) << 32 | FIRSTNBITS(pRaw[1], 10) << 22 | NEXTSNBITS(pRaw[0], 22, 42);
Signature = NEXTSNBITS(pRaw[1], 30, 10) << 32 | FIRSTNBITS(pRaw[1], 10) << 22 | NEXTSNBITS(pRaw[0], 22, 42);
// AuthInfo = Bits [104..113] -> 10 bits
pAuthInfo = NEXTSNBITS(pRaw[1], 10, 40);
AuthInfo = NEXTSNBITS(pRaw[1], 10, 40);
return true;
}
/* Packs a Windows Server 2003-like Product Key. */
void PIDGEN3::BINK2002::Pack(QWORD (&pRaw)[2], BOOL pUpgrade, DWORD pChannelID, DWORD pHash, QWORD pSignature,
DWORD pAuthInfo)
/**
* Packs a Windows Server 2003-like Product Key.
*
* @param pRaw *QWORD[2] raw product key output
**/
BOOL BINK2002::Pack(QWORD (&pRaw)[2])
{
// AuthInfo [113..104] <- Signature [103..42] <- Hash [41..11] <- Channel ID [10..1] <- Upgrade [0]
pRaw[0] = FIRSTNBITS(pSignature, 22) << 42 | (QWORD)pHash << 11 | pChannelID << 1 | pUpgrade;
pRaw[1] = FIRSTNBITS(pAuthInfo, 10) << 40 | NEXTSNBITS(pSignature, 40, 22);
pRaw[0] = FIRSTNBITS(Signature, 22) << 42 | (QWORD)Hash << 11 | ChannelID << 1 | isUpgrade;
pRaw[1] = FIRSTNBITS(AuthInfo, 10) << 40 | NEXTSNBITS(Signature, 40, 22);
return true;
}
/* Verifies a Windows Server 2003-like Product Key. */
bool PIDGEN3::BINK2002::Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *publicKey, char (&cdKey)[25])
/**
* Verifies a Windows Server 2003-like Product Key.
*
* @param pKey
**/
BOOL BINK2002::Verify(std::string &pKey)
{
BN_CTX *context = BN_CTX_new();
QWORD bKey[2]{}, pSignature = 0;
DWORD pData, pChannelID, pHash, pAuthInfo;
BOOL pUpgrade;
QWORD bKey[2]{};
// Convert Base24 CD-key to bytecode.
unbase24((BYTE *)bKey, cdKey);
unbase24((BYTE *)bKey, pKey.c_str());
// Extract product key segments from bytecode.
Unpack(bKey, pUpgrade, pChannelID, pHash, pSignature, pAuthInfo);
Unpack(bKey);
pData = pChannelID << 1 | pUpgrade;
DWORD pData = ChannelID << 1 | isUpgrade;
fmt::print(UMSKT::debug, "Validation results:\n");
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", pChannelID);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", pHash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", pSignature);
fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", pAuthInfo);
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", isUpgrade);
fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", ChannelID);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", Hash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", Signature);
fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", AuthInfo);
fmt::print(UMSKT::debug, "\n");
BYTE msgDigest[SHA_DIGEST_LENGTH]{}, msgBuffer[SHA_MSG_LENGTH_2003]{}, xBin[FIELD_BYTES_2003]{},
@ -97,12 +107,12 @@ bool PIDGEN3::BINK2002::Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *
msgBuffer[0x00] = 0x5D;
msgBuffer[0x01] = (pData & 0x00FF);
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
msgBuffer[0x03] = (pHash & 0x000000FF);
msgBuffer[0x04] = (pHash & 0x0000FF00) >> 8;
msgBuffer[0x05] = (pHash & 0x00FF0000) >> 16;
msgBuffer[0x06] = (pHash & 0xFF000000) >> 24;
msgBuffer[0x07] = (pAuthInfo & 0x00FF);
msgBuffer[0x08] = (pAuthInfo & 0xFF00) >> 8;
msgBuffer[0x03] = (Hash & 0x000000FF);
msgBuffer[0x04] = (Hash & 0x0000FF00) >> 8;
msgBuffer[0x05] = (Hash & 0x00FF0000) >> 16;
msgBuffer[0x06] = (Hash & 0xFF000000) >> 24;
msgBuffer[0x07] = (AuthInfo & 0x00FF);
msgBuffer[0x08] = (AuthInfo & 0xFF00) >> 8;
msgBuffer[0x09] = 0x00;
msgBuffer[0x0A] = 0x00;
@ -130,11 +140,10 @@ bool PIDGEN3::BINK2002::Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *
*/
BIGNUM *e = BN_lebin2bn((BYTE *)&iSignature, sizeof(iSignature), nullptr),
*s = BN_lebin2bn((BYTE *)&pSignature, sizeof(pSignature), nullptr), *x = BN_new(), *y = BN_new();
*s = BN_lebin2bn((BYTE *)&Signature, sizeof(Signature), nullptr), *x = BN_new(), *y = BN_new();
// Create 2 points on the elliptic curve.
EC_POINT *p = EC_POINT_new(eCurve);
EC_POINT *t = EC_POINT_new(eCurve);
EC_POINT *p = EC_POINT_new(eCurve), *t = EC_POINT_new(eCurve);
// t = sG
EC_POINT_mul(eCurve, t, nullptr, basePoint, s, context);
@ -181,21 +190,20 @@ bool PIDGEN3::BINK2002::Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *
EC_POINT_free(t);
// If the computed hash checks out, the key is valid.
return compHash == pHash;
return compHash == Hash;
}
/* Generates a Windows Server 2003-like Product Key. */
void PIDGEN3::BINK2002::Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *genOrder, BIGNUM *privateKey,
DWORD pChannelID, DWORD pAuthInfo, BOOL pUpgrade, char (&pKey)[25])
BOOL BINK2002::Generate(std::string &pKey)
{
BN_CTX *numContext = BN_CTX_new();
BIGNUM *c = BN_new(), *e = BN_new(), *s = BN_new(), *x = BN_new(), *y = BN_new();
QWORD pRaw[2]{}, pSignature = 0;
QWORD pRaw[2]{};
// Data segment of the RPK.
DWORD pData = pChannelID << 1 | pUpgrade;
DWORD pData = ChannelID << 1 | isUpgrade;
BOOL noSquare;
@ -243,8 +251,8 @@ void PIDGEN3::BINK2002::Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *
msgBuffer[0x04] = (pHash & 0x0000FF00) >> 8;
msgBuffer[0x05] = (pHash & 0x00FF0000) >> 16;
msgBuffer[0x06] = (pHash & 0xFF000000) >> 24;
msgBuffer[0x07] = (pAuthInfo & 0x00FF);
msgBuffer[0x08] = (pAuthInfo & 0xFF00) >> 8;
msgBuffer[0x07] = (AuthInfo & 0x00FF);
msgBuffer[0x08] = (AuthInfo & 0xFF00) >> 8;
msgBuffer[0x09] = 0x00;
msgBuffer[0x0A] = 0x00;
@ -323,21 +331,21 @@ void PIDGEN3::BINK2002::Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *
BN_rshift1(s, s);
// Translate resulting scalar into a 64-bit integer (the byte order is little-endian).
BN_bn2lebinpad(s, (BYTE *)&pSignature, BN_num_bytes(s));
BN_bn2lebinpad(s, (BYTE *)&Signature, BN_num_bytes(s));
// Pack product key.
Pack(pRaw, pUpgrade, pChannelID, pHash, pSignature, pAuthInfo);
Pack(pRaw);
fmt::print(UMSKT::debug, "Generation results:\n");
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", pChannelID);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", pHash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", pSignature);
fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", pAuthInfo);
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", isUpgrade);
fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", ChannelID);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", Hash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", Signature);
fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", AuthInfo);
fmt::print(UMSKT::debug, "\n");
EC_POINT_free(r);
} while (pSignature > BITMASK(62) || noSquare);
} while (Signature > BITMASK(62) || noSquare);
// ↑ ↑ ↑
// The signature can't be longer than 62 bits, else it will
// overlap with the AuthInfo segment next to it.
@ -352,4 +360,6 @@ void PIDGEN3::BINK2002::Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *
BN_free(e);
BN_CTX_free(numContext);
return true;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/6/2023
* @FileCreated by Neo on 06/06/2023
* @Maintainer Neo
*/
@ -25,18 +25,14 @@
#include "PIDGEN3.h"
EXPORT class PIDGEN3::BINK2002
class BINK2002 : public PIDGEN3
{
public:
static void Unpack(QWORD (&pRaw)[2], BOOL &pUpgrade, DWORD &pChannelID, DWORD &pHash, QWORD &pSignature,
DWORD &pAuthInfo);
static void Pack(QWORD (&pRaw)[2], BOOL pUpgrade, DWORD pChannelID, DWORD pHash, QWORD pSignature, DWORD pAuthInfo);
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, BOOL pUpgrade, char (&pKey)[25]);
BOOL Unpack(QWORD (&pRaw)[2]) override;
BOOL Pack(QWORD (&pRaw)[2]) override;
BOOL Verify(std::string &pKey) override;
BOOL Generate(std::string &pKey) override;
};
#endif // UMSKT_BINK2002_H

View File

@ -0,0 +1,258 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Andrew on 01/06/2023
* @Maintainer Andrew
*/
#include "PIDGEN3.h"
/**
* https://xkcd.com/221/
*
* @return 4
*/
int getRandomNumber()
{
return 4; // chosen by fair dice roll
// guaranteed to be random
}
/**
* Initializes the elliptic curve
*
* @param pSel [in] prime
* @param aSel [in] a
* @param bSel [in] b
* @param generatorXSel [in] G[x]
* @param generatorYSel [in] G[y]
* @param publicKeyXSel [in] pub[x]
* @param publicKeyYSel [in] pub[y]
* @param genOrderSel [in] computed order of G
* @param privateKeySel [in] computed private key
*
* @return true on success, false on fail
*/
BOOL PIDGEN3::LoadEllipticCurve(const std::string pSel, const std::string aSel, const std::string bSel,
const std::string generatorXSel, const std::string generatorYSel,
const std::string publicKeyXSel, const std::string publicKeyYSel,
const std::string genOrderSel, const std::string privateKeySel)
{
// 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).
// 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.
// Initialize BIGNUM and BIGNUMCTX structures.
// BIGNUM - Large numbers
// BIGNUMCTX - Context large numbers (temporary)
BIGNUM *a, *b, *p, *generatorX, *generatorY, *publicKeyX, *publicKeyY;
BN_CTX *context;
// We're presented with an elliptic curve, a multivariable function y(x; p; a; b), where
// y^2 % p = x^3 + ax + b % p.
a = BN_new();
b = BN_new();
p = BN_new();
// Public key will consist of the resulting (x; y) values.
publicKeyX = BN_new();
publicKeyY = BN_new();
// G(x; y) is a generator function, its return value represents a point on the elliptic curve.
generatorX = BN_new();
generatorY = BN_new();
// Context variable
context = BN_CTX_new();
/* Public data */
BN_dec2bn(&p, pSel.c_str());
BN_dec2bn(&a, aSel.c_str());
BN_dec2bn(&b, bSel.c_str());
BN_dec2bn(&generatorX, generatorXSel.c_str());
BN_dec2bn(&generatorY, generatorYSel.c_str());
BN_dec2bn(&publicKeyX, publicKeyXSel.c_str());
BN_dec2bn(&publicKeyY, publicKeyYSel.c_str());
/* Computed Data */
BN_dec2bn(&genOrder, genOrderSel.c_str());
BN_dec2bn(&privateKey, privateKeySel.c_str());
BN_sub(privateKey, genOrder, privateKey);
/* Elliptic Curve calculations. */
// The group is defined via Fp = all integers [0; p - 1], where p is prime.
// The function EC_POINT_set_affine_coordinates() sets the x and y coordinates for the point p defined over the
// curve given in group.
eCurve = EC_GROUP_new_curve_GFp(p, a, b, context);
// Create new point for the generator on the elliptic curve and set its coordinates to (genX; genY).
genPoint = EC_POINT_new(eCurve);
EC_POINT_set_affine_coordinates(eCurve, genPoint, generatorX, generatorY, context);
// Create new point for the public key on the elliptic curve and set its coordinates to (pubX; pubY).
pubPoint = EC_POINT_new(eCurve);
EC_POINT_set_affine_coordinates(eCurve, pubPoint, publicKeyX, publicKeyY, context);
// If generator and public key points are not on the elliptic curve, either the generator or the public key values
// are incorrect.
assert(EC_POINT_is_on_curve(eCurve, genPoint, context) == true);
assert(EC_POINT_is_on_curve(eCurve, pubPoint, context) == true);
// Cleanup
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;
}
/**
* Convert data between endianness types.
*
* @param data [in]
* @param length [in]
**/
inline void PIDGEN3::endian(BYTE *data, int length)
{
for (int i = 0; i < length / 2; i++)
{
BYTE temp = data[i];
data[i] = data[length - i - 1];
data[length - i - 1] = temp;
}
}
/**
* Converts an OpenSSL BigNumber to it's Little Endian binary equivalent
*
* @param a [in] BigNumber to convert
* @param to [out] char* binary representation
* @param tolen [in] length of the char* array
*
* @return length of number in to
**/
int PIDGEN3::BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen)
{
if (a == nullptr || to == nullptr)
{
return 0;
}
int len = BN_bn2bin(a, to);
if (len > tolen)
{
return -1;
}
// Choke point inside BN_bn2lebinpad: OpenSSL uses len instead of tolen.
endian(to, tolen);
return len;
}
/**
* Converts from byte sequence to the CD-key.
*
* @param cdKey [out] std::string CDKey input
* @param byteSeq [in] BYTE*
**/
void PIDGEN3::base24(std::string &cdKey, BYTE *byteSeq)
{
BYTE rbyteSeq[16];
BIGNUM *z;
// Copy byte sequence to the reversed byte sequence.
memcpy(rbyteSeq, byteSeq, sizeof(rbyteSeq));
// Skip trailing zeroes and reverse y.
int length;
for (length = 15; rbyteSeq[length] <= 0; length--)
{
; // do nothing, just counting
}
endian(rbyteSeq, ++length);
// Convert reversed byte sequence to BigNum z.
z = BN_bin2bn(rbyteSeq, length, nullptr);
// Divide z by 24 and convert the remainder to a CD-key char.
for (int i = 24; i >= 0; i--)
{
cdKey[i] = pKeyCharset[BN_div_word(z, 24)];
}
BN_free(z);
}
/**
* Converts from CD-key to a byte sequence.
*
* @param byteSeq [out] *BYTE representation of the CDKey
* @param cdKey [in] std::string CDKey to convert
**/
void PIDGEN3::unbase24(BYTE *byteSeq, std::string cdKey)
{
BYTE pDecodedKey[PK_LENGTH + NULL_TERMINATOR]{};
BIGNUM *y = BN_new();
BN_zero(y);
// Remove dashes from the CD-key and put it into a Base24 byte array.
for (int i = 0, k = 0; i < cdKey.length() && k < PK_LENGTH; i++)
{
for (int j = 0; j < 24; j++)
{
if (cdKey[i] != '-' && cdKey[i] == pKeyCharset[j])
{
pDecodedKey[k++] = j;
break;
}
}
}
// Empty byte sequence.
memset(byteSeq, 0, 16);
// Calculate the weighed sum of byte array elements.
for (int i = 0; i < PK_LENGTH; i++)
{
BN_mul_word(y, PK_LENGTH - 1);
BN_add_word(y, pDecodedKey[i]);
}
// Acquire length.
int n = BN_num_bytes(y);
// Place the generated code into the byte sequence.
BN_bn2bin(y, byteSeq);
BN_free(y);
// Reverse the byte sequence.
endian(byteSeq, n);
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/24/2023
* @FileCreated by Neo on 06/24/2023
* @Maintainer Neo
*/
@ -27,23 +27,65 @@
class PIDGEN3
{
protected:
EC_GROUP *eCurve;
EC_POINT *basePoint, *publicKey, *genPoint, *pubPoint;
BIGNUM *genOrder, *privateKey;
DWORD Serial, AuthInfo, ChannelID, Hash;
QWORD Signature;
BOOL isUpgrade;
public:
class BINK1998;
class BINK2002;
PIDGEN3()
{
}
// util.cpp
static int BN_bn2lebin(const BIGNUM *a, unsigned char *to,
int tolen); // Hello OpenSSL developers, please tell me, where is this function at?
static void endian(BYTE *data, int length);
static EC_GROUP *initializeEllipticCurve(std::string pSel, std::string aSel, std::string bSel,
std::string generatorXSel, std::string generatorYSel,
std::string publicKeyXSel, std::string publicKeyYSel, EC_POINT *&genPoint,
EC_POINT *&pubPoint);
~PIDGEN3()
{
EC_GROUP_free(eCurve);
EC_POINT_free(genPoint);
EC_POINT_free(pubPoint);
EC_POINT_free(basePoint);
EC_POINT_free(publicKey);
BN_free(genOrder);
BN_free(privateKey);
BN_free(privateKey);
BN_free(genOrder);
}
// key.cpp
static constexpr char pKeyCharset[] = "BCDFGHJKMPQRTVWXY2346789";
static void unbase24(BYTE *byteSeq, const char *cdKey);
static void base24(char *cdKey, BYTE *byteSeq);
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(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)
{
Serial = serialIn;
}
void setAuthInfo(DWORD AuthInfoIn)
{
AuthInfo = AuthInfoIn;
}
void setChannelID(DWORD ChannelIDIn)
{
ChannelID = ChannelIDIn;
}
};
#endif // UMSKT_PIDGEN3_H

View File

@ -1,97 +0,0 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 5/26/2023
* @Maintainer Andrew
*/
#include "PIDGEN3.h"
/* Converts from CD-key to a byte sequence. */
void PIDGEN3::unbase24(BYTE *byteSeq, const char *cdKey)
{
BYTE pDecodedKey[PK_LENGTH + NULL_TERMINATOR]{};
BIGNUM *y = BN_new();
BN_zero(y);
// Remove dashes from the CD-key and put it into a Base24 byte array.
for (int i = 0, k = 0; i < strlen(cdKey) && k < PK_LENGTH; i++)
{
for (int j = 0; j < 24; j++)
{
if (cdKey[i] != '-' && cdKey[i] == pKeyCharset[j])
{
pDecodedKey[k++] = j;
break;
}
}
}
// Empty byte sequence.
memset(byteSeq, 0, 16);
// Calculate the weighed sum of byte array elements.
for (int i = 0; i < PK_LENGTH; i++)
{
BN_mul_word(y, PK_LENGTH - 1);
BN_add_word(y, pDecodedKey[i]);
}
// Acquire length.
int n = BN_num_bytes(y);
// Place the generated code into the byte sequence.
BN_bn2bin(y, byteSeq);
BN_free(y);
// Reverse the byte sequence.
endian(byteSeq, n);
}
/* Converts from byte sequence to the CD-key. */
void PIDGEN3::base24(char *cdKey, BYTE *byteSeq)
{
BYTE rbyteSeq[16];
BIGNUM *z;
// Copy byte sequence to the reversed byte sequence.
memcpy(rbyteSeq, byteSeq, sizeof(rbyteSeq));
// Skip trailing zeroes and reverse y.
int length;
for (length = 15; rbyteSeq[length] == 0; length--)
{
;
}
endian(rbyteSeq, ++length);
// Convert reversed byte sequence to BigNum z.
z = BN_bin2bn(rbyteSeq, length, nullptr);
// Divide z by 24 and convert the remainder to a CD-key char.
cdKey[25] = 0;
for (int i = 24; i >= 0; i--)
{
cdKey[i] = pKeyCharset[BN_div_word(z, 24)];
}
BN_free(z);
}

View File

@ -1,131 +0,0 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Andrew on 01/06/2023
* @Maintainer Andrew
*/
#include "PIDGEN3.h"
int randomRange()
{
return 4; // chosen by fair dice roll
// guaranteed to be random
}
/* Convert data between endianness types. */
void PIDGEN3::endian(BYTE *data, int length)
{
for (int i = 0; i < length / 2; i++)
{
BYTE temp = data[i];
data[i] = data[length - i - 1];
data[length - i - 1] = temp;
}
}
/* Initializes the elliptic curve. */
EC_GROUP *PIDGEN3::initializeEllipticCurve(const std::string pSel, const std::string aSel, const std::string bSel,
const std::string generatorXSel, const std::string generatorYSel,
const std::string publicKeyXSel, const std::string publicKeyYSel,
EC_POINT *&genPoint, EC_POINT *&pubPoint)
{
// Initialize BIGNUM and BIGNUMCTX structures.
// BIGNUM - Large numbers
// BIGNUMCTX - Context large numbers (temporary)
BIGNUM *a, *b, *p, *generatorX, *generatorY, *publicKeyX, *publicKeyY;
BN_CTX *context;
// We're presented with an elliptic curve, a multivariable function y(x; p; a; b), where
// y^2 % p = x^3 + ax + b % p.
a = BN_new();
b = BN_new();
p = BN_new();
// Public key will consist of the resulting (x; y) values.
publicKeyX = BN_new();
publicKeyY = BN_new();
// G(x; y) is a generator function, its return value represents a point on the elliptic curve.
generatorX = BN_new();
generatorY = BN_new();
// Context variable
context = BN_CTX_new();
/* Public data */
BN_dec2bn(&p, pSel.c_str());
BN_dec2bn(&a, aSel.c_str());
BN_dec2bn(&b, bSel.c_str());
BN_dec2bn(&generatorX, generatorXSel.c_str());
BN_dec2bn(&generatorY, generatorYSel.c_str());
BN_dec2bn(&publicKeyX, publicKeyXSel.c_str());
BN_dec2bn(&publicKeyY, publicKeyYSel.c_str());
/* Elliptic Curve calculations. */
// The group is defined via Fp = all integers [0; p - 1], where p is prime.
// The function EC_POINT_set_affine_coordinates() sets the x and y coordinates for the point p defined over the
// curve given in group.
EC_GROUP *eCurve = EC_GROUP_new_curve_GFp(p, a, b, context);
// Create new point for the generator on the elliptic curve and set its coordinates to (genX; genY).
genPoint = EC_POINT_new(eCurve);
EC_POINT_set_affine_coordinates(eCurve, genPoint, generatorX, generatorY, context);
// Create new point for the public key on the elliptic curve and set its coordinates to (pubX; pubY).
pubPoint = EC_POINT_new(eCurve);
EC_POINT_set_affine_coordinates(eCurve, pubPoint, publicKeyX, publicKeyY, context);
// If generator and public key points are not on the elliptic curve, either the generator or the public key values
// are incorrect.
assert(EC_POINT_is_on_curve(eCurve, genPoint, context) == true);
assert(EC_POINT_is_on_curve(eCurve, pubPoint, context) == true);
// Cleanup
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 eCurve;
}
int PIDGEN3::BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen)
{
if (a == nullptr || to == nullptr)
{
return 0;
}
int len = BN_bn2bin(a, to);
if (len > tolen)
{
return -1;
}
// Choke point inside BN_bn2lebinpad: OpenSSL uses len instead of tolen.
endian(to, tolen);
return len;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -21,47 +21,15 @@
*/
#include "cli.h"
#include "header.h"
Options options;
int main(int argc, char *argv[])
{
if (!CLI::parseCommandLine(argc, argv, &options))
{
fmt::print("error parsing command line options\n");
CLI::showHelp(argv);
return !options.error ? 0 : 1;
}
json keys;
int status = CLI::validateCommandLine(&options, argv, &keys);
if (status > 0)
int status;
if (status = CLI::Init(argc, argv); status > 0)
{
return status;
}
CLI run(options, keys);
switch (options.applicationMode)
{
case MODE_BINK1998_GENERATE:
return run.BINK1998Generate();
case MODE_BINK2002_GENERATE:
return run.BINK2002Generate();
case MODE_BINK1998_VALIDATE:
return run.BINK1998Validate();
case MODE_BINK2002_VALIDATE:
return run.BINK2002Validate();
case MODE_CONFIRMATION_ID:
return run.ConfirmationID();
default:
return 1;
}
auto cli = CLI();
return cli.Run();
}

318
src/options.cpp Normal file
View File

@ -0,0 +1,318 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 01/02/2024
* @Maintainer Neo
*/
#include "cli.h"
// define static storage
std::array<CLIHelpOptions, CLIHelpOptionID_END> CLI::helpOptions;
void CLI::SetHelpText()
{
helpOptions[OPTION_HELP] = {"h", "help", "show this help text", false, "", &DisplayHelp};
helpOptions[OPTION_VERBOSE] = {"v", "verbose", "enable verbose output", false, "", &SetVerboseOption};
helpOptions[OPTION_DEBUG] = {"d", "debug", "enable debug output", false, "", &SetDebugOption};
helpOptions[OPTION_FILE] = {"f", "file", "specify which keys file to load", true, "", &SetFileOption};
helpOptions[OPTION_LIST] = {"l", "list", "list supported products", false, "", &SetListOption};
helpOptions[OPTION_NUMBER] = {"n", "number", "(PIDGEN only) number of keys to generate",
true, "1", &SetNumberOption};
helpOptions[OPTION_PRODUCT] = {"p", "product", "which product to generate keys for",
true, options.productCode, nullptr};
helpOptions[OPTION_ACTIVATIONID] = {
"i", "instid", "(activation only) installation ID used to generate confirmation ID",
true, "", &SetActivationIDOption};
helpOptions[OPTION_ACTIVATIONPID] = {
"P", "productid", "(Office activation only) product ID to generate confirmation ID for",
true, "", &SetProductIDOption};
helpOptions[OPTION_OEM] = {"o", "oem", "\t(PIDGEN) generate an OEM key", false, "", &SetOEMOption};
helpOptions[OPTION_UPGRADE] = {"u", "upgrade", "(PIDGEN 3 only) generate an upgrade key",
false, "", &SetUpgradeOption};
helpOptions[OPTION_BINK] = {"b", "binkid", "(advanced) override which BINK identifier to load",
true, "", &SetBINKOption};
helpOptions[OPTION_CHANNELID] = {"c", "channelid", "(advanced) override which product channel to use",
true, "", &SetChannelIDOption};
helpOptions[OPTION_SERIAL] = {
"s", "serial", "(advanced, PIDGEN 2/3 [BINK 1998] only) specify a serial to generate",
true, "", &SetSerialOption};
helpOptions[OPTION_AUTHDATA] = {
"a", "authdata", "(advanced, PIDGEN 3 [BINK 2000] only) specify a value for the authentication data field",
true, "", nullptr};
helpOptions[OPTION_VALIDATE] = {
"V", "validate", "validate a specified product ID against known BINKs and algorithms",
true, "", &SetValidateOption};
}
/**
*
* @return success
*/
BOOL CLI::parseCommandLine()
{
for (DWORD i = 1; i < options.argc; i++)
{
std::string arg = options.argv[i];
if (arg[0] == '-')
{
arg.erase(0, 1);
}
if (arg[0] == '-')
{
arg.erase(0, 1);
}
if (arg.empty())
{
continue;
}
for (BYTE j = 0; j < CLIHelpOptionID_END; j++)
{
if (arg != helpOptions[j].Short && arg != helpOptions[j].Long)
{
continue;
}
std::string nextarg;
if (helpOptions[j].hasArguments)
{
if (i == options.argc - 1)
{
options.error = true;
goto CommandLineParseEnd;
}
else
{
nextarg = arg[i + 1];
}
}
auto success = helpOptions[j].handler(1, &nextarg[0]);
if (!success)
{
options.error = true;
goto CommandLineParseEnd;
}
if (options.help)
{
goto CommandLineParseEnd;
}
goto ParseNextCommandLineOption;
}
fmt::print("unknown option: {}\n", arg);
options.error = true;
goto CommandLineParseEnd;
ParseNextCommandLineOption:
continue;
}
CommandLineParseEnd:
if (options.error)
{
DisplayErrorMessage(0, nullptr);
}
return !options.error;
}
/**
*
* @return success
*/
BOOL CLI::DisplayHelp(int, char *)
{
options.help = true;
fmt::print("usage: {} \n", options.argv[0]);
for (BYTE i = 0; i < CLIHelpOptionID_END; i++)
{
CLIHelpOptions o = helpOptions[i];
fmt::print(" -{} --{}\t{}", o.Short, o.Long, o.HelpText);
if (!o.Default.empty())
{
fmt::print(" (defaults to {})", o.Default);
}
fmt::print("\n");
}
fmt::print("\n");
return true;
}
BOOL CLI::DisplayErrorMessage(int, char *)
{
fmt::print("error parsing command line options\n");
DisplayHelp(0, nullptr);
options.error = true;
return false;
}
BOOL CLI::SetVerboseOption(int, char *)
{
fmt::print("enabling verbose option\n");
options.verbose = true;
UMSKT::VERBOSE = true;
UMSKT::setDebugOutput(stderr);
return true;
}
BOOL CLI::SetDebugOption(int, char *)
{
fmt::print("enabling debug option\n");
options.verbose = true;
UMSKT::DEBUG = true;
UMSKT::setDebugOutput(stderr);
return true;
}
BOOL CLI::SetListOption(int, char *)
{
options.list = true;
return true;
}
BOOL CLI::SetOEMOption(int, char *)
{
options.oem = true;
return true;
}
BOOL CLI::SetUpgradeOption(int, char *)
{
options.upgrade = true;
return true;
}
BOOL CLI::SetFileOption(int count, char *file)
{
options.keysFilename = file;
return true;
}
BOOL CLI::SetNumberOption(int count, char *num)
{
int nKeys;
if (!sscanf(num, "%d", &nKeys))
{
return false;
}
options.numKeys = nKeys;
return true;
}
/**
*
* @param count
* @param channum
* @return
*/
BOOL CLI::SetChannelIDOption(int count, char *channum)
{
int siteID;
if (!sscanf(channum, "%d", &siteID))
{
return false;
}
// channel ids must be between 000 and 999
if (siteID > 999)
{
fmt::print("ERROR: refusing to create a key with a Channel ID greater than 999\n");
return false;
}
options.channelID = siteID;
return true;
}
BOOL CLI::SetBINKOption(int count, char *bink)
{
options.binkid = bink;
return true;
}
/**
*
* @param count
* @param arg
* @return
*/
BOOL CLI::SetSerialOption(int count, char *arg)
{
int serial_val;
if (!sscanf(arg, "%d", &serial_val))
{
return false;
}
// serials must be between 000000 and 999999
if (serial_val > 999999)
{
fmt::print("ERROR: refusing to create a key with a Serial not between 000000 and 999999\n");
return false;
}
options.serialSet = true;
options.serial = serial_val;
return true;
}
BOOL CLI::SetActivationIDOption(int count, char *aid)
{
options.instid = aid;
options.state = STATE_CONFIRMATION_ID;
return true;
}
BOOL CLI::SetProductIDOption(int count, char *product)
{
if (options.verbose)
{
fmt::print("Setting product ID to {}", product);
}
options.productid = product;
return true;
}
BOOL CLI::SetValidateOption(int count, char *product)
{
options.keyToCheck = product;
return true;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,26 +16,45 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 5/26/2023
* @FileCreated by Neo on 01/02/2024
* @Maintainer Neo
*/
#ifndef UMSKT_HEADER_H
#define UMSKT_HEADER_H
#ifndef UMSKT_OPTIONS_H
#define UMSKT_OPTIONS_H
#include "typedefs.h"
typedef BOOL CLIHandlerFunc(int, char *);
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
enum CLIHelpOptionIDs
{
OPTION_HELP,
OPTION_VERBOSE,
OPTION_DEBUG,
OPTION_FILE,
OPTION_LIST,
OPTION_NUMBER,
OPTION_PRODUCT,
OPTION_OEM,
OPTION_UPGRADE,
OPTION_ACTIVATIONID,
OPTION_ACTIVATIONPID,
OPTION_BINK,
OPTION_CHANNELID,
OPTION_SERIAL,
OPTION_AUTHDATA,
OPTION_VALIDATE,
#include <fmt/core.h>
#include <nlohmann/json.hpp>
CLIHelpOptionID_END
};
using json = nlohmann::json;
namespace fs = std::filesystem;
struct CLIHelpOptions
{
std::string Short;
std::string Long;
std::string HelpText;
BOOL hasArguments;
std::string Default;
CLIHandlerFunc *handler;
};
#endif // UMSKT_HEADER_H
#endif // UMSKT_OPTIONS_H

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/24/2023
* @FileCreated by Neo on 06/24/2023
* @Maintainer Neo
*/
@ -29,13 +29,19 @@
#ifdef DEBUG
#include <cassert>
#else
#define assert(x) /* nothing */
#define assert(x) /* do nothing */
#endif
#ifdef _MSC_VER
#define EXPORT extern "C" __declspec(dllexport)
#define INLINE __forceinline
#elif defined(__GNUC__)
#define EXPORT extern "C" __attribute__((visibility("default")))
#define INLINE __attribute__((always_inline))
#else
#define EXPORT extern "C"
#define INLINE
#warning "function inlining not handled"
#endif
#ifdef __EMSCRIPTEN__
@ -45,6 +51,21 @@
#define FNEXPORT EXPORT
#endif
#ifdef _MSC_VER
#ifndef strncasecmp
#define strncasecmp _strnicmp
#endif
#ifndef strcasecmp
#define strcasecmp _stricmp
#endif
#ifndef strcmp
#define strcmp strcmp_s
#endif
#ifndef sscanf
#define sscanf sscanf_s
#endif
#endif
// Type definitions
typedef bool BOOL;
typedef uint8_t BYTE;
@ -56,4 +77,12 @@ typedef uint64_t QWORD;
typedef unsigned __int128 OWORD;
#endif
typedef union {
// OWORD oword;
QWORD qword[2];
DWORD dword[4];
WORD word[8];
BYTE byte[16];
} Q_OWORD;
#endif // UMSKT_TYPEDEFS_H

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/17/2023
* @FileCreated by Neo on 06/17/2023
* @Maintainer Neo
*/

Binary file not shown.