2016-01-28 15:11:54 -05:00
|
|
|
package crypto
|
|
|
|
|
2016-01-29 08:36:04 -05:00
|
|
|
/*
|
|
|
|
#cgo pkg-config: libsodium
|
|
|
|
#include <sodium.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
*/
|
|
|
|
import "C"
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/sha512"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
2016-01-28 15:11:54 -05:00
|
|
|
type Ed25519PublicKey [32]byte
|
2016-01-29 08:36:04 -05:00
|
|
|
|
|
|
|
type Ed25519Verifier struct {
|
|
|
|
k [32]C.uchar
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k Ed25519PublicKey) NewVerifier() (v Verifier, err error) {
|
|
|
|
ev := new(Ed25519Verifier)
|
|
|
|
for i, b := range k {
|
|
|
|
ev.k[i] = C.uchar(b)
|
|
|
|
}
|
|
|
|
v = ev
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Ed25519Verifier) VerifyHash(h, sig []byte) (err error) {
|
|
|
|
if len(sig) == C.crypto_sign_BYTES {
|
|
|
|
// valid size of sig
|
|
|
|
// copy signature and hash
|
|
|
|
var csig, ch [32]C.uchar
|
|
|
|
for i, b := range h {
|
|
|
|
ch[i] = C.uchar(b)
|
|
|
|
}
|
|
|
|
for i, b := range sig {
|
|
|
|
csig[i] = C.uchar(b)
|
|
|
|
}
|
|
|
|
// verify
|
|
|
|
if C.crypto_sign_verify_detached(&csig[0], &ch[0], C.ulonglong(32), &v.k[0]) == 0 {
|
|
|
|
// valid signature
|
|
|
|
} else {
|
|
|
|
// bad signature
|
|
|
|
err = ErrInvalidSignature
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// bad size of sig
|
|
|
|
err = ErrBadSignatureSize
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Ed25519Verifier) Verify(data, sig []byte) (err error) {
|
|
|
|
h := sha512.Sum512(data)
|
|
|
|
err = v.VerifyHash(h[:], sig)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-01-28 15:11:54 -05:00
|
|
|
type Ed25519PrivateKey [32]byte
|
2016-01-29 08:36:04 -05:00
|
|
|
|
|
|
|
type Ed25519Signer struct {
|
|
|
|
k [32]C.uchar
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Ed25519Signer) Sign(data []byte) (sig []byte, err error) {
|
|
|
|
h := sha512.Sum512(data)
|
|
|
|
sig, err = s.SignHash(h[:])
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Ed25519Signer) SignHash(h []byte) (sig []byte, err error) {
|
|
|
|
var ch [32]C.uchar
|
|
|
|
for i, b := range h {
|
|
|
|
ch[i] = C.uchar(b)
|
|
|
|
}
|
|
|
|
var csig [32]C.uchar
|
|
|
|
var smlen_p C.ulonglong
|
|
|
|
res := C.crypto_sign_detached(&csig[0], &smlen_p, &ch[0], C.ulonglong(32), &s.k[0])
|
|
|
|
if res == 0 {
|
|
|
|
// success signing
|
|
|
|
sig = make([]byte, 32)
|
|
|
|
for i, b := range csig {
|
|
|
|
sig[i] = byte(b)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// failed signing
|
|
|
|
err = errors.New(fmt.Sprintf("failed to sign: crypto_sign_detached exit code %d", int(res)))
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|