132
navicat-keygen/CollectInformation.cpp
Normal file
132
navicat-keygen/CollectInformation.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#include <iostream>
|
||||
#include "navicat_serial_generator.hpp"
|
||||
#include "exceptions/operation_canceled_exception.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\CollectInformation.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
[[nodiscard]]
|
||||
static int read_int(int min_val, int max_val, std::string_view prompt, std::string_view error_msg) {
|
||||
int val;
|
||||
|
||||
for (std::string s;;) {
|
||||
std::cout << prompt;
|
||||
if (!std::getline(std::cin, s)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
}
|
||||
|
||||
if (s.empty())
|
||||
continue;
|
||||
|
||||
try {
|
||||
val = std::stoi(s, nullptr, 0);
|
||||
if (min_val <= val && val <= max_val) {
|
||||
return val;
|
||||
} else {
|
||||
throw std::invalid_argument("Out of range.");
|
||||
}
|
||||
} catch (std::invalid_argument&) {
|
||||
std::cout << error_msg << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
static int read_int(int min_val, int max_val, int default_val, std::string_view prompt, std::string_view error_msg) {
|
||||
int val;
|
||||
|
||||
for (std::string s;;) {
|
||||
std::cout << prompt;
|
||||
if (!std::getline(std::cin, s)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
}
|
||||
|
||||
if (s.empty()) {
|
||||
return default_val;
|
||||
}
|
||||
|
||||
try {
|
||||
val = std::stoi(s, nullptr, 0);
|
||||
if (min_val <= val && val <= max_val) {
|
||||
return val;
|
||||
} else {
|
||||
throw std::invalid_argument("Out of range.");
|
||||
}
|
||||
} catch (std::invalid_argument&) {
|
||||
std::cout << error_msg << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
navicat_serial_generator CollectInformationNormal() {
|
||||
navicat_serial_generator sn_generator;
|
||||
|
||||
std::cout << "[*] Select Navicat product:" << std::endl;
|
||||
std::cout << " 0. DataModeler" << std::endl;
|
||||
std::cout << " 1. Premium" << std::endl;
|
||||
std::cout << " 2. MySQL" << std::endl;
|
||||
std::cout << " 3. PostgreSQL" << std::endl;
|
||||
std::cout << " 4. Oracle" << std::endl;
|
||||
std::cout << " 5. SQLServer" << std::endl;
|
||||
std::cout << " 6. SQLite" << std::endl;
|
||||
std::cout << " 7. MariaDB" << std::endl;
|
||||
std::cout << " 8. MongoDB" << std::endl;
|
||||
std::cout << " 9. ReportViewer" << std::endl;
|
||||
std::cout << std::endl;
|
||||
sn_generator.set_software_type(static_cast<navicat_software_type>(read_int(0, 9, "(Input index)> ", "Invalid index.")));
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "[*] Select product language:" << std::endl;
|
||||
std::cout << " 0. English" << std::endl;
|
||||
std::cout << " 1. Simplified Chinese" << std::endl;
|
||||
std::cout << " 2. Traditional Chinese" << std::endl;
|
||||
std::cout << " 3. Japanese" << std::endl;
|
||||
std::cout << " 4. Polish" << std::endl;
|
||||
std::cout << " 5. Spanish" << std::endl;
|
||||
std::cout << " 6. French" << std::endl;
|
||||
std::cout << " 7. German" << std::endl;
|
||||
std::cout << " 8. Korean" << std::endl;
|
||||
std::cout << " 9. Russian" << std::endl;
|
||||
std::cout << " 10. Portuguese" << std::endl;
|
||||
std::cout << std::endl;
|
||||
sn_generator.set_software_language(static_cast<navicat_software_language>(read_int(0, 10, "(Input index)> ", "Invalid index.")));
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "[*] Input major version number:" << std::endl;
|
||||
sn_generator.set_software_version(read_int(11, 16, 16, "(range: 11 ~ 16, default: 16)> ", "Invalid number."));
|
||||
|
||||
std::cout << std::endl;
|
||||
return sn_generator;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
navicat_serial_generator CollectInformationAdvanced() {
|
||||
navicat_serial_generator sn_generator;
|
||||
|
||||
std::cout << "[*] Navicat Product Signature:" << std::endl;
|
||||
sn_generator.set_software_type(static_cast<uint8_t>(read_int(0x00, 0xff, "(range: 0x00 ~ 0xFF)> ", "Invalid number.")));
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "[*] Navicat Language Signature 0:" << std::endl;
|
||||
auto s1 = static_cast<uint8_t>(read_int(0x00, 0xff, "(range: 0x00 ~ 0xFF)> ", "Invalid number."));
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "[*] Navicat Language Signature 1:" << std::endl;
|
||||
auto s2 = static_cast<uint8_t>(read_int(0x00, 0xff, "(range: 0x00 ~ 0xFF)> ", "Invalid number."));
|
||||
|
||||
sn_generator.set_software_language(s1, s2);
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "[*] Input major version number:" << std::endl;
|
||||
sn_generator.set_software_version(read_int(0, 15, 12, "(range: 0 ~ 15, default: 12)> ", "Invalid number."));
|
||||
|
||||
std::cout << std::endl;
|
||||
return sn_generator;
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
211
navicat-keygen/GenerateLicense.cpp
Normal file
211
navicat-keygen/GenerateLicense.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
#include <fmt/format.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "exceptions/operation_canceled_exception.hpp"
|
||||
#include "exceptions/unix_exception.hpp"
|
||||
|
||||
#include "resource_wrapper.hpp"
|
||||
#include "resource_traits/unix_os/file_descriptor.hpp"
|
||||
|
||||
#include "rsa_cipher.hpp"
|
||||
#include "navicat_serial_generator.hpp"
|
||||
#include "base64_rfc4648.hpp"
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\GenerateLicense.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
void GenerateLicenseText(const rsa_cipher& cipher, const navicat_serial_generator& sn_generator) {
|
||||
std::string u8_username;
|
||||
std::string u8_organization;
|
||||
|
||||
std::string b64_request_code;
|
||||
std::vector<uint8_t> request_code;
|
||||
std::string u8_request_info;
|
||||
std::string u8_response_info;
|
||||
std::vector<uint8_t> response_code;
|
||||
std::string b64_response_code;
|
||||
|
||||
std::cout << "[*] Your name: ";
|
||||
if (!std::getline(std::cin, u8_username)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
}
|
||||
|
||||
std::cout << "[*] Your organization: ";
|
||||
if (!std::getline(std::cin, u8_organization)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "[*] Input request code in Base64: (Double press ENTER to end)" << std::endl;
|
||||
while (true) {
|
||||
std::string temp;
|
||||
if (!std::getline(std::cin, temp)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
}
|
||||
|
||||
if (temp.empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
b64_request_code.append(temp);
|
||||
}
|
||||
|
||||
request_code = base64_rfc4648::decode(b64_request_code);
|
||||
if (request_code.size() != 256) {
|
||||
throw ::nkg::exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Broken request code. %zu", request_code.size()));
|
||||
}
|
||||
|
||||
u8_request_info.resize((cipher.bits() + 7) / 8);
|
||||
u8_request_info.resize(cipher.private_decrypt(request_code.data(), request_code.size(), u8_request_info.data(), RSA_PKCS1_PADDING));
|
||||
|
||||
std::cout << "[*] Request Info:" << std::endl;
|
||||
std::cout << u8_request_info << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
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);
|
||||
|
||||
//
|
||||
// Begin to parse
|
||||
//
|
||||
json.Parse(u8_request_info.c_str());
|
||||
//
|
||||
// Remove "Platform" info
|
||||
//
|
||||
json.RemoveMember("P");
|
||||
//
|
||||
// Set "Name" info
|
||||
//
|
||||
N_Key.SetString("N", 1);
|
||||
N_Value.SetString(u8_username.c_str(), static_cast<rapidjson::SizeType>(u8_username.length()));
|
||||
//
|
||||
// Set "Organization" info
|
||||
//
|
||||
O_Key.SetString("O", 1);
|
||||
O_Value.SetString(u8_organization.c_str(), static_cast<rapidjson::SizeType>(u8_organization.length()));
|
||||
//
|
||||
// Set "Time" info
|
||||
//
|
||||
T_Key.SetString("T", 1);
|
||||
T_Value.SetUint(static_cast<unsigned int>(std::time(nullptr)));
|
||||
//
|
||||
// Add "Name", "Organization" and "Time"
|
||||
//
|
||||
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) {
|
||||
throw ::nkg::exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Response Info is too long.");
|
||||
}
|
||||
|
||||
u8_response_info.assign(buffer.GetString(), buffer.GetSize());
|
||||
|
||||
std::cout << "[*] Response Info:" << std::endl;
|
||||
std::cout << u8_response_info << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
response_code.resize((cipher.bits() + 7) / 8);
|
||||
response_code.resize(cipher.private_encrypt(u8_response_info.data(), u8_response_info.size(), response_code.data(), RSA_PKCS1_PADDING));
|
||||
|
||||
b64_response_code = base64_rfc4648::encode(response_code);
|
||||
|
||||
std::cout << "[*] Activation Code:" << std::endl;
|
||||
std::cout << b64_response_code << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void GenerateLicenseBinary(const rsa_cipher& cipher, const navicat_serial_generator& sn_generator) {
|
||||
std::string u8_serial_number = sn_generator.serial_number();
|
||||
|
||||
std::string u8_username;
|
||||
std::string u8_organization;
|
||||
|
||||
std::string u8_response_info;
|
||||
std::vector<uint8_t> response_code;
|
||||
|
||||
std::cout << "[*] Your name: ";
|
||||
if (!std::getline(std::cin, u8_username)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
}
|
||||
|
||||
std::cout << "[*] Your organization: ";
|
||||
if (!std::getline(std::cin, u8_organization)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
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::Value K_Key;
|
||||
rapidjson::Value K_Value;
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
|
||||
json.Parse("{}");
|
||||
K_Key.SetString("K", 1);
|
||||
K_Value.SetString(u8_serial_number.c_str(), static_cast<rapidjson::SizeType>(u8_serial_number.length()));
|
||||
N_Key.SetString("N", 1);
|
||||
N_Value.SetString(u8_username.c_str(), static_cast<rapidjson::SizeType>(u8_username.length()));
|
||||
O_Key.SetString("O", 1);
|
||||
O_Value.SetString(u8_organization.c_str(), static_cast<rapidjson::SizeType>(u8_organization.length()));
|
||||
T_Key.SetString("T", 1);
|
||||
T_Value.SetUint(static_cast<unsigned int>(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) {
|
||||
throw ::nkg::exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Response Info is too long.");
|
||||
}
|
||||
|
||||
u8_response_info.assign(buffer.GetString(), buffer.GetSize());
|
||||
|
||||
std::cout << "[*] Response Info:" << std::endl;
|
||||
std::cout << u8_response_info << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
response_code.resize((cipher.bits() + 7) / 8);
|
||||
response_code.resize(cipher.private_encrypt(u8_response_info.data(), u8_response_info.size(), response_code.data(), RSA_PKCS1_PADDING));
|
||||
|
||||
resource_wrapper license_file{ resource_traits::unix_os::file_descriptor{}, open("license_file", O_WRONLY | O_CREAT) };
|
||||
if (!license_file.is_valid()) {
|
||||
throw exceptions::unix_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), errno, u8"open failed.");
|
||||
}
|
||||
|
||||
if (write(license_file.get(), response_code.data(), response_code.size()) < 0) {
|
||||
throw exceptions::unix_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), errno, u8"write failed.");
|
||||
}
|
||||
|
||||
std::cout << "[+] license_file has been generated." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
122
navicat-keygen/base32_rfc4648.cpp
Normal file
122
navicat-keygen/base32_rfc4648.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "base32_rfc4648.hpp"
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\base32_rfc4648.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
char base32_rfc4648::symbol(alphabet_index_t idx) {
|
||||
return alphabet[idx];
|
||||
}
|
||||
|
||||
base32_rfc4648::alphabet_index_t base32_rfc4648::reverse_symbol(char c) {
|
||||
if ('A' <= c && c <= 'Z') {
|
||||
return c - 'A';
|
||||
} else if ('2' <= c && c <= '7') {
|
||||
return c - '2' + 26;
|
||||
} else {
|
||||
throw decoding_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Non-base32 digit is found.");
|
||||
}
|
||||
}
|
||||
|
||||
std::string base32_rfc4648::encode(const std::vector<uint8_t>& data) {
|
||||
return encode(data.data(), data.size());
|
||||
}
|
||||
|
||||
std::string base32_rfc4648::encode(const void* data_ptr, size_t data_size) {
|
||||
std::string retval;
|
||||
|
||||
if (data_size) {
|
||||
retval.reserve((data_size * 8 + 4) / 5);
|
||||
|
||||
auto p = reinterpret_cast<const uint8_t*>(data_ptr);
|
||||
alphabet_index_t left_bits = 0;
|
||||
alphabet_index_t bit_buffer = 0;
|
||||
for (size_t i = 0; i < data_size; ++i) {
|
||||
bit_buffer = (bit_buffer << 8) | p[i];
|
||||
left_bits += 8;
|
||||
|
||||
while (left_bits >= 5) {
|
||||
alphabet_index_t idx = (bit_buffer >> (left_bits - 5)) & 0x1f;
|
||||
retval.push_back(symbol(idx));
|
||||
left_bits -= 5;
|
||||
}
|
||||
}
|
||||
|
||||
if (left_bits > 0) {
|
||||
alphabet_index_t idx = (bit_buffer << (5 - left_bits)) & 0x1f;
|
||||
retval.push_back(symbol(idx));
|
||||
}
|
||||
|
||||
switch (data_size % 5) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
retval.append(6, padding_character);
|
||||
break;
|
||||
case 2:
|
||||
retval.append(4, padding_character);
|
||||
break;
|
||||
case 3:
|
||||
retval.append(3, padding_character);
|
||||
break;
|
||||
case 4:
|
||||
retval.append(1, padding_character);
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> base32_rfc4648::decode(std::string_view b32_string) {
|
||||
if (b32_string.length() % 8 == 0) {
|
||||
std::vector<uint8_t> retval;
|
||||
|
||||
size_t count_of_padding = std::distance(b32_string.crbegin(), std::find_if_not(b32_string.crbegin(), b32_string.crend(), [](char c) -> bool { return c == padding_character; }));
|
||||
switch (count_of_padding) {
|
||||
case 1:
|
||||
retval.reserve(b32_string.length() / 8 * 5 - (5 - 4));
|
||||
break;
|
||||
case 3:
|
||||
retval.reserve(b32_string.length() / 8 * 5 - (5 - 3));
|
||||
break;
|
||||
case 4:
|
||||
retval.reserve(b32_string.length() / 8 * 5 - (5 - 2));
|
||||
break;
|
||||
case 6:
|
||||
retval.reserve(b32_string.length() / 8 * 5 - (5 - 1));
|
||||
break;
|
||||
default:
|
||||
throw decoding_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Incorrect padding");
|
||||
}
|
||||
|
||||
size_t count_of_encoded = b32_string.length() - count_of_padding;
|
||||
|
||||
alphabet_index_t left_bits = 0;
|
||||
alphabet_index_t bit_buffer = 0;
|
||||
for (size_t i = 0; i < count_of_encoded; ++i) {
|
||||
bit_buffer = (bit_buffer << 5) | reverse_symbol(b32_string[i]);
|
||||
left_bits += 5;
|
||||
|
||||
while (left_bits >= 8) {
|
||||
auto val = static_cast<uint8_t>((bit_buffer >> (left_bits - 8)) & 0xff);
|
||||
retval.push_back(val);
|
||||
left_bits -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
} else {
|
||||
throw decoding_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Incorrect padding");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
31
navicat-keygen/base32_rfc4648.hpp
Normal file
31
navicat-keygen/base32_rfc4648.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "exception.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
struct base32_rfc4648 {
|
||||
using alphabet_index_t = size_t;
|
||||
|
||||
static constexpr const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
static constexpr const char padding_character = '=';
|
||||
|
||||
class decoding_error : public ::nkg::exception {
|
||||
public:
|
||||
decoding_error(std::string_view file, int line, std::string_view message) noexcept :
|
||||
::nkg::exception(file, line, message) {}
|
||||
};
|
||||
|
||||
static char symbol(alphabet_index_t idx);
|
||||
|
||||
static alphabet_index_t reverse_symbol(char c);
|
||||
|
||||
static std::string encode(const std::vector<uint8_t>& data);
|
||||
|
||||
static std::string encode(const void* data_ptr, size_t data_size);
|
||||
|
||||
static std::vector<uint8_t> decode(std::string_view b32_string);
|
||||
};
|
||||
|
||||
}
|
||||
99
navicat-keygen/base64_rfc4648.cpp
Normal file
99
navicat-keygen/base64_rfc4648.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#include "base64_rfc4648.hpp"
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "resource_wrapper.hpp"
|
||||
#include "resource_traits/openssl/bio.hpp"
|
||||
#include "resource_traits/openssl/bio_chain.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\base64_rfc4648.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
std::string base64_rfc4648::encode(const std::vector<std::uint8_t>& data) {
|
||||
resource_wrapper bio_b64{ resource_traits::openssl::bio_chain{}, BIO_new(BIO_f_base64()) };
|
||||
if (!bio_b64.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
|
||||
BIO_set_flags(bio_b64.get(), BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
resource_wrapper bio_memory{ resource_traits::openssl::bio{}, BIO_new(BIO_s_mem()) };
|
||||
if (!bio_memory.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
|
||||
BIO_push(bio_b64.get(), bio_memory.get());
|
||||
|
||||
for (size_t written_size = 0, left_size = data.size(); left_size != 0;) {
|
||||
int size_to_write = static_cast<int>(std::min(left_size, static_cast<size_t>(INT_MAX)));
|
||||
|
||||
int r = BIO_write(bio_b64.get(), data.data() + written_size, size_to_write);
|
||||
if (r > 0) {
|
||||
written_size += r;
|
||||
left_size -= r;
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_write failed.");
|
||||
}
|
||||
}
|
||||
|
||||
BIO_flush(bio_b64.get());
|
||||
|
||||
const char* pch = nullptr;
|
||||
long lch = BIO_get_mem_data(bio_memory.get(), &pch);
|
||||
|
||||
bio_memory.discard(); // the bio_chain `bio_b64` will free it
|
||||
|
||||
return std::string(pch, lch);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> base64_rfc4648::decode(std::string_view b64_string) {
|
||||
resource_wrapper bio_b64{ resource_traits::openssl::bio_chain{}, BIO_new(BIO_f_base64()) };
|
||||
if (!bio_b64.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
|
||||
BIO_set_flags(bio_b64.get(), BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
resource_wrapper bio_memory{ resource_traits::openssl::bio{}, BIO_new(BIO_s_mem()) };
|
||||
if (!bio_memory.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
|
||||
BIO_push(bio_b64.get(), bio_memory.get());
|
||||
|
||||
for (size_t written_length = 0, left_length = b64_string.length(); left_length != 0;) {
|
||||
int length_to_write = static_cast<int>(std::min(left_length, static_cast<size_t>(INT_MAX)));
|
||||
|
||||
int r = BIO_write(bio_memory.get(), b64_string.data() + written_length, length_to_write);
|
||||
if (r > 0) {
|
||||
written_length += r;
|
||||
left_length -= r;
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_write failed.");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> retval;
|
||||
retval.reserve(b64_string.length() * 3 / 4 + 1);
|
||||
|
||||
for (uint8_t buf[256];;) {
|
||||
auto len = BIO_read(bio_b64.get(), buf, sizeof(buf));
|
||||
if (len > 0) {
|
||||
retval.insert(retval.end(), buf, buf + len);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bio_memory.discard(); // the bio_chain `bio_b64` will free it
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
20
navicat-keygen/base64_rfc4648.hpp
Normal file
20
navicat-keygen/base64_rfc4648.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "exception.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
struct base64_rfc4648 {
|
||||
class backend_error : public ::nkg::exception {
|
||||
public:
|
||||
backend_error(std::string_view file, int line, std::string_view message) noexcept :
|
||||
::nkg::exception(file, line, message) {}
|
||||
};
|
||||
|
||||
static std::string encode(const std::vector<std::uint8_t>& data);
|
||||
|
||||
static std::vector<uint8_t> decode(std::string_view str_b64);
|
||||
};
|
||||
|
||||
}
|
||||
123
navicat-keygen/main.cpp
Normal file
123
navicat-keygen/main.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <functional>
|
||||
|
||||
#include "exception.hpp"
|
||||
#include "exceptions/operation_canceled_exception.hpp"
|
||||
|
||||
#include "base64_rfc4648.hpp"
|
||||
#include "navicat_serial_generator.hpp"
|
||||
#include "rsa_cipher.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\wmain.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
using fnCollectInformation = std::function<navicat_serial_generator()>;
|
||||
using fnGenerateLicense = std::function<void(const rsa_cipher& cipher, const navicat_serial_generator& generator)>;
|
||||
|
||||
navicat_serial_generator CollectInformationNormal();
|
||||
navicat_serial_generator CollectInformationAdvanced();
|
||||
void GenerateLicenseText(const rsa_cipher& cipher, const navicat_serial_generator& sn_generator);
|
||||
void GenerateLicenseBinary(const rsa_cipher& cipher, const navicat_serial_generator& sn_generator);
|
||||
}
|
||||
|
||||
void welcome() {
|
||||
puts("***************************************************");
|
||||
puts("* navicat-keygen by @DoubleLabyrinth *");
|
||||
puts("* version: 16.0.7.0 *");
|
||||
puts("***************************************************");
|
||||
puts("");
|
||||
}
|
||||
|
||||
void help() {
|
||||
puts("Usage:");
|
||||
puts(" navicat-keygen.exe <-bin|-text> [-adv] <RSA-2048 Private Key File>");
|
||||
puts("");
|
||||
puts(" <-bin|-text> Specify \"-bin\" to generate \"license_file\" used by Navicat 11.");
|
||||
puts(" Specify \"-text\" to generate base64-encoded activation code.");
|
||||
puts(" This parameter must be specified.");
|
||||
puts("");
|
||||
puts(" [-adv] Enable advance mode.");
|
||||
puts(" This parameter is optional.");
|
||||
puts("");
|
||||
puts(" <RSA-2048 Private Key File> A path to an RSA-2048 private key file.");
|
||||
puts(" This parameter must be specified.");
|
||||
puts("");
|
||||
puts("Example:");
|
||||
puts(" navicat-keygen.exe -text .\\RegPrivateKey.pem");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
welcome();
|
||||
|
||||
if (argc == 3 || argc == 4) {
|
||||
nkg::fnCollectInformation lpfnCollectInformation;
|
||||
nkg::fnGenerateLicense lpfnGenerateLicense;
|
||||
|
||||
if (strcmp(argv[1], "-bin") == 0) {
|
||||
lpfnGenerateLicense = nkg::GenerateLicenseBinary;
|
||||
} else if (strcmp(argv[1], "-text") == 0) {
|
||||
lpfnGenerateLicense = nkg::GenerateLicenseText;
|
||||
} else {
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc == 4) {
|
||||
if (strcmp(argv[2], "-adv") == 0) {
|
||||
lpfnCollectInformation = nkg::CollectInformationAdvanced;
|
||||
} else {
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
lpfnCollectInformation = nkg::CollectInformationNormal;
|
||||
}
|
||||
|
||||
try {
|
||||
nkg::rsa_cipher cipher;
|
||||
|
||||
cipher.import_private_key_file(argv[argc - 1]);
|
||||
if (cipher.bits() != 2048) {
|
||||
throw nkg::exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"RSA key length mismatches.")
|
||||
.push_hint(u8"You must provide an RSA key whose modulus length is 2048 bits.");
|
||||
}
|
||||
|
||||
auto sn_generator = lpfnCollectInformation();
|
||||
sn_generator.generate();
|
||||
|
||||
puts("[*] Serial number:");
|
||||
puts(sn_generator.serial_number_formatted().c_str());
|
||||
puts("");
|
||||
|
||||
lpfnGenerateLicense(cipher, sn_generator);
|
||||
|
||||
return 0;
|
||||
} catch (nkg::exceptions::operation_canceled_exception&) {
|
||||
return -1;
|
||||
} catch (nkg::exception& e) {
|
||||
printf("[-] %s:%d ->\n", e.source_file().c_str(), e.source_line());
|
||||
printf(" %s\n", e.custom_message().c_str());
|
||||
|
||||
if (e.error_code_exists()) {
|
||||
printf(" %s (0x%zx)\n", e.error_string().c_str(), e.error_code());
|
||||
}
|
||||
|
||||
for (auto& hint : e.hints()) {
|
||||
printf(" Hints: %s\n", hint.c_str());
|
||||
}
|
||||
|
||||
return -1;
|
||||
} catch (std::exception& e) {
|
||||
printf("[-] %s\n", e.what());
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
160
navicat-keygen/navicat_serial_generator.cpp
Normal file
160
navicat-keygen/navicat_serial_generator.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
#include "navicat_serial_generator.hpp"
|
||||
#include <fmt/format.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <algorithm>
|
||||
#include "base32_rfc4648.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\navicat_serial_generator.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
char navicat_serial_generator::_replace_confusing_chars(char c) {
|
||||
if (c == 'I') {
|
||||
return '8';
|
||||
} else if (c == 'O') {
|
||||
return '9';
|
||||
} else {
|
||||
return c;
|
||||
}
|
||||
};
|
||||
|
||||
navicat_serial_generator::navicat_serial_generator() noexcept :
|
||||
m_data{ 0x68 , 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32 }, m_des_key{} {}
|
||||
|
||||
void navicat_serial_generator::set_software_language(navicat_software_language lang) noexcept {
|
||||
switch (lang) {
|
||||
case navicat_software_language::English:
|
||||
m_data[5] = 0xAC; // Must be 0xAC for English version.
|
||||
m_data[6] = 0x88; // Must be 0x88 for English version.
|
||||
break;
|
||||
case navicat_software_language::SimplifiedChinese:
|
||||
m_data[5] = 0xCE; // Must be 0xCE for Simplified Chinese version.
|
||||
m_data[6] = 0x32; // Must be 0x32 for Simplified Chinese version.
|
||||
break;
|
||||
case navicat_software_language::TraditionalChinese:
|
||||
m_data[5] = 0xAA; // Must be 0xAA for Traditional Chinese version.
|
||||
m_data[6] = 0x99; // Must be 0x99 for Traditional Chinese version.
|
||||
break;
|
||||
case navicat_software_language::Japanese:
|
||||
m_data[5] = 0xAD; // Must be 0xAD for Japanese version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x82; // Must be 0x82 for Japanese version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case navicat_software_language::Polish:
|
||||
m_data[5] = 0xBB; // Must be 0xBB for Polish version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x55; // Must be 0x55 for Polish version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case navicat_software_language::Spanish:
|
||||
m_data[5] = 0xAE; // Must be 0xAE for Spanish version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x10; // Must be 0x10 for Spanish version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case navicat_software_language::French:
|
||||
m_data[5] = 0xFA; // Must be 0xFA for French version. Discoverer: @Deltafox79
|
||||
m_data[6] = 0x20; // Must be 0x20 for French version. Discoverer: @Deltafox79
|
||||
break;
|
||||
case navicat_software_language::German:
|
||||
m_data[5] = 0xB1; // Must be 0xB1 for German version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x60; // Must be 0x60 for German version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case navicat_software_language::Korean:
|
||||
m_data[5] = 0xB5; // Must be 0xB5 for Korean version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x60; // Must be 0x60 for Korean version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case navicat_software_language::Russian:
|
||||
m_data[5] = 0xEE; // Must be 0xB5 for Russian version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x16; // Must be 0x60 for Russian version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case navicat_software_language::Portuguese:
|
||||
m_data[5] = 0xCD; // Must be 0xCD for Portuguese version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x49; // Must be 0x49 for Portuguese version. Discoverer: @dragonflylee
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
void navicat_serial_generator::set_software_language(uint8_t lang_sig0, uint8_t lang_sig1) noexcept {
|
||||
m_data[5] = lang_sig0;
|
||||
m_data[6] = lang_sig1;
|
||||
}
|
||||
|
||||
void navicat_serial_generator::set_software_type(navicat_software_type software_type) noexcept {
|
||||
switch (software_type) {
|
||||
case navicat_software_type::DataModeler:
|
||||
m_data[7] = 0x84;
|
||||
break;
|
||||
case navicat_software_type::Premium:
|
||||
m_data[7] = 0x65;
|
||||
break;
|
||||
case navicat_software_type::MySQL:
|
||||
m_data[7] = 0x68;
|
||||
break;
|
||||
case navicat_software_type::PostgreSQL:
|
||||
m_data[7] = 0x6C;
|
||||
break;
|
||||
case navicat_software_type::Oracle:
|
||||
m_data[7] = 0x70;
|
||||
break;
|
||||
case navicat_software_type::SQLServer:
|
||||
m_data[7] = 0x74;
|
||||
break;
|
||||
case navicat_software_type::SQLite:
|
||||
m_data[7] = 0x78;
|
||||
break;
|
||||
case navicat_software_type::MariaDB:
|
||||
m_data[7] = 0x7C;
|
||||
break;
|
||||
case navicat_software_type::MongoDB:
|
||||
m_data[7] = 0x80;
|
||||
break;
|
||||
case navicat_software_type::ReportViewer:
|
||||
m_data[7] = 0xb;
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
void navicat_serial_generator::set_software_type(uint8_t software_type_sig) noexcept {
|
||||
m_data[7] = software_type_sig;
|
||||
}
|
||||
|
||||
void navicat_serial_generator::set_software_version(int ver) {
|
||||
if (11 <= ver && ver < 16) {
|
||||
m_data[8] = static_cast<std::uint8_t>((ver << 4) | (m_data[8] & 0x0f));
|
||||
memcpy(m_des_key, s_des_key0, sizeof(s_des_key0));
|
||||
} else if (16 <= ver && ver < 32) {
|
||||
m_data[8] = static_cast<std::uint8_t>(((ver - 16) << 4) | (m_data[8] & 0x0f));
|
||||
memcpy(m_des_key, s_des_key1, sizeof(s_des_key1));
|
||||
} else {
|
||||
throw version_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Invalid navicat version.");
|
||||
}
|
||||
}
|
||||
|
||||
void navicat_serial_generator::generate() {
|
||||
RAND_bytes(m_data + 2, 3);
|
||||
|
||||
DES_key_schedule schedule;
|
||||
DES_set_key_unchecked(&m_des_key, &schedule);
|
||||
DES_ecb_encrypt(reinterpret_cast<const_DES_cblock*>(m_data + 2), reinterpret_cast<const_DES_cblock*>(m_data + 2), &schedule, DES_ENCRYPT);
|
||||
|
||||
m_serial_number = base32_rfc4648::encode(m_data, sizeof(m_data));
|
||||
std::transform(m_serial_number.begin(), m_serial_number.end(), m_serial_number.begin(), _replace_confusing_chars);
|
||||
|
||||
std::string_view sn = m_serial_number;
|
||||
m_serial_number_formatted = fmt::format("{}-{}-{}-{}", sn.substr(0, 4), sn.substr(4, 4), sn.substr(8, 4), sn.substr(12, 4));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& navicat_serial_generator::serial_number() const noexcept {
|
||||
return m_serial_number;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& navicat_serial_generator::serial_number_formatted() const noexcept {
|
||||
return m_serial_number_formatted;
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
75
navicat-keygen/navicat_serial_generator.hpp
Normal file
75
navicat-keygen/navicat_serial_generator.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <openssl/des.h>
|
||||
#include "exception.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
enum class navicat_software_language {
|
||||
English,
|
||||
SimplifiedChinese,
|
||||
TraditionalChinese,
|
||||
Japanese,
|
||||
Polish,
|
||||
Spanish,
|
||||
French,
|
||||
German,
|
||||
Korean,
|
||||
Russian,
|
||||
Portuguese
|
||||
};
|
||||
|
||||
enum class navicat_software_type {
|
||||
DataModeler,
|
||||
Premium,
|
||||
MySQL,
|
||||
PostgreSQL,
|
||||
Oracle,
|
||||
SQLServer,
|
||||
SQLite,
|
||||
MariaDB,
|
||||
MongoDB,
|
||||
ReportViewer
|
||||
};
|
||||
|
||||
class navicat_serial_generator {
|
||||
public:
|
||||
class version_error : public ::nkg::exception {
|
||||
public:
|
||||
version_error(std::string_view file, int line, std::string_view message) noexcept :
|
||||
::nkg::exception(file, line, message) {}
|
||||
};
|
||||
|
||||
private:
|
||||
static inline const DES_cblock s_des_key0 = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
|
||||
static inline const DES_cblock s_des_key1 = { 0xE9, 0x7F, 0xB0, 0x60, 0x77, 0x45, 0x90, 0xAE };
|
||||
|
||||
uint8_t m_data[10];
|
||||
DES_cblock m_des_key;
|
||||
std::string m_serial_number;
|
||||
std::string m_serial_number_formatted;
|
||||
|
||||
static char _replace_confusing_chars(char c);
|
||||
|
||||
public:
|
||||
navicat_serial_generator() noexcept;
|
||||
|
||||
void set_software_language(navicat_software_language lang) noexcept;
|
||||
void set_software_language(uint8_t lang_sig0, uint8_t lang_sig1) noexcept;
|
||||
|
||||
void set_software_type(navicat_software_type software_type) noexcept;
|
||||
void set_software_type(uint8_t software_type_sig) noexcept;
|
||||
|
||||
void set_software_version(int Version);
|
||||
|
||||
void generate();
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& serial_number() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& serial_number_formatted() const noexcept;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user