diff --git a/obfs4.go b/obfs4.go
index 429ba95f655c9ae2e762e4df38449bc2ffcf8bc3..d3dfc3854ef4a26a52fa1bd1ce43ddb1cb80cd85 100644
--- a/obfs4.go
+++ b/obfs4.go
@@ -467,12 +467,15 @@ func Dial(network, address, nodeID, publicKey string) (net.Conn, error) {
 		return nil, err
 	}
 
-	// Connect to the peer.
-	c := new(Obfs4Conn)
-	c.lenProbDist, err = newWDist(nil, 0, framing.MaximumSegmentLength)
+	// Generate the initial length obfuscation distribution.
+	seed, err := newRandomDrbgSeed()
 	if err != nil {
 		return nil, err
 	}
+
+	// Connect to the peer.
+	c := new(Obfs4Conn)
+	c.lenProbDist = newWDist(seed, 0, framing.MaximumSegmentLength)
 	c.conn, err = net.Dial(network, address)
 	if err != nil {
 		return nil, err
@@ -495,6 +498,7 @@ type Obfs4Listener struct {
 
 	keyPair *ntor.Keypair
 	nodeID  *ntor.NodeID
+	seed    *drbgSeed
 }
 
 func (l *Obfs4Listener) Accept() (net.Conn, error) {
@@ -509,7 +513,7 @@ func (l *Obfs4Listener) Accept() (net.Conn, error) {
 	cObfs.conn = c
 	cObfs.isServer = true
 	cObfs.listener = l
-	cObfs.lenProbDist, err = newWDist(nil, 0, framing.MaximumSegmentLength)
+	cObfs.lenProbDist = newWDist(l.seed, 0, framing.MaximumSegmentLength)
 	if err != nil {
 		c.Close()
 		return nil, err
@@ -548,6 +552,13 @@ func Listen(network, laddr, nodeID, privateKey string) (net.Listener, error) {
 		return nil, err
 	}
 
+	// Generate the initial length obfuscation distribution.
+	// XXX: Load this from args.
+	l.seed, err = newRandomDrbgSeed()
+	if err != nil {
+		return nil, err
+	}
+
 	// Start up the listener.
 	l.listener, err = net.Listen(network, laddr)
 	if err != nil {
diff --git a/packet.go b/packet.go
index 75179cbe17e769e00b30691df2d2f5ddb7b78286..2528a53be9f70e725e629e3f16db71ed694438d4 100644
--- a/packet.go
+++ b/packet.go
@@ -173,8 +173,13 @@ func (c *Obfs4Conn) consumeFramedPackets(w io.Writer) (n int, err error) {
 			}
 		case packetTypePrngSeed:
 			// Only regenerate the distribution if we are the client.
-			if len(payload) >= distSeedLength && !c.isServer {
-				c.lenProbDist.reset(payload[:distSeedLength])
+			if len(payload) >= drbgSeedLength && !c.isServer {
+				var seed *drbgSeed
+				seed, err = drbgSeedFromBytes(payload[:drbgSeedLength])
+				if err != nil {
+					break
+				}
+				c.lenProbDist.reset(seed)
 			}
 		default:
 			// Ignore unrecognised packet types.
diff --git a/weighted_dist.go b/weighted_dist.go
index b1658692636cd0f07c4ee6727600f0c7d8c8fffb..56128ae6c1dca3db0e7e842e6497fe3b1e93f2a7 100644
--- a/weighted_dist.go
+++ b/weighted_dist.go
@@ -29,6 +29,7 @@ package obfs4
 
 import (
 	csrand "crypto/rand"
+	"encoding/base64"
 	"encoding/binary"
 	"fmt"
 	"hash"
@@ -37,7 +38,51 @@ import (
 	"github.com/dchest/siphash"
 )
 
-const distSeedLength = 16
+const drbgSeedLength = 32
+
+// drbgSeed is the initial state for a hashDrbg.  It consists of a SipHash-2-4
+// key, and 16 bytes of initial data.
+type drbgSeed [drbgSeedLength]byte
+
+// bytes returns a pointer to the raw hashDrbg seed.
+func (seed *drbgSeed) bytes() *[drbgSeedLength]byte {
+	return (*[drbgSeedLength]byte)(seed)
+}
+
+// base64 returns the Base64 representation of the seed.
+func (seed *drbgSeed) base64() string {
+	return base64.StdEncoding.EncodeToString(seed.bytes()[:])
+}
+
+// newRandomDrbgSeed returns a drbgSeed initialized with the runtime CSPRNG.
+func newRandomDrbgSeed() (seed *drbgSeed, err error) {
+	seed = new(drbgSeed)
+	_, err = csrand.Read(seed.bytes()[:])
+	if err != nil {
+		return nil, err
+	}
+
+	return
+}
+
+// drbgSeedFromBytes returns a drbg seed initialized with the caller provided
+// slice.
+func drbgSeedFromBytes(src []byte) (seed *drbgSeed, err error) {
+	if len(src) != drbgSeedLength {
+		return nil, InvalidSeedLengthError(len(src))
+	}
+
+	seed = new(drbgSeed)
+	copy(seed.bytes()[:], src)
+
+	return
+}
+
+/*
+func drbgSeedFromBse64(encoded string) (seed *drbgSeed, err error) {
+	return
+}
+*/
 
 // InvalidSeedLengthError is the error returned when the seed provided to the
 // DRBG is an invalid length.
@@ -54,10 +99,11 @@ type hashDrbg struct {
 }
 
 // newHashDrbg makes a hashDrbg instance based off an optional seed.  The seed
-// is truncated to distSeedLength.
-func newHashDrbg(seed []byte) *hashDrbg {
+// is truncated to drbgSeedLength.
+func newHashDrbg(seed *drbgSeed) *hashDrbg {
 	drbg := new(hashDrbg)
-	drbg.sip = siphash.New(seed)
+	drbg.sip = siphash.New(seed.bytes()[:16])
+	copy(drbg.ofb[:], seed.bytes()[16:])
 
 	return drbg
 }
@@ -88,9 +134,9 @@ type wDist struct {
 }
 
 // newWDist creates a weighted distribution of values ranging from min to max
-// based on a CSDRBG initialized with the optional 128 bit seed.
-func newWDist(seed []byte, min, max int) (*wDist, error) {
-	w := new(wDist)
+// based on a hashDrbg initialized with seed.
+func newWDist(seed *drbgSeed, min, max int) (w *wDist) {
+	w = new(wDist)
 	w.minValue = min
 	w.maxValue = max
 
@@ -98,12 +144,9 @@ func newWDist(seed []byte, min, max int) (*wDist, error) {
 		panic(fmt.Sprintf("wDist.Reset(): min >= max (%d, %d)", min, max))
 	}
 
-	err := w.reset(seed)
-	if err != nil {
-		return nil, err
-	}
+	w.reset(seed)
 
-	return w, nil
+	return
 }
 
 // sample generates a random value according to the distribution.
@@ -123,18 +166,7 @@ func (w *wDist) sample() int {
 }
 
 // reset generates a new distribution with the same min/max based on a new seed.
-func (w *wDist) reset(seed []byte) error {
-	if seed == nil {
-		seed = make([]byte, distSeedLength)
-		_, err := csrand.Read(seed)
-		if err != nil {
-			return err
-		}
-	}
-	if len(seed) != distSeedLength {
-		return InvalidSeedLengthError(len(seed))
-	}
-
+func (w *wDist) reset(seed *drbgSeed) {
 	// Initialize the deterministic random number generator.
 	drbg := newHashDrbg(seed)
 	dRng := rand.New(drbg)
@@ -150,8 +182,6 @@ func (w *wDist) reset(seed []byte) error {
 		totalProb += prob
 	}
 	w.buckets[len(w.buckets)-1] = 1.0
-
-	return nil
 }
 
 /* vim :set ts=4 sw=4 sts=4 noet : */