Navicat密码解析器
简介
Navicat的连接信息是都保存在注册表中,其中注册表的位置与数据库类型一一对应。
Database Type | Path |
---|---|
MySQL | HKEY_CURRENT_USER\Software\PremiumSoft\Navicat\Servers\<your connection name> |
MariaDB | HKEY_CURRENT_USER\Software\PremiumSoft\NavicatMARIADB\Servers\<your connection name> |
MongoDB | HKEY_CURRENT_USER\Software\PremiumSoft\NavicatMONGODB\Servers\<your connection name> |
Microsoft SQL | HKEY_CURRENT_USER\Software\PremiumSoft\NavicatMSSQL\Servers\<your connection name> |
Oracle | HKEY_CURRENT_USER\Software\PremiumSoft\NavicatOra\Servers\<your connection name> |
PostgreSQL | HKEY_CURRENT_USER\Software\PremiumSoft\NavicatPG\Servers\<your connection name> |
SQLite | HKEY_CURRENT_USER\Software\PremiumSoft\NavicatSQLite\Servers\<your connection name> |
这些连接信息中的密码都是加密存储的,但是在很久前已经有大佬提供了加解密的源码了。可以参考下:源码地址
这个项目里面有c++、java、python3、vb.net的版本,但是我们这边主要采用golang去实现,无奈之下也只能硬着头皮把C++与java的实现看了一遍。功夫不负有心人,在公司的巨佬的帮助下终于写出来。
加解密
Navicat加解密主要分为11版本和12版本,高版本Navicat可以使用11版本进行加密,所有这边我就贴上11版本的加解密方法
type LowVersionCipher struct {
key []byte
cipher cipher.Block
iv []byte
}
func (l *LowVersionCipher) Encrypt(input string) (string, error) {
srcBytes := []byte(input)
ret := ""
if len(srcBytes) == 0 {
return ret, fmt.Errorf("source string is empty")
}
cv := make([]byte, 8)
copy(cv, []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})
l.cipher.Encrypt(cv, cv)
blocksLen := len(srcBytes) / 8
for i := 0; i < blocksLen; i++ {
temp := make([]byte, 8)
qword := binary.LittleEndian.Uint64(srcBytes[i*8 : (i+1)*8])
binary.LittleEndian.PutUint64(temp, qword^binary.LittleEndian.Uint64(cv))
l.cipher.Encrypt(temp, temp)
xorBytes(cv, temp)
ret += hex.EncodeToString(temp)
}
block := len(srcBytes) % 8
if block > 0 {
l.cipher.Encrypt(cv, cv)
temp := srcBytes[blocksLen*8:]
xorBytesLeft(temp, cv, block)
ret += hex.EncodeToString(temp)
}
return ret, nil
}
func (l *LowVersionCipher) Decrypt(input string) (string, error) {
ciphertext, err := hex.DecodeString(input)
if err != nil {
return "", err
}
if len(ciphertext)%8 != 0 {
return "", errors.New("ciphertext length must be a multiple of 8")
}
plaintext := make([]byte, len(ciphertext))
cv := make([]byte, len(l.iv))
copy(cv, l.iv)
blocksLen := len(ciphertext) / blowfish.BlockSize
leftLen := len(ciphertext) % blowfish.BlockSize
decrypter := NewECBDecrypter(l.cipher)
for i := 0; i < blocksLen; i++ {
temp := make([]byte, blowfish.BlockSize)
copy(temp, ciphertext[i*blowfish.BlockSize:(i+1)*blowfish.BlockSize])
if err != nil {
panic(err)
}
decrypter.CryptBlocks(temp, temp)
xorBytes(temp, cv)
copy(plaintext[i*blowfish.BlockSize:(i+1)*blowfish.BlockSize], temp)
for j := 0; j < len(cv); j++ {
cv[j] ^= ciphertext[i*blowfish.BlockSize+j]
}
}
if leftLen != 0 {
decrypter.CryptBlocks(cv, cv)
temp := make([]byte, leftLen)
copy(temp, ciphertext[blocksLen*blowfish.BlockSize:])
xorBytes(temp, cv[:leftLen])
copy(plaintext[blocksLen*blowfish.BlockSize:], temp)
}
return string(plaintext), nil
}
func xorBytes(a []byte, b []byte) {
for i := 0; i < len(a); i++ {
aVal := int(a[i]) & 0xff // convert byte to integer
bVal := int(b[i]) & 0xff
a[i] = byte(aVal ^ bVal) // xor aVal and bVal and typecast to byte
}
}
func xorBytesLeft(a, b []byte, l int) {
for i := 0; i < l; i++ {
aVal := int(a[i]) & 0xff
bVal := int(b[i]) & 0xff
a[i] = byte(aVal ^ bVal)
}
}