요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
.. _inline_encryption:
=================
Inline Encryption
=================
Background
==========
Inline encryption hardware sits logically between memory and disk, and can
en/decrypt data as it goes in/out of the disk. For each I/O request, software
can control exactly how the inline encryption hardware will en/decrypt the data
in terms of key, algorithm, data unit size (the granularity of en/decryption),
and data unit number (a value that determines the initialization vector(s)).
Some inline encryption hardware accepts all encryption parameters including raw
keys directly in low-level I/O requests. However, most inline encryption
hardware instead has a fixed number of "keyslots" and requires that the key,
algorithm, and data unit size first be programmed into a keyslot. Each
low-level I/O request then just contains a keyslot index and data unit number.
Note that inline encryption hardware is very different from traditional crypto
accelerators, which are supported through the kernel crypto API. Traditional
crypto accelerators operate on memory regions, whereas inline encryption
hardware operates on I/O requests. Thus, inline encryption hardware needs to be
managed by the block layer, not the kernel crypto API.
Inline encryption hardware is also very different from "self-encrypting drives",
such as those based on the TCG Opal or ATA Security standards. Self-encrypting
drives don't provide fine-grained control of encryption and provide no way to
verify the correctness of the resulting ciphertext. Inline encryption hardware
provides fine-grained control of encryption, including the choice of key and
initialization vector for each sector, and can be tested for correctness.
Objective
=========
We want to support inline encryption in the kernel. To make testing easier, we
also want support for falling back to the kernel crypto API when actual inline
encryption hardware is absent. We also want inline encryption to work with
layered devices like device-mapper and loopback (i.e. we want to be able to use
the inline encryption hardware of the underlying devices if present, or else
fall back to crypto API en/decryption).
Constraints and notes
=====================
- We need a way for upper layers (e.g. filesystems) to specify an encryption
context to use for en/decrypting a bio, and device drivers (e.g. UFSHCD) need
to be able to use that encryption context when they process the request.
Encryption contexts also introduce constraints on bio merging; the block layer
needs to be aware of these constraints.
- Different inline encryption hardware has different supported algorithms,
supported data unit sizes, maximum data unit numbers, etc. We call these
properties the "crypto capabilities". We need a way for device drivers to
advertise crypto capabilities to upper layers in a generic way.
- Inline encryption hardware usually (but not always) requires that keys be
programmed into keyslots before being used. Since programming keyslots may be
slow and there may not be very many keyslots, we shouldn't just program the
key for every I/O request, but rather keep track of which keys are in the
keyslots and reuse an already-programmed keyslot when possible.
- Upper layers typically define a specific end-of-life for crypto keys, e.g.
when an encrypted directory is locked or when a crypto mapping is torn down.
At these times, keys are wiped from memory. We must provide a way for upper
layers to also evict keys from any keyslots they are present in.
- When possible, device-mapper devices must be able to pass through the inline
encryption support of their underlying devices. However, it doesn't make
sense for device-mapper devices to have keyslots themselves.
Basic design
============
We introduce ``struct blk_crypto_key`` to represent an inline encryption key and
how it will be used. This includes the type of the key (raw or
hardware-wrapped); the actual bytes of the key; the size of the key; the
algorithm and data unit size the key will be used with; and the number of bytes
needed to represent the maximum data unit number the key will be used with.
We introduce ``struct bio_crypt_ctx`` to represent an encryption context. It
contains a data unit number and a pointer to a blk_crypto_key. We add pointers
to a bio_crypt_ctx to ``struct bio`` and ``struct request``; this allows users
of the block layer (e.g. filesystems) to provide an encryption context when
creating a bio and have it be passed down the stack for processing by the block
layer and device drivers. Note that the encryption context doesn't explicitly
say whether to encrypt or decrypt, as that is implicit from the direction of the
bio; WRITE means encrypt, and READ means decrypt.
We also introduce ``struct blk_crypto_profile`` to contain all generic inline
encryption-related state for a particular inline encryption device. The
blk_crypto_profile serves as the way that drivers for inline encryption hardware
advertise their crypto capabilities and provide certain functions (e.g.,
functions to program and evict keys) to upper layers. Each device driver that
wants to support inline encryption will construct a blk_crypto_profile, then
associate it with the disk's request_queue.
The blk_crypto_profile also manages the hardware's keyslots, when applicable.
This happens in the block layer, so that users of the block layer can just
specify encryption contexts and don't need to know about keyslots at all, nor do
device drivers need to care about most details of keyslot management.
Specifically, for each keyslot, the block layer (via the blk_crypto_profile)
keeps track of which blk_crypto_key that keyslot contains (if any), and how many
in-flight I/O requests are using it. When the block layer creates a
``struct request`` for a bio that has an encryption context, it grabs a keyslot
that already contains the key if possible. Otherwise it waits for an idle
keyslot (a keyslot that isn't in-use by any I/O), then programs the key into the
least-recently-used idle keyslot using the function the device driver provided.
In both cases, the resulting keyslot is stored in the ``crypt_keyslot`` field of
the request, where it is then accessible to device drivers and is released after
the request completes.
``struct request`` also contains a pointer to the original bio_crypt_ctx.
Requests can be built from multiple bios, and the block layer must take the
encryption context into account when trying to merge bios and requests. For two
bios/requests to be merged, they must have compatible encryption contexts: both
unencrypted, or both encrypted with the same key and contiguous data unit
numbers. Only the encryption context for the first bio in a request is
retained, since the remaining bios have been verified to be merge-compatible
with the first bio.
To make it possible for inline encryption to work with request_queue based
layered devices, when a request is cloned, its encryption context is cloned as
well. When the cloned request is submitted, it is then processed as usual; this
includes getting a keyslot from the clone's target device if needed.
blk-crypto-fallback
===================
It is desirable for the inline encryption support of upper layers (e.g.
filesystems) to be testable without real inline encryption hardware, and
likewise for the block layer's keyslot management logic. It is also desirable
to allow upper layers to just always use inline encryption rather than have to
implement encryption in multiple ways.
Therefore, we also introduce *blk-crypto-fallback*, which is an implementation
of inline encryption using the kernel crypto API. blk-crypto-fallback is built
into the block layer, so it works on any block device without any special setup.
Essentially, when a bio with an encryption context is submitted to a
block_device that doesn't support that encryption context, the block layer will
handle en/decryption of the bio using blk-crypto-fallback.
For encryption, the data cannot be encrypted in-place, as callers usually rely
on it being unmodified. Instead, blk-crypto-fallback allocates bounce pages,
fills a new bio with those bounce pages, encrypts the data into those bounce
pages, and submits that "bounce" bio. When the bounce bio completes,
blk-crypto-fallback completes the original bio. If the original bio is too
large, multiple bounce bios may be required; see the code for details.
For decryption, blk-crypto-fallback "wraps" the bio's completion callback
(``bi_complete``) and private data (``bi_private``) with its own, unsets the
bio's encryption context, then submits the bio. If the read completes
successfully, blk-crypto-fallback restores the bio's original completion
callback and private data, then decrypts the bio's data in-place using the
kernel crypto API. Decryption happens from a workqueue, as it may sleep.
Afterwards, blk-crypto-fallback completes the bio.
In both cases, the bios that blk-crypto-fallback submits no longer have an
encryption context. Therefore, lower layers only see standard unencrypted I/O.
blk-crypto-fallback also defines its own blk_crypto_profile and has its own
"keyslots"; its keyslots contain ``struct crypto_skcipher`` objects. The reason
for this is twofold. First, it allows the keyslot management logic to be tested
without actual inline encryption hardware. Second, similar to actual inline
encryption hardware, the crypto API doesn't accept keys directly in requests but
rather requires that keys be set ahead of time, and setting keys can be
expensive; moreover, allocating a crypto_skcipher can't happen on the I/O path
at all due to the locks it takes. Therefore, the concept of keyslots still
makes sense for blk-crypto-fallback.
Note that regardless of whether real inline encryption hardware or
blk-crypto-fallback is used, the ciphertext written to disk (and hence the
on-disk format of data) will be the same (assuming that both the inline
encryption hardware's implementation and the kernel crypto API's implementation
of the algorithm being used adhere to spec and function correctly).
blk-crypto-fallback is optional and is controlled by the
``CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK`` kernel configuration option.
API presented to users of the block layer
=========================================
``blk_crypto_config_supported()`` allows users to check ahead of time whether
inline encryption with particular crypto settings will work on a particular
block_device -- either via hardware or via blk-crypto-fallback. This function
takes in a ``struct blk_crypto_config`` which is like blk_crypto_key, but omits
the actual bytes of the key and instead just contains the algorithm, data unit
size, etc. This function can be useful if blk-crypto-fallback is disabled.
``blk_crypto_init_key()`` allows users to initialize a blk_crypto_key.
Users must call ``blk_crypto_start_using_key()`` before actually starting to use
a blk_crypto_key on a block_device (even if ``blk_crypto_config_supported()``
was called earlier). This is needed to initialize blk-crypto-fallback if it
will be needed. This must not be called from the data path, as this may have to
allocate resources, which may deadlock in that case.
Next, to attach an encryption context to a bio, users should call
``bio_crypt_set_ctx()``. This function allocates a bio_crypt_ctx and attaches
it to a bio, given the blk_crypto_key and the data unit number that will be used
for en/decryption. Users don't need to worry about freeing the bio_crypt_ctx
later, as that happens automatically when the bio is freed or reset.
Finally, when done using inline encryption with a blk_crypto_key on a
block_device, users must call ``blk_crypto_evict_key()``. This ensures that
the key is evicted from all keyslots it may be programmed into and unlinked from
any kernel data structures it may be linked into.
In summary, for users of the block layer, the lifecycle of a blk_crypto_key is
as follows:
1. ``blk_crypto_config_supported()`` (optional)
2. ``blk_crypto_init_key()``
3. ``blk_crypto_start_using_key()``
4. ``bio_crypt_set_ctx()`` (potentially many times)
5. ``blk_crypto_evict_key()`` (after all I/O has completed)
6. Zeroize the blk_crypto_key (this has no dedicated function)
If a blk_crypto_key is being used on multiple block_devices, then
``blk_crypto_config_supported()`` (if used), ``blk_crypto_start_using_key()``,
and ``blk_crypto_evict_key()`` must be called on each block_device.
API presented to device drivers
===============================
A device driver that wants to support inline encryption must set up a
blk_crypto_profile in the request_queue of its device. To do this, it first
must call ``blk_crypto_profile_init()`` (or its resource-managed variant
``devm_blk_crypto_profile_init()``), providing the number of keyslots.
Next, it must advertise its crypto capabilities by setting fields in the
blk_crypto_profile, e.g. ``modes_supported`` and ``max_dun_bytes_supported``.
It then must set function pointers in the ``ll_ops`` field of the
blk_crypto_profile to tell upper layers how to control the inline encryption
hardware, e.g. how to program and evict keyslots. Most drivers will need to
implement ``keyslot_program`` and ``keyslot_evict``. For details, see the
comments for ``struct blk_crypto_ll_ops``.
Once the driver registers a blk_crypto_profile with a request_queue, I/O
requests the driver receives via that queue may have an encryption context. All
encryption contexts will be compatible with the crypto capabilities declared in
the blk_crypto_profile, so drivers don't need to worry about handling
unsupported requests. Also, if a nonzero number of keyslots was declared in the
blk_crypto_profile, then all I/O requests that have an encryption context will
also have a keyslot which was already programmed with the appropriate key.
If the driver implements runtime suspend and its blk_crypto_ll_ops don't work
while the device is runtime-suspended, then the driver must also set the ``dev``
field of the blk_crypto_profile to point to the ``struct device`` that will be
resumed before any of the low-level operations are called.
If there are situations where the inline encryption hardware loses the contents
of its keyslots, e.g. device resets, the driver must handle reprogramming the
keyslots. To do this, the driver may call ``blk_crypto_reprogram_all_keys()``.
Finally, if the driver used ``blk_crypto_profile_init()`` instead of
``devm_blk_crypto_profile_init()``, then it is responsible for calling
``blk_crypto_profile_destroy()`` when the crypto profile is no longer needed.
Layered Devices
===============
Request queue based layered devices like dm-rq that wish to support inline
encryption need to create their own blk_crypto_profile for their request_queue,
and expose whatever functionality they choose. When a layered device wants to
pass a clone of that request to another request_queue, blk-crypto will
initialize and prepare the clone as necessary.
Interaction between inline encryption and blk integrity
=======================================================
At the time of this patch, there is no real hardware that supports both these
features. However, these features do interact with each other, and it's not
completely trivial to make them both work together properly. In particular,
when a WRITE bio wants to use inline encryption on a device that supports both
features, the bio will have an encryption context specified, after which
its integrity information is calculated (using the plaintext data, since
the encryption will happen while data is being written), and the data and
integrity info is sent to the device. Obviously, the integrity info must be
verified before the data is encrypted. After the data is encrypted, the device
must not store the integrity info that it received with the plaintext data
since that might reveal information about the plaintext data. As such, it must
re-generate the integrity info from the ciphertext data and store that on disk
instead. Another issue with storing the integrity info of the plaintext data is
that it changes the on disk format depending on whether hardware inline
encryption support is present or the kernel crypto API fallback is used (since
if the fallback is used, the device will receive the integrity info of the
ciphertext, not that of the plaintext).
Because there isn't any real hardware yet, it seems prudent to assume that
hardware implementations might not implement both features together correctly,
and disallow the combination for now. Whenever a device supports integrity, the
kernel will pretend that the device does not support hardware inline encryption
(by setting the blk_crypto_profile in the request_queue of the device to NULL).
When the crypto API fallback is enabled, this means that all bios with and
encryption context will use the fallback, and IO will complete as usual. When
the fallback is disabled, a bio with an encryption context will be failed.
.. _hardware_wrapped_keys:
Hardware-wrapped keys
=====================
Motivation and threat model
---------------------------
Linux storage encryption (dm-crypt, fscrypt, eCryptfs, etc.) traditionally
relies on the raw encryption key(s) being present in kernel memory so that the
encryption can be performed. This traditionally isn't seen as a problem because
the key(s) won't be present during an offline attack, which is the main type of
attack that storage encryption is intended to protect from.
However, there is an increasing desire to also protect users' data from other
types of attacks (to the extent possible), including:
- Cold boot attacks, where an attacker with physical access to a system suddenly
powers it off, then immediately dumps the system memory to extract recently
in-use encryption keys, then uses these keys to decrypt user data on-disk.
- Online attacks where the attacker is able to read kernel memory without fully
compromising the system, followed by an offline attack where any extracted
keys can be used to decrypt user data on-disk. An example of such an online
attack would be if the attacker is able to run some code on the system that
exploits a Meltdown-like vulnerability but is unable to escalate privileges.
- Online attacks where the attacker fully compromises the system, but their data
exfiltration is significantly time-limited and/or bandwidth-limited, so in
order to completely exfiltrate the data they need to extract the encryption
keys to use in a later offline attack.
Hardware-wrapped keys are a feature of inline encryption hardware that is
designed to protect users' data from the above attacks (to the extent possible),
without introducing limitations such as a maximum number of keys.
Note that it is impossible to **fully** protect users' data from these attacks.
Even in the attacks where the attacker "just" gets read access to kernel memory,
they can still extract any user data that is present in memory, including
plaintext pagecache pages of encrypted files. The focus here is just on
protecting the encryption keys, as those instantly give access to **all** user
data in any following offline attack, rather than just some of it (where which
data is included in that "some" might not be controlled by the attacker).
Solution overview
-----------------
Inline encryption hardware typically has "keyslots" into which software can
program keys for the hardware to use; the contents of keyslots typically can't
be read back by software. As such, the above security goals could be achieved
if the kernel simply erased its copy of the key(s) after programming them into
keyslot(s) and thereafter only referred to them via keyslot number.
However, that naive approach runs into a couple problems:
- It limits the number of unlocked keys to the number of keyslots, which
typically is a small number. In cases where there is only one encryption key
system-wide (e.g., a full-disk encryption key), that can be tolerable.
However, in general there can be many logged-in users with many different
keys, and/or many running applications with application-specific encrypted
storage areas. This is especially true if file-based encryption (e.g.
fscrypt) is being used.
- Inline crypto engines typically lose the contents of their keyslots if the
storage controller (usually UFS or eMMC) is reset. Resetting the storage
controller is a standard error recovery procedure that is executed if certain
types of storage errors occur, and such errors can occur at any time.
Therefore, when inline crypto is being used, the operating system must always
be ready to reprogram the keyslots without user intervention.
Thus, it is important for the kernel to still have a way to "remind" the
hardware about a key, without actually having the raw key itself.
Somewhat less importantly, it is also desirable that the raw keys are never
visible to software at all, even while being initially unlocked. This would
ensure that a read-only compromise of system memory will never allow a key to be
extracted to be used off-system, even if it occurs when a key is being unlocked.
To solve all these problems, some vendors of inline encryption hardware have
made their hardware support *hardware-wrapped keys*. Hardware-wrapped keys
are encrypted keys that can only be unwrapped (decrypted) and used by hardware
-- either by the inline encryption hardware itself, or by a dedicated hardware
block that can directly provision keys to the inline encryption hardware.
(We refer to them as "hardware-wrapped keys" rather than simply "wrapped keys"
to add some clarity in cases where there could be other types of wrapped keys,
such as in file-based encryption. Key wrapping is a commonly used technique.)
The key which wraps (encrypts) hardware-wrapped keys is a hardware-internal key
that is never exposed to software; it is either a persistent key (a "long-term
wrapping key") or a per-boot key (an "ephemeral wrapping key"). The long-term
wrapped form of the key is what is initially unlocked, but it is erased from
memory as soon as it is converted into an ephemerally-wrapped key. In-use
hardware-wrapped keys are always ephemerally-wrapped, not long-term wrapped.
As inline encryption hardware can only be used to encrypt/decrypt data on-disk,
the hardware also includes a level of indirection; it doesn't use the unwrapped
key directly for inline encryption, but rather derives both an inline encryption
key and a "software secret" from it. Software can use the "software secret" for
tasks that can't use the inline encryption hardware, such as filenames
encryption. The software secret is not protected from memory compromise.
Key hierarchy
-------------
Here is the key hierarchy for a hardware-wrapped key::
Hardware-wrapped key
|
|
<Hardware KDF>
|
-----------------------------
| |
Inline encryption key Software secret
The components are:
- *Hardware-wrapped key*: a key for the hardware's KDF (Key Derivation
Function), in ephemerally-wrapped form. The key wrapping algorithm is a
hardware implementation detail that doesn't impact kernel operation, but a
strong authenticated encryption algorithm such as AES-256-GCM is recommended.
- *Hardware KDF*: a KDF (Key Derivation Function) which the hardware uses to
derive subkeys after unwrapping the wrapped key. The hardware's choice of KDF
doesn't impact kernel operation, but it does need to be known for testing
purposes, and it's also assumed to have at least a 256-bit security strength.
All known hardware uses the SP800-108 KDF in Counter Mode with AES-256-CMAC,
with a particular choice of labels and contexts; new hardware should use this
already-vetted KDF.
- *Inline encryption key*: a derived key which the hardware directly provisions
to a keyslot of the inline encryption hardware, without exposing it to
software. In all known hardware, this will always be an AES-256-XTS key.
However, in principle other encryption algorithms could be supported too.
Hardware must derive distinct subkeys for each supported encryption algorithm.
- *Software secret*: a derived key which the hardware returns to software so
that software can use it for cryptographic tasks that can't use inline
encryption. This value is cryptographically isolated from the inline
encryption key, i.e. knowing one doesn't reveal the other. (The KDF ensures
this.) Currently, the software secret is always 32 bytes and thus is suitable
for cryptographic applications that require up to a 256-bit security strength.
Some use cases (e.g. full-disk encryption) won't require the software secret.
Example: in the case of fscrypt, the fscrypt master key (the key that protects a
particular set of encrypted directories) is made hardware-wrapped. The inline
encryption key is used as the file contents encryption key, while the software
secret (rather than the master key directly) is used to key fscrypt's KDF
(HKDF-SHA512) to derive other subkeys such as filenames encryption keys.
Note that currently this design assumes a single inline encryption key per
hardware-wrapped key, without any further key derivation. Thus, in the case of
fscrypt, currently hardware-wrapped keys are only compatible with the "inline
encryption optimized" settings, which use one file contents encryption key per
encryption policy rather than one per file. This design could be extended to
make the hardware derive per-file keys using per-file nonces passed down the
storage stack, and in fact some hardware already supports this; future work is
planned to remove this limitation by adding the corresponding kernel support.
Kernel support
--------------
The inline encryption support of the kernel's block layer ("blk-crypto") has
been extended to support hardware-wrapped keys as an alternative to raw keys,
when hardware support is available. This works in the following way:
- A ``key_types_supported`` field is added to the crypto capabilities in
``struct blk_crypto_profile``. This allows device drivers to declare that
they support raw keys, hardware-wrapped keys, or both.
- ``struct blk_crypto_key`` can now contain a hardware-wrapped key as an
alternative to a raw key; a ``key_type`` field is added to
``struct blk_crypto_config`` to distinguish between the different key types.
This allows users of blk-crypto to en/decrypt data using a hardware-wrapped
key in a way very similar to using a raw key.
- A new method ``blk_crypto_ll_ops::derive_sw_secret`` is added. Device drivers
that support hardware-wrapped keys must implement this method. Users of
blk-crypto can call ``blk_crypto_derive_sw_secret()`` to access this method.
- The programming and eviction of hardware-wrapped keys happens via
``blk_crypto_ll_ops::keyslot_program`` and
``blk_crypto_ll_ops::keyslot_evict``, just like it does for raw keys. If a
driver supports hardware-wrapped keys, then it must handle hardware-wrapped
keys being passed to these methods.
blk-crypto-fallback doesn't support hardware-wrapped keys. Therefore,
hardware-wrapped keys can only be used with actual inline encryption hardware.
All the above deals with hardware-wrapped keys in ephemerally-wrapped form only.
To get such keys in the first place, new block device ioctls have been added to
provide a generic interface to creating and preparing such keys:
- ``BLKCRYPTOIMPORTKEY`` converts a raw key to long-term wrapped form. It takes
in a pointer to a ``struct blk_crypto_import_key_arg``. The caller must set
``raw_key_ptr`` and ``raw_key_size`` to the pointer and size (in bytes) of the
raw key to import. On success, ``BLKCRYPTOIMPORTKEY`` returns 0 and writes
the resulting long-term wrapped key blob to the buffer pointed to by
``lt_key_ptr``, which is of maximum size ``lt_key_size``. It also updates
``lt_key_size`` to be the actual size of the key. On failure, it returns -1
and sets errno. An errno of ``EOPNOTSUPP`` indicates that the block device
does not support hardware-wrapped keys. An errno of ``EOVERFLOW`` indicates
that the output buffer did not have enough space for the key blob.
- ``BLKCRYPTOGENERATEKEY`` is like ``BLKCRYPTOIMPORTKEY``, but it has the
hardware generate the key instead of importing one. It takes in a pointer to
a ``struct blk_crypto_generate_key_arg``.
- ``BLKCRYPTOPREPAREKEY`` converts a key from long-term wrapped form to
ephemerally-wrapped form. It takes in a pointer to a ``struct
blk_crypto_prepare_key_arg``. The caller must set ``lt_key_ptr`` and
``lt_key_size`` to the pointer and size (in bytes) of the long-term wrapped
key blob to convert. On success, ``BLKCRYPTOPREPAREKEY`` returns 0 and writes
the resulting ephemerally-wrapped key blob to the buffer pointed to by
``eph_key_ptr``, which is of maximum size ``eph_key_size``. It also updates
``eph_key_size`` to be the actual size of the key. On failure, it returns -1
and sets errno. Errno values of ``EOPNOTSUPP`` and ``EOVERFLOW`` mean the
same as they do for ``BLKCRYPTOIMPORTKEY``. An errno of ``EBADMSG`` indicates
that the long-term wrapped key is invalid.
Userspace needs to use either ``BLKCRYPTOIMPORTKEY`` or ``BLKCRYPTOGENERATEKEY``
once to create a key, and then ``BLKCRYPTOPREPAREKEY`` each time the key is
unlocked and added to the kernel. Note that these ioctls have no relevance for
raw keys; they are only for hardware-wrapped keys.
Testability
-----------
Both the hardware KDF and the inline encryption itself are well-defined
algorithms that don't depend on any secrets other than the unwrapped key.
Therefore, if the unwrapped key is known to software, these algorithms can be
reproduced in software in order to verify the ciphertext that is written to disk
by the inline encryption hardware.
However, the unwrapped key will only be known to software for testing if the
"import" functionality is used. Proper testing is not possible in the
"generate" case where the hardware generates the key itself. The correct
operation of the "generate" mode thus relies on the security and correctness of
the hardware RNG and its use to generate the key, as well as the testing of the
"import" mode as that should cover all parts other than the key generation.
For an example of a test that verifies the ciphertext written to disk in the
"import" mode, see the fscrypt hardware-wrapped key tests in xfstests, or
`Android's vts_kernel_encryption_test
<https://android.googlesource.com/platform/test/vts-testcase/kernel/+/refs/heads/main/encryption/>`_.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
inline encryption 배경
1-36이 문서는 `SPDX-License-Identifier: GPL-2.0`으로 배포되며 `_inline_encryption` anchor를 정의합니다. inline encryption hardware는 논리적으로 memory와 disk 사이에 있으며 data가 disk로 들어가거나 나올 때 encrypt/decrypt할 수 있습니다.
software는 각 I/O request마다 key, algorithm, data unit size, data unit number를 지정해 hardware 동작을 정밀하게 제어합니다. data unit size는 encryption/decryption granularity이고 data unit number는 initialization vector를 결정하는 값입니다.
일부 hardware는 raw key를 포함한 모든 encryption parameter를 low-level I/O request에서 직접 받습니다. 하지만 대부분은 고정된 수의 `keyslot`을 제공하며 key, algorithm, data unit size를 먼저 keyslot에 program해야 합니다. 이후 각 low-level request에는 keyslot index와 data unit number만 넣습니다.
inline encryption hardware는 kernel crypto API가 지원하는 traditional crypto accelerator와 매우 다릅니다. traditional accelerator는 memory region에 작동하지만 inline encryption hardware는 I/O request에 작동하므로 kernel crypto API가 아니라 block layer가 관리해야 합니다.
TCG Opal이나 ATA Security 표준 기반 `self-encrypting drive`와도 다릅니다. self-encrypting drive는 encryption을 세밀하게 제어할 수 없고 생성된 ciphertext의 correctness를 검증할 방법도 없습니다. inline encryption hardware는 sector마다 key와 initialization vector를 선택하는 등 세밀하게 제어할 수 있으며 correctness test도 가능합니다.
목표와 제약
37-75kernel에서 inline encryption을 지원하되 실제 hardware가 없을 때는 test가 쉽도록 kernel crypto API fallback을 지원해야 합니다. device-mapper와 loopback 같은 layered device에서도 underlying device의 hardware를 사용할 수 있으면 사용하고, 그렇지 않으면 crypto API encryption/decryption으로 fallback해야 합니다.
- filesystem 같은 upper layer가 `bio`의 encryption/decryption에 쓸 encryption context를 지정하고 UFSHCD 같은 device driver가 request 처리 시 그 context를 사용할 방법이 필요합니다. encryption context는 bio merge 제약도 만들므로 block layer가 이를 알아야 합니다.
- hardware마다 지원 algorithm, data unit size, maximum data unit number 등이 다릅니다. 이 `crypto capabilities`를 device driver가 generic한 방식으로 upper layer에 알릴 수 있어야 합니다.
- keyslot programming은 느릴 수 있고 keyslot 수도 적으므로 request마다 key를 program해서는 안 됩니다. 각 keyslot의 key를 추적하고 이미 program된 keyslot을 가능하면 재사용해야 합니다.
- encrypted directory lock이나 crypto mapping 해제처럼 upper layer가 정한 key end-of-life 시점에는 memory에서 key를 지웁니다. upper layer가 그 key가 들어 있는 모든 keyslot에서도 key를 evict할 방법을 제공해야 합니다.
- 가능하면 device-mapper device는 underlying device의 inline encryption 지원을 pass through해야 합니다. 그러나 device-mapper 자체가 keyslot을 갖는 것은 타당하지 않습니다.
기본 구조체와 profile
76-106`struct blk_crypto_key`는 inline encryption key와 사용 방식을 나타냅니다. raw 또는 hardware-wrapped인 key type, 실제 key byte, key size, 함께 사용할 algorithm과 data unit size, 사용할 maximum data unit number를 나타내는 데 필요한 byte 수를 포함합니다.
`struct bio_crypt_ctx`는 encryption context를 나타내며 data unit number와 `blk_crypto_key` pointer를 담습니다. `struct bio`와 `struct request`에 `bio_crypt_ctx` pointer를 추가해 filesystem 같은 block layer user가 `bio` 생성 시 context를 제공하고 block layer와 device driver까지 stack 아래로 전달하게 합니다.
encryption context는 encrypt인지 decrypt인지 명시하지 않습니다. `bio` direction에서 암시되기 때문입니다. WRITE는 encrypt, READ는 decrypt를 뜻합니다.
`struct blk_crypto_profile`은 특정 inline encryption device의 generic inline-encryption state를 모두 담습니다. hardware driver는 이 profile로 crypto capabilities와 key program·evict 같은 function을 upper layer에 제공합니다. inline encryption을 지원하는 driver는 profile을 구성해 disk의 `request_queue`와 연결합니다.
해당되는 경우 `blk_crypto_profile`이 hardware keyslot도 block layer에서 관리합니다. block layer user는 encryption context만 지정하면 되고 keyslot을 알 필요가 없으며, device driver도 대부분의 keyslot management detail을 다루지 않아도 됩니다.
keyslot 할당·merge·clone
107-131block layer는 `blk_crypto_profile`을 통해 각 keyslot이 어떤 `blk_crypto_key`를 포함하는지와 이를 사용하는 in-flight I/O request 수를 추적합니다. encryption context가 있는 `bio`에서 `struct request`를 만들 때 가능한 경우 이미 key가 있는 keyslot을 잡습니다.
그렇지 않으면 어떤 I/O도 사용하지 않는 idle keyslot을 기다린 뒤 device driver가 제공한 function으로 least-recently-used idle keyslot에 key를 program합니다. 결과 keyslot은 request의 `crypt_keyslot` field에 저장되어 driver가 접근할 수 있고 request 완료 후 release됩니다.
`struct request`는 원본 `bio_crypt_ctx` pointer도 포함합니다. request는 여러 `bio`로 만들 수 있으므로 merge 시 encryption context를 고려해야 합니다. 두 bio/request는 둘 다 unencrypted이거나, 같은 key로 encrypted되고 data unit number가 연속될 때만 merge할 수 있습니다.
나머지 bio는 첫 bio와 merge-compatible임이 검증되므로 request에는 첫 bio의 encryption context만 유지합니다. `request_queue` 기반 layered device에서 request를 clone할 때 encryption context도 clone합니다. clone을 submit하면 일반 경로로 처리되며 필요하면 clone target device에서 keyslot을 얻습니다.
blk-crypto-fallback 처리 경로
132-165upper layer와 block layer keyslot management logic은 실제 inline encryption hardware 없이도 test할 수 있어야 합니다. 또한 upper layer가 여러 encryption 방식을 각각 구현하지 않고 항상 inline encryption interface를 사용할 수 있으면 좋습니다.
`blk-crypto-fallback`은 kernel crypto API로 inline encryption을 구현합니다. block layer에 내장되어 특별한 설정 없이 모든 block device에서 동작합니다. encryption context가 있는 `bio`를 해당 context를 지원하지 않는 `block_device`에 submit하면 block layer가 fallback으로 encrypt/decrypt합니다.
encryption에서는 caller가 원본 data가 바뀌지 않기를 기대하므로 in-place encryption을 할 수 없습니다. fallback은 bounce page를 할당하고 이 page로 새 `bio`를 채운 뒤 data를 encrypt해 `bounce bio`를 submit합니다. bounce bio가 완료되면 원본 bio를 완료합니다. 원본 bio가 너무 크면 bounce bio가 여러 개 필요할 수 있습니다.
decryption에서는 fallback이 bio completion callback `bi_complete`와 private data `bi_private`를 자체 값으로 wrap하고 encryption context를 해제한 뒤 bio를 submit합니다. read가 성공하면 원래 callback과 private data를 복구하고 kernel crypto API로 bio data를 in-place decrypt합니다.
decryption은 sleep할 수 있어 workqueue에서 수행하며 이후 bio를 완료합니다. 두 경로 모두 fallback이 submit하는 bio에는 encryption context가 더 이상 없으므로 lower layer는 standard unencrypted I/O만 봅니다.
fallback keyslot과 설정
166-184`blk-crypto-fallback`도 자체 `blk_crypto_profile`과 `keyslot`을 정의하며 keyslot에는 `struct crypto_skcipher` object가 들어 있습니다. 첫째, 실제 hardware 없이 keyslot management logic을 test할 수 있기 때문입니다.
둘째, crypto API도 실제 inline encryption hardware처럼 request에서 key를 직접 받지 않고 미리 설정해야 하며 key 설정 비용이 클 수 있습니다. 또한 lock 때문에 I/O path에서는 `crypto_skcipher` 자체를 할당할 수도 없습니다. 따라서 fallback에도 keyslot 개념이 타당합니다.
실제 hardware를 쓰든 fallback을 쓰든 사용 algorithm의 두 구현이 specification을 준수하고 올바르게 동작한다면 disk에 기록되는 ciphertext와 on-disk data format은 같습니다.
`blk-crypto-fallback`은 선택 기능이며 kernel configuration option `CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK`이 제어합니다.
block layer user API와 key lifecycle
185-227`blk_crypto_config_supported()`는 특정 crypto setting의 inline encryption이 특정 `block_device`에서 hardware 또는 fallback을 통해 동작할지 미리 확인합니다. `struct blk_crypto_config`를 받는데 이는 `blk_crypto_key`와 비슷하지만 실제 key byte를 생략하고 algorithm, data unit size 등만 포함합니다. fallback이 disabled인 경우 특히 유용합니다.
`blk_crypto_init_key()`는 `blk_crypto_key`를 initialize합니다.
사용자는 실제 사용 전에 `blk_crypto_start_using_key()`를 호출해야 하며, 앞서 `blk_crypto_config_supported()`를 호출했더라도 마찬가지입니다. 필요할 경우 fallback을 initialize하기 위한 절차입니다. resource allocation으로 deadlock이 날 수 있으므로 data path에서 호출해서는 안 됩니다.
`bio`에 encryption context를 연결하려면 `bio_crypt_set_ctx()`를 호출합니다. 이 함수는 `blk_crypto_key`와 encryption/decryption에 쓸 data unit number를 받아 `bio_crypt_ctx`를 할당하고 bio에 연결합니다. bio가 free 또는 reset될 때 자동 해제되므로 user가 따로 free할 필요는 없습니다.
특정 `block_device`에서 `blk_crypto_key` 사용을 마치면 `blk_crypto_evict_key()`를 호출해야 합니다. key가 program되었을 수 있는 모든 keyslot에서 evict하고 연결된 kernel data structure에서 unlink합니다.
block layer user가 따라야 하는 `blk_crypto_key` lifecycle은 다음과 같습니다.
- 1. `blk_crypto_config_supported()` (optional)
- 2. `blk_crypto_init_key()`
- 3. `blk_crypto_start_using_key()`
- 4. `bio_crypt_set_ctx()` (여러 번 가능)
- 5. 모든 I/O 완료 후 `blk_crypto_evict_key()`
- 6. `blk_crypto_key` zeroize (전용 function 없음)
하나의 `blk_crypto_key`를 여러 `block_device`에서 사용한다면 `blk_crypto_config_supported()`를 사용할 경우 각 device에서 호출하고, `blk_crypto_start_using_key()`와 `blk_crypto_evict_key()`도 각 device마다 호출해야 합니다.
device driver API
228-265inline encryption을 지원하려는 device driver는 device `request_queue`에 `blk_crypto_profile`을 설정해야 합니다. 먼저 keyslot 수를 제공해 `blk_crypto_profile_init()` 또는 resource-managed variant인 `devm_blk_crypto_profile_init()`을 호출합니다.
그 다음 profile의 `modes_supported`, `max_dun_bytes_supported` 같은 field를 설정해 crypto capabilities를 알립니다.
이어서 profile의 `ll_ops` field에 function pointer를 설정해 keyslot program·evict 같은 hardware 제어 방법을 upper layer에 제공합니다. 대부분 driver는 `keyslot_program`과 `keyslot_evict`를 구현해야 하며 자세한 내용은 `struct blk_crypto_ll_ops` comment를 참조합니다.
profile을 `request_queue`에 register하면 그 queue에서 받는 I/O request에 encryption context가 있을 수 있습니다. 모든 context는 profile이 선언한 capability와 호환되므로 unsupported request 처리를 걱정할 필요가 없습니다.
profile이 0보다 큰 keyslot 수를 선언했다면 encryption context가 있는 모든 request에는 적절한 key가 이미 program된 keyslot도 있습니다.
driver가 runtime suspend를 구현하고 device가 runtime-suspended일 때 `blk_crypto_ll_ops`가 동작하지 않는다면 profile의 `dev` field가 low-level operation 전에 resume할 `struct device`를 가리키게 해야 합니다.
device reset 등으로 hardware keyslot 내용을 잃을 수 있다면 driver가 reprogramming을 처리해야 하며 `blk_crypto_reprogram_all_keys()`를 호출할 수 있습니다.
`devm_blk_crypto_profile_init()` 대신 `blk_crypto_profile_init()`을 사용했다면 crypto profile이 더 필요하지 않을 때 `blk_crypto_profile_destroy()`를 호출할 책임도 driver에게 있습니다.
layered device와 blk integrity 상호작용
266-304dm-rq처럼 request queue 기반 layered device가 inline encryption을 지원하려면 자체 `request_queue`용 `blk_crypto_profile`을 만들고 원하는 기능을 노출해야 합니다. 다른 `request_queue`로 request clone을 보낼 때 blk-crypto가 필요에 따라 clone을 initialize하고 prepare합니다.
이 문서 작성 시점에는 inline encryption과 blk integrity를 모두 지원하는 실제 hardware가 없습니다. 두 기능을 함께 올바르게 동작시키는 일도 단순하지 않습니다.
두 기능을 지원하는 device에서 WRITE bio가 inline encryption을 요청하면 encryption context를 지정한 뒤 plaintext data로 integrity information을 계산합니다. encryption은 write 중에 일어나기 때문입니다. device로 data와 integrity information을 보내며, encrypt하기 전에 integrity information을 검증해야 합니다.
encryption 후에는 plaintext integrity information이 plaintext 정보를 노출할 수 있으므로 device가 이를 저장해서는 안 됩니다. ciphertext data에서 integrity information을 다시 생성해 disk에 저장해야 합니다.
plaintext integrity information을 저장하면 hardware inline encryption 유무와 kernel crypto API fallback 사용 여부에 따라 on-disk format도 달라집니다. fallback에서는 device가 plaintext가 아니라 ciphertext의 integrity information을 받기 때문입니다.
실제 hardware가 아직 없으므로 당분간 조합을 금지합니다. device가 integrity를 지원하면 kernel은 device `request_queue`의 `blk_crypto_profile`을 NULL로 설정해 hardware inline encryption을 지원하지 않는 것처럼 처리합니다.
crypto API fallback이 enabled이면 encryption context가 있는 모든 bio가 fallback을 사용하고 I/O는 정상 완료됩니다. fallback이 disabled이면 encryption context가 있는 bio는 fail됩니다.
hardware-wrapped key의 동기와 threat model
305-348`_hardware_wrapped_keys` anchor는 hardware-wrapped key 절을 가리킵니다. Linux storage encryption인 dm-crypt, fscrypt, eCryptfs 등은 전통적으로 encryption을 수행할 raw key가 kernel memory에 있어야 합니다. storage encryption의 주된 위협인 offline attack 중에는 key가 memory에 없으므로 보통 문제로 보지 않았습니다.
하지만 가능한 범위에서 다음 공격으로부터 user data도 보호하려는 요구가 커지고 있습니다.
- cold boot attack: physical access를 얻은 attacker가 system 전원을 갑자기 끄고 즉시 memory를 dump해 최근 사용한 encryption key를 추출한 뒤 on-disk user data를 decrypt합니다.
- system 전체를 compromise하지 않고 kernel memory를 읽는 online attack 뒤 추출한 key로 offline attack을 수행합니다. privilege escalation 없이 Meltdown-like vulnerability를 exploit하는 code를 실행하는 경우가 예입니다.
- system을 완전히 compromise했지만 data exfiltration 시간 또는 bandwidth가 크게 제한된 online attack에서, 나중 offline attack에 사용할 encryption key를 먼저 추출합니다.
hardware-wrapped key는 최대 key 수 같은 제한을 만들지 않으면서 가능한 범위에서 위 공격으로부터 user data를 보호하도록 설계된 inline encryption hardware 기능입니다.
이 공격에서 user data를 완전히 보호하는 것은 불가능합니다. attacker가 kernel memory read access만 얻어도 encrypted file의 plaintext pagecache page 등 memory에 있는 user data를 추출할 수 있습니다. 여기서는 이후 offline attack에서 모든 user data에 즉시 접근하게 하는 encryption key 보호에 집중합니다.
hardware-wrapped key 해법
349-406inline encryption hardware의 keyslot 내용은 보통 software가 다시 읽을 수 없습니다. 따라서 kernel이 keyslot에 key를 program한 뒤 자체 copy를 지우고 이후 keyslot number로만 참조하면 앞선 보안 목표를 달성할 수 있어 보입니다.
하지만 이 단순한 방식에는 두 문제가 있습니다.
- unlock 가능한 key 수가 보통 적은 keyslot 수로 제한됩니다. system-wide full-disk encryption key 하나만 있으면 견딜 수 있지만, 일반적으로 여러 login user의 여러 key나 application-specific encrypted storage area가 많을 수 있으며 fscrypt 같은 file-based encryption에서는 특히 그렇습니다.
- storage controller, 보통 UFS나 eMMC를 reset하면 inline crypto engine이 keyslot 내용을 잃는 경우가 많습니다. controller reset은 언제든 생길 수 있는 storage error의 표준 recovery 절차이므로 operating system은 user 개입 없이 keyslot을 항상 reprogram할 준비가 되어 있어야 합니다.
따라서 kernel은 raw key 자체를 보유하지 않으면서도 hardware에 key를 다시 알려 줄 방법이 필요합니다. 중요도는 조금 낮지만 처음 unlock하는 동안조차 raw key가 software에 전혀 보이지 않으면 read-only memory compromise로도 off-system에서 쓸 key를 추출할 수 없습니다.
이를 위해 일부 vendor hardware는 `hardware-wrapped key`를 지원합니다. 이는 inline encryption hardware 자체 또는 key를 직접 provision하는 전용 hardware block만 unwrap하여 사용할 수 있는 encrypted key입니다. file-based encryption의 다른 wrapped key와 구분하려고 단순히 wrapped key가 아니라 hardware-wrapped key라고 부릅니다.
hardware-wrapped key를 wrap하는 key는 software에 노출되지 않는 hardware-internal key입니다. persistent한 `long-term wrapping key`이거나 per-boot `ephemeral wrapping key`입니다.
처음 unlock하는 것은 long-term wrapped form이지만 이를 ephemerally-wrapped key로 바꾸자마자 memory에서 지웁니다. 사용 중인 hardware-wrapped key는 항상 long-term wrapped가 아니라 ephemerally-wrapped 상태입니다.
inline encryption hardware는 on-disk data에만 사용할 수 있으므로 indirection level을 둡니다. unwrapped key를 직접 inline encryption에 쓰지 않고 여기서 inline encryption key와 `software secret`을 모두 derive합니다. software는 filename encryption처럼 hardware를 쓸 수 없는 작업에 software secret을 사용할 수 있으며, 이 secret은 memory compromise로부터 보호되지는 않습니다.
hardware-wrapped key hierarchy
407-449hardware-wrapped key의 hierarchy는 다음과 같습니다.
Hardware KDF가 wrapped key를 두 개의 암호학적으로 분리된 결과로 파생합니다.
- `Hardware-wrapped key`: hardware KDF용 key의 ephemerally-wrapped form입니다. wrapping algorithm은 kernel 동작에 영향을 주지 않는 hardware detail이지만 AES-256-GCM 같은 강한 authenticated encryption algorithm을 권장합니다.
- `Hardware KDF`: wrapped key를 unwrap한 뒤 subkey를 derive하는 Key Derivation Function입니다. 선택한 KDF는 kernel 동작에 영향을 주지 않지만 test를 위해 알아야 하고 최소 256-bit security strength를 가정합니다. 알려진 모든 hardware는 특정 label·context와 함께 AES-256-CMAC 기반 SP800-108 KDF Counter Mode를 사용하며 새 hardware도 검증된 이 KDF를 사용해야 합니다.
- `Inline encryption key`: software에 노출하지 않고 hardware가 inline encryption keyslot에 직접 provision하는 derived key입니다. 알려진 모든 hardware에서는 항상 AES-256-XTS key이지만 원칙적으로 다른 algorithm도 지원할 수 있습니다. 지원 algorithm마다 distinct subkey를 derive해야 합니다.
- `Software secret`: inline encryption을 쓸 수 없는 cryptographic task에 software가 사용하도록 hardware가 반환하는 derived key입니다. inline encryption key와 cryptographically isolated되어 하나를 알아도 다른 하나가 드러나지 않습니다. 현재 항상 32 byte이므로 최대 256-bit security strength를 요구하는 application에 적합하며 full-disk encryption 같은 일부 use case에는 필요하지 않습니다.
fscrypt 사용 예와 현재 제한
450-464fscrypt 예에서는 특정 encrypted directory 집합을 보호하는 fscrypt master key를 hardware-wrapped로 만듭니다. inline encryption key는 file contents encryption key로 사용하고, master key 대신 software secret을 fscrypt KDF인 `HKDF-SHA512`의 key로 사용해 filename encryption key 같은 다른 subkey를 derive합니다.
현재 설계는 추가 derivation 없이 hardware-wrapped key 하나당 inline encryption key 하나를 가정합니다. 따라서 fscrypt에서는 file마다가 아니라 encryption policy마다 file contents encryption key 하나를 쓰는 `inline encryption optimized` setting과만 호환됩니다.
storage stack으로 전달한 per-file nonce로 hardware가 per-file key를 derive하도록 확장할 수 있고 일부 hardware는 이미 지원합니다. 대응 kernel 지원을 추가해 이 제한을 없애는 future work가 계획되어 있습니다.
hardware-wrapped key kernel 지원
465-494kernel block layer의 inline encryption 지원인 `blk-crypto`는 hardware가 지원할 때 raw key 대신 hardware-wrapped key도 사용할 수 있도록 확장되었습니다.
- `struct blk_crypto_profile`의 crypto capabilities에 `key_types_supported` field를 추가해 driver가 raw key, hardware-wrapped key 또는 둘 다 지원한다고 선언할 수 있습니다.
- `struct blk_crypto_key`는 raw key 대신 hardware-wrapped key를 담을 수 있고, `struct blk_crypto_config`에 key type을 구분하는 `key_type` field를 추가합니다. blk-crypto user는 raw key와 매우 비슷한 방식으로 hardware-wrapped key로 data를 encrypt/decrypt할 수 있습니다.
- 새 method `blk_crypto_ll_ops::derive_sw_secret`을 추가하며 hardware-wrapped key driver는 이를 구현해야 합니다. blk-crypto user는 `blk_crypto_derive_sw_secret()`으로 이 method에 접근합니다.
- hardware-wrapped key도 raw key처럼 `blk_crypto_ll_ops::keyslot_program`과 `blk_crypto_ll_ops::keyslot_evict`로 program·evict합니다. 이를 지원하는 driver는 두 method에 hardware-wrapped key가 전달되는 경우를 처리해야 합니다.
`blk-crypto-fallback`은 hardware-wrapped key를 지원하지 않으므로 실제 inline encryption hardware에서만 사용할 수 있습니다.
wrapped key import·generate ioctl
495-513앞선 지원은 ephemerally-wrapped form만 다룹니다. 이 형태의 key를 만들고 준비하는 generic interface로 새 block device ioctl을 제공합니다.
- `BLKCRYPTOIMPORTKEY`는 raw key를 long-term wrapped form으로 변환하고 `struct blk_crypto_import_key_arg` pointer를 받습니다. caller는 `raw_key_ptr`과 `raw_key_size`에 import할 raw key pointer와 byte size를 설정합니다. 성공하면 `0`을 반환하고 최대 size가 `lt_key_size`인 `lt_key_ptr` buffer에 long-term wrapped key blob을 쓰며 `lt_key_size`를 실제 size로 갱신합니다. 실패하면 `-1`을 반환하고 errno를 설정합니다. `EOPNOTSUPP`는 device가 hardware-wrapped key를 지원하지 않음을, `EOVERFLOW`는 output buffer 공간이 부족함을 뜻합니다.
- `BLKCRYPTOGENERATEKEY`는 import 대신 hardware가 key를 생성한다는 점을 제외하면 `BLKCRYPTOIMPORTKEY`와 같으며 `struct blk_crypto_generate_key_arg` pointer를 받습니다.
wrapped key prepare와 userspace 절차
514-530`BLKCRYPTOPREPAREKEY`는 long-term wrapped key를 ephemerally-wrapped form으로 바꾸고 `struct blk_crypto_prepare_key_arg` pointer를 받습니다. caller는 `lt_key_ptr`과 `lt_key_size`에 변환할 long-term wrapped key blob의 pointer와 byte size를 설정합니다.
성공하면 `0`을 반환하고 최대 size가 `eph_key_size`인 `eph_key_ptr` buffer에 결과 blob을 쓰며 `eph_key_size`를 실제 size로 갱신합니다. 실패하면 `-1`과 errno를 반환합니다. `EOPNOTSUPP`, `EOVERFLOW`는 import ioctl과 같고 `EBADMSG`는 long-term wrapped key가 invalid임을 뜻합니다.
userspace는 key 생성 시 `BLKCRYPTOIMPORTKEY` 또는 `BLKCRYPTOGENERATEKEY`를 한 번 사용하고, key를 unlock해 kernel에 추가할 때마다 `BLKCRYPTOPREPAREKEY`를 사용해야 합니다. 이 ioctl은 raw key와 무관하며 hardware-wrapped key 전용입니다.
testability
531-550hardware KDF와 inline encryption 자체는 unwrapped key 외 secret에 의존하지 않는 잘 정의된 algorithm입니다. software가 unwrapped key를 안다면 이 algorithm을 software로 재현해 hardware가 disk에 쓴 ciphertext를 검증할 수 있습니다.
하지만 software가 unwrapped key를 아는 test는 `import` 기능을 사용할 때만 가능합니다. hardware가 key를 직접 생성하는 `generate` case는 proper testing이 불가능합니다.
따라서 generate mode의 correctness는 hardware RNG의 security와 correctness, 그 RNG를 key 생성에 올바르게 사용하는지에 의존합니다. key generation 외 모든 부분을 포괄해야 하는 import mode test에도 의존합니다.
import mode에서 disk ciphertext를 검증하는 예는 xfstests의 fscrypt hardware-wrapped key test 또는 Android `vts_kernel_encryption_test`를 참조하십시오: https://android.googlesource.com/platform/test/vts-testcase/kernel/+/refs/heads/main/encryption/
요약과 해설
inline-encryption.rst:1-550`blk-crypto`는 filesystem이 encryption context만 지정하면 block layer가 device capability, keyslot, merge·clone 제약과 hardware 또는 crypto API fallback을 일관되게 처리하도록 합니다.
hardware-wrapped key는 raw key를 kernel memory에 유지하지 않고도 reset 후 keyslot을 복구하고 많은 key를 지원합니다. hardware KDF가 inline encryption key와 software secret을 분리해 파생하며, import·generate·prepare ioctl이 userspace lifecycle을 제공합니다.