+func (h *handshake) initerSteps() (ret io.ReadWriter, err error) {
+ h.postWrite(hash(req1, h.s.Bytes()))
+ h.postWrite(xor(hash(req2, h.skey), hash(req3, h.s.Bytes())))
+ buf := &bytes.Buffer{}
+ err = (&cryptoNegotiation{
+ Method: cryptoMethodRC4,
+ PadLen: uint16(newPadLen()),
+ }).MarshalWriter(buf)
+ if err != nil {
+ return
+ }
+ err = marshal(buf, uint16(0))
+ if err != nil {
+ return
+ }
+ e := newEncrypt(true, h.s.Bytes(), h.skey)
+ be := make([]byte, buf.Len())
+ e.XORKeyStream(be, buf.Bytes())
+ h.postWrite(be)
+ bC := newEncrypt(false, h.s.Bytes(), h.skey)
+ var eVC [8]byte
+ bC.XORKeyStream(eVC[:], make([]byte, 8))
+ log.Print(eVC)
+ // Read until the all zero VC.
+ err = readUntil(h.conn, eVC[:])
+ if err != nil {
+ err = fmt.Errorf("error reading until VC: %s", err)
+ return
+ }
+ var cn cryptoNegotiation
+ r := &cipherReader{bC, h.conn}
+ err = cn.UnmarshalReader(io.MultiReader(bytes.NewReader(make([]byte, 8)), r))
+ log.Printf("initer got %v", cn)
+ if err != nil {
+ err = fmt.Errorf("error reading crypto negotiation: %s", err)
+ return
+ }
+ ret = readWriter{r, &cipherWriter{e, h.conn}}
+ return
+}
+
+func (h *handshake) receiverSteps() (ret io.ReadWriter, err error) {
+ err = readUntil(h.conn, hash(req1, h.s.Bytes()))
+ if err != nil {
+ return
+ }
+ var b [20]byte
+ _, err = io.ReadFull(h.conn, b[:])
+ if err != nil {
+ return
+ }
+ err = errors.New("skey doesn't match")
+ for _, skey := range h.skeys {
+ if bytes.Equal(xor(hash(req2, skey), hash(req3, h.s.Bytes())), b[:]) {
+ h.skey = skey
+ err = nil
+ break
+ }
+ }
+ if err != nil {
+ return
+ }
+ var cn cryptoNegotiation
+ r := newCipherReader(newEncrypt(true, h.s.Bytes(), h.skey), h.conn)
+ err = cn.UnmarshalReader(r)
+ if err != nil {
+ return
+ }
+ log.Printf("receiver got %v", cn)
+ if cn.Method&cryptoMethodRC4 == 0 {
+ err = errors.New("no supported crypto methods were provided")
+ return
+ }
+ unmarshal(r, new(uint16))
+ buf := &bytes.Buffer{}
+ w := cipherWriter{newEncrypt(false, h.s.Bytes(), h.skey), buf}
+ err = (&cryptoNegotiation{
+ Method: cryptoMethodRC4,
+ PadLen: uint16(newPadLen()),
+ }).MarshalWriter(&w)
+ if err != nil {
+ return
+ }
+ err = h.postWrite(buf.Bytes())
+ if err != nil {
+ return
+ }
+ ret = readWriter{r, &cipherWriter{w.c, h.conn}}
+ return
+}
+