WIP - CryptoPP Port, remove refrences to OpenSSL, many things are currently broken

This commit is contained in:
Neo-Desktop 2024-02-04 20:26:29 -08:00
parent a827844cbd
commit 2ac7f9bc1e
27 changed files with 690 additions and 816 deletions

View File

@ -1,2 +1,2 @@
build*/ build*/
cmake-*/ cmake*/

4
.gitignore vendored
View File

@ -1,4 +1,4 @@
build/* build*/
*.tar *.tar
*.exe *.exe
*.wasm *.wasm
@ -66,7 +66,7 @@ umskt
# *.ipr # *.ipr
# CMake # CMake
cmake-*/ cmake*/
# Mongo Explorer plugin # Mongo Explorer plugin
.idea/**/mongoSettings.xml .idea/**/mongoSettings.xml

View File

@ -19,7 +19,12 @@
# @Maintainer Neo # @Maintainer Neo
repos: 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 rev: 'v17.0.6' # Use the sha / tag you want to point at
hooks: hooks:
- id: clang-format - id: clang-format
# - repo: https://github.com/cheshirekow/cmake-format-precommit
# rev: v0.6.10
# hooks:
# - id: cmake-format

View File

@ -26,32 +26,19 @@ SET(CMAKE_OSX_SYSROOT "macosx" CACHE PATH "macOS SDK path")
SET(CMAKE_POSITION_INDEPENDENT_CODE ON) SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
OPTION(BUILD_SHARED_LIBS "Build all libraries as shared" OFF) 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(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) 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_LIBS ${UMSKT_LINK_LIBS})
SET(UMSKT_LINK_DIRS ${UMSKT_LINK_DIRS}) SET(UMSKT_LINK_DIRS ${UMSKT_LINK_DIRS})
# macOS does not support static build IF (NOT MSVC)
IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") SET(CMAKE_CXX_FLAGS "-Os -fdata-sections -ffunction-sections -flto -Wl,--gc-sections")
SET(UMSKT_USE_SHARED_OPENSSL ON) SET(CMAKE_CXX_FLAGS_DEBUG "-g")
ENDIF () SET(CMAKE_CXX_FLAGS_DEBUG_INIT "-Wall -Wextra")
SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -Wl,--gc-sections")
# neither does dos idk i'm trying random stuff SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -Wl,--gc-sections")
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")
ENDIF () ENDIF ()
IF (DJGPP_WATT32) IF (DJGPP_WATT32)
@ -72,9 +59,11 @@ ENDIF ()
# if we're compiling with MSVC, respect the DEBUG compile option # if we're compiling with MSVC, respect the DEBUG compile option
IF (MSVC) IF (MSVC)
SET(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") SET(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
SET(CMAKE_CXX_FLAGS "/O1 /GL /LTCG /Gy /OPT:REF /OPT:ICF /EHsc")
SET(CMAKE_CXX_FLAGS_RELEASE "/MT") SET(CMAKE_CXX_FLAGS_RELEASE "/MT")
SET(CMAKE_CXX_FLAGS_DEBUG "/MTd") SET(CMAKE_CXX_FLAGS_DEBUG "/MTd /Z7")
SET(CMAKE_EXE_LINKER_FLAGS "/INCREMENTAL:NO /NODEFAULTLIB:MSVCRT") SET(CMAKE_EXE_LINKER_FLAGS "/INCREMENTAL:NO /NODEFAULTLIB:MSVCRT /LTCG")
SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG")
SET(CMAKE_ENABLE_EXPORTS ON) SET(CMAKE_ENABLE_EXPORTS ON)
SET(UMSKT_EXE_WINDOWS_EXTRA src/windows/umskt.rc) SET(UMSKT_EXE_WINDOWS_EXTRA src/windows/umskt.rc)
SET(UMSKT_EXE_WINDOWS_DLL src/windows/dllmain.cpp) SET(UMSKT_EXE_WINDOWS_DLL src/windows/dllmain.cpp)
@ -83,53 +72,11 @@ ENDIF ()
IF (MUSL_STATIC) IF (MUSL_STATIC)
MESSAGE(STATUS "[UMSKT] Performing a fully static build using muslc") MESSAGE(STATUS "[UMSKT] Performing a fully static build using muslc")
SET(BUILD_SHARED_LIBS OFF) 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_FIND_LIBRARY_SUFFIXES ".a")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc -static-libstdc++") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc -static-libstdc++")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
ENDIF () SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++")
# 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 ()
ENDIF () ENDIF ()
# initialize cpm.CMake # initialize cpm.CMake
@ -166,13 +113,13 @@ CPMAddPackage(
) )
# Include Crypto++ development library # Include Crypto++ development library
#CPMAddPackage( CPMAddPackage(
# NAME cryptopp-cmake NAME cryptopp-cmake
# GITHUB_REPOSITORY abdes/cryptopp-cmake GITHUB_REPOSITORY abdes/cryptopp-cmake
# GIT_TAG CRYPTOPP_8_8_0 GIT_TAG CRYPTOPP_8_9_0
# VERSION 8.8.0 VERSION 8.9.0
# OPTIONS "CRYPTOPP_BUILD_TESTING OFF" OPTIONS "CRYPTOPP_BUILD_TESTING OFF"
#) )
#include googletest unit testing library #include googletest unit testing library
#CPMAddPackage( #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_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(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_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) IF (NOT MSVC)
SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} umskt::rc) SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} umskt::rc)
@ -202,7 +149,8 @@ ENDIF()
#### Separate Build Path for emscripten #### Separate Build Path for emscripten
IF (EMSCRIPTEN) IF (EMSCRIPTEN)
ADD_EXECUTABLE(umskt ${UMSKT_CLI_SRC} ${LIBUMSKT_SRC}) 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}) TARGET_LINK_LIBRARIES(umskt PUBLIC ${UMSKT_LINK_LIBS})
SET(CMAKE_EXECUTABLE_SUFFIX ".html") 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") SET_TARGET_PROPERTIES(umskt PROPERTIES LINK_FLAGS "-Os -sWASM=1 -sEXPORT_ALL=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap --no-entry")
ELSE () ELSE ()
## umskt.so/.dll creation ## umskt.so/.dll creation
ADD_LIBRARY(_umskt SHARED ${LIBUMSKT_SRC} ${UMSKT_EXE_WINDOWS_EXTRA} ${UMSKT_EXE_WINDOWS_DLL}) ADD_LIBRARY(libumskt SHARED ${LIBUMSKT_SRC} ${UMSKT_EXE_WINDOWS_EXTRA} ${UMSKT_EXE_WINDOWS_DLL})
TARGET_INCLUDE_DIRECTORIES(_umskt PUBLIC ${OPENSSL_INCLUDE_DIR} ${CMAKE_BINARY_DIR}) TARGET_INCLUDE_DIRECTORIES(libumskt PUBLIC ${CMAKE_BINARY_DIR})
TARGET_LINK_DIRECTORIES(_umskt PUBLIC ${UMSKT_LINK_DIRS}) TARGET_LINK_DIRECTORIES(libumskt PUBLIC ${UMSKT_LINK_DIRS})
TARGET_LINK_LIBRARIES(_umskt PUBLIC ${UMSKT_LINK_LIBS}) TARGET_LINK_LIBRARIES(libumskt PUBLIC ${UMSKT_LINK_LIBS})
IF(MSVC) IF (MSVC)
SET_TARGET_PROPERTIES(_umskt PROPERTIES OUTPUT_NAME libumskt) SET_TARGET_PROPERTIES(libumskt PROPERTIES OUTPUT_NAME libumskt)
ELSE() ELSE ()
SET_TARGET_PROPERTIES(_umskt PROPERTIES OUTPUT_NAME umskt) SET_TARGET_PROPERTIES(libumskt PROPERTIES OUTPUT_NAME umskt)
ENDIF() ENDIF ()
## umskt_static.a/.lib creation ## umskt_static.a/.lib creation
ADD_LIBRARY(umskt_static ${LIBUMSKT_SRC} ${UMSKT_EXE_WINDOWS_EXTRA} ${UMSKT_EXE_WINDOWS_DLL}) ADD_LIBRARY(libumskt_static ${LIBUMSKT_SRC} ${UMSKT_EXE_WINDOWS_EXTRA} ${UMSKT_EXE_WINDOWS_DLL})
TARGET_INCLUDE_DIRECTORIES(umskt_static PUBLIC ${OPENSSL_INCLUDE_DIR} ${CMAKE_BINARY_DIR}) TARGET_INCLUDE_DIRECTORIES(libumskt_static PUBLIC ${CMAKE_BINARY_DIR})
TARGET_LINK_DIRECTORIES(umskt_static PUBLIC ${UMSKT_LINK_DIRS}) TARGET_LINK_DIRECTORIES(libumskt_static PUBLIC ${UMSKT_LINK_DIRS})
TARGET_LINK_LIBRARIES(umskt_static PUBLIC ${UMSKT_LINK_LIBS}) TARGET_LINK_LIBRARIES(libumskt_static PUBLIC ${UMSKT_LINK_LIBS})
IF(MSVC) IF (MSVC)
SET_TARGET_PROPERTIES(umskt_static PROPERTIES OUTPUT_NAME libumskt_static) SET_TARGET_PROPERTIES(libumskt_static PROPERTIES OUTPUT_NAME libumskt_static)
ELSE() ELSE ()
SET_TARGET_PROPERTIES(umskt_static PROPERTIES OUTPUT_NAME umskt_static) SET_TARGET_PROPERTIES(libumskt_static PROPERTIES OUTPUT_NAME umskt_static)
ENDIF() ENDIF ()
### UMSKT executable compilation ### UMSKT executable compilation
IF (NOT BUILD_SHARED_LIBS)
## Link against the static lib
ADD_EXECUTABLE(umskt ${UMSKT_CLI_SRC} ${UMSKT_EXE_WINDOWS_EXTRA}) 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 libumskt_static ${UMSKT_LINK_LIBS} nlohmann_json::nlohmann_json)
TARGET_LINK_LIBRARIES(umskt PUBLIC umskt_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}) TARGET_LINK_DIRECTORIES(umskt PUBLIC ${UMSKT_LINK_DIRS})
IF (MSVC) IF (MSVC)
SET_PROPERTY(TARGET umskt APPEND PROPERTY COMPILE_FLAGS /DUMSKT_CLI_WINRC_EMBED_JSON) SET_PROPERTY(TARGET umskt APPEND PROPERTY COMPILE_FLAGS /DUMSKT_CLI_WINRC_EMBED_JSON)
@ -246,10 +201,4 @@ ELSE ()
IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux") IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
INSTALL(TARGETS umskt DESTINATION bin) INSTALL(TARGETS umskt DESTINATION bin)
ENDIF () 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 ()

View File

@ -40,14 +40,15 @@ COPY . /src
# Build UMSKT from the local directory # Build UMSKT from the local directory
RUN mkdir /src/build \ RUN mkdir /src/build \
&& cd /src/build \ && cmake -B /src/build -DMUSL_STATIC=ON \
&& cmake -DMUSL_STATIC=ON .. \ && cmake --build /src/build -j 10
&& make
# Stage 3: Output # Stage 3: Output
FROM scratch as output FROM scratch as output
COPY --from=builder /src/build/umskt /umskt 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 # invoke via
# docker build -o type=tar,dest=umskt.tar . # docker build -o type=tar,dest=umskt.tar .

View File

@ -84,21 +84,8 @@ RUN git clone https://github.com/gvanem/Watt-32.git watt32 \
&& make -f djgpp.mak \ && make -f djgpp.mak \
&& ln -s /djgpp/watt32/lib/libwatt.a /djgpp/lib && 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 # Stage 5: compile UMSKT
FROM openssl as build FROM watt32 as build
WORKDIR /src WORKDIR /src
COPY . /src COPY . /src

View File

View File

@ -463,17 +463,56 @@
"BINK": [ "BINK": [
"2C", "2C",
"2D" "2D"
] ],
"DPC": {
"2C": [
{
"min": 5,
"max": 85,
"isEvaluation": false
}, },
"PROK": { {
"name": "Professional K", "min": 337,
"BINK": [ "max": 359,
"30", "isEvaluation": false
"31"
]
}, },
"PROVLK": { {
"name": "Professional VLK", "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
}
]
}
},
"VLK": {
"name": "Home/Professional VLK",
"BINK": [ "BINK": [
"2E", "2E",
"2F" "2F"
@ -484,16 +523,6 @@
"min": 640, "min": 640,
"max": 699, "max": 699,
"isEvaluation": false "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"
]
} }
} }
}, },

View File

@ -129,13 +129,13 @@ BOOL CLI::loadJSON(const fs::path &filename)
* *
* @param pid * @param pid
*/ */
void CLI::printID(DWORD *pid) void CLI::printID(DWORD32 *pid)
{ {
char raw[12], b[6], c[8]; char raw[12], b[6], c[8];
char i, digit = 0; char i, digit = 0;
// Convert PID to ascii-number (=raw) // Convert PID to ascii-number (=raw)
snprintf(raw, sizeof(raw), "%09lu", pid[0]); snprintf(raw, sizeof(raw), "%09u", pid[0]);
// Make b-part {640-....} // Make b-part {640-....}
_strncpy(b, 6, &raw[0], 3); _strncpy(b, 6, &raw[0], 3);
@ -160,8 +160,8 @@ void CLI::printID(DWORD *pid)
c[6] = digit + '0'; c[6] = digit + '0';
c[7] = 0; c[7] = 0;
DWORD binkid; DWORD32 binkid;
_sscanf(options.binkID.c_str(), "%lx", &binkid); _sscanf(&options.binkID[0], "%x", &binkid);
binkid /= 2; binkid /= 2;
fmt::print("> Product ID: PPPPP-{}-{}-{}xxx\n", b, c, binkid); fmt::print("> Product ID: PPPPP-{}-{}-{}xxx\n", b, c, binkid);
@ -172,7 +172,7 @@ void CLI::printID(DWORD *pid)
* @param pidgen3 * @param pidgen3
* @return success * @return success
*/ */
BOOL CLI::InitPIDGEN3(PIDGEN3 &pidgen3) BOOL CLI::InitPIDGEN3(PIDGEN3 *p3)
{ {
const char *BINKID = &options.binkID[0]; const char *BINKID = &options.binkID[0];
auto bink = keys["BINK"][BINKID]; auto bink = keys["BINK"][BINKID];
@ -192,7 +192,7 @@ BOOL CLI::InitPIDGEN3(PIDGEN3 &pidgen3)
fmt::print("\n"); fmt::print("\n");
} }
pidgen3.LoadEllipticCurve(bink["p"], bink["a"], bink["b"], bink["g"]["x"], bink["g"]["y"], bink["pub"]["x"], p3->LoadEllipticCurve(bink["p"], bink["a"], bink["b"], bink["g"]["x"], bink["g"]["y"], bink["pub"]["x"],
bink["pub"]["y"], bink["n"], bink["priv"]); bink["pub"]["y"], bink["n"], bink["priv"]);
if (options.state != STATE_PIDGEN_GENERATE) if (options.state != STATE_PIDGEN_GENERATE)
@ -200,18 +200,18 @@ BOOL CLI::InitPIDGEN3(PIDGEN3 &pidgen3)
return true; return true;
} }
pidgen3.info.setChannelID(options.channelID); p3->info.setChannelID(options.channelID);
if (options.verbose) if (options.verbose)
{ {
fmt::print("> Channel ID: {:03d}\n", options.channelID); fmt::print("> Channel ID: {:#03d}\n", options.channelID);
} }
if (options.serialSet) if (options.serialSet)
{ {
pidgen3.info.setSerial(options.serial); p3->info.setSerial(options.serial);
if (options.verbose) 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) 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") || if (!keys["products"][options.productCode].contains("meta") ||
!keys["products"][options.productCode]["meta"].contains("activation")) !keys["products"][options.productCode]["meta"].contains("activation"))
{ {
@ -264,17 +259,10 @@ BOOL CLI::InitConfirmationID(ConfirmationID &confid)
fmt::print("\n"); fmt::print("\n");
} }
for (BYTE i = 0; i < 6; i++) confid.LoadHyperellipticCurve(flavour["x"]["0"], flavour["x"]["1"], flavour["x"]["2"], flavour["x"]["3"],
{ flavour["x"]["4"], flavour["x"]["5"], flavour["priv"], flavour["quotient"],
fvals[i] = BN_CTX_get(ctx); flavour["non_residue"], flavour["iid_key"], meta["tags"].contains("xpbrand"),
auto xval = flavour["x"][fmt::format("{}", i)].get<std::string>(); meta["tags"].contains("office"), meta["activation"]["version"]);
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);
return false; return false;
} }
@ -282,7 +270,7 @@ BOOL CLI::InitConfirmationID(ConfirmationID &confid)
* *
* @return success * @return success
*/ */
BOOL CLI::PIDGENGenerate() BOOL CLI::PIDGenerate()
{ {
// TODO: // TODO:
// if options.pidgen2generate // if options.pidgen2generate
@ -295,34 +283,20 @@ BOOL CLI::PIDGENGenerate()
std::string key; std::string key;
bink["p"].get_to(key); bink["p"].get_to(key);
if (PIDGEN3::checkFieldStrIsBink1998(key)) auto p3 = PIDGEN3::Factory(key);
{ InitPIDGEN3(p3);
if (options.verbose)
{
fmt::print("Detected a BINK1998 key\n");
}
auto bink1998 = BINK1998(); auto retval = PIDGEN3Generate(p3);
InitPIDGEN3(bink1998);
return BINK1998Generate(bink1998); delete p3;
} return retval;
else
{
if (options.verbose)
{
fmt::print("Detected a BINK2002 key\n");
}
auto bink2002 = BINK2002();
InitPIDGEN3(bink2002);
return BINK2002Generate(bink2002);
}
} }
/** /**
* *
* @return isValid * @return isValid
*/ */
BOOL CLI::PIDGENValidate() BOOL CLI::PIDValidate()
{ {
// TODO: // TODO:
// if options.pidgen2validate // if options.pidgen2validate
@ -335,26 +309,12 @@ BOOL CLI::PIDGENValidate()
std::string key; std::string key;
bink["p"].get_to(key); bink["p"].get_to(key);
if (PIDGEN3::checkFieldStrIsBink1998(key)) auto p3 = PIDGEN3::Factory(key);
{ InitPIDGEN3(p3);
if (options.verbose) auto retval = PIDGEN3Validate(p3);
{
fmt::print("Detected a BINK1998 key\n"); delete p3;
} return retval;
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);
}
} }
/** /**
@ -371,10 +331,10 @@ int CLI::Run()
switch (options.state) switch (options.state)
{ {
case STATE_PIDGEN_GENERATE: case STATE_PIDGEN_GENERATE:
return PIDGENGenerate(); return PIDGenerate();
case STATE_PIDGEN_VALIDATE: case STATE_PIDGEN_VALIDATE:
return PIDGENValidate(); return PIDValidate();
case STATE_CONFIRMATION_ID: case STATE_CONFIRMATION_ID:
return ConfirmationIDGenerate(); return ConfirmationIDGenerate();

View File

@ -23,6 +23,7 @@
#ifndef UMSKT_CLI_H #ifndef UMSKT_CLI_H
#define UMSKT_CLI_H #define UMSKT_CLI_H
#include "libumskt/libumskt.h"
#include "typedefs.h" #include "typedefs.h"
#include <filesystem> #include <filesystem>
@ -96,9 +97,9 @@ struct Options
std::string productCode; std::string productCode;
std::string productFlavour; std::string productFlavour;
DWORD channelID; DWORD32 channelID;
DWORD serial; DWORD32 serial;
DWORD numKeys; DWORD32 numKeys;
BOOL oem; BOOL oem;
BOOL upgrade; BOOL upgrade;
@ -128,7 +129,7 @@ struct Options
class CLI class CLI
{ {
std::string pKey; std::string pKey;
DWORD count, total, iBinkID; DWORD32 count, total, iBinkID;
static Options options; static Options options;
@ -168,23 +169,21 @@ class CLI
static BOOL parseCommandLine(); static BOOL parseCommandLine();
static BOOL processOptions(); static BOOL processOptions();
static void printID(DWORD *pid); static void printID(DWORD32 *pid);
static void printKey(std::string &pk); static void printKey(std::string &pk);
static BOOL stripKey(const std::string &in_key, std::string &out_key); static BOOL stripKey(const std::string &in_key, std::string &out_key);
static std::string validateInputKeyCharset(std::string &accumulator, char currentChar); static std::string validateInputKeyCharset(std::string &accumulator, char currentChar);
BOOL InitPIDGEN3(PIDGEN3 &pidgen3); BOOL InitPIDGEN3(PIDGEN3 *p3);
BOOL InitConfirmationID(ConfirmationID &confid); BOOL InitConfirmationID(ConfirmationID &confid);
BOOL PIDGENGenerate(); BOOL PIDGenerate();
BOOL PIDGENValidate(); BOOL PIDValidate();
BOOL PIDGEN2Generate(PIDGEN2 &pidgen2); BOOL PIDGEN2Generate(PIDGEN2 &p2);
BOOL PIDGEN2Validate(PIDGEN2 &pidgen2); BOOL PIDGEN2Validate(PIDGEN2 &p2);
BOOL BINK1998Generate(PIDGEN3 &pidgen3); BOOL PIDGEN3Generate(PIDGEN3 *p3);
BOOL BINK1998Validate(PIDGEN3 &pidgen3); BOOL PIDGEN3Validate(PIDGEN3 *p3);
BOOL BINK2002Generate(PIDGEN3 &pidgen3);
BOOL BINK2002Validate(PIDGEN3 &pidgen3);
BOOL ConfirmationIDGenerate(); BOOL ConfirmationIDGenerate();
INLINE static std::string strtolower(std::string &in) INLINE static std::string strtolower(std::string &in)

View File

@ -46,12 +46,14 @@ BOOL CLI::PIDGEN2Validate(PIDGEN2 &pidgen2)
* *
* @return success * @return success
*/ */
BOOL CLI::BINK1998Generate(PIDGEN3 &pidgen3) BOOL CLI::PIDGEN3Generate(PIDGEN3 *p3)
{ {
// raw PID/serial value // raw PID/serial value
DWORD nRaw = options.channelID * 1'000'000; DWORD32 nRaw = options.channelID * 1'000'000;
DWORD serialRnd; DWORD32 serialRnd;
if (p3->checkFieldIsBink1998())
{
if (options.serialSet) if (options.serialSet)
{ {
// using user-provided serial // using user-provided serial
@ -60,7 +62,7 @@ BOOL CLI::BINK1998Generate(PIDGEN3 &pidgen3)
else else
{ {
// generate a random number to use as a serial // generate a random number to use as a serial
serialRnd = UMSKT::getRandom<DWORD>(); serialRnd = UMSKT::getRandom<DWORD32>();
} }
// make sure it's less than 999999 // make sure it's less than 999999
@ -72,13 +74,28 @@ BOOL CLI::BINK1998Generate(PIDGEN3 &pidgen3)
// PID value is printed in BINK1998::Generate // PID value is printed in BINK1998::Generate
printID(&nRaw); printID(&nRaw);
} }
}
for (int i = 0; i < total; i++) for (DWORD32 i = 0; i < total; i++)
{ {
pidgen3.info.setSerial(nRaw); if (!p3->checkFieldIsBink1998())
pidgen3.Generate(pKey); {
auto authvalue = UMSKT::getRandom<DWORD32>() & BITMASK(10);
p3->info.AuthInfo.Decode((BYTE *)&authvalue, sizeof(DWORD32));
bool isValid = pidgen3.Validate(pKey); if (options.verbose)
{
fmt::print("> AuthInfo: {:#08x}\n", p3->info.AuthInfo);
}
}
else
{
p3->info.setSerial(nRaw);
}
p3->Generate(pKey);
bool isValid = p3->Validate(pKey);
if (isValid) if (isValid)
{ {
printKey(pKey); printKey(pKey);
@ -115,7 +132,7 @@ BOOL CLI::BINK1998Generate(PIDGEN3 &pidgen3)
* *
* @return success * @return success
*/ */
BOOL CLI::BINK1998Validate(PIDGEN3 &bink1998) BOOL CLI::PIDGEN3Validate(PIDGEN3 *p3)
{ {
std::string product_key; std::string product_key;
@ -127,84 +144,7 @@ BOOL CLI::BINK1998Validate(PIDGEN3 &bink1998)
CLI::printKey(product_key); CLI::printKey(product_key);
fmt::print("\n"); fmt::print("\n");
if (!bink1998.Validate(product_key)) if (!p3->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<DWORD>() & 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))
{ {
fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n"); fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n");
return false; return false;
@ -228,7 +168,7 @@ BOOL CLI::ConfirmationIDGenerate()
return false; 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) if (err == SUCCESS)
{ {

View File

@ -89,7 +89,7 @@ void CLI::SetHelpText()
*/ */
BOOL CLI::parseCommandLine() 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]; std::string arg = options.argv[i];
@ -436,7 +436,7 @@ BOOL CLI::SetOEMOption(int, char *)
{ {
if (options.verbose) if (options.verbose)
{ {
fmt::print("Setting oem option\n"); fmt::print("Setting OEM option\n");
} }
options.oem = true; options.oem = true;
return true; return true;
@ -523,12 +523,13 @@ BOOL CLI::SetBINKOption(int count, char *bink)
BOOL CLI::SetFlavourOption(int count, char *flavour) BOOL CLI::SetFlavourOption(int count, char *flavour)
{ {
auto strflavour = std::string(flavour);
options.productFlavour = strtoupper(strflavour);
if (options.verbose) if (options.verbose)
{ {
fmt::print("Setting flavour option to {}\n", flavour); fmt::print("Setting flavour option to {}\n", strflavour);
} }
options.productFlavour = flavour;
return true; return true;
} }
@ -584,12 +585,12 @@ BOOL CLI::SetValidateOption(int count, char *productID)
BOOL CLI::SetProductCodeOption(int, char *product) BOOL CLI::SetProductCodeOption(int, char *product)
{ {
if (options.verbose)
{
fmt::print("Setting product code to {}\n", product);
}
auto strProduct = std::string(product); auto strProduct = std::string(product);
options.productCode = strtoupper(strProduct); options.productCode = strtoupper(strProduct);
if (options.verbose)
{
fmt::print("Setting product code to {}\n", strProduct);
}
return true; return true;
} }

View File

@ -38,7 +38,7 @@
* @param x4 * @param x4
* @param x5 * @param x5
* @param priv * @param priv
* @param modulous * @param modulus
* @param nonresidue * @param nonresidue
* @param isOffice * @param isOffice
* @param isXPBrand * @param isXPBrand
@ -46,58 +46,74 @@
* @return * @return
*/ */
BOOL ConfirmationID::LoadHyperellipticCurve(QWORD x0, QWORD x1, QWORD x2, QWORD x3, QWORD x4, QWORD x5, Q_OWORD priv, 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, QWORD modulus, QWORD nonresidue, DWORD32 iidkey, BOOL isOffice,
BYTE flagVersion) BOOL isXPBrand, BYTE flagVersion)
{ {
curve[0] = x0; QWORD fvals[6] = {x0, x1, x2, x3, x4, x5};
curve[1] = x1;
curve[2] = x2;
curve[3] = x3;
curve[4] = x4;
curve[5] = x5;
memcpy(&privateKey, &priv, sizeof(Q_OWORD)); return LoadHyperellipticCurve(fvals, priv, modulus, nonresidue, iidkey, isOffice, isXPBrand, flagVersion);
MOD = modulous;
NON_RESIDUE = nonresidue;
this->isOffice = isOffice;
this->isXPBrand = isXPBrand;
this->flagVersion = flagVersion;
return true;
} }
/** /**
* *
* @param f * @param f
* @param priv * @param priv
* @param modulous * @param modulus
* @param nonresidue * @param nonresidue
* @param isOffice * @param isOffice
* @param isXPBrand * @param isXPBrand
* @param flagVersion * @param flagVersion
* @return * @return
*/ */
BOOL ConfirmationID::LoadHyperellipticCurve(QWORD *f, Q_OWORD priv, QWORD modulous, QWORD nonresidue, BOOL isOffice, BOOL ConfirmationID::LoadHyperellipticCurve(QWORD *f, Q_OWORD priv, QWORD modulus, QWORD nonresidue, DWORD32 iidkey,
BOOL isXPBrand, BYTE flagVersion) BOOL isOffice, BOOL isXPBrand, BYTE flagVersion)
{ {
memcpy(&curve, f, sizeof(curve)); memcpy(&curve, f, sizeof(curve));
memcpy(&privateKey, &priv, sizeof(Q_OWORD)); memcpy(&privateKey, &priv, sizeof(Q_OWORD));
MOD = modulous; MOD = modulus;
NON_RESIDUE = nonresidue; NON_RESIDUE = nonresidue;
this->isOffice = isOffice; this->isOffice = isOffice;
this->isXPBrand = isXPBrand; this->isXPBrand = isXPBrand;
this->flagVersion = flagVersion; this->flagVersion = flagVersion;
return true; return true;
} }
BOOL LoadHyperellipticCurve(const std::string &x0, const std::string &x1, const std::string &x2, const std::string &x3, BOOL ConfirmationID::LoadHyperellipticCurve(const std::string &x0, const std::string &x1, const std::string &x2,
const std::string &x4, const std::string &x5, const std::string &priv, const std::string &x3, const std::string &x4, const std::string &x5,
const std::string &modulous, const std::string &nonresidue, BOOL isOffice, BOOL isXPBrand, const std::string &priv, const std::string &modulus,
BYTE flagVersion) 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; return true;
} }
@ -107,9 +123,9 @@ BOOL LoadHyperellipticCurve(const std::string &x0, const std::string &x1, const
* @param pid * @param pid
* @return * @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) for (j = pid; j; i += k)
{ {
k = j % 10; k = j % 10;
@ -125,7 +141,7 @@ DWORD ConfirmationID::calculateCheckDigit(DWORD pid)
* @param hwid * @param hwid
* @param version * @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]; QWORD buffer[5];
for (BYTE i = 0; i < 5; i++) 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); memcpy(&buffer[i], (iid + (4 * i)), 4);
} }
DWORD v1 = (buffer[3] & 0xFFFFFFF8) | 2; DWORD32 v1 = (buffer[3] & 0xFFFFFFF8) | 2;
DWORD v2 = ((buffer[3] & 7) << 29) | (buffer[2] >> 3); DWORD32 v2 = ((buffer[3] & 7) << 29) | (buffer[2] >> 3);
QWORD hardwareIDVal = ((QWORD)v1 << 32) | v2; QWORD hardwareIDVal = ((QWORD)v1 << 32) | v2;
for (BYTE i = 0; i < 8; ++i) 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) 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; BYTE half = bufSize / 2;
auto digest = SHA();
// assert(half <= sizeof(sha1_result) && half + keySize <= sizeof(sha1_input) - 9); // assert(half <= sizeof(sha1_result) && half + keySize <= sizeof(sha1_input) - 9);
for (BYTE external_counter = 0; external_counter < 4; external_counter++) 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_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++) 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) 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; BYTE half = bufSize / 2;
auto digest = SHA();
// assert(half <= sizeof(sha1_result) && half + keySize <= sizeof(sha1_input) - 9); // assert(half <= sizeof(sha1_result) && half + keySize <= sizeof(sha1_input) - 9);
for (BYTE external_counter = 0; external_counter < 4; external_counter++) 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_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++) 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, CONFIRMATION_ID_STATUS ConfirmationID::Generate(const std::string &installationIDIn, std::string &confirmationIDOut,
std::string &productIDIn) std::string &productIDIn)
{ {
DWORD version; DWORD32 version;
BYTE hardwareID[8]; BYTE hardwareID[8];
BYTE installation_id[19]; // 10**45 < 256**19 BYTE installation_id[19]; // 10**45 < 256**19
BYTE productID[4]; BYTE productID[4];
BYTE installation_id_len = 0; BYTE installation_id_len = 0;
auto pid = installationIDIn.c_str(); auto pid = &installationIDIn[0];
BYTE count = 0, totalCount = 0; BYTE count = 0, totalCount = 0;
unsigned check = 0; unsigned check = 0;
@ -441,8 +461,8 @@ CONFIRMATION_ID_STATUS ConfirmationID::Generate(const std::string &installationI
QWORD x1 = ulowhi.qword[0] - x2 * MOD; QWORD x1 = ulowhi.qword[0] - x2 * MOD;
x2++; x2++;
d.u[0] = residue->sub(residue->mul(x1, x1), residue->mul(NON_RESIDUE, residue->mul(x2, x2))); d.u.qword[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[1] = residue->add(x1, x1);
if (divisor->find_divisor_v(&d)) if (divisor->find_divisor_v(&d))
{ {
break; break;
@ -462,23 +482,23 @@ CONFIRMATION_ID_STATUS ConfirmationID::Generate(const std::string &installationI
Q_OWORD e; Q_OWORD e;
memset(&e, 0, sizeof(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... // we can not get the zero divisor, actually...
e.qword[0] = residue->__umul128(MOD + 2, MOD, &e.qword[1]); 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 // O(1/MOD) chance
// encoded = (unsigned __int128)(MOD + 1) * d.u[0] + MOD; // * MOD + d.u[0] is fine too // 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[0] += MOD;
e.qword[1] += (e.qword[0] < MOD); e.qword[1] += (e.qword[0] < MOD);
} }
else else
{ {
QWORD x1 = (d.u[1] % 2 ? d.u[1] + MOD : d.u[1]) / 2; 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[0]); QWORD x2sqr = residue->sub(residue->mul(x1, x1), d.u.qword[0]);
QWORD x2 = residue->sqrt(x2sqr); QWORD x2 = residue->sqrt(x2sqr);
if (x2 == BAD) 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)) // points (-x1+x2, v(-x1+x2)) and (-x1-x2, v(-x1-x2))
QWORD x1a = residue->sub(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 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) if (x1a > x2a)
{ {
QWORD tmp = x1a; QWORD tmp = x1a;

View File

@ -41,8 +41,7 @@ enum CONFIRMATION_ID_STATUS
typedef struct typedef struct
{ {
QWORD u[2]; Q_OWORD u, v;
QWORD v[2];
} TDivisor; } TDivisor;
class EXPORT ConfirmationID class EXPORT ConfirmationID
@ -55,8 +54,8 @@ class EXPORT ConfirmationID
BOOL isOffice = false, isXPBrand = false; BOOL isOffice = false, isXPBrand = false;
unsigned flagVersion = 0; unsigned flagVersion = 0;
DWORD calculateCheckDigit(DWORD pid); DWORD32 calculateCheckDigit(DWORD32 pid);
void decode_iid_new_version(BYTE *iid, BYTE *hwid, DWORD *version); void decode_iid_new_version(BYTE *iid, BYTE *hwid, DWORD32 *version);
void Mix(BYTE *buffer, BYTE bufSize, const BYTE *key, BYTE keySize); void Mix(BYTE *buffer, BYTE bufSize, const BYTE *key, BYTE keySize);
void Unmix(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); residue = new Residue(this);
polynomial = new Polynomial(this); polynomial = new Polynomial(this);
divisor = new Divisor(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, 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 &x3, const std::string &x4, const std::string &x5,
const std::string &priv, const std::string &modulous, const std::string &nonresidue, const std::string &priv, const std::string &modulus, const std::string &nonresidue,
BOOL isOffice, BOOL isXPBrand, BYTE flagVersion); 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, BOOL LoadHyperellipticCurve(QWORD x0, QWORD x1, QWORD x2, QWORD x3, QWORD x4, QWORD x5, Q_OWORD priv, QWORD modulus,
QWORD modulous, QWORD nonresidue, BOOL isOffice, BOOL isXPBrand, BYTE flagVersion); 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, BOOL LoadHyperellipticCurve(QWORD *f, Q_OWORD priv, QWORD modulus, QWORD nonresidue, DWORD32 iidkey, BOOL isOffice,
BYTE flagVersion); BOOL isXPBrand, BYTE flagVersion);
CONFIRMATION_ID_STATUS Generate(const std::string &installation_id_str, std::string &confirmation_id, CONFIRMATION_ID_STATUS Generate(const std::string &installation_id_str, std::string &confirmation_id,
std::string &productid); std::string &productid);
~ConfirmationID() ~ConfirmationID()
{ {
delete residue, polynomial, divisor; delete residue;
delete polynomial;
delete divisor;
} }
}; };

View File

@ -39,7 +39,7 @@ int ConfirmationID::ConfirmationID::Divisor::find_divisor_v(TDivisor *d)
f2[i] = parent->curve[i]; 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--;) for (BYTE j = 4; j--;)
{ {
f2[j] = parent->residue->sub(f2[j], parent->residue->mul(u0, f2[j + 2])); 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))), 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))); parent->residue->inv(parent->residue->add(v1, v1)));
d->v[0] = v0; d->v.qword[0] = v0;
d->v[1] = v1; d->v.qword[1] = v1;
return 1; 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]) 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[0] = src->u.qword[0];
polyu[1] = src->u[1]; polyu[1] = src->u.qword[1];
polyu[2] = 1; polyu[2] = 1;
polyv[0] = src->v[0]; polyv[0] = src->v.qword[0];
polyv[1] = src->v[1]; polyv[1] = src->v.qword[1];
return 2; 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; polyu[1] = 1;
polyv[0] = src->v[0]; polyv[0] = src->v.qword[0];
polyv[1] = 0; polyv[1] = 0;
return 1; 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) 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]); 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) if (udeg == 2)
{ {
dst->u[0] = u[0]; dst->u.qword[0] = u[0];
dst->u[1] = u[1]; dst->u.qword[1] = u[1];
dst->v[0] = (vdeg >= 0 ? v[0] : 0); dst->v.qword[0] = (vdeg >= 0 ? v[0] : 0);
dst->v[1] = (vdeg >= 1 ? v[1] : 0); dst->v.qword[1] = (vdeg >= 1 ? v[1] : 0);
} }
else if (udeg == 1) else if (udeg == 1)
{ {
dst->u[0] = u[0]; dst->u.qword[0] = u[0];
dst->u[1] = BAD; dst->u.qword[1] = BAD;
dst->v[0] = (vdeg >= 0 ? v[0] : 0); dst->v.qword[0] = (vdeg >= 0 ? v[0] : 0);
dst->v[1] = BAD; dst->v.qword[1] = BAD;
} }
else else
{ {
assert(udeg == 0); assert(udeg == 0);
dst->u[0] = BAD; dst->u.qword[0] = BAD;
dst->u[1] = BAD; dst->u.qword[1] = BAD;
dst->v[0] = BAD; dst->v.qword[0] = BAD;
dst->v[1] = BAD; dst->v.qword[1] = BAD;
} }
} }
@ -318,10 +318,10 @@ void ConfirmationID::Divisor::mul(const TDivisor *src, QWORD mult, TDivisor *dst
{ {
if (mult == 0) if (mult == 0)
{ {
dst->u[0] = BAD; dst->u.qword[0] = BAD;
dst->u[1] = BAD; dst->u.qword[1] = BAD;
dst->v[0] = BAD; dst->v.qword[0] = BAD;
dst->v[1] = BAD; dst->v.qword[1] = BAD;
return; return;
} }
@ -354,10 +354,10 @@ void ConfirmationID::Divisor::mul128(const TDivisor *src, QWORD mult_lo, QWORD m
{ {
if (mult_lo == 0 && mult_hi == 0) if (mult_lo == 0 && mult_hi == 0)
{ {
dst->u[0] = BAD; dst->u.qword[0] = BAD;
dst->u[1] = BAD; dst->u.qword[1] = BAD;
dst->v[0] = BAD; dst->v.qword[0] = BAD;
dst->v[1] = BAD; dst->v.qword[1] = BAD;
return; return;
} }

View File

@ -22,17 +22,7 @@
#include "libumskt.h" #include "libumskt.h"
#ifdef _WIN32 std::FILE *UMSKT::debug;
// 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 = false; BOOL UMSKT::VERBOSE = false;
BOOL UMSKT::DEBUG = false; BOOL UMSKT::DEBUG = false;

View File

@ -28,10 +28,10 @@
#include "pidgen3/PIDGEN3.h" #include "pidgen3/PIDGEN3.h"
std::map<UMSKT_TAG, UMSKT_Value> UMSKT::tags; std::map<UMSKT_TAG, UMSKT_Value> UMSKT::tags;
CryptoPP::DefaultAutoSeededRNG UMSKT::rng;
extern "C" extern "C"
{ {
/** /**
* Sets debug output to a given C++ File stream * Sets debug output to a given C++ File stream
* if the memory allocated at filestream is "STDOUT" or "STDERR" * if the memory allocated at filestream is "STDOUT" or "STDERR"
@ -195,7 +195,7 @@ extern "C"
std::string str; std::string str;
BOOL retval = p3->Generate(str); BOOL retval = p3->Generate(str);
assert(pKeySizeIn >= str.length() + 1); assert(pKeySizeIn >= str.length() + NULL_TERMINATOR);
memcpy(pKeyOut, &str[0], str.length()); memcpy(pKeyOut, &str[0], str.length());
pKeyOut[str.length()] = 0; pKeyOut[str.length()] = 0;
@ -245,48 +245,3 @@ extern "C"
} }
} // 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;
}

View File

@ -29,34 +29,68 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <openssl/bn.h> #include <cryptopp/cryptlib.h>
#include <openssl/ec.h> #include <cryptopp/ecp.h>
#include <openssl/evp.h> #include <cryptopp/filters.h>
#include <openssl/rand.h> #include <cryptopp/hex.h>
#include <openssl/sha.h> #include <cryptopp/integer.h>
#include <cryptopp/nbtheory.h>
#include <cryptopp/osrng.h>
#include <cryptopp/randpool.h>
#include <cryptopp/rng.h>
#include <cryptopp/sha.h>
using Integer = CryptoPP::Integer;
using ECP = CryptoPP::ECP;
using SHA = CryptoPP::SHA1;
#include <fmt/core.h> #include <fmt/core.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <fmt/ostream.h>
class HexInteger : public Integer
{
};
// fmt <-> CryptoPP linkage
template <> struct fmt::formatter<HexInteger> : fmt::formatter<std::string_view>
{
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<std::string_view>::format(hexString, ctx);
}
};
template <> struct fmt::formatter<Integer> : ostream_formatter
{
auto format(const Integer &i, format_context &ctx) const
{
return basic_ostream_formatter<char>::format(i, ctx);
}
};
// Algorithm macros // Algorithm macros
#define PK_LENGTH 25 #define PK_LENGTH 25
#define NULL_TERMINATOR 1 #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 NEXTSNBITS(field, n, offset) (((QWORD)(field) >> (offset)) & ((1ULL << (n)) - 1))
#define FIRSTNBITS(field, n) NEXTSNBITS((field), (n), 0) #define FIRSTNBITS(field, n) NEXTSNBITS((field), (n), 0)
#define HIBYTES(field, bytes) NEXTSNBITS((QWORD)(field), ((bytes) * 8), ((bytes) * 8)) #define HIBYTES(field, bytes) NEXTSNBITS((QWORD)(field), ((bytes) * 8), ((bytes) * 8))
#define LOBYTES(field, bytes) FIRSTNBITS((QWORD)(field), ((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) #define BITMASK(n) ((1ULL << (n)) - 1)
#ifndef LIBUMSKT_VERSION_STRING #ifndef LIBUMSKT_VERSION_STRING
@ -79,7 +113,7 @@ struct UMSKT_Value
union { union {
BOOL boolean; BOOL boolean;
WORD word; WORD word;
DWORD dword; DWORD32 dword;
QWORD qword; QWORD qword;
OWORD oword; OWORD oword;
char *chars; char *chars;
@ -107,10 +141,7 @@ class EXPORT UMSKT
static BOOL VERBOSE; static BOOL VERBOSE;
static BOOL DEBUG; static BOOL DEBUG;
static std::map<UMSKT_TAG, UMSKT_Value> tags; static std::map<UMSKT_TAG, UMSKT_Value> tags;
static CryptoPP::DefaultAutoSeededRNG rng;
// 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 void DESTRUCT() static void DESTRUCT()
{ {
@ -126,7 +157,7 @@ class EXPORT UMSKT
template <typename T> static T getRandom() template <typename T> static T getRandom()
{ {
T retval; T retval;
RAND_bytes((BYTE *)&retval, sizeof(retval)); rng.GenerateBlock((BYTE *)&retval, sizeof(retval));
return retval; return retval;
} }

View File

@ -199,10 +199,10 @@ int PIDGEN2::GenerateOEM(char *year, char *day, char *oem, char *&keyout)
if (!isValidDay(day)) if (!isValidDay(day))
{ {
auto iday = UMSKT::getRandom<int>(); auto iday = UMSKT::getRandom<int>();
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; return 0;
} }

View File

@ -27,8 +27,8 @@
class EXPORT PIDGEN2 class EXPORT PIDGEN2
{ {
DWORD year; DWORD32 year;
DWORD day; DWORD32 day;
BOOL isOEM; BOOL isOEM;
BOOL isOffice; BOOL isOffice;

View File

@ -34,15 +34,20 @@
* *
* @param pRaw [in] *QWORD[2] raw product key input * @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. // The quantity of information the key provides is 114 bits.
// We're storing it in 2 64-bit quad-words with 14 trailing bits. // We're storing it in 2 64-bit quad-words with 14 trailing bits.
// 64 * 2 = 128 // 64 * 2 = 128
// Signature [114..59] <- Hash [58..31] <- Serial [30..1] <- Upgrade [0] // 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; Integer raw;
pRaw[1] = NEXTSNBITS(info.Signature, 51, 5); 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; return true;
} }
@ -52,22 +57,22 @@ BOOL BINK1998::Pack(QWORD *pRaw)
* *
* @param pRaw [out] *QWORD[2] raw product key output * @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. // We're assuming that the quantity of information within the product key is at most 114 bits.
// log2(24^25) = 114. // log2(24^25) = 114.
// Upgrade = Bit 0 // Upgrade = Bit 0
info.isUpgrade = FIRSTNBITS(pRaw[0], 1); info.isUpgrade = FIRSTNBITS(pRaw->qword[0], 1);
// Serial = Bits [1..30] -> 30 bits // 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 // 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 // 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; return true;
} }
@ -81,51 +86,55 @@ BOOL BINK1998::Unpack(QWORD *pRaw)
*/ */
BOOL BINK1998::Generate(std::string &pKey) 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), Q_OWORD pRaw;
*y = BN_CTX_get(numContext);
QWORD pRaw[2];
// Data segment of the RPK. // 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 // prepare the private key for generation
BN_sub(privateKey, genOrder, privateKey); privateKey -= genOrder;
Integer limit;
limit.SetBit(55);
limit -= 1;
do do
{ {
EC_POINT *r = EC_POINT_new(eCurve); ECP::Point R;
// Generate a random number c consisting of 384 bits without any constraints. // 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. // Pick a random derivative of the base point on the elliptic curve.
// R = cG; // R = cG;
EC_POINT_mul(eCurve, r, nullptr, genPoint, c, numContext); R = eCurve.Multiply(c, genPoint);
// Acquire its coordinates. // Acquire its coordinates.
// x = R.x; y = R.y; // 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 msgDigest[SHA::DIGESTSIZE], msgBuffer[SHAMessageLength], *pMsgBuffer = msgBuffer;
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);
// Assemble the SHA message. // Assemble the SHA message.
memcpy(&msgBuffer[0], &pData, 4); pData.Encode((CryptoPP::byte *)msgBuffer, 4);
memcpy(&msgBuffer[4], xBin, FIELD_BYTES); pMsgBuffer += 4;
memcpy(&msgBuffer[4 + FIELD_BYTES], yBin, FIELD_BYTES);
R.x.Encode(pMsgBuffer, FieldBytes);
pMsgBuffer += FieldBytes;
R.y.Encode(pMsgBuffer, FieldBytes);
pMsgBuffer += FieldBytes;
// pHash = SHA1(pSerial || R.x || R.y) // 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. // Translate the byte digest into a 32-bit integer - this is our computed pHash.
// Truncate the pHash to 28 bits. // Truncate the pHash to 28 bits.
info.Hash.Decode(msgDigest, SHAMessageLength);
info.Hash = BYDWORD(msgDigest) >> 4 & BITMASK(28); info.Hash = BYDWORD(msgDigest) >> 4 & BITMASK(28);
/* /*
@ -148,37 +157,33 @@ BOOL BINK1998::Generate(std::string &pKey)
*/ */
// s = ek; // s = ek;
BN_copy(s, privateKey); s = privateKey * info.Hash;
BN_mul_word(s, info.Hash);
// s += c (mod n) // 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). // 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 product key.
Pack(pRaw); Pack(&pRaw);
auto serial = fmt::format("{:d}", info.Serial); auto serial = fmt::format("{:d}", info.Serial);
fmt::print(UMSKT::debug, "Generation results:\n"); 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", "Channel ID", serial.substr(0, 3));
fmt::print(UMSKT::debug, "{:>10}: {}\n", "Sequence", serial.substr(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}: {}\n", "Hash", info.Hash);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Signature", info.Signature); fmt::print(UMSKT::debug, "{:>10}: {}\n", "Signature", info.Signature);
fmt::print(UMSKT::debug, "\n"); fmt::print(UMSKT::debug, "\n");
EC_POINT_free(r); } while (info.Signature > limit);
} while (info.Signature > BITMASK(55));
// ↑ ↑ ↑ // ↑ ↑ ↑
// The signature can't be longer than 55 bits, else it will // The signature can't be longer than 55 bits, else it will
// make the CD-key longer than 25 characters. // make the CD-key longer than 25 characters.
// Convert bytecode to Base24 CD-key. // Convert bytecode to Base24 CD-key.
base24(pKey, (BYTE *)pRaw); base24(pKey, pRaw.byte);
BN_CTX_free(numContext);
return true; return true;
} }
@ -197,26 +202,24 @@ BOOL BINK1998::Validate(std::string &pKey)
return false; return false;
} }
BN_CTX *numContext = BN_CTX_new(); Q_OWORD pRaw;
QWORD pRaw[2];
// Convert Base24 CD-key to bytecode. // Convert Base24 CD-key to bytecode.
unbase24((BYTE *)pRaw, pKey); unbase24(pRaw.byte, pKey);
// Extract RPK, hash and signature from bytecode. // Extract RPK, hash and signature from bytecode.
Unpack(pRaw); Unpack(&pRaw);
auto serial = fmt::format("{:d}", info.Serial); auto serial = fmt::format("{:d}", info.Serial);
fmt::print(UMSKT::debug, "Validation results:\n"); fmt::print(UMSKT::debug, "Validation results:\n");
fmt::print(UMSKT::debug, "{:>10}: {}\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", "Channel ID", serial.substr(0, 3));
fmt::print(UMSKT::debug, "{:>10}: {}\n", "Sequence", serial.substr(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}: {}\n", "Hash", info.Hash);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Signature", info.Signature); fmt::print(UMSKT::debug, "{:>10}: {}\n", "Signature", info.Signature);
fmt::print(UMSKT::debug, "\n"); 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), Integer e = info.Hash, s;
*s = BN_lebin2bn((BYTE *)&info.Signature, sizeof(info.Signature), nullptr); s.Decode((BYTE *)&info.Signature, sizeof(info.Signature));
BIGNUM *x = BN_CTX_get(numContext), *y = BN_CTX_get(numContext);
// Create 2 points on the elliptic curve. // 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 // t = sG
EC_POINT_mul(eCurve, t, nullptr, genPoint, s, numContext); t = eCurve.Multiply(s, genPoint);
// P = eK // P = eK
EC_POINT_mul(eCurve, p, nullptr, pubPoint, e, numContext); P = eCurve.Multiply(e, pubPoint);
// P += t // P += t
EC_POINT_add(eCurve, p, t, p, numContext); P = eCurve.Add(P, t);
// x = P.x; y = P.y; BYTE msgDigest[SHA::DIGESTSIZE], msgBuffer[SHAMessageLength], *pMsgBuffer = msgBuffer;
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];
// Convert resulting point coordinates to bytes. // Convert resulting point coordinates to bytes.
UMSKT::BN_bn2lebin(x, xBin, FIELD_BYTES);
UMSKT::BN_bn2lebin(y, yBin, FIELD_BYTES);
// Assemble the SHA message. // Assemble the SHA message.
memcpy(&msgBuffer[0], &pData, 4); pData.Encode(pMsgBuffer, 4);
memcpy(&msgBuffer[4], xBin, FIELD_BYTES); pMsgBuffer += 4;
memcpy(&msgBuffer[4 + FIELD_BYTES], yBin, FIELD_BYTES);
P.x.Encode(pMsgBuffer, FieldBytes);
pMsgBuffer += FieldBytes;
P.y.Encode(pMsgBuffer, FieldBytes);
pMsgBuffer += FieldBytes;
// compHash = SHA1(pSerial || P.x || P.y) // 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. // Translate the byte digest into a 32-bit integer - this is our computed hash.
// Truncate the hash to 28 bits. // Truncate the hash to 28 bits.
DWORD compHash = BYDWORD(msgDigest) >> 4 & BITMASK(28); Integer compHash = BYDWORD(msgDigest) >> 4 & BITMASK(28);
BN_free(e);
BN_free(s);
BN_CTX_free(numContext);
EC_POINT_free(t);
EC_POINT_free(p);
// If the computed hash checks out, the key is valid. // If the computed hash checks out, the key is valid.
return compHash == info.Hash; return compHash == info.Hash;

View File

@ -29,6 +29,7 @@ class EXPORT BINK1998 : public PIDGEN3
{ {
public: public:
using PIDGEN3::PIDGEN3; using PIDGEN3::PIDGEN3;
BINK1998() = default;
explicit BINK1998(PIDGEN3 *p3) explicit BINK1998(PIDGEN3 *p3)
{ {
privateKey = p3->privateKey; privateKey = p3->privateKey;
@ -38,11 +39,15 @@ class EXPORT BINK1998 : public PIDGEN3
eCurve = p3->eCurve; eCurve = p3->eCurve;
} }
static constexpr DWORD32 FieldBits = 384;
static constexpr DWORD32 FieldBytes = FieldBits / 8;
static constexpr DWORD32 SHAMessageLength = (4 + 2 * FieldBytes);
using PIDGEN3::Pack; using PIDGEN3::Pack;
BOOL Pack(QWORD *pRaw) override; BOOL Pack(Q_OWORD *pRaw) override;
using PIDGEN3::Unpack; using PIDGEN3::Unpack;
BOOL Unpack(QWORD *pRaw) override; BOOL Unpack(Q_OWORD *pRaw) override;
using PIDGEN3::Generate; using PIDGEN3::Generate;
BOOL Generate(std::string &pKey) override; BOOL Generate(std::string &pKey) override;

View File

@ -32,13 +32,19 @@
/** /**
* Packs a Windows Server 2003-like Product Key. * 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] Integer raw;
pRaw[0] = FIRSTNBITS(info.Signature, 22) << 42 | (QWORD)info.Hash << 11 | info.ChannelID << 1 | info.isUpgrade; // AuthInfo [113..104] <- Signature [103..42] <- Hash [41..11] <- Channel ID [10..1] <- Upgrade [0];
pRaw[1] = FIRSTNBITS(info.AuthInfo, 10) << 40 | NEXTSNBITS(info.Signature, 40, 22); 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; return true;
} }
@ -46,29 +52,30 @@ BOOL BINK2002::Pack(QWORD *pRaw)
/** /**
* Unpacks a Windows Server 2003-like Product Key. * 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. // We're assuming that the quantity of information within the product key is at most 114 bits.
// log2(24^25) = 114. // log2(24^25) = 114.
// Upgrade = Bit 0 // Upgrade = Bit 0
info.isUpgrade = FIRSTNBITS(pRaw[0], 1); info.isUpgrade = FIRSTNBITS(pRaw->qword[0], 1);
// Channel ID = Bits [1..10] -> 10 bits // 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 // 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 // Signature = Bits [42..103] -> 62 bits
// The quad-word signature overlaps AuthInfo in bits 104 and 105, // The quad-word signature overlaps AuthInfo in bits 104 and 105,
// hence Microsoft employs a secret technique called: Signature = HIDWORD(Signature) >> 2 | LODWORD(Signature) // 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 // AuthInfo = Bits [104..113] -> 10 bits
info.AuthInfo = NEXTSNBITS(pRaw[1], 10, 40); info.AuthInfo = NEXTSNBITS(pRaw->qword[1], 10, 40);
return true; return true;
} }
@ -82,76 +89,83 @@ BOOL BINK2002::Unpack(QWORD *pRaw)
*/ */
BOOL BINK2002::Generate(std::string &pKey) 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), Q_OWORD pRaw;
*x = BN_CTX_get(numContext), *y = BN_CTX_get(numContext);
QWORD pRaw[2]; Integer limit;
limit.SetBit(62);
limit--;
// Data segment of the RPK. // Data segment of the RPK.
DWORD pData = info.ChannelID << 1 | info.isUpgrade; Integer pData = info.ChannelID << 1 | info.isUpgrade;
BOOL noSquare; BOOL noSquare;
do do
{ {
EC_POINT *r = EC_POINT_new(eCurve); ECP::Point R;
// Generate a random number c consisting of 512 bits without any constraints. // 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 // R = cG
EC_POINT_mul(eCurve, r, nullptr, genPoint, c, numContext); R = eCurve.Multiply(c, genPoint);
// Acquire its coordinates. BYTE msgDigest[SHA::DIGESTSIZE], msgBuffer[SHAMessageLength], *pMsgBuffer = msgBuffer;
// 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);
// Assemble the first SHA message. // Assemble the first SHA message.
msgBuffer[0x00] = 0x79; msgBuffer[0] = 0x79;
msgBuffer[0x01] = (pData & 0x00FF); pMsgBuffer++;
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
memcpy(&msgBuffer[3], xBin, FIELD_BYTES_2003); pData.Encode(pMsgBuffer, 2);
memcpy(&msgBuffer[3 + FIELD_BYTES_2003], yBin, FIELD_BYTES_2003); 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) // 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. // Translate the byte digest into a 32-bit integer - this is our computed hash.
// Truncate the hash to 31 bits. // Truncate the hash to 31 bits.
info.Hash = BYDWORD(msgDigest) & BITMASK(31); info.Hash = BYDWORD(msgDigest) & BITMASK(31);
// Assemble the second SHA message. // Assemble the second SHA message.
pMsgBuffer = msgBuffer;
msgBuffer[0x00] = 0x5D; msgBuffer[0x00] = 0x5D;
msgBuffer[0x01] = (pData & 0x00FF); pMsgBuffer++;
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
msgBuffer[0x03] = (info.Hash & 0x000000FF); pData.Encode(pMsgBuffer, 2);
msgBuffer[0x04] = (info.Hash & 0x0000FF00) >> 8; pMsgBuffer += 2;
msgBuffer[0x05] = (info.Hash & 0x00FF0000) >> 16;
msgBuffer[0x06] = (info.Hash & 0xFF000000) >> 24; info.Hash.Encode(pMsgBuffer, 4);
msgBuffer[0x07] = (info.AuthInfo & 0x00FF); pMsgBuffer += 4;
msgBuffer[0x08] = (info.AuthInfo & 0xFF00) >> 8;
info.AuthInfo.Encode(pMsgBuffer, 2);
pMsgBuffer += 2;
msgBuffer[0x09] = 0x00; msgBuffer[0x09] = 0x00;
msgBuffer[0x0A] = 0x00; msgBuffer[0x0A] = 0x00;
// newSignature = SHA1(5D || Channel ID || Hash || AuthInfo || 00 00) // 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. // 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 // 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). // 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);
BN_lebin2bn((BYTE *)&iSignature, sizeof(iSignature), e);
/* /*
* *
@ -183,63 +197,57 @@ BOOL BINK2002::Generate(std::string &pKey)
*/ */
// e = ek (mod n) // e = ek (mod n)
BN_mod_mul(e, e, privateKey, genOrder, numContext); e = iSignature * privateKey % genOrder;
// s = e
BN_copy(s, e);
// s = (ek (mod n))² // s = (ek (mod n))²
BN_mod_sqr(s, s, genOrder, numContext); s = CryptoPP::ModularExponentiation(e, Integer::Two(), genOrder);
// c *= 4 (c <<= 2) // c *= 4 (c <<= 2)
BN_lshift(c, c, 2); c <<= 2;
// s += c // 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, // 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. // hence if BN_sqrt_mod returns NULL, we need to restart with a different seed.
// s = √((ek)² + 4c (mod n)) // 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) // 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. // If s is odd, add order to it.
// The order is a prime, so it can't be even. // 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 // s = -ek + √((ek)² + 4c) + n
BN_add(s, s, genOrder); s += genOrder;
} }
// s /= 2 (s >>= 1) // s /= 2 (s >>= 1)
BN_rshift1(s, s); s >>= 1;
// Translate resulting scalar into a 64-bit integer (the byte order is little-endian). // 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 product key.
Pack(pRaw); Pack(&pRaw);
fmt::print(UMSKT::debug, "Generation results:\n"); 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}: {:d}\n", "Channel ID", info.ChannelID); fmt::print(UMSKT::debug, "{:>10}: {}\n", "Channel ID", info.ChannelID);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Hash", info.Hash); fmt::print(UMSKT::debug, "{:>10}: {}\n", "Hash", info.Hash);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Signature", info.Signature); fmt::print(UMSKT::debug, "{:>10}: {}\n", "Signature", info.Signature);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "AuthInfo", info.AuthInfo); fmt::print(UMSKT::debug, "{:>10}: {}\n", "AuthInfo", info.AuthInfo);
fmt::print(UMSKT::debug, "\n"); fmt::print(UMSKT::debug, "\n");
EC_POINT_free(r); } while (info.Signature > limit || noSquare);
} while (info.Signature > BITMASK(62) || noSquare);
// ↑ ↑ ↑ // ↑ ↑ ↑
// The signature can't be longer than 62 bits, else it will // The signature can't be longer than 62 bits, else it will
// overlap with the AuthInfo segment next to it. // overlap with the AuthInfo segment next to it.
// Convert bytecode to Base24 CD-key. // Convert bytecode to Base24 CD-key.
base24(pKey, (BYTE *)pRaw); base24(pKey, pRaw.byte);
BN_CTX_free(numContext);
return true; return true;
} }
@ -251,48 +259,51 @@ BOOL BINK2002::Generate(std::string &pKey)
**/ **/
BOOL BINK2002::Validate(std::string &pKey) BOOL BINK2002::Validate(std::string &pKey)
{ {
BN_CTX *context = BN_CTX_new(); Q_OWORD bKey;
QWORD bKey[2];
// Convert Base24 CD-key to bytecode. // Convert Base24 CD-key to bytecode.
unbase24((BYTE *)bKey, &pKey[0]); unbase24(bKey.byte, &pKey[0]);
// Extract product key segments from bytecode. // 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, "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", "Channel ID", info.ChannelID);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Hash", info.Hash); 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", "Signature", info.Signature);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "AuthInfo", info.AuthInfo); fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "AuthInfo", info.AuthInfo);
fmt::print(UMSKT::debug, "\n"); 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. // Assemble the first SHA message.
msgBuffer[0x00] = 0x5D; msgBuffer[0x00] = 0x5D;
msgBuffer[0x01] = (pData & 0x00FF); pMsgBuffer++;
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
msgBuffer[0x03] = (info.Hash & 0x000000FF); pData.Encode(pMsgBuffer, 2);
msgBuffer[0x04] = (info.Hash & 0x0000FF00) >> 8; pMsgBuffer += 2;
msgBuffer[0x05] = (info.Hash & 0x00FF0000) >> 16;
msgBuffer[0x06] = (info.Hash & 0xFF000000) >> 24; info.Hash.Encode(pMsgBuffer, 4);
msgBuffer[0x07] = (info.AuthInfo & 0x00FF); pMsgBuffer += 4;
msgBuffer[0x08] = (info.AuthInfo & 0xFF00) >> 8;
info.AuthInfo.Encode(pMsgBuffer, 2);
pMsgBuffer += 2;
msgBuffer[0x09] = 0x00; msgBuffer[0x09] = 0x00;
msgBuffer[0x0A] = 0x00; msgBuffer[0x0A] = 0x00;
// newSignature = SHA1(5D || Channel ID || Hash || AuthInfo || 00 00) // 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. // 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 // 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). // (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) * P = s(sG + eK)
* *
*/ */
Integer e = iSignature, s = info.Signature;
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);
// Create 2 points on the elliptic curve. // 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 // t = sG
EC_POINT_mul(eCurve, t, nullptr, genPoint, s, context); t = eCurve.Multiply(s, genPoint);
// p = eK // p = eK
EC_POINT_mul(eCurve, p, nullptr, pubPoint, e, context); p = eCurve.Multiply(e, pubPoint);
// p += t // p += t
EC_POINT_add(eCurve, p, t, p, context); p = eCurve.Add(p, t);
// p *= s // p *= s
EC_POINT_mul(eCurve, p, nullptr, p, s, context); p = eCurve.Multiply(s, p);
// 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);
// Assemble the second SHA message. // Assemble the second SHA message.
pMsgBuffer = msgBuffer;
msgBuffer[0x00] = 0x79; msgBuffer[0x00] = 0x79;
msgBuffer[0x01] = (pData & 0x00FF); pMsgBuffer++;
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
memcpy((void *)&msgBuffer[3], (void *)xBin, FIELD_BYTES_2003); pData.Encode(pMsgBuffer, 2);
memcpy((void *)&msgBuffer[3 + FIELD_BYTES_2003], (void *)yBin, FIELD_BYTES_2003); 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) // 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. // Translate the byte digest into a 32-bit integer - this is our computed hash.
// Truncate the hash to 31 bits. // Truncate the hash to 31 bits.
DWORD compHash = BYDWORD(msgDigest) & BITMASK(31); Integer compHash = BYDWORD(msgDigest) & BITMASK(31);
BN_free(s);
BN_free(e);
EC_POINT_free(p);
EC_POINT_free(t);
BN_CTX_free(context);
// If the computed hash checks out, the key is valid. // If the computed hash checks out, the key is valid.
return compHash == info.Hash; return compHash == info.Hash;

View File

@ -29,6 +29,7 @@ class EXPORT BINK2002 : public PIDGEN3
{ {
public: public:
using PIDGEN3::PIDGEN3; using PIDGEN3::PIDGEN3;
BINK2002() = default;
explicit BINK2002(PIDGEN3 *p3) explicit BINK2002(PIDGEN3 *p3)
{ {
privateKey = p3->privateKey; privateKey = p3->privateKey;
@ -38,11 +39,15 @@ class EXPORT BINK2002 : public PIDGEN3
eCurve = p3->eCurve; eCurve = p3->eCurve;
} }
static constexpr DWORD32 FieldBits = 512;
static constexpr DWORD32 FieldBytes = FieldBits / 8;
static constexpr DWORD32 SHAMessageLength = (3 + 2 * FieldBytes);
using PIDGEN3::Pack; using PIDGEN3::Pack;
BOOL Pack(QWORD *pRaw) override; BOOL Pack(Q_OWORD *pRaw) override;
using PIDGEN3::Unpack; using PIDGEN3::Unpack;
BOOL Unpack(QWORD *pRaw) override; BOOL Unpack(Q_OWORD *pRaw) override;
using PIDGEN3::Generate; using PIDGEN3::Generate;
BOOL Generate(std::string &pKey) override; BOOL Generate(std::string &pKey) override;

View File

@ -35,6 +35,24 @@ int getRandomNumber()
// guaranteed to be random // 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 * Initializes the elliptic curve
* *
@ -65,61 +83,49 @@ BOOL PIDGEN3::LoadEllipticCurve(const std::string pSel, const std::string aSel,
// BIGNUM - Large numbers // BIGNUM - Large numbers
// BIGNUMCTX - Context large numbers (temporary) // 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 // We're presented with an elliptic curve, a multivariable function y(x; p; a; b), where
// y^2 % p = x^3 + ax + b % p. // 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. // Public key will consist of the resulting (x; y) values.
BIGNUM *publicKeyX = BN_CTX_get(context), *publicKeyY = BN_CTX_get(context); 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. // 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); publicKeyX = Integer(&publicKeyXSel[0]), publicKeyY = Integer(&publicKeyYSel[0]);
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]);
/* Computed Data */ /* Computed Data */
BN_dec2bn(&genOrder, &genOrderSel[0]); genOrder = Integer(&genOrderSel[0]);
BN_dec2bn(&privateKey, &privateKeySel[0]); privateKey = Integer(&privateKeySel[0]);
/* Elliptic Curve calculations. */ /* Elliptic Curve calculations. */
// The group is defined via Fp = all integers [0; p - 1], where p is prime. // 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 // The function EC_POINT_set_affine_coordinates() sets the x and y coordinates for the point p defined over the
// curve given in group. // 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). // Create new point N for the generator on the elliptic curve and set its coordinates to (genX; genY).
genPoint = EC_POINT_new(eCurve); genPoint = ECP::Point(generatorX, generatorY);
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). // Create new point Q for the public key on the elliptic curve and set its coordinates to (pubX; pubY).
pubPoint = EC_POINT_new(eCurve); pubPoint = ECP::Point(publicKeyX, publicKeyY);
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 // If generator and public key points are not on the elliptic curve, either the generator or the public key values
// are incorrect. // are incorrect.
assert(EC_POINT_is_on_curve(eCurve, genPoint, context) == true); assert(eCurve.VerifyPoint(genPoint) == true);
assert(EC_POINT_is_on_curve(eCurve, pubPoint, context) == true); assert(eCurve.VerifyPoint(pubPoint) == true);
// Cleanup
BN_CTX_free(context);
return 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 PIDGEN3::Generate(std::string &pKey)
{ {
BOOL retval; BOOL retval;
@ -165,7 +171,6 @@ BOOL PIDGEN3::Validate(std::string &pKey)
void PIDGEN3::base24(std::string &cdKey, BYTE *byteSeq) void PIDGEN3::base24(std::string &cdKey, BYTE *byteSeq)
{ {
BYTE rbyteSeq[16], output[26]; BYTE rbyteSeq[16], output[26];
BIGNUM *z;
// Copy byte sequence to the reversed byte sequence. // Copy byte sequence to the reversed byte sequence.
memcpy(rbyteSeq, byteSeq, sizeof(rbyteSeq)); memcpy(rbyteSeq, byteSeq, sizeof(rbyteSeq));
@ -178,22 +183,18 @@ void PIDGEN3::base24(std::string &cdKey, BYTE *byteSeq)
; // do nothing, just counting ; // do nothing, just counting
} }
UMSKT::endian(rbyteSeq, ++length);
// Convert reversed byte sequence to BigNum z. // 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. // Divide z by 24 and convert the remainder to a CD-key char.
for (int i = 24; i >= 0; i--) for (int i = 24; i >= 0; i--)
{ {
output[i] = pKeyCharset[BN_div_word(z, 24)]; output[i] = pKeyCharset[z.Modulo(24)];
} }
output[25] = 0; output[25] = 0;
cdKey = (char *)output; 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) void PIDGEN3::unbase24(BYTE *byteSeq, std::string cdKey)
{ {
BYTE pDecodedKey[PK_LENGTH + NULL_TERMINATOR]{}; 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. // 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 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. // Calculate the weighed sum of byte array elements.
for (int i = 0; i < PK_LENGTH; i++) for (int i = 0; i < PK_LENGTH; i++)
{ {
BN_mul_word(y, PK_LENGTH - 1); y *= PK_LENGTH - 1;
BN_add_word(y, pDecodedKey[i]); y += pDecodedKey[i];
} }
// Acquire length. // Acquire length.
int n = BN_num_bytes(y); auto n = y.ByteCount();
// Place the generated code into the byte sequence. // Place the generated code into the byte sequence.
BN_bn2bin(y, byteSeq); y.Encode(byteSeq, 16);
BN_free(y);
// Reverse the byte sequence.
UMSKT::endian(byteSeq, n);
} }
/**
* Checks to see if the currently instantiated PIDGEN3 object has a
* field size greater than the maximum known BINK1998 size.
*
* @return
*/
BOOL PIDGEN3::checkFieldIsBink1998() 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? // 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) BOOL PIDGEN3::checkFieldStrIsBink1998(std::string keyin)
{ {
auto *context = BN_CTX_new(); Integer check(&keyin[0]);
auto max = BN_CTX_get(context), input = BN_CTX_get(context);
BN_dec2bn(&input, &keyin[0]); // is max > check?
return (MaxSizeBINK1998 > check);
// 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;
} }

View File

@ -34,14 +34,12 @@ class EXPORT PIDGEN3
friend class BINK2002; friend class BINK2002;
protected: protected:
BIGNUM *privateKey, *genOrder; Integer privateKey, genOrder;
EC_POINT *genPoint, *pubPoint; ECP::Point genPoint, pubPoint;
EC_GROUP *eCurve; ECP eCurve;
public: public:
PIDGEN3() PIDGEN3() = default;
{
}
PIDGEN3(PIDGEN3 &p3) PIDGEN3(PIDGEN3 &p3)
{ {
@ -54,43 +52,38 @@ class EXPORT PIDGEN3
virtual ~PIDGEN3() virtual ~PIDGEN3()
{ {
EC_GROUP_free(eCurve);
EC_POINT_free(genPoint);
EC_POINT_free(pubPoint);
BN_free(genOrder);
BN_free(privateKey);
} }
struct KeyInfo struct KeyInfo
{ {
DWORD Serial = 0, AuthInfo = 0, ChannelID = 0, Hash = 0; Integer Serial = 0, AuthInfo = 0, ChannelID = 0, Hash = 0, Signature = 0;
QWORD Signature = 0;
BOOL isUpgrade = false; 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; } info;
static constexpr char pKeyCharset[] = "BCDFGHJKMPQRTVWXY2346789"; static constexpr char pKeyCharset[] = "BCDFGHJKMPQRTVWXY2346789";
static const Integer MaxSizeBINK1998;
BOOL LoadEllipticCurve(std::string pSel, std::string aSel, std::string bSel, std::string generatorXSel, 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 generatorYSel, std::string publicKeyXSel, std::string publicKeyYSel,
std::string genOrderSel, std::string privateKeySel); std::string genOrderSel, std::string privateKeySel);
virtual BOOL Pack(QWORD *pRaw) = 0; virtual BOOL Pack(Q_OWORD *pRaw) = 0;
virtual BOOL Unpack(QWORD *pRaw) = 0; virtual BOOL Unpack(Q_OWORD *pRaw) = 0;
virtual BOOL Generate(std::string &pKey); virtual BOOL Generate(std::string &pKey);
virtual BOOL Validate(std::string &pKey); virtual BOOL Validate(std::string &pKey);
@ -99,6 +92,7 @@ class EXPORT PIDGEN3
void unbase24(BYTE *byteSeq, std::string cdKey); void unbase24(BYTE *byteSeq, std::string cdKey);
BOOL checkFieldIsBink1998(); BOOL checkFieldIsBink1998();
static BOOL checkFieldStrIsBink1998(std::string keyin); static BOOL checkFieldStrIsBink1998(std::string keyin);
static PIDGEN3 *Factory(const std::string &field);
}; };
#endif // UMSKT_PIDGEN3_H #endif // UMSKT_PIDGEN3_H

View File

@ -98,9 +98,10 @@ using BOOL = int32_t;
using BYTE = uint8_t; using BYTE = uint8_t;
using WORD = uint16_t; using WORD = uint16_t;
using DWORD = unsigned long; using DWORD = unsigned long;
using DWORD32 = uint32_t;
using QWORD = uint64_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; using __m128 = __n128;
#endif #endif
@ -114,7 +115,7 @@ using OWORD = uint128_t;
typedef union { typedef union {
OWORD oword; OWORD oword;
QWORD qword[2]; QWORD qword[2];
DWORD dword[4]; DWORD32 dword32[4];
WORD word[8]; WORD word[8];
BYTE byte[16]; BYTE byte[16];
} Q_OWORD; } Q_OWORD;