From c2ba5865a83564a5fa4620622d80f37ae8bb8338 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Mon, 10 Jun 2013 18:03:26 -0400 Subject: [PATCH] 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 --- nacl/secretbox/secretbox.go | 44 ++++++++++++++------------------ nacl/secretbox/secretbox_test.go | 18 +++++++++++++ 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/nacl/secretbox/secretbox.go b/nacl/secretbox/secretbox.go index 699f020..ad64c24 100644 --- a/nacl/secretbox/secretbox.go +++ b/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 } diff --git a/nacl/secretbox/secretbox_test.go b/nacl/secretbox/secretbox_test.go index d7a3e7d..664dc15 100644 --- a/nacl/secretbox/secretbox_test.go +++ b/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.") + } +}