github.com/opentofu/opentofu@v1.7.1/internal/encryption/keyprovider/pbkdf2/provider.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 contains a key provider that takes a passphrase and emits a PBKDF2 hash of the configured length.
     7  package pbkdf2
     8  
     9  import (
    10  	"fmt"
    11  	"io"
    12  
    13  	"github.com/opentofu/opentofu/internal/encryption/keyprovider"
    14  
    15  	goPBKDF2 "golang.org/x/crypto/pbkdf2"
    16  )
    17  
    18  type pbkdf2KeyProvider struct {
    19  	Config
    20  }
    21  
    22  func (p pbkdf2KeyProvider) generateMetadata() (*Metadata, error) {
    23  	// Build outMeta based on current configuration
    24  	outMeta := &Metadata{
    25  		Iterations:   p.Iterations,
    26  		HashFunction: p.HashFunction,
    27  		Salt:         make([]byte, p.SaltLength),
    28  		KeyLength:    p.KeyLength,
    29  	}
    30  	// Generate new salt
    31  	if _, err := io.ReadFull(p.randomSource, outMeta.Salt); err != nil {
    32  		return nil, &keyprovider.ErrKeyProviderFailure{
    33  			Message: fmt.Sprintf("failed to obtain %d bytes of random data", p.SaltLength),
    34  			Cause:   err,
    35  		}
    36  	}
    37  	return outMeta, nil
    38  }
    39  
    40  func (p pbkdf2KeyProvider) Provide(rawMeta keyprovider.KeyMeta) (keyprovider.Output, keyprovider.KeyMeta, error) {
    41  	if rawMeta == nil {
    42  		return keyprovider.Output{}, nil, &keyprovider.ErrInvalidMetadata{Message: "bug: no metadata struct provided"}
    43  	}
    44  	inMeta, ok := rawMeta.(*Metadata)
    45  	if !ok {
    46  		return keyprovider.Output{}, nil, &keyprovider.ErrInvalidMetadata{
    47  			Message: fmt.Sprintf("bug: incorrect metadata type of %T provided", rawMeta),
    48  		}
    49  	}
    50  
    51  	outMeta, err := p.generateMetadata()
    52  	if err != nil {
    53  		return keyprovider.Output{}, nil, err
    54  	}
    55  
    56  	var decryptionKey []byte
    57  	if inMeta.isPresent() {
    58  		if err := inMeta.validate(); err != nil {
    59  			return keyprovider.Output{}, nil, err
    60  		}
    61  		decryptionKey = goPBKDF2.Key(
    62  			[]byte(p.Passphrase),
    63  			inMeta.Salt,
    64  			inMeta.Iterations,
    65  			inMeta.KeyLength,
    66  			inMeta.HashFunction.Function(),
    67  		)
    68  	}
    69  
    70  	return keyprovider.Output{
    71  		EncryptionKey: goPBKDF2.Key(
    72  			[]byte(p.Passphrase),
    73  			outMeta.Salt,
    74  			outMeta.Iterations,
    75  			outMeta.KeyLength,
    76  			outMeta.HashFunction.Function(),
    77  		),
    78  		DecryptionKey: decryptionKey,
    79  	}, outMeta, nil
    80  }