Revert "Revert "veyron/runtimes/google/ipc/stream/crypto: use nacl/crypto_box""

This reverts commit bcab01884738b1ad598cb744c66ba4a2fb9ca093.

Change-Id: I0a15287993732465f0f514b747209ab850a3cde0
diff --git a/runtimes/google/ipc/stream/crypto/box.go b/runtimes/google/ipc/stream/crypto/box.go
new file mode 100644
index 0000000..3ab2c33
--- /dev/null
+++ b/runtimes/google/ipc/stream/crypto/box.go
@@ -0,0 +1,87 @@
+package crypto
+
+import (
+	"bytes"
+	"code.google.com/p/go.crypto/nacl/box"
+	"crypto/rand"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"net"
+	"veyron/runtimes/google/lib/iobuf"
+)
+
+type boxcrypter struct {
+	conn                  net.Conn
+	alloc                 *iobuf.Allocator
+	sharedKey             [32]byte
+	writeNonce, readNonce uint64
+}
+
+// NewBoxCrypter uses Curve25519, XSalsa20 and Poly1305 to encrypt and
+// authenticate messages (as defined in http://nacl.cr.yp.to/box.html).
+// An ephemeral Diffie-Hellman key exchange is performed per invocation
+// of NewBoxCrypter; the data sent has forward security with connection
+// granularity. One round-trip is required before any data can be sent.
+// BoxCrypter does NOT do anything to verify the identity of the peer.
+func NewBoxCrypter(conn net.Conn, pool *iobuf.Pool) (Crypter, error) {
+	pk, sk, err := box.GenerateKey(rand.Reader)
+	if err != nil {
+		return nil, err
+	}
+	var theirPK [32]byte
+	errChan := make(chan error)
+	defer close(errChan)
+	go func() { _, err := conn.Write(pk[:]); errChan <- err }()
+	go func() { _, err := io.ReadFull(conn, theirPK[:]); errChan <- err }()
+	if err := <-errChan; err != nil {
+		return nil, err
+	}
+	if err := <-errChan; err != nil {
+		return nil, err
+	}
+	ret := &boxcrypter{conn: conn, alloc: iobuf.NewAllocator(pool, 0)}
+	box.Precompute(&ret.sharedKey, &theirPK, sk)
+	// Distinct messages between the same {sender, receiver} set are required
+	// to have distinct nonces. The server with the lexicographically smaller
+	// public key will be sending messages with 0, 2, 4... and the other will
+	// be using 1, 3, 5...
+	if bytes.Compare(pk[:], theirPK[:]) < 0 {
+		ret.writeNonce, ret.readNonce = 0, 1
+	} else {
+		ret.writeNonce, ret.readNonce = 1, 0
+	}
+	return ret, nil
+}
+
+func (c *boxcrypter) Encrypt(src *iobuf.Slice) (*iobuf.Slice, error) {
+	defer src.Release()
+	var nonce [24]byte
+	binary.LittleEndian.PutUint64(nonce[:], c.writeNonce)
+	c.writeNonce += 2
+	ret := c.alloc.Alloc(uint(len(src.Contents) + box.Overhead))
+	ret.Contents = box.SealAfterPrecomputation(ret.Contents[:0], src.Contents, &nonce, &c.sharedKey)
+	return ret, nil
+}
+
+func (c *boxcrypter) Decrypt(src *iobuf.Slice) (*iobuf.Slice, error) {
+	defer src.Release()
+	var nonce [24]byte
+	binary.LittleEndian.PutUint64(nonce[:], c.readNonce)
+	c.readNonce += 2
+	retLen := len(src.Contents) - box.Overhead
+	if retLen < 0 {
+		return nil, fmt.Errorf("ciphertext too short")
+	}
+	ret := c.alloc.Alloc(uint(retLen))
+	var ok bool
+	ret.Contents, ok = box.OpenAfterPrecomputation(ret.Contents[:0], src.Contents, &nonce, &c.sharedKey)
+	if !ok {
+		return nil, fmt.Errorf("message authentication failed")
+	}
+	return ret, nil
+}
+
+func (c *boxcrypter) String() string {
+	return fmt.Sprintf("%#v", *c)
+}
diff --git a/runtimes/google/ipc/stream/crypto/crypto_test.go b/runtimes/google/ipc/stream/crypto/crypto_test.go
index 063d222..4bbdd45 100644
--- a/runtimes/google/ipc/stream/crypto/crypto_test.go
+++ b/runtimes/google/ipc/stream/crypto/crypto_test.go
@@ -37,8 +37,8 @@
 	crypter.String() // Only to test that String does not crash.
 }
 
-func TestTLS(t *testing.T) {
-	c1, c2 := tlsCrypters(t)
+func testSimple(t *testing.T, crypters func(testing.TB) (Crypter, Crypter)) {
+	c1, c2 := crypters(t)
 	// Execute String just to check that it does not crash.
 	c1.String()
 	c2.String()
@@ -63,6 +63,9 @@
 	t.Logf("Byte overhead of encryption: %v", overhead)
 }
 
+func TestTLS(t *testing.T) { testSimple(t, tlsCrypters) }
+func TestBox(t *testing.T) { testSimple(t, boxCrypters) }
+
 func TestTLSNil(t *testing.T) {
 	c1, c2 := tlsCrypters(t)
 	if t.Failed() {
@@ -123,12 +126,27 @@
 	return c1, c2
 }
 
-func benchmarkEncrypt(b *testing.B, size int) {
+func boxCrypters(t testing.TB) (Crypter, Crypter) {
+	serverConn, clientConn := net.Pipe()
+	crypters := make(chan Crypter)
+	for _, conn := range []net.Conn{serverConn, clientConn} {
+		go func(conn net.Conn) {
+			crypter, err := NewBoxCrypter(conn, iobuf.NewPool(0))
+			if err != nil {
+				t.Fatal(err)
+			}
+			crypters <- crypter
+		}(conn)
+	}
+	return <-crypters, <-crypters
+}
+
+func benchmarkEncrypt(b *testing.B, crypters func(testing.TB) (Crypter, Crypter), size int) {
 	plaintext := make([]byte, size)
 	if _, err := rand.Read(plaintext); err != nil {
 		b.Fatal(err)
 	}
-	e, _ := tlsCrypters(b)
+	e, _ := crypters(b)
 	b.SetBytes(int64(size))
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
@@ -140,13 +158,19 @@
 	}
 }
 
-func BenchmarkEncrypt_1B(b *testing.B)  { benchmarkEncrypt(b, 1) }
-func BenchmarkEncrypt_1K(b *testing.B)  { benchmarkEncrypt(b, 1<<10) }
-func BenchmarkEncrypt_10K(b *testing.B) { benchmarkEncrypt(b, 10<<10) }
-func BenchmarkEncrypt_1M(b *testing.B)  { benchmarkEncrypt(b, 1<<20) }
-func BenchmarkEncrypt_5M(b *testing.B)  { benchmarkEncrypt(b, 5<<20) }
+func BenchmarkTLSEncrypt_1B(b *testing.B)  { benchmarkEncrypt(b, tlsCrypters, 1) }
+func BenchmarkTLSEncrypt_1K(b *testing.B)  { benchmarkEncrypt(b, tlsCrypters, 1<<10) }
+func BenchmarkTLSEncrypt_10K(b *testing.B) { benchmarkEncrypt(b, tlsCrypters, 10<<10) }
+func BenchmarkTLSEncrypt_1M(b *testing.B)  { benchmarkEncrypt(b, tlsCrypters, 1<<20) }
+func BenchmarkTLSEncrypt_5M(b *testing.B)  { benchmarkEncrypt(b, tlsCrypters, 5<<20) }
 
-func benchmarkRoundTrip(b *testing.B, size int) {
+func BenchmarkBoxEncrypt_1B(b *testing.B)  { benchmarkEncrypt(b, boxCrypters, 1) }
+func BenchmarkBoxEncrypt_1K(b *testing.B)  { benchmarkEncrypt(b, boxCrypters, 1<<10) }
+func BenchmarkBoxEncrypt_10K(b *testing.B) { benchmarkEncrypt(b, boxCrypters, 10<<10) }
+func BenchmarkBoxEncrypt_1M(b *testing.B)  { benchmarkEncrypt(b, boxCrypters, 1<<20) }
+func BenchmarkBoxEncrypt_5M(b *testing.B)  { benchmarkEncrypt(b, boxCrypters, 5<<20) }
+
+func benchmarkRoundTrip(b *testing.B, crypters func(testing.TB) (Crypter, Crypter), size int) {
 	plaintext := make([]byte, size)
 	if _, err := rand.Read(plaintext); err != nil {
 		b.Fatal(err)
@@ -166,8 +190,14 @@
 		plainslice.Release()
 	}
 }
-func BenchmarkRoundTrip_1B(b *testing.B)  { benchmarkRoundTrip(b, 1) }
-func BenchmarkRoundTrip_1K(b *testing.B)  { benchmarkRoundTrip(b, 1<<10) }
-func BenchmarkRoundTrip_10K(b *testing.B) { benchmarkRoundTrip(b, 10<<10) }
-func BenchmarkRoundTrip_1M(b *testing.B)  { benchmarkRoundTrip(b, 1<<20) }
-func BenchmarkRoundTrip_5M(b *testing.B)  { benchmarkRoundTrip(b, 5<<20) }
+func BenchmarkTLSRoundTrip_1B(b *testing.B)  { benchmarkRoundTrip(b, tlsCrypters, 1) }
+func BenchmarkTLSRoundTrip_1K(b *testing.B)  { benchmarkRoundTrip(b, tlsCrypters, 1<<10) }
+func BenchmarkTLSRoundTrip_10K(b *testing.B) { benchmarkRoundTrip(b, tlsCrypters, 10<<10) }
+func BenchmarkTLSRoundTrip_1M(b *testing.B)  { benchmarkRoundTrip(b, tlsCrypters, 1<<20) }
+func BenchmarkTLSRoundTrip_5M(b *testing.B)  { benchmarkRoundTrip(b, tlsCrypters, 5<<20) }
+
+func BenchmarkBoxRoundTrip_1B(b *testing.B)  { benchmarkRoundTrip(b, boxCrypters, 1) }
+func BenchmarkBoxRoundTrip_1K(b *testing.B)  { benchmarkRoundTrip(b, boxCrypters, 1<<10) }
+func BenchmarkBoxRoundTrip_10K(b *testing.B) { benchmarkRoundTrip(b, boxCrypters, 10<<10) }
+func BenchmarkBoxRoundTrip_1M(b *testing.B)  { benchmarkRoundTrip(b, boxCrypters, 1<<20) }
+func BenchmarkBoxRoundTrip_5M(b *testing.B)  { benchmarkRoundTrip(b, boxCrypters, 5<<20) }