nota: Sono a conoscenza del caso d'uso di deviazione del PO, ma penso che potrebbe aiutare gli altri che hanno un caso d'uso leggermente diverso
Molto può essere detto a proposito del motivi per convertire un array di byte crittografici in una stringa, ma di solito è per scopi di serializzazione; e quindi, in quel caso: il set di caratteri selezionato è arbitrario.
Quindi, se e solo se il primo è vero E la lunghezza della stringa non deve essere ottimizzata; è possibile utilizzare una semplice rappresentazione esadecimale della matrice di byte in questo modo:
//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"
Ora direte: Ma aspetta: questi sono solo 16 caratteri in cui la sequenza di OP ha 62. La stringa sarà molto più a lungo.
"Sì", io risponderò, "e se questo è un problema, perché non si fa a scegliere 256 serrializable-caratteri di facile lettura e ... o forse 64"; -)
Come dichiarato da @Guffa; utilizzando %
è vietato a meno che non altera la distribuzione. Per fare in modo che ciò accada, dato un insieme uniformemente distribuito, il sottoinsieme deve corrispondere esattamente a x volte nel set originale.
Così, espandendo il set iniziale valido con 2 si ottiene un risultato valido (perché: 256/64 = 4).
Il codice sarebbe:
//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]);
Si prega di notare: in tutte le risposte, compreso questo, il sub-set è più piccolo di 256 possibilità del byte. Questo significa che ci sono meno informazioni disponibili. Ciò significa che se hai la tua stringa con 4 caratteri, è più facile decifrare il risultato originale a 4 byte di RNGCryptoServiceProvider.
Quindi ... ora si dice: "Perché non utilizzare la codifica di base 64?", bene, se si tratta di vi si addice, ma stare attenti con il trailing =
, vedere 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);
prega note²: Un tipico caso d'uso è qualche segno url. Si noti che il segno +
non è valido come tale carattere.
È necessario fare attenzione quando si convertono i valori di byte in un numero in un intervallo specifico. Se si usa '%', allora produrrà numeri con una distribuzione non uniforme, e l'intero scopo di usare un generatore casuale migliore è inutile. – Guffa
È vero, volevo aggiungere che dopo aver postato la mia risposta. La risposta di Tamir Vered è piuttosto interessante anche se orribilmente inefficiente dal momento che non usa StringBuilder. Lascia fuori i byte non accettati come input, che è una soluzione interessante e avrà una distribuzione corretta, come pure – hl3mukkel