Golang解析Navicat密码

Navicat密码解析器

简介

Navicat的连接信息是都保存在注册表中,其中注册表的位置与数据库类型一一对应。

Database TypePath
MySQLHKEY_CURRENT_USER\Software\PremiumSoft\Navicat\Servers\<your connection name>
MariaDBHKEY_CURRENT_USER\Software\PremiumSoft\NavicatMARIADB\Servers\<your connection name>
MongoDBHKEY_CURRENT_USER\Software\PremiumSoft\NavicatMONGODB\Servers\<your connection name>
Microsoft SQLHKEY_CURRENT_USER\Software\PremiumSoft\NavicatMSSQL\Servers\<your connection name>
OracleHKEY_CURRENT_USER\Software\PremiumSoft\NavicatOra\Servers\<your connection name>
PostgreSQLHKEY_CURRENT_USER\Software\PremiumSoft\NavicatPG\Servers\<your connection name>
SQLiteHKEY_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)
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值