passlock

package
v0.0.0-...-e5e38fc Latest Latest
Warning

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

Go to latest
Published: Dec 17, 2023 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package passlock provides functions for encrypting data using a key derived from a user-provided passphrase. This uses AES-256 encryption to encrypt the provided data.

Definition of terms:

  • plaintext: Data that has not been encrypted.
  • passphrase: A user-defined phrase used in place of an encryption key. Longer is better.
  • key: A key is a byte array of a size specific to the encryption algorithm used. An AES-128 key may not be used for AES-256 encryption operations.
  • salt: A salt is a generated byte array that is the same size as the key. This is generated using a secure random source, and is the entropy used for key generation and recovery.
  • key derivation: The process of securely creating a key from secure inputs. This process should be practically infeasible to reproduce without knowing the original inputs.
  • scrypt: A CPU and memory hard algorithm used for key derivation in this library. This was designed as an improvement to bcrypt to combat GPU brute force attacks.
  • AES: Stands for Advanced Encryption Standard. This is an encryption algorithm that - at the time of this writing - has not been shown to be directly broken in any way. Side-channel attacks are possible, but are a weakness of implementation and hardware.
  • base key: The key used to encrypt/decrypt the payload in a MultiLocker.
  • surrogate key: A key used to encrypt the base key in a MultiLocker. This allows different passphrases to be used with the same encrypted payload.

How it works:

A key and salt is generated from the given passphrase. The salt is appended to the encrypted payload so the same key can be derived later given the same passphrase. Scrypt is memory and CPU hard, so it's impractical to brute force the salt to get the original passphrase, provided that sufficient tuning values are provided to the KeyGenerator. A normal user is really only expected to define an iteration count for key generation.

The key, salt, and plaintext are passed to the Lock function to encrypt the payload and append the salt to it. The key is recovered from the encrypted payload by passing the original passphrase and the payload to KeyGenerator.Derive. The key and encrypted payload are passed to the Unlock function to decrypt the payload and return the original plain text.

The MultiLocker type extends the functionality above by providing the ability to use multiple surrogate keys to interact with the encrypted payload. A MultiLocker is created using a KeyGenerator, and the encrypted payload is set by calling MultiLocker.Lock with the base passphrase and plaintext. Once created, surrogate keys may be added to the MultiLocker that allow reading the encrypted payload. A MultiLocker with surrogate keys and encrypted payload may be persisted to disk in binary form, and read back - including key generation settings.

A freshly read MultiLocker may not be changed in any way. Editing is enabled by calling EnableUpdate with the base passphrase. After this call completes successfully, surrogate keys may be added or removed. A new encrypted payload may only be set in a MultiLocker with the base passphrase. A WriteMultiLocker allows surrogate passphrases to be used to lock a new payload, instead of just the base passphrase.

General guidelines:

  • It's possible to customize the CPU cost, iteration count, and relative block size parameters directly for key generation. If you're not an expert, then don't use SetIterations, SetCPUCost, or SetRelativeBlockSize.
  • Both short and long delay iteration GeneratorOpt functions are provided, choose the correct iterations for your use-case using either SetLongDelayIterations or SetShortDelayIterations.
  • If encrypted data is intended to be stored indefinitely, choose the SetLongDelayIterations option for key generation.
  • This method of encryption (AES-GCM) supports encrypting and authenticating at most about 64GB at a time. You could get around this by splitting a very large file into multiple chunks that include some metadata to prevent reordering or truncating.
  • AES-256 is a good default for a lot of cases, with excellent security and good throughput speeds.
  • This library supports AES-256 since that is the best supported by the Go standard lib, but AES-128 may also be used for situations where more throughput is desired.
  • The main limit to operation speed comes from key generation (as intended), the AES key size makes a much smaller impact to performance unless a very large payload is encrypted.
  • When deriving the key from an encrypted payload, make sure that the same KeyGenerator settings are used. Not doing so will result in an incorrect key.
  • Technically, a surrogate key could be used to update a MultiLocker encrypted payload without invalidating other surrogate keys, since there are no cryptographic blockers to that. The base MultiLocker doesn't provide that function as a logical constraint only.
  • The MultiLocker base key may not be updated without invalidating all surrogate keys.

Index

Constants

View Source
const (
	DefaultLargeIterations       uint64 = 1 << 30
	DefaultInteractiveIterations uint64 = 1 << 17
	DefaultRelBlockSize          uint8  = 8
	DefaultCpuCost               uint8  = 1
	AES256KeySize                uint8  = 256 / 8
	AES128KeySize                uint8  = 128 / 8
)

Variables

View Source
var (
	ErrEmptyPassPhrase = errors.New("cannot use an empty passphrase")
	ErrInvalidData     = errors.New("unable to use input data")
)
View Source
var (
	ErrInvalidHeader   = errors.New("invalid MultiLocker header")
	ErrInvalidPassword = errors.New("invalid password")
)

Functions

This section is empty.

Types

type Encrypted

type Encrypted []byte

Encrypted is an encrypted payload.

func Lock

func Lock(key Key, salt Salt, data Plaintext) (Encrypted, error)

Lock will encrypt the payload with the given Key, and append the given Salt to the payload. Exposure of the Salt doesn't weaken the Key, since the passphrase is also required to arrive at the same Key. Salt exposure is required to be able to derive the same Key from the same passphrase. However, tampering with the Salt or the payload would prevent Unlock from recovering the Plaintext payload.

type GeneratorOpt

type GeneratorOpt = func(*KeyGenerator) error

GeneratorOpt is a function option to be used with NewKeyGenerator.

func SetAES128KeySize

func SetAES128KeySize() GeneratorOpt

SetAES128KeySize uses 128 bits (16 bytes) as the key size to be generated.

func SetAES256KeySize

func SetAES256KeySize() GeneratorOpt

SetAES256KeySize uses 256 bits (32 bytes) as the key size to be generated.

func SetCPUCost

func SetCPUCost(cost uint8) GeneratorOpt

SetCPUCost sets the parallelism factor for key generation from the default of 1. Only use this option if you know what you're doing.

func SetIterations

func SetIterations(iterations uint64) GeneratorOpt

SetIterations allows the caller to customize the iteration count. Only use this option if you know what you're doing.

func SetLongDelayIterations

func SetLongDelayIterations() GeneratorOpt

SetLongDelayIterations sets a higher iteration count. This is sufficient for infrequent key derivation, or cases where the key will be cached for long periods of time. This option is much more resistant to password cracking, and is the default.

func SetRelativeBlockSize

func SetRelativeBlockSize(size uint8) GeneratorOpt

SetRelativeBlockSize sets the relative block size. Only use this option if you know what you're doing.

func SetShortDelayIterations

func SetShortDelayIterations() GeneratorOpt

SetShortDelayIterations sets a lower iteration count. This is appropriate for situations where a shorter delay is desired because of frequent key derivations. This option balances speed with password cracking resistance. It's recommended to use longer passwords with this approach.

type Key

type Key []byte

Key is an AES key that can be used to encrypt or decrypt an encrypted payload.

type KeyGenerator

type KeyGenerator struct {
	// contains filtered or unexported fields
}

func NewKeyGenerator

func NewKeyGenerator(opts ...GeneratorOpt) (*KeyGenerator, error)

NewKeyGenerator creates a new KeyGenerator using the options provided as zero or more GeneratorOpt. By default, the generator generates a key for AES256KeySize using DefaultLargeIterations.

func (*KeyGenerator) DeriveKey

func (g *KeyGenerator) DeriveKey(pass Passphrase, data Encrypted) (key Key, err error)

DeriveKey will recover a key with the salt in the payload and the given passphrase. This doesn't ensure that the given passphrase is the *correct* passphrase used to encrypt the payload.

func (*KeyGenerator) DeriveKeySalt

func (g *KeyGenerator) DeriveKeySalt(pass Passphrase, data Encrypted) (key Key, salt Salt, err error)

DeriveKeySalt will recover a key and the original salt in the payload with the given passphrase. This doesn't ensure that the given passphrase is the *correct* passphrase used to encrypt the payload.

func (*KeyGenerator) DeriveSalt

func (g *KeyGenerator) DeriveSalt(data Encrypted) (salt Salt, err error)

DeriveSalt gets the salt value from the encrypted payload.

func (*KeyGenerator) GenerateKey

func (g *KeyGenerator) GenerateKey(pass Passphrase) (key Key, salt Salt, err error)

GenerateKey will generate an AES key and salt using the configuration of the KeyGenerator.

type MultiLocker

type MultiLocker struct {
	// contains filtered or unexported fields
}

MultiLocker allows using surrogate keys - in addition to a base key - for reading an encrypted payload. If surrogate key writes are desired, then use the WriteMultiLocker instead.

func NewMultiLocker

func NewMultiLocker(gen *KeyGenerator) *MultiLocker

func (*MultiLocker) AddSurrogatePass

func (l *MultiLocker) AddSurrogatePass(id string, pass Passphrase) error

AddSurrogatePass will add a new surrogate key to this MultiLocker. Update must be enabled in this MultiLocker before this can be done.

func (*MultiLocker) DisableUpdate

func (l *MultiLocker) DisableUpdate()

DisableUpdate will disable updates to this MultiLocker.

func (*MultiLocker) EnableUpdate

func (l *MultiLocker) EnableUpdate(pass []byte) error

EnableUpdate validates the MultiLocker and ensures that it's in a suitable state for updating by setting the base key. The original base passphrase must be used, not a surrogate passphrase, to validate that the correct key is populated.

func (*MultiLocker) ListKeyIDs

func (l *MultiLocker) ListKeyIDs() []string

ListKeyIDs lists all surrogate key IDs in this MultiLocker.

func (*MultiLocker) Lock

func (l *MultiLocker) Lock(pass []byte, unencrypted Plaintext) error

Lock will lock a new payload with the base key. If surrogate keys are present, then the same salt will be used to ensure that surrogate keys are not invalidated.

func (*MultiLocker) Read

func (l *MultiLocker) Read(r io.Reader) error

Read will read the MultiLocker as a binary payload from the io.Reader.

func (*MultiLocker) RemoveSurrogatePass

func (l *MultiLocker) RemoveSurrogatePass(id string) error

RemoveSurrogatePass will remove a surrogate key. Update must be enabled in this MultiLocker before this can be done.

func (*MultiLocker) Unlock

func (l *MultiLocker) Unlock(id string, pass []byte) ([]byte, error)

Unlock will unlock the payload with a surrogate key.

func (*MultiLocker) UpdateSurrogatePass

func (l *MultiLocker) UpdateSurrogatePass(id string, newPass Passphrase) error

UpdateSurrogatePass will update the passphrase of an existing surrogate key by ID. Update must be enabled in this MultiLocker before this can be done.

func (*MultiLocker) Write

func (l *MultiLocker) Write(w io.Writer) error

Write will write the MultiLocker as a binary payload to the io.Writer.

type Passphrase

type Passphrase []byte

Passphrase is a human-readable string used to generate a Key.

type Plaintext

type Plaintext []byte

Plaintext is an unencrypted payload.

func Unlock

func Unlock(key Key, data Encrypted) (Plaintext, error)

Unlock will decrypt the payload after stripping the Salt from the end of it. The Salt length is expected to match the Key length (which is enforced by KeyGenerator).

type Salt

type Salt []byte

Salt is a slice of secure random bytes that is used with scrypt to generate a Key from a Passphrase.

type WriteMultiLocker

type WriteMultiLocker struct {
	*MultiLocker
}

WriteMultiLocker is the same as MultiLocker, except that the logical constraint that surrogate keys cannot write a new payload is lifted.

func NewWriteMultiLocker

func NewWriteMultiLocker(gen *KeyGenerator) *WriteMultiLocker

func (*WriteMultiLocker) SurrogateLock

func (l *WriteMultiLocker) SurrogateLock(id string, pass Passphrase, unencrypted Plaintext) error

SurrogateLock will Lock a new payload in the MultiLocker using a surrogate key.

Jump to

Keyboard shortcuts

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