Skip to content

Commit

Permalink
Merge pull request #31 from silkeh/crypto_aead
Browse files Browse the repository at this point in the history
Crypto aead
  • Loading branch information
redragonx authored Oct 22, 2017
2 parents 757aafd + 1aaaa11 commit 272960b
Show file tree
Hide file tree
Showing 15 changed files with 1,222 additions and 14 deletions.
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

0 comments on commit 272960b

Please sign in to comment.