Say I would like to generate a secure random int between 0 and 27 using:
func Int(rand io.Reader, max *big.Int) (n *big.Int, err error)
in the "crypto/rand"
package.
How would I do that?
I do not really understand how this works, why does it not return one of the built in Go ints instead of pointer to some big.Int type?
EDIT:
Would this be considered secure enough for tokens?
func getToken(length int) string { token := "" codeAlphabet := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" codeAlphabet += "abcdefghijklmnopqrstuvwxyz" codeAlphabet += "0123456789" 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)) }
This would output something like this:
qZDbuPwNQGrgVmZCU9A7FUWbp8eIfn0Z EwZVoQ5D5SEfdhiRsDfH6dU6tAovILCZ cOqzODVP0GwbiNBwtmqLA78rFgV9d3VT
The rand() function generates a pseudo-random integer in the range 0 to RAND_MAX . Use the srand() function before calling rand() to set a seed for the random number generator. If you do not make a call to srand(), the default seed is 1.
In Golang, the rand. Seed() function is used to set a seed value to generate pseudo-random numbers. If the same seed value is used in every execution, then the same set of pseudo-random numbers is generated. In order to get a different set of pseudo-random numbers, we need to update the seed value.
Here is some working code :
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) }
But to generate a random token, I'd do something like 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] }
If you're generating secure tokens for session IDs, OAuth Bearer tokens, CSRF or similar: you want to generate a token of (ideally) 256 bits (32 bytes) or no less than 192 bits (24 bytes).
A token with values between (0-27) can be brute-forced in less than a second and could not be considered secure.
e.g.
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. } }
The base64 output is safe for headers, HTTP forms, JSON bodies, etc.
If you need an integer it may help to explain your use-case, as it would be odd for a system to require tokens as ints.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With