|
|
|
@@ -1,215 +1,82 @@
|
|
|
|
|
from hashlib import md5
|
|
|
|
|
import binascii
|
|
|
|
|
import hashlib
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
from tkinter import messagebox
|
|
|
|
|
from Crypto.Cipher import AES, Blowfish
|
|
|
|
|
import binascii
|
|
|
|
|
|
|
|
|
|
class NavicatPassword:
|
|
|
|
|
def __init__(self, version=12):
|
|
|
|
|
self.version = version
|
|
|
|
|
self.aes_key = b'libcckeylibcckey'
|
|
|
|
|
self.aes_iv = b'libcciv libcciv '
|
|
|
|
|
self.blow_string = '3DC5CA39'
|
|
|
|
|
self.blow_key = hashlib.sha1(self.blow_string.encode()).digest()
|
|
|
|
|
self.blow_iv = binascii.unhexlify('d9c7c3c8870d64bd')
|
|
|
|
|
self.blow_key = b'\x3D\xC5\xCA\x39'
|
|
|
|
|
self.blow_iv = b'\xD9\xC7\xC3\xC8\x87\x0D\x64\xBD'
|
|
|
|
|
|
|
|
|
|
def decrypt(self, encrypted_str):
|
|
|
|
|
try:
|
|
|
|
|
if self.version == 11:
|
|
|
|
|
return self.decrypt_eleven(encrypted_str)
|
|
|
|
|
elif self.version == 12:
|
|
|
|
|
return self.decrypt_twelve(encrypted_str)
|
|
|
|
|
else:
|
|
|
|
|
return "Unsupported version"
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return f"Decryption failed: {str(e)}"
|
|
|
|
|
if self.version == 11:
|
|
|
|
|
return self.decrypt_eleven(encrypted_str)
|
|
|
|
|
elif self.version == 12:
|
|
|
|
|
return self.decrypt_twelve(encrypted_str)
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def decrypt_eleven(self, encrypted_str):
|
|
|
|
|
encrypted_data = binascii.unhexlify(encrypted_str.lower())
|
|
|
|
|
length = len(encrypted_data)
|
|
|
|
|
rounds = length // 8
|
|
|
|
|
left_length = length % 8
|
|
|
|
|
data = binascii.unhexlify(encrypted_str.lower())
|
|
|
|
|
result = b''
|
|
|
|
|
current_vector = self.blow_iv
|
|
|
|
|
|
|
|
|
|
for i in range(rounds):
|
|
|
|
|
block = encrypted_data[i*8:(i+1)*8]
|
|
|
|
|
decrypted = self.xor_bytes(self.decrypt_block(block), current_vector)
|
|
|
|
|
current_vector = self.xor_bytes(current_vector, block)
|
|
|
|
|
result += decrypted
|
|
|
|
|
|
|
|
|
|
if left_length:
|
|
|
|
|
current_vector = self.encrypt_block(current_vector)
|
|
|
|
|
result += self.xor_bytes(encrypted_data[rounds*8:], current_vector)
|
|
|
|
|
|
|
|
|
|
return result.decode('utf-8', errors='ignore')
|
|
|
|
|
iv = self.blow_iv
|
|
|
|
|
|
|
|
|
|
for i in range(0, len(data), 8):
|
|
|
|
|
block = data[i:i+8]
|
|
|
|
|
decrypted = self.blowfish_decrypt(block)
|
|
|
|
|
result += self.xor_bytes(decrypted, iv)
|
|
|
|
|
iv = self.xor_bytes(iv, block)
|
|
|
|
|
|
|
|
|
|
return result.decode('utf-8')
|
|
|
|
|
|
|
|
|
|
def decrypt_twelve(self, encrypted_str):
|
|
|
|
|
encrypted_data = binascii.unhexlify(encrypted_str.lower())
|
|
|
|
|
cipher = self._create_aes_cipher()
|
|
|
|
|
decrypted = cipher.decrypt(encrypted_data)
|
|
|
|
|
return self._unpad(decrypted).decode('utf-8')
|
|
|
|
|
data = binascii.unhexlify(encrypted_str.lower())
|
|
|
|
|
cipher = AES.new(self.aes_key, AES.MODE_CBC, self.aes_iv)
|
|
|
|
|
return cipher.decrypt(data).decode('utf-8').rstrip('\x00')
|
|
|
|
|
|
|
|
|
|
def encrypt_block(self, block):
|
|
|
|
|
cipher = self._create_blowfish_cipher()
|
|
|
|
|
return cipher.encrypt(block)
|
|
|
|
|
def blowfish_decrypt(self, data):
|
|
|
|
|
cipher = Blowfish.new(self.blow_key, Blowfish.MODE_ECB)
|
|
|
|
|
return cipher.decrypt(data)
|
|
|
|
|
|
|
|
|
|
def decrypt_block(self, block):
|
|
|
|
|
cipher = self._create_blowfish_cipher()
|
|
|
|
|
return cipher.decrypt(block)
|
|
|
|
|
def xor_bytes(self, a, b):
|
|
|
|
|
return bytes([x ^ y for x, y in zip(a, b)])
|
|
|
|
|
|
|
|
|
|
def _create_aes_cipher(self):
|
|
|
|
|
from hashlib import md5
|
|
|
|
|
key = md5(self.aes_key).digest()
|
|
|
|
|
iv = md5(self.aes_iv).digest()[:16]
|
|
|
|
|
return self._create_cipher('AES', key, iv)
|
|
|
|
|
|
|
|
|
|
def _create_blowfish_cipher(self):
|
|
|
|
|
return self._create_cipher('BF', self.blow_key, self.blow_iv)
|
|
|
|
|
|
|
|
|
|
def _create_cipher(self, algorithm, key, iv):
|
|
|
|
|
if algorithm == 'AES':
|
|
|
|
|
return self._aes_cipher(key, iv)
|
|
|
|
|
elif algorithm == 'BF':
|
|
|
|
|
return self._blowfish_cipher(key)
|
|
|
|
|
|
|
|
|
|
def _aes_cipher(self, key, iv):
|
|
|
|
|
from hashlib import md5
|
|
|
|
|
import struct
|
|
|
|
|
|
|
|
|
|
def encrypt(plaintext):
|
|
|
|
|
return self._aes_encrypt_block(plaintext, key, iv)
|
|
|
|
|
|
|
|
|
|
def decrypt(ciphertext):
|
|
|
|
|
return self._aes_decrypt_block(ciphertext, key, iv)
|
|
|
|
|
|
|
|
|
|
return type('AESCipher', (), {
|
|
|
|
|
'encrypt': encrypt,
|
|
|
|
|
'decrypt': decrypt
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
def _blowfish_cipher(self, key):
|
|
|
|
|
from hashlib import md5
|
|
|
|
|
import struct
|
|
|
|
|
|
|
|
|
|
def encrypt(plaintext):
|
|
|
|
|
return self._blowfish_encrypt_block(plaintext, key)
|
|
|
|
|
|
|
|
|
|
def decrypt(ciphertext):
|
|
|
|
|
return self._blowfish_decrypt_block(ciphertext, key)
|
|
|
|
|
|
|
|
|
|
return type('BlowfishCipher', (), {
|
|
|
|
|
'encrypt': encrypt,
|
|
|
|
|
'decrypt': decrypt
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
def _aes_encrypt_block(self, block, key, iv):
|
|
|
|
|
from hashlib import md5
|
|
|
|
|
import struct
|
|
|
|
|
|
|
|
|
|
# AES-128 CBC mode encryption
|
|
|
|
|
key = md5(key).digest()
|
|
|
|
|
iv = md5(iv).digest()[:16]
|
|
|
|
|
|
|
|
|
|
# Pad the block to 16 bytes
|
|
|
|
|
pad_len = 16 - (len(block) % 16)
|
|
|
|
|
block += bytes([pad_len] * pad_len)
|
|
|
|
|
|
|
|
|
|
# Encrypt using AES CBC mode
|
|
|
|
|
result = b''
|
|
|
|
|
prev = iv
|
|
|
|
|
for i in range(0, len(block), 16):
|
|
|
|
|
chunk = block[i:i+16]
|
|
|
|
|
chunk = self.xor_bytes(chunk, prev)
|
|
|
|
|
chunk = self._aes_encrypt_chunk(chunk, key)
|
|
|
|
|
result += chunk
|
|
|
|
|
prev = chunk
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def _aes_decrypt_block(self, block, key, iv):
|
|
|
|
|
from hashlib import md5
|
|
|
|
|
|
|
|
|
|
# AES-128 CBC mode decryption
|
|
|
|
|
key = md5(key).digest()
|
|
|
|
|
iv = md5(iv).digest()[:16]
|
|
|
|
|
|
|
|
|
|
# Decrypt using AES CBC mode
|
|
|
|
|
result = b''
|
|
|
|
|
prev = iv
|
|
|
|
|
for i in range(0, len(block), 16):
|
|
|
|
|
chunk = block[i:i+16]
|
|
|
|
|
decrypted = self._aes_decrypt_chunk(chunk, key)
|
|
|
|
|
decrypted = self.xor_bytes(decrypted, prev)
|
|
|
|
|
result += decrypted
|
|
|
|
|
prev = chunk
|
|
|
|
|
return self._unpad(result)
|
|
|
|
|
|
|
|
|
|
def _aes_encrypt_chunk(self, chunk, key):
|
|
|
|
|
# Simplified AES round function
|
|
|
|
|
return self.xor_bytes(chunk, key)
|
|
|
|
|
|
|
|
|
|
def _aes_decrypt_chunk(self, chunk, key):
|
|
|
|
|
# Simplified AES inverse round function
|
|
|
|
|
return self.xor_bytes(chunk, key)
|
|
|
|
|
|
|
|
|
|
def _blowfish_encrypt_block(self, block, key):
|
|
|
|
|
# Blowfish ECB mode encryption
|
|
|
|
|
return self._blowfish_encrypt_chunk(block, key)
|
|
|
|
|
|
|
|
|
|
def _blowfish_decrypt_block(self, block, key):
|
|
|
|
|
# Blowfish ECB mode decryption
|
|
|
|
|
return self._blowfish_decrypt_chunk(block, key)
|
|
|
|
|
|
|
|
|
|
def _blowfish_encrypt_chunk(self, chunk, key):
|
|
|
|
|
# Simplified Blowfish round function
|
|
|
|
|
return self.xor_bytes(chunk, key)
|
|
|
|
|
|
|
|
|
|
def _blowfish_decrypt_chunk(self, chunk, key):
|
|
|
|
|
# Simplified Blowfish inverse round function
|
|
|
|
|
return self.xor_bytes(chunk, key)
|
|
|
|
|
|
|
|
|
|
def _unpad(self, data):
|
|
|
|
|
pad_len = data[-1]
|
|
|
|
|
return data[:-pad_len]
|
|
|
|
|
|
|
|
|
|
def xor_bytes(self, str1, str2):
|
|
|
|
|
return bytes(a ^ b for a, b in zip(str1, str2))
|
|
|
|
|
|
|
|
|
|
class NavicatDecryptorApp:
|
|
|
|
|
class App:
|
|
|
|
|
def __init__(self, root):
|
|
|
|
|
self.root = root
|
|
|
|
|
self.root.title("Navicat Password Decryptor")
|
|
|
|
|
self.root.geometry("400x200")
|
|
|
|
|
self.root.title("Navicat密码解密工具")
|
|
|
|
|
|
|
|
|
|
self.version_var = tk.IntVar(value=12)
|
|
|
|
|
self.version = tk.IntVar(value=12)
|
|
|
|
|
self.password = tk.StringVar()
|
|
|
|
|
|
|
|
|
|
tk.Label(root, text="Navicat Version:").grid(row=0, column=0, padx=10, pady=10)
|
|
|
|
|
tk.Radiobutton(root, text="Version 11", variable=self.version_var, value=11).grid(row=0, column=1, sticky="w")
|
|
|
|
|
tk.Radiobutton(root, text="Version 12", variable=self.version_var, value=12).grid(row=0, column=2, sticky="w")
|
|
|
|
|
self.create_widgets()
|
|
|
|
|
|
|
|
|
|
def create_widgets(self):
|
|
|
|
|
tk.Label(self.root, text="Navicat版本:").grid(row=0, column=0, padx=5, pady=5)
|
|
|
|
|
tk.Radiobutton(self.root, text="11", variable=self.version, value=11).grid(row=0, column=1, sticky="w")
|
|
|
|
|
tk.Radiobutton(self.root, text="12", variable=self.version, value=12).grid(row=0, column=2, sticky="w")
|
|
|
|
|
|
|
|
|
|
tk.Label(root, text="Encrypted Password:").grid(row=1, column=0, padx=10, pady=10)
|
|
|
|
|
self.password_entry = tk.Entry(root, width=30)
|
|
|
|
|
self.password_entry.grid(row=1, column=1, columnspan=2)
|
|
|
|
|
tk.Label(self.root, text="加密密码:").grid(row=1, column=0, padx=5, pady=5)
|
|
|
|
|
tk.Entry(self.root, textvariable=self.password, width=30).grid(row=1, column=1, columnspan=2)
|
|
|
|
|
|
|
|
|
|
self.result_label = tk.Label(root, text="", fg="blue")
|
|
|
|
|
self.result_label.grid(row=2, column=0, columnspan=3, pady=10)
|
|
|
|
|
|
|
|
|
|
tk.Button(root, text="Decrypt", command=self.decrypt_password).grid(row=3, column=1, pady=20)
|
|
|
|
|
tk.Button(self.root, text="解密", command=self.decrypt_password).grid(row=2, column=1, pady=10)
|
|
|
|
|
|
|
|
|
|
def decrypt_password(self):
|
|
|
|
|
password = self.password_entry.get().strip()
|
|
|
|
|
password = self.password.get().strip()
|
|
|
|
|
if not password:
|
|
|
|
|
messagebox.showwarning("Input Error", "Please enter an encrypted password")
|
|
|
|
|
messagebox.showerror("错误", "请输入加密密码")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
decryptor = NavicatPassword(self.version_var.get())
|
|
|
|
|
result = decryptor.decrypt(password)
|
|
|
|
|
self.result_label.config(text=f"Decrypted Password: {result}")
|
|
|
|
|
navicat = NavicatPassword(self.version.get())
|
|
|
|
|
result = navicat.decrypt(password)
|
|
|
|
|
messagebox.showinfo("解密结果", f"解密后的密码是:\n{result}")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
messagebox.showerror("Error", f"Decryption failed: {str(e)}")
|
|
|
|
|
messagebox.showerror("错误", f"解密失败:{str(e)}")
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
root = tk.Tk()
|
|
|
|
|
app = NavicatDecryptorApp(root)
|
|
|
|
|
app = App(root)
|
|
|
|
|
root.mainloop()
|
|
|
|
|