versia-go/pkg/lysand/signature.go
2024-08-13 01:18:14 +02:00

71 lines
1.7 KiB
Go

package lysand
import (
"crypto/ed25519"
"encoding/base64"
"fmt"
"net/url"
"strings"
"time"
)
type SignatureData struct {
RequestMethod string
Date time.Time
Host string
Path string
Digest []byte
}
func NewSignatureData(method string, date time.Time, host, path string, digest []byte) *SignatureData {
return &SignatureData{
RequestMethod: method,
Date: date,
Host: host,
Path: path,
Digest: digest,
}
}
func (s *SignatureData) String() string {
return strings.Join([]string{
fmt.Sprintf("(request-target): %s %s", strings.ToLower(s.RequestMethod), s.Path),
fmt.Sprintf("host: %s", s.Host),
fmt.Sprintf("date: %s", TimeFromStd(s.Date).String()),
fmt.Sprintf("digest: SHA-256=%s", base64.StdEncoding.EncodeToString(s.Digest)),
"",
}, "\n")
}
func (s *SignatureData) Validate(pubKey ed25519.PublicKey, signature []byte) bool {
return ed25519.Verify(pubKey, []byte(s.String()), signature)
}
func (s *SignatureData) Sign(privKey ed25519.PrivateKey) []byte {
return ed25519.Sign(privKey, []byte(s.String()))
}
type Signer struct {
PrivateKey ed25519.PrivateKey
UserURL *url.URL
}
func (s Signer) Sign(signatureData SignatureData) *SignatureHeader {
return &SignatureHeader{
KeyID: s.UserURL,
Algorithm: "ed25519",
Headers: "(request-target) host date digest",
Signature: signatureData.Sign(s.PrivateKey),
}
}
type Verifier struct {
PublicKey ed25519.PublicKey
}
func (v Verifier) Verify(method string, date time.Time, host, path string, body []byte, sigHeader *SignatureHeader) bool {
sigData := NewSignatureData(method, date, host, path, hashSHA256(body))
return sigData.Validate(v.PublicKey, sigHeader.Signature)
}