T SQL MD5 поколения с UTF8 - PullRequest
       4

T SQL MD5 поколения с UTF8

2 голосов
/ 14 января 2020

У меня есть. NET функция MD5, которая при запуске на «146.185.59.178acu-cell.com» возвращает f36674ed3dbcb151e1c0dfe4acdbb9f5

public static String MD5(String s)
{
    using (var provider = System.Security.Cryptography.MD5.Create())
    {
        StringBuilder builder = new StringBuilder();

        foreach (Byte b in provider.ComputeHash(Encoding.UTF8.GetBytes(s)))
            builder.Append(b.ToString("x2").ToLower());

        return builder.ToString();
    }
}

Я написал тот же код в T SQL, но по какой-то причине только varchar возвращает ожидаемый результат. Nvarchar возвращает другое значение md5: f04b83328560f1bd1c08104b83bc30ea

declare @v varchar(150)   = '146.185.59.178acu-cell.com'
declare @nv nvarchar(150) = '146.185.59.178acu-cell.com'


select LOWER(CONVERT(VARCHAR(32), HashBytes('MD5', @v), 2))  
--f36674ed3dbcb151e1c0dfe4acdbb9f5
select LOWER(CONVERT(VARCHAR(32), HashBytes('MD5',@nv), 2)) 
--f04b83328560f1bd1c08104b83bc30ea

Не уверен, что здесь происходит, потому что я ожидаю, что nvarchar вернет f36674ed3dbcb151e1d2b4505 . NET

Ответы [ 2 ]

1 голос
/ 14 января 2020

Вы получаете разные хэши, потому что двоичное представление текста отличается. Следующий запрос демонстрирует это:

declare @v  varchar(150)  = '146.185.59.178acu-cell.com'
declare @nv nvarchar(150) = '146.185.59.178acu-cell.com'

select convert(varbinary(max), @v)  -- 0x3134362E3138352E35392E3137386163752D63656C6C2E636F6D
select convert(varbinary(max), @nv) -- 0x3100340036002E003100380035002E00350039002E003100370038006100630075002D00630065006C006C002E0063006F006D00

Дополнительные 0 байтов для nvarchar связаны с тем, что это 2-байтовый тип данных Unicode. См. MSDN для получения дополнительной информации о Unicode на SQL сервере.

0 голосов
/ 14 января 2020

Оказывается, мне нужно явно преобразовать NVarChar в UTF8

Нашли этот код на net:

    CREATE FUNCTION [dbo].[fnUTF8] (
    @String NVarChar(max)
) RETURNS VarChar(max) AS BEGIN
    DECLARE  @Result    VarChar(max)
        ,@Counter   Int
        ,@Len       Int
    SELECT   @Result    = ''
        ,@Counter   = 1
        ,@Len       = Len(@String)
    WHILE (@@RowCount > 0)
        SELECT   @Result    = @Result
                    + CASE  WHEN Code < 128     THEN ''
                        WHEN Code < 2048    THEN Char(192 + Code / 64)
                                    ELSE Char(224 + Code / 4096)
                        END
                    + CASE  WHEN Code < 128     THEN Char(Code)
                        WHEN Code < 2048    THEN Char(128 + Code % 64)
                                    ELSE Char(128 + Code / 64 % 64)
                        END
            ,@Counter   = @Counter + 1
        FROM    (SELECT UniCode(SubString(@String,@Counter,1)) AS Code) C
        WHERE   @Counter <= @Len
    RETURN  @Result
END
GO

И теперь я использую это так:

select LOWER(CONVERT(VARCHAR(32), HashBytes('MD5', [dbo].[fnUTF8](@nv)), 2))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...