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