当前位置: 首页 > news >正文

专注咖啡相关的网站中文域名 网站

专注咖啡相关的网站,中文域名 网站,wordpress添加自定义tag标签,产品营销推广方案引言 应公司要求,数据库的敏感数据在写入到数据库中要进行加密,但是在测试环境查询数据的时候要手动解密,很不方便,有的时候数据比较多,解密比较麻烦。遂研究了一下如何通过 MySQL Workbench 的插件来实现查询数据一键…

引言

应公司要求,数据库的敏感数据在写入到数据库中要进行加密,但是在测试环境查询数据的时候要手动解密,很不方便,有的时候数据比较多,解密比较麻烦。遂研究了一下如何通过 MySQL Workbench 的插件来实现查询数据一键解密。

问题

之前已经通过 mybatis 拦截器实现了自动加解密的功能,并且可以兼容 LambdaQueryWrapperQueryWrapperMapper 等查询方式,现在要解决的问题是通过插件自动解密数据。

插件原理

要想写 MySQL Workbench 插件,要先了解 MySQL Workbench 的原理。

插件

查看官方文档,MySQL Workbench 的核心使用 C++ 写的,但是留了大量的拓展接口,可以通过 Python 包装的方式来控制。例如可以通过 Python 创建一些界面,可以执行一些数据处理数据转换的逻辑等等,官方的用户模块文件夹中有大量的 Python 文件,感兴趣的小伙伴可以自行查看学习。

在这里插入图片描述

导入插件

MySQL Workbench 中的插件都是通过模块的方式导入的,一些拓展的插件都是完全通过 Python 脚本实现的。MySQL Workbench 内置了 Python 3.12,可以执行所有的 Python 脚本,所有的插件都放到一个 modules 的文件夹里面。细节文档这里不放了,可以查看文中的链接。

插件要求

插件的编写有几个要求:

  1. 源文件必须位于用户模块文件夹中。用户模块文件夹路径如下
Operating SystemFile Path
Windows%AppData%\MySQL\Workbench\modules
macOS~username/Library/Application Support/MySQL/Workbench/modules
Linux~username/.mysql/workbench/modules
  1. 模块文件名必须以 _grt.py 结尾,例如:my_module_grt.py
  2. 必须通过 DefineModule 为插件添加元数据。例如:
from wb import *
ModuleInfo = DefineModule(name='MyModule', author='Your Name', version='1.0')
  1. 插件方法需要通过进行签名,指定方法的返回值类型和参数个数,参数类型。
@ModuleInfo.export(grt.INT, grt.STRING)
def checkString(s):...

看一下官方的 demo:

from wb import *
import grtModuleInfo = DefineModule(name='MyModule', author="your name", version='1.0')@ModuleInfo.export(grt.DOUBLE, grt.STRING, (grt.LIST, grt.DOUBLE))
def printListSum(message, doubleList):sum = 0for d in doubleList:sum = sum + dprint message, sumreturn sum

Script Shell 查询

Script Shell 是一个可以执行脚本,查看 MySQL Workbench 拓展接口文档的工具,打开方式如下:

image-20241112225116753

查看下面的 Classes 选项卡,本次需求使用到了 db.query.Resultset 对象,可以在这里找到 Resultset 对象的方法和属性。MySQL Workbench 提供了大量的对象,如果有其他需求的小伙伴可以研究一下其他的对象如何使用,用得好的话拓展性很高。

在这里插入图片描述

编写插件

前面铺垫完了,开始看本次分享的插件吧。

import base64
import binascii
from base64 import b64encode, b64decode
from binascii import hexlify, unhexlifyimport grt
from wb import DefineModule, wbinputs
from workbench.log import log_infokey = binascii.unhexlify('你的key,十六进制字符串')
# python3
PY2 = False
PY3 = True_range = range
string_types = (str,)
text_type = str
binary_type = bytesE_FMT = 'UTF8'# S盒
S_BOX = {0X00: 0XD6, 0X01: 0X90, 0X02: 0XE9, 0X03: 0XFE, 0X04: 0XCC, 0X05: 0XE1, 0X06: 0X3D, 0X07: 0XB7,0X08: 0X16, 0X09: 0XB6, 0X0A: 0X14, 0X0B: 0XC2, 0X0C: 0X28, 0X0D: 0XFB, 0X0E: 0X2C, 0X0F: 0X05,0X10: 0X2B, 0X11: 0X67, 0X12: 0X9A, 0X13: 0X76, 0X14: 0X2A, 0X15: 0XBE, 0X16: 0X04, 0X17: 0XC3,0X18: 0XAA, 0X19: 0X44, 0X1A: 0X13, 0X1B: 0X26, 0X1C: 0X49, 0X1D: 0X86, 0X1E: 0X06, 0X1F: 0X99,0X20: 0X9C, 0X21: 0X42, 0X22: 0X50, 0X23: 0XF4, 0X24: 0X91, 0X25: 0XEF, 0X26: 0X98, 0X27: 0X7A,0X28: 0X33, 0X29: 0X54, 0X2A: 0X0B, 0X2B: 0X43, 0X2C: 0XED, 0X2D: 0XCF, 0X2E: 0XAC, 0X2F: 0X62,0X30: 0XE4, 0X31: 0XB3, 0X32: 0X1C, 0X33: 0XA9, 0X34: 0XC9, 0X35: 0X08, 0X36: 0XE8, 0X37: 0X95,0X38: 0X80, 0X39: 0XDF, 0X3A: 0X94, 0X3B: 0XFA, 0X3C: 0X75, 0X3D: 0X8F, 0X3E: 0X3F, 0X3F: 0XA6,0X40: 0X47, 0X41: 0X07, 0X42: 0XA7, 0X43: 0XFC, 0X44: 0XF3, 0X45: 0X73, 0X46: 0X17, 0X47: 0XBA,0X48: 0X83, 0X49: 0X59, 0X4A: 0X3C, 0X4B: 0X19, 0X4C: 0XE6, 0X4D: 0X85, 0X4E: 0X4F, 0X4F: 0XA8,0X50: 0X68, 0X51: 0X6B, 0X52: 0X81, 0X53: 0XB2, 0X54: 0X71, 0X55: 0X64, 0X56: 0XDA, 0X57: 0X8B,0X58: 0XF8, 0X59: 0XEB, 0X5A: 0X0F, 0X5B: 0X4B, 0X5C: 0X70, 0X5D: 0X56, 0X5E: 0X9D, 0X5F: 0X35,0X60: 0X1E, 0X61: 0X24, 0X62: 0X0E, 0X63: 0X5E, 0X64: 0X63, 0X65: 0X58, 0X66: 0XD1, 0X67: 0XA2,0X68: 0X25, 0X69: 0X22, 0X6A: 0X7C, 0X6B: 0X3B, 0X6C: 0X01, 0X6D: 0X21, 0X6E: 0X78, 0X6F: 0X87,0X70: 0XD4, 0X71: 0X00, 0X72: 0X46, 0X73: 0X57, 0X74: 0X9F, 0X75: 0XD3, 0X76: 0X27, 0X77: 0X52,0X78: 0X4C, 0X79: 0X36, 0X7A: 0X02, 0X7B: 0XE7, 0X7C: 0XA0, 0X7D: 0XC4, 0X7E: 0XC8, 0X7F: 0X9E,0X80: 0XEA, 0X81: 0XBF, 0X82: 0X8A, 0X83: 0XD2, 0X84: 0X40, 0X85: 0XC7, 0X86: 0X38, 0X87: 0XB5,0X88: 0XA3, 0X89: 0XF7, 0X8A: 0XF2, 0X8B: 0XCE, 0X8C: 0XF9, 0X8D: 0X61, 0X8E: 0X15, 0X8F: 0XA1,0X90: 0XE0, 0X91: 0XAE, 0X92: 0X5D, 0X93: 0XA4, 0X94: 0X9B, 0X95: 0X34, 0X96: 0X1A, 0X97: 0X55,0X98: 0XAD, 0X99: 0X93, 0X9A: 0X32, 0X9B: 0X30, 0X9C: 0XF5, 0X9D: 0X8C, 0X9E: 0XB1, 0X9F: 0XE3,0XA0: 0X1D, 0XA1: 0XF6, 0XA2: 0XE2, 0XA3: 0X2E, 0XA4: 0X82, 0XA5: 0X66, 0XA6: 0XCA, 0XA7: 0X60,0XA8: 0XC0, 0XA9: 0X29, 0XAA: 0X23, 0XAB: 0XAB, 0XAC: 0X0D, 0XAD: 0X53, 0XAE: 0X4E, 0XAF: 0X6F,0XB0: 0XD5, 0XB1: 0XDB, 0XB2: 0X37, 0XB3: 0X45, 0XB4: 0XDE, 0XB5: 0XFD, 0XB6: 0X8E, 0XB7: 0X2F,0XB8: 0X03, 0XB9: 0XFF, 0XBA: 0X6A, 0XBB: 0X72, 0XBC: 0X6D, 0XBD: 0X6C, 0XBE: 0X5B, 0XBF: 0X51,0XC0: 0X8D, 0XC1: 0X1B, 0XC2: 0XAF, 0XC3: 0X92, 0XC4: 0XBB, 0XC5: 0XDD, 0XC6: 0XBC, 0XC7: 0X7F,0XC8: 0X11, 0XC9: 0XD9, 0XCA: 0X5C, 0XCB: 0X41, 0XCC: 0X1F, 0XCD: 0X10, 0XCE: 0X5A, 0XCF: 0XD8,0XD0: 0X0A, 0XD1: 0XC1, 0XD2: 0X31, 0XD3: 0X88, 0XD4: 0XA5, 0XD5: 0XCD, 0XD6: 0X7B, 0XD7: 0XBD,0XD8: 0X2D, 0XD9: 0X74, 0XDA: 0XD0, 0XDB: 0X12, 0XDC: 0XB8, 0XDD: 0XE5, 0XDE: 0XB4, 0XDF: 0XB0,0XE0: 0X89, 0XE1: 0X69, 0XE2: 0X97, 0XE3: 0X4A, 0XE4: 0X0C, 0XE5: 0X96, 0XE6: 0X77, 0XE7: 0X7E,0XE8: 0X65, 0XE9: 0XB9, 0XEA: 0XF1, 0XEB: 0X09, 0XEC: 0XC5, 0XED: 0X6E, 0XEE: 0XC6, 0XEF: 0X84,0XF0: 0X18, 0XF1: 0XF0, 0XF2: 0X7D, 0XF3: 0XEC, 0XF4: 0X3A, 0XF5: 0XDC, 0XF6: 0X4D, 0XF7: 0X20,0XF8: 0X79, 0XF9: 0XEE, 0XFA: 0X5F, 0XFB: 0X3E, 0XFC: 0XD7, 0XFD: 0XCB, 0XFE: 0X39, 0XFF: 0X48
}# 系统参数FK
FK = (0XA3B1BAC6, 0X56AA3350, 0X677D9197, 0XB27022DC)# 固定参数CK
CK = (0X00070E15, 0X1C232A31, 0X383F464D, 0X545B6269,0X70777E85, 0X8C939AA1, 0XA8AFB6BD, 0XC4CBD2D9,0XE0E7EEF5, 0XFC030A11, 0X181F262D, 0X343B4249,0X50575E65, 0X6C737A81, 0X888F969D, 0XA4ABB2B9,0XC0C7CED5, 0XDCE3EAF1, 0XF8FF060D, 0X141B2229,0X30373E45, 0X4C535A61, 0X686F767D, 0X848B9299,0XA0A7AEB5, 0XBCC3CAD1, 0XD8DFE6ED, 0XF4FB0209,0X10171E25, 0X2C333A41, 0X484F565D, 0X646B7279)# 轮密钥缓存
_rk_cache = {}# 加密
SM4_ENCRYPT = 1
# 解密
SM4_DECRYPT = 0
# 分组byte数
BLOCK_BYTE = 16
BLOCK_HEX = BLOCK_BYTE * 2def num2hex(num, width=1):"""整数转为指定长度的十六进制字符串,不足补0>>> num2hex(1000, width=4)'03e8':param num: 整数:param width: 16进制字符串长度, 默认为1:return str"""return '{:0>{width}}'.format(hex(num)[2:].replace('L', ''),width=width)def _byte_unpack(num, byte_n=4):# 分解后元组长度_len = 4# 步长step = (byte_n // _len) * 2hex_str = num2hex(num=num, width=byte_n * 2)split_v = list(_range(len(hex_str)))[::step] + [len(hex_str)]return tuple([int(hex_str[s:e], base=16) for s, e inzip(split_v[:-1], split_v[1:])])def _byte_pack(byte_array, byte_n=4):_len = 4# byte_array每一项16进制字符串的长度width = (byte_n // _len) * 2if len(byte_array) != _len:raise ValueError('byte_array length must be 4.')return int(''.join([num2hex(num=v, width=width)for v in byte_array]), 16)def _s_box(byte):return S_BOX.get(byte)def _non_linear_map(byte_array):"""非线性变换, 输入A=(a0, a1, a2, a3)(b0, b1, b2, b3) = (Sbox(a0), Sbox(a1), Sbox(a2), Sbox(a3))"""return (_s_box(byte_array[0]), _s_box(byte_array[1]),_s_box(byte_array[2]), _s_box(byte_array[3]))def _linear_map(byte4):"""线性变换LL(B) = B ⊕ (B <<< 2) ⊕ (B <<< 10) ⊕ (B <<< 18) ⊕ (B <<< 24)"""_left = loop_left_shiftreturn byte4 ^ _left(byte4, 2) ^ _left(byte4, 10) ^ _left(byte4, 18) ^ _left(byte4, 24)def _linear_map_s(byte4):"""线性变换L'L'(B) = B ⊕ (B <<< 13) ⊕ (B <<< 23)"""_left = loop_left_shiftreturn byte4 ^ _left(byte4, 13) ^ _left(byte4, 23)def loop_left_shift(num, offset, base=32):"""循环向左移位>>> loop_left_shift(0b11010000, 3, base=8)>>> 0b10000110"""bin_str = '{:0>{width}}'.format(bin(num)[2:], width=base)rem = offset % basereturn int(bin_str[rem:] + bin_str[:rem], 2)def _rep_t(byte4):"""合成置换T, 由非线性变换和线性变换L复合而成"""# 非线性变换b_array = _non_linear_map(_byte_unpack(byte4))# 线性变换Lreturn _linear_map(_byte_pack(b_array))def _rep_t_s(byte4):"""合成置换T', 由非线性变换和线性变换L'复合而成"""# 非线性变换b_array = _non_linear_map(_byte_unpack(byte4))# 线性变换L'return _linear_map_s(_byte_pack(b_array))def _round_keys(mk):"""轮密钥由加密密钥通过密钥扩展算法生成加密密钥MK = (MK0, MK1, MK2, MK3)轮密钥生成算法:(K0, K1, K2, K3) = (MK0 ⊕ FK0, MK1 ⊕ FK1, MK2 ⊕ FK2, MK3 ⊕ FK3)rki = Ki+4 = Ki⊕T'(Ki+1 ⊕ Ki+2 ⊕ Ki+3 ⊕ CKi) i=0, 1,...,31:param mk: 加密密钥, 16byte, 128bit:return list"""# 尝试从轮密钥缓存中获取轮密钥# 没有获取到, 根据密钥扩展算法生成_rk_keys = _rk_cache.get(mk)if _rk_keys is None:mk0, mk1, mk2, mk3 = _byte_unpack(mk, byte_n=16)keys = [mk0 ^ FK[0], mk1 ^ FK[1], mk2 ^ FK[2], mk3 ^ FK[3]]for i in _range(32):rk = keys[i] ^ _rep_t_s(keys[i + 1] ^ keys[i + 2] ^ keys[i + 3] ^ CK[i])keys.append(rk)_rk_keys = keys[4:]# 加入轮密钥缓存中_rk_cache[mk] = _rk_keysreturn _rk_keysdef _round_f(byte4_array, rk):"""轮函数, F(X0, X1, X2, X3, rk) = X0 ⊕ T(X1 ⊕ X2 ⊕ X3 ⊕ rk):param byte4_array: (X0, X1, X2, X3), 每一项4byte, 32bit:param rk: 轮密钥, 4byte, 32bit"""x0, x1, x2, x3 = byte4_arrayreturn x0 ^ _rep_t(x1 ^ x2 ^ x3 ^ rk)def _crypt(num, mk, mode=SM4_ENCRYPT):"""SM4加密和解密:param num: 密文或明文 16byte:param mk:  密钥 16byte:param mode: 轮密钥顺序"""x_keys = list(_byte_unpack(num, byte_n=16))round_keys = _round_keys(mk)if mode == SM4_DECRYPT:round_keys = round_keys[::-1]for i in _range(32):x_keys.append(_round_f(x_keys[i:i + 4], round_keys[i]))return _byte_pack(x_keys[-4:][::-1], byte_n=16)def encrypt(clear_num, mk):"""SM4加密算法由32次迭代运算和1次反序变换R组成.明文输入为(X0, X1, X2, X3), 每一项4byte, 密文输出为(Y0, Y1, Y2, Y3), 每一项4byte轮密钥为rki, i=0,1,...,32, 4byte, 运算过程如下:1). 32次迭代运算: Xi+4 = F(Xi, Xi+1, Xi+2, Xi+3, rki), i=0,1,...,322). 反序变换: (Y0, Y1, Y2, Y3) = (X35, X34, X33, X32):param clear_num: 明文, 16byte:param mk: 密钥, 16byte"""return _crypt(num=clear_num, mk=mk)def decrypt(cipher_num, mk):"""SM4解密算法, 解密变换与加密变换结构相同, 不同的仅是轮密钥的使用顺序.解密时轮密钥使用顺序为(rk31,rk30,...,rk0):param cipher_num: 密文, 16byte:param mk: 密钥, 16byte"""return _crypt(num=cipher_num, mk=mk, mode=SM4_DECRYPT)def _padding(text, mode=SM4_ENCRYPT):"""加密填充和解密去填充"""# python2 is (basestring, )# python3 is (str, bytes)_str_or_bytes = string_types if PY2 else (string_types + (binary_type,))if text is None or not isinstance(text, _str_or_bytes):return# unicodeif isinstance(text, text_type):text = text.encode(encoding=E_FMT)if mode == SM4_ENCRYPT:# 填充p_num = BLOCK_BYTE - (len(text) % BLOCK_BYTE)space = '' if PY2 else b''pad_s = (chr(p_num) * p_num) if PY2 else (chr(p_num).encode(E_FMT) * p_num)res = space.join([text, pad_s])else:# 去填充p_num = ord(text[-1]) if PY2 else text[-1]res = text[:-p_num]return resdef _key_iv_check(key_iv):"""密钥或初始化向量检测"""# 密钥if key_iv is None or not isinstance(key_iv, (string_types, binary_type)):raise TypeError('Parameter key or iv:{} not string_types or binary_type'.format(key_iv))if isinstance(key_iv, text_type):key_iv = key_iv.encode(encoding=E_FMT)if len(key_iv) > BLOCK_BYTE:raise ValueError('Parameter key or iv:{} byte greater than {}'.format(key_iv.decode(E_FMT),BLOCK_BYTE))return key_ivdef _hex(str_or_bytes):# PY2: _hex('北京') --> 'e58c97e4baac'# PY3: _hex('北京') --> b'e58c97e4baac'if PY2:hex_str = hexlify(str_or_bytes)else:# python3if isinstance(str_or_bytes, text_type):byte = str_or_bytes.encode(encoding=E_FMT)elif isinstance(str_or_bytes, binary_type):byte = str_or_byteselse:byte = b''hex_str = hexlify(byte)return hex_strdef _unhex(hex_str):# PY2: _unhex('e58c97e4baac') --> '\xe5\x8c\x97\xe4\xba\xac'# PY3: _unhex('e58c97e4baac') --> b'\xe5\x8c\x97\xe4\xba\xac'return unhexlify(hex_str)# 电子密码本(ECB)
def encrypt_ecb(plain_text, key):"""SM4(ECB)加密:param plain_text: 明文:param key: 密钥, 小于等于16字节"""plain_text = _padding(plain_text, mode=SM4_ENCRYPT)if plain_text is None:return# 密钥检验key = _key_iv_check(key_iv=key)plain_hex = _hex(plain_text)cipher_hex_list = []for i in _range(len(plain_text) // BLOCK_BYTE):sub_hex = plain_hex[i * BLOCK_HEX:(i + 1) * BLOCK_HEX]cipher = encrypt(clear_num=int(sub_hex, 16),mk=int(_hex(key), 16))cipher_hex_list.append(num2hex(num=cipher, width=BLOCK_HEX))cipher_text = b64encode(_unhex(''.join(cipher_hex_list)))return cipher_text if PY2 else cipher_text.decode(E_FMT)def decrypt_ecb(cipher_text, key):"""SM4(ECB)解密:param cipher_text: 密文:param key: 密钥, 小于等于16字节"""cipher_text = b64decode(cipher_text)cipher_hex = _hex(cipher_text)# 密码检验key = _key_iv_check(key_iv=key)plain_hex_list = []for i in _range(len(cipher_text) // BLOCK_BYTE):sub_hex = cipher_hex[i * BLOCK_HEX:(i + 1) * BLOCK_HEX]plain = decrypt(cipher_num=int(sub_hex, 16),mk=int(_hex(key), 16))plain_hex_list.append(num2hex(num=plain, width=BLOCK_HEX))plain_text = _padding(_unhex(''.join(plain_hex_list)),mode=SM4_DECRYPT)return plain_text if PY2 else plain_text.decode(E_FMT)# 密码块链接(CBC)
def encrypt_cbc(plain_text, key, iv):"""SM4(CBC)加密:param plain_text: 明文:param key: 密钥, 小于等于16字节:param iv: 初始化向量, 小于等于16字节"""plain_text = _padding(plain_text, mode=SM4_ENCRYPT)if plain_text is None:return# 密钥检验key = _key_iv_check(key_iv=key)# 初始化向量监测iv = _key_iv_check(key_iv=iv)plain_hex = _hex(plain_text)ivs = [int(_hex(iv), 16)]for i in _range(len(plain_text) // BLOCK_BYTE):sub_hex = plain_hex[i * BLOCK_HEX:(i + 1) * BLOCK_HEX]cipher = encrypt(clear_num=(int(sub_hex, 16) ^ ivs[i]),mk=int(_hex(key), 16))ivs.append(cipher)cipher_text = b64encode(_unhex(''.join([num2hex(num=c, width=BLOCK_HEX)for c in ivs[1:]])))return cipher_text if PY2 else cipher_text.decode(E_FMT)def decrypt_cbc(cipher_text, key, iv):"""SM4(CBC)解密:param cipher_text: 密文:param key: 密钥 小于等于16字节:param iv: 初始化向量 小于等于16字节"""cipher_text = b64decode(cipher_text)cipher_hex = _hex(cipher_text)# 密钥检测key = _key_iv_check(key_iv=key)# 初始化向量检测iv = _key_iv_check(key_iv=iv)ivs = [int(_hex(iv), 16)]plain_hex_list = []for i in _range(len(cipher_text) // BLOCK_BYTE):sub_hex = cipher_hex[i * BLOCK_HEX:(i + 1) * BLOCK_HEX]cipher = int(sub_hex, 16)plain = (ivs[i] ^ decrypt(cipher_num=cipher,mk=int(_hex(key), 16)))ivs.append(cipher)plain_hex_list.append(num2hex(num=plain, width=BLOCK_HEX))plain_text = _padding(_unhex(''.join(plain_hex_list)),mode=SM4_DECRYPT)return plain_text if PY2 else plain_text.decode(E_FMT)ModuleInfo = DefineModule(name="DataUtils", author="b", version="1.0")@ModuleInfo.plugin("wb.sqlide.decryptData", caption="decrypt data from resultSet",input=[wbinputs.currentResultset(), wbinputs.currentEditableResultset()], pluginMenu="SQL/Utilities",accessibilityName="decryptData from resultSet")
@ModuleInfo.export(grt.INT, grt.classes.db_query_Resultset, grt.classes.db_query_EditableResultset)
def decryptData(result_set, edit_result_set):"""decryptData from resultSet"""try:row_count = result_set.rowCountcolumn_count = len(result_set.columns)log_info(str(row_count) + '\n')log_info(str(column_count) + '\n')for a in range(row_count - 1):result_set.goToRow(a)edit_column(result_set, edit_result_set, column_count)result_set.nextRow()except Exception as e:log_info(str(e) + '\n')return 0def edit_column(result_set, edit_result_set, column_count):for a in range(column_count - 1):value = result_set.stringFieldValue(a)log_info(value + '\n')if value.startswith('enc:'):b = binascii.unhexlify(value[4:])data = base64.b64encode(b).decode()edit_result_set.setStringFieldValue(a, decrypt_ecb(data, key))

插件效果

上面的插件实现的功能是,在通过 SQL 查询完数据之后,点击 decryptData from resultSet 即可自动解密查询结果中被加密的数据。由于用到了 SM4 来解密,所以这里为了不引入外部依赖,将 pysm4 这个库的源码放到同一个插件脚本里面了,所以上面的一大堆方法都是 pysm4 里面的,可以先忽略。

image-20241112231017602

执行插件前:

在这里插入图片描述

执行插件后,enc 前缀已经没有了,自动解密出来原始的数据了。

在这里插入图片描述

插件编写

首先,需要使用 DefineModule 来实例化一个对象,用这个对象来注册插件,通过装饰器的方式,DefineModule 中会定义名字,作者,版本等信息。

ModuleInfo = DefineModule(name="DataUtils", author="b", version="1.0")@ModuleInfo.plugin("wb.sqlide.decryptData", caption="decrypt data from resultSet",input=[wbinputs.currentResultset(), wbinputs.currentEditableResultset()], pluginMenu="SQL/Utilities",accessibilityName="decryptData from resultSet")
@ModuleInfo.export(grt.INT, grt.classes.db_query_Resultset, grt.classes.db_query_EditableResultset)

这里要注意几点:

  • @ModuleInfo.plugin 中的参数,第一个"wb.sqlide.decryptData"是可以自定义的
  • caption 是插件的说明,也可以自定义
  • input 参数是根据你的需求,例如要操作 Resultset 对象,就去 wbinputs 中去找返回 Resultset 类型的方法,这里我额外用到了 EditableResultset 对象,因为我还要对 Resultset 中的某行数据进行更改。
  • pluginMenu 就是在菜单中的位置,可以更改。
  • @ModuleInfo.export 中的参数,第一个参数是返回值的类型,后面的所有参数都是要注册的插件的参数,和刚才的 inputs 参数的类型和数量要一致。
def decryptData(result_set, edit_result_set):"""decryptData from resultSet"""try:row_count = result_set.rowCountcolumn_count = len(result_set.columns)log_info(str(row_count) + '\n')log_info(str(column_count) + '\n')for a in range(row_count - 1):result_set.goToRow(a)edit_column(result_set, edit_result_set, column_count)result_set.nextRow()except Exception as e:log_info(str(e) + '\n')return 0

自定义的插件方法,参数的数量和类型要和刚才定义的一致,返回值的类型也要和刚才定义的一致。

完成以上内容后就可以开始编写插件的逻辑了,插件的逻辑比较简单,这里我就不详细分析了。主要的功能就是实现一个解密函数,对 Resultset 中某行的加密数据进行解密。

注意事项

插件写完了,说几点注意事项。

  • 插件的加载是通过 Python 进行的,所以每次插件的更改都要重启 MySQL Workbench 才能生效。
  • 需要输出日志的话可以自己在 Python 中写文件,也可以通过 from workbench.log import log_info 的方式把日志打印到软件的日志里面。
  • MySQL Workbench 的插件其实是可以调用外部依赖的,不过我没有在官方的文档中找到教程,自己摸索了一下,可以把外部依赖文件夹手动复制到 C:\Program Files\MySQL\MySQL Workbench 8.0 CE\python\site-packages 这个路径中,即可在插件中直接 import 调用了。
  • Resultset 类型和 EditableResultset 类型应该有继承关系,EditableResultset 也可以用 Resultset 的属性和方法。

总结

MySQL Workbench 的文档写的太差了,好多用法都没有明确的文档,还得靠自己猜和看官方的脚本才能知道怎么用,不过最终花了几个小时还是搞定了这个功能。

http://www.yayakq.cn/news/168156/

相关文章:

  • 南宁专业做网站一个网址建多个网站
  • 网站关键词排名企业网站代码
  • 大连电子学校网站建设南昌响应式网站建设
  • wordpress本地安卓安装广州制作网站seo
  • 制作网站费用分类优秀企业网站建设价格
  • 怎么做科技小制作视频网站兴县做网站
  • 广西住建局和城乡建设局网站网站开发招标评分标准
  • 新网站排名优化软件工程师招聘简章
  • 如何是网站排名上升西城网站建设浩森宇特
  • 免费建企业网站做淘客哪个网站好点
  • 白山市网站建设网站需求文档
  • 浏阳网页设计网站优化难吗
  • 搜索公司信息的网站免费网页制作平台
  • 医疗网站优化怎么做接做网站私活
  • 建设企业功能网站洛阳搜索引擎优化
  • 网站百度抓取17一起做网站包包
  • 江山做网站怎么做一考试网站
  • 地产公司网站建设如何用api做网站
  • 福建省建设工程继续教育网站个人信息查询
  • 做期货要看哪些网站全国十大家装公司排名
  • 做网站 分辨率应该是多少iis网站正在建设中
  • 专业手机网站制作公司网站主题设计特色
  • 网站外链坏处wordpress反斜杠安装
  • 海尔网站建设投入seo辅助
  • 蚌埠建设学校网站青岛建筑
  • 福州网站制作建设不知此网站做男人也
  • 做gif动图的网站犯法吗网页游戏单机
  • 对网站的赏析用商城系统做教育网站
  • 给手机做网站的公司有哪些网页设计跳转链接怎么制作
  • 网站开发运行详细步骤做招聘网站如何宣传