如何知道Navicat Premium保存的密码
前几天需要用到一个数据库的密码,但是却无论如何也找不到之前存在哪了(顺便说下,把密码写着纸上或是某个文件里实在是个蠢主意)。想起之前看到过一篇关于navicat是如何加密的文章 ,于是找来翻看,并成功把密码复现。为了再稍微深入了解下那篇文章,所以也就有了这篇文章。
不同数据类型保存的windows注册表路径位置
Database Type | Path |
---|---|
MySQL | HKEYCURRENTUSER\\Software\\PremiumSoft\\Navicat\\Servers\\`<your connection name>` |
MariaDB | HKEYCURRENTUSER\\Software\\PremiumSoft\\NavicatMARIADB\\Servers\\`<your connection name>` |
MongoDB | HKEYCURRENTUSER\\Software\\PremiumSoft\\NavicatMONGODB\\Servers\\`<your connection name>` |
Microsoft SQL | HKEYCURRENTUSER\\Software\\PremiumSoft\\NavicatMSSQL\\Servers\\`<your connection name>` |
Oracle | HKEYCURRENTUSER\\Software\\PremiumSoft\\NavicatOra\\Servers\\`<your connection name>` |
PostgreSQL | HKEYCURRENTUSER\\Software\\PremiumSoft\\NavicatPG\\Servers\\`<your connection name>` |
SQLite | HKEYCURRENTUSER\\Software\\PremiumSoft\\NavicatSQLite\\Servers\\`<your connection name>` |
如何解密
作者写了个python脚本,不过你需要确保安装了Python3和依赖模块。
模块安装
pip3 install pycryptodome
加解密脚本
#!/usr/bin/env python3 import sys from Crypto.Hash import SHA1 from Crypto.Cipher import AES, Blowfish class Navicat11Crypto: @staticmethod def _XorBytes(a : bytes, b : bytes): return bytes([ i ^ j for i, j in zip(a, b) ]) def __init__(self, Key = b'3DC5CA39'): self._CipherKey = SHA1.new(Key).digest() self._Cipher = Blowfish.new(self._CipherKey, Blowfish.MODE_ECB) self._IV = self._Cipher.encrypt(b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF') def EncryptString(self, s : str): if type(s) != str: raise TypeError('Parameter s must be a str.') else: plaintext = s.encode('utf-8') ciphertext = b'' cv = self._IV full_round, left_length = divmod(len(plaintext), 8) for i in range(0, full_round * 8, 8): t = Navicat11Crypto._XorBytes(plaintext[i:i + 8], cv) t = self._Cipher.encrypt(t) cv = Navicat11Crypto._XorBytes(cv, t) ciphertext += t if left_length != 0: cv = self._Cipher.encrypt(cv) ciphertext += Navicat11Crypto._XorBytes(plaintext[8 * full_round:], cv[:left_length]) return ciphertext.hex().upper() def DecryptString(self, s : str): if type(s) != str: raise TypeError('Parameter s must be str.') else: plaintext = b'' ciphertext = bytes.fromhex(s) cv = self._IV full_round, left_length = divmod(len(ciphertext), 8) for i in range(0, full_round * 8, 8): t = self._Cipher.decrypt(ciphertext[i:i + 8]) t = Navicat11Crypto._XorBytes(t, cv) plaintext += t cv = Navicat11Crypto._XorBytes(cv, ciphertext[i:i + 8]) if left_length != 0: cv = self._Cipher.encrypt(cv) plaintext += Navicat11Crypto._XorBytes(ciphertext[8 * full_round:], cv[:left_length]) return plaintext.decode('utf-8') class Navicat12Crypto(Navicat11Crypto): @staticmethod def _Pkcs7Padding(Data : bytes, BlockSize : int): return Data + (BlockSize - len(Data) % BlockSize) * bytes([BlockSize - len(Data) % BlockSize]) @staticmethod def _Pkcs7Unpadding(Data): return Data[0:-Data[-1]] def __init__(self): super().__init__() def EncryptStringForNCX(self, s : str): cipher = AES.new(b'libcckeylibcckey', AES.MODE_CBC, iv = b'libcciv libcciv ') padded_plaintext = Navicat12Crypto._Pkcs7Padding(s.encode('utf-8'), AES.block_size) return cipher.encrypt(padded_plaintext).hex().upper() def DecryptStringForNCX(self, s : str): cipher = AES.new(b'libcckeylibcckey', AES.MODE_CBC, iv = b'libcciv libcciv ') padded_plaintext = cipher.decrypt(bytes.fromhex(s)) return Navicat12Crypto._Pkcs7Unpadding(padded_plaintext).decode('utf-8') if __name__ == '__main__': def Help(): print('Usage:') print(' NavicatCrypto.py <enc|dec> [-ncx] <plaintext|ciphertext>') print('') print(' <enc|dec> "enc" for encryption, "dec" for decryption.') print(' This parameter must be specified.') print('') print(' [-ncx] Indicate that plaintext/ciphertext is') print(' prepared for/exported from NCX file.') print(' This parameter is optional.') print('') print(' <plaintext|ciphertext> Plaintext string or ciphertext string.') print(' NOTICE: Ciphertext string must be a hex string.') print(' This parameter must be specified.') print('') def Main(argc : int, argv : list): if argc == 3: if argv[1].lower() == 'enc': print(Navicat11Crypto().EncryptString(argv[2])) elif argv[1].lower() == 'dec': print(Navicat11Crypto().DecryptString(argv[2])) else: Help() return -1 elif argc == 4: if argv[1].lower() == 'enc' and argv[2].lower() == '-ncx': print(Navicat12Crypto().EncryptStringForNCX(argv[3])) elif argv[1].lower() == 'dec' and argv[2].lower() == '-ncx': print(Navicat12Crypto().DecryptStringForNCX(argv[3])) else: Help() return -1 else: Help() return 0 exit(Main(len(sys.argv), sys.argv))
也可以直接下载该脚本,记得有时间给作者点个赞哟。
wget https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password/blob/master/python3/NavicatCipher.py
如何使用呢? 把下面dec后面的字符串换成你注册表里Pwd里的,然后执行下面命令
./NavicatCipher.py dec 0EA71F51DD37BFB60CCBA219BE3A
Comments:
Email questions, comments, and corrections to hi@smartisan.dev.
Submissions may appear publicly on this website, unless requested otherwise in your email.