Compare commits

...

164 Commits

Author SHA1 Message Date
Milan Broz
d0dc59e792 Update po file. 2019-06-14 13:54:23 +02:00
Ondrej Kozina
0106c64369 Fix issues reported by valgrind.
keyslot_cipher member leaked after existing LUKS2 context reload.

crypt_keyslot_set_encryption may access freed memory if
crypt_keyslot_get_encryption was previously called with
CRYPT_ANY_SLOT parameter.
2019-06-14 13:50:09 +02:00
Ondrej Kozina
69fdb41934 Add tests for LUKS2 reencryption with multiple active keyslots. 2019-06-14 09:10:28 +02:00
Ondrej Kozina
550b3ee1d3 Fix off-by-one error in reencryption keyslots count check. 2019-06-14 09:10:28 +02:00
Milan Broz
961cc6a6d3 Prepare version 2.2.0-rc1. 2019-06-14 08:20:04 +02:00
Ondrej Kozina
05091ab656 Improve reencryption when dealing with multiple keyslots.
It's possible to retain all keyslots (passphrases) when
performing LUKS2 reencryption provided there's enough
space in LUKS2 json metadata.

When specific keyslot is selected all other keyslots
bound to old volume key get deleted after reencryption
is finished.

Existing tokens are assigned to new keyslots.
2019-06-13 17:04:34 +02:00
Ondrej Kozina
272505b99d If no hash is specified in pbkdf use default value for keyslot AF. 2019-06-13 17:04:21 +02:00
Ondrej Kozina
60a769955b Rename hash data parameter in reencrypt keyslot dump. 2019-06-12 12:36:51 +02:00
Ondrej Kozina
34bec53474 Drop excessive nested locking in LUKS2 keyslot store path.
Since commit 80a435f it's not needed to call device_write_lock
in function luks2_encrypt_to_storage. It's handled correctly on
upper layer.
2019-06-12 12:36:51 +02:00
Ondrej Kozina
c77ae65a0d Wipe both keyslot data and metadata holding single write lock. 2019-06-12 12:36:51 +02:00
Ondrej Kozina
1ed0430b82 Move LUKS2 write lock upper when storing reencryption keyslot. 2019-06-12 12:36:51 +02:00
Ondrej Kozina
82f640e360 Open device in locked mode for wipe when necessary. 2019-06-12 12:36:51 +02:00
Ondrej Kozina
44aabc3ae4 Drop reload of metadata in reencryption initialization. 2019-06-12 12:36:50 +02:00
Ondrej Kozina
bbdf9b2745 Read and compare metadata sequence id after taking write lock. 2019-06-12 12:36:46 +02:00
Ondrej Kozina
96a87170f7 Return usage count from device locking functions. 2019-06-12 11:51:08 +02:00
Ondrej Kozina
281323db42 Fix condition for printing debug message. 2019-06-12 11:51:08 +02:00
Milan Broz
32258ee8ae Fix debugging messages callback.
The debug messages should contain EOL char.

Also check string lengths in internal logging macros.
2019-06-11 15:26:53 +02:00
Milan Broz
df0faef9ca Add integritysetup bitmap mode test. 2019-06-04 20:05:13 +02:00
Ondrej Kozina
9c3a020ecf Remove useless debug message from keyslot dump. 2019-05-27 16:23:56 +02:00
Ondrej Kozina
4c4cc55bb7 Wipe backup segment data after reencryption is finished. 2019-05-27 16:05:21 +02:00
Ondrej Kozina
f4c2e7e629 Implement LUKS2 reencrypt keyslot dump. 2019-05-27 15:27:23 +02:00
Ondrej Kozina
eadef08fd5 Extend LUKS2 reencryption recovery tests.
- test repair commad for reencryption recovery.
- test close command is able to teardown leftover device stack after
  crash.
- test open performs recovery by default (to be able to open root
  volume).
2019-05-24 17:29:56 +02:00
Ondrej Kozina
0c725a257d Compare moved segment specific size against real device size only. 2019-05-24 17:29:56 +02:00
Ondrej Kozina
6f35fb5f80 Silence query error messages for unsupported target types. 2019-05-24 17:29:56 +02:00
Ondrej Kozina
cd1fe75987 Close all device handlers after failed internal load. 2019-05-24 17:29:56 +02:00
Ondrej Kozina
e92e320956 Add explicit device_close routine. 2019-05-24 17:29:56 +02:00
Ondrej Kozina
0e4757e0fb Add LUKS2 reencryption recovery in repair command. 2019-05-24 17:29:56 +02:00
Ondrej Kozina
bd6af68bc5 Add support for explicit reencryption recovery in request. 2019-05-24 17:07:37 +02:00
Ondrej Kozina
13050f73c1 Properly finished reencryption after recovery. 2019-05-24 17:07:37 +02:00
Ondrej Kozina
5472fb0c56 Refactor reencryption recovery during activation. 2019-05-24 17:07:36 +02:00
Ondrej Kozina
73c2424b24 Refactor LUKS2 device activation (in reencryption). 2019-05-24 17:07:36 +02:00
Milan Broz
5117eda688 Switch to Xenial distro in Travis. 2019-05-24 08:33:20 +02:00
Ondrej Kozina
cfbef51d3d Add interactive dialog in case active device auto-detection fails. 2019-05-22 12:50:18 +02:00
Ondrej Kozina
09cb2d76ef Add dialog with default 'no' answer. 2019-05-22 12:50:17 +02:00
Ondrej Kozina
3f549ad0df Refactor yesDialog utility. 2019-05-22 12:50:17 +02:00
Ondrej Kozina
60d26be325 Load volume key in keyring when activated by token.
LUKS2 should use keyring for dm-crypt volume keys by default
when possible. crypt_activate_by_token didn't load keys in
keyring by default. It was a bug.
2019-05-21 18:08:00 +02:00
Ondrej Kozina
013d0d3753 Rename internal reencrypt enum to REENC_PROTECTION_NONE. 2019-05-21 18:08:00 +02:00
Ondrej Kozina
97da67c6a8 Add tests for reencryption with fixed device size. 2019-05-21 18:08:00 +02:00
Ondrej Kozina
f74072ba28 Silence active device detection message in batch mode. 2019-05-21 16:05:23 +02:00
Ondrej Kozina
19eac239b7 Add --device-size parameter for use in LUKS2 reencryption.
Currently it's used only in LUKS2 reencryption code
for reencrypting initial part of data device only.

It may be used to encrypt/reencrypt only initial part
of data device if user is aware that rest of the device
is empty.
2019-05-21 15:54:43 +02:00
Ondrej Kozina
31cd41bfe4 Add support for reencryption of initial device part.
It's useful to reencrypt only initial device part only.
For example with golden image reencryption it may be useful
to reencrypt only first X bytes of device because we know
the rest of device is empty.
2019-05-21 15:54:07 +02:00
Ondrej Kozina
af6c321395 Set default length for reencryption with resilience 'none' only. 2019-05-21 15:54:07 +02:00
Milan Broz
448fca1fdf Integritysetup: implement new bitmap mode. 2019-05-21 15:54:07 +02:00
Ondrej Kozina
1923928fdc Drop duplicate error message from reencrypt load. 2019-05-21 15:54:07 +02:00
Ondrej Kozina
bee5574656 Add --resume-only parameter to reencrypt command. 2019-05-21 15:54:07 +02:00
Ondrej Kozina
8c8a68d850 Add CRYPT_REENCRYPT_RESUME_ONLY flag. 2019-05-13 18:23:20 +02:00
Ondrej Kozina
9159b5b120 Add coverity toctou annotation in device_open_excl.
We can't avoid this race due to undefined behaviour if called with
O_EXCL flag on regular file.

Let's double-check fd with O_EXCL flag is actually open block device.
2019-05-13 18:23:20 +02:00
Ondrej Kozina
2d0079905e Adapt device_open_excl to reusing of fds. 2019-05-10 21:05:31 +02:00
Ondrej Kozina
83c227d53c Sync device using internal write enabled descriptor. 2019-05-10 21:05:31 +02:00
Ondrej Kozina
ee57b865b0 Reuse device file desriptors. 2019-05-10 21:05:31 +02:00
Milan Broz
ecbb9cfa90 Use upstream gnulib patch for Coverity warning fixed by previous patch. 2019-05-10 21:03:22 +02:00
Ondrej Kozina
8545e8496b Fix memleak in reencryption with moved segment. 2019-05-07 17:17:34 +02:00
Kamil Dudka
75b2610e85 Fix TAINTED_SCALAR false positives of Coverity
Coverity Analysis 2019.03 incorrectly marks the input argument
of base64_encode(), and conseuqnetly base64_encode_alloc(), as
tainted_data_sink because it sees byte-level operations on the input.
This one-line annotation makes Coverity suppress the following false
positives:

Error: TAINTED_SCALAR:
lib/luks2/luks2_digest_pbkdf2.c:117: tainted_data_argument: Calling function "crypt_random_get" taints argument "salt".
lib/luks2/luks2_digest_pbkdf2.c:157: tainted_data: Passing tainted variable "salt" to a tainted sink.

Error: TAINTED_SCALAR:
lib/luks2/luks2_keyslot_luks2.c:445: tainted_data_argument: Calling function "crypt_random_get" taints argument "salt".
lib/luks2/luks2_keyslot_luks2.c:448: tainted_data: Passing tainted variable "salt" to a tainted sink.
2019-05-07 15:35:55 +02:00
Milan Broz
237021ec15 Fix some warnings in static analysis. 2019-05-07 13:44:43 +02:00
Ondrej Kozina
4f5c25d0dd Add HAVE_DECL_DM_TASK_RETRY_REMOVE define in local tests. 2019-05-06 15:42:11 +02:00
Ondrej Kozina
4c33ab1997 Remove internal config file scratching (breaks local tests.) 2019-05-06 15:41:37 +02:00
Ondrej Kozina
5bb65aca8f Remove all test dm devices with retry option if available. 2019-05-06 15:37:35 +02:00
Milan Broz
3fd7babacc Update Readme.md. 2019-05-03 15:50:39 +02:00
Ondrej Kozina
caea8a9588 Update rc release notes. 2019-05-03 15:16:12 +02:00
Ondrej Kozina
e1d6cba014 Add reencryption action man page. 2019-05-03 15:00:33 +02:00
Milan Broz
1f91fe7a2c Use JSON-debug wrappers. 2019-05-03 14:02:43 +02:00
Milan Broz
dc53261c3b Fix data leak in format and reencrypt command. 2019-05-03 13:06:58 +02:00
Milan Broz
b3e90a93b0 Add test release notes and increase ABI version. 2019-05-03 12:57:29 +02:00
Milan Broz
1f3e2b770c Fix offline reencryption tool name. 2019-05-02 21:05:22 +02:00
Ondrej Kozina
d310e896cb Add basic offline tests for LUKS2 reencryption. 2019-05-02 17:23:59 +02:00
Ondrej Kozina
a36245cef6 Add new reencrypt cryptsetup action.
The new reencryption code is enabled via cryptsetup cli
and works with LUKS2 devices only.
2019-05-02 16:45:43 +02:00
Ondrej Kozina
092ef90f29 Add autodetection code for active dm device. 2019-05-02 16:44:23 +02:00
Ondrej Kozina
64f59ff71e Add reencryption progress function. 2019-05-02 16:44:23 +02:00
Ondrej Kozina
a7f80a2770 Add resilient LUKS2 reencryption library code. 2019-05-02 16:44:23 +02:00
Ondrej Kozina
a5c5e3e876 Add dm_device_deps for quering dm device dependencies. 2019-05-02 15:23:29 +02:00
Ondrej Kozina
8e4fb993c0 Add error target support in dm_query_device. 2019-05-02 15:23:29 +02:00
Ondrej Kozina
846567275a Move dm_query_device body in static function. 2019-05-02 15:23:28 +02:00
Ondrej Kozina
741c972935 Remove unused minor number from dm_is_dm_device. 2019-05-02 15:23:28 +02:00
Ondrej Kozina
6c2760c9cd Report data sync errors from storage wrapper. 2019-04-29 16:48:20 +02:00
Ondrej Kozina
b35a5ee4a3 Replace table with error mapping even when in use. 2019-04-29 16:10:57 +02:00
Ondrej Kozina
345385376a Add missing validation check for area type specification. 2019-04-29 16:10:57 +02:00
Milan Broz
dbe9db26fc Never serialize memory-hard KDF for small amount of memory. 2019-04-29 16:10:57 +02:00
Milan Broz
91ba22b157 Do not try to remove device that was not succesfully activated. 2019-04-29 16:10:57 +02:00
Ondrej Kozina
86b2736480 Drop unused type parameter from LUKS2_keyslot_find_empty() 2019-04-23 10:41:56 +02:00
Milan Broz
cfe2fb66ab Fix some untranslated error messages. 2019-04-23 10:41:06 +02:00
Milan Broz
428e61253c Fix dm_error_device() to properly use error device. 2019-04-10 15:06:07 +02:00
Milan Broz
95bcd0c9d5 Fix previous patch locking to return EBUSY. 2019-04-10 14:27:42 +02:00
Milan Broz
23bada3c5a Fix several issues found by Coverity scan. 2019-04-10 12:30:09 +02:00
Stig Otnes Kolstad
de0cf8433b Add pbkdf options to all key operations in manpage 2019-04-09 17:19:41 +02:00
Milan Broz
1b49ea4061 Add global serialization lock for memory hard PBKDF.
This is very ugly workaround for situation when multiple
devices are being activated in parallel (systemd crypttab)
and system  instead of returning ENOMEM use OOM killer
to randomly kill processes.

This flag is intended to be used only in very specific situations.
2019-03-29 11:58:12 +01:00
Ondrej Kozina
29b94d6ba3 Add arbitrary resource locking (named locks).
It's complementary to current device locking. It'll be used
for mutual exclusion of two or more reencryption resume processes
2019-03-26 14:48:27 +01:00
Ondrej Kozina
80a435f00b Write keyslot binary data and metadata holding single lock. 2019-03-25 11:37:32 +01:00
Ondrej Kozina
fdcd5806b1 Allow to change requirements flag in-memory only. 2019-03-25 11:37:32 +01:00
Ondrej Kozina
9ddcfce915 Refactor locking code. 2019-03-25 11:37:32 +01:00
Ondrej Kozina
6ba358533b Modify crypt lock handle internal structure.
makes it ready for future lock handle type
2019-03-25 11:37:32 +01:00
TrueDoctor
73aa329d57 fixed Grammar in manpage cryptsetup-reencrypt(8) 2019-03-22 23:20:13 +00:00
Ondrej Kozina
379016fd78 Add no flush internal suspend/resume flag. 2019-03-22 08:01:21 +01:00
Ondrej Kozina
ea4b586c77 Add tests for CRYPT_VOLUME_KEY_DIGEST_REUSE flag.
Tests commit 7569519530
2019-03-22 08:01:21 +01:00
Ondrej Kozina
6961f2caae Switch crypt_suspend() to DM_SUSPEND_WIPE_KEY flag. 2019-03-22 08:01:21 +01:00
Ondrej Kozina
4df2ce4409 Add wipe key flag for internal device suspend. 2019-03-22 08:01:21 +01:00
Ondrej Kozina
052a4f432c Add internal option to skip fs freeze in device suspend. 2019-03-22 08:01:21 +01:00
Ondrej Kozina
de86ff051e Introduce support for internal dm suspend/resume flags. 2019-03-22 08:01:21 +01:00
Ondrej Kozina
f5feeab48d Add experimental storage wrappers. 2019-03-22 08:01:21 +01:00
Milan Broz
1317af028e Use compatible switch for free command. 2019-03-21 15:32:22 +01:00
Milan Broz
cdcd4ddd35 Print free memory in tests. 2019-03-21 15:16:33 +01:00
Milan Broz
2960164cf8 Fix localtest if the last test is skipped. 2019-03-21 15:12:39 +01:00
Milan Broz
a98ef9787c Set devel version. 2019-03-20 21:58:27 +01:00
Milan Broz
b6d406fbc8 Add fixed Makefile that can run tests outside of compiled tree. 2019-03-20 21:58:07 +01:00
Ondrej Kozina
e3488292ba Fix typo in --disable-keyring description. 2019-03-13 15:24:45 +01:00
Ondrej Kozina
fea2e0be4f Add algorithm for searching largest gap in keyslots area. 2019-03-13 14:56:31 +01:00
Milan Broz
751f5dfda3 Move error message for a keyslot area search. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
d5f71e66f9 Allow digest segment (un)binding for all segments at once. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
03e810ec72 Split crypt_drop_keyring_key in two different routines.
crypt_drop_keyring_key function allow to drop all keys in keyring
assocatiated with passed volume key list.

crypt_drop_keyring_key_by_description is used to drop independent key.
2019-03-13 14:56:31 +01:00
Ondrej Kozina
6c6f4bcd45 Add signed int64 json helpers. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
304942302b Introduce CRYPT_DEFAULT_SEGMENT abstraction.
Default segment is no longer constant segment with id 0.
2019-03-13 14:56:31 +01:00
Ondrej Kozina
8dc1a74df8 Adapt existing code to future reencryption changes. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
e295d01505 Adding new functions later used in reencryption. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
aa1b29ea0e Add volume key next helper. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
cef857fbbd Add routine for adding volume key in a list. 2019-03-13 14:56:31 +01:00
Ondrej Kozina
6bba8ce0dc Allow vk insert in linked list.
Also adds search function crypt_volume_key_by_id.
2019-03-13 14:56:31 +01:00
Ondrej Kozina
b0330d62e5 Add id member in volume_key structure.
Also adds set/get helper routines.
2019-03-13 14:56:31 +01:00
Frederik Nnaji
fc0c857cfe Update README.md 2019-03-13 13:52:40 +00:00
Milan Broz
238b18b8ac Upstream fixes to bundled Argon2 code.
Wait for already running threads if a thread creation failed.
Use explicit_bzero() on recent glibc versions.
(Without fixed logic, we have already macro definition through automake.)

Fixes #444.
2019-03-13 08:26:40 +01:00
Ondrej Kozina
6a2d023b7b Make keyring utilities ready for additional kernel key types. 2019-03-08 09:03:35 +01:00
Ondrej Kozina
4bb1fff15d Add new functions for kernel keyring handling. 2019-03-08 08:54:09 +01:00
Ondrej Kozina
37f5bda227 Add explicit key type name in keyring functions. 2019-03-08 08:53:33 +01:00
Ondrej Kozina
56b571fcaa Use const before vk in all digest verify functions. 2019-03-08 08:52:47 +01:00
Ondrej Kozina
46bf3c9e9c Add segment create helpers. 2019-03-08 08:44:51 +01:00
Ondrej Kozina
361fb22954 Remove helper get_first_data_offset completely. 2019-03-08 08:43:19 +01:00
Ondrej Kozina
203fe0f4bf Move get_first_data_offset to luks2_segment.c 2019-03-08 08:42:23 +01:00
Ondrej Kozina
36ac5fe735 Move LUKS2 segments handling in separate file. 2019-03-08 08:39:32 +01:00
Ondrej Kozina
7569519530 Allow unbound keyslots to be assigned to existing digest.
If passed key matches any existing digest we will not create
new digest but assign the keyslot to already existing one.

Because reencryption should be able to create more than one
keyslot assigned to new key digest.

TODO: Tests for the new feature
2019-03-08 08:37:27 +01:00
Ondrej Kozina
a848179286 Add json_object_copy wrapper. 2019-03-08 08:27:18 +01:00
Milan Broz
456ab38caa Allow to set CRYPTSETUP_PATH in tests for system installed cryptsetup tools.
Run: make check CRYPTSETUP_PATH=/sbin
2019-03-08 08:16:45 +01:00
Milan Broz
c71b5c0426 Update po files. 2019-03-08 08:15:57 +01:00
Ondrej Kozina
868cc52415 Abort conversion to LUKS1 with incompatible sector size. 2019-03-05 17:08:05 +01:00
Ondrej Kozina
8c168cc337 Introduce file for luks2 segments handling. 2019-03-05 17:08:02 +01:00
Ondrej Kozina
f9fa4cc099 Add kernel only detection in crypt storage API. 2019-03-05 17:07:57 +01:00
Ondrej Kozina
a0540cafb3 alter crypt_storage interface
rename sector_start -> iv_start (it's now a iv shift for subsequent
en/decrypt operations)

rename count -> length. We accept length in bytes now and perform sanity
checks at the crypt_storage_init and crypt_storage_decrypt (or encrypt)
respectively.

rename sector -> offset. It's in bytes as well. Sanity checks inside
crypt_storage functions.
2019-03-05 17:07:45 +01:00
Ondrej Kozina
88b3924132 Update LUKS2 locks for atomic operations.
Atomic operation requires to hold a lock for longer period than
single metadata I/O. Update locks so that we can:

- lock a device more than once (lock ref counting)
- reaquire read lock on already held write lock (write lock
  is stronger than read lock)
2019-03-05 17:07:31 +01:00
Ondrej Kozina
3023f26911 Always allocate new header file of 4KiB.
All issues related to header wiping and smaller
files were resolved. It's no longer needed to allocate
files larger than 4KiB.
2019-03-05 16:55:17 +01:00
Milan Broz
c9347d3d7d Fix a gcc warning when accessing packed struct member. 2019-03-05 16:50:24 +01:00
Ondrej Kozina
d85c7d06af Do not fail tests if benchmarked >= 1000 iterations with -i1. 2019-03-01 21:43:35 +01:00
Ondrej Kozina
e229f79741 Open device in locked mode if needed. 2019-03-01 21:43:31 +01:00
Ondrej Kozina
a4d236eebe Add device_is_locked function. 2019-03-01 21:43:25 +01:00
Milan Broz
1192fd27c6 Add query for cipher implementation is used through kernel API. 2019-03-01 21:43:10 +01:00
Milan Broz
cd1cb40033 Use crypto library for ciphers if algorithms are available. 2019-03-01 21:34:22 +01:00
Milan Broz
14e085f70e Move cipher performance check to crypto backend. 2019-03-01 21:16:05 +01:00
Milan Broz
fc37d81144 Move crypt_cipher to per-lib implementation.
For now, it calls kernel fallback only.
2019-03-01 21:14:13 +01:00
Milan Broz
a859455aad Move block ciphers backend wrappers to per-library files.
For now it always fallbacks to kernel crypto API.
2019-03-01 21:10:50 +01:00
Milan Broz
93d596ace2 Introduce internal backend header.
And remove commented-out test vectors (moved to tests).
2019-03-01 20:39:33 +01:00
Ondrej Kozina
c03e3fe88a Fix getting default LUKS2 keyslot encryption parameters.
When information about original keyslot size is missing (no active
keyslot assigned to default segment) we have to fallback to
default luks2 encryption parameters even though we know default
segment cipher and mode.

Fixes: #442.
2019-03-01 20:39:06 +01:00
Ondrej Kozina
a90a5c9244 Avoid double free corruption after failed crypt_init_data_device. 2019-03-01 20:31:00 +01:00
Ondrej Kozina
26772f8184 Return NULL explicitly if keyslot is missing.
json_object_object_get_ex return parameter is
undefined if function returns false.
2019-03-01 20:30:21 +01:00
Ondrej Kozina
8f8ad83861 Validate metadata before writting binary keyslot area. 2019-03-01 20:29:49 +01:00
Ondrej Kozina
d111b42cf1 Fix keyslot area gap find algorithm.
get_max_offset must use value calculated from LUKS2 metadata
boundaries. Data offset didn't have to match end of LUKS2 metadata
area.
2019-03-01 20:29:40 +01:00
Ondrej Kozina
821c965b45 Drop commented code block. 2019-03-01 20:28:56 +01:00
Ondrej Kozina
4acac9a294 Properly handle DM_LINEAR type while checking version or dmflags. 2019-03-01 20:28:43 +01:00
Ondrej Kozina
4adb06ae91 Add missing direction flag in dm_crypt_target_set.
This bug may have caused memory corruption in dm_targets_free
later.
2019-03-01 20:27:53 +01:00
Milan Broz
dce7a1e2aa Fix gcc warning in tests. 2019-02-24 12:35:54 +01:00
Milan Broz
a354b72546 Add some symmetric block ciphers vector tests for crypto backend. 2019-02-24 12:35:50 +01:00
Milan Broz
ac8f41404b Simplify and reformat hash/HMAC test vectors test. 2019-02-24 12:35:45 +01:00
Milan Broz
fc7b257bab Silence dmsetup removal messages. 2019-02-13 13:34:39 +01:00
Milan Broz
787066c292 Report error if no LUKS keyslots are available.
Also fix LUKS1 keyslot function to proper return -ENOENT errno in this case.

This change means, that user can distinguish between bad passphrase and
no keyslot available. (But this information was avalilable with luksDump
even before the change.)
2019-02-13 13:19:48 +01:00
Milan Broz
71ab6cb818 Fix other tests to not fail if keyring support is missing in kernel. 2019-02-12 16:16:56 +01:00
Milan Broz
1158ba453e Use better test for a bad loop descriptor. 2019-02-12 14:54:56 +01:00
Milan Broz
2e3f764272 Fix api-test-2 to properly detect missing keyring in kernel.
Also properly cleanup after some failures.
2019-02-12 14:49:21 +01:00
Milan Broz
2172f1d2cd Print PBKDF debug log in a better format.
Fixes #439.
2019-02-11 12:37:33 +01:00
Milan Broz
6efc1eae9f Update Readme.md. 2019-02-08 15:37:17 +01:00
103 changed files with 14865 additions and 3824 deletions

View File

@@ -1,7 +1,7 @@
language: c
sudo: required
dist: trusty
dist: xenial
compiler:
- gcc

View File

@@ -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).

View File

@@ -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],

View 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).

View File

@@ -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 \

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View 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;
}

View File

@@ -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;
}

View File

@@ -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)

View 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 */

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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

View File

@@ -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:
*;
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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)

View 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
};

View File

@@ -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

File diff suppressed because it is too large Load Diff

454
lib/luks2/luks2_segment.c Normal file
View 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;
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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];

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;
}

View 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;
}

View 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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

1421
po/es.po

File diff suppressed because it is too large Load Diff

3238
po/sv.po

File diff suppressed because it is too large Load Diff

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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)

View File

@@ -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;

View File

@@ -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
View 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;
}

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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
View 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

View File

@@ -1,6 +1,7 @@
#!/bin/bash
CRYPTSETUP="../cryptsetup"
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
DEV=""
DEV_STACKED="luks0xbabe"
DEV_NAME="dummyalign"

View File

@@ -1,6 +1,7 @@
#!/bin/bash
CRYPTSETUP="../cryptsetup"
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
DEV=""
DEV_STACKED="luks0xbabe"
DEV_NAME="dummyalign"

View File

@@ -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, &params2));
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, &params2));
/* 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;

View File

@@ -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;

View File

@@ -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)

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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
}

View File

@@ -1,6 +1,7 @@
#!/bin/bash
CRYPTSETUP="../cryptsetup"
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
DEV_NAME="discard-t3st"
DEV=""
PWD1="93R4P4pIqAH8"

View File

@@ -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

View File

@@ -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()
{

View File

@@ -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

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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]

View File

@@ -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