func KeyIsSuitable(key PrivateKey, pub PublicKey) bool {
	if key == nil && pub == nil {
		return false
	} else if key != nil && len(key) != privateKeySize {
		return false
	} else if pub != nil && len(pub) != publicKeySize {
		return false
	}
	return true
}
IsKeySuitable takes a private and/or public key, and returns true if
all keys passed in are valid. If no key is passed in, or any key passed
in is invalid, it will return false.
package stoutbox
import (
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha512"
	"github.com/kisom/aescrypt/strongbox"
	"math/big"
)
type PublicKey []byte
type PrivateKey []byte
const VersionString = "2.0.0"
const (
	publicKeySize  = 133
	privateKeySize = 66
	sigSize        = 140
)
const (
	BoxUnsigned     byte = 1
	BoxSigned       byte = 2
	BoxShared       byte = 11
	BoxSharedSigned byte = 12
	peerList             = 21
)
const (
	SharedKeySize  = 80
	ecdhSharedSize = 80
)
var Overhead = publicKeySize + strongbox.Overhead + 9  
var SignedOverhead = publicKeySize + strongbox.Overhead + sigSize
var PRNG = rand.Reader
var curve = elliptic.P521()
func ecdh(key PrivateKey, peer PublicKey) ([]byte, bool) {
	x, y := elliptic.Unmarshal(curve, peer)
	if x == nil {
		return nil, false
	} else if !curve.IsOnCurve(x, y) {
		return nil, false
	}
	x, _ = curve.ScalarMult(x, y, key)
	if x == nil {
		return nil, false
	}
	xb := sha512.Sum512(x.Bytes())
	skey := xb[:32]
	mkey := xb[32:]
	h := sha512.New384()
	h.Write(mkey)
	mkey = h.Sum(nil)
	return append(skey, mkey...), true
}
func SharedKey(key PrivateKey, peer PublicKey) (strongbox.Key, bool) {
	return ecdh(key, peer)
}
func GenerateKey() (PrivateKey, PublicKey, bool) {
	key, x, y, err := elliptic.GenerateKey(curve, PRNG)
	if err != nil {
		return nil, nil, false
	}
	peer := elliptic.Marshal(curve, x, y)
	if peer == nil {
	}
	if len(key) != privateKeySize || len(peer) != publicKeySize {
		return nil, nil, false
	}
	return key, peer, true
}
func sealBox(message []byte, peer PublicKey, boxtype byte) *bw {
	if message == nil {
		return nil
	} else if !KeyIsSuitable(nil, peer) {
		return nil
	}
	eph_key, eph_peer, ok := GenerateKey()
	if !ok {
		return nil
	}
	defer zero(eph_key)
	skey, ok := ecdh(eph_key, peer)
	if !ok {
		return nil
	}
	defer zero(skey)
	packer := newbw([]byte{boxtype})
	sbox, ok := strongbox.Seal(message, skey)
	if !ok {
		return nil
	}
	packer.Write(eph_peer)
	packer.Write(sbox)
	return packer
}
func Seal(message []byte, peer PublicKey) (box []byte, ok bool) {
	packer := sealBox(message, peer, BoxUnsigned)
	if packer == nil {
		ok = false
	} else {
		box = packer.Bytes()
		if box == nil {
			ok = false
		} else {
			ok = true
		}
	}
	return
}
func openBox(box []byte, key PrivateKey) (btype byte, message []byte, ok bool) {
	if box == nil {
		return 0, nil, false
	} else if !KeyIsSuitable(key, nil) {
		return 0, nil, false
	}
	btype = box[0]
	unpacker := newbr(box[1:])
	eph_pub := unpacker.Next()
	sbox := unpacker.Next()
	shared, ok := ecdh(key, eph_pub)
	if !ok {
		return 0, nil, false
	}
	message, ok = strongbox.Open(sbox, shared)
	if !ok {
		return 0, nil, false
	}
	return btype, message, true
}
func Open(box []byte, key PrivateKey) (message []byte, ok bool) {
	btype, message, ok := openBox(box, key)
	if !ok {
		return nil, false
	} else if message == nil {
		return nil, false
	} else if btype != BoxUnsigned {
		return nil, false
	}
	return message, true
}
func ecdsa_private(key PrivateKey, pub PublicKey) (skey *ecdsa.PrivateKey, ok bool) {
	x, y := elliptic.Unmarshal(curve, pub)
	if x == nil {
		return
	}
	skey = new(ecdsa.PrivateKey)
	skey.D = new(big.Int).SetBytes(key)
	skey.PublicKey.Curve = curve
	skey.X = x
	skey.Y = y
	ok = true
	return
}
func ecdsa_public(peer PublicKey) (pkey *ecdsa.PublicKey, ok bool) {
	x, y := elliptic.Unmarshal(curve, peer)
	if x == nil {
		return
	}
	pkey = &ecdsa.PublicKey{
		Curve: curve,
		X:     x,
		Y:     y,
	}
	return pkey, true
}
func Sign(message []byte, key PrivateKey, pub PublicKey) (signature []byte, ok bool) {
	if message == nil {
		return nil, false
	} else if !KeyIsSuitable(key, pub) {
		return nil, false
	}
	h := sha512.New384()
	h.Write(message)
	hash := h.Sum(nil)
	skey, ok := ecdsa_private(key, pub)
	if !ok {
		return
	}
	r, s, err := ecdsa.Sign(PRNG, skey, hash)
	if err != nil {
		ok = false
	} else {
		signature = marshalSignature(r, s)
		if signature == nil {
			ok = false
		}
	}
	return
}
func Verify(message, signature []byte, signer PublicKey) bool {
	if message == nil || signature == nil {
		return false
	} else if !KeyIsSuitable(nil, signer) {
		return false
	}
	r, s := unmarshalSignature(signature)
	if r == nil || s == nil {
		return false
	}
	h := sha512.New384()
	h.Write(message)
	pub, ok := ecdsa_public(signer)
	if !ok {
		return false
	}
	return ecdsa.Verify(pub, h.Sum(nil), r, s)
}
func SignAndSeal(message []byte, key PrivateKey, public PublicKey, peer PublicKey) (box []byte, ok bool) {
	sig, ok := Sign(message, key, public)
	if !ok || sig == nil {
		return nil, false
	}
	mpack := newbw(nil)
	mpack.Write(message)
	mpack.Write(sig)
	signedMessage := mpack.Bytes()
	if signedMessage == nil {
		return nil, false
	}
	defer zero(signedMessage)
	packer := sealBox(signedMessage, peer, BoxSigned)
	if packer == nil {
		return nil, false
	}
	box = packer.Bytes()
	if box == nil {
		return nil, false
	}
	return box, true
}
func OpenAndVerify(box []byte, key PrivateKey, peer PublicKey) (message []byte, ok bool) {
	btype, smessage, ok := openBox(box, key)
	if !ok || smessage == nil {
		return nil, false
	} else if btype != BoxSigned {
		return nil, false
	}
	mpack := newbr(smessage)
	message = mpack.Next()
	if message == nil {
		return nil, false
	}
	sig := mpack.Next()
	if sig == nil {
		return nil, false
	}
	if !Verify(message, sig, peer) {
		return nil, false
	}
	return message, true
}
func BoxIsSigned(box []byte) bool {
	if box == nil {
		return false
	} else if box[0] == BoxSigned {
		return true
	} else if box[0] == BoxSharedSigned {
		return true
	} else {
		return false
	}
}