NavicatCrypto.hpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #pragma once
  2. #include <openssl/crypto.h>
  3. #include <openssl/blowfish.h>
  4. #include <openssl/sha.h>
  5. #include <string>
  6. #include <stdexcept>
  7. class Navicat11Crypto {
  8. protected:
  9. using BlockType = uint8_t[BF_BLOCK];
  10. BF_KEY _BlowfishKey;
  11. template<bool __UpperCase = true>
  12. static void _BytesToHex(const void* src, size_t len, char* dst) noexcept {
  13. auto pb_src = reinterpret_cast<const uint8_t*>(src);
  14. for (size_t i = 0; i < len; ++i) {
  15. char h = pb_src[i] >> 4;
  16. char l = pb_src[i] & 0x0F;
  17. if constexpr (__UpperCase) {
  18. h += h >= 10 ? 'A' - 10 : '0';
  19. l += l >= 10 ? 'A' - 10 : '0';
  20. } else {
  21. h += h >= 10 ? 'a' - 10 : '0';
  22. l += l >= 10 ? 'a' - 10 : '0';
  23. }
  24. dst[2 * i] = h;
  25. dst[2 * i + 1] = l;
  26. }
  27. }
  28. static void _HexToBytes(const char* src, size_t len, void* dst) {
  29. auto pb_dst = reinterpret_cast<uint8_t*>(dst);
  30. for (size_t i = 0; i < len; i += 2) {
  31. uint8_t h = src[i];
  32. uint8_t l = src[i + 1];
  33. if ('0' <= h && h <= '9') {
  34. h -= '0';
  35. } else if ('A' <= h && h <= 'F') {
  36. h -= 'A';
  37. } else if ('a' <= h && h <= 'f') {
  38. h -= 'a';
  39. } else {
  40. throw std::invalid_argument("Non-hex character detected.");
  41. }
  42. if ('0' <= l && l <= '9') {
  43. l -= '0';
  44. } else if ('A' <= l && l <= 'F') {
  45. l -= 'A';
  46. } else if ('a' <= l && l <= 'f') {
  47. l -= 'a';
  48. } else {
  49. throw std::invalid_argument("Non-hex character detected.");
  50. }
  51. pb_dst[i / 2] = (h << 4) ^ l;
  52. }
  53. }
  54. static void _XorBlock(BlockType& a, const BlockType& b) noexcept {
  55. reinterpret_cast<uint64_t&>(a) ^= reinterpret_cast<const uint64_t&>(b);
  56. }
  57. [[nodiscard]]
  58. std::string _EncryptString(const void* lpPlaintext, size_t cbPlaintext) const {
  59. std::string Ciphertext;
  60. if (cbPlaintext) {
  61. Ciphertext.resize(2 * cbPlaintext);
  62. alignas(sizeof(BlockType)) BlockType CV = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  63. alignas(sizeof(BlockType)) BlockType Block;
  64. auto lpPlaintextBlock = reinterpret_cast<const uint8_t*>(lpPlaintext);
  65. auto lpCiphertextHexBlock = Ciphertext.data();
  66. auto BlockCount = cbPlaintext / BF_BLOCK;
  67. BF_ecb_encrypt(CV, CV, &_BlowfishKey, BF_ENCRYPT);
  68. for (size_t i = 0; i < BlockCount; ++i, lpPlaintextBlock += sizeof(BlockType), lpCiphertextHexBlock += 2 * sizeof(BlockType)) {
  69. memcpy(Block, lpPlaintextBlock, sizeof(BlockType));
  70. _XorBlock(Block, CV);
  71. BF_ecb_encrypt(Block, Block, &_BlowfishKey, BF_ENCRYPT);
  72. _XorBlock(CV, Block);
  73. _BytesToHex(Block, sizeof(Block), lpCiphertextHexBlock);
  74. }
  75. auto LeftByteCount = cbPlaintext % sizeof(BlockType);
  76. if (LeftByteCount) {
  77. BF_ecb_encrypt(CV, CV, &_BlowfishKey, BF_ENCRYPT);
  78. for (size_t i = 0; i < LeftByteCount; ++i) {
  79. CV[i] ^= lpPlaintextBlock[i];
  80. }
  81. _BytesToHex(CV, LeftByteCount, lpCiphertextHexBlock);
  82. }
  83. }
  84. return Ciphertext;
  85. }
  86. [[nodiscard]]
  87. std::string _DecryptString(const char* lpCiphertext, size_t cbCiphertext) const {
  88. std::string Plaintext;
  89. if (cbCiphertext) {
  90. if (cbCiphertext % 2) {
  91. throw std::invalid_argument("Ciphertext is not a hex string.");
  92. }
  93. Plaintext.resize(cbCiphertext / 2);
  94. alignas(sizeof(BlockType)) BlockType CV = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  95. alignas(sizeof(BlockType)) BlockType Block;
  96. auto lpPlaintextBlock = Plaintext.data();
  97. auto lpCiphertextHexBlock = lpCiphertext;
  98. auto BlockCount = cbCiphertext / (2 * sizeof(BlockType));
  99. BF_ecb_encrypt(CV, CV, &_BlowfishKey, BF_ENCRYPT);
  100. for (size_t i = 0; i < BlockCount; ++i, lpPlaintextBlock += sizeof(BlockType), lpCiphertextHexBlock += 2 * sizeof(BlockType)) {
  101. alignas(sizeof(BlockType)) BlockType CiphertextBlock;
  102. _HexToBytes(lpCiphertextHexBlock, 2 * sizeof(BlockType), CiphertextBlock);
  103. memcpy(Block, CiphertextBlock, sizeof(BlockType));
  104. BF_ecb_encrypt(Block, Block, &_BlowfishKey, BF_DECRYPT);
  105. _XorBlock(Block, CV);
  106. _XorBlock(CV, CiphertextBlock);
  107. memcpy(lpPlaintextBlock, Block, sizeof(BlockType));
  108. }
  109. auto LeftHexCount = cbCiphertext % (2 * sizeof(BlockType));
  110. if (LeftHexCount) {
  111. _HexToBytes(lpCiphertextHexBlock, LeftHexCount, Block);
  112. BF_ecb_encrypt(CV, CV, &_BlowfishKey, BF_ENCRYPT);
  113. for (size_t i = 0; i < LeftHexCount / 2; ++i) {
  114. lpPlaintextBlock[i] = Block[i] ^ CV[i];
  115. }
  116. }
  117. }
  118. return Plaintext;
  119. }
  120. public:
  121. Navicat11Crypto() noexcept {
  122. static const uint8_t PresetKey[SHA_DIGEST_LENGTH] = {
  123. 0x42, 0xCE, 0xB2, 0x71, 0xA5, 0xE4, 0x58, 0xB7,
  124. 0x4A, 0xEA, 0x93, 0x94, 0x79, 0x22, 0x35, 0x43,
  125. 0x91, 0x87, 0x33, 0x40
  126. };
  127. BF_set_key(&_BlowfishKey, sizeof(PresetKey), PresetKey);
  128. }
  129. Navicat11Crypto(const void* lpUserKey, size_t cbUserKey) noexcept {
  130. SetKey(lpUserKey, cbUserKey);
  131. }
  132. Navicat11Crypto(const std::initializer_list<uint8_t>& UserKey) noexcept {
  133. SetKey(UserKey);
  134. }
  135. void SetKey(const void* lpUserKey, size_t cbUserKey) noexcept {
  136. uint8_t MessageDigest[SHA_DIGEST_LENGTH];
  137. BF_set_key(
  138. &_BlowfishKey,
  139. sizeof(MessageDigest),
  140. SHA1(reinterpret_cast<const uint8_t*>(lpUserKey), cbUserKey, MessageDigest)
  141. );
  142. OPENSSL_cleanse(MessageDigest, SHA_DIGEST_LENGTH);
  143. }
  144. void SetKey(const std::initializer_list<uint8_t>& UserKey) noexcept {
  145. uint8_t MessageDigest[SHA_DIGEST_LENGTH];
  146. BF_set_key(
  147. &_BlowfishKey,
  148. sizeof(MessageDigest),
  149. SHA1(UserKey.begin(), UserKey.size(), MessageDigest)
  150. );
  151. OPENSSL_cleanse(MessageDigest, SHA_DIGEST_LENGTH);
  152. }
  153. [[nodiscard]]
  154. std::string EncryptString(const std::string& Plaintext) const {
  155. return _EncryptString(Plaintext.c_str(), Plaintext.length());
  156. }
  157. [[nodiscard]]
  158. std::string DecryptString(const std::string& Ciphertext) const {
  159. return _DecryptString(Ciphertext.c_str(), Ciphertext.length());
  160. }
  161. void Clear() noexcept {
  162. OPENSSL_cleanse(&_BlowfishKey, sizeof(_BlowfishKey));
  163. }
  164. ~Navicat11Crypto() noexcept {
  165. Clear();
  166. }
  167. };