Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions threefish.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package threefish
import (
"encoding/binary"
"fmt"
"unsafe"
)

const (
Expand Down Expand Up @@ -64,3 +65,29 @@ func calculateTweak(dst *[(tweakSize / 8) + 1]uint64, src []byte) error {

return nil
}

// anyOverlap reports whether x and y share memory at any (not necessarily
// corresponding) index. The memory beyond the slice length is ignored.
//
// This is a copy of crypto/internal/fips140/alias.AnyOverlap, which is not
// importable from outside the standard library. It also exists as
// golang.org/x/crypto/internal/alias.AnyOverlap.
func anyOverlap(x, y []byte) bool {
return len(x) > 0 && len(y) > 0 &&
uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
}

// inexactOverlap reports whether x and y share memory at any non-corresponding
// index. The memory beyond the slice length is ignored. Note that x and y can
// have different lengths and still not have any inexact overlap.
//
// inexactOverlap can be used to implement the requirements of the
// crypto/cipher Block interface. It is a copy of
// crypto/internal/fips140/alias.InexactOverlap.
func inexactOverlap(x, y []byte) bool {
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
return false
}
return anyOverlap(x, y)
}
20 changes: 20 additions & 0 deletions threefish1024.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ func (c *cipher1024) BlockSize() int { return blockSize1024 }

// Encrypt loads plaintext from src, encrypts it, and stores it in dst.
func (c *cipher1024) Encrypt(dst, src []byte) {
if len(src) < blockSize1024 {
panic("threefish: input not full block")
}
if len(dst) < blockSize1024 {
panic("threefish: output not full block")
}
if inexactOverlap(dst[:blockSize1024], src[:blockSize1024]) {
panic("threefish: invalid buffer overlap")
}

// Load the input
in := new([numWords1024]uint64)
in[0] = loadWord(src[0:8])
Expand Down Expand Up @@ -317,6 +327,16 @@ func (c *cipher1024) Encrypt(dst, src []byte) {

// Decrypt loads ciphertext from src, decrypts it, and stores it in dst.
func (c *cipher1024) Decrypt(dst, src []byte) {
if len(src) < blockSize1024 {
panic("threefish: input not full block")
}
if len(dst) < blockSize1024 {
panic("threefish: output not full block")
}
if inexactOverlap(dst[:blockSize1024], src[:blockSize1024]) {
panic("threefish: invalid buffer overlap")
}

// Load the ciphertext
ct := new([numWords1024]uint64)
ct[0] = loadWord(src[0:8])
Expand Down
65 changes: 65 additions & 0 deletions threefish1024_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,71 @@ func TestThreefish1024(t *testing.T) {
)
}

func TestThreefish1024Panics(t *testing.T) {
key := make([]byte, blockSize1024)
tweak := make([]byte, tweakSize)

block, err := New1024(key, tweak)
if err != nil {
t.Fatalf("failed to create cipher with error: %s", err)
}

full := make([]byte, blockSize1024)
short := make([]byte, blockSize1024-1)

cases := []struct {
name string
fn func()
}{
{"encrypt short src", func() { block.Encrypt(full, short) }},
{"encrypt short dst", func() { block.Encrypt(short, full) }},
{"decrypt short src", func() { block.Decrypt(full, short) }},
{"decrypt short dst", func() { block.Decrypt(short, full) }},
{
"encrypt inexact overlap",
func() {
buf := make([]byte, blockSize1024+1)
block.Encrypt(buf[0:blockSize1024], buf[1:blockSize1024+1])
},
},
{
"decrypt inexact overlap",
func() {
buf := make([]byte, blockSize1024+1)
block.Decrypt(buf[0:blockSize1024], buf[1:blockSize1024+1])
},
},
}
for _, c := range cases {
t.Run(
c.name,
func(t *testing.T) {
defer func() {
if recover() == nil {
t.Fatal("expected a panic but none occurred")
}
}()
c.fn()
},
)
}

// Exact overlap (in-place operation) must remain allowed.
t.Run(
"in-place is allowed",
func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Fatalf("in-place operation should not panic, got: %v", r)
}
}()
buf := make([]byte, blockSize1024)
block.Encrypt(buf, buf)
block.Decrypt(buf, buf)
},
)
}

func BenchmarkThreefish1024(b *testing.B) {
key := make([]byte, blockSize1024)
tweak := make([]byte, tweakSize)
Expand Down
20 changes: 20 additions & 0 deletions threefish256.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ func (c *cipher256) BlockSize() int { return blockSize256 }

// Encrypt loads plaintext from src, encrypts it, and stores it in dst.
func (c *cipher256) Encrypt(dst, src []byte) {
if len(src) < blockSize256 {
panic("threefish: input not full block")
}
if len(dst) < blockSize256 {
panic("threefish: output not full block")
}
if inexactOverlap(dst[:blockSize256], src[:blockSize256]) {
panic("threefish: invalid buffer overlap")
}

// Load the input
in := new([numWords256]uint64)
in[0] = loadWord(src[0:8])
Expand Down Expand Up @@ -153,6 +163,16 @@ func (c *cipher256) Encrypt(dst, src []byte) {

// Decrypt loads ciphertext from src, decrypts it, and stores it in dst.
func (c *cipher256) Decrypt(dst, src []byte) {
if len(src) < blockSize256 {
panic("threefish: input not full block")
}
if len(dst) < blockSize256 {
panic("threefish: output not full block")
}
if inexactOverlap(dst[:blockSize256], src[:blockSize256]) {
panic("threefish: invalid buffer overlap")
}

// Load the ciphertext
ct := new([numWords256]uint64)
ct[0] = loadWord(src[0:8])
Expand Down
65 changes: 65 additions & 0 deletions threefish256_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,71 @@ func TestThreefish256(t *testing.T) {
)
}

func TestThreefish256Panics(t *testing.T) {
key := make([]byte, blockSize256)
tweak := make([]byte, tweakSize)

block, err := New256(key, tweak)
if err != nil {
t.Fatalf("failed to create cipher with error: %s", err)
}

full := make([]byte, blockSize256)
short := make([]byte, blockSize256-1)

cases := []struct {
name string
fn func()
}{
{"encrypt short src", func() { block.Encrypt(full, short) }},
{"encrypt short dst", func() { block.Encrypt(short, full) }},
{"decrypt short src", func() { block.Decrypt(full, short) }},
{"decrypt short dst", func() { block.Decrypt(short, full) }},
{
"encrypt inexact overlap",
func() {
buf := make([]byte, blockSize256+1)
block.Encrypt(buf[0:blockSize256], buf[1:blockSize256+1])
},
},
{
"decrypt inexact overlap",
func() {
buf := make([]byte, blockSize256+1)
block.Decrypt(buf[0:blockSize256], buf[1:blockSize256+1])
},
},
}
for _, c := range cases {
t.Run(
c.name,
func(t *testing.T) {
defer func() {
if recover() == nil {
t.Fatal("expected a panic but none occurred")
}
}()
c.fn()
},
)
}

// Exact overlap (in-place operation) must remain allowed.
t.Run(
"in-place is allowed",
func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Fatalf("in-place operation should not panic, got: %v", r)
}
}()
buf := make([]byte, blockSize256)
block.Encrypt(buf, buf)
block.Decrypt(buf, buf)
},
)
}

func BenchmarkThreefish256(b *testing.B) {
key := make([]byte, blockSize256)
tweak := make([]byte, tweakSize)
Expand Down
20 changes: 20 additions & 0 deletions threefish512.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ func (c *cipher512) BlockSize() int { return blockSize512 }

// Encrypt loads plaintext from src, encrypts it, and stores it in dst.
func (c *cipher512) Encrypt(dst, src []byte) {
if len(src) < blockSize512 {
panic("threefish: input not full block")
}
if len(dst) < blockSize512 {
panic("threefish: output not full block")
}
if inexactOverlap(dst[:blockSize512], src[:blockSize512]) {
panic("threefish: invalid buffer overlap")
}

// Load the input
in := new([numWords512]uint64)
in[0] = loadWord(src[0:8])
Expand Down Expand Up @@ -205,6 +215,16 @@ func (c *cipher512) Encrypt(dst, src []byte) {

// Decrypt loads ciphertext from src, decrypts it, and stores it in dst.
func (c *cipher512) Decrypt(dst, src []byte) {
if len(src) < blockSize512 {
panic("threefish: input not full block")
}
if len(dst) < blockSize512 {
panic("threefish: output not full block")
}
if inexactOverlap(dst[:blockSize512], src[:blockSize512]) {
panic("threefish: invalid buffer overlap")
}

// Load the ciphertext
ct := new([numWords512]uint64)
ct[0] = loadWord(src[0:8])
Expand Down
65 changes: 65 additions & 0 deletions threefish512_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,71 @@ func TestThreefish512(t *testing.T) {
)
}

func TestThreefish512Panics(t *testing.T) {
key := make([]byte, blockSize512)
tweak := make([]byte, tweakSize)

block, err := New512(key, tweak)
if err != nil {
t.Fatalf("failed to create cipher with error: %s", err)
}

full := make([]byte, blockSize512)
short := make([]byte, blockSize512-1)

cases := []struct {
name string
fn func()
}{
{"encrypt short src", func() { block.Encrypt(full, short) }},
{"encrypt short dst", func() { block.Encrypt(short, full) }},
{"decrypt short src", func() { block.Decrypt(full, short) }},
{"decrypt short dst", func() { block.Decrypt(short, full) }},
{
"encrypt inexact overlap",
func() {
buf := make([]byte, blockSize512+1)
block.Encrypt(buf[0:blockSize512], buf[1:blockSize512+1])
},
},
{
"decrypt inexact overlap",
func() {
buf := make([]byte, blockSize512+1)
block.Decrypt(buf[0:blockSize512], buf[1:blockSize512+1])
},
},
}
for _, c := range cases {
t.Run(
c.name,
func(t *testing.T) {
defer func() {
if recover() == nil {
t.Fatal("expected a panic but none occurred")
}
}()
c.fn()
},
)
}

// Exact overlap (in-place operation) must remain allowed.
t.Run(
"in-place is allowed",
func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Fatalf("in-place operation should not panic, got: %v", r)
}
}()
buf := make([]byte, blockSize512)
block.Encrypt(buf, buf)
block.Decrypt(buf, buf)
},
)
}

func BenchmarkThreefish512(b *testing.B) {
key := make([]byte, blockSize512)
tweak := make([]byte, tweakSize)
Expand Down
Loading