| // Copyright 2016 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package grpc |
| |
| import ( |
| "bytes" |
| _ "encoding/binary" |
| "errors" |
| "fmt" |
| "io" |
| _ "io/ioutil" |
| "log" |
| "net" |
| "runtime/debug" |
| "sync" |
| "time" |
| |
| "golang.org/x/crypto/nacl/box" |
| ) |
| |
| // Implements net.Conn. Encrypts messages using keys negotioated via NaCl. |
| // TODO: blessings |
| // TODO: discharges and caveats |
| // TODO: ensuer that all 5 of these are set. Constructor? |
| // TODO: do I need to check the message size as in box_coipher.Seal? |
| // TODO: make all these keys not pointers? |
| // TODO: should I have locks here? |
| // TODO: what's all this salsa stuff? |
| type conn struct { |
| rawConn net.Conn |
| publicKey *[32]byte |
| secretKey *[32]byte |
| sharedKey *[32]byte |
| binding []byte |
| nonce [24]byte // TODO: do I need a second nonce? Does this need to be random? |
| counter uint64 // Why is this so weirdly handled in advanceNonce? |
| mu sync.Mutex |
| } |
| |
| // TODO: what if bytesRead < 3? = 3? |
| func (c *conn) Read(b []byte) (n int, err error) { |
| c.mu.Lock() |
| defer c.mu.Unlock() |
| log.Printf("Beginning to Read.\n") |
| |
| frame := [3]byte{} |
| frameCopied, err := c.rawConn.Read(frame[:]) |
| if frameCopied != 3 { |
| return -1, errors.New("Did not copy 3 frame bytes.") |
| } |
| msgSize := read3ByteUint(frame) |
| |
| resBuf := make([]byte, msgSize) // TODO better (dynamic) size or way of reading? |
| bytesRead, err := c.rawConn.Read(resBuf) |
| // log.Printf("Read %d bytes: %v\n", bytesRead, resBuf) |
| if err != nil { |
| // log.Printf("Failed to read.\n") |
| log.Fatal(err) |
| return bytesRead, err |
| } |
| |
| // tmp := make([]byte, 0, bytesRead-box.Overhead) // TODO: is this enough? Also, why do we need both of tmp and out? |
| out, ok := box.OpenAfterPrecomputation(nil, resBuf, c.currentNonce(), c.sharedKey) |
| log.Printf("%d bytes after opening: %v\n", len(out), out) |
| log.Printf("%d bytes after opening: %v\n", len(out), string(out)) |
| c.advanceNonce() // TODO: defer? Is there harm in advancing often than necessary (i.e. on error)? |
| if !ok { |
| // log.Printf("Failed to decrypt.\n") |
| //log.Fatal(err) |
| return 0, err |
| } |
| copy(b, out) |
| // should we return bytesRead or len(b)? |
| // log.Printf("cap(b): %d, len(b) %d, \ncap(out): %d, len(out): %d\n", cap(b), len(b), cap(out), len(out)) |
| log.Printf("Succeeded in reading.\n\n") |
| // return bytesRead, nil |
| return len(b), nil |
| } |
| |
| // TODO: all this casting is gross |
| func (c *conn) Write(b []byte) (n int, err error) { |
| // log.Printf("Write called:\n%v\n", string(debug.Stack())) |
| c.mu.Lock() |
| defer c.mu.Unlock() |
| log.Printf("Beginning to write.\n") |
| log.Printf("%d bytes before sealing: %v\n", len(b), b) |
| tmp := make([]byte, 3, 3+len(b)+box.Overhead) // TODO: is this enough? Also, why do we need both of tmp and out? |
| err = write3ByteUint(tmp[:3], len(b)+box.Overhead) |
| if err != nil { |
| return -1, err |
| } |
| out := box.SealAfterPrecomputation(tmp, b, c.currentNonce(), c.sharedKey) |
| // log.Printf("tmp: %v", tmp) |
| // log.Printf("out: %v", out) |
| c.advanceNonce() |
| bytesCopied, err := io.Copy(c.rawConn, bytes.NewReader(out)) |
| // log.Printf("Wrote %d bytes.\n", bytesCopied) |
| if err != nil { |
| log.Printf("Failed to copy to rawConn.\n") |
| log.Fatal(err) |
| return int(bytesCopied), err |
| } |
| if bytesCopied != int64(len(out)) { |
| errMsg := fmt.Sprintf("Did not write entire message. Expected to write %d bytes but wrote %d.", len(out), bytesCopied) |
| log.Printf("Did not write entire message. Expected to write %d bytes but wrote %d.", len(out), bytesCopied) |
| log.Printf("Failed to write.\n") |
| log.Fatal(err) |
| return -1, errors.New(errMsg) |
| } |
| // log.Printf("cap(b): %d, len(b) %d, cap(out): %d, len(out): %d\n", cap(b), len(b), cap(out), len(out)) |
| log.Printf("Succeeded in writing!\n\n") |
| // return int(bytesCopied), nil |
| return len(b), nil |
| } |
| |
| // TODO: understand this stuff |
| const maxPacketSize = 0xffffff |
| |
| func write3ByteUint(dst []byte, n int) error { |
| if n > maxPacketSize || n < 0 { |
| // return NewErrLargerThan3ByteUInt(nil) |
| return errors.New("TOOO BIG") |
| } |
| n = maxPacketSize - n |
| dst[0] = byte((n & 0xff0000) >> 16) |
| dst[1] = byte((n & 0x00ff00) >> 8) |
| dst[2] = byte(n & 0x0000ff) |
| return nil |
| } |
| |
| func read3ByteUint(src [3]byte) int { |
| return maxPacketSize - (int(src[0])<<16 | int(src[1])<<8 | int(src[2])) |
| } |
| |
| // TODO: cover these up with an interface? |
| // TODO: remove all these useless mutex locks and unlocks |
| func (c *conn) Close() error { |
| c.mu.Lock() |
| defer c.mu.Unlock() |
| debug.PrintStack() |
| // log.Fatalf("DON'T CLOSE THE CONNETION\n") |
| return c.rawConn.Close() |
| } |
| |
| func (c *conn) LocalAddr() net.Addr { |
| c.mu.Lock() |
| defer c.mu.Unlock() |
| return c.rawConn.LocalAddr() |
| } |
| |
| func (c *conn) RemoteAddr() net.Addr { |
| c.mu.Lock() |
| defer c.mu.Unlock() |
| return c.rawConn.RemoteAddr() |
| } |
| |
| func (c *conn) SetDeadline(t time.Time) error { |
| c.mu.Lock() |
| defer c.mu.Unlock() |
| return c.rawConn.SetDeadline(t) |
| } |
| |
| func (c *conn) SetReadDeadline(t time.Time) error { |
| c.mu.Lock() |
| defer c.mu.Unlock() |
| return c.rawConn.SetReadDeadline(t) |
| } |
| |
| func (c *conn) SetWriteDeadline(t time.Time) error { |
| c.mu.Lock() |
| defer c.mu.Unlock() |
| return c.rawConn.SetWriteDeadline(t) |
| } |
| |
| // TODO: should I just collapse current and advance? |
| func (c *conn) currentNonce() *[24]byte { |
| return &c.nonce |
| } |
| |
| // TODO: re enable. |
| func (c *conn) advanceNonce() { |
| |
| // c.counter++ |
| // binary.LittleEndian.PutUint64(c.nonce[:], c.counter) |
| } |