2015-09-02 9 views
10

Dire Vorrei generare un int casuale sicura tra 0 e 27 con:Come posso generare un int random usando il pacchetto "crypto/rand"?

func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) 

nel pacchetto "crypto/rand".

Come faccio?

Non ho veramente capito come funziona, perché non restituisce uno dei Go in built invece del puntatore ad un tipo big.Int?

EDIT:

Sarebbe questo essere considerato abbastanza sicuro per i token?

func getToken(length int) string { 
    token := "" 
    codeAlphabet := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
    codeAlphabet += "abcdefghijklmnopqrstuvwxyz" 
    codeAlphabet += "" 

    for i := 0; i < length; i++ { 
     token += string(codeAlphabet[cryptoRandSecure(int64(len(codeAlphabet)))]) 
    } 
    return token 
} 

func cryptoRandSecure(max int64) int64 { 
    nBig, err := rand.Int(rand.Reader, big.NewInt(max)) 
    if err != nil { 
     log.Println(err) 
    } 
    return nBig.Int64() 
} 

func main() { 
    fmt.Println(getToken(32)) 
} 

Questa uscita sarebbe qualcosa di simile:

qZDbuPwNQGrgVmZCU9A7FUWbp8eIfn0Z 

EwZVoQ5D5SEfdhiRsDfH6dU6tAovILCZ 

cOqzODVP0GwbiNBwtmqLA78rFgV9d3VT 
+3

Hai davvero bisogno di un "numero pseudocasuale crittograficamente sicuro"? (dal doc https://godoc.org/crypto/rand) Se non lo fai, puoi usare https://godoc.org/math/rand – HectorJ

+0

Ho bisogno di generare token sicuri. Come quello che ho mostrato sopra. Mi piacerebbe se potesse includere tutti i caratteri dell'alfabeto, compresi i numeri. – Aiden

+0

Hai appena visto la tua modifica. Un modo alternativo potrebbe essere quello di generare un int molto casuale (come tra 0 e il massimo int64) e codificarlo in esadecimale o base32. Lo aggiungerò alla mia risposta – HectorJ

risposta

11

Se si generano token sicuri per ID sessione, token OAuth Bearer, CSRF o simili: si desidera generare un token di (idealmente) 256 bit (32 byte) o non meno di 192 bit (24 byte).

Un token con valori compresi tra (0-27) può essere forzato a forza in meno di un secondo e non può essere considerato sicuro.

ad es.

package main 

import (
    "crypto/rand" 
    "encoding/base64" 
) 

// GenerateRandomBytes returns securely generated random bytes. 
// It will return an error if the system's secure random 
// number generator fails to function correctly, in which 
// case the caller should not continue. 
func GenerateRandomBytes(n int) ([]byte, error) { 
    b := make([]byte, n) 
    _, err := rand.Read(b) 
    // Note that err == nil only if we read len(b) bytes. 
    if err != nil { 
     return nil, err 
    } 

    return b, nil 
} 

// GenerateRandomString returns a URL-safe, base64 encoded 
// securely generated random string. 
func GenerateRandomString(s int) (string, error) { 
    b, err := GenerateRandomBytes(s) 
    return base64.URLEncoding.EncodeToString(b), err 
} 

func main() { 
    // Example: this will give us a 44 byte, base64 encoded output 
    token, err := GenerateRandomString(32) 
    if err != nil { 
     // Serve an appropriately vague error to the 
     // user, but log the details internally. 
    } 
} 

L'uscita base64 è sicuro per le intestazioni, moduli HTTP, enti JSON, ecc

Se avete bisogno di un numero intero che può aiutare a spiegare il vostro caso d'uso, in quanto sarebbe strano per un sistema richiedere i token come ints.

+0

Ciao elithrar, ho modificato i miei post. Volevo usarlo per creare token per cose diverse come reimpostazioni di password e chiavi da distribuire alle persone per la registrazione di un sito web chiuso e così via. – Aiden

+1

@Aiden In tal caso non è necessario inserire numeri casuali. Una stringa sufficientemente casuale (base64, hex, qualunque cosa) sarebbe più che fine. Il mio frammento sopra utilizza 'base64.URLEncoding' per generare stringhe che è possibile utilizzare in un URL, ad es. 'yourdomain.com/resetpassword? token = YW55m5hbCIGNhcm5hbCBwbGVhc3U =' coprirebbe tale caso d'uso. Come suggerimento: assicurati di applicare rigorosamente una data di scadenza e uso singolo sui token nel tuo back-end (SQL, Redis, ecc.) Poiché ci sono molti spigoli vivi attorno al riutilizzo di token di reimpostazione della password che non scadono " correttamente". – elithrar

+0

Grazie per l'aiuto! – Aiden

12

Ecco il codice di lavoro:

package main 

import (
    "fmt" 
    "crypto/rand" 
    "math/big" 
) 

func main() { 
    nBig, err := rand.Int(rand.Reader, big.NewInt(27)) 
    if err != nil { 
     panic(err) 
    } 
    n := nBig.Int64() 
    fmt.Printf("Here is a random %T in [0,27) : %d\n", n, n) 
} 

Ma per generare un token a caso, mi piacerebbe fare qualcosa di simile this:

package main 

import (
    "crypto/rand" 
    "encoding/base32" 
    "fmt" 
) 

func main() { 
    token := getToken(10) 
    fmt.Println("Here is a random token : ", token) 
} 

func getToken(length int) string { 
    randomBytes := make([]byte, 32) 
    _, err := rand.Read(randomBytes) 
    if err != nil { 
     panic(err) 
    } 
    return base32.StdEncoding.EncodeToString(randomBytes)[:length] 
} 
+0

Vedere anche https://www.socketloop.com/tutorials/golang-how-to-generate-random-string (usando base64, quindi più che l'alfabeto e i numeri https://en.wikipedia.org/wiki/ Base64) – HectorJ

+1

Suggerirei almeno 24 (se non 32) byte per qualsiasi tipo di token. – elithrar

+1

@elithrar: grazie, modificato. – HectorJ

0

Se è necessario solo un numero ridotto (ad es. [0, 255]), si può solo leggere un byte di fuori del pacchetto di Reader:

b := []byte{0} 
if _, err := rand.Reader.Read(b); err != nil { 
    panic(err) 
} 
n := b[0] 
fmt.Println(n) 

Playground: http://play.golang.org/p/4VO52LiEVh (l'esempio non funziona lì, non so se funziona come previsto o è un bug nel parco giochi).

+2

Informazioni sul parco giochi, questo problema è stato contrassegnato come risolto ma in realtà non lo è: https://github.com/golang/go/issues/5096. Ho lasciato un commento lì – HectorJ

Problemi correlati