signature.go 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. package security
  2. import (
  3. "crypto/hmac"
  4. "crypto/sha256"
  5. "encoding/base64"
  6. "slices"
  7. "github.com/imgproxy/imgproxy/v3/config"
  8. )
  9. func VerifySignature(signature, path string) error {
  10. if len(config.Keys) == 0 || len(config.Salts) == 0 {
  11. return nil
  12. }
  13. if slices.Contains(config.TrustedSignatures, signature) {
  14. return nil
  15. }
  16. messageMAC, err := base64.RawURLEncoding.DecodeString(signature)
  17. if err != nil {
  18. return newSignatureError("Invalid signature encoding")
  19. }
  20. for i := 0; i < len(config.Keys); i++ {
  21. if hmac.Equal(messageMAC, signatureFor(path, config.Keys[i], config.Salts[i], config.SignatureSize)) {
  22. return nil
  23. }
  24. }
  25. return newSignatureError("Invalid signature")
  26. }
  27. func signatureFor(str string, key, salt []byte, signatureSize int) []byte {
  28. mac := hmac.New(sha256.New, key)
  29. mac.Write(salt)
  30. // It's supposed that path starts with '/'. However, if and input path comes with the
  31. // leading slash split, let's re-add it here.
  32. if str[0] != '/' {
  33. mac.Write([]byte{'/'})
  34. }
  35. mac.Write([]byte(str))
  36. expectedMAC := mac.Sum(nil)
  37. if signatureSize < 32 {
  38. return expectedMAC[:signatureSize]
  39. }
  40. return expectedMAC
  41. }