...
1 package signature
2
3 import (
4 "crypto/hmac"
5 "crypto/sha512"
6 "encoding/hex"
7 "errors"
8 "strings"
9 "time"
10
11 "edge-infra.dev/pkg/edge/datasync/internal/config"
12 )
13
14 type MessageSignatureContext struct {
15 MessageID string
16 MessageType string
17 Payload []byte
18 Timestamp time.Time
19 }
20
21 func Generate(sharedKey string, secretKey string, messageContext MessageSignatureContext, organizationName string) (string, error) {
22 if sharedKey == "" || secretKey == "" {
23 return "", errors.New("failed to sign message. missing keys")
24 }
25
26 signableContent := getSignableContent(messageContext, organizationName)
27
28
29
30
31 authenticationHash := GenerateHmac(secretKey, signableContent, messageContext.Timestamp)
32
33 return sharedKey + ":" + authenticationHash, nil
34 }
35
36 func getSignableContent(messageContext MessageSignatureContext, organizationName string) string {
37 appKey := config.GetAppKey()
38
39 values := make([]string, 0)
40
41
42
43
44
45
46
47
48
49 values = append(values, appKey)
50
51 values = append(values, string(messageContext.Payload))
52 values = append(values, messageContext.MessageID)
53 values = append(values, organizationName)
54
55 valuesWithContent := make([]string, 0)
56 for _, value := range values {
57 if value != "" {
58 valuesWithContent = append(valuesWithContent, value)
59 }
60 }
61
62 signableContent := strings.Join(valuesWithContent, "\n")
63
64 return signableContent
65 }
66
67 func GenerateHmac(secretKey string, signableContent string, timestamp time.Time) string {
68 iso8601Timestamp := timestamp.Format(time.RFC3339)
69
70 uniqueKey := secretKey + iso8601Timestamp
71
72
73 h := hmac.New(sha512.New, []byte(uniqueKey))
74
75 _, err := h.Write([]byte(signableContent))
76 if err != nil {
77 return ""
78 }
79
80 sha := hex.EncodeToString(h.Sum(nil))
81
82 return sha
83 }
84
View as plain text