summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYawning Angel <yawning@schwanenlied.me>2014-05-15 20:21:46 +0000
committerYawning Angel <yawning@schwanenlied.me>2014-05-15 20:21:46 +0000
commit77090696177d7b0a9dfd5a11c0ac7dbaa3623d6b (patch)
treefc974b73e245d9e3af6f30ff3cbe2f8d5c45d900
parent6f875c99a9047d8a04a9ac2db9c6305dee3e2901 (diff)
Send the DRBG seed as a packetTypePrngSeed post server handshake.
This fixes #3, and brings the code to be on par with the delopyed versions of ScrambleSuit in terms of features.
-rw-r--r--obfs4.go79
-rw-r--r--obfs4proxy/obfs4proxy.go2
-rw-r--r--packet.go11
3 files changed, 53 insertions, 39 deletions
diff --git a/obfs4.go b/obfs4.go
index 17f8b3c..f13e14a 100644
--- a/obfs4.go
+++ b/obfs4.go
@@ -79,18 +79,37 @@ type Obfs4Conn struct {
listener *Obfs4Listener
}
-func (c *Obfs4Conn) calcPadLen(burstLen int) int {
- tailLen := burstLen % framing.MaximumSegmentLength
+func (c *Obfs4Conn) padBurst(burst *bytes.Buffer) (err error) {
+ tailLen := burst.Len() % framing.MaximumSegmentLength
toPadTo := c.lenProbDist.sample()
- ret := 0
+ padLen := 0
if toPadTo >= tailLen {
- ret = toPadTo - tailLen
+ padLen = toPadTo - tailLen
} else {
- ret = (framing.MaximumSegmentLength - tailLen) + toPadTo
+ padLen = (framing.MaximumSegmentLength - tailLen) + toPadTo
}
- return ret
+ if padLen > headerLength {
+ err = c.producePacket(burst, packetTypePayload, []byte{},
+ uint16(padLen-headerLength))
+ if err != nil {
+ return
+ }
+ } else if padLen > 0 {
+ err = c.producePacket(burst, packetTypePayload, []byte{},
+ maxPacketPayloadLength)
+ if err != nil {
+ return
+ }
+ err = c.producePacket(burst, packetTypePayload, []byte{},
+ uint16(padLen))
+ if err != nil {
+ return
+ }
+ }
+
+ return
}
func (c *Obfs4Conn) closeAfterDelay() {
@@ -231,6 +250,11 @@ func (c *Obfs4Conn) serverHandshake(nodeID *ntor.NodeID, keypair *ntor.Keypair)
}
c.receiveBuffer.Reset()
+ err = c.conn.SetDeadline(time.Time{})
+ if err != nil {
+ return
+ }
+
// Use the derived key material to intialize the link crypto.
okm := ntor.Kdf(seed, framing.KeyLength*2)
c.encoder = framing.NewEncoder(okm[framing.KeyLength:])
@@ -249,17 +273,21 @@ func (c *Obfs4Conn) serverHandshake(nodeID *ntor.NodeID, keypair *ntor.Keypair)
if err != nil {
return
}
+ c.state = stateEstablished
- err = c.conn.SetDeadline(time.Time{})
+ // Send the PRNG seed as the first packet.
+ var frameBuf bytes.Buffer
+ err = c.producePacket(&frameBuf, packetTypePrngSeed, c.listener.seed.Bytes()[:], 0)
if err != nil {
return
}
+ err = c.padBurst(&frameBuf)
+ if err != nil {
+ return
+ }
+ _, err = c.conn.Write(frameBuf.Bytes())
- c.state = stateEstablished
-
- // TODO: Generate/send the PRNG seed.
-
- return nil
+ return
}
func (c *Obfs4Conn) CanHandshake() bool {
@@ -379,27 +407,12 @@ func (c *Obfs4Conn) Write(b []byte) (n int, err error) {
}
}
- // Insert random padding. In theory it's possible to inline padding for
- // certain framesizes into the last AEAD packet, but always sending 1 or 2
- // padding frames is considerably easier.
- padLen := c.calcPadLen(frameBuf.Len())
- if padLen > headerLength {
- err = c.producePacket(&frameBuf, packetTypePayload, []byte{},
- uint16(padLen-headerLength))
- if err != nil {
- return 0, err
- }
- } else if padLen > 0 {
- err = c.producePacket(&frameBuf, packetTypePayload, []byte{},
- maxPacketPayloadLength)
- if err != nil {
- return 0, err
- }
- err = c.producePacket(&frameBuf, packetTypePayload, []byte{},
- uint16(padLen))
- if err != nil {
- return 0, err
- }
+ // Insert random padding. In theory for some padding lengths, this can be
+ // inlined with the payload, but doing it this way simplifies the code
+ // significantly.
+ err = c.padBurst(&frameBuf)
+ if err != nil {
+ return 0, err
}
// Send the frame(s).
diff --git a/obfs4proxy/obfs4proxy.go b/obfs4proxy/obfs4proxy.go
index 02873b9..8447eb8 100644
--- a/obfs4proxy/obfs4proxy.go
+++ b/obfs4proxy/obfs4proxy.go
@@ -39,7 +39,7 @@
// ORPort 9001
// ExtORPort 6669
// ServerTransportPlugin obfs4 exec obfs4proxy
-// ServerTransportOptions obfs4 private-key=<Base64 Bridge private key> node-id=<Base64 Node ID>
+// ServerTransportOptions obfs4 private-key=<Base64 Bridge private key> node-id=<Base64 Node ID> drbg-seed=<Base64 DRBG seed>
//
// Because the pluggable transport requires arguments, obfs4proxy requires
// tor-0.2.5.x to be useful.
diff --git a/packet.go b/packet.go
index f1c0ab1..4112c9b 100644
--- a/packet.go
+++ b/packet.go
@@ -37,9 +37,10 @@ import (
)
const (
- packetOverhead = 2 + 1
- maxPacketPayloadLength = framing.MaximumFramePayloadLength - packetOverhead
- maxPacketPaddingLength = maxPacketPayloadLength
+ packetOverhead = 2 + 1
+ maxPacketPayloadLength = framing.MaximumFramePayloadLength - packetOverhead
+ maxPacketPaddingLength = maxPacketPayloadLength
+ seedPacketPayloadLength = DrbgSeedLength
consumeReadSize = framing.MaximumSegmentLength * 16
)
@@ -173,9 +174,9 @@ 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) >= DrbgSeedLength && !c.isServer {
+ if len(payload) == seedPacketPayloadLength && !c.isServer {
var seed *DrbgSeed
- seed, err = DrbgSeedFromBytes(payload[:DrbgSeedLength])
+ seed, err = DrbgSeedFromBytes(payload)
if err != nil {
break
}