From bf6365916dccc25ed77cf699cfba30894d4ef909 Mon Sep 17 00:00:00 2001 From: Neo-Desktop <321592+Neo-Desktop@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:32:18 -0800 Subject: [PATCH] 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 --- .clang-format | 4 + .github/workflows/dos-djgpp.yml | 2 +- .github/workflows/freebsd.yml | 38 +- .github/workflows/linux.yml | 2 +- .github/workflows/macos.yml | 2 +- .github/workflows/windows.yml | 2 +- .idea/remote-targets.xml | 14 + .pre-commit-config.yaml | 25 + CMakeLists.txt | 121 ++-- Dockerfile | 2 +- Dockerfile.djgpp | 2 +- Dockerfile.emscripten | 2 +- Dockerfile.windows | 2 +- keys.json | 932 +++++++++++++++++++++++------ src/cli.cpp | 717 ++++++++++------------ src/cli.h | 128 ++-- src/libumskt/confid/confid.cpp | 253 ++++---- src/libumskt/confid/confid.h | 168 +++--- src/libumskt/confid/divisor.cpp | 46 +- src/libumskt/confid/polynomial.cpp | 24 +- src/libumskt/confid/residue.cpp | 49 +- src/libumskt/debugoutput.cpp | 15 +- src/libumskt/libumskt.cpp | 145 ++++- src/libumskt/libumskt.h | 18 +- src/libumskt/pidgen2/PIDGEN2.cpp | 5 +- src/libumskt/pidgen2/PIDGEN2.h | 30 +- src/libumskt/pidgen3/BINK1998.cpp | 106 ++-- src/libumskt/pidgen3/BINK1998.h | 19 +- src/libumskt/pidgen3/BINK2002.cpp | 116 ++-- src/libumskt/pidgen3/BINK2002.h | 20 +- src/libumskt/pidgen3/PIDGEN3.cpp | 258 ++++++++ src/libumskt/pidgen3/PIDGEN3.h | 72 ++- src/libumskt/pidgen3/key.cpp | 97 --- src/libumskt/pidgen3/util.cpp | 131 ---- src/main.cpp | 42 +- src/options.cpp | 318 ++++++++++ src/{header.h => options.h} | 51 +- src/typedefs.h | 35 +- src/windows/dllmain.cpp | 2 +- src/windows/resource.h | 4 +- src/windows/umskt.rc | Bin 4976 -> 4978 bytes 41 files changed, 2571 insertions(+), 1448 deletions(-) create mode 100644 .idea/remote-targets.xml create mode 100644 .pre-commit-config.yaml create mode 100644 src/libumskt/pidgen3/PIDGEN3.cpp delete mode 100644 src/libumskt/pidgen3/key.cpp delete mode 100644 src/libumskt/pidgen3/util.cpp create mode 100644 src/options.cpp rename src/{header.h => options.h} (50%) diff --git a/.clang-format b/.clang-format index 674336e..b75ce03 100644 --- a/.clang-format +++ b/.clang-format @@ -213,4 +213,8 @@ WhitespaceSensitiveMacros: - NS_SWIFT_NAME - CF_SWIFT_NAME ... +--- +Language: Json +BasedOnStyle: LLVM +... diff --git a/.github/workflows/dos-djgpp.yml b/.github/workflows/dos-djgpp.yml index d28d938..a6d370d 100644 --- a/.github/workflows/dos-djgpp.yml +++ b/.github/workflows/dos-djgpp.yml @@ -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 diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml index bc75a3a..358c839 100644 --- a/.github/workflows/freebsd.yml +++ b/.github/workflows/freebsd.yml @@ -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 . - # - # @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 . +# +# @FileCreated by techguy16 on 07/23/2023 +# @Maintainer techguy16 name: C/C++ CI (FreeBSD) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index a2c790b..f60478f 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -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 diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 74a3d68..cf689dc 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -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 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 99857d4..84177bb 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -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 diff --git a/.idea/remote-targets.xml b/.idea/remote-targets.xml new file mode 100644 index 0000000..e8ce669 --- /dev/null +++ b/.idea/remote-targets.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..a8f316b --- /dev/null +++ b/.pre-commit-config.yaml @@ -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 . +# +# @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 \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bcac58..dab7308 100644 --- a/CMakeLists.txt +++ b/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$<$: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 () diff --git a/Dockerfile b/Dockerfile index 81cea46..58daeb1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 diff --git a/Dockerfile.djgpp b/Dockerfile.djgpp index 4f0784a..a718689 100644 --- a/Dockerfile.djgpp +++ b/Dockerfile.djgpp @@ -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 diff --git a/Dockerfile.emscripten b/Dockerfile.emscripten index e7e6bad..af3fcee 100644 --- a/Dockerfile.emscripten +++ b/Dockerfile.emscripten @@ -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 diff --git a/Dockerfile.windows b/Dockerfile.windows index 30711aa..5c23d1c 100644 --- a/Dockerfile.windows +++ b/Dockerfile.windows @@ -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 diff --git a/keys.json b/keys.json index f5a144b..873ae55 100644 --- a/keys.json +++ b/keys.json @@ -1,154 +1,750 @@ { "Products": { - "Windows CE Platform Builder 3": { - "BINK": ["00", "01", "0E", "0D", "0F"] + "WINCEPB3": { + "Name": "Windows CE Platform Builder 3", + "BINK": [ + "00", + "01", + "0E", + "0D", + "0F" + ] }, - "Windows CE .Net Platform Builder 4": { - "BINK": ["00", "01"] + "WINCEPB4": { + "Name": "Windows CE .Net Platform Builder 4", + "BINK": [ + "00", + "01" + ] }, - "Windows 98 (all)": { - "BINK": ["02","03"] + "WIN98": { + "Name": "Windows 98 (all types)", + "BINK": [ + "02", + "03" + ] }, - "Office 2000": { - "BINK": ["04", "05"] + "OFFICE2K": { + "Name": "Office 2000 (all variants)", + "BINK": [ + "04", + "05" + ] }, - "Internet Security and Acceleration (ISA) Server 2004": { - "BINK": ["06", "07"] + "ISA2K4": { + "Name": "Internet Security and Acceleration (ISA) Server 2004", + "BINK": [ + "06", + "07" + ] }, - "PLUS! for Windows XP": { - "BINK": ["08", "09"] + "PLUSXP": { + "Name": "PLUS! for Windows XP", + "BINK": [ + "08", + "09" + ] }, - "Windows 2000 Server (all)": { - "BINK": ["0A", "13"] + "WIN2KSVR": { + "Name": "Windows 2000 Server (all types)", + "BINK": [ + "0A", + "13" + ] }, - "Office Communicator 2007": { - "BINK": ["0C", "0D"] + "OFFICEC2007": { + "Name": "Office Communicator 2007", + "BINK": [ + "0C", + "0D" + ] }, - "Windows Embedded POSReady 2009": { - "BINK": ["0D", "0D"] + "POS2009": { + "Name": "Windows Embedded POSReady 2009", + "BINK": [ + "0D", + "0D" + ], + "DPC": { + "0D": [ + { + "Min": 100, + "Max": 199, + "IsEvaluation": true, + "EvaluationDays": 125 + }, + { + "Min": 200, + "Max": 619, + "IsEvaluation": false + }, + { + "Min": 940, + "Max": 960, + "IsEvaluation": false + }, + { + "Min": 963, + "Max": 979, + "IsEvaluation": false + }, + { + "Min": 985, + "Max": 986, + "IsEvaluation": false + }, + { + "Min": 996, + "Max": 996, + "IsEvaluation": true, + "EvaluationDays": 125 + }, + { + "Min": 997, + "Max": 997, + "IsEvaluation": true, + "EvaluationDays": 370 + }, + { + "Min": 998, + "Max": 998, + "IsEvaluation": false + }, + { + "Min": 620, + "Max": 620, + "IsEvaluation": false + }, + { + "Min": 621, + "Max": 621, + "IsEvaluation": false + }, + { + "Min": 622, + "Max": 622, + "IsEvaluation": true, + "EvaluationDays": 125 + }, + { + "Min": 623, + "Max": 623, + "IsEvaluation": true, + "EvaluationDays": 370 + } + ] + } }, - "Windows CE .Net Platform Builder 5": { - "BINK": ["0D", "0D"] + "WINCDPB5": { + "Name": "Windows CE .Net Platform Builder 5", + "BINK": [ + "0D", + "0D" + ] }, - "Commerce Server 2002": { - "BINK": ["0E", "0F"] + "CSERV2K2": { + "Name": "Commerce Server 2002", + "BINK": [ + "0E", + "0F" + ] }, - "Windows 2000 Professional": { - "BINK": ["12", "13"] + "WIN2K": { + "Name": "Windows 2000 Professional", + "BINK": [ + "12", + "13" + ] }, - "Office for Mac 2004 / 2008": { - "BINK": ["18", "19"] + "OFFICEMAC2KX": { + "Name": "Office for Mac 2004 / 2008", + "BINK": [ + "18", + "19" + ] }, - "Windows ME": { - "BINK": ["1C", "1D"] + "WINME": { + "Name": "Windows ME", + "BINK": [ + "1C", + "1D" + ] }, - "Office XP Applications": { - "BINK": ["20", "21"] + "OFFICEXPA": { + "Name": "Office XP Applications", + "BINK": [ + "20", + "21" + ] }, - "Works Suite 2003 and 2004": { - "BINK": ["20", "21"] + "WORKS2K3X": { + "Name": "Works Suite 2003 and 2004", + "BINK": [ + "20", + "21" + ] }, - "Office XP": { - "BINK": ["22", "23"] + "OFFICEXP": { + "Name": "Office XP", + "BINK": [ + "22", + "23" + ], + "Activation": "OFFICEXP" }, - "Visual Studio .Net / .Net 2003": { - "BINK": ["24", "25"] + "VSNET2KX": { + "Name": "Visual Studio .Net / .Net 2003", + "BINK": [ + "24", + "25" + ] }, - "Windows XP Professional Evaluation": { - "BINK": ["28", "29"] + "WINXPPEVAL": { + "Name": "Windows XP Professional Evaluation", + "BINK": [ + "28", + "29" + ], + "Activation": "WINXP" }, - "Windows XP Home": { - "BINK": ["2A", "2B"] + "WINXPH": { + "Name": "Windows XP Home", + "BINK": [ + "2A", + "2B" + ], + "DPC": { + "2A": [ + { + "Min": 5, + "Max": 85, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 337, + "Max": 359, + "IsEvaluation": false, + "ActivationGraceDays": "60" + }, + { + "Min": 755, + "Max": 779, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 106, + "Max": 106, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 187, + "Max": 187, + "IsEvaluation": false, + "ActivationGraceDays": "60" + }, + { + "Min": 188, + "Max": 188, + "IsEvaluation": false, + "ActivationGraceDays": "60" + }, + { + "Min": 362, + "Max": 376, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 377, + "Max": 377, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 984, + "Max": 984, + "IsEvaluation": false, + "ActivationGraceDays": "30" + } + ], + "2B": [ + { + "Min": 119, + "Max": 119, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 120, + "Max": 169, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 400, + "Max": 665, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 667, + "Max": 699, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 700, + "Max": 754, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 85, + "Max": 85, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 86, + "Max": 95, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 96, + "Max": 105, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 170, + "Max": 186, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 189, + "Max": 189, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 190, + "Max": 190, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 191, + "Max": 191, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 107, + "Max": 118, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 192, + "Max": 336, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 755, + "Max": 899, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 921, + "Max": 979, + "IsEvaluation": false, + "ActivationGraceDays": "30" + } + ] + }, + "Activation": "WINXP" }, - "Windows XP Pro": { - "BINK": ["2C", "2D"] + "WINXPP": { + "Name": "Windows XP Pro", + "BINK": [ + "2C", + "2D" + ], + "Activation": "WINXP" }, - "Windows XP Pro IA-64": { - "BINK": ["2C", "2D"] + "WINXPPIA64": { + "Name": "Windows XP Pro IA-64", + "BINK": [ + "2C", + "2D" + ] }, - "Windows XP Pro VLK": { - "BINK": ["2E", "2F"] + "WINXPPVLK": { + "Name": "Windows XP Pro VLK", + "BINK": [ + "2E", + "2F" + ], + "DPC": { + "2E": [ + { + "Min": 640, + "Max": 699, + "IsEvaluation": false + }, + { + "Min": 700, + "Max": 701, + "IsEvaluation": false + }, + { + "Min": 704, + "Max": 705, + "IsEvaluation": false + } + ] + }, + "Exclusions": [ + "640200176", + "640000035" + ] }, - "Windows XP Fundamentals for Legacy PCs": { - "BINK": ["2E", "2F"] + "WINXPFLPC": { + "Name": "Windows XP Fundamentals for Legacy PCs", + "BINK": [ + "2E", + "2F" + ], + "Activation": "WINXP" }, - "Windows XP Professional K": { - "BINK": ["30", "31"] + "WINXPK": { + "Name": "Windows XP Professional K", + "BINK": [ + "30", + "31" + ], + "Activation": "WINXP" }, - "Windows XP Starter Edition": { - "BINK": ["32", "33"] + "WINXPSE": { + "Name": "Windows XP Starter Edition", + "BINK": [ + "32", + "33" + ], + "Activation": "WINXP" }, - "Windows Longhorn (6.0.3683.0 -> 6.0.4029.0)": { - "BINK": ["40", "41"] + "WINLH4029": { + "Name": "Windows Longhorn (6.0.3683.0 -> 6.0.4029.0)", + "BINK": [ + "40", + "41" + ] }, - "Halo: Combat Evolved": { - "BINK": ["50", "51"] + "HALOCE": { + "Name": "Halo: Combat Evolved/Custom Edition", + "BINK": [ + "50", + "51" + ] }, - "Halo: Custom Edition": { - "BINK": ["50", "51"] + "VS2K5": { + "Name": "Visual Studio 2005", + "BINK": [ + "52", + "53" + ] }, - "Visual Studio 2005": { - "BINK": ["52", "53"] + "WINXPDME": { + "Name": "Plus! Digital Media Edition for Windows XP", + "BINK": [ + "52", + "53" + ], + "Activation": "PLUSDME" }, - "Plus! Digital Media Edition for Windows XP": { - "BINK": ["52", "53"] + "RONROL": { + "Name": "Rise of Nations - Rise of Legends", + "BINK": [ + "52", + "53" + ] }, - "Rise of Nations - Rise of Legends": { - "BINK": ["52", "53"] + "WINLH4033": { + "Name": "Windows Longhorn (6.0.4033.0)", + "BINK": [ + "54", + "55" + ] }, - "Windows Longhorn (6.0.4033.0)": { - "BINK": ["54", "55"] + "WINSVR2K3": { + "Name": "Windows Server 2003", + "BINK": [ + "54", + "55", + "58", + "59" + ], + "Activation": "WINSVR2K3", + "DPC": { + "54": [ + { + "Min": 5, + "Max": 84, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 337, + "Max": 369, + "IsEvaluation": false, + "ActivationGraceDays": "60" + }, + { + "Min": 755, + "Max": 780, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 781, + "Max": 789, + "IsEvaluation": false, + "ActivationGraceDays": "30" + } + ], + "55": [ + { + "Min": 119, + "Max": 119, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 120, + "Max": 169, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 170, + "Max": 269, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 400, + "Max": 699, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 700, + "Max": 754, + "IsEvaluation": false, + "ActivationGraceDays": "30" + } + ] + } }, - "Windows Server 2003": { - "BINK": ["54", "55", "58", "59"] + "WINSVR2K3VLK": { + "Name": "Windows Server 2003 VLK", + "BINK": [ + "5A", + "5B" + ], + "DPC": { + "5A": [ + { + "Min": 640, + "Max": 642, + "IsEvaluation": false + } + ] + }, + "Exclusions": [ + "640200176", + "640000035" + ] }, - "Windows Server 2003 VLK": { - "BINK": ["5A", "5B"] + "WINXPP64BVLK": { + "Name": "Windows XP Pro 64 Bit Edition VLK", + "BINK": [ + "64", + "65" + ], + "DPC": { + "64": [ + { + "Min": 1, + "Max": 2, + "IsEvaluation": true, + "ActivationGraceDays": "14" + }, + { + "Min": 640, + "Max": 649, + "IsEvaluation": false + }, + { + "Min": 652, + "Max": 657, + "IsEvaluation": false + } + ], + "Exclusions": [ + "640200176", + "640000035" + ] + } }, - "Windows XP Pro 64 Bit Edition VLK": { - "BINK": ["64", "65"] + "WINXPP64B": { + "Name": "Windows XP Pro 64 Bit Edition", + "BINK": [ + "66", + "67" + ], + "DPC": { + "66": [ + { + "Min": 306, + "Max": 370, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 371, + "Max": 410, + "IsEvaluation": false, + "ActivationGraceDays": "60" + } + ], + "67": [ + { + "Min": 5, + "Max": 118, + "IsEvaluation": false, + "ActivationGraceDays": "30" + }, + { + "Min": 119, + "Max": 119, + "IsEvaluation": false, + "ActivationGraceDays": "30" + } + ] + }, + "Activation": "WINXP" }, - "Windows XP Pro 64 Bit Edition": { - "BINK": ["66", "67"] + "WINSVR2K364B": { + "Name": "Windows Server 2003 64 Bit", + "BINK": [ + "68", + "69", + "6C", + "6D" + ], + "Activation": "WINSVR2K3" }, - "Windows Server 2003 64 Bit": { - "BINK": ["68", "69", "6C", "6D"] + "WINSVR2K3BVLK": { + "Name": "Windows Server 2003 64 Bit VLK", + "BINK": [ + "68", + "69", + "6C", + "6D" + ] }, - "Windows Server 2003 64 Bit VLK": { - "BINK": ["68", "69", "6C", "6D"] + "OFFICE2K3A": { + "Name": "Office 2003 Applications", + "BINK": [ + "6E", + "6F" + ], + "Activation": "OFFICE2K3" }, - "Office 2003 Applications": { - "BINK": ["6E", "6F"] + "OFFICE2K3SB": { + "Name": "Office 2003 Small Business", + "BINK": [ + "70", + "71" + ], + "Activation": "OFFICE2K3" }, - "Office 2003 Small Business": { - "BINK": ["70", "71"] + "OFFICE2K3ST": { + "Name": "Office 2003 Student and Teacher", + "BINK": [ + "70", + "71" + ], + "Activation": "OFFICE2K3" }, - "Office 2003 Student and Teacher": { - "BINK": ["70", "71"] + "OFFICE2K3PRO": { + "Name": "Office 2003 Professional", + "BINK": [ + "72", + "73" + ], + "Activation": "OFFICE2K3" }, - "Office 2003 Professional": { - "BINK": ["72", "73"] + "WINLHPREPX": { + "Name": "Windows Longhorn (6.0.4039.0 -> Pre PIDGENX)", + "BINK": [ + "74", + "75" + ] }, - "Windows Longhorn (6.0.4039.0 -> Pre PIDGENX)": { - "BINK": ["74", "75"] + "ILM2K7": { + "Name": "Identity Lifecycle Manager 2007", + "BINK": [ + "78", + "79" + ] }, - "Identity Lifecycle Manager 2007": { - "BINK": ["78", "79"] + "VS2K8": { + "Name": "Visual Studio 2008", + "BINK": [ + "78", + "79" + ] }, - "Visual Studio 2008": { - "BINK": ["78", "79"] + "OFFICE2K7A": { + "Name": "Office 2007 Applications", + "BINK": [ + "7E", + "7F" + ], + "Activation": "OFFICE2K7" }, - "Office 2007 Applications": { - "BINK": ["7E", "7F"] + "OFFICE2K7SB": { + "Name": "Office 2007 Basic / Small Business", + "BINK": [ + "80", + "81" + ], + "Activation": "OFFICE2K7" }, - "Office 2007 Basic / Small Business": { - "BINK": ["80", "81"] + "OFFICE2K7": { + "Name": "Office 2007 Standard / Professional / Ultimate / Enterprise", + "BINK": [ + "82", + "83" + ], + "Activation": "OFFICE2K7" }, - "Office 2007 Standard / Professional / Ultimate / Enterprise": { - "BINK": ["82", "83"] - }, - "Office 2007 Home & Student": { - "BINK": ["88", "89"] + "OFFICE2K7HS": { + "Name": "Office 2007 Home & Student", + "BINK": [ + "88", + "89" + ], + "Activation": "OFFICE2K7" } }, "BINK": { @@ -1534,7 +2130,8 @@ } }, "Activation": { - "Windows XP": { + "WINXP": { + "Name": "Windows XP", "flags": { "XPBrand": true, "Office": false, @@ -1549,22 +2146,55 @@ "4": "90078616228674308", "5": "1" }, - "mul": "65537", "priv": "1315384396487572637498562978064321", "iid_key": "6AC85ED4", "non_residue": "43", - "mod_constants": { - "0": "0x604FA6A1C6346A87", - "1": "0x2D351C6D04F8B", - "2": "0x604FA6A1C6346A87", - "3": "0x2D351C6D04F8B" - }, - "verification": { - "low": "351874082296375233", - "hi": "71307131016268" - } + "quotient": "14670661154467966223547127731350151" }, - "Whistler": { + "WINSVR2K3": { + "Name": "Windows Server 2003", + "flags": { + "XPBrand": true, + "Office": false, + "version": 0 + }, + "p": "102011604035381881", + "x": { + "0": "0", + "1": "9433814980383617", + "2": "19168316694801104", + "3": "90078616228674308", + "4": "90078616228674308", + "5": "1" + }, + "priv": "1315384396487572637498562978064321", + "iid_key": "6AC85ED4", + "non_residue": "43", + "quotient": "14670661154467966223547127731350151" + }, + "WINLH": { + "Name": "Windows Longhorn - (pre-reset)", + "flags": { + "XPBrand": true, + "Office": false, + "version": 0 + }, + "p": "102011604035381881", + "x": { + "0": "0", + "1": "9433814980383617", + "2": "19168316694801104", + "3": "90078616228674308", + "4": "90078616228674308", + "5": "1" + }, + "priv": "1315384396487572637498562978064321", + "iid_key": "6AC85ED4", + "non_residue": "43", + "quotient": "14670661154467966223547127731350151" + }, + "WINWH": { + "Name": "Windows Whistler", "flags": { "XPBrand": false, "Office": false, @@ -1579,22 +2209,13 @@ "4": "57597400967455908", "5": "1" }, - "mul": "", - "priv": "", + "priv": "4420101814959421052277784766820305", "iid_key": "6AC85ED4", "non_residue": "2", - "mod_constants": { - "0": "", - "1": "", - "2": "", - "3": "" - }, - "verification": { - "low": "", - "hi": "" - } + "quotient": "14613149284703660878250367809118961" }, - "Office XP": { + "OFFICEXP": { + "Name": "Office XP", "flags": { "XPBrand": true, "Office": true, @@ -1609,22 +2230,13 @@ "4": "64728167274549202", "5": "1" }, - "mul": "65537", "priv": "10294349293510589382098112327865153", "iid_key": "5A30B9F3", "non_residue": "3", - "mod_constants": { - "0": "0x4FA8E4A40CDAE44A", - "1": "0x2CBAF12A59BBE", - "2": "0x4FA8E4A40CDAE44A", - "3": "0x2CBAF12A59BBE" - }, - "verification": { - "low": "17284868327322833729", - "hi": "558057793417439" - } + "quotient": "14515793565989355059134123881456714" }, - "Office 2003": { + "OFFICE2K3": { + "Name": "Office 2003", "flags": { "XPBrand": false, "Office": true, @@ -1639,22 +2251,13 @@ "4": "64728167274549202", "5": "1" }, - "mul": "65537", "priv": "10294349293510589382098112327865153", "iid_key": "5A30B9F3", "non_residue": "3", - "mod_constants": { - "0": "0x4FA8E4A40CDAE44A", - "1": "0x2CBAF12A59BBE", - "2": "0x4FA8E4A40CDAE44A", - "3": "0x2CBAF12A59BBE" - }, - "verification": { - "low": "17284868327322833729", - "hi": "558057793417439" - } + "quotient": "14515793565989355059134123881456714" }, - "Office 2007": { + "OFFICE2K7": { + "Name": "Office 2007", "flags": { "XPBrand": false, "Office": true, @@ -1669,22 +2272,13 @@ "4": "64728167274549202", "5": "1" }, - "mul": "65537", "priv": "10294349293510589382098112327865153", "iid_key": "5A30B9F3", "non_residue": "3", - "mod_constants": { - "0": "0x4FA8E4A40CDAE44A", - "1": "0x2CBAF12A59BBE", - "2": "0x4FA8E4A40CDAE44A", - "3": "0x2CBAF12A59BBE" - }, - "verification": { - "low": "17284868327322833729", - "hi": "558057793417439" - } + "quotient": "14515793565989355059134123881456714" }, - "Plus! Digital Media Edition for Windows XP": { + "PLUSDME": { + "Name": "Plus! Digital Media Edition for Windows XP", "flags": { "XPBrand": true, "Office": false, @@ -1699,20 +2293,10 @@ "4": "6252462837094107", "5": "1" }, - "mul": "65537", "priv": "2752030625102368166730185283969067", "iid_key": "6AC85ED4", "non_residue": "2", - "mod_constants": { - "0": "0x2C5C4D3654A594F0", - "1": "0x2D36C691A4EA5", - "2": "0x2C5C4D3654A594F0", - "3": "0x2D36C691A4EA5" - }, - "verification": { - "low": "8953812210935468417", - "hi": "499255905936912" - } + "quotient": "14672771312721192311137265743402224" } } } diff --git a/src/cli.cpp b/src/cli.cpp index 2d4976d..16a2719 100644 --- a/src/cli.cpp +++ b/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().c_str(), "%x", &id); - std::cout << el.key() << ": " << el.value()["BINK"] << std::endl; + sscanf(&(el["BINK"][0]).get()[0], "%x", &id); + fmt::print("{}\n\tName: {}\n\tBINKs: ", i.key(), el["Name"].get()); + 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(); + } + else + { + options.binkid = product["BINK"][0].get(); + } - // 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().c_str()); - BN_dec2bn(&this->privateKey, this->keys["BINK"][this->BINKID]["priv"].get().c_str()); + std::vector 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()) + { + filtered.push_back(el); + } + } + + // roll a die to choose which DPC entry to pick + auto rand = UMSKT::getRandom(); + auto dpc = filtered[rand % filtered.size()]; + auto min = dpc["Min"].get(), max = dpc["Max"].get(); + 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()); - fmt::print(" a: {}\n", this->keys["BINK"][this->BINKID]["a"].get()); - fmt::print(" b: {}\n", this->keys["BINK"][this->BINKID]["b"].get()); - fmt::print("Gx: {}\n", this->keys["BINK"][this->BINKID]["g"]["x"].get()); - fmt::print("Gy: {}\n", this->keys["BINK"][this->BINKID]["g"]["y"].get()); - fmt::print("Kx: {}\n", this->keys["BINK"][this->BINKID]["pub"]["x"].get()); - fmt::print("Ky: {}\n", this->keys["BINK"][this->BINKID]["pub"]["y"].get()); - fmt::print(" n: {}\n", this->keys["BINK"][this->BINKID]["n"].get()); - fmt::print(" k: {}\n", this->keys["BINK"][this->BINKID]["priv"].get()); + fmt::print(" P: {}\n", bink["p"].get()); + fmt::print(" a: {}\n", bink["a"].get()); + fmt::print(" b: {}\n", bink["b"].get()); + fmt::print("Gx: {}\n", bink["g"]["x"].get()); + fmt::print("Gy: {}\n", bink["g"]["y"].get()); + fmt::print("Kx: {}\n", bink["pub"]["x"].get()); + fmt::print("Ky: {}\n", bink["pub"]["y"].get()); + fmt::print(" n: {}\n", bink["n"].get()); + fmt::print(" k: {}\n", bink["priv"].get()); fmt::print("\n"); } - eCurve = PIDGEN3::initializeEllipticCurve(this->keys["BINK"][this->BINKID]["p"].get(), - this->keys["BINK"][this->BINKID]["a"].get(), - this->keys["BINK"][this->BINKID]["b"].get(), - this->keys["BINK"][this->BINKID]["g"]["x"].get(), - this->keys["BINK"][this->BINKID]["g"]["y"].get(), - this->keys["BINK"][this->BINKID]["pub"]["x"].get(), - this->keys["BINK"][this->BINKID]["pub"]["y"].get(), - this->genPoint, this->pubPoint); + pidgen3->LoadEllipticCurve(bink["p"].get(), bink["a"].get(), bink["b"].get(), + bink["g"]["x"].get(), bink["g"]["y"].get(), + bink["pub"]["x"].get(), bink["pub"]["y"].get(), + bink["n"].get(), bink["priv"].get()); - 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(); 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; } diff --git a/src/cli.h b/src/cli.h index 84ace37..22a8efe 100644 --- a/src/cli.h +++ b/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 . * - * @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 +#include +#include +#include +#include +#include #include +#include +#include + +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 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 diff --git a/src/libumskt/confid/confid.cpp b/src/libumskt/confid/confid.cpp index fbb6b1b..c04ecb5 100644 --- a/src/libumskt/confid/confid.cpp +++ b/src/libumskt/confid/confid.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 @@ -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; } diff --git a/src/libumskt/confid/confid.h b/src/libumskt/confid/confid.h index 09d933b..af54954 100644 --- a/src/libumskt/confid/confid.h +++ b/src/libumskt/confid/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 @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - * @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 diff --git a/src/libumskt/confid/divisor.cpp b/src/libumskt/confid/divisor.cpp index 8709a6e..c0cc63b 100644 --- a/src/libumskt/confid/divisor.cpp +++ b/src/libumskt/confid/divisor.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,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) { diff --git a/src/libumskt/confid/polynomial.cpp b/src/libumskt/confid/polynomial.cpp index cf3b888..2d37891 100644 --- a/src/libumskt/confid/polynomial.cpp +++ b/src/libumskt/confid/polynomial.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 @@ -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; } diff --git a/src/libumskt/confid/residue.cpp b/src/libumskt/confid/residue.cpp index 70ecd97..742c366 100644 --- a/src/libumskt/confid/residue.cpp +++ b/src/libumskt/confid/residue.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 @@ -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; -} \ No newline at end of file +} diff --git a/src/libumskt/debugoutput.cpp b/src/libumskt/debugoutput.cpp index 824d12f..9b5d8c6 100644 --- a/src/libumskt/debugoutput.cpp +++ b/src/libumskt/debugoutput.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 @@ -16,18 +16,27 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - * @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; diff --git a/src/libumskt/libumskt.cpp b/src/libumskt/libumskt.cpp index 608b22b..6bb14f5 100644 --- a/src/libumskt/libumskt.cpp +++ b/src/libumskt/libumskt.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 @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - * @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; +} \ No newline at end of file diff --git a/src/libumskt/libumskt.h b/src/libumskt/libumskt.h index 1631dbd..d73127e 100644 --- a/src/libumskt/libumskt.h +++ b/src/libumskt/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 @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - * @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 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 diff --git a/src/libumskt/pidgen2/PIDGEN2.cpp b/src/libumskt/pidgen2/PIDGEN2.cpp index e9c26c8..677663d 100644 --- a/src/libumskt/pidgen2/PIDGEN2.cpp +++ b/src/libumskt/pidgen2/PIDGEN2.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,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++) diff --git a/src/libumskt/pidgen2/PIDGEN2.h b/src/libumskt/pidgen2/PIDGEN2.h index 7c4bd0d..e6d4ffb 100644 --- a/src/libumskt/pidgen2/PIDGEN2.h +++ b/src/libumskt/pidgen2/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 @@ -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 diff --git a/src/libumskt/pidgen3/BINK1998.cpp b/src/libumskt/pidgen3/BINK1998.cpp index a1bfbd4..6c4e9f7 100644 --- a/src/libumskt/pidgen3/BINK1998.cpp +++ b/src/libumskt/pidgen3/BINK1998.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 @@ -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; } diff --git a/src/libumskt/pidgen3/BINK1998.h b/src/libumskt/pidgen3/BINK1998.h index 65bf702..65e7e68 100644 --- a/src/libumskt/pidgen3/BINK1998.h +++ b/src/libumskt/pidgen3/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 @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - * @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 diff --git a/src/libumskt/pidgen3/BINK2002.cpp b/src/libumskt/pidgen3/BINK2002.cpp index ca87563..0942559 100644 --- a/src/libumskt/pidgen3/BINK2002.cpp +++ b/src/libumskt/pidgen3/BINK2002.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 @@ -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; } diff --git a/src/libumskt/pidgen3/BINK2002.h b/src/libumskt/pidgen3/BINK2002.h index 9391b87..8c7e677 100644 --- a/src/libumskt/pidgen3/BINK2002.h +++ b/src/libumskt/pidgen3/BINK2002.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 . * - * @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 diff --git a/src/libumskt/pidgen3/PIDGEN3.cpp b/src/libumskt/pidgen3/PIDGEN3.cpp new file mode 100644 index 0000000..9bf0a60 --- /dev/null +++ b/src/libumskt/pidgen3/PIDGEN3.cpp @@ -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 . + * + * @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); +} diff --git a/src/libumskt/pidgen3/PIDGEN3.h b/src/libumskt/pidgen3/PIDGEN3.h index e396c47..272ba22 100644 --- a/src/libumskt/pidgen3/PIDGEN3.h +++ b/src/libumskt/pidgen3/PIDGEN3.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 . * - * @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 diff --git a/src/libumskt/pidgen3/key.cpp b/src/libumskt/pidgen3/key.cpp deleted file mode 100644 index 7cb2a8a..0000000 --- a/src/libumskt/pidgen3/key.cpp +++ /dev/null @@ -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 . - * - * @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); -} diff --git a/src/libumskt/pidgen3/util.cpp b/src/libumskt/pidgen3/util.cpp deleted file mode 100644 index 38b81a4..0000000 --- a/src/libumskt/pidgen3/util.cpp +++ /dev/null @@ -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 . - * - * @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; -} diff --git a/src/main.cpp b/src/main.cpp index f3571c4..c85ea8f 100644 --- a/src/main.cpp +++ b/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(); } diff --git a/src/options.cpp b/src/options.cpp new file mode 100644 index 0000000..b7cd67e --- /dev/null +++ b/src/options.cpp @@ -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 . + * + * @FileCreated by Neo on 01/02/2024 + * @Maintainer Neo + */ + +#include "cli.h" + +// define static storage +std::array 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; +} diff --git a/src/header.h b/src/options.h similarity index 50% rename from src/header.h rename to src/options.h index 3ef7e48..a64743a 100644 --- a/src/header.h +++ b/src/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,26 +16,45 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - * @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 -#include -#include -#include -#include -#include +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 -#include + 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 diff --git a/src/typedefs.h b/src/typedefs.h index 3adf14d..6e6f7d0 100644 --- a/src/typedefs.h +++ b/src/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 @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - * @FileCreated by Neo on 6/24/2023 + * @FileCreated by Neo on 06/24/2023 * @Maintainer Neo */ @@ -29,13 +29,19 @@ #ifdef DEBUG #include #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 diff --git a/src/windows/dllmain.cpp b/src/windows/dllmain.cpp index e769ebd..179103e 100644 --- a/src/windows/dllmain.cpp +++ b/src/windows/dllmain.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 diff --git a/src/windows/resource.h b/src/windows/resource.h index af03788..133a7ef 100644 --- a/src/windows/resource.h +++ b/src/windows/resource.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 . * - * @FileCreated by Neo on 6/17/2023 + * @FileCreated by Neo on 06/17/2023 * @Maintainer Neo */ diff --git a/src/windows/umskt.rc b/src/windows/umskt.rc index df98e3002919733ef2d48bb3488224acb0265b71..7ff8bd6b4492a0ea2eb4676167b6f4deb73f472e 100644 GIT binary patch delta 19 bcmeyM_DOBRJVuj^^N+JK8f;Ew1prBU2IT+%