diff options
author | Yawning Angel <yawning@schwanenlied.me> | 2014-05-24 04:47:10 +0000 |
---|---|---|
committer | Yawning Angel <yawning@schwanenlied.me> | 2014-05-24 04:47:10 +0000 |
commit | b3f0f51775ae2e19c62c70e15f77ef991ad4bb49 (patch) | |
tree | 0a779fe20ffead1e8a87ba209ac566829c7ce93a | |
parent | e77ddddf4d10dbd3387c2e4714c287c546c70512 (diff) |
Move utils.go to csrand/csrand.go, and clean up the interface.
All of the obfs4 code except unit tests now uses the csrand wrapper
routines.
-rw-r--r-- | csrand/csrand.go (renamed from utils.go) | 42 | ||||
-rw-r--r-- | handshake_ntor.go | 8 | ||||
-rw-r--r-- | ntor/ntor.go | 5 | ||||
-rw-r--r-- | obfs4.go | 6 | ||||
-rw-r--r-- | replay_filter.go | 5 | ||||
-rw-r--r-- | weighted_dist.go | 7 |
6 files changed, 52 insertions, 21 deletions
diff --git a/utils.go b/csrand/csrand.go index 51d99d8..1700b02 100644 --- a/utils.go +++ b/csrand/csrand.go @@ -25,10 +25,16 @@ * POSSIBILITY OF SUCH DAMAGE. */ -package obfs4 +// Package csrand implements the math/rand interface over crypto/rand, along +// with some utility functions for common random number/byte related tasks. +// +// Not all of the convinience routines are replicated, only those that are +// useful for obfs4. The CsRand variable provides access to the full math/rand +// API. +package csrand import ( - csrand "crypto/rand" + cryptRand "crypto/rand" "fmt" "math/big" "math/rand" @@ -36,7 +42,9 @@ import ( var ( csRandSourceInstance csRandSource - csRandInstance = rand.New(csRandSourceInstance) + + // CsRand is a math/rand instance backed by crypto/rand CSPRNG. + CsRand = rand.New(csRandSourceInstance) ) type csRandSource struct { @@ -44,7 +52,7 @@ type csRandSource struct { } func (r csRandSource) Int63() int64 { - ret, err := csrand.Int(csrand.Reader, big.NewInt(int64((1<<63)-1))) + ret, err := cryptRand.Int(cryptRand.Reader, big.NewInt(int64((1<<63)-1))) if err != nil { panic(err) } @@ -56,14 +64,34 @@ func (r csRandSource) Seed(seed int64) { // No-op. } -func randRange(min, max int) int { +// Float64 returns, as a float 64, a pesudo random number in [0.0,1.0). +func Float64() float64 { + return CsRand.Float64() +} + +// IntRange returns a uniformly distributed int [min, max]. +func IntRange(min, max int) int { if max < min { - panic(fmt.Sprintf("randRange: min > max (%d, %d)", min, max)) + panic(fmt.Sprintf("IntRange: min > max (%d, %d)", min, max)) } r := (max + 1) - min - ret := csRandInstance.Intn(r) + ret := CsRand.Intn(r) return ret + min } +// Bytes fills the slice with random data. +func Bytes(buf []byte) error { + n, err := cryptRand.Read(buf) + if err != nil { + // Yes, the go idiom is to check the length, but we panic() when it + // does not match because the system is screwed at that point. + return err + } else if n != len(buf) { + panic(fmt.Sprintf("Bytes: truncated rand.Read (%d, %d)", n, len(buf))) + } + + return nil +} + /* vim :set ts=4 sw=4 sts=4 noet : */ diff --git a/handshake_ntor.go b/handshake_ntor.go index 8baa382..fc107c2 100644 --- a/handshake_ntor.go +++ b/handshake_ntor.go @@ -30,7 +30,6 @@ package obfs4 import ( "bytes" "crypto/hmac" - "crypto/rand" "crypto/sha256" "encoding/hex" "errors" @@ -39,6 +38,7 @@ import ( "strconv" "time" + "github.com/yawning/obfs4/csrand" "github.com/yawning/obfs4/framing" "github.com/yawning/obfs4/ntor" ) @@ -131,7 +131,7 @@ func newClientHandshake(nodeID *ntor.NodeID, serverIdentity *ntor.PublicKey) (*c } hs.nodeID = nodeID hs.serverIdentity = serverIdentity - hs.padLen = randRange(clientMinPadLength, clientMaxPadLength) + hs.padLen = csrand.IntRange(clientMinPadLength, clientMaxPadLength) hs.mac = hmac.New(sha256.New, append(hs.serverIdentity.Bytes()[:], hs.nodeID.Bytes()[:]...)) return hs, nil @@ -245,7 +245,7 @@ func newServerHandshake(nodeID *ntor.NodeID, serverIdentity *ntor.Keypair) *serv hs := new(serverHandshake) hs.nodeID = nodeID hs.serverIdentity = serverIdentity - hs.padLen = randRange(serverMinPadLength, serverMaxPadLength) + hs.padLen = csrand.IntRange(serverMinPadLength, serverMaxPadLength) hs.mac = hmac.New(sha256.New, append(hs.serverIdentity.Public().Bytes()[:], hs.nodeID.Bytes()[:]...)) return hs @@ -428,7 +428,7 @@ func findMarkMac(mark, buf []byte, startPos, maxPos int, fromTail bool) (pos int func makePad(padLen int) ([]byte, error) { pad := make([]byte, padLen) - _, err := rand.Read(pad) + err := csrand.Bytes(pad) if err != nil { return nil, err } diff --git a/ntor/ntor.go b/ntor/ntor.go index eecf038..4483a6b 100644 --- a/ntor/ntor.go +++ b/ntor/ntor.go @@ -39,7 +39,6 @@ package ntor import ( "bytes" "crypto/hmac" - "crypto/rand" "crypto/sha256" "crypto/subtle" "encoding/base64" @@ -50,6 +49,8 @@ import ( "code.google.com/p/go.crypto/hkdf" "github.com/agl/ed25519/extra25519" + + "github.com/yawning/obfs4/csrand" ) const ( @@ -266,7 +267,7 @@ func NewKeypair(elligator bool) (*Keypair, error) { // Generate a Curve25519 private key. Like everyone who does this, // run the CSPRNG output through SHA256 for extra tinfoil hattery. priv := keypair.private.Bytes()[:] - _, err := rand.Read(priv) + err := csrand.Bytes(priv) if err != nil { return nil, err } @@ -51,7 +51,7 @@ const ( maxCloseDelayBytes = maxHandshakeLength maxCloseDelay = 60 - maxIatDelay = 100 + maxIatDelay = 100 ) type connState int @@ -472,7 +472,7 @@ func (c *Obfs4Conn) Write(b []byte) (n int, err error) { if err != nil { return 0, err } - time.Sleep(iatDelta * time.Microsecond) + time.Sleep(iatDelta * time.Microsecond) } } else { _, err = c.conn.Write(frameBuf.Bytes()) @@ -584,7 +584,7 @@ type Obfs4Listener struct { keyPair *ntor.Keypair nodeID *ntor.NodeID - seed *DrbgSeed + seed *DrbgSeed iatObfuscation bool closeDelayBytes int diff --git a/replay_filter.go b/replay_filter.go index 5e98b89..9556ef4 100644 --- a/replay_filter.go +++ b/replay_filter.go @@ -29,11 +29,12 @@ package obfs4 import ( "container/list" - "crypto/rand" "encoding/binary" "sync" "github.com/dchest/siphash" + + "github.com/yawning/obfs4/csrand" ) // maxFilterSize is the maximum capacity of the replay filter. The busiest @@ -63,7 +64,7 @@ type filterEntry struct { func newReplayFilter() (filter *replayFilter, err error) { // Initialize the SipHash-2-4 instance with a random key. var key [16]byte - _, err = rand.Read(key[:]) + err = csrand.Bytes(key[:]) if err != nil { return } diff --git a/weighted_dist.go b/weighted_dist.go index af0fa7d..04b0d2d 100644 --- a/weighted_dist.go +++ b/weighted_dist.go @@ -28,7 +28,6 @@ package obfs4 import ( - csrand "crypto/rand" "encoding/base64" "encoding/binary" "fmt" @@ -36,6 +35,8 @@ import ( "math/rand" "github.com/dchest/siphash" + + "github.com/yawning/obfs4/csrand" ) // DrbgSeedLength is the length of the hashDrbg seed. @@ -58,7 +59,7 @@ func (seed *DrbgSeed) Base64() string { // NewDrbgSeed returns a DrbgSeed initialized with the runtime CSPRNG. func NewDrbgSeed() (seed *DrbgSeed, err error) { seed = new(DrbgSeed) - _, err = csrand.Read(seed.Bytes()[:]) + err = csrand.Bytes(seed.Bytes()[:]) if err != nil { return nil, err } @@ -160,7 +161,7 @@ func newWDist(seed *DrbgSeed, min, max int) (w *wDist) { func (w *wDist) sample() int { retIdx := 0 totalProb := 0.0 - prob := csRandInstance.Float64() + prob := csrand.Float64() for i, bucketProb := range w.buckets { totalProb += bucketProb if prob <= totalProb { |