forked from hashicorp/memberlist
-
Notifications
You must be signed in to change notification settings - Fork 0
/
keyring.go
160 lines (141 loc) · 4.4 KB
/
keyring.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
package memberlist
import (
"bytes"
"fmt"
"sync"
)
type Keyring struct {
// Keys stores the key data used during encryption and decryption. It is
// ordered in such a way where the first key (index 0) is the primary key,
// which is used for encrypting messages, and is the first key tried during
// message decryption.
keys [][]byte
// The keyring lock is used while performing IO operations on the keyring.
l sync.Mutex
}
// Init allocates substructures
func (k *Keyring) init() {
k.keys = make([][]byte, 0)
}
// NewKeyring constructs a new container for a set of encryption keys. The
// keyring contains all key data used internally by memberlist.
//
// While creating a new keyring, you must do one of:
// - Omit keys and primary key, effectively disabling encryption
// - Pass a set of keys plus the primary key
// - Pass only a primary key
//
// If only a primary key is passed, then it will be automatically added to the
// keyring. If creating a keyring with multiple keys, one key must be designated
// primary by passing it as the primaryKey. If the primaryKey does not exist in
// the list of secondary keys, it will be automatically added at position 0.
//
// A key should be either 16, 24, or 32 bytes to select AES-128,
// AES-192, or AES-256.
func NewKeyring(keys [][]byte, primaryKey []byte) (*Keyring, error) {
keyring := &Keyring{}
keyring.init()
if len(keys) > 0 || len(primaryKey) > 0 {
if len(primaryKey) == 0 {
return nil, fmt.Errorf("Empty primary key not allowed")
}
if err := keyring.AddKey(primaryKey); err != nil {
return nil, err
}
for _, key := range keys {
if err := keyring.AddKey(key); err != nil {
return nil, err
}
}
}
return keyring, nil
}
// ValidateKey will check to see if the key is valid and returns an error if not.
//
// key should be either 16, 24, or 32 bytes to select AES-128,
// AES-192, or AES-256.
func ValidateKey(key []byte) error {
if l := len(key); l != 16 && l != 24 && l != 32 {
return fmt.Errorf("key size must be 16, 24 or 32 bytes")
}
return nil
}
// AddKey will install a new key on the ring. Adding a key to the ring will make
// it available for use in decryption. If the key already exists on the ring,
// this function will just return noop.
//
// key should be either 16, 24, or 32 bytes to select AES-128,
// AES-192, or AES-256.
func (k *Keyring) AddKey(key []byte) error {
if err := ValidateKey(key); err != nil {
return err
}
// No-op if key is already installed
for _, installedKey := range k.keys {
if bytes.Equal(installedKey, key) {
return nil
}
}
keys := append(k.keys, key)
primaryKey := k.GetPrimaryKey()
if primaryKey == nil {
primaryKey = key
}
k.installKeys(keys, primaryKey)
return nil
}
// UseKey changes the key used to encrypt messages. This is the only key used to
// encrypt messages, so peers should know this key before this method is called.
func (k *Keyring) UseKey(key []byte) error {
for _, installedKey := range k.keys {
if bytes.Equal(key, installedKey) {
k.installKeys(k.keys, key)
return nil
}
}
return fmt.Errorf("Requested key is not in the keyring")
}
// RemoveKey drops a key from the keyring. This will return an error if the key
// requested for removal is currently at position 0 (primary key).
func (k *Keyring) RemoveKey(key []byte) error {
if bytes.Equal(key, k.keys[0]) {
return fmt.Errorf("Removing the primary key is not allowed")
}
for i, installedKey := range k.keys {
if bytes.Equal(key, installedKey) {
keys := append(k.keys[:i], k.keys[i+1:]...)
k.installKeys(keys, k.keys[0])
}
}
return nil
}
// installKeys will take out a lock on the keyring, and replace the keys with a
// new set of keys. The key indicated by primaryKey will be installed as the new
// primary key.
func (k *Keyring) installKeys(keys [][]byte, primaryKey []byte) {
k.l.Lock()
defer k.l.Unlock()
newKeys := [][]byte{primaryKey}
for _, key := range keys {
if !bytes.Equal(key, primaryKey) {
newKeys = append(newKeys, key)
}
}
k.keys = newKeys
}
// GetKeys returns the current set of keys on the ring.
func (k *Keyring) GetKeys() [][]byte {
k.l.Lock()
defer k.l.Unlock()
return k.keys
}
// GetPrimaryKey returns the key on the ring at position 0. This is the key used
// for encrypting messages, and is the first key tried for decrypting messages.
func (k *Keyring) GetPrimaryKey() (key []byte) {
k.l.Lock()
defer k.l.Unlock()
if len(k.keys) > 0 {
key = k.keys[0]
}
return
}