github.com/unionj-cloud/go-doudou/v2@v2.3.5/toolkit/memberlist/keyring.go (about)

     1  package memberlist
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"sync"
     7  )
     8  
     9  type Keyring struct {
    10  	// Keys stores the key data used during encryption and decryption. It is
    11  	// ordered in such a way where the first key (index 0) is the primary key,
    12  	// which is used for encrypting messages, and is the first key tried during
    13  	// message decryption.
    14  	keys [][]byte
    15  
    16  	// The keyring lock is used while performing IO operations on the keyring.
    17  	l sync.Mutex
    18  }
    19  
    20  // Init allocates substructures
    21  func (k *Keyring) init() {
    22  	k.keys = make([][]byte, 0)
    23  }
    24  
    25  // NewKeyring constructs a new container for a set of encryption keys. The
    26  // keyring contains all key data used internally by memberlist.
    27  //
    28  // While creating a new keyring, you must do one of:
    29  //   - Omit keys and primary key, effectively disabling encryption
    30  //   - Pass a set of keys plus the primary key
    31  //   - Pass only a primary key
    32  //
    33  // If only a primary key is passed, then it will be automatically added to the
    34  // keyring. If creating a keyring with multiple keys, one key must be designated
    35  // primary by passing it as the primaryKey. If the primaryKey does not exist in
    36  // the list of secondary keys, it will be automatically added at position 0.
    37  //
    38  // A key should be either 16, 24, or 32 bytes to select AES-128,
    39  // AES-192, or AES-256.
    40  func NewKeyring(keys [][]byte, primaryKey []byte) (*Keyring, error) {
    41  	keyring := &Keyring{}
    42  	keyring.init()
    43  
    44  	if len(keys) > 0 || len(primaryKey) > 0 {
    45  		if len(primaryKey) == 0 {
    46  			return nil, fmt.Errorf("Empty primary key not allowed")
    47  		}
    48  		if err := keyring.AddKey(primaryKey); err != nil {
    49  			return nil, err
    50  		}
    51  		for _, key := range keys {
    52  			if err := keyring.AddKey(key); err != nil {
    53  				return nil, err
    54  			}
    55  		}
    56  	}
    57  
    58  	return keyring, nil
    59  }
    60  
    61  // ValidateKey will check to see if the key is valid and returns an error if not.
    62  //
    63  // key should be either 16, 24, or 32 bytes to select AES-128,
    64  // AES-192, or AES-256.
    65  func ValidateKey(key []byte) error {
    66  	if l := len(key); l != 16 && l != 24 && l != 32 {
    67  		return fmt.Errorf("key size must be 16, 24 or 32 bytes")
    68  	}
    69  	return nil
    70  }
    71  
    72  // AddKey will install a new key on the ring. Adding a key to the ring will make
    73  // it available for use in decryption. If the key already exists on the ring,
    74  // this function will just return noop.
    75  //
    76  // key should be either 16, 24, or 32 bytes to select AES-128,
    77  // AES-192, or AES-256.
    78  func (k *Keyring) AddKey(key []byte) error {
    79  	if err := ValidateKey(key); err != nil {
    80  		return err
    81  	}
    82  
    83  	// No-op if key is already installed
    84  	for _, installedKey := range k.keys {
    85  		if bytes.Equal(installedKey, key) {
    86  			return nil
    87  		}
    88  	}
    89  
    90  	keys := append(k.keys, key)
    91  	primaryKey := k.GetPrimaryKey()
    92  	if primaryKey == nil {
    93  		primaryKey = key
    94  	}
    95  	k.installKeys(keys, primaryKey)
    96  	return nil
    97  }
    98  
    99  // UseKey changes the key used to encrypt messages. This is the only key used to
   100  // encrypt messages, so peers should know this key before this method is called.
   101  func (k *Keyring) UseKey(key []byte) error {
   102  	for _, installedKey := range k.keys {
   103  		if bytes.Equal(key, installedKey) {
   104  			k.installKeys(k.keys, key)
   105  			return nil
   106  		}
   107  	}
   108  	return fmt.Errorf("Requested key is not in the keyring")
   109  }
   110  
   111  // RemoveKey drops a key from the keyring. This will return an error if the key
   112  // requested for removal is currently at position 0 (primary key).
   113  func (k *Keyring) RemoveKey(key []byte) error {
   114  	if bytes.Equal(key, k.keys[0]) {
   115  		return fmt.Errorf("Removing the primary key is not allowed")
   116  	}
   117  	for i, installedKey := range k.keys {
   118  		if bytes.Equal(key, installedKey) {
   119  			keys := append(k.keys[:i], k.keys[i+1:]...)
   120  			k.installKeys(keys, k.keys[0])
   121  		}
   122  	}
   123  	return nil
   124  }
   125  
   126  // installKeys will take out a lock on the keyring, and replace the keys with a
   127  // new set of keys. The key indicated by primaryKey will be installed as the new
   128  // primary key.
   129  func (k *Keyring) installKeys(keys [][]byte, primaryKey []byte) {
   130  	k.l.Lock()
   131  	defer k.l.Unlock()
   132  
   133  	newKeys := [][]byte{primaryKey}
   134  	for _, key := range keys {
   135  		if !bytes.Equal(key, primaryKey) {
   136  			newKeys = append(newKeys, key)
   137  		}
   138  	}
   139  	k.keys = newKeys
   140  }
   141  
   142  // GetKeys returns the current set of keys on the ring.
   143  func (k *Keyring) GetKeys() [][]byte {
   144  	k.l.Lock()
   145  	defer k.l.Unlock()
   146  
   147  	return k.keys
   148  }
   149  
   150  // GetPrimaryKey returns the key on the ring at position 0. This is the key used
   151  // for encrypting messages, and is the first key tried for decrypting messages.
   152  func (k *Keyring) GetPrimaryKey() (key []byte) {
   153  	k.l.Lock()
   154  	defer k.l.Unlock()
   155  
   156  	if len(k.keys) > 0 {
   157  		key = k.keys[0]
   158  	}
   159  	return
   160  }