Implementing SQL CHECKSUM in Java

风流意气都作罢 提交于 2019-12-23 12:42:50

问题


I have an existing database in SQL Server 2008 that performs user authentication via stored procedure for an existing PHP web application. The web application sends the stored procedure a string, however the stored procedure stores, and checks the value with SQL Checksum (http://msdn.microsoft.com/en-us/library/ms189788.aspx). The Stored Procedure casts the string as NVARCHAR(50), and stores the CHECKSUM as int in the user table.

I am now writing a new Java application on top of the existing database, and I'm writing a custom spring authentication manager. I would like to re-implement the CHECKSUM algorithm in Java so I do not need to call a stored procedure to perform the conversion, however I can not find any documentation on how SQL CHECKSUM works.

I tried the following code, with the guess that it was CRC32, however it fails to return the same value as SQL CHECKSUM:

String pass = "foobar";
CRC32 crc32 = new CRC32();
crc32.update(pass.getBytes("UTF-16")); //This is due to the stored procedure casting as nvarchar
crc32.getValue();

Can anyone point me to the algorithm that SQL CHECKSUM uses so I can re-implement it in Java?

The question also isn't which algorithm provides the best hash for security. Security is outside of the requirements in this particular instance, as we are not prepared to force a system wide password reset. The question is what algorithm is used by T-SQL CHECKSUM, so that it could be re-implemented. This particular use case is for auth, however there is potential for this being necessary in many different applications.


回答1:


On SQL Server Forum, at this page, it's stated:

The built-in CHECKUM function in SQL Server is built on a series of 4 bit left rotational xor operations. See this post for more explanation.

I was able to port the BINARY_CHECKSUM to c# (sorry I don't have a Java compiler at hand) and it seems to be working... I'll be looking at the plain CHECKSUM later...

private int SQLBinaryChecksum(string text)
{
    long sum = 0;
    byte overflow;
    for (int i = 0; i < text.Length; i++)
    {
        sum = (long)((16 * sum) ^ Convert.ToUInt32(text[i]));
        overflow = (byte)(sum / 4294967296);
        sum = sum - overflow * 4294967296;
        sum = sum ^ overflow;
    }

    if (sum > 2147483647)
        sum = sum - 4294967296;
    else if (sum >= 32768 && sum <= 65535)
        sum = sum - 65536;
    else if (sum >= 128 && sum <= 255)
        sum = sum - 256;

    return (int)sum;
}



回答2:


I would suggest you to replace TSQL CHECKSUM by HASBYTES with MD5 algorithm so you easily find MD5 implementation in Java.

One more benefit you will get from HASHBYTES is more stable behaviour. CHECKSUM could generate the same hash for different inputs.

See how to use HASHBYTES with MD5:

HASHBYTES('MD5', @input)

EDIT: Answer to comments regarding MD5

HASHBYTES also support both SHA and SHA1 algorithms so no problems if you won't use MD5



来源:https://stackoverflow.com/questions/6892138/implementing-sql-checksum-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!