Generating a random, fixed-length byte array in Go

36,732

Solution 1

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]

Solution 2

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.

Solution 3

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
}
Share:
36,732
Momo
Author by

Momo

Updated on July 09, 2022

Comments

  • Momo
    Momo almost 2 years

    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 efficient matter? The math/rand methods do not provide a Random Byte function, as far as I am concerned.

    Perhaps there is a built-in way, or should I go with generating a random string and converting it to a byte array?