Skip to content

Commit

Permalink
Fix potential non-random UUIDs
Browse files Browse the repository at this point in the history
Use ReadFull to fetch random bytes from crypto/rand instead of calling
Read directly as Read may read less bytes than asked.

Fix #73
  • Loading branch information
Josselin Costanzi committed Apr 4, 2018
1 parent 36e9d2e commit 75cca53
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 3 deletions.
6 changes: 3 additions & 3 deletions generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ func (g *rfc4122Generator) NewV3(ns UUID, name string) UUID {
// NewV4 returns random generated UUID.
func (g *rfc4122Generator) NewV4() (UUID, error) {
u := UUID{}
if _, err := g.rand.Read(u[:]); err != nil {
if _, err := io.ReadFull(g.rand, u[:]); err != nil {
return Nil, err
}
u.SetVersion(V4)
Expand All @@ -188,7 +188,7 @@ func (g *rfc4122Generator) getClockSequence() (uint64, uint16, error) {
var err error
g.clockSequenceOnce.Do(func() {
buf := make([]byte, 2)
if _, err = g.rand.Read(buf); err != nil {
if _, err = io.ReadFull(g.rand, buf); err != nil {
return
}
g.clockSequence = binary.BigEndian.Uint16(buf)
Expand Down Expand Up @@ -222,7 +222,7 @@ func (g *rfc4122Generator) getHardwareAddr() ([]byte, error) {

// Initialize hardwareAddr randomly in case
// of real network interfaces absence.
if _, err = g.rand.Read(g.hardwareAddr[:]); err != nil {
if _, err = io.ReadFull(g.rand, g.hardwareAddr[:]); err != nil {
return
}
// Set multicast bit as recommended by RFC 4122
Expand Down
16 changes: 16 additions & 0 deletions generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@
package uuid

import (
"bytes"
"crypto/rand"
"fmt"
"net"
"testing/iotest"
"time"

. "gopkg.in/check.v1"
Expand Down Expand Up @@ -195,6 +197,20 @@ func (s *genTestSuite) TestNewV4FaultyRand(c *C) {
c.Assert(u1, Equals, Nil)
}

func (s *genTestSuite) TestNewV4PartialRead(c *C) {
g := &rfc4122Generator{
epochFunc: time.Now,
hwAddrFunc: defaultHWAddrFunc,
rand: iotest.OneByteReader(rand.Reader),
}
u1, err := g.NewV4()
zeros := bytes.Count(u1.Bytes(), []byte{0})
mostlyZeros := zeros >= 10

c.Assert(err, IsNil)
c.Assert(mostlyZeros, Equals, false)
}

func (s *genTestSuite) BenchmarkNewV4(c *C) {
for i := 0; i < c.N; i++ {
NewV4()
Expand Down

0 comments on commit 75cca53

Please sign in to comment.