Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crypto aead #31

Merged
merged 5 commits into from
Oct 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions crypto/aead/aes256gcm/crypto_aead_aes256gcm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Package aes256gcm contains the libsodium bindings for AES256-GCM.
package aes256gcm

// #cgo pkg-config: libsodium
// #include <stdlib.h>
// #include <sodium.h>
import "C"
import "github.com/GoKillers/libsodium-go/support"

// Sodium should always be initialised
func init() {
C.sodium_init()
}

// Sizes of nonces, key and mac.
const (
KeyBytes int = C.crypto_aead_aes256gcm_KEYBYTES // Size of a secret key in bytes
NSecBytes int = C.crypto_aead_aes256gcm_NSECBYTES // Size of a secret nonce in bytes
NonceBytes int = C.crypto_aead_aes256gcm_NPUBBYTES // Size of a nonce in bytes
ABytes int = C.crypto_aead_aes256gcm_ABYTES // Size of an authentication tag in bytes
)

// IsAvailable returns true if AES256 is available on the current CPU
func IsAvailable() bool {
return C.crypto_aead_aes256gcm_is_available() != 0
}

// GenerateKey generates a secret key
func GenerateKey() *[KeyBytes]byte {
k := new([KeyBytes]byte)
C.crypto_aead_aes256gcm_keygen((*C.uchar)(&k[0]))
return k
}

// Encrypt a message `m` with additional data `ad` using a nonce `npub` and a secret key `k`.
// A ciphertext (including authentication tag) and encryption status are returned.
func Encrypt(m, ad []byte, nonce *[NonceBytes]byte, k *[KeyBytes]byte) (c []byte) {
support.NilPanic(k == nil, "secret key")
support.NilPanic(nonce == nil, "nonce")

c = make([]byte, len(m)+ABytes)

C.crypto_aead_aes256gcm_encrypt(
(*C.uchar)(support.BytePointer(c)),
(*C.ulonglong)(nil),
(*C.uchar)(support.BytePointer(m)),
(C.ulonglong)(len(m)),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(nil),
(*C.uchar)(&nonce[0]),
(*C.uchar)(&k[0]))

return
}

// Decrypt and verify a ciphertext `c` using additional data `ad`, nonce `npub` and secret key `k`.
// Returns the decrypted message and verification status.
func Decrypt(c, ad []byte, nonce *[NonceBytes]byte, k *[KeyBytes]byte) (m []byte, err error) {
support.NilPanic(k == nil, "secret key")
support.NilPanic(nonce == nil, "nonce")
support.CheckSizeMin(c, ABytes, "ciphertext")

m = make([]byte, len(c)-ABytes)

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

if exit != 0 {
err = &support.VerificationError{}
}

return
}

// EncryptDetached encrypts a message `m` with additional data `ad` using
// a nonce `npub` and a secret key `k`.
// A ciphertext, authentication tag and encryption status are returned.
func EncryptDetached(m, ad []byte, nonce *[NonceBytes]byte, k *[KeyBytes]byte) (c, mac []byte) {
support.NilPanic(k == nil, "secret key")
support.NilPanic(nonce == nil, "nonce")

c = make([]byte, len(m))
mac = make([]byte, ABytes)

C.crypto_aead_aes256gcm_encrypt_detached(
(*C.uchar)(support.BytePointer(c)),
(*C.uchar)(&mac[0]),
(*C.ulonglong)(nil),
(*C.uchar)(support.BytePointer(m)),
(C.ulonglong)(len(m)),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(nil),
(*C.uchar)(&nonce[0]),
(*C.uchar)(&k[0]))

return
}

// DecryptDetached decrypts and verifies a ciphertext `c` with authentication tag `mac`
// using additional data `ad`, nonce `npub` and secret key `k`.
// Returns the decrypted message and verification status.
func DecryptDetached(c, mac, ad []byte, nonce *[NonceBytes]byte, k *[KeyBytes]byte) (m []byte, err error) {
support.NilPanic(k == nil, "secret key")
support.NilPanic(nonce == nil, "nonce")
support.CheckSize(mac, ABytes, "mac")

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

exit := 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)(&nonce[0]),
(*C.uchar)(&k[0]))

if exit != 0 {
err = &support.VerificationError{}
}

return
}
87 changes: 87 additions & 0 deletions crypto/aead/aes256gcm/crypto_aead_aes256gcm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package aes256gcm

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

var testCount = 100000

type TestData struct {
Message []byte
Ad []byte
Key [KeyBytes]byte
Nonce [NonceBytes]byte
}

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

// Test the key generation
if *GenerateKey() == ([KeyBytes]byte{}) {
t.Error("Generated key is zero")
}

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

// Fuzzing
f := fuzz.New()

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

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

// Detached encryption test
c, mac = EncryptDetached(test.Message, test.Ad, &test.Nonce, &test.Key)

// Encryption test
ec = Encrypt(test.Message, test.Ad, &test.Nonce, &test.Key)
if !bytes.Equal(ec, append(c, mac...)) {
t.Errorf("Encryption failed for %+v", test)
t.FailNow()
}

// Detached decryption test
m, err = DecryptDetached(c, mac, test.Ad, &test.Nonce, &test.Key)
if err != nil || !bytes.Equal(m, test.Message) {
t.Errorf("Detached decryption failed for %+v", test)
t.FailNow()
}

// Decryption test
m, err = Decrypt(ec, test.Ad, &test.Nonce, &test.Key)
if err != nil || !bytes.Equal(m, test.Message) {
t.Errorf("Decryption failed for %+v", test)
t.FailNow()
}

// Failed detached decryption test
mac = make([]byte, ABytes)
m, err = DecryptDetached(c, mac, test.Ad, &test.Nonce, &test.Key)
if err == nil {
t.Errorf("Detached decryption unexpectedly succeeded for %+v", test)
t.FailNow()
}

// Failed decryption test
copy(ec[len(m):], mac)
m, err = Decrypt(ec, test.Ad, &test.Nonce, &test.Key)
if err == nil {
t.Errorf("Decryption unexpectedly succeeded for %+v", test)
t.FailNow()
}
}
t.Logf("Completed %v tests", testCount)
}
130 changes: 130 additions & 0 deletions crypto/aead/chacha20poly1305/crypto_aead_chacha20poly1305.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Package chacha20poly1305 contains the libsodium bindings for ChaCha20-Poly1305.
package chacha20poly1305

// #cgo pkg-config: libsodium
// #include <stdlib.h>
// #include <sodium.h>
import "C"
import "github.com/GoKillers/libsodium-go/support"

// Sodium should always be initialised
func init() {
C.sodium_init()
}

// Sizes of nonces, key and mac.
const (
KeyBytes int = C.crypto_aead_chacha20poly1305_KEYBYTES // Size of a secret key in bytes
NSecBytes int = C.crypto_aead_chacha20poly1305_NSECBYTES // Size of a secret nonce in bytes
NonceBytes int = C.crypto_aead_chacha20poly1305_NPUBBYTES // Size of a nonce in bytes
ABytes int = C.crypto_aead_chacha20poly1305_ABYTES // Size of an authentication tag in bytes
)

// GenerateKey generates a secret key
func GenerateKey() *[KeyBytes]byte {
k := new([KeyBytes]byte)
C.crypto_aead_chacha20poly1305_keygen((*C.uchar)(&k[0]))
return k
}

// Encrypt a message `m` with additional data `ad` using a nonce `npub` and a secret key `k`.
// A ciphertext (including authentication tag) and encryption status are returned.
func Encrypt(m, ad []byte, nonce *[NonceBytes]byte, k *[KeyBytes]byte) (c []byte) {
support.NilPanic(k == nil, "secret key")
support.NilPanic(nonce == nil, "nonce")

c = make([]byte, len(m)+ABytes)

C.crypto_aead_chacha20poly1305_encrypt(
(*C.uchar)(support.BytePointer(c)),
(*C.ulonglong)(nil),
(*C.uchar)(support.BytePointer(m)),
(C.ulonglong)(len(m)),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(nil),
(*C.uchar)(&nonce[0]),
(*C.uchar)(&k[0]))

return
}

// Decrypt and verify a ciphertext `c` using additional data `ad`, nonce `npub` and secret key `k`.
// Returns the decrypted message and verification status.
func Decrypt(c, ad []byte, nonce *[NonceBytes]byte, k *[KeyBytes]byte) (m []byte, err error) {
support.NilPanic(k == nil, "secret key")
support.NilPanic(nonce == nil, "nonce")
support.CheckSizeMin(c, ABytes, "ciphertext")

m = make([]byte, len(c)-ABytes)

exit := C.crypto_aead_chacha20poly1305_decrypt(
(*C.uchar)(support.BytePointer(m)),
(*C.ulonglong)(nil),
(*C.uchar)(nil),
(*C.uchar)(&c[0]),
(C.ulonglong)(len(c)),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(&nonce[0]),
(*C.uchar)(&k[0]))

if exit != 0 {
err = &support.VerificationError{}
}

return
}

// EncryptDetached encrypts a message `m` with additional data `ad` using
// a nonce `npub` and a secret key `k`.
// A ciphertext, authentication tag and encryption status are returned.
func EncryptDetached(m, ad []byte, nonce *[NonceBytes]byte, k *[KeyBytes]byte) (c, mac []byte) {
support.NilPanic(k == nil, "secret key")
support.NilPanic(nonce == nil, "nonce")

c = make([]byte, len(m))
mac = make([]byte, ABytes)

C.crypto_aead_chacha20poly1305_encrypt_detached(
(*C.uchar)(support.BytePointer(c)),
(*C.uchar)(&mac[0]),
(*C.ulonglong)(nil),
(*C.uchar)(support.BytePointer(m)),
(C.ulonglong)(len(m)),
(*C.uchar)(support.BytePointer(ad)),
(C.ulonglong)(len(ad)),
(*C.uchar)(nil),
(*C.uchar)(&nonce[0]),
(*C.uchar)(&k[0]))

return
}

// DecryptDetached decrypts and verifies a ciphertext `c` with authentication tag `mac`
// using additional data `ad`, nonce `npub` and secret key `k`.
// Returns the decrypted message and verification status.
func DecryptDetached(c, mac, ad []byte, nonce *[NonceBytes]byte, k *[KeyBytes]byte) (m []byte, err error) {
support.NilPanic(k == nil, "secret key")
support.NilPanic(nonce == nil, "nonce")
support.CheckSize(mac, ABytes, "mac")

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

exit := C.crypto_aead_chacha20poly1305_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)(&nonce[0]),
(*C.uchar)(&k[0]))

if exit != 0 {
err = &support.VerificationError{}
}

return
}
Loading