Perhatikan bahwa Anda TIDAK boleh menggunakan metode apa pun berdasarkan Randomkelas untuk menghasilkan kata sandi. Penyemaian Randomentropi sangat rendah, sehingga tidak benar-benar aman. Gunakan PRNG kriptografi untuk kata sandi.
CodesInChaos
2
Akan menyenangkan untuk memasukkan lokalisasi bahasa dalam pertanyaan ini. Terutama jika gui Anda harus memenuhi kebutuhan orang Cina atau Bulgaria!
Peter Jamsmenson
15
Sesuatu dengan banyak peningkatan ini dan banyak jawaban berkualitas ini tidak layak untuk ditandai sebagai ditutup. Saya memilih itu dibuka kembali.
John Coleman
Jawaban:
1686
Saya mendengar LINQ adalah hitam baru, jadi inilah upaya saya menggunakan LINQ:
privatestaticRandom random =newRandom();publicstaticstringRandomString(int length){conststring chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";returnnewstring(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());}
(Catatan: Penggunaan Randomkelas membuat ini tidak cocok untuk keamanan apa pun yang terkait , seperti membuat kata sandi atau token. Gunakan RNGCryptoServiceProviderkelas jika Anda memerlukan generator nomor acak yang kuat.)
@Alex: Saya sudah menjalankan beberapa tes cepat dan tampaknya skala cukup banyak linear ketika menghasilkan string lebih lama (asalkan sebenarnya ada cukup memori yang tersedia). Karena itu, jawaban Dan Rigby hampir dua kali lebih cepat dari yang ini di setiap tes.
LukeH
6
Baik. Jika kriteria Anda adalah bahwa ia menggunakan LINQ dan bahwa ia memiliki narasi kode buruk maka pasti lutut lebah. Baik narasi kode dan jalur aktual eksekusi agak tidak efisien dan tidak langsung. Jangan salah paham, saya seorang hipster kode besar (saya suka python), tapi ini mesin rberg goldberg.
eremzeit
5
Meskipun ini secara teknis menjawab pertanyaan, hasilnya sangat menyesatkan. Menghasilkan 8 karakter acak sepertinya ada sangat banyak hasil, sedangkan ini yang terbaik menghasilkan 2 miliar hasil yang berbeda. Dan dalam praktiknya bahkan lebih sedikit. Anda juga harus menambahkan peringatan FAT BESAR untuk tidak menggunakan ini untuk hal-hal terkait keamanan apa pun.
CodesInChaos
41
@xaisoft: Huruf kecil dibiarkan sebagai latihan untuk pembaca.
dtb
15
Baris berikut ini lebih banyak memori (dan dengan demikian waktu) lebih efisien daripada yang diberikanreturn new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
Tyson Williams
376
var chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";var stringChars =newchar[8];var random =newRandom();for(int i =0; i < stringChars.Length; i++){
stringChars[i]= chars[random.Next(chars.Length)];}var finalString =newString(stringChars);
Tidak seanggun solusi Linq.
(Catatan: Penggunaan Randomkelas membuat ini tidak cocok untuk keamanan apa pun yang terkait , seperti membuat kata sandi atau token. Gunakan RNGCryptoServiceProviderkelas jika Anda memerlukan generator nomor acak yang kuat.)
@Alex: Ini bukan jawaban tercepat mutlak, tetapi itu adalah jawaban "nyata" tercepat (yaitu, dari mereka yang memungkinkan kontrol atas karakter yang digunakan dan panjang string).
LukeH
2
@Alex: Solusi Adam Porad GetRandomFileNamelebih cepat tetapi tidak memungkinkan kontrol karakter yang digunakan dan panjang maksimal yang mungkin adalah 11 karakter. GuidSolusi Douglas adalah kilat-cepat tetapi karakter dibatasi untuk A-F0-9 dan panjang maksimal yang mungkin adalah 32 karakter.
LukeH
1
@ Adam: Ya, Anda bisa menyetujui hasil dari beberapa panggilan, GetRandomFileNametetapi kemudian (a) Anda akan kehilangan keunggulan kinerja Anda, dan (b) kode Anda akan menjadi lebih rumit.
LukeH
2
@xaisoft buat instance dari objek Random () di luar loop Anda. Jika Anda membuat banyak instance Random () dalam interval pendek maka panggilan ke .Next () akan mengembalikan nilai yang sama seperti Random () menggunakan seed berdasarkan waktu.
Dan Rigby
2
@xaisoft Jangan gunakan jawaban ini untuk keamanan apa pun yang penting, seperti kata sandi. System.Randomtidak cocok untuk keamanan.
CodesInChaos
333
DIPERBARUI berdasarkan komentar. Implementasi asli menghasilkan ah ~ 1,95% dari waktu dan karakter yang tersisa ~ 1,56% dari waktu. Pembaruan menghasilkan semua karakter ~ 1,61% dari waktu.
FRAMEWORK DUKUNGAN -. NET Core 3 (dan platform masa depan yang mendukung .NET Standard 2.1 atau lebih tinggi) memberikan metode suara cryptographically RandomNumberGenerator.GetInt32 () untuk menghasilkan bilangan bulat acak dalam rentang yang diinginkan.
Tidak seperti beberapa alternatif yang disajikan, yang satu ini secara kriptografi masuk akal .
using System;
using System.Security.Cryptography;
using System.Text;
namespace UniqueKey{publicclassKeyGenerator{internalstaticreadonlychar[] chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();publicstaticstringGetUniqueKey(int size){byte[] data =newbyte[4*size];
using (RNGCryptoServiceProvider crypto =newRNGCryptoServiceProvider()){
crypto.GetBytes(data);}StringBuilder result =newStringBuilder(size);for(int i =0; i < size; i++){var rnd =BitConverter.ToUInt32(data, i *4);var idx = rnd % chars.Length;
result.Append(chars[idx]);}return result.ToString();}publicstaticstringGetUniqueKeyOriginal_BIASED(int size){char[] chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();byte[] data =newbyte[size];
using (RNGCryptoServiceProvider crypto =newRNGCryptoServiceProvider()){
crypto.GetBytes(data);}StringBuilder result =newStringBuilder(size);foreach(byte b in data){
result.Append(chars[b %(chars.Length)]);}return result.ToString();}}}
Berdasarkan pembahasan alternatif di sini dan diperbarui / dimodifikasi berdasarkan komentar di bawah ini.
Berikut ini adalah test harness kecil yang menunjukkan distribusi karakter dalam output yang lama dan yang diperbarui. Untuk diskusi mendalam tentang analisis keacakan , lihat random.org.
using System;
using System.Collections.Generic;
using System.Linq;
using UniqueKey;
namespace CryptoRNGDemo{classProgram{constint REPETITIONS =1000000;constint KEY_SIZE =32;staticvoidMain(string[] args){Console.WriteLine("Original BIASED implementation");PerformTest(REPETITIONS, KEY_SIZE,KeyGenerator.GetUniqueKeyOriginal_BIASED);Console.WriteLine("Updated implementation");PerformTest(REPETITIONS, KEY_SIZE,KeyGenerator.GetUniqueKey);Console.ReadKey();}staticvoidPerformTest(int repetitions,int keySize,Func<int,string> generator){Dictionary<char,int> counts =newDictionary<char,int>();foreach(var ch inUniqueKey.KeyGenerator.chars) counts.Add(ch,0);for(int i =0; i < REPETITIONS; i++){var key = generator(KEY_SIZE);foreach(var ch in key) counts[ch]++;}int totalChars = counts.Values.Sum();foreach(var ch inUniqueKey.KeyGenerator.chars){Console.WriteLine($"{ch}: {(100.0 * counts[ch] / totalChars).ToString("#.000")}%");}}}}
Ini terlihat seperti pendekatan yang tepat untuk saya - kata sandi acak, garam, entropi dan sebagainya tidak boleh dihasilkan menggunakan Random () yang dioptimalkan untuk kecepatan dan menghasilkan urutan angka yang dapat direproduksi; RNGCryptoServiceProvider.GetNonZeroBytes () di sisi lain menghasilkan urutan angka liar yang TIDAK dapat direproduksi.
mindplay.dk
25
Huruf-hurufnya sedikit bias (255% 62! = 0). Terlepas dari kekurangan kecil ini, sejauh ini solusi terbaik di sini.
CodesInChaos
13
Perhatikan bahwa ini tidak terdengar jika Anda ingin kekuatan crypto, keacakan tidak bias. (Dan jika Anda tidak menginginkannya maka mengapa harus menggunakan RNGCSPpertama kali?) Menggunakan mod untuk mengindeks ke dalam charsarray berarti bahwa Anda akan mendapatkan output yang bias kecuali chars.Lengthkebetulan menjadi pembagi 256.
LukeH
15
Satu kemungkinan untuk mengurangi bias banyak, adalah meminta 4*maxSizebyte acak, lalu gunakan (UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length. Saya juga akan menggunakan GetBytesbukan GetNonZeroBytes. Dan akhirnya Anda dapat menghapus panggilan pertama ke GetNonZeroBytes. Anda tidak menggunakan hasilnya.
CodesInChaos
14
Fakta menyenangkan: AZ az 0-9 adalah 62 karakter. Orang-orang menunjukkan bias huruf karena 256% 62! = 0. ID video YouTube adalah AZ az 0-9, serta "-" dan "_", yang menghasilkan 64 karakter yang mungkin, yang dibagi menjadi 256 secara merata. Kebetulan? Saya pikir tidak! :)
qJake
200
Solusi 1 - 'rentang' terbesar dengan panjang paling fleksibel
Solusi ini memiliki rentang yang lebih banyak daripada menggunakan GUID karena GUID memiliki beberapa bit tetap yang selalu sama dan karenanya tidak acak, misalnya 13 karakter dalam hex selalu "4" - setidaknya dalam GUID versi 6.
Solusi ini juga memungkinkan Anda menghasilkan string dengan panjang berapa pun.
Solusi 2 - Satu baris kode - baik untuk hingga 22 karakter
Anda tidak dapat membuat string selama Solusi 1 dan string tidak memiliki rentang yang sama karena bit yang diperbaiki di GUID, tetapi dalam banyak kasus ini akan melakukan pekerjaan.
Solusi 3 - Kode sedikit lebih sedikit
Guid.NewGuid().ToString("n").Substring(0,8);
Sebagian besar menyimpan ini di sini untuk tujuan historis. Ini menggunakan kode sedikit lebih sedikit, yang meskipun datang sebagai biaya memiliki rentang kurang - karena menggunakan hex bukan base64 dibutuhkan lebih banyak karakter untuk mewakili kisaran yang sama dibandingkan solusi lain.
Yang berarti lebih banyak peluang tabrakan - mengujinya dengan 100.000 iterasi dari 8 string karakter yang dihasilkan satu duplikat.
Anda benar-benar membuat duplikat? Mengejutkan di 5.316.911.983.139.663.491.615.228.241.121.400.000 kemungkinan kombinasi GUID.
Alex
73
@Alex: Dia memperpendek GUID menjadi 8 karakter, sehingga kemungkinan tabrakan jauh lebih tinggi daripada GUID.
dtb
23
Tidak ada yang bisa menghargai ini selain kutu buku :) Ya Anda memang benar, batas 8 karakter membuat perbedaan.
Alex
31
Guid.NewGuid (). ToString ("n") akan menjaga tanda hubung keluar, tidak perlu panggilan Replace (). Tetapi harus disebutkan, GUID hanya 0-9 dan AF. Jumlah kombinasi "cukup baik," tetapi tidak mendekati apa yang diizinkan oleh string acak alfanumerik yang sebenarnya . Peluang tabrakan adalah 1: 4.294.967.296 - sama dengan bilangan bulat 32-bit acak.
richardtallent
32
1) GUID dirancang untuk menjadi unik, bukan acak. Sementara versi windows saat ini menghasilkan GUID V4 yang memang acak, itu tidak dijamin. Misalnya versi windows yang lebih lama menggunakan GUID V1, di mana Anda bisa gagal. 2) Hanya dengan menggunakan karakter hex mengurangi kualitas string acak secara signifikan. Dari 47 hingga 32 bit. 3) Orang-orang meremehkan probabilitas tabrakan, karena mereka memberikannya untuk pasangan individu. Jika Anda menghasilkan nilai 100k 32 bit, Anda mungkin memiliki satu tabrakan di antaranya. Lihat masalah Ulang Tahun.
CodesInChaos
72
Inilah contoh yang saya curi dari contoh Sam Allen di Dot Net Perls
Jika Anda hanya membutuhkan 8 karakter, gunakan Path.GetRandomFileName () di namespace System.IO. Sam mengatakan menggunakan "Path.GetRandomFileName di sini kadang-kadang lebih unggul, karena menggunakan RNGCryptoServiceProvider untuk keacakan yang lebih baik. Namun, terbatas pada 11 karakter acak."
GetRandomFileName selalu mengembalikan string 12 karakter dengan titik pada karakter ke-9. Jadi, Anda harus menghapus periode (karena itu tidak acak) dan kemudian mengambil 8 karakter dari string. Sebenarnya, Anda bisa mengambil 8 karakter pertama dan tidak khawatir tentang periode.
Ini bekerja dengan baik. Saya menjalankannya melalui 100.000 iterasi dan tidak pernah memiliki nama duplikat. Namun, saya memang menemukan beberapa kata vulgar (dalam bahasa Inggris). Bahkan tidak akan memikirkan hal ini kecuali salah satu yang pertama dalam daftar memiliki F *** di dalamnya. Hanya kepala jika Anda menggunakan ini untuk sesuatu yang akan dilihat pengguna.
techturtle
3
@turturtle Terima kasih atas peringatannya. Saya kira ada risiko untuk kata-kata vulgar dengan generasi string acak yang menggunakan semua huruf dalam alfabet.
Adam Porad
bagus dan sederhana tetapi tidak bagus untuk string panjang ... pilih trik yang bagus ini
Maher Abuthraa
Metode ini tampaknya hanya mengembalikan string alfanumerik huruf kecil.
jaybro
2
Ada kata-kata vulgar dari waktu ke waktu, tetapi jika Anda menjaga ini berjalan cukup lama pada akhirnya itu menulis Shakespeare. (Hanya beberapa masa kehidupan alam semesta. :)
Slothario
38
Tujuan utama kode saya adalah:
Distribusi string hampir seragam (tidak peduli dengan penyimpangan kecil, asalkan kecil)
Ini menghasilkan lebih dari beberapa miliar string untuk setiap set argumen. Menghasilkan string 8 karakter (~ 47 bit entropi) tidak ada artinya jika PRNG Anda hanya menghasilkan 2 miliar (31 bit entropi) nilai yang berbeda.
Ini aman, karena saya berharap orang menggunakan ini untuk kata sandi atau token keamanan lainnya.
Properti pertama dicapai dengan mengambil modulo nilai alfabet 64 bit. Untuk huruf kecil (seperti 62 karakter dari pertanyaan) ini menyebabkan bias diabaikan. Properti kedua dan ketiga dicapai dengan menggunakan RNGCryptoServiceProvideralih-alih System.Random.
using System;
using System.Security.Cryptography;publicstaticstringGetRandomAlphanumericString(int length){conststring alphanumericCharacters ="ABCDEFGHIJKLMNOPQRSTUVWXYZ"+"abcdefghijklmnopqrstuvwxyz"+"0123456789";returnGetRandomString(length, alphanumericCharacters);}publicstaticstringGetRandomString(int length,IEnumerable<char> characterSet){if(length <0)thrownewArgumentException("length must not be negative","length");if(length >int.MaxValue/8)// 250 million chars ought to be enough for anybodythrownewArgumentException("length is too big","length");if(characterSet ==null)thrownewArgumentNullException("characterSet");var characterArray = characterSet.Distinct().ToArray();if(characterArray.Length==0)thrownewArgumentException("characterSet must not be empty","characterSet");var bytes =newbyte[length *8];var result =newchar[length];
using (var cryptoProvider =newRNGCryptoServiceProvider()){
cryptoProvider.GetBytes(bytes);}for(int i =0; i < length; i++){ulongvalue=BitConverter.ToUInt64(bytes, i *8);
result[i]= characterArray[value%(uint)characterArray.Length];}returnnewstring(result);}
Tidak ada persimpangan dengan 64 x Z dan Math.Pow (2, Y). Jadi, sementara membuat angka yang lebih besar mengurangi bias, itu tidak menghilangkannya. Saya memperbarui jawaban saya di bawah, pendekatan saya adalah membuang input acak dan mengganti dengan nilai lain.
Todd
@Todd Saya tahu itu tidak menghilangkan bias, tapi saya memilih kesederhanaan dari solusi ini daripada menghilangkan bias yang secara praktis tidak relevan.
CodesInChaos
Saya setuju untuk sebagian besar kasus itu mungkin praktis tidak relevan. Tapi sekarang saya sudah memperbarui milik saya menjadi secepat Acak dan sedikit lebih aman dari milik Anda. Semua sumber terbuka untuk semua orang untuk berbagi. Ya, saya terlalu banyak membuang waktu dalam hal ini ...
Todd
Jika kita menggunakan penyedia RNG apakah kita punya cara untuk menghindari bias secara teori? Saya tidak yakin ... Jika Todd memaksudkan cara ketika dia menghasilkan angka acak tambahan (ketika kita berada di zona bias) maka itu bisa menjadi asumsi yang salah. RNG memiliki distribusi hampir linier dari semua nilai yang dihasilkan dalam rata-rata. Tetapi itu tidak berarti bahwa kita tidak akan memiliki korelasi lokal antara byte yang dihasilkan. Jadi byte tambahan hanya untuk zona bias masih dapat memberi kita beberapa bias tetapi karena alasan yang berbeda. Kemungkinan besar bias ini akan sangat kecil. TETAPI dalam hal ini peningkatan total byte yang dihasilkan lebih mudah.
Maxim
1
@ Maxim Anda dapat menggunakan penolakan untuk sepenuhnya menghilangkan bias (dengan asumsi generator yang mendasari adalah acak sempurna). Sebagai gantinya kode mungkin berjalan lama sewenang-wenang (dengan probabilitas kecil secara eksponensial).
Jika Anda khawatir huruf-huruf bahasa Inggris dapat berubah sewaktu-waktu dan Anda mungkin kehilangan bisnis, maka Anda dapat menghindari pengkodean yang sulit, tetapi harus berkinerja sedikit lebih buruk (sebanding dengan Path.GetRandomFileNamependekatan)
publicstaticstringGetRandomAlphaNumeric(){var chars ='a'.To('z').Concat('0'.To('9')).ToList();returnnewstring(chars.Select(c => chars[random.Next(chars.Length)]).Take(8).ToArray());}publicstaticIEnumerable<char>To(thischar start,char end){if(end < start)thrownewArgumentOutOfRangeException("the end char should not be less than start char", innerException:null);returnEnumerable.Range(start, end - start +1).Select(i =>(char)i);}
Dua pendekatan terakhir terlihat lebih baik jika Anda dapat menjadikannya metode ekstensi secara System.Randominstan.
Penggunaannya chars.Selectsangat jelek karena bergantung pada ukuran output paling banyak ukuran alfabet.
CodesInChaos
@CodesInChaos Saya tidak yakin apakah saya mengerti Anda. Maksud Anda dalam 'a'.To('z')pendekatan?
nawfal
1
1) chars.Select().Ambil (n) `hanya berfungsi jika chars.Count >= n. Memilih pada urutan yang sebenarnya tidak Anda gunakan agak tidak intuitif, terutama dengan batasan panjang implisit. Saya lebih suka menggunakan Enumerable.Rangeatau Enumerable.Repeat. 2) Pesan kesalahan "char akhir harus kurang dari start char" adalah cara yang salah bulat / hilang a not.
CodesInChaos
@ CodeInChaos tetapi dalam kasus saya chars.Countadalah cara > n. Saya juga tidak mendapatkan bagian yang tidak intuitif. Itu membuat semua penggunaan Taketidak intuitif bukan? Saya tidak percaya itu. Terima kasih telah menunjukkan kesalahan ketik.
Diuji dalam LinqPad. Untuk ukuran string 10, menghasilkan:
dari Linq = chdgmevhcy [10]
dari Loop = gtnoaryhxr [10]
dari Select = rsndbztyby [10]
dari GenerateRandomString = owyefjjakj [10]
dari SecureFastRandom = VzougLYHYP [10]
dari SecureFastRandom-NoCache = oVQXNGmO1S [10]
Dan angka kinerja cenderung sedikit berbeda, sangat kadang NonOptimized- kadang sebenarnya lebih cepat, dan kadang ForLoop- kadang dan GenerateRandomStringberalih siapa yang memimpin.
LinqIsTheNewBlack (10000x) = 96762 kutu telah berlalu (9,672 ms)
Akan menarik untuk mengetahui mana yang dibuat dupes.
Rebecca
@Junto - untuk mencari tahu yang menghasilkan duplikat, seperti var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());, di mana Anda ganti EachRandomizingMethoddengan ... masing-masing metode
Saya memikirkan hal itu tetapi tidak bisa menghilangkan karakter non alfanumerik karena argumen ke-2 adalah MINIMUM karakter non alpha
ozzy432836
13
Kode yang ditulis oleh Eric J. cukup ceroboh (cukup jelas bahwa itu dari 6 tahun yang lalu ... dia mungkin tidak akan menulis kode itu hari ini), dan bahkan ada beberapa masalah.
Tidak seperti beberapa alternatif yang disajikan, yang satu ini secara kriptografi masuk akal.
Tidak Benar ... Ada bias dalam kata sandi (seperti yang ditulis dalam komentar), bcdefghsedikit lebih mungkin daripada yang lain ( abukan karena GetNonZeroBytestidak menghasilkan byte dengan nilai nol, jadi bias untuk aitu diimbangi dengan itu), jadi itu tidak benar-benar terdengar kriptografis.
Ini harus memperbaiki semua masalah.
publicstaticstringGetUniqueKey(int size =6,string chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"){
using (var crypto =newRNGCryptoServiceProvider()){var data =newbyte[size];// If chars.Length isn't a power of 2 then there is a bias if// we simply use the modulus operator. The first characters of// chars will be more probable than the last ones.// buffer used if we encounter an unusable random byte. We will// regenerate it in this bufferbyte[] smallBuffer =null;// Maximum random number that can be used without introducing a// biasint maxRandom =byte.MaxValue-((byte.MaxValue+1)% chars.Length);
crypto.GetBytes(data);var result =newchar[size];for(int i =0; i < size; i++){byte v = data[i];while(v > maxRandom){if(smallBuffer ==null){
smallBuffer =newbyte[1];}
crypto.GetBytes(smallBuffer);
v = smallBuffer[0];}
result[i]= chars[v % chars.Length];}returnnewstring(result);}}
Pertanyaan: Mengapa saya harus membuang-buang waktu menggunakan Enumerable.Rangedaripada mengetik "ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"?
using System;
using System.Collections.Generic;
using System.Linq;publicclassTest{publicstaticvoidMain(){var randomCharacters =GetRandomCharacters(8,true);Console.WriteLine(newstring(randomCharacters.ToArray()));}privatestaticList<char> getAvailableRandomCharacters(bool includeLowerCase){var integers =Enumerable.Empty<int>();
integers = integers.Concat(Enumerable.Range('A',26));
integers = integers.Concat(Enumerable.Range('0',10));if( includeLowerCase )
integers = integers.Concat(Enumerable.Range('a',26));return integers.Select(i =>(char)i).ToList();}publicstaticIEnumerable<char>GetRandomCharacters(int count,bool includeLowerCase){var characters = getAvailableRandomCharacters(includeLowerCase);var random =newRandom();var result =Enumerable.Range(0, count).Select(_ => characters[random.Next(characters.Count)]);return result;}}
Jawab: Senar ajaib itu BURUK. Apa ada yang memperhatikan?I " tali saya di atas? Ibu saya mengajari saya untuk tidak menggunakan string sihir karena alasan ini ...
nb 1: Seperti yang dikatakan banyak orang seperti @dtb, jangan gunakan System.Randomjika Anda membutuhkan keamanan kriptografis ...
nb 2: Jawaban ini bukan yang paling efisien atau terpendek, tetapi saya ingin ruang untuk memisahkan jawaban dari pertanyaan. Tujuan dari jawaban saya lebih untuk memperingatkan terhadap string sihir daripada memberikan jawaban inovatif yang mewah.
Alfanumerik (kasus abaikan) adalah [A-Z0-9]. Jika, secara tidak sengaja, string acak Anda hanya menutupi [A-HJ-Z0-9]hasil tidak mencakup rentang yang diijinkan penuh, yang mungkin bermasalah.
Wai Ha Lee
Bagaimana itu bisa menjadi masalah? Jadi itu tidak mengandung I. Apakah karena ada satu karakter yang kurang dan itu membuatnya lebih mudah untuk retak? Apa statistik pada kata sandi yang dapat dipecahkan yang berisi 35 karakter dalam kisaran dari 36. Saya pikir saya lebih suka mengambil risiko ... atau hanya membuktikan buluh rentang karakter ... daripada memasukkan semua sampah ekstra dalam kode saya. Tapi itu aku. Maksudku, bukan untuk menjadi lubang pantat, aku hanya mengatakan. Kadang-kadang saya pikir programmer cenderung menempuh rute ekstra-kompleks demi menjadi ekstra-kompleks.
Christine
1
Itu tergantung pada use case. Sangat umum untuk mengecualikan karakter seperti Idan Odari jenis string acak ini untuk menghindari manusia membingungkan mereka dengan 1dan 0. Jika Anda tidak peduli tentang memiliki string yang dapat dibaca manusia, baik, tetapi jika itu adalah sesuatu yang seseorang perlu ketik, maka sebenarnya pintar untuk menghapus karakter tersebut.
Chris Pratt
5
Versi solusi DTB yang sedikit lebih bersih.
var chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";var random =newRandom();varlist=Enumerable.Repeat(0,8).Select(x=>chars[random.Next(chars.Length)]);returnstring.Join("",list);
Setelah meninjau jawaban lain dan mempertimbangkan komentar CodeInChaos, bersama dengan CodeInChaos masih bias (walaupun kurang) jawaban, saya pikir diperlukan solusi final cut and paste . Jadi, sementara memperbarui jawaban saya, saya memutuskan untuk keluar semua.
Berkaitan dengan beberapa jawaban lain - Jika Anda mengetahui panjang output, Anda tidak memerlukan StringBuilder, dan saat menggunakan ToCharArray, ini membuat dan mengisi array (Anda tidak perlu membuat array kosong terlebih dahulu)
Berkaitan dengan beberapa jawaban lain - Anda harus menggunakan NextBytes, daripada mendapatkan satu per satu untuk kinerja
Secara teknis Anda dapat menyematkan array byte untuk akses yang lebih cepat .. biasanya layak jika iterasi Anda lebih dari 6-8 kali melalui array byte. (Tidak dilakukan di sini)
Penggunaan RNGCryptoServiceProvider untuk keacakan terbaik
Penggunaan caching buffer data acak 1MB - pembandingan menunjukkan kecepatan akses byte tunggal yang di-cache ~ 1000x lebih cepat - mengambil 9ms lebih dari 1MB vs 989ms untuk tidak di-cache.
Penolakan zona bias dioptimalkan di dalam kelas baru saya.
Solusi akhir untuk pertanyaan:
staticchar[] charSet ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();staticint byteSize =256;//Labelling conveniencestaticint biasZone = byteSize -(byteSize % charSet.Length);publicstringGenerateRandomString(intLength)//Configurable output string length{byte[] rBytes =newbyte[Length];//Do as much before and after lock as possiblechar[] rName =newchar[Length];SecureFastRandom.GetNextBytesMax(rBytes, biasZone);for(var i =0; i <Length; i++){
rName[i]= charSet[rBytes[i]% charSet.Length];}returnnewstring(rName);}
Tetapi Anda membutuhkan kelas baru saya (yang belum diuji):
/// <summary>/// My benchmarking showed that for RNGCryptoServiceProvider:/// 1. There is negligable benefit of sharing RNGCryptoServiceProvider object reference /// 2. Initial GetBytes takes 2ms, and an initial read of 1MB takes 3ms (starting to rise, but still negligable)/// 2. Cached is ~1000x faster for single byte at a time - taking 9ms over 1MB vs 989ms for uncached/// </summary>classSecureFastRandom{staticbyte[] byteCache =newbyte[1000000];//My benchmark showed that an initial read takes 2ms, and an initial read of this size takes 3ms (starting to raise)staticint lastPosition =0;staticint remaining =0;/// <summary>/// Static direct uncached access to the RNGCryptoServiceProvider GetBytes function/// </summary>/// <param name="buffer"></param>publicstaticvoidDirectGetBytes(byte[] buffer){
using (var r =newRNGCryptoServiceProvider()){
r.GetBytes(buffer);}}/// <summary>/// Main expected method to be called by user. Underlying random data is cached from RNGCryptoServiceProvider for best performance/// </summary>/// <param name="buffer"></param>publicstaticvoidGetBytes(byte[] buffer){if(buffer.Length> byteCache.Length){DirectGetBytes(buffer);return;}lock(byteCache){if(buffer.Length> remaining){DirectGetBytes(byteCache);
lastPosition =0;
remaining = byteCache.Length;}Buffer.BlockCopy(byteCache, lastPosition, buffer,0, buffer.Length);
lastPosition += buffer.Length;
remaining -= buffer.Length;}}/// <summary>/// Return a single byte from the cache of random data./// </summary>/// <returns></returns>publicstaticbyteGetByte(){lock(byteCache){returnUnsafeGetByte();}}/// <summary>/// Shared with public GetByte and GetBytesWithMax, and not locked to reduce lock/unlocking in loops. Must be called within lock of byteCache./// </summary>/// <returns></returns>staticbyteUnsafeGetByte(){if(1> remaining){DirectGetBytes(byteCache);
lastPosition =0;
remaining = byteCache.Length;}
lastPosition++;
remaining--;return byteCache[lastPosition -1];}/// <summary>/// Rejects bytes which are equal to or greater than max. This is useful for ensuring there is no bias when you are modulating with a non power of 2 number./// </summary>/// <param name="buffer"></param>/// <param name="max"></param>publicstaticvoidGetBytesWithMax(byte[] buffer,byte max){if(buffer.Length> byteCache.Length/2)//No point caching for larger sizes{DirectGetBytes(buffer);lock(byteCache){UnsafeCheckBytesMax(buffer, max);}}else{lock(byteCache){if(buffer.Length> remaining)//Recache if not enough remaining, discarding remaining - too much work to join two blocksDirectGetBytes(byteCache);Buffer.BlockCopy(byteCache, lastPosition, buffer,0, buffer.Length);
lastPosition += buffer.Length;
remaining -= buffer.Length;UnsafeCheckBytesMax(buffer, max);}}}/// <summary>/// Checks buffer for bytes equal and above max. Must be called within lock of byteCache./// </summary>/// <param name="buffer"></param>/// <param name="max"></param>staticvoidUnsafeCheckBytesMax(byte[] buffer,byte max){for(int i =0; i < buffer.Length; i++){while(buffer[i]>= max)
buffer[i]=UnsafeGetByte();//Replace all bytes which are equal or above max}}}
Untuk riwayat - solusi lama saya untuk jawaban ini, menggunakan objek acak:
privatestaticchar[] charSet ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();static rGen =newRandom();//Must share, because the clock seed only has Ticks (~10ms) resolution, yet lock has only 20-50ns delay.staticint byteSize =256;//Labelling conveniencestaticint biasZone = byteSize -(byteSize % charSet.Length);staticboolSlightlyMoreSecurityNeeded=true;//Configuration - needs to be true, if more security is desired and if charSet.Length is not divisible by 2^X.publicstringGenerateRandomString(intLength)//Configurable output string length{byte[] rBytes =newbyte[Length];//Do as much before and after lock as possiblechar[] rName =newchar[Length];lock(rGen)//~20-50ns{
rGen.NextBytes(rBytes);for(int i =0; i <Length; i++){while(SlightlyMoreSecurityNeeded&& rBytes[i]>= biasZone)//Secure against 1/5 increased bias of index[0-7] values against others. Note: Must exclude where it == biasZone (that is >=), otherwise there's still a bias on index 0.
rBytes[i]= rGen.NextByte();
rName[i]= charSet[rBytes[i]% charSet.Length];}}returnnewstring(rName);}
Kinerja:
SecureFastRandom - Jalankan tunggal pertama = ~ 9-33ms . Tak kelihatan. Sedang berjalan : 5 ms (kadang-kadang naik hingga 13 ms) lebih dari 10.000 iterasi, Dengan iterasi rata-rata tunggal = 1,5 mikrodetik. . Catatan: Membutuhkan umumnya 2, tetapi kadang-kadang hingga 8 cache menyegarkan - tergantung pada berapa banyak byte tunggal melebihi zona bias
Acak - Menjalankan tunggal pertama = ~ 0-1ms . Tak kelihatan. Sedang berlangsung : 5ms lebih dari 10.000 iterasi. Dengan iterasi rata-rata tunggal = 0,5 mikrodetik. . Tentang kecepatan yang sama.
Tautan ini adalah pendekatan lain. Buffering dapat ditambahkan ke basis kode baru ini, tetapi yang paling penting adalah mengeksplorasi berbagai pendekatan untuk menghilangkan bias, dan membandingkan kecepatan dan pro / kontra.
1) Mengapa semua konstanta ajaib itu? Anda menetapkan panjang output tiga kali. Cukup definisikan sebagai konstanta atau parameter. Anda bisa menggunakan charSet.Lengthbukan 62. 2) Statis Randomtanpa penguncian berarti kode ini bukan threadsafe. 3) mengurangi 0-255 mod 62 memperkenalkan bias yang terdeteksi. 4) Anda tidak dapat menggunakan ToStringarray char, yang selalu kembali "System.Char[]". Anda harus menggunakannya new String(rName)sebagai gantinya.
CodesInChaos
Terima kasih @CodesInChaos, saya tidak pernah memikirkan hal-hal itu saat itu. Masih hanya menggunakan kelas acak, tetapi ini harus lebih baik. Saya tidak bisa memikirkan cara yang lebih baik untuk mendeteksi dan mengoreksi input bias.
Todd
Agak konyol untuk memulai dengan RNG yang lemah ( System.Random) dan kemudian dengan hati-hati menghindari bias dalam kode Anda sendiri. Ungkapan "memoles kotoran" muncul di pikiran.
CodesInChaos
@CodesInChaos Dan sekarang murid magang telah melampaui tuannya
Todd
4
Mengerikan, aku tahu, tapi aku tidak bisa menahan diri:
namespace ConsoleApplication2{
using System;
using System.Text.RegularExpressions;classProgram{staticvoidMain(string[] args){Random adomRng =newRandom();string rndString =string.Empty;char c;for(int i =0; i <8; i++){while(!Regex.IsMatch((c=Convert.ToChar(adomRng.Next(48,128))).ToString(),"[A-Za-z0-9]"));
rndString += c;}Console.WriteLine(rndString +Environment.NewLine);}}}
Saya mencari jawaban yang lebih spesifik, di mana saya ingin mengontrol format string acak dan menemukan posting ini. Sebagai contoh: plat nomor (mobil) memiliki format tertentu (per negara) dan saya ingin membuat plat nomor acak.
Saya memutuskan untuk menulis metode ekstensi Acak saya sendiri untuk ini. (ini untuk menggunakan kembali objek acak yang sama, karena Anda bisa memiliki dua kali lipat dalam skenario multi-threading). Saya membuat intisari ( https://gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), tetapi juga akan menyalin kelas ekstensi di sini:
voidMain(){Random rnd =newRandom();
rnd.GetString("1-###-000").Dump();}publicstaticclassRandomExtensions{publicstaticstringGetString(thisRandom random,string format){// Based on http://stackoverflow.com/questions/1344221/how-can-i-generate-random-alphanumeric-strings-in-c// Added logic to specify the format of the random string (# will be random string, 0 will be random numeric, other characters remain)StringBuilder result =newStringBuilder();for(int formatIndex =0; formatIndex < format.Length; formatIndex++){switch(format.ToUpper()[formatIndex]){case'0': result.Append(getRandomNumeric(random));break;case'#': result.Append(getRandomCharacter(random));break;default: result.Append(format[formatIndex]);break;}}return result.ToString();}privatestaticchar getRandomCharacter(Random random){string chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";return chars[random.Next(chars.Length)];}privatestaticchar getRandomNumeric(Random random){string nums ="0123456789";return nums[random.Next(nums.Length)];}}
Menggunakan properti untuk sesuatu yang berubah pada setiap akses agak meragukan. Saya akan merekomendasikan menggunakan metode sebagai gantinya.
CodesInChaos
2
RNGCryptoServiceProviderharus dibuang setelah digunakan.
Tsahi Asher
Saya memperbaiki masalah IDisposable, tetapi ini masih sangat meragukan, membuat RNGCryptoServiceProvider baru untuk setiap surat.
piojo
@CodesInChaos selesai, sekarang menjadi metode.
Matas Vaitkevicius
3
Cobalah untuk menggabungkan dua bagian: unik (urutan, penghitung atau tanggal) dan acak
publicclassRandomStringGenerator{publicstaticstringGen(){returnConvertToBase(DateTime.UtcNow.ToFileTimeUtc())+GenRandomStrings(5);//keep length fixed at least of one part}privatestaticstringGenRandomStrings(int strLen){var result =string.Empty;varGen=newRNGCryptoServiceProvider();var data =newbyte[1];while(result.Length< strLen){Gen.GetNonZeroBytes(data);int code = data[0];if(code >48&& code <57||// 0-9
code >65&& code <90||// A-Z
code >97&& code <122// a-z){
result +=Convert.ToChar(code);}}return result;}privatestaticstringConvertToBase(long num,int nbase =36){var chars ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//if you wish make algorithm more secure - change order of letter here// check if we can convert to another baseif(nbase <2|| nbase > chars.Length)returnnull;int r;var newNumber =string.Empty;// in r we have the offset of the char that was converted to the new basewhile(num >= nbase){
r =(int)(num % nbase);
newNumber = chars[r]+ newNumber;
num = num / nbase;}// the last number to convert
newNumber = chars[(int)num]+ newNumber;return newNumber;}}
1) Anda dapat menggunakan literal karakter alih-alih nilai ASCII yang terkait dengan karakter tersebut. 2) Anda memiliki kesalahan satu-per-satu dalam kode pencocokan interval Anda. Anda harus menggunakan <=dan >=bukannya <dan >. 3) Saya akan menambahkan tanda kurung yang tidak perlu di sekitar &&ekspresi untuk memperjelas bahwa mereka memiliki prioritas, tetapi tentu saja itu hanya pilihan gaya.
CodesInChaos
+1 Baik untuk menghapus bias dan menambahkan pengujian. Saya tidak yakin mengapa Anda menambahkan string acak Anda dengan string yang berasal dari timestamp? Selain itu, Anda masih harus membuang RNGCryptoServiceProvider Anda
monty
2
Solusi tanpa menggunakan Random:
var chars =Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",8);var randomStr =newstring(chars.SelectMany(str => str).OrderBy(c =>Guid.NewGuid()).Take(8).ToArray());
NewGuid menggunakan acak secara internal. Jadi ini masih menggunakan acak, hanya menyembunyikannya.
Wedge
2
Berikut ini adalah varian dari solusi Eric J, yaitu suara kriptografis, untuk WinRT (Aplikasi Windows Store):
publicstaticstringGenerateRandomString(int length){var chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";var result =newStringBuilder(length);for(int i =0; i < length;++i){
result.Append(CryptographicBuffer.GenerateRandomNumber()% chars.Length);}return result.ToString();}
Jika kinerja penting (terutama ketika panjangnya tinggi):
publicstaticstringGenerateRandomString(int length){var chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";var result =newSystem.Text.StringBuilder(length);var bytes =CryptographicBuffer.GenerateRandom((uint)length *4).ToArray();for(int i =0; i < bytes.Length; i +=4){
result.Append(BitConverter.ToUInt32(bytes, i)% chars.Length);}return result.ToString();}
Ini tidak terdengar secara kriptografis. Ada bias kecil karena operasi modulus tidak menyebarkan seluruh lebar ulong secara merata menjadi 62 karakter.
Lie Ryan
1
Saya tahu ini bukan cara terbaik. Tetapi Anda dapat mencoba ini.
string str =Path.GetRandomFileName();//This method returns a random file name of 11 characters
str = str.Replace(".","");Console.WriteLine("Random string: "+ str);
Bagaimana itu satu baris? Console.WriteLine ($ "String acak: {Path.GetRandomFileName (). Ganti (". "," "")} "); adalah satu baris.
PmanAce
1
Saya tidak tahu bagaimana suara ini secara kriptografis, tetapi ini lebih mudah dibaca dan ringkas daripada solusi yang lebih rumit (imo), dan itu harus lebih "acak" daripada System.Randomsolusi berbasis.
Memang, itu tidak dioptimalkan untuk kecepatan, jadi jika itu penting untuk menghasilkan jutaan string acak setiap detik, coba yang lain!
CATATAN: Solusi ini tidak memungkinkan pengulangan simbol dalam alfabet, dan alfabet HARUS berukuran sama atau lebih besar dari string output, membuat pendekatan ini kurang diinginkan dalam beberapa keadaan, semuanya tergantung pada use-case Anda.
Jika nilai-nilai Anda tidak sepenuhnya acak, tetapi sebenarnya mungkin tergantung pada sesuatu - Anda dapat menghitung hash md5 atau sha1 dari 'somwthing' dan kemudian memotongnya dengan panjang berapa pun yang Anda inginkan.
Anda juga dapat menghasilkan dan memotong panduan.
1) metode statis harus aman thread. 2) Apa gunanya menambah indeks daripada menggunakan hasil random.Nextsecara langsung? Menyulitkan kode dan tidak mencapai apa pun yang bermanfaat.
CodesInChaos
0
Berikut adalah mekanisme untuk menghasilkan string alpha-numeric acak (saya menggunakan ini untuk menghasilkan kata sandi dan menguji data) tanpa mendefinisikan alfabet dan angka,
CleanupBase64 akan menghapus bagian-bagian yang diperlukan dalam string dan terus menambahkan huruf alfanumerik acak secara rekursif.
publicstaticstringGenerateRandomString(int length){var numArray =newbyte[length];newRNGCryptoServiceProvider().GetBytes(numArray);returnCleanUpBase64String(Convert.ToBase64String(numArray), length);}privatestaticstringCleanUpBase64String(string input,int maxLength){
input = input.Replace("-","");
input = input.Replace("=","");
input = input.Replace("/","");
input = input.Replace("+","");
input = input.Replace(" ","");while(input.Length< maxLength)
input = input +GenerateRandomString(maxLength);return input.Length<= maxLength ?
input.ToUpper()://In my case I want capital letters
input.ToUpper().Substring(0, maxLength);}
Anda telah menyatakan GenerateRandomStringdan melakukan panggilan keGetRandomString dari dalam SanitiseBase64String. Juga Anda telah menyatakan SanitiseBase64String dan panggilan CleanUpBase64Stringdi GenerateRandomString.
Wai Ha Lee
0
Ada satu paket nuget yang membuat hal ini sangat sederhana.
var myObject =newFaker<MyObject>().RuleFor(p => p.MyAlphaNumericProperty, f => f.Random.AlphaNumeric(/*lenght*/7)).Generate();
tidak 100% yakin, karena saya tidak menguji SETIAP opsi di sini, tetapi dari yang saya uji, ini adalah yang tercepat. mengatur waktu dengan stopwatch dan menunjukkan 9-10 kutu jadi jika kecepatan lebih penting daripada keamanan, coba ini:
privatestaticRandom random =newRandom();publicstaticstringRandom(int length){var stringChars =newchar[length];for(int i =0; i < length; i++){
stringChars[i]=(char)random.Next(0x30,0x7a);returnnewstring(stringChars);}}
Random
kelas untuk menghasilkan kata sandi. PenyemaianRandom
entropi sangat rendah, sehingga tidak benar-benar aman. Gunakan PRNG kriptografi untuk kata sandi.Jawaban:
Saya mendengar LINQ adalah hitam baru, jadi inilah upaya saya menggunakan LINQ:
(Catatan: Penggunaan
Random
kelas membuat ini tidak cocok untuk keamanan apa pun yang terkait , seperti membuat kata sandi atau token. GunakanRNGCryptoServiceProvider
kelas jika Anda memerlukan generator nomor acak yang kuat.)sumber
return new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
Tidak seanggun solusi Linq.
(Catatan: Penggunaan
Random
kelas membuat ini tidak cocok untuk keamanan apa pun yang terkait , seperti membuat kata sandi atau token. GunakanRNGCryptoServiceProvider
kelas jika Anda memerlukan generator nomor acak yang kuat.)sumber
GetRandomFileName
lebih cepat tetapi tidak memungkinkan kontrol karakter yang digunakan dan panjang maksimal yang mungkin adalah 11 karakter.Guid
Solusi Douglas adalah kilat-cepat tetapi karakter dibatasi untuk A-F0-9 dan panjang maksimal yang mungkin adalah 32 karakter.GetRandomFileName
tetapi kemudian (a) Anda akan kehilangan keunggulan kinerja Anda, dan (b) kode Anda akan menjadi lebih rumit.System.Random
tidak cocok untuk keamanan.Tidak seperti beberapa alternatif yang disajikan, yang satu ini secara kriptografi masuk akal .
Berdasarkan pembahasan alternatif di sini dan diperbarui / dimodifikasi berdasarkan komentar di bawah ini.
Berikut ini adalah test harness kecil yang menunjukkan distribusi karakter dalam output yang lama dan yang diperbarui. Untuk diskusi mendalam tentang analisis keacakan , lihat random.org.
sumber
RNGCSP
pertama kali?) Menggunakan mod untuk mengindeks ke dalamchars
array berarti bahwa Anda akan mendapatkan output yang bias kecualichars.Length
kebetulan menjadi pembagi 256.4*maxSize
byte acak, lalu gunakan(UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length
. Saya juga akan menggunakanGetBytes
bukanGetNonZeroBytes
. Dan akhirnya Anda dapat menghapus panggilan pertama keGetNonZeroBytes
. Anda tidak menggunakan hasilnya.Solusi 1 - 'rentang' terbesar dengan panjang paling fleksibel
Solusi ini memiliki rentang yang lebih banyak daripada menggunakan GUID karena GUID memiliki beberapa bit tetap yang selalu sama dan karenanya tidak acak, misalnya 13 karakter dalam hex selalu "4" - setidaknya dalam GUID versi 6.
Solusi ini juga memungkinkan Anda menghasilkan string dengan panjang berapa pun.
Solusi 2 - Satu baris kode - baik untuk hingga 22 karakter
Anda tidak dapat membuat string selama Solusi 1 dan string tidak memiliki rentang yang sama karena bit yang diperbaiki di GUID, tetapi dalam banyak kasus ini akan melakukan pekerjaan.
Solusi 3 - Kode sedikit lebih sedikit
Sebagian besar menyimpan ini di sini untuk tujuan historis. Ini menggunakan kode sedikit lebih sedikit, yang meskipun datang sebagai biaya memiliki rentang kurang - karena menggunakan hex bukan base64 dibutuhkan lebih banyak karakter untuk mewakili kisaran yang sama dibandingkan solusi lain.
Yang berarti lebih banyak peluang tabrakan - mengujinya dengan 100.000 iterasi dari 8 string karakter yang dihasilkan satu duplikat.
sumber
Inilah contoh yang saya curi dari contoh Sam Allen di Dot Net Perls
Jika Anda hanya membutuhkan 8 karakter, gunakan Path.GetRandomFileName () di namespace System.IO. Sam mengatakan menggunakan "Path.GetRandomFileName di sini kadang-kadang lebih unggul, karena menggunakan RNGCryptoServiceProvider untuk keacakan yang lebih baik. Namun, terbatas pada 11 karakter acak."
GetRandomFileName selalu mengembalikan string 12 karakter dengan titik pada karakter ke-9. Jadi, Anda harus menghapus periode (karena itu tidak acak) dan kemudian mengambil 8 karakter dari string. Sebenarnya, Anda bisa mengambil 8 karakter pertama dan tidak khawatir tentang periode.
PS: terima kasih Sam
sumber
Tujuan utama kode saya adalah:
Properti pertama dicapai dengan mengambil modulo nilai alfabet 64 bit. Untuk huruf kecil (seperti 62 karakter dari pertanyaan) ini menyebabkan bias diabaikan. Properti kedua dan ketiga dicapai dengan menggunakan
RNGCryptoServiceProvider
alih-alihSystem.Random
.sumber
Yang paling sederhana:
Anda bisa mendapatkan kinerja yang lebih baik jika Anda membuat kode char array dan mengandalkan
System.Random
:Jika Anda khawatir huruf-huruf bahasa Inggris dapat berubah sewaktu-waktu dan Anda mungkin kehilangan bisnis, maka Anda dapat menghindari pengkodean yang sulit, tetapi harus berkinerja sedikit lebih buruk (sebanding dengan
Path.GetRandomFileName
pendekatan)Dua pendekatan terakhir terlihat lebih baik jika Anda dapat menjadikannya metode ekstensi secara
System.Random
instan.sumber
chars.Select
sangat jelek karena bergantung pada ukuran output paling banyak ukuran alfabet.'a'.To('z')
pendekatan?chars.Select()
.Ambil (n) `hanya berfungsi jikachars.Count >= n
. Memilih pada urutan yang sebenarnya tidak Anda gunakan agak tidak intuitif, terutama dengan batasan panjang implisit. Saya lebih suka menggunakanEnumerable.Range
atauEnumerable.Repeat
. 2) Pesan kesalahan "char akhir harus kurang dari start char" adalah cara yang salah bulat / hilang anot
.chars.Count
adalah cara> n
. Saya juga tidak mendapatkan bagian yang tidak intuitif. Itu membuat semua penggunaanTake
tidak intuitif bukan? Saya tidak percaya itu. Terima kasih telah menunjukkan kesalahan ketik.Hanya beberapa perbandingan kinerja dari berbagai jawaban di utas ini:
Metode & Pengaturan
Hasil
Diuji dalam LinqPad. Untuk ukuran string 10, menghasilkan:
Dan angka kinerja cenderung sedikit berbeda, sangat kadang
NonOptimized
- kadang sebenarnya lebih cepat, dan kadangForLoop
- kadang danGenerateRandomString
beralih siapa yang memimpin.sumber
var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());
, di mana Anda gantiEachRandomizingMethod
dengan ... masing-masing metodeSatu baris kode
Membership.GeneratePassword()
melakukan trik :)Ini demo yang sama.
sumber
Kode yang ditulis oleh Eric J. cukup ceroboh (cukup jelas bahwa itu dari 6 tahun yang lalu ... dia mungkin tidak akan menulis kode itu hari ini), dan bahkan ada beberapa masalah.
Tidak Benar ... Ada bias dalam kata sandi (seperti yang ditulis dalam komentar),
bcdefgh
sedikit lebih mungkin daripada yang lain (a
bukan karenaGetNonZeroBytes
tidak menghasilkan byte dengan nilai nol, jadi bias untuka
itu diimbangi dengan itu), jadi itu tidak benar-benar terdengar kriptografis.Ini harus memperbaiki semua masalah.
sumber
Kami juga menggunakan string kustom acak tetapi kami implementasikan sebagai penolong string sehingga memberikan fleksibilitas ...
Pemakaian
atau
sumber
Kode satu baris sederhana saya berfungsi untuk saya :)
Untuk memperluas ini untuk string panjang apa pun
sumber
Opsi lain bisa menggunakan Linq dan menggabungkan karakter acak ke stringbuilder.
sumber
Pertanyaan: Mengapa saya harus membuang-buang waktu menggunakan
Enumerable.Range
daripada mengetik"ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"
?Jawab: Senar ajaib itu BURUK. Apa ada yang memperhatikan?
I
" tali saya di atas? Ibu saya mengajari saya untuk tidak menggunakan string sihir karena alasan ini ...nb 1: Seperti yang dikatakan banyak orang seperti @dtb, jangan gunakan
System.Random
jika Anda membutuhkan keamanan kriptografis ...nb 2: Jawaban ini bukan yang paling efisien atau terpendek, tetapi saya ingin ruang untuk memisahkan jawaban dari pertanyaan. Tujuan dari jawaban saya lebih untuk memperingatkan terhadap string sihir daripada memberikan jawaban inovatif yang mewah.
sumber
I
?"[A-Z0-9]
. Jika, secara tidak sengaja, string acak Anda hanya menutupi[A-HJ-Z0-9]
hasil tidak mencakup rentang yang diijinkan penuh, yang mungkin bermasalah.I
. Apakah karena ada satu karakter yang kurang dan itu membuatnya lebih mudah untuk retak? Apa statistik pada kata sandi yang dapat dipecahkan yang berisi 35 karakter dalam kisaran dari 36. Saya pikir saya lebih suka mengambil risiko ... atau hanya membuktikan buluh rentang karakter ... daripada memasukkan semua sampah ekstra dalam kode saya. Tapi itu aku. Maksudku, bukan untuk menjadi lubang pantat, aku hanya mengatakan. Kadang-kadang saya pikir programmer cenderung menempuh rute ekstra-kompleks demi menjadi ekstra-kompleks.I
danO
dari jenis string acak ini untuk menghindari manusia membingungkan mereka dengan1
dan0
. Jika Anda tidak peduli tentang memiliki string yang dapat dibaca manusia, baik, tetapi jika itu adalah sesuatu yang seseorang perlu ketik, maka sebenarnya pintar untuk menghapus karakter tersebut.Versi solusi DTB yang sedikit lebih bersih.
Preferensi gaya Anda dapat bervariasi.
sumber
sumber
Setelah meninjau jawaban lain dan mempertimbangkan komentar CodeInChaos, bersama dengan CodeInChaos masih bias (walaupun kurang) jawaban, saya pikir diperlukan solusi final cut and paste . Jadi, sementara memperbarui jawaban saya, saya memutuskan untuk keluar semua.
Untuk versi terbaru dari kode ini, silakan kunjungi repositori Hg baru di Bitbucket: https://bitbucket.org/merarischroeder/secureswiftrandom . Saya sarankan Anda copy dan paste kode dari: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.cs?at=default&fileviewer=file-view-default (make yakin Anda mengklik tombol Raw untuk membuatnya lebih mudah untuk menyalin dan memastikan Anda memiliki versi terbaru, saya pikir tautan ini menuju ke versi kode yang spesifik, bukan yang terbaru).
Catatan yang diperbarui:
Solusi akhir untuk pertanyaan:
Tetapi Anda membutuhkan kelas baru saya (yang belum diuji):
Untuk riwayat - solusi lama saya untuk jawaban ini, menggunakan objek acak:
Kinerja:
Lihat juga:
Tautan ini adalah pendekatan lain. Buffering dapat ditambahkan ke basis kode baru ini, tetapi yang paling penting adalah mengeksplorasi berbagai pendekatan untuk menghilangkan bias, dan membandingkan kecepatan dan pro / kontra.
sumber
charSet.Length
bukan62
. 2) StatisRandom
tanpa penguncian berarti kode ini bukan threadsafe. 3) mengurangi 0-255 mod 62 memperkenalkan bias yang terdeteksi. 4) Anda tidak dapat menggunakanToString
array char, yang selalu kembali"System.Char[]"
. Anda harus menggunakannyanew String(rName)
sebagai gantinya.System.Random
) dan kemudian dengan hati-hati menghindari bias dalam kode Anda sendiri. Ungkapan "memoles kotoran" muncul di pikiran.Mengerikan, aku tahu, tapi aku tidak bisa menahan diri:
sumber
Saya mencari jawaban yang lebih spesifik, di mana saya ingin mengontrol format string acak dan menemukan posting ini. Sebagai contoh: plat nomor (mobil) memiliki format tertentu (per negara) dan saya ingin membuat plat nomor acak.
Saya memutuskan untuk menulis metode ekstensi Acak saya sendiri untuk ini. (ini untuk menggunakan kembali objek acak yang sama, karena Anda bisa memiliki dua kali lipat dalam skenario multi-threading). Saya membuat intisari ( https://gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), tetapi juga akan menyalin kelas ekstensi di sini:
sumber
Sekarang dalam rasa satu-liner.
sumber
RNGCryptoServiceProvider
harus dibuang setelah digunakan.Cobalah untuk menggabungkan dua bagian: unik (urutan, penghitung atau tanggal) dan acak
Tes:
sumber
<=
dan>=
bukannya<
dan>
. 3) Saya akan menambahkan tanda kurung yang tidak perlu di sekitar&&
ekspresi untuk memperjelas bahwa mereka memiliki prioritas, tetapi tentu saja itu hanya pilihan gaya.Solusi tanpa menggunakan
Random
:sumber
Berikut ini adalah varian dari solusi Eric J, yaitu suara kriptografis, untuk WinRT (Aplikasi Windows Store):
Jika kinerja penting (terutama ketika panjangnya tinggi):
sumber
Saya tahu ini bukan cara terbaik. Tetapi Anda dapat mencoba ini.
sumber
Saya tidak tahu bagaimana suara ini secara kriptografis, tetapi ini lebih mudah dibaca dan ringkas daripada solusi yang lebih rumit (imo), dan itu harus lebih "acak" daripada
System.Random
solusi berbasis.Saya tidak dapat memutuskan apakah menurut saya versi ini atau yang berikutnya "lebih cantik", tetapi mereka memberikan hasil yang sama persis:
Memang, itu tidak dioptimalkan untuk kecepatan, jadi jika itu penting untuk menghasilkan jutaan string acak setiap detik, coba yang lain!
CATATAN: Solusi ini tidak memungkinkan pengulangan simbol dalam alfabet, dan alfabet HARUS berukuran sama atau lebih besar dari string output, membuat pendekatan ini kurang diinginkan dalam beberapa keadaan, semuanya tergantung pada use-case Anda.
sumber
Jika nilai-nilai Anda tidak sepenuhnya acak, tetapi sebenarnya mungkin tergantung pada sesuatu - Anda dapat menghitung hash md5 atau sha1 dari 'somwthing' dan kemudian memotongnya dengan panjang berapa pun yang Anda inginkan.
Anda juga dapat menghasilkan dan memotong panduan.
sumber
sumber
random.Next
secara langsung? Menyulitkan kode dan tidak mencapai apa pun yang bermanfaat.Berikut adalah mekanisme untuk menghasilkan string alpha-numeric acak (saya menggunakan ini untuk menghasilkan kata sandi dan menguji data) tanpa mendefinisikan alfabet dan angka,
CleanupBase64 akan menghapus bagian-bagian yang diperlukan dalam string dan terus menambahkan huruf alfanumerik acak secara rekursif.
sumber
GenerateRandomString
dan melakukan panggilan keGetRandomString
dari dalamSanitiseBase64String
. Juga Anda telah menyatakanSanitiseBase64String
dan panggilanCleanUpBase64String
diGenerateRandomString
.Ada satu paket nuget yang membuat hal ini sangat sederhana.
Salah satu contoh yang baik ada di sini .
sumber
tidak 100% yakin, karena saya tidak menguji SETIAP opsi di sini, tetapi dari yang saya uji, ini adalah yang tercepat. mengatur waktu dengan stopwatch dan menunjukkan 9-10 kutu jadi jika kecepatan lebih penting daripada keamanan, coba ini:
sumber