From 75cca531ea763666bc46e531da3b4c3b95f64557 Mon Sep 17 00:00:00 2001 From: Josselin Costanzi Date: Wed, 4 Apr 2018 18:55:56 +0200 Subject: [PATCH] Fix potential non-random UUIDs Use ReadFull to fetch random bytes from crypto/rand instead of calling Read directly as Read may read less bytes than asked. Fix satori/go.uuid#73 --- generator.go | 6 +++--- generator_test.go | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/generator.go b/generator.go index 499dc35..c50d33c 100644 --- a/generator.go +++ b/generator.go @@ -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) @@ -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) @@ -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 diff --git a/generator_test.go b/generator_test.go index 82a236a..a445fb0 100644 --- a/generator_test.go +++ b/generator_test.go @@ -22,9 +22,11 @@ package uuid import ( + "bytes" "crypto/rand" "fmt" "net" + "testing/iotest" "time" . "gopkg.in/check.v1" @@ -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()