From 9b4c299488b450acd4a8dc60d4089621c695daa4 Mon Sep 17 00:00:00 2001 From: Silke Date: Wed, 22 Mar 2017 17:21:54 +0100 Subject: [PATCH 1/6] More/rename crypto stream functions and add tests - Rename all functions - Add tests for all functions - Change return types (removed exit status) - Rename Keygen to KeyGen - Fix issues with zero-length data --- .../stream/chacha20/crypto_stream_chacha20.go | 76 +++++++++++++++++++ .../chacha20/crypto_stream_chacha20_test.go | 54 +++++++++++++ crypto/stream/crypto_stream.go | 62 +++++++++++++++ crypto/stream/crypto_stream_test.go | 52 +++++++++++++ .../stream/salsa20/crypto_stream_salsa20.go | 76 +++++++++++++++++++ .../salsa20/crypto_stream_salsa20_test.go | 54 +++++++++++++ .../salsa2012/crypto_stream_salsa2012.go | 57 ++++++++++++++ .../salsa2012/crypto_stream_salsa2012_test.go | 47 ++++++++++++ .../stream/salsa208/crypto_stream_salsa208.go | 57 ++++++++++++++ .../salsa208/crypto_stream_salsa208_test.go | 47 ++++++++++++ .../xchacha20/crypto_stream_xchacha20.go | 76 +++++++++++++++++++ .../xchacha20/crypto_stream_xchacha20_test.go | 54 +++++++++++++ .../stream/xsalsa20/crypto_stream_xsalsa20.go | 76 +++++++++++++++++++ .../xsalsa20/crypto_stream_xsalsa20_test.go | 54 +++++++++++++ 14 files changed, 842 insertions(+) create mode 100644 crypto/stream/chacha20/crypto_stream_chacha20.go create mode 100644 crypto/stream/chacha20/crypto_stream_chacha20_test.go create mode 100644 crypto/stream/crypto_stream.go create mode 100644 crypto/stream/crypto_stream_test.go create mode 100644 crypto/stream/salsa20/crypto_stream_salsa20.go create mode 100644 crypto/stream/salsa20/crypto_stream_salsa20_test.go create mode 100644 crypto/stream/salsa2012/crypto_stream_salsa2012.go create mode 100644 crypto/stream/salsa2012/crypto_stream_salsa2012_test.go create mode 100644 crypto/stream/salsa208/crypto_stream_salsa208.go create mode 100644 crypto/stream/salsa208/crypto_stream_salsa208_test.go create mode 100644 crypto/stream/xchacha20/crypto_stream_xchacha20.go create mode 100644 crypto/stream/xchacha20/crypto_stream_xchacha20_test.go create mode 100644 crypto/stream/xsalsa20/crypto_stream_xsalsa20.go create mode 100644 crypto/stream/xsalsa20/crypto_stream_xsalsa20_test.go diff --git a/crypto/stream/chacha20/crypto_stream_chacha20.go b/crypto/stream/chacha20/crypto_stream_chacha20.go new file mode 100644 index 0000000..e8c387f --- /dev/null +++ b/crypto/stream/chacha20/crypto_stream_chacha20.go @@ -0,0 +1,76 @@ +package chacha20 + +// #cgo pkg-config: libsodium +// #include +// #include +import "C" +import "github.com/GoKillers/libsodium-go/support" + +// KeyBytes returns the required length of a secret key +func KeyBytes() int { + return int(C.crypto_stream_chacha20_keybytes()) +} + +// NonceBytes returns the required length of a nonce +func NonceBytes() int { + return int(C.crypto_stream_chacha20_noncebytes()) +} + +// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. +func Random(clen int, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, clen) + + C.crypto_stream_chacha20( + (*C.uchar)(support.BytePointer(c)), + (C.ulonglong)(clen), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. +func XOR(m []byte, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_chacha20_xor( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XORIC encrypts a message `m` using a nonce `n` and a secret key `k`, +// but with a block counter starting at `ic`. +func XORIC(m []byte, n []byte, ic uint64, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_chacha20_xor_ic( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (C.uint64_t)(ic), + (*C.uchar)(&k[0])) + + return c +} + +// KeyGen generates a secret key +func KeyGen() []byte { + k := make([]byte, KeyBytes()) + C.crypto_stream_chacha20_keygen((*C.uchar)(&k[0])) + return k +} diff --git a/crypto/stream/chacha20/crypto_stream_chacha20_test.go b/crypto/stream/chacha20/crypto_stream_chacha20_test.go new file mode 100644 index 0000000..a0eb291 --- /dev/null +++ b/crypto/stream/chacha20/crypto_stream_chacha20_test.go @@ -0,0 +1,54 @@ +package chacha20 + +import ( + "testing" + "bytes" + "github.com/google/gofuzz" +) + +var TestCount = 100000 + +func Test(t *testing.T) { + // Test the key generation + if len(KeyGen()) != KeyBytes() { + t.Error("Generated key has the wrong length") + } + + // Fuzzing + f := fuzz.New() + + // Run tests + for i := 0; i < TestCount; i++ { + var c, m, r, d []byte + var n [8]byte + + // Generate random data + f.Fuzz(&m) + f.Fuzz(&n) + k := KeyGen() + + // Generate pseudo-random data + r = Random(len(m), n[:], k) + + // Perform XOR + d = make([]byte, len(m)) + for i := range r { + d[i] = r[i] ^ m[i] + } + + // Generate a ciphertext + c = XOR(m, n[:], k) + if !bytes.Equal(c, d) { + t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Generate another ciphertext + c = XORIC(m, n[:], 0, k) + if !bytes.Equal(c, d) { + t.Errorf("XORIC failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + } +} + diff --git a/crypto/stream/crypto_stream.go b/crypto/stream/crypto_stream.go new file mode 100644 index 0000000..48b0ed8 --- /dev/null +++ b/crypto/stream/crypto_stream.go @@ -0,0 +1,62 @@ +package stream + +// #cgo pkg-config: libsodium +// #include +// #include +import "C" +import "github.com/GoKillers/libsodium-go/support" + +// KeyBytes returns the required length of a secret key +func KeyBytes() int { + return int(C.crypto_stream_keybytes()) +} + +// NonceBytes returns the required length of a nonce +func NonceBytes() int { + return int(C.crypto_stream_noncebytes()) +} + +// Primitive returns the name of the used algorithm +func Primitive() string { + return C.GoString(C.crypto_stream_primitive()) +} + +// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. +func Random(clen int, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, clen) + + C.crypto_stream( + (*C.uchar)(support.BytePointer(c)), + (C.ulonglong)(clen), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. +func XOR(m []byte, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_xor( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// KeyGen generates a secret key +func KeyGen() []byte { + c := make([]byte, KeyBytes()) + C.crypto_stream_keygen((*C.uchar)(&c[0])) + return c +} diff --git a/crypto/stream/crypto_stream_test.go b/crypto/stream/crypto_stream_test.go new file mode 100644 index 0000000..5f2db81 --- /dev/null +++ b/crypto/stream/crypto_stream_test.go @@ -0,0 +1,52 @@ +package stream + +import ( + "testing" + "bytes" + "github.com/google/gofuzz" +) + +var TestCount = 100000 + +func Test(t *testing.T) { + // Check the primitive + if Primitive() != "xsalsa20" { + t.Error("Incorrect primitive: %x", Primitive()) + } + + // Test the key generation + if len(KeyGen()) != KeyBytes() { + t.Error("Generated key has the wrong length") + } + + // Fuzzing + f := fuzz.New() + + // Run tests + for i := 0; i < TestCount; i++ { + var c, m, r, d []byte + var n [24]byte + + // Generate random data + f.Fuzz(&m) + f.Fuzz(&n) + k := KeyGen() + + // Generate pseudo-random data + r = Random(len(m), n[:], k) + + // Perform XOR + d = make([]byte, len(m)) + for i := range r { + d[i] = r[i] ^ m[i] + } + + // Generate a ciphertext + c = XOR(m, n[:], k) + if !bytes.Equal(c, d) { + t.Errorf("Encryption failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + } +} + diff --git a/crypto/stream/salsa20/crypto_stream_salsa20.go b/crypto/stream/salsa20/crypto_stream_salsa20.go new file mode 100644 index 0000000..20a670b --- /dev/null +++ b/crypto/stream/salsa20/crypto_stream_salsa20.go @@ -0,0 +1,76 @@ +package salsa20 + +// #cgo pkg-config: libsodium +// #include +// #include +import "C" +import "github.com/GoKillers/libsodium-go/support" + +// KeyBytes returns the required length of a secret key +func KeyBytes() int { + return int(C.crypto_stream_salsa20_keybytes()) +} + +// NonceBytes returns the required length of a nonce +func NonceBytes() int { + return int(C.crypto_stream_salsa20_noncebytes()) +} + +// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. +func Random(clen int, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, clen) + + C.crypto_stream_salsa20( + (*C.uchar)(support.BytePointer(c)), + (C.ulonglong)(clen), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. +func XOR(m []byte, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_salsa20_xor( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XORIC encrypts a message `m` using a nonce `n` and a secret key `k`, +// but with a block counter starting at `ic`. +func XORIC(m []byte, n []byte, ic uint64, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_salsa20_xor_ic( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (C.uint64_t)(ic), + (*C.uchar)(&k[0])) + + return c +} + +// KeyGen generates a secret key +func KeyGen() []byte { + k := make([]byte, KeyBytes()) + C.crypto_stream_salsa20_keygen((*C.uchar)(&k[0])) + return k +} diff --git a/crypto/stream/salsa20/crypto_stream_salsa20_test.go b/crypto/stream/salsa20/crypto_stream_salsa20_test.go new file mode 100644 index 0000000..3983fc7 --- /dev/null +++ b/crypto/stream/salsa20/crypto_stream_salsa20_test.go @@ -0,0 +1,54 @@ +package salsa20 + +import ( + "testing" + "bytes" + "github.com/google/gofuzz" +) + +var TestCount = 100000 + +func Test(t *testing.T) { + // Test the key generation + if len(KeyGen()) != KeyBytes() { + t.Error("Generated key has the wrong length") + } + + // Fuzzing + f := fuzz.New() + + // Run tests + for i := 0; i < TestCount; i++ { + var c, m, r, d []byte + var n [8]byte + + // Generate random data + f.Fuzz(&m) + f.Fuzz(&n) + k := KeyGen() + + // Generate pseudo-random data + r = Random(len(m), n[:], k) + + // Perform XOR + d = make([]byte, len(m)) + for i := range r { + d[i] = r[i] ^ m[i] + } + + // Generate a ciphertext + c = XOR(m, n[:], k) + if !bytes.Equal(c, d) { + t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Generate another ciphertext + c = XORIC(m, n[:], 0, k) + if !bytes.Equal(c, d) { + t.Errorf("XORIC failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + } +} + diff --git a/crypto/stream/salsa2012/crypto_stream_salsa2012.go b/crypto/stream/salsa2012/crypto_stream_salsa2012.go new file mode 100644 index 0000000..9b5d0bb --- /dev/null +++ b/crypto/stream/salsa2012/crypto_stream_salsa2012.go @@ -0,0 +1,57 @@ +package salsa2012 + +// #cgo pkg-config: libsodium +// #include +// #include +import "C" +import "github.com/GoKillers/libsodium-go/support" + +// KeyBytes returns the required length of a secret key +func KeyBytes() int { + return int(C.crypto_stream_salsa2012_keybytes()) +} + +// NonceBytes returns the required length of a nonce +func NonceBytes() int { + return int(C.crypto_stream_salsa2012_noncebytes()) +} + +// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. +func Random(clen int, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, clen) + + C.crypto_stream_salsa2012( + (*C.uchar)(support.BytePointer(c)), + (C.ulonglong)(clen), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. +func XOR(m []byte, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_salsa2012_xor( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// KeyGen generates a secret key +func KeyGen() []byte { + k := make([]byte, KeyBytes()) + C.crypto_stream_salsa2012_keygen((*C.uchar)(&k[0])) + return k +} diff --git a/crypto/stream/salsa2012/crypto_stream_salsa2012_test.go b/crypto/stream/salsa2012/crypto_stream_salsa2012_test.go new file mode 100644 index 0000000..7eb075f --- /dev/null +++ b/crypto/stream/salsa2012/crypto_stream_salsa2012_test.go @@ -0,0 +1,47 @@ +package salsa2012 + +import ( + "testing" + "bytes" + "github.com/google/gofuzz" +) + +var TestCount = 100000 + +func Test(t *testing.T) { + // Test the key generation + if len(KeyGen()) != KeyBytes() { + t.Error("Generated key has the wrong length") + } + + // Fuzzing + f := fuzz.New() + + // Run tests + for i := 0; i < TestCount; i++ { + var c, m, r, d []byte + var n [8]byte + + // Generate random data + f.Fuzz(&m) + f.Fuzz(&n) + k := KeyGen() + + // Generate pseudo-random data + r = Random(len(m), n[:], k) + + // Perform XOR + d = make([]byte, len(m)) + for i := range r { + d[i] = r[i] ^ m[i] + } + + // Generate a ciphertext + c = XOR(m, n[:], k) + if !bytes.Equal(c, d) { + t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + } +} + diff --git a/crypto/stream/salsa208/crypto_stream_salsa208.go b/crypto/stream/salsa208/crypto_stream_salsa208.go new file mode 100644 index 0000000..3623933 --- /dev/null +++ b/crypto/stream/salsa208/crypto_stream_salsa208.go @@ -0,0 +1,57 @@ +package salsa208 + +// #cgo pkg-config: libsodium +// #include +// #include +import "C" +import "github.com/GoKillers/libsodium-go/support" + +// KeyBytes returns the required length of a secret key +func KeyBytes() int { + return int(C.crypto_stream_salsa208_keybytes()) +} + +// NonceBytes returns the required length of a nonce +func NonceBytes() int { + return int(C.crypto_stream_salsa208_noncebytes()) +} + +// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. +func Random(clen int, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, clen) + + C.crypto_stream_salsa208( + (*C.uchar)(support.BytePointer(c)), + (C.ulonglong)(clen), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. +func XOR(m []byte, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_salsa208_xor( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// KeyGen generates a secret key +func KeyGen() []byte { + k := make([]byte, KeyBytes()) + C.crypto_stream_salsa208_keygen((*C.uchar)(&k[0])) + return k +} diff --git a/crypto/stream/salsa208/crypto_stream_salsa208_test.go b/crypto/stream/salsa208/crypto_stream_salsa208_test.go new file mode 100644 index 0000000..a5409bb --- /dev/null +++ b/crypto/stream/salsa208/crypto_stream_salsa208_test.go @@ -0,0 +1,47 @@ +package salsa208 + +import ( + "testing" + "bytes" + "github.com/google/gofuzz" +) + +var TestCount = 100000 + +func Test(t *testing.T) { + // Test the key generation + if len(KeyGen()) != KeyBytes() { + t.Error("Generated key has the wrong length") + } + + // Fuzzing + f := fuzz.New() + + // Run tests + for i := 0; i < TestCount; i++ { + var c, m, r, d []byte + var n [8]byte + + // Generate random data + f.Fuzz(&m) + f.Fuzz(&n) + k := KeyGen() + + // Generate pseudo-random data + r = Random(len(m), n[:], k) + + // Perform XOR + d = make([]byte, len(m)) + for i := range r { + d[i] = r[i] ^ m[i] + } + + // Generate a ciphertext + c = XOR(m, n[:], k) + if !bytes.Equal(c, d) { + t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + } +} + diff --git a/crypto/stream/xchacha20/crypto_stream_xchacha20.go b/crypto/stream/xchacha20/crypto_stream_xchacha20.go new file mode 100644 index 0000000..99d6919 --- /dev/null +++ b/crypto/stream/xchacha20/crypto_stream_xchacha20.go @@ -0,0 +1,76 @@ +package xchacha20 + +// #cgo pkg-config: libsodium +// #include +// #include +import "C" +import "github.com/GoKillers/libsodium-go/support" + +// KeyBytes returns the required length of a secret key +func KeyBytes() int { + return int(C.crypto_stream_xchacha20_keybytes()) +} + +// NonceBytes returns the required length of a nonce +func NonceBytes() int { + return int(C.crypto_stream_xchacha20_noncebytes()) +} + +// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. +func Random(clen int, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, clen) + + C.crypto_stream_xchacha20( + (*C.uchar)(support.BytePointer(c)), + (C.ulonglong)(clen), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. +func XOR(m []byte, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_xchacha20_xor( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XORIC encrypts a message `m` using a nonce `n` and a secret key `k`, +// but with a block counter starting at `ic`. +func XORIC(m []byte, n []byte, ic uint64, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_xchacha20_xor_ic( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (C.uint64_t)(ic), + (*C.uchar)(&k[0])) + + return c +} + +// KeyGen generates a secret key +func KeyGen() []byte { + k := make([]byte, KeyBytes()) + C.crypto_stream_xchacha20_keygen((*C.uchar)(&k[0])) + return k +} diff --git a/crypto/stream/xchacha20/crypto_stream_xchacha20_test.go b/crypto/stream/xchacha20/crypto_stream_xchacha20_test.go new file mode 100644 index 0000000..86681b3 --- /dev/null +++ b/crypto/stream/xchacha20/crypto_stream_xchacha20_test.go @@ -0,0 +1,54 @@ +package xchacha20 + +import ( + "testing" + "bytes" + "github.com/google/gofuzz" +) + +var TestCount = 100000 + +func Test(t *testing.T) { + // Test the key generation + if len(KeyGen()) != KeyBytes() { + t.Error("Generated key has the wrong length") + } + + // Fuzzing + f := fuzz.New() + + // Run tests + for i := 0; i < TestCount; i++ { + var c, m, r, d []byte + var n [24]byte + + // Generate random data + f.Fuzz(&m) + f.Fuzz(&n) + k := KeyGen() + + // Generate pseudo-random data + r = Random(len(m), n[:], k) + + // Perform XOR + d = make([]byte, len(m)) + for i := range r { + d[i] = r[i] ^ m[i] + } + + // Generate a ciphertext + c = XOR(m, n[:], k) + if !bytes.Equal(c, d) { + t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Generate another ciphertext + c = XORIC(m, n[:], 0, k) + if !bytes.Equal(c, d) { + t.Errorf("XORIC failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + } +} + diff --git a/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go b/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go new file mode 100644 index 0000000..928fbfd --- /dev/null +++ b/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go @@ -0,0 +1,76 @@ +package xsalsa20 + +// #cgo pkg-config: libsodium +// #include +// #include +import "C" +import "github.com/GoKillers/libsodium-go/support" + +// KeyBytes returns the required length of a secret key +func KeyBytes() int { + return int(C.crypto_stream_xsalsa20_keybytes()) +} + +// NonceBytes returns the required length of a nonce +func NonceBytes() int { + return int(C.crypto_stream_xsalsa20_noncebytes()) +} + +// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. +func Random(clen int, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, clen) + + C.crypto_stream_xsalsa20( + (*C.uchar)(support.BytePointer(c)), + (C.ulonglong)(clen), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. +func XOR(m []byte, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_xsalsa20_xor( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XORIC encrypts a message `m` using a nonce `n` and a secret key `k`, +// but with a block counter starting at `ic`. +func XORIC(m []byte, n []byte, ic uint64, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_xsalsa20_xor_ic( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (C.uint64_t)(ic), + (*C.uchar)(&k[0])) + + return c +} + +// KeyGen generates a secret key +func KeyGen() []byte { + k := make([]byte, KeyBytes()) + C.crypto_stream_xsalsa20_keygen((*C.uchar)(&k[0])) + return k +} diff --git a/crypto/stream/xsalsa20/crypto_stream_xsalsa20_test.go b/crypto/stream/xsalsa20/crypto_stream_xsalsa20_test.go new file mode 100644 index 0000000..6aa6b07 --- /dev/null +++ b/crypto/stream/xsalsa20/crypto_stream_xsalsa20_test.go @@ -0,0 +1,54 @@ +package xsalsa20 + +import ( + "testing" + "bytes" + "github.com/google/gofuzz" +) + +var TestCount = 100000 + +func Test(t *testing.T) { + // Test the key generation + if len(KeyGen()) != KeyBytes() { + t.Error("Generated key has the wrong length") + } + + // Fuzzing + f := fuzz.New() + + // Run tests + for i := 0; i < TestCount; i++ { + var c, m, r, d []byte + var n [24]byte + + // Generate random data + f.Fuzz(&m) + f.Fuzz(&n) + k := KeyGen() + + // Generate pseudo-random data + r = Random(len(m), n[:], k) + + // Perform XOR + d = make([]byte, len(m)) + for i := range r { + d[i] = r[i] ^ m[i] + } + + // Generate a ciphertext + c = XOR(m, n[:], k) + if !bytes.Equal(c, d) { + t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Generate another ciphertext + c = XORIC(m, n[:], 0, k) + if !bytes.Equal(c, d) { + t.Errorf("XORIC failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + } +} + From ac3a365e52402bcc01ed769d792a847b4b489685 Mon Sep 17 00:00:00 2001 From: Silke Date: Wed, 22 Mar 2017 17:47:59 +0100 Subject: [PATCH 2/6] Add IETF version of ChaCha20 --- .../crypto_stream_chacha20_ietf.go | 76 +++++++++++++++++++ .../crypto_stream_chacha20_ietf_test.go | 54 +++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go create mode 100644 crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf_test.go diff --git a/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go new file mode 100644 index 0000000..0317958 --- /dev/null +++ b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go @@ -0,0 +1,76 @@ +package chacha20ietf + +// #cgo pkg-config: libsodium +// #include +// #include +import "C" +import "github.com/GoKillers/libsodium-go/support" + +// KeyBytes returns the required length of a secret key +func KeyBytes() int { + return int(C.crypto_stream_chacha20_ietf_keybytes()) +} + +// NonceBytes returns the required length of a nonce +func NonceBytes() int { + return int(C.crypto_stream_chacha20_ietf_noncebytes()) +} + +// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. +func Random(clen int, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, clen) + + C.crypto_stream_chacha20_ietf( + (*C.uchar)(support.BytePointer(c)), + (C.ulonglong)(clen), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. +func XOR(m []byte, n []byte, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_chacha20_ietf_xor( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (*C.uchar)(&k[0])) + + return c +} + +// XORIC encrypts a message `m` using a nonce `n` and a secret key `k`, +// but with a block counter starting at `ic`. +func XORIC(m []byte, n []byte, ic uint64, k []byte) []byte { + support.CheckSize(n, NonceBytes(), "nonce") + support.CheckSize(k, KeyBytes(), "key") + + c := make([]byte, len(m)) + + C.crypto_stream_chacha20_ietf_xor_ic( + (*C.uchar)(support.BytePointer(c)), + (*C.uchar)(support.BytePointer(m)), + (C.ulonglong)(len(m)), + (*C.uchar)(&n[0]), + (C.uint32_t)(ic), + (*C.uchar)(&k[0])) + + return c +} + +// KeyGen generates a secret key +func KeyGen() []byte { + k := make([]byte, KeyBytes()) + C.crypto_stream_chacha20_ietf_keygen((*C.uchar)(&k[0])) + return k +} diff --git a/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf_test.go b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf_test.go new file mode 100644 index 0000000..3231e0b --- /dev/null +++ b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf_test.go @@ -0,0 +1,54 @@ +package chacha20ietf + +import ( + "testing" + "bytes" + "github.com/google/gofuzz" +) + +var TestCount = 100000 + +func Test(t *testing.T) { + // Test the key generation + if len(KeyGen()) != KeyBytes() { + t.Error("Generated key has the wrong length") + } + + // Fuzzing + f := fuzz.New() + + // Run tests + for i := 0; i < TestCount; i++ { + var c, m, r, d []byte + var n [12]byte + + // Generate random data + f.Fuzz(&m) + f.Fuzz(&n) + k := KeyGen() + + // Generate pseudo-random data + r = Random(len(m), n[:], k) + + // Perform XOR + d = make([]byte, len(m)) + for i := range r { + d[i] = r[i] ^ m[i] + } + + // Generate a ciphertext + c = XOR(m, n[:], k) + if !bytes.Equal(c, d) { + t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Generate another ciphertext + c = XORIC(m, n[:], 0, k) + if !bytes.Equal(c, d) { + t.Errorf("XORIC failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + } +} + From ea30eb1402751db15683cfb186396d3d4d120535 Mon Sep 17 00:00:00 2001 From: Silke Date: Wed, 12 Apr 2017 23:42:58 +0200 Subject: [PATCH 3/6] Refactor crypto/stream functions - Use constants instead of getter functions - Create types for key and nonce - Rename function to match golang.org/crypto naming --- .../stream/chacha20/crypto_stream_chacha20.go | 88 +++++++++++-------- .../chacha20/crypto_stream_chacha20_test.go | 52 +++++++---- .../crypto_stream_chacha20_ietf.go | 88 +++++++++++-------- .../crypto_stream_chacha20_ietf_test.go | 52 +++++++---- crypto/stream/crypto_stream.go | 72 ++++++++------- crypto/stream/crypto_stream_test.go | 37 +++++--- .../stream/salsa20/crypto_stream_salsa20.go | 88 +++++++++++-------- .../salsa20/crypto_stream_salsa20_test.go | 52 +++++++---- .../salsa2012/crypto_stream_salsa2012.go | 68 ++++++++------ .../salsa2012/crypto_stream_salsa2012_test.go | 35 +++++--- .../stream/salsa208/crypto_stream_salsa208.go | 68 ++++++++------ .../salsa208/crypto_stream_salsa208_test.go | 35 +++++--- .../xchacha20/crypto_stream_xchacha20.go | 88 +++++++++++-------- .../xchacha20/crypto_stream_xchacha20_test.go | 52 +++++++---- .../stream/xsalsa20/crypto_stream_xsalsa20.go | 88 +++++++++++-------- .../xsalsa20/crypto_stream_xsalsa20_test.go | 52 +++++++---- 16 files changed, 617 insertions(+), 398 deletions(-) diff --git a/crypto/stream/chacha20/crypto_stream_chacha20.go b/crypto/stream/chacha20/crypto_stream_chacha20.go index e8c387f..eafa4dc 100644 --- a/crypto/stream/chacha20/crypto_stream_chacha20.go +++ b/crypto/stream/chacha20/crypto_stream_chacha20.go @@ -1,3 +1,4 @@ +// Package chacha20 contains the libsodium bindings for the ChaCha20 stream cipher. package chacha20 // #cgo pkg-config: libsodium @@ -6,71 +7,84 @@ package chacha20 import "C" import "github.com/GoKillers/libsodium-go/support" -// KeyBytes returns the required length of a secret key -func KeyBytes() int { - return int(C.crypto_stream_chacha20_keybytes()) +// Sodium should always be initialised +func init() { + C.sodium_init() } -// NonceBytes returns the required length of a nonce -func NonceBytes() int { - return int(C.crypto_stream_chacha20_noncebytes()) -} +// Required length of secret key and nonce +const ( + KeyBytes int = C.crypto_stream_chacha20_KEYBYTES + NonceBytes int = C.crypto_stream_chacha20_NONCEBYTES +) + +// Nonce represents a cryptographic nonce +type Nonce [NonceBytes]byte -// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. -func Random(clen int, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// Key represents a secret key +type Key [KeyBytes]byte - c := make([]byte, clen) +// KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. +func KeyStream(c []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + + if len(c) == 0 { + return + } C.crypto_stream_chacha20( - (*C.uchar)(support.BytePointer(c)), - (C.ulonglong)(clen), + (*C.uchar)(&c[0]), + (C.ulonglong)(len(c)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. -func XOR(m []byte, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStream(c, m []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_chacha20_xor( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XORIC encrypts a message `m` using a nonce `n` and a secret key `k`, +// XORKeyStreamIC encrypts a message `m` using a nonce `n` and a secret key `k`, // but with a block counter starting at `ic`. -func XORIC(m []byte, n []byte, ic uint64, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint64) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_chacha20_xor_ic( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (C.uint64_t)(ic), (*C.uchar)(&k[0])) - - return c } -// KeyGen generates a secret key -func KeyGen() []byte { - k := make([]byte, KeyBytes()) +// GenerateKey generates a secret key +func GenerateKey() *Key { + k := new(Key) + C.crypto_stream_chacha20_keygen((*C.uchar)(&k[0])) + return k } diff --git a/crypto/stream/chacha20/crypto_stream_chacha20_test.go b/crypto/stream/chacha20/crypto_stream_chacha20_test.go index a0eb291..59ad6ff 100644 --- a/crypto/stream/chacha20/crypto_stream_chacha20_test.go +++ b/crypto/stream/chacha20/crypto_stream_chacha20_test.go @@ -1,34 +1,36 @@ package chacha20 import ( - "testing" "bytes" "github.com/google/gofuzz" + "testing" ) var TestCount = 100000 -func Test(t *testing.T) { +func TestChaCha20(t *testing.T) { // Test the key generation - if len(KeyGen()) != KeyBytes() { - t.Error("Generated key has the wrong length") + if *GenerateKey() == (Key{}) { + t.Error("Generated key is zero") } // Fuzzing - f := fuzz.New() + fm := fuzz.New() + fn := fuzz.New().NilChance(0) // Run tests for i := 0; i < TestCount; i++ { - var c, m, r, d []byte - var n [8]byte + var c, m, m2, r, d []byte + n := new(Nonce) // Generate random data - f.Fuzz(&m) - f.Fuzz(&n) - k := KeyGen() + fm.Fuzz(&m) + fn.Fuzz(&n) + k := GenerateKey() // Generate pseudo-random data - r = Random(len(m), n[:], k) + r = make([]byte, len(m)) + KeyStream(r, n, k) // Perform XOR d = make([]byte, len(m)) @@ -37,18 +39,34 @@ func Test(t *testing.T) { } // Generate a ciphertext - c = XOR(m, n[:], k) + c = make([]byte, len(m)) + XORKeyStream(c, m, n, k) if !bytes.Equal(c, d) { - t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.Errorf("Encryption failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } - // Generate another ciphertext - c = XORIC(m, n[:], 0, k) + // Generate one with IC + XORKeyStreamIC(c, m, n, k, 0) if !bytes.Equal(c, d) { - t.Errorf("XORIC failed for m: %x, n: %x, k: %x", m, n, k) + t.Errorf("Encryption with IC failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Check if in-place encryption works + m2 = make([]byte, len(m)) + copy(m2, m) + XORKeyStream(m2, m2, n, k) + if !bytes.Equal(c, m2) { + t.Errorf("In place encryption failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Check again with IC + XORKeyStreamIC(m, m, n, k, 0) + if !bytes.Equal(c, m2) { + t.Errorf("In place encryption with IC failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } } } - diff --git a/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go index 0317958..c18b7a8 100644 --- a/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go +++ b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go @@ -1,3 +1,4 @@ +// Package chacha20ietf contains the libsodium bindings for the IETF variant of the ChaCha20 stream cipher. package chacha20ietf // #cgo pkg-config: libsodium @@ -6,71 +7,84 @@ package chacha20ietf import "C" import "github.com/GoKillers/libsodium-go/support" -// KeyBytes returns the required length of a secret key -func KeyBytes() int { - return int(C.crypto_stream_chacha20_ietf_keybytes()) +// Sodium should always be initialised +func init() { + C.sodium_init() } -// NonceBytes returns the required length of a nonce -func NonceBytes() int { - return int(C.crypto_stream_chacha20_ietf_noncebytes()) -} +// Required length of secret key and nonce +const ( + KeyBytes int = C.crypto_stream_chacha20_ietf_KEYBYTES + NonceBytes int = C.crypto_stream_chacha20_ietf_NONCEBYTES +) + +// Nonce represents a cryptographic nonce +type Nonce [NonceBytes]byte -// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. -func Random(clen int, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// Key represents a secret key +type Key [KeyBytes]byte - c := make([]byte, clen) +// KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. +func KeyStream(c []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + + if len(c) == 0 { + return + } C.crypto_stream_chacha20_ietf( - (*C.uchar)(support.BytePointer(c)), - (C.ulonglong)(clen), + (*C.uchar)(&c[0]), + (C.ulonglong)(len(c)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. -func XOR(m []byte, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStream(c, m []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_chacha20_ietf_xor( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XORIC encrypts a message `m` using a nonce `n` and a secret key `k`, +// XORKeyStreamIC encrypts a message `m` using a nonce `n` and a secret key `k`, // but with a block counter starting at `ic`. -func XORIC(m []byte, n []byte, ic uint64, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint32) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_chacha20_ietf_xor_ic( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (C.uint32_t)(ic), (*C.uchar)(&k[0])) - - return c } -// KeyGen generates a secret key -func KeyGen() []byte { - k := make([]byte, KeyBytes()) +// GenerateKey generates a secret key +func GenerateKey() *Key { + k := new(Key) + C.crypto_stream_chacha20_ietf_keygen((*C.uchar)(&k[0])) + return k } diff --git a/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf_test.go b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf_test.go index 3231e0b..f3eaaff 100644 --- a/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf_test.go +++ b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf_test.go @@ -1,34 +1,36 @@ package chacha20ietf import ( - "testing" "bytes" "github.com/google/gofuzz" + "testing" ) var TestCount = 100000 -func Test(t *testing.T) { +func TestChaCha20IETF(t *testing.T) { // Test the key generation - if len(KeyGen()) != KeyBytes() { - t.Error("Generated key has the wrong length") + if *GenerateKey() == (Key{}) { + t.Error("Generated key is zero") } // Fuzzing - f := fuzz.New() + fm := fuzz.New() + fn := fuzz.New().NilChance(0) // Run tests for i := 0; i < TestCount; i++ { - var c, m, r, d []byte - var n [12]byte + var c, m, m2, r, d []byte + n := new(Nonce) // Generate random data - f.Fuzz(&m) - f.Fuzz(&n) - k := KeyGen() + fm.Fuzz(&m) + fn.Fuzz(&n) + k := GenerateKey() // Generate pseudo-random data - r = Random(len(m), n[:], k) + r = make([]byte, len(m)) + KeyStream(r, n, k) // Perform XOR d = make([]byte, len(m)) @@ -37,18 +39,34 @@ func Test(t *testing.T) { } // Generate a ciphertext - c = XOR(m, n[:], k) + c = make([]byte, len(m)) + XORKeyStream(c, m, n, k) if !bytes.Equal(c, d) { - t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.Errorf("Encryption failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } - // Generate another ciphertext - c = XORIC(m, n[:], 0, k) + // Generate one with IC + XORKeyStreamIC(c, m, n, k, 0) if !bytes.Equal(c, d) { - t.Errorf("XORIC failed for m: %x, n: %x, k: %x", m, n, k) + t.Errorf("Encryption with IC failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Check if in-place encryption works + m2 = make([]byte, len(m)) + copy(m2, m) + XORKeyStream(m2, m2, n, k) + if !bytes.Equal(c, m2) { + t.Errorf("In place encryption failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Check again with IC + XORKeyStreamIC(m, m, n, k, 0) + if !bytes.Equal(c, m2) { + t.Errorf("In place encryption with IC failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } } } - diff --git a/crypto/stream/crypto_stream.go b/crypto/stream/crypto_stream.go index 48b0ed8..60cc0d6 100644 --- a/crypto/stream/crypto_stream.go +++ b/crypto/stream/crypto_stream.go @@ -1,3 +1,4 @@ +// Package stream contains the libsodium bindings for the XSalsa20 stream cipher. package stream // #cgo pkg-config: libsodium @@ -6,57 +7,64 @@ package stream import "C" import "github.com/GoKillers/libsodium-go/support" -// KeyBytes returns the required length of a secret key -func KeyBytes() int { - return int(C.crypto_stream_keybytes()) +// Sodium should always be initialised +func init() { + C.sodium_init() } -// NonceBytes returns the required length of a nonce -func NonceBytes() int { - return int(C.crypto_stream_noncebytes()) -} +// Stream byte lengths and algorithm name +const ( + KeyBytes int = C.crypto_stream_KEYBYTES // Length of a secret key + NonceBytes int = C.crypto_stream_NONCEBYTES // Length of a nonce + Primitive string = C.crypto_stream_PRIMITIVE // Name of the used algorithm +) -// Primitive returns the name of the used algorithm -func Primitive() string { - return C.GoString(C.crypto_stream_primitive()) -} +// Nonce represents a cryptographic nonce +type Nonce [NonceBytes]byte + +// Key represents a secret key +type Key [KeyBytes]byte -// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. -func Random(clen int, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. +func KeyStream(c []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") - c := make([]byte, clen) + if len(c) == 0 { + return + } C.crypto_stream( - (*C.uchar)(support.BytePointer(c)), - (C.ulonglong)(clen), + (*C.uchar)(&c[0]), + (C.ulonglong)(len(c)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. -func XOR(m []byte, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStream(c, m []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_xor( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// KeyGen generates a secret key -func KeyGen() []byte { - c := make([]byte, KeyBytes()) +// GenerateKey generates a secret key +func GenerateKey() *Key { + c := new(Key) + C.crypto_stream_keygen((*C.uchar)(&c[0])) + return c } diff --git a/crypto/stream/crypto_stream_test.go b/crypto/stream/crypto_stream_test.go index 5f2db81..9654d50 100644 --- a/crypto/stream/crypto_stream_test.go +++ b/crypto/stream/crypto_stream_test.go @@ -1,39 +1,41 @@ package stream import ( - "testing" "bytes" "github.com/google/gofuzz" + "testing" ) var TestCount = 100000 -func Test(t *testing.T) { +func TestStream(t *testing.T) { // Check the primitive - if Primitive() != "xsalsa20" { - t.Error("Incorrect primitive: %x", Primitive()) + if Primitive != "xsalsa20" { + t.Errorf("Incorrect primitive: %x", Primitive) } // Test the key generation - if len(KeyGen()) != KeyBytes() { - t.Error("Generated key has the wrong length") + if *GenerateKey() == (Key{}) { + t.Error("Generated key is zero") } // Fuzzing - f := fuzz.New() + fm := fuzz.New() + fn := fuzz.New().NilChance(0) // Run tests for i := 0; i < TestCount; i++ { var c, m, r, d []byte - var n [24]byte + n := new(Nonce) // Generate random data - f.Fuzz(&m) - f.Fuzz(&n) - k := KeyGen() + fm.Fuzz(&m) + fn.Fuzz(&n) + k := GenerateKey() // Generate pseudo-random data - r = Random(len(m), n[:], k) + r = make([]byte, len(m)) + KeyStream(r, n, k) // Perform XOR d = make([]byte, len(m)) @@ -42,11 +44,18 @@ func Test(t *testing.T) { } // Generate a ciphertext - c = XOR(m, n[:], k) + c = make([]byte, len(m)) + XORKeyStream(c, m, n, k) if !bytes.Equal(c, d) { t.Errorf("Encryption failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } + + // Check if in-place encryption works + XORKeyStream(m, m, n, k) + if !bytes.Equal(c, m) { + t.Errorf("In place encryption failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } } } - diff --git a/crypto/stream/salsa20/crypto_stream_salsa20.go b/crypto/stream/salsa20/crypto_stream_salsa20.go index 20a670b..5ef55e4 100644 --- a/crypto/stream/salsa20/crypto_stream_salsa20.go +++ b/crypto/stream/salsa20/crypto_stream_salsa20.go @@ -1,3 +1,4 @@ +// Package salsa20 contains the libsodium bindings for the Salsa20 stream cipher. package salsa20 // #cgo pkg-config: libsodium @@ -6,71 +7,84 @@ package salsa20 import "C" import "github.com/GoKillers/libsodium-go/support" -// KeyBytes returns the required length of a secret key -func KeyBytes() int { - return int(C.crypto_stream_salsa20_keybytes()) +// Sodium should always be initialised +func init() { + C.sodium_init() } -// NonceBytes returns the required length of a nonce -func NonceBytes() int { - return int(C.crypto_stream_salsa20_noncebytes()) -} +// Required length of secret key and nonce +const ( + KeyBytes int = C.crypto_stream_salsa20_KEYBYTES + NonceBytes int = C.crypto_stream_salsa20_NONCEBYTES +) + +// Nonce represents a cryptographic nonce +type Nonce [NonceBytes]byte -// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. -func Random(clen int, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// Key represents a secret key +type Key [KeyBytes]byte - c := make([]byte, clen) +// KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. +func KeyStream(c []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + + if len(c) == 0 { + return + } C.crypto_stream_salsa20( - (*C.uchar)(support.BytePointer(c)), - (C.ulonglong)(clen), + (*C.uchar)(&c[0]), + (C.ulonglong)(len(c)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. -func XOR(m []byte, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStream(c, m []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_salsa20_xor( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XORIC encrypts a message `m` using a nonce `n` and a secret key `k`, +// XORKeyStreamIC encrypts a message `m` using a nonce `n` and a secret key `k`, // but with a block counter starting at `ic`. -func XORIC(m []byte, n []byte, ic uint64, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint64) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_salsa20_xor_ic( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (C.uint64_t)(ic), (*C.uchar)(&k[0])) - - return c } -// KeyGen generates a secret key -func KeyGen() []byte { - k := make([]byte, KeyBytes()) +// GenerateKey generates a secret key +func GenerateKey() *Key { + k := new(Key) + C.crypto_stream_salsa20_keygen((*C.uchar)(&k[0])) + return k } diff --git a/crypto/stream/salsa20/crypto_stream_salsa20_test.go b/crypto/stream/salsa20/crypto_stream_salsa20_test.go index 3983fc7..5928335 100644 --- a/crypto/stream/salsa20/crypto_stream_salsa20_test.go +++ b/crypto/stream/salsa20/crypto_stream_salsa20_test.go @@ -1,34 +1,36 @@ package salsa20 import ( - "testing" "bytes" "github.com/google/gofuzz" + "testing" ) var TestCount = 100000 -func Test(t *testing.T) { +func TestSalsa20(t *testing.T) { // Test the key generation - if len(KeyGen()) != KeyBytes() { - t.Error("Generated key has the wrong length") + if *GenerateKey() == (Key{}) { + t.Error("Generated key is zero") } // Fuzzing - f := fuzz.New() + fm := fuzz.New() + fn := fuzz.New().NilChance(0) // Run tests for i := 0; i < TestCount; i++ { - var c, m, r, d []byte - var n [8]byte + var c, m, m2, r, d []byte + n := new(Nonce) // Generate random data - f.Fuzz(&m) - f.Fuzz(&n) - k := KeyGen() + fm.Fuzz(&m) + fn.Fuzz(&n) + k := GenerateKey() // Generate pseudo-random data - r = Random(len(m), n[:], k) + r = make([]byte, len(m)) + KeyStream(r, n, k) // Perform XOR d = make([]byte, len(m)) @@ -37,18 +39,34 @@ func Test(t *testing.T) { } // Generate a ciphertext - c = XOR(m, n[:], k) + c = make([]byte, len(m)) + XORKeyStream(c, m, n, k) if !bytes.Equal(c, d) { - t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.Errorf("Encryption failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } - // Generate another ciphertext - c = XORIC(m, n[:], 0, k) + // Generate one with IC + XORKeyStreamIC(c, m, n, k, 0) if !bytes.Equal(c, d) { - t.Errorf("XORIC failed for m: %x, n: %x, k: %x", m, n, k) + t.Errorf("Encryption with IC failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Check if in-place encryption works + m2 = make([]byte, len(m)) + copy(m2, m) + XORKeyStream(m2, m2, n, k) + if !bytes.Equal(c, m2) { + t.Errorf("In place encryption failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Check again with IC + XORKeyStreamIC(m, m, n, k, 0) + if !bytes.Equal(c, m2) { + t.Errorf("In place encryption with IC failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } } } - diff --git a/crypto/stream/salsa2012/crypto_stream_salsa2012.go b/crypto/stream/salsa2012/crypto_stream_salsa2012.go index 9b5d0bb..b885902 100644 --- a/crypto/stream/salsa2012/crypto_stream_salsa2012.go +++ b/crypto/stream/salsa2012/crypto_stream_salsa2012.go @@ -1,3 +1,4 @@ +// Package salsa2012 contains the libsodium bindings for the Salsa20 stream cipher reduced to 12 rounds. package salsa2012 // #cgo pkg-config: libsodium @@ -6,52 +7,63 @@ package salsa2012 import "C" import "github.com/GoKillers/libsodium-go/support" -// KeyBytes returns the required length of a secret key -func KeyBytes() int { - return int(C.crypto_stream_salsa2012_keybytes()) +// Sodium should always be initialised +func init() { + C.sodium_init() } -// NonceBytes returns the required length of a nonce -func NonceBytes() int { - return int(C.crypto_stream_salsa2012_noncebytes()) -} +// Required length of secret key and nonce +const ( + KeyBytes int = C.crypto_stream_salsa2012_KEYBYTES + NonceBytes int = C.crypto_stream_salsa2012_NONCEBYTES +) + +// Nonce represents a cryptographic nonce +type Nonce [NonceBytes]byte -// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. -func Random(clen int, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// Key represents a secret key +type Key [KeyBytes]byte - c := make([]byte, clen) +// KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. +func KeyStream(c []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + + if len(c) == 0 { + return + } C.crypto_stream_salsa2012( - (*C.uchar)(support.BytePointer(c)), - (C.ulonglong)(clen), + (*C.uchar)(&c[0]), + (C.ulonglong)(len(c)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. -func XOR(m []byte, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStream(c, m []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_salsa2012_xor( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// KeyGen generates a secret key -func KeyGen() []byte { - k := make([]byte, KeyBytes()) +// GenerateKey generates a secret key +func GenerateKey() *Key { + k := new(Key) + C.crypto_stream_salsa2012_keygen((*C.uchar)(&k[0])) + return k } diff --git a/crypto/stream/salsa2012/crypto_stream_salsa2012_test.go b/crypto/stream/salsa2012/crypto_stream_salsa2012_test.go index 7eb075f..267aedc 100644 --- a/crypto/stream/salsa2012/crypto_stream_salsa2012_test.go +++ b/crypto/stream/salsa2012/crypto_stream_salsa2012_test.go @@ -1,34 +1,36 @@ package salsa2012 import ( - "testing" "bytes" "github.com/google/gofuzz" + "testing" ) var TestCount = 100000 -func Test(t *testing.T) { +func TestSalsa2012(t *testing.T) { // Test the key generation - if len(KeyGen()) != KeyBytes() { - t.Error("Generated key has the wrong length") + if *GenerateKey() == (Key{}) { + t.Error("Generated key is zero") } // Fuzzing - f := fuzz.New() + fm := fuzz.New() + fn := fuzz.New().NilChance(0) // Run tests for i := 0; i < TestCount; i++ { var c, m, r, d []byte - var n [8]byte + n := new(Nonce) // Generate random data - f.Fuzz(&m) - f.Fuzz(&n) - k := KeyGen() + fm.Fuzz(&m) + fn.Fuzz(&n) + k := GenerateKey() // Generate pseudo-random data - r = Random(len(m), n[:], k) + r = make([]byte, len(m)) + KeyStream(r, n, k) // Perform XOR d = make([]byte, len(m)) @@ -37,11 +39,18 @@ func Test(t *testing.T) { } // Generate a ciphertext - c = XOR(m, n[:], k) + c = make([]byte, len(m)) + XORKeyStream(c, m, n, k) if !bytes.Equal(c, d) { - t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.Errorf("Encryption failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Check if in-place encryption works + XORKeyStream(m, m, n, k) + if !bytes.Equal(c, m) { + t.Errorf("In place encryption failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } } } - diff --git a/crypto/stream/salsa208/crypto_stream_salsa208.go b/crypto/stream/salsa208/crypto_stream_salsa208.go index 3623933..00a2665 100644 --- a/crypto/stream/salsa208/crypto_stream_salsa208.go +++ b/crypto/stream/salsa208/crypto_stream_salsa208.go @@ -1,3 +1,4 @@ +// Package salsa208 contains the libsodium bindings for the Salsa20 stream cipher reduced to 8 rounds. package salsa208 // #cgo pkg-config: libsodium @@ -6,52 +7,63 @@ package salsa208 import "C" import "github.com/GoKillers/libsodium-go/support" -// KeyBytes returns the required length of a secret key -func KeyBytes() int { - return int(C.crypto_stream_salsa208_keybytes()) +// Sodium should always be initialised +func init() { + C.sodium_init() } -// NonceBytes returns the required length of a nonce -func NonceBytes() int { - return int(C.crypto_stream_salsa208_noncebytes()) -} +// Required length of secret key and nonce +const ( + KeyBytes int = C.crypto_stream_salsa208_KEYBYTES + NonceBytes int = C.crypto_stream_salsa208_NONCEBYTES +) + +// Nonce represents a cryptographic nonce +type Nonce [NonceBytes]byte -// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. -func Random(clen int, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// Key represents a secret key +type Key [KeyBytes]byte - c := make([]byte, clen) +// KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. +func KeyStream(c []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + + if len(c) == 0 { + return + } C.crypto_stream_salsa208( - (*C.uchar)(support.BytePointer(c)), - (C.ulonglong)(clen), + (*C.uchar)(&c[0]), + (C.ulonglong)(len(c)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. -func XOR(m []byte, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStream(c, m []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_salsa208_xor( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// KeyGen generates a secret key -func KeyGen() []byte { - k := make([]byte, KeyBytes()) +// GenerateKey generates a secret key +func GenerateKey() *Key { + k := new(Key) + C.crypto_stream_salsa208_keygen((*C.uchar)(&k[0])) + return k } diff --git a/crypto/stream/salsa208/crypto_stream_salsa208_test.go b/crypto/stream/salsa208/crypto_stream_salsa208_test.go index a5409bb..272e18d 100644 --- a/crypto/stream/salsa208/crypto_stream_salsa208_test.go +++ b/crypto/stream/salsa208/crypto_stream_salsa208_test.go @@ -1,34 +1,36 @@ package salsa208 import ( - "testing" "bytes" "github.com/google/gofuzz" + "testing" ) var TestCount = 100000 -func Test(t *testing.T) { +func TestSalsa208(t *testing.T) { // Test the key generation - if len(KeyGen()) != KeyBytes() { - t.Error("Generated key has the wrong length") + if *GenerateKey() == (Key{}) { + t.Error("Generated key is zero") } // Fuzzing - f := fuzz.New() + fm := fuzz.New() + fn := fuzz.New().NilChance(0) // Run tests for i := 0; i < TestCount; i++ { var c, m, r, d []byte - var n [8]byte + n := new(Nonce) // Generate random data - f.Fuzz(&m) - f.Fuzz(&n) - k := KeyGen() + fm.Fuzz(&m) + fn.Fuzz(&n) + k := GenerateKey() // Generate pseudo-random data - r = Random(len(m), n[:], k) + r = make([]byte, len(m)) + KeyStream(r, n, k) // Perform XOR d = make([]byte, len(m)) @@ -37,11 +39,18 @@ func Test(t *testing.T) { } // Generate a ciphertext - c = XOR(m, n[:], k) + c = make([]byte, len(m)) + XORKeyStream(c, m, n, k) if !bytes.Equal(c, d) { - t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.Errorf("Encryption failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Check if in-place encryption works + XORKeyStream(m, m, n, k) + if !bytes.Equal(c, m) { + t.Errorf("In place encryption failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } } } - diff --git a/crypto/stream/xchacha20/crypto_stream_xchacha20.go b/crypto/stream/xchacha20/crypto_stream_xchacha20.go index 99d6919..8eef7ed 100644 --- a/crypto/stream/xchacha20/crypto_stream_xchacha20.go +++ b/crypto/stream/xchacha20/crypto_stream_xchacha20.go @@ -1,3 +1,4 @@ +// Package xchacha20 contains the libsodium bindings for the XChaCha20 stream cipher. package xchacha20 // #cgo pkg-config: libsodium @@ -6,71 +7,84 @@ package xchacha20 import "C" import "github.com/GoKillers/libsodium-go/support" -// KeyBytes returns the required length of a secret key -func KeyBytes() int { - return int(C.crypto_stream_xchacha20_keybytes()) +// Sodium should always be initialised +func init() { + C.sodium_init() } -// NonceBytes returns the required length of a nonce -func NonceBytes() int { - return int(C.crypto_stream_xchacha20_noncebytes()) -} +// Required length of secret key and nonce +const ( + KeyBytes int = C.crypto_stream_xchacha20_KEYBYTES + NonceBytes int = C.crypto_stream_xchacha20_NONCEBYTES +) + +// Nonce represents a cryptographic nonce +type Nonce [NonceBytes]byte -// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. -func Random(clen int, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// Key represents a secret key +type Key [KeyBytes]byte - c := make([]byte, clen) +// KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. +func KeyStream(c []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + + if len(c) == 0 { + return + } C.crypto_stream_xchacha20( - (*C.uchar)(support.BytePointer(c)), - (C.ulonglong)(clen), + (*C.uchar)(&c[0]), + (C.ulonglong)(len(c)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. -func XOR(m []byte, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStream(c, m []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_xchacha20_xor( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XORIC encrypts a message `m` using a nonce `n` and a secret key `k`, +// XORKeyStreamIC encrypts a message `m` using a nonce `n` and a secret key `k`, // but with a block counter starting at `ic`. -func XORIC(m []byte, n []byte, ic uint64, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint64) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_xchacha20_xor_ic( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (C.uint64_t)(ic), (*C.uchar)(&k[0])) - - return c } -// KeyGen generates a secret key -func KeyGen() []byte { - k := make([]byte, KeyBytes()) +// GenerateKey generates a secret key +func GenerateKey() *Key { + k := new(Key) + C.crypto_stream_xchacha20_keygen((*C.uchar)(&k[0])) + return k } diff --git a/crypto/stream/xchacha20/crypto_stream_xchacha20_test.go b/crypto/stream/xchacha20/crypto_stream_xchacha20_test.go index 86681b3..b590c47 100644 --- a/crypto/stream/xchacha20/crypto_stream_xchacha20_test.go +++ b/crypto/stream/xchacha20/crypto_stream_xchacha20_test.go @@ -1,34 +1,36 @@ package xchacha20 import ( - "testing" "bytes" "github.com/google/gofuzz" + "testing" ) var TestCount = 100000 -func Test(t *testing.T) { +func TestXChaCha20(t *testing.T) { // Test the key generation - if len(KeyGen()) != KeyBytes() { - t.Error("Generated key has the wrong length") + if *GenerateKey() == (Key{}) { + t.Error("Generated key is zero") } // Fuzzing - f := fuzz.New() + fm := fuzz.New() + fn := fuzz.New().NilChance(0) // Run tests for i := 0; i < TestCount; i++ { - var c, m, r, d []byte - var n [24]byte + var c, m, m2, r, d []byte + n := new(Nonce) // Generate random data - f.Fuzz(&m) - f.Fuzz(&n) - k := KeyGen() + fm.Fuzz(&m) + fn.Fuzz(&n) + k := GenerateKey() // Generate pseudo-random data - r = Random(len(m), n[:], k) + r = make([]byte, len(m)) + KeyStream(r, n, k) // Perform XOR d = make([]byte, len(m)) @@ -37,18 +39,34 @@ func Test(t *testing.T) { } // Generate a ciphertext - c = XOR(m, n[:], k) + c = make([]byte, len(m)) + XORKeyStream(c, m, n, k) if !bytes.Equal(c, d) { - t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.Errorf("Encryption failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } - // Generate another ciphertext - c = XORIC(m, n[:], 0, k) + // Generate one with IC + XORKeyStreamIC(c, m, n, k, 0) if !bytes.Equal(c, d) { - t.Errorf("XORIC failed for m: %x, n: %x, k: %x", m, n, k) + t.Errorf("Encryption with IC failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Check if in-place encryption works + m2 = make([]byte, len(m)) + copy(m2, m) + XORKeyStream(m2, m2, n, k) + if !bytes.Equal(c, m2) { + t.Errorf("In place encryption failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Check again with IC + XORKeyStreamIC(m, m, n, k, 0) + if !bytes.Equal(c, m2) { + t.Errorf("In place encryption with IC failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } } } - diff --git a/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go b/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go index 928fbfd..8d781d5 100644 --- a/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go +++ b/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go @@ -1,3 +1,4 @@ +// Package xsalsa20 contains the libsodium bindings for the XSalsa20 stream cipher. package xsalsa20 // #cgo pkg-config: libsodium @@ -6,71 +7,84 @@ package xsalsa20 import "C" import "github.com/GoKillers/libsodium-go/support" -// KeyBytes returns the required length of a secret key -func KeyBytes() int { - return int(C.crypto_stream_xsalsa20_keybytes()) +// Sodium should always be initialised +func init() { + C.sodium_init() } -// NonceBytes returns the required length of a nonce -func NonceBytes() int { - return int(C.crypto_stream_xsalsa20_noncebytes()) -} +// Required length of secret key and nonce +const ( + KeyBytes int = C.crypto_stream_xsalsa20_KEYBYTES + NonceBytes int = C.crypto_stream_xsalsa20_NONCEBYTES +) + +// Nonce represents a cryptographic nonce +type Nonce [NonceBytes]byte -// Random returns `clen` pseudo random bytes using a nonce `n` and a secret key `k`. -func Random(clen int, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// Key represents a secret key +type Key [KeyBytes]byte - c := make([]byte, clen) +// KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. +func KeyStream(c []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + + if len(c) == 0 { + return + } C.crypto_stream_xsalsa20( - (*C.uchar)(support.BytePointer(c)), - (C.ulonglong)(clen), + (*C.uchar)(&c[0]), + (C.ulonglong)(len(c)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XOR encrypts a message `m` using a nonce `n` and a secret key `k`. -func XOR(m []byte, n []byte, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStream(c, m []byte, n *Nonce, k *Key) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_xsalsa20_xor( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (*C.uchar)(&k[0])) - - return c } -// XORIC encrypts a message `m` using a nonce `n` and a secret key `k`, +// XORKeyStreamIC encrypts a message `m` using a nonce `n` and a secret key `k`, // but with a block counter starting at `ic`. -func XORIC(m []byte, n []byte, ic uint64, k []byte) []byte { - support.CheckSize(n, NonceBytes(), "nonce") - support.CheckSize(k, KeyBytes(), "key") +// If `m` and `c` are the same slice, in-place encryption is performed. +func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint64) { + support.NilPanic(n == nil, "nonce") + support.NilPanic(k == nil, "key") + support.CheckSizeSmaller(c, m, "output", "input") - c := make([]byte, len(m)) + if len(c) == 0 { + return + } C.crypto_stream_xsalsa20_xor_ic( - (*C.uchar)(support.BytePointer(c)), - (*C.uchar)(support.BytePointer(m)), + (*C.uchar)(&c[0]), + (*C.uchar)(&m[0]), (C.ulonglong)(len(m)), (*C.uchar)(&n[0]), (C.uint64_t)(ic), (*C.uchar)(&k[0])) - - return c } -// KeyGen generates a secret key -func KeyGen() []byte { - k := make([]byte, KeyBytes()) +// GenerateKey generates a secret key +func GenerateKey() *Key { + k := new(Key) + C.crypto_stream_xsalsa20_keygen((*C.uchar)(&k[0])) + return k } diff --git a/crypto/stream/xsalsa20/crypto_stream_xsalsa20_test.go b/crypto/stream/xsalsa20/crypto_stream_xsalsa20_test.go index 6aa6b07..3f796cd 100644 --- a/crypto/stream/xsalsa20/crypto_stream_xsalsa20_test.go +++ b/crypto/stream/xsalsa20/crypto_stream_xsalsa20_test.go @@ -1,34 +1,36 @@ package xsalsa20 import ( - "testing" "bytes" "github.com/google/gofuzz" + "testing" ) var TestCount = 100000 -func Test(t *testing.T) { +func TestXSalsa20(t *testing.T) { // Test the key generation - if len(KeyGen()) != KeyBytes() { - t.Error("Generated key has the wrong length") + if *GenerateKey() == (Key{}) { + t.Error("Generated key is zero") } // Fuzzing - f := fuzz.New() + fm := fuzz.New() + fn := fuzz.New().NilChance(0) // Run tests for i := 0; i < TestCount; i++ { - var c, m, r, d []byte - var n [24]byte + var c, m, m2, r, d []byte + n := new(Nonce) // Generate random data - f.Fuzz(&m) - f.Fuzz(&n) - k := KeyGen() + fm.Fuzz(&m) + fn.Fuzz(&n) + k := GenerateKey() // Generate pseudo-random data - r = Random(len(m), n[:], k) + r = make([]byte, len(m)) + KeyStream(r, n, k) // Perform XOR d = make([]byte, len(m)) @@ -37,18 +39,34 @@ func Test(t *testing.T) { } // Generate a ciphertext - c = XOR(m, n[:], k) + c = make([]byte, len(m)) + XORKeyStream(c, m, n, k) if !bytes.Equal(c, d) { - t.Errorf("XOR failed for m: %x, n: %x, k: %x", m, n, k) + t.Errorf("Encryption failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } - // Generate another ciphertext - c = XORIC(m, n[:], 0, k) + // Generate one with IC + XORKeyStreamIC(c, m, n, k, 0) if !bytes.Equal(c, d) { - t.Errorf("XORIC failed for m: %x, n: %x, k: %x", m, n, k) + t.Errorf("Encryption with IC failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Check if in-place encryption works + m2 = make([]byte, len(m)) + copy(m2, m) + XORKeyStream(m2, m2, n, k) + if !bytes.Equal(c, m2) { + t.Errorf("In place encryption failed for m: %x, n: %x, k: %x", m, n, k) + t.FailNow() + } + + // Check again with IC + XORKeyStreamIC(m, m, n, k, 0) + if !bytes.Equal(c, m2) { + t.Errorf("In place encryption with IC failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } } } - From 0ffe0952e788fef7eed429ee27f59db10ff7e459 Mon Sep 17 00:00:00 2001 From: Silke Date: Mon, 17 Jul 2017 15:43:13 +0200 Subject: [PATCH 4/6] Remove Nonce and Key types --- .../stream/chacha20/crypto_stream_chacha20.go | 20 +++++++------------ .../chacha20/crypto_stream_chacha20_test.go | 4 ++-- .../crypto_stream_chacha20_ietf.go | 20 +++++++------------ .../crypto_stream_chacha20_ietf_test.go | 4 ++-- crypto/stream/crypto_stream.go | 16 +++++---------- crypto/stream/crypto_stream_test.go | 4 ++-- .../stream/salsa20/crypto_stream_salsa20.go | 20 +++++++------------ .../salsa20/crypto_stream_salsa20_test.go | 4 ++-- .../salsa2012/crypto_stream_salsa2012.go | 16 +++++---------- .../salsa2012/crypto_stream_salsa2012_test.go | 12 ++++++----- .../stream/salsa208/crypto_stream_salsa208.go | 16 +++++---------- .../salsa208/crypto_stream_salsa208_test.go | 12 ++++++----- .../xchacha20/crypto_stream_xchacha20.go | 20 +++++++------------ .../xchacha20/crypto_stream_xchacha20_test.go | 4 ++-- .../stream/xsalsa20/crypto_stream_xsalsa20.go | 20 +++++++------------ .../xsalsa20/crypto_stream_xsalsa20_test.go | 4 ++-- 16 files changed, 76 insertions(+), 120 deletions(-) diff --git a/crypto/stream/chacha20/crypto_stream_chacha20.go b/crypto/stream/chacha20/crypto_stream_chacha20.go index eafa4dc..4784b4c 100644 --- a/crypto/stream/chacha20/crypto_stream_chacha20.go +++ b/crypto/stream/chacha20/crypto_stream_chacha20.go @@ -18,14 +18,8 @@ const ( NonceBytes int = C.crypto_stream_chacha20_NONCEBYTES ) -// Nonce represents a cryptographic nonce -type Nonce [NonceBytes]byte - -// Key represents a secret key -type Key [KeyBytes]byte - // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. -func KeyStream(c []byte, n *Nonce, k *Key) { +func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") @@ -42,10 +36,10 @@ func KeyStream(c []byte, n *Nonce, k *Key) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStream(c, m []byte, n *Nonce, k *Key) { +func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -62,10 +56,10 @@ func XORKeyStream(c, m []byte, n *Nonce, k *Key) { // XORKeyStreamIC encrypts a message `m` using a nonce `n` and a secret key `k`, // but with a block counter starting at `ic`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint64) { +func XORKeyStreamIC(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte, ic uint64) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -81,8 +75,8 @@ func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint64) { } // GenerateKey generates a secret key -func GenerateKey() *Key { - k := new(Key) +func GenerateKey() *[KeyBytes]byte { + k := new([KeyBytes]byte) C.crypto_stream_chacha20_keygen((*C.uchar)(&k[0])) diff --git a/crypto/stream/chacha20/crypto_stream_chacha20_test.go b/crypto/stream/chacha20/crypto_stream_chacha20_test.go index 59ad6ff..8049814 100644 --- a/crypto/stream/chacha20/crypto_stream_chacha20_test.go +++ b/crypto/stream/chacha20/crypto_stream_chacha20_test.go @@ -10,7 +10,7 @@ var TestCount = 100000 func TestChaCha20(t *testing.T) { // Test the key generation - if *GenerateKey() == (Key{}) { + if *GenerateKey() == ([KeyBytes]byte{}) { t.Error("Generated key is zero") } @@ -21,7 +21,7 @@ func TestChaCha20(t *testing.T) { // Run tests for i := 0; i < TestCount; i++ { var c, m, m2, r, d []byte - n := new(Nonce) + n := new([NonceBytes]byte) // Generate random data fm.Fuzz(&m) diff --git a/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go index c18b7a8..be36c76 100644 --- a/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go +++ b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go @@ -18,14 +18,8 @@ const ( NonceBytes int = C.crypto_stream_chacha20_ietf_NONCEBYTES ) -// Nonce represents a cryptographic nonce -type Nonce [NonceBytes]byte - -// Key represents a secret key -type Key [KeyBytes]byte - // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. -func KeyStream(c []byte, n *Nonce, k *Key) { +func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") @@ -42,10 +36,10 @@ func KeyStream(c []byte, n *Nonce, k *Key) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStream(c, m []byte, n *Nonce, k *Key) { +func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -62,10 +56,10 @@ func XORKeyStream(c, m []byte, n *Nonce, k *Key) { // XORKeyStreamIC encrypts a message `m` using a nonce `n` and a secret key `k`, // but with a block counter starting at `ic`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint32) { +func XORKeyStreamIC(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte, ic uint64) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -81,8 +75,8 @@ func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint32) { } // GenerateKey generates a secret key -func GenerateKey() *Key { - k := new(Key) +func GenerateKey() *[KeyBytes]byte { + k := new([KeyBytes]byte) C.crypto_stream_chacha20_ietf_keygen((*C.uchar)(&k[0])) diff --git a/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf_test.go b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf_test.go index f3eaaff..25af781 100644 --- a/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf_test.go +++ b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf_test.go @@ -10,7 +10,7 @@ var TestCount = 100000 func TestChaCha20IETF(t *testing.T) { // Test the key generation - if *GenerateKey() == (Key{}) { + if *GenerateKey() == ([KeyBytes]byte{}) { t.Error("Generated key is zero") } @@ -21,7 +21,7 @@ func TestChaCha20IETF(t *testing.T) { // Run tests for i := 0; i < TestCount; i++ { var c, m, m2, r, d []byte - n := new(Nonce) + n := new([NonceBytes]byte) // Generate random data fm.Fuzz(&m) diff --git a/crypto/stream/crypto_stream.go b/crypto/stream/crypto_stream.go index 60cc0d6..b511a9f 100644 --- a/crypto/stream/crypto_stream.go +++ b/crypto/stream/crypto_stream.go @@ -19,14 +19,8 @@ const ( Primitive string = C.crypto_stream_PRIMITIVE // Name of the used algorithm ) -// Nonce represents a cryptographic nonce -type Nonce [NonceBytes]byte - -// Key represents a secret key -type Key [KeyBytes]byte - // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. -func KeyStream(c []byte, n *Nonce, k *Key) { +func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") @@ -43,10 +37,10 @@ func KeyStream(c []byte, n *Nonce, k *Key) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStream(c, m []byte, n *Nonce, k *Key) { +func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -61,8 +55,8 @@ func XORKeyStream(c, m []byte, n *Nonce, k *Key) { } // GenerateKey generates a secret key -func GenerateKey() *Key { - c := new(Key) +func GenerateKey() *[KeyBytes]byte { + c := new([KeyBytes]byte) C.crypto_stream_keygen((*C.uchar)(&c[0])) diff --git a/crypto/stream/crypto_stream_test.go b/crypto/stream/crypto_stream_test.go index 9654d50..71f0844 100644 --- a/crypto/stream/crypto_stream_test.go +++ b/crypto/stream/crypto_stream_test.go @@ -15,7 +15,7 @@ func TestStream(t *testing.T) { } // Test the key generation - if *GenerateKey() == (Key{}) { + if *GenerateKey() == ([KeyBytes]byte{}) { t.Error("Generated key is zero") } @@ -26,7 +26,7 @@ func TestStream(t *testing.T) { // Run tests for i := 0; i < TestCount; i++ { var c, m, r, d []byte - n := new(Nonce) + n := new([NonceBytes]byte) // Generate random data fm.Fuzz(&m) diff --git a/crypto/stream/salsa20/crypto_stream_salsa20.go b/crypto/stream/salsa20/crypto_stream_salsa20.go index 5ef55e4..b060413 100644 --- a/crypto/stream/salsa20/crypto_stream_salsa20.go +++ b/crypto/stream/salsa20/crypto_stream_salsa20.go @@ -18,14 +18,8 @@ const ( NonceBytes int = C.crypto_stream_salsa20_NONCEBYTES ) -// Nonce represents a cryptographic nonce -type Nonce [NonceBytes]byte - -// Key represents a secret key -type Key [KeyBytes]byte - // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. -func KeyStream(c []byte, n *Nonce, k *Key) { +func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") @@ -42,10 +36,10 @@ func KeyStream(c []byte, n *Nonce, k *Key) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStream(c, m []byte, n *Nonce, k *Key) { +func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -62,10 +56,10 @@ func XORKeyStream(c, m []byte, n *Nonce, k *Key) { // XORKeyStreamIC encrypts a message `m` using a nonce `n` and a secret key `k`, // but with a block counter starting at `ic`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint64) { +func XORKeyStreamIC(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte, ic uint64) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -81,8 +75,8 @@ func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint64) { } // GenerateKey generates a secret key -func GenerateKey() *Key { - k := new(Key) +func GenerateKey() *[KeyBytes]byte { + k := new([KeyBytes]byte) C.crypto_stream_salsa20_keygen((*C.uchar)(&k[0])) diff --git a/crypto/stream/salsa20/crypto_stream_salsa20_test.go b/crypto/stream/salsa20/crypto_stream_salsa20_test.go index 5928335..c3a15c7 100644 --- a/crypto/stream/salsa20/crypto_stream_salsa20_test.go +++ b/crypto/stream/salsa20/crypto_stream_salsa20_test.go @@ -10,7 +10,7 @@ var TestCount = 100000 func TestSalsa20(t *testing.T) { // Test the key generation - if *GenerateKey() == (Key{}) { + if *GenerateKey() == ([KeyBytes]byte{}) { t.Error("Generated key is zero") } @@ -21,7 +21,7 @@ func TestSalsa20(t *testing.T) { // Run tests for i := 0; i < TestCount; i++ { var c, m, m2, r, d []byte - n := new(Nonce) + n := new([NonceBytes]byte) // Generate random data fm.Fuzz(&m) diff --git a/crypto/stream/salsa2012/crypto_stream_salsa2012.go b/crypto/stream/salsa2012/crypto_stream_salsa2012.go index b885902..48fa29d 100644 --- a/crypto/stream/salsa2012/crypto_stream_salsa2012.go +++ b/crypto/stream/salsa2012/crypto_stream_salsa2012.go @@ -18,14 +18,8 @@ const ( NonceBytes int = C.crypto_stream_salsa2012_NONCEBYTES ) -// Nonce represents a cryptographic nonce -type Nonce [NonceBytes]byte - -// Key represents a secret key -type Key [KeyBytes]byte - // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. -func KeyStream(c []byte, n *Nonce, k *Key) { +func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") @@ -42,10 +36,10 @@ func KeyStream(c []byte, n *Nonce, k *Key) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStream(c, m []byte, n *Nonce, k *Key) { +func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -60,8 +54,8 @@ func XORKeyStream(c, m []byte, n *Nonce, k *Key) { } // GenerateKey generates a secret key -func GenerateKey() *Key { - k := new(Key) +func GenerateKey() *[KeyBytes]byte { + k := new([KeyBytes]byte) C.crypto_stream_salsa2012_keygen((*C.uchar)(&k[0])) diff --git a/crypto/stream/salsa2012/crypto_stream_salsa2012_test.go b/crypto/stream/salsa2012/crypto_stream_salsa2012_test.go index 267aedc..d41435a 100644 --- a/crypto/stream/salsa2012/crypto_stream_salsa2012_test.go +++ b/crypto/stream/salsa2012/crypto_stream_salsa2012_test.go @@ -10,7 +10,7 @@ var TestCount = 100000 func TestSalsa2012(t *testing.T) { // Test the key generation - if *GenerateKey() == (Key{}) { + if *GenerateKey() == ([KeyBytes]byte{}) { t.Error("Generated key is zero") } @@ -20,8 +20,8 @@ func TestSalsa2012(t *testing.T) { // Run tests for i := 0; i < TestCount; i++ { - var c, m, r, d []byte - n := new(Nonce) + var c, m, m2, r, d []byte + n := new([NonceBytes]byte) // Generate random data fm.Fuzz(&m) @@ -47,8 +47,10 @@ func TestSalsa2012(t *testing.T) { } // Check if in-place encryption works - XORKeyStream(m, m, n, k) - if !bytes.Equal(c, m) { + m2 = make([]byte, len(m)) + copy(m2, m) + XORKeyStream(m2, m2, n, k) + if !bytes.Equal(c, m2) { t.Errorf("In place encryption failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } diff --git a/crypto/stream/salsa208/crypto_stream_salsa208.go b/crypto/stream/salsa208/crypto_stream_salsa208.go index 00a2665..6b16899 100644 --- a/crypto/stream/salsa208/crypto_stream_salsa208.go +++ b/crypto/stream/salsa208/crypto_stream_salsa208.go @@ -18,14 +18,8 @@ const ( NonceBytes int = C.crypto_stream_salsa208_NONCEBYTES ) -// Nonce represents a cryptographic nonce -type Nonce [NonceBytes]byte - -// Key represents a secret key -type Key [KeyBytes]byte - // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. -func KeyStream(c []byte, n *Nonce, k *Key) { +func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") @@ -42,10 +36,10 @@ func KeyStream(c []byte, n *Nonce, k *Key) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStream(c, m []byte, n *Nonce, k *Key) { +func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -60,8 +54,8 @@ func XORKeyStream(c, m []byte, n *Nonce, k *Key) { } // GenerateKey generates a secret key -func GenerateKey() *Key { - k := new(Key) +func GenerateKey() *[KeyBytes]byte { + k := new([KeyBytes]byte) C.crypto_stream_salsa208_keygen((*C.uchar)(&k[0])) diff --git a/crypto/stream/salsa208/crypto_stream_salsa208_test.go b/crypto/stream/salsa208/crypto_stream_salsa208_test.go index 272e18d..997fc7e 100644 --- a/crypto/stream/salsa208/crypto_stream_salsa208_test.go +++ b/crypto/stream/salsa208/crypto_stream_salsa208_test.go @@ -10,7 +10,7 @@ var TestCount = 100000 func TestSalsa208(t *testing.T) { // Test the key generation - if *GenerateKey() == (Key{}) { + if *GenerateKey() == ([KeyBytes]byte{}) { t.Error("Generated key is zero") } @@ -20,8 +20,8 @@ func TestSalsa208(t *testing.T) { // Run tests for i := 0; i < TestCount; i++ { - var c, m, r, d []byte - n := new(Nonce) + var c, m, m2, r, d []byte + n := new([NonceBytes]byte) // Generate random data fm.Fuzz(&m) @@ -47,8 +47,10 @@ func TestSalsa208(t *testing.T) { } // Check if in-place encryption works - XORKeyStream(m, m, n, k) - if !bytes.Equal(c, m) { + m2 = make([]byte, len(m)) + copy(m2, m) + XORKeyStream(m2, m2, n, k) + if !bytes.Equal(c, m2) { t.Errorf("In place encryption failed for m: %x, n: %x, k: %x", m, n, k) t.FailNow() } diff --git a/crypto/stream/xchacha20/crypto_stream_xchacha20.go b/crypto/stream/xchacha20/crypto_stream_xchacha20.go index 8eef7ed..2a26b4d 100644 --- a/crypto/stream/xchacha20/crypto_stream_xchacha20.go +++ b/crypto/stream/xchacha20/crypto_stream_xchacha20.go @@ -18,14 +18,8 @@ const ( NonceBytes int = C.crypto_stream_xchacha20_NONCEBYTES ) -// Nonce represents a cryptographic nonce -type Nonce [NonceBytes]byte - -// Key represents a secret key -type Key [KeyBytes]byte - // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. -func KeyStream(c []byte, n *Nonce, k *Key) { +func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") @@ -42,10 +36,10 @@ func KeyStream(c []byte, n *Nonce, k *Key) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStream(c, m []byte, n *Nonce, k *Key) { +func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -62,10 +56,10 @@ func XORKeyStream(c, m []byte, n *Nonce, k *Key) { // XORKeyStreamIC encrypts a message `m` using a nonce `n` and a secret key `k`, // but with a block counter starting at `ic`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint64) { +func XORKeyStreamIC(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte, ic uint64) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -81,8 +75,8 @@ func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint64) { } // GenerateKey generates a secret key -func GenerateKey() *Key { - k := new(Key) +func GenerateKey() *[KeyBytes]byte { + k := new([KeyBytes]byte) C.crypto_stream_xchacha20_keygen((*C.uchar)(&k[0])) diff --git a/crypto/stream/xchacha20/crypto_stream_xchacha20_test.go b/crypto/stream/xchacha20/crypto_stream_xchacha20_test.go index b590c47..1326079 100644 --- a/crypto/stream/xchacha20/crypto_stream_xchacha20_test.go +++ b/crypto/stream/xchacha20/crypto_stream_xchacha20_test.go @@ -10,7 +10,7 @@ var TestCount = 100000 func TestXChaCha20(t *testing.T) { // Test the key generation - if *GenerateKey() == (Key{}) { + if *GenerateKey() == ([KeyBytes]byte{}) { t.Error("Generated key is zero") } @@ -21,7 +21,7 @@ func TestXChaCha20(t *testing.T) { // Run tests for i := 0; i < TestCount; i++ { var c, m, m2, r, d []byte - n := new(Nonce) + n := new([NonceBytes]byte) // Generate random data fm.Fuzz(&m) diff --git a/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go b/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go index 8d781d5..1390cb1 100644 --- a/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go +++ b/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go @@ -18,14 +18,8 @@ const ( NonceBytes int = C.crypto_stream_xsalsa20_NONCEBYTES ) -// Nonce represents a cryptographic nonce -type Nonce [NonceBytes]byte - -// Key represents a secret key -type Key [KeyBytes]byte - // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. -func KeyStream(c []byte, n *Nonce, k *Key) { +func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") @@ -42,10 +36,10 @@ func KeyStream(c []byte, n *Nonce, k *Key) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStream(c, m []byte, n *Nonce, k *Key) { +func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -62,10 +56,10 @@ func XORKeyStream(c, m []byte, n *Nonce, k *Key) { // XORKeyStreamIC encrypts a message `m` using a nonce `n` and a secret key `k`, // but with a block counter starting at `ic`. // If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint64) { +func XORKeyStreamIC(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte, ic uint64) { support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") - support.CheckSizeSmaller(c, m, "output", "input") + support.CheckSizeGreaterOrEqual(c, m, "output", "input") if len(c) == 0 { return @@ -81,8 +75,8 @@ func XORKeyStreamIC(c, m []byte, n *Nonce, k *Key, ic uint64) { } // GenerateKey generates a secret key -func GenerateKey() *Key { - k := new(Key) +func GenerateKey() *[KeyBytes]byte { + k := new([KeyBytes]byte) C.crypto_stream_xsalsa20_keygen((*C.uchar)(&k[0])) diff --git a/crypto/stream/xsalsa20/crypto_stream_xsalsa20_test.go b/crypto/stream/xsalsa20/crypto_stream_xsalsa20_test.go index 3f796cd..f1bf7a1 100644 --- a/crypto/stream/xsalsa20/crypto_stream_xsalsa20_test.go +++ b/crypto/stream/xsalsa20/crypto_stream_xsalsa20_test.go @@ -10,7 +10,7 @@ var TestCount = 100000 func TestXSalsa20(t *testing.T) { // Test the key generation - if *GenerateKey() == (Key{}) { + if *GenerateKey() == ([KeyBytes]byte{}) { t.Error("Generated key is zero") } @@ -21,7 +21,7 @@ func TestXSalsa20(t *testing.T) { // Run tests for i := 0; i < TestCount; i++ { var c, m, m2, r, d []byte - n := new(Nonce) + n := new([NonceBytes]byte) // Generate random data fm.Fuzz(&m) From ea9921d75a65fafe5765f59c1b538267385edc05 Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Mon, 23 Oct 2017 20:18:39 +0200 Subject: [PATCH 5/6] Add CheckSizeMax support function --- support/support.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/support/support.go b/support/support.go index a3eeb90..886ab2c 100644 --- a/support/support.go +++ b/support/support.go @@ -18,7 +18,15 @@ func CheckSize(buf []byte, expected int, descrip string) { // and panics when this is not the case. func CheckSizeMin(buf []byte, min int, descrip string) { if len(buf) < min { - panic(fmt.Sprintf("Incorrect %s buffer size, expected (>%d), got (%d).", descrip, min, len(buf))) + panic(fmt.Sprintf("Incorrect %s buffer size, expected (>=%d), got (%d).", descrip, min, len(buf))) + } +} + +// CheckSizeMax checks if the length of a byte slice is less or equal than a minimum length, +// and panics when this is not the case. +func CheckSizeMax(buf []byte, max uint64, descrip string) { + if uint64(len(buf)) > max { + panic(fmt.Sprintf("Incorrect %s buffer size, expected (<=%d), got (%d).", descrip, max, len(buf))) } } From e3abafc95c0a9e21214c5c4646015ea1cdb8b08d Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Mon, 23 Oct 2017 20:19:46 +0200 Subject: [PATCH 6/6] Update crypto/stream to libsodium 10.0.15 - Add message length checks - Remove Salsa208 as it is deprecated --- .../stream/chacha20/crypto_stream_chacha20.go | 7 ++- .../crypto_stream_chacha20_ietf.go | 7 ++- crypto/stream/crypto_stream.go | 8 ++- .../stream/salsa20/crypto_stream_salsa20.go | 7 ++- .../salsa2012/crypto_stream_salsa2012.go | 6 +- .../stream/salsa208/crypto_stream_salsa208.go | 63 ------------------- .../salsa208/crypto_stream_salsa208_test.go | 58 ----------------- .../xchacha20/crypto_stream_xchacha20.go | 7 ++- .../stream/xsalsa20/crypto_stream_xsalsa20.go | 7 ++- 9 files changed, 34 insertions(+), 136 deletions(-) delete mode 100644 crypto/stream/salsa208/crypto_stream_salsa208.go delete mode 100644 crypto/stream/salsa208/crypto_stream_salsa208_test.go diff --git a/crypto/stream/chacha20/crypto_stream_chacha20.go b/crypto/stream/chacha20/crypto_stream_chacha20.go index 4784b4c..f9ca00f 100644 --- a/crypto/stream/chacha20/crypto_stream_chacha20.go +++ b/crypto/stream/chacha20/crypto_stream_chacha20.go @@ -14,8 +14,9 @@ func init() { // Required length of secret key and nonce const ( - KeyBytes int = C.crypto_stream_chacha20_KEYBYTES - NonceBytes int = C.crypto_stream_chacha20_NONCEBYTES + KeyBytes = C.crypto_stream_chacha20_KEYBYTES + NonceBytes = C.crypto_stream_chacha20_NONCEBYTES + MessageBytesMax = C.crypto_stream_chacha20_MESSAGEBYTES_MAX ) // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. @@ -37,6 +38,7 @@ func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { + support.CheckSizeMax(m, MessageBytesMax, "message") support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") support.CheckSizeGreaterOrEqual(c, m, "output", "input") @@ -57,6 +59,7 @@ func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { // but with a block counter starting at `ic`. // If `m` and `c` are the same slice, in-place encryption is performed. func XORKeyStreamIC(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte, ic uint64) { + support.CheckSizeMax(m, MessageBytesMax, "message") support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") support.CheckSizeGreaterOrEqual(c, m, "output", "input") diff --git a/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go index be36c76..58db5c5 100644 --- a/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go +++ b/crypto/stream/chacha20ietf/crypto_stream_chacha20_ietf.go @@ -14,8 +14,9 @@ func init() { // Required length of secret key and nonce const ( - KeyBytes int = C.crypto_stream_chacha20_ietf_KEYBYTES - NonceBytes int = C.crypto_stream_chacha20_ietf_NONCEBYTES + KeyBytes = C.crypto_stream_chacha20_ietf_KEYBYTES + NonceBytes = C.crypto_stream_chacha20_ietf_NONCEBYTES + MessageBytesMax = C.crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX ) // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. @@ -37,6 +38,7 @@ func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { + support.CheckSizeMax(m, MessageBytesMax, "message") support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") support.CheckSizeGreaterOrEqual(c, m, "output", "input") @@ -57,6 +59,7 @@ func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { // but with a block counter starting at `ic`. // If `m` and `c` are the same slice, in-place encryption is performed. func XORKeyStreamIC(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte, ic uint64) { + support.CheckSizeMax(m, MessageBytesMax, "message") support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") support.CheckSizeGreaterOrEqual(c, m, "output", "input") diff --git a/crypto/stream/crypto_stream.go b/crypto/stream/crypto_stream.go index b511a9f..1298dae 100644 --- a/crypto/stream/crypto_stream.go +++ b/crypto/stream/crypto_stream.go @@ -14,9 +14,10 @@ func init() { // Stream byte lengths and algorithm name const ( - KeyBytes int = C.crypto_stream_KEYBYTES // Length of a secret key - NonceBytes int = C.crypto_stream_NONCEBYTES // Length of a nonce - Primitive string = C.crypto_stream_PRIMITIVE // Name of the used algorithm + KeyBytes = C.crypto_stream_KEYBYTES // Length of a secret key + NonceBytes = C.crypto_stream_NONCEBYTES // Length of a nonce + MessageBytesMax = C.crypto_stream_MESSAGEBYTES_MAX // Maximum length of a message + Primitive = C.crypto_stream_PRIMITIVE // Name of the used algorithm ) // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. @@ -38,6 +39,7 @@ func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { + support.CheckSizeMax(m, MessageBytesMax, "message") support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") support.CheckSizeGreaterOrEqual(c, m, "output", "input") diff --git a/crypto/stream/salsa20/crypto_stream_salsa20.go b/crypto/stream/salsa20/crypto_stream_salsa20.go index b060413..bedb114 100644 --- a/crypto/stream/salsa20/crypto_stream_salsa20.go +++ b/crypto/stream/salsa20/crypto_stream_salsa20.go @@ -14,8 +14,9 @@ func init() { // Required length of secret key and nonce const ( - KeyBytes int = C.crypto_stream_salsa20_KEYBYTES - NonceBytes int = C.crypto_stream_salsa20_NONCEBYTES + KeyBytes = C.crypto_stream_salsa20_KEYBYTES + NonceBytes = C.crypto_stream_salsa20_NONCEBYTES + MessageBytesMax = C.crypto_stream_salsa20_MESSAGEBYTES_MAX ) // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. @@ -37,6 +38,7 @@ func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { + support.CheckSizeMax(m, MessageBytesMax, "message") support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") support.CheckSizeGreaterOrEqual(c, m, "output", "input") @@ -57,6 +59,7 @@ func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { // but with a block counter starting at `ic`. // If `m` and `c` are the same slice, in-place encryption is performed. func XORKeyStreamIC(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte, ic uint64) { + support.CheckSizeMax(m, MessageBytesMax, "message") support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") support.CheckSizeGreaterOrEqual(c, m, "output", "input") diff --git a/crypto/stream/salsa2012/crypto_stream_salsa2012.go b/crypto/stream/salsa2012/crypto_stream_salsa2012.go index 48fa29d..628ee31 100644 --- a/crypto/stream/salsa2012/crypto_stream_salsa2012.go +++ b/crypto/stream/salsa2012/crypto_stream_salsa2012.go @@ -14,8 +14,9 @@ func init() { // Required length of secret key and nonce const ( - KeyBytes int = C.crypto_stream_salsa2012_KEYBYTES - NonceBytes int = C.crypto_stream_salsa2012_NONCEBYTES + KeyBytes = C.crypto_stream_salsa2012_KEYBYTES + NonceBytes = C.crypto_stream_salsa2012_NONCEBYTES + MessageBytesMax = C.crypto_stream_salsa2012_MESSAGEBYTES_MAX ) // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. @@ -37,6 +38,7 @@ func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { + support.CheckSizeMax(m, MessageBytesMax, "message") support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") support.CheckSizeGreaterOrEqual(c, m, "output", "input") diff --git a/crypto/stream/salsa208/crypto_stream_salsa208.go b/crypto/stream/salsa208/crypto_stream_salsa208.go deleted file mode 100644 index 6b16899..0000000 --- a/crypto/stream/salsa208/crypto_stream_salsa208.go +++ /dev/null @@ -1,63 +0,0 @@ -// Package salsa208 contains the libsodium bindings for the Salsa20 stream cipher reduced to 8 rounds. -package salsa208 - -// #cgo pkg-config: libsodium -// #include -// #include -import "C" -import "github.com/GoKillers/libsodium-go/support" - -// Sodium should always be initialised -func init() { - C.sodium_init() -} - -// Required length of secret key and nonce -const ( - KeyBytes int = C.crypto_stream_salsa208_KEYBYTES - NonceBytes int = C.crypto_stream_salsa208_NONCEBYTES -) - -// KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. -func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { - support.NilPanic(n == nil, "nonce") - support.NilPanic(k == nil, "key") - - if len(c) == 0 { - return - } - - C.crypto_stream_salsa208( - (*C.uchar)(&c[0]), - (C.ulonglong)(len(c)), - (*C.uchar)(&n[0]), - (*C.uchar)(&k[0])) -} - -// XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. -// If `m` and `c` are the same slice, in-place encryption is performed. -func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { - support.NilPanic(n == nil, "nonce") - support.NilPanic(k == nil, "key") - support.CheckSizeGreaterOrEqual(c, m, "output", "input") - - if len(c) == 0 { - return - } - - C.crypto_stream_salsa208_xor( - (*C.uchar)(&c[0]), - (*C.uchar)(&m[0]), - (C.ulonglong)(len(m)), - (*C.uchar)(&n[0]), - (*C.uchar)(&k[0])) -} - -// GenerateKey generates a secret key -func GenerateKey() *[KeyBytes]byte { - k := new([KeyBytes]byte) - - C.crypto_stream_salsa208_keygen((*C.uchar)(&k[0])) - - return k -} diff --git a/crypto/stream/salsa208/crypto_stream_salsa208_test.go b/crypto/stream/salsa208/crypto_stream_salsa208_test.go deleted file mode 100644 index 997fc7e..0000000 --- a/crypto/stream/salsa208/crypto_stream_salsa208_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package salsa208 - -import ( - "bytes" - "github.com/google/gofuzz" - "testing" -) - -var TestCount = 100000 - -func TestSalsa208(t *testing.T) { - // Test the key generation - if *GenerateKey() == ([KeyBytes]byte{}) { - t.Error("Generated key is zero") - } - - // Fuzzing - fm := fuzz.New() - fn := fuzz.New().NilChance(0) - - // Run tests - for i := 0; i < TestCount; i++ { - var c, m, m2, r, d []byte - n := new([NonceBytes]byte) - - // Generate random data - fm.Fuzz(&m) - fn.Fuzz(&n) - k := GenerateKey() - - // Generate pseudo-random data - r = make([]byte, len(m)) - KeyStream(r, n, k) - - // Perform XOR - d = make([]byte, len(m)) - for i := range r { - d[i] = r[i] ^ m[i] - } - - // Generate a ciphertext - c = make([]byte, len(m)) - XORKeyStream(c, m, n, k) - if !bytes.Equal(c, d) { - t.Errorf("Encryption failed for m: %x, n: %x, k: %x", m, n, k) - t.FailNow() - } - - // Check if in-place encryption works - m2 = make([]byte, len(m)) - copy(m2, m) - XORKeyStream(m2, m2, n, k) - if !bytes.Equal(c, m2) { - t.Errorf("In place encryption failed for m: %x, n: %x, k: %x", m, n, k) - t.FailNow() - } - } -} diff --git a/crypto/stream/xchacha20/crypto_stream_xchacha20.go b/crypto/stream/xchacha20/crypto_stream_xchacha20.go index 2a26b4d..c90c4c3 100644 --- a/crypto/stream/xchacha20/crypto_stream_xchacha20.go +++ b/crypto/stream/xchacha20/crypto_stream_xchacha20.go @@ -14,8 +14,9 @@ func init() { // Required length of secret key and nonce const ( - KeyBytes int = C.crypto_stream_xchacha20_KEYBYTES - NonceBytes int = C.crypto_stream_xchacha20_NONCEBYTES + KeyBytes = C.crypto_stream_xchacha20_KEYBYTES + NonceBytes = C.crypto_stream_xchacha20_NONCEBYTES + MessageBytesMax = C.crypto_stream_xchacha20_MESSAGEBYTES_MAX ) // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. @@ -37,6 +38,7 @@ func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { + support.CheckSizeMax(m, MessageBytesMax, "message") support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") support.CheckSizeGreaterOrEqual(c, m, "output", "input") @@ -57,6 +59,7 @@ func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { // but with a block counter starting at `ic`. // If `m` and `c` are the same slice, in-place encryption is performed. func XORKeyStreamIC(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte, ic uint64) { + support.CheckSizeMax(m, MessageBytesMax, "message") support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") support.CheckSizeGreaterOrEqual(c, m, "output", "input") diff --git a/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go b/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go index 1390cb1..3e1b0d8 100644 --- a/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go +++ b/crypto/stream/xsalsa20/crypto_stream_xsalsa20.go @@ -14,8 +14,9 @@ func init() { // Required length of secret key and nonce const ( - KeyBytes int = C.crypto_stream_xsalsa20_KEYBYTES - NonceBytes int = C.crypto_stream_xsalsa20_NONCEBYTES + KeyBytes = C.crypto_stream_xsalsa20_KEYBYTES + NonceBytes = C.crypto_stream_xsalsa20_NONCEBYTES + MessageBytesMax = C.crypto_stream_xsalsa20_MESSAGEBYTES_MAX ) // KeyStream fills an output buffer `c` with pseudo random bytes using a nonce `n` and a secret key `k`. @@ -37,6 +38,7 @@ func KeyStream(c []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { // XORKeyStream encrypts a message `m` using a nonce `n` and a secret key `k` and puts the resulting ciphertext into `c`. // If `m` and `c` are the same slice, in-place encryption is performed. func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { + support.CheckSizeMax(m, MessageBytesMax, "message") support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") support.CheckSizeGreaterOrEqual(c, m, "output", "input") @@ -57,6 +59,7 @@ func XORKeyStream(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte) { // but with a block counter starting at `ic`. // If `m` and `c` are the same slice, in-place encryption is performed. func XORKeyStreamIC(c, m []byte, n *[NonceBytes]byte, k *[KeyBytes]byte, ic uint64) { + support.CheckSizeMax(m, MessageBytesMax, "message") support.NilPanic(n == nil, "nonce") support.NilPanic(k == nil, "key") support.CheckSizeGreaterOrEqual(c, m, "output", "input")