2012-12-11 14 views
21

मैं वर्तमान में guid NEWID() का उपयोग कर रहा हूं लेकिन मुझे पता है कि यह क्रिप्टोग्राफ़िक रूप से सुरक्षित नहीं है।मैं SQL सर्वर में क्रिप्टोग्राफ़िक रूप से सुरक्षित संख्या कैसे उत्पन्न कर सकता हूं?

SQL सर्वर में क्रिप्टोग्राफ़िक रूप से सुरक्षित संख्या उत्पन्न करने का कोई बेहतर तरीका है?

+0

@ इंड्री क्या आप स्पष्ट कर सकते हैं कि आपको क्या कमी है? 'CRYPT_GEN_RANDOM' पूरी तरह से ठीक उत्तर की तरह दिखता है। – CodesInChaos

+0

@CodesInChaos 'CRYPT_GEN_RANDOM' बिल्कुल संख्या उत्पन्न नहीं करता है .. बेशक आप उन्हें Int में परिवर्तित कर सकते हैं, लेकिन क्या लंबाई आवश्यक होगी? उदाहरण के लिए, यदि मुझे 8 अंकों की क्रिप्टोग्राफ़िक रूप से सुरक्षित संख्याएं उत्पन्न करने की आवश्यकता है, तो मैं 'CRYPT_GEN_RANDOM' का उपयोग कैसे कर सकता हूं? इसके अलावा, क्या वे अद्वितीय हैं? –

+0

इसके अलावा मैं 'SQL' में सुरक्षित संख्याएं उत्पन्न करने के किसी भी अन्य तरीके के बारे में उत्सुक हूं। –

उत्तर

11

दिलचस्प सवाल :)

मुझे लगता है कि यह काम करेगा: CRYPT_GEN_RANDOM

+0

ओह, यह एक यादृच्छिक संख्या स्रोत के रूप में भी प्रयोग योग्य है! SQL सर्वर में यादृच्छिक संख्या कठिन हैं। – usr

+0

मुझे इसे अद्वितीय होने की आवश्यकता है। क्या मैं 'कन्वर्ट (int, CRYPT_GEN_RANDOM (9, कन्वर्ट (varbinary, NEWID()) का उपयोग कर सकता हूं))? –

+0

@ user1761123 - शायद अगर आप अपने प्रश्नों में * अपनी सभी आवश्यकताओं को डाल सकते हैं, तो लोगों को इसका जवाब देने का मौका मिल सकता है। अब तक, ऐसा प्रतीत होता है कि इसे अद्वितीय और 'int' आकार होना चाहिए। अब, आप "क्रिप्टोग्राफिक रूप से सुरक्षित" की परिभाषा क्या चाहते हैं कि आप इसका उपयोग करें? क्या यह उदाहरण होना है एक नॉन? –

26

CRYPT_GEN_RANDOM एक "क्रिप्टोग्राफिक यादृच्छिक संख्या" वापस जाने के लिए दर्ज है।

यह 1 और 8000 के बीच एक लंबा पैरामीटर लेता है जो बाइट्स में वापस आने की संख्या की लंबाई है।

लंबाई < = 8 बाइट्स के लिए। इसे सीधे SQL Server integer types में से एक में डाला जा सकता है।

+-----------+------------------+---------+ 
| Data type |  Range  | Storage | 
+-----------+------------------+---------+ 
| bigint | -2^63 to 2^63-1 | 8 Bytes | 
| int  | -2^31 to 2^31-1 | 4 Bytes | 
| smallint | -2^15 to 2^15-1 | 2 Bytes | 
| tinyint | 0 to 255   | 1 Byte | 
+-----------+------------------+---------+ 

उनमें से तीन हस्ताक्षर किए गए पूर्णांक और एक हस्ताक्षरित हैं। निम्नलिखित प्रत्येक अपने संबंधित डेटाटाइप की पूरी श्रृंखला का उपयोग करेंगे।

SELECT 
     CAST(CRYPT_GEN_RANDOM(1) AS TINYINT), 
     CAST(CRYPT_GEN_RANDOM(2) AS SMALLINT), 
     CAST(CRYPT_GEN_RANDOM(4) AS INT), 
     CAST(CRYPT_GEN_RANDOM(8) AS BIGINT) 

डाटाटाइप स्टोरेज की तुलना में कम मूल्य प्रदान करना भी संभव है।

SELECT CAST(CRYPT_GEN_RANDOM(3) AS INT) 

इस मामले में केवल सकारात्मक संख्याएं वापस की जा सकती हैं। साइन बिट हमेशा 0 होगा क्योंकि अंतिम बाइट 0x00 के रूप में माना जाता है। उपरोक्त द्वारा वापस किए जा सकने वाले संभावित संख्याओं की सीमा 0 और POWER(2, 24) - 1 समावेशी के बीच है।

मान लीजिए कि 1 and 250 के बीच कुछ यादृच्छिक संख्या उत्पन्न करने की आवश्यकता है। यह ऐसा करने का

एक संभव तरीका होगा

SELECT (1 + CAST(CRYPT_GEN_RANDOM(1) AS TINYINT) % 250) AS X 
INTO #T 
FROM master..spt_values V1, master..spt_values 

हालांकि इस पद्धति का एक समस्या है।

SELECT COUNT(*),X 
FROM #T 
GROUP BY X 
ORDER BY X 

पहले दस परिणामों की पंक्तियों क्योंकि वहाँ मापांक समारोह उत्पन्न कर सकते हैं कि करने के लिए दो संभावित आदानों हैं दूसरों के रूप में के रूप में नियमित रूप से दो बार उत्पन्न कर रहे हैं (इस मामले 1 -6 में)

+-------+----+ 
| Count | X | 
+-------+----+ 
| 49437 | 1 | 
| 49488 | 2 | 
| 49659 | 3 | 
| 49381 | 4 | 
| 49430 | 5 | 
| 49356 | 6 | 
| 24914 | 7 | 
| 24765 | 8 | 
| 24513 | 9 | 
| 24732 | 10 | 
+-------+----+ 

लोअर नंबर दिए गए हैं उन परिणामों में से प्रत्येक।

एक संभव समाधान सभी नंबरों को निरस्त करने के लिए किया जाएगा> = 250

UPDATE #T 
SET X = CASE 
      WHEN Random >= 250 THEN NULL 
      ELSE (1 + Random % 250) 
      END 
FROM #T 
CROSS APPLY (SELECT CAST(CRYPT_GEN_RANDOM(1) AS TINYINT)) CA (Random) 

यह मेरा मशीन पर काम करने के लिए प्रकट होता है लेकिन यह शायद इसकी गारंटी नहीं है कि SQL सर्वर केवल समारोह एक बार दोनों संदर्भों को भर में Random करने का मूल्यांकन करेंगे CASE अभिव्यक्ति में। इसके अतिरिक्त यह NULL पंक्तियों को ठीक करने के लिए दूसरी और बाद के पास की आवश्यकता की समस्या को छोड़ देता है जहां यादृच्छिक मान को त्याग दिया गया था।

एक स्केलर घोषित करना यूडीएफ उन दोनों मुद्दों को हल कर सकता है।

/*Work around as can't call CRYPT_GEN_RANDOM from a UDF directly*/ 
CREATE VIEW dbo.CRYPT_GEN_RANDOM1 
AS 
SELECT CAST(CRYPT_GEN_RANDOM(1) AS TINYINT) AS Random 

go 


CREATE FUNCTION GET_CRYPT_GEN_RANDOM1() 
RETURNS TINYINT 
AS 
BEGIN 
    DECLARE @Result TINYINT 

    WHILE (@Result IS NULL OR @Result >= 250) 
      /*Not initialised or result to be discarded*/ 
     SELECT @Result = Random FROM dbo.CRYPT_GEN_RANDOM1 

    RETURN @Result 

END 

और फिर

UPDATE #T 
SET X = dbo.GET_CRYPT_GEN_RANDOM1() 

वैकल्पिक रूप से और अधिक सीधे आगे की ओर एक बस

CAST(CRYPT_GEN_RANDOM(8) AS BIGINT) % 250 

आधार पर इस्तेमाल कर सकते हैं कि bigint की सीमा इतनी बड़ी है कि किसी भी पूर्वाग्रह की संभावना नगण्य हो जाएगा । 73,786,976,294,838,208 तरीके हैं जो 1 उत्पन्न किए जा सकते हैं और 73,786,976,294,838,206 249 उपर्युक्त क्वेरी से हो सकते हैं।

यदि यहां तक ​​कि छोटे संभव पूर्वाग्रहों की अनुमति नहीं है तो आप पहले दिखाए गए अनुसार NOT BETWEEN -9223372036854775750 AND 9223372036854775749 किसी भी मूल्य को त्याग सकते हैं।

संबंधित मुद्दे

 संबंधित मुद्दे