94 Commits

Author SHA1 Message Date
a827844cbd merge in HEAD changes 2024-01-24 20:20:03 -08:00
3e51fe1c8b WIP more rewrite/rework changes, major refactoring 2024-01-24 20:04:36 -08:00
783a5afb3a update CPM, don't store in repository 2024-01-05 18:29:14 -08:00
cb557c1ed8 Fix PIDGEN3 2024-01-05 12:17:32 -08:00
d378c6499e Update README.md 2024-01-05 06:52:47 -05:00
5e68e1c8e1 things are quite broken 2024-01-04 22:21:35 -08:00
bf6365916d total refactor, happy new year, ground level code for automatic DPC selection, code is currently very much a work in progress, and very much broken, we'll work through it 2024-01-04 16:32:18 -08:00
3ea8731271 Merge pull request #80 from Neilpang/patch-1
Upgrade to freebsd-vm@v1
2023-12-19 17:03:52 +00:00
018f9f533c add trigger for pull_request 2023-12-17 20:38:37 +01:00
f1f1e0e6ea Upgrade to freebsd-vm@v1
The v0 is not working.
2023-12-17 20:26:24 +01:00
c4b63c15b2 Update keys.json (#79)
Added BINK ID10
2023-12-15 13:32:09 -08:00
1548e14169 Update OpenSSL to 3.1.4
Please see GIF attached for what we'll eventually do to OpenSSL.
2023-12-14 00:24:33 +00:00
c0a4c76b54 standardize using clang-format 2023-12-10 04:06:42 -08:00
8cc691b72f refactor/rework confid 2023-12-09 18:50:47 -08:00
72d48dd38b Merge pull request #74 from whatdoineed2do/build-static-normal-fixes
cleanup CMakeLists.txt
2023-09-30 17:51:45 -04:00
00d4906b28 djgpp: drop forced shared 2023-09-29 22:43:52 +01:00
88f60630c1 gh: window - upgrade from 404'd 3.1.2 resource to openssl 3.1.3 2023-09-29 22:16:33 +01:00
2ac6920e2c cleanup CMakeLists.txt to build normal with statically linked internal lib without need for full static linkage 2023-09-29 22:16:33 +01:00
8f843ad4c3 Merge pull request #72 from whatdoineed2do/usage-validation-memleaks
Usage validation and memleaks fixes
2023-09-27 04:42:08 -04:00
2753bf2a40 Update README.md 2023-09-26 23:05:22 -04:00
d17ada2e64 Merge pull request #73 from techguy16/master
Add Discord Invite
2023-09-26 14:28:13 -04:00
6685b38aac Update README.md 2023-09-27 07:26:10 +13:00
884d8c9703 Update README.md 2023-09-27 07:24:56 +13:00
5ba2dbddd4 EC/BN memleak 2023-09-25 12:13:53 +01:00
bf40bb6402 CLI moved to stack object 2023-09-25 12:13:43 +01:00
12a041c380 BN_free() memleaks 2023-09-25 12:04:52 +01:00
ecd9cd8dd2 office 2k7 enterprise must be given inst id 2023-09-25 11:26:28 +01:00
6989ae6c94 ensure arg for -p 2023-09-25 11:21:42 +01:00
ac510f8253 Update README.md 2023-09-17 19:05:16 -04:00
72c42f66c9 Merge pull request #70 from pottzman/master
Universal ConfirmationID
2023-09-07 13:34:10 -04:00
759c4009ef Merge pull request #16 from UMSKT/master
test merge
2023-09-07 19:21:48 +10:00
78c358c933 Merge pull request #15 from pottzman/ConfirmationID
Universal ConfirmationID
2023-09-07 19:17:53 +10:00
1d5e233c19 Update confid.cpp 2023-09-07 18:44:47 +10:00
6c06732331 Update confid.cpp 2023-09-07 18:05:58 +10:00
f347231362 Update confid.cpp 2023-09-07 17:29:07 +10:00
a7e97e45ee Update confid.cpp 2023-09-07 17:16:00 +10:00
bf57c32eae Merge pull request #12 from pottzman/ConfirmationID
Universal ConfirmationID
2023-09-06 23:16:38 +10:00
25db955b61 Update confid.cpp 2023-09-06 22:56:28 +10:00
1aeceb28f1 Update confid.cpp 2023-09-06 21:56:53 +10:00
b451a04f3c Update confid.cpp 2023-09-06 21:32:12 +10:00
3e5e03df4d Update confid.cpp 2023-09-06 20:54:34 +10:00
e3bdc93249 Update confid.cpp 2023-09-06 20:49:09 +10:00
36b2eb3e7d Update confid.cpp 2023-09-06 20:46:36 +10:00
49fefca596 Fix DOS compilation (Attempt 2) 2023-09-02 13:44:35 -04:00
178c9e0689 Fix DOS compilation (Attempt 1) 2023-09-02 13:43:03 -04:00
214d2d38a5 Merge pull request #68 from UMSKT/newline-fix 2023-09-02 13:16:56 -04:00
3ae078e3c5 update arg from nonewline to nonewlines 2023-09-02 11:53:09 -04:00
12e511b3a5 Update cli.cpp 2023-09-02 11:39:22 -04:00
21bac3b66c Update cli.cpp 2023-09-02 11:37:41 -04:00
09842ace12 Update cli.h 2023-09-02 11:37:38 -04:00
0d016b8872 Update cli.cpp 2023-09-02 11:31:25 -04:00
b1743f4bff fix name for FreeBSD 2023-09-02 11:17:52 -04:00
cc765edb4f Merge pull request #61 from UMSKT/workflow-update 2023-09-02 11:11:47 -04:00
4d1b5d6681 Update README.md 2023-09-02 11:11:16 -04:00
f59d77bdd1 Merge branch 'master' into workflow-update 2023-09-02 10:43:12 -04:00
71cbd19017 Add universal Confirmation ID 2023-09-02 10:42:26 -04:00
974f400cfc Revert "TEMP -- use -v" 2023-09-02 09:56:36 -04:00
a2d521c230 Update CMakeLists.txt 2023-09-02 09:55:20 -04:00
d53409f5bd TEMP -- use -v 2023-09-02 09:51:35 -04:00
2703e17f69 Update cli.cpp 2023-09-02 23:51:08 +10:00
680239bdb7 Merge branch 'cmake-fix' into master 2023-09-02 09:44:57 -04:00
104bdb19e3 Update confid.cpp 2023-09-02 23:33:47 +10:00
f2f859faeb Update confid.h 2023-09-02 23:27:02 +10:00
a2d9c46a4b Update libumskt.cpp 2023-09-02 23:25:14 +10:00
f65533bbb3 macOS build is not static 2023-09-02 09:24:04 -04:00
90e31b667a Update cli.h 2023-09-02 23:23:59 +10:00
492d245f86 Update cli.cpp
added CLI options for confirmation ID generation
2023-09-02 23:22:53 +10:00
361a39e204 Fix macOS compilation (Attempt 1) 2023-09-02 09:20:54 -04:00
31993afb62 Merge pull request #3 from UMSKT/master
FE and FF BINK exclusions
2023-09-02 23:03:17 +10:00
b3f64e6330 fix typo 2023-09-02 00:59:34 -04:00
ccf93a0089 Merge pull request #51 from UMSKT/fe-ff-fix
Add exclusions for FE and FF BINKs
2023-09-01 23:17:58 -04:00
ae391a5e50 Update cli.cpp 2023-09-01 22:43:32 -04:00
3620cf5af6 Update README.md 2023-09-01 19:54:08 -04:00
b7965f19e8 Delete test.md 2023-08-14 22:20:59 -04:00
52c9a57ea2 Create test.md 2023-08-14 22:16:07 -04:00
283df1c1fe Update linux.yml 2023-08-14 22:01:07 -04:00
c1eb81490b Update freebsd.yml 2023-08-14 22:01:01 -04:00
2ee6a99acd Update macos.yml 2023-08-14 22:00:58 -04:00
1370a6ecff Update windows.yml 2023-08-14 22:00:56 -04:00
e3a6b78407 Update dos-djgpp.yml 2023-08-14 21:59:25 -04:00
6ae5c9e435 Update windows.yml 2023-08-14 15:12:24 -04:00
a6bfaed6e8 Update macos.yml 2023-08-14 15:12:13 -04:00
f7b41a9810 Update linux.yml 2023-08-14 15:11:53 -04:00
e76eb7ac33 Update freebsd.yml 2023-08-14 15:11:35 -04:00
c91bbad69a Update dos-djgpp.yml 2023-08-14 15:11:17 -04:00
75e81e7049 Update dos-djgpp.yml 2023-08-14 15:09:41 -04:00
e9131e45c8 Update freebsd.yml 2023-08-14 15:09:16 -04:00
c664ea7f9c Update linux.yml 2023-08-14 15:08:52 -04:00
f95501b789 Update macos.yml 2023-08-14 15:08:24 -04:00
444f8c45c7 Allow manual workflows and auto workflows on all branches
This lets workflows work on all branches without changing anything, and allows workflows to be activated manually.
2023-08-14 15:07:24 -04:00
Neo
45004623be Why does the Github web editor commit tabs??? 2023-07-28 16:17:57 -07:00
Neo
a4cb524fed re-add removed comment 2023-07-28 16:16:31 -07:00
Neo
03ae90163a cleaner cli.cpp fix 2023-07-28 16:15:37 -07:00
c1e9a0f021 add exclusions for FE and FF 2023-07-28 18:10:25 -05:00
52 changed files with 6063 additions and 2511 deletions

220
.clang-format Normal file
View File

@ -0,0 +1,220 @@
---
Language: Cpp
# BasedOnStyle: Microsoft
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: false
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: BinPack
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: false
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: Signature
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 1000
PenaltyIndentedWhitespace: 0
PointerAlignment: Right
PPIndentWidth: -1
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RequiresClausePosition: OwnLine
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...
---
Language: Json
BasedOnStyle: LLVM
...

View File

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

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -22,9 +22,9 @@ name: C/C++ CI (DOS DJGPP)
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
branches: [ "*" ]
paths-ignore: [ '**.md', 'doc/**', '.idea/**'] # If only these files are edited, skip
workflow_dispatch:
env:
CC: ${{ github.workspace }}/djgpp/bin/i586-pc-msdosdjgpp-gcc

View File

@ -1,41 +1,45 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# @FileCreated by techguy16 on 07/23/2023
# @Maintainer techguy16
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# @FileCreated by techguy16 on 07/23/2023
# @Maintainer techguy16
name: C/C++ CI (FreeBSD)
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
push:
branches: [ "*" ]
paths-ignore: [ '**.md', 'doc/**', '.idea/**'] # If only these files are edited, skip
pull_request:
branches: [ "*" ]
paths-ignore: [ '**.md', 'doc/**', '.idea/**'] # If only these files are edited, skip
workflow_dispatch:
jobs:
build:
runs-on: macos-latest
runs-on: ubuntu-latest
name: build-x86_64
steps:
- uses: actions/checkout@v3
- name: Build & Test in FreeBSD
id: test
uses: vmactions/freebsd-vm@v0
uses: vmactions/freebsd-vm@v1
with:
envs: 'MYTOKEN MYTOKEN2'
usesh: true

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -22,9 +22,9 @@ name: C/C++ CI (Linux)
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
branches: [ "*" ]
paths-ignore: [ '**.md', 'doc/**', '.idea/**'] # If only these files are edited, skip
workflow_dispatch:
jobs:
build:
@ -50,6 +50,7 @@ jobs:
musl-dev
openssl-dev
openssl-libs-static
zlib-dev
arch: ${{ matrix.arch }}
shell-name: alpine-target.sh
@ -70,3 +71,17 @@ jobs:
with:
name: UMSKT-linux-${{ matrix.arch }}-static
path: build/actions_upload
- name: Configure and build static internal deps UMSKT
uses: threeal/cmake-action@7ef2eb8da6e5ec0a6de6b1ddc96987080bed06e8
with:
options: MUSL_STATIC=OFF BUILD_SHARED_LIBS=OFF
run-build: true
shell: alpine-target.sh {0}
- name: Configure and build shared deps UMSKT
uses: threeal/cmake-action@7ef2eb8da6e5ec0a6de6b1ddc96987080bed06e8
with:
options: MUSL_STATIC=OFF BUILD_SHARED_LIBS=ON
run-build: true
shell: alpine-target.sh {0}

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -22,9 +22,9 @@ name: C/C++ CI (macOS)
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
branches: [ "*" ]
paths-ignore: [ '**.md', 'doc/**', '.idea/**'] # If only these files are edited, skip
workflow_dispatch:
jobs:
build-x86:
@ -56,5 +56,5 @@ jobs:
- name: Upload build artifact
uses: actions/upload-artifact@v3.1.2
with:
name: UMSKT-macOS-${{ matrix.arch }}-static
name: UMSKT-macOS-${{ matrix.arch }}
path: build/actions_upload

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -22,9 +22,9 @@ name: C/C++ CI (Windows)
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
branches: [ "*" ]
paths-ignore: [ '**.md', 'doc/**', '.idea/**'] # If only these files are edited, skip
workflow_dispatch:
jobs:
build-32bit:
@ -52,11 +52,11 @@ jobs:
exit 1
}
- name: Download And Install 32-bit OpenSSL 3.1.2
- name: Download And Install 32-bit OpenSSL 3.1.4
run: |
$installDir = "$Env:ProgramFiles\OpenSSL"
$installerURL = "https://slproweb.com/download/Win32OpenSSL-3_1_2.exe"
$installerName = "Win32OpenSSL-3_1_2.exe"
$installerURL = "https://slproweb.com/download/Win32OpenSSL-3_1_4.exe"
$installerName = "Win32OpenSSL-3_1_4.exe"
$installerPath = Join-Path -Path "${env:Temp}" -ChildPath "$installerName"
(New-Object System.Net.WebClient).DownloadFile($installerURL, $installerPath)
@ -112,11 +112,11 @@ jobs:
exit 1
}
- name: Download And Install 64-bit OpenSSL 3.1.2
- name: Download And Install 64-bit OpenSSL 3.1.4
run: |
$installDir = "$Env:ProgramFiles\OpenSSL"
$installerURL = "https://slproweb.com/download/Win64OpenSSL-3_1_2.exe"
$installerName = "Win64OpenSSL-3_1_2.exe"
$installerURL = "https://slproweb.com/download/Win64OpenSSL-3_1_4.exe"
$installerName = "Win64OpenSSL-3_1_4.exe"
$installerPath = Join-Path -Path "${env:Temp}" -ChildPath "$installerName"
(New-Object System.Net.WebClient).DownloadFile($installerURL, $installerPath)

2
.gitignore vendored
View File

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

2
.idea/UMSKT.iml generated Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

90
.idea/editor.xml generated Normal file
View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BackendCodeEditorSettings">
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/FREE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
</component>
</project>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/UMSKT.iml" filepath="$PROJECT_DIR$/.idea/UMSKT.iml" />
</modules>
</component>
</project>

14
.idea/remote-targets.xml generated Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteTargetsManager">
<option name="projectDefaultTargetUuid" value="36c80fd0-a122-4ef6-8ee6-1bd41007a378" />
<targets>
<target name="WSL - Ubuntu" type="wsl" uuid="36c80fd0-a122-4ef6-8ee6-1bd41007a378">
<config>
<option name="distributionMsId" value="Ubuntu" />
<option name="projectRootOnTarget" value="{exitCode=0, timeout=false, cancelled=false, stdout=/mnt/c/Users/neo/AppData/Local/Programs/CLion/jbr/bin&#10;, stderr=}/UMSKT" />
</config>
</target>
</targets>
</component>
</project>

25
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,25 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# @FileCreated by Neo on 01/03/2024
# @Maintainer Neo
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: 'v17.0.6' # Use the sha / tag you want to point at
hooks:
- id: clang-format

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -20,9 +20,12 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
PROJECT(UMSKT)
SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
SET(CMAKE_OSX_SYSROOT "macosx" CACHE PATH "macOS SDK path")
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
OPTION(BUILD_SHARED_LIBS "Build all libraries as shared" OFF)
OPTION(UMSKT_USE_SHARED_OPENSSL "Force linking against the system-wide OpenSSL library" OFF)
OPTION(MUSL_STATIC "Enable fully static builds in a muslc environment (i.e. Alpine Linux)" OFF)
OPTION(DJGPP_WATT32 "Enable compilation and linking with DJGPP/WATT32/OpenSSL" OFF)
@ -31,16 +34,27 @@ OPTION(MSVC_MSDOS_STUB "Specify a custom MS-DOS stub for a 32-bit MSVC compilati
SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS})
SET(UMSKT_LINK_DIRS ${UMSKT_LINK_DIRS})
IF(UMSKT_USE_SHARED_OPENSSL)
# macOS does not support static build
IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
SET(UMSKT_USE_SHARED_OPENSSL ON)
ENDIF ()
# neither does dos idk i'm trying random stuff
IF (DJGPP_WATT32)
SET(UMSKT_USE_SHARED_OPENSSL ON)
ENDIF ()
IF (UMSKT_USE_SHARED_OPENSSL)
SET(OPENSSL_USE_STATIC_LIBS FALSE)
SET(OPENSSL_MSVC_STATIC_RT FALSE)
MESSAGE(WARNING "[UMSKT] Forcing shared OpenSSL runtime")
ELSE()
MESSAGE(STATUS "[UMSKT] Requesting dynamic version of OpenSSL")
ELSE ()
SET(OPENSSL_USE_STATIC_LIBS TRUE)
SET(OPENSSL_MSVC_STATIC_RT TRUE)
ENDIF()
MESSAGE(STATUS "[UMSKT] Requesting static version of OpenSSL")
ENDIF ()
IF(DJGPP_WATT32)
IF (DJGPP_WATT32)
SET(CMAKE_SYSTEM_NAME MSDOS)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
@ -48,68 +62,99 @@ IF(DJGPP_WATT32)
SET(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} ${DJGPP_WATT32})
SET(UMSKT_LINK_DIRS ${UMSKT_LINK_DIRS} ${WATT_ROOT}/lib)
ENDIF()
ENDIF ()
# 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 we found shared libraries - do the following:
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")
IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
SET(BUILD_SHARED_LIBS ON)
ELSE()
MESSAGE(STATUS "[UMSKT] Detected Static Library version of OpenSSL")
ENDIF()
MESSAGE(STATUS "[UMSKT] macOS has no static library - Shared library forced on")
ENDIF ()
# if we're compiling with MSVC, respect the DEBUG compile option
IF(MSVC)
IF (MSVC)
SET(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
IF(NOT BUILD_SHARED_LIBS)
SET(CMAKE_CXX_FLAGS_RELEASE "/MT")
SET(CMAKE_CXX_FLAGS_DEBUG "/MTd")
ELSE()
SET(CMAKE_CXX_FLAGS_RELEASE "/MD")
SET(CMAKE_CXX_FLAGS_DEBUG "/MDd")
ENDIF()
SET(CMAKE_CXX_FLAGS_RELEASE "/MT")
SET(CMAKE_CXX_FLAGS_DEBUG "/MTd")
SET(CMAKE_EXE_LINKER_FLAGS "/INCREMENTAL:NO /NODEFAULTLIB:MSVCRT")
SET(CMAKE_ENABLE_EXPORTS ON)
SET(UMSKT_EXE_WINDOWS_EXTRA src/windows/umskt.rc)
SET(UMSKT_EXE_WINDOWS_DLL src/windows/dllmain.cpp)
ENDIF()
ENDIF ()
IF(MUSL_STATIC)
IF (MUSL_STATIC)
MESSAGE(STATUS "[UMSKT] Performing a fully static build using muslc")
SET(BUILD_SHARED_LIBS OFF)
SET(OPENSSL_USE_STATIC_LIBS TRUE)
SET(CMAKE_EXE_LINKER_FLAGS "-static -static-libgcc -static-libstdc++")
SET(CMAKE_SHARED_LINKER_FLAGS "-static -static-libgcc -static-libstdc++")
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc -static-libstdc++")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
ENDIF()
ENDIF ()
# initalize cpm.CMake
INCLUDE(cmake/CPM.cmake)
# 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 ()
# initialize cpm.CMake
FILE(
DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.38.3/CPM.cmake
${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake
EXPECTED_HASH SHA256=cc155ce02e7945e7b8967ddfaff0b050e958a723ef7aad3766d368940cb15494
)
INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake)
# fetch cpm.CMake dependencies
# Include JSON development library
CPMAddPackage(
NAME nlohmann_json
GITHUB_REPOSITORY nlohmann/json
VERSION 3.11.2
VERSION 3.11.3
)
# Include fmt development library
CPMAddPackage(
NAME fmt
GITHUB_REPOSITORY fmtlib/fmt
GIT_TAG 10.0.0
VERSION 10.0.0
GIT_TAG 10.2.0
VERSION 10.2.0
)
# Include cmrc resource compiler
@ -140,43 +185,71 @@ CPMAddPackage(
### Resource compilation
CMRC_ADD_RESOURCE_LIBRARY(umskt-rc ALIAS umskt::rc NAMESPACE umskt keys.json)
SET(LIBUMSKT_SRC src/libumskt/libumskt.cpp src/libumskt/pidgen3/BINK1998.cpp src/libumskt/pidgen3/BINK2002.cpp src/libumskt/pidgen3/key.cpp src/libumskt/pidgen3/util.cpp src/libumskt/confid/confid.cpp src/libumskt/pidgen2/PIDGEN2.cpp src/libumskt/debugoutput.cpp)
SET(LIBUMSKT_PIDGEN2 src/libumskt/pidgen2/PIDGEN2.cpp)
SET(LIBUMSKT_PIDGEN3 src/libumskt/pidgen3/PIDGEN3.cpp src/libumskt/pidgen3/BINK1998.cpp src/libumskt/pidgen3/BINK2002.cpp)
SET(LIBUMSKT_CONFID src/libumskt/confid/confid.cpp src/libumskt/confid/polynomial.cpp src/libumskt/confid/residue.cpp src/libumskt/confid/divisor.cpp)
SET(LIBUMSKT_SRC src/libumskt/libumskt.cpp src/libumskt/debugoutput.cpp ${LIBUMSKT_PIDGEN2} ${LIBUMSKT_PIDGEN3} ${LIBUMSKT_CONFID})
SET(UMSKT_CLI_SRC src/main.cpp src/help.cpp src/cli.cpp src/generate.cpp)
SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} ${OPENSSL_CRYPTO_LIBRARIES} ${ZLIB_LIBRARIES} fmt)
IF (NOT MSVC)
SET(UMSKT_LINK_LIBS ${UMSKT_LINK_LIBS} umskt::rc)
SET(UMSKT_CLI_SRC ${UMSKT_CLI_SRC} src/rc.cpp)
ELSE()
SET(UMSKT_CLI_SRC ${UMSKT_CLI_SRC} src/windows/platform.cpp)
ENDIF()
#### Separate Build Path for emscripten
IF (EMSCRIPTEN)
ADD_EXECUTABLE(umskt ${LIBUMSKT_SRC})
ADD_EXECUTABLE(umskt ${UMSKT_CLI_SRC} ${LIBUMSKT_SRC})
TARGET_INCLUDE_DIRECTORIES(umskt PUBLIC ${OPENSSL_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(umskt -static OpenSSL::Crypto cryptopp::cryptopp fmt)
TARGET_LINK_LIBRARIES(umskt PUBLIC ${UMSKT_LINK_LIBS})
SET(CMAKE_EXECUTABLE_SUFFIX ".html")
SET_TARGET_PROPERTIES(umskt PROPERTIES COMPILE_FLAGS "-Os -sEXPORTED_RUNTIME_METHODS=ccall,cwrap")
SET_TARGET_PROPERTIES(umskt PROPERTIES LINK_FLAGS "-Os -sWASM=1 -sEXPORT_ALL=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap --no-entry")
ELSE()
IF(NOT UMSKT_USE_SHARED_OPENSSL)
### Static library compilation
ADD_LIBRARY(_umskt STATIC ${LIBUMSKT_SRC})
TARGET_INCLUDE_DIRECTORIES(_umskt PUBLIC ${OPENSSL_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(_umskt -static OpenSSL::Crypto fmt ${UMSKT_LINK_LIBS})
SET_TARGET_PROPERTIES(umskt PROPERTIES LINK_FLAGS "-Os -sWASM=1 -sEXPORT_ALL=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap --no-entry")
ELSE ()
## umskt.so/.dll creation
ADD_LIBRARY(_umskt SHARED ${LIBUMSKT_SRC} ${UMSKT_EXE_WINDOWS_EXTRA} ${UMSKT_EXE_WINDOWS_DLL})
TARGET_INCLUDE_DIRECTORIES(_umskt PUBLIC ${OPENSSL_INCLUDE_DIR} ${CMAKE_BINARY_DIR})
TARGET_LINK_DIRECTORIES(_umskt PUBLIC ${UMSKT_LINK_DIRS})
TARGET_LINK_LIBRARIES(_umskt PUBLIC ${UMSKT_LINK_LIBS})
IF(MSVC)
SET_TARGET_PROPERTIES(_umskt PROPERTIES OUTPUT_NAME libumskt)
ELSE()
### Shared library compilation
ADD_LIBRARY(_umskt SHARED ${LIBUMSKT_SRC} ${UMSKT_EXE_WINDOWS_EXTRA} ${UMSKT_EXE_WINDOWS_DLL})
TARGET_INCLUDE_DIRECTORIES(_umskt PUBLIC ${OPENSSL_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(_umskt OpenSSL::Crypto fmt ${UMSKT_LINK_LIBS})
TARGET_LINK_DIRECTORIES(_umskt PUBLIC ${UMSKT_LINK_DIRS})
SET_TARGET_PROPERTIES(_umskt PROPERTIES OUTPUT_NAME umskt)
ENDIF()
## umskt_static.a/.lib creation
ADD_LIBRARY(umskt_static ${LIBUMSKT_SRC} ${UMSKT_EXE_WINDOWS_EXTRA} ${UMSKT_EXE_WINDOWS_DLL})
TARGET_INCLUDE_DIRECTORIES(umskt_static PUBLIC ${OPENSSL_INCLUDE_DIR} ${CMAKE_BINARY_DIR})
TARGET_LINK_DIRECTORIES(umskt_static PUBLIC ${UMSKT_LINK_DIRS})
TARGET_LINK_LIBRARIES(umskt_static PUBLIC ${UMSKT_LINK_LIBS})
IF(MSVC)
SET_TARGET_PROPERTIES(umskt_static PROPERTIES OUTPUT_NAME libumskt_static)
ELSE()
SET_TARGET_PROPERTIES(umskt_static PROPERTIES OUTPUT_NAME umskt_static)
ENDIF()
### UMSKT executable compilation
ADD_EXECUTABLE(umskt src/main.cpp src/cli.cpp ${UMSKT_EXE_WINDOWS_EXTRA})
TARGET_INCLUDE_DIRECTORIES(umskt PUBLIC ${OPENSSL_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(umskt _umskt OpenSSL::Crypto fmt nlohmann_json::nlohmann_json umskt::rc ${UMSKT_LINK_LIBS})
ADD_EXECUTABLE(umskt ${UMSKT_CLI_SRC} ${UMSKT_EXE_WINDOWS_EXTRA})
TARGET_INCLUDE_DIRECTORIES(umskt PUBLIC ${OPENSSL_INCLUDE_DIR} ${CMAKE_BINARY_DIR})
TARGET_LINK_LIBRARIES(umskt PUBLIC umskt_static ${UMSKT_LINK_LIBS} nlohmann_json::nlohmann_json)
TARGET_LINK_DIRECTORIES(umskt PUBLIC ${UMSKT_LINK_DIRS})
IF(MSVC AND MSVC_MSDOS_STUB)
SET_PROPERTY(TARGET umskt APPEND PROPERTY LINK_FLAGS /STUB:${MSVC_MSDOS_STUB})
ENDIF()
IF (MSVC)
SET_PROPERTY(TARGET umskt APPEND PROPERTY COMPILE_FLAGS /DUMSKT_CLI_WINRC_EMBED_JSON)
IF (MSVC_MSDOS_STUB)
SET_PROPERTY(TARGET umskt APPEND PROPERTY LINK_FLAGS /STUB:${MSVC_MSDOS_STUB})
ENDIF()
ENDIF ()
IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
INSTALL(TARGETS umskt DESTINATION bin)
ENDIF ()
### Copy Shared Libraries and dependency files
IF (OPENSSL_CRYPTO_SHARED)
GET_FILENAME_COMPONENT(OPENSSL_CRYPTO_LIBRARY_FILENAME ${OPENSSL_CRYPTO_LIBRARY} NAME)
CONFIGURE_FILE(${OPENSSL_CRYPTO_LIBRARY} "${CMAKE_CURRENT_BINARY_DIR}/${OPENSSL_CRYPTO_LIBRARY_FILENAME}" COPYONLY)
ENDIF()
ENDIF()
ENDIF ()
ENDIF ()

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -1,6 +1,6 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -2,7 +2,7 @@
# This file is a part of the UMSKT Project
#
# Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
# Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by

View File

@ -4,6 +4,7 @@
[![Zulip chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://umskt.zulipchat.com)
[![libera.chat - #mspid](https://img.shields.io/badge/libera.chat-%23mspid-brightgreen)](https://web.libera.chat/gamja/?nick=Guest?#mspid)
[![Discord](https://dcbadge.vercel.app/api/server/cUZxfNNSdt?style=flat)](https://discord.gg/PpBSpuphWM)
**Build status**
@ -13,9 +14,9 @@
[![C/C++ CI (Linux)](https://github.com/UMSKT/UMSKT/actions/workflows/linux.yml/badge.svg)](../../actions/workflows/linux.yml)
[![C/C++ CI (FreeBSD)](https://github.com/UMSKT/UMSKT/actions/workflows/freebsd.yml/badge.svg)](../../actions/workflows/dos-djgpp.yml)
[![C/C++ CI (FreeBSD)](https://github.com/UMSKT/UMSKT/actions/workflows/freebsd.yml/badge.svg)](../../actions/workflows/freebsd.yml)
[![C/C++ CI (DOS DJGPP)](https://github.com/UMSKT/UMSKT/actions/workflows/dos-djgpp.yml/badge.svg)](../../actions/workflows/freebsd.yml)
[![C/C++ CI (DOS DJGPP)](https://github.com/UMSKT/UMSKT/actions/workflows/dos-djgpp.yml/badge.svg)](../../actions/workflows/dos-djgpp.yml)
------
@ -56,13 +57,19 @@ In light of the recent exponential interest in this project I've decided to put
* **Note:** Before continuing, please ensure you have the `umskt` executable extracted and on UNIX-like systems, have execution permissions (`chmod +x umskt`).
#### 2. Run `umskt` to generate a key, or add `--help` or `-h` to see more options.
#### 2. Install OpenSSL 3.1.2.
For Windows, click [here](https://slproweb.com/products/Win32OpenSSL.html) and choose the right version. For other operating systems, consult your package manager.
*Note: This only applies if the build you download has OpenSSL embedded (static library) or not. You can usually tell if the download size is measured in KB or MB. If it's MB, you don't need this.*
#### 3. *(Activation step for `Retail` and `OEM` only)*
#### 3. Run `umskt` to generate a key, or add `--help` or `-h` to see more options.
#### 4. *(Activation step for `Retail` and `OEM` only)*
* After installation, you will be prompted to activate Windows.
* Select the **telephone activation** method, then, run `umskt -i <Installation ID>` using the `Installation ID` the activation Wizard provides for you
* If you're activating a non-Windows product, use `umskt -i <Installation ID> -m <Product>`, where `<Product>` is one of `OFFICEXP`, `OFFICE2K3`, `OFFICE2K7`, or `PLUSDME`
* If activating Office 2003/2007, use `umskt -i <Installation ID> -m <Product> -p <Product ID>`
#### 4. Profit!
@ -76,6 +83,7 @@ The list of people who have helped to bring the XP generation to where it is now
* MSKey
* diamondggg
* pottzman
* david4599
* Endermanch
* Neo-Desktop
* WitherOrNot

View File

@ -1,33 +0,0 @@
set(CPM_DOWNLOAD_VERSION 0.38.1)
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
function(download_cpm)
message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION}
)
endfunction()
if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
download_cpm()
else()
# resume download if it previously failed
file(READ ${CPM_DOWNLOAD_LOCATION} check)
if("${check}" STREQUAL "")
download_cpm()
endif()
unset(check)
endif()
include(${CPM_DOWNLOAD_LOCATION})

View File

@ -47,7 +47,7 @@ The procedure for SLP 2.0 verification is as follows:
4. If the OEM product ID is detected, the OEM verification process starts, and it will check the installed OEM certificate <!-- "product certificate" ? --> is valid. It mainly uses the SLIC public key from BIOS which is loaded into the RAM, to verify the digital signature of product certificate <!-- Yes, this "product certificate" came from nowhere, so I guess this the OEM certificate that installed while installing the Windows Vista by OEM. -->. If validation failed, it is considered as inactivated.
5. Verify the OEM ID field between SLIC and RSDT (Root System Description Table), and compare the OEM ID field and OEM Table ID fields between SLIC and XSDT (Extended System Description Table). If they didn't match, it is considered as inactivated.
5. Validate the OEM ID field between SLIC and RSDT (Root System Description Table), and compare the OEM ID field and OEM Table ID fields between SLIC and XSDT (Extended System Description Table). If they didn't match, it is considered as inactivated.
6. After the above hurdles, the OEM license will be considered as activated. If not then fallback to inactivated and continue with normal procedure, like require user to activate the Windows.
@ -65,9 +65,9 @@ Here is more detailed verification process:
4. Use OEM public key verify against the digital signature of the Marker inside SLIC. if verified (this means the Message in the Marker is correct. <!-- There is no where talked about what is that Message and Marker. -->) then continue on OEM activation process, otherwise continue on WPA activation process.
5. Verify the Windows Logo <!-- I guess? "Windows Logo" part can be directly translate to "Windows Flag Mark", and this "Flag" means that actual waving thing, not a digital bit. I guess this approach is similar as the Nintendo logo bitmap inside Game Boy game cartridge ROM thing. --> inside the Marker. If the Windows Logo is present, then continue on OEM activation process, otherwise continue on WPA activation process.
5. Validate the Windows Logo <!-- I guess? "Windows Logo" part can be directly translate to "Windows Flag Mark", and this "Flag" means that actual waving thing, not a digital bit. I guess this approach is similar as the Nintendo logo bitmap inside Game Boy game cartridge ROM thing. --> inside the Marker. If the Windows Logo is present, then continue on OEM activation process, otherwise continue on WPA activation process.
6. Verify the version of Marker. If it's at least `0x20001` then continue on OEM activation process, otherwise OEM activation failed, and continue on WPA activation process.
6. Validate the version of Marker. If it's at least `0x20001` then continue on OEM activation process, otherwise OEM activation failed, and continue on WPA activation process.
7. Compare the OEM ID and OEM Table ID against all corresponding ACPI table headers. If they match, then OEM activation completed successfully, otherwise continue on WPA activation process.

1188
keys.json

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -22,537 +22,411 @@
#include "cli.h"
bool CLI::loadJSON(const fs::path& filename, json *output) {
if (!filename.empty() && !fs::exists(filename)) {
// define static storage
Options CLI::options;
json CLI::keys;
/**
*
* @param argcIn
* @param argvIn
* @return exit status (where success is 0)
*/
BYTE CLI::Init(int argcIn, char **argvIn)
{
// set default options
options = {argcIn, argvIn, "2E", "", "", "", "", "", "WINXP", "PROVLK", 0,
0, 1, false, false, false, false, false, false, false, PIDGEN_3, STATE_PIDGEN_GENERATE};
SetHelpText();
BOOL success = parseCommandLine();
if (!success)
{
return options.error;
}
// if we displayed help, without an error
// return success
if (options.help)
{
return -1;
}
success = processOptions();
if (!success)
{
return 2;
}
return 0;
}
/**
*
* @param filename
* @return success
*/
BOOL CLI::loadJSON(const fs::path &filename)
{
if (filename.empty())
{
if (options.verbose)
{
fmt::print("Loading internal keys file\n");
}
auto retval = loadEmbeddedJSON();
if (retval && options.verbose)
{
fmt::print("Loaded internal keys file successfully\n\n");
}
else if (!retval)
{
fmt::print("Error loading internal keys file...\n\n");
}
return retval;
}
if (!fs::exists(filename))
{
fmt::print("ERROR: File {} does not exist\n", filename.string());
return false;
}
else if (fs::exists(filename)) {
std::ifstream f(filename);
*output = json::parse(f, nullptr, false, false);
}
else if (filename.empty()) {
cmrc::embedded_filesystem fs = cmrc::umskt::get_filesystem();
cmrc::file keys = fs.open("keys.json");
*output = json::parse(keys, nullptr, false, false);
if (options.verbose)
{
fmt::print("Loading keys file {}\n", options.keysFilename);
}
if (output->is_discarded()) {
std::ifstream f(filename);
try
{
keys = json::parse(f, nullptr, false, false);
}
catch (const json::exception &e)
{
fmt::print("ERROR: Exception thrown while parsing {}: {}\n", filename.string(), e.what());
return false;
}
if (keys.is_discarded())
{
fmt::print("ERROR: Unable to parse keys from {}\n", filename.string());
return false;
}
if (options.verbose)
{
fmt::print("Loaded keys from {} successfully\n", options.keysFilename);
}
return true;
}
void CLI::showHelp(char *argv[]) {
fmt::print("usage: {} \n", argv[0]);
fmt::print("\t-h --help\tshow this message\n");
fmt::print("\t-v --verbose\tenable verbose output\n");
fmt::print("\t-n --number\tnumber of keys to generate (defaults to 1)\n");
fmt::print("\t-f --file\tspecify which keys file to load\n");
fmt::print("\t-i --instid\tinstallation ID used to generate confirmation ID\n");
fmt::print("\t-b --binkid\tspecify which BINK identifier to load (defaults to 2E)\n");
fmt::print("\t-l --list\tshow which products/binks can be loaded\n");
fmt::print("\t-c --channelid\tspecify which Channel Identifier to use (defaults to 640)\n");
fmt::print("\t-s --serial\tspecifies a serial to use in the product ID (defaults to random, BINK1998 only)\n");
fmt::print("\t-u --upgrade\tspecifies the Product Key will be an \"Upgrade\" version\n");
fmt::print("\t-V --validate\tproduct key to validate signature\n");
fmt::print("\n");
}
int CLI::parseCommandLine(int argc, char* argv[], Options* options) {
// set default options
*options = Options {
"2E",
"",
"",
"",
640,
0,
1,
false,
false,
false,
false,
false,
false,
MODE_BINK1998_GENERATE
};
for (int i = 1; i < argc; i++) {
std::string arg = argv[i];
if (arg == "-v" || arg == "--verbose") {
options->verbose = true;
UMSKT::setDebugOutput(stderr);
} else if (arg == "-h" || arg == "--help") {
options->help = true;
} else if (arg == "-n" || arg == "--number") {
if (i == argc - 1) {
options->error = true;
break;
}
int nKeys;
if (!sscanf(argv[i+1], "%d", &nKeys)) {
options->error = true;
} else {
options->numKeys = nKeys;
}
i++;
} else if (arg == "-b" || arg == "--bink") {
if (i == argc - 1) {
options->error = true;
break;
}
options->binkid = argv[i+1];
i++;
} else if (arg == "-l" || arg == "--list") {
options->list = true;
} else if (arg == "-c" || arg == "--channelid") {
if (i == argc - 1) {
options->error = true;
break;
}
int siteID;
if (!sscanf(argv[i+1], "%d", &siteID)) {
options->error = true;
} else {
options->channelID = siteID;
}
i++;
} else if (arg == "-s" || arg == "--serial") {
if (i == argc - 1) {
options->error = true;
break;
}
int serial_val;
if (!sscanf(argv[i+1], "%d", &serial_val)) {
options->error = true;
} else {
options->serialSet = true;
options->serial = serial_val;
}
i++;
} else if (arg == "-u" || arg == "--upgrade") {
options->upgrade = true;
} else if (arg == "-f" || arg == "--file") {
if (i == argc - 1) {
options->error = true;
break;
}
options->keysFilename = argv[i+1];
i++;
} else if (arg == "-i" || arg == "--instid") {
if (i == argc - 1) {
options->error = true;
break;
}
options->instid = argv[i+1];
options->applicationMode = MODE_CONFIRMATION_ID;
i++;
} else if (arg == "-V" || arg == "--validate") {
if (i == argc - 1) {
options->error = true;
break;
}
options->keyToCheck = argv[i+1];
options->applicationMode = MODE_BINK1998_VALIDATE;
i++;
} else {
options->error = true;
}
}
return !options->error;
}
int CLI::validateCommandLine(Options* options, char *argv[], json *keys) {
if (options->help || options->error) {
if (options->error) {
fmt::print("error parsing command line options\n");
}
showHelp(argv);
return 1;
}
if (options->verbose) {
if(options->keysFilename.empty()) {
fmt::print("Loading internal keys file\n");
} else {
fmt::print("Loading keys file {}\n", options->keysFilename);
}
}
if (!loadJSON(options->keysFilename, keys)) {
return 2;
}
if (options->verbose) {
if(options->keysFilename.empty()) {
fmt::print("Loaded internal keys file successfully\n");
} else {
fmt::print("Loaded keys from {} successfully\n",options->keysFilename);
}
}
if (options->list) {
for (auto el : (*keys)["Products"].items()) {
int id;
sscanf((el.value()["BINK"][0]).get<std::string>().c_str(), "%x", &id);
std::cout << el.key() << ": " << el.value()["BINK"] << std::endl;
}
fmt::print("\n\n");
fmt::print("** Please note: any BINK ID other than 2E is considered experimental at this time **\n");
fmt::print("\n");
return 1;
}
int intBinkID;
sscanf(options->binkid.c_str(), "%x", &intBinkID);
if (intBinkID >= 0x40) {
// set bink2002 validate mode if in bink1998 validate mode, else set bink2002 generate mode
options->applicationMode = (options->applicationMode == MODE_BINK1998_VALIDATE) ? MODE_BINK2002_VALIDATE : MODE_BINK2002_GENERATE;
}
if (options->channelID > 999) {
fmt::print("ERROR: refusing to create a key with a Channel ID greater than 999\n");
return 1;
}
// don't allow any serial not between 0 and 999999
if (options->serial > 999999 || options->serial < 0) {
fmt::print("ERROR: refusing to create a key with a Serial not between 000000 and 999999\n");
return 1;
}
return 0;
}
void CLI::printID(DWORD *pid) {
char raw[12];
char b[6], c[8];
int i, digit = 0;
/**
*
* @param pid
*/
void CLI::printID(DWORD *pid)
{
char raw[12], b[6], c[8];
char i, digit = 0;
// Convert PID to ascii-number (=raw)
snprintf(raw, sizeof(raw), "%09u", pid[0]);
snprintf(raw, sizeof(raw), "%09lu", pid[0]);
// Make b-part {640-....}
strncpy(b, raw, 3);
_strncpy(b, 6, &raw[0], 3);
b[3] = 0;
// Make c-part {...-123456X...}
strcpy(c, raw + 3);
_strcpy(c, &raw[3]);
// Make checksum digit-part {...56X-}
assert(strlen(c) == 6);
for (i = 0; i < 6; i++)
digit -= c[i] - '0'; // Sum digits
{
digit += c[i] - '0'; // Sum digits
}
digit %= 7;
if (digit > 0)
{
digit = 7 - digit;
}
while (digit < 0)
digit += 7;
c[6] = digit + '0';
c[7] = 0;
fmt::print("> Product ID: PPPPP-{}-{}-23xxx\n", b, c);
DWORD binkid;
_sscanf(options.binkID.c_str(), "%lx", &binkid);
binkid /= 2;
fmt::print("> Product ID: PPPPP-{}-{}-{}xxx\n", b, c, binkid);
}
void CLI::printKey(char *pk) {
assert(strlen(pk) >= PK_LENGTH);
/**
*
* @param pidgen3
* @return success
*/
BOOL CLI::InitPIDGEN3(PIDGEN3 &pidgen3)
{
const char *BINKID = &options.binkID[0];
auto bink = keys["BINK"][BINKID];
std::string spk = pk;
fmt::print("{}-{}-{}-{}-{}",
spk.substr(0,5),
spk.substr(5,5),
spk.substr(10,5),
spk.substr(15,5),
spk.substr(20,5));
}
bool CLI::stripKey(const char *in_key, char out_key[PK_LENGTH]) {
// copy out the product key stripping out extraneous characters
const char *p = in_key;
size_t i = 0;
for (; *p; p++) {
// strip out space or dash
if (*p == ' ' || *p == '-')
continue;
// check if we've passed the product key length to avoid overflow
if (i >= PK_LENGTH)
return false;
// convert to uppercase - if character allowed, copy into array
for (int j = 0; j < strlen(PIDGEN3::pKeyCharset); j++) {
if (toupper(*p) == PIDGEN3::pKeyCharset[j]) {
out_key[i++] = toupper(*p);
continue;
}
}
}
// only return true if we've handled exactly PK_LENGTH chars
return (i == PK_LENGTH);
}
CLI::CLI(Options options, json keys) {
this->options = options;
this->keys = keys;
this->BINKID = options.binkid.c_str();
// We cannot produce a valid key without knowing the private key k. The reason for this is that
// we need the result of the function K(x; y) = kG(x; y).
this->privateKey = BN_new();
// We can, however, validate any given key using the available public key: {p, a, b, G, K}.
// genOrder the order of the generator G, a value we have to reverse -> Schoof's Algorithm.
this->genOrder = BN_new();
/* Computed data */
BN_dec2bn(&this->genOrder, this->keys["BINK"][this->BINKID]["n"]. get<std::string>().c_str());
BN_dec2bn(&this->privateKey, this->keys["BINK"][this->BINKID]["priv"].get<std::string>().c_str());
if (options.verbose) {
fmt::print("----------------------------------------------------------- \n");
fmt::print("Loaded the following elliptic curve parameters: BINK[{}]\n", this->BINKID);
fmt::print("----------------------------------------------------------- \n");
fmt::print(" P: {}\n", this->keys["BINK"][this->BINKID]["p"].get<std::string>());
fmt::print(" a: {}\n", this->keys["BINK"][this->BINKID]["a"].get<std::string>());
fmt::print(" b: {}\n", this->keys["BINK"][this->BINKID]["b"].get<std::string>());
fmt::print("Gx: {}\n", this->keys["BINK"][this->BINKID]["g"]["x"].get<std::string>());
fmt::print("Gy: {}\n", this->keys["BINK"][this->BINKID]["g"]["y"].get<std::string>());
fmt::print("Kx: {}\n", this->keys["BINK"][this->BINKID]["pub"]["x"].get<std::string>());
fmt::print("Ky: {}\n", this->keys["BINK"][this->BINKID]["pub"]["y"].get<std::string>());
fmt::print(" n: {}\n", this->keys["BINK"][this->BINKID]["n"].get<std::string>());
fmt::print(" k: {}\n", this->keys["BINK"][this->BINKID]["priv"].get<std::string>());
if (options.verbose)
{
fmt::print("{:->80}\n", "");
fmt::print("Loaded the following elliptic curve parameters: BINK[{}]\n", BINKID);
fmt::print("{:->80}\n", "");
fmt::print("{:>6}: {}\n", "P", bink["p"]);
fmt::print("{:>6}: {}\n", "a", bink["a"]);
fmt::print("{:>6}: {}\n", "b", bink["b"]);
fmt::print("{:>6}: [{},\n{:>9}{}]\n", "G[x,y]", bink["g"]["x"], "", bink["g"]["y"]);
fmt::print("{:>6}: [{},\n{:>9}{}]\n", "K[x,y]", bink["pub"]["x"], "", bink["pub"]["y"]);
fmt::print("{:>6}: {}\n", "n", bink["n"]);
fmt::print("{:>6}: {}\n", "k", bink["priv"]);
fmt::print("\n");
}
pidgen3.LoadEllipticCurve(bink["p"], bink["a"], bink["b"], bink["g"]["x"], bink["g"]["y"], bink["pub"]["x"],
bink["pub"]["y"], bink["n"], bink["priv"]);
eCurve = PIDGEN3::initializeEllipticCurve(
this->keys["BINK"][this->BINKID]["p"].get<std::string>(),
this->keys["BINK"][this->BINKID]["a"].get<std::string>(),
this->keys["BINK"][this->BINKID]["b"].get<std::string>(),
this->keys["BINK"][this->BINKID]["g"]["x"].get<std::string>(),
this->keys["BINK"][this->BINKID]["g"]["y"].get<std::string>(),
this->keys["BINK"][this->BINKID]["pub"]["x"].get<std::string>(),
this->keys["BINK"][this->BINKID]["pub"]["y"].get<std::string>(),
this->genPoint,
this->pubPoint
);
if (options.state != STATE_PIDGEN_GENERATE)
{
return true;
}
this->count = 0;
this->total = this->options.numKeys;
pidgen3.info.setChannelID(options.channelID);
if (options.verbose)
{
fmt::print("> Channel ID: {:03d}\n", options.channelID);
}
if (options.serialSet)
{
pidgen3.info.setSerial(options.serial);
if (options.verbose)
{
fmt::print("> Serial {:#09d}\n", options.serial);
}
}
return true;
}
int CLI::BINK1998Generate() {
// raw PID/serial value
DWORD nRaw = this->options.channelID * 1'000'000 ; /* <- change */
/**
*
* @param confid
* @return success
*/
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];
// using user-provided serial
if (this->options.serialSet) {
// just in case, make sure it's less than 999999
int serialRnd = (this->options.serial % 999999);
nRaw += serialRnd;
} else {
// generate a random number to use as a serial
BIGNUM *bnrand = BN_new();
BN_rand(bnrand, 19, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY);
int oRaw;
char *cRaw = BN_bn2dec(bnrand);
sscanf(cRaw, "%d", &oRaw);
nRaw += (oRaw % 999999); // ensure our serial is less than 999999
if (!keys["products"][options.productCode].contains("meta") ||
!keys["products"][options.productCode]["meta"].contains("activation"))
{
fmt::print("ERROR: product flavour {} does not have known activation values", options.productCode);
return false;
}
if (this->options.verbose) {
// print the resulting Product ID
// PID value is printed in BINK1998::Generate
printID(&nRaw);
auto meta = keys["products"][options.productCode]["meta"]["activation"];
if (!keys["activation"].contains(meta["flavour"]))
{
fmt::print("ERROR: {} is an unknown activation flavour", meta["flavour"]);
return false;
}
// generate a key
BN_sub(this->privateKey, this->genOrder, this->privateKey);
auto flavour = keys["activation"][meta["flavour"]];
// Specify whether an upgrade version or not
bool bUpgrade = false;
if (options.upgrade == true)
bUpgrade = true;
for (int i = 0; i < this->total; i++) {
PIDGEN3::BINK1998::Generate(this->eCurve, this->genPoint, this->genOrder, this->privateKey, nRaw, bUpgrade, this->pKey);
bool isValid = PIDGEN3::BINK1998::Verify(this->eCurve, this->genPoint, this->pubPoint, this->pKey);
if (isValid) {
CLI::printKey(this->pKey);
if (i < this->total - 1 || this->options.verbose) {
fmt::print("\n");
}
this->count += isValid;
}
else {
if (this->options.verbose) {
CLI::printKey(this->pKey);
fmt::print(" [Invalid]");
if (i < this->total - 1) {
fmt::print("\n");
}
}
this->total++; // queue a redo, basically
}
if (options.verbose)
{
fmt::print("{:->80}\n", "");
fmt::print("Loaded the following hyperelliptic curve parameters: activation[{}]\n", meta["flavour"]);
fmt::print("{:->80}\n", "");
fmt::print("{:>7}: {}\n", "name", flavour["name"]);
fmt::print("{:>7}: {}\n", "version", meta["version"]);
fmt::print("{:>7}: {}\n", "Fp", flavour["p"]);
fmt::print("{:>7}: [{}, {}, {},\n{:>10}{}, {}, {}]\n", "F[]", flavour["x"]["0"], flavour["x"]["1"],
flavour["x"]["2"], "", flavour["x"]["3"], flavour["x"]["4"], flavour["x"]["5"]);
fmt::print("{:>7}: {}\n", "INV", flavour["quotient"]);
fmt::print("{:>7}: {}\n", "mqnr", flavour["non_residue"]);
fmt::print("{:>7}: {}\n", "k", flavour["priv"]);
fmt::print("{:>7}: {}\n", "IID", flavour["iid_key"]);
fmt::print("\n");
}
if (this->options.verbose) {
fmt::print("\nSuccess count: {}/{}", this->count, this->total);
for (BYTE i = 0; i < 6; i++)
{
fvals[i] = BN_CTX_get(ctx);
auto xval = flavour["x"][fmt::format("{}", i)].get<std::string>();
BN_dec2bn(&fvals[i], xval.c_str());
UMSKT::BN_bn2lebin(fvals[i], (unsigned char *)&fvalsq[i], sizeof(*fvalsq));
}
#ifndef _WIN32
fmt::print("\n");
#endif
return 0;
// confid.LoadHyperellipticCurve(fvals, );
BN_CTX_free(ctx);
return false;
}
int CLI::BINK2002Generate() {
DWORD pChannelID = this->options.channelID;
/**
*
* @return success
*/
BOOL CLI::PIDGENGenerate()
{
// TODO:
// if options.pidgen2generate
// return pidgen2generate
// otherwise...
if (this->options.verbose) {
fmt::print("> Channel ID: {:03d}\n", this->options.channelID);
}
const char *BINKID = &options.binkID[0];
auto bink = keys["BINK"][BINKID];
// generate a key
for (int i = 0; i < this->total; i++) {
DWORD pAuthInfo;
RAND_bytes((BYTE *)&pAuthInfo, 4);
pAuthInfo &= BITMASK(10);
std::string key;
bink["p"].get_to(key);
if (this->options.verbose) {
fmt::print("> AuthInfo: {}\n", pAuthInfo);
if (PIDGEN3::checkFieldStrIsBink1998(key))
{
if (options.verbose)
{
fmt::print("Detected a BINK1998 key\n");
}
// Specify whether an upgrade version or not
bool bUpgrade = false;
if (options.upgrade == true)
bUpgrade = true;
PIDGEN3::BINK2002::Generate(this->eCurve, this->genPoint, this->genOrder, this->privateKey, pChannelID, pAuthInfo, bUpgrade, this->pKey);
bool isValid = PIDGEN3::BINK2002::Verify(this->eCurve, this->genPoint, this->pubPoint, this->pKey);
if (isValid) {
CLI::printKey(this->pKey);
if (i < this->total - 1 || this->options.verbose) { // check if end of list or verbose
fmt::print("\n");
}
this->count += isValid; // add to count
}
else {
if (this->options.verbose) {
CLI::printKey(this->pKey); // print the key
fmt::print(" [Invalid]"); // and add " [Invalid]" to the key
if (i < this->total - 1) { // check if end of list
fmt::print("\n");
}
}
this->total++; // queue a redo, basically
}
auto bink1998 = BINK1998();
InitPIDGEN3(bink1998);
return BINK1998Generate(bink1998);
}
if (this->options.verbose) {
fmt::print("\nSuccess count: {}/{}", this->count, this->total);
else
{
if (options.verbose)
{
fmt::print("Detected a BINK2002 key\n");
}
auto bink2002 = BINK2002();
InitPIDGEN3(bink2002);
return BINK2002Generate(bink2002);
}
#ifndef _WIN32
fmt::print("\n");
#endif
return 0;
}
int CLI::BINK1998Validate() {
char product_key[PK_LENGTH]{};
/**
*
* @return isValid
*/
BOOL CLI::PIDGENValidate()
{
// TODO:
// if options.pidgen2validate
// return pidgen2validate
// otherwise...
if (!CLI::stripKey(this->options.keyToCheck.c_str(), product_key)) {
fmt::print("ERROR: Product key is in an incorrect format!\n");
const char *BINKID = &options.binkID[0];
auto bink = keys["BINK"][BINKID];
std::string key;
bink["p"].get_to(key);
if (PIDGEN3::checkFieldStrIsBink1998(key))
{
if (options.verbose)
{
fmt::print("Detected a BINK1998 key\n");
}
auto bink1998 = BINK1998();
InitPIDGEN3(bink1998);
return BINK1998Validate(bink1998);
}
else
{
if (options.verbose)
{
fmt::print("Detected a BINK2002 key\n");
}
auto bink2002 = BINK2002();
InitPIDGEN3(bink2002);
return BINK2002Validate(bink2002);
}
}
/**
* Process application state
*
* @return application status code
*/
int CLI::Run()
{
/**
* TODO: we should be checking if the system's pseudorandom facilities work
* before attempting generation, validation does not require entropy
*/
switch (options.state)
{
case STATE_PIDGEN_GENERATE:
return PIDGENGenerate();
case STATE_PIDGEN_VALIDATE:
return PIDGENValidate();
case STATE_CONFIRMATION_ID:
return ConfirmationIDGenerate();
default:
return 1;
}
CLI::printKey(product_key);
fmt::print("\n");
if (!PIDGEN3::BINK1998::Verify(this->eCurve, this->genPoint, this->pubPoint, product_key)) {
fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n");
return 1;
}
fmt::print("Key validated successfully!\n");
return 0;
}
int CLI::BINK2002Validate() {
char product_key[PK_LENGTH]{};
/**
* Prints a product key to stdout
*
* @param pk std::string to print
*/
void CLI::printKey(std::string &pk)
{
assert(pk.length() >= PK_LENGTH);
if (!CLI::stripKey(this->options.keyToCheck.c_str(), product_key)) {
fmt::print("ERROR: Product key is in an incorrect format!\n");
return 1;
}
CLI::printKey(product_key);
fmt::print("\n");
if (!PIDGEN3::BINK2002::Verify(this->eCurve, this->genPoint, this->pubPoint, product_key)) {
fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n");
return 1;
}
fmt::print("Key validated successfully!\n");
return 0;
fmt::print("{}-{}-{}-{}-{}", pk.substr(0, 5), pk.substr(5, 5), pk.substr(10, 5), pk.substr(15, 5),
pk.substr(20, 5));
}
int CLI::ConfirmationID() {
char confirmation_id[49];
int err = ConfirmationID::Generate(this->options.instid.c_str(), confirmation_id);
switch (err) {
case ERR_TOO_SHORT:
fmt::print("ERROR: Installation ID is too short.\n");
return 1;
case ERR_TOO_LARGE:
fmt::print("ERROR: Installation ID is too long.\n");
return 1;
case ERR_INVALID_CHARACTER:
fmt::print("ERROR: Invalid character in installation ID.\n");
return 1;
case ERR_INVALID_CHECK_DIGIT:
fmt::print("ERROR: Installation ID checksum failed. Please check that it is typed correctly.\n");
return 1;
case ERR_UNKNOWN_VERSION:
fmt::print("ERROR: Unknown installation ID version.\n");
return 1;
case ERR_UNLUCKY:
fmt::print("ERROR: Unable to generate valid confirmation ID.\n");
return 1;
case SUCCESS:
fmt::print(confirmation_id);
#ifndef _WIN32
fmt::print("\n");
#endif
return 0;
default:
fmt::print("Unknown error occurred during Confirmation ID generation: {}\n", err);
/**
* std::BinaryOperation compatible accumulator for validating/stripping an input string against the PIDGEN3 charset
* this can be moved to the PIDGEN3 at a later date
*
* @param accumulator
* @param currentChar
* @return
*/
std::string CLI::validateInputKeyCharset(std::string &accumulator, char currentChar)
{
char cchar = ::toupper(currentChar);
if (std::find(std::begin(PIDGEN3::pKeyCharset), std::end(PIDGEN3::pKeyCharset), cchar) !=
std::end(PIDGEN3::pKeyCharset))
{
accumulator.push_back(cchar);
}
return 1;
return accumulator;
}
/**
*
* @param in_key
* @param out_key
* @return
*/
BOOL CLI::stripKey(const std::string &in_key, std::string &out_key)
{
// copy out the product key stripping out extraneous characters
out_key = std::accumulate(in_key.begin(), in_key.end(), std::string(), validateInputKeyCharset);
// only return true if we've handled exactly PK_LENGTH chars
return (out_key.length() == PK_LENGTH);
}

212
src/cli.h
View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,78 +16,192 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/6/2023
* @FileCreated by Neo on 06/06/2023
* @Maintainer Neo
*/
#ifndef UMSKT_CLI_H
#define UMSKT_CLI_H
#include "header.h"
#include "typedefs.h"
#include <cmrc/cmrc.hpp>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <fmt/color.h>
#include <fmt/core.h>
#include <fmt/ostream.h>
#include <fmt/ranges.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
namespace fs = std::filesystem;
// fmt <-> json linkage
template <> struct fmt::formatter<json> : ostream_formatter
{
auto format(const json &j, format_context &ctx) const
{
if (j.is_string())
{
return formatter<string_view>::format(j.get<std::string>(), ctx);
}
else
{
return basic_ostream_formatter<char>::format(j, ctx);
}
}
};
#include "help.h"
#include "libumskt/confid/confid.h"
#include "libumskt/libumskt.h"
#include "libumskt/pidgen2/PIDGEN2.h"
#include "libumskt/pidgen3/PIDGEN3.h"
#include "libumskt/pidgen3/BINK1998.h"
#include "libumskt/pidgen3/BINK2002.h"
#include "libumskt/confid/confid.h"
#include "libumskt/pidgen3/PIDGEN3.h"
CMRC_DECLARE(umskt);
#ifndef UMSKTCLI_VERSION_STRING
#define UMSKTCLI_VERSION_STRING "unknown version-dirty"
#endif
enum MODE {
MODE_BINK1998_GENERATE = 0,
MODE_BINK2002_GENERATE = 1,
MODE_CONFIRMATION_ID = 2,
MODE_BINK1998_VALIDATE = 3,
MODE_BINK2002_VALIDATE = 4,
enum APPLICATION_STATE
{
STATE_PIDGEN_GENERATE,
STATE_PIDGEN_VALIDATE,
STATE_CONFIRMATION_ID
};
struct Options {
std::string binkid;
enum PIDGEN_VERSION
{
PIDGEN_2 = 2,
PIDGEN_3 = 3,
};
struct Options
{
int argc;
char **argv;
std::string binkID;
std::string keysFilename;
std::string instid;
std::string installationID;
std::string keyToCheck;
int channelID;
int serial;
int numKeys;
bool upgrade;
bool serialSet;
bool verbose;
bool help;
bool error;
bool list;
std::string productID;
std::string authInfo;
std::string productCode;
std::string productFlavour;
MODE applicationMode;
DWORD channelID;
DWORD serial;
DWORD numKeys;
BOOL oem;
BOOL upgrade;
BOOL serialSet;
BOOL verbose;
BOOL help;
BOOL error;
BOOL list;
struct Meta
{
std::string type;
std::vector<std::string> tags;
struct Activation
{
std::string flavour;
int version;
};
};
PIDGEN3::KeyInfo info;
PIDGEN_VERSION pidgenversion;
APPLICATION_STATE state;
};
class CLI {
Options options;
json keys;
const char* BINKID;
BIGNUM *privateKey, *genOrder;
EC_POINT *genPoint, *pubPoint;
EC_GROUP *eCurve;
char pKey[25];
int count, total;
class CLI
{
std::string pKey;
DWORD count, total, iBinkID;
public:
CLI(Options options, json keys);
static Options options;
static bool loadJSON(const fs::path& filename, json *output);
static void showHelp(char *argv[]);
static int parseCommandLine(int argc, char* argv[], Options *options);
static int validateCommandLine(Options* options, char *argv[], json *keys);
public:
CLI()
{
count = 0;
total = options.numKeys;
}
static std::array<CLIHelpOptions, CLIHelpOptionID_END> helpOptions;
static json keys;
static BYTE Init(int argv, char *argc[]);
static void SetHelpText();
static BOOL loadJSON(const fs::path &filename);
static BOOL loadEmbeddedJSON();
static CLIHandlerFunc DisplayHelp;
static CLIHandlerFunc DisplayErrorMessage;
static CLIHandlerFunc SetVerboseOption;
static CLIHandlerFunc SetDebugOption;
static CLIHandlerFunc SetListOption;
static CLIHandlerFunc SetOEMOption;
static CLIHandlerFunc SetUpgradeOption;
static CLIHandlerFunc SetFileOption;
static CLIHandlerFunc SetNumberOption;
static CLIHandlerFunc SetChannelIDOption;
static CLIHandlerFunc SetBINKOption;
static CLIHandlerFunc SetSerialOption;
static CLIHandlerFunc SetActivationIDOption;
static CLIHandlerFunc SetProductIDOption;
static CLIHandlerFunc SetValidateOption;
static CLIHandlerFunc SetProductCodeOption;
static CLIHandlerFunc SetFlavourOption;
static BOOL parseCommandLine();
static BOOL processOptions();
static void printID(DWORD *pid);
static void printKey(char *pk);
static bool stripKey(const char *in_key, char out_key[PK_LENGTH]);
static void printKey(std::string &pk);
static BOOL stripKey(const std::string &in_key, std::string &out_key);
static std::string validateInputKeyCharset(std::string &accumulator, char currentChar);
int BINK1998Generate();
int BINK2002Generate();
int BINK1998Validate();
int BINK2002Validate();
int ConfirmationID();
BOOL InitPIDGEN3(PIDGEN3 &pidgen3);
BOOL InitConfirmationID(ConfirmationID &confid);
BOOL PIDGENGenerate();
BOOL PIDGENValidate();
BOOL PIDGEN2Generate(PIDGEN2 &pidgen2);
BOOL PIDGEN2Validate(PIDGEN2 &pidgen2);
BOOL BINK1998Generate(PIDGEN3 &pidgen3);
BOOL BINK1998Validate(PIDGEN3 &pidgen3);
BOOL BINK2002Generate(PIDGEN3 &pidgen3);
BOOL BINK2002Validate(PIDGEN3 &pidgen3);
BOOL ConfirmationIDGenerate();
INLINE static std::string strtolower(std::string &in)
{
auto retval = std::string(in);
std::transform(retval.begin(), retval.end(), retval.begin(), ::tolower);
return retval;
}
INLINE static std::string strtoupper(std::string &in)
{
auto retval = std::string(in);
std::transform(retval.begin(), retval.end(), retval.begin(), ::toupper);
return retval;
}
int Run();
};
#endif //UMSKT_CLI_H
#endif // UMSKT_CLI_H

271
src/generate.cpp Normal file
View File

@ -0,0 +1,271 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 01/05/2024
* @Maintainer Neo
*/
#include "cli.h"
/**
*
* @param pidgen2
* @return success
*/
BOOL CLI::PIDGEN2Generate(PIDGEN2 &pidgen2)
{
return true;
}
/**
*
* @param pidgen2
* @return success
*/
BOOL CLI::PIDGEN2Validate(PIDGEN2 &pidgen2)
{
return true;
}
/**
*
* @return success
*/
BOOL CLI::BINK1998Generate(PIDGEN3 &pidgen3)
{
// raw PID/serial value
DWORD nRaw = options.channelID * 1'000'000;
DWORD serialRnd;
if (options.serialSet)
{
// using user-provided serial
serialRnd = options.serial;
}
else
{
// generate a random number to use as a serial
serialRnd = UMSKT::getRandom<DWORD>();
}
// make sure it's less than 999999
nRaw += (serialRnd % 999999);
if (options.verbose)
{
// print the resulting Product ID
// PID value is printed in BINK1998::Generate
printID(&nRaw);
}
for (int i = 0; i < total; i++)
{
pidgen3.info.setSerial(nRaw);
pidgen3.Generate(pKey);
bool isValid = pidgen3.Validate(pKey);
if (isValid)
{
printKey(pKey);
if (i <= total - 1 || options.verbose)
{
fmt::print("\n");
}
count += isValid;
}
else
{
if (options.verbose)
{
printKey(pKey);
fmt::print(" [Invalid]");
if (i <= total - 1)
{
fmt::print("\n");
}
}
total++; // queue a redo, basically
}
}
if (options.verbose)
{
fmt::print("\nSuccess count: {}/{}\n", count, total);
}
return true;
}
/**
*
* @return success
*/
BOOL CLI::BINK1998Validate(PIDGEN3 &bink1998)
{
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 (!bink1998.Validate(product_key))
{
fmt::print("ERROR: Product key is invalid! Wrong BINK ID?\n");
return false;
}
fmt::print("Key validated successfully!\n");
return true;
}
/**
*
* @return success
*/
BOOL CLI::BINK2002Generate(PIDGEN3 &pidgen3)
{
// generate a key
for (int i = 0; i < total; i++)
{
pidgen3.info.AuthInfo = UMSKT::getRandom<DWORD>() & BITMASK(10);
if (options.verbose)
{
fmt::print("> AuthInfo: {:#08x}\n", pidgen3.info.AuthInfo);
}
pidgen3.Generate(pKey);
bool isValid = pidgen3.Validate(pKey);
if (isValid)
{
CLI::printKey(pKey);
if (i <= total - 1 || options.verbose)
{ // check if end of list or verbose
fmt::print("\n");
}
count += isValid; // add to count
}
else
{
if (options.verbose)
{
CLI::printKey(pKey); // print the key
fmt::print(" [Invalid]"); // and add " [Invalid]" to the key
if (i <= total - 1)
{ // check if end of list
fmt::print("\n");
}
}
total++; // queue a redo, basically
}
}
if (options.verbose)
{
fmt::print("\nSuccess count: {}/{}\n", count, total);
}
return true;
}
/**
*
* @return success
*/
BOOL CLI::BINK2002Validate(PIDGEN3 &pidgen3)
{
std::string product_key;
if (!CLI::stripKey(options.keyToCheck, product_key))
{
fmt::print("ERROR: Product key is in an incorrect format!\n");
return false;
}
CLI::printKey(product_key);
fmt::print("\n");
if (!pidgen3.Validate(product_key))
{
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::ConfirmationIDGenerate()
{
auto confid = ConfirmationID();
std::string confirmation_id;
if (!InitConfirmationID(confid))
{
return false;
}
DWORD err = confid.Generate(options.installationID, confirmation_id, options.productID);
if (err == SUCCESS)
{
fmt::print("{}\n", confirmation_id);
return true;
}
switch (err)
{
case ERR_TOO_SHORT:
fmt::print("ERROR: Installation ID is too short.\n");
break;
case ERR_TOO_LARGE:
fmt::print("ERROR: Installation ID is too long.\n");
break;
case ERR_INVALID_CHARACTER:
fmt::print("ERROR: Invalid character in installation ID.\n");
break;
case ERR_INVALID_CHECK_DIGIT:
fmt::print("ERROR: Installation ID checksum failed. Please check that it is typed correctly.\n");
break;
case ERR_UNKNOWN_VERSION:
fmt::print("ERROR: Unknown installation ID version.\n");
break;
case ERR_UNLUCKY:
fmt::print("ERROR: Unable to generate valid confirmation ID.\n");
break;
default:
fmt::print("Unknown error occurred during Confirmation ID generation: {}\n", err);
break;
}
return false;
}

595
src/help.cpp Normal file
View File

@ -0,0 +1,595 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 01/02/2024
* @Maintainer Neo
*/
#include "cli.h"
// define static storage
std::array<CLIHelpOptions, CLIHelpOptionID_END> CLI::helpOptions;
void CLI::SetHelpText()
{
helpOptions[OPTION_HELP] = {"h", "help", "show this help text", false, "", &DisplayHelp};
helpOptions[OPTION_HELP2] = {"?", "", "show this help text", false, "", &DisplayHelp};
helpOptions[OPTION_VERSION] = {"", "version", "show UMSKT CLI / libumskt versions", false, "", nullptr};
helpOptions[OPTION_VERBOSE] = {"v", "verbose", "enable verbose output", false, "", &SetVerboseOption};
helpOptions[OPTION_DEBUG] = {"d", "debug", "enable debug output", false, "", &SetDebugOption};
helpOptions[OPTION_FILE] = {
"F", "file", "(advanced) specify which keys JSON file to load", true, "[embedded file]", &SetFileOption};
helpOptions[OPTION_LIST] = {"l", "list", "list supported products", false, "", &SetListOption};
helpOptions[OPTION_PRODUCT] = {"p", "product", "[REQUIRED] which product to generate keys for",
true, options.productCode, &SetProductCodeOption};
helpOptions[OPTION_FLAVOUR] = {
"f", "flavour", "which product flavour to generate keys for (required in some instances)",
true, "", &SetFlavourOption};
helpOptions[OPTION_NUMBER] = {"n", "number", "(PIDGEN only) number of keys to generate",
true, "1", &SetNumberOption};
helpOptions[OPTION_ACTIVATIONID] = {
"i", "installationID", "(activation only) installation ID used to generate confirmation ID", true,
"", &SetActivationIDOption};
helpOptions[OPTION_ACTIVATIONPID] = {
"P", "productID", "(Office activation only) product ID to generate confirmation ID for",
true, "", &SetProductIDOption};
helpOptions[OPTION_OEM] = {"O", "oem", "(PIDGEN) generate an OEM key", false, "", &SetOEMOption};
helpOptions[OPTION_UPGRADE] = {"U", "upgrade", "(PIDGEN 3 only) generate an upgrade key",
false, "", &SetUpgradeOption};
helpOptions[OPTION_BINK] = {"b", "binkID", "(advanced) override which BINK identifier to load",
true, "", &SetBINKOption};
helpOptions[OPTION_CHANNELID] = {"c", "channelid", "(advanced) override which product channel to use",
true, "", &SetChannelIDOption};
helpOptions[OPTION_SERIAL] = {
"s", "serial", "(advanced, PIDGEN 2/3 [BINK 1998] only) specify a serial to generate",
true, "", &SetSerialOption};
helpOptions[OPTION_AUTHDATA] = {
"a", "authdata", "(advanced, PIDGEN 3 [BINK 2002] only) specify a value for the authentication data field",
true, "", nullptr};
helpOptions[OPTION_VALIDATE] = {
"V", "validate", "validate a specified product ID against known BINKs and algorithms",
true, "", &SetValidateOption};
}
/**
*
* @return success
*/
BOOL CLI::parseCommandLine()
{
for (DWORD i = 1; i < options.argc; i++)
{
std::string arg = options.argv[i];
if (arg[0] == '-' || arg[0] == '/')
{
arg.erase(0, 1 + (arg[1] == '-' ? 1 : 0));
}
if (arg.empty())
{
continue;
}
for (BYTE j = 0; j < CLIHelpOptionID_END; j++)
{
auto thisOption = helpOptions[j];
if (arg != thisOption.Short && arg != thisOption.Long)
{
continue;
}
std::string nextarg;
if (thisOption.hasArguments)
{
if (i == options.argc - 1)
{
options.error = true;
goto CommandLineParseEnd;
}
else
{
i++;
nextarg = std::string(options.argv[i]);
}
}
if (thisOption.handler == nullptr)
{
// prevent accidental segmentation faults
continue;
}
auto success = thisOption.handler(1, &nextarg[0]);
if (!success)
{
options.error = true;
goto CommandLineParseEnd;
}
if (options.help)
{
goto CommandLineParseEnd;
}
goto ParseNextCommandLineOption;
}
fmt::print("unknown option: {}\n", arg);
options.error = true;
goto CommandLineParseEnd;
ParseNextCommandLineOption:
continue;
}
CommandLineParseEnd:
if (options.error)
{
DisplayErrorMessage(0, nullptr);
}
return !options.error;
}
/**
*
* @return success
*/
BOOL CLI::processOptions()
{
if (!loadJSON(options.keysFilename))
{
options.error = true;
return false;
}
if (options.list)
{
// the following code is absolutely unhinged
// I'm so sorry
#if defined(__UNICODE__) || defined(__GNUC__)
auto *leaf = "\u251C", *last = "\u2514", *line = "\u2500";
#else
auto *leaf = "\xC3", *last = "\xC0", *line = "\xC4";
#endif
fmt::print("Listing known products and flavours: \n\n");
fmt::print("* The following product list uses this style of formatting:\n");
fmt::print("{}: {} \n", fmt::styled("PRODUCT", fmt::emphasis::bold), "Product name");
fmt::print("{}{}{} {}: {} \n", last, line, line, "FLAVOUR", "Flavour name");
fmt::print("* Products that require a flavour are noted with {}\n\n",
fmt::styled("(no default)", fmt::emphasis::bold));
for (auto const &i : keys["products"].items())
{
auto el = i.value();
auto containsFlavours = el.contains("flavours");
fmt::print("{:<9} {} ", fmt::styled(fmt::format("{}:", i.key()), fmt::emphasis::bold), el["name"]);
if (el.contains("BINK"))
{
fmt::print("{}\n", el["BINK"]);
}
else if (el["meta"].contains("default"))
{
fmt::print("(default: {} {})\n", fmt::styled(el["meta"]["default"], fmt::emphasis::bold),
el["flavours"][el["meta"]["default"]]["BINK"]);
}
else if (el["meta"]["type"].get<std::string>() == "PIDGEN3")
{
fmt::print("[{}]\n", el["meta"]["type"]);
}
else
{
fmt::print("{}\n", fmt::styled("(no default)", fmt::emphasis::bold));
}
if (containsFlavours)
{
auto flavours = el["flavours"];
for (auto j = flavours.begin(); j != flavours.end(); j++)
{
auto el2 = j.value();
BOOL isLast = j == --flavours.end();
fmt::print("{}{}{} {:<9} {} ", !isLast ? leaf : last, line, line, fmt::format("{}:", j.key()),
fmt::format("{} {}", el["name"], el2["name"]));
if (el2.contains("meta") && el2["meta"].contains("type"))
{
fmt::print("[{}]\n", el2["meta"]["type"]);
}
else
{
fmt::print("{}\n", el2["BINK"]);
}
}
}
fmt::print("\n");
}
return false;
}
if (options.productCode.empty())
{
fmt::print("ERROR: product code is required. Exiting...");
DisplayHelp(0, nullptr);
return false;
}
const char *productCode = &options.productCode[0];
if (!keys["products"].contains(productCode))
{
fmt::print("ERROR: Product {} is unknown", productCode);
return false;
}
auto product = keys["products"][productCode];
if (options.verbose)
{
fmt::print("Selecting product: {}\n", productCode);
}
json flavour;
if (product.contains("flavours"))
{
flavour = product["flavours"][options.productFlavour];
if (options.verbose)
{
fmt::print("Selecting flavour: {}\n", options.productFlavour);
}
}
else
{
flavour = product;
}
if (options.state != STATE_PIDGEN_GENERATE && options.state != STATE_PIDGEN_VALIDATE)
{
// exit early if we're not doing PIDGEN
goto processOptionsExitEarly;
}
if (options.oem)
{
flavour["BINK"][1].get_to(options.binkID);
}
else
{
flavour["BINK"][0].get_to(options.binkID);
}
if (options.verbose)
{
fmt::print("Selected BINK: {}\n", options.binkID);
}
if (options.state != STATE_PIDGEN_GENERATE)
{
// exit early if we're only validating
goto processOptionsExitEarly;
}
if (flavour.contains("DPC") && flavour["DPC"].contains(options.binkID) && options.channelID == 0)
{
std::vector<json> filtered;
for (auto const &i : flavour["DPC"][options.binkID].items())
{
auto el = i.value();
if (!el["isEvaluation"].get<bool>())
{
filtered.emplace_back(el);
}
}
// roll a die to choose which DPC entry to pick
auto rand = UMSKT::getRandom<BYTE>();
auto dpc = filtered[rand % filtered.size()];
auto min = dpc["min"].get<WORD>(), max = dpc["max"].get<WORD>();
if (min == max)
{
options.channelID = min;
}
else
{
options.channelID = min + (rand % (max - min));
}
if (options.verbose)
{
fmt::print("Selected channel ID: {} (DPC entry {}/{})\n", options.channelID, rand % filtered.size(),
filtered.size());
}
}
if (options.channelID == 0)
{
options.channelID = UMSKT::getRandom<WORD>() % 999;
if (options.verbose)
{
fmt::print("Generated channel ID: {}\n", options.channelID);
}
}
// FE and FF are BINK 1998, but use a different, currently unhandled encoding scheme, we return an error here
if (options.binkID == "FE" || options.binkID == "FF")
{
fmt::print("ERROR: Terminal Services BINKs (FE and FF) are unsupported at this time\n");
return false;
}
processOptionsExitEarly:
if (options.verbose)
{
fmt::print("\n");
}
return true;
}
/**
*
* @return success
*/
BOOL CLI::DisplayHelp(int, char *)
{
options.help = true;
fmt::print("usage: {} \n", options.argv[0]);
for (BYTE i = 0; i < CLIHelpOptionID_END; i++)
{
CLIHelpOptions o = helpOptions[i];
if (o.Short.empty())
{
fmt::print("\t{:>2} --{:<15} {}", "", o.Long, o.HelpText);
}
else if (o.Long.empty())
{
fmt::print("\t-{} {:<15} {}", o.Short, "", o.HelpText);
}
else
{
fmt::print("\t-{} --{:<15} {}", o.Short, o.Long, o.HelpText);
}
if (!o.Default.empty())
{
fmt::print(" (defaults to {})", o.Default);
}
fmt::print("\n");
}
fmt::print("\n");
return true;
}
BOOL CLI::DisplayErrorMessage(int, char *)
{
fmt::print("Error parsing command line options\n");
DisplayHelp(0, nullptr);
options.error = true;
return false;
}
BOOL CLI::SetVerboseOption(int, char *)
{
fmt::print("Enabling verbose option\n\n");
options.verbose = true;
UMSKT::VERBOSE = true;
UMSKT::setDebugOutput(stderr);
return true;
}
BOOL CLI::SetDebugOption(int, char *)
{
fmt::print("Enabling debug option\n");
options.verbose = true;
UMSKT::DEBUG = true;
UMSKT::setDebugOutput(stderr);
return true;
}
BOOL CLI::SetListOption(int, char *)
{
if (options.verbose)
{
fmt::print("Setting list option\n");
}
options.list = true;
return true;
}
BOOL CLI::SetOEMOption(int, char *)
{
if (options.verbose)
{
fmt::print("Setting oem option\n");
}
options.oem = true;
return true;
}
BOOL CLI::SetUpgradeOption(int, char *)
{
if (options.verbose)
{
fmt::print("Setting upgrade option\n");
}
options.upgrade = true;
return true;
}
BOOL CLI::SetFileOption(int count, char *file)
{
if (options.verbose)
{
fmt::print("Setting file option to: {}\n", file);
}
options.keysFilename = file;
return true;
}
BOOL CLI::SetNumberOption(int count, char *num)
{
int nKeys;
if (!_sscanf(num, "%d", &nKeys))
{
return false;
}
if (options.verbose)
{
fmt::print("Setting generation number option to: {}\n", num);
}
options.numKeys = nKeys;
return true;
}
/**
*
* @param count
* @param channum
* @return
*/
BOOL CLI::SetChannelIDOption(int count, char *channum)
{
int siteID;
if (!_sscanf(channum, "%d", &siteID))
{
return false;
}
// channel ids must be between 000 and 999
if (siteID > 999)
{
fmt::print("ERROR: refusing to create a key with a Channel ID greater than 999\n");
return false;
}
if (options.verbose)
{
fmt::print("Setting channel number option to: {}\n", siteID);
}
options.channelID = siteID;
return true;
}
BOOL CLI::SetBINKOption(int count, char *bink)
{
auto strbinkid = std::string(bink);
options.binkID = strtoupper(strbinkid);
if (options.verbose)
{
fmt::print("Setting BINK option to {}\n", strbinkid);
}
return true;
}
BOOL CLI::SetFlavourOption(int count, char *flavour)
{
if (options.verbose)
{
fmt::print("Setting flavour option to {}\n", flavour);
}
options.productFlavour = flavour;
return true;
}
/**
*
* @param count
* @param arg
* @return
*/
BOOL CLI::SetSerialOption(int count, char *arg)
{
int serial_val;
if (!_sscanf(arg, "%d", &serial_val))
{
return false;
}
// serials must be between 000000 and 999999
if (serial_val > 999999)
{
fmt::print("ERROR: refusing to create a key with a Serial not between 000000 and 999999\n");
return false;
}
options.serialSet = true;
options.serial = serial_val;
return true;
}
BOOL CLI::SetActivationIDOption(int count, char *aid)
{
options.installationID = aid;
options.state = STATE_CONFIRMATION_ID;
return true;
}
BOOL CLI::SetProductIDOption(int count, char *product)
{
if (options.verbose)
{
fmt::print("Setting product ID to {}", product);
}
options.productID = product;
return true;
}
BOOL CLI::SetValidateOption(int count, char *productID)
{
options.keyToCheck = productID;
options.state = STATE_PIDGEN_VALIDATE;
return true;
}
BOOL CLI::SetProductCodeOption(int, char *product)
{
if (options.verbose)
{
fmt::print("Setting product code to {}\n", product);
}
auto strProduct = std::string(product);
options.productCode = strtoupper(strProduct);
return true;
}

63
src/help.h Normal file
View File

@ -0,0 +1,63 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 01/02/2024
* @Maintainer Neo
*/
#ifndef UMSKT_HELP_H
#define UMSKT_HELP_H
typedef BOOL CLIHandlerFunc(int, char *);
enum CLIHelpOptionIDs
{
OPTION_HELP,
OPTION_HELP2,
OPTION_VERSION,
OPTION_VERBOSE,
OPTION_DEBUG,
OPTION_FILE,
OPTION_LIST,
OPTION_PRODUCT,
OPTION_FLAVOUR,
OPTION_NUMBER,
OPTION_OEM,
OPTION_UPGRADE,
OPTION_ACTIVATIONID,
OPTION_ACTIVATIONPID,
OPTION_BINK,
OPTION_CHANNELID,
OPTION_SERIAL,
OPTION_AUTHDATA,
OPTION_VALIDATE,
CLIHelpOptionID_END
};
struct CLIHelpOptions
{
std::string Short;
std::string Long;
std::string HelpText;
BOOL hasArguments;
std::string Default;
CLIHandlerFunc *handler;
};
#endif // UMSKT_HELP_H

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/6/2023
* @FileCreated by Neo on 06/06/2023
* @Maintainer Neo
*/
@ -26,46 +26,128 @@
#include "../libumskt.h"
// Confirmation ID generator constants
#define SUCCESS 0
#define ERR_TOO_SHORT 1
#define ERR_TOO_LARGE 2
#define ERR_INVALID_CHARACTER 3
#define ERR_INVALID_CHECK_DIGIT 4
#define ERR_UNKNOWN_VERSION 5
#define ERR_UNLUCKY 6
enum CONFIRMATION_ID_STATUS
{
SUCCESS = 0,
ERR_TOO_SHORT = 1,
ERR_TOO_LARGE = 2,
ERR_INVALID_CHARACTER = 3,
ERR_INVALID_CHECK_DIGIT = 4,
ERR_UNKNOWN_VERSION = 5,
ERR_UNLUCKY = 6
};
#define BAD 0xFFFFFFFFFFFFFFFFull
typedef struct {
typedef struct
{
QWORD u[2];
QWORD v[2];
} TDivisor;
EXPORT class ConfirmationID {
static QWORD residue_add(QWORD x, QWORD y);
static QWORD residue_sub(QWORD x, QWORD y);
static QWORD __umul128(QWORD a, QWORD b, QWORD* hi);
static QWORD ui128_quotient_mod(QWORD lo, QWORD hi);
static QWORD residue_mul(QWORD x, QWORD y);
static QWORD residue_pow(QWORD x, QWORD y);
static QWORD inverse(QWORD u, QWORD v);
static QWORD residue_inv(QWORD x);
static QWORD residue_sqrt(QWORD what);
static int find_divisor_v(TDivisor* d);
static int polynomial_mul(int adeg, const QWORD a[], int bdeg, const QWORD b[], int resultprevdeg, QWORD result[]);
static int polynomial_div_monic(int adeg, QWORD a[], int bdeg, const QWORD b[], QWORD* quotient);
static void polynomial_xgcd(int adeg, const QWORD a[3], int bdeg, const QWORD b[3], int* pgcddeg, QWORD gcd[3], int* pmult1deg, QWORD mult1[3], int* pmult2deg, QWORD mult2[3]);
static int u2poly(const TDivisor* src, QWORD polyu[3], QWORD polyv[2]);
static void divisor_add(const TDivisor* src1, const TDivisor* src2, TDivisor* dst);
static void divisor_mul(const TDivisor* src, QWORD mult, TDivisor* dst);
static void divisor_mul128(const TDivisor* src, QWORD mult_lo, QWORD mult_hi, TDivisor* dst);
static unsigned rol(unsigned x, int shift);
static void sha1_single_block(unsigned char input[64], unsigned char output[20]);
static void Mix(unsigned char* buffer, size_t bufSize, const unsigned char* key, size_t keySize);
static void Unmix(unsigned char* buffer, size_t bufSize, const unsigned char* key, size_t keySize);
class EXPORT ConfirmationID
{
QWORD MOD = 0, NON_RESIDUE = 0;
QWORD curve[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
Q_OWORD privateKey;
public:
static int Generate(const char* installation_id_str, char confirmation_id[49]);
//EXPORT static int CLIRun();
BYTE iid_key[4] = {0x0, 0x0, 0x0, 0x0};
BOOL isOffice = false, isXPBrand = false;
unsigned flagVersion = 0;
DWORD calculateCheckDigit(DWORD pid);
void decode_iid_new_version(BYTE *iid, BYTE *hwid, DWORD *version);
void Mix(BYTE *buffer, BYTE bufSize, const BYTE *key, BYTE keySize);
void Unmix(BYTE *buffer, BYTE bufSize, const BYTE *key, BYTE keySize);
class Divisor
{
ConfirmationID *parent;
public:
explicit Divisor(ConfirmationID *p)
{
parent = p;
}
int find_divisor_v(TDivisor *d);
void add(const TDivisor *src1, const TDivisor *src2, TDivisor *dst);
void mul(const TDivisor *src, QWORD mult, TDivisor *dst);
void mul128(const TDivisor *src, QWORD mult_lo, QWORD mult_hi, TDivisor *dst);
int u2poly(const TDivisor *src, QWORD polyu[3], QWORD polyv[2]);
};
friend class Divisor;
class Residue
{
ConfirmationID *parent;
public:
explicit Residue(ConfirmationID *p)
{
parent = p;
}
QWORD add(QWORD x, QWORD y);
QWORD sub(QWORD x, QWORD y);
QWORD __umul128(QWORD a, QWORD b, QWORD *hi);
QWORD ui128_quotient_mod(QWORD lo, QWORD hi);
QWORD mul(QWORD x, QWORD y);
QWORD pow(QWORD x, QWORD y);
QWORD inverse(QWORD u, QWORD v);
QWORD inv(QWORD x);
QWORD sqrt(QWORD what);
};
friend class Residue;
class Polynomial
{
ConfirmationID *parent;
public:
explicit Polynomial(ConfirmationID *p)
{
parent = p;
}
int mul(int adeg, const QWORD a[], int bdeg, const QWORD b[], int resultprevdeg, QWORD result[]);
int div_monic(int adeg, QWORD a[], int bdeg, const QWORD b[], QWORD *quotient);
void xgcd(int adeg, const QWORD a[3], int bdeg, const QWORD b[3], int *pgcddeg, QWORD gcd[3], int *pmult1deg,
QWORD mult1[3], int *pmult2deg, QWORD mult2[3]);
};
friend class Polynomial;
Residue *residue;
Polynomial *polynomial;
Divisor *divisor;
public:
ConfirmationID()
{
residue = new Residue(this);
polynomial = new Polynomial(this);
divisor = new Divisor(this);
privateKey.qword[0] = privateKey.qword[1] = 0x00;
}
BOOL LoadHyperellipticCurve(const std::string &x0, const std::string &x1, const std::string &x2,
const std::string &x3, const std::string &x4, const std::string &x5,
const std::string &priv, const std::string &modulous, const std::string &nonresidue,
BOOL isOffice, BOOL isXPBrand, BYTE flagVersion);
BOOL LoadHyperellipticCurve(QWORD x0, QWORD x1, QWORD x2, QWORD x3, QWORD x4, QWORD x5, Q_OWORD priv,
QWORD modulous, QWORD nonresidue, BOOL isOffice, BOOL isXPBrand, BYTE flagVersion);
BOOL LoadHyperellipticCurve(QWORD *f, Q_OWORD priv, QWORD modulous, QWORD nonresidue, BOOL isOffice, BOOL isXPBrand,
BYTE flagVersion);
CONFIRMATION_ID_STATUS Generate(const std::string &installation_id_str, std::string &confirmation_id,
std::string &productid);
~ConfirmationID()
{
delete residue, polynomial, divisor;
}
};
#endif //UMSKT_CONFID_H
#endif // UMSKT_CONFID_H

View File

@ -0,0 +1,397 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 12/05/2023
* @Maintainer Neo
*/
#include "confid.h"
/**
*
* @param d
* @return
*/
int ConfirmationID::ConfirmationID::Divisor::find_divisor_v(TDivisor *d)
{
// u | v^2 - curve
// u = u0 + u1*x + x^2
// curve%u = f0 + f1*x
QWORD v1, f2[6];
for (BYTE i = 0; i < 6; i++)
{
f2[i] = parent->curve[i];
}
const QWORD u0 = d->u[0], u1 = d->u[1];
for (BYTE j = 4; j--;)
{
f2[j] = parent->residue->sub(f2[j], parent->residue->mul(u0, f2[j + 2]));
f2[j + 1] = parent->residue->sub(f2[j + 1], parent->residue->mul(u1, f2[j + 2]));
f2[j + 2] = 0;
}
// v = v0 + v1*x
// u | (v0^2 - f0) + (2*v0*v1 - f1)*x + v1^2*x^2 = u0*v1^2 + u1*v1^2*x + v1^2*x^2
// v0^2 - f0 = u0*v1^2
// 2*v0*v1 - f1 = u1*v1^2
// v0^2 = f0 + u0*v1^2 = (f1 + u1*v1^2)^2 / (2*v1)^2
// (f1^2) + 2*(f1*u1-2*f0) * v1^2 + (u1^2-4*u0) * v1^4 = 0
// v1^2 = ((2*f0-f1*u1) +- 2*sqrt(-f0*f1*u1 + f0^2 + f1^2*u0))) / (u1^2-4*u0)
const QWORD f0 = f2[0], f1 = f2[1];
const QWORD u0double = parent->residue->add(u0, u0);
const QWORD coeff2 = parent->residue->sub(parent->residue->mul(u1, u1), parent->residue->add(u0double, u0double));
const QWORD coeff1 = parent->residue->sub(parent->residue->add(f0, f0), parent->residue->mul(f1, u1));
if (coeff2 == 0)
{
if (coeff1 == 0)
{
if (f1 == 0)
{
// impossible
// printf("bad curve(), double root detected\n");
}
return 0;
}
QWORD sqr = parent->residue->mul(parent->residue->mul(f1, f1),
parent->residue->inv(parent->residue->add(coeff1, coeff1)));
v1 = parent->residue->sqrt(sqr);
if (v1 == BAD)
{
return 0;
}
}
else
{
QWORD d = parent->residue->add(
parent->residue->mul(f0, f0),
parent->residue->mul(f1, parent->residue->sub(parent->residue->mul(f1, u0), parent->residue->mul(f0, u1))));
d = parent->residue->sqrt(d);
if (d == BAD)
{
return 0;
}
d = parent->residue->add(d, d);
QWORD inv = parent->residue->inv(coeff2);
QWORD root = parent->residue->mul(parent->residue->add(coeff1, d), inv);
v1 = parent->residue->sqrt(root);
if (v1 == BAD)
{
root = parent->residue->mul(parent->residue->sub(coeff1, d), inv);
v1 = parent->residue->sqrt(root);
if (v1 == BAD)
{
return 0;
}
}
}
QWORD v0 = parent->residue->mul(parent->residue->add(f1, parent->residue->mul(u1, parent->residue->mul(v1, v1))),
parent->residue->inv(parent->residue->add(v1, v1)));
d->v[0] = v0;
d->v[1] = v1;
return 1;
}
/**
*
* @param src
* @param polyu
* @param polyv
* @return
*/
int ConfirmationID::ConfirmationID::Divisor::u2poly(const TDivisor *src, QWORD polyu[3], QWORD polyv[2])
{
if (src->u[1] != BAD)
{
polyu[0] = src->u[0];
polyu[1] = src->u[1];
polyu[2] = 1;
polyv[0] = src->v[0];
polyv[1] = src->v[1];
return 2;
}
if (src->u[0] != BAD)
{
polyu[0] = src->u[0];
polyu[1] = 1;
polyv[0] = src->v[0];
polyv[1] = 0;
return 1;
}
polyu[0] = 1;
polyv[0] = 0;
polyv[1] = 0;
return 0;
}
/**
*
* @param src1
* @param src2
* @param dst
*/
void ConfirmationID::Divisor::add(const TDivisor *src1, const TDivisor *src2, TDivisor *dst)
{
QWORD u1[3], u2[3], v1[2], v2[2];
int u1deg = u2poly(src1, u1, v1);
int u2deg = u2poly(src2, u2, v2);
// extended gcd: d1 = gcd(u1, u2) = e1*u1 + e2*u2
int d1deg, e1deg, e2deg;
QWORD d1[3], e1[3], e2[3];
parent->polynomial->xgcd(u1deg, u1, u2deg, u2, &d1deg, d1, &e1deg, e1, &e2deg, e2);
assert(e1deg <= 1);
assert(e2deg <= 1);
// extended gcd again: d = gcd(d1, v1+v2) = c1*d1 + c2*(v1+v2)
QWORD b[3] = {parent->residue->add(v1[0], v2[0]), parent->residue->add(v1[1], v2[1]), 0};
int bdeg = (b[1] == 0 ? (b[0] == 0 ? -1 : 0) : 1);
int ddeg, c1deg, c2deg;
QWORD d[3], c1[3], c2[3];
parent->polynomial->xgcd(d1deg, d1, bdeg, b, &ddeg, d, &c1deg, c1, &c2deg, c2);
assert(c1deg <= 0);
assert(c2deg <= 1);
assert(ddeg >= 0);
QWORD dmult = parent->residue->inv(d[ddeg]);
int i;
for (i = 0; i < ddeg; i++)
{
d[i] = parent->residue->mul(d[i], dmult);
}
d[i] = 1;
for (i = 0; i <= c1deg; i++)
{
c1[i] = parent->residue->mul(c1[i], dmult);
}
for (i = 0; i <= c2deg; i++)
{
c2[i] = parent->residue->mul(c2[i], dmult);
}
QWORD u[5];
int udeg = parent->polynomial->mul(u1deg, u1, u2deg, u2, -1, u);
// u is monic
QWORD v[7], tmp[7];
int vdeg, tmpdeg;
// c1*(e1*u1*v2 + e2*u2*v1) + c2*(v1*v2 + curve)
// c1*(e1*u1*(v2-v1) + d1*v1) + c2*(v1*v2 + curve)
v[0] = parent->residue->sub(v2[0], v1[0]);
v[1] = parent->residue->sub(v2[1], v1[1]);
tmpdeg = parent->polynomial->mul(e1deg, e1, 1, v, -1, tmp);
vdeg = parent->polynomial->mul(u1deg, u1, tmpdeg, tmp, -1, v);
vdeg = parent->polynomial->mul(d1deg, d1, 1, v1, vdeg, v);
for (i = 0; i <= vdeg; i++)
{
v[i] = parent->residue->mul(v[i], c1[0]);
}
memcpy(tmp, parent->curve, 6 * sizeof(parent->curve[0]));
tmpdeg = 5;
tmpdeg = parent->polynomial->mul(1, v1, 1, v2, tmpdeg, tmp);
vdeg = parent->polynomial->mul(c2deg, c2, tmpdeg, tmp, vdeg, v);
if (ddeg > 0)
{
assert(udeg >= 2 * ddeg);
QWORD udiv[5];
parent->polynomial->div_monic(udeg, u, ddeg, d, udiv);
udeg -= ddeg;
parent->polynomial->div_monic(udeg, udiv, ddeg, d, u);
udeg -= ddeg;
if (vdeg >= 0)
{
assert(vdeg >= ddeg);
parent->polynomial->div_monic(vdeg, v, ddeg, d, udiv);
vdeg -= ddeg;
memcpy(v, udiv, (vdeg + 1) * sizeof(v[0]));
}
}
vdeg = parent->polynomial->div_monic(vdeg, v, udeg, u, NULL);
while (udeg > 2)
{
assert(udeg <= 4);
assert(vdeg <= 3);
// u' = monic((curve-v^2)/u), v'=-v mod u'
tmpdeg = parent->polynomial->mul(vdeg, v, vdeg, v, -1, tmp);
for (i = 0; i <= tmpdeg && i <= 5; i++)
{
tmp[i] = parent->residue->sub(parent->curve[i], tmp[i]);
}
for (; i <= tmpdeg; i++)
{
tmp[i] = parent->residue->sub(0, tmp[i]);
}
for (; i <= 5; i++)
{
tmp[i] = parent->curve[i];
}
tmpdeg = i - 1;
QWORD udiv[5];
parent->polynomial->div_monic(tmpdeg, tmp, udeg, u, udiv);
udeg = tmpdeg - udeg;
QWORD mult = parent->residue->inv(udiv[udeg]);
for (i = 0; i < udeg; i++)
{
u[i] = parent->residue->mul(udiv[i], mult);
}
u[i] = 1;
for (i = 0; i <= vdeg; i++)
{
v[i] = parent->residue->sub(0, v[i]);
}
vdeg = parent->polynomial->div_monic(vdeg, v, udeg, u, NULL);
}
if (udeg == 2)
{
dst->u[0] = u[0];
dst->u[1] = u[1];
dst->v[0] = (vdeg >= 0 ? v[0] : 0);
dst->v[1] = (vdeg >= 1 ? v[1] : 0);
}
else if (udeg == 1)
{
dst->u[0] = u[0];
dst->u[1] = BAD;
dst->v[0] = (vdeg >= 0 ? v[0] : 0);
dst->v[1] = BAD;
}
else
{
assert(udeg == 0);
dst->u[0] = BAD;
dst->u[1] = BAD;
dst->v[0] = BAD;
dst->v[1] = BAD;
}
}
#define divisor_double(src, dst) add(src, src, dst)
/**
*
* @param src
* @param mult
* @param dst
*/
void ConfirmationID::Divisor::mul(const TDivisor *src, QWORD mult, TDivisor *dst)
{
if (mult == 0)
{
dst->u[0] = BAD;
dst->u[1] = BAD;
dst->v[0] = BAD;
dst->v[1] = BAD;
return;
}
TDivisor cur = *src;
while (!(mult & 1))
{
divisor_double(&cur, &cur);
mult >>= 1;
}
*dst = cur;
while ((mult >>= 1) != 0)
{
divisor_double(&cur, &cur);
if (mult & 1)
{
add(dst, &cur, dst);
}
}
}
/**
*
* @param src
* @param mult_lo
* @param mult_hi
* @param dst
*/
void ConfirmationID::Divisor::mul128(const TDivisor *src, QWORD mult_lo, QWORD mult_hi, TDivisor *dst)
{
if (mult_lo == 0 && mult_hi == 0)
{
dst->u[0] = BAD;
dst->u[1] = BAD;
dst->v[0] = BAD;
dst->v[1] = BAD;
return;
}
TDivisor cur = *src;
while (!(mult_lo & 1))
{
divisor_double(&cur, &cur);
mult_lo >>= 1;
if (mult_hi & 1)
{
mult_lo |= (1ULL << 63);
}
mult_hi >>= 1;
}
*dst = cur;
for (;;)
{
mult_lo >>= 1;
if (mult_hi & 1)
{
mult_lo |= (1ULL << 63);
}
mult_hi >>= 1;
if (mult_lo == 0 && mult_hi == 0)
{
break;
}
divisor_double(&cur, &cur);
if (mult_lo & 1)
{
add(dst, &cur, dst);
}
}
}

View File

@ -0,0 +1,261 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 12/05/2023
* @Maintainer Neo
*/
#include "confid.h"
/**
* generic short slow code
*
* @param adeg
* @param a
* @param bdeg
* @param b
* @param resultprevdeg
* @param result
* @return
*/
int ConfirmationID::Polynomial::mul(int adeg, const QWORD a[], int bdeg, const QWORD b[], int resultprevdeg,
QWORD result[])
{
if (adeg < 0 || bdeg < 0)
{
return resultprevdeg;
}
int i, j;
for (i = resultprevdeg + 1; i <= adeg + bdeg; i++)
{
result[i] = 0;
}
resultprevdeg = i - 1;
for (i = 0; i <= adeg; i++)
{
for (j = 0; j <= bdeg; j++)
{
result[i + j] = parent->residue->add(result[i + j], parent->residue->mul(a[i], b[j]));
}
}
while (resultprevdeg >= 0 && result[resultprevdeg] == 0)
{
--resultprevdeg;
}
return resultprevdeg;
}
/**
*
* @param adeg
* @param a
* @param bdeg
* @param b
* @param quotient
* @return
*/
int ConfirmationID::Polynomial::div_monic(int adeg, QWORD a[], int bdeg, const QWORD b[], QWORD *quotient)
{
assert(bdeg >= 0);
assert(b[bdeg] == 1);
int i, j;
for (i = adeg - bdeg; i >= 0; i--)
{
QWORD q = a[i + bdeg];
if (quotient)
{
quotient[i] = q;
}
for (j = 0; j < bdeg; j++)
{
a[i + j] = parent->residue->sub(a[i + j], parent->residue->mul(q, b[j]));
}
a[i + j] = 0;
}
i += bdeg;
while (i >= 0 && a[i] == 0)
{
i--;
}
return i;
}
/**
*
* @param adeg
* @param a
* @param bdeg
* @param b
* @param pgcddeg
* @param gcd
* @param pmult1deg
* @param mult1
* @param pmult2deg
* @param mult2
*/
void ConfirmationID::Polynomial::xgcd(int adeg, const QWORD a[3], int bdeg, const QWORD b[3], int *pgcddeg,
QWORD gcd[3], int *pmult1deg, QWORD mult1[3], int *pmult2deg, QWORD mult2[3])
{
int sdeg = -1;
QWORD s[3] = {0, 0, 0};
int mult1deg = 0;
mult1[0] = 1;
mult1[1] = 0;
mult1[2] = 0;
int tdeg = 0;
QWORD t[3] = {1, 0, 0};
int mult2deg = -1;
mult2[0] = 0;
mult2[1] = 0;
mult2[2] = 0;
int rdeg = bdeg;
QWORD r[3] = {b[0], b[1], b[2]};
int gcddeg = adeg;
gcd[0] = a[0];
gcd[1] = a[1];
gcd[2] = a[2];
// s*u1 + t*u2 = r
// mult1*u1 + mult2*u2 = gcd
while (rdeg >= 0)
{
if (rdeg > gcddeg)
{
unsigned tmp;
int tmpi;
tmp = rdeg;
rdeg = gcddeg;
gcddeg = tmp;
tmpi = sdeg;
sdeg = mult1deg;
mult1deg = tmpi;
tmpi = tdeg;
tdeg = mult2deg;
mult2deg = tmpi;
QWORD tmp2;
tmp2 = r[0];
r[0] = gcd[0];
gcd[0] = tmp2;
tmp2 = r[1];
r[1] = gcd[1];
gcd[1] = tmp2;
tmp2 = r[2];
r[2] = gcd[2];
gcd[2] = tmp2;
tmp2 = s[0];
s[0] = mult1[0];
mult1[0] = tmp2;
tmp2 = s[1];
s[1] = mult1[1];
mult1[1] = tmp2;
tmp2 = s[2];
s[2] = mult1[2];
mult1[2] = tmp2;
tmp2 = t[0];
t[0] = mult2[0];
mult2[0] = tmp2;
tmp2 = t[1];
t[1] = mult2[1];
mult2[1] = tmp2;
tmp2 = t[2];
t[2] = mult2[2];
mult2[2] = tmp2;
continue;
}
int delta = gcddeg - rdeg;
QWORD mult = parent->residue->mul(gcd[gcddeg], parent->residue->inv(r[rdeg]));
// quotient = mult * x**delta
assert(rdeg + delta < 3);
for (int i = 0; i <= rdeg; i++)
{
gcd[i + delta] = parent->residue->sub(gcd[i + delta], parent->residue->mul(mult, r[i]));
}
while (gcddeg >= 0 && gcd[gcddeg] == 0)
{
gcddeg--;
}
assert(sdeg + delta < 3);
for (int i = 0; i <= sdeg; i++)
{
mult1[i + delta] = parent->residue->sub(mult1[i + delta], parent->residue->mul(mult, s[i]));
}
if (mult1deg < sdeg + delta)
{
mult1deg = sdeg + delta;
}
while (mult1deg >= 0 && mult1[mult1deg] == 0)
{
mult1deg--;
}
assert(tdeg + delta < 3);
for (int i = 0; i <= tdeg; i++)
{
mult2[i + delta] = parent->residue->sub(mult2[i + delta], parent->residue->mul(mult, t[i]));
}
if (mult2deg < tdeg + delta)
{
mult2deg = tdeg + delta;
}
while (mult2deg >= 0 && mult2[mult2deg] == 0)
{
mult2deg--;
}
}
// d1 = gcd, e1 = mult1, e2 = mult2
*pgcddeg = gcddeg;
*pmult1deg = mult1deg;
*pmult2deg = mult2deg;
}

View File

@ -0,0 +1,279 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 12/05/2023
* @Maintainer Neo
*/
#include "confid.h"
#if defined(__x86_64__) || defined(_M_AMD64) || defined(__aarch64__) || (defined(__arm64__) && defined(__APPLE__))
#ifdef __GNUC__
QWORD ConfirmationID::Residue::__umul128(QWORD multiplier, QWORD multiplicand, QWORD *product_hi)
{
OWORD r = (OWORD)multiplier * (OWORD)multiplicand;
*product_hi = r >> 64;
return (QWORD)r;
}
#else // basically msvc
/**
*
* @param multiplier
* @param multiplicand
* @param product_hi
* @return
*/
QWORD ConfirmationID::Residue::__umul128(QWORD multiplier, QWORD multiplicand, QWORD *product_hi)
{
return _umul128(multiplier, multiplicand, product_hi);
}
#endif
#elif defined(__i386__) || defined(_M_IX86) || defined(__arm__) || defined(__EMSCRIPTEN__)
QWORD ConfirmationID::Residue::__umul128(QWORD multiplier, QWORD multiplicand, QWORD *product_hi)
{
// multiplier = ab = a * 2^32 + b
// multiplicand = cd = c * 2^32 + d
// ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
QWORD a = multiplier >> 32;
QWORD b = multiplier & 0xFFFFFFFF;
QWORD c = multiplicand >> 32;
QWORD d = multiplicand & 0xFFFFFFFF;
// QWORD ac = a * c;
QWORD ad = a * d;
// QWORD bc = b * c;
QWORD bd = b * d;
QWORD adbc = ad + (b * c);
QWORD adbc_carry = adbc < ad ? 1 : 0;
// multiplier * multiplicand = product_hi * 2^64 + product_lo
QWORD product_lo = bd + (adbc << 32);
QWORD product_lo_carry = product_lo < bd ? 1 : 0;
*product_hi = (a * c) + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
return product_lo;
}
#else
#error Unknown architecture detected - please edit confid.cpp to tailor __umul128() your architecture
#endif
/**
*
* @param lo
* @param hi
* @return
*/
QWORD ConfirmationID::Residue::ui128_quotient_mod(QWORD lo, QWORD hi)
{
// hi:lo * ceil(2**170/MOD) >> (64 + 64 + 42)
QWORD prod1;
__umul128(lo, parent->privateKey.qword[0], &prod1);
QWORD part1hi, part1lo = __umul128(lo, parent->privateKey.qword[1], &part1hi);
QWORD part2hi, part2lo = __umul128(hi, parent->privateKey.qword[0], &part2hi);
QWORD sum1 = part1lo + part2lo;
unsigned sum1carry = (sum1 < part1lo);
sum1 += prod1;
sum1carry += (sum1 < prod1);
QWORD prod2 = part1hi + part2hi + sum1carry;
QWORD prod3hi, prod3lo = __umul128(hi, parent->privateKey.qword[1], &prod3hi);
prod3lo += prod2;
prod3hi += (prod3lo < prod2);
return (prod3lo >> 42) | (prod3hi << 22);
}
/**
*
* @param x
* @param y
* @return
*/
QWORD ConfirmationID::Residue::mul(QWORD x, QWORD y)
{
// * ceil(2**170/MOD) = 0x2d351 c6d04f8b|604fa6a1 c6346a87 for (p-1)*(p-1) max
QWORD hi, lo = __umul128(x, y, &hi);
QWORD quotient = ui128_quotient_mod(lo, hi);
return lo - quotient * parent->MOD;
}
/**
*
* @param x
* @param y
* @return
*/
QWORD ConfirmationID::Residue::pow(QWORD x, QWORD y)
{
if (y == 0)
{
return 1;
}
QWORD cur = x;
while (!(y & 1))
{
cur = mul(cur, cur);
y >>= 1;
}
QWORD res = cur;
while ((y >>= 1) != 0)
{
cur = mul(cur, cur);
if (y & 1)
{
res = mul(res, cur);
}
}
return res;
}
/**
*
* @param x
* @param y
* @return
*/
QWORD ConfirmationID::Residue::add(QWORD x, QWORD y)
{
QWORD z = x + y;
// z = z - (z >= MOD ? MOD : 0);
if (z >= parent->MOD)
{
z -= parent->MOD;
}
return z;
}
/**
*
* @param x
* @param y
* @return
*/
QWORD ConfirmationID::Residue::sub(QWORD x, QWORD y)
{
QWORD z = x - y;
// z += (x < y ? MOD : 0);
if (x < y)
{
z += parent->MOD;
}
return z;
}
/**
*
* @param u
* @param v
* @return
*/
QWORD ConfirmationID::Residue::inverse(QWORD u, QWORD v)
{
// assert(u);
int64_t tmp;
int64_t xu = 1, xv = 0;
QWORD v0 = v;
while (u > 1)
{
QWORD d = v / u;
QWORD remainder = v % u;
tmp = u;
u = remainder;
v = tmp;
tmp = xu;
xu = xv - d * xu;
xv = tmp;
}
xu += (xu < 0 ? v0 : 0);
return xu;
}
/**
*
* @param x
* @return
*/
QWORD ConfirmationID::Residue::inv(QWORD x)
{
return inverse(x, parent->MOD);
// return residue_pow(x, MOD - 2);
}
/**
*
* @param what
* @return
*/
QWORD ConfirmationID::Residue::sqrt(QWORD what)
{
if (!what)
{
return 0;
}
QWORD g = parent->NON_RESIDUE, z, y, r, x, b, t;
QWORD e = 0, q = parent->MOD - 1;
while (!(q & 1))
{
e++, q >>= 1;
}
z = pow(g, q);
y = z;
r = e;
x = pow(what, (q - 1) / 2);
b = mul(mul(what, x), x);
x = mul(what, x);
while (b != 1)
{
QWORD m = 0, b2 = b;
do
{
m++;
b2 = mul(b2, b2);
} while (b2 != 1);
if (m == r)
{
return BAD;
}
t = pow(y, 1 << (r - m - 1));
y = mul(t, t);
r = m;
x = mul(x, t);
b = mul(b, y);
}
if (mul(x, x) != what)
{
// printf("internal error in sqrt\n");
return BAD;
}
return x;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,20 +16,33 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/25/2023
* @FileCreated by Neo on 06/25/2023
* @Maintainer Neo
*/
#include "libumskt.h"
#ifdef _WIN32
std::FILE* UMSKT::debug = std::fopen("NUL:", "w");
// this seems janky but it works, and doesn't use storage that would otherwise get clobbered
std::FILE *getFileStreamToNul()
{
fopen_s(&UMSKT::debug, "nul", "w");
return UMSKT::debug;
}
std::FILE *UMSKT::debug = getFileStreamToNul();
#else
std::FILE* UMSKT::debug = std::fopen("/dev/null", "w");
std::FILE *UMSKT::debug = std::fopen("/dev/null", "w");
#endif
BOOL UMSKT::VERBOSE = false;
BOOL UMSKT::DEBUG = false;
void UMSKT::setDebugOutput(std::FILE* input) {
/**
* sets the filestream used for debugging
*
* @param input std::FILE
*/
void UMSKT::setDebugOutput(std::FILE *input)
{
debug = input;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,45 +16,277 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/25/2023
* @FileCreated by Neo on 06/25/2023
* @Maintainer Neo
*/
#include "libumskt.h"
#include "confid/confid.h"
#include "pidgen3/PIDGEN3.h"
#include "pidgen2/PIDGEN2.h"
#include "pidgen3/BINK1998.h"
#include "pidgen3/BINK2002.h"
#include "pidgen2/PIDGEN2.h"
#include "pidgen3/PIDGEN3.h"
FNEXPORT int ConfirmationID_Generate(const char* installation_id_str, char confirmation_id[49]) {
return ConfirmationID::Generate(installation_id_str, confirmation_id);
std::map<UMSKT_TAG, UMSKT_Value> UMSKT::tags;
extern "C"
{
/**
* Sets debug output to a given C++ File stream
* if the memory allocated at filestream is "STDOUT" or "STDERR"
* simply use the global vars allocated by *this* C++ runtime.
* otherwise, assume that the input pointer is an ABI equivalent std::FILE
*
* @param char* or std::FILE "filestream"
*/
EXPORT BOOL UMSKT_SET_DEBUG_OUTPUT(void *filestream)
{
char buffer[7];
memcpy(buffer, filestream, 6);
buffer[6] = 0;
auto buffstring = std::string(buffer);
std::transform(buffstring.begin(), buffstring.end(), buffstring.begin(), ::tolower);
if (buffstring == "stdout")
{
UMSKT::debug = stdout;
return true;
}
else if (buffstring == "stderr")
{
UMSKT::debug = stderr;
return true;
}
else
{
UMSKT::debug = (std::FILE *)filestream;
return true;
}
return false;
}
// ---------------------------------------------
/**
*
* @param tag
* @param value
* @param valueSize
* @return success
*/
EXPORT BOOL UMSKT_SET_TAG(UMSKT_TAG tag, char *value, size_t valueSize)
{
if (valueSize > sizeof(UMSKT_Value))
{
return false;
}
// wipe/set the tag
memset(&UMSKT::tags[tag], 0, sizeof(UMSKT_Value));
memcpy(&UMSKT::tags[tag], value, valueSize);
return true;
}
EXPORT void UMSKT_RESET_TAGS()
{
UMSKT::tags.clear();
}
// ---------------------------------------------
EXPORT void *CONFID_INIT()
{
auto cid = new ConfirmationID();
// cid->LoadHyperellipticCurve(0, 0, 0, 0, 0, 0, 0, 0, 0, false, false, 0);
return cid;
}
EXPORT BYTE CONFID_GENERATE(void *cidIn, const char *installation_id_str, char *&confirmation_id, char *productid)
{
ConfirmationID *cid;
try
{
cid = static_cast<ConfirmationID *>(cidIn);
}
catch (const std::bad_cast &e)
{
fmt::print(UMSKT::debug, "{}: input is not a {} - {}", __FUNCTION__, e.what());
return -1;
}
for (auto const i : UMSKT::tags)
{
switch (i.first)
{
case UMSKT_tag_InstallationID:
break;
case UMSKT_tag_ProductID:
break;
default:
break;
}
}
std::string str, confid(confirmation_id), productids(productid);
auto retval = cid->Generate(str, confid, productids);
return retval;
}
EXPORT void CONFID_END(void *cidIn)
{
auto *cid((ConfirmationID *)cidIn);
delete cid;
cid = nullptr;
cidIn = nullptr;
}
// ---------------------------------------------
EXPORT void *PIDGEN3_INIT(const char *p, const char *a, const char *b, const char *generatorX,
const char *generatorY, const char *publicKeyX, const char *publicKeyY,
const char *genOrder, const char *privateKey)
{
PIDGEN3 *p3;
if (PIDGEN3::checkFieldStrIsBink1998(p))
{
p3 = new BINK1998();
}
else
{
p3 = new BINK2002();
}
p3->LoadEllipticCurve(p, a, b, generatorX, generatorY, publicKeyX, publicKeyY, genOrder, privateKey);
return p3;
}
EXPORT BOOL PIDGEN3_Generate(void *&ptrIn, char *&pKeyOut, int pKeySizeIn)
{
auto *p3((PIDGEN3 *)ptrIn);
for (auto const i : UMSKT::tags)
{
switch (i.first)
{
case UMSKT_tag_isUpgrade:
p3->info.isUpgrade = i.second.boolean;
break;
case UMSKT_tag_ChannelID:
p3->info.setChannelID(i.second.dword);
break;
case UMSKT_tag_Serial:
p3->info.setSerial(i.second.dword);
break;
case UMSKT_tag_AuthData:
p3->info.setAuthInfo(i.second.dword);
default:
break;
}
}
std::string str;
BOOL retval = p3->Generate(str);
assert(pKeySizeIn >= str.length() + 1);
memcpy(pKeyOut, &str[0], str.length());
pKeyOut[str.length()] = 0;
return retval;
}
EXPORT BOOL PIDGEN3_Validate(void *&ptrIn, char *pKeyIn)
{
auto *p3((PIDGEN3 *)ptrIn);
std::string str(pKeyIn);
BOOL retval = p3->Validate(str);
return retval;
}
EXPORT void PIDGEN3_END(void *ptrIn)
{
auto *p3((PIDGEN3 *)ptrIn);
delete p3;
ptrIn = nullptr;
p3 = nullptr;
}
// ---------------------------------------------
EXPORT void *PIDGEN2_INIT()
{
auto p2 = new PIDGEN2();
return p2;
}
EXPORT BOOL PIDGEN2_GENERATE(void *ptrIn, char *&keyout)
{
auto p2 = (PIDGEN2 *)ptrIn;
return true;
}
EXPORT void PIDGEN2_END(void *ptrIn)
{
auto p2 = (PIDGEN2 *)ptrIn;
delete p2;
p2 = nullptr;
ptrIn = nullptr;
}
} // 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;
}
}
FNEXPORT EC_GROUP* PIDGEN3_initializeEllipticCurve(char* pSel, char* aSel, char* bSel, char* generatorXSel, char* generatorYSel, char* publicKeyXSel, char* publicKeyYSel, EC_POINT *&genPoint, EC_POINT *&pubPoint) {
return PIDGEN3::initializeEllipticCurve(pSel, aSel, bSel, generatorXSel, generatorYSel, publicKeyXSel, publicKeyYSel, genPoint, pubPoint);
}
/**
* 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;
}
FNEXPORT bool PIDGEN3_BINK1998_Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *publicKey, char (&pKey)[25]) {
return PIDGEN3::BINK1998::Verify(eCurve, basePoint, publicKey, pKey);
}
int len = BN_bn2bin(a, to);
FNEXPORT void PIDGEN3_BINK1998_Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *genOrder, BIGNUM *privateKey, DWORD pSerial, BOOL pUpgrade,char (&pKey)[25]) {
return PIDGEN3::BINK1998::Generate(eCurve, basePoint, genOrder, privateKey, pSerial, pUpgrade, pKey);
}
if (len > tolen)
{
return -1;
}
FNEXPORT bool PIDGEN3_BINK2002_Verify(EC_GROUP *eCurve, EC_POINT *basePoint, EC_POINT *publicKey, char (&cdKey)[25]) {
return PIDGEN3::BINK2002::Verify(eCurve, basePoint, publicKey, cdKey);
}
// Choke point inside BN_bn2lebinpad: OpenSSL uses len instead of tolen.
endian(to, tolen);
FNEXPORT void PIDGEN3_BINK2002_Generate(EC_GROUP *eCurve, EC_POINT *basePoint, BIGNUM *genOrder, BIGNUM *privateKey, DWORD pChannelID, DWORD pAuthInfo, BOOL pUpgrade, char (&pKey)[25]) {
return PIDGEN3::BINK2002::Generate(eCurve, basePoint, genOrder, privateKey, pChannelID, pAuthInfo, pUpgrade, pKey);
}
FNEXPORT int PIDGEN2_GenerateRetail(char* channelID, char* &keyout) {
return PIDGEN2::GenerateRetail(channelID, keyout);
}
FNEXPORT int PIDGEN2_GenerateOEM(char* year, char* day, char* oem, char* keyout) {
return PIDGEN2::GenerateOEM(year, day, oem, keyout);
return len;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/24/2023
* @FileCreated by Neo on 06/24/2023
* @Maintainer Neo
*/
@ -25,49 +25,115 @@
#include "../typedefs.h"
#include <string>
#include <iostream>
#include <sstream>
#include <string>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <fmt/core.h>
#include <fmt/format.h>
// Algorithm macros
#define PK_LENGTH 25
#define NULL_TERMINATOR 1
#define PK_LENGTH 25
#define NULL_TERMINATOR 1
#define FIELD_BITS 384
#define FIELD_BYTES 48
#define FIELD_BITS_2003 512
#define FIELD_BYTES_2003 64
#define 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 SHA_MSG_LENGTH_XP (4 + 2 * FIELD_BYTES)
#define SHA_MSG_LENGTH_2003 (3 + 2 * FIELD_BYTES_2003)
#define NEXTSNBITS(field, n, offset) (((QWORD)(field) >> (offset)) & ((1ULL << (n)) - 1))
#define FIRSTNBITS(field, n) NEXTSNBITS((field), (n), 0)
#define NEXTSNBITS(field, n, offset) (((QWORD)(field) >> (offset)) & ((1ULL << (n)) - 1))
#define FIRSTNBITS(field, n) NEXTSNBITS((field), (n), 0)
#define HIBYTES(field, bytes) NEXTSNBITS((QWORD)(field), ((bytes) * 8), ((bytes) * 8))
#define LOBYTES(field, bytes) FIRSTNBITS((QWORD)(field), ((bytes) * 8))
#define HIBYTES(field, bytes) NEXTSNBITS((QWORD)(field), ((bytes) * 8), ((bytes) * 8))
#define LOBYTES(field, bytes) FIRSTNBITS((QWORD)(field), ((bytes) * 8))
#define BYDWORD(n) (DWORD)(*((n) + 0) | *((n) + 1) << 8 | *((n) + 2) << 16 | *((n) + 3) << 24)
#define BITMASK(n) ((1ULL << (n)) - 1)
#define BYDWORD(n) (DWORD)(*((n) + 0) | *((n) + 1) << 8 | *((n) + 2) << 16 | *((n) + 3) << 24)
#define BITMASK(n) ((1ULL << (n)) - 1)
class UMSKT {
public:
static std::FILE* debug;
class PIDGEN2;
class PIDGEN3;
class ConfigurationID;
#ifndef LIBUMSKT_VERSION_STRING
#define LIBUMSKT_VERSION_STRING "unknown version-dirty"
#endif
static void setDebugOutput(std::FILE* input);
enum ValueType
{
VALUE_BOOL,
VALUE_WORD,
VALUE_DWORD,
VALUE_QWORD,
VALUE_OWORD,
VALUE_CHARPTR
};
struct UMSKT_Value
{
ValueType type;
union {
BOOL boolean;
WORD word;
DWORD dword;
QWORD qword;
OWORD oword;
char *chars;
};
};
#endif //UMSKT_LIBUMSKT_H
enum UMSKT_TAG
{
UMSKT_tag_isOEM,
UMSKT_tag_isUpgrade,
UMSKT_tag_Year,
UMSKT_tag_Day,
UMSKT_tag_OEMID,
UMSKT_tag_AuthData,
UMSKT_tag_Serial,
UMSKT_tag_ChannelID,
UMSKT_tag_InstallationID,
UMSKT_tag_ProductID
};
class EXPORT UMSKT
{
public:
static std::FILE *debug;
static BOOL VERBOSE;
static BOOL DEBUG;
static std::map<UMSKT_TAG, UMSKT_Value> tags;
// Hello OpenSSL developers, please tell me, where is this function at?
static int BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen);
static void endian(BYTE *data, int length);
static void DESTRUCT()
{
if (debug != nullptr)
{
std::fclose(debug);
}
debug = nullptr;
}
static void setDebugOutput(std::FILE *input);
template <typename T> static T getRandom()
{
T retval;
RAND_bytes((BYTE *)&retval, sizeof(retval));
return retval;
}
static const char *VERSION()
{
return fmt::format("LIBUMSKT {} compiled on {} {}", LIBUMSKT_VERSION_STRING, __DATE__, __TIME__).c_str();
}
};
#endif // UMSKT_LIBUMSKT_H

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -22,12 +22,17 @@
#include "PIDGEN2.h"
const char* channelIDBlacklist [7] = {"333", "444", "555", "666", "777", "888", "999"};
const char* validYears[8] = { "95", "96", "97", "98", "99", "00", "01", "02"};
bool PIDGEN2::isNumericString(char* input) {
for(int i = 0; i < strlen(input); i++) {
if (input[i] < '0' || input[i] > '9') {
/**
*
* @param input
* @return
*/
BOOL PIDGEN2::isNumericString(char *input)
{
for (int i = 0; i < strlen(input); i++)
{
if (input[i] < '0' || input[i] > '9')
{
return false;
}
}
@ -35,27 +40,44 @@ bool PIDGEN2::isNumericString(char* input) {
return true;
}
int PIDGEN2::addDigits(char* input) {
/**
*
* @param input
* @return
*/
int PIDGEN2::addDigits(char *input)
{
int output = 0;
if (!isNumericString(input)) {
if (!isNumericString(input))
{
return -1;
}
for(int i = 0; i < strlen(input); i++) {
for (int i = 0; i < strlen(input); i++)
{
output += input[i] - '0';
}
return output;
}
bool PIDGEN2::isValidChannelID(char* channelID) {
if (strlen(channelID) > 3) {
/**
*
* @param channelID
* @return
*/
BOOL PIDGEN2::isValidChannelID(char *channelID)
{
if (strlen(channelID) > 3)
{
return false;
}
for (int i = 0; i <= 6; i++) {
if (strcmp(channelID, channelIDBlacklist[i]) != 0) {
for (int i = 0; i <= 6; i++)
{
if (strcmp(channelID, channelIDBlacklist[i]) != 0)
{
return false;
}
}
@ -63,13 +85,22 @@ bool PIDGEN2::isValidChannelID(char* channelID) {
return true;
}
bool PIDGEN2::isValidOEMID(char* OEMID) {
if (!isNumericString(OEMID)) {
/**
*
* @param OEMID
* @return
*/
BOOL PIDGEN2::isValidOEMID(char *OEMID)
{
if (!isNumericString(OEMID))
{
return false;
}
if (strlen(OEMID) > 5) {
if (OEMID[0] != '0' || OEMID[1] != '0') {
if (strlen(OEMID) > 5)
{
if (OEMID[0] != '0' || OEMID[1] != '0')
{
return false;
}
}
@ -79,57 +110,99 @@ bool PIDGEN2::isValidOEMID(char* OEMID) {
return (mod % 21 == 0);
}
bool PIDGEN2::isValidYear(char* year) {
for (int i = 0; i <= 7; i++) {
if (year == validYears[i]) {
/**
*
* @param year
* @return
*/
BOOL PIDGEN2::isValidYear(char *year)
{
for (int i = 0; i <= 7; i++)
{
if (year == validYears[i])
{
return false;
}
}
return true;
}
bool PIDGEN2::isValidDay(char* day) {
if (!isNumericString(day)) {
/**
*
* @param day
* @return
*/
BOOL PIDGEN2::isValidDay(char *day)
{
if (!isNumericString(day))
{
return false;
}
int iDay = std::stoi(day);
if (iDay == 0 || iDay >= 365) {
if (iDay == 0 || iDay >= 365)
{
return false;
}
return true;
}
bool PIDGEN2::isValidRetailProductID(char* productID) {
/**
*
* @param productID
* @return
*/
BOOL PIDGEN2::isValidRetailProductID(char *productID)
{
return true;
}
int PIDGEN2::GenerateRetail(char* channelID, char* &keyout) {
if (!isValidChannelID(channelID)) {
/**
*
* @param channelID
* @param keyout
* @return
*/
int PIDGEN2::GenerateRetail(char *channelID, char *&keyout)
{
if (!isValidChannelID(channelID))
{
return 1;
}
return 0;
}
int PIDGEN2::GenerateOEM(char* year, char* day, char* oem, char* &keyout) {
if (!isValidOEMID(oem)) {
/**
*
* @param year
* @param day
* @param oem
* @param keyout
* @return
*/
int PIDGEN2::GenerateOEM(char *year, char *day, char *oem, char *&keyout)
{
if (!isValidOEMID(oem))
{
int mod = addDigits(oem);
mod += mod % 21;
strcpy(oem, fmt::format("{:07d}", mod).c_str());
snprintf(oem, 8, "%07u", mod);
}
if (!isValidYear(year)) {
strcpy(year, validYears[0]);
if (!isValidYear(year))
{
_strncpy(year, 4, validYears[0], 4);
}
if (!isValidDay(day)) {
int iday = std::stoi(day);
if (!isValidDay(day))
{
auto iday = UMSKT::getRandom<int>();
iday = (iday + 1) % 365;
}
strcpy(keyout, fmt::format("{}{}-OEM-{}-{}", year, day, oem, oem).c_str());
_strncpy(keyout, 32, &fmt::format("{}{}-OEM-{}-{}", year, day, oem, oem).c_str()[0], 32);
return 0;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -25,17 +25,26 @@
#include "../libumskt.h"
EXPORT class PIDGEN2 {
public:
static bool isNumericString(char* input);
static bool isValidChannelID(char* channelID);
static bool isValidOEMID(char* OEMID);
static bool isValidYear(char* year);
static bool isValidDay(char* day);
static bool isValidRetailProductID(char* productID);
static int addDigits(char* input);
static int GenerateRetail(char* channelID, char* &keyout);
static int GenerateOEM(char* year, char* day, char* oem, char* &keyout);
class EXPORT PIDGEN2
{
DWORD year;
DWORD day;
BOOL isOEM;
BOOL isOffice;
static constexpr char channelIDBlacklist[7][4] = {"333", "444", "555", "666", "777", "888", "999"};
static constexpr char validYears[8][3] = {"95", "96", "97", "98", "99", "00", "01", "02"};
public:
BOOL isNumericString(char *input);
BOOL isValidChannelID(char *channelID);
BOOL isValidOEMID(char *OEMID);
BOOL isValidYear(char *year);
BOOL isValidDay(char *day);
BOOL isValidRetailProductID(char *productID);
int addDigits(char *input);
int GenerateRetail(char *channelID, char *&keyout);
int GenerateOEM(char *year, char *day, char *oem, char *&keyout);
};
#endif //UMSKT_PIDGEN2_H
#endif // UMSKT_PIDGEN2_H

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -29,175 +29,73 @@
#include "BINK1998.h"
/* Unpacks a Windows XP-like Product Key. */
void PIDGEN3::BINK1998::Unpack(
QWORD (&pRaw)[2],
BOOL &pUpgrade,
DWORD &pSerial,
DWORD &pHash,
QWORD &pSignature
) {
// We're assuming that the quantity of information within the product key is at most 114 bits.
// log2(24^25) = 114.
// Upgrade = Bit 0
pUpgrade = FIRSTNBITS(pRaw[0], 1);
// Serial = Bits [1..30] -> 30 bits
pSerial = NEXTSNBITS(pRaw[0], 30, 1);
// Hash = Bits [31..58] -> 28 bits
pHash = NEXTSNBITS(pRaw[0], 28, 31);
// Signature = Bits [59..113] -> 56 bits
pSignature = FIRSTNBITS(pRaw[1], 51) << 5 | NEXTSNBITS(pRaw[0], 5, 59);
}
/* Packs a Windows XP-like Product Key. */
void PIDGEN3::BINK1998::Pack(
QWORD (&pRaw)[2],
BOOL pUpgrade,
DWORD pSerial,
DWORD pHash,
QWORD pSignature
) {
/**
* Packs a Windows XP-like Product Key.
*
* @param pRaw [in] *QWORD[2] raw product key input
**/
BOOL BINK1998::Pack(QWORD *pRaw)
{
// The quantity of information the key provides is 114 bits.
// We're storing it in 2 64-bit quad-words with 14 trailing bits.
// 64 * 2 = 128
// Signature [114..59] <- Hash [58..31] <- Serial [30..1] <- Upgrade [0]
pRaw[0] = FIRSTNBITS(pSignature, 5) << 59 | FIRSTNBITS(pHash, 28) << 31 | pSerial << 1 | pUpgrade;
pRaw[1] = NEXTSNBITS(pSignature, 51, 5);
pRaw[0] = FIRSTNBITS(info.Signature, 5) << 59 | FIRSTNBITS(info.Hash, 28) << 31 | info.Serial << 1 | info.isUpgrade;
pRaw[1] = NEXTSNBITS(info.Signature, 51, 5);
return true;
}
/* Verifies a Windows XP-like Product Key. */
bool PIDGEN3::BINK1998::Verify(
EC_GROUP *eCurve,
EC_POINT *basePoint,
EC_POINT *publicKey,
char (&pKey)[25]
) {
BN_CTX *numContext = BN_CTX_new();
/**
* Unpacks a Windows XP-like Product Key.
*
* @param pRaw [out] *QWORD[2] raw product key output
**/
BOOL BINK1998::Unpack(QWORD *pRaw)
{
// We're assuming that the quantity of information within the product key is at most 114 bits.
// log2(24^25) = 114.
QWORD pRaw[2]{},
pSignature;
// Upgrade = Bit 0
info.isUpgrade = FIRSTNBITS(pRaw[0], 1);
DWORD pData,
pSerial,
pHash;
// Serial = Bits [1..30] -> 30 bits
info.Serial = NEXTSNBITS(pRaw[0], 30, 1);
BOOL pUpgrade;
// Hash = Bits [31..58] -> 28 bits
info.Hash = NEXTSNBITS(pRaw[0], 28, 31);
// Convert Base24 CD-key to bytecode.
PIDGEN3::unbase24((BYTE *)pRaw, pKey);
// Signature = Bits [59..113] -> 56 bits
info.Signature = FIRSTNBITS(pRaw[1], 51) << 5 | NEXTSNBITS(pRaw[0], 5, 59);
// Extract RPK, hash and signature from bytecode.
Unpack(pRaw, pUpgrade, pSerial, pHash, pSignature);
fmt::print(UMSKT::debug, "Validation results:\n");
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", pSerial);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", pHash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", pSignature);
fmt::print(UMSKT::debug, "\n");
pData = pSerial << 1 | pUpgrade;
/*
*
* Scalars:
* e = Hash
* s = Schnorr Signature
*
* Points:
* G(x, y) = Generator (Base Point)
* K(x, y) = Public Key
*
* Equation:
* P = sG + eK
*
*/
BIGNUM *e = BN_lebin2bn((BYTE *)&pHash, sizeof(pHash), nullptr),
*s = BN_lebin2bn((BYTE *)&pSignature, sizeof(pSignature), nullptr),
*x = BN_new(),
*y = BN_new();
// Create 2 points on the elliptic curve.
EC_POINT *t = EC_POINT_new(eCurve);
EC_POINT *p = EC_POINT_new(eCurve);
// t = sG
EC_POINT_mul(eCurve, t, nullptr, basePoint, s, numContext);
// P = eK
EC_POINT_mul(eCurve, p, nullptr, publicKey, e, numContext);
// P += t
EC_POINT_add(eCurve, p, t, p, numContext);
// x = P.x; y = P.y;
EC_POINT_get_affine_coordinates(eCurve, p, x, y, numContext);
BYTE msgDigest[SHA_DIGEST_LENGTH]{},
msgBuffer[SHA_MSG_LENGTH_XP]{},
xBin[FIELD_BYTES]{},
yBin[FIELD_BYTES]{};
// Convert resulting point coordinates to bytes.
BN_bn2lebin(x, xBin, FIELD_BYTES);
BN_bn2lebin(y, yBin, FIELD_BYTES);
// Assemble the SHA message.
memcpy((void *)&msgBuffer[0], (void *)&pData, 4);
memcpy((void *)&msgBuffer[4], (void *)xBin, FIELD_BYTES);
memcpy((void *)&msgBuffer[4 + FIELD_BYTES], (void *)yBin, FIELD_BYTES);
// compHash = SHA1(pSerial || P.x || P.y)
SHA1(msgBuffer, SHA_MSG_LENGTH_XP, msgDigest);
// Translate the byte digest into a 32-bit integer - this is our computed hash.
// Truncate the hash to 28 bits.
DWORD compHash = BYDWORD(msgDigest) >> 4 & BITMASK(28);
BN_free(e);
BN_free(s);
BN_free(x);
BN_free(y);
BN_CTX_free(numContext);
EC_POINT_free(t);
EC_POINT_free(p);
// If the computed hash checks out, the key is valid.
return compHash == pHash;
return true;
}
/* Generates a Windows XP-like Product Key. */
void PIDGEN3::BINK1998::Generate(
EC_GROUP *eCurve,
EC_POINT *basePoint,
BIGNUM *genOrder,
BIGNUM *privateKey,
DWORD pSerial,
BOOL pUpgrade,
char (&pKey)[25]
) {
/**
* Generates a Windows XP-like Product Key.
*
* @param pKey [out]
*
* @return true on success, false on fail
*/
BOOL BINK1998::Generate(std::string &pKey)
{
BN_CTX *numContext = BN_CTX_new();
BIGNUM *c = BN_new(),
*s = BN_new(),
*x = BN_new(),
*y = BN_new();
BIGNUM *c = BN_CTX_get(numContext), *s = BN_CTX_get(numContext), *x = BN_CTX_get(numContext),
*y = BN_CTX_get(numContext);
QWORD pRaw[2]{},
pSignature = 0;
QWORD pRaw[2];
// Data segment of the RPK.
DWORD pData = pSerial << 1 | pUpgrade;
DWORD pData = info.Serial << 1 | info.isUpgrade;
do {
// prepare the private key for generation
BN_sub(privateKey, genOrder, privateKey);
do
{
EC_POINT *r = EC_POINT_new(eCurve);
// Generate a random number c consisting of 384 bits without any constraints.
@ -205,32 +103,30 @@ void PIDGEN3::BINK1998::Generate(
// Pick a random derivative of the base point on the elliptic curve.
// R = cG;
EC_POINT_mul(eCurve, r, nullptr, basePoint, c, numContext);
EC_POINT_mul(eCurve, r, nullptr, genPoint, c, numContext);
// Acquire its coordinates.
// x = R.x; y = R.y;
EC_POINT_get_affine_coordinates(eCurve, r, x, y, numContext);
BYTE msgDigest[SHA_DIGEST_LENGTH]{},
msgBuffer[SHA_MSG_LENGTH_XP]{},
xBin[FIELD_BYTES]{},
yBin[FIELD_BYTES]{};
BYTE msgDigest[SHA_DIGEST_LENGTH], msgBuffer[SHA_MSG_LENGTH_XP];
BYTE xBin[FIELD_BYTES], yBin[FIELD_BYTES];
// Convert coordinates to bytes.
BN_bn2lebin(x, xBin, FIELD_BYTES);
BN_bn2lebin(y, yBin, FIELD_BYTES);
UMSKT::BN_bn2lebin(x, xBin, FIELD_BYTES);
UMSKT::BN_bn2lebin(y, yBin, FIELD_BYTES);
// Assemble the SHA message.
memcpy((void *)&msgBuffer[0], (void *)&pData, 4);
memcpy((void *)&msgBuffer[4], (void *)xBin, FIELD_BYTES);
memcpy((void *)&msgBuffer[4 + FIELD_BYTES], (void *)yBin, FIELD_BYTES);
memcpy(&msgBuffer[0], &pData, 4);
memcpy(&msgBuffer[4], xBin, FIELD_BYTES);
memcpy(&msgBuffer[4 + FIELD_BYTES], yBin, FIELD_BYTES);
// pHash = SHA1(pSerial || R.x || R.y)
SHA1(msgBuffer, SHA_MSG_LENGTH_XP, msgDigest);
// Translate the byte digest into a 32-bit integer - this is our computed pHash.
// Truncate the pHash to 28 bits.
DWORD pHash = BYDWORD(msgDigest) >> 4 & BITMASK(28);
info.Hash = BYDWORD(msgDigest) >> 4 & BITMASK(28);
/*
*
@ -253,26 +149,28 @@ void PIDGEN3::BINK1998::Generate(
// s = ek;
BN_copy(s, privateKey);
BN_mul_word(s, pHash);
BN_mul_word(s, info.Hash);
// s += c (mod n)
BN_mod_add(s, s, c, genOrder, numContext);
// Translate resulting scalar into a 64-bit integer (the byte order is little-endian).
BN_bn2lebinpad(s, (BYTE *)&pSignature, BN_num_bytes(s));
BN_bn2lebinpad(s, (BYTE *)&info.Signature, BN_num_bytes(s));
// Pack product key.
Pack(pRaw, pUpgrade, pSerial, pHash, pSignature);
Pack(pRaw);
auto serial = fmt::format("{:d}", info.Serial);
fmt::print(UMSKT::debug, "Generation results:\n");
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print(UMSKT::debug, " Serial: 0x{:08x}\n", pSerial);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", pHash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", pSignature);
fmt::print(UMSKT::debug, "{:>10}: {:b}\n", "Upgrade", (bool)info.isUpgrade);
fmt::print(UMSKT::debug, "{:>10}: {}\n", "Channel ID", serial.substr(0, 3));
fmt::print(UMSKT::debug, "{:>10}: {}\n", "Sequence", serial.substr(3));
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Hash", info.Hash);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Signature", info.Signature);
fmt::print(UMSKT::debug, "\n");
EC_POINT_free(r);
} while (pSignature > BITMASK(55));
} while (info.Signature > BITMASK(55));
// ↑ ↑ ↑
// The signature can't be longer than 55 bits, else it will
// make the CD-key longer than 25 characters.
@ -280,10 +178,107 @@ void PIDGEN3::BINK1998::Generate(
// Convert bytecode to Base24 CD-key.
base24(pKey, (BYTE *)pRaw);
BN_free(c);
BN_CTX_free(numContext);
return true;
}
/**
* Validate a Windows XP-like Product Key.
*
* @param pKey [in]
*
* @return true if provided key validates against loaded curve
*/
BOOL BINK1998::Validate(std::string &pKey)
{
if (pKey.length() != 25)
{
return false;
}
BN_CTX *numContext = BN_CTX_new();
QWORD pRaw[2];
// Convert Base24 CD-key to bytecode.
unbase24((BYTE *)pRaw, pKey);
// Extract RPK, hash and signature from bytecode.
Unpack(pRaw);
auto serial = fmt::format("{:d}", info.Serial);
fmt::print(UMSKT::debug, "Validation results:\n");
fmt::print(UMSKT::debug, "{:>10}: {}\n", "Upgrade", (bool)info.isUpgrade);
fmt::print(UMSKT::debug, "{:>10}: {}\n", "Channel ID", serial.substr(0, 3));
fmt::print(UMSKT::debug, "{:>10}: {}\n", "Sequence", serial.substr(3));
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Hash", info.Hash);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Signature", info.Signature);
fmt::print(UMSKT::debug, "\n");
DWORD pData = info.Serial << 1 | info.isUpgrade;
/*
*
* Scalars:
* e = Hash
* s = Schnorr Signature
*
* Points:
* G(x, y) = Generator (Base Point)
* K(x, y) = Public Key
*
* Equation:
* P = sG + eK
*
*/
BIGNUM *e = BN_lebin2bn((BYTE *)&info.Hash, sizeof(info.Hash), nullptr),
*s = BN_lebin2bn((BYTE *)&info.Signature, sizeof(info.Signature), nullptr);
BIGNUM *x = BN_CTX_get(numContext), *y = BN_CTX_get(numContext);
// Create 2 points on the elliptic curve.
EC_POINT *t = EC_POINT_new(eCurve), *p = EC_POINT_new(eCurve);
// t = sG
EC_POINT_mul(eCurve, t, nullptr, genPoint, s, numContext);
// P = eK
EC_POINT_mul(eCurve, p, nullptr, pubPoint, e, numContext);
// P += t
EC_POINT_add(eCurve, p, t, p, numContext);
// x = P.x; y = P.y;
EC_POINT_get_affine_coordinates(eCurve, p, x, y, numContext);
BYTE msgDigest[SHA_DIGEST_LENGTH], msgBuffer[SHA_MSG_LENGTH_XP], xBin[FIELD_BYTES], yBin[FIELD_BYTES];
// Convert resulting point coordinates to bytes.
UMSKT::BN_bn2lebin(x, xBin, FIELD_BYTES);
UMSKT::BN_bn2lebin(y, yBin, FIELD_BYTES);
// Assemble the SHA message.
memcpy(&msgBuffer[0], &pData, 4);
memcpy(&msgBuffer[4], xBin, FIELD_BYTES);
memcpy(&msgBuffer[4 + FIELD_BYTES], yBin, FIELD_BYTES);
// compHash = SHA1(pSerial || P.x || P.y)
SHA1(msgBuffer, SHA_MSG_LENGTH_XP, msgDigest);
// Translate the byte digest into a 32-bit integer - this is our computed hash.
// Truncate the hash to 28 bits.
DWORD compHash = BYDWORD(msgDigest) >> 4 & BITMASK(28);
BN_free(e);
BN_free(s);
BN_free(x);
BN_free(y);
BN_CTX_free(numContext);
EC_POINT_free(t);
EC_POINT_free(p);
// If the computed hash checks out, the key is valid.
return compHash == info.Hash;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/6/2023
* @FileCreated by Neo on 06/06/2023
* @Maintainer Neo
*/
@ -25,40 +25,30 @@
#include "PIDGEN3.h"
EXPORT class PIDGEN3::BINK1998 {
public:
static void Unpack(
QWORD (&pRaw)[2],
BOOL &pUpgrade,
DWORD &pSerial,
DWORD &pHash,
QWORD &pSignature
);
class EXPORT BINK1998 : public PIDGEN3
{
public:
using PIDGEN3::PIDGEN3;
explicit BINK1998(PIDGEN3 *p3)
{
privateKey = p3->privateKey;
genOrder = p3->genOrder;
genPoint = p3->genPoint;
pubPoint = p3->pubPoint;
eCurve = p3->eCurve;
}
static void Pack(
QWORD (&pRaw)[2],
BOOL pUpgrade,
DWORD pSerial,
DWORD pHash,
QWORD pSignature
);
using PIDGEN3::Pack;
BOOL Pack(QWORD *pRaw) override;
static bool Verify(
EC_GROUP *eCurve,
EC_POINT *basePoint,
EC_POINT *publicKey,
char (&pKey)[25]
);
using PIDGEN3::Unpack;
BOOL Unpack(QWORD *pRaw) override;
static void Generate(
EC_GROUP *eCurve,
EC_POINT *basePoint,
BIGNUM *genOrder,
BIGNUM *privateKey,
DWORD pSerial,
BOOL pUpgrade,
char (&pKey)[25]
);
using PIDGEN3::Generate;
BOOL Generate(std::string &pKey) override;
using PIDGEN3::Validate;
BOOL Validate(std::string &pKey) override;
};
#endif //UMSKT_BINK1998_H
#endif // UMSKT_BINK1998_H

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -29,256 +29,117 @@
#include "BINK2002.h"
/* Unpacks a Windows Server 2003-like Product Key. */
void PIDGEN3::BINK2002::Unpack(
QWORD (&pRaw)[2],
BOOL &pUpgrade,
DWORD &pChannelID,
DWORD &pHash,
QWORD &pSignature,
DWORD &pAuthInfo
) {
/**
* Packs a Windows Server 2003-like Product Key.
*
* @param pRaw *QWORD[2] raw product key output
**/
BOOL BINK2002::Pack(QWORD *pRaw)
{
// AuthInfo [113..104] <- Signature [103..42] <- Hash [41..11] <- Channel ID [10..1] <- Upgrade [0]
pRaw[0] = FIRSTNBITS(info.Signature, 22) << 42 | (QWORD)info.Hash << 11 | info.ChannelID << 1 | info.isUpgrade;
pRaw[1] = FIRSTNBITS(info.AuthInfo, 10) << 40 | NEXTSNBITS(info.Signature, 40, 22);
return true;
}
/**
* Unpacks a Windows Server 2003-like Product Key.
*
* @param pRaw *QWORD[2] raw product key input
**/
BOOL BINK2002::Unpack(QWORD *pRaw)
{
// We're assuming that the quantity of information within the product key is at most 114 bits.
// log2(24^25) = 114.
// Upgrade = Bit 0
pUpgrade = FIRSTNBITS(pRaw[0], 1);
info.isUpgrade = FIRSTNBITS(pRaw[0], 1);
// Channel ID = Bits [1..10] -> 10 bits
pChannelID = NEXTSNBITS(pRaw[0], 10, 1);
info.ChannelID = NEXTSNBITS(pRaw[0], 10, 1);
// Hash = Bits [11..41] -> 31 bits
pHash = NEXTSNBITS(pRaw[0], 31, 11);
info.Hash = NEXTSNBITS(pRaw[0], 31, 11);
// Signature = Bits [42..103] -> 62 bits
// The quad-word signature overlaps AuthInfo in bits 104 and 105,
// hence Microsoft employs a secret technique called: Signature = HIDWORD(Signature) >> 2 | LODWORD(Signature)
pSignature = NEXTSNBITS(pRaw[1], 30, 10) << 32 | FIRSTNBITS(pRaw[1], 10) << 22 | NEXTSNBITS(pRaw[0], 22, 42);
info.Signature = NEXTSNBITS(pRaw[1], 30, 10) << 32 | FIRSTNBITS(pRaw[1], 10) << 22 | NEXTSNBITS(pRaw[0], 22, 42);
// AuthInfo = Bits [104..113] -> 10 bits
pAuthInfo = NEXTSNBITS(pRaw[1], 10, 40);
info.AuthInfo = NEXTSNBITS(pRaw[1], 10, 40);
return true;
}
/* Packs a Windows Server 2003-like Product Key. */
void PIDGEN3::BINK2002::Pack(
QWORD (&pRaw)[2],
BOOL pUpgrade,
DWORD pChannelID,
DWORD pHash,
QWORD pSignature,
DWORD pAuthInfo
) {
// AuthInfo [113..104] <- Signature [103..42] <- Hash [41..11] <- Channel ID [10..1] <- Upgrade [0]
pRaw[0] = FIRSTNBITS(pSignature, 22) << 42 | (QWORD)pHash << 11 | pChannelID << 1 | pUpgrade;
pRaw[1] = FIRSTNBITS(pAuthInfo, 10) << 40 | NEXTSNBITS(pSignature, 40, 22);
}
/* Verifies a Windows Server 2003-like Product Key. */
bool PIDGEN3::BINK2002::Verify(
EC_GROUP *eCurve,
EC_POINT *basePoint,
EC_POINT *publicKey,
char (&cdKey)[25]
) {
BN_CTX *context = BN_CTX_new();
QWORD bKey[2]{},
pSignature = 0;
DWORD pData,
pChannelID,
pHash,
pAuthInfo;
BOOL pUpgrade;
// Convert Base24 CD-key to bytecode.
unbase24((BYTE *)bKey, cdKey);
// Extract product key segments from bytecode.
Unpack(bKey, pUpgrade, pChannelID, pHash, pSignature, pAuthInfo);
pData = pChannelID << 1 | pUpgrade;
fmt::print(UMSKT::debug, "Validation results:\n");
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", pChannelID);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", pHash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", pSignature);
fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", pAuthInfo);
fmt::print(UMSKT::debug, "\n");
BYTE msgDigest[SHA_DIGEST_LENGTH]{},
msgBuffer[SHA_MSG_LENGTH_2003]{},
xBin[FIELD_BYTES_2003]{},
yBin[FIELD_BYTES_2003]{};
// Assemble the first SHA message.
msgBuffer[0x00] = 0x5D;
msgBuffer[0x01] = (pData & 0x00FF);
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
msgBuffer[0x03] = (pHash & 0x000000FF);
msgBuffer[0x04] = (pHash & 0x0000FF00) >> 8;
msgBuffer[0x05] = (pHash & 0x00FF0000) >> 16;
msgBuffer[0x06] = (pHash & 0xFF000000) >> 24;
msgBuffer[0x07] = (pAuthInfo & 0x00FF);
msgBuffer[0x08] = (pAuthInfo & 0xFF00) >> 8;
msgBuffer[0x09] = 0x00;
msgBuffer[0x0A] = 0x00;
// newSignature = SHA1(5D || Channel ID || Hash || AuthInfo || 00 00)
SHA1(msgBuffer, 11, msgDigest);
// Translate the byte digest into a 64-bit integer - this is our computed intermediate signature.
// As the signature is only 62 bits long at most, we have to truncate it by shifting the high DWORD right 2 bits (per spec).
QWORD iSignature = NEXTSNBITS(BYDWORD(&msgDigest[4]), 30, 2) << 32 | BYDWORD(msgDigest);
/*
*
* Scalars:
* e = Hash
* s = Schnorr Signature
*
* Points:
* G(x, y) = Generator (Base Point)
* K(x, y) = Public Key
*
* Equation:
* P = s(sG + eK)
*
*/
BIGNUM *e = BN_lebin2bn((BYTE *)&iSignature, sizeof(iSignature), nullptr),
*s = BN_lebin2bn((BYTE *)&pSignature, sizeof(pSignature), nullptr),
*x = BN_new(),
*y = BN_new();
// Create 2 points on the elliptic curve.
EC_POINT *p = EC_POINT_new(eCurve);
EC_POINT *t = EC_POINT_new(eCurve);
// t = sG
EC_POINT_mul(eCurve, t, nullptr, basePoint, s, context);
// p = eK
EC_POINT_mul(eCurve, p, nullptr, publicKey, e, context);
// p += t
EC_POINT_add(eCurve, p, t, p, context);
// p *= s
EC_POINT_mul(eCurve, p, nullptr, p, s, context);
// x = p.x; y = p.y;
EC_POINT_get_affine_coordinates(eCurve, p, x, y, context);
// Convert resulting point coordinates to bytes.
BN_bn2lebin(x, xBin, FIELD_BYTES_2003);
BN_bn2lebin(y, yBin, FIELD_BYTES_2003);
// Assemble the second SHA message.
msgBuffer[0x00] = 0x79;
msgBuffer[0x01] = (pData & 0x00FF);
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
memcpy((void *)&msgBuffer[3], (void *)xBin, FIELD_BYTES_2003);
memcpy((void *)&msgBuffer[3 + FIELD_BYTES_2003], (void *)yBin, FIELD_BYTES_2003);
// compHash = SHA1(79 || Channel ID || p.x || p.y)
SHA1(msgBuffer, SHA_MSG_LENGTH_2003, msgDigest);
// Translate the byte digest into a 32-bit integer - this is our computed hash.
// Truncate the hash to 31 bits.
DWORD compHash = BYDWORD(msgDigest) & BITMASK(31);
BN_free(s);
BN_free(e);
BN_free(x);
BN_free(y);
BN_CTX_free(context);
EC_POINT_free(p);
EC_POINT_free(t);
// If the computed hash checks out, the key is valid.
return compHash == pHash;
}
/* Generates a Windows Server 2003-like Product Key. */
void PIDGEN3::BINK2002::Generate(
EC_GROUP *eCurve,
EC_POINT *basePoint,
BIGNUM *genOrder,
BIGNUM *privateKey,
DWORD pChannelID,
DWORD pAuthInfo,
BOOL pUpgrade,
char (&pKey)[25]
) {
/**
* Generates a Windows Server 2003-like Product Key.
*
* @param info
* @param pKey
* @return
*/
BOOL BINK2002::Generate(std::string &pKey)
{
BN_CTX *numContext = BN_CTX_new();
BIGNUM *c = BN_new(),
*e = BN_new(),
*s = BN_new(),
*x = BN_new(),
*y = BN_new();
BIGNUM *c = BN_CTX_get(numContext), *e = BN_CTX_get(numContext), *s = BN_CTX_get(numContext),
*x = BN_CTX_get(numContext), *y = BN_CTX_get(numContext);
QWORD pRaw[2]{},
pSignature = 0;
QWORD pRaw[2];
// Data segment of the RPK.
DWORD pData = pChannelID << 1 | pUpgrade;
DWORD pData = info.ChannelID << 1 | info.isUpgrade;
BOOL noSquare;
do {
do
{
EC_POINT *r = EC_POINT_new(eCurve);
// 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);
// R = cG
EC_POINT_mul(eCurve, r, nullptr, basePoint, c, numContext);
EC_POINT_mul(eCurve, r, nullptr, genPoint, c, numContext);
// Acquire its coordinates.
// x = R.x; y = R.y;
EC_POINT_get_affine_coordinates(eCurve, r, x, y, numContext);
BYTE msgDigest[SHA_DIGEST_LENGTH]{},
msgBuffer[SHA_MSG_LENGTH_2003]{},
xBin[FIELD_BYTES_2003]{},
yBin[FIELD_BYTES_2003]{};
BYTE msgDigest[SHA_DIGEST_LENGTH], msgBuffer[SHA_MSG_LENGTH_2003], xBin[FIELD_BYTES_2003],
yBin[FIELD_BYTES_2003];
// Convert resulting point coordinates to bytes.
BN_bn2lebin(x, xBin, FIELD_BYTES_2003);
BN_bn2lebin(y, yBin, FIELD_BYTES_2003);
UMSKT::BN_bn2lebin(x, xBin, FIELD_BYTES_2003);
UMSKT::BN_bn2lebin(y, yBin, FIELD_BYTES_2003);
// Assemble the first SHA message.
msgBuffer[0x00] = 0x79;
msgBuffer[0x01] = (pData & 0x00FF);
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
memcpy((void *)&msgBuffer[3], (void *)xBin, FIELD_BYTES_2003);
memcpy((void *)&msgBuffer[3 + FIELD_BYTES_2003], (void *)yBin, FIELD_BYTES_2003);
memcpy(&msgBuffer[3], xBin, FIELD_BYTES_2003);
memcpy(&msgBuffer[3 + FIELD_BYTES_2003], yBin, FIELD_BYTES_2003);
// pHash = SHA1(79 || Channel ID || R.x || R.y)
SHA1(msgBuffer, SHA_MSG_LENGTH_2003, msgDigest);
// Translate the byte digest into a 32-bit integer - this is our computed hash.
// Truncate the hash to 31 bits.
DWORD pHash = BYDWORD(msgDigest) & BITMASK(31);
info.Hash = BYDWORD(msgDigest) & BITMASK(31);
// Assemble the second SHA message.
msgBuffer[0x00] = 0x5D;
msgBuffer[0x01] = (pData & 0x00FF);
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
msgBuffer[0x03] = (pHash & 0x000000FF);
msgBuffer[0x04] = (pHash & 0x0000FF00) >> 8;
msgBuffer[0x05] = (pHash & 0x00FF0000) >> 16;
msgBuffer[0x06] = (pHash & 0xFF000000) >> 24;
msgBuffer[0x07] = (pAuthInfo & 0x00FF);
msgBuffer[0x08] = (pAuthInfo & 0xFF00) >> 8;
msgBuffer[0x03] = (info.Hash & 0x000000FF);
msgBuffer[0x04] = (info.Hash & 0x0000FF00) >> 8;
msgBuffer[0x05] = (info.Hash & 0x00FF0000) >> 16;
msgBuffer[0x06] = (info.Hash & 0xFF000000) >> 24;
msgBuffer[0x07] = (info.AuthInfo & 0x00FF);
msgBuffer[0x08] = (info.AuthInfo & 0xFF00) >> 8;
msgBuffer[0x09] = 0x00;
msgBuffer[0x0A] = 0x00;
@ -286,7 +147,8 @@ void PIDGEN3::BINK2002::Generate(
SHA1(msgBuffer, 11, msgDigest);
// Translate the byte digest into a 64-bit integer - this is our computed intermediate signature.
// As the signature is only 62 bits long at most, we have to truncate it by shifting the high DWORD right 2 bits (per spec).
// As the signature is only 62 bits long at most, we have to truncate it by shifting the high DWORD right 2
// bits (per spec).
QWORD iSignature = NEXTSNBITS(BYDWORD(&msgDigest[4]), 30, 2) << 32 | BYDWORD(msgDigest);
BN_lebin2bn((BYTE *)&iSignature, sizeof(iSignature), e);
@ -346,29 +208,30 @@ void PIDGEN3::BINK2002::Generate(
// If s is odd, add order to it.
// The order is a prime, so it can't be even.
if (BN_is_odd(s))
{
// s = -ek + √((ek)² + 4c) + n
BN_add(s, s, genOrder);
}
// s /= 2 (s >>= 1)
BN_rshift1(s, s);
// Translate resulting scalar into a 64-bit integer (the byte order is little-endian).
BN_bn2lebinpad(s, (BYTE *)&pSignature, BN_num_bytes(s));
BN_bn2lebinpad(s, (BYTE *)&info.Signature, BN_num_bytes(s));
// Pack product key.
Pack(pRaw, pUpgrade, pChannelID, pHash, pSignature, pAuthInfo);
Pack(pRaw);
fmt::print(UMSKT::debug, "Generation results:\n");
fmt::print(UMSKT::debug, " Upgrade: 0x{:08x}\n", pUpgrade);
fmt::print(UMSKT::debug, "Channel ID: 0x{:08x}\n", pChannelID);
fmt::print(UMSKT::debug, " Hash: 0x{:08x}\n", pHash);
fmt::print(UMSKT::debug, " Signature: 0x{:08x}\n", pSignature);
fmt::print(UMSKT::debug, " AuthInfo: 0x{:08x}\n", pAuthInfo);
fmt::print(UMSKT::debug, "{:>10}: {:b}\n", "Upgrade", (bool)info.isUpgrade);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Channel ID", info.ChannelID);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Hash", info.Hash);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Signature", info.Signature);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "AuthInfo", info.AuthInfo);
fmt::print(UMSKT::debug, "\n");
EC_POINT_free(r);
} while (pSignature > BITMASK(62) || noSquare);
} while (info.Signature > BITMASK(62) || noSquare);
// ↑ ↑ ↑
// The signature can't be longer than 62 bits, else it will
// overlap with the AuthInfo segment next to it.
@ -376,11 +239,125 @@ void PIDGEN3::BINK2002::Generate(
// Convert bytecode to Base24 CD-key.
base24(pKey, (BYTE *)pRaw);
BN_free(c);
BN_CTX_free(numContext);
return true;
}
/**
* Validates a Windows Server 2003-like Product Key.
*
* @param pKey
**/
BOOL BINK2002::Validate(std::string &pKey)
{
BN_CTX *context = BN_CTX_new();
QWORD bKey[2];
// Convert Base24 CD-key to bytecode.
unbase24((BYTE *)bKey, &pKey[0]);
// Extract product key segments from bytecode.
Unpack(bKey);
DWORD pData = info.ChannelID << 1 | info.isUpgrade;
fmt::print(UMSKT::debug, "Validation results:\n");
fmt::print(UMSKT::debug, "{:>10}: {:b}\n", "Upgrade", (bool)info.isUpgrade);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Channel ID", info.ChannelID);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Hash", info.Hash);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "Signature", info.Signature);
fmt::print(UMSKT::debug, "{:>10}: {:d}\n", "AuthInfo", info.AuthInfo);
fmt::print(UMSKT::debug, "\n");
BYTE msgDigest[SHA_DIGEST_LENGTH], msgBuffer[SHA_MSG_LENGTH_2003], xBin[FIELD_BYTES_2003], yBin[FIELD_BYTES_2003];
// Assemble the first SHA message.
msgBuffer[0x00] = 0x5D;
msgBuffer[0x01] = (pData & 0x00FF);
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
msgBuffer[0x03] = (info.Hash & 0x000000FF);
msgBuffer[0x04] = (info.Hash & 0x0000FF00) >> 8;
msgBuffer[0x05] = (info.Hash & 0x00FF0000) >> 16;
msgBuffer[0x06] = (info.Hash & 0xFF000000) >> 24;
msgBuffer[0x07] = (info.AuthInfo & 0x00FF);
msgBuffer[0x08] = (info.AuthInfo & 0xFF00) >> 8;
msgBuffer[0x09] = 0x00;
msgBuffer[0x0A] = 0x00;
// newSignature = SHA1(5D || Channel ID || Hash || AuthInfo || 00 00)
SHA1(msgBuffer, 11, msgDigest);
// Translate the byte digest into a 64-bit integer - this is our computed intermediate signature.
// As the signature is only 62 bits long at most, we have to truncate it by shifting the high DWORD right 2 bits
// (per spec).
QWORD iSignature = NEXTSNBITS(BYDWORD(&msgDigest[4]), 30, 2) << 32 | BYDWORD(msgDigest);
/*
*
* Scalars:
* e = Hash
* s = Schnorr Signature
*
* Points:
* G(x, y) = Generator (Base Point)
* K(x, y) = Public Key
*
* Equation:
* P = s(sG + eK)
*
*/
BIGNUM *e = BN_lebin2bn((BYTE *)&iSignature, sizeof(iSignature), nullptr),
*s = BN_lebin2bn((BYTE *)&info.Signature, sizeof(info.Signature), nullptr);
BIGNUM *x = BN_CTX_get(context), *y = BN_CTX_get(context);
// Create 2 points on the elliptic curve.
EC_POINT *p = EC_POINT_new(eCurve), *t = EC_POINT_new(eCurve);
// t = sG
EC_POINT_mul(eCurve, t, nullptr, genPoint, s, context);
// p = eK
EC_POINT_mul(eCurve, p, nullptr, pubPoint, e, context);
// p += t
EC_POINT_add(eCurve, p, t, p, context);
// p *= s
EC_POINT_mul(eCurve, p, nullptr, p, s, context);
// x = p.x; y = p.y;
EC_POINT_get_affine_coordinates(eCurve, p, x, y, context);
// Convert resulting point coordinates to bytes.
UMSKT::BN_bn2lebin(x, xBin, FIELD_BYTES_2003);
UMSKT::BN_bn2lebin(y, yBin, FIELD_BYTES_2003);
// Assemble the second SHA message.
msgBuffer[0x00] = 0x79;
msgBuffer[0x01] = (pData & 0x00FF);
msgBuffer[0x02] = (pData & 0xFF00) >> 8;
memcpy((void *)&msgBuffer[3], (void *)xBin, FIELD_BYTES_2003);
memcpy((void *)&msgBuffer[3 + FIELD_BYTES_2003], (void *)yBin, FIELD_BYTES_2003);
// compHash = SHA1(79 || Channel ID || p.x || p.y)
SHA1(msgBuffer, SHA_MSG_LENGTH_2003, msgDigest);
// Translate the byte digest into a 32-bit integer - this is our computed hash.
// Truncate the hash to 31 bits.
DWORD compHash = BYDWORD(msgDigest) & BITMASK(31);
BN_free(s);
BN_free(x);
BN_free(y);
BN_free(e);
BN_CTX_free(numContext);
EC_POINT_free(p);
EC_POINT_free(t);
BN_CTX_free(context);
// If the computed hash checks out, the key is valid.
return compHash == info.Hash;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/6/2023
* @FileCreated by Neo on 06/06/2023
* @Maintainer Neo
*/
@ -25,43 +25,30 @@
#include "PIDGEN3.h"
EXPORT class PIDGEN3::BINK2002 {
public:
static void Unpack(
QWORD (&pRaw)[2],
BOOL &pUpgrade,
DWORD &pChannelID,
DWORD &pHash,
QWORD &pSignature,
DWORD &pAuthInfo
);
class EXPORT BINK2002 : public PIDGEN3
{
public:
using PIDGEN3::PIDGEN3;
explicit BINK2002(PIDGEN3 *p3)
{
privateKey = p3->privateKey;
genOrder = p3->genOrder;
genPoint = p3->genPoint;
pubPoint = p3->pubPoint;
eCurve = p3->eCurve;
}
static void Pack(
QWORD (&pRaw)[2],
BOOL pUpgrade,
DWORD pChannelID,
DWORD pHash,
QWORD pSignature,
DWORD pAuthInfo
);
using PIDGEN3::Pack;
BOOL Pack(QWORD *pRaw) override;
static bool Verify(
EC_GROUP *eCurve,
EC_POINT *basePoint,
EC_POINT *publicKey,
char (&cdKey)[25]
);
using PIDGEN3::Unpack;
BOOL Unpack(QWORD *pRaw) override;
static void Generate(
EC_GROUP *eCurve,
EC_POINT *basePoint,
BIGNUM *genOrder,
BIGNUM *privateKey,
DWORD pChannelID,
DWORD pAuthInfo,
BOOL pUpgrade,
char (&pKey)[25]
);
using PIDGEN3::Generate;
BOOL Generate(std::string &pKey) override;
using PIDGEN3::Validate;
BOOL Validate(std::string &pKey) override;
};
#endif //UMSKT_BINK2002_H
#endif // UMSKT_BINK2002_H

View File

@ -0,0 +1,277 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Andrew on 01/06/2023
* @Maintainer Andrew
*/
#include "PIDGEN3.h"
#include "BINK1998.h"
#include "BINK2002.h"
/**
* https://xkcd.com/221/
*
* @return 4
*/
int getRandomNumber()
{
return 4; // chosen by fair dice roll
// guaranteed to be random
}
/**
* Initializes the elliptic curve
*
* @param pSel [in] prime
* @param aSel [in] a
* @param bSel [in] b
* @param generatorXSel [in] G[x]
* @param generatorYSel [in] G[y]
* @param publicKeyXSel [in] pub[x]
* @param publicKeyYSel [in] pub[y]
* @param genOrderSel [in] computed order of G
* @param privateKeySel [in] computed private key
*
* @return true on success, false on fail
*/
BOOL PIDGEN3::LoadEllipticCurve(const std::string pSel, const std::string aSel, const std::string bSel,
const std::string generatorXSel, const std::string generatorYSel,
const std::string publicKeyXSel, const std::string publicKeyYSel,
const std::string genOrderSel, const std::string privateKeySel)
{
// We cannot produce a valid key without knowing the private key k. The reason for this is that
// we need the result of the function K(x; y) = kG(x; y).
// We can, however, validate any given key using the available public key: {p, a, b, G, K}.
// genOrder the order of the generator G, a value we have to reverse -> Schoof's Algorithm.
// Initialize BIGNUM and BIGNUMCTX structures.
// BIGNUM - Large numbers
// BIGNUMCTX - Context large numbers (temporary)
// Context variable
BN_CTX *context = BN_CTX_new();
// We're presented with an elliptic curve, a multivariable function y(x; p; a; b), where
// y^2 % p = x^3 + ax + b % p.
BIGNUM *a = BN_CTX_get(context), *b = BN_CTX_get(context), *p = BN_CTX_get(context);
// Public key will consist of the resulting (x; y) values.
BIGNUM *publicKeyX = BN_CTX_get(context), *publicKeyY = BN_CTX_get(context);
// G(x; y) is a generator function, its return value represents a point on the elliptic curve.
BIGNUM *generatorX = BN_CTX_get(context), *generatorY = BN_CTX_get(context);
genOrder = BN_new();
privateKey = BN_new();
/* Public data */
BN_dec2bn(&p, &pSel[0]);
BN_dec2bn(&a, &aSel[0]);
BN_dec2bn(&b, &bSel[0]);
BN_dec2bn(&generatorX, &generatorXSel[0]);
BN_dec2bn(&generatorY, &generatorYSel[0]);
BN_dec2bn(&publicKeyX, &publicKeyXSel[0]);
BN_dec2bn(&publicKeyY, &publicKeyYSel[0]);
/* Computed Data */
BN_dec2bn(&genOrder, &genOrderSel[0]);
BN_dec2bn(&privateKey, &privateKeySel[0]);
/* Elliptic Curve calculations. */
// The group is defined via Fp = all integers [0; p - 1], where p is prime.
// The function EC_POINT_set_affine_coordinates() sets the x and y coordinates for the point p defined over the
// curve given in group.
eCurve = EC_GROUP_new_curve_GFp(p, a, b, context);
// Create new point for the generator on the elliptic curve and set its coordinates to (genX; genY).
genPoint = EC_POINT_new(eCurve);
EC_POINT_set_affine_coordinates(eCurve, genPoint, generatorX, generatorY, context);
// Create new point for the public key on the elliptic curve and set its coordinates to (pubX; pubY).
pubPoint = EC_POINT_new(eCurve);
EC_POINT_set_affine_coordinates(eCurve, pubPoint, publicKeyX, publicKeyY, context);
// If generator and public key points are not on the elliptic curve, either the generator or the public key values
// are incorrect.
assert(EC_POINT_is_on_curve(eCurve, genPoint, context) == true);
assert(EC_POINT_is_on_curve(eCurve, pubPoint, context) == true);
// Cleanup
BN_CTX_free(context);
return true;
}
BOOL PIDGEN3::Generate(std::string &pKey)
{
BOOL retval;
if (checkFieldIsBink1998())
{
auto p3 = BINK1998();
retval = p3.Generate(pKey);
}
else
{
auto p3 = BINK2002();
retval = p3.Generate(pKey);
}
return retval;
}
BOOL PIDGEN3::Validate(std::string &pKey)
{
BOOL retval;
if (checkFieldIsBink1998())
{
auto p3 = BINK1998(this);
retval = p3.Validate(pKey);
}
else
{
auto p3 = BINK2002(this);
retval = p3.Validate(pKey);
}
return retval;
}
/**
* Converts from byte sequence to the CD-key.
*
* @param cdKey [out] std::string CDKey input
* @param byteSeq [in] BYTE*
**/
void PIDGEN3::base24(std::string &cdKey, BYTE *byteSeq)
{
BYTE rbyteSeq[16], output[26];
BIGNUM *z;
// Copy byte sequence to the reversed byte sequence.
memcpy(rbyteSeq, byteSeq, sizeof(rbyteSeq));
// Skip trailing zeroes and reverse y.
int length;
for (length = 15; rbyteSeq[length] <= 0; length--)
{
; // do nothing, just counting
}
UMSKT::endian(rbyteSeq, ++length);
// Convert reversed byte sequence to BigNum z.
z = BN_bin2bn(rbyteSeq, length, nullptr);
// Divide z by 24 and convert the remainder to a CD-key char.
for (int i = 24; i >= 0; i--)
{
output[i] = pKeyCharset[BN_div_word(z, 24)];
}
output[25] = 0;
cdKey = (char *)output;
BN_free(z);
}
/**
* Converts from CD-key to a byte sequence.
*
* @param byteSeq [out] *BYTE representation of the CDKey
* @param cdKey [in] std::string CDKey to convert
**/
void PIDGEN3::unbase24(BYTE *byteSeq, std::string cdKey)
{
BYTE pDecodedKey[PK_LENGTH + NULL_TERMINATOR]{};
BIGNUM *y = BN_new();
// Remove dashes from the CD-key and put it into a Base24 byte array.
for (int i = 0, k = 0; i < cdKey.length() && k < PK_LENGTH; i++)
{
for (int j = 0; j < 24; j++)
{
if (cdKey[i] != '-' && cdKey[i] == pKeyCharset[j])
{
pDecodedKey[k++] = j;
break;
}
}
}
// Empty byte sequence.
memset(byteSeq, 0, 16);
// Calculate the weighed sum of byte array elements.
for (int i = 0; i < PK_LENGTH; i++)
{
BN_mul_word(y, PK_LENGTH - 1);
BN_add_word(y, pDecodedKey[i]);
}
// Acquire length.
int n = BN_num_bytes(y);
// Place the generated code into the byte sequence.
BN_bn2bin(y, byteSeq);
BN_free(y);
// Reverse the byte sequence.
UMSKT::endian(byteSeq, n);
}
BOOL PIDGEN3::checkFieldIsBink1998()
{
auto *max = BN_new();
// 1 << 385 (or max size of BINK1998 field in bits + 1)
BN_set_bit(max, (12 * 4 * 8) + 1);
// retval is -1 when (max < privateKey)
int retval = BN_cmp(max, privateKey);
BN_free(max);
// is max > privateKey?
return retval == 1;
}
BOOL PIDGEN3::checkFieldStrIsBink1998(std::string keyin)
{
auto *context = BN_CTX_new();
auto max = BN_CTX_get(context), input = BN_CTX_get(context);
BN_dec2bn(&input, &keyin[0]);
// 1 << 385 (or max size of BINK1998 field in bits + 1)
BN_set_bit(max, (12 * 4 * 8) + 1);
// retval is -1 when (max < privateKey)
int retval = BN_cmp(max, input);
BN_CTX_free(context);
// is max > privateKey?
return retval == 1;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/24/2023
* @FileCreated by Neo on 06/24/2023
* @Maintainer Neo
*/
@ -25,30 +25,80 @@
#include "../libumskt.h"
class PIDGEN3 {
public:
class BINK1998;
class BINK2002;
class BINK1998;
class BINK2002;
// util.cpp
static int BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen); // Hello OpenSSL developers, please tell me, where is this function at?
static void endian(BYTE *data, int length);
static EC_GROUP* initializeEllipticCurve(
std::string pSel,
std::string aSel,
std::string bSel,
std::string generatorXSel,
std::string generatorYSel,
std::string publicKeyXSel,
std::string publicKeyYSel,
EC_POINT *&genPoint,
EC_POINT *&pubPoint
);
class EXPORT PIDGEN3
{
friend class BINK1998;
friend class BINK2002;
protected:
BIGNUM *privateKey, *genOrder;
EC_POINT *genPoint, *pubPoint;
EC_GROUP *eCurve;
public:
PIDGEN3()
{
}
PIDGEN3(PIDGEN3 &p3)
{
privateKey = p3.privateKey;
genOrder = p3.genOrder;
genPoint = p3.genPoint;
pubPoint = p3.pubPoint;
eCurve = p3.eCurve;
}
virtual ~PIDGEN3()
{
EC_GROUP_free(eCurve);
EC_POINT_free(genPoint);
EC_POINT_free(pubPoint);
BN_free(genOrder);
BN_free(privateKey);
}
struct KeyInfo
{
DWORD Serial = 0, AuthInfo = 0, ChannelID = 0, Hash = 0;
QWORD Signature = 0;
BOOL isUpgrade = false;
void setSerial(DWORD serialIn)
{
Serial = serialIn;
}
void setAuthInfo(DWORD AuthInfoIn)
{
AuthInfo = AuthInfoIn;
}
void setChannelID(DWORD ChannelIDIn)
{
ChannelID = ChannelIDIn;
}
} info;
// key.cpp
static constexpr char pKeyCharset[] = "BCDFGHJKMPQRTVWXY2346789";
static void unbase24(BYTE *byteSeq, const char *cdKey);
static void base24(char *cdKey, BYTE *byteSeq);
BOOL LoadEllipticCurve(std::string pSel, std::string aSel, std::string bSel, std::string generatorXSel,
std::string generatorYSel, std::string publicKeyXSel, std::string publicKeyYSel,
std::string genOrderSel, std::string privateKeySel);
virtual BOOL Pack(QWORD *pRaw) = 0;
virtual BOOL Unpack(QWORD *pRaw) = 0;
virtual BOOL Generate(std::string &pKey);
virtual BOOL Validate(std::string &pKey);
// PIDGEN3.cpp
void base24(std::string &cdKey, BYTE *byteSeq);
void unbase24(BYTE *byteSeq, std::string cdKey);
BOOL checkFieldIsBink1998();
static BOOL checkFieldStrIsBink1998(std::string keyin);
};
#endif //UMSKT_PIDGEN3_H
#endif // UMSKT_PIDGEN3_H

View File

@ -1,86 +0,0 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 5/26/2023
* @Maintainer Andrew
*/
#include "PIDGEN3.h"
/* Converts from CD-key to a byte sequence. */
void PIDGEN3::unbase24(BYTE *byteSeq, const char *cdKey) {
BYTE pDecodedKey[PK_LENGTH + NULL_TERMINATOR]{};
BIGNUM *y = BN_new();
BN_zero(y);
// Remove dashes from the CD-key and put it into a Base24 byte array.
for (int i = 0, k = 0; i < strlen(cdKey) && k < PK_LENGTH; i++) {
for (int j = 0; j < 24; j++) {
if (cdKey[i] != '-' && cdKey[i] == pKeyCharset[j]) {
pDecodedKey[k++] = j;
break;
}
}
}
// Empty byte sequence.
memset(byteSeq, 0, 16);
// Calculate the weighed sum of byte array elements.
for (int i = 0; i < PK_LENGTH; i++) {
BN_mul_word(y, PK_LENGTH - 1);
BN_add_word(y, pDecodedKey[i]);
}
// Acquire length.
int n = BN_num_bytes(y);
// Place the generated code into the byte sequence.
BN_bn2bin(y, byteSeq);
BN_free(y);
// Reverse the byte sequence.
endian(byteSeq, n);
}
/* Converts from byte sequence to the CD-key. */
void PIDGEN3::base24(char *cdKey, BYTE *byteSeq) {
BYTE rbyteSeq[16];
BIGNUM *z;
// Copy byte sequence to the reversed byte sequence.
memcpy(rbyteSeq, byteSeq, sizeof(rbyteSeq));
// Skip trailing zeroes and reverse y.
int length;
for (length = 15; rbyteSeq[length] == 0; length--);
endian(rbyteSeq, ++length);
// Convert reversed byte sequence to BigNum z.
z = BN_bin2bn(rbyteSeq, length, nullptr);
// Divide z by 24 and convert the remainder to a CD-key char.
cdKey[25] = 0;
for (int i = 24; i >= 0; i--)
cdKey[i] = pKeyCharset[BN_div_word(z, 24)];
BN_free(z);
}

View File

@ -1,120 +0,0 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Andrew on 01/06/2023
* @Maintainer Andrew
*/
#include "PIDGEN3.h"
int randomRange() {
return 4; // chosen by fair dice roll
// guaranteed to be random
}
/* Convert data between endianness types. */
void PIDGEN3::endian(BYTE *data, int length) {
for (int i = 0; i < length / 2; i++) {
BYTE temp = data[i];
data[i] = data[length - i - 1];
data[length - i - 1] = temp;
}
}
/* Initializes the elliptic curve. */
EC_GROUP* PIDGEN3::initializeEllipticCurve(
const std::string pSel,
const std::string aSel,
const std::string bSel,
const std::string generatorXSel,
const std::string generatorYSel,
const std::string publicKeyXSel,
const std::string publicKeyYSel,
EC_POINT *&genPoint,
EC_POINT *&pubPoint
) {
// Initialize BIGNUM and BIGNUMCTX structures.
// BIGNUM - Large numbers
// BIGNUMCTX - Context large numbers (temporary)
BIGNUM *a, *b, *p, *generatorX, *generatorY, *publicKeyX, *publicKeyY;
BN_CTX *context;
// We're presented with an elliptic curve, a multivariable function y(x; p; a; b), where
// y^2 % p = x^3 + ax + b % p.
a = BN_new();
b = BN_new();
p = BN_new();
// Public key will consist of the resulting (x; y) values.
publicKeyX = BN_new();
publicKeyY = BN_new();
// G(x; y) is a generator function, its return value represents a point on the elliptic curve.
generatorX = BN_new();
generatorY = BN_new();
// Context variable
context = BN_CTX_new();
/* Public data */
BN_dec2bn(&p, pSel.c_str());
BN_dec2bn(&a, aSel.c_str());
BN_dec2bn(&b, bSel.c_str());
BN_dec2bn(&generatorX, generatorXSel.c_str());
BN_dec2bn(&generatorY, generatorYSel.c_str());
BN_dec2bn(&publicKeyX, publicKeyXSel.c_str());
BN_dec2bn(&publicKeyY, publicKeyYSel.c_str());
/* Elliptic Curve calculations. */
// The group is defined via Fp = all integers [0; p - 1], where p is prime.
// The function EC_POINT_set_affine_coordinates() sets the x and y coordinates for the point p defined over the curve given in group.
EC_GROUP *eCurve = EC_GROUP_new_curve_GFp(p, a, b, context);
// Create new point for the generator on the elliptic curve and set its coordinates to (genX; genY).
genPoint = EC_POINT_new(eCurve);
EC_POINT_set_affine_coordinates(eCurve, genPoint, generatorX, generatorY, context);
// Create new point for the public key on the elliptic curve and set its coordinates to (pubX; pubY).
pubPoint = EC_POINT_new(eCurve);
EC_POINT_set_affine_coordinates(eCurve, pubPoint, publicKeyX, publicKeyY, context);
// If generator and public key points are not on the elliptic curve, either the generator or the public key values are incorrect.
assert(EC_POINT_is_on_curve(eCurve, genPoint, context) == true);
assert(EC_POINT_is_on_curve(eCurve, pubPoint, context) == true);
// Cleanup
BN_CTX_free(context);
return eCurve;
}
int PIDGEN3::BN_bn2lebin(const BIGNUM *a, unsigned char *to, int tolen) {
if (a == nullptr || to == nullptr)
return 0;
int len = BN_bn2bin(a, to);
if (len > tolen)
return -1;
// Choke point inside BN_bn2lebinpad: OpenSSL uses len instead of tolen.
endian(to, tolen);
return len;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -20,44 +20,19 @@
* @Maintainer Neo
*/
#include "header.h"
#include "cli.h"
Options options;
int main(int argc, char *argv[]) {
if (!CLI::parseCommandLine(argc, argv, &options)) {
fmt::print("error parsing command line options\n");
CLI::showHelp(argv);
return !options.error ? 0 : 1;
}
json keys;
int status = CLI::validateCommandLine(&options, argv, &keys);
if (status > 0) {
int main(int argc, char *argv[])
{
int status;
if (status = CLI::Init(argc, argv); status != 0)
{
return status;
}
CLI* run = new CLI(options, keys);
auto cli = CLI();
status = cli.Run();
switch(options.applicationMode) {
case MODE_BINK1998_GENERATE:
return run->BINK1998Generate();
case MODE_BINK2002_GENERATE:
return run->BINK2002Generate();
case MODE_BINK1998_VALIDATE:
return run->BINK1998Validate();
case MODE_BINK2002_VALIDATE:
return run->BINK2002Validate();
case MODE_CONFIRMATION_ID:
return run->ConfirmationID();
default:
return 1;
}
UMSKT::DESTRUCT();
return status;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,26 +16,25 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 5/26/2023
* @FileCreated by Neo on 01/07/2024
* @Maintainer Neo
*/
#ifndef UMSKT_HEADER_H
#define UMSKT_HEADER_H
#include "cli.h"
#include "typedefs.h"
#include <cmrc/cmrc.hpp>
CMRC_DECLARE(umskt);
#include <iostream>
#include <fstream>
#include <filesystem>
#include <string>
#include <vector>
#include <unordered_map>
/**
* load a cmrc embedded JSON file
*
* @return success
*/
BOOL CLI::loadEmbeddedJSON()
{
auto fs = cmrc::umskt::get_filesystem();
auto jsonFile = fs.open("keys.json");
keys = json::parse(jsonFile, nullptr, false, false);
#include <fmt/core.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
namespace fs = std::filesystem;
#endif //UMSKT_HEADER_H
return true;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,44 +16,107 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/24/2023
* @FileCreated by Neo on 06/24/2023
* @Maintainer Neo
*/
#ifndef UMSKT_TYPEDEFS_H
#define UMSKT_TYPEDEFS_H
#include <cstdint>
#if defined(_MSC_VER)
#define WIN32_LEAN_AND_MEAN
#include <intrin.h>
#include <windows.h>
#endif // defined(WIN32)
#include <algorithm>
#include <cstdbool>
#include <cstdint>
#include <map>
#include <vector>
#ifdef DEBUG
#include <cassert>
#else
#define assert(x) /* nothing */
#define assert(x) /* do nothing */
#endif
#ifdef _MSC_VER
#define EXPORT extern "C" __declspec(dllexport)
#if defined(_MSC_VER)
#define FNEXPORT __declspec(dllexport)
#define FNIMPORT __declspec(dllimport)
#define FNINLINE __forceinline
#elif defined(__GNUC__)
#define FNEXPORT __attribute__((visibility("default")))
#define FNIMPORT __attribute__((visibility("default")))
#define FNINLINE inline __attribute__((__always_inline__))
#elif defined(__CLANG__)
#if __has_attribute(__always_inline__)
#define forceinline inline __attribute__((__always_inline__))
#else
#define EXPORT extern "C"
#endif
#define forceinline inline
#endif // __has_attribute(__always_inline__)
#else
#define FNEXPORT
#define FNINLINE
#warning "function inlining not handled"
#endif // defined(_MSC_VER)
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#define FNEXPORT EMSCRIPTEN_KEEPALIVE EXPORT
#define EXPORT EMSCRIPTEN_KEEPALIVE FNEXPORT
#define INLINE FNINLINE
#else
#define FNEXPORT EXPORT
#ifdef UMSKT_IMPORT_LIB
#define EXPORT FNIMPORT
#else
#define EXPORT FNEXPORT
#endif // ifdef UMSKT_IMPORT_LIB
#define INLINE FNINLINE
#endif // ifdef __EMSCRIPTEN__
// POSIX <-> Windows compatability layer, because MS just *had* to be different
#ifdef _MSC_VER
#ifndef _sscanf
#define _sscanf sscanf_s
#endif
#ifndef _strncpy
#define _strncpy strncpy_s
#endif
#ifndef _strcpy
#define _strcpy strcpy_s
#endif
#else
#define _sscanf sscanf
#define _strncpy(x, y, z, w) strncpy(x, z, w)
#define _strcpy strcpy
#endif // ifdef _MSC_VER
// Type definitions now with more windows compatability (unfortunately)
using BOOL = int32_t;
using BYTE = uint8_t;
using WORD = uint16_t;
using DWORD = unsigned long;
using QWORD = uint64_t;
#if defined(_M_ARM) // for Windows on ARM ??
using __m128 = __n128;
#endif
// Type definitions
typedef bool BOOL;
typedef uint8_t BYTE;
typedef uint16_t WORD;
typedef uint32_t DWORD;
typedef uint64_t QWORD;
#ifdef __SIZEOF_INT128__
typedef unsigned __int128 OWORD;
#if defined(__SIZEOF_INT128__) || defined(__int128)
using uint128_t = unsigned __int128;
#else // use the intel-supplied __m128 intrisic
using uint128_t = __m128;
#endif
using OWORD = uint128_t;
#endif //UMSKT_TYPEDEFS_H
typedef union {
OWORD oword;
QWORD qword[2];
DWORD dword[4];
WORD word[8];
BYTE byte[16];
} Q_OWORD;
#endif // UMSKT_TYPEDEFS_H

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -20,24 +20,23 @@
* @Maintainer Neo
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "../typedefs.h"
#include "resource.h"
BOOLEAN WINAPI DllMain( IN HINSTANCE hDllHandle,
IN DWORD nReason,
IN LPVOID Reserved ) {
BOOLEAN WINAPI DllMain(IN HINSTANCE hDllHandle, IN DWORD nReason, IN LPVOID Reserved)
{
BOOLEAN bSuccess = TRUE;
// Perform global initialization.
switch (nReason) {
case DLL_PROCESS_ATTACH:
// For optimization.
DisableThreadLibraryCalls(hDllHandle);
break;
switch (nReason)
{
case DLL_PROCESS_ATTACH:
// For optimization.
DisableThreadLibraryCalls(hDllHandle);
break;
case DLL_PROCESS_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return bSuccess;

70
src/windows/platform.cpp Normal file
View File

@ -0,0 +1,70 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 01/07/2024
* @Maintainer Neo
*/
#include "../cli.h"
#include "resource.h"
/**
*
* @return success
*/
BOOL CLI::loadEmbeddedJSON()
{
HMODULE hModule = GetModuleHandle(nullptr);
// Find
HRSRC hResource = FindResource(hModule, MAKEINTRESOURCE(IDR_JSON1), "JSON");
if (hResource == nullptr)
{
fmt::print("ERROR: Could not find internal JSON resource?");
return false;
}
// Load
HGLOBAL hResourceData = LoadResource(hModule, hResource);
if (hResourceData == nullptr)
{
fmt::print("ERROR: Could not load internal JSON resource?");
return false;
}
// Lock
LPVOID pData = LockResource(hResourceData);
if (pData == nullptr)
{
fmt::print("ERROR: Could not lock internal JSON resource?");
return false;
}
try
{
keys = json::parse((char *)pData, nullptr, false, false);
}
catch (const json::exception &e)
{
fmt::print("ERROR: Exception occurred while parsing internal JSON file: {}\n", e.what());
}
FreeResource(hResourceData);
return true;
}

View File

@ -1,7 +1,7 @@
/**
* This file is a part of the UMSKT Project
*
* Copyleft (C) 2019-2023 UMSKT Contributors (et.al.)
* Copyleft (C) 2019-2024 UMSKT Contributors (et.al.)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @FileCreated by Neo on 6/17/2023
* @FileCreated by Neo on 06/17/2023
* @Maintainer Neo
*/
@ -24,15 +24,17 @@
// Microsoft Visual C++ generated include file.
// Used by umskt.rc
//
#define IDI_ICON1 101
#define IDI_ICON1 101
#define IDR_JSON1 102
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

Binary file not shown.