Skip to content

Commit

Permalink
Merge pull request #24 from silkeh/crypto_aead_aes256gcm_test
Browse files Browse the repository at this point in the history
Add, test and fix CryptoAEADAES256GCM functions
  • Loading branch information
redragonx authored May 22, 2017
2 parents 66848fb + eada2c4 commit 7b76856
Show file tree
Hide file tree
Showing 3 changed files with 293 additions and 21 deletions.
197 changes: 176 additions & 21 deletions cryptoaead/crypto_aead_aes256gcm.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@ package cryptoaead
// #include <stdlib.h>
// #include <sodium.h>
import "C"
import "github.com/GoKillers/libsodium-go/support"
import (
"github.com/GoKillers/libsodium-go/support"
"unsafe"
)

func CryptoAEADAES256GCMIsAvailable() bool {
C.sodium_init()
return int(C.crypto_aead_aes256gcm_is_available()) != 0
}

func CryptoAEADAES256GCMKeyBytes() int {
return int(C.crypto_aead_aes256gcm_keybytes())
}

func CryptoAEADAES256GCMNSecBytes() int {
return int(C.crypto_aead_aes256gcm_keybytes())
return int(C.crypto_aead_aes256gcm_nsecbytes())
}

func CryptoAEADAES256GCMNPubBytes() int {
Expand All @@ -26,47 +34,194 @@ func CryptoAEADAES256GCMStateBytes() int {
return int(C.crypto_aead_aes256gcm_statebytes())
}

func CryptoAESAES256GCMIsAvailable() int {
return int(C.crypto_aead_aes256gcm_is_available())
}

func CryptoAEADAES256GCMEncrypt(m []byte, ad []byte, nsec []byte, npub []byte, k []byte) ([]byte, int) {
func CryptoAEADAES256GCMEncrypt(m, ad, npub, k []byte) ([]byte, int) {
support.CheckSize(k, CryptoAEADAES256GCMKeyBytes(), "secret key")
support.CheckSize(npub, CryptoAEADAES256GCMNPubBytes(), "public nonce")

c := make([]byte, len(m)+CryptoAEADAES256GCMABytes())
cLen := len(c)
cLenLongLong := (C.ulonglong(cLen))
cLen := C.ulonglong(len(c))

exit := int(C.crypto_aead_aes256gcm_encrypt(
(*C.uchar)(&c[0]),
&cLenLongLong,
(*C.uchar)(&m[0]),
(*C.uchar)(support.BytePointer(c)),
(*C.ulonglong)(&cLen),
(*C.uchar)(support.BytePointer(m)),
(C.ulonglong)(len(m)),
(*C.uchar)(&ad[0]),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(&nsec[0]),
(*C.uchar)(nil),
(*C.uchar)(&npub[0]),
(*C.uchar)(&k[0])))

return c, exit
}

func CryptoAEADAES256GCMDecrypt(nsec []byte, c []byte, ad []byte, npub []byte, k []byte) ([]byte, int) {
func CryptoAEADAES256GCMDecrypt(c, ad, npub, k []byte) ([]byte, int) {
support.CheckSize(k, CryptoAEADAES256GCMKeyBytes(), "secret key")
support.CheckSize(npub, CryptoAEADAES256GCMNPubBytes(), "public nonce")
support.CheckSizeMin(c, CryptoAEADAES256GCMABytes(), "ciphertext")

m := make([]byte, len(c)-CryptoAEADAES256GCMABytes())
mLen := len(m)
mLenLongLong := (C.ulonglong)(mLen)
mLen := (C.ulonglong)(len(m))

exit := int(C.crypto_aead_aes256gcm_decrypt(
(*C.uchar)(&m[0]),
&mLenLongLong,
(*C.uchar)(&nsec[0]),
(*C.uchar)(support.BytePointer(m)),
(*C.ulonglong)(&mLen),
(*C.uchar)(nil),
(*C.uchar)(&c[0]),
(C.ulonglong)(len(c)),
(*C.uchar)(&ad[0]),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(&npub[0]),
(*C.uchar)(&k[0])))

return m, exit
}

func CryptoAEADAES256GCMEncryptDetached(m, ad, npub, k []byte) ([]byte, []byte, int) {
support.CheckSize(k, CryptoAEADAES256GCMKeyBytes(), "secret key")
support.CheckSize(npub, CryptoAEADAES256GCMNPubBytes(), "public nonce")

c := make([]byte, len(m))
mac := make([]byte , CryptoAEADAES256GCMABytes())
macLen := C.ulonglong(len(c))

exit := int(C.crypto_aead_aes256gcm_encrypt_detached(
(*C.uchar)(support.BytePointer(c)),
(*C.uchar)(&mac[0]),
(*C.ulonglong)(&macLen),
(*C.uchar)(support.BytePointer(m)),
(C.ulonglong)(len(m)),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(nil),
(*C.uchar)(&npub[0]),
(*C.uchar)(&k[0])))

return c, mac, exit
}

func CryptoAEADAES256GCMDecryptDetached(c, mac, ad, npub, k []byte) ([]byte, int) {
support.CheckSize(k, CryptoAEADAES256GCMKeyBytes(), "secret key")
support.CheckSize(npub, CryptoAEADAES256GCMNPubBytes(), "public nonce")
support.CheckSize(mac, CryptoAEADAES256GCMABytes(), "mac")

m := make([]byte, len(c))

exit := int(C.crypto_aead_aes256gcm_decrypt_detached(
(*C.uchar)(support.BytePointer(m)),
(*C.uchar)(nil),
(*C.uchar)(support.BytePointer(c)),
(C.ulonglong)(len(c)),
(*C.uchar)(&mac[0]),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(&npub[0]),
(*C.uchar)(&k[0])))

return m, exit
}

func CryptoAEADAES256GCMBeforeNM(k []byte) ([]byte, int) {
support.CheckSize(k, CryptoAEADAES256GCMKeyBytes(), "secret key")

ctx := make([]byte, CryptoAEADAES256GCMStateBytes())

exit := int(C.crypto_aead_aes256gcm_beforenm(
(*C.crypto_aead_aes256gcm_state)(unsafe.Pointer(&ctx[0])),
(*C.uchar)(&k[0])))

return ctx, exit
}

func CryptoAEADAES256GCMEncryptAfterNM(m, ad, npub, ctx []byte) ([]byte, int) {
support.CheckSize(ctx, CryptoAEADAES256GCMStateBytes(), "context")
support.CheckSize(npub, CryptoAEADAES256GCMNPubBytes(), "public nonce")

c := make([]byte, len(m)+CryptoAEADAES256GCMABytes())
cLen := C.ulonglong(len(c))

exit := int(C.crypto_aead_aes256gcm_encrypt_afternm(
(*C.uchar)(support.BytePointer(c)),
(*C.ulonglong)(&cLen),
(*C.uchar)(support.BytePointer(m)),
(C.ulonglong)(len(m)),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(nil),
(*C.uchar)(&npub[0]),
(*[512]C.uchar)(unsafe.Pointer(&ctx[0]))))

return c, exit
}

func CryptoAEADAES256GCMDecryptAfterNM(c, ad, npub, ctx []byte) ([]byte, int) {
support.CheckSize(ctx, CryptoAEADAES256GCMStateBytes(), "context")
support.CheckSize(npub, CryptoAEADAES256GCMNPubBytes(), "public nonce")
support.CheckSizeMin(c, CryptoAEADAES256GCMABytes(), "ciphertext")

m := make([]byte, len(c)-CryptoAEADAES256GCMABytes())
mLen := (C.ulonglong)(len(m))

exit := int(C.crypto_aead_aes256gcm_decrypt_afternm(
(*C.uchar)(support.BytePointer(m)),
(*C.ulonglong)(&mLen),
(*C.uchar)(nil),
(*C.uchar)(&c[0]),
(C.ulonglong)(len(c)),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(&npub[0]),
(*[512]C.uchar)(unsafe.Pointer(&ctx[0]))))

return m, exit
}

func CryptoAEADAES256GCMEncryptDetachedAfterNM(m, ad, npub, ctx []byte) ([]byte, []byte, int) {
support.CheckSize(ctx, CryptoAEADAES256GCMStateBytes(), "context")
support.CheckSize(npub, CryptoAEADAES256GCMNPubBytes(), "public nonce")

c := make([]byte, len(m))
mac := make([]byte , CryptoAEADAES256GCMABytes())
macLen := C.ulonglong(len(c))

exit := int(C.crypto_aead_aes256gcm_encrypt_detached_afternm(
(*C.uchar)(support.BytePointer(c)),
(*C.uchar)(&mac[0]),
(*C.ulonglong)(&macLen),
(*C.uchar)(support.BytePointer(m)),
(C.ulonglong)(len(m)),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(nil),
(*C.uchar)(&npub[0]),
(*[512]C.uchar)(unsafe.Pointer(&ctx[0]))))

return c, mac, exit
}

func CryptoAEADAES256GCMDecryptDetachedAfterNM(c, mac, ad, npub, ctx []byte) ([]byte, int) {
support.CheckSize(ctx, CryptoAEADAES256GCMStateBytes(), "context")
support.CheckSize(npub, CryptoAEADAES256GCMNPubBytes(), "public nonce")
support.CheckSize(mac, CryptoAEADAES256GCMABytes(), "mac")

m := make([]byte, len(c))

exit := int(C.crypto_aead_aes256gcm_decrypt_detached_afternm(
(*C.uchar)(support.BytePointer(m)),
(*C.uchar)(nil),
(*C.uchar)(support.BytePointer(c)),
(C.ulonglong)(len(c)),
(*C.uchar)(&mac[0]),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(&npub[0]),
(*[512]C.uchar)(unsafe.Pointer(&ctx[0]))))

return m, exit
}

func CryptoAEADAES256GCMKeyGen() []byte {
k := make([]byte, CryptoAEADAES256GCMKeyBytes())
C.crypto_aead_aes256gcm_keygen((*C.uchar)(&k[0]))
return k
}
103 changes: 103 additions & 0 deletions cryptoaead/crypto_aead_aes256gcm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package cryptoaead

import (
"testing"
"bytes"
"github.com/google/gofuzz"
)

var testCount = 100000

type Test struct {
Message []byte
Ad []byte
Key [32]byte
Nonce [12]byte
Ciphertext []byte
Mac []byte
}

func TestCryptoAEADAES256GCM(t *testing.T) {
// Skip the test if unsupported on this platform
if !CryptoAEADAES256GCMIsAvailable() {
t.Skip("The CPU does not support this implementation of AES256GCM.")
}

// Test the key generation
if len(CryptoAEADAES256GCMKeyGen()) != CryptoAEADAES256GCMKeyBytes() {
t.Error("Generated key has the wrong length")
}

// Test the length of NSecBytes
if CryptoAEADAES256GCMNSecBytes() != 0 {
t.Errorf("CryptoAEADAES256GCMNSecBytes is %v but should be %v", CryptoAEADAES256GCMNSecBytes(), 0)
}

// Fuzzing
f := fuzz.New()

// Run tests
for i := 0; i < testCount; i++ {
var c, m, ec, mac []byte
var err int
var test Test

// Fuzz the test struct
f.Fuzz(&test)

// Create a key context
ctx, err := CryptoAEADAES256GCMBeforeNM(test.Key[:])
if err != 0 {
t.Error("Context creation failed for %+v", test)
}

// Detached encryption test
test.Ciphertext, test.Mac, err = CryptoAEADAES256GCMEncryptDetached(test.Message, test.Ad, test.Nonce[:], test.Key[:])
if err != 0 {
t.Errorf("Detached encryption failed for %+v", test)
}

// Detached encryption with context
c, mac, err = CryptoAEADAES256GCMEncryptDetachedAfterNM(test.Message, test.Ad, test.Nonce[:], ctx)
if err != 0 || !bytes.Equal(c, test.Ciphertext) || !bytes.Equal(mac, test.Mac) {
t.Errorf("Detached encryption with context failed for %+v", test)
}

// Encryption test
ec, err = CryptoAEADAES256GCMEncrypt(test.Message, test.Ad, test.Nonce[:], test.Key[:])
if err != 0 || !bytes.Equal(ec, append(test.Ciphertext, test.Mac...)) {
t.Errorf("Encryption failed for %+v", test)
}

// Encryption with context
ec, err = CryptoAEADAES256GCMEncryptAfterNM(test.Message, test.Ad, test.Nonce[:], ctx)
if err != 0 || !bytes.Equal(ec, append(test.Ciphertext, test.Mac...)) {
t.Errorf("Encryption with context failed for %+v", test)
}

// Detached decryption test
m, err = CryptoAEADAES256GCMDecryptDetached(c, mac, test.Ad, test.Nonce[:], test.Key[:])
if err != 0 || !bytes.Equal(m, test.Message) {
t.Errorf("Detached decryption failed for %+v", test)
}

// Detached decryption with context test
m, err = CryptoAEADAES256GCMDecryptDetachedAfterNM(c, mac, test.Ad, test.Nonce[:], ctx)
if err != 0 || !bytes.Equal(m, test.Message) {
t.Errorf("Detached decryption with context failed for %+v", test)
}

// Decryption test
m, err = CryptoAEADAES256GCMDecrypt(ec, test.Ad, test.Nonce[:], test.Key[:])
if err != 0 || !bytes.Equal(m, test.Message) {
t.Errorf("Decryption failed for %+v", test)
}

// Decryption with context test
m, err = CryptoAEADAES256GCMDecryptAfterNM(ec, test.Ad, test.Nonce[:], ctx)
if err != 0 || !bytes.Equal(m, test.Message) {
t.Errorf("Decryption with context failed for %+v", test)
}
}
t.Logf("Completed %v tests", testCount)
}
14 changes: 14 additions & 0 deletions support/support.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,22 @@ func CheckSize(buf []byte, expected int, descrip string) {
}
}

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)))
}
}

func CheckSizeInRange(size int, min int, max int, descrip string) {
if size < min || size > max {
panic(fmt.Sprintf("Incorrect %s buffer size, expected (%d - %d), got (%d).", descrip, min, max, size))
}
}

func BytePointer(b []byte) *uint8 {
if len(b) > 0 {
return &b[0]
} else {
return nil
}
}

0 comments on commit 7b76856

Please sign in to comment.