Navicat 密码一旦保存, 再次编辑就没法查看密码是什么了, 包括之前可以使用的星号密码查看器也看不到密码, 我们可以通过导出链接文件, 然后通过解密被加密的密码来获取密码原文.
导出加密密码
打开 Navicat – 文件 – 导出连接
接下来的弹窗里, 勾选导出密码, 然后导出成 ncx 文件
用文本编辑器打开 connections.ncx 文件, 复制 password 的值, 这个就是加密后的密码.
使用 PHP 解密
电脑没有 PHP 环境, 所以选择使用 Docker 来运行 PHP, 操作如下:
准备解密脚本
vim navicat-decode-password.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
| <?php
namespace FatSmallTools;
class NavicatPassword { protected $version = 0; protected $aesKey = 'libcckeylibcckey'; protected $aesIv = 'libcciv libcciv '; protected $blowString = '3DC5CA39'; protected $blowKey = null; protected $blowIv = null;
public function __construct($version = 12) { $this->version = $version; $this->blowKey = sha1('3DC5CA39', true); $this->blowIv = hex2bin('d9c7c3c8870d64bd'); }
public function encrypt($string) { $result = FALSE; switch ($this->version) { case 11: $result = $this->encryptEleven($string); break; case 12: $result = $this->encryptTwelve($string); break; default: break; }
return $result; }
protected function encryptEleven($string) { $round = intval(floor(strlen($string) / 8)); $leftLength = strlen($string) % 8; $result = ''; $currentVector = $this->blowIv;
for ($i = 0; $i < $round; $i++) { $temp = $this->encryptBlock($this->xorBytes(substr($string, 8 * $i, 8), $currentVector)); $currentVector = $this->xorBytes($currentVector, $temp); $result .= $temp; }
if ($leftLength) { $currentVector = $this->encryptBlock($currentVector); $result .= $this->xorBytes(substr($string, 8 * $i, $leftLength), $currentVector); }
return strtoupper(bin2hex($result)); }
protected function encryptBlock($block) { return openssl_encrypt($block, 'BF-ECB', $this->blowKey, OPENSSL_RAW_DATA|OPENSSL_NO_PADDING); }
protected function decryptBlock($block) { return openssl_decrypt($block, 'BF-ECB', $this->blowKey, OPENSSL_RAW_DATA|OPENSSL_NO_PADDING); }
protected function xorBytes($str1, $str2) { $result = ''; for ($i = 0; $i < strlen($str1); $i++) { $result .= chr(ord($str1[$i]) ^ ord($str2[$i])); }
return $result; }
protected function encryptTwelve($string) { $result = openssl_encrypt($string, 'AES-128-CBC', $this->aesKey, OPENSSL_RAW_DATA, $this->aesIv); return strtoupper(bin2hex($result)); }
public function decrypt($string) { $result = FALSE; switch ($this->version) { case 11: $result = $this->decryptEleven($string); break; case 12: $result = $this->decryptTwelve($string); break; default: break; }
return $result; }
protected function decryptEleven($upperString) { $string = hex2bin(strtolower($upperString));
$round = intval(floor(strlen($string) / 8)); $leftLength = strlen($string) % 8; $result = ''; $currentVector = $this->blowIv;
for ($i = 0; $i < $round; $i++) { $encryptedBlock = substr($string, 8 * $i, 8); $temp = $this->xorBytes($this->decryptBlock($encryptedBlock), $currentVector); $currentVector = $this->xorBytes($currentVector, $encryptedBlock); $result .= $temp; }
if ($leftLength) { $currentVector = $this->encryptBlock($currentVector); $result .= $this->xorBytes(substr($string, 8 * $i, $leftLength), $currentVector); }
return $result; }
protected function decryptTwelve($upperString) { $string = hex2bin(strtolower($upperString)); return openssl_decrypt($string, 'AES-128-CBC', $this->aesKey, OPENSSL_RAW_DATA, $this->aesIv); } }
use FatSmallTools\NavicatPassword;
$navicatPassword = new NavicatPassword(12);
$encrypted_password = $_SERVER['argv'][1]; $decode = $navicatPassword->decrypt($encrypted_password); echo $decode."\n";
|
使用 Docker 版 PHP 来执行脚本
执行 php 脚本,使用 cli 版本的镜像即可. 这里选择 php:8.3.1-cli
1
| docker run --rm -v "$(pwd)":/data php:8.3.1-cli php /data/navicat-decode-password.php "F0FC4E94542FF60596CC6FFA9F5F68D1"
|
密码会打印在控制台上.
优化版脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #!/bin/bash
list=$(grep "<Connection ConnectionName=" connections.ncx)
IFS=$'\n' for i in ${list[*]}; do name=$(echo "$i" | awk -F 'ConnectionName="' '{print $2}' | awk -F '"' '{print $1}') user=$(echo "$i" | awk -F 'UserName="' '{print $2}' | awk -F '"' '{print $1}') host=$(echo "$i" | awk -F 'Host="' '{print $2}' | awk -F '"' '{print $1}') port=$(echo "$i" | awk -F 'Port="' '{print $2}' | awk -F '"' '{print $1}') en_password=$(echo "$i" | awk -F 'Password="' '{print $2}' | awk -F '" ' '{print $1}') password=$(docker run --rm -v "$(pwd)":/data php:8.3.1-cli php /data/navicat-decode-password.php "$en_password")
echo "$name" echo "地址: $host" echo "端口: $port" echo "用户: $user" echo "密码: $password" echo ---------------------------------------------------------------------------------------- done
|
脚本会读取 connections.ncx
文件,并按照格式将内容输出: