pbkdf2

package
v1.0.0-rc5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 2, 2024 License: MPL-2.0 Imports: 9 Imported by: 0

README

PBKDF passphrase key provider

[!WARNING] This file is not an end-user documentation, it is intended for developers. Please follow the user documentation on the OpenTofu website unless you want to work on the encryption code.

This folder contains the code for the PBKDF2 passphrase key provider. The user can enter a passphrase and the key provider will generate []byte keys of a given length and will record the salt in the encryption metadata.

Configuration

You can configure this key provider by specifying the following options:

terraform {
    encryption {
        key_provider "pbkdf2" "myprovider" {
            passphrase = "enter a long and complex passphrase here"
            
            # Adapt the key length to your encryption method needs,
            # check the method documentation for the right key length
            key_length = 32
            
            # Provide the number of iterations that should be performed.
            # See https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
            # for recommendations
            iterations = 600000 
	
            # Pick the hashing function. Can be sha256 or sha512.
            hash_function = "sha512"
	        
            # Pick the salt length in bytes.
            salt_length = 32
        }
    }
}

Documentation

Overview

Package pbkdf2 contains a key provider that takes a passphrase and emits a PBKDF2 hash of the configured length.

Example (Decrypt)

This example is a bare-bones configuration for a static key provider. It is mainly intended to demonstrate how you can use parse configuration and construct a static key provider from it.

package main

import (
	"fmt"

	"github.com/terramate-io/hcl/v2/gohcl"
	"github.com/terramate-io/opentofulib/internal/encryption/keyprovider/pbkdf2"

	"github.com/terramate-io/opentofulib/internal/encryption/config"
)

var configuration = `key_provider "pbkdf2" "foo" {
  passphrase = "correct-horse-battery-staple"
}
`

// This example is a bare-bones configuration for a static key provider.
// It is mainly intended to demonstrate how you can use parse configuration
// and construct a static key provider from it.
func main() {
	configStruct := pbkdf2.New().ConfigStruct()

	// Parse the config:
	parsedConfig, diags := config.LoadConfigFromString("config.hcl", configuration)
	if diags.HasErrors() {
		panic(diags)
	}

	// Use gohcl to parse the hcl block from parsedConfig into the static configuration struct:
	if err := gohcl.DecodeBody(
		parsedConfig.KeyProviderConfigs[0].Body,
		nil,
		configStruct,
	); err != nil {
		panic(err)
	}

	// Create the actual key provider.
	keyProvider, keyMeta, err := configStruct.Build()
	if err != nil {
		panic(err)
	}

	// Fill in the metadata stored with the encrypted form:
	meta := keyMeta.(*pbkdf2.Metadata)
	meta.Salt = []byte{0x10, 0xec, 0x3d, 0x3f, 0xe0, 0x2a, 0xd2, 0xbe, 0xe6, 0xf1, 0xf5, 0x54, 0xf, 0x8e, 0x6b, 0xbe, 0x3b, 0x8b, 0x29, 0x44, 0x5c, 0xf5, 0x2, 0xd2, 0x7d, 0x47, 0xad, 0x55, 0x4a, 0xa8, 0x97, 0x1f}
	meta.Iterations = 600000
	meta.HashFunction = "sha512"
	meta.KeyLength = 32

	// Get decryption key from the provider.
	keys, _, err := keyProvider.Provide(meta)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%x", keys.DecryptionKey)
}
Output:

225872367198760137e0a18580433447bbf578fbe2b87ff36aef3c175fe5709c

Index

Examples

Constants

View Source
const (
	MinimumIterations       int = 200000
	MinimumPassphraseLength int = 16
)
View Source
const (
	// DefaultSaltLength specifies the default salt length in bytes.
	DefaultSaltLength int = 32
	// DefaultIterations contains the default iterations to use. The number is set to the current recommendations
	// outlined here:
	// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
	DefaultIterations int = 600000
	// DefaultKeyLength is the default output length. We set it to the key length required by AES-GCM 256
	DefaultKeyLength int = 32
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Passphrase   string           `hcl:"passphrase"`
	KeyLength    int              `hcl:"key_length,optional"`
	Iterations   int              `hcl:"iterations,optional"`
	HashFunction HashFunctionName `hcl:"hash_function,optional"`
	SaltLength   int              `hcl:"salt_length,optional"`
	// contains filtered or unexported fields
}

func (*Config) Build

func (*Config) WithHashFunction

func (c *Config) WithHashFunction(hashFunction HashFunctionName) *Config

WithHashFunction sets the hash function and returns the same config for chaining

func (*Config) WithIterations

func (c *Config) WithIterations(iterations int) *Config

WithIterations sets the iterations and returns the same config for chaining

func (*Config) WithKeyLength

func (c *Config) WithKeyLength(length int) *Config

WithKeyLength sets the key length and returns the same config for chaining

func (*Config) WithPassphrase

func (c *Config) WithPassphrase(passphrase string) *Config

WithPassphrase adds the passphrase and returns the same config for chaining.

func (*Config) WithSaltLength

func (c *Config) WithSaltLength(length int) *Config

WithSaltLength sets the salt length and returns the same config for chaining

type Descriptor

type Descriptor interface {
	keyprovider.Descriptor

	TypedConfig() *Config
}

Descriptor provides TypedConfig on top of keyprovider.Descriptor.

func New

func New() Descriptor

New creates a new PBKDF2 key provider descriptor.

type HashFunction

type HashFunction func() hash.Hash

HashFunction is a provider of a hash.Hash.

type HashFunctionName

type HashFunctionName string

HashFunctionName describes a hash function to use for PBKDF2 hash generation. While you could theoretically supply your own from outside the package, please don't do that. Include your hash function in this package. (Thanks Go for the lack of visibility constraints.)

const (
	SHA256HashFunctionName  HashFunctionName = "sha256"
	SHA512HashFunctionName  HashFunctionName = "sha512"
	DefaultHashFunctionName HashFunctionName = SHA512HashFunctionName
)

func (HashFunctionName) Function

func (h HashFunctionName) Function() HashFunction

Function returns the underlying hash function for the name.

func (HashFunctionName) Validate

func (h HashFunctionName) Validate() error

Validate checks if the specified hash function name is valid.

type Metadata

type Metadata struct {
	Salt         []byte           `json:"salt"`
	Iterations   int              `json:"iterations"`
	HashFunction HashFunctionName `json:"hash_function"`
	KeyLength    int              `json:"key_length"`
}

Metadata describes the metadata to be stored alongside the encrypted form.

Example
package main

import (
	"bytes"
	"fmt"

	"github.com/terramate-io/hcl/v2/gohcl"
	"github.com/terramate-io/opentofulib/internal/encryption/config"
	"github.com/terramate-io/opentofulib/internal/encryption/keyprovider/pbkdf2"
)

var metadataExampleConfiguration = `key_provider "pbkdf2" "foo" {
  passphrase = "correct-horse-battery-staple"
}
`

func main() {
	configStruct := pbkdf2.New().ConfigStruct()

	// Parse the config:
	parsedConfig, diags := config.LoadConfigFromString("config.hcl", metadataExampleConfiguration)
	if diags.HasErrors() {
		panic(diags)
	}

	// Use gohcl to parse the hcl block from parsedConfig into the static configuration struct:
	if err := gohcl.DecodeBody(
		parsedConfig.KeyProviderConfigs[0].Body,
		nil,
		configStruct,
	); err != nil {
		panic(err)
	}

	// Create the actual key provider.
	keyProvider, keyMeta, err := configStruct.Build()
	if err != nil {
		panic(err)
	}

	// The first time around, let's get an encryption key:
	oldKeys, oldMeta, err := keyProvider.Provide(keyMeta)
	if err != nil {
		panic(err)
	}

	// The second time, you can pass in the metadata from the previous encryption:
	newKeys, _, err := keyProvider.Provide(oldMeta)
	if err != nil {
		panic(err)
	}

	// The old encryption and new decryption key will be the same:
	if bytes.Equal(oldKeys.EncryptionKey, newKeys.DecryptionKey) {
		fmt.Println("The keys match!")
	}
}
Output:

The keys match!

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL