package service import ( "crypto" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/pem" "fmt" "os" ) type CryptoService struct { privateKey *rsa.PrivateKey } func NewCryptoService(keyPath string) (*CryptoService, error) { data, err := os.ReadFile(keyPath) if err != nil { return nil, fmt.Errorf("read private key: %w", err) } block, _ := pem.Decode(data) if block == nil { return nil, fmt.Errorf("failed to decode PEM block") } key, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { // Try PKCS8 pkcs8Key, err2 := x509.ParsePKCS8PrivateKey(block.Bytes) if err2 != nil { return nil, fmt.Errorf("parse private key: %w", err) } var ok bool key, ok = pkcs8Key.(*rsa.PrivateKey) if !ok { return nil, fmt.Errorf("not an RSA private key") } } return &CryptoService{privateKey: key}, nil } func (s *CryptoService) Sign(data []byte) (string, error) { hash := sha256.Sum256(data) sig, err := rsa.SignPKCS1v15(rand.Reader, s.privateKey, crypto.SHA256, hash[:]) if err != nil { return "", fmt.Errorf("sign: %w", err) } return "RSA-SHA256:" + base64.StdEncoding.EncodeToString(sig), nil } func (s *CryptoService) PublicKeyPEM() (string, error) { pubBytes, err := x509.MarshalPKIXPublicKey(&s.privateKey.PublicKey) if err != nil { return "", err } block := &pem.Block{Type: "PUBLIC KEY", Bytes: pubBytes} return string(pem.EncodeToMemory(block)), nil }