sql >> Database teknologi >  >> RDS >> Sqlserver

TSQL md5 hash forskellig fra C# .NET md5

Hvis du har med NVARCHAR at gøre / NCHAR data (som er gemt som UTF-16 Little Endian ), så ville du bruge Unicode kodning, ikke BigEndianUnicode . I .NET hedder UTF-16 Unicode mens andre Unicode-kodninger omtales med deres faktiske navne:UTF7, UTF8 og UTF32. Derfor Unicode i sig selv er Lille Endian i modsætning til BigEndianUnicode . OPDATERING: Se venligst afsnittet i slutningen vedrørende UCS-2 og supplerende tegn.

På databasesiden:

VÆLG HASHBYTES('MD5', N'è') AS [HashBytesNVARCHAR]-- FAC02CD988801F0495D35611223782CF 

På .NET-siden:

System.Text.Encoding.ASCII.GetBytes("è")// D1457B72C3FB323A2671125AEF3EAB5DSystem.Text.Encoding.UTF7.GetBytes("è")// F63A0999FE5999DE5369DE7369.TUTFètes ")// 0A35E149DBBB2D10D744BF675C7744B1System.Text.Encoding.UTF32.GetBytes("è")// 86D29922AC56CF022B639187828137F8System.Text.Encoding.BigEndianUnicode.GetBytes("è")// 407256AC97E4C5AEBCA825DEB3D2E89CSystem.Text.Encoding.Unicode.GetBytes("è") // denne matcher HASHBYTES('MD5', N'è')// FAC02CD988801F0495D35611223782CF 

Dette spørgsmål vedrører dog VARCHAR / CHAR data, som er ASCII, og så tingene er lidt mere komplicerede.

På databasesiden:

VÆLG HASHBYTES('MD5', 'è') SOM [HashBytesVARCHAR]-- 785D512BE4316D578E6650613B45E934 

Vi ser allerede .NET-siden ovenfor. Fra disse hash-værdier burde der være to spørgsmål:

  • Hvorfor ikke nogle af dem matcher HASHBYTES værdi?
  • Hvorfor viser "sqlteam.com"-artiklen, der er linket til i @Eric J.s svar, at tre af dem (ASCII , UTF7 og UTF8 ) matcher alle HASHBYTES værdi?

Der er ét svar, der dækker begge spørgsmål:Kodesider. Testen udført i "sqlteam"-artiklen brugte "sikre" ASCII-tegn, der er i intervallet 0 - 127 (med hensyn til int / decimalværdien), som ikke varierer mellem kodesider. Men intervallet 128 - 255 -- hvor vi finder tegnet "è" -- er Udvidet sæt, der varierer efter kodeside (hvilket giver mening, da dette er grunden til at have kodesider).

Prøv nu:

SELECT HASHBYTES('MD5', 'è' COLLATE SQL_Latin1_General_CP1255_CI_AS) AS [HashBytes]-- D1457B72C3FB323A2671125AEF3EAB5D 

Det matcher ASCII hashed værdi (og igen, fordi "sqlteam" artiklen / testen brugte værdier i intervallet 0 - 127, så de ingen ændringer ved brug af COLLATE ). Godt, nu har vi endelig fundet en måde at matche VARCHAR / CHAR data. Alt godt?

Nå, ikke rigtig. Lad os tage et kig på, hvad vi rent faktisk hash:

VÆLG 'è' AS [TheChar], ASCII('è') AS [TheASCIIvalue], 'è' COLLATE SQL_Latin1_General_CP1255_CI_AS AS [CharCP1255], ASCII('è' COLLATE SQL_Latin1_General_CP1255) [CP12CII5) [CP12CII5]. /kode> 

Returnerer:

TheChar TheASCIIvalue CharCP1255 TheASCIIvalueCP1255è 232 ? 63 

En ? ? Bare for at bekræfte, kør:

VÆLG CHAR(63) AS [WhatIs63?];-- ? 

Ah, så Code Page 1255 har ikke è tegn, så det bliver oversat som alles favorit ? . Men hvorfor matchede det så MD5-hash-værdien i .NET, når du brugte ASCII-kodning? Kunne det være, at vi faktisk ikke matchede den hashed værdi af è , men i stedet matchede den hash-kodede værdi af ? :

VÆLG HASHBYTES('MD5', '?') SOM [HashBytesVARCHAR]-- 0xD1457B72C3FB323A2671125AEF3EAB5D 

Jep. Det ægte ASCII-tegnsæt er kun de første 128 tegn (værdier 0 - 127). Og som vi lige så, è er 232. Så ved at bruge ASCII kodning i .NET er ikke så nyttig. Brugte heller ikke COLLATE på T-SQL-siden.

Er det muligt at få en bedre kodning på .NET-siden? Ja, ved at bruge Encoding.GetEncoding(Int32), som gør det muligt at angive kodesiden. Kodesiden, der skal bruges, kan findes ved hjælp af følgende forespørgsel (brug sys.columns når du arbejder med en kolonne i stedet for en bogstavelig eller variabel):

VÆLG sd.[collation_name], COLLATIONPROPERTY(sd.[collation_name], 'CodePage') SOM [CodePage]FRA sys.databases sdWHERE sd.[navn] =DB_NAME(); -- Erstat funktionen med N'{db_name}', hvis den ikke kører i DB 

Forespørgslen ovenfor returnerer (for mig):

Latin1_General_100_CI_AS_SC 1252 

Så lad os prøve Kode Side 1252:

System.Text.Encoding.GetEncoding(1252).GetBytes("è") // Matcher HASHBYTES('MD5', 'è')// 785D512BE4316D578E6650613B45E934 

Hov hov! Vi har et match til VARCHAR data, der bruger vores standard SQL Server-sortering :). Selvfølgelig, hvis dataene kommer fra en database eller et felt, der er sat til en anden sortering, så GetEncoding(1252) måske ikke virker, og du bliver nødt til at finde den faktiske matchende kodeside ved hjælp af forespørgslen vist ovenfor (en kodeside bruges på tværs af mange sorteringer, så en anden sortering er ikke nødvendigvis antyde en anden kodeside).

For at se, hvad de mulige kodesideværdier er, og hvilken kultur/lokalitet de vedrører, se venligst listen over kodesider her (listen er i afsnittet "Bemærkninger").

Yderligere oplysninger relateret til, hvad der faktisk er gemt i NVARCHAR / NCHAR felter:

Ethvert UTF-16-tegn (2 eller 4 bytes) kan lagres, selvom standardadfærden for de indbyggede funktioner forudsætter, at alle tegn er UCS-2 (2 bytes hver), som er en delmængde af UTF-16. Fra og med SQL Server 2012 er det muligt at få adgang til et sæt Windows-kollationer, der understøtter de 4 byte-tegn kendt som Supplerende tegn. Brug af en af ​​disse Windows-sammenstillinger, der ender på _SC , enten angivet for en kolonne eller direkte i en forespørgsel, vil tillade de indbyggede funktioner at håndtere de 4 byte tegn korrekt.

-- Databasens sortering er indstillet til:SQL_Latin1_General_CP1_CI_ASSELECT N'𨝫' AS [Supplementary Character], LEN(N'𨝫') AS [LEN], DATALENGTH(N'𨝫') AS [DATALENGTH], UNICODE (N'𨝫') AS [UNICODE], LEFT(N'𨝫', 1) AS [LEFT], HASHBYTES('MD5', N'𨝫') AS [HASHBYTES];SELECT N'𨝫' AS [Supplerende tegn] , LEN(N'𨝫' COLLATE Latin1_General_100_CI_AS_SC) AS [LEN], DATALENGTH(N'🨝' COLLATE Latin1_General_100_CI_AS_SC) AS [DATALENGTH], UNICODE(N'𨝫' COLLATE Latin_1_SCODE)'N COLLATE Latin1_General_100_CI_AS_SC, 1) AS [LEFT], HASHBYTES('MD5', N'𨝫' SAMLER Latin1_General_100_CI_AS_SC) AS [HASHBYTES];

Returnerer:

SupplementaryChar LEN DATALENGTH UNICODE LEFT HASHBYTES𨝫 2 4 55393 � 0x7A04F43DA81E3150F539C6B99F4B8FA9💫 1 4 165739 37B504039F69A 37B5040 365739 365739 365739 365739 365739 365739 

Som du kan se, hverken DATALENGTH heller ikke HASHBYTES er ramt. For mere information, se venligst MSDN-siden for Collation og Unicode Support (specifikt afsnittet "Supplerende tegn").



  1. hvordan tildeler man brugerrettigheder på et specifikt skema?

  2. Sådan får du kalenderkvartal fra en dato i TSQL

  3. Implementer en Hybrid Cloud MySQL-database ved hjælp af ClusterControl

  4. Importer XML-filer til PostgreSQL