2015-10-04 10 views
10

मैं दिया लंबाई के साथ यादृच्छिक तार उत्पन्न करने के लिएRNGCryptoServiceProvider का उपयोग कर यादृच्छिक स्ट्रिंग उत्पन्न करने के लिए

public string RandomString(int length) 
{ 
    const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; 
    StringBuilder res = new StringBuilder(); 
    Random rnd = new Random(); 
    while (0 < length--) 
    { 
     res.Append(valid[rnd.Next(valid.Length)]); 
    } 
    return res.ToString(); 
} 

हालांकि इस कोड का उपयोग कर रहा हूँ, मैंने पढ़ा है कि RNGCryptoServiceProviderRandom वर्ग की तुलना में अधिक सुरक्षित है। मैं इस फ़ंक्शन में RNGCryptoServiceProvider कैसे कार्यान्वित कर सकता हूं। इसे इस फ़ंक्शन की तरह valid स्ट्रिंग का उपयोग करना चाहिए।

उत्तर

2

RNGCryptoServiceProvider रिटर्न बाइट्स के रूप में यादृच्छिक संख्या, आप इसे से एक और अधिक सुविधाजनक यादृच्छिक संख्या पाने के लिए एक तरह से की जरूरत है ताकि:

public static int GetInt(RNGCryptoServiceProvider rnd, int max) { 
    byte[] r = new byte[4]; 
    int value; 
    do { 
    rnd.GetBytes(r); 
    value = BitConverter.ToInt32(r, 0) & Int32.MaxValue; 
    } while (value >= max * (Int32.MaxValue/max)); 
    return value % max; 
} 

तो फिर तुम कि आपके विधि में उपयोग कर सकते हैं:

public static string RandomString(int length) { 
    const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; 
    StringBuilder res = new StringBuilder(); 
    using (RNGCryptoServiceProvider rnd = new RNGCryptoServiceProvider()) { 
    while (length-- > 0) { 
     res.Append(valid[GetInt(rnd, valid.Length)]); 
    } 
    } 
    return res.ToString(); 
} 

(मैं, विधि स्थिर बना यह किसी भी उदाहरण डेटा का उपयोग नहीं करता है।)

14

के बाद से RNGRandomNumberGenerator केवल बाइट सरणियों देता है, तो आप इसे एल क्या करना है आइक इस: लेकिन है कि यह एक दोष है

static string RandomString(int length) 
{ 
    const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; 
    StringBuilder res = new StringBuilder(); 
    using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) 
    { 
     byte[] uintBuffer = new byte[sizeof(uint)]; 

     while (length-- > 0) 
     { 
      rng.GetBytes(uintBuffer); 
      uint num = BitConverter.ToUInt32(uintBuffer, 0); 
      res.Append(valid[(int)(num % (uint)valid.Length)]); 
     } 
    } 

    return res.ToString(); 
} 

ध्यान दें, 62 मान्य वर्ण ((2) लॉग (62)/लॉग), तो यह एक 32 पर समान रूप से विभाजित नहीं होगा 5,9541963103868752088061235991756 बिट होते हैं बिट नंबर (यूआईंट)।

इसका क्या परिणाम है? नतीजतन, यादृच्छिक आउटपुट समान नहीं होगा। अक्षरों जो वैध में कम हैं, अधिक संभावना होगी (केवल एक छोटे से अंश से, लेकिन फिर भी ऐसा होता है)।

अधिक सटीक होने के लिए, वैध सरणी के पहले 4 वर्ण 0,00000144354999199840239435286% होने की अधिक संभावना है।

इससे बचने के लिए आप सरणी लंबाई जो समान रूप से 64 (की तरह विभाजित का उपयोग करने के बजाय उत्पादन पर Convert.ToBase64String का उपयोग कर, जब से तुम सफाई से 6 बाइट्स 64 बिट्स से मिलान कर सकते पर विचार करना चाहिए।

+1

जब आप बाइट मानों को किसी विशिष्ट श्रेणी में परिवर्तित करते हैं तो आपको सावधान रहना होगा। यदि आप केवल '%' का उपयोग करते हैं तो यह असमान वितरण के साथ संख्याएं उत्पन्न करेगा, और एक बेहतर यादृच्छिक जनरेटर का उपयोग करने का पूरा उद्देश्य व्यर्थ है। – Guffa

+1

यह सच है, मैं अपना जवाब पोस्ट करने के बाद जोड़ना चाहता था। Tamir Vered का जवाब बहुत दिलचस्प है हालांकि बहुत अक्षम है क्योंकि यह स्ट्रिंगबिल्डर का उपयोग नहीं करता है। यह बाइट्स को इनपुट के रूप में स्वीकार नहीं करता है, जो एक दिलचस्प समाधान है और इसके साथ उचित वितरण होगा – hl3mukkel

2

आप का उपयोग कर यादृच्छिक byte रों उत्पन्न करने के लिए की जरूरत है RNGCryptoServiceProvider और संलग्न वैध लौटे string करने वाले:।

const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; 

static string GetRandomString(int length) 
{ 
    string s = ""; 
    using (RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider()) 
    { 
     while (s.Length != length) 
     { 
      byte[] oneByte = new byte[1]; 
      provider.GetBytes(oneByte); 
      char character = (char)oneByte[0]; 
      if (valid.Contains(character)) 
      { 
       s += character; 
      } 
     } 
    } 
    return s; 
} 

तुम भी अवैध byte मूल्यों को छोड़ नहीं करने के लिए, लेकिन वह हर किरदार के लिए अवसरों को भी नहीं होगा सापेक्ष इस्तेमाल कर सकते हैं

+0

'लम्बाई! = मान्य। लम्बाई' होना चाहिए। लम्बाई! = लंबाई', अन्यथा यह एक स्ट्रिंग बनाता है स्ट्रिंग 'वैध' (और 'लंबाई' पैरामीटर की आवश्यकता है) के समान लंबाई के साथ। – Guffa

+0

हाँ, मुझे नहीं पता था कि वह विधि, संपादन की लंबाई प्रदान करना चाहता है। –

2

मुझे यकीन है कि मैंने सुरक्षित कार्यान्वयन, कोई पूर्वाग्रह और अच्छा प्रदर्शन के साथ पहले इसका जवाब नहीं दिया है। यदि ऐसा है, तो कृपया टिप्पणी करें।

तामीर के जवाब को देखते हुए, मैंने सोचा कि मॉड्यूलस ऑपरेशन का उपयोग करना बेहतर होगा, लेकिन बाइट मूल्यों के अपूर्ण शेष को ट्रिम करें। मैं अब भी इस उत्तर को लिख रहा हूं (संभवतः फिर से), क्योंकि मुझे इस समाधान को एक सहकर्मी को संदर्भित करने की आवश्यकता है।

यह अभी तक परीक्षण नहीं किया गया है, इसलिए कुछ कीड़े हो सकती हैं।

const string lookup = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; 

static string GetRandomString(int length) 
{ 
    if (lookup.Length > 256) 
     throw new Exception("Lookup must be <= 256 characters in length"); 

    var maxMultiples = (int)Math.Floor(256/lookup.Length); 
    var exclusiveLimit = (lookup.Length * maxMultiples); 

    var sb = new StringBuilder(); 
    using (var provider = new RNGCryptoServiceProvider()) 
    { 
     var buffer = new byte[length]; 
     while (true) 
     { 
      var remaining = length - b.Length; 
      if (remaining == 0) 
       break; 

      provider.GetBytes(oneByte, 0 remaining); 

      for (int i = 0; i < remaining) 
      { 
       if (buffer[i] >= exclusiveLimit) 
        continue; 

       var index = buffer[i] % lookup.Length; 
       sb.Append(lookup[index]); 
      } 
     } 
    } 
    return sb.ToString(); 
} 
+0

आह, इसे मिला: https://stackoverflow.com/a/1518495/887092। लेकिन यह अभी भी बेहतर हो सकता है (जब यह परीक्षण हो रहा है और काम करने की पुष्टि की गई है)। कृपया मुझे बताओ। – Todd

0
private string sifreuretimi(int sayı) //3 
    { 
     Random rastgele = new Random(); 
     StringBuilder sb = new StringBuilder(); 
     char karakter1 = ' ', karakter2 = ' ', karakter3 = ' '; 
     int ascii1, ascii2, ascii3 = 0; 

     for (int i = 0; i < sayı/3; i++) 
     { 
      ascii1 = rastgele.Next(48,58); 
      karakter1 = Convert.ToChar(ascii1); 

      ascii2 = rastgele.Next(65, 91); 
      karakter2 = Convert.ToChar(ascii2); 

      ascii3 = rastgele.Next(97, 123); 
      karakter3 = Convert.ToChar(ascii3); 

      sb.Append(karakter1); 
      sb.Append(karakter2); 
      sb.Append(karakter3); 
     } 
     return sb.ToString(); 
    } 
+0

हैलो, कृपया अपने उत्तर की व्याख्या करने के लिए टिप्पणी प्रदान करें; धन्यवाद ! – NatNgs

+0

ऐसे सॉफ़्टवेयर में वर्ण सरणी का उपयोग करना सही दृष्टिकोण नहीं है। –

0

टिप्पणी: मैं ओपी के यूज-केस विचलन के बारे में पता कर रहा हूँ, लेकिन मुझे लगता है कि जो दूसरों एक अलग यूज-केस

एक बहुत के बारे में कहा जा सकता है मदद कर सकता है एक क्रिप्टोग्राफिक बाइट सरणी को एक स्ट्रिंग में परिवर्तित करने के कारण, लेकिन आमतौर पर यह किसी प्रकार के क्रमिक उद्देश्यों के लिए होता है; और इसलिए, उस मामले में: चयनित चरित्र सेट मनमाने ढंग से है।

तो, यदि, और केवल तभी यदि सत्य सत्य है और स्ट्रिंग की लंबाई को अनुकूलित करने की आवश्यकता नहीं है; आप इस तरह से बाइट सरणी के एक सरल हेक्साडेसिमल प्रतिनिधित्व का उपयोग कर सकते हैं:

//note: since the choice of characters [0..9a..zA...Z] is arbitrary, 
//limiting to [0..9,A..F] would seem to be a really big problem if it can be compensated 
//by the length. 

var rnd = new RNGCryptoServiceProvider(); 
var sb = new StringBuilder(); 
var buf = new byte[10]; //length: should be larger 
rnd.GetBytes(buf); 

//gives a "valid" range of: "ABCDEF" 
foreach (byte b in buf) 
    sb.AppendFormat("{0:x2}", b); 

//sb contains a RNGCryptoServiceProvider based "string" 

अब आप कहूँगा: लेकिन इंतजार: इनमें से केवल 16 वर्णों जहां ओपी के अनुक्रम 62. आपका स्ट्रिंग है हो जाएगा एक बहुत लंबे समय तक कर रहे हैं।

"हाँ", मैं जवाब देंगे, "और है कि अगर कोई समस्या है, तुम क्यों 256 आसानी से पढ़ने के लिए और serrializable-वर्ण लेने नहीं है ... या शायद 64"; -)

@Guffa ने कहा; % का उपयोग तब तक प्रतिबंधित है जब तक यह वितरण को परिवर्तित नहीं करता है। ऐसा करने के लिए, समान रूप से वितरित सेट दिया गया है, मूल सेट में सबसेट को x बार फिट होना चाहिए।

तो, 2 के साथ अपने प्रारंभिक वैध सेट को विस्तारित करने से वैध परिणाम मिलता है (क्योंकि: 256/64 = 4)।

कोड होगा:

//note: added + and/chars. could be any of them 
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+/"; 

var rnd = new RNGCryptoServiceProvider(); 
var sb = new StringBuilder(); 
var buf = new byte[10]; //length: should be larger 
rnd.GetBytes(buf); //get the bytes 

foreach (byte b in buf) 
    sb.Append(valid[b%64]); 

कृपया ध्यान दें: इस एक, उप-सेट बाइट की 256 संभावनाओं से छोटी है सहित सभी प्रश्नों के उत्तर, में। इसका मतलब है कि कम जानकारी उपलब्ध है। इसका मतलब है कि यदि आपके पास 4 वर्णों के साथ आपकी स्ट्रिंग है, तो RNGCryptoServiceProvider के मूल 4 बाइट परिणाम को क्रैक करना आसान है।

तो ... अब आप कहते हैं: "64 बेस एन्कोडिंग का उपयोग क्यों नहीं करें?", ठीक है, सूट आप अगर यह है, लेकिन पीछे चल = के साथ सावधान रहना, Base64 on Wikipedia देखें:

var rnd = new RNGCryptoServiceProvider(); 
var buf = new byte[60]; //length not randomly picked, see 64Base, wikipedia 
rnd.GetBytes(buf); 
string result = Convert.ToBase64String(buf); 

कृपया note²: एक ठेठ उपयोग के मामले में कुछ यूआरएल टोकन है। कृपया ध्यान दें कि + साइन इन वर्ण के रूप में अमान्य है।

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

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