Use pion/randutil

Move common random generators to pion/randutil.
This commit is contained in:
Atsushi Watanabe
2020-07-13 14:32:18 +09:00
parent 2be742f5d2
commit 4ad5dc4f02
4 changed files with 10 additions and 100 deletions
+1
View File
@@ -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
+2
View File
@@ -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=
+7 -67
View File
@@ -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)
}
-33
View File
@@ -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()