Sqlserver
 sql >> डेटाबेस >  >> RDS >> Sqlserver

TSQL md5 हैश C# .NET md5 से अलग है

यदि आप NVARCHAR . के साथ काम कर रहे हैं / NCHAR डेटा (जिसे UTF-16 Little Endian . के रूप में संग्रहीत किया जाता है) ), तो आप Unicode . का उपयोग करेंगे एन्कोडिंग, नहीं BigEndianUnicode . .NET में, UTF-16 को Unicode . कहा जाता है जबकि अन्य यूनिकोड एन्कोडिंग को उनके वास्तविक नामों से संदर्भित किया जाता है:UTF7, UTF8, और UTF32। इसलिए, Unicode अपने आप में Little Endian है BigEndianUnicode . के विपरीत . अद्यतन करें: कृपया UCS-2 और पूरक वर्णों से संबंधित अनुभाग को अंत में देखें।

डेटाबेस की तरफ:

SELECT HASHBYTES('MD5', N'è') AS [HashBytesNVARCHAR]
-- FAC02CD988801F0495D35611223782CF

.NET की तरफ:

System.Text.Encoding.ASCII.GetBytes("è")
// D1457B72C3FB323A2671125AEF3EAB5D

System.Text.Encoding.UTF7.GetBytes("è")
// F63A0999FE759C5054613DDE20346193

System.Text.Encoding.UTF8.GetBytes("è")
// 0A35E149DBBB2D10D744BF675C7744B1

System.Text.Encoding.UTF32.GetBytes("è")
// 86D29922AC56CF022B639187828137F8

System.Text.Encoding.BigEndianUnicode.GetBytes("è")
// 407256AC97E4C5AEBCA825DEB3D2E89C

System.Text.Encoding.Unicode.GetBytes("è")  // this one matches HASHBYTES('MD5', N'è')
// FAC02CD988801F0495D35611223782CF

हालाँकि, यह प्रश्न VARCHAR . से संबंधित है / CHAR डेटा, जो ASCII है, और इसलिए चीजें थोड़ी अधिक जटिल हैं।

डेटाबेस की तरफ:

SELECT HASHBYTES('MD5', 'è') AS [HashBytesVARCHAR]
-- 785D512BE4316D578E6650613B45E934

हम ऊपर .NET पक्ष पहले ही देख चुके हैं। उन हैश किए गए मानों से दो प्रश्न होने चाहिए:

  • क्यों नहीं कोई उनमें से HASHBYTES . से मेल खाते हैं मूल्य?
  • @Eric J.'s answer में जुड़ा "sqlteam.com" लेख क्यों दिखाता है कि उनमें से तीन (ASCII , UTF7 , और UTF8 ) सभी HASHBYTES . से मेल खाते हैं मूल्य?

एक उत्तर है जिसमें दोनों प्रश्न शामिल हैं:कोड पृष्ठ। "एसक्यूएलटीम" आलेख में किए गए परीक्षण में "सुरक्षित" ASCII वर्णों का उपयोग किया गया है जो 0 - 127 श्रेणी (इंट/दशमलव मान के संदर्भ में) में हैं जो कोड पेजों के बीच भिन्न नहीं होते हैं। लेकिन 128 - 255 रेंज - जहां हम "è" वर्ण पाते हैं - विस्तारित . है सेट जो कोड पेज के अनुसार अलग-अलग होता है (जो समझ में आता है क्योंकि कोड पेज होने का यही कारण है)।

अब कोशिश करें:

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

यह ASCII . से मेल खाता है हैशेड मान (और फिर से, क्योंकि "sqlteam" लेख / परीक्षण में 0 - 127 श्रेणी में मानों का उपयोग किया गया था, उन्होंने COLLATE का उपयोग करते समय कोई परिवर्तन नहीं देखा। ) बढ़िया, अब हमें अंततः VARCHAR . से मिलान करने का एक तरीका मिल गया है / CHAR जानकारी। सब ठीक?

असल में ऐसा नहीं है। आइए एक नज़र डालते हैं कि हम वास्तव में क्या हैशिंग कर रहे थे:

SELECT 'è' AS [TheChar],
       ASCII('è') AS [TheASCIIvalue],
       'è' COLLATE SQL_Latin1_General_CP1255_CI_AS AS [CharCP1255],
       ASCII('è' COLLATE SQL_Latin1_General_CP1255_CI_AS) AS [TheASCIIvalueCP1255];

रिटर्न:

TheChar TheASCIIvalue   CharCP1255  TheASCIIvalueCP1255
è       232             ?           63

एक ? ? बस सत्यापित करने के लिए, चलाएं:

SELECT CHAR(63) AS [WhatIs63?];
-- ?

आह, इसलिए कोड पेज 1255 में è . नहीं है चरित्र, तो यह हर किसी के पसंदीदा के रूप में अनुवादित हो जाता है ? . लेकिन फिर ASCII एन्कोडिंग का उपयोग करते समय .NET में MD5 हैशेड मान से मिलान क्यों हुआ? क्या ऐसा हो सकता है कि हम वास्तव में è . के हैशेड मान से मेल नहीं खा रहे थे , लेकिन इसके बजाय ? . के हैशेड मान से मेल खा रहे थे :

SELECT HASHBYTES('MD5', '?') AS [HashBytesVARCHAR]
-- 0xD1457B72C3FB323A2671125AEF3EAB5D

हां। सही ASCII वर्ण सेट बस है पहले 128 वर्ण (मान 0 - 127)। और जैसा कि हमने अभी देखा, è 232 है। तो, ASCII . का उपयोग करके .NET में एन्कोडिंग उतना उपयोगी नहीं है। न ही COLLATE . का उपयोग कर रहा था टी-एसक्यूएल की तरफ।

क्या .NET पक्ष पर बेहतर एन्कोडिंग प्राप्त करना संभव है? हाँ, Encoding.GetEncoding(Int32) का उपयोग करके, जो कोड पेज को निर्दिष्ट करने की अनुमति देता है। उपयोग करने के लिए कोड पृष्ठ को निम्न क्वेरी का उपयोग करके खोजा जा सकता है (sys.columns . का उपयोग करें) एक शाब्दिक या चर के बजाय एक स्तंभ के साथ काम करते समय):

SELECT sd.[collation_name],
       COLLATIONPROPERTY(sd.[collation_name], 'CodePage') AS [CodePage]
FROM   sys.databases sd
WHERE  sd.[name] = DB_NAME(); -- replace function with N'{db_name}' if not running in the DB

उपरोक्त क्वेरी रिटर्न (मेरे लिए):

Latin1_General_100_CI_AS_SC    1252

तो, आइए कोड पेज 1252 आज़माएँ:

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

वू हू! हमारे पास VARCHAR . के लिए एक मैच है डेटा जो हमारे डिफ़ॉल्ट SQL सर्वर संयोजन का उपयोग करता है :)। बेशक, यदि डेटा किसी डेटाबेस या फ़ील्ड सेट से किसी भिन्न संयोजन में आ रहा है, तो GetEncoding(1252) हो सकता है काम नहीं करता है और आपको ऊपर दिखाई गई क्वेरी का उपयोग करके वास्तविक मिलान कोड पृष्ठ ढूंढना होगा (एक कोड पृष्ठ कई कॉलेशन में उपयोग किया जाता है, इसलिए एक अलग कोलेशन जरूरी नहीं है एक अलग कोड पेज का संकेत दें)।

यह देखने के लिए कि संभावित कोड पृष्ठ मान क्या हैं, और वे किस संस्कृति/स्थान से संबंधित हैं, कृपया यहां कोड पृष्ठों की सूची देखें (सूची "टिप्पणी" अनुभाग में है)।

जो वास्तव में NVARCHAR में संग्रहीत है, उससे संबंधित अतिरिक्त जानकारी / NCHAR फ़ील्ड:

कोई भी UTF-16 कैरेक्टर (2 या 4 बाइट्स) स्टोर किया जा सकता है, हालांकि बिल्ट-इन फ़ंक्शंस का डिफ़ॉल्ट व्यवहार मानता है कि सभी कैरेक्टर UCS-2 (प्रत्येक 2 बाइट्स) हैं, जो UTF-16 का सबसेट है। SQL सर्वर 2012 से शुरू होकर, विंडोज कॉलेशन के एक सेट तक पहुंचना संभव है जो पूरक वर्णों के रूप में ज्ञात 4 बाइट वर्णों का समर्थन करता है। _SC in में समाप्त होने वाले इन विंडोज़ कॉलेशनों में से किसी एक का उपयोग करना , या तो एक कॉलम के लिए या सीधे एक क्वेरी में निर्दिष्ट, बिल्ट-इन फ़ंक्शंस को 4 बाइट वर्णों को ठीक से संभालने की अनुमति देगा।

-- The database's collation is set to: SQL_Latin1_General_CP1_CI_AS
SELECT  N'𨝫' AS [SupplementaryCharacter],
        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 [SupplementaryCharacter],
        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 Latin1_General_100_CI_AS_SC) AS [UNICODE],
        LEFT(N'𨝫' COLLATE Latin1_General_100_CI_AS_SC, 1) AS [LEFT],
        HASHBYTES('MD5', N'𨝫' COLLATE Latin1_General_100_CI_AS_SC) AS [HASHBYTES];

रिटर्न:

SupplementaryChar   LEN   DATALENGTH   UNICODE   LEFT   HASHBYTES
𨝫                  2     4             55393    �     0x7A04F43DA81E3150F539C6B99F4B8FA9
𨝫                  1     4            165739    𨝫     0x7A04F43DA81E3150F539C6B99F4B8FA9

जैसा कि आप देख सकते हैं, न तो DATALENGTH न ही HASHBYTES प्रभावित कर रहे हैं। अधिक जानकारी के लिए, कृपया कोलेशन और यूनिकोड समर्थन के लिए MSDN पृष्ठ देखें (विशेषकर "सप्लीमेंट्री कैरेक्टर" अनुभाग)।



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. (WHERE) शर्तों के साथ चयनित पंक्तियों से पिछली और अगली पंक्ति प्राप्त करें

  2. SQL सर्वर:PIVOTing String डेटा के उदाहरण

  3. SQL सर्वर मैनेजमेंट स्टूडियो (SSMS) में वर्टिकल ब्लॉक्स को चुनें और संपादित करें - SQL सर्वर / TSQL ट्यूटोरियल पार्ट 9

  4. SQL सर्वर कर्सर प्रकार - डायनेमिक कर्सर | SQL सर्वर ट्यूटोरियल / TSQL ट्यूटोरियल

  5. SQL सर्वर (SSMS) में डेटाबेस के संगतता स्तर की जाँच करें/बदलें