-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #31 from silkeh/crypto_aead
Crypto aead
- Loading branch information
Showing
15 changed files
with
1,222 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
130
crypto/aead/chacha20poly1305/crypto_aead_chacha20poly1305.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.