首页 杂烩分享

dbeaver密码解密脚本


背景

dbeaver查看连接密码,可以通过输入主密码进行查看。但是免费版是没有对应功能的。在某次次破解失效了,想要转到免费版使用,但之前存储的密码因为加密,没办法迁移到免费版,会解析出问题。

搜索学习

解密示例:

openssl aes-128-cbc -d -K babb4a9f774ab853c96c2d653dfe544a -iv 00000000000000000000000000000000 -in "credentials-config.json"

加密示例:

openssl aes-128-cbc -e -nosalt -K babb4a9f774ab853c96c2d653dfe544a -iv 00000000000000000000000000000000 -in credentials.json -out credentials-config.json

其中"babb4a9f774ab853c96c2d653dfe544a"为默认密码的16进制转义,在github:dbeaver源码中为

private static final byte[] LOCAL_KEY_CACHE = new byte[] { -70, -69, 74, -97, 119, 74, -72, 83, -55, 108, 45, 101, 61, -2, 84, 74 };

解密命令

解密成功!

源码解析

github:源代码连接
分析其dbeaver加密代码和上面openssl参数可以看到使用的aes cdc加密方式
加密方式

密码转义和创建密钥

密码转义
使用传递过来的字符串生成密钥,其中有个bug,只取前16位byte,如果密码超过16位(前端页面无限制),则也只有前16位生效。

解密代码

密码转义
先读取传递过来的value(也就是文件内容),读取前16位作为iv,后面的内容是真正的文本内容,使用密钥进行解密。

加密代码

密码转义
生成新的iv,并以密钥进行加密,最后将iv拼接到加密后的内容前,整体返回iv+密文。

python复现

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import sys
import os
import json



default_paths = [
  '~/Library/DBeaverData/workspace6/General/.dbeaver/credentials-config.json',
  '~/.local/share/DBeaverData/workspace6/General/.dbeaver/credentials-config.json',
  '~/.local/share/.DBeaverData/workspace6/General/.dbeaver/credentials-config.json',
  '~/AppData/Roaming/DBeaverData/workspace6/General/.dbeaver/credentials-config.json',
]

PASSWORD_DECRYPTION_KEY = bytes([186, 187, 74, 159, 119, 74, 184, 83, 201, 108, 45, 101, 61, 254, 84, 74])


# password补位或默认密码
def pad_password(password:str) -> bytes:
       # 不足16位的补位,超过16位的截取前16位
    if password is not None:
        password_encode=password.encode('utf-8')
        secret_key = password_encode[:16].ljust(16, b'\0')
    else:
       secret_key = PASSWORD_DECRYPTION_KEY
    return secret_key

# 解密
def decryptValue(iv:bytes,metadata:bytes,password=None) -> bytes:
    # 不足16位的补位,超过16位的截取前16位
    secret_key = pad_password(password)
    # 获取AES密钥对象
    decryptor = AES.new(secret_key, AES.MODE_CBC,iv)
    # 解密
    padded_output = decryptor.decrypt(metadata)
    # 去除补位
    output=unpad(padded_output, AES.block_size)
    return output


# 加密
def encryptValue(metadata:bytes,password=None,iv=None) -> bytes:
    # 不足16位的补位,超过16位的截取前16位
    secret_key = pad_password(password)
    # 获取AES密钥对象
    if iv is not None:
        encryptor = AES.new(secret_key, AES.MODE_CBC,iv)
    else:
        encryptor = AES.new(secret_key, AES.MODE_CBC)
    # 获取iv
    iv = encryptor.iv
    # 补位
    padded_input = pad(metadata, AES.block_size)
    # 加密
    input = encryptor.encrypt(padded_input)
    # 返回iv和加密后的值
    return iv,input



def read_file(path):
    if not os.path.exists(path):
        print('文件不存在')
        sys.exit(1)
    with open(path, 'rb') as f:
        data = f.read()
        return data

# 选择默认路径或手动输入路径
def choice_path():
    for path in default_paths:
        path = os.path.expanduser(path)
        if os.path.exists(path):
            break
    if path is None:
        print('未找到默认路径,请手动输入路径')
        path = input('请输入路径:')
        return path
        
    print(f'找到默认路径:{path},是否使用默认路径?(y/n)')
    choice = input('请输入:')
    if choice.lower() == 'n':
        path = input('请输入路径:')
    return path


def main():
   # 判断默认路径是否存在
    path = choice_path()
    # 读取文件
    data = read_file(path)
    print(data)
    iv,metadata = data[:16],data[16:]
    # 解密
    de_data = decryptValue(iv,metadata,password='123')
    print(json.dumps(json.loads(de_data), indent=4, ensure_ascii=False))

    #转换为json文件
    with open('data.json', 'wb') as f:
        f.write(de_data)
    print('解密成功,已生成data.json文件')

    # 进行重新加密,如果是从自定义加密修改为默认加密或新加密
    # iv,en_data= encryptValue(de_data,password='123',iv=iv)




if __name__ == '__main__':
    main()

疑问

为什么iv为任何值都可以解密?所以iv的作用是什么?





文章评论