Mysql:使用密钥对字符串进行异或运算

5

我想用一个KEY对字符串(实际上是其二进制表示)进行位异或。

操作的结果应表示为十六进制。

我有: 'a' - 要更改的UTF-8字符串。 'ACF123456' - 十六进制格式的密钥。

将结果表示为BIGINT:

select CONV(HEX('a'), 16, 10)  ^  CONV('ACF123456', 16, 10);

结果以十六进制显示:

select CONV( CONV(HEX('a'), 16, 10)  ^  CONV('ACF123456', 16, 10), 10, 16);

问题:

  1. 上述转换是否正确?
  2. 如果字符串太长会发生什么情况(即我们使用'a veeeeeery long string'而不是'a')?似乎conv()函数有一个限制(文档中的64位精度是吗)?除此之外,XOR运算符^也有一个限制,与返回结果的位数相关。有任何适用于任何字符串的解决方案(存储过程允许)吗?

谢谢。

2个回答

1

你的转换看起来很好。

正如你所指出的,CONV()^都具有64位精度。

2^64 = 16^16,因此超过16个十六进制数字的字符串应该转换为大于2^64的整数。然而,在尝试将它们转换为整数时,这些字符串将被从左侧残酷(静默)截断。

我在这里提供的解决方案的重点是切片这样的字符串。显然,结果可能不会显示为整数,而只能显示为字符串表示形式。

@input成为您要更改的"字符串",@key是您的"密钥"。

  1. HEX(@input)赋值给@hex_input。这里没有问题,因为HEX()可以处理字符串。
  2. 从右侧开始,将@hex_input切成16个十六进制数字长的字符串。
  3. 同样地,将@key切成16位数字长的字符串。
  4. 计算@hex_input的每个64位切片与@key的每个64位切片的X-OR,从右侧开始。使用CONV(@slice, 16, 10)。如果@hex_input@key中有一个字符串的切片少于另一个字符串,则将另一个字符串的剩余切片与0进行X-OR
  5. 将点4中X-OR得到的每个64位数字转换回十六进制字符串,使用UNHEX()
  6. 重新组装结果切片。这就是你的结果。

可以使用三列TEMPORARY表作为数组来存储@hex_input@mask和结果切片。

将所有内容放在一个存储过程中,voilà

你似乎在MySQL方面有一些技能,应该能够将上述内容翻译成真正的代码。但如果需要进一步指导,我很乐意提供帮助。


0
上面的转换是正确的吗? 不,操作数的大小不同,如果字符串的大小已知,你已经把密钥的余数给了可能的攻击者。
select HEX(CONV(HEX('a'), 16, 10)  ^  CONV('ACF123456', 16, 10));

返回:

'ACF123437'

输出中明显包含了部分关键内容:

'ACF1234'

剩下的部分:

HEX(HEX('a') ^ 0x56)

如果密钥只被使用一次(一次性密码本),或者数据是固定长度的字符串,或者(非重复密钥长度大于等于数据可能的长度且不知道数据长度不是问题),那么这种解决方案是可以接受的。
但是,如果相同的密钥应用于具有可变长度数据的整个列,统计分析可以被应用于大大减少搜索空间,尤其是如果人们对数据有任何先前的了解。
任何适用于任何字符串的解决方案:
从MySql 8开始,但截至11.3版本的MariaDB,您可以在BINARY()数据类型上使用位运算AND OR XOR NOT(分别为&、|、^、~)操作符,以产生大于64位的结果。
操作数必须具有相同的大小。转换将填充大小差异。
必须注意确保数据和密钥与任何长度差异相同,否则将输出原始数据或密钥,因为任何值与0异或都会得到原始数据。上述问题已经表达出来。
select CAST('a' as BINARY(1)) ^  CAST(0xACF123456 as BINARY(1));

返回一个包含0xCD: 0x61 ^ 0xAC的BINARY(1)。
请注意截断的顺序,是AC而不是56,这可能与其他语言、平台或先前使用(即发布的代码)的预期结果不匹配。如果需要兼容性,请反转字节顺序(0x563412CF0A)。
您可以将结果HEX化:
select HEX(CAST('Hello World!' as BINARY(12)) ^ CAST(0xACF123456ACF123456ACF123 as BINARY(12)));

'E4944F2905EF455B24C09502'
反转(注意上述字符串前面添加的0x):
select CAST(CAST(0xE4944F2905EF455B24C09502 as BINARY(12)) ^ CAST(0xACF123456ACF123456ACF123 as BINARY(12)) as CHAR(12));

'你好世界!'

限制条件

BINARY(n) 大小 n 表示为字节数,因此数据和密钥必须对齐到8位。非对齐的密钥 ACF123456 需要变为 ACF12345600ACF123456 以满足对齐要求。

注意:上述字节反转中的 '0A' 是由 '0x563412CF0A' 中的 '0A' 提供的。

对于已知长度的字符串或动态生成的 SQL 语句,此解决方案非常有效,因为传递给 Binary(size)size 不能是函数或参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接