lldbenc

package module
v0.0.0-...-85f5d4a Latest Latest
Warning

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

Go to latest
Published: Aug 8, 2020 License: GPL-3.0 Imports: 6 Imported by: 0

README

lldbenc

this library is a work in progess!

it has not been audited!

DO NOT EXPECT IT TO BE SECURE!

This package implements an encryption wrapper for lldb.Filer. Ideally it can at some point be used to encrypt modernc.org/kv databases.

The encryption is performed using AES-XTS. This is also used e.g. by the linux disk encryption LUKS. What is noteworthy is that the XTS mode of operation is not authenticated, i.e. it can not detect if changes to the ciphertext are made. Instead it decrypts to random data. Authenticated modes of operation have a per-block overhead, which is something i didn't want in the application i had in mind designing this. However, in order to be helpful in other contexts as well, I am considering to add support for this.

Open Issues
  • figure out how to select initial tweak
    • idea: derive two values from the provided key, one for en/decryption; one as a tweak
  • consider implementing support for multiple modes of operation.
  • throughout the code, implement logical and physical block size to be different. this is a groundstone for authenticated modes of operation.
  • discuss threat model around unencrypted write-ahead-log files, and how to mitigate the threat.
  • research if lldb.ACIDFiler0 can be made to use an lldb.Filer instead of os.File.
Limitations

I hoped I could use this library to encrypt a modernc.org/kv database. However, despite being mostly based on lldb.Filer, parts of that library (the write-ahead-log, to be precise) still consume an *os.File, which we can not encrypt this way. This means that if we still used it, all data will be written to disk in the clear, and only deleted afterwards. Since SSDs usually don't really delete data in order to achieve longer life-times, this can be a powerful exfiltration vector. Additionally having regular disk-encryption reduces the risk to some degree, but not entirely. Another option could be to store the write-ahead-log in a ramdisk, but that would mean that it is lost if the computer crashes.

The best case would be if the write-ahead-log would be changed to work with lldb.Filers.

How does it work?

Encryption is performed in larger blocks (these are not the AES blocks). The current default block size is 256 bytes but can be configured. I believe a reasonable block size nowadays woud be 4kB, because disk updates require rewriting this much anyway. Ultimately however it likely depends on the use case.

In order to provide a footgun for users, the package allows using a different block cipher than AES.

What can I use as keys?

The encryption key must be pseudorandom. This especially means that passwords can be immediately used. Instead, use a password-based key derivation function like Argon2, Ballon hashing or scrypt to derive a strong key from the password. To select the parameters, follow the advice in the Argon2 RFC:

We recommend the following procedure to select the type and the parameters for practical use of Argon2.

  1. Select the type y. If you do not know the difference between them or you consider side-channel attacks as viable threat, choose Argon2id.

  2. Figure out the maximum number h of threads that can be initiated by each call to Argon2.

  3. Figure out the maximum amount m of memory that each call can afford.

  4. Figure out the maximum amount x of time (in seconds) that each call can afford.

  5. Select the salt length. 128 bits is sufficient for all applications, but can be reduced to 64 bits in the case of space constraints.

  6. Select the tag length. 128 bits is sufficient for most applications, including key derivation. If longer keys are needed, select longer tags.

  7. If side-channel attacks are a viable threat, or if you're uncertain, enable the memory wiping option in the library call.

  8. Run the scheme of type y, memory m and h lanes and threads, using different number of passes t. Figure out the maximum t such that the running time does not exceed x. If it exceeds x even for t = 1, reduce m accordingly.

  9. Hash all the passwords with the just determined values m, h, and t.

Documentation

Overview

lldb implements an encryption wrapper for "modernc.org/lldb".Filer. Ideally it can at some point be used to encrypt modernc.org/kv databases.

Index

Constants

View Source
const DefaultBlockSize = 4 * 1024

DefaultBlockSize is the default size of encrypted blocks. It is set to 4kB, because that is the block size of must underlying storage media.

Variables

This section is empty.

Functions

This section is empty.

Types

type Filer

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

Filer wraps an lldb.Filer to add simple encryption.

func NewFiler

func NewFiler(filer lldb.Filer, key []byte, opts ...Option) (Filer, error)

NewFiler returns a new encrypted Filer that wraps filer, uses encryption key key and applies the supplied options opts.

func (Filer) BeginUpdate

func (f Filer) BeginUpdate() error

BeginUpdate starts an update transaction. Depending on the lower-level filer, this may be a no-op.

func (Filer) Close

func (f Filer) Close() error

Close closes the filer.

func (Filer) EndUpdate

func (f Filer) EndUpdate() error

EndUpdate ends (commits) an update transaction. Depending on the lower-level filer, this may be a no-op.

func (Filer) Name

func (f Filer) Name() string

Name returns the name of the wrapped filer.

func (Filer) PunchHole

func (f Filer) PunchHole(off, size int64) error

PunchHole punches a hole of size at offset off in the underlying filer. The behaviour depends on the wrapped filer. More information on what this does can be found in the lldb package documentation.

func (Filer) ReadAt

func (f Filer) ReadAt(b []byte, off int64) (n int, err error)

ReadAt reads the data in the filer at offset off into b. The specific behaviour may depend on the wrapped filer. TODO verify that we bahave correctly according to io.ReaderAt

func (Filer) Rollback

func (f Filer) Rollback() error

Rollback rolls back the most recently started and not yet ended/rolled back update transaction. Depending on the wrapped filer, this may be a no-op.

func (Filer) Size

func (f Filer) Size() (int64, error)

Size returns the size of the filer. At this point, the encryption does not provide any authentication, so the size of the plaintext is the same as the size of the ciphertext.

func (Filer) Sync

func (f Filer) Sync() error

Sync triggers the syncing of written data to disk. It only calls the same method on the wrapped filer.

func (Filer) Truncate

func (f Filer) Truncate(sz int64) error

Truncate truncates the filer. It only calls the same method on the wrapped filer.

func (Filer) WriteAt

func (f Filer) WriteAt(b []byte, off int64) (n int, err error)

WriteAt writes the data in b into the filer at offset off. The specific behaviour may depend on the wrapped filer. TODO verify that we bahave correctly according to io.WriterAt

type NewBlockCipherFunc

type NewBlockCipherFunc func(key []byte) (cipher.Block, error)

NewBlockCipherFunc is a function that initialized a block cipher based on the supplied key.

type NewXTSCipherFunc

type NewXTSCipherFunc func(key []byte) (*xts.Cipher, error)

NewXTSCipherFunc is a function that returns an XTS cipher based on the supplied key. This can be used to use XTS with a different block cipher than AES.

type Option

type Option func(f *Filer) error

Option is the functional option type for Filer.

func WithBlockCipher

func WithBlockCipher(newBlockCipher NewBlockCipherFunc) Option

WithBlockCipher returns an option that sets the block cipher to the one specified by newBlockCipher.

func WithBlockSize

func WithBlockSize(blockSize int) Option

WithBlockSize returns an option that sets the block size to blockSize.

Jump to

Keyboard shortcuts

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