SQL Server提供了Checksum(),Binary_Checksum()和 CHECKSUM_AVG()函数,以根据表达式或列列表构建哈希索引。那么这可以帮助确定行是否已经改变。然后可以使用该机制来识别记录是否已经更新。
但我发现了很多碰撞的例子,它们为不同的值生成相同的哈希值。我们如何识别这些功能的碰撞条件。
任何人都必须知道用于生成/计算哈希的算法或技术。????
答案 0 :(得分:2)
根据sqlTeam上的CHECKSUM weakness explained文章:
SQL Server中的内置CHECKUM函数基于一系列4位左旋转xor运算。
由Peter Larsson发布的forum post from 2006(在文章中也链接)包括计算校验和的SQL用户定义函数。该帖子的作者声称与SQL Server的内置功能100%兼容(我自己没有对其进行过测试)。
如果链接失效,这里是相关部分的副本:
使用text / varchar / image数据,使用SELECTBINARY_CHECKSUM('abcdefghijklmnop')
,dbo.fnPesoBinaryChecksum('abcdefghijklmnop')
进行调用 对于整数数据,请使用SELECT BINARY_CHECKSUM(123)
,dbo.fnPesoBinaryChecksum(CAST(123 AS VARBINARY))
进行通话 我还没弄明白如何计算大于255的整数的校验和。
CREATE FUNCTION dbo.fnPesoBinaryChecksum ( @Data IMAGE ) RETURNS INT AS BEGIN DECLARE @Index INT, @MaxIndex INT, @SUM BIGINT, @Overflow TINYINT SELECT @Index = 1, @MaxIndex = DATALENGTH(@Data), @SUM = 0 WHILE @Index <= @MaxIndex SELECT @SUM = (16 * @SUM) ^ SUBSTRING(@Data, @Index, 1), @Overflow = @SUM / 4294967296, @SUM = @SUM - @Overflow * 4294967296, @SUM = @SUM ^ @Overflow, @Index = @Index + 1 IF @SUM > 2147483647 SET @SUM = @SUM - 4294967296 ELSE IF @SUM BETWEEN 32768 AND 65535 SET @SUM = @SUM - 65536 ELSE IF @SUM BETWEEN 128 AND 255 SET @SUM = @SUM - 256 RETURN @SUM END
实际上这是对MS功能的改进,因为它接受TEXT和IMAGE数据。
CREATE FUNCTION [dbo].[fnPesoTextChecksum] ( @Data TEXT ) RETURNS INT AS BEGIN DECLARE @Index INT, @MaxIndex INT, @SUM BIGINT, @Overflow TINYINT SELECT @Index = 1, @MaxIndex = DATALENGTH(@Data), @SUM = 0 WHILE @Index <= @MaxIndex SELECT @SUM = (16 * @SUM) ^ ASCII(SUBSTRING(@Data, @Index, 1)), @Overflow = @SUM / 4294967296, @SUM = @SUM - @Overflow * 4294967296, @SUM = @SUM ^ @Overflow, @Index = @Index + 1 IF @SUM > 2147483647 SET @SUM = @SUM - 4294967296 ELSE IF @SUM BETWEEN 32768 AND 65535 SET @SUM = @SUM - 65536 ELSE IF @SUM BETWEEN 128 AND 255 SET @SUM = @SUM - 256 RETURN @SUM END
另一个好的读物是Thomas Kejser的Exploring Hash Functions In SQL Server,作者在sql server中检查内置的哈希函数,以提高质量。
答案 1 :(得分:-1)
BINARY_CHECKSUM的PHP实现:
$input = 'binary string';
$sum = 0;
for ($i = 0; $i < strlen($input); $i++) {
$sum = ($sum << 4) ^ ord($in[$i]);
$sum = ($sum & 0xffffffff) ^ ($sum >> 32);
}
return $sum > 0x7fffffff ? $sum - 0x100000000 : $sum;