Compare commits

...

337 Commits

Author SHA1 Message Date
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
Milan Broz
87dcc9fe07 Prepare version 2.0.2. 2018-03-07 12:55:54 +01:00
Milan Broz
c56e0eb556 Update po files. 2018-03-06 09:18:08 +01:00
Milan Broz
ba959970c6 Update po files. 2018-03-02 08:58:39 +01:00
Milan Broz
c75e31d3da Set devel version. 2018-03-01 15:04:12 +01:00
Milan Broz
bcc2330a18 Actually fail early Travis test if non-root test fails. 2018-03-01 14:31:04 +01:00
Milan Broz
f0f5913efe Fix device_test to properly fail for non-root user. 2018-03-01 14:05:51 +01:00
Milan Broz
17aefd333a Fix intearctive tests to actually fail if there is a timeout. 2018-03-01 13:48:04 +01:00
Milan Broz
b86a652b90 Return back check for inactive keyslot for luksKillSlot. 2018-03-01 13:46:50 +01:00
Ondrej Kozina
5968323642 Refactor cryptsetup-reencrypt luks2 handling.
Fold former luks2_transfer_tokens and luks2_transfer_flags into
new luks2_metadata_copy.
2018-02-28 10:37:14 +01:00
Ondrej Kozina
26727882d0 Refactor update_persistent_flags. 2018-02-28 10:36:43 +01:00
Ondrej Kozina
106e441a61 Add error message explaining locking failure. 2018-02-28 10:36:34 +01:00
Ondrej Kozina
6d22ba9f87 Allow symbolic links in locking path.
Allow symbolic links in the initial part of locking path.
If /run/x/y/crypsetup is locking path, starting with
'run' anything may be symbolic link up to (including) 'y'.
2018-02-28 10:36:26 +01:00
Ondrej Kozina
8cd9db272f Adapt device-test to different performance options handling.
cpu --perf-* options do not trigger error when
not supported by current kernel.

Also be more carefull about --sector-size when not supported by
dm-crypt. Test is made more pedantic now.
2018-02-28 10:36:06 +01:00
Ondrej Kozina
b8691649c5 Retry dm-crypt load if performance options are not supported. 2018-02-28 10:35:53 +01:00
Ondrej Kozina
e9a2938c6b Test persistent flags after reencryption. 2018-02-28 10:35:41 +01:00
Milan Broz
44fa0bfbc6 Ensure that we do not process null in atoi call. 2018-02-28 08:57:10 +01:00
Ondrej Kozina
36c213ed3a Remove warning from cryptsetup-reencrypt man page.
Tokens and persistent flags are now transferred during
reencryption.
2018-02-27 12:09:44 +01:00
Ondrej Kozina
5f26f8a03d Transfer persistent flags to new LUKS2 header. 2018-02-27 12:09:18 +01:00
Ondrej Kozina
471f781022 Enhance persistent flags handling in cryptsetup.
With --persistent option, write only flags actually
used during activation. In other words we will not
store anymore flags not supported by running kernel.
2018-02-27 11:58:20 +01:00
Ondrej Kozina
f6cb8e4118 Do not allow --persistent and --test-passphrase. 2018-02-27 11:58:15 +01:00
Ondrej Kozina
515eff269c Add basic tests for persistent flags API. 2018-02-27 11:58:11 +01:00
Ondrej Kozina
bd370ab789 Fix bugs in crypt_persistent_flags_get.
various bugfixes:
- erase flags variable if no flags are stored
- do not print false debug warning
- during activation do not overwrite activation flags
  with persistent flags
2018-02-27 11:58:05 +01:00
Ondrej Kozina
3e10116437 Test crypt_activate_by_token() and keyring. 2018-02-27 11:58:01 +01:00
Ondrej Kozina
05f665ecda Return error on conflicting keyring requests.
Add missing check in crypt_activate_by_token. An oversight
from previous patch.
2018-02-27 11:57:57 +01:00
Milan Broz
cd65f6a84d Speedup reencryption test. 2018-02-23 13:50:44 +01:00
Milan Broz
6d2979459e Key parameter is always const in cipher and storage backend. 2018-02-23 10:40:17 +01:00
Milan Broz
dee38e9c0b Rename buffer to key in hmac_init in crypto backend.
It is key and naming was confusing.
2018-02-23 10:40:14 +01:00
Milan Broz
b4fc36ea62 Make all crypto backend destructors return void.
Nothing in the code actually checks the return values anyway.
2018-02-23 10:40:11 +01:00
Milan Broz
fb6b4739e4 Clean up keyring handling.
Move all keyring functions to one place and separate LUKS2 specific
code to generic handling.

Also fix possible mismatch if volume key is in keyring but it is not native
LUKS2 device (libarary cannot process such a device properly).
2018-02-22 15:26:07 +01:00
Milan Broz
32700cc51b Fix possible dereference of type string. 2018-02-22 15:26:03 +01:00
Milan Broz
1ac353d24e Allocate key description in volume key.
The key description is now allocated by volume key wrappers.
2018-02-22 15:23:11 +01:00
Ondrej Kozina
d7686201dc Grow fs images and alter tests accordingly. 2018-02-22 15:22:39 +01:00
Ondrej Kozina
248733de44 Add reencryption test for LUKS2 tokens.
Test tokens are transferred properly to new LUKS2 header.
2018-02-22 15:22:08 +01:00
Ondrej Kozina
e410ba9623 On reencryption transfer tokens to new LUKS2 header. 2018-02-22 15:21:59 +01:00
Ondrej Kozina
8295bde95a Update tests for token enhancements.
- add crypt_token_is_assigned tests
- test crypt_token_json_set extended to be able
  to create builtin tokens.
2018-02-22 15:21:52 +01:00
Ondrej Kozina
f3a9e95dd8 Add simple API for token assignment reporting. 2018-02-22 15:21:37 +01:00
Ondrej Kozina
7378e3be01 Allow crypt_token_json_set to create internal types. 2018-02-22 15:21:31 +01:00
Ondrej Kozina
1968efe9f0 Do not allow unexpected fields in keyring token validation. 2018-02-22 15:21:24 +01:00
Milan Broz
2b6808f165 Fix some anoying gcc buffer size warnings. 2018-02-14 18:23:25 +01:00
Milan Broz
92f14d28d1 Fix null dereference in previous commit. 2018-02-14 14:19:48 +01:00
Milan Broz
954214e48c Use integrity key during integritysetup format.
Kernel could reject HMAC without a key during format, we must set a key here as well.

Because there is no data area (device size is 8 sectors), it is actually never used,
so we can use zeroed key here.

The real HMAC key is used later during device activation with the real size.
2018-02-13 14:41:36 +01:00
Milan Broz
828e6f2077 Skip legacy TrueCrypt algoritms if PIM is specified. 2018-02-13 13:27:07 +01:00
Ondrej Kozina
982b7373ea Sort option descriptions in reencrypt man page.
Sort detailed option descriptions alphabetically (LANG=C)
2018-02-13 13:04:11 +01:00
Ondrej Kozina
39b5359efd Update cryptsetup-reencrypt page.
- add --pbkdf* option descriptions
- few clarifications wrt LUKS2 format
- alter note about limited support for LUKS2. It's 1:1
  with LUKS1 format currently, but tokens are not yet
  transfered to new LUKS2 header for reencrypted device.
- few minor corrections
2018-02-13 13:04:07 +01:00
Milan Broz
627a538bf2 Fix Veracrypt PIM handling.
The code must not set global table with KDF variants but
it shuld calculate local iterations count.

Also PIM is not used for old Trucrypt modes, do not use it there.

Also fix leak of PIM iteration count to debug log.

Fixes issue #366 and issue #367.
2018-02-12 20:19:04 +01:00
Milan Broz
e07e3ecc22 Fix integrity tests to always use a key with HMAC algorithms.
Recent kernel changes disallows to use keyed-hash algorithms
without settting the key.

Unfortunately, dm-integrity fails too late (during IO, not on init).

For now fix just the test.
2018-02-12 11:53:02 +01:00
Ondrej Kozina
b426db6086 Reencrypt tests improvements.
- adapt tests to new features (luks2 keyslot change, pbkdf params)
- add tests for fixes (max keyslot)
- speed up tests significantly by add minimal forced values everywhere.
2018-02-11 15:09:38 +01:00
Ondrej Kozina
d4b43d8578 Allow changing LUKS2 keyslot params in cryptsetup-reencrypt. 2018-02-11 14:59:32 +01:00
Ondrej Kozina
b9b1680f08 Various improvements to cryptsetup-reencrypt tool.
- allow changing pbkdf parameters for LUKS2
- allow force iterations for both LUKS1 and LUKS2 formats.
2018-02-11 14:53:20 +01:00
Ondrej Kozina
3e37975a00 Fix cryptsetup-reencrypt verbose message.
Print volume key change only when --keep-key option is not specified.
2018-02-11 14:52:34 +01:00
Ondrej Kozina
b0e252684d Allow higher keyslot numbers with LUKS2 format in reencryption. 2018-02-11 14:49:47 +01:00
Ondrej Kozina
919e1c3f08 Adapt tests to --pbkdf-force-iterations restrictions. 2018-02-08 15:35:02 +01:00
Milan Broz
16dc58312c Move PBKDF limits to crypto backend (to one place). 2018-02-08 15:34:45 +01:00
Ondrej Kozina
169bd9db5e Do not allow forced pbkdf parameters below minimal values. 2018-02-08 15:33:08 +01:00
Milan Broz
4e5e8fd8fe cryptsetup: Print message about operation aborted if user did not answer YES.
Thanks Colin Walters for the initial idea in !33.
2018-01-24 10:17:28 +01:00
Milan Broz
8728ba08e2 Fix loopaesOpen for keyfile on standard input.
The change in keyfile processing caused that special loopAES
keyfiles are no longer read from stdin if key-file argument is "-".

Fix it by using /dev/stdin in cryptsetup if "-" is detected.
(The libcryptsetup API no longer parses spacial meaning of "-" internally).

Fixes #364.
2018-01-24 09:05:52 +01:00
Milan Broz
3ba07ed27f Fix another typo in release notes. 2018-01-21 12:59:08 +01:00
Milan Broz
9b4b659804 Fix missing 2.0.0 release notes in readme.md. 2018-01-21 12:48:57 +01:00
Milan Broz
c00a31077c Update Readme.md for 2.0.1. 2018-01-21 12:43:00 +01:00
Milan Broz
e8fc17f816 Prepare version 2.0.1. 2018-01-21 12:28:01 +01:00
Milan Broz
4a2da4b51e Add 2.0.1 Release Notes. 2018-01-21 12:10:23 +01:00
Milan Broz
180d96234e Fix another compiler warnings with extra flags. 2018-01-20 21:17:10 +01:00
Milan Broz
1a04ffbae4 Update LUKS1 standard doc (link fixes). 2018-01-20 18:46:00 +01:00
Milan Broz
1fe014dbae Update copyright year. 2018-01-20 17:55:21 +01:00
Milan Broz
579c31aa23 Update po files. 2018-01-20 17:26:49 +01:00
Milan Broz
74c914475f Increase maximum allowed PBKDF memory limit.
And also fix physical memory trimming function
to really allow requested value.
2018-01-20 17:04:02 +01:00
Milan Broz
1ca439f4e0 Fix some warnings found during static analysis. 2018-01-20 14:42:05 +01:00
Ondrej Kozina
08e7c143b3 Add internal code for LUKS2 keyslot params.
This fixes crypt_keyslot_add_by_key where we were unable to store
keyslot (unbound to segment) with different key_size.
The code used (new) volume key size implicitly which could be wrong
if new size was not compatible with cipher parameter for keyslot area.
2018-01-19 13:48:09 +01:00
Milan Broz
d399dfa792 Add error hint for wrongly formatted cipher strings in LUKS1. 2018-01-19 11:09:06 +01:00
Milan Broz
f6e613a76f Revert cipher requirement in parse cipher.
There is several specification that violate this (chacha20 etc).
Just use the old way...
2018-01-18 22:42:34 +01:00
Milan Broz
c6a8b6471a Allow ECB in cipher spec (fixes previous patch). 2018-01-18 21:55:52 +01:00
Ondrej Kozina
83589b7cec Extend LUKS2 specific tests.
Add yet another flawed dm-crypt test (keyring)
and test crypt_get_volume_key_size works
as expected after LUKS2 crypt_format (before
adding first keyslot).
2018-01-18 21:26:55 +01:00
Milan Broz
aeea93fa95 Properly fail in luksFormat if cipher format is missing required IV.
For now, crypto API quietly used cipher witout IV if a cipher
algorithm wihtou IV specificaton was used (e.g. aes-xts).

This caused fail later during activation.

This patch allows only two specific backed use without specified IV
(ECB mode and NULL cipher).

Also check cipher string early during parsing of CLI options.
2018-01-18 21:20:25 +01:00
Ondrej Kozina
be417d6605 Test keyring is disabled with flawed dm-crypt. 2018-01-18 14:37:51 +01:00
Ondrej Kozina
2f890dea18 Update tests for dm-crypt kernel key bugfix.
cryptsetup now requires dm-crypt v1.18.1 or higher
to use kernel keyring service for passing VKs.

Also, relevant API functions fail if CRYPT_ACTIVATE_KEYRING_KEY
is set, but library is not allowed to use kernel keyring for
VK.
2018-01-18 14:24:24 +01:00
Ondrej Kozina
de76628539 Return error for conflicting requests.
Return error when CRYPT_ACTIVATE_KEYRING_KEY flag is
raised but activation with vk in kernel keyring is not
possible.
2018-01-18 14:19:33 +01:00
Ondrej Kozina
598dd672bc Detect kernel version for dm-crypt kernel key bugfix.
When loading first dm-crypt table (or action that triggers dm-crypt
module load) we do not know dm-crypt version yet. Let's assume all
kernels before 4.15.0 are flawed and reject VK load via kernel keyring
service.

When dm-crypt is already in kernel, check for correct target version
instead (v1.18.1 or later).
2018-01-18 14:17:00 +01:00
Ondrej Kozina
d12fb3d6e1 Postpone use of kernel keyring for VKs to dm-crypt 1.18.1
Upstream dm-crypt v1.15.0 through v1.18.0 contains
serious bug in kernel key processing that may cause
data corruption for ciphers using essiv, tcw and lmk IVs.

Patch adds patch number processing to DM version checks.
2018-01-18 14:07:54 +01:00
Ondrej Kozina
9504d866b6 Use default segment alias in LUKS2 activatation. 2018-01-18 14:05:33 +01:00
Ondrej Kozina
865b1dc66e Add kernel key compat tests.
This test can detect ugly dm-crypt kernel key bug
present in kernels 4.10.0 through 4.15.0-rc8.
2018-01-18 14:05:13 +01:00
Ondrej Kozina
5143b210cf Return correct volume key size if internal volume key exists.
Return correct volume key size as long as valid volume key
is reachable at least in device context.
2018-01-18 13:42:11 +01:00
Milan Broz
f34ce81f25 Introduce new 64bit *keyfile_device_offset functions.
The keyfile interface was designed, well, for keyfiles.

Unfortunately, a keyfile can be placed on a device and the size_t offset
can overflow.

We have to introduce new set of fucntions that allows 64bit offsets even on 32bit systems:
 - crypt_resume_by_keyfile_device_offset
 - crypt_keyslot_add_by_keyfile_device_offset
 - crypt_activate_by_keyfile_device_offset
 - crypt_keyfile_device_read

The new functions have added _device_ in name.

Old functions are just internall wrappers around these.

Also cryptsetup --keyfile-offset and --new-keyfile-offset must now
process 64bit offsets.

For more info see issue 359.
2018-01-17 22:07:23 +01:00
madblobfish
b072c6c4c9 fix logic sentence error in releasenotes 2018-01-15 09:50:17 +01:00
Milan Broz
7951ed3bce Remove GMANE list archive that no longer exists. 2018-01-15 09:48:29 +01:00
Ondrej Kozina
02431c57db Force dmsetup to show dm-integrity keys in tests.
Recent dmsetup requires --showkeys option to
print dm-integrity keys.
2018-01-10 18:46:32 +01:00
Milan Broz
3f186c009c Auth tag size and iv size can depend on auth cipher.
Some experimental ciphers will use different IV sizes,
add parameter to check it in future (unused for now).
2018-01-05 16:38:58 +01:00
Milan Broz
6f4c15b2b2 Use /run/cryptsetup as default for cryptsetup locking dir.
There are problems with sharing /run/lock with lockdev and also in early boot
we cannot create the whole subir chain.

It is safe to switch to separate locking dir.
This can be changed with --with-luks2-lock-path and --with-luks2-lock-dir-perms
configure switches.

See Issue#361 and issue#362.
2018-01-04 09:23:11 +01:00
Ondrej Kozina
b31e029000 Validate LUKS2 header in crypt_set_uuid(). 2018-01-04 09:20:23 +01:00
Ondrej Kozina
5f5ffcd48a Remove logging from keyring utilities.
Reduce bloated code in low level keyring utilities code.
Move log messages higher the library code.

Also return -ENOTSUP when code was compiled out by configure
option.
2018-01-04 09:20:14 +01:00
Ondrej Kozina
cc76f3746f Remove unused digests handling code.
Remove code for handling multiple digests per single keyslot.
Same would apply to segments with the only exception of segment
in-reencryption. We need that exception so that we will not lose
old key digests too early.
2018-01-04 09:17:34 +01:00
Yuri Chornoivan
982da4d20c Fix minor typos 2018-01-04 09:13:58 +01:00
Milan Broz
113374fd04 Update po files. 2018-01-04 09:11:28 +01:00
Ondrej Kozina
e4520693dd API docs cleanup and clarifications 2017-12-18 19:32:44 +01:00
Milan Broz
ccffc88ceb Check for recent Argon2 lib to support Argon2id.
Fixes Issue#356.
2017-12-17 15:29:35 +01:00
Milan Broz
7c9312607c Fix cryptsetup-reencrypt static build if pwquality is enabled.
In static build we need to link also to pwquality.

Fixes Issue#357.
2017-12-17 15:20:49 +01:00
Ondrej Kozina
286c2960c8 silence signed/unsigned compiler warnings
any array with item count close to INT32_MAX would
not fit LUKS2 header json area anyway
2017-12-13 12:06:58 +01:00
Ondrej Kozina
a12e374a04 harden checks of json_object_array_length return values
with json-c until 0.12.x json_object_array_length returned signed
integer. json-c 0.13.x and later changed return type to unsigned
size_t.

Consider return values less or equal to zero as empty array, otherwise
array is non-empty.
2017-12-13 12:06:54 +01:00
Ondrej Kozina
d799c8bd1e update crypt_resize api docs 2017-12-12 14:02:41 +01:00
Milan Broz
251eec8401 Update Readme.md. 2017-12-10 21:26:56 +01:00
Milan Broz
bca8a32674 Prepare version 2.0.0. 2017-12-10 20:49:43 +01:00
Ondrej Kozina
c740324636 Derive VK kernel key description from digest id
Originally the key description for VK was derived
from segment id. This could lead to ambiguity when
keyslot key is verified and loaded in kernel keyring
using activation functions with CRYPT_ACTIVATE_KEYRING_KEY
flag raised.
2017-12-10 19:56:14 +01:00
Milan Broz
f049afcb5b Fix a rare fail in key-length regression test with PBKDF2.
PBKDF2 has nasty behaviour that it generates the same output
for passwords that has several trailing zero bytes.
(IOW null trailing bytes causes collision.)

Unfortunatelly our test plays with password length
and expect wrong length must always fail.
Sometimes the randomly generated key key contains
the null byte in the "wrong" place and PBKDF2 causes test to fail.

For now, fix it by using fixed keyfile without null bytes
(similar to fixed passphrased we already have).
2017-12-10 11:39:00 +01:00
Ondrej Kozina
c188654ebd simplify kernel keyring key removal path
simplify crypt_drop_keyring_key

also do not search for keyring keys when we know
we haven't loaded any
2017-12-09 14:55:23 +01:00
Ondrej Kozina
a6aba8cab2 tests: check keyring key is gone after crypt_suspend 2017-12-09 14:53:02 +01:00
Ondrej Kozina
583fbfdb2a drop keyring key after successful crypt_suspend
due to wrong sequence of function calls the volume key
(if present) in keyring was never dropped properly.
2017-12-09 14:52:46 +01:00
Ondrej Kozina
7c34ac6f6d always return error when VK fails to load in keyring 2017-12-09 14:52:26 +01:00
Milan Broz
b72354ca22 Fix test scripts to always use different keyfile size.
Othewise it fails later with 1/256 probability if the first random byte is
the same :-]
2017-12-07 14:21:29 +01:00
Ondrej Kozina
82d81b9e86 extend use of lseek_blockwise functions 2017-12-07 13:01:04 +01:00
Ondrej Kozina
ed19ddf620 be specific about version in failed format operation 2017-12-07 13:00:59 +01:00
Milan Broz
ebbd33db7a Add po file. 2017-12-07 12:16:37 +01:00
Milan Broz
7ba4ca1854 Add bundled lib README to package. 2017-12-07 12:15:55 +01:00
Milan Broz
fa1f8c0d87 Limit KDF memory by available physical memory.
On some systems the requested amount of memory causes OOM killer
to kill the process (instead of returning ENOMEM).

For now, we never try to use more than half of available
physical memory.
2017-12-07 10:43:52 +01:00
Milan Broz
e0cacef52e Align legacy keyslot temporary device according to keyslot alignment.
For some strange filesystems (nfs) we get big block size (1MB).

For temporary keyslot devices this mapping does not make sense and
can cause problem with detached headers that are smaller (contains
exactly the slot size).
2017-12-06 17:07:24 +01:00
Milan Broz
767ed40b75 Use better "time cost" for Argon than time. 2017-12-05 15:41:24 +01:00
Milan Broz
3c2f92a7af Increase Argon2 LUKS2 default. 2017-12-05 14:44:44 +01:00
Milan Broz
2568f828c8 Workaround to delete stale library if --disable-libargon2 was used. 2017-12-05 14:43:41 +01:00
Michal Virgovic
5427f55358 Add test for integritysetup modes. 2017-12-05 10:50:45 +01:00
Ondrej Kozina
92b41e4935 more return NULL instead of 0 cleanups 2017-12-01 13:17:32 +01:00
Ondrej Kozina
6edae6ddef return NULL instead of 0 2017-12-01 13:10:37 +01:00
Ondrej Kozina
f787eafd8a drop duplicate default segment define 2017-11-30 16:54:06 +01:00
Milan Broz
9588a961d6 Do not alloc tcrypt keyfileon stack.
The keyfile has 1MB, it is better to run malloc for this code.
2017-11-24 13:45:21 +01:00
Ondrej Kozina
88758703fa test: update luks2 validation tests 2017-11-23 16:18:27 +01:00
Ondrej Kozina
3c839f44d8 luks2: fix off-by-one error in uint64 validation 2017-11-23 16:18:19 +01:00
Ondrej Kozina
304bdd7d0d luks2: add json_object_new_uint64 wrapper
json doesn't support 64 bits integers. We workaround it by storing
large numbers as string and validate the value internally.
2017-11-23 16:18:14 +01:00
Ondrej Kozina
382d27b4dc remove unused function 2017-11-23 16:17:07 +01:00
Milan Broz
b80278c04f Ignore device opt-io alignment if it is not multiple of minimal-io.
Some USB enclosures seems to report bogus topology info.
Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1513820
2017-11-21 15:39:36 +01:00
Ondrej Kozina
7d4fcfa191 fix memleaks on integrity format error path 2017-11-19 10:01:59 +01:00
Ondrej Kozina
ad3fe00dea fix memleaks on verity format error path 2017-11-19 09:51:59 +01:00
Milan Broz
f507d16baa Update bundled Argon2 source. 2017-11-14 12:07:53 +01:00
Milan Broz
dcce2edc4f Fix integrity setup test journal watermark setting. 2017-11-14 09:31:33 +01:00
Milan Broz
e7e1e7a0a3 Update po files. 2017-11-13 19:57:59 +01:00
Milan Broz
68f4485cdd Fix deactivation of standalone integrity device. 2017-11-13 19:57:16 +01:00
Guilhem Moulin
d93ac3c496 Remove libargon2 code from source tree
[mbroz: fix for make distcheck]
2017-11-08 10:51:58 +01:00
Andrea Gelmini
a97de38b6b Fix typos. 2017-11-08 10:22:49 +01:00
Milan Broz
444eac3597 Update po files. 2017-11-08 09:56:32 +01:00
Ondrej Kozina
1f01c76fa5 fix memory leak on failed luks2 activation 2017-11-03 17:30:14 +01:00
199 changed files with 30294 additions and 12466 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,6 +38,7 @@ function check_nonroot
configure_travis \
--enable-python \
--enable-cryptsetup-reencrypt \
--enable-internal-sse-argon2 \
"$cfg_opts" \
|| return
@@ -50,9 +51,7 @@ function check_nonroot
sudo dmsetup version
sudo dmsetup targets
make check || return
#sudo $MAKE install || return
make check
}
function check_root
@@ -64,6 +63,7 @@ function check_root
configure_travis \
--enable-python \
--enable-cryptsetup-reencrypt \
--enable-internal-sse-argon2 \
"$cfg_opts" \
|| return
@@ -77,9 +77,7 @@ function check_root
sudo dmsetup targets
# FIXME: we should use -E option here
sudo make check || return
#sudo $MAKE install || return
sudo make check
}
function check_nonroot_compile_only
@@ -91,6 +89,7 @@ function check_nonroot_compile_only
configure_travis \
--enable-python \
--enable-cryptsetup-reencrypt \
--enable-internal-sse-argon2 \
"$cfg_opts" \
|| return
@@ -120,6 +119,7 @@ function travis_install_script
expect \
keyutils \
libjson-c-dev \
libblkid-dev \
|| return
}
@@ -141,14 +141,14 @@ function travis_script
case "$MAKE_CHECK" in
gcrypt)
check_nonroot "--with-crypto_backend=gcrypt"
check_nonroot "--with-crypto_backend=gcrypt" && \
check_root "--with-crypto_backend=gcrypt"
;;
gcrypt_compile)
check_nonroot_compile_only "--with-crypto_backend=gcrypt"
;;
openssl)
check_nonroot "--with-crypto_backend=openssl"
check_nonroot "--with-crypto_backend=openssl" && \
check_root "--with-crypto_backend=openssl"
;;
openssl_compile)

8
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.
@@ -209,7 +209,7 @@ A. Contributors
to send it from your list address.
The mailing list archive is here:
http://dir.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt
https://marc.info/?l=dm-crypt
* 1.8 Unsubscribe from the mailing-list
@@ -2475,7 +2475,7 @@ offset length name data type description
More details:
Cipher, mode and pasword hash (or no hash):
Cipher, mode and password hash (or no hash):
-e cipher [-N] => -c cipher-cbc-plain -H plain [-s 256]
-e cipher => -c cipher-cbc-plain -H ripemd160 [-s 256]
@@ -2616,7 +2616,7 @@ My take is this was much more driven by some big egos that wanted
to make a splash for self-aggrandizement, than by any actual
security concerns. Ignore it.
* 9.3 How do I do my own inird with cryptsetup?
* 9.3 How do I do my own initrd with cryptsetup?
It depends on the distribution. Below, I give a very simple example
and step-by-step instructions for Debian. With a bit of work, it

View File

@@ -44,7 +44,7 @@ The simplest way to compile this package is:
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
Running `configure' takes a while. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.

View File

@@ -29,7 +29,9 @@ include python/Makemodule.am
include scripts/Makemodule.am
if CRYPTO_INTERNAL_ARGON2
include lib/crypto_backend/argon2/Makemodule.am
endif
include lib/crypto_backend/Makemodule.am
include lib/Makemodule.am
@@ -39,11 +41,12 @@ ACLOCAL_AMFLAGS = -I m4
DISTCHECK_CONFIGURE_FLAGS = \
--enable-python \
--with-tmpfilesdir=$$dc_install_base/usr/lib/tmpfiles.d
--with-tmpfilesdir=$$dc_install_base/usr/lib/tmpfiles.d \
--enable-internal-argon2 --enable-internal-sse-argon2
distclean-local:
-find . -name \*~ -o -name \*.orig -o -name \*.rej | xargs rm -f
rm -rf autom4te.cache
clean-local:
-rm -rf docs/doxygen_api_docs
-rm -rf docs/doxygen_api_docs libargon2.la

View File

@@ -26,7 +26,7 @@ Last version of the LUKS format specification is
Why LUKS?
---------
* compatiblity via standardization,
* compatibility via standardization,
* secure against low entropy attacks,
* support for multiple keys,
* effective passphrase revocation,
@@ -42,19 +42,25 @@ Download
--------
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
**The latest cryptsetup TESTING version is 2.0.0-rc1**
* [cryptsetup-2.0.0-rc1.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0-rc1.tar.xz)
* Signature [cryptsetup-2.0.0-rc1.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0-rc1.tar.sign)
**The latest cryptsetup version is 2.0.3**
* [cryptsetup-2.0.3.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.3.tar.xz)
* Signature [cryptsetup-2.0.3.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.3.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.0.0-rc1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.0-rc1-ReleaseNotes).
**The latest cryptsetup version is 1.7.5**
* [cryptsetup-1.7.5.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz)
* Signature [cryptsetup-1.7.5.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 1.7.5 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).
* [Cryptsetup 2.0.3 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.3-ReleaseNotes).
Previous versions
* [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).
* [Version 1.7.5](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).
* [Version 1.7.4](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.4.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.4.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.4-ReleaseNotes).
@@ -78,7 +84,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).
@@ -90,4 +96,4 @@ For cryptsetup and LUKS related questions, please use the dm-crypt mailing list,
If you want to subscribe just send an empty mail to [dm-crypt-subscribe@saout.de](mailto:dm-crypt-subscribe@saout.de).
You can also browse [list archive](http://www.saout.de/pipermail/dm-crypt/) or read it through
[web interface](http://news.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt).
[web interface](https://marc.info/?l=dm-crypt).

6
TODO
View File

@@ -1,5 +1 @@
- Support K/M suffixes for align payload (new switch?).
- Do we need crypt_data_path() - path to data device (if differs)?
- Resync ETA time is not accurate, calculate it better (last minute window?).
- Fix all crazy automake warnings (or switch to Cmake).
- Nettle3 backend is not compatible
Please see issues tracked at https://gitlab.com/cryptsetup/cryptsetup/issues.

View File

@@ -1,9 +1,9 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[2.0.0-rc1])
AC_INIT([cryptsetup],[2.0.4])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
LIBCRYPTSETUP_VERSION_INFO=12:0:0
LIBCRYPTSETUP_VERSION_INFO=15:0:3
AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR(src/cryptsetup.c)
@@ -403,14 +403,64 @@ AC_ARG_ENABLE([libargon2], AS_HELP_STRING([--enable-libargon2],
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>])
PKG_CHECK_MODULES([LIBARGON2], [libargon2],,[LIBARGON2_LIBS="-largon2"])
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]),[], [enable_internal_sse_argon2=no])
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
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_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
@@ -462,14 +512,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 ==========================================================================
@@ -489,6 +544,13 @@ 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]),
@@ -532,8 +594,8 @@ CS_NUM_WITH([luks1-keybits],[key length in bits for LUKS1], [256])
CS_STR_WITH([luks2-pbkdf], [Default PBKDF algorithm (pbkdf2 or argon2i/argon2id) for LUKS2], [argon2i])
CS_NUM_WITH([luks1-iter-time], [PBKDF2 iteration time for LUKS1 (in ms)], [2000])
CS_NUM_WITH([luks2-iter-time], [Argon2 PBKDF iteration time for LUKS2 (in ms)], [800])
CS_NUM_WITH([luks2-memory-kb], [Argon2 PBKDF memory cost for LUKS2 (in kB)], [131072])
CS_NUM_WITH([luks2-iter-time], [Argon2 PBKDF iteration time for LUKS2 (in ms)], [2000])
CS_NUM_WITH([luks2-memory-kb], [Argon2 PBKDF memory cost for LUKS2 (in kB)], [1048576])
CS_NUM_WITH([luks2-parallel-threads],[Argon2 PBKDF max parallel cost for LUKS2 (if CPUs available)], [4])
CS_STR_WITH([loopaes-cipher], [cipher for loop-AES mode], [aes])
@@ -550,17 +612,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/lock/cryptsetup])
test -z "$with_luks2_lock_path" && with_luks2_lock_path=/run/lock/cryptsetup
test "${with_luks2_lock_path:0:1}" = "/" || AC_MSG_ERROR([--with-luks2-lock-path argument must be an absolute path.])
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
CS_ABSPATH([${with_luks2_lock_path}],[with-luks2-lock-path])
DEFAULT_LUKS2_LOCK_PATH=$with_luks2_lock_path
AC_SUBST(DEFAULT_LUKS2_LOCK_PATH)
@@ -569,6 +630,19 @@ 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

@@ -178,7 +178,7 @@
* Document cryptsetup exit codes.
2011-03-18 Milan Broz <mbroz@redhat.com>
* Respect maximum keyfile size paramater.
* Respect maximum keyfile size parameter.
* Introduce maximum default keyfile size, add configure option.
* Require the whole key read from keyfile in create command (broken in 1.2.0).
* Fix offset option for loopaesOpen.
@@ -334,13 +334,13 @@
* Version 1.1.0.
2010-01-10 Milan Broz <mbroz@redhat.com>
* Fix initialisation of gcrypt duting luksFormat.
* Convert hash name to lower case in header (fix sha1 backward comatible header)
* Fix initialisation of gcrypt during luksFormat.
* Convert hash name to lower case in header (fix sha1 backward compatible header)
* Check for minimum required gcrypt version.
2009-12-30 Milan Broz <mbroz@redhat.com>
* Fix key slot iteration count calculation (small -i value was the same as default).
* The slot and key digest iteration minimun is now 1000.
* The slot and key digest iteration minimum is now 1000.
* The key digest iteration # is calculated from iteration time (approx 1/8 of that).
* Version 1.1.0-rc4.
@@ -395,16 +395,16 @@
* Require device device-mapper to build and do not use backend wrapper for dm calls.
* Move memory locking and dm initialization to command layer.
* Increase priority of process if memory is locked.
* Add log macros and make logging modre consitent.
* Add log macros and make logging more consistent.
* Move command successful messages to verbose level.
* Introduce --debug parameter.
* Move device utils code and provide context parameter (for log).
* Keyfile now must be provided by path, only stdin file descriptor is used (api only).
* Do not call isatty() on closed keyfile descriptor.
* Run performance check for PBKDF2 from LUKS code, do not mix hash algoritms results.
* Run performance check for PBKDF2 from LUKS code, do not mix hash algorithms results.
* Add ability to provide pre-generated master key and UUID in LUKS header format.
* Add LUKS function to verify master key digest.
* Move key slot manuipulation function into LUKS specific code.
* Move key slot manipulation function into LUKS specific code.
* Replace global options struct with separate parameters in helper functions.
* Add new libcryptsetup API (documented in libcryptsetup.h).
* Implement old API calls using new functions.
@@ -412,7 +412,7 @@
* Add --master-key-file option for luksFormat and luksAddKey.
2009-08-17 Milan Broz <mbroz@redhat.com>
* Fix PBKDF2 speed calculation for large passhrases.
* Fix PBKDF2 speed calculation for large passphrases.
* Allow using passphrase provided in options struct for LuksOpen.
* Allow restrict keys size in LuksOpen.
@@ -424,7 +424,7 @@
* Switch PBKDF2 from internal SHA1 to libgcrypt, make hash algorithm not hardcoded to SHA1 here.
* Add required parameters for changing hash used in LUKS key setup scheme.
* Do not export simple XOR helper now used only inside AF functions.
* Completely remove internal SHA1 implementanion code, not needed anymore.
* Completely remove internal SHA1 implementation code, not needed anymore.
* Enable hash algorithm selection for LUKS through -h luksFormat option.
2009-07-28 Milan Broz <mbroz@redhat.com>
@@ -705,7 +705,7 @@
2005-12-06 Clemens Fruhwirth <clemens@endorphin.org>
* man/cryptsetup.8: Correct "seconds" to "microseconds" in the explaination for -i.
* man/cryptsetup.8: Correct "seconds" to "microseconds" in the explanation for -i.
2005-11-09 Clemens Fruhwirth <clemens@endorphin.org>
@@ -726,7 +726,7 @@
2005-09-08 Clemens Fruhwirth <clemens@endorphin.org>
* lib/setup.c (get_key): Fixed another incompatiblity with
* lib/setup.c (get_key): Fixed another incompatibility with
original cryptsetup.
2005-08-20 Clemens Fruhwirth <clemens@endorphin.org>
@@ -816,7 +816,7 @@
* man/cryptsetup.1: Add man page.
* lib/setup.c: Remove unneccessary LUKS_write_phdr call, so the
* lib/setup.c: Remove unnecessary LUKS_write_phdr call, so the
phdr is written after passphrase reading, so the user can change
his mind, and not have a partial written LUKS header on it's disk.

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

View File

@@ -1,7 +1,7 @@
/*
* An example of using logging through libcryptsetup API
*
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-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

View File

@@ -1,7 +1,7 @@
/*
* An example of using LUKS device through libcryptsetup API
*
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-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

Binary file not shown.

Binary file not shown.

View File

@@ -15,7 +15,7 @@ Important changes
* NSS (because of missing ripemd160 it cannot provide full backward compatibility)
* kernel userspace API (provided by kernel 2.6.38 and above)
(Note that kernel userspace backend is very slow for this type of operation.
But it can be usefull for embedded systems, because you can avoid userspace
But it can be useful for embedded systems, because you can avoid userspace
crypto library completely.)
Backend is selected during configure time, using --with-crypto_backend option.

View File

@@ -89,7 +89,7 @@ WARNING: This release removes old deprecated API from libcryptsetup
(It can be used to simulate trivial hidden disk concepts.)
libcryptsetup API changes:
* Added options to suport detached metadata device
* Added options to support detached metadata device
crypt_init_by_name_and_header()
crypt_set_data_device()
* Add crypt_last_error() API call.

View File

@@ -1,6 +1,6 @@
Cryptsetup 2.0.0 RC1 Release Notes
==================================
Release candidate with experimental features.
Cryptsetup 2.0.0 Release Notes
==============================
Stable release with experimental features.
This version introduces a new on-disk LUKS2 format.
@@ -12,18 +12,28 @@ major version for all public symbols.
Most of the old functions are fully backward compatible, so only
recompilation of programs should be needed.
Please note that authenticated disk encryption, noncryptographic
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 it without properly configured backup or in
production systems.
Until final 2.0 version is released, the new LUKS2 format
could still internally change if a major problem is found.
To provide all security features of authenticated encryption we need
better nonce-reuse resistant algorithm in kernel (see note below).
For now, please use authenticated encryption as experimental feature.
The library API calls (versioned symbols) are now stable and
will not change in an incompatible way.
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.0-RC1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Limit KDF requested (for format) memory by available physical memory.
On some systems too high requested amount of memory causes OOM killer
to kill the process (instead of returning ENOMEM).
We never try to use more than half of available physical memory.
* Ignore device alignment if it is not multiple of minimal-io.
Some USB enclosures seems to report bogus topology info that
prevents to use LUKS detached header.
Changes since version 2.0.0-RC0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -248,12 +258,13 @@ The newly added features in LUKS2 include:
For testing of authenticated encryption, these algorithms work for now:
1) aes-xts-random with hmac-sha256 or hmac-sha512 as the authentication tag.
(Authentication key for HMAC is independently generated. This mode is very slow.)
$ cryptsetup luksFormat --type luks2 <device> --cipher aes-xts-random --integrity hmac-sha256
1) aes-xts-plain64 with hmac-sha256 or hmac-sha512 as the authentication tag.
(Common FDE mode + independent authentication tag. Authentication key
for HMAC is independently generated. This mode is very slow.)
$ cryptsetup luksFormat --type luks2 <device> --cipher aes-xts-plain64 --integrity hmac-sha256
2) aes-gcm-random (native AEAD mode)
DO NOT USE in production. The GCM mode uses only 96-bit nonce,
DO NOT USE in production! The GCM mode uses only 96-bit nonce,
and possible collision means fatal security problem.
GCM mode has very good hardware support through AES-NI, so it is useful
for performance testing.
@@ -267,17 +278,8 @@ The newly added features in LUKS2 include:
should work as well. The mode 1) and 2) should be compatible with IEEE 1619.1
standard recommendation.
You can also store only random IV in tag without integrity protection.
Note that using random IV forces the system to pseudorandomly change the whole
sector on every write without removing parallel processing of XTS mode.
In cryptography, we can say that this will provide indistinguishability under
chosen plaintext attack (IND-CPA) that cannot be achieved in legacy
FDE systems. On the other side, if stored random IV is corrupted, the sector
is no longer decrypted properly.
To use only random IV (no integrity protection), just specify "none" integrity.
$ cryptsetup luksFormat --type luks2 <device> --cipher aes-xts-random --integrity none
There will be better suitable authenticated modes available soon
For now we are just preparing framework to enable it (and hopefully improve security of FDE).
FDE authenticated encryption is not a replacement for filesystem layer
authenticated encryption. The goal is to provide at least something because
@@ -296,7 +298,7 @@ The newly added features in LUKS2 include:
To solve this problem, a new PBKDF, based on so-called memory-hard functions
can be used. Key derivation with memory-hard function requires a certain
amount of memory to compute its output. The memory requirement is very
costly for GPUs and prevents these systems to operate ineffectively,
costly for GPUs and prevents these systems to operate effectively,
increasing cost for attackers.
LUKS2 introduces support for Argon2i and Argon2id as a PBKDF.
@@ -481,7 +483,7 @@ Other changes
For LUKS2 it is always better to specify full settings (do not rely on default
cost values).
For example, we can set to use Argon2id with iteration cost 5, memory 128000
and paralell set 1:
and parallel set 1:
$ cryptsetup luksFormat --type luks2 <device> \
--pbkdf argon2id --pbkdf-force-iterations 5 --pbkdf-memory 128000 --pbkdf-parallel 1
@@ -565,21 +567,24 @@ These new calls are now exported, for details see libcryptsetup.h:
crypt_keyfile_read;
crypt_wipe;
Unfinished things & TODO for next RC or future
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unfinished things & TODO for next releases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* There will be better documentation and examples.
* 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.)
* Offline re-encrypt tool supports only LUKS1 format for now (patches are
on the way).
* Offline re-encrypt tool LUKS2 support is currently limited.
There will be online LUKS2 re-encryption tool in future.
* There will be online LUKS2 re-encryption tool in future.
* Authenticated encryption will use new algorithms from CAESAR competition,
once these algorithms are available in kernel.
* Authenticated encryption will use new algorithms from CAESAR competition
(https://competitions.cr.yp.to/caesar.html) once these algorithms are available
in kernel (more on this later).
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
in kernel have too small 96-bit nonces that are problematic with
randomly generated IVs (the collison probability is not negligible).
For the GCM, nonce collision is a fatal problem.
* Authenticated encryption do not set encryption for dm-integrity journal.
@@ -588,17 +593,13 @@ Unfinished things & TODO for next RC or future
system will corrupt sectors after journal replay. (That corruption will be
detected though.)
* Some utilities (blkid, systemd-cryptsetup) will need small updates to support
LUKS2 format.
* Some utilities (blkid, systemd-cryptsetup) have already support for LUKS
but not yet in released version (support in crypttab etc).
* There are some 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).
We will document these examples later in release notes for next RC.
* The distribution archive is now very big because of some testing images that do not compress
well. Some cleaning is needed here.
* A lot of ideas are hidden inside the LUKS2 design that is not yet used or
described here, let's try if the basics work first :-)
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
(it is not updated for new features) and will be deprecated soon in favor
of python bindings to libblockdev library (that can already handle LUKS1 devices).

109
docs/v2.0.1-ReleaseNotes Normal file
View File

@@ -0,0 +1,109 @@
Cryptsetup 2.0.1 Release Notes
==============================
Stable and bug-fix release with experimental features.
This 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.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* To store volume key into kernel keyring, kernel 4.15 with dm-crypt 1.18.1
is required. If a volume key is stored in keyring (LUKS2 only),
the dm-crypt v1.15.0 through v1.18.0 contains a serious bug that may cause
data corruption for ciphers with ESSIV.
(The key for ESSIV is zeroed because of code misplacement.)
This bug is not present for LUKS1 or any other IVs used in LUKS modes.
This change is not visible to the user (except dmsetup output).
* Increase maximum allowed PBKDF memory-cost limit to 4 GiB.
The Argon2 PBKDF uses 1GiB by default; this is also limited by the amount
of physical memory available (maximum is half of the physical memory).
* Use /run/cryptsetup as default for cryptsetup locking dir.
There were problems with sharing /run/lock with lockdev, and in the early
boot, the directory was missing.
The directory can be changed with --with-luks2-lock-path and
--with-luks2-lock-dir-perms configure switches.
* Introduce new 64-bit byte-offset *keyfile_device_offset functions.
The keyfile interface was designed, well, for keyfiles. Unfortunately,
there are user cases where a keyfile can be placed on a device, and
size_t offset can overflow on 32-bit systems.
New set of functions that allow 64-bit offsets even on 32bit systems
are now available:
- crypt_resume_by_keyfile_device_offset
- crypt_keyslot_add_by_keyfile_device_offset
- crypt_activate_by_keyfile_device_offset
- crypt_keyfile_device_read
The new functions have added the _device_ in name.
Old functions are just internal wrappers around these.
Also cryptsetup --keyfile-offset and --new-keyfile-offset now allows
64-bit offsets as parameters.
* Add error hint for wrongly formatted cipher strings in LUKS1 and
properly fail in luksFormat if cipher format is missing required IV.
For now, crypto API quietly used cipher without IV if a cipher
algorithm without IV specification was used (e.g., aes-xts).
This caused fail later during activation.
* Configure check for a recent Argon2 lib to support mandatory Argon2id.
* Fix for the cryptsetup-reencrypt static build if pwquality is enabled.
* Update LUKS1 standard doc (https links in the bibliography).
Unfinished things & TODO for next releases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* There will be better documentation and examples.
* 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.)
* Offline re-encrypt tool LUKS2 support is currently limited.
There will be online LUKS2 re-encryption tool in future.
* Authenticated encryption will use new algorithms from CAESAR competition
(https://competitions.cr.yp.to/caesar.html) once these algorithms are
available in the kernel (more on this later).
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 the GCM, nonce collision is a fatal problem.
* 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 deprecated soon in favor
of python bindings to the libblockdev library (that can already handle LUKS1
devices).

93
docs/v2.0.2-ReleaseNotes Normal file
View File

@@ -0,0 +1,93 @@
Cryptsetup 2.0.2 Release Notes
==============================
Stable and bug-fix release with experimental 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.1
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix a regression in early detection of inactive keyslot for luksKillSlot.
It tried to ask for passphrase even for already erased keyslot.
* Fix a regression in loopaesOpen processing for keyfile on standard input.
Use of "-" argument was not working properly.
* 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 allows
to set precalculated values (no benchmarks).
* Do not allow LUKS2 --persistent and --test-passphrase cryptsetup flags
combination. Persistent flags are now stored only if the device was
successfully activated with the specified flags.
* Fix integritysetup format after recent Linux kernel changes that
requires to setup key for HMAC in all cases.
Previously integritysetup allowed HMAC with zero key that behaves
like a plain hash.
* Fix VeraCrypt PIM handling that modified internal iteration counts
even for subsequent activations. The PIM count is no longer printed
in debug log as it is sensitive information.
Also, the code now skips legacy TrueCrypt algorithms if a PIM
is specified (they cannot be used with PIM anyway).
* PBKDF values cannot be set (even with force parameters) below
hardcoded minimums. For PBKDF2 is it 1000 iterations, for Argon2
it is 4 iterations and 32 KiB of memory cost.
* Introduce new crypt_token_is_assigned() API function for reporting
the binding between token and keyslots.
* Allow crypt_token_json_set() API function to create internal token types.
Do not allow unknown fields in internal token objects.
* Print message in cryptsetup that about was aborted if a user did not
answer YES in a query.
Unfinished things & TODO for next releases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* There will be better documentation and examples.
* 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 deprecated in version 2.1
in favor of python bindings to the libblockdev library.

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.

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

@@ -1,5 +1,5 @@
/* base64.c -- Encode binary data using printable characters.
Copyright (C) 1999-2001, 2004-2006, 2009-2017 Free Software Foundation, Inc.
Copyright (C) 1999-2001, 2004-2006, 2009-2018 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -12,13 +12,13 @@
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, see <http://www.gnu.org/licenses/>. */
along with this program; if not, see <https://www.gnu.org/licenses/>. */
/* Written by Simon Josefsson. Partially adapted from GNU MailUtils
* (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
* from Paul Eggert, Bruno Haible, and Stepan Kasal.
*
* See also RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>.
* See also RFC 4648 <https://www.ietf.org/rfc/rfc4648.txt>.
*
* Be careful with error checking. Here is how you would typically
* use these functions:

View File

@@ -1,5 +1,5 @@
/* base64.h -- Encode binary data using printable characters.
Copyright (C) 2004-2006, 2009-2017 Free Software Foundation, Inc.
Copyright (C) 2004-2006, 2009-2018 Free Software Foundation, Inc.
Written by Simon Josefsson.
This program is free software; you can redistribute it and/or modify
@@ -13,7 +13,7 @@
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, see <http://www.gnu.org/licenses/>. */
along with this program; if not, see <https://www.gnu.org/licenses/>. */
#ifndef BASE64_H
# define BASE64_H

View File

@@ -2,8 +2,8 @@
* cryptsetup plain device helper functions
*
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2017, Milan Broz
* Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-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

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,21 +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

@@ -23,6 +23,9 @@
#include "encoding.h"
#include "core.h"
/* to silent gcc -Wcast-qual for const cast */
#define CONST_CAST(x) (x)(uintptr_t)
const char *argon2_type2string(argon2_type type, int uppercase) {
switch (type) {
case Argon2_d:
@@ -283,7 +286,7 @@ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
goto fail;
}
ctx.pwd = (uint8_t *)pwd;
ctx.pwd = CONST_CAST(uint8_t *)pwd;
ctx.pwdlen = (uint32_t)pwdlen;
ret = decode_string(&ctx, encoded, type);
@@ -346,7 +349,7 @@ int argon2_verify_ctx(argon2_context *context, const char *hash,
return ret;
}
if (argon2_compare((uint8_t *)hash, context->out, context->outlen)) {
if (argon2_compare(CONST_CAST(uint8_t *)hash, context->out, context->outlen)) {
return ARGON2_VERIFY_MISMATCH;
}

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

@@ -151,6 +151,4 @@ static BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) {
return (w >> c) | (w << (64 - c));
}
void clear_internal_memory(void *v, size_t n);
#endif

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

@@ -22,6 +22,8 @@
#include "blake2.h"
#include "blake2-impl.h"
void clear_internal_memory(void *v, size_t n);
static const uint64_t blake2b_IV[8] = {
UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b),
UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1),

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

@@ -25,7 +25,6 @@
#endif
#define VC_GE_2005(version) (version >= 1400)
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -396,11 +395,11 @@ int validate_inputs(const argon2_context *context) {
return ARGON2_PWD_PTR_MISMATCH;
}
}
#if ARGON2_MIN_PWD_LENGTH > 0 /* cryptsetup: fix gcc warning */
if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) {
return ARGON2_PWD_TOO_SHORT;
}
#endif
if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) {
return ARGON2_PWD_TOO_LONG;
}
@@ -426,9 +425,11 @@ int validate_inputs(const argon2_context *context) {
return ARGON2_SECRET_PTR_MISMATCH;
}
} else {
#if ARGON2_MIN_SECRET > 0 /* cryptsetup: fix gcc warning */
if (ARGON2_MIN_SECRET > context->secretlen) {
return ARGON2_SECRET_TOO_SHORT;
}
#endif
if (ARGON2_MAX_SECRET < context->secretlen) {
return ARGON2_SECRET_TOO_LONG;
}
@@ -440,9 +441,11 @@ int validate_inputs(const argon2_context *context) {
return ARGON2_AD_PTR_MISMATCH;
}
} else {
#if ARGON2_MIN_AD_LENGTH > 0 /* cryptsetup: fix gcc warning */
if (ARGON2_MIN_AD_LENGTH > context->adlen) {
return ARGON2_AD_TOO_SHORT;
}
#endif
if (ARGON2_MAX_AD_LENGTH < context->adlen) {
return ARGON2_AD_TOO_LONG;
}
@@ -452,11 +455,11 @@ int validate_inputs(const argon2_context *context) {
if (ARGON2_MIN_MEMORY > context->m_cost) {
return ARGON2_MEMORY_TOO_LITTLE;
}
#if 0 /* UINT32_MAX, cryptsetup: fix gcc warning */
if (ARGON2_MAX_MEMORY < context->m_cost) {
return ARGON2_MEMORY_TOO_MUCH;
}
#endif
if (context->m_cost < 8 * context->lanes) {
return ARGON2_MEMORY_TOO_LITTLE;
}

View File

@@ -30,6 +30,7 @@ enum argon2_core_constants {
ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8,
ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16,
ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32,
ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64,
/* Number of pseudo-random values generated by one call to Blake in Argon2i
to

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

@@ -46,7 +46,7 @@ typedef pthread_t argon2_thread_handle_t;
* @param func A function pointer for the thread's entry point. Must not be
* NULL.
* @param args Pointer that is passed as an argument to @func. May be NULL.
* @return 0 if @handle and @func are valid pointers and a thread is successfuly
* @return 0 if @handle and @func are valid pointers and a thread is successfully
* created.
*/
int argon2_thread_create(argon2_thread_handle_t *handle,

View File

@@ -1,8 +1,8 @@
/*
* Argon2 PBKDF2 library wrapper
*
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2017, Milan Broz
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-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

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

@@ -1,8 +1,8 @@
/*
* crypto backend implementation
*
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2017, Milan Broz
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-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
@@ -22,6 +22,7 @@
#define _CRYPTO_BACKEND_H
#include <stdint.h>
#include <stddef.h>
#include <string.h>
struct crypt_device;
@@ -43,20 +44,27 @@ int crypt_hash_size(const char *name);
int crypt_hash_init(struct crypt_hash **ctx, const char *name);
int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length);
int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length);
int crypt_hash_destroy(struct crypt_hash *ctx);
void crypt_hash_destroy(struct crypt_hash *ctx);
/* HMAC */
int crypt_hmac_size(const char *name);
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
const void *buffer, size_t length);
const void *key, size_t key_length);
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length);
int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length);
int crypt_hmac_destroy(struct crypt_hmac *ctx);
void crypt_hmac_destroy(struct crypt_hmac *ctx);
/* RNG (if fips paramater set, must provide FIPS compliance) */
/* RNG (if fips parameter set, must provide FIPS compliance) */
enum { CRYPT_RND_NORMAL = 0, CRYPT_RND_KEY = 1, CRYPT_RND_SALT = 2 };
int crypt_backend_rng(char *buffer, size_t length, int quality, int fips);
struct crypt_pbkdf_limits {
uint32_t min_iterations, max_iterations;
uint32_t min_memory, max_memory;
uint32_t min_parallel, max_parallel;
};
int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *l);
/* PBKDF*/
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
@@ -92,9 +100,10 @@ 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 *buffer, size_t length);
int crypt_cipher_destroy(struct crypt_cipher *ctx);
const char *mode, const void *key, size_t key_length);
void crypt_cipher_destroy(struct crypt_cipher *ctx);
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length);
@@ -105,8 +114,8 @@ int crypt_cipher_decrypt(struct crypt_cipher *ctx,
/* storage encryption wrappers */
int crypt_storage_init(struct crypt_storage **ctx, uint64_t sector_start,
const char *cipher, const char *cipher_mode,
char *key, size_t key_length);
int crypt_storage_destroy(struct crypt_storage *ctx);
const void *key, size_t key_length);
void crypt_storage_destroy(struct crypt_storage *ctx);
int crypt_storage_decrypt(struct crypt_storage *ctx, uint64_t sector,
size_t count, char *buffer);
int crypt_storage_encrypt(struct crypt_storage *ctx, uint64_t sector,

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel userspace API crypto backend implementation (skcipher)
*
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2017, Milan Broz
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-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
@@ -44,59 +44,15 @@ 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 *buffer, size_t length)
const char *mode, const void *key, size_t key_length)
{
struct crypt_cipher *h;
struct sockaddr_alg sa = {
@@ -124,9 +80,9 @@ int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
}
if (!strcmp(name, "cipher_null"))
length = 0;
key_length = 0;
if (setsockopt(h->tfmfd, SOL_ALG, ALG_SET_KEY, buffer, length) < 0) {
if (setsockopt(h->tfmfd, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) {
crypt_cipher_destroy(h);
return -EINVAL;
}
@@ -225,7 +181,7 @@ int crypt_cipher_decrypt(struct crypt_cipher *ctx,
iv, iv_length, ALG_OP_DECRYPT);
}
int crypt_cipher_destroy(struct crypt_cipher *ctx)
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
if (ctx->tfmfd >= 0)
close(ctx->tfmfd);
@@ -233,25 +189,18 @@ int crypt_cipher_destroy(struct crypt_cipher *ctx)
close(ctx->opfd);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
return 0;
}
#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)
{
return -ENOTSUP;
}
int crypt_cipher_destroy(struct crypt_cipher *ctx)
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
return 0;
return;
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,

View File

@@ -1,8 +1,8 @@
/*
* GCRYPT crypto backend implementation
*
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2017, Milan Broz
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-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
@@ -225,12 +225,11 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
return 0;
}
int crypt_hash_destroy(struct crypt_hash *ctx)
void crypt_hash_destroy(struct crypt_hash *ctx)
{
gcry_md_close(ctx->hd);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
return 0;
}
/* HMAC */
@@ -240,7 +239,7 @@ int crypt_hmac_size(const char *name)
}
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
const void *buffer, size_t length)
const void *key, size_t key_length)
{
struct crypt_hmac *h;
unsigned int flags = GCRY_MD_FLAG_HMAC;
@@ -262,7 +261,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
return -EINVAL;
}
if (gcry_md_setkey(h->hd, buffer, length)) {
if (gcry_md_setkey(h->hd, key, key_length)) {
gcry_md_close(h->hd);
free(h);
return -EINVAL;
@@ -301,12 +300,11 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
return 0;
}
int crypt_hmac_destroy(struct crypt_hmac *ctx)
void crypt_hmac_destroy(struct crypt_hmac *ctx)
{
gcry_md_close(ctx->hd);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
return 0;
}
/* RNG */

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel userspace API crypto backend implementation
*
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2017, Milan Broz
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-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
@@ -217,7 +217,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
return 0;
}
int crypt_hash_destroy(struct crypt_hash *ctx)
void crypt_hash_destroy(struct crypt_hash *ctx)
{
if (ctx->tfmfd >= 0)
close(ctx->tfmfd);
@@ -225,7 +225,6 @@ int crypt_hash_destroy(struct crypt_hash *ctx)
close(ctx->opfd);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
return 0;
}
/* HMAC */
@@ -235,7 +234,7 @@ int crypt_hmac_size(const char *name)
}
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
const void *buffer, size_t length)
const void *key, size_t key_length)
{
struct crypt_hmac *h;
struct hash_alg *ha;
@@ -258,7 +257,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
snprintf((char *)sa.salg_name, sizeof(sa.salg_name),
"hmac(%s)", ha->kernel_name);
if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd, buffer, length) < 0) {
if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd, key, key_length) < 0) {
free(h);
return -EINVAL;
}
@@ -292,7 +291,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
return 0;
}
int crypt_hmac_destroy(struct crypt_hmac *ctx)
void crypt_hmac_destroy(struct crypt_hmac *ctx)
{
if (ctx->tfmfd >= 0)
close(ctx->tfmfd);
@@ -300,7 +299,6 @@ int crypt_hmac_destroy(struct crypt_hmac *ctx)
close(ctx->opfd);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
return 0;
}
/* RNG - N/A */

View File

@@ -1,8 +1,8 @@
/*
* Nettle crypto backend implementation
*
* Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2017, Milan Broz
* Copyright (C) 2011-2018 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-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
@@ -202,11 +202,10 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
return 0;
}
int crypt_hash_destroy(struct crypt_hash *ctx)
void crypt_hash_destroy(struct crypt_hash *ctx)
{
memset(ctx, 0, sizeof(*ctx));
free(ctx);
return 0;
}
/* HMAC */
@@ -216,7 +215,7 @@ int crypt_hmac_size(const char *name)
}
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
const void *buffer, size_t length)
const void *key, size_t key_length)
{
struct crypt_hmac *h;
@@ -230,12 +229,12 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
if (!h->hash)
goto bad;
h->key = malloc(length);
h->key = malloc(key_length);
if (!h->key)
goto bad;
memcpy(h->key, buffer, length);
h->key_length = length;
memcpy(h->key, key, key_length);
h->key_length = key_length;
h->hash->init(&h->nettle_ctx);
h->hash->hmac_set_key(&h->nettle_ctx, h->key_length, h->key);
@@ -268,13 +267,12 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
return 0;
}
int crypt_hmac_destroy(struct crypt_hmac *ctx)
void crypt_hmac_destroy(struct crypt_hmac *ctx)
{
memset(ctx->key, 0, ctx->key_length);
free(ctx->key);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
return 0;
}
/* RNG - N/A */

View File

@@ -1,8 +1,8 @@
/*
* NSS crypto backend implementation
*
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2017, Milan Broz
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-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
@@ -180,12 +180,11 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
return 0;
}
int crypt_hash_destroy(struct crypt_hash *ctx)
void crypt_hash_destroy(struct crypt_hash *ctx)
{
PK11_DestroyContext(ctx->md, PR_TRUE);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
return 0;
}
/* HMAC */
@@ -195,15 +194,15 @@ int crypt_hmac_size(const char *name)
}
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
const void *buffer, size_t length)
const void *key, size_t key_length)
{
struct crypt_hmac *h;
SECItem keyItem;
SECItem noParams;
keyItem.type = siBuffer;
keyItem.data = CONST_CAST(unsigned char *)buffer;
keyItem.len = (int)length;
keyItem.data = CONST_CAST(unsigned char *)key;
keyItem.len = (int)key_length;
noParams.type = siBuffer;
noParams.data = 0;
@@ -282,7 +281,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
return 0;
}
int crypt_hmac_destroy(struct crypt_hmac *ctx)
void crypt_hmac_destroy(struct crypt_hmac *ctx)
{
if (ctx->key)
PK11_FreeSymKey(ctx->key);
@@ -292,7 +291,6 @@ int crypt_hmac_destroy(struct crypt_hmac *ctx)
PK11_DestroyContext(ctx->md, PR_TRUE);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
return 0;
}
/* RNG */

View File

@@ -1,8 +1,8 @@
/*
* OPENSSL crypto backend implementation
*
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2017, Milan Broz
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-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
@@ -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();
@@ -213,12 +215,11 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
return 0;
}
int crypt_hash_destroy(struct crypt_hash *ctx)
void crypt_hash_destroy(struct crypt_hash *ctx)
{
EVP_MD_CTX_free(ctx->md);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
return 0;
}
/* HMAC */
@@ -228,7 +229,7 @@ int crypt_hmac_size(const char *name)
}
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
const void *buffer, size_t length)
const void *key, size_t key_length)
{
struct crypt_hmac *h;
@@ -249,7 +250,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
return -EINVAL;
}
HMAC_Init_ex(h->md, buffer, length, h->hash_id, NULL);
HMAC_Init_ex(h->md, key, key_length, h->hash_id, NULL);
h->hash_len = EVP_MD_size(h->hash_id);
*ctx = h;
@@ -288,12 +289,11 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
return 0;
}
int crypt_hmac_destroy(struct crypt_hmac *ctx)
void crypt_hmac_destroy(struct crypt_hmac *ctx)
{
HMAC_CTX_free(ctx->md);
memset(ctx, 0, sizeof(*ctx));
free(ctx);
return 0;
}
/* RNG */

View File

@@ -2,7 +2,7 @@
* Generic wrapper for storage encryption modes and Initial Vectors
* (reimplementation of some functions from Linux dm-crypt kernel)
*
* Copyright (C) 2014-2017, Milan Broz
* Copyright (C) 2014-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
@@ -56,7 +56,7 @@ static int int_log2(unsigned int x)
static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
const char *cipher_name, const char *mode_name,
const char *iv_name, char *key, size_t key_length)
const char *iv_name, const void *key, size_t key_length)
{
memset(ctx, 0, sizeof(*ctx));
@@ -64,12 +64,15 @@ static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
if (ctx->iv_size < 8)
return -ENOENT;
if (!iv_name ||
!strcmp(cipher_name, "cipher_null") ||
if (!strcmp(cipher_name, "cipher_null") ||
!strcmp(mode_name, "ecb")) {
if (iv_name)
return -EINVAL;
ctx->type = IV_NONE;
ctx->iv_size = 0;
return 0;
} else if (!iv_name) {
return -EINVAL;
} else if (!strcasecmp(iv_name, "null")) {
ctx->type = IV_NULL;
} else if (!strcasecmp(iv_name, "plain64")) {
@@ -175,7 +178,7 @@ static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector
return 0;
}
static int crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
static void crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
{
if (ctx->type == IV_ESSIV)
crypt_cipher_destroy(ctx->essiv_cipher);
@@ -186,7 +189,6 @@ static int crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
}
memset(ctx, 0, sizeof(*ctx));
return 0;
}
/* Block encryption storage wrappers */
@@ -195,7 +197,7 @@ int crypt_storage_init(struct crypt_storage **ctx,
uint64_t sector_start,
const char *cipher,
const char *cipher_mode,
char *key, size_t key_length)
const void *key, size_t key_length)
{
struct crypt_storage *s;
char mode_name[64];
@@ -282,10 +284,10 @@ int crypt_storage_encrypt(struct crypt_storage *ctx,
return r;
}
int crypt_storage_destroy(struct crypt_storage *ctx)
void crypt_storage_destroy(struct crypt_storage *ctx)
{
if (!ctx)
return 0;
return;
crypt_sector_iv_destroy(&ctx->cipher_iv);
@@ -294,6 +296,4 @@ int crypt_storage_destroy(struct crypt_storage *ctx)
memset(ctx, 0, sizeof(*ctx));
free(ctx);
return 0;
}

View File

@@ -4,8 +4,8 @@
* Copyright (C) 2004 Free Software Foundation
*
* cryptsetup related changes
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2017, Milan Broz
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-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

View File

@@ -1,8 +1,8 @@
/*
* PBKDF performance check
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2017, Milan Broz
* Copyright (C) 2016-2017, Ondrej Mosnacek
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2018, Milan Broz
* Copyright (C) 2016-2018, Ondrej Mosnacek
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -34,6 +34,33 @@
#define BENCH_SAMPLES_FAST 3
#define BENCH_SAMPLES_SLOW 1
/* These PBKDF2 limits must be never violated */
int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *limits)
{
if (!kdf || !limits)
return -EINVAL;
if (!strcmp(kdf, "pbkdf2")) {
limits->min_iterations = 1000; /* recommendation in NIST SP 800-132 */
limits->max_iterations = UINT32_MAX;
limits->min_memory = 0; /* N/A */
limits->max_memory = 0; /* N/A */
limits->min_parallel = 0; /* N/A */
limits->max_parallel = 0; /* N/A */
return 0;
} else if (!strncmp(kdf, "argon2", 6)) {
limits->min_iterations = 4;
limits->max_iterations = UINT32_MAX;
limits->min_memory = 32;
limits->max_memory = 4*1024*1024; /* 4GiB */
limits->min_parallel = 1;
limits->max_parallel = 4;
return 0;
}
return -EINVAL;
}
static long time_ms(struct rusage *start, struct rusage *end)
{
int count_kernel_time = 0;
@@ -362,8 +389,6 @@ out:
return r;
}
#define ARGON2_MIN_T_COST 4
int crypt_pbkdf_perf(const char *kdf, const char *hash,
const char *password, size_t password_size,
const char *salt, size_t salt_size,
@@ -372,11 +397,16 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
uint32_t *iterations_out, uint32_t *memory_out,
int (*progress)(uint32_t time_ms, void *usrptr), void *usrptr)
{
struct crypt_pbkdf_limits pbkdf_limits;
int r = -EINVAL;
if (!kdf || !iterations_out || !memory_out)
return -EINVAL;
r = crypt_pbkdf_get_limits(kdf, &pbkdf_limits);
if (r < 0)
return r;
*memory_out = 0;
*iterations_out = 0;
@@ -388,7 +418,7 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
else if (!strncmp(kdf, "argon2", 6))
r = crypt_argon2_check(kdf, password, password_size,
salt, salt_size, volume_key_size,
ARGON2_MIN_T_COST, max_memory_kb,
pbkdf_limits.min_iterations, max_memory_kb,
parallel_threads, time_ms, iterations_out,
memory_out, progress, usrptr);
return r;

View File

@@ -1,7 +1,7 @@
/*
* Integrity volume handling
*
* Copyright (C) 2016-2017, Milan Broz
* Copyright (C) 2016-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
@@ -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)"))
@@ -130,6 +138,7 @@ int INTEGRITY_key_size(struct crypt_device *cd)
int INTEGRITY_tag_size(struct crypt_device *cd,
const char *integrity,
const char *cipher,
const char *cipher_mode)
{
int iv_tag_size = 0, auth_tag_size = 0;
@@ -144,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;
@@ -154,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)"))
@@ -217,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;
}
@@ -268,13 +281,19 @@ 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)
return r;
/* There is no data area, we can actually use fake zeroed key */
if (params && params->integrity_key_size)
dmdi.u.integrity.vk = crypt_alloc_volume_key(params->integrity_key_size, NULL);
r = dm_create_device(cd, tmp_name, "INTEGRITY", &dmdi, 0);
crypt_free_volume_key(dmdi.u.integrity.vk);
if (r)
return r;

View File

@@ -1,7 +1,7 @@
/*
* Integrity header defitinion
*
* Copyright (C) 2016-2017, Milan Broz
* Copyright (C) 2016-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
@@ -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,9 +56,11 @@ 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,
const char *cipher_mode);
int INTEGRITY_format(struct crypt_device *cd,

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2017, Milan Broz
* 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
@@ -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"
@@ -49,15 +51,13 @@
#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 MAX_PBKDF_THREADS 4
#define MAX_PBKDF_MEMORY 1024*1024 /* 1GiB */
#define MIN_PBKDF2_ITERATIONS 1000 /* recommendation in NIST SP 800-132 */
#define LOG_MAX_LEN 4096
#define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); })
#define CRYPT_DEFAULT_SEGMENT 0
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
struct crypt_device;
@@ -70,8 +70,7 @@ struct volume_key {
struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key);
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength);
void crypt_free_volume_key(struct volume_key *vk);
void crypt_volume_key_set_description(struct volume_key *key, const char *key_description);
const char *crypt_volume_key_get_description(const struct volume_key *key);
int crypt_volume_key_set_description(struct volume_key *key, const char *key_description);
struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd);
int init_pbkdf_type(struct crypt_device *cd,
@@ -139,21 +138,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);
const char *uint64_to_str(char *buffer, size_t size, const uint64_t *val);
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)
@@ -199,5 +190,15 @@ int crypt_get_integrity_tag_size(struct crypt_device *cd);
int crypt_key_in_keyring(struct crypt_device *cd);
void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring);
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk);
int crypt_use_keyring_for_vk(const struct crypt_device *cd);
void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description);
static inline uint64_t version(uint16_t major, uint16_t minor, uint16_t patch, uint16_t release)
{
return (uint64_t)release | ((uint64_t)patch << 16) | ((uint64_t)minor << 32) | ((uint64_t)major << 48);
}
int kernel_version(uint64_t *kversion);
#endif /* INTERNAL_H */

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2017, Milan Broz
* 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
@@ -48,7 +48,7 @@ extern "C" {
struct crypt_device; /* crypt device handle */
/**
* Initialize crypt device handle and check if provided device exists.
* Initialize crypt device handle and check if the provided device exists.
*
* @param cd Returns pointer to crypt device handle
* @param device Path to the backing device.
@@ -59,7 +59,7 @@ struct crypt_device; /* crypt device handle */
*
* @return @e 0 on success or negative errno value otherwise.
*
* @note Note that logging is not initialized here, possible messages uses
* @note Note that logging is not initialized here, possible messages use
* default log function.
*/
int crypt_init(struct crypt_device **cd, const char *device);
@@ -116,7 +116,8 @@ void crypt_free(struct crypt_device *cd);
* @param usrptr provided identification in callback
* @param msg Message for user to confirm
*
* @note Current version of cryptsetup API requires confirmation only when UUID is being changed
* @note Current version of cryptsetup API requires confirmation for UUID change and
* LUKS header restore only.
*/
void crypt_set_confirm_callback(struct crypt_device *cd,
int (*confirm)(const char *msg, void *usrptr),
@@ -239,14 +240,25 @@ struct crypt_pbkdf_type {
*
* @return 0 on success or negative errno value otherwise.
*
* @note For LUKS1, only PBKDF2 is suppported, other settings will be rejected.
* @note For LUKS1, only PBKDF2 is supported, other settings will be rejected.
* @note For non-LUKS context types the call succeeds, but PBKDF is not used.
*/
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
@@ -509,9 +521,9 @@ struct crypt_params_luks2 {
*
* @returns @e 0 on success or negative errno value otherwise.
*
* @note Note that crypt_format does not enable any keyslot (in case of work with LUKS device),
* but it stores volume key internally and subsequent crypt_keyslot_add_* calls can be used.
* @note For VERITY @link crypt-type @endlink, only uuid parameter is used, others paramaters
* @note Note that crypt_format does not create LUKS keyslot (any version). To create keyslot
* call any crypt_keyslot_add_* function.
* @note For VERITY @link crypt-type @endlink, only uuid parameter is used, other parameters
* are ignored and verity specific attributes are set through mandatory params option.
*/
int crypt_format(struct crypt_device *cd,
@@ -532,7 +544,14 @@ int crypt_format(struct crypt_device *cd,
*
* @returns 0 on success or negative errno value otherwise.
*
* @note Currently, only LUKS1->LUKS2 conversion is supported
* @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
* 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
* devices.
*/
int crypt_convert(struct crypt_device *cd,
const char *type,
@@ -567,10 +586,11 @@ int crypt_set_label(struct crypt_device *cd,
const char *subsystem);
/**
* Set or unset loading of volume keys via kernel keyring. When set to 'enabled'
* library loads key in kernel keyring first and pass the key description to
* dm-crypt instead of binary key copy. If set to 'disabled' library fall backs
* to classical method loading volume key directly in dm-crypt target.
* Enable or disable loading of volume keys via kernel keyring. When set to
* 'enabled' library loads key in kernel keyring first and pass the key
* description to dm-crypt instead of binary key copy. If set to 'disabled'
* library fallbacks to old method of loading volume key directly in
* dm-crypt target.
*
* @param cd crypt device handle, can be @e NULL
* @param enable 0 to disable loading of volume keys via kernel keyring
@@ -604,7 +624,7 @@ int crypt_load(struct crypt_device *cd,
void *params);
/**
* Try to repair crypt device 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
@@ -612,6 +632,11 @@ int crypt_load(struct crypt_device *cd,
*
* @returns 0 on success or negative errno value otherwise.
*
* @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,
@@ -627,10 +652,12 @@ int crypt_repair(struct crypt_device *cd,
* @return @e 0 on success or negative errno value otherwise.
*
* @note Most notably it returns -EPERM when device was activated with volume key
* in kernel keyring and current device handle doesn't have verified key
* in kernel keyring in the same time. Perform any crypt_activate_*()
* operation with device name set to NULL to load verified volume key in
* the keyring.
* in kernel keyring and current device handle (context) doesn't have verified key
* loaded in kernel. To load volume key for already active device use any of
* @link crypt_activate_by_passphrase @endlink, @link crypt_activate_by_keyfile @endlink,
* @link crypt_activate_by_keyfile_offset @endlink, @link crypt_activate_by_volume_key @endlink,
* @link crypt_activate_by_keyring @endlink or @link crypt_activate_by_token @endlink with flag
* @e CRYPT_ACTIVATE_KEYRING_KEY raised and @e name parameter set to @e NULL.
*/
int crypt_resize(struct crypt_device *cd,
const char *name,
@@ -657,7 +684,7 @@ int crypt_suspend(struct crypt_device *cd,
* @param cd crypt device handle
* @param name name of device to resume
* @param keyslot requested keyslot or CRYPT_ANY_SLOT
* @param passphrase passphrase used to unlock volume key, @e NULL for query
* @param passphrase passphrase used to unlock volume key
* @param passphrase_size size of @e passphrase (binary data)
*
* @return unlocked key slot number or negative errno otherwise.
@@ -676,20 +703,31 @@ int crypt_resume_by_passphrase(struct crypt_device *cd,
* @param cd crypt device handle
* @param name name of device to resume
* @param keyslot requested keyslot or CRYPT_ANY_SLOT
* @param keyfile key file used to unlock volume key, @e NULL for passphrase query
* @param keyfile key file used to unlock volume key
* @param keyfile_size number of bytes to read from keyfile, 0 is unlimited
* @param keyfile_offset number of bytes to skip at start of keyfile
*
* @return unlocked key slot number or negative errno otherwise.
*/
int crypt_resume_by_keyfile_device_offset(struct crypt_device *cd,
const char *name,
int keyslot,
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset);
/**
* Backward compatible crypt_resume_by_keyfile_device_offset() (with size_t offset).
*/
int crypt_resume_by_keyfile_offset(struct crypt_device *cd,
const char *name,
int keyslot,
const char *keyfile,
size_t keyfile_size,
size_t keyfile_offset);
/**
* Backward compatible crypt_resume_by_keyfile_offset() (without offset).
* Backward compatible crypt_resume_by_keyfile_device_offset() (without offset).
*/
int crypt_resume_by_keyfile(struct crypt_device *cd,
const char *name,
@@ -714,9 +752,9 @@ int crypt_resume_by_keyfile(struct crypt_device *cd,
*
* @param cd crypt device handle
* @param keyslot requested keyslot or @e CRYPT_ANY_SLOT
* @param passphrase passphrase used to unlock volume key, @e NULL for query
* @param passphrase passphrase used to unlock volume key
* @param passphrase_size size of passphrase (binary data)
* @param new_passphrase passphrase for new keyslot, @e NULL for query
* @param new_passphrase passphrase for new keyslot
* @param new_passphrase_size size of @e new_passphrase (binary data)
*
* @return allocated key slot number or negative errno otherwise.
@@ -736,9 +774,9 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
* @param cd crypt device handle
* @param keyslot_old old keyslot or @e CRYPT_ANY_SLOT
* @param keyslot_new new keyslot (can be the same as old)
* @param passphrase passphrase used to unlock volume key, @e NULL for query
* @param passphrase passphrase used to unlock volume key
* @param passphrase_size size of passphrase (binary data)
* @param new_passphrase passphrase for new keyslot, @e NULL for query
* @param new_passphrase passphrase for new keyslot
* @param new_passphrase_size size of @e new_passphrase (binary data)
*
* @return allocated key slot number or negative errno otherwise.
@@ -762,15 +800,27 @@ int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
*
* @param cd crypt device handle
* @param keyslot requested keyslot or @e CRYPT_ANY_SLOT
* @param keyfile key file used to unlock volume key, @e NULL for passphrase query
* @param keyfile key file used to unlock volume key
* @param keyfile_size number of bytes to read from keyfile, @e 0 is unlimited
* @param keyfile_offset number of bytes to skip at start of keyfile
* @param new_keyfile keyfile for new keyslot, @e NULL for passphrase query
* @param new_keyfile keyfile for new keyslot
* @param new_keyfile_size number of bytes to read from @e new_keyfile, @e 0 is unlimited
* @param new_keyfile_offset number of bytes to skip at start of new_keyfile
*
* @return allocated key slot number or negative errno otherwise.
*/
int crypt_keyslot_add_by_keyfile_device_offset(struct crypt_device *cd,
int keyslot,
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset,
const char *new_keyfile,
size_t new_keyfile_size,
uint64_t new_keyfile_offset);
/**
* Backward compatible crypt_keyslot_add_by_keyfile_device_offset() (with size_t offset).
*/
int crypt_keyslot_add_by_keyfile_offset(struct crypt_device *cd,
int keyslot,
const char *keyfile,
@@ -779,8 +829,9 @@ int crypt_keyslot_add_by_keyfile_offset(struct crypt_device *cd,
const char *new_keyfile,
size_t new_keyfile_size,
size_t new_keyfile_offset);
/**
* Backward compatible crypt_keyslot_add_by_keyfile_offset() (without offset).
* Backward compatible crypt_keyslot_add_by_keyfile_device_offset() (without offset).
*/
int crypt_keyslot_add_by_keyfile(struct crypt_device *cd,
int keyslot,
@@ -798,7 +849,7 @@ int crypt_keyslot_add_by_keyfile(struct crypt_device *cd,
* @param keyslot requested keyslot or CRYPT_ANY_SLOT
* @param volume_key provided volume key or @e NULL if used after crypt_format
* @param volume_key_size size of volume_key
* @param passphrase passphrase for new keyslot, @e NULL for query
* @param passphrase passphrase for new keyslot
* @param passphrase_size size of passphrase
*
* @return allocated key slot number or negative errno otherwise.
@@ -813,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.
*
@@ -822,17 +876,25 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
* @param keyslot requested keyslot or CRYPT_ANY_SLOT
* @param volume_key provided volume key or @e NULL (see note below)
* @param volume_key_size size of volume_key
* @param passphrase passphrase for new keyslot, @e NULL for query
* @param passphrase passphrase for new keyslot
* @param passphrase_size size of passphrase
* @param flags key flags to set
*
* @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,
@@ -894,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 (kesylots without segments) */
#define CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY (1 << 16)
/**
* Active device runtime attributes
@@ -916,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);
/** @} */
/**
@@ -958,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,
@@ -990,7 +1068,7 @@ int crypt_persistent_flags_get(struct crypt_device *cd,
* @param cd crypt device handle
* @param name name of device to create, if @e NULL only check passphrase
* @param keyslot requested keyslot to check or @e CRYPT_ANY_SLOT
* @param passphrase passphrase used to unlock volume key, @e NULL for query
* @param passphrase passphrase used to unlock volume key
* @param passphrase_size size of @e passphrase
* @param flags activation flags
*
@@ -1016,6 +1094,17 @@ int crypt_activate_by_passphrase(struct crypt_device *cd,
*
* @return unlocked key slot number or negative errno otherwise.
*/
int crypt_activate_by_keyfile_device_offset(struct crypt_device *cd,
const char *name,
int keyslot,
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset,
uint32_t flags);
/**
* Backward compatible crypt_activate_by_keyfile_device_offset() (with size_t offset).
*/
int crypt_activate_by_keyfile_offset(struct crypt_device *cd,
const char *name,
int keyslot,
@@ -1023,8 +1112,9 @@ int crypt_activate_by_keyfile_offset(struct crypt_device *cd,
size_t keyfile_size,
size_t keyfile_offset,
uint32_t flags);
/**
* Backward compatible crypt_activate_by_keyfile_offset() (without offset).
* Backward compatible crypt_activate_by_keyfile_device_offset() (without offset).
*/
int crypt_activate_by_keyfile(struct crypt_device *cd,
const char *name,
@@ -1036,7 +1126,6 @@ int crypt_activate_by_keyfile(struct crypt_device *cd,
/**
* Activate device using provided volume key.
*
*
* @param cd crypt device handle
* @param name name of device to create, if @e NULL only check volume key
* @param volume_key provided volume key (or @e NULL to use internal)
@@ -1063,7 +1152,6 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
/**
* Activate device using passphrase stored in kernel keyring.
*
*
* @param cd crypt device handle
* @param name name of device to create, if @e NULL only check passphrase in keyring
* @param key_description kernel keyring key description library should look
@@ -1129,7 +1217,7 @@ int crypt_deactivate(struct crypt_device *cd, const char *name);
*
* @return unlocked key slot number or negative errno otherwise.
*
* @note For TCRYPT cipher chain is the volume key concatenated
* @note For TCRYPT cipher chain is the volume key concatenated
* for all ciphers in chain.
*/
int crypt_volume_key_get(struct crypt_device *cd,
@@ -1365,14 +1453,15 @@ 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;
/**
* Get information about particular key slot.
*
*
* @param cd crypt device handle
* @param keyslot requested keyslot to check or CRYPT_ANY_SLOT
*
@@ -1438,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
*
@@ -1469,7 +1570,6 @@ int crypt_header_backup(struct crypt_device *cd,
/**
* Restore header and keyslots from backup file.
*
*
* @param cd crypt device handle
* @param requested_type @link crypt-type @endlink or @e NULL for all known
* @param backup_file file to restore header from
@@ -1512,15 +1612,37 @@ void crypt_set_debug_level(int level);
/**
* Read keyfile
*
* @param cd crypt device handle
* @param keyfile keyfile to read
* @param key buffer for key
* @param key_size_read size of read key
* @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 key_size,
uint32_t flags);
/**
* Backward compatible crypt_keyfile_device_read() (with size_t offset).
*/
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,
uint32_t flags
);
/** No on-disk header (only hashes) */
size_t key_size,
uint32_t flags);
/** Read key only to the first end of line (\\n). */
#define CRYPT_KEYFILE_STOP_EOL (1 << 0)
/** @} */
@@ -1580,13 +1702,13 @@ int crypt_wipe(struct crypt_device *cd,
* Utilities for handling tokens LUKS2
* Token is a device or a method how to read password for particular keyslot
* automatically. It can be chunk of data stored on hardware token or
* just a metadata how to generate password.
* just a metadata how to generate the password.
*
* @addtogroup crypt-tokens
* @{
*/
/** iterate through all tokens */
/** Iterate through all tokens */
#define CRYPT_ANY_TOKEN -1
/**
@@ -1612,7 +1734,7 @@ int crypt_token_json_get(struct crypt_device *cd,
* @return allocated token id or negative errno otherwise.
*
* @note The buffer must be in proper JSON format and must contain at least
* string "type" with slot type and array of string names "keyslots".
* string "type" with slot type and an array of string names "keyslots".
* Keyslots array contains assignments to particular slots and can be empty.
*/
int crypt_token_json_set(struct crypt_device *cd,
@@ -1648,7 +1770,7 @@ typedef enum {
crypt_token_info crypt_token_status(struct crypt_device *cd, int token, const char **type);
/**
* LUKS2 keyring token paramaters.
* LUKS2 keyring token parameters.
*
* @see crypt_token_builtin_set
*
@@ -1717,9 +1839,24 @@ int crypt_token_unassign_keyslot(struct crypt_device *cd,
int token,
int keyslot);
/**
* Get info about token assignment to particular keyslot.
*
* @param cd crypt device handle
* @param token token id
* @param keyslot keyslot
*
* @return 0 on success (token exists and is assigned to the keyslot),
* -ENOENT if token is not assigned to a keyslot (token, keyslot
* or both may be inactive) or other negative errno otherwise.
*/
int crypt_token_is_assigned(struct crypt_device *cd,
int token,
int keyslot);
/**
* Token handler open function prototype.
* This fuction retrieves password from a token and return allocated buffer
* This function retrieves password from a token and return allocated buffer
* containing this password. This buffer has to be deallocated by calling
* free() function and content should be wiped before deallocation.
*
@@ -1749,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
@@ -1762,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

@@ -22,12 +22,14 @@ CRYPTSETUP_2.0 {
crypt_resume_by_passphrase;
crypt_resume_by_keyfile;
crypt_resume_by_keyfile_offset;
crypt_resume_by_keyfile_device_offset;
crypt_free;
crypt_keyslot_add_by_passphrase;
crypt_keyslot_change_by_passphrase;
crypt_keyslot_add_by_keyfile;
crypt_keyslot_add_by_keyfile_offset;
crypt_keyslot_add_by_keyfile_device_offset;
crypt_keyslot_add_by_volume_key;
crypt_keyslot_add_by_key;
@@ -41,6 +43,7 @@ CRYPTSETUP_2.0 {
crypt_token_luks2_keyring_set;
crypt_token_assign_keyslot;
crypt_token_unassign_keyslot;
crypt_token_is_assigned;
crypt_token_register;
crypt_activate_by_token;
@@ -49,6 +52,7 @@ CRYPTSETUP_2.0 {
crypt_activate_by_passphrase;
crypt_activate_by_keyfile;
crypt_activate_by_keyfile_offset;
crypt_activate_by_keyfile_device_offset;
crypt_activate_by_volume_key;
crypt_activate_by_keyring;
crypt_deactivate;
@@ -73,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;
@@ -80,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;
@@ -92,6 +99,7 @@ CRYPTSETUP_2.0 {
crypt_header_restore;
crypt_keyfile_read;
crypt_keyfile_device_read;
crypt_wipe;
local:

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2017, Milan Broz
* 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
@@ -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))
@@ -109,13 +108,16 @@ static void set_dm_error(int level,
static int _dm_simple(int task, const char *name, int udev_wait);
static int _dm_satisfies_version(unsigned target_maj, unsigned target_min,
unsigned actual_maj, unsigned actual_min)
static int _dm_satisfies_version(unsigned target_maj, unsigned target_min, unsigned target_patch,
unsigned actual_maj, unsigned actual_min, unsigned actual_patch)
{
if (actual_maj > target_maj)
return 1;
if (actual_maj == target_maj && actual_min >= target_min)
if (actual_maj == target_maj && actual_min > target_min)
return 1;
if (actual_maj == target_maj && actual_min == target_min && actual_patch >= target_patch)
return 1;
return 0;
@@ -131,33 +133,33 @@ static void _dm_set_crypt_compat(unsigned crypt_maj,
log_dbg("Detected dm-crypt version %i.%i.%i.",
crypt_maj, crypt_min, crypt_patch);
if (_dm_satisfies_version(1, 2, crypt_maj, crypt_min))
if (_dm_satisfies_version(1, 2, 0, crypt_maj, crypt_min, crypt_patch))
_dm_flags |= DM_KEY_WIPE_SUPPORTED;
else
log_dbg("Suspend and resume disabled, no wipe key support.");
if (_dm_satisfies_version(1, 10, crypt_maj, crypt_min))
if (_dm_satisfies_version(1, 10, 0, crypt_maj, crypt_min, crypt_patch))
_dm_flags |= DM_LMK_SUPPORTED;
/* not perfect, 2.6.33 supports with 1.7.0 */
if (_dm_satisfies_version(1, 8, crypt_maj, crypt_min))
if (_dm_satisfies_version(1, 8, 0, crypt_maj, crypt_min, crypt_patch))
_dm_flags |= DM_PLAIN64_SUPPORTED;
if (_dm_satisfies_version(1, 11, crypt_maj, crypt_min))
if (_dm_satisfies_version(1, 11, 0, crypt_maj, crypt_min, crypt_patch))
_dm_flags |= DM_DISCARDS_SUPPORTED;
if (_dm_satisfies_version(1, 13, crypt_maj, crypt_min))
if (_dm_satisfies_version(1, 13, 0, crypt_maj, crypt_min, crypt_patch))
_dm_flags |= DM_TCW_SUPPORTED;
if (_dm_satisfies_version(1, 14, crypt_maj, crypt_min)) {
if (_dm_satisfies_version(1, 14, 0, crypt_maj, crypt_min, crypt_patch)) {
_dm_flags |= DM_SAME_CPU_CRYPT_SUPPORTED;
_dm_flags |= DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED;
}
if (_dm_satisfies_version(1, 15, crypt_maj, crypt_min))
if (_dm_satisfies_version(1, 18, 1, crypt_maj, crypt_min, crypt_patch))
_dm_flags |= DM_KERNEL_KEYRING_SUPPORTED;
if (_dm_satisfies_version(1, 17, crypt_maj, crypt_min)) {
if (_dm_satisfies_version(1, 17, 0, crypt_maj, crypt_min, crypt_patch)) {
_dm_flags |= DM_SECTOR_SIZE_SUPPORTED;
_dm_flags |= DM_CAPI_STRING_SUPPORTED;
}
@@ -182,8 +184,9 @@ 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, verity_maj, verity_min)) {
if (_dm_satisfies_version(1, 3, 0, verity_maj, verity_min, verity_patch)) {
_dm_flags |= DM_VERITY_ON_CORRUPTION_SUPPORTED;
_dm_flags |= DM_VERITY_FEC_SUPPORTED;
}
@@ -238,10 +241,10 @@ static int _dm_check_versions(dm_target_type target_type)
goto out;
log_dbg("Detected dm-ioctl version %u.%u.%u.", dm_maj, dm_min, dm_patch);
if (_dm_satisfies_version(4, 20, dm_maj, dm_min))
if (_dm_satisfies_version(4, 20, 0, dm_maj, dm_min, dm_patch))
_dm_flags |= DM_SECURE_SUPPORTED;
#if HAVE_DECL_DM_TASK_DEFERRED_REMOVE
if (_dm_satisfies_version(4, 27, dm_maj, dm_min))
if (_dm_satisfies_version(4, 27, 0, dm_maj, dm_min, dm_patch))
_dm_flags |= DM_DEFERRED_SUPPORTED;
#endif
}
@@ -326,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;
}
@@ -454,7 +457,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], capi[CAPIL];
char tmp[CAPIL*2], capi[CAPIL];
size_t len;
int i;
@@ -520,7 +523,7 @@ static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd, uint32_t fl
{
int r, max_size, null_cipher = 0, num_options = 0, keystr_len = 0;
char *params, *hexkey;
char sector_feature[32], features[256], integrity_dm[256], cipher_dm[256];
char sector_feature[32], features[512], integrity_dm[256], cipher_dm[256];
if (!dmd)
return NULL;
@@ -619,6 +622,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;
@@ -630,10 +635,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';
@@ -929,7 +935,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;
}
@@ -994,7 +1000,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;
}
@@ -1155,11 +1161,19 @@ static int check_retry(uint32_t *dmd_flags, uint32_t dmt_flags)
/* If kernel keyring is not supported load key directly in dm-crypt */
if ((*dmd_flags & CRYPT_ACTIVATE_KEYRING_KEY) &&
!(dmt_flags & DM_KERNEL_KEYRING_SUPPORTED)) {
log_dbg("dm-crypt doesn't suport kernel keyring");
log_dbg("dm-crypt doesn't support kernel keyring");
*dmd_flags = *dmd_flags & ~CRYPT_ACTIVATE_KEYRING_KEY;
ret = 1;
}
/* Drop performance options if not supported */
if ((*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_dbg("dm-crypt doesn't support performance options");
*dmd_flags = *dmd_flags & ~(CRYPT_ACTIVATE_SAME_CPU_CRYPT | CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS);
ret = 1;
}
return ret;
}
@@ -1206,23 +1220,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);
@@ -1288,7 +1303,7 @@ int dm_status_device(struct crypt_device *cd, const char *name)
struct stat st;
/* libdevmapper is too clever and handles
* path argument differenly with error.
* path argument differently with error.
* Fail early here if parameter is non-existent path.
*/
if (strchr(name, '/') && stat(name, &st) < 0)
@@ -1349,6 +1364,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,
@@ -1479,11 +1517,16 @@ static int _dm_query_crypt(uint32_t get_flags,
if (get_flags & DM_ACTIVE_CRYPT_KEY) {
if (key_[0] == ':') {
key_desc = strdup(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';
@@ -1673,6 +1716,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);
@@ -1683,9 +1728,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")) {
@@ -2026,6 +2072,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;

View File

@@ -1,8 +1,8 @@
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2017, Milan Broz
* Copyright (C) 2011-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-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
@@ -87,12 +87,12 @@ 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;
}
*vk = crypt_alloc_volume_key(key_len_output * keys_count, NULL);
*vk = crypt_alloc_volume_key((size_t)key_len_output * keys_count, NULL);
if (!*vk)
return -ENOMEM;
@@ -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

@@ -1,8 +1,8 @@
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2017, Milan Broz
* Copyright (C) 2011-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-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
@@ -22,6 +22,7 @@
#ifndef _LOOPAES_H
#define _LOOPAES_H
#include <stdint.h>
#include <unistd.h>
struct crypt_device;

View File

@@ -2,10 +2,10 @@
* AFsplitter - Anti forensic information splitter
*
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* 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

@@ -2,10 +2,10 @@
* AFsplitter - Anti forensic information splitter
*
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* 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

@@ -2,8 +2,8 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2017, Milan Broz
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-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
@@ -21,6 +21,7 @@
*/
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include "luks.h"
@@ -30,17 +31,19 @@
static void _error_hint(struct crypt_device *ctx, const char *device,
const char *cipher, const char *mode, size_t keyLength)
{
char cipher_spec[MAX_CIPHER_LEN * 3];
char *c, cipher_spec[MAX_CIPHER_LEN * 3];
if (snprintf(cipher_spec, sizeof(cipher_spec), "%s-%s", cipher, mode) < 0)
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."));
}
static int LUKS_endec_template(char *src, size_t srcLength,
@@ -67,7 +70,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
}
};
int r, devfd = -1;
size_t bsize, alignment;
size_t bsize, keyslot_alignment, alignment;
log_dbg("Using dmcrypt to access keyslot area.");
@@ -76,7 +79,11 @@ static int LUKS_endec_template(char *src, size_t srcLength,
if (!bsize || !alignment)
return -EINVAL;
dmd.size = size_round_up(srcLength, bsize) / SECTOR_SIZE;
if (bsize > LUKS_ALIGN_KEYSLOTS)
keyslot_alignment = LUKS_ALIGN_KEYSLOTS;
else
keyslot_alignment = bsize;
dmd.size = size_round_up(srcLength, keyslot_alignment) / SECTOR_SIZE;
if (mode == O_RDONLY)
dmd.flags |= CRYPT_ACTIVATE_READONLY;
@@ -91,13 +98,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;
}
@@ -112,14 +119,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;
@@ -179,9 +186,9 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
if (devfd < 0)
goto out;
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
write_blockwise(devfd, device_block_size(device),
device_alignment(device), src, srcLength) == -1)
if (write_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), src, srcLength,
sector * SECTOR_SIZE) < 0)
goto out;
r = 0;
@@ -189,7 +196,7 @@ out:
if (devfd >= 0)
close(devfd);
if (r)
log_err(ctx, _("IO error while encrypting keyslot.\n"));
log_err(ctx, _("IO error while encrypting keyslot."));
return r;
}
@@ -235,9 +242,9 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
if (devfd < 0)
goto bad;
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
read_blockwise(devfd, device_block_size(device),
device_alignment(device), dst, dstLength) == -1)
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), dst, dstLength,
sector * SECTOR_SIZE) < 0)
goto bad;
close(devfd);
@@ -251,7 +258,7 @@ bad:
if (devfd >= 0)
close(devfd);
log_err(ctx, _("IO error while decrypting keyslot.\n"));
log_err(ctx, _("IO error while decrypting keyslot."));
crypt_storage_destroy(s);
return r;

View File

@@ -2,8 +2,8 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2017, Milan Broz
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-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
@@ -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. (LUKS 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;
}
@@ -393,18 +393,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 +428,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 +436,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 +445,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;
@@ -457,18 +461,18 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
}
/*
* check repair result before writting because repair can't fix out of order
* check repair result before writing because repair can't fix out of order
* keyslot offsets and would corrupt header again
*/
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 +491,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 +528,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;
@@ -539,7 +543,7 @@ static void _to_lower(char *str, unsigned max_len)
static void LUKS_fix_header_compatible(struct luks_phdr *header)
{
/* Old cryptsetup expects "sha1", gcrypt allows case insensistive names,
/* Old cryptsetup expects "sha1", gcrypt allows case insensitive names,
* so always convert hash to lower case in header */
_to_lower(header->hashSpec, LUKS_HASHSPEC_L);
@@ -564,7 +568,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 +607,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 +655,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 +680,14 @@ 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));
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 +695,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 +740,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 +770,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 +797,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 +837,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 +860,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 accoding to specification */
/* 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 +1023,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 +1057,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 +1074,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 +1088,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;
}

View File

@@ -2,7 +2,7 @@
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-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
@@ -99,6 +99,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,

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. 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
@@ -22,7 +22,7 @@
#ifndef _CRYPTSETUP_LUKS2_ONDISK_H
#define _CRYPTSETUP_LUKS2_ONDISK_H
#include <stdint.h>
#include "libcryptsetup.h"
#define LUKS2_MAGIC_1ST "LUKS\xba\xbe"
#define LUKS2_MAGIC_2ND "SKUL\xba\xbe"
@@ -43,12 +43,12 @@
#define LUKS2_DIGEST_MAX 8
typedef int digests_t[LUKS2_DIGEST_MAX];
#define CRYPT_ANY_SEGMENT -1
#define CRYPT_DEFAULT_SEGMENT 0
#define CRYPT_DEFAULT_SEGMENT_STR "0"
#define CRYPT_ANY_DIGEST -1
/*
* LUKS2 header on-disk.
*
@@ -97,6 +97,25 @@ struct luks2_hdr {
json_object *jobj;
};
struct luks2_keyslot_params {
enum { LUKS2_KEYSLOT_AF_LUKS1 = 0 } af_type;
enum { LUKS2_KEYSLOT_AREA_RAW = 0 } area_type;
union {
struct {
char hash[LUKS2_CHECKSUM_ALG_L]; // or include luks.h
unsigned int stripes;
} luks1;
} af;
union {
struct {
char encryption[65]; // or include utils_crypt.h
size_t key_size;
} raw;
} area;
};
/*
* Supportable header sizes (hdr_disk + JSON area)
* Also used as offset for the 2nd header.
@@ -109,10 +128,14 @@ struct luks2_hdr {
#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);
@@ -138,6 +161,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
*/
@@ -153,7 +178,8 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
int keyslot,
const char *password,
size_t password_len,
const struct volume_key *vk);
const struct volume_key *vk,
const struct luks2_keyslot_params *params);
int LUKS2_keyslot_wipe(struct crypt_device *cd,
struct luks2_hdr *hdr,
@@ -188,6 +214,11 @@ int LUKS2_token_assign(struct crypt_device *cd,
int assign,
int commit);
int LUKS2_token_is_assigned(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int token);
int LUKS2_token_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
int token,
@@ -224,14 +255,19 @@ 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
*/
int LUKS2_digests_verify_by_segment(struct crypt_device *cd,
int LUKS2_digest_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
int segment);
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
int segment,
const struct volume_key *vk,
digests_t digests);
const struct volume_key *vk);
void LUKS2_digests_erase_unused(struct crypt_device *cd,
struct luks2_hdr *hdr);
@@ -244,23 +280,6 @@ int LUKS2_digest_verify(struct crypt_device *cd,
int LUKS2_digest_dump(struct crypt_device *cd,
int digest);
int LUKS2_digest_json_get(struct crypt_device *cd,
struct luks2_hdr *hdr,
int digest,
const char **json);
int LUKS2_digest_json_set(struct crypt_device *cd,
struct luks2_hdr *hdr,
int digest,
const char *json);
int LUKS2_digests_assign(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
digests_t digests,
int assign,
int commit);
int LUKS2_digest_assign(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -275,10 +294,9 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd,
int assign,
int commit);
int LUKS2_digests_by_keyslot(struct crypt_device *cd,
int LUKS2_digest_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
digests_t digests);
int keyslot);
int LUKS2_digest_create(struct crypt_device *cd,
const char *type,
@@ -316,6 +334,10 @@ 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);
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment);
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
size_t key_size, struct luks2_keyslot_params *params);
int LUKS2_get_keyslot_params(struct luks2_hdr *hdr, int keyslot,
struct luks2_keyslot_params *params);
int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment);
int LUKS2_get_keyslot_key_size(struct luks2_hdr *hdr, int keyslot);
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type);
@@ -340,8 +362,10 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
int crypt_use_keyring_for_vk(const struct crypt_device *cd);
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk);
int LUKS2_key_description_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int segment);
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot);
struct luks_phdr;
int LUKS2_luks1_to_luks2(struct crypt_device *cd,

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, digest handling
*
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. 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
@@ -28,22 +28,6 @@ static const digest_handler *digest_handlers[LUKS2_DIGEST_MAX] = {
NULL
};
int crypt_digest_register(const digest_handler *handler)
{
int i;
for (i = 0; i < LUKS2_DIGEST_MAX && digest_handlers[i]; i++) {
if (!strcmp(digest_handlers[i]->name, handler->name))
return -EINVAL;
}
if (i == LUKS2_DIGEST_MAX)
return -EINVAL;
digest_handlers[i] = handler;
return 0;
}
const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type)
{
int i;
@@ -107,13 +91,11 @@ int LUKS2_digest_create(struct crypt_device *cd,
return dh->store(cd, digest, vk->key, vk->keylength) ?: digest;
}
int LUKS2_digests_by_keyslot(struct crypt_device *cd,
int LUKS2_digest_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
digests_t digests)
int keyslot)
{
char keyslot_name[16];
int i = 0;
json_object *jobj_digests, *jobj_digest_keyslots;
if (snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1)
@@ -124,13 +106,10 @@ int LUKS2_digests_by_keyslot(struct crypt_device *cd,
json_object_object_foreach(jobj_digests, key, val) {
json_object_object_get_ex(val, "keyslots", &jobj_digest_keyslots);
if (LUKS2_array_jobj(jobj_digest_keyslots, keyslot_name))
digests[i++] = atoi(key);
return atoi(key);
}
if (i < LUKS2_DIGEST_MAX)
digests[i] = -1;
return i ? 0 : -ENOENT;
return -ENOENT;
}
int LUKS2_digest_verify(struct crypt_device *cd,
@@ -139,31 +118,24 @@ int LUKS2_digest_verify(struct crypt_device *cd,
int keyslot)
{
const digest_handler *h;
digests_t digests;
int i, r;
int digest, r;
r = LUKS2_digests_by_keyslot(cd, hdr, keyslot, digests);
if (r == -ENOENT)
return 0;
if (r < 0)
digest = LUKS2_digest_by_keyslot(cd, hdr, keyslot);
if (digest < 0)
return digest;
log_dbg("Verifying key from keyslot %d, digest %d.", keyslot, digest);
h = LUKS2_digest_handler(cd, digest);
if (!h)
return -EINVAL;
r = h->verify(cd, digest, vk->key, vk->keylength);
if (r < 0) {
log_dbg("Digest %d (%s) verify failed with %d.", digest, h->name, r);
return r;
for (i = 0; i < LUKS2_DIGEST_MAX && digests[i] != -1 ; i++) {
log_dbg("Verifying key from keyslot %d, digest %d.",
keyslot, digests[i]);
h = LUKS2_digest_handler(cd, digests[i]);
if (!h)
return -EINVAL;
r = h->verify(cd, digests[i], vk->key, vk->keylength);
if (r < 0) {
log_dbg("Digest %d (%s) verify failed with %d.",
digests[i], h->name, r);
return r;
}
}
return 0;
return digest;
}
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
@@ -176,16 +148,40 @@ int LUKS2_digest_dump(struct crypt_device *cd, int digest)
return h->dump(cd, digest);
}
int LUKS2_digests_verify_by_segment(struct crypt_device *cd,
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
int segment,
const struct volume_key *vk,
digests_t digests)
const struct volume_key *vk)
{
const digest_handler *h;
int digest, r;
digest = LUKS2_digest_by_segment(cd, hdr, segment);
if (digest < 0)
return digest;
log_dbg("Verifying key digest %d.", digest);
h = LUKS2_digest_handler(cd, digest);
if (!h)
return -EINVAL;
r = h->verify(cd, digest, vk->key, vk->keylength);
if (r < 0) {
log_dbg("Digest %d (%s) verify failed with %d.", digest, h->name, r);
return r;
}
return digest;
}
/* FIXME: segment can have more digests */
int LUKS2_digest_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
int segment)
{
char segment_name[16];
const digest_handler *h;
json_object *jobj_digests, *jobj_digest_segments;
int digest, r, i = 0;
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
@@ -197,41 +193,10 @@ int LUKS2_digests_verify_by_segment(struct crypt_device *cd,
if (!LUKS2_array_jobj(jobj_digest_segments, segment_name))
continue;
digest = atoi(key);
log_dbg("Verifying key digest %d.", digest);
h = LUKS2_digest_handler(cd, digest);
if (!h)
return -EINVAL;
r = h->verify(cd, digest, vk->key, vk->keylength);
if (r < 0) {
log_dbg("Digest %d (%s) verify failed with %d.", digest, h->name, r);
return r;
}
if (digests)
digests[i] = digest;
i++;
return atoi(key);
}
if (digests && i < LUKS2_DIGEST_MAX)
digests[i] = -1;
return i ? 0 : -ENOENT;
}
int LUKS2_digest_json_get(struct crypt_device *cd, struct luks2_hdr *hdr,
int digest, const char **json)
{
json_object *jobj_digest;
jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
if (!jobj_digest)
return -EINVAL;
*json = json_object_to_json_string_ext(jobj_digest, JSON_C_TO_STRING_PLAIN);
return 0;
return -ENOENT;
}
static int assign_one_digest(struct crypt_device *cd, struct luks2_hdr *hdr,
@@ -264,20 +229,6 @@ static int assign_one_digest(struct crypt_device *cd, struct luks2_hdr *hdr,
return 0;
}
int LUKS2_digests_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
int keyslot, digests_t digests, int assign, int commit)
{
int i, r;
for (i = 0; i < LUKS2_DIGEST_MAX && digests[i] != -1; i++) {
r = LUKS2_digest_assign(cd, hdr, keyslot, digests[i], assign, 0);
if (r < 0)
return r;
}
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
}
int LUKS2_digest_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
int keyslot, int digest, int assign, int commit)
{
@@ -363,14 +314,14 @@ static int digest_unused(json_object *jobj_digest)
json_object *jobj;
json_object_object_get_ex(jobj_digest, "segments", &jobj);
if (!jobj || !json_object_is_type(jobj, json_type_array) || json_object_array_length(jobj))
if (!jobj || !json_object_is_type(jobj, json_type_array) || json_object_array_length(jobj) > 0)
return 0;
json_object_object_get_ex(jobj_digest, "keyslots", &jobj);
if (!jobj || !json_object_is_type(jobj, json_type_array))
return 0;
return json_object_array_length(jobj) ? 0 : 1;
return json_object_array_length(jobj) > 0 ? 0 : 1;
}
void LUKS2_digests_erase_unused(struct crypt_device *cd,
@@ -389,3 +340,58 @@ void LUKS2_digests_erase_unused(struct crypt_device *cd,
}
}
}
/* Key description helpers */
static char *get_key_description_by_digest(struct crypt_device *cd, int digest)
{
char *desc, digest_str[3];
int r;
size_t len;
if (!crypt_get_uuid(cd))
return NULL;
r = snprintf(digest_str, sizeof(digest_str), "d%u", digest);
if (r < 0 || (size_t)r >= sizeof(digest_str))
return NULL;
/* "cryptsetup:<uuid>-<digest_str>" + \0 */
len = strlen(crypt_get_uuid(cd)) + strlen(digest_str) + 13;
desc = malloc(len);
if (!desc)
return NULL;
r = snprintf(desc, len, "%s:%s-%s", "cryptsetup", crypt_get_uuid(cd), digest_str);
if (r < 0 || (size_t)r >= len) {
free(desc);
return NULL;
}
return desc;
}
int LUKS2_key_description_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int segment)
{
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_segment(cd, hdr, segment));
int r;
r = crypt_volume_key_set_description(vk, desc);
free(desc);
return r;
}
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot)
{
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_keyslot(cd, hdr, keyslot));
int r;
r = crypt_volume_key_set_description(vk, desc);
if (!r)
r = crypt_volume_key_load_in_keyring(cd, vk);
free(desc);
return r;
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, PBKDF2 digest handler (LUKS1 compatible)
*
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. 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
@@ -95,9 +95,10 @@ 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;
struct crypt_pbkdf_type pbkdf = {
.type = CRYPT_KDF_PBKDF2,
.hash = "sha256",
@@ -110,16 +111,24 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
if (r < 0)
return r;
r = crypt_pbkdf_get_limits(CRYPT_KDF_PBKDF2, &pbkdf_limits);
if (r < 0)
return r;
if (crypt_get_pbkdf(cd)->flags & CRYPT_PBKDF_NO_BENCHMARK)
pbkdf.iterations = MIN_PBKDF2_ITERATIONS;
pbkdf.iterations = pbkdf_limits.min_iterations;
else {
r = crypt_benchmark_pbkdf_internal(cd, &pbkdf, volume_key_len);
if (r < 0)
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;
@@ -146,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

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. 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
@@ -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;
@@ -182,7 +184,7 @@ static void hdr_to_disk(struct luks2_hdr *hdr,
}
/*
* Sanity checks before checkum is validated
* Sanity checks before checksum is validated
*/
static int hdr_disk_sanity_check_pre(struct luks2_hdr_disk *hdr,
size_t *hdr_json_size, int secondary,
@@ -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);
@@ -324,7 +326,7 @@ static int hdr_write_disk(struct device *device, struct luks2_hdr *hdr,
}
/*
* Calculate checksum and write header with checkum.
* Calculate checksum and write header with checksum.
*/
r = hdr_checksum_calculate(hdr_disk.checksum_alg, &hdr_disk,
json_area, hdr_json_len);
@@ -361,7 +363,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 +408,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 +427,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 +493,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");
@@ -504,7 +516,7 @@ static json_object *parse_and_validate_json(const char *json_area, int length)
if (!jobj)
return NULL;
/* successfull parse_json_len must not return offset <= 0 */
/* successful parse_json_len must not return offset <= 0 */
assert(offset > 0);
r = validate_json_area(json_area, offset, length);
@@ -519,21 +531,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 +626,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 +666,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 +687,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

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. 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
@@ -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);
@@ -55,6 +61,7 @@ void hexprint_base64(struct crypt_device *cd, json_object *jobj,
json_object *parse_json_len(const char *json_area, int length, int *end_offset);
uint64_t json_object_get_uint64(json_object *jobj);
uint32_t json_object_get_uint32(json_object *jobj);
json_object *json_object_new_uint64(uint64_t value);
void JSON_DBG(json_object *jobj, const char *desc);
@@ -62,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
*/
@@ -82,7 +99,10 @@ struct json_object *LUKS2_array_remove(struct json_object *array, const char *nu
* LUKS2 keyslots handlers (EXPERIMENTAL)
*/
typedef int (*keyslot_alloc_func)(struct crypt_device *cd, int keyslot,
size_t volume_key_len);
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);
@@ -91,20 +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,
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;
/**
@@ -123,13 +152,8 @@ typedef struct {
digest_dump_func dump;
} digest_handler;
int crypt_digest_register(const digest_handler *handler);
const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type);
#define CRYPT_ANY_DIGEST -1
int crypt_keyslot_assign_digest(struct crypt_device *cd, int keyslot, int digest);
int crypt_keyslot_unassign_digest(struct crypt_device *cd, int keyslot, int digest);
/**
* 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

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 header format code
*
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. 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
@@ -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;
}
@@ -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)
@@ -186,11 +186,11 @@ int LUKS2_generate_hdr(
else {
//FIXME
//offset = size_round_up(areas[7].offset + areas[7].length, alignPayload * SECTOR_SIZE);
offset = size_round_up(LUKS2_HDR_DEFAULT_LEN, alignPayload * sector_size);
offset = size_round_up(LUKS2_HDR_DEFAULT_LEN, (size_t)alignPayload * sector_size);
offset += alignOffset;
}
json_object_object_add(jobj_segment, "offset", json_object_new_string(uint64_to_str(num, sizeof(num), &offset)));
json_object_object_add(jobj_segment, "offset", json_object_new_uint64(offset));
json_object_object_add(jobj_segment, "iv_tweak", json_object_new_string("0"));
json_object_object_add(jobj_segment, "size", json_object_new_string("dynamic"));
json_object_object_add(jobj_segment, "encryption", json_object_new_string(cipher));
@@ -208,12 +208,11 @@ int LUKS2_generate_hdr(
json_object_object_add(jobj_segments, num, jobj_segment);
json_size = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
json_object_object_add(jobj_config, "json_size",
json_object_new_string(uint64_to_str(num, sizeof(num), &json_size)));
json_object_object_add(jobj_config, "json_size", json_object_new_uint64(json_size));
/* 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);
@@ -225,8 +224,7 @@ int LUKS2_generate_hdr(
/* keyslots size has to be 4 KiB aligned */
keyslots_size -= (keyslots_size % 4096);
json_object_object_add(jobj_config, "keyslots_size",
json_object_new_string(uint64_to_str(num, sizeof(num), &keyslots_size)));
json_object_object_add(jobj_config, "keyslots_size", json_object_new_uint64(keyslots_size));
JSON_DBG(hdr->jobj, "Header JSON");
return 0;

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, keyslot handling
*
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. 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
@@ -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,77 +74,27 @@ int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
return -EINVAL;
}
static int digests_by_segment(json_object *jobj_digests, const char *segment,
digests_t digests)
{
json_object *jobj_segs;
int i = 0;
json_object_object_foreach(jobj_digests, dig, val) {
json_object_object_get_ex(val, "segments", &jobj_segs);
if (LUKS2_array_jobj(jobj_segs, segment))
digests[i++] = atoi(dig);
}
if (i < LUKS2_DIGEST_MAX)
digests[i] = -1;
return i ? 0 : -ENOENT;
}
static int is_in(const int super[], int super_size, int elem)
{
int i;
for (i = 0; i < super_size && super[i] != -1; i++)
if (super[i] == elem)
return 1;
return 0;
}
static int is_subset(const int super[], const int sub[], int super_size)
{
int i;
for (i = 0; i < super_size && sub[i] != -1; i++)
if (!is_in(super, super_size, sub[i]))
return 0;
return 1;
}
/* Check if a keyslot is asssigned to specific segment */
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
{
char keyslot_name[16], segment_name[16];
digests_t keyslot_digests, segment_digests;
json_object *jobj_digests;
int r = -ENOENT;
int keyslot_digest, segment_digest;
/* no need to check anything */
if (segment == CRYPT_ANY_SEGMENT)
return 0;
if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1 ||
snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1)
keyslot_digest = LUKS2_digest_by_keyslot(NULL, hdr, keyslot);
if (keyslot_digest < 0)
return -EINVAL;
/* empty set is subset of any set and it'd be wrong */
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
r = LUKS2_digests_by_keyslot(NULL, hdr, keyslot, keyslot_digests);
if (r)
return r;
segment_digest = LUKS2_digest_by_segment(NULL, hdr, segment);
if (segment_digest < 0)
return segment_digest;
/* empty set can't be superset of non-empty one */
if (digests_by_segment(jobj_digests, segment_name, segment_digests))
return r;
/*
* keyslot may activate segment if set of digests for keyslot
* is actually subset of set of digests for segment
*/
return is_subset(segment_digests, keyslot_digests, LUKS2_DIGEST_MAX) ? 0 : -ENOENT;
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;
@@ -160,7 +102,6 @@ int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
/* keyslot digests must be subset of segment digests */
json_object_object_foreach(jobj_keyslots, slot, val) {
UNUSED(val);
if (!LUKS2_keyslot_for_segment(hdr, atoi(slot), segment))
@@ -170,18 +111,97 @@ 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)
{
int r, integrity_key_size = crypt_get_integrity_key_size(cd);
const struct crypt_pbkdf_type *pbkdf = crypt_get_pbkdf_type(cd);
if (!hdr || !pbkdf || !params)
return -EINVAL;
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
params->area_type = LUKS2_KEYSLOT_AREA_RAW;
/* set keyslot AF parameters */
/* currently we use hash for AF from pbkdf settings */
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash),
"%s", pbkdf->hash);
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
return -EINVAL;
params->af.luks1.stripes = 4000;
/* set keyslot area encryption parameters */
/* short circuit authenticated encryption hardcoded defaults */
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");
params->area.raw.key_size = 32;
return 0;
}
r = snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption),
"%s", LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT));
if (r < 0 || (size_t)r >= sizeof(params->area.raw.encryption))
return -EINVAL;
/* Slot encryption tries to use the same key size as for the main algorithm */
if ((size_t)integrity_key_size > key_size)
return -EINVAL;
params->area.raw.key_size = key_size - integrity_key_size;
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;
@@ -229,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)
@@ -315,7 +341,7 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
password, password_len, segment, vk);
if (r_prio >= 0)
r = r_prio;
else if (r_prio < 0 && (r_prio != -EPERM) && (r_prio != -ENOENT))
else if (r_prio != -EPERM && r_prio != -ENOENT)
r = r_prio;
else
r = LUKS2_keyslot_open_priority(cd, hdr, CRYPT_SLOT_PRIORITY_NORMAL,
@@ -334,7 +360,8 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
int keyslot,
const char *password,
size_t password_len,
const struct volume_key *vk)
const struct volume_key *vk,
const struct luks2_keyslot_params *params)
{
const keyslot_handler *h;
int r;
@@ -348,13 +375,21 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
if (!h)
return -EINVAL;
r = h->alloc(cd, keyslot, vk->keylength);
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;
@@ -391,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;
}
@@ -408,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;
}
}
@@ -475,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

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 type keyslot handler
*
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. 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
@@ -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);
@@ -66,17 +66,16 @@ 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;
}
devfd = device_open_locked(device, O_RDWR);
if (devfd >= 0) {
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
write_blockwise(devfd, device_block_size(device),
device_alignment(device), src,
srcLength) == -1)
if (write_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), src,
srcLength, sector * SECTOR_SIZE) < 0)
r = -EIO;
else
r = 0;
@@ -87,7 +86,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
@@ -101,7 +100,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);
@@ -124,7 +123,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;
@@ -132,9 +131,9 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
devfd = device_open_locked(device, O_RDONLY);
if (devfd >= 0) {
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 ||
read_blockwise(devfd, device_block_size(device),
device_alignment(device), dst, dstLength) == -1)
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), dst,
dstLength, sector * SECTOR_SIZE) < 0)
r = -EIO;
else
r = 0;
@@ -148,13 +147,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,
@@ -162,11 +212,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) ||
@@ -174,6 +225,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);
@@ -188,52 +245,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;
@@ -247,7 +279,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);
@@ -261,7 +293,6 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
if (r < 0)
return r;
JSON_DBG(jobj_keyslot, "Keyslot JSON");
return 0;
}
@@ -271,53 +302,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))
@@ -354,10 +353,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);
@@ -375,28 +375,101 @@ 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)
size_t volume_key_len,
const struct luks2_keyslot_params *params)
{
struct luks2_hdr *hdr;
const struct crypt_pbkdf_type *pbkdf;
char area_offset_string[24], area_length_string[24];
char cipher[2 * MAX_CIPHER_LEN + 1], num[16];
char num[16];
uint64_t area_offset, area_length;
json_object *jobj_keyslots, *jobj_keyslot, *jobj_kdf, *jobj_af, *jobj_area;
size_t keyslot_key_len;
json_object *jobj_keyslots, *jobj_keyslot, *jobj_af, *jobj_area;
int r;
log_dbg("Trying to allocate LUKS2 keyslot %d.", keyslot);
if (!params || params->area_type != LUKS2_KEYSLOT_AREA_RAW ||
params->af_type != LUKS2_KEYSLOT_AF_LUKS1) {
log_dbg("Invalid LUKS2 keyslot parameters.");
return -EINVAL;
}
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
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)) {
@@ -411,74 +484,40 @@ 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(pbkdf->hash));
json_object_object_add(jobj_af, "stripes", json_object_new_int(4000));
json_object_object_add(jobj_af, "stripes", json_object_new_int(params->af.luks1.stripes));
json_object_object_add(jobj_keyslot, "af", jobj_af);
/* Area object */
jobj_area = json_object_new_object();
json_object_object_add(jobj_area, "type", json_object_new_string("raw"));
/* Slot encryption tries to use the same key size as fot the main algorithm */
keyslot_key_len = volume_key_len - crypt_get_integrity_key_size(cd);
/* Cannot use metadata tags in keyslot */
if (crypt_get_integrity_tag_size(cd)) {
snprintf(cipher, sizeof(cipher), "aes-xts-plain64"); // FIXME: fixed cipher and key size can be wrong
keyslot_key_len = 32;
} else if (crypt_get_cipher_mode(cd))
snprintf(cipher, sizeof(cipher), "%s-%s", crypt_get_cipher(cd), crypt_get_cipher_mode(cd));
else
snprintf(cipher, sizeof(cipher), "%s", crypt_get_cipher(cd));
json_object_object_add(jobj_area, "encryption", json_object_new_string(cipher));
json_object_object_add(jobj_area, "key_size", json_object_new_int(keyslot_key_len));
uint64_to_str(area_offset_string, sizeof(area_offset_string), &area_offset);
json_object_object_add(jobj_area, "offset", json_object_new_string(area_offset_string));
uint64_to_str(area_length_string, sizeof(area_length_string), &area_length);
json_object_object_add(jobj_area, "size", json_object_new_string(area_length_string));
json_object_object_add(jobj_area, "encryption", json_object_new_string(params->area.raw.encryption));
json_object_object_add(jobj_area, "key_size", json_object_new_int(params->area.raw.key_size));
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);
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,
@@ -505,6 +544,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,
@@ -579,7 +622,7 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
log_std(cd, "\tIterations: %" PRIu64 "\n", json_object_get_uint64(jobj1));
} else {
json_object_object_get_ex(jobj_kdf, "time", &jobj1);
log_std(cd, "\tTime: %" PRIu64 "\n", json_object_get_int64(jobj1));
log_std(cd, "\tTime cost: %" PRIu64 "\n", json_object_get_int64(jobj1));
json_object_object_get_ex(jobj_kdf, "memory", &jobj1);
log_std(cd, "\tMemory: %" PRIu64 "\n", json_object_get_int64(jobj1));
@@ -604,59 +647,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;
@@ -665,10 +696,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;
@@ -676,12 +707,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

@@ -1,9 +1,9 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS1 conversion code
*
* Copyright (C) 2015-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2017, Ondrej Kozina. All rights reserved.
* Copyright (C) 2015-2017, Milan Broz. All rights reserved.
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Ondrej Kozina. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. 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
@@ -26,7 +26,7 @@
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struct json_object **keyslot_object)
{
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L], num[24];
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
size_t base64_len;
struct json_object *keyslot_obj, *field, *jobj_kdf, *jobj_af, *jobj_area;
uint64_t offset, area_size, offs_a, offs_b, length;
@@ -83,8 +83,8 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
}
area_size = offs_b - offs_a;
json_object_object_add(jobj_area, "key_size", json_object_new_int(hdr_v1->keyBytes));
json_object_object_add(jobj_area, "offset", json_object_new_string(uint64_to_str(num, sizeof(num), &offset)));
json_object_object_add(jobj_area, "size", json_object_new_string(uint64_to_str(num, sizeof(num), &area_size)));
json_object_object_add(jobj_area, "offset", json_object_new_uint64(offset));
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_size));
json_object_object_add(keyslot_obj, "area", jobj_area);
*keyslot_object = keyslot_obj;
@@ -121,7 +121,6 @@ static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object
{
const char *c;
char cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
char num[24]; /* uint64_t in string */
struct json_object *segment_obj, *field;
uint64_t number;
@@ -140,7 +139,7 @@ static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object
/* offset field */
number = (uint64_t)hdr_v1->payloadOffset * SECTOR_SIZE;
field = json_object_new_string(uint64_to_str(num, sizeof(num), &number));
field = json_object_new_uint64(number);
if (!field) {
json_object_put(segment_obj);
return -ENOMEM;
@@ -348,7 +347,6 @@ static int json_luks1_digests(const struct luks_phdr *hdr_v1, struct json_object
static int json_luks1_object(struct luks_phdr *hdr_v1, struct json_object **luks1_object, uint64_t keyslots_size)
{
char num[24];
int r;
struct json_object *luks1_obj, *field;
uint64_t json_size;
@@ -399,10 +397,8 @@ static int json_luks1_object(struct luks_phdr *hdr_v1, struct json_object **luks
json_object_object_add(luks1_obj, "config", field);
json_size = LUKS2_HDR_16K_LEN - LUKS2_HDR_BIN_LEN;
json_object_object_add(field, "json_size",
json_object_new_string(uint64_to_str(num, sizeof(num), &json_size)));
json_object_object_add(field, "keyslots_size",
json_object_new_string(uint64_to_str(num, sizeof(num), &keyslots_size)));
json_object_object_add(field, "json_size", json_object_new_uint64(json_size));
json_object_object_add(field, "keyslots_size", json_object_new_uint64(keyslots_size));
*luks1_object = luks1_obj;
return 0;
@@ -410,7 +406,6 @@ static int json_luks1_object(struct luks_phdr *hdr_v1, struct json_object **luks
static void move_keyslot_offset(json_object *jobj, int offset_add)
{
char num[24];
json_object *jobj1, *jobj2, *jobj_area;
uint64_t offset = 0;
@@ -420,7 +415,7 @@ static void move_keyslot_offset(json_object *jobj, int offset_add)
json_object_object_get_ex(val, "area", &jobj_area);
json_object_object_get_ex(jobj_area, "offset", &jobj2);
offset = json_object_get_uint64(jobj2) + offset_add;
json_object_object_add(jobj_area, "offset", json_object_new_string(uint64_to_str(num, sizeof(num), &offset)));
json_object_object_add(jobj_area, "offset", json_object_new_uint64(offset));
}
}
@@ -430,43 +425,47 @@ 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:
close(devfd);
crypt_memzero(buf, buf_size);
free(buf);
return 0;
return r;
}
static int luks_header_in_use(struct crypt_device *cd)
@@ -475,11 +474,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)
{
@@ -493,6 +522,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;
@@ -501,10 +531,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;
}
@@ -543,8 +576,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);
@@ -587,6 +622,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);
@@ -629,30 +665,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;
}
key_size = r = LUKS2_get_volume_key_size(hdr2, 0);
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;
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;
}
}
@@ -674,8 +728,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))
/*
* 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;
}
@@ -784,8 +842,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

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, token handling
*
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2017, Milan Broz. All rights reserved.
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2018, Milan Broz. 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
@@ -132,6 +132,7 @@ int LUKS2_token_create(struct crypt_device *cd,
int commit)
{
const crypt_token_handler *h;
const token_handler *th;
json_object *jobj_tokens, *jobj_type, *jobj;
enum json_tokener_error jerr;
char num[16];
@@ -169,14 +170,19 @@ int LUKS2_token_create(struct crypt_device *cd,
json_object_object_get_ex(jobj, "type", &jobj_type);
if (is_builtin_candidate(json_object_get_string(jobj_type))) {
log_dbg("%s is builtin token candidate", json_object_get_string(jobj_type));
json_object_put(jobj);
return -EINVAL;
}
th = LUKS2_token_handler_type_internal(cd, json_object_get_string(jobj_type));
if (!th || !th->set) {
log_dbg("%s is builtin token candidate with missing handler", json_object_get_string(jobj_type));
json_object_put(jobj);
return -EINVAL;
}
h = th->h;
} else
h = LUKS2_token_handler_type(cd, json_object_get_string(jobj_type));
h = LUKS2_token_handler_type(cd, json_object_get_string(jobj_type));
if (h && h->validate && h->validate(cd, json)) {
json_object_put(jobj);
log_dbg("Token type %s validation failed.", h->name);
return -EINVAL;
}
@@ -257,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;
@@ -265,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);
@@ -345,7 +352,7 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
{
const crypt_token_handler *h;
json_object *jobj_token, *jobj_token_keyslots, *jobj;
const char *num;
const char *num = NULL;
int i, r;
if (!(h = LUKS2_token_handler(cd, token)))
@@ -361,14 +368,17 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
/* Try to open keyslot referenced in token */
r = -EINVAL;
for (i = 0; i < json_object_array_length(jobj_token_keyslots) && r < 0; i++) {
for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots) && r < 0; i++) {
jobj = json_object_array_get_idx(jobj_token_keyslots, i);
num = json_object_get_string(jobj);
log_dbg("Trying to open keyslot %s with token %d (type %s).", num, token, h->name);
r = LUKS2_keyslot_open(cd, atoi(num), segment, buffer, buffer_len, vk);
}
return r < 0 ? r : atoi(num);
if (r >= 0 && num)
return atoi(num);
return r;
}
int LUKS2_token_open_and_activate(struct crypt_device *cd,
@@ -388,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);
@@ -399,11 +410,13 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
keyslot = r;
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
r = crypt_volume_key_load_in_keyring(cd, vk);
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot);
if (r >= 0 && name)
r = LUKS2_activate(cd, name, vk, flags);
if (r < 0 && vk)
crypt_drop_keyring_key(cd, vk->key_description);
crypt_free_volume_key(vk);
return r < 0 ? r : keyslot;
@@ -431,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)
@@ -441,11 +455,13 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
keyslot = r;
if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
r = crypt_volume_key_load_in_keyring(cd, vk);
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot);
if (r >= 0 && name)
r = LUKS2_activate(cd, name, vk, flags);
if (r < 0 && vk)
crypt_drop_keyring_key(cd, vk->key_description);
crypt_free_volume_key(vk);
return r < 0 ? r : keyslot;
@@ -460,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));
}
}
@@ -473,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;
}
@@ -558,3 +576,36 @@ int LUKS2_token_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
return token;
}
int LUKS2_token_is_assigned(struct crypt_device *cd, struct luks2_hdr *hdr,
int keyslot, int token)
{
int i;
json_object *jobj_token, *jobj_token_keyslots, *jobj;
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX || token < 0 || token >= LUKS2_TOKENS_MAX)
return -EINVAL;
jobj_token = LUKS2_get_token_jobj(hdr, token);
if (!jobj_token)
return -ENOENT;
json_object_object_get_ex(jobj_token, "keyslots", &jobj_token_keyslots);
for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots); i++) {
jobj = json_object_array_get_idx(jobj_token_keyslots, i);
if (keyslot == atoi(json_object_get_string(jobj)))
return 0;
}
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

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, kernel keyring token
*
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2017, Ondrej Kozina. All rights reserved.
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2018, Ondrej Kozina. 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
@@ -31,6 +31,7 @@ static int keyring_open(struct crypt_device *cd,
{
json_object *jobj_token, *jobj_key;
struct luks2_hdr *hdr;
int r;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
@@ -41,9 +42,14 @@ static int keyring_open(struct crypt_device *cd,
json_object_object_get_ex(jobj_token, "key_description", &jobj_key);
/* TODO: if r == -ENOKEY then instantiate the key? */
if (keyring_get_passphrase(json_object_get_string(jobj_key), buffer, buffer_len))
r = keyring_get_passphrase(json_object_get_string(jobj_key), buffer, buffer_len);
if (r == -ENOTSUP) {
log_dbg("Kernel keyring features disabled.");
return -EINVAL;
} else if (r < 0) {
log_dbg("keyring_get_passphrase failed (error %d)", r);
return -EINVAL;
}
return 0;
}
@@ -63,6 +69,11 @@ static int keyring_validate(struct crypt_device *cd __attribute__((unused)),
return r;
}
if (json_object_object_length(jobj_token) != 3) {
log_dbg("Keyring token is expected to have exactly 3 fields.");
goto out;
}
if (!json_object_object_get_ex(jobj_token, "key_description", &jobj_key)) {
log_dbg("missing key_description field.");
goto out;

View File

@@ -1,7 +1,7 @@
/*
* cryptsetup kernel RNG access functions
*
* Copyright (C) 2010-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-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
@@ -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

@@ -1,8 +1,8 @@
/*
* TCRYPT (TrueCrypt-compatible) and VeraCrypt volume handling
*
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2017, Milan Broz
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-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
@@ -31,25 +31,27 @@
#include "internal.h"
/* TCRYPT PBKDF variants */
static struct {
static const struct {
unsigned int legacy:1;
unsigned int veracrypt:1;
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, 0, NULL, NULL, 0, 0, 0 }
};
struct tcrypt_alg {
@@ -350,7 +352,7 @@ static int TCRYPT_decrypt_hdr_one(struct tcrypt_alg *alg, const char *mode,
}
/*
* For chanined ciphers and CBC mode we need "outer" decryption.
* For chained ciphers and CBC mode we need "outer" decryption.
* Backend doesn't provide this, so implement it here directly using ECB.
*/
static int TCRYPT_decrypt_cbci(struct tcrypt_algs *ciphers,
@@ -457,23 +459,28 @@ static int TCRYPT_pool_keyfile(struct crypt_device *cd,
unsigned char pool[TCRYPT_KEY_POOL_LEN],
const char *keyfile)
{
unsigned char data[TCRYPT_KEYFILE_LEN];
int i, j, fd, data_size;
unsigned char *data;
int i, j, fd, data_size, r = -EIO;
uint32_t crc;
log_dbg("TCRYPT: using keyfile %s.", keyfile);
data = malloc(TCRYPT_KEYFILE_LEN);
if (!data)
return -ENOMEM;
memset(data, 0, TCRYPT_KEYFILE_LEN);
fd = open(keyfile, O_RDONLY);
if (fd < 0) {
log_err(cd, _("Failed to open key file.\n"));
return -EIO;
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);
return -EIO;
log_err(cd, _("Error reading keyfile %s."), keyfile);
goto out;
}
for (i = 0, j = 0, crc = ~0U; i < data_size; i++) {
@@ -484,11 +491,13 @@ static int TCRYPT_pool_keyfile(struct crypt_device *cd,
pool[j++] += (unsigned char)(crc);
j %= TCRYPT_KEY_POOL_LEN;
}
r = 0;
out:
crypt_memzero(&crc, sizeof(crc));
crypt_memzero(data, TCRYPT_KEYFILE_LEN);
free(data);
return 0;
return r;
}
static int TCRYPT_init_hdr(struct crypt_device *cd,
@@ -498,7 +507,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
unsigned char pwd[TCRYPT_KEY_POOL_LEN] = {};
size_t passphrase_size;
char *key;
unsigned int i, skipped = 0;
unsigned int i, skipped = 0, iterations;
int r = -EPERM;
if (posix_memalign((void*)&key, crypt_getpagesize(), TCRYPT_HDR_KEY_LEN))
@@ -510,7 +519,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;
}
@@ -532,23 +541,26 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
if (!(params->flags & CRYPT_TCRYPT_VERA_MODES) && tcrypt_kdf[i].veracrypt)
continue;
if ((params->flags & CRYPT_TCRYPT_VERA_MODES) && params->veracrypt_pim) {
/* Do not try TrueCrypt modes if we have PIM value */
if (!tcrypt_kdf[i].veracrypt)
continue;
/* adjust iterations to given PIM cmdline parameter */
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER)
tcrypt_kdf[i].iterations = params->veracrypt_pim * 2048;
else
tcrypt_kdf[i].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;
/* Derive header key */
log_dbg("TCRYPT: trying KDF: %s-%s-%d.",
tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations);
log_dbg("TCRYPT: trying KDF: %s-%s-%d%s.",
tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations,
params->veracrypt_pim && tcrypt_kdf[i].veracrypt ? "-PIM" : "");
r = crypt_pbkdf(tcrypt_kdf[i].name, tcrypt_kdf[i].hash,
(char*)pwd, passphrase_size,
hdr->salt, TCRYPT_HDR_SALT_LEN,
key, TCRYPT_HDR_KEY_LEN,
tcrypt_kdf[i].iterations, 0, 0);
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;
}
@@ -566,9 +578,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)
@@ -625,7 +637,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;
}
@@ -714,13 +726,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;
}
@@ -754,7 +766,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;
@@ -775,7 +787,7 @@ int TCRYPT_activate(struct crypt_device *cd,
return r;
}
/* Frome here, key size for every cipher must be the same */
/* From here, key size for every cipher must be the same */
dmd.u.crypt.vk = crypt_alloc_volume_key(algs->cipher[0].key_size +
algs->cipher[0].key_extra_size, NULL);
if (!dmd.u.crypt.vk) {
@@ -822,7 +834,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

@@ -1,8 +1,8 @@
/*
* TCRYPT (TrueCrypt-compatible) header defitinion
*
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2017, Milan Broz
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-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
@@ -19,11 +19,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "libcryptsetup.h"
#ifndef _CRYPTSETUP_TCRYPT_H
#define _CRYPTSETUP_TCRYPT_H
#include <stdint.h>
#define TCRYPT_HDR_SALT_LEN 64
#define TCRYPT_HDR_IV_LEN 16
#define TCRYPT_HDR_LEN 448
@@ -72,6 +72,8 @@ struct tcrypt_phdr {
};
} __attribute__((__packed__));
struct crypt_device;
struct crypt_params_tcrypt;
struct crypt_dm_active_device;
struct volume_key;
struct device;

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2017, Milan Broz
* 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
@@ -22,14 +22,12 @@
*/
#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>
#include "internal.h"
@@ -45,267 +43,21 @@ unsigned crypt_cpusonline(void)
return r < 0 ? 1 : r;
}
const char *uint64_to_str(char *buffer, size_t size, const uint64_t *val)
uint64_t crypt_getphysmemory_kb(void)
{
int r = snprintf(buffer, size, "%" PRIu64, *val);
if (r < 0) {
log_dbg("Failed to convert integer to string.");
*buffer = '\0';
} else if ((size_t)r >= size) {
log_dbg("Not enough space to store '%" PRIu64 "' to a string buffer.", *val);
*buffer = '\0';
}
long pagesize, phys_pages;
uint64_t phys_memory_kb;
return buffer;
}
pagesize = sysconf(_SC_PAGESIZE);
phys_pages = sysconf(_SC_PHYS_PAGES);
ssize_t read_buffer(int fd, void *buf, size_t count)
{
size_t read_size = 0;
ssize_t r;
if (pagesize < 0 || phys_pages < 0)
return 0;
if (fd < 0 || !buf)
return -EINVAL;
phys_memory_kb = pagesize / 1024;
phys_memory_kb *= phys_pages;
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;
return phys_memory_kb;
}
/* MEMLOCK */
@@ -326,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",
@@ -340,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));
}
@@ -356,14 +108,14 @@ int crypt_memlock_dec(struct crypt_device *ctx)
* or when it reaches EOF before the requested number of bytes have been
* discarded.
*/
static int keyfile_seek(int fd, size_t bytes)
static int keyfile_seek(int fd, uint64_t bytes)
{
char tmp[BUFSIZ];
size_t next_read;
ssize_t bytes_r;
off_t r;
off64_t r;
r = lseek(fd, bytes, SEEK_CUR);
r = lseek64(fd, bytes, SEEK_CUR);
if (r > 0)
return 0;
if (r < 0 && errno != ESPIPE)
@@ -371,13 +123,14 @@ static int keyfile_seek(int fd, size_t bytes)
while (bytes > 0) {
/* figure out how much to read */
next_read = bytes > sizeof(tmp) ? sizeof(tmp) : bytes;
next_read = bytes > sizeof(tmp) ? sizeof(tmp) : (size_t)bytes;
bytes_r = read(fd, tmp, next_read);
if (bytes_r < 0) {
if (errno == EINTR)
continue;
crypt_memzero(tmp, sizeof(tmp));
/* read error */
return -1;
}
@@ -389,18 +142,20 @@ static int keyfile_seek(int fd, size_t bytes)
bytes -= bytes_r;
}
crypt_memzero(tmp, sizeof(tmp));
return bytes == 0 ? 0 : -1;
}
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,
uint32_t flags)
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 key_size,
uint32_t flags)
{
int fd, regular_file, char_to_read = 0, char_read = 0, unlimited_read = 0;
int r = -EINVAL, newline;
char *pass = NULL;
size_t buflen, i, file_read_size;
size_t buflen, i;
uint64_t file_read_size;
struct stat st;
if (!key || !key_size_read)
@@ -411,44 +166,44 @@ int crypt_keyfile_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 requsted otherwise, we limit input to prevent memory exhaustion */
if (keyfile_size_max == 0) {
keyfile_size_max = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1;
/* If not requested otherwise, we limit input to prevent memory exhaustion */
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)) {
regular_file = 1;
file_read_size = (size_t)st.st_size;
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 >= 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;
}
@@ -456,22 +211,22 @@ int crypt_keyfile_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;
}
@@ -485,13 +240,13 @@ int crypt_keyfile_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;
}
@@ -508,19 +263,19 @@ int crypt_keyfile_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;
}
@@ -535,3 +290,36 @@ out_err:
crypt_safe_free(pass);
return r;
}
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,
uint32_t flags)
{
return crypt_keyfile_device_read(cd, keyfile, key, key_size_read,
keyfile_offset, keyfile_size_max, flags);
}
int kernel_version(uint64_t *kversion)
{
struct utsname uts;
uint16_t maj, min, patch, rel;
int r = -EINVAL;
if (uname(&uts) < 0)
return r;
if (sscanf(uts.release, "%" SCNu16 ".%" SCNu16 ".%" SCNu16 "-%" SCNu16,
&maj, &min, &patch, &rel) == 4)
r = 0;
else if (sscanf(uts.release, "%" SCNu16 ".%" SCNu16 ".%" SCNu16,
&maj, &min, &patch) == 3) {
rel = 0;
r = 0;
}
if (!r)
*kversion = version(maj, min, patch, rel);
return r;
}

View File

@@ -1,8 +1,8 @@
/*
* libcryptsetup - cryptsetup library, cipher bechmark
* libcryptsetup - cryptsetup library, cipher benchmark
*
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2017, Milan Broz
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-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
@@ -281,33 +281,37 @@ static int benchmark_callback(uint32_t time_ms, void *usrptr)
/*
* Used in internal places to benchmark crypt_device context PBKDF.
* Once requested parameters are benchmarked, iterations attribute is set,
* and the benchamarked values can be reused.
* Note that memory cost can be changed after benchark (if used).
* and the benchmarked values can be reused.
* Note that memory cost can be changed after benchmark (if used).
* NOTE: You need to check that you are benchmarking for the same key size.
*/
int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
struct crypt_pbkdf_type *pbkdf,
size_t volume_key_size)
{
struct crypt_pbkdf_limits pbkdf_limits;
double PBKDF2_tmp;
uint32_t ms_tmp;
int r = -EINVAL;
/* Already benchmarked */
if (pbkdf->iterations) {
log_dbg("Reusing PBKDF values.");
return 0;
}
r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
if (r)
return r;
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) {
log_err(cd, _("PBKDF benchmark disabled but iterations not set.\n"));
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 enouch to run benchmark for only 1 second
* and interpolate final iterarions value from it.
* For PBKDF2 it is enough to run benchmark for only 1 second
* and interpolate final iterations value from it.
*/
ms_tmp = pbkdf->time_ms;
pbkdf->time_ms = 1000;
@@ -318,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;
}
@@ -326,13 +330,19 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
PBKDF2_tmp = ((double)pbkdf->iterations * pbkdf->time_ms / 1000.);
if (PBKDF2_tmp > (double)UINT32_MAX)
return -EINVAL;
pbkdf->iterations = at_least((uint32_t)PBKDF2_tmp, MIN_PBKDF2_ITERATIONS);
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

@@ -2,8 +2,8 @@
* utils_crypt - cipher utilities for cryptsetup
*
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2017, Milan Broz
* 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
@@ -37,7 +37,7 @@ int crypt_parse_name_and_mode(const char *s, char *cipher, int *key_nums,
if (sscanf(s, "%" MAX_CIPHER_LEN_STR "[^-]-%" MAX_CIPHER_LEN_STR "s",
cipher, cipher_mode) == 2) {
if (!strcmp(cipher_mode, "plain"))
strncpy(cipher_mode, "cbc-plain", 10);
strcpy(cipher_mode, "cbc-plain");
if (key_nums) {
char *tmp = strchr(cipher, ':');
*key_nums = tmp ? atoi(++tmp) : 1;
@@ -49,16 +49,16 @@ int crypt_parse_name_and_mode(const char *s, char *cipher, int *key_nums,
}
/* Short version for "empty" cipher */
if (!strcmp(s, "null")) {
strncpy(cipher, "cipher_null", MAX_CIPHER_LEN);
strncpy(cipher_mode, "ecb", 9);
if (!strcmp(s, "null") || !strcmp(s, "cipher_null")) {
strcpy(cipher, "cipher_null");
strcpy(cipher_mode, "ecb");
if (key_nums)
*key_nums = 0;
return 0;
}
if (sscanf(s, "%" MAX_CIPHER_LEN_STR "[^-]", cipher) == 1) {
strncpy(cipher_mode, "cbc-plain", 10);
strcpy(cipher_mode, "cbc-plain");
if (key_nums)
*key_nums = 1;
return 0;
@@ -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;

View File

@@ -2,8 +2,8 @@
* utils_crypt - cipher utilities for cryptsetup
*
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2017, Milan Broz
* 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

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2017, Milan Broz
* 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
@@ -48,8 +48,8 @@ struct device {
struct crypt_lock_handle *lh;
int o_direct:1;
int init_done:1;
unsigned int o_direct:1;
unsigned int init_done:1;
/* cached values */
size_t alignment;
@@ -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;
}
@@ -246,7 +252,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;
}
@@ -414,7 +422,9 @@ void device_topology_alignment(struct device *device,
temp_alignment = (unsigned long)min_io_size;
if (temp_alignment < (unsigned long)opt_io_size)
/* Ignore bogus opt-io that could break alignment */
if ((temp_alignment < (unsigned long)opt_io_size) &&
!((unsigned long)opt_io_size % temp_alignment))
temp_alignment = (unsigned long)opt_io_size;
/* If calculated alignment is multiple of default, keep default */
@@ -498,7 +508,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;
@@ -563,7 +573,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;
@@ -587,13 +597,13 @@ 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);
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);
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);
}
return r;
@@ -616,7 +626,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;
}
@@ -626,7 +636,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;
}
@@ -671,7 +681,7 @@ 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"),
log_err(cd, _("Requested offset is beyond real size of device %s."),
device->path);
return -EINVAL;
}
@@ -679,7 +689,7 @@ int device_block_adjust(struct crypt_device *cd,
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);
return -ENOTBLK;
}
*size -= device_offset;
@@ -690,7 +700,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);
return -EINVAL;
}

View File

@@ -1,8 +1,8 @@
/*
* Metadata on-disk locking for processes serialization
*
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2017, Ondrej Kozina. All rights reserved.
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2018, Ondrej Kozina. 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
@@ -73,9 +73,11 @@ static int open_lock_dir(struct crypt_device *cd, const char *dir, const char *b
{
int dirfd, lockdfd;
dirfd = open(dir, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
dirfd = open(dir, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (dirfd < 0) {
log_dbg("Failed to open directory '%s': (%d: %s).", dir, errno, strerror(errno));
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)."), dir, base);
return -EINVAL;
}
@@ -89,8 +91,11 @@ static int open_lock_dir(struct crypt_device *cd, const char *dir, const char *b
log_dbg("Failed to create directory %s in %s (%d: %s).", base, dir, errno, strerror(errno));
else
lockdfd = openat(dirfd, base, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
} else
} 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)."), dir, base, base);
}
}
close(dirfd);
@@ -172,8 +177,8 @@ static void release_lock_handle(struct crypt_lock_handle *h)
if (S_ISBLK(h->mode) && /* was it block device */
!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 refered by fd */
!stat(res, &buf_b) && /* does path file stil exist? */
!fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
!stat(res, &buf_b) && /* does path file still exist? */
same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
/* coverity[toctou] */
if (unlink(res)) /* yes? unlink the file */

View File

@@ -1,8 +1,8 @@
/*
* Metadata on-disk locking for processes serialization
*
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2017, Ondrej Kozina. All rights reserved.
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2018, Ondrej Kozina. 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

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2017, Milan Broz
* 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

View File

@@ -3,8 +3,8 @@
*
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2017, Milan Broz
* 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
@@ -86,7 +86,7 @@ struct crypt_dm_active_device {
/* struct crypt_active_device */
uint64_t offset; /* offset in sectors */
uint64_t iv_offset; /* IV initilisation sector */
uint64_t iv_offset; /* IV initialisation sector */
uint32_t tag_size; /* additional on-disk tag size */
uint32_t sector_size; /* encryption sector size */
} crypt;
@@ -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);

View File

@@ -1,7 +1,7 @@
/*
* FIPS mode utilities
*
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-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

View File

@@ -1,7 +1,7 @@
/*
* FIPS mode utilities
*
* Copyright (C) 2011-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-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

298
lib/utils_io.c Normal file
View File

@@ -0,0 +1,298 @@
/*
* 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) {
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

@@ -1,8 +1,8 @@
/*
* kernel keyring utilities
*
* Copyright (C) 2016-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016, Ondrej Kozina. All rights reserved.
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2018, Ondrej Kozina. 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
@@ -31,7 +31,7 @@
typedef int32_t key_serial_t;
#endif
#include "internal.h"
#include "utils_crypt.h"
#include "utils_keyring.h"
#ifdef KERNEL_KEYRING
@@ -91,80 +91,16 @@ int keyring_add_key_in_thread_keyring(const char *key_desc, const void *key, siz
#ifdef KERNEL_KEYRING
key_serial_t kid;
log_dbg("Loading key %s (%zu bytes) in thread keyring", key_desc, key_size);
kid = add_key("logon", key_desc, key, key_size, KEY_SPEC_THREAD_KEYRING);
if (kid < 0) {
switch (errno) {
case EINVAL:
log_dbg("add_key: the payload data is invalid.");
break;
case ENOMEM:
log_dbg("add_key: insufficient memory to create a key.");
break;
case EDQUOT:
log_dbg("add_key: quota would exceed.");
break;
}
if (kid < 0)
return -errno;
}
return 0;
#else
return -EINVAL;
return -ENOTSUP;
#endif
}
#ifdef KERNEL_KEYRING
static key_serial_t request_key_verbose(const char *type,
const char *key_desc,
const char *callout_info,
key_serial_t keyring)
{
key_serial_t kid;
/*
* Search for a key in this particular order (first found, first served):
*
* 1) thread keyring
* 2) process keyring
* 3) user keyring (if exists) or user session keyring (if exists)
*/
kid = request_key(type, key_desc, callout_info, keyring);
if (kid < 0) {
switch (errno) {
case EACCES:
log_dbg("request_key: The keyring wasn't available for modification by the user.");
break;
case EINTR:
log_dbg("request_key: The request was interrupted by a signal.");
break;
case EDQUOT:
log_dbg("request_key: The key quota for this user would be exceeded by creating this key or linking it to the keyring.");
break;
case EKEYEXPIRED:
log_dbg("request_key: An expired key was found, but no replacement could be obtained.");
break;
case EKEYREVOKED:
log_dbg("request_key: A revoked key was found, but no replacement could be obtained.");
break;
case ENOKEY:
log_dbg("request_key: No matching key was found.");
break;
/* NOTE following error codes are unreachable unless key generation is triggered */
case EKEYREJECTED:
log_dbg("request_key: The attempt to generate a new key was rejected.");
break;
case ENOMEM:
log_dbg("request_key: Insufficient memory to create a key.");
break;
}
}
return kid;
}
#endif
int keyring_get_passphrase(const char *key_desc,
char **passphrase,
size_t *passphrase_len)
@@ -176,10 +112,8 @@ int keyring_get_passphrase(const char *key_desc,
char *buf = NULL;
size_t len = 0;
log_dbg("Looking for key described with '%s'.", key_desc);
do
kid = request_key_verbose("user", key_desc, NULL, 0);
kid = request_key("user", key_desc, NULL, 0);
while (kid < 0 && errno == EINTR);
if (kid < 0)
@@ -201,20 +135,6 @@ int keyring_get_passphrase(const char *key_desc,
err = errno;
crypt_memzero(buf, len);
free(buf);
switch (err) {
case ENOKEY:
log_dbg("keyctl_read: The key specified is invalid.");
break;
case EKEYEXPIRED:
log_dbg("keyctl_read: The key specified has expired.");
break;
case EKEYREVOKED:
log_dbg("keyctl_read: The key specified had been revoked.");
break;
case EACCES:
log_dbg("keyctl_read: The key exists, but is not readable by the calling process.");
break;
}
return -err;
}
@@ -223,8 +143,7 @@ int keyring_get_passphrase(const char *key_desc,
return 0;
#else
log_dbg("Kernel keyring features disabled");
return -EINVAL;
return -ENOTSUP;
#endif
}
@@ -233,32 +152,15 @@ int keyring_revoke_and_unlink_key(const char *key_desc)
#ifdef KERNEL_KEYRING
key_serial_t kid;
log_dbg("requesting keyring key %s for removal", key_desc);
do
kid = request_key_verbose("logon", key_desc, NULL, 0);
kid = request_key("logon", key_desc, NULL, 0);
while (kid < 0 && errno == EINTR);
if (kid < 0)
return 0;
log_dbg("Revoking key %s", key_desc);
if (keyctl_revoke(kid)) {
switch (errno) {
case ENOKEY:
log_dbg ("keyctl_revoke: The specified key does not exist.");
break;
case EKEYREVOKED:
log_dbg("keyctl_revoke: The key has already been revoked.");
break;
case EACCES:
log_dbg("keyctl_revoke: The name key exists, but is not writable by the calling process.");
return -errno;
default:
log_dbg("keyctl_revoke: Unexpected errno: %d", errno);
}
}
if (keyctl_revoke(kid))
return -errno;
/*
* best effort only. the key could have been linked
@@ -271,6 +173,6 @@ int keyring_revoke_and_unlink_key(const char *key_desc)
return 0;
#else
return -EINVAL;
return -ENOTSUP;
#endif
}

View File

@@ -1,8 +1,8 @@
/*
* kernel keyring syscall wrappers
*
* Copyright (C) 2016, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016, Ondrej Kozina. All rights reserved.
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2018, Ondrej Kozina. 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
@@ -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

@@ -1,8 +1,8 @@
/*
* loopback block device utilities
*
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2017, Milan Broz
* 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

View File

@@ -1,8 +1,8 @@
/*
* loopback block device utilities
*
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2017, Milan Broz
* 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

View File

@@ -1,8 +1,8 @@
/*
* utils_pbkdf - PBKDF ssettings for libcryptsetup
*
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2017, Milan Broz
* 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
@@ -38,55 +38,99 @@ const struct crypt_pbkdf_type default_luks1 = {
.time_ms = DEFAULT_LUKS1_ITER_TIME
};
static uint32_t adjusted_phys_memory(void)
{
uint64_t memory_kb = crypt_getphysmemory_kb();
/* Ignore bogus value */
if (memory_kb < (128 * 1024) || memory_kb > UINT32_MAX)
return DEFAULT_LUKS2_MEMORY_KB;
/*
* Never use more than half of physical memory.
* OOM killer is too clever...
*/
memory_kb /= 2;
return memory_kb;
}
/*
* PBKDF configuration interface
*/
int verify_pbkdf_params(struct crypt_device *cd,
const struct crypt_pbkdf_type *pbkdf)
{
struct crypt_pbkdf_limits pbkdf_limits;
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;
}
r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
if (r < 0)
return r;
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)."),
pbkdf_type, pbkdf_limits.min_iterations);
return -EINVAL;
}
return 0;
}
if (pbkdf->max_memory_kb > MAX_PBKDF_MEMORY) {
log_err(cd, _("Requested maximum PBKDF memory cost is too high (maximum is %d kilobytes).\n"),
MAX_PBKDF_MEMORY);
/* 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)."),
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)."),
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)."),
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;
}
@@ -98,9 +142,10 @@ int init_pbkdf_type(struct crypt_device *cd,
const char *dev_type)
{
struct crypt_pbkdf_type *cd_pbkdf = crypt_get_pbkdf(cd);
struct crypt_pbkdf_limits pbkdf_limits;
const char *hash, *type;
unsigned cpus;
uint32_t old_flags;
uint32_t old_flags, memory_kb;
int r;
if (!pbkdf && dev_type && !strcmp(dev_type, CRYPT_LUKS2))
@@ -112,15 +157,19 @@ int init_pbkdf_type(struct crypt_device *cd,
if (r)
return r;
r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
if (r < 0)
return r;
/*
* Crypto backend may be not initialized here,
* cannot check if algorithms are really available.
* 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;
@@ -148,10 +197,10 @@ int init_pbkdf_type(struct crypt_device *cd,
cd_pbkdf->max_memory_kb = pbkdf->max_memory_kb;
cd_pbkdf->parallel_threads = pbkdf->parallel_threads;
if (cd_pbkdf->parallel_threads > MAX_PBKDF_THREADS) {
if (cd_pbkdf->parallel_threads > pbkdf_limits.max_parallel) {
log_dbg("Maximum PBKDF threads is %d (requested %d).",
MAX_PBKDF_THREADS, cd_pbkdf->parallel_threads);
cd_pbkdf->parallel_threads = MAX_PBKDF_THREADS;
pbkdf_limits.max_parallel, cd_pbkdf->parallel_threads);
cd_pbkdf->parallel_threads = pbkdf_limits.max_parallel;
}
if (cd_pbkdf->parallel_threads) {
@@ -164,6 +213,16 @@ int init_pbkdf_type(struct crypt_device *cd,
}
}
if (cd_pbkdf->max_memory_kb) {
memory_kb = adjusted_phys_memory();
if (cd_pbkdf->max_memory_kb > memory_kb) {
log_dbg("Not enough physical memory detected, "
"PBKDF max memory decreased from %dkB to %dkB.",
cd_pbkdf->max_memory_kb, memory_kb);
cd_pbkdf->max_memory_kb = memory_kb;
}
}
log_dbg("PBKDF %s, hash %s, time_ms %u (iterations %u), max_memory_kb %u, parallel_threads %u.",
cd_pbkdf->type ?: "(none)", cd_pbkdf->hash ?: "(none)", cd_pbkdf->time_ms,
cd_pbkdf->iterations, cd_pbkdf->max_memory_kb, cd_pbkdf->parallel_threads);
@@ -194,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;
@@ -218,5 +290,5 @@ void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_m
pbkdf->flags &= ~(CRYPT_PBKDF_NO_BENCHMARK);
pbkdf->iterations = 0;
log_dbg("Iteration time set to %" PRIu64 " miliseconds.", iteration_time_ms);
log_dbg("Iteration time set to %" PRIu64 " milliseconds.", iteration_time_ms);
}

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