コード例 #1
0
ファイル: statefile.go プロジェクト: getlantern/obfs4
func newJSONServerState(stateDir string, js *jsonServerState) (err error) {
	// Generate everything a server needs, using the cryptographic PRNG.
	var st obfs4ServerState
	rawID := make([]byte, ntor.NodeIDLength)
	if err = csrand.Bytes(rawID); err != nil {
		return
	}
	if st.nodeID, err = ntor.NewNodeID(rawID); err != nil {
		return
	}
	if st.identityKey, err = ntor.NewKeypair(false); err != nil {
		return
	}
	if st.drbgSeed, err = drbg.NewSeed(); err != nil {
		return
	}
	st.iatMode = iatNone

	// Encode it into JSON format and write the state file.
	js.NodeID = st.nodeID.Hex()
	js.PrivateKey = st.identityKey.Private().Hex()
	js.PublicKey = st.identityKey.Public().Hex()
	js.DrbgSeed = st.drbgSeed.Hex()
	js.IATMode = st.iatMode

	return writeJSONServerState(stateDir, js)
}
コード例 #2
0
func makePad(padLen int) ([]byte, error) {
	pad := make([]byte, padLen)
	if err := csrand.Bytes(pad); err != nil {
		return nil, err
	}
	return pad, nil
}
コード例 #3
0
ファイル: hash_drbg.go プロジェクト: manawenuz/obfs4
// NewSeed returns a Seed initialized with the runtime CSPRNG.
func NewSeed() (seed *Seed, err error) {
	seed = new(Seed)
	if err = csrand.Bytes(seed.Bytes()[:]); err != nil {
		return nil, err
	}

	return
}
コード例 #4
0
ファイル: obfs3.go プロジェクト: wan-qy/obfs4
func (conn *obfs3Conn) handshake() error {
	// The party who opens the connection is the 'initiator'; the one who
	// accepts it is the 'responder'.  Each begins by generating a
	// UniformDH keypair, and a random number PADLEN in [0, MAX_PADDING/2].
	// Both parties then send:
	//
	//  PUB_KEY | WR(PADLEN)
	privateKey, err := uniformdh.GenerateKey(csrand.Reader)
	if err != nil {
		return err
	}
	padLen := csrand.IntRange(0, maxPadding/2)
	blob := make([]byte, uniformdh.Size+padLen)
	publicKey, err := privateKey.PublicKey.Bytes()
	if err != nil {
		return err
	}
	copy(blob[0:], publicKey)
	if err := csrand.Bytes(blob[uniformdh.Size:]); err != nil {
		return err
	}
	if _, err := conn.Conn.Write(blob); err != nil {
		return err
	}

	// Read the public key from the peer.
	rawPeerPublicKey := make([]byte, uniformdh.Size)
	if _, err := io.ReadFull(conn.Conn, rawPeerPublicKey); err != nil {
		return err
	}
	var peerPublicKey uniformdh.PublicKey
	if err := peerPublicKey.SetBytes(rawPeerPublicKey); err != nil {
		return err
	}

	// After retrieving the public key of the other end, each party
	// completes the DH key exchange and generates a shared-secret for the
	// session (named SHARED_SECRET).
	sharedSecret, err := uniformdh.Handshake(privateKey, &peerPublicKey)
	if err != nil {
		return err
	}
	if err := conn.kdf(sharedSecret); err != nil {
		return err
	}

	return nil
}
コード例 #5
0
ファイル: replay_filter.go プロジェクト: manawenuz/obfs4
// New creates a new ReplayFilter instance.
func New(ttl time.Duration) (filter *ReplayFilter, err error) {
	// Initialize the SipHash-2-4 instance with a random key.
	var key [16]byte
	if err = csrand.Bytes(key[:]); err != nil {
		return
	}

	filter = new(ReplayFilter)
	filter.filter = make(map[uint64]*entry)
	filter.fifo = list.New()
	filter.key[0] = binary.BigEndian.Uint64(key[0:8])
	filter.key[1] = binary.BigEndian.Uint64(key[8:16])
	filter.ttl = ttl

	return
}
コード例 #6
0
ファイル: obfs3.go プロジェクト: wan-qy/obfs4
func (conn *obfs3Conn) Write(b []byte) (n int, err error) {
	// If this is the first time we write data post handshake, send the
	// padding/magic value.
	if conn.txMagic != nil {
		padLen := csrand.IntRange(0, maxPadding/2)
		blob := make([]byte, padLen+len(conn.txMagic))
		if err = csrand.Bytes(blob[:padLen]); err != nil {
			conn.Close()
			return
		}
		copy(blob[padLen:], conn.txMagic)
		if _, err = conn.Conn.Write(blob); err != nil {
			conn.Close()
			return
		}
		conn.txMagic = nil
	}

	return conn.tx.Write(b)
}
コード例 #7
0
ファイル: ntor.go プロジェクト: manawenuz/obfs4
// NewKeypair generates a new Curve25519 keypair, and optionally also generates
// an Elligator representative of the public key.
func NewKeypair(elligator bool) (*Keypair, error) {
	keypair := new(Keypair)
	keypair.private = new(PrivateKey)
	keypair.public = new(PublicKey)
	if elligator {
		keypair.representative = new(Representative)
	}

	for {
		// Generate a Curve25519 private key.  Like everyone who does this,
		// run the CSPRNG output through SHA256 for extra tinfoil hattery.
		priv := keypair.private.Bytes()[:]
		if err := csrand.Bytes(priv); err != nil {
			return nil, err
		}
		digest := sha256.Sum256(priv)
		digest[0] &= 248
		digest[31] &= 127
		digest[31] |= 64
		copy(priv, digest[:])

		if elligator {
			// Apply the Elligator transform.  This fails ~50% of the time.
			if !extra25519.ScalarBaseMult(keypair.public.Bytes(),
				keypair.representative.Bytes(),
				keypair.private.Bytes()) {
				continue
			}
		} else {
			// Generate the corresponding Curve25519 public key.
			curve25519.ScalarBaseMult(keypair.public.Bytes(),
				keypair.private.Bytes())
		}

		return keypair, nil
	}
}
コード例 #8
0
ファイル: obfs2.go プロジェクト: manawenuz/obfs4
func (conn *obfs2Conn) handshake() error {
	// Each begins by generating a seed and a padding key as follows.
	// The initiator generates:
	//
	//  INIT_SEED = SR(SEED_LENGTH)
	//  INIT_PAD_KEY = MAC("Initiator obfuscation padding", INIT_SEED)[:KEYLEN]
	//
	// And the responder generates:
	//
	//  RESP_SEED = SR(SEED_LENGTH)
	//  RESP_PAD_KEY = MAC("Responder obfuscation padding", INIT_SEED)[:KEYLEN]
	//
	// Each then generates a random number PADLEN in range from 0 through
	// MAX_PADDING (inclusive).
	var seed [seedLen]byte
	if err := csrand.Bytes(seed[:]); err != nil {
		return err
	}
	var padMagic []byte
	if conn.isInitiator {
		padMagic = []byte(initiatorPadString)
	} else {
		padMagic = []byte(responderPadString)
	}
	padKey, padIV := hsKdf(padMagic, seed[:], conn.isInitiator)
	padLen := uint32(csrand.IntRange(0, maxPadding))

	hsBlob := make([]byte, hsLen+padLen)
	binary.BigEndian.PutUint32(hsBlob[0:4], magicValue)
	binary.BigEndian.PutUint32(hsBlob[4:8], padLen)
	if padLen > 0 {
		if err := csrand.Bytes(hsBlob[8:]); err != nil {
			return err
		}
	}

	// The initiator then sends:
	//
	//  INIT_SEED | E(INIT_PAD_KEY, UINT32(MAGIC_VALUE) | UINT32(PADLEN) | WR(PADLEN))
	//
	// and the responder sends:
	//
	//  RESP_SEED | E(RESP_PAD_KEY, UINT32(MAGIC_VALUE) | UINT32(PADLEN) | WR(PADLEN))
	txBlock, err := aes.NewCipher(padKey)
	if err != nil {
		return err
	}
	txStream := cipher.NewCTR(txBlock, padIV)
	conn.tx = &cipher.StreamWriter{S: txStream, W: conn.Conn}
	if _, err := conn.Conn.Write(seed[:]); err != nil {
		return err
	}
	if _, err := conn.Write(hsBlob); err != nil {
		return err
	}

	// Upon receiving the SEED from the other party, each party derives
	// the other party's padding key value as above, and decrypts the next
	// 8 bytes of the key establishment message.
	var peerSeed [seedLen]byte
	if _, err := io.ReadFull(conn.Conn, peerSeed[:]); err != nil {
		return err
	}
	var peerPadMagic []byte
	if conn.isInitiator {
		peerPadMagic = []byte(responderPadString)
	} else {
		peerPadMagic = []byte(initiatorPadString)
	}
	peerKey, peerIV := hsKdf(peerPadMagic, peerSeed[:], !conn.isInitiator)
	rxBlock, err := aes.NewCipher(peerKey)
	if err != nil {
		return err
	}
	rxStream := cipher.NewCTR(rxBlock, peerIV)
	conn.rx = &cipher.StreamReader{S: rxStream, R: conn.Conn}
	hsHdr := make([]byte, hsLen)
	if _, err := io.ReadFull(conn, hsHdr[:]); err != nil {
		return err
	}

	// If the MAGIC_VALUE does not match, or the PADLEN value is greater than
	// MAX_PADDING, the party receiving it should close the connection
	// immediately.
	if peerMagic := binary.BigEndian.Uint32(hsHdr[0:4]); peerMagic != magicValue {
		return fmt.Errorf("invalid magic value: %x", peerMagic)
	}
	padLen = binary.BigEndian.Uint32(hsHdr[4:8])
	if padLen > maxPadding {
		return fmt.Errorf("padlen too long: %d", padLen)
	}

	// Otherwise, it should read the remaining PADLEN bytes of padding data
	// and discard them.
	tmp := make([]byte, padLen)
	if _, err := io.ReadFull(conn.Conn, tmp); err != nil { // Note: Skips AES.
		return err
	}

	// Derive the actual keys.
	if err := conn.kdf(seed[:], peerSeed[:]); err != nil {
		return err
	}

	return nil
}