// The connection is lazily established, letting data be included in the handshake. // A subsequent Read() or Write() may fail establishing a connection. func Dial(addr *net.UDPAddr) (c *CurveCPConn, err error) { c = new(CurveCPConn) c.client = new(curveCPClient) c.ephPublicKey, c.ephPrivateKey, err = box.GenerateKey(rand.Reader) if err != nil { return nil, err } // TODO: fetch server and client long-term keys var sPublicKey [32]byte var cPrivateKey [32]byte box.Precompute(&c.client.sharedHelloKey, &sPublicKey, c.ephPrivateKey) box.Precompute(&c.client.sharedVouchKey, &sPublicKey, &cPrivateKey) nonceInt, err := rand.Int(rand.Reader, big.NewInt(1<<48)) // start incrementing at random [0,2^48) if err != nil { return nil, err } c.nonce = nonceInt.Int64() c.conn, err = net.DialUDP("udp", nil, addr) if err != nil { return nil, err } c.sendHello() deadline := 1000 // TODO: add to connection struct connectionTimeout := time.NewTimer(min(deadline, 60*time.Second)) cookies := make(chan bool) go c.cookieReceiver(cookies) for { select { case <-cookies: break case <-time.After(time.Second): // repeat Hello; TODO: fuzz + backoff c.sendHello() case <-connectionTimeout.C: return nil, ConnectionTimeoutError } } go c.clientReactor() return c, nil }
func newConn(sock *net.UDPConn, peerIdentity, publicKey, privateKey []byte, domain string) *conn { if len(peerIdentity) != 32 || len(publicKey) != 32 || len(privateKey) != 32 { panic("wrong key size") } c := &conn{ domain: domain, packetIn: make(chan packet), sock: sock, readRequest: make(chan []byte), writeRequest: make(chan []byte), ioResult: make(chan opResult), toSend: list.New(), sendFree: list.New(), received: ringbuf.New(recvBufferSize), } // Key setup. copy(c.peerIdentity[:], peerIdentity) var pub, priv [32]byte copy(pub[:], publicKey) copy(priv[:], privateKey) box.Precompute(&c.sharedKey, &pub, &priv) // Send blocks for i := 0; i < numSendBlocks; i++ { c.sendFree.PushBack(new(block)) } go c.pump() return c }
func FormSessionKey(remotePublicKey, localPrivateKey *[32]byte, secretKey []byte) *[32]byte { var sharedKey [32]byte box.Precompute(&sharedKey, remotePublicKey, localPrivateKey) sharedKeySlice := sharedKey[:] sharedKeySlice = append(sharedKeySlice, secretKey...) sessionKey := sha256.Sum256(sharedKeySlice) return &sessionKey }
func (c *CurveCPConn) cookieReceiver(ch chan bool) { for { var buff [1400]byte bytesRead, err := c.conn.Read(buff[:]) if err != nil { // TODO: debug continue } if bytesRead != cookiePacketLength { debug(-1, -1, packetDiscard, 'd', unknownPkt) continue } if !bytes.HasPrefix(buff[:], cookiePkt.magic) { debug() continue } var text [128]byte var nonce [24]byte var sEphPublicKey [32]byte copy(nonce, cookiePkt.noncePrefix) copy(nonce[8:], packet[40:56]) _, ok := box.OpenAfterPrecomputation(text, packet[56:], &nonce, &c.client.sharedHelloKey) if ok == false { debug(-1, -1, packetDiscard, 'd', unknownPkt) continue } copy(sEphPublicKey, text[0:32]) box.Precompute(&c.sharedKey, &sEphPublicKey, &c.ephPrivateKey) copy(c.client.serverCookie, text[32:]) ch <- true break } }