github.com/s7techlab/cckit@v0.10.5/extensions/encryption/state.go (about)

     1  package encryption
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  
     7  	"github.com/pkg/errors"
     8  
     9  	"github.com/s7techlab/cckit/convert"
    10  	"github.com/s7techlab/cckit/router"
    11  	"github.com/s7techlab/cckit/state"
    12  )
    13  
    14  var (
    15  	// ErrKeyNotDefinedInTransientMap occurs when key not defined in transient map
    16  	ErrKeyNotDefinedInTransientMap = errors.New(`encryption key is not defined in transient map`)
    17  )
    18  
    19  // State wrapper, encrypts the data before putting to state and
    20  // decrypts the data after getting from state
    21  func State(c router.Context, key []byte) (state.State, error) {
    22  	//current state
    23  	s := c.State()
    24  
    25  	s.UseKeyTransformer(KeyEncryptor(key))
    26  	s.UseKeyReverseTransformer(KeyDecryptor(key))
    27  	s.UseStateGetTransformer(FromBytesDecryptor(key))
    28  	s.UseStatePutTransformer(ToBytesEncryptor(key))
    29  
    30  	return s, nil
    31  }
    32  
    33  // KeyFromTransient gets key for encrypting/decrypting from transient map
    34  func KeyFromTransient(c router.Context) ([]byte, error) {
    35  	tm, err := c.Stub().GetTransient()
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	key, ok := tm[TransientMapKey]
    41  	if !ok {
    42  		return nil, ErrKeyNotDefinedInTransientMap
    43  	}
    44  
    45  	return key, nil
    46  }
    47  
    48  // StateWithTransientKey creates encrypted state state with provided key for symmetric encryption/decryption
    49  func StateWithTransientKey(c router.Context) (state.State, error) {
    50  	key, err := KeyFromTransient(c)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	return State(c, key)
    55  }
    56  
    57  // StateWithTransientKeyIfProvided creates encrypted state wrapper with provided key for symmetric encryption/decryption
    58  // if key provided, otherwise - standard state wrapper without encryption
    59  func StateWithTransientKeyIfProvided(c router.Context) (state.State, error) {
    60  	key, err := KeyFromTransient(c)
    61  	switch err {
    62  	case nil:
    63  		return State(c, key)
    64  	case ErrKeyNotDefinedInTransientMap:
    65  		//default state wrapper without encryption
    66  		return c.State(), nil
    67  	}
    68  	return nil, err
    69  }
    70  
    71  // KeyEncryptor encrypts state key
    72  func KeyEncryptor(encryptKey []byte) state.KeyTransformer {
    73  	return func(key state.Key) (state.Key, error) {
    74  		keyEnc := make(state.Key, len(key))
    75  
    76  		for i, p := range key {
    77  			keyPartEnc, err := Encrypt(encryptKey, p)
    78  			if err != nil {
    79  				return nil, fmt.Errorf(`encrypt key: %w`, err)
    80  			}
    81  			keyEnc[i] = base64.StdEncoding.EncodeToString(keyPartEnc)
    82  		}
    83  		return keyEnc, nil
    84  	}
    85  }
    86  
    87  // KeyDecryptor decrypts state key
    88  func KeyDecryptor(encryptKey []byte) state.KeyTransformer {
    89  	return func(key state.Key) (state.Key, error) {
    90  		keyEnc := make(state.Key, len(key))
    91  
    92  		for i, p := range key {
    93  			keyPartEnc, err := base64.StdEncoding.DecodeString(p)
    94  			if err != nil {
    95  				return nil, fmt.Errorf(`decrypt key base4 decode: %w`, err)
    96  			}
    97  			keyPart, err := Decrypt(encryptKey, keyPartEnc)
    98  			if err != nil {
    99  				return nil, fmt.Errorf(`decrypt key: %w`, err)
   100  			}
   101  			keyEnc[i] = string(keyPart)
   102  		}
   103  		return keyEnc, nil
   104  	}
   105  }
   106  
   107  // FromBytesDecryptor returns state.FromBytesTransformer - used for decrypting data after reading from state
   108  func FromBytesDecryptor(key []byte) state.FromBytesTransformer {
   109  	return func(bb []byte, config ...interface{}) (interface{}, error) {
   110  		decrypted, err := Decrypt(key, bb)
   111  		if err != nil {
   112  			return nil, errors.Wrap(err, `decrypt bytes`)
   113  		}
   114  		if len(config) == 0 {
   115  			return decrypted, nil
   116  		}
   117  		return convert.FromBytes(decrypted, config[0])
   118  	}
   119  }
   120  
   121  // ToBytesEncryptor returns state.ToBytesTransformer - used for encrypting data for state
   122  func ToBytesEncryptor(key []byte) state.ToBytesTransformer {
   123  	return func(v interface{}, config ...interface{}) ([]byte, error) {
   124  		bb, err := convert.ToBytes(v)
   125  		if err != nil {
   126  			return nil, err
   127  		}
   128  		return Encrypt(key, bb)
   129  	}
   130  }
   131  
   132  // EncryptWithTransientKey encrypts val with key from transient map
   133  func EncryptWithTransientKey(c router.Context, val interface{}) (encrypted []byte, err error) {
   134  	var (
   135  		key []byte
   136  	)
   137  
   138  	if key, err = KeyFromTransient(c); err != nil {
   139  		return
   140  	}
   141  
   142  	return ToBytesEncryptor(key)(val)
   143  }