From 2ac7f9bc1e26e2163cd9d47c026c0633d5e7532d Mon Sep 17 00:00:00 2001 From: Neo-Desktop <321592+Neo-Desktop@users.noreply.github.com> Date: Sun, 4 Feb 2024 20:26:29 -0800 Subject: [PATCH] WIP - CryptoPP Port, remove refrences to OpenSSL, many things are currently broken --- .dockerignore | 2 +- .gitignore | 4 +- .pre-commit-config.yaml | 9 +- CMakeLists.txt | 151 +++++++------------ Dockerfile | 7 +- Dockerfile.djgpp | 15 +- build/.gitkeep | 0 keys.json | 83 ++++++++--- src/cli.cpp | 102 ++++--------- src/cli.h | 27 ++-- src/generate.cpp | 148 ++++++------------ src/help.cpp | 21 +-- src/libumskt/confid/confid.cpp | 114 ++++++++------ src/libumskt/confid/confid.h | 28 ++-- src/libumskt/confid/divisor.cpp | 66 ++++---- src/libumskt/debugoutput.cpp | 12 +- src/libumskt/libumskt.cpp | 49 +----- src/libumskt/libumskt.h | 71 ++++++--- src/libumskt/pidgen2/PIDGEN2.cpp | 4 +- src/libumskt/pidgen2/PIDGEN2.h | 4 +- src/libumskt/pidgen3/BINK1998.cpp | 149 +++++++++---------- src/libumskt/pidgen3/BINK1998.h | 9 +- src/libumskt/pidgen3/BINK2002.cpp | 240 +++++++++++++++--------------- src/libumskt/pidgen3/BINK2002.h | 9 +- src/libumskt/pidgen3/PIDGEN3.cpp | 141 ++++++++---------- src/libumskt/pidgen3/PIDGEN3.h | 36 ++--- src/typedefs.h | 5 +- 27 files changed, 690 insertions(+), 816 deletions(-) delete mode 100644 build/.gitkeep diff --git a/.dockerignore b/.dockerignore index bdc79fc..ae7cc49 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,2 @@ build*/ -cmake-*/ +cmake*/ diff --git a/.gitignore b/.gitignore index a71d4ef..30a6828 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -build/* +build*/ *.tar *.exe *.wasm @@ -66,7 +66,7 @@ umskt # *.ipr # CMake -cmake-*/ +cmake*/ # Mongo Explorer plugin .idea/**/mongoSettings.xml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d6d9981..711ab96 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,7 +19,12 @@ # @Maintainer Neo repos: -- repo: https://github.com/pre-commit/mirrors-clang-format + - repo: https://github.com/pre-commit/mirrors-clang-format rev: 'v17.0.6' # Use the sha / tag you want to point at hooks: - - id: clang-format \ No newline at end of file + - id: clang-format + +# - repo: https://github.com/cheshirekow/cmake-format-precommit +# rev: v0.6.10 +# hooks: +# - id: cmake-format \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e556a35..c6c7056 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,32 +26,19 @@ SET(CMAKE_OSX_SYSROOT "macosx" CACHE PATH "macOS SDK path") SET(CMAKE_POSITION_INDEPENDENT_CODE ON) OPTION(BUILD_SHARED_LIBS "Build all libraries as shared" OFF) -OPTION(UMSKT_USE_SHARED_OPENSSL "Force linking against the system-wide OpenSSL library" OFF) OPTION(MUSL_STATIC "Enable fully static builds in a muslc environment (i.e. Alpine Linux)" OFF) -OPTION(DJGPP_WATT32 "Enable compilation and linking with DJGPP/WATT32/OpenSSL" OFF) +OPTION(DJGPP_WATT32 "Enable compilation and linking with DJGPP/WATT32" OFF) OPTION(MSVC_MSDOS_STUB "Specify a custom MS-DOS stub for a 32-bit MSVC compilation" OFF) 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") - SET(UMSKT_USE_SHARED_OPENSSL ON) -ENDIF () - -# neither does dos idk i'm trying random stuff -IF (DJGPP_WATT32) - SET(UMSKT_USE_SHARED_OPENSSL ON) -ENDIF () - -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 () - SET(OPENSSL_USE_STATIC_LIBS TRUE) - SET(OPENSSL_MSVC_STATIC_RT TRUE) - MESSAGE(STATUS "[UMSKT] Requesting static version of OpenSSL") +IF (NOT MSVC) + SET(CMAKE_CXX_FLAGS "-Os -fdata-sections -ffunction-sections -flto -Wl,--gc-sections") + SET(CMAKE_CXX_FLAGS_DEBUG "-g") + SET(CMAKE_CXX_FLAGS_DEBUG_INIT "-Wall -Wextra") + SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -Wl,--gc-sections") + SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -Wl,--gc-sections") ENDIF () IF (DJGPP_WATT32) @@ -72,9 +59,11 @@ ENDIF () # if we're compiling with MSVC, respect the DEBUG compile option IF (MSVC) SET(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + SET(CMAKE_CXX_FLAGS "/O1 /GL /LTCG /Gy /OPT:REF /OPT:ICF /EHsc") SET(CMAKE_CXX_FLAGS_RELEASE "/MT") - SET(CMAKE_CXX_FLAGS_DEBUG "/MTd") - SET(CMAKE_EXE_LINKER_FLAGS "/INCREMENTAL:NO /NODEFAULTLIB:MSVCRT") + SET(CMAKE_CXX_FLAGS_DEBUG "/MTd /Z7") + SET(CMAKE_EXE_LINKER_FLAGS "/INCREMENTAL:NO /NODEFAULTLIB:MSVCRT /LTCG") + SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG") SET(CMAKE_ENABLE_EXPORTS ON) SET(UMSKT_EXE_WINDOWS_EXTRA src/windows/umskt.rc) SET(UMSKT_EXE_WINDOWS_DLL src/windows/dllmain.cpp) @@ -83,53 +72,11 @@ ENDIF () IF (MUSL_STATIC) MESSAGE(STATUS "[UMSKT] Performing a fully static build using muslc") SET(BUILD_SHARED_LIBS OFF) - SET(OPENSSL_USE_STATIC_LIBS TRUE) - SET(CMAKE_EXE_LINKER_FLAGS "-static -static-libgcc -static-libstdc++") - SET(CMAKE_SHARED_LINKER_FLAGS "-static -static-libgcc -static-libstdc++") 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 () - -# find the system installed OpenSSL development library -FIND_PACKAGE(OpenSSL REQUIRED) -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 () - -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 () - - 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") - - # 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 () + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++") ENDIF () # initialize cpm.CMake @@ -166,13 +113,13 @@ CPMAddPackage( ) # Include Crypto++ development library -#CPMAddPackage( -# NAME cryptopp-cmake -# GITHUB_REPOSITORY abdes/cryptopp-cmake -# GIT_TAG CRYPTOPP_8_8_0 -# VERSION 8.8.0 -# OPTIONS "CRYPTOPP_BUILD_TESTING OFF" -#) +CPMAddPackage( + NAME cryptopp-cmake + GITHUB_REPOSITORY abdes/cryptopp-cmake + GIT_TAG CRYPTOPP_8_9_0 + VERSION 8.9.0 + OPTIONS "CRYPTOPP_BUILD_TESTING OFF" +) #include googletest unit testing library #CPMAddPackage( @@ -190,7 +137,7 @@ SET(LIBUMSKT_PIDGEN3 src/libumskt/pidgen3/PIDGEN3.cpp src/libumskt/pidgen3/BINK1 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/help.cpp src/cli.cpp src/generate.cpp) -SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} ${OPENSSL_CRYPTO_LIBRARIES} ${ZLIB_LIBRARIES} fmt) +SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} fmt cryptopp) IF (NOT MSVC) SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} umskt::rc) @@ -202,7 +149,8 @@ ENDIF() #### Separate Build Path for emscripten IF (EMSCRIPTEN) ADD_EXECUTABLE(umskt ${UMSKT_CLI_SRC} ${LIBUMSKT_SRC}) - TARGET_INCLUDE_DIRECTORIES(umskt PUBLIC ${OPENSSL_INCLUDE_DIR}) + TARGET_INCLUDE_DIRECTORIES(umskt PUBLIC ${CMAKE_BINARY_DIR}) + TARGET_LINK_DIRECTORIES(umskt PUBLIC ${UMSKT_LINK_DIRS}) TARGET_LINK_LIBRARIES(umskt PUBLIC ${UMSKT_LINK_LIBS}) SET(CMAKE_EXECUTABLE_SUFFIX ".html") @@ -210,31 +158,38 @@ IF (EMSCRIPTEN) SET_TARGET_PROPERTIES(umskt PROPERTIES LINK_FLAGS "-Os -sWASM=1 -sEXPORT_ALL=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap --no-entry") ELSE () ## umskt.so/.dll creation - ADD_LIBRARY(_umskt SHARED ${LIBUMSKT_SRC} ${UMSKT_EXE_WINDOWS_EXTRA} ${UMSKT_EXE_WINDOWS_DLL}) - TARGET_INCLUDE_DIRECTORIES(_umskt PUBLIC ${OPENSSL_INCLUDE_DIR} ${CMAKE_BINARY_DIR}) - TARGET_LINK_DIRECTORIES(_umskt PUBLIC ${UMSKT_LINK_DIRS}) - TARGET_LINK_LIBRARIES(_umskt PUBLIC ${UMSKT_LINK_LIBS}) - IF(MSVC) - SET_TARGET_PROPERTIES(_umskt PROPERTIES OUTPUT_NAME libumskt) - ELSE() - SET_TARGET_PROPERTIES(_umskt PROPERTIES OUTPUT_NAME umskt) - ENDIF() + ADD_LIBRARY(libumskt SHARED ${LIBUMSKT_SRC} ${UMSKT_EXE_WINDOWS_EXTRA} ${UMSKT_EXE_WINDOWS_DLL}) + TARGET_INCLUDE_DIRECTORIES(libumskt PUBLIC ${CMAKE_BINARY_DIR}) + TARGET_LINK_DIRECTORIES(libumskt PUBLIC ${UMSKT_LINK_DIRS}) + TARGET_LINK_LIBRARIES(libumskt PUBLIC ${UMSKT_LINK_LIBS}) + IF (MSVC) + SET_TARGET_PROPERTIES(libumskt PROPERTIES OUTPUT_NAME libumskt) + ELSE () + SET_TARGET_PROPERTIES(libumskt PROPERTIES OUTPUT_NAME umskt) + ENDIF () ## umskt_static.a/.lib creation - ADD_LIBRARY(umskt_static ${LIBUMSKT_SRC} ${UMSKT_EXE_WINDOWS_EXTRA} ${UMSKT_EXE_WINDOWS_DLL}) - TARGET_INCLUDE_DIRECTORIES(umskt_static PUBLIC ${OPENSSL_INCLUDE_DIR} ${CMAKE_BINARY_DIR}) - TARGET_LINK_DIRECTORIES(umskt_static PUBLIC ${UMSKT_LINK_DIRS}) - TARGET_LINK_LIBRARIES(umskt_static PUBLIC ${UMSKT_LINK_LIBS}) - IF(MSVC) - SET_TARGET_PROPERTIES(umskt_static PROPERTIES OUTPUT_NAME libumskt_static) - ELSE() - SET_TARGET_PROPERTIES(umskt_static PROPERTIES OUTPUT_NAME umskt_static) - ENDIF() + ADD_LIBRARY(libumskt_static ${LIBUMSKT_SRC} ${UMSKT_EXE_WINDOWS_EXTRA} ${UMSKT_EXE_WINDOWS_DLL}) + TARGET_INCLUDE_DIRECTORIES(libumskt_static PUBLIC ${CMAKE_BINARY_DIR}) + TARGET_LINK_DIRECTORIES(libumskt_static PUBLIC ${UMSKT_LINK_DIRS}) + TARGET_LINK_LIBRARIES(libumskt_static PUBLIC ${UMSKT_LINK_LIBS}) + IF (MSVC) + SET_TARGET_PROPERTIES(libumskt_static PROPERTIES OUTPUT_NAME libumskt_static) + ELSE () + SET_TARGET_PROPERTIES(libumskt_static PROPERTIES OUTPUT_NAME umskt_static) + ENDIF () ### UMSKT executable compilation - ADD_EXECUTABLE(umskt ${UMSKT_CLI_SRC} ${UMSKT_EXE_WINDOWS_EXTRA}) - TARGET_INCLUDE_DIRECTORIES(umskt PUBLIC ${OPENSSL_INCLUDE_DIR} ${CMAKE_BINARY_DIR}) - TARGET_LINK_LIBRARIES(umskt PUBLIC umskt_static ${UMSKT_LINK_LIBS} nlohmann_json::nlohmann_json) + IF (NOT BUILD_SHARED_LIBS) + ## Link against the static lib + ADD_EXECUTABLE(umskt ${UMSKT_CLI_SRC} ${UMSKT_EXE_WINDOWS_EXTRA}) + TARGET_LINK_LIBRARIES(umskt PUBLIC libumskt_static ${UMSKT_LINK_LIBS} nlohmann_json::nlohmann_json) + ELSE () + ## Link against the dynamic lib + ADD_EXECUTABLE(umskt ${UMSKT_CLI_SRC} ${UMSKT_EXE_WINDOWS_EXTRA}) + TARGET_LINK_LIBRARIES(umskt PUBLIC libumskt ${UMSKT_LINK_LIBS} nlohmann_json::nlohmann_json) + ENDIF() + TARGET_INCLUDE_DIRECTORIES(umskt PUBLIC ${CMAKE_BINARY_DIR}) TARGET_LINK_DIRECTORIES(umskt PUBLIC ${UMSKT_LINK_DIRS}) IF (MSVC) SET_PROPERTY(TARGET umskt APPEND PROPERTY COMPILE_FLAGS /DUMSKT_CLI_WINRC_EMBED_JSON) @@ -246,10 +201,4 @@ ELSE () IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 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 () diff --git a/Dockerfile b/Dockerfile index 58daeb1..a983077 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,14 +40,15 @@ COPY . /src # Build UMSKT from the local directory RUN mkdir /src/build \ - && cd /src/build \ - && cmake -DMUSL_STATIC=ON .. \ - && make + && cmake -B /src/build -DMUSL_STATIC=ON \ + && cmake --build /src/build -j 10 # Stage 3: Output FROM scratch as output COPY --from=builder /src/build/umskt /umskt +COPY --from=builder /src/build/libumskt.a /umskt +COPY --from=builder /src/build/libumskt.so /umskt # invoke via # docker build -o type=tar,dest=umskt.tar . diff --git a/Dockerfile.djgpp b/Dockerfile.djgpp index a718689..cd286d0 100644 --- a/Dockerfile.djgpp +++ b/Dockerfile.djgpp @@ -84,21 +84,8 @@ RUN git clone https://github.com/gvanem/Watt-32.git watt32 \ && make -f djgpp.mak \ && ln -s /djgpp/watt32/lib/libwatt.a /djgpp/lib -# Stage 4: compile OpenSSL for djgpp-i386/watt32 -FROM watt32 as openssl -WORKDIR /tmp -SHELL ["/bin/bash", "-c"] -RUN git clone https://github.com/openssl/openssl.git openssl \ - && cd openssl \ - && git checkout openssl-3.1.1 \ - && source /djgpp/setenv \ - && wget https://gist.github.com/Neo-Desktop/ad26e888d64b22a59c743ab4e21ac186/raw/c9a73e1eb75ba8857883ac5c08691d2fe5b82594/50-djgpp.conf.patch -O Configurations/50-djgpp.conf.patch \ - && git apply Configurations/50-djgpp.conf.patch \ - && ./Configure no-threads -DOPENSSL_DEV_NO_ATOMICS --prefix=/djgpp DJGPP \ - && make && make install - # Stage 5: compile UMSKT -FROM openssl as build +FROM watt32 as build WORKDIR /src COPY . /src diff --git a/build/.gitkeep b/build/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/keys.json b/keys.json index f51aa08..7c72374 100644 --- a/keys.json +++ b/keys.json @@ -463,17 +463,56 @@ "BINK": [ "2C", "2D" - ] + ], + "DPC": { + "2C": [ + { + "min": 5, + "max": 85, + "isEvaluation": false + }, + { + "min": 337, + "max": 359, + "isEvaluation": false + }, + { + "min": 755, + "max": 779, + "isEvaluation": false + }, + { + "min": 785, + "max": 789, + "isEvaluation": false + } + ], + "2D": [ + { + "min": 119, + "max": 119, + "isEvaluation": false + }, + { + "min": 120, + "max": 169, + "isEvaluation": false + }, + { + "min": 400, + "max": 699, + "isEvaluation": false + }, + { + "min": 170, + "max": 269, + "isEvaluation": false + } + ] + } }, - "PROK": { - "name": "Professional K", - "BINK": [ - "30", - "31" - ] - }, - "PROVLK": { - "name": "Professional VLK", + "VLK": { + "name": "Home/Professional VLK", "BINK": [ "2E", "2F" @@ -484,16 +523,6 @@ "min": 640, "max": 699, "isEvaluation": false - }, - { - "min": 700, - "max": 701, - "isEvaluation": false - }, - { - "min": 704, - "max": 705, - "isEvaluation": false } ] }, @@ -673,6 +702,20 @@ } ] } + }, + "CNOEMHOME": { + "name": "[CN] OEM Home", + "BINK": [ + "30", + "31" + ] + }, + "CNOEMPRO": { + "name": "[CN] OEM Professional", + "BINK": [ + "32", + "33" + ] } } }, diff --git a/src/cli.cpp b/src/cli.cpp index a85e3a8..a0284ce 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -129,13 +129,13 @@ BOOL CLI::loadJSON(const fs::path &filename) * * @param pid */ -void CLI::printID(DWORD *pid) +void CLI::printID(DWORD32 *pid) { char raw[12], b[6], c[8]; char i, digit = 0; // Convert PID to ascii-number (=raw) - snprintf(raw, sizeof(raw), "%09lu", pid[0]); + snprintf(raw, sizeof(raw), "%09u", pid[0]); // Make b-part {640-....} _strncpy(b, 6, &raw[0], 3); @@ -160,8 +160,8 @@ void CLI::printID(DWORD *pid) c[6] = digit + '0'; c[7] = 0; - DWORD binkid; - _sscanf(options.binkID.c_str(), "%lx", &binkid); + DWORD32 binkid; + _sscanf(&options.binkID[0], "%x", &binkid); binkid /= 2; fmt::print("> Product ID: PPPPP-{}-{}-{}xxx\n", b, c, binkid); @@ -172,7 +172,7 @@ void CLI::printID(DWORD *pid) * @param pidgen3 * @return success */ -BOOL CLI::InitPIDGEN3(PIDGEN3 &pidgen3) +BOOL CLI::InitPIDGEN3(PIDGEN3 *p3) { const char *BINKID = &options.binkID[0]; auto bink = keys["BINK"][BINKID]; @@ -192,26 +192,26 @@ BOOL CLI::InitPIDGEN3(PIDGEN3 &pidgen3) fmt::print("\n"); } - pidgen3.LoadEllipticCurve(bink["p"], bink["a"], bink["b"], bink["g"]["x"], bink["g"]["y"], bink["pub"]["x"], - bink["pub"]["y"], bink["n"], bink["priv"]); + p3->LoadEllipticCurve(bink["p"], bink["a"], bink["b"], bink["g"]["x"], bink["g"]["y"], bink["pub"]["x"], + bink["pub"]["y"], bink["n"], bink["priv"]); if (options.state != STATE_PIDGEN_GENERATE) { return true; } - pidgen3.info.setChannelID(options.channelID); + p3->info.setChannelID(options.channelID); if (options.verbose) { - fmt::print("> Channel ID: {:03d}\n", options.channelID); + fmt::print("> Channel ID: {:#03d}\n", options.channelID); } if (options.serialSet) { - pidgen3.info.setSerial(options.serial); + p3->info.setSerial(options.serial); if (options.verbose) { - fmt::print("> Serial {:#09d}\n", options.serial); + fmt::print("> Serial {:#06d}\n", options.serial); } } @@ -225,11 +225,6 @@ BOOL CLI::InitPIDGEN3(PIDGEN3 &pidgen3) */ BOOL CLI::InitConfirmationID(ConfirmationID &confid) { - auto ctx = BN_CTX_new(); - BIGNUM *pkey = BN_CTX_get(ctx), *nonresidue = BN_CTX_get(ctx), *modulous = BN_CTX_get(ctx); - BIGNUM *fvals[6]; - QWORD fvalsq[6]; - if (!keys["products"][options.productCode].contains("meta") || !keys["products"][options.productCode]["meta"].contains("activation")) { @@ -264,17 +259,10 @@ BOOL CLI::InitConfirmationID(ConfirmationID &confid) fmt::print("\n"); } - for (BYTE i = 0; i < 6; i++) - { - fvals[i] = BN_CTX_get(ctx); - auto xval = flavour["x"][fmt::format("{}", i)].get(); - BN_dec2bn(&fvals[i], xval.c_str()); - UMSKT::BN_bn2lebin(fvals[i], (unsigned char *)&fvalsq[i], sizeof(*fvalsq)); - } - - // confid.LoadHyperellipticCurve(fvals, ); - - BN_CTX_free(ctx); + confid.LoadHyperellipticCurve(flavour["x"]["0"], flavour["x"]["1"], flavour["x"]["2"], flavour["x"]["3"], + flavour["x"]["4"], flavour["x"]["5"], flavour["priv"], flavour["quotient"], + flavour["non_residue"], flavour["iid_key"], meta["tags"].contains("xpbrand"), + meta["tags"].contains("office"), meta["activation"]["version"]); return false; } @@ -282,7 +270,7 @@ BOOL CLI::InitConfirmationID(ConfirmationID &confid) * * @return success */ -BOOL CLI::PIDGENGenerate() +BOOL CLI::PIDGenerate() { // TODO: // if options.pidgen2generate @@ -295,34 +283,20 @@ BOOL CLI::PIDGENGenerate() std::string key; bink["p"].get_to(key); - if (PIDGEN3::checkFieldStrIsBink1998(key)) - { - if (options.verbose) - { - fmt::print("Detected a BINK1998 key\n"); - } + auto p3 = PIDGEN3::Factory(key); + InitPIDGEN3(p3); - auto bink1998 = BINK1998(); - InitPIDGEN3(bink1998); - return BINK1998Generate(bink1998); - } - else - { - if (options.verbose) - { - fmt::print("Detected a BINK2002 key\n"); - } - auto bink2002 = BINK2002(); - InitPIDGEN3(bink2002); - return BINK2002Generate(bink2002); - } + auto retval = PIDGEN3Generate(p3); + + delete p3; + return retval; } /** * * @return isValid */ -BOOL CLI::PIDGENValidate() +BOOL CLI::PIDValidate() { // TODO: // if options.pidgen2validate @@ -335,26 +309,12 @@ BOOL CLI::PIDGENValidate() std::string key; bink["p"].get_to(key); - if (PIDGEN3::checkFieldStrIsBink1998(key)) - { - if (options.verbose) - { - fmt::print("Detected a BINK1998 key\n"); - } - auto bink1998 = BINK1998(); - InitPIDGEN3(bink1998); - return BINK1998Validate(bink1998); - } - else - { - if (options.verbose) - { - fmt::print("Detected a BINK2002 key\n"); - } - auto bink2002 = BINK2002(); - InitPIDGEN3(bink2002); - return BINK2002Validate(bink2002); - } + auto p3 = PIDGEN3::Factory(key); + InitPIDGEN3(p3); + auto retval = PIDGEN3Validate(p3); + + delete p3; + return retval; } /** @@ -371,10 +331,10 @@ int CLI::Run() switch (options.state) { case STATE_PIDGEN_GENERATE: - return PIDGENGenerate(); + return PIDGenerate(); case STATE_PIDGEN_VALIDATE: - return PIDGENValidate(); + return PIDValidate(); case STATE_CONFIRMATION_ID: return ConfirmationIDGenerate(); diff --git a/src/cli.h b/src/cli.h index 1850184..c6794e4 100644 --- a/src/cli.h +++ b/src/cli.h @@ -23,6 +23,7 @@ #ifndef UMSKT_CLI_H #define UMSKT_CLI_H +#include "libumskt/libumskt.h" #include "typedefs.h" #include @@ -96,9 +97,9 @@ struct Options std::string productCode; std::string productFlavour; - DWORD channelID; - DWORD serial; - DWORD numKeys; + DWORD32 channelID; + DWORD32 serial; + DWORD32 numKeys; BOOL oem; BOOL upgrade; @@ -128,7 +129,7 @@ struct Options class CLI { std::string pKey; - DWORD count, total, iBinkID; + DWORD32 count, total, iBinkID; static Options options; @@ -168,23 +169,21 @@ class CLI static BOOL parseCommandLine(); static BOOL processOptions(); - static void printID(DWORD *pid); + static void printID(DWORD32 *pid); static void printKey(std::string &pk); static BOOL stripKey(const std::string &in_key, std::string &out_key); static std::string validateInputKeyCharset(std::string &accumulator, char currentChar); - BOOL InitPIDGEN3(PIDGEN3 &pidgen3); + BOOL InitPIDGEN3(PIDGEN3 *p3); BOOL InitConfirmationID(ConfirmationID &confid); - BOOL PIDGENGenerate(); - BOOL PIDGENValidate(); + BOOL PIDGenerate(); + BOOL PIDValidate(); - BOOL PIDGEN2Generate(PIDGEN2 &pidgen2); - BOOL PIDGEN2Validate(PIDGEN2 &pidgen2); - BOOL BINK1998Generate(PIDGEN3 &pidgen3); - BOOL BINK1998Validate(PIDGEN3 &pidgen3); - BOOL BINK2002Generate(PIDGEN3 &pidgen3); - BOOL BINK2002Validate(PIDGEN3 &pidgen3); + BOOL PIDGEN2Generate(PIDGEN2 &p2); + BOOL PIDGEN2Validate(PIDGEN2 &p2); + BOOL PIDGEN3Generate(PIDGEN3 *p3); + BOOL PIDGEN3Validate(PIDGEN3 *p3); BOOL ConfirmationIDGenerate(); INLINE static std::string strtolower(std::string &in) diff --git a/src/generate.cpp b/src/generate.cpp index 181533d..134ad27 100644 --- a/src/generate.cpp +++ b/src/generate.cpp @@ -46,39 +46,56 @@ BOOL CLI::PIDGEN2Validate(PIDGEN2 &pidgen2) * * @return success */ -BOOL CLI::BINK1998Generate(PIDGEN3 &pidgen3) +BOOL CLI::PIDGEN3Generate(PIDGEN3 *p3) { // raw PID/serial value - DWORD nRaw = options.channelID * 1'000'000; - DWORD serialRnd; + DWORD32 nRaw = options.channelID * 1'000'000; + DWORD32 serialRnd; - if (options.serialSet) + if (p3->checkFieldIsBink1998()) { - // using user-provided serial - serialRnd = options.serial; - } - else - { - // generate a random number to use as a serial - serialRnd = UMSKT::getRandom(); + if (options.serialSet) + { + // using user-provided serial + serialRnd = options.serial; + } + else + { + // generate a random number to use as a serial + serialRnd = UMSKT::getRandom(); + } + + // make sure it's less than 999999 + nRaw += (serialRnd % 999999); + + if (options.verbose) + { + // print the resulting Product ID + // PID value is printed in BINK1998::Generate + printID(&nRaw); + } } - // make sure it's less than 999999 - nRaw += (serialRnd % 999999); - - if (options.verbose) + for (DWORD32 i = 0; i < total; i++) { - // print the resulting Product ID - // PID value is printed in BINK1998::Generate - printID(&nRaw); - } + if (!p3->checkFieldIsBink1998()) + { + auto authvalue = UMSKT::getRandom() & BITMASK(10); + p3->info.AuthInfo.Decode((BYTE *)&authvalue, sizeof(DWORD32)); - for (int i = 0; i < total; i++) - { - pidgen3.info.setSerial(nRaw); - pidgen3.Generate(pKey); + if (options.verbose) + { + fmt::print("> AuthInfo: {:#08x}\n", p3->info.AuthInfo); + } + } + else + { + p3->info.setSerial(nRaw); + } - bool isValid = pidgen3.Validate(pKey); + p3->Generate(pKey); + + bool isValid = p3->Validate(pKey); if (isValid) { printKey(pKey); @@ -115,7 +132,7 @@ BOOL CLI::BINK1998Generate(PIDGEN3 &pidgen3) * * @return success */ -BOOL CLI::BINK1998Validate(PIDGEN3 &bink1998) +BOOL CLI::PIDGEN3Validate(PIDGEN3 *p3) { std::string product_key; @@ -127,84 +144,7 @@ BOOL CLI::BINK1998Validate(PIDGEN3 &bink1998) CLI::printKey(product_key); fmt::print("\n"); - if (!bink1998.Validate(product_key)) - { - fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n"); - return false; - } - - fmt::print("Key validated successfully!\n"); - return true; -} - -/** - * - * @return success - */ -BOOL CLI::BINK2002Generate(PIDGEN3 &pidgen3) -{ - // generate a key - for (int i = 0; i < total; i++) - { - pidgen3.info.AuthInfo = UMSKT::getRandom() & BITMASK(10); - - if (options.verbose) - { - fmt::print("> AuthInfo: {:#08x}\n", pidgen3.info.AuthInfo); - } - - pidgen3.Generate(pKey); - - bool isValid = pidgen3.Validate(pKey); - if (isValid) - { - CLI::printKey(pKey); - if (i <= total - 1 || options.verbose) - { // check if end of list or verbose - fmt::print("\n"); - } - count += isValid; // add to count - } - else - { - if (options.verbose) - { - CLI::printKey(pKey); // print the key - fmt::print(" [Invalid]"); // and add " [Invalid]" to the key - if (i <= total - 1) - { // check if end of list - fmt::print("\n"); - } - } - total++; // queue a redo, basically - } - } - - if (options.verbose) - { - fmt::print("\nSuccess count: {}/{}\n", count, total); - } - - return true; -} - -/** - * - * @return success - */ -BOOL CLI::BINK2002Validate(PIDGEN3 &pidgen3) -{ - std::string product_key; - - if (!CLI::stripKey(options.keyToCheck, product_key)) - { - fmt::print("ERROR: Product key is in an incorrect format!\n"); - return false; - } - - CLI::printKey(product_key); - fmt::print("\n"); - if (!pidgen3.Validate(product_key)) + if (!p3->Validate(product_key)) { fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n"); return false; @@ -228,7 +168,7 @@ BOOL CLI::ConfirmationIDGenerate() return false; } - DWORD err = confid.Generate(options.installationID, confirmation_id, options.productID); + DWORD32 err = confid.Generate(options.installationID, confirmation_id, options.productID); if (err == SUCCESS) { diff --git a/src/help.cpp b/src/help.cpp index 777d85e..9ecbc8d 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -89,7 +89,7 @@ void CLI::SetHelpText() */ BOOL CLI::parseCommandLine() { - for (DWORD i = 1; i < options.argc; i++) + for (DWORD32 i = 1; i < options.argc; i++) { std::string arg = options.argv[i]; @@ -436,7 +436,7 @@ BOOL CLI::SetOEMOption(int, char *) { if (options.verbose) { - fmt::print("Setting oem option\n"); + fmt::print("Setting OEM option\n"); } options.oem = true; return true; @@ -523,12 +523,13 @@ BOOL CLI::SetBINKOption(int count, char *bink) BOOL CLI::SetFlavourOption(int count, char *flavour) { + auto strflavour = std::string(flavour); + options.productFlavour = strtoupper(strflavour); + if (options.verbose) { - fmt::print("Setting flavour option to {}\n", flavour); + fmt::print("Setting flavour option to {}\n", strflavour); } - - options.productFlavour = flavour; return true; } @@ -584,12 +585,12 @@ BOOL CLI::SetValidateOption(int count, char *productID) BOOL CLI::SetProductCodeOption(int, char *product) { - if (options.verbose) - { - fmt::print("Setting product code to {}\n", product); - } - auto strProduct = std::string(product); options.productCode = strtoupper(strProduct); + + if (options.verbose) + { + fmt::print("Setting product code to {}\n", strProduct); + } return true; } diff --git a/src/libumskt/confid/confid.cpp b/src/libumskt/confid/confid.cpp index 9f04be9..8dd5502 100644 --- a/src/libumskt/confid/confid.cpp +++ b/src/libumskt/confid/confid.cpp @@ -38,7 +38,7 @@ * @param x4 * @param x5 * @param priv - * @param modulous + * @param modulus * @param nonresidue * @param isOffice * @param isXPBrand @@ -46,58 +46,74 @@ * @return */ 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) + QWORD modulus, QWORD nonresidue, DWORD32 iidkey, BOOL isOffice, + BOOL isXPBrand, BYTE flagVersion) { - curve[0] = x0; - curve[1] = x1; - curve[2] = x2; - curve[3] = x3; - curve[4] = x4; - curve[5] = x5; + QWORD fvals[6] = {x0, x1, x2, x3, x4, x5}; - memcpy(&privateKey, &priv, sizeof(Q_OWORD)); - - MOD = modulous; - NON_RESIDUE = nonresidue; - this->isOffice = isOffice; - this->isXPBrand = isXPBrand; - this->flagVersion = flagVersion; - - return true; + return LoadHyperellipticCurve(fvals, priv, modulus, nonresidue, iidkey, isOffice, isXPBrand, flagVersion); } /** * * @param f * @param priv - * @param modulous + * @param modulus * @param nonresidue * @param isOffice * @param isXPBrand * @param flagVersion * @return */ -BOOL ConfirmationID::LoadHyperellipticCurve(QWORD *f, Q_OWORD priv, QWORD modulous, QWORD nonresidue, BOOL isOffice, - BOOL isXPBrand, BYTE flagVersion) +BOOL ConfirmationID::LoadHyperellipticCurve(QWORD *f, Q_OWORD priv, QWORD modulus, QWORD nonresidue, DWORD32 iidkey, + BOOL isOffice, BOOL isXPBrand, BYTE flagVersion) { memcpy(&curve, f, sizeof(curve)); memcpy(&privateKey, &priv, sizeof(Q_OWORD)); - MOD = modulous; + MOD = modulus; NON_RESIDUE = nonresidue; this->isOffice = isOffice; this->isXPBrand = isXPBrand; this->flagVersion = flagVersion; - return true; } -BOOL LoadHyperellipticCurve(const std::string &x0, const std::string &x1, const std::string &x2, const std::string &x3, - const std::string &x4, const std::string &x5, const std::string &priv, - const std::string &modulous, const std::string &nonresidue, BOOL isOffice, BOOL isXPBrand, - BYTE flagVersion) +BOOL ConfirmationID::LoadHyperellipticCurve(const std::string &x0, const std::string &x1, const std::string &x2, + const std::string &x3, const std::string &x4, const std::string &x5, + const std::string &priv, const std::string &modulus, + const std::string &nonresidue, const std::string &iidkey, BOOL isOffice, + BOOL isXPBrand, BYTE flagVersion) { + std::string f[6]; + f[0] = x0; + f[1] = x1; + f[2] = x2; + f[3] = x3; + f[4] = x4; + f[5] = x5; + + return LoadHyperellipticCurve(f, priv, modulus, nonresidue, iidkey, isOffice, isXPBrand, flagVersion); +} + +BOOL ConfirmationID::LoadHyperellipticCurve(const std::string *f, const std::string &priv, const std::string &modulus, + const std::string &nonresidue, const std::string &iidkey, BOOL isOffice, + BOOL isXPBrand, BYTE flagVersion) +{ + for (int i = 0; i < 6; i++) + { + Integer(&f[i][0]).Encode((BYTE *)curve[i], sizeof(QWORD)); + } + + Integer(&priv[0]).Encode(privateKey.byte, sizeof(Q_OWORD)); + + Integer(&modulus[0]).Encode((BYTE *)&MOD, sizeof(QWORD)); + + Integer(&nonresidue[0]).Encode((BYTE *)NON_RESIDUE, sizeof(QWORD)); + + this->isOffice = isOffice; + this->isXPBrand = isXPBrand; + this->flagVersion = flagVersion; return true; } @@ -107,9 +123,9 @@ BOOL LoadHyperellipticCurve(const std::string &x0, const std::string &x1, const * @param pid * @return */ -DWORD ConfirmationID::calculateCheckDigit(DWORD pid) +DWORD32 ConfirmationID::calculateCheckDigit(DWORD32 pid) { - DWORD i = 0, j = 0, k = 0; + DWORD32 i = 0, j = 0, k = 0; for (j = pid; j; i += k) { k = j % 10; @@ -125,7 +141,7 @@ DWORD ConfirmationID::calculateCheckDigit(DWORD pid) * @param hwid * @param version */ -void ConfirmationID::decode_iid_new_version(BYTE *iid, BYTE *hwid, DWORD *version) +void ConfirmationID::decode_iid_new_version(BYTE *iid, BYTE *hwid, DWORD32 *version) { QWORD buffer[5]; for (BYTE i = 0; i < 5; i++) @@ -133,8 +149,8 @@ void ConfirmationID::decode_iid_new_version(BYTE *iid, BYTE *hwid, DWORD *versio memcpy(&buffer[i], (iid + (4 * i)), 4); } - DWORD v1 = (buffer[3] & 0xFFFFFFF8) | 2; - DWORD v2 = ((buffer[3] & 7) << 29) | (buffer[2] >> 3); + DWORD32 v1 = (buffer[3] & 0xFFFFFFF8) | 2; + DWORD32 v2 = ((buffer[3] & 7) << 29) | (buffer[2] >> 3); QWORD hardwareIDVal = ((QWORD)v1 << 32) | v2; for (BYTE i = 0; i < 8; ++i) { @@ -153,8 +169,9 @@ void ConfirmationID::decode_iid_new_version(BYTE *iid, BYTE *hwid, DWORD *versio */ void ConfirmationID::Mix(BYTE *buffer, BYTE bufSize, const BYTE *key, BYTE keySize) { - BYTE sha1_input[64], sha1_result[20]; + BYTE sha1_input[64], sha1_result[SHA::DIGESTSIZE]; BYTE half = bufSize / 2; + auto digest = SHA(); // assert(half <= sizeof(sha1_result) && half + keySize <= sizeof(sha1_input) - 9); for (BYTE external_counter = 0; external_counter < 4; external_counter++) @@ -181,7 +198,8 @@ void ConfirmationID::Mix(BYTE *buffer, BYTE bufSize, const BYTE *key, BYTE keySi sha1_input[sizeof(sha1_input) - 2] = (1 + half + keySize) * 8 / 0x100; } - SHA1(sha1_input, sizeof(sha1_input), sha1_result); + digest.Update(sha1_input, sizeof(sha1_input)); + digest.Final(sha1_result); for (BYTE i = half & ~3; i < half; i++) { @@ -206,8 +224,9 @@ void ConfirmationID::Mix(BYTE *buffer, BYTE bufSize, const BYTE *key, BYTE keySi */ void ConfirmationID::Unmix(BYTE *buffer, BYTE bufSize, const BYTE key[4], BYTE keySize) { - BYTE sha1_input[64], sha1_result[20]; + BYTE sha1_input[64], sha1_result[SHA::DIGESTSIZE]; BYTE half = bufSize / 2; + auto digest = SHA(); // assert(half <= sizeof(sha1_result) && half + keySize <= sizeof(sha1_input) - 9); for (BYTE external_counter = 0; external_counter < 4; external_counter++) @@ -232,7 +251,8 @@ void ConfirmationID::Unmix(BYTE *buffer, BYTE bufSize, const BYTE key[4], BYTE k sha1_input[sizeof(sha1_input) - 2] = (1 + half + keySize) * 8 / 0x100; } - SHA1(sha1_input, sizeof(sha1_input), sha1_result); + digest.Update(sha1_input, sizeof(sha1_input)); + digest.Final(sha1_result); for (BYTE i = half & ~3; i < half; i++) { @@ -258,13 +278,13 @@ void ConfirmationID::Unmix(BYTE *buffer, BYTE bufSize, const BYTE key[4], BYTE k CONFIRMATION_ID_STATUS ConfirmationID::Generate(const std::string &installationIDIn, std::string &confirmationIDOut, std::string &productIDIn) { - DWORD version; + DWORD32 version; BYTE hardwareID[8]; BYTE installation_id[19]; // 10**45 < 256**19 BYTE productID[4]; BYTE installation_id_len = 0; - auto pid = installationIDIn.c_str(); + auto pid = &installationIDIn[0]; BYTE count = 0, totalCount = 0; unsigned check = 0; @@ -441,8 +461,8 @@ CONFIRMATION_ID_STATUS ConfirmationID::Generate(const std::string &installationI 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))); - d.u[1] = residue->add(x1, x1); + d.u.qword[0] = residue->sub(residue->mul(x1, x1), residue->mul(NON_RESIDUE, residue->mul(x2, x2))); + d.u.qword[1] = residue->add(x1, x1); if (divisor->find_divisor_v(&d)) { break; @@ -462,23 +482,23 @@ CONFIRMATION_ID_STATUS ConfirmationID::Generate(const std::string &installationI Q_OWORD e; memset(&e, 0, sizeof(e)); - if (d.u[0] == BAD) + if (d.u.qword[0] == BAD) { // we can not get the zero divisor, actually... e.qword[0] = residue->__umul128(MOD + 2, MOD, &e.qword[1]); } - else if (d.u[1] == BAD) + else if (d.u.qword[1] == BAD) { // O(1/MOD) chance // encoded = (unsigned __int128)(MOD + 1) * d.u[0] + MOD; // * MOD + d.u[0] is fine too - e.qword[0] = residue->__umul128(MOD + 1, d.u[0], &e.qword[1]); + e.qword[0] = residue->__umul128(MOD + 1, d.u.qword[0], &e.qword[1]); e.qword[0] += MOD; e.qword[1] += (e.qword[0] < MOD); } else { - QWORD x1 = (d.u[1] % 2 ? d.u[1] + MOD : d.u[1]) / 2; - QWORD x2sqr = residue->sub(residue->mul(x1, x1), d.u[0]); + QWORD x1 = (d.u.qword[1] % 2 ? d.u.qword[1] + MOD : d.u.qword[1]) / 2; + QWORD x2sqr = residue->sub(residue->mul(x1, x1), d.u.qword[0]); QWORD x2 = residue->sqrt(x2sqr); if (x2 == BAD) @@ -493,9 +513,9 @@ CONFIRMATION_ID_STATUS ConfirmationID::Generate(const std::string &installationI { // points (-x1+x2, v(-x1+x2)) and (-x1-x2, v(-x1-x2)) QWORD x1a = residue->sub(x1, x2); - QWORD y1 = residue->sub(d.v[0], residue->mul(d.v[1], x1a)); + QWORD y1 = residue->sub(d.v.qword[0], residue->mul(d.v.qword[1], x1a)); QWORD x2a = residue->add(x1, x2); - QWORD y2 = residue->sub(d.v[0], residue->mul(d.v[1], x2a)); + QWORD y2 = residue->sub(d.v.qword[0], residue->mul(d.v.qword[1], x2a)); if (x1a > x2a) { QWORD tmp = x1a; diff --git a/src/libumskt/confid/confid.h b/src/libumskt/confid/confid.h index 4702be3..a1ffb66 100644 --- a/src/libumskt/confid/confid.h +++ b/src/libumskt/confid/confid.h @@ -41,8 +41,7 @@ enum CONFIRMATION_ID_STATUS typedef struct { - QWORD u[2]; - QWORD v[2]; + Q_OWORD u, v; } TDivisor; class EXPORT ConfirmationID @@ -55,8 +54,8 @@ class EXPORT ConfirmationID BOOL isOffice = false, isXPBrand = false; unsigned flagVersion = 0; - DWORD calculateCheckDigit(DWORD pid); - void decode_iid_new_version(BYTE *iid, BYTE *hwid, DWORD *version); + DWORD32 calculateCheckDigit(DWORD32 pid); + void decode_iid_new_version(BYTE *iid, BYTE *hwid, DWORD32 *version); void Mix(BYTE *buffer, BYTE bufSize, const BYTE *key, BYTE keySize); void Unmix(BYTE *buffer, BYTE bufSize, const BYTE *key, BYTE keySize); @@ -127,26 +126,31 @@ class EXPORT ConfirmationID residue = new Residue(this); polynomial = new Polynomial(this); divisor = new Divisor(this); - privateKey.qword[0] = privateKey.qword[1] = 0x00; } + BOOL LoadHyperellipticCurve(const std::string *f, const std::string &priv, const std::string &modulus, + const std::string &nonresidue, const std::string &iidkey, BOOL isOffice, BOOL isXPBrand, + BYTE flagVersion); + BOOL LoadHyperellipticCurve(const std::string &x0, const std::string &x1, const std::string &x2, const std::string &x3, const std::string &x4, const std::string &x5, - const std::string &priv, const std::string &modulous, const std::string &nonresidue, - BOOL isOffice, BOOL isXPBrand, BYTE flagVersion); + const std::string &priv, const std::string &modulus, const std::string &nonresidue, + const std::string &iidkey, BOOL isOffice, BOOL isXPBrand, BYTE flagVersion); - 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 x0, QWORD x1, QWORD x2, QWORD x3, QWORD x4, QWORD x5, Q_OWORD priv, QWORD modulus, + QWORD nonresidue, DWORD32 iidkey, BOOL isOffice, BOOL isXPBrand, BYTE flagVersion); - BOOL LoadHyperellipticCurve(QWORD *f, Q_OWORD priv, QWORD modulous, QWORD nonresidue, BOOL isOffice, BOOL isXPBrand, - BYTE flagVersion); + BOOL LoadHyperellipticCurve(QWORD *f, Q_OWORD priv, QWORD modulus, QWORD nonresidue, DWORD32 iidkey, BOOL isOffice, + BOOL isXPBrand, BYTE flagVersion); CONFIRMATION_ID_STATUS Generate(const std::string &installation_id_str, std::string &confirmation_id, std::string &productid); ~ConfirmationID() { - delete residue, polynomial, divisor; + delete residue; + delete polynomial; + delete divisor; } }; diff --git a/src/libumskt/confid/divisor.cpp b/src/libumskt/confid/divisor.cpp index bd515ec..e2b3692 100644 --- a/src/libumskt/confid/divisor.cpp +++ b/src/libumskt/confid/divisor.cpp @@ -39,7 +39,7 @@ int ConfirmationID::ConfirmationID::Divisor::find_divisor_v(TDivisor *d) f2[i] = parent->curve[i]; } - const QWORD u0 = d->u[0], u1 = d->u[1]; + const QWORD u0 = d->u.qword[0], u1 = d->u.qword[1]; for (BYTE j = 4; j--;) { f2[j] = parent->residue->sub(f2[j], parent->residue->mul(u0, f2[j + 2])); @@ -106,8 +106,8 @@ int ConfirmationID::ConfirmationID::Divisor::find_divisor_v(TDivisor *d) QWORD v0 = parent->residue->mul(parent->residue->add(f1, parent->residue->mul(u1, parent->residue->mul(v1, v1))), parent->residue->inv(parent->residue->add(v1, v1))); - d->v[0] = v0; - d->v[1] = v1; + d->v.qword[0] = v0; + d->v.qword[1] = v1; return 1; } @@ -121,24 +121,24 @@ int ConfirmationID::ConfirmationID::Divisor::find_divisor_v(TDivisor *d) */ int ConfirmationID::ConfirmationID::Divisor::u2poly(const TDivisor *src, QWORD polyu[3], QWORD polyv[2]) { - if (src->u[1] != BAD) + if (src->u.qword[1] != BAD) { - polyu[0] = src->u[0]; - polyu[1] = src->u[1]; + polyu[0] = src->u.qword[0]; + polyu[1] = src->u.qword[1]; polyu[2] = 1; - polyv[0] = src->v[0]; - polyv[1] = src->v[1]; + polyv[0] = src->v.qword[0]; + polyv[1] = src->v.qword[1]; return 2; } - if (src->u[0] != BAD) + if (src->u.qword[0] != BAD) { - polyu[0] = src->u[0]; + polyu[0] = src->u.qword[0]; polyu[1] = 1; - polyv[0] = src->v[0]; + polyv[0] = src->v.qword[0]; polyv[1] = 0; return 1; @@ -237,7 +237,7 @@ void ConfirmationID::Divisor::add(const TDivisor *src1, const TDivisor *src2, TD } } - vdeg = parent->polynomial->div_monic(vdeg, v, udeg, u, NULL); + vdeg = parent->polynomial->div_monic(vdeg, v, udeg, u, nullptr); while (udeg > 2) { @@ -279,30 +279,30 @@ void ConfirmationID::Divisor::add(const TDivisor *src1, const TDivisor *src2, TD v[i] = parent->residue->sub(0, v[i]); } - vdeg = parent->polynomial->div_monic(vdeg, v, udeg, u, NULL); + vdeg = parent->polynomial->div_monic(vdeg, v, udeg, u, nullptr); } if (udeg == 2) { - dst->u[0] = u[0]; - dst->u[1] = u[1]; - dst->v[0] = (vdeg >= 0 ? v[0] : 0); - dst->v[1] = (vdeg >= 1 ? v[1] : 0); + dst->u.qword[0] = u[0]; + dst->u.qword[1] = u[1]; + dst->v.qword[0] = (vdeg >= 0 ? v[0] : 0); + dst->v.qword[1] = (vdeg >= 1 ? v[1] : 0); } else if (udeg == 1) { - dst->u[0] = u[0]; - dst->u[1] = BAD; - dst->v[0] = (vdeg >= 0 ? v[0] : 0); - dst->v[1] = BAD; + dst->u.qword[0] = u[0]; + dst->u.qword[1] = BAD; + dst->v.qword[0] = (vdeg >= 0 ? v[0] : 0); + dst->v.qword[1] = BAD; } else { assert(udeg == 0); - dst->u[0] = BAD; - dst->u[1] = BAD; - dst->v[0] = BAD; - dst->v[1] = BAD; + dst->u.qword[0] = BAD; + dst->u.qword[1] = BAD; + dst->v.qword[0] = BAD; + dst->v.qword[1] = BAD; } } @@ -318,10 +318,10 @@ void ConfirmationID::Divisor::mul(const TDivisor *src, QWORD mult, TDivisor *dst { if (mult == 0) { - dst->u[0] = BAD; - dst->u[1] = BAD; - dst->v[0] = BAD; - dst->v[1] = BAD; + dst->u.qword[0] = BAD; + dst->u.qword[1] = BAD; + dst->v.qword[0] = BAD; + dst->v.qword[1] = BAD; return; } @@ -354,10 +354,10 @@ void ConfirmationID::Divisor::mul128(const TDivisor *src, QWORD mult_lo, QWORD m { if (mult_lo == 0 && mult_hi == 0) { - dst->u[0] = BAD; - dst->u[1] = BAD; - dst->v[0] = BAD; - dst->v[1] = BAD; + dst->u.qword[0] = BAD; + dst->u.qword[1] = BAD; + dst->v.qword[0] = BAD; + dst->v.qword[1] = BAD; return; } diff --git a/src/libumskt/debugoutput.cpp b/src/libumskt/debugoutput.cpp index 7762a12..4b5f27b 100644 --- a/src/libumskt/debugoutput.cpp +++ b/src/libumskt/debugoutput.cpp @@ -22,17 +22,7 @@ #include "libumskt.h" -#ifdef _WIN32 -// 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 +std::FILE *UMSKT::debug; BOOL UMSKT::VERBOSE = false; BOOL UMSKT::DEBUG = false; diff --git a/src/libumskt/libumskt.cpp b/src/libumskt/libumskt.cpp index bed2056..c3f8af6 100644 --- a/src/libumskt/libumskt.cpp +++ b/src/libumskt/libumskt.cpp @@ -28,10 +28,10 @@ #include "pidgen3/PIDGEN3.h" std::map UMSKT::tags; +CryptoPP::DefaultAutoSeededRNG UMSKT::rng; extern "C" { - /** * Sets debug output to a given C++ File stream * if the memory allocated at filestream is "STDOUT" or "STDERR" @@ -195,7 +195,7 @@ extern "C" std::string str; BOOL retval = p3->Generate(str); - assert(pKeySizeIn >= str.length() + 1); + assert(pKeySizeIn >= str.length() + NULL_TERMINATOR); memcpy(pKeyOut, &str[0], str.length()); pKeyOut[str.length()] = 0; @@ -245,48 +245,3 @@ extern "C" } } // extern "C" - -/** - * Convert data between endianness types. - * - * @param data [in] - * @param length [in] - **/ -void UMSKT::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 UMSKT::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; -} \ No newline at end of file diff --git a/src/libumskt/libumskt.h b/src/libumskt/libumskt.h index 234f1c3..c043ddc 100644 --- a/src/libumskt/libumskt.h +++ b/src/libumskt/libumskt.h @@ -29,34 +29,68 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using Integer = CryptoPP::Integer; +using ECP = CryptoPP::ECP; +using SHA = CryptoPP::SHA1; #include #include +#include + +class HexInteger : public Integer +{ +}; + +// fmt <-> CryptoPP linkage +template <> struct fmt::formatter : fmt::formatter +{ + auto format(const HexInteger &i, format_context &ctx) const + { + size_t size = i.MinEncodedSize(); + CryptoPP::SecByteBlock encoded; + encoded.resize(size); + i.Encode(encoded, size); + + std::string hexString; + + CryptoPP::HexEncoder encoder(new CryptoPP::StringSink(hexString), false); + encoder.Put(encoded, size); + encoder.MessageEnd(); + + return fmt::formatter::format(hexString, ctx); + } +}; + +template <> struct fmt::formatter : ostream_formatter +{ + auto format(const Integer &i, format_context &ctx) const + { + return basic_ostream_formatter::format(i, ctx); + } +}; // Algorithm macros #define PK_LENGTH 25 #define NULL_TERMINATOR 1 -#define FIELD_BITS 384 -#define FIELD_BYTES 48 -#define FIELD_BITS_2003 512 -#define FIELD_BYTES_2003 64 - -#define SHA_MSG_LENGTH_XP (4 + 2 * FIELD_BYTES) -#define SHA_MSG_LENGTH_2003 (3 + 2 * FIELD_BYTES_2003) - #define NEXTSNBITS(field, n, offset) (((QWORD)(field) >> (offset)) & ((1ULL << (n)) - 1)) #define FIRSTNBITS(field, n) NEXTSNBITS((field), (n), 0) #define HIBYTES(field, bytes) NEXTSNBITS((QWORD)(field), ((bytes) * 8), ((bytes) * 8)) #define LOBYTES(field, bytes) FIRSTNBITS((QWORD)(field), ((bytes) * 8)) -#define BYDWORD(n) (DWORD)(*((n) + 0) | *((n) + 1) << 8 | *((n) + 2) << 16 | *((n) + 3) << 24) +#define BYDWORD(n) (DWORD32)(*((n) + 0) | *((n) + 1) << 8 | *((n) + 2) << 16 | *((n) + 3) << 24) #define BITMASK(n) ((1ULL << (n)) - 1) #ifndef LIBUMSKT_VERSION_STRING @@ -79,7 +113,7 @@ struct UMSKT_Value union { BOOL boolean; WORD word; - DWORD dword; + DWORD32 dword; QWORD qword; OWORD oword; char *chars; @@ -107,10 +141,7 @@ class EXPORT UMSKT static BOOL VERBOSE; static BOOL DEBUG; static std::map tags; - - // Hello OpenSSL developers, please tell me, where is this function at? - static int BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen); - static void endian(BYTE *data, int length); + static CryptoPP::DefaultAutoSeededRNG rng; static void DESTRUCT() { @@ -126,7 +157,7 @@ class EXPORT UMSKT template static T getRandom() { T retval; - RAND_bytes((BYTE *)&retval, sizeof(retval)); + rng.GenerateBlock((BYTE *)&retval, sizeof(retval)); return retval; } diff --git a/src/libumskt/pidgen2/PIDGEN2.cpp b/src/libumskt/pidgen2/PIDGEN2.cpp index 2eb55dc..d925681 100644 --- a/src/libumskt/pidgen2/PIDGEN2.cpp +++ b/src/libumskt/pidgen2/PIDGEN2.cpp @@ -199,10 +199,10 @@ int PIDGEN2::GenerateOEM(char *year, char *day, char *oem, char *&keyout) if (!isValidDay(day)) { auto iday = UMSKT::getRandom(); - iday = (iday + 1) % 365; + iday = (iday + NULL_TERMINATOR) % 365; } - _strncpy(keyout, 32, &fmt::format("{}{}-OEM-{}-{}", year, day, oem, oem).c_str()[0], 32); + _strncpy(keyout, 32, fmt::format("{}{}-OEM-{}-{}", year, day, oem, oem).c_str(), 32); return 0; } \ No newline at end of file diff --git a/src/libumskt/pidgen2/PIDGEN2.h b/src/libumskt/pidgen2/PIDGEN2.h index 643a72c..3c89bfd 100644 --- a/src/libumskt/pidgen2/PIDGEN2.h +++ b/src/libumskt/pidgen2/PIDGEN2.h @@ -27,8 +27,8 @@ class EXPORT PIDGEN2 { - DWORD year; - DWORD day; + DWORD32 year; + DWORD32 day; BOOL isOEM; BOOL isOffice; diff --git a/src/libumskt/pidgen3/BINK1998.cpp b/src/libumskt/pidgen3/BINK1998.cpp index 71aa350..5f26b4c 100644 --- a/src/libumskt/pidgen3/BINK1998.cpp +++ b/src/libumskt/pidgen3/BINK1998.cpp @@ -34,15 +34,20 @@ * * @param pRaw [in] *QWORD[2] raw product key input **/ -BOOL BINK1998::Pack(QWORD *pRaw) +BOOL BINK1998::Pack(Q_OWORD *pRaw) { // 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(info.Signature, 5) << 59 | FIRSTNBITS(info.Hash, 28) << 31 | info.Serial << 1 | info.isUpgrade; - pRaw[1] = NEXTSNBITS(info.Signature, 51, 5); + Integer raw; + raw += info.Signature << 59; + raw += (info.Hash & BITMASK(28)) << 31; + raw += info.Serial << 1; + raw += info.isUpgrade; + + raw.Encode(pRaw->byte, sizeof(Q_OWORD)); return true; } @@ -52,22 +57,22 @@ BOOL BINK1998::Pack(QWORD *pRaw) * * @param pRaw [out] *QWORD[2] raw product key output **/ -BOOL BINK1998::Unpack(QWORD *pRaw) +BOOL BINK1998::Unpack(Q_OWORD *pRaw) { // We're assuming that the quantity of information within the product key is at most 114 bits. // log2(24^25) = 114. // Upgrade = Bit 0 - info.isUpgrade = FIRSTNBITS(pRaw[0], 1); + info.isUpgrade = FIRSTNBITS(pRaw->qword[0], 1); // Serial = Bits [1..30] -> 30 bits - info.Serial = NEXTSNBITS(pRaw[0], 30, 1); + info.Serial = NEXTSNBITS(pRaw->qword[0], 30, 1); // Hash = Bits [31..58] -> 28 bits - info.Hash = NEXTSNBITS(pRaw[0], 28, 31); + info.Hash = NEXTSNBITS(pRaw->qword[0], 28, 31); // Signature = Bits [59..113] -> 56 bits - info.Signature = FIRSTNBITS(pRaw[1], 51) << 5 | NEXTSNBITS(pRaw[0], 5, 59); + info.Signature = FIRSTNBITS(pRaw->qword[1], 51) << 5 | NEXTSNBITS(pRaw->qword[0], 5, 59); return true; } @@ -81,51 +86,55 @@ BOOL BINK1998::Unpack(QWORD *pRaw) */ BOOL BINK1998::Generate(std::string &pKey) { - BN_CTX *numContext = BN_CTX_new(); + Integer c, s; - BIGNUM *c = BN_CTX_get(numContext), *s = BN_CTX_get(numContext), *x = BN_CTX_get(numContext), - *y = BN_CTX_get(numContext); - - QWORD pRaw[2]; + Q_OWORD pRaw; // Data segment of the RPK. - DWORD pData = info.Serial << 1 | info.isUpgrade; + Integer pData = info.Serial << 1 | info.isUpgrade; // prepare the private key for generation - BN_sub(privateKey, genOrder, privateKey); + privateKey -= genOrder; + + Integer limit; + limit.SetBit(55); + limit -= 1; do { - EC_POINT *r = EC_POINT_new(eCurve); + ECP::Point R; // Generate a random number c consisting of 384 bits without any constraints. - BN_rand(c, FIELD_BITS, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY); + c.Randomize(UMSKT::rng, FieldBits); // Pick a random derivative of the base point on the elliptic curve. // R = cG; - EC_POINT_mul(eCurve, r, nullptr, genPoint, c, numContext); + R = eCurve.Multiply(c, genPoint); // Acquire its coordinates. // x = R.x; y = R.y; - EC_POINT_get_affine_coordinates(eCurve, r, x, y, numContext); - BYTE msgDigest[SHA_DIGEST_LENGTH], msgBuffer[SHA_MSG_LENGTH_XP]; - BYTE xBin[FIELD_BYTES], yBin[FIELD_BYTES]; - - // Convert coordinates to bytes. - UMSKT::BN_bn2lebin(x, xBin, FIELD_BYTES); - UMSKT::BN_bn2lebin(y, yBin, FIELD_BYTES); + BYTE msgDigest[SHA::DIGESTSIZE], msgBuffer[SHAMessageLength], *pMsgBuffer = msgBuffer; // Assemble the SHA message. - memcpy(&msgBuffer[0], &pData, 4); - memcpy(&msgBuffer[4], xBin, FIELD_BYTES); - memcpy(&msgBuffer[4 + FIELD_BYTES], yBin, FIELD_BYTES); + pData.Encode((CryptoPP::byte *)msgBuffer, 4); + pMsgBuffer += 4; + + R.x.Encode(pMsgBuffer, FieldBytes); + pMsgBuffer += FieldBytes; + + R.y.Encode(pMsgBuffer, FieldBytes); + pMsgBuffer += FieldBytes; // pHash = SHA1(pSerial || R.x || R.y) - SHA1(msgBuffer, SHA_MSG_LENGTH_XP, msgDigest); + auto digest = SHA(); + digest.Update(msgBuffer, SHAMessageLength); + digest.Final(msgDigest); // Translate the byte digest into a 32-bit integer - this is our computed pHash. // Truncate the pHash to 28 bits. + + info.Hash.Decode(msgDigest, SHAMessageLength); info.Hash = BYDWORD(msgDigest) >> 4 & BITMASK(28); /* @@ -148,37 +157,33 @@ BOOL BINK1998::Generate(std::string &pKey) */ // s = ek; - BN_copy(s, privateKey); - BN_mul_word(s, info.Hash); + s = privateKey * info.Hash; // s += c (mod n) - BN_mod_add(s, s, c, genOrder, numContext); + s = s + c % genOrder; // Translate resulting scalar into a 64-bit integer (the byte order is little-endian). - BN_bn2lebinpad(s, (BYTE *)&info.Signature, BN_num_bytes(s)); + info.Signature = s; // Pack product key. - Pack(pRaw); + Pack(&pRaw); auto serial = fmt::format("{:d}", info.Serial); fmt::print(UMSKT::debug, "Generation results:\n"); - fmt::print(UMSKT::debug, "{:>10}: {:b}\n", "Upgrade", (bool)info.isUpgrade); + fmt::print(UMSKT::debug, "{:>10}: {}\n", "Upgrade", (bool)info.isUpgrade); fmt::print(UMSKT::debug, "{:>10}: {}\n", "Channel ID", serial.substr(0, 3)); fmt::print(UMSKT::debug, "{:>10}: {}\n", "Sequence", serial.substr(3)); - fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Hash", info.Hash); - fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Signature", info.Signature); + fmt::print(UMSKT::debug, "{:>10}: {}\n", "Hash", info.Hash); + fmt::print(UMSKT::debug, "{:>10}: {}\n", "Signature", info.Signature); fmt::print(UMSKT::debug, "\n"); - EC_POINT_free(r); - } while (info.Signature > BITMASK(55)); + } while (info.Signature > limit); // ↑ ↑ ↑ // The signature can't be longer than 55 bits, else it will // make the CD-key longer than 25 characters. // Convert bytecode to Base24 CD-key. - base24(pKey, (BYTE *)pRaw); - - BN_CTX_free(numContext); + base24(pKey, pRaw.byte); return true; } @@ -197,26 +202,24 @@ BOOL BINK1998::Validate(std::string &pKey) return false; } - BN_CTX *numContext = BN_CTX_new(); - - QWORD pRaw[2]; + Q_OWORD pRaw; // Convert Base24 CD-key to bytecode. - unbase24((BYTE *)pRaw, pKey); + unbase24(pRaw.byte, pKey); // Extract RPK, hash and signature from bytecode. - Unpack(pRaw); + Unpack(&pRaw); auto serial = fmt::format("{:d}", info.Serial); fmt::print(UMSKT::debug, "Validation results:\n"); fmt::print(UMSKT::debug, "{:>10}: {}\n", "Upgrade", (bool)info.isUpgrade); fmt::print(UMSKT::debug, "{:>10}: {}\n", "Channel ID", serial.substr(0, 3)); fmt::print(UMSKT::debug, "{:>10}: {}\n", "Sequence", serial.substr(3)); - fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Hash", info.Hash); - fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Signature", info.Signature); + fmt::print(UMSKT::debug, "{:>10}: {}\n", "Hash", info.Hash); + fmt::print(UMSKT::debug, "{:>10}: {}\n", "Signature", info.Signature); fmt::print(UMSKT::debug, "\n"); - DWORD pData = info.Serial << 1 | info.isUpgrade; + Integer pData = info.Serial << 1 | info.isUpgrade; /* * @@ -233,51 +236,43 @@ BOOL BINK1998::Validate(std::string &pKey) * */ - BIGNUM *e = BN_lebin2bn((BYTE *)&info.Hash, sizeof(info.Hash), nullptr), - *s = BN_lebin2bn((BYTE *)&info.Signature, sizeof(info.Signature), nullptr); - - BIGNUM *x = BN_CTX_get(numContext), *y = BN_CTX_get(numContext); + Integer e = info.Hash, s; + s.Decode((BYTE *)&info.Signature, sizeof(info.Signature)); // Create 2 points on the elliptic curve. - EC_POINT *t = EC_POINT_new(eCurve), *p = EC_POINT_new(eCurve); + ECP::Point t, P; // t = sG - EC_POINT_mul(eCurve, t, nullptr, genPoint, s, numContext); + t = eCurve.Multiply(s, genPoint); // P = eK - EC_POINT_mul(eCurve, p, nullptr, pubPoint, e, numContext); + P = eCurve.Multiply(e, pubPoint); // P += t - EC_POINT_add(eCurve, p, t, p, numContext); + P = eCurve.Add(P, t); - // x = P.x; y = P.y; - EC_POINT_get_affine_coordinates(eCurve, p, x, y, numContext); - - BYTE msgDigest[SHA_DIGEST_LENGTH], msgBuffer[SHA_MSG_LENGTH_XP], xBin[FIELD_BYTES], yBin[FIELD_BYTES]; + BYTE msgDigest[SHA::DIGESTSIZE], msgBuffer[SHAMessageLength], *pMsgBuffer = msgBuffer; // Convert resulting point coordinates to bytes. - UMSKT::BN_bn2lebin(x, xBin, FIELD_BYTES); - UMSKT::BN_bn2lebin(y, yBin, FIELD_BYTES); // Assemble the SHA message. - memcpy(&msgBuffer[0], &pData, 4); - memcpy(&msgBuffer[4], xBin, FIELD_BYTES); - memcpy(&msgBuffer[4 + FIELD_BYTES], yBin, FIELD_BYTES); + pData.Encode(pMsgBuffer, 4); + pMsgBuffer += 4; + + P.x.Encode(pMsgBuffer, FieldBytes); + pMsgBuffer += FieldBytes; + + P.y.Encode(pMsgBuffer, FieldBytes); + pMsgBuffer += FieldBytes; // compHash = SHA1(pSerial || P.x || P.y) - SHA1(msgBuffer, SHA_MSG_LENGTH_XP, msgDigest); + auto digest = SHA(); + digest.Update(msgBuffer, SHAMessageLength); + digest.Final(msgDigest); // Translate the byte digest into a 32-bit integer - this is our computed hash. // Truncate the hash to 28 bits. - DWORD compHash = BYDWORD(msgDigest) >> 4 & BITMASK(28); - - BN_free(e); - BN_free(s); - - BN_CTX_free(numContext); - - EC_POINT_free(t); - EC_POINT_free(p); + Integer compHash = BYDWORD(msgDigest) >> 4 & BITMASK(28); // If the computed hash checks out, the key is valid. return compHash == info.Hash; diff --git a/src/libumskt/pidgen3/BINK1998.h b/src/libumskt/pidgen3/BINK1998.h index ae20c6a..65dbbad 100644 --- a/src/libumskt/pidgen3/BINK1998.h +++ b/src/libumskt/pidgen3/BINK1998.h @@ -29,6 +29,7 @@ class EXPORT BINK1998 : public PIDGEN3 { public: using PIDGEN3::PIDGEN3; + BINK1998() = default; explicit BINK1998(PIDGEN3 *p3) { privateKey = p3->privateKey; @@ -38,11 +39,15 @@ class EXPORT BINK1998 : public PIDGEN3 eCurve = p3->eCurve; } + static constexpr DWORD32 FieldBits = 384; + static constexpr DWORD32 FieldBytes = FieldBits / 8; + static constexpr DWORD32 SHAMessageLength = (4 + 2 * FieldBytes); + using PIDGEN3::Pack; - BOOL Pack(QWORD *pRaw) override; + BOOL Pack(Q_OWORD *pRaw) override; using PIDGEN3::Unpack; - BOOL Unpack(QWORD *pRaw) override; + BOOL Unpack(Q_OWORD *pRaw) override; using PIDGEN3::Generate; BOOL Generate(std::string &pKey) override; diff --git a/src/libumskt/pidgen3/BINK2002.cpp b/src/libumskt/pidgen3/BINK2002.cpp index ebb8168..7caf87b 100644 --- a/src/libumskt/pidgen3/BINK2002.cpp +++ b/src/libumskt/pidgen3/BINK2002.cpp @@ -32,13 +32,19 @@ /** * Packs a Windows Server 2003-like Product Key. * - * @param pRaw *QWORD[2] raw product key output + * @param pRaw [out] *OWORD raw product key **/ -BOOL BINK2002::Pack(QWORD *pRaw) +BOOL BINK2002::Pack(Q_OWORD *pRaw) { - // AuthInfo [113..104] <- Signature [103..42] <- Hash [41..11] <- Channel ID [10..1] <- Upgrade [0] - pRaw[0] = FIRSTNBITS(info.Signature, 22) << 42 | (QWORD)info.Hash << 11 | info.ChannelID << 1 | info.isUpgrade; - pRaw[1] = FIRSTNBITS(info.AuthInfo, 10) << 40 | NEXTSNBITS(info.Signature, 40, 22); + Integer raw; + // AuthInfo [113..104] <- Signature [103..42] <- Hash [41..11] <- Channel ID [10..1] <- Upgrade [0]; + raw += (info.AuthInfo & ((1 << 11) - 1)) << 104; + raw += info.Signature << 42; + raw += info.Hash << 11; + raw += info.ChannelID << 1; + raw += info.isUpgrade; + + raw.Encode((BYTE *)pRaw, sizeof(QWORD) * 2); return true; } @@ -46,29 +52,30 @@ BOOL BINK2002::Pack(QWORD *pRaw) /** * Unpacks a Windows Server 2003-like Product Key. * - * @param pRaw *QWORD[2] raw product key input + * @param pRaw [in] *OWORD raw product key input **/ -BOOL BINK2002::Unpack(QWORD *pRaw) +BOOL BINK2002::Unpack(Q_OWORD *pRaw) { // We're assuming that the quantity of information within the product key is at most 114 bits. // log2(24^25) = 114. // Upgrade = Bit 0 - info.isUpgrade = FIRSTNBITS(pRaw[0], 1); + info.isUpgrade = FIRSTNBITS(pRaw->qword[0], 1); // Channel ID = Bits [1..10] -> 10 bits - info.ChannelID = NEXTSNBITS(pRaw[0], 10, 1); + info.ChannelID = NEXTSNBITS(pRaw->qword[0], 10, 1); // Hash = Bits [11..41] -> 31 bits - info.Hash = NEXTSNBITS(pRaw[0], 31, 11); + info.Hash = NEXTSNBITS(pRaw->qword[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) - info.Signature = NEXTSNBITS(pRaw[1], 30, 10) << 32 | FIRSTNBITS(pRaw[1], 10) << 22 | NEXTSNBITS(pRaw[0], 22, 42); + info.Signature = NEXTSNBITS(pRaw->qword[0], 30, 10) << 32 | FIRSTNBITS(pRaw->qword[1], 10) << 22 | + NEXTSNBITS(pRaw->qword[0], 22, 42); // AuthInfo = Bits [104..113] -> 10 bits - info.AuthInfo = NEXTSNBITS(pRaw[1], 10, 40); + info.AuthInfo = NEXTSNBITS(pRaw->qword[1], 10, 40); return true; } @@ -82,76 +89,83 @@ BOOL BINK2002::Unpack(QWORD *pRaw) */ BOOL BINK2002::Generate(std::string &pKey) { - BN_CTX *numContext = BN_CTX_new(); + Integer c, e, s; - BIGNUM *c = BN_CTX_get(numContext), *e = BN_CTX_get(numContext), *s = BN_CTX_get(numContext), - *x = BN_CTX_get(numContext), *y = BN_CTX_get(numContext); + Q_OWORD pRaw; - QWORD pRaw[2]; + Integer limit; + limit.SetBit(62); + limit--; // Data segment of the RPK. - DWORD pData = info.ChannelID << 1 | info.isUpgrade; + Integer pData = info.ChannelID << 1 | info.isUpgrade; BOOL noSquare; do { - EC_POINT *r = EC_POINT_new(eCurve); + ECP::Point R; // Generate a random number c consisting of 512 bits without any constraints. - BN_rand(c, FIELD_BITS_2003, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY); + c.Randomize(UMSKT::rng, FieldBits); // R = cG - EC_POINT_mul(eCurve, r, nullptr, genPoint, c, numContext); + R = eCurve.Multiply(c, genPoint); - // Acquire its coordinates. - // x = R.x; y = R.y; - EC_POINT_get_affine_coordinates(eCurve, r, x, y, numContext); - - BYTE msgDigest[SHA_DIGEST_LENGTH], msgBuffer[SHA_MSG_LENGTH_2003], xBin[FIELD_BYTES_2003], - yBin[FIELD_BYTES_2003]; - - // Convert resulting point coordinates to bytes. - UMSKT::BN_bn2lebin(x, xBin, FIELD_BYTES_2003); - UMSKT::BN_bn2lebin(y, yBin, FIELD_BYTES_2003); + BYTE msgDigest[SHA::DIGESTSIZE], msgBuffer[SHAMessageLength], *pMsgBuffer = msgBuffer; // Assemble the first SHA message. - msgBuffer[0x00] = 0x79; - msgBuffer[0x01] = (pData & 0x00FF); - msgBuffer[0x02] = (pData & 0xFF00) >> 8; + msgBuffer[0] = 0x79; + pMsgBuffer++; - memcpy(&msgBuffer[3], xBin, FIELD_BYTES_2003); - memcpy(&msgBuffer[3 + FIELD_BYTES_2003], yBin, FIELD_BYTES_2003); + pData.Encode(pMsgBuffer, 2); + pMsgBuffer += 2; + + // Convert resulting point coordinates to bytes. + // and flip the endianness + R.x.Encode(pMsgBuffer, FieldBytes); + std::reverse(pMsgBuffer, pMsgBuffer + FieldBytes); + pMsgBuffer += FieldBytes; + + R.y.Encode(pMsgBuffer, FieldBytes); + std::reverse(pMsgBuffer, pMsgBuffer + FieldBytes); + pMsgBuffer += FieldBytes; // pHash = SHA1(79 || Channel ID || R.x || R.y) - SHA1(msgBuffer, SHA_MSG_LENGTH_2003, msgDigest); + auto digest = SHA(); + digest.Update(msgBuffer, FieldBytes); + digest.Final(msgDigest); // Translate the byte digest into a 32-bit integer - this is our computed hash. // Truncate the hash to 31 bits. info.Hash = BYDWORD(msgDigest) & BITMASK(31); // Assemble the second SHA message. + pMsgBuffer = msgBuffer; msgBuffer[0x00] = 0x5D; - msgBuffer[0x01] = (pData & 0x00FF); - msgBuffer[0x02] = (pData & 0xFF00) >> 8; - msgBuffer[0x03] = (info.Hash & 0x000000FF); - msgBuffer[0x04] = (info.Hash & 0x0000FF00) >> 8; - msgBuffer[0x05] = (info.Hash & 0x00FF0000) >> 16; - msgBuffer[0x06] = (info.Hash & 0xFF000000) >> 24; - msgBuffer[0x07] = (info.AuthInfo & 0x00FF); - msgBuffer[0x08] = (info.AuthInfo & 0xFF00) >> 8; + pMsgBuffer++; + + pData.Encode(pMsgBuffer, 2); + pMsgBuffer += 2; + + info.Hash.Encode(pMsgBuffer, 4); + pMsgBuffer += 4; + + info.AuthInfo.Encode(pMsgBuffer, 2); + pMsgBuffer += 2; + msgBuffer[0x09] = 0x00; msgBuffer[0x0A] = 0x00; // newSignature = SHA1(5D || Channel ID || Hash || AuthInfo || 00 00) - SHA1(msgBuffer, 11, msgDigest); + digest = SHA(); + digest.Update(msgBuffer, 0x0B); + digest.Final(msgDigest); // Translate the byte digest into a 64-bit integer - this is our computed intermediate signature. // As the signature is only 62 bits long at most, we have to truncate it by shifting the high DWORD right 2 // bits (per spec). - QWORD iSignature = NEXTSNBITS(BYDWORD(&msgDigest[4]), 30, 2) << 32 | BYDWORD(msgDigest); - - BN_lebin2bn((BYTE *)&iSignature, sizeof(iSignature), e); + Integer iSignature = NEXTSNBITS(BYDWORD(&msgDigest[4]), 30, 2) << 32 | BYDWORD(msgDigest); /* * @@ -183,63 +197,57 @@ BOOL BINK2002::Generate(std::string &pKey) */ // e = ek (mod n) - BN_mod_mul(e, e, privateKey, genOrder, numContext); - - // s = e - BN_copy(s, e); + e = iSignature * privateKey % genOrder; // s = (ek (mod n))² - BN_mod_sqr(s, s, genOrder, numContext); + s = CryptoPP::ModularExponentiation(e, Integer::Two(), genOrder); // c *= 4 (c <<= 2) - BN_lshift(c, c, 2); + c <<= 2; // s += c - BN_add(s, s, c); + s += c; // Around half of numbers modulo a prime are not squares -> BN_sqrt_mod fails about half of the times, // hence if BN_sqrt_mod returns NULL, we need to restart with a different seed. // s = √((ek)² + 4c (mod n)) - noSquare = BN_mod_sqrt(s, s, genOrder, numContext) == nullptr; + s = CryptoPP::ModularSquareRoot(s, genOrder); // s = -ek + √((ek)² + 4c) (mod n) - BN_mod_sub(s, s, e, genOrder, numContext); + s = s - e % genOrder; // If s is odd, add order to it. // The order is a prime, so it can't be even. - if (BN_is_odd(s)) + if (s % Integer::Two() != 0) { // s = -ek + √((ek)² + 4c) + n - BN_add(s, s, genOrder); + s += genOrder; } // s /= 2 (s >>= 1) - BN_rshift1(s, s); + s >>= 1; // Translate resulting scalar into a 64-bit integer (the byte order is little-endian). - BN_bn2lebinpad(s, (BYTE *)&info.Signature, BN_num_bytes(s)); + info.Signature = s; // Pack product key. - Pack(pRaw); + Pack(&pRaw); fmt::print(UMSKT::debug, "Generation results:\n"); - fmt::print(UMSKT::debug, "{:>10}: {:b}\n", "Upgrade", (bool)info.isUpgrade); - fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Channel ID", info.ChannelID); - fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Hash", info.Hash); - fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Signature", info.Signature); - fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "AuthInfo", info.AuthInfo); + fmt::print(UMSKT::debug, "{:>10}: {}\n", "Upgrade", (bool)info.isUpgrade); + fmt::print(UMSKT::debug, "{:>10}: {}\n", "Channel ID", info.ChannelID); + fmt::print(UMSKT::debug, "{:>10}: {}\n", "Hash", info.Hash); + fmt::print(UMSKT::debug, "{:>10}: {}\n", "Signature", info.Signature); + fmt::print(UMSKT::debug, "{:>10}: {}\n", "AuthInfo", info.AuthInfo); fmt::print(UMSKT::debug, "\n"); - EC_POINT_free(r); - } while (info.Signature > BITMASK(62) || noSquare); + } while (info.Signature > limit || noSquare); // ↑ ↑ ↑ // The signature can't be longer than 62 bits, else it will // overlap with the AuthInfo segment next to it. // Convert bytecode to Base24 CD-key. - base24(pKey, (BYTE *)pRaw); - - BN_CTX_free(numContext); + base24(pKey, pRaw.byte); return true; } @@ -251,48 +259,51 @@ BOOL BINK2002::Generate(std::string &pKey) **/ BOOL BINK2002::Validate(std::string &pKey) { - BN_CTX *context = BN_CTX_new(); - - QWORD bKey[2]; + Q_OWORD bKey; // Convert Base24 CD-key to bytecode. - unbase24((BYTE *)bKey, &pKey[0]); + unbase24(bKey.byte, &pKey[0]); // Extract product key segments from bytecode. - Unpack(bKey); + Unpack(&bKey); - DWORD pData = info.ChannelID << 1 | info.isUpgrade; + Integer pData = info.ChannelID << 1 | info.isUpgrade; fmt::print(UMSKT::debug, "Validation results:\n"); - fmt::print(UMSKT::debug, "{:>10}: {:b}\n", "Upgrade", (bool)info.isUpgrade); + fmt::print(UMSKT::debug, "{:>10}: {}\n", "Upgrade", (bool)info.isUpgrade); fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Channel ID", info.ChannelID); fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Hash", info.Hash); fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Signature", info.Signature); fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "AuthInfo", info.AuthInfo); fmt::print(UMSKT::debug, "\n"); - BYTE msgDigest[SHA_DIGEST_LENGTH], msgBuffer[SHA_MSG_LENGTH_2003], xBin[FIELD_BYTES_2003], yBin[FIELD_BYTES_2003]; + BYTE msgDigest[SHA::DIGESTSIZE], msgBuffer[SHAMessageLength], *pMsgBuffer = msgBuffer; // Assemble the first SHA message. msgBuffer[0x00] = 0x5D; - msgBuffer[0x01] = (pData & 0x00FF); - msgBuffer[0x02] = (pData & 0xFF00) >> 8; - msgBuffer[0x03] = (info.Hash & 0x000000FF); - msgBuffer[0x04] = (info.Hash & 0x0000FF00) >> 8; - msgBuffer[0x05] = (info.Hash & 0x00FF0000) >> 16; - msgBuffer[0x06] = (info.Hash & 0xFF000000) >> 24; - msgBuffer[0x07] = (info.AuthInfo & 0x00FF); - msgBuffer[0x08] = (info.AuthInfo & 0xFF00) >> 8; + pMsgBuffer++; + + pData.Encode(pMsgBuffer, 2); + pMsgBuffer += 2; + + info.Hash.Encode(pMsgBuffer, 4); + pMsgBuffer += 4; + + info.AuthInfo.Encode(pMsgBuffer, 2); + pMsgBuffer += 2; + msgBuffer[0x09] = 0x00; msgBuffer[0x0A] = 0x00; // newSignature = SHA1(5D || Channel ID || Hash || AuthInfo || 00 00) - SHA1(msgBuffer, 11, msgDigest); + auto digest = SHA(); + digest.Update(msgBuffer, 0x0B); + digest.Final(msgDigest); // Translate the byte digest into a 64-bit integer - this is our computed intermediate signature. // As the signature is only 62 bits long at most, we have to truncate it by shifting the high DWORD right 2 bits // (per spec). - QWORD iSignature = NEXTSNBITS(BYDWORD(&msgDigest[4]), 30, 2) << 32 | BYDWORD(msgDigest); + Integer iSignature = NEXTSNBITS(BYDWORD(&msgDigest[4]), 30, 2) << 32 | BYDWORD(msgDigest); /* * @@ -308,55 +319,44 @@ BOOL BINK2002::Validate(std::string &pKey) * P = s(sG + eK) * */ - - BIGNUM *e = BN_lebin2bn((BYTE *)&iSignature, sizeof(iSignature), nullptr), - *s = BN_lebin2bn((BYTE *)&info.Signature, sizeof(info.Signature), nullptr); - BIGNUM *x = BN_CTX_get(context), *y = BN_CTX_get(context); + Integer e = iSignature, s = info.Signature; // Create 2 points on the elliptic curve. - EC_POINT *p = EC_POINT_new(eCurve), *t = EC_POINT_new(eCurve); + ECP::Point p, t; // t = sG - EC_POINT_mul(eCurve, t, nullptr, genPoint, s, context); + t = eCurve.Multiply(s, genPoint); // p = eK - EC_POINT_mul(eCurve, p, nullptr, pubPoint, e, context); + p = eCurve.Multiply(e, pubPoint); // p += t - EC_POINT_add(eCurve, p, t, p, context); + p = eCurve.Add(p, t); // p *= s - EC_POINT_mul(eCurve, p, nullptr, p, s, context); - - // x = p.x; y = p.y; - EC_POINT_get_affine_coordinates(eCurve, p, x, y, context); - - // Convert resulting point coordinates to bytes. - UMSKT::BN_bn2lebin(x, xBin, FIELD_BYTES_2003); - UMSKT::BN_bn2lebin(y, yBin, FIELD_BYTES_2003); + p = eCurve.Multiply(s, p); // Assemble the second SHA message. + pMsgBuffer = msgBuffer; msgBuffer[0x00] = 0x79; - msgBuffer[0x01] = (pData & 0x00FF); - msgBuffer[0x02] = (pData & 0xFF00) >> 8; + pMsgBuffer++; - memcpy((void *)&msgBuffer[3], (void *)xBin, FIELD_BYTES_2003); - memcpy((void *)&msgBuffer[3 + FIELD_BYTES_2003], (void *)yBin, FIELD_BYTES_2003); + pData.Encode(pMsgBuffer, 2); + pMsgBuffer += 2; + + p.x.Encode(pMsgBuffer, FieldBytes); + pMsgBuffer += FieldBytes; + + p.y.Encode(pMsgBuffer, FieldBytes); + pMsgBuffer += FieldBytes; // compHash = SHA1(79 || Channel ID || p.x || p.y) - SHA1(msgBuffer, SHA_MSG_LENGTH_2003, msgDigest); + digest.Update(msgBuffer, SHAMessageLength); + digest.Final(msgDigest); // Translate the byte digest into a 32-bit integer - this is our computed hash. // Truncate the hash to 31 bits. - DWORD compHash = BYDWORD(msgDigest) & BITMASK(31); - - BN_free(s); - BN_free(e); - - EC_POINT_free(p); - EC_POINT_free(t); - - BN_CTX_free(context); + Integer compHash = BYDWORD(msgDigest) & BITMASK(31); // If the computed hash checks out, the key is valid. return compHash == info.Hash; diff --git a/src/libumskt/pidgen3/BINK2002.h b/src/libumskt/pidgen3/BINK2002.h index f6e424e..eb7fc56 100644 --- a/src/libumskt/pidgen3/BINK2002.h +++ b/src/libumskt/pidgen3/BINK2002.h @@ -29,6 +29,7 @@ class EXPORT BINK2002 : public PIDGEN3 { public: using PIDGEN3::PIDGEN3; + BINK2002() = default; explicit BINK2002(PIDGEN3 *p3) { privateKey = p3->privateKey; @@ -38,11 +39,15 @@ class EXPORT BINK2002 : public PIDGEN3 eCurve = p3->eCurve; } + static constexpr DWORD32 FieldBits = 512; + static constexpr DWORD32 FieldBytes = FieldBits / 8; + static constexpr DWORD32 SHAMessageLength = (3 + 2 * FieldBytes); + using PIDGEN3::Pack; - BOOL Pack(QWORD *pRaw) override; + BOOL Pack(Q_OWORD *pRaw) override; using PIDGEN3::Unpack; - BOOL Unpack(QWORD *pRaw) override; + BOOL Unpack(Q_OWORD *pRaw) override; using PIDGEN3::Generate; BOOL Generate(std::string &pKey) override; diff --git a/src/libumskt/pidgen3/PIDGEN3.cpp b/src/libumskt/pidgen3/PIDGEN3.cpp index 1f31afa..0768329 100644 --- a/src/libumskt/pidgen3/PIDGEN3.cpp +++ b/src/libumskt/pidgen3/PIDGEN3.cpp @@ -35,6 +35,24 @@ int getRandomNumber() // guaranteed to be random } +/** + * Creates an Integer that populates PIDGEN3::MaxSizeBINK1998 + * Invoked during Runtime startup + * + * @return + */ +Integer MakeMaxSizeBINK1998() +{ + Integer max; + + // 1 << 385 (or max size of BINK1998 field in bits + 1) + max.SetBit((12 * 4 * 8) + 1); + + return max; +} + +const Integer PIDGEN3::MaxSizeBINK1998 = MakeMaxSizeBINK1998(); + /** * Initializes the elliptic curve * @@ -65,61 +83,49 @@ BOOL PIDGEN3::LoadEllipticCurve(const std::string pSel, const std::string aSel, // BIGNUM - Large numbers // BIGNUMCTX - Context large numbers (temporary) - // Context variable - BN_CTX *context = BN_CTX_new(); - // We're presented with an elliptic curve, a multivariable function y(x; p; a; b), where // y^2 % p = x^3 + ax + b % p. - BIGNUM *a = BN_CTX_get(context), *b = BN_CTX_get(context), *p = BN_CTX_get(context); + auto p = Integer(&pSel[0]), a = Integer(&aSel[0]), b = Integer(&bSel[0]), - // Public key will consist of the resulting (x; y) values. - BIGNUM *publicKeyX = BN_CTX_get(context), *publicKeyY = BN_CTX_get(context); + // Public key will consist of the resulting (x; y) values. + generatorX = Integer(&generatorXSel[0]), generatorY = Integer(&generatorYSel[0]), - // G(x; y) is a generator function, its return value represents a point on the elliptic curve. - BIGNUM *generatorX = BN_CTX_get(context), *generatorY = BN_CTX_get(context); - - genOrder = BN_new(); - privateKey = BN_new(); - - /* Public data */ - BN_dec2bn(&p, &pSel[0]); - BN_dec2bn(&a, &aSel[0]); - BN_dec2bn(&b, &bSel[0]); - BN_dec2bn(&generatorX, &generatorXSel[0]); - BN_dec2bn(&generatorY, &generatorYSel[0]); - - BN_dec2bn(&publicKeyX, &publicKeyXSel[0]); - BN_dec2bn(&publicKeyY, &publicKeyYSel[0]); + // G(x; y) is a generator function, its return value represents a point on the elliptic curve. + publicKeyX = Integer(&publicKeyXSel[0]), publicKeyY = Integer(&publicKeyYSel[0]); /* Computed Data */ - BN_dec2bn(&genOrder, &genOrderSel[0]); - BN_dec2bn(&privateKey, &privateKeySel[0]); + genOrder = Integer(&genOrderSel[0]); + privateKey = Integer(&privateKeySel[0]); /* 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); + eCurve = ECP(p, a, b); - // 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 N for the generator on the elliptic curve and set its coordinates to (genX; genY). + genPoint = ECP::Point(generatorX, generatorY); - // 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); + // Create new point Q for the public key on the elliptic curve and set its coordinates to (pubX; pubY). + pubPoint = ECP::Point(publicKeyX, publicKeyY); // 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); + assert(eCurve.VerifyPoint(genPoint) == true); + assert(eCurve.VerifyPoint(pubPoint) == true); return true; } +PIDGEN3 *PIDGEN3::Factory(const std::string &field) +{ + if (checkFieldStrIsBink1998(field)) + { + return new BINK1998(); + } + return new BINK2002(); +} + BOOL PIDGEN3::Generate(std::string &pKey) { BOOL retval; @@ -165,7 +171,6 @@ BOOL PIDGEN3::Validate(std::string &pKey) void PIDGEN3::base24(std::string &cdKey, BYTE *byteSeq) { BYTE rbyteSeq[16], output[26]; - BIGNUM *z; // Copy byte sequence to the reversed byte sequence. memcpy(rbyteSeq, byteSeq, sizeof(rbyteSeq)); @@ -178,22 +183,18 @@ void PIDGEN3::base24(std::string &cdKey, BYTE *byteSeq) ; // do nothing, just counting } - UMSKT::endian(rbyteSeq, ++length); - // Convert reversed byte sequence to BigNum z. - z = BN_bin2bn(rbyteSeq, length, nullptr); + auto z = Integer((BYTE *)&rbyteSeq, sizeof(rbyteSeq)); // Divide z by 24 and convert the remainder to a CD-key char. for (int i = 24; i >= 0; i--) { - output[i] = pKeyCharset[BN_div_word(z, 24)]; + output[i] = pKeyCharset[z.Modulo(24)]; } output[25] = 0; cdKey = (char *)output; - - BN_free(z); } /** @@ -205,7 +206,7 @@ void PIDGEN3::base24(std::string &cdKey, BYTE *byteSeq) void PIDGEN3::unbase24(BYTE *byteSeq, std::string cdKey) { BYTE pDecodedKey[PK_LENGTH + NULL_TERMINATOR]{}; - BIGNUM *y = BN_new(); + Integer 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++) @@ -226,52 +227,40 @@ void PIDGEN3::unbase24(BYTE *byteSeq, std::string cdKey) // 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]); + y *= PK_LENGTH - 1; + y += pDecodedKey[i]; } // Acquire length. - int n = BN_num_bytes(y); + auto n = y.ByteCount(); // Place the generated code into the byte sequence. - BN_bn2bin(y, byteSeq); - BN_free(y); - - // Reverse the byte sequence. - UMSKT::endian(byteSeq, n); + y.Encode(byteSeq, 16); } +/** + * Checks to see if the currently instantiated PIDGEN3 object has a + * field size greater than the maximum known BINK1998 size. + * + * @return + */ BOOL PIDGEN3::checkFieldIsBink1998() { - auto *max = BN_new(); - - // 1 << 385 (or max size of BINK1998 field in bits + 1) - BN_set_bit(max, (12 * 4 * 8) + 1); - - // retval is -1 when (max < privateKey) - int retval = BN_cmp(max, privateKey); - - BN_free(max); - // is max > privateKey? - return retval == 1; + return (MaxSizeBINK1998 > privateKey); } +/** + * Checks if a given field, in a std::string, is greater than + * the maximum known BINK1998 size + * + * @param keyin + * @return + */ BOOL PIDGEN3::checkFieldStrIsBink1998(std::string keyin) { - auto *context = BN_CTX_new(); - auto max = BN_CTX_get(context), input = BN_CTX_get(context); + Integer check(&keyin[0]); - BN_dec2bn(&input, &keyin[0]); - - // 1 << 385 (or max size of BINK1998 field in bits + 1) - BN_set_bit(max, (12 * 4 * 8) + 1); - - // retval is -1 when (max < privateKey) - int retval = BN_cmp(max, input); - - BN_CTX_free(context); - - // is max > privateKey? - return retval == 1; + // is max > check? + return (MaxSizeBINK1998 > check); } diff --git a/src/libumskt/pidgen3/PIDGEN3.h b/src/libumskt/pidgen3/PIDGEN3.h index 7a22220..3cf6d18 100644 --- a/src/libumskt/pidgen3/PIDGEN3.h +++ b/src/libumskt/pidgen3/PIDGEN3.h @@ -34,14 +34,12 @@ class EXPORT PIDGEN3 friend class BINK2002; protected: - BIGNUM *privateKey, *genOrder; - EC_POINT *genPoint, *pubPoint; - EC_GROUP *eCurve; + Integer privateKey, genOrder; + ECP::Point genPoint, pubPoint; + ECP eCurve; public: - PIDGEN3() - { - } + PIDGEN3() = default; PIDGEN3(PIDGEN3 &p3) { @@ -54,43 +52,38 @@ class EXPORT PIDGEN3 virtual ~PIDGEN3() { - EC_GROUP_free(eCurve); - EC_POINT_free(genPoint); - EC_POINT_free(pubPoint); - BN_free(genOrder); - BN_free(privateKey); } struct KeyInfo { - DWORD Serial = 0, AuthInfo = 0, ChannelID = 0, Hash = 0; - QWORD Signature = 0; + Integer Serial = 0, AuthInfo = 0, ChannelID = 0, Hash = 0, Signature = 0; BOOL isUpgrade = false; - void setSerial(DWORD serialIn) + void setSerial(DWORD32 serialIn) { - Serial = serialIn; + Serial.Decode((BYTE *)&serialIn, sizeof(serialIn)); } - void setAuthInfo(DWORD AuthInfoIn) + void setAuthInfo(DWORD32 AuthInfoIn) { - AuthInfo = AuthInfoIn; + AuthInfo.Decode((BYTE *)&AuthInfoIn, sizeof(AuthInfoIn)); } - void setChannelID(DWORD ChannelIDIn) + void setChannelID(DWORD32 ChannelIDIn) { - ChannelID = ChannelIDIn; + ChannelID.Decode((BYTE *)&ChannelIDIn, sizeof(ChannelIDIn)); } } info; static constexpr char pKeyCharset[] = "BCDFGHJKMPQRTVWXY2346789"; + static const Integer MaxSizeBINK1998; 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 Pack(QWORD *pRaw) = 0; - virtual BOOL Unpack(QWORD *pRaw) = 0; + virtual BOOL Pack(Q_OWORD *pRaw) = 0; + virtual BOOL Unpack(Q_OWORD *pRaw) = 0; virtual BOOL Generate(std::string &pKey); virtual BOOL Validate(std::string &pKey); @@ -99,6 +92,7 @@ class EXPORT PIDGEN3 void unbase24(BYTE *byteSeq, std::string cdKey); BOOL checkFieldIsBink1998(); static BOOL checkFieldStrIsBink1998(std::string keyin); + static PIDGEN3 *Factory(const std::string &field); }; #endif // UMSKT_PIDGEN3_H diff --git a/src/typedefs.h b/src/typedefs.h index cec60f6..8809374 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -98,9 +98,10 @@ using BOOL = int32_t; using BYTE = uint8_t; using WORD = uint16_t; using DWORD = unsigned long; +using DWORD32 = uint32_t; using QWORD = uint64_t; -#if defined(_M_ARM) // for Windows on ARM ?? +#if defined(_MSC_VER) && defined(_M_ARM) // for Windows on ARM ?? using __m128 = __n128; #endif @@ -114,7 +115,7 @@ using OWORD = uint128_t; typedef union { OWORD oword; QWORD qword[2]; - DWORD dword[4]; + DWORD32 dword32[4]; WORD word[8]; BYTE byte[16]; } Q_OWORD;