-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsecurity.go
161 lines (141 loc) · 4.54 KB
/
security.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Package gopgsession provides utilities for session management and security.
package gopgsession
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"errors"
"hash"
"strings"
)
// HMACSHA256SignerPool represents a limited pool of HMAC-SHA256 signers.
// It provides thread-safe access to a pool of HMAC signers for efficient signing and verification.
type HMACSHA256SignerPool struct {
pool chan hash.Hash
secret []byte
maxSize int
}
// NewHMACSHA256SignerPool initializes a new limited pool of HMAC-SHA256 signers.
//
// Parameters:
// - secret: A byte slice containing the secret key used for HMAC operations.
// - maxPoolSize: An integer specifying the maximum number of HMAC signers to keep in the pool.
//
// Returns:
// - A pointer to a new HMACSHA256SignerPool instance.
func NewHMACSHA256SignerPool(secret []byte, maxPoolSize int) *HMACSHA256SignerPool {
return &HMACSHA256SignerPool{
secret: secret,
maxSize: maxPoolSize,
pool: make(chan hash.Hash, maxPoolSize),
}
}
// getHMAC retrieves or creates an HMAC from the pool.
//
// Returns:
// - A hash.Hash interface representing an HMAC-SHA256 instance.
// - An error if the HMAC creation fails (which is unlikely and would indicate a system-level issue).
func (s *HMACSHA256SignerPool) getHMAC() (hash.Hash, error) {
select {
case h := <-s.pool:
return h, nil
default:
return hmac.New(sha256.New, s.secret), nil
}
}
// releaseHMAC releases an HMAC back to the pool.
//
// Parameters:
// - h: A hash.Hash interface representing the HMAC-SHA256 instance to be released back to the pool.
func (s *HMACSHA256SignerPool) releaseHMAC(h hash.Hash) {
h.Reset()
select {
case s.pool <- h:
default:
// Pool is full, discard the HMAC
}
}
// Sign signs a message using a pooled HMAC.
//
// Parameters:
// - message: A byte slice containing the message to be signed.
//
// Returns:
// - A byte slice containing the HMAC signature.
// - An error if the signing process fails.
func (s *HMACSHA256SignerPool) Sign(message []byte) ([]byte, error) {
h, err := s.getHMAC()
if err != nil {
return nil, err
}
defer s.releaseHMAC(h)
h.Write(message)
return h.Sum(nil), nil
}
// Verify verifies a signed message using a pooled HMAC.
//
// Parameters:
// - message: A byte slice containing the original message that was signed.
// - signature: A byte slice containing the HMAC signature to verify.
//
// Returns:
// - A boolean indicating whether the signature is valid (true) or not (false).
func (s *HMACSHA256SignerPool) Verify(message, signature []byte) bool {
h, err := s.getHMAC()
if err != nil {
return false
}
defer s.releaseHMAC(h)
h.Write(message)
expectedSignature := h.Sum(nil)
return hmac.Equal(expectedSignature, signature)
}
// SignAndEncode signs a message and encodes it with the signature.
//
// Parameters:
// - message: A string containing the message to be signed.
//
// Returns:
// - A string containing the base64-encoded message and HMAC signature, separated by a delimiter.
// - An error if the signing process fails.
func (s *HMACSHA256SignerPool) SignAndEncode(message string) (string, error) {
signature, err := s.Sign([]byte(message))
if err != nil {
return "", err
}
// Encode message and signature separately
encodedMessage := base64.StdEncoding.EncodeToString([]byte(message))
encodedSignature := base64.StdEncoding.EncodeToString(signature)
// Combine encoded message and signature
return encodedMessage + "." + encodedSignature, nil
}
// VerifyAndDecode verifies a signed and encoded message and returns the original message.
//
// Parameters:
// - signedMessage: A string containing the base64-encoded message and HMAC signature.
//
// Returns:
// - A boolean indicating whether the signature is valid (true) or not (false).
// - A string containing the original message.
// - An error if the verification process fails.
func (s *HMACSHA256SignerPool) VerifyAndDecode(signedMessage string) (bool, string, error) {
// Split the combined message and signature
parts := strings.Split(signedMessage, ".")
if len(parts) != 2 {
return false, "", errors.New("invalid signed message format")
}
encodedMessage, encodedSignature := parts[0], parts[1]
// Decode the message
messageBytes, err := base64.StdEncoding.DecodeString(encodedMessage)
if err != nil {
return false, "", err
}
// Decode the signature
signatureBytes, err := base64.StdEncoding.DecodeString(encodedSignature)
if err != nil {
return false, "", err
}
// Verify the signature
isValid := s.Verify(messageBytes, signatureBytes)
return isValid, string(messageBytes), nil
}