package v4 import ( "encoding/hex" "strings" "time" "github.com/aws/aws-sdk-go/aws/credentials" ) type credentialValueProvider interface { Get() (credentials.Value, error) } // StreamSigner implements signing of event stream encoded payloads. type StreamSigner struct { region string service string credentials credentialValueProvider prevSig []byte } // NewStreamSigner creates a SigV4 signer used to sign Event Stream encoded messages. func NewStreamSigner(region, service string, seedSignature []byte, credentials *credentials.Credentials) *StreamSigner { return &StreamSigner{ region: region, service: service, credentials: credentials, prevSig: seedSignature, } } // GetSignature takes an event stream encoded headers and payload and returns a signature. func (s *StreamSigner) GetSignature(headers, payload []byte, date time.Time) ([]byte, error) { credValue, err := s.credentials.Get() if err != nil { return nil, err } sigKey := deriveSigningKey(s.region, s.service, credValue.SecretAccessKey, date) keyPath := buildSigningScope(s.region, s.service, date) stringToSign := buildEventStreamStringToSign(headers, payload, s.prevSig, keyPath, date) signature := hmacSHA256(sigKey, []byte(stringToSign)) s.prevSig = signature return signature, nil } func buildEventStreamStringToSign(headers, payload, prevSig []byte, scope string, date time.Time) string { return strings.Join([]string{ "AWS4-HMAC-SHA256-PAYLOAD", formatTime(date), scope, hex.EncodeToString(prevSig), hex.EncodeToString(hashSHA256(headers)), hex.EncodeToString(hashSHA256(payload)), }, "\n") }