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) }
func makePad(padLen int) ([]byte, error) { pad := make([]byte, padLen) if err := csrand.Bytes(pad); err != nil { return nil, err } return pad, nil }
// 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 }
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 }
// 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 }
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) }
// 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 } }
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 }