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