// NewDecoder creates a new Decoder instance. It must be supplied a slice // containing exactly KeyLength bytes of keying material. func NewDecoder(key []byte) *Decoder { if len(key) != KeyLength { panic(fmt.Sprintf("BUG: Invalid decoder key length: %d", len(key))) } decoder := new(Decoder) copy(decoder.key[:], key[0:keyLength]) decoder.nonce.init(key[keyLength : keyLength+noncePrefixLength]) seed, err := drbg.SeedFromBytes(key[keyLength+noncePrefixLength:]) if err != nil { panic(fmt.Sprintf("BUG: Failed to initialize DRBG: %s", err)) } decoder.drbg, _ = drbg.NewHashDrbg(seed) return decoder }
func newObfs4ClientConn(conn net.Conn, args *obfs4ClientArgs) (c *obfs4Conn, err error) { // Generate the initial protocol polymorphism distribution(s). var seed *drbg.Seed if seed, err = drbg.NewSeed(); err != nil { return } lenDist := probdist.New(seed, 0, framing.MaximumSegmentLength, biasedDist) var iatDist *probdist.WeightedDist if args.iatMode != iatNone { var iatSeed *drbg.Seed iatSeedSrc := sha256.Sum256(seed.Bytes()[:]) if iatSeed, err = drbg.SeedFromBytes(iatSeedSrc[:]); err != nil { return } iatDist = probdist.New(iatSeed, 0, maxIATDelay, biasedDist) } // Allocate the client structure. c = &obfs4Conn{conn, false, lenDist, iatDist, args.iatMode, bytes.NewBuffer(nil), bytes.NewBuffer(nil), nil, nil} // Start the handshake timeout. deadline := time.Now().Add(clientHandshakeTimeout) if err = conn.SetDeadline(deadline); err != nil { return nil, err } if err = c.clientHandshake(args.nodeID, args.publicKey, args.sessionKey); err != nil { return nil, err } // Stop the handshake timeout. if err = conn.SetDeadline(time.Time{}); err != nil { return nil, err } return }
// ServerFactory returns a new obfs4ServerFactory instance. func (t *Transport) ServerFactory(stateDir string, args *pt.Args) (base.ServerFactory, error) { st, err := serverStateFromArgs(stateDir, args) if err != nil { return nil, err } var iatSeed *drbg.Seed if st.iatMode != iatNone { iatSeedSrc := sha256.Sum256(st.drbgSeed.Bytes()[:]) var err error iatSeed, err = drbg.SeedFromBytes(iatSeedSrc[:]) if err != nil { return nil, err } } // Store the arguments that should appear in our descriptor for the clients. ptArgs := pt.Args{} ptArgs.Add(certArg, st.cert.String()) ptArgs.Add(iatArg, strconv.Itoa(st.iatMode)) // Initialize the replay filter. filter, err := replayfilter.New(replayTTL) if err != nil { return nil, err } // Initialize the close thresholds for failed connections. drbg, err := drbg.NewHashDrbg(st.drbgSeed) if err != nil { return nil, err } rng := rand.New(drbg) sf := &obfs4ServerFactory{t, &ptArgs, st.nodeID, st.identityKey, st.drbgSeed, iatSeed, st.iatMode, filter, rng.Intn(maxCloseDelayBytes), rng.Intn(maxCloseDelay)} return sf, nil }
func (conn *obfs4Conn) readPackets() (err error) { // Attempt to read off the network. var buf [consumeReadSize]byte rdLen, rdErr := conn.Conn.Read(buf[:]) conn.receiveBuffer.Write(buf[:rdLen]) var decoded [framing.MaximumFramePayloadLength]byte for conn.receiveBuffer.Len() > 0 { // Decrypt an AEAD frame. decLen := 0 decLen, err = conn.decoder.Decode(decoded[:], conn.receiveBuffer) if err == framing.ErrAgain { break } else if err != nil { break } else if decLen < packetOverhead { err = InvalidPacketLengthError(decLen) break } // Decode the packet. pkt := decoded[0:decLen] pktType := pkt[0] payloadLen := binary.BigEndian.Uint16(pkt[1:]) if int(payloadLen) > len(pkt)-packetOverhead { err = InvalidPayloadLengthError(int(payloadLen)) break } payload := pkt[3 : 3+payloadLen] switch pktType { case packetTypePayload: if payloadLen > 0 { conn.receiveDecodedBuffer.Write(payload) } case packetTypePrngSeed: // Only regenerate the distribution if we are the client. if len(payload) == seedPacketPayloadLength && !conn.isServer { var seed *drbg.Seed seed, err = drbg.SeedFromBytes(payload) if err != nil { break } conn.lenDist.Reset(seed) if conn.iatDist != nil { iatSeedSrc := sha256.Sum256(seed.Bytes()[:]) iatSeed, err := drbg.SeedFromBytes(iatSeedSrc[:]) if err != nil { break } conn.iatDist.Reset(iatSeed) } } default: // Ignore unknown packet types. } } // Read errors (all fatal) take priority over various frame processing // errors. if rdErr != nil { return rdErr } return }
func (conn *ssConn) readPackets() error { // Consume and buffer up to 1 MSS worth of data. var buf [maxSegmentLength]byte rdLen, rdErr := conn.Conn.Read(buf[:]) conn.receiveBuffer.Write(buf[:rdLen]) // Process incoming packets incrementally. conn.receiveState stores // the results of partial processing. for conn.receiveBuffer.Len() > 0 { if conn.receiveState.mac == nil { // Read and store the packet MAC. if conn.receiveBuffer.Len() < macLength { break } mac := make([]byte, macLength) conn.receiveBuffer.Read(mac) conn.receiveState.mac = mac } if conn.receiveState.hdr == nil { // Read and store the packet header. if conn.receiveBuffer.Len() < pktHdrLength { break } hdr := make([]byte, pktHdrLength) conn.receiveBuffer.Read(hdr) // Add the encrypted packet header to the HMAC instance, and then // decrypt it so that the length of the packet can be determined. conn.rxCrypto.mac.Reset() conn.rxCrypto.mac.Write(hdr) conn.rxCrypto.s.XORKeyStream(hdr, hdr) // Store the plaintext packet header, and host byte order length // values. totalLen := int(binary.BigEndian.Uint16(hdr[0:])) payloadLen := int(binary.BigEndian.Uint16(hdr[2:])) if payloadLen > totalLen || totalLen > maxPayloadLength { return ErrInvalidPacket } conn.receiveState.hdr = hdr conn.receiveState.totalLen = totalLen conn.receiveState.payloadLen = payloadLen } var data []byte if conn.receiveState.totalLen > 0 { // If the packet actually has payload (including padding), read, // digest and decrypt it. if conn.receiveBuffer.Len() < conn.receiveState.totalLen { break } data = make([]byte, conn.receiveState.totalLen) conn.receiveBuffer.Read(data) conn.rxCrypto.mac.Write(data) conn.rxCrypto.s.XORKeyStream(data, data) } // Authenticate the packet, by comparing the received MAC with the one // calculated over the ciphertext consumed off the network. cmpMAC := conn.rxCrypto.mac.Sum(nil)[:macLength] if !hmac.Equal(cmpMAC, conn.receiveState.mac[:]) { return ErrInvalidPacket } // Based on the packet flags, do something useful with the payload. data = data[:conn.receiveState.payloadLen] switch conn.receiveState.hdr[4] { case pktPayload: // User data, write it into the decoded payload buffer so that Read // calls can be serviced. conn.receiveDecodedBuffer.Write(data) case pktNewTicket: // New Session Ticket to be used for future handshakes, store it in // the Session Ticket store. if conn.isServer || len(data) != ticketKeyLength+ticketLength { return ErrInvalidPacket } conn.ticketStore.storeTicket(conn.RemoteAddr(), data) case pktPrngSeed: // New PRNG_SEED for the protocol polymorphism. Regenerate the // length obfuscation probability distribution. if conn.isServer || len(data) != pktPrngSeedLength { return ErrInvalidPacket } seed, err := drbg.SeedFromBytes(data) if err != nil { return ErrInvalidPacket } conn.lenDist.Reset(seed) default: return ErrInvalidPacket } // Done processing a packet, clear the partial state. conn.receiveState.mac = nil conn.receiveState.hdr = nil conn.receiveState.totalLen = 0 conn.receiveState.payloadLen = 0 } return rdErr }