Generating a random, fixed-length byte array in Go
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
.
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]
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
}