diff --git a/crypto/signature/signature.go b/crypto/signature/signature.go new file mode 100644 index 0000000..5cf1a21 --- /dev/null +++ b/crypto/signature/signature.go @@ -0,0 +1,69 @@ +package signature + +import ( + "fmt" + sign "golang.org/x/crypto/nacl/sign" + rand "crypto/rand" + hex "encoding/hex" + "errors" +) + +const signatureSize = 128 + +type SignKeys struct { + Public *[32]byte + Private *[64]byte +} + +func (k *SignKeys) Generate() error { + var err error + k.Public = new([32]byte) + k.Private = new([64]byte) + k.Public, k.Private, err = sign.GenerateKey(rand.Reader) + return err +} + +func (k *SignKeys) AddHexKeys(pubHex string, privHex string) error { + if len(pubHex) < 32 || len(privHex) < 64 { + return errors.New("Wrong key size, must be pub:32 priv:64 (bytes)") + } + pubKey, err := hex.DecodeString(pubHex) + if err != nil { return err } + privKey, err := hex.DecodeString(privHex) + if err != nil { return err } + k.Public = new([32]byte) + k.Private = new([64]byte) + copy(k.Public[:],pubKey[:32]) + copy(k.Private[:],privKey[:64]) + return nil +} + +func (k *SignKeys) HexString() (string, string) { + pubHex := hex.EncodeToString(k.Public[:]) + privHex := hex.EncodeToString(k.Private[:]) + return pubHex, privHex +} + +// message is a normal string (no HexString) +func (k *SignKeys) Sign(message string) (string, error) { + if k.Private == nil { + return "", errors.New("No private key available") + } + signature := sign.Sign(nil, []byte(message), k.Private) + signHexFull := hex.EncodeToString(signature) + return signHexFull[:signatureSize], nil +} + +// message is a normal string, signature and pubHex are HexStrings +func (k *SignKeys) Verify(message, signature, pubHex string) (bool, error) { + msgHex := hex.EncodeToString([]byte(message)) + signatureAndText := fmt.Sprintf("%s%s", signature, msgHex) + signatureToVerify, err := hex.DecodeString(signatureAndText) + if err != nil { return false, err } + pubKeyToVerify, err := hex.DecodeString(pubHex) + if err != nil { return false, err } + pubKey := new([32]byte) + copy(pubKey[:],pubKeyToVerify[:32]) + _, result := sign.Open(nil, signatureToVerify, pubKey) + return result, nil +} diff --git a/crypto/signature/signature_test.go b/crypto/signature/signature_test.go new file mode 100644 index 0000000..6281581 --- /dev/null +++ b/crypto/signature/signature_test.go @@ -0,0 +1,26 @@ +package signature + +import "testing" + +func TestSignature(t *testing.T) { + t.Log("Testing signature creation and verification") + var s SignKeys + s.Generate() + pub, priv := s.HexString() + t.Logf("Generated pub:%s priv:%s\n", pub, priv) + message := "Hello, this is gonna be signed!" + t.Logf("Message to sign: %s\n", message) + msgSign, err := s.Sign(message) + if err != nil { + t.Errorf("Error while signing %s\n", err) + } + t.Logf("Signature of message: %s\n", msgSign) + v, err := s.Verify(message, msgSign, pub) + if err != nil { + t.Errorf("Verification error: %s\n", err) + } + if !v { + t.Error("Verification failed!") + } + t.Logf("Testing verification... %t\n", v) +}