Go: Cryptographically secure random numbers

Go has two packages for random numbers:

  • math/rand implements a large selection of pseudo-random number generators.
  • crypto/rand implements a cryptographically secure pseudo-random number generator with a limited interface.

The two packages can be combined by calling rand.New in package math/rand with a source that gets its data from crypto/rand.

import (
	crand "crypto/rand"
	rand "math/rand"

	"encoding/binary"
	"fmt"
	"log"
)

func main() {
	var src cryptoSource
	rnd := rand.New(src)
	fmt.Println(rnd.Intn(1000)) // a random number from 0 to 999
}

type cryptoSource struct{}

func (s cryptoSource) Seed(seed int64) {}

func (s cryptoSource) Int63() int64 {
	return int64(s.Uint64() & ^uint64(1<<63))
}

func (s cryptoSource) Uint64() (v uint64) {
	err := binary.Read(crand.Reader, binary.BigEndian, &v)
	if err != nil {
		log.Fatal(err)
	}
	return v
}

The crand.Reader returns an error if the underlying system call fails. For instance if the runtime can’t read /dev/urandom on a *nix system or if CryptAcquireContext fails on a Windows system.

Comments