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

WIP: Crypto box #34

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
284 changes: 284 additions & 0 deletions crypto/box/crypto_box.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
// Package box contains the libsodium bindings for public-key authenticated encryption.
//
// Note that the message length is not checked against MessageBytesMax,
// as this is based on SODIUM_SIZE_MAX, which is the minimum of UINT64_MAX and SIZE_MAX.
// Both can be expected to be higher than the maximum size of an integer and byte slice.
package box

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

// Lengths of various arguments.
const (
SeedBytes = C.crypto_box_SEEDBYTES // Required size of a keypair seed.
PublicKeyBytes = C.crypto_box_PUBLICKEYBYTES // Size of a public key.
SecretKeyBytes = C.crypto_box_SECRETKEYBYTES // Size of a secret key.
NonceBytes = C.crypto_box_NONCEBYTES // Size of a nonce.
MACBytes = C.crypto_box_MACBYTES // Size of an authentication tag.
Primitive = C.crypto_box_PRIMITIVE // Name of the algorithm used by crypto/box.
SharedKeyBytes = C.crypto_box_BEFORENMBYTES // Size of a shared secret key.
SealBytes = C.crypto_box_SEALBYTES // Overhead of a sealed encryption.
MessageBytesMax = C.crypto_box_MESSAGEBYTES_MAX // Maximum message size.
)

// GenerateKeyFromSeed returns a keypair generated from a given seed.
func GenerateKeyFromSeed(seed *[SeedBytes]byte) (pk *[PublicKeyBytes]byte, sk *[SecretKeyBytes]byte) {
support.NilPanic(seed == nil, "seed")

pk = new([PublicKeyBytes]byte)
sk = new([SecretKeyBytes]byte)

C.crypto_box_seed_keypair(
(*C.uchar)(&pk[0]),
(*C.uchar)(&sk[0]),
(*C.uchar)(&seed[0]))

return
}

// GenerateKey returns a keypair.
func GenerateKey() (pk *[PublicKeyBytes]byte, sk *[SecretKeyBytes]byte) {
pk = new([PublicKeyBytes]byte)
sk = new([SecretKeyBytes]byte)

C.crypto_box_keypair(
(*C.uchar)(&pk[0]),
(*C.uchar)(&sk[0]))

return
}

// Precompute generates a shared key from a recipients public key `pk` and a sender's secret key `sk`.
func Precompute(pk *[PublicKeyBytes]byte, sk *[SecretKeyBytes]byte) (k *[SharedKeyBytes]byte) {
support.NilPanic(pk == nil, "public key")
support.NilPanic(sk == nil, "secret key")

k = new([SharedKeyBytes]byte)

C.crypto_box_beforenm(
(*C.uchar)(&k[0]),
(*C.uchar)(&pk[0]),
(*C.uchar)(&sk[0]))

return
}

// Seal encrypts a message `m` using nonce `n`, public key `pk` and secret key `sk`.
// Returns a ciphertext.
func Seal(m []byte, n *[NonceBytes]byte, pk *[PublicKeyBytes]byte, sk *[SecretKeyBytes]byte) (c []byte) {
support.NilPanic(n == nil, "nonce")
support.NilPanic(pk == nil, "public key")
support.NilPanic(sk == nil, "secret key")

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

C.crypto_box_easy(
(*C.uchar)(&c[0]),
(*C.uchar)(support.BytePointer(m)),
C.ulonglong(len(m)),
(*C.uchar)(&n[0]),
(*C.uchar)(&pk[0]),
(*C.uchar)(&sk[0]))

return
}

// Open decrypts a ciphertext `c` using nonce `n`, public key `pk` and secret key `sk`.
// Returns the decrypted message and an error indicating decryption or verification failure.
func Open(c []byte, n *[NonceBytes]byte, pk *[PublicKeyBytes]byte, sk *[SecretKeyBytes]byte) (m []byte, err error) {
support.CheckSizeMin(c, MACBytes, "ciphertext")
support.NilPanic(n == nil, "nonce")
support.NilPanic(pk == nil, "public key")
support.NilPanic(sk == nil, "secret key")

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

exit := C.crypto_box_open_easy(
(*C.uchar)(support.BytePointer(m)),
(*C.uchar)(&c[0]),
(C.ulonglong)(len(c)),
(*C.uchar)(&n[0]),
(*C.uchar)(&pk[0]),
(*C.uchar)(&sk[0]))

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

return
}

// SealAfterPrecomputation encrypts a message `m` with nonce `n` from a shared secret key `k`.
// Returns the encrypted message.
func SealAfterPrecomputation(m []byte, n *[NonceBytes]byte, k *[SharedKeyBytes]byte) (c []byte) {
support.NilPanic(n == nil, "nonce")
support.NilPanic(k == nil, "shared key")

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

C.crypto_box_easy_afternm(
(*C.uchar)(&c[0]),
(*C.uchar)(support.BytePointer(m)),
(C.ulonglong)(len(m)),
(*C.uchar)(&n[0]),
(*C.uchar)(&k[0]))

return
}

// OpenAfterPrecomputation decrypts a ciphertext `c` using nonce `n` from a shared secret key `k`.
// Returns the decrypted message and an error indicating decryption or verification failure.
func OpenAfterPrecomputation(c []byte, n *[NonceBytes]byte, k *[SharedKeyBytes]byte) (m []byte, err error) {
support.CheckSizeMin(c, MACBytes, "ciphertext")
support.NilPanic(n == nil, "nonce")
support.NilPanic(k == nil, "shared key")

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

exit := C.crypto_box_open_easy_afternm(
(*C.uchar)(support.BytePointer(m)),
(*C.uchar)(&c[0]),
(C.ulonglong)(len(c)),
(*C.uchar)(&n[0]),
(*C.uchar)(&k[0]))

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

return
}

// SealDetached encrypts a message `m` using nonce `n`, public key `pk` and secret key `sk`.
// Returns a ciphertext and an authentication tag.
func SealDetached(m []byte, n *[NonceBytes]byte, pk *[PublicKeyBytes]byte, sk *[SecretKeyBytes]byte) (c []byte, mac *[MACBytes]byte) {
support.NilPanic(n == nil, "nonce")
support.NilPanic(pk == nil, "public key")
support.NilPanic(sk == nil, "secret key")

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

C.crypto_box_detached(
(*C.uchar)(support.BytePointer(c)),
(*C.uchar)(&mac[0]),
(*C.uchar)(support.BytePointer(m)),
C.ulonglong(len(m)),
(*C.uchar)(&n[0]),
(*C.uchar)(&pk[0]),
(*C.uchar)(&sk[0]))

return
}

// OpenDetached decrypts a ciphertext `c` using nonce `n`, public key `pk` and secret key `sk`.
// Returns the decrypted message and an error indicating decryption or verification failure.
func OpenDetached(c []byte, mac *[MACBytes]byte, n *[NonceBytes]byte, pk *[PublicKeyBytes]byte, sk *[SecretKeyBytes]byte) (m []byte, err error) {
support.NilPanic(mac == nil, "mac")
support.NilPanic(n == nil, "nonce")
support.NilPanic(pk == nil, "public key")
support.NilPanic(sk == nil, "secret key")

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

exit := C.crypto_box_open_detached(
(*C.uchar)(support.BytePointer(m)),
(*C.uchar)(support.BytePointer(c)),
(*C.uchar)(&mac[0]),
(C.ulonglong)(len(c)),
(*C.uchar)(&n[0]),
(*C.uchar)(&pk[0]),
(*C.uchar)(&sk[0]))

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

return
}

// SealDetachedAfterPrecomputation encrypts a message `m` with nonce `n` from a shared secret key `k`.
// Returns a ciphertext and an authentication tag.
func SealDetachedAfterPrecomputation(m []byte, n *[NonceBytes]byte, k *[SharedKeyBytes]byte) (c []byte, mac *[MACBytes]byte) {
support.NilPanic(n == nil, "nonce")
support.NilPanic(k == nil, "shared key")

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

C.crypto_box_detached_afternm(
(*C.uchar)(support.BytePointer(c)),
(*C.uchar)(&mac[0]),
(*C.uchar)(support.BytePointer(m)),
(C.ulonglong)(len(m)),
(*C.uchar)(&n[0]),
(*C.uchar)(&k[0]))

return
}

// OpenDetachedAfterPrecomputation decrypts a ciphertext `c` using nonce `n` from a shared secret key `k`.
// Returns the decrypted message and an error indicating decryption or verification failure.
func OpenDetachedAfterPrecomputation(c []byte, mac *[MACBytes]byte, n *[NonceBytes]byte, k *[SharedKeyBytes]byte) (m []byte, err error) {
support.NilPanic(mac == nil, "mac")
support.NilPanic(n == nil, "nonce")
support.NilPanic(k == nil, "shared key")

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

exit := C.crypto_box_open_detached_afternm(
(*C.uchar)(support.BytePointer(m)),
(*C.uchar)(support.BytePointer(c)),
(*C.uchar)(&mac[0]),
(C.ulonglong)(len(c)),
(*C.uchar)(&n[0]),
(*C.uchar)(&k[0]))

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

return
}

// SealAnonymous encrypts a message `m` for a public key `pk` without information about the sender.
// Returns the encrypted message.
func SealAnonymous(m []byte, pk *[PublicKeyBytes]byte) (c []byte) {
support.NilPanic(pk == nil, "public key")

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

C.crypto_box_seal(
(*C.uchar)(&c[0]),
(*C.uchar)(support.BytePointer(m)),
C.ulonglong(len(m)),
(*C.uchar)(&pk[0]))

return
}

// OpenAnonymous decrypts a message `m` with public key `pk` and secret key `sk`.
// Returns the decrypted message and an error indicating decryption or verification failure.
func OpenAnonymous(c []byte, pk *[PublicKeyBytes]byte, sk *[SecretKeyBytes]byte) (m []byte, err error) {
support.CheckSizeMin(c, SealBytes, "ciphertext")
support.NilPanic(pk == nil, "public key")
support.NilPanic(sk == nil, "secret key")

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

exit := C.crypto_box_seal_open(
(*C.uchar)(support.BytePointer(m)),
(*C.uchar)(&c[0]),
(C.ulonglong)(len(c)),
(*C.uchar)(&pk[0]),
(*C.uchar)(&sk[0]))

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

return
}
105 changes: 105 additions & 0 deletions crypto/box/crypto_box_compat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package box

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

// Lengths of various arguments.
const (
ZeroBytes = C.crypto_box_ZEROBYTES // Size of the zero padding of the message.
BoxZeroBytes = C.crypto_box_BOXZEROBYTES // Size of NaCl box / ciphertext
)

// NaClSealAfterPrecomputation encrypts a message `m` with nonce `n` from a shared key `k`.
// Returns the decrypted message and a boolean indicating successful encryption.
// Note: message `m` requires `ZeroBytes` of padding on the front.
func NaClSealAfterPrecomputation(m, n []byte, k *[SharedKeyBytes]byte) (c []byte) {
support.CheckSizeMin(m, ZeroBytes, "message with padding")
support.CheckSize(n, NonceBytes, "nonce")
support.NilPanic(k == nil, "shared key")

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

C.crypto_box_afternm(
(*C.uchar)(&c[0]),
(*C.uchar)(support.BytePointer(m)),
(C.ulonglong)(len(m)),
(*C.uchar)(&n[0]),
(*C.uchar)(&k[0]))

return
}

// NaClOpenAfterPrecomputation decrypts a cyphertext `c` using nonce `n` from a shared key `k`.
// Returns the decrypted message and a boolean indicating successful decryption and verification.
// Note: ciphertext `c` requires `BoxZeroBytes` padding on the front.
func NaClOpenAfterPrecomputation(c, n []byte, k *[SharedKeyBytes]byte) (m []byte, err error) {
support.CheckSizeMin(c, ZeroBytes, "ciphertext with padding")
support.CheckSize(n, NonceBytes, "nonce")
support.NilPanic(k == nil, "shared key")

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

exit := C.crypto_box_open_afternm(
(*C.uchar)(support.BytePointer(m)),
(*C.uchar)(&c[0]),
(C.ulonglong)(len(c)),
(*C.uchar)(&n[0]),
(*C.uchar)(&k[0]))

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

return
}

// NaClSeal encrypts a message `m` using nonce `n`, public key `pk` and secret key `sk`.
// Returns a ciphertext and a boolean indicating successful encryption.
// Note: message `m` requires `ZeroBytes` of padding on the front.
func NaClSeal(m, n []byte, pk *[PublicKeyBytes]byte, sk *[SecretKeyBytes]byte) (c []byte) {
support.CheckSizeMin(m, ZeroBytes, "message with padding")
support.CheckSize(n, NonceBytes, "nonce")
support.NilPanic(pk == nil, "public key")
support.NilPanic(sk == nil, "secret key")

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

C.crypto_box(
(*C.uchar)(&c[0]),
(*C.uchar)(&m[0]),
C.ulonglong(len(m)),
(*C.uchar)(&n[0]),
(*C.uchar)(&pk[0]),
(*C.uchar)(&sk[0]))

return
}

// NaClOpen decrypts a ciphertext `c` using nonce `n`, public key `pk` and secret key `sk`.
// Returns the decrypted message and a boolean indicating successful decryption and verification.
// Note: ciphertext `c` requires `BoxZeroBytes` padding on the front.
func NaClOpen(c, n []byte, pk *[PublicKeyBytes]byte, sk *[SecretKeyBytes]byte) (m []byte, err error) {
support.CheckSizeMin(c, ZeroBytes, "ciphertext with padding")
support.CheckSize(n, NonceBytes, "nonce")
support.NilPanic(pk == nil, "public key")
support.NilPanic(sk == nil, "secret key")

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

exit := C.crypto_box_open(
(*C.uchar)(&m[0]),
(*C.uchar)(&c[0]),
(C.ulonglong)(len(c)),
(*C.uchar)(&n[0]),
(*C.uchar)(&pk[0]),
(*C.uchar)(&sk[0]))

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

return
}