github.com/opentofu/opentofu@v1.7.1/internal/encryption/keyprovider/pbkdf2/config.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package pbkdf2
     7  
     8  import (
     9  	"fmt"
    10  	"hash"
    11  	"io"
    12  
    13  	"github.com/opentofu/opentofu/internal/encryption/keyprovider"
    14  )
    15  
    16  // HashFunction is a provider of a hash.Hash.
    17  type HashFunction func() hash.Hash
    18  
    19  // HashFunctionName describes a hash function to use for PBKDF2 hash generation. While you could theoretically supply
    20  // your own from outside the package, please don't do that. Include your hash function in this package. (Thanks Go for
    21  // the lack of visibility constraints.)
    22  type HashFunctionName string
    23  
    24  // Validate checks if the specified hash function name is valid.
    25  func (h HashFunctionName) Validate() error {
    26  	if h == "" {
    27  		return &keyprovider.ErrInvalidConfiguration{Message: "please specify a hash function"}
    28  	}
    29  	if _, ok := hashFunctions[h]; !ok {
    30  		return &keyprovider.ErrInvalidConfiguration{Message: fmt.Sprintf("invalid hash function name: %s", h)}
    31  	}
    32  	return nil
    33  }
    34  
    35  // Function returns the underlying hash function for the name.
    36  func (h HashFunctionName) Function() HashFunction {
    37  	return hashFunctions[h]
    38  }
    39  
    40  type Config struct {
    41  	// Set by the descriptor.
    42  	randomSource io.Reader
    43  
    44  	Passphrase   string           `hcl:"passphrase"`
    45  	KeyLength    int              `hcl:"key_length,optional"`
    46  	Iterations   int              `hcl:"iterations,optional"`
    47  	HashFunction HashFunctionName `hcl:"hash_function,optional"`
    48  	SaltLength   int              `hcl:"salt_length,optional"`
    49  }
    50  
    51  // WithPassphrase adds the passphrase and returns the same config for chaining.
    52  func (c *Config) WithPassphrase(passphrase string) *Config {
    53  	c.Passphrase = passphrase
    54  	return c
    55  }
    56  
    57  // WithKeyLength sets the key length and returns the same config for chaining
    58  func (c *Config) WithKeyLength(length int) *Config {
    59  	c.KeyLength = length
    60  	return c
    61  }
    62  
    63  // WithIterations sets the iterations and returns the same config for chaining
    64  func (c *Config) WithIterations(iterations int) *Config {
    65  	c.Iterations = iterations
    66  	return c
    67  }
    68  
    69  // WithSaltLength sets the salt length and returns the same config for chaining
    70  func (c *Config) WithSaltLength(length int) *Config {
    71  	c.SaltLength = length
    72  	return c
    73  }
    74  
    75  // WithHashFunction sets the hash function and returns the same config for chaining
    76  func (c *Config) WithHashFunction(hashFunction HashFunctionName) *Config {
    77  	c.HashFunction = hashFunction
    78  	return c
    79  }
    80  
    81  func (c *Config) Build() (keyprovider.KeyProvider, keyprovider.KeyMeta, error) {
    82  	if c.randomSource == nil {
    83  		return nil, nil, &keyprovider.ErrInvalidConfiguration{
    84  			Message: "missing randomness source (please don't initialize the Config struct directly, use the descriptor)",
    85  		}
    86  	}
    87  
    88  	if c.Passphrase == "" {
    89  		return nil, nil, &keyprovider.ErrInvalidConfiguration{
    90  			Message: "no passphrase provided",
    91  		}
    92  	}
    93  
    94  	if len(c.Passphrase) < MinimumPassphraseLength {
    95  		return nil, nil, &keyprovider.ErrInvalidConfiguration{
    96  			Message: fmt.Sprintf("passphrase is too short (minimum %d characters)", MinimumPassphraseLength),
    97  		}
    98  	}
    99  
   100  	if c.KeyLength <= 0 {
   101  		return nil, nil, &keyprovider.ErrInvalidConfiguration{
   102  			Message: "the key length must be larger than zero",
   103  		}
   104  	}
   105  
   106  	if c.Iterations <= 0 {
   107  		return nil, nil, &keyprovider.ErrInvalidConfiguration{
   108  			Message: "the number of iterations must be larger than zero",
   109  		}
   110  	}
   111  	if c.Iterations < MinimumIterations {
   112  		return nil, nil, &keyprovider.ErrInvalidConfiguration{
   113  			Message: fmt.Sprintf("the number of iterations is dangerously low (<%d), refusing to generate key", MinimumIterations),
   114  		}
   115  	}
   116  
   117  	if c.SaltLength <= 0 {
   118  		return nil, nil, &keyprovider.ErrInvalidConfiguration{
   119  			Message: "the salt length must be larger than zero",
   120  		}
   121  	}
   122  
   123  	if err := c.HashFunction.Validate(); err != nil {
   124  		return nil, nil, &keyprovider.ErrInvalidConfiguration{
   125  			Cause: err,
   126  		}
   127  	}
   128  
   129  	return &pbkdf2KeyProvider{*c}, new(Metadata), nil
   130  }