mirror of
https://github.com/Neo-Desktop/WindowsXPKg
synced 2024-12-22 04:20:17 +02:00
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:
parent
c0a4c76b54
commit
bf6365916d
@ -213,4 +213,8 @@ WhitespaceSensitiveMacros:
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
...
|
||||
---
|
||||
Language: Json
|
||||
BasedOnStyle: LLVM
|
||||
...
|
||||
|
||||
|
2
.github/workflows/dos-djgpp.yml
vendored
2
.github/workflows/dos-djgpp.yml
vendored
@ -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
|
||||
|
38
.github/workflows/freebsd.yml
vendored
38
.github/workflows/freebsd.yml
vendored
@ -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)
|
||||
|
||||
|
2
.github/workflows/linux.yml
vendored
2
.github/workflows/linux.yml
vendored
@ -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
|
||||
|
2
.github/workflows/macos.yml
vendored
2
.github/workflows/macos.yml
vendored
@ -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
|
||||
|
2
.github/workflows/windows.yml
vendored
2
.github/workflows/windows.yml
vendored
@ -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
generated
Normal file
14
.idea/remote-targets.xml
generated
Normal 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 , stderr=}/UMSKT" />
|
||||
</config>
|
||||
</target>
|
||||
</targets>
|
||||
</component>
|
||||
</project>
|
25
.pre-commit-config.yaml
Normal file
25
.pre-commit-config.yaml
Normal 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
|
121
CMakeLists.txt
121
CMakeLists.txt
@ -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 ()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
717
src/cli.cpp
717
src/cli.cpp
@ -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
128
src/cli.h
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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++)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
258
src/libumskt/pidgen3/PIDGEN3.cpp
Normal file
258
src/libumskt/pidgen3/PIDGEN3.cpp
Normal 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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
42
src/main.cpp
42
src/main.cpp
@ -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
318
src/options.cpp
Normal 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;
|
||||
}
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
Loading…
Reference in New Issue
Block a user