Browse Source

go.crypto/nacl/secretbox: fix append behaviour.

secretbox is supposed to append to the given slice, like hash.Sum() and
append(). However, I had a complete brain-fart: I've really no idea what
I was thinking of at the time.

R=golang-dev, sfrithjof, rsc
CC=agl, golang-dev
https://golang.org/cl/10099043
Adam Langley 12 years ago
parent
commit
c2ba5865a8
2 changed files with 37 additions and 25 deletions
  1. 19 25
      nacl/secretbox/secretbox.go
  2. 18 0
      nacl/secretbox/secretbox_test.go

+ 19 - 25
nacl/secretbox/secretbox.go

@@ -37,6 +37,21 @@ func setup(subKey *[32]byte, counter *[16]byte, nonce *[24]byte, key *[32]byte)
 	copy(counter[:], nonce[16:])
 }
 
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+	if total := len(in) + n; cap(in) >= total {
+		head = in[:total]
+	} else {
+		head = make([]byte, total)
+		copy(head, in)
+	}
+	tail = head[len(in):]
+	return
+}
+
 // Seal appends an encrypted and authenticated copy of message to out, which
 // must not overlap message. The key and nonce pair must be unique for each
 // distinct message and the output will be Overhead bytes longer than message.
@@ -54,17 +69,7 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
 	var poly1305Key [32]byte
 	copy(poly1305Key[:], firstBlock[:])
 
-	out = out[len(out):]
-	outLen := len(message) + poly1305.TagSize
-	if cap(out) >= outLen {
-		out = out[:outLen]
-	} else if out == nil {
-		out = make([]byte, outLen)
-	} else {
-		for i := 0; i < outLen; i++ {
-			out = append(out, 0)
-		}
-	}
+	ret, out := sliceForAppend(out, len(message)+poly1305.TagSize)
 
 	// We XOR up to 32 bytes of message with the keystream generated from
 	// the first block.
@@ -90,7 +95,7 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
 	poly1305.Sum(&tag, ciphertext, &poly1305Key)
 	copy(tagOut, tag[:])
 
-	return tagOut
+	return ret
 }
 
 // Open authenticates and decrypts a box produced by Seal and appends the
@@ -120,17 +125,7 @@ func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool)
 		return nil, false
 	}
 
-	out = out[len(out):]
-	outLen := len(box) - Overhead
-	if cap(out) >= outLen {
-		out = out[:outLen]
-	} else if out == nil {
-		out = make([]byte, outLen)
-	} else {
-		for i := 0; i < outLen; i++ {
-			out = append(out, 0)
-		}
-	}
+	ret, out := sliceForAppend(out, len(box)-Overhead)
 
 	// We XOR up to 32 bytes of box with the keystream generated from
 	// the first block.
@@ -144,12 +139,11 @@ func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool)
 	}
 
 	box = box[len(firstMessageBlock):]
-	plaintext := out
 	out = out[len(firstMessageBlock):]
 
 	// Now decrypt the rest.
 	counter[8] = 1
 	salsa.XORKeyStream(out, box, &counter, &subKey)
 
-	return plaintext, true
+	return ret, true
 }

+ 18 - 0
nacl/secretbox/secretbox_test.go

@@ -71,3 +71,21 @@ func TestSecretBox(t *testing.T) {
 		t.Fatalf("box didn't match, got\n%x\n, expected\n%x", box, expected)
 	}
 }
+
+func TestAppend(t *testing.T) {
+	var key [32]byte
+	var nonce [24]byte
+	var message [8]byte
+
+	out := make([]byte, 4)
+	box := Seal(out, message[:], &nonce, &key)
+	if !bytes.Equal(box[:4], out[:4]) {
+		t.Fatalf("Seal didn't correctly append")
+	}
+
+	out = make([]byte, 4, 100)
+	box = Seal(out, message[:], &nonce, &key)
+	if !bytes.Equal(box[:4], out[:4]) {
+		t.Fatalf("Seal didn't correctly append with sufficient capacity.")
+	}
+}