上面的转换是正确的吗?
不,操作数的大小不同,如果字符串的大小已知,你已经把密钥的余数给了可能的攻击者。
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
需要变为 ACF1234560
或 0ACF123456
以满足对齐要求。
注意:上述字节反转中的 '0A' 是由 '0x563412CF0A' 中的 '0A' 提供的。
对于已知长度的字符串或动态生成的 SQL 语句,此解决方案非常有效,因为传递给 Binary(size)
的 size
不能是函数或参数。