Skip to content

Commit

Permalink
Merge 5e6cb68 into 6821d90
Browse files Browse the repository at this point in the history
  • Loading branch information
ebiggers committed Dec 3, 2019
2 parents 6821d90 + 5e6cb68 commit 5e03e91
Show file tree
Hide file tree
Showing 28 changed files with 1,859 additions and 381 deletions.
152 changes: 135 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ Concretely, fscrypt contains the following functionality:
* `fscrypt setup MOUNTPOINT` - Gets a filesystem ready for use with fscrypt
* `fscrypt encrypt DIRECTORY` - Encrypts an empty directory
* `fscrypt unlock DIRECTORY` - Unlocks an encrypted directory
* `fscrypt purge MOUNTPOINT` - Removes keys for a filesystem before unmounting
* `fscrypt lock DIRECTORY` - Locks an encrypted directory
* `fscrypt purge MOUNTPOINT` - Locks all encrypted directories on a filesystem
* `fscrypt status [PATH]` - Gets detailed info about filesystems or paths
* `fscrypt metadata` - Manages policies or protectors directly

Expand Down Expand Up @@ -171,6 +172,92 @@ Be careful when using encryption on removable media, since filesystems with the
`encrypt` feature cannot be mounted on systems with kernel versions older than
the minimums listed above -- even to access unencrypted files!

If you configure fscrypt to use non-default features, other kernel
prerequisites may be needed too. See [Configuration
file](#configuration-file).

### Configuration file

Running `sudo fscrypt setup` will create the configuration file
`/etc/fscrypt.conf` if it doesn't already exist. It's a JSON file
that looks like the following:

```
{
"source": "custom_passphrase",
"hash_costs": {
"time": "52",
"memory": "131072",
"parallelism": "32"
},
"compatibility": "legacy",
"options": {
"padding": "32",
"contents": "AES_256_XTS",
"filenames": "AES_256_CTS",
"policy_version": "1"
},
"use_fs_keyring_for_v1_policies": false
}
```

The fields are:

* "source" is the default source for new protectors. The choices are
"pam\_passphrase", "custom\_passphrase", and "raw\_key".

* "hash\_costs" describes how difficult the passphrase hashing is.
By default, `fscrypt setup` calibrates the hashing to use all CPUs
and take about 1 second. The `--time` option to `fscrypt setup` can
be used to customize this time when creating the configuration file.

* "compatibility" can be "legacy" to support kernels older than v4.8,
or the empty string to only support kernels v4.8 and later.

* "options" are the encryption options to use for new encrypted
directories:

* "padding" is the number of bytes by which filenames are padded
before being encrypted. The choices are "32", "16", "8", and
"4". "32" is recommended.

* "contents" is the algorithm used to encrypt file contents. The
choices are "AES_256_XTS", "AES_128_CBC", and "Adiantum".
Normally, "AES_256_XTS" is recommended.

* "filenames" is the algorithm used to encrypt file names. The
choices are "AES_256_CTS", "AES_128_CTS", and "Adiantum".
Normally, "AES_256_CTS" is recommended.

To use algorithms other than "AES_256_XTS" for contents and
"AES_256_CTS" for filenames, the needed algorithm(s) may need to
be enabled in the Linux kernel's cryptography API. For example,
to use Adiantum, `CONFIG_CRYPTO_ADIANTUM` must be set. Also,
not all combinations of algorithms are allowed; for example,
"Adiantum" for contents can only be paired with "Adiantum" for
filenames. See the [kernel
documentation](https://www.kernel.org/doc/html/latest/filesystems/fscrypt.html#encryption-modes-and-usage)
for more details about the supported algorithms.

* "policy\_version" is the version of encryption policy to use.
The choices are "1" and "2". Directories created with policy
version "2" are only usable on kernel v5.4 or later, but are
preferable to version "1" if you don't mind this restriction.

* "use\_fs\_keyring\_for\_v1\_policies" specifies whether to add keys
for v1 encryption policies to the filesystem keyring, rather than to
user keyrings. This can solve [issues with processes being unable
to access encrypted files](#cant-log-in-with-ssh-even-when-users-encrypted-home-directory-is-unlocked).
However, it requires kernel v5.4 or later, and it makes unlocking
and locking encrypted directories require root.

The purpose of this setting is to allow people to take advantage of
some of the improvements in Linux v5.4 on encrypted directories that
are also compatible with older kernels. If you don't need
compatibility with older kernels, it's better to not use this
setting and instead (re-)create your encrypted directories with
`"policy_version": "2"`.

### Setting up the PAM module

Note that to make use of the installed PAM module, your
Expand Down Expand Up @@ -213,8 +300,9 @@ after `pam_unix.so` in `/etc/pam.d/common-session` or similar. The
`lock_policies` option locks the directories protected with the user's login
passphrase when the last session ends. The `drop_caches` option tells fscrypt to
clear the filesystem caches when the last session closes, ensuring all the
locked data is inaccessible. All the types also support the `debug` option which
prints additional debug information to the syslog.
locked data is inaccessible; this only needed for v1 encryption policies.
All the types also support the `debug` option which prints additional
debug information to the syslog.

## Note about stability

Expand Down Expand Up @@ -295,24 +383,23 @@ POLICY UNLOCKED PROTECTORS
"/mnt/disk/dir1" is encrypted with fscrypt.

Policy: 16382f282d7b29ee
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
Unlocked: Yes

Protected with 1 protector:
PROTECTOR LINKED DESCRIPTION
7626382168311a9d No custom protector "Super Secret"

# Purging a filesystem locks all the files.
>>>>> sudo fscrypt purge /mnt/disk --user=$USER
WARNING: Encrypted data on this filesystem will be inaccessible until unlocked again!!
Purge all policy keys from "/mnt/disk" and drop global inode cache? [y/N] y
Policies purged for "/mnt/disk".

# Lock the directory. 'sudo' and the '--user' argument are only
# required if the directory uses a v1 encryption policy.
>>>>> sudo fscrypt lock /mnt/disk/dir1 --user=$USER
Encrypted data removed from filesystem cache.
"/mnt/disk/dir1" is now locked.
>>>>> fscrypt status /mnt/disk/dir1
"/mnt/disk/dir1" is encrypted with fscrypt.

Policy: 16382f282d7b29ee
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
Unlocked: No

Protected with 1 protector:
Expand All @@ -333,7 +420,7 @@ Enter custom passphrase for protector "Super Secret":
"/mnt/disk/dir1" is encrypted with fscrypt.

Policy: 16382f282d7b29ee
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
Unlocked: Yes

Protected with 1 protector:
Expand All @@ -345,7 +432,7 @@ Hello World

#### Quiet Version
```bash
>>>>> sudo fscrypt purge /mnt/disk --user=$USER --quiet --force
>>>>> sudo fscrypt lock /mnt/disk/dir1 --quiet --user=$USER
>>>>> echo "hunter2" | fscrypt unlock /mnt/disk/dir1 --quiet
```

Expand All @@ -369,7 +456,7 @@ Enter login passphrase for joerichey:
"/mnt/disk/dir2" is encrypted with fscrypt.

Policy: fe1c92009abc1cff
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
Unlocked: Yes

Protected with 1 protector:
Expand Down Expand Up @@ -405,7 +492,7 @@ PROTECTOR LINKED DESCRIPTION
"/mnt/disk/dir1" is encrypted with fscrypt.

Policy: 16382f282d7b29ee
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
Unlocked: Yes

Protected with 1 protector:
Expand Down Expand Up @@ -501,7 +588,7 @@ fe1c92009abc1cff No 6891f0a901f0065e
"/mnt/disk/dir1" is encrypted with fscrypt.

Policy: 16382f282d7b29ee
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
Unlocked: No

Protected with 1 protector:
Expand All @@ -517,7 +604,7 @@ Protector 2c75f519b9c9959d now protecting policy 16382f282d7b29ee.
"/mnt/disk/dir1" is encrypted with fscrypt.

Policy: 16382f282d7b29ee
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS
Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1
Unlocked: No

Protected with 2 protectors:
Expand Down Expand Up @@ -650,6 +737,37 @@ shred -u file
However, `shred` isn't guaranteed to be effective on all filesystems and storage
devices.

#### Can't log in with ssh even when user's encrypted home directory is unlocked

This is caused by a limitation in the original design of Linux
filesystem encryption which made it difficult to ensure that all
processes can access unlocked encrypted files. This issue can also
manifest in other ways such as Docker containers being unable to
access encrypted files, or NetworkManager being unable to access
certificates if they are located in an encrypted directory.

If you are using kernel v5.4 or later, you can fix this by setting the
following in `/etc/fscrypt.conf`:

"use_fs_keyring_for_v1_policies": true

However, this makes manually unlocking and locking encrypted
directories start to require root. (The PAM module will still work.)
E.g., you'll need to run `sudo fscrypt unlock`, not `fscrypt unlock`.

Alternatively, you can upgrade your encrypted directories to use v2
encryption policies by setting the following in the "options" section
of `/etc/fscrypt.conf`:

"policy_version": "2"

... and then for each of your encrypted directories, using `fscrypt
encrypt` to encrypt a new empty directory, copying your files into it,
and replacing the original directory with it. This will fix the key
access problems, while also keeping `fscrypt unlock` and `fscrypt
lock` usable by non-root users. This is the recommended solution if
you don't need to access your files on kernels older than v5.4.

## Legal

Copyright 2017 Google Inc. under the
Expand Down
4 changes: 4 additions & 0 deletions actions/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ func getConfig() (*metadata.Config, error) {
config.Options.Filenames = metadata.DefaultOptions.Filenames
log.Printf("Falling back to filenames mode of %q", config.Options.Filenames)
}
if config.Options.PolicyVersion == 0 {
config.Options.PolicyVersion = metadata.DefaultOptions.PolicyVersion
log.Printf("Falling back to policy version of %d", config.Options.PolicyVersion)
}

if err := config.CheckValidity(); err != nil {
return nil, errors.Wrap(ErrBadConfigFile, err.Error())
Expand Down
19 changes: 16 additions & 3 deletions actions/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/pkg/errors"

"github.com/google/fscrypt/filesystem"
"github.com/google/fscrypt/keyring"
"github.com/google/fscrypt/metadata"
"github.com/google/fscrypt/util"
)
Expand All @@ -57,10 +58,13 @@ type Context struct {
// modified after being loaded to customise parameters.
Config *metadata.Config
// Mount is the filesystem relative to which all Protectors and Policies
// are added, edited, removed, and applied.
// are added, edited, removed, and applied, and to which policies using
// the filesystem keyring are provisioned.
Mount *filesystem.Mount
// TargetUser is the user for which protectors are created and to whose
// keyring policies are provisioned.
// TargetUser is the user for whom protectors are created, and to whose
// keyring policies using the user keyring are provisioned. It's also
// the user for whom the keys are claimed in the filesystem keyring when
// v2 policies are provisioned.
TargetUser *user.User
}

Expand Down Expand Up @@ -145,6 +149,15 @@ func (ctx *Context) getService() string {
return unix.FSCRYPT_KEY_DESC_PREFIX
}

func (ctx *Context) getKeyringOptions() *keyring.Options {
return &keyring.Options{
Mount: ctx.Mount,
User: ctx.TargetUser,
Service: ctx.getService(),
UseFsKeyringForV1Policies: ctx.Config.GetUseFsKeyringForV1Policies(),
}
}

// getProtectorOption returns the ProtectorOption for the protector on the
// context's mountpoint with the specified descriptor.
func (ctx *Context) getProtectorOption(protectorDescriptor string) *ProtectorOption {
Expand Down
Loading

0 comments on commit 5e03e91

Please sign in to comment.