21 Commits
Author SHA1 Message Date
Double Sine c3548220ab Update Readme for Navicat Premium 12.1.11 2018-12-13 21:01:42 +08:00
Double Sine b588e7f608 Add support for Navicat Premium 12.1.11 x86 2018-12-13 20:41:27 +08:00
Double Sine 5ffe7a198e Add support for Navicat Premium 12.1.11 x64 2018-12-13 18:41:23 +08:00
Double Sine e5300eee16 Refactor code 2018-12-13 12:59:38 +08:00
Double Sine 04fd1ba315 Add HandleGuard and FileMapper 2018-12-13 00:23:30 +08:00
Double Sine d4202a907c Rename parameters of PrintMemory and add comments 2018-12-12 22:56:17 +08:00
Double Sine 23987cb031 Fix a mistake in README.zh-CN.md 2018-09-23 14:05:53 +08:00
Double Sine b9f6504c59 Update README 2018-09-23 00:41:30 +08:00
Double Sine 057d33fd9d Fix spelling mistakes 2018-09-22 23:52:32 +08:00
Double Sine b6aa89bb57 Adjust keygen and add advanced mode 2018-09-22 21:24:41 +08:00
Double Sine b3cfffddf6 Add pragma comment 2018-09-22 21:22:04 +08:00
Double Sine cf945793e4 Update vcxproj 2018-09-22 12:00:19 +08:00
Double Sine 96f40aef26 Adjust Solution0 and Solution1 2018-09-22 11:59:59 +08:00
Double Sine 28c2cfa290 Move some functions to Helper.cpp 2018-09-22 11:58:31 +08:00
Double Sine ac271858f0 Fix mistake: BF_encrypt, BF_decrypt -> BF_ecb_encrypt 2018-09-22 11:56:38 +08:00
Double Sine 368d56b709 Remove unnecessary components and use blowfish, sha1 of OpenSSL version 2018-09-21 21:39:43 +08:00
Double Sine 1f0298a4a8 unsigned long long --> unsigned int 2018-09-21 20:49:20 +08:00
Double Sine 59ff9a0b24 Merge branch 'windows' of https://github.com/DoubleLabyrinth/navicat-keygen into windows 2018-09-12 18:19:11 +08:00
Double Sine a9d7f1004d Fix bug reported in #135 2018-09-12 18:18:35 +08:00
Double SineandGitHub bee41465cf Merge pull request #133 from garboy/windows
增加Release包的下载页面地址
2018-09-11 14:16:49 +08:00
zhangcheng 0e9a00b77c 增加Release包的下载页面地址 2018-09-10 15:07:55 +08:00
31 changed files with 2935 additions and 3465 deletions
+258
View File
@@ -0,0 +1,258 @@
# Navicat keygen - How does it work?
[中文版 How does it work?](HOW_DOES_IT_WORK.zh-CN.md)
## 1. Keyword Explanation.
* __Navicat Activation Public Key__
It is a __RSA-2048__ public key that Navicat used to encrypt or decrypt offline activation information.
It is stored in __navicat.exe__ as a kind of resource called __RCData__. The resource name is `"ACTIVATIONPUBKEY"`. You can see it by a kind of software [___Resource Hacker___](http://www.angusj.com/resourcehacker/). The public key is
```
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
awIDAQAB
-----END PUBLIC KEY-----
```
If you have the corresponding private key, you can tell me. I would be very appreciated for your generous.
__NOTICE:__
Start from __Navicat Premium 12.0.25__, Navicat do not load this public key from resource in `navicat.exe`. Instead, the public key is stored in `libcc.dll` and bas been encrypted. To avoid being replaced easily, the public key is split into 5 parts:
The following content is discovered from `libcc.dll` of __Navicat Premium x64 12.0.25 Simplified Chinese version__. The SHA256 value of `libcc.dll` is `607e0a84c75966b00f3d12fa833e91d159e4f51ac51b6ba66f98d0c3cbefdce0`.
I __DO NOT__ guarantee that offset values are absolutely correct in other versions. But __char strings__ and __immediate values__ are highly possible to be found.
1. At file offset `+0x01A12090` in `libcc.dll`, stored as __char string__:
```
"D75125B70767B94145B47C1CB3C0755E
7CCB8825C5DCE0C58ACF944E08280140
9A02472FAFFD1CD77864BB821AE36766
FEEDE6A24F12662954168BFA314BD950
32B9D82445355ED7BC0B880887D650F5"
```
2. At file offset `+0x0059D799` in `libcc.dll`, stored as __immediate value__ in a instruction:
```
0xFE 0xEA 0xBC 0x01
```
In decimal: `29158142`
3. At file offset `+0x01A11DA0` in `libcc.dll`, stored as __char string__:
```
"E1CED09B9C2186BF71A70C0FE2F1E0AE
F3BD6B75277AAB20DFAF3D110F75912B
FB63AC50EC4C48689D1502715243A79F
39FF2DE2BF15CE438FF885745ED54573
850E8A9F40EE2FF505EB7476F95ADB78
3B28CA374FAC4632892AB82FB3BF4715
FCFE6E82D03731FC3762B6AAC3DF1C3B
C646FE9CD3C62663A97EE72DB932A301
312B4A7633100C8CC357262C39A2B3A6
4B224F5276D5EDBDF0804DC3AC4B8351
62BB1969EAEBADC43D2511D6E0239287
81B167A48273B953378D3D2080CC0677
7E8A2364F0234B81064C5C739A8DA28D
C5889072BF37685CBC94C2D31D0179AD
86D8E3AA8090D4F0B281BE37E0143746
E6049CCC06899401264FA471C016A96C
79815B55BBC26B43052609D9D175FBCD
E455392F10E51EC162F51CF732E6BB39
1F56BBFD8D957DF3D4C55B71CEFD54B1
9C16D458757373E698D7E693A8FC3981
5A8BF03BA05EA8C8778D38F9873D62B4
460F41ACF997C30E7C3AF025FA171B5F
5AD4D6B15E95C27F6B35AD61875E5505
449B4E"
```
4. At file offset `+0x0059D77F` in `libcc.dll`, stored as __immediate value__ in a instruction:
```
0x59 0x08 0x01 0x00
```
In decimal: `67673`
5. At file offset `+ 0x1A11D8C` in `libcc.dll`, stored as __char string__:
```
"92933"
```
Then output encrypted public key with format `"%s%d%s%d%s"`. The order is the same as it lists:
```
D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933
```
This encrypted public key can be decrypted by my another repo: [how-does-navicat-encrypt-password](https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password), while the key used is `b'23970790'`.
Example:
```cmd
E:\GitHub>git clone https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password.git
...
E:\GitHub>cd how-does-navicat-encrypt-password\python3
E:\GitHub\how-does-navicat-encrypt-password\python3>python
Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from NavicatCrypto import *
>>> cipher = Navicat11Crypto(b'23970790')
>>> print(cipher.DecryptString('D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933'))
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
awIDAQAB
-----END PUBLIC KEY-----
```
* __Request Code__
It is a Base64 string that represents 256-bytes-long data, while the 256-bytes-long data is the cipher text of __Offline Activation Information__ encrypted by __Navicat Activation Public Key__.
* __Offline Activation Request Information__
It is just a JSON-style ASCII string which contains 3 items. They are `"K"`, `"DI"` and `"P"` respectively, which represent __snKey__, __DeviceIdentifier__ (related with your machine), __Platform__ (OS Type).
Like
```
{"K": "xxxxxxxxxxxxxxxx", "DI": "yyyyyyyyyyyyy", "P": "WIN8"}
```
* __Activation Code__
It is a Base64 string that represents 256-bytes-long data, while the 256-bytes-long data is the cipher text of the __Offline Activation Response Information__ encrypted by __Navicat Activation Private Key__. So far, we don't know the official activation private key and we have to replace it in `navicat.exe` and `libcc.dll`.
* __Offline Activation Response Information__
Just like __Offline Activation Request Information__, it is also a JSON-style ASCII string. But it contains 5 items. They are `"K"`, `"N"`, `"O"`, `"T"` and `"DI"` respectively.
`"K"` and `"DI"` has the same meaning that is mentioned in __Offline Activation Request Information__ and must be the same with the corresponding items in __Offline Activation Request Information__.
`"N"`, `"O"`, `"T"` represent __Name__, __Organization__, __Timestamp__ respectively. __Name__ and __Organization__ are UTF-8 strings and the type of __Timestamp__ can be string or integer. (Thanks for discoveries from @Wizr, issue #10)
`"T"` can be omitted.
* __snKey__
It is a 4-block-long string, while every block is 4-chars-long.
__snKey__ is generated by 10-bytes-long data. In order to explain it easily, I use __uint8_t data[10]__ to represent the 10-bytes-long data.
1. __data[0]__ and __data[1]__ must be `0x68` and `0x2A` respectively.
These two bytes are Naivcat signature number.
2. __data[2]__, __data[3]__ and __data[4]__ can be any byte. Just set them whatever you want.
3. __data[5]__ and __data[6]__ are product language signatures.
| Language | data[5] | data[6] | Discoverer |
|------------|:---------:|:---------:|-----------------|
| English | 0xAC | 0x88 | |
| 简体中文 | 0xCE | 0x32 | |
| 繁體中文 | 0xAA | 0x99 | |
| 日本語 | 0xAD | 0x82 | @dragonflylee |
| Polski | 0xBB | 0x55 | @dragonflylee |
| Español | 0xAE | 0x10 | @dragonflylee |
| Français | 0xFA | 0x20 | @Deltafox79 |
| Deutsch | 0xB1 | 0x60 | @dragonflylee |
| 한국어 | 0xB5 | 0x60 | @dragonflylee |
| Русский | 0xEE | 0x16 | @dragonflylee |
| Português | 0xCD | 0x49 | @dragonflylee |
4. __data[7]__ is Navicat product ID. (Thanks @dragonflylee and @Deltafox79)
|Product Name |Enterprise|Standard|Educational|Essentials|
|---------------------|:--------:|:------:|:---------:|:--------:|
|Navicat Report Viewer|0x0B | | | |
|Navicat Data Modeler | |0x47 |0x4A | |
|Navicat Premium |0x65 | |0x66 |0x67 |
|Navicat MySQL |0x68 |0x69 |0x6A |0x6B |
|Navicat PostgreSQL |0x6C |0x6D |0x6E |0x6F |
|Navicat Oracle |0x70 |0x71 |0x72 |0x73 |
|Navicat SQL Server |0x74 |0x75 |0x76 |0x77 |
|Navicat SQLite |0x78 |0x79 |0x7A |0x7B |
|Navicat MariaDB |0x7C |0x7D |0x7E |0x7F |
|Navicat MongoDB |0x80 |0x81 |0x82 | |
5. High 4 bits of __data[8]__ represents __major version number__.
Low 4 bits is unknown, but we can use it to delay activation deadline. Possible values are `0000` or `0001`.
__Example:__
For __Navicat 12 x64__: High 4 bits must be `1100`, which is the binary of number `12`.
For __Navicat 11 x64__: High 4 bits must be `1011`, which is the binary of number `11`.
6. __data[9]__ is unknown, but you can set it by `0xFD`, `0xFC` or `0xFB` if you want to use __not-for-resale license__.
According to symbol information in __Navicat 12 for Mac x64__ version:
* `0xFB` is __Not-For-Resale-30-days__ license.
* `0xFC` is __Not-For-Resale-90-days__ license.
* `0xFD` is __Not-For-Resale-365-days__ license.
* `0xFE` is __Not-For-Resale__ license.
* `0xFF` is __Site__ license.
After `uint8_t data[10]` is ready, Navicat uses __DES__ with __ECB mode__ to encrypt the last 8 bytes of `uint8_t data[10]` which are from __data[2]__ to __data[9]__.
The DES key is:
```cpp
unsigned char DESKey = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
```
Then use Base32 to encode `uint8_t data[10]` whose encode table is
```cpp
char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
```
After encoding, you will get a 16-char-long string starting with `"NAV"`.
Finally, divide the 16-char-long string to four 4-chars-long blocks and join them with `"-"` then you will get __snKey__.
## 2. Activation Process
1. Check whether __snKey__ that user inputs is valid.
2. After user clicks `Activate`, Navicat will start online activation first. If fails, user can choose offline activation.
3. Navicat will use the __snKey__ that user inputs and some information collected from user's machine to generate __Offline Activation Request Information__. Then Navicat will encrypt it by __Navicat Activation Public Key__ and return a Base64-encoded string as __Request Code__.
4. In legal way, the __Request Code__ should be sent to Navicat official activation server by a Internet-accessible computer. And Navicat official activation server will return a legal __Activation Code__.
But now, we use keygen to play the official activation server's role.
1. According to the __Request Code__, get `"DI"` value and `"K"` value.
2. Fill __Offline Activation Response Information__ with `"K"` value, name, organization name, `"DI"` value and, if need, `"T"` value.
3. Encrypt __Offline Activation Response Information__ by __Navicat Activation Private Key__ and you will get 256-byte-long data.
4. Encode the 256-byte-long data by Base64. The result is __Activation Code__.
5. After user input __Activation Code__, offline activation is done successfully.
+254
View File
@@ -0,0 +1,254 @@
# Navicat keygen - 注册机是怎么工作的?
## 1. 关键词解释.
* __Navicat激活公钥__
这是一个2048位的RSA公钥,Navicat使用这个公钥来完成相关激活信息的加密和解密。
这个公钥被作为 __RCData__ 类型的资源储存在 __navicat.exe__ 当中。资源名为`"ACTIVATIONPUBKEY"`。你可以使用一个叫[Resource Hacker](http://www.angusj.com/resourcehacker/)的软件来查看它。这个公钥的具体内容为:
```
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
awIDAQAB
-----END PUBLIC KEY-----
```
如果您有相应的私钥并乐意公开的话欢迎联系我,我将非常感谢您的慷慨。
__注意:__
从 __Navicat Premium 12.0.25__ 开始,Navicat不再从`navicat.exe`的资源中加载私钥。事实上,公钥转为从`libcc.dll`中加载,并且已经被加密。与此同时,为了防止被轻松地替换,加密的公钥被分到5个地方储存:
以下内容是从 __Navicat Premium x64 12.0.25 简体中文版__ 的`libcc.dll`中发现的,`libcc.dll`的SHA256值为`607e0a84c75966b00f3d12fa833e91d159e4f51ac51b6ba66f98d0c3cbefdce0`。我不保证在Navicat的其他版本中相关偏移量和下述的相同,但相关的 __字符串__ 以及 __立即数__ 是很可能找得到的。
1. 在`libcc.dll`中,文件偏移量`+0x01A12090`的地方,储存了加密公钥的第一部分,以 __字符串__ 的形式储存:
```
"D75125B70767B94145B47C1CB3C0755E
7CCB8825C5DCE0C58ACF944E08280140
9A02472FAFFD1CD77864BB821AE36766
FEEDE6A24F12662954168BFA314BD950
32B9D82445355ED7BC0B880887D650F5"
```
2. 在`libcc.dll`中,文件偏移量`+0x0059D799`的地方,储存了加密公钥的第二部分,以 __立即数__ 的形式储存在一条指令中:
```
0xFE 0xEA 0xBC 0x01
```
相应的十进制值为: `29158142`
3. 在`libcc.dll`中,文件偏移量`+0x01A11DA0`的地方,储存了加密公钥的第三部分,以 __字符串__ 的形式储存:
```
"E1CED09B9C2186BF71A70C0FE2F1E0AE
F3BD6B75277AAB20DFAF3D110F75912B
FB63AC50EC4C48689D1502715243A79F
39FF2DE2BF15CE438FF885745ED54573
850E8A9F40EE2FF505EB7476F95ADB78
3B28CA374FAC4632892AB82FB3BF4715
FCFE6E82D03731FC3762B6AAC3DF1C3B
C646FE9CD3C62663A97EE72DB932A301
312B4A7633100C8CC357262C39A2B3A6
4B224F5276D5EDBDF0804DC3AC4B8351
62BB1969EAEBADC43D2511D6E0239287
81B167A48273B953378D3D2080CC0677
7E8A2364F0234B81064C5C739A8DA28D
C5889072BF37685CBC94C2D31D0179AD
86D8E3AA8090D4F0B281BE37E0143746
E6049CCC06899401264FA471C016A96C
79815B55BBC26B43052609D9D175FBCD
E455392F10E51EC162F51CF732E6BB39
1F56BBFD8D957DF3D4C55B71CEFD54B1
9C16D458757373E698D7E693A8FC3981
5A8BF03BA05EA8C8778D38F9873D62B4
460F41ACF997C30E7C3AF025FA171B5F
5AD4D6B15E95C27F6B35AD61875E5505
449B4E"
```
4. 在`libcc.dll`中,文件偏移量`+0x0059D77F`的地方,储存了加密公钥的第四部分,以 __立即数__ 的形式储存在一条指令中:
```
0x59 0x08 0x01 0x00
```
相应的十进制值为: `67673`
5. 在`libcc.dll`中,文件偏移量`+0x01A11D8C`的地方,储存了加密公钥的第五部分,以 __字符串__ 的形式储存:
```
"92933"
```
这五部分按照`"%s%d%s%d%s"`的形式输出则为加密的公钥,顺序和上述的顺序相同,具体的输出为:
```
D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933
```
这个加密的公钥可以用我的另外一个repo[how-does-navicat-encrypt-password](https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password))解密,其中密钥为`b'23970790'`。
例如:
```cmd
E:\GitHub>git clone https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password.git
...
E:\GitHub>cd how-does-navicat-encrypt-password\python3
E:\GitHub\how-does-navicat-encrypt-password\python3>python
Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from NavicatCrypto import *
>>> cipher = Navicat11Crypto(b'23970790')
>>> print(cipher.DecryptString('D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933'))
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
awIDAQAB
-----END PUBLIC KEY-----
```
* __请求码__
这是一个Base64编码的字符串,代表的是长度为256字节的数据。这256字节的数据是 __离线激活信息__ 用 __Navicat激活公钥__ 加密的密文。
* __离线激活请求信息__
这是一个JSON风格的字符串。它包含了3个Key:`"K"`、`"DI"`和`"P"`,分别代表 __序列号__、__设备识别码__(与你的电脑硬件信息相关)和 __平台__ (其实就是操作系统类型)。
例如:
```
{"K": "xxxxxxxxxxxxxxxx", "DI": "yyyyyyyyyyyyy", "P": "WIN8"}
```
* __激活码__
这是一个Base64编码的字符串,代表的是长度为256字节的数据。这256字节的数据是 __离线激活回复信息__ 用 __Navicat激活私钥__ 加密的密文。目前我们不知道官方的 __Navicat激活私钥__,所以我们得替换掉软件里的公钥。
* __离线激活回复信息__
和 __离线激活请求信息__ 一样,它也是一个JSON风格的字符串。但是它包含5个Key,分别为`"K"`、`"N"`、`"O"`、`"T"` 和 `"DI"`.
`"K"` 和 `"DI"` 的意义与 __离线激活请求信息__ 中的相同,且Value必须与 __离线激活请求信息__ 中的相同。
`"N"`、`"O"`、`"T"` 分别代表 __注册名__、__组织__、__授权时间__。
__注册名__ 和 __组织__ 的值类型为UTF-8编码的字符串。__授权时间__ 的值类型可以为字符串或整数(感谢@Wizr在issue #10中的报告)。
`"T"` 可以被省略。
* __序列号__
这是一个被分为了4个部分的字符串,其中每个部分都是4个字符长。
__序列号__ 是通过10个字节的数据来生成的。为了表达方便,我用 __uint8_t data[10]__ 来表示这10个字节。
1. __data[0]__ 和 __data[1]__ 必须分别为 `0x68` 和 `0x2A`。
这两个字节为Navicat的标志数。
2. __data[2]__、__data[3]__ 和 __data[4]__ 可以是任意字节,你想设成什么都行。
3. __data[5]__ 和 __data[6]__ 是Navicat的语言标志,值如下:
| 语言类型 | data[5] | data[6] | 发现者 |
|------------|:---------:|:---------:|-----------------|
| English | 0xAC | 0x88 | |
| 简体中文 | 0xCE | 0x32 | |
| 繁體中文 | 0xAA | 0x99 | |
| 日本語 | 0xAD | 0x82 | @dragonflylee |
| Polski | 0xBB | 0x55 | @dragonflylee |
| Español | 0xAE | 0x10 | @dragonflylee |
| Français | 0xFA | 0x20 | @Deltafox79 |
| Deutsch | 0xB1 | 0x60 | @dragonflylee |
| 한국어 | 0xB5 | 0x60 | @dragonflylee |
| Русский | 0xEE | 0x16 | @dragonflylee |
| Português | 0xCD | 0x49 | @dragonflylee |
4. __data[7]__ 是Navicat产品ID。(感谢 @dragonflylee 和 @Deltafox79提供的数据)
|产品名 |Enterprise|Standard|Educational|Essentials|
|---------------------|:--------:|:------:|:---------:|:--------:|
|Navicat Report Viewer|0x0B | | | |
|Navicat Data Modeler | |0x47 |0x4A | |
|Navicat Premium |0x65 | |0x66 |0x67 |
|Navicat MySQL |0x68 |0x69 |0x6A |0x6B |
|Navicat PostgreSQL |0x6C |0x6D |0x6E |0x6F |
|Navicat Oracle |0x70 |0x71 |0x72 |0x73 |
|Navicat SQL Server |0x74 |0x75 |0x76 |0x77 |
|Navicat SQLite |0x78 |0x79 |0x7A |0x7B |
|Navicat MariaDB |0x7C |0x7D |0x7E |0x7F |
|Navicat MongoDB |0x80 |0x81 |0x82 | |
5. __data[8]__ 的高4位代表 __版本号__。低4位未知,但可以用来延长激活期限,可取的值有`0000`和`0001`。
例如:
对于 __Navicat 12__: 高4位必须是`1100`,为`12`的二进制形式。
对于 __Navicat 11__: 高4位必须是`1011`,为`11`的二进制形式。
6. __data[9]__ 目前暂未知,但如果你想要 __not-for-resale license__ 的话可以设成`0xFD`、`0xFC`或`0xFB`。
根据 __Navicat 12 for Mac x64__ 版本残留的符号信息可知:
* `0xFB`是 __Not-For-Resale-30-days__ license.
* `0xFC`是 __Not-For-Resale-90-days__ license.
* `0xFD`是 __Not-For-Resale-365-days__ license.
* `0xFE`是 __Not-For-Resale__ license.
* `0xFF`是 __Site__ license.
之后Navicat使用 __ECB__ 模式的 __DES__ 算法来加密 __data[10]__ 的后8字节,也就是 __data[2]__ 到 __data[9]__ 的部分。
相应的DES密钥为:
```cpp
unsigned char DESKey = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
```
之后使用Base32编码 __data[10]__,其中编码表改为:
```cpp
char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
```
编码之后你应该会得到一个16字节长的字符串,并且以"NAV"打头。
将16字节的字符串分成4个4字节的小块,然后用`"-"`连接就可以得到 __序列号__。
## 2. 激活过程
1. 检查用户输入的 __序列号__ 是否合法。
2. 在用户点击了`激活`按钮之后,Navicat会先尝试在线激活。如果失败,用户可以选择离线激活。
3. Navicat会使用用户输入的 __序列号__ 以及从用户电脑收集来的信息生成 __离线激活请求信息__,然后用 __Navicat激活公钥__ 加密,并将密文用Base64编码,最后得到 __请求码__。
4. 正常流程下,__请求码__ 应该通过可联网的电脑发送给Navicat的官方激活服务器。之后Navicat的官方激活服务器会返回一个合法的 __激活码__。
但现在我们使用注册机来扮演官方激活服务器的角色,只是Navicat软件里的激活公钥得换成自己的公钥:
1. 根据 __请求码__, 获得`"DI"`值和`"K"`值。
2. 用`"K"`值、用户名、组织名和`"DI"`值填写 __离线激活回复信息__
3. 用自己的2048位RSA私钥加密 __离线激活回复信息__,你将会得到256字节的密文。
4. 用Base64编码这256字节的密文,就可以得到 __激活码__
5. 在Navicat软件中填入 __激活码__ 即可完成离线激活。
+179 -367
View File
@@ -1,389 +1,201 @@
# Navicat Keygen
[中文版README](README.zh-CN.md)
[中文版README](README.zh-CN.md)
This repository will tell you how Navicat offline activation works.
This repository will tell you how Navicat offline activation works.
## 1. Keyword Explanation.
[How does it work?](HOW_DOES_IT_WORK.md)
* __Navicat Activation Public Key__
## How to use?
It is a __RSA-2048__ public key that Navicat used to encrypt or decrypt offline activation information.
1. Download the latest release [from here](https://github.com/DoubleLabyrinth/navicat-keygen/releases).
It is stored in __navicat.exe__ as a kind of resource called __RCData__. The resource name is `"ActivationPubKey"`. You can see it by a kind of software [___Resource Hacker___](http://www.angusj.com/resourcehacker/). The concrete content is:
2. Use `navicat-patcher.exe` to replace __Navicat Activation Public Key__ that is stored in `navicat.exe` and `libcc.dll`.
```
navicat-patcher.exe <Navicat installation path> [RSA-2048 PEM file]
```
> -----BEGIN PUBLIC KEY-----
> MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
> qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
> a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
> R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
> WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
> YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
> awIDAQAB
> -----END PUBLIC KEY-----
If you have the corresponding private key, please tell me. I would be very appreciated for your generous.
__NOTICE:__
Start from __Navicat Premium 12.0.25__, Navicat do not load this public key from resource in `navicat.exe`. Actually the public key is stored in `libcc.dll` and encrypted. And to avoid being replaced easily, the public key is split into 5 parts:
The content below is discovered from `libcc.dll` of Navicat Premium x64 12.0.25 Simplified Chinese version. SHA256 value is `607e0a84c75966b00f3d12fa833e91d159e4f51ac51b6ba66f98d0c3cbefdce0`. I do not guaranteed that __offset__ value is absolutely correct in other versions. But __char string__ and __immediate values__ is highly possible to be found.
1. At file offset `+ 0x1A12090` in `libcc.dll`, stored as __char string__:
> "D75125B70767B94145B47C1CB3C0755E
> 7CCB8825C5DCE0C58ACF944E08280140
> 9A02472FAFFD1CD77864BB821AE36766
> FEEDE6A24F12662954168BFA314BD950
> 32B9D82445355ED7BC0B880887D650F5"
2. At file offset `+ 0x59D799` in `libcc.dll`, stored as __immediate value__ in a instruction:
> 0xFE 0xEA 0xBC 0x01
In decimal: `29158142`
3. At file offset `+ 0x1A11DA0` in `libcc.dll`, stored as __char string__:
> "E1CED09B9C2186BF71A70C0FE2F1E0AE
> F3BD6B75277AAB20DFAF3D110F75912B
> FB63AC50EC4C48689D1502715243A79F
> 39FF2DE2BF15CE438FF885745ED54573
> 850E8A9F40EE2FF505EB7476F95ADB78
> 3B28CA374FAC4632892AB82FB3BF4715
> FCFE6E82D03731FC3762B6AAC3DF1C3B
> C646FE9CD3C62663A97EE72DB932A301
> 312B4A7633100C8CC357262C39A2B3A6
> 4B224F5276D5EDBDF0804DC3AC4B8351
> 62BB1969EAEBADC43D2511D6E0239287
> 81B167A48273B953378D3D2080CC0677
> 7E8A2364F0234B81064C5C739A8DA28D
> C5889072BF37685CBC94C2D31D0179AD
> 86D8E3AA8090D4F0B281BE37E0143746
> E6049CCC06899401264FA471C016A96C
> 79815B55BBC26B43052609D9D175FBCD
> E455392F10E51EC162F51CF732E6BB39
> 1F56BBFD8D957DF3D4C55B71CEFD54B1
> 9C16D458757373E698D7E693A8FC3981
> 5A8BF03BA05EA8C8778D38F9873D62B4
> 460F41ACF997C30E7C3AF025FA171B5F
> 5AD4D6B15E95C27F6B35AD61875E5505
> 449B4E"
4. At file offset `+ 0x59D77F` in `libcc.dll`, stored as __immediate value__ in a instruction:
> 0x59 0x08 0x01 0x00 (in decimal )
In decimal: `67673`
5. At file offset `+ 0x1A11D8C` in `libcc.dll`, stored as __char string__:
> "92933"
Then output encrypted public key with format `"%s%d%s%d%s"`, the order is the same as it list:
> D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933
This encrypted public key can be decrypted by my another repo: [how-does-navicat-encrypt-password](https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password), while the key used is `b'23970790'`
Example:
```cmd
E:\GitHub>git clone https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password.git
...
E:\GitHub>cd how-does-navicat-encrypt-password\python3
E:\GitHub\how-does-navicat-encrypt-password\python3>python
Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from NavicatCrypto import *
>>> cipher = Navicat11Crypto(b'23970790')
>>> print(cipher.DecryptString('D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933'))
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
awIDAQAB
-----END PUBLIC KEY-----
```
* __Request Code__
It is a Base64 string that represents 256-bytes-long data, while the 256-bytes-long data is the cipher text of the __offline activation information__ encrypted by __Navicat Activation Public Key__.
* __Offline Activation Request Information__
It is just a JSON-style ASCII string which contains 3 items. Respectively they are `"K"`, `"DI"` and `"P"`, which represent __snKey__, __DeviceIdentifier__ (related with your machine), __Platform__ (Appropriately speaking, it should be OS Type).
Like:
> {"K": "xxxxxxxxxxxxxxxx", "DI": "yyyyyyyyyyyyy", "P": "WIN8"}
* __Activation Code__
It is a Base64 string that represents 256-bytes-long data, while the 256-bytes-long data is the cipher text of the __offline activation response information__ encrypted by __Navicat Activation Private Key__ (so far, we don't know official activation private key).
* __Offline Activation Response Information__
Just like __Offline Activation Request Information__, it is also a JSON-style ASCII string. But it contains 5 items. Respectively they are `"K"`, `"N"`, `"O"`, `"T"`, '`DI`'.
`"K"` and `"DI"` has the same meaning mentioned in __Offline Activation Request Information__ and must be same with the corresponding items in __Offline Activation Request Information__.
`"N"`, `"O"`, `"T"` represent __Name__, __Organization__, __Time__ respectively. __Name__ and __Organization__ are string and the type of __Time__ can be string or integer (Thanks for discoveries from @Wizr, issue #10).
`"T"` can be omitted.
* __snKey__
It is a 4-block-long string, while every block is 4-chars-long.
__snKey__ is generated by 10-bytes-long data. In order to explain it easily, I use __uint8_t data[10]__ to represent the 10-bytes-long data.
1. __data[0]__ and __data[1]__ must be `0x68` and `0x2A` respectively.
These two bytes are Naivcat signature number.
2. __data[2]__, __data[3]__ and __data[4]__ can be any byte. Just set them whatever you want.
3. __data[5]__ and __data[6]__ are related with your Navicat product language.
| Language | data[5] | data[6] | Discoverer |
|------------|-----------|-----------|-----------------|
| English | 0xAC | 0x88 | |
| 简体中文 | 0xCE | 0x32 | |
| 繁體中文 | 0xAA | 0x99 | |
| 日本語 | 0xAD | 0x82 | @dragonflylee |
| Polski | 0xBB | 0x55 | @dragonflylee |
| Español | 0xAE | 0x10 | @dragonflylee |
| Français | 0xFA | 0x20 | @Deltafox79 |
| Deutsch | 0xB1 | 0x60 | @dragonflylee |
| 한국어 | 0xB5 | 0x60 | @dragonflylee |
| Русский | 0xEE | 0x16 | @dragonflylee |
| Português | 0xCD | 0x49 | @dragonflylee |
According to symbol information in __Navicat 12 for Mac x64__, these two bytes are product language signature.
4. __data[7]__ represents Navicat product ID. (Thanks @dragonflylee and @Deltafox79)
|Product Name |Enterprise|Standard|Educational|Essentials|
|---------------------|:--------:|:------:|:---------:|:--------:|
|Navicat Report Viewer|0x0B | | | |
|Navicat Data Modeler | |0x47 |0x4A | |
|Navicat Premium |0x65 | |0x66 |0x67 |
|Navicat MySQL |0x68 |0x69 |0x6A |0x6B |
|Navicat PostgreSQL |0x6C |0x6D |0x6E |0x6F |
|Navicat Oracle |0x70 |0x71 |0x72 |0x73 |
|Navicat SQL Server |0x74 |0x75 |0x76 |0x77 |
|Navicat SQLite |0x78 |0x79 |0x7A |0x7B |
|Navicat MariaDB |0x7C |0x7D |0x7E |0x7F |
|Navicat MongoDB |0x80 |0x81 |0x82 | |
5. High 4 bits of __data[8]__ represents __major version number__. Low 4 bits is unknown, but we can use it to delay activation deadline. Possible value is `0000` or `0001`.
__Example:__
For __Navicat 12 x64__: High 4 bits must be `1100`, which is the binary of number `12`.
For __Navicat 11 x64__: High 4 bits must be `1011`, which is the binary of number `11`.
6. __data[9]__ is unknown, but you can set it `0xFD` or `0xFC` or `0xFB` if you want to use __not-for-resale license__.
According to symbol information in __Navicat 12 for Mac x64__ version:
* `0xFB` is __Not-For-Resale-30-days__ license.
* `0xFC` is __Not-For-Resale-90-days__ license.
* `0xFD` is __Not-For-Resale-365-days__ license.
* `0xFE` is __Not-For-Resale__ license.
* `0xFF` is __Site__ license.
-----------------
After that. Navicat use __DES__ with __ECB mode__ to encrypt the last 8 bytes which are from __data[2]__ to __data[9]__.
The DES key is:
```cpp
unsigned char DESKey = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
```
Then encode the 10-bytes-long data: __(Use Base32 encode if you just want a conclusion.)__
1. Regard __uint8_t data[10]__ as a 80-bits-long data.
If __uint8_t data[10]__ starts with `0x68` and `0x2A`, so the 80-bits-long data is `01011000 00101010......`
2. Divide the 80-bits-long data as 16 5-bits-long blocks.
If __uint8_t data[10]__ starts with `0x68` and `0x2A`, so the 80-bits-long data is `01011`, `00000`, `10101`, `0....`, ...
3. The values in every block are less than 32. Map them by a encode-table:
```cpp
char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
```
Then you will get a 16-char-long string.
If __uint8_t data[10]__ starts with `0x68` and `0x2A`, after encoded, it should starts with `"N"`, `"A"`, `"V"`.
4. Divide the 16-char-long string to four 4-chars-long blocks, then you get __snKey__.
## 3. Activation Process
1. Check whether __snKey__ that user inputs is legal.
2. After user clicks `Activate`, Navicat will start online activation first. If fails, users can choose offline activation.
3. Navicat will use the __snKey__ that user inputs and some information collected from user's machine to generate __Offline Activation Request Information__, then encrypt it by __Navicat Activation Public Key__ and return Base64-encoded string as __Request Code__.
4. In legal way, the __Request Code__ should be sent to Navicat official activation server by a Internet-accessible computer. And Navicat official activation server will return a legal __Activation Code__.
But now, we use keygen to play the official activation server's role.
1. According to the __Request Code__, Get `"DI"` value and `"K"` value.
2. Fill __Offline Activation Response Information__ with `"K"` value, name, organization name and `"DI"` value.
3. Encrypt __Offline Activation Response Information__ by __Navicat Activation Private Key__ and you will get 256-byte-long data.
4. Encode 256-byte-long data by Base64. The result is __Activation Code__.
5. Input __Activation Code__, then offline activation is done.
## 4. How to use
1. Download the latest release.
2. Replace __Navicat Activation Public Key__ in `navicat.exe` or `libcc.dll`.
Example:
```bash
C:\Users\DoubleSine\Github\navicat-keygen\x64\Release>navicat-patcher.exe "C:\Program Files\PremiumSoft\Navicat Premium 12" RegPrivateKey.pem
Target has been found: navicat.exe
Solution0 has been done successfully.
Keyword0 has been found: offset = +0x02048200.
Keyword1 has been found: offset = +0x006C4E29.
Keyword2 has been found: offset = +0x02047F10.
Keyword3 has been found: offset = +0x006C4E0F.
Keyword4 has been found: offset = +0x02047F04.
@Offset +0x02048200, write string:
"D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7784ADAC1C58775D2"
@Offset +0x006C4E29, write uint32_t:
0x0520738A
@Offset +0x02047F10, write string:
"20EEA059669FE4E949F414710A6C11CF68B5318B445D2D0CA85471E9DC382F271E974315F2F3645C2613BF60669584CF0A7531B1E5D2D281097E32A6B17286E8A9BDD06A17A036BC8949C9069CA3A166C251D325A7EAF81DB272CF4E277CC487D6BACB83C1059BBC0D45F49CBB6EA2C0E8033039CA575A939C8FF705FFA1FCA9DD53FD10447EE8D2F48128298E5DAB483F7A1500C455AFE33BB7FB280C39686CC45C7EC8C024EBF1089040D6636FF02E0E2A61092168A5CB105DBF3F5C6EB5C10D7392A46254B6E34DD4365F778ED199A52C6AB931416453CB8A677C90A6674BA5D546B25CDEC9C2E0B067729A6067FB1106B3BF7BBD56B888B5321484779570040B2095CD410D3B33F77BCFC9C24CA5A60003E342F110D35AA4714BFC8B3D9840BB3C8C286C5E353D5DEC4351A27E6E403AED2A21BBD0EA4194FB65B37F301A2E86BF9E9F8BBBFAA2400410ABC7833B3CCAAC66F27F873990E2D97BB36A70A5C9E4E3647C3AD0FAA716820A0BDC15CA8D7392"
@Offset +0x006C4E0F, write uint32_t:
0x00004708
@Offset +0x02047F04, write string:
"64308"
Solution1 has been done successfully.
```
3. Then in console:
```bash
C:\Users\DoubleSine\Github\navicat-keygen\x64\Release>navicat-keygen.exe RegPrivateKey.pem
```
You will be asked to select Navicat product, language and input major version number. After that an randomly generated __snKey__ will be generated.
__Example:__
```bash
C:\Users\DoubleSine\Github\navicat-keygen\x64\Release>navicat-keygen.exe RegPrivateKey.pem
Select Navicat product:
0. DataModeler
1. Premium
2. MySQL
3. PostgreSQL
4. Oracle
5. SQLServer
6. SQLite
7. MariaDB
8. MongoDB
9. ReportViewer
(input index)> 1
Select product language:
0. English
1. Simplified Chinese
2. Traditional Chinese
3. Japanese
4. Polish
5. Spanish
6. French
7. German
8. Korean
9. Russian
10. Portuguese
(input index)> 0
(input major version number)> 12
Serial number:
NAVI-2ORL-MJQC-7WFO
Your name:
```
You can use this __snKey__ to activate your Navicat preliminarily.
* `<Navicat installation path>`: The full path to Navicat installation folder.
Then you will be asked to input `Your name` and `Your organization`. Just set them whatever you want, but not too long.
__This parameter must be specified.__
* `[RSA-2048 PEM file]`: The full path or relative path to a RSA-2048 private key file.
__Example:__
__This parameter is optional.__ If not specified, `navicat-patcher.exe` will generate a new RSA-2048 private key file `RegPrivateKey.pem` at current directory.
```bash
Your name: DoubleLabyrinth
Your organization: DoubleLabyrinth
Input request code (in Base64), input empty line to end:
```
__Example: (in cmd.exe)__
```
navicat-patcher.exe "C:\Program Files\PremiumSoft\Navicat Premium 12" .\RegPrivateKey.pem
```
It has been tested on __Navicat Premium 12.1.11 Simplified Chinese version__. The following is an example of output.
```
MESSAGE: Navicat.exe has been found.
MESSAGE: libcc.dll has been found.
MESSAGE: [Solution0] Keyword has been found: offset = +0x029a4b9c.
MESSAGE: [Solution1] Keywords[0] has been found: offset = +0x02294960.
MESSAGE: [Solution1] Keywords[1] has been found: offset = +0x0074bd29.
MESSAGE: [Solution1] Keywords[2] has been found: offset = +0x02294670.
MESSAGE: [Solution1] Keywords[3] has been found: offset = +0x0074bd0f.
MESSAGE: [Solution1] Keywords[4] has been found: offset = +0x02294664.
MESSAGE: [Solution2] Keywords[0] has been found: offset = +0x01643118.
MESSAGE: [Solution2] Keywords[1] has been found: offset = +0x016437c1.
MESSAGE: [Solution2] Keywords[2] has been found: offset = +0x01643ed0.
MESSAGE: [Solution2] Keywords[3] has been found: offset = +0x016445df.
MESSAGE: [Solution2] Keywords[4] has been found: offset = +0x01644cee.
MESSAGE: [Solution2] Keywords[5] has been found: offset = +0x016453fd.
MESSAGE: [Solution2] Keywords[6] has been found: offset = +0x01645b0b.
MESSAGE: [Solution2] Keywords[7] has been found: offset = +0x01646217.
MESSAGE: [Solution2] Keywords[8] has been found: offset = +0x01646926.
MESSAGE: [Solution2] Keywords[9] has been found: offset = +0x01647035.
...
...
Your RSA public key:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtOZGsX7UoDPuxCfEuw4i
yWDASpwaN19GaPNrTlWz6K7MKXGrAQpYD5gNZ8nGdfRgp52TErTHSNoRjgfpxGqK
ApPUISsIanGMcyf/H2b8pGuz1oF19kVKSyZTPaVLbE+1Cw7FULbI04bc64XnWSHo
aQAXrYKGpC7oDomRGMtx28figu3AHAk1UQrcCvE3+0ITTA7X8xaRwz6+gb+uLgCd
iXyRYDodG8i+kk1YIt3f2mt7jH+uEHqBYjIfvvo6g5MZz4KNz7Ewc6+sDyO8bmlX
eFnHo6YAgCcaHVvVtGNCxCd1O5wWHvUN985HHQYnFr7qzJaL9cPb735pP2hb0IXe
ywIDAQAB
-----END PUBLIC KEY-----
MESSAGE: Navicat.exe has been backed up successfully.
MESSAGE: libcc.dll has been backed up successfully.
......
......
......
@+0x016ED490: 83 F0 49 --> 83 F0 49
@+0x016EDB9F: 83 F0 44 --> 83 F0 44
@+0x016EE2AE: 83 F0 41 --> 83 F0 41
@+0x016EE9BD: 83 F0 51 --> 83 F0 51
@+0x016EF0CB: 83 F0 41 --> 83 F0 41
@+0x016EF7D7: 83 F0 42 --> 83 F0 42
Solution0 has been done successfully.
Solution1 has been done successfully.
Solution2 has been done successfully.
```
3. Then use `navicat-keygen.exe` to generate __snKey__ and __Activation Code__
```
navicat-keygen.exe <-bin|-text> [-adv] <RSA-2048 PrivateKey(PEM file)>
```
* `<-bin|-text>`: Must be `-bin` or `-text`.
If `-bin` is specified, `navicat-keygen.exe` will finally generate `license_file`. It is used for Navicat old activation method only.
If `-text` is specified, `navicat-keygen.exe` will finally generate a Base64-style string which is __Activation Code__. It is used for Navicat new activation method.
__This parameter must be specified.__
* `[-adv]`: Enable advanced mode.
__This parameter is optional.__ If specified, `navicat-keygen.exe` will ask you input Navicat product ID number, language signature numbers. It is for future use generally.
* `<RSA-2048 PrivateKey(PEM file)>`: The full path or relative path to a RSA-2048 private key file.
After that, you will be asked to input the request code. Now __DO NOT CLOSE KEYGEN__.
__This parameter must be specified.__
4. Disconnect network and open Navicat. Find and click `Registration`. Fill `Registration Key` by __snKey__ that keygen gave. Then click `Activate`.
__Example: (in cmd.exe)__
5. Generally online activation will failed and Navicat will ask you do `Manual Activation`, just choose it.
```bash
navicat-keygen.exe -text .\RegPrivateKey.pem
```
6. Copy your request code and paste it in keygen. Input empty line to tell keygen that your input ends.
You will be asked to select Navicat product, language and input major version number. After that an randomly generated __snKey__ will be given.
__Example:__
```
Select Navicat product:
1. DataModeler
2. Premium
3. MySQL
4. PostgreSQL
5. Oracle
6. SQLServer
7. SQLite
8. MariaDB
9. MongoDB
10. ReportViewer
```bash
Your name: DoubleLabyrinth
Your organization: DoubleLabyrinth
Input request code (in Base64), input empty line to end:
J517hWX/29aQMITp5UfS/FarX6q8pFKmW1Cl7Nt2UpvmVxhZDn5YBdPw/htDsBbXacNpLtorxfZM
Jxv/SZMqHsr7/JqexaaAEfzn5mo6zpatcSRArFoQh2h9IcnjRqziZ8yihkMUesKgsWXvVXMEYk7u
D1rc/GhzTf6/2kn0gTKRAlJGsxt+e1p6SOhPuMyzt3AyNvJ2s0o607Nub7vC37FOJF69jN1nOvej
uy3bmr2HSPFsh10WqUUYi6F1lzzYIq6nDjQ5CeKrCT2jPfrhoFtRbwJyYDxQOxU/adrm1bg8VjrK
XNGeKS67R1nrbBM03IKzPP3pxEGFut4gZdskRw==
(Input index)> 1
Request Info:
{"K":"NAVI2ORLMJQC7WFO", "DI":"Y2eJk9vrvfGudPG7Mbdn", "P":"WIN 8"}
Select product language:
1. English
2. Simplified Chinese
3. Traditional Chinese
4. Japanese
5. Polish
6. Spanish
7. French
8. German
9. Korean
10. Russian
11. Portuguese
Response Info:
{"K":"NAVI2ORLMJQC7WFO","DI":"Y2eJk9vrvfGudPG7Mbdn","N":"DoubleLabyrinth","O":"DoubleLabyrinth","T":1534251096}
(Input index)> 1
License:
iFvqOkwsVq/Wutw/hELC5dyweDahl2v8R3bMWcNXS/V49CjpaDEJIHtRLddu/ldg
WVGdwdh3aHVJ5k8I6RkUicDvZJH2vLn3o5O9Q/A5ThED0AoYnwu0DLa1gEUlRO68
4+uXwo1nZ+xtjLOSxrVh+fLkcvKtd5RDgHS5957qUwjoYBiuePGomtt9mF4NtfaF
E7pnfP/OGp8xtWdUfGZ1fESWttKcVXcmOpyF4uTWtluUhFHRk+ZueST/ETyaSx33
Kv/zSLBbK8KaVqS2sh5WBs8xVaYxDV08EC8uCCp1euTFOPG5nlrcf7iyILsh6I67
xfGRliXvM67jvsxqD200fg==
(Input major version number, range: 0 ~ 15, default: 12)> 12
```
Serial number:
NAVA-DHCN-P2OI-DV46
Your name:
```
You can use this __snKey__ to activate your Navicat preliminarily.
Then you will be asked to input `Your name` and `Your organization`. Just set them whatever you want, but not too long.
```bash
Your name: DoubleLabyrinth
Your organization: DoubleLabyrinth
Input request code (in Base64), input empty line to end:
```
After that, you will be asked to input the request code. Now __DO NOT CLOSE KEYGEN__.
4. __Disconnect your network__ and open Navicat. Find and click `Registration`. Fill `Registration Key` by __snKey__ that the keygen gave and click `Activate`.
5. Generally online activation will failed and Navicat will ask you do `Manual Activation`, just choose it.
6. Copy your request code and paste it in the keygen. Input empty line to tell the keygen that your input ends.
```bash
Your name: DoubleLabyrinth
Your organization: DoubleLabyrinth
Input request code (in Base64), input empty line to end:
q/cv0bkTrG1YDkS+fajFdi85bwNVBD/lc5jBYJPOSS5bfl4DdtnfXo+RRxdMjJtEcYQnvLPi2LF0
OB464brX9dqU29/O+A3qstSyhBq5//iezxfu2Maqca4y0rVtZgQSpEnZ0lBNlqKXv7CuTUYCS1pm
tEPgwJysQTMUZf7tu5MR0cQ+hY/AlyQ9iKrQAMhHklqZslaisi8VsnoIqH56vfTyyUwUQXrFNc41
qG5zZNsXu/NI79JOo7qTvcFHQT/k5cTadbKTxY+9c5eh+nF3JR7zEa2BDDfdQRLNvy4DTSyxdYXd
sAk/YPU+JdWI+8ELaa0SuAuNzr5fEkD6NDSG2A==
Request Info:
{"K":"NAVADHCNP2OIDV46", "DI":"Y2eJk9vrvfGudPG7Mbdn", "P":"WIN 8"}
Response Info:
{"K":"NAVADHCNP2OIDV46","DI":"Y2eJk9vrvfGudPG7Mbdn","N":"DoubleLabyrinth","O":"DoubleLabyrinth","T":1537630251}
License:
oyoMYr9cfVGXeT7F1dqBwHsB/vvWj6SUL6aR+Kzb0lm5IyEj1CgovuSq+qMzFfx+
oHMFaGKFg6viOY2hfJcrO2Vdq0hXZS/B/Ie3jBS2Ov37v8e3ufVajaH+wLkmEpLd
xppCVLkDQjIHYR2IPz5s/L/RuWqDpEY4TPmGFF6q+xQMnqQA3vXPyG+JYMARXLru
Y1gCDLN30v3DpyOeqKmFjUqiHK5h8s0NYiH2OpMyaCpi12JsF23miP89ldQp3+SJ
8moo0cNGy7sFp2gX9ol2zVoo7qxfYlLl03f7CALJ6im0sx4yBsmlzFDdvpQUbXk8
YZ5rT4LML2Fx6Wgnnklb5g==
```
7. Finally, you will get __Activation Code__ which looks like a Base64 string. Just copy it and paste it in Navicat `Manual Activation` window, then click `Activate`. If nothing wrong, activation should be done successfully.
7. Finally, you will get activation code which looks like a Base64 string. Just copy it and paste it in Navicat `Manual Activation` window, then click `Activate`. If nothing wrong, activation should be done successfully.
+159 -371
View File
@@ -1,392 +1,180 @@
# Navicat Keygen
这份repo将会告诉你Navicat是怎么完成离线激活的。
这份repo将会告诉你Navicat是怎么完成离线激活的。
## 1. 关键词解释.
[注册机是怎么工作的?](HOW_DOES_IT_WORK.zh-CN.md)
* __Navicat激活公钥__
## 如何使用这个注册机
这是一个2048位的RSA公钥,Navicat使用这个公钥来完成相关激活信息的加密和解密
1. [从这里](https://github.com/DoubleLabyrinth/navicat-keygen/releases)下载最新的release
这个公钥被作为 __RCData__ 类型的资源储存在 __navicat.exe__ 当中。资源名为`"ActivationPubKey"`。你可以使用一个叫[Resource Hacker](http://www.angusj.com/resourcehacker/)的软件来查看它。这个公钥的具体内容为:
2. 使用`navicat-patcher.exe`替换掉`navicat.exe``libcc.dll`里的Navicat激活公钥。
> -----BEGIN PUBLIC KEY-----
> MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
> qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
> a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
> R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
> WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
> YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
> awIDAQAB
> -----END PUBLIC KEY-----
```
navicat-patcher.exe <Navicat installation path> [RSA-2048 PEM file]
```
如果您有相应的私钥并乐意公开的话欢迎联系我,我将非常感谢您的慷慨。
__注意:__
__Navicat Premium 12.0.25__ 开始,Navicat不再从`navicat.exe`的资源中加载私钥。事实上,公钥转为从`libcc.dll`中加载,并且已经被加密。与此同时,为了防止被轻松地替换,加密的公钥被分到5个地方储存:
以下内容是从 __Navicat Premium x64 12.0.25 简体中文版__`libcc.dll`中发现的,`libcc.dll`的SHA256值为`607e0a84c75966b00f3d12fa833e91d159e4f51ac51b6ba66f98d0c3cbefdce0`。我不保证在Navicat的其他版本中相关偏移量和下述的相同,但相关的 __字符串__ 以及 __立即数__ 是很可能找得到的。
1.`libcc.dll`中,文件偏移量`+0x1A12090`的地方,储存了加密公钥的第一部分,以 __字符串__ 的形式储存:
> "D75125B70767B94145B47C1CB3C0755E
> 7CCB8825C5DCE0C58ACF944E08280140
> 9A02472FAFFD1CD77864BB821AE36766
> FEEDE6A24F12662954168BFA314BD950
> 32B9D82445355ED7BC0B880887D650F5"
2.`libcc.dll`中,文件偏移量`+0x59D799`的地方,储存了加密公钥的第二部分,以 __立即数__ 的形式储存在一条指令中:
> 0xFE 0xEA 0xBC 0x01
相应十进制为: `29158142`
3.`libcc.dll`中,文件偏移量`+0x1A11DA0`的地方,储存了加密公钥的第三部分,以 __字符串__ 的形式储存:
> "E1CED09B9C2186BF71A70C0FE2F1E0AE
> F3BD6B75277AAB20DFAF3D110F75912B
> FB63AC50EC4C48689D1502715243A79F
> 39FF2DE2BF15CE438FF885745ED54573
> 850E8A9F40EE2FF505EB7476F95ADB78
> 3B28CA374FAC4632892AB82FB3BF4715
> FCFE6E82D03731FC3762B6AAC3DF1C3B
> C646FE9CD3C62663A97EE72DB932A301
> 312B4A7633100C8CC357262C39A2B3A6
> 4B224F5276D5EDBDF0804DC3AC4B8351
> 62BB1969EAEBADC43D2511D6E0239287
> 81B167A48273B953378D3D2080CC0677
> 7E8A2364F0234B81064C5C739A8DA28D
> C5889072BF37685CBC94C2D31D0179AD
> 86D8E3AA8090D4F0B281BE37E0143746
> E6049CCC06899401264FA471C016A96C
> 79815B55BBC26B43052609D9D175FBCD
> E455392F10E51EC162F51CF732E6BB39
> 1F56BBFD8D957DF3D4C55B71CEFD54B1
> 9C16D458757373E698D7E693A8FC3981
> 5A8BF03BA05EA8C8778D38F9873D62B4
> 460F41ACF997C30E7C3AF025FA171B5F
> 5AD4D6B15E95C27F6B35AD61875E5505
> 449B4E"
4.`libcc.dll`中,文件偏移量`+0x59D77F`的地方,储存了加密公钥的第四部分,以 __立即数__ 的形式储存在一条指令中:
> 0x59 0x08 0x01 0x00
相应十进制为: `67673`
5.`libcc.dll`中,文件偏移量`+0x1A11D8C`的地方,储存了加密公钥的第五部分,以 __字符串__ 的形式储存:
> "92933"
这五部分按照`"%s%d%s%d%s"`的形式输出则为加密的公钥,顺序和上述的顺序相同,具体的输出为:
> D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933
这个加密的公钥可以用我的另外一个repo([how-does-navicat-encrypt-password](https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password))解密,其中密钥为`b'23970790'`
例如:
```cmd
E:\GitHub>git clone https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password.git
...
E:\GitHub>cd how-does-navicat-encrypt-password\python3
E:\GitHub\how-does-navicat-encrypt-password\python3>python
Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from NavicatCrypto import *
>>> cipher = Navicat11Crypto(b'23970790')
>>> print(cipher.DecryptString('D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933'))
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
awIDAQAB
-----END PUBLIC KEY-----
```
* __请求码__
这是一个Base64编码的字符串,代表的是长度为256字节的数据。这256字节的数据是 __离线激活信息__ 用 __Navicat激活公钥__ 加密的密文。
* __离线激活请求信息__
这是一个JSON风格的字符串。它包含了3个Key:`"K"`、`"DI"`和`"P"`,分别代表 __序列号__、__设备识别码__(与你的电脑硬件信息相关)和 __平台__ (其实就是操作系统类型)。
例如:
> {"K": "xxxxxxxxxxxxxxxx", "DI": "yyyyyyyyyyyyy", "P": "WIN8"}
* __激活码__
这是一个Base64编码的字符串,代表的是长度为256字节的数据。这256字节的数据是 __离线激活回复信息__ 用 __Navicat激活私钥__ 加密的密文,目前我们不知道官方的 __Navicat激活私钥__。
* __离线激活回复信息__
和 __离线激活请求信息__ 一样,它也是一个JSON风格的字符串。但是它包含5个Key,分别为`"K"`、`"N"`、`"O"`、`"T"`和`"DI"`.
`"K"` 和 `"DI"` 的意义与 __离线激活请求信息__ 中的相同,且Value必须与 __离线激活请求信息__ 中的相同。
`"N"`、`"O"`、`"T"` 分别代表 __注册名__、__组织__、__授权时间__。__注册名__ 和 __组织__ 的值类型为字符串,__授权时间__ 的值类型可以为字符串或整数(感谢@Wizr在issue #10的报告)。
`"T"` 可以被省略。
* __序列号__
这是一个被分为了4个部分的字符串,其中每个部分都是4个字符长。
__序列号__ 是通过10个字节的数据来生成的。为了表达方便,我用 __uint8_t data[10]__ 来表示这10个字节。
1. __data[0]__ 和 __data[1]__ 必须分别为 `0x68` 和 `0x2A`。
这两个字节时Navicat的标志数。
2. __data[2]__、__data[3]__ 和 __data[4]__ 可以是任意字节,你想设成什么都行。
3. __data[5]__ 和 __data[6]__ 与你Navicat的语言有关,值如下:
| 语言类型 | data[5] | data[6] | 发现者 |
|------------|-----------|-----------|-----------------|
| English | 0xAC | 0x88 | |
| 简体中文 | 0xCE | 0x32 | |
| 繁體中文 | 0xAA | 0x99 | |
| 日本語 | 0xAD | 0x82 | @dragonflylee |
| Polski | 0xBB | 0x55 | @dragonflylee |
| Español | 0xAE | 0x10 | @dragonflylee |
| Français | 0xFA | 0x20 | @Deltafox79 |
| Deutsch | 0xB1 | 0x60 | @dragonflylee |
| 한국어 | 0xB5 | 0x60 | @dragonflylee |
| Русский | 0xEE | 0x16 | @dragonflylee |
| Português | 0xCD | 0x49 | @dragonflylee |
根据 __Navicat 12 for Mac x64__ 版本残留的符号信息可知这两个字节为 __Product Signature__。
4. __data[7]__ 是Navicat产品ID。(感谢 @dragonflylee 和 @Deltafox79)这是 __commercial license__ 还是 __non-commercial license__。
|Product Name |Enterprise|Standard|Educational|Essentials|
|---------------------|:--------:|:------:|:---------:|:--------:|
|Navicat Report Viewer|0x0B | | | |
|Navicat Data Modeler | |0x47 |0x4A | |
|Navicat Premium |0x65 | |0x66 |0x67 |
|Navicat MySQL |0x68 |0x69 |0x6A |0x6B |
|Navicat PostgreSQL |0x6C |0x6D |0x6E |0x6F |
|Navicat Oracle |0x70 |0x71 |0x72 |0x73 |
|Navicat SQL Server |0x74 |0x75 |0x76 |0x77 |
|Navicat SQLite |0x78 |0x79 |0x7A |0x7B |
|Navicat MariaDB |0x7C |0x7D |0x7E |0x7F |
|Navicat MongoDB |0x80 |0x81 |0x82 | |
5. __data[8]__ 的高4位代表 __版本号__。低4位未知,但可以用来延长激活期限,可取的值有`0000`和`0001`。
例如:
对于 __Navicat 12__: 高4位必须是`1100`,为`12`的二进制形式。
对于 __Navicat 11__: 高4位必须是`1011`,为`11`的二进制形式。
6. __data[9]__ 目前暂未知,但如果你想要 __not-for-resale license__ 的话可以设成`0xFD`、`0xFC`或`0xFB`。
根据 __Navicat 12 for Mac x64__ 版本残留的符号信息可知:
* `0xFB`是 __Not-For-Resale-30-days__ license.
* `0xFC`是 __Not-For-Resale-90-days__ license.
* `0xFD`是 __Not-For-Resale-365-days__ license.
* `0xFE`是 __Not-For-Resale__ license.
* `0xFF`是 __Site__ license.
-----------------
之后Navicat使用 __ECB__ 模式的 __DES__ 算法来加密 __data[10]__ 的后8字节,也就是 __data[2]__ 到 __data[9]__ 的部分。
相应的DES密钥为:
```cpp
unsigned char DESKey = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
```
之后编码 __data[10]__ __(使用Base32编码)__
1. 将 __data[10]__ 视作为一个80位长的数据。
如果 __data[10]__ 以`0x68`和`0x2A`开始的话,80位长的数据应该为`01011000 00101010......`
2. 将80位长的数据分为16个5位长的块。
如果 __data[10]__ 以`0x68`和`0x2A`开始的话,16个5位长的块应为`01011`、 `00000`、`10101`、`0....`
3. 这样每一块的值就会小于32。将它们通过下表编码:
```cpp
char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
```
你就会得到一个16字节的字符串。
如果 __uint8_t data[10]__ 以`0x68`和`0x2A`开始的话,编码之后应该以`"N"`、`"A"`、`"V"`打头。
4. 将16字节的字符串分成4个4字节的小块,然后用`"-"`连接就可以得到 __序列号__。
## 3. 激活过程
1. 检查用户输入的 __序列号__ 是否合法。
2. 在用户点击了`激活`按钮之后,Navicat会先尝试在线激活。如果失败,用户可以选择离线激活。
3. Navicat会使用用户输入的 __序列号__ 以及从用户电脑收集来的信息生成 __离线激活请求信息__,然后用 __Navicat激活公钥__ 加密,并将密文用Base64编码,最后得到 __请求码__。
4. 正常流程下,__请求码__ 应该通过可访问Internet的电脑发送给Navicat的官方激活服务器。之后Navicat的官方激活服务器会返回一个合法的 __激活码__。
但现在我们使用注册机来扮演官方激活服务器的角色,只是Navicat软件里的激活公钥得换成自己的公钥:
1. 根据 __请求码__, 获得`"DI"`值和`"K"`值。
2. 用`"K"`值、用户名、组织名和`"DI"`值填写 __离线激活回复信息__。
3. 用自己的2048位RSA私钥加密 __离线激活回复信息__,你将会得到256字节的密文。
4. 用Base64编码这256字节的密文,就可以得到 __激活码__。
5. 在Navicat软件中填入 __激活码__ 即可完成离线激活。
## 4. 如何使用这个Keygen
1. 下载最新的release。
2. 替换掉`navicat.exe`或`libcc.dll`里的 __Navicat激活公钥__。
```bash
navicat-patcher.exe <Navicat 安装路径> <RSA私钥文件>
```
RSA私钥文件可以为RegPrivateKey.pem
例如:
```bash
C:\Users\DoubleSine\Github\navicat-keygen\x64\Release>navicat-patcher.exe "C:\Program Files\PremiumSoft\Navicat Premium 12" RegPrivateKey.pem
Target has been found: navicat.exe
Solution0 has been done successfully.
Keyword0 has been found: offset = +0x02048200.
Keyword1 has been found: offset = +0x006C4E29.
Keyword2 has been found: offset = +0x02047F10.
Keyword3 has been found: offset = +0x006C4E0F.
Keyword4 has been found: offset = +0x02047F04.
@Offset +0x02048200, write string:
"D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7784ADAC1C58775D2"
@Offset +0x006C4E29, write uint32_t:
0x0520738A
@Offset +0x02047F10, write string:
"20EEA059669FE4E949F414710A6C11CF68B5318B445D2D0CA85471E9DC382F271E974315F2F3645C2613BF60669584CF0A7531B1E5D2D281097E32A6B17286E8A9BDD06A17A036BC8949C9069CA3A166C251D325A7EAF81DB272CF4E277CC487D6BACB83C1059BBC0D45F49CBB6EA2C0E8033039CA575A939C8FF705FFA1FCA9DD53FD10447EE8D2F48128298E5DAB483F7A1500C455AFE33BB7FB280C39686CC45C7EC8C024EBF1089040D6636FF02E0E2A61092168A5CB105DBF3F5C6EB5C10D7392A46254B6E34DD4365F778ED199A52C6AB931416453CB8A677C90A6674BA5D546B25CDEC9C2E0B067729A6067FB1106B3BF7BBD56B888B5321484779570040B2095CD410D3B33F77BCFC9C24CA5A60003E342F110D35AA4714BFC8B3D9840BB3C8C286C5E353D5DEC4351A27E6E403AED2A21BBD0EA4194FB65B37F301A2E86BF9E9F8BBBFAA2400410ABC7833B3CCAAC66F27F873990E2D97BB36A70A5C9E4E3647C3AD0FAA716820A0BDC15CA8D7392"
@Offset +0x006C4E0F, write uint32_t:
0x00004708
@Offset +0x02047F04, write string:
"64308"
Solution1 has been done successfully.
```
3. 接下来,还是在console中:
```bash
navicat-keygen.exe RegPrivateKey.pem
```
你会被要求选择Navicat产品类别、语言以及输入主版本号。之后会随机生成一个 __序列号__。
例如:
```bash
C:\Users\DoubleSine\Github\navicat-keygen\x64\Release>navicat-keygen.exe RegPrivateKey.pem
Select Navicat product:
1. DataModeler
2. Premium
3. MySQL
4. PostgreSQL
5. Oracle
6. SQLServer
7. SQLite
8. MariaDB
9. MongoDB
10. ReportViewer
(input index)> 1
Select product language:
1. English
2. Simplified Chinese
3. Traditional Chinese
4. Japanese
5. Polish
6. Spanish
7. French
8. German
9. Korean
10. Russian
11. Portuguese
(input index)> 0
(input major version number)> 12
Serial number:
NAVI-2ORL-MJQC-7WFO
Your name:
```
你可以使用这个序列号暂时激活Navicat。
接下来你会被要求输入`用户名`和`组织名`;请随便填写,但不要太长。
* `<Navicat installation path>`: Navicat的完整安装路径。
例如:
__这个参数必须指定。__
```bash
Your name: DoubleLabyrinth
Your organization: DoubleLabyrinth
Input request code (in Base64), input empty line to end:
```
* `[RSA-2048 PEM file]`: RSA-2048私钥文件的完整路径或相对路径。
之后你会被要求填入 __请求码__。注意 __不要关闭命令行__.
__这个参数是可选的。__ 如果未指定,`navicat-patcher.exe`将会在当前目录生成一个新的RSA-2048私钥文件。
4. 断开网络并打开 Navicat Premium。找到`注册`窗口,并填入keygen给你的 __序列号__。然后点击`激活`按钮。
__例如:(在cmd.exe中)__
5. 一般来说在线激活肯定会失败,这时候Navicat会询问你是否`手动激活`,直接选吧。
```
navicat-patcher.exe "C:\Program Files\PremiumSoft\Navicat Premium 12" .\RegPrivateKey.pem
```
__Navicat Premium 12.1.7 简体中文版已通过测试__。下面将是一份样例输出。
6. 在`手动激活`窗口你会得到一个请求码,复制它并把它粘贴到keygen里。最后别忘了连按至少两下回车结束输入。
```
MESSAGE: Navicat.exe has been found.
MESSAGE: libcc.dll has been found.
例如:
MESSAGE: [Solution0] Keyword has been found: offset = +0x0297a6e0.
MESSAGE: [Solution1] Keywords[0] has been found: offset = +0x02057530.
MESSAGE: [Solution1] Keywords[1] has been found: offset = +0x006c4f89.
MESSAGE: [Solution1] Keywords[2] has been found: offset = +0x02057240.
MESSAGE: [Solution1] Keywords[3] has been found: offset = +0x006c4f6f.
MESSAGE: [Solution1] Keywords[4] has been found: offset = +0x0205722c.
```bash
Your name: DoubleLabyrinth
Your organization: DoubleLabyrinth
Input request code (in Base64), input empty line to end:
J517hWX/29aQMITp5UfS/FarX6q8pFKmW1Cl7Nt2UpvmVxhZDn5YBdPw/htDsBbXacNpLtorxfZM
Jxv/SZMqHsr7/JqexaaAEfzn5mo6zpatcSRArFoQh2h9IcnjRqziZ8yihkMUesKgsWXvVXMEYk7u
D1rc/GhzTf6/2kn0gTKRAlJGsxt+e1p6SOhPuMyzt3AyNvJ2s0o607Nub7vC37FOJF69jN1nOvej
uy3bmr2HSPFsh10WqUUYi6F1lzzYIq6nDjQ5CeKrCT2jPfrhoFtRbwJyYDxQOxU/adrm1bg8VjrK
XNGeKS67R1nrbBM03IKzPP3pxEGFut4gZdskRw==
Your RSA public key:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtOZGsX7UoDPuxCfEuw4i
yWDASpwaN19GaPNrTlWz6K7MKXGrAQpYD5gNZ8nGdfRgp52TErTHSNoRjgfpxGqK
ApPUISsIanGMcyf/H2b8pGuz1oF19kVKSyZTPaVLbE+1Cw7FULbI04bc64XnWSHo
aQAXrYKGpC7oDomRGMtx28figu3AHAk1UQrcCvE3+0ITTA7X8xaRwz6+gb+uLgCd
iXyRYDodG8i+kk1YIt3f2mt7jH+uEHqBYjIfvvo6g5MZz4KNz7Ewc6+sDyO8bmlX
eFnHo6YAgCcaHVvVtGNCxCd1O5wWHvUN985HHQYnFr7qzJaL9cPb735pP2hb0IXe
ywIDAQAB
-----END PUBLIC KEY-----
Request Info:
{"K":"NAVI2ORLMJQC7WFO", "DI":"Y2eJk9vrvfGudPG7Mbdn", "P":"WIN 8"}
Response Info:
{"K":"NAVI2ORLMJQC7WFO","DI":"Y2eJk9vrvfGudPG7Mbdn","N":"DoubleLabyrinth","O":"DoubleLabyrinth","T":1534251096}
MESSAGE: Navicat.exe has been backed up successfully.
MESSAGE: libcc.dll has been backed up successfully.
License:
iFvqOkwsVq/Wutw/hELC5dyweDahl2v8R3bMWcNXS/V49CjpaDEJIHtRLddu/ldg
WVGdwdh3aHVJ5k8I6RkUicDvZJH2vLn3o5O9Q/A5ThED0AoYnwu0DLa1gEUlRO68
4+uXwo1nZ+xtjLOSxrVh+fLkcvKtd5RDgHS5957qUwjoYBiuePGomtt9mF4NtfaF
E7pnfP/OGp8xtWdUfGZ1fESWttKcVXcmOpyF4uTWtluUhFHRk+ZueST/ETyaSx33
Kv/zSLBbK8KaVqS2sh5WBs8xVaYxDV08EC8uCCp1euTFOPG5nlrcf7iyILsh6I67
xfGRliXvM67jvsxqD200fg==
......
......
......
```
Solution0 has been done successfully.
Solution1 has been done successfully.
```
3. 接下来使用`navicat-keygen.exe`来生成序列号和激活码
```
navicat-keygen.exe <-bin|-text> [-adv] <RSA-2048 PrivateKey(PEM file)>
```
* `<-bin|-text>`: 必须是`-bin`或`-text`。
如果指定了`-bin``navicat-keygen.exe`最终将生成`license_file`文件。这个选项是给Navicat旧激活方式使用的。
如果指定了`-text``navicat-keygen.exe`最终将生成Base64样式的激活码。这个选项是给Navicat新激活方式使用的。
__这个参数必须指定。__
* `[-adv]`: 开启高级模式。
__这个参数是可选的。__ 如果指定了这个参数,`navicat-keygen.exe`将会要求你手工填写产品ID号、语言标识号。这个选项一般是给以后用的。
* `<RSA-2048 PrivateKey(PEM file)>`: RSA-2048私钥文件的完整路径或相对路径。
__这个参数必须指定。__
__例如:(在cmd.exe中)__
```bash
navicat-keygen.exe -text .\RegPrivateKey.pem
```
你会被要求选择Navicat产品类别、语言以及输入主版本号。之后会随机生成一个序列号。
```
Select Navicat product:
1. DataModeler
2. Premium
3. MySQL
4. PostgreSQL
5. Oracle
6. SQLServer
7. SQLite
8. MariaDB
9. MongoDB
10. ReportViewer
(Input index)> 1
Select product language:
1. English
2. Simplified Chinese
3. Traditional Chinese
4. Japanese
5. Polish
6. Spanish
7. French
8. German
9. Korean
10. Russian
11. Portuguese
(Input index)> 1
(Input major version number, range: 0 ~ 15, default: 12)> 12
Serial number:
NAVA-DHCN-P2OI-DV46
Your name:
```
你可以使用这个序列号暂时激活Navicat。
接下来你会被要求输入`用户名`和`组织名`;请随便填写,但不要太长。
```bash
Your name: DoubleLabyrinth
Your organization: DoubleLabyrinth
Input request code (in Base64), input empty line to end:
```
之后你会被要求填入请求码。注意 __不要关闭命令行__.
4. __断开网络__ 并打开Navicat。找到`注册`窗口,并填入keygen给你的序列号。然后点击`激活`按钮。
5. 一般来说在线激活肯定会失败,这时候Navicat会询问你是否`手动激活`,直接选吧。
6. 在`手动激活`窗口你会得到一个请求码,复制它并把它粘贴到keygen里。最后别忘了连按至少两下回车结束输入。
```bash
Your name: DoubleLabyrinth
Your organization: DoubleLabyrinth
Input request code (in Base64), input empty line to end:
q/cv0bkTrG1YDkS+fajFdi85bwNVBD/lc5jBYJPOSS5bfl4DdtnfXo+RRxdMjJtEcYQnvLPi2LF0
OB464brX9dqU29/O+A3qstSyhBq5//iezxfu2Maqca4y0rVtZgQSpEnZ0lBNlqKXv7CuTUYCS1pm
tEPgwJysQTMUZf7tu5MR0cQ+hY/AlyQ9iKrQAMhHklqZslaisi8VsnoIqH56vfTyyUwUQXrFNc41
qG5zZNsXu/NI79JOo7qTvcFHQT/k5cTadbKTxY+9c5eh+nF3JR7zEa2BDDfdQRLNvy4DTSyxdYXd
sAk/YPU+JdWI+8ELaa0SuAuNzr5fEkD6NDSG2A==
Request Info:
{"K":"NAVADHCNP2OIDV46", "DI":"Y2eJk9vrvfGudPG7Mbdn", "P":"WIN 8"}
Response Info:
{"K":"NAVADHCNP2OIDV46","DI":"Y2eJk9vrvfGudPG7Mbdn","N":"DoubleLabyrinth","O":"DoubleLabyrinth","T":1537630251}
License:
oyoMYr9cfVGXeT7F1dqBwHsB/vvWj6SUL6aR+Kzb0lm5IyEj1CgovuSq+qMzFfx+
oHMFaGKFg6viOY2hfJcrO2Vdq0hXZS/B/Ie3jBS2Ov37v8e3ufVajaH+wLkmEpLd
xppCVLkDQjIHYR2IPz5s/L/RuWqDpEY4TPmGFF6q+xQMnqQA3vXPyG+JYMARXLru
Y1gCDLN30v3DpyOeqKmFjUqiHK5h8s0NYiH2OpMyaCpi12JsF23miP89ldQp3+SJ
8moo0cNGy7sFp2gX9ol2zVoo7qxfYlLl03f7CALJ6im0sx4yBsmlzFDdvpQUbXk8
YZ5rT4LML2Fx6Wgnnklb5g==
```
4. 如果不出意外,你会得到一个看似用Base64编码的激活码。直接复制它,并把它粘贴到Navicat的`手动激活`窗口,最后点`激活`按钮。如果没什么意外的话应该能成功激活。
7. 如果不出意外,你会得到一个看似用Base64编码的 __激活码__。直接复制它,并把它粘贴到Navicat的`手动激活`窗口,最后点`激活`按钮。如果没什么意外的话应该能成功激活。
+135
View File
@@ -0,0 +1,135 @@
#include <vector>
#include <string>
#include <windows.h>
namespace Helper {
bool ConvertToUTF8(LPCSTR from, std::string& to) {
bool bSuccess = false;
int len = 0;
LPWSTR lpUnicodeString = nullptr;
len = MultiByteToWideChar(CP_ACP, NULL, from, -1, NULL, 0);
if (len == 0)
goto ON_ConvertToUTF8_0_ERROR;
lpUnicodeString = reinterpret_cast<LPWSTR>(HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
len * sizeof(WCHAR)));
if (lpUnicodeString == nullptr)
goto ON_ConvertToUTF8_0_ERROR;
if (!MultiByteToWideChar(CP_ACP, NULL, from, -1, lpUnicodeString, len))
goto ON_ConvertToUTF8_0_ERROR;
len = WideCharToMultiByte(CP_UTF8, NULL, lpUnicodeString, -1, NULL, 0, NULL, NULL);
if (len == 0)
goto ON_ConvertToUTF8_0_ERROR;
to.resize(len);
if (!WideCharToMultiByte(CP_UTF8, NULL, lpUnicodeString, -1, to.data(), len, NULL, NULL))
goto ON_ConvertToUTF8_0_ERROR;
while (to.back() == 0)
to.pop_back();
bSuccess = true;
ON_ConvertToUTF8_0_ERROR:
if (lpUnicodeString)
HeapFree(GetProcessHeap(), NULL, lpUnicodeString);
return bSuccess;
}
bool ConvertToUTF8(LPCWSTR from, std::string& to) {
bool bSuccess = false;
int len = 0;
len = WideCharToMultiByte(CP_UTF8, NULL, from, -1, NULL, 0, NULL, NULL);
if (len == 0)
goto ON_ConvertToUTF8_1_ERROR;
to.resize(len);
if (!WideCharToMultiByte(CP_UTF8, NULL, from, -1, to.data(), len, NULL, NULL))
goto ON_ConvertToUTF8_1_ERROR;
while (to.back() == 0)
to.pop_back();
bSuccess = true;
ON_ConvertToUTF8_1_ERROR:
return bSuccess;
}
bool ConvertToUTF8(std::string& str) {
bool bSuccess = false;
std::string temp;
bSuccess = ConvertToUTF8(str.c_str(), temp);
if (!bSuccess)
return false;
str = temp;
return true;
}
std::string Base64Encode(const std::vector<uint8_t>& bytes) {
std::string Result;
DWORD pcchString = 0;
if (bytes.empty())
return Result;
CryptBinaryToStringA(bytes.data(),
bytes.size(),
CRYPT_STRING_BASE64,
NULL,
&pcchString);
if (pcchString == 0)
return Result;
Result.resize(pcchString + 1);
if (!CryptBinaryToStringA(bytes.data(),
bytes.size(),
CRYPT_STRING_BASE64,
Result.data(),
&pcchString))
Result.clear();
return Result;
}
std::vector<uint8_t> Base64Decode(std::string& str) {
std::vector<uint8_t> Result;
DWORD pcbBinary = 0;
if (str.empty())
return Result;
CryptStringToBinaryA(str.c_str(),
NULL,
CRYPT_STRING_BASE64,
NULL,
&pcbBinary,
NULL,
NULL);
if (pcbBinary == 0)
return Result;
Result.resize(pcbBinary);
if (!CryptStringToBinaryA(str.c_str(),
NULL,
CRYPT_STRING_BASE64,
Result.data(),
&pcbBinary,
NULL,
NULL))
Result.clear();
return Result;
}
}
+108 -98
View File
@@ -38,93 +38,6 @@ private:
std::uniform_int_distribution<int> rand;
uint8_t data[10];
void SetLanguageSigature(Language _language) {
switch (_language) {
case Language::English:
data[5] = 0xAC; // Must be 0xAC for English version.
data[6] = 0x88; // Must be 0x88 for English version.
break;
case Language::SimplifiedChinese:
data[5] = 0xCE; // Must be 0xCE for Simplified Chinese version.
data[6] = 0x32; // Must be 0x32 for Simplified Chinese version.
break;
case Language::TraditionalChinese:
data[5] = 0xAA; // Must be 0xAA for Traditional Chinese version.
data[6] = 0x99; // Must be 0x99 for Traditional Chinese version.
break;
case Language::Japanese:
data[5] = 0xAD; // Must be 0xAD for Japanese version. Discoverer: @dragonflylee
data[6] = 0x82; // Must be 0x82 for Japanese version. Discoverer: @dragonflylee
break;
case Language::Polish:
data[5] = 0xBB; // Must be 0xBB for Polish version. Discoverer: @dragonflylee
data[6] = 0x55; // Must be 0x55 for Polish version. Discoverer: @dragonflylee
break;
case Language::Spanish:
data[5] = 0xAE; // Must be 0xAE for Spanish version. Discoverer: @dragonflylee
data[6] = 0x10; // Must be 0x10 for Spanish version. Discoverer: @dragonflylee
break;
case Language::French:
data[5] = 0xFA; // Must be 0xFA for French version. Discoverer: @Deltafox79
data[6] = 0x20; // Must be 0x20 for French version. Discoverer: @Deltafox79
break;
case Language::German:
data[5] = 0xB1; // Must be 0xB1 for German version. Discoverer: @dragonflylee
data[6] = 0x60; // Must be 0x60 for German version. Discoverer: @dragonflylee
break;
case Language::Korean:
data[5] = 0xB5; // Must be 0xB5 for Korean version. Discoverer: @dragonflylee
data[6] = 0x60; // Must be 0x60 for Korean version. Discoverer: @dragonflylee
break;
case Language::Russian:
data[5] = 0xEE; // Must be 0xB5 for Russian version. Discoverer: @dragonflylee
data[6] = 0x16; // Must be 0x60 for Russian version. Discoverer: @dragonflylee
break;
case Language::Portuguese:
data[5] = 0xCD; // Must be 0xCD for Portuguese version. Discoverer: @dragonflylee
data[6] = 0x49; // Must be 0x49 for Portuguese version. Discoverer: @dragonflylee
break;
default:
break;
}
}
void SetProductSignature(Product _product) {
switch (_product) {
case Product::DataModeler:
data[7] = 0x47;
break;
case Product::Premium:
data[7] = 0x65;
break;
case Product::MySQL:
data[7] = 0x68;
break;
case Product::PostgreSQL:
data[7] = 0x6C;
break;
case Product::Oracle:
data[7] = 0x70;
break;
case Product::SQLServer:
data[7] = 0x74;
break;
case Product::SQLite:
data[7] = 0x78;
break;
case Product::MariaDB:
data[7] = 0x7C;
break;
case Product::MongoDB:
data[7] = 0x80;
break;
case Product::ReportViewer:
data[7] = 0xb;
default:
break;
}
}
void DoEncrypt() {
const_DES_cblock DESKey = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
DES_key_schedule schedule;
@@ -145,15 +58,111 @@ public:
data[1] = 0x2A;
}
void Generate(uint8_t version, Language language, Product product) {
void SetLanguageSignature(Language _language) {
switch (_language) {
case Language::English:
data[5] = 0xAC; // Must be 0xAC for English version.
data[6] = 0x88; // Must be 0x88 for English version.
break;
case Language::SimplifiedChinese:
data[5] = 0xCE; // Must be 0xCE for Simplified Chinese version.
data[6] = 0x32; // Must be 0x32 for Simplified Chinese version.
break;
case Language::TraditionalChinese:
data[5] = 0xAA; // Must be 0xAA for Traditional Chinese version.
data[6] = 0x99; // Must be 0x99 for Traditional Chinese version.
break;
case Language::Japanese:
data[5] = 0xAD; // Must be 0xAD for Japanese version. Discoverer: @dragonflylee
data[6] = 0x82; // Must be 0x82 for Japanese version. Discoverer: @dragonflylee
break;
case Language::Polish:
data[5] = 0xBB; // Must be 0xBB for Polish version. Discoverer: @dragonflylee
data[6] = 0x55; // Must be 0x55 for Polish version. Discoverer: @dragonflylee
break;
case Language::Spanish:
data[5] = 0xAE; // Must be 0xAE for Spanish version. Discoverer: @dragonflylee
data[6] = 0x10; // Must be 0x10 for Spanish version. Discoverer: @dragonflylee
break;
case Language::French:
data[5] = 0xFA; // Must be 0xFA for French version. Discoverer: @Deltafox79
data[6] = 0x20; // Must be 0x20 for French version. Discoverer: @Deltafox79
break;
case Language::German:
data[5] = 0xB1; // Must be 0xB1 for German version. Discoverer: @dragonflylee
data[6] = 0x60; // Must be 0x60 for German version. Discoverer: @dragonflylee
break;
case Language::Korean:
data[5] = 0xB5; // Must be 0xB5 for Korean version. Discoverer: @dragonflylee
data[6] = 0x60; // Must be 0x60 for Korean version. Discoverer: @dragonflylee
break;
case Language::Russian:
data[5] = 0xEE; // Must be 0xB5 for Russian version. Discoverer: @dragonflylee
data[6] = 0x16; // Must be 0x60 for Russian version. Discoverer: @dragonflylee
break;
case Language::Portuguese:
data[5] = 0xCD; // Must be 0xCD for Portuguese version. Discoverer: @dragonflylee
data[6] = 0x49; // Must be 0x49 for Portuguese version. Discoverer: @dragonflylee
break;
default:
break;
}
}
void SetLanguageSignature(uint8_t value0, uint8_t value1) {
data[5] = value0;
data[6] = value1;
}
void SetProductSignature(Product _product) {
switch (_product) {
case Product::DataModeler:
data[7] = 0x47;
break;
case Product::Premium:
data[7] = 0x65;
break;
case Product::MySQL:
data[7] = 0x68;
break;
case Product::PostgreSQL:
data[7] = 0x6C;
break;
case Product::Oracle:
data[7] = 0x70;
break;
case Product::SQLServer:
data[7] = 0x74;
break;
case Product::SQLite:
data[7] = 0x78;
break;
case Product::MariaDB:
data[7] = 0x7C;
break;
case Product::MongoDB:
data[7] = 0x80;
break;
case Product::ReportViewer:
data[7] = 0xb;
default:
break;
}
}
void SetProductSignature(uint8_t value) {
data[7] = value;
}
void SetVersion(uint8_t version) {
data[8] = version << 4;
}
void Generate() {
data[2] = rand(rand_eng);
data[3] = rand(rand_eng);
data[4] = rand(rand_eng);
SetLanguageSigature(language);
SetProductSignature(product);
data[8] = version << 4;
data[9] = 0x32;
DoEncrypt();
}
@@ -161,7 +170,7 @@ public:
std::string Key;
const char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
Key.resize(16 + 1);
Key.resize(16);
Key[0] = EncodeTable[data[0] >> 3];
Key[1] = EncodeTable[(data[0] & 0x07) << 2 | data[1] >> 6];
Key[2] = EncodeTable[data[1] >> 1 & 0x1F];
@@ -179,20 +188,21 @@ public:
Key[13] = EncodeTable[data[8] >> 2 & 0x1F];
Key[14] = EncodeTable[data[8] << 3 & 0x1F | data[9] >> 5];
Key[15] = EncodeTable[data[9] & 0x1F];
Key[16] = 0;
return Key;
}
std::string GetFormatedKey() const {
std::string Key = GetKey();
auto ptr = Key.begin() + 4;
Key.insert(ptr++, '-');
ptr = Key.insert(ptr, '-');
ptr++;
ptr += 4;
Key.insert(ptr++, '-');
ptr = Key.insert(ptr, '-');
ptr++;
ptr += 4;
Key.insert(ptr++, '-');
Key.insert(ptr, '-');
return Key;
}
+342
View File
@@ -0,0 +1,342 @@
#include <iostream>
#include <ctime>
#include <windows.h>
#include "RSACipher.hpp"
#include "NavicatKeygen.hpp"
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
namespace Helper {
bool ConvertToUTF8(LPCSTR from, std::string& to);
bool ConvertToUTF8(LPCWSTR from, std::string& to);
bool ConvertToUTF8(std::string& str);
std::string Base64Encode(const std::vector<uint8_t>& bytes);
std::vector<uint8_t> Base64Decode(std::string& str);
template<int min_num, int max_num>
bool ReadNumber(int& num, const char* msg, const char* err_msg) {
int temp;
std::string input;
while (true) {
std::cout << msg;
if (!std::getline(std::cin, input))
return false;
try {
temp = std::stoi(input, nullptr, 0);
if (min_num <= temp && temp <= max_num) {
num = temp;
return true;
} else {
throw std::invalid_argument("Invalid number");
}
} catch (...) {
std::cout << err_msg << std::endl;
}
}
}
}
#define MODE_SIMPLE 1
#define MODE_ADVANCED 2
#define FLAG_BIN 1
#define FLAG_TEXT 2
void Process(RSACipher* cipher, int mode, int flag) {
std::string input;
int num;
NavicatKeygen::Product product;
NavicatKeygen::Language language;
uint8_t product0;
uint8_t language0, language1;
uint8_t version;
NavicatKeygen keygen;
std::string username;
std::string organization;
std::string RequestCode_b64;
std::vector<uint8_t> RequestCode;
char RequestInfo[256] = {};
char ResponseInfo[256] = {};
std::vector<uint8_t> ResponseCode;
std::string ResponseCode_b64;
rapidjson::Document json;
rapidjson::Value N_Key;
rapidjson::Value N_Value;
rapidjson::Value O_Key;
rapidjson::Value O_Value;
rapidjson::Value T_Key;
rapidjson::Value T_Value;
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
if (mode == MODE_SIMPLE) {
std::cout << "Select Navicat product:" << std::endl
<< "0. DataModeler" << std::endl
<< "1. Premium" << std::endl
<< "2. MySQL" << std::endl
<< "3. PostgreSQL" << std::endl
<< "4. Oracle" << std::endl
<< "5. SQLServer" << std::endl
<< "6. SQLite" << std::endl
<< "7. MariaDB" << std::endl
<< "8. MongoDB" << std::endl
<< "9. ReportViewer" << std::endl
<< std::endl;
if (!Helper::ReadNumber<0, 9>(num,
"(Input index)> ",
"Invalid index.")) {
return;
}
product = static_cast<NavicatKeygen::Product>(num);
std::cout << std::endl;
std::cout << "Select product language:" << std::endl
<< "0. English" << std::endl
<< "1. Simplified Chinese" << std::endl
<< "2. Traditional Chinese" << std::endl
<< "3. Japanese" << std::endl
<< "4. Polish" << std::endl
<< "5. Spanish" << std::endl
<< "6. French" << std::endl
<< "7. German" << std::endl
<< "8. Korean" << std::endl
<< "9. Russian" << std::endl
<< "10. Portuguese" << std::endl
<< std::endl;
if (!Helper::ReadNumber<0, 10>(num,
"(Input index)> ",
"Invalid index.")) {
return;
}
language = static_cast<NavicatKeygen::Language>(num);
std::cout << std::endl;
keygen.SetProductSignature(product);
keygen.SetLanguageSignature(language);
}
if (mode == MODE_ADVANCED) {
if (!Helper::ReadNumber<0, 255>(num,
"(Navicat Product ID, 0x00 ~ 0xFF)> ",
"Invalid number.")) {
return;
}
product0 = static_cast<uint8_t>(num);
if (!Helper::ReadNumber<0, 255>(num,
"(Navicat Language Signature 0, 0x00 ~ 0xFF)> ",
"Invalid number.")) {
return;
}
language0 = static_cast<uint8_t>(num);
if (!Helper::ReadNumber<0, 255>(num,
"(Navicat Language Signature 1, 0x00 ~ 0xFF)> ",
"Invalid number.")) {
return;
}
language1 = static_cast<uint8_t>(num);
keygen.SetProductSignature(product0);
keygen.SetLanguageSignature(language0, language1);
}
if (!Helper::ReadNumber<0, 16 - 1>(num,
"(Input major version number, range: 0 ~ 15, default: 12)> ",
"Invalid number.")) {
return;
}
version = static_cast<uint8_t>(num);
keygen.SetVersion(version);
keygen.Generate();
std::cout << std::endl;
std::cout << "Serial number:" << std::endl;
std::cout << keygen.GetFormatedKey() << std::endl;
std::cout << std::endl;
std::cout << "Your name: ";
if (!std::getline(std::cin, username))
return;
if (!Helper::ConvertToUTF8(username)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ERROR: ConvertToUTF8 fails." << std::endl;
return;
}
std::cout << "Your organization: ";
if (!std::getline(std::cin, organization))
return;
if (!Helper::ConvertToUTF8(organization)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ERROR: ConvertToUTF8 fails." << std::endl;
return;
}
std::cout << std::endl;
if (flag == FLAG_TEXT) {
std::cout << "Input request code (in Base64), input empty line to end:" << std::endl;
while (true) {
std::string temp;
if (!std::getline(std::cin, temp))
return;
if (temp.empty())
break;
RequestCode_b64 += temp;
}
RequestCode = Helper::Base64Decode(RequestCode_b64);
if (RequestCode.empty()) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ERROR: Base64Decode fails." << std::endl;
return;
}
if (!cipher->Decrypt(RequestCode.data(),
RequestCode.size(),
RequestInfo,
RSA_PKCS1_PADDING)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ERROR: Decrypt<RSACipher::KeyType::PrivateKey> fails." << std::endl;
return;
}
std::cout << "Request Info:" << std::endl;
std::cout << RequestInfo << std::endl;
std::cout << std::endl;
json.Parse(RequestInfo);
json.RemoveMember("P"); // remove Platform info
N_Key.SetString("N", 1);
N_Value.SetString(username.c_str(), username.length());
O_Key.SetString("O", 1);
O_Value.SetString(organization.c_str(), organization.length());
T_Key.SetString("T", 1);
T_Value.SetUint(std::time(nullptr));
json.AddMember(N_Key, N_Value, json.GetAllocator());
json.AddMember(O_Key, O_Value, json.GetAllocator());
json.AddMember(T_Key, T_Value, json.GetAllocator());
json.Accept(writer);
if (buffer.GetSize() > 240) {
std::cout << "ERROR: Response info is too long." << std::endl;
return;
}
memcpy(ResponseInfo, buffer.GetString(), buffer.GetSize());
std::cout << "Response Info:" << std::endl;
std::cout << ResponseInfo << std::endl;
std::cout << std::endl;
ResponseCode.resize(256);
if (!cipher->Encrypt<RSACipher::KeyType::PrivateKey>(ResponseInfo,
strlen(ResponseInfo),
ResponseCode.data(),
RSA_PKCS1_PADDING)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ERROR: Encrypt<RSACipher::KeyType::PrivateKey> fails." << std::endl;
return;
}
ResponseCode_b64 = Helper::Base64Encode(ResponseCode);
if (ResponseCode_b64.empty()) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "Base64Encode fails." << std::endl;
return;
}
std::cout << "License:" << std::endl;
std::cout << ResponseCode_b64 << std::endl;
}
if (flag == FLAG_BIN) {
rapidjson::Value K_Key;
rapidjson::Value K_Value;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD NumberOfBytesWritten;
json.Parse("{}");
K_Key.SetString("K", 1);
K_Value.SetString(keygen.GetKey().c_str(), keygen.GetKey().size());
N_Key.SetString("N", 1);
N_Value.SetString(username.c_str(), username.length());
O_Key.SetString("O", 1);
O_Value.SetString(organization.c_str(), organization.length());
T_Key.SetString("T", 1);
T_Value.SetUint(std::time(nullptr));
json.AddMember(K_Key, K_Value, json.GetAllocator());
json.AddMember(N_Key, N_Value, json.GetAllocator());
json.AddMember(O_Key, O_Value, json.GetAllocator());
json.AddMember(T_Key, T_Value, json.GetAllocator());
json.Accept(writer);
if (buffer.GetSize() > 240) {
std::cout << "ERROR: Response info is too long." << std::endl;
return;
}
memcpy(ResponseInfo, buffer.GetString(), buffer.GetSize());
std::cout << "Response Info:" << std::endl;
std::cout << ResponseInfo << std::endl;
std::cout << std::endl;
ResponseCode.resize(256);
if (!cipher->Encrypt<RSACipher::KeyType::PrivateKey>(ResponseInfo,
strlen(ResponseInfo),
ResponseCode.data(),
RSA_PKCS1_PADDING)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ERROR: Encrypt<RSACipher::KeyType::PrivateKey> fails." << std::endl;
return;
}
hFile = CreateFile(TEXT("license_file"),
GENERIC_READ | GENERIC_WRITE,
0,
nullptr,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE) {
DWORD dwLastError = GetLastError();
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ERROR: CreateFile fails. CODE: " << dwLastError << std::endl;
return;
}
if (!WriteFile(hFile, ResponseCode.data(), ResponseCode.size(), &NumberOfBytesWritten, nullptr)) {
DWORD dwLastError = GetLastError();
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ERROR: WriteFile fails. CODE: " << dwLastError << std::endl;
CloseHandle(hFile);
return;
}
CloseHandle(hFile);
std::cout << "license_file has been generated." << std::endl;
}
}
+1 -1
View File
@@ -54,7 +54,7 @@ public:
return aCipher;
}
bool GenerateKey(int bits, unsigned long long e = RSA_F4) {
bool GenerateKey(int bits, unsigned int e = RSA_F4) {
bool bSuccess = false;
BIGNUM* bn_e = nullptr;
-460
View File
@@ -1,460 +0,0 @@
#include <iostream>
#include <ctime>
#include <tchar.h>
#include <windows.h>
#include "NavicatKeygen.hpp"
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
bool ConvertToUTF8(LPCSTR from, std::string& to) {
bool bSuccess = false;
int len = 0;
LPWSTR lpUnicodeString = nullptr;
len = MultiByteToWideChar(CP_ACP, NULL, from, -1, NULL, 0);
if (len == 0)
goto ON_ConvertToUTF8_0_ERROR;
lpUnicodeString = reinterpret_cast<LPWSTR>(HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
len * sizeof(WCHAR)));
if (lpUnicodeString == nullptr)
goto ON_ConvertToUTF8_0_ERROR;
if (!MultiByteToWideChar(CP_ACP, NULL, from, -1, lpUnicodeString, len))
goto ON_ConvertToUTF8_0_ERROR;
len = WideCharToMultiByte(CP_UTF8, NULL, lpUnicodeString, -1, NULL, 0, NULL, NULL);
if (len == 0)
goto ON_ConvertToUTF8_0_ERROR;
to.resize(len);
if (!WideCharToMultiByte(CP_UTF8, NULL, lpUnicodeString, -1, to.data(), len, NULL, NULL))
goto ON_ConvertToUTF8_0_ERROR;
while (to.back() == 0)
to.pop_back();
bSuccess = true;
ON_ConvertToUTF8_0_ERROR:
if (lpUnicodeString)
HeapFree(GetProcessHeap(), NULL, lpUnicodeString);
return bSuccess;
}
bool ConvertToUTF8(LPCWSTR from, std::string& to) {
bool bSuccess = false;
int len = 0;
len = WideCharToMultiByte(CP_UTF8, NULL, from, -1, NULL, 0, NULL, NULL);
if (len == 0)
goto ON_ConvertToUTF8_1_ERROR;
to.resize(len);
if (!WideCharToMultiByte(CP_UTF8, NULL, from, -1, to.data(), len, NULL, NULL))
goto ON_ConvertToUTF8_1_ERROR;
while (to.back() == 0)
to.pop_back();
bSuccess = true;
ON_ConvertToUTF8_1_ERROR:
return bSuccess;
}
bool ConvertToUTF8(std::string& str) {
bool bSuccess = false;
std::string temp;
bSuccess = ConvertToUTF8(str.c_str(), temp);
if (!bSuccess)
return false;
str = temp;
return true;
}
std::string Base64Encode(const std::vector<uint8_t>& bytes) {
std::string Result;
DWORD pcchString = 0;
if (bytes.empty())
return Result;
CryptBinaryToStringA(bytes.data(),
bytes.size(),
CRYPT_STRING_BASE64,
NULL,
&pcchString);
if (pcchString == 0)
return Result;
Result.resize(pcchString + 1);
if (!CryptBinaryToStringA(bytes.data(),
bytes.size(),
CRYPT_STRING_BASE64,
Result.data(),
&pcchString))
Result.clear();
return Result;
}
std::vector<uint8_t> Base64Decode(std::string& str) {
std::vector<uint8_t> Result;
DWORD pcbBinary = 0;
if (str.empty())
return Result;
CryptStringToBinaryA(str.c_str(),
NULL,
CRYPT_STRING_BASE64,
NULL,
&pcbBinary,
NULL,
NULL);
if (pcbBinary == 0)
return Result;
Result.resize(pcbBinary);
if (!CryptStringToBinaryA(str.c_str(),
NULL,
CRYPT_STRING_BASE64,
Result.data(),
&pcbBinary,
NULL,
NULL))
Result.clear();
return Result;
}
void help() {
std::cout << "Usage:" << std::endl;
std::cout << " navicat-keygen.exe <RSA-2048 PrivateKey(PEM file)>" << std::endl;
}
bool GatherInformation(NavicatKeygen::Product& product,
NavicatKeygen::Language& language,
uint8_t& version) {
int index = -1;
std::string temp;
std::cout << "Select Navicat product:" << std::endl
<< "0. DataModeler" << std::endl
<< "1. Premium" << std::endl
<< "2. MySQL" << std::endl
<< "3. PostgreSQL" << std::endl
<< "4. Oracle" << std::endl
<< "5. SQLServer" << std::endl
<< "6. SQLite" << std::endl
<< "7. MariaDB" << std::endl
<< "8. MongoDB" << std::endl
<< "9. ReportViewer" << std::endl
<< std::endl;
while (true) {
std::cout << "(input index)> ";
if (!std::getline(std::cin, temp)) {
return false;
}
try {
index = std::stoi(temp);
switch (index) {
case 0:
product = NavicatKeygen::Product::DataModeler;
break;
case 1:
product = NavicatKeygen::Product::Premium;
break;
case 2:
product = NavicatKeygen::Product::MySQL;
break;
case 3:
product = NavicatKeygen::Product::PostgreSQL;
break;
case 4:
product = NavicatKeygen::Product::Oracle;
break;
case 5:
product = NavicatKeygen::Product::SQLServer;
break;
case 6:
product = NavicatKeygen::Product::SQLite;
break;
case 7:
product = NavicatKeygen::Product::MariaDB;
break;
case 8:
product = NavicatKeygen::Product::MongoDB;
break;
case 9:
product = NavicatKeygen::Product::ReportViewer;
break;
default:
throw std::invalid_argument("Invalid index");
}
break;
} catch (...) {
std::cout << "Invalid index." << std::endl;
continue;
}
}
std::cout << std::endl;
std::cout << "Select product language:" << std::endl
<< "0. English" << std::endl
<< "1. Simplified Chinese" << std::endl
<< "2. Traditional Chinese" << std::endl
<< "3. Japanese" << std::endl
<< "4. Polish" << std::endl
<< "5. Spanish" << std::endl
<< "6. French" << std::endl
<< "7. German" << std::endl
<< "8. Korean" << std::endl
<< "9. Russian" << std::endl
<< "10. Portuguese" << std::endl
<< std::endl;
while (true) {
std::cout << "(input index)> ";
if (!std::getline(std::cin, temp)) {
return false;
}
try {
index = std::stoi(temp);
switch (index) {
case 0:
language = NavicatKeygen::Language::English;
break;
case 1:
language = NavicatKeygen::Language::SimplifiedChinese;
break;
case 2:
language = NavicatKeygen::Language::TraditionalChinese;
break;
case 3:
language = NavicatKeygen::Language::Japanese;
break;
case 4:
language = NavicatKeygen::Language::Polish;
break;
case 5:
language = NavicatKeygen::Language::Spanish;
break;
case 6:
language = NavicatKeygen::Language::French;
break;
case 7:
language = NavicatKeygen::Language::German;
break;
case 8:
language = NavicatKeygen::Language::Korean;
break;
case 9:
language = NavicatKeygen::Language::Russian;
break;
case 10:
language = NavicatKeygen::Language::Portuguese;
break;
default:
throw std::invalid_argument("Invalid index");
}
break;
} catch (...) {
std::cout << "Invalid index." << std::endl;
continue;
}
}
std::cout << std::endl;
while (true) {
std::cout << "(input major version number)> ";
if (!std::getline(std::cin, temp)) {
return false;
}
try {
version = std::stoi(temp);
break;
} catch (...) {
std::cout << "Invalid index." << std::endl;
continue;
}
}
std::cout << std::endl;
}
int _tmain(int argc, LPTSTR argv[]) {
if (argc != 2) {
help();
return 0;
}
std::string RSAPrivateKeyPath;
RSACipher* cipher = nullptr;
std::string RequestCode_b64;
std::string ResponseCode_b64;
std::vector<uint8_t> RequestCode;
std::vector<uint8_t> ResponseCode;
char RequestInfo[256] = {};
char ResponseInfo[256] = {};
rapidjson::Document json;
NavicatKeygen keygen;
NavicatKeygen::Product product;
NavicatKeygen::Language language;
uint8_t version = 0;
std::string username;
std::string organization;
cipher = RSACipher::Create();
if (cipher == nullptr) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "Failed to create RSACipher." << std::endl;
goto ON_tmain_ERROR;
}
if (!ConvertToUTF8(argv[1], RSAPrivateKeyPath)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ConvertToUTF8 fails." << std::endl;
goto ON_tmain_ERROR;
}
if (!cipher->ImportKeyFromFile<RSACipher::KeyType::PrivateKey>(RSAPrivateKeyPath)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ImportKeyFromFile fails." << std::endl;
goto ON_tmain_ERROR;
}
GatherInformation(product, language, version);
keygen.Generate(version, language, product);
std::cout << "Serial number:" << std::endl;
std::cout << keygen.GetFormatedKey() << std::endl;
std::cout << std::endl;
std::cout << "Your name: ";
if (!std::getline(std::cin, username))
goto ON_tmain_ERROR;
if (!ConvertToUTF8(username)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ConvertToUTF8 fails." << std::endl;
goto ON_tmain_ERROR;
}
std::cout << "Your organization: ";
if (!std::getline(std::cin, organization))
goto ON_tmain_ERROR;
if (!ConvertToUTF8(organization)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ConvertToUTF8 fails." << std::endl;
goto ON_tmain_ERROR;
}
std::cout << "Input request code (in Base64), input empty line to end:" << std::endl;
while (true) {
std::string temp;
if (!std::getline(std::cin, temp))
goto ON_tmain_ERROR;
if (temp.empty())
break;
RequestCode_b64 += temp;
}
RequestCode = Base64Decode(RequestCode_b64);
if (RequestCode.empty()) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "Base64Decode fails." << std::endl;
goto ON_tmain_ERROR;
}
if (!cipher->Decrypt(RequestCode.data(),
RequestCode.size(),
RequestInfo,
RSA_PKCS1_PADDING)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "Decrypt<RSACipher::KeyType::PrivateKey> fails." << std::endl;
goto ON_tmain_ERROR;
}
std::cout << "Request Info:" << std::endl;
std::cout << RequestInfo << std::endl << std::endl;
json.Parse(RequestInfo);
json.RemoveMember("P");
{
rapidjson::Value N_Key;
rapidjson::Value N_Value;
rapidjson::Value O_Key;
rapidjson::Value O_Value;
rapidjson::Value T_Key;
rapidjson::Value T_Value;
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
N_Key.SetString("N", 1);
N_Value.SetString(username.c_str(), username.length());
O_Key.SetString("O", 1);
O_Value.SetString(organization.c_str(), organization.length());
T_Key.SetString("T", 1);
T_Value.SetUint(std::time(nullptr));
json.AddMember(N_Key, N_Value, json.GetAllocator());
json.AddMember(O_Key, O_Value, json.GetAllocator());
json.AddMember(T_Key, T_Value, json.GetAllocator());
json.Accept(writer);
if (buffer.GetSize() > 240) {
std::cout << "Response info too long." << std::endl;
goto ON_tmain_ERROR;
}
memcpy(ResponseInfo, buffer.GetString(), buffer.GetSize());
}
std::cout << "Response Info:" << std::endl;
std::cout << ResponseInfo << std::endl << std::endl;
ResponseCode.resize(256);
if (!cipher->Encrypt<RSACipher::KeyType::PrivateKey>(ResponseInfo,
strlen(ResponseInfo),
ResponseCode.data(),
RSA_PKCS1_PADDING)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "Encrypt<RSACipher::KeyType::PrivateKey> fails." << std::endl;
goto ON_tmain_ERROR;
}
ResponseCode_b64 = Base64Encode(ResponseCode);
if (ResponseCode_b64.empty()) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "Base64Encode fails." << std::endl;
goto ON_tmain_ERROR;
}
std::cout << "License:" << std::endl;
std::cout << ResponseCode_b64 << std::endl;
ON_tmain_ERROR:
if (cipher)
delete cipher;
return 0;
}
+69
View File
@@ -0,0 +1,69 @@
#include <iostream>
#include "RSACipher.hpp"
namespace Helper {
bool ConvertToUTF8(std::string& str);
}
#define MODE_SIMPLE 1
#define MODE_ADVANCED 2
#define FLAG_BIN 1
#define FLAG_TEXT 2
void Process(RSACipher* cipher, int mode, int flag);
void help() {
std::cout << "Usage:" << std::endl;
std::cout << " navicat-keygen.exe <-bin|-text> [-adv] <RSA-2048 PrivateKey(PEM file)>" << std::endl;
}
int main(int argc, char* argv[]) {
if (argc != 3 && argc != 4) {
help();
return 0;
}
std::string RSAPrivateKeyPath = argv[argc - 1];
RSACipher* cipher = nullptr;
cipher = RSACipher::Create();
if (cipher == nullptr) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ERROR: Failed to create RSACipher." << std::endl;
goto ON_tmain_ERROR;
}
if (!Helper::ConvertToUTF8(RSAPrivateKeyPath)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ERROR: ConvertToUTF8 fails." << std::endl;
goto ON_tmain_ERROR;
}
if (!cipher->ImportKeyFromFile<RSACipher::KeyType::PrivateKey>(RSAPrivateKeyPath)) {
std::cout << "@Function: " << __FUNCSIG__ << " LINE: " << __LINE__ << std::endl;
std::cout << "ERROR: ImportKeyFromFile<RSACipher::KeyType::PrivateKey> fails." << std::endl;
goto ON_tmain_ERROR;
}
if (argc == 3) {
if (_stricmp(argv[1], "-bin") == 0)
Process(cipher, MODE_SIMPLE, FLAG_BIN);
else if (_stricmp(argv[1], "-text") == 0)
Process(cipher, MODE_SIMPLE, FLAG_TEXT);
else
help();
}
if (argc == 4) {
if (_stricmp(argv[1], "-bin") == 0)
Process(cipher, MODE_ADVANCED, FLAG_BIN);
else if (_stricmp(argv[1], "-text") == 0)
Process(cipher, MODE_ADVANCED, FLAG_TEXT);
else
help();
}
ON_tmain_ERROR:
if (cipher)
delete cipher;
return 0;
}
+3 -1
View File
@@ -166,7 +166,9 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="_tmain.cpp" />
<ClCompile Include="Helper.cpp" />
<ClCompile Include="Process.cpp" />
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="NavicatKeygen.hpp" />
@@ -15,7 +15,13 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="_tmain.cpp">
<ClCompile Include="Helper.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="Process.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
-13
View File
@@ -1,13 +0,0 @@
// to avoid "AES_KEY" definaition conflict
#include "NavicatCrypto/NavicatCrypto.hpp"
namespace patcher {
static Navicat11Crypto cipher("23970790", 8);
std::string EncryptPublicKey(const char* public_key, size_t len) {
auto&& temp = cipher.EncryptString(public_key, len);
return std::string(temp.begin(), temp.end());
}
}
+185
View File
@@ -0,0 +1,185 @@
#include "def.hpp"
#include "NavicatCrypto.hpp"
namespace Helper {
static Navicat11Crypto NavicatCipher("23970790", 8);
std::string EncryptPublicKey(const std::string& PublicKeyString) {
return NavicatCipher.EncryptString(PublicKeyString.c_str(),
PublicKeyString.length());
}
bool ConvertToUTF8(LPCSTR from, std::string& to) {
bool bSuccess = false;
int RequireLength = 0;
LPWSTR lpUnicodeString = nullptr;
RequireLength = MultiByteToWideChar(CP_ACP, NULL, from, -1, nullptr, 0);
if (RequireLength == 0)
goto ON_ConvertToUTF8_0_ERROR;
lpUnicodeString = reinterpret_cast<LPWSTR>(HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
RequireLength * sizeof(WCHAR)));
if (lpUnicodeString == nullptr)
goto ON_ConvertToUTF8_0_ERROR;
if (!MultiByteToWideChar(CP_ACP, NULL, from, -1, lpUnicodeString, RequireLength))
goto ON_ConvertToUTF8_0_ERROR;
RequireLength = WideCharToMultiByte(CP_UTF8, NULL, lpUnicodeString, -1, nullptr, 0, nullptr, nullptr);
if (RequireLength == 0)
goto ON_ConvertToUTF8_0_ERROR;
to.resize(RequireLength);
if (!WideCharToMultiByte(CP_UTF8, NULL, lpUnicodeString, -1, to.data(), RequireLength, nullptr, nullptr))
goto ON_ConvertToUTF8_0_ERROR;
while (to.back() == 0)
to.pop_back();
bSuccess = true;
ON_ConvertToUTF8_0_ERROR:
if (lpUnicodeString)
HeapFree(GetProcessHeap(), NULL, lpUnicodeString);
return bSuccess;
}
bool ConvertToUTF8(LPCWSTR from, std::string& to) {
bool bSuccess = false;
int RequireLength = 0;
RequireLength = WideCharToMultiByte(CP_UTF8, NULL, from, -1, nullptr, 0, nullptr, nullptr);
if (RequireLength == 0)
goto ON_ConvertToUTF8_1_ERROR;
to.resize(RequireLength);
if (!WideCharToMultiByte(CP_UTF8, NULL, from, -1, to.data(), RequireLength, nullptr, nullptr))
goto ON_ConvertToUTF8_1_ERROR;
while (to.back() == 0)
to.pop_back();
bSuccess = true;
ON_ConvertToUTF8_1_ERROR:
return bSuccess;
}
bool ConvertToUTF8(std::string& str) {
bool bSuccess = false;
std::string temp;
bSuccess = ConvertToUTF8(str.c_str(), temp);
if (bSuccess)
str = temp;
return bSuccess;
}
void ErrorReport(LPCTSTR at, UINT line, LPCTSTR msg) {
_tprintf_s(TEXT("@%s LINE: %u\n"), at, line);
_tprintf_s(TEXT("%s\n"), msg);
}
void ErrorReport(LPCTSTR at, UINT line, LPCTSTR msg, DWORD err_code) {
_tprintf_s(TEXT("@%s LINE: %u\n"), at, line);
_tprintf_s(TEXT("%s CODE: 0x%08X\n"), msg, err_code);
}
//
// read byte(s) at address `p` as _Type to `out`
// succeed if return true, otherwise return false
//
template<typename _Type>
static __forceinline bool ProbeForRead(const void* p, void* out) {
__try {
*reinterpret_cast<_Type*>(out) = *reinterpret_cast<const _Type*>(p);
return true;
} __except (EXCEPTION_EXECUTE_HANDLER) {
return false;
}
}
//
// Print memory data in [from, to) at least
// If `base` is not nullptr, print address as offset. Otherwise, as absolute address.
// NOTICE:
// `base` must >= `from`
//
void PrintMemory(const void* from, const void* to, const void* base) {
const uint8_t* start = reinterpret_cast<const uint8_t*>(from);
const uint8_t* end = reinterpret_cast<const uint8_t*>(to);
const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(base);
if (start >= end)
return;
while (reinterpret_cast<uintptr_t>(start) % 16)
start--;
while (reinterpret_cast<uintptr_t>(start) % 16)
end++;
while (start < end) {
uint16_t value[16] = {};
if (base_ptr)
_tprintf(TEXT("+0x%p "), reinterpret_cast<const void*>(start - base_ptr));
else
_tprintf(TEXT("0x%p "), start);
for (int i = 0; i < 16; ++i) {
if (ProbeForRead<uint8_t>(start + i, value + i)) {
_tprintf(TEXT("%02x "), value[i]);
} else {
value[i] = -1;
_tprintf(TEXT("?? "));
}
}
_tprintf(TEXT(" "));
for (int i = 0; i < 16; ++i) {
if (value[i] < 0x20) {
_tprintf(TEXT("."));
} else if (value[i] > 0x7e) {
_tprintf(TEXT("."));
} else {
_tprintf(TEXT("%c"), value[i]);
}
}
_tprintf(TEXT("\n"));
start += 0x10;
}
}
PIMAGE_SECTION_HEADER ImageSectionHeader(PVOID lpBase, LPCSTR lpSectionName) {
PIMAGE_DOS_HEADER pFileHeader = NULL;
PIMAGE_NT_HEADERS pNtHeader = NULL;
IMAGE_SECTION_HEADER* pSectionHeaders = NULL;
pFileHeader = (IMAGE_DOS_HEADER*)lpBase;
if (pFileHeader->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
pNtHeader = (IMAGE_NT_HEADERS*)((BYTE*)lpBase + pFileHeader->e_lfanew);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
return NULL;
pSectionHeaders = (IMAGE_SECTION_HEADER*)((BYTE*)pNtHeader +
offsetof(IMAGE_NT_HEADERS, OptionalHeader) +
pNtHeader->FileHeader.SizeOfOptionalHeader);
for (WORD i = 0; i < pNtHeader->FileHeader.NumberOfSections; ++i)
if (_stricmp((const char*)pSectionHeaders[i].Name, lpSectionName) == 0)
return pSectionHeaders + i;
return NULL;
}
}
+180
View File
@@ -0,0 +1,180 @@
#pragma once
#include <openssl/crypto.h>
#include <openssl/blowfish.h>
#include <openssl/sha.h>
#include <string>
#ifdef _DEBUG
#pragma comment(lib, "libcryptoMTd.lib")
#else
#pragma comment(lib, "libcryptoMT.lib")
#endif
#pragma comment(lib, "WS2_32.lib") // some symbol are used in OpenSSL static lib
#pragma comment(lib, "Crypt32.lib") // some symbol are used in OpenSSL static lib
class Navicat11Crypto {
protected:
BF_KEY BlowfishKey;
void BytesToHex(const void* src, size_t len, char* dst) {
for (size_t i = 0; i < len; ++i) {
char h = reinterpret_cast<const uint8_t*>(src)[i] >> 4;
char l = reinterpret_cast<const uint8_t*>(src)[i] & 0x0F;
h += h >= 10 ? 'A' - 10 : '0';
l += l >= 10 ? 'A' - 10 : '0';
dst[2 * i] = h;
dst[2 * i + 1] = l;
}
}
bool CheckHex(const char* src, size_t len) {
if (len % 2 != 0)
return false;
for (size_t i = 0; i < len; i += 2) {
char h = src[i];
char l = src[i + 1];
if (src[i] < '0' || src[i] > 'F')
return false;
if (src[i] < 'A' && src[i] > '9')
return false;
if (src[i + 1] < '0' || src[i + 1] > 'F')
return false;
if (src[i + 1] < 'A' && src[i + 1] > '9')
return false;
}
return true;
}
void HexToBytes(const char* src, size_t len, void* dst) {
for (size_t i = 0; i < len; i += 2) {
uint8_t h = src[i];
uint8_t l = src[i + 1];
h -= h > '9' ? 'A' - 10 : '0';
l -= l > '9' ? 'A' - 10 : '0';
reinterpret_cast<uint8_t*>(dst)[i / 2] = (h << 4) ^ l;
}
}
public:
Navicat11Crypto() {
static const uint8_t PresetKey[20] = {
0x42, 0xCE, 0xB2, 0x71, 0xA5, 0xE4, 0x58, 0xB7,
0x4A, 0xEA, 0x93, 0x94, 0x79, 0x22, 0x35, 0x43,
0x91, 0x87, 0x33, 0x40
};
BF_set_key(&BlowfishKey, SHA_DIGEST_LENGTH, PresetKey);
}
Navicat11Crypto(const void* UserKey, size_t Length) {
SetKey(UserKey, Length);
}
void SetKey(const void* UserKey, size_t Length) {
unsigned char MessageDigest[SHA_DIGEST_LENGTH];
SHA1(reinterpret_cast<const unsigned char*>(UserKey), Length, MessageDigest);
BF_set_key(&BlowfishKey, SHA_DIGEST_LENGTH, MessageDigest);
OPENSSL_cleanse(MessageDigest, SHA_DIGEST_LENGTH);
}
std::string EncryptString(const void* srcBytes, size_t srclen) {
std::string ret;
uint8_t CV[BF_BLOCK] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
if (srclen == 0)
return ret;
ret.resize(2 * srclen);
BF_ecb_encrypt(CV, CV, &BlowfishKey, BF_ENCRYPT);
const uint64_t* blocks = reinterpret_cast<const uint64_t*>(srcBytes);
size_t blocks_len = srclen / BF_BLOCK;
for (size_t i = 0; i < blocks_len; ++i) {
union {
uint8_t byte[8];
uint64_t qword;
} temp;
temp.qword = blocks[i];
temp.qword ^= *reinterpret_cast<uint64_t*>(CV);
BF_ecb_encrypt(temp.byte, temp.byte, &BlowfishKey, BF_ENCRYPT);
*reinterpret_cast<uint64_t*>(CV) ^= temp.qword;
BytesToHex(&temp, 8, ret.data() + 16 * i);
}
if (srclen % BF_BLOCK) {
BF_ecb_encrypt(CV, CV, &BlowfishKey, BF_ENCRYPT);
for (size_t i = 0; i < srclen % BF_BLOCK; ++i) {
CV[i] ^= reinterpret_cast<const uint8_t*>(blocks + blocks_len)[i];
}
BytesToHex(CV, srclen % BF_BLOCK, ret.data() + 16 * blocks_len);
}
return ret;
}
std::string DecryptString(const char* srchex, size_t srclen) {
std::string ret;
uint8_t CV[BF_BLOCK] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
if (CheckHex(srchex, srclen) == false)
return ret;
ret.resize(srclen / 2);
BF_ecb_encrypt(CV, CV, &BlowfishKey, BF_ENCRYPT);
const char(*blocks)[16] = reinterpret_cast<const char(*)[16]>(srchex);
size_t blocks_len = srclen / 16;
for (size_t i = 0; i < blocks_len; ++i) {
union {
uint8_t byte[8];
uint64_t qword;
} temp, temp2;
HexToBytes(blocks[i], 16, temp.byte);
temp2.qword = temp.qword;
BF_ecb_encrypt(temp.byte, temp.byte, &BlowfishKey, BF_DECRYPT);
temp.qword ^= *reinterpret_cast<uint64_t*>(CV);
*reinterpret_cast<uint64_t*>(ret.data() + 8 * i) = temp.qword;
*reinterpret_cast<uint64_t*>(CV) ^= temp2.qword;
}
if (srclen % 16) {
union {
uint8_t byte[8];
uint64_t qword;
} temp = { };
HexToBytes(blocks[blocks_len], srclen % 16, temp.byte);
BF_ecb_encrypt(CV, CV, &BlowfishKey, BF_ENCRYPT);
for (size_t i = 0; i < (srclen % 16) / 2; ++i)
ret[blocks_len * 8 + i] = temp.byte[i] ^ CV[i];
}
return ret;
}
void Clear() {
OPENSSL_cleanse(&BlowfishKey, sizeof(BlowfishKey));
}
~Navicat11Crypto() {
Clear();
}
};
@@ -1,291 +0,0 @@
#pragma once
#include "aes.h"
#include "blowfish.h"
#include "SHA1.h"
#include <vector>
class Navicat11Crypto {
protected:
BLOWFISH_KEY BlowfishKey;
void BytesToHex(const void* src, size_t len, char* dst) {
for (size_t i = 0; i < len; ++i) {
char h = reinterpret_cast<const uint8_t*>(src)[i] >> 4;
char l = reinterpret_cast<const uint8_t*>(src)[i] & 0x0F;
h += h >= 10 ? 'A' - 10 : '0';
l += l >= 10 ? 'A' - 10 : '0';
dst[2 * i] = h;
dst[2 * i + 1] = l;
}
}
bool CheckHex(const char* src, size_t len) {
if (len % 2 != 0)
return false;
for (size_t i = 0; i < len; i += 2) {
char h = src[i];
char l = src[i + 1];
if (src[i] < '0' || src[i] > 'F')
return false;
if (src[i] < 'A' && src[i] > '9')
return false;
if (src[i + 1] < '0' || src[i + 1] > 'F')
return false;
if (src[i + 1] < 'A' && src[i + 1] > '9')
return false;
}
return true;
}
void HexToBytes(const char* src, size_t len, void* dst) {
for (size_t i = 0; i < len; i += 2) {
uint8_t h = src[i];
uint8_t l = src[i + 1];
h -= h > '9' ? 'A' - 10 : '0';
l -= l > '9' ? 'A' - 10 : '0';
reinterpret_cast<uint8_t*>(dst)[i / 2] = (h << 4 )^ l;
}
}
public:
Navicat11Crypto() {
const uint8_t DefaultKey[8] = {
'3', 'D', 'C', '5', 'C', 'A', '3', '9'
};
SHA1_DIGEST KeyHash;
accelc_SHA1(DefaultKey, sizeof(DefaultKey), &KeyHash);
accelc_Blowfish_set_key(KeyHash.byte, sizeof(KeyHash), &BlowfishKey);
}
Navicat11Crypto(const void* srcBytes, size_t srclen) {
if (srclen == 0)
srclen = BLOWFISH_MIN_KEY_LENGTH;
if (srclen > BLOWFISH_MAX_KEY_LENGTH)
srclen = BLOWFISH_MAX_KEY_LENGTH;
SHA1_DIGEST KeyHash;
accelc_SHA1(srcBytes, srclen, &KeyHash);
accelc_Blowfish_set_key(KeyHash.byte, sizeof(KeyHash), &BlowfishKey);
}
std::vector<char> EncryptString(const void* srcBytes, size_t srclen) {
std::vector<char> ret;
if (srclen == 0)
return ret;
ret.resize(srclen * 2 + 1);
ret[srclen * 2] = 0;
uint8_t CV[BLOWFISH_BLOCK_SIZE] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
accelc_Blowfish_encrypt(CV, &BlowfishKey, BLOWFISH_BIG_ENDIAN);
const uint64_t* blocks = reinterpret_cast<const uint64_t*>(srcBytes);
size_t blocks_len = srclen / BLOWFISH_BLOCK_SIZE;
for (size_t i = 0; i < blocks_len; ++i) {
union {
uint8_t byte[8];
uint64_t qword;
} temp;
temp.qword = blocks[i];
temp.qword ^= *reinterpret_cast<uint64_t*>(CV);
accelc_Blowfish_encrypt(temp.byte, &BlowfishKey, BLOWFISH_BIG_ENDIAN);
*reinterpret_cast<uint64_t*>(CV) ^= temp.qword;
BytesToHex(temp.byte, 8, ret.data() + 16 * i);
}
if (srclen % BLOWFISH_BLOCK_SIZE) {
accelc_Blowfish_encrypt(CV, &BlowfishKey, BLOWFISH_BIG_ENDIAN);
for (size_t i = 0; i < srclen % BLOWFISH_BLOCK_SIZE; ++i)
CV[i] ^= reinterpret_cast<const uint8_t*>(blocks + blocks_len)[i];
BytesToHex(CV, srclen % BLOWFISH_BLOCK_SIZE, ret.data() + 16 * blocks_len);
}
return ret;
}
std::vector<uint8_t> DecryptString(const char* srchex, size_t srclen) {
std::vector<uint8_t> ret;
if (CheckHex(srchex, srclen) == false)
return ret;
ret.resize(srclen / 2);
uint8_t CV[BLOWFISH_BLOCK_SIZE] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
accelc_Blowfish_encrypt(CV, &BlowfishKey, BLOWFISH_BIG_ENDIAN);
const char (*blocks)[16] = reinterpret_cast<const char (*)[16]>(srchex);
size_t blocks_len = srclen / 16;
for (size_t i = 0; i < blocks_len; ++i) {
union {
uint8_t byte[8];
uint64_t qword;
} temp, temp2;
HexToBytes(blocks[i], 16, temp.byte);
std::memcpy(temp2.byte, temp.byte, 8);
accelc_Blowfish_decrypt(temp.byte, &BlowfishKey, BLOWFISH_BIG_ENDIAN);
temp.qword ^= *reinterpret_cast<uint64_t*>(CV);
*reinterpret_cast<uint64_t*>(ret.data() + 8 * i) = temp.qword;
*reinterpret_cast<uint64_t*>(CV) ^= temp2.qword;
}
if (srclen % 16) {
union {
uint8_t byte[8];
uint64_t qword;
} temp = { };
HexToBytes(blocks[blocks_len], srclen % 16, temp.byte);
accelc_Blowfish_encrypt(CV, &BlowfishKey, BLOWFISH_BIG_ENDIAN);
for (size_t i = 0; i < (srclen % 16) / 2; ++i)
ret[blocks_len * 8 + i] = temp.byte[i] ^ CV[i];
}
return ret;
}
};
class Navicat12Crypto : public Navicat11Crypto {
protected:
AES_KEY AES128Key;
public:
Navicat12Crypto() : Navicat11Crypto() {
uint8_t DefaultKey[16] = {
'l', 'i', 'b', 'c', 'c', 'k', 'e', 'y',
'l', 'i', 'b', 'c', 'c', 'k', 'e', 'y'
};
accelc_AES128_set_key(DefaultKey, &AES128Key);
}
Navicat12Crypto(const void* srcBytes, size_t srclen) :
Navicat11Crypto(srcBytes, srclen) {
uint8_t DefaultKey[16] = {
'l', 'i', 'b', 'c', 'c', 'k', 'e', 'y',
'l', 'i', 'b', 'c', 'c', 'k', 'e', 'y'
};
accelc_AES128_set_key(DefaultKey, &AES128Key);
}
std::vector<char> EncryptString(const void* srcBytes, size_t srclen) {
std::vector<char> ret;
if (srclen == 0)
return ret;
ret.resize((srclen / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE * 2);
union {
uint8_t byte[AES_BLOCK_SIZE];
uint64_t qword[2];
} CV = {
'l', 'i', 'b', 'c', 'c', 'i', 'v', ' ',
'l', 'i', 'b', 'c', 'c', 'i', 'v', ' '
};
const uint8_t (*blocks)[AES_BLOCK_SIZE] = reinterpret_cast<const uint8_t (*)[AES_BLOCK_SIZE]>(srcBytes);
size_t blocks_len = srclen / AES_BLOCK_SIZE;
for (size_t i = 0; i < blocks_len; ++i) {
union {
uint8_t byte[AES_BLOCK_SIZE];
uint64_t qword[2];
} temp;
std::memcpy(temp.byte, blocks[i], AES_BLOCK_SIZE);
temp.qword[0] ^= CV.qword[0];
temp.qword[1] ^= CV.qword[1];
accelc_AES128_encrypt(temp.byte, &AES128Key);
BytesToHex(temp.byte, AES_BLOCK_SIZE, ret.data() + 2 * AES_BLOCK_SIZE * i);
CV.qword[0] = temp.qword[0];
CV.qword[1] = temp.qword[1];
}
uint8_t padding = AES_BLOCK_SIZE - srclen % AES_BLOCK_SIZE;
union {
uint8_t byte[AES_BLOCK_SIZE];
uint64_t qword[2];
} temp;
std::memcpy(temp.byte, blocks[blocks_len], srclen % AES_BLOCK_SIZE);
for (size_t i = srclen % AES_BLOCK_SIZE; i < AES_BLOCK_SIZE; ++i)
temp.byte[i] = padding;
temp.qword[0] ^= CV.qword[0];
temp.qword[1] ^= CV.qword[1];
accelc_AES128_encrypt(temp.byte, &AES128Key);
BytesToHex(temp.byte, AES_BLOCK_SIZE, ret.data() + 2 * AES_BLOCK_SIZE * blocks_len);
return ret;
}
std::vector<uint8_t> DecryptString(const char* srchex, size_t srclen) {
std::vector<uint8_t> ret;
if (srclen % (2 * AES_BLOCK_SIZE) != 0 || CheckHex(srchex, srclen) == false)
return ret;
ret.reserve(srclen / 2);
ret.resize(srclen / 2 - AES_BLOCK_SIZE);
union {
uint8_t byte[AES_BLOCK_SIZE];
uint64_t qword[2];
} CV = {
'l', 'i', 'b', 'c', 'c', 'i', 'v', ' ',
'l', 'i', 'b', 'c', 'c', 'i', 'v', ' '
};
const char (*blocks)[2 * AES_BLOCK_SIZE] = reinterpret_cast<const char(*)[2 * AES_BLOCK_SIZE]>(srchex);
size_t blocks_len = srclen / (2 * AES_BLOCK_SIZE);
for (size_t i = 0; i < blocks_len; ++i) {
union {
uint8_t byte[AES_BLOCK_SIZE];
uint64_t qword[2];
} temp, NextVector;
HexToBytes(blocks[i], 2 * AES_BLOCK_SIZE, temp.byte);
std::memcpy(NextVector.byte, temp.byte, AES_BLOCK_SIZE);
accelc_AES128_decrypt(temp.byte, &AES128Key);
temp.qword[0] ^= CV.qword[0];
temp.qword[1] ^= CV.qword[1];
std::memcpy(ret.data() + AES_BLOCK_SIZE * i, temp.byte, AES_BLOCK_SIZE);
std::memcpy(CV.byte, NextVector.byte, AES_BLOCK_SIZE);
}
union {
uint8_t byte[AES_BLOCK_SIZE];
uint64_t qword[2];
} temp;
HexToBytes(blocks[blocks_len], 2 * AES_BLOCK_SIZE, temp.byte);
accelc_AES128_decrypt(temp.byte, &AES128Key);
temp.qword[0] ^= CV.qword[0];
temp.qword[1] ^= CV.qword[1];
if (temp.byte[AES_BLOCK_SIZE - 1] > AES_BLOCK_SIZE) {
ret.clear();
return ret;
} else {
uint8_t padding = temp.byte[AES_BLOCK_SIZE - 1];
for (int i = AES_BLOCK_SIZE - padding; i < AES_BLOCK_SIZE; ++i)
if (temp.byte[i] != padding) {
ret.clear();
return ret;
}
for (int i = 0; i < (AES_BLOCK_SIZE - padding); ++i)
ret.emplace_back(temp.byte[i]);
}
return ret;
}
};
-438
View File
@@ -1,438 +0,0 @@
#include "aes.h"
#if defined(_MSC_VER)
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
extern const uint32_t accelc_aes_rcon[11];
extern const uint8_t accelc_aes_SBox[256];
extern const uint8_t accelc_aes_InverseSBox[256];
extern const uint8_t accelc_aes_GF2p8_Mul_0x02[256];
extern const uint8_t accelc_aes_GF2p8_Mul_0x03[256];
extern const uint8_t accelc_aes_GF2p8_Mul_0x09[256];
extern const uint8_t accelc_aes_GF2p8_Mul_0x0B[256];
extern const uint8_t accelc_aes_GF2p8_Mul_0x0D[256];
extern const uint8_t accelc_aes_GF2p8_Mul_0x0E[256];
#define Swap(X, Y, Temp) \
Temp = X; \
X = Y; \
Y = Temp;
void accelc_AES128_encrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey) {
((uint64_t*)srcBytes)[0] ^= srcKey->qword[0];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[1];
uint8_t ShiftTemp = 0;
for (int i = 1; i < 10; ++i) {
for (int j = 0; j < 16; ++j)
srcBytes[j] = accelc_aes_SBox[srcBytes[j]];
//Shift rows starts;
//Shift the second row;
Swap(srcBytes[1], srcBytes[5], ShiftTemp)
Swap(srcBytes[5], srcBytes[9], ShiftTemp)
Swap(srcBytes[9], srcBytes[13], ShiftTemp)
//Shift the third row;
Swap(srcBytes[2], srcBytes[10], ShiftTemp)
Swap(srcBytes[6], srcBytes[14], ShiftTemp)
//Shift the fourth row;
Swap(srcBytes[3], srcBytes[15], ShiftTemp)
Swap(srcBytes[15], srcBytes[11], ShiftTemp)
Swap(srcBytes[11], srcBytes[7], ShiftTemp)
//Shift rows ends;
for (int j = 0; j < 16; j += 4) {
uint8_t temp[4];
*(uint32_t*)temp = ((uint32_t*)srcBytes)[j / 4];
srcBytes[j] = (uint8_t)(accelc_aes_GF2p8_Mul_0x02[temp[0]] ^ accelc_aes_GF2p8_Mul_0x03[temp[1]] ^ temp[2] ^ temp[3]);
srcBytes[j + 1] = (uint8_t)(temp[0] ^ accelc_aes_GF2p8_Mul_0x02[temp[1]] ^ accelc_aes_GF2p8_Mul_0x03[temp[2]] ^ temp[3]);
srcBytes[j + 2] = (uint8_t)(temp[0] ^ temp[1] ^ accelc_aes_GF2p8_Mul_0x02[temp[2]] ^ accelc_aes_GF2p8_Mul_0x03[temp[3]]);
srcBytes[j + 3] = (uint8_t)(accelc_aes_GF2p8_Mul_0x03[temp[0]] ^ temp[1] ^ temp[2] ^ accelc_aes_GF2p8_Mul_0x02[temp[3]]);
}
((uint64_t*)(srcBytes))[0] ^= srcKey->qword[i * 2];
((uint64_t*)(srcBytes))[1] ^= srcKey->qword[i * 2 + 1];
}
for (int j = 0; j < 16; ++j)
srcBytes[j] = accelc_aes_SBox[srcBytes[j]];
//Shift rows starts;
//Shift the second row;
Swap(srcBytes[1], srcBytes[5], ShiftTemp)
Swap(srcBytes[5], srcBytes[9], ShiftTemp)
Swap(srcBytes[9], srcBytes[13], ShiftTemp)
//Shift the third row;
Swap(srcBytes[2], srcBytes[10], ShiftTemp)
Swap(srcBytes[6], srcBytes[14], ShiftTemp)
//Shift the fourth row;
Swap(srcBytes[3], srcBytes[15], ShiftTemp)
Swap(srcBytes[15], srcBytes[11], ShiftTemp)
Swap(srcBytes[11], srcBytes[7], ShiftTemp)
//Shift rows ends;
((uint64_t*)srcBytes)[0] ^= srcKey->qword[20];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[21];
}
void accelc_AES128_decrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey) {
((uint64_t*)srcBytes)[0] ^= srcKey->qword[20];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[21];
uint8_t ShiftTemp = 0;
for (int i = 9; i > 0; --i) {
//Inverse Shift rows starts;
//Inverse shift the second row;
Swap(srcBytes[13], srcBytes[9], ShiftTemp)
Swap(srcBytes[9], srcBytes[5], ShiftTemp)
Swap(srcBytes[5], srcBytes[1], ShiftTemp)
//Inverse shift the third row;
Swap(srcBytes[14], srcBytes[6], ShiftTemp)
Swap(srcBytes[10], srcBytes[2], ShiftTemp)
//Inverse shift the fourth row;
Swap(srcBytes[3], srcBytes[7], ShiftTemp)
Swap(srcBytes[7], srcBytes[11], ShiftTemp)
Swap(srcBytes[11], srcBytes[15], ShiftTemp)
for (int j = 0; j < 16; ++j)
srcBytes[j] = accelc_aes_InverseSBox[srcBytes[j]];
((uint64_t*)srcBytes)[0] ^= srcKey->qword[i * 2];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[i * 2 + 1];
for (int j = 0; j < 16; j += 4) {
uint8_t temp[4];
*(uint32_t*)temp = ((uint32_t*)srcBytes)[j / 4];
srcBytes[j] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0E[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[2]] ^ accelc_aes_GF2p8_Mul_0x09[temp[3]]);
srcBytes[j + 1] = (uint8_t)(accelc_aes_GF2p8_Mul_0x09[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[3]]);
srcBytes[j + 2] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0D[temp[0]] ^ accelc_aes_GF2p8_Mul_0x09[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[3]]);
srcBytes[j + 3] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0B[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[1]] ^ accelc_aes_GF2p8_Mul_0x09[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[3]]);
}
}
//Inverse Shift rows starts;
//Inverse shift the second row;
Swap(srcBytes[13], srcBytes[9], ShiftTemp)
Swap(srcBytes[9], srcBytes[5], ShiftTemp)
Swap(srcBytes[5], srcBytes[1], ShiftTemp)
//Inverse shift the third row;
Swap(srcBytes[14], srcBytes[6], ShiftTemp)
Swap(srcBytes[10], srcBytes[2], ShiftTemp)
//Inverse shift the fourth row;
Swap(srcBytes[3], srcBytes[7], ShiftTemp)
Swap(srcBytes[7], srcBytes[11], ShiftTemp)
Swap(srcBytes[11], srcBytes[15], ShiftTemp)
for (int j = 0; j < 16; ++j)
srcBytes[j] = accelc_aes_InverseSBox[srcBytes[j]];
((uint64_t*)srcBytes)[0] ^= srcKey->qword[0];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[1];
}
void accelc_AES128_set_key(const uint8_t srcUserKey[16], AES_KEY* dstKey) {
dstKey->qword[0] = ((const uint64_t*)srcUserKey)[0];
dstKey->qword[1] = ((const uint64_t*)srcUserKey)[1];
for (int i = 4; i < 44; ++i) {
uint32_t temp = dstKey->dword[i - 1];
if (i % 4 == 0) {
temp = _rotr(temp, 8);
((uint8_t*)&temp)[0] = accelc_aes_SBox[((uint8_t*)&temp)[0]];
((uint8_t*)&temp)[1] = accelc_aes_SBox[((uint8_t*)&temp)[1]];
((uint8_t*)&temp)[2] = accelc_aes_SBox[((uint8_t*)&temp)[2]];
((uint8_t*)&temp)[3] = accelc_aes_SBox[((uint8_t*)&temp)[3]];
temp ^= accelc_aes_rcon[i / 4];
}
dstKey->dword[i] = dstKey->dword[i - 4] ^ temp;
}
}
void accelc_AES192_encrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey) {
((uint64_t*)srcBytes)[0] ^= srcKey->qword[0];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[1];
uint8_t ShiftTemp = 0;
for (int i = 1; i < 12; ++i) {
for (int j = 0; j < 16; ++j)
srcBytes[j] = accelc_aes_SBox[srcBytes[j]];
//Shift rows starts;
//Shift the second row;
Swap(srcBytes[1], srcBytes[5], ShiftTemp)
Swap(srcBytes[5], srcBytes[9], ShiftTemp)
Swap(srcBytes[9], srcBytes[13], ShiftTemp)
//Shift the third row;
Swap(srcBytes[2], srcBytes[10], ShiftTemp)
Swap(srcBytes[6], srcBytes[14], ShiftTemp)
//Shift the fourth row;
Swap(srcBytes[3], srcBytes[15], ShiftTemp)
Swap(srcBytes[15], srcBytes[11], ShiftTemp)
Swap(srcBytes[11], srcBytes[7], ShiftTemp)
//Shift rows ends;
for (int j = 0; j < 16; j += 4) {
uint8_t temp[4];
*(uint32_t*)temp = ((uint32_t*)srcBytes)[j / 4];
srcBytes[j] = (uint8_t)(accelc_aes_GF2p8_Mul_0x02[temp[0]] ^ accelc_aes_GF2p8_Mul_0x03[temp[1]] ^ temp[2] ^ temp[3]);
srcBytes[j + 1] = (uint8_t)(temp[0] ^ accelc_aes_GF2p8_Mul_0x02[temp[1]] ^ accelc_aes_GF2p8_Mul_0x03[temp[2]] ^ temp[3]);
srcBytes[j + 2] = (uint8_t)(temp[0] ^ temp[1] ^ accelc_aes_GF2p8_Mul_0x02[temp[2]] ^ accelc_aes_GF2p8_Mul_0x03[temp[3]]);
srcBytes[j + 3] = (uint8_t)(accelc_aes_GF2p8_Mul_0x03[temp[0]] ^ temp[1] ^ temp[2] ^ accelc_aes_GF2p8_Mul_0x02[temp[3]]);
}
((uint64_t*)srcBytes)[0] ^= srcKey->qword[i * 2];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[i * 2 + 1];
}
for (int j = 0; j < 16; ++j)
srcBytes[j] = accelc_aes_SBox[srcBytes[j]];
//Shift rows starts;
//Shift the second row;
Swap(srcBytes[1], srcBytes[5], ShiftTemp) //Swap is a MACRO, no need to add ';'.
Swap(srcBytes[5], srcBytes[9], ShiftTemp)
Swap(srcBytes[9], srcBytes[13], ShiftTemp)
//Shift the third row;
Swap(srcBytes[2], srcBytes[10], ShiftTemp)
Swap(srcBytes[6], srcBytes[14], ShiftTemp)
//Shift the fourth row;
Swap(srcBytes[3], srcBytes[15], ShiftTemp)
Swap(srcBytes[15], srcBytes[11], ShiftTemp)
Swap(srcBytes[11], srcBytes[7], ShiftTemp)
//Shift rows ends;
((uint64_t*)srcBytes)[0] ^= srcKey->qword[24];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[25];
}
void accelc_AES192_decrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey) {
((uint64_t*)srcBytes)[0] ^= srcKey->qword[24];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[25];
uint8_t ShiftTemp = 0;
for (int i = 11; i > 0; --i) {
//Inverse Shift rows starts;
//Inverse shift the second row;
Swap(srcBytes[13], srcBytes[9], ShiftTemp)
Swap(srcBytes[9], srcBytes[5], ShiftTemp)
Swap(srcBytes[5], srcBytes[1], ShiftTemp)
//Inverse shift the third row;
Swap(srcBytes[14], srcBytes[6], ShiftTemp)
Swap(srcBytes[10], srcBytes[2], ShiftTemp)
//Inverse shift the fourth row;
Swap(srcBytes[3], srcBytes[7], ShiftTemp)
Swap(srcBytes[7], srcBytes[11], ShiftTemp)
Swap(srcBytes[11], srcBytes[15], ShiftTemp)
for (int j = 0; j < 16; ++j)
srcBytes[j] = accelc_aes_InverseSBox[srcBytes[j]];
((uint64_t*)srcBytes)[0] ^= srcKey->qword[i * 2];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[i * 2 + 1];
for (int j = 0; j < 16; j += 4) {
uint8_t temp[4];
*(uint32_t*)temp = ((uint32_t*)srcBytes)[j / 4];
srcBytes[j] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0E[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[2]] ^ accelc_aes_GF2p8_Mul_0x09[temp[3]]);
srcBytes[j + 1] = (uint8_t)(accelc_aes_GF2p8_Mul_0x09[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[3]]);
srcBytes[j + 2] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0D[temp[0]] ^ accelc_aes_GF2p8_Mul_0x09[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[3]]);
srcBytes[j + 3] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0B[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[1]] ^ accelc_aes_GF2p8_Mul_0x09[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[3]]);
}
}
//Inverse Shift rows starts;
//Inverse shift the second row;
Swap(srcBytes[13], srcBytes[9], ShiftTemp)
Swap(srcBytes[9], srcBytes[5], ShiftTemp)
Swap(srcBytes[5], srcBytes[1], ShiftTemp)
//Inverse shift the third row;
Swap(srcBytes[14], srcBytes[6], ShiftTemp)
Swap(srcBytes[10], srcBytes[2], ShiftTemp)
//Inverse shift the fourth row;
Swap(srcBytes[3], srcBytes[7], ShiftTemp)
Swap(srcBytes[7], srcBytes[11], ShiftTemp)
Swap(srcBytes[11], srcBytes[15], ShiftTemp)
for (uint8_t j = 0; j < 16; ++j)
srcBytes[j] = accelc_aes_InverseSBox[srcBytes[j]];
((uint64_t*)srcBytes)[0] ^= srcKey->qword[0];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[1];
}
void accelc_AES192_set_key(const uint8_t srcUserKey[24], AES_KEY* dstKey) {
dstKey->qword[0] = ((const uint64_t*)srcUserKey)[0];
dstKey->qword[1] = ((const uint64_t*)srcUserKey)[1];
dstKey->qword[2] = ((const uint64_t*)srcUserKey)[2];
for (int i = 6; i < 52; ++i) {
uint32_t temp = dstKey->dword[i - 1];
if (i % 6 == 0) {
temp = _rotr(temp, 8);
((uint8_t*)&temp)[0] = accelc_aes_SBox[((uint8_t*)&temp)[0]];
((uint8_t*)&temp)[1] = accelc_aes_SBox[((uint8_t*)&temp)[1]];
((uint8_t*)&temp)[2] = accelc_aes_SBox[((uint8_t*)&temp)[2]];
((uint8_t*)&temp)[3] = accelc_aes_SBox[((uint8_t*)&temp)[3]];
temp ^= accelc_aes_rcon[i / 6];
}
dstKey->dword[i] = dstKey->dword[i - 6] ^ temp;
}
}
void accelc_AES256_encrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey) {
((uint64_t*)srcBytes)[0] ^= srcKey->qword[0];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[1];
uint8_t ShiftTemp = 0;
for (int i = 1; i < 14; ++i) {
for (int j = 0; j < 16; ++j)
srcBytes[j] = accelc_aes_SBox[srcBytes[j]];
//Shift rows starts;
//Shift the second row;
Swap(srcBytes[1], srcBytes[5], ShiftTemp)
Swap(srcBytes[5], srcBytes[9], ShiftTemp)
Swap(srcBytes[9], srcBytes[13], ShiftTemp)
//Shift the third row;
Swap(srcBytes[2], srcBytes[10], ShiftTemp)
Swap(srcBytes[6], srcBytes[14], ShiftTemp)
//Shift the fourth row;
Swap(srcBytes[3], srcBytes[15], ShiftTemp)
Swap(srcBytes[15], srcBytes[11], ShiftTemp)
Swap(srcBytes[11], srcBytes[7], ShiftTemp)
//Shift rows ends;
for (int j = 0; j < 16; j += 4) {
uint8_t temp[4];
*(uint32_t*)temp = ((uint32_t*)srcBytes)[j / 4];
srcBytes[j] = (uint8_t)(accelc_aes_GF2p8_Mul_0x02[temp[0]] ^ accelc_aes_GF2p8_Mul_0x03[temp[1]] ^ temp[2] ^ temp[3]);
srcBytes[j + 1] = (uint8_t)(temp[0] ^ accelc_aes_GF2p8_Mul_0x02[temp[1]] ^ accelc_aes_GF2p8_Mul_0x03[temp[2]] ^ temp[3]);
srcBytes[j + 2] = (uint8_t)(temp[0] ^ temp[1] ^ accelc_aes_GF2p8_Mul_0x02[temp[2]] ^ accelc_aes_GF2p8_Mul_0x03[temp[3]]);
srcBytes[j + 3] = (uint8_t)(accelc_aes_GF2p8_Mul_0x03[temp[0]] ^ temp[1] ^ temp[2] ^ accelc_aes_GF2p8_Mul_0x02[temp[3]]);
}
((uint64_t*)srcBytes)[0] ^= srcKey->qword[i * 2];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[i * 2 + 1];
}
for (int j = 0; j < 16; ++j)
srcBytes[j] = accelc_aes_SBox[srcBytes[j]];
//Shift rows starts;
//Shift the second row;
Swap(srcBytes[1], srcBytes[5], ShiftTemp)
Swap(srcBytes[5], srcBytes[9], ShiftTemp)
Swap(srcBytes[9], srcBytes[13], ShiftTemp)
//Shift the third row;
Swap(srcBytes[2], srcBytes[10], ShiftTemp)
Swap(srcBytes[6], srcBytes[14], ShiftTemp)
//Shift the fourth row;
Swap(srcBytes[3], srcBytes[15], ShiftTemp)
Swap(srcBytes[15], srcBytes[11], ShiftTemp)
Swap(srcBytes[11], srcBytes[7], ShiftTemp)
//Shift rows ends;
((uint64_t*)srcBytes)[0] ^= srcKey->qword[28];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[29];
}
void accelc_AES256_decrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey) {
((uint64_t*)srcBytes)[0] ^= srcKey->qword[28];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[29];
uint8_t ShiftTemp = 0;
for (int i = 13; i > 0; --i) {
//Inverse Shift rows starts;
//Inverse shift the second row;
Swap(srcBytes[13], srcBytes[9], ShiftTemp)
Swap(srcBytes[9], srcBytes[5], ShiftTemp)
Swap(srcBytes[5], srcBytes[1], ShiftTemp)
//Inverse shift the third row;
Swap(srcBytes[14], srcBytes[6], ShiftTemp)
Swap(srcBytes[10], srcBytes[2], ShiftTemp)
//Inverse shift the fourth row;
Swap(srcBytes[3], srcBytes[7], ShiftTemp)
Swap(srcBytes[7], srcBytes[11], ShiftTemp)
Swap(srcBytes[11], srcBytes[15], ShiftTemp)
for (int j = 0; j < 16; ++j)
srcBytes[j] = accelc_aes_InverseSBox[srcBytes[j]];
((uint64_t*)srcBytes)[0] ^= srcKey->qword[i * 2];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[i * 2 + 1];
for (int j = 0; j < 16; j += 4) {
uint8_t temp[4];
*(uint32_t*)temp = ((uint32_t*)srcBytes)[j / 4];
srcBytes[j] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0E[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[2]] ^ accelc_aes_GF2p8_Mul_0x09[temp[3]]);
srcBytes[j + 1] = (uint8_t)(accelc_aes_GF2p8_Mul_0x09[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[3]]);
srcBytes[j + 2] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0D[temp[0]] ^ accelc_aes_GF2p8_Mul_0x09[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[3]]);
srcBytes[j + 3] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0B[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[1]] ^ accelc_aes_GF2p8_Mul_0x09[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[3]]);
}
}
//Inverse Shift rows starts;
//Inverse shift the second row;
Swap(srcBytes[13], srcBytes[9], ShiftTemp)
Swap(srcBytes[9], srcBytes[5], ShiftTemp)
Swap(srcBytes[5], srcBytes[1], ShiftTemp)
//Inverse shift the third row;
Swap(srcBytes[14], srcBytes[6], ShiftTemp)
Swap(srcBytes[10], srcBytes[2], ShiftTemp)
//Inverse shift the fourth row;
Swap(srcBytes[3], srcBytes[7], ShiftTemp)
Swap(srcBytes[7], srcBytes[11], ShiftTemp)
Swap(srcBytes[11], srcBytes[15], ShiftTemp)
for (int j = 0; j < 16; ++j)
srcBytes[j] = accelc_aes_InverseSBox[srcBytes[j]];
((uint64_t*)srcBytes)[0] ^= srcKey->qword[0];
((uint64_t*)srcBytes)[1] ^= srcKey->qword[1];
}
void accelc_AES256_set_key(const uint8_t srcUserKey[32], AES_KEY* dstKey) {
dstKey->qword[0] = ((const uint64_t*)srcUserKey)[0];
dstKey->qword[1] = ((const uint64_t*)srcUserKey)[1];
dstKey->qword[2] = ((const uint64_t*)srcUserKey)[2];
dstKey->qword[3] = ((const uint64_t*)srcUserKey)[3];
for (int i = 8; i < 60; ++i) {
uint32_t temp = dstKey->dword[i - 1];
if (i % 8 == 0) {
temp = _rotr(temp, 8);
((uint8_t*)&temp)[0] = accelc_aes_SBox[((uint8_t*)&temp)[0]];
((uint8_t*)&temp)[1] = accelc_aes_SBox[((uint8_t*)&temp)[1]];
((uint8_t*)&temp)[2] = accelc_aes_SBox[((uint8_t*)&temp)[2]];
((uint8_t*)&temp)[3] = accelc_aes_SBox[((uint8_t*)&temp)[3]];
temp ^= accelc_aes_rcon[i / 8];
}
if (i % 8 == 4) {
((uint8_t*)&temp)[0] = accelc_aes_SBox[((uint8_t*)&temp)[0]];
((uint8_t*)&temp)[1] = accelc_aes_SBox[((uint8_t*)&temp)[1]];
((uint8_t*)&temp)[2] = accelc_aes_SBox[((uint8_t*)&temp)[2]];
((uint8_t*)&temp)[3] = accelc_aes_SBox[((uint8_t*)&temp)[3]];
}
dstKey->dword[i] = dstKey->dword[i - 8] ^ temp;
}
}
-82
View File
@@ -1,82 +0,0 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#if defined(__cplusplus)
extern "C" {
#endif
#define AES_BLOCK_SIZE 16
#define AES128_USERKEY_LENGTH 16
#define AES192_USERKEY_LENGTH 24
#define AES256_USERKEY_LENGTH 32
typedef struct _AES_KEY {
union {
uint8_t byte[240];
uint16_t word[120];
uint32_t dword[60];
uint64_t qword[30];
};
} AES_KEY;
//
// encrypt
//
void accelc_AES128_encrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
void accelc_AES192_encrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
void accelc_AES256_encrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
//
// dncrypt
//
void accelc_AES128_decrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
void accelc_AES192_decrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
void accelc_AES256_decrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
//
// set_key
//
void accelc_AES128_set_key(const uint8_t srcUserKey[AES128_USERKEY_LENGTH], AES_KEY* dstKey);
void accelc_AES192_set_key(const uint8_t srcUserKey[AES192_USERKEY_LENGTH], AES_KEY* dstKey);
void accelc_AES256_set_key(const uint8_t srcUserKey[AES256_USERKEY_LENGTH], AES_KEY* dstKey);
//
// encrypt_aesni
//
void accelc_AES128_encrypt_aesni(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
void accelc_AES192_encrypt_aesni(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
void accelc_AES256_encrypt_aesni(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
//
// decrypt_aesni
//
void accelc_AES128_decrypt_aesni(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
void accelc_AES192_decrypt_aesni(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
void accelc_AES256_decrypt_aesni(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
//
// decrypt_aesni_fast
//
void accelc_AES128_decrypt_aesni_fast(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcInverseKey);
void accelc_AES192_decrypt_aesni_fast(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcInverseKey);
void accelc_AES256_decrypt_aesni_fast(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcInverseKey);
//
// set_key_aesni
//
void accelc_AES128_set_key_aesni(const uint8_t srcUserKey[AES128_USERKEY_LENGTH], AES_KEY* dstKey);
void accelc_AES192_set_key_aesni(const uint8_t srcUserKey[AES128_USERKEY_LENGTH], AES_KEY* dstKey);
void accelc_AES256_set_key_aesni(const uint8_t srcUserKey[AES256_USERKEY_LENGTH], AES_KEY* dstKey);
//
// set_invkey_aesni
//
void accelc_AES128_set_invkey_aesni(const AES_KEY* __restrict srcKey, AES_KEY* __restrict dstInverseKey);
void accelc_AES192_set_invkey_aesni(const AES_KEY* __restrict srcKey, AES_KEY* __restrict dstInverseKey);
void accelc_AES256_set_invkey_aesni(const AES_KEY* __restrict srcKey, AES_KEY* __restrict dstInverseKey);
#if defined(__cplusplus)
}
#endif
@@ -1,157 +0,0 @@
#include <stdint.h>
const uint8_t accelc_aes_SBox[256] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};
const uint32_t accelc_aes_rcon[11] = {
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
};
const uint8_t accelc_aes_GF2p8_Mul_0x02[256] = {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E,
0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E,
0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5A, 0x5C, 0x5E,
0x60, 0x62, 0x64, 0x66, 0x68, 0x6A, 0x6C, 0x6E, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7A, 0x7C, 0x7E,
0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9A, 0x9C, 0x9E,
0xA0, 0xA2, 0xA4, 0xA6, 0xA8, 0xAA, 0xAC, 0xAE, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0xBE,
0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE, 0xF0, 0xF2, 0xF4, 0xF6, 0xF8, 0xFA, 0xFC, 0xFE,
0x1B, 0x19, 0x1F, 0x1D, 0x13, 0x11, 0x17, 0x15, 0x0B, 0x09, 0x0F, 0x0D, 0x03, 0x01, 0x07, 0x05,
0x3B, 0x39, 0x3F, 0x3D, 0x33, 0x31, 0x37, 0x35, 0x2B, 0x29, 0x2F, 0x2D, 0x23, 0x21, 0x27, 0x25,
0x5B, 0x59, 0x5F, 0x5D, 0x53, 0x51, 0x57, 0x55, 0x4B, 0x49, 0x4F, 0x4D, 0x43, 0x41, 0x47, 0x45,
0x7B, 0x79, 0x7F, 0x7D, 0x73, 0x71, 0x77, 0x75, 0x6B, 0x69, 0x6F, 0x6D, 0x63, 0x61, 0x67, 0x65,
0x9B, 0x99, 0x9F, 0x9D, 0x93, 0x91, 0x97, 0x95, 0x8B, 0x89, 0x8F, 0x8D, 0x83, 0x81, 0x87, 0x85,
0xBB, 0xB9, 0xBF, 0xBD, 0xB3, 0xB1, 0xB7, 0xB5, 0xAB, 0xA9, 0xAF, 0xAD, 0xA3, 0xA1, 0xA7, 0xA5,
0xDB, 0xD9, 0xDF, 0xDD, 0xD3, 0xD1, 0xD7, 0xD5, 0xCB, 0xC9, 0xCF, 0xCD, 0xC3, 0xC1, 0xC7, 0xC5,
0xFB, 0xF9, 0xFF, 0xFD, 0xF3, 0xF1, 0xF7, 0xF5, 0xEB, 0xE9, 0xEF, 0xED, 0xE3, 0xE1, 0xE7, 0xE5
};
const uint8_t accelc_aes_GF2p8_Mul_0x03[256] = {
0x00, 0x03, 0x06, 0x05, 0x0C, 0x0F, 0x0A, 0x09, 0x18, 0x1B, 0x1E, 0x1D, 0x14, 0x17, 0x12, 0x11,
0x30, 0x33, 0x36, 0x35, 0x3C, 0x3F, 0x3A, 0x39, 0x28, 0x2B, 0x2E, 0x2D, 0x24, 0x27, 0x22, 0x21,
0x60, 0x63, 0x66, 0x65, 0x6C, 0x6F, 0x6A, 0x69, 0x78, 0x7B, 0x7E, 0x7D, 0x74, 0x77, 0x72, 0x71,
0x50, 0x53, 0x56, 0x55, 0x5C, 0x5F, 0x5A, 0x59, 0x48, 0x4B, 0x4E, 0x4D, 0x44, 0x47, 0x42, 0x41,
0xC0, 0xC3, 0xC6, 0xC5, 0xCC, 0xCF, 0xCA, 0xC9, 0xD8, 0xDB, 0xDE, 0xDD, 0xD4, 0xD7, 0xD2, 0xD1,
0xF0, 0xF3, 0xF6, 0xF5, 0xFC, 0xFF, 0xFA, 0xF9, 0xE8, 0xEB, 0xEE, 0xED, 0xE4, 0xE7, 0xE2, 0xE1,
0xA0, 0xA3, 0xA6, 0xA5, 0xAC, 0xAF, 0xAA, 0xA9, 0xB8, 0xBB, 0xBE, 0xBD, 0xB4, 0xB7, 0xB2, 0xB1,
0x90, 0x93, 0x96, 0x95, 0x9C, 0x9F, 0x9A, 0x99, 0x88, 0x8B, 0x8E, 0x8D, 0x84, 0x87, 0x82, 0x81,
0x9B, 0x98, 0x9D, 0x9E, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8F, 0x8C, 0x89, 0x8A,
0xAB, 0xA8, 0xAD, 0xAE, 0xA7, 0xA4, 0xA1, 0xA2, 0xB3, 0xB0, 0xB5, 0xB6, 0xBF, 0xBC, 0xB9, 0xBA,
0xFB, 0xF8, 0xFD, 0xFE, 0xF7, 0xF4, 0xF1, 0xF2, 0xE3, 0xE0, 0xE5, 0xE6, 0xEF, 0xEC, 0xE9, 0xEA,
0xCB, 0xC8, 0xCD, 0xCE, 0xC7, 0xC4, 0xC1, 0xC2, 0xD3, 0xD0, 0xD5, 0xD6, 0xDF, 0xDC, 0xD9, 0xDA,
0x5B, 0x58, 0x5D, 0x5E, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4F, 0x4C, 0x49, 0x4A,
0x6B, 0x68, 0x6D, 0x6E, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7F, 0x7C, 0x79, 0x7A,
0x3B, 0x38, 0x3D, 0x3E, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2F, 0x2C, 0x29, 0x2A,
0x0B, 0x08, 0x0D, 0x0E, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1F, 0x1C, 0x19, 0x1A
};
const uint8_t accelc_aes_InverseSBox[256] = {
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
};
const uint8_t accelc_aes_GF2p8_Mul_0x09[256] = {
0x00, 0x09, 0x12, 0x1B, 0x24, 0x2D, 0x36, 0x3F, 0x48, 0x41, 0x5A, 0x53, 0x6C, 0x65, 0x7E, 0x77,
0x90, 0x99, 0x82, 0x8B, 0xB4, 0xBD, 0xA6, 0xAF, 0xD8, 0xD1, 0xCA, 0xC3, 0xFC, 0xF5, 0xEE, 0xE7,
0x3B, 0x32, 0x29, 0x20, 0x1F, 0x16, 0x0D, 0x04, 0x73, 0x7A, 0x61, 0x68, 0x57, 0x5E, 0x45, 0x4C,
0xAB, 0xA2, 0xB9, 0xB0, 0x8F, 0x86, 0x9D, 0x94, 0xE3, 0xEA, 0xF1, 0xF8, 0xC7, 0xCE, 0xD5, 0xDC,
0x76, 0x7F, 0x64, 0x6D, 0x52, 0x5B, 0x40, 0x49, 0x3E, 0x37, 0x2C, 0x25, 0x1A, 0x13, 0x08, 0x01,
0xE6, 0xEF, 0xF4, 0xFD, 0xC2, 0xCB, 0xD0, 0xD9, 0xAE, 0xA7, 0xBC, 0xB5, 0x8A, 0x83, 0x98, 0x91,
0x4D, 0x44, 0x5F, 0x56, 0x69, 0x60, 0x7B, 0x72, 0x05, 0x0C, 0x17, 0x1E, 0x21, 0x28, 0x33, 0x3A,
0xDD, 0xD4, 0xCF, 0xC6, 0xF9, 0xF0, 0xEB, 0xE2, 0x95, 0x9C, 0x87, 0x8E, 0xB1, 0xB8, 0xA3, 0xAA,
0xEC, 0xE5, 0xFE, 0xF7, 0xC8, 0xC1, 0xDA, 0xD3, 0xA4, 0xAD, 0xB6, 0xBF, 0x80, 0x89, 0x92, 0x9B,
0x7C, 0x75, 0x6E, 0x67, 0x58, 0x51, 0x4A, 0x43, 0x34, 0x3D, 0x26, 0x2F, 0x10, 0x19, 0x02, 0x0B,
0xD7, 0xDE, 0xC5, 0xCC, 0xF3, 0xFA, 0xE1, 0xE8, 0x9F, 0x96, 0x8D, 0x84, 0xBB, 0xB2, 0xA9, 0xA0,
0x47, 0x4E, 0x55, 0x5C, 0x63, 0x6A, 0x71, 0x78, 0x0F, 0x06, 0x1D, 0x14, 0x2B, 0x22, 0x39, 0x30,
0x9A, 0x93, 0x88, 0x81, 0xBE, 0xB7, 0xAC, 0xA5, 0xD2, 0xDB, 0xC0, 0xC9, 0xF6, 0xFF, 0xE4, 0xED,
0x0A, 0x03, 0x18, 0x11, 0x2E, 0x27, 0x3C, 0x35, 0x42, 0x4B, 0x50, 0x59, 0x66, 0x6F, 0x74, 0x7D,
0xA1, 0xA8, 0xB3, 0xBA, 0x85, 0x8C, 0x97, 0x9E, 0xE9, 0xE0, 0xFB, 0xF2, 0xCD, 0xC4, 0xDF, 0xD6,
0x31, 0x38, 0x23, 0x2A, 0x15, 0x1C, 0x07, 0x0E, 0x79, 0x70, 0x6B, 0x62, 0x5D, 0x54, 0x4F, 0x46
};
const uint8_t accelc_aes_GF2p8_Mul_0x0B[256] = {
0x00, 0x0B, 0x16, 0x1D, 0x2C, 0x27, 0x3A, 0x31, 0x58, 0x53, 0x4E, 0x45, 0x74, 0x7F, 0x62, 0x69,
0xB0, 0xBB, 0xA6, 0xAD, 0x9C, 0x97, 0x8A, 0x81, 0xE8, 0xE3, 0xFE, 0xF5, 0xC4, 0xCF, 0xD2, 0xD9,
0x7B, 0x70, 0x6D, 0x66, 0x57, 0x5C, 0x41, 0x4A, 0x23, 0x28, 0x35, 0x3E, 0x0F, 0x04, 0x19, 0x12,
0xCB, 0xC0, 0xDD, 0xD6, 0xE7, 0xEC, 0xF1, 0xFA, 0x93, 0x98, 0x85, 0x8E, 0xBF, 0xB4, 0xA9, 0xA2,
0xF6, 0xFD, 0xE0, 0xEB, 0xDA, 0xD1, 0xCC, 0xC7, 0xAE, 0xA5, 0xB8, 0xB3, 0x82, 0x89, 0x94, 0x9F,
0x46, 0x4D, 0x50, 0x5B, 0x6A, 0x61, 0x7C, 0x77, 0x1E, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2F,
0x8D, 0x86, 0x9B, 0x90, 0xA1, 0xAA, 0xB7, 0xBC, 0xD5, 0xDE, 0xC3, 0xC8, 0xF9, 0xF2, 0xEF, 0xE4,
0x3D, 0x36, 0x2B, 0x20, 0x11, 0x1A, 0x07, 0x0C, 0x65, 0x6E, 0x73, 0x78, 0x49, 0x42, 0x5F, 0x54,
0xF7, 0xFC, 0xE1, 0xEA, 0xDB, 0xD0, 0xCD, 0xC6, 0xAF, 0xA4, 0xB9, 0xB2, 0x83, 0x88, 0x95, 0x9E,
0x47, 0x4C, 0x51, 0x5A, 0x6B, 0x60, 0x7D, 0x76, 0x1F, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2E,
0x8C, 0x87, 0x9A, 0x91, 0xA0, 0xAB, 0xB6, 0xBD, 0xD4, 0xDF, 0xC2, 0xC9, 0xF8, 0xF3, 0xEE, 0xE5,
0x3C, 0x37, 0x2A, 0x21, 0x10, 0x1B, 0x06, 0x0D, 0x64, 0x6F, 0x72, 0x79, 0x48, 0x43, 0x5E, 0x55,
0x01, 0x0A, 0x17, 0x1C, 0x2D, 0x26, 0x3B, 0x30, 0x59, 0x52, 0x4F, 0x44, 0x75, 0x7E, 0x63, 0x68,
0xB1, 0xBA, 0xA7, 0xAC, 0x9D, 0x96, 0x8B, 0x80, 0xE9, 0xE2, 0xFF, 0xF4, 0xC5, 0xCE, 0xD3, 0xD8,
0x7A, 0x71, 0x6C, 0x67, 0x56, 0x5D, 0x40, 0x4B, 0x22, 0x29, 0x34, 0x3F, 0x0E, 0x05, 0x18, 0x13,
0xCA, 0xC1, 0xDC, 0xD7, 0xE6, 0xED, 0xF0, 0xFB, 0x92, 0x99, 0x84, 0x8F, 0xBE, 0xB5, 0xA8, 0xA3
};
const uint8_t accelc_aes_GF2p8_Mul_0x0D[256] = {
0x00, 0x0D, 0x1A, 0x17, 0x34, 0x39, 0x2E, 0x23, 0x68, 0x65, 0x72, 0x7F, 0x5C, 0x51, 0x46, 0x4B,
0xD0, 0xDD, 0xCA, 0xC7, 0xE4, 0xE9, 0xFE, 0xF3, 0xB8, 0xB5, 0xA2, 0xAF, 0x8C, 0x81, 0x96, 0x9B,
0xBB, 0xB6, 0xA1, 0xAC, 0x8F, 0x82, 0x95, 0x98, 0xD3, 0xDE, 0xC9, 0xC4, 0xE7, 0xEA, 0xFD, 0xF0,
0x6B, 0x66, 0x71, 0x7C, 0x5F, 0x52, 0x45, 0x48, 0x03, 0x0E, 0x19, 0x14, 0x37, 0x3A, 0x2D, 0x20,
0x6D, 0x60, 0x77, 0x7A, 0x59, 0x54, 0x43, 0x4E, 0x05, 0x08, 0x1F, 0x12, 0x31, 0x3C, 0x2B, 0x26,
0xBD, 0xB0, 0xA7, 0xAA, 0x89, 0x84, 0x93, 0x9E, 0xD5, 0xD8, 0xCF, 0xC2, 0xE1, 0xEC, 0xFB, 0xF6,
0xD6, 0xDB, 0xCC, 0xC1, 0xE2, 0xEF, 0xF8, 0xF5, 0xBE, 0xB3, 0xA4, 0xA9, 0x8A, 0x87, 0x90, 0x9D,
0x06, 0x0B, 0x1C, 0x11, 0x32, 0x3F, 0x28, 0x25, 0x6E, 0x63, 0x74, 0x79, 0x5A, 0x57, 0x40, 0x4D,
0xDA, 0xD7, 0xC0, 0xCD, 0xEE, 0xE3, 0xF4, 0xF9, 0xB2, 0xBF, 0xA8, 0xA5, 0x86, 0x8B, 0x9C, 0x91,
0x0A, 0x07, 0x10, 0x1D, 0x3E, 0x33, 0x24, 0x29, 0x62, 0x6F, 0x78, 0x75, 0x56, 0x5B, 0x4C, 0x41,
0x61, 0x6C, 0x7B, 0x76, 0x55, 0x58, 0x4F, 0x42, 0x09, 0x04, 0x13, 0x1E, 0x3D, 0x30, 0x27, 0x2A,
0xB1, 0xBC, 0xAB, 0xA6, 0x85, 0x88, 0x9F, 0x92, 0xD9, 0xD4, 0xC3, 0xCE, 0xED, 0xE0, 0xF7, 0xFA,
0xB7, 0xBA, 0xAD, 0xA0, 0x83, 0x8E, 0x99, 0x94, 0xDF, 0xD2, 0xC5, 0xC8, 0xEB, 0xE6, 0xF1, 0xFC,
0x67, 0x6A, 0x7D, 0x70, 0x53, 0x5E, 0x49, 0x44, 0x0F, 0x02, 0x15, 0x18, 0x3B, 0x36, 0x21, 0x2C,
0x0C, 0x01, 0x16, 0x1B, 0x38, 0x35, 0x22, 0x2F, 0x64, 0x69, 0x7E, 0x73, 0x50, 0x5D, 0x4A, 0x47,
0xDC, 0xD1, 0xC6, 0xCB, 0xE8, 0xE5, 0xF2, 0xFF, 0xB4, 0xB9, 0xAE, 0xA3, 0x80, 0x8D, 0x9A, 0x97
};
const uint8_t accelc_aes_GF2p8_Mul_0x0E[256] = {
0x00, 0x0E, 0x1C, 0x12, 0x38, 0x36, 0x24, 0x2A, 0x70, 0x7E, 0x6C, 0x62, 0x48, 0x46, 0x54, 0x5A,
0xE0, 0xEE, 0xFC, 0xF2, 0xD8, 0xD6, 0xC4, 0xCA, 0x90, 0x9E, 0x8C, 0x82, 0xA8, 0xA6, 0xB4, 0xBA,
0xDB, 0xD5, 0xC7, 0xC9, 0xE3, 0xED, 0xFF, 0xF1, 0xAB, 0xA5, 0xB7, 0xB9, 0x93, 0x9D, 0x8F, 0x81,
0x3B, 0x35, 0x27, 0x29, 0x03, 0x0D, 0x1F, 0x11, 0x4B, 0x45, 0x57, 0x59, 0x73, 0x7D, 0x6F, 0x61,
0xAD, 0xA3, 0xB1, 0xBF, 0x95, 0x9B, 0x89, 0x87, 0xDD, 0xD3, 0xC1, 0xCF, 0xE5, 0xEB, 0xF9, 0xF7,
0x4D, 0x43, 0x51, 0x5F, 0x75, 0x7B, 0x69, 0x67, 0x3D, 0x33, 0x21, 0x2F, 0x05, 0x0B, 0x19, 0x17,
0x76, 0x78, 0x6A, 0x64, 0x4E, 0x40, 0x52, 0x5C, 0x06, 0x08, 0x1A, 0x14, 0x3E, 0x30, 0x22, 0x2C,
0x96, 0x98, 0x8A, 0x84, 0xAE, 0xA0, 0xB2, 0xBC, 0xE6, 0xE8, 0xFA, 0xF4, 0xDE, 0xD0, 0xC2, 0xCC,
0x41, 0x4F, 0x5D, 0x53, 0x79, 0x77, 0x65, 0x6B, 0x31, 0x3F, 0x2D, 0x23, 0x09, 0x07, 0x15, 0x1B,
0xA1, 0xAF, 0xBD, 0xB3, 0x99, 0x97, 0x85, 0x8B, 0xD1, 0xDF, 0xCD, 0xC3, 0xE9, 0xE7, 0xF5, 0xFB,
0x9A, 0x94, 0x86, 0x88, 0xA2, 0xAC, 0xBE, 0xB0, 0xEA, 0xE4, 0xF6, 0xF8, 0xD2, 0xDC, 0xCE, 0xC0,
0x7A, 0x74, 0x66, 0x68, 0x42, 0x4C, 0x5E, 0x50, 0x0A, 0x04, 0x16, 0x18, 0x32, 0x3C, 0x2E, 0x20,
0xEC, 0xE2, 0xF0, 0xFE, 0xD4, 0xDA, 0xC8, 0xC6, 0x9C, 0x92, 0x80, 0x8E, 0xA4, 0xAA, 0xB8, 0xB6,
0x0C, 0x02, 0x10, 0x1E, 0x34, 0x3A, 0x28, 0x26, 0x7C, 0x72, 0x60, 0x6E, 0x44, 0x4A, 0x58, 0x56,
0x37, 0x39, 0x2B, 0x25, 0x0F, 0x01, 0x13, 0x1D, 0x47, 0x49, 0x5B, 0x55, 0x7F, 0x71, 0x63, 0x6D,
0xD7, 0xD9, 0xCB, 0xC5, 0xEF, 0xE1, 0xF3, 0xFD, 0xA7, 0xA9, 0xBB, 0xB5, 0x9F, 0x91, 0x83, 0x8D
};
-281
View File
@@ -1,281 +0,0 @@
#include "blowfish.h"
#include <memory.h>
#if defined(_MSC_VER)
#include <intrin.h>
#define _bswap _byteswap_ulong
#elif defined(__GNUC__)
#include <x86intrin.h>
#endif
const uint32_t accelc_Blowfish_Original_PBox[18] = {
0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0,
0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B
};
const uint32_t accelc_Blowfish_Original_SBox[4][256] = {
{
0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A
},
{
0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7
},
{
0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0
},
{
0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
}
};
#define f_transform(_x, _S) ((((_S)[0][(_x)[3]] + (_S)[1][(_x)[2]]) ^ (_S)[2][(_x)[1]]) + (_S)[3][(_x)[0]])
void accelc_Blowfish_encrypt(uint8_t srcBytes[8],
const BLOWFISH_KEY* srcKey,
int Endian) {
uint32_t* const L = (uint32_t*)srcBytes;
uint32_t* const R = (uint32_t*)(srcBytes + 4);
if (Endian == BLOWFISH_BIG_ENDIAN) {
*L = _bswap(*L);
*R = _bswap(*R);
}
*L ^= srcKey->SubKey[0];
*R ^= f_transform(srcBytes, srcKey->SBox);
*R ^= srcKey->SubKey[1];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*L ^= srcKey->SubKey[2];
*R ^= f_transform(srcBytes, srcKey->SBox);
*R ^= srcKey->SubKey[3];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*L ^= srcKey->SubKey[4];
*R ^= f_transform(srcBytes, srcKey->SBox);
*R ^= srcKey->SubKey[5];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*L ^= srcKey->SubKey[6];
*R ^= f_transform(srcBytes, srcKey->SBox);
*R ^= srcKey->SubKey[7];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*L ^= srcKey->SubKey[8];
*R ^= f_transform(srcBytes, srcKey->SBox);
*R ^= srcKey->SubKey[9];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*L ^= srcKey->SubKey[10];
*R ^= f_transform(srcBytes, srcKey->SBox);
*R ^= srcKey->SubKey[11];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*L ^= srcKey->SubKey[12];
*R ^= f_transform(srcBytes, srcKey->SBox);
*R ^= srcKey->SubKey[13];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*L ^= srcKey->SubKey[14];
*R ^= f_transform(srcBytes, srcKey->SBox);
*R ^= srcKey->SubKey[15];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*L ^= srcKey->SubKey[16];
*R ^= srcKey->SubKey[17];
uint32_t temp = *R;
*R = *L;
*L = temp;
if (Endian == BLOWFISH_BIG_ENDIAN) {
*L = _bswap(*L);
*R = _bswap(*R);
}
}
void accelc_Blowfish_decrypt(uint8_t srcBytes[8],
const BLOWFISH_KEY* srcKey,
int Endian) {
uint32_t* const L = (uint32_t*)srcBytes;
uint32_t* const R = (uint32_t*)(srcBytes + 4);
if (Endian == BLOWFISH_BIG_ENDIAN) {
*L = _bswap(*L);
*R = _bswap(*R);
}
uint32_t temp = *R;
*R = *L;
*L = temp;
*L ^= srcKey->SubKey[16];
*R ^= srcKey->SubKey[17];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*R ^= srcKey->SubKey[15];
*R ^= f_transform(srcBytes, srcKey->SBox);
*L ^= srcKey->SubKey[14];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*R ^= srcKey->SubKey[13];
*R ^= f_transform(srcBytes, srcKey->SBox);
*L ^= srcKey->SubKey[12];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*R ^= srcKey->SubKey[11];
*R ^= f_transform(srcBytes, srcKey->SBox);
*L ^= srcKey->SubKey[10];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*R ^= srcKey->SubKey[9];
*R ^= f_transform(srcBytes, srcKey->SBox);
*L ^= srcKey->SubKey[8];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*R ^= srcKey->SubKey[7];
*R ^= f_transform(srcBytes, srcKey->SBox);
*L ^= srcKey->SubKey[6];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*R ^= srcKey->SubKey[5];
*R ^= f_transform(srcBytes, srcKey->SBox);
*L ^= srcKey->SubKey[4];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*R ^= srcKey->SubKey[3];
*R ^= f_transform(srcBytes, srcKey->SBox);
*L ^= srcKey->SubKey[2];
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
*R ^= srcKey->SubKey[1];
*R ^= f_transform(srcBytes, srcKey->SBox);
*L ^= srcKey->SubKey[0];
if (Endian == BLOWFISH_BIG_ENDIAN) {
*L = _bswap(*L);
*R = _bswap(*R);
}
}
int accelc_Blowfish_set_key(const uint8_t srcUserKey[], uint8_t UserKeyLength,
BLOWFISH_KEY* dstKey) {
if (UserKeyLength == 0)
return STATUS_BLOWFISH_INVALID_KEY_LENGTH;
if (UserKeyLength > BLOWFISH_MAX_KEY_LENGTH)
return STATUS_BLOWFISH_KEY_TOO_LONG;
memcpy(dstKey->SubKey, accelc_Blowfish_Original_PBox, sizeof(accelc_Blowfish_Original_PBox));
memcpy(dstKey->SBox, accelc_Blowfish_Original_SBox, sizeof(accelc_Blowfish_Original_SBox));
for (int i = 0; i < 18; ++i) {
uint32_t temp = 0;
temp <<= 8;
temp |= srcUserKey[(i * 4) % UserKeyLength];
temp <<= 8;
temp |= srcUserKey[(i * 4 + 1) % UserKeyLength];
temp <<= 8;
temp |= srcUserKey[(i * 4 + 2) % UserKeyLength];
temp <<= 8;
temp |= srcUserKey[(i * 4 + 3) % UserKeyLength];
dstKey->SubKey[i] ^= temp;
}
uint8_t temp[8] = { 0 };
for (int i = 0; i < 9; ++i) {
accelc_Blowfish_encrypt(temp, dstKey, BLOWFISH_LITTLE_ENDIAN);
((uint64_t*)dstKey->SubKey)[i] = *(uint64_t*)temp;
}
for (int i = 0; i < 512; ++i) {
accelc_Blowfish_encrypt(temp, dstKey, BLOWFISH_LITTLE_ENDIAN);
((uint64_t*)dstKey->SBox)[i] = *(uint64_t*)temp;
}
return STATUS_BLOWFISH_SUCCESS;
}
-39
View File
@@ -1,39 +0,0 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#define STATUS_BLOWFISH_SUCCESS 0
#define STATUS_BLOWFISH_INVALID_KEY_LENGTH (-1)
#define STATUS_BLOWFISH_KEY_TOO_LONG (-2)
#define BLOWFISH_LITTLE_ENDIAN 0
#define BLOWFISH_BIG_ENDIAN 1
#define BLOWFISH_MIN_KEY_LENGTH 1
#define BLOWFISH_MAX_KEY_LENGTH 56
#define BLOWFISH_BLOCK_SIZE 8
#if defined(__cplusplus)
extern "C" {
#endif
typedef struct _BLOWFISH_KEY {
uint32_t SubKey[18];
uint32_t SBox[4][256];
} BLOWFISH_KEY;
void accelc_Blowfish_encrypt(uint8_t srcBytes[8],
const BLOWFISH_KEY* srcKey,
int Endian);
void accelc_Blowfish_decrypt(uint8_t srcBytes[8],
const BLOWFISH_KEY* srcKey,
int Endian);
int accelc_Blowfish_set_key(const uint8_t srcUserKey[], uint8_t UserKeyLength,
BLOWFISH_KEY* dstKey);
#if defined(__cplusplus)
}
#endif
-120
View File
@@ -1,120 +0,0 @@
#include "sha1.h"
#include <memory.h>
#if defined(_MSC_VER)
#include <intrin.h>
#define _bswap _byteswap_ulong
#define _bswap64 _byteswap_uint64
#elif defined(__GNUC__)
#include <x86intrin.h>
#endif
#define SHA1_BLOCKSIZE 64
void accelc_SHA1_init(SHA1_BUFFER* HashBuffer) {
HashBuffer->dword[0] = 0x67452301;
HashBuffer->dword[1] = 0xEFCDAB89;
HashBuffer->dword[2] = 0x98BADCFE;
HashBuffer->dword[3] = 0x10325476;
HashBuffer->dword[4] = 0xC3D2E1F0;
}
void accelc_SHA1_update(const void* __restrict srcBytes, size_t srcBytesLength,
SHA1_BUFFER* __restrict HashBuffer) {
uint32_t Buffer[80] = { 0 };
uint32_t a, b, c, d, e;
const uint32_t (*MessageBlock)[16] = srcBytes;
size_t RoundsOfMainCycle = srcBytesLength / SHA1_BLOCKSIZE;
for (size_t i = 0; i < RoundsOfMainCycle; ++i) {
for (int j = 0; j < 16; ++j)
Buffer[j] = _bswap(MessageBlock[i][j]);
for (int j = 16; j < 80; ++j) {
uint32_t temp = Buffer[j - 3] ^ Buffer[j - 8] ^ Buffer[j - 14] ^ Buffer[j - 16];
Buffer[j] = _rotl(temp, 1);
}
a = HashBuffer->dword[0];
b = HashBuffer->dword[1];
c = HashBuffer->dword[2];
d = HashBuffer->dword[3];
e = HashBuffer->dword[4];
for (int j = 0; j < 20; ++j) {
uint32_t T = _rotl(a, 5);
T += ((b & c) ^ (~b & d)) + e + 0x5A827999 + Buffer[j];
e = d;
d = c;
c = _rotl(b, 30);
b = a;
a = T;
}
for (int j = 20; j < 40; ++j) {
uint32_t T = _rotl(a, 5);
T += (b ^ c ^ d) + e + 0x6ED9EBA1 + Buffer[j];
e = d;
d = c;
c = _rotl(b, 30);
b = a;
a = T;
}
for (int j = 40; j < 60; ++j) {
uint32_t T = _rotl(a, 5);
T += ((b & c) ^ (b & d) ^ (c & d)) + e + 0x8F1BBCDC + Buffer[j];
e = d;
d = c;
c = _rotl(b, 30);
b = a;
a = T;
}
for (int j = 60; j < 80; ++j) {
uint32_t T = _rotl(a, 5);
T += (b ^ c ^ d) + e + 0xCA62C1D6 + Buffer[j];
e = d;
d = c;
c = _rotl(b, 30);
b = a;
a = T;
}
HashBuffer->dword[0] += a;
HashBuffer->dword[1] += b;
HashBuffer->dword[2] += c;
HashBuffer->dword[3] += d;
HashBuffer->dword[4] += e;
}
}
void accelc_SHA1_final(const void* __restrict LeftBytes, size_t LeftBytesLength, uint64_t TotalBytesLength,
const SHA1_BUFFER* HashBuffer, SHA1_DIGEST* Hash) {
if (HashBuffer != Hash)
memcpy(Hash, HashBuffer, sizeof(SHA1_BUFFER));
if (LeftBytesLength >= SHA1_BLOCKSIZE) {
accelc_SHA1_update(LeftBytes, LeftBytesLength, Hash);
LeftBytes = (const uint8_t*)LeftBytes + (LeftBytesLength / SHA1_BLOCKSIZE) * SHA1_BLOCKSIZE;
LeftBytesLength %= SHA1_BLOCKSIZE;
}
uint8_t Extra[128] = { 0 };
for (size_t i = 0; i < LeftBytesLength; ++i)
Extra[i] = ((const uint8_t*)LeftBytes)[i];
Extra[LeftBytesLength] = 0x80;
*(uint64_t*)(Extra + (LeftBytesLength >= 64 - 8 ? 128 - 8 : 64 - 8)) = _bswap64(TotalBytesLength * 8);
accelc_SHA1_update(Extra, LeftBytesLength >= 56 ? 128 : 64, Hash);
Hash->dword[0] = _bswap(Hash->dword[0]);
Hash->dword[1] = _bswap(Hash->dword[1]);
Hash->dword[2] = _bswap(Hash->dword[2]);
Hash->dword[3] = _bswap(Hash->dword[3]);
Hash->dword[4] = _bswap(Hash->dword[4]);
}
void accelc_SHA1(const void* __restrict srcBytes, size_t srclen,
SHA1_DIGEST* __restrict Hash) {
accelc_SHA1_init(Hash);
accelc_SHA1_update(srcBytes, srclen, Hash);
accelc_SHA1_final((uint8_t*)srcBytes + (srclen / SHA1_BLOCKSIZE) * SHA1_BLOCKSIZE, srclen % SHA1_BLOCKSIZE, srclen, Hash, Hash);
}
-29
View File
@@ -1,29 +0,0 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#if defined(__cplusplus)
extern "C" {
#endif
typedef struct _SHA1_DIGEST {
union {
uint8_t byte[20];
uint32_t dword[5];
};
} SHA1_DIGEST, SHA1_BUFFER;
void accelc_SHA1_init(SHA1_BUFFER* HashBuffer);
void accelc_SHA1_update(const void* __restrict srcBytes, size_t srcBytesLength,
SHA1_BUFFER* __restrict HashBuffer);
void accelc_SHA1_final(const void* __restrict LeftBytes, size_t LeftBytesLength, uint64_t TotalBytesLength,
const SHA1_BUFFER* HashBuffer, SHA1_DIGEST* Hash);
void accelc_SHA1(const void* __restrict srcBytes, size_t srclen,
SHA1_DIGEST* __restrict Hash);
#if defined(__cplusplus)
}
#endif
+1 -1
View File
@@ -54,7 +54,7 @@ public:
return aCipher;
}
bool GenerateKey(int bits, unsigned long long e = RSA_F4) {
bool GenerateKey(int bits, unsigned int e = RSA_F4) {
bool bSuccess = false;
BIGNUM* bn_e = nullptr;
+98 -241
View File
@@ -1,11 +1,14 @@
#include "def.hpp"
// Solution0 is for navicat premium of which the version < 12.0.25
namespace patcher::Solution0 {
// The following APIs are in version.lib
// GetFileVersionInfoSize
// GetFileVersionInfo
// VerQueryValue
// #pragma comment(lib, "version.lib")
static std::Tstring InstallationPath;
namespace Patcher {
static const CHAR Keyword[] =
const char Solution0::Keyword[461] =
"-----BEGIN PUBLIC KEY-----\r\n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I\r\n"
"qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv\r\n"
@@ -16,171 +19,43 @@ namespace patcher::Solution0 {
"awIDAQAB\r\n"
"-----END PUBLIC KEY-----\r\n";
static const DWORD KeywordLength = sizeof(Keyword) - 1;
bool Solution0::FindPatchOffset() noexcept {
bool bFound = false;
static LPCTSTR PossibleName[3] = {
TEXT("Navicat.exe"), // for Linux compatible, main program name is "Navicat.exe" in Linux, case sensitive
TEXT("Modeler.exe"), // for Linux compatible
TEXT("Rviewer.exe") // for Linux compatible
};
static LPCTSTR TargetName = NULL;
static HMODULE hTarget = NULL;
BOOL Init(const std::Tstring& Path) {
BOOL bSuccess = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
DWORD attr = INVALID_FILE_ATTRIBUTES;
attr = GetFileAttributes(Path.c_str());
if (attr == INVALID_FILE_ATTRIBUTES) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ GetFileAttributes. CODE: 0x%08X\n"), dwLastError);
goto ON_Init_ERROR;
}
if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Error: Path is not a directory.\n"));
goto ON_Init_ERROR;
}
InstallationPath = Path;
if (InstallationPath.back() != TEXT('\\') && InstallationPath.back() != TEXT('/'))
InstallationPath.push_back(TEXT('/')); // for Linux compatible
bSuccess = TRUE;
ON_Init_ERROR:
return bSuccess;
}
BOOL CheckKey(RSACipher* cipher) {
return TRUE;
}
BOOL FindTargetFile() {
BOOL bSuccess = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
for (size_t i = 0; i < _countof(PossibleName); ++i) {
std::Tstring&& PossibleFileName = InstallationPath + PossibleName[i];
hTarget = LoadLibrary(PossibleFileName.c_str());
if (hTarget == NULL && (dwLastError = GetLastError()) != ERROR_MOD_NOT_FOUND) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Unexpected Error @ LoadLibrary. CODE: 0x%08X\n"), dwLastError);
goto ON_FindTargetFile_ERROR;
}
if (hTarget) {
_tprintf_s(TEXT("Target has been found: %s\n"), PossibleName[i]);
TargetName = PossibleName[i];
bSuccess = TRUE;
goto ON_FindTargetFile_ERROR;
PIMAGE_SECTION_HEADER pResourceSection =
Helper::ImageSectionHeader(pTargetFile->GetView<uint8_t>(), ".rsrc");
if (pResourceSection == nullptr)
return false;
uint8_t* pResourceSectionData =
pTargetFile->GetView<uint8_t>() + pResourceSection->PointerToRawData;
for (DWORD i = 0; i < pResourceSection->SizeOfRawData; ++i) {
if (memcmp(pResourceSectionData + i, Keyword, KeywordLength) == 0) {
PatchOffset = pResourceSection->PointerToRawData + i;
bFound = true;
break;
}
}
ON_FindTargetFile_ERROR:
return bSuccess;
}
BOOL CheckFile() {
BOOL bFound = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
HRSRC hRes = NULL;
HGLOBAL hGLobal = NULL;
PVOID lpData = NULL;
DWORD dwSize = 0;
if (hTarget == NULL) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Error: Target has not been set yet.\n"));
goto ON_CheckFile_ERROR;
}
hRes = FindResource(hTarget, TEXT("ACTIVATIONPUBKEY"), RT_RCDATA);
if (hRes == NULL) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ FindResource. CODE: 0x%08X\n"), dwLastError);
goto ON_CheckFile_ERROR;
}
hGLobal = LoadResource(hTarget, hRes);
if (hGLobal == NULL) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ LoadResource. CODE: 0x%08X\n"), dwLastError);
goto ON_CheckFile_ERROR;
}
lpData = LockResource(hGLobal);
if (lpData == NULL) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ LockResource. CODE: 0x%08X\n"), dwLastError);
goto ON_CheckFile_ERROR;
}
dwSize = SizeofResource(hTarget, hRes);
if (dwSize == 0) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ SizeofResource. CODE: 0x%08X\n"), dwLastError);
goto ON_CheckFile_ERROR;
}
if (dwSize == KeywordLength && memcmp(lpData, Keyword, KeywordLength) == 0) {
FreeLibrary(hTarget);
hTarget = NULL;
bFound = TRUE;
} else {
FreeLibrary(hTarget);
hTarget = NULL;
TargetName = NULL;
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: Resource doest not match.\n"));
goto ON_CheckFile_ERROR;
}
ON_CheckFile_ERROR:
if (bFound)
_tprintf_s(TEXT("MESSAGE: [Solution0] Keyword has been found: offset = +0x%08lx.\n"), PatchOffset);
return bFound;
}
BOOL BackupFile() {
BOOL bSuccess = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
std::Tstring&& TargetFileName = InstallationPath + TargetName;
std::Tstring&& BackupFileName = InstallationPath + TargetName + TEXT(".backup");
if (!CopyFile(TargetFileName.c_str(), BackupFileName.c_str(), TRUE)) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ CopyFile. CODE: 0x%08X\n"), dwLastError);
goto ON_BackupFile_ERROR;
}
bSuccess = TRUE;
ON_BackupFile_ERROR:
return bSuccess;
}
BOOL Do(RSACipher* cipher) {
BOOL bSuccess = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
bool Solution0::MakePatch(RSACipher* cipher) const {
uint8_t* lpTargetFileView = pTargetFile->GetView<uint8_t>();
std::string RSAPublicKeyPEM;
std::Tstring&& TargetFileName = InstallationPath + TargetName;
HANDLE hUpdater = NULL;
RSAPublicKeyPEM = cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
RSAPublicKeyPEM =
cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
if (RSAPublicKeyPEM.empty()) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: cipher->ExportKeyString failed.\n"));
goto ON_Do_ERROR;
REPORT_ERROR("ERROR: cipher->ExportKeyString failed.");
return false;
}
// lambda function, replace '\n' to '\r\n'
[](std::string& str, const std::string& OldSub, const std::string& NewSub) {
std::string::size_type pos = 0;
std::string::size_type srclen = OldSub.size();
@@ -190,96 +65,78 @@ namespace patcher::Solution0 {
str.replace(pos, srclen, NewSub);
pos += dstlen;
}
} (RSAPublicKeyPEM, "\n", "\r\n"); // replace '\n' to '\r\n'
} (RSAPublicKeyPEM, "\n", "\r\n");
if (RSAPublicKeyPEM.length() != KeywordLength) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: Public key length does not match.\n"));
goto ON_Do_ERROR;
REPORT_ERROR("ERROR: Public key length does not match.");
return false;
}
hUpdater = BeginUpdateResource(TargetFileName.c_str(), FALSE);
if (hUpdater == NULL) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ BeginUpdateResource. CODE: 0x%08X\n"), dwLastError);
goto ON_Do_ERROR;
}
PRINT_MESSAGE("//");
PRINT_MESSAGE("// Begin Solution0");
PRINT_MESSAGE("//");
_tprintf_s(TEXT("@+0x%08X\nPrevious:\n"), PatchOffset);
Helper::PrintMemory(lpTargetFileView + PatchOffset,
lpTargetFileView + PatchOffset + KeywordLength,
lpTargetFileView);
if (!UpdateResource(hUpdater,
RT_RCDATA,
TEXT("ACTIVATIONPUBKEY"),
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
(LPVOID)RSAPublicKeyPEM.c_str(),
KeywordLength)) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ UpdateResource. CODE: 0x%08X\n"), dwLastError);
goto ON_Do_ERROR;
}
memcpy(lpTargetFileView + PatchOffset, RSAPublicKeyPEM.c_str(), KeywordLength);
PRINT_MESSAGE("After:");
Helper::PrintMemory(lpTargetFileView + PatchOffset,
lpTargetFileView + PatchOffset + KeywordLength,
lpTargetFileView);
PRINT_MESSAGE("");
bSuccess = TRUE;
ON_Do_ERROR:
EndUpdateResource(hUpdater, !bSuccess);
return bSuccess;
return true;
}
BOOL GetVersion(LPDWORD lpMajorVer, LPDWORD lpMinorVer) {
BOOL bSuccess = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
std::Tstring&& TargetFileName = InstallationPath + TargetName;
DWORD dwSize = 0;
PVOID lpData = NULL;
VS_FIXEDFILEINFO* lpVersionInfo = NULL;
UINT VersionInfoSize = 0;
dwSize = GetFileVersionInfoSize(TargetFileName.c_str(),
&dwSize); // MSDN doesn't say it can be NULL.
// so I use dwSize to receive this deprecated value
if (dwSize == 0) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ GetFileVersionInfoSize. CODE: 0x%08X\n"), dwLastError);
goto ON_GetVersion_ERROR;
}
lpData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
if (lpData == NULL) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ HeapAlloc. CODE: 0x%08X\n"), dwLastError);
goto ON_GetVersion_ERROR;
}
if (!GetFileVersionInfo(TargetFileName.c_str(), NULL, dwSize, lpData)) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ GetFileVersionInfo. CODE: 0x%08X\n"), dwLastError);
goto ON_GetVersion_ERROR;
}
if (!VerQueryValue(lpData, TEXT("\\"), (LPVOID*)&lpVersionInfo, &VersionInfoSize)) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ VerQueryValue. CODE: 0x%08X\n"), dwLastError);
goto ON_GetVersion_ERROR;
}
*lpMajorVer = lpVersionInfo->dwProductVersionMS;
*lpMinorVer = lpVersionInfo->dwProductVersionLS;
bSuccess = TRUE;
ON_GetVersion_ERROR:
if (lpData)
HeapFree(GetProcessHeap(), NULL, lpData);
return bSuccess;
}
VOID Finalize() {
if (hTarget) {
FreeLibrary(hTarget);
hTarget = NULL;
}
}
// DWORD Solution0::GetMainAppVersion(LPDWORD lpMajorVer, LPDWORD lpMinorVer) {
// BOOL bSuccess = FALSE;
// DWORD dwLastError = ERROR_SUCCESS;
// std::Tstring TargetFileFullName = InstallationPath + MainAppName;
//
// DWORD dwSize = 0;
// PVOID lpData = NULL;
// VS_FIXEDFILEINFO* lpVersionInfo = NULL;
// UINT VersionInfoSize = 0;
//
// dwSize = GetFileVersionInfoSize(TargetFileFullName.c_str(),
// &dwSize); // MSDN doesn't say it can be NULL.
// // so I use dwSize to receive this deprecated value
// if (dwSize == 0) {
// dwLastError = GetLastError();
// REPORT_ERROR_WITH_CODE("ERROR: GetFileVersionInfoSize failed.", dwLastError);
// goto ON_Solution0_GetMainAppVersion_ERROR;
// }
//
// lpData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
// if (lpData == nullptr) {
// dwLastError = GetLastError();
// REPORT_ERROR_WITH_CODE("ERROR: HeapAlloc failed.", dwLastError);
// goto ON_Solution0_GetMainAppVersion_ERROR;
// }
//
// if (!GetFileVersionInfo(TargetFileFullName.c_str(), NULL, dwSize, lpData)) {
// dwLastError = GetLastError();
// REPORT_ERROR_WITH_CODE("ERROR: GetFileVersionInfo failed.", dwLastError);
// goto ON_Solution0_GetMainAppVersion_ERROR;
// }
//
// if (!VerQueryValue(lpData, TEXT("\\"), reinterpret_cast<LPVOID*>(&lpVersionInfo), &VersionInfoSize)) {
// dwLastError = GetLastError();
// REPORT_ERROR_WITH_CODE("ERROR: VerQueryValue failed.", dwLastError);
// goto ON_Solution0_GetMainAppVersion_ERROR;
// }
//
// *lpMajorVer = lpVersionInfo->dwProductVersionMS;
// *lpMinorVer = lpVersionInfo->dwProductVersionLS;
//
// bSuccess = TRUE;
// ON_Solution0_GetMainAppVersion_ERROR:
// if (lpData)
// HeapFree(GetProcessHeap(), NULL, lpData);
// return bSuccess;
// }
}
+177 -283
View File
@@ -1,26 +1,16 @@
#include "def.hpp"
// Solution1 is for navicat premium of which the version = 12.0.25
namespace patcher::Solution1 {
namespace Patcher {
static std::Tstring InstallationPath;
static const CHAR Keyword0[] =
const char* Solution1::Keywords[5] = {
"D75125B70767B94145B47C1CB3C0755E"
"7CCB8825C5DCE0C58ACF944E08280140"
"9A02472FAFFD1CD77864BB821AE36766"
"FEEDE6A24F12662954168BFA314BD950"
"32B9D82445355ED7BC0B880887D650F5";
"32B9D82445355ED7BC0B880887D650F5",
static const DWORD KeywordSize0 = sizeof(Keyword0) - 1;
"\xfe\xea\xbc\x01",
static const uint8_t Keyword1[] = {
0xFE, 0xEA, 0xBC, 0x01
};
static const DWORD KeywordSize1 = sizeof(Keyword1);
static const CHAR Keyword2[] =
"E1CED09B9C2186BF71A70C0FE2F1E0AE"
"F3BD6B75277AAB20DFAF3D110F75912B"
"FB63AC50EC4C48689D1502715243A79F"
@@ -44,66 +34,30 @@ namespace patcher::Solution1 {
"5A8BF03BA05EA8C8778D38F9873D62B4"
"460F41ACF997C30E7C3AF025FA171B5F"
"5AD4D6B15E95C27F6B35AD61875E5505"
"449B4E";
"449B4E",
static const DWORD KeywordSize2 = sizeof(Keyword2) - 1;
"\x59\x08\x01\x00",
static const uint8_t Keyword3[] = {
0x59, 0x08, 0x01, 0x00
"92933"
};
static const DWORD KeywordSize3 = sizeof(Keyword3);
const int Solution1::KeywordsLength[5] = {
160,
4,
742,
4,
5
};
static const CHAR Keyword4[] = "92933";
static const DWORD KeywordSize4 = sizeof(Keyword4) - 1;
static DWORD KeywordOffset[5] = { -1, -1, -1, -1, -1 };
static LPCTSTR TargetName = TEXT("libcc.dll");
static HANDLE hTarget = INVALID_HANDLE_VALUE;
static HANDLE hTargetMap = NULL;
static PVOID lpFileContent = NULL;
BOOL Init(const std::Tstring& Path) {
BOOL bSuccess = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
DWORD attr = INVALID_FILE_ATTRIBUTES;
attr = GetFileAttributes(Path.c_str());
if (attr == INVALID_FILE_ATTRIBUTES) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ GetFileAttributes. CODE: 0x%08X\n"), dwLastError);
goto ON_Init_ERROR;
}
if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Error: Path is not a directory.\n"));
goto ON_Init_ERROR;
}
InstallationPath = Path;
if (InstallationPath.back() != TEXT('\\') && InstallationPath.back() != TEXT('/'))
InstallationPath.push_back(TEXT('/')); // for Linux compatible
bSuccess = TRUE;
ON_Init_ERROR:
return bSuccess;
}
BOOL CheckKey(RSACipher* cipher) {
bool Solution1::CheckKey(RSACipher* cipher) const noexcept {
BOOL bOk = FALSE;
std::string RSAPublicKeyPEM;
RSAPublicKeyPEM = cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
RSAPublicKeyPEM =
cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
if (RSAPublicKeyPEM.empty()) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: cipher->ExportKeyString failed.\n"));
return FALSE;
REPORT_ERROR("ERROR: cipher->ExportKeyString failed.");
return false;
}
[](std::string& str, const std::string& OldSub, const std::string& NewSub) {
@@ -117,236 +71,138 @@ namespace patcher::Solution1 {
}
} (RSAPublicKeyPEM, "\n", "\r\n"); // replace '\n' to '\r\n'
std::string encrypted_pem_text = EncryptPublicKey(RSAPublicKeyPEM.c_str(),
RSAPublicKeyPEM.length());
std::string encrypted_pem_text = Helper::EncryptPublicKey(RSAPublicKeyPEM);
if (encrypted_pem_text[160] > '9' || encrypted_pem_text[160] < '1')
return FALSE;
return false;
for (int i = 1; i < 8; ++i)
if (encrypted_pem_text[160 + i] > '9' || encrypted_pem_text[160 + i] < '0')
return FALSE;
return false;
if (encrypted_pem_text[910] > '9' || encrypted_pem_text[910] < '1')
return FALSE;
return false;
for (int i = 1; i < 5; ++i)
if (encrypted_pem_text[910 + i] > '9' || encrypted_pem_text[910 + i] < '0')
return FALSE;
return false;
return TRUE;
return true;
}
static PIMAGE_SECTION_HEADER ImageSectionHeader(PVOID lpBase, LPCSTR lpSectionName) {
IMAGE_DOS_HEADER* pFileHeader = NULL;
IMAGE_NT_HEADERS* pNtHeader = NULL;
IMAGE_SECTION_HEADER* pSectionHeaders = NULL;
bool Solution1::FindPatchOffset() noexcept {
PIMAGE_SECTION_HEADER textSection = nullptr;
PIMAGE_SECTION_HEADER rdataSection = nullptr;
pFileHeader = (IMAGE_DOS_HEADER*)lpBase;
if (pFileHeader->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
uint8_t* pTargetFileView = pTargetFile->GetView<uint8_t>();
off_t Offsets[5] = { -1, -1, -1, -1, -1 };
pNtHeader = (IMAGE_NT_HEADERS*)((BYTE*)lpBase + pFileHeader->e_lfanew);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
return NULL;
pSectionHeaders = (IMAGE_SECTION_HEADER*)((BYTE*)pNtHeader +
offsetof(IMAGE_NT_HEADERS, OptionalHeader) +
pNtHeader->FileHeader.SizeOfOptionalHeader);
for (WORD i = 0; i < pNtHeader->FileHeader.NumberOfSections; ++i)
if (_stricmp((const char*)pSectionHeaders[i].Name, lpSectionName) == 0)
return pSectionHeaders + i;
return NULL;
}
BOOL FindTargetFile() {
DWORD dwLastError = ERROR_SUCCESS;
std::Tstring&& TargetFileName = InstallationPath + TargetName;
hTarget = CreateFile(TargetFileName.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hTarget == INVALID_HANDLE_VALUE) {
dwLastError = GetLastError();
if (dwLastError == ERROR_FILE_NOT_FOUND) {
return FALSE;
} else {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Unexpected Error @ CreateFile. CODE: 0x%08X\n"), dwLastError);
return FALSE;
}
}
return TRUE;
}
BOOL FindOffset() {
BOOL bSuccess = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
IMAGE_SECTION_HEADER* textSection = NULL;
IMAGE_SECTION_HEADER* rdataSection = NULL;
hTargetMap = CreateFileMapping(hTarget,
NULL,
PAGE_READWRITE,
0,
0,
NULL);
if (hTargetMap == NULL) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ CreateFileMapping. CODE: 0x%08X\n"), dwLastError);
goto ON_FindOffset_ERROR;
textSection = Helper::ImageSectionHeader(pTargetFileView, ".text");
if (textSection == nullptr) {
// REPORT_ERROR("ERROR: Cannot find .text section.");
return false;
}
lpFileContent = MapViewOfFile(hTargetMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
if (lpFileContent == NULL) {
dwLastError = GetLastError();
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ MapViewOfFile. CODE: 0x%08X\n"), dwLastError);
goto ON_FindOffset_ERROR;
}
textSection = ImageSectionHeader(lpFileContent, ".text");
if (textSection == NULL) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: Cannot find .text section.\n"));
goto ON_FindOffset_ERROR;
}
rdataSection = ImageSectionHeader(lpFileContent, ".rdata");
if (textSection == NULL) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: Cannot find .rdata section.\n"));
goto ON_FindOffset_ERROR;
rdataSection = Helper::ImageSectionHeader(pTargetFileView, ".rdata");
if (textSection == nullptr) {
// REPORT_ERROR("ERROR: Cannot find .rdata section.");
return false;
}
// -------------------------
// try to search keyword0
// try to search Keywords[0]
// -------------------------
for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) {
if (memcmp((uint8_t*)lpFileContent + rdataSection->PointerToRawData + i, Keyword0, KeywordSize0) == 0) {
KeywordOffset[0] = rdataSection->PointerToRawData + i;
if (memcmp(pTargetFileView + rdataSection->PointerToRawData + i, Keywords[0], KeywordsLength[0]) == 0) {
Offsets[0] = rdataSection->PointerToRawData + i;
break;
}
}
if (KeywordOffset[0] == -1) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: Cannot find Keyword0.\n"));
goto ON_FindOffset_ERROR;
} else {
_tprintf_s(TEXT("Keyword0 has been found: offset = +0x%08X.\n"), KeywordOffset[0]);
if (Offsets[0] == -1) {
// REPORT_ERROR("ERROR: Cannot find Keywords[0].");
return false;
}
// -------------------------
// try to search keyword1
// try to search Keywords[2]
// -------------------------
for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) {
if (memcmp(pTargetFileView + rdataSection->PointerToRawData + i, Keywords[2], KeywordsLength[2]) == 0) {
Offsets[2] = rdataSection->PointerToRawData + i;
break;
}
}
if (Offsets[2] == -1) {
// REPORT_ERROR("ERROR: Cannot find Keywords[2].");
return false;
}
// -------------------------
// try to search Keywords[4]
// -------------------------
for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) {
if (memcmp((uint8_t*)pTargetFileView + rdataSection->PointerToRawData + i, Keywords[4], KeywordsLength[4]) == 0) {
Offsets[4] = rdataSection->PointerToRawData + i;
break;
}
}
if (Offsets[4] == -1) {
// REPORT_ERROR("ERROR: Cannot find Keywords[4].");
return false;
}
// -------------------------
// try to search Keywords[1] and Keywords[3]
// -------------------------
for (DWORD i = 0; i < textSection->SizeOfRawData; ++i) {
if (memcmp((uint8_t*)lpFileContent + textSection->PointerToRawData + i, Keyword1, KeywordSize1) == 0) {
KeywordOffset[1] = textSection->PointerToRawData + i;
break;
if (memcmp(pTargetFileView + textSection->PointerToRawData + i, Keywords[1], KeywordsLength[1]) == 0) {
// Keywords[3] must be close to Keywords[1]
for (DWORD j = i - 64; j < i + 64; ++j) {
if (memcmp(pTargetFileView + textSection->PointerToRawData + j, Keywords[3], KeywordsLength[3]) == 0) {
Offsets[1] = textSection->PointerToRawData + i;
Offsets[3] = textSection->PointerToRawData + j;
break;
}
}
// Offsets[1] and Offsets[3] are set synchronously
// so check Offsets[1] is enough
if (Offsets[1] != -1)
break;
}
}
if (KeywordOffset[1] == -1) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: Cannot find Keyword1.\n"));
goto ON_FindOffset_ERROR;
} else {
_tprintf_s(TEXT("Keyword1 has been found: offset = +0x%08X.\n"), KeywordOffset[1]);
}
// -------------------------
// try to search keyword2
// -------------------------
for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) {
if (memcmp((uint8_t*)lpFileContent + rdataSection->PointerToRawData + i, Keyword2, KeywordSize2) == 0) {
KeywordOffset[2] = rdataSection->PointerToRawData + i;
break;
}
}
if (KeywordOffset[2] == -1) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: Cannot find Keyword2.\n"));
goto ON_FindOffset_ERROR;
} else {
_tprintf_s(TEXT("Keyword2 has been found: offset = +0x%08X.\n"), KeywordOffset[2]);
}
// -------------------------
// try to search keyword3
// -------------------------
for (DWORD i = 0; i < textSection->SizeOfRawData; ++i) {
if (memcmp((uint8_t*)lpFileContent + textSection->PointerToRawData + i, Keyword3, KeywordSize3) == 0) {
KeywordOffset[3] = textSection->PointerToRawData + i;
break;
}
}
if (KeywordOffset[3] == -1) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: Cannot find Keyword3.\n"));
goto ON_FindOffset_ERROR;
} else {
_tprintf_s(TEXT("Keyword3 has been found: offset = +0x%08X.\n"), KeywordOffset[3]);
}
// -------------------------
// try to search keyword4
// -------------------------
for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) {
if (memcmp((uint8_t*)lpFileContent + rdataSection->PointerToRawData + i, Keyword4, KeywordSize4) == 0) {
KeywordOffset[4] = rdataSection->PointerToRawData + i;
break;
}
}
if (KeywordOffset[4] == -1) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: Cannot find Keyword4.\n"));
goto ON_FindOffset_ERROR;
} else {
_tprintf_s(TEXT("Keyword4 has been found: offset = +0x%08X.\n"), KeywordOffset[4]);
if (Offsets[1] == -1) {
// REPORT_ERROR("ERROR: Cannot find Keywords[1] and Keywords[3].");
return false;
}
bSuccess = TRUE;
PatchOffsets[0] = Offsets[0];
PatchOffsets[1] = Offsets[1];
PatchOffsets[2] = Offsets[2];
PatchOffsets[3] = Offsets[3];
PatchOffsets[4] = Offsets[4];
_tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[0] has been found: offset = +0x%08lx.\n"), PatchOffsets[0]);
_tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[1] has been found: offset = +0x%08lx.\n"), PatchOffsets[1]);
_tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[2] has been found: offset = +0x%08lx.\n"), PatchOffsets[2]);
_tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[3] has been found: offset = +0x%08lx.\n"), PatchOffsets[3]);
_tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[4] has been found: offset = +0x%08lx.\n"), PatchOffsets[4]);
ON_FindOffset_ERROR:
return bSuccess;
return true;
}
BOOL BackupFile() {
BOOL bSuccess = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
std::Tstring&& TargetFileName = InstallationPath + TargetName;
std::Tstring&& BackupFileName = InstallationPath + TargetName + TEXT(".backup");
if (!CopyFile(TargetFileName.c_str(), BackupFileName.c_str(), TRUE)) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("Failed @ CopyFile. CODE: 0x%08X\n"), dwLastError);
goto ON_BackupFile_ERROR;
}
bSuccess = TRUE;
ON_BackupFile_ERROR:
return bSuccess;
}
BOOL Do(RSACipher* cipher) {
bool Solution1::MakePatch(RSACipher* cipher) const {
std::string RSAPublicKeyPEM;
std::string encrypted_pem_pubkey;
uint8_t* pTargetFileView = pTargetFile->GetView<uint8_t>();
RSAPublicKeyPEM = cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
if (RSAPublicKeyPEM.empty()) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: cipher->ExportKeyString failed.\n"));
REPORT_ERROR("ERROR: cipher->ExportKeyString failed.");
return FALSE;
}
@@ -361,7 +217,7 @@ namespace patcher::Solution1 {
}
} (RSAPublicKeyPEM, "\n", "\r\n"); // replace '\n' to '\r\n'
encrypted_pem_pubkey = EncryptPublicKey(RSAPublicKeyPEM.c_str(), RSAPublicKeyPEM.length());
encrypted_pem_pubkey = Helper::EncryptPublicKey(RSAPublicKeyPEM);
// split encrypted_pem_pubkey to 5 part: |160 chars|8 chars|742 chars|5 chars|5 chars|
// | |
@@ -375,43 +231,81 @@ namespace patcher::Solution1 {
uint32_t imm1 = std::stoul(encrypted_pem_pubkey1.c_str());
uint32_t imm3 = std::stoul(encrypted_pem_pubkey3.c_str());
_tprintf_s(TEXT("\n"));
_tprintf_s(TEXT("@Offset +0x%08X, write string:\n"), KeywordOffset[0]);
printf_s("\"%s\"\n\n", encrypted_pem_pubkey0.c_str());
memcpy((uint8_t*)lpFileContent + KeywordOffset[0], encrypted_pem_pubkey0.c_str(), 160);
PRINT_MESSAGE("//");
PRINT_MESSAGE("// Begin Solution1");
PRINT_MESSAGE("//");
_tprintf_s(TEXT("@Offset +0x%08X, write uint32_t:\n"), KeywordOffset[1]);
printf_s("0x%08X\n\n", imm1);
memcpy((uint8_t*)lpFileContent + KeywordOffset[1], &imm1, sizeof(uint32_t));
// ----------------------------------
// process PatchOffsets[0]
// ----------------------------------
_tprintf_s(TEXT("@+0x%08X\nPrevious:\n"), PatchOffsets[0]);
Helper::PrintMemory(pTargetFileView + PatchOffsets[0],
pTargetFileView + PatchOffsets[0] + KeywordsLength[0],
pTargetFileView);
memcpy(pTargetFileView + PatchOffsets[0], encrypted_pem_pubkey0.c_str(), KeywordsLength[0]);
PRINT_MESSAGE("After:");
Helper::PrintMemory(pTargetFileView + PatchOffsets[0],
pTargetFileView + PatchOffsets[0] + KeywordsLength[0],
pTargetFileView);
PRINT_MESSAGE("");
_tprintf_s(TEXT("@Offset +0x%08X, write string:\n"), KeywordOffset[2]);
printf_s("\"%s\"\n\n", encrypted_pem_pubkey2.c_str());
memcpy((uint8_t*)lpFileContent + KeywordOffset[2], encrypted_pem_pubkey2.c_str(), 742);
// ----------------------------------
// process PatchOffsets[1]
// ----------------------------------
_tprintf_s(TEXT("@+0x%08X\nPrevious:\n"), PatchOffsets[1]);
Helper::PrintMemory(pTargetFileView + PatchOffsets[1],
pTargetFileView + PatchOffsets[1] + KeywordsLength[1],
pTargetFileView);
memcpy(pTargetFileView + PatchOffsets[1], &imm1, KeywordsLength[1]);
PRINT_MESSAGE("After:");
Helper::PrintMemory(pTargetFileView + PatchOffsets[1],
pTargetFileView + PatchOffsets[1] + KeywordsLength[1],
pTargetFileView);
PRINT_MESSAGE("");
_tprintf_s(TEXT("@Offset +0x%08X, write uint32_t:\n"), KeywordOffset[3]);
printf_s("0x%08X\n\n", imm3);
memcpy((uint8_t*)lpFileContent + KeywordOffset[3], &imm3, sizeof(uint32_t));
// ----------------------------------
// process PatchOffsets[2]
// ----------------------------------
_tprintf_s(TEXT("@+0x%08X\nPrevious:\n"), PatchOffsets[2]);
Helper::PrintMemory(pTargetFileView + PatchOffsets[2],
pTargetFileView + PatchOffsets[2] + KeywordsLength[2],
pTargetFileView);
memcpy(pTargetFileView + PatchOffsets[2], encrypted_pem_pubkey2.c_str(), KeywordsLength[2]);
PRINT_MESSAGE("After:");
Helper::PrintMemory(pTargetFileView + PatchOffsets[2],
pTargetFileView + PatchOffsets[2] + KeywordsLength[2],
pTargetFileView);
PRINT_MESSAGE("");
_tprintf_s(TEXT("@Offset +0x%08X, write string:\n"), KeywordOffset[4]);
printf_s("\"%s\"\n\n", encrypted_pem_pubkey4.c_str());
memcpy((uint8_t*)lpFileContent + KeywordOffset[4], encrypted_pem_pubkey4.c_str(), 5);
// ----------------------------------
// process PatchOffsets[3]
// ----------------------------------
_tprintf_s(TEXT("@+0x%08X\nPrevious:\n"), PatchOffsets[3]);
Helper::PrintMemory(pTargetFileView + PatchOffsets[3],
pTargetFileView + PatchOffsets[3] + KeywordsLength[3],
pTargetFileView);
memcpy(pTargetFileView + PatchOffsets[3], &imm3, KeywordsLength[3]);
PRINT_MESSAGE("After:");
Helper::PrintMemory(pTargetFileView + PatchOffsets[3],
pTargetFileView + PatchOffsets[3] + KeywordsLength[3],
pTargetFileView);
PRINT_MESSAGE("");
// ----------------------------------
// process PatchOffsets[4]
// ----------------------------------
_tprintf_s(TEXT("@+0x%08X\nPrevious:\n"), PatchOffsets[4]);
Helper::PrintMemory(pTargetFileView + PatchOffsets[4],
pTargetFileView + PatchOffsets[4] + KeywordsLength[4],
pTargetFileView);
memcpy(pTargetFileView + PatchOffsets[4], encrypted_pem_pubkey4.c_str(), KeywordsLength[4]);
PRINT_MESSAGE("After:");
Helper::PrintMemory(pTargetFileView + PatchOffsets[4],
pTargetFileView + PatchOffsets[4] + KeywordsLength[4],
pTargetFileView);
PRINT_MESSAGE("");
return TRUE;
}
VOID Finalize() {
if (lpFileContent) {
UnmapViewOfFile(lpFileContent);
lpFileContent = NULL;
}
if (hTargetMap) {
CloseHandle(hTargetMap);
hTargetMap = NULL;
}
if (hTarget) {
CloseHandle(hTarget);
hTarget = INVALID_HANDLE_VALUE;
}
}
}
}
+253
View File
@@ -0,0 +1,253 @@
#include "def.hpp"
namespace Patcher {
const char Solution2::KeywordsMeta[KeywordsCount + 1] =
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I"
"qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv"
"a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF"
"R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2"
"WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt"
"YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ"
"awIDAQAB";
uint8_t Solution2::Keywords[KeywordsCount][5];
#if defined(_M_X64)
void Solution2::BuildKeywords() noexcept {
for (size_t i = 0; i < KeywordsCount; ++i) {
Keywords[i][0] = 0x83; // Keywords[i] = asm('xor eax, KeywordsMeta[i]') +
Keywords[i][1] = 0xf0;
Keywords[i][2] = KeywordsMeta[i];
Keywords[i][3] = 0x88; // asm_prefix('mov byte ptr ds:xxxxxxxxxxxxxxxx, al')
Keywords[i][4] = 0x05;
}
}
bool Solution2::FindPatchOffset() noexcept {
PIMAGE_SECTION_HEADER textSection = nullptr;
uint8_t* pTargetFileView = pTargetFile->GetView<uint8_t>();
uint8_t* ptextSectionData = nullptr;
off_t Offsets[KeywordsCount];
memset(Offsets, -1, sizeof(Offsets));
textSection = Helper::ImageSectionHeader(pTargetFileView, ".text");
if (textSection == nullptr)
return false;
ptextSectionData = pTargetFileView + textSection->PointerToRawData;
BuildKeywords();
// Find offsets
{
size_t FirstKeywordCounter = 0;
uint32_t Hints[9];
DWORD PossibleRangeStart = 0xffffffff;
DWORD PossibleRangeEnd;
for (DWORD i = 0; i < textSection->SizeOfRawData; ++i) {
if (memcmp(ptextSectionData + i, Keywords[0], sizeof(Keywords[0])) == 0) {
Hints[FirstKeywordCounter++] =
*reinterpret_cast<uint32_t*>(ptextSectionData + i + sizeof(Keywords[0])) +
i + sizeof(Keywords[0]) + sizeof(uint32_t);
if (i < PossibleRangeStart)
PossibleRangeStart = i;
}
}
PossibleRangeStart -= 0x1000;
PossibleRangeEnd = PossibleRangeStart + 0x100000;
// Keywords[0] should occur 9 times.
// Because there's only 9 'M' chars in `KeywordsMeta`.
if (FirstKeywordCounter != 9)
return false;
Helper::QuickSort(Hints, 0, _countof(Hints));
// assert
// if not satisfied, refuse to patch
if (Hints[8] - Hints[0] != 0x18360F8F8 - 0x18360F7D0)
return false;
for (size_t i = 0; i < KeywordsCount; ++i) {
if (Offsets[i] != -1)
continue;
for (DWORD j = PossibleRangeStart; j < PossibleRangeEnd; ++j) {
if (memcmp(ptextSectionData + j, Keywords[i], sizeof(Keywords[i])) == 0) {
off_t index =
*reinterpret_cast<uint32_t*>(ptextSectionData + j + sizeof(Keywords[i])) +
j + sizeof(Keywords[i]) + sizeof(uint32_t) - Hints[0];
if (0 <= index && index < KeywordsCount && KeywordsMeta[index] == KeywordsMeta[i]) {
Offsets[index] = textSection->PointerToRawData + j;
}
}
}
// if not found, refuse to patch
if (Offsets[i] == -1)
return false;
}
}
static_assert(sizeof(PatchOffsets) == sizeof(Offsets), "static_assert failure!");
memcpy(PatchOffsets, Offsets, sizeof(PatchOffsets));
for (size_t i = 0; i < KeywordsCount; ++i)
_tprintf_s(TEXT("MESSAGE: [Solution2] Keywords[%zu] has been found: offset = +0x%08lx.\n"),
i, PatchOffsets[i]);
return true;
}
#else
void Solution2::BuildKeywords() noexcept {
for (size_t i = 0; i < KeywordsCount; ++i) {
switch (i % 3) {
case 0:
Keywords[i][0] = 0x83; // Keywords[i] = asm('xor edx, KeywordsMeta[i]') +
Keywords[i][1] = 0xf2;
Keywords[i][2] = KeywordsMeta[i];
Keywords[i][3] = 0x88; // asm_prefix('mov byte ptr ds:xxxxxxxx, dl')
Keywords[i][4] = 0x15;
break;
case 1:
Keywords[i][0] = 0x83; // Keywords[i] = asm('xor eax, KeywordsMeta[i]') +
Keywords[i][1] = 0xf0;
Keywords[i][2] = KeywordsMeta[i];
Keywords[i][3] = 0xa2; // asm_prefix('mov byte ptr ds:xxxxxxxx, al')
break;
default:
Keywords[i][0] = 0x83; // Keywords[i] = asm('xor ecx, KeywordsMeta[i]') +
Keywords[i][1] = 0xf1;
Keywords[i][2] = KeywordsMeta[i];
Keywords[i][3] = 0x88; // asm_prefix('mov byte ptr ds:xxxxxxxx, cl')
Keywords[i][4] = 0x0D;
break;
}
}
}
bool Solution2::FindPatchOffset() noexcept {
PIMAGE_SECTION_HEADER textSection = nullptr;
uint8_t* pTargetFileView = pTargetFile->GetView<uint8_t>();
uint8_t* ptextSectionData = nullptr;
off_t Offsets[KeywordsCount];
memset(Offsets, -1, sizeof(Offsets));
textSection = Helper::ImageSectionHeader(pTargetFileView, ".text");
if (textSection == nullptr)
return false;
ptextSectionData = pTargetFileView + textSection->PointerToRawData;
BuildKeywords();
// Find offsets
{
size_t FirstKeywordCounter = 0;
uint32_t Hints[3];
DWORD PossibleRangeStart = 0xffffffff;
DWORD PossibleRangeEnd;
for (DWORD i = 0; i < textSection->SizeOfRawData; ++i) {
if (memcmp(ptextSectionData + i, Keywords[0], sizeof(Keywords[0])) == 0) {
Hints[FirstKeywordCounter++] =
*reinterpret_cast<uint32_t*>(ptextSectionData + i + sizeof(Keywords[0]));
if (i < PossibleRangeStart)
PossibleRangeStart = i;
}
}
PossibleRangeStart -= 0x1000;
PossibleRangeEnd = PossibleRangeStart + 0x100000;
// Keywords[0] should occur 3 times.
if (FirstKeywordCounter != 3)
return false;
Helper::QuickSort(Hints, 0, _countof(Hints));
// assert
// if not satisfied, refuse to patch
if (Hints[2] - Hints[0] != 0x127382BE - 0x12738210)
return false;
for (size_t i = 0; i < KeywordsCount; ++i) {
uint8_t CurrentKeyword[9];
size_t CurrentKeywordSize = i % 3 == 1 ? 4 : 5;
memcpy(CurrentKeyword, Keywords[i], CurrentKeywordSize);
*reinterpret_cast<uint32_t*>(CurrentKeyword + CurrentKeywordSize) = Hints[0] + i;
CurrentKeywordSize += sizeof(uint32_t);
for (DWORD j = PossibleRangeStart; j < PossibleRangeEnd; ++j) {
if (memcmp(ptextSectionData + j, CurrentKeyword, CurrentKeywordSize) == 0) {
Offsets[i] = textSection->PointerToRawData + j;
break;
}
}
// if not found, refuse to patch
if (Offsets[i] == -1)
return false;
}
}
static_assert(sizeof(PatchOffsets) == sizeof(Offsets), "static_assert failure!");
memcpy(PatchOffsets, Offsets, sizeof(PatchOffsets));
for (size_t i = 0; i < KeywordsCount; ++i)
_tprintf_s(TEXT("MESSAGE: [Solution2] Keywords[%zu] has been found: offset = +0x%08lx.\n"),
i, PatchOffsets[i]);
return true;
}
#endif
bool Solution2::MakePatch(RSACipher* cipher) const {
std::string RSAPublicKeyPEM;
uint8_t* pTargetFileView = pTargetFile->GetView<uint8_t>();
RSAPublicKeyPEM = cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
if (RSAPublicKeyPEM.empty()) {
REPORT_ERROR("ERROR: cipher->ExportKeyString failed.");
return false;
}
RSAPublicKeyPEM.erase(RSAPublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"), 26);
RSAPublicKeyPEM.erase(RSAPublicKeyPEM.find("-----END PUBLIC KEY-----"), 24);
{
std::string::size_type pos = 0;
while ((pos = RSAPublicKeyPEM.find("\n", pos)) != std::string::npos) {
RSAPublicKeyPEM.erase(pos, 1);
}
}
if (RSAPublicKeyPEM.length() != KeywordsCount) {
REPORT_ERROR("ERROR: Public key length does not match.");
return false;
}
PRINT_MESSAGE("//");
PRINT_MESSAGE("// Begin Solution2");
PRINT_MESSAGE("//");
for (size_t i = 0; i < KeywordsCount; ++i) {
_tprintf_s(TEXT("@+0x%08X: %02X %02X %02X --> "),
PatchOffsets[i],
pTargetFileView[PatchOffsets[i]],
pTargetFileView[PatchOffsets[i] + 1],
pTargetFileView[PatchOffsets[i] + 2]);
pTargetFileView[PatchOffsets[i] + 2] = RSAPublicKeyPEM[i];
_tprintf_s(TEXT("%02X %02X %02X\n"),
pTargetFileView[PatchOffsets[i]],
pTargetFileView[PatchOffsets[i] + 1],
pTargetFileView[PatchOffsets[i] + 2]);
}
PRINT_MESSAGE("");
return true;
}
}
+253 -129
View File
@@ -1,178 +1,302 @@
#include "def.hpp"
bool ConvertToUTF8(LPCSTR from, std::string& to) {
bool bSuccess = false;
int len = 0;
LPWSTR lpUnicodeString = nullptr;
#define SAFE_DELETE(x) { delete x; x = nullptr; }
len = MultiByteToWideChar(CP_ACP, NULL, from, -1, NULL, 0);
if (len == 0)
goto ON_ConvertToUTF8_0_ERROR;
lpUnicodeString = reinterpret_cast<LPWSTR>(HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
len * sizeof(WCHAR)));
if (lpUnicodeString == nullptr)
goto ON_ConvertToUTF8_0_ERROR;
if (!MultiByteToWideChar(CP_ACP, NULL, from, -1, lpUnicodeString, len))
goto ON_ConvertToUTF8_0_ERROR;
len = WideCharToMultiByte(CP_UTF8, NULL, lpUnicodeString, -1, NULL, 0, NULL, NULL);
if (len == 0)
goto ON_ConvertToUTF8_0_ERROR;
to.resize(len);
if (!WideCharToMultiByte(CP_UTF8, NULL, lpUnicodeString, -1, to.data(), len, NULL, NULL))
goto ON_ConvertToUTF8_0_ERROR;
while (to.back() == 0)
to.pop_back();
bSuccess = true;
ON_ConvertToUTF8_0_ERROR:
if (lpUnicodeString)
HeapFree(GetProcessHeap(), NULL, lpUnicodeString);
return bSuccess;
static void help() {
PRINT_MESSAGE("Usage:");
PRINT_MESSAGE(" navicat-patcher.exe <Navicat installation path> [RSA-2048 PEM file]");
}
bool ConvertToUTF8(LPCWSTR from, std::string& to) {
bool bSuccess = false;
int len = 0;
std::Tstring InstallationPath;
std::Tstring MainAppName;
std::Tstring LibccName = TEXT("libcc.dll");
len = WideCharToMultiByte(CP_UTF8, NULL, from, -1, NULL, 0, NULL, NULL);
if (len == 0)
goto ON_ConvertToUTF8_1_ERROR;
static BOOL SetPath(const std::Tstring& Path) {
DWORD Attr;
to.resize(len);
if (!WideCharToMultiByte(CP_UTF8, NULL, from, -1, to.data(), len, NULL, NULL))
goto ON_ConvertToUTF8_1_ERROR;
Attr = GetFileAttributes(Path.c_str());
if (Attr == INVALID_FILE_ATTRIBUTES) {
if (GetLastError() == ERROR_INVALID_NAME || GetLastError() == ERROR_FILE_NOT_FOUND)
REPORT_ERROR("ERROR: Invalid path. Are you sure the path you specified is correct?");
else
REPORT_ERROR_WITH_CODE("ERROR: GetFileAttributes failed.", GetLastError());
return FALSE;
}
while (to.back() == 0)
to.pop_back();
if ((Attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
REPORT_ERROR("ERROR: Path is not a directory.");
return FALSE;
}
bSuccess = true;
InstallationPath = Path;
if (InstallationPath.back() != TEXT('\\') && InstallationPath.back() != TEXT('/'))
InstallationPath.push_back(TEXT('/')); // for Linux compatible
ON_ConvertToUTF8_1_ERROR:
return bSuccess;
return TRUE;
}
bool ConvertToUTF8(std::string& str) {
bool bSuccess = false;
static DWORD BackupFile(std::Tstring& from, std::Tstring& to) {
if (::CopyFile(from.c_str(), to.c_str(), TRUE))
return ERROR_SUCCESS;
else
return GetLastError();
}
std::string temp;
bSuccess = ConvertToUTF8(str.c_str(), temp);
if (!bSuccess)
return false;
static BOOL LoadKey(RSACipher* cipher, LPTSTR filename,
Patcher::Solution* pSolution0,
Patcher::Solution* pSolution1,
Patcher::Solution* pSolution2) {
if (filename) {
std::string PrivateKeyFileName;
str = temp;
return true;
if (!Helper::ConvertToUTF8(filename, PrivateKeyFileName)) {
REPORT_ERROR("ERROR: ConvertToUTF8 failed.");
return FALSE;
}
if (!cipher->ImportKeyFromFile<RSACipher::KeyType::PrivateKey, RSACipher::KeyFormat::PEM>(PrivateKeyFileName)) {
REPORT_ERROR("ERROR: cipher->ImportKeyFromFile failed.");
return FALSE;
}
if (pSolution0 && !pSolution0->CheckKey(cipher) ||
pSolution1 && !pSolution1->CheckKey(cipher) ||
pSolution2 && !pSolution2->CheckKey(cipher)) {
REPORT_ERROR("ERROR: The RSA private key you provide cannot be used.");
return FALSE;
}
} else {
PRINT_MESSAGE("MESSAGE: Generating new RSA private key, it may take a long time.");
do {
cipher->GenerateKey(2048);
} while (pSolution0 && !pSolution0->CheckKey(cipher) ||
pSolution1 && !pSolution1->CheckKey(cipher) ||
pSolution2 && !pSolution2->CheckKey(cipher)); // re-generate RSA key if one of CheckKey return false
if (!cipher->ExportKeyToFile<RSACipher::KeyType::PrivateKey, RSACipher::KeyFormat::NotSpecified>("RegPrivateKey.pem")) {
REPORT_ERROR("ERROR: Failed to save RSA private key.");
return FALSE;
}
PRINT_MESSAGE("MESSAGE: New RSA private key has been saved to RegPrivateKey.pem.");
}
std::string PublicKeyString = cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
if (PublicKeyString.empty()) {
REPORT_ERROR("ERROR: cipher->ExportKeyString failed.");
return FALSE;
}
PRINT_MESSAGE("Your RSA public key:");
PRINT_LPCSTR(PublicKeyString.c_str());
return TRUE;
}
int _tmain(int argc, TCHAR* argv[]) {
if (argc != 2 && argc != 3) {
_tprintf_s(TEXT("Usage:\n"));
_tprintf_s(TEXT(" navicat-patcher.exe <Navicat installation path> [RSA-2048 PEM file]\n"));
help();
return 0;
}
RSACipher* cipher = NULL;
DWORD dwMajorVer = 0;
DWORD dwMinorVer = 0;
RSACipher* cipher = nullptr;
FileMapper* pMainApp = nullptr;
FileMapper* pLibcc = nullptr;
Patcher::Solution* pSolution0 = nullptr;
Patcher::Solution* pSolution1 = nullptr;
Patcher::Solution* pSolution2 = nullptr;
DWORD ErrorCode;
cipher = RSACipher::Create();
if (cipher == NULL) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("RSACipher::Create failed.\n"));
if (cipher == nullptr) {
REPORT_ERROR("ERROR: RSACipher::Create failed.");
goto ON_tmain_ERROR;
}
if (!patcher::Solution0::Init(argv[1]))
pMainApp = new FileMapper();
pLibcc = new FileMapper();
pSolution0 = new Patcher::Solution0();
pSolution1 = new Patcher::Solution1();
pSolution2 = new Patcher::Solution2();
if (!SetPath(argv[1])) {
PRINT_MESSAGE("The path you specified:");
PRINT_LPCTSTR(argv[1]);
goto ON_tmain_ERROR;
if (!patcher::Solution1::Init(argv[1]))
}
FindMainApp:
ErrorCode = pMainApp->MapFile(InstallationPath + TEXT("Navicat.exe"));
if (ErrorCode == ERROR_SUCCESS) {
MainAppName = TEXT("Navicat.exe");
PRINT_MESSAGE("MESSAGE: Navicat.exe has been found.");
goto FindLibcc;
}
if (ErrorCode == ERROR_ACCESS_DENIED) {
PRINT_MESSAGE("ERROR: Cannot open Navicat.exe for ERROR_ACCESS_DENIED.");
PRINT_MESSAGE("Please re-run with Administrator privilege.");
goto ON_tmain_ERROR;
}
if (ErrorCode != ERROR_FILE_NOT_FOUND) {
REPORT_ERROR_WITH_CODE("ERROR: Cannot open Navicat.exe.", ErrorCode);
goto ON_tmain_ERROR;
}
if (argc == 3) {
std::string PrivateKeyFileName;
ErrorCode = pMainApp->MapFile(InstallationPath + TEXT("Modeler.exe"));
if (ErrorCode == ERROR_SUCCESS) {
MainAppName = TEXT("Modeler.exe");
PRINT_MESSAGE("MESSAGE: Modeler.exe has been found.");
goto FindLibcc;
}
if (ErrorCode == ERROR_ACCESS_DENIED) {
PRINT_MESSAGE("ERROR: Cannot open Modeler.exe for ERROR_ACCESS_DENIED.");
PRINT_MESSAGE("Please re-run with Administrator privilege.");
goto ON_tmain_ERROR;
}
if (ErrorCode != ERROR_FILE_NOT_FOUND) {
REPORT_ERROR_WITH_CODE("ERROR: Cannot open Modeler.exe.", ErrorCode);
goto ON_tmain_ERROR;
}
if (!ConvertToUTF8(argv[2], PrivateKeyFileName)) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: ConvertToUTF8 failed.\n"));
goto ON_tmain_ERROR;
}
ErrorCode = pMainApp->MapFile(InstallationPath + TEXT("Rviewer.exe"));
if (ErrorCode == ERROR_SUCCESS) {
MainAppName = TEXT("Rviewer.exe");
PRINT_MESSAGE("MESSAGE: Rviewer.exe has been found.");
goto FindLibcc;
}
if (ErrorCode == ERROR_ACCESS_DENIED) {
PRINT_MESSAGE("ERROR: Cannot open Rviewer.exe for ERROR_ACCESS_DENIED.");
PRINT_MESSAGE("Please re-run with Administrator privilege.");
goto ON_tmain_ERROR;
}
if (ErrorCode != ERROR_FILE_NOT_FOUND) {
REPORT_ERROR_WITH_CODE("ERROR: Cannot open Rviewer.exe.", ErrorCode);
goto ON_tmain_ERROR;
}
if (!cipher->ImportKeyFromFile<RSACipher::KeyType::PrivateKey, RSACipher::KeyFormat::PEM>(PrivateKeyFileName)) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: cipher->ImportKeyFromFile failed.\n"));
goto ON_tmain_ERROR;
}
PRINT_MESSAGE("ERROR: Cannot find main application. Are you sure the path you specified is correct?");
PRINT_MESSAGE("The path you specified:");
PRINT_LPCTSTR(argv[1]);
goto ON_tmain_ERROR;
if (patcher::Solution0::CheckKey(cipher) == FALSE || patcher::Solution1::CheckKey(cipher) == FALSE) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: RSA private key specified cannot be used.\n"));
goto ON_tmain_ERROR;
}
FindLibcc:
ErrorCode = pLibcc->MapFile(InstallationPath + LibccName);
if (ErrorCode == ERROR_SUCCESS) {
PRINT_MESSAGE("MESSAGE: libcc.dll has been found.");
} else if (ErrorCode == ERROR_FILE_NOT_FOUND) {
PRINT_MESSAGE("MESSAGE: libcc.dll is not found. Solution1 and Solution2 will be omitted.");
SAFE_DELETE(pSolution2);
SAFE_DELETE(pSolution1);
SAFE_DELETE(pLibcc);
} else if (ErrorCode == ERROR_ACCESS_DENIED) {
PRINT_MESSAGE("ERROR: Cannot open libcc.dll for ERROR_ACCESS_DENIED.");
PRINT_MESSAGE("Please re-run with Administrator privilege.");
goto ON_tmain_ERROR;
} else {
do {
cipher->GenerateKey(2048);
} while (patcher::Solution0::CheckKey(cipher) && patcher::Solution1::CheckKey(cipher));
cipher->ExportKeyToFile<RSACipher::KeyType::PrivateKey, RSACipher::KeyFormat::PEM>("RegPrivateKey.pem");
_tprintf_s(TEXT("New RSA private key has been saved to RegPrivateKey.pem.\n"));
}
// ------------------
// begin Solution0
// ------------------
if (!patcher::Solution0::FindTargetFile()) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: Cannot find main program. Are you sure the path you specified is correct?\n"));
REPORT_ERROR_WITH_CODE("ERROR: Cannot open libcc.dll.", ErrorCode);
goto ON_tmain_ERROR;
}
if (!patcher::Solution0::GetVersion(&dwMajorVer, &dwMinorVer))
goto ON_tmain_ERROR;
SearchPublicKey:
pSolution0->SetFile(pMainApp);
if (pSolution1) pSolution1->SetFile(pLibcc);
if (pSolution2) pSolution2->SetFile(pLibcc);
if (!patcher::Solution0::CheckFile())
goto ON_tmain_ERROR;
if (!patcher::Solution0::BackupFile())
goto ON_tmain_ERROR;
if (!patcher::Solution0::Do(cipher))
goto ON_tmain_ERROR;
_tprintf_s(TEXT("Solution0 has been done successfully.\n"));
_tprintf_s(TEXT("\n"));
// for ver <= 12.0.24
if (dwMajorVer == 0x000c0000 && dwMinorVer < 0x00180000)
goto ON_tmain_ERROR; // you don't need Solution1 patch.
// ------------------
// begin Solution1
// ------------------
if (!patcher::Solution1::FindTargetFile()) {
PRINT_MESSAGE("");
if (!pSolution0->FindPatchOffset()) {
_tprintf_s(TEXT("@%s LINE: %u\n"), TEXT(__FUNCTION__), __LINE__);
_tprintf_s(TEXT("ERROR: Cannot find libcc.dll. Are you sure the path you specified is correct?\n"));
_tprintf_s(TEXT("ERROR: Cannot find RSA public key in %s.\n"), MainAppName.c_str());
goto ON_tmain_ERROR;
}
}
if (!patcher::Solution1::FindOffset())
if (pSolution1 && !pSolution1->FindPatchOffset()) {
PRINT_MESSAGE("MESSAGE: Cannot find RSA public key in libcc.dll. Solution1 will be omitted.");
pSolution1->SetFile(nullptr);
SAFE_DELETE(pSolution1);
}
if (pSolution2 && !pSolution2->FindPatchOffset()) {
PRINT_MESSAGE("MESSAGE: Cannot find RSA public key in libcc.dll. Solution2 will be omitted.");
pSolution2->SetFile(nullptr);
SAFE_DELETE(pSolution2);
}
LoadingKey:
PRINT_MESSAGE("");
if (!LoadKey(cipher, argc == 3 ? argv[2] : nullptr, pSolution0, pSolution1, pSolution2))
goto ON_tmain_ERROR;
if (!patcher::Solution1::BackupFile())
BackupFiles:
PRINT_MESSAGE("");
ErrorCode = BackupFile(InstallationPath + MainAppName, InstallationPath + MainAppName + TEXT(".backup"));
if (ErrorCode == ERROR_SUCCESS) {
_tprintf_s(TEXT("MESSAGE: %s has been backed up successfully.\n"), MainAppName.c_str());
} else if (ErrorCode == ERROR_ACCESS_DENIED) {
_tprintf_s(TEXT("ERROR: Cannot back up %s for ERROR_ACCESS_DENIED.\n"), MainAppName.c_str());
_tprintf_s(TEXT("Please re-run with Administrator privilege.\n"));
goto ON_tmain_ERROR;
} else if (ErrorCode == ERROR_FILE_EXISTS) {
_tprintf_s(TEXT("ERROR: The backup of %s has been found.\n"), MainAppName.c_str());
_tprintf_s(TEXT("Please remove %s.backup in Navicat installation path if you're sure %s has not been patched.\n"),
MainAppName.c_str(),
MainAppName.c_str());
_tprintf_s(TEXT("Otherwise please restore %s by %s.backup and remove %s.backup then try again.\n"),
MainAppName.c_str(),
MainAppName.c_str(),
MainAppName.c_str());
goto ON_tmain_ERROR;
} else {
_tprintf_s(TEXT("ERROR: Cannot back up %s. CODE: 0x%08X\n"),
MainAppName.c_str(),
ErrorCode);
goto ON_tmain_ERROR;
}
if (pSolution1 || pSolution2) {
ErrorCode = BackupFile(InstallationPath + LibccName, InstallationPath + LibccName + TEXT(".backup"));
if (ErrorCode == ERROR_SUCCESS) {
PRINT_MESSAGE("MESSAGE: libcc.dll has been backed up successfully.");
} else if (ErrorCode == ERROR_ACCESS_DENIED) {
PRINT_MESSAGE("ERROR: Cannot back up libcc.dll for ERROR_ACCESS_DENIED.");
PRINT_MESSAGE("Please re-run with Administrator privilege.");
goto ON_tmain_ERROR;
} else if (ErrorCode == ERROR_FILE_EXISTS) {
PRINT_MESSAGE("ERROR: The backup of libcc.dll has been found.");
PRINT_MESSAGE("Please remove libcc.dll.backup in Navicat installation path if you're sure libcc.dll has not been patched.");
PRINT_MESSAGE("Otherwise please restore libcc.dll by libcc.dll.backup and remove libcc.dll.backup then try again.");
goto ON_tmain_ERROR;
} else {
REPORT_ERROR_WITH_CODE("ERROR: Cannot back up libcc.dll.", ErrorCode);
goto ON_tmain_ERROR;
}
}
MakingPatch:
PRINT_MESSAGE("");
if (!pSolution0->MakePatch(cipher))
goto ON_tmain_ERROR;
if (!patcher::Solution1::Do(cipher))
if (pSolution1 && !pSolution1->MakePatch(cipher))
goto ON_tmain_ERROR;
_tprintf_s(TEXT("Solution1 has been done successfully.\n"));
_tprintf_s(TEXT("\n"));
if (pSolution2 && !pSolution2->MakePatch(cipher))
goto ON_tmain_ERROR;
PRINT_MESSAGE("Solution0 has been done successfully.");
if (pSolution1)
PRINT_MESSAGE("Solution1 has been done successfully.");
if (pSolution2)
PRINT_MESSAGE("Solution2 has been done successfully.");
ON_tmain_ERROR:
patcher::Solution1::Finalize();
patcher::Solution0::Finalize();
delete cipher;
SAFE_DELETE(pSolution2);
SAFE_DELETE(pSolution1);
SAFE_DELETE(pSolution0);
SAFE_DELETE(pLibcc);
SAFE_DELETE(pMainApp);
SAFE_DELETE(cipher);
return 0;
}
}
+261 -26
View File
@@ -2,41 +2,276 @@
#include <tchar.h>
#include <windows.h>
#include <string>
#include "RSACipher.hpp"
#pragma comment(lib, "version.lib") // GetFileVersionInfoSize, GetFileVersionInfo, VerQueryValue are in this lib
namespace std {
#ifdef UNICODE
typedef wstring Tstring;
namespace std { typedef wstring Tstring; }
#else
typedef string Tstring;
#endif // UNICODE
namespace std { typedef string Tstring; }
#endif
namespace Helper {
std::string EncryptPublicKey(const std::string& PublicKeyString);
bool ConvertToUTF8(LPCSTR from, std::string& to);
bool ConvertToUTF8(LPCWSTR from, std::string& to);
bool ConvertToUTF8(std::string& str);
void ErrorReport(LPCTSTR at, UINT line, LPCTSTR msg);
void ErrorReport(LPCTSTR at, UINT line, LPCTSTR msg, DWORD err_code);
//
// Print memory data in [from, to) at least
// If `base` is not nullptr, print address as offset. Otherwise, as absolute address.
// NOTICE:
// `base` must >= `from`
//
void PrintMemory(const void* from, const void* to, const void* base = nullptr);
PIMAGE_SECTION_HEADER ImageSectionHeader(PVOID lpBase, LPCSTR lpSectionName);
template<typename _Type, bool _Ascending = true>
void QuickSort(_Type* pArray, off_t begin, off_t end) {
if (end - begin <= 1)
return;
off_t i = begin;
off_t j = end - 1;
_Type seperator = static_cast<_Type&&>(pArray[begin]);
while (i < j) {
if (_Ascending) {
while (i < j && seperator <= pArray[j])
--j;
if (i < j)
pArray[i++] = static_cast<_Type&&>(pArray[j]);
while (i < j && pArray[i] <= seperator)
++i;
if (i < j)
pArray[j--] = static_cast<_Type&&>(pArray[i]);
} else {
while (i < j && seperator >= pArray[j])
--j;
if (i < j)
pArray[i++] = static_cast<_Type&&>(pArray[j]);
while (i < j && pArray[i] >= seperator)
++i;
if (i < j)
pArray[j--] = static_cast<_Type&&>(pArray[i]);
}
}
pArray[i] = static_cast<_Type&&>(seperator);
QuickSort<_Type, _Ascending>(pArray, begin, i);
QuickSort<_Type, _Ascending>(pArray, i + 1, end);
}
}
namespace patcher {
#define REPORT_ERROR(msg) Helper::ErrorReport(TEXT(__FUNCTION__), __LINE__, TEXT(msg))
#define REPORT_ERROR_WITH_CODE(msg, err_code) Helper::ErrorReport(TEXT(__FUNCTION__), __LINE__, TEXT(msg), (err_code))
std::string EncryptPublicKey(const char* public_key, size_t len);
#define PRINT_MESSAGE(msg) _tprintf_s(TEXT("%s\n"), TEXT(msg))
#define PRINT_LPCTSTR(msg) _tprintf_s(TEXT("%s\n"), (msg))
#define PRINT_LPCSTR(msg) printf_s("%s\n", (msg))
#define PRINT_LPCWSTR(msg) wprintf_s(L"%s\n", (msg))
namespace Solution0 {
BOOL Init(const std::Tstring& Path);
BOOL CheckKey(RSACipher* cipher);
BOOL FindTargetFile();
BOOL CheckFile();
BOOL BackupFile();
BOOL Do(RSACipher* cipher);
BOOL GetVersion(LPDWORD lpMajorVer, LPDWORD lpMinorVer);
VOID Finalize();
template<HANDLE __Invalid>
class HandleGuard {
private:
bool bError;
HANDLE& Handle;
public:
HandleGuard(HANDLE& Target) noexcept : bError(true), Handle(Target) {}
void ErrorOccurs() noexcept { bError = true; }
void NoErrorOccurs() noexcept { bError = false; }
~HandleGuard() noexcept {
if (bError && Handle != __Invalid) {
CloseHandle(Handle);
Handle = __Invalid;
}
}
};
class FileMapper {
private:
HANDLE hFile;
HANDLE hMap;
PVOID pMapView;
public:
FileMapper() noexcept :
hFile(INVALID_HANDLE_VALUE),
hMap(NULL),
pMapView(nullptr) {}
void Release() noexcept {
if (pMapView) {
UnmapViewOfFile(pMapView);
pMapView = NULL;
}
if (hMap) {
CloseHandle(hMap);
hMap = NULL;
}
if (hFile != INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
}
}
namespace Solution1 {
BOOL Init(const std::Tstring& Path);
BOOL CheckKey(RSACipher* cipher);
BOOL FindTargetFile();
BOOL FindOffset();
BOOL BackupFile();
BOOL Do(RSACipher* cipher);
VOID Finalize();
template<typename _Type>
_Type* GetView() const noexcept {
return reinterpret_cast<_Type*>(pMapView);
}
}
DWORD MapFile(std::Tstring& Name) noexcept {
HandleGuard<INVALID_HANDLE_VALUE> hFileGuard(hFile);
HandleGuard<NULL> hMapGuard(hMap);
hFile = CreateFile(Name.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, // share read so that we can copy
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return GetLastError();
hMap = CreateFileMapping(hFile,
NULL,
PAGE_READWRITE,
0,
0,
NULL);
if (hMap == NULL)
return GetLastError();
pMapView = MapViewOfFile(hMap,
FILE_MAP_READ | FILE_MAP_WRITE,
0,
0,
0);
if (pMapView == NULL)
return GetLastError();
hFileGuard.NoErrorOccurs();
hMapGuard.NoErrorOccurs();
return ERROR_SUCCESS;
}
~FileMapper() {
Release();
}
};
namespace Patcher {
class Solution {
public:
virtual void SetFile(FileMapper* pFile) = 0;
virtual bool CheckKey(RSACipher* cipher) const = 0;
virtual bool FindPatchOffset() = 0;
virtual bool MakePatch(RSACipher* cipher) const = 0;
virtual ~Solution() {}
};
// Solution0 will replace the RSA public key stored in main application.
class Solution0 : public Solution {
private:
static const char Keyword[461];
static constexpr int KeywordLength = 460;
FileMapper* pTargetFile;
off_t PatchOffset;
public:
Solution0() noexcept :
pTargetFile(nullptr),
PatchOffset(-1) {}
virtual void SetFile(FileMapper* pMainApp) noexcept override {
pTargetFile = pMainApp;
}
// Solution0 does not have any requirements for an RSA-2048 key
virtual bool CheckKey(RSACipher* cipher) const noexcept override {
return true;
}
// Return true if found, other return false
virtual bool FindPatchOffset() noexcept override;
// Make a patch based on an RSA private key given
// Return true if success, otherwise return false
virtual bool MakePatch(RSACipher* cipher) const override;
};
// Solution0 will replace the RSA public key stored in libcc.dll
class Solution1 : public Solution {
private:
static const char* Keywords[5];
static const int KeywordsLength[5];
FileMapper* pTargetFile;
off_t PatchOffsets[5];
public:
Solution1() :
pTargetFile(nullptr),
PatchOffsets{ -1, -1, -1, -1, -1 } {}
virtual void SetFile(FileMapper* pLibccFile) noexcept override {
pTargetFile = pLibccFile;
}
// Solution1 has some requirements for an RSA-2048 key
virtual bool CheckKey(RSACipher* cipher) const noexcept override;
// Return true if found, otherwise return false
virtual bool FindPatchOffset() noexcept override;
// Make a patch based on an RSA private key given
// Return true if success, otherwise return false
virtual bool MakePatch(RSACipher* cipher) const override;
};
class Solution2 : public Solution {
private:
static constexpr size_t KeywordsCount = 0x188;
static const char KeywordsMeta[KeywordsCount + 1];
static uint8_t Keywords[KeywordsCount][5];
FileMapper* pTargetFile;
off_t PatchOffsets[KeywordsCount];
void BuildKeywords() noexcept;
public:
Solution2() :
pTargetFile(nullptr) {
memset(PatchOffsets, -1, sizeof(PatchOffsets));
}
virtual void SetFile(FileMapper* pLibccFile) noexcept override {
pTargetFile = pLibccFile;
}
// Solution2 has no requirements for an RSA-2048 key
virtual bool CheckKey(RSACipher* cipher) const noexcept override {
return true;
}
// Return true if found, otherwise return false
virtual bool FindPatchOffset() noexcept override;
// Make a patch based on an RSA private key given
// Return true if success, otherwise return false
virtual bool MakePatch(RSACipher* cipher) const override;
};
}
+3 -9
View File
@@ -166,21 +166,15 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="EncryptPublicKey.cpp" />
<ClCompile Include="NavicatCrypto\aes.c" />
<ClCompile Include="NavicatCrypto\aes_constant.c" />
<ClCompile Include="NavicatCrypto\blowfish.c" />
<ClCompile Include="NavicatCrypto\sha1.c" />
<ClCompile Include="Helper.cpp" />
<ClCompile Include="Solution0.cpp" />
<ClCompile Include="Solution1.cpp" />
<ClCompile Include="Solution2.cpp" />
<ClCompile Include="_tmain.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="def.hpp" />
<ClInclude Include="NavicatCrypto\aes.h" />
<ClInclude Include="NavicatCrypto\blowfish.h" />
<ClInclude Include="NavicatCrypto\NavicatCrypto.hpp" />
<ClInclude Include="NavicatCrypto\sha1.h" />
<ClInclude Include="NavicatCrypto.hpp" />
<ClInclude Include="RSACipher.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
@@ -18,46 +18,28 @@
<ClCompile Include="_tmain.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="NavicatCrypto\aes.c">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="NavicatCrypto\aes_constant.c">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="NavicatCrypto\blowfish.c">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="NavicatCrypto\sha1.c">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="EncryptPublicKey.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="Solution0.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="Solution1.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="Helper.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="Solution2.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="NavicatCrypto\aes.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="NavicatCrypto\blowfish.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="NavicatCrypto\NavicatCrypto.hpp">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="NavicatCrypto\sha1.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="def.hpp">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="RSACipher.hpp">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="NavicatCrypto.hpp">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
</Project>