I have a byte array, with a fixed length of 4.
token := make([]byte, 4)
I need to set each byte to a random byte. How can I do so, in the most
Using math.Rand means that you are using the system CSPRNG that your operating system provides. This means using /dev/urandom/ and Windows’ CryptGenRandom API. Go’s crypto/rand package, thankfully, abstracts these implementation details away to minimise the risk of getting it wrong.
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
}
Package rand
import "math/rand"
func Read
func Read(p []byte) (n int, err error)
Read generates len(p) random bytes from the default Source and writes them into p. It always returns len(p) and a nil error.
func (*Rand) Read
func (r *Rand) Read(p []byte) (n int, err error)
Read generates len(p) random bytes and writes them into p. It always returns len(p) and a nil error.
For example,
package main
import (
"math/rand"
"fmt"
)
func main() {
token := make([]byte, 4)
rand.Read(token)
fmt.Println(token)
}
Output:
[187 163 35 30]
Go 1.6 added a new function to the math/rand package:
func Read(p []byte) (n int, err error)
which fills the passed byte
slice with random data. Using this rand.Read():
token := make([]byte, 4)
if _, err := rand.Read(token); err != nil {
// Handle err
}
fmt.Println(token)
rand.Read()
has 2 return values: the number of "read" bytes and an (optional) error. This is to conform with the general io.Reader interface, but the documentation of rand.Read()
states that (despite its signature) it will never actually return a non-nil
error, so we may omit checking it, which simplifies it to this:
token := make([]byte, 4)
rand.Read(token)
fmt.Println(token)
Don't forget to call rand.Seed() to properly initialize it before you use the math/rand
package, e.g.:
rand.Seed(time.Now().UnixNano())
Note: Prior to Go 1.6 there was no math/rand.Read()
function, but there was (and still is) a crypto/rand.Read() function, but the crypto/rand package implements a cryptographically secure pseudorandom number generator, so it is much slower than math/rand
.