mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-06 08:20:07 +01:00
Compare commits
164 Commits
v2.1.0
...
v2.2.0-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0dc59e792 | ||
|
|
0106c64369 | ||
|
|
69fdb41934 | ||
|
|
550b3ee1d3 | ||
|
|
961cc6a6d3 | ||
|
|
05091ab656 | ||
|
|
272505b99d | ||
|
|
60a769955b | ||
|
|
34bec53474 | ||
|
|
c77ae65a0d | ||
|
|
1ed0430b82 | ||
|
|
82f640e360 | ||
|
|
44aabc3ae4 | ||
|
|
bbdf9b2745 | ||
|
|
96a87170f7 | ||
|
|
281323db42 | ||
|
|
32258ee8ae | ||
|
|
df0faef9ca | ||
|
|
9c3a020ecf | ||
|
|
4c4cc55bb7 | ||
|
|
f4c2e7e629 | ||
|
|
eadef08fd5 | ||
|
|
0c725a257d | ||
|
|
6f35fb5f80 | ||
|
|
cd1fe75987 | ||
|
|
e92e320956 | ||
|
|
0e4757e0fb | ||
|
|
bd6af68bc5 | ||
|
|
13050f73c1 | ||
|
|
5472fb0c56 | ||
|
|
73c2424b24 | ||
|
|
5117eda688 | ||
|
|
cfbef51d3d | ||
|
|
09cb2d76ef | ||
|
|
3f549ad0df | ||
|
|
60d26be325 | ||
|
|
013d0d3753 | ||
|
|
97da67c6a8 | ||
|
|
f74072ba28 | ||
|
|
19eac239b7 | ||
|
|
31cd41bfe4 | ||
|
|
af6c321395 | ||
|
|
448fca1fdf | ||
|
|
1923928fdc | ||
|
|
bee5574656 | ||
|
|
8c8a68d850 | ||
|
|
9159b5b120 | ||
|
|
2d0079905e | ||
|
|
83c227d53c | ||
|
|
ee57b865b0 | ||
|
|
ecbb9cfa90 | ||
|
|
8545e8496b | ||
|
|
75b2610e85 | ||
|
|
237021ec15 | ||
|
|
4f5c25d0dd | ||
|
|
4c33ab1997 | ||
|
|
5bb65aca8f | ||
|
|
3fd7babacc | ||
|
|
caea8a9588 | ||
|
|
e1d6cba014 | ||
|
|
1f91fe7a2c | ||
|
|
dc53261c3b | ||
|
|
b3e90a93b0 | ||
|
|
1f3e2b770c | ||
|
|
d310e896cb | ||
|
|
a36245cef6 | ||
|
|
092ef90f29 | ||
|
|
64f59ff71e | ||
|
|
a7f80a2770 | ||
|
|
a5c5e3e876 | ||
|
|
8e4fb993c0 | ||
|
|
846567275a | ||
|
|
741c972935 | ||
|
|
6c2760c9cd | ||
|
|
b35a5ee4a3 | ||
|
|
345385376a | ||
|
|
dbe9db26fc | ||
|
|
91ba22b157 | ||
|
|
86b2736480 | ||
|
|
cfe2fb66ab | ||
|
|
428e61253c | ||
|
|
95bcd0c9d5 | ||
|
|
23bada3c5a | ||
|
|
de0cf8433b | ||
|
|
1b49ea4061 | ||
|
|
29b94d6ba3 | ||
|
|
80a435f00b | ||
|
|
fdcd5806b1 | ||
|
|
9ddcfce915 | ||
|
|
6ba358533b | ||
|
|
73aa329d57 | ||
|
|
379016fd78 | ||
|
|
ea4b586c77 | ||
|
|
6961f2caae | ||
|
|
4df2ce4409 | ||
|
|
052a4f432c | ||
|
|
de86ff051e | ||
|
|
f5feeab48d | ||
|
|
1317af028e | ||
|
|
cdcd4ddd35 | ||
|
|
2960164cf8 | ||
|
|
a98ef9787c | ||
|
|
b6d406fbc8 | ||
|
|
e3488292ba | ||
|
|
fea2e0be4f | ||
|
|
751f5dfda3 | ||
|
|
d5f71e66f9 | ||
|
|
03e810ec72 | ||
|
|
6c6f4bcd45 | ||
|
|
304942302b | ||
|
|
8dc1a74df8 | ||
|
|
e295d01505 | ||
|
|
aa1b29ea0e | ||
|
|
cef857fbbd | ||
|
|
6bba8ce0dc | ||
|
|
b0330d62e5 | ||
|
|
fc0c857cfe | ||
|
|
238b18b8ac | ||
|
|
6a2d023b7b | ||
|
|
4bb1fff15d | ||
|
|
37f5bda227 | ||
|
|
56b571fcaa | ||
|
|
46bf3c9e9c | ||
|
|
361fb22954 | ||
|
|
203fe0f4bf | ||
|
|
36ac5fe735 | ||
|
|
7569519530 | ||
|
|
a848179286 | ||
|
|
456ab38caa | ||
|
|
c71b5c0426 | ||
|
|
868cc52415 | ||
|
|
8c168cc337 | ||
|
|
f9fa4cc099 | ||
|
|
a0540cafb3 | ||
|
|
88b3924132 | ||
|
|
3023f26911 | ||
|
|
c9347d3d7d | ||
|
|
d85c7d06af | ||
|
|
e229f79741 | ||
|
|
a4d236eebe | ||
|
|
1192fd27c6 | ||
|
|
cd1cb40033 | ||
|
|
14e085f70e | ||
|
|
fc37d81144 | ||
|
|
a859455aad | ||
|
|
93d596ace2 | ||
|
|
c03e3fe88a | ||
|
|
a90a5c9244 | ||
|
|
26772f8184 | ||
|
|
8f8ad83861 | ||
|
|
d111b42cf1 | ||
|
|
821c965b45 | ||
|
|
4acac9a294 | ||
|
|
4adb06ae91 | ||
|
|
dce7a1e2aa | ||
|
|
a354b72546 | ||
|
|
ac8f41404b | ||
|
|
fc7b257bab | ||
|
|
787066c292 | ||
|
|
71ab6cb818 | ||
|
|
1158ba453e | ||
|
|
2e3f764272 | ||
|
|
2172f1d2cd | ||
|
|
6efc1eae9f |
@@ -1,7 +1,7 @@
|
||||
language: c
|
||||
|
||||
sudo: required
|
||||
dist: trusty
|
||||
dist: xenial
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
30
README.md
30
README.md
@@ -2,13 +2,13 @@
|
||||
|
||||
What the ...?
|
||||
=============
|
||||
**Cryptsetup** is utility used to conveniently setup disk encryption based
|
||||
on [DMCrypt](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt) kernel module.
|
||||
**Cryptsetup** is a utility used to conveniently set up disk encryption based
|
||||
on the [DMCrypt](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt) kernel module.
|
||||
|
||||
These include **plain** **dm-crypt** volumes, **LUKS** volumes, **loop-AES**
|
||||
and **TrueCrypt** (including **VeraCrypt** extension) format.
|
||||
and **TrueCrypt** (including **VeraCrypt** extension) formats.
|
||||
|
||||
Project also includes **veritysetup** utility used to conveniently setup
|
||||
The project also includes a **veritysetup** utility used to conveniently setup
|
||||
[DMVerity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity) block integrity checking kernel module
|
||||
and, since version 2.0, **integritysetup** to setup
|
||||
[DMIntegrity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMIntegrity) block integrity kernel module.
|
||||
@@ -20,7 +20,10 @@ LUKS Design
|
||||
only facilitate compatibility among distributions, but also provides secure management of multiple user passwords.
|
||||
LUKS stores all necessary setup information in the partition header, enabling to transport or migrate data seamlessly.
|
||||
|
||||
Last version of the LUKS format specification is
|
||||
Last version of the LUKS2 format specification is
|
||||
[available here](https://gitlab.com/cryptsetup/LUKS2-docs).
|
||||
|
||||
Last version of the LUKS1 format specification is
|
||||
[available here](https://www.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf).
|
||||
|
||||
Why LUKS?
|
||||
@@ -41,13 +44,22 @@ Download
|
||||
--------
|
||||
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
|
||||
|
||||
**The latest cryptsetup version is 2.0.6**
|
||||
* [cryptsetup-2.0.6.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.xz)
|
||||
* Signature [cryptsetup-2.0.6.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.sign)
|
||||
**The latest cryptsetup version is 2.1.0**
|
||||
* [cryptsetup-2.1.0.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.1/cryptsetup-2.1.0.tar.xz)
|
||||
* Signature [cryptsetup-2.1.0.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.1/cryptsetup-2.1.0.tar.sign)
|
||||
_(You need to decompress file first to check signature.)_
|
||||
* [Cryptsetup 2.0.6 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.6-ReleaseNotes).
|
||||
* [Cryptsetup 2.1.0 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.1/v2.1.0-ReleaseNotes).
|
||||
|
||||
**The latest testing and experimental cryptsetup version is 2.2.0-rc0**
|
||||
* [cryptsetup-2.2.0-rc0.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/cryptsetup-2.2.0-rc0.tar.xz)
|
||||
* Signature [cryptsetup-2.2.0-rc0.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/cryptsetup-2.2.0-rc0.tar.sign)
|
||||
_(You need to decompress file first to check signature.)_
|
||||
* [Cryptsetup 2.2.0-rc0 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.2/v2.2.0-rc0-ReleaseNotes).
|
||||
|
||||
Previous versions
|
||||
* [Version 2.0.6](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.6.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.6-ReleaseNotes).
|
||||
* [Version 2.0.5](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.5.tar.xz) -
|
||||
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.5.tar.sign) -
|
||||
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.5-ReleaseNotes).
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
AC_PREREQ([2.67])
|
||||
AC_INIT([cryptsetup],[2.1.0])
|
||||
AC_INIT([cryptsetup],[2.2.0-rc1])
|
||||
|
||||
dnl library version from <major>.<minor>.<release>[-<suffix>]
|
||||
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
|
||||
LIBCRYPTSETUP_VERSION_INFO=16:0:4
|
||||
LIBCRYPTSETUP_VERSION_INFO=17:0:5
|
||||
|
||||
AM_SILENT_RULES([yes])
|
||||
AC_CONFIG_SRCDIR(src/cryptsetup.c)
|
||||
@@ -209,6 +209,8 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
|
||||
NO_FIPS([])
|
||||
fi
|
||||
|
||||
AC_CHECK_DECLS([GCRY_CIPHER_MODE_XTS], [], [], [#include <gcrypt.h>])
|
||||
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
saved_LIBS=$LIBS
|
||||
LIBS="$saved_LIBS $LIBGCRYPT_LIBS -static"
|
||||
@@ -359,6 +361,7 @@ LIBS=$saved_LIBS
|
||||
dnl Check for JSON-C used in LUKS2
|
||||
PKG_CHECK_MODULES([JSON_C], [json-c])
|
||||
AC_CHECK_DECLS([json_object_object_add_ex], [], [], [#include <json-c/json.h>])
|
||||
AC_CHECK_DECLS([json_object_deep_copy], [], [], [#include <json-c/json.h>])
|
||||
|
||||
dnl Crypto backend configuration.
|
||||
AC_ARG_WITH([crypto_backend],
|
||||
|
||||
266
docs/v2.2.0-rc1-ReleaseNotes
Normal file
266
docs/v2.2.0-rc1-ReleaseNotes
Normal file
@@ -0,0 +1,266 @@
|
||||
Cryptsetup 2.2.0-rc1 Release Notes
|
||||
==================================
|
||||
Testing release with new experimental features and bug fixes.
|
||||
|
||||
Cryptsetup 2.2 version introduces a new LUKS2 online reencryption
|
||||
extension that allows reencryption of mounted LUKS2 devices
|
||||
(device in use) in the background.
|
||||
|
||||
This testing release is intended for more extensive testing
|
||||
of very complex online reencryption feature; it is expected
|
||||
that it contains bugs, performance issues and that some functions
|
||||
are in this testing release limited.
|
||||
|
||||
Please do not use this testing version in production environments.
|
||||
Also, use it only if you have a full data backup.
|
||||
|
||||
Changes since version 2.2.0-rc0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Add integritysetup support for bitmap mode introduced in Linux kernel 5.2.
|
||||
Integritysetup now supports --integrity-bitmap-mode option and
|
||||
--bitmap-sector-per-bit and --bitmap-flush-time commandline options.
|
||||
|
||||
In the bitmap operation mode, if a bit in the bitmap is 1, the corresponding
|
||||
region's data and integrity tags are not synchronized - if the machine
|
||||
crashes, the unsynchronized regions will be recalculated.
|
||||
The bitmap mode is faster than the journal mode because we don't have
|
||||
to write the data twice, but it is also less reliable, because if data
|
||||
corruption happens when the machine crashes, it may not be detected.
|
||||
This can be used only for standalone devices, not with dm-crypt.
|
||||
|
||||
* The libcryptsetup now keeps all file descriptors to underlying device
|
||||
open during the whole lifetime of crypt device context to avoid excessive
|
||||
scanning in udev (udev run scan on every descriptor close).
|
||||
|
||||
* The luksDump command now prints more info for reencryption keyslot
|
||||
(when a device is in-reencryption).
|
||||
|
||||
* New --device-size parameter is supported for LUKS2 reencryption.
|
||||
It may be used to encrypt/reencrypt only the initial part of the data
|
||||
device if the user is aware that the rest of the device is empty.
|
||||
|
||||
Note: This change causes API break since the last rc0 release
|
||||
(crypt_params_reencrypt structure contains additional field).
|
||||
|
||||
* New --resume-only parameter is supported for LUKS2 reencryption.
|
||||
This flag resumes reencryption process if it exists (not starting
|
||||
new reencryption).
|
||||
|
||||
* The repair command now tries LUKS2 reencryption recovery if needed.
|
||||
|
||||
* If reencryption device is a file image, an interactive dialog now
|
||||
asks if reencryption should be run safely in offline mode
|
||||
(if autodetection of active devices failed).
|
||||
|
||||
* Fix activation through a token where dm-crypt volume key was not
|
||||
set through keyring (but using old device-mapper table parameter mode).
|
||||
|
||||
* Online reencryption can now retain all keyslots (if all passphrases
|
||||
are provided). Note that keyslot numbers will change in this case.
|
||||
|
||||
Changes since version 2.1.0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
LUKS2 online reencryption
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The reencryption is intended to provide a reliable way to change
|
||||
volume key or an algorithm change while the encrypted device is still
|
||||
in use.
|
||||
|
||||
It is based on userspace-only approach (no kernel changes needed)
|
||||
that uses the device-mapper subsystem to remap active devices on-the-fly
|
||||
dynamically. The device is split into several segments (encrypted by old
|
||||
key, new key and so-called hotzone, where reencryption is actively running).
|
||||
|
||||
The flexible LUKS2 metadata format is used to store intermediate states
|
||||
(segment mappings) and both version of keyslots (old and new keys).
|
||||
Also, it provides a binary area (in the unused keyslot area space)
|
||||
to provide recovery metadata in the case of unexpected failure during
|
||||
reencryption. LUKS2 header is during the reencryption marked with
|
||||
"online-reencryption" keyword. After the reencryption is finished,
|
||||
this keyword is removed, and the device is backward compatible with all
|
||||
older cryptsetup tools (that support LUKS2).
|
||||
|
||||
The recovery supports three resilience modes:
|
||||
|
||||
- checksum: default mode, where individual checksums of ciphertext hotzone
|
||||
sectors are stored, so the recovery process can detect which sectors were
|
||||
already reencrypted. It requires that the device sector write is atomic.
|
||||
|
||||
- journal: the hotzone is journaled in the binary area
|
||||
(so the data are written twice)
|
||||
|
||||
- none: performance mode; there is no protection
|
||||
(similar to old offline reencryption)
|
||||
|
||||
These resilience modes are not available if reencryption uses data shift.
|
||||
|
||||
|
||||
Note: until we have full documentation (both of the process and metadata),
|
||||
please refer to Ondrej's slides (some slight details are no longer relevant)
|
||||
https://okozina.fedorapeople.org/online-disk-reencryption-with-luks2-compact.pdf
|
||||
|
||||
The offline reencryption tool (cryptsetup-reencrypt) is still supported
|
||||
for both LUKS1 and LUKS2 format.
|
||||
|
||||
Cryptsetup examples for reencryption
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The reencryption feature is integrated directly into cryptsetup utility
|
||||
as the new "reencrypt" action (command).
|
||||
|
||||
There are three basic modes - to perform reencryption (change of already
|
||||
existing LUKS2 device), to add encryption to plaintext device and to remove
|
||||
encryption from a device (decryption).
|
||||
|
||||
In all cases, if existing LUKS2 metadata contains information about
|
||||
the ongoing reencryption process, following reencrypt command continues
|
||||
with the ongoing reencryption process until it is finished.
|
||||
|
||||
You can activate a device with ongoing reencryption as the standard LUKS2
|
||||
device, but the reencryption process will not continue until the cryptsetup
|
||||
reencrypt command is issued.
|
||||
|
||||
|
||||
1) Reencryption
|
||||
~~~~~~~~~~~~~~~
|
||||
This mode is intended to change any attribute of the data encryption
|
||||
(change of the volume key, algorithm or sector size).
|
||||
Note that authenticated encryption is not yet supported.
|
||||
|
||||
You can start the reencryption process by specifying a LUKS2 device or with
|
||||
a detached LUKS2 header.
|
||||
The code should automatically recognize if the device is in use (and if it
|
||||
should use online mode of reencryption).
|
||||
|
||||
If you do not specify parameters, only volume key is changed
|
||||
(a new random key is generated).
|
||||
|
||||
# cryptsetup reencrypt <device> [--header <hdr>]
|
||||
|
||||
You can also start reencryption using active mapped device name:
|
||||
# cryptsetup reencrypt --active-name <name>
|
||||
|
||||
You can also specify the resilience mode (none, checksum, journal) with
|
||||
--resilience=<mode> option, for checksum mode also the hash algorithm with
|
||||
--resilience-hash=<alg> (only hash algorithms supported by cryptographic
|
||||
backend are available).
|
||||
|
||||
The maximal size of reencryption hotzone can be limited by
|
||||
--hotzone-size=<size> option and applies to all reencryption modes.
|
||||
Note that for checksum and journal mode hotzone size is also limited
|
||||
by available space in binary keyslot area.
|
||||
|
||||
2) Encryption
|
||||
~~~~~~~~~~~~~
|
||||
This mode provides a way to encrypt a plaintext device to LUKS2 format.
|
||||
This option requires reduction of device size (for LUKS2 header) or new
|
||||
detached header.
|
||||
|
||||
# cryptsetup reencrypt <device> --encrypt --reduce-device-size <size>
|
||||
|
||||
Or with detached header:
|
||||
# cryptsetup reencrypt <device> --encrypt --header <hdr>
|
||||
|
||||
3) Decryption
|
||||
~~~~~~~~~~~~~
|
||||
This mode provides the removal of existing LUKS2 encryption and replacing
|
||||
a device with plaintext content only.
|
||||
For now, we support only decryption with a detached header.
|
||||
|
||||
# cryptsetup reencrypt <device> --decrypt --header <hdr>
|
||||
|
||||
For all three modes, you can split the process to metadata initialization
|
||||
(prepare keyslots and segments but do not run reencryption yet) and the data
|
||||
reencryption step by using --init-only option.
|
||||
|
||||
Prepares metadata:
|
||||
# cryptsetup reencrypt --init-only <parameters>
|
||||
|
||||
Starts the data processing:
|
||||
# cryptsetup reencrypt <device>
|
||||
|
||||
Please note, that due to the Linux kernel limitation, the encryption or
|
||||
decryption process cannot be run entirely online - there must be at least
|
||||
short offline window where operation adds/removes device-mapper crypt (LUKS2) layer.
|
||||
This step should also include modification of /etc/crypttab and fstab UUIDs,
|
||||
but it is out of the scope of cryptsetup tools.
|
||||
|
||||
Limitations
|
||||
~~~~~~~~~~~
|
||||
Most of these limitations will be (hopefully) fixed in next versions.
|
||||
|
||||
* Only one active keyslot is supported (all old keyslots will be removed
|
||||
after reencryption).
|
||||
|
||||
* Only block devices are now supported as parameters. As a workaround
|
||||
for images in a file, please explicitly map a loop device over the image
|
||||
and use the loop device as the parameter.
|
||||
|
||||
* Devices with authenticated encryption are not supported. (Later it will
|
||||
be limited by the fixed per-sector metadata, per-sector metadata size
|
||||
cannot be changed without a new device format operation.)
|
||||
|
||||
* The reencryption uses userspace crypto library, with fallback to
|
||||
the kernel (if available). There can be some specific configurations
|
||||
where the fallback does not provide optimal performance.
|
||||
|
||||
* There are no translations of error messages until the final release
|
||||
(some messages can be rephrased as well).
|
||||
|
||||
* The repair command is not finished; the recovery of interrupted
|
||||
reencryption is made automatically on the first device activation.
|
||||
|
||||
* Reencryption triggers too many udev scans on metadata updates (on closing
|
||||
write enabled file descriptors). This has a negative performance impact on the whole
|
||||
reencryption and generates excessive I/O load on the system.
|
||||
|
||||
New libcryptsetup reencryption API
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The libcryptsetup contains new API calls that are used to setup and
|
||||
run the reencryption.
|
||||
|
||||
Note that there can be some changes in API implementation of these functions
|
||||
and/or some new function can be introduced in final cryptsetup 2.2 release.
|
||||
|
||||
New API symbols (see documentation in libcryptsetup.h)
|
||||
* struct crypt_params_reencrypt - reencryption parameters
|
||||
|
||||
* crypt_reencrypt_init_by_passphrase
|
||||
* crypt_reencrypt_init_by_keyring
|
||||
- function to configure LUKS2 metadata for reencryption;
|
||||
if metadata already exists, it configures the context from this metadata
|
||||
|
||||
* crypt_reencrypt
|
||||
- run the reencryption process (processing the data)
|
||||
- the optional callback function can be used to interrupt the reencryption
|
||||
or report the progress.
|
||||
|
||||
* crypt_reencrypt_status
|
||||
- function to query LUKS2 metadata about the reencryption state
|
||||
|
||||
Other changes and fixes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Add optional global serialization lock for memory hard PBKDF.
|
||||
(The --serialize-memory-hard-pbkdf option in cryptsetup and
|
||||
CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF in activation flag.)
|
||||
|
||||
This is an "ugly" optional workaround for a situation when multiple devices
|
||||
are being activated in parallel (like systemd crypttab activation).
|
||||
The system instead of returning ENOMEM (no memory available) starts
|
||||
out-of-memory (OOM) killer to kill processes randomly.
|
||||
|
||||
Until we find a reliable way how to work with memory-hard function
|
||||
in these situations, cryptsetup provide a way how to serialize memory-hard
|
||||
unlocking among parallel cryptsetup instances to workaround this problem.
|
||||
This flag is intended to be used only in very specific situations,
|
||||
never use it directly :-)
|
||||
|
||||
* Abort conversion to LUKS1 with incompatible sector size that is
|
||||
not supported in LUKS1.
|
||||
|
||||
* Report error (-ENOENT) if no LUKS keyslots are available. User can now
|
||||
distinguish between a wrong passphrase and no keyslot available.
|
||||
|
||||
* Fix a possible segfault in detached header handling (double free).
|
||||
@@ -64,6 +64,8 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/utils_device_locking.c \
|
||||
lib/utils_device_locking.h \
|
||||
lib/utils_pbkdf.c \
|
||||
lib/utils_storage_wrappers.c \
|
||||
lib/utils_storage_wrappers.h \
|
||||
lib/libdevmapper.c \
|
||||
lib/utils_dm.h \
|
||||
lib/volumekey.c \
|
||||
@@ -97,6 +99,9 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/luks2/luks2_digest_pbkdf2.c \
|
||||
lib/luks2/luks2_keyslot.c \
|
||||
lib/luks2/luks2_keyslot_luks2.c \
|
||||
lib/luks2/luks2_keyslot_reenc.c \
|
||||
lib/luks2/luks2_reencrypt.c \
|
||||
lib/luks2/luks2_segment.c \
|
||||
lib/luks2/luks2_token_keyring.c \
|
||||
lib/luks2/luks2_token.c \
|
||||
lib/luks2/luks2_internal.h \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* base64.c -- Encode binary data using printable characters.
|
||||
Copyright (C) 1999-2001, 2004-2006, 2009-2018 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999-2001, 2004-2006, 2009-2019 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -70,7 +70,7 @@ base64_encode_fast (const char *restrict in, size_t inlen, char *restrict out)
|
||||
{
|
||||
while (inlen)
|
||||
{
|
||||
*out++ = b64c[to_uchar (in[0]) >> 2];
|
||||
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
|
||||
*out++ = b64c[((to_uchar (in[0]) << 4) + (to_uchar (in[1]) >> 4)) & 0x3f];
|
||||
*out++ = b64c[((to_uchar (in[1]) << 2) + (to_uchar (in[2]) >> 6)) & 0x3f];
|
||||
*out++ = b64c[to_uchar (in[2]) & 0x3f];
|
||||
@@ -103,7 +103,7 @@ base64_encode (const char *restrict in, size_t inlen,
|
||||
|
||||
while (inlen && outlen)
|
||||
{
|
||||
*out++ = b64c[to_uchar (in[0]) >> 2];
|
||||
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
|
||||
if (!--outlen)
|
||||
break;
|
||||
*out++ = b64c[((to_uchar (in[0]) << 4)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* base64.h -- Encode binary data using printable characters.
|
||||
Copyright (C) 2004-2006, 2009-2018 Free Software Foundation, Inc.
|
||||
Copyright (C) 2004-2006, 2009-2019 Free Software Foundation, Inc.
|
||||
Written by Simon Josefsson.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
||||
@@ -4,12 +4,14 @@ libcrypto_backend_la_CFLAGS = $(AM_CFLAGS) @CRYPTO_CFLAGS@
|
||||
|
||||
libcrypto_backend_la_SOURCES = \
|
||||
lib/crypto_backend/crypto_backend.h \
|
||||
lib/crypto_backend/crypto_backend_internal.h \
|
||||
lib/crypto_backend/crypto_cipher_kernel.c \
|
||||
lib/crypto_backend/crypto_storage.c \
|
||||
lib/crypto_backend/pbkdf_check.c \
|
||||
lib/crypto_backend/crc32.c \
|
||||
lib/crypto_backend/argon2_generic.c \
|
||||
lib/crypto_backend/cipher_generic.c
|
||||
lib/crypto_backend/cipher_generic.c \
|
||||
lib/crypto_backend/cipher_check.c
|
||||
|
||||
if CRYPTO_BACKEND_GCRYPT
|
||||
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_gcrypt.c
|
||||
|
||||
@@ -125,7 +125,7 @@ void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) {
|
||||
SecureZeroMemory(v, n);
|
||||
#elif defined memset_s
|
||||
memset_s(v, n, 0, n);
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(HAVE_EXPLICIT_BZERO)
|
||||
explicit_bzero(v, n);
|
||||
#else
|
||||
static void *(*const volatile memset_sec)(void *, int, size_t) = &memset;
|
||||
@@ -299,7 +299,7 @@ static int fill_memory_blocks_mt(argon2_instance_t *instance) {
|
||||
|
||||
for (r = 0; r < instance->passes; ++r) {
|
||||
for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
|
||||
uint32_t l;
|
||||
uint32_t l, ll;
|
||||
|
||||
/* 2. Calling threads */
|
||||
for (l = 0; l < instance->lanes; ++l) {
|
||||
@@ -324,6 +324,9 @@ static int fill_memory_blocks_mt(argon2_instance_t *instance) {
|
||||
sizeof(argon2_position_t));
|
||||
if (argon2_thread_create(&thread[l], &fill_segment_thr,
|
||||
(void *)&thr_data[l])) {
|
||||
/* Wait for already running threads */
|
||||
for (ll = 0; ll < l; ++ll)
|
||||
argon2_thread_join(thread[ll]);
|
||||
rc = ARGON2_THREAD_FAIL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
#if HAVE_ARGON2_H
|
||||
#include <argon2.h>
|
||||
#else
|
||||
@@ -77,117 +77,3 @@ int argon2(const char *type, const char *password, size_t password_length,
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
|
||||
struct test_vector {
|
||||
argon2_type type;
|
||||
unsigned int memory;
|
||||
unsigned int iterations;
|
||||
unsigned int parallelism;
|
||||
const char *password;
|
||||
unsigned int password_length;
|
||||
const char *salt;
|
||||
unsigned int salt_length;
|
||||
const char *key;
|
||||
unsigned int key_length;
|
||||
const char *ad;
|
||||
unsigned int ad_length;
|
||||
const char *output;
|
||||
unsigned int output_length;
|
||||
};
|
||||
|
||||
struct test_vector test_vectors[] = {
|
||||
/* Argon2 RFC */
|
||||
{
|
||||
Argon2_i, 32, 3, 4,
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01", 32,
|
||||
"\x02\x02\x02\x02\x02\x02\x02\x02"
|
||||
"\x02\x02\x02\x02\x02\x02\x02\x02", 16,
|
||||
"\x03\x03\x03\x03\x03\x03\x03\x03", 8,
|
||||
"\x04\x04\x04\x04\x04\x04\x04\x04"
|
||||
"\x04\x04\x04\x04", 12,
|
||||
"\xc8\x14\xd9\xd1\xdc\x7f\x37\xaa"
|
||||
"\x13\xf0\xd7\x7f\x24\x94\xbd\xa1"
|
||||
"\xc8\xde\x6b\x01\x6d\xd3\x88\xd2"
|
||||
"\x99\x52\xa4\xc4\x67\x2b\x6c\xe8", 32
|
||||
},
|
||||
{
|
||||
Argon2_id, 32, 3, 4,
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01"
|
||||
"\x01\x01\x01\x01\x01\x01\x01\x01", 32,
|
||||
"\x02\x02\x02\x02\x02\x02\x02\x02"
|
||||
"\x02\x02\x02\x02\x02\x02\x02\x02", 16,
|
||||
"\x03\x03\x03\x03\x03\x03\x03\x03", 8,
|
||||
"\x04\x04\x04\x04\x04\x04\x04\x04"
|
||||
"\x04\x04\x04\x04", 12,
|
||||
"\x0d\x64\x0d\xf5\x8d\x78\x76\x6c"
|
||||
"\x08\xc0\x37\xa3\x4a\x8b\x53\xc9"
|
||||
"\xd0\x1e\xf0\x45\x2d\x75\xb6\x5e"
|
||||
"\xb5\x25\x20\xe9\x6b\x01\xe6\x59", 32
|
||||
}
|
||||
};
|
||||
|
||||
static void printhex(const char *s, const char *buf, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
printf("%s: ", s);
|
||||
for (i = 0; i < len; i++)
|
||||
printf("\\x%02x", (unsigned char)buf[i]);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static int argon2_test_vectors(void)
|
||||
{
|
||||
char result[64];
|
||||
int i, r;
|
||||
struct test_vector *vec;
|
||||
argon2_context context;
|
||||
|
||||
printf("Argon2 running test vectors\n");
|
||||
|
||||
for (i = 0; i < (sizeof(test_vectors) / sizeof(*test_vectors)); i++) {
|
||||
vec = &test_vectors[i];
|
||||
memset(result, 0, sizeof(result));
|
||||
memset(&context, 0, sizeof(context));
|
||||
|
||||
context.flags = ARGON2_DEFAULT_FLAGS;
|
||||
context.version = ARGON2_VERSION_NUMBER;
|
||||
context.out = (uint8_t *)result;
|
||||
context.outlen = (uint32_t)vec->output_length;
|
||||
context.pwd = (uint8_t *)vec->password;
|
||||
context.pwdlen = (uint32_t)vec->password_length;
|
||||
context.salt = (uint8_t *)vec->salt;
|
||||
context.saltlen = (uint32_t)vec->salt_length;
|
||||
context.secret = (uint8_t *)vec->key;
|
||||
context.secretlen = (uint32_t)vec->key_length;;
|
||||
context.ad = (uint8_t *)vec->ad;
|
||||
context.adlen = (uint32_t)vec->ad_length;
|
||||
context.t_cost = vec->iterations;
|
||||
context.m_cost = vec->memory;
|
||||
context.lanes = vec->parallelism;
|
||||
context.threads = vec->parallelism;
|
||||
|
||||
r = argon2_ctx(&context, vec->type);
|
||||
if (r != ARGON2_OK) {
|
||||
printf("Argon2 failed %i, vector %d\n", r, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (memcmp(result, vec->output, vec->output_length) != 0) {
|
||||
printf("vector %u\n", i);
|
||||
printhex(" got", result, vec->output_length);
|
||||
printhex("want", vec->output, vec->output_length);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
157
lib/crypto_backend/cipher_check.c
Normal file
157
lib/crypto_backend/cipher_check.c
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Cipher performance check
|
||||
*
|
||||
* Copyright (C) 2018-2019 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018-2019 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
/*
|
||||
* This is not simulating storage, so using disk block causes extreme overhead.
|
||||
* Let's use some fixed block size where results are more reliable...
|
||||
*/
|
||||
#define CIPHER_BLOCK_BYTES 65536
|
||||
|
||||
/*
|
||||
* If the measured value is lower, encrypted buffer is probably too small
|
||||
* and calculated values are not reliable.
|
||||
*/
|
||||
#define CIPHER_TIME_MIN_MS 0.001
|
||||
|
||||
/*
|
||||
* The whole test depends on Linux kernel usermode crypto API for now.
|
||||
* (The same implementations are used in dm-crypt though.)
|
||||
*/
|
||||
|
||||
static int time_ms(struct timespec *start, struct timespec *end, double *ms)
|
||||
{
|
||||
double start_ms, end_ms;
|
||||
|
||||
start_ms = start->tv_sec * 1000.0 + start->tv_nsec / (1000.0 * 1000);
|
||||
end_ms = end->tv_sec * 1000.0 + end->tv_nsec / (1000.0 * 1000);
|
||||
|
||||
*ms = end_ms - start_ms;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cipher_perf_one(const char *name, const char *mode, char *buffer, size_t buffer_size,
|
||||
const char *key, size_t key_size, const char *iv, size_t iv_size, int enc)
|
||||
{
|
||||
struct crypt_cipher_kernel cipher;
|
||||
size_t done = 0, block = CIPHER_BLOCK_BYTES;
|
||||
int r;
|
||||
|
||||
if (buffer_size < block)
|
||||
block = buffer_size;
|
||||
|
||||
r = crypt_cipher_init_kernel(&cipher, name, mode, key, key_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while (done < buffer_size) {
|
||||
if ((done + block) > buffer_size)
|
||||
block = buffer_size - done;
|
||||
|
||||
if (enc)
|
||||
r = crypt_cipher_encrypt_kernel(&cipher, &buffer[done], &buffer[done],
|
||||
block, iv, iv_size);
|
||||
else
|
||||
r = crypt_cipher_decrypt_kernel(&cipher, &buffer[done], &buffer[done],
|
||||
block, iv, iv_size);
|
||||
if (r < 0)
|
||||
break;
|
||||
|
||||
done += block;
|
||||
}
|
||||
|
||||
crypt_cipher_destroy_kernel(&cipher);
|
||||
|
||||
return r;
|
||||
}
|
||||
static int cipher_measure(const char *name, const char *mode, char *buffer, size_t buffer_size,
|
||||
const char *key, size_t key_size, const char *iv, size_t iv_size,
|
||||
int encrypt, double *ms)
|
||||
{
|
||||
struct timespec start, end;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* Using getrusage would be better here but the precision
|
||||
* is not adequate, so better stick with CLOCK_MONOTONIC
|
||||
*/
|
||||
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = cipher_perf_one(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, encrypt);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC_RAW, &end) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = time_ms(&start, &end, ms);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (*ms < CIPHER_TIME_MIN_MS)
|
||||
return -ERANGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static double speed_mbs(unsigned long bytes, double ms)
|
||||
{
|
||||
double speed = bytes, s = ms / 1000.;
|
||||
|
||||
return speed / (1024 * 1024) / s;
|
||||
}
|
||||
|
||||
int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, size_t buffer_size,
|
||||
const char *key, size_t key_size, const char *iv, size_t iv_size,
|
||||
double *encryption_mbs, double *decryption_mbs)
|
||||
{
|
||||
double ms_enc, ms_dec, ms;
|
||||
int r, repeat_enc, repeat_dec;
|
||||
|
||||
ms_enc = 0.0;
|
||||
repeat_enc = 1;
|
||||
while (ms_enc < 1000.0) {
|
||||
r = cipher_measure(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, 1, &ms);
|
||||
if (r < 0)
|
||||
return r;
|
||||
ms_enc += ms;
|
||||
repeat_enc++;
|
||||
}
|
||||
|
||||
ms_dec = 0.0;
|
||||
repeat_dec = 1;
|
||||
while (ms_dec < 1000.0) {
|
||||
r = cipher_measure(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, 0, &ms);
|
||||
if (r < 0)
|
||||
return r;
|
||||
ms_dec += ms;
|
||||
repeat_dec++;
|
||||
}
|
||||
|
||||
*encryption_mbs = speed_mbs(buffer_size * repeat_enc, ms_enc);
|
||||
*decryption_mbs = speed_mbs(buffer_size * repeat_dec, ms_dec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -42,7 +42,6 @@
|
||||
|
||||
#include "crypto_backend.h"
|
||||
|
||||
|
||||
static const uint32_t crc32_tab[] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
@@ -113,4 +112,3 @@ uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len)
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#define _CRYPTO_BACKEND_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -58,14 +59,15 @@ void crypt_hmac_destroy(struct crypt_hmac *ctx);
|
||||
enum { CRYPT_RND_NORMAL = 0, CRYPT_RND_KEY = 1, CRYPT_RND_SALT = 2 };
|
||||
int crypt_backend_rng(char *buffer, size_t length, int quality, int fips);
|
||||
|
||||
|
||||
/* PBKDF*/
|
||||
struct crypt_pbkdf_limits {
|
||||
uint32_t min_iterations, max_iterations;
|
||||
uint32_t min_memory, max_memory;
|
||||
uint32_t min_parallel, max_parallel;
|
||||
};
|
||||
int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *l);
|
||||
|
||||
/* PBKDF*/
|
||||
int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *l);
|
||||
int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length,
|
||||
@@ -79,26 +81,10 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
|
||||
uint32_t *iterations_out, uint32_t *memory_out,
|
||||
int (*progress)(uint32_t time_ms, void *usrptr), void *usrptr);
|
||||
|
||||
#if USE_INTERNAL_PBKDF2
|
||||
/* internal PBKDF2 implementation */
|
||||
int pkcs5_pbkdf2(const char *hash,
|
||||
const char *P, size_t Plen,
|
||||
const char *S, size_t Slen,
|
||||
unsigned int c,
|
||||
unsigned int dkLen, char *DK,
|
||||
unsigned int hash_block_size);
|
||||
#endif
|
||||
|
||||
/* Argon2 implementation wrapper */
|
||||
int argon2(const char *type, const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length,
|
||||
char *key, size_t key_length,
|
||||
uint32_t iterations, uint32_t memory, uint32_t parallel);
|
||||
|
||||
/* CRC32 */
|
||||
uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len);
|
||||
|
||||
/* ciphers */
|
||||
/* Block ciphers */
|
||||
int crypt_cipher_ivsize(const char *name, const char *mode);
|
||||
int crypt_cipher_wrapped_key(const char *name, const char *mode);
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
@@ -110,20 +96,28 @@ int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length);
|
||||
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx);
|
||||
|
||||
/* Check availability of a cipher */
|
||||
int crypt_cipher_check(const char *name, const char *mode,
|
||||
const char *integrity, size_t key_length);
|
||||
/* Benchmark of kernel cipher performance */
|
||||
int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, size_t buffer_size,
|
||||
const char *key, size_t key_size, const char *iv, size_t iv_size,
|
||||
double *encryption_mbs, double *decryption_mbs);
|
||||
|
||||
/* storage encryption wrappers */
|
||||
int crypt_storage_init(struct crypt_storage **ctx, uint64_t sector_start,
|
||||
/* Check availability of a cipher (in kernel only) */
|
||||
int crypt_cipher_check_kernel(const char *name, const char *mode,
|
||||
const char *integrity, size_t key_length);
|
||||
|
||||
/* Storage encryption wrappers */
|
||||
int crypt_storage_init(struct crypt_storage **ctx, size_t sector_size,
|
||||
const char *cipher, const char *cipher_mode,
|
||||
const void *key, size_t key_length);
|
||||
void crypt_storage_destroy(struct crypt_storage *ctx);
|
||||
int crypt_storage_decrypt(struct crypt_storage *ctx, uint64_t sector,
|
||||
size_t count, char *buffer);
|
||||
int crypt_storage_encrypt(struct crypt_storage *ctx, uint64_t sector,
|
||||
size_t count, char *buffer);
|
||||
int crypt_storage_decrypt(struct crypt_storage *ctx, uint64_t iv_offset,
|
||||
uint64_t length, char *buffer);
|
||||
int crypt_storage_encrypt(struct crypt_storage *ctx, uint64_t iv_offset,
|
||||
uint64_t length, char *buffer);
|
||||
|
||||
bool crypt_storage_kernel_only(struct crypt_storage *ctx);
|
||||
|
||||
/* Memzero helper (memset on stack can be optimized out) */
|
||||
static inline void crypt_backend_memzero(void *s, size_t n)
|
||||
|
||||
59
lib/crypto_backend/crypto_backend_internal.h
Normal file
59
lib/crypto_backend/crypto_backend_internal.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* crypto backend implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2019 Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
#ifndef _CRYPTO_BACKEND_INTERNAL_H
|
||||
#define _CRYPTO_BACKEND_INTERNAL_H
|
||||
|
||||
#include "crypto_backend.h"
|
||||
|
||||
#if USE_INTERNAL_PBKDF2
|
||||
/* internal PBKDF2 implementation */
|
||||
int pkcs5_pbkdf2(const char *hash,
|
||||
const char *P, size_t Plen,
|
||||
const char *S, size_t Slen,
|
||||
unsigned int c,
|
||||
unsigned int dkLen, char *DK,
|
||||
unsigned int hash_block_size);
|
||||
#endif
|
||||
|
||||
/* Argon2 implementation wrapper */
|
||||
int argon2(const char *type, const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length,
|
||||
char *key, size_t key_length,
|
||||
uint32_t iterations, uint32_t memory, uint32_t parallel);
|
||||
|
||||
/* Block ciphers: fallback to kernel crypto API */
|
||||
|
||||
struct crypt_cipher_kernel {
|
||||
int tfmfd;
|
||||
int opfd;
|
||||
};
|
||||
|
||||
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length);
|
||||
int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length);
|
||||
int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length);
|
||||
void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx);
|
||||
|
||||
#endif /* _CRYPTO_BACKEND_INTERNAL_H */
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
#ifdef ENABLE_AF_ALG
|
||||
|
||||
@@ -40,11 +40,6 @@
|
||||
#define SOL_ALG 279
|
||||
#endif
|
||||
|
||||
struct crypt_cipher {
|
||||
int tfmfd;
|
||||
int opfd;
|
||||
};
|
||||
|
||||
/*
|
||||
* ciphers
|
||||
*
|
||||
@@ -52,45 +47,41 @@ struct crypt_cipher {
|
||||
* ENOTSUP - AF_ALG family not available
|
||||
* (but cannot check specifically for skcipher API)
|
||||
*/
|
||||
static int _crypt_cipher_init(struct crypt_cipher **ctx,
|
||||
static int _crypt_cipher_init(struct crypt_cipher_kernel *ctx,
|
||||
const void *key, size_t key_length,
|
||||
struct sockaddr_alg *sa)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
if (!ctx)
|
||||
return -EINVAL;
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
h->opfd = -1;
|
||||
h->tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
|
||||
if (h->tfmfd < 0) {
|
||||
crypt_cipher_destroy(h);
|
||||
ctx->opfd = -1;
|
||||
ctx->tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
|
||||
if (ctx->tfmfd < 0) {
|
||||
crypt_cipher_destroy_kernel(ctx);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (bind(h->tfmfd, (struct sockaddr *)sa, sizeof(*sa)) < 0) {
|
||||
crypt_cipher_destroy(h);
|
||||
if (bind(ctx->tfmfd, (struct sockaddr *)sa, sizeof(*sa)) < 0) {
|
||||
crypt_cipher_destroy_kernel(ctx);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (setsockopt(h->tfmfd, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) {
|
||||
crypt_cipher_destroy(h);
|
||||
if (setsockopt(ctx->tfmfd, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) {
|
||||
crypt_cipher_destroy_kernel(ctx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
h->opfd = accept(h->tfmfd, NULL, 0);
|
||||
if (h->opfd < 0) {
|
||||
crypt_cipher_destroy(h);
|
||||
ctx->opfd = accept(ctx->tfmfd, NULL, 0);
|
||||
if (ctx->opfd < 0) {
|
||||
crypt_cipher_destroy_kernel(ctx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct sockaddr_alg sa = {
|
||||
.salg_family = AF_ALG,
|
||||
@@ -106,10 +97,10 @@ int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
}
|
||||
|
||||
/* The in/out should be aligned to page boundary */
|
||||
static int crypt_cipher_crypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length,
|
||||
uint32_t direction)
|
||||
static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length,
|
||||
uint32_t direction)
|
||||
{
|
||||
int r = 0;
|
||||
ssize_t len;
|
||||
@@ -173,36 +164,37 @@ bad:
|
||||
return r;
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_crypt(ctx, in, out, length,
|
||||
iv, iv_length, ALG_OP_ENCRYPT);
|
||||
return _crypt_cipher_crypt(ctx, in, out, length,
|
||||
iv, iv_length, ALG_OP_ENCRYPT);
|
||||
}
|
||||
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_crypt(ctx, in, out, length,
|
||||
iv, iv_length, ALG_OP_DECRYPT);
|
||||
return _crypt_cipher_crypt(ctx, in, out, length,
|
||||
iv, iv_length, ALG_OP_DECRYPT);
|
||||
}
|
||||
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx)
|
||||
{
|
||||
if (ctx->tfmfd >= 0)
|
||||
close(ctx->tfmfd);
|
||||
if (ctx->opfd >= 0)
|
||||
close(ctx->opfd);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
|
||||
ctx->tfmfd = -1;
|
||||
ctx->opfd = -1;
|
||||
}
|
||||
|
||||
int crypt_cipher_check(const char *name, const char *mode,
|
||||
const char *integrity, size_t key_length)
|
||||
int crypt_cipher_check_kernel(const char *name, const char *mode,
|
||||
const char *integrity, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *c = NULL;
|
||||
struct crypt_cipher_kernel c;
|
||||
char mode_name[64], tmp_salg_name[180], *real_mode = NULL, *cipher_iv = NULL, *key;
|
||||
const char *salg_type;
|
||||
bool aead;
|
||||
@@ -252,40 +244,40 @@ int crypt_cipher_check(const char *name, const char *mode,
|
||||
*key = 0xef;
|
||||
|
||||
r = _crypt_cipher_init(&c, key, key_length, &sa);
|
||||
if (c)
|
||||
crypt_cipher_destroy(c);
|
||||
crypt_cipher_destroy_kernel(&c);
|
||||
free(key);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#else /* ENABLE_AF_ALG */
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *buffer, size_t length)
|
||||
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
int crypt_cipher_check(const char *name, const char *mode,
|
||||
const char *integrity, size_t key_length)
|
||||
int crypt_cipher_check_kernel(const char *name, const char *mode,
|
||||
const char *integrity, size_t key_length)
|
||||
{
|
||||
/* Cannot check, expect success. */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <gcrypt.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
static int crypto_backend_initialised = 0;
|
||||
static int crypto_backend_secmem = 1;
|
||||
@@ -43,6 +43,14 @@ struct crypt_hmac {
|
||||
int hash_len;
|
||||
};
|
||||
|
||||
struct crypt_cipher {
|
||||
bool use_kernel;
|
||||
union {
|
||||
struct crypt_cipher_kernel kernel;
|
||||
gcry_cipher_hd_t hd;
|
||||
} u;
|
||||
};
|
||||
|
||||
/*
|
||||
* Test for wrong Whirlpool variant,
|
||||
* Ref: http://lists.gnupg.org/pipermail/gcrypt-devel/2014-January/002889.html
|
||||
@@ -366,3 +374,108 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Block ciphers */
|
||||
static int _cipher_init(gcry_cipher_hd_t *hd, const char *name,
|
||||
const char *mode, const void *buffer, size_t length)
|
||||
{
|
||||
int cipher_id, mode_id;
|
||||
|
||||
cipher_id = gcry_cipher_map_name(name);
|
||||
if (cipher_id == GCRY_CIPHER_MODE_NONE)
|
||||
return -ENOENT;
|
||||
|
||||
if (!strcmp(mode, "ecb"))
|
||||
mode_id = GCRY_CIPHER_MODE_ECB;
|
||||
else if (!strcmp(mode, "cbc"))
|
||||
mode_id = GCRY_CIPHER_MODE_CBC;
|
||||
#if HAVE_DECL_GCRY_CIPHER_MODE_XTS
|
||||
else if (!strcmp(mode, "xts"))
|
||||
mode_id = GCRY_CIPHER_MODE_XTS;
|
||||
#endif
|
||||
else
|
||||
return -ENOENT;
|
||||
|
||||
if (gcry_cipher_open(hd, cipher_id, mode_id, 0))
|
||||
return -EINVAL;
|
||||
|
||||
if (gcry_cipher_setkey(*hd, buffer, length)) {
|
||||
gcry_cipher_close(*hd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
int r;
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!_cipher_init(&h->u.hd, name, mode, key, key_length)) {
|
||||
h->use_kernel = false;
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = crypt_cipher_init_kernel(&h->u.kernel, name, mode, key, key_length);
|
||||
if (r < 0) {
|
||||
free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
h->use_kernel = true;
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
{
|
||||
if (ctx->use_kernel)
|
||||
crypt_cipher_destroy_kernel(&ctx->u.kernel);
|
||||
else
|
||||
gcry_cipher_close(ctx->u.hd);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
if (ctx->use_kernel)
|
||||
return crypt_cipher_encrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
|
||||
|
||||
if (iv && gcry_cipher_setiv(ctx->u.hd, iv, iv_length))
|
||||
return -EINVAL;
|
||||
|
||||
if (gcry_cipher_encrypt(ctx->u.hd, out, length, in, length))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
if (ctx->use_kernel)
|
||||
return crypt_cipher_decrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
|
||||
|
||||
if (iv && gcry_cipher_setiv(ctx->u.hd, iv, iv_length))
|
||||
return -EINVAL;
|
||||
|
||||
if (gcry_cipher_decrypt(ctx->u.hd, out, length, in, length))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
|
||||
{
|
||||
return ctx->use_kernel;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <linux/if_alg.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
/* FIXME: remove later */
|
||||
#ifndef AF_ALG
|
||||
@@ -77,6 +77,10 @@ struct crypt_hmac {
|
||||
int hash_len;
|
||||
};
|
||||
|
||||
struct crypt_cipher {
|
||||
struct crypt_cipher_kernel ck;
|
||||
};
|
||||
|
||||
static int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *opfd,
|
||||
const void *key, size_t key_length)
|
||||
{
|
||||
@@ -342,3 +346,49 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Block ciphers */
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
int r;
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
r = crypt_cipher_init_kernel(&h->ck, name, mode, key, key_length);
|
||||
if (r < 0) {
|
||||
free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
{
|
||||
crypt_cipher_destroy_kernel(&ctx->ck);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_encrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
|
||||
}
|
||||
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_decrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
|
||||
}
|
||||
|
||||
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <nettle/sha3.h>
|
||||
#include <nettle/hmac.h>
|
||||
#include <nettle/pbkdf2.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
#if HAVE_NETTLE_VERSION_H
|
||||
#include <nettle/version.h>
|
||||
@@ -192,6 +192,10 @@ struct crypt_hmac {
|
||||
uint8_t *key;
|
||||
};
|
||||
|
||||
struct crypt_cipher {
|
||||
struct crypt_cipher_kernel ck;
|
||||
};
|
||||
|
||||
uint32_t crypt_backend_flags(void)
|
||||
{
|
||||
return 0;
|
||||
@@ -383,3 +387,49 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Block ciphers */
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
int r;
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
r = crypt_cipher_init_kernel(&h->ck, name, mode, key, key_length);
|
||||
if (r < 0) {
|
||||
free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
{
|
||||
crypt_cipher_destroy_kernel(&ctx->ck);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_encrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
|
||||
}
|
||||
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_decrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
|
||||
}
|
||||
|
||||
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <errno.h>
|
||||
#include <nss.h>
|
||||
#include <pk11pub.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
#define CONST_CAST(x) (x)(uintptr_t)
|
||||
|
||||
@@ -59,6 +59,10 @@ struct crypt_hmac {
|
||||
const struct hash_alg *hash;
|
||||
};
|
||||
|
||||
struct crypt_cipher {
|
||||
struct crypt_cipher_kernel ck;
|
||||
};
|
||||
|
||||
static struct hash_alg *_get_alg(const char *name)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -331,3 +335,49 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Block ciphers */
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
int r;
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
r = crypt_cipher_init_kernel(&h->ck, name, mode, key, key_length);
|
||||
if (r < 0) {
|
||||
free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
{
|
||||
crypt_cipher_destroy_kernel(&ctx->ck);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_encrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
|
||||
}
|
||||
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
return crypt_cipher_decrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
|
||||
}
|
||||
|
||||
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/rand.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
static int crypto_backend_initialised = 0;
|
||||
|
||||
@@ -49,6 +49,18 @@ struct crypt_hmac {
|
||||
int hash_len;
|
||||
};
|
||||
|
||||
struct crypt_cipher {
|
||||
bool use_kernel;
|
||||
union {
|
||||
struct crypt_cipher_kernel kernel;
|
||||
struct {
|
||||
EVP_CIPHER_CTX *hd_enc;
|
||||
EVP_CIPHER_CTX *hd_dec;
|
||||
size_t iv_length;
|
||||
} lib;
|
||||
} u;
|
||||
};
|
||||
|
||||
/*
|
||||
* Compatible wrappers for OpenSSL < 1.1.0 and LibreSSL < 2.7.0
|
||||
*/
|
||||
@@ -335,3 +347,161 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Block ciphers */
|
||||
static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec)
|
||||
{
|
||||
EVP_CIPHER_CTX_free(*hd_enc);
|
||||
*hd_enc = NULL;
|
||||
|
||||
EVP_CIPHER_CTX_free(*hd_dec);
|
||||
*hd_dec = NULL;
|
||||
}
|
||||
|
||||
static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const char *name,
|
||||
const char *mode, const void *key, size_t key_length, size_t *iv_length)
|
||||
{
|
||||
char cipher_name[256];
|
||||
const EVP_CIPHER *type;
|
||||
int r, key_bits;
|
||||
|
||||
key_bits = key_length * 8;
|
||||
if (!strcmp(mode, "xts"))
|
||||
key_bits /= 2;
|
||||
|
||||
r = snprintf(cipher_name, sizeof(cipher_name), "%s-%d-%s", name, key_bits, mode);
|
||||
if (r < 0 || r >= (int)sizeof(cipher_name))
|
||||
return -EINVAL;
|
||||
|
||||
type = EVP_get_cipherbyname(cipher_name);
|
||||
if (!type)
|
||||
return -ENOENT;
|
||||
|
||||
if (EVP_CIPHER_key_length(type) != (int)key_length)
|
||||
return -EINVAL;
|
||||
|
||||
*hd_enc = EVP_CIPHER_CTX_new();
|
||||
*hd_dec = EVP_CIPHER_CTX_new();
|
||||
*iv_length = EVP_CIPHER_iv_length(type);
|
||||
|
||||
if (!*hd_enc || !*hd_dec)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_EncryptInit_ex(*hd_enc, type, NULL, key, NULL) != 1 ||
|
||||
EVP_DecryptInit_ex(*hd_dec, type, NULL, key, NULL) != 1) {
|
||||
_cipher_destroy(hd_enc, hd_dec);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (EVP_CIPHER_CTX_set_padding(*hd_enc, 0) != 1 ||
|
||||
EVP_CIPHER_CTX_set_padding(*hd_dec, 0) != 1) {
|
||||
_cipher_destroy(hd_enc, hd_dec);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
{
|
||||
struct crypt_cipher *h;
|
||||
int r;
|
||||
|
||||
h = malloc(sizeof(*h));
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, name, mode, key,
|
||||
key_length, &h->u.lib.iv_length)) {
|
||||
h->use_kernel = false;
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = crypt_cipher_init_kernel(&h->u.kernel, name, mode, key, key_length);
|
||||
if (r < 0) {
|
||||
free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
h->use_kernel = true;
|
||||
*ctx = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
{
|
||||
if (ctx->use_kernel)
|
||||
crypt_cipher_destroy_kernel(&ctx->u.kernel);
|
||||
else
|
||||
_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static int _cipher_encrypt(struct crypt_cipher *ctx, const unsigned char *in, unsigned char *out,
|
||||
int length, const unsigned char *iv, size_t iv_length)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (ctx->u.lib.iv_length != iv_length)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_EncryptInit_ex(ctx->u.lib.hd_enc, NULL, NULL, NULL, iv) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_EncryptUpdate(ctx->u.lib.hd_enc, out, &len, in, length) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_EncryptFinal(ctx->u.lib.hd_enc, out + len, &len) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _cipher_decrypt(struct crypt_cipher *ctx, const unsigned char *in, unsigned char *out,
|
||||
int length, const unsigned char *iv, size_t iv_length)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (ctx->u.lib.iv_length != iv_length)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_DecryptInit_ex(ctx->u.lib.hd_dec, NULL, NULL, NULL, iv) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_DecryptUpdate(ctx->u.lib.hd_dec, out, &len, in, length) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (EVP_DecryptFinal(ctx->u.lib.hd_dec, out + len, &len) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
if (ctx->use_kernel)
|
||||
return crypt_cipher_encrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
|
||||
|
||||
return _cipher_encrypt(ctx, (const unsigned char*)in,
|
||||
(unsigned char *)out, length, (const unsigned char*)iv, iv_length);
|
||||
}
|
||||
|
||||
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
|
||||
const char *in, char *out, size_t length,
|
||||
const char *iv, size_t iv_length)
|
||||
{
|
||||
if (ctx->use_kernel)
|
||||
return crypt_cipher_decrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
|
||||
|
||||
return _cipher_decrypt(ctx, (const unsigned char*)in,
|
||||
(unsigned char *)out, length, (const unsigned char*)iv, iv_length);
|
||||
}
|
||||
|
||||
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
|
||||
{
|
||||
return ctx->use_kernel;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "crypto_backend.h"
|
||||
|
||||
#define SECTOR_SHIFT 9
|
||||
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
|
||||
|
||||
/*
|
||||
* Internal IV helper
|
||||
@@ -41,7 +40,8 @@ struct crypt_sector_iv {
|
||||
|
||||
/* Block encryption storage context */
|
||||
struct crypt_storage {
|
||||
uint64_t sector_start;
|
||||
unsigned sector_shift;
|
||||
unsigned iv_shift;
|
||||
struct crypt_cipher *cipher;
|
||||
struct crypt_sector_iv cipher_iv;
|
||||
};
|
||||
@@ -194,7 +194,7 @@ static void crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
|
||||
/* Block encryption storage wrappers */
|
||||
|
||||
int crypt_storage_init(struct crypt_storage **ctx,
|
||||
uint64_t sector_start,
|
||||
size_t sector_size,
|
||||
const char *cipher,
|
||||
const char *cipher_mode,
|
||||
const void *key, size_t key_length)
|
||||
@@ -204,6 +204,11 @@ int crypt_storage_init(struct crypt_storage **ctx,
|
||||
char *cipher_iv = NULL;
|
||||
int r = -EIO;
|
||||
|
||||
if (sector_size < (1 << SECTOR_SHIFT) ||
|
||||
sector_size > (1 << (SECTOR_SHIFT + 3)) ||
|
||||
sector_size & (sector_size - 1))
|
||||
return -EINVAL;
|
||||
|
||||
s = malloc(sizeof(*s));
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
@@ -230,27 +235,33 @@ int crypt_storage_init(struct crypt_storage **ctx,
|
||||
return r;
|
||||
}
|
||||
|
||||
s->sector_start = sector_start;
|
||||
s->sector_shift = int_log2(sector_size);
|
||||
s->iv_shift = s->sector_shift - SECTOR_SHIFT;
|
||||
|
||||
*ctx = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_storage_decrypt(struct crypt_storage *ctx,
|
||||
uint64_t sector, size_t count,
|
||||
char *buffer)
|
||||
uint64_t iv_offset,
|
||||
uint64_t length, char *buffer)
|
||||
{
|
||||
unsigned int i;
|
||||
uint64_t i;
|
||||
int r = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
r = crypt_sector_iv_generate(&ctx->cipher_iv, sector + i);
|
||||
if (length & ((1 << ctx->sector_shift) - 1))
|
||||
return -EINVAL;
|
||||
|
||||
length >>= ctx->sector_shift;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
r = crypt_sector_iv_generate(&ctx->cipher_iv, iv_offset + (uint64_t)(i << ctx->iv_shift));
|
||||
if (r)
|
||||
break;
|
||||
r = crypt_cipher_decrypt(ctx->cipher,
|
||||
&buffer[i * SECTOR_SIZE],
|
||||
&buffer[i * SECTOR_SIZE],
|
||||
SECTOR_SIZE,
|
||||
&buffer[i << ctx->sector_shift],
|
||||
&buffer[i << ctx->sector_shift],
|
||||
1 << ctx->sector_shift,
|
||||
ctx->cipher_iv.iv,
|
||||
ctx->cipher_iv.iv_size);
|
||||
if (r)
|
||||
@@ -261,20 +272,25 @@ int crypt_storage_decrypt(struct crypt_storage *ctx,
|
||||
}
|
||||
|
||||
int crypt_storage_encrypt(struct crypt_storage *ctx,
|
||||
uint64_t sector, size_t count,
|
||||
char *buffer)
|
||||
uint64_t iv_offset,
|
||||
uint64_t length, char *buffer)
|
||||
{
|
||||
unsigned int i;
|
||||
uint64_t i;
|
||||
int r = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
r = crypt_sector_iv_generate(&ctx->cipher_iv, sector + i);
|
||||
if (length & ((1 << ctx->sector_shift) - 1))
|
||||
return -EINVAL;
|
||||
|
||||
length >>= ctx->sector_shift;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
r = crypt_sector_iv_generate(&ctx->cipher_iv, iv_offset + (i << ctx->iv_shift));
|
||||
if (r)
|
||||
break;
|
||||
r = crypt_cipher_encrypt(ctx->cipher,
|
||||
&buffer[i * SECTOR_SIZE],
|
||||
&buffer[i * SECTOR_SIZE],
|
||||
SECTOR_SIZE,
|
||||
&buffer[i << ctx->sector_shift],
|
||||
&buffer[i << ctx->sector_shift],
|
||||
1 << ctx->sector_shift,
|
||||
ctx->cipher_iv.iv,
|
||||
ctx->cipher_iv.iv_size);
|
||||
if (r)
|
||||
@@ -297,3 +313,8 @@ void crypt_storage_destroy(struct crypt_storage *ctx)
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
bool crypt_storage_kernel_only(struct crypt_storage *ctx)
|
||||
{
|
||||
return crypt_cipher_kernel_only(ctx->cipher);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <alloca.h>
|
||||
#include "crypto_backend.h"
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
static int hash_buf(const char *src, size_t src_len,
|
||||
char *dst, size_t dst_len,
|
||||
@@ -230,197 +230,3 @@ out:
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
|
||||
struct test_vector {
|
||||
const char *hash;
|
||||
unsigned int hash_block_length;
|
||||
unsigned int iterations;
|
||||
const char *password;
|
||||
unsigned int password_length;
|
||||
const char *salt;
|
||||
unsigned int salt_length;
|
||||
const char *output;
|
||||
unsigned int output_length;
|
||||
};
|
||||
|
||||
struct test_vector test_vectors[] = {
|
||||
/* RFC 3962 */
|
||||
{
|
||||
"sha1", 64, 1,
|
||||
"password", 8,
|
||||
"ATHENA.MIT.EDUraeburn", 21,
|
||||
"\xcd\xed\xb5\x28\x1b\xb2\xf8\x01"
|
||||
"\x56\x5a\x11\x22\xb2\x56\x35\x15"
|
||||
"\x0a\xd1\xf7\xa0\x4b\xb9\xf3\xa3"
|
||||
"\x33\xec\xc0\xe2\xe1\xf7\x08\x37", 32
|
||||
}, {
|
||||
"sha1", 64, 2,
|
||||
"password", 8,
|
||||
"ATHENA.MIT.EDUraeburn", 21,
|
||||
"\x01\xdb\xee\x7f\x4a\x9e\x24\x3e"
|
||||
"\x98\x8b\x62\xc7\x3c\xda\x93\x5d"
|
||||
"\xa0\x53\x78\xb9\x32\x44\xec\x8f"
|
||||
"\x48\xa9\x9e\x61\xad\x79\x9d\x86", 32
|
||||
}, {
|
||||
"sha1", 64, 1200,
|
||||
"password", 8,
|
||||
"ATHENA.MIT.EDUraeburn", 21,
|
||||
"\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e"
|
||||
"\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b"
|
||||
"\xa7\xe5\x2d\xdb\xc5\xe5\x14\x2f"
|
||||
"\x70\x8a\x31\xe2\xe6\x2b\x1e\x13", 32
|
||||
}, {
|
||||
"sha1", 64, 5,
|
||||
"password", 8,
|
||||
"\0224VxxV4\022", 8, // "\x1234567878563412
|
||||
"\xd1\xda\xa7\x86\x15\xf2\x87\xe6"
|
||||
"\xa1\xc8\xb1\x20\xd7\x06\x2a\x49"
|
||||
"\x3f\x98\xd2\x03\xe6\xbe\x49\xa6"
|
||||
"\xad\xf4\xfa\x57\x4b\x6e\x64\xee", 32
|
||||
}, {
|
||||
"sha1", 64, 1200,
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 64,
|
||||
"pass phrase equals block size", 29,
|
||||
"\x13\x9c\x30\xc0\x96\x6b\xc3\x2b"
|
||||
"\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9"
|
||||
"\xc5\xec\x59\xf1\xa4\x52\xf5\xcc"
|
||||
"\x9a\xd9\x40\xfe\xa0\x59\x8e\xd1", 32
|
||||
}, {
|
||||
"sha1", 64, 1200,
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 65,
|
||||
"pass phrase exceeds block size", 30,
|
||||
"\x9c\xca\xd6\xd4\x68\x77\x0c\xd5"
|
||||
"\x1b\x10\xe6\xa6\x87\x21\xbe\x61"
|
||||
"\x1a\x8b\x4d\x28\x26\x01\xdb\x3b"
|
||||
"\x36\xbe\x92\x46\x91\x5e\xc8\x2a", 32
|
||||
}, {
|
||||
"sha1", 64, 50,
|
||||
"\360\235\204\236", 4, // g-clef ("\xf09d849e)
|
||||
"EXAMPLE.COMpianist", 18,
|
||||
"\x6b\x9c\xf2\x6d\x45\x45\x5a\x43"
|
||||
"\xa5\xb8\xbb\x27\x6a\x40\x3b\x39"
|
||||
"\xe7\xfe\x37\xa0\xc4\x1e\x02\xc2"
|
||||
"\x81\xff\x30\x69\xe1\xe9\x4f\x52", 32
|
||||
}, {
|
||||
/* RFC-6070 */
|
||||
"sha1", 64, 1,
|
||||
"password", 8,
|
||||
"salt", 4,
|
||||
"\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9"
|
||||
"\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6", 20
|
||||
}, {
|
||||
"sha1", 64, 2,
|
||||
"password", 8,
|
||||
"salt", 4,
|
||||
"\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e"
|
||||
"\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57", 20
|
||||
}, {
|
||||
"sha1", 64, 4096,
|
||||
"password", 8,
|
||||
"salt", 4,
|
||||
"\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad"
|
||||
"\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1", 20
|
||||
}, {
|
||||
"sha1", 64, 16777216,
|
||||
"password", 8,
|
||||
"salt", 4,
|
||||
"\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94"
|
||||
"\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84", 20
|
||||
}, {
|
||||
"sha1", 64, 4096,
|
||||
"passwordPASSWORDpassword", 24,
|
||||
"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
|
||||
"\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8"
|
||||
"\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96"
|
||||
"\x4c\xf2\xf0\x70\x38", 25
|
||||
}, {
|
||||
"sha1", 64, 4096,
|
||||
"pass\0word", 9,
|
||||
"sa\0lt", 5,
|
||||
"\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37"
|
||||
"\xd7\xf0\x34\x25\xe0\xc3", 16
|
||||
}, {
|
||||
/* empty password test */
|
||||
"sha1", 64, 2,
|
||||
"", 0,
|
||||
"salt", 4,
|
||||
"\x13\x3a\x4c\xe8\x37\xb4\xd2\x52\x1e\xe2"
|
||||
"\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97", 20
|
||||
}, {
|
||||
/* Password exceeds block size test */
|
||||
"sha256", 64, 1200,
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 65,
|
||||
"pass phrase exceeds block size", 30,
|
||||
"\x22\x34\x4b\xc4\xb6\xe3\x26\x75"
|
||||
"\xa8\x09\x0f\x3e\xa8\x0b\xe0\x1d"
|
||||
"\x5f\x95\x12\x6a\x2c\xdd\xc3\xfa"
|
||||
"\xcc\x4a\x5e\x6d\xca\x04\xec\x58", 32
|
||||
}, {
|
||||
"sha512", 128, 1200,
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 129,
|
||||
"pass phrase exceeds block size", 30,
|
||||
"\x0f\xb2\xed\x2c\x0e\x6e\xfb\x7d"
|
||||
"\x7d\x8e\xdd\x58\x01\xb4\x59\x72"
|
||||
"\x99\x92\x16\x30\x5e\xa4\x36\x8d"
|
||||
"\x76\x14\x80\xf3\xe3\x7a\x22\xb9", 32
|
||||
}, {
|
||||
"whirlpool", 64, 1200,
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 65,
|
||||
"pass phrase exceeds block size", 30,
|
||||
"\x9c\x1c\x74\xf5\x88\x26\xe7\x6a"
|
||||
"\x53\x58\xf4\x0c\x39\xe7\x80\x89"
|
||||
"\x07\xc0\x31\x19\x9a\x50\xa2\x48"
|
||||
"\xf1\xd9\xfe\x78\x64\xe5\x84\x50", 32
|
||||
}
|
||||
};
|
||||
|
||||
static void printhex(const char *s, const char *buf, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
printf("%s: ", s);
|
||||
for (i = 0; i < len; i++)
|
||||
printf("\\x%02x", (unsigned char)buf[i]);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static int pkcs5_pbkdf2_test_vectors(void)
|
||||
{
|
||||
char result[64];
|
||||
unsigned int i, j;
|
||||
struct test_vector *vec;
|
||||
|
||||
for (i = 0; i < (sizeof(test_vectors) / sizeof(*test_vectors)); i++) {
|
||||
vec = &test_vectors[i];
|
||||
for (j = 1; j <= vec->output_length; j++) {
|
||||
if (pkcs5_pbkdf2(vec->hash,
|
||||
vec->password, vec->password_length,
|
||||
vec->salt, vec->salt_length,
|
||||
vec->iterations,
|
||||
j, result, vec->hash_block_length)) {
|
||||
printf("pbkdf2 failed, vector %d\n", i);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (memcmp(result, vec->output, j) != 0) {
|
||||
printf("vector %u\n", i);
|
||||
printhex(" got", result, j);
|
||||
printhex("want", vec->output, j);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(result, 0, sizeof(result));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -35,14 +35,14 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
|
||||
int devfd, r;
|
||||
|
||||
devfd = device_open(cd, device, O_RDONLY);
|
||||
if(devfd < 0) {
|
||||
if(devfd < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
|
||||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic)) ||
|
||||
(sb->version != SB_VERSION_1 && sb->version != SB_VERSION_2)) {
|
||||
(sb->version != SB_VERSION_1 && sb->version != SB_VERSION_2 &&
|
||||
sb->version != SB_VERSION_3)) {
|
||||
log_std(cd, "No integrity superblock detected on %s.\n",
|
||||
device_path(device));
|
||||
r = -EINVAL;
|
||||
@@ -55,7 +55,6 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
|
||||
r = 0;
|
||||
}
|
||||
|
||||
close(devfd);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -92,9 +91,11 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
|
||||
log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
|
||||
if (sb.version == SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
|
||||
log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
|
||||
log_std(cd, "flags %s%s\n",
|
||||
log_std(cd, "log2_blocks_per_bitmap %u\n", sb.log2_blocks_per_bitmap_bit);
|
||||
log_std(cd, "flags %s%s%s\n",
|
||||
sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
|
||||
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "");
|
||||
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "",
|
||||
sb.flags & SB_FLAG_DIRTY_BITMAP ? "dirty_bitmap " : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -33,9 +33,11 @@ struct crypt_dm_active_device;
|
||||
#define SB_MAGIC "integrt"
|
||||
#define SB_VERSION_1 1
|
||||
#define SB_VERSION_2 2
|
||||
#define SB_VERSION_3 3
|
||||
|
||||
#define SB_FLAG_HAVE_JOURNAL_MAC (1 << 0)
|
||||
#define SB_FLAG_RECALCULATING (1 << 1) /* V2 only */
|
||||
#define SB_FLAG_DIRTY_BITMAP (1 << 2) /* V3 only */
|
||||
|
||||
struct superblock {
|
||||
uint8_t magic[8];
|
||||
@@ -46,8 +48,9 @@ struct superblock {
|
||||
uint64_t provided_data_sectors;
|
||||
uint32_t flags;
|
||||
uint8_t log2_sectors_per_block;
|
||||
uint8_t pad[3];
|
||||
uint64_t recalc_sector; /* V2 only */
|
||||
uint8_t log2_blocks_per_bitmap_bit; /* V3 only */
|
||||
uint8_t pad[2];
|
||||
uint64_t recalc_sector; /* V2 only */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
int INTEGRITY_read_sb(struct crypt_device *cd, struct crypt_params_integrity *params);
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "utils_keyring.h"
|
||||
#include "utils_io.h"
|
||||
#include "crypto_backend.h"
|
||||
#include "utils_storage_wrappers.h"
|
||||
|
||||
#include "libcryptsetup.h"
|
||||
|
||||
@@ -73,10 +74,13 @@
|
||||
} while (0)
|
||||
|
||||
struct crypt_device;
|
||||
struct luks2_reenc_context;
|
||||
|
||||
struct volume_key {
|
||||
int id;
|
||||
size_t keylength;
|
||||
const char *key_description;
|
||||
struct volume_key *next;
|
||||
char key[];
|
||||
};
|
||||
|
||||
@@ -84,6 +88,11 @@ struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key);
|
||||
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength);
|
||||
void crypt_free_volume_key(struct volume_key *vk);
|
||||
int crypt_volume_key_set_description(struct volume_key *key, const char *key_description);
|
||||
void crypt_volume_key_set_id(struct volume_key *vk, int id);
|
||||
int crypt_volume_key_get_id(const struct volume_key *vk);
|
||||
void crypt_volume_key_add_next(struct volume_key **vks, struct volume_key *vk);
|
||||
struct volume_key *crypt_volume_key_next(struct volume_key *vk);
|
||||
struct volume_key *crypt_volume_key_by_id(struct volume_key *vk, int id);
|
||||
|
||||
struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd);
|
||||
int init_pbkdf_type(struct crypt_device *cd,
|
||||
@@ -100,6 +109,7 @@ const char *crypt_get_cipher_spec(struct crypt_device *cd);
|
||||
struct device;
|
||||
int device_alloc(struct crypt_device *cd, struct device **device, const char *path);
|
||||
int device_alloc_no_check(struct device **device, const char *path);
|
||||
void device_close(struct crypt_device *cd, struct device *device);
|
||||
void device_free(struct crypt_device *cd, struct device *device);
|
||||
const char *device_path(const struct device *device);
|
||||
const char *device_dm_name(const struct device *device);
|
||||
@@ -113,13 +123,15 @@ size_t device_block_size(struct crypt_device *cd, struct device *device);
|
||||
int device_read_ahead(struct device *device, uint32_t *read_ahead);
|
||||
int device_size(struct device *device, uint64_t *size);
|
||||
int device_open(struct crypt_device *cd, struct device *device, int flags);
|
||||
int device_open_excl(struct crypt_device *cd, struct device *device, int flags);
|
||||
void device_release_excl(struct crypt_device *cd, struct device *device);
|
||||
void device_disable_direct_io(struct device *device);
|
||||
int device_is_identical(struct device *device1, struct device *device2);
|
||||
int device_is_rotational(struct device *device);
|
||||
size_t device_alignment(struct device *device);
|
||||
int device_direct_io(const struct device *device);
|
||||
int device_fallocate(struct device *device, uint64_t size);
|
||||
void device_sync(struct crypt_device *cd, struct device *device, int devfd);
|
||||
void device_sync(struct crypt_device *cd, struct device *device);
|
||||
int device_check_size(struct crypt_device *cd,
|
||||
struct device *device,
|
||||
uint64_t req_offset, int falloc);
|
||||
@@ -129,6 +141,7 @@ int device_read_lock(struct crypt_device *cd, struct device *device);
|
||||
int device_write_lock(struct crypt_device *cd, struct device *device);
|
||||
void device_read_unlock(struct crypt_device *cd, struct device *device);
|
||||
void device_write_unlock(struct crypt_device *cd, struct device *device);
|
||||
bool device_is_locked(struct device *device);
|
||||
|
||||
enum devcheck { DEV_OK = 0, DEV_EXCL = 1 };
|
||||
int device_check_access(struct crypt_device *cd,
|
||||
@@ -163,6 +176,7 @@ char *crypt_get_base_device(const char *dev_path);
|
||||
uint64_t crypt_dev_partition_offset(const char *dev_path);
|
||||
int lookup_by_disk_id(const char *dm_uuid);
|
||||
int lookup_by_sysfs_uuid_field(const char *dm_uuid, size_t max_len);
|
||||
int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid);
|
||||
|
||||
size_t crypt_getpagesize(void);
|
||||
unsigned crypt_cpusonline(void);
|
||||
@@ -199,6 +213,11 @@ int PLAIN_activate(struct crypt_device *cd,
|
||||
uint32_t flags);
|
||||
|
||||
void *crypt_get_hdr(struct crypt_device *cd, const char *type);
|
||||
void crypt_set_reenc_context(struct crypt_device *cd, struct luks2_reenc_context *rh);
|
||||
struct luks2_reenc_context *crypt_get_reenc_context(struct crypt_device *cd);
|
||||
|
||||
int onlyLUKS2(struct crypt_device *cd);
|
||||
int onlyLUKS2mask(struct crypt_device *cd, uint32_t mask);
|
||||
|
||||
int crypt_wipe_device(struct crypt_device *cd,
|
||||
struct device *device,
|
||||
@@ -218,7 +237,8 @@ int crypt_key_in_keyring(struct crypt_device *cd);
|
||||
void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring);
|
||||
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk);
|
||||
int crypt_use_keyring_for_vk(struct crypt_device *cd);
|
||||
void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description);
|
||||
void crypt_drop_keyring_key_by_description(struct crypt_device *cd, const char *key_description, key_type_t ktype);
|
||||
void crypt_drop_keyring_key(struct crypt_device *cd, struct volume_key *vks);
|
||||
|
||||
static inline uint64_t version(uint16_t major, uint16_t minor, uint16_t patch, uint16_t release)
|
||||
{
|
||||
@@ -227,4 +247,7 @@ static inline uint64_t version(uint16_t major, uint16_t minor, uint16_t patch, u
|
||||
|
||||
int kernel_version(uint64_t *kversion);
|
||||
|
||||
int crypt_serialize_lock(struct crypt_device *cd);
|
||||
void crypt_serialize_unlock(struct crypt_device *cd);
|
||||
|
||||
#endif /* INTERNAL_H */
|
||||
|
||||
@@ -546,11 +546,15 @@ struct crypt_params_tcrypt {
|
||||
*
|
||||
* @see crypt_format, crypt_load
|
||||
*
|
||||
* @note In bitmap tracking mode, the journal is implicitly disabled.
|
||||
* As an ugly workaround for compatibility, journal_watermark is overloaded
|
||||
* to mean 512-bytes sectors-per-bit and journal_commit_time means bitmap flush time.
|
||||
* All other journal parameters are not applied in the bitmap mode.
|
||||
*/
|
||||
struct crypt_params_integrity {
|
||||
uint64_t journal_size; /**< size of journal in bytes */
|
||||
unsigned int journal_watermark; /**< journal flush watermark in percents */
|
||||
unsigned int journal_commit_time; /**< journal commit time in ms */
|
||||
unsigned int journal_watermark; /**< journal flush watermark in percents; in bitmap mode sectors-per-bit */
|
||||
unsigned int journal_commit_time; /**< journal commit time (or bitmap flush time) in ms */
|
||||
uint32_t interleave_sectors; /**< number of interleave sectors (power of two) */
|
||||
uint32_t tag_size; /**< tag size per-sector in bytes */
|
||||
uint32_t sector_size; /**< sector size in bytes */
|
||||
@@ -957,6 +961,9 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
|
||||
/** create keyslot with new volume key and assign it to current dm-crypt segment */
|
||||
#define CRYPT_VOLUME_KEY_SET (1 << 1)
|
||||
|
||||
/** Assign key to first matching digest before creating new digest */
|
||||
#define CRYPT_VOLUME_KEY_DIGEST_REUSE (1 << 2)
|
||||
|
||||
/**
|
||||
* Add key slot using provided key.
|
||||
*
|
||||
@@ -1054,6 +1061,10 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
|
||||
#define CRYPT_ACTIVATE_RECALCULATE (1 << 17)
|
||||
/** reactivate existing and update flags, input only */
|
||||
#define CRYPT_ACTIVATE_REFRESH (1 << 18)
|
||||
/** Use global lock to serialize memory hard KDF on activation (OOM workaround) */
|
||||
#define CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF (1 << 19)
|
||||
/** dm-integrity: direct writes, use bitmap to track dirty sectors */
|
||||
#define CRYPT_ACTIVATE_NO_JOURNAL_BITMAP (1 << 20)
|
||||
|
||||
/**
|
||||
* Active device runtime attributes
|
||||
@@ -1103,6 +1114,8 @@ uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd,
|
||||
*/
|
||||
/** Unfinished offline reencryption */
|
||||
#define CRYPT_REQUIREMENT_OFFLINE_REENCRYPT (1 << 0)
|
||||
/** Online reencryption in-progress */
|
||||
#define CRYPT_REQUIREMENT_ONLINE_REENCRYPT (1 << 1)
|
||||
/** unknown requirement in header (output only) */
|
||||
#define CRYPT_REQUIREMENT_UNKNOWN (1 << 31)
|
||||
|
||||
@@ -2098,6 +2111,139 @@ int crypt_activate_by_token(struct crypt_device *cd,
|
||||
uint32_t flags);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup crypt-reencryption LUKS2 volume reencryption support
|
||||
*
|
||||
* Set of functions to handling LUKS2 volume reencryption
|
||||
*
|
||||
* @addtogroup crypt-reencryption
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Initialize reencryption metadata but do not run reencryption yet. */
|
||||
#define CRYPT_REENCRYPT_INITIALIZE_ONLY (1 << 0)
|
||||
/** Move the first segment; used only with data shift. */
|
||||
#define CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT (1 << 1)
|
||||
/** Resume already initialized reencryption only. */
|
||||
#define CRYPT_REENCRYPT_RESUME_ONLY (1 << 2)
|
||||
/** Run reencryption recovery only */
|
||||
#define CRYPT_REENCRYPT_RECOVERY (1 << 3)
|
||||
|
||||
/**
|
||||
* Reencryption direction
|
||||
*/
|
||||
typedef enum {
|
||||
CRYPT_REENCRYPT_FORWARD = 0, /**< forward direction */
|
||||
CRYPT_REENCRYPT_BACKWARD /**< backward direction */
|
||||
} crypt_reencrypt_direction_info;
|
||||
|
||||
/**
|
||||
* LUKS2 reencryption options.
|
||||
*/
|
||||
struct crypt_params_reencrypt {
|
||||
const char *mode; /**< Mode as "encrypt" / "reencrypt" / "decrypt", immutable after first init. */
|
||||
crypt_reencrypt_direction_info direction; /**< Reencryption direction, immutable after first init. */
|
||||
const char *resilience; /**< Resilience mode: "none", "checksum", "journal" or "shift" (only "shift" is immutable after init) */
|
||||
const char *hash; /**< Used hash for "checksum" resilience type, ignored otherwise. */
|
||||
uint64_t data_shift; /**< Used in "shift" mode, must be non-zero, immutable after first init. */
|
||||
uint64_t max_hotzone_size; /**< Hotzone size for "none" mode; maximum hotzone size for "checksum" mode. */
|
||||
uint64_t device_size; /**< Reencrypt only initial part of the data device. */
|
||||
const struct crypt_params_luks2 *luks2; /**< LUKS2 parameters for the final reencryption volume.*/
|
||||
uint32_t flags; /**< Reencryption flags. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize reencryption metadata using passphrase.
|
||||
*
|
||||
* This function initializes on-disk metadata to include all reencryption segments,
|
||||
* according to the provided options.
|
||||
* If metadata already contains ongoing reencryption metadata, it loads these parameters
|
||||
* (in this situation all parameters except @e name and @e passphrase can be omitted).
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param name name of active device or @e NULL for offline reencryption
|
||||
* @param passphrase passphrase used to unlock volume key
|
||||
* @param passphrase_size size of @e passphrase (binary data)
|
||||
* @param keyslot_old keyslot to unlock existing device or CRYPT_ANY_SLOT
|
||||
* @param keyslot_new existing (unbound) reencryption keyslot; must be set except for decryption
|
||||
* @param cipher cipher specification (e.g. "aes")
|
||||
* @param cipher_mode cipher mode and IV (e.g. "xts-plain64")
|
||||
* @param params reencryption parameters @link crypt_params_reencrypt @endlink.
|
||||
*
|
||||
* @return reencryption key slot number or negative errno otherwise.
|
||||
*/
|
||||
int crypt_reencrypt_init_by_passphrase(struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *cipher,
|
||||
const char *cipher_mode,
|
||||
const struct crypt_params_reencrypt *params);
|
||||
|
||||
/**
|
||||
* Initialize reencryption metadata using passphrase in keyring.
|
||||
*
|
||||
* This function initializes on-disk metadata to include all reencryption segments,
|
||||
* according to the provided options.
|
||||
* If metadata already contains ongoing reencryption metadata, it loads these parameters
|
||||
* (in this situation all parameters except @e name and @e key_description can be omitted).
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param name name of active device or @e NULL for offline reencryption
|
||||
* @param key_description passphrase (key) identification in keyring
|
||||
* @param keyslot_old keyslot to unlock existing device or CRYPT_ANY_SLOT
|
||||
* @param keyslot_new existing (unbound) reencryption keyslot; must be set except for decryption
|
||||
* @param cipher cipher specification (e.g. "aes")
|
||||
* @param cipher_mode cipher mode and IV (e.g. "xts-plain64")
|
||||
* @param params reencryption parameters @link crypt_params_reencrypt @endlink.
|
||||
*
|
||||
* @return reencryption key slot number or negative errno otherwise.
|
||||
*/
|
||||
int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *key_description,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *cipher,
|
||||
const char *cipher_mode,
|
||||
const struct crypt_params_reencrypt *params);
|
||||
|
||||
/**
|
||||
* Run data reencryption.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param progress is a callback funtion reporting device \b size,
|
||||
* current \b offset of reencryption and provided \b usrptr identification
|
||||
*
|
||||
* @return @e 0 on success or negative errno value otherwise.
|
||||
*/
|
||||
int crypt_reencrypt(struct crypt_device *cd,
|
||||
int (*progress)(uint64_t size, uint64_t offset, void *usrptr));
|
||||
|
||||
/**
|
||||
* Reencryption status info
|
||||
*/
|
||||
typedef enum {
|
||||
CRYPT_REENCRYPT_NONE = 0, /**< No reencryption in progress */
|
||||
CRYPT_REENCRYPT_CLEAN, /**< Ongoing reencryption in a clean state. */
|
||||
CRYPT_REENCRYPT_CRASH, /**< Aborted reencryption that need internal recovery. */
|
||||
CRYPT_REENCRYPT_INVALID /**< Invalid state. */
|
||||
} crypt_reencrypt_info;
|
||||
|
||||
/**
|
||||
* LUKS2 reencryption status.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param params reecryption parameters
|
||||
*
|
||||
* @return reencryption status info and parameters.
|
||||
*/
|
||||
crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd,
|
||||
struct crypt_params_reencrypt *params);
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -113,6 +113,11 @@ CRYPTSETUP_2.0 {
|
||||
crypt_keyfile_device_read;
|
||||
|
||||
crypt_wipe;
|
||||
|
||||
crypt_reencrypt_init_by_passphrase;
|
||||
crypt_reencrypt_init_by_keyring;
|
||||
crypt_reencrypt;
|
||||
crypt_reencrypt_status;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
#include <linux/fs.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
# include <sys/sysmacros.h> /* for major, minor */
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -43,6 +46,7 @@
|
||||
#define DM_VERITY_TARGET "verity"
|
||||
#define DM_INTEGRITY_TARGET "integrity"
|
||||
#define DM_LINEAR_TARGET "linear"
|
||||
#define DM_ERROR_TARGET "error"
|
||||
#define RETRY_COUNT 5
|
||||
|
||||
/* Set if DM target versions were probed */
|
||||
@@ -211,6 +215,9 @@ static void _dm_set_integrity_compat(struct crypt_device *cd,
|
||||
if (_dm_satisfies_version(1, 2, 0, integrity_maj, integrity_min, integrity_patch))
|
||||
_dm_flags |= DM_INTEGRITY_RECALC_SUPPORTED;
|
||||
|
||||
if (_dm_satisfies_version(1, 3, 0, integrity_maj, integrity_min, integrity_patch))
|
||||
_dm_flags |= DM_INTEGRITY_BITMAP_SUPPORTED;
|
||||
|
||||
_dm_integrity_checked = true;
|
||||
}
|
||||
|
||||
@@ -222,9 +229,10 @@ static int _dm_check_versions(struct crypt_device *cd, dm_target_type target_typ
|
||||
unsigned dm_maj, dm_min, dm_patch;
|
||||
int r = 0;
|
||||
|
||||
if (((target_type == DM_CRYPT || target_type == DM_LINEAR) && _dm_crypt_checked) ||
|
||||
if ((target_type == DM_CRYPT && _dm_crypt_checked) ||
|
||||
(target_type == DM_VERITY && _dm_verity_checked) ||
|
||||
(target_type == DM_INTEGRITY && _dm_integrity_checked) ||
|
||||
(target_type == DM_LINEAR) ||
|
||||
(_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked))
|
||||
return 1;
|
||||
|
||||
@@ -296,9 +304,10 @@ int dm_flags(struct crypt_device *cd, dm_target_type target, uint32_t *flags)
|
||||
_dm_crypt_checked && _dm_verity_checked && _dm_integrity_checked)
|
||||
return 0;
|
||||
|
||||
if (((target == DM_CRYPT || target == DM_LINEAR) && _dm_crypt_checked) ||
|
||||
if ((target == DM_CRYPT && _dm_crypt_checked) ||
|
||||
(target == DM_VERITY && _dm_verity_checked) ||
|
||||
(target == DM_INTEGRITY && _dm_integrity_checked))
|
||||
(target == DM_INTEGRITY && _dm_integrity_checked) ||
|
||||
(target == DM_LINEAR)) /* nothing to check with linear */
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
@@ -703,7 +712,7 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
|
||||
(tgt->u.integrity.journal_crypt_key ? tgt->u.integrity.journal_crypt_key->keylength * 2 : 0) +
|
||||
(tgt->u.integrity.integrity ? strlen(tgt->u.integrity.integrity) : 0) +
|
||||
(tgt->u.integrity.journal_integrity ? strlen(tgt->u.integrity.journal_integrity) : 0) +
|
||||
(tgt->u.integrity.journal_crypt ? strlen(tgt->u.integrity.journal_crypt) : 0) + 128;
|
||||
(tgt->u.integrity.journal_crypt ? strlen(tgt->u.integrity.journal_crypt) : 0) + 128;
|
||||
|
||||
params = crypt_safe_alloc(max_size);
|
||||
if (!params)
|
||||
@@ -718,13 +727,17 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
|
||||
}
|
||||
if (tgt->u.integrity.journal_watermark) {
|
||||
num_options++;
|
||||
snprintf(feature, sizeof(feature), "journal_watermark:%u ",
|
||||
snprintf(feature, sizeof(feature),
|
||||
/* bitmap oveloaded values */
|
||||
(flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "sectors_per_bit:%u " : "journal_watermark:%u ",
|
||||
tgt->u.integrity.journal_watermark);
|
||||
strncat(features, feature, sizeof(features) - strlen(features) - 1);
|
||||
}
|
||||
if (tgt->u.integrity.journal_commit_time) {
|
||||
num_options++;
|
||||
snprintf(feature, sizeof(feature), "commit_time:%u ",
|
||||
snprintf(feature, sizeof(feature),
|
||||
/* bitmap oveloaded values */
|
||||
(flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) ? "bitmap_flush_interval:%u " : "commit_time:%u ",
|
||||
tgt->u.integrity.journal_commit_time);
|
||||
strncat(features, feature, sizeof(features) - strlen(features) - 1);
|
||||
}
|
||||
@@ -818,7 +831,9 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
|
||||
strncat(features, feature, sizeof(features) - strlen(features) - 1);
|
||||
}
|
||||
|
||||
if (flags & CRYPT_ACTIVATE_RECOVERY)
|
||||
if (flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP)
|
||||
mode = 'B';
|
||||
else if (flags & CRYPT_ACTIVATE_RECOVERY)
|
||||
mode = 'R';
|
||||
else if (flags & CRYPT_ACTIVATE_NO_JOURNAL)
|
||||
mode = 'D';
|
||||
@@ -894,7 +909,7 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _dm_simple(int task, const char *name)
|
||||
static int _dm_simple(int task, const char *name, uint32_t dmflags)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
@@ -905,6 +920,14 @@ static int _dm_simple(int task, const char *name)
|
||||
if (name && !dm_task_set_name(dmt, name))
|
||||
goto out;
|
||||
|
||||
if (task == DM_DEVICE_SUSPEND &&
|
||||
(dmflags & DM_SUSPEND_SKIP_LOCKFS) && !dm_task_skip_lockfs(dmt))
|
||||
goto out;
|
||||
|
||||
if (task == DM_DEVICE_SUSPEND &&
|
||||
(dmflags & DM_SUSPEND_NOFLUSH) && !dm_task_no_flush(dmt))
|
||||
goto out;
|
||||
|
||||
r = dm_task_run(dmt);
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
@@ -937,7 +960,7 @@ static int _error_device(const char *name, size_t size)
|
||||
goto error;
|
||||
|
||||
if (_dm_resume_device(name, 0)) {
|
||||
_dm_simple(DM_DEVICE_CLEAR, name);
|
||||
_dm_simple(DM_DEVICE_CLEAR, name, 0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -959,7 +982,7 @@ int dm_error_device(struct crypt_device *cd, const char *name)
|
||||
if (dm_init_context(cd, DM_UNKNOWN))
|
||||
return -ENOTSUP;
|
||||
|
||||
if (dm_query_device(cd, name, 0, &dmd) && _error_device(name, dmd.size))
|
||||
if ((dm_query_device(cd, name, 0, &dmd) >= 0) && _error_device(name, dmd.size))
|
||||
r = 0;
|
||||
else
|
||||
r = -EINVAL;
|
||||
@@ -981,7 +1004,7 @@ int dm_clear_device(struct crypt_device *cd, const char *name)
|
||||
if (dm_init_context(cd, DM_UNKNOWN))
|
||||
return -ENOTSUP;
|
||||
|
||||
if (_dm_simple(DM_DEVICE_CLEAR, name))
|
||||
if (_dm_simple(DM_DEVICE_CLEAR, name, 0))
|
||||
r = 0;
|
||||
else
|
||||
r = -EINVAL;
|
||||
@@ -1259,14 +1282,14 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _dm_resume_device(const char *name, uint32_t flags)
|
||||
static int _dm_resume_device(const char *name, uint32_t dmflags)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
int r = -EINVAL;
|
||||
uint32_t cookie = 0;
|
||||
uint16_t udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK;
|
||||
|
||||
if (flags & CRYPT_ACTIVATE_PRIVATE)
|
||||
if (dmflags & DM_RESUME_PRIVATE)
|
||||
udev_flags |= CRYPT_TEMP_UDEV_FLAGS;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_RESUME)))
|
||||
@@ -1275,6 +1298,12 @@ static int _dm_resume_device(const char *name, uint32_t flags)
|
||||
if (!dm_task_set_name(dmt, name))
|
||||
goto out;
|
||||
|
||||
if ((dmflags & DM_SUSPEND_SKIP_LOCKFS) && !dm_task_skip_lockfs(dmt))
|
||||
goto out;
|
||||
|
||||
if ((dmflags & DM_SUSPEND_NOFLUSH) && !dm_task_no_flush(dmt))
|
||||
goto out;
|
||||
|
||||
if (_dm_use_udev() && !_dm_task_set_cookie(dmt, &cookie, udev_flags))
|
||||
goto out;
|
||||
|
||||
@@ -1378,9 +1407,11 @@ static void _dm_target_free_query_path(struct crypt_device *cd, struct dm_target
|
||||
free(CONST_CAST(void*)tgt->u.verity.root_hash);
|
||||
/* fall through */
|
||||
case DM_LINEAR:
|
||||
/* fall through */
|
||||
case DM_ERROR:
|
||||
break;
|
||||
default:
|
||||
log_err(NULL, "Unknown dm target type.");
|
||||
log_err(cd, _("Unknown dm target type."));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1506,13 +1537,17 @@ int dm_create_device(struct crypt_device *cd, const char *name,
|
||||
if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) &&
|
||||
!(dmt_flags & DM_INTEGRITY_RECALC_SUPPORTED))
|
||||
log_err(cd, _("Requested automatic recalculation of integrity tags is not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) &&
|
||||
!(dmt_flags & DM_INTEGRITY_BITMAP_SUPPORTED))
|
||||
log_err(cd, _("Requested dm-integtity bitmap mode is not supported."));
|
||||
out:
|
||||
dm_exit_context();
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_reload_device(struct crypt_device *cd, const char *name,
|
||||
struct crypt_dm_active_device *dmd, unsigned resume)
|
||||
struct crypt_dm_active_device *dmd, uint32_t dmflags, unsigned resume)
|
||||
{
|
||||
int r;
|
||||
uint32_t dmt_flags;
|
||||
@@ -1538,7 +1573,7 @@ int dm_reload_device(struct crypt_device *cd, const char *name,
|
||||
}
|
||||
|
||||
if (!r && resume)
|
||||
r = _dm_resume_device(name, dmd->flags);
|
||||
r = _dm_resume_device(name, dmflags | act2dmflags(dmd->flags));
|
||||
|
||||
dm_exit_context();
|
||||
return r;
|
||||
@@ -1585,7 +1620,8 @@ static int dm_status_dmi(const char *name, struct dm_info *dmi,
|
||||
if (!target && (strcmp(target_type, DM_CRYPT_TARGET) &&
|
||||
strcmp(target_type, DM_VERITY_TARGET) &&
|
||||
strcmp(target_type, DM_INTEGRITY_TARGET) &&
|
||||
strcmp(target_type, DM_LINEAR_TARGET)))
|
||||
strcmp(target_type, DM_LINEAR_TARGET) &&
|
||||
strcmp(target_type, DM_ERROR_TARGET)))
|
||||
goto out;
|
||||
r = 0;
|
||||
out:
|
||||
@@ -2142,12 +2178,16 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
|
||||
|
||||
/* journal */
|
||||
c = toupper(*(++params));
|
||||
if (!*params || *(++params) != ' ' || (c != 'D' && c != 'J' && c != 'R'))
|
||||
if (!*params || *(++params) != ' ' || (c != 'D' && c != 'J' && c != 'R' && c != 'B'))
|
||||
goto err;
|
||||
if (c == 'D')
|
||||
*act_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
|
||||
if (c == 'R')
|
||||
*act_flags |= CRYPT_ACTIVATE_RECOVERY;
|
||||
if (c == 'B') {
|
||||
*act_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
|
||||
*act_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP;
|
||||
}
|
||||
|
||||
tgt->u.integrity.sector_size = SECTOR_SIZE;
|
||||
|
||||
@@ -2169,7 +2209,15 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
|
||||
tgt->u.integrity.journal_size = val * SECTOR_SIZE;
|
||||
else if (sscanf(arg, "journal_watermark:%u", &val) == 1)
|
||||
tgt->u.integrity.journal_watermark = val;
|
||||
else if (sscanf(arg, "commit_time:%u", &val) == 1)
|
||||
else if (sscanf(arg, "sectors_per_bit:%" PRIu64, &val64) == 1) {
|
||||
if (val64 > UINT_MAX)
|
||||
goto err;
|
||||
/* overrloaded value for bitmap mode */
|
||||
tgt->u.integrity.journal_watermark = (unsigned int)val64;
|
||||
} else if (sscanf(arg, "commit_time:%u", &val) == 1)
|
||||
tgt->u.integrity.journal_commit_time = val;
|
||||
else if (sscanf(arg, "bitmap_flush_interval:%u", &val) == 1)
|
||||
/* overrloaded value for bitmap mode */
|
||||
tgt->u.integrity.journal_commit_time = val;
|
||||
else if (sscanf(arg, "interleave_sectors:%u", &val) == 1)
|
||||
tgt->u.integrity.interleave_sectors = val;
|
||||
@@ -2313,6 +2361,14 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _dm_target_query_error(struct crypt_device *cd, struct dm_target *tgt)
|
||||
{
|
||||
tgt->type = DM_ERROR;
|
||||
tgt->direction = TARGET_QUERY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* on error retval has to be negative
|
||||
*
|
||||
@@ -2322,7 +2378,7 @@ static int dm_target_query(struct crypt_device *cd, struct dm_target *tgt, const
|
||||
const uint64_t *length, const char *target_type,
|
||||
char *params, uint32_t get_flags, uint32_t *act_flags)
|
||||
{
|
||||
int r = -EINVAL;
|
||||
int r = -ENOTSUP;
|
||||
|
||||
if (!strcmp(target_type, DM_CRYPT_TARGET))
|
||||
r = _dm_target_query_crypt(cd, get_flags, params, tgt, act_flags);
|
||||
@@ -2332,6 +2388,8 @@ static int dm_target_query(struct crypt_device *cd, struct dm_target *tgt, const
|
||||
r = _dm_target_query_integrity(cd, get_flags, params, tgt, act_flags);
|
||||
else if (!strcmp(target_type, DM_LINEAR_TARGET))
|
||||
r = _dm_target_query_linear(cd, tgt, get_flags, params);
|
||||
else if (!strcmp(target_type, DM_ERROR_TARGET))
|
||||
r = _dm_target_query_error(cd, tgt);
|
||||
|
||||
if (!r) {
|
||||
tgt->offset = *start;
|
||||
@@ -2341,7 +2399,7 @@ static int dm_target_query(struct crypt_device *cd, struct dm_target *tgt, const
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_query_device(struct crypt_device *cd, const char *name,
|
||||
static int _dm_query_device(struct crypt_device *cd, const char *name,
|
||||
uint32_t get_flags, struct crypt_dm_active_device *dmd)
|
||||
{
|
||||
struct dm_target *t;
|
||||
@@ -2353,17 +2411,10 @@ int dm_query_device(struct crypt_device *cd, const char *name,
|
||||
void *next = NULL;
|
||||
int r = -EINVAL;
|
||||
|
||||
if (dm_init_context(cd, DM_UNKNOWN))
|
||||
return -ENOTSUP;
|
||||
if (!dmd)
|
||||
return -EINVAL;
|
||||
|
||||
t = &dmd->segment;
|
||||
|
||||
memset(dmd, 0, sizeof(*dmd));
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
|
||||
goto out;
|
||||
return r;
|
||||
if (!dm_task_secure_data(dmt))
|
||||
goto out;
|
||||
if (!dm_task_set_name(dmt, name))
|
||||
@@ -2409,7 +2460,8 @@ int dm_query_device(struct crypt_device *cd, const char *name,
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Failed to query dm-%s segment."), target_type);
|
||||
if (r != -ENOTSUP)
|
||||
log_err(cd, _("Failed to query dm-%s segment."), target_type);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2443,6 +2495,136 @@ out:
|
||||
if (r < 0)
|
||||
dm_targets_free(cd, dmd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_query_device(struct crypt_device *cd, const char *name,
|
||||
uint32_t get_flags, struct crypt_dm_active_device *dmd)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!dmd)
|
||||
return -EINVAL;
|
||||
|
||||
memset(dmd, 0, sizeof(*dmd));
|
||||
|
||||
if (dm_init_context(cd, DM_UNKNOWN))
|
||||
return -ENOTSUP;
|
||||
|
||||
r = _dm_query_device(cd, name, get_flags, dmd);
|
||||
|
||||
dm_exit_context();
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool name_in_list(char **names, const char *name)
|
||||
{
|
||||
while (*names) {
|
||||
if (!strcmp(*names++, name))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int _process_deps(struct crypt_device *cd, const char *prefix, struct dm_deps *deps, char **names, size_t names_offset, size_t names_length)
|
||||
{
|
||||
struct crypt_dm_active_device dmd;
|
||||
char dmname[PATH_MAX];
|
||||
unsigned i;
|
||||
int r, major, minor, count = 0;
|
||||
|
||||
if (!prefix || !deps)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < deps->count; i++) {
|
||||
major = major(deps->device[i]);
|
||||
if (!dm_is_dm_major(major))
|
||||
continue;
|
||||
|
||||
minor = minor(deps->device[i]);
|
||||
if (!dm_device_get_name(major, minor, 0, dmname, PATH_MAX))
|
||||
return -EINVAL;
|
||||
|
||||
memset(&dmd, 0, sizeof(dmd));
|
||||
r = _dm_query_device(cd, dmname, DM_ACTIVE_UUID, &dmd);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
if (!dmd.uuid ||
|
||||
strncmp(prefix, dmd.uuid, strlen(prefix)) ||
|
||||
name_in_list(names, dmname))
|
||||
*dmname = '\0';
|
||||
|
||||
dm_targets_free(cd, &dmd);
|
||||
free(CONST_CAST(void*)dmd.uuid);
|
||||
|
||||
if ((size_t)count >= (names_length - names_offset))
|
||||
return -ENOMEM;
|
||||
|
||||
if (*dmname && !(names[names_offset + count++] = strdup(dmname)))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int dm_device_deps(struct crypt_device *cd, const char *name, const char *prefix, char **names, size_t names_length)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
struct dm_info dmi;
|
||||
struct dm_deps *deps;
|
||||
int r = -EINVAL;
|
||||
size_t i, last = 0, offset = 0;
|
||||
|
||||
if (!name || !names_length || !names)
|
||||
return -EINVAL;
|
||||
|
||||
if (dm_init_context(cd, DM_UNKNOWN))
|
||||
return -ENOTSUP;
|
||||
|
||||
while (name) {
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
|
||||
goto out;
|
||||
if (!dm_task_set_name(dmt, name))
|
||||
goto out;
|
||||
|
||||
r = -ENODEV;
|
||||
if (!dm_task_run(dmt))
|
||||
goto out;
|
||||
|
||||
r = -EINVAL;
|
||||
if (!dm_task_get_info(dmt, &dmi))
|
||||
goto out;
|
||||
if (!(deps = dm_task_get_deps(dmt)))
|
||||
goto out;
|
||||
|
||||
r = -ENODEV;
|
||||
if (!dmi.exists)
|
||||
goto out;
|
||||
|
||||
r = _process_deps(cd, prefix, deps, names, offset, names_length - 1);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
dmt = NULL;
|
||||
|
||||
offset += r;
|
||||
name = names[last++];
|
||||
}
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
if (r < 0) {
|
||||
for (i = 0; i < names_length - 1; i++)
|
||||
free(names[i]);
|
||||
*names = NULL;
|
||||
}
|
||||
|
||||
if (dmt)
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
dm_exit_context();
|
||||
return r;
|
||||
}
|
||||
@@ -2473,61 +2655,48 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_suspend_device(struct crypt_device *cd, const char *name)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (dm_init_context(cd, DM_UNKNOWN))
|
||||
return -ENOTSUP;
|
||||
|
||||
if (!_dm_simple(DM_DEVICE_SUSPEND, name))
|
||||
r = -EINVAL;
|
||||
else
|
||||
r = 0;
|
||||
|
||||
dm_exit_context();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name)
|
||||
int dm_suspend_device(struct crypt_device *cd, const char *name, uint32_t dmflags)
|
||||
{
|
||||
uint32_t dmt_flags;
|
||||
int r = -ENOTSUP;
|
||||
|
||||
if (dm_init_context(cd, DM_CRYPT))
|
||||
return -ENOTSUP;
|
||||
if (dm_init_context(cd, DM_UNKNOWN))
|
||||
return r;
|
||||
|
||||
if (dm_flags(cd, DM_CRYPT, &dmt_flags))
|
||||
goto out;
|
||||
if (dmflags & DM_SUSPEND_WIPE_KEY) {
|
||||
if (dm_flags(cd, DM_CRYPT, &dmt_flags))
|
||||
goto out;
|
||||
|
||||
if (!(dmt_flags & DM_KEY_WIPE_SUPPORTED))
|
||||
goto out;
|
||||
|
||||
if (!_dm_simple(DM_DEVICE_SUSPEND, name)) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
if (!(dmt_flags & DM_KEY_WIPE_SUPPORTED))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!_dm_message(name, "key wipe")) {
|
||||
_dm_resume_device(name, 0);
|
||||
r = -EINVAL;
|
||||
r = -EINVAL;
|
||||
|
||||
if (!_dm_simple(DM_DEVICE_SUSPEND, name, dmflags))
|
||||
goto out;
|
||||
|
||||
if (dmflags & DM_SUSPEND_WIPE_KEY) {
|
||||
if (!_dm_message(name, "key wipe")) {
|
||||
_dm_resume_device(name, 0);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
dm_exit_context();
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_resume_device(struct crypt_device *cd, const char *name, uint32_t flags)
|
||||
int dm_resume_device(struct crypt_device *cd, const char *name, uint32_t dmflags)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (dm_init_context(cd, DM_UNKNOWN))
|
||||
return -ENOTSUP;
|
||||
|
||||
r = _dm_resume_device(name, flags);
|
||||
r = _dm_resume_device(name, dmflags);
|
||||
|
||||
dm_exit_context();
|
||||
|
||||
@@ -2582,7 +2751,7 @@ const char *dm_get_dir(void)
|
||||
return dm_dir();
|
||||
}
|
||||
|
||||
int dm_is_dm_device(int major, int minor)
|
||||
int dm_is_dm_device(int major)
|
||||
{
|
||||
return dm_is_dm_major((uint32_t)major);
|
||||
}
|
||||
@@ -2614,6 +2783,7 @@ int dm_crypt_target_set(struct dm_target *tgt, size_t seg_offset, size_t seg_siz
|
||||
tgt->data_device = data_device;
|
||||
|
||||
tgt->type = DM_CRYPT;
|
||||
tgt->direction = TARGET_SET;
|
||||
tgt->u.crypt.vk = vk;
|
||||
tgt->offset = seg_offset;
|
||||
tgt->size = seg_size;
|
||||
|
||||
@@ -60,7 +60,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
struct crypt_dm_active_device dmd = {
|
||||
.flags = CRYPT_ACTIVATE_PRIVATE,
|
||||
};
|
||||
int r, devfd = -1;
|
||||
int r, devfd = -1, remove_dev = 0;
|
||||
size_t bsize, keyslot_alignment, alignment;
|
||||
|
||||
log_dbg(ctx, "Using dmcrypt to access keyslot area.");
|
||||
@@ -114,6 +114,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
remove_dev = 1;
|
||||
|
||||
devfd = open(path, mode | O_DIRECT | O_SYNC);
|
||||
if (devfd == -1) {
|
||||
@@ -132,7 +133,8 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
dm_targets_free(ctx, &dmd);
|
||||
if (devfd != -1)
|
||||
close(devfd);
|
||||
dm_remove_device(ctx, name, CRYPT_DEACTIVATE_FORCE);
|
||||
if (remove_dev)
|
||||
dm_remove_device(ctx, name, CRYPT_DEACTIVATE_FORCE);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -143,17 +145,16 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
|
||||
unsigned int sector,
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
|
||||
struct device *device = crypt_metadata_device(ctx);
|
||||
struct crypt_storage *s;
|
||||
int devfd = -1, r = 0;
|
||||
int devfd, r = 0;
|
||||
|
||||
/* Only whole sector writes supported */
|
||||
if (MISALIGNED_512(srcLength))
|
||||
return -EINVAL;
|
||||
|
||||
/* Encrypt buffer */
|
||||
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
|
||||
if (r)
|
||||
log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
|
||||
@@ -172,7 +173,7 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
|
||||
|
||||
log_dbg(ctx, "Using userspace crypto wrapper to access keyslot area.");
|
||||
|
||||
r = crypt_storage_encrypt(s, 0, srcLength / SECTOR_SIZE, src);
|
||||
r = crypt_storage_encrypt(s, 0, srcLength, src);
|
||||
crypt_storage_destroy(s);
|
||||
|
||||
if (r)
|
||||
@@ -181,7 +182,10 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
|
||||
r = -EIO;
|
||||
|
||||
/* Write buffer to device */
|
||||
devfd = device_open(ctx, device, O_RDWR);
|
||||
if (device_is_locked(device))
|
||||
devfd = device_open_locked(ctx, device, O_RDWR);
|
||||
else
|
||||
devfd = device_open(ctx, device, O_RDWR);
|
||||
if (devfd < 0)
|
||||
goto out;
|
||||
|
||||
@@ -192,10 +196,7 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
if (devfd >= 0) {
|
||||
device_sync(ctx, device, devfd);
|
||||
close(devfd);
|
||||
}
|
||||
device_sync(ctx, device);
|
||||
if (r)
|
||||
log_err(ctx, _("IO error while encrypting keyslot."));
|
||||
|
||||
@@ -212,13 +213,13 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
struct device *device = crypt_metadata_device(ctx);
|
||||
struct crypt_storage *s;
|
||||
struct stat st;
|
||||
int devfd = -1, r = 0;
|
||||
int devfd, r = 0;
|
||||
|
||||
/* Only whole sector reads supported */
|
||||
if (MISALIGNED_512(dstLength))
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
|
||||
if (r)
|
||||
log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
|
||||
@@ -238,7 +239,10 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
log_dbg(ctx, "Using userspace crypto wrapper to access keyslot area.");
|
||||
|
||||
/* Read buffer from device */
|
||||
devfd = device_open(ctx, device, O_RDONLY);
|
||||
if (device_is_locked(device))
|
||||
devfd = device_open_locked(ctx, device, O_RDONLY);
|
||||
else
|
||||
devfd = device_open(ctx, device, O_RDONLY);
|
||||
if (devfd < 0) {
|
||||
log_err(ctx, _("Cannot open device %s."), device_path(device));
|
||||
crypt_storage_destroy(s);
|
||||
@@ -253,15 +257,12 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
else
|
||||
log_err(ctx, _("IO error while decrypting keyslot."));
|
||||
|
||||
close(devfd);
|
||||
crypt_storage_destroy(s);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
close(devfd);
|
||||
|
||||
/* Decrypt buffer */
|
||||
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
|
||||
r = crypt_storage_decrypt(s, 0, dstLength, dst);
|
||||
crypt_storage_destroy(s);
|
||||
|
||||
return r;
|
||||
|
||||
@@ -200,9 +200,10 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
|
||||
{
|
||||
struct device *device = crypt_metadata_device(ctx);
|
||||
struct luks_phdr hdr;
|
||||
int r = 0, devfd = -1;
|
||||
int fd, devfd, r = 0;
|
||||
size_t hdr_size;
|
||||
size_t buffer_size;
|
||||
ssize_t ret;
|
||||
char *buffer = NULL;
|
||||
|
||||
r = LUKS_read_phdr(&hdr, 1, 0, ctx);
|
||||
@@ -230,19 +231,18 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (read_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
|
||||
buffer, hdr_size) < (ssize_t)hdr_size) {
|
||||
if (read_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
|
||||
buffer, hdr_size, 0) < (ssize_t)hdr_size) {
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
close(devfd);
|
||||
|
||||
/* Wipe unused area, so backup cannot contain old signatures */
|
||||
if (hdr.keyblock[0].keyMaterialOffset * SECTOR_SIZE == LUKS_ALIGN_KEYSLOTS)
|
||||
memset(buffer + sizeof(hdr), 0, LUKS_ALIGN_KEYSLOTS - sizeof(hdr));
|
||||
|
||||
devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
|
||||
if (devfd == -1) {
|
||||
fd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
|
||||
if (fd == -1) {
|
||||
if (errno == EEXIST)
|
||||
log_err(ctx, _("Requested header backup file %s already exists."), backup_file);
|
||||
else
|
||||
@@ -250,7 +250,9 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (write_buffer(devfd, buffer, buffer_size) < (ssize_t)buffer_size) {
|
||||
ret = write_buffer(fd, buffer, buffer_size);
|
||||
close(fd);
|
||||
if (ret < (ssize_t)buffer_size) {
|
||||
log_err(ctx, _("Cannot write header backup file %s."), backup_file);
|
||||
r = -EIO;
|
||||
goto out;
|
||||
@@ -258,8 +260,6 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
if (devfd >= 0)
|
||||
close(devfd);
|
||||
crypt_memzero(&hdr, sizeof(hdr));
|
||||
crypt_safe_free(buffer);
|
||||
return r;
|
||||
@@ -271,8 +271,8 @@ int LUKS_hdr_restore(
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
struct device *device = crypt_metadata_device(ctx);
|
||||
int r = 0, devfd = -1, diff_uuid = 0;
|
||||
ssize_t buffer_size = 0;
|
||||
int fd, r = 0, devfd = -1, diff_uuid = 0;
|
||||
ssize_t ret, buffer_size = 0;
|
||||
char *buffer = NULL, msg[200];
|
||||
struct luks_phdr hdr_file;
|
||||
|
||||
@@ -295,20 +295,20 @@ int LUKS_hdr_restore(
|
||||
goto out;
|
||||
}
|
||||
|
||||
devfd = open(backup_file, O_RDONLY);
|
||||
if (devfd == -1) {
|
||||
fd = open(backup_file, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
log_err(ctx, _("Cannot open header backup file %s."), backup_file);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (read_buffer(devfd, buffer, buffer_size) < buffer_size) {
|
||||
ret = read_buffer(fd, buffer, buffer_size);
|
||||
close(fd);
|
||||
if (ret < buffer_size) {
|
||||
log_err(ctx, _("Cannot read header backup file %s."), backup_file);
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
close(devfd);
|
||||
devfd = -1;
|
||||
|
||||
r = LUKS_read_phdr(hdr, 0, 0, ctx);
|
||||
if (r == 0) {
|
||||
@@ -350,21 +350,16 @@ int LUKS_hdr_restore(
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (write_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
|
||||
buffer, buffer_size) < buffer_size) {
|
||||
if (write_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
|
||||
buffer, buffer_size, 0) < buffer_size) {
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
close(devfd);
|
||||
devfd = -1;
|
||||
|
||||
/* Be sure to reload new data */
|
||||
r = LUKS_read_phdr(hdr, 1, 0, ctx);
|
||||
out:
|
||||
if (devfd >= 0) {
|
||||
device_sync(ctx, device, devfd);
|
||||
close(devfd);
|
||||
}
|
||||
device_sync(ctx, device);
|
||||
crypt_safe_free(buffer);
|
||||
return r;
|
||||
}
|
||||
@@ -573,9 +568,9 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
|
||||
int repair,
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
int devfd, r = 0;
|
||||
struct device *device = crypt_metadata_device(ctx);
|
||||
ssize_t hdr_size = sizeof(struct luks_phdr);
|
||||
int devfd = 0, r = 0;
|
||||
|
||||
/* LUKS header starts at offset 0, first keyslot on LUKS_ALIGN_KEYSLOTS */
|
||||
assert(sizeof(struct luks_phdr) <= LUKS_ALIGN_KEYSLOTS);
|
||||
@@ -595,8 +590,8 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (read_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
|
||||
hdr, hdr_size) < hdr_size)
|
||||
if (read_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
|
||||
hdr, hdr_size, 0) < hdr_size)
|
||||
r = -EIO;
|
||||
else
|
||||
r = _check_and_convert_hdr(device_path(device), hdr, require_luks_device,
|
||||
@@ -615,7 +610,6 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
|
||||
device_disable_direct_io(device);
|
||||
}
|
||||
|
||||
close(devfd);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -661,13 +655,12 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
|
||||
convHdr.keyblock[i].stripes = htonl(hdr->keyblock[i].stripes);
|
||||
}
|
||||
|
||||
r = write_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
|
||||
&convHdr, hdr_size) < hdr_size ? -EIO : 0;
|
||||
r = write_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
|
||||
&convHdr, hdr_size, 0) < hdr_size ? -EIO : 0;
|
||||
if (r)
|
||||
log_err(ctx, _("Error during update of LUKS header on device %s."), device_path(device));
|
||||
|
||||
device_sync(ctx, device, devfd);
|
||||
close(devfd);
|
||||
device_sync(ctx, device);
|
||||
|
||||
/* Re-read header from disk to be sure that in-memory and on-disk data are the same. */
|
||||
if (!r) {
|
||||
@@ -1024,7 +1017,7 @@ int LUKS_open_key_with_hdr(int keyIndex,
|
||||
struct volume_key **vk,
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i, tried = 0;
|
||||
int r;
|
||||
|
||||
*vk = crypt_alloc_volume_key(hdr->keyBytes, NULL);
|
||||
@@ -1034,7 +1027,7 @@ int LUKS_open_key_with_hdr(int keyIndex,
|
||||
return (r < 0) ? r : keyIndex;
|
||||
}
|
||||
|
||||
for(i = 0; i < LUKS_NUMKEYS; i++) {
|
||||
for (i = 0; i < LUKS_NUMKEYS; i++) {
|
||||
r = LUKS_open_key(i, password, passwordLen, hdr, *vk, ctx);
|
||||
if(r == 0)
|
||||
return i;
|
||||
@@ -1043,9 +1036,11 @@ int LUKS_open_key_with_hdr(int keyIndex,
|
||||
former meaning password wrong, latter key slot inactive */
|
||||
if ((r != -EPERM) && (r != -ENOENT))
|
||||
return r;
|
||||
if (r == -EPERM)
|
||||
tried++;
|
||||
}
|
||||
/* Warning, early returns above */
|
||||
return -EPERM;
|
||||
return tried ? -EPERM : -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS_del_key(unsigned int keyIndex,
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#ifndef _CRYPTSETUP_LUKS2_ONDISK_H
|
||||
#define _CRYPTSETUP_LUKS2_ONDISK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "libcryptsetup.h"
|
||||
|
||||
#define LUKS2_MAGIC_1ST "LUKS\xba\xbe"
|
||||
@@ -45,11 +47,16 @@
|
||||
#define LUKS2_DIGEST_MAX 8
|
||||
|
||||
#define CRYPT_ANY_SEGMENT -1
|
||||
#define CRYPT_DEFAULT_SEGMENT 0
|
||||
#define CRYPT_DEFAULT_SEGMENT_STR "0"
|
||||
#define CRYPT_DEFAULT_SEGMENT -2
|
||||
#define CRYPT_ONE_SEGMENT -3
|
||||
|
||||
#define CRYPT_ANY_DIGEST -1
|
||||
|
||||
/* 20 MiBs */
|
||||
#define LUKS2_DEFAULT_NONE_REENCRYPTION_LENGTH 0x1400000
|
||||
|
||||
struct device;
|
||||
|
||||
/*
|
||||
* LUKS2 header on-disk.
|
||||
*
|
||||
@@ -117,6 +124,77 @@ struct luks2_keyslot_params {
|
||||
} area;
|
||||
};
|
||||
|
||||
struct reenc_protection {
|
||||
enum { REENC_PROTECTION_NONE = 0, /* none should be 0 always */
|
||||
REENC_PROTECTION_CHECKSUM,
|
||||
REENC_PROTECTION_JOURNAL,
|
||||
REENC_PROTECTION_DATASHIFT } type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
} none;
|
||||
struct {
|
||||
char hash[LUKS2_CHECKSUM_ALG_L]; // or include luks.h
|
||||
struct crypt_hash *ch;
|
||||
size_t hash_size;
|
||||
/* buffer for checksums */
|
||||
void *checksums;
|
||||
size_t checksums_len;
|
||||
} csum;
|
||||
struct {
|
||||
} ds;
|
||||
} p;
|
||||
};
|
||||
|
||||
struct luks2_reenc_context {
|
||||
/* reencryption window attributes */
|
||||
uint64_t offset;
|
||||
uint64_t progress;
|
||||
uint64_t length;
|
||||
uint64_t data_shift;
|
||||
size_t alignment;
|
||||
uint64_t device_size;
|
||||
bool online;
|
||||
bool fixed_length;
|
||||
crypt_reencrypt_direction_info direction;
|
||||
|
||||
enum { REENCRYPT = 0, ENCRYPT, DECRYPT } type;
|
||||
|
||||
char *device_name;
|
||||
char *hotzone_name;
|
||||
char *overlay_name;
|
||||
|
||||
/* reencryption window persistence attributes */
|
||||
struct reenc_protection rp;
|
||||
|
||||
int reenc_keyslot;
|
||||
|
||||
/* already running reencryption */
|
||||
json_object *jobj_segs_pre;
|
||||
json_object *jobj_segs_after;
|
||||
|
||||
/* backup segments */
|
||||
json_object *jobj_segment_new;
|
||||
int digest_new;
|
||||
json_object *jobj_segment_old;
|
||||
int digest_old;
|
||||
json_object *jobj_segment_moved;
|
||||
|
||||
struct volume_key *vks;
|
||||
|
||||
void *reenc_buffer;
|
||||
ssize_t read;
|
||||
|
||||
struct crypt_storage_wrapper *cw1;
|
||||
struct crypt_storage_wrapper *cw2;
|
||||
|
||||
uint32_t wflags1;
|
||||
uint32_t wflags2;
|
||||
|
||||
struct crypt_lock_handle *reenc_lock;
|
||||
};
|
||||
|
||||
crypt_reencrypt_info LUKS2_reenc_status(struct luks2_hdr *hdr);
|
||||
/*
|
||||
* Supportable header sizes (hdr_disk + JSON area)
|
||||
* Also used as offset for the 2nd header.
|
||||
@@ -139,8 +217,12 @@ struct luks2_keyslot_params {
|
||||
int LUKS2_hdr_version_unlocked(struct crypt_device *cd,
|
||||
const char *backup_file);
|
||||
|
||||
int LUKS2_device_write_lock(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct device *device);
|
||||
|
||||
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair);
|
||||
int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
int LUKS2_hdr_write_force(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_hdr_uuid(struct crypt_device *cd,
|
||||
@@ -178,6 +260,13 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
size_t password_len,
|
||||
struct volume_key **vk);
|
||||
|
||||
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vks);
|
||||
|
||||
int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -186,6 +275,20 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
const struct volume_key *vk,
|
||||
const struct luks2_keyslot_params *params);
|
||||
|
||||
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const void *buffer,
|
||||
size_t buffer_length);
|
||||
|
||||
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params);
|
||||
|
||||
int reenc_keyslot_update(struct crypt_device *cd,
|
||||
const struct luks2_reenc_context *rh);
|
||||
|
||||
int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -262,11 +365,86 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
|
||||
|
||||
int LUKS2_tokens_count(struct luks2_hdr *hdr);
|
||||
|
||||
/*
|
||||
* Generic LUKS2 segment
|
||||
*/
|
||||
json_object *json_get_segments_jobj(json_object *hdr_jobj);
|
||||
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise);
|
||||
const char *json_segment_type(json_object *jobj_segment);
|
||||
uint64_t json_segment_get_iv_offset(json_object *jobj_segment);
|
||||
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise);
|
||||
const char *json_segment_get_cipher(json_object *jobj_segment);
|
||||
int json_segment_get_sector_size(json_object *jobj_segment);
|
||||
json_object *json_segment_get_flags(json_object *jobj_segment);
|
||||
bool json_segment_is_backup(json_object *jobj_segment);
|
||||
bool json_segment_is_reencrypt(json_object *jobj_segment);
|
||||
json_object *json_segments_get_segment(json_object *jobj_segments, int segment);
|
||||
int json_segments_count(json_object *jobj_segments);
|
||||
json_object *json_segments_get_segment_by_flag(json_object *jobj_segments, const char *flag);
|
||||
void json_segment_remove_flag(json_object *jobj_segment, const char *flag);
|
||||
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise);
|
||||
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
|
||||
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length, const char *cipher, uint32_t sector_size, unsigned reencryption);
|
||||
int json_segments_segment_in_reencrypt(json_object *jobj_segments);
|
||||
|
||||
int LUKS2_segments_count(struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag);
|
||||
|
||||
json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag);
|
||||
|
||||
int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag);
|
||||
|
||||
json_object *LUKS2_get_ignored_segments(struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_segments_set(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
json_object *jobj_segments,
|
||||
int commit);
|
||||
|
||||
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
unsigned blockwise);
|
||||
|
||||
uint64_t LUKS2_segment_size(struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
unsigned blockwise);
|
||||
|
||||
int LUKS2_segment_is_type(struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
const char *type);
|
||||
|
||||
int LUKS2_segment_by_type(struct luks2_hdr *hdr,
|
||||
const char *type);
|
||||
|
||||
int LUKS2_last_segment_by_type(struct luks2_hdr *hdr,
|
||||
const char *type);
|
||||
|
||||
int LUKS2_get_default_segment(struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_reencrypt_digest_new(struct luks2_hdr *hdr);
|
||||
int LUKS2_reencrypt_digest_old(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_reencrypt_protection_type(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_reencrypt_protection_hash(struct luks2_hdr *hdr);
|
||||
uint64_t LUKS2_reencrypt_data_shift(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_reencrypt_mode(struct luks2_hdr *hdr);
|
||||
|
||||
/*
|
||||
* Generic LUKS2 digest
|
||||
*/
|
||||
int LUKS2_digest_any_matching(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
const struct volume_key *vk);
|
||||
|
||||
int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment);
|
||||
|
||||
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int digest,
|
||||
const struct volume_key *vk);
|
||||
|
||||
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
@@ -277,7 +455,7 @@ void LUKS2_digests_erase_unused(struct crypt_device *cd,
|
||||
|
||||
int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vk,
|
||||
const struct volume_key *vk,
|
||||
int keyslot);
|
||||
|
||||
int LUKS2_digest_dump(struct crypt_device *cd,
|
||||
@@ -312,6 +490,25 @@ int LUKS2_activate(struct crypt_device *cd,
|
||||
struct volume_key *vk,
|
||||
uint32_t flags);
|
||||
|
||||
int LUKS2_activate_multi(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vks,
|
||||
uint32_t flags);
|
||||
|
||||
struct crypt_dm_active_device;
|
||||
|
||||
int LUKS2_deactivate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct luks2_hdr *hdr,
|
||||
struct crypt_dm_active_device *dmd,
|
||||
uint32_t flags);
|
||||
|
||||
int LUKS2_reload(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vks,
|
||||
uint64_t device_size,
|
||||
uint32_t flags);
|
||||
|
||||
int LUKS2_keyslot_luks2_format(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -340,6 +537,7 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr);
|
||||
|
||||
uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr);
|
||||
int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size, bool *dynamic);
|
||||
int LUKS2_get_sector_size(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment);
|
||||
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment);
|
||||
@@ -348,15 +546,20 @@ int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment);
|
||||
int LUKS2_get_keyslot_stored_key_size(struct luks2_hdr *hdr, int keyslot);
|
||||
const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size);
|
||||
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type);
|
||||
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr);
|
||||
int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment);
|
||||
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment);
|
||||
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type);
|
||||
int LUKS2_find_keyslot_for_segment(struct luks2_hdr *hdr, int segment, const char *type);
|
||||
crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot);
|
||||
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
uint64_t *offset,
|
||||
uint64_t *length);
|
||||
int LUKS2_keyslot_pbkdf(struct luks2_hdr *hdr, int keyslot, struct crypt_pbkdf_type *pbkdf);
|
||||
int LUKS2_set_keyslots_size(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
uint64_t data_offset);
|
||||
|
||||
/*
|
||||
* Permanent activation flags stored in header
|
||||
@@ -368,14 +571,17 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
|
||||
* Requirements for device activation or header modification
|
||||
*/
|
||||
int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs);
|
||||
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs);
|
||||
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit);
|
||||
|
||||
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
|
||||
|
||||
char *LUKS2_key_description_by_digest(struct crypt_device *cd, int digest);
|
||||
int LUKS2_key_description_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int segment);
|
||||
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot);
|
||||
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int digest);
|
||||
|
||||
struct luks_phdr;
|
||||
int LUKS2_luks1_to_luks2(struct crypt_device *cd,
|
||||
@@ -385,4 +591,32 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr2,
|
||||
struct luks_phdr *hdr1);
|
||||
|
||||
/*
|
||||
* LUKS2 reencryption
|
||||
*/
|
||||
int LUKS2_verify_and_upload_keys(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int digest_old,
|
||||
int digest_new,
|
||||
struct volume_key *vks);
|
||||
|
||||
int LUKS2_reenc_update_segments(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct luks2_reenc_context *rh);
|
||||
|
||||
int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
uint32_t flags,
|
||||
struct volume_key **vks);
|
||||
|
||||
void LUKS2_reenc_context_free(struct crypt_device *cd, struct luks2_reenc_context *rh);
|
||||
|
||||
int crypt_reencrypt_lock(struct crypt_device *cd, const char *uuid, struct crypt_lock_handle **reencrypt_lock);
|
||||
void crypt_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *reencrypt_lock);
|
||||
|
||||
int luks2_check_device_size(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t check_size, uint64_t *device_size, bool activation);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -110,19 +110,14 @@ int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vk,
|
||||
int keyslot)
|
||||
int digest,
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
const digest_handler *h;
|
||||
int digest, r;
|
||||
int r;
|
||||
|
||||
digest = LUKS2_digest_by_keyslot(hdr, keyslot);
|
||||
if (digest < 0)
|
||||
return digest;
|
||||
|
||||
log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest);
|
||||
h = LUKS2_digest_handler(cd, digest);
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
@@ -136,6 +131,22 @@ int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
return digest;
|
||||
}
|
||||
|
||||
int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
const struct volume_key *vk,
|
||||
int keyslot)
|
||||
{
|
||||
int digest;
|
||||
|
||||
digest = LUKS2_digest_by_keyslot(hdr, keyslot);
|
||||
if (digest < 0)
|
||||
return digest;
|
||||
|
||||
log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest);
|
||||
|
||||
return LUKS2_digest_verify_by_digest(cd, hdr, digest, vk);
|
||||
}
|
||||
|
||||
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
|
||||
{
|
||||
const digest_handler *h;
|
||||
@@ -146,31 +157,25 @@ int LUKS2_digest_dump(struct crypt_device *cd, int digest)
|
||||
return h->dump(cd, digest);
|
||||
}
|
||||
|
||||
int LUKS2_digest_any_matching(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
int digest;
|
||||
|
||||
for (digest = 0; digest < LUKS2_DIGEST_MAX; digest++)
|
||||
if (LUKS2_digest_verify_by_digest(cd, hdr, digest, vk) == digest)
|
||||
return digest;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
const digest_handler *h;
|
||||
int digest, r;
|
||||
|
||||
digest = LUKS2_digest_by_segment(hdr, segment);
|
||||
if (digest < 0)
|
||||
return digest;
|
||||
|
||||
log_dbg(cd, "Verifying key digest %d.", digest);
|
||||
|
||||
h = LUKS2_digest_handler(cd, digest);
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
r = h->verify(cd, digest, vk->key, vk->keylength);
|
||||
if (r < 0) {
|
||||
log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
return digest;
|
||||
return LUKS2_digest_verify_by_digest(cd, hdr, LUKS2_digest_by_segment(hdr, segment), vk);
|
||||
}
|
||||
|
||||
/* FIXME: segment can have more digests */
|
||||
@@ -179,6 +184,9 @@ int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment)
|
||||
char segment_name[16];
|
||||
json_object *jobj_digests, *jobj_digest_segments;
|
||||
|
||||
if (segment == CRYPT_DEFAULT_SEGMENT)
|
||||
segment = LUKS2_get_default_segment(hdr);
|
||||
|
||||
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
|
||||
|
||||
if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)
|
||||
@@ -250,6 +258,36 @@ int LUKS2_digest_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
|
||||
}
|
||||
|
||||
static int assign_all_segments(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int digest, int assign)
|
||||
{
|
||||
json_object *jobj1, *jobj_digest, *jobj_digest_segments;
|
||||
|
||||
jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
|
||||
if (!jobj_digest)
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_get_ex(jobj_digest, "segments", &jobj_digest_segments);
|
||||
if (!jobj_digest_segments)
|
||||
return -EINVAL;
|
||||
|
||||
if (assign) {
|
||||
json_object_object_foreach(LUKS2_get_segments_jobj(hdr), key, value) {
|
||||
UNUSED(value);
|
||||
jobj1 = LUKS2_array_jobj(jobj_digest_segments, key);
|
||||
if (!jobj1)
|
||||
json_object_array_add(jobj_digest_segments, json_object_new_string(key));
|
||||
}
|
||||
} else {
|
||||
jobj1 = json_object_new_array();
|
||||
if (!jobj1)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_digest, "segments", jobj1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int assign_one_segment(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int segment, int digest, int assign)
|
||||
{
|
||||
@@ -286,17 +324,27 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
json_object *jobj_digests;
|
||||
int r = 0;
|
||||
|
||||
if (segment == CRYPT_DEFAULT_SEGMENT)
|
||||
segment = LUKS2_get_default_segment(hdr);
|
||||
|
||||
if (digest == CRYPT_ANY_DIGEST) {
|
||||
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
|
||||
|
||||
json_object_object_foreach(jobj_digests, key, val) {
|
||||
UNUSED(val);
|
||||
r = assign_one_segment(cd, hdr, segment, atoi(key), assign);
|
||||
if (segment == CRYPT_ANY_SEGMENT)
|
||||
r = assign_all_segments(cd, hdr, atoi(key), assign);
|
||||
else
|
||||
r = assign_one_segment(cd, hdr, segment, atoi(key), assign);
|
||||
if (r < 0)
|
||||
break;
|
||||
}
|
||||
} else
|
||||
r = assign_one_segment(cd, hdr, segment, digest, assign);
|
||||
} else {
|
||||
if (segment == CRYPT_ANY_SEGMENT)
|
||||
r = assign_all_segments(cd, hdr, digest, assign);
|
||||
else
|
||||
r = assign_one_segment(cd, hdr, segment, digest, assign);
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -367,6 +415,11 @@ static char *get_key_description_by_digest(struct crypt_device *cd, int digest)
|
||||
return desc;
|
||||
}
|
||||
|
||||
char *LUKS2_key_description_by_digest(struct crypt_device *cd, int digest)
|
||||
{
|
||||
return get_key_description_by_digest(cd, digest);
|
||||
}
|
||||
|
||||
int LUKS2_key_description_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int segment)
|
||||
{
|
||||
@@ -391,3 +444,17 @@ int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
|
||||
free(desc);
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int digest)
|
||||
{
|
||||
char *desc = get_key_description_by_digest(cd, digest);
|
||||
int r;
|
||||
|
||||
r = crypt_volume_key_set_description(vk, desc);
|
||||
if (!r)
|
||||
r = crypt_volume_key_load_in_keyring(cd, vk);
|
||||
|
||||
free(desc);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -131,8 +131,8 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
|
||||
}
|
||||
|
||||
hmac_size = crypt_hmac_size(pbkdf.hash);
|
||||
if (hmac_size < 0)
|
||||
return hmac_size;
|
||||
if (hmac_size < 0 || hmac_size > (int)sizeof(digest_raw))
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, pbkdf.hash, volume_key, volume_key_len,
|
||||
salt, LUKS_SALTSIZE, digest_raw, hmac_size,
|
||||
|
||||
@@ -233,7 +233,7 @@ static int hdr_read_disk(struct crypt_device *cd,
|
||||
char **json_area, uint64_t offset, int secondary)
|
||||
{
|
||||
size_t hdr_json_size = 0;
|
||||
int devfd = -1, r;
|
||||
int devfd, r;
|
||||
|
||||
log_dbg(cd, "Trying to read %s LUKS2 header at offset 0x%" PRIx64 ".",
|
||||
secondary ? "secondary" : "primary", offset);
|
||||
@@ -249,13 +249,11 @@ static int hdr_read_disk(struct crypt_device *cd,
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), hdr_disk,
|
||||
LUKS2_HDR_BIN_LEN, offset) != LUKS2_HDR_BIN_LEN) {
|
||||
close(devfd);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
r = hdr_disk_sanity_check_pre(cd, hdr_disk, &hdr_json_size, secondary, offset);
|
||||
if (r < 0) {
|
||||
close(devfd);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -264,21 +262,17 @@ static int hdr_read_disk(struct crypt_device *cd,
|
||||
*/
|
||||
*json_area = malloc(hdr_json_size);
|
||||
if (!*json_area) {
|
||||
close(devfd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), *json_area, hdr_json_size,
|
||||
offset + LUKS2_HDR_BIN_LEN) != (ssize_t)hdr_json_size) {
|
||||
close(devfd);
|
||||
free(*json_area);
|
||||
*json_area = NULL;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
close(devfd);
|
||||
|
||||
/*
|
||||
* Calculate and validate checksum and zero it afterwards.
|
||||
*/
|
||||
@@ -302,7 +296,7 @@ static int hdr_write_disk(struct crypt_device *cd,
|
||||
struct luks2_hdr_disk hdr_disk;
|
||||
uint64_t offset = secondary ? hdr->hdr_size : 0;
|
||||
size_t hdr_json_len;
|
||||
int devfd = -1, r;
|
||||
int devfd, r;
|
||||
|
||||
log_dbg(cd, "Trying to write LUKS2 header (%zu bytes) at offset %" PRIu64 ".",
|
||||
hdr->hdr_size, offset);
|
||||
@@ -323,7 +317,6 @@ static int hdr_write_disk(struct crypt_device *cd,
|
||||
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), (char *)&hdr_disk,
|
||||
LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN) {
|
||||
close(devfd);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -334,7 +327,6 @@ static int hdr_write_disk(struct crypt_device *cd,
|
||||
device_alignment(device),
|
||||
CONST_CAST(char*)json_area, hdr_json_len,
|
||||
LUKS2_HDR_BIN_LEN + offset) < (ssize_t)hdr_json_len) {
|
||||
close(devfd);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -344,7 +336,6 @@ static int hdr_write_disk(struct crypt_device *cd,
|
||||
r = hdr_checksum_calculate(hdr_disk.checksum_alg, &hdr_disk,
|
||||
json_area, hdr_json_len);
|
||||
if (r < 0) {
|
||||
close(devfd);
|
||||
return r;
|
||||
}
|
||||
log_dbg_checksum(cd, hdr_disk.csum, hdr_disk.checksum_alg, "in-memory");
|
||||
@@ -354,16 +345,63 @@ static int hdr_write_disk(struct crypt_device *cd,
|
||||
LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN)
|
||||
r = -EIO;
|
||||
|
||||
device_sync(cd, device, devfd);
|
||||
close(devfd);
|
||||
device_sync(cd, device);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int LUKS2_check_sequence_id(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device)
|
||||
{
|
||||
int devfd;
|
||||
struct luks2_hdr_disk dhdr;
|
||||
|
||||
if (!hdr)
|
||||
return -EINVAL;
|
||||
|
||||
devfd = device_open_locked(cd, device, O_RDONLY);
|
||||
if (devfd < 0)
|
||||
return devfd == -1 ? -EINVAL : devfd;
|
||||
|
||||
/* we need only first 512 bytes, see luks2_hdr_disk structure */
|
||||
if ((read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), &dhdr, 512, 0) != 512))
|
||||
return -EIO;
|
||||
|
||||
/* there's nothing to check if there's no LUKS2 header */
|
||||
if ((be16_to_cpu(dhdr.version) != 2) ||
|
||||
memcmp(dhdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L) ||
|
||||
strcmp(dhdr.uuid, hdr->uuid))
|
||||
return 0;
|
||||
|
||||
return hdr->seqid != be64_to_cpu(dhdr.seqid);
|
||||
}
|
||||
|
||||
int LUKS2_device_write_lock(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device)
|
||||
{
|
||||
int r = device_write_lock(cd, device);
|
||||
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."), device_path(device));
|
||||
return r;
|
||||
}
|
||||
|
||||
/* run sequence id check only on first write lock (r == 1) and w/o LUKS2 reencryption in-progress */
|
||||
if (r == 1 && !crypt_get_reenc_context(cd)) {
|
||||
log_dbg(cd, "Checking context sequence id matches value stored on disk.");
|
||||
if (LUKS2_check_sequence_id(cd, hdr, device)) {
|
||||
device_write_unlock(cd, device);
|
||||
log_err(cd, _("Detected attempt for concurrent LUKS2 metadata update. Aborting operation."));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert in-memory LUKS2 header and write it to disk.
|
||||
* This will increase sequence id, write both header copies and calculate checksum.
|
||||
*/
|
||||
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device)
|
||||
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device, bool seqid_check)
|
||||
{
|
||||
char *json_area;
|
||||
const char *json_text;
|
||||
@@ -405,16 +443,18 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
|
||||
}
|
||||
strncpy(json_area, json_text, json_area_len);
|
||||
|
||||
/* Increase sequence id before writing it to disk. */
|
||||
hdr->seqid++;
|
||||
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write device lock."));
|
||||
if (seqid_check)
|
||||
r = LUKS2_device_write_lock(cd, hdr, device);
|
||||
else
|
||||
r = device_write_lock(cd, device);
|
||||
if (r < 0) {
|
||||
free(json_area);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Increase sequence id before writing it to disk. */
|
||||
hdr->seqid++;
|
||||
|
||||
/* Write primary and secondary header */
|
||||
r = hdr_write_disk(cd, device, hdr, json_area, 0);
|
||||
if (!r)
|
||||
@@ -425,8 +465,6 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
|
||||
|
||||
device_write_unlock(cd, device);
|
||||
|
||||
/* FIXME: try recovery here? */
|
||||
|
||||
free(json_area);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct device *device, int do_recovery, int do_blkprobe);
|
||||
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct device *device);
|
||||
struct device *device, bool seqid_check);
|
||||
|
||||
/*
|
||||
* JSON struct access helpers
|
||||
@@ -54,6 +54,7 @@ json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token);
|
||||
json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int digest);
|
||||
json_object *LUKS2_get_segment_jobj(struct luks2_hdr *hdr, int segment);
|
||||
json_object *LUKS2_get_tokens_jobj(struct luks2_hdr *hdr);
|
||||
json_object *LUKS2_get_segments_jobj(struct luks2_hdr *hdr);
|
||||
|
||||
void hexprint_base64(struct crypt_device *cd, json_object *jobj,
|
||||
const char *sep, const char *line_sep);
|
||||
@@ -63,8 +64,10 @@ json_object *parse_json_len(struct crypt_device *cd, const char *json_area,
|
||||
uint64_t json_object_get_uint64(json_object *jobj);
|
||||
uint32_t json_object_get_uint32(json_object *jobj);
|
||||
json_object *json_object_new_uint64(uint64_t value);
|
||||
|
||||
int json_object_object_add_by_uint(json_object *jobj, unsigned key, json_object *jobj_val);
|
||||
void json_object_object_del_by_uint(json_object *jobj, unsigned key);
|
||||
int json_object_copy(json_object *jobj_src, json_object **jobj_dst);
|
||||
|
||||
void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc);
|
||||
|
||||
@@ -73,6 +76,7 @@ void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc);
|
||||
*/
|
||||
|
||||
/* validation helper */
|
||||
json_bool validate_json_uint32(json_object *jobj);
|
||||
json_object *json_contains(struct crypt_device *cd, json_object *jobj, const char *name,
|
||||
const char *section, const char *key, json_type type);
|
||||
|
||||
@@ -141,6 +145,12 @@ typedef struct {
|
||||
keyslot_repair_func repair;
|
||||
} keyslot_handler;
|
||||
|
||||
/* can not fit prototype alloc function */
|
||||
int reenc_keyslot_alloc(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params);
|
||||
|
||||
/**
|
||||
* LUKS2 digest handlers (EXPERIMENTAL)
|
||||
*/
|
||||
@@ -178,5 +188,11 @@ int token_keyring_get(json_object *, void *);
|
||||
|
||||
int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
size_t keylength, uint64_t *area_offset, uint64_t *area_length);
|
||||
int LUKS2_find_area_max_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
uint64_t *area_offset, uint64_t *area_length);
|
||||
|
||||
int LUKS2_check_cipher(struct crypt_device *cd,
|
||||
size_t keylength,
|
||||
const char *cipher,
|
||||
const char *cipher_mode);
|
||||
#endif
|
||||
|
||||
@@ -39,9 +39,83 @@ static size_t get_min_offset(struct luks2_hdr *hdr)
|
||||
return 2 * hdr->hdr_size;
|
||||
}
|
||||
|
||||
static size_t get_max_offset(struct crypt_device *cd)
|
||||
static size_t get_max_offset(struct luks2_hdr *hdr)
|
||||
{
|
||||
return crypt_get_data_offset(cd) * SECTOR_SIZE;
|
||||
return LUKS2_hdr_and_areas_size(hdr->jobj);
|
||||
}
|
||||
|
||||
int LUKS2_find_area_max_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
uint64_t *area_offset, uint64_t *area_length)
|
||||
{
|
||||
struct area areas[LUKS2_KEYSLOTS_MAX], sorted_areas[LUKS2_KEYSLOTS_MAX+1] = {};
|
||||
int i, j, k, area_i;
|
||||
size_t valid_offset, offset, length;
|
||||
|
||||
/* fill area offset + length table */
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
if (!LUKS2_keyslot_area(hdr, i, &areas[i].offset, &areas[i].length))
|
||||
continue;
|
||||
areas[i].length = 0;
|
||||
areas[i].offset = 0;
|
||||
}
|
||||
|
||||
/* sort table */
|
||||
k = 0; /* index in sorted table */
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
offset = get_max_offset(hdr) ?: UINT64_MAX;
|
||||
area_i = -1;
|
||||
/* search for the smallest offset in table */
|
||||
for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++)
|
||||
if (areas[j].offset && areas[j].offset <= offset) {
|
||||
area_i = j;
|
||||
offset = areas[j].offset;
|
||||
}
|
||||
|
||||
if (area_i >= 0) {
|
||||
sorted_areas[k].length = areas[area_i].length;
|
||||
sorted_areas[k].offset = areas[area_i].offset;
|
||||
areas[area_i].length = 0;
|
||||
areas[area_i].offset = 0;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
sorted_areas[LUKS2_KEYSLOTS_MAX].offset = get_max_offset(hdr);
|
||||
sorted_areas[LUKS2_KEYSLOTS_MAX].length = 1;
|
||||
|
||||
/* search for the gap we can use */
|
||||
length = valid_offset = 0;
|
||||
offset = get_min_offset(hdr);
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX+1; i++) {
|
||||
/* skip empty */
|
||||
if (sorted_areas[i].offset == 0 || sorted_areas[i].length == 0)
|
||||
continue;
|
||||
|
||||
/* found bigger gap than the last one */
|
||||
if ((offset < sorted_areas[i].offset) && (sorted_areas[i].offset - offset) > length) {
|
||||
length = sorted_areas[i].offset - offset;
|
||||
valid_offset = offset;
|
||||
}
|
||||
|
||||
/* move beyond allocated area */
|
||||
offset = sorted_areas[i].offset + sorted_areas[i].length;
|
||||
}
|
||||
|
||||
/* this search 'algorithm' does not work with unaligned areas */
|
||||
assert(length == size_round_up(length, 4096));
|
||||
assert(valid_offset == size_round_up(valid_offset, 4096));
|
||||
|
||||
if (!length) {
|
||||
log_dbg(cd, "Not enough space in header keyslot area.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
log_dbg(cd, "Found largest free area %zu -> %zu", valid_offset, length + valid_offset);
|
||||
|
||||
*area_offset = valid_offset;
|
||||
*area_length = length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
@@ -62,7 +136,7 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
/* sort table */
|
||||
k = 0; /* index in sorted table */
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
offset = get_max_offset(cd) ?: UINT64_MAX;
|
||||
offset = get_max_offset(hdr) ?: UINT64_MAX;
|
||||
area_i = -1;
|
||||
/* search for the smallest offset in table */
|
||||
for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++)
|
||||
@@ -96,20 +170,13 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
offset = sorted_areas[i].offset + sorted_areas[i].length;
|
||||
}
|
||||
|
||||
if (get_max_offset(cd) && (offset + length) > get_max_offset(cd)) {
|
||||
log_err(cd, _("No space for new keyslot."));
|
||||
if ((offset + length) > get_max_offset(hdr)) {
|
||||
log_dbg(cd, "Not enough space in header keyslot area.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
log_dbg(cd, "Found area %zu -> %zu", offset, length + offset);
|
||||
/*
|
||||
log_dbg("Area offset min: %zu, max %zu, slots max %u",
|
||||
get_min_offset(hdr), get_max_offset(cd), LUKS2_KEYSLOTS_MAX);
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++)
|
||||
log_dbg("SLOT[%02i]: %-8" PRIu64 " -> %-8" PRIu64, i,
|
||||
sorted_areas[i].offset,
|
||||
sorted_areas[i].length + sorted_areas[i].offset);
|
||||
*/
|
||||
|
||||
*area_offset = offset;
|
||||
*area_length = length;
|
||||
return 0;
|
||||
@@ -232,25 +299,15 @@ int LUKS2_generate_hdr(
|
||||
json_object_object_add(hdr->jobj, "config", jobj_config);
|
||||
|
||||
digest = LUKS2_digest_create(cd, "pbkdf2", hdr, vk);
|
||||
if (digest < 0) {
|
||||
json_object_put(hdr->jobj);
|
||||
hdr->jobj = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (digest < 0)
|
||||
goto err;
|
||||
|
||||
if (LUKS2_digest_segment_assign(cd, hdr, CRYPT_DEFAULT_SEGMENT, digest, 1, 0) < 0) {
|
||||
json_object_put(hdr->jobj);
|
||||
hdr->jobj = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (LUKS2_digest_segment_assign(cd, hdr, 0, digest, 1, 0) < 0)
|
||||
goto err;
|
||||
|
||||
jobj_segment = json_object_new_object();
|
||||
json_object_object_add(jobj_segment, "type", json_object_new_string("crypt"));
|
||||
json_object_object_add(jobj_segment, "offset", json_object_new_uint64(data_offset));
|
||||
json_object_object_add(jobj_segment, "iv_tweak", json_object_new_string("0"));
|
||||
json_object_object_add(jobj_segment, "size", json_object_new_string("dynamic"));
|
||||
json_object_object_add(jobj_segment, "encryption", json_object_new_string(cipher));
|
||||
json_object_object_add(jobj_segment, "sector_size", json_object_new_int(sector_size));
|
||||
jobj_segment = json_segment_create_crypt(data_offset, 0, NULL, cipher, sector_size, 0);
|
||||
if (!jobj_segment)
|
||||
goto err;
|
||||
|
||||
if (integrity) {
|
||||
jobj_integrity = json_object_new_object();
|
||||
@@ -260,13 +317,17 @@ int LUKS2_generate_hdr(
|
||||
json_object_object_add(jobj_segment, "integrity", jobj_integrity);
|
||||
}
|
||||
|
||||
json_object_object_add_by_uint(jobj_segments, CRYPT_DEFAULT_SEGMENT, jobj_segment);
|
||||
json_object_object_add_by_uint(jobj_segments, 0, jobj_segment);
|
||||
|
||||
json_object_object_add(jobj_config, "json_size", json_object_new_uint64(metadata_size - LUKS2_HDR_BIN_LEN));
|
||||
json_object_object_add(jobj_config, "keyslots_size", json_object_new_uint64(keyslots_size));
|
||||
|
||||
JSON_DBG(cd, hdr->jobj, "Header JSON:");
|
||||
return 0;
|
||||
err:
|
||||
json_object_put(hdr->jobj);
|
||||
hdr->jobj = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int LUKS2_wipe_header_areas(struct crypt_device *cd,
|
||||
@@ -309,3 +370,30 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
|
||||
return crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_RANDOM,
|
||||
offset, length, wipe_block, NULL, NULL);
|
||||
}
|
||||
|
||||
/* FIXME: what if user wanted to keep original keyslots size? */
|
||||
int LUKS2_set_keyslots_size(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
uint64_t data_offset)
|
||||
{
|
||||
json_object *jobj_config;
|
||||
uint64_t keyslots_size;
|
||||
|
||||
if (data_offset < get_min_offset(hdr))
|
||||
return 1;
|
||||
|
||||
keyslots_size = data_offset - get_min_offset(hdr);
|
||||
|
||||
/* keep keyslots_size reasonable for custom data alignments */
|
||||
if (keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE)
|
||||
keyslots_size = LUKS2_MAX_KEYSLOTS_SIZE;
|
||||
|
||||
/* keyslots size has to be 4 KiB aligned */
|
||||
keyslots_size -= (keyslots_size % 4096);
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
|
||||
return 1;
|
||||
|
||||
json_object_object_add(jobj_config, "keyslots_size", json_object_new_uint64(keyslots_size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,9 +23,11 @@
|
||||
|
||||
/* Internal implementations */
|
||||
extern const keyslot_handler luks2_keyslot;
|
||||
extern const keyslot_handler reenc_keyslot;
|
||||
|
||||
static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
|
||||
&luks2_keyslot,
|
||||
&reenc_keyslot,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -63,7 +65,7 @@ static const keyslot_handler
|
||||
return LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj2));
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
|
||||
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -75,23 +77,55 @@ int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
|
||||
}
|
||||
|
||||
/* Check if a keyslot is asssigned to specific segment */
|
||||
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
|
||||
static int _keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
|
||||
{
|
||||
int keyslot_digest, segment_digest;
|
||||
|
||||
/* no need to check anything */
|
||||
if (segment == CRYPT_ANY_SEGMENT)
|
||||
return 0;
|
||||
int keyslot_digest, segment_digest, s, count = 0;
|
||||
|
||||
keyslot_digest = LUKS2_digest_by_keyslot(hdr, keyslot);
|
||||
if (keyslot_digest < 0)
|
||||
return -EINVAL;
|
||||
return keyslot_digest;
|
||||
|
||||
segment_digest = LUKS2_digest_by_segment(hdr, segment);
|
||||
if (segment_digest < 0)
|
||||
return segment_digest;
|
||||
if (segment >= 0) {
|
||||
segment_digest = LUKS2_digest_by_segment(hdr, segment);
|
||||
return segment_digest == keyslot_digest;
|
||||
}
|
||||
for (s = 0; s < 3; s++) {
|
||||
segment_digest = LUKS2_digest_by_segment(hdr, s);
|
||||
if (segment_digest == keyslot_digest)
|
||||
count++;
|
||||
}
|
||||
|
||||
return segment_digest == keyslot_digest ? 0 : -ENOENT;
|
||||
return count;
|
||||
}
|
||||
|
||||
static int _keyslot_for_digest(struct luks2_hdr *hdr, int keyslot, int digest)
|
||||
{
|
||||
int r = -EINVAL;
|
||||
|
||||
r = LUKS2_digest_by_keyslot(hdr, keyslot);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r == digest ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
|
||||
{
|
||||
int r = -EINVAL;
|
||||
|
||||
/* no need to check anything */
|
||||
if (segment == CRYPT_ANY_SEGMENT)
|
||||
return 0; /* ok */
|
||||
if (segment == CRYPT_DEFAULT_SEGMENT) {
|
||||
segment = LUKS2_get_default_segment(hdr);
|
||||
if (segment < 0)
|
||||
return segment;
|
||||
}
|
||||
|
||||
r = _keyslot_for_segment(hdr, keyslot, segment);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return r >= 1 ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
/* Number of keyslots assigned to a segment or all keyslots for CRYPT_ANY_SEGMENT */
|
||||
@@ -165,7 +199,7 @@ int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
*/
|
||||
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
|
||||
/* currently we use hash for AF from pbkdf settings */
|
||||
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash), "%s", pbkdf->hash);
|
||||
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash), "%s", pbkdf->hash ?: DEFAULT_LUKS1_HASH);
|
||||
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
|
||||
return -EINVAL;
|
||||
params->af.luks1.stripes = 4000;
|
||||
@@ -266,15 +300,58 @@ int LUKS2_keyslot_area(struct luks2_hdr *hdr,
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "offset", &jobj))
|
||||
return -EINVAL;
|
||||
*offset = json_object_get_int64(jobj);
|
||||
*offset = json_object_get_uint64(jobj);
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "size", &jobj))
|
||||
return -EINVAL;
|
||||
*length = json_object_get_int64(jobj);
|
||||
*length = json_object_get_uint64(jobj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int LUKS2_open_and_verify_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
int digest,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vk)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int key_size, r;
|
||||
|
||||
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
|
||||
return -ENOENT;
|
||||
|
||||
r = _keyslot_for_digest(hdr, keyslot, digest);
|
||||
if (r) {
|
||||
if (r == -ENOENT)
|
||||
log_dbg(cd, "Keyslot %d unusable for digest %d.", keyslot, digest);
|
||||
return r;
|
||||
}
|
||||
|
||||
key_size = LUKS2_get_keyslot_stored_key_size(hdr, keyslot);
|
||||
if (key_size < 0)
|
||||
return -EINVAL;
|
||||
|
||||
*vk = crypt_alloc_volume_key(key_size, NULL);
|
||||
if (!*vk)
|
||||
return -ENOMEM;
|
||||
|
||||
r = h->open(cd, keyslot, password, password_len, (*vk)->key, (*vk)->keylength);
|
||||
if (r < 0)
|
||||
log_dbg(cd, "Keyslot %d (%s) open failed with %d.", keyslot, h->name, r);
|
||||
else
|
||||
r = LUKS2_digest_verify(cd, hdr, *vk, keyslot);
|
||||
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(*vk);
|
||||
*vk = NULL;
|
||||
}
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
static int LUKS2_open_and_verify(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -321,11 +398,50 @@ static int LUKS2_open_and_verify(struct crypt_device *cd,
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(*vk);
|
||||
*vk = NULL;
|
||||
}
|
||||
} else
|
||||
crypt_volume_key_set_id(*vk, r);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
static int LUKS2_keyslot_open_priority_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
crypt_keyslot_priority priority,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
int digest,
|
||||
struct volume_key **vk)
|
||||
{
|
||||
json_object *jobj_keyslots, *jobj;
|
||||
crypt_keyslot_priority slot_priority;
|
||||
int keyslot, r = -ENOENT;
|
||||
|
||||
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
|
||||
|
||||
json_object_object_foreach(jobj_keyslots, slot, val) {
|
||||
if (!json_object_object_get_ex(val, "priority", &jobj))
|
||||
slot_priority = CRYPT_SLOT_PRIORITY_NORMAL;
|
||||
else
|
||||
slot_priority = json_object_get_int(jobj);
|
||||
|
||||
keyslot = atoi(slot);
|
||||
if (slot_priority != priority) {
|
||||
log_dbg(cd, "Keyslot %d priority %d != %d (required), skipped.",
|
||||
keyslot, slot_priority, priority);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
|
||||
|
||||
/* Do not retry for errors that are no -EPERM or -ENOENT,
|
||||
former meaning password wrong, latter key slot unusable for segment */
|
||||
if ((r != -EPERM) && (r != -ENOENT))
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
crypt_keyslot_priority priority,
|
||||
@@ -364,6 +480,76 @@ static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int LUKS2_keyslot_open_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
int digest,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vk)
|
||||
{
|
||||
int r_prio, r = -EINVAL;
|
||||
|
||||
if (digest < 0)
|
||||
return r;
|
||||
|
||||
if (keyslot == CRYPT_ANY_SLOT) {
|
||||
r_prio = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_PREFER,
|
||||
password, password_len, digest, vk);
|
||||
if (r_prio >= 0)
|
||||
r = r_prio;
|
||||
else if (r_prio != -EPERM && r_prio != -ENOENT)
|
||||
r = r_prio;
|
||||
else
|
||||
r = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_NORMAL,
|
||||
password, password_len, digest, vk);
|
||||
/* Prefer password wrong to no entry from priority slot */
|
||||
if (r_prio == -EPERM && r == -ENOENT)
|
||||
r = r_prio;
|
||||
} else
|
||||
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vks)
|
||||
{
|
||||
struct volume_key *vk;
|
||||
int digest_old, digest_new, r = -EINVAL;
|
||||
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
|
||||
digest_old = LUKS2_reencrypt_digest_old(hdr);
|
||||
if (digest_old >= 0) {
|
||||
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_old, keyslot_old);
|
||||
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_old, digest_old, password, password_len, &vk);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
crypt_volume_key_set_id(vk, digest_old);
|
||||
crypt_volume_key_add_next(vks, vk);
|
||||
}
|
||||
|
||||
digest_new = LUKS2_reencrypt_digest_new(hdr);
|
||||
if (digest_new >= 0 && digest_old != digest_new) {
|
||||
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_new, keyslot_new);
|
||||
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_new, digest_new, password, password_len, &vk);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
crypt_volume_key_set_id(vk, digest_new);
|
||||
crypt_volume_key_add_next(vks, vk);
|
||||
}
|
||||
out:
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(*vks);
|
||||
*vks = NULL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
int segment,
|
||||
@@ -395,6 +581,64 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int r;
|
||||
|
||||
if (keyslot == CRYPT_ANY_SLOT)
|
||||
return -EINVAL;
|
||||
|
||||
/* FIXME: find keyslot by type */
|
||||
h = LUKS2_keyslot_handler_type(cd, "reencrypt");
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
r = reenc_keyslot_alloc(cd, hdr, keyslot, params);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = LUKS2_keyslot_priority_set(cd, hdr, keyslot, CRYPT_SLOT_PRIORITY_IGNORE, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
log_dbg(cd, "Keyslot validation failed.");
|
||||
return r;
|
||||
}
|
||||
|
||||
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const void *buffer,
|
||||
size_t buffer_length)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int r;
|
||||
|
||||
if (!(h = LUKS2_keyslot_handler(cd, keyslot)) || strcmp(h->name, "reencrypt"))
|
||||
return -EINVAL;
|
||||
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
log_dbg(cd, "Keyslot validation failed.");
|
||||
return r;
|
||||
}
|
||||
|
||||
return h->store(cd, keyslot, NULL, 0,
|
||||
buffer, buffer_length);
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -435,6 +679,9 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
|
||||
return -EINVAL;
|
||||
|
||||
return h->store(cd, keyslot, password, password_len,
|
||||
vk->key, vk->keylength);
|
||||
}
|
||||
@@ -462,21 +709,15 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
if (wipe_area_only)
|
||||
log_dbg(cd, "Wiping keyslot %d area only.", keyslot);
|
||||
|
||||
/* Just check that nobody uses the metadata now */
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."),
|
||||
device_path(device));
|
||||
r = LUKS2_device_write_lock(cd, hdr, device);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
device_write_unlock(cd, device);
|
||||
|
||||
/* secure deletion of possible key material in keyslot area */
|
||||
r = crypt_keyslot_area(cd, keyslot, &area_offset, &area_length);
|
||||
if (r && r != -ENOENT)
|
||||
return r;
|
||||
goto out;
|
||||
|
||||
/* We can destroy the binary keyslot area now without lock */
|
||||
if (!r) {
|
||||
r = crypt_wipe_device(cd, device, CRYPT_WIPE_SPECIAL, area_offset,
|
||||
area_length, area_length, NULL, NULL);
|
||||
@@ -487,24 +728,27 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
r = -EINVAL;
|
||||
} else
|
||||
log_err(cd, _("Cannot wipe device %s."), device_path(device));
|
||||
return r;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (wipe_area_only)
|
||||
return r;
|
||||
goto out;
|
||||
|
||||
/* Slot specific wipe */
|
||||
if (h) {
|
||||
r = h->wipe(cd, keyslot);
|
||||
if (r < 0)
|
||||
return r;
|
||||
goto out;
|
||||
} else
|
||||
log_dbg(cd, "Wiping keyslot %d without specific-slot handler loaded.", keyslot);
|
||||
|
||||
json_object_object_del_by_uint(jobj_keyslots, keyslot);
|
||||
|
||||
return LUKS2_hdr_write(cd, hdr);
|
||||
r = LUKS2_hdr_write(cd, hdr);
|
||||
out:
|
||||
device_write_unlock(cd, crypt_metadata_device(cd));
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
@@ -661,3 +905,46 @@ void LUKS2_keyslots_repair(struct crypt_device *cd, json_object *jobj_keyslots)
|
||||
h->repair(cd, val);
|
||||
}
|
||||
}
|
||||
|
||||
/* assumes valid header */
|
||||
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type)
|
||||
{
|
||||
int i;
|
||||
json_object *jobj_keyslot, *jobj_type;
|
||||
|
||||
if (!type)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, i);
|
||||
if (!jobj_keyslot)
|
||||
continue;
|
||||
|
||||
json_object_object_get_ex(jobj_keyslot, "type", &jobj_type);
|
||||
if (!strcmp(json_object_get_string(jobj_type), type))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_find_keyslot_for_segment(struct luks2_hdr *hdr, int segment, const char *type)
|
||||
{
|
||||
int i;
|
||||
json_object *jobj_keyslot, *jobj_type;
|
||||
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, i);
|
||||
if (!jobj_keyslot)
|
||||
continue;
|
||||
|
||||
json_object_object_get_ex(jobj_keyslot, "type", &jobj_type);
|
||||
if (strcmp(json_object_get_string(jobj_type), type))
|
||||
continue;
|
||||
|
||||
if (!LUKS2_keyslot_for_segment(hdr, i, segment))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -28,49 +28,38 @@
|
||||
#define LUKS_SLOT_ITERATIONS_MIN 1000
|
||||
#define LUKS_STRIPES 4000
|
||||
|
||||
/* Serialize memory-hard keyslot access: opttional workaround for parallel processing */
|
||||
#define MIN_MEMORY_FOR_SERIALIZE_LOCK_KB 32*1024 /* 32MB */
|
||||
|
||||
static int luks2_encrypt_to_storage(char *src, size_t srcLength,
|
||||
const char *cipher, const char *cipher_mode,
|
||||
struct volume_key *vk, unsigned int sector,
|
||||
struct crypt_device *cd)
|
||||
{
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
|
||||
int r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."), device_path(device));
|
||||
return r;
|
||||
}
|
||||
r = LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd);
|
||||
device_write_unlock(cd, crypt_metadata_device(cd));
|
||||
return r;
|
||||
return LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd);
|
||||
#else
|
||||
struct crypt_storage *s;
|
||||
int devfd = -1, r;
|
||||
int devfd, r;
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
|
||||
/* Only whole sector writes supported */
|
||||
if (MISALIGNED_512(srcLength))
|
||||
return -EINVAL;
|
||||
|
||||
/* Encrypt buffer */
|
||||
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
if (r) {
|
||||
log_dbg(cd, "Userspace crypto wrapper cannot use %s-%s (%d).",
|
||||
cipher, cipher_mode, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = crypt_storage_encrypt(s, 0, srcLength / SECTOR_SIZE, src);
|
||||
r = crypt_storage_encrypt(s, 0, srcLength, src);
|
||||
crypt_storage_destroy(s);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."),
|
||||
device_path(device));
|
||||
return r;
|
||||
}
|
||||
|
||||
devfd = device_open_locked(cd, device, O_RDWR);
|
||||
if (devfd >= 0) {
|
||||
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
@@ -80,13 +69,10 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
|
||||
else
|
||||
r = 0;
|
||||
|
||||
device_sync(cd, device, devfd);
|
||||
close(devfd);
|
||||
device_sync(cd, device);
|
||||
} else
|
||||
r = -EIO;
|
||||
|
||||
device_write_unlock(cd, device);
|
||||
|
||||
if (r)
|
||||
log_err(cd, _("IO error while encrypting keyslot."));
|
||||
|
||||
@@ -110,13 +96,13 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
return r;
|
||||
#else
|
||||
struct crypt_storage *s;
|
||||
int devfd = -1, r;
|
||||
int devfd, r;
|
||||
|
||||
/* Only whole sector writes supported */
|
||||
if (MISALIGNED_512(dstLength))
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
if (r) {
|
||||
log_dbg(cd, "Userspace crypto wrapper cannot use %s-%s (%d).",
|
||||
cipher, cipher_mode, r);
|
||||
@@ -139,7 +125,6 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
r = -EIO;
|
||||
else
|
||||
r = 0;
|
||||
close(devfd);
|
||||
} else
|
||||
r = -EIO;
|
||||
|
||||
@@ -147,7 +132,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
|
||||
/* Decrypt buffer */
|
||||
if (!r)
|
||||
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
|
||||
r = crypt_storage_decrypt(s, 0, dstLength, dst);
|
||||
else
|
||||
log_err(cd, _("IO error while decrypting keyslot."));
|
||||
|
||||
@@ -312,6 +297,7 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
json_object *jobj2, *jobj_af, *jobj_area;
|
||||
uint64_t area_offset;
|
||||
size_t keyslot_key_len;
|
||||
bool try_serialize_lock = false;
|
||||
int r;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
@@ -339,6 +325,13 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
keyslot_key_len = json_object_get_int(jobj2);
|
||||
|
||||
/*
|
||||
* If requested, serialize unlocking for memory-hard KDF. Usually NOOP.
|
||||
*/
|
||||
if (pbkdf.max_memory_kb > MIN_MEMORY_FOR_SERIALIZE_LOCK_KB)
|
||||
try_serialize_lock = true;
|
||||
if (try_serialize_lock && crypt_serialize_lock(cd))
|
||||
return -EINVAL;
|
||||
/*
|
||||
* Allocate derived key storage space.
|
||||
*/
|
||||
@@ -361,6 +354,9 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
pbkdf.iterations, pbkdf.max_memory_kb,
|
||||
pbkdf.parallel_threads);
|
||||
|
||||
if (try_serialize_lock)
|
||||
crypt_serialize_unlock(cd);
|
||||
|
||||
if (r == 0) {
|
||||
log_dbg(cd, "Reading keyslot area [0x%04x].", (unsigned)area_offset);
|
||||
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
|
||||
@@ -466,7 +462,7 @@ static int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
|
||||
if (keyslot == CRYPT_ANY_SLOT)
|
||||
keyslot = LUKS2_keyslot_find_empty(hdr, "luks2");
|
||||
keyslot = LUKS2_keyslot_find_empty(hdr);
|
||||
|
||||
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return -ENOMEM;
|
||||
@@ -480,8 +476,10 @@ static int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
|
||||
r = LUKS2_find_area_gap(cd, hdr, volume_key_len, &area_offset, &area_length);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
log_err(cd, _("No space for new keyslot."));
|
||||
return r;
|
||||
}
|
||||
|
||||
jobj_keyslot = json_object_new_object();
|
||||
json_object_object_add(jobj_keyslot, "type", json_object_new_string("luks2"));
|
||||
@@ -563,17 +561,19 @@ static int luks2_keyslot_store(struct crypt_device *cd,
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
|
||||
if(r)
|
||||
return r;
|
||||
|
||||
r = luks2_keyslot_set_key(cd, jobj_keyslot,
|
||||
password, password_len,
|
||||
volume_key, volume_key_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!r)
|
||||
r = LUKS2_hdr_write(cd, hdr);
|
||||
|
||||
r = LUKS2_hdr_write(cd, hdr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
device_write_unlock(cd, crypt_metadata_device(cd));
|
||||
|
||||
return keyslot;
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_wipe(struct crypt_device *cd, int keyslot)
|
||||
|
||||
329
lib/luks2/luks2_keyslot_reenc.c
Normal file
329
lib/luks2/luks2_keyslot_reenc.c
Normal file
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, reencryption keyslot handler
|
||||
*
|
||||
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Ondrej Kozina
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "luks2_internal.h"
|
||||
|
||||
static int reenc_keyslot_open(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
char *volume_key,
|
||||
size_t volume_key_len)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int reenc_keyslot_alloc(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params)
|
||||
{
|
||||
int r;
|
||||
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
|
||||
uint64_t area_offset, area_length;
|
||||
|
||||
log_dbg(cd, "Allocating reencrypt keyslot %d.", keyslot);
|
||||
|
||||
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
|
||||
return -EINVAL;
|
||||
|
||||
/* encryption doesn't require area (we shift data and backup will be available) */
|
||||
if (!params->data_shift) {
|
||||
r = LUKS2_find_area_max_gap(cd, hdr, &area_offset, &area_length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else { /* we can't have keyslot w/o area...bug? */
|
||||
r = LUKS2_find_area_gap(cd, hdr, 1, &area_offset, &area_length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
jobj_keyslot = json_object_new_object();
|
||||
if (!jobj_keyslot)
|
||||
return -ENOMEM;
|
||||
|
||||
jobj_area = json_object_new_object();
|
||||
|
||||
if (params->data_shift) {
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("datashift"));
|
||||
json_object_object_add(jobj_area, "shift_size", json_object_new_uint64(params->data_shift << SECTOR_SHIFT));
|
||||
} else
|
||||
/* except data shift protection, initial setting is irrelevant. Type can be changed during reencryption */
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("none"));
|
||||
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_uint64(area_offset));
|
||||
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_length));
|
||||
|
||||
json_object_object_add(jobj_keyslot, "type", json_object_new_string("reencrypt"));
|
||||
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(1)); /* useless but mandatory */
|
||||
json_object_object_add(jobj_keyslot, "mode", json_object_new_string(params->mode));
|
||||
if (params->direction == CRYPT_REENCRYPT_FORWARD)
|
||||
json_object_object_add(jobj_keyslot, "direction", json_object_new_string("forward"));
|
||||
else if (params->direction == CRYPT_REENCRYPT_BACKWARD)
|
||||
json_object_object_add(jobj_keyslot, "direction", json_object_new_string("backward"));
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_add(jobj_keyslot, "area", jobj_area);
|
||||
|
||||
json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
|
||||
if (LUKS2_check_json_size(cd, hdr)) {
|
||||
log_dbg(cd, "New keyslot too large to fit in free metadata space.");
|
||||
json_object_object_del_by_uint(jobj_keyslots, keyslot);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
JSON_DBG(cd, hdr->jobj, "JSON:");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_store_data(struct crypt_device *cd,
|
||||
json_object *jobj_keyslot,
|
||||
const void *buffer, size_t buffer_len)
|
||||
{
|
||||
int devfd, r;
|
||||
json_object *jobj_area, *jobj_offset, *jobj_length;
|
||||
uint64_t area_offset, area_length;
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
|
||||
!json_object_object_get_ex(jobj_area, "offset", &jobj_offset) ||
|
||||
!json_object_object_get_ex(jobj_area, "size", &jobj_length))
|
||||
return -EINVAL;
|
||||
|
||||
area_offset = json_object_get_uint64(jobj_offset);
|
||||
area_length = json_object_get_uint64(jobj_length);
|
||||
|
||||
if (!area_offset || !area_length || ((uint64_t)buffer_len > area_length))
|
||||
return -EINVAL;
|
||||
|
||||
devfd = device_open_locked(cd, device, O_RDWR);
|
||||
if (devfd >= 0) {
|
||||
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), CONST_CAST(void *)buffer,
|
||||
buffer_len, area_offset) < 0)
|
||||
r = -EIO;
|
||||
else
|
||||
r = 0;
|
||||
} else
|
||||
r = -EINVAL;
|
||||
|
||||
if (r)
|
||||
log_err(cd, _("IO error while encrypting keyslot."));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_store(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *password __attribute__((unused)),
|
||||
size_t password_len __attribute__((unused)),
|
||||
const char *buffer,
|
||||
size_t buffer_len)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
json_object *jobj_keyslot;
|
||||
int r = 0;
|
||||
|
||||
if (!cd || !buffer || !buffer_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg(cd, "Reencrypt keyslot %d store.", keyslot);
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = reenc_keyslot_store_data(cd, jobj_keyslot, buffer, buffer_len);
|
||||
if (r < 0) {
|
||||
device_write_unlock(cd, crypt_metadata_device(cd));
|
||||
return r;
|
||||
}
|
||||
|
||||
r = LUKS2_hdr_write(cd, hdr);
|
||||
|
||||
device_write_unlock(cd, crypt_metadata_device(cd));
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
int reenc_keyslot_update(struct crypt_device *cd,
|
||||
const struct luks2_reenc_context *rh)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj_area, *jobj_area_type;
|
||||
struct luks2_hdr *hdr;
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, rh->reenc_keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_get_ex(jobj_keyslot, "area", &jobj_area);
|
||||
json_object_object_get_ex(jobj_area, "type", &jobj_area_type);
|
||||
|
||||
if (rh->rp.type == REENC_PROTECTION_CHECKSUM) {
|
||||
log_dbg(cd, "Updating reencrypt keyslot for checksum protection.");
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("checksum"));
|
||||
json_object_object_add(jobj_area, "hash", json_object_new_string(rh->rp.p.csum.hash));
|
||||
json_object_object_add(jobj_area, "sector_size", json_object_new_int64(rh->alignment));
|
||||
} else if (rh->rp.type == REENC_PROTECTION_NONE) {
|
||||
log_dbg(cd, "Updating reencrypt keyslot for none protection.");
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("none"));
|
||||
json_object_object_del(jobj_area, "hash");
|
||||
} else if (rh->rp.type == REENC_PROTECTION_JOURNAL) {
|
||||
log_dbg(cd, "Updating reencrypt keyslot for journal protection.");
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("journal"));
|
||||
json_object_object_del(jobj_area, "hash");
|
||||
} else
|
||||
log_dbg(cd, "No update of reencrypt keyslot needed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_wipe(struct crypt_device *cd, int keyslot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj_area, *jobj_direction, *jobj_mode, *jobj_resilience,
|
||||
*jobj1;
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "direction", &jobj_direction) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "mode", &jobj_mode) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
|
||||
!json_object_object_get_ex(jobj_area, "type", &jobj_resilience))
|
||||
return -EINVAL;
|
||||
|
||||
log_std(cd, "\t%-12s%s\n", "Mode:", json_object_get_string(jobj_mode));
|
||||
log_std(cd, "\t%-12s%s\n", "Direction:", json_object_get_string(jobj_direction));
|
||||
log_std(cd, "\t%-12s%s\n", "Resilience:", json_object_get_string(jobj_resilience));
|
||||
|
||||
if (!strcmp(json_object_get_string(jobj_resilience), "checksum")) {
|
||||
json_object_object_get_ex(jobj_area, "hash", &jobj1);
|
||||
log_std(cd, "\t%-12s%s\n", "Hash:", json_object_get_string(jobj1));
|
||||
json_object_object_get_ex(jobj_area, "sector_size", &jobj1);
|
||||
log_std(cd, "\t%-12s%d [bytes]\n", "Hash data:", json_object_get_int(jobj1));
|
||||
} else if (!strcmp(json_object_get_string(jobj_resilience), "datashift")) {
|
||||
json_object_object_get_ex(jobj_area, "shift_size", &jobj1);
|
||||
log_std(cd, "\t%-12s%" PRIu64 "[bytes]\n", "Shift size:", json_object_get_uint64(jobj1));
|
||||
}
|
||||
|
||||
json_object_object_get_ex(jobj_area, "offset", &jobj1);
|
||||
log_std(cd, "\tArea offset:%" PRIu64 " [bytes]\n", json_object_get_uint64(jobj1));
|
||||
|
||||
json_object_object_get_ex(jobj_area, "size", &jobj1);
|
||||
log_std(cd, "\tArea length:%" PRIu64 " [bytes]\n", json_object_get_uint64(jobj1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
|
||||
{
|
||||
json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size;
|
||||
const char *mode, *type;
|
||||
uint32_t sector_size;
|
||||
uint64_t shift_size;
|
||||
|
||||
/* mode (string: encrypt,reencrypt,decrypt)
|
||||
* direction (string:)
|
||||
* area {
|
||||
* type: (string: datashift, journal, checksum, none)
|
||||
* hash: (string: checksum only)
|
||||
* sector_size (uint32: checksum only)
|
||||
* shift_size (uint64: datashift only)
|
||||
* }
|
||||
*/
|
||||
|
||||
/* area and area type are validated in general validation code */
|
||||
if (!jobj_keyslot || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
|
||||
!json_object_object_get_ex(jobj_area, "type", &jobj_type))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_mode = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "mode", json_type_string);
|
||||
|
||||
if (!jobj_mode || !json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "direction", json_type_string))
|
||||
return -EINVAL;
|
||||
|
||||
mode = json_object_get_string(jobj_mode);
|
||||
type = json_object_get_string(jobj_type);
|
||||
|
||||
if (strcmp(mode, "reencrypt") && strcmp(mode, "encrypt") &&
|
||||
strcmp(mode, "decrypt")) {
|
||||
log_dbg(cd, "Illegal reencrypt mode %s.", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(type, "checksum")) {
|
||||
jobj_hash = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "hash", json_type_string);
|
||||
jobj_sector_size = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "sector_size", json_type_int);
|
||||
if (!jobj_hash || !jobj_sector_size)
|
||||
return -EINVAL;
|
||||
if (!validate_json_uint32(jobj_sector_size))
|
||||
return -EINVAL;
|
||||
sector_size = json_object_get_uint32(jobj_sector_size);
|
||||
if (sector_size < SECTOR_SIZE || NOTPOW2(sector_size)) {
|
||||
log_dbg(cd, "Invalid sector_size (%" PRIu32 ") for checksum resilience mode.", sector_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (!strcmp(type, "datashift")) {
|
||||
if (!(jobj_shift_size = json_contains(cd, jobj_area, "type:datashift", "Keyslot area", "shift_size", json_type_string)))
|
||||
return -EINVAL;
|
||||
|
||||
shift_size = json_object_get_uint64(jobj_shift_size);
|
||||
if (!shift_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (MISALIGNED_512(shift_size)) {
|
||||
log_dbg(cd, "Shift size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const keyslot_handler reenc_keyslot = {
|
||||
.name = "reencrypt",
|
||||
.open = reenc_keyslot_open,
|
||||
.store = reenc_keyslot_store, /* initialization only or also per every chunk write */
|
||||
.wipe = reenc_keyslot_wipe,
|
||||
.dump = reenc_keyslot_dump,
|
||||
.validate = reenc_keyslot_validate
|
||||
};
|
||||
@@ -24,6 +24,14 @@
|
||||
#include "../luks1/luks.h"
|
||||
#include "../luks1/af.h"
|
||||
|
||||
int LUKS2_check_cipher(struct crypt_device *cd,
|
||||
size_t keylength,
|
||||
const char *cipher,
|
||||
const char *cipher_mode)
|
||||
{
|
||||
return LUKS_check_cipher(cd, keylength, cipher, cipher_mode);
|
||||
}
|
||||
|
||||
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struct json_object **keyslot_object)
|
||||
{
|
||||
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
|
||||
@@ -200,7 +208,7 @@ static int json_luks1_segments(const struct luks_phdr *hdr_v1, struct json_objec
|
||||
json_object_put(segments_obj);
|
||||
return r;
|
||||
}
|
||||
json_object_object_add_by_uint(segments_obj, CRYPT_DEFAULT_SEGMENT, field);
|
||||
json_object_object_add_by_uint(segments_obj, 0, field);
|
||||
|
||||
*segments_object = segments_obj;
|
||||
return 0;
|
||||
@@ -419,9 +427,9 @@ static void move_keyslot_offset(json_object *jobj, int offset_add)
|
||||
static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
|
||||
off_t offset_to, size_t buf_size)
|
||||
{
|
||||
int devfd, r = -EIO;
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
void *buf = NULL;
|
||||
int r = -EIO, devfd = -1;
|
||||
|
||||
log_dbg(cd, "Moving keyslot areas of size %zu from %jd to %jd.",
|
||||
buf_size, (intmax_t)offset_from, (intmax_t)offset_to);
|
||||
@@ -430,7 +438,7 @@ static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
|
||||
return -ENOMEM;
|
||||
|
||||
devfd = device_open(cd, device, O_RDWR);
|
||||
if (devfd == -1) {
|
||||
if (devfd < 0) {
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -457,8 +465,7 @@ static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
device_sync(cd, device, devfd);
|
||||
close(devfd);
|
||||
device_sync(cd, device);
|
||||
crypt_memzero(buf, buf_size);
|
||||
free(buf);
|
||||
|
||||
@@ -479,16 +486,16 @@ static int luks_header_in_use(struct crypt_device *cd)
|
||||
/* Check if there is a luksmeta area (foreign metadata created by the luksmeta package) */
|
||||
static int luksmeta_header_present(struct crypt_device *cd, off_t luks1_size)
|
||||
{
|
||||
int devfd, r = 0;
|
||||
static const uint8_t LM_MAGIC[] = { 'L', 'U', 'K', 'S', 'M', 'E', 'T', 'A' };
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
void *buf = NULL;
|
||||
int devfd, r = 0;
|
||||
|
||||
if (posix_memalign(&buf, crypt_getpagesize(), sizeof(LM_MAGIC)))
|
||||
return -ENOMEM;
|
||||
|
||||
devfd = device_open(cd, device, O_RDONLY);
|
||||
if (devfd == -1) {
|
||||
if (devfd < 0) {
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -501,7 +508,6 @@ static int luksmeta_header_present(struct crypt_device *cd, off_t luks1_size)
|
||||
r = -EBUSY;
|
||||
}
|
||||
|
||||
close(devfd);
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
||||
@@ -665,6 +671,11 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
if (!jobj_segment)
|
||||
return -EINVAL;
|
||||
|
||||
if (json_segment_get_sector_size(jobj_segment) != SECTOR_SIZE) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - default segment encryption sector size is not 512 bytes."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
json_object_object_get_ex(hdr2->jobj, "digests", &jobj1);
|
||||
if (!json_object_object_get_ex(jobj_digest, "type", &jobj2) ||
|
||||
strcmp(json_object_get_string(jobj2), "pbkdf2") ||
|
||||
|
||||
3310
lib/luks2/luks2_reencrypt.c
Normal file
3310
lib/luks2/luks2_reencrypt.c
Normal file
File diff suppressed because it is too large
Load Diff
454
lib/luks2/luks2_segment.c
Normal file
454
lib/luks2/luks2_segment.c
Normal file
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, internal segment handling
|
||||
*
|
||||
* Copyright (C) 2018-2019, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018-2019, Ondrej Kozina
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "luks2_internal.h"
|
||||
|
||||
json_object *json_get_segments_jobj(json_object *hdr_jobj)
|
||||
{
|
||||
json_object *jobj_segments;
|
||||
|
||||
if (!hdr_jobj || !json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
|
||||
return NULL;
|
||||
|
||||
return jobj_segments;
|
||||
}
|
||||
|
||||
/* use only on already validated 'segments' object */
|
||||
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise)
|
||||
{
|
||||
uint64_t tmp, min = blockwise ? UINT64_MAX >> SECTOR_SHIFT : UINT64_MAX;
|
||||
|
||||
if (!jobj_segments)
|
||||
return 0;
|
||||
|
||||
json_object_object_foreach(jobj_segments, key, val) {
|
||||
UNUSED(key);
|
||||
|
||||
if (json_segment_is_backup(val))
|
||||
continue;
|
||||
|
||||
tmp = json_segment_get_offset(val, blockwise);
|
||||
|
||||
if (!tmp)
|
||||
return tmp;
|
||||
|
||||
if (tmp < min)
|
||||
min = tmp;
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
if (!jobj_segment ||
|
||||
!json_object_object_get_ex(jobj_segment, "offset", &jobj))
|
||||
return 0;
|
||||
|
||||
return blockwise ? json_object_get_uint64(jobj) >> SECTOR_SHIFT : json_object_get_uint64(jobj);
|
||||
}
|
||||
|
||||
const char *json_segment_type(json_object *jobj_segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
if (!jobj_segment ||
|
||||
!json_object_object_get_ex(jobj_segment, "type", &jobj))
|
||||
return NULL;
|
||||
|
||||
return json_object_get_string(jobj);
|
||||
}
|
||||
|
||||
uint64_t json_segment_get_iv_offset(json_object *jobj_segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
if (!jobj_segment ||
|
||||
!json_object_object_get_ex(jobj_segment, "iv_tweak", &jobj))
|
||||
return 0;
|
||||
|
||||
return json_object_get_uint64(jobj);
|
||||
}
|
||||
|
||||
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
if (!jobj_segment ||
|
||||
!json_object_object_get_ex(jobj_segment, "size", &jobj))
|
||||
return 0;
|
||||
|
||||
return blockwise ? json_object_get_uint64(jobj) >> SECTOR_SHIFT : json_object_get_uint64(jobj);
|
||||
}
|
||||
|
||||
const char *json_segment_get_cipher(json_object *jobj_segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
/* FIXME: Pseudo "null" cipher should be handled elsewhere */
|
||||
if (!jobj_segment ||
|
||||
!json_object_object_get_ex(jobj_segment, "encryption", &jobj))
|
||||
return "null";
|
||||
|
||||
return json_object_get_string(jobj);
|
||||
}
|
||||
|
||||
int json_segment_get_sector_size(json_object *jobj_segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
if (!jobj_segment ||
|
||||
!json_object_object_get_ex(jobj_segment, "sector_size", &jobj))
|
||||
return -1;
|
||||
|
||||
return json_object_get_int(jobj);
|
||||
}
|
||||
|
||||
json_object *json_segment_get_flags(json_object *jobj_segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
|
||||
if (!jobj_segment || !(json_object_object_get_ex(jobj_segment, "flags", &jobj)))
|
||||
return NULL;
|
||||
return jobj;
|
||||
}
|
||||
|
||||
static bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
|
||||
{
|
||||
int r, i;
|
||||
json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment);
|
||||
|
||||
if (!jobj_flags)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < (int)json_object_array_length(jobj_flags); i++) {
|
||||
jobj = json_object_array_get_idx(jobj_flags, i);
|
||||
if (len)
|
||||
r = strncmp(json_object_get_string(jobj), flag_str, len);
|
||||
else
|
||||
r = strcmp(json_object_get_string(jobj), flag_str);
|
||||
if (!r)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_segment_is_backup(json_object *jobj_segment)
|
||||
{
|
||||
return json_segment_contains_flag(jobj_segment, "backup-", 7);
|
||||
}
|
||||
|
||||
bool json_segment_is_reencrypt(json_object *jobj_segment)
|
||||
{
|
||||
return json_segment_contains_flag(jobj_segment, "in-reencryption", 0);
|
||||
}
|
||||
|
||||
json_object *json_segments_get_segment(json_object *jobj_segments, int segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
char segment_name[16];
|
||||
|
||||
if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)
|
||||
return NULL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_segments, segment_name, &jobj))
|
||||
return NULL;
|
||||
|
||||
return jobj;
|
||||
}
|
||||
|
||||
int json_segments_count(json_object *jobj_segments)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (!jobj_segments)
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
UNUSED(slot);
|
||||
if (!json_segment_is_backup(val))
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void _get_segment_or_id_by_flag(json_object *jobj_segments, const char *flag, unsigned id, void *retval)
|
||||
{
|
||||
json_object *jobj_flags, **jobj_ret = (json_object **)retval;
|
||||
int *ret = (int *)retval;
|
||||
|
||||
if (!flag)
|
||||
return;
|
||||
|
||||
json_object_object_foreach(jobj_segments, key, value) {
|
||||
if (!json_object_object_get_ex(value, "flags", &jobj_flags))
|
||||
continue;
|
||||
if (LUKS2_array_jobj(jobj_flags, flag)) {
|
||||
if (id)
|
||||
*ret = atoi(key);
|
||||
else
|
||||
*jobj_ret = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
json_object *json_segments_get_segment_by_flag(json_object *jobj_segments, const char *flag)
|
||||
{
|
||||
json_object *jobj_segment = NULL;
|
||||
|
||||
if (jobj_segments)
|
||||
_get_segment_or_id_by_flag(jobj_segments, flag, 0, &jobj_segment);
|
||||
|
||||
return jobj_segment;
|
||||
}
|
||||
|
||||
void json_segment_remove_flag(json_object *jobj_segment, const char *flag)
|
||||
{
|
||||
json_object *jobj_flags, *jobj_flags_new;
|
||||
|
||||
if (!jobj_segment)
|
||||
return;
|
||||
|
||||
jobj_flags = json_segment_get_flags(jobj_segment);
|
||||
if (!jobj_flags)
|
||||
return;
|
||||
|
||||
jobj_flags_new = LUKS2_array_remove(jobj_flags, flag);
|
||||
if (!jobj_flags_new)
|
||||
return;
|
||||
|
||||
if (json_object_array_length(jobj_flags_new) <= 0) {
|
||||
json_object_put(jobj_flags_new);
|
||||
json_object_object_del(jobj_segment, "flags");
|
||||
} else
|
||||
json_object_object_add(jobj_segment, "flags", jobj_flags_new);
|
||||
}
|
||||
|
||||
static json_object *_segment_create_generic(const char *type, uint64_t offset, const uint64_t *length)
|
||||
{
|
||||
json_object *jobj = json_object_new_object();
|
||||
if (!jobj)
|
||||
return NULL;
|
||||
|
||||
json_object_object_add(jobj, "type", json_object_new_string(type));
|
||||
json_object_object_add(jobj, "offset", json_object_new_uint64(offset));
|
||||
json_object_object_add(jobj, "size", length ? json_object_new_uint64(*length) : json_object_new_string("dynamic"));
|
||||
|
||||
return jobj;
|
||||
}
|
||||
|
||||
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption)
|
||||
{
|
||||
json_object *jobj = _segment_create_generic("linear", offset, length);
|
||||
if (reencryption)
|
||||
LUKS2_segment_set_flag(jobj, "in-reencryption");
|
||||
return jobj;
|
||||
}
|
||||
|
||||
json_object *json_segment_create_crypt(uint64_t offset,
|
||||
uint64_t iv_offset, const uint64_t *length,
|
||||
const char *cipher, uint32_t sector_size,
|
||||
unsigned reencryption)
|
||||
{
|
||||
json_object *jobj = _segment_create_generic("crypt", offset, length);
|
||||
if (!jobj)
|
||||
return NULL;
|
||||
|
||||
json_object_object_add(jobj, "iv_tweak", json_object_new_uint64(iv_offset));
|
||||
json_object_object_add(jobj, "encryption", json_object_new_string(cipher));
|
||||
json_object_object_add(jobj, "sector_size", json_object_new_int(sector_size));
|
||||
if (reencryption)
|
||||
LUKS2_segment_set_flag(jobj, "in-reencryption");
|
||||
|
||||
return jobj;
|
||||
}
|
||||
|
||||
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr, int segment, unsigned blockwise)
|
||||
{
|
||||
return json_segment_get_offset(LUKS2_get_segment_jobj(hdr, segment), blockwise);
|
||||
}
|
||||
|
||||
int json_segments_segment_in_reencrypt(json_object *jobj_segments)
|
||||
{
|
||||
json_object *jobj_flags;
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
if (!json_object_object_get_ex(val, "flags", &jobj_flags) ||
|
||||
!LUKS2_array_jobj(jobj_flags, "in-reencryption"))
|
||||
continue;
|
||||
|
||||
return atoi(slot);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t LUKS2_segment_size(struct luks2_hdr *hdr, int segment, unsigned blockwise)
|
||||
{
|
||||
return json_segment_get_size(LUKS2_get_segment_jobj(hdr, segment), blockwise);
|
||||
}
|
||||
|
||||
int LUKS2_segment_is_type(struct luks2_hdr *hdr, int segment, const char *type)
|
||||
{
|
||||
return !strcmp(json_segment_type(LUKS2_get_segment_jobj(hdr, segment)) ?: "", type);
|
||||
}
|
||||
|
||||
int LUKS2_last_segment_by_type(struct luks2_hdr *hdr, const char *type)
|
||||
{
|
||||
json_object *jobj_segments;
|
||||
int last_found = -1;
|
||||
|
||||
if (!type)
|
||||
return -1;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
|
||||
return -1;
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
if (json_segment_is_backup(val))
|
||||
continue;
|
||||
if (strcmp(type, json_segment_type(val) ?: ""))
|
||||
continue;
|
||||
|
||||
if (atoi(slot) > last_found)
|
||||
last_found = atoi(slot);
|
||||
}
|
||||
|
||||
return last_found;
|
||||
}
|
||||
|
||||
int LUKS2_segment_by_type(struct luks2_hdr *hdr, const char *type)
|
||||
{
|
||||
json_object *jobj_segments;
|
||||
int first_found = -1;
|
||||
|
||||
if (!type)
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
if (json_segment_is_backup(val))
|
||||
continue;
|
||||
if (strcmp(type, json_segment_type(val) ?: ""))
|
||||
continue;
|
||||
|
||||
if (first_found < 0)
|
||||
first_found = atoi(slot);
|
||||
else if (atoi(slot) < first_found)
|
||||
first_found = atoi(slot);
|
||||
}
|
||||
|
||||
return first_found;
|
||||
}
|
||||
|
||||
int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr)
|
||||
{
|
||||
json_object *jobj_segments;
|
||||
int id, last_id = -1;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
UNUSED(val);
|
||||
id = atoi(slot);
|
||||
if (id > last_id)
|
||||
last_id = id;
|
||||
}
|
||||
|
||||
return last_id + 1;
|
||||
}
|
||||
|
||||
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag)
|
||||
{
|
||||
json_object *jobj_flags;
|
||||
|
||||
if (!jobj_segment || !flag)
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_segment, "flags", &jobj_flags)) {
|
||||
jobj_flags = json_object_new_array();
|
||||
if (!jobj_flags)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_segment, "flags", jobj_flags);
|
||||
}
|
||||
|
||||
if (LUKS2_array_jobj(jobj_flags, flag))
|
||||
return 0;
|
||||
|
||||
json_object_array_add(jobj_flags, json_object_new_string(flag));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_segments_set(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
json_object *jobj_segments, int commit)
|
||||
{
|
||||
json_object_object_add(hdr->jobj, "segments", jobj_segments);
|
||||
|
||||
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
|
||||
}
|
||||
|
||||
int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag)
|
||||
{
|
||||
int ret = -ENOENT;
|
||||
json_object *jobj_segments = LUKS2_get_segments_jobj(hdr);
|
||||
|
||||
if (jobj_segments)
|
||||
_get_segment_or_id_by_flag(jobj_segments, flag, 1, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)
|
||||
{
|
||||
json_object *jobj_segment = NULL,
|
||||
*jobj_segments = LUKS2_get_segments_jobj(hdr);
|
||||
|
||||
if (jobj_segments)
|
||||
_get_segment_or_id_by_flag(jobj_segments, flag, 0, &jobj_segment);
|
||||
|
||||
return jobj_segment;
|
||||
}
|
||||
|
||||
json_object *LUKS2_get_ignored_segments(struct luks2_hdr *hdr)
|
||||
{
|
||||
json_object *jobj_segments, *jobj = json_object_new_object();
|
||||
int i = 0;
|
||||
|
||||
if (!jobj || !json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
|
||||
return NULL;
|
||||
|
||||
json_object_object_foreach(jobj_segments, key, value) {
|
||||
UNUSED(key);
|
||||
if (json_segment_is_backup(value))
|
||||
json_object_object_add_by_uint(jobj, i++, json_object_get(value));
|
||||
}
|
||||
|
||||
return jobj;
|
||||
}
|
||||
@@ -347,7 +347,7 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
|
||||
{
|
||||
const crypt_token_handler *h;
|
||||
json_object *jobj_token, *jobj_token_keyslots, *jobj;
|
||||
const char *num = NULL;
|
||||
unsigned int num = 0;
|
||||
int i, r;
|
||||
|
||||
if (!(h = LUKS2_token_handler(cd, token)))
|
||||
@@ -365,15 +365,15 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
|
||||
r = -EINVAL;
|
||||
for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots) && r < 0; i++) {
|
||||
jobj = json_object_array_get_idx(jobj_token_keyslots, i);
|
||||
num = json_object_get_string(jobj);
|
||||
log_dbg(cd, "Trying to open keyslot %s with token %d (type %s).", num, token, h->name);
|
||||
r = LUKS2_keyslot_open(cd, atoi(num), segment, buffer, buffer_len, vk);
|
||||
num = atoi(json_object_get_string(jobj));
|
||||
log_dbg(cd, "Trying to open keyslot %u with token %d (type %s).", num, token, h->name);
|
||||
r = LUKS2_keyslot_open(cd, num, segment, buffer, buffer_len, vk);
|
||||
}
|
||||
|
||||
if (r >= 0 && num)
|
||||
return atoi(num);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return r;
|
||||
return num;
|
||||
}
|
||||
|
||||
int LUKS2_token_open_and_activate(struct crypt_device *cd,
|
||||
@@ -404,14 +404,16 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
|
||||
|
||||
keyslot = r;
|
||||
|
||||
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
|
||||
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot);
|
||||
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) {
|
||||
if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot)))
|
||||
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
|
||||
}
|
||||
|
||||
if (r >= 0 && name)
|
||||
r = LUKS2_activate(cd, name, vk, flags);
|
||||
|
||||
if (r < 0 && vk)
|
||||
crypt_drop_keyring_key(cd, vk->key_description);
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, vk);
|
||||
crypt_free_volume_key(vk);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
@@ -449,14 +451,16 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
|
||||
|
||||
keyslot = r;
|
||||
|
||||
if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
|
||||
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot);
|
||||
if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) {
|
||||
if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot)))
|
||||
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
|
||||
}
|
||||
|
||||
if (r >= 0 && name)
|
||||
r = LUKS2_activate(cd, name, vk, flags);
|
||||
|
||||
if (r < 0 && vk)
|
||||
crypt_drop_keyring_key(cd, vk->key_description);
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, vk);
|
||||
crypt_free_volume_key(vk);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
|
||||
519
lib/setup.c
519
lib/setup.c
@@ -36,6 +36,7 @@
|
||||
#include "verity.h"
|
||||
#include "tcrypt.h"
|
||||
#include "integrity.h"
|
||||
#include "utils_device_locking.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define CRYPT_CD_UNRESTRICTED (1 << 0)
|
||||
@@ -58,6 +59,10 @@ struct crypt_device {
|
||||
uint64_t metadata_size; /* Used in LUKS2 format */
|
||||
uint64_t keyslots_size; /* Used in LUKS2 format */
|
||||
|
||||
/* Workaround for OOM during parallel activation (like in systemd) */
|
||||
bool memory_hard_pbkdf_lock_enabled;
|
||||
struct crypt_lock_handle *pbkdf_memory_hard_lock;
|
||||
|
||||
// FIXME: private binary headers and access it properly
|
||||
// through sub-library (LUKS1, TCRYPT)
|
||||
|
||||
@@ -72,6 +77,7 @@ struct crypt_device {
|
||||
char cipher_mode[MAX_CIPHER_LEN]; /* only for compatibility */
|
||||
char *keyslot_cipher;
|
||||
unsigned int keyslot_key_size;
|
||||
struct luks2_reenc_context *rh;
|
||||
} luks2;
|
||||
struct { /* used in CRYPT_PLAIN */
|
||||
struct crypt_params_plain hdr;
|
||||
@@ -169,12 +175,15 @@ void logger(struct crypt_device *cd, int level, const char *file,
|
||||
{
|
||||
va_list argp;
|
||||
char target[LOG_MAX_LEN + 2];
|
||||
int len;
|
||||
|
||||
va_start(argp, format);
|
||||
|
||||
if (vsnprintf(&target[0], LOG_MAX_LEN, format, argp) > 0 ) {
|
||||
len = vsnprintf(&target[0], LOG_MAX_LEN, format, argp);
|
||||
if (len > 0 && len < LOG_MAX_LEN) {
|
||||
/* All verbose and error messages in tools end with EOL. */
|
||||
if (level == CRYPT_LOG_VERBOSE || level == CRYPT_LOG_ERROR)
|
||||
if (level == CRYPT_LOG_VERBOSE || level == CRYPT_LOG_ERROR ||
|
||||
level == CRYPT_LOG_DEBUG || level == CRYPT_LOG_DEBUG_JSON)
|
||||
strncat(target, "\n", LOG_MAX_LEN);
|
||||
|
||||
crypt_log(cd, level, target);
|
||||
@@ -333,7 +342,7 @@ static int onlyLUKS(struct crypt_device *cd)
|
||||
return _onlyLUKS(cd, 0);
|
||||
}
|
||||
|
||||
static int _onlyLUKS2(struct crypt_device *cd, uint32_t cdflags)
|
||||
static int _onlyLUKS2(struct crypt_device *cd, uint32_t cdflags, uint32_t mask)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
@@ -352,12 +361,19 @@ static int _onlyLUKS2(struct crypt_device *cd, uint32_t cdflags)
|
||||
if (r || (cdflags & CRYPT_CD_UNRESTRICTED))
|
||||
return r;
|
||||
|
||||
return LUKS2_unmet_requirements(cd, &cd->u.luks2.hdr, 0, cdflags & CRYPT_CD_QUIET);
|
||||
return LUKS2_unmet_requirements(cd, &cd->u.luks2.hdr, mask, cdflags & CRYPT_CD_QUIET);
|
||||
}
|
||||
|
||||
static int onlyLUKS2(struct crypt_device *cd)
|
||||
/* Internal only */
|
||||
int onlyLUKS2(struct crypt_device *cd)
|
||||
{
|
||||
return _onlyLUKS2(cd, 0);
|
||||
return _onlyLUKS2(cd, 0, 0);
|
||||
}
|
||||
|
||||
/* Internal only */
|
||||
int onlyLUKS2mask(struct crypt_device *cd, uint32_t mask)
|
||||
{
|
||||
return _onlyLUKS2(cd, 0, mask);
|
||||
}
|
||||
|
||||
static void crypt_set_null_type(struct crypt_device *cd)
|
||||
@@ -391,7 +407,7 @@ static int keyslot_verify_or_find_empty(struct crypt_device *cd, int *keyslot)
|
||||
if (isLUKS1(cd->type))
|
||||
*keyslot = LUKS_keyslot_find_empty(&cd->u.luks1.hdr);
|
||||
else
|
||||
*keyslot = LUKS2_keyslot_find_empty(&cd->u.luks2.hdr, "luks2");
|
||||
*keyslot = LUKS2_keyslot_find_empty(&cd->u.luks2.hdr);
|
||||
if (*keyslot < 0) {
|
||||
log_err(cd, _("All key slots full."));
|
||||
return -EINVAL;
|
||||
@@ -422,7 +438,7 @@ static int keyslot_verify_or_find_empty(struct crypt_device *cd, int *keyslot)
|
||||
/*
|
||||
* compares UUIDs returned by device-mapper (striped by cryptsetup) and uuid in header
|
||||
*/
|
||||
static int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid)
|
||||
int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid)
|
||||
{
|
||||
int i, j;
|
||||
char *str;
|
||||
@@ -624,7 +640,12 @@ int crypt_set_data_device(struct crypt_device *cd, const char *device)
|
||||
if (!isLUKS1(cd->type) && !isLUKS2(cd->type) && !isVERITY(cd->type) &&
|
||||
!isINTEGRITY(cd->type)) {
|
||||
log_err(cd, _("This operation is not supported for this device type."));
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (isLUKS2(cd->type) && crypt_get_reenc_context(cd)) {
|
||||
log_err(cd, _("Illegal operation with reencryption in-progress."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return _crypt_set_data_device(cd, device);
|
||||
@@ -643,8 +664,10 @@ int crypt_init_data_device(struct crypt_device **cd, const char *device, const c
|
||||
|
||||
log_dbg(NULL, "Setting ciphertext data device to %s.", data_device ?: "(none)");
|
||||
r = _crypt_set_data_device(*cd, data_device);
|
||||
if (r)
|
||||
if (r) {
|
||||
crypt_free(*cd);
|
||||
*cd = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -682,14 +705,16 @@ static int _crypt_load_luks2(struct crypt_device *cd, int reload, int repair)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (reload)
|
||||
if (reload) {
|
||||
LUKS2_hdr_free(cd, &cd->u.luks2.hdr);
|
||||
else
|
||||
free(cd->u.luks2.keyslot_cipher);
|
||||
} else
|
||||
cd->type = type;
|
||||
|
||||
r = 0;
|
||||
memcpy(&cd->u.luks2.hdr, &hdr2, sizeof(hdr2));
|
||||
cd->u.luks2.keyslot_cipher = NULL;
|
||||
cd->u.luks2.rh = NULL;
|
||||
|
||||
out:
|
||||
if (r) {
|
||||
@@ -1041,6 +1066,7 @@ static void crypt_free_type(struct crypt_device *cd)
|
||||
free(cd->u.plain.cipher);
|
||||
free(cd->u.plain.cipher_spec);
|
||||
} else if (isLUKS2(cd->type)) {
|
||||
LUKS2_reenc_context_free(cd, cd->u.luks2.rh);
|
||||
LUKS2_hdr_free(cd, &cd->u.luks2.hdr);
|
||||
free(cd->u.luks2.keyslot_cipher);
|
||||
} else if (isLUKS1(cd->type)) {
|
||||
@@ -1088,20 +1114,21 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!single_segment(&dmd) || tgt->type != DM_CRYPT) {
|
||||
/* TODO: segment count */
|
||||
if (!(tgt->type == DM_CRYPT || tgt->type == DM_LINEAR)) {
|
||||
log_dbg(cd, "Unsupported device table detected in %s.", name);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = crypt_parse_name_and_mode(tgt->u.crypt.cipher, cipher,
|
||||
r = crypt_parse_name_and_mode(tgt->type == DM_LINEAR ? "null" : tgt->u.crypt.cipher, cipher,
|
||||
&key_nums, cipher_mode);
|
||||
if (r < 0) {
|
||||
log_dbg(cd, "Cannot parse cipher and mode from active device.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tgt->u.crypt.integrity && (namei = device_dm_name(tgt->data_device))) {
|
||||
if (tgt->type == DM_CRYPT && tgt->u.crypt.integrity && (namei = device_dm_name(tgt->data_device))) {
|
||||
r = dm_query_device(cd, namei, DM_ACTIVE_DEVICE, &dmdi);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
@@ -1146,6 +1173,8 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
|
||||
if (r < 0) {
|
||||
log_dbg(cd, "LUKS device header does not match active device.");
|
||||
crypt_set_null_type(cd);
|
||||
device_close(cd, cd->metadata_device);
|
||||
device_close(cd, cd->device);
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
@@ -1292,11 +1321,13 @@ int crypt_init_by_name_and_header(struct crypt_device **cd,
|
||||
r = dm_query_device(NULL, name, DM_ACTIVE_DEVICE | DM_ACTIVE_UUID, &dmd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!single_segment(&dmd)) {
|
||||
/* TODO: segment count */
|
||||
/*
|
||||
if (dmd.segment_count > 4) {
|
||||
log_dbg(NULL, "Unsupported device table detected in %s.", name);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}*/
|
||||
|
||||
*cd = NULL;
|
||||
|
||||
@@ -1346,7 +1377,7 @@ int crypt_init_by_name_and_header(struct crypt_device **cd,
|
||||
|
||||
/* Try to initialise basic parameters from active device */
|
||||
|
||||
if (tgt->type == DM_CRYPT)
|
||||
if (tgt->type == DM_CRYPT || tgt->type == DM_LINEAR)
|
||||
r = _init_by_name_crypt(*cd, name);
|
||||
else if (tgt->type == DM_VERITY)
|
||||
r = _init_by_name_verity(*cd, name);
|
||||
@@ -1680,7 +1711,7 @@ static int _crypt_format_luks2(struct crypt_device *cd,
|
||||
|
||||
/* FIXME: allow this later also for normal ciphers (check AF_ALG availability. */
|
||||
if (integrity && !integrity_key_size) {
|
||||
r = crypt_cipher_check(cipher, cipher_mode, integrity, volume_key_size);
|
||||
r = crypt_cipher_check_kernel(cipher, cipher_mode, integrity, volume_key_size);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Cipher %s-%s (key size %zd bits) is not available."),
|
||||
cipher, cipher_mode, volume_key_size * 8);
|
||||
@@ -1766,7 +1797,8 @@ static int _crypt_format_luks2(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = LUKS2_hdr_write(cd, &cd->u.luks2.hdr);
|
||||
/* override sequence id check with format */
|
||||
r = LUKS2_hdr_write_force(cd, &cd->u.luks2.hdr);
|
||||
if (r < 0) {
|
||||
if (r == -EBUSY)
|
||||
log_err(cd, _("Cannot format device %s in use."),
|
||||
@@ -2434,7 +2466,7 @@ static int _reload_device(struct crypt_device *cd, const char *name,
|
||||
tdmd.flags = sdmd->flags;
|
||||
tgt->size = tdmd.size = sdmd->size;
|
||||
|
||||
r = dm_reload_device(cd, name, &tdmd, 1);
|
||||
r = dm_reload_device(cd, name, &tdmd, 0, 1);
|
||||
out:
|
||||
dm_targets_free(cd, &tdmd);
|
||||
free(CONST_CAST(void*)tdmd.uuid);
|
||||
@@ -2506,7 +2538,7 @@ static int _reload_device_with_integrity(struct crypt_device *cd,
|
||||
|
||||
r = _compare_dm_devices(cd, sdmd, &tdmd);
|
||||
if (r) {
|
||||
log_err(cd, "Crypt devices mismatch.");
|
||||
log_err(cd, _("Crypt devices mismatch."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2542,32 +2574,32 @@ static int _reload_device_with_integrity(struct crypt_device *cd,
|
||||
tdmd.flags = sdmd->flags;
|
||||
tdmd.size = sdmd->size;
|
||||
|
||||
if ((r = dm_reload_device(cd, iname, sdmdi, 0))) {
|
||||
if ((r = dm_reload_device(cd, iname, sdmdi, 0, 0))) {
|
||||
log_dbg(cd, "Failed to reload device %s.", iname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((r = dm_reload_device(cd, name, &tdmd, 0))) {
|
||||
if ((r = dm_reload_device(cd, name, &tdmd, 0, 0))) {
|
||||
log_dbg(cd, "Failed to reload device %s.", name);
|
||||
goto err_clear;
|
||||
}
|
||||
|
||||
if ((r = dm_suspend_device(cd, name))) {
|
||||
if ((r = dm_suspend_device(cd, name, 0))) {
|
||||
log_dbg(cd, "Failed to suspend device %s.", name);
|
||||
goto err_clear;
|
||||
}
|
||||
|
||||
if ((r = dm_suspend_device(cd, iname))) {
|
||||
log_err(cd, "Failed to suspend device %s.", iname);
|
||||
if ((r = dm_suspend_device(cd, iname, 0))) {
|
||||
log_err(cd, _("Failed to suspend device %s."), iname);
|
||||
goto err_clear;
|
||||
}
|
||||
|
||||
if ((r = dm_resume_device(cd, iname, sdmdi->flags))) {
|
||||
log_err(cd, "Failed to resume device %s.", iname);
|
||||
if ((r = dm_resume_device(cd, iname, act2dmflags(sdmdi->flags)))) {
|
||||
log_err(cd, _("Failed to resume device %s."), iname);
|
||||
goto err_clear;
|
||||
}
|
||||
|
||||
r = dm_resume_device(cd, name, tdmd.flags);
|
||||
r = dm_resume_device(cd, name, act2dmflags(tdmd.flags));
|
||||
if (!r)
|
||||
goto out;
|
||||
|
||||
@@ -2577,12 +2609,12 @@ static int _reload_device_with_integrity(struct crypt_device *cd,
|
||||
* burn it for good.
|
||||
*/
|
||||
|
||||
log_err(cd, "Fatal error while reloading device %s (on top of device %s).", name, iname);
|
||||
log_err(cd, _("Fatal error while reloading device %s (on top of device %s)."), name, iname);
|
||||
|
||||
if (dm_error_device(cd, name))
|
||||
log_err(cd, "Failed to switch device %s to dm-error.", name);
|
||||
log_err(cd, _("Failed to switch device %s to dm-error."), name);
|
||||
if (dm_error_device(cd, iname))
|
||||
log_err(cd, "Failed to switch device %s to dm-error.", iname);
|
||||
log_err(cd, _("Failed to switch device %s to dm-error."), iname);
|
||||
goto out;
|
||||
|
||||
err_clear:
|
||||
@@ -2842,7 +2874,6 @@ void crypt_free(struct crypt_device *cd)
|
||||
|
||||
free(CONST_CAST(void*)cd->pbkdf.type);
|
||||
free(CONST_CAST(void*)cd->pbkdf.hash);
|
||||
|
||||
crypt_free_type(cd);
|
||||
|
||||
/* Some structures can contain keys (TCRYPT), wipe it */
|
||||
@@ -2874,6 +2905,7 @@ int crypt_suspend(struct crypt_device *cd,
|
||||
char *key_desc;
|
||||
crypt_status_info ci;
|
||||
int r;
|
||||
uint32_t dmflags = DM_SUSPEND_WIPE_KEY;
|
||||
|
||||
/* FIXME: check context uuid matches the dm-crypt device uuid (onlyLUKS branching) */
|
||||
|
||||
@@ -2917,16 +2949,15 @@ int crypt_suspend(struct crypt_device *cd,
|
||||
|
||||
/* we can't simply wipe wrapped keys */
|
||||
if (crypt_cipher_wrapped_key(crypt_get_cipher(cd), crypt_get_cipher_mode(cd)))
|
||||
r = dm_suspend_device(cd, name);
|
||||
else
|
||||
r = dm_suspend_and_wipe_key(cd, name);
|
||||
dmflags &= ~DM_SUSPEND_WIPE_KEY;
|
||||
|
||||
r = dm_suspend_device(cd, name, dmflags);
|
||||
if (r == -ENOTSUP)
|
||||
log_err(cd, _("Suspend is not supported for device %s."), name);
|
||||
else if (r)
|
||||
log_err(cd, _("Error during suspending device %s."), name);
|
||||
else
|
||||
crypt_drop_keyring_key(cd, key_desc);
|
||||
crypt_drop_keyring_key_by_description(cd, key_desc, LOGON_KEY);
|
||||
free(key_desc);
|
||||
out:
|
||||
dm_backend_exit(cd);
|
||||
@@ -2990,8 +3021,8 @@ int crypt_resume_by_passphrase(struct crypt_device *cd,
|
||||
else if (r)
|
||||
log_err(cd, _("Error during resuming device %s."), name);
|
||||
out:
|
||||
if (r < 0 && vk)
|
||||
crypt_drop_keyring_key(cd, vk->key_description);
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, vk);
|
||||
crypt_free_volume_key(vk);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
@@ -3059,8 +3090,8 @@ int crypt_resume_by_keyfile_device_offset(struct crypt_device *cd,
|
||||
log_err(cd, _("Error during resuming device %s."), name);
|
||||
out:
|
||||
crypt_safe_free(passphrase_read);
|
||||
if (r < 0 && vk)
|
||||
crypt_drop_keyring_key(cd, vk->key_description);
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, vk);
|
||||
crypt_free_volume_key(vk);
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
@@ -3221,7 +3252,7 @@ int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
|
||||
if (isLUKS1(cd->type))
|
||||
keyslot_new = LUKS_keyslot_find_empty(&cd->u.luks1.hdr);
|
||||
else if (isLUKS2(cd->type))
|
||||
keyslot_new = LUKS2_keyslot_find_empty(&cd->u.luks2.hdr, "luks2"); // FIXME
|
||||
keyslot_new = LUKS2_keyslot_find_empty(&cd->u.luks2.hdr);
|
||||
if (keyslot_new < 0)
|
||||
keyslot_new = keyslot_old;
|
||||
}
|
||||
@@ -3616,9 +3647,222 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks)
|
||||
{
|
||||
int r;
|
||||
struct volume_key *vk = vks;
|
||||
|
||||
while (vk) {
|
||||
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk));
|
||||
if (r < 0)
|
||||
return r;
|
||||
vk = vk->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* See fixmes in _open_and_activate_luks2 */
|
||||
int update_reencryption_flag(struct crypt_device *cd, int enable, bool commit);
|
||||
|
||||
/* TODO: This function should 1:1 with pre-reencryption code */
|
||||
static int _open_and_activate(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *name,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
uint32_t flags)
|
||||
{
|
||||
int r;
|
||||
struct volume_key *vk = NULL;
|
||||
|
||||
r = LUKS2_keyslot_open(cd, keyslot,
|
||||
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ?
|
||||
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
|
||||
passphrase, passphrase_size, &vk);
|
||||
if (r < 0)
|
||||
return r;
|
||||
keyslot = r;
|
||||
|
||||
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) &&
|
||||
crypt_use_keyring_for_vk(cd)) {
|
||||
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd,
|
||||
&cd->u.luks2.hdr, vk, keyslot);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
|
||||
}
|
||||
|
||||
if (name)
|
||||
r = LUKS2_activate(cd, name, vk, flags);
|
||||
out:
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, vk);
|
||||
crypt_free_volume_key(vk);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
static int _open_all_keys(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
uint32_t flags,
|
||||
struct volume_key **vks)
|
||||
{
|
||||
int r, segment;
|
||||
struct volume_key *_vks = NULL;
|
||||
crypt_reencrypt_info ri = LUKS2_reenc_status(hdr);
|
||||
|
||||
segment = (flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ? CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT;
|
||||
|
||||
switch (ri) {
|
||||
case CRYPT_REENCRYPT_NONE:
|
||||
r = LUKS2_keyslot_open(cd, keyslot, segment, passphrase, passphrase_size, &_vks);
|
||||
break;
|
||||
case CRYPT_REENCRYPT_CLEAN:
|
||||
case CRYPT_REENCRYPT_CRASH:
|
||||
if (segment == CRYPT_ANY_SEGMENT)
|
||||
r = LUKS2_keyslot_open(cd, keyslot, segment, passphrase,
|
||||
passphrase_size, &_vks);
|
||||
else
|
||||
r = LUKS2_keyslot_open_all_segments(cd, keyslot,
|
||||
keyslot, passphrase, passphrase_size,
|
||||
&_vks);
|
||||
break;
|
||||
default:
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (keyslot == CRYPT_ANY_SLOT)
|
||||
keyslot = r;
|
||||
|
||||
if (r >= 0 && (flags & CRYPT_ACTIVATE_KEYRING_KEY))
|
||||
r = load_all_keys(cd, hdr, _vks);
|
||||
|
||||
if (r >= 0 && vks)
|
||||
MOVE_REF(*vks, _vks);
|
||||
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, _vks);
|
||||
crypt_free_volume_key(_vks);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
static int _open_and_activate_reencrypt_device(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const char *name,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
uint32_t flags)
|
||||
{
|
||||
crypt_reencrypt_info ri;
|
||||
uint64_t minimal_size, device_size;
|
||||
struct volume_key *vks = NULL;
|
||||
int r = 0;
|
||||
struct crypt_lock_handle *reencrypt_lock = NULL;
|
||||
|
||||
if (crypt_use_keyring_for_vk(cd))
|
||||
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
|
||||
|
||||
r = crypt_reencrypt_lock(cd, NULL, &reencrypt_lock);
|
||||
if (r) {
|
||||
if (r == -EBUSY)
|
||||
log_err(cd, _("Reencryption in-progress. Cannot activate device."));
|
||||
else
|
||||
log_err(cd, _("Failed to get reencryption lock."));
|
||||
return r;
|
||||
}
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS2, NULL)))
|
||||
goto err;
|
||||
|
||||
ri = LUKS2_reenc_status(hdr);
|
||||
|
||||
if (ri == CRYPT_REENCRYPT_CRASH) {
|
||||
r = LUKS2_reencrypt_locked_recovery_by_passphrase(cd, keyslot,
|
||||
keyslot, passphrase, passphrase_size, flags, &vks);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
keyslot = r;
|
||||
|
||||
ri = LUKS2_reenc_status(hdr);
|
||||
}
|
||||
|
||||
/* recovery finished reencryption or it's already finished */
|
||||
if (ri == CRYPT_REENCRYPT_NONE) {
|
||||
crypt_drop_keyring_key(cd, vks);
|
||||
crypt_free_volume_key(vks);
|
||||
crypt_reencrypt_unlock(cd, reencrypt_lock);
|
||||
return _open_and_activate(cd, keyslot, name, passphrase, passphrase_size, flags);
|
||||
}
|
||||
|
||||
if (ri > CRYPT_REENCRYPT_CLEAN) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (LUKS2_get_data_size(hdr, &minimal_size, NULL))
|
||||
goto err;
|
||||
|
||||
if (!vks) {
|
||||
r = _open_all_keys(cd, hdr, keyslot, passphrase, passphrase_size, flags, &vks);
|
||||
if (r >= 0)
|
||||
keyslot = r;
|
||||
}
|
||||
|
||||
log_dbg(cd, "Entering clean reencryption state mode.");
|
||||
|
||||
if (r >= 0)
|
||||
r = luks2_check_device_size(cd, hdr, minimal_size >> SECTOR_SHIFT,
|
||||
&device_size, true);
|
||||
|
||||
if (r >= 0)
|
||||
r = LUKS2_activate_multi(cd, name, vks, flags);
|
||||
err:
|
||||
crypt_reencrypt_unlock(cd, reencrypt_lock);
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, vks);
|
||||
crypt_free_volume_key(vks);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
/*
|
||||
* Activation/deactivation of a device
|
||||
*/
|
||||
static int _open_and_activate_luks2(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *name,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
uint32_t flags)
|
||||
{
|
||||
crypt_reencrypt_info ri;
|
||||
int r;
|
||||
struct luks2_hdr *hdr = &cd->u.luks2.hdr;
|
||||
|
||||
ri = LUKS2_reenc_status(hdr);
|
||||
if (ri == CRYPT_REENCRYPT_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
if (ri > CRYPT_REENCRYPT_NONE) {
|
||||
if (name)
|
||||
r = _open_and_activate_reencrypt_device(cd, hdr, keyslot, name, passphrase,
|
||||
passphrase_size, flags);
|
||||
else
|
||||
r = _open_all_keys(cd, hdr, keyslot, passphrase,
|
||||
passphrase_size, flags, NULL);
|
||||
} else
|
||||
r = _open_and_activate(cd, keyslot, name, passphrase,
|
||||
passphrase_size, flags);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _activate_by_passphrase(struct crypt_device *cd,
|
||||
const char *name,
|
||||
int keyslot,
|
||||
@@ -3639,10 +3883,14 @@ static int _activate_by_passphrase(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (flags & CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF)
|
||||
cd->memory_hard_pbkdf_lock_enabled = true;
|
||||
|
||||
/* plain, use hashed passphrase */
|
||||
if (isPLAIN(cd->type)) {
|
||||
r = -EINVAL;
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
goto out;
|
||||
|
||||
r = process_key(cd, cd->u.plain.hdr.hash,
|
||||
cd->u.plain.key_size,
|
||||
@@ -3661,34 +3909,19 @@ static int _activate_by_passphrase(struct crypt_device *cd,
|
||||
r = LUKS1_activate(cd, name, vk, flags);
|
||||
}
|
||||
} else if (isLUKS2(cd->type)) {
|
||||
r = LUKS2_keyslot_open(cd, keyslot,
|
||||
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ?
|
||||
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
|
||||
passphrase, passphrase_size, &vk);
|
||||
if (r >= 0) {
|
||||
keyslot = r;
|
||||
|
||||
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) &&
|
||||
crypt_use_keyring_for_vk(cd)) {
|
||||
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd,
|
||||
&cd->u.luks2.hdr, vk, keyslot);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
|
||||
}
|
||||
|
||||
if (name)
|
||||
r = LUKS2_activate(cd, name, vk, flags);
|
||||
}
|
||||
r = _open_and_activate_luks2(cd, keyslot, name, passphrase, passphrase_size, flags);
|
||||
keyslot = r;
|
||||
} else {
|
||||
log_err(cd, _("Device type is not properly initialised."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
out:
|
||||
if (r < 0 && vk)
|
||||
crypt_drop_keyring_key(cd, vk->key_description);
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, vk);
|
||||
crypt_free_volume_key(vk);
|
||||
|
||||
cd->memory_hard_pbkdf_lock_enabled = false;
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
@@ -3953,8 +4186,8 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (r < 0 && vk)
|
||||
crypt_drop_keyring_key(cd, vk->key_description);
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, vk);
|
||||
crypt_free_volume_key(vk);
|
||||
|
||||
return r;
|
||||
@@ -3962,13 +4195,11 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
|
||||
|
||||
int crypt_deactivate_by_name(struct crypt_device *cd, const char *name, uint32_t flags)
|
||||
{
|
||||
char *key_desc;
|
||||
struct crypt_device *fake_cd = NULL;
|
||||
const char *namei = NULL;
|
||||
struct luks2_hdr *hdr2 = NULL;
|
||||
struct crypt_dm_active_device dmd = {};
|
||||
int r;
|
||||
struct dm_target *tgt = &dmd.segment;
|
||||
uint32_t get_flags = DM_ACTIVE_DEVICE | DM_ACTIVE_HOLDERS;
|
||||
uint32_t get_flags = DM_ACTIVE_DEVICE | DM_ACTIVE_UUID | DM_ACTIVE_HOLDERS;
|
||||
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
@@ -3996,26 +4227,21 @@ int crypt_deactivate_by_name(struct crypt_device *cd, const char *name, uint32_t
|
||||
r = -EBUSY;
|
||||
break;
|
||||
}
|
||||
if (isLUKS2(cd->type) && single_segment(&dmd) && tgt->type == DM_CRYPT && crypt_get_integrity_tag_size(cd))
|
||||
namei = device_dm_name(tgt->data_device);
|
||||
}
|
||||
|
||||
key_desc = crypt_get_device_key_description(cd, name);
|
||||
if (isLUKS2(cd->type))
|
||||
hdr2 = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
|
||||
if (isTCRYPT(cd->type))
|
||||
if (!strncmp(CRYPT_LUKS2, dmd.uuid ?: "", sizeof(CRYPT_LUKS2)-1) || hdr2)
|
||||
r = LUKS2_deactivate(cd, name, hdr2, &dmd, flags);
|
||||
else if (isTCRYPT(cd->type))
|
||||
r = TCRYPT_deactivate(cd, name, flags);
|
||||
else
|
||||
r = dm_remove_device(cd, name, flags);
|
||||
if (r < 0 && crypt_status(cd, name) == CRYPT_BUSY) {
|
||||
log_err(cd, _("Device %s is still in use."), name);
|
||||
r = -EBUSY;
|
||||
} else if (namei) {
|
||||
log_dbg(cd, "Deactivating integrity device %s.", namei);
|
||||
r = dm_remove_device(cd, namei, 0);
|
||||
}
|
||||
if (!r)
|
||||
crypt_drop_keyring_key(cd, key_desc);
|
||||
free(key_desc);
|
||||
break;
|
||||
case CRYPT_INACTIVE:
|
||||
log_err(cd, _("Device %s is not active."), name);
|
||||
@@ -4027,6 +4253,7 @@ int crypt_deactivate_by_name(struct crypt_device *cd, const char *name, uint32_t
|
||||
}
|
||||
|
||||
dm_targets_free(cd, &dmd);
|
||||
free(CONST_CAST(void*)dmd.uuid);
|
||||
crypt_free(fake_cd);
|
||||
|
||||
return r;
|
||||
@@ -4589,14 +4816,17 @@ int crypt_keyslot_set_encryption(struct crypt_device *cd,
|
||||
const char *cipher,
|
||||
size_t key_size)
|
||||
{
|
||||
char *tmp;
|
||||
|
||||
if (!cd || !cipher || ! key_size || !isLUKS2(cd->type))
|
||||
return -EINVAL;
|
||||
|
||||
if (LUKS2_keyslot_cipher_incompatible(cd, cipher))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = strdup(cipher);
|
||||
free(cd->u.luks2.keyslot_cipher);
|
||||
cd->u.luks2.keyslot_cipher = strdup(cipher);
|
||||
cd->u.luks2.keyslot_cipher = tmp;
|
||||
if (!cd->u.luks2.keyslot_cipher)
|
||||
return -ENOMEM;
|
||||
cd->u.luks2.keyslot_key_size = key_size;
|
||||
@@ -4632,7 +4862,8 @@ const char *crypt_keyslot_get_encryption(struct crypt_device *cd, int keyslot, s
|
||||
cipher = LUKS2_get_cipher(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT);
|
||||
if (!LUKS2_keyslot_cipher_incompatible(cd, cipher)) {
|
||||
*key_size = crypt_get_volume_key_size(cd);
|
||||
return cipher;
|
||||
if (*key_size)
|
||||
return cipher;
|
||||
}
|
||||
|
||||
/* Fallback to default LUKS2 keyslot encryption */
|
||||
@@ -4658,7 +4889,7 @@ int crypt_set_data_offset(struct crypt_device *cd, uint64_t data_offset)
|
||||
if (!cd)
|
||||
return -EINVAL;
|
||||
if (data_offset % (MAX_SECTOR_SIZE >> SECTOR_SHIFT)) {
|
||||
log_err(cd, "Data offset is not multiple of %u bytes.", MAX_SECTOR_SIZE);
|
||||
log_err(cd, _("Data offset is not multiple of %u bytes."), MAX_SECTOR_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -4977,6 +5208,18 @@ void *crypt_get_hdr(struct crypt_device *cd, const char *type)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* internal only */
|
||||
struct luks2_reenc_context *crypt_get_reenc_context(struct crypt_device *cd)
|
||||
{
|
||||
return cd->u.luks2.rh;
|
||||
}
|
||||
|
||||
/* internal only */
|
||||
void crypt_set_reenc_context(struct crypt_device *cd, struct luks2_reenc_context *rh)
|
||||
{
|
||||
cd->u.luks2.rh = rh;
|
||||
}
|
||||
|
||||
/*
|
||||
* Token handling
|
||||
*/
|
||||
@@ -4988,7 +5231,7 @@ int crypt_activate_by_token(struct crypt_device *cd,
|
||||
log_dbg(cd, "%s volume %s using token %d.",
|
||||
name ? "Activating" : "Checking", name ?: "passphrase", token);
|
||||
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED)))
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0)))
|
||||
return r;
|
||||
|
||||
if ((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd))
|
||||
@@ -5012,7 +5255,7 @@ int crypt_token_json_get(struct crypt_device *cd, int token, const char **json)
|
||||
|
||||
log_dbg(cd, "Requesting JSON for token %d.", token);
|
||||
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED)))
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED, 0)))
|
||||
return r;
|
||||
|
||||
return LUKS2_token_json_get(cd, &cd->u.luks2.hdr, token, json) ?: token;
|
||||
@@ -5032,7 +5275,7 @@ int crypt_token_json_set(struct crypt_device *cd, int token, const char *json)
|
||||
|
||||
crypt_token_info crypt_token_status(struct crypt_device *cd, int token, const char **type)
|
||||
{
|
||||
if (_onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED))
|
||||
if (_onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0))
|
||||
return CRYPT_TOKEN_INVALID;
|
||||
|
||||
return LUKS2_token_status(cd, &cd->u.luks2.hdr, token, type);
|
||||
@@ -5051,7 +5294,7 @@ int crypt_token_luks2_keyring_get(struct crypt_device *cd,
|
||||
|
||||
log_dbg(cd, "Requesting LUKS2 keyring token %d.", token);
|
||||
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED)))
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED, 0)))
|
||||
return r;
|
||||
|
||||
token_info = LUKS2_token_status(cd, &cd->u.luks2.hdr, token, &type);
|
||||
@@ -5117,7 +5360,7 @@ int crypt_token_is_assigned(struct crypt_device *cd, int token, int keyslot)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED)))
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0)))
|
||||
return r;
|
||||
|
||||
return LUKS2_token_is_assigned(cd, &cd->u.luks2.hdr, keyslot, token);
|
||||
@@ -5149,7 +5392,7 @@ int crypt_persistent_flags_set(struct crypt_device *cd, crypt_flags_type type, u
|
||||
return LUKS2_config_set_flags(cd, &cd->u.luks2.hdr, flags);
|
||||
|
||||
if (type == CRYPT_FLAGS_REQUIREMENTS)
|
||||
return LUKS2_config_set_requirements(cd, &cd->u.luks2.hdr, flags);
|
||||
return LUKS2_config_set_requirements(cd, &cd->u.luks2.hdr, flags, true);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -5161,7 +5404,7 @@ int crypt_persistent_flags_get(struct crypt_device *cd, crypt_flags_type type, u
|
||||
if (!flags)
|
||||
return -EINVAL;
|
||||
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED)))
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED, 0)))
|
||||
return r;
|
||||
|
||||
if (type == CRYPT_FLAGS_ACTIVATION)
|
||||
@@ -5221,6 +5464,8 @@ static int verify_and_update_segment_digest(struct crypt_device *cd,
|
||||
if (r >= 0)
|
||||
goto out;
|
||||
|
||||
/* FIXME: check new volume key is usable with current default segment */
|
||||
|
||||
r = update_volume_key_segment_digest(cd, &cd->u.luks2.hdr, digest, 1);
|
||||
if (r)
|
||||
log_err(cd, _("Failed to assign keyslot %u as the new volume key."), keyslot);
|
||||
@@ -5278,9 +5523,15 @@ int crypt_keyslot_add_by_key(struct crypt_device *cd,
|
||||
if (digest >= 0)
|
||||
flags &= ~CRYPT_VOLUME_KEY_SET;
|
||||
|
||||
/* if key matches any existing digest, do not create new digest */
|
||||
if (digest < 0 && (flags & CRYPT_VOLUME_KEY_DIGEST_REUSE))
|
||||
digest = LUKS2_digest_any_matching(cd, &cd->u.luks2.hdr, vk);
|
||||
|
||||
/* no segment flag or new vk flag requires new key digest */
|
||||
if (flags & (CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_SET))
|
||||
digest = LUKS2_digest_create(cd, "pbkdf2", &cd->u.luks2.hdr, vk);
|
||||
if (flags & (CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_SET)) {
|
||||
if (digest < 0 || !(flags & CRYPT_VOLUME_KEY_DIGEST_REUSE))
|
||||
digest = LUKS2_digest_create(cd, "pbkdf2", &cd->u.luks2.hdr, vk);
|
||||
}
|
||||
|
||||
r = digest;
|
||||
if (r < 0) {
|
||||
@@ -5366,8 +5617,9 @@ int crypt_volume_key_keyring(struct crypt_device *cd, int enable)
|
||||
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk)
|
||||
{
|
||||
int r;
|
||||
const char *type_name = key_type_name(LOGON_KEY);
|
||||
|
||||
if (!vk || !cd)
|
||||
if (!vk || !cd || !type_name)
|
||||
return -EINVAL;
|
||||
|
||||
if (!vk->key_description) {
|
||||
@@ -5375,9 +5627,9 @@ int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
log_dbg(cd, "Loading key (%zu bytes) in thread keyring.", vk->keylength);
|
||||
log_dbg(cd, "Loading key (%zu bytes, type %s) in thread keyring.", vk->keylength, type_name);
|
||||
|
||||
r = keyring_add_key_in_thread_keyring(vk->key_description, vk->key, vk->keylength);
|
||||
r = keyring_add_key_in_thread_keyring(LOGON_KEY, vk->key_description, vk->key, vk->keylength);
|
||||
if (r) {
|
||||
log_dbg(cd, "keyring_add_key_in_thread_keyring failed (error %d)", r);
|
||||
log_err(cd, _("Failed to load key in kernel keyring."));
|
||||
@@ -5403,21 +5655,33 @@ void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring)
|
||||
}
|
||||
|
||||
/* internal only */
|
||||
void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description)
|
||||
void crypt_drop_keyring_key_by_description(struct crypt_device *cd, const char *key_description, key_type_t ktype)
|
||||
{
|
||||
int r;
|
||||
const char *type_name = key_type_name(ktype);
|
||||
|
||||
if (!key_description)
|
||||
if (!key_description || !type_name)
|
||||
return;
|
||||
|
||||
log_dbg(cd, "Requesting keyring key for revoke and unlink.");
|
||||
log_dbg(cd, "Requesting keyring %s key for revoke and unlink.", type_name);
|
||||
|
||||
r = keyring_revoke_and_unlink_key(key_description);
|
||||
r = keyring_revoke_and_unlink_key(ktype, key_description);
|
||||
if (r)
|
||||
log_dbg(cd, "keyring_revoke_and_unlink failed (error %d)", r);
|
||||
log_dbg(cd, "keyring_revoke_and_unlink_key failed (error %d)", r);
|
||||
crypt_set_key_in_keyring(cd, 0);
|
||||
}
|
||||
|
||||
/* internal only */
|
||||
void crypt_drop_keyring_key(struct crypt_device *cd, struct volume_key *vks)
|
||||
{
|
||||
struct volume_key *vk = vks;
|
||||
|
||||
while (vk) {
|
||||
crypt_drop_keyring_key_by_description(cd, vk->key_description, LOGON_KEY);
|
||||
vk = crypt_volume_key_next(vk);
|
||||
}
|
||||
}
|
||||
|
||||
int crypt_activate_by_keyring(struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *key_description,
|
||||
@@ -5457,6 +5721,59 @@ int crypt_activate_by_keyring(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Workaround for serialization of parallel activation and memory-hard PBKDF
|
||||
* In specific situation (systemd activation) this causes OOM killer activation.
|
||||
* For now, let's provide this ugly way to serialize unlocking of devices.
|
||||
*/
|
||||
int crypt_serialize_lock(struct crypt_device *cd)
|
||||
{
|
||||
if (!cd->memory_hard_pbkdf_lock_enabled)
|
||||
return 0;
|
||||
|
||||
log_dbg(cd, "Taking global memory-hard access serialization lock.");
|
||||
if (crypt_write_lock(cd, "memory-hard-access", true, &cd->pbkdf_memory_hard_lock)) {
|
||||
log_err(cd, _("Failed to acquire global memory-hard access serialization lock."));
|
||||
cd->pbkdf_memory_hard_lock = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_serialize_unlock(struct crypt_device *cd)
|
||||
{
|
||||
if (!cd->memory_hard_pbkdf_lock_enabled)
|
||||
return;
|
||||
|
||||
crypt_unlock_internal(cd, cd->pbkdf_memory_hard_lock);
|
||||
cd->pbkdf_memory_hard_lock = NULL;
|
||||
}
|
||||
|
||||
crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd,
|
||||
struct crypt_params_reencrypt *params)
|
||||
{
|
||||
crypt_reencrypt_info ri;
|
||||
struct luks2_hdr *hdr;
|
||||
|
||||
if (_onlyLUKS2(cd, CRYPT_CD_QUIET, CRYPT_REQUIREMENT_ONLINE_REENCRYPT))
|
||||
return CRYPT_REENCRYPT_INVALID;
|
||||
|
||||
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
|
||||
ri = LUKS2_reenc_status(hdr);
|
||||
if (ri == CRYPT_REENCRYPT_NONE || ri == CRYPT_REENCRYPT_INVALID || !params)
|
||||
return ri;
|
||||
|
||||
params->mode = LUKS2_reencrypt_mode(hdr);
|
||||
params->resilience = LUKS2_reencrypt_protection_type(hdr);
|
||||
params->hash = LUKS2_reencrypt_protection_hash(hdr);
|
||||
params->data_shift = LUKS2_reencrypt_data_shift(hdr);
|
||||
params->max_hotzone_size = 0;
|
||||
|
||||
return ri;
|
||||
}
|
||||
|
||||
static void __attribute__((destructor)) libcryptsetup_exit(void)
|
||||
{
|
||||
crypt_backend_destroy();
|
||||
|
||||
@@ -635,7 +635,7 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
|
||||
struct device *base_device, *device = crypt_metadata_device(cd);
|
||||
ssize_t hdr_size = sizeof(struct tcrypt_phdr);
|
||||
char *base_device_path;
|
||||
int devfd = 0, r;
|
||||
int devfd, r;
|
||||
|
||||
assert(sizeof(struct tcrypt_phdr) == 512);
|
||||
|
||||
@@ -692,11 +692,10 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
|
||||
device_alignment(device), hdr, hdr_size,
|
||||
TCRYPT_HDR_OFFSET_BCK) == hdr_size)
|
||||
r = TCRYPT_init_hdr(cd, hdr, params);
|
||||
} else if (read_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), hdr, hdr_size) == hdr_size)
|
||||
} else if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), hdr, hdr_size, 0) == hdr_size)
|
||||
r = TCRYPT_init_hdr(cd, hdr, params);
|
||||
|
||||
close(devfd);
|
||||
if (r < 0)
|
||||
memset(hdr, 0, sizeof (*hdr));
|
||||
return r;
|
||||
@@ -920,9 +919,10 @@ out:
|
||||
}
|
||||
|
||||
static int TCRYPT_status_one(struct crypt_device *cd, const char *name,
|
||||
const char *base_uuid, int index,
|
||||
size_t *key_size, char *cipher,
|
||||
uint64_t *data_offset, struct device **device)
|
||||
const char *base_uuid, int index,
|
||||
size_t *key_size, char *cipher,
|
||||
struct tcrypt_phdr *tcrypt_hdr,
|
||||
struct device **device)
|
||||
{
|
||||
struct crypt_dm_active_device dmd;
|
||||
struct dm_target *tgt = &dmd.segment;
|
||||
@@ -955,7 +955,7 @@ static int TCRYPT_status_one(struct crypt_device *cd, const char *name,
|
||||
strcat(cipher, "-");
|
||||
strncat(cipher, tgt->u.crypt.cipher, MAX_CIPHER_LEN);
|
||||
*key_size += tgt->u.crypt.vk->keylength;
|
||||
*data_offset = tgt->u.crypt.offset * SECTOR_SIZE;
|
||||
tcrypt_hdr->d.mk_offset = tgt->u.crypt.offset * SECTOR_SIZE;
|
||||
device_free(cd, *device);
|
||||
MOVE_REF(*device, tgt->data_device);
|
||||
} else
|
||||
@@ -993,10 +993,10 @@ int TCRYPT_init_by_name(struct crypt_device *cd, const char *name,
|
||||
|
||||
key_size = tgt->u.crypt.vk->keylength;
|
||||
r = TCRYPT_status_one(cd, name, uuid, 1, &key_size,
|
||||
cipher, &tcrypt_hdr->d.mk_offset, device);
|
||||
cipher, tcrypt_hdr, device);
|
||||
if (!r)
|
||||
r = TCRYPT_status_one(cd, name, uuid, 2, &key_size,
|
||||
cipher, &tcrypt_hdr->d.mk_offset, device);
|
||||
cipher, tcrypt_hdr, device);
|
||||
|
||||
if (r < 0 && r != -ENODEV)
|
||||
return r;
|
||||
|
||||
@@ -21,167 +21,9 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* This is not simulating storage, so using disk block causes extreme overhead.
|
||||
* Let's use some fixed block size where results are more reliable...
|
||||
*/
|
||||
#define CIPHER_BLOCK_BYTES 65536
|
||||
|
||||
/*
|
||||
* If the measured value is lower, encrypted buffer is probably too small
|
||||
* and calculated values are not reliable.
|
||||
*/
|
||||
#define CIPHER_TIME_MIN_MS 0.001
|
||||
|
||||
/*
|
||||
* The whole test depends on Linux kernel usermode crypto API for now.
|
||||
* (The same implementations are used in dm-crypt though.)
|
||||
*/
|
||||
|
||||
struct cipher_perf {
|
||||
char name[32];
|
||||
char mode[32];
|
||||
char *key;
|
||||
size_t key_length;
|
||||
char *iv;
|
||||
size_t iv_length;
|
||||
size_t buffer_size;
|
||||
};
|
||||
|
||||
static int time_ms(struct timespec *start, struct timespec *end, double *ms)
|
||||
{
|
||||
double start_ms, end_ms;
|
||||
|
||||
start_ms = start->tv_sec * 1000.0 + start->tv_nsec / (1000.0 * 1000);
|
||||
end_ms = end->tv_sec * 1000.0 + end->tv_nsec / (1000.0 * 1000);
|
||||
|
||||
*ms = end_ms - start_ms;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cipher_perf_one(struct crypt_device *cd,
|
||||
struct cipher_perf *cp, char *buf,
|
||||
size_t buf_size, int enc)
|
||||
{
|
||||
struct crypt_cipher *cipher = NULL;
|
||||
size_t done = 0, block = CIPHER_BLOCK_BYTES;
|
||||
int r;
|
||||
|
||||
if (buf_size < block)
|
||||
block = buf_size;
|
||||
|
||||
r = crypt_cipher_init(&cipher, cp->name, cp->mode, cp->key, cp->key_length);
|
||||
if (r < 0) {
|
||||
log_dbg(cd, "Cannot initialise cipher %s, mode %s.", cp->name, cp->mode);
|
||||
return r;
|
||||
}
|
||||
|
||||
while (done < buf_size) {
|
||||
if ((done + block) > buf_size)
|
||||
block = buf_size - done;
|
||||
|
||||
if (enc)
|
||||
r = crypt_cipher_encrypt(cipher, &buf[done], &buf[done],
|
||||
block, cp->iv, cp->iv_length);
|
||||
else
|
||||
r = crypt_cipher_decrypt(cipher, &buf[done], &buf[done],
|
||||
block, cp->iv, cp->iv_length);
|
||||
if (r < 0)
|
||||
break;
|
||||
|
||||
done += block;
|
||||
}
|
||||
|
||||
crypt_cipher_destroy(cipher);
|
||||
|
||||
return r;
|
||||
}
|
||||
static int cipher_measure(struct crypt_device *cd,
|
||||
struct cipher_perf *cp, char *buf,
|
||||
size_t buf_size, int encrypt, double *ms)
|
||||
{
|
||||
struct timespec start, end;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* Using getrusage would be better here but the precision
|
||||
* is not adequate, so better stick with CLOCK_MONOTONIC
|
||||
*/
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &start) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = cipher_perf_one(cd, cp, buf, buf_size, encrypt);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &end) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = time_ms(&start, &end, ms);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (*ms < CIPHER_TIME_MIN_MS) {
|
||||
log_dbg(cd, "Measured cipher runtime (%1.6f) is too low.", *ms);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static double speed_mbs(unsigned long bytes, double ms)
|
||||
{
|
||||
double speed = bytes, s = ms / 1000.;
|
||||
|
||||
return speed / (1024 * 1024) / s;
|
||||
}
|
||||
|
||||
static int cipher_perf(struct crypt_device *cd, struct cipher_perf *cp,
|
||||
double *encryption_mbs, double *decryption_mbs)
|
||||
{
|
||||
double ms_enc, ms_dec, ms;
|
||||
int r, repeat_enc, repeat_dec;
|
||||
void *buf = NULL;
|
||||
|
||||
if (posix_memalign(&buf, crypt_getpagesize(), cp->buffer_size))
|
||||
return -ENOMEM;
|
||||
|
||||
ms_enc = 0.0;
|
||||
repeat_enc = 1;
|
||||
while (ms_enc < 1000.0) {
|
||||
r = cipher_measure(cd, cp, buf, cp->buffer_size, 1, &ms);
|
||||
if (r < 0) {
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
||||
ms_enc += ms;
|
||||
repeat_enc++;
|
||||
}
|
||||
|
||||
ms_dec = 0.0;
|
||||
repeat_dec = 1;
|
||||
while (ms_dec < 1000.0) {
|
||||
r = cipher_measure(cd, cp, buf, cp->buffer_size, 0, &ms);
|
||||
if (r < 0) {
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
||||
ms_dec += ms;
|
||||
repeat_dec++;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
*encryption_mbs = speed_mbs(cp->buffer_size * repeat_enc, ms_enc);
|
||||
*decryption_mbs = speed_mbs(cp->buffer_size * repeat_dec, ms_dec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_benchmark(struct crypt_device *cd,
|
||||
const char *cipher,
|
||||
const char *cipher_mode,
|
||||
@@ -191,12 +33,8 @@ int crypt_benchmark(struct crypt_device *cd,
|
||||
double *encryption_mbs,
|
||||
double *decryption_mbs)
|
||||
{
|
||||
struct cipher_perf cp = {
|
||||
.key_length = volume_key_size,
|
||||
.iv_length = iv_size,
|
||||
.buffer_size = buffer_size,
|
||||
};
|
||||
char *c;
|
||||
void *buffer = NULL;
|
||||
char *iv = NULL, *key = NULL, mode[MAX_CIPHER_LEN], *c;
|
||||
int r;
|
||||
|
||||
if (!cipher || !cipher_mode || !volume_key_size || !encryption_mbs || !decryption_mbs)
|
||||
@@ -207,29 +45,40 @@ int crypt_benchmark(struct crypt_device *cd,
|
||||
return r;
|
||||
|
||||
r = -ENOMEM;
|
||||
if (iv_size) {
|
||||
cp.iv = malloc(iv_size);
|
||||
if (!cp.iv)
|
||||
goto out;
|
||||
crypt_random_get(cd, cp.iv, iv_size, CRYPT_RND_NORMAL);
|
||||
}
|
||||
|
||||
cp.key = malloc(volume_key_size);
|
||||
if (!cp.key)
|
||||
if (posix_memalign(&buffer, crypt_getpagesize(), buffer_size))
|
||||
goto out;
|
||||
|
||||
crypt_random_get(cd, cp.key, volume_key_size, CRYPT_RND_NORMAL);
|
||||
strncpy(cp.name, cipher, sizeof(cp.name)-1);
|
||||
strncpy(cp.mode, cipher_mode, sizeof(cp.mode)-1);
|
||||
if (iv_size) {
|
||||
iv = malloc(iv_size);
|
||||
if (!iv)
|
||||
goto out;
|
||||
crypt_random_get(cd, iv, iv_size, CRYPT_RND_NORMAL);
|
||||
}
|
||||
|
||||
key = malloc(volume_key_size);
|
||||
if (!key)
|
||||
goto out;
|
||||
|
||||
crypt_random_get(cd, key, volume_key_size, CRYPT_RND_NORMAL);
|
||||
|
||||
strncpy(mode, cipher_mode, sizeof(mode)-1);
|
||||
/* Ignore IV generator */
|
||||
if ((c = strchr(cp.mode, '-')))
|
||||
if ((c = strchr(mode, '-')))
|
||||
*c = '\0';
|
||||
|
||||
r = cipher_perf(cd, &cp, encryption_mbs, decryption_mbs);
|
||||
r = crypt_cipher_perf_kernel(cipher, cipher_mode, buffer, buffer_size, key, volume_key_size,
|
||||
iv, iv_size, encryption_mbs, decryption_mbs);
|
||||
|
||||
if (r == -ERANGE)
|
||||
log_dbg(cd, "Measured cipher runtime is too low.");
|
||||
else if (r == -ENOTSUP || r == -ENOENT)
|
||||
log_dbg(cd, "Cannot initialise cipher %s, mode %s.", cipher, cipher_mode);
|
||||
|
||||
out:
|
||||
free(cp.key);
|
||||
free(cp.iv);
|
||||
free(buffer);
|
||||
free(key);
|
||||
free(iv);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,10 @@ struct device {
|
||||
char *file_path;
|
||||
int loop_fd;
|
||||
|
||||
int ro_dev_fd;
|
||||
int dev_fd;
|
||||
int dev_fd_excl;
|
||||
|
||||
struct crypt_lock_handle *lh;
|
||||
|
||||
unsigned int o_direct:1;
|
||||
@@ -237,11 +241,13 @@ static int _open_locked(struct crypt_device *cd, struct device *device, int flag
|
||||
|
||||
/*
|
||||
* Common wrapper for device sync.
|
||||
* FIXME: file descriptor will be in struct later.
|
||||
*/
|
||||
void device_sync(struct crypt_device *cd, struct device *device, int devfd)
|
||||
void device_sync(struct crypt_device *cd, struct device *device)
|
||||
{
|
||||
if (fsync(devfd) == -1)
|
||||
if (!device || device->dev_fd < 0)
|
||||
return;
|
||||
|
||||
if (fsync(device->dev_fd) == -1)
|
||||
log_dbg(cd, "Cannot sync device %s.", device_path(device));
|
||||
}
|
||||
|
||||
@@ -256,20 +262,39 @@ void device_sync(struct crypt_device *cd, struct device *device, int devfd)
|
||||
*/
|
||||
static int device_open_internal(struct crypt_device *cd, struct device *device, int flags)
|
||||
{
|
||||
int devfd;
|
||||
int access, devfd;
|
||||
|
||||
if (device->o_direct)
|
||||
flags |= O_DIRECT;
|
||||
|
||||
access = flags & O_ACCMODE;
|
||||
if (access == O_WRONLY)
|
||||
access = O_RDWR;
|
||||
|
||||
if (access == O_RDONLY && device->ro_dev_fd >= 0) {
|
||||
log_dbg(cd, "Reusing open r%c fd on device %s", 'o', device_path(device));
|
||||
return device->ro_dev_fd;
|
||||
} else if (access == O_RDWR && device->dev_fd >= 0) {
|
||||
log_dbg(cd, "Reusing open r%c fd on device %s", 'w', device_path(device));
|
||||
return device->dev_fd;
|
||||
}
|
||||
|
||||
if (device_locked(device->lh))
|
||||
devfd = _open_locked(cd, device, flags);
|
||||
else
|
||||
devfd = open(device_path(device), flags);
|
||||
|
||||
if (devfd < 0)
|
||||
if (devfd < 0) {
|
||||
log_dbg(cd, "Cannot open device %s%s.",
|
||||
device_path(device),
|
||||
(flags & O_ACCMODE) != O_RDONLY ? " for write" : "");
|
||||
access != O_RDONLY ? " for write" : "");
|
||||
return devfd;
|
||||
}
|
||||
|
||||
if (access == O_RDONLY)
|
||||
device->ro_dev_fd = devfd;
|
||||
else
|
||||
device->dev_fd = devfd;
|
||||
|
||||
return devfd;
|
||||
}
|
||||
@@ -280,6 +305,54 @@ int device_open(struct crypt_device *cd, struct device *device, int flags)
|
||||
return device_open_internal(cd, device, flags);
|
||||
}
|
||||
|
||||
int device_open_excl(struct crypt_device *cd, struct device *device, int flags)
|
||||
{
|
||||
const char *path;
|
||||
struct stat st;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
assert(!device_locked(device->lh));
|
||||
|
||||
if (device->dev_fd_excl < 0) {
|
||||
path = device_path(device);
|
||||
if (stat(path, &st))
|
||||
return -EINVAL;
|
||||
if (!S_ISBLK(st.st_mode))
|
||||
log_dbg(cd, "%s is not a block device. Can't open in exclusive mode.",
|
||||
path);
|
||||
else {
|
||||
/* open(2) with O_EXCL (w/o O_CREAT) on regular file is undefined behaviour according to man page */
|
||||
/* coverity[toctou] */
|
||||
device->dev_fd_excl = open(path, O_RDONLY | O_EXCL);
|
||||
if (device->dev_fd_excl < 0)
|
||||
return errno == EBUSY ? -EBUSY : device->dev_fd_excl;
|
||||
if (fstat(device->dev_fd_excl, &st) || !S_ISBLK(st.st_mode)) {
|
||||
log_dbg(cd, "%s is not a block device. Can't open in exclusive mode.",
|
||||
path);
|
||||
close(device->dev_fd_excl);
|
||||
device->dev_fd_excl = -1;
|
||||
} else
|
||||
log_dbg(cd, "Device %s is blocked for exclusive open.", path);
|
||||
}
|
||||
}
|
||||
|
||||
return device_open_internal(cd, device, flags);
|
||||
}
|
||||
|
||||
void device_release_excl(struct crypt_device *cd, struct device *device)
|
||||
{
|
||||
if (device && device->dev_fd_excl >= 0) {
|
||||
if (close(device->dev_fd_excl))
|
||||
log_dbg(cd, "Failed to release exclusive handle on device %s.",
|
||||
device_path(device));
|
||||
else
|
||||
log_dbg(cd, "Closed exclusive fd for %s.", device_path(device));
|
||||
device->dev_fd_excl = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int device_open_locked(struct crypt_device *cd, struct device *device, int flags)
|
||||
{
|
||||
assert(!crypt_metadata_locking_enabled() || device_locked(device->lh));
|
||||
@@ -307,6 +380,9 @@ int device_alloc_no_check(struct device **device, const char *path)
|
||||
return -ENOMEM;
|
||||
}
|
||||
dev->loop_fd = -1;
|
||||
dev->ro_dev_fd = -1;
|
||||
dev->dev_fd = -1;
|
||||
dev->dev_fd_excl = -1;
|
||||
dev->o_direct = 1;
|
||||
|
||||
*device = dev;
|
||||
@@ -344,12 +420,19 @@ void device_free(struct crypt_device *cd, struct device *device)
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
device_close(cd, device);
|
||||
|
||||
if (device->dev_fd_excl != -1) {
|
||||
log_dbg(cd, "Closed exclusive fd for %s.", device_path(device));
|
||||
close(device->dev_fd_excl);
|
||||
}
|
||||
|
||||
if (device->loop_fd != -1) {
|
||||
log_dbg(cd, "Closed loop %s (%s).", device->path, device->file_path);
|
||||
close(device->loop_fd);
|
||||
}
|
||||
|
||||
assert (!device_locked(device->lh));
|
||||
assert(!device_locked(device->lh));
|
||||
|
||||
free(device->file_path);
|
||||
free(device->path);
|
||||
@@ -829,21 +912,25 @@ size_t device_alignment(struct device *device)
|
||||
return device->alignment;
|
||||
}
|
||||
|
||||
void device_set_lock_handle(struct device *device, struct crypt_lock_handle *h)
|
||||
{
|
||||
device->lh = h;
|
||||
}
|
||||
|
||||
struct crypt_lock_handle *device_get_lock_handle(struct device *device)
|
||||
{
|
||||
return device->lh;
|
||||
}
|
||||
|
||||
int device_read_lock(struct crypt_device *cd, struct device *device)
|
||||
{
|
||||
if (!crypt_metadata_locking_enabled())
|
||||
return 0;
|
||||
|
||||
assert(!device_locked(device->lh));
|
||||
if (device_read_lock_internal(cd, device))
|
||||
return -EBUSY;
|
||||
|
||||
device->lh = device_read_lock_handle(cd, device_path(device));
|
||||
|
||||
if (device_locked(device->lh)) {
|
||||
log_dbg(cd, "Device %s READ lock taken.", device_path(device));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EBUSY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int device_write_lock(struct crypt_device *cd, struct device *device)
|
||||
@@ -851,16 +938,9 @@ int device_write_lock(struct crypt_device *cd, struct device *device)
|
||||
if (!crypt_metadata_locking_enabled())
|
||||
return 0;
|
||||
|
||||
assert(!device_locked(device->lh));
|
||||
assert(!device_locked(device->lh) || !device_locked_readonly(device->lh));
|
||||
|
||||
device->lh = device_write_lock_handle(cd, device_path(device));
|
||||
|
||||
if (device_locked(device->lh)) {
|
||||
log_dbg(cd, "Device %s WRITE lock taken.", device_path(device));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EBUSY;
|
||||
return device_write_lock_internal(cd, device);
|
||||
}
|
||||
|
||||
void device_read_unlock(struct crypt_device *cd, struct device *device)
|
||||
@@ -868,13 +948,9 @@ void device_read_unlock(struct crypt_device *cd, struct device *device)
|
||||
if (!crypt_metadata_locking_enabled())
|
||||
return;
|
||||
|
||||
assert(device_locked(device->lh) && device_locked_readonly(device->lh));
|
||||
assert(device_locked(device->lh));
|
||||
|
||||
device_unlock_handle(cd, device->lh);
|
||||
|
||||
log_dbg(cd, "Device %s READ lock released.", device_path(device));
|
||||
|
||||
device->lh = NULL;
|
||||
device_unlock_internal(cd, device);
|
||||
}
|
||||
|
||||
void device_write_unlock(struct crypt_device *cd, struct device *device)
|
||||
@@ -884,9 +960,30 @@ void device_write_unlock(struct crypt_device *cd, struct device *device)
|
||||
|
||||
assert(device_locked(device->lh) && !device_locked_readonly(device->lh));
|
||||
|
||||
device_unlock_handle(cd, device->lh);
|
||||
|
||||
log_dbg(cd, "Device %s WRITE lock released.", device_path(device));
|
||||
|
||||
device->lh = NULL;
|
||||
device_unlock_internal(cd, device);
|
||||
}
|
||||
|
||||
bool device_is_locked(struct device *device)
|
||||
{
|
||||
return device ? device_locked(device->lh) : 0;
|
||||
}
|
||||
|
||||
void device_close(struct crypt_device *cd, struct device *device)
|
||||
{
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
if (device->ro_dev_fd != -1) {
|
||||
log_dbg(cd, "Closing read only fd for %s.", device_path(device));
|
||||
if (close(device->ro_dev_fd))
|
||||
log_dbg(cd, "Failed to close read only fd for %s.", device_path(device));
|
||||
device->ro_dev_fd = -1;
|
||||
}
|
||||
|
||||
if (device->dev_fd != -1) {
|
||||
log_dbg(cd, "Closing read write fd for %s.", device_path(device));
|
||||
if (close(device->dev_fd))
|
||||
log_dbg(cd, "Failed to close read write fd for %s.", device_path(device));
|
||||
device->dev_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
# include <sys/sysmacros.h> /* for major, minor */
|
||||
#endif
|
||||
#include <libgen.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "utils_device_locking.h"
|
||||
@@ -41,22 +42,44 @@
|
||||
((buf1).st_ino == (buf2).st_ino && \
|
||||
(buf1).st_dev == (buf2).st_dev)
|
||||
|
||||
#ifndef __GNUC__
|
||||
# define __typeof__ typeof
|
||||
#endif
|
||||
|
||||
enum lock_type {
|
||||
DEV_LOCK_READ = 0,
|
||||
DEV_LOCK_WRITE
|
||||
};
|
||||
|
||||
enum lock_mode {
|
||||
DEV_LOCK_FILE = 0,
|
||||
DEV_LOCK_BDEV,
|
||||
DEV_LOCK_NAME
|
||||
};
|
||||
|
||||
struct crypt_lock_handle {
|
||||
dev_t devno;
|
||||
unsigned refcnt;
|
||||
int flock_fd;
|
||||
enum lock_type type;
|
||||
__typeof__( ((struct stat*)0)->st_mode) mode;
|
||||
enum lock_mode mode;
|
||||
union {
|
||||
struct {
|
||||
dev_t devno;
|
||||
} bdev;
|
||||
struct {
|
||||
char *name;
|
||||
} name;
|
||||
} u;
|
||||
};
|
||||
|
||||
static int resource_by_name(char *res, size_t res_size, const char *name, bool fullpath)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (fullpath)
|
||||
r = snprintf(res, res_size, "%s/LN_%s", DEFAULT_LUKS2_LOCK_PATH, name);
|
||||
else
|
||||
r = snprintf(res, res_size, "LN_%s", name);
|
||||
|
||||
return (r < 0 || (size_t)r >= res_size) ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static int resource_by_devno(char *res, size_t res_size, dev_t devno, unsigned fullpath)
|
||||
{
|
||||
int r;
|
||||
@@ -121,13 +144,13 @@ static int open_resource(struct crypt_device *cd, const char *res)
|
||||
return r < 0 ? -err : r;
|
||||
}
|
||||
|
||||
static int acquire_lock_handle(struct crypt_device *cd, const char *device_path, struct crypt_lock_handle *h)
|
||||
static int acquire_lock_handle(struct crypt_device *cd, struct device *device, struct crypt_lock_handle *h)
|
||||
{
|
||||
char res[PATH_MAX];
|
||||
int dev_fd, fd;
|
||||
struct stat st;
|
||||
|
||||
dev_fd = open(device_path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
|
||||
dev_fd = open(device_path(device), O_RDONLY | O_NONBLOCK | O_CLOEXEC);
|
||||
if (dev_fd < 0)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -148,23 +171,49 @@ static int acquire_lock_handle(struct crypt_device *cd, const char *device_path,
|
||||
return fd;
|
||||
|
||||
h->flock_fd = fd;
|
||||
h->devno = st.st_rdev;
|
||||
h->u.bdev.devno = st.st_rdev;
|
||||
h->mode = DEV_LOCK_BDEV;
|
||||
} else if (S_ISREG(st.st_mode)) {
|
||||
// FIXME: workaround for nfsv4
|
||||
fd = open(device_path, O_RDWR | O_NONBLOCK | O_CLOEXEC);
|
||||
fd = open(device_path(device), O_RDWR | O_NONBLOCK | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
h->flock_fd = dev_fd;
|
||||
else {
|
||||
h->flock_fd = fd;
|
||||
close(dev_fd);
|
||||
}
|
||||
h->mode = DEV_LOCK_FILE;
|
||||
} else {
|
||||
/* Wrong device type */
|
||||
close(dev_fd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
h->mode = st.st_mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acquire_lock_handle_by_name(struct crypt_device *cd, const char *name, struct crypt_lock_handle *h)
|
||||
{
|
||||
char res[PATH_MAX];
|
||||
int fd;
|
||||
|
||||
h->u.name.name = strdup(name);
|
||||
if (!h->u.name.name)
|
||||
return -ENOMEM;
|
||||
|
||||
if (resource_by_name(res, sizeof(res), name, false)) {
|
||||
free(h->u.name.name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fd = open_resource(cd, res);
|
||||
if (fd < 0) {
|
||||
free(h->u.name.name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
h->flock_fd = fd;
|
||||
h->mode = DEV_LOCK_NAME;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -174,9 +223,9 @@ static void release_lock_handle(struct crypt_device *cd, struct crypt_lock_handl
|
||||
char res[PATH_MAX];
|
||||
struct stat buf_a, buf_b;
|
||||
|
||||
if (S_ISBLK(h->mode) && /* was it block device */
|
||||
if ((h->mode == DEV_LOCK_NAME) && /* was it name lock */
|
||||
!flock(h->flock_fd, LOCK_EX | LOCK_NB) && /* lock to drop the file */
|
||||
!resource_by_devno(res, sizeof(res), h->devno, 1) && /* acquire lock resource name */
|
||||
!resource_by_name(res, sizeof(res), h->u.name.name, true) && /* acquire lock resource name */
|
||||
!fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
|
||||
!stat(res, &buf_b) && /* does path file still exist? */
|
||||
same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
|
||||
@@ -185,8 +234,22 @@ static void release_lock_handle(struct crypt_device *cd, struct crypt_lock_handl
|
||||
log_dbg(cd, "Failed to unlink resource file: %s", res);
|
||||
}
|
||||
|
||||
if ((h->mode == DEV_LOCK_BDEV) && /* was it block device */
|
||||
!flock(h->flock_fd, LOCK_EX | LOCK_NB) && /* lock to drop the file */
|
||||
!resource_by_devno(res, sizeof(res), h->u.bdev.devno, 1) && /* acquire lock resource name */
|
||||
!fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
|
||||
!stat(res, &buf_b) && /* does path file still exist? */
|
||||
same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
|
||||
/* coverity[toctou] */
|
||||
if (unlink(res)) /* yes? unlink the file */
|
||||
log_dbg(cd, "Failed to unlink resource file: %s", res);
|
||||
}
|
||||
|
||||
if (h->mode == DEV_LOCK_NAME)
|
||||
free(h->u.name.name);
|
||||
|
||||
if (close(h->flock_fd))
|
||||
log_dbg(cd, "Failed to close resource fd (%d).", h->flock_fd);
|
||||
log_dbg(cd, "Failed to close lock resource fd (%d).", h->flock_fd);
|
||||
}
|
||||
|
||||
int device_locked(struct crypt_lock_handle *h)
|
||||
@@ -205,10 +268,16 @@ static int verify_lock_handle(const char *device_path, struct crypt_lock_handle
|
||||
struct stat lck_st, res_st;
|
||||
|
||||
/* we locked a regular file, check during device_open() instead. No reason to check now */
|
||||
if (S_ISREG(h->mode))
|
||||
if (h->mode == DEV_LOCK_FILE)
|
||||
return 0;
|
||||
|
||||
if (resource_by_devno(res, sizeof(res), h->devno, 1))
|
||||
if (h->mode == DEV_LOCK_NAME) {
|
||||
if (resource_by_name(res, sizeof(res), h->u.name.name, true))
|
||||
return -EINVAL;
|
||||
} else if (h->mode == DEV_LOCK_BDEV) {
|
||||
if (resource_by_devno(res, sizeof(res), h->u.bdev.devno, true))
|
||||
return -EINVAL;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
if (fstat(h->flock_fd, &lck_st))
|
||||
@@ -217,108 +286,216 @@ static int verify_lock_handle(const char *device_path, struct crypt_lock_handle
|
||||
return (stat(res, &res_st) || !same_inode(lck_st, res_st)) ? -EAGAIN : 0;
|
||||
}
|
||||
|
||||
struct crypt_lock_handle *device_read_lock_handle(struct crypt_device *cd, const char *device_path)
|
||||
static unsigned device_lock_inc(struct crypt_lock_handle *h)
|
||||
{
|
||||
return ++h->refcnt;
|
||||
}
|
||||
|
||||
static unsigned device_lock_dec(struct crypt_lock_handle *h)
|
||||
{
|
||||
assert(h->refcnt);
|
||||
|
||||
return --h->refcnt;
|
||||
}
|
||||
|
||||
static int acquire_and_verify(struct crypt_device *cd, struct device *device, const char *resource, int flock_op, struct crypt_lock_handle **lock)
|
||||
{
|
||||
int r;
|
||||
struct crypt_lock_handle *h = malloc(sizeof(*h));
|
||||
struct crypt_lock_handle *h;
|
||||
|
||||
if (!h)
|
||||
return NULL;
|
||||
if (device && resource)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(h = malloc(sizeof(*h))))
|
||||
return -ENOMEM;
|
||||
|
||||
do {
|
||||
r = acquire_lock_handle(cd, device_path, h);
|
||||
if (r)
|
||||
r = device ? acquire_lock_handle(cd, device, h) : acquire_lock_handle_by_name(cd, resource, h);
|
||||
if (r < 0)
|
||||
break;
|
||||
|
||||
log_dbg(cd, "Acquiring read lock for device %s.", device_path);
|
||||
|
||||
if (flock(h->flock_fd, LOCK_SH)) {
|
||||
log_dbg(cd, "Shared flock failed with errno %d.", errno);
|
||||
r = -EINVAL;
|
||||
if (flock(h->flock_fd, flock_op)) {
|
||||
log_dbg(cd, "Flock on fd %d failed with errno %d.", h->flock_fd, errno);
|
||||
r = (errno == EWOULDBLOCK) ? -EBUSY : -EINVAL;
|
||||
release_lock_handle(cd, h);
|
||||
break;
|
||||
}
|
||||
|
||||
log_dbg(cd, "Verifying read lock handle for device %s.", device_path);
|
||||
log_dbg(cd, "Verifying lock handle for %s.", device ? device_path(device) : resource);
|
||||
|
||||
/*
|
||||
* check whether another libcryptsetup process removed resource file before this
|
||||
* one managed to flock() it. See release_lock_handle() for details
|
||||
*/
|
||||
r = verify_lock_handle(device_path, h);
|
||||
if (r) {
|
||||
flock(h->flock_fd, LOCK_UN);
|
||||
r = verify_lock_handle(device_path(device), h);
|
||||
if (r < 0) {
|
||||
if (flock(h->flock_fd, LOCK_UN))
|
||||
log_dbg(cd, "flock on fd %d failed.", h->flock_fd);
|
||||
release_lock_handle(cd, h);
|
||||
log_dbg(cd, "Read lock handle verification failed.");
|
||||
log_dbg(cd, "Lock handle verification failed.");
|
||||
}
|
||||
} while (r == -EAGAIN);
|
||||
|
||||
if (r) {
|
||||
if (r < 0) {
|
||||
free(h);
|
||||
return NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
*lock = h;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int device_read_lock_internal(struct crypt_device *cd, struct device *device)
|
||||
{
|
||||
int r;
|
||||
struct crypt_lock_handle *h;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
h = device_get_lock_handle(device);
|
||||
|
||||
if (device_locked(h)) {
|
||||
device_lock_inc(h);
|
||||
log_dbg(cd, "Device %s READ lock (or higher) already held.", device_path(device));
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_dbg(cd, "Acquiring read lock for device %s.", device_path(device));
|
||||
|
||||
r = acquire_and_verify(cd, device, NULL, LOCK_SH, &h);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
h->type = DEV_LOCK_READ;
|
||||
h->refcnt = 1;
|
||||
device_set_lock_handle(device, h);
|
||||
|
||||
return h;
|
||||
log_dbg(cd, "Device %s READ lock taken.", device_path(device));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct crypt_lock_handle *device_write_lock_handle(struct crypt_device *cd, const char *device_path)
|
||||
int device_write_lock_internal(struct crypt_device *cd, struct device *device)
|
||||
{
|
||||
int r;
|
||||
struct crypt_lock_handle *h = malloc(sizeof(*h));
|
||||
struct crypt_lock_handle *h;
|
||||
|
||||
if (!h)
|
||||
return NULL;
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
r = acquire_lock_handle(cd, device_path, h);
|
||||
if (r)
|
||||
break;
|
||||
h = device_get_lock_handle(device);
|
||||
|
||||
log_dbg(cd, "Acquiring write lock for device %s.", device_path);
|
||||
|
||||
if (flock(h->flock_fd, LOCK_EX)) {
|
||||
log_dbg(cd, "Exclusive flock failed with errno %d.", errno);
|
||||
r = -EINVAL;
|
||||
release_lock_handle(cd, h);
|
||||
break;
|
||||
}
|
||||
|
||||
log_dbg(cd, "Verifying write lock handle for device %s.", device_path);
|
||||
|
||||
/*
|
||||
* check whether another libcryptsetup process removed resource file before this
|
||||
* one managed to flock() it. See release_lock_handle() for details
|
||||
*/
|
||||
r = verify_lock_handle(device_path, h);
|
||||
if (r) {
|
||||
flock(h->flock_fd, LOCK_UN);
|
||||
release_lock_handle(cd, h);
|
||||
log_dbg(cd, "Write lock handle verification failed.");
|
||||
}
|
||||
} while (r == -EAGAIN);
|
||||
|
||||
if (r) {
|
||||
free(h);
|
||||
return NULL;
|
||||
if (device_locked(h)) {
|
||||
log_dbg(cd, "Device %s WRITE lock already held.", device_path(device));
|
||||
return device_lock_inc(h);
|
||||
}
|
||||
|
||||
h->type = DEV_LOCK_WRITE;
|
||||
log_dbg(cd, "Acquiring write lock for device %s.", device_path(device));
|
||||
|
||||
return h;
|
||||
r = acquire_and_verify(cd, device, NULL, LOCK_EX, &h);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
h->type = DEV_LOCK_WRITE;
|
||||
h->refcnt = 1;
|
||||
device_set_lock_handle(device, h);
|
||||
|
||||
log_dbg(cd, "Device %s WRITE lock taken.", device_path(device));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void device_unlock_handle(struct crypt_device *cd, struct crypt_lock_handle *h)
|
||||
int crypt_read_lock(struct crypt_device *cd, const char *resource, bool blocking, struct crypt_lock_handle **lock)
|
||||
{
|
||||
int r;
|
||||
struct crypt_lock_handle *h;
|
||||
|
||||
if (!resource)
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg(cd, "Acquiring %sblocking read lock for resource %s.", blocking ? "" : "non", resource);
|
||||
|
||||
r = acquire_and_verify(cd, NULL, resource, LOCK_SH | (blocking ? 0 : LOCK_NB), &h);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
h->type = DEV_LOCK_READ;
|
||||
h->refcnt = 1;
|
||||
|
||||
log_dbg(cd, "READ lock for resource %s taken.", resource);
|
||||
|
||||
*lock = h;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_write_lock(struct crypt_device *cd, const char *resource, bool blocking, struct crypt_lock_handle **lock)
|
||||
{
|
||||
int r;
|
||||
struct crypt_lock_handle *h;
|
||||
|
||||
if (!resource)
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg(cd, "Acquiring %sblocking write lock for resource %s.", blocking ? "" : "non", resource);
|
||||
|
||||
r = acquire_and_verify(cd, NULL, resource, LOCK_EX | (blocking ? 0 : LOCK_NB), &h);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
h->type = DEV_LOCK_WRITE;
|
||||
h->refcnt = 1;
|
||||
|
||||
log_dbg(cd, "WRITE lock for resource %s taken.", resource);
|
||||
|
||||
*lock = h;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unlock_internal(struct crypt_device *cd, struct crypt_lock_handle *h)
|
||||
{
|
||||
if (flock(h->flock_fd, LOCK_UN))
|
||||
log_dbg(cd, "flock on fd %d failed.", h->flock_fd);
|
||||
|
||||
release_lock_handle(cd, h);
|
||||
|
||||
free(h);
|
||||
}
|
||||
|
||||
void crypt_unlock_internal(struct crypt_device *cd, struct crypt_lock_handle *h)
|
||||
{
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
/* nested locks are illegal */
|
||||
assert(!device_lock_dec(h));
|
||||
|
||||
log_dbg(cd, "Unlocking %s lock for resource %s.",
|
||||
device_locked_readonly(h) ? "READ" : "WRITE", h->u.name.name);
|
||||
|
||||
unlock_internal(cd, h);
|
||||
}
|
||||
|
||||
void device_unlock_internal(struct crypt_device *cd, struct device *device)
|
||||
{
|
||||
bool readonly;
|
||||
struct crypt_lock_handle *h = device_get_lock_handle(device);
|
||||
unsigned u = device_lock_dec(h);
|
||||
|
||||
if (u)
|
||||
return;
|
||||
|
||||
readonly = device_locked_readonly(h);
|
||||
|
||||
unlock_internal(cd, h);
|
||||
|
||||
log_dbg(cd, "Device %s %s lock released.", device_path(device),
|
||||
readonly ? "READ" : "WRITE");
|
||||
|
||||
device_set_lock_handle(device, NULL);
|
||||
}
|
||||
|
||||
int device_locked_verify(struct crypt_device *cd, int dev_fd, struct crypt_lock_handle *h)
|
||||
{
|
||||
char res[PATH_MAX];
|
||||
|
||||
@@ -24,14 +24,24 @@
|
||||
|
||||
struct crypt_device;
|
||||
struct crypt_lock_handle;
|
||||
struct device;
|
||||
|
||||
int device_locked_readonly(struct crypt_lock_handle *h);
|
||||
int device_locked(struct crypt_lock_handle *h);
|
||||
|
||||
struct crypt_lock_handle *device_read_lock_handle(struct crypt_device *cd, const char *device_path);
|
||||
struct crypt_lock_handle *device_write_lock_handle(struct crypt_device *cd, const char *device_path);
|
||||
void device_unlock_handle(struct crypt_device *cd, struct crypt_lock_handle *h);
|
||||
int device_read_lock_internal(struct crypt_device *cd, struct device *device);
|
||||
int device_write_lock_internal(struct crypt_device *cd, struct device *device);
|
||||
void device_unlock_internal(struct crypt_device *cd, struct device *device);
|
||||
|
||||
int device_locked_verify(struct crypt_device *cd, int fd, struct crypt_lock_handle *h);
|
||||
|
||||
int crypt_read_lock(struct crypt_device *cd, const char *name, bool blocking, struct crypt_lock_handle **lock);
|
||||
int crypt_write_lock(struct crypt_device *cd, const char *name, bool blocking, struct crypt_lock_handle **lock);
|
||||
void crypt_unlock_internal(struct crypt_device *cd, struct crypt_lock_handle *h);
|
||||
|
||||
|
||||
/* Used only in device internal allocation */
|
||||
void device_set_lock_handle(struct device *device, struct crypt_lock_handle *h);
|
||||
struct crypt_lock_handle *device_get_lock_handle(struct device *device);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -111,7 +111,7 @@ static char *lookup_dev_old(int major, int minor)
|
||||
return result;
|
||||
|
||||
/* If it is dm, try DM dir */
|
||||
if (dm_is_dm_device(major, minor)) {
|
||||
if (dm_is_dm_device(major)) {
|
||||
strncpy(buf, dm_get_dir(), PATH_MAX);
|
||||
if ((result = __lookup_dev(buf, dev, 0, 0)))
|
||||
return result;
|
||||
|
||||
@@ -33,6 +33,17 @@ struct crypt_params_verity;
|
||||
struct device;
|
||||
struct crypt_params_integrity;
|
||||
|
||||
/* Device mapper internal flags */
|
||||
#define DM_RESUME_PRIVATE (1 << 4) /* CRYPT_ACTIVATE_PRIVATE */
|
||||
#define DM_SUSPEND_SKIP_LOCKFS (1 << 5)
|
||||
#define DM_SUSPEND_WIPE_KEY (1 << 6)
|
||||
#define DM_SUSPEND_NOFLUSH (1 << 7)
|
||||
|
||||
static inline uint32_t act2dmflags(uint32_t act_flags)
|
||||
{
|
||||
return (act_flags & DM_RESUME_PRIVATE);
|
||||
}
|
||||
|
||||
/* Device mapper backend - kernel support flags */
|
||||
#define DM_KEY_WIPE_SUPPORTED (1 << 0) /* key wipe message */
|
||||
#define DM_LMK_SUPPORTED (1 << 1) /* lmk mode */
|
||||
@@ -51,8 +62,9 @@ struct crypt_params_integrity;
|
||||
#define DM_CAPI_STRING_SUPPORTED (1 << 14) /* support for cryptoapi format cipher definition */
|
||||
#define DM_DEFERRED_SUPPORTED (1 << 15) /* deferred removal of device */
|
||||
#define DM_INTEGRITY_RECALC_SUPPORTED (1 << 16) /* dm-integrity automatic recalculation supported */
|
||||
#define DM_INTEGRITY_BITMAP_SUPPORTED (1 << 17) /* dm-integrity bitmap mode supported */
|
||||
|
||||
typedef enum { DM_CRYPT = 0, DM_VERITY, DM_INTEGRITY, DM_LINEAR, DM_UNKNOWN } dm_target_type;
|
||||
typedef enum { DM_CRYPT = 0, DM_VERITY, DM_INTEGRITY, DM_LINEAR, DM_ERROR, DM_UNKNOWN } dm_target_type;
|
||||
enum tdirection { TARGET_SET = 1, TARGET_QUERY };
|
||||
|
||||
int dm_flags(struct crypt_device *cd, dm_target_type target, uint32_t *flags);
|
||||
@@ -180,13 +192,14 @@ int dm_status_verity_ok(struct crypt_device *cd, const char *name);
|
||||
int dm_status_integrity_failures(struct crypt_device *cd, const char *name, uint64_t *count);
|
||||
int dm_query_device(struct crypt_device *cd, const char *name,
|
||||
uint32_t get_flags, struct crypt_dm_active_device *dmd);
|
||||
int dm_device_deps(struct crypt_device *cd, const char *name, const char *prefix,
|
||||
char **names, size_t names_length);
|
||||
int dm_create_device(struct crypt_device *cd, const char *name,
|
||||
const char *type, struct crypt_dm_active_device *dmd);
|
||||
int dm_reload_device(struct crypt_device *cd, const char *name,
|
||||
struct crypt_dm_active_device *dmd, unsigned resume);
|
||||
int dm_suspend_device(struct crypt_device *cd, const char *name);
|
||||
int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name);
|
||||
int dm_resume_device(struct crypt_device *cd, const char *name, uint32_t flags);
|
||||
struct crypt_dm_active_device *dmd, uint32_t dmflags, unsigned resume);
|
||||
int dm_suspend_device(struct crypt_device *cd, const char *name, uint32_t dmflags);
|
||||
int dm_resume_device(struct crypt_device *cd, const char *name, uint32_t dmflags);
|
||||
int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
|
||||
const struct volume_key *vk);
|
||||
int dm_error_device(struct crypt_device *cd, const char *name);
|
||||
@@ -197,7 +210,7 @@ const char *dm_get_dir(void);
|
||||
int lookup_dm_dev_by_uuid(struct crypt_device *cd, const char *uuid, const char *type);
|
||||
|
||||
/* These are DM helpers used only by utils_devpath file */
|
||||
int dm_is_dm_device(int major, int minor);
|
||||
int dm_is_dm_device(int major);
|
||||
int dm_is_dm_kernel_name(const char *name);
|
||||
char *dm_device_path(const char *prefix, int major, int minor);
|
||||
|
||||
|
||||
@@ -34,8 +34,20 @@ typedef int32_t key_serial_t;
|
||||
#include "utils_crypt.h"
|
||||
#include "utils_keyring.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
#ifdef KERNEL_KEYRING
|
||||
|
||||
static const struct {
|
||||
key_type_t type;
|
||||
const char *type_name;
|
||||
} key_types[] = {
|
||||
{ LOGON_KEY, "logon" },
|
||||
{ USER_KEY, "user" },
|
||||
};
|
||||
|
||||
#include <linux/keyctl.h>
|
||||
|
||||
/* request_key */
|
||||
@@ -86,12 +98,16 @@ int keyring_check(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
int keyring_add_key_in_thread_keyring(const char *key_desc, const void *key, size_t key_size)
|
||||
int keyring_add_key_in_thread_keyring(key_type_t ktype, const char *key_desc, const void *key, size_t key_size)
|
||||
{
|
||||
#ifdef KERNEL_KEYRING
|
||||
key_serial_t kid;
|
||||
const char *type_name = key_type_name(ktype);
|
||||
|
||||
kid = add_key("logon", key_desc, key, key_size, KEY_SPEC_THREAD_KEYRING);
|
||||
if (!type_name || !key_desc)
|
||||
return -EINVAL;
|
||||
|
||||
kid = add_key(type_name, key_desc, key, key_size, KEY_SPEC_THREAD_KEYRING);
|
||||
if (kid < 0)
|
||||
return -errno;
|
||||
|
||||
@@ -101,6 +117,34 @@ int keyring_add_key_in_thread_keyring(const char *key_desc, const void *key, siz
|
||||
#endif
|
||||
}
|
||||
|
||||
/* currently used in client utilities only */
|
||||
int keyring_add_key_in_user_keyring(key_type_t ktype, const char *key_desc, const void *key, size_t key_size)
|
||||
{
|
||||
#ifdef KERNEL_KEYRING
|
||||
const char *type_name = key_type_name(ktype);
|
||||
key_serial_t kid;
|
||||
|
||||
if (!type_name || !key_desc)
|
||||
return -EINVAL;
|
||||
|
||||
kid = add_key(type_name, key_desc, key, key_size, KEY_SPEC_USER_KEYRING);
|
||||
if (kid < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* alias for the same code */
|
||||
int keyring_get_key(const char *key_desc,
|
||||
char **key,
|
||||
size_t *key_size)
|
||||
{
|
||||
return keyring_get_passphrase(key_desc, key, key_size);
|
||||
}
|
||||
|
||||
int keyring_get_passphrase(const char *key_desc,
|
||||
char **passphrase,
|
||||
size_t *passphrase_len)
|
||||
@@ -113,7 +157,7 @@ int keyring_get_passphrase(const char *key_desc,
|
||||
size_t len = 0;
|
||||
|
||||
do
|
||||
kid = request_key("user", key_desc, NULL, 0);
|
||||
kid = request_key(key_type_name(USER_KEY), key_desc, NULL, 0);
|
||||
while (kid < 0 && errno == EINTR);
|
||||
|
||||
if (kid < 0)
|
||||
@@ -148,13 +192,16 @@ int keyring_get_passphrase(const char *key_desc,
|
||||
#endif
|
||||
}
|
||||
|
||||
int keyring_revoke_and_unlink_key(const char *key_desc)
|
||||
static int keyring_revoke_and_unlink_key_type(const char *type_name, const char *key_desc)
|
||||
{
|
||||
#ifdef KERNEL_KEYRING
|
||||
key_serial_t kid;
|
||||
|
||||
if (!type_name || !key_desc)
|
||||
return -EINVAL;
|
||||
|
||||
do
|
||||
kid = request_key("logon", key_desc, NULL, 0);
|
||||
kid = request_key(type_name, key_desc, NULL, 0);
|
||||
while (kid < 0 && errno == EINTR);
|
||||
|
||||
if (kid < 0)
|
||||
@@ -177,3 +224,20 @@ int keyring_revoke_and_unlink_key(const char *key_desc)
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *key_type_name(key_type_t type)
|
||||
{
|
||||
#ifdef KERNEL_KEYRING
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(key_types); i++)
|
||||
if (type == key_types[i].type)
|
||||
return key_types[i].type_name;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int keyring_revoke_and_unlink_key(key_type_t ktype, const char *key_desc)
|
||||
{
|
||||
return keyring_revoke_and_unlink_key_type(key_type_name(ktype), key_desc);
|
||||
}
|
||||
|
||||
@@ -24,17 +24,32 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef enum { LOGON_KEY = 0, USER_KEY } key_type_t;
|
||||
|
||||
const char *key_type_name(key_type_t ktype);
|
||||
|
||||
int keyring_check(void);
|
||||
|
||||
int keyring_get_key(const char *key_desc,
|
||||
char **key,
|
||||
size_t *key_size);
|
||||
|
||||
int keyring_get_passphrase(const char *key_desc,
|
||||
char **passphrase,
|
||||
size_t *passphrase_len);
|
||||
|
||||
int keyring_add_key_in_thread_keyring(
|
||||
key_type_t ktype,
|
||||
const char *key_desc,
|
||||
const void *key,
|
||||
size_t key_size);
|
||||
|
||||
int keyring_revoke_and_unlink_key(const char *key_desc);
|
||||
int keyring_add_key_in_user_keyring(
|
||||
key_type_t ktype,
|
||||
const char *key_desc,
|
||||
const void *key,
|
||||
size_t key_size);
|
||||
|
||||
int keyring_revoke_and_unlink_key(key_type_t ktype, const char *key_desc);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -181,7 +181,7 @@ int init_pbkdf_type(struct crypt_device *cd,
|
||||
|
||||
if (crypt_fips_mode()) {
|
||||
if (pbkdf && strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
log_err(cd, "Only PBKDF2 is supported in FIPS mode.");
|
||||
log_err(cd, _("Only PBKDF2 is supported in FIPS mode."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!pbkdf)
|
||||
@@ -258,9 +258,13 @@ int init_pbkdf_type(struct crypt_device *cd,
|
||||
}
|
||||
}
|
||||
|
||||
log_dbg(cd, "PBKDF %s, hash %s, time_ms %u (iterations %u), max_memory_kb %u, parallel_threads %u.",
|
||||
cd_pbkdf->type ?: "(none)", cd_pbkdf->hash ?: "(none)", cd_pbkdf->time_ms,
|
||||
cd_pbkdf->iterations, cd_pbkdf->max_memory_kb, cd_pbkdf->parallel_threads);
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2))
|
||||
log_dbg(cd, "PBKDF %s-%s, time_ms %u (iterations %u).",
|
||||
cd_pbkdf->type, cd_pbkdf->hash, cd_pbkdf->time_ms, cd_pbkdf->iterations);
|
||||
else
|
||||
log_dbg(cd, "PBKDF %s, time_ms %u (iterations %u), max_memory_kb %u, parallel_threads %u.",
|
||||
cd_pbkdf->type, cd_pbkdf->time_ms, cd_pbkdf->iterations,
|
||||
cd_pbkdf->max_memory_kb, cd_pbkdf->parallel_threads);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
395
lib/utils_storage_wrappers.c
Normal file
395
lib/utils_storage_wrappers.c
Normal file
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Generic wrapper for storage functions
|
||||
* (experimental only)
|
||||
*
|
||||
* Copyright (C) 2018, Ondrej Kozina
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "utils_storage_wrappers.h"
|
||||
#include "internal.h"
|
||||
|
||||
struct crypt_storage_wrapper {
|
||||
crypt_storage_wrapper_type type;
|
||||
int dev_fd;
|
||||
int block_size;
|
||||
size_t mem_alignment;
|
||||
uint64_t data_offset;
|
||||
union {
|
||||
struct {
|
||||
struct crypt_storage *s;
|
||||
uint64_t iv_start;
|
||||
} cb;
|
||||
struct {
|
||||
int dmcrypt_fd;
|
||||
char name[PATH_MAX];
|
||||
} dm;
|
||||
} u;
|
||||
};
|
||||
|
||||
static int crypt_storage_backend_init(struct crypt_device *cd,
|
||||
struct crypt_storage_wrapper *w,
|
||||
uint64_t iv_start,
|
||||
int sector_size,
|
||||
const char *cipher,
|
||||
const char *cipher_mode,
|
||||
const struct volume_key *vk,
|
||||
uint32_t flags)
|
||||
{
|
||||
int r;
|
||||
struct crypt_storage *s;
|
||||
|
||||
/* iv_start, sector_size */
|
||||
r = crypt_storage_init(&s, sector_size, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if ((flags & DISABLE_KCAPI) && crypt_storage_kernel_only(s)) {
|
||||
log_dbg(cd, "Could not initialize userspace block cipher and kernel fallback is disabled.");
|
||||
crypt_storage_destroy(s);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
w->type = USPACE;
|
||||
w->u.cb.s = s;
|
||||
w->u.cb.iv_start = iv_start;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypt_storage_dmcrypt_init(
|
||||
struct crypt_device *cd,
|
||||
struct crypt_storage_wrapper *cw,
|
||||
struct device *device,
|
||||
uint64_t device_offset,
|
||||
uint64_t iv_start,
|
||||
int sector_size,
|
||||
const char *cipher_spec,
|
||||
struct volume_key *vk,
|
||||
int open_flags)
|
||||
{
|
||||
static int counter = 0;
|
||||
char path[PATH_MAX];
|
||||
struct crypt_dm_active_device dmd = {
|
||||
.flags = CRYPT_ACTIVATE_PRIVATE,
|
||||
};
|
||||
int mode, r, fd = -1;
|
||||
|
||||
log_dbg(cd, "Using temporary dmcrypt to access data.");
|
||||
|
||||
if (snprintf(cw->u.dm.name, sizeof(cw->u.dm.name), "temporary-cryptsetup-%d-%d", getpid(), counter++) < 0)
|
||||
return -ENOMEM;
|
||||
if (snprintf(path, sizeof(path), "%s/%s", dm_get_dir(), cw->u.dm.name) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
r = device_block_adjust(cd, device, DEV_OK,
|
||||
device_offset, &dmd.size, &dmd.flags);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Device %s doesn't exist or access denied."),
|
||||
device_path(device));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
mode = open_flags | O_DIRECT;
|
||||
if (dmd.flags & CRYPT_ACTIVATE_READONLY)
|
||||
mode = (open_flags & ~O_ACCMODE) | O_RDONLY;
|
||||
|
||||
if (vk->key_description)
|
||||
dmd.flags |= CRYPT_ACTIVATE_KEYRING_KEY;
|
||||
|
||||
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size,
|
||||
device,
|
||||
vk,
|
||||
cipher_spec,
|
||||
iv_start,
|
||||
device_offset,
|
||||
NULL,
|
||||
0,
|
||||
sector_size);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dm_create_device(cd, cw->u.dm.name, "TEMP", &dmd);
|
||||
if (r < 0) {
|
||||
if (r != -EACCES && r != -ENOTSUP)
|
||||
log_dbg(cd, "error hint would be nice");
|
||||
r = -EIO;
|
||||
}
|
||||
|
||||
dm_targets_free(cd, &dmd);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
fd = open(path, mode);
|
||||
if (fd < 0) {
|
||||
log_dbg(cd, "Failed to open %s", path);
|
||||
dm_remove_device(cd, cw->u.dm.name, CRYPT_DEACTIVATE_FORCE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cw->type = DMCRYPT;
|
||||
cw->u.dm.dmcrypt_fd = fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_storage_wrapper_init(struct crypt_device *cd,
|
||||
struct crypt_storage_wrapper **cw,
|
||||
struct device *device,
|
||||
uint64_t data_offset,
|
||||
uint64_t iv_start,
|
||||
int sector_size,
|
||||
const char *cipher,
|
||||
struct volume_key *vk,
|
||||
uint32_t flags)
|
||||
{
|
||||
int open_flags, r;
|
||||
char _cipher[MAX_CIPHER_LEN], mode[MAX_CIPHER_LEN];
|
||||
struct crypt_storage_wrapper *w;
|
||||
|
||||
/* device-mapper restrictions */
|
||||
if (data_offset & ((1 << SECTOR_SHIFT) - 1))
|
||||
return -EINVAL;
|
||||
|
||||
if (crypt_parse_name_and_mode(cipher, _cipher, NULL, mode))
|
||||
return -EINVAL;
|
||||
|
||||
open_flags = O_CLOEXEC | ((flags & OPEN_READONLY) ? O_RDONLY : O_RDWR);
|
||||
|
||||
w = malloc(sizeof(*w));
|
||||
if (!w)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(w, 0, sizeof(*w));
|
||||
w->data_offset = data_offset;
|
||||
w->mem_alignment = device_alignment(device);
|
||||
w->block_size = device_block_size(cd, device);
|
||||
if (!w->block_size || !w->mem_alignment) {
|
||||
log_dbg(cd, "block size or alignment error.");
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
w->dev_fd = device_open(cd, device, open_flags);
|
||||
if (w->dev_fd < 0) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!strcmp(_cipher, "cipher_null")) {
|
||||
log_dbg(cd, "Requested cipher_null, switching to noop wrapper.");
|
||||
w->type = NONE;
|
||||
*cw = w;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vk) {
|
||||
log_dbg(cd, "no key passed.");
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = crypt_storage_backend_init(cd, w, iv_start, sector_size, _cipher, mode, vk, flags);
|
||||
if (!r) {
|
||||
*cw = w;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_dbg(cd, "Failed to initialize userspace block cipher.");
|
||||
|
||||
if ((r != -ENOTSUP && r != -ENOENT) || (flags & DISABLE_DMCRYPT))
|
||||
goto err;
|
||||
|
||||
r = crypt_storage_dmcrypt_init(cd, w, device, data_offset >> SECTOR_SHIFT, iv_start,
|
||||
sector_size, cipher, vk, open_flags);
|
||||
if (r) {
|
||||
log_dbg(cd, "Dm-crypt backend failed to initialize.");
|
||||
goto err;
|
||||
}
|
||||
*cw = w;
|
||||
return 0;
|
||||
err:
|
||||
crypt_storage_wrapper_destroy(w);
|
||||
/* wrapper destroy */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* offset is relative to sector_start */
|
||||
ssize_t crypt_storage_wrapper_read(struct crypt_storage_wrapper *cw,
|
||||
off_t offset, void *buffer, size_t buffer_length)
|
||||
{
|
||||
return read_lseek_blockwise(cw->dev_fd,
|
||||
cw->block_size,
|
||||
cw->mem_alignment,
|
||||
buffer,
|
||||
buffer_length,
|
||||
cw->data_offset + offset);
|
||||
}
|
||||
|
||||
ssize_t crypt_storage_wrapper_read_decrypt(struct crypt_storage_wrapper *cw,
|
||||
off_t offset, void *buffer, size_t buffer_length)
|
||||
{
|
||||
int r;
|
||||
ssize_t read;
|
||||
|
||||
if (cw->type == DMCRYPT)
|
||||
return read_lseek_blockwise(cw->u.dm.dmcrypt_fd,
|
||||
cw->block_size,
|
||||
cw->mem_alignment,
|
||||
buffer,
|
||||
buffer_length,
|
||||
offset);
|
||||
|
||||
read = read_lseek_blockwise(cw->dev_fd,
|
||||
cw->block_size,
|
||||
cw->mem_alignment,
|
||||
buffer,
|
||||
buffer_length,
|
||||
cw->data_offset + offset);
|
||||
if (cw->type == NONE || read < 0)
|
||||
return read;
|
||||
|
||||
r = crypt_storage_decrypt(cw->u.cb.s,
|
||||
cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
|
||||
read,
|
||||
buffer);
|
||||
if (r)
|
||||
return -EINVAL;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
ssize_t crypt_storage_wrapper_decrypt(struct crypt_storage_wrapper *cw,
|
||||
off_t offset, void *buffer, size_t buffer_length)
|
||||
{
|
||||
int r;
|
||||
ssize_t read;
|
||||
|
||||
if (cw->type == NONE)
|
||||
return 0;
|
||||
|
||||
if (cw->type == DMCRYPT) {
|
||||
/* there's nothing we can do, just read/decrypt via dm-crypt */
|
||||
read = crypt_storage_wrapper_read_decrypt(cw, offset, buffer, buffer_length);
|
||||
if (read < 0 || (size_t)read != buffer_length)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = crypt_storage_decrypt(cw->u.cb.s,
|
||||
cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
|
||||
buffer_length,
|
||||
buffer);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t crypt_storage_wrapper_write(struct crypt_storage_wrapper *cw,
|
||||
off_t offset, void *buffer, size_t buffer_length)
|
||||
{
|
||||
return write_lseek_blockwise(cw->dev_fd,
|
||||
cw->block_size,
|
||||
cw->mem_alignment,
|
||||
buffer,
|
||||
buffer_length,
|
||||
cw->data_offset + offset);
|
||||
}
|
||||
|
||||
ssize_t crypt_storage_wrapper_encrypt_write(struct crypt_storage_wrapper *cw,
|
||||
off_t offset, void *buffer, size_t buffer_length)
|
||||
{
|
||||
if (cw->type == DMCRYPT)
|
||||
return write_lseek_blockwise(cw->u.dm.dmcrypt_fd,
|
||||
cw->block_size,
|
||||
cw->mem_alignment,
|
||||
buffer,
|
||||
buffer_length,
|
||||
offset);
|
||||
|
||||
if (cw->type == USPACE &&
|
||||
crypt_storage_encrypt(cw->u.cb.s,
|
||||
cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
|
||||
buffer_length, buffer))
|
||||
return -EINVAL;
|
||||
|
||||
return write_lseek_blockwise(cw->dev_fd,
|
||||
cw->block_size,
|
||||
cw->mem_alignment,
|
||||
buffer,
|
||||
buffer_length,
|
||||
cw->data_offset + offset);
|
||||
}
|
||||
|
||||
ssize_t crypt_storage_wrapper_encrypt(struct crypt_storage_wrapper *cw,
|
||||
off_t offset, void *buffer, size_t buffer_length)
|
||||
{
|
||||
if (cw->type == NONE)
|
||||
return 0;
|
||||
|
||||
if (cw->type == DMCRYPT)
|
||||
return -ENOTSUP;
|
||||
|
||||
if (crypt_storage_encrypt(cw->u.cb.s,
|
||||
cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
|
||||
buffer_length,
|
||||
buffer))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_storage_wrapper_destroy(struct crypt_storage_wrapper *cw)
|
||||
{
|
||||
if (!cw)
|
||||
return;
|
||||
|
||||
if (cw->type == USPACE)
|
||||
crypt_storage_destroy(cw->u.cb.s);
|
||||
if (cw->type == DMCRYPT) {
|
||||
close(cw->u.dm.dmcrypt_fd);
|
||||
dm_remove_device(NULL, cw->u.dm.name, CRYPT_DEACTIVATE_FORCE);
|
||||
}
|
||||
|
||||
free(cw);
|
||||
}
|
||||
|
||||
int crypt_storage_wrapper_datasync(const struct crypt_storage_wrapper *cw)
|
||||
{
|
||||
if (!cw)
|
||||
return -EINVAL;
|
||||
if (cw->type == DMCRYPT)
|
||||
return fdatasync(cw->u.dm.dmcrypt_fd);
|
||||
else
|
||||
return fdatasync(cw->dev_fd);
|
||||
}
|
||||
|
||||
crypt_storage_wrapper_type crypt_storage_wrapper_get_type(const struct crypt_storage_wrapper *cw)
|
||||
{
|
||||
return cw ? cw->type : NONE;
|
||||
}
|
||||
71
lib/utils_storage_wrappers.h
Normal file
71
lib/utils_storage_wrappers.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Generic wrapper for storage functions
|
||||
* (experimental only)
|
||||
*
|
||||
* Copyright (C) 2018, Ondrej Kozina
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _UTILS_STORAGE_WRAPPERS_H
|
||||
#define _UTILS_STORAGE_WRAPPERS_H
|
||||
|
||||
struct crypt_storage_wrapper;
|
||||
struct device;
|
||||
struct volume_key;
|
||||
struct crypt_device;
|
||||
|
||||
#define DISABLE_USPACE (1 << 0)
|
||||
#define DISABLE_KCAPI (1 << 1)
|
||||
#define DISABLE_DMCRYPT (1 << 2)
|
||||
#define OPEN_READONLY (1 << 3)
|
||||
|
||||
typedef enum {
|
||||
NONE = 0,
|
||||
USPACE,
|
||||
DMCRYPT
|
||||
} crypt_storage_wrapper_type;
|
||||
|
||||
int crypt_storage_wrapper_init(struct crypt_device *cd,
|
||||
struct crypt_storage_wrapper **cw,
|
||||
struct device *device,
|
||||
uint64_t data_offset,
|
||||
uint64_t iv_start,
|
||||
int sector_size,
|
||||
const char *cipher,
|
||||
struct volume_key *vk,
|
||||
uint32_t flags);
|
||||
|
||||
void crypt_storage_wrapper_destroy(struct crypt_storage_wrapper *cw);
|
||||
|
||||
/* !!! when doing 'read' or 'write' all offset values are RELATIVE to data_offset !!! */
|
||||
ssize_t crypt_storage_wrapper_read(struct crypt_storage_wrapper *cw,
|
||||
off_t offset, void *buffer, size_t buffer_length);
|
||||
ssize_t crypt_storage_wrapper_read_decrypt(struct crypt_storage_wrapper *cw,
|
||||
off_t offset, void *buffer, size_t buffer_length);
|
||||
ssize_t crypt_storage_wrapper_decrypt(struct crypt_storage_wrapper *cw,
|
||||
off_t offset, void *buffer, size_t buffer_length);
|
||||
|
||||
ssize_t crypt_storage_wrapper_write(struct crypt_storage_wrapper *cw,
|
||||
off_t offset, void *buffer, size_t buffer_length);
|
||||
ssize_t crypt_storage_wrapper_encrypt_write(struct crypt_storage_wrapper *cw,
|
||||
off_t offset, void *buffer, size_t buffer_length);
|
||||
ssize_t crypt_storage_wrapper_encrypt(struct crypt_storage_wrapper *cw,
|
||||
off_t offset, void *buffer, size_t buffer_length);
|
||||
|
||||
int crypt_storage_wrapper_datasync(const struct crypt_storage_wrapper *cw);
|
||||
|
||||
crypt_storage_wrapper_type crypt_storage_wrapper_get_type(const struct crypt_storage_wrapper *cw);
|
||||
#endif
|
||||
@@ -139,7 +139,7 @@ int crypt_wipe_device(struct crypt_device *cd,
|
||||
int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
|
||||
void *usrptr)
|
||||
{
|
||||
int r, devfd = -1;
|
||||
int r, devfd;
|
||||
size_t bsize, alignment;
|
||||
char *sf = NULL;
|
||||
uint64_t dev_size;
|
||||
@@ -157,7 +157,10 @@ int crypt_wipe_device(struct crypt_device *cd,
|
||||
if (MISALIGNED_512(offset) || MISALIGNED_512(length) || MISALIGNED_512(wipe_block_size))
|
||||
return -EINVAL;
|
||||
|
||||
devfd = device_open(cd, device, O_RDWR);
|
||||
if (device_is_locked(device))
|
||||
devfd = device_open_locked(cd, device, O_RDWR);
|
||||
else
|
||||
devfd = device_open(cd, device, O_RDWR);
|
||||
if (devfd < 0)
|
||||
return errno ? -errno : -EINVAL;
|
||||
|
||||
@@ -179,7 +182,7 @@ int crypt_wipe_device(struct crypt_device *cd,
|
||||
goto out;
|
||||
|
||||
if (lseek64(devfd, offset, SEEK_SET) < 0) {
|
||||
log_err(cd, "Cannot seek to device offset.");
|
||||
log_err(cd, _("Cannot seek to device offset."));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -203,7 +206,7 @@ int crypt_wipe_device(struct crypt_device *cd,
|
||||
r = wipe_block(cd, devfd, pattern, sf, bsize, alignment,
|
||||
wipe_block_size, offset, &need_block_init);
|
||||
if (r) {
|
||||
log_err(cd, "Device wipe error, offset %" PRIu64 ".", offset);
|
||||
log_err(cd,_("Device wipe error, offset %" PRIu64 "."), offset);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -215,9 +218,8 @@ int crypt_wipe_device(struct crypt_device *cd,
|
||||
}
|
||||
}
|
||||
|
||||
device_sync(cd, device, devfd);
|
||||
device_sync(cd, device);
|
||||
out:
|
||||
close(devfd);
|
||||
free(sf);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ int VERITY_read_sb(struct crypt_device *cd,
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
struct verity_sb sb = {};
|
||||
ssize_t hdr_size = sizeof(struct verity_sb);
|
||||
int devfd = 0, sb_version;
|
||||
int devfd, sb_version;
|
||||
|
||||
log_dbg(cd, "Reading VERITY header of size %zu on device %s, offset %" PRIu64 ".",
|
||||
sizeof(struct verity_sb), device_path(device), sb_offset);
|
||||
@@ -84,11 +84,8 @@ int VERITY_read_sb(struct crypt_device *cd,
|
||||
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), &sb, hdr_size,
|
||||
sb_offset) < hdr_size) {
|
||||
close(devfd);
|
||||
sb_offset) < hdr_size)
|
||||
return -EIO;
|
||||
}
|
||||
close(devfd);
|
||||
|
||||
if (memcmp(sb.signature, VERITY_SIGNATURE, sizeof(sb.signature))) {
|
||||
log_err(cd, _("Device %s is not a valid VERITY device."),
|
||||
@@ -160,7 +157,7 @@ int VERITY_write_sb(struct crypt_device *cd,
|
||||
ssize_t hdr_size = sizeof(struct verity_sb);
|
||||
char *algorithm;
|
||||
uuid_t uuid;
|
||||
int r, devfd = 0;
|
||||
int r, devfd;
|
||||
|
||||
log_dbg(cd, "Updating VERITY header of size %zu on device %s, offset %" PRIu64 ".",
|
||||
sizeof(struct verity_sb), device_path(device), sb_offset);
|
||||
@@ -202,8 +199,7 @@ int VERITY_write_sb(struct crypt_device *cd,
|
||||
log_err(cd, _("Error during update of verity header on device %s."),
|
||||
device_path(device));
|
||||
|
||||
device_sync(cd, device, devfd);
|
||||
close(devfd);
|
||||
device_sync(cd, device);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key)
|
||||
|
||||
vk->key_description = NULL;
|
||||
vk->keylength = keylength;
|
||||
vk->id = -1;
|
||||
vk->next = NULL;
|
||||
|
||||
/* keylength 0 is valid => no key */
|
||||
if (vk->keylength) {
|
||||
@@ -64,13 +66,66 @@ int crypt_volume_key_set_description(struct volume_key *vk, const char *key_desc
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crypt_volume_key_set_id(struct volume_key *vk, int id)
|
||||
{
|
||||
if (vk && id >= 0)
|
||||
vk->id = id;
|
||||
}
|
||||
|
||||
int crypt_volume_key_get_id(const struct volume_key *vk)
|
||||
{
|
||||
return vk ? vk->id : -1;
|
||||
}
|
||||
|
||||
struct volume_key *crypt_volume_key_by_id(struct volume_key *vks, int id)
|
||||
{
|
||||
struct volume_key *vk = vks;
|
||||
|
||||
if (id < 0)
|
||||
return NULL;
|
||||
|
||||
while (vk && vk->id != id)
|
||||
vk = vk->next;
|
||||
|
||||
return vk;
|
||||
}
|
||||
|
||||
void crypt_volume_key_add_next(struct volume_key **vks, struct volume_key *vk)
|
||||
{
|
||||
struct volume_key *tmp;
|
||||
|
||||
if (!vks)
|
||||
return;
|
||||
|
||||
if (!*vks) {
|
||||
*vks = vk;
|
||||
return;
|
||||
}
|
||||
|
||||
tmp = *vks;
|
||||
|
||||
while (tmp->next)
|
||||
tmp = tmp->next;
|
||||
|
||||
tmp->next = vk;
|
||||
}
|
||||
|
||||
struct volume_key *crypt_volume_key_next(struct volume_key *vk)
|
||||
{
|
||||
return vk ? vk->next : NULL;
|
||||
}
|
||||
|
||||
void crypt_free_volume_key(struct volume_key *vk)
|
||||
{
|
||||
if (vk) {
|
||||
struct volume_key *vk_next;
|
||||
|
||||
while (vk) {
|
||||
crypt_memzero(vk->key, vk->keylength);
|
||||
vk->keylength = 0;
|
||||
free(CONST_CAST(void*)vk->key_description);
|
||||
vk_next = vk->next;
|
||||
free(vk);
|
||||
vk = vk_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ To start (or continue) re-encryption for <device> use:
|
||||
\-\-progress-frequency, \-\-use-directio, \-\-use-random | \-\-use-urandom, \-\-use-fsync,
|
||||
\-\-uuid, \-\-verbose, \-\-write-log]
|
||||
|
||||
To encrypt data on (not yet encrypted) device, use \fI\-\-new\fR with combination
|
||||
To encrypt data on (not yet encrypted) device, use \fI\-\-new\fR in combination
|
||||
with \fI\-\-reduce-device-size\fR or with \fI\-\-header\fR option for detached header.
|
||||
|
||||
To remove encryption from device, use \fI\-\-decrypt\fR.
|
||||
|
||||
121
man/cryptsetup.8
121
man/cryptsetup.8
@@ -160,6 +160,41 @@ above in LUKS2 metadata (only after successful refresh operation).
|
||||
\-\-disable\-keyring parameter refreshes a device with volume key passed
|
||||
in dm-crypt driver.
|
||||
|
||||
.PP
|
||||
\fIreencrypt\fR <device> or --active-name <name>
|
||||
.IP
|
||||
Run resilient reencryption (LUKS2 device only).
|
||||
|
||||
There are 3 basic modes of operation:
|
||||
|
||||
\(bu device reencryption (\fIreencrypt\fR)
|
||||
|
||||
\(bu device encryption (\fIreencrypt\fR \-\-encrypt)
|
||||
|
||||
\(bu device decryption (\fIreencrypt\fR \-\-decrypt)
|
||||
|
||||
<device> or --active-name <name> is mandatory parameter.
|
||||
|
||||
With <device> parameter cryptsetup looks up active <device> dm mapping.
|
||||
If no active mapping is detected, it starts offline reencryption otherwise online
|
||||
reencryption takes place.
|
||||
|
||||
Reencryption process may be safely interrupted by a user via SIGTERM signal (ctrl+c).
|
||||
|
||||
To resume already initialized or interrupted reencryption, just run the cryptsetup
|
||||
\fIreencrypt\fR command again to continue the reencryption operation.
|
||||
Reencryption may be resumed with different \-\-resilience or \-\-hotzone\-size unless
|
||||
implicit datashift resilience mode is used (reencrypt \-\-encrypt with \-\-reduce-device-size
|
||||
option).
|
||||
|
||||
If the reencryption process was interrupted abruptly (reencryption process crash, system crash, poweroff)
|
||||
it may require recovery. The recovery is currently run automatically on next activation (action \fIopen\fR)
|
||||
when needed.
|
||||
|
||||
Action supports following additional \fB<options>\fR [\-\-encrypt, \-\-decrypt, \-\-device\-size,
|
||||
\-\-resilience, \-\-resilience-hash, \-\-hotzone-size, \-\-init\-only, \-\-resume\-only,
|
||||
\-\-reduce\-device\-size].
|
||||
|
||||
.SH PLAIN MODE
|
||||
Plain dm-crypt encrypts the device sector-by-sector with a
|
||||
single, non-salted hash of the passphrase. No checks
|
||||
@@ -276,7 +311,8 @@ the command prompts for it interactively.
|
||||
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
|
||||
\-\-keyfile\-size, \-\-readonly, \-\-test\-passphrase,
|
||||
\-\-allow\-discards, \-\-header, \-\-key-slot, \-\-master\-key\-file, \-\-token\-id,
|
||||
\-\-token\-only, \-\-disable\-keyring, \-\-disable\-locks, \-\-type, \-\-refresh].
|
||||
\-\-token\-only, \-\-disable\-keyring, \-\-disable\-locks, \-\-type, \-\-refresh,
|
||||
\-\-serialize\-memory\-hard\-pbkdf].
|
||||
.PP
|
||||
\fIluksSuspend\fR <name>
|
||||
.IP
|
||||
@@ -317,7 +353,8 @@ is not required.
|
||||
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
|
||||
\-\-keyfile\-size, \-\-new\-keyfile\-offset,
|
||||
\-\-new\-keyfile\-size, \-\-key\-slot, \-\-master\-key\-file,
|
||||
\-\-iter\-time, \-\-force\-password, \-\-header, \-\-disable\-locks,
|
||||
\-\-force\-password, \-\-header, \-\-disable\-locks,
|
||||
\-\-iter-time, \-\-pbkdf, \-\-pbkdf\-force\-iterations,
|
||||
\-\-unbound, \-\-type, \-\-keyslot\-cipher, \-\-keyslot\-key\-size].
|
||||
.PP
|
||||
\fIluksRemoveKey\fR <device> [<key file with passphrase to be removed>]
|
||||
@@ -360,6 +397,7 @@ inaccessible.
|
||||
|
||||
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
|
||||
\-\-keyfile\-size, \-\-new\-keyfile\-offset,
|
||||
\-\-iter-time, \-\-pbkdf, \-\-pbkdf\-force\-iterations,
|
||||
\-\-new\-keyfile\-size, \-\-key\-slot, \-\-force\-password, \-\-header,
|
||||
\-\-disable\-locks, \-\-type, \-\-keyslot\-cipher, \-\-keyslot\-key\-size].
|
||||
.PP
|
||||
@@ -943,6 +981,19 @@ Hence, if \-\-offset \fIn\fR, and \-\-skip \fIs\fR, sector \fIn\fR
|
||||
(the first sector of the encrypted device) will get a sector number
|
||||
of \fIs\fR for the IV calculation.
|
||||
.TP
|
||||
.B "\-\-device-size \fIsize[units]\fR"
|
||||
Instead of real device size, use specified value.
|
||||
|
||||
It means that only specified area (from the start of the device
|
||||
to the specified size) will be reencrypted.
|
||||
|
||||
If no unit suffix is specified, the size is in bytes.
|
||||
|
||||
Unit suffix can be S for 512 byte sectors, K/M/G/T (or KiB,MiB,GiB,TiB)
|
||||
for units with 1024 base or KB/MB/GB/TB for 1000 base (SI scale).
|
||||
|
||||
\fBWARNING:\fR This is destructive operation when used with reencrypt command.
|
||||
.TP
|
||||
.B "\-\-readonly, \-r"
|
||||
set up a read-only mapping.
|
||||
.TP
|
||||
@@ -1159,8 +1210,8 @@ a restricted environment where locking is impossible to perform
|
||||
(where /run directory cannot be used).
|
||||
.TP
|
||||
.B "\-\-disable\-keyring"
|
||||
Do not load volume key in kernel keyring but use store key directly
|
||||
in the dm-crypt target.
|
||||
Do not load volume key in kernel keyring and store it directly
|
||||
in the dm-crypt target instead.
|
||||
This option is supported only for the LUKS2 format.
|
||||
.TP
|
||||
.B "\-\-key\-description <text>"
|
||||
@@ -1284,6 +1335,68 @@ See \fITCRYPT\fR section for more info.
|
||||
Use a custom Personal Iteration Multiplier (PIM) for VeraCrypt device.
|
||||
See \fITCRYPT\fR section for more info.
|
||||
.TP
|
||||
.B "\-\-serialize\-memory\-hard\-pbkdf"
|
||||
Use a global lock to serialize unlocking of keyslots using memory-hard PBKDF.
|
||||
|
||||
\fBNOTE:\fR This is (ugly) workaround for a specific situation when multiple
|
||||
devices are activated in parallel and system instead of reporting out of memory
|
||||
starts unconditionally stop processes using out-of-memory killer.
|
||||
|
||||
\fBDO NOT USE\fR this switch until you are implementing boot environment
|
||||
with parallel devices activation!
|
||||
.TP
|
||||
.B "\-\-encrypt"
|
||||
Initialize (and run) device encryption (\fIreencrypt\fR action parameter)
|
||||
.TP
|
||||
.B "\-\-decrypt"
|
||||
Initialize (and run) device decryption (\fIreencrypt\fR action parameter)
|
||||
.TP
|
||||
.B "\-\-init\-only"
|
||||
Initialize reencryption (any variant) operation in LUKS2 metadata only and exit. If any
|
||||
reencrypt operation is already initialized in metadata, the command with \-\-init\-only
|
||||
parameter fails.
|
||||
.TP
|
||||
.B "\-\-resume\-only"
|
||||
Resume reencryption (any variant) operation already described in LUKS2 metadata. If no
|
||||
reencrypt operation is initialized, the command with \-\-resume\-only
|
||||
parameter fails. Useful for resuming reencrypt operation without accidentaly trigerring
|
||||
new reencryption operation.
|
||||
.TP
|
||||
.B "\-\-resilience <mode>"
|
||||
Reencryption resilience mode can be one of \fIchecksum\fR, \fIjournal\fR or \fInone\fR.
|
||||
|
||||
\fIchecksum\fR: default mode, where individual checksums of ciphertext hotzone sectors are stored,
|
||||
so the recovery process can detect which sectors where already reencrypted. It requires that the device sector write is atomic.
|
||||
|
||||
\fIjournal\fR: the hotzone is journaled in the binary area (so the data are written twice).
|
||||
|
||||
\fInone\fR: performance mode. There is no protection and the only way it's safe to interrupt
|
||||
the reencryption is similar to old offline reencryption utility. (ctrl+c).
|
||||
|
||||
The option is ignored if reencryption with datashift mode is in progress.
|
||||
.TP
|
||||
.B "\-\-resilience-hash <hash>"
|
||||
The hash algorithm used with "\-\-resilience checksum" only. The default hash is sha256. With other resilience modes, the hash parameter is ignored.
|
||||
.TP
|
||||
.B "\-\-hotzone-size <size>"
|
||||
This option can be used to set an upper limit on the size of reencryption area (hotzone).
|
||||
The <size> can be specified with unit suffix (for example 50M). Note that actual hotzone
|
||||
size may be less than specified <size> due to other limitations (free space in keyslots area or
|
||||
available memory).
|
||||
.TP
|
||||
.B "\-\-reduce\-device\-size <size>"
|
||||
Initialize LUKS2 reencryption with data device size reduction (currently only \-\-encrypt variant is supported).
|
||||
|
||||
Last <size> sectors of <device> will be used to properly initialize device reencryption. That means any
|
||||
data at last <size> sectors will be lost.
|
||||
|
||||
It could be useful if you added some space to underlying partition or logical volume (so last <size> sectors contains no data).
|
||||
|
||||
Recommended minimal size is twice the default LUKS2 header size (\-\-reduce\-device\-size 32M) for \-\-encrypt use case. Be sure to
|
||||
have enough (at least \-\-reduce\-device\-size value of free space at the end of <device>).
|
||||
|
||||
WARNING: This is a destructive operation and cannot be reverted. Use with extreme care - accidentally overwritten filesystems are usually unrecoverable.
|
||||
.TP
|
||||
.B "\-\-version"
|
||||
Show the program version.
|
||||
.TP
|
||||
|
||||
@@ -125,6 +125,21 @@ The file with the integrity key.
|
||||
.TP
|
||||
.B "\-\-integrity\-no\-journal, \-D"
|
||||
Disable journal for integrity device.
|
||||
.TP
|
||||
.B "\-\-integrity\-bitmap\-mode. \-B"
|
||||
Use alternate bitmap mode (available since Linux kernel 5.2) where dm-integrity uses bitmap
|
||||
instead of a journal. If a bit in the bitmap is 1, the corresponding region's data and integrity tags
|
||||
are not synchronized - if the machine crashes, the unsynchronized regions will be recalculated.
|
||||
The bitmap mode is faster than the journal mode, because we don't have to write the data
|
||||
twice, but it is also less reliable, because if data corruption happens
|
||||
when the machine crashes, it may not be detected.
|
||||
.TP
|
||||
.B "\-\-bitmap\-sectors\-per\-bit SECTORS"
|
||||
Number of 512-byte sectors per bitmap bit, the value must be power of two.
|
||||
.TP
|
||||
.B "\-\-bitmap\-flush\-time MS"
|
||||
Bitmap flush time in milliseconds.
|
||||
.TP
|
||||
|
||||
\fBWARNING:\fR
|
||||
In case of a crash, it is possible that the data and integrity tag doesn't match
|
||||
|
||||
@@ -16,6 +16,7 @@ lib/utils_wipe.c
|
||||
lib/utils_keyring.c
|
||||
lib/utils_blkid.c
|
||||
lib/utils_io.c
|
||||
lib/utils_storage_wrappers.c
|
||||
lib/luks1/af.c
|
||||
lib/luks1/keyencryption.c
|
||||
lib/luks1/keymanage.c
|
||||
@@ -32,7 +33,10 @@ lib/luks2/luks2_json_format.c
|
||||
lib/luks2/luks2_json_metadata.c
|
||||
lib/luks2/luks2_keyslot.c
|
||||
lib/luks2/luks2_keyslot_luks2.c
|
||||
lib/luks2/luks2_keyslot_reenc.c
|
||||
lib/luks2/luks2_luks1_convert.c
|
||||
lib/luks2/luks2_reencrypt.c
|
||||
lib/luks2/luks2_segment.c
|
||||
lib/luks2/luks2_token.c
|
||||
lib/luks2/luks2_token_keyring.c
|
||||
src/cryptsetup.c
|
||||
@@ -42,3 +46,4 @@ src/cryptsetup_reencrypt.c
|
||||
src/utils_tools.c
|
||||
src/utils_password.c
|
||||
src/utils_luks2.c
|
||||
src/utils_blockdev.c
|
||||
|
||||
56
po/da.po
56
po/da.po
@@ -4,8 +4,10 @@
|
||||
# Joe Hansen <joedalton2@yahoo.dk>, 2015, 2016, 2017, 2018, 2019.
|
||||
#
|
||||
# Konventioner
|
||||
# argument -> argument
|
||||
# deferred -> udskudt
|
||||
# iteration -> iteration (gennemløb)
|
||||
# parameter -> parameter
|
||||
# probe -> undersøge (bedre mulighed?)
|
||||
# reencryption -> omkryptering
|
||||
# suspended -> suspenderet (skal det være standset i stedet for?)
|
||||
@@ -16,7 +18,7 @@ msgstr ""
|
||||
"Project-Id-Version: cryptsetup-2.1.0\n"
|
||||
"Report-Msgid-Bugs-To: dm-crypt@saout.de\n"
|
||||
"POT-Creation-Date: 2019-01-26 19:02+0100\n"
|
||||
"PO-Revision-Date: 2019-02-05 22:30+0200\n"
|
||||
"PO-Revision-Date: 2019-03-03 22:35+0200\n"
|
||||
"Last-Translator: Joe Hansen <joedalton2@yahoo.dk>\n"
|
||||
"Language-Team: Danish <dansk@dansk-gruppen.dk>\n"
|
||||
"Language: da\n"
|
||||
@@ -35,7 +37,7 @@ msgstr "Kan ikke initialisere enhedsoversætter. Er dm_mod-kernemodulet indlæst
|
||||
|
||||
#: lib/libdevmapper.c:1010
|
||||
msgid "Requested deferred flag is not supported."
|
||||
msgstr "Det anmodte udskudte flag er ikke understøttet."
|
||||
msgstr "Det anmodede udskudte flag er ikke understøttet."
|
||||
|
||||
#: lib/libdevmapper.c:1077
|
||||
#, c-format
|
||||
@@ -199,7 +201,7 @@ msgstr "Sektorstørrelsen på krypteringen er ikke understøttet."
|
||||
|
||||
#: lib/setup.c:1421 lib/setup.c:1720
|
||||
msgid "Device size is not aligned to requested sector size."
|
||||
msgstr "Enhedsstørrelsen er ikke justeret til den anmodte sektorstørrelse."
|
||||
msgstr "Enhedsstørrelsen er ikke justeret til den anmodede sektorstørrelse."
|
||||
|
||||
#: lib/setup.c:1472 lib/setup.c:1591
|
||||
msgid "Can't format LUKS without device."
|
||||
@@ -211,7 +213,7 @@ msgstr "Forespurgte datajustering er ikke kompatibel med dataforskydning."
|
||||
|
||||
#: lib/setup.c:1546 lib/setup.c:1715
|
||||
msgid "WARNING: Data offset is outside of currently available data device.\n"
|
||||
msgstr "ADVARSEL: Dataforskydning er uden for nuværende tilgængelig dataenhed.\n"
|
||||
msgstr "ADVARSEL: Dataforskydning er uden for nuværende tilgængelige dataenhed.\n"
|
||||
|
||||
#: lib/setup.c:1556 lib/setup.c:1735 lib/setup.c:1754 lib/setup.c:2021
|
||||
#, c-format
|
||||
@@ -315,7 +317,7 @@ msgstr "Kan ikke ændre størrelse på loop-enhed."
|
||||
#: lib/setup.c:2666
|
||||
#, c-format
|
||||
msgid "Device %s size is not aligned to requested sector size (%u bytes)."
|
||||
msgstr "Enhedsstørrelsen for %s er ikke justeret til den anmodte sektorstørrelse (%u byte)."
|
||||
msgstr "Enhedsstørrelsen for %s er ikke justeret til den anmodede sektorstørrelse (%u byte)."
|
||||
|
||||
#: lib/setup.c:2725
|
||||
msgid "Do you really want to change UUID of device?"
|
||||
@@ -421,7 +423,7 @@ msgstr "Ugyldig enhed %s."
|
||||
|
||||
#: lib/setup.c:4134
|
||||
msgid "Function not available in FIPS mode."
|
||||
msgstr "Funkton er ikke tilgængelig i FIPS-tilstand."
|
||||
msgstr "Funktion er ikke tilgængelig i FIPS-tilstand."
|
||||
|
||||
#: lib/setup.c:4148
|
||||
msgid "Volume key buffer too small."
|
||||
@@ -494,7 +496,7 @@ msgstr "Kunne ikke køre stat på nøglefil."
|
||||
|
||||
#: lib/utils.c:199 lib/utils.c:220
|
||||
msgid "Cannot seek to requested keyfile offset."
|
||||
msgstr "Kan ikke søge til anmodte nøglefilsforskydning."
|
||||
msgstr "Kan ikke søge til anmodede nøglefilsforskydning."
|
||||
|
||||
#: lib/utils.c:214 lib/utils.c:229 src/utils_password.c:188
|
||||
#: src/utils_password.c:201
|
||||
@@ -515,7 +517,7 @@ msgstr "Nøglefilsstørrelsen er over maksimum."
|
||||
|
||||
#: lib/utils.c:278
|
||||
msgid "Cannot read requested amount of data."
|
||||
msgstr "Kan ikke læse den anmodte datamængde."
|
||||
msgstr "Kan ikke læse den anmodede datamængde."
|
||||
|
||||
#: lib/utils_device.c:184 lib/luks1/keyencryption.c:92
|
||||
#, c-format
|
||||
@@ -572,7 +574,7 @@ msgstr "Enheden %s er for lille."
|
||||
|
||||
#: lib/utils_pbkdf.c:100
|
||||
msgid "Requested PBKDF target time cannot be zero."
|
||||
msgstr "Anmodte PBKDF-måltidspunkt kan ikke være nul."
|
||||
msgstr "Anmodede PBKDF-måltidspunkt kan ikke være nul."
|
||||
|
||||
#: lib/utils_pbkdf.c:106
|
||||
#, c-format
|
||||
@@ -582,11 +584,11 @@ msgstr "Ukendt PBKDF-type %s."
|
||||
#: lib/utils_pbkdf.c:111
|
||||
#, c-format
|
||||
msgid "Requested hash %s is not supported."
|
||||
msgstr "Den anmodte hash %s er ikke understøttet."
|
||||
msgstr "Den anmodede hash %s er ikke understøttet."
|
||||
|
||||
#: lib/utils_pbkdf.c:122
|
||||
msgid "Requested PBKDF type is not supported for LUKS1."
|
||||
msgstr "Den anmodte PBKDF-type er ikke understøttet for LUKS1."
|
||||
msgstr "Den anmodede PBKDF-type er ikke understøttet for LUKS1."
|
||||
|
||||
#: lib/utils_pbkdf.c:128
|
||||
msgid "PBKDF max memory or parallel threads must not be set with pbkdf2."
|
||||
@@ -605,15 +607,15 @@ msgstr "Tvungen hukommelsesomkostning er for lav for %s (minimum er %u kilobyte)
|
||||
#: lib/utils_pbkdf.c:155
|
||||
#, c-format
|
||||
msgid "Requested maximum PBKDF memory cost is too high (maximum is %d kilobytes)."
|
||||
msgstr "Anmodte maksimal PBKDF-hukommelsesomkostning er for høj (maksimum er %d kilobyte)."
|
||||
msgstr "Anmodede maksimal PBKDF-hukommelsesomkostning er for høj (maksimum er %d kilobyte)."
|
||||
|
||||
#: lib/utils_pbkdf.c:160
|
||||
msgid "Requested maximum PBKDF memory cannot be zero."
|
||||
msgstr "Anmodte maksimal PBKDF-hukommelse kan ikke være nul."
|
||||
msgstr "Anmodede maksimal PBKDF-hukommelse kan ikke være nul."
|
||||
|
||||
#: lib/utils_pbkdf.c:164
|
||||
msgid "Requested PBKDF parallel threads cannot be zero."
|
||||
msgstr "Anmodte PBKDF parallelle tråde kan ikke være nul."
|
||||
msgstr "Anmodede PBKDF parallelle tråde kan ikke være nul."
|
||||
|
||||
#: lib/utils_benchmark.c:317
|
||||
msgid "PBKDF benchmark disabled but iterations not set."
|
||||
@@ -719,7 +721,7 @@ msgstr "Enheden %s er ikke en gyldig LUKS-enhed."
|
||||
#: lib/luks1/keymanage.c:247 lib/luks2/luks2_json_metadata.c:1010
|
||||
#, c-format
|
||||
msgid "Requested header backup file %s already exists."
|
||||
msgstr "Den anmodte sikkerhedskopifil %s for teksthoveder findes allerede."
|
||||
msgstr "Den anmodede sikkerhedskopifil %s for teksthoveder findes allerede."
|
||||
|
||||
#: lib/luks1/keymanage.c:249 lib/luks2/luks2_json_metadata.c:1012
|
||||
#, c-format
|
||||
@@ -814,7 +816,7 @@ msgstr "Reparation mislykkedes."
|
||||
#: lib/luks1/keymanage.c:487 lib/luks1/keymanage.c:758
|
||||
#, c-format
|
||||
msgid "Requested LUKS hash %s is not supported."
|
||||
msgstr "Den anmodte LUKS-hash %s er ikke understøttet."
|
||||
msgstr "Den anmodede LUKS-hash %s er ikke understøttet."
|
||||
|
||||
#: lib/luks1/keymanage.c:515 src/cryptsetup.c:960
|
||||
msgid "No known problems detected for LUKS header."
|
||||
@@ -832,7 +834,7 @@ msgstr "Fejl under genlæsning af LUKS-teksthoved efter opdatering på enheden %
|
||||
|
||||
#: lib/luks1/keymanage.c:752
|
||||
msgid "Data offset for LUKS header must be either 0 or higher than header size."
|
||||
msgstr "Dataforskydning for LUKS-teksthoved skal være enten 0 eller højere end teksthovedstørrelse."
|
||||
msgstr "Dataforskydning for LUKS-teksthoved skal være enten 0 eller større end teksthovedstørrelse."
|
||||
|
||||
#: lib/luks1/keymanage.c:763 lib/luks1/keymanage.c:828
|
||||
#: lib/luks2/luks2_json_format.c:207 lib/luks2/luks2_json_metadata.c:909
|
||||
@@ -1082,12 +1084,12 @@ msgstr "Ingen plads for ny nøgleplads."
|
||||
|
||||
#: lib/luks2/luks2_json_format.c:158
|
||||
msgid "Requested data offset is too small."
|
||||
msgstr "Forespurgt dataforskydning er for lille."
|
||||
msgstr "Forespurgte dataforskydning er for lille."
|
||||
|
||||
#: lib/luks2/luks2_json_format.c:195
|
||||
#, c-format
|
||||
msgid "WARNING: keyslots area (%<PRIu64> bytes) is very small, available LUKS2 keyslot count is very limited.\n"
|
||||
msgstr "ADVARSEL: nøglepladsområde (%<PRIu64> byte) er meget lille, tilgængelig LUKS2-nøglepladsantal er meget begrænset.\n"
|
||||
msgstr "ADVARSEL: nøglepladsområde (%<PRIu64> byte) er meget lille, tilgængelige LUKS2-nøglepladsantal er meget begrænset.\n"
|
||||
|
||||
#: lib/luks2/luks2_json_metadata.c:866 lib/luks2/luks2_json_metadata.c:982
|
||||
#: lib/luks2/luks2_json_metadata.c:1055 lib/luks2/luks2_keyslot_luks2.c:105
|
||||
@@ -1253,7 +1255,7 @@ msgstr "ADVARSEL: Tilvalget --keyfile-size bliver ignoreret, læsestørrelsen er
|
||||
#: src/cryptsetup.c:268
|
||||
#, c-format
|
||||
msgid "Detected device signature(s) on %s. Proceeding further may damage existing data."
|
||||
msgstr "Registrerede enhedssignaturer på %s. Videre behanding kan beskadige eksisterende data."
|
||||
msgstr "Registrerede enhedssignaturer på %s. Videre behandling kan beskadige eksisterende data."
|
||||
|
||||
#: src/cryptsetup.c:274 src/cryptsetup.c:969 src/cryptsetup.c:1065
|
||||
#: src/cryptsetup.c:1138 src/cryptsetup.c:1763 src/integritysetup.c:230
|
||||
@@ -1853,7 +1855,7 @@ msgstr "Dump diskenheds (master) nøgle i stedet for information om nøgleplads"
|
||||
|
||||
#: src/cryptsetup.c:2514 src/cryptsetup_reencrypt.c:1622
|
||||
msgid "The size of the encryption key"
|
||||
msgstr "Størrelsen for den krypterede nøgle"
|
||||
msgstr "Krypteringsnøglens størrelse"
|
||||
|
||||
#: src/cryptsetup.c:2514 src/cryptsetup.c:2571 src/integritysetup.c:539
|
||||
#: src/integritysetup.c:543 src/integritysetup.c:547
|
||||
@@ -2121,7 +2123,7 @@ msgstr "Opdater (genaktiver) enhed med nye parametre"
|
||||
|
||||
#: src/cryptsetup.c:2571
|
||||
msgid "LUKS2 keyslot: The size of the encryption key"
|
||||
msgstr "LUKS2-nøgleplads: Størrelsen for den krypterede nøgle"
|
||||
msgstr "LUKS2-nøgleplads: Krypteringsnøglens størrelse"
|
||||
|
||||
#: src/cryptsetup.c:2572
|
||||
msgid "LUKS2 keyslot: The cipher used for keyslot encryption"
|
||||
@@ -2141,7 +2143,7 @@ msgstr "Ukendt handling."
|
||||
|
||||
#: src/cryptsetup.c:2718
|
||||
msgid "Parameter --refresh is only allowed with open or refresh commands.\n"
|
||||
msgstr "Parameter --refresh er kun tilladt for kommandoerne open (åbn) eller refresh (opdater).\n"
|
||||
msgstr "Parameteren --refresh er kun tilladt for kommandoerne open (åbn) eller refresh (opdater).\n"
|
||||
|
||||
#: src/cryptsetup.c:2723
|
||||
msgid "Options --refresh and --test-passphrase are mutually exclusive.\n"
|
||||
@@ -2212,7 +2214,7 @@ msgstr "Negativ nummer for tilvalg er ikke tilladt."
|
||||
|
||||
#: src/cryptsetup.c:2809
|
||||
msgid "Only one --key-file argument is allowed."
|
||||
msgstr "Kun en parameter for --key-file er tilladt."
|
||||
msgstr "Kun et argument for --key-file er tilladt."
|
||||
|
||||
#: src/cryptsetup.c:2813 src/cryptsetup_reencrypt.c:1689
|
||||
#: src/cryptsetup_reencrypt.c:1727
|
||||
@@ -2245,7 +2247,7 @@ msgstr "Ugyldig specifikation for størrelsen på LUKS2-nøgleplads."
|
||||
|
||||
#: src/cryptsetup.c:2842
|
||||
msgid "Option --align-payload and --offset cannot be combined."
|
||||
msgstr "Tilvalget --align-payload og --offset kan ikke kombineres."
|
||||
msgstr "Tilvalgene --align-payload og --offset kan ikke kombineres."
|
||||
|
||||
#: src/cryptsetup.c:2848
|
||||
msgid "Option --skip is supported only for open of plain and loopaes devices.\n"
|
||||
@@ -2269,7 +2271,7 @@ msgstr "Tilvalget --veracrypt er kun understøttet for TCRYPT-enhedstype.\n"
|
||||
|
||||
#: src/cryptsetup.c:2877
|
||||
msgid "Invalid argument for parameter --veracrypt-pim supplied.\n"
|
||||
msgstr "Ugyldigt argument for parameter --veracrypt-pim angivet.\n"
|
||||
msgstr "Ugyldigt argument for parameteren --veracrypt-pim angivet.\n"
|
||||
|
||||
#: src/cryptsetup.c:2881
|
||||
msgid "Option --veracrypt-pim is supported only for VeraCrypt compatible devices.\n"
|
||||
@@ -2542,7 +2544,7 @@ msgstr ""
|
||||
|
||||
#: src/integritysetup.c:528
|
||||
msgid "Path to data device (if separated)"
|
||||
msgstr "Sti til datatjeneste (hvis adskilt)"
|
||||
msgstr "Sti til dataenhed (hvis adskilt)"
|
||||
|
||||
#: src/integritysetup.c:530
|
||||
msgid "Journal size"
|
||||
|
||||
@@ -9,6 +9,7 @@ cryptsetup_SOURCES = \
|
||||
src/utils_tools.c \
|
||||
src/utils_password.c \
|
||||
src/utils_luks2.c \
|
||||
src/utils_blockdev.c \
|
||||
src/cryptsetup.c \
|
||||
src/cryptsetup.h
|
||||
|
||||
|
||||
884
src/cryptsetup.c
884
src/cryptsetup.c
File diff suppressed because it is too large
Load Diff
@@ -69,7 +69,8 @@ void clogger(struct crypt_device *cd, int level, const char *file, int line,
|
||||
void tool_log(int level, const char *msg, void *usrptr __attribute__((unused)));
|
||||
void quiet_log(int level, const char *msg, void *usrptr);
|
||||
|
||||
int yesDialog(const char *msg, void *usrptr __attribute__((unused)));
|
||||
int yesDialog(const char *msg, void *usrptr);
|
||||
int noDialog(const char *msg, void *usrptr);
|
||||
void show_status(int errcode);
|
||||
const char *uuid_or_device(const char *spec);
|
||||
__attribute__ ((noreturn)) \
|
||||
@@ -103,6 +104,7 @@ void tools_clear_line(void);
|
||||
void tools_time_progress(uint64_t device_size, uint64_t bytes,
|
||||
struct timeval *start_time, struct timeval *end_time);
|
||||
int tools_wipe_progress(uint64_t size, uint64_t offset, void *usrptr);
|
||||
int tools_reencrypt_progress(uint64_t size, uint64_t offset, void *usrptr);
|
||||
|
||||
int tools_read_mk(const char *file, char **key, int keysize);
|
||||
int tools_write_mk(const char *file, const char *key, int keysize);
|
||||
@@ -113,6 +115,9 @@ int tools_write_json_file(struct crypt_device *cd, const char *file, const char
|
||||
int tools_detect_signatures(const char *device, int ignore_luks, size_t *count);
|
||||
int tools_wipe_all_signatures(const char *path);
|
||||
|
||||
int tools_lookup_crypt_device(struct crypt_device *cd, const char *type,
|
||||
const char *data_device_path, char *name, size_t name_length);
|
||||
|
||||
/* Log */
|
||||
#define log_dbg(x...) clogger(NULL, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
|
||||
#define log_std(x...) clogger(NULL, CRYPT_LOG_NORMAL, __FILE__, __LINE__, x)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#define PACKAGE_REENC "crypt_reencrypt"
|
||||
#define PACKAGE_REENC "cryptsetup-reencrypt"
|
||||
|
||||
#define NO_UUID "cafecafe-cafe-cafe-cafe-cafecafeeeee"
|
||||
|
||||
@@ -269,20 +269,15 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int create_empty_header(const char *new_file, uint64_t data_sectors)
|
||||
static int create_empty_header(const char *new_file)
|
||||
{
|
||||
int fd, r = 0;
|
||||
|
||||
data_sectors *= SECTOR_SIZE;
|
||||
|
||||
if (!data_sectors)
|
||||
data_sectors = 4096;
|
||||
|
||||
log_dbg("Creating empty file %s of size %" PRIu64 ".", new_file, data_sectors);
|
||||
log_dbg("Creating empty file %s of size 4096.", new_file);
|
||||
|
||||
/* coverity[toctou] */
|
||||
fd = open(new_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
|
||||
if (fd == -1 || posix_fallocate(fd, 0, data_sectors))
|
||||
if (fd == -1 || posix_fallocate(fd, 0, 4096))
|
||||
r = -EINVAL;
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
@@ -709,7 +704,7 @@ static int backup_luks_headers(struct reenc_ctx *rc)
|
||||
|
||||
rc->data_offset = crypt_get_data_offset(cd) + ROUND_SECTOR(opt_reduce_size);
|
||||
|
||||
if ((r = create_empty_header(rc->header_file_new, rc->data_offset)))
|
||||
if ((r = create_empty_header(rc->header_file_new)))
|
||||
goto out;
|
||||
|
||||
params.hash = opt_hash ?: DEFAULT_LUKS1_HASH;
|
||||
@@ -794,7 +789,7 @@ static int backup_fake_header(struct reenc_ctx *rc)
|
||||
}
|
||||
}
|
||||
|
||||
r = create_empty_header(header_file_fake, 0);
|
||||
r = create_empty_header(header_file_fake);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -824,7 +819,7 @@ static int backup_fake_header(struct reenc_ctx *rc)
|
||||
if (rc->reencrypt_mode == DECRYPT)
|
||||
goto out;
|
||||
|
||||
r = create_empty_header(rc->header_file_new, ROUND_SECTOR(opt_reduce_size));
|
||||
r = create_empty_header(rc->header_file_new);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -32,7 +32,9 @@ static const char *opt_journal_size_str = NULL;
|
||||
static uint64_t opt_journal_size = 0;
|
||||
static int opt_interleave_sectors = 0;
|
||||
static int opt_journal_watermark = 0;
|
||||
static int opt_bitmap_sectors_per_bit = 0;
|
||||
static int opt_journal_commit_time = 0;
|
||||
static int opt_bitmap_flush_time = 0;
|
||||
static int opt_tag_size = 0;
|
||||
static int opt_sector_size = 0;
|
||||
static int opt_buffer_sectors = 0;
|
||||
@@ -55,6 +57,7 @@ static int opt_journal_crypt_key_size = 0;
|
||||
|
||||
static int opt_integrity_nojournal = 0;
|
||||
static int opt_integrity_recovery = 0;
|
||||
static int opt_integrity_bitmap = 0;
|
||||
|
||||
static int opt_integrity_recalculate = 0;
|
||||
|
||||
@@ -175,8 +178,9 @@ static int action_format(int arg)
|
||||
struct crypt_params_integrity params = {
|
||||
.journal_size = opt_journal_size,
|
||||
.interleave_sectors = opt_interleave_sectors,
|
||||
.journal_watermark = opt_journal_watermark,
|
||||
.journal_commit_time = opt_journal_commit_time,
|
||||
/* in bitmap mode we have to overload these values... */
|
||||
.journal_watermark = opt_integrity_bitmap ? opt_bitmap_sectors_per_bit : opt_journal_watermark,
|
||||
.journal_commit_time = opt_integrity_bitmap ? opt_bitmap_flush_time : opt_journal_commit_time,
|
||||
.buffer_sectors = opt_buffer_sectors,
|
||||
.tag_size = opt_tag_size,
|
||||
.sector_size = opt_sector_size ?: SECTOR_SIZE,
|
||||
@@ -261,8 +265,9 @@ static int action_open(int arg)
|
||||
{
|
||||
struct crypt_device *cd = NULL;
|
||||
struct crypt_params_integrity params = {
|
||||
.journal_watermark = opt_journal_watermark,
|
||||
.journal_commit_time = opt_journal_commit_time,
|
||||
/* in bitmap mode we have to overload these values... */
|
||||
.journal_watermark = opt_integrity_bitmap ? opt_bitmap_sectors_per_bit : opt_journal_watermark,
|
||||
.journal_commit_time = opt_integrity_bitmap ? opt_bitmap_flush_time : opt_journal_commit_time,
|
||||
.buffer_sectors = opt_buffer_sectors,
|
||||
};
|
||||
uint32_t activate_flags = 0;
|
||||
@@ -298,10 +303,12 @@ static int action_open(int arg)
|
||||
params.journal_crypt = journal_crypt;
|
||||
}
|
||||
|
||||
if (opt_integrity_nojournal)
|
||||
if (opt_integrity_nojournal || opt_integrity_bitmap)
|
||||
activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
|
||||
if (opt_integrity_recovery)
|
||||
activate_flags |= CRYPT_ACTIVATE_RECOVERY;
|
||||
if (opt_integrity_bitmap)
|
||||
activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP;
|
||||
|
||||
if (opt_integrity_recalculate)
|
||||
activate_flags |= CRYPT_ACTIVATE_RECALCULATE;
|
||||
@@ -415,7 +422,10 @@ static int action_status(int arg)
|
||||
cad.flags & CRYPT_ACTIVATE_RECOVERY ? " recovery" : "");
|
||||
log_std(" failures: %" PRIu64 "\n",
|
||||
crypt_get_active_integrity_failures(cd, action_argv[0]));
|
||||
if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL) {
|
||||
if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) {
|
||||
log_std(" bitmap 512-byte sectors per bit: %u\n", ip.journal_watermark);
|
||||
log_std(" bitmap flush interval: %u ms\n", ip.journal_commit_time);
|
||||
} if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL) {
|
||||
log_std(" journal: not active\n");
|
||||
} else {
|
||||
log_std(" journal size: %" PRIu64 " bytes\n", ip.journal_size);
|
||||
@@ -531,6 +541,8 @@ int main(int argc, const char **argv)
|
||||
{ "interleave-sectors", '\0', POPT_ARG_INT, &opt_interleave_sectors, 0, N_("Interleave sectors"), N_("SECTORS") },
|
||||
{ "journal-watermark", '\0', POPT_ARG_INT, &opt_journal_watermark, 0, N_("Journal watermark"),N_("percent") },
|
||||
{ "journal-commit-time",'\0', POPT_ARG_INT, &opt_journal_commit_time,0, N_("Journal commit time"), N_("ms") },
|
||||
{ "bitmap-sectors-per-bit",'\0', POPT_ARG_INT,&opt_bitmap_sectors_per_bit, 0, N_("Number of 512-byte sectors per bit (bitmap mode)."), NULL },
|
||||
{ "bitmap-flush-time", '\0', POPT_ARG_INT, &opt_bitmap_flush_time, 0, N_("Bitmap mode flush time"), N_("ms") },
|
||||
{ "tag-size", 't', POPT_ARG_INT, &opt_tag_size, 0, N_("Tag size (per-sector)"), N_("bytes") },
|
||||
{ "sector-size", 's', POPT_ARG_INT, &opt_sector_size, 0, N_("Sector size"), N_("bytes") },
|
||||
{ "buffer-sectors", '\0', POPT_ARG_INT, &opt_buffer_sectors, 0, N_("Buffers size"), N_("SECTORS") },
|
||||
@@ -549,6 +561,7 @@ int main(int argc, const char **argv)
|
||||
|
||||
{ "integrity-no-journal", 'D', POPT_ARG_NONE, &opt_integrity_nojournal, 0, N_("Disable journal for integrity device"), NULL },
|
||||
{ "integrity-recovery-mode", 'R', POPT_ARG_NONE, &opt_integrity_recovery, 0, N_("Recovery mode (no journal, no tag checking)"), NULL },
|
||||
{ "integrity-bitmap-mode", 'B', POPT_ARG_NONE, &opt_integrity_bitmap, 0, N_("Use bitmap to track changes and disable journal for integrity device"), NULL },
|
||||
{ "integrity-recalculate", '\0', POPT_ARG_NONE, &opt_integrity_recalculate, 0, N_("Recalculate initial tags automatically."), NULL },
|
||||
POPT_TABLEEND
|
||||
};
|
||||
@@ -635,7 +648,7 @@ int main(int argc, const char **argv)
|
||||
opt_journal_commit_time < 0 || opt_tag_size < 0 ||
|
||||
opt_sector_size < 0 || opt_buffer_sectors < 0 ||
|
||||
opt_integrity_key_size < 0 || opt_journal_integrity_key_size < 0 ||
|
||||
opt_journal_crypt_key_size < 0)
|
||||
opt_journal_crypt_key_size < 0 || opt_bitmap_flush_time < 0 || opt_bitmap_sectors_per_bit < 0)
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("Negative number for option not permitted."),
|
||||
poptGetInvocationName(popt_context));
|
||||
@@ -676,6 +689,18 @@ int main(int argc, const char **argv)
|
||||
usage(popt_context, EXIT_FAILURE, _("Journal encryption algorithm must be specified if journal encryption key is used."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_integrity_recovery && opt_integrity_bitmap)
|
||||
usage(popt_context, EXIT_FAILURE, _("Recovery and bitmap mode options are mutually exclusive."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_integrity_bitmap && (opt_journal_integrity_key_file || opt_journal_crypt || opt_journal_watermark || opt_journal_commit_time))
|
||||
usage(popt_context, EXIT_FAILURE, _("Journal options cannot be used in bitmap mode."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (!opt_integrity_bitmap && (opt_bitmap_flush_time || opt_bitmap_sectors_per_bit))
|
||||
usage(popt_context, EXIT_FAILURE, _("Bitmap options can be used only in bitmap mode."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_debug) {
|
||||
opt_verbose = 1;
|
||||
crypt_set_debug_level(-1);
|
||||
|
||||
189
src/utils_blockdev.c
Normal file
189
src/utils_blockdev.c
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Linux block devices helpers
|
||||
*
|
||||
* Copyright (C) 2018-2019 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018-2019 Ondrej Kozina
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "cryptsetup.h"
|
||||
#include <dirent.h>
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
# include <sys/sysmacros.h> /* for major, minor */
|
||||
#endif
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#define DM_UUID_LEN 129
|
||||
#define DM_BY_ID_PREFIX "dm-uuid-"
|
||||
#define DM_BY_ID_PREFIX_LEN 8
|
||||
#define DM_UUID_PREFIX "CRYPT-"
|
||||
#define DM_UUID_PREFIX_LEN 6
|
||||
#define UUID_LEN 37 /* 36 + \0, libuuid ... */
|
||||
|
||||
static int dm_prepare_uuid(const char *type, const char *uuid, char *buf, size_t buflen)
|
||||
{
|
||||
char *ptr, uuid2[UUID_LEN] = {0};
|
||||
uuid_t uu;
|
||||
unsigned i = 0;
|
||||
|
||||
/* Remove '-' chars */
|
||||
if (uuid) {
|
||||
if (uuid_parse(uuid, uu) < 0) {
|
||||
log_dbg("Requested UUID %s has invalid format.", uuid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (ptr = uuid2, i = 0; i < UUID_LEN; i++)
|
||||
if (uuid[i] != '-') {
|
||||
*ptr = uuid[i];
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(buf, buflen, DM_UUID_PREFIX "%s%s%s%s",
|
||||
type ?: "", type ? "-" : "",
|
||||
uuid2[0] ? uuid2 : "", uuid2[0] ? "-" : "");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* return number of holders in general, if matched dm_uuid prefix it's returned via dm_name */
|
||||
/* negative value is error */
|
||||
static int lookup_holder_dm_name(const char *dm_uuid, size_t max_len, dev_t devno, char *dm_name, size_t dm_name_length)
|
||||
{
|
||||
struct dirent *entry;
|
||||
char dm_subpath[PATH_MAX], data_dev_dir[PATH_MAX], uuid[max_len];
|
||||
ssize_t s;
|
||||
struct stat st;
|
||||
int dmfd, fd, len, r = 0; /* not found */
|
||||
DIR *dir;
|
||||
|
||||
if (!dm_name || !dm_name_length)
|
||||
return -EINVAL;
|
||||
|
||||
*dm_name = '\0';
|
||||
|
||||
len = snprintf(data_dev_dir, PATH_MAX, "/sys/dev/block/%u:%u/holders", major(devno), minor(devno));
|
||||
if (len < 0 || len >= PATH_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(dir = opendir(data_dev_dir)))
|
||||
/* map ENOTDIR to ENOENT we'll handle both errors same */
|
||||
return errno == ENOTDIR ? -ENOENT : -errno;
|
||||
|
||||
while (r != 1 && (entry = readdir(dir))) {
|
||||
if (entry->d_name[0] == '.' ||
|
||||
!strncmp(entry->d_name, "..", 2))
|
||||
continue;
|
||||
|
||||
/* there's a holder */
|
||||
r++;
|
||||
|
||||
/* we already have a dm_name, just count remaining holders */
|
||||
if (*dm_name != '\0')
|
||||
continue;
|
||||
|
||||
len = snprintf(dm_subpath, PATH_MAX, "%s/%s", entry->d_name, "dm");
|
||||
if (len < 0 || len >= PATH_MAX) {
|
||||
r = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* looking for dm-X/dm directory, symlinks are fine */
|
||||
dmfd = openat(dirfd(dir), dm_subpath, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
|
||||
if (dmfd < 0)
|
||||
continue;
|
||||
|
||||
fd = openat(dmfd, "uuid", O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
close(dmfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fstat(fd, &st) || !S_ISREG(st.st_mode)) {
|
||||
close(fd);
|
||||
close(dmfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* reads binary data */
|
||||
s = read_buffer(fd, uuid, max_len - 1);
|
||||
close(fd);
|
||||
uuid[s > 0 ? s : 0] = '\0';
|
||||
if (!strncmp(uuid, dm_uuid, strlen(dm_uuid)))
|
||||
log_dbg("Found candidate device %s", entry->d_name);
|
||||
else {
|
||||
close(dmfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
fd = openat(dmfd, "name", O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
close(dmfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fstat(fd, &st) || !S_ISREG(st.st_mode)) {
|
||||
close(fd);
|
||||
close(dmfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* reads binary data */
|
||||
s = read_buffer(fd, dm_name, dm_name_length - 1);
|
||||
close(fd);
|
||||
close(dmfd);
|
||||
if (s > 1) {
|
||||
dm_name[s-1] = '\0';
|
||||
log_dbg("Found dm device %s", dm_name);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int tools_lookup_crypt_device(struct crypt_device *cd, const char *type,
|
||||
const char *data_device_path, char *name, size_t name_length)
|
||||
{
|
||||
int r;
|
||||
char *c;
|
||||
struct stat st;
|
||||
char dev_uuid[DM_UUID_LEN + DM_BY_ID_PREFIX_LEN] = DM_BY_ID_PREFIX;
|
||||
|
||||
if (!dm_prepare_uuid(type, crypt_get_uuid(cd), dev_uuid + DM_BY_ID_PREFIX_LEN, DM_UUID_LEN))
|
||||
return -EINVAL;
|
||||
|
||||
c = strrchr(dev_uuid, '-');
|
||||
if (!c)
|
||||
return -EINVAL;
|
||||
|
||||
/* cut of dm name */
|
||||
*c = '\0';
|
||||
|
||||
log_dbg("Looking for any dm device with prefix: %s", dev_uuid);
|
||||
|
||||
if (stat(data_device_path, &st) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (!S_ISBLK(st.st_mode))
|
||||
return -ENOTBLK;
|
||||
|
||||
r = lookup_holder_dm_name(dev_uuid + DM_BY_ID_PREFIX_LEN, DM_UUID_LEN,
|
||||
st.st_rdev, name, name_length);
|
||||
return r;
|
||||
}
|
||||
@@ -283,6 +283,8 @@ void tools_passphrase_msg(int r)
|
||||
{
|
||||
if (r == -EPERM)
|
||||
log_err(_("No key available with this passphrase."));
|
||||
else if (r == -ENOENT)
|
||||
log_err(_("No usable keyslot is available."));
|
||||
}
|
||||
|
||||
int tools_read_mk(const char *file, char **key, int keysize)
|
||||
|
||||
@@ -116,7 +116,7 @@ void tool_log(int level, const char *msg, void *usrptr __attribute__((unused)))
|
||||
case CRYPT_LOG_DEBUG_JSON:
|
||||
case CRYPT_LOG_DEBUG:
|
||||
if (opt_debug)
|
||||
fprintf(stdout, "# %s\n", msg);
|
||||
fprintf(stdout, "# %s", msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -128,12 +128,12 @@ void quiet_log(int level, const char *msg, void *usrptr)
|
||||
tool_log(level, msg, usrptr);
|
||||
}
|
||||
|
||||
int yesDialog(const char *msg, void *usrptr)
|
||||
static int _dialog(const char *msg, void *usrptr, int default_answer)
|
||||
{
|
||||
const char *fail_msg = (const char *)usrptr;
|
||||
char *answer = NULL;
|
||||
size_t size = 0;
|
||||
int r = 1, block;
|
||||
int r = default_answer, block;
|
||||
|
||||
block = tools_signals_blocked();
|
||||
if (block)
|
||||
@@ -150,9 +150,9 @@ int yesDialog(const char *msg, void *usrptr)
|
||||
log_err(_("Error reading response from terminal."));
|
||||
else
|
||||
log_dbg("Query interrupted on signal.");
|
||||
} else if (strcmp(answer, "YES\n")) {
|
||||
r = 0;
|
||||
if (fail_msg)
|
||||
} else {
|
||||
r = !strcmp(answer, "YES\n");
|
||||
if (!r && fail_msg)
|
||||
log_err("%s", fail_msg);
|
||||
}
|
||||
}
|
||||
@@ -164,6 +164,16 @@ int yesDialog(const char *msg, void *usrptr)
|
||||
return r;
|
||||
}
|
||||
|
||||
int yesDialog(const char *msg, void *usrptr)
|
||||
{
|
||||
return _dialog(msg, usrptr, 1);
|
||||
}
|
||||
|
||||
int noDialog(const char *msg, void *usrptr)
|
||||
{
|
||||
return _dialog(msg, usrptr, 0);
|
||||
}
|
||||
|
||||
void show_status(int errcode)
|
||||
{
|
||||
char *crypt_error;
|
||||
@@ -592,3 +602,19 @@ int tools_is_stdin(const char *key_file)
|
||||
|
||||
return strcmp(key_file, "-") ? 0 : 1;
|
||||
}
|
||||
|
||||
int tools_reencrypt_progress(uint64_t size, uint64_t offset, void *usrptr)
|
||||
{
|
||||
static struct timeval start_time = {}, end_time = {};
|
||||
int r = 0;
|
||||
|
||||
tools_time_progress(size, offset, &start_time, &end_time);
|
||||
|
||||
check_signal(&r);
|
||||
if (r) {
|
||||
tools_clear_line();
|
||||
log_err("\nReencrypt interrupted.");
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
|
||||
function pversion() {
|
||||
if [ ! -x $CRYPTSETUP_PATH/$1 ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo -n "$CRYPTSETUP_PATH/"
|
||||
$CRYPTSETUP_PATH/$1 --version
|
||||
}
|
||||
|
||||
echo "Cryptsetup test environment ($(date))"
|
||||
uname -a
|
||||
|
||||
@@ -8,10 +19,13 @@ if [ -f /etc/os-release ] ; then
|
||||
echo "$PRETTY_NAME ($NAME) $VERSION"
|
||||
fi
|
||||
|
||||
[ -x ../cryptsetup ] && ../cryptsetup --version
|
||||
[ -x ../veritysetup ] && ../veritysetup --version
|
||||
[ -x ../integritysetup ] && ../integritysetup --version
|
||||
[ -x ../cryptsetup-reencrypt ] && ../cryptsetup-reencrypt --version
|
||||
echo "Memory"
|
||||
free -h
|
||||
|
||||
pversion cryptsetup
|
||||
pversion veritysetup
|
||||
pversion integritysetup
|
||||
pversion cryptsetup-reencrypt
|
||||
|
||||
[ $(id -u) != 0 ] && exit 77
|
||||
|
||||
|
||||
@@ -24,8 +24,7 @@ TESTS += verity-compat-test
|
||||
endif
|
||||
|
||||
if REENCRYPT
|
||||
TESTS += reencryption-compat-test reencryption-compat-test2
|
||||
|
||||
TESTS += reencryption-compat-test reencryption-compat-test2 luks2-reencryption-test
|
||||
endif
|
||||
|
||||
if INTEGRITYSETUP
|
||||
@@ -56,6 +55,7 @@ EXTRA_DIST = compatimage.img.xz compatv10image.img.xz \
|
||||
align-test2 verity-compat-test \
|
||||
reencryption-compat-test \
|
||||
reencryption-compat-test2 \
|
||||
luks2-reencryption-test \
|
||||
tcrypt-compat-test \
|
||||
luks1-compat-test \
|
||||
luks2-validation-test generators \
|
||||
@@ -66,7 +66,8 @@ EXTRA_DIST = compatimage.img.xz compatv10image.img.xz \
|
||||
integrity-compat-test \
|
||||
cryptsetup-valg-supps valg.sh valg-api.sh \
|
||||
blockwise-compat \
|
||||
blkid-luks2-pv.img.xz
|
||||
blkid-luks2-pv.img.xz \
|
||||
Makefile.localtest
|
||||
|
||||
CLEANFILES = cryptsetup-tst* valglog* *-fail-*.log
|
||||
clean-local:
|
||||
|
||||
30
tests/Makefile.localtest
Normal file
30
tests/Makefile.localtest
Normal file
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# Makefile to run tests with system binaries
|
||||
# USE: make -f Makefile.localtest tests CRYPTSETUP_PATH=/sbin
|
||||
#
|
||||
CPPFLAGS=-I../lib/ -I../lib/luks1 -DHAVE_DECL_DM_TASK_RETRY_REMOVE -DKERNEL_KEYRING -DHAVE_SYS_SYSMACROS_H -DNO_CRYPTSETUP_PATH
|
||||
CFLAGS=-O2 -g -Wall
|
||||
LDLIBS=-lcryptsetup -ldevmapper
|
||||
TESTS=$(wildcard *-test *-test2) api-test api-test-2
|
||||
|
||||
differ: differ.o
|
||||
$(CC) -o $@ $^
|
||||
|
||||
api-test: api-test.o test_utils.o
|
||||
$(CC) -o $@ $^ $(LDLIBS)
|
||||
|
||||
api-test-2: api-test-2.o test_utils.o
|
||||
$(CC) -o $@ $^ $(LDLIBS)
|
||||
|
||||
tests: differ $(TESTS)
|
||||
@for test in $(sort $(TESTS)); do \
|
||||
echo [$$test]; \
|
||||
./$$test; \
|
||||
[ $$? -ne 77 -a $$? -ne 0 ] && exit 1; \
|
||||
true; \
|
||||
done;
|
||||
|
||||
clean:
|
||||
rm -f *.o differ api-test api-test-2
|
||||
|
||||
.PHONY: clean
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
CRYPTSETUP="../cryptsetup"
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
DEV=""
|
||||
DEV_STACKED="luks0xbabe"
|
||||
DEV_NAME="dummyalign"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
CRYPTSETUP="../cryptsetup"
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
DEV=""
|
||||
DEV_STACKED="luks0xbabe"
|
||||
DEV_NAME="dummyalign"
|
||||
|
||||
@@ -116,6 +116,16 @@ typedef int32_t key_serial_t;
|
||||
#define PASS7 "bbb"
|
||||
#define PASS8 "iii"
|
||||
|
||||
/* Allow to run without config.h */
|
||||
#ifndef DEFAULT_LUKS1_HASH
|
||||
#define DEFAULT_LUKS1_HASH "sha256"
|
||||
#define DEFAULT_LUKS1_ITER_TIME 2000
|
||||
#define DEFAULT_LUKS2_ITER_TIME 2000
|
||||
#define DEFAULT_LUKS2_MEMORY_KB 1048576
|
||||
#define DEFAULT_LUKS2_PARALLEL_THREADS 4
|
||||
#define DEFAULT_LUKS2_PBKDF "argon2i"
|
||||
#endif
|
||||
|
||||
static int _fips_mode = 0;
|
||||
|
||||
static char *DEVICE_1 = NULL;
|
||||
@@ -221,27 +231,29 @@ static void _remove_keyfiles(void)
|
||||
#define DM_RETRY ""
|
||||
#endif
|
||||
|
||||
#define DM_NOSTDERR " 2>/dev/null"
|
||||
|
||||
static void _cleanup_dmdevices(void)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (!stat(DMDIR H_DEVICE, &st))
|
||||
_system("dmsetup remove " DM_RETRY H_DEVICE, 0);
|
||||
_system("dmsetup remove " DM_RETRY H_DEVICE DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DMDIR H_DEVICE_WRONG, &st))
|
||||
_system("dmsetup remove " DM_RETRY H_DEVICE_WRONG, 0);
|
||||
_system("dmsetup remove " DM_RETRY H_DEVICE_WRONG DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DMDIR L_DEVICE_0S, &st))
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_0S, 0);
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_0S DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DMDIR L_DEVICE_1S, &st))
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_1S, 0);
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_1S DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DMDIR L_DEVICE_WRONG, &st))
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_WRONG, 0);
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_WRONG DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DMDIR L_DEVICE_OK, &st))
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_OK, 0);
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_OK DM_NOSTDERR, 0);
|
||||
|
||||
t_dev_offset = 0;
|
||||
}
|
||||
@@ -253,16 +265,16 @@ static void _cleanup(void)
|
||||
//_system("udevadm settle", 0);
|
||||
|
||||
if (!stat(DMDIR CDEVICE_1, &st))
|
||||
_system("dmsetup remove " CDEVICE_1, 0);
|
||||
_system("dmsetup remove " DM_RETRY CDEVICE_1 DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DMDIR CDEVICE_2, &st))
|
||||
_system("dmsetup remove " CDEVICE_2, 0);
|
||||
_system("dmsetup remove " DM_RETRY CDEVICE_2 DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DEVICE_EMPTY, &st))
|
||||
_system("dmsetup remove " DEVICE_EMPTY_name, 0);
|
||||
_system("dmsetup remove " DM_RETRY DEVICE_EMPTY_name DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DEVICE_ERROR, &st))
|
||||
_system("dmsetup remove " DEVICE_ERROR_name, 0);
|
||||
_system("dmsetup remove " DM_RETRY DEVICE_ERROR_name DM_NOSTDERR, 0);
|
||||
|
||||
_cleanup_dmdevices();
|
||||
|
||||
@@ -914,6 +926,25 @@ static void AddDeviceLuks2(void)
|
||||
FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_1, key3, key_size, 0), "VK doesn't match any digest assigned to segment 0");
|
||||
crypt_free(cd);
|
||||
|
||||
/*
|
||||
* Check regression in getting keyslot encryption parameters when
|
||||
* volume key size is unknown (no active keyslots).
|
||||
*/
|
||||
if (!_fips_mode) {
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_1S));
|
||||
crypt_set_iteration_time(cd, 1);
|
||||
OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, NULL));
|
||||
EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, key_size, PASSPHRASE, strlen(PASSPHRASE)), 0);
|
||||
/* drop context copy of volume key */
|
||||
crypt_free(cd);
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_1S));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS, NULL));
|
||||
EQ_(crypt_volume_key_get(cd, CRYPT_ANY_SLOT, key, &key_size, PASSPHRASE, strlen(PASSPHRASE)), 0);
|
||||
OK_(crypt_keyslot_destroy(cd, 0));
|
||||
EQ_(crypt_keyslot_add_by_volume_key(cd, 0, key, key_size, PASSPHRASE, strlen(PASSPHRASE)), 0);
|
||||
crypt_free(cd);
|
||||
}
|
||||
|
||||
_cleanup_dmdevices();
|
||||
}
|
||||
|
||||
@@ -1282,8 +1313,8 @@ static void Luks2HeaderBackup(void)
|
||||
|
||||
// exercise luksOpen using backup header on block device
|
||||
fd = loop_attach(&DEVICE_3, BACKUP_FILE, 0, 0, &ro);
|
||||
NOTFAIL_(fd, "Bad loop device.");
|
||||
close(fd);
|
||||
OK_(fd < 0);
|
||||
OK_(crypt_init(&cd, DEVICE_3));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
|
||||
OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK));
|
||||
@@ -1473,6 +1504,7 @@ static void TokenActivationByKeyring(void)
|
||||
#ifdef KERNEL_KEYRING
|
||||
key_serial_t kid, kid1;
|
||||
struct crypt_device *cd;
|
||||
struct crypt_active_device cad;
|
||||
|
||||
const char *cipher = "aes";
|
||||
const char *cipher_mode = "xts-plain64";
|
||||
@@ -1484,12 +1516,14 @@ static void TokenActivationByKeyring(void)
|
||||
};
|
||||
uint64_t r_payload_offset;
|
||||
|
||||
kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_THREAD_KEYRING);
|
||||
if (kid < 0) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
if (!t_dm_crypt_keyring_support()) {
|
||||
printf("WARNING: Kernel keyring not supported, skipping test.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_THREAD_KEYRING);
|
||||
NOTFAIL_(kid, "Test or kernel keyring are broken.");
|
||||
|
||||
OK_(get_luks2_offsets(1, 0, 0, NULL, &r_payload_offset));
|
||||
OK_(create_dmdevice_over_loop(L_DEVICE_1S, r_payload_offset + 1));
|
||||
|
||||
@@ -1510,16 +1544,10 @@ static void TokenActivationByKeyring(void)
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
crypt_free(cd);
|
||||
|
||||
if (keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING)) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
}
|
||||
NOTFAIL_(keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING), "Test or kernel keyring are broken.");
|
||||
|
||||
kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_PROCESS_KEYRING);
|
||||
if (kid < 0) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
}
|
||||
NOTFAIL_(kid, "Test or kernel keyring are broken.");
|
||||
|
||||
// add token 1 with process keyring key
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_1S));
|
||||
@@ -1537,23 +1565,14 @@ static void TokenActivationByKeyring(void)
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
crypt_free(cd);
|
||||
|
||||
if (keyctl_unlink(kid, KEY_SPEC_PROCESS_KEYRING)) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
}
|
||||
NOTFAIL_(keyctl_unlink(kid, KEY_SPEC_PROCESS_KEYRING), "Test or kernel keyring are broken.");
|
||||
|
||||
// create two tokens and let the cryptsetup unlock the volume with the valid one
|
||||
kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_THREAD_KEYRING);
|
||||
if (kid < 0) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
}
|
||||
NOTFAIL_(kid, "Test or kernel keyring are broken.");
|
||||
|
||||
kid1 = add_key("user", KEY_DESC_TEST1, PASSPHRASE1, strlen(PASSPHRASE1), KEY_SPEC_THREAD_KEYRING);
|
||||
if (kid1 < 0) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
}
|
||||
NOTFAIL_(kid1, "Test or kernel keyring are broken.");
|
||||
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_1S));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
|
||||
@@ -1570,28 +1589,30 @@ static void TokenActivationByKeyring(void)
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_1S));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
|
||||
EQ_(crypt_activate_by_token(cd, CDEVICE_1, 0, NULL, 0), 0);
|
||||
if (t_dm_crypt_keyring_support()) {
|
||||
OK_(crypt_get_active_device(cd, CDEVICE_1, &cad));
|
||||
EQ_(cad.flags & CRYPT_ACTIVATE_KEYRING_KEY, CRYPT_ACTIVATE_KEYRING_KEY);
|
||||
}
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
EQ_(crypt_activate_by_token(cd, CDEVICE_1, 1, NULL, 0), 1);
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
crypt_free(cd);
|
||||
|
||||
if (keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING)) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
}
|
||||
NOTFAIL_(keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING), "Test or kernel keyring are broken.");
|
||||
|
||||
// activate by any token with token 0 having absent pass from keyring
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_1S));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
|
||||
EQ_(crypt_activate_by_token(cd, CDEVICE_1, CRYPT_ANY_TOKEN, NULL, 0), 1);
|
||||
if (t_dm_crypt_keyring_support()) {
|
||||
OK_(crypt_get_active_device(cd, CDEVICE_1, &cad));
|
||||
EQ_(cad.flags & CRYPT_ACTIVATE_KEYRING_KEY, CRYPT_ACTIVATE_KEYRING_KEY);
|
||||
}
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
crypt_free(cd);
|
||||
|
||||
kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_THREAD_KEYRING);
|
||||
if (kid < 0) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
}
|
||||
NOTFAIL_(kid, "Test or kernel keyring are broken.");
|
||||
|
||||
// replace pass for keyslot 0 making token 0 invalid
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_1S));
|
||||
@@ -1622,16 +1643,10 @@ static void TokenActivationByKeyring(void)
|
||||
EQ_(crypt_token_assign_keyslot(cd, 2, 1), 2);
|
||||
crypt_free(cd);
|
||||
|
||||
if (keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING)) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
}
|
||||
NOTFAIL_(keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING), "Test or kernel keyring are broken.");
|
||||
|
||||
kid1 = add_key("user", KEY_DESC_TEST1, PASSPHRASE1, strlen(PASSPHRASE1), KEY_SPEC_THREAD_KEYRING);
|
||||
if (kid1 < 0) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
}
|
||||
NOTFAIL_(kid1, "Test or kernel keyring are broken.");
|
||||
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_1S));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
|
||||
@@ -2581,6 +2596,18 @@ static void Luks2KeyslotAdd(void)
|
||||
const char *mk_hex2 = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1e";
|
||||
size_t key_ret_len, key_size = strlen(mk_hex) / 2;
|
||||
uint64_t r_payload_offset;
|
||||
const struct crypt_pbkdf_type argon2kdf = {
|
||||
.type = "argon2i",
|
||||
.hash = "sha256",
|
||||
.iterations = 4,
|
||||
.max_memory_kb = 32,
|
||||
.parallel_threads = 1,
|
||||
.flags = CRYPT_PBKDF_NO_BENCHMARK,
|
||||
};
|
||||
struct crypt_params_luks2 params2 = {
|
||||
.pbkdf = &argon2kdf,
|
||||
.sector_size = SECTOR_SIZE
|
||||
};
|
||||
|
||||
crypt_decode_key(key, mk_hex, key_size);
|
||||
crypt_decode_key(key2, mk_hex2, key_size);
|
||||
@@ -2590,8 +2617,7 @@ static void Luks2KeyslotAdd(void)
|
||||
|
||||
/* test crypt_keyslot_add_by_key */
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
|
||||
crypt_set_iteration_time(cd, 1);
|
||||
OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, NULL));
|
||||
OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms2));
|
||||
EQ_(crypt_keyslot_add_by_key(cd, 1, key2, key_size, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT), 1);
|
||||
EQ_(crypt_keyslot_add_by_volume_key(cd, 0, key, key_size, PASSPHRASE, strlen(PASSPHRASE)), 0);
|
||||
EQ_(crypt_keyslot_status(cd, 0), CRYPT_SLOT_ACTIVE_LAST);
|
||||
@@ -2650,6 +2676,45 @@ static void Luks2KeyslotAdd(void)
|
||||
|
||||
crypt_free(cd);
|
||||
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
|
||||
OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms2));
|
||||
/* keyslot 0, volume key, digest 0 */
|
||||
EQ_(crypt_keyslot_add_by_key(cd, 0, key, key_size, PASSPHRASE, strlen(PASSPHRASE), 0), 0);
|
||||
/* keyslot 1, unbound key, digest 1 */
|
||||
EQ_(crypt_keyslot_add_by_key(cd, 1, key2, key_size, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT), 1);
|
||||
/* keyslot 2, unbound key, digest 1 */
|
||||
EQ_(crypt_keyslot_add_by_key(cd, 2, key2, key_size, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_DIGEST_REUSE), 2);
|
||||
/* keyslot 3, unbound key, digest 2 */
|
||||
EQ_(crypt_keyslot_add_by_key(cd, 3, key2, key_size - 1, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_DIGEST_REUSE), 3);
|
||||
/* keyslot 4, unbound key, digest 1 */
|
||||
EQ_(crypt_keyslot_add_by_key(cd, CRYPT_ANY_SLOT, key2, key_size, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_DIGEST_REUSE), 4);
|
||||
FAIL_(crypt_keyslot_add_by_key(cd, CRYPT_ANY_SLOT, key, key_size, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_SET), "Illegal");
|
||||
FAIL_(crypt_keyslot_add_by_key(cd, CRYPT_ANY_SLOT, key, key_size, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_SET | CRYPT_VOLUME_KEY_DIGEST_REUSE), "Illegal");
|
||||
/* Such key doesn't exist, nothing to reuse */
|
||||
FAIL_(crypt_keyslot_add_by_key(cd, CRYPT_ANY_SLOT, key2, key_size - 2, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_DIGEST_REUSE), "Key digest doesn't match any existing.");
|
||||
/* Keyslot 5, volume key, digest 0 */
|
||||
EQ_(crypt_keyslot_add_by_key(cd, 5, key, key_size, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_DIGEST_REUSE), 5);
|
||||
|
||||
OK_(crypt_activate_by_volume_key(cd, NULL, key, key_size, 0));
|
||||
EQ_(crypt_keyslot_add_by_key(cd, 1, NULL, key_size, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_SET), 1);
|
||||
OK_(crypt_activate_by_volume_key(cd, NULL, key2, key_size, 0));
|
||||
FAIL_(crypt_activate_by_volume_key(cd, NULL, key, key_size, 0), "Not a volume key");
|
||||
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 1, PASSPHRASE1, strlen(PASSPHRASE1), 0), 1);
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 2, PASSPHRASE1, strlen(PASSPHRASE1), 0), 2);
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, 0, PASSPHRASE, strlen(PASSPHRASE), 0), "No volume key keyslot");
|
||||
|
||||
/* TODO: key is unusable with aes-xts */
|
||||
// FAIL_(crypt_keyslot_add_by_key(cd, 3, NULL, 0, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_SET), "Unusable key with segment cipher");
|
||||
|
||||
EQ_(crypt_keyslot_add_by_key(cd, 5, NULL, 0, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_SET), 5);
|
||||
FAIL_(crypt_activate_by_volume_key(cd, NULL, key2, key_size, 0), "Not a volume key");
|
||||
EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 5, PASSPHRASE1, strlen(PASSPHRASE1), 0), 5);
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
|
||||
crypt_free(cd);
|
||||
|
||||
_cleanup_dmdevices();
|
||||
}
|
||||
|
||||
@@ -2789,13 +2854,16 @@ static void Luks2ActivateByKeyring(void)
|
||||
const char *cipher = "aes";
|
||||
const char *cipher_mode = "xts-plain64";
|
||||
|
||||
kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_THREAD_KEYRING);
|
||||
kid1 = add_key("user", KEY_DESC_TEST1, PASSPHRASE1, strlen(PASSPHRASE1), KEY_SPEC_THREAD_KEYRING);
|
||||
if (kid < 0 || kid1 < 0) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
if (!t_dm_crypt_keyring_support()) {
|
||||
printf("WARNING: Kernel keyring not supported, skipping test.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_THREAD_KEYRING);
|
||||
NOTFAIL_(kid, "Test or kernel keyring are broken.");
|
||||
kid1 = add_key("user", KEY_DESC_TEST1, PASSPHRASE1, strlen(PASSPHRASE1), KEY_SPEC_THREAD_KEYRING);
|
||||
NOTFAIL_(kid1, "Test or kernel keyring are broken.");
|
||||
|
||||
OK_(get_luks2_offsets(1, 0, 0, NULL, &r_payload_offset));
|
||||
OK_(create_dmdevice_over_loop(L_DEVICE_OK, r_payload_offset + 1));
|
||||
|
||||
@@ -2830,15 +2898,8 @@ static void Luks2ActivateByKeyring(void)
|
||||
FAIL_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST1, 0, 0), "Failed to unclock keyslot");
|
||||
crypt_free(cd);
|
||||
|
||||
if (keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING)) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (keyctl_unlink(kid1, KEY_SPEC_THREAD_KEYRING)) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
}
|
||||
NOTFAIL_(keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING), "Test or kernel keyring are broken.");
|
||||
NOTFAIL_(keyctl_unlink(kid1, KEY_SPEC_THREAD_KEYRING), "Test or kernel keyring are broken.");
|
||||
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
|
||||
@@ -2993,17 +3054,16 @@ static void Luks2Requirements(void)
|
||||
OK_(crypt_activate_by_volume_key(cd, NULL, key, key_size, t_dm_crypt_keyring_support() ? CRYPT_ACTIVATE_KEYRING_KEY : 0));
|
||||
|
||||
#ifdef KERNEL_KEYRING
|
||||
kid = add_key("user", KEY_DESC_TEST0, "aaa", 3, KEY_SPEC_THREAD_KEYRING);
|
||||
if (kid < 0) {
|
||||
printf("Test or kernel keyring are broken.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (t_dm_crypt_keyring_support()) {
|
||||
kid = add_key("user", KEY_DESC_TEST0, "aaa", 3, KEY_SPEC_THREAD_KEYRING);
|
||||
NOTFAIL_(kid, "Test or kernel keyring are broken.");
|
||||
|
||||
/* crypt_activate_by_keyring (restricted for activation only) */
|
||||
FAIL_((r = crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST0, 0, 0)), "Unmet requirements detected");
|
||||
EQ_(r, -ETXTBSY);
|
||||
OK_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST0, 0, 0));
|
||||
OK_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST0, 0, t_dm_crypt_keyring_support() ? CRYPT_ACTIVATE_KEYRING_KEY : 0));
|
||||
/* crypt_activate_by_keyring (restricted for activation only) */
|
||||
FAIL_((r = crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST0, 0, 0)), "Unmet requirements detected");
|
||||
EQ_(r, t_dm_crypt_keyring_support() ? -ETXTBSY : -EINVAL);
|
||||
OK_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST0, 0, 0));
|
||||
OK_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST0, 0, CRYPT_ACTIVATE_KEYRING_KEY));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* crypt_volume_key_verify (unrestricted) */
|
||||
@@ -3087,10 +3147,12 @@ static void Luks2Requirements(void)
|
||||
|
||||
/* crypt_activate_by_token (restricted for activation only) */
|
||||
#ifdef KERNEL_KEYRING
|
||||
FAIL_((r = crypt_activate_by_token(cd, CDEVICE_1, 1, NULL, 0)), ""); // supposed to be silent
|
||||
EQ_(r, -ETXTBSY);
|
||||
OK_(crypt_activate_by_token(cd, NULL, 1, NULL, 0));
|
||||
OK_(crypt_activate_by_token(cd, NULL, 1, NULL, t_dm_crypt_keyring_support() ? CRYPT_ACTIVATE_KEYRING_KEY : 0));
|
||||
if (t_dm_crypt_keyring_support()) {
|
||||
FAIL_((r = crypt_activate_by_token(cd, CDEVICE_1, 1, NULL, 0)), ""); // supposed to be silent
|
||||
EQ_(r, -ETXTBSY);
|
||||
OK_(crypt_activate_by_token(cd, NULL, 1, NULL, 0));
|
||||
OK_(crypt_activate_by_token(cd, NULL, 1, NULL, CRYPT_ACTIVATE_KEYRING_KEY));
|
||||
}
|
||||
#endif
|
||||
OK_(get_luks2_offsets(1, 8192, 0, NULL, &r_payload_offset));
|
||||
OK_(create_dmdevice_over_loop(L_DEVICE_OK, r_payload_offset + 2));
|
||||
@@ -3506,7 +3568,12 @@ int main(int argc, char *argv[])
|
||||
printf("You must be root to run this test.\n");
|
||||
exit(77);
|
||||
}
|
||||
|
||||
#ifndef NO_CRYPTSETUP_PATH
|
||||
if (getenv("CRYPTSETUP_PATH")) {
|
||||
printf("Cannot run this test with CRYPTSETUP_PATH set.\n");
|
||||
exit(77);
|
||||
}
|
||||
#endif
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp("-v", argv[i]) || !strcmp("--verbose", argv[i]))
|
||||
_verbose = 1;
|
||||
|
||||
@@ -143,27 +143,29 @@ static void _remove_keyfiles(void)
|
||||
#define DM_RETRY ""
|
||||
#endif
|
||||
|
||||
#define DM_NOSTDERR " 2>/dev/null"
|
||||
|
||||
static void _cleanup_dmdevices(void)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (!stat(DMDIR H_DEVICE, &st))
|
||||
_system("dmsetup remove " DM_RETRY H_DEVICE, 0);
|
||||
_system("dmsetup remove " DM_RETRY H_DEVICE DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DMDIR H_DEVICE_WRONG, &st))
|
||||
_system("dmsetup remove " DM_RETRY H_DEVICE_WRONG, 0);
|
||||
_system("dmsetup remove " DM_RETRY H_DEVICE_WRONG DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DMDIR L_DEVICE_0S, &st))
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_0S, 0);
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_0S DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DMDIR L_DEVICE_1S, &st))
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_1S, 0);
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_1S DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DMDIR L_DEVICE_WRONG, &st))
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_WRONG, 0);
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_WRONG DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DMDIR L_DEVICE_OK, &st))
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_OK, 0);
|
||||
_system("dmsetup remove " DM_RETRY L_DEVICE_OK DM_NOSTDERR, 0);
|
||||
|
||||
t_dev_offset = 0;
|
||||
}
|
||||
@@ -175,16 +177,16 @@ static void _cleanup(void)
|
||||
//_system("udevadm settle", 0);
|
||||
|
||||
if (!stat(DMDIR CDEVICE_1, &st))
|
||||
_system("dmsetup remove " DM_RETRY CDEVICE_1, 0);
|
||||
_system("dmsetup remove " DM_RETRY CDEVICE_1 DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DMDIR CDEVICE_2, &st))
|
||||
_system("dmsetup remove " DM_RETRY CDEVICE_2, 0);
|
||||
_system("dmsetup remove " DM_RETRY CDEVICE_2 DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DEVICE_EMPTY, &st))
|
||||
_system("dmsetup remove " DM_RETRY DEVICE_EMPTY_name, 0);
|
||||
_system("dmsetup remove " DM_RETRY DEVICE_EMPTY_name DM_NOSTDERR, 0);
|
||||
|
||||
if (!stat(DEVICE_ERROR, &st))
|
||||
_system("dmsetup remove " DM_RETRY DEVICE_ERROR_name, 0);
|
||||
_system("dmsetup remove " DM_RETRY DEVICE_ERROR_name DM_NOSTDERR, 0);
|
||||
|
||||
_cleanup_dmdevices();
|
||||
|
||||
@@ -527,8 +529,8 @@ static void AddDevicePlain(void)
|
||||
EQ_(r_size>>SECTOR_SHIFT, params.size + 10);
|
||||
EQ_(crypt_status(cd,CDEVICE_1),CRYPT_ACTIVE);
|
||||
fd = open(path, O_RDONLY);
|
||||
NOTFAIL_(fd, "Bad loop device.");
|
||||
close(fd);
|
||||
OK_(fd < 0);
|
||||
|
||||
// resize to minimal size
|
||||
OK_(crypt_resize(cd,CDEVICE_1, 1)); // minimal device size
|
||||
@@ -920,7 +922,7 @@ static void AddDeviceLuks(void)
|
||||
OK_(crypt_keyslot_get_pbkdf(cd, 1, &pbkdf));
|
||||
OK_(strcmp(pbkdf.type, CRYPT_KDF_PBKDF2));
|
||||
OK_(strcmp(pbkdf.hash, params.hash));
|
||||
EQ_(1000, pbkdf.iterations); /* set by minimum iterations above */
|
||||
OK_(pbkdf.iterations < 1000); /* set by minimum iterations above */
|
||||
EQ_(0, pbkdf.max_memory_kb);
|
||||
EQ_(0, pbkdf.parallel_threads);
|
||||
|
||||
@@ -1312,8 +1314,8 @@ static void LuksHeaderBackup(void)
|
||||
|
||||
// exercise luksOpen using backup header on block device
|
||||
fd = loop_attach(&DEVICE_3, BACKUP_FILE, 0, 0, &ro);
|
||||
NOTFAIL_(fd, "Bad loop device.");
|
||||
close(fd);
|
||||
OK_(fd < 0);
|
||||
OK_(crypt_init(&cd, DEVICE_3));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS1, NULL));
|
||||
OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK));
|
||||
@@ -1876,7 +1878,12 @@ int main(int argc, char *argv[])
|
||||
printf("You must be root to run this test.\n");
|
||||
exit(77);
|
||||
}
|
||||
|
||||
#ifndef NO_CRYPTSETUP_PATH
|
||||
if (getenv("CRYPTSETUP_PATH")) {
|
||||
printf("Cannot run this test with CRYPTSETUP_PATH set.\n");
|
||||
exit(77);
|
||||
}
|
||||
#endif
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp("-v", argv[i]) || !strcmp("--verbose", argv[i]))
|
||||
_verbose = 1;
|
||||
|
||||
@@ -58,6 +58,7 @@ int _system(const char *command, int warn);
|
||||
void register_cleanup(void (*cleanup)(void));
|
||||
|
||||
void check_ok(int status, int line, const char *func);
|
||||
void check_ok_return(int status, int line, const char *func);
|
||||
void check_ko(int status, int line, const char *func);
|
||||
void check_equal(int line, const char *func, int64_t x, int64_t y);
|
||||
void check_null(int line, const char *func, const void *x);
|
||||
@@ -68,6 +69,9 @@ void xlog(const char *msg, const char *tst, const char *func, int line, const ch
|
||||
#define OK_(x) do { xlog("(success)", #x, __FUNCTION__, __LINE__, NULL); \
|
||||
check_ok((x), __LINE__, __FUNCTION__); \
|
||||
} while(0)
|
||||
#define NOTFAIL_(x, y) do { xlog("(notfail)", #x, __FUNCTION__, __LINE__, y); \
|
||||
check_ok_return((x), __LINE__, __FUNCTION__); \
|
||||
} while(0)
|
||||
#define FAIL_(x, y) do { xlog("(fail) ", #x, __FUNCTION__, __LINE__, y); \
|
||||
check_ko((x), __LINE__, __FUNCTION__); \
|
||||
} while(0)
|
||||
|
||||
@@ -304,6 +304,8 @@ run_all() {
|
||||
RUN "$BD_FAIL" $1 write_lseek_blockwise $((BSIZE+1)) $BSIZE $((DEVSIZE-BSIZE))
|
||||
}
|
||||
|
||||
[ -n "$CRYPTSETUP_PATH" ] && skip "Cannot run this test with CRYPTSETUP_PATH set."
|
||||
|
||||
which $STRACE > /dev/null 2>&1 || unset STRACE
|
||||
test -x $BW_UNIT || skip "Run \"make `basename $BW_UNIT`\" first"
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
PS4='$LINENO:'
|
||||
CRYPTSETUP=../cryptsetup
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
|
||||
CRYPTSETUP_VALGRIND=../.libs/cryptsetup
|
||||
CRYPTSETUP_LIB_VALGRIND=../.libs
|
||||
@@ -200,9 +201,9 @@ echo $PWD0 | $CRYPTSETUP luksRemoveKey $IMG || fail
|
||||
echo $PWD2 | $CRYPTSETUP luksRemoveKey $IMG || fail
|
||||
# check if keys were deleted
|
||||
echo $PWD0 | $CRYPTSETUP luksOpen $IMG --test-passphrase 2>/dev/null && fail
|
||||
[ $? -ne 2 ] && fail "luksOpen should return EPERM exit code"
|
||||
[ $? -ne 1 ] && fail "luksOpen should return ENOENT exit code"
|
||||
echo $PWD2 | $CRYPTSETUP luksOpen $IMG --test-passphrase 2>/dev/null && fail
|
||||
[ $? -ne 2 ] && fail "luksOpen should return EPERM exit code"
|
||||
[ $? -ne 1 ] && fail "luksOpen should return ENOENT exit code"
|
||||
echo "[6] kill slot"
|
||||
# format new luks device with active keys PWD1, PWD2
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks1 $IMG $FAST_PBKDF_OPT || fail
|
||||
@@ -652,7 +653,7 @@ prepare "[27] luksOpen with specified key slot number" wipe
|
||||
# first, let's try passphrase option
|
||||
echo $PWD3 | $CRYPTSETUP luksFormat --type luks1 $FAST_PBKDF_OPT -S 5 $LOOPDEV || fail
|
||||
check $LUKS_HEADER $KEY_SLOT5 $KEY_MATERIAL5
|
||||
echo $PWD3 | $CRYPTSETUP luksOpen -S 4 $LOOPDEV $DEV_NAME && fail
|
||||
echo $PWD3 | $CRYPTSETUP luksOpen -S 4 $LOOPDEV $DEV_NAME 2>/dev/null && fail
|
||||
[ -b /dev/mapper/$DEV_NAME ] && fail
|
||||
echo $PWD3 | $CRYPTSETUP luksOpen -S 5 $LOOPDEV $DEV_NAME || fail
|
||||
check_exists
|
||||
@@ -687,6 +688,7 @@ echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks1 $FAST_PBKDF_OPT $LOOPDEV --h
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks1 $FAST_PBKDF_OPT $LOOPDEV --header $HEADER_IMG --offset 80000 >/dev/null 2>&1 || fail
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks1 $FAST_PBKDF_OPT $LOOPDEV --header $HEADER_IMG --offset 8192 || fail
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks1 $FAST_PBKDF_OPT $LOOPDEV --header $HEADER_IMG --offset 0 || fail
|
||||
echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV-missing --header $HEADER_IMG $DEV_NAME 2>/dev/null && fail
|
||||
echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV --header $HEADER_IMG $DEV_NAME || fail
|
||||
$CRYPTSETUP -q resize $DEV_NAME --size 100 --header $HEADER_IMG || fail
|
||||
$CRYPTSETUP -q status $DEV_NAME --header $HEADER_IMG | grep "size:" | grep -q "100 sectors" || fail
|
||||
@@ -848,7 +850,7 @@ eval spawn $CRYPTSETUP luksOpen -v $LOOPDEV -T 1 --test-passphrase
|
||||
expect timeout abort "Enter passphrase for $LOOPDEV:"
|
||||
sleep 0.1
|
||||
send "$PWD0\n"
|
||||
expect timeout abort "No key available with this passphrase."
|
||||
expect timeout abort "No usable keyslot is available."
|
||||
expect timeout abort eof
|
||||
exit
|
||||
EOF
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
PS4='$LINENO:'
|
||||
CRYPTSETUP=../cryptsetup
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
|
||||
CRYPTSETUP_VALGRIND=../.libs/cryptsetup
|
||||
CRYPTSETUP_LIB_VALGRIND=../.libs
|
||||
@@ -40,11 +41,6 @@ TEST_UUID="12345678-1234-1234-1234-123456789abc"
|
||||
LOOPDEV=$(losetup -f 2>/dev/null)
|
||||
[ -f /etc/system-fips ] && FIPS_MODE=$(cat /proc/sys/crypto/fips_enabled 2>/dev/null)
|
||||
|
||||
LOCK_DIR=$(grep DEFAULT_LUKS2_LOCK_PATH ../config.h | cut -d\" -f 2)
|
||||
HAVE_KEYRING=$(grep -e "#define KERNEL_KEYRING" ../config.h)
|
||||
test -n "$HAVE_KEYRING" || HAVE_KEYRING=0
|
||||
HAVE_KEYRING=${HAVE_KEYRING: -1}
|
||||
|
||||
function remove_mapping()
|
||||
{
|
||||
[ -b /dev/mapper/$DEV_NAME3 ] && dmsetup remove $DEV_NAME3
|
||||
@@ -168,6 +164,8 @@ function dm_crypt_keyring_support()
|
||||
VER_MIN=$(echo $VER_STR | cut -f 2 -d.)
|
||||
VER_PTC=$(echo $VER_STR | cut -f 3 -d.)
|
||||
|
||||
test -d /proc/sys/kernel/keys || return 1
|
||||
|
||||
[ $VER_MAJ -gt 1 ] && return 0
|
||||
[ $VER_MAJ -eq 1 -a $VER_MIN -gt 18 ] && return 0
|
||||
[ $VER_MAJ -eq 1 -a $VER_MIN -eq 18 -a $VER_PTC -ge 1 ] && return 0
|
||||
@@ -213,13 +211,28 @@ function load_key()
|
||||
keyctl add $@ >/dev/null
|
||||
}
|
||||
|
||||
export LANG=C
|
||||
function setup_luks2_env() {
|
||||
echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 $FAST_PBKDF_OPT $LOOPDEV || fail
|
||||
$CRYPTSETUP luksDump $LOOPDEV >/dev/null || fail
|
||||
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME || fail
|
||||
HAVE_KEYRING=$($CRYPTSETUP status $DEV_NAME | grep "keyring")
|
||||
if [ -n "$HAVE_KEYRING" ]; then
|
||||
HAVE_KEYRING=1
|
||||
else
|
||||
HAVE_KEYRING=0
|
||||
fi
|
||||
$CRYPTSETUP close $DEV_NAME || fail
|
||||
}
|
||||
|
||||
[ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run
|
||||
export LANG=C
|
||||
|
||||
[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped."
|
||||
[ -z "$LOOPDEV" ] && skip "WARNING: Cannot find free loop device, test skipped."
|
||||
[ -d "$LOCK_DIR" ] || skip "WARNING: LUKS2 locking directory ($LOCK_DIR) is missing, test skipped."
|
||||
|
||||
prepare "[0] Detect LUKS2 environment" wipe
|
||||
setup_luks2_env
|
||||
|
||||
[ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run
|
||||
|
||||
prepare "[1] Data offset" wipe
|
||||
echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV -q --offset 1 2>/dev/null && fail
|
||||
@@ -607,7 +620,7 @@ $CRYPTSETUP -q luksClose $DEV_NAME || fail
|
||||
prepare "[27] luksOpen with specified key slot number" wipe
|
||||
# first, let's try passphrase option
|
||||
echo $PWD3 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT -S 5 --type luks2 $LOOPDEV || fail
|
||||
echo $PWD3 | $CRYPTSETUP luksOpen -S 4 $LOOPDEV $DEV_NAME && fail
|
||||
echo $PWD3 | $CRYPTSETUP luksOpen -S 4 $LOOPDEV $DEV_NAME 2>/dev/null && fail
|
||||
[ -b /dev/mapper/$DEV_NAME ] && fail
|
||||
echo $PWD3 | $CRYPTSETUP luksOpen -S 5 $LOOPDEV $DEV_NAME || fail
|
||||
check_exists
|
||||
@@ -632,16 +645,16 @@ $CRYPTSETUP luksOpen -S 5 -d $KEY1 $LOOPDEV $DEV_NAME 2>/dev/null && fail
|
||||
prepare "" new
|
||||
echo $PWD1 | $CRYPTSETUP open -S1 --test-passphrase $HEADER_KEYU || fail
|
||||
echo $PWD1 | $CRYPTSETUP open --test-passphrase $HEADER_KEYU || fail
|
||||
echo $PWD1 | $CRYPTSETUP open -S1 $HEADER_KEYU $DEV_NAME && fail
|
||||
echo $PWD1 | $CRYPTSETUP open -S1 $HEADER_KEYU $DEV_NAME 2>/dev/null && fail
|
||||
[ -b /dev/mapper/$DEV_NAME ] && fail
|
||||
echo $PWD1 | $CRYPTSETUP open $HEADER_KEYU $DEV_NAME && fail
|
||||
echo $PWD1 | $CRYPTSETUP open $HEADER_KEYU $DEV_NAME 2>/dev/null && fail
|
||||
[ -b /dev/mapper/$DEV_NAME ] && fail
|
||||
echo $PWD0 | $CRYPTSETUP open -S1 --test-passphrase $HEADER_KEYU $DEV_NAME 2>/dev/null && fail
|
||||
$CRYPTSETUP luksKillSlot -q $HEADER_KEYU 0
|
||||
$CRYPTSETUP luksDump $HEADER_KEYU | grep -q "0: luks2" && fail
|
||||
echo $PWD1 | $CRYPTSETUP open -S1 --test-passphrase $HEADER_KEYU || fail
|
||||
echo $PWD1 | $CRYPTSETUP open --test-passphrase $HEADER_KEYU || fail
|
||||
echo $PWD1 | $CRYPTSETUP open -S1 $HEADER_KEYU $DEV_NAME && fail
|
||||
echo $PWD1 | $CRYPTSETUP open -S1 $HEADER_KEYU $DEV_NAME 2>/dev/null && fail
|
||||
|
||||
prepare "[28] Detached LUKS header" wipe
|
||||
echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --header $HEADER_IMG || fail
|
||||
@@ -650,6 +663,7 @@ echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --h
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --header $HEADER_IMG --align-payload 4096 >/dev/null || fail
|
||||
$CRYPTSETUP luksDump $HEADER_IMG | grep -e "0: crypt" -A1 | grep -qe $((4096*512)) || fail
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --header $HEADER_IMG --align-payload 0 || fail
|
||||
echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV-missing --header $HEADER_IMG $DEV_NAME 2>/dev/null && fail
|
||||
echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV --header $HEADER_IMG $DEV_NAME || fail
|
||||
echo $PWD1 | $CRYPTSETUP -q resize $DEV_NAME --size 100 --header $HEADER_IMG || fail
|
||||
$CRYPTSETUP -q status $DEV_NAME --header $HEADER_IMG | grep "size:" | grep -q "100 sectors" || fail
|
||||
@@ -697,13 +711,16 @@ $CRYPTSETUP luksDump $LOOPDEV | grep -q "1: luks2" || fail
|
||||
$CRYPTSETUP luksDump $LOOPDEV | grep -q "5: luks2" || fail
|
||||
$CRYPTSETUP -q convert --type luks1 $LOOPDEV || fail
|
||||
# hash test
|
||||
$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV $KEY5 -S 0 --hash sha1 || fail
|
||||
$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 --sector-size 512 $LOOPDEV $KEY5 -S 0 --hash sha1 || fail
|
||||
$CRYPTSETUP luksAddKey $FAST_PBKDF_OPT -S 1 -d $KEY5 $LOOPDEV $KEY1 --hash sha256 || fail
|
||||
$CRYPTSETUP -q convert --type luks1 $LOOPDEV >/dev/null 2>&1 && fail
|
||||
$CRYPTSETUP -q luksKillSlot $LOOPDEV 1 || fail
|
||||
$CRYPTSETUP -q convert --type luks1 $LOOPDEV || fail
|
||||
$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 0: ENABLED" || fail
|
||||
$CRYPTSETUP luksOpen $LOOPDEV --test-passphrase --key-slot 0 -d $KEY5 || fail
|
||||
# sector size test
|
||||
$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 --sector-size 1024 $LOOPDEV $KEY5 || fail
|
||||
$CRYPTSETUP -q convert --type luks1 $LOOPDEV >/dev/null 2>&1 && fail
|
||||
|
||||
if dm_crypt_keyring_flawed; then
|
||||
prepare "[32a] LUKS2 keyring dm-crypt bug" wipe
|
||||
@@ -749,7 +766,7 @@ fi
|
||||
# FIXME: candidate for non-root tests
|
||||
prepare "[33] tokens" wipe
|
||||
echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV || fail
|
||||
if [ $HAVE_KEYRING -gt 0 ]; then
|
||||
if [ $HAVE_KEYRING -gt 0 -a -d /proc/sys/kernel/keys ]; then
|
||||
|
||||
test_and_prepare_keyring
|
||||
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
|
||||
#include "crypto_backend.h"
|
||||
|
||||
#define MAX_BLOCK_SIZE 128
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
static void printhex(const char *s, const char *buf, size_t len)
|
||||
{
|
||||
@@ -60,7 +62,7 @@ struct kdf_test_vector {
|
||||
unsigned int output_length;
|
||||
};
|
||||
|
||||
struct kdf_test_vector kdf_test_vectors[] = {
|
||||
static struct kdf_test_vector kdf_test_vectors[] = {
|
||||
/* Argon2 RFC (without key and ad values) */
|
||||
{
|
||||
"argon2i", NULL, 0, 3, 32, 4,
|
||||
@@ -242,102 +244,123 @@ struct kdf_test_vector kdf_test_vectors[] = {
|
||||
/*
|
||||
* Hash tests
|
||||
*/
|
||||
|
||||
struct hash_alg {
|
||||
const char *name;
|
||||
int length;
|
||||
struct hash_test_vector {
|
||||
const char *data;
|
||||
unsigned int data_length;
|
||||
struct {
|
||||
const char *name;
|
||||
unsigned int length;
|
||||
const char *out;
|
||||
} out[6];
|
||||
};
|
||||
|
||||
static struct hash_alg hash_algs[] = {
|
||||
{ "sha1", 20 },
|
||||
{ "sha256", 32 },
|
||||
{ "sha512", 64 },
|
||||
{ "ripemd160", 20 },
|
||||
{ "whirlpool", 64 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
struct hash_in {
|
||||
const char* buffer;
|
||||
unsigned int length;
|
||||
};
|
||||
|
||||
struct hash_in hash_inputs[]
|
||||
= { { "", 0 },
|
||||
{ "a", 1 },
|
||||
{ "abc", 3 },
|
||||
{ "abcdefghijklmnopqrstuvwxyz", 26 },
|
||||
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 62 },
|
||||
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56 },
|
||||
{ "message digest", 14 } };
|
||||
|
||||
struct hash_out {
|
||||
uint32_t crc32_out;
|
||||
const char* sha1_out;
|
||||
const char* sha256_out;
|
||||
const char* sha512_out;
|
||||
const char* rmd160_out;
|
||||
const char* wp512_out;
|
||||
};
|
||||
|
||||
struct hash_out hash_outputs[] = {
|
||||
{
|
||||
0x00000000,
|
||||
"\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09",
|
||||
"\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55",
|
||||
"\xcf\x83\xe1\x35\x7e\xef\xb8\xbd\xf1\x54\x28\x50\xd6\x6d\x80\x07\xd6\x20\xe4\x05\x0b\x57\x15\xdc\x83\xf4\xa9\x21\xd3\x6c\xe9\xce\x47\xd0\xd1\x3c\x5d\x85\xf2\xb0\xff\x83\x18\xd2\x87\x7e\xec\x2f\x63\xb9\x31\xbd\x47\x41\x7a\x81\xa5\x38\x32\x7a\xf9\x27\xda\x3e",
|
||||
"\x9c\x11\x85\xa5\xc5\xe9\xfc\x54\x61\x28\x08\x97\x7e\xe8\xf5\x48\xb2\x25\x8d\x31",
|
||||
"\x19\xfa\x61\xd7\x55\x22\xa4\x66\x9b\x44\xe3\x9c\x1d\x2e\x17\x26\xc5\x30\x23\x21\x30\xd4\x07\xf8\x9a\xfe\xe0\x96\x49\x97\xf7\xa7\x3e\x83\xbe\x69\x8b\x28\x8f\xeb\xcf\x88\xe3\xe0\x3c\x4f\x07\x57\xea\x89\x64\xe5\x9b\x63\xd9\x37\x08\xb1\x38\xcc\x42\xa6\x6e\xb3"
|
||||
},
|
||||
{
|
||||
0xe8b7be43,
|
||||
"\x86\xf7\xe4\x37\xfa\xa5\xa7\xfc\xe1\x5d\x1d\xdc\xb9\xea\xea\xea\x37\x76\x67\xb8",
|
||||
"\xca\x97\x81\x12\xca\x1b\xbd\xca\xfa\xc2\x31\xb3\x9a\x23\xdc\x4d\xa7\x86\xef\xf8\x14\x7c\x4e\x72\xb9\x80\x77\x85\xaf\xee\x48\xbb",
|
||||
"\x1f\x40\xfc\x92\xda\x24\x16\x94\x75\x09\x79\xee\x6c\xf5\x82\xf2\xd5\xd7\xd2\x8e\x18\x33\x5d\xe0\x5a\xbc\x54\xd0\x56\x0e\x0f\x53\x02\x86\x0c\x65\x2b\xf0\x8d\x56\x02\x52\xaa\x5e\x74\x21\x05\x46\xf3\x69\xfb\xbb\xce\x8c\x12\xcf\xc7\x95\x7b\x26\x52\xfe\x9a\x75",
|
||||
"\x0b\xdc\x9d\x2d\x25\x6b\x3e\xe9\xda\xae\x34\x7b\xe6\xf4\xdc\x83\x5a\x46\x7f\xfe",
|
||||
"\x8a\xca\x26\x02\x79\x2a\xec\x6f\x11\xa6\x72\x06\x53\x1f\xb7\xd7\xf0\xdf\xf5\x94\x13\x14\x5e\x69\x73\xc4\x50\x01\xd0\x08\x7b\x42\xd1\x1b\xc6\x45\x41\x3a\xef\xf6\x3a\x42\x39\x1a\x39\x14\x5a\x59\x1a\x92\x20\x0d\x56\x01\x95\xe5\x3b\x47\x85\x84\xfd\xae\x23\x1a"
|
||||
},
|
||||
{
|
||||
0x352441c2,
|
||||
"\xa9\x99\x3e\x36\x47\x06\x81\x6a\xba\x3e\x25\x71\x78\x50\xc2\x6c\x9c\xd0\xd8\x9d",
|
||||
"\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad",
|
||||
"\xdd\xaf\x35\xa1\x93\x61\x7a\xba\xcc\x41\x73\x49\xae\x20\x41\x31\x12\xe6\xfa\x4e\x89\xa9\x7e\xa2\x0a\x9e\xee\xe6\x4b\x55\xd3\x9a\x21\x92\x99\x2a\x27\x4f\xc1\xa8\x36\xba\x3c\x23\xa3\xfe\xeb\xbd\x45\x4d\x44\x23\x64\x3c\xe8\x0e\x2a\x9a\xc9\x4f\xa5\x4c\xa4\x9f",
|
||||
"\x8e\xb2\x08\xf7\xe0\x5d\x98\x7a\x9b\x04\x4a\x8e\x98\xc6\xb0\x87\xf1\x5a\x0b\xfc",
|
||||
"\x4e\x24\x48\xa4\xc6\xf4\x86\xbb\x16\xb6\x56\x2c\x73\xb4\x02\x0b\xf3\x04\x3e\x3a\x73\x1b\xce\x72\x1a\xe1\xb3\x03\xd9\x7e\x6d\x4c\x71\x81\xee\xbd\xb6\xc5\x7e\x27\x7d\x0e\x34\x95\x71\x14\xcb\xd6\xc7\x97\xfc\x9d\x95\xd8\xb5\x82\xd2\x25\x29\x20\x76\xd4\xee\xf5"
|
||||
},
|
||||
{
|
||||
0x4c2750bd,
|
||||
"\x32\xd1\x0c\x7b\x8c\xf9\x65\x70\xca\x04\xce\x37\xf2\xa1\x9d\x84\x24\x0d\x3a\x89",
|
||||
"\x71\xc4\x80\xdf\x93\xd6\xae\x2f\x1e\xfa\xd1\x44\x7c\x66\xc9\x52\x5e\x31\x62\x18\xcf\x51\xfc\x8d\x9e\xd8\x32\xf2\xda\xf1\x8b\x73",
|
||||
"\x4d\xbf\xf8\x6c\xc2\xca\x1b\xae\x1e\x16\x46\x8a\x05\xcb\x98\x81\xc9\x7f\x17\x53\xbc\xe3\x61\x90\x34\x89\x8f\xaa\x1a\xab\xe4\x29\x95\x5a\x1b\xf8\xec\x48\x3d\x74\x21\xfe\x3c\x16\x46\x61\x3a\x59\xed\x54\x41\xfb\x0f\x32\x13\x89\xf7\x7f\x48\xa8\x79\xc7\xb1\xf1",
|
||||
"\xf7\x1c\x27\x10\x9c\x69\x2c\x1b\x56\xbb\xdc\xeb\x5b\x9d\x28\x65\xb3\x70\x8d\xbc",
|
||||
"\xf1\xd7\x54\x66\x26\x36\xff\xe9\x2c\x82\xeb\xb9\x21\x2a\x48\x4a\x8d\x38\x63\x1e\xad\x42\x38\xf5\x44\x2e\xe1\x3b\x80\x54\xe4\x1b\x08\xbf\x2a\x92\x51\xc3\x0b\x6a\x0b\x8a\xae\x86\x17\x7a\xb4\xa6\xf6\x8f\x67\x3e\x72\x07\x86\x5d\x5d\x98\x19\xa3\xdb\xa4\xeb\x3b"
|
||||
},
|
||||
{
|
||||
0x1fc2e6d2,
|
||||
"\x76\x1c\x45\x7b\xf7\x3b\x14\xd2\x7e\x9e\x92\x65\xc4\x6f\x4b\x4d\xda\x11\xf9\x40",
|
||||
"\xdb\x4b\xfc\xbd\x4d\xa0\xcd\x85\xa6\x0c\x3c\x37\xd3\xfb\xd8\x80\x5c\x77\xf1\x5f\xc6\xb1\xfd\xfe\x61\x4e\xe0\xa7\xc8\xfd\xb4\xc0",
|
||||
"\x1e\x07\xbe\x23\xc2\x6a\x86\xea\x37\xea\x81\x0c\x8e\xc7\x80\x93\x52\x51\x5a\x97\x0e\x92\x53\xc2\x6f\x53\x6c\xfc\x7a\x99\x96\xc4\x5c\x83\x70\x58\x3e\x0a\x78\xfa\x4a\x90\x04\x1d\x71\xa4\xce\xab\x74\x23\xf1\x9c\x71\xb9\xd5\xa3\xe0\x12\x49\xf0\xbe\xbd\x58\x94",
|
||||
"\xb0\xe2\x0b\x6e\x31\x16\x64\x02\x86\xed\x3a\x87\xa5\x71\x30\x79\xb2\x1f\x51\x89",
|
||||
"\xdc\x37\xe0\x08\xcf\x9e\xe6\x9b\xf1\x1f\x00\xed\x9a\xba\x26\x90\x1d\xd7\xc2\x8c\xde\xc0\x66\xcc\x6a\xf4\x2e\x40\xf8\x2f\x3a\x1e\x08\xeb\xa2\x66\x29\x12\x9d\x8f\xb7\xcb\x57\x21\x1b\x92\x81\xa6\x55\x17\xcc\x87\x9d\x7b\x96\x21\x42\xc6\x5f\x5a\x7a\xf0\x14\x67"
|
||||
},
|
||||
{
|
||||
0x171a3f5f,
|
||||
"\x84\x98\x3e\x44\x1c\x3b\xd2\x6e\xba\xae\x4a\xa1\xf9\x51\x29\xe5\xe5\x46\x70\xf1",
|
||||
"\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1",
|
||||
"\x20\x4a\x8f\xc6\xdd\xa8\x2f\x0a\x0c\xed\x7b\xeb\x8e\x08\xa4\x16\x57\xc1\x6e\xf4\x68\xb2\x28\xa8\x27\x9b\xe3\x31\xa7\x03\xc3\x35\x96\xfd\x15\xc1\x3b\x1b\x07\xf9\xaa\x1d\x3b\xea\x57\x78\x9c\xa0\x31\xad\x85\xc7\xa7\x1d\xd7\x03\x54\xec\x63\x12\x38\xca\x34\x45",
|
||||
"\x12\xa0\x53\x38\x4a\x9c\x0c\x88\xe4\x05\xa0\x6c\x27\xdc\xf4\x9a\xda\x62\xeb\x2b",
|
||||
"\x52\x6b\x23\x94\xd8\x56\x83\xe2\x4b\x29\xac\xd0\xfd\x37\xf7\xd5\x02\x7f\x61\x36\x6a\x14\x07\x26\x2d\xc2\xa6\xa3\x45\xd9\xe2\x40\xc0\x17\xc1\x83\x3d\xb1\xe6\xdb\x6a\x46\xbd\x44\x4b\x0c\x69\x52\x0c\x85\x6e\x7c\x6e\x9c\x36\x6d\x15\x0a\x7d\xa3\xae\xb1\x60\xd1"
|
||||
},
|
||||
{
|
||||
0x20159d7f,
|
||||
"\xc1\x22\x52\xce\xda\x8b\xe8\x99\x4d\x5f\xa0\x29\x0a\x47\x23\x1c\x1d\x16\xaa\xe3",
|
||||
"\xf7\x84\x6f\x55\xcf\x23\xe1\x4e\xeb\xea\xb5\xb4\xe1\x55\x0c\xad\x5b\x50\x9e\x33\x48\xfb\xc4\xef\xa3\xa1\x41\x3d\x39\x3c\xb6\x50",
|
||||
"\x10\x7d\xbf\x38\x9d\x9e\x9f\x71\xa3\xa9\x5f\x6c\x05\x5b\x92\x51\xbc\x52\x68\xc2\xbe\x16\xd6\xc1\x34\x92\xea\x45\xb0\x19\x9f\x33\x09\xe1\x64\x55\xab\x1e\x96\x11\x8e\x8a\x90\x5d\x55\x97\xb7\x20\x38\xdd\xb3\x72\xa8\x98\x26\x04\x6d\xe6\x66\x87\xbb\x42\x0e\x7c",
|
||||
"\x5d\x06\x89\xef\x49\xd2\xfa\xe5\x72\xb8\x81\xb1\x23\xa8\x5f\xfa\x21\x59\x5f\x36",
|
||||
"\x37\x8c\x84\xa4\x12\x6e\x2d\xc6\xe5\x6d\xcc\x74\x58\x37\x7a\xac\x83\x8d\x00\x03\x22\x30\xf5\x3c\xe1\xf5\x70\x0c\x0f\xfb\x4d\x3b\x84\x21\x55\x76\x59\xef\x55\xc1\x06\xb4\xb5\x2a\xc5\xa4\xaa\xa6\x92\xed\x92\x00\x52\x83\x8f\x33\x62\xe8\x6d\xbd\x37\xa8\x90\x3e"
|
||||
}
|
||||
};
|
||||
static struct hash_test_vector hash_test_vectors[] = {
|
||||
{
|
||||
"", 0, {
|
||||
{ "crc32", 4, "\x00\x00\x00\x00" },
|
||||
{ "sha1", 20, "\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09" },
|
||||
{ "sha256", 32, "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24"
|
||||
"\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55" },
|
||||
{ "sha512", 64, "\xcf\x83\xe1\x35\x7e\xef\xb8\xbd\xf1\x54\x28\x50\xd6\x6d\x80\x07"
|
||||
"\xd6\x20\xe4\x05\x0b\x57\x15\xdc\x83\xf4\xa9\x21\xd3\x6c\xe9\xce"
|
||||
"\x47\xd0\xd1\x3c\x5d\x85\xf2\xb0\xff\x83\x18\xd2\x87\x7e\xec\x2f"
|
||||
"\x63\xb9\x31\xbd\x47\x41\x7a\x81\xa5\x38\x32\x7a\xf9\x27\xda\x3e" },
|
||||
{ "ripemd160", 20, "\x9c\x11\x85\xa5\xc5\xe9\xfc\x54\x61\x28\x08\x97\x7e\xe8\xf5\x48\xb2\x25\x8d\x31" },
|
||||
{ "whirlpool", 64, "\x19\xfa\x61\xd7\x55\x22\xa4\x66\x9b\x44\xe3\x9c\x1d\x2e\x17\x26"
|
||||
"\xc5\x30\x23\x21\x30\xd4\x07\xf8\x9a\xfe\xe0\x96\x49\x97\xf7\xa7"
|
||||
"\x3e\x83\xbe\x69\x8b\x28\x8f\xeb\xcf\x88\xe3\xe0\x3c\x4f\x07\x57"
|
||||
"\xea\x89\x64\xe5\x9b\x63\xd9\x37\x08\xb1\x38\xcc\x42\xa6\x6e\xb3" },
|
||||
}},{
|
||||
"a", 1, {
|
||||
{ "crc32", 4, "\xe8\xb7\xbe\x43" },
|
||||
{ "sha1", 20, "\x86\xf7\xe4\x37\xfa\xa5\xa7\xfc\xe1\x5d\x1d\xdc\xb9\xea\xea\xea\x37\x76\x67\xb8" },
|
||||
{ "sha256", 32, "\xca\x97\x81\x12\xca\x1b\xbd\xca\xfa\xc2\x31\xb3\x9a\x23\xdc\x4d"
|
||||
"\xa7\x86\xef\xf8\x14\x7c\x4e\x72\xb9\x80\x77\x85\xaf\xee\x48\xbb" },
|
||||
{ "sha512", 64, "\x1f\x40\xfc\x92\xda\x24\x16\x94\x75\x09\x79\xee\x6c\xf5\x82\xf2"
|
||||
"\xd5\xd7\xd2\x8e\x18\x33\x5d\xe0\x5a\xbc\x54\xd0\x56\x0e\x0f\x53"
|
||||
"\x02\x86\x0c\x65\x2b\xf0\x8d\x56\x02\x52\xaa\x5e\x74\x21\x05\x46"
|
||||
"\xf3\x69\xfb\xbb\xce\x8c\x12\xcf\xc7\x95\x7b\x26\x52\xfe\x9a\x75" },
|
||||
{ "ripemd160", 20, "\x0b\xdc\x9d\x2d\x25\x6b\x3e\xe9\xda\xae\x34\x7b\xe6\xf4\xdc\x83\x5a\x46\x7f\xfe" },
|
||||
{ "whirlpool", 64, "\x8a\xca\x26\x02\x79\x2a\xec\x6f\x11\xa6\x72\x06\x53\x1f\xb7\xd7"
|
||||
"\xf0\xdf\xf5\x94\x13\x14\x5e\x69\x73\xc4\x50\x01\xd0\x08\x7b\x42"
|
||||
"\xd1\x1b\xc6\x45\x41\x3a\xef\xf6\x3a\x42\x39\x1a\x39\x14\x5a\x59"
|
||||
"\x1a\x92\x20\x0d\x56\x01\x95\xe5\x3b\x47\x85\x84\xfd\xae\x23\x1a" },
|
||||
}},{
|
||||
"abc", 3, {
|
||||
{ "crc32", 4, "\x35\x24\x41\xc2" },
|
||||
{ "sha1", 20, "\xa9\x99\x3e\x36\x47\x06\x81\x6a\xba\x3e\x25\x71\x78\x50\xc2\x6c\x9c\xd0\xd8\x9d" },
|
||||
{ "sha256", 32, "\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23"
|
||||
"\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad" },
|
||||
{ "sha512", 64, "\xdd\xaf\x35\xa1\x93\x61\x7a\xba\xcc\x41\x73\x49\xae\x20\x41\x31"
|
||||
"\x12\xe6\xfa\x4e\x89\xa9\x7e\xa2\x0a\x9e\xee\xe6\x4b\x55\xd3\x9a"
|
||||
"\x21\x92\x99\x2a\x27\x4f\xc1\xa8\x36\xba\x3c\x23\xa3\xfe\xeb\xbd"
|
||||
"\x45\x4d\x44\x23\x64\x3c\xe8\x0e\x2a\x9a\xc9\x4f\xa5\x4c\xa4\x9f" },
|
||||
{ "ripemd160", 20, "\x8e\xb2\x08\xf7\xe0\x5d\x98\x7a\x9b\x04\x4a\x8e\x98\xc6\xb0\x87\xf1\x5a\x0b\xfc" },
|
||||
{ "whirlpool", 64, "\x4e\x24\x48\xa4\xc6\xf4\x86\xbb\x16\xb6\x56\x2c\x73\xb4\x02\x0b"
|
||||
"\xf3\x04\x3e\x3a\x73\x1b\xce\x72\x1a\xe1\xb3\x03\xd9\x7e\x6d\x4c"
|
||||
"\x71\x81\xee\xbd\xb6\xc5\x7e\x27\x7d\x0e\x34\x95\x71\x14\xcb\xd6"
|
||||
"\xc7\x97\xfc\x9d\x95\xd8\xb5\x82\xd2\x25\x29\x20\x76\xd4\xee\xf5" },
|
||||
}},{
|
||||
"abcdefghijklmnopqrstuvwxyz", 26, {
|
||||
{ "crc32", 4, "\x4c\x27\x50\xbd" },
|
||||
{ "sha1", 20, "\x32\xd1\x0c\x7b\x8c\xf9\x65\x70\xca\x04\xce\x37\xf2\xa1\x9d\x84\x24\x0d\x3a\x89" },
|
||||
{ "sha256", 32, "\x71\xc4\x80\xdf\x93\xd6\xae\x2f\x1e\xfa\xd1\x44\x7c\x66\xc9\x52"
|
||||
"\x5e\x31\x62\x18\xcf\x51\xfc\x8d\x9e\xd8\x32\xf2\xda\xf1\x8b\x73" },
|
||||
{ "sha512", 64, "\x4d\xbf\xf8\x6c\xc2\xca\x1b\xae\x1e\x16\x46\x8a\x05\xcb\x98\x81"
|
||||
"\xc9\x7f\x17\x53\xbc\xe3\x61\x90\x34\x89\x8f\xaa\x1a\xab\xe4\x29"
|
||||
"\x95\x5a\x1b\xf8\xec\x48\x3d\x74\x21\xfe\x3c\x16\x46\x61\x3a\x59"
|
||||
"\xed\x54\x41\xfb\x0f\x32\x13\x89\xf7\x7f\x48\xa8\x79\xc7\xb1\xf1" },
|
||||
{ "ripemd160", 20, "\xf7\x1c\x27\x10\x9c\x69\x2c\x1b\x56\xbb\xdc\xeb\x5b\x9d\x28\x65\xb3\x70\x8d\xbc" },
|
||||
{ "whirlpool", 64, "\xf1\xd7\x54\x66\x26\x36\xff\xe9\x2c\x82\xeb\xb9\x21\x2a\x48\x4a"
|
||||
"\x8d\x38\x63\x1e\xad\x42\x38\xf5\x44\x2e\xe1\x3b\x80\x54\xe4\x1b"
|
||||
"\x08\xbf\x2a\x92\x51\xc3\x0b\x6a\x0b\x8a\xae\x86\x17\x7a\xb4\xa6"
|
||||
"\xf6\x8f\x67\x3e\x72\x07\x86\x5d\x5d\x98\x19\xa3\xdb\xa4\xeb\x3b" },
|
||||
}},{
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 62, {
|
||||
{ "crc32", 4, "\x1f\xc2\xe6\xd2" },
|
||||
{ "sha1", 20, "\x76\x1c\x45\x7b\xf7\x3b\x14\xd2\x7e\x9e\x92\x65\xc4\x6f\x4b\x4d\xda\x11\xf9\x40" },
|
||||
{ "sha256", 32, "\xdb\x4b\xfc\xbd\x4d\xa0\xcd\x85\xa6\x0c\x3c\x37\xd3\xfb\xd8\x80"
|
||||
"\x5c\x77\xf1\x5f\xc6\xb1\xfd\xfe\x61\x4e\xe0\xa7\xc8\xfd\xb4\xc0" },
|
||||
{ "sha512", 64, "\x1e\x07\xbe\x23\xc2\x6a\x86\xea\x37\xea\x81\x0c\x8e\xc7\x80\x93"
|
||||
"\x52\x51\x5a\x97\x0e\x92\x53\xc2\x6f\x53\x6c\xfc\x7a\x99\x96\xc4"
|
||||
"\x5c\x83\x70\x58\x3e\x0a\x78\xfa\x4a\x90\x04\x1d\x71\xa4\xce\xab"
|
||||
"\x74\x23\xf1\x9c\x71\xb9\xd5\xa3\xe0\x12\x49\xf0\xbe\xbd\x58\x94" },
|
||||
{ "ripemd160", 20, "\xb0\xe2\x0b\x6e\x31\x16\x64\x02\x86\xed\x3a\x87\xa5\x71\x30\x79\xb2\x1f\x51\x89" },
|
||||
{ "whirlpool", 64, "\xdc\x37\xe0\x08\xcf\x9e\xe6\x9b\xf1\x1f\x00\xed\x9a\xba\x26\x90"
|
||||
"\x1d\xd7\xc2\x8c\xde\xc0\x66\xcc\x6a\xf4\x2e\x40\xf8\x2f\x3a\x1e"
|
||||
"\x08\xeb\xa2\x66\x29\x12\x9d\x8f\xb7\xcb\x57\x21\x1b\x92\x81\xa6"
|
||||
"\x55\x17\xcc\x87\x9d\x7b\x96\x21\x42\xc6\x5f\x5a\x7a\xf0\x14\x67" },
|
||||
}},{
|
||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, {
|
||||
{ "crc32", 4, "\x17\x1a\x3f\x5f" },
|
||||
{ "sha1", 20, "\x84\x98\x3e\x44\x1c\x3b\xd2\x6e\xba\xae\x4a\xa1\xf9\x51\x29\xe5\xe5\x46\x70\xf1" },
|
||||
{ "sha256", 32, "\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39"
|
||||
"\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1" },
|
||||
{ "sha512", 64, "\x20\x4a\x8f\xc6\xdd\xa8\x2f\x0a\x0c\xed\x7b\xeb\x8e\x08\xa4\x16"
|
||||
"\x57\xc1\x6e\xf4\x68\xb2\x28\xa8\x27\x9b\xe3\x31\xa7\x03\xc3\x35"
|
||||
"\x96\xfd\x15\xc1\x3b\x1b\x07\xf9\xaa\x1d\x3b\xea\x57\x78\x9c\xa0"
|
||||
"\x31\xad\x85\xc7\xa7\x1d\xd7\x03\x54\xec\x63\x12\x38\xca\x34\x45" },
|
||||
{ "ripemd160", 20, "\x12\xa0\x53\x38\x4a\x9c\x0c\x88\xe4\x05\xa0\x6c\x27\xdc\xf4\x9a\xda\x62\xeb\x2b" },
|
||||
{ "whirlpool", 64, "\x52\x6b\x23\x94\xd8\x56\x83\xe2\x4b\x29\xac\xd0\xfd\x37\xf7\xd5"
|
||||
"\x02\x7f\x61\x36\x6a\x14\x07\x26\x2d\xc2\xa6\xa3\x45\xd9\xe2\x40"
|
||||
"\xc0\x17\xc1\x83\x3d\xb1\xe6\xdb\x6a\x46\xbd\x44\x4b\x0c\x69\x52"
|
||||
"\x0c\x85\x6e\x7c\x6e\x9c\x36\x6d\x15\x0a\x7d\xa3\xae\xb1\x60\xd1" },
|
||||
}},{
|
||||
"message digest", 14, {
|
||||
{ "crc32", 4, "\x20\x15\x9d\x7f" },
|
||||
{ "sha1", 20, "\xc1\x22\x52\xce\xda\x8b\xe8\x99\x4d\x5f\xa0\x29\x0a\x47\x23\x1c\x1d\x16\xaa\xe3" },
|
||||
{ "sha256", 32, "\xf7\x84\x6f\x55\xcf\x23\xe1\x4e\xeb\xea\xb5\xb4\xe1\x55\x0c\xad"
|
||||
"\x5b\x50\x9e\x33\x48\xfb\xc4\xef\xa3\xa1\x41\x3d\x39\x3c\xb6\x50" },
|
||||
{ "sha512", 64, "\x10\x7d\xbf\x38\x9d\x9e\x9f\x71\xa3\xa9\x5f\x6c\x05\x5b\x92\x51"
|
||||
"\xbc\x52\x68\xc2\xbe\x16\xd6\xc1\x34\x92\xea\x45\xb0\x19\x9f\x33"
|
||||
"\x09\xe1\x64\x55\xab\x1e\x96\x11\x8e\x8a\x90\x5d\x55\x97\xb7\x20"
|
||||
"\x38\xdd\xb3\x72\xa8\x98\x26\x04\x6d\xe6\x66\x87\xbb\x42\x0e\x7c" },
|
||||
{ "ripemd160", 20, "\x5d\x06\x89\xef\x49\xd2\xfa\xe5\x72\xb8\x81\xb1\x23\xa8\x5f\xfa\x21\x59\x5f\x36" },
|
||||
{ "whirlpool", 64, "\x37\x8c\x84\xa4\x12\x6e\x2d\xc6\xe5\x6d\xcc\x74\x58\x37\x7a\xac"
|
||||
"\x83\x8d\x00\x03\x22\x30\xf5\x3c\xe1\xf5\x70\x0c\x0f\xfb\x4d\x3b"
|
||||
"\x84\x21\x55\x76\x59\xef\x55\xc1\x06\xb4\xb5\x2a\xc5\xa4\xaa\xa6"
|
||||
"\x92\xed\x92\x00\x52\x83\x8f\x33\x62\xe8\x6d\xbd\x37\xa8\x90\x3e" },
|
||||
}}};
|
||||
|
||||
/*
|
||||
* HMAC tests
|
||||
@@ -350,65 +373,287 @@ struct hmac_test_vector {
|
||||
unsigned int key_length;
|
||||
const char *data;
|
||||
unsigned int data_length;
|
||||
const char *hmac_sha_1;
|
||||
const char *hmac_sha_256;
|
||||
const char *hmac_sha_512;
|
||||
struct {
|
||||
const char *name;
|
||||
unsigned int length;
|
||||
const char *out;
|
||||
} out[3];
|
||||
};
|
||||
|
||||
struct hmac_test_vector hmac_test_vectors[] = {
|
||||
{
|
||||
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20,
|
||||
"\x48\x69\x20\x54\x68\x65\x72\x65", 8, // "Hi There"
|
||||
"\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00",
|
||||
"\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf\x0b\xf1\x2b\x88\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9\x37\x6c\x2e\x32\xcf\xf7",
|
||||
"\x87\xaa\x7c\xde\xa5\xef\x61\x9d\x4f\xf0\xb4\x24\x1a\x1d\x6c\xb0\x23\x79\xf4\xe2\xce\x4e\xc2\x78\x7a\xd0\xb3\x05\x45\xe1\x7c\xde\xda\xa8\x33\xb7\xd6\xb8\xa7\x02\x03\x8b\x27\x4e\xae\xa3\xf4\xe4\xbe\x9d\x91\x4e\xeb\x61\xf1\x70\x2e\x69\x6c\x20\x3a\x12\x68\x54"
|
||||
},
|
||||
{
|
||||
"\x4a\x65\x66\x65", 4, // "Jefe"
|
||||
"\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f", 28, // "what do ya want for nothing?"
|
||||
"\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79",
|
||||
"\x5b\xdc\xc1\x46\xbf\x60\x75\x4e\x6a\x04\x24\x26\x08\x95\x75\xc7\x5a\x00\x3f\x08\x9d\x27\x39\x83\x9d\xec\x58\xb9\x64\xec\x38\x43",
|
||||
"\x16\x4b\x7a\x7b\xfc\xf8\x19\xe2\xe3\x95\xfb\xe7\x3b\x56\xe0\xa3\x87\xbd\x64\x22\x2e\x83\x1f\xd6\x10\x27\x0c\xd7\xea\x25\x05\x54\x97\x58\xbf\x75\xc0\x5a\x99\x4a\x6d\x03\x4f\x65\xf8\xf0\xe6\xfd\xca\xea\xb1\xa3\x4d\x4a\x6b\x4b\x63\x6e\x07\x0a\x38\xbc\xe7\x37"
|
||||
},
|
||||
{
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20,
|
||||
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", 50,
|
||||
"\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3",
|
||||
"\x77\x3e\xa9\x1e\x36\x80\x0e\x46\x85\x4d\xb8\xeb\xd0\x91\x81\xa7\x29\x59\x09\x8b\x3e\xf8\xc1\x22\xd9\x63\x55\x14\xce\xd5\x65\xfe",
|
||||
"\xfa\x73\xb0\x08\x9d\x56\xa2\x84\xef\xb0\xf0\x75\x6c\x89\x0b\xe9\xb1\xb5\xdb\xdd\x8e\xe8\x1a\x36\x55\xf8\x3e\x33\xb2\x27\x9d\x39\xbf\x3e\x84\x82\x79\xa7\x22\xc8\x06\xb4\x85\xa4\x7e\x67\xc8\x07\xb9\x46\xa3\x37\xbe\xe8\x94\x26\x74\x27\x88\x59\xe1\x32\x92\xfb"
|
||||
},
|
||||
{
|
||||
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", 25,
|
||||
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", 50,
|
||||
"\x4c\x90\x07\xf4\x02\x62\x50\xc6\xbc\x84\x14\xf9\xbf\x50\xc8\x6c\x2d\x72\x35\xda",
|
||||
"\x82\x55\x8a\x38\x9a\x44\x3c\x0e\xa4\xcc\x81\x98\x99\xf2\x08\x3a\x85\xf0\xfa\xa3\xe5\x78\xf8\x07\x7a\x2e\x3f\xf4\x67\x29\x66\x5b",
|
||||
"\xb0\xba\x46\x56\x37\x45\x8c\x69\x90\xe5\xa8\xc5\xf6\x1d\x4a\xf7\xe5\x76\xd9\x7f\xf9\x4b\x87\x2d\xe7\x6f\x80\x50\x36\x1e\xe3\xdb\xa9\x1c\xa5\xc1\x1a\xa2\x5e\xb4\xd6\x79\x27\x5c\xc5\x78\x80\x63\xa5\xf1\x97\x41\x12\x0c\x4f\x2d\xe2\xad\xeb\xeb\x10\xa2\x98\xdd"
|
||||
},
|
||||
{
|
||||
// Long key
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131,
|
||||
"\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72\x73\x74", 54, // "Test Using Larger Than Block-Size Key - Hash Key First"
|
||||
"\x90\xd0\xda\xce\x1c\x1b\xdc\x95\x73\x39\x30\x78\x03\x16\x03\x35\xbd\xe6\xdf\x2b",
|
||||
"\x60\xe4\x31\x59\x1e\xe0\xb6\x7f\x0d\x8a\x26\xaa\xcb\xf5\xb7\x7f\x8e\x0b\xc6\x21\x37\x28\xc5\x14\x05\x46\x04\x0f\x0e\xe3\x7f\x54",
|
||||
"\x80\xb2\x42\x63\xc7\xc1\xa3\xeb\xb7\x14\x93\xc1\xdd\x7b\xe8\xb4\x9b\x46\xd1\xf4\x1b\x4a\xee\xc1\x12\x1b\x01\x37\x83\xf8\xf3\x52\x6b\x56\xd0\x37\xe0\x5f\x25\x98\xbd\x0f\xd2\x21\x5d\x6a\x1e\x52\x95\xe6\x4f\x73\xf6\x3f\x0a\xec\x8b\x91\x5a\x98\x5d\x78\x65\x98"
|
||||
},
|
||||
{
|
||||
// Long key and long data
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131,
|
||||
"\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e", 152,
|
||||
"\x21\x7e\x44\xbb\x08\xb6\xe0\x6a\x2d\x6c\x30\xf3\xcb\x9f\x53\x7f\x97\xc6\x33\x56",
|
||||
"\x9b\x09\xff\xa7\x1b\x94\x2f\xcb\x27\x63\x5f\xbc\xd5\xb0\xe9\x44\xbf\xdc\x63\x64\x4f\x07\x13\x93\x8a\x7f\x51\x53\x5c\x3a\x35\xe2",
|
||||
"\xe3\x7b\x6a\x77\x5d\xc8\x7d\xba\xa4\xdf\xa9\xf9\x6e\x5e\x3f\xfd\xde\xbd\x71\xf8\x86\x72\x89\x86\x5d\xf5\xa3\x2d\x20\xcd\xc9\x44\xb6\x02\x2c\xac\x3c\x49\x82\xb1\x0d\x5e\xeb\x55\xc3\xe4\xde\x15\x13\x46\x76\xfb\x6d\xe0\x44\x60\x65\xc9\x74\x40\xfa\x8c\x6a\x58"
|
||||
}
|
||||
static struct hmac_test_vector hmac_test_vectors[] = {
|
||||
{
|
||||
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20,
|
||||
"\x48\x69\x20\x54\x68\x65\x72\x65", 8, /* "Hi There" */ {
|
||||
{ "sha1", 20, "\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00" },
|
||||
{ "sha256", 32, "\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf\x0b\xf1\x2b"
|
||||
"\x88\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9\x37\x6c\x2e\x32\xcf\xf7" },
|
||||
{ "sha512", 64, "\x87\xaa\x7c\xde\xa5\xef\x61\x9d\x4f\xf0\xb4\x24\x1a\x1d\x6c\xb0"
|
||||
"\x23\x79\xf4\xe2\xce\x4e\xc2\x78\x7a\xd0\xb3\x05\x45\xe1\x7c\xde"
|
||||
"\xda\xa8\x33\xb7\xd6\xb8\xa7\x02\x03\x8b\x27\x4e\xae\xa3\xf4\xe4"
|
||||
"\xbe\x9d\x91\x4e\xeb\x61\xf1\x70\x2e\x69\x6c\x20\x3a\x12\x68\x54" },
|
||||
}},{
|
||||
"\x4a\x65\x66\x65", 4, /* "Jefe" */
|
||||
"\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61\x6e\x74\x20"
|
||||
"\x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f", 28, /* "what do ya want for nothing?" */ {
|
||||
{ "sha1", 20, "\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79" },
|
||||
{ "sha256", 32, "\x5b\xdc\xc1\x46\xbf\x60\x75\x4e\x6a\x04\x24\x26\x08\x95\x75\xc7"
|
||||
"\x5a\x00\x3f\x08\x9d\x27\x39\x83\x9d\xec\x58\xb9\x64\xec\x38\x43" },
|
||||
{ "sha512", 64, "\x16\x4b\x7a\x7b\xfc\xf8\x19\xe2\xe3\x95\xfb\xe7\x3b\x56\xe0\xa3"
|
||||
"\x87\xbd\x64\x22\x2e\x83\x1f\xd6\x10\x27\x0c\xd7\xea\x25\x05\x54"
|
||||
"\x97\x58\xbf\x75\xc0\x5a\x99\x4a\x6d\x03\x4f\x65\xf8\xf0\xe6\xfd"
|
||||
"\xca\xea\xb1\xa3\x4d\x4a\x6b\x4b\x63\x6e\x07\x0a\x38\xbc\xe7\x37" },
|
||||
}},{
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20,
|
||||
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
|
||||
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
|
||||
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", 50, {
|
||||
{ "sha1", 20, "\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3" },
|
||||
{ "sha256", 32, "\x77\x3e\xa9\x1e\x36\x80\x0e\x46\x85\x4d\xb8\xeb\xd0\x91\x81\xa7"
|
||||
"\x29\x59\x09\x8b\x3e\xf8\xc1\x22\xd9\x63\x55\x14\xce\xd5\x65\xfe" },
|
||||
{ "sha512", 64, "\xfa\x73\xb0\x08\x9d\x56\xa2\x84\xef\xb0\xf0\x75\x6c\x89\x0b\xe9"
|
||||
"\xb1\xb5\xdb\xdd\x8e\xe8\x1a\x36\x55\xf8\x3e\x33\xb2\x27\x9d\x39"
|
||||
"\xbf\x3e\x84\x82\x79\xa7\x22\xc8\x06\xb4\x85\xa4\x7e\x67\xc8\x07"
|
||||
"\xb9\x46\xa3\x37\xbe\xe8\x94\x26\x74\x27\x88\x59\xe1\x32\x92\xfb" },
|
||||
}},{
|
||||
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", 25,
|
||||
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
|
||||
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
|
||||
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", 50, {
|
||||
{ "sha1", 20, "\x4c\x90\x07\xf4\x02\x62\x50\xc6\xbc\x84\x14\xf9\xbf\x50\xc8\x6c\x2d\x72\x35\xda" },
|
||||
{ "sha256", 32, "\x82\x55\x8a\x38\x9a\x44\x3c\x0e\xa4\xcc\x81\x98\x99\xf2\x08\x3a"
|
||||
"\x85\xf0\xfa\xa3\xe5\x78\xf8\x07\x7a\x2e\x3f\xf4\x67\x29\x66\x5b" },
|
||||
{ "sha512", 64, "\xb0\xba\x46\x56\x37\x45\x8c\x69\x90\xe5\xa8\xc5\xf6\x1d\x4a\xf7"
|
||||
"\xe5\x76\xd9\x7f\xf9\x4b\x87\x2d\xe7\x6f\x80\x50\x36\x1e\xe3\xdb"
|
||||
"\xa9\x1c\xa5\xc1\x1a\xa2\x5e\xb4\xd6\x79\x27\x5c\xc5\x78\x80\x63"
|
||||
"\xa5\xf1\x97\x41\x12\x0c\x4f\x2d\xe2\xad\xeb\xeb\x10\xa2\x98\xdd" },
|
||||
}},{
|
||||
// Long key
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131,
|
||||
"\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65"
|
||||
"\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a"
|
||||
"\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79"
|
||||
"\x20\x46\x69\x72\x73\x74", 54, /* "Test Using Larger Than Block-Size Key - Hash Key First" */ {
|
||||
{ "sha1", 20, "\x90\xd0\xda\xce\x1c\x1b\xdc\x95\x73\x39\x30\x78\x03\x16\x03\x35\xbd\xe6\xdf\x2b" },
|
||||
{ "sha256", 32, "\x60\xe4\x31\x59\x1e\xe0\xb6\x7f\x0d\x8a\x26\xaa\xcb\xf5\xb7\x7f"
|
||||
"\x8e\x0b\xc6\x21\x37\x28\xc5\x14\x05\x46\x04\x0f\x0e\xe3\x7f\x54" },
|
||||
{ "sha512", 64, "\x80\xb2\x42\x63\xc7\xc1\xa3\xeb\xb7\x14\x93\xc1\xdd\x7b\xe8\xb4"
|
||||
"\x9b\x46\xd1\xf4\x1b\x4a\xee\xc1\x12\x1b\x01\x37\x83\xf8\xf3\x52"
|
||||
"\x6b\x56\xd0\x37\xe0\x5f\x25\x98\xbd\x0f\xd2\x21\x5d\x6a\x1e\x52"
|
||||
"\x95\xe6\x4f\x73\xf6\x3f\x0a\xec\x8b\x91\x5a\x98\x5d\x78\x65\x98" },
|
||||
}},{
|
||||
// Long key and long data
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131,
|
||||
"\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75"
|
||||
"\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68"
|
||||
"\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65"
|
||||
"\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74"
|
||||
"\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64"
|
||||
"\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65"
|
||||
"\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20"
|
||||
"\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65"
|
||||
"\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e", 152, {
|
||||
{ "sha1", 20, "\x21\x7e\x44\xbb\x08\xb6\xe0\x6a\x2d\x6c\x30\xf3\xcb\x9f\x53\x7f\x97\xc6\x33\x56" },
|
||||
{ "sha256", 32, "\x9b\x09\xff\xa7\x1b\x94\x2f\xcb\x27\x63\x5f\xbc\xd5\xb0\xe9\x44"
|
||||
"\xbf\xdc\x63\x64\x4f\x07\x13\x93\x8a\x7f\x51\x53\x5c\x3a\x35\xe2" },
|
||||
{ "sha512", 64, "\xe3\x7b\x6a\x77\x5d\xc8\x7d\xba\xa4\xdf\xa9\xf9\x6e\x5e\x3f\xfd"
|
||||
"\xde\xbd\x71\xf8\x86\x72\x89\x86\x5d\xf5\xa3\x2d\x20\xcd\xc9\x44"
|
||||
"\xb6\x02\x2c\xac\x3c\x49\x82\xb1\x0d\x5e\xeb\x55\xc3\xe4\xde\x15"
|
||||
"\x13\x46\x76\xfb\x6d\xe0\x44\x60\x65\xc9\x74\x40\xfa\x8c\x6a\x58" },
|
||||
}}};
|
||||
|
||||
/*
|
||||
* Block cipher tests
|
||||
*/
|
||||
struct cipher_test_vector {
|
||||
const char *key;
|
||||
unsigned int key_length;
|
||||
const char *iv;
|
||||
unsigned int iv_length;
|
||||
const char *plaintext;
|
||||
unsigned int data_length;
|
||||
struct {
|
||||
const char *name;
|
||||
const char *mode;
|
||||
const char *ciphertext;
|
||||
} out[2];
|
||||
};
|
||||
|
||||
static struct cipher_test_vector cipher_test_vectors[] = {
|
||||
{ // NIST SP 800-38A
|
||||
"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", 16,
|
||||
NULL, 0,
|
||||
"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
|
||||
"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
|
||||
"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
|
||||
"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10", 64, {
|
||||
{
|
||||
"aes", "ecb",
|
||||
"\x3a\xd7\x7b\xb4\x0d\x7a\x36\x60\xa8\x9e\xca\xf3\x24\x66\xef\x97"
|
||||
"\xf5\xd3\xd5\x85\x03\xb9\x69\x9d\xe7\x85\x89\x5a\x96\xfd\xba\xaf"
|
||||
"\x43\xb1\xcd\x7f\x59\x8e\xce\x23\x88\x1b\x00\xe3\xed\x03\x06\x88"
|
||||
"\x7b\x0c\x78\x5e\x27\xe8\xad\x3f\x82\x23\x20\x71\x04\x72\x5d\xd4"
|
||||
},{
|
||||
"serpent", "ecb",
|
||||
"\xf7\xa7\x21\xe6\xc7\x56\xb6\x55\xcb\xdf\x53\x3f\xc3\xb3\x1a\xc4"
|
||||
"\x4b\xc6\x04\x29\x3a\x81\xa6\xa6\xe4\xcb\xa7\x8d\x1a\x32\xa2\x9e"
|
||||
"\xcf\xc2\x8e\x50\x97\xdd\x6b\x49\xa9\x38\xb1\x51\x5e\xbc\x5a\xac"
|
||||
"\xfe\xd2\xc4\x95\x92\xf9\x1c\x0c\x9f\x17\xcd\x86\x38\x65\x29\xeb"
|
||||
},
|
||||
}},{ // NIST SP 800-38A
|
||||
"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", 16,
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16,
|
||||
"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
|
||||
"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
|
||||
"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
|
||||
"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10", 64, {
|
||||
{
|
||||
"aes", "cbc",
|
||||
"\x76\x49\xab\xac\x81\x19\xb2\x46\xce\xe9\x8e\x9b\x12\xe9\x19\x7d"
|
||||
"\x50\x86\xcb\x9b\x50\x72\x19\xee\x95\xdb\x11\x3a\x91\x76\x78\xb2"
|
||||
"\x73\xbe\xd6\xb8\xe3\xc1\x74\x3b\x71\x16\xe6\x9e\x22\x22\x95\x16"
|
||||
"\x3f\xf1\xca\xa1\x68\x1f\xac\x09\x12\x0e\xca\x30\x75\x86\xe1\xa7"
|
||||
},{
|
||||
"serpent", "cbc",
|
||||
"\xdd\x73\x69\x1a\xb5\x66\xb6\x38\xe3\xb9\x62\x36\xc8\xc8\xa1\xdd"
|
||||
"\xa9\xb5\xd9\xdb\x20\xfb\x8b\x82\x51\x40\xbf\xe6\x4d\xf2\x1c\xa8"
|
||||
"\x5f\x48\xbc\x29\xff\x62\x27\xda\x09\x7c\xaa\x22\x75\x6f\x43\xff"
|
||||
"\x31\xd8\x3e\x83\x4d\x92\x48\xeb\x49\x1c\xf8\x26\x80\x4e\xb9\x02"
|
||||
},
|
||||
}},{ // NIST SP 800-38A
|
||||
"\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
|
||||
"\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", 32,
|
||||
NULL, 0,
|
||||
"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
|
||||
"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
|
||||
"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
|
||||
"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10", 64, {
|
||||
{
|
||||
"aes", "ecb",
|
||||
"\xf3\xee\xd1\xbd\xb5\xd2\xa0\x3c\x06\x4b\x5a\x7e\x3d\xb1\x81\xf8"
|
||||
"\x59\x1c\xcb\x10\xd4\x10\xed\x26\xdc\x5b\xa7\x4a\x31\x36\x28\x70"
|
||||
"\xb6\xed\x21\xb9\x9c\xa6\xf4\xf9\xf1\x53\xe7\xb1\xbe\xaf\xed\x1d"
|
||||
"\x23\x30\x4b\x7a\x39\xf9\xf3\xff\x06\x7d\x8d\x8f\x9e\x24\xec\xc7"
|
||||
},{
|
||||
"serpent", "ecb",
|
||||
"\x78\xe5\x84\x8e\xd9\xd5\xde\x2d\x4d\xb0\x2f\x53\x61\x6a\xfd\xf2"
|
||||
"\x50\x5d\xf1\x68\x92\x40\x8e\xf6\x9c\x3b\x9e\xa6\x67\xd9\xdd\xb8"
|
||||
"\xb9\x5f\xc8\x20\x76\x52\x1d\xce\x60\xe4\xfc\xac\xe3\xd3\x91\x51"
|
||||
"\x09\x22\x62\xde\x62\x6d\xc5\x7b\x4c\x87\x0c\x65\xe7\x1f\xc7\x13"
|
||||
},
|
||||
}},{ // NIST SP 800-38A
|
||||
"\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
|
||||
"\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", 32,
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16,
|
||||
"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
|
||||
"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
|
||||
"\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
|
||||
"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10", 64, {
|
||||
{
|
||||
"aes", "cbc",
|
||||
"\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6"
|
||||
"\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d\x67\x9f\x77\x7b\xc6\x70\x2c\x7d"
|
||||
"\x39\xf2\x33\x69\xa9\xd9\xba\xcf\xa5\x30\xe2\x63\x04\x23\x14\x61"
|
||||
"\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc\xda\x6c\x19\x07\x8c\x6a\x9d\x1b"
|
||||
},{
|
||||
"serpent", "cbc",
|
||||
"\xb8\x93\xc8\xde\xc5\xc8\x5f\x03\x01\xac\x32\x74\xdf\xc6\x71\x9d"
|
||||
"\x37\x61\xc5\xf8\x34\x4d\xe9\x10\x91\xd3\x87\x80\x42\xcc\x70\x95"
|
||||
"\x40\x95\xa3\x2c\xdb\x38\xe2\x6f\x03\x91\xf5\xd3\x51\x7e\x52\xb0"
|
||||
"\x8a\x1c\x2d\x7f\x04\x59\x13\x93\x31\xa9\x82\xc9\x4e\xd9\x11\x0c"
|
||||
},
|
||||
}},{ // CAVS XTSGenAES128,101
|
||||
"\xb7\xb9\x3f\x51\x6a\xef\x29\x5e\xff\x3a\x29\xd8\x37\xcf\x1f\x13"
|
||||
"\x53\x47\xe8\xa2\x1d\xae\x61\x6f\xf5\x06\x2b\x2e\x8d\x78\xce\x5e", 32,
|
||||
"\x87\x3e\xde\xa6\x53\xb6\x43\xbd\x8b\xcf\x51\x40\x31\x97\xed\x14", 16,
|
||||
"\x23\x6f\x8a\x5b\x58\xdd\x55\xf6\x19\x4e\xd7\x0c\x4a\xc1\xa1\x7f"
|
||||
"\x1f\xe6\x0e\xc9\xa6\xc4\x54\xd0\x87\xcc\xb7\x7d\x6b\x63\x8c\x47", 32, {
|
||||
{
|
||||
"aes", "xts",
|
||||
"\x22\xe6\xa3\xc6\x37\x9d\xcf\x75\x99\xb0\x52\xb5\xa7\x49\xc7\xf7"
|
||||
"\x8a\xd8\xa1\x1b\x9f\x1a\xa9\x43\x0c\xf3\xae\xf4\x45\x68\x2e\x19"
|
||||
},{
|
||||
"serpent", "xts",
|
||||
"\x6d\xa2\xa4\x2b\x18\x71\x57\xdc\x03\xaf\x8b\x82\x28\x66\x3d\xf1"
|
||||
"\x70\x8b\x75\x98\xd2\xdd\xbf\x72\x9e\xb3\xb4\xc2\x3f\x18\xdf\xa1"
|
||||
},
|
||||
}},{ // CAVS XTSGenAES256,101
|
||||
"\x26\x6c\x33\x6b\x3b\x01\x48\x9f\x32\x67\xf5\x28\x35\xfd\x92\xf6"
|
||||
"\x74\x37\x4b\x88\xb4\xe1\xeb\xd2\xd3\x6a\x5f\x45\x75\x81\xd9\xd0"
|
||||
"\x42\xc3\xee\xf7\xb0\xb7\xe5\x13\x7b\x08\x64\x96\xb4\xd9\xe6\xac"
|
||||
"\x65\x8d\x71\x96\xa2\x3f\x23\xf0\x36\x17\x2f\xdb\x8f\xae\xe5\x27", 64,
|
||||
"\x06\xb2\x09\xa7\xa2\x2f\x48\x6e\xcb\xfa\xdb\x0f\x31\x37\xba\x42", 16,
|
||||
"\xca\x7d\x65\xef\x8d\x3d\xfa\xd3\x45\xb6\x1c\xcd\xdc\xa1\xad\x81"
|
||||
"\xde\x83\x0b\x9e\x86\xc7\xb4\x26\xd7\x6c\xb7\xdb\x76\x68\x52\xd9"
|
||||
"\x81\xc6\xb2\x14\x09\x39\x9d\x78\xf4\x2c\xc0\xb3\x3a\x7b\xbb\x06", 48, {
|
||||
{
|
||||
"aes", "xts",
|
||||
"\xc7\x32\x56\x87\x0c\xc2\xf4\xdd\x57\xac\xc7\x4b\x54\x56\xdb\xd7"
|
||||
"\x76\x91\x2a\x12\x8b\xc1\xf7\x7d\x72\xcd\xeb\xbf\x27\x00\x44\xb7"
|
||||
"\xa4\x3c\xee\xd2\x90\x25\xe1\xe8\xbe\x21\x1f\xa3\xc3\xed\x00\x2d"
|
||||
},{
|
||||
"serpent", "xts",
|
||||
"\x37\xe4\xc0\xa9\xf1\x49\xe5\x3e\x73\xb9\x1f\xec\xdc\xe0\xbd\xc5"
|
||||
"\x31\xd7\xef\x08\x65\x20\xe3\xad\xd9\x84\x60\xdc\x61\x6f\x26\x86"
|
||||
"\xb8\xd5\x29\x4b\x04\x41\x52\x59\x05\x00\xb0\xc2\x9b\x30\xda\x48"
|
||||
},
|
||||
}},{
|
||||
"\xa5\x28\x24\x34\x1a\x3c\xd8\xf7\x05\x91\x8f\xee\x85\x1f\x35\x7f"
|
||||
"\x80\x3d\xfc\x9b\x94\xf6\xfc\x9e\x19\x09\x00\xa9\x04\x31\x4f\x11", 32,
|
||||
"\xa1\xba\x49\x95\xff\x34\x6d\xb8\xcd\x87\x5d\x5e\xfd\xea\x85\xdb"
|
||||
"\x8a\x7b\x5e\xb2\x5d\x57\xdd\x62\xac\xa9\x8c\x41\x42\x94\x75\xb7", 32,
|
||||
"\x69\xb4\xe8\x8c\x37\xe8\x67\x82\xf1\xec\x5d\x04\xe5\x14\x91\x13"
|
||||
"\xdf\xf2\x87\x1b\x69\x81\x1d\x71\x70\x9e\x9c\x3b\xde\x49\x70\x11"
|
||||
"\xa0\xa3\xdb\x0d\x54\x4f\x66\x69\xd7\xdb\x80\xa7\x70\x92\x68\xce"
|
||||
"\x81\x04\x2c\xc6\xab\xae\xe5\x60\x15\xe9\x6f\xef\xaa\x8f\xa7\xa7"
|
||||
"\x63\x8f\xf2\xf0\x77\xf1\xa8\xea\xe1\xb7\x1f\x9e\xab\x9e\x4b\x3f"
|
||||
"\x07\x87\x5b\x6f\xcd\xa8\xaf\xb9\xfa\x70\x0b\x52\xb8\xa8\xa7\x9e"
|
||||
"\x07\x5f\xa6\x0e\xb3\x9b\x79\x13\x79\xc3\x3e\x8d\x1c\x2c\x68\xc8"
|
||||
"\x51\x1d\x3c\x7b\x7d\x79\x77\x2a\x56\x65\xc5\x54\x23\x28\xb0\x03", 128, {
|
||||
{
|
||||
"xchacha12,aes", "adiantum",
|
||||
"\x9e\x16\xab\xed\x4b\xa7\x42\x5a\xc6\xfb\x4e\x76\xff\xbe\x03\xa0"
|
||||
"\x0f\xe3\xad\xba\xe4\x98\x2b\x0e\x21\x48\xa0\xb8\x65\x48\x27\x48"
|
||||
"\x84\x54\x54\xb2\x9a\x94\x7b\xe6\x4b\x29\xe9\xcf\x05\x91\x80\x1a"
|
||||
"\x3a\xf3\x41\x96\x85\x1d\x9f\x74\x51\x56\x63\xfa\x7c\x28\x85\x49"
|
||||
"\xf7\x2f\xf9\xf2\x18\x46\xf5\x33\x80\xa3\x3c\xce\xb2\x57\x93\xf5"
|
||||
"\xae\xbd\xa9\xf5\x7b\x30\xc4\x93\x66\xe0\x30\x77\x16\xe4\xa0\x31"
|
||||
"\xba\x70\xbc\x68\x13\xf5\xb0\x9a\xc1\xfc\x7e\xfe\x55\x80\x5c\x48"
|
||||
"\x74\xa6\xaa\xa3\xac\xdc\xc2\xf5\x8d\xde\x34\x86\x78\x60\x75\x8d",
|
||||
},{
|
||||
"xchacha20,aes", "adiantum",
|
||||
"\xb1\x8b\xa0\x05\x77\xa8\x4d\x59\x1b\x8e\x21\xfc\x3a\x49\xfa\xd4"
|
||||
"\xeb\x36\xf3\xc4\xdf\xdc\xae\x67\x07\x3f\x70\x0e\xe9\x66\xf5\x0c"
|
||||
"\x30\x4d\x66\xc9\xa4\x2f\x73\x9c\x13\xc8\x49\x44\xcc\x0a\x90\x9d"
|
||||
"\x7c\xdd\x19\x3f\xea\x72\x8d\x58\xab\xe7\x09\x2c\xec\xb5\x44\xd2"
|
||||
"\xca\xa6\x2d\x7a\x5c\x9c\x2b\x15\xec\x2a\xa6\x69\x91\xf9\xf3\x13"
|
||||
"\xf7\x72\xc1\xc1\x40\xd5\xe1\x94\xf4\x29\xa1\x3e\x25\x02\xa8\x3e"
|
||||
"\x94\xc1\x91\x14\xa1\x14\xcb\xbe\x67\x4c\xb9\x38\xfe\xa7\xaa\x32"
|
||||
"\x29\x62\x0d\xb2\xf6\x3c\x58\x57\xc1\xd5\x5a\xbb\xd6\xa6\x2a\xe5"
|
||||
},
|
||||
}}};
|
||||
|
||||
static int pbkdf_test_vectors(void)
|
||||
{
|
||||
char result[256];
|
||||
unsigned int i;
|
||||
struct kdf_test_vector *vec;
|
||||
const struct kdf_test_vector *vec;
|
||||
|
||||
for (i = 0; i < (sizeof(kdf_test_vectors) / sizeof(*kdf_test_vectors)); i++) {
|
||||
crypt_backend_memzero(result, sizeof(result));
|
||||
vec = &kdf_test_vectors[i];
|
||||
printf("PBKDF vector %02d %s ", i, vec->type);
|
||||
if (vec->hash && crypt_hash_size(vec->hash) < 0) {
|
||||
@@ -420,213 +665,255 @@ static int pbkdf_test_vectors(void)
|
||||
vec->salt, vec->salt_length,
|
||||
result, vec->output_length,
|
||||
vec->iterations, vec->memory, vec->parallelism)) {
|
||||
printf("crypto backend [FAILED].\n");
|
||||
return -EINVAL;
|
||||
printf("[FAILED]\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (memcmp(result, vec->output, vec->output_length)) {
|
||||
printf("expected output [FAILED].\n");
|
||||
printf("[FAILED]\n");
|
||||
printhex(" got", result, vec->output_length);
|
||||
printhex("want", vec->output, vec->output_length);
|
||||
return -EINVAL;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("[OK]\n");
|
||||
memset(result, 0, sizeof(result));
|
||||
}
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static const char* get_vec(struct hash_out* out, int i)
|
||||
static int crc32_test(const struct hash_test_vector *vector, unsigned int i)
|
||||
{
|
||||
switch (i) {
|
||||
case 0:
|
||||
return out->sha1_out;
|
||||
case 1:
|
||||
return out->sha256_out;
|
||||
case 2:
|
||||
return out->sha512_out;
|
||||
case 3:
|
||||
return out->rmd160_out;
|
||||
case 4:
|
||||
return out->wp512_out;
|
||||
uint32_t crc32;
|
||||
|
||||
if (vector->out[i].length != sizeof(uint32_t))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
crc32 = crypt_crc32(~0, (const unsigned char*)vector->data, vector->data_length) ^ ~0;
|
||||
|
||||
if ((unsigned char)vector->out[i].out[0] != ((crc32 >> 24) & 0xFF) ||
|
||||
(unsigned char)vector->out[i].out[1] != ((crc32 >> 16) & 0xFF) ||
|
||||
(unsigned char)vector->out[i].out[2] != ((crc32 >> 8) & 0xFF) ||
|
||||
(unsigned char)vector->out[i].out[3] != ((crc32 >> 0) & 0xFF)) {
|
||||
printf("[FAILED]\n");
|
||||
printhex(" got", (const char *)&crc32, sizeof(crc32));
|
||||
printhex("want", vector->out[i].out, vector->out[i].length);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int hash_test(void)
|
||||
{
|
||||
uint32_t crc32;
|
||||
const struct hash_test_vector *vector;
|
||||
unsigned int i, j;
|
||||
int r, hash_length;
|
||||
struct hash_in* in_vec;
|
||||
struct hash_out* out_vec;
|
||||
struct hash_alg* hash;
|
||||
int r;
|
||||
struct crypt_hash *h;
|
||||
char result[64];
|
||||
|
||||
for (i = 0; i < (sizeof(hash_inputs) / sizeof(*hash_inputs)); i++) {
|
||||
in_vec = &hash_inputs[i];
|
||||
out_vec = &hash_outputs[i];
|
||||
for (i = 0; i < ARRAY_SIZE(hash_test_vectors); i++) {
|
||||
vector = &hash_test_vectors[i];
|
||||
printf("Hash vector %02d: ", i);
|
||||
|
||||
// CRC32 vector test
|
||||
printf("Hash vector %02d: [CRC32]", i);
|
||||
crc32 = crypt_crc32(~0, (const unsigned char*)in_vec->buffer, in_vec->length) ^ ~0;
|
||||
if (crc32 != out_vec->crc32_out) {
|
||||
printf("expected output [FAILED].\n");
|
||||
printf(" got: %x\n", crc32);
|
||||
printf("want: %x\n", out_vec->crc32_out);
|
||||
return -EINVAL;
|
||||
}
|
||||
for (j = 0; j < ARRAY_SIZE(vector->out); j++) {
|
||||
|
||||
// Other hashes test
|
||||
for (j = 0; j < (sizeof(hash_algs) / sizeof(*hash_algs) - 1); j++) {
|
||||
hash = &hash_algs[j];
|
||||
|
||||
hash_length = crypt_hash_size(hash->name);
|
||||
if (hash_length != hash->length) {
|
||||
if (hash_length < 0) {
|
||||
printf("[%s N/A]", hash->name);
|
||||
continue;
|
||||
}
|
||||
return -EINVAL;
|
||||
// CRC32 vector test is special
|
||||
if (!strcmp("crc32", vector->out[j].name)) {
|
||||
if (crc32_test(vector, j) < 0)
|
||||
return EXIT_FAILURE;
|
||||
printf("[%s]", vector->out[j].name);
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("[%s]", hash->name);
|
||||
if (crypt_hash_init(&h, hash->name))
|
||||
return -EINVAL;
|
||||
if (crypt_hash_size(vector->out[j].name) < 0) {
|
||||
printf("[%s N/A]", vector->out[j].name);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = crypt_hash_write(h, in_vec->buffer, in_vec->length);
|
||||
if (crypt_hash_size(vector->out[j].name) != (int)vector->out[j].length)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (sizeof(result) < vector->out[j].length)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
crypt_backend_memzero(result, sizeof(result));
|
||||
printf("[%s]", vector->out[j].name);
|
||||
|
||||
if (crypt_hash_init(&h, vector->out[j].name))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
r = crypt_hash_write(h, vector->data, vector->data_length);
|
||||
if (!r)
|
||||
r = crypt_hash_final(h, result, hash->length);
|
||||
r = crypt_hash_final(h, result, vector->out[j].length);
|
||||
|
||||
crypt_hash_destroy(h);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (memcmp(result, get_vec(out_vec, j), hash->length)) {
|
||||
printf("expected output [FAILED].\n");
|
||||
printhex(" got", result, hash->length);
|
||||
printhex("want", get_vec(out_vec, j), hash->length);
|
||||
return -EINVAL;
|
||||
if (memcmp(result, vector->out[j].out, vector->out[j].length)) {
|
||||
printf("[FAILED]\n");
|
||||
printhex(" got", result, vector->out[j].length);
|
||||
printhex("want", vector->out[j].out, vector->out[j].length);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static const char* get_hmac_res(struct hmac_test_vector* out, int i)
|
||||
{
|
||||
switch (i) {
|
||||
case 0:
|
||||
return out->hmac_sha_1;
|
||||
case 1:
|
||||
return out->hmac_sha_256;
|
||||
case 2:
|
||||
return out->hmac_sha_512;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int hmac_test(void)
|
||||
{
|
||||
const struct hmac_test_vector *vector;
|
||||
struct crypt_hmac *hmac;
|
||||
struct hmac_test_vector *vector;
|
||||
struct crypt_hash *h;
|
||||
unsigned int i, j;
|
||||
int hmac_length, r;
|
||||
|
||||
int r;
|
||||
char result[64];
|
||||
char key[MAX_BLOCK_SIZE];
|
||||
|
||||
for (i = 0; i < (sizeof(hmac_test_vectors) / sizeof(*hmac_test_vectors)); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(hmac_test_vectors); i++) {
|
||||
vector = &hmac_test_vectors[i];
|
||||
printf("HMAC vector %02d: ", i);
|
||||
|
||||
for(j = 0; j < 3; j++) {
|
||||
struct hash_alg* hash = &hash_algs[j];
|
||||
hmac_length = crypt_hmac_size(hash->name);
|
||||
if (hmac_length != hash->length) {
|
||||
if (hmac_length < 0) {
|
||||
printf("[%s N/A]", hash->name);
|
||||
continue;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
printf("[%s]", hash->name);
|
||||
for(j = 0; j < ARRAY_SIZE(vector->out); j++) {
|
||||
|
||||
int key_length = vector->key_length;
|
||||
|
||||
// hash key first if key size is greater than max block size
|
||||
if (key_length > MAX_BLOCK_SIZE) {
|
||||
if (crypt_hash_init(&h, hash->name))
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_hash_write(h, vector->key, vector->key_length);
|
||||
|
||||
if (!r)
|
||||
r = crypt_hash_final(h, key, hash->length);
|
||||
|
||||
crypt_hash_destroy(h);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
key_length = hash->length;
|
||||
} else {
|
||||
memcpy(key, vector->key, vector->key_length);
|
||||
if (crypt_hmac_size(vector->out[j].name) < 0) {
|
||||
printf("[%s N/A]", vector->out[j].name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (crypt_hmac_init(&hmac, hash->name, key, key_length))
|
||||
return -EINVAL;
|
||||
if (crypt_hmac_size(vector->out[j].name) != (int)vector->out[j].length)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (sizeof(result) < vector->out[j].length)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
crypt_backend_memzero(result, sizeof(result));
|
||||
printf("[%s]", vector->out[j].name);
|
||||
|
||||
if (crypt_hmac_init(&hmac, vector->out[j].name, vector->key, vector->key_length))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
r = crypt_hmac_write(hmac, vector->data, vector->data_length);
|
||||
|
||||
if (!r)
|
||||
r = crypt_hmac_final(hmac, result, hmac_length);
|
||||
r = crypt_hmac_final(hmac, result, vector->out[j].length);
|
||||
|
||||
crypt_hmac_destroy(hmac);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (memcmp(result, get_hmac_res(vector, j), hash->length)) {
|
||||
printf("expected output [FAILED].\n");
|
||||
printhex(" got", result, hash->length);
|
||||
printhex("want", get_hmac_res(vector, j), hash->length);
|
||||
return -EINVAL;
|
||||
if (memcmp(result, vector->out[j].out, vector->out[j].length)) {
|
||||
printf("[FAILED]\n");
|
||||
printhex(" got", result, vector->out[j].length);
|
||||
printhex("want", vector->out[j].out, vector->out[j].length);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
static int cipher_test(void)
|
||||
{
|
||||
if (crypt_backend_init(NULL)) {
|
||||
printf("Crypto backend init error.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
const struct cipher_test_vector *vector;
|
||||
struct crypt_cipher *cipher;
|
||||
unsigned int i, j;
|
||||
char result[256];
|
||||
int r;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cipher_test_vectors); i++) {
|
||||
vector = &cipher_test_vectors[i];
|
||||
printf("CIPHER vector %02d: ", i);
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(vector->out); j++) {
|
||||
if (vector->iv_length &&
|
||||
crypt_cipher_ivsize(vector->out[j].name, vector->out[j].mode) != (int)vector->iv_length)
|
||||
return EXIT_FAILURE;
|
||||
if (vector->data_length > sizeof(result))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
r = crypt_cipher_init(&cipher, vector->out[j].name, vector->out[j].mode,
|
||||
vector->key, vector->key_length);
|
||||
if (r == -ENOENT || r == -ENOTSUP) {
|
||||
printf("[%s-%s N/A]", vector->out[j].name, vector->out[j].mode);
|
||||
continue;
|
||||
} else {
|
||||
printf("[%s-%s,%dbits]", vector->out[j].name, vector->out[j].mode, vector->key_length * 8);
|
||||
if (r)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
crypt_backend_memzero(result, sizeof(result));
|
||||
if (crypt_cipher_encrypt(cipher, vector->plaintext, result, vector->data_length,
|
||||
vector->iv, vector->iv_length)) {
|
||||
crypt_cipher_destroy(cipher);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (memcmp(vector->out[j].ciphertext, result, vector->data_length)) {
|
||||
printf("[ENCRYPTION FAILED]\n");
|
||||
printhex(" got", result, vector->data_length);
|
||||
printhex("want", vector->out[j].ciphertext, vector->data_length);
|
||||
crypt_cipher_destroy(cipher);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
crypt_backend_memzero(result, sizeof(result));
|
||||
if (crypt_cipher_decrypt(cipher, vector->out[j].ciphertext, result, vector->data_length,
|
||||
vector->iv, vector->iv_length)) {
|
||||
crypt_cipher_destroy(cipher);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (memcmp(vector->plaintext, result, vector->data_length)) {
|
||||
printf("[DECRYPTION FAILED]\n");
|
||||
printhex(" got", result, vector->data_length);
|
||||
printhex("want", vector->plaintext, vector->data_length);
|
||||
crypt_cipher_destroy(cipher);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
crypt_cipher_destroy(cipher);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void __attribute__((noreturn)) exit_test(const char *msg, int r)
|
||||
{
|
||||
if (msg)
|
||||
printf("%s\n", msg);
|
||||
crypt_backend_destroy();
|
||||
exit(r);
|
||||
}
|
||||
|
||||
int main(__attribute__ ((unused)) int argc, __attribute__ ((unused))char *argv[])
|
||||
{
|
||||
if (getenv("CRYPTSETUP_PATH")) {
|
||||
printf("Cannot run this test with CRYPTSETUP_PATH set.\n");
|
||||
exit(77);
|
||||
}
|
||||
|
||||
if (crypt_backend_init(NULL))
|
||||
exit_test("Crypto backend init error.", EXIT_FAILURE);
|
||||
|
||||
printf("Test vectors using %s crypto backend.\n", crypt_backend_version());
|
||||
|
||||
if (pbkdf_test_vectors())
|
||||
exit(EXIT_FAILURE);
|
||||
exit_test("PBKDF test failed.", EXIT_FAILURE);
|
||||
|
||||
if (hash_test())
|
||||
exit(EXIT_FAILURE);
|
||||
exit_test("HASH test failed.", EXIT_FAILURE);
|
||||
|
||||
if (hmac_test())
|
||||
exit(EXIT_FAILURE);
|
||||
exit_test("HMAC test failed.", EXIT_FAILURE);
|
||||
|
||||
crypt_backend_destroy();
|
||||
exit(EXIT_SUCCESS);
|
||||
if (cipher_test())
|
||||
exit_test("CIPHER test failed.", EXIT_FAILURE);
|
||||
|
||||
exit_test(NULL, EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
CRYPTSETUP="../cryptsetup"
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
MNT_DIR="./mnt_luks"
|
||||
DEV_NAME="dummy"
|
||||
DEV_NAME2="ymmud"
|
||||
@@ -50,7 +51,7 @@ function dm_crypt_features()
|
||||
[ $VER_MAJ -gt 1 ] && {
|
||||
DM_PERF_CPU=1
|
||||
DM_SECTOR_SIZE=1
|
||||
DM_KEYRING=1
|
||||
test -d /proc/sys/kernel/keys && DM_KEYRING=1
|
||||
return
|
||||
}
|
||||
|
||||
@@ -60,7 +61,7 @@ function dm_crypt_features()
|
||||
DM_SECTOR_SIZE=1
|
||||
fi
|
||||
if [ $VER_MIN -gt 18 -o \( $VER_MIN -eq 18 -a $VER_PTC -ge 1 \) ]; then
|
||||
DM_KEYRING=1
|
||||
test -d /proc/sys/kernel/keys && DM_KEYRING=1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
CRYPTSETUP="../cryptsetup"
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
DEV_NAME="discard-t3st"
|
||||
DEV=""
|
||||
PWD1="93R4P4pIqAH8"
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#
|
||||
# Test integritysetup compatibility.
|
||||
#
|
||||
INTSETUP=../integritysetup
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
INTSETUP=$CRYPTSETUP_PATH/integritysetup
|
||||
|
||||
INTSETUP_VALGRIND=../.libs/integritysetup
|
||||
INTSETUP_LIB_VALGRIND=../.libs
|
||||
|
||||
@@ -49,6 +51,9 @@ function dm_integrity_features()
|
||||
DM_INTEGRITY_META=1
|
||||
DM_INTEGRITY_RECALC=1
|
||||
}
|
||||
[ $VER_MIN -gt 2 ] && {
|
||||
DM_INTEGRITY_BITMAP=1
|
||||
}
|
||||
}
|
||||
|
||||
add_device() {
|
||||
@@ -154,24 +159,29 @@ intformat() # alg alg_out tagsize sector_size csum [keyfile keysize]
|
||||
echo "[OK]"
|
||||
}
|
||||
|
||||
int_error_detection() # alg tagsize sector_size key_file key_size
|
||||
int_error_detection() # mode alg tagsize sector_size key_file key_size
|
||||
{
|
||||
if [ -n "$5" ] ; then
|
||||
KEY_PARAMS="--integrity-key-file $4 --integrity-key-size $5"
|
||||
if [ "$1" == "B" ] ; then
|
||||
INT_MODE="-B"
|
||||
else
|
||||
INT_MODE=""
|
||||
fi
|
||||
if [ -n "$6" ] ; then
|
||||
KEY_PARAMS="--integrity-key-file $5 --integrity-key-size $6"
|
||||
else
|
||||
KEY_PARAMS=""
|
||||
fi
|
||||
dd if=/dev/zero of=$DEV bs=1M count=32 >/dev/null 2>&1
|
||||
|
||||
echo -n "[INTEGRITY:$1:$2:$3]"
|
||||
echo -n "[INTEGRITY:$1:$2:$3:$4]"
|
||||
echo -n "[FORMAT]"
|
||||
$INTSETUP format -q --integrity $1 --tag-size $2 --sector-size $3 $KEY_PARAMS $DEV || fail "Cannot format device."
|
||||
$INTSETUP format -q --integrity $2 --tag-size $3 --sector-size $4 $KEY_PARAMS $DEV $INT_MODE || fail "Cannot format device."
|
||||
echo -n "[ACTIVATE]"
|
||||
$INTSETUP open $DEV $DEV_NAME --integrity $1 --integrity-no-journal $KEY_PARAMS || fail "Cannot activate device."
|
||||
$INTSETUP open $DEV $DEV_NAME --integrity $2 --integrity-no-journal $KEY_PARAMS $INT_MODE || fail "Cannot activate device."
|
||||
|
||||
if [ -n "$4" -a -n "$5" ]; then
|
||||
if [ -n "$5" -a -n "$6" ]; then
|
||||
echo -n "[KEYED HASH]"
|
||||
KEY_HEX=$(xxd -c 256 -l $5 -p $4)
|
||||
KEY_HEX=$(xxd -c 256 -l $6 -p $5)
|
||||
[ -z "$KEY_HEX" ] && fail "Cannot decode key."
|
||||
dmsetup table --showkeys $DEV_NAME | grep -q $KEY_HEX || fail "Key mismatch."
|
||||
fi
|
||||
@@ -189,9 +199,8 @@ int_error_detection() # alg tagsize sector_size key_file key_size
|
||||
echo -n "Z" | dd of=$DEV bs=1 seek=$OFF_DEC conv=notrunc >/dev/null 2>&1 || fail "Cannot write to device."
|
||||
|
||||
echo -n "[DETECT ERROR]"
|
||||
$INTSETUP open $DEV $DEV_NAME --integrity $1 $KEY_PARAMS || fail "Cannot activate device."
|
||||
$INTSETUP open $DEV $DEV_NAME --integrity $2 $KEY_PARAMS $INT_MODE || fail "Cannot activate device."
|
||||
dd if=/dev/mapper/$DEV_NAME >/dev/null 2>&1 && fail "Error detection failed."
|
||||
|
||||
echo -n "[REMOVE]"
|
||||
$INTSETUP close $DEV_NAME || fail "Cannot deactivate device."
|
||||
echo "[OK]"
|
||||
@@ -299,19 +308,19 @@ intformat sha256 sha256 32 4096 33f7dfa5163ca9f740383fb8b0919574e38
|
||||
intformat hmac-sha256 hmac\(sha256\) 32 4096 33f7dfa5163ca9f740383fb8b0919574e38a7b20a94a4170fde4238196b7c4b4 $KEY_FILE 32
|
||||
|
||||
echo "Error detection tests:"
|
||||
int_error_detection crc32c 4 512
|
||||
int_error_detection crc32c 4 4096
|
||||
int_error_detection crc32 4 512
|
||||
int_error_detection crc32 4 4096
|
||||
int_error_detection sha1 20 512
|
||||
int_error_detection sha1 16 512
|
||||
int_error_detection sha1 20 4096
|
||||
int_error_detection sha256 32 512
|
||||
int_error_detection sha256 32 4096
|
||||
int_error_detection J crc32c 4 512
|
||||
int_error_detection J crc32c 4 4096
|
||||
int_error_detection J crc32 4 512
|
||||
int_error_detection J crc32 4 4096
|
||||
int_error_detection J sha1 20 512
|
||||
int_error_detection J sha1 16 512
|
||||
int_error_detection J sha1 20 4096
|
||||
int_error_detection J sha256 32 512
|
||||
int_error_detection J sha256 32 4096
|
||||
|
||||
which xxd >/dev/null 2>&1 || skip "WARNING: xxd tool required."
|
||||
int_error_detection hmac-sha256 32 512 $KEY_FILE 32
|
||||
int_error_detection hmac-sha256 32 4096 $KEY_FILE 32
|
||||
int_error_detection J hmac-sha256 32 512 $KEY_FILE 32
|
||||
int_error_detection J hmac-sha256 32 4096 $KEY_FILE 32
|
||||
|
||||
echo "Journal parameters tests:"
|
||||
# Watermark is calculated in kernel, so it can be rounded down/up
|
||||
@@ -360,4 +369,24 @@ else
|
||||
echo "[N/A]"
|
||||
fi
|
||||
|
||||
echo -n "Bitmap mode parameters:"
|
||||
if [ -n "$DM_INTEGRITY_BITMAP" ] ; then
|
||||
add_device
|
||||
$INTSETUP format -q $DEV --integrity-bitmap-mode $DEV2 || fail "Cannot format device."
|
||||
$INTSETUP open $DEV --integrity-bitmap-mode --bitmap-sectors-per-bit 65536 --bitmap-flush-time 5000 $DEV_NAME || fail "Cannot activate device."
|
||||
$INTSETUP status $DEV_NAME | grep -q 'bitmap 512-byte sectors per bit: 65536' || fail
|
||||
$INTSETUP status $DEV_NAME | grep -q 'bitmap flush interval: 5000 ms' || fail
|
||||
$INTSETUP close $DEV_NAME fail "Cannot deactivate device."
|
||||
echo "[OK]"
|
||||
echo "Bitmap error detection tests:"
|
||||
int_error_detection B crc32c 4 512
|
||||
int_error_detection B crc32c 4 4096
|
||||
int_error_detection B sha256 32 512
|
||||
int_error_detection B sha256 32 4096
|
||||
int_error_detection B hmac-sha256 32 512 $KEY_FILE 32
|
||||
int_error_detection B hmac-sha256 32 4096 $KEY_FILE 32
|
||||
else
|
||||
echo "[N/A]"
|
||||
fi
|
||||
|
||||
cleanup
|
||||
|
||||
@@ -22,7 +22,9 @@ CHKS_DMCRYPT=vk_in_dmcrypt.chk
|
||||
CHKS_KEYRING=vk_in_keyring.chk
|
||||
|
||||
PWD="aaa"
|
||||
CRYPTSETUP=../cryptsetup
|
||||
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
|
||||
function remove_mapping()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
CRYPTSETUP=../cryptsetup
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
|
||||
# try to validate using loop-AES losetup/kernel if available
|
||||
LOSETUP_AES=/losetup-aes.old
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
# that you are not using old gcrypt with flawed whirlpool
|
||||
# (see cryptsetup debug output)
|
||||
|
||||
CRYPTSETUP=../cryptsetup
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
TST_DIR=luks1-images
|
||||
MAP=luks1tst
|
||||
KEYFILE=keyfile1
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
#
|
||||
# Test cryptsetup/authenticated encryption compatibility.
|
||||
#
|
||||
CRYPTSETUP=../cryptsetup
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
DEV_NAME=dmi_test
|
||||
DEV=mode-test.img
|
||||
PWD1=nHjJHjI23JK
|
||||
|
||||
1275
tests/luks2-reencryption-test
Executable file
1275
tests/luks2-reencryption-test
Executable file
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,8 @@
|
||||
#turn on debug mode by following env. variable _DEBUG=1
|
||||
|
||||
PS4='$LINENO:'
|
||||
CRYPTSETUP=../cryptsetup
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
|
||||
CRYPTSETUP_VALGRIND=../.libs/cryptsetup
|
||||
CRYPTSETUP_LIB_VALGRIND=../.libs
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
#
|
||||
# Test mode compatibility, check input + kernel and cryptsetup cipher status
|
||||
#
|
||||
CRYPTSETUP=../cryptsetup
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
DEV_NAME=dmc_test
|
||||
HEADER_IMG=mode-test.img
|
||||
PASSWORD=3xrododenron
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
# check hash processing in create command
|
||||
|
||||
CRYPTSETUP=../cryptsetup
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
DEV_NAME=dmc_test
|
||||
KEY_FILE=keyfile
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
CRYPTSETUP=../cryptsetup
|
||||
REENC=../cryptsetup-reencrypt
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
REENC=$CRYPTSETUP_PATH/cryptsetup-reencrypt
|
||||
FAST_PBKDF="--pbkdf-force-iterations 1000"
|
||||
|
||||
DEV_NAME=reenc9768
|
||||
@@ -185,7 +186,14 @@ function mount_and_test() {
|
||||
}
|
||||
rm $MNT_DIR/* 2>/dev/null
|
||||
cd $MNT_DIR
|
||||
echo $PWD2 | $START_DIR/$REENC $LOOPDEV1 -q --use-fsync --use-directio --write-log $FAST_PBKDF || return 1
|
||||
|
||||
if [ "${REENC:0:1}" != "/" ] ; then
|
||||
MNT_REENC=$START_DIR/$REENC
|
||||
else
|
||||
MNT_REENC=$REENC
|
||||
fi
|
||||
|
||||
echo $PWD2 | $MNT_REENC $LOOPDEV1 -q --use-fsync --use-directio --write-log $FAST_PBKDF || return 1
|
||||
cd $START_DIR
|
||||
umount $MNT_DIR
|
||||
echo -n [OK]
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
CRYPTSETUP=../cryptsetup
|
||||
REENC=../cryptsetup-reencrypt
|
||||
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
|
||||
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
|
||||
REENC=$CRYPTSETUP_PATH/cryptsetup-reencrypt
|
||||
FAST_PBKDF_ARGON="--pbkdf-force-iterations 4 --pbkdf-memory 32 --pbkdf-parallel 1"
|
||||
FAST_PBKDF_PBKDF2="--pbkdf-force-iterations 1000 --pbkdf pbkdf2"
|
||||
DEFAULT_ARGON="argon2i"
|
||||
@@ -193,7 +194,13 @@ function mount_and_test() {
|
||||
}
|
||||
rm $MNT_DIR/* 2>/dev/null
|
||||
cd $MNT_DIR
|
||||
echo $PWD2 | $START_DIR/$REENC $START_DIR/$IMG -q --use-fsync --use-directio --write-log $FAST_PBKDF_ARGON || return 1
|
||||
|
||||
if [ "${REENC:0:1}" != "/" ] ; then
|
||||
MNT_REENC=$START_DIR/$REENC
|
||||
else
|
||||
MNT_REENC=$REENC
|
||||
fi
|
||||
echo $PWD2 | $MNT_REENC $START_DIR/$IMG -q --use-fsync --use-directio --write-log $FAST_PBKDF_ARGON || return 1
|
||||
cd $START_DIR
|
||||
umount $MNT_DIR
|
||||
echo -n [OK]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user