Compare commits

..

285 Commits

Author SHA1 Message Date
Milan Broz
517b5da67a Version 2.0.5. 2018-10-28 15:30:25 +01:00
Milan Broz
98460af44f Update LUKS2 docs. 2018-10-28 15:27:55 +01:00
Milan Broz
7213d5a76b Fix verbose message about key removal in luksKillSlot,luksErase and luksKremoveKey.
The crypt_keyslot_destroy() does not return keyslot number,
so return value 0 was always used as a keyslot reference.
2018-10-27 17:44:38 +02:00
Ondrej Kozina
bb29c5b322 Update man section describing convert command.
Fixes #414.
2018-10-26 10:07:41 +02:00
Milan Broz
58ad7bae48 Add 2.0.5 release notes. 2018-10-22 12:23:54 +02:00
Milan Broz
82a3480b12 Update po files. 2018-10-21 12:30:34 +02:00
Ondrej Kozina
c00811a846 Run LUKS2 validation code before header areas wiping.
Also drops redundant checks peformed in general validation code.
2018-10-18 08:48:48 +02:00
Milan Broz
27eaf46c8a Fix issues found by Coverity scan.
- possible overflow of data offset calculation in wipe and
- dereferencing of pointer in a keyring error path.
2018-10-14 21:50:06 +02:00
Milan Broz
202aeece3c Fix test module inclusion in tarball. 2018-10-14 20:54:06 +02:00
Milan Broz
825fc895dc Fix some signed/unsigned comparison warnings. 2018-10-14 20:36:45 +02:00
Milan Broz
a74aecedf1 Set devel version. 2018-10-14 20:24:34 +02:00
Milan Broz
fa1f63bcd0 Update po files. 2018-10-14 20:23:32 +02:00
Milan Broz
c2bce3e93e Wipe full header areas (including unused) during LUKS format.
All previous version of cryptsetup wiped only first 4k for LUKS1
and both JSON areas for LUKS2 (first 32k) and the allocated
keyslot area (as it contained the generated key).

Remaining areas (unused keyslots, padding, and alignment) were
not wiped and could contain some previous data.

Since this commit, the whole area up to the data offset is zeroed,
and subsequently, all keyslots areas are wiped with random data.

Only exceptions are
 - padding/alignment areas for detached header
   if the data offset is set to 0
 - bogus LUKS1 keyslot areas (upstream code never
   created such keyslots but someone could use that).

This operation could slow down luksFormat on some devices, but
it guarantees that after this operation LUKS header does not
contain any foreign data.
2018-10-14 13:11:50 +02:00
Milan Broz
a46733e701 Reintroduce error message if LUKS device is not detected.
Older cryptsetup printed this message through library,
later it disappeared even in cryptsetup binary.
2018-10-13 10:13:29 +02:00
Milan Broz
8f350f9b9f Print error message if crypt_load() detects unsupported version of LUKS. 2018-10-12 12:34:43 +02:00
Milan Broz
484692aacd Do not ask wiping questions in format if we just created the file. 2018-10-12 12:24:42 +02:00
Milan Broz
7f0df99511 Properly parse errno to error message for devices. 2018-10-12 12:03:56 +02:00
Milan Broz
bebd2fe7e7 Do not print error for used device twice. 2018-10-12 12:03:54 +02:00
Milan Broz
36e8839675 Do not fail if device is smaller than requested wipe size. 2018-10-11 21:20:34 +02:00
Ondrej Kozina
61305a50c1 Add delay=0 parameter to scsi_debug in all tests.
Speed up tests significantly.
2018-10-11 16:21:36 +02:00
Milan Broz
1d7749a40f Show better errors if kesylot decryption fails.
This happens also in cipher check where the old message was
very confusing.
2018-10-11 15:41:35 +02:00
Milan Broz
f01d044618 Print file name size instead of a loop device in error messages. 2018-10-11 15:40:22 +02:00
Milan Broz
31532adf86 Do not copy buffer if read fails. 2018-10-11 15:39:31 +02:00
Milan Broz
879e06db39 Wiping empty device should not fail. 2018-10-11 15:38:56 +02:00
Milan Broz
4beb0f702a Do not allow device activation if data area overlaps with LUKS header. 2018-10-11 11:55:45 +02:00
Ondrej Kozina
a771460dbd Add validation tests for optional segment flags section. 2018-10-11 11:55:26 +02:00
Ondrej Kozina
f849f83d84 Add validation code for option flags section of segment. 2018-10-11 11:55:22 +02:00
Ondrej Kozina
1d084a41ad Add support for optional flags section in LUKS2 segments dump. 2018-10-11 11:55:18 +02:00
Ondrej Kozina
c4198986f1 Sort LUKS2 segments by keys in crypt_dump output. 2018-10-11 11:55:13 +02:00
Milan Broz
7514786b20 Add an error message if device is unusable. 2018-10-04 20:00:12 +02:00
Milan Broz
9df042c0b8 Use explicit_bzero if available. 2018-10-04 15:21:01 +02:00
Ondrej Kozina
37e0150f70 Do not use fallocate in blockwise tests.
fs driver may skip some sanity checks if it's aware the content
of file is uninitialized.

Fixes warnings for xfs in kernel 4.19+
2018-10-04 11:20:03 +02:00
Milan Broz
294e4cbcb7 Fix tcrypt test on very old distros. 2018-10-02 13:56:57 +02:00
Milan Broz
952716afe1 Report versions in test run. 2018-10-02 13:46:03 +02:00
Milan Broz
24aba9a514 tcrypt: Support additional Veracrypt modes.
Add support for Camellia and Kuznyechik ciphers and Streebog hash functions,
introduced in recent Veracrypt.

Note, that Kuznyechik requires out-of-tree kernel module and Streebog
hash function is available only with gcrypt backend.
2018-10-02 10:47:38 +02:00
Milan Broz
905993751c Fix integritysetup build. 2018-09-29 18:28:10 +02:00
Milan Broz
0b10d877b0 Some more gcc warnings fixes. 2018-09-29 17:32:33 +02:00
Milan Broz
874fa5810d Do not use local libutils. 2018-09-29 10:42:05 +02:00
Milan Broz
5be31bbce6 More warnings fixes. 2018-09-27 20:54:06 +02:00
Milan Broz
a6e3a31690 Workaround for some gcc8 warnings.
Some new string length checks are too clever now...
2018-09-27 13:25:52 +02:00
Milan Broz
506f3f7b57 Decrease memory limit for pbkdf test. 2018-09-26 10:48:31 +02:00
Ondrej Kozina
cd1c36ef94 Allow passphrase change for unbound keyslots.
Also fixes small typo in API.

Fixes #409.
2018-09-25 13:13:31 +02:00
Ondrej Kozina
ee689d88b4 Add blkid scan when attemting to open plain device.
Warn user about existing device signatures on candidate ciphertext
device and prompt for action confirmation.

Fixes #411.
2018-09-25 13:13:18 +02:00
Ondrej Kozina
b93b676336 Move blkid scan after device context initialization.
Fixes bug with misleading error message when target device
does not exist.
2018-09-25 08:55:24 +02:00
Ondrej Kozina
1c6d66fccc Emit error message for converting inactive keyslot.
Fixes: #416.
2018-09-25 08:53:48 +02:00
Ondrej Kozina
114356ad2e Properly load new device context after header restore. 2018-09-25 08:53:26 +02:00
Ondrej Kozina
7ab419701c Rename get_key_size_strlen() to int_log10().
because that's what the function does
2018-09-25 08:52:29 +02:00
Ondrej Kozina
d41b1a7560 Unify checks for misaligned values. 2018-09-25 08:51:51 +02:00
Ondrej Kozina
622943529e Wipe LUKS header if luksFormat fails to add first keyslot. 2018-09-25 08:45:03 +02:00
Ondrej Kozina
9d7cc152f9 Do not enforce iv_tweak alignment in LUKS2 validation.
1) iv_tweak is not in 'bytes'
2) it may be arbitrary number
3) there's no reason to enforce alignment to encryption sector size

Fixes #406.
2018-09-25 08:44:31 +02:00
Milan Broz
3f73d448f3 Retry temporary device removal in align test. 2018-09-10 15:53:27 +02:00
Milan Broz
a1b606803f Fix HMAC vector test exit value. 2018-09-05 14:38:16 +02:00
Michal Virgovič
b2c7b40568 Add test vectors for HMAC - sha1, sha256, sha512. 2018-09-05 14:17:25 +02:00
Milan Broz
0cbe09d43a Rephrase LUKS info. 2018-09-03 15:16:31 +02:00
Milan Broz
f1d5b94762 Run API tests without verbose flag by default.
And rename some tests.
2018-08-10 12:36:15 +02:00
Ondrej Kozina
6fc2e7c774 Skip pbkdf benchmark in align-test (test speedup). 2018-08-10 08:20:00 +02:00
Ondrej Kozina
3b39c1d1ef Fix data alignment test in compat-test2.
Alignment should not expected failure when --align-payload is not
aligned to encryption sector size.
2018-08-10 08:19:49 +02:00
Ondrej Kozina
5a3e4abf71 Add basic LUKS2 align test. 2018-08-10 08:19:38 +02:00
Ondrej Kozina
48e9362186 Do not enforce encryption sector size alignment on data offset.
crypt segment data offset has nothing to do with encryption sector
size. The device may hint alignment offset which is completely
unrelated and LUKS2 validation blocks it.
2018-08-10 08:19:17 +02:00
Ondrej Kozina
03a74b74e5 Revert "Fix data alignment calculations with custom encryption sector size."
This reverts commit 71dd149ca2.

Enforcing data alignment to be encryption sector size aligned
is completelly wrong. The underlying data device alignment
has nothing to do with dm-crypt internal encryption sector size.

The restriction is however valid for dm-crypt segment size.
2018-08-10 08:19:02 +02:00
Ondrej Kozina
248f99cad3 Data alignment is always 512B sectors count. 2018-08-10 08:18:18 +02:00
Ondrej Kozina
d2f0773eb8 Remove useless division followed by multiplication by same base. 2018-08-10 08:16:27 +02:00
Ondrej Kozina
dd36d56d47 Fix miscalculation of device alignment offset.
device_topology_alignment routine already returns alignment offset
in bytes. There's no need to divide it by sector size, since LUKS2
format have all offsets and sizes stored in bytes.
2018-08-10 08:15:01 +02:00
Milan Broz
0270fc66a1 Fix align test.
Seems that the forced alignment value was never properly used...
2018-08-09 13:53:48 +02:00
Milan Broz
69a844c654 Remove O_SYNC from device open and use fsync().
This speed up wipe operation considerably.
2018-08-09 12:01:20 +02:00
Ondrej Kozina
5b5a64361f Update blockwise-compat test.
Issue warning in case of failure with file-systems based
tests.

Mute the test so that it prints out messages only for 'warning'
and 'fail' results.
2018-08-08 21:48:10 +02:00
Milan Broz
26f6d1cb10 Create --master-key-file in luksDump and fail if file already exists.
For some reason the volume key file have to exists.

Let's change the logic to the same as for luksBackupHeader
(a file is created and operation fails if it already exists).
2018-08-08 14:32:15 +02:00
Ondrej Kozina
f87eb1668a Allow compat-test2 to run with larger LUKS2 header size. 2018-08-08 12:55:29 +02:00
Milan Broz
3114abfd55 Remove not needed -Z option from diff that is not present on older systems. 2018-08-08 10:43:03 +02:00
Ondrej Kozina
5a94cff91e Do not fail device-test with larger LUKS2 header. 2018-08-08 10:13:40 +02:00
Ondrej Kozina
d704e87ee4 No need to lock data device in crypt_format. 2018-08-08 08:54:42 +02:00
Ondrej Kozina
c8ce996872 Wipe data device in crypt_format with auth. encryption.
crypt_wipe_device was called incorrectly on metadata device even
though integrity header is always on data device from cryptsetup
pov. During LUKS2 crypt_format with detached header scenario we
would wiped first 8 sectors of metadata device instead of data
device.
2018-08-08 08:52:44 +02:00
Milan Broz
0e7b068061 Add sector-size & payload align test. 2018-08-08 08:45:26 +02:00
Ondrej Kozina
71dd149ca2 Fix data alignment calculations with custom encryption sector size. 2018-08-08 08:01:45 +02:00
Ondrej Kozina
b30ba41d6a Fix typo in blockwise-compat test. 2018-08-08 07:44:07 +02:00
Ondrej Kozina
a0bf790892 Fix FAST_PBKDF typos in LUKS2 reencrypt tests. 2018-08-08 07:43:56 +02:00
Ondrej Kozina
caefc4eb8e Add basic test for token import and export. 2018-08-08 07:42:58 +02:00
Milan Broz
31364c17d6 Fix configure typo in previous patch. 2018-08-07 15:28:43 +02:00
Milan Broz
5e56966e72 Make tests for strings in configure more consistent.
Intead of
  test x$enable_xyz = xyes;
use
  test "$enable_xyz" = "xyes"; then
2018-08-07 09:29:51 +02:00
Milan Broz
1f951ed7ec Use AC_ARG_ENABLE consistently.
AC_ARG_ENABLE(feature, ...) -> AC_ARG_ENABLE([feature], ...
2018-08-07 08:37:55 +02:00
joerichey@google.com
ecd82f1fc9 Fix configure.ac formatting
Currently, AC_ARG_[ENABLE|WITH] are used in multiple different ways.
This change makes all their uses the same by following the style of
the GNU manual:
  - AC_ARG_ENABLE(foo) should only define $enable_foo
  - Use the 2 argument form with a --enable_foo flag
  - Use the 4 argument form with a --disable_foo flag
  - Format all uses the same way
  - Always compare using: test "x$enable_foo" = "xyes"

This makes the easier to debug, more readable, and shorter.

This formatting fix also revealed a bug (fix submitted seperately).
2018-08-07 08:21:25 +02:00
Milan Broz
7aaf1eeb1b Fix bz2->xz untar api-test option. 2018-08-06 15:16:39 +02:00
Milan Broz
e53fe70668 Use only xz archives in tests.
Bzip2 is sometimesmissing and we use xz already.

Seems xz produces slightly larger archives (despite the best mode)
but it is not worth to keep bz2 here.
2018-08-06 13:48:54 +02:00
Milan Broz
9e2e0a4a2d Update Readme.md 2018-08-03 12:51:22 +02:00
Milan Broz
b52719fd73 Version 2.0.4. 2018-08-03 12:31:21 +02:00
Milan Broz
7953976d25 Add 2.0.4 Release Notes 2018-08-03 12:29:31 +02:00
Ondrej Kozina
39d6b94835 Add test for reencryption after format conversion. 2018-08-03 11:15:43 +02:00
Ondrej Kozina
4fdce0695d Add test for LUKS2 detached header with non-default alignment. 2018-08-03 11:15:33 +02:00
Ondrej Kozina
ae8247fe6a Calculate keyslots area size properly with detached headers.
When LUKS2 crypt_format() is called with detached header and custom data
alignment is requested, keyslots area is miscalculated. This mistake
is correctly detected by LUKS2 validation code but it's feature
regression with regard to LUKSv1 format.
2018-08-03 11:15:27 +02:00
Milan Broz
d664565174 Add snapshot of LUKS2 docs. 2018-08-02 15:47:56 +02:00
Ondrej Kozina
b24a46ad8f Add tests for updated segments validation.
Tests commit c1777cfb8
2018-08-02 09:21:23 +02:00
Ondrej Kozina
6bffe34faa Fix problem found by Coverity scan.
NEGATIVE_RETURNS from crypt_hmac_size().
2018-08-02 09:19:57 +02:00
Milan Broz
abe3fb4acb Return no encryption if segment is not crypt type.
Currently the code expects "cipher" everywhere, this is temporary
workaround to enable basic operations if other segmens are present
in metadata.
2018-08-01 13:58:08 +02:00
Ondrej Kozina
39905bd8fd Return proper err when looking for segment digest.
Otherwise keyslot in luksDump are wrongly marked as device
keyslots even though default segment is not crypt.
2018-08-01 13:57:06 +02:00
Ondrej Kozina
078dbfb0a9 Do not dump crypt segment specific fields for other types. 2018-08-01 13:56:50 +02:00
Ondrej Kozina
dfeb5cfdd2 Do not allow segment with size set to 0. 2018-08-01 13:56:40 +02:00
Ondrej Kozina
c1777cfb89 Move crypt specific segment validation in new routine.
Also rename all 'length' variable to 'size' since json
field is named size.

Make segment validation two step process. First
validate general segment object is valid and later
validate specific segment type has all necessary fields.

Without this patch older libraries won't be able to print out
(luksDump) basic information about devices created with newer
libraries.
2018-08-01 13:55:28 +02:00
Ondrej Kozina
974072bdae Add segment validation tests. 2018-08-01 13:53:14 +02:00
Ondrej Kozina
b95e18956f Fix possible segfault in validation code.
If any segment has missing 'offset' field keyslots validation
routine could trigger segfault due to misuse of function that
expects valid 'segments' object.

Fix it by reordering validation routines.
2018-08-01 13:52:46 +02:00
Michal Virgovič
3c1c5ef281 Add vector tests for hash algorithms. 2018-08-01 09:16:44 +02:00
Ondrej Kozina
7194b14cd2 Fix typo in crypt_persistent_flags_set documentation. 2018-07-27 13:50:34 +02:00
Milan Broz
4e6f8d561c Update po files. 2018-07-27 08:39:49 +02:00
Milan Broz
ac26921569 Add support for dm-integrity superblock V2.
Only support parsing superblock data,
new functions will be supported in later kernel and releases.
2018-07-21 15:24:07 +02:00
Rafael Fontenelle
a60543728b Remove unmatched parethensis
This string had parentheses around part of the text, but it was restyled.
2018-07-21 07:25:52 -03:00
Rafael Fontenelle
f35ec9771e Fix typos
A bunch of typos reported by codespell, most of them comments in the code
2018-07-21 07:24:25 -03:00
Ondrej Kozina
de4fe99e34 Silence empty stdin error message in tests. 2018-07-21 11:28:46 +02:00
Ondrej Kozina
8ea6b3eebd Redirect stdout to stderr during reencryption in initrd.
Stdout is not printed in initrd unless user invokes debug mode.
It's inconvenient to have users waiting for reencryption to
finish with no input at all.
2018-07-21 11:28:41 +02:00
Milan Broz
a01836fe8d Update po files. 2018-07-21 11:28:24 +02:00
Ondrej Kozina
268dc97857 Emit error when there's nothing to read from key file. 2018-07-20 15:24:16 +02:00
Milan Broz
fc203c9654 Set devel version. 2018-07-19 14:48:34 +02:00
Milan Broz
8eedd5b277 Update po files. 2018-07-19 14:47:06 +02:00
Milan Broz
561d9ac2bc Fix problems found by Coverity scan. 2018-07-19 14:45:46 +02:00
Milan Broz
1112da76f1 Fix some compiler warnings. 2018-07-19 14:45:37 +02:00
Ondrej Kozina
081aa18f39 Exclude valgrind logs from git. 2018-07-19 14:45:29 +02:00
Milan Broz
c05c8bbba1 Fix switched parameters in cryptsetup-reencrypt. 2018-07-19 14:45:23 +02:00
Milan Broz
eabd23f31e Print verbose message about keyslot and token numbers.
Move all messages to cryptsetup tools and print these
verbose messages:

  - Key slot X unlocked.
  - Key slot X created.
  - Key slot X removed.
and
  - Token X created.
  - Token X removed.

Also print error, if unknown token is tried to be removed.
2018-07-19 14:45:16 +02:00
Ondrej Kozina
cc27088df9 Add support for LUKS2 token export and import. 2018-07-19 14:44:54 +02:00
Ondrej Kozina
97ab7e9c65 Add interruptible variants of buffered io. 2018-07-19 14:44:42 +02:00
Ondrej Kozina
bbf92828f6 Move buffered io implementation in new functions.
No functional changes yet. See later commits.
2018-07-19 14:44:37 +02:00
Milan Broz
2f83bf9f83 Change wording of blkid signature messages. 2018-07-18 13:22:11 +02:00
Ondrej Kozina
b2a1728201 Fix bundled argon2 distcheck errors. 2018-07-18 11:57:43 +02:00
Ondrej Kozina
18cbbbe9aa Silent compiler warning about unused code. 2018-07-18 11:56:34 +02:00
Ondrej Kozina
d90f8a3697 Remove useless redeclaration in blkid_utils. 2018-07-18 11:56:19 +02:00
Ondrej Kozina
fe3ef6fc2e Fix type mistake in blkid_handle allocation. 2018-07-18 11:56:12 +02:00
Ondrej Kozina
1b9148f12f dracut-reencrypt: add --progress-frequency parameter 2018-07-18 11:56:04 +02:00
Ondrej Kozina
deb8e49483 Cleanup test files after failure.
'missing-file' must be removed if test failes. Otherwise
the test fails even after regression is fixed :)
2018-07-18 11:55:53 +02:00
Ondrej Kozina
d75af2a156 Move pwquality libs in tools. 2018-07-18 11:55:47 +02:00
Ondrej Kozina
9895edefff Fix misleading parameter name in crypt_keyfile_device_read.
This patch has no functional impact. It only renames misleading
parameter 'keyfile_size_max' to 'key_size' because that's
how it's actually interpreted since beginning. Also updated
API documentation accordingly.
2018-07-18 11:55:20 +02:00
Ondrej Kozina
b60e856087 Rephrase error message for invalid --type param in convert. 2018-07-17 10:53:20 +02:00
Milan Broz
6244b4d00f Use LANG=C in interactive tests. 2018-07-13 08:58:38 +02:00
Milan Broz
ee167b1a43 Fix offset parsing in unit test. 2018-07-11 22:41:15 +02:00
Ondrej Kozina
e8b9bfe44c Use 'cannot' instead of 'can not' in every message. 2018-07-11 22:39:31 +02:00
Ondrej Kozina
50f5593ffc Update dm-crypt version check in device-test.
Test is now able to detect backported sector_size feature
in RHEL7 kernels.
2018-07-11 22:24:26 +02:00
Ondrej Kozina
3f0f7acbc0 Update cryptsetup man page for --type option usage.
Fixes #394.
2018-07-11 22:24:05 +02:00
Ondrej Kozina
7f6f8ec386 Test fixes for pbkdf verifications. 2018-07-11 22:23:53 +02:00
Ondrej Kozina
24d1798779 Fix mistakes in pbkdf_type verification.
- hash is currently relevant only for pbkdf2
- time_ms may be unset (zero) if forced iterations
  are set.

Fixes #398.
2018-07-11 22:23:41 +02:00
Ondrej Kozina
3e9d603f0b Add cryptsetup repair tests. 2018-07-11 22:23:24 +02:00
Ondrej Kozina
71a8fd3106 Test basic LUKS2 repair capabilities.
a) checks crypt_load() fails when single LUKS2 header is corrupted and
   blkid detect other device signature from LUKS or none.
b) check explicit crypt_repair is able to override blkid restriction
   and fix corrupted primary header
c) check a) and b) with disabled locks
2018-07-11 22:23:10 +02:00
Ondrej Kozina
49279a3c19 Print device signatures before prompt in repair action. 2018-07-11 22:22:47 +02:00
Milan Broz
43a1291f7c Add Argon2 SSE compile to Travis script. 2018-07-11 22:22:32 +02:00
Milan Broz
6dc5340f60 Add libblkid-dev to Travis script install. 2018-07-11 22:22:16 +02:00
Ondrej Kozina
2a6e33bc73 Add prompt for integritysetup format action.
Also adds blkid wipe support when user confirms format action.
2018-07-11 22:22:04 +02:00
Ondrej Kozina
0f6b2cfd3d Wipe all device signatures in luksFormat action. 2018-07-11 22:21:51 +02:00
Ondrej Kozina
30d109c0e9 Add support for blkid scans and signature wiping in tools. 2018-07-11 22:21:32 +02:00
Ondrej Kozina
e8e1f844d9 Extend blkid utilities for signatures wiping.
For older distributions there's fallback mode for missing
blkid_do_wipe function. We erase signatures based on offsets
and lengths detected by blkid.
2018-07-11 22:20:54 +02:00
Ondrej Kozina
05a89e5566 Allow LUKS2 repair with disabled locks. 2018-07-11 22:20:31 +02:00
Ondrej Kozina
c122889c95 Update crypt_repair API documentation for LUKS2. 2018-07-11 22:20:16 +02:00
Ondrej Kozina
9de5dc932b Allow explicit LUKS2 repair.
Also moves FIXME comment lower to LUKS2 code with note that currently it's
safe to do crypt_repair on LUKS2 format without paying attention to LUKS2
requirements.
2018-07-11 22:19:58 +02:00
Ondrej Kozina
289c9ecf5d Allow LUKS2 repair to override blkid checks.
Allow user to run cryptsetup repair command and explicitly do
repair on corrupted LUKS2 headers where blkid decides it's no longer
a LUKS2 device.
2018-07-11 22:19:47 +02:00
Ondrej Kozina
2c1a6e3f94 Make LUKS2 auto-recovery aware of device signatures.
auto-recovery triggers any time when only single correct LUKS2
header instance was found. That may be dangerous.

We should suppress auto-recovery in case blkid decided the
device is no longer LUKS device. For example if secondary (intact)
LUKS2 header was left behind and blkid declares the device is LVM2
member.

Moreover if at least one header instance is corrupted and blkid
declares device non-empty and non-LUKS in the same time, header load
operation will be aborted with error.
2018-07-11 22:19:35 +02:00
Ondrej Kozina
ad092a898d Add blkid utilities for fast detection of device signatures. 2018-07-11 22:19:11 +02:00
joerichey@google.com
56f2548b6e Fix --disable-dev-random bug
--disable-dev-random now disables reading from /dev/random instead of
incorrectly enabling it. This was found by reviewing all of flags
in configure.ac.
2018-07-11 22:03:47 +02:00
joerichey@google.com
25467243a6 Add missing call to crypt_random_exit
We call crypt_random_init in init_crypto, but never call
crypt_random_exit. This change just copies what the crypt_backend
functions do, and calls crypt_random_exit in the descructor.
2018-07-11 22:03:44 +02:00
joerichey@google.com
e07d40fc26 Fix .gitignore to ignore all generated files 2018-07-11 22:03:41 +02:00
Milan Broz
09877e4e63 Use explicit list for LUKS2 secondary header offsets.
The code scan for the second header only if primary is corrrupted.

Let's set the possible offsets more clear.

This patch also removes 8kB header offset (that was not supported anyway).
2018-07-11 10:05:36 +02:00
Milan Broz
d3460b6cf5 Fix internal bundled Argon2 build. 2018-07-07 11:06:54 +02:00
Milan Broz
ba384d15d2 Add optimized Argon2 SSE code.
Note: it is always better to use external libargon2 library.

Unfortunately, until Argon2 is in generic crypto libraries,
we must sometimes use bundled version just for bureaucratic reasons.

Let's include optimized variant of reference implementation as well.

Note, this code will not add any SSE compiler switches.

If --enable-internal-sse-argon2 option is used, it checks if current
compilation flags support simple SSE progam and if so, it use
the optimized variant.
(Not tested for AVX optimizations; it expects that SSE is enabled as well.)
2018-07-07 10:36:49 +02:00
Milan Broz
2f38ade0e0 Update Argon2 header to match upstream. 2018-07-07 10:35:23 +02:00
Ondrej Kozina
4d110d4c82 Silence luksFormat in tests. 2018-07-07 10:26:32 +02:00
Ondrej Kozina
1bf5ff3e6e Open files in read-write mode for posix_fallocate.
Unfortunately there exists some weird NFS variations requiring read
permissions for fallocate.
2018-07-07 10:25:01 +02:00
Milan Broz
cd2a1a169f Skip test if scsi_debug is not available. 2018-07-07 10:24:35 +02:00
joerichey@google.com
59b5f360af Make all header files self-suffienct
Almost all the headers in cryptsetup are self-suffienct (in that they
compile on their own). By including <stddef.h>, <stdint.h>, or
<sys/types.h>, all headers will now compile on their own.

This is useful for importing cryptsetup into Bazel/Blaze.
2018-07-07 10:23:39 +02:00
joerichey@google.com
e8b6890318 Don't implicitly discard const
As poptGetOptArg() returns "const char *", assigning it to a
"const char *" varible triggers a warning on Clang:
"incompatible-pointer-types-discards-qualifiers".
2018-07-07 10:22:57 +02:00
Ondrej Kozina
d7b9ed05f0 Add scsi_debug_teardown loop in blockwise tests.
scsi_debug module sometimes fails to remove due to
open references from udev scans.
2018-06-20 16:58:25 +02:00
Ondrej Kozina
dc852a100f Fix write_blockwise on short files.
see unit test write_blockwise(length=2097153, bsize=4096), on x86
with original test file size=2097152.

The test is trying to write_blockwise 1 more byte than actual file
size.
2018-06-20 16:58:19 +02:00
Ondrej Kozina
838d51d296 Fix write_lseek_blockwise for in the middle of sector case.
See unit test write_lseek_blockwise(bsize=512, offset=1, length=1).

The test tries to modify single byte at offset 1 of device with
bsize=512.
2018-06-20 16:58:01 +02:00
Ondrej Kozina
e2845bc032 Zero length lseek blockwise i/o should return zero.
Note that both functions perform seek operations aligned to sector
boundary if possible before returning.

Unaligned input offset gets aligned on first preceding sector
boundary.
2018-06-20 16:57:54 +02:00
Ondrej Kozina
8c021fd784 Extend blockwise unit tests on files. 2018-06-20 16:57:46 +02:00
Ondrej Kozina
406ec14585 Add unit tests for low level io helpers. 2018-06-20 16:57:40 +02:00
Ondrej Kozina
c27b42e425 Make low level io functions internal library.
it's prerequisite for later unit tests
2018-06-20 16:57:33 +02:00
joerichey@google.com
2d94d7ab0c Fix declaration of logger()
This change makes the declaration of logger() match its definition,
it also avoids the use of the "class" C++ keyword. This is useful for
importing cryptsetup into Bazel/Blaze.
2018-06-19 08:27:46 +02:00
Milan Broz
5fcf430c81 Fix crypto backend for LibreSSL >= 2.7.0.
There are now OpenSSL 1.1.x API functions, no need for compatibility wrapper.

Fixes #393.
2018-06-17 16:45:09 +02:00
Milan Broz
cea4b3e363 Fix #389 Base64 typo. 2018-06-07 08:37:23 +02:00
Milan Broz
e00d8fb544 Add basic tests for new AEAD modes. 2018-05-21 15:52:31 +02:00
Milan Broz
e654fabe04 Add some new AEAD modes and allow SHA1 for integrity check.
NOTE: all this code will be switched to generic checks, this list
is just a temporary hack.
2018-05-21 15:29:49 +02:00
Milan Broz
18592a08be Update readme.md. 2018-05-03 22:45:48 +02:00
Milan Broz
1763260578 Update po files. 2018-05-03 21:30:29 +02:00
Milan Broz
955f10e621 Add 2.0.3 release notes. 2018-05-03 21:29:39 +02:00
Ondrej Kozina
2565fedeb7 Add test for stand-alone --keep-key parameter.
The --keep-key should work when no other parameters are requested.
It was meant to be "apply defaults on original header".
2018-05-03 20:23:41 +02:00
Ondrej Kozina
6b8e553ecc Remove subcondition for reencryption --keep-key parameter.
If removed subcondition was true --keep-key parameter (alone)
would fail the command. But it is valid to request reencryption
of LUKS header and applying defaults to pbkdf parameters.
2018-05-03 20:23:38 +02:00
Ondrej Kozina
14f81cb275 Fix few typos in cryptsetup-reencrypt man page. 2018-05-03 14:41:18 +02:00
Milan Broz
ddb844226d Run PBKDF2 benchmark always.
The PBKDF2 benchmark heavily depends on exported volume key length,
so we either have to remeber benchmarked length or just run test always.

For other KDFs the dependence on generated key length is negligible,
so we can cache benchmark.
2018-05-03 13:01:54 +02:00
Milan Broz
f87ee5112a Fix check for AEAD cipher.
The crypt_get_integrity() can be not yet set, check for key size
explicitly (otherwise we reject composed ciphers in keyslot check too early.)
2018-05-03 13:00:40 +02:00
Milan Broz
2a1a773777 Fixes and workarounds for some Coverity scan reports. 2018-04-30 12:26:12 +02:00
Milan Broz
7fede3ee45 Update po files.
(Version 2.0.3.1 is just resping of translation strings with
trimmed EOL characters.)
2018-04-30 08:03:40 +02:00
Ondrej Kozina
abcd3511bf Fix memory leak in luksKillSlot action. 2018-04-26 16:39:39 +02:00
Milan Broz
a387557970 Introduce crypt_keyslot_get_key_size()
This function allows to get key size even for unboud keyslots.
2018-04-26 14:24:10 +02:00
Milan Broz
daba04d54b Update po files. 2018-04-26 11:50:42 +02:00
Milan Broz
b00a87d8fa Remove trailing EOL for verbose and error messages. 2018-04-26 10:38:17 +02:00
Milan Broz
aee55b0595 Use fixed buffer in log function.
And unify EOL for error and verbose messages.
2018-04-26 10:00:31 +02:00
Milan Broz
e58883c183 Hide return code check fot fallocate (that can silenty fail in this context). 2018-04-26 09:55:31 +02:00
Milan Broz
321e840c1c Fix some signed/unsigned warnings. 2018-04-25 14:59:36 +02:00
Milan Broz
19ac1dd393 Fix Veracrypt PIM iteration calculation for system volumes
According to
https://www.veracrypt.fr/en/Personal%20Iterations%20Multiplier%20%28PIM%29.html

The PBKDF2-SHA512 and PBKDF2-Whirlpool KDF for system volumes uses the same
formula as normal encryption.

Thanks Bernhard Kirchen for original patch.
2018-04-25 14:01:36 +02:00
Ondrej Kozina
13796ee4c7 Add --with-default-luks-format configure time option.
Add option to override default LUKS format version (currently LUKS1).
2018-04-25 12:19:45 +02:00
Milan Broz
10bb78458d Move EOL in tool verbose and error messages to log wrapper. 2018-04-25 10:43:02 +02:00
Milan Broz
6997506bb9 Fix error messages and include benchmark string for translators. 2018-04-25 09:35:11 +02:00
Milan Broz
480c7178a8 Do not use trailing period in options help texts. 2018-04-25 08:41:59 +02:00
Milan Broz
0279d8f466 Update po files. 2018-04-25 08:32:40 +02:00
Milan Broz
1a6183d0c4 Fix non-translated string with default integrity algorithm macro.
Fixes #377.
2018-04-25 08:29:34 +02:00
Milan Broz
487acbb573 Merge branch 'veracrypt-kdf-preference' into 'master'
adjust KDF preference to VeraCrypt order

See merge request cryptsetup/cryptsetup!39
2018-04-24 21:08:28 +00:00
Milan Broz
f97eba6539 Merge branch 'tcryptDump-pim-support' into 'master'
tcryptDump: fix support for --veracrypt-pim

See merge request cryptsetup/cryptsetup!37
2018-04-24 21:02:19 +00:00
Milan Broz
cac84abdd9 Merge branch 'urlencode-veracrypt-docs-link' into 'master'
urlencode brackets in URL to VeraCrypt PIM docs

See merge request cryptsetup/cryptsetup!36
2018-04-24 21:00:10 +00:00
Bernhard Kirchen
ef045f9f65 adjust KDF preference to VeraCrypt order
RIPEMD160 is not even allowed any more as an option when creating an
encrypted file container using VeraCrypt. when encryption the system
partition/drive, it is below SHA256 in the list of options.

the order is like that since VeraCrypt version 1.0f (2014-12-30,
see https://www.veracrypt.fr/en/Release%20Notes.html).
2018-04-24 22:22:55 +02:00
Bernhard Kirchen
6002099288 tcryptDump: fix support for --veracrypt-pim
the user provided PIM value was not forwarded to the respective
implementation dumping the VeraCrypt header information.

extends the tcrypt-compat-test such that tcryptDump is performed
on VeraCrypt containers as well.
2018-04-24 22:20:06 +02:00
Bernhard Kirchen
181f621a90 urlencode brackets in URL to VeraCrypt PIM docs 2018-04-24 21:54:26 +02:00
Milan Broz
5a71c6f2eb Set devel version. 2018-04-24 20:22:00 +02:00
Milan Broz
487965dc8a Fix LUKS convert on trimmed headers in file.
If last write in move area failed, the keyslot is in fact destroyed.

We need to at least ensure that the whole area is there
(so write fails only for hard errors).
2018-04-24 16:36:17 +02:00
Milan Broz
874c573bd4 Do not allow used block size larger than page size.
Some filesystems (NFS) returns bogus blocksize (1MB).
Page-size io should always work and avoids increasing IO beyond aligned LUKS header.
2018-04-24 16:36:11 +02:00
Milan Broz
f63e1cfbfc Rename contains() to json_contains(). 2018-04-24 11:04:53 +02:00
Milan Broz
f049f719f8 Fix keyslot validation. 2018-04-24 10:51:47 +02:00
Milan Broz
30754473fc Add API to get integrity current failure count for dm-integrity. 2018-04-24 08:51:32 +02:00
Ondrej Kozina
7c70e6ce74 Add repair test for keyslot with kdf leftover params. 2018-04-21 20:29:17 +02:00
Ondrej Kozina
a702b7ccc5 Add new validation test for keyslot digest bond 2018-04-21 20:29:12 +02:00
Ondrej Kozina
f6be62ac5f Add repair for known glitches in LUKS2 json. 2018-04-21 20:27:05 +02:00
Ondrej Kozina
dddd30bef8 Add paranoid check for accidental volume key length change. 2018-04-21 20:18:00 +02:00
Ondrej Kozina
a054206d25 Suppress useless slash escaping in json lib 2018-04-21 20:14:28 +02:00
Ondrej Kozina
5b6f06b2ac Hide luks2 specific keyslot allocation from internal api. 2018-04-21 19:43:11 +02:00
Ondrej Kozina
6f83822b6e Validate all keyslot implementations after load and before write. 2018-04-21 19:42:55 +02:00
Ondrej Kozina
9b635a3e90 Cleanup LUKS2 keyslot specific validation.
- do not run general LUKS2 format validation from inside the specific one
- validate luks2 json object only
- temporary move digests count restrictions, going to be fixed in next
  commit
2018-04-21 19:37:05 +02:00
Ondrej Kozina
172af5465d Harden LUKS2 keyslot kdf section validation. 2018-04-21 19:36:31 +02:00
Ondrej Kozina
22f10dd8d2 Remove custom made 'contains' helper from keyslot validation. 2018-04-21 10:57:24 +02:00
Ondrej Kozina
790fdc0aa6 Add crypt_volume_key_get tests for unbound key. 2018-04-21 10:54:12 +02:00
Ondrej Kozina
45356f5e12 Split keyslot update in separate functions.
This patch fixes several problems:

- pbkdf benchmark should be run with keyslot encryption key length
  instead volume key length
- run LUKS2 keyslot validation on final keyslot json object instead
  temporary stub created in keyslot_alloc
- replace whole json kdf object during keyslot update. We left behind
  old parameters from old pbkdf during transition to differnt type
2018-04-21 10:53:54 +02:00
Ondrej Kozina
08ee50403d Move reading keyslot pbkdf params in helper. 2018-04-20 21:08:03 +02:00
Milan Broz
aa1551c6e8 Introduce CRYPT_SLOT_UNBOUND keyslot status for LUKS2.
A keyslot not bound to any segment can store any key for any purpose.

To easily check slot status, new enum value is introduced.
This status is valid only for LUKS2, so the functions are backward compatible
with LUKS1.
2018-04-19 22:28:13 +02:00
Ondrej Kozina
879403a172 Add tests for cryptsetup luksAddKey --unbound. 2018-04-19 18:29:47 +02:00
Milan Broz
6ddf765d8d Remove example covered by cryptsetup already. 2018-04-19 18:29:26 +02:00
Ondrej Kozina
38d83c27b4 Add --unbound keyslot option to cryptsetup.
An unbound keyslot is slot not assigned to a segment;
such a keyslot cannot be used to activate LUKS device, but
can be used for an arbitrary key store.

This patch adds --unboud option for luksAddKey cryptsetup command.
2018-04-19 18:25:35 +02:00
Ondrej Kozina
103fa8fa2c Remove redundant check for key file.
Semantically same check is in tools_get_key routine.
2018-04-19 18:18:56 +02:00
Ondrej Kozina
53dcee6176 Test dump of volume key in a file. 2018-04-19 18:17:45 +02:00
Ondrej Kozina
0c6129c54e Allow volume key store in a file with cryptsetup.
The --dump-master-key together with --master-key-file allows cryptsetup
to store the volume key to a file instead of standard output.
2018-04-19 18:08:37 +02:00
Ondrej Kozina
1f01754ea6 Update FIPS restrictions on crypt_volume_key_get
Allow crypt_volume_key_get for wrapped volume keys.
Allow crypt_volume_key_get for unbound LUKS2 keyslot keys.
2018-04-19 18:01:31 +02:00
Milan Broz
f8a7ab1752 Add crypt_get_pbkdf_default() function to get per-type PBKDF default. 2018-04-16 15:26:43 +02:00
Ondrej Kozina
09842ce46f Update docs for crypt_keyslot_add_by_key. 2018-04-15 15:46:16 +02:00
Ondrej Kozina
0b849985b2 Do not wipe keys for wrapped key enabled ciphers.
We can't wipe (overwrite with random noise) wrapped key in
kernel. Such keys are usually structured and not only random
bytes.

Also it doesn't make sense to wipe these keys. They are supposed
to be protected (encrypted) by keys sealed in hardware.

TODO: tests: 1) with header, 2) without header (dm-crypt only),
      3) arch with working paes cipher (at least).
2018-04-15 15:44:17 +02:00
Ondrej Kozina
34b8a48252 Add stand-alone device suspend. 2018-04-15 15:41:42 +02:00
Ondrej Kozina
6f6e1efbc8 Abort conversion when wrapped key cipher is used. 2018-04-15 15:40:48 +02:00
Milan Broz
9a72ec366d Move generic ciper backend utilities to separate file.
And add wrapped key check.
2018-04-15 15:31:10 +02:00
Ondrej Kozina
d97302f351 Extend suspend tests for missing header case. 2018-04-15 13:12:25 +02:00
Ondrej Kozina
4eb75f3c80 Add debug message for failed external token validation. 2018-04-15 13:10:32 +02:00
Ondrej Kozina
e5f72a0d4f Remove duplicate CRYPT_ANY_TOKEN define. 2018-04-15 13:10:01 +02:00
Ondrej Kozina
b11b11f9b0 Add test for LUKS2 conversion with tokens. 2018-04-15 13:08:57 +02:00
Ondrej Kozina
70077db07d Abort conversion when LUKS2 header contains tokens.
Tokens may contain import 3rd party data. Prompt users
to remove such tokens explicitly.
2018-04-15 13:08:44 +02:00
Ondrej Kozina
eed682c529 Add fixme in luks2->luks1 convert code. 2018-04-15 13:05:22 +02:00
Ondrej Kozina
fbf2d64f34 Allow crypt_volume_key_get for unbound keyslots. 2018-04-15 13:05:08 +02:00
Ondrej Kozina
48bf08922c Make all LUKS2 key size helpers return negative value on error. 2018-04-15 13:03:51 +02:00
Ondrej Kozina
3616ee50c0 Fix off by one bug in LUKS2 keyslot max id allocation.
This is almost impossible to hit bug. The max keyslot id is
checked in higher layer.
2018-04-12 15:50:24 +02:00
Ondrej Kozina
255c8e8ff4 Avoid pbkdf benchmark on LUKS2 header down conversion.
Also clarify use of placeholder keyslots in down conversion.
2018-04-12 15:49:35 +02:00
Ondrej Kozina
0891e84bf8 Add reencrypt tests for --master-key-file option. 2018-04-12 15:45:40 +02:00
Ondrej Kozina
a63db4ab24 Add --master-key-file parameter to cryptsetup-reencrypt. 2018-04-12 15:45:30 +02:00
Ondrej Kozina
169d45fbdb Move reading master key in command line utilities.
Move and rename _read_mk->tools_read_mk in utils_password.c
2018-04-12 15:44:19 +02:00
Ondrej Kozina
965e0237a3 Add basic test for CRYPT_VOLUME_KEY_SET flag.
Also test for bug in keyslot to digest assignment if target
digest id is not 0.
2018-04-12 15:42:32 +02:00
Ondrej Kozina
4caef0dec7 Add new volume key flag to crypt_keyslot_add_by_key.
The new flag may be used to force update device volume key.
2018-04-12 15:35:34 +02:00
Ondrej Kozina
622763b240 Fix memory leak on error path in cryptsetup-reencrypt. 2018-04-11 16:12:15 +02:00
Ondrej Kozina
35d29b22c0 Move CRYPT_ANY_DIGEST definition. 2018-04-11 15:49:29 +02:00
Ondrej Kozina
fee1d659cf Fix wrong digest assignment to new LUKS2 (volume key) keyslot.
All new LUKS2 keyslots added by passphrase or by volume key
were assigned to digest 0 despite the fact segment was assigned
to different digest.
2018-04-11 15:49:15 +02:00
Ondrej Kozina
869767a5cf Move general i/o code to stand-alone utility file.
Get rid of internal library stuff linked to the utilities.
Also rename 'count' param to 'length' clarifying handling
of the parameter internally.
2018-04-11 15:33:43 +02:00
Milan Broz
23b01621ff Print better debug message for open with write mode. 2018-04-10 15:33:30 +02:00
Milan Broz
f21ebaf839 Check LUKS2 conversion for luksmeta header.
We will reject upconversion if there is a luksmeta magic signature.
2018-04-10 14:54:35 +02:00
Milan Broz
f6f00b98a7 Always convert the whole last keyslot (including alignment). 2018-04-10 14:53:33 +02:00
Milan Broz
187170ec51 Check cipher before writing metadata (LUKS2).
Some ciphers and key sizes created on-disk metadata that cannot be used.
Use the same test for length-preserving cipher as LUKS1.

Also check if key for integrity algorithm is not too small.

Fixes #373.
2018-04-06 12:57:58 +02:00
Milan Broz
f7ad64a3d3 Move absolute path helper to m4 macro. 2018-04-04 12:35:08 +02:00
Eli Schwartz
103d75f773 configure.ac: fix bashisms
In commits 9bcc97bc5e and
5536b3a58d new features were
added, which used bash-specific features in a POSIX sh script. This
caused configure to completely fail with syntax errors on systems where
/bin/sh was not symlinked to GNU bash.

`==` is a bash-specific alias for `=` and should never, ever, ever be
used since it offers no additional utility for bash but merely serves
to confuse people writing POSIX.

substring parameter expansion, e.g. `${with_tmpfilesdir:0:1}` is not
POSIX but can be trivially replaced by case wildcards.
2018-04-04 12:13:59 +02:00
Milan Broz
ed2968e3e8 Add paes to ciphers that cannot be used for LUKS2 keyslot encryption.
And use AES-XTS for keyslot in this case.
2018-03-31 17:42:30 +02:00
Milan Broz
fef5121cee veritysetup: add support for --check-at-most-once option.
The kernel 4.17 will include a new dm-verity flag that
instructs kernel to verify data blocks only once.

This patch adds support for it to libcryptsetup and veritysetup.

This flag can be dangerous; if you can control underlying device
(you can change its content after it was verified) it will no longer
prevent reading tampered data and also it does not prevent to silent
data corrruptions that appears after the block was once read.
2018-03-31 11:50:09 +02:00
Milan Broz
c84983f91e Add simple luksConvertKey test. 2018-03-25 15:04:00 +02:00
Milan Broz
86f4f4440a Reformat crypt_resize function. 2018-03-25 14:25:02 +02:00
Milan Broz
af0887fb48 Remove no passphrase error message from library.
And move it to tools.

This will unify LUKS1/2 error messages.
2018-03-25 14:14:37 +02:00
Matthew Garrett
610c7858d6 Add explicit key conversion command
Add support for converting a keyslot from one pbkdf to another without
opening the device.
2018-03-23 09:53:06 +01:00
Milan Broz
8d1fb88a20 Fix return code and retry count for bad passphrase and non-tty input.
It there is an input on stdin (pipe), we cannot retry for password,
a retry applies only for the real terminal.

Also the retry lost EPERM (wrong passphrase) return code in this case,
replacing it with tty read error.

Fixes #321.
2018-03-23 08:13:43 +01:00
Ondrej Kozina
1e2ad19d68 Validate LUKS2 keyslot json before opening it. 2018-03-22 14:06:31 +01:00
Ondrej Kozina
7bee66fe36 Add new luks2 keyslot validation condition. 2018-03-22 14:05:19 +01:00
Ondrej Kozina
303fe886b7 Fix misleading param name in prototype. 2018-03-22 14:05:08 +01:00
Ondrej Kozina
761a472b45 Remove missing digest condition from LUKS2 digest verification. 2018-03-22 14:04:56 +01:00
Ondrej Kozina
3cf2da877f Refactor crypt_activate_by_keyfile_device_offset.
It's activation by passphrase after all.
2018-03-22 14:03:48 +01:00
Michal Virgovič
5b7b1596a2 Add tests for veritysetup FEC userspace decoding. 2018-03-22 12:44:14 +01:00
Michal Virgovič
dc58985ac6 Enable userspace FEC decoding in veritysetup. 2018-03-22 12:43:49 +01:00
Michal Virgovič
5e0db46f17 Add Reed-Solomon user-space decoding lib. 2018-03-22 12:41:57 +01:00
Milan Broz
4e19bc01d5 Fix test vectors test link. 2018-03-19 19:21:35 +01:00
Milan Broz
2d2acda404 Add crypto backend vectors test.
Still need to add
 - hash, HMAC,
 - symmetric ciphers,
 - storage encryption wrapper.
2018-03-19 13:02:12 +01:00
Milan Broz
fa8d5d1769 Remove losetup handling from reencrypt2 test. 2018-03-13 15:20:07 +01:00
Milan Broz
fe058e2c27 Update reencrypt test to use option --type only when really needed. 2018-03-13 14:14:44 +01:00
Milan Broz
a22a24bc98 Support detached header for cryptsetup-reencrypt.
This patch allows encryption/decryption of the whole device,
IOW add encryption later with detached header.

This operation can be dangerous, there is no fixed bindings between
the specific LUKS header and data device (encrypted data device
contains no magic signatures).
2018-03-08 10:15:56 +01:00
Milan Broz
b7c2465887 Add link to ABI tracker. 2018-03-07 13:47:00 +01:00
Milan Broz
f34158250a Update Readme.md. 2018-03-07 13:33:22 +01:00
175 changed files with 25372 additions and 14101 deletions

9
.gitignore vendored
View File

@@ -6,10 +6,12 @@ Makefile.in.in
*.lo
*.la
*.o
**/*.dirstamp
.deps/
.libs/
src/cryptsetup
src/veritysetup
ABOUT-NLS
aclocal.m4
autom4te.cache/
compile
@@ -21,8 +23,11 @@ config.rpath
config.status
config.sub
configure
cryptsetup
cryptsetup-reencrypt
depcomp
install-sh
integritysetup
lib/libcryptsetup.pc
libtool
ltmain.sh
@@ -36,5 +41,7 @@ po/*.header
po/*.sed
po/*.sin
po/stamp-po
scripts/cryptsetup.conf
stamp-h1
veritysetup
tests/valglog.*

View File

@@ -38,18 +38,12 @@ function check_nonroot
configure_travis \
--enable-python \
--enable-cryptsetup-reencrypt \
--enable-internal-sse-argon2 \
"$cfg_opts" \
|| return
$MAKE || return
sudo modprobe dm-crypt
sudo modprobe dm-verity
sudo modprobe dm-integrity
uname -a
sudo dmsetup version
sudo dmsetup targets
make check
}
@@ -62,18 +56,12 @@ function check_root
configure_travis \
--enable-python \
--enable-cryptsetup-reencrypt \
--enable-internal-sse-argon2 \
"$cfg_opts" \
|| return
$MAKE || return
sudo modprobe dm-crypt
sudo modprobe dm-verity
sudo modprobe dm-integrity
uname -a
sudo dmsetup version
sudo dmsetup targets
# FIXME: we should use -E option here
sudo make check
}
@@ -87,6 +75,7 @@ function check_nonroot_compile_only
configure_travis \
--enable-python \
--enable-cryptsetup-reencrypt \
--enable-internal-sse-argon2 \
"$cfg_opts" \
|| return
@@ -116,6 +105,7 @@ function travis_install_script
expect \
keyutils \
libjson-c-dev \
libblkid-dev \
|| return
}

2
FAQ
View File

@@ -128,7 +128,7 @@ A. Contributors
recommended to not install Ubuntu on a system with existing LUKS
containers without complete backups.
Update 11/2014: There seem to be other problems withe existing LUKS
Update 11/2014: There seem to be other problems with existing LUKS
containers and Ubuntu as well, be extra careful when using LUKS
on Ubuntu in any way, but exactly as the Ubuntu installer does.

View File

@@ -42,7 +42,7 @@ ACLOCAL_AMFLAGS = -I m4
DISTCHECK_CONFIGURE_FLAGS = \
--enable-python \
--with-tmpfilesdir=$$dc_install_base/usr/lib/tmpfiles.d \
--enable-internal-argon2
--enable-internal-argon2 --enable-internal-sse-argon2
distclean-local:
-find . -name \*~ -o -name \*.orig -o -name \*.rej | xargs rm -f

View File

@@ -18,8 +18,7 @@ LUKS Design
-----------
**LUKS** is the standard for Linux hard disk encryption. By providing a standard on-disk-format, it does not
only facilitate compatibility among distributions, but also provides secure management of multiple user passwords.
In contrast to existing solution, LUKS stores all setup necessary setup information in the partition header,
enabling the user to transport or migrate his data seamlessly.
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
[available here](https://www.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf).
@@ -42,13 +41,25 @@ 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.1**
* [cryptsetup-2.0.1.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.1.tar.xz)
* Signature [cryptsetup-2.0.1.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.1.tar.sign)
**The latest cryptsetup version is 2.0.5**
* [cryptsetup-2.0.5.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.5.tar.xz)
* Signature [cryptsetup-2.0.5.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.5.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.0.1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.1-ReleaseNotes).
* [Cryptsetup 2.0.5 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.5-ReleaseNotes).
Previous versions
* [Version 2.0.4](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.4.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.4.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.4-ReleaseNotes).
* [Version 2.0.3](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.3.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.3.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.3-ReleaseNotes).
* [Version 2.0.2](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.2.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.2.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.2-ReleaseNotes).
* [Version 2.0.1](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.1.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.1.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.1-ReleaseNotes).
* [Version 2.0.0](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.0-ReleaseNotes).
@@ -78,7 +89,7 @@ mirror on [kernel.org](https://git.kernel.org/cgit/utils/cryptsetup/cryptsetup.g
For libcryptsetup documentation see [libcryptsetup API](https://gitlab.com/cryptsetup/cryptsetup/wikis/API/index.html) page.
The libcryptsetup API/ABI changes are tracked in [compatibility report](https://gitlab.com/cryptsetup/cryptsetup/wikis/ABI-tracker/timeline/libcryptsetup/index.html).
The libcryptsetup API/ABI changes are tracked in [compatibility report](https://abi-laboratory.pro/tracker/timeline/cryptsetup/).
NLS PO files are maintained by [TranslationProject](http://translationproject.org/domain/cryptsetup.html).

View File

@@ -1,9 +1,9 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[2.0.2])
AC_INIT([cryptsetup],[2.0.5])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
LIBCRYPTSETUP_VERSION_INFO=14:0:2
LIBCRYPTSETUP_VERSION_INFO=15:0:3
AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR(src/cryptsetup.c)
@@ -63,7 +63,9 @@ AC_CHECK_HEADERS(fcntl.h malloc.h inttypes.h sys/ioctl.h sys/mman.h \
AC_CHECK_HEADERS(uuid/uuid.h,,[AC_MSG_ERROR([You need the uuid library.])])
AC_CHECK_HEADER(libdevmapper.h,,[AC_MSG_ERROR([You need the device-mapper library.])])
AC_ARG_ENABLE(keyring, AS_HELP_STRING([--disable-keyring],[disable kernel keyring support and builtin kernel keyring token]),[], [enable_keyring=yes])
AC_ARG_ENABLE([keyring],
AS_HELP_STRING([--disable-keyring], [disable kernel keyring support and builtin kernel keyring token]),
[], [enable_keyring=yes])
if test "x$enable_keyring" = "xyes"; then
AC_CHECK_HEADERS(linux/keyctl.h,,[AC_MSG_ERROR([You need Linux kernel headers with kernel keyring service compiled.])])
@@ -84,7 +86,7 @@ if test "x$enable_keyring" = "xyes"; then
AC_DEFINE(KERNEL_KEYRING, 1, [Enable kernel keyring service support])
fi
AM_CONDITIONAL(KERNEL_KEYRING, test x$enable_keyring = xyes)
AM_CONDITIONAL(KERNEL_KEYRING, test "x$enable_keyring" = "xyes")
saved_LIBS=$LIBS
AC_CHECK_LIB(uuid, uuid_clear, ,[AC_MSG_ERROR([You need the uuid library.])])
@@ -92,9 +94,9 @@ AC_SUBST(UUID_LIBS, $LIBS)
LIBS=$saved_LIBS
AC_SEARCH_LIBS([clock_gettime],[rt posix4])
AC_CHECK_FUNCS([posix_memalign clock_gettime posix_fallocate])
AC_CHECK_FUNCS([posix_memalign clock_gettime posix_fallocate explicit_bzero])
if test "x$enable_largefile" = "xno" ; then
if test "x$enable_largefile" = "xno"; then
AC_MSG_ERROR([Building with --disable-largefile is not supported, it can cause data corruption.])
fi
@@ -120,12 +122,10 @@ AC_SUBST(POPT_LIBS, $LIBS)
LIBS=$saved_LIBS
dnl ==========================================================================
dnl FIPS extensions (only for RHEL)
AC_ARG_ENABLE([fips], AS_HELP_STRING([--enable-fips],[enable FIPS mode restrictions]),
[with_fips=$enableval],
[with_fips=no])
if test "x$with_fips" = "xyes"; then
dnl FIPS extensions
AC_ARG_ENABLE([fips],
AS_HELP_STRING([--enable-fips], [enable FIPS mode restrictions]))
if test "x$enable_fips" = "xyes"; then
AC_DEFINE(ENABLE_FIPS, 1, [Enable FIPS mode restrictions])
if test "x$enable_static" = "xyes" -o "x$enable_static_cryptsetup" = "xyes" ; then
@@ -134,7 +134,7 @@ if test "x$with_fips" = "xyes"; then
fi
AC_DEFUN([NO_FIPS], [
if test "x$with_fips" = "xyes"; then
if test "x$enable_fips" = "xyes"; then
AC_MSG_ERROR([This option is not compatible with FIPS.])
fi
])
@@ -142,12 +142,9 @@ AC_DEFUN([NO_FIPS], [
dnl ==========================================================================
dnl pwquality library (cryptsetup CLI only)
AC_ARG_ENABLE([pwquality],
AS_HELP_STRING([--enable-pwquality],
[enable password quality checking using pwquality library]),
[with_pwquality=$enableval],
[with_pwquality=no])
AS_HELP_STRING([--enable-pwquality], [enable password quality checking using pwquality library]))
if test "x$with_pwquality" = "xyes"; then
if test "x$enable_pwquality" = "xyes"; then
AC_DEFINE(ENABLE_PWQUALITY, 1, [Enable password quality checking using pwquality library])
PKG_CHECK_MODULES([PWQUALITY], [pwquality >= 1.0.0],,
AC_MSG_ERROR([You need pwquality library.]))
@@ -159,13 +156,11 @@ fi
dnl ==========================================================================
dnl passwdqc library (cryptsetup CLI only)
AC_ARG_ENABLE([passwdqc],
AS_HELP_STRING([--enable-passwdqc@<:@=CONFIG_PATH@:>@],
[enable password quality checking using passwdqc library (optionally with CONFIG_PATH)]),
[enable_passwdqc=$enableval],
[enable_passwdqc=no])
AS_HELP_STRING([--enable-passwdqc@<:@=CONFIG_PATH@:>@],
[enable password quality checking using passwdqc library (optionally with CONFIG_PATH)]))
case "$enable_passwdqc" in
yes|no) use_passwdqc_config="" ;;
""|yes|no) use_passwdqc_config="" ;;
/*) use_passwdqc_config="$enable_passwdqc"; enable_passwdqc=yes ;;
*) AC_MSG_ERROR([Unrecognized --enable-passwdqc parameter.]) ;;
esac
@@ -177,7 +172,7 @@ if test "x$enable_passwdqc" = "xyes"; then
PASSWDQC_LIBS="-lpasswdqc"
fi
if test "x$with_pwquality$enable_passwdqc" = "xyesyes"; then
if test "x$enable_pwquality$enable_passwdqc" = "xyesyes"; then
AC_MSG_ERROR([--enable-pwquality and --enable-passwdqc are mutually incompatible.])
fi
@@ -185,13 +180,14 @@ dnl ==========================================================================
dnl Crypto backend functions
AC_DEFUN([CONFIGURE_GCRYPT], [
if test "x$with_fips" = "xyes"; then
if test "x$enable_fips" = "xyes"; then
GCRYPT_REQ_VERSION=1.4.5
else
GCRYPT_REQ_VERSION=1.1.42
fi
dnl Check if we can use gcrypt PBKDF2 (1.6.0 supports empty password)
AC_ARG_ENABLE([gcrypt-pbkdf2], AS_HELP_STRING([--enable-gcrypt-pbkdf2],[force enable internal gcrypt PBKDF2]),
AC_ARG_ENABLE([gcrypt-pbkdf2],
AS_HELP_STRING([--enable-gcrypt-pbkdf2], [force enable internal gcrypt PBKDF2]),
if test "x$enableval" = "xyes"; then
[use_internal_pbkdf2=0]
else
@@ -208,7 +204,7 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
NO_FIPS([])
fi
if test x$enable_static_cryptsetup = xyes; then
if test "x$enable_static_cryptsetup" = "xyes"; then
saved_LIBS=$LIBS
LIBS="$saved_LIBS $LIBGCRYPT_LIBS -static"
AC_CHECK_LIB(gcrypt, gcry_check_version,,
@@ -232,7 +228,7 @@ AC_DEFUN([CONFIGURE_OPENSSL], [
CRYPTO_LIBS=$OPENSSL_LIBS
use_internal_pbkdf2=0
if test x$enable_static_cryptsetup = xyes; then
if test "x$enable_static_cryptsetup" = "xyes"; then
saved_PKG_CONFIG=$PKG_CONFIG
PKG_CONFIG="$PKG_CONFIG --static"
PKG_CHECK_MODULES([OPENSSL_STATIC], [openssl])
@@ -242,7 +238,7 @@ AC_DEFUN([CONFIGURE_OPENSSL], [
])
AC_DEFUN([CONFIGURE_NSS], [
if test x$enable_static_cryptsetup = xyes; then
if test "x$enable_static_cryptsetup" = "xyes"; then
AC_MSG_ERROR([Static build of cryptsetup is not supported with NSS.])
fi
@@ -291,43 +287,42 @@ dnl ==========================================================================
saved_LIBS=$LIBS
AC_ARG_ENABLE([static-cryptsetup],
AS_HELP_STRING([--enable-static-cryptsetup],
[enable build of static version of tools]))
if test x$enable_static_cryptsetup = xyes; then
if test x$enable_static = xno; then
AS_HELP_STRING([--enable-static-cryptsetup], [enable build of static version of tools]))
if test "x$enable_static_cryptsetup" = "xyes"; then
if test "x$enable_static" = "xno"; then
AC_MSG_WARN([Requested static cryptsetup build, enabling static library.])
enable_static=yes
fi
fi
AM_CONDITIONAL(STATIC_TOOLS, test x$enable_static_cryptsetup = xyes)
AM_CONDITIONAL(STATIC_TOOLS, test "x$enable_static_cryptsetup" = "xyes")
AC_ARG_ENABLE(cryptsetup,
AS_HELP_STRING([--disable-cryptsetup],
[disable cryptsetup support]),[], [enable_cryptsetup=yes])
AM_CONDITIONAL(CRYPTSETUP, test x$enable_cryptsetup = xyes)
AC_ARG_ENABLE([cryptsetup],
AS_HELP_STRING([--disable-cryptsetup], [disable cryptsetup support]),
[], [enable_cryptsetup=yes])
AM_CONDITIONAL(CRYPTSETUP, test "x$enable_cryptsetup" = "xyes")
AC_ARG_ENABLE(veritysetup,
AS_HELP_STRING([--disable-veritysetup],
[disable veritysetup support]),[], [enable_veritysetup=yes])
AM_CONDITIONAL(VERITYSETUP, test x$enable_veritysetup = xyes)
AC_ARG_ENABLE([veritysetup],
AS_HELP_STRING([--disable-veritysetup], [disable veritysetup support]),
[], [enable_veritysetup=yes])
AM_CONDITIONAL(VERITYSETUP, test "x$enable_veritysetup" = "xyes")
AC_ARG_ENABLE([cryptsetup-reencrypt],
AS_HELP_STRING([--disable-cryptsetup-reencrypt],
[disable cryptsetup-reencrypt tool]),[], [enable_cryptsetup_reencrypt=yes])
AM_CONDITIONAL(REENCRYPT, test x$enable_cryptsetup_reencrypt = xyes)
AS_HELP_STRING([--disable-cryptsetup-reencrypt], [disable cryptsetup-reencrypt tool]),
[], [enable_cryptsetup_reencrypt=yes])
AM_CONDITIONAL(REENCRYPT, test "x$enable_cryptsetup_reencrypt" = "xyes")
AC_ARG_ENABLE(integritysetup,
AS_HELP_STRING([--disable-integritysetup],
[disable integritysetup support]),[], [enable_integritysetup=yes])
AM_CONDITIONAL(INTEGRITYSETUP, test x$enable_integritysetup = xyes)
AC_ARG_ENABLE([integritysetup],
AS_HELP_STRING([--disable-integritysetup], [disable integritysetup support]),
[], [enable_integritysetup=yes])
AM_CONDITIONAL(INTEGRITYSETUP, test "x$enable_integritysetup" = "xyes")
AC_ARG_ENABLE(selinux,
AS_HELP_STRING([--disable-selinux],
[disable selinux support [default=auto]]),[], [])
AC_ARG_ENABLE([selinux],
AS_HELP_STRING([--disable-selinux], [disable selinux support [default=auto]]),
[], [enable_selinux=yes])
AC_ARG_ENABLE([udev],
AS_HELP_STRING([--disable-udev],
[disable udev support]),[], enable_udev=yes)
AS_HELP_STRING([--disable-udev], [disable udev support]),
[], [enable_udev=yes])
dnl Try to use pkg-config for devmapper, but fallback to old detection
PKG_CHECK_MODULES([DEVMAPPER], [devmapper >= 1.02.03],, [
@@ -361,16 +356,14 @@ PKG_CHECK_MODULES([JSON_C], [json-c])
dnl Crypto backend configuration.
AC_ARG_WITH([crypto_backend],
AS_HELP_STRING([--with-crypto_backend=BACKEND], [crypto backend (gcrypt/openssl/nss/kernel/nettle) [gcrypt]]),
[], with_crypto_backend=gcrypt
)
[], [with_crypto_backend=gcrypt])
dnl Kernel crypto API backend needed for benchmark and tcrypt
AC_ARG_ENABLE([kernel_crypto], AS_HELP_STRING([--disable-kernel_crypto],
[disable kernel userspace crypto (no benchmark and tcrypt)]),
[with_kernel_crypto=$enableval],
[with_kernel_crypto=yes])
AC_ARG_ENABLE([kernel_crypto],
AS_HELP_STRING([--disable-kernel_crypto], [disable kernel userspace crypto (no benchmark and tcrypt)]),
[], [enable_kernel_crypto=yes])
if test "x$with_kernel_crypto" = "xyes"; then
if test "x$enable_kernel_crypto" = "xyes"; then
AC_CHECK_HEADERS(linux/if_alg.h,,
[AC_MSG_ERROR([You need Linux kernel headers with userspace crypto interface. (Or use --disable-kernel_crypto.)])])
AC_DEFINE(ENABLE_AF_ALG, 1, [Enable using of kernel userspace crypto])
@@ -384,23 +377,24 @@ case $with_crypto_backend in
nettle) CONFIGURE_NETTLE([]) ;;
*) AC_MSG_ERROR([Unknown crypto backend.]) ;;
esac
AM_CONDITIONAL(CRYPTO_BACKEND_GCRYPT, test $with_crypto_backend = gcrypt)
AM_CONDITIONAL(CRYPTO_BACKEND_OPENSSL, test $with_crypto_backend = openssl)
AM_CONDITIONAL(CRYPTO_BACKEND_NSS, test $with_crypto_backend = nss)
AM_CONDITIONAL(CRYPTO_BACKEND_KERNEL, test $with_crypto_backend = kernel)
AM_CONDITIONAL(CRYPTO_BACKEND_NETTLE, test $with_crypto_backend = nettle)
AM_CONDITIONAL(CRYPTO_BACKEND_GCRYPT, test "$with_crypto_backend" = "gcrypt")
AM_CONDITIONAL(CRYPTO_BACKEND_OPENSSL, test "$with_crypto_backend" = "openssl")
AM_CONDITIONAL(CRYPTO_BACKEND_NSS, test "$with_crypto_backend" = "nss")
AM_CONDITIONAL(CRYPTO_BACKEND_KERNEL, test "$with_crypto_backend" = "kernel")
AM_CONDITIONAL(CRYPTO_BACKEND_NETTLE, test "$with_crypto_backend" = "nettle")
AM_CONDITIONAL(CRYPTO_INTERNAL_PBKDF2, test $use_internal_pbkdf2 = 1)
AC_DEFINE_UNQUOTED(USE_INTERNAL_PBKDF2, [$use_internal_pbkdf2], [Use internal PBKDF2])
dnl Argon2 implementation
AC_ARG_ENABLE(internal-argon2, AS_HELP_STRING([--disable-internal-argon2],
[disable internal implementation of Argon2 PBKDF]),[], [enable_internal_argon2=yes])
AC_ARG_ENABLE([internal-argon2],
AS_HELP_STRING([--disable-internal-argon2], [disable internal implementation of Argon2 PBKDF]),
[], [enable_internal_argon2=yes])
AC_ARG_ENABLE([libargon2], AS_HELP_STRING([--enable-libargon2],
[enable external libargon2 (PHC) library (disables internal bundled version) ]),[], [enable_libargon2=no])
AC_ARG_ENABLE([libargon2],
AS_HELP_STRING([--enable-libargon2], [enable external libargon2 (PHC) library (disables internal bundled version)]))
if test x$enable_libargon2 = xyes ; then
if test "x$enable_libargon2" = "xyes" ; then
AC_CHECK_HEADERS(argon2.h,,
[AC_MSG_ERROR([You need libargon2 development library installed.])])
AC_CHECK_DECL(Argon2_id,,[AC_MSG_ERROR([You need more recent Argon2 library with support for Argon2id.])], [#include <argon2.h>])
@@ -408,15 +402,63 @@ if test x$enable_libargon2 = xyes ; then
enable_internal_argon2=no
else
AC_MSG_WARN([Argon2 bundled (slow) reference implementation will be used, please consider to use system library with --enable-libargon2.])
AC_ARG_ENABLE([internal-sse-argon2],
AS_HELP_STRING([--enable-internal-sse-argon2], [enable internal SSE implementation of Argon2 PBKDF]))
if test "x$enable_internal_sse_argon2" = "xyes"; then
AC_MSG_CHECKING(if Argon2 SSE optimization can be used)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <emmintrin.h>
__m128i testfunc(__m128i *a, __m128i *b) {
return _mm_xor_si128(_mm_loadu_si128(a), _mm_loadu_si128(b));
}
]])],,[enable_internal_sse_argon2=no])
AC_MSG_RESULT($enable_internal_sse_argon2)
fi
fi
if test x$enable_internal_argon2 = xyes ; then
if test "x$enable_internal_argon2" = "xyes"; then
AC_DEFINE(USE_INTERNAL_ARGON2, 1, [Use internal Argon2])
fi
AM_CONDITIONAL(CRYPTO_INTERNAL_ARGON2, test x$enable_internal_argon2 = xyes)
AM_CONDITIONAL(CRYPTO_INTERNAL_ARGON2, test "x$enable_internal_argon2" = "xyes")
AM_CONDITIONAL(CRYPTO_INTERNAL_SSE_ARGON2, test "x$enable_internal_sse_argon2" = "xyes")
dnl Link with blkid to check for other device types
AC_ARG_ENABLE([blkid],
AS_HELP_STRING([--disable-blkid], [disable use of blkid for device signature detection and wiping]),
[], [enable_blkid=yes])
if test "x$enable_blkid" = "xyes"; then
PKG_CHECK_MODULES([BLKID], [blkid],[AC_DEFINE([HAVE_BLKID], 1, [Define to 1 to use blkid for detection of disk signatures.])],[LIBBLKID_LIBS="-lblkid"])
AC_CHECK_HEADERS(blkid/blkid.h,,[AC_MSG_ERROR([You need blkid development library installed.])])
AC_CHECK_DECL([blkid_do_wipe],
[ AC_DEFINE([HAVE_BLKID_WIPE], 1, [Define to 1 to use blkid_do_wipe.])
enable_blkid_wipe=yes
],,
[#include <blkid/blkid.h>])
AC_CHECK_DECL([blkid_probe_step_back],
[ AC_DEFINE([HAVE_BLKID_STEP_BACK], 1, [Define to 1 to use blkid_probe_step_back.])
enable_blkid_step_back=yes
],,
[#include <blkid/blkid.h>])
AC_CHECK_DECLS([ blkid_reset_probe,
blkid_probe_set_device,
blkid_probe_filter_superblocks_type,
blkid_do_safeprobe,
blkid_do_probe,
blkid_probe_lookup_value
],,
[AC_MSG_ERROR([Can not compile with blkid support, disable it by --disable-blkid.])],
[#include <blkid/blkid.h>])
fi
AM_CONDITIONAL(HAVE_BLKID, test "x$enable_blkid" = "xyes")
AM_CONDITIONAL(HAVE_BLKID_WIPE, test "x$enable_blkid_wipe" = "xyes")
AM_CONDITIONAL(HAVE_BLKID_STEP_BACK, test "x$enable_blkid_step_back" = "xyes")
dnl Magic for cryptsetup.static build.
if test x$enable_static_cryptsetup = xyes; then
if test "x$enable_static_cryptsetup" = "xyes"; then
saved_PKG_CONFIG=$PKG_CONFIG
PKG_CONFIG="$PKG_CONFIG --static"
@@ -428,7 +470,7 @@ if test x$enable_static_cryptsetup = xyes; then
LIBS="$saved_LIBS -static"
PKG_CHECK_MODULES([DEVMAPPER_STATIC], [devmapper >= 1.02.27],,[
DEVMAPPER_STATIC_LIBS=$DEVMAPPER_LIBS
if test "x$enable_selinux" != xno; then
if test "x$enable_selinux" = "xyes"; then
AC_CHECK_LIB(sepol, sepol_bool_set)
AC_CHECK_LIB(selinux, is_selinux_enabled)
DEVMAPPER_STATIC_LIBS="$DEVMAPPER_STATIC_LIBS $LIBS"
@@ -465,14 +507,19 @@ AC_SUBST([CRYPTO_STATIC_LIBS])
AC_SUBST([JSON_C_LIBS])
AC_SUBST([LIBARGON2_LIBS])
AC_SUBST([BLKID_LIBS])
AC_SUBST([LIBCRYPTSETUP_VERSION])
AC_SUBST([LIBCRYPTSETUP_VERSION_INFO])
dnl ==========================================================================
AC_ARG_ENABLE([dev-random], AS_HELP_STRING([--enable-dev-random],
[use blocking /dev/random by default for key generator (otherwise use /dev/urandom)]),
[default_rng=/dev/random], [default_rng=/dev/urandom])
AC_ARG_ENABLE([dev-random],
AS_HELP_STRING([--enable-dev-random], [use /dev/random by default for key generation (otherwise use /dev/urandom)]))
if test "x$enable_dev_random" = "xyes"; then
default_rng=/dev/random
else
default_rng=/dev/urandom
fi
AC_DEFINE_UNQUOTED(DEFAULT_RNG, ["$default_rng"], [default RNG type for key generator])
dnl ==========================================================================
@@ -492,17 +539,23 @@ AC_DEFUN([CS_NUM_WITH], [AC_ARG_WITH([$1],
[CS_DEFINE([$1], [$3], [$2])]
)])
AC_DEFUN([CS_ABSPATH], [
case "$1" in
/*) ;;
*) AC_MSG_ERROR([$2 argument must be an absolute path.]);;
esac
])
dnl ==========================================================================
dnl Python bindings
AC_ARG_ENABLE([python], AS_HELP_STRING([--enable-python],[enable Python bindings]),
[with_python=$enableval],
[with_python=no])
AC_ARG_ENABLE([python],
AS_HELP_STRING([--enable-python], [enable Python bindings]))
AC_ARG_WITH([python_version],
AS_HELP_STRING([--with-python_version=VERSION], [required Python version [2.6]]),
[PYTHON_VERSION=$withval], [PYTHON_VERSION=2.6])
if test "x$with_python" = "xyes"; then
if test "x$enable_python" = "xyes"; then
AM_PATH_PYTHON([$PYTHON_VERSION])
AC_PATH_PROGS([PYTHON_CONFIG], [python${PYTHON_VERSION}-config python-config], [no])
@@ -520,7 +573,7 @@ if test "x$with_python" = "xyes"; then
AC_MSG_RESULT($PYTHON_LIBS)
AC_SUBST(PYTHON_LIBS)
fi
AM_CONDITIONAL([PYTHON_CRYPTSETUP], [test "x$with_python" = "xyes"])
AM_CONDITIONAL([PYTHON_CRYPTSETUP], [test "x$enable_python" = "xyes"])
dnl ==========================================================================
CS_STR_WITH([plain-hash], [password hashing function for plain mode], [ripemd160])
@@ -553,17 +606,16 @@ CS_NUM_WITH([verity-fec-roots], [parity bytes for verity FEC], [2])
CS_STR_WITH([tmpfilesdir], [override default path to directory with systemd temporary files], [])
test -z "$with_tmpfilesdir" && with_tmpfilesdir=$systemd_tmpfilesdir
test "x$with_tmpfilesdir" == "xno" || {
test "${with_tmpfilesdir:0:1}" = "/" || AC_MSG_ERROR([--with-tmpfilesdir argument must be an absolute path.])
test "x$with_tmpfilesdir" = "xno" || {
CS_ABSPATH([${with_tmpfilesdir}],[with-tmpfilesdir])
DEFAULT_TMPFILESDIR=$with_tmpfilesdir
AC_SUBST(DEFAULT_TMPFILESDIR)
}
AM_CONDITIONAL(CRYPTSETUP_TMPFILE, test -n "$DEFAULT_TMPFILESDIR")
CS_STR_WITH([luks2-lock-path], [path to directory for LUKSv2 locks], [/run/cryptsetup])
test -z "$with_luks2_lock_path" && with_luks2_lock_path=/run/cryptsetup
test "${with_luks2_lock_path:0:1}" = "/" || AC_MSG_ERROR([--with-luks2-lock-path argument must be an absolute path.])
CS_ABSPATH([${with_luks2_lock_path}],[with-luks2-lock-path])
DEFAULT_LUKS2_LOCK_PATH=$with_luks2_lock_path
AC_SUBST(DEFAULT_LUKS2_LOCK_PATH)
@@ -572,6 +624,18 @@ test -z "$with_luks2_lock_dir_perms" && with_luks2_lock_dir_perms=0700
DEFAULT_LUKS2_LOCK_DIR_PERMS=$with_luks2_lock_dir_perms
AC_SUBST(DEFAULT_LUKS2_LOCK_DIR_PERMS)
dnl Override default LUKS format version (for cryptsetup or cryptsetup-reencrypt format actions only).
AC_ARG_WITH([default_luks_format],
AS_HELP_STRING([--with-default-luks-format=FORMAT], [default LUKS format version (LUKS1/LUKS2) [LUKS1]]),
[], [with_default_luks_format=LUKS1])
case $with_default_luks_format in
LUKS1) default_luks=CRYPT_LUKS1 ;;
LUKS2) default_luks=CRYPT_LUKS2 ;;
*) AC_MSG_ERROR([Unknown default LUKS format. Use LUKS1 or LUKS2 only.]) ;;
esac
AC_DEFINE_UNQUOTED([DEFAULT_LUKS_FORMAT], [$default_luks], [default LUKS format version])
dnl ==========================================================================
AC_CONFIG_FILES([ Makefile

View File

@@ -1,279 +0,0 @@
LUKS2 on-disk format
====================
Note: these are temporary documentation notes only.
The more formal definition will be published later.
Design goals
~~~~~~~~~~~~
The LUKS2 is an on-disk storage format designed to
provide simple key management, primarily intended for Full Disk
Encryption based on dm-crypt.
The LUKS2 is highly inspired by LUKS1 format and in some
specific situations (most of the default installations) can be converted
in-place (in both ways - to and from LUKS1).
The LUKS2 format is designed to allow future updates of various
parts without the need to modify binary structures.
On-disk format provides redundancy of metadata, detection
of metadata corruption and automatic repair from metadata copy.
NOTE: For security reasons, there is no redundancy in keyslots
binary data (encrypted keys) but format allows updating to redundant
keyslot encryption in future (add forward error correction codes
is one possibility).
On-disk structure
~~~~~~~~~~~~~~~~~
The LUKS2 header contains three parts:
- binary header (one 4096 bytes sector)
- area for metadata stored in JSON format
- keyslot area (per-context binary data).
The binary header and JSON area are stored twice to increase
redundancy. Keyslot area is allocated per-demand, and it is stored only once.
The basic on-disk structure is then
0 4096
| bin hdr1 | JSON ... | bin hdr2 | JSON ... | Keyslot data | <padding> | (data payload)
Binary header
~~~~~~~~~~~~~
The binary header is intended for quick scanning (by blkid and udev) and contains
magic string to detect the device, basic information (labels), header size information
and metadata checksum.
Checksum covers both binary data and following JSON area and is calculated
with checksum fields zeroed. By default plain SHA256 checksum is used.
The primary binary header is always stored in sector 0 of the device.
The C structure of binary header (see luks2.h) is
#define LUKS2_MAGIC_1ST "LUKS\xba\xbe"
#define LUKS2_MAGIC_2ND "SKUL\xba\xbe"
#define LUKS2_MAGIC_L 6
#define LUKS2_UUID_L 40
#define LUKS2_LABEL_L 48
#define LUKS2_SALT_L 64
#define LUKS2_CHECKSUM_ALG_L 32
#define LUKS2_CHECKSUM_L 64
struct luks2_hdr_disk {
char magic[LUKS2_MAGIC_L]; /* "LUKS\xba\xbe" (1st) or "SKUL\xba\be" (2nd) */
uint16_t version; /* Version 2 */
uint64_t hdr_size; /* in bytes, including JSON area */
uint64_t seqid; /* sequence ID, increased on every update */
char label[LUKS2_LABEL_L]; /* ASCII label or empty */
char checksum_alg[LUKS2_CHECKSUM_ALG_L]; /* checksum algorithm, "sha256" */
uint8_t salt[LUKS2_SALT_L]; /* random salt, unique for every header */
char uuid[LUKS2_UUID_L]; /* UUID of device */
char subsystem[LUKS2_LABEL_L]; /* owner subsystem label or empty */
uint64_t hdr_offset; /* header offset from device start in bytes */
char _padding[184]; /* must be zeroed */
uint8_t csum[LUKS2_CHECKSUM_L]; /* header checksum */
char _padding4096[7*512]; /* must be zeroed */
} __attribute__ ((packed));
The LUKS1 compatible field (magic, UUID) are placed intentionally on the same offsets.
The header version must be set to 2.
The UUID is the same format as in LUKS1.
Magic string differs between the first and second header.
The hdr_offset must match physical header offset on the device.
If hdr_offset does not match, the header is misplaced and must not be used.
(It is a prevention to partition resize or manipulation with device start offset.)
The hdr_size contains the size of the binary header and JSON data area.
The offset and size of the second (backup) header must match to these data.
(Prevention to rewrite of a header with different JSON area size.)
There are two labels - label and subsystem. Content of these fields will be visible
in UDEV/blkid scan and can be used for similar purposes as a filesystem label.
These fields are by default empty.
The salt field in binary header is generated by an RNG and is different for
every header, even the backup header must contain a different salt.
The salt in binary header is not used after the header is read, the main intention
is to avoid deduplication of the header sector.
The salt must be regenerated on every header repair (but not on regular update).
The sequential number (seqid) is a counter that is always increased when a new
update of the header is written. The header with higher seqid is more recent and
is used for recovery (if there are two headers with different seqid, the
more recent one is automatically used).
The rest of binary header must be zeroed.
JSON area
~~~~~~~~~
The JSON area starts immediately after the binary header. Its size is set
by binary header hdr_size field (JSON area size = hdr_size - 4096).
The area contains metadata in JSON format and is fixed. Unused remainder
of the area must be empty.
The header cannot store larger metadata that this fixed buffer and header
size must be set properly during format. For now, only areas with 14 kB
header (4kB binary header + 14kB JSON area) is created during format.
The JSON is structured to be able to describe system in very generic way,
but LUKS2 intentionally limits options to values that are supportable
in implemented version.
JSON structure is as follows:
Mandatory sections (must be present but some can be empty):
- config
- keyslots
- digests
- segments
- tokens
Except for config section, all section contains array of objects that must be named
as number (unsigned integer) - for example keyslot "0", "1" etc.
Every object is typed (must contain attribute "type").
According to type, library decides how to handle (or ignore) such an object.
Binary data inside JSON (for example salt) is stored in Hexa64 encoding.
If a value is needed to be stored as a 64bit integer (usually offset or size),
it is stored in text format and later converted to the 64bit integer.
(JSON cannot store 64bit integers directly.)
Config section
~~~~~~~~~~~~~~
Config contains information about JSON buffer size (cross-checked with binary header),
keyslot area size and optional object with activation flags.
The "flags" section is array of activation flags that are automatically used
when LUKS device is activated (for example it can unconditionally allow TRIM/discard
functionality on the encrypted device).
Segments sections
~~~~~~~~~~~~~~~~~
The segment is an encrypted area on the disk containing data (in LUKS1 often
mentioned as a data payload).
For now, only one data area is available for the user.
(More segments will be later used for on-line re-encryption functionality.)
Segments contain definition about encryption parameters, sector size and
start and length of the segments. By default, the segment starts directly
after the LUKS2 header and is marked as "dynamic" (it automatically detects
the size of the available device).
Optionally it can contain information about data integrity protection,
then the data segments is formatted as dm-integrity device and dm-crypt
encryption is stacked above.
To activate a segment, there must be at least one digest linked to it.
Keyslots section
~~~~~~~~~~~~~~~~
Keyslot object contains information stored key - area, where it is stored
(keyslot data), encryption, anti-forensic function, and Key Derivation Function
and its parameters (PBKDF type, costs, salt).
For now, only internal "luks2" keyslot type is available, it uses the same logic
as LUKS1 keyslot, but allows to define per-keyslot algorithms
(for example different PBKDF).
Digests section
~~~~~~~~~~~~~~~
The digest is used to verify that volume key decrypted from a keyslot is correct.
A digest is linked to keyslots and segment.
For now, only "pbkdf2" digest (LUKS1 compatible digest that uses PBKDF2)
is supported.
Tokens section
~~~~~~~~~~~~~~
A token is an object that can describe "how to get passphrase or key" to unlock
particular keyslot or it can be used t store any additional data (even unrelated
to a keyslot).
This area can be user configurable, and libcryptsetup provides interface to
store used data directly in JSON format.
Some token types are implemented internally, for now, there is only "luks2-keyring".
type. This token type tries to load unlocking passphrase from kernel keyring
with stored identification.
There can be external application that uses token objects to store metadata and
implements bindings to specific hardware (TPM etc.).
LUKS2 JSON Format Example
~~~~~~~~~~~~~~~~~~~~~~~~~
For illustration this is example of a LUKS2 device JSON:
{
"keyslots":{
"0":{
"type":"luks2",
"key_size":32,
"kdf":{
"type":"argon2i",
"time":181,
"memory":1024,
"cpus":4,
"salt":"Xfc5ScS8tCLrdbt6jtyWsBjCwAn3Msn\/enOYaAq8PEo="
},
"af":{
"type":"luks1",
"hash":"sha256",
"stripes":4000
},
"area":{
"type":"raw",
"encryption":"aes-xts-plain64",
"key_size":32,
"offset":"32768",
"size":"131072"
}
}
},
"tokens":{
"0":{
"type":"luks2-keyring",
"keyslots":[
"0"
],
"key_description":"my-token"
}
},
"segments":{
"0":{
"type":"crypt",
"offset":"4194304",
"iv_tweak":"0",
"size":"dynamic",
"encryption":"aes-xts-plain64",
"sector_size":512
}
},
"digests":{
"0":{
"type":"pbkdf2",
"keyslots":[
"0"
],
"segments":[
"0"
],
"hash":"sha256",
"iterations":155298,
"salt":"WgMOideLECc5hfnmFVu3bwttJpkfnpf2RayE2WhP8zU=",
"digest":"olobPk9pc0GItqofH78aMPmRaOZIbRevlvSlTZ91NLI="
}
},
"config":{
"json_size":"12288",
"keyslots_size":"4161536",
"flags":[
"allow-discards"
]
}
}

View File

@@ -40,7 +40,7 @@
* @subsection cformat crypt_format() - header and payload on mutual device
* This section covers basic use cases for formatting LUKS devices. Format operation
* sets device type in context and in case of LUKS header is written at the beginning
* of block device. In the example bellow we use the scenario where LUKS header and data
* of block device. In the example below we use the scenario where LUKS header and data
* are both stored on the same device. There's also a possibility to store header and
* data separately.
*

Binary file not shown.

View File

@@ -30,7 +30,7 @@ Changes since version 2.0.1
* Add LUKS2 specific options for cryptsetup-reencrypt.
Tokens and persistent flags are now transferred during reencryption;
change of PBKDF keyslot parameters is now supported and alllows
change of PBKDF keyslot parameters is now supported and allows
to set precalculated values (no benchmarks).
* Do not allow LUKS2 --persistent and --test-passphrase cryptsetup flags

121
docs/v2.0.3-ReleaseNotes Normal file
View File

@@ -0,0 +1,121 @@
Cryptsetup 2.0.3 Release Notes
==============================
Stable bug-fix release with new features.
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
The legacy LUKS (referenced as LUKS1) will be fully supported
forever as well as a traditional and fully backward compatible format.
Please note that authenticated disk encryption, non-cryptographic
data integrity protection (dm-integrity), use of Argon2 Password-Based
Key Derivation Function and the LUKS2 on-disk format itself are new
features and can contain some bugs.
To provide all security features of authenticated encryption, we need
a better nonce-reuse resistant algorithm in the kernel (see note below).
For now, please use authenticated encryption as an experimental feature.
Please do not use LUKS2 without properly configured backup or in
production systems that need to be compatible with older systems.
Changes since version 2.0.2
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Expose interface to unbound LUKS2 keyslots.
Unbound LUKS2 keyslot allows storing a key material that is independent
of master volume key (it is not bound to encrypted data segment).
* New API extensions for unbound keyslots (LUKS2 only)
crypt_keyslot_get_key_size() and crypt_volume_key_get()
These functions allow to get key and key size for unbound keyslots.
* New enum value CRYPT_SLOT_UNBOUND for keyslot status (LUKS2 only).
* Add --unbound keyslot option to the cryptsetup luksAddKey command.
* Add crypt_get_active_integrity_failures() call to get integrity
failure count for dm-integrity devices.
* Add crypt_get_pbkdf_default() function to get per-type PBKDF default
setting.
* Add new flag to crypt_keyslot_add_by_key() to force update device
volume key. This call is mainly intended for a wrapped key change.
* Allow volume key store in a file with cryptsetup.
The --dump-master-key together with --master-key-file allows cryptsetup
to store the binary volume key to a file instead of standard output.
* Add support detached header for cryptsetup-reencrypt command.
* Fix VeraCrypt PIM handling - use proper iterations count formula
for PBKDF2-SHA512 and PBKDF2-Whirlpool used in system volumes.
* Fix cryptsetup tcryptDump for VeraCrypt PIM (support --veracrypt-pim).
* Add --with-default-luks-format configure time option.
(Option to override default LUKS format version.)
* Fix LUKS version conversion for detached (and trimmed) LUKS headers.
* Add luksConvertKey cryptsetup command that converts specific keyslot
from one PBKDF to another.
* Do not allow conversion to LUKS2 if LUKSMETA (external tool metadata)
header is detected.
* More cleanup and hardening of LUKS2 keyslot specific validation options.
Add more checks for cipher validity before writing metadata on-disk.
* Do not allow LUKS1 version downconversion if the header contains tokens.
* Add "paes" family ciphers (AES wrapped key scheme for mainframes)
to allowed ciphers.
Specific wrapped ley configuration logic must be done by 3rd party tool,
LUKS2 stores only keyslot material and allow activation of the device.
* Add support for --check-at-most-once option (kernel 4.17) to veritysetup.
This flag can be dangerous; if you can control underlying device
(you can change its content after it was verified) it will no longer
prevent reading tampered data and also it does not prevent silent
data corruptions that appear after the block was once read.
* Fix return code (EPERM instead of EINVAL) and retry count for bad
passphrase on non-tty input.
* Enable support for FEC decoding in veritysetup to check dm-verity devices
with additional Reed-Solomon code in userspace (verify command).
Unfinished things & TODO for next releases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* There will be better documentation and examples (planned for 2.0.4).
* There will be some more formal definition of the threat model for integrity
protection. (And a link to some papers discussing integrity protection,
once it is, hopefully, accepted and published.)
* Authenticated encryption will use new algorithms from CAESAR competition
https://competitions.cr.yp.to/caesar-submissions.html.
We plan to use AEGIS and MORUS, as CAESAR finalists.
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
in the kernel have too small 96-bit nonces that are problematic with
randomly generated IVs (the collision probability is not negligible).
* Authenticated encryption do not set encryption for a dm-integrity journal.
While it does not influence data confidentiality or integrity protection,
an attacker can get some more information from data journal or cause that
system will corrupt sectors after journal replay. (That corruption will be
detected though.)
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
directory (like a simple external program that uses libssh to unlock LUKS2
using remote keyfile).
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
(it is not updated for new features) and will be REMOVED in version 2.1
in favor of python bindings to the libblockdev library.
See https://github.com/storaged-project/libblockdev/releases/tag/2.17-1 that
already supports LUKS2 and VeraCrypt devices handling through libcryptsetup.

119
docs/v2.0.4-ReleaseNotes Normal file
View File

@@ -0,0 +1,119 @@
Cryptsetup 2.0.4 Release Notes
==============================
Stable bug-fix release with new features.
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
The legacy LUKS (referenced as LUKS1) will be fully supported
forever as well as a traditional and fully backward compatible format.
Please note that authenticated disk encryption, non-cryptographic
data integrity protection (dm-integrity), use of Argon2 Password-Based
Key Derivation Function and the LUKS2 on-disk format itself are new
features and can contain some bugs.
To provide all security features of authenticated encryption, we need
a better nonce-reuse resistant algorithm in the kernel (see note below).
For now, please use authenticated encryption as an experimental feature.
Please do not use LUKS2 without properly configured backup or in
production systems that need to be compatible with older systems.
Changes since version 2.0.3
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Use the libblkid (blockid) library to detect foreign signatures
on a device before LUKS format and LUKS2 auto-recovery.
This change fixes an unexpected recovery using the secondary
LUKS2 header after a device was already overwritten with
another format (filesystem or LVM physical volume).
LUKS2 will not recreate a primary header if it detects a valid
foreign signature. In this situation, a user must always
use cryptsetup repair command for the recovery.
Note that libcryptsetup and utilities are now linked to libblkid
as a new dependence.
To compile code without blockid support (strongly discouraged),
use --disable-blkid configure switch.
* Add prompt for format and repair actions in cryptsetup and
integritysetup if foreign signatures are detected on the device
through the blockid library.
After the confirmation, all known signatures are then wiped as
part of the format or repair procedure.
* Print consistent verbose message about keyslot and token numbers.
For keyslot actions: Key slot <number> unlocked/created/removed.
For token actions: Token <number> created/removed.
* Print error, if a non-existent token is tried to be removed.
* Add support for LUKS2 token definition export and import.
The token command now can export/import customized token JSON file
directly from command line. See the man page for more details.
* Add support for new dm-integrity superblock version 2.
* Add an error message when nothing was read from a key file.
* Update cryptsetup man pages, including --type option usage.
* Add a snapshot of LUKS2 format specification to documentation
and accordingly fix supported secondary header offsets.
* Add bundled optimized Argon2 SSE (X86_64 platform) code.
If the bundled Argon2 code is used and the new configure switch
--enable-internal-sse-argon2 option is present, and compiler flags
support required optimization, the code will try to use optimized
and faster variant.
Always use the shared library (--enable-libargon2) if possible.
This option was added because an enterprise distribution
rejected to support the shared Argon2 library and native support
in generic cryptographic libraries is not ready yet.
* Fix compilation with crypto backend for LibreSSL >= 2.7.0.
LibreSSL introduced OpenSSL 1.1.x API functions, so compatibility
wrapper must be commented out.
* Fix on-disk header size calculation for LUKS2 format if a specific
data alignment is requested. Until now, the code used default size
that could be wrong for converted devices.
Unfinished things & TODO for next releases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Authenticated encryption will use new algorithms from CAESAR competition
https://competitions.cr.yp.to/caesar-submissions.html.
We plan to use AEGIS and MORUS (in kernel 4.18), as CAESAR finalists.
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
in the kernel have too small 96-bit nonces that are problematic with
randomly generated IVs (the collision probability is not negligible).
For more info about LUKS2 authenticated encryption, please see our paper
https://arxiv.org/abs/1807.00309
* Authenticated encryption do not set encryption for a dm-integrity journal.
While it does not influence data confidentiality or integrity protection,
an attacker can get some more information from data journal or cause that
system will corrupt sectors after journal replay. (That corruption will be
detected though.)
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
directory (like a simple external program that uses libssh to unlock LUKS2
using remote keyfile).
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
(it is not updated for new features) and will be REMOVED in version 2.1
in favor of python bindings to the libblockdev library.
See https://github.com/storaged-project/libblockdev/releases that
already supports LUKS2 and VeraCrypt devices handling through libcryptsetup.

102
docs/v2.0.5-ReleaseNotes Normal file
View File

@@ -0,0 +1,102 @@
Cryptsetup 2.0.5 Release Notes
==============================
Stable bug-fix release with new features.
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
The legacy LUKS (referenced as LUKS1) will be fully supported
forever as well as a traditional and fully backward compatible format.
Please note that authenticated disk encryption, non-cryptographic
data integrity protection (dm-integrity), use of Argon2 Password-Based
Key Derivation Function and the LUKS2 on-disk format itself are new
features and can contain some bugs.
Please do not use LUKS2 without properly configured backup or in
production systems that need to be compatible with older systems.
Changes since version 2.0.4
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Wipe full header areas (including unused) during LUKS format.
Since this version, the whole area up to the data offset is zeroed,
and subsequently, all keyslots areas are wiped with random data.
This ensures that no remaining old data remains in the LUKS header
areas, but it could slow down format operation on some devices.
Previously only first 4k (or 32k for LUKS2) and the used keyslot
was overwritten in the format operation.
* Several fixes to error messages that were unintentionally replaced
in previous versions with a silent exit code.
More descriptive error messages were added, including error
messages if
- a device is unusable (not a block device, no access, etc.),
- a LUKS device is not detected,
- LUKS header load code detects unsupported version,
- a keyslot decryption fails (also happens in the cipher check),
- converting an inactive keyslot.
* Device activation fails if data area overlaps with LUKS header.
* Code now uses explicit_bzero to wipe memory if available
(instead of own implementation).
* Additional VeraCrypt modes are now supported, including Camellia
and Kuznyechik symmetric ciphers (and cipher chains) and Streebog
hash function. These were introduced in a recent VeraCrypt upstream.
Note that Kuznyechik requires out-of-tree kernel module and
Streebog hash function is available only with the gcrypt cryptographic
backend for now.
* Fixes static build for integritysetup if the pwquality library is used.
* Allows passphrase change for unbound keyslots.
* Fixes removed keyslot number in verbose message for luksKillSlot,
luksRemoveKey and erase command.
* Adds blkid scan when attempting to open a plain device and warn the user
about existing device signatures in a ciphertext device.
* Remove LUKS header signature if luksFormat fails to add the first keyslot.
* Remove O_SYNC from device open and use fsync() to speed up
wipe operation considerably.
* Create --master-key-file in luksDump and fail if the file already exists.
* Fixes a bug when LUKS2 authenticated encryption with a detached header
wiped the header device instead of dm-integrity data device area (causing
unnecessary LUKS2 header auto recovery).
Unfinished things & TODO for next releases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Authenticated encryption should use new algorithms from CAESAR competition
https://competitions.cr.yp.to/caesar-submissions.html.
AEGIS and MORUS are already available in kernel 4.18.
For more info about LUKS2 authenticated encryption, please see our paper
https://arxiv.org/abs/1807.00309
Please note that authenticated encryption is still an experimental feature
and can have performance problems for hish-speed devices and device
with larger IO blocks (like RAID).
* Authenticated encryption do not set encryption for a dm-integrity journal.
While it does not influence data confidentiality or integrity protection,
an attacker can get some more information from data journal or cause that
system will corrupt sectors after journal replay. (That corruption will be
detected though.)
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
directory (like a simple external program that uses libssh to unlock LUKS2
using remote keyfile).
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
(it is not updated for new features) and will be REMOVED in version 2.1
in favor of python bindings to the libblockdev library.
See https://github.com/storaged-project/libblockdev/releases that
already supports LUKS2 and VeraCrypt devices handling through libcryptsetup.

View File

@@ -3,10 +3,18 @@ pkgconfig_DATA = lib/libcryptsetup.pc
lib_LTLIBRARIES = libcryptsetup.la
noinst_LTLIBRARIES += libutils_io.la
include_HEADERS = lib/libcryptsetup.h
EXTRA_DIST += lib/libcryptsetup.pc.in lib/libcryptsetup.sym
libutils_io_la_CFLAGS = $(AM_CFLAGS)
libutils_io_la_SOURCES = \
lib/utils_io.c \
lib/utils_io.h
libcryptsetup_la_CPPFLAGS = $(AM_CPPFLAGS) \
-I $(top_srcdir)/lib/crypto_backend \
-I $(top_srcdir)/lib/luks1 \
@@ -16,7 +24,7 @@ libcryptsetup_la_CPPFLAGS = $(AM_CPPFLAGS) \
-I $(top_srcdir)/lib/tcrypt \
-I $(top_srcdir)/lib/integrity
libcryptsetup_la_DEPENDENCIES = libcrypto_backend.la lib/libcryptsetup.sym
libcryptsetup_la_DEPENDENCIES = libutils_io.la libcrypto_backend.la lib/libcryptsetup.sym
libcryptsetup_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \
-Wl,--version-script=$(top_srcdir)/lib/libcryptsetup.sym \
@@ -30,7 +38,9 @@ libcryptsetup_la_LIBADD = \
@CRYPTO_LIBS@ \
@LIBARGON2_LIBS@ \
@JSON_C_LIBS@ \
libcrypto_backend.la
@BLKID_LIBS@ \
libcrypto_backend.la \
libutils_io.la
libcryptsetup_la_SOURCES = \
lib/setup.c \
@@ -77,6 +87,7 @@ libcryptsetup_la_SOURCES = \
lib/verity/verity.c \
lib/verity/verity.h \
lib/verity/rs_encode_char.c \
lib/verity/rs_decode_char.c \
lib/verity/rs.h \
lib/luks2/luks2_disk_metadata.c \
lib/luks2/luks2_json_format.c \
@@ -89,4 +100,6 @@ libcryptsetup_la_SOURCES = \
lib/luks2/luks2_token_keyring.c \
lib/luks2/luks2_token.c \
lib/luks2/luks2_internal.h \
lib/luks2/luks2.h
lib/luks2/luks2.h \
lib/utils_blkid.c \
lib/utils_blkid.h

View File

@@ -8,7 +8,8 @@ libcrypto_backend_la_SOURCES = \
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/argon2_generic.c \
lib/crypto_backend/cipher_generic.c
if CRYPTO_BACKEND_GCRYPT
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_gcrypt.c

View File

@@ -1,22 +1,30 @@
noinst_LTLIBRARIES += libargon2.la
libargon2_la_CFLAGS = $(AM_CFLAGS) -std=c89 -pthread -O3
libargon2_la_CPPFLAGS = $(AM_CPPFLAGS) -I lib/crypto_backend/argon2/blake2
libargon2_la_CPPFLAGS = $(AM_CPPFLAGS) \
-I lib/crypto_backend/argon2 \
-I lib/crypto_backend/argon2/blake2
libargon2_la_SOURCES = \
lib/crypto_backend/argon2/blake2/blake2b.c \
lib/crypto_backend/argon2/blake2/blake2.h \
lib/crypto_backend/argon2/blake2/blake2-impl.h \
lib/crypto_backend/argon2/blake2/blamka-round-ref.h \
lib/crypto_backend/argon2/argon2.c \
lib/crypto_backend/argon2/argon2.h \
lib/crypto_backend/argon2/core.c \
lib/crypto_backend/argon2/core.h \
lib/crypto_backend/argon2/encoding.c \
lib/crypto_backend/argon2/encoding.h \
lib/crypto_backend/argon2/ref.c \
lib/crypto_backend/argon2/thread.c \
lib/crypto_backend/argon2/thread.h
if CRYPTO_INTERNAL_SSE_ARGON2
libargon2_la_SOURCES += lib/crypto_backend/argon2/blake2/blamka-round-opt.h \
lib/crypto_backend/argon2/opt.c
else
libargon2_la_SOURCES += lib/crypto_backend/argon2/blake2/blamka-round-ref.h \
lib/crypto_backend/argon2/ref.c
endif
EXTRA_DIST += lib/crypto_backend/argon2/LICENSE
EXTRA_DIST += lib/crypto_backend/argon2/README

View File

@@ -29,10 +29,13 @@ extern "C" {
/* Symbols visibility control */
#ifdef A2_VISCTL
#define ARGON2_PUBLIC __attribute__((visibility("default")))
#define ARGON2_LOCAL __attribute__ ((visibility ("hidden")))
#elif _MSC_VER
#define ARGON2_PUBLIC __declspec(dllexport)
#define ARGON2_LOCAL
#else
#define ARGON2_PUBLIC
#define ARGON2_LOCAL
#endif
/*
@@ -90,7 +93,7 @@ extern "C" {
#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1)
/* Global flag to determine if we are wiping internal memory buffers. This flag
* is defined in core.c and deafults to 1 (wipe internal memory). */
* is defined in core.c and defaults to 1 (wipe internal memory). */
extern int FLAG_clear_internal_memory;
/* Error codes */

View File

@@ -18,9 +18,7 @@
#ifndef PORTABLE_BLAKE2_H
#define PORTABLE_BLAKE2_H
#include <stddef.h>
#include <stdint.h>
#include <limits.h>
#include "../argon2.h"
#if defined(__cplusplus)
extern "C" {
@@ -69,19 +67,19 @@ enum {
};
/* Streaming API */
int blake2b_init(blake2b_state *S, size_t outlen);
int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,
ARGON2_LOCAL int blake2b_init(blake2b_state *S, size_t outlen);
ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,
size_t keylen);
int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
int blake2b_update(blake2b_state *S, const void *in, size_t inlen);
int blake2b_final(blake2b_state *S, void *out, size_t outlen);
ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, size_t inlen);
ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, size_t outlen);
/* Simple API */
int blake2b(void *out, size_t outlen, const void *in, size_t inlen,
const void *key, size_t keylen);
ARGON2_LOCAL int blake2b(void *out, size_t outlen, const void *in, size_t inlen,
const void *key, size_t keylen);
/* Argon2 Team - Begin Code */
int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen);
ARGON2_LOCAL int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen);
/* Argon2 Team - End Code */
#if defined(__cplusplus)

View File

@@ -0,0 +1,471 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#ifndef BLAKE_ROUND_MKA_OPT_H
#define BLAKE_ROUND_MKA_OPT_H
#include "blake2-impl.h"
#include <emmintrin.h>
#if defined(__SSSE3__)
#include <tmmintrin.h> /* for _mm_shuffle_epi8 and _mm_alignr_epi8 */
#endif
#if defined(__XOP__) && (defined(__GNUC__) || defined(__clang__))
#include <x86intrin.h>
#endif
#if !defined(__AVX512F__)
#if !defined(__AVX2__)
#if !defined(__XOP__)
#if defined(__SSSE3__)
#define r16 \
(_mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))
#define r24 \
(_mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))
#define _mm_roti_epi64(x, c) \
(-(c) == 32) \
? _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) \
: (-(c) == 24) \
? _mm_shuffle_epi8((x), r24) \
: (-(c) == 16) \
? _mm_shuffle_epi8((x), r16) \
: (-(c) == 63) \
? _mm_xor_si128(_mm_srli_epi64((x), -(c)), \
_mm_add_epi64((x), (x))) \
: _mm_xor_si128(_mm_srli_epi64((x), -(c)), \
_mm_slli_epi64((x), 64 - (-(c))))
#else /* defined(__SSE2__) */
#define _mm_roti_epi64(r, c) \
_mm_xor_si128(_mm_srli_epi64((r), -(c)), _mm_slli_epi64((r), 64 - (-(c))))
#endif
#else
#endif
static BLAKE2_INLINE __m128i fBlaMka(__m128i x, __m128i y) {
const __m128i z = _mm_mul_epu32(x, y);
return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z));
}
#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
A0 = fBlaMka(A0, B0); \
A1 = fBlaMka(A1, B1); \
\
D0 = _mm_xor_si128(D0, A0); \
D1 = _mm_xor_si128(D1, A1); \
\
D0 = _mm_roti_epi64(D0, -32); \
D1 = _mm_roti_epi64(D1, -32); \
\
C0 = fBlaMka(C0, D0); \
C1 = fBlaMka(C1, D1); \
\
B0 = _mm_xor_si128(B0, C0); \
B1 = _mm_xor_si128(B1, C1); \
\
B0 = _mm_roti_epi64(B0, -24); \
B1 = _mm_roti_epi64(B1, -24); \
} while ((void)0, 0)
#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
A0 = fBlaMka(A0, B0); \
A1 = fBlaMka(A1, B1); \
\
D0 = _mm_xor_si128(D0, A0); \
D1 = _mm_xor_si128(D1, A1); \
\
D0 = _mm_roti_epi64(D0, -16); \
D1 = _mm_roti_epi64(D1, -16); \
\
C0 = fBlaMka(C0, D0); \
C1 = fBlaMka(C1, D1); \
\
B0 = _mm_xor_si128(B0, C0); \
B1 = _mm_xor_si128(B1, C1); \
\
B0 = _mm_roti_epi64(B0, -63); \
B1 = _mm_roti_epi64(B1, -63); \
} while ((void)0, 0)
#if defined(__SSSE3__)
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
__m128i t0 = _mm_alignr_epi8(B1, B0, 8); \
__m128i t1 = _mm_alignr_epi8(B0, B1, 8); \
B0 = t0; \
B1 = t1; \
\
t0 = C0; \
C0 = C1; \
C1 = t0; \
\
t0 = _mm_alignr_epi8(D1, D0, 8); \
t1 = _mm_alignr_epi8(D0, D1, 8); \
D0 = t1; \
D1 = t0; \
} while ((void)0, 0)
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
__m128i t0 = _mm_alignr_epi8(B0, B1, 8); \
__m128i t1 = _mm_alignr_epi8(B1, B0, 8); \
B0 = t0; \
B1 = t1; \
\
t0 = C0; \
C0 = C1; \
C1 = t0; \
\
t0 = _mm_alignr_epi8(D0, D1, 8); \
t1 = _mm_alignr_epi8(D1, D0, 8); \
D0 = t1; \
D1 = t0; \
} while ((void)0, 0)
#else /* SSE2 */
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
__m128i t0 = D0; \
__m128i t1 = B0; \
D0 = C0; \
C0 = C1; \
C1 = D0; \
D0 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t0, t0)); \
D1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(D1, D1)); \
B0 = _mm_unpackhi_epi64(B0, _mm_unpacklo_epi64(B1, B1)); \
B1 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(t1, t1)); \
} while ((void)0, 0)
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
__m128i t0, t1; \
t0 = C0; \
C0 = C1; \
C1 = t0; \
t0 = B0; \
t1 = D0; \
B0 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(B0, B0)); \
B1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(B1, B1)); \
D0 = _mm_unpackhi_epi64(D0, _mm_unpacklo_epi64(D1, D1)); \
D1 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t1, t1)); \
} while ((void)0, 0)
#endif
#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1) \
do { \
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
\
DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
\
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
\
UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
} while ((void)0, 0)
#else /* __AVX2__ */
#include <immintrin.h>
#define rotr32(x) _mm256_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1))
#define rotr24(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10, 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))
#define rotr16(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9, 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))
#define rotr63(x) _mm256_xor_si256(_mm256_srli_epi64((x), 63), _mm256_add_epi64((x), (x)))
#define G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
do { \
__m256i ml = _mm256_mul_epu32(A0, B0); \
ml = _mm256_add_epi64(ml, ml); \
A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \
D0 = _mm256_xor_si256(D0, A0); \
D0 = rotr32(D0); \
\
ml = _mm256_mul_epu32(C0, D0); \
ml = _mm256_add_epi64(ml, ml); \
C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \
\
B0 = _mm256_xor_si256(B0, C0); \
B0 = rotr24(B0); \
\
ml = _mm256_mul_epu32(A1, B1); \
ml = _mm256_add_epi64(ml, ml); \
A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \
D1 = _mm256_xor_si256(D1, A1); \
D1 = rotr32(D1); \
\
ml = _mm256_mul_epu32(C1, D1); \
ml = _mm256_add_epi64(ml, ml); \
C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \
\
B1 = _mm256_xor_si256(B1, C1); \
B1 = rotr24(B1); \
} while((void)0, 0);
#define G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
do { \
__m256i ml = _mm256_mul_epu32(A0, B0); \
ml = _mm256_add_epi64(ml, ml); \
A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \
D0 = _mm256_xor_si256(D0, A0); \
D0 = rotr16(D0); \
\
ml = _mm256_mul_epu32(C0, D0); \
ml = _mm256_add_epi64(ml, ml); \
C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \
B0 = _mm256_xor_si256(B0, C0); \
B0 = rotr63(B0); \
\
ml = _mm256_mul_epu32(A1, B1); \
ml = _mm256_add_epi64(ml, ml); \
A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \
D1 = _mm256_xor_si256(D1, A1); \
D1 = rotr16(D1); \
\
ml = _mm256_mul_epu32(C1, D1); \
ml = _mm256_add_epi64(ml, ml); \
C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \
B1 = _mm256_xor_si256(B1, C1); \
B1 = rotr63(B1); \
} while((void)0, 0);
#define DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \
C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \
\
B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \
C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \
} while((void)0, 0);
#define DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
do { \
__m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \
__m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \
B1 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
B0 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
\
tmp1 = C0; \
C0 = C1; \
C1 = tmp1; \
\
tmp1 = _mm256_blend_epi32(D0, D1, 0xCC); \
tmp2 = _mm256_blend_epi32(D0, D1, 0x33); \
D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
} while(0);
#define UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \
C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \
\
B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \
C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \
} while((void)0, 0);
#define UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
do { \
__m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \
__m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \
B0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
B1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
\
tmp1 = C0; \
C0 = C1; \
C1 = tmp1; \
\
tmp1 = _mm256_blend_epi32(D0, D1, 0x33); \
tmp2 = _mm256_blend_epi32(D0, D1, 0xCC); \
D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
} while((void)0, 0);
#define BLAKE2_ROUND_1(A0, A1, B0, B1, C0, C1, D0, D1) \
do{ \
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
\
DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
\
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
\
UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
} while((void)0, 0);
#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \
do{ \
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
\
DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
\
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
\
UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
} while((void)0, 0);
#endif /* __AVX2__ */
#else /* __AVX512F__ */
#include <immintrin.h>
#define ror64(x, n) _mm512_ror_epi64((x), (n))
static __m512i muladd(__m512i x, __m512i y)
{
__m512i z = _mm512_mul_epu32(x, y);
return _mm512_add_epi64(_mm512_add_epi64(x, y), _mm512_add_epi64(z, z));
}
#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
A0 = muladd(A0, B0); \
A1 = muladd(A1, B1); \
\
D0 = _mm512_xor_si512(D0, A0); \
D1 = _mm512_xor_si512(D1, A1); \
\
D0 = ror64(D0, 32); \
D1 = ror64(D1, 32); \
\
C0 = muladd(C0, D0); \
C1 = muladd(C1, D1); \
\
B0 = _mm512_xor_si512(B0, C0); \
B1 = _mm512_xor_si512(B1, C1); \
\
B0 = ror64(B0, 24); \
B1 = ror64(B1, 24); \
} while ((void)0, 0)
#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
A0 = muladd(A0, B0); \
A1 = muladd(A1, B1); \
\
D0 = _mm512_xor_si512(D0, A0); \
D1 = _mm512_xor_si512(D1, A1); \
\
D0 = ror64(D0, 16); \
D1 = ror64(D1, 16); \
\
C0 = muladd(C0, D0); \
C1 = muladd(C1, D1); \
\
B0 = _mm512_xor_si512(B0, C0); \
B1 = _mm512_xor_si512(B1, C1); \
\
B0 = ror64(B0, 63); \
B1 = ror64(B1, 63); \
} while ((void)0, 0)
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \
B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \
\
C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
\
D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \
D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \
} while ((void)0, 0)
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \
B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \
\
C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
\
D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \
D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \
} while ((void)0, 0)
#define BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1) \
do { \
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
\
DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
\
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
\
UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
} while ((void)0, 0)
#define SWAP_HALVES(A0, A1) \
do { \
__m512i t0, t1; \
t0 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(1, 0, 1, 0)); \
t1 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(3, 2, 3, 2)); \
A0 = t0; \
A1 = t1; \
} while((void)0, 0)
#define SWAP_QUARTERS(A0, A1) \
do { \
SWAP_HALVES(A0, A1); \
A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \
A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \
} while((void)0, 0)
#define UNSWAP_QUARTERS(A0, A1) \
do { \
A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \
A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \
SWAP_HALVES(A0, A1); \
} while((void)0, 0)
#define BLAKE2_ROUND_1(A0, C0, B0, D0, A1, C1, B1, D1) \
do { \
SWAP_HALVES(A0, B0); \
SWAP_HALVES(C0, D0); \
SWAP_HALVES(A1, B1); \
SWAP_HALVES(C1, D1); \
BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \
SWAP_HALVES(A0, B0); \
SWAP_HALVES(C0, D0); \
SWAP_HALVES(A1, B1); \
SWAP_HALVES(C1, D1); \
} while ((void)0, 0)
#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \
do { \
SWAP_QUARTERS(A0, A1); \
SWAP_QUARTERS(B0, B1); \
SWAP_QUARTERS(C0, C1); \
SWAP_QUARTERS(D0, D1); \
BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \
UNSWAP_QUARTERS(A0, A1); \
UNSWAP_QUARTERS(B0, B1); \
UNSWAP_QUARTERS(C0, C1); \
UNSWAP_QUARTERS(D0, D1); \
} while ((void)0, 0)
#endif /* __AVX512F__ */
#endif /* BLAKE_ROUND_MKA_OPT_H */

View File

@@ -21,7 +21,7 @@
#include "blake2.h"
#include "blake2-impl.h"
/*designed by the Lyra PHC team */
/* designed by the Lyra PHC team */
static BLAKE2_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) {
const uint64_t m = UINT64_C(0xFFFFFFFF);
const uint64_t xy = (x & m) * (y & m);

View File

@@ -0,0 +1,283 @@
/*
* Argon2 reference source code package - reference C implementations
*
* Copyright 2015
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
*
* You may use this work under the terms of a Creative Commons CC0 1.0
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "argon2.h"
#include "core.h"
#include "blake2/blake2.h"
#include "blake2/blamka-round-opt.h"
/*
* Function fills a new memory block and optionally XORs the old block over the new one.
* Memory must be initialized.
* @param state Pointer to the just produced block. Content will be updated(!)
* @param ref_block Pointer to the reference block
* @param next_block Pointer to the block to be XORed over. May coincide with @ref_block
* @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
* @pre all block pointers must be valid
*/
#if defined(__AVX512F__)
static void fill_block(__m512i *state, const block *ref_block,
block *next_block, int with_xor) {
__m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK];
unsigned int i;
if (with_xor) {
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
state[i] = _mm512_xor_si512(
state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));
block_XY[i] = _mm512_xor_si512(
state[i], _mm512_loadu_si512((const __m512i *)next_block->v + i));
}
} else {
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
block_XY[i] = state[i] = _mm512_xor_si512(
state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));
}
}
for (i = 0; i < 2; ++i) {
BLAKE2_ROUND_1(
state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
}
for (i = 0; i < 2; ++i) {
BLAKE2_ROUND_2(
state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i],
state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]);
}
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
state[i] = _mm512_xor_si512(state[i], block_XY[i]);
_mm512_storeu_si512((__m512i *)next_block->v + i, state[i]);
}
}
#elif defined(__AVX2__)
static void fill_block(__m256i *state, const block *ref_block,
block *next_block, int with_xor) {
__m256i block_XY[ARGON2_HWORDS_IN_BLOCK];
unsigned int i;
if (with_xor) {
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
state[i] = _mm256_xor_si256(
state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));
block_XY[i] = _mm256_xor_si256(
state[i], _mm256_loadu_si256((const __m256i *)next_block->v + i));
}
} else {
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
block_XY[i] = state[i] = _mm256_xor_si256(
state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));
}
}
for (i = 0; i < 4; ++i) {
BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5],
state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);
}
for (i = 0; i < 4; ++i) {
BLAKE2_ROUND_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i],
state[16 + i], state[20 + i], state[24 + i], state[28 + i]);
}
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
state[i] = _mm256_xor_si256(state[i], block_XY[i]);
_mm256_storeu_si256((__m256i *)next_block->v + i, state[i]);
}
}
#else
static void fill_block(__m128i *state, const block *ref_block,
block *next_block, int with_xor) {
__m128i block_XY[ARGON2_OWORDS_IN_BLOCK];
unsigned int i;
if (with_xor) {
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
state[i] = _mm_xor_si128(
state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));
block_XY[i] = _mm_xor_si128(
state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));
}
} else {
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
block_XY[i] = state[i] = _mm_xor_si128(
state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));
}
}
for (i = 0; i < 8; ++i) {
BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2],
state[8 * i + 3], state[8 * i + 4], state[8 * i + 5],
state[8 * i + 6], state[8 * i + 7]);
}
for (i = 0; i < 8; ++i) {
BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i],
state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i],
state[8 * 6 + i], state[8 * 7 + i]);
}
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
state[i] = _mm_xor_si128(state[i], block_XY[i]);
_mm_storeu_si128((__m128i *)next_block->v + i, state[i]);
}
}
#endif
static void next_addresses(block *address_block, block *input_block) {
/*Temporary zero-initialized blocks*/
#if defined(__AVX512F__)
__m512i zero_block[ARGON2_512BIT_WORDS_IN_BLOCK];
__m512i zero2_block[ARGON2_512BIT_WORDS_IN_BLOCK];
#elif defined(__AVX2__)
__m256i zero_block[ARGON2_HWORDS_IN_BLOCK];
__m256i zero2_block[ARGON2_HWORDS_IN_BLOCK];
#else
__m128i zero_block[ARGON2_OWORDS_IN_BLOCK];
__m128i zero2_block[ARGON2_OWORDS_IN_BLOCK];
#endif
memset(zero_block, 0, sizeof(zero_block));
memset(zero2_block, 0, sizeof(zero2_block));
/*Increasing index counter*/
input_block->v[6]++;
/*First iteration of G*/
fill_block(zero_block, input_block, address_block, 0);
/*Second iteration of G*/
fill_block(zero2_block, address_block, address_block, 0);
}
void fill_segment(const argon2_instance_t *instance,
argon2_position_t position) {
block *ref_block = NULL, *curr_block = NULL;
block address_block, input_block;
uint64_t pseudo_rand, ref_index, ref_lane;
uint32_t prev_offset, curr_offset;
uint32_t starting_index, i;
#if defined(__AVX512F__)
__m512i state[ARGON2_512BIT_WORDS_IN_BLOCK];
#elif defined(__AVX2__)
__m256i state[ARGON2_HWORDS_IN_BLOCK];
#else
__m128i state[ARGON2_OWORDS_IN_BLOCK];
#endif
int data_independent_addressing;
if (instance == NULL) {
return;
}
data_independent_addressing =
(instance->type == Argon2_i) ||
(instance->type == Argon2_id && (position.pass == 0) &&
(position.slice < ARGON2_SYNC_POINTS / 2));
if (data_independent_addressing) {
init_block_value(&input_block, 0);
input_block.v[0] = position.pass;
input_block.v[1] = position.lane;
input_block.v[2] = position.slice;
input_block.v[3] = instance->memory_blocks;
input_block.v[4] = instance->passes;
input_block.v[5] = instance->type;
}
starting_index = 0;
if ((0 == position.pass) && (0 == position.slice)) {
starting_index = 2; /* we have already generated the first two blocks */
/* Don't forget to generate the first block of addresses: */
if (data_independent_addressing) {
next_addresses(&address_block, &input_block);
}
}
/* Offset of the current block */
curr_offset = position.lane * instance->lane_length +
position.slice * instance->segment_length + starting_index;
if (0 == curr_offset % instance->lane_length) {
/* Last block in this lane */
prev_offset = curr_offset + instance->lane_length - 1;
} else {
/* Previous block */
prev_offset = curr_offset - 1;
}
memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE);
for (i = starting_index; i < instance->segment_length;
++i, ++curr_offset, ++prev_offset) {
/*1.1 Rotating prev_offset if needed */
if (curr_offset % instance->lane_length == 1) {
prev_offset = curr_offset - 1;
}
/* 1.2 Computing the index of the reference block */
/* 1.2.1 Taking pseudo-random value from the previous block */
if (data_independent_addressing) {
if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
next_addresses(&address_block, &input_block);
}
pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
} else {
pseudo_rand = instance->memory[prev_offset].v[0];
}
/* 1.2.2 Computing the lane of the reference block */
ref_lane = ((pseudo_rand >> 32)) % instance->lanes;
if ((position.pass == 0) && (position.slice == 0)) {
/* Can not reference other lanes yet */
ref_lane = position.lane;
}
/* 1.2.3 Computing the number of possible reference block within the
* lane.
*/
position.index = i;
ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
ref_lane == position.lane);
/* 2 Creating a new block */
ref_block =
instance->memory + instance->lane_length * ref_lane + ref_index;
curr_block = instance->memory + curr_offset;
if (ARGON2_VERSION_10 == instance->version) {
/* version 1.2.1 and earlier: overwrite, not XOR */
fill_block(state, ref_block, curr_block, 0);
} else {
if(0 == position.pass) {
fill_block(state, ref_block, curr_block, 0);
} else {
fill_block(state, ref_block, curr_block, 1);
}
}
}
}

View File

@@ -0,0 +1,78 @@
/*
* Linux kernel cipher generic utilities
*
* Copyright (C) 2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2018, 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 <string.h>
#include <stdbool.h>
#include <errno.h>
#include "crypto_backend.h"
struct cipher_alg {
const char *name;
int blocksize;
bool wrapped_key;
};
/* FIXME: Getting block size should be dynamic from cipher backend. */
static const struct cipher_alg cipher_algs[] = {
{ "cipher_null", 16, false },
{ "aes", 16, false },
{ "serpent", 16, false },
{ "twofish", 16, false },
{ "anubis", 16, false },
{ "blowfish", 8, false },
{ "camellia", 16, false },
{ "cast5", 8, false },
{ "cast6", 16, false },
{ "des", 8, false },
{ "des3_ede", 8, false },
{ "khazad", 8, false },
{ "seed", 16, false },
{ "tea", 8, false },
{ "xtea", 8, false },
{ "paes", 16, true }, /* protected AES, s390 wrapped key scheme */
{ NULL, 0, false }
};
static const struct cipher_alg *_get_alg(const char *name)
{
int i = 0;
while (name && cipher_algs[i].name) {
if (!strcasecmp(name, cipher_algs[i].name))
return &cipher_algs[i];
i++;
}
return NULL;
}
int crypt_cipher_blocksize(const char *name)
{
const struct cipher_alg *ca = _get_alg(name);
return ca ? ca->blocksize : -EINVAL;
}
int crypt_cipher_wrapped_key(const char *name)
{
const struct cipher_alg *ca = _get_alg(name);
return ca ? (int)ca->wrapped_key : 0;
}

View File

@@ -100,6 +100,7 @@ uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len);
/* ciphers */
int crypt_cipher_blocksize(const char *name);
int crypt_cipher_wrapped_key(const char *name);
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length);
void crypt_cipher_destroy(struct crypt_cipher *ctx);
@@ -123,8 +124,12 @@ int crypt_storage_encrypt(struct crypt_storage *ctx, uint64_t sector,
/* Memzero helper (memset on stack can be optimized out) */
static inline void crypt_backend_memzero(void *s, size_t n)
{
#ifdef HAVE_EXPLICIT_BZERO
explicit_bzero(s, n);
#else
volatile uint8_t *p = (volatile uint8_t *)s;
while(n--) *p++ = 0;
#endif
}
#endif /* _CRYPTO_BACKEND_H */

View File

@@ -44,56 +44,12 @@ struct crypt_cipher {
int opfd;
};
struct cipher_alg {
const char *name;
int blocksize;
};
/* FIXME: Getting block size should be dynamic from cipher backend. */
static struct cipher_alg cipher_algs[] = {
{ "cipher_null", 16 },
{ "aes", 16 },
{ "serpent", 16 },
{ "twofish", 16 },
{ "anubis", 16 },
{ "blowfish", 8 },
{ "camellia", 16 },
{ "cast5", 8 },
{ "cast6", 16 },
{ "des", 8 },
{ "des3_ede", 8 },
{ "khazad", 8 },
{ "seed", 16 },
{ "tea", 8 },
{ "xtea", 8 },
{ NULL, 0 }
};
static struct cipher_alg *_get_alg(const char *name)
{
int i = 0;
while (name && cipher_algs[i].name) {
if (!strcasecmp(name, cipher_algs[i].name))
return &cipher_algs[i];
i++;
}
return NULL;
}
int crypt_cipher_blocksize(const char *name)
{
struct cipher_alg *ca = _get_alg(name);
return ca ? ca->blocksize : -EINVAL;
}
/*
* ciphers
*
* ENOENT - algorithm not available
* ENOTSUP - AF_ALG family not available
* (but cannot check specificaly for skcipher API)
* (but cannot check specifically for skcipher API)
*/
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
@@ -236,12 +192,6 @@ void crypt_cipher_destroy(struct crypt_cipher *ctx)
}
#else /* ENABLE_AF_ALG */
int crypt_cipher_blocksize(const char *name)
{
return -EINVAL;
}
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *buffer, size_t length)
{

View File

@@ -50,9 +50,11 @@ struct crypt_hmac {
};
/*
* Compatible wrappers for OpenSSL < 1.1.0
* Compatible wrappers for OpenSSL < 1.1.0 and LibreSSL < 2.7.0
*/
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
static void openssl_backend_init(void)
{
OpenSSL_add_all_algorithms();

View File

@@ -42,7 +42,7 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic)) ||
sb->version != SB_VERSION) {
(sb->version != SB_VERSION_1 && sb->version != SB_VERSION_2)) {
log_std(cd, "No integrity superblock detected on %s.\n",
device_path(device));
r = -EINVAL;
@@ -50,6 +50,8 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
sb->integrity_tag_size = le16toh(sb->integrity_tag_size);
sb->journal_sections = le32toh(sb->journal_sections);
sb->provided_data_sectors = le64toh(sb->provided_data_sectors);
sb->recalc_sector = le64toh(sb->recalc_sector);
sb->flags = le32toh(sb->flags);
r = 0;
}
@@ -82,11 +84,17 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
return r;
log_std(cd, "Info for integrity device %s.\n", device_path(device));
log_std(cd, "superblock_version %d\n", (unsigned)sb.version);
log_std(cd, "log2_interleave_sectors %d\n", sb.log2_interleave_sectors);
log_std(cd, "integrity_tag_size %u\n", sb.integrity_tag_size);
log_std(cd, "journal_sections %u\n", sb.journal_sections);
log_std(cd, "provided_data_sectors %" PRIu64 "\n", sb.provided_data_sectors);
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",
sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "");
return 0;
}
@@ -106,16 +114,16 @@ int INTEGRITY_data_sectors(struct crypt_device *cd,
return 0;
}
int INTEGRITY_key_size(struct crypt_device *cd)
int INTEGRITY_key_size(struct crypt_device *cd, const char *integrity)
{
const char *integrity = crypt_get_integrity(cd);
if (!integrity)
return 0;
//FIXME: use crypto backend hash size
if (!strcmp(integrity, "aead"))
return 0;
else if (!strcmp(integrity, "hmac(sha1)"))
return 20;
else if (!strcmp(integrity, "hmac(sha256)"))
return 32;
else if (!strcmp(integrity, "hmac(sha512)"))
@@ -145,6 +153,8 @@ int INTEGRITY_tag_size(struct crypt_device *cd,
iv_tag_size = 8;
else if (!strcmp(cipher_mode, "ctr-random"))
iv_tag_size = 16;
else if (!strcmp(cipher, "aegis256") && !strcmp(cipher_mode, "random"))
iv_tag_size = 32;
else if (!strcmp(cipher_mode, "random"))
iv_tag_size = 16;
@@ -155,6 +165,8 @@ int INTEGRITY_tag_size(struct crypt_device *cd,
auth_tag_size = 16; //FIXME gcm- mode only
else if (!strcmp(integrity, "cmac(aes)"))
auth_tag_size = 16;
else if (!strcmp(integrity, "hmac(sha1)"))
auth_tag_size = 20;
else if (!strcmp(integrity, "hmac(sha256)"))
auth_tag_size = 32;
else if (!strcmp(integrity, "hmac(sha512)"))
@@ -218,7 +230,7 @@ int INTEGRITY_activate(struct crypt_device *cd,
r = dm_create_device(cd, name, "INTEGRITY", &dmdi, 0);
if (r < 0 && (dm_flags(DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
log_err(cd, _("Kernel doesn't support dm-integrity mapping.\n"));
log_err(cd, _("Kernel doesn't support dm-integrity mapping."));
return -ENOTSUP;
}
@@ -269,7 +281,7 @@ int INTEGRITY_format(struct crypt_device *cd,
r = device_block_adjust(cd, dmdi.data_device, DEV_EXCL, dmdi.u.integrity.offset, NULL, NULL);
if (r < 0 && (dm_flags(DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
log_err(cd, _("Kernel doesn't support dm-integrity mapping.\n"));
log_err(cd, _("Kernel doesn't support dm-integrity mapping."));
return -ENOTSUP;
}
if (r)

View File

@@ -30,7 +30,11 @@ struct volume_key;
/* dm-integrity helper */
#define SB_MAGIC "integrt"
#define SB_VERSION 1
#define SB_VERSION_1 1
#define SB_VERSION_2 2
#define SB_FLAG_HAVE_JOURNAL_MAC (1 << 0)
#define SB_FLAG_RECALCULATING (1 << 1) /* V2 only */
struct superblock {
uint8_t magic[8];
@@ -41,6 +45,8 @@ 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 */
} __attribute__ ((packed));
int INTEGRITY_read_sb(struct crypt_device *cd, struct crypt_params_integrity *params);
@@ -50,7 +56,8 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
int INTEGRITY_data_sectors(struct crypt_device *cd,
struct device *device, uint64_t offset,
uint64_t *data_sectors);
int INTEGRITY_key_size(struct crypt_device *cd);
int INTEGRITY_key_size(struct crypt_device *cd,
const char *integrity);
int INTEGRITY_tag_size(struct crypt_device *cd,
const char *integrity,
const char *cipher,

View File

@@ -32,11 +32,13 @@
#include "nls.h"
#include "bitops.h"
#include "utils_blkid.h"
#include "utils_crypt.h"
#include "utils_loop.h"
#include "utils_dm.h"
#include "utils_fips.h"
#include "utils_keyring.h"
#include "utils_io.h"
#include "crypto_backend.h"
#include "libcryptsetup.h"
@@ -44,15 +46,25 @@
/* to silent gcc -Wcast-qual for const cast */
#define CONST_CAST(x) (x)(uintptr_t)
#define SHIFT_4K 12
#define SECTOR_SHIFT 9
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
#define MAX_SECTOR_SIZE 4096 /* min page size among all platforms */
#define DEFAULT_DISK_ALIGNMENT 1048576 /* 1MiB */
#define DEFAULT_MEM_ALIGNMENT 4096
#define MAX_ERROR_LENGTH 512
#define LOG_MAX_LEN 4096
#define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); })
#define MISALIGNED(a, b) ((a) & ((b) - 1))
#define MISALIGNED_4K(a) MISALIGNED((a), 1 << SHIFT_4K)
#define MISALIGNED_512(a) MISALIGNED((a), 1 << SECTOR_SHIFT)
#define NOTPOW2(a) MISALIGNED((a), (a))
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
struct crypt_device;
struct volume_key {
@@ -98,6 +110,7 @@ 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 device *device, int devfd);
int device_open_locked(struct device *device, int flags);
int device_read_lock(struct crypt_device *cd, struct device *device);
@@ -132,20 +145,13 @@ 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);
ssize_t write_buffer(int fd, const void *buf, size_t count);
ssize_t read_buffer(int fd, void *buf, size_t count);
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment, void *orig_buf, size_t count);
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count);
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count, off_t offset);
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count, off_t offset);
size_t crypt_getpagesize(void);
unsigned crypt_cpusonline(void);
uint64_t crypt_getphysmemory_kb(void);
int init_crypto(struct crypt_device *ctx);
void logger(struct crypt_device *cd, int class, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
void logger(struct crypt_device *cd, int level, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
#define log_dbg(x...) logger(NULL, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
#define log_std(c, x...) logger(c, CRYPT_LOG_NORMAL, __FILE__, __LINE__, x)
#define log_verbose(c, x...) logger(c, CRYPT_LOG_VERBOSE, __FILE__, __LINE__, x)

View File

@@ -247,7 +247,18 @@ int crypt_set_pbkdf_type(struct crypt_device *cd,
const struct crypt_pbkdf_type *pbkdf);
/**
* Get current default PBKDF (Password-Based Key Derivation Algorithm) for keyslots.
* Get default PBKDF (Password-Based Key Derivation Algorithm) settings for keyslots.
* Works only with LUKS device handles (both versions).
*
* @param type type of device (see @link crypt-type @endlink)
*
* @return struct on success or NULL value otherwise.
*
*/
const struct crypt_pbkdf_type *crypt_get_pbkdf_default(const char *type);
/**
* Get current PBKDF (Password-Based Key Derivation Algorithm) settings for keyslots.
* Works only with LUKS device handles (both versions).
*
* @param cd crypt device handle
@@ -357,7 +368,7 @@ struct crypt_params_plain {
*/
struct crypt_params_luks1 {
const char *hash; /**< hash used in LUKS header */
size_t data_alignment; /**< data alignment in sectors, data offset is multiple of this */
size_t data_alignment; /**< data area alignment in 512B sectors, data offset is multiple of this */
const char *data_device; /**< detached encrypted data device or @e NULL */
};
@@ -479,7 +490,7 @@ struct crypt_params_luks2 {
const struct crypt_pbkdf_type *pbkdf; /**< PBKDF (and hash) parameters or @e NULL*/
const char *integrity; /**< integrity algorithm or @e NULL */
const struct crypt_params_integrity *integrity_params; /**< Data integrity parameters or @e NULL*/
size_t data_alignment; /**< data alignment in sectors, data offset is multiple of this */
size_t data_alignment; /**< data area alignment in 512B sectors, data offset is multiple of this */
const char *data_device; /**< detached encrypted data device or @e NULL */
uint32_t sector_size; /**< encryption sector size */
const char *label; /**< header label or @e NULL*/
@@ -535,8 +546,8 @@ int crypt_format(struct crypt_device *cd,
*
* @note Currently, only LUKS1->LUKS2 and LUKS2->LUKS1 conversions are supported.
* Not all LUKS2 devices may be converted back to LUKS1. To make such a conversion
* posible all active LUKS2 keyslots must be in LUKS1 compatible mode (i.e. pbkdf
* type must be PBKDF2) and device cannot be formated with any authenticated
* possible all active LUKS2 keyslots must be in LUKS1 compatible mode (i.e. pbkdf
* type must be PBKDF2) and device cannot be formatted with any authenticated
* encryption mode.
*
* @note Device must be offline for conversion. UUID change is not possible for active
@@ -613,7 +624,7 @@ int crypt_load(struct crypt_device *cd,
void *params);
/**
* Try to repair crypt device LUKS1 on-disk header if invalid.
* Try to repair crypt device LUKS on-disk header if invalid.
*
* @param cd crypt device handle
* @param requested_type @link crypt-type @endlink or @e NULL for all known
@@ -621,9 +632,11 @@ int crypt_load(struct crypt_device *cd,
*
* @returns 0 on success or negative errno value otherwise.
*
* @note Does not support LUKS2 devices explicitly. LUKS2 header is auto-repaired
* (if exactly one header checksum does not match) automatically on
* crypt_load().
* @note For LUKS2 device crypt_repair bypass blkid checks and
* perform auto-recovery even though there're third party device
* signatures found by blkid probes. Currently the crypt_repair on LUKS2
* works only if exactly one header checksum does not match or exactly
* one header is missing.
*/
int crypt_repair(struct crypt_device *cd,
const char *requested_type,
@@ -851,6 +864,9 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
/** create keyslot with volume key not associated with current dm-crypt segment */
#define CRYPT_VOLUME_KEY_NO_SEGMENT (1 << 0)
/** create keyslot with new volume key and assign it to current dm-crypt segment */
#define CRYPT_VOLUME_KEY_SET (1 << 1)
/**
* Add key slot using provided key.
*
@@ -867,10 +883,18 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
* @return allocated key slot number or negative errno otherwise.
*
* @note in case volume_key is @e NULL following first matching rule will apply:
* a) if cd is device handle used in crypt_format() by current process, the volume
* key generated (passed) to crypt_format() will be stored in keyslot.
* b) if CRYPT_VOLUME_KEY_NO_SEGMENT flag is raised the new volume_key will be
* generated and stored in keyslot.
* @li if cd is device handle used in crypt_format() by current process, the volume
* key generated (or passed) in crypt_format() will be stored in keyslot.
* @li if CRYPT_VOLUME_KEY_NO_SEGMENT flag is raised the new volume_key will be
* generated and stored in keyslot. The keyslot will become unbound (unusable to
* dm-crypt device activation).
* @li fails with -EINVAL otherwise
*
* @warning CRYPT_VOLUME_KEY_SET flag force updates volume key. It is @b not @b reencryption!
* By doing so you will most probably destroy your ciphertext data device. It's supposed
* to be used only in wrapped keys scheme for key refresh process where real (inner) volume
* key stays untouched. It may be involed on active @e keyslot which makes the (previously
* unbound) keyslot new regular keyslot.
*/
int crypt_keyslot_add_by_key(struct crypt_device *cd,
int keyslot,
@@ -932,6 +956,10 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
#define CRYPT_ACTIVATE_RECOVERY (1 << 13)
/** ignore persistently stored flags */
#define CRYPT_ACTIVATE_IGNORE_PERSISTENT (1 << 14)
/** dm-verity: check_at_most_once - check data blocks only the first time */
#define CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE (1 << 15)
/** allow activation check including unbound keyslots (keyslots without segments) */
#define CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY (1 << 16)
/**
* Active device runtime attributes
@@ -954,8 +982,20 @@ struct crypt_active_device {
*
*/
int crypt_get_active_device(struct crypt_device *cd,
const char *name,
struct crypt_active_device *cad);
const char *name,
struct crypt_active_device *cad);
/**
* Get detected number of integrity failures.
*
* @param cd crypt device handle (can be @e NULL)
* @param name name of active device
*
* @return number of integrity failures or @e 0 otherwise
*
*/
uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd,
const char *name);
/** @} */
/**
@@ -996,7 +1036,7 @@ typedef enum {
* stored persistently.
*
* @note Only requirements flags recognised by current library may be set.
* CRYPT_REQUIREMENT_FLAG is illegal (output only) in set operation.
* CRYPT_REQUIREMENT_UNKNOWN is illegal (output only) in set operation.
*/
int crypt_persistent_flags_set(struct crypt_device *cd,
crypt_flags_type type,
@@ -1413,8 +1453,10 @@ typedef enum {
CRYPT_SLOT_INVALID, /**< invalid keyslot */
CRYPT_SLOT_INACTIVE, /**< keyslot is inactive (free) */
CRYPT_SLOT_ACTIVE, /**< keyslot is active (used) */
CRYPT_SLOT_ACTIVE_LAST /**< keylost is active (used)
CRYPT_SLOT_ACTIVE_LAST,/**< keylost is active (used)
* and last used at the same time */
CRYPT_SLOT_UNBOUND /**< keyslot is active and not bound
* to any crypt segment (LUKS2 only) */
} crypt_keyslot_info;
/**
@@ -1485,6 +1527,18 @@ int crypt_keyslot_area(struct crypt_device *cd,
uint64_t *offset,
uint64_t *length);
/**
* Get size (in bytes) of key for particular keyslot.
* Use for LUKS2 unbound keyslots, for other keyslots it is the same as @ref crypt_get_volume_key_size
*
* @param cd crypt device handle
* @param keyslot keyslot number
*
* @return volume key size or negative errno value otherwise.
*
*/
int crypt_keyslot_get_key_size(struct crypt_device *cd, int keyslot);
/**
* Get directory where mapped crypt devices are created
*
@@ -1562,17 +1616,20 @@ void crypt_set_debug_level(int level);
* @param keyfile keyfile to read
* @param key buffer for key
* @param key_size_read size of read key
* @param keyfile_offset keyfile offset
* @param keyfile_size_max maximal size of keyfile to read
* @param keyfile_offset key offset in keyfile
* @param key_size exact key length to read from file or 0
* @param flags keyfile read flags
*
* @return @e 0 on success or negative errno value otherwise.
*
* @note If key_size is set to zero we read internal max length
* and actual size read is returned via key_size_read parameter.
*/
int crypt_keyfile_device_read(struct crypt_device *cd,
const char *keyfile,
char **key, size_t *key_size_read,
uint64_t keyfile_offset,
size_t keyfile_size_max,
size_t key_size,
uint32_t flags);
/**
@@ -1582,7 +1639,7 @@ int crypt_keyfile_read(struct crypt_device *cd,
const char *keyfile,
char **key, size_t *key_size_read,
size_t keyfile_offset,
size_t keyfile_size_max,
size_t key_size,
uint32_t flags);
/** Read key only to the first end of line (\\n). */
@@ -1829,7 +1886,7 @@ typedef void (*crypt_token_buffer_free_func) (void *buffer, size_t buffer_len);
/**
* Token handler validate function prototype.
* This fuction validates JSON representation of user defined token for additional data
* This function validates JSON representation of user defined token for additional data
* specific for its token type. If defined in the handler, it's called
* during @link crypt_activate_by_token @endlink. It may also be called during
* @link crypt_token_json_set @endlink when appropriate token handler was registered before
@@ -1842,7 +1899,7 @@ typedef int (*crypt_token_validate_func) (struct crypt_device *cd, const char *j
/**
* Token handler dump function prototype.
* This fuction is supposed to print token implementation specific details. It gets
* This function is supposed to print token implementation specific details. It gets
* called during @link crypt_dump @endlink if token handler was registered before.
*
* @param cd crypt device handle

View File

@@ -77,6 +77,7 @@ CRYPTSETUP_2.0 {
crypt_get_type;
crypt_get_active_device;
crypt_get_active_integrity_failures;
crypt_persistent_flags_set;
crypt_persistent_flags_get;
@@ -84,10 +85,12 @@ CRYPTSETUP_2.0 {
crypt_get_rng_type;
crypt_set_pbkdf_type;
crypt_get_pbkdf_type;
crypt_get_pbkdf_default;
crypt_keyslot_max;
crypt_keyslot_area;
crypt_keyslot_status;
crypt_keyslot_get_key_size;
crypt_get_dir;
crypt_set_debug_level;
crypt_log;

View File

@@ -96,7 +96,6 @@ static void set_dm_error(int level,
if (vasprintf(&msg, f, va) > 0) {
if (level < 4 && !_quiet_log) {
log_err(_context, "%s", msg);
log_err(_context, "\n");
} else {
/* We do not use DM visual stack backtrace here */
if (strncmp(msg, "<backtrace>", 11))
@@ -185,6 +184,7 @@ static void _dm_set_verity_compat(unsigned verity_maj,
* ignore_zero_blocks since 1.3 (kernel 4.5)
* (but some dm-verity targets 1.2 don't support it)
* FEC is added in 1.3 as well.
* Check at most once is added in 1.4 (kernel 4.17).
*/
if (_dm_satisfies_version(1, 3, 0, verity_maj, verity_min, verity_patch)) {
_dm_flags |= DM_VERITY_ON_CORRUPTION_SUPPORTED;
@@ -329,10 +329,10 @@ static int dm_init_context(struct crypt_device *cd, dm_target_type target)
if (!_dm_check_versions(target)) {
if (getuid() || geteuid())
log_err(cd, _("Cannot initialize device-mapper, "
"running as non-root user.\n"));
"running as non-root user."));
else
log_err(cd, _("Cannot initialize device-mapper. "
"Is dm_mod kernel module loaded?\n"));
"Is dm_mod kernel module loaded?"));
_context = NULL;
return -ENOTSUP;
}
@@ -376,15 +376,12 @@ static void hex_key(char *hexkey, size_t key_size, const char *key)
sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]);
}
/* get string length for key_size written in decimal system */
static size_t get_key_size_strlen(size_t key_size)
static size_t int_log10(size_t x)
{
size_t ret = 1;
while ((key_size /= 10))
ret++;
return ret;
size_t r = 0;
for (x /= 10; x > 0; x /= 10)
r++;
return r;
}
#define CLEN 64 /* 2*MAX_CIPHER_LEN */
@@ -397,7 +394,7 @@ static int cipher_c2dm(const char *org_c, const char *org_i, unsigned tag_size,
char *i_dm, int i_dm_size)
{
int c_size = 0, i_size = 0, i;
char cipher[CLEN], mode[CLEN], iv[CLEN], tmp[CLEN];
char cipher[CLEN], mode[CLEN], iv[CLEN+1], tmp[CLEN];
char capi[CAPIL];
if (!c_dm || !c_dm_size || !i_dm || !i_dm_size)
@@ -410,7 +407,7 @@ static int cipher_c2dm(const char *org_c, const char *org_i, unsigned tag_size,
i = sscanf(tmp, "%" CLENS "[^-]-%" CLENS "s", mode, iv);
if (i == 1) {
memset(iv, 0, sizeof(iv));
strncpy(iv, mode, sizeof(iv) - 1);
strncpy(iv, mode, sizeof(iv)-1);
*mode = '\0';
if (snprintf(capi, sizeof(capi), "%s", cipher) < 0)
return -EINVAL;
@@ -457,7 +454,7 @@ static int cipher_c2dm(const char *org_c, const char *org_i, unsigned tag_size,
static int cipher_dm2c(char **org_c, char **org_i, const char *c_dm, const char *i_dm)
{
char cipher[CLEN], mode[CLEN], iv[CLEN], auth[CLEN];
char tmp[CAPIL*2], capi[CAPIL];
char tmp[CAPIL], dmcrypt_tmp[CAPIL*2], capi[CAPIL+1];
size_t len;
int i;
@@ -500,16 +497,16 @@ static int cipher_dm2c(char **org_c, char **org_i, const char *c_dm, const char
} else
*org_i = NULL;
memset(capi, 0, sizeof(capi));
strncpy(capi, tmp, sizeof(capi) - 1);
strncpy(capi, tmp, sizeof(capi)-1);
}
i = sscanf(capi, "%" CLENS "[^(](%" CLENS "[^)])", mode, cipher);
if (i == 2)
snprintf(tmp, sizeof(tmp), "%s-%s-%s", cipher, mode, iv);
snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s-%s", cipher, mode, iv);
else
snprintf(tmp, sizeof(tmp), "%s-%s", capi, iv);
snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s", capi, iv);
if (!(*org_c = strdup(tmp))) {
if (!(*org_c = strdup(dmcrypt_tmp))) {
free(*org_i);
*org_i = NULL;
return -ENOMEM;
@@ -561,7 +558,7 @@ static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd, uint32_t fl
null_cipher = 1;
if (flags & CRYPT_ACTIVATE_KEYRING_KEY) {
keystr_len = strlen(dmd->u.crypt.vk->key_description) + get_key_size_strlen(dmd->u.crypt.vk->keylength) + 9;
keystr_len = strlen(dmd->u.crypt.vk->key_description) + int_log10(dmd->u.crypt.vk->keylength) + 10;
hexkey = crypt_safe_alloc(keystr_len);
} else
hexkey = crypt_safe_alloc(null_cipher ? 2 : (dmd->u.crypt.vk->keylength * 2 + 1));
@@ -622,6 +619,8 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp,
num_options++;
if (flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS)
num_options++;
if (flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE)
num_options++;
if (dmd->u.verity.fec_device) {
num_options += 8;
@@ -633,10 +632,11 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp,
*fec_features = '\0';
if (num_options)
snprintf(features, sizeof(features)-1, " %d%s%s%s", num_options,
snprintf(features, sizeof(features)-1, " %d%s%s%s%s", num_options,
(flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? " ignore_corruption" : "",
(flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) ? " restart_on_corruption" : "",
(flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? " ignore_zero_blocks" : "");
(flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? " ignore_zero_blocks" : "",
(flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) ? " check_at_most_once" : "");
else
*features = '\0';
@@ -684,7 +684,7 @@ static char *get_dm_integrity_params(struct crypt_dm_active_device *dmd, uint32_
{
int r, max_size, num_options = 0;
char *params, *hexkey, mode;
char features[256], feature[256];
char features[512], feature[256];
if (!dmd)
return NULL;
@@ -932,7 +932,7 @@ int dm_remove_device(struct crypt_device *cd, const char *name, uint32_t flags)
dm_flags(DM_UNKNOWN, &dmt_flags);
if (deferred && !(dmt_flags & DM_DEFERRED_SUPPORTED)) {
log_err(cd, _("Requested deferred flag is not supported.\n"));
log_err(cd, _("Requested deferred flag is not supported."));
return -ENOTSUP;
}
@@ -997,7 +997,7 @@ static int dm_prepare_uuid(const char *name, const char *type, const char *uuid,
log_dbg("DM-UUID is %s", buf);
if (i >= buflen)
log_err(NULL, _("DM-UUID for device %s was truncated.\n"), name);
log_err(NULL, _("DM-UUID for device %s was truncated."), name);
return 1;
}
@@ -1217,23 +1217,24 @@ int dm_create_device(struct crypt_device *cd, const char *name,
if (r == -EINVAL &&
dmd_flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT|CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) &&
!(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED|DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED)))
log_err(cd, _("Requested dm-crypt performance options are not supported.\n"));
log_err(cd, _("Requested dm-crypt performance options are not supported."));
if (r == -EINVAL && dmd_flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION|
CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|
CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) &&
CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS|
CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) &&
!(dmt_flags & DM_VERITY_ON_CORRUPTION_SUPPORTED))
log_err(cd, _("Requested dm-verity data corruption handling options are not supported.\n"));
log_err(cd, _("Requested dm-verity data corruption handling options are not supported."));
if (r == -EINVAL && dmd->target == DM_VERITY && dmd->u.verity.fec_device &&
!(dmt_flags & DM_VERITY_FEC_SUPPORTED))
log_err(cd, _("Requested dm-verity FEC options are not supported.\n"));
log_err(cd, _("Requested dm-verity FEC options are not supported."));
if (r == -EINVAL && dmd->target == DM_CRYPT) {
if (dmd->u.crypt.integrity && !(dmt_flags & DM_INTEGRITY_SUPPORTED))
log_err(cd, _("Requested data integrity options are not supported.\n"));
log_err(cd, _("Requested data integrity options are not supported."));
if (dmd->u.crypt.sector_size != SECTOR_SIZE && !(dmt_flags & DM_SECTOR_SIZE_SUPPORTED))
log_err(cd, _("Requested sector_size option is not supported.\n"));
log_err(cd, _("Requested sector_size option is not supported."));
}
out:
crypt_safe_free(table_params);
@@ -1360,6 +1361,29 @@ int dm_status_verity_ok(struct crypt_device *cd, const char *name)
return r;
}
int dm_status_integrity_failures(struct crypt_device *cd, const char *name, uint64_t *count)
{
int r;
struct dm_info dmi;
char *status_line = NULL;
if (dm_init_context(cd, DM_INTEGRITY))
return -ENOTSUP;
r = dm_status_dmi(name, &dmi, DM_INTEGRITY_TARGET, &status_line);
if (r < 0 || !status_line) {
free(status_line);
return r;
}
log_dbg("Integrity volume %s failure status is %s.", name, status_line ?: "");
*count = strtoull(status_line, NULL, 10);
free(status_line);
dm_exit_context();
return 0;
}
/* FIXME use hex wrapper, user val wrappers for line parsing */
static int _dm_query_crypt(uint32_t get_flags,
struct dm_info *dmi,
@@ -1490,11 +1514,16 @@ static int _dm_query_crypt(uint32_t get_flags,
if (get_flags & DM_ACTIVE_CRYPT_KEY) {
if (key_[0] == ':') {
key_desc = strpbrk(strpbrk(key_ + 1, ":") + 1, ":") + 1;
/* :<key_size>:<key_type>:<key_description> */
key_desc = NULL;
endp = strpbrk(key_ + 1, ":");
if (endp)
key_desc = strpbrk(endp + 1, ":");
if (!key_desc) {
r = -ENOMEM;
goto err;
}
key_desc++;
crypt_volume_key_set_description(vk, key_desc);
} else {
buffer[2] = '\0';
@@ -1684,6 +1713,8 @@ static int _dm_query_verity(uint32_t get_flags,
dmd->flags |= CRYPT_ACTIVATE_RESTART_ON_CORRUPTION;
else if (!strcasecmp(arg, "ignore_zero_blocks"))
dmd->flags |= CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS;
else if (!strcasecmp(arg, "check_at_most_once"))
dmd->flags |= CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE;
else if (!strcasecmp(arg, "use_fec_from_device")) {
str = strsep(&params, " ");
str2 = crypt_lookup_dev(str);
@@ -1694,9 +1725,10 @@ static int _dm_query_verity(uint32_t get_flags,
goto err;
}
}
if (vp)
if (vp) {
free(fec_dev_str);
fec_dev_str = str2;
else
} else
free(str2);
i++;
} else if (!strcasecmp(arg, "fec_start")) {
@@ -2037,6 +2069,23 @@ 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, 0))
r = -EINVAL;
else
r = 0;
dm_exit_context();
return r;
}
int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name)
{
uint32_t dmt_flags;
@@ -2079,7 +2128,7 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
goto out;
if (vk->key_description)
msg_size = strlen(vk->key_description) + get_key_size_strlen(vk->keylength) + 17;
msg_size = strlen(vk->key_description) + int_log10(vk->keylength) + 18;
else
msg_size = vk->keylength * 2 + 10; // key set <key>

View File

@@ -87,7 +87,7 @@ static int hash_keys(struct crypt_device *cd,
tweak = get_tweak(keys_count);
if (!keys_count || !key_len_output || !hash_name || !key_len_input) {
log_err(cd, _("Key processing error (using hash %s).\n"),
log_err(cd, _("Key processing error (using hash %s)."),
hash_name ?: "[none]");
return -EINVAL;
}
@@ -165,7 +165,7 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
}
if (offset == buffer_len) {
log_dbg("Unterminated key #%d in keyfile.", key_index);
log_err(cd, _("Incompatible loop-AES keyfile detected.\n"));
log_err(cd, _("Incompatible loop-AES keyfile detected."));
return -EINVAL;
}
while (offset < buffer_len && !buffer[offset])
@@ -185,7 +185,7 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
if (offset != buffer_len || key_len == 0 ||
(key_index != 1 && key_index !=64 && key_index != 65)) {
log_err(cd, _("Incompatible loop-AES keyfile detected.\n"));
log_err(cd, _("Incompatible loop-AES keyfile detected."));
return -EINVAL;
}
@@ -243,7 +243,7 @@ int LOOPAES_activate(struct crypt_device *cd,
if (r < 0 && !dm_flags(DM_CRYPT, &dmc_flags) &&
(dmc_flags & req_flags) != req_flags) {
log_err(cd, _("Kernel doesn't support loop-AES compatible mapping.\n"));
log_err(cd, _("Kernel doesn't support loop-AES compatible mapping."));
r = -ENOTSUP;
}

View File

@@ -22,6 +22,7 @@
#ifndef _LOOPAES_H
#define _LOOPAES_H
#include <stdint.h>
#include <unistd.h>
struct crypt_device;

View File

@@ -5,7 +5,7 @@
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefor supporting secure data destruction.
* therefore supporting secure data destruction.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -5,7 +5,7 @@
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefor supporting secure data destruction.
* therefore supporting secure data destruction.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,6 +24,8 @@
#ifndef INCLUDED_CRYPTSETUP_LUKS_AF_H
#define INCLUDED_CRYPTSETUP_LUKS_AF_H
#include <stddef.h>
/*
* AF_split operates on src and produces information split data in
* dst. src is assumed to be of the length blocksize. The data stripe

View File

@@ -24,6 +24,7 @@
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include "luks.h"
#include "af.h"
#include "internal.h"
@@ -37,13 +38,13 @@ static void _error_hint(struct crypt_device *ctx, const char *device,
return;
log_err(ctx, _("Failed to setup dm-crypt key mapping for device %s.\n"
"Check that kernel supports %s cipher (check syslog for more info).\n"),
"Check that kernel supports %s cipher (check syslog for more info)."),
device, cipher_spec);
if (!strncmp(mode, "xts", 3) && (keyLength != 256 && keyLength != 512))
log_err(ctx, _("Key size in XTS mode must be 256 or 512 bits.\n"));
log_err(ctx, _("Key size in XTS mode must be 256 or 512 bits."));
else if (!(c = strchr(mode, '-')) || strlen(c) < 4)
log_err(ctx, _("Cipher specification should be in [cipher]-[mode]-[iv] format.\n"));
log_err(ctx, _("Cipher specification should be in [cipher]-[mode]-[iv] format."));
}
static int LUKS_endec_template(char *src, size_t srcLength,
@@ -98,13 +99,13 @@ static int LUKS_endec_template(char *src, size_t srcLength,
r = device_block_adjust(ctx, dmd.data_device, DEV_OK,
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
if (r < 0) {
log_err(ctx, _("Device %s doesn't exist or access denied.\n"),
log_err(ctx, _("Device %s doesn't exist or access denied."),
device_path(dmd.data_device));
return -EIO;
}
if (mode != O_RDONLY && dmd.flags & CRYPT_ACTIVATE_READONLY) {
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
log_err(ctx, _("Cannot write to device %s, permission denied."),
device_path(dmd.data_device));
return -EACCES;
}
@@ -119,14 +120,14 @@ static int LUKS_endec_template(char *src, size_t srcLength,
devfd = open(path, mode | O_DIRECT | O_SYNC);
if (devfd == -1) {
log_err(ctx, _("Failed to open temporary keystore device.\n"));
log_err(ctx, _("Failed to open temporary keystore device."));
r = -EIO;
goto out;
}
r = func(devfd, bsize, alignment, src, srcLength);
if (r < 0) {
log_err(ctx, _("Failed to access temporary keystore device.\n"));
log_err(ctx, _("Failed to access temporary keystore device."));
r = -EIO;
} else
r = 0;
@@ -150,7 +151,7 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
int devfd = -1, r = 0;
/* Only whole sector writes supported */
if (srcLength % SECTOR_SIZE)
if (MISALIGNED_512(srcLength))
return -EINVAL;
/* Encrypt buffer */
@@ -193,10 +194,12 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
r = 0;
out:
if (devfd >= 0)
if (devfd >= 0) {
device_sync(device, devfd);
close(devfd);
}
if (r)
log_err(ctx, _("IO error while encrypting keyslot.\n"));
log_err(ctx, _("IO error while encrypting keyslot."));
return r;
}
@@ -210,10 +213,11 @@ 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;
/* Only whole sector reads supported */
if (dstLength % SECTOR_SIZE)
if (MISALIGNED_512(dstLength))
return -EINVAL;
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
@@ -235,17 +239,26 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
log_dbg("Using userspace crypto wrapper to access keyslot area.");
r = -EIO;
/* Read buffer from device */
devfd = device_open(device, O_RDONLY);
if (devfd < 0)
goto bad;
if (devfd < 0) {
log_err(ctx, _("Cannot open device %s."), device_path(device));
crypt_storage_destroy(s);
return -EIO;
}
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), dst, dstLength,
sector * SECTOR_SIZE) < 0)
goto bad;
sector * SECTOR_SIZE) < 0) {
if (!fstat(devfd, &st) && (st.st_size < (off_t)dstLength))
log_err(ctx, _("Device %s is too small."), device_path(device));
else
log_err(ctx, _("IO error while decrypting keyslot."));
close(devfd);
crypt_storage_destroy(s);
return -EIO;
}
close(devfd);
@@ -253,13 +266,5 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
crypt_storage_destroy(s);
return r;
bad:
if (devfd >= 0)
close(devfd);
log_err(ctx, _("IO error while decrypting keyslot.\n"));
crypt_storage_destroy(s);
return r;
}

View File

@@ -125,7 +125,7 @@ static int LUKS_check_device_size(struct crypt_device *ctx, const struct luks_ph
if (falloc && !device_fallocate(device, hdr_sectors << SECTOR_SHIFT))
return 0;
log_err(ctx, _("Device %s is too small. (LUKS1 requires at least %" PRIu64 " bytes.)\n"),
log_err(ctx, _("Device %s is too small. (LUKS1 requires at least %" PRIu64 " bytes.)"),
device_path(device), hdr_sectors * SECTOR_SIZE);
return -EINVAL;
}
@@ -146,7 +146,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
if (phdr->keyblock[i].stripes != LUKS_STRIPES) {
log_dbg("Invalid stripes count %u in keyslot %u.",
phdr->keyblock[i].stripes, i);
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
return -1;
}
@@ -154,7 +154,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
if (phdr->keyblock[i].keyMaterialOffset * SECTOR_SIZE < sizeof(*phdr)) {
log_dbg("Invalid offset %u in keyslot %u.",
phdr->keyblock[i].keyMaterialOffset, i);
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
return -1;
}
@@ -166,7 +166,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
log_dbg("Invalid offset %u in keyslot %u (beyond data area offset %u).",
phdr->keyblock[i].keyMaterialOffset, i,
phdr->payloadOffset);
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
return -1;
}
@@ -177,7 +177,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
phdr->keyblock[i].keyMaterialOffset,
phdr->keyblock[i].stripes,
i, phdr->payloadOffset);
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
return -1;
}
}
@@ -189,7 +189,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
if (phdr->keyblock[next].keyMaterialOffset <
(phdr->keyblock[prev].keyMaterialOffset + secs_per_stripes)) {
log_dbg("Not enough space in LUKS keyslot %d.", prev);
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), prev);
log_err(ctx, _("LUKS keyslot %u is invalid."), prev);
return -1;
}
}
@@ -242,7 +242,7 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
devfd = device_open(device, O_RDONLY);
if (devfd < 0) {
log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device_path(device));
log_err(ctx, _("Device %s is not a valid LUKS device."), device_path(device));
r = -EINVAL;
goto out;
}
@@ -261,14 +261,14 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
if (devfd == -1) {
if (errno == EEXIST)
log_err(ctx, _("Requested header backup file %s already exists.\n"), backup_file);
log_err(ctx, _("Requested header backup file %s already exists."), backup_file);
else
log_err(ctx, _("Cannot create header backup file %s.\n"), backup_file);
log_err(ctx, _("Cannot create header backup file %s."), backup_file);
r = -EINVAL;
goto out;
}
if (write_buffer(devfd, buffer, buffer_size) < (ssize_t)buffer_size) {
log_err(ctx, _("Cannot write header backup file %s.\n"), backup_file);
log_err(ctx, _("Cannot write header backup file %s."), backup_file);
r = -EIO;
goto out;
}
@@ -301,7 +301,7 @@ int LUKS_hdr_restore(
buffer_size = LUKS_device_sectors(&hdr_file) << SECTOR_SHIFT;
if (r || buffer_size < LUKS_ALIGN_KEYSLOTS) {
log_err(ctx, _("Backup file doesn't contain valid LUKS header.\n"));
log_err(ctx, _("Backup file doesn't contain valid LUKS header."));
r = -EINVAL;
goto out;
}
@@ -314,13 +314,13 @@ int LUKS_hdr_restore(
devfd = open(backup_file, O_RDONLY);
if (devfd == -1) {
log_err(ctx, _("Cannot open header backup file %s.\n"), backup_file);
log_err(ctx, _("Cannot open header backup file %s."), backup_file);
r = -EINVAL;
goto out;
}
if (read_buffer(devfd, buffer, buffer_size) < buffer_size) {
log_err(ctx, _("Cannot read header backup file %s.\n"), backup_file);
log_err(ctx, _("Cannot read header backup file %s."), backup_file);
r = -EIO;
goto out;
}
@@ -332,7 +332,7 @@ int LUKS_hdr_restore(
log_dbg("Device %s already contains LUKS header, checking UUID and offset.", device_path(device));
if(hdr->payloadOffset != hdr_file.payloadOffset ||
hdr->keyBytes != hdr_file.keyBytes) {
log_err(ctx, _("Data offset or key size differs on device and backup, restore failed.\n"));
log_err(ctx, _("Data offset or key size differs on device and backup, restore failed."));
r = -EINVAL;
goto out;
}
@@ -359,10 +359,10 @@ int LUKS_hdr_restore(
devfd = device_open(device, O_RDWR);
if (devfd < 0) {
if (errno == EACCES)
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
log_err(ctx, _("Cannot write to device %s, permission denied."),
device_path(device));
else
log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
log_err(ctx, _("Cannot open device %s."), device_path(device));
r = -EINVAL;
goto out;
}
@@ -378,8 +378,10 @@ int LUKS_hdr_restore(
/* Be sure to reload new data */
r = LUKS_read_phdr(hdr, 1, 0, ctx);
out:
if (devfd >= 0)
if (devfd >= 0) {
device_sync(device, devfd);
close(devfd);
}
crypt_safe_free(buffer);
return r;
}
@@ -393,18 +395,22 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
int i, bad, r, need_write = 0;
if (phdr->keyBytes != 16 && phdr->keyBytes != 32 && phdr->keyBytes != 64) {
log_err(ctx, _("Non standard key size, manual repair required.\n"));
log_err(ctx, _("Non standard key size, manual repair required."));
return -EINVAL;
}
/* cryptsetup 1.0 did not align to 4k, cannot repair this one */
if (LUKS_keyslots_offset(phdr) < (LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE)) {
log_err(ctx, _("Non standard keyslots alignment, manual repair required.\n"));
log_err(ctx, _("Non standard keyslots alignment, manual repair required."));
return -EINVAL;
}
r = LUKS_check_cipher(ctx, phdr->keyBytes, phdr->cipherName, phdr->cipherMode);
if (r < 0)
return -EINVAL;
vk = crypt_alloc_volume_key(phdr->keyBytes, NULL);
log_verbose(ctx, _("Repairing keyslots.\n"));
log_verbose(ctx, _("Repairing keyslots."));
log_dbg("Generating second header with the same parameters for check.");
/* cipherName, cipherMode, hashSpec, uuid are already null terminated */
@@ -424,7 +430,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
bad = 0;
if (phdr->keyblock[i].keyMaterialOffset != temp_phdr.keyblock[i].keyMaterialOffset) {
log_err(ctx, _("Keyslot %i: offset repaired (%u -> %u).\n"), i,
log_err(ctx, _("Keyslot %i: offset repaired (%u -> %u)."), i,
(unsigned)phdr->keyblock[i].keyMaterialOffset,
(unsigned)temp_phdr.keyblock[i].keyMaterialOffset);
phdr->keyblock[i].keyMaterialOffset = temp_phdr.keyblock[i].keyMaterialOffset;
@@ -432,7 +438,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
}
if (phdr->keyblock[i].stripes != temp_phdr.keyblock[i].stripes) {
log_err(ctx, _("Keyslot %i: stripes repaired (%u -> %u).\n"), i,
log_err(ctx, _("Keyslot %i: stripes repaired (%u -> %u)."), i,
(unsigned)phdr->keyblock[i].stripes,
(unsigned)temp_phdr.keyblock[i].stripes);
phdr->keyblock[i].stripes = temp_phdr.keyblock[i].stripes;
@@ -441,12 +447,12 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
/* Known case - MSDOS partition table signature */
if (i == 6 && sector[0x1fe] == 0x55 && sector[0x1ff] == 0xaa) {
log_err(ctx, _("Keyslot %i: bogus partition signature.\n"), i);
log_err(ctx, _("Keyslot %i: bogus partition signature."), i);
bad = 1;
}
if(bad) {
log_err(ctx, _("Keyslot %i: salt wiped.\n"), i);
log_err(ctx, _("Keyslot %i: salt wiped."), i);
phdr->keyblock[i].active = LUKS_KEY_DISABLED;
memset(&phdr->keyblock[i].passwordSalt, 0x00, LUKS_SALTSIZE);
phdr->keyblock[i].passwordIterations = 0;
@@ -463,12 +469,12 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
if (LUKS_check_keyslots(ctx, phdr))
r = -EINVAL;
else if (need_write) {
log_verbose(ctx, _("Writing LUKS header to disk.\n"));
log_verbose(ctx, _("Writing LUKS header to disk."));
r = LUKS_write_phdr(phdr, ctx);
}
out:
if (r)
log_err(ctx, _("Repair failed.\n"));
log_err(ctx, _("Repair failed."));
crypt_free_volume_key(vk);
crypt_memzero(&temp_phdr, sizeof(temp_phdr));
return r;
@@ -487,16 +493,16 @@ static int _check_and_convert_hdr(const char *device,
if(memcmp(hdr->magic, luksMagic, LUKS_MAGIC_L)) { /* Check magic */
log_dbg("LUKS header not detected.");
if (require_luks_device)
log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device);
log_err(ctx, _("Device %s is not a valid LUKS device."), device);
return -EINVAL;
} else if((hdr->version = ntohs(hdr->version)) != 1) { /* Convert every uint16/32_t item from network byte order */
log_err(ctx, _("Unsupported LUKS version %d.\n"), hdr->version);
log_err(ctx, _("Unsupported LUKS version %d."), hdr->version);
return -EINVAL;
}
hdr->hashSpec[LUKS_HASHSPEC_L - 1] = '\0';
if (crypt_hmac_size(hdr->hashSpec) < LUKS_DIGESTSIZE) {
log_err(ctx, _("Requested LUKS hash %s is not supported.\n"), hdr->hashSpec);
log_err(ctx, _("Requested LUKS hash %s is not supported."), hdr->hashSpec);
return -EINVAL;
}
@@ -524,7 +530,7 @@ static int _check_and_convert_hdr(const char *device,
if (r == -EINVAL)
r = _keyslot_repair(hdr, ctx);
else
log_verbose(ctx, _("No known problems detected for LUKS header.\n"));
log_verbose(ctx, _("No known problems detected for LUKS header."));
}
return r;
@@ -564,7 +570,7 @@ int LUKS_read_phdr_backup(const char *backup_file,
devfd = open(backup_file, O_RDONLY);
if (devfd == -1) {
log_err(ctx, _("Cannot open header backup file %s.\n"), backup_file);
log_err(ctx, _("Cannot open header backup file %s."), backup_file);
return -ENOENT;
}
@@ -603,7 +609,7 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
devfd = device_open(device, O_RDONLY);
if (devfd < 0) {
log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
log_err(ctx, _("Cannot open device %s."), device_path(device));
return -EINVAL;
}
@@ -651,10 +657,10 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
devfd = device_open(device, O_RDWR);
if (devfd < 0) {
if (errno == EACCES)
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
log_err(ctx, _("Cannot write to device %s, permission denied."),
device_path(device));
else
log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
log_err(ctx, _("Cannot open device %s."), device_path(device));
return -EINVAL;
}
@@ -676,14 +682,16 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
r = write_blockwise(devfd, device_block_size(device), device_alignment(device),
&convHdr, hdr_size) < hdr_size ? -EIO : 0;
if (r)
log_err(ctx, _("Error during update of LUKS header on device %s.\n"), device_path(device));
log_err(ctx, _("Error during update of LUKS header on device %s."), device_path(device));
device_sync(device, devfd);
close(devfd);
/* Re-read header from disk to be sure that in-memory and on-disk data are the same. */
if (!r) {
r = LUKS_read_phdr(hdr, 1, 0, ctx);
if (r)
log_err(ctx, _("Error re-reading LUKS header after update on device %s.\n"),
log_err(ctx, _("Error re-reading LUKS header after update on device %s."),
device_path(device));
}
@@ -691,23 +699,22 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
}
/* Check that kernel supports requested cipher by decryption of one sector */
static int LUKS_check_cipher(struct luks_phdr *hdr, struct crypt_device *ctx)
int LUKS_check_cipher(struct crypt_device *ctx, size_t keylength, const char *cipher, const char *cipher_mode)
{
int r;
struct volume_key *empty_key;
char buf[SECTOR_SIZE];
log_dbg("Checking if cipher %s-%s is usable.", hdr->cipherName, hdr->cipherMode);
log_dbg("Checking if cipher %s-%s is usable.", cipher, cipher_mode);
empty_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
empty_key = crypt_alloc_volume_key(keylength, NULL);
if (!empty_key)
return -ENOMEM;
/* No need to get KEY quality random but it must avoid known weak keys. */
r = crypt_random_get(ctx, empty_key->key, empty_key->keylength, CRYPT_RND_NORMAL);
if (!r)
r = LUKS_decrypt_from_storage(buf, sizeof(buf), hdr->cipherName,
hdr->cipherMode, empty_key, 0, ctx);
r = LUKS_decrypt_from_storage(buf, sizeof(buf), cipher, cipher_mode, empty_key, 0, ctx);
crypt_free_volume_key(empty_key);
crypt_memzero(buf, sizeof(buf));
@@ -737,18 +744,18 @@ int LUKS_generate_phdr(struct luks_phdr *header,
if (alignPayload && detached_metadata_device && alignPayload < hdr_sectors) {
log_err(ctx, _("Data offset for detached LUKS header must be "
"either 0 or higher than header size (%d sectors).\n"),
"either 0 or higher than header size (%d sectors)."),
hdr_sectors);
return -EINVAL;
}
if (crypt_hmac_size(hashSpec) < LUKS_DIGESTSIZE) {
log_err(ctx, _("Requested LUKS hash %s is not supported.\n"), hashSpec);
log_err(ctx, _("Requested LUKS hash %s is not supported."), hashSpec);
return -EINVAL;
}
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
log_err(ctx, _("Wrong LUKS UUID format provided.\n"));
log_err(ctx, _("Wrong LUKS UUID format provided."));
return -EINVAL;
}
if (!uuid)
@@ -767,17 +774,13 @@ int LUKS_generate_phdr(struct luks_phdr *header,
LUKS_fix_header_compatible(header);
r = LUKS_check_cipher(header, ctx);
if (r < 0)
return r;
log_dbg("Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes",
header->version, header->hashSpec ,header->cipherName, header->cipherMode,
header->keyBytes);
r = crypt_random_get(ctx, header->mkDigestSalt, LUKS_SALTSIZE, CRYPT_RND_SALT);
if(r < 0) {
log_err(ctx, _("Cannot create LUKS header: reading random salt failed.\n"));
log_err(ctx, _("Cannot create LUKS header: reading random salt failed."));
return r;
}
@@ -798,7 +801,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
header->mkDigest,LUKS_DIGESTSIZE,
header->mkDigestIterations, 0, 0);
if(r < 0) {
log_err(ctx, _("Cannot create LUKS header: header digest failed (using hash %s).\n"),
log_err(ctx, _("Cannot create LUKS header: header digest failed (using hash %s)."),
header->hashSpec);
return r;
}
@@ -838,7 +841,7 @@ int LUKS_hdr_uuid_set(
uuid_t partitionUuid;
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
log_err(ctx, _("Wrong LUKS UUID format provided.\n"));
log_err(ctx, _("Wrong LUKS UUID format provided."));
return -EINVAL;
}
if (!uuid)
@@ -861,13 +864,13 @@ int LUKS_set_key(unsigned int keyIndex,
int r;
if(hdr->keyblock[keyIndex].active != LUKS_KEY_DISABLED) {
log_err(ctx, _("Key slot %d active, purge first.\n"), keyIndex);
log_err(ctx, _("Key slot %d active, purge first."), keyIndex);
return -EINVAL;
}
/* LUKS keyslot has always at least 4000 stripes according to specification */
if(hdr->keyblock[keyIndex].stripes < 4000) {
log_err(ctx, _("Key slot %d material includes too few stripes. Header manipulation?\n"),
log_err(ctx, _("Key slot %d material includes too few stripes. Header manipulation?"),
keyIndex);
return -EINVAL;
}
@@ -1024,9 +1027,6 @@ static int LUKS_open_key(unsigned int keyIndex,
/* Allow only empty passphrase with null cipher */
if (!r && !strcmp(hdr->cipherName, "cipher_null") && passwordLen)
r = -EPERM;
if (!r)
log_verbose(ctx, _("Key slot %d unlocked.\n"), keyIndex);
out:
crypt_safe_free(AfKey);
crypt_free_volume_key(derived_key);
@@ -1061,7 +1061,6 @@ int LUKS_open_key_with_hdr(int keyIndex,
return r;
}
/* Warning, early returns above */
log_err(ctx, _("No key available with this passphrase.\n"));
return -EPERM;
}
@@ -1079,7 +1078,7 @@ int LUKS_del_key(unsigned int keyIndex,
r = LUKS_keyslot_set(hdr, keyIndex, 0);
if (r) {
log_err(ctx, _("Key slot %d is invalid, please select keyslot between 0 and %d.\n"),
log_err(ctx, _("Key slot %d is invalid, please select keyslot between 0 and %d."),
keyIndex, LUKS_NUMKEYS - 1);
return r;
}
@@ -1093,11 +1092,11 @@ int LUKS_del_key(unsigned int keyIndex,
(endOffset - startOffset) * SECTOR_SIZE, NULL, NULL);
if (r) {
if (r == -EACCES) {
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
log_err(ctx, _("Cannot write to device %s, permission denied."),
device_path(device));
r = -EINVAL;
} else
log_err(ctx, _("Cannot wipe device %s.\n"),
log_err(ctx, _("Cannot wipe device %s."),
device_path(device));
return r;
}
@@ -1211,3 +1210,56 @@ int LUKS1_activate(struct crypt_device *cd,
free(dm_cipher);
return r;
}
int LUKS_wipe_header_areas(struct luks_phdr *hdr,
struct crypt_device *ctx)
{
int i, r;
uint64_t offset, length;
size_t wipe_block;
/* Wipe complete header, keyslots and padding areas with zeroes. */
offset = 0;
length = (uint64_t)hdr->payloadOffset * SECTOR_SIZE;
wipe_block = 1024 * 1024;
/* On detached header or bogus header, wipe at least the first 4k */
if (length == 0 || length > (LUKS_MAX_KEYSLOT_SIZE * LUKS_NUMKEYS)) {
length = 4096;
wipe_block = 4096;
}
log_dbg("Wiping LUKS areas (0x%06" PRIx64 " - 0x%06" PRIx64") with zeroes.",
offset, length + offset);
r = crypt_wipe_device(ctx, crypt_metadata_device(ctx), CRYPT_WIPE_ZERO,
offset, length, wipe_block, NULL, NULL);
if (r < 0)
return r;
/* Wipe keyslots areas */
wipe_block = 1024 * 1024;
for (i = 0; i < LUKS_NUMKEYS; i++) {
r = LUKS_keyslot_area(hdr, i, &offset, &length);
if (r < 0)
return r;
/* Ignore too big LUKS1 keyslots here */
if (length > LUKS_MAX_KEYSLOT_SIZE ||
offset > (LUKS_MAX_KEYSLOT_SIZE - length))
continue;
if (length == 0 || offset < 4096)
return -EINVAL;
log_dbg("Wiping keyslot %i area (0x%06" PRIx64 " - 0x%06" PRIx64") with random data.",
i, offset, length + offset);
r = crypt_wipe_device(ctx, crypt_metadata_device(ctx), CRYPT_WIPE_RANDOM,
offset, length, wipe_block, NULL, NULL);
if (r < 0)
return r;
}
return r;
}

View File

@@ -61,6 +61,9 @@
/* Offset to keyslot area [in bytes] */
#define LUKS_ALIGN_KEYSLOTS 4096
/* Maximal LUKS header size, for wipe [in bytes] */
#define LUKS_MAX_KEYSLOT_SIZE 0x1000000 /* 16 MB, up to 32768 bits key */
/* Any integer values are stored in network byte order on disk and must be
converted */
@@ -99,6 +102,11 @@ struct luks_phdr {
int LUKS_verify_volume_key(const struct luks_phdr *hdr,
const struct volume_key *vk);
int LUKS_check_cipher(struct crypt_device *ctx,
size_t keylength,
const char *cipher,
const char *cipher_mode);
int LUKS_generate_phdr(
struct luks_phdr *header,
const struct volume_key *vk,
@@ -163,6 +171,9 @@ int LUKS_del_key(
struct luks_phdr *hdr,
struct crypt_device *ctx);
int LUKS_wipe_header_areas(struct luks_phdr *hdr,
struct crypt_device *ctx);
crypt_keyslot_info LUKS_keyslot_info(struct luks_phdr *hdr, int keyslot);
int LUKS_keyslot_find_empty(struct luks_phdr *hdr);
int LUKS_keyslot_active_count(struct luks_phdr *hdr);

View File

@@ -35,6 +35,7 @@
#define LUKS2_KEYSLOTS_MAX 32
#define LUKS2_TOKENS_MAX 32
#define LUKS2_SEGMENT_MAX 32
#define LUKS2_BUILTIN_TOKEN_PREFIX "luks2-"
#define LUKS2_BUILTIN_TOKEN_PREFIX_LEN 6
@@ -47,6 +48,8 @@
#define CRYPT_DEFAULT_SEGMENT 0
#define CRYPT_DEFAULT_SEGMENT_STR "0"
#define CRYPT_ANY_DIGEST -1
/*
* LUKS2 header on-disk.
*
@@ -126,10 +129,14 @@ struct luks2_keyslot_params {
#define LUKS2_MAX_KEYSLOTS_SIZE 0x8000000 /* 128 MiB */
/* Offsets for secondary header (for scan if primary header is corrupted). */
#define LUKS2_HDR2_OFFSETS { 0x04000, 0x008000, 0x010000, 0x020000, \
0x40000, 0x080000, 0x100000, 0x200000, 0x400000 }
int LUKS2_hdr_version_unlocked(struct crypt_device *cd,
const char *backup_file);
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr);
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_dump(struct crypt_device *cd, struct luks2_hdr *hdr);
@@ -155,6 +162,8 @@ int LUKS2_hdr_restore(struct crypt_device *cd,
uint64_t LUKS2_hdr_and_areas_size(json_object *jobj);
uint64_t LUKS2_keyslots_size(json_object *jobj);
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd);
/*
* Generic LUKS2 keyslot
*/
@@ -247,6 +256,8 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
const char *name,
uint32_t flags);
int LUKS2_tokens_count(struct luks2_hdr *hdr);
/*
* Generic LUKS2 digest
*/
@@ -320,6 +331,9 @@ int LUKS2_generate_hdr(
unsigned int alignOffset,
int detached_metadata_device);
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_sector_size(struct luks2_hdr *hdr);
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment);

View File

@@ -121,8 +121,6 @@ int LUKS2_digest_verify(struct crypt_device *cd,
int digest, r;
digest = LUKS2_digest_by_keyslot(cd, hdr, keyslot);
if (digest == -ENOENT)
return 0;
if (digest < 0)
return digest;
@@ -137,7 +135,7 @@ int LUKS2_digest_verify(struct crypt_device *cd,
return r;
}
return 0;
return digest;
}
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
@@ -174,9 +172,10 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
return r;
}
return 0;
return digest;
}
/* FIXME: segment can have more digests */
int LUKS2_digest_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
int segment)

View File

@@ -95,7 +95,7 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
{
json_object *jobj_digest, *jobj_digests;
char salt[LUKS_SALTSIZE], digest_raw[128], num[16];
int r;
int hmac_size, r;
char *base64_str;
struct luks2_hdr *hdr;
struct crypt_pbkdf_limits pbkdf_limits;
@@ -123,8 +123,12 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
return r;
}
hmac_size = crypt_hmac_size(pbkdf.hash);
if (hmac_size < 0)
return hmac_size;
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, pbkdf.hash, volume_key, volume_key_len,
salt, LUKS_SALTSIZE, digest_raw, crypt_hmac_size(pbkdf.hash),
salt, LUKS_SALTSIZE, digest_raw, hmac_size,
pbkdf.iterations, 0, 0);
if (r < 0)
return r;
@@ -151,7 +155,7 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
json_object_object_add(jobj_digest, "salt", json_object_new_string(base64_str));
free(base64_str);
base64_encode_alloc(digest_raw, crypt_hmac_size(pbkdf.hash), &base64_str);
base64_encode_alloc(digest_raw, hmac_size, &base64_str);
if (!base64_str) {
json_object_put(jobj_digest);
return -ENOMEM;

View File

@@ -74,9 +74,10 @@ static int hdr_checksum_calculate(const char *alg, struct luks2_hdr_disk *hdr_di
const char *json_area, size_t json_len)
{
struct crypt_hash *hd = NULL;
int r;
int hash_size, r;
if (crypt_hash_size(alg) <= 0 || crypt_hash_init(&hd, alg))
hash_size = crypt_hash_size(alg);
if (hash_size <= 0 || crypt_hash_init(&hd, alg))
return -EINVAL;
/* Binary header, csum zeroed. */
@@ -87,7 +88,7 @@ static int hdr_checksum_calculate(const char *alg, struct luks2_hdr_disk *hdr_di
r = crypt_hash_write(hd, json_area, json_len);
if (!r)
r = crypt_hash_final(hd, (char*)hdr_disk->csum, crypt_hash_size(alg));
r = crypt_hash_final(hd, (char*)hdr_disk->csum, (size_t)hash_size);
crypt_hash_destroy(hd);
return r;
@@ -100,9 +101,10 @@ static int hdr_checksum_check(const char *alg, struct luks2_hdr_disk *hdr_disk,
const char *json_area, size_t json_len)
{
struct luks2_hdr_disk hdr_tmp;
int r;
int hash_size, r;
if (crypt_hash_size(alg) <= 0)
hash_size = crypt_hash_size(alg);
if (hash_size <= 0)
return -EINVAL;
/* Copy header and zero checksum. */
@@ -116,7 +118,7 @@ static int hdr_checksum_check(const char *alg, struct luks2_hdr_disk *hdr_disk,
log_dbg_checksum(hdr_disk->csum, alg, "on-disk");
log_dbg_checksum(hdr_tmp.csum, alg, "in-memory");
if (memcmp(hdr_tmp.csum, hdr_disk->csum, crypt_hash_size(alg)))
if (memcmp(hdr_tmp.csum, hdr_disk->csum, (size_t)hash_size))
return -EINVAL;
return 0;
@@ -221,7 +223,7 @@ static int hdr_read_disk(struct device *device, struct luks2_hdr_disk *hdr_disk,
size_t hdr_json_size = 0;
int devfd = -1, r;
log_dbg("Trying to read %s LUKS2 header at offset %" PRIu64 ".",
log_dbg("Trying to read %s LUKS2 header at offset 0x%" PRIx64 ".",
secondary ? "secondary" : "primary", offset);
devfd = device_open_locked(device, O_RDONLY);
@@ -339,6 +341,7 @@ static int hdr_write_disk(struct device *device, struct luks2_hdr *hdr,
LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN)
r = -EIO;
device_sync(device, devfd);
close(devfd);
return r;
}
@@ -361,7 +364,7 @@ static int LUKS2_check_device_size(struct crypt_device *cd, struct device *devic
if (falloc && !device_fallocate(device, hdr_size))
return 0;
log_err(cd, _("Device %s is too small. (LUKS2 requires at least %" PRIu64 " bytes.)\n"),
log_err(cd, _("Device %s is too small. (LUKS2 requires at least %" PRIu64 " bytes.)"),
device_path(device), hdr_size);
return -EINVAL;
}
@@ -406,7 +409,8 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
/*
* Generate text space-efficient JSON representation to json area.
*/
json_text = json_object_to_json_string_ext(hdr->jobj, JSON_C_TO_STRING_PLAIN);
json_text = json_object_to_json_string_ext(hdr->jobj,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
if (!json_text || !*json_text) {
log_dbg("Cannot parse JSON object to text representation.");
free(json_area);
@@ -424,7 +428,7 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
r = device_write_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire write device lock.\n"));
log_err(cd, _("Failed to acquire write device lock."));
free(json_area);
return r;
}
@@ -490,6 +494,15 @@ static int validate_luks2_json_object(json_object *jobj_hdr)
}
r = LUKS2_hdr_validate(jobj_hdr);
if (r) {
log_dbg("Repairing JSON metadata.");
/* try to correct known glitches */
LUKS2_hdr_repair(jobj_hdr);
/* run validation again */
r = LUKS2_hdr_validate(jobj_hdr);
}
if (r)
log_dbg("ERROR: LUKS2 validation failed");
@@ -519,21 +532,71 @@ static json_object *parse_and_validate_json(const char *json_area, int length)
return jobj;
}
static int detect_device_signatures(const char *path)
{
blk_probe_status prb_state;
int r;
struct blkid_handle *h;
if (!blk_supported()) {
log_dbg("Blkid probing of device signatures disabled.");
return 0;
}
if ((r = blk_init_by_path(&h, path))) {
log_dbg("Failed to initialize blkid_handle by path.");
return -EINVAL;
}
/* We don't care about details. Be fast. */
blk_set_chains_for_fast_detection(h);
/* Filter out crypto_LUKS. we don't care now */
blk_superblocks_filter_luks(h);
prb_state = blk_safeprobe(h);
switch (prb_state) {
case PRB_AMBIGUOUS:
log_dbg("Blkid probe couldn't decide device type unambiguously.");
/* fall through */
case PRB_FAIL:
log_dbg("Blkid probe failed.");
r = -EINVAL;
break;
case PRB_OK: /* crypto_LUKS type is filtered out */
r = -EINVAL;
if (blk_is_partition(h))
log_dbg("Blkid probe detected partition type '%s'", blk_get_partition_type(h));
else if (blk_is_superblock(h))
log_dbg("blkid probe detected superblock type '%s'", blk_get_superblock_type(h));
break;
case PRB_EMPTY:
log_dbg("Blkid probe detected no foreign device signature.");
}
blk_free(h);
return r;
}
/*
* Read and convert on-disk LUKS2 header to in-memory representation..
* Try to do recovery if on-disk state is not consistent.
*/
int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
struct device *device, int do_recovery)
struct device *device, int do_recovery, int do_blkprobe)
{
enum { HDR_OK, HDR_OBSOLETE, HDR_FAIL, HDR_FAIL_IO } state_hdr1, state_hdr2;
struct luks2_hdr_disk hdr_disk1, hdr_disk2;
char *json_area1 = NULL, *json_area2 = NULL;
json_object *jobj_hdr1 = NULL, *jobj_hdr2 = NULL;
int i, r;
unsigned int i;
int r;
uint64_t hdr_size;
uint64_t hdr2_offsets[] = LUKS2_HDR2_OFFSETS;
if (do_recovery && !crypt_metadata_locking_enabled()) {
/* Skip auto-recovery if locks are disabled and we're not doing LUKS2 explicit repair */
if (do_recovery && do_blkprobe && !crypt_metadata_locking_enabled()) {
do_recovery = 0;
log_dbg("Disabling header auto-recovery due to locking being disabled.");
}
@@ -564,8 +627,8 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
/*
* No header size, check all known offsets.
*/
for (r = -EINVAL,i = 2; r < 0 && i <= 1024; i <<= 1)
r = hdr_read_disk(device, &hdr_disk2, &json_area2, i * 4096, 1);
for (r = -EINVAL,i = 0; r < 0 && i < ARRAY_SIZE(hdr2_offsets); i++)
r = hdr_read_disk(device, &hdr_disk2, &json_area2, hdr2_offsets[i], 1);
if (r == 0) {
jobj_hdr2 = parse_and_validate_json(json_area2, be64_to_cpu(hdr_disk2.hdr_size) - LUKS2_HDR_BIN_LEN);
@@ -604,6 +667,12 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
if (state_hdr1 == HDR_OK && state_hdr2 != HDR_OK) {
log_dbg("Secondary LUKS2 header requires recovery.");
if (do_blkprobe && (r = detect_device_signatures(device_path(device)))) {
log_err(cd, _("Device contains ambiguous signatures, cannot auto-recover LUKS2.\n"
"Please run \"cryptsetup repair\" for recovery."));
goto err;
}
if (do_recovery) {
memcpy(&hdr_disk2, &hdr_disk1, LUKS2_HDR_BIN_LEN);
r = crypt_random_get(NULL, (char*)hdr_disk2.salt, sizeof(hdr_disk2.salt), CRYPT_RND_SALT);
@@ -619,6 +688,12 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
} else if (state_hdr1 != HDR_OK && state_hdr2 == HDR_OK) {
log_dbg("Primary LUKS2 header requires recovery.");
if (do_blkprobe && (r = detect_device_signatures(device_path(device)))) {
log_err(cd, _("Device contains ambiguous signatures, cannot auto-recover LUKS2.\n"
"Please run \"cryptsetup repair\" for recovery."));
goto err;
}
if (do_recovery) {
memcpy(&hdr_disk1, &hdr_disk2, LUKS2_HDR_BIN_LEN);
r = crypt_random_get(NULL, (char*)hdr_disk1.salt, sizeof(hdr_disk1.salt), CRYPT_RND_SALT);

View File

@@ -33,11 +33,16 @@
#define UNUSED(x) (void)(x)
/* override useless forward slash escape when supported by json-c */
#ifndef JSON_C_TO_STRING_NOSLASHESCAPE
#define JSON_C_TO_STRING_NOSLASHESCAPE 0
#endif
/*
* On-disk access function prototypes
*/
int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
struct device *device, int do_recovery);
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);
@@ -46,8 +51,9 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr,
*/
json_object *LUKS2_get_keyslot_jobj(struct luks2_hdr *hdr, int keyslot);
json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token);
json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int keyslot);
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);
void hexprint_base64(struct crypt_device *cd, json_object *jobj,
const char *sep, const char *line_sep);
@@ -63,12 +69,22 @@ void JSON_DBG(json_object *jobj, const char *desc);
* LUKS2 JSON validation
*/
/* validation helper */
json_object *json_contains(json_object *jobj, const char *name, const char *section,
const char *key, json_type type);
int LUKS2_hdr_validate(json_object *hdr_jobj);
int LUKS2_keyslot_validate(json_object *hdr_jobj, json_object *hdr_keyslot, const char *key);
int LUKS2_check_json_size(const struct luks2_hdr *hdr);
int LUKS2_token_validate(json_object *hdr_jobj, json_object *jobj_token, const char *key);
void LUKS2_token_dump(struct crypt_device *cd, int token);
/*
* LUKS2 JSON repair for known glitches
*/
void LUKS2_hdr_repair(json_object *jobj_hdr);
void LUKS2_keyslots_repair(json_object *jobj_hdr);
/*
* JSON array helpers
*/
@@ -85,6 +101,8 @@ struct json_object *LUKS2_array_remove(struct json_object *array, const char *nu
typedef int (*keyslot_alloc_func)(struct crypt_device *cd, int keyslot,
size_t volume_key_len,
const struct luks2_keyslot_params *params);
typedef int (*keyslot_update_func)(struct crypt_device *cd, int keyslot,
const struct luks2_keyslot_params *params);
typedef int (*keyslot_open_func) (struct crypt_device *cd, int keyslot,
const char *password, size_t password_len,
char *volume_key, size_t volume_key_len);
@@ -93,21 +111,29 @@ typedef int (*keyslot_store_func)(struct crypt_device *cd, int keyslot,
const char *volume_key, size_t volume_key_len);
typedef int (*keyslot_wipe_func) (struct crypt_device *cd, int keyslot);
typedef int (*keyslot_dump_func) (struct crypt_device *cd, int keyslot);
typedef int (*keyslot_validate_func) (struct crypt_device *cd, int keyslot);
typedef int (*keyslot_validate_func) (struct crypt_device *cd, json_object *jobj_keyslot);
typedef void(*keyslot_repair_func) (struct crypt_device *cd, json_object *jobj_keyslot);
int luks2_keyslot_alloc(struct crypt_device *cd,
/* see LUKS2_luks2_to_luks1 */
int placeholder_keyslot_alloc(struct crypt_device *cd,
int keyslot,
size_t volume_key_len,
const struct luks2_keyslot_params *params);
uint64_t area_offset,
uint64_t area_length,
size_t volume_key_len);
/* validate all keyslot implementations in hdr json */
int LUKS2_keyslots_validate(json_object *hdr_jobj);
typedef struct {
const char *name;
keyslot_alloc_func alloc;
keyslot_update_func update;
keyslot_open_func open;
keyslot_store_func store;
keyslot_wipe_func wipe;
keyslot_dump_func dump;
keyslot_validate_func validate;
keyslot_repair_func repair;
} keyslot_handler;
/**
@@ -128,8 +154,6 @@ typedef struct {
const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type);
#define CRYPT_ANY_DIGEST -1
/**
* LUKS2 token handlers (internal use only)
*/
@@ -147,7 +171,6 @@ typedef struct {
int token_keyring_set(json_object **, const void *);
int token_keyring_get(json_object *, void *);
#define CRYPT_ANY_TOKEN -1
int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
size_t keylength, uint64_t *area_offset, uint64_t *area_length);

View File

@@ -96,7 +96,7 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
}
if (get_max_offset(cd) && (offset + length) > get_max_offset(cd)) {
log_err(cd, _("No space for new keyslot.\n"));
log_err(cd, _("No space for new keyslot."));
return -EINVAL;
}
@@ -122,9 +122,9 @@ int LUKS2_generate_hdr(
const char *cipherMode,
const char *integrity,
const char *uuid,
unsigned int sector_size,
unsigned int alignPayload,
unsigned int alignOffset,
unsigned int sector_size, /* in bytes */
unsigned int alignPayload, /* in bytes */
unsigned int alignOffset, /* in bytes */
int detached_metadata_device)
{
struct json_object *jobj_segment, *jobj_integrity, *jobj_keyslots, *jobj_segments, *jobj_config;
@@ -142,7 +142,7 @@ int LUKS2_generate_hdr(
crypt_random_get(NULL, (char*)hdr->salt2, LUKS2_SALT_L, CRYPT_RND_SALT);
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
log_err(cd, _("Wrong LUKS UUID format provided.\n"));
log_err(cd, _("Wrong LUKS UUID format provided."));
return -EINVAL;
}
if (!uuid)
@@ -182,11 +182,11 @@ int LUKS2_generate_hdr(
jobj_segment = json_object_new_object();
json_object_object_add(jobj_segment, "type", json_object_new_string("crypt"));
if (detached_metadata_device)
offset = (uint64_t)alignPayload * sector_size;
offset = (uint64_t)alignPayload;
else {
//FIXME
//offset = size_round_up(areas[7].offset + areas[7].length, alignPayload * SECTOR_SIZE);
offset = size_round_up(LUKS2_HDR_DEFAULT_LEN, (size_t)alignPayload * sector_size);
offset = size_round_up(LUKS2_HDR_DEFAULT_LEN, (size_t)alignPayload);
offset += alignOffset;
}
@@ -212,7 +212,7 @@ int LUKS2_generate_hdr(
/* for detached metadata device compute reasonable keyslot areas size */
// FIXME: this is coupled with FIXME above
if (detached_metadata_device)
if (detached_metadata_device && !offset)
keyslots_size = LUKS2_HDR_DEFAULT_LEN - get_min_offset(hdr);
else
keyslots_size = offset - get_min_offset(hdr);
@@ -229,3 +229,44 @@ int LUKS2_generate_hdr(
JSON_DBG(hdr->jobj, "Header JSON");
return 0;
}
int LUKS2_wipe_header_areas(struct crypt_device *cd,
struct luks2_hdr *hdr)
{
int r;
uint64_t offset, length;
size_t wipe_block;
/* Wipe complete header, keyslots and padding areas with zeroes. */
offset = 0;
length = LUKS2_get_data_offset(hdr) * SECTOR_SIZE;
wipe_block = 1024 * 1024;
if (LUKS2_hdr_validate(hdr->jobj))
return -EINVAL;
/* On detached header wipe at least the first 4k */
if (length == 0) {
length = 4096;
wipe_block = 4096;
}
log_dbg("Wiping LUKS areas (0x%06" PRIx64 " - 0x%06" PRIx64") with zeroes.",
offset, length + offset);
r = crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_ZERO,
offset, length, wipe_block, NULL, NULL);
if (r < 0)
return r;
/* Wipe keyslot area */
wipe_block = 1024 * 1024;
offset = get_min_offset(hdr);
length = LUKS2_keyslots_size(hdr->jobj);
log_dbg("Wiping keyslots area (0x%06" PRIx64 " - 0x%06" PRIx64") with random data.",
offset, length + offset);
return crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_RANDOM,
offset, length, wipe_block, NULL, NULL);
}

View File

@@ -59,7 +59,8 @@ void JSON_DBG(json_object *jobj, const char *desc)
/* FIXME: make this conditional and disable for stable release. */
if (desc)
log_dbg("%s:", desc);
log_dbg("%s", json_object_to_json_string_ext(jobj, JSON_C_TO_STRING_PRETTY));
log_dbg("%s", json_object_to_json_string_ext(jobj,
JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE));
}
/*
@@ -120,6 +121,16 @@ json_object *LUKS2_get_keyslot_jobj(struct luks2_hdr *hdr, int keyslot)
return jobj2;
}
json_object *LUKS2_get_tokens_jobj(struct luks2_hdr *hdr)
{
json_object *jobj_tokens;
if (!hdr || !json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens))
return NULL;
return jobj_tokens;
}
json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token)
{
json_object *jobj1, *jobj2;
@@ -128,10 +139,11 @@ json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token)
if (!hdr || token < 0)
return NULL;
if (snprintf(token_name, sizeof(token_name), "%u", token) < 1)
jobj1 = LUKS2_get_tokens_jobj(hdr);
if (!jobj1)
return NULL;
if (!json_object_object_get_ex(hdr->jobj, "tokens", &jobj1))
if (snprintf(token_name, sizeof(token_name), "%u", token) < 1)
return NULL;
json_object_object_get_ex(jobj1, token_name, &jobj2);
@@ -240,8 +252,8 @@ static json_bool numbered(const char *name, const char *key)
return TRUE;
}
static json_object *contains(json_object *jobj, const char *name,
const char *section, const char *key, json_type type)
json_object *json_contains(json_object *jobj, const char *name,
const char *section, const char *key, json_type type)
{
json_object *sobj;
@@ -305,7 +317,8 @@ static json_bool validate_keyslots_array(json_object *jarr, json_object *jobj_ke
return FALSE;
}
if (!contains(jobj_keys, "", "Keyslots section", json_object_get_string(jobj), json_type_object))
if (!json_contains(jobj_keys, "", "Keyslots section",
json_object_get_string(jobj), json_type_object))
return FALSE;
i++;
@@ -326,7 +339,8 @@ static json_bool validate_segments_array(json_object *jarr, json_object *jobj_se
return FALSE;
}
if (!contains(jobj_segments, "", "Segments section", json_object_get_string(jobj), json_type_object))
if (!json_contains(jobj_segments, "", "Segments section",
json_object_get_string(jobj), json_type_object))
return FALSE;
i++;
@@ -393,9 +407,9 @@ int LUKS2_keyslot_validate(json_object *hdr_jobj, json_object *hdr_keyslot, cons
{
json_object *jobj_key_size;
if (!contains(hdr_keyslot, key, "Keyslot", "type", json_type_string))
if (!json_contains(hdr_keyslot, key, "Keyslot", "type", json_type_string))
return 1;
if (!(jobj_key_size = contains(hdr_keyslot, key, "Keyslot", "key_size", json_type_int)))
if (!(jobj_key_size = json_contains(hdr_keyslot, key, "Keyslot", "key_size", json_type_int)))
return 1;
/* enforce uint32_t type */
@@ -415,13 +429,14 @@ int LUKS2_token_validate(json_object *hdr_jobj, json_object *jobj_token, const c
{
json_object *jarr, *jobj_keyslots;
/* keyslots are not yet validated, but we need to know token doesn't reference missing keyslot */
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return 1;
if (!contains(jobj_token, key, "Token", "type", json_type_string))
if (!json_contains(jobj_token, key, "Token", "type", json_type_string))
return 1;
jarr = contains(jobj_token, key, "Token", "keyslots", json_type_array);
jarr = json_contains(jobj_token, key, "Token", "keyslots", json_type_array);
if (!jarr)
return 1;
@@ -434,11 +449,18 @@ int LUKS2_token_validate(json_object *hdr_jobj, json_object *jobj_token, const c
static int hdr_validate_json_size(json_object *hdr_jobj)
{
json_object *jobj, *jobj1;
const char *json;
uint64_t json_area_size, json_size;
json_object_object_get_ex(hdr_jobj, "config", &jobj);
json_object_object_get_ex(jobj, "json_size", &jobj1);
return (strlen(json_object_to_json_string_ext(hdr_jobj, JSON_C_TO_STRING_PLAIN)) > json_object_get_uint64(jobj1));
json = json_object_to_json_string_ext(hdr_jobj,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
json_area_size = json_object_get_uint64(jobj1);
json_size = (uint64_t)strlen(json);
return json_size > json_area_size ? 1 : 0;
}
int LUKS2_check_json_size(const struct luks2_hdr *hdr)
@@ -484,12 +506,59 @@ static int hdr_validate_tokens(json_object *hdr_jobj)
return 0;
}
static int hdr_validate_crypt_segment(json_object *jobj, const char *key, json_object *jobj_digests,
uint64_t offset, uint64_t size)
{
json_object *jobj_ivoffset, *jobj_sector_size, *jobj_integrity;
uint32_t sector_size;
uint64_t ivoffset;
if (!(jobj_ivoffset = json_contains(jobj, key, "Segment", "iv_tweak", json_type_string)) ||
!json_contains(jobj, key, "Segment", "encryption", json_type_string) ||
!(jobj_sector_size = json_contains(jobj, key, "Segment", "sector_size", json_type_int)))
return 1;
/* integrity */
if (json_object_object_get_ex(jobj, "integrity", &jobj_integrity)) {
if (!json_contains(jobj, key, "Segment", "integrity", json_type_object) ||
!json_contains(jobj_integrity, key, "Segment integrity", "type", json_type_string) ||
!json_contains(jobj_integrity, key, "Segment integrity", "journal_encryption", json_type_string) ||
!json_contains(jobj_integrity, key, "Segment integrity", "journal_integrity", json_type_string))
return 1;
}
/* enforce uint32_t type */
if (!validate_json_uint32(jobj_sector_size)) {
log_dbg("Illegal field \"sector_size\":%s.",
json_object_get_string(jobj_sector_size));
return 1;
}
sector_size = json_object_get_uint32(jobj_sector_size);
if (!sector_size || MISALIGNED_512(sector_size)) {
log_dbg("Illegal sector size: %" PRIu32, sector_size);
return 1;
}
if (!numbered("iv_tweak", json_object_get_string(jobj_ivoffset)) ||
!json_str_to_uint64(jobj_ivoffset, &ivoffset)) {
log_dbg("Illegal iv_tweak value.");
return 1;
}
if (size % sector_size) {
log_dbg("Size field has to be aligned to sector size: %" PRIu32, sector_size);
return 1;
}
return !segment_has_digest(key, jobj_digests);
}
static int hdr_validate_segments(json_object *hdr_jobj)
{
json_object *jobj, *jobj_digests, *jobj_offset, *jobj_ivoffset,
*jobj_length, *jobj_sector_size, *jobj_type, *jobj_integrity;
uint32_t sector_size;
uint64_t ivoffset, offset, length;
json_object *jobj, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags;
int i;
uint64_t offset, size;
if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj)) {
log_dbg("Missing segments section.");
@@ -509,70 +578,46 @@ static int hdr_validate_segments(json_object *hdr_jobj)
if (!numbered("Segment", key))
return 1;
if (!contains(val, key, "Segment", "type", json_type_string) ||
!(jobj_offset = contains(val, key, "Segment", "offset", json_type_string)) ||
!(jobj_ivoffset = contains(val, key, "Segment", "iv_tweak", json_type_string)) ||
!(jobj_length = contains(val, key, "Segment", "size", json_type_string)) ||
!contains(val, key, "Segment", "encryption", json_type_string) ||
!(jobj_sector_size = contains(val, key, "Segment", "sector_size", json_type_int)))
/* those fields are mandatory for all segment types */
if (!(jobj_type = json_contains(val, key, "Segment", "type", json_type_string)) ||
!(jobj_offset = json_contains(val, key, "Segment", "offset", json_type_string)) ||
!(jobj_size = json_contains(val, key, "Segment", "size", json_type_string)))
return 1;
/* integrity */
if (json_object_object_get_ex(val, "integrity", &jobj_integrity)) {
if (!contains(val, key, "Segment", "integrity", json_type_object) ||
!contains(jobj_integrity, key, "Segment integrity", "type", json_type_string) ||
!contains(jobj_integrity, key, "Segment integrity", "journal_encryption", json_type_string) ||
!contains(jobj_integrity, key, "Segment integrity", "journal_integrity", json_type_string))
return 1;
}
/* enforce uint32_t type */
if (!validate_json_uint32(jobj_sector_size)) {
log_dbg("Illegal field \"sector_size\":%s.",
json_object_get_string(jobj_sector_size));
return 1;
}
sector_size = json_object_get_uint32(jobj_sector_size);
if (!sector_size || sector_size % 512) {
log_dbg("Illegal sector size: %" PRIu32, sector_size);
return 1;
}
if (!numbered("offset", json_object_get_string(jobj_offset)) ||
!numbered("iv_tweak", json_object_get_string(jobj_ivoffset)))
!json_str_to_uint64(jobj_offset, &offset))
return 1;
/* rule out values > UINT64_MAX */
if (!json_str_to_uint64(jobj_offset, &offset) ||
!json_str_to_uint64(jobj_ivoffset, &ivoffset))
return 1;
if (offset % sector_size) {
log_dbg("Offset field has to be aligned to sector size: %" PRIu32, sector_size);
return 1;
}
if (ivoffset % sector_size) {
log_dbg("IV offset field has to be aligned to sector size: %" PRIu32, sector_size);
return 1;
}
/* length "dynamic" means whole device starting at 'offset' */
if (strcmp(json_object_get_string(jobj_length), "dynamic")) {
if (!numbered("size", json_object_get_string(jobj_length)) ||
!json_str_to_uint64(jobj_length, &length))
/* size "dynamic" means whole device starting at 'offset' */
if (strcmp(json_object_get_string(jobj_size), "dynamic")) {
if (!numbered("size", json_object_get_string(jobj_size)) ||
!json_str_to_uint64(jobj_size, &size) || !size)
return 1;
} else
size = 0;
if (length % sector_size) {
log_dbg("Length field has to be aligned to sector size: %" PRIu32, sector_size);
return 1;
}
/* all device-mapper devices are aligned to 512 sector size */
if (MISALIGNED_512(offset)) {
log_dbg("Offset field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
return 1;
}
if (MISALIGNED_512(size)) {
log_dbg("Size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
return 1;
}
json_object_object_get_ex(val, "type", &jobj_type);
/* flags array is optional and must contain strings */
if (json_object_object_get_ex(val, "flags", NULL)) {
if (!(jobj_flags = json_contains(val, key, "Segment", "flags", json_type_array)))
return 1;
for (i = 0; i < (int) json_object_array_length(jobj_flags); i++)
if (!json_object_is_type(json_object_array_get_idx(jobj_flags, i), json_type_string))
return 1;
}
/* crypt */
if (!strcmp(json_object_get_string(jobj_type), "crypt") &&
!segment_has_digest(key, jobj_digests))
hdr_validate_crypt_segment(val, key, jobj_digests, offset, size))
return 1;
}
@@ -586,11 +631,10 @@ static int hdr_validate_areas(json_object *hdr_jobj)
int length, ret, i = 0;
uint64_t first_offset;
/* keyslots should already be validated */
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return 1;
/* segments should already be validated */
/* segments are already validated */
if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
return 1;
@@ -613,9 +657,9 @@ static int hdr_validate_areas(json_object *hdr_jobj)
json_object_object_foreach(jobj_keyslots, key, val) {
if (!(jobj_area = contains(val, key, "Keyslot", "area", json_type_object)) ||
!(jobj_offset = contains(jobj_area, key, "Keyslot", "offset", json_type_string)) ||
!(jobj_length = contains(jobj_area, key, "Keyslot", "size", json_type_string)) ||
if (!(jobj_area = json_contains(val, key, "Keyslot", "area", json_type_object)) ||
!(jobj_offset = json_contains(jobj_area, key, "Keyslot", "offset", json_type_string)) ||
!(jobj_length = json_contains(jobj_area, key, "Keyslot", "size", json_type_string)) ||
!numbered("offset", json_object_get_string(jobj_offset)) ||
!numbered("size", json_object_get_string(jobj_length))) {
free(intervals);
@@ -655,11 +699,11 @@ static int hdr_validate_digests(json_object *hdr_jobj)
return 1;
}
/* keyslots should already be validated */
/* keyslots are not yet validated, but we need to know digest doesn't reference missing keyslot */
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return 1;
/* segments are not validated atm, but we need to know digest doesn't reference missing segment */
/* segments are not yet validated, but we need to know digest doesn't reference missing segment */
if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
return 1;
@@ -667,9 +711,9 @@ static int hdr_validate_digests(json_object *hdr_jobj)
if (!numbered("Digest", key))
return 1;
if (!contains(val, key, "Digest", "type", json_type_string) ||
!(jarr_keys = contains(val, key, "Digest", "keyslots", json_type_array)) ||
!(jarr_segs = contains(val, key, "Digest", "segments", json_type_array)))
if (!json_contains(val, key, "Digest", "type", json_type_string) ||
!(jarr_keys = json_contains(val, key, "Digest", "keyslots", json_type_array)) ||
!(jarr_segs = json_contains(val, key, "Digest", "segments", json_type_array)))
return 1;
if (!validate_keyslots_array(jarr_keys, jobj_keyslots))
@@ -690,7 +734,7 @@ static int validate_keyslots_size(json_object *hdr_jobj, json_object *jobj_keysl
if (!json_str_to_uint64(jobj_keyslots_size, &keyslots_size))
return 1;
if (keyslots_size % 4096) {
if (MISALIGNED_4K(keyslots_size)) {
log_dbg("keyslots_size is not 4 KiB aligned");
return 1;
}
@@ -737,7 +781,7 @@ static int hdr_validate_config(json_object *hdr_jobj)
return 1;
}
if (!(jobj = contains(jobj_config, "section", "Config", "json_size", json_type_string)) ||
if (!(jobj = json_contains(jobj_config, "section", "Config", "json_size", json_type_string)) ||
!json_str_to_uint64(jobj, &json_size))
return 1;
@@ -747,12 +791,12 @@ static int hdr_validate_config(json_object *hdr_jobj)
return 1;
}
if (json_size % 4096) {
if (MISALIGNED_4K(json_size)) {
log_dbg("Json area is not properly aligned to 4 KiB.");
return 1;
}
if (!(jobj = contains(jobj_config, "section", "Config", "keyslots_size", json_type_string)))
if (!(jobj = json_contains(jobj_config, "section", "Config", "keyslots_size", json_type_string)))
return 1;
if (validate_keyslots_size(hdr_jobj, jobj))
@@ -760,7 +804,7 @@ static int hdr_validate_config(json_object *hdr_jobj)
/* Flags array is optional */
if (json_object_object_get_ex(jobj_config, "flags", &jobj)) {
if (!contains(jobj_config, "section", "Config", "flags", json_type_array))
if (!json_contains(jobj_config, "section", "Config", "flags", json_type_array))
return 1;
/* All array members must be strings */
@@ -771,12 +815,12 @@ static int hdr_validate_config(json_object *hdr_jobj)
/* Requirements object is optional */
if (json_object_object_get_ex(jobj_config, "requirements", &jobj)) {
if (!contains(jobj_config, "section", "Config", "requirements", json_type_object))
if (!json_contains(jobj_config, "section", "Config", "requirements", json_type_object))
return 1;
/* Mandatory array is optional */
if (json_object_object_get_ex(jobj, "mandatory", &jobj1)) {
if (!contains(jobj, "section", "Requirements", "mandatory", json_type_array))
if (!json_contains(jobj, "section", "Requirements", "mandatory", json_type_array))
return 1;
/* All array members must be strings */
@@ -794,10 +838,10 @@ int LUKS2_hdr_validate(json_object *hdr_jobj)
struct {
int (*validate)(json_object *);
} checks[] = {
{ hdr_validate_keyslots },
{ hdr_validate_tokens },
{ hdr_validate_digests },
{ hdr_validate_segments },
{ hdr_validate_keyslots },
{ hdr_validate_areas },
{ hdr_validate_config },
{ NULL }
@@ -816,33 +860,38 @@ int LUKS2_hdr_validate(json_object *hdr_jobj)
return 1;
}
/* validate keyslot implementations */
if (LUKS2_keyslots_validate(hdr_jobj))
return 1;
return 0;
}
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr)
/* FIXME: should we expose do_recovery parameter explicitly? */
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair)
{
int r;
r = device_read_lock(cd, crypt_metadata_device(cd));
if (r) {
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
log_err(cd, _("Failed to acquire read lock on device %s."),
device_path(crypt_metadata_device(cd)));
return r;
}
r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1);
r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1, !repair);
if (r == -EAGAIN) {
/* unlikely: auto-recovery is required and failed due to read lock being held */
device_read_unlock(crypt_metadata_device(cd));
r = device_write_lock(cd, crypt_metadata_device(cd));
if (r) {
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
log_err(cd, _("Failed to acquire write lock on device %s."),
device_path(crypt_metadata_device(cd)));
return r;
}
r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1);
r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1, !repair);
device_write_unlock(crypt_metadata_device(cd));
} else
@@ -851,17 +900,11 @@ int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr)
return r;
}
/* NOTE: is called before LUKS2 validation routines */
static void LUKS2_hdr_free_unused_objects(struct crypt_device *cd, struct luks2_hdr *hdr)
{
/* erase unused digests (no assigned keyslot or segment) */
LUKS2_digests_erase_unused(cd, hdr);
}
int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr)
{
/* FIXME: we risk to hide future internal implementation bugs with this */
LUKS2_hdr_free_unused_objects(cd, hdr);
/* NOTE: is called before LUKS2 validation routines */
/* erase unused digests (no assigned keyslot or segment) */
LUKS2_digests_erase_unused(cd, hdr);
if (LUKS2_hdr_validate(hdr->jobj))
return -EINVAL;
@@ -874,7 +917,7 @@ int LUKS2_hdr_uuid(struct crypt_device *cd, struct luks2_hdr *hdr, const char *u
uuid_t partitionUuid;
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
log_err(cd, _("Wrong LUKS UUID format provided.\n"));
log_err(cd, _("Wrong LUKS UUID format provided."));
return -EINVAL;
}
if (!uuid)
@@ -954,7 +997,7 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
r = device_read_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
log_err(cd, _("Failed to acquire read lock on device %s."),
device_path(crypt_metadata_device(cd)));
crypt_safe_free(buffer);
return r;
@@ -963,7 +1006,7 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
devfd = device_open_locked(device, O_RDONLY);
if (devfd < 0) {
device_read_unlock(device);
log_err(cd, _("Device %s is not a valid LUKS device.\n"), device_path(device));
log_err(cd, _("Device %s is not a valid LUKS device."), device_path(device));
crypt_safe_free(buffer);
return devfd == -1 ? -EINVAL : devfd;
}
@@ -982,14 +1025,14 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
if (devfd == -1) {
if (errno == EEXIST)
log_err(cd, _("Requested header backup file %s already exists.\n"), backup_file);
log_err(cd, _("Requested header backup file %s already exists."), backup_file);
else
log_err(cd, _("Cannot create header backup file %s.\n"), backup_file);
log_err(cd, _("Cannot create header backup file %s."), backup_file);
crypt_safe_free(buffer);
return -EINVAL;
}
if (write_buffer(devfd, buffer, buffer_size) < buffer_size) {
log_err(cd, _("Cannot write header backup file %s.\n"), backup_file);
log_err(cd, _("Cannot write header backup file %s."), backup_file);
r = -EIO;
} else
r = 0;
@@ -1027,24 +1070,24 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
/* FIXME: why lock backup device ? */
r = device_read_lock(cd, backup_device);
if (r) {
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
log_err(cd, _("Failed to acquire read lock on device %s."),
device_path(backup_device));
device_free(backup_device);
return r;
}
r = LUKS2_disk_hdr_read(cd, &hdr_file, backup_device, 0);
r = LUKS2_disk_hdr_read(cd, &hdr_file, backup_device, 0, 0);
device_read_unlock(backup_device);
device_free(backup_device);
if (r < 0) {
log_err(cd, _("Backup file doesn't contain valid LUKS header.\n"));
log_err(cd, _("Backup file doesn't contain valid LUKS header."));
goto out;
}
/* do not allow header restore from backup with unmet requirements */
if (LUKS2_unmet_requirements(cd, &hdr_file, 0, 1)) {
log_err(cd, _("Forbidden LUKS2 requirements detected in backup %s.\n"),
log_err(cd, _("Forbidden LUKS2 requirements detected in backup %s."),
backup_file);
r = -ETXTBSY;
goto out;
@@ -1059,20 +1102,20 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
devfd = open(backup_file, O_RDONLY);
if (devfd == -1) {
log_err(cd, _("Cannot open header backup file %s.\n"), backup_file);
log_err(cd, _("Cannot open header backup file %s."), backup_file);
r = -EINVAL;
goto out;
}
if (read_buffer(devfd, buffer, buffer_size) < buffer_size) {
log_err(cd, _("Cannot read header backup file %s.\n"), backup_file);
log_err(cd, _("Cannot read header backup file %s."), backup_file);
r = -EIO;
goto out;
}
close(devfd);
devfd = -1;
r = LUKS2_hdr_read(cd, &tmp_hdr);
r = LUKS2_hdr_read(cd, &tmp_hdr, 0);
if (r == 0) {
log_dbg("Device %s already contains LUKS2 header, checking UUID and requirements.", device_path(device));
r = LUKS2_config_get_requirements(cd, &tmp_hdr, &reqs);
@@ -1085,13 +1128,13 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
if (!reqs_reencrypt(reqs)) {
log_dbg("Checking LUKS2 header size and offsets.");
if (LUKS2_get_data_offset(&tmp_hdr) != LUKS2_get_data_offset(&hdr_file)) {
log_err(cd, _("Data offset differ on device and backup, restore failed.\n"));
log_err(cd, _("Data offset differ on device and backup, restore failed."));
r = -EINVAL;
goto out;
}
/* FIXME: what could go wrong? Erase if we're fine with consequences */
if (buffer_size != (ssize_t) LUKS2_hdr_and_areas_size(tmp_hdr.jobj)) {
log_err(cd, _("Binary header with keyslot areas size differ on device and backup, restore failed.\n"));
log_err(cd, _("Binary header with keyslot areas size differ on device and backup, restore failed."));
r = -EINVAL;
goto out;
}
@@ -1121,7 +1164,7 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
/* TODO: perform header restore on bdev in stand-alone routine? */
r = device_write_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
log_err(cd, _("Failed to acquire write lock on device %s."),
device_path(device));
goto out;
}
@@ -1129,10 +1172,10 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
devfd = device_open_locked(device, O_RDWR);
if (devfd < 0) {
if (errno == EACCES)
log_err(cd, _("Cannot write to device %s, permission denied.\n"),
log_err(cd, _("Cannot write to device %s, permission denied."),
device_path(device));
else
log_err(cd, _("Cannot open device %s.\n"), device_path(device));
log_err(cd, _("Cannot open device %s."), device_path(device));
device_write_unlock(device);
r = -EINVAL;
goto out;
@@ -1148,20 +1191,19 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
/* end of TODO */
out:
LUKS2_hdr_free(hdr);
LUKS2_hdr_free(&hdr_file);
LUKS2_hdr_free(&tmp_hdr);
crypt_memzero(&hdr_file, sizeof(hdr_file));
crypt_memzero(&tmp_hdr, sizeof(tmp_hdr));
crypt_safe_free(buffer);
if (devfd >= 0)
if (devfd >= 0) {
device_sync(device, devfd);
close(devfd);
if (!r) {
LUKS2_hdr_free(hdr);
r = LUKS2_hdr_read(cd, hdr);
}
return r;
}
@@ -1206,7 +1248,7 @@ int LUKS2_config_get_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
found = 1;
}
if (!found)
log_verbose(cd, _("Ignored unknown flag %s.\n"),
log_verbose(cd, _("Ignored unknown flag %s."),
json_object_get_string(jobj1));
}
@@ -1498,40 +1540,56 @@ static void hdr_dump_tokens(struct crypt_device *cd, json_object *hdr_jobj)
}
}
/* FIXME: sort segments when more segments available later */
static void hdr_dump_segments(struct crypt_device *cd, json_object *hdr_jobj)
{
json_object *jobj1, *jobj2, *jobj3;
char segment[16];
json_object *jobj_segments, *jobj_segment, *jobj1, *jobj2;
int i, j, flags;
uint64_t value;
log_std(cd, "Data segments:\n");
json_object_object_get_ex(hdr_jobj, "segments", &jobj1);
json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments);
json_object_object_foreach(jobj1, key, val) {
json_object_object_get_ex(val, "type", &jobj2);
log_std(cd, " %s: %s\n", key, json_object_get_string(jobj2));
for (i = 0; i < LUKS2_SEGMENT_MAX; i++) {
(void) snprintf(segment, sizeof(segment), "%i", i);
if (!json_object_object_get_ex(jobj_segments, segment, &jobj_segment))
continue;
json_object_object_get_ex(val, "offset", &jobj3);
json_str_to_uint64(jobj3, &value);
json_object_object_get_ex(jobj_segment, "type", &jobj1);
log_std(cd, " %s: %s\n", segment, json_object_get_string(jobj1));
json_object_object_get_ex(jobj_segment, "offset", &jobj1);
json_str_to_uint64(jobj1, &value);
log_std(cd, "\toffset: %" PRIu64 " [bytes]\n", value);
json_object_object_get_ex(val, "size", &jobj3);
if (!(strcmp(json_object_get_string(jobj3), "dynamic")))
json_object_object_get_ex(jobj_segment, "size", &jobj1);
if (!(strcmp(json_object_get_string(jobj1), "dynamic")))
log_std(cd, "\tlength: (whole device)\n");
else {
json_str_to_uint64(jobj3, &value);
json_str_to_uint64(jobj1, &value);
log_std(cd, "\tlength: %" PRIu64 " [bytes]\n", value);
}
json_object_object_get_ex(val, "encryption", &jobj3);
log_std(cd, "\tcipher: %s\n", json_object_get_string(jobj3));
if (json_object_object_get_ex(jobj_segment, "encryption", &jobj1))
log_std(cd, "\tcipher: %s\n", json_object_get_string(jobj1));
json_object_object_get_ex(val, "sector_size", &jobj3);
log_std(cd, "\tsector: %" PRIu32 " [bytes]\n", json_object_get_uint32(jobj3));
if (json_object_object_get_ex(jobj_segment, "sector_size", &jobj1))
log_std(cd, "\tsector: %" PRIu32 " [bytes]\n", json_object_get_uint32(jobj1));
if (json_object_object_get_ex(val, "integrity", &jobj2) &&
json_object_object_get_ex(jobj2, "type", &jobj3))
log_std(cd, "\tintegrity: %s\n", json_object_get_string(jobj3));
if (json_object_object_get_ex(jobj_segment, "integrity", &jobj1) &&
json_object_object_get_ex(jobj1, "type", &jobj2))
log_std(cd, "\tintegrity: %s\n", json_object_get_string(jobj2));
if (json_object_object_get_ex(jobj_segment, "flags", &jobj1) &&
(flags = (int)json_object_array_length(jobj1)) > 0) {
jobj2 = json_object_array_get_idx(jobj1, 0);
log_std(cd, "\tflags : %s", json_object_get_string(jobj2));
for (j = 1; j < flags; j++) {
jobj2 = json_object_array_get_idx(jobj1, j);
log_std(cd, ", %s", json_object_get_string(jobj2));
}
log_std(cd, "\n");
}
log_std(cd, "\n");
}
@@ -1609,10 +1667,12 @@ const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment)
if (!json_object_object_get_ex(jobj1, buf, &jobj2))
return NULL;
if (!json_object_object_get_ex(jobj2, "encryption", &jobj3))
return NULL;
if (json_object_object_get_ex(jobj2, "encryption", &jobj3))
return json_object_get_string(jobj3);
/* FIXME: default encryption (for other segment types) must be string here. */
return "null";
return json_object_get_string(jobj3);
}
static int luks2_keyslot_af_params(json_object *jobj_af, struct luks2_keyslot_params *params)
@@ -1743,13 +1803,13 @@ static int LUKS2_keyslot_get_volume_key_size(struct luks2_hdr *hdr, const char *
json_object *jobj1, *jobj2, *jobj3;
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj1))
return 0;
return -1;
if (!json_object_object_get_ex(jobj1, keyslot, &jobj2))
return 0;
return -1;
if (!json_object_object_get_ex(jobj2, "key_size", &jobj3))
return 0;
return -1;
return json_object_get_int(jobj3);
}
@@ -1850,7 +1910,7 @@ int LUKS2_activate(struct crypt_device *cd,
if (dmd.u.crypt.tag_size) {
if (!LUKS2_integrity_compatible(hdr)) {
log_err(cd, "Unsupported device integrity configuration.\n");
log_err(cd, "Unsupported device integrity configuration.");
return -EINVAL;
}
@@ -1877,7 +1937,7 @@ int LUKS2_activate(struct crypt_device *cd,
crypt_get_data_offset(cd) * SECTOR_SIZE,
&dmd.size);
if (r < 0) {
log_err(cd, "Cannot detect integrity device size.\n");
log_err(cd, "Cannot detect integrity device size.");
device_free(device);
dm_remove_device(cd, dm_int_name, 0);
return r;
@@ -1903,14 +1963,14 @@ int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uin
if (r) {
if (!quiet)
log_err(cd, _("Failed to read LUKS2 requirements.\n"));
log_err(cd, _("Failed to read LUKS2 requirements."));
return r;
}
/* do not mask unknown requirements check */
if (reqs_unknown(reqs)) {
if (!quiet)
log_err(cd, _("Unmet LUKS2 requirements detected.\n"));
log_err(cd, _("Unmet LUKS2 requirements detected."));
return -ETXTBSY;
}
@@ -1918,8 +1978,31 @@ int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uin
reqs &= ~reqs_mask;
if (reqs_reencrypt(reqs) && !quiet)
log_err(cd, _("Offline reencryption in progress. Aborting.\n"));
log_err(cd, _("Offline reencryption in progress. Aborting."));
/* any remaining unmasked requirement fails the check */
return reqs ? -EINVAL : 0;
}
/*
* NOTE: this routine is called on json object that failed validation.
* Proceed with caution :)
*
* known glitches so far:
*
* any version < 2.0.3:
* - luks2 keyslot pbkdf params change via crypt_keyslot_change_by_passphrase()
* could leave previous type parameters behind. Correct this by purging
* all params not needed by current type.
*/
void LUKS2_hdr_repair(json_object *hdr_jobj)
{
json_object *jobj_keyslots;
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return;
if (!json_object_is_type(jobj_keyslots, json_type_object))
return;
LUKS2_keyslots_repair(jobj_keyslots);
}

View File

@@ -63,14 +63,6 @@ static const keyslot_handler
return LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj2));
}
static crypt_keyslot_info LUKS2_keyslot_active(struct luks2_hdr *hdr, int keyslot)
{
if (keyslot >= LUKS2_KEYSLOTS_MAX)
return CRYPT_SLOT_INVALID;
return LUKS2_get_keyslot_jobj(hdr, keyslot) ? CRYPT_SLOT_ACTIVE : CRYPT_SLOT_INACTIVE;
}
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
{
int i;
@@ -82,6 +74,7 @@ int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
return -EINVAL;
}
/* Check if a keyslot is asssigned to specific segment */
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
{
int keyslot_digest, segment_digest;
@@ -96,11 +89,12 @@ int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
segment_digest = LUKS2_digest_by_segment(NULL, hdr, segment);
if (segment_digest < 0)
return -EINVAL;
return segment_digest;
return segment_digest == keyslot_digest ? 0 : -ENOENT;
}
/* Number of keyslots assigned to a segment or all keyslots for CRYPT_ANY_SEGMENT */
int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
{
int num = 0;
@@ -117,6 +111,21 @@ int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
return num;
}
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd)
{
const char *cipher = crypt_get_cipher(cd);
/* Keyslot is already authenticated; we cannot use integrity tags here */
if (crypt_get_integrity_tag_size(cd) || !cipher)
return 1;
/* Wrapped key schemes cannot be used for keyslot encryption */
if (crypt_cipher_wrapped_key(cipher))
return 1;
return 0;
}
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
size_t key_size, struct luks2_keyslot_params *params)
{
@@ -140,7 +149,7 @@ int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
/* set keyslot area encryption parameters */
/* short circuit authenticated encryption hardcoded defaults */
if (crypt_get_integrity_tag_size(cd) || key_size == 0) {
if (LUKS2_keyslot_cipher_incompatible(cd) || key_size == 0) {
// FIXME: fixed cipher and key size can be wrong
snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption),
"aes-xts-plain64");
@@ -161,18 +170,38 @@ int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
return 0;
}
static int LUKS2_keyslot_unbound(struct luks2_hdr *hdr, int keyslot)
{
json_object *jobj_digest, *jobj_segments;
int digest = LUKS2_digest_by_keyslot(NULL, hdr, keyslot);
if (digest < 0)
return 0;
if (!(jobj_digest = LUKS2_get_digest_jobj(hdr, digest)))
return 0;
json_object_object_get_ex(jobj_digest, "segments", &jobj_segments);
if (!jobj_segments || !json_object_is_type(jobj_segments, json_type_array) ||
json_object_array_length(jobj_segments) == 0)
return 1;
return 0;
}
crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot)
{
crypt_keyslot_info ki;
if(keyslot >= LUKS2_KEYSLOTS_MAX || keyslot < 0)
return CRYPT_SLOT_INVALID;
ki = LUKS2_keyslot_active(hdr, keyslot);
if (ki != CRYPT_SLOT_ACTIVE)
return ki;
if (!LUKS2_get_keyslot_jobj(hdr, keyslot))
return CRYPT_SLOT_INACTIVE;
if (LUKS2_keyslot_active_count(hdr, CRYPT_DEFAULT_SEGMENT) == 1 && !LUKS2_keyslot_for_segment(hdr, keyslot, CRYPT_DEFAULT_SEGMENT))
if (LUKS2_keyslot_unbound(hdr, keyslot))
return CRYPT_SLOT_UNBOUND;
if (LUKS2_keyslot_active_count(hdr, CRYPT_DEFAULT_SEGMENT) == 1 &&
!LUKS2_keyslot_for_segment(hdr, keyslot, CRYPT_DEFAULT_SEGMENT))
return CRYPT_SLOT_ACTIVE_LAST;
return CRYPT_SLOT_ACTIVE;
@@ -220,6 +249,12 @@ static int LUKS2_open_and_verify(struct crypt_device *cd,
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
return -ENOENT;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg("Keyslot %d validation failed.", keyslot);
return r;
}
r = LUKS2_keyslot_for_segment(hdr, keyslot, segment);
if (r) {
if (r == -ENOENT)
@@ -343,10 +378,18 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
r = h->alloc(cd, keyslot, vk->keylength, params);
if (r)
return r;
} else if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
return -EINVAL;
} else {
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
return -EINVAL;
r = h->validate(cd, keyslot);
r = h->update(cd, keyslot, params);
if (r) {
log_dbg("Failed to update keyslot %d json.", keyslot);
return r;
}
}
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg("Keyslot validation failed.");
return r;
@@ -383,7 +426,7 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
/* 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.\n"),
log_err(cd, _("Failed to acquire write lock on device %s."),
device_path(device));
return r;
}
@@ -400,11 +443,11 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
area_length, area_length, NULL, NULL);
if (r) {
if (r == -EACCES) {
log_err(cd, _("Cannot write to device %s, permission denied.\n"),
log_err(cd, _("Cannot write to device %s, permission denied."),
device_path(device));
r = -EINVAL;
} else
log_err(cd, _("Cannot wipe device %s.\n"), device_path(device));
log_err(cd, _("Cannot wipe device %s."), device_path(device));
return r;
}
}
@@ -467,3 +510,119 @@ int LUKS2_keyslot_priority_set(struct crypt_device *cd, struct luks2_hdr *hdr,
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
}
int placeholder_keyslot_alloc(struct crypt_device *cd,
int keyslot,
uint64_t area_offset,
uint64_t area_length,
size_t volume_key_len)
{
struct luks2_hdr *hdr;
char num[16];
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
log_dbg("Allocating placeholder keyslot %d for LUKS1 down conversion.", keyslot);
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
return -EINVAL;
if (LUKS2_get_keyslot_jobj(hdr, keyslot))
return -EINVAL;
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
return -EINVAL;
jobj_keyslot = json_object_new_object();
json_object_object_add(jobj_keyslot, "type", json_object_new_string("placeholder"));
/*
* key_size = -1 makes placeholder keyslot impossible to pass validation.
* It's a safeguard against accidentally storing temporary conversion
* LUKS2 header.
*/
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(-1));
/* Area object */
jobj_area = json_object_new_object();
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, "area", jobj_area);
snprintf(num, sizeof(num), "%d", keyslot);
json_object_object_add(jobj_keyslots, num, jobj_keyslot);
return 0;
}
static unsigned LUKS2_get_keyslot_digests_count(json_object *hdr_jobj, int keyslot)
{
char num[16];
json_object *jobj_digests, *jobj_keyslots;
unsigned count = 0;
if (!json_object_object_get_ex(hdr_jobj, "digests", &jobj_digests))
return 0;
if (snprintf(num, sizeof(num), "%u", keyslot) < 0)
return 0;
json_object_object_foreach(jobj_digests, key, val) {
UNUSED(key);
json_object_object_get_ex(val, "keyslots", &jobj_keyslots);
if (LUKS2_array_jobj(jobj_keyslots, num))
count++;
}
return count;
}
/* run only on header that passed basic format validation */
int LUKS2_keyslots_validate(json_object *hdr_jobj)
{
const keyslot_handler *h;
int keyslot;
json_object *jobj_keyslots, *jobj_type;
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return -EINVAL;
json_object_object_foreach(jobj_keyslots, slot, val) {
keyslot = atoi(slot);
json_object_object_get_ex(val, "type", &jobj_type);
h = LUKS2_keyslot_handler_type(NULL, json_object_get_string(jobj_type));
if (!h)
continue;
if (h->validate && h->validate(NULL, val)) {
log_dbg("Keyslot type %s validation failed on keyslot %d.", h->name, keyslot);
return -EINVAL;
}
if (!strcmp(h->name, "luks2") && LUKS2_get_keyslot_digests_count(hdr_jobj, keyslot) != 1) {
log_dbg("Keyslot %d is not assigned to exactly 1 digest.", keyslot);
return -EINVAL;
}
}
return 0;
}
void LUKS2_keyslots_repair(json_object *jobj_keyslots)
{
const keyslot_handler *h;
json_object *jobj_type;
json_object_object_foreach(jobj_keyslots, slot, val) {
UNUSED(slot);
if (!json_object_is_type(val, json_type_object) ||
!json_object_object_get_ex(val, "type", &jobj_type) ||
!json_object_is_type(jobj_type, json_type_string))
continue;
h = LUKS2_keyslot_handler_type(NULL, json_object_get_string(jobj_type));
if (h && h->repair)
h->repair(NULL, val);
}
}

View File

@@ -37,7 +37,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
#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.\n"), device_path(device));
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);
@@ -48,7 +48,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
int devfd = -1, r;
/* Only whole sector writes supported */
if (srcLength % SECTOR_SIZE)
if (MISALIGNED_512(srcLength))
return -EINVAL;
/* Encrypt buffer */
@@ -66,7 +66,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
r = device_write_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
log_err(cd, _("Failed to acquire write lock on device %s."),
device_path(device));
return r;
}
@@ -79,6 +79,8 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
r = -EIO;
else
r = 0;
device_sync(device, devfd);
close(devfd);
} else
r = -EIO;
@@ -86,7 +88,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
device_write_unlock(device);
if (r)
log_err(cd, _("IO error while encrypting keyslot.\n"));
log_err(cd, _("IO error while encrypting keyslot."));
return r;
#endif
@@ -100,7 +102,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
int r = device_read_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire read lock on device %s.\n"), device_path(device));
log_err(cd, _("Failed to acquire read lock on device %s."), device_path(device));
return r;
}
r = LUKS_decrypt_from_storage(dst, dstLength, cipher, cipher_mode, vk, sector, cd);
@@ -111,7 +113,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
int devfd = -1, r;
/* Only whole sector writes supported */
if (dstLength % SECTOR_SIZE)
if (MISALIGNED_512(dstLength))
return -EINVAL;
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
@@ -123,7 +125,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
r = device_read_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
log_err(cd, _("Failed to acquire read lock on device %s."),
device_path(device));
crypt_storage_destroy(s);
return r;
@@ -147,13 +149,64 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
if (!r)
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
else
log_err(cd, _("IO error while decrypting keyslot.\n"));
log_err(cd, _("IO error while decrypting keyslot."));
crypt_storage_destroy(s);
return r;
#endif
}
static int luks2_keyslot_get_pbkdf_params(json_object *jobj_keyslot,
struct crypt_pbkdf_type *pbkdf, char *salt)
{
json_object *jobj_kdf, *jobj1, *jobj2;
size_t salt_len;
if (!jobj_keyslot || !pbkdf)
return -EINVAL;
memset(pbkdf, 0, sizeof(*pbkdf));
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf))
return -EINVAL;
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj1))
return -EINVAL;
pbkdf->type = json_object_get_string(jobj1);
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
if (!json_object_object_get_ex(jobj_kdf, "hash", &jobj2))
return -EINVAL;
pbkdf->hash = json_object_get_string(jobj2);
if (!json_object_object_get_ex(jobj_kdf, "iterations", &jobj2))
return -EINVAL;
pbkdf->iterations = json_object_get_int(jobj2);
pbkdf->max_memory_kb = 0;
pbkdf->parallel_threads = 0;
} else {
if (!json_object_object_get_ex(jobj_kdf, "time", &jobj2))
return -EINVAL;
pbkdf->iterations = json_object_get_int(jobj2);
if (!json_object_object_get_ex(jobj_kdf, "memory", &jobj2))
return -EINVAL;
pbkdf->max_memory_kb = json_object_get_int(jobj2);
if (!json_object_object_get_ex(jobj_kdf, "cpus", &jobj2))
return -EINVAL;
pbkdf->parallel_threads = json_object_get_int(jobj2);
}
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj2))
return -EINVAL;
salt_len = LUKS_SALTSIZE;
if (!base64_decode(json_object_get_string(jobj2),
json_object_get_string_len(jobj2),
salt, &salt_len))
return -EINVAL;
if (salt_len != LUKS_SALTSIZE)
return -EINVAL;
return 0;
}
static int luks2_keyslot_set_key(struct crypt_device *cd,
json_object *jobj_keyslot,
const char *password, size_t passwordLen,
@@ -161,11 +214,12 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
{
struct volume_key *derived_key;
char salt[LUKS_SALTSIZE], cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char *AfKey = NULL, *salt_base64 = NULL;
char *AfKey = NULL;
const char *af_hash = NULL;
size_t AFEKSize, keyslot_key_len;
json_object *jobj2, *jobj_kdf, *jobj_af, *jobj_area;
uint64_t area_offset;
const struct crypt_pbkdf_type *pbkdf;
struct crypt_pbkdf_type pbkdf;
int r;
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
@@ -173,6 +227,12 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
/* prevent accidental volume key size change after allocation */
if (!json_object_object_get_ex(jobj_keyslot, "key_size", &jobj2))
return -EINVAL;
if (json_object_get_int(jobj2) != (int)volume_key_len)
return -EINVAL;
if (!json_object_object_get_ex(jobj_area, "offset", &jobj2))
return -EINVAL;
area_offset = json_object_get_uint64(jobj2);
@@ -187,52 +247,27 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
return -EINVAL;
keyslot_key_len = json_object_get_int(jobj2);
pbkdf = crypt_get_pbkdf_type(cd);
if (!pbkdf)
if (!json_object_object_get_ex(jobj_af, "hash", &jobj2))
return -EINVAL;
af_hash = json_object_get_string(jobj2);
if (luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, salt))
return -EINVAL;
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, volume_key_len);
if (r < 0)
return r;
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
json_object_object_add(jobj_kdf, "hash", json_object_new_string(pbkdf->hash));
json_object_object_add(jobj_kdf, "iterations", json_object_new_int(pbkdf->iterations));
} else {
json_object_object_add(jobj_kdf, "time", json_object_new_int(pbkdf->iterations));
json_object_object_add(jobj_kdf, "memory", json_object_new_int(pbkdf->max_memory_kb));
json_object_object_add(jobj_kdf, "cpus", json_object_new_int(pbkdf->parallel_threads));
}
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
/*
* Get salt and allocate derived key storage.
* Allocate derived key storage.
*/
r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
if (r < 0)
return r;
base64_encode_alloc(salt, LUKS_SALTSIZE, &salt_base64);
if (!salt_base64)
return -ENOMEM;
json_object_object_add(jobj_kdf, "salt", json_object_new_string(salt_base64));
free(salt_base64);
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
json_object_object_add(jobj_af, "hash", json_object_new_string(pbkdf->hash));
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
if (!derived_key)
return -ENOMEM;
/*
* Calculate keyslot content, split and store it to keyslot area.
*/
r = crypt_pbkdf(pbkdf->type, pbkdf->hash, password, passwordLen,
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
salt, LUKS_SALTSIZE,
derived_key->key, derived_key->keylength,
pbkdf->iterations, pbkdf->max_memory_kb,
pbkdf->parallel_threads);
pbkdf.iterations, pbkdf.max_memory_kb,
pbkdf.parallel_threads);
if (r < 0) {
crypt_free_volume_key(derived_key);
return r;
@@ -246,7 +281,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
return -ENOMEM;
}
r = AF_split(volume_key, AfKey, volume_key_len, LUKS_STRIPES, pbkdf->hash);
r = AF_split(volume_key, AfKey, volume_key_len, LUKS_STRIPES, af_hash);
if (r == 0) {
log_dbg("Updating keyslot area [0x%04x].", (unsigned)area_offset);
@@ -260,7 +295,6 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
if (r < 0)
return r;
JSON_DBG(jobj_keyslot, "Keyslot JSON");
return 0;
}
@@ -270,53 +304,21 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
char *volume_key, size_t volume_key_len)
{
struct volume_key *derived_key;
struct crypt_pbkdf_type pbkdf;
char *AfKey;
size_t AFEKSize;
const char *hash = NULL, *af_hash = NULL, *kdf;
const char *af_hash = NULL;
char salt[LUKS_SALTSIZE], cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
json_object *jobj1, *jobj2, *jobj_kdf, *jobj_af, *jobj_area;
uint32_t iterations, memory, parallel;
json_object *jobj2, *jobj_af, *jobj_area;
uint64_t area_offset;
size_t salt_len, keyslot_key_len;
size_t keyslot_key_len;
int r;
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj1))
return -EINVAL;
kdf = json_object_get_string(jobj1);
if (!strcmp(kdf, CRYPT_KDF_PBKDF2)) {
if (!json_object_object_get_ex(jobj_kdf, "hash", &jobj2))
return -EINVAL;
hash = json_object_get_string(jobj2);
if (!json_object_object_get_ex(jobj_kdf, "iterations", &jobj2))
return -EINVAL;
iterations = json_object_get_int(jobj2);
memory = 0;
parallel = 0;
} else {
if (!json_object_object_get_ex(jobj_kdf, "time", &jobj2))
return -EINVAL;
iterations = json_object_get_int(jobj2);
if (!json_object_object_get_ex(jobj_kdf, "memory", &jobj2))
return -EINVAL;
memory = json_object_get_int(jobj2);
if (!json_object_object_get_ex(jobj_kdf, "cpus", &jobj2))
return -EINVAL;
parallel = json_object_get_int(jobj2);
}
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj2))
return -EINVAL;
salt_len = LUKS_SALTSIZE;
if (!base64_decode(json_object_get_string(jobj2),
json_object_get_string_len(jobj2),
salt, &salt_len))
return -EINVAL;
if (salt_len != LUKS_SALTSIZE)
if (luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, salt))
return -EINVAL;
if (!json_object_object_get_ex(jobj_af, "hash", &jobj2))
@@ -353,10 +355,11 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
/*
* Calculate derived key, decrypt keyslot content and merge it.
*/
r = crypt_pbkdf(kdf, hash, password, passwordLen,
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
salt, LUKS_SALTSIZE,
derived_key->key, derived_key->keylength,
iterations, memory, parallel);
pbkdf.iterations, pbkdf.max_memory_kb,
pbkdf.parallel_threads);
if (r == 0) {
log_dbg("Reading keyslot area [0x%04x].", (unsigned)area_offset);
@@ -374,16 +377,84 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
return r;
}
int luks2_keyslot_alloc(struct crypt_device *cd,
/*
* currently we support update of only:
*
* - af hash function
* - kdf params
*/
static int luks2_keyslot_update_json(struct crypt_device *cd,
json_object *jobj_keyslot,
const struct luks2_keyslot_params *params)
{
const struct crypt_pbkdf_type *pbkdf;
json_object *jobj_af, *jobj_area, *jobj_kdf, *jobj1;
char salt[LUKS_SALTSIZE], *salt_base64 = NULL;
int r, keyslot_key_len;
/* jobj_keyslot is not yet validated */
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "key_size", &jobj1))
return -EINVAL;
/* we do not allow any 'area' object modifications yet */
keyslot_key_len = json_object_get_int(jobj1);
if (keyslot_key_len < 0)
return -EINVAL;
pbkdf = crypt_get_pbkdf_type(cd);
if (!pbkdf)
return -EINVAL;
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, keyslot_key_len);
if (r < 0)
return r;
/* refresh whole 'kdf' object */
jobj_kdf = json_object_new_object();
if (!jobj_kdf)
return -ENOMEM;
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
json_object_object_add(jobj_kdf, "hash", json_object_new_string(pbkdf->hash));
json_object_object_add(jobj_kdf, "iterations", json_object_new_int(pbkdf->iterations));
} else {
json_object_object_add(jobj_kdf, "time", json_object_new_int(pbkdf->iterations));
json_object_object_add(jobj_kdf, "memory", json_object_new_int(pbkdf->max_memory_kb));
json_object_object_add(jobj_kdf, "cpus", json_object_new_int(pbkdf->parallel_threads));
}
json_object_object_add(jobj_keyslot, "kdf", jobj_kdf);
/*
* Regenerate salt and add it in 'kdf' object
*/
r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
if (r < 0)
return r;
base64_encode_alloc(salt, LUKS_SALTSIZE, &salt_base64);
if (!salt_base64)
return -ENOMEM;
json_object_object_add(jobj_kdf, "salt", json_object_new_string(salt_base64));
free(salt_base64);
/* update 'af' hash */
json_object_object_add(jobj_af, "hash", json_object_new_string(params->af.luks1.hash));
JSON_DBG(jobj_keyslot, "Keyslot JSON");
return 0;
}
static int luks2_keyslot_alloc(struct crypt_device *cd,
int keyslot,
size_t volume_key_len,
const struct luks2_keyslot_params *params)
{
struct luks2_hdr *hdr;
const struct crypt_pbkdf_type *pbkdf;
char num[16];
uint64_t area_offset, area_length;
json_object *jobj_keyslots, *jobj_keyslot, *jobj_kdf, *jobj_af, *jobj_area;
json_object *jobj_keyslots, *jobj_keyslot, *jobj_af, *jobj_area;
int r;
log_dbg("Trying to allocate LUKS2 keyslot %d.", keyslot);
@@ -400,7 +471,7 @@ int luks2_keyslot_alloc(struct crypt_device *cd,
if (keyslot == CRYPT_ANY_SLOT)
keyslot = LUKS2_keyslot_find_empty(hdr, "luks2");
if (keyslot < 0 || keyslot > LUKS2_KEYSLOTS_MAX)
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
return -ENOMEM;
if (LUKS2_get_keyslot_jobj(hdr, keyslot)) {
@@ -415,37 +486,13 @@ int luks2_keyslot_alloc(struct crypt_device *cd,
if (r < 0)
return r;
pbkdf = crypt_get_pbkdf_type(cd);
if (!pbkdf)
return -EINVAL;
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, volume_key_len);
if (r < 0)
return r;
jobj_keyslot = json_object_new_object();
json_object_object_add(jobj_keyslot, "type", json_object_new_string("luks2"));
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(volume_key_len));
/* PBKDF object */
jobj_kdf = json_object_new_object();
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
json_object_object_add(jobj_kdf, "iterations", json_object_new_int(pbkdf->iterations));
json_object_object_add(jobj_kdf, "hash", json_object_new_string(pbkdf->hash));
json_object_object_add(jobj_kdf, "salt", json_object_new_string(""));
} else {
json_object_object_add(jobj_kdf, "time", json_object_new_int(pbkdf->iterations));
json_object_object_add(jobj_kdf, "memory", json_object_new_int(pbkdf->max_memory_kb));
json_object_object_add(jobj_kdf, "cpus", json_object_new_int(pbkdf->parallel_threads));
json_object_object_add(jobj_kdf, "salt", json_object_new_string(""));
}
json_object_object_add(jobj_keyslot, "kdf", jobj_kdf);
/* AF object */
jobj_af = json_object_new_object();
json_object_object_add(jobj_af, "type", json_object_new_string("luks1"));
json_object_object_add(jobj_af, "hash", json_object_new_string(params->af.luks1.hash));
json_object_object_add(jobj_af, "stripes", json_object_new_int(params->af.luks1.stripes));
json_object_object_add(jobj_keyslot, "af", jobj_af);
@@ -461,13 +508,18 @@ int luks2_keyslot_alloc(struct crypt_device *cd,
snprintf(num, sizeof(num), "%d", keyslot);
json_object_object_add(jobj_keyslots, num, jobj_keyslot);
if (LUKS2_check_json_size(hdr)) {
r = luks2_keyslot_update_json(cd, jobj_keyslot, params);
if (!r && LUKS2_check_json_size(hdr)) {
log_dbg("Not enough space in header json area for new keyslot.");
json_object_object_del(jobj_keyslots, num);
return -ENOSPC;
r = -ENOSPC;
}
return 0;
if (r)
json_object_object_del(jobj_keyslots, num);
return r;
}
static int luks2_keyslot_open(struct crypt_device *cd,
@@ -494,6 +546,10 @@ static int luks2_keyslot_open(struct crypt_device *cd,
volume_key, volume_key_len);
}
/*
* This function must not modify json.
* It's called after luks2 keyslot validation.
*/
static int luks2_keyslot_store(struct crypt_device *cd,
int keyslot,
const char *password,
@@ -593,59 +649,47 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
return 0;
}
static int contains(json_object *jobj, const char *key, json_type type)
static int luks2_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
{
json_object *sobj;
json_object *jobj_kdf, *jobj_af, *jobj_area, *jobj1;
const char *type;
int count;
if (!json_object_object_get_ex(jobj, key, &sobj) ||
!json_object_is_type(sobj, type))
return 0;
return 1;
}
static int luks2_keyslot_validate(struct crypt_device *cd, int keyslot)
{
struct luks2_hdr *hdr;
json_object *jobj_keyslot, *jobj_kdf, *jobj_af, *jobj_area, *jobj1;
char num[16];
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -EINVAL;
snprintf(num, sizeof(num), "%d", keyslot);
if (LUKS2_keyslot_validate(hdr->jobj, jobj_keyslot, num))
return -EINVAL;
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj1))
return -EINVAL;
count = json_object_object_length(jobj_kdf);
if (!strcmp(json_object_get_string(jobj1), CRYPT_KDF_PBKDF2)) {
if (!contains(jobj_kdf, "hash", json_type_string) ||
!contains(jobj_kdf, "iterations", json_type_int) ||
!contains(jobj_kdf, "salt", json_type_string))
jobj1 = json_contains(jobj_kdf, "", "kdf section", "type", json_type_string);
if (!jobj1)
return -EINVAL;
type = json_object_get_string(jobj1);
if (!strcmp(type, CRYPT_KDF_PBKDF2)) {
if (count != 4 || /* type, salt, hash, iterations only */
!json_contains(jobj_kdf, "kdf type", type, "hash", json_type_string) ||
!json_contains(jobj_kdf, "kdf type", type, "iterations", json_type_int) ||
!json_contains(jobj_kdf, "kdf type", type, "salt", json_type_string))
return -EINVAL;
} else {
if (!contains(jobj_kdf, "time", json_type_int) ||
!contains(jobj_kdf, "memory", json_type_int) ||
!contains(jobj_kdf, "cpus", json_type_int) ||
!contains(jobj_kdf, "salt", json_type_string))
} else if (!strcmp(type, CRYPT_KDF_ARGON2I) || !strcmp(type, CRYPT_KDF_ARGON2ID)) {
if (count != 5 || /* type, salt, time, memory, cpus only */
!json_contains(jobj_kdf, "kdf type", type, "time", json_type_int) ||
!json_contains(jobj_kdf, "kdf type", type, "memory", json_type_int) ||
!json_contains(jobj_kdf, "kdf type", type, "cpus", json_type_int) ||
!json_contains(jobj_kdf, "kdf type", type, "salt", json_type_string))
return -EINVAL;
}
if (!json_object_object_get_ex(jobj_af, "type", &jobj1))
return -EINVAL;
if (!strcmp(json_object_get_string(jobj1), "luks1")) {
if (!contains(jobj_af, "hash", json_type_string) ||
!contains(jobj_af, "stripes", json_type_int))
if (!json_contains(jobj_af, "", "luks1 af", "hash", json_type_string) ||
!json_contains(jobj_af, "", "luks1 af", "stripes", json_type_int))
return -EINVAL;
} else
return -EINVAL;
@@ -654,10 +698,10 @@ static int luks2_keyslot_validate(struct crypt_device *cd, int keyslot)
if (!json_object_object_get_ex(jobj_area, "type", &jobj1))
return -EINVAL;
if (!strcmp(json_object_get_string(jobj1), "raw")) {
if (!contains(jobj_area, "encryption", json_type_string) ||
!contains(jobj_area, "key_size", json_type_int) ||
!contains(jobj_area, "offset", json_type_string) ||
!contains(jobj_area, "size", json_type_string))
if (!json_contains(jobj_area, "area", "raw type", "encryption", json_type_string) ||
!json_contains(jobj_area, "area", "raw type", "key_size", json_type_int) ||
!json_contains(jobj_area, "area", "raw type", "offset", json_type_string) ||
!json_contains(jobj_area, "area", "raw type", "size", json_type_string))
return -EINVAL;
} else
return -EINVAL;
@@ -665,12 +709,78 @@ static int luks2_keyslot_validate(struct crypt_device *cd, int keyslot)
return 0;
}
static int luks2_keyslot_update(struct crypt_device *cd,
int keyslot,
const struct luks2_keyslot_params *params)
{
struct luks2_hdr *hdr;
json_object *jobj_keyslot;
int r;
log_dbg("Updating LUKS2 keyslot %d.", keyslot);
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -EINVAL;
r = luks2_keyslot_update_json(cd, jobj_keyslot, params);
if (!r && LUKS2_check_json_size(hdr)) {
log_dbg("Not enough space in header json area for updated keyslot %d.", keyslot);
r = -ENOSPC;
}
return r;
}
static void luks2_keyslot_repair(struct crypt_device *cd, json_object *jobj_keyslot)
{
const char *type;
json_object *jobj_kdf, *jobj_type;
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
!json_object_is_type(jobj_kdf, json_type_object))
return;
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj_type) ||
!json_object_is_type(jobj_type, json_type_string))
return;
type = json_object_get_string(jobj_type);
if (!strcmp(type, CRYPT_KDF_PBKDF2)) {
/* type, salt, hash, iterations only */
json_object_object_foreach(jobj_kdf, key, val) {
UNUSED(val);
if (!strcmp(key, "type") || !strcmp(key, "salt") ||
!strcmp(key, "hash") || !strcmp(key, "iterations"))
continue;
json_object_object_del(jobj_kdf, key);
}
} else if (!strcmp(type, CRYPT_KDF_ARGON2I) || !strcmp(type, CRYPT_KDF_ARGON2ID)) {
/* type, salt, time, memory, cpus only */
json_object_object_foreach(jobj_kdf, key, val) {
UNUSED(val);
if (!strcmp(key, "type") || !strcmp(key, "salt") ||
!strcmp(key, "time") || !strcmp(key, "memory") ||
!strcmp(key, "cpus"))
continue;
json_object_object_del(jobj_kdf, key);
}
}
}
const keyslot_handler luks2_keyslot = {
.name = "luks2",
.alloc = luks2_keyslot_alloc,
.update = luks2_keyslot_update,
.open = luks2_keyslot_open,
.store = luks2_keyslot_store,
.wipe = luks2_keyslot_wipe,
.dump = luks2_keyslot_dump,
.validate = luks2_keyslot_validate,
.repair = luks2_keyslot_repair
};

View File

@@ -425,43 +425,48 @@ static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
{
struct device *device = crypt_metadata_device(cd);
void *buf = NULL;
int devfd = -1;
int r = -EIO, devfd = -1;
log_dbg("Moving keyslot areas of size %zu from %jd to %jd.",
buf_size, (intmax_t)offset_from, (intmax_t)offset_to);
// FIXME: export aligned_malloc from utils
if (posix_memalign(&buf, crypt_getpagesize(), buf_size))
return -ENOMEM;
devfd = device_open(device, O_RDWR);
if (devfd == -1) {
log_dbg("Cannot open device %s.", device_path(device));
free(buf);
return -EIO;
}
/* This can safely fail (for block devices). It only allocates space if it is possible. */
if (posix_fallocate(devfd, offset_to, buf_size))
log_dbg("Preallocation (fallocate) of new keyslot area not available.");
/* Try to read *new* area to check that area is there (trimmed backup). */
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), buf, buf_size,
offset_to)!= (ssize_t)buf_size)
goto out;
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), buf, buf_size,
offset_from)!= (ssize_t)buf_size) {
close(devfd);
free(buf);
return -EIO;
}
offset_from)!= (ssize_t)buf_size)
goto out;
if (write_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), buf, buf_size,
offset_to) != (ssize_t)buf_size) {
close(devfd);
free(buf);
return -EIO;
}
offset_to) != (ssize_t)buf_size)
goto out;
r = 0;
out:
device_sync(device, devfd);
close(devfd);
crypt_memzero(buf, buf_size);
free(buf);
return 0;
return r;
}
static int luks_header_in_use(struct crypt_device *cd)
@@ -470,11 +475,41 @@ static int luks_header_in_use(struct crypt_device *cd)
r = lookup_dm_dev_by_uuid(crypt_get_uuid(cd), crypt_get_type(cd));
if (r < 0)
log_err(cd, _("Can not check status of device with uuid: %s.\n"), crypt_get_uuid(cd));
log_err(cd, _("Can not check status of device with uuid: %s."), crypt_get_uuid(cd));
return r;
}
/* 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)
{
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(device, O_RDONLY);
if (devfd == -1) {
free(buf);
return -EIO;
}
/* Note: we must not detect failure as problem here, header can be trimmed. */
if (read_lseek_blockwise(devfd, device_block_size(device), device_alignment(device),
buf, sizeof(LM_MAGIC), luks1_size) == (ssize_t)sizeof(LM_MAGIC) &&
!memcmp(LM_MAGIC, buf, sizeof(LM_MAGIC))) {
log_err(cd, _("Unable to convert header with LUKSMETA additional metadata."));
r = -EBUSY;
}
close(devfd);
free(buf);
return r;
}
/* Convert LUKS1 -> LUKS2 */
int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct luks2_hdr *hdr2)
{
@@ -488,6 +523,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
return r;
luks1_size = LUKS_device_sectors(hdr1) << SECTOR_SHIFT;
luks1_size = size_round_up(luks1_size, LUKS_ALIGN_KEYSLOTS);
if (!luks1_size)
return -EINVAL;
@@ -496,10 +532,13 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
return -EINVAL;
}
if (luksmeta_header_present(cd, luks1_size))
return -EINVAL;
log_dbg("Max size: %" PRIu64 ", LUKS1 (full) header size %zu , required shift: %zu",
max_size, luks1_size, luks1_shift);
if ((max_size - luks1_size) < luks1_shift) {
log_err(cd, _("Unable to move keyslot materials. Not enough space\n"));
log_err(cd, _("Unable to move keyslot area. Not enough space."));
return -EINVAL;
}
@@ -538,8 +577,10 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
// move keyslots 4k -> 32k offset
buf_offset = 2 * LUKS2_HDR_16K_LEN;
buf_size = luks1_size - LUKS_ALIGN_KEYSLOTS;
if ((r = move_keyslot_areas(cd, 8 * SECTOR_SIZE, buf_offset, buf_size)) < 0)
if ((r = move_keyslot_areas(cd, 8 * SECTOR_SIZE, buf_offset, buf_size)) < 0) {
log_err(cd, _("Unable to move keyslot area."));
goto out;
}
// Write JSON hdr2
r = LUKS2_hdr_write(cd, hdr2);
@@ -582,6 +623,7 @@ static int keyslot_LUKS1_compatible(struct luks2_hdr *hdr, int keyslot, uint32_t
return 0;
/* FIXME: should this go to validation code instead (aka invalid luks2 header if assigned to segment 0)? */
/* FIXME: check all keyslots are assigned to segment id 0, and segments count == 1 */
ks_key_size = LUKS2_get_keyslot_key_size(hdr, keyslot);
if (ks_key_size < 0 || (int)key_size != LUKS2_get_keyslot_key_size(hdr, keyslot)) {
log_dbg("Key length in keyslot %d is different from volume key length", keyslot);
@@ -603,14 +645,13 @@ static int keyslot_LUKS1_compatible(struct luks2_hdr *hdr, int keyslot, uint32_t
int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct luks_phdr *hdr1)
{
size_t buf_size, buf_offset;
char cipher[LUKS_CIPHERNAME_L], cipher_mode[LUKS_CIPHERMODE_L];
char cipher[LUKS_CIPHERNAME_L-1], cipher_mode[LUKS_CIPHERMODE_L-1];
char digest[LUKS_DIGESTSIZE], digest_salt[LUKS_SALTSIZE];
size_t len;
json_object *jobj_keyslot, *jobj_digest, *jobj_segment, *jobj_kdf, *jobj_area, *jobj1, *jobj2;
uint32_t key_size;
int i, r, last_active = 0;
uint64_t offset, area_length;
struct luks2_keyslot_params params;
char buf[256], luksMagic[] = LUKS_MAGIC;
jobj_digest = LUKS2_get_digest_jobj(hdr2, 0);
@@ -625,37 +666,48 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (!json_object_object_get_ex(jobj_digest, "type", &jobj2) ||
strcmp(json_object_get_string(jobj2), "pbkdf2") ||
json_object_object_length(jobj1) != 1) {
log_err(cd, _("Cannot convert to LUKS1 format - key slot digests are not LUKS1 compatible.\n"));
log_err(cd, _("Cannot convert to LUKS1 format - key slot digests are not LUKS1 compatible."));
return -EINVAL;
}
/* We really do not care about params later except keys_size */
r = LUKS2_keyslot_params_default(cd, hdr2, 0, &params);
r = crypt_parse_name_and_mode(LUKS2_get_cipher(hdr2, CRYPT_DEFAULT_SEGMENT), cipher, NULL, cipher_mode);
if (r < 0)
return r;
if (crypt_cipher_wrapped_key(cipher)) {
log_err(cd, _("Cannot convert to LUKS1 format - device uses wrapped key cipher %s."), cipher);
return -EINVAL;
}
r = LUKS2_tokens_count(hdr2);
if (r < 0)
return r;
if (r > 0) {
log_err(cd, _("Cannot convert to LUKS1 format - LUKS2 header contains %u token(s)."), r);
return -EINVAL;
}
r = LUKS2_get_volume_key_size(hdr2, 0);
if (r < 0)
return -EINVAL;
key_size = r;
params.area.raw.key_size = key_size;
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INACTIVE)
continue;
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INVALID) {
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is in invalid state.\n"), i);
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is in invalid state."), i);
return -EINVAL;
}
if (i >= LUKS_NUMKEYS) {
log_err(cd, _("Cannot convert to LUKS1 format - slot %u (over maximum slots) is still active.\n"), i);
log_err(cd, _("Cannot convert to LUKS1 format - slot %u (over maximum slots) is still active."), i);
return -EINVAL;
}
if (!keyslot_LUKS1_compatible(hdr2, i, key_size)) {
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is not LUKS1 compatible.\n"), i);
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is not LUKS1 compatible."), i);
return -EINVAL;
}
}
@@ -677,8 +729,12 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
} else {
if (LUKS2_find_area_gap(cd, hdr2, key_size, &offset, &area_length))
return -EINVAL;
/* FIXME: luks2 reload is required! */
if (luks2_keyslot_alloc(cd, i, key_size, &params))
/*
* We have to create placeholder luks2 keyslots in place of all
* inactive keyslots. Otherwise we would allocate all
* inactive luks1 keyslots over same binary keyslot area.
*/
if (placeholder_keyslot_alloc(cd, i, offset, area_length, key_size))
return -EINVAL;
}
@@ -773,7 +829,8 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
/* FIXME: LUKS1 requires offset == 0 || offset >= luks1_hdr_size */
hdr1->payloadOffset = offset;
strncpy(hdr1->uuid, hdr2->uuid, UUID_STRING_L - 1); /* max 36 chars */
strncpy(hdr1->uuid, hdr2->uuid, UUID_STRING_L); /* max 36 chars */
hdr1->uuid[UUID_STRING_L-1] = '\0';
memcpy(hdr1->magic, luksMagic, LUKS_MAGIC_L);
@@ -787,8 +844,10 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
buf_offset = 2 * LUKS2_HDR_16K_LEN;
buf_size = LUKS2_keyslots_size(hdr2->jobj);
r = move_keyslot_areas(cd, buf_offset, 8 * SECTOR_SIZE, buf_size);
if (r < 0)
if (r < 0) {
log_err(cd, _("Unable to move keyslot area."));
return r;
}
crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_ZERO, 0,
8 * SECTOR_SIZE, 8 * SECTOR_SIZE, NULL, NULL);

View File

@@ -182,6 +182,7 @@ int LUKS2_token_create(struct crypt_device *cd,
if (h && h->validate && h->validate(cd, json)) {
json_object_put(jobj);
log_dbg("Token type %s validation failed.", h->name);
return -EINVAL;
}
@@ -262,7 +263,7 @@ int LUKS2_builtin_token_create(struct crypt_device *cd,
if (token == CRYPT_ANY_TOKEN) {
if ((token = LUKS2_token_find_free(hdr)) < 0)
log_err(cd, _("No free token slot\n"));
log_err(cd, _("No free token slot."));
}
if (token < 0 || token >= LUKS2_TOKENS_MAX)
return -EINVAL;
@@ -270,14 +271,15 @@ int LUKS2_builtin_token_create(struct crypt_device *cd,
r = th->set(&jobj_token, params);
if (r) {
log_err(cd, _("Failed to create builtin token %s\n"), type);
log_err(cd, _("Failed to create builtin token %s."), type);
return r;
}
// builtin tokens must produce valid json
r = LUKS2_token_validate(hdr->jobj, jobj_token, "new");
assert(!r);
r = th->h->validate(cd, json_object_to_json_string_ext(jobj_token, JSON_C_TO_STRING_PLAIN));
r = th->h->validate(cd, json_object_to_json_string_ext(jobj_token,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE));
assert(!r);
json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens);
@@ -396,7 +398,8 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
return r;
r = LUKS2_keyslot_open_by_token(cd, hdr, token,
name ? CRYPT_DEFAULT_SEGMENT : CRYPT_ANY_SEGMENT,
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ?
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
buffer, buffer_len, &vk);
LUKS2_token_buffer_free(cd, token, buffer, buffer_len);
@@ -441,7 +444,8 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
continue;
r = LUKS2_keyslot_open_by_token(cd, hdr, token,
name ? CRYPT_DEFAULT_SEGMENT : CRYPT_ANY_SEGMENT,
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ?
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
buffer, buffer_len, &vk);
LUKS2_token_buffer_free(cd, token, buffer, buffer_len);
if (r >= 0)
@@ -472,7 +476,8 @@ void LUKS2_token_dump(struct crypt_device *cd, int token)
if (h && h->dump) {
jobj_token = LUKS2_get_token_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), token);
if (jobj_token)
h->dump(cd, json_object_to_json_string_ext(jobj_token, JSON_C_TO_STRING_PLAIN));
h->dump(cd, json_object_to_json_string_ext(jobj_token,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE));
}
}
@@ -485,7 +490,8 @@ int LUKS2_token_json_get(struct crypt_device *cd, struct luks2_hdr *hdr,
if (!jobj_token)
return -EINVAL;
*json = json_object_to_json_string_ext(jobj_token, JSON_C_TO_STRING_PLAIN);
*json = json_object_to_json_string_ext(jobj_token,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
return 0;
}
@@ -594,3 +600,12 @@ int LUKS2_token_is_assigned(struct crypt_device *cd, struct luks2_hdr *hdr,
return -ENOENT;
}
int LUKS2_tokens_count(struct luks2_hdr *hdr)
{
json_object *jobj_tokens = LUKS2_get_tokens_jobj(hdr);
if (!jobj_tokens)
return -EINVAL;
return json_object_object_length(jobj_tokens);
}

View File

@@ -167,13 +167,13 @@ int crypt_random_init(struct crypt_device *ctx)
goto fail;
if (crypt_fips_mode())
log_verbose(ctx, _("Running in FIPS mode.\n"));
log_verbose(ctx, _("Running in FIPS mode."));
random_initialised = 1;
return 0;
fail:
crypt_random_exit();
log_err(ctx, _("Fatal error during RNG initialisation.\n"));
log_err(ctx, _("Fatal error during RNG initialisation."));
return -ENOSYS;
}
@@ -210,12 +210,12 @@ int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int qualit
}
break;
default:
log_err(ctx, _("Unknown RNG quality requested.\n"));
log_err(ctx, _("Unknown RNG quality requested."));
return -EINVAL;
}
if (status)
log_err(ctx, _("Error reading from RNG.\n"));
log_err(ctx, _("Error reading from RNG."));
return status;
}

File diff suppressed because it is too large Load Diff

View File

@@ -37,19 +37,23 @@ static const struct {
const char *name;
const char *hash;
unsigned int iterations;
uint32_t veracrypt_pim_const;
uint32_t veracrypt_pim_mult;
} tcrypt_kdf[] = {
{ 0, 0, "pbkdf2", "ripemd160", 2000 },
{ 0, 0, "pbkdf2", "ripemd160", 1000 },
{ 0, 0, "pbkdf2", "sha512", 1000 },
{ 0, 0, "pbkdf2", "whirlpool", 1000 },
{ 1, 0, "pbkdf2", "sha1", 2000 },
{ 0, 1, "pbkdf2", "sha512", 500000 },
{ 0, 1, "pbkdf2", "ripemd160", 655331 },
{ 0, 1, "pbkdf2", "ripemd160", 327661 }, // boot only
{ 0, 1, "pbkdf2", "whirlpool", 500000 },
{ 0, 1, "pbkdf2", "sha256", 500000 }, // VeraCrypt 1.0f
{ 0, 1, "pbkdf2", "sha256", 200000 }, // boot only
{ 0, 0, NULL, NULL, 0 }
{ 0, 0, "pbkdf2", "ripemd160", 2000, 0, 0 },
{ 0, 0, "pbkdf2", "ripemd160", 1000, 0, 0 },
{ 0, 0, "pbkdf2", "sha512", 1000, 0, 0 },
{ 0, 0, "pbkdf2", "whirlpool", 1000, 0, 0 },
{ 1, 0, "pbkdf2", "sha1", 2000, 0, 0 },
{ 0, 1, "pbkdf2", "sha512", 500000, 15000, 1000 },
{ 0, 1, "pbkdf2", "whirlpool", 500000, 15000, 1000 },
{ 0, 1, "pbkdf2", "sha256", 500000, 15000, 1000 }, // VeraCrypt 1.0f
{ 0, 1, "pbkdf2", "sha256", 200000, 0, 2048 }, // boot only
{ 0, 1, "pbkdf2", "ripemd160", 655331, 15000, 1000 },
{ 0, 1, "pbkdf2", "ripemd160", 327661, 0, 2048 }, // boot only
{ 0, 1, "pbkdf2", "stribog512",500000, 15000, 1000 },
// { 0, 1, "pbkdf2", "stribog512",200000, 0, 2048 }, // boot only
{ 0, 0, NULL, NULL, 0, 0, 0 }
};
struct tcrypt_alg {
@@ -96,6 +100,26 @@ static struct tcrypt_algs tcrypt_cipher[] = {
{0,2,128,"serpent-twofish","xts-plain64",
{{"serpent",64,16, 0,64,0},
{"twofish",64,16,32,96,0}}},
{0,1,64,"camellia","xts-plain64",
{{"camellia", 64,16,0,32,0}}},
{0,1,64,"kuznyechik","xts-plain64",
{{"kuznyechik", 64,16,0,32,0}}},
{0,2,128,"kuznyechik-camellia","xts-plain64",
{{"kuznyechik",64,16, 0,64,0},
{"camellia", 64,16,32,96,0}}},
{0,2,128,"twofish-kuznyechik","xts-plain64",
{{"twofish", 64,16, 0,64,0},
{"kuznyechik",64,16,32,96,0}}},
{0,2,128,"serpent-camellia","xts-plain64",
{{"serpent", 64,16, 0,64,0},
{"camellia", 64,16,32,96,0}}},
{0,2,128,"aes-kuznyechik","xts-plain64",
{{"aes", 64,16, 0,64,0},
{"kuznyechik",64,16,32,96,0}}},
{0,3,192,"camellia-serpent-kuznyechik","xts-plain64",
{{"camellia", 64,16, 0, 96,0},
{"serpent", 64,16,32,128,0},
{"kuznyechik",64,16,64,160,0}}},
/* LRW mode */
{0,1,48,"aes","lrw-benbi",
@@ -470,14 +494,14 @@ static int TCRYPT_pool_keyfile(struct crypt_device *cd,
fd = open(keyfile, O_RDONLY);
if (fd < 0) {
log_err(cd, _("Failed to open key file.\n"));
log_err(cd, _("Failed to open key file."));
goto out;
}
data_size = read_buffer(fd, data, TCRYPT_KEYFILE_LEN);
close(fd);
if (data_size < 0) {
log_err(cd, _("Error reading keyfile %s.\n"), keyfile);
log_err(cd, _("Error reading keyfile %s."), keyfile);
goto out;
}
@@ -517,7 +541,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
passphrase_size = params->passphrase_size;
if (params->passphrase_size > TCRYPT_KEY_POOL_LEN) {
log_err(cd, _("Maximum TCRYPT passphrase length (%d) exceeded.\n"),
log_err(cd, _("Maximum TCRYPT passphrase length (%d) exceeded."),
TCRYPT_KEY_POOL_LEN);
goto out;
}
@@ -543,10 +567,8 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
if (!tcrypt_kdf[i].veracrypt)
continue;
/* adjust iterations to given PIM cmdline parameter */
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER)
iterations = params->veracrypt_pim * 2048;
else
iterations = 15000 + (params->veracrypt_pim * 1000);
iterations = tcrypt_kdf[i].veracrypt_pim_const +
(tcrypt_kdf[i].veracrypt_pim_mult * params->veracrypt_pim);
} else
iterations = tcrypt_kdf[i].iterations;
@@ -560,7 +582,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
key, TCRYPT_HDR_KEY_LEN,
iterations, 0, 0);
if (r < 0 && crypt_hash_size(tcrypt_kdf[i].hash) < 0) {
log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping.\n"),
log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping."),
tcrypt_kdf[i].hash);
continue;
}
@@ -578,9 +600,9 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
}
if ((r < 0 && r != -EPERM && skipped && skipped == i) || r == -ENOTSUP) {
log_err(cd, _("Required kernel crypto interface not available.\n"));
log_err(cd, _("Required kernel crypto interface not available."));
#ifdef ENABLE_AF_ALG
log_err(cd, _("Ensure you have algif_skcipher kernel module loaded.\n"));
log_err(cd, _("Ensure you have algif_skcipher kernel module loaded."));
#endif
}
if (r < 0)
@@ -637,7 +659,7 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
devfd = device_open(device, O_RDONLY);
if (devfd < 0) {
log_err(cd, _("Cannot open device %s.\n"), device_path(device));
log_err(cd, _("Cannot open device %s."), device_path(device));
return -EINVAL;
}
@@ -726,13 +748,13 @@ int TCRYPT_activate(struct crypt_device *cd,
}
if (hdr->d.sector_size && hdr->d.sector_size != SECTOR_SIZE) {
log_err(cd, _("Activation is not supported for %d sector size.\n"),
log_err(cd, _("Activation is not supported for %d sector size."),
hdr->d.sector_size);
return -ENOTSUP;
}
if (strstr(params->mode, "-tcrypt")) {
log_err(cd, _("Kernel doesn't support activation for this TCRYPT legacy mode.\n"));
log_err(cd, _("Kernel doesn't support activation for this TCRYPT legacy mode."));
return -ENOTSUP;
}
@@ -766,7 +788,7 @@ int TCRYPT_activate(struct crypt_device *cd,
dmd.u.crypt.offset, dmd.size);
if (part_path) {
if (!device_alloc(&part_device, part_path)) {
log_verbose(cd, _("Activating TCRYPT system encryption for partition %s.\n"),
log_verbose(cd, _("Activating TCRYPT system encryption for partition %s."),
part_path);
dmd.data_device = part_device;
dmd.u.crypt.offset = 0;
@@ -834,7 +856,7 @@ int TCRYPT_activate(struct crypt_device *cd,
if (r < 0 &&
(dm_flags(DM_CRYPT, &dmc_flags) || ((dmc_flags & req_flags) != req_flags))) {
log_err(cd, _("Kernel doesn't support TCRYPT compatible mapping.\n"));
log_err(cd, _("Kernel doesn't support TCRYPT compatible mapping."));
r = -ENOTSUP;
}

View File

@@ -22,13 +22,10 @@
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>
@@ -63,255 +60,6 @@ uint64_t crypt_getphysmemory_kb(void)
return phys_memory_kb;
}
ssize_t read_buffer(int fd, void *buf, size_t count)
{
size_t read_size = 0;
ssize_t r;
if (fd < 0 || !buf)
return -EINVAL;
do {
r = read(fd, buf, count - read_size);
if (r == -1 && errno != EINTR)
return r;
if (r == 0)
return (ssize_t)read_size;
if (r > 0) {
read_size += (size_t)r;
buf = (uint8_t*)buf + r;
}
} while (read_size != count);
return (ssize_t)count;
}
ssize_t write_buffer(int fd, const void *buf, size_t count)
{
size_t write_size = 0;
ssize_t w;
if (fd < 0 || !buf || !count)
return -EINVAL;
do {
w = write(fd, buf, count - write_size);
if (w < 0 && errno != EINTR)
return w;
if (w == 0)
return (ssize_t)write_size;
if (w > 0) {
write_size += (size_t) w;
buf = (const uint8_t*)buf + w;
}
} while (write_size != count);
return (ssize_t)write_size;
}
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment,
void *orig_buf, size_t count)
{
void *hangover_buf = NULL, *buf = NULL;
size_t hangover, solid;
ssize_t r, ret = -1;
if (fd == -1 || !orig_buf || !bsize || !alignment)
return -1;
hangover = count % bsize;
solid = count - hangover;
if ((size_t)orig_buf & (alignment - 1)) {
if (posix_memalign(&buf, alignment, count))
return -1;
memcpy(buf, orig_buf, count);
} else
buf = orig_buf;
if (solid) {
r = write_buffer(fd, buf, solid);
if (r < 0 || r != (ssize_t)solid)
goto out;
}
if (hangover) {
if (posix_memalign(&hangover_buf, alignment, bsize))
goto out;
r = read_buffer(fd, hangover_buf, bsize);
if (r < 0 || r < (ssize_t)hangover)
goto out;
if (r < (ssize_t)bsize)
bsize = r;
if (lseek(fd, -(off_t)bsize, SEEK_CUR) < 0)
goto out;
memcpy(hangover_buf, (char*)buf + solid, hangover);
r = write_buffer(fd, hangover_buf, bsize);
if (r < 0 || r < (ssize_t)hangover)
goto out;
}
ret = count;
out:
free(hangover_buf);
if (buf != orig_buf)
free(buf);
return ret;
}
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment,
void *orig_buf, size_t count)
{
void *hangover_buf = NULL, *buf = NULL;
size_t hangover, solid;
ssize_t r, ret = -1;
if (fd == -1 || !orig_buf || !bsize || !alignment)
return -1;
hangover = count % bsize;
solid = count - hangover;
if ((size_t)orig_buf & (alignment - 1)) {
if (posix_memalign(&buf, alignment, count))
return -1;
} else
buf = orig_buf;
r = read_buffer(fd, buf, solid);
if (r < 0 || r != (ssize_t)solid)
goto out;
if (hangover) {
if (posix_memalign(&hangover_buf, alignment, bsize))
goto out;
r = read_buffer(fd, hangover_buf, bsize);
if (r < 0 || r < (ssize_t)hangover)
goto out;
memcpy((char *)buf + solid, hangover_buf, hangover);
}
ret = count;
out:
free(hangover_buf);
if (buf != orig_buf) {
memcpy(orig_buf, buf, count);
free(buf);
}
return ret;
}
/*
* Combines llseek with blockwise write. write_blockwise can already deal with short writes
* but we also need a function to deal with short writes at the start. But this information
* is implicitly included in the read/write offset, which can not be set to non-aligned
* boundaries. Hence, we combine llseek with write.
*/
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment,
void *buf, size_t count, off_t offset)
{
void *frontPadBuf = NULL;
size_t frontHang, innerCount = 0;
ssize_t r, ret = -1;
if (fd == -1 || !buf || !bsize || !alignment)
return -1;
if (offset < 0)
offset = lseek(fd, offset, SEEK_END);
if (offset < 0)
return -1;
frontHang = offset % bsize;
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
return -1;
if (frontHang) {
if (posix_memalign(&frontPadBuf, alignment, bsize))
return -1;
innerCount = bsize - frontHang;
if (innerCount > count)
innerCount = count;
r = read_buffer(fd, frontPadBuf, bsize);
if (r < 0 || r < (ssize_t)(frontHang + innerCount))
goto out;
memcpy((char*)frontPadBuf + frontHang, buf, innerCount);
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
goto out;
r = write_buffer(fd, frontPadBuf, frontHang + innerCount);
if (r < 0 || r != (ssize_t)(frontHang + innerCount))
goto out;
buf = (char*)buf + innerCount;
count -= innerCount;
}
ret = count ? write_blockwise(fd, bsize, alignment, buf, count) : 0;
if (ret >= 0)
ret += innerCount;
out:
free(frontPadBuf);
return ret;
}
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment,
void *buf, size_t count, off_t offset)
{
void *frontPadBuf = NULL;
size_t frontHang, innerCount = 0;
ssize_t r, ret = -1;
if (fd == -1 || !buf || bsize <= 0)
return -1;
if (offset < 0)
offset = lseek(fd, offset, SEEK_END);
if (offset < 0)
return -1;
frontHang = offset % bsize;
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
return -1;
if (frontHang) {
if (posix_memalign(&frontPadBuf, alignment, bsize))
return -1;
innerCount = bsize - frontHang;
if (innerCount > count)
innerCount = count;
r = read_buffer(fd, frontPadBuf, bsize);
if (r < 0 || r < (ssize_t)(frontHang + innerCount))
goto out;
memcpy(buf, (char*)frontPadBuf + frontHang, innerCount);
buf = (char*)buf + innerCount;
count -= innerCount;
}
ret = read_blockwise(fd, bsize, alignment, buf, count);
if (ret >= 0)
ret += innerCount;
out:
free(frontPadBuf);
return ret;
}
/* MEMLOCK */
#define DEFAULT_PROCESS_PRIORITY -18
@@ -330,7 +78,7 @@ int crypt_memlock_inc(struct crypt_device *ctx)
}
errno = 0;
if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno)
log_err(ctx, _("Cannot get process priority.\n"));
log_err(ctx, _("Cannot get process priority."));
else
if (setpriority(PRIO_PROCESS, 0, DEFAULT_PROCESS_PRIORITY))
log_dbg("setpriority %d failed: %s",
@@ -344,7 +92,7 @@ int crypt_memlock_dec(struct crypt_device *ctx)
if (_memlock_count && (!--_memlock_count)) {
log_dbg("Unlocking memory.");
if (munlockall() == -1)
log_err(ctx, _("Cannot unlock memory.\n"));
log_err(ctx, _("Cannot unlock memory."));
if (setpriority(PRIO_PROCESS, 0, _priority))
log_dbg("setpriority %d failed: %s", _priority, strerror(errno));
}
@@ -400,7 +148,7 @@ static int keyfile_seek(int fd, uint64_t bytes)
int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
char **key, size_t *key_size_read,
uint64_t keyfile_offset, size_t keyfile_size_max,
uint64_t keyfile_offset, size_t key_size,
uint32_t flags)
{
int fd, regular_file, char_to_read = 0, char_read = 0, unlimited_read = 0;
@@ -418,29 +166,29 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
fd = keyfile ? open(keyfile, O_RDONLY) : STDIN_FILENO;
if (fd < 0) {
log_err(cd, _("Failed to open key file.\n"));
log_err(cd, _("Failed to open key file."));
return -EINVAL;
}
if (isatty(fd)) {
log_err(cd, _("Cannot read keyfile from a terminal.\n"));
log_err(cd, _("Cannot read keyfile from a terminal."));
r = -EINVAL;
goto out_err;
}
/* If not requested otherwise, we limit input to prevent memory exhaustion */
if (keyfile_size_max == 0) {
keyfile_size_max = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1;
if (key_size == 0) {
key_size = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1;
unlimited_read = 1;
/* use 4k for buffer (page divisor but avoid huge pages) */
buflen = 4096 - sizeof(struct safe_allocation);
} else
buflen = keyfile_size_max;
buflen = key_size;
regular_file = 0;
if (keyfile) {
if (stat(keyfile, &st) < 0) {
log_err(cd, _("Failed to stat key file.\n"));
log_err(cd, _("Failed to stat key file."));
goto out_err;
}
if (S_ISREG(st.st_mode)) {
@@ -448,14 +196,14 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
file_read_size = (uint64_t)st.st_size;
if (keyfile_offset > file_read_size) {
log_err(cd, _("Cannot seek to requested keyfile offset.\n"));
log_err(cd, _("Cannot seek to requested keyfile offset."));
goto out_err;
}
file_read_size -= keyfile_offset;
/* known keyfile size, alloc it in one step */
if (file_read_size >= (uint64_t)keyfile_size_max)
buflen = keyfile_size_max;
if (file_read_size >= (uint64_t)key_size)
buflen = key_size;
else if (file_read_size)
buflen = file_read_size;
}
@@ -463,22 +211,22 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
pass = crypt_safe_alloc(buflen);
if (!pass) {
log_err(cd, _("Out of memory while reading passphrase.\n"));
log_err(cd, _("Out of memory while reading passphrase."));
goto out_err;
}
/* Discard keyfile_offset bytes on input */
if (keyfile_offset && keyfile_seek(fd, keyfile_offset) < 0) {
log_err(cd, _("Cannot seek to requested keyfile offset.\n"));
log_err(cd, _("Cannot seek to requested keyfile offset."));
goto out_err;
}
for (i = 0, newline = 0; i < keyfile_size_max; i += char_read) {
for (i = 0, newline = 0; i < key_size; i += char_read) {
if (i == buflen) {
buflen += 4096;
pass = crypt_safe_realloc(pass, buflen);
if (!pass) {
log_err(cd, _("Out of memory while reading passphrase.\n"));
log_err(cd, _("Out of memory while reading passphrase."));
r = -ENOMEM;
goto out_err;
}
@@ -492,13 +240,13 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
*/
char_to_read = 1;
} else {
/* char_to_read = min(keyfile_size_max - i, buflen - i) */
char_to_read = keyfile_size_max < buflen ?
keyfile_size_max - i : buflen - i;
/* char_to_read = min(key_size - i, buflen - i) */
char_to_read = key_size < buflen ?
key_size - i : buflen - i;
}
char_read = read_buffer(fd, &pass[i], char_to_read);
if (char_read < 0) {
log_err(cd, _("Error reading passphrase.\n"));
log_err(cd, _("Error reading passphrase."));
r = -EPIPE;
goto out_err;
}
@@ -515,19 +263,19 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
/* Fail if piped input dies reading nothing */
if (!i && !regular_file && !newline) {
log_dbg("Nothing read on input.");
log_err(cd, _("Nothing to read on input."));
r = -EPIPE;
goto out_err;
}
/* Fail if we exceeded internal default (no specified size) */
if (unlimited_read && i == keyfile_size_max) {
log_err(cd, _("Maximum keyfile size exceeded.\n"));
if (unlimited_read && i == key_size) {
log_err(cd, _("Maximum keyfile size exceeded."));
goto out_err;
}
if (!unlimited_read && i != keyfile_size_max) {
log_err(cd, _("Cannot read requested amount of data.\n"));
if (!unlimited_read && i != key_size) {
log_err(cd, _("Cannot read requested amount of data."));
goto out_err;
}

View File

@@ -294,21 +294,20 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
uint32_t ms_tmp;
int r = -EINVAL;
/* Already benchmarked */
if (pbkdf->iterations) {
log_dbg("Reusing PBKDF values.");
return 0;
}
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) {
log_err(cd, _("PBKDF benchmark disabled but iterations not set.\n"));
return -EINVAL;
}
r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
if (r)
return r;
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) {
if (pbkdf->iterations) {
log_dbg("Reusing PBKDF values (no benchmark flag is set).");
return 0;
}
log_err(cd, _("PBKDF benchmark disabled but iterations not set."));
return -EINVAL;
}
/* For PBKDF2 run benchmark always. Also note it depends on volume_key_size! */
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
/*
* For PBKDF2 it is enough to run benchmark for only 1 second
@@ -323,7 +322,7 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
volume_key_size, &benchmark_callback, pbkdf);
pbkdf->time_ms = ms_tmp;
if (r < 0) {
log_err(cd, _("Not compatible PBKDF2 options (using hash algorithm %s).\n"),
log_err(cd, _("Not compatible PBKDF2 options (using hash algorithm %s)."),
pbkdf->hash);
return r;
}
@@ -333,11 +332,17 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
return -EINVAL;
pbkdf->iterations = at_least((uint32_t)PBKDF2_tmp, pbkdf_limits.min_iterations);
} else {
/* Already benchmarked */
if (pbkdf->iterations) {
log_dbg("Reusing PBKDF values.");
return 0;
}
r = crypt_benchmark_pbkdf(cd, pbkdf, "foo", 3,
"0123456789abcdef0123456789abcdef", 32,
volume_key_size, &benchmark_callback, pbkdf);
if (r < 0)
log_err(cd, _("Not compatible PBKDF options.\n"));
log_err(cd, _("Not compatible PBKDF options."));
}
return r;

309
lib/utils_blkid.c Normal file
View File

@@ -0,0 +1,309 @@
/*
* blkid probe utilities
*
* Copyright (C) 2018, Red Hat, Inc. All rights reserved.
*
* 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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "utils_blkid.h"
#include "utils_io.h"
#ifdef HAVE_BLKID
#include <blkid/blkid.h>
/* make bad checksums flag optional */
#ifndef BLKID_SUBLKS_BADCSUM
#define BLKID_SUBLKS_BADCSUM 0
#endif
struct blkid_handle {
int fd;
blkid_probe pr;
};
#ifndef HAVE_BLKID_WIPE
static size_t crypt_getpagesize(void)
{
long r = sysconf(_SC_PAGESIZE);
return r <= 0 ? 4096 : (size_t)r;
}
#endif
#endif
void blk_set_chains_for_wipes(struct blkid_handle *h)
{
#ifdef HAVE_BLKID
blkid_probe_enable_partitions(h->pr, 1);
blkid_probe_set_partitions_flags(h->pr, 0
#ifdef HAVE_BLKID_WIPE
| BLKID_PARTS_MAGIC
#endif
);
blkid_probe_enable_superblocks(h->pr, 1);
blkid_probe_set_superblocks_flags(h->pr, BLKID_SUBLKS_LABEL |
BLKID_SUBLKS_UUID |
BLKID_SUBLKS_TYPE |
BLKID_SUBLKS_USAGE |
BLKID_SUBLKS_VERSION |
BLKID_SUBLKS_MAGIC |
BLKID_SUBLKS_BADCSUM);
#endif
}
void blk_set_chains_for_full_print(struct blkid_handle *h)
{
blk_set_chains_for_wipes(h);
}
void blk_set_chains_for_fast_detection(struct blkid_handle *h)
{
#ifdef HAVE_BLKID
blkid_probe_enable_partitions(h->pr, 1);
blkid_probe_set_partitions_flags(h->pr, 0);
blkid_probe_enable_superblocks(h->pr, 1);
blkid_probe_set_superblocks_flags(h->pr, BLKID_SUBLKS_TYPE);
#endif
}
int blk_init_by_path(struct blkid_handle **h, const char *path)
{
int r = -ENOTSUP;
#ifdef HAVE_BLKID
struct blkid_handle *tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
tmp->fd = -1;
tmp->pr = blkid_new_probe_from_filename(path);
if (!tmp->pr) {
free(tmp);
return -EINVAL;
}
*h = tmp;
r = 0;
#endif
return r;
}
int blk_init_by_fd(struct blkid_handle **h, int fd)
{
int r = -ENOTSUP;
#ifdef HAVE_BLKID
struct blkid_handle *tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
tmp->pr = blkid_new_probe();
if (!tmp->pr) {
free(tmp);
return -EINVAL;
}
if (blkid_probe_set_device(tmp->pr, fd, 0, 0)) {
blkid_free_probe(tmp->pr);
free(tmp);
return -EINVAL;
}
tmp->fd = fd;
*h = tmp;
r = 0;
#endif
return r;
}
int blk_superblocks_filter_luks(struct blkid_handle *h)
{
int r = -ENOTSUP;
#ifdef HAVE_BLKID
char luks[] = "crypto_LUKS";
char *luks_filter[] = {
luks,
NULL
};
r = blkid_probe_filter_superblocks_type(h->pr, BLKID_FLTR_NOTIN, luks_filter);
#endif
return r;
}
blk_probe_status blk_probe(struct blkid_handle *h)
{
blk_probe_status pr = PRB_FAIL;
#ifdef HAVE_BLKID
int r = blkid_do_probe(h->pr);
if (r == 0)
pr = PRB_OK;
else if (r == 1)
pr = PRB_EMPTY;
#endif
return pr;
}
blk_probe_status blk_safeprobe(struct blkid_handle *h)
{
int r = -1;
#ifdef HAVE_BLKID
r = blkid_do_safeprobe(h->pr);
#endif
switch (r) {
case -2:
return PRB_AMBIGUOUS;
case 1:
return PRB_EMPTY;
case 0:
return PRB_OK;
default:
return PRB_FAIL;
}
}
int blk_is_partition(struct blkid_handle *h)
{
int r = 0;
#ifdef HAVE_BLKID
r = blkid_probe_has_value(h->pr, "PTTYPE");
#endif
return r;
}
int blk_is_superblock(struct blkid_handle *h)
{
int r = 0;
#ifdef HAVE_BLKID
r = blkid_probe_has_value(h->pr, "TYPE");
#endif
return r;
}
const char *blk_get_partition_type(struct blkid_handle *h)
{
const char *value = NULL;
#ifdef HAVE_BLKID
(void) blkid_probe_lookup_value(h->pr, "PTTYPE", &value, NULL);
#endif
return value;
}
const char *blk_get_superblock_type(struct blkid_handle *h)
{
const char *value = NULL;
#ifdef HAVE_BLKID
(void) blkid_probe_lookup_value(h->pr, "TYPE", &value, NULL);
#endif
return value;
}
void blk_free(struct blkid_handle *h)
{
#ifdef HAVE_BLKID
if (!h)
return;
if (h->pr)
blkid_free_probe(h->pr);
free(h);
#endif
}
#ifdef HAVE_BLKID
#ifndef HAVE_BLKID_WIPE
static int blk_step_back(struct blkid_handle *h)
{
#ifdef HAVE_BLKID_STEP_BACK
return blkid_probe_step_back(h->pr);
#else
blkid_reset_probe(h->pr);
blkid_probe_set_device(h->pr, h->fd, 0, 0);
return 0;
#endif
}
#endif /* not HAVE_BLKID_WIPE */
#endif /* HAVE_BLKID */
int blk_do_wipe(struct blkid_handle *h)
{
#ifdef HAVE_BLKID
#ifdef HAVE_BLKID_WIPE
return blkid_do_wipe(h->pr, 0);
#else
const char *offset;
off_t offset_val;
void *buf;
ssize_t ret;
size_t alignment, len, bsize = blkid_probe_get_sectorsize(h->pr);
if (h->fd < 0 || !bsize)
return -EINVAL;
if (blk_is_partition(h)) {
if (blkid_probe_lookup_value(h->pr, "PTMAGIC_OFFSET", &offset, NULL))
return -EINVAL;
if (blkid_probe_lookup_value(h->pr, "PTMAGIC", NULL, &len))
return -EINVAL;
} else if (blk_is_superblock(h)) {
if (blkid_probe_lookup_value(h->pr, "SBMAGIC_OFFSET", &offset, NULL))
return -EINVAL;
if (blkid_probe_lookup_value(h->pr, "SBMAGIC", NULL, &len))
return -EINVAL;
} else
return 0;
alignment = crypt_getpagesize();
if (posix_memalign(&buf, alignment, len))
return -EINVAL;
memset(buf, 0, len);
offset_val = strtoll(offset, NULL, 10);
/* TODO: missing crypt_wipe_fd() */
ret = write_lseek_blockwise(h->fd, bsize, alignment, buf, len, offset_val);
free(buf);
if (ret < 0)
return -EIO;
if ((size_t)ret == len) {
blk_step_back(h);
return 0;
}
return -EIO;
#endif
#else /* HAVE_BLKID */
return -ENOTSUP;
#endif
}
int blk_supported(void)
{
int r = 0;
#ifdef HAVE_BLKID
r = 1;
#endif
return r;
}

62
lib/utils_blkid.h Normal file
View File

@@ -0,0 +1,62 @@
/*
* blkid probe utilities
*
* Copyright (C) 2018, Red Hat, Inc. All rights reserved.
*
* 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.
*/
#ifndef _UTILS_BLKID_H
#define _UTILS_BLKID_H
struct blkid_handle;
typedef enum { PRB_OK = 0, PRB_EMPTY, PRB_AMBIGUOUS, PRB_FAIL } blk_probe_status;
int blk_init_by_path(struct blkid_handle **h, const char *path);
void blk_free(struct blkid_handle *h);
/*
* WARNING: This will reset file description offset as if
* lseek(devfd, 0, SEEK_SET) was called!
*/
int blk_init_by_fd(struct blkid_handle **h, int fd);
void blk_set_chains_for_wipes(struct blkid_handle *h);
void blk_set_chains_for_full_print(struct blkid_handle *h);
void blk_set_chains_for_fast_detection(struct blkid_handle *h);
int blk_superblocks_filter_luks(struct blkid_handle *h);
blk_probe_status blk_safeprobe(struct blkid_handle *h);
blk_probe_status blk_probe(struct blkid_handle *h);
int blk_is_partition(struct blkid_handle *h);
int blk_is_superblock(struct blkid_handle *h);
const char *blk_get_partition_type(struct blkid_handle *h);
const char *blk_get_superblock_type(struct blkid_handle *h);
int blk_do_wipe(struct blkid_handle *h);
int blk_supported(void);
#endif

View File

@@ -105,6 +105,9 @@ int crypt_parse_integrity_mode(const char *s, char *integrity,
!strcmp(s, "none")) {
strncpy(integrity, s, MAX_CIPHER_LEN);
ks = 0;
} else if (!strcmp(s, "hmac-sha1")) {
strncpy(integrity, "hmac(sha1)", MAX_CIPHER_LEN);
ks = 20;
} else if (!strcmp(s, "hmac-sha256")) {
strncpy(integrity, "hmac(sha256)", MAX_CIPHER_LEN);
ks = 32;
@@ -152,10 +155,14 @@ int crypt_parse_pbkdf(const char *s, const char **pbkdf)
*/
void crypt_memzero(void *s, size_t n)
{
#ifdef HAVE_EXPLICIT_BZERO
explicit_bzero(s, n);
#else
volatile uint8_t *p = (volatile uint8_t *)s;
while(n--)
*p++ = 0;
#endif
}
/* safe allocations */

View File

@@ -58,13 +58,19 @@ struct device {
static size_t device_fs_block_size_fd(int fd)
{
size_t page_size = crypt_getpagesize();
#ifdef HAVE_SYS_STATVFS_H
struct statvfs buf;
if (!fstatvfs(fd, &buf) && buf.f_bsize)
/*
* NOTE: some filesystems (NFS) returns bogus blocksize (1MB).
* Page-size io should always work and avoids increasing IO beyond aligned LUKS header.
*/
if (!fstatvfs(fd, &buf) && buf.f_bsize && buf.f_bsize <= page_size)
return (size_t)buf.f_bsize;
#endif
return crypt_getpagesize();
return page_size;
}
static size_t device_block_size_fd(int fd, size_t *min_size)
@@ -175,7 +181,7 @@ static int device_ready(struct device *device)
}
if (devfd < 0) {
log_err(NULL, _("Device %s doesn't exist or access denied.\n"),
log_err(NULL, _("Device %s doesn't exist or access denied."),
device_path(device));
return -EINVAL;
}
@@ -184,6 +190,12 @@ static int device_ready(struct device *device)
r = -EINVAL;
else if (!S_ISBLK(st.st_mode))
r = S_ISREG(st.st_mode) ? -ENOTBLK : -EINVAL;
if (r == -EINVAL) {
log_err(NULL, _("Device %s is not compatible."),
device_path(device));
close(devfd);
return r;
}
/* Allow only increase (loop device) */
tmp_size = device_alignment_fd(devfd);
@@ -223,6 +235,16 @@ static int _open_locked(struct device *device, int flags)
return fd;
}
/*
* Common wrapper for device sync.
* FIXME: file descriptor will be in struct later.
*/
void device_sync(struct device *device, int devfd)
{
if (fsync(devfd) == -1)
log_dbg("Cannot sync device %s.", device_path(device));
}
/*
* in non-locked mode returns always fd or -1
*
@@ -236,7 +258,6 @@ static int device_open_internal(struct device *device, int flags)
{
int devfd;
flags |= O_SYNC;
if (device->o_direct)
flags |= O_DIRECT;
@@ -246,7 +267,9 @@ static int device_open_internal(struct device *device, int flags)
devfd = open(device_path(device), flags);
if (devfd < 0)
log_dbg("Cannot open device %s.", device_path(device));
log_dbg("Cannot open device %s%s.",
device_path(device),
(flags & O_ACCMODE) != O_RDONLY ? " for write" : "");
return devfd;
}
@@ -500,7 +523,7 @@ int device_fallocate(struct device *device, uint64_t size)
struct stat st;
int devfd, r = -EINVAL;
devfd = open(device_path(device), O_WRONLY);
devfd = open(device_path(device), O_RDWR);
if(devfd == -1)
return -EINVAL;
@@ -553,7 +576,7 @@ static int device_info(struct crypt_device *cd,
}
if (fd == -1) {
r = -EINVAL;
r = errno ? -errno : -EINVAL;
goto out;
}
@@ -565,7 +588,7 @@ static int device_info(struct crypt_device *cd,
} else {
/* If the device can be opened read-write, i.e. readonly is still 0, then
* check whether BKROGET says that it is read-only. E.g. read-only loop
* devices may be openend read-write but are read-only according to BLKROGET
* devices may be opened read-write but are read-only according to BLKROGET
*/
if (real_readonly == 0 && (r = ioctl(fd, BLKROGET, &real_readonly)) < 0)
goto out;
@@ -589,13 +612,14 @@ out:
break;
case -EBUSY:
log_err(cd, _("Cannot use device %s which is in use "
"(already mapped or mounted).\n"), device->path);
"(already mapped or mounted)."), device_path(device));
break;
case -EACCES:
log_err(cd, _("Cannot use device %s, permission denied.\n"), device->path);
log_err(cd, _("Cannot use device %s, permission denied."), device_path(device));
break;
default:
log_err(cd, _("Cannot get info about device %s.\n"), device->path);
log_err(cd, _("Cannot get info about device %s."), device_path(device));
r = -EINVAL;
}
return r;
@@ -618,7 +642,7 @@ static int device_internal_prepare(struct crypt_device *cd, struct device *devic
if (getuid() || geteuid()) {
log_err(cd, _("Cannot use a loopback device, "
"running as non-root user.\n"));
"running as non-root user."));
return -ENOTSUP;
}
@@ -628,7 +652,7 @@ static int device_internal_prepare(struct crypt_device *cd, struct device *devic
loop_fd = crypt_loop_attach(&loop_device, device->path, 0, 1, &readonly);
if (loop_fd == -1) {
log_err(cd, _("Attaching loopback device failed "
"(loop device with autoclear flag is required).\n"));
"(loop device with autoclear flag is required)."));
free(loop_device);
return -EINVAL;
}
@@ -673,15 +697,15 @@ int device_block_adjust(struct crypt_device *cd,
return r;
if (device_offset >= real_size) {
log_err(cd, _("Requested offset is beyond real size of device %s.\n"),
device->path);
log_err(cd, _("Requested offset is beyond real size of device %s."),
device_path(device));
return -EINVAL;
}
if (size && !*size) {
*size = real_size;
if (!*size) {
log_err(cd, _("Device %s has zero size.\n"), device->path);
log_err(cd, _("Device %s has zero size."), device_path(device));
return -ENOTBLK;
}
*size -= device_offset;
@@ -692,7 +716,7 @@ int device_block_adjust(struct crypt_device *cd,
log_dbg("Device %s: offset = %" PRIu64 " requested size = %" PRIu64
", backing device size = %" PRIu64,
device->path, device_offset, *size, real_size);
log_err(cd, _("Device %s is too small.\n"), device->path);
log_err(cd, _("Device %s is too small."), device_path(device));
return -EINVAL;
}

View File

@@ -77,7 +77,7 @@ static int open_lock_dir(struct crypt_device *cd, const char *dir, const char *b
if (dirfd < 0) {
log_dbg("Failed to open directory %s: (%d: %s).", dir, errno, strerror(errno));
if (errno == ENOTDIR || errno == ENOENT)
log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (not a directory or missing).\n"), dir, base);
log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (not a directory or missing)."), dir, base);
return -EINVAL;
}
@@ -94,7 +94,7 @@ static int open_lock_dir(struct crypt_device *cd, const char *dir, const char *b
} else {
log_dbg("Failed to open directory %s/%s: (%d: %s)", dir, base, errno, strerror(errno));
if (errno == ENOTDIR || errno == ELOOP)
log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (%s is not a directory).\n"), dir, base, base);
log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (%s is not a directory)."), dir, base, base);
}
}
@@ -178,7 +178,7 @@ static void release_lock_handle(struct crypt_lock_handle *h)
!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 */
!fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
!stat(res, &buf_b) && /* does path file stil exist? */
!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 */

View File

@@ -133,11 +133,13 @@ int dm_remove_device(struct crypt_device *cd, const char *name, uint32_t flags);
int dm_status_device(struct crypt_device *cd, const char *name);
int dm_status_suspended(struct crypt_device *cd, const char *name);
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_create_device(struct crypt_device *cd, const char *name,
const char *type, struct crypt_dm_active_device *dmd,
int reload);
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_and_reinstate_key(struct crypt_device *cd, const char *name,
const struct volume_key *vk);

299
lib/utils_io.c Normal file
View File

@@ -0,0 +1,299 @@
/*
* utils - miscellaneous I/O utilities for cryptsetup
*
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2018, Milan Broz
*
* 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 <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include "utils_io.h"
static ssize_t _read_buffer(int fd, void *buf, size_t length, volatile int *quit)
{
size_t read_size = 0;
ssize_t r;
if (fd < 0 || !buf)
return -EINVAL;
do {
r = read(fd, buf, length - read_size);
if (r == -1 && errno != EINTR)
return r;
if (r > 0) {
read_size += (size_t)r;
buf = (uint8_t*)buf + r;
}
if (r == 0 || (quit && *quit))
return (ssize_t)read_size;
} while (read_size != length);
return (ssize_t)length;
}
ssize_t read_buffer(int fd, void *buf, size_t length)
{
return _read_buffer(fd, buf, length, NULL);
}
ssize_t read_buffer_intr(int fd, void *buf, size_t length, volatile int *quit)
{
return _read_buffer(fd, buf, length, quit);
}
static ssize_t _write_buffer(int fd, const void *buf, size_t length, volatile int *quit)
{
size_t write_size = 0;
ssize_t w;
if (fd < 0 || !buf || !length)
return -EINVAL;
do {
w = write(fd, buf, length - write_size);
if (w < 0 && errno != EINTR)
return w;
if (w > 0) {
write_size += (size_t) w;
buf = (const uint8_t*)buf + w;
}
if (w == 0 || (quit && *quit))
return (ssize_t)write_size;
} while (write_size != length);
return (ssize_t)write_size;
}
ssize_t write_buffer(int fd, const void *buf, size_t length)
{
return _write_buffer(fd, buf, length, NULL);
}
ssize_t write_buffer_intr(int fd, const void *buf, size_t length, volatile int *quit)
{
return _write_buffer(fd, buf, length, quit);
}
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment,
void *orig_buf, size_t length)
{
void *hangover_buf = NULL, *buf = NULL;
size_t hangover, solid;
ssize_t r, ret = -1;
if (fd == -1 || !orig_buf || !bsize || !alignment)
return -1;
hangover = length % bsize;
solid = length - hangover;
if ((size_t)orig_buf & (alignment - 1)) {
if (posix_memalign(&buf, alignment, length))
return -1;
memcpy(buf, orig_buf, length);
} else
buf = orig_buf;
if (solid) {
r = write_buffer(fd, buf, solid);
if (r < 0 || r != (ssize_t)solid)
goto out;
}
if (hangover) {
if (posix_memalign(&hangover_buf, alignment, bsize))
goto out;
memset(hangover_buf, 0, bsize);
r = read_buffer(fd, hangover_buf, bsize);
if (r < 0)
goto out;
if (lseek(fd, -(off_t)r, SEEK_CUR) < 0)
goto out;
memcpy(hangover_buf, (char*)buf + solid, hangover);
r = write_buffer(fd, hangover_buf, bsize);
if (r < 0 || r < (ssize_t)hangover)
goto out;
}
ret = length;
out:
free(hangover_buf);
if (buf != orig_buf)
free(buf);
return ret;
}
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment,
void *orig_buf, size_t length)
{
void *hangover_buf = NULL, *buf = NULL;
size_t hangover, solid;
ssize_t r, ret = -1;
if (fd == -1 || !orig_buf || !bsize || !alignment)
return -1;
hangover = length % bsize;
solid = length - hangover;
if ((size_t)orig_buf & (alignment - 1)) {
if (posix_memalign(&buf, alignment, length))
return -1;
} else
buf = orig_buf;
r = read_buffer(fd, buf, solid);
if (r < 0 || r != (ssize_t)solid)
goto out;
if (hangover) {
if (posix_memalign(&hangover_buf, alignment, bsize))
goto out;
r = read_buffer(fd, hangover_buf, bsize);
if (r < 0 || r < (ssize_t)hangover)
goto out;
memcpy((char *)buf + solid, hangover_buf, hangover);
}
ret = length;
out:
free(hangover_buf);
if (buf != orig_buf) {
if (ret != -1)
memcpy(orig_buf, buf, length);
free(buf);
}
return ret;
}
/*
* Combines llseek with blockwise write. write_blockwise can already deal with short writes
* but we also need a function to deal with short writes at the start. But this information
* is implicitly included in the read/write offset, which can not be set to non-aligned
* boundaries. Hence, we combine llseek with write.
*/
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment,
void *buf, size_t length, off_t offset)
{
void *frontPadBuf = NULL;
size_t frontHang, innerCount = 0;
ssize_t r, ret = -1;
if (fd == -1 || !buf || !bsize || !alignment)
return -1;
if (offset < 0)
offset = lseek(fd, offset, SEEK_END);
if (offset < 0)
return -1;
frontHang = offset % bsize;
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
return -1;
if (frontHang && length) {
if (posix_memalign(&frontPadBuf, alignment, bsize))
return -1;
innerCount = bsize - frontHang;
if (innerCount > length)
innerCount = length;
r = read_buffer(fd, frontPadBuf, bsize);
if (r < 0 || r < (ssize_t)(frontHang + innerCount))
goto out;
memcpy((char*)frontPadBuf + frontHang, buf, innerCount);
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
goto out;
r = write_buffer(fd, frontPadBuf, bsize);
if (r < 0 || r != (ssize_t)bsize)
goto out;
buf = (char*)buf + innerCount;
length -= innerCount;
}
ret = length ? write_blockwise(fd, bsize, alignment, buf, length) : 0;
if (ret >= 0)
ret += innerCount;
out:
free(frontPadBuf);
return ret;
}
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment,
void *buf, size_t length, off_t offset)
{
void *frontPadBuf = NULL;
size_t frontHang, innerCount = 0;
ssize_t r, ret = -1;
if (fd == -1 || !buf || bsize <= 0)
return -1;
if (offset < 0)
offset = lseek(fd, offset, SEEK_END);
if (offset < 0)
return -1;
frontHang = offset % bsize;
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
return -1;
if (frontHang && length) {
if (posix_memalign(&frontPadBuf, alignment, bsize))
return -1;
innerCount = bsize - frontHang;
if (innerCount > length)
innerCount = length;
r = read_buffer(fd, frontPadBuf, bsize);
if (r < 0 || r < (ssize_t)(frontHang + innerCount))
goto out;
memcpy(buf, (char*)frontPadBuf + frontHang, innerCount);
buf = (char*)buf + innerCount;
length -= innerCount;
}
ret = read_blockwise(fd, bsize, alignment, buf, length);
if (ret >= 0)
ret += innerCount;
out:
free(frontPadBuf);
return ret;
}

42
lib/utils_io.h Normal file
View File

@@ -0,0 +1,42 @@
/*
* utils - miscellaneous I/O utilities for cryptsetup
*
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2018, Milan Broz
*
* 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.
*/
#ifndef _CRYPTSETUP_UTILS_IO_H
#define _CRYPTSETUP_UTILS_IO_H
#include <sys/types.h>
ssize_t read_buffer(int fd, void *buf, size_t length);
ssize_t read_buffer_intr(int fd, void *buf, size_t length, volatile int *quit);
ssize_t write_buffer(int fd, const void *buf, size_t length);
ssize_t write_buffer_intr(int fd, const void *buf, size_t length, volatile int *quit);
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment,
void *orig_buf, size_t length);
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment,
void *orig_buf, size_t length);
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment,
void *buf, size_t length, off_t offset);
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment,
void *buf, size_t length, off_t offset);
#endif

View File

@@ -133,7 +133,8 @@ int keyring_get_passphrase(const char *key_desc,
if (ret < 0) {
err = errno;
crypt_memzero(buf, len);
if (buf)
crypt_memzero(buf, len);
free(buf);
return -err;
}

View File

@@ -22,6 +22,8 @@
#ifndef _UTILS_KEYRING
#define _UTILS_KEYRING
#include <stddef.h>
int keyring_check(void);
int keyring_get_passphrase(const char *key_desc,

View File

@@ -65,13 +65,19 @@ int verify_pbkdf_params(struct crypt_device *cd,
const char *pbkdf_type;
int r = 0;
if (!pbkdf->type || !pbkdf->hash || !pbkdf->time_ms)
if (!pbkdf->type ||
(!pbkdf->hash && !strcmp(pbkdf->type, "pbkdf2")))
return -EINVAL;
if (!pbkdf->time_ms && !(pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK)) {
log_err(cd, _("Requested PBKDF target time cannot be zero."));
return -EINVAL;
}
/* TODO: initialise crypto and check the hash and pbkdf are both available */
r = crypt_parse_pbkdf(pbkdf->type, &pbkdf_type);
if (r < 0) {
log_err(cd, _("Unknown PBKDF type %s.\n"), pbkdf->type);
log_err(cd, _("Unknown PBKDF type %s."), pbkdf->type);
return r;
}
@@ -82,18 +88,18 @@ int verify_pbkdf_params(struct crypt_device *cd,
if (crypt_get_type(cd) &&
!strcmp(crypt_get_type(cd), CRYPT_LUKS1) &&
strcmp(pbkdf_type, CRYPT_KDF_PBKDF2)) {
log_err(cd, _("Requested PBKDF type is not supported for LUKS1.\n"));
log_err(cd, _("Requested PBKDF type is not supported for LUKS1."));
return -EINVAL;
}
if (!strcmp(pbkdf_type, CRYPT_KDF_PBKDF2)) {
if (pbkdf->max_memory_kb || pbkdf->parallel_threads) {
log_err(cd, _("PBKDF max memory or parallel threads must not be set with pbkdf2.\n"));
log_err(cd, _("PBKDF max memory or parallel threads must not be set with pbkdf2."));
return -EINVAL;
}
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK &&
pbkdf->iterations < pbkdf_limits.min_iterations) {
log_err(cd, _("Forced iteration count is too low for %s (minimum is %u).\n"),
log_err(cd, _("Forced iteration count is too low for %s (minimum is %u)."),
pbkdf_type, pbkdf_limits.min_iterations);
return -EINVAL;
}
@@ -103,32 +109,28 @@ int verify_pbkdf_params(struct crypt_device *cd,
/* TODO: properly define minimal iterations and also minimal memory values */
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) {
if (pbkdf->iterations < pbkdf_limits.min_iterations) {
log_err(cd, _("Forced iteration count is too low for %s (minimum is %u).\n"),
log_err(cd, _("Forced iteration count is too low for %s (minimum is %u)."),
pbkdf_type, pbkdf_limits.min_iterations);
r = -EINVAL;
}
if (pbkdf->max_memory_kb < pbkdf_limits.min_memory) {
log_err(cd, _("Forced memory cost is too low for %s (minimum is %u kilobytes).\n"),
log_err(cd, _("Forced memory cost is too low for %s (minimum is %u kilobytes)."),
pbkdf_type, pbkdf_limits.min_memory);
r = -EINVAL;
}
}
if (pbkdf->max_memory_kb > pbkdf_limits.max_memory) {
log_err(cd, _("Requested maximum PBKDF memory cost is too high (maximum is %d kilobytes).\n"),
log_err(cd, _("Requested maximum PBKDF memory cost is too high (maximum is %d kilobytes)."),
pbkdf_limits.max_memory);
r = -EINVAL;
}
if (!pbkdf->max_memory_kb) {
log_err(cd, _("Requested maximum PBKDF memory can not be zero.\n"));
log_err(cd, _("Requested maximum PBKDF memory cannot be zero."));
r = -EINVAL;
}
if (!pbkdf->parallel_threads) {
log_err(cd, _("Requested PBKDF parallel threads can not be zero.\n"));
r = -EINVAL;
}
if (!pbkdf->time_ms) {
log_err(cd, _("Requested PBKDF target time can not be zero.\n"));
log_err(cd, _("Requested PBKDF parallel threads cannot be zero."));
r = -EINVAL;
}
@@ -165,9 +167,9 @@ int init_pbkdf_type(struct crypt_device *cd,
* It will fail later anyway :-)
*/
type = strdup(pbkdf->type);
hash = strdup(pbkdf->hash);
hash = pbkdf->hash ? strdup(pbkdf->hash) : NULL;
if (!type || !hash) {
if (!type || (!hash && pbkdf->hash)) {
free(CONST_CAST(void*)type);
free(CONST_CAST(void*)hash);
return -ENOMEM;
@@ -251,6 +253,19 @@ const struct crypt_pbkdf_type *crypt_get_pbkdf_type(struct crypt_device *cd)
return crypt_get_pbkdf(cd)->type ? crypt_get_pbkdf(cd) : NULL;
}
const struct crypt_pbkdf_type *crypt_get_pbkdf_default(const char *type)
{
if (!type)
return NULL;
if (!strcmp(type, CRYPT_LUKS1))
return &default_luks1;
else if (!strcmp(type, CRYPT_LUKS2))
return &default_luks2;
return NULL;
}
void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_ms)
{
struct crypt_pbkdf_type *pbkdf;

View File

@@ -153,7 +153,7 @@ int crypt_wipe_device(struct crypt_device *cd,
/* FIXME: if wipe_block_size < bsize, then a wipe is highly ineffective */
/* Everything must be aligned to SECTOR_SIZE */
if ((offset % SECTOR_SIZE) || (length % SECTOR_SIZE) || (wipe_block_size % SECTOR_SIZE))
if (MISALIGNED_512(offset) || MISALIGNED_512(length) || MISALIGNED_512(wipe_block_size))
return -EINVAL;
devfd = device_open(device, O_RDWR);
@@ -161,9 +161,12 @@ int crypt_wipe_device(struct crypt_device *cd,
return errno ? -errno : -EINVAL;
r = device_size(device, &dev_size);
if (r)
if (r || dev_size == 0)
goto out;
if (dev_size < length)
length = 0;
if (length) {
if ((dev_size <= offset) || (dev_size - offset) < length) {
r = -EINVAL;
@@ -177,7 +180,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.\n");
log_err(cd, "Cannot seek to device offset.");
r = -EINVAL;
goto out;
}
@@ -201,7 +204,7 @@ int crypt_wipe_device(struct crypt_device *cd,
r = wipe_block(devfd, pattern, sf, bsize, alignment,
wipe_block_size, offset, &need_block_init);
if (r) {
log_err(cd, "Device wipe error, offset %" PRIu64 ".\n", offset);
log_err(cd, "Device wipe error, offset %" PRIu64 ".", offset);
break;
}
@@ -213,7 +216,7 @@ int crypt_wipe_device(struct crypt_device *cd,
}
}
fsync(devfd);
device_sync(device, devfd);
out:
close(devfd);
free(sf);

View File

@@ -23,13 +23,41 @@
#ifndef _LIBFEC_RS_H
#define _LIBFEC_RS_H
/* Special reserved value encoding zero in index form. */
#define A0 (rs->nn)
#define RS_MIN(a, b) ((a) < (b) ? (a) : (b))
typedef unsigned char data_t;
struct rs;
/* Reed-Solomon codec control block */
struct rs {
int mm; /* Bits per symbol */
int nn; /* Symbols per block (= (1<<mm)-1) */
data_t *alpha_to;/* log lookup table */
data_t *index_of;/* Antilog lookup table */
data_t *genpoly; /* Generator polynomial */
int nroots; /* Number of generator roots = number of parity symbols */
int fcr; /* First consecutive root, index form */
int prim; /* Primitive element, index form */
int iprim; /* prim-th root of 1, index form */
int pad; /* Padding bytes in shortened block */
};
static inline int modnn(struct rs *rs, int x)
{
while (x >= rs->nn) {
x -= rs->nn;
x = (x >> rs->mm) + (x & rs->nn);
}
return x;
}
struct rs *init_rs_char(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad);
void free_rs_char(struct rs *rs);
/* General purpose RS codec, 8-bit symbols */
void encode_rs_char(struct rs *rs, data_t *data, data_t *parity);
int decode_rs_char(struct rs *rs, data_t *data);
#endif

197
lib/verity/rs_decode_char.c Normal file
View File

@@ -0,0 +1,197 @@
/*
* Reed-Solomon decoder, based on libfec
*
* Copyright (C) 2002, Phil Karn, KA9Q
* libcryptsetup modifications
* Copyright (C) 2017-2018, Red Hat, Inc. All rights reserved.
*
* 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 <string.h>
#include <stdlib.h>
#include "rs.h"
int decode_rs_char(struct rs* rs, data_t* data)
{
int deg_lambda, el, deg_omega, syn_error, count;
int i, j, r, k;
data_t q, tmp, num1, num2, den, discr_r;
/* FIXME: remove VLAs here */
data_t lambda[rs->nroots + 1], s[rs->nroots]; /* Err+Eras Locator poly and syndrome poly */
data_t b[rs->nroots + 1], t[rs->nroots + 1], omega[rs->nroots + 1];
data_t root[rs->nroots], reg[rs->nroots + 1], loc[rs->nroots];
memset(s, 0, rs->nroots * sizeof(data_t));
memset(b, 0, (rs->nroots + 1) * sizeof(data_t));
/* form the syndromes; i.e., evaluate data(x) at roots of g(x) */
for (i = 0; i < rs->nroots; i++)
s[i] = data[0];
for (j = 1; j < rs->nn - rs->pad; j++) {
for (i = 0; i < rs->nroots; i++) {
if (s[i] == 0) {
s[i] = data[j];
} else {
s[i] = data[j] ^ rs->alpha_to[modnn(rs, rs->index_of[s[i]] + (rs->fcr + i) * rs->prim)];
}
}
}
/* Convert syndromes to index form, checking for nonzero condition */
syn_error = 0;
for (i = 0; i < rs->nroots; i++) {
syn_error |= s[i];
s[i] = rs->index_of[s[i]];
}
/*
* if syndrome is zero, data[] is a codeword and there are no
* errors to correct. So return data[] unmodified
*/
if (!syn_error)
return 0;
memset(&lambda[1], 0, rs->nroots * sizeof(lambda[0]));
lambda[0] = 1;
for (i = 0; i < rs->nroots + 1; i++)
b[i] = rs->index_of[lambda[i]];
/*
* Begin Berlekamp-Massey algorithm to determine error+erasure
* locator polynomial
*/
r = 0;
el = 0;
while (++r <= rs->nroots) { /* r is the step number */
/* Compute discrepancy at the r-th step in poly-form */
discr_r = 0;
for (i = 0; i < r; i++) {
if ((lambda[i] != 0) && (s[r - i - 1] != A0)) {
discr_r ^= rs->alpha_to[modnn(rs, rs->index_of[lambda[i]] + s[r - i - 1])];
}
}
discr_r = rs->index_of[discr_r]; /* Index form */
if (discr_r == A0) {
/* 2 lines below: B(x) <-- x*B(x) */
memmove(&b[1], b, rs->nroots * sizeof(b[0]));
b[0] = A0;
} else {
/* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
t[0] = lambda[0];
for (i = 0; i < rs->nroots; i++) {
if (b[i] != A0)
t[i + 1] = lambda[i + 1] ^ rs->alpha_to[modnn(rs, discr_r + b[i])];
else
t[i + 1] = lambda[i + 1];
}
if (2 * el <= r - 1) {
el = r - el;
/*
* 2 lines below: B(x) <-- inv(discr_r) *
* lambda(x)
*/
for (i = 0; i <= rs->nroots; i++)
b[i] = (lambda[i] == 0) ? A0 : modnn(rs, rs->index_of[lambda[i]] - discr_r + rs->nn);
} else {
/* 2 lines below: B(x) <-- x*B(x) */
memmove(&b[1], b, rs->nroots * sizeof(b[0]));
b[0] = A0;
}
memcpy(lambda, t, (rs->nroots + 1) * sizeof(t[0]));
}
}
/* Convert lambda to index form and compute deg(lambda(x)) */
deg_lambda = 0;
for (i = 0; i < rs->nroots + 1; i++) {
lambda[i] = rs->index_of[lambda[i]];
if (lambda[i] != A0)
deg_lambda = i;
}
/* Find roots of the error+erasure locator polynomial by Chien search */
memcpy(&reg[1], &lambda[1], rs->nroots * sizeof(reg[0]));
count = 0; /* Number of roots of lambda(x) */
for (i = 1, k = rs->iprim - 1; i <= rs->nn; i++, k = modnn(rs, k + rs->iprim)) {
q = 1; /* lambda[0] is always 0 */
for (j = deg_lambda; j > 0; j--) {
if (reg[j] != A0) {
reg[j] = modnn(rs, reg[j] + j);
q ^= rs->alpha_to[reg[j]];
}
}
if (q != 0)
continue; /* Not a root */
/* store root (index-form) and error location number */
root[count] = i;
loc[count] = k;
/* If we've already found max possible roots, abort the search to save time */
if (++count == deg_lambda)
break;
}
/*
* deg(lambda) unequal to number of roots => uncorrectable
* error detected
*/
if (deg_lambda != count)
return -1;
/*
* Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
* x**rs->nroots). in index form. Also find deg(omega).
*/
deg_omega = deg_lambda - 1;
for (i = 0; i <= deg_omega; i++) {
tmp = 0;
for (j = i; j >= 0; j--) {
if ((s[i - j] != A0) && (lambda[j] != A0))
tmp ^= rs->alpha_to[modnn(rs, s[i - j] + lambda[j])];
}
omega[i] = rs->index_of[tmp];
}
/*
* Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
* inv(X(l))**(rs->fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
*/
for (j = count - 1; j >= 0; j--) {
num1 = 0;
for (i = deg_omega; i >= 0; i--) {
if (omega[i] != A0)
num1 ^= rs->alpha_to[modnn(rs, omega[i] + i * root[j])];
}
num2 = rs->alpha_to[modnn(rs, root[j] * (rs->fcr - 1) + rs->nn)];
den = 0;
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
for (i = RS_MIN(deg_lambda, rs->nroots - 1) & ~1; i >= 0; i -= 2) {
if (lambda[i + 1] != A0)
den ^= rs->alpha_to[modnn(rs, lambda[i + 1] + i * root[j])];
}
/* Apply error to data */
if (num1 != 0 && loc[j] >= rs->pad) {
data[loc[j] - rs->pad] ^= rs->alpha_to[modnn(rs, rs->index_of[num1] +
rs->index_of[num2] + rs->nn - rs->index_of[den])];
}
}
return count;
}

View File

@@ -25,32 +25,6 @@
#include "rs.h"
/* Special reserved value encoding zero in index form. */
#define A0 (rs->nn)
/* Reed-Solomon codec control block */
struct rs {
int mm; /* Bits per symbol */
int nn; /* Symbols per block (= (1<<mm)-1) */
data_t *alpha_to;/* log lookup table */
data_t *index_of;/* Antilog lookup table */
data_t *genpoly; /* Generator polynomial */
int nroots; /* Number of generator roots = number of parity symbols */
int fcr; /* First consecutive root, index form */
int prim; /* Primitive element, index form */
int iprim; /* prim-th root of 1, index form */
int pad; /* Padding bytes in shortened block */
};
static inline int modnn(struct rs *rs, int x)
{
while (x >= rs->nn) {
x -= rs->nn;
x = (x >> rs->mm) + (x & rs->nn);
}
return x;
}
/* Initialize a Reed-Solomon codec
* symsize = symbol size, bits
* gfpoly = Field generator polynomial coefficients

View File

@@ -66,19 +66,19 @@ int VERITY_read_sb(struct crypt_device *cd,
sizeof(struct verity_sb), device_path(device), sb_offset);
if (params->flags & CRYPT_VERITY_NO_HEADER) {
log_err(cd, _("Verity device %s doesn't use on-disk header.\n"),
log_err(cd, _("Verity device %s doesn't use on-disk header."),
device_path(device));
return -EINVAL;
}
if (sb_offset % 512) {
log_err(cd, _("Unsupported VERITY hash offset.\n"));
if (MISALIGNED_512(sb_offset)) {
log_err(cd, _("Unsupported VERITY hash offset."));
return -EINVAL;
}
devfd = device_open(device, O_RDONLY);
if (devfd < 0) {
log_err(cd, _("Cannot open device %s.\n"), device_path(device));
log_err(cd, _("Cannot open device %s."), device_path(device));
return -EINVAL;
}
@@ -91,19 +91,19 @@ int VERITY_read_sb(struct crypt_device *cd,
close(devfd);
if (memcmp(sb.signature, VERITY_SIGNATURE, sizeof(sb.signature))) {
log_err(cd, _("Device %s is not a valid VERITY device.\n"),
log_err(cd, _("Device %s is not a valid VERITY device."),
device_path(device));
return -EINVAL;
}
sb_version = le32_to_cpu(sb.version);
if (sb_version != 1) {
log_err(cd, _("Unsupported VERITY version %d.\n"), sb_version);
log_err(cd, _("Unsupported VERITY version %d."), sb_version);
return -EINVAL;
}
params->hash_type = le32_to_cpu(sb.hash_type);
if (params->hash_type > VERITY_MAX_HASH_TYPE) {
log_err(cd, _("Unsupported VERITY hash type %d.\n"), params->hash_type);
log_err(cd, _("Unsupported VERITY hash type %d."), params->hash_type);
return -EINVAL;
}
@@ -111,7 +111,7 @@ int VERITY_read_sb(struct crypt_device *cd,
params->hash_block_size = le32_to_cpu(sb.hash_block_size);
if (VERITY_BLOCK_SIZE_OK(params->data_block_size) ||
VERITY_BLOCK_SIZE_OK(params->hash_block_size)) {
log_err(cd, _("Unsupported VERITY block size.\n"));
log_err(cd, _("Unsupported VERITY block size."));
return -EINVAL;
}
params->data_size = le64_to_cpu(sb.data_blocks);
@@ -120,7 +120,7 @@ int VERITY_read_sb(struct crypt_device *cd,
if (!params->hash_name)
return -ENOMEM;
if (crypt_hash_size(params->hash_name) <= 0) {
log_err(cd, _("Hash algorithm %s not supported.\n"),
log_err(cd, _("Hash algorithm %s not supported."),
params->hash_name);
free(CONST_CAST(char*)params->hash_name);
params->hash_name = NULL;
@@ -129,7 +129,7 @@ int VERITY_read_sb(struct crypt_device *cd,
params->salt_size = le16_to_cpu(sb.salt_size);
if (params->salt_size > sizeof(sb.salt)) {
log_err(cd, _("VERITY header corrupted.\n"));
log_err(cd, _("VERITY header corrupted."));
free(CONST_CAST(char*)params->hash_name);
params->hash_name = NULL;
return -EINVAL;
@@ -166,20 +166,20 @@ int VERITY_write_sb(struct crypt_device *cd,
sizeof(struct verity_sb), device_path(device), sb_offset);
if (!uuid_string || uuid_parse(uuid_string, uuid) == -1) {
log_err(cd, _("Wrong VERITY UUID format provided on device %s.\n"),
log_err(cd, _("Wrong VERITY UUID format provided on device %s."),
device_path(device));
return -EINVAL;
}
if (params->flags & CRYPT_VERITY_NO_HEADER) {
log_err(cd, _("Verity device %s doesn't use on-disk header.\n"),
log_err(cd, _("Verity device %s doesn't use on-disk header."),
device_path(device));
return -EINVAL;
}
devfd = device_open(device, O_RDWR);
if (devfd < 0) {
log_err(cd, _("Cannot open device %s.\n"), device_path(device));
log_err(cd, _("Cannot open device %s."), device_path(device));
return -EINVAL;
}
@@ -199,8 +199,10 @@ int VERITY_write_sb(struct crypt_device *cd,
r = write_lseek_blockwise(devfd, device_block_size(device), device_alignment(device),
(char*)&sb, hdr_size, sb_offset) < hdr_size ? -EIO : 0;
if (r)
log_err(cd, _("Error during update of verity header on device %s.\n"),
log_err(cd, _("Error during update of verity header on device %s."),
device_path(device));
device_sync(device, devfd);
close(devfd);
return r;
@@ -242,6 +244,7 @@ int VERITY_activate(struct crypt_device *cd,
{
struct crypt_dm_active_device dmd;
uint32_t dmv_flags;
unsigned int fec_errors = 0;
int r;
log_dbg("Trying to activate VERITY device %s using hash %s.",
@@ -249,8 +252,18 @@ int VERITY_activate(struct crypt_device *cd,
if (verity_hdr->flags & CRYPT_VERITY_CHECK_HASH) {
log_dbg("Verification of data in userspace required.");
r = VERITY_verify(cd, verity_hdr,
root_hash, root_hash_size);
r = VERITY_verify(cd, verity_hdr, root_hash, root_hash_size);
if (r == -EPERM && fec_device) {
log_dbg("Verification failed, trying to repair with FEC device.");
r = VERITY_FEC_process(cd, verity_hdr, fec_device, 1, &fec_errors);
if (r < 0)
log_err(cd, _("Errors cannot be repaired with FEC device."));
else if (fec_errors)
log_err(cd, _("Found %u repairable errors with FEC device."),
fec_errors);
}
if (r < 0)
return r;
}
@@ -291,7 +304,7 @@ int VERITY_activate(struct crypt_device *cd,
r = dm_create_device(cd, name, CRYPT_VERITY, &dmd, 0);
if (r < 0 && (dm_flags(DM_VERITY, &dmv_flags) || !(dmv_flags & DM_VERITY_SUPPORTED))) {
log_err(cd, _("Kernel doesn't support dm-verity mapping.\n"));
log_err(cd, _("Kernel doesn't support dm-verity mapping."));
return -ENOTSUP;
}
if (r < 0)
@@ -302,6 +315,6 @@ int VERITY_activate(struct crypt_device *cd,
return r;
if (!r)
log_err(cd, _("Verity device detected corruption after activation.\n"));
log_err(cd, _("Verity device detected corruption after activation."));
return 0;
}

View File

@@ -21,6 +21,7 @@
#ifndef _VERITY_H
#define _VERITY_H
#include <stddef.h>
#include <stdint.h>
#define VERITY_MAX_HASH_TYPE 1
@@ -59,9 +60,11 @@ int VERITY_create(struct crypt_device *cd,
char *root_hash,
size_t root_hash_size);
int VERITY_FEC_create(struct crypt_device *cd,
int VERITY_FEC_process(struct crypt_device *cd,
struct crypt_params_verity *params,
struct device *fec_device);
struct device *fec_device,
int check_fec,
unsigned int *errors);
uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params);

View File

@@ -104,18 +104,18 @@ static int FEC_read_interleaved(struct fec_context *ctx, uint64_t i,
return -1;
}
/* encodes inputs to fd */
static int FEC_encode_inputs(struct crypt_device *cd,
struct crypt_params_verity *params,
struct fec_input_device *inputs,
size_t ninputs, int fd)
/* encodes/decode inputs to/from fd */
static int FEC_process_inputs(struct crypt_device *cd,
struct crypt_params_verity *params,
struct fec_input_device *inputs,
size_t ninputs, int fd,
int decode, unsigned int *errors)
{
int r = 0;
unsigned int i;
struct fec_context ctx;
uint32_t b;
uint64_t n;
uint8_t parity[params->fec_roots];
uint8_t rs_block[FEC_RSM];
uint8_t *buf = NULL;
void *rs;
@@ -129,7 +129,7 @@ static int FEC_encode_inputs(struct crypt_device *cd,
rs = init_rs_char(FEC_PARAMS(ctx.roots));
if (!rs) {
log_err(cd, _("Failed to allocate RS context.\n"));
log_err(cd, _("Failed to allocate RS context."));
return -ENOMEM;
}
@@ -144,17 +144,17 @@ static int FEC_encode_inputs(struct crypt_device *cd,
buf = malloc((size_t)ctx.block_size * ctx.rsn);
if (!buf) {
log_err(cd, _("Failed to allocate buffer.\n"));
log_err(cd, _("Failed to allocate buffer."));
r = -ENOMEM;
goto out;
}
/* encode input */
/* encode/decode input */
for (n = 0; n < ctx.rounds; ++n) {
for (i = 0; i < ctx.rsn; ++i) {
if (FEC_read_interleaved(&ctx, n * ctx.rsn * ctx.block_size + i,
&buf[i * ctx.block_size], ctx.block_size)) {
log_err(cd, _("Failed to read RS block %" PRIu64 " byte %d.\n"), n, i);
log_err(cd, _("Failed to read RS block %" PRIu64 " byte %d."), n, i);
r = -EIO;
goto out;
}
@@ -164,24 +164,45 @@ static int FEC_encode_inputs(struct crypt_device *cd,
for (i = 0; i < ctx.rsn; ++i)
rs_block[i] = buf[i * ctx.block_size + b];
encode_rs_char(rs, rs_block, parity);
if (write_buffer(fd, parity, sizeof(parity)) != (ssize_t)sizeof(parity)) {
log_err(cd, _("Failed to write parity for RS block %" PRIu64 ".\n"), n);
r = -EIO;
goto out;
/* decoding from parity device */
if (decode) {
if (read_buffer(fd, &rs_block[ctx.rsn], ctx.roots) != ctx.roots) {
log_err(cd, _("Failed to read parity for RS block %" PRIu64 "."), n);
r = -EIO;
goto out;
}
/* coverity[tainted_data] */
r = decode_rs_char(rs, rs_block);
if (r < 0) {
log_err(cd, _("Failed to repair parity for block %" PRIu64 "."), n);
goto out;
}
/* return number of detected errors */
if (errors)
*errors += r;
r = 0;
} else {
/* encoding and writing parity data to fec device */
encode_rs_char(rs, rs_block, &rs_block[ctx.rsn]);
if (write_buffer(fd, &rs_block[ctx.rsn], ctx.roots) != ctx.roots) {
log_err(cd, _("Failed to write parity for RS block %" PRIu64 "."), n);
r = -EIO;
goto out;
}
}
}
}
out:
free_rs_char(rs);
free(buf);
return r;
}
int VERITY_FEC_create(struct crypt_device *cd,
int VERITY_FEC_process(struct crypt_device *cd,
struct crypt_params_verity *params,
struct device *fec_device)
struct device *fec_device, int check_fec,
unsigned int *errors)
{
int r;
int fd = -1;
@@ -200,22 +221,25 @@ int VERITY_FEC_create(struct crypt_device *cd,
/* validate parameters */
if (params->data_block_size != params->hash_block_size) {
log_err(cd, _("Block sizes must match for FEC.\n"));
log_err(cd, _("Block sizes must match for FEC."));
return -EINVAL;
}
if (params->fec_roots > FEC_RSM - FEC_MIN_RSN ||
params->fec_roots < FEC_RSM - FEC_MAX_RSN) {
log_err(cd, _("Invalid number of parity bytes.\n"));
log_err(cd, _("Invalid number of parity bytes."));
return -EINVAL;
}
r = -EIO;
/* output device */
fd = open(device_path(fec_device), O_RDWR);
if (check_fec)
fd = open(device_path(fec_device), O_RDONLY);
else
fd = open(device_path(fec_device), O_RDWR);
if (fd == -1) {
log_err(cd, _("Cannot open device %s.\n"), device_path(fec_device));
log_err(cd, _("Cannot open device %s."), device_path(fec_device));
goto out;
}
@@ -227,25 +251,25 @@ int VERITY_FEC_create(struct crypt_device *cd,
/* input devices */
inputs[0].fd = open(device_path(inputs[0].device), O_RDONLY);
if (inputs[0].fd == -1) {
log_err(cd, _("Cannot open device %s.\n"), device_path(inputs[0].device));
log_err(cd, _("Cannot open device %s."), device_path(inputs[0].device));
goto out;
}
inputs[1].fd = open(device_path(inputs[1].device), O_RDONLY);
if (inputs[1].fd == -1) {
log_err(cd, _("Cannot open device %s.\n"), device_path(inputs[1].device));
log_err(cd, _("Cannot open device %s."), device_path(inputs[1].device));
goto out;
}
/* cover the entire hash device starting from hash_offset */
r = device_size(inputs[1].device, &inputs[1].count);
if (r) {
log_err(cd, _("Failed to determine size for device %s.\n"),
log_err(cd, _("Failed to determine size for device %s."),
device_path(inputs[1].device));
goto out;
}
inputs[1].count -= inputs[1].start;
r = FEC_encode_inputs(cd, params, inputs, FEC_INPUT_DEVICES, fd);
r = FEC_process_inputs(cd, params, inputs, FEC_INPUT_DEVICES, fd, check_fec, errors);
out:
if (inputs[0].fd != -1)
close(inputs[0].fd);

View File

@@ -56,7 +56,7 @@ static int verify_zero(struct crypt_device *cd, FILE *wr, size_t bytes)
}
for (i = 0; i < bytes; i++)
if (block[i]) {
log_err(cd, _("Spare area is not zeroed at position %" PRIu64 ".\n"),
log_err(cd, _("Spare area is not zeroed at position %" PRIu64 "."),
ftello(wr) - bytes);
return -EPERM;
}
@@ -157,7 +157,7 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
if (mult_overflow(&seek_rd, data_block, data_block_size) ||
mult_overflow(&seek_wr, hash_block, hash_block_size)) {
log_err(cd, _("Device offset overflow.\n"));
log_err(cd, _("Device offset overflow."));
return -EINVAL;
}
@@ -197,7 +197,7 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
return -EIO;
}
if (memcmp(read_digest, calculated_digest, digest_size)) {
log_err(cd, _("Verification failed at position %" PRIu64 ".\n"),
log_err(cd, _("Verification failed at position %" PRIu64 "."),
ftello(rd) - data_block_size);
return -EPERM;
}
@@ -270,7 +270,7 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
device_path(hash_device), hash_position);
if (data_blocks < 0 || hash_position < 0) {
log_err(cd, _("Invalid size parameters for verity device.\n"));
log_err(cd, _("Invalid size parameters for verity device."));
return -EINVAL;
}
@@ -284,20 +284,20 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
data_file_blocks = data_blocks;
if (mult_overflow(&data_device_size, data_blocks, data_block_size)) {
log_err(cd, _("Device offset overflow.\n"));
log_err(cd, _("Device offset overflow."));
return -EINVAL;
}
if (hash_levels(hash_block_size, digest_size, data_file_blocks, &hash_position,
&levels, &hash_level_block[0], &hash_level_size[0])) {
log_err(cd, _("Hash area overflow.\n"));
log_err(cd, _("Hash area overflow."));
return -EINVAL;
}
log_dbg("Using %d hash levels.", levels);
if (mult_overflow(&hash_device_size, hash_position, hash_block_size)) {
log_err(cd, _("Device offset overflow.\n"));
log_err(cd, _("Device offset overflow."));
return -EINVAL;
}
@@ -305,7 +305,7 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
data_device_size);
data_file = fopen(device_path(data_device), "r");
if (!data_file) {
log_err(cd, _("Cannot open device %s.\n"),
log_err(cd, _("Cannot open device %s."),
device_path(data_device)
);
r = -EIO;
@@ -316,7 +316,7 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
hash_device_size);
hash_file = fopen(device_path(hash_device), verify ? "r" : "r+");
if (!hash_file) {
log_err(cd, _("Cannot open device %s.\n"),
log_err(cd, _("Cannot open device %s."),
device_path(hash_device));
r = -EIO;
goto out;
@@ -336,7 +336,7 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
} else {
hash_file_2 = fopen(device_path(hash_device), "r");
if (!hash_file_2) {
log_err(cd, _("Cannot open device %s.\n"),
log_err(cd, _("Cannot open device %s."),
device_path(hash_device));
r = -EIO;
goto out;
@@ -367,20 +367,20 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
out:
if (verify) {
if (r)
log_err(cd, _("Verification of data area failed.\n"));
log_err(cd, _("Verification of data area failed."));
else {
log_dbg("Verification of data area succeeded.");
r = memcmp(root_hash, calculated_digest, digest_size) ? -EPERM : 0;
if (r)
log_err(cd, _("Verification of root hash failed.\n"));
log_err(cd, _("Verification of root hash failed."));
else
log_dbg("Verification of root hash succeeded.");
}
} else {
if (r == -EIO)
log_err(cd, _("Input/output error while creating hash area.\n"));
log_err(cd, _("Input/output error while creating hash area."));
else if (r)
log_err(cd, _("Creation of hash area failed.\n"));
log_err(cd, _("Creation of hash area failed."));
else {
fsync(fileno(hash_file));
memcpy(root_hash, calculated_digest, digest_size);
@@ -428,7 +428,7 @@ int VERITY_create(struct crypt_device *cd,
if (verity_hdr->data_block_size > pgsize)
log_err(cd, _("WARNING: Kernel cannot activate device if data "
"block size exceeds page size (%u).\n"), pgsize);
"block size exceeds page size (%u)."), pgsize);
return VERITY_create_or_verify_hash(cd, 0,
verity_hdr->hash_type,

View File

@@ -23,7 +23,7 @@ The reencryption can be temporarily suspended (by TERM signal or by
using ctrl+c) but you need to retain temporary files named LUKS-<uuid>.[log|org|new].
LUKS device is unavailable until reencryption is finished though.
Current working directory must by writable and temporary
Current working directory must be writable and temporary
files created during reencryption must be present.
For more info about LUKS see cryptsetup(8).
@@ -35,14 +35,14 @@ To start (or continue) re-encryption for <device> use:
\fIcryptsetup-reencrypt\fR <device>
\fB<options>\fR can be [\-\-batch-mode, \-\-block-size, \-\-cipher | \-\-keep-key,
\-\-debug, \-\-device-size, \-\-hash, \-\-iter-time | \-\-pbkdf\-force\-iterations,
\-\-debug, \-\-device-size, \-\-hash, \-\-header, \-\-iter-time | \-\-pbkdf\-force\-iterations,
\-\-key-file, \-\-key-size, \-\-key-slot, \-\-keyfile-offset, \-\-keyfile-size,
\-\-tries, \-\-pbkdf, \-\-pbkdf\-memory, \-\-pbkdf\-parallel, \-\-progress-frequency,
\-\-use-directio, \-\-use-random | \-\-use-urandom, \-\-use-fsync, \-\-uuid,
\-\-verbose, \-\-write-log]
\-\-master\-key\-file, \-\-tries, \-\-pbkdf, \-\-pbkdf\-memory, \-\-pbkdf\-parallel,
\-\-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
with \fI\-\-reduce-device-size\fR.
with \fI\-\-reduce-device-size\fR or with \fI\-\-header\fR option for detached header.
To remove encryption from device, use \fI\-\-decrypt\fR.
@@ -89,7 +89,17 @@ Specifies the hash used in the LUKS1 key setup scheme and volume key digest.
for new LUKS1 device header.
\fBNOTE:\fR with LUKS2 format this option is only relevant when new keyslot pbkdf algorithm
is set to PBKDF2 (see \fI\-\-pbkdf).
is set to PBKDF2 (see \fI\-\-pbkdf\fR).
.TP
.B "\-\-header\fR \fI<LUKS header file>\fR"
Use a detached (separated) metadata device or file where the
LUKS header is stored. This option allows one to store ciphertext
and LUKS header on different devices.
\fBWARNING:\fR There is no check whether the ciphertext device specified
actually belongs to the header given.
If used with \fI\-\-new\fR option, the header file will created (or overwritten).
Use with care.
.TP
.B "\-\-iter-time, \-i \fI<milliseconds>\fR"
The number of milliseconds to spend with PBKDF2 passphrase processing for the
@@ -106,7 +116,7 @@ This option can be combined only with \fI\-\-hash\fR, \fI\-\-iter-time\fR,
.B "\-\-key-file, \-d \fIname\fR"
Read the passphrase from file.
\fBWARNING:\fR \-\-key-file option can be used only if there only one active keyslot,
\fBWARNING:\fR \-\-key-file option can be used only if there is only one active keyslot,
or alternatively, also if \-\-key-slot option is specified (then all other keyslots
will be disabled in new LUKS device).
@@ -138,6 +148,9 @@ Read a maximum of \fIvalue\fR bytes from the key file.
Default is to read the whole file up to the compiled-in
maximum.
.TP
.B "\-\-master\-key\-file"
Use new volume (master) key stored in a file.
.TP
.B "\-\-new, \-N"
Create new header (encrypt not yet encrypted device).

View File

@@ -70,8 +70,8 @@ The following are valid actions for all supported device types.
.IP
Opens (creates a mapping with) <name> backed by device <device>.
Device type can be \fIplain\fR, \fIluks\fR (default), \fIloopaes\fR
or \fItcrypt\fR.
Device type can be \fIplain\fR, \fIluks\fR (default), \fIluks1\fR, \fIluks2\fR,
\fIloopaes\fR or \fItcrypt\fR.
For backward compatibility there are \fBopen\fR command aliases:
@@ -243,7 +243,7 @@ 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].
\-\-token\-only, \-\-disable\-keyring, \-\-disable\-locks, \-\-type].
.PP
\fIluksSuspend\fR <name>
.IP
@@ -266,19 +266,26 @@ Resumes a suspended device and reinstates the encryption key.
Prompts interactively for a passphrase if \-\-key-file is not given.
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-size, \-\-header,
\-\-disable\-keyring,\-\-disable\-locks]
\-\-disable\-keyring, \-\-disable\-locks, \-\-type]
.PP
\fIluksAddKey\fR <device> [<key file with new key>]
.IP
adds a new passphrase. An existing passphrase must be supplied
Adds a new passphrase. An existing passphrase must be supplied
interactively or via \-\-key-file.
The new passphrase to be added can be specified interactively
or read from the file given as positional argument.
\fBNOTE:\fR with \-\-unbound option the action creates new unbound
LUKS2 keyslot. The keyslot cannot be used for device activation.
If you don't pass new key via \-\-master\-key\-file option,
new random key is generated. Existing passphrase for any active keyslot
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].
\-\-iter\-time, \-\-force\-password, \-\-header, \-\-disable\-locks,
\-\-unbound, \-\-type].
.PP
\fIluksRemoveKey\fR <device> [<key file with passphrase to be removed>]
.IP
@@ -287,7 +294,7 @@ passphrase to be removed can be specified interactively,
as the positional argument or via \-\-key-file.
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
\-\-keyfile\-size, \-\-header, \-\-disable\-locks]
\-\-keyfile\-size, \-\-header, \-\-disable\-locks, \-\-type]
\fBWARNING:\fR If you read the passphrase from stdin
(without further argument or with '-' as an argument
@@ -321,7 +328,31 @@ inaccessible.
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
\-\-keyfile\-size, \-\-new\-keyfile\-offset,
\-\-new\-keyfile\-size, \-\-key\-slot, \-\-force\-password, \-\-header,
\-\-disable\-locks].
\-\-disable\-locks, \-\-type].
.PP
.PP
\fIluksConvertKey\fR <device>
.IP
Converts an existing LUKS2 keyslot to new pbkdf parameters. The
passphrase for keyslot to be converted must be supplied interactively
or via \-\-key\-file. If no \-\-pbkdf parameters are specified LUKS2
default pbkdf values will apply.
If a keyslot is specified (via \-\-key\-slot), the passphrase for that
keyslot must be given. If no keyslot is specified and there is still
a free keyslot, then the new parameters will be put into a free
keyslot before the keyslot containing the old parameters is
purged. If there is no free keyslot, then the keyslot with the old
parameters is overwritten directly.
\fBWARNING:\fR If a keyslot is overwritten, a media failure during
this operation can cause the overwrite to fail after the old
parameters have been wiped and make the LUKS container inaccessible.
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
\-\-keyfile\-size, \-\-key\-slot, \-\-header, \-\-disable\-locks,
\-\-iter-time, \-\-pbkdf, \-\-pbkdf\-force\-iterations,
\-\-pbkdf\-memory, \-\-pbkdf\-parallel].
.PP
\fIluksKillSlot\fR <device> <key slot number>
.IP
@@ -333,7 +364,7 @@ an interactive confirmation when doing so. Removing the last
passphrase makes a LUKS container permanently inaccessible.
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
\-\-keyfile\-size, \-\-header, \-\-disable\-locks].
\-\-keyfile\-size, \-\-header, \-\-disable\-locks, \-\-type].
\fBWARNING:\fR If you read the passphrase from stdin
(without further argument or with '-' as an argument
@@ -368,23 +399,27 @@ Set new UUID if \fI\-\-uuid\fR option is specified.
Returns true, if <device> is a LUKS device, false otherwise.
Use option \-v to get human-readable feedback. 'Command successful.'
means the device is a LUKS device.
By specifying \-\-type you may query for specific LUKS version.
.PP
\fIluksDump\fR <device>
.IP
Dump the header information of a LUKS device.
If the \-\-dump\-master\-key option is used, the LUKS device master key is
dumped instead of the keyslot info. Beware that the master key cannot be
changed and can be used to decrypt the data stored in the LUKS container
without a passphrase and even without the LUKS header. This means
that if the master key is compromised, the whole device has to be
erased to prevent further access. Use this option carefully.
dumped instead of the keyslot info. Together with \-\-master\-key\-file option,
master key is dumped to a file instead of standard output. Beware that the
master key cannot be changed without reencryption and can be used to decrypt
the data stored in the LUKS container without a passphrase and even without the
LUKS header. This means that if the master key is compromised, the whole device
has to be erased to prevent further access. Use this option carefully.
To dump the master key, a passphrase has to be supplied,
either interactively or via \-\-key\-file.
\fB<options>\fR can be [\-\-dump\-master\-key, \-\-key\-file,
\-\-keyfile\-offset, \-\-keyfile\-size, \-\-header, \-\-disable\-locks].
\-\-keyfile\-offset, \-\-keyfile\-size, \-\-header, \-\-disable\-locks,
\-\-master\-key\-file, \-\-type].
\fBWARNING:\fR If \-\-dump\-master\-key is used with \-\-key\-file
and the argument to \-\-key\-file is '-', no validation question
@@ -422,9 +457,9 @@ of the LUKS header already on the device and of the header backup
match. Alternatively, if there is no LUKS header on the device,
the backup will also be written to it.
.PP
\fItoken\fR <add|remove> <device>
\fItoken\fR <add|remove|import|export> <device>
.IP
Adds a new keyring token to enable auto-activation of the device.
Action \fIadd\fR creates new keyring token to enable auto-activation of the device.
For the auto-activation, the passphrase must be stored in keyring with the specified
description. Usually, the passphrase should be stored in \fIuser\fR or
\fIuser-session\fR keyring.
@@ -440,15 +475,27 @@ To remove existing token, specify the token ID which should be removed with
\fBWARNING:\fR The action \fItoken remove\fR removes any token type, not just \fIkeyring\fR
type from token slot specified by \-\-token\-id option.
\fB<options>\fR can be [\-\-header, \-\-token\-id, \-\-key-slot, \-\-key\-description,
\-\-disable\-locks, \-\-disable\-keyring].
Action \fIimport\fR can store arbitrary valid token json in LUKS2 header. It may be passed via
standard input or via file passed in \-\-json\-file option. If you specify \-\-key\-slot then
successfully imported token is also assigned to the key slot.
Action \fIexport\fR writes requested token json to a file passed with \-\-json\-file or
to standard output.
\fB<options>\fR can be [\-\-header, \-\-token\-id, \-\-key\-slot, \-\-key\-description,
\-\-disable\-locks, \-\-disable\-keyring, \-\-json\-file].
.PP
\fIconvert\fR <device> \-\-type <format>
.IP
Converts the device between LUKS and LUKS2 format (if possible).
The conversion will not be performed if there is an additional LUKS2 feature or LUKS has
Converts the device between LUKS1 and LUKS2 format (if possible).
The conversion will not be performed if there is an additional LUKS2 feature or LUKS1 has
unsupported header size.
Conversion (both directions) must be performed on inactive device. There must not be active
dm-crypt mapping established for LUKS header requested for conversion.
\fB\-\-type\fR option is mandatory with following accepted values: \fIluks1\fR or \fIluks2\fR.
\fBWARNING:\fR The \fIconvert\fR action can destroy the LUKS header in the case of a crash
during conversion or if a media error occurs.
Always create a header backup before performing this operation!
@@ -539,7 +586,7 @@ value, \fBadditionally to \-\-veracrypt \fR use either the
line or use \fB\-\-veracrypt\-query\-pim\fR to be prompted for the PIM.
The PIM value affects the number of iterations applied during key derivation. Please refer to
\fBhttps://www.veracrypt.fr/en/Personal%20Iterations%20Multiplier%20(PIM).html\fR
\fBhttps://www.veracrypt.fr/en/Personal%20Iterations%20Multiplier%20%28PIM%29.html\fR
for more detailed information.
\fBNOTE:\fR Activation with \fBtcryptOpen\fR is supported only for cipher chains
@@ -630,7 +677,8 @@ for LUKS device type.
This command is useful to fix some known benign LUKS metadata
header corruptions. Only basic corruptions of unused keyslot
are fixable. This command will only change the LUKS header, not
any key-slot data.
any key-slot data. You may enforce LUKS version by adding \-\-type
option.
\fBWARNING:\fR Always create a binary backup of the original
header before calling this command.
@@ -770,6 +818,10 @@ LUKS header and all other parameters are the same,
then the new header decrypts the data encrypted with the
header the master key was taken from.
Action \fIluksDump\fR together with \-\-dump\-master\-key
option: The volume (master) key is stored in a file instead of
being printed out to standard output.
\fBWARNING:\fR If you create your own master key, you
need to make sure to do it right. Otherwise, you can end
up with a low-entropy or otherwise partially predictable
@@ -786,6 +838,11 @@ For \fIluksDump\fR this option includes the master key in the displayed
information. Use with care, as the master key can be used to
bypass the passphrases, see also option \-\-master\-key\-file.
.TP
.B "\-\-json\-file"
Read token json from a file or write token to it. See \fItoken\fR action for more
information. \-\-json\-file=- reads json from standard input or writes it to
standard output respectively.
.TP
.B "\-\-use\-random"
.TP
.B "\-\-use\-urandom"
@@ -1136,6 +1193,11 @@ to the sector.
aligned to page size and page-cache initiates read of a sector with invalid
integrity tag.
.TP
.B "\-\-unbound"
Creates new LUKS2 unbound keyslot. See \fIluksAddKey\fR action for more
details.
.TP
.B "\-\-tcrypt\-hidden"
.B "\-\-tcrypt\-system"
.B "\-\-tcrypt\-backup"

View File

@@ -39,7 +39,8 @@ Creates a mapping with <name> backed by device <data_device> and using
The <root_hash> is a hexadecimal string.
\fB<options>\fR can be [\-\-hash-offset, \-\-no-superblock,
\-\-ignore-corruption or \-\-restart-on-corruption, \-\-ignore-zero-blocks]
\-\-ignore-corruption or \-\-restart-on-corruption, \-\-ignore-zero-blocks,
\-\-check-at-most-once]
If option \-\-no-superblock is used, you have to use as the same options
as in initial format operation.
@@ -133,6 +134,15 @@ and always directly return zeroes instead.
\fBWARNING:\fR Use this option only in very specific cases.
This option is available since Linux kernel version 4.5.
.TP
.B "\-\-check-at-most-once"
Instruct kernel to verify blocks only the first time they are read
from the data device, rather than every time.
\fBWARNING:\fR It provides a reduced level of security because only
offline tampering of the data device's content will be detected,
not online tampering.
This option is available since Linux kernel version 4.17.
.TP
.B "\-\-hash=hash"
Hash algorithm for dm-verity. For default see \-\-help option.
.TP

View File

@@ -123,7 +123,7 @@ int main(int argc, char *argv[])
/*
* Need to create temporary keyslot device-mapper devices and allocate loop if needed,
* so root is requried here.
* so root is required here.
*/
if (getuid() != 0) {
printf("You must be root to run this program.\n");

View File

@@ -28,4 +28,5 @@ install() {
# shellcheck disable=SC2154
inst_hook cmdline 30 "$moddir/parse-reencrypt.sh"
inst_simple "$moddir"/reencrypt.sh /sbin/reencrypt
inst_simple "$moddir"/reencrypt-verbose.sh /sbin/cryptsetup-reencrypt-verbose
}

View File

@@ -0,0 +1,5 @@
#!/bin/sh
# Route stdout to stderr in initrd. Otherwise output is invisible
# unless we run in debug mode.
/sbin/cryptsetup-reencrypt $@ 1>&2

View File

@@ -18,7 +18,7 @@ else
device="$1"
fi
PARAMS="$device -T 1 --use-fsync -B 32"
PARAMS="$device -T 1 --use-fsync --progress-frequency 5 -B 32"
if [ "$3" != "any" ]; then
PARAMS="$PARAMS -S $3"
fi
@@ -50,10 +50,10 @@ reenc_run() {
fi
/bin/plymouth ask-for-password \
--prompt "$_prompt" \
--command="/sbin/cryptsetup-reencrypt $PARAMS"
--command="/sbin/cryptsetup-reencrypt-verbose $PARAMS"
else
info "REENCRYPT using key $1"
reenc_readkey "$1" | /sbin/cryptsetup-reencrypt -d - $PARAMS
reenc_readkey "$1" | /sbin/cryptsetup-reencrypt-verbose -d - $PARAMS
fi
_ret=$?
cd $cwd

View File

@@ -4,14 +4,11 @@ LDLIBS=-ljson-c -luuid -lgcrypt -ldevmapper -lpthread -lssh
CC=gcc
TARGET2=keyslot_test_remote_pass
TARGET4=keyslot_add_by_key
SOURCES=keyslot_test.c
OBJECTS=$(SOURCES:.c=.o)
SOURCES2=keyslot_test_remote_pass.c
OBJECTS2=$(SOURCES2:.c=.o)
SOURCES4=keyslot_add_by_key.c
OBJECTS4=$(SOURCES4:.c=.o)
all: $(TARGET) $(TARGET2) $(TARGET4)
@@ -21,10 +18,7 @@ $(TARGET): $(OBJECTS) ../../.libs/libcryptsetup.a
$(TARGET2): $(OBJECTS2) ../../.libs/libcryptsetup.a
$(CC) -o $@ $^ $(LDLIBS)
$(TARGET4): $(OBJECTS4) ../../.libs/libcryptsetup.a
$(CC) -o $@ $^ $(LDLIBS)
clean:
rm -f *.o *~ core $(TARGET) $(TARGET2) $(TARGET4)
rm -f *.o *~ core $(TARGET) $(TARGET2)
.PHONY: clean

View File

@@ -1,62 +0,0 @@
/*
* Prototype LUKS2 utility for keyslots unassigned to volume
*
* Copyright (C) 2017-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2017-2018, Ondrej Kozina <okozina@redhat.com>
*
* Use:
* - generate LUKS2 device
* - add new keyslot unassigned to segment using this example
* (it'll generate random key with same size as volume key)
*
* 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "libcryptsetup.h"
int main(int argc, char **argv)
{
int r;
struct crypt_device *cd;
if (argc < 3)
return EXIT_FAILURE;
if (crypt_init(&cd, argv[1])) {
fprintf(stderr, "Failed to init device %s.\n", argv[1]);
return EXIT_FAILURE;
}
if (crypt_load(cd, CRYPT_LUKS2, NULL)) {
fprintf(stderr, "Failed to load luks2 device %s.\n", argv[1]);
crypt_free(cd);
return EXIT_FAILURE;
}
r = crypt_keyslot_add_by_key(cd, CRYPT_ANY_SLOT, NULL,
crypt_get_volume_key_size(cd), argv[2],
strlen(argv[2]),
CRYPT_VOLUME_KEY_NO_SEGMENT);
if (r < 0)
fprintf(stderr, "Failed to load luks2 device %s.\n", argv[1]);
crypt_free(cd);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

2889
po/cs.po

File diff suppressed because it is too large Load Diff

3161
po/da.po

File diff suppressed because it is too large Load Diff

2989
po/de.po

File diff suppressed because it is too large Load Diff

2936
po/es.po

File diff suppressed because it is too large Load Diff

2988
po/fr.po

File diff suppressed because it is too large Load Diff

2927
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2980
po/uk.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -512,6 +512,8 @@ static PyObject *CryptSetup_killSlot(CryptSetupObject* self, PyObject *args, PyO
case CRYPT_SLOT_INVALID:
PyErr_SetString(PyExc_ValueError, "Invalid slot");
break;
default:
break;
}
return NULL;

View File

@@ -4,8 +4,11 @@ if CRYPTSETUP
cryptsetup_SOURCES = \
lib/utils_crypt.c \
lib/utils_loop.c \
lib/utils_io.c \
lib/utils_blkid.c \
src/utils_tools.c \
src/utils_password.c \
src/utils_luks2.c \
src/cryptsetup.c \
src/cryptsetup.h
@@ -14,7 +17,8 @@ cryptsetup_LDADD = -lm \
@POPT_LIBS@ \
@PWQUALITY_LIBS@ \
@PASSWDQC_LIBS@ \
@UUID_LIBS@
@UUID_LIBS@ \
@BLKID_LIBS@
sbin_PROGRAMS += cryptsetup
@@ -36,13 +40,16 @@ if VERITYSETUP
veritysetup_SOURCES = \
lib/utils_crypt.c \
lib/utils_loop.c \
lib/utils_io.c \
lib/utils_blkid.c \
src/utils_tools.c \
src/veritysetup.c \
src/cryptsetup.h
veritysetup_LDADD = -lm \
libcryptsetup.la \
@POPT_LIBS@
@POPT_LIBS@ \
@BLKID_LIBS@
sbin_PROGRAMS += veritysetup
@@ -64,6 +71,8 @@ if INTEGRITYSETUP
integritysetup_SOURCES = \
lib/utils_crypt.c \
lib/utils_loop.c \
lib/utils_io.c \
lib/utils_blkid.c \
src/utils_tools.c \
src/integritysetup.c \
src/cryptsetup.h
@@ -71,7 +80,8 @@ integritysetup_SOURCES = \
integritysetup_LDADD = -lm \
libcryptsetup.la \
@POPT_LIBS@ \
@UUID_LIBS@
@UUID_LIBS@ \
@BLKID_LIBS@
sbin_PROGRAMS += integritysetup
@@ -91,6 +101,8 @@ endif
if REENCRYPT
cryptsetup_reencrypt_SOURCES = \
lib/utils_crypt.c \
lib/utils_io.c \
lib/utils_blkid.c \
src/utils_tools.c \
src/utils_password.c \
src/cryptsetup_reencrypt.c \
@@ -101,7 +113,8 @@ cryptsetup_reencrypt_LDADD = -lm \
@POPT_LIBS@ \
@PWQUALITY_LIBS@ \
@PASSWDQC_LIBS@ \
@UUID_LIBS@
@UUID_LIBS@ \
@BLKID_LIBS@
sbin_PROGRAMS += cryptsetup-reencrypt

File diff suppressed because it is too large Load Diff

View File

@@ -43,6 +43,8 @@
#include "lib/utils_crypt.h"
#include "lib/utils_loop.h"
#include "lib/utils_fips.h"
#include "lib/utils_io.h"
#include "lib/utils_blkid.h"
#include "libcryptsetup.h"
@@ -60,7 +62,6 @@ extern int opt_batch_mode;
extern int opt_force_password;
extern int opt_progress_frequency;
/* Common tools */
void clogger(struct crypt_device *cd, int level, const char *file, int line,
const char *format, ...) __attribute__ ((format (printf, 5, 6)));
@@ -75,6 +76,10 @@ void usage(poptContext popt_context, int exitcode, const char *error, const char
void dbg_version_and_cmd(int argc, const char **argv);
int translate_errno(int r);
typedef enum { CREATED, UNLOCKED, REMOVED } crypt_object_op;
void tools_keyslot_msg(int keyslot, crypt_object_op op);
void tools_token_msg(int token, crypt_object_op op);
extern volatile int quit;
void set_int_block(int block);
void set_int_handler(int block);
@@ -87,6 +92,7 @@ int tools_get_key(const char *prompt,
const char *key_file,
int timeout, int verify, int pwquality,
struct crypt_device *cd);
void tools_passphrase_msg(int r);
int tools_is_stdin(const char *key_file);
int tools_string_to_size(struct crypt_device *cd, const char *s, uint64_t *size);
int tools_is_cipher_null(const char *cipher);
@@ -97,6 +103,15 @@ 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_read_mk(const char *file, char **key, int keysize);
int tools_write_mk(const char *file, const char *key, int keysize);
int tools_read_json_file(struct crypt_device *cd, const char *file, char **json, size_t *json_size);
int tools_write_json_file(struct crypt_device *cd, const char *file, const char *json);
int tools_detect_signatures(const char *device, int ignore_luks, size_t *count);
int tools_wipe_all_signatures(const char *path);
/* 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

@@ -33,6 +33,7 @@
static const char *opt_cipher = NULL;
static const char *opt_hash = NULL;
static const char *opt_key_file = NULL;
static const char *opt_master_key_file = NULL;
static const char *opt_uuid = NULL;
static const char *opt_type = "luks";
static long opt_keyfile_size = 0;
@@ -55,6 +56,7 @@ static int opt_key_size = 0;
static int opt_new = 0;
static int opt_keep_key = 0;
static int opt_decrypt = 0;
static const char *opt_header_device = NULL;
static const char *opt_reduce_size_str = NULL;
static uint64_t opt_reduce_size = 0;
@@ -68,6 +70,7 @@ static const char **action_argv;
#define MAX_TOKEN 32
struct reenc_ctx {
char *device;
char *device_header;
char *device_uuid;
const char *type;
uint64_t device_size; /* overridden by parameter */
@@ -140,13 +143,20 @@ static const char *luksType(const char *type)
if (type && !strcmp(type, "luks2"))
return CRYPT_LUKS2;
/* make LUKS1 default */
if (type && (!strcmp(type, "luks1") || !strcmp(type, "luks")))
if (type && !strcmp(type, "luks1"))
return CRYPT_LUKS1;
if (!type || !strcmp(type, "luks"))
return DEFAULT_LUKS_FORMAT;
return NULL;
}
static const char *hdr_device(const struct reenc_ctx *rc)
{
return rc->device_header ?: rc->device;
}
static int set_reencrypt_requirement(const struct reenc_ctx *rc)
{
uint32_t reqs;
@@ -154,20 +164,20 @@ static int set_reencrypt_requirement(const struct reenc_ctx *rc)
struct crypt_device *cd = NULL;
struct crypt_params_integrity ip = { 0 };
if (crypt_init(&cd, rc->device) ||
if (crypt_init(&cd, hdr_device(rc)) ||
crypt_load(cd, CRYPT_LUKS2, NULL) ||
crypt_persistent_flags_get(cd, CRYPT_FLAGS_REQUIREMENTS, &reqs))
goto out;
/* reencrypt already in-progress */
if (reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT) {
log_err(_("Reencryption already in-progress.\n"));
log_err(_("Reencryption already in-progress."));
goto out;
}
/* raw integrity info is available since 2.0 */
if (crypt_get_integrity_info(cd, &ip) || ip.tag_size) {
log_err(_("Reencryption of device with integrity profile is not supported.\n"));
log_err(_("Reencryption of device with integrity profile is not supported."));
r = -ENOTSUP;
goto out;
}
@@ -179,7 +189,7 @@ out:
}
/* Depends on the first two fields of LUKS1 header format, magic and version */
static int device_check(struct reenc_ctx *rc, header_magic set_magic)
static int device_check(struct reenc_ctx *rc, const char *device, header_magic set_magic)
{
char *buf = NULL;
int r, devfd;
@@ -187,14 +197,14 @@ static int device_check(struct reenc_ctx *rc, header_magic set_magic)
uint16_t version;
size_t buf_size = pagesize();
devfd = open(rc->device, O_RDWR | O_EXCL | O_DIRECT);
devfd = open(device, O_RDWR | O_EXCL | O_DIRECT);
if (devfd == -1) {
if (errno == EBUSY) {
log_err(_("Cannot exclusively open %s, device in use.\n"),
rc->device);
log_err(_("Cannot exclusively open %s, device in use."),
device);
return -EBUSY;
}
log_err(_("Cannot open device %s.\n"), rc->device);
log_err(_("Cannot open device %s."), device);
return -EINVAL;
}
@@ -204,14 +214,14 @@ static int device_check(struct reenc_ctx *rc, header_magic set_magic)
}
if (posix_memalign((void *)&buf, alignment(devfd), buf_size)) {
log_err(_("Allocation of aligned memory failed.\n"));
log_err(_("Allocation of aligned memory failed."));
r = -ENOMEM;
goto out;
}
s = read(devfd, buf, buf_size);
if (s < 0 || s != (ssize_t)buf_size) {
log_err(_("Cannot read device %s.\n"), rc->device);
log_err(_("Cannot read device %s."), device);
r = -EIO;
goto out;
}
@@ -222,11 +232,11 @@ static int device_check(struct reenc_ctx *rc, header_magic set_magic)
if (set_magic == MAKE_UNUSABLE && !memcmp(buf, MAGIC, MAGIC_L) &&
version == 1) {
log_verbose(_("Marking LUKS1 device %s unusable.\n"), rc->device);
log_verbose(_("Marking LUKS1 device %s unusable."), device);
memcpy(buf, NOMAGIC, MAGIC_L);
r = 0;
} else if (set_magic == MAKE_UNUSABLE && version == 2) {
log_verbose(_("Setting LUKS2 offline reencrypt flag on device %s.\n"), rc->device);
log_verbose(_("Setting LUKS2 offline reencrypt flag on device %s."), device);
r = set_reencrypt_requirement(rc);
if (!r)
rc->stained = 1;
@@ -243,14 +253,14 @@ static int device_check(struct reenc_ctx *rc, header_magic set_magic)
goto out;
s = write(devfd, buf, buf_size);
if (s < 0 || s != (ssize_t)buf_size) {
log_err(_("Cannot write device %s.\n"), rc->device);
log_err(_("Cannot write device %s."), device);
r = -EIO;
}
if (s > 0 && set_magic == MAKE_UNUSABLE)
rc->stained = 1;
}
if (r)
log_dbg("LUKS signature check failed for %s.", rc->device);
log_dbg("LUKS signature check failed for %s.", device);
out:
if (buf)
memset(buf, 0, buf_size);
@@ -284,7 +294,7 @@ static int create_empty_header(const char *new_file, const char *old_file,
* if requesting key size change, try to use offset
* here can be enough space to fit new key.
*/
if (opt_key_size)
if (opt_key_size && data_sector)
size = data_sector * SECTOR_SIZE;
/* if reducing size, be sure we have enough space */
@@ -327,7 +337,7 @@ static int write_log(struct reenc_ctx *rc)
r = write(rc->log_fd, rc->log_buf, SECTOR_SIZE);
if (r < 0 || r != SECTOR_SIZE) {
log_err(_("Cannot write reencryption log file.\n"));
log_err(_("Cannot write reencryption log file."));
return -EIO;
}
@@ -383,7 +393,7 @@ static int parse_log(struct reenc_ctx *rc)
s = read(rc->log_fd, rc->log_buf, SECTOR_SIZE);
if (s == -1) {
log_err(_("Cannot read reencryption log file.\n"));
log_err(_("Cannot read reencryption log file."));
return -EIO;
}
@@ -394,7 +404,7 @@ static int parse_log(struct reenc_ctx *rc)
if (end) {
*end++ = '\0';
if (parse_line_log(rc, start)) {
log_err("Wrong log format.\n");
log_err("Wrong log format.");
return -EINVAL;
}
}
@@ -471,7 +481,7 @@ static int activate_luks_headers(struct reenc_ctx *rc)
(r = crypt_set_data_device(cd, rc->device)))
goto out;
log_verbose(_("Activating temporary device using old LUKS header.\n"));
log_verbose(_("Activating temporary device using old LUKS header."));
if ((r = crypt_activate_by_passphrase(cd, rc->header_file_org,
opt_key_slot, pwd_old, pwd_old_len,
CRYPT_ACTIVATE_READONLY|CRYPT_ACTIVATE_PRIVATE)) < 0)
@@ -482,7 +492,7 @@ static int activate_luks_headers(struct reenc_ctx *rc)
(r = crypt_set_data_device(cd_new, rc->device)))
goto out;
log_verbose(_("Activating temporary device using new LUKS header.\n"));
log_verbose(_("Activating temporary device using new LUKS header."));
if ((r = crypt_activate_by_passphrase(cd_new, rc->header_file_new,
opt_key_slot, pwd_new, pwd_new_len,
CRYPT_ACTIVATE_SHARED|CRYPT_ACTIVATE_PRIVATE)) < 0)
@@ -492,7 +502,7 @@ out:
crypt_free(cd);
crypt_free(cd_new);
if (r < 0)
log_err(_("Activation of temporary devices failed.\n"));
log_err(_("Activation of temporary devices failed."));
return r;
}
@@ -525,8 +535,38 @@ static int set_pbkdf_params(struct crypt_device *cd, const char *dev_type)
return crypt_set_pbkdf_type(cd, &pbkdf);
}
static int create_new_header(struct reenc_ctx *rc, const char *cipher,
const char *cipher_mode, const char *uuid,
static int create_new_keyslot(struct reenc_ctx *rc, int keyslot,
struct crypt_device *cd_old,
struct crypt_device *cd_new)
{
int r;
char *key = NULL;
size_t key_size;
if (cd_old && crypt_keyslot_status(cd_old, keyslot) == CRYPT_SLOT_UNBOUND) {
key_size = 4096;
key = crypt_safe_alloc(key_size);
if (!key)
return -ENOMEM;
r = crypt_volume_key_get(cd_old, keyslot, key, &key_size,
rc->p[keyslot].password, rc->p[keyslot].passwordLen);
if (r == keyslot) {
r = crypt_keyslot_add_by_key(cd_new, keyslot, key, key_size,
rc->p[keyslot].password, rc->p[keyslot].passwordLen,
CRYPT_VOLUME_KEY_NO_SEGMENT);
} else
r = -EINVAL;
crypt_safe_free(key);
} else
r = crypt_keyslot_add_by_volume_key(cd_new, keyslot, NULL, 0,
rc->p[keyslot].password, rc->p[keyslot].passwordLen);
return r;
}
static int create_new_header(struct reenc_ctx *rc, struct crypt_device *cd_old,
const char *cipher, const char *cipher_mode,
const char *uuid,
const char *key, int key_size,
const char *type,
void *params)
@@ -544,22 +584,23 @@ static int create_new_header(struct reenc_ctx *rc, const char *cipher,
r = set_pbkdf_params(cd_new, type);
if (r) {
log_err(_("Failed to set PBKDF parameters.\n"));
log_err(_("Failed to set PBKDF parameters."));
goto out;
}
if ((r = crypt_format(cd_new, type, cipher, cipher_mode,
uuid, key, key_size, params)))
goto out;
log_verbose(_("New LUKS header for device %s created.\n"), rc->device);
log_verbose(_("New LUKS header for device %s created."), rc->device);
for (i = 0; i < crypt_keyslot_max(type); i++) {
if (!rc->p[i].password)
continue;
if ((r = crypt_keyslot_add_by_volume_key(cd_new, i,
NULL, 0, rc->p[i].password, rc->p[i].passwordLen)) < 0)
r = create_new_keyslot(rc, i, cd_old, cd_new);
if (r < 0)
goto out;
log_verbose(_("Activated keyslot %i.\n"), r);
tools_keyslot_msg(r, CREATED);
r = 0;
}
out:
@@ -609,7 +650,7 @@ static int luks2_metadata_copy(struct reenc_ctx *rc)
case CRYPT_TOKEN_INACTIVE:
break;
case CRYPT_TOKEN_INTERNAL_UNKNOWN:
log_err(_("This version of cryptsetup-reencrypt can't handle new internal token type %s.\n"), type);
log_err(_("This version of cryptsetup-reencrypt can't handle new internal token type %s."), type);
r = -EINVAL;
goto out;
case CRYPT_TOKEN_INTERNAL:
@@ -631,19 +672,19 @@ static int luks2_metadata_copy(struct reenc_ctx *rc)
}
if ((r = crypt_persistent_flags_get(cd_old, CRYPT_FLAGS_ACTIVATION, &flags))) {
log_err(_("Failed to read activation flags from backup header.\n"));
log_err(_("Failed to read activation flags from backup header."));
goto out;
}
if ((r = crypt_persistent_flags_set(cd_new, CRYPT_FLAGS_ACTIVATION, flags))) {
log_err(_("Failed to write activation flags to new header.\n"));
log_err(_("Failed to write activation flags to new header."));
goto out;
}
if ((r = crypt_persistent_flags_get(cd_old, CRYPT_FLAGS_REQUIREMENTS, &flags))) {
log_err(_("Failed to read requirements from backup header.\n"));
log_err(_("Failed to read requirements from backup header."));
goto out;
}
if ((r = crypt_persistent_flags_set(cd_new, CRYPT_FLAGS_REQUIREMENTS, flags)))
log_err(_("Failed to read requirements from backup header.\n"));
log_err(_("Failed to read requirements from backup header."));
out:
crypt_free(cd_old);
crypt_free(cd_new);
@@ -659,13 +700,13 @@ static int backup_luks_headers(struct reenc_ctx *rc)
struct crypt_params_luks2 params2 = {0};
struct stat st;
char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char *old_key = NULL;
size_t old_key_size;
char *key = NULL;
size_t key_size;
int r;
log_dbg("Creating LUKS header backup for device %s.", rc->device);
log_dbg("Creating LUKS header backup for device %s.", hdr_device(rc));
if ((r = crypt_init(&cd, rc->device)) ||
if ((r = crypt_init(&cd, hdr_device(rc))) ||
(r = crypt_load(cd, CRYPT_LUKS, NULL)))
goto out;
@@ -676,10 +717,11 @@ static int backup_luks_headers(struct reenc_ctx *rc)
goto out;
if ((r = stat(rc->header_file_tmp, &st)))
goto out;
/* coverity[toctou] */
if ((r = chmod(rc->header_file_tmp, st.st_mode | S_IWUSR)))
goto out;
}
log_verbose(_("%s header backup of device %s created.\n"), rc->device, isLUKS2(rc->type) ? "LUKS2" : "LUKS1");
log_verbose(_("%s header backup of device %s created."), isLUKS2(rc->type) ? "LUKS2" : "LUKS1", rc->device);
/* For decrypt, new header will be fake one, so we are done here. */
if (rc->reencrypt_mode == DECRYPT)
@@ -699,31 +741,37 @@ static int backup_luks_headers(struct reenc_ctx *rc)
if (opt_cipher) {
r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
if (r < 0) {
log_err(_("No known cipher specification pattern detected.\n"));
log_err(_("No known cipher specification pattern detected."));
goto out;
}
}
key_size = opt_key_size ? opt_key_size / 8 : crypt_get_volume_key_size(cd);
if (opt_keep_key) {
log_dbg("Keeping key from old header.");
old_key_size = crypt_get_volume_key_size(cd);
old_key = crypt_safe_alloc(old_key_size);
if (!old_key) {
key_size = crypt_get_volume_key_size(cd);
key = crypt_safe_alloc(key_size);
if (!key) {
r = -ENOMEM;
goto out;
}
r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, old_key, &old_key_size,
r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, key, &key_size,
rc->p[rc->keyslot].password, rc->p[rc->keyslot].passwordLen);
if (r < 0)
goto out;
} else if (opt_master_key_file) {
log_dbg("Loading new key from file.");
r = tools_read_mk(opt_master_key_file, &key, key_size);
}
r = create_new_header(rc,
if (r < 0)
goto out;
r = create_new_header(rc, cd,
opt_cipher ? cipher : crypt_get_cipher(cd),
opt_cipher ? cipher_mode : crypt_get_cipher_mode(cd),
crypt_get_uuid(cd),
old_key,
opt_key_size ? opt_key_size / 8 : crypt_get_volume_key_size(cd),
key,
key_size,
rc->type,
isLUKS2(rc->type) ? (void*)&params2 : (void*)&params);
@@ -731,9 +779,9 @@ static int backup_luks_headers(struct reenc_ctx *rc)
r = luks2_metadata_copy(rc);
out:
crypt_free(cd);
crypt_safe_free(old_key);
crypt_safe_free(key);
if (r)
log_err(_("Creation of LUKS backup headers failed.\n"));
log_err(_("Creation of LUKS backup headers failed."));
return r;
}
@@ -767,7 +815,7 @@ static int backup_fake_header(struct reenc_ctx *rc)
if (opt_cipher) {
r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
if (r < 0) {
log_err(_("No known cipher specification pattern detected.\n"));
log_err(_("No known cipher specification pattern detected."));
goto out;
}
}
@@ -804,7 +852,7 @@ static int backup_fake_header(struct reenc_ctx *rc)
goto out;
params2.data_alignment = params.data_alignment = ROUND_SECTOR(opt_reduce_size);
r = create_new_header(rc,
r = create_new_header(rc, NULL,
opt_cipher ? cipher : DEFAULT_LUKS1_CIPHER,
opt_cipher ? cipher_mode : DEFAULT_LUKS1_MODE,
NULL, NULL,
@@ -834,21 +882,43 @@ static void remove_headers(struct reenc_ctx *rc)
static int restore_luks_header(struct reenc_ctx *rc)
{
struct stat st;
struct crypt_device *cd = NULL;
int r;
int fd, r;
log_dbg("Restoring header for %s from %s.", rc->device, rc->header_file_new);
log_dbg("Restoring header for %s from %s.", hdr_device(rc), rc->header_file_new);
r = crypt_init(&cd, rc->device);
/*
* For new encryption and new detached header in file just move it.
* For existing file try to ensure we have prealocated space for restore.
*/
if (opt_new && rc->device_header) {
r = stat(rc->device_header, &st);
if (r == -1) {
r = rename(rc->header_file_new, rc->device_header);
goto out;
} else if ((st.st_mode & S_IFMT) == S_IFREG &&
stat(rc->header_file_new, &st) != -1) {
/* coverity[toctou] */
fd = open(rc->device_header, O_WRONLY);
if (fd != -1) {
if (posix_fallocate(fd, 0, st.st_size)) {};
close(fd);
}
}
}
r = crypt_init(&cd, hdr_device(rc));
if (r == 0) {
r = crypt_header_restore(cd, rc->type, rc->header_file_new);
}
crypt_free(cd);
out:
if (r)
log_err(_("Cannot restore %s header on device %s.\n"), rc->device, isLUKS2(rc->type) ? "LUKS2" : "LUKS1");
log_err(_("Cannot restore %s header on device %s."), isLUKS2(rc->type) ? "LUKS2" : "LUKS1", hdr_device(rc));
else {
log_verbose(_("%s header on device %s restored.\n"), rc->device, isLUKS2(rc->type) ? "LUKS2" : "LUKS1");
log_verbose(_("%s header on device %s restored."), isLUKS2(rc->type) ? "LUKS2" : "LUKS1", hdr_device(rc));
rc->stained = 0;
}
return r;
@@ -886,7 +956,7 @@ static int copy_data_forward(struct reenc_ctx *rc, int fd_old, int fd_new,
if (lseek64(fd_old, rc->device_offset, SEEK_SET) < 0 ||
lseek64(fd_new, rc->device_offset, SEEK_SET) < 0) {
log_err(_("Cannot seek to device offset.\n"));
log_err(_("Cannot seek to device offset."));
return -EIO;
}
@@ -966,7 +1036,7 @@ static int copy_data_backward(struct reenc_ctx *rc, int fd_old, int fd_new,
if (lseek64(fd_old, working_offset, SEEK_SET) < 0 ||
lseek64(fd_new, working_offset, SEEK_SET) < 0) {
log_err(_("Cannot seek to device offset.\n"));
log_err(_("Cannot seek to device offset."));
return -EIO;
}
@@ -1048,23 +1118,23 @@ static int copy_data(struct reenc_ctx *rc)
fd_old = open(rc->crypt_path_org, O_RDONLY | (opt_directio ? O_DIRECT : 0));
if (fd_old == -1) {
log_err(_("Cannot open temporary LUKS device.\n"));
log_err(_("Cannot open temporary LUKS device."));
goto out;
}
fd_new = open(rc->crypt_path_new, O_WRONLY | (opt_directio ? O_DIRECT : 0));
if (fd_new == -1) {
log_err(_("Cannot open temporary LUKS device.\n"));
log_err(_("Cannot open temporary LUKS device."));
goto out;
}
if (ioctl(fd_old, BLKGETSIZE64, &rc->device_size_org_real) < 0) {
log_err(_("Cannot get device size.\n"));
log_err(_("Cannot get device size."));
goto out;
}
if (ioctl(fd_new, BLKGETSIZE64, &rc->device_size_new_real) < 0) {
log_err(_("Cannot get device size.\n"));
log_err(_("Cannot get device size."));
goto out;
}
@@ -1076,7 +1146,7 @@ static int copy_data(struct reenc_ctx *rc)
rc->device_size = rc->device_size_new_real;
if (posix_memalign((void *)&buf, alignment(fd_new), block_size)) {
log_err(_("Allocation of aligned memory failed.\n"));
log_err(_("Allocation of aligned memory failed."));
r = -ENOMEM;
goto out;
}
@@ -1101,9 +1171,9 @@ static int copy_data(struct reenc_ctx *rc)
set_int_block(1);
if (r == -EAGAIN)
log_err(_("Interrupted by a signal.\n"));
log_err(_("Interrupted by a signal."));
else if (r < 0)
log_err(_("IO error during reencryption.\n"));
log_err(_("IO error during reencryption."));
(void)write_log(rc);
out:
@@ -1134,13 +1204,13 @@ static int initialize_uuid(struct reenc_ctx *rc)
if (!r)
rc->device_uuid = strdup(opt_uuid);
else
log_err(_("Provided UUID is invalid.\n"));
log_err(_("Provided UUID is invalid."));
return r;
}
/* Try to load LUKS from device */
if ((r = crypt_init(&cd, rc->device)))
if ((r = crypt_init(&cd, hdr_device(rc))))
return r;
crypt_set_log_callback(cd, _quiet_log, NULL);
r = crypt_load(cd, CRYPT_LUKS, NULL);
@@ -1148,7 +1218,7 @@ static int initialize_uuid(struct reenc_ctx *rc)
rc->device_uuid = strdup(crypt_get_uuid(cd));
else
/* Reencryption already in progress - magic header? */
r = device_check(rc, CHECK_UNUSABLE);
r = device_check(rc, hdr_device(rc), CHECK_UNUSABLE);
if (!r)
rc->type = isLUKS2(crypt_get_type(cd)) ? CRYPT_LUKS2 : CRYPT_LUKS1;
@@ -1160,10 +1230,19 @@ static int initialize_uuid(struct reenc_ctx *rc)
static int init_passphrase1(struct reenc_ctx *rc, struct crypt_device *cd,
const char *msg, int slot_to_check, int check, int verify)
{
crypt_keyslot_info ki;
char *password;
int r = -EINVAL, retry_count;
size_t passwordLen;
/* mode ENCRYPT call this without header */
if (cd && slot_to_check != CRYPT_ANY_SLOT) {
ki = crypt_keyslot_status(cd, slot_to_check);
if (ki < CRYPT_SLOT_ACTIVE)
return -ENOENT;
} else
ki = CRYPT_SLOT_ACTIVE;
retry_count = opt_tries ?: 1;
while (retry_count--) {
r = tools_get_key(msg, &password, &passwordLen, 0, 0,
@@ -1179,7 +1258,7 @@ static int init_passphrase1(struct reenc_ctx *rc, struct crypt_device *cd,
if (check)
r = crypt_activate_by_passphrase(cd, NULL, slot_to_check,
password, passwordLen, 0);
password, passwordLen, CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY);
else
r = (slot_to_check == CRYPT_ANY_SLOT) ? 0 : slot_to_check;
@@ -1190,13 +1269,16 @@ static int init_passphrase1(struct reenc_ctx *rc, struct crypt_device *cd,
}
if (r < 0 && r != -EPERM)
return r;
if (r >= 0) {
rc->keyslot = r;
tools_keyslot_msg(r, UNLOCKED);
rc->p[r].password = password;
rc->p[r].passwordLen = passwordLen;
if (ki != CRYPT_SLOT_UNBOUND)
rc->keyslot = r;
break;
}
log_err(_("No key available with this passphrase.\n"));
tools_passphrase_msg(r);
}
password = NULL;
@@ -1226,14 +1308,13 @@ static int init_keyfile(struct reenc_ctx *rc, struct crypt_device *cd, int slot_
if (r >= 0 && opt_key_slot == CRYPT_ANY_SLOT &&
crypt_keyslot_status(cd, r) != CRYPT_SLOT_ACTIVE_LAST) {
log_err(_("Key file can be used only with --key-slot or with "
"exactly one key slot active.\n"));
"exactly one key slot active."));
r = -EINVAL;
}
if (r < 0) {
crypt_safe_free(password);
if (r == -EPERM)
log_err(_("No key available with this passphrase.\n"));
tools_passphrase_msg(r);
} else {
rc->keyslot = r;
rc->p[r].password = password;
@@ -1249,11 +1330,10 @@ static int init_keyfile(struct reenc_ctx *rc, struct crypt_device *cd, int slot_
static int initialize_passphrase(struct reenc_ctx *rc, const char *device)
{
struct crypt_device *cd = NULL;
crypt_keyslot_info ki;
char msg[256];
int i, r;
log_dbg("Passhrases initialization.");
log_dbg("Passphrases initialization.");
if (rc->reencrypt_mode == ENCRYPT && !rc->in_progress) {
r = init_passphrase1(rc, cd, _("Enter new passphrase: "), opt_key_slot, 0, 1);
@@ -1280,12 +1360,12 @@ static int initialize_passphrase(struct reenc_ctx *rc, const char *device)
rc->reencrypt_mode == DECRYPT) {
r = init_passphrase1(rc, cd, msg, opt_key_slot, 1, 0);
} else for (i = 0; i < crypt_keyslot_max(crypt_get_type(cd)); i++) {
ki = crypt_keyslot_status(cd, i);
if (ki != CRYPT_SLOT_ACTIVE && ki != CRYPT_SLOT_ACTIVE_LAST)
continue;
snprintf(msg, sizeof(msg), _("Enter passphrase for key slot %u: "), i);
r = init_passphrase1(rc, cd, msg, i, 1, 0);
if (r == -ENOENT) {
r = 0;
continue;
}
if (r < 0)
break;
}
@@ -1309,17 +1389,20 @@ static int initialize_context(struct reenc_ctx *rc, const char *device)
if (!(rc->device = strndup(device, PATH_MAX)))
return -ENOMEM;
if (device_check(rc, CHECK_OPEN) < 0)
if (opt_header_device && !(rc->device_header = strndup(opt_header_device, PATH_MAX)))
return -ENOMEM;
if (device_check(rc, rc->device, CHECK_OPEN) < 0)
return -EINVAL;
if (initialize_uuid(rc)) {
log_err(_("Device %s is not a valid LUKS device.\n"), device);
log_err(_("Device %s is not a valid LUKS device."), device);
return -EINVAL;
}
if (opt_key_slot != CRYPT_ANY_SLOT &&
opt_key_slot >= crypt_keyslot_max(rc->type)) {
log_err(_("Key slot is invalid.\n"));
log_err(_("Key slot is invalid."));
return -EINVAL;
}
@@ -1348,14 +1431,14 @@ static int initialize_context(struct reenc_ctx *rc, const char *device)
remove_headers(rc);
if (open_log(rc) < 0) {
log_err(_("Cannot open reencryption log file.\n"));
log_err(_("Cannot open reencryption log file."));
return -EINVAL;
}
if (!rc->in_progress) {
if (opt_uuid) {
log_err(_("No decryption in progress, provided UUID can "
"be used only to resume suspended decryption process.\n"));
"be used only to resume suspended decryption process."));
return -EINVAL;
}
@@ -1397,20 +1480,23 @@ static void destroy_context(struct reenc_ctx *rc)
crypt_safe_free(rc->p[i].password);
free(rc->device);
free(rc->device_header);
free(rc->device_uuid);
}
static int luks2_change_pbkdf_params(struct reenc_ctx *rc)
{
int i, r;
struct crypt_device *cd;
struct crypt_device *cd = NULL;
if ((r = initialize_passphrase(rc, rc->device)))
if ((r = initialize_passphrase(rc, hdr_device(rc))))
return r;
if (crypt_init(&cd, rc->device) ||
crypt_load(cd, CRYPT_LUKS2, NULL))
return -EINVAL;
if (crypt_init(&cd, hdr_device(rc)) ||
crypt_load(cd, CRYPT_LUKS2, NULL)) {
r = -EINVAL;
goto out;
}
if ((r = set_pbkdf_params(cd, CRYPT_LUKS2)))
goto out;
@@ -1426,7 +1512,7 @@ static int luks2_change_pbkdf_params(struct reenc_ctx *rc)
rc->p[i].password, rc->p[i].passwordLen,
rc->p[i].password, rc->p[i].passwordLen)) < 0)
goto out;
log_verbose(_("Changed pbkdf parameters in keyslot %i.\n"), r);
log_verbose(_("Changed pbkdf parameters in keyslot %i."), r);
r = 0;
}
@@ -1461,11 +1547,12 @@ static int run_reencrypt(const char *device)
log_dbg("Running reencryption.");
if (!rc.in_progress) {
if ((r = initialize_passphrase(&rc, rc.device)))
if ((r = initialize_passphrase(&rc, hdr_device(&rc))))
goto out;
log_dbg("Storing backup of LUKS headers.");
if (rc.reencrypt_mode == ENCRYPT) {
/* Create fake header for exising device */
/* Create fake header for existing device */
if ((r = backup_fake_header(&rc)))
goto out;
} else {
@@ -1475,7 +1562,7 @@ static int run_reencrypt(const char *device)
if (rc.reencrypt_mode == DECRYPT &&
(r = backup_fake_header(&rc)))
goto out;
if ((r = device_check(&rc, MAKE_UNUSABLE)))
if ((r = device_check(&rc, hdr_device(&rc), MAKE_UNUSABLE)))
goto out;
}
} else {
@@ -1534,30 +1621,32 @@ int main(int argc, const char **argv)
{ "cipher", 'c', POPT_ARG_STRING, &opt_cipher, 0, N_("The cipher used to encrypt the disk (see /proc/crypto)"), NULL },
{ "key-size", 's', POPT_ARG_INT, &opt_key_size, 0, N_("The size of the encryption key"), N_("BITS") },
{ "hash", 'h', POPT_ARG_STRING, &opt_hash, 0, N_("The hash used to create the encryption key from the passphrase"), NULL },
{ "keep-key", '\0', POPT_ARG_NONE, &opt_keep_key, 0, N_("Do not change key, no data area reencryption."), NULL },
{ "key-file", 'd', POPT_ARG_STRING, &opt_key_file, 0, N_("Read the key from a file."), NULL },
{ "keep-key", '\0', POPT_ARG_NONE, &opt_keep_key, 0, N_("Do not change key, no data area reencryption"), NULL },
{ "key-file", 'd', POPT_ARG_STRING, &opt_key_file, 0, N_("Read the key from a file"), NULL },
{ "master-key-file", '\0', POPT_ARG_STRING, &opt_master_key_file, 0, N_("Read new volume (master) key from file"), NULL },
{ "iter-time", 'i', POPT_ARG_INT, &opt_iteration_time, 0, N_("PBKDF2 iteration time for LUKS (in ms)"), N_("msecs") },
{ "batch-mode", 'q', POPT_ARG_NONE, &opt_batch_mode, 0, N_("Do not ask for confirmation"), NULL },
{ "progress-frequency",'\0', POPT_ARG_INT, &opt_progress_frequency, 0, N_("Progress line update (in seconds)"), N_("secs") },
{ "tries", 'T', POPT_ARG_INT, &opt_tries, 0, N_("How often the input of the passphrase can be retried"), NULL },
{ "use-random", '\0', POPT_ARG_NONE, &opt_random, 0, N_("Use /dev/random for generating volume key."), NULL },
{ "use-urandom", '\0', POPT_ARG_NONE, &opt_urandom, 0, N_("Use /dev/urandom for generating volume key."), NULL },
{ "use-directio", '\0', POPT_ARG_NONE, &opt_directio, 0, N_("Use direct-io when accessing devices."), NULL },
{ "use-fsync", '\0', POPT_ARG_NONE, &opt_fsync, 0, N_("Use fsync after each block."), NULL },
{ "write-log", '\0', POPT_ARG_NONE, &opt_write_log, 0, N_("Update log file after every block."), NULL },
{ "key-slot", 'S', POPT_ARG_INT, &opt_key_slot, 0, N_("Use only this slot (others will be disabled)."), NULL },
{ "use-random", '\0', POPT_ARG_NONE, &opt_random, 0, N_("Use /dev/random for generating volume key"), NULL },
{ "use-urandom", '\0', POPT_ARG_NONE, &opt_urandom, 0, N_("Use /dev/urandom for generating volume key"), NULL },
{ "use-directio", '\0', POPT_ARG_NONE, &opt_directio, 0, N_("Use direct-io when accessing devices"), NULL },
{ "use-fsync", '\0', POPT_ARG_NONE, &opt_fsync, 0, N_("Use fsync after each block"), NULL },
{ "write-log", '\0', POPT_ARG_NONE, &opt_write_log, 0, N_("Update log file after every block"), NULL },
{ "key-slot", 'S', POPT_ARG_INT, &opt_key_slot, 0, N_("Use only this slot (others will be disabled)"), NULL },
{ "keyfile-offset", '\0', POPT_ARG_LONG, &opt_keyfile_offset, 0, N_("Number of bytes to skip in keyfile"), N_("bytes") },
{ "keyfile-size", 'l', POPT_ARG_LONG, &opt_keyfile_size, 0, N_("Limits the read from keyfile"), N_("bytes") },
{ "reduce-device-size",'\0', POPT_ARG_STRING, &opt_reduce_size_str, 0, N_("Reduce data device size (move data offset). DANGEROUS!"), N_("bytes") },
{ "device-size", '\0', POPT_ARG_STRING, &opt_device_size_str, 0, N_("Use only specified device size (ignore rest of device). DANGEROUS!"), N_("bytes") },
{ "new", 'N', POPT_ARG_NONE, &opt_new, 0, N_("Create new header on not encrypted device."), NULL },
{ "decrypt", '\0', POPT_ARG_NONE, &opt_decrypt, 0, N_("Permanently decrypt device (remove encryption)."), NULL },
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("The uuid used to resume decryption."), NULL },
{ "type", '\0', POPT_ARG_STRING, &opt_type, 0, N_("Type of LUKS metadata (luks1 or luks2)."), NULL },
{ "pbkdf", '\0', POPT_ARG_STRING, &opt_pbkdf, 0, N_("PBKDF algorithm (for LUKS2) (argon2i/argon2id/pbkdf2)."), NULL },
{ "new", 'N', POPT_ARG_NONE, &opt_new, 0, N_("Create new header on not encrypted device"), NULL },
{ "decrypt", '\0', POPT_ARG_NONE, &opt_decrypt, 0, N_("Permanently decrypt device (remove encryption)"), NULL },
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("The UUID used to resume decryption"), NULL },
{ "type", '\0', POPT_ARG_STRING, &opt_type, 0, N_("Type of LUKS metadata: luks1, luks2"), NULL },
{ "pbkdf", '\0', POPT_ARG_STRING, &opt_pbkdf, 0, N_("PBKDF algorithm (for LUKS2): argon2i, argon2id, pbkdf2"), NULL },
{ "pbkdf-memory", '\0', POPT_ARG_LONG, &opt_pbkdf_memory, 0, N_("PBKDF memory cost limit"), N_("kilobytes") },
{ "pbkdf-parallel", '\0', POPT_ARG_LONG, &opt_pbkdf_parallel, 0, N_("PBKDF parallel cost "), N_("threads") },
{ "pbkdf-parallel", '\0', POPT_ARG_LONG, &opt_pbkdf_parallel, 0, N_("PBKDF parallel cost"), N_("threads") },
{ "pbkdf-force-iterations",'\0',POPT_ARG_LONG, &opt_pbkdf_iterations, 0, N_("PBKDF iterations cost (forced, disables benchmark)"), NULL },
{ "header", '\0', POPT_ARG_STRING, &opt_header_device, 0, N_("Device or file with separated LUKS header"), NULL },
POPT_TABLEEND
};
poptContext popt_context;
@@ -1587,7 +1676,7 @@ int main(int argc, const char **argv)
}
if (!opt_batch_mode)
log_verbose(_("Reencryption will change: %s%s%s%s%s%s.\n"),
log_verbose(_("Reencryption will change: %s%s%s%s%s%s."),
opt_keep_key ? "" : _("volume key"),
(!opt_keep_key && opt_hash) ? ", " : "",
opt_hash ? _("set hash to ") : "", opt_hash ?: "",
@@ -1656,11 +1745,11 @@ int main(int argc, const char **argv)
usage(popt_context, EXIT_FAILURE, _("Reduce size must be multiple of 512 bytes sector."),
poptGetInvocationName(popt_context));
if (opt_new && !opt_reduce_size)
usage(popt_context, EXIT_FAILURE, _("Option --new must be used together with --reduce-device-size."),
if (opt_new && (!opt_reduce_size && !opt_header_device))
usage(popt_context, EXIT_FAILURE, _("Option --new must be used together with --reduce-device-size or --header."),
poptGetInvocationName(popt_context));
if (opt_keep_key && ((!opt_hash && !opt_iteration_time && !opt_pbkdf_iterations) || opt_cipher || opt_new))
if (opt_keep_key && (opt_cipher || opt_new || opt_master_key_file))
usage(popt_context, EXIT_FAILURE, _("Option --keep-key can be used only with --hash, --iter-time or --pbkdf-force-iterations."),
poptGetInvocationName(popt_context));

View File

@@ -65,7 +65,7 @@ static int _read_mk(const char *file, char **key, int keysize)
int fd;
if (keysize <= 0 || keysize > MAX_KEY_SIZE) {
log_err(_("Invalid key size.\n"));
log_err(_("Invalid key size."));
return -EINVAL;
}
@@ -75,11 +75,11 @@ static int _read_mk(const char *file, char **key, int keysize)
fd = open(file, O_RDONLY);
if (fd == -1) {
log_err(_("Cannot read keyfile %s.\n"), file);
log_err(_("Cannot read keyfile %s."), file);
goto fail;
}
if ((read(fd, *key, keysize) != keysize)) {
log_err(_("Cannot read %d bytes from keyfile %s.\n"), keysize, file);
log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
close(fd);
goto fail;
}
@@ -159,7 +159,7 @@ static int _wipe_data_device(struct crypt_device *cd, const char *integrity_key)
r = crypt_wipe(cd, tmp_path, CRYPT_WIPE_ZERO, 0, 0, DEFAULT_WIPE_BLOCK,
0, &tools_wipe_progress, NULL);
if (crypt_deactivate(cd, tmp_name))
log_err(_("Cannot deactivate temporary device %s.\n"), tmp_path);
log_err(_("Cannot deactivate temporary device %s."), tmp_path);
set_int_block(0);
return r;
@@ -178,13 +178,14 @@ static int action_format(int arg)
.sector_size = opt_sector_size ?: SECTOR_SIZE,
};
char integrity[MAX_CIPHER_LEN], journal_integrity[MAX_CIPHER_LEN], journal_crypt[MAX_CIPHER_LEN];
char *integrity_key = NULL;
char *integrity_key = NULL, *msg = NULL;
int r;
size_t signatures;
if (opt_integrity) {
r = crypt_parse_hash_integrity_mode(opt_integrity, integrity);
if (r < 0) {
log_err(_("No known integrity specification pattern detected.\n"));
log_err(_("No known integrity specification pattern detected."));
return r;
}
params.integrity = integrity;
@@ -193,7 +194,7 @@ static int action_format(int arg)
if (opt_journal_integrity) {
r = crypt_parse_hash_integrity_mode(opt_journal_integrity, journal_integrity);
if (r < 0) {
log_err(_("No known integrity specification pattern detected.\n"));
log_err(_("No known integrity specification pattern detected."));
return r;
}
params.journal_integrity = journal_integrity;
@@ -202,7 +203,7 @@ static int action_format(int arg)
if (opt_journal_crypt) {
r = crypt_parse_hash_integrity_mode(opt_journal_crypt, journal_crypt);
if (r < 0) {
log_err(_("No known integrity specification pattern detected.\n"));
log_err(_("No known integrity specification pattern detected."));
return r;
}
params.journal_crypt = journal_crypt;
@@ -216,10 +217,29 @@ static int action_format(int arg)
if (r < 0)
goto out;
r = crypt_format(cd, CRYPT_INTEGRITY, NULL, NULL, NULL, NULL, 0, &params);
r = asprintf(&msg, _("This will overwrite data on %s irrevocably."), action_argv[0]);
if (r == -1) {
r = -ENOMEM;
goto out;
}
r = yesDialog(msg, _("Operation aborted.\n")) ? 0 : -EINVAL;
free(msg);
if (r < 0)
goto out;
r = tools_detect_signatures(action_argv[0], 0, &signatures);
if (r < 0)
goto out;
/* Signature candidates found */
if (signatures && ((r = tools_wipe_all_signatures(action_argv[0])) < 0))
goto out;
r = crypt_format(cd, CRYPT_INTEGRITY, NULL, NULL, NULL, NULL, 0, &params);
if (r < 0) /* FIXME: call wipe signatures again */
goto out;
if (!opt_batch_mode)
log_std(_("Formatted with tag size %u, internal integrity %s.\n"), opt_tag_size, opt_integrity);
@@ -249,7 +269,7 @@ static int action_open(int arg)
if (opt_integrity) {
r = crypt_parse_hash_integrity_mode(opt_integrity, integrity);
if (r < 0) {
log_err(_("No known integrity specification pattern detected.\n"));
log_err(_("No known integrity specification pattern detected."));
return r;
}
params.integrity = integrity;
@@ -258,7 +278,7 @@ static int action_open(int arg)
if (opt_journal_integrity) {
r = crypt_parse_hash_integrity_mode(opt_journal_integrity, journal_integrity);
if (r < 0) {
log_err(_("No known integrity specification pattern detected.\n"));
log_err(_("No known integrity specification pattern detected."));
return r;
}
@@ -268,7 +288,7 @@ static int action_open(int arg)
if (opt_journal_crypt) {
r = crypt_parse_hash_integrity_mode(opt_journal_crypt, journal_crypt);
if (r < 0) {
log_err(_("No known integrity specification pattern detected.\n"));
log_err(_("No known integrity specification pattern detected."));
return r;
}
params.journal_crypt = journal_crypt;
@@ -376,6 +396,8 @@ static int action_status(int arg)
log_std(" mode: %s%s\n",
cad.flags & CRYPT_ACTIVATE_READONLY ? "readonly" : "read/write",
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) {
log_std(" journal: not active\n");
} else {
@@ -490,24 +512,24 @@ 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") },
{ "tag-size", 't', POPT_ARG_INT, &opt_tag_size, 0, N_("Tag size per-sector"), N_("bytes") },
{ "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") },
{ "integrity", 'I', POPT_ARG_STRING, &opt_integrity, 0, N_("Data integrity algorithm (default "DEFAULT_ALG_NAME ")"), NULL },
{ "integrity", 'I', POPT_ARG_STRING, &opt_integrity, 0, N_("Data integrity algorithm"), NULL },
{ "integrity-key-size", '\0', POPT_ARG_INT, &opt_integrity_key_size, 0, N_("The size of the data integrity key"), N_("BITS") },
{ "integrity-key-file", '\0', POPT_ARG_STRING, &opt_integrity_key_file, 0, N_("Read the integrity key from a file."), NULL },
{ "integrity-key-file", '\0', POPT_ARG_STRING, &opt_integrity_key_file, 0, N_("Read the integrity key from a file"), NULL },
{ "journal-integrity", '\0', POPT_ARG_STRING, &opt_journal_integrity, 0, N_("Journal integrity algorithm"), NULL },
{ "journal-integrity-key-size",'\0', POPT_ARG_INT, &opt_journal_integrity_key_size,0, N_("The size of the journal integrity key"), N_("BITS") },
{ "journal-integrity-key-file",'\0', POPT_ARG_STRING, &opt_journal_integrity_key_file,0, N_("Read the journal integrity key from a file."), NULL },
{ "journal-integrity-key-file",'\0', POPT_ARG_STRING, &opt_journal_integrity_key_file,0, N_("Read the journal integrity key from a file"), NULL },
{ "journal-crypt", '\0', POPT_ARG_STRING, &opt_journal_crypt, 0, N_("Journal encryption algorithm"), NULL },
{ "journal-crypt-key-size", '\0', POPT_ARG_INT, &opt_journal_crypt_key_size, 0, N_("The size of the journal encryption key"), N_("BITS") },
{ "journal-crypt-key-file", '\0', POPT_ARG_STRING, &opt_journal_crypt_key_file, 0, N_("Read the journal encryption key from a file."), NULL },
{ "journal-crypt-key-file", '\0', POPT_ARG_STRING, &opt_journal_crypt_key_file, 0, N_("Read the journal encryption key from a file"), NULL },
{ "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-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 },
POPT_TABLEEND
};
poptContext popt_context;
@@ -554,7 +576,7 @@ int main(int argc, const char **argv)
action_argc++;
/* Handle aliases */
if (!strcmp(aname, "create")) {
if (!strcmp(aname, "create") && action_argc > 1) {
/* create command had historically switched arguments */
if (action_argv[0] && action_argv[1]) {
const char *tmp = action_argv[0];

139
src/utils_luks2.c Normal file
View File

@@ -0,0 +1,139 @@
/*
* Helper utilities for LUKS2 features
*
* Copyright (C) 2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2018, Milan Broz
* Copyright (C) 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 "cryptsetup.h"
/*
* FIXME: 4MiBs is max LUKS2 mda length (including binary header).
* In future, read max allowed JSON size from config section.
*/
#define LUKS2_MAX_MDA_SIZE 0x400000
int tools_read_json_file(struct crypt_device *cd, const char *file, char **json, size_t *json_size)
{
ssize_t ret;
int fd, block, r;
void *buf = NULL;
block = tools_signals_blocked();
if (block)
set_int_block(0);
if (tools_is_stdin(file)) {
fd = STDIN_FILENO;
log_dbg("STDIN descriptor JSON read requested.");
} else {
log_dbg("File descriptor JSON read requested.");
fd = open(file, O_RDONLY);
if (fd < 0) {
log_err(_("Failed to open file %s in read-only mode."), file);
r = -EINVAL;
goto out;
}
}
buf = malloc(LUKS2_MAX_MDA_SIZE);
if (!buf) {
r = -ENOMEM;
goto out;
}
if (isatty(fd) && !opt_batch_mode)
log_std(_("Provide valid LUKS2 token JSON:\n"));
/* we expect JSON (string) */
r = 0;
ret = read_buffer_intr(fd, buf, LUKS2_MAX_MDA_SIZE - 1, &quit);
if (ret < 0) {
r = -EIO;
log_err(_("Failed to read JSON file."));
goto out;
}
check_signal(&r);
if (r) {
log_err(_("\nRead interrupted."));
goto out;
}
*json_size = (size_t)ret;
*json = buf;
*(*json + ret) = '\0';
out:
if (block && !quit)
set_int_block(1);
if (fd >= 0 && fd != STDIN_FILENO)
close(fd);
if (r && buf) {
memset(buf, 0, LUKS2_MAX_MDA_SIZE);
free(buf);
}
return r;
}
int tools_write_json_file(struct crypt_device *cd, const char *file, const char *json)
{
int block, fd, r;
size_t json_len;
ssize_t ret;
if (!json || !(json_len = strlen(json)) || json_len >= LUKS2_MAX_MDA_SIZE)
return -EINVAL;
block = tools_signals_blocked();
if (block)
set_int_block(0);
if (tools_is_stdin(file)) {
fd = STDOUT_FILENO;
log_dbg("STDOUT descriptor JSON write requested.");
} else {
log_dbg("File descriptor JSON write requested.");
fd = open(file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
}
if (fd < 0) {
log_err(_("Failed to open file %s in write mode."), file ?: "");
r = -EINVAL;
goto out;
}
r = 0;
ret = write_buffer_intr(fd, json, json_len, &quit);
check_signal(&r);
if (r) {
log_err(_("\nWrite interrupted."));
goto out;
}
if (ret < 0 || (size_t)ret != json_len) {
log_err(_("Failed to write JSON file."));
r = -EIO;
goto out;
}
if (isatty(fd))
(void) write_buffer_intr(fd, "\n", 1, &quit);
out:
if (block && !quit)
set_int_block(1);
if (fd >=0 && fd != STDOUT_FILENO)
close(fd);
return r;
}

View File

@@ -40,7 +40,7 @@ static int tools_check_pwquality(const char *password)
r = pwquality_read_config(pwq, NULL, &auxerror);
if (r) {
log_err(_("Cannot check password quality: %s\n"),
log_err(_("Cannot check password quality: %s"),
pwquality_strerror(NULL, 0, r, auxerror));
pwquality_free_settings(pwq);
return -EINVAL;
@@ -48,7 +48,7 @@ static int tools_check_pwquality(const char *password)
r = pwquality_check(pwq, password, NULL, NULL, &auxerror);
if (r < 0) {
log_err(_("Password quality check failed:\n %s\n"),
log_err(_("Password quality check failed:\n %s"),
pwquality_strerror(NULL, 0, r, auxerror));
r = -EPERM;
} else {
@@ -72,7 +72,7 @@ static int tools_check_pwquality(const char *password)
passwdqc_params_reset(&params);
if (*config && passwdqc_params_load(&params, &parse_reason, config)) {
log_err(_("Cannot check password quality: %s\n"),
log_err(_("Cannot check password quality: %s"),
(parse_reason ? parse_reason : "Out of memory"));
free(parse_reason);
return -EINVAL;
@@ -80,7 +80,7 @@ static int tools_check_pwquality(const char *password)
check_reason = passwdqc_check(&params.qc, password, NULL, NULL);
if (check_reason) {
log_err(_("Password quality check failed: Bad passphrase (%s)\n"),
log_err(_("Password quality check failed: Bad passphrase (%s)"),
check_reason);
return -EPERM;
}
@@ -94,25 +94,6 @@ static int tools_check_pwquality(const char *password)
}
#endif /* ENABLE_PWQUALITY || ENABLE_PASSWDQC */
int tools_is_cipher_null(const char *cipher)
{
if (!cipher)
return 0;
return !strcmp(cipher, "cipher_null") ? 1 : 0;
}
/*
* Keyfile - is standard input treated as a binary file (no EOL handling).
*/
int tools_is_stdin(const char *key_file)
{
if (!key_file)
return 1;
return strcmp(key_file, "-") ? 0 : 1;
}
/* Password reading helpers */
static int untimed_read(int fd, char *pass, size_t maxlen)
{
@@ -204,12 +185,12 @@ static int crypt_get_key_tty(const char *prompt,
pass = crypt_safe_alloc(key_size_max + 1);
if (!pass) {
log_err( _("Out of memory while reading passphrase.\n"));
log_err( _("Out of memory while reading passphrase."));
return -ENOMEM;
}
if (interactive_pass(prompt, pass, key_size_max, timeout)) {
log_err(_("Error reading passphrase from terminal.\n"));
log_err(_("Error reading passphrase from terminal."));
goto out_err;
}
pass[key_size_max] = '\0';
@@ -217,19 +198,19 @@ static int crypt_get_key_tty(const char *prompt,
if (verify) {
pass_verify = crypt_safe_alloc(key_size_max);
if (!pass_verify) {
log_err(_("Out of memory while reading passphrase.\n"));
log_err(_("Out of memory while reading passphrase."));
r = -ENOMEM;
goto out_err;
}
if (interactive_pass(_("Verify passphrase: "),
pass_verify, key_size_max, timeout)) {
log_err(_("Error reading passphrase from terminal.\n"));
log_err(_("Error reading passphrase from terminal."));
goto out_err;
}
if (strncmp(pass, pass_verify, key_size_max)) {
log_err(_("Passphrases do not match.\n"));
log_err(_("Passphrases do not match."));
r = -EPERM;
goto out_err;
}
@@ -266,7 +247,7 @@ int tools_get_key(const char *prompt,
if (tools_is_stdin(key_file)) {
if (isatty(STDIN_FILENO)) {
if (keyfile_offset) {
log_err(_("Cannot use offset with terminal input.\n"));
log_err(_("Cannot use offset with terminal input."));
} else {
if (!prompt && !crypt_get_device_name(cd))
snprintf(tmp, sizeof(tmp), _("Enter passphrase: "));
@@ -297,3 +278,54 @@ int tools_get_key(const char *prompt,
return r;
}
void tools_passphrase_msg(int r)
{
if (r == -EPERM)
log_err(_("No key available with this passphrase."));
}
int tools_read_mk(const char *file, char **key, int keysize)
{
int fd;
*key = crypt_safe_alloc(keysize);
if (!*key)
return -ENOMEM;
fd = open(file, O_RDONLY);
if (fd == -1) {
log_err(_("Cannot read keyfile %s."), file);
goto fail;
}
if ((read(fd, *key, keysize) != keysize)) {
log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
close(fd);
goto fail;
}
close(fd);
return 0;
fail:
crypt_safe_free(*key);
*key = NULL;
return -EINVAL;
}
int tools_write_mk(const char *file, const char *key, int keysize)
{
int fd, r = -EINVAL;
fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
if (fd < 0) {
log_err(_("Cannot open keyfile %s for write."), file);
return r;
}
if (write_buffer(fd, key, keysize) == keysize)
r = 0;
else
log_err(_("Cannot write to keyfile %s."), file);
close(fd);
return r;
}

View File

@@ -76,17 +76,23 @@ void check_signal(int *r)
*r = -EINTR;
}
#define LOG_MAX_LEN 4096
__attribute__((format(printf, 5, 6)))
void clogger(struct crypt_device *cd, int level, const char *file, int line,
const char *format, ...)
{
va_list argp;
char *target = NULL;
char target[LOG_MAX_LEN + 2];
va_start(argp, format);
if (vasprintf(&target, format, argp) > 0) {
if (vsnprintf(&target[0], LOG_MAX_LEN, format, argp) > 0) {
if (level >= 0) {
/* All verbose and error messages in tools end with EOL. */
if (level == CRYPT_LOG_VERBOSE || level == CRYPT_LOG_ERROR)
strncat(target, "\n", LOG_MAX_LEN);
crypt_log(cd, level, target);
#ifdef CRYPT_DEBUG
} else if (opt_debug)
@@ -98,7 +104,6 @@ void clogger(struct crypt_device *cd, int level, const char *file, int line,
}
va_end(argp);
free(target);
}
void tool_log(int level, const char *msg, void *usrptr __attribute__((unused)))
@@ -151,7 +156,7 @@ int yesDialog(const char *msg, void *usrptr)
r = 0;
/* Aborted by signal */
if (!quit)
log_err(_("Error reading response from terminal.\n"));
log_err(_("Error reading response from terminal."));
else
log_dbg("Query interrupted on signal.");
} else if (strcmp(answer, "YES\n")) {
@@ -230,7 +235,7 @@ __attribute__ ((noreturn)) void usage(poptContext popt_context,
{
poptPrintUsage(popt_context, stderr, 0);
if (error)
log_err("%s: %s\n", more, error);
log_err("%s: %s", more, error);
poptFreeContext(popt_context);
exit(exitcode);
}
@@ -267,6 +272,30 @@ int translate_errno(int r)
return r;
}
void tools_keyslot_msg(int keyslot, crypt_object_op op)
{
if (keyslot < 0)
return;
if (op == CREATED)
log_verbose(_("Key slot %i created."), keyslot);
else if (op == UNLOCKED)
log_verbose(_("Key slot %i unlocked."), keyslot);
else if (op == REMOVED)
log_verbose(_("Key slot %i removed."), keyslot);
}
void tools_token_msg(int token, crypt_object_op op)
{
if (token < 0)
return;
if (op == CREATED)
log_verbose(_("Token %i created."), token);
else if (op == REMOVED)
log_verbose(_("Token %i removed."), token);
}
/*
* Device size string parsing, suffixes:
* s|S - 512 bytes sectors
@@ -419,8 +448,156 @@ int tools_wipe_progress(uint64_t size, uint64_t offset, void *usrptr)
check_signal(&r);
if (r) {
tools_clear_line();
log_err("\nWipe interrupted.\n");
log_err("\nWipe interrupted.");
}
return r;
}
static void report_partition(const char *value, const char *device)
{
if (opt_batch_mode)
log_dbg("Device %s already contains a '%s' partition signature.", device, value);
else
log_std(_("WARNING: Device %s already contains a '%s' partition signature.\n"), device, value);
}
static void report_superblock(const char *value, const char *device)
{
if (opt_batch_mode)
log_dbg("Device %s already contains a '%s' superblock signature.", device, value);
else
log_std(_("WARNING: Device %s already contains a '%s' superblock signature.\n"), device, value);
}
int tools_detect_signatures(const char *device, int ignore_luks, size_t *count)
{
int r;
size_t tmp_count;
struct blkid_handle *h;
blk_probe_status pr;
if (!count)
count = &tmp_count;
*count = 0;
if (!blk_supported()) {
log_dbg("Blkid support disabled.");
return 0;
}
if ((r = blk_init_by_path(&h, device))) {
log_err(_("Failed to initialize device signature probes."));
return -EINVAL;
}
blk_set_chains_for_full_print(h);
if (ignore_luks && blk_superblocks_filter_luks(h)) {
r = -EINVAL;
goto out;
}
while ((pr = blk_probe(h)) < PRB_EMPTY) {
if (blk_is_partition(h))
report_partition(blk_get_partition_type(h), device);
else if (blk_is_superblock(h))
report_superblock(blk_get_superblock_type(h), device);
else {
log_dbg("Internal tools_detect_signatures() error.");
r = -EINVAL;
goto out;
}
(*count)++;
}
if (pr == PRB_FAIL)
r = -EINVAL;
out:
blk_free(h);
return r;
}
int tools_wipe_all_signatures(const char *path)
{
int fd, flags, r;
blk_probe_status pr;
struct stat st;
struct blkid_handle *h = NULL;
if (!blk_supported()) {
log_dbg("Blkid support disabled.");
return 0;
}
if (stat(path, &st)) {
log_err(_("Failed to stat device %s."), path);
return -EINVAL;
}
flags = O_RDWR;
if (S_ISBLK(st.st_mode))
flags |= O_EXCL;
/* better than opening regular file with O_EXCL (undefined) */
/* coverity[toctou] */
fd = open(path, flags);
if (fd < 0) {
if (errno == EBUSY)
log_err(_("Device %s is in use. Can not proceed with format operation."), path);
else
log_err(_("Failed to open file %s in read/write mode."), path);
return -EINVAL;
}
if ((r = blk_init_by_fd(&h, fd))) {
log_err(_("Failed to initialize device signature probes."));
r = -EINVAL;
goto out;
}
blk_set_chains_for_wipes(h);
while ((pr = blk_probe(h)) < PRB_EMPTY) {
if (blk_is_partition(h))
log_verbose("Existing '%s' partition signature on device %s will be wiped.",
blk_get_partition_type(h), path);
if (blk_is_superblock(h))
log_verbose("Existing '%s' superblock signature on device %s will be wiped.",
blk_get_superblock_type(h), path);
if (blk_do_wipe(h)) {
log_err(_("Failed to wipe device signature."));
r = -EINVAL;
goto out;
}
}
if (pr != PRB_EMPTY) {
log_err(_("Failed to probe device %s for a signature."), path);
r = -EINVAL;
}
out:
close(fd);
blk_free(h);
return r;
}
int tools_is_cipher_null(const char *cipher)
{
if (!cipher)
return 0;
return !strcmp(cipher, "cipher_null") ? 1 : 0;
}
/*
* Keyfile - is standard input treated as a binary file (no EOL handling).
*/
int tools_is_stdin(const char *key_file)
{
if (!key_file)
return 1;
return strcmp(key_file, "-") ? 0 : 1;
}

Some files were not shown because too many files have changed in this diff Show More