summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--csrand/csrand.go (renamed from utils.go)42
-rw-r--r--handshake_ntor.go8
-rw-r--r--ntor/ntor.go5
-rw-r--r--obfs4.go6
-rw-r--r--replay_filter.go5
-rw-r--r--weighted_dist.go7
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
}
diff --git a/obfs4.go b/obfs4.go
index 3bbccb3..6978a97 100644
--- a/obfs4.go
+++ b/obfs4.go
@@ -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 {