123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649 |
- =====================================
- Filesystem-level encryption (fscrypt)
- =====================================
- Introduction
- ============
- fscrypt is a library which filesystems can hook into to support
- transparent encryption of files and directories.
- Note: "fscrypt" in this document refers to the kernel-level portion,
- implemented in ``fs/crypto/``, as opposed to the userspace tool
- `fscrypt <https://github.com/google/fscrypt>`_. This document only
- covers the kernel-level portion. For command-line examples of how to
- use encryption, see the documentation for the userspace tool `fscrypt
- <https://github.com/google/fscrypt>`_. Also, it is recommended to use
- the fscrypt userspace tool, or other existing userspace tools such as
- `fscryptctl <https://github.com/google/fscryptctl>`_ or `Android's key
- management system
- <https://source.android.com/security/encryption/file-based>`_, over
- using the kernel's API directly. Using existing tools reduces the
- chance of introducing your own security bugs. (Nevertheless, for
- completeness this documentation covers the kernel's API anyway.)
- Unlike dm-crypt, fscrypt operates at the filesystem level rather than
- at the block device level. This allows it to encrypt different files
- with different keys and to have unencrypted files on the same
- filesystem. This is useful for multi-user systems where each user's
- data-at-rest needs to be cryptographically isolated from the others.
- However, except for filenames, fscrypt does not encrypt filesystem
- metadata.
- Unlike eCryptfs, which is a stacked filesystem, fscrypt is integrated
- directly into supported filesystems --- currently ext4, F2FS, and
- UBIFS. This allows encrypted files to be read and written without
- caching both the decrypted and encrypted pages in the pagecache,
- thereby nearly halving the memory used and bringing it in line with
- unencrypted files. Similarly, half as many dentries and inodes are
- needed. eCryptfs also limits encrypted filenames to 143 bytes,
- causing application compatibility issues; fscrypt allows the full 255
- bytes (NAME_MAX). Finally, unlike eCryptfs, the fscrypt API can be
- used by unprivileged users, with no need to mount anything.
- fscrypt does not support encrypting files in-place. Instead, it
- supports marking an empty directory as encrypted. Then, after
- userspace provides the key, all regular files, directories, and
- symbolic links created in that directory tree are transparently
- encrypted.
- Threat model
- ============
- Offline attacks
- ---------------
- Provided that userspace chooses a strong encryption key, fscrypt
- protects the confidentiality of file contents and filenames in the
- event of a single point-in-time permanent offline compromise of the
- block device content. fscrypt does not protect the confidentiality of
- non-filename metadata, e.g. file sizes, file permissions, file
- timestamps, and extended attributes. Also, the existence and location
- of holes (unallocated blocks which logically contain all zeroes) in
- files is not protected.
- fscrypt is not guaranteed to protect confidentiality or authenticity
- if an attacker is able to manipulate the filesystem offline prior to
- an authorized user later accessing the filesystem.
- Online attacks
- --------------
- fscrypt (and storage encryption in general) can only provide limited
- protection, if any at all, against online attacks. In detail:
- fscrypt is only resistant to side-channel attacks, such as timing or
- electromagnetic attacks, to the extent that the underlying Linux
- Cryptographic API algorithms are. If a vulnerable algorithm is used,
- such as a table-based implementation of AES, it may be possible for an
- attacker to mount a side channel attack against the online system.
- Side channel attacks may also be mounted against applications
- consuming decrypted data.
- After an encryption key has been provided, fscrypt is not designed to
- hide the plaintext file contents or filenames from other users on the
- same system, regardless of the visibility of the keyring key.
- Instead, existing access control mechanisms such as file mode bits,
- POSIX ACLs, LSMs, or mount namespaces should be used for this purpose.
- Also note that as long as the encryption keys are *anywhere* in
- memory, an online attacker can necessarily compromise them by mounting
- a physical attack or by exploiting any kernel security vulnerability
- which provides an arbitrary memory read primitive.
- While it is ostensibly possible to "evict" keys from the system,
- recently accessed encrypted files will remain accessible at least
- until the filesystem is unmounted or the VFS caches are dropped, e.g.
- using ``echo 2 > /proc/sys/vm/drop_caches``. Even after that, if the
- RAM is compromised before being powered off, it will likely still be
- possible to recover portions of the plaintext file contents, if not
- some of the encryption keys as well. (Since Linux v4.12, all
- in-kernel keys related to fscrypt are sanitized before being freed.
- However, userspace would need to do its part as well.)
- Currently, fscrypt does not prevent a user from maliciously providing
- an incorrect key for another user's existing encrypted files. A
- protection against this is planned.
- Key hierarchy
- =============
- Master Keys
- -----------
- Each encrypted directory tree is protected by a *master key*. Master
- keys can be up to 64 bytes long, and must be at least as long as the
- greater of the key length needed by the contents and filenames
- encryption modes being used. For example, if AES-256-XTS is used for
- contents encryption, the master key must be 64 bytes (512 bits). Note
- that the XTS mode is defined to require a key twice as long as that
- required by the underlying block cipher.
- To "unlock" an encrypted directory tree, userspace must provide the
- appropriate master key. There can be any number of master keys, each
- of which protects any number of directory trees on any number of
- filesystems.
- Userspace should generate master keys either using a cryptographically
- secure random number generator, or by using a KDF (Key Derivation
- Function). Note that whenever a KDF is used to "stretch" a
- lower-entropy secret such as a passphrase, it is critical that a KDF
- designed for this purpose be used, such as scrypt, PBKDF2, or Argon2.
- Per-file keys
- -------------
- Since each master key can protect many files, it is necessary to
- "tweak" the encryption of each file so that the same plaintext in two
- files doesn't map to the same ciphertext, or vice versa. In most
- cases, fscrypt does this by deriving per-file keys. When a new
- encrypted inode (regular file, directory, or symlink) is created,
- fscrypt randomly generates a 16-byte nonce and stores it in the
- inode's encryption xattr. Then, it uses a KDF (Key Derivation
- Function) to derive the file's key from the master key and nonce.
- The Adiantum encryption mode (see `Encryption modes and usage`_) is
- special, since it accepts longer IVs and is suitable for both contents
- and filenames encryption. For it, a "direct key" option is offered
- where the file's nonce is included in the IVs and the master key is
- used for encryption directly. This improves performance; however,
- users must not use the same master key for any other encryption mode.
- Below, the KDF and design considerations are described in more detail.
- The current KDF works by encrypting the master key with AES-128-ECB,
- using the file's nonce as the AES key. The output is used as the
- derived key. If the output is longer than needed, then it is
- truncated to the needed length.
- Note: this KDF meets the primary security requirement, which is to
- produce unique derived keys that preserve the entropy of the master
- key, assuming that the master key is already a good pseudorandom key.
- However, it is nonstandard and has some problems such as being
- reversible, so it is generally considered to be a mistake! It may be
- replaced with HKDF or another more standard KDF in the future.
- Key derivation was chosen over key wrapping because wrapped keys would
- require larger xattrs which would be less likely to fit in-line in the
- filesystem's inode table, and there didn't appear to be any
- significant advantages to key wrapping. In particular, currently
- there is no requirement to support unlocking a file with multiple
- alternative master keys or to support rotating master keys. Instead,
- the master keys may be wrapped in userspace, e.g. as is done by the
- `fscrypt <https://github.com/google/fscrypt>`_ tool.
- Including the inode number in the IVs was considered. However, it was
- rejected as it would have prevented ext4 filesystems from being
- resized, and by itself still wouldn't have been sufficient to prevent
- the same key from being directly reused for both XTS and CTS-CBC.
- Encryption modes and usage
- ==========================
- fscrypt allows one encryption mode to be specified for file contents
- and one encryption mode to be specified for filenames. Different
- directory trees are permitted to use different encryption modes.
- Currently, the following pairs of encryption modes are supported:
- - AES-256-XTS for contents and AES-256-CTS-CBC for filenames
- - AES-128-CBC for contents and AES-128-CTS-CBC for filenames
- - Adiantum for both contents and filenames
- If unsure, you should use the (AES-256-XTS, AES-256-CTS-CBC) pair.
- AES-128-CBC was added only for low-powered embedded devices with
- crypto accelerators such as CAAM or CESA that do not support XTS.
- Adiantum is a (primarily) stream cipher-based mode that is fast even
- on CPUs without dedicated crypto instructions. It's also a true
- wide-block mode, unlike XTS. It can also eliminate the need to derive
- per-file keys. However, it depends on the security of two primitives,
- XChaCha12 and AES-256, rather than just one. See the paper
- "Adiantum: length-preserving encryption for entry-level processors"
- (https://eprint.iacr.org/2018/720.pdf) for more details. To use
- Adiantum, CONFIG_CRYPTO_ADIANTUM must be enabled. Also, fast
- implementations of ChaCha and NHPoly1305 should be enabled, e.g.
- CONFIG_CRYPTO_CHACHA20_NEON and CONFIG_CRYPTO_NHPOLY1305_NEON for ARM.
- New encryption modes can be added relatively easily, without changes
- to individual filesystems. However, authenticated encryption (AE)
- modes are not currently supported because of the difficulty of dealing
- with ciphertext expansion.
- Contents encryption
- -------------------
- For file contents, each filesystem block is encrypted independently.
- Currently, only the case where the filesystem block size is equal to
- the system's page size (usually 4096 bytes) is supported.
- Each block's IV is set to the logical block number within the file as
- a little endian number, except that:
- - With CBC mode encryption, ESSIV is also used. Specifically, each IV
- is encrypted with AES-256 where the AES-256 key is the SHA-256 hash
- of the file's data encryption key.
- - In the "direct key" configuration (FS_POLICY_FLAG_DIRECT_KEY set in
- the fscrypt_policy), the file's nonce is also appended to the IV.
- Currently this is only allowed with the Adiantum encryption mode.
- Filenames encryption
- --------------------
- For filenames, each full filename is encrypted at once. Because of
- the requirements to retain support for efficient directory lookups and
- filenames of up to 255 bytes, the same IV is used for every filename
- in a directory.
- However, each encrypted directory still uses a unique key; or
- alternatively (for the "direct key" configuration) has the file's
- nonce included in the IVs. Thus, IV reuse is limited to within a
- single directory.
- With CTS-CBC, the IV reuse means that when the plaintext filenames
- share a common prefix at least as long as the cipher block size (16
- bytes for AES), the corresponding encrypted filenames will also share
- a common prefix. This is undesirable. Adiantum does not have this
- weakness, as it is a wide-block encryption mode.
- All supported filenames encryption modes accept any plaintext length
- >= 16 bytes; cipher block alignment is not required. However,
- filenames shorter than 16 bytes are NUL-padded to 16 bytes before
- being encrypted. In addition, to reduce leakage of filename lengths
- via their ciphertexts, all filenames are NUL-padded to the next 4, 8,
- 16, or 32-byte boundary (configurable). 32 is recommended since this
- provides the best confidentiality, at the cost of making directory
- entries consume slightly more space. Note that since NUL (``\0``) is
- not otherwise a valid character in filenames, the padding will never
- produce duplicate plaintexts.
- Symbolic link targets are considered a type of filename and are
- encrypted in the same way as filenames in directory entries, except
- that IV reuse is not a problem as each symlink has its own inode.
- User API
- ========
- Setting an encryption policy
- ----------------------------
- The FS_IOC_SET_ENCRYPTION_POLICY ioctl sets an encryption policy on an
- empty directory or verifies that a directory or regular file already
- has the specified encryption policy. It takes in a pointer to a
- :c:type:`struct fscrypt_policy`, defined as follows::
- #define FS_KEY_DESCRIPTOR_SIZE 8
- struct fscrypt_policy {
- __u8 version;
- __u8 contents_encryption_mode;
- __u8 filenames_encryption_mode;
- __u8 flags;
- __u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
- };
- This structure must be initialized as follows:
- - ``version`` must be 0.
- - ``contents_encryption_mode`` and ``filenames_encryption_mode`` must
- be set to constants from ``<linux/fs.h>`` which identify the
- encryption modes to use. If unsure, use
- FS_ENCRYPTION_MODE_AES_256_XTS (1) for ``contents_encryption_mode``
- and FS_ENCRYPTION_MODE_AES_256_CTS (4) for
- ``filenames_encryption_mode``.
- - ``flags`` must contain a value from ``<linux/fs.h>`` which
- identifies the amount of NUL-padding to use when encrypting
- filenames. If unsure, use FS_POLICY_FLAGS_PAD_32 (0x3).
- In addition, if the chosen encryption modes are both
- FS_ENCRYPTION_MODE_ADIANTUM, this can contain
- FS_POLICY_FLAG_DIRECT_KEY to specify that the master key should be
- used directly, without key derivation.
- - ``master_key_descriptor`` specifies how to find the master key in
- the keyring; see `Adding keys`_. It is up to userspace to choose a
- unique ``master_key_descriptor`` for each master key. The e4crypt
- and fscrypt tools use the first 8 bytes of
- ``SHA-512(SHA-512(master_key))``, but this particular scheme is not
- required. Also, the master key need not be in the keyring yet when
- FS_IOC_SET_ENCRYPTION_POLICY is executed. However, it must be added
- before any files can be created in the encrypted directory.
- If the file is not yet encrypted, then FS_IOC_SET_ENCRYPTION_POLICY
- verifies that the file is an empty directory. If so, the specified
- encryption policy is assigned to the directory, turning it into an
- encrypted directory. After that, and after providing the
- corresponding master key as described in `Adding keys`_, all regular
- files, directories (recursively), and symlinks created in the
- directory will be encrypted, inheriting the same encryption policy.
- The filenames in the directory's entries will be encrypted as well.
- Alternatively, if the file is already encrypted, then
- FS_IOC_SET_ENCRYPTION_POLICY validates that the specified encryption
- policy exactly matches the actual one. If they match, then the ioctl
- returns 0. Otherwise, it fails with EEXIST. This works on both
- regular files and directories, including nonempty directories.
- Note that the ext4 filesystem does not allow the root directory to be
- encrypted, even if it is empty. Users who want to encrypt an entire
- filesystem with one key should consider using dm-crypt instead.
- FS_IOC_SET_ENCRYPTION_POLICY can fail with the following errors:
- - ``EACCES``: the file is not owned by the process's uid, nor does the
- process have the CAP_FOWNER capability in a namespace with the file
- owner's uid mapped
- - ``EEXIST``: the file is already encrypted with an encryption policy
- different from the one specified
- - ``EINVAL``: an invalid encryption policy was specified (invalid
- version, mode(s), or flags)
- - ``ENOTDIR``: the file is unencrypted and is a regular file, not a
- directory
- - ``ENOTEMPTY``: the file is unencrypted and is a nonempty directory
- - ``ENOTTY``: this type of filesystem does not implement encryption
- - ``EOPNOTSUPP``: the kernel was not configured with encryption
- support for filesystems, or the filesystem superblock has not
- had encryption enabled on it. (For example, to use encryption on an
- ext4 filesystem, CONFIG_FS_ENCRYPTION must be enabled in the
- kernel config, and the superblock must have had the "encrypt"
- feature flag enabled using ``tune2fs -O encrypt`` or ``mkfs.ext4 -O
- encrypt``.)
- - ``EPERM``: this directory may not be encrypted, e.g. because it is
- the root directory of an ext4 filesystem
- - ``EROFS``: the filesystem is readonly
- Getting an encryption policy
- ----------------------------
- The FS_IOC_GET_ENCRYPTION_POLICY ioctl retrieves the :c:type:`struct
- fscrypt_policy`, if any, for a directory or regular file. See above
- for the struct definition. No additional permissions are required
- beyond the ability to open the file.
- FS_IOC_GET_ENCRYPTION_POLICY can fail with the following errors:
- - ``EINVAL``: the file is encrypted, but it uses an unrecognized
- encryption context format
- - ``ENODATA``: the file is not encrypted
- - ``ENOTTY``: this type of filesystem does not implement encryption
- - ``EOPNOTSUPP``: the kernel was not configured with encryption
- support for this filesystem
- Note: if you only need to know whether a file is encrypted or not, on
- most filesystems it is also possible to use the FS_IOC_GETFLAGS ioctl
- and check for FS_ENCRYPT_FL, or to use the statx() system call and
- check for STATX_ATTR_ENCRYPTED in stx_attributes.
- Getting the per-filesystem salt
- -------------------------------
- Some filesystems, such as ext4 and F2FS, also support the deprecated
- ioctl FS_IOC_GET_ENCRYPTION_PWSALT. This ioctl retrieves a randomly
- generated 16-byte value stored in the filesystem superblock. This
- value is intended to used as a salt when deriving an encryption key
- from a passphrase or other low-entropy user credential.
- FS_IOC_GET_ENCRYPTION_PWSALT is deprecated. Instead, prefer to
- generate and manage any needed salt(s) in userspace.
- Adding keys
- -----------
- To provide a master key, userspace must add it to an appropriate
- keyring using the add_key() system call (see:
- ``Documentation/security/keys/core.rst``). The key type must be
- "logon"; keys of this type are kept in kernel memory and cannot be
- read back by userspace. The key description must be "fscrypt:"
- followed by the 16-character lower case hex representation of the
- ``master_key_descriptor`` that was set in the encryption policy. The
- key payload must conform to the following structure::
- #define FS_MAX_KEY_SIZE 64
- struct fscrypt_key {
- u32 mode;
- u8 raw[FS_MAX_KEY_SIZE];
- u32 size;
- };
- ``mode`` is ignored; just set it to 0. The actual key is provided in
- ``raw`` with ``size`` indicating its size in bytes. That is, the
- bytes ``raw[0..size-1]`` (inclusive) are the actual key.
- The key description prefix "fscrypt:" may alternatively be replaced
- with a filesystem-specific prefix such as "ext4:". However, the
- filesystem-specific prefixes are deprecated and should not be used in
- new programs.
- There are several different types of keyrings in which encryption keys
- may be placed, such as a session keyring, a user session keyring, or a
- user keyring. Each key must be placed in a keyring that is "attached"
- to all processes that might need to access files encrypted with it, in
- the sense that request_key() will find the key. Generally, if only
- processes belonging to a specific user need to access a given
- encrypted directory and no session keyring has been installed, then
- that directory's key should be placed in that user's user session
- keyring or user keyring. Otherwise, a session keyring should be
- installed if needed, and the key should be linked into that session
- keyring, or in a keyring linked into that session keyring.
- Note: introducing the complex visibility semantics of keyrings here
- was arguably a mistake --- especially given that by design, after any
- process successfully opens an encrypted file (thereby setting up the
- per-file key), possessing the keyring key is not actually required for
- any process to read/write the file until its in-memory inode is
- evicted. In the future there probably should be a way to provide keys
- directly to the filesystem instead, which would make the intended
- semantics clearer.
- Access semantics
- ================
- With the key
- ------------
- With the encryption key, encrypted regular files, directories, and
- symlinks behave very similarly to their unencrypted counterparts ---
- after all, the encryption is intended to be transparent. However,
- astute users may notice some differences in behavior:
- - Unencrypted files, or files encrypted with a different encryption
- policy (i.e. different key, modes, or flags), cannot be renamed or
- linked into an encrypted directory; see `Encryption policy
- enforcement`_. Attempts to do so will fail with EXDEV. However,
- encrypted files can be renamed within an encrypted directory, or
- into an unencrypted directory.
- Note: "moving" an unencrypted file into an encrypted directory, e.g.
- with the `mv` program, is implemented in userspace by a copy
- followed by a delete. Be aware that the original unencrypted data
- may remain recoverable from free space on the disk; prefer to keep
- all files encrypted from the very beginning. The `shred` program
- may be used to overwrite the source files but isn't guaranteed to be
- effective on all filesystems and storage devices.
- - Direct I/O is not supported on encrypted files. Attempts to use
- direct I/O on such files will fall back to buffered I/O.
- - The fallocate operations FALLOC_FL_COLLAPSE_RANGE,
- FALLOC_FL_INSERT_RANGE, and FALLOC_FL_ZERO_RANGE are not supported
- on encrypted files and will fail with EOPNOTSUPP.
- - Online defragmentation of encrypted files is not supported. The
- EXT4_IOC_MOVE_EXT and F2FS_IOC_MOVE_RANGE ioctls will fail with
- EOPNOTSUPP.
- - The ext4 filesystem does not support data journaling with encrypted
- regular files. It will fall back to ordered data mode instead.
- - DAX (Direct Access) is not supported on encrypted files.
- - The st_size of an encrypted symlink will not necessarily give the
- length of the symlink target as required by POSIX. It will actually
- give the length of the ciphertext, which will be slightly longer
- than the plaintext due to NUL-padding and an extra 2-byte overhead.
- - The maximum length of an encrypted symlink is 2 bytes shorter than
- the maximum length of an unencrypted symlink. For example, on an
- EXT4 filesystem with a 4K block size, unencrypted symlinks can be up
- to 4095 bytes long, while encrypted symlinks can only be up to 4093
- bytes long (both lengths excluding the terminating null).
- Note that mmap *is* supported. This is possible because the pagecache
- for an encrypted file contains the plaintext, not the ciphertext.
- Without the key
- ---------------
- Some filesystem operations may be performed on encrypted regular
- files, directories, and symlinks even before their encryption key has
- been provided:
- - File metadata may be read, e.g. using stat().
- - Directories may be listed, in which case the filenames will be
- listed in an encoded form derived from their ciphertext. The
- current encoding algorithm is described in `Filename hashing and
- encoding`_. The algorithm is subject to change, but it is
- guaranteed that the presented filenames will be no longer than
- NAME_MAX bytes, will not contain the ``/`` or ``\0`` characters, and
- will uniquely identify directory entries.
- The ``.`` and ``..`` directory entries are special. They are always
- present and are not encrypted or encoded.
- - Files may be deleted. That is, nondirectory files may be deleted
- with unlink() as usual, and empty directories may be deleted with
- rmdir() as usual. Therefore, ``rm`` and ``rm -r`` will work as
- expected.
- - Symlink targets may be read and followed, but they will be presented
- in encrypted form, similar to filenames in directories. Hence, they
- are unlikely to point to anywhere useful.
- Without the key, regular files cannot be opened or truncated.
- Attempts to do so will fail with ENOKEY. This implies that any
- regular file operations that require a file descriptor, such as
- read(), write(), mmap(), fallocate(), and ioctl(), are also forbidden.
- Also without the key, files of any type (including directories) cannot
- be created or linked into an encrypted directory, nor can a name in an
- encrypted directory be the source or target of a rename, nor can an
- O_TMPFILE temporary file be created in an encrypted directory. All
- such operations will fail with ENOKEY.
- It is not currently possible to backup and restore encrypted files
- without the encryption key. This would require special APIs which
- have not yet been implemented.
- Encryption policy enforcement
- =============================
- After an encryption policy has been set on a directory, all regular
- files, directories, and symbolic links created in that directory
- (recursively) will inherit that encryption policy. Special files ---
- that is, named pipes, device nodes, and UNIX domain sockets --- will
- not be encrypted.
- Except for those special files, it is forbidden to have unencrypted
- files, or files encrypted with a different encryption policy, in an
- encrypted directory tree. Attempts to link or rename such a file into
- an encrypted directory will fail with EXDEV. This is also enforced
- during ->lookup() to provide limited protection against offline
- attacks that try to disable or downgrade encryption in known locations
- where applications may later write sensitive data. It is recommended
- that systems implementing a form of "verified boot" take advantage of
- this by validating all top-level encryption policies prior to access.
- Implementation details
- ======================
- Encryption context
- ------------------
- An encryption policy is represented on-disk by a :c:type:`struct
- fscrypt_context`. It is up to individual filesystems to decide where
- to store it, but normally it would be stored in a hidden extended
- attribute. It should *not* be exposed by the xattr-related system
- calls such as getxattr() and setxattr() because of the special
- semantics of the encryption xattr. (In particular, there would be
- much confusion if an encryption policy were to be added to or removed
- from anything other than an empty directory.) The struct is defined
- as follows::
- #define FS_KEY_DESCRIPTOR_SIZE 8
- #define FS_KEY_DERIVATION_NONCE_SIZE 16
- struct fscrypt_context {
- u8 format;
- u8 contents_encryption_mode;
- u8 filenames_encryption_mode;
- u8 flags;
- u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
- u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
- };
- Note that :c:type:`struct fscrypt_context` contains the same
- information as :c:type:`struct fscrypt_policy` (see `Setting an
- encryption policy`_), except that :c:type:`struct fscrypt_context`
- also contains a nonce. The nonce is randomly generated by the kernel
- and is used to derive the inode's encryption key as described in
- `Per-file keys`_.
- Data path changes
- -----------------
- For the read path (->readpage()) of regular files, filesystems can
- read the ciphertext into the page cache and decrypt it in-place. The
- page lock must be held until decryption has finished, to prevent the
- page from becoming visible to userspace prematurely.
- For the write path (->writepage()) of regular files, filesystems
- cannot encrypt data in-place in the page cache, since the cached
- plaintext must be preserved. Instead, filesystems must encrypt into a
- temporary buffer or "bounce page", then write out the temporary
- buffer. Some filesystems, such as UBIFS, already use temporary
- buffers regardless of encryption. Other filesystems, such as ext4 and
- F2FS, have to allocate bounce pages specially for encryption.
- Filename hashing and encoding
- -----------------------------
- Modern filesystems accelerate directory lookups by using indexed
- directories. An indexed directory is organized as a tree keyed by
- filename hashes. When a ->lookup() is requested, the filesystem
- normally hashes the filename being looked up so that it can quickly
- find the corresponding directory entry, if any.
- With encryption, lookups must be supported and efficient both with and
- without the encryption key. Clearly, it would not work to hash the
- plaintext filenames, since the plaintext filenames are unavailable
- without the key. (Hashing the plaintext filenames would also make it
- impossible for the filesystem's fsck tool to optimize encrypted
- directories.) Instead, filesystems hash the ciphertext filenames,
- i.e. the bytes actually stored on-disk in the directory entries. When
- asked to do a ->lookup() with the key, the filesystem just encrypts
- the user-supplied name to get the ciphertext.
- Lookups without the key are more complicated. The raw ciphertext may
- contain the ``\0`` and ``/`` characters, which are illegal in
- filenames. Therefore, readdir() must base64-encode the ciphertext for
- presentation. For most filenames, this works fine; on ->lookup(), the
- filesystem just base64-decodes the user-supplied name to get back to
- the raw ciphertext.
- However, for very long filenames, base64 encoding would cause the
- filename length to exceed NAME_MAX. To prevent this, readdir()
- actually presents long filenames in an abbreviated form which encodes
- a strong "hash" of the ciphertext filename, along with the optional
- filesystem-specific hash(es) needed for directory lookups. This
- allows the filesystem to still, with a high degree of confidence, map
- the filename given in ->lookup() back to a particular directory entry
- that was previously listed by readdir(). See :c:type:`struct
- fscrypt_digested_name` in the source for more details.
- Note that the precise way that filenames are presented to userspace
- without the key is subject to change in the future. It is only meant
- as a way to temporarily present valid filenames so that commands like
- ``rm -r`` work as expected on encrypted directories.
|