From 4ad5dc4f02a73a596863baf0f01746fd77b98346 Mon Sep 17 00:00:00 2001 From: Atsushi Watanabe Date: Mon, 13 Jul 2020 13:04:35 +0900 Subject: [PATCH] Use pion/randutil Move common random generators to pion/randutil. --- go.mod | 1 + go.sum | 2 ++ rand.go | 74 +++++----------------------------------------------- rand_test.go | 33 ----------------------- 4 files changed, 10 insertions(+), 100 deletions(-) diff --git a/go.mod b/go.mod index 3f270a3..dd10f83 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/pion/dtls/v2 v2.0.1 github.com/pion/logging v0.2.2 github.com/pion/mdns v0.0.4 + github.com/pion/randutil v0.0.0 github.com/pion/stun v0.3.5 github.com/pion/transport v0.10.1 github.com/pion/turn/v2 v2.0.4 diff --git a/go.sum b/go.sum index 746e21d..5aec491 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= github.com/pion/mdns v0.0.4 h1:O4vvVqr4DGX63vzmO6Fw9vpy3lfztVWHGCQfyw0ZLSY= github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0= +github.com/pion/randutil v0.0.0 h1:aLWLVhTG2jzoD25F0OlW6nXvXrjoGwiXq2Sz7j7NzL0= +github.com/pion/randutil v0.0.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg= github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA= github.com/pion/transport v0.8.10 h1:lTiobMEw2PG6BH/mgIVqTV2mBp/mPT+IJLaN8ZxgdHk= diff --git a/rand.go b/rand.go index 8455b07..5e3c132 100644 --- a/rand.go +++ b/rand.go @@ -1,13 +1,6 @@ package ice -import ( - crand "crypto/rand" - "encoding/binary" - "math/big" - mrand "math/rand" // used for non-crypto unique ID and random port selection - "sync" - "time" -) +import "github.com/pion/randutil" const ( runesAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" @@ -21,58 +14,19 @@ const ( // Seeding random generator each time limits number of generated sequence to 31-bits, // and causes collision on low time accuracy environments. // Use global random generator seeded by crypto grade random. -var globalMathRandomGenerator = newMathRandomGenerator() +var globalMathRandomGenerator = randutil.NewMathRandomGenerator() var globalCandidateIDGenerator = candidateIDGenerator{globalMathRandomGenerator} -// mathRandomGenerator is a random generator for non-crypto usage. -type mathRandomGenerator struct { - r *mrand.Rand - mu sync.Mutex -} - -func newMathRandomGenerator() *mathRandomGenerator { - var seed int64 - if err := binary.Read(crand.Reader, binary.LittleEndian, &seed); err != nil { - // crypto/rand is unavailable. Fallback to seed by time. - seed = time.Now().UnixNano() - } - - return &mathRandomGenerator{r: mrand.New(mrand.NewSource(seed))} -} - -func (g *mathRandomGenerator) Intn(n int) int { - g.mu.Lock() - v := g.r.Intn(n) - g.mu.Unlock() - return v -} - -func (g *mathRandomGenerator) Uint64() uint64 { - g.mu.Lock() - v := g.r.Uint64() - g.mu.Unlock() - return v -} - -func (g *mathRandomGenerator) GenerateString(n int, runes string) string { - letters := []rune(runes) - b := make([]rune, n) - for i := range b { - b[i] = letters[g.Intn(len(letters))] - } - return string(b) -} - // candidateIDGenerator is a random candidate ID generator. // Candidate ID is used in SDP and always shared to the other peer. // It doesn't require cryptographic random. type candidateIDGenerator struct { - *mathRandomGenerator + randutil.MathRandomGenerator } func newCandidateIDGenerator() *candidateIDGenerator { return &candidateIDGenerator{ - newMathRandomGenerator(), + randutil.NewMathRandomGenerator(), } } @@ -81,31 +35,17 @@ func (g *candidateIDGenerator) Generate() string { // candidate-id = "candidate" ":" foundation // foundation = 1*32ice-char // ice-char = ALPHA / DIGIT / "+" / "/" - return "candidate:" + g.mathRandomGenerator.GenerateString(32, runesCandidateIDFoundation) -} - -// generateCryptoRandomString generates a random string for crypto usage. -func generateCryptoRandomString(n int, runes string) (string, error) { - letters := []rune(runes) - b := make([]rune, n) - for i := range b { - v, err := crand.Int(crand.Reader, big.NewInt(int64(len(letters)))) - if err != nil { - return "", err - } - b[i] = letters[v.Int64()] - } - return string(b), nil + return "candidate:" + g.MathRandomGenerator.GenerateString(32, runesCandidateIDFoundation) } // generatePwd generates ICE pwd. // This internally uses generateCryptoRandomString. func generatePwd() (string, error) { - return generateCryptoRandomString(lenPwd, runesAlpha) + return randutil.GenerateCryptoRandomString(lenPwd, runesAlpha) } // generateUFrag generates ICE user fragment. // This internally uses generateCryptoRandomString. func generateUFrag() (string, error) { - return generateCryptoRandomString(lenUFrag, runesAlpha) + return randutil.GenerateCryptoRandomString(lenUFrag, runesAlpha) } diff --git a/rand_test.go b/rand_test.go index 44c4bb3..d44103a 100644 --- a/rand_test.go +++ b/rand_test.go @@ -1,43 +1,10 @@ package ice import ( - "regexp" "sync" "testing" ) -func TestMathRandomGenerator(t *testing.T) { - g := newMathRandomGenerator() - isLetter := regexp.MustCompile(`^[a-zA-Z]+$`).MatchString - - for i := 0; i < 10000; i++ { - s := g.GenerateString(10, runesAlpha) - if len(s) != 10 { - t.Error("Generator returned invalid length") - } - if !isLetter(s) { - t.Errorf("Generator returned unexpected character: %s", s) - } - } -} - -func TestCryptoRandomGenerator(t *testing.T) { - isLetter := regexp.MustCompile(`^[a-zA-Z]+$`).MatchString - - for i := 0; i < 10000; i++ { - s, err := generateCryptoRandomString(10, runesAlpha) - if err != nil { - t.Error(err) - } - if len(s) != 10 { - t.Error("Generator returned invalid length") - } - if !isLetter(s) { - t.Errorf("Generator returned unexpected character: %s", s) - } - } -} - func TestRandomGeneratorCollision(t *testing.T) { candidateIDGen := newCandidateIDGenerator()