forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 0
/
salt.go
164 lines (139 loc) · 4.05 KB
/
salt.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
162
163
164
package salt
import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"encoding/hex"
"fmt"
"hash"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/vault/logical"
)
const (
// DefaultLocation is the path in the view we store our key salt
// if no other path is provided.
DefaultLocation = "salt"
)
// Salt is used to manage a persistent salt key which is used to
// hash values. This allows keys to be generated and recovered
// using the global salt. Primarily, this allows paths in the storage
// backend to be obfuscated if they may contain sensitive information.
type Salt struct {
config *Config
salt string
generated bool
hmacType string
}
type HashFunc func([]byte) []byte
// Config is used to parameterize the Salt
type Config struct {
// Location is the path in the storage backend for the
// salt. Uses DefaultLocation if not specified.
Location string
// HashFunc is the hashing function to use for salting.
// Defaults to SHA1 if not provided.
HashFunc HashFunc
// HMAC allows specification of a hash function to use for
// the HMAC helpers
HMAC func() hash.Hash
// String prepended to HMAC strings for identification.
// Required if using HMAC
HMACType string
}
// NewSalt creates a new salt based on the configuration
func NewSalt(view logical.Storage, config *Config) (*Salt, error) {
// Setup the configuration
if config == nil {
config = &Config{}
}
if config.Location == "" {
config.Location = DefaultLocation
}
if config.HashFunc == nil {
config.HashFunc = SHA256Hash
}
// Create the salt
s := &Salt{
config: config,
}
// Look for the salt
raw, err := view.Get(config.Location)
if err != nil {
return nil, fmt.Errorf("failed to read salt: %v", err)
}
// Restore the salt if it exists
if raw != nil {
s.salt = string(raw.Value)
}
// Generate a new salt if necessary
if s.salt == "" {
s.salt, err = uuid.GenerateUUID()
if err != nil {
return nil, fmt.Errorf("failed to generate uuid: %v", err)
}
s.generated = true
if view != nil {
raw := &logical.StorageEntry{
Key: config.Location,
Value: []byte(s.salt),
}
if err := view.Put(raw); err != nil {
return nil, fmt.Errorf("failed to persist salt: %v", err)
}
}
}
if config.HMAC != nil {
if len(config.HMACType) == 0 {
return nil, fmt.Errorf("HMACType must be defined")
}
s.hmacType = config.HMACType
}
return s, nil
}
// SaltID is used to apply a salt and hash function to an ID to make sure
// it is not reversible
func (s *Salt) SaltID(id string) string {
return SaltID(s.salt, id, s.config.HashFunc)
}
// GetHMAC is used to apply a salt and hash function to data to make sure it is
// not reversible, with an additional HMAC
func (s *Salt) GetHMAC(data string) string {
hm := hmac.New(s.config.HMAC, []byte(s.salt))
hm.Write([]byte(data))
return hex.EncodeToString(hm.Sum(nil))
}
// GetIdentifiedHMAC is used to apply a salt and hash function to data to make
// sure it is not reversible, with an additional HMAC, and ID prepended
func (s *Salt) GetIdentifiedHMAC(data string) string {
return s.hmacType + ":" + s.GetHMAC(data)
}
// DidGenerate returns if the underlying salt value was generated
// on initialization or if an existing salt value was loaded
func (s *Salt) DidGenerate() bool {
return s.generated
}
// SaltID is used to apply a salt and hash function to an ID to make sure
// it is not reversible
func SaltID(salt, id string, hash HashFunc) string {
comb := salt + id
hashVal := hash([]byte(comb))
return hex.EncodeToString(hashVal)
}
func HMACValue(salt, val string, hashFunc func() hash.Hash) string {
hm := hmac.New(hashFunc, []byte(salt))
hm.Write([]byte(val))
return hex.EncodeToString(hm.Sum(nil))
}
func HMACIdentifiedValue(salt, val, hmacType string, hashFunc func() hash.Hash) string {
return hmacType + ":" + HMACValue(salt, val, hashFunc)
}
// SHA1Hash returns the SHA1 of the input
func SHA1Hash(inp []byte) []byte {
hashed := sha1.Sum(inp)
return hashed[:]
}
// SHA256Hash returns the SHA256 of the input
func SHA256Hash(inp []byte) []byte {
hashed := sha256.Sum256(inp)
return hashed[:]
}