Compare commits

...

245 Commits

Author SHA1 Message Date
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
160 changed files with 22635 additions and 10519 deletions

View File

@@ -50,9 +50,7 @@ function check_nonroot
sudo dmsetup version
sudo dmsetup targets
make check || return
#sudo $MAKE install || return
make check
}
function check_root
@@ -77,9 +75,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
@@ -141,14 +137,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)

6
FAQ
View File

@@ -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
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,22 @@ 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.2**
* [cryptsetup-2.0.2.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.2.tar.xz)
* Signature [cryptsetup-2.0.2.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.2.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.2 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.2-ReleaseNotes).
Previous versions
* [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 +81,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 +93,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.3])
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,8 +403,11 @@ 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.])
fi
if test x$enable_internal_argon2 = xyes ; then
@@ -489,6 +492,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 +542,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 +560,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 +578,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,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.

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

View File

@@ -54,6 +54,8 @@ libcryptsetup_la_SOURCES = \
lib/utils_device_locking.c \
lib/utils_device_locking.h \
lib/utils_pbkdf.c \
lib/utils_io.c \
lib/utils_io.h \
lib/libdevmapper.c \
lib/utils_dm.h \
lib/volumekey.c \
@@ -77,6 +79,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 \

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

@@ -19,3 +19,4 @@ libargon2_la_SOURCES = \
lib/crypto_backend/argon2/thread.h
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

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

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

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

@@ -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,50 +44,6 @@ 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
*
@@ -96,7 +52,7 @@ int crypt_cipher_blocksize(const char *name)
* (but cannot check specificaly 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
@@ -213,12 +213,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 +227,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 +248,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 +287,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
@@ -106,10 +106,8 @@ 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;
@@ -130,6 +128,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;
@@ -217,7 +216,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 +267,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
@@ -50,9 +50,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
@@ -37,6 +37,7 @@
#include "utils_dm.h"
#include "utils_fips.h"
#include "utils_keyring.h"
#include "utils_io.h"
#include "crypto_backend.h"
#include "libcryptsetup.h"
@@ -49,16 +50,10 @@
#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
struct crypt_device;
struct volume_key {
@@ -70,8 +65,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,20 +133,12 @@ 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)));
#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)
@@ -199,5 +185,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
* posible all active LUKS2 keyslots must be in LUKS1 compatible mode (i.e. pbkdf
* type must be PBKDF2) and device cannot be formated with any authenticated
* 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 LUKS1 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,9 @@ int crypt_load(struct crypt_device *cd,
*
* @returns 0 on success or negative errno value otherwise.
*
* @note Does not support LUKS2 devices explicitly. LUKS2 header is auto-repaired
* (if exactly one header checksum does not match) automatically on
* crypt_load().
*/
int crypt_repair(struct crypt_device *cd,
const char *requested_type,
@@ -627,10 +650,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 +682,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 +701,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 +750,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 +772,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 +798,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 +827,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 +847,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 +862,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 +874,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 +954,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 +980,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);
/** @} */
/**
@@ -990,7 +1066,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 +1092,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 +1110,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 +1124,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 +1150,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 +1215,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 +1451,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 +1525,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 +1568,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 +1610,34 @@ 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 keyfile offset
* @param keyfile_size_max maximal size of keyfile to read
* @param flags keyfile read flags
*
* @return @e 0 on success or negative errno value otherwise.
*/
int crypt_keyfile_device_read(struct crypt_device *cd,
const char *keyfile,
char **key, size_t *key_size_read,
uint64_t keyfile_offset,
size_t keyfile_size_max,
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) */
uint32_t flags);
/** Read key only to the first end of line (\\n). */
#define CRYPT_KEYFILE_STOP_EOL (1 << 0)
/** @} */
@@ -1580,13 +1697,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 +1729,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 +1765,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 +1834,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.
*

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

View File

@@ -2,7 +2,7 @@
* 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.

View File

@@ -2,7 +2,7 @@
* 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.

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;
}
@@ -1026,7 +1025,7 @@ static int LUKS_open_key(unsigned int keyIndex,
r = -EPERM;
if (!r)
log_verbose(ctx, _("Key slot %d unlocked.\n"), keyIndex);
log_verbose(ctx, _("Key slot %d unlocked."), keyIndex);
out:
crypt_safe_free(AfKey);
crypt_free_volume_key(derived_key);
@@ -1061,7 +1060,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 +1077,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 +1091,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.
@@ -138,6 +157,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 +174,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 +210,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 +251,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 +276,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 +290,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 +330,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 +358,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
@@ -98,6 +98,7 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
int 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,8 +111,12 @@ 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)

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

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,6 +33,11 @@
#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
*/
@@ -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,8 +208,7 @@ 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
@@ -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;

View File

@@ -1,9 +1,9 @@
/*
* 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-2017, Ondrej Kozina. All rights reserved.
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
* Copyright (C) 2015-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
@@ -26,6 +26,8 @@
#include <ctype.h>
#include <uuid/uuid.h>
#define LUKS_STRIPES 4000
struct interval {
uint64_t offset;
uint64_t length;
@@ -57,7 +59,8 @@ void JSON_DBG(json_object *jobj, const char *desc)
/* FIXME: make this conditional and disable for stable release. */
if (desc)
log_dbg("%s:", desc);
log_dbg("%s", json_object_to_json_string_ext(jobj, JSON_C_TO_STRING_PRETTY));
log_dbg("%s", json_object_to_json_string_ext(jobj,
JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE));
}
/*
@@ -68,7 +71,7 @@ struct json_object *LUKS2_array_jobj(struct json_object *array, const char *num)
struct json_object *jobj1;
int i;
for (i = 0; i < json_object_array_length(array); i++) {
for (i = 0; i < (int) json_object_array_length(array); i++) {
jobj1 = json_object_array_get_idx(array, i);
if (!strcmp(num, json_object_get_string(jobj1)))
return jobj1;
@@ -88,7 +91,7 @@ struct json_object *LUKS2_array_remove(struct json_object *array, const char *nu
/* Create new array without jobj_removing. */
array_new = json_object_new_array();
for (i = 0; i < json_object_array_length(array); i++) {
for (i = 0; i < (int) json_object_array_length(array); i++) {
jobj1 = json_object_array_get_idx(array, i);
if (jobj1 != jobj_removing)
json_object_array_add(array_new, json_object_get(jobj1));
@@ -105,7 +108,7 @@ json_object *LUKS2_get_keyslot_jobj(struct luks2_hdr *hdr, int keyslot)
json_object *jobj1, *jobj2;
char keyslot_name[16];
if (!hdr)
if (!hdr || keyslot < 0)
return NULL;
if (snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1)
@@ -118,20 +121,31 @@ json_object *LUKS2_get_keyslot_jobj(struct luks2_hdr *hdr, int keyslot)
return jobj2;
}
json_object *LUKS2_get_tokens_jobj(struct luks2_hdr *hdr)
{
json_object *jobj_tokens;
if (!hdr || !json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens))
return NULL;
return jobj_tokens;
}
json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token)
{
json_object *jobj1, *jobj2;
char token_name[16];
if (!hdr)
if (!hdr || token < 0)
return NULL;
jobj1 = LUKS2_get_tokens_jobj(hdr);
if (!jobj1)
return NULL;
if (snprintf(token_name, sizeof(token_name), "%u", token) < 1)
return NULL;
if (!json_object_object_get_ex(hdr->jobj, "tokens", &jobj1))
return NULL;
json_object_object_get_ex(jobj1, token_name, &jobj2);
return jobj2;
}
@@ -141,7 +155,7 @@ json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int digest)
json_object *jobj1, *jobj2;
char digest_name[16];
if (!hdr)
if (!hdr || digest < 0)
return NULL;
if (snprintf(digest_name, sizeof(digest_name), "%u", digest) < 1)
@@ -159,7 +173,7 @@ json_object *LUKS2_get_segment_jobj(struct luks2_hdr *hdr, int segment)
json_object *jobj1, *jobj2;
char segment_name[16];
if (!hdr)
if (!hdr || segment < 0)
return NULL;
if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)
@@ -184,7 +198,6 @@ uint32_t json_object_get_uint32(json_object *jobj)
}
/* jobj has to be json_type_string and numbered */
/* FIXME: sscanf() instead? */
static json_bool json_str_to_uint64(json_object *jobj, uint64_t *value)
{
char *endptr;
@@ -192,7 +205,7 @@ static json_bool json_str_to_uint64(json_object *jobj, uint64_t *value)
errno = 0;
tmp = strtoull(json_object_get_string(jobj), &endptr, 10);
if (*endptr || errno || tmp >= UINT64_MAX) {
if (*endptr || errno) {
log_dbg("Failed to parse uint64_t type from string %s.",
json_object_get_string(jobj));
*value = 0;
@@ -209,6 +222,21 @@ uint64_t json_object_get_uint64(json_object *jobj)
return json_str_to_uint64(jobj, &r) ? r : 0;
}
json_object *json_object_new_uint64(uint64_t value)
{
/* 18446744073709551615 */
char num[21];
int r;
json_object *jobj;
r = snprintf(num, sizeof(num), "%" PRIu64, value);
if (r < 0 || (size_t)r >= sizeof(num))
return NULL;
jobj = json_object_new_string(num);
return jobj;
}
/*
* Validate helpers
*/
@@ -224,8 +252,8 @@ static json_bool numbered(const char *name, const char *key)
return TRUE;
}
static json_object *contains(json_object *jobj, const char *name,
const char *section, const char *key, json_type type)
json_object *json_contains(json_object *jobj, const char *name,
const char *section, const char *key, json_type type)
{
json_object *sobj;
@@ -280,7 +308,7 @@ static json_bool validate_json_uint32(json_object *jobj)
static json_bool validate_keyslots_array(json_object *jarr, json_object *jobj_keys)
{
json_object *jobj;
int i = 0, length = json_object_array_length(jarr);
int i = 0, length = (int) json_object_array_length(jarr);
while (i < length) {
jobj = json_object_array_get_idx(jarr, i);
@@ -289,7 +317,8 @@ static json_bool validate_keyslots_array(json_object *jarr, json_object *jobj_ke
return FALSE;
}
if (!contains(jobj_keys, "", "Keyslots section", json_object_get_string(jobj), json_type_object))
if (!json_contains(jobj_keys, "", "Keyslots section",
json_object_get_string(jobj), json_type_object))
return FALSE;
i++;
@@ -301,7 +330,7 @@ static json_bool validate_keyslots_array(json_object *jarr, json_object *jobj_ke
static json_bool validate_segments_array(json_object *jarr, json_object *jobj_segments)
{
json_object *jobj;
int i = 0, length = json_object_array_length(jarr);
int i = 0, length = (int) json_object_array_length(jarr);
while (i < length) {
jobj = json_object_array_get_idx(jarr, i);
@@ -310,7 +339,8 @@ static json_bool validate_segments_array(json_object *jarr, json_object *jobj_se
return FALSE;
}
if (!contains(jobj_segments, "", "Segments section", json_object_get_string(jobj), json_type_object))
if (!json_contains(jobj_segments, "", "Segments section",
json_object_get_string(jobj), json_type_object))
return FALSE;
i++;
@@ -377,9 +407,9 @@ int LUKS2_keyslot_validate(json_object *hdr_jobj, json_object *hdr_keyslot, cons
{
json_object *jobj_key_size;
if (!contains(hdr_keyslot, key, "Keyslot", "type", json_type_string))
if (!json_contains(hdr_keyslot, key, "Keyslot", "type", json_type_string))
return 1;
if (!(jobj_key_size = contains(hdr_keyslot, key, "Keyslot", "key_size", json_type_int)))
if (!(jobj_key_size = json_contains(hdr_keyslot, key, "Keyslot", "key_size", json_type_int)))
return 1;
/* enforce uint32_t type */
@@ -402,10 +432,10 @@ int LUKS2_token_validate(json_object *hdr_jobj, json_object *jobj_token, const c
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return 1;
if (!contains(jobj_token, key, "Token", "type", json_type_string))
if (!json_contains(jobj_token, key, "Token", "type", json_type_string))
return 1;
jarr = contains(jobj_token, key, "Token", "keyslots", json_type_array);
jarr = json_contains(jobj_token, key, "Token", "keyslots", json_type_array);
if (!jarr)
return 1;
@@ -418,11 +448,18 @@ int LUKS2_token_validate(json_object *hdr_jobj, json_object *jobj_token, const c
static int hdr_validate_json_size(json_object *hdr_jobj)
{
json_object *jobj, *jobj1;
const char *json;
uint64_t json_area_size, json_size;
json_object_object_get_ex(hdr_jobj, "config", &jobj);
json_object_object_get_ex(jobj, "json_size", &jobj1);
return (strlen(json_object_to_json_string_ext(hdr_jobj, JSON_C_TO_STRING_PLAIN)) > json_object_get_uint64(jobj1));
json = json_object_to_json_string_ext(hdr_jobj,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
json_area_size = json_object_get_uint64(jobj1);
json_size = (uint64_t)strlen(json);
return json_size > json_area_size ? 1 : 0;
}
int LUKS2_check_json_size(const struct luks2_hdr *hdr)
@@ -493,20 +530,20 @@ static int hdr_validate_segments(json_object *hdr_jobj)
if (!numbered("Segment", key))
return 1;
if (!contains(val, key, "Segment", "type", json_type_string) ||
!(jobj_offset = contains(val, key, "Segment", "offset", json_type_string)) ||
!(jobj_ivoffset = contains(val, key, "Segment", "iv_tweak", json_type_string)) ||
!(jobj_length = contains(val, key, "Segment", "size", json_type_string)) ||
!contains(val, key, "Segment", "encryption", json_type_string) ||
!(jobj_sector_size = contains(val, key, "Segment", "sector_size", json_type_int)))
if (!json_contains(val, key, "Segment", "type", json_type_string) ||
!(jobj_offset = json_contains(val, key, "Segment", "offset", json_type_string)) ||
!(jobj_ivoffset = json_contains(val, key, "Segment", "iv_tweak", json_type_string)) ||
!(jobj_length = json_contains(val, key, "Segment", "size", json_type_string)) ||
!json_contains(val, key, "Segment", "encryption", json_type_string) ||
!(jobj_sector_size = json_contains(val, key, "Segment", "sector_size", json_type_int)))
return 1;
/* integrity */
if (json_object_object_get_ex(val, "integrity", &jobj_integrity)) {
if (!contains(val, key, "Segment", "integrity", json_type_object) ||
!contains(jobj_integrity, key, "Segment integrity", "type", json_type_string) ||
!contains(jobj_integrity, key, "Segment integrity", "journal_encryption", json_type_string) ||
!contains(jobj_integrity, key, "Segment integrity", "journal_integrity", json_type_string))
if (!json_contains(val, key, "Segment", "integrity", json_type_object) ||
!json_contains(jobj_integrity, key, "Segment integrity", "type", json_type_string) ||
!json_contains(jobj_integrity, key, "Segment integrity", "journal_encryption", json_type_string) ||
!json_contains(jobj_integrity, key, "Segment integrity", "journal_integrity", json_type_string))
return 1;
}
@@ -570,11 +607,9 @@ static int hdr_validate_areas(json_object *hdr_jobj)
int length, ret, i = 0;
uint64_t first_offset;
/* keyslots should already be validated */
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return 1;
/* segments should already be validated */
if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
return 1;
@@ -597,9 +632,9 @@ static int hdr_validate_areas(json_object *hdr_jobj)
json_object_object_foreach(jobj_keyslots, key, val) {
if (!(jobj_area = contains(val, key, "Keyslot", "area", json_type_object)) ||
!(jobj_offset = contains(jobj_area, key, "Keyslot", "offset", json_type_string)) ||
!(jobj_length = contains(jobj_area, key, "Keyslot", "size", json_type_string)) ||
if (!(jobj_area = json_contains(val, key, "Keyslot", "area", json_type_object)) ||
!(jobj_offset = json_contains(jobj_area, key, "Keyslot", "offset", json_type_string)) ||
!(jobj_length = json_contains(jobj_area, key, "Keyslot", "size", json_type_string)) ||
!numbered("offset", json_object_get_string(jobj_offset)) ||
!numbered("size", json_object_get_string(jobj_length))) {
free(intervals);
@@ -651,9 +686,9 @@ static int hdr_validate_digests(json_object *hdr_jobj)
if (!numbered("Digest", key))
return 1;
if (!contains(val, key, "Digest", "type", json_type_string) ||
!(jarr_keys = contains(val, key, "Digest", "keyslots", json_type_array)) ||
!(jarr_segs = contains(val, key, "Digest", "segments", json_type_array)))
if (!json_contains(val, key, "Digest", "type", json_type_string) ||
!(jarr_keys = json_contains(val, key, "Digest", "keyslots", json_type_array)) ||
!(jarr_segs = json_contains(val, key, "Digest", "segments", json_type_array)))
return 1;
if (!validate_keyslots_array(jarr_keys, jobj_keyslots))
@@ -721,7 +756,7 @@ static int hdr_validate_config(json_object *hdr_jobj)
return 1;
}
if (!(jobj = contains(jobj_config, "section", "Config", "json_size", json_type_string)) ||
if (!(jobj = json_contains(jobj_config, "section", "Config", "json_size", json_type_string)) ||
!json_str_to_uint64(jobj, &json_size))
return 1;
@@ -736,7 +771,7 @@ static int hdr_validate_config(json_object *hdr_jobj)
return 1;
}
if (!(jobj = contains(jobj_config, "section", "Config", "keyslots_size", json_type_string)))
if (!(jobj = json_contains(jobj_config, "section", "Config", "keyslots_size", json_type_string)))
return 1;
if (validate_keyslots_size(hdr_jobj, jobj))
@@ -744,27 +779,27 @@ static int hdr_validate_config(json_object *hdr_jobj)
/* Flags array is optional */
if (json_object_object_get_ex(jobj_config, "flags", &jobj)) {
if (!contains(jobj_config, "section", "Config", "flags", json_type_array))
if (!json_contains(jobj_config, "section", "Config", "flags", json_type_array))
return 1;
/* All array members must be strings */
for (i = 0; i < json_object_array_length(jobj); i++)
for (i = 0; i < (int) json_object_array_length(jobj); i++)
if (!json_object_is_type(json_object_array_get_idx(jobj, i), json_type_string))
return 1;
}
/* Requirements object is optional */
if (json_object_object_get_ex(jobj_config, "requirements", &jobj)) {
if (!contains(jobj_config, "section", "Config", "requirements", json_type_object))
if (!json_contains(jobj_config, "section", "Config", "requirements", json_type_object))
return 1;
/* Mandatory array is optional */
if (json_object_object_get_ex(jobj, "mandatory", &jobj1)) {
if (!contains(jobj, "section", "Requirements", "mandatory", json_type_array))
if (!json_contains(jobj, "section", "Requirements", "mandatory", json_type_array))
return 1;
/* All array members must be strings */
for (i = 0; i < json_object_array_length(jobj1); i++)
for (i = 0; i < (int) json_object_array_length(jobj1); i++)
if (!json_object_is_type(json_object_array_get_idx(jobj1, i), json_type_string))
return 1;
}
@@ -800,6 +835,10 @@ int LUKS2_hdr_validate(json_object *hdr_jobj)
return 1;
}
/* validate keyslot implementations */
if (LUKS2_keyslots_validate(hdr_jobj))
return 1;
return 0;
}
@@ -809,7 +848,7 @@ int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr)
r = device_read_lock(cd, crypt_metadata_device(cd));
if (r) {
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
log_err(cd, _("Failed to acquire read lock on device %s."),
device_path(crypt_metadata_device(cd)));
return r;
}
@@ -821,7 +860,7 @@ int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr)
r = device_write_lock(cd, crypt_metadata_device(cd));
if (r) {
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
log_err(cd, _("Failed to acquire write lock on device %s."),
device_path(crypt_metadata_device(cd)));
return r;
}
@@ -835,17 +874,11 @@ int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr)
return r;
}
/* NOTE: is called before LUKS2 validation routines */
static void LUKS2_hdr_free_unused_objects(struct crypt_device *cd, struct luks2_hdr *hdr)
{
/* erase unused digests (no assigned keyslot or segment) */
LUKS2_digests_erase_unused(cd, hdr);
}
int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr)
{
/* FIXME: we risk to hide future intenal implementation bugs with this */
LUKS2_hdr_free_unused_objects(cd, hdr);
/* NOTE: is called before LUKS2 validation routines */
/* erase unused digests (no assigned keyslot or segment) */
LUKS2_digests_erase_unused(cd, hdr);
if (LUKS2_hdr_validate(hdr->jobj))
return -EINVAL;
@@ -858,7 +891,7 @@ int LUKS2_hdr_uuid(struct crypt_device *cd, struct luks2_hdr *hdr, const char *u
uuid_t partitionUuid;
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
log_err(cd, _("Wrong LUKS UUID format provided.\n"));
log_err(cd, _("Wrong LUKS UUID format provided."));
return -EINVAL;
}
if (!uuid)
@@ -866,8 +899,7 @@ int LUKS2_hdr_uuid(struct crypt_device *cd, struct luks2_hdr *hdr, const char *u
uuid_unparse(partitionUuid, hdr->uuid);
/* FIXME: why is this not LUKS2_hdr_write? */
return LUKS2_disk_hdr_write(cd, hdr, crypt_metadata_device(cd));
return LUKS2_hdr_write(cd, hdr);
}
int LUKS2_hdr_labels(struct crypt_device *cd, struct luks2_hdr *hdr,
@@ -939,7 +971,7 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
r = device_read_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
log_err(cd, _("Failed to acquire read lock on device %s."),
device_path(crypt_metadata_device(cd)));
crypt_safe_free(buffer);
return r;
@@ -948,7 +980,7 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
devfd = device_open_locked(device, O_RDONLY);
if (devfd < 0) {
device_read_unlock(device);
log_err(cd, _("Device %s is not a valid LUKS device.\n"), device_path(device));
log_err(cd, _("Device %s is not a valid LUKS device."), device_path(device));
crypt_safe_free(buffer);
return devfd == -1 ? -EINVAL : devfd;
}
@@ -967,14 +999,14 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
if (devfd == -1) {
if (errno == EEXIST)
log_err(cd, _("Requested header backup file %s already exists.\n"), backup_file);
log_err(cd, _("Requested header backup file %s already exists."), backup_file);
else
log_err(cd, _("Cannot create header backup file %s.\n"), backup_file);
log_err(cd, _("Cannot create header backup file %s."), backup_file);
crypt_safe_free(buffer);
return -EINVAL;
}
if (write_buffer(devfd, buffer, buffer_size) < buffer_size) {
log_err(cd, _("Cannot write header backup file %s.\n"), backup_file);
log_err(cd, _("Cannot write header backup file %s."), backup_file);
r = -EIO;
} else
r = 0;
@@ -1012,7 +1044,7 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
/* FIXME: why lock backup device ? */
r = device_read_lock(cd, backup_device);
if (r) {
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
log_err(cd, _("Failed to acquire read lock on device %s."),
device_path(backup_device));
device_free(backup_device);
return r;
@@ -1023,13 +1055,13 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
device_free(backup_device);
if (r < 0) {
log_err(cd, _("Backup file doesn't contain valid LUKS header.\n"));
log_err(cd, _("Backup file doesn't contain valid LUKS header."));
goto out;
}
/* do not allow header restore from backup with unmet requirements */
if (LUKS2_unmet_requirements(cd, &hdr_file, 0, 1)) {
log_err(cd, _("Forbidden LUKS2 requirements detected in backup %s.\n"),
log_err(cd, _("Forbidden LUKS2 requirements detected in backup %s."),
backup_file);
r = -ETXTBSY;
goto out;
@@ -1044,13 +1076,13 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
devfd = open(backup_file, O_RDONLY);
if (devfd == -1) {
log_err(cd, _("Cannot open header backup file %s.\n"), backup_file);
log_err(cd, _("Cannot open header backup file %s."), backup_file);
r = -EINVAL;
goto out;
}
if (read_buffer(devfd, buffer, buffer_size) < buffer_size) {
log_err(cd, _("Cannot read header backup file %s.\n"), backup_file);
log_err(cd, _("Cannot read header backup file %s."), backup_file);
r = -EIO;
goto out;
}
@@ -1070,13 +1102,13 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
if (!reqs_reencrypt(reqs)) {
log_dbg("Checking LUKS2 header size and offsets.");
if (LUKS2_get_data_offset(&tmp_hdr) != LUKS2_get_data_offset(&hdr_file)) {
log_err(cd, _("Data offset differ on device and backup, restore failed.\n"));
log_err(cd, _("Data offset differ on device and backup, restore failed."));
r = -EINVAL;
goto out;
}
/* FIXME: what could go wrong? Erase if we're fine with consequences */
if (buffer_size != (ssize_t) LUKS2_hdr_and_areas_size(tmp_hdr.jobj)) {
log_err(cd, _("Binary header with keyslot areas size differ on device and backup, restore failed.\n"));
log_err(cd, _("Binary header with keyslot areas size differ on device and backup, restore failed."));
r = -EINVAL;
goto out;
}
@@ -1106,7 +1138,7 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
/* TODO: perform header restore on bdev in stand-alone routine? */
r = device_write_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
log_err(cd, _("Failed to acquire write lock on device %s."),
device_path(device));
goto out;
}
@@ -1114,10 +1146,10 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
devfd = device_open_locked(device, O_RDWR);
if (devfd < 0) {
if (errno == EACCES)
log_err(cd, _("Cannot write to device %s, permission denied.\n"),
log_err(cd, _("Cannot write to device %s, permission denied."),
device_path(device));
else
log_err(cd, _("Cannot open device %s.\n"), device_path(device));
log_err(cd, _("Cannot open device %s."), device_path(device));
device_write_unlock(device);
r = -EINVAL;
goto out;
@@ -1167,30 +1199,32 @@ static const struct {
int LUKS2_config_get_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *flags)
{
json_object *jobj1, *jobj_config, *jobj_flags;
int i, j;
int i, j, found;
if (!hdr || !flags)
return -EINVAL;
*flags = 0;
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
return 0;
if (!json_object_object_get_ex(jobj_config, "flags", &jobj_flags))
return 0;
for (i = 0; i < json_object_array_length(jobj_flags); i++) {
for (i = 0; i < (int) json_object_array_length(jobj_flags); i++) {
jobj1 = json_object_array_get_idx(jobj_flags, i);
for (j = 0; persistent_flags[j].description; j++) {
for (j = 0, found = 0; persistent_flags[j].description && !found; j++)
if (!strcmp(persistent_flags[j].description,
json_object_get_string(jobj1))) {
*flags |= persistent_flags[j].flag;
log_dbg("Using persistent flag %s.",
json_object_get_string(jobj1));
break;
found = 1;
}
if (!found)
log_verbose(cd, _("Ignored unknown flag %s."),
json_object_get_string(jobj1));
}
json_object_get_string(jobj1));
}
return 0;
@@ -1273,8 +1307,8 @@ int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory))
return 0;
len = json_object_array_length(jobj_mandatory);
if (!len)
len = (int) json_object_array_length(jobj_mandatory);
if (len <= 0)
return 0;
log_dbg("LUKS2 requirements detected:");
@@ -1317,7 +1351,7 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
/* any remaining bit in requirements is unknown therefore illegal */
if (reqs) {
log_dbg("Illegal requiremnt flag(s) requested");
log_dbg("Illegal requirement flag(s) requested");
goto err;
}
@@ -1333,7 +1367,7 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
json_object_object_add(jobj_config, "requirements", jobj_requirements);
}
if (json_object_array_length(jobj_mandatory)) {
if (json_object_array_length(jobj_mandatory) > 0) {
/* replace mandatory field with new values */
json_object_object_add(jobj_requirements, "mandatory", jobj_mandatory);
} else {
@@ -1365,10 +1399,10 @@ static void hdr_dump_config(struct crypt_device *cd, json_object *hdr_jobj)
if (json_object_object_get_ex(hdr_jobj, "config", &jobj_config)) {
if (json_object_object_get_ex(jobj_config, "flags", &jobj_flags))
flags = json_object_array_length(jobj_flags);
flags = (int) json_object_array_length(jobj_flags);
if (json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements) &&
json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory))
reqs = json_object_array_length(jobj_mandatory);
reqs = (int) json_object_array_length(jobj_mandatory);
}
for (i = 0; i < flags; i++) {
@@ -1376,9 +1410,9 @@ static void hdr_dump_config(struct crypt_device *cd, json_object *hdr_jobj)
log_std(cd, "%s ", json_object_get_string(jobj1));
}
log_std(cd, "%s\n%s", flags ? "" : "(no flags)", reqs ? "" : "\n");
log_std(cd, "%s\n%s", flags > 0 ? "" : "(no flags)", reqs > 0 ? "" : "\n");
if (reqs) {
if (reqs > 0) {
log_std(cd, "Requirements:\t");
for (i = 0; i < reqs; i++) {
jobj1 = json_object_array_get_idx(jobj_mandatory, i);
@@ -1441,7 +1475,7 @@ static void hdr_dump_keyslots(struct crypt_device *cd, json_object *hdr_jobj)
json_object_object_get_ex(hdr_jobj, "digests", &digests_jobj);
json_object_object_foreach(digests_jobj, key2, val2) {
json_object_object_get_ex(val2, "keyslots", &jobj2);
for (i = 0; i < json_object_array_length(jobj2); i++) {
for (i = 0; i < (int) json_object_array_length(jobj2); i++) {
jobj3 = json_object_array_get_idx(jobj2, i);
if (!strcmp(slot, json_object_get_string(jobj3))) {
log_std(cd, "\tDigest ID: %s\n", key2);
@@ -1474,7 +1508,7 @@ static void hdr_dump_tokens(struct crypt_device *cd, json_object *hdr_jobj)
LUKS2_token_dump(cd, j);
json_object_object_get_ex(val, "keyslots", &jobj2);
for (i = 0; i < json_object_array_length(jobj2); i++) {
for (i = 0; i < (int) json_object_array_length(jobj2); i++) {
jobj3 = json_object_array_get_idx(jobj2, i);
log_std(cd, "\tKeyslot: %s\n", json_object_get_string(jobj3));
}
@@ -1587,17 +1621,89 @@ const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment)
return NULL;
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj1))
return 0;
return NULL;
if (!json_object_object_get_ex(jobj1, buf, &jobj2))
return 0;
return NULL;
if (!json_object_object_get_ex(jobj2, "encryption", &jobj3))
return 0;
return NULL;
return json_object_get_string(jobj3);
}
static int luks2_keyslot_af_params(json_object *jobj_af, struct luks2_keyslot_params *params)
{
int r;
json_object *jobj_type, *jobj1;
/* currently we only support luks1 AF */
json_object_object_get_ex(jobj_af, "type", &jobj_type);
if (strcmp(json_object_get_string(jobj_type), "luks1"))
return 1;
/* process luks1 af params */
json_object_object_get_ex(jobj_af, "stripes", &jobj1);
params->af.luks1.stripes = json_object_get_int(jobj1);
if (params->af.luks1.stripes != LUKS_STRIPES)
return 1;
json_object_object_get_ex(jobj_af, "hash", &jobj1);
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash), "%s",
json_object_get_string(jobj1));
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
return 1;
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
return 0;
}
static int luks2_keyslot_area_params(json_object *jobj_area, struct luks2_keyslot_params *params)
{
int r;
json_object *jobj_type, *jobj1;
/* currently we only support raw length preserving area encryption */
json_object_object_get_ex(jobj_area, "type", &jobj_type);
if (strcmp(json_object_get_string(jobj_type), "raw"))
return 1;
/* process raw area encryption params */
json_object_object_get_ex(jobj_area, "encryption", &jobj1);
r = snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption), "%s",
json_object_get_string(jobj1));
if (r < 0 || (size_t)r >= sizeof(params->area.raw.encryption))
return 1;
json_object_object_get_ex(jobj_area, "key_size", &jobj1);
params->area.raw.key_size = json_object_get_int(jobj1);
params->area_type = LUKS2_KEYSLOT_AREA_RAW;
return 0;
}
/* keyslot must be validated */
int LUKS2_get_keyslot_params(struct luks2_hdr *hdr, int keyslot, struct luks2_keyslot_params *params)
{
json_object *jobj_keyslot, *jobj_af, *jobj_area;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -ENOENT;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af))
return -EINVAL;
if (luks2_keyslot_af_params(jobj_af, params))
return -EINVAL;
if (luks2_keyslot_area_params(jobj_area, params))
return -EINVAL;
return 0;
}
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment)
{
json_object *jobj1, *jobj2, *jobj3, *jobj4;
@@ -1607,16 +1713,16 @@ const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment)
return NULL;
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj1))
return 0;
return NULL;
if (!json_object_object_get_ex(jobj1, buf, &jobj2))
return 0;
return NULL;
if (!json_object_object_get_ex(jobj2, "integrity", &jobj3))
return 0;
return NULL;
if (!json_object_object_get_ex(jobj3, "type", &jobj4))
return 0;
return NULL;
return json_object_get_string(jobj4);
}
@@ -1654,13 +1760,13 @@ static int LUKS2_keyslot_get_volume_key_size(struct luks2_hdr *hdr, const char *
json_object *jobj1, *jobj2, *jobj3;
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj1))
return 0;
return -1;
if (!json_object_object_get_ex(jobj1, keyslot, &jobj2))
return 0;
return -1;
if (!json_object_object_get_ex(jobj2, "key_size", &jobj3))
return 0;
return -1;
return json_object_get_int(jobj3);
}
@@ -1692,7 +1798,7 @@ int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment)
if (!LUKS2_array_jobj(jobj_digest_segments, buf))
continue;
if (!json_object_array_length(jobj_digest_keyslots))
if (json_object_array_length(jobj_digest_keyslots) <= 0)
continue;
jobj1 = json_object_array_get_idx(jobj_digest_keyslots, 0);
@@ -1729,20 +1835,19 @@ int LUKS2_activate(struct crypt_device *cd,
struct crypt_dm_active_device dmd = {
.target = DM_CRYPT,
.uuid = crypt_get_uuid(cd),
.flags = flags,
.size = 0,
.data_device = crypt_data_device(cd),
.u.crypt = {
.vk = vk,
.offset = crypt_get_data_offset(cd),
.cipher = LUKS2_get_cipher(hdr, 0),
.cipher = LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT),
.integrity = crypt_get_integrity(cd),
.iv_offset = 0,
.tag_size = crypt_get_integrity_tag_size(cd),
.sector_size = crypt_get_sector_size(cd)
}
};
char dm_int_name[PATH_MAX], dm_int_dev_name[PATH_MAX];
char dm_int_name[512], dm_int_dev_name[PATH_MAX];
struct device *device = NULL;
/* do not allow activation when particular requirements detected */
@@ -1753,6 +1858,8 @@ int LUKS2_activate(struct crypt_device *cd,
if (!(flags & CRYPT_ACTIVATE_IGNORE_PERSISTENT))
LUKS2_config_get_flags(cd, hdr, &dmd.flags);
dmd.flags |= flags;
if (dmd.flags & CRYPT_ACTIVATE_SHARED)
device_check = DEV_SHARED;
else
@@ -1760,7 +1867,7 @@ int LUKS2_activate(struct crypt_device *cd,
if (dmd.u.crypt.tag_size) {
if (!LUKS2_integrity_compatible(hdr)) {
log_err(cd, "Unsupported device integrity configuration.\n");
log_err(cd, "Unsupported device integrity configuration.");
return -EINVAL;
}
@@ -1787,7 +1894,8 @@ int LUKS2_activate(struct crypt_device *cd,
crypt_get_data_offset(cd) * SECTOR_SIZE,
&dmd.size);
if (r < 0) {
log_err(cd, "Cannot detect integrity device size.\n");
log_err(cd, "Cannot detect integrity device size.");
device_free(device);
dm_remove_device(cd, dm_int_name, 0);
return r;
}
@@ -1812,14 +1920,14 @@ int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uin
if (r) {
if (!quiet)
log_err(cd, _("Failed to read LUKS2 requierements.\n"));
log_err(cd, _("Failed to read LUKS2 requirements."));
return r;
}
/* do not mask unknown requirements check */
if (reqs_unknown(reqs)) {
if (!quiet)
log_err(cd, _("Unmet LUKS2 requirements detected.\n"));
log_err(cd, _("Unmet LUKS2 requirements detected."));
return -ETXTBSY;
}
@@ -1827,8 +1935,31 @@ int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uin
reqs &= ~reqs_mask;
if (reqs_reencrypt(reqs) && !quiet)
log_err(cd, _("Offline reencryption in progress. Aborting.\n"));
log_err(cd, _("Offline reencryption in progress. Aborting."));
/* any remaining unmasked requirement fails the check */
return reqs ? -EINVAL : 0;
}
/*
* NOTE: this routine is called on json object that failed validation.
* Proceed with caution :)
*
* known glitches so far:
*
* any version < 2.0.3:
* - luks2 keyslot pbkdf params change via crypt_keyslot_change_by_passphrase()
* could leave previous type parameters behind. Correct this by purging
* all params not needed by current type.
*/
void LUKS2_hdr_repair(json_object *hdr_jobj)
{
json_object *jobj_keyslots;
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return;
if (!json_object_is_type(jobj_keyslots, json_type_object))
return;
LUKS2_keyslots_repair(jobj_keyslots);
}

View File

@@ -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 -EINVAL;
/* 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 accidentaly 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 keyfile_size_max,
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,17 +166,17 @@ 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 not requested otherwise, we limit input to prevent memory exhaustion */
if (keyfile_size_max == 0) {
keyfile_size_max = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1;
unlimited_read = 1;
@@ -433,21 +188,21 @@ int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile,
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)
if (file_read_size >= (uint64_t)keyfile_size_max)
buflen = keyfile_size_max;
else if (file_read_size)
buflen = file_read_size;
@@ -456,13 +211,13 @@ 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;
}
@@ -471,7 +226,7 @@ int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile,
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;
}
@@ -491,7 +246,7 @@ int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile,
}
char_read = read_buffer(fd, &pass[i], char_to_read);
if (char_read < 0) {
log_err(cd, _("Error reading passphrase.\n"));
log_err(cd, _("Error reading passphrase."));
r = -EPIPE;
goto out_err;
}
@@ -515,12 +270,12 @@ int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile,
/* Fail if we exceeded internal default (no specified size) */
if (unlimited_read && i == keyfile_size_max) {
log_err(cd, _("Maximum keyfile size exceeded.\n"));
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"));
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;

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;

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 */
@@ -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,7 +177,7 @@ 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 */
!fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
!stat(res, &buf_b) && /* does path file stil exist? */
same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
/* coverity[toctou] */

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

280
lib/utils_io.c Normal file
View File

@@ -0,0 +1,280 @@
/*
* 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"
ssize_t read_buffer(int fd, void *buf, size_t length)
{
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)
return (ssize_t)read_size;
if (r > 0) {
read_size += (size_t)r;
buf = (uint8_t*)buf + r;
}
} while (read_size != length);
return (ssize_t)length;
}
ssize_t write_buffer(int fd, const void *buf, size_t length)
{
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)
return (ssize_t)write_size;
if (w > 0) {
write_size += (size_t) w;
buf = (const uint8_t*)buf + w;
}
} while (write_size != length);
return (ssize_t)write_size;
}
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;
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 = 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) {
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, frontHang + innerCount);
if (r < 0 || r != (ssize_t)(frontHang + innerCount))
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) {
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;
}

38
lib/utils_io.h Normal file
View File

@@ -0,0 +1,38 @@
/*
* 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
ssize_t read_buffer(int fd, void *buf, size_t length);
ssize_t write_buffer(int fd, const void *buf, size_t length);
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

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,12 +38,30 @@ 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;
@@ -53,40 +71,64 @@ int verify_pbkdf_params(struct crypt_device *cd,
/* 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 can not be zero."));
r = -EINVAL;
}
if (!pbkdf->parallel_threads) {
log_err(cd, _("Requested PBKDF parallel threads can not be zero.\n"));
log_err(cd, _("Requested PBKDF parallel threads can not be zero."));
r = -EINVAL;
}
if (!pbkdf->time_ms) {
log_err(cd, _("Requested PBKDF target time can not be zero.\n"));
log_err(cd, _("Requested PBKDF target time can not be zero."));
r = -EINVAL;
}
@@ -98,9 +140,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,6 +155,10 @@ 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.
@@ -148,10 +195,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 +211,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 +251,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 +288,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);
}

View File

@@ -2,8 +2,8 @@
* utils_wipe - wipe a device
*
* 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
@@ -177,7 +177,7 @@ int crypt_wipe_device(struct crypt_device *cd,
goto out;
if (lseek64(devfd, offset, SEEK_SET) < 0) {
log_err(cd, "Cannot seek to device offset.\n");
log_err(cd, "Cannot seek to device offset.");
r = -EINVAL;
goto out;
}
@@ -201,7 +201,7 @@ int crypt_wipe_device(struct crypt_device *cd,
r = wipe_block(devfd, pattern, sf, bsize, alignment,
wipe_block_size, offset, &need_block_init);
if (r) {
log_err(cd, "Device wipe error, offset %" PRIu64 ".\n", offset);
log_err(cd, "Device wipe error, offset %" PRIu64 ".", offset);
break;
}

View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 2004 Phil Karn, KA9Q
* libcryptsetup modifications
* Copyright (C) 2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2017-2018, Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,13 +23,41 @@
#ifndef _LIBFEC_RS_H
#define _LIBFEC_RS_H
/* Special reserved value encoding zero in index form. */
#define A0 (rs->nn)
#define RS_MIN(a, b) ((a) < (b) ? (a) : (b))
typedef unsigned char data_t;
struct rs;
/* Reed-Solomon codec control block */
struct rs {
int mm; /* Bits per symbol */
int nn; /* Symbols per block (= (1<<mm)-1) */
data_t *alpha_to;/* log lookup table */
data_t *index_of;/* Antilog lookup table */
data_t *genpoly; /* Generator polynomial */
int nroots; /* Number of generator roots = number of parity symbols */
int fcr; /* First consecutive root, index form */
int prim; /* Primitive element, index form */
int iprim; /* prim-th root of 1, index form */
int pad; /* Padding bytes in shortened block */
};
static inline int modnn(struct rs *rs, int x)
{
while (x >= rs->nn) {
x -= rs->nn;
x = (x >> rs->mm) + (x & rs->nn);
}
return x;
}
struct rs *init_rs_char(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad);
void free_rs_char(struct rs *rs);
/* General purpose RS codec, 8-bit symbols */
void encode_rs_char(struct rs *rs, data_t *data, data_t *parity);
int decode_rs_char(struct rs *rs, data_t *data);
#endif

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

@@ -0,0 +1,197 @@
/*
* Reed-Solomon decoder, based on libfec
*
* Copyright (C) 2002, Phil Karn, KA9Q
* libcryptsetup modifications
* Copyright (C) 2017-2018, Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <string.h>
#include <stdlib.h>
#include "rs.h"
int decode_rs_char(struct rs* rs, data_t* data)
{
int deg_lambda, el, deg_omega, syn_error, count;
int i, j, r, k;
data_t q, tmp, num1, num2, den, discr_r;
/* FIXME: remove VLAs here */
data_t lambda[rs->nroots + 1], s[rs->nroots]; /* Err+Eras Locator poly and syndrome poly */
data_t b[rs->nroots + 1], t[rs->nroots + 1], omega[rs->nroots + 1];
data_t root[rs->nroots], reg[rs->nroots + 1], loc[rs->nroots];
memset(s, 0, rs->nroots * sizeof(data_t));
memset(b, 0, (rs->nroots + 1) * sizeof(data_t));
/* form the syndromes; i.e., evaluate data(x) at roots of g(x) */
for (i = 0; i < rs->nroots; i++)
s[i] = data[0];
for (j = 1; j < rs->nn - rs->pad; j++) {
for (i = 0; i < rs->nroots; i++) {
if (s[i] == 0) {
s[i] = data[j];
} else {
s[i] = data[j] ^ rs->alpha_to[modnn(rs, rs->index_of[s[i]] + (rs->fcr + i) * rs->prim)];
}
}
}
/* Convert syndromes to index form, checking for nonzero condition */
syn_error = 0;
for (i = 0; i < rs->nroots; i++) {
syn_error |= s[i];
s[i] = rs->index_of[s[i]];
}
/*
* if syndrome is zero, data[] is a codeword and there are no
* errors to correct. So return data[] unmodified
*/
if (!syn_error)
return 0;
memset(&lambda[1], 0, rs->nroots * sizeof(lambda[0]));
lambda[0] = 1;
for (i = 0; i < rs->nroots + 1; i++)
b[i] = rs->index_of[lambda[i]];
/*
* Begin Berlekamp-Massey algorithm to determine error+erasure
* locator polynomial
*/
r = 0;
el = 0;
while (++r <= rs->nroots) { /* r is the step number */
/* Compute discrepancy at the r-th step in poly-form */
discr_r = 0;
for (i = 0; i < r; i++) {
if ((lambda[i] != 0) && (s[r - i - 1] != A0)) {
discr_r ^= rs->alpha_to[modnn(rs, rs->index_of[lambda[i]] + s[r - i - 1])];
}
}
discr_r = rs->index_of[discr_r]; /* Index form */
if (discr_r == A0) {
/* 2 lines below: B(x) <-- x*B(x) */
memmove(&b[1], b, rs->nroots * sizeof(b[0]));
b[0] = A0;
} else {
/* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
t[0] = lambda[0];
for (i = 0; i < rs->nroots; i++) {
if (b[i] != A0)
t[i + 1] = lambda[i + 1] ^ rs->alpha_to[modnn(rs, discr_r + b[i])];
else
t[i + 1] = lambda[i + 1];
}
if (2 * el <= r - 1) {
el = r - el;
/*
* 2 lines below: B(x) <-- inv(discr_r) *
* lambda(x)
*/
for (i = 0; i <= rs->nroots; i++)
b[i] = (lambda[i] == 0) ? A0 : modnn(rs, rs->index_of[lambda[i]] - discr_r + rs->nn);
} else {
/* 2 lines below: B(x) <-- x*B(x) */
memmove(&b[1], b, rs->nroots * sizeof(b[0]));
b[0] = A0;
}
memcpy(lambda, t, (rs->nroots + 1) * sizeof(t[0]));
}
}
/* Convert lambda to index form and compute deg(lambda(x)) */
deg_lambda = 0;
for (i = 0; i < rs->nroots + 1; i++) {
lambda[i] = rs->index_of[lambda[i]];
if (lambda[i] != A0)
deg_lambda = i;
}
/* Find roots of the error+erasure locator polynomial by Chien search */
memcpy(&reg[1], &lambda[1], rs->nroots * sizeof(reg[0]));
count = 0; /* Number of roots of lambda(x) */
for (i = 1, k = rs->iprim - 1; i <= rs->nn; i++, k = modnn(rs, k + rs->iprim)) {
q = 1; /* lambda[0] is always 0 */
for (j = deg_lambda; j > 0; j--) {
if (reg[j] != A0) {
reg[j] = modnn(rs, reg[j] + j);
q ^= rs->alpha_to[reg[j]];
}
}
if (q != 0)
continue; /* Not a root */
/* store root (index-form) and error location number */
root[count] = i;
loc[count] = k;
/* If we've already found max possible roots, abort the search to save time */
if (++count == deg_lambda)
break;
}
/*
* deg(lambda) unequal to number of roots => uncorrectable
* error detected
*/
if (deg_lambda != count)
return -1;
/*
* Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
* x**rs->nroots). in index form. Also find deg(omega).
*/
deg_omega = deg_lambda - 1;
for (i = 0; i <= deg_omega; i++) {
tmp = 0;
for (j = i; j >= 0; j--) {
if ((s[i - j] != A0) && (lambda[j] != A0))
tmp ^= rs->alpha_to[modnn(rs, s[i - j] + lambda[j])];
}
omega[i] = rs->index_of[tmp];
}
/*
* Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
* inv(X(l))**(rs->fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
*/
for (j = count - 1; j >= 0; j--) {
num1 = 0;
for (i = deg_omega; i >= 0; i--) {
if (omega[i] != A0)
num1 ^= rs->alpha_to[modnn(rs, omega[i] + i * root[j])];
}
num2 = rs->alpha_to[modnn(rs, root[j] * (rs->fcr - 1) + rs->nn)];
den = 0;
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
for (i = RS_MIN(deg_lambda, rs->nroots - 1) & ~1; i >= 0; i -= 2) {
if (lambda[i + 1] != A0)
den ^= rs->alpha_to[modnn(rs, lambda[i + 1] + i * root[j])];
}
/* Apply error to data */
if (num1 != 0 && loc[j] >= rs->pad) {
data[loc[j] - rs->pad] ^= rs->alpha_to[modnn(rs, rs->index_of[num1] +
rs->index_of[num2] + rs->nn - rs->index_of[den])];
}
}
return count;
}

View File

@@ -3,7 +3,7 @@
*
* Copyright (C) 2002, Phil Karn, KA9Q
* libcryptsetup modifications
* Copyright (C) 2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2017-2018, Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,32 +25,6 @@
#include "rs.h"
/* Special reserved value encoding zero in index form. */
#define A0 (rs->nn)
/* Reed-Solomon codec control block */
struct rs {
int mm; /* Bits per symbol */
int nn; /* Symbols per block (= (1<<mm)-1) */
data_t *alpha_to;/* log lookup table */
data_t *index_of;/* Antilog lookup table */
data_t *genpoly; /* Generator polynomial */
int nroots; /* Number of generator roots = number of parity symbols */
int fcr; /* First consecutive root, index form */
int prim; /* Primitive element, index form */
int iprim; /* prim-th root of 1, index form */
int pad; /* Padding bytes in shortened block */
};
static inline int modnn(struct rs *rs, int x)
{
while (x >= rs->nn) {
x -= rs->nn;
x = (x >> rs->mm) + (x & rs->nn);
}
return x;
}
/* Initialize a Reed-Solomon codec
* symsize = symbol size, bits
* gfpoly = Field generator polynomial coefficients

View File

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

View File

@@ -1,7 +1,7 @@
/*
* dm-verity volume handling
*
* Copyright (C) 2012-2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-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
@@ -59,9 +59,11 @@ int VERITY_create(struct crypt_device *cd,
char *root_hash,
size_t root_hash_size);
int VERITY_FEC_create(struct crypt_device *cd,
int VERITY_FEC_process(struct crypt_device *cd,
struct crypt_params_verity *params,
struct device *fec_device);
struct device *fec_device,
int check_fec,
unsigned int *errors);
uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params);

View File

@@ -2,7 +2,7 @@
* dm-verity Forward Error Correction (FEC) support
*
* Copyright (C) 2015, Google, Inc. All rights reserved.
* Copyright (C) 2017, Red Hat, Inc. All rights reserved.
* Copyright (C) 2017-2018, Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -51,8 +51,8 @@ struct fec_input_device {
};
struct fec_context {
int rsn;
int roots;
uint32_t rsn;
uint32_t roots;
uint64_t size;
uint64_t blocks;
uint64_t rounds;
@@ -94,6 +94,7 @@ static int FEC_read_interleaved(struct fec_context *ctx, uint64_t i,
continue;
}
/* FIXME: read_lseek_blockwise candidate */
if (lseek(ctx->inputs[n].fd, ctx->inputs[n].start + offset, SEEK_SET) < 0)
return -1;
return (read_buffer(ctx->inputs[n].fd, output, count) == (ssize_t)count) ? 0 : -1;
@@ -103,17 +104,18 @@ static int FEC_read_interleaved(struct fec_context *ctx, uint64_t i,
return -1;
}
/* encodes inputs to fd */
static int FEC_encode_inputs(struct crypt_device *cd,
struct crypt_params_verity *params,
struct fec_input_device *inputs,
size_t ninputs, int fd)
/* encodes/decode inputs to/from fd */
static int FEC_process_inputs(struct crypt_device *cd,
struct crypt_params_verity *params,
struct fec_input_device *inputs,
size_t ninputs, int fd,
int decode, unsigned int *errors)
{
int i, r = 0;
int r = 0;
unsigned int i;
struct fec_context ctx;
uint32_t b;
uint64_t n;
uint8_t parity[params->fec_roots];
uint8_t rs_block[FEC_RSM];
uint8_t *buf = NULL;
void *rs;
@@ -127,7 +129,7 @@ static int FEC_encode_inputs(struct crypt_device *cd,
rs = init_rs_char(FEC_PARAMS(ctx.roots));
if (!rs) {
log_err(cd, _("Failed to allocate RS context.\n"));
log_err(cd, _("Failed to allocate RS context."));
return -ENOMEM;
}
@@ -140,19 +142,19 @@ static int FEC_encode_inputs(struct crypt_device *cd,
ctx.blocks = FEC_div_round_up(ctx.size, ctx.block_size);
ctx.rounds = FEC_div_round_up(ctx.blocks, ctx.rsn);
buf = malloc(ctx.block_size * ctx.rsn);
buf = malloc((size_t)ctx.block_size * ctx.rsn);
if (!buf) {
log_err(cd, _("Failed to allocate buffer.\n"));
log_err(cd, _("Failed to allocate buffer."));
r = -ENOMEM;
goto out;
}
/* encode input */
/* encode/decode input */
for (n = 0; n < ctx.rounds; ++n) {
for (i = 0; i < ctx.rsn; ++i) {
if (FEC_read_interleaved(&ctx, n * ctx.rsn * ctx.block_size + i,
&buf[i * ctx.block_size], ctx.block_size)) {
log_err(cd, _("Failed to read RS block %" PRIu64 " byte %d.\n"), n, i);
log_err(cd, _("Failed to read RS block %" PRIu64 " byte %d."), n, i);
r = -EIO;
goto out;
}
@@ -162,24 +164,45 @@ static int FEC_encode_inputs(struct crypt_device *cd,
for (i = 0; i < ctx.rsn; ++i)
rs_block[i] = buf[i * ctx.block_size + b];
encode_rs_char(rs, rs_block, parity);
if (write_buffer(fd, parity, sizeof(parity)) != (ssize_t)sizeof(parity)) {
log_err(cd, _("Failed to write parity for RS block %" PRIu64 ".\n"), n);
r = -EIO;
goto out;
/* decoding from parity device */
if (decode) {
if (read_buffer(fd, &rs_block[ctx.rsn], ctx.roots) != ctx.roots) {
log_err(cd, _("Failed to read parity for RS block %" PRIu64 "."), n);
r = -EIO;
goto out;
}
/* coverity[tainted_data] */
r = decode_rs_char(rs, rs_block);
if (r < 0) {
log_err(cd, _("Failed to repair parity for block %" PRIu64 "."), n);
goto out;
}
/* return number of detected errors */
if (errors)
*errors += r;
r = 0;
} else {
/* encoding and writing parity data to fec device */
encode_rs_char(rs, rs_block, &rs_block[ctx.rsn]);
if (write_buffer(fd, &rs_block[ctx.rsn], ctx.roots) != ctx.roots) {
log_err(cd, _("Failed to write parity for RS block %" PRIu64 "."), n);
r = -EIO;
goto out;
}
}
}
}
out:
free_rs_char(rs);
free(buf);
return r;
}
int VERITY_FEC_create(struct crypt_device *cd,
int VERITY_FEC_process(struct crypt_device *cd,
struct crypt_params_verity *params,
struct device *fec_device)
struct device *fec_device, int check_fec,
unsigned int *errors)
{
int r;
int fd = -1;
@@ -198,22 +221,25 @@ int VERITY_FEC_create(struct crypt_device *cd,
/* validate parameters */
if (params->data_block_size != params->hash_block_size) {
log_err(cd, _("Block sizes must match for FEC.\n"));
log_err(cd, _("Block sizes must match for FEC."));
return -EINVAL;
}
if (params->fec_roots > FEC_RSM - FEC_MIN_RSN ||
params->fec_roots < FEC_RSM - FEC_MAX_RSN) {
log_err(cd, _("Invalid number of parity bytes.\n"));
log_err(cd, _("Invalid number of parity bytes."));
return -EINVAL;
}
r = -EIO;
/* output device */
fd = open(device_path(fec_device), O_RDWR);
if (check_fec)
fd = open(device_path(fec_device), O_RDONLY);
else
fd = open(device_path(fec_device), O_RDWR);
if (fd == -1) {
log_err(cd, _("Cannot open device %s.\n"), device_path(fec_device));
log_err(cd, _("Cannot open device %s."), device_path(fec_device));
goto out;
}
@@ -225,25 +251,25 @@ int VERITY_FEC_create(struct crypt_device *cd,
/* input devices */
inputs[0].fd = open(device_path(inputs[0].device), O_RDONLY);
if (inputs[0].fd == -1) {
log_err(cd, _("Cannot open device %s.\n"), device_path(inputs[0].device));
log_err(cd, _("Cannot open device %s."), device_path(inputs[0].device));
goto out;
}
inputs[1].fd = open(device_path(inputs[1].device), O_RDONLY);
if (inputs[1].fd == -1) {
log_err(cd, _("Cannot open device %s.\n"), device_path(inputs[1].device));
log_err(cd, _("Cannot open device %s."), device_path(inputs[1].device));
goto out;
}
/* cover the entire hash device starting from hash_offset */
r = device_size(inputs[1].device, &inputs[1].count);
if (r) {
log_err(cd, _("Failed to determine size for device %s.\n"),
log_err(cd, _("Failed to determine size for device %s."),
device_path(inputs[1].device));
goto out;
}
inputs[1].count -= inputs[1].start;
r = FEC_encode_inputs(cd, params, inputs, FEC_INPUT_DEVICES, fd);
r = FEC_process_inputs(cd, params, inputs, FEC_INPUT_DEVICES, fd, check_fec, errors);
out:
if (inputs[0].fd != -1)
close(inputs[0].fd);

View File

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

View File

@@ -2,7 +2,7 @@
* cryptsetup volume key implementation
*
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
* 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
@@ -22,6 +22,7 @@
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include "internal.h"
@@ -50,20 +51,17 @@ struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key)
return vk;
}
void crypt_volume_key_set_description(struct volume_key *vk, const char *key_description)
{
if (vk) {
free(CONST_CAST(void*)vk->key_description);
vk->key_description = key_description;
}
}
const char *crypt_volume_key_get_description(const struct volume_key *vk)
int crypt_volume_key_set_description(struct volume_key *vk, const char *key_description)
{
if (!vk)
return NULL;
return -EINVAL;
return vk->key_description;
free(CONST_CAST(void*)vk->key_description);
vk->key_description = NULL;
if (key_description && !(vk->key_description = strdup(key_description)))
return -ENOMEM;
return 0;
}
void crypt_free_volume_key(struct volume_key *vk)

View File

@@ -1,4 +1,4 @@
.TH CRYPTSETUP-REENCRYPT "8" "September 2017" "cryptsetup-reencrypt" "Maintenance Commands"
.TH CRYPTSETUP-REENCRYPT "8" "January 2018" "cryptsetup-reencrypt" "Maintenance Commands"
.SH NAME
cryptsetup-reencrypt - tool for offline LUKS device re-encryption
.SH SYNOPSIS
@@ -14,12 +14,8 @@ unclocked by passphrase), \fBcipher\fR, \fBcipher mode\fR.
Cryptsetup-reencrypt reencrypts data on LUKS device in-place. During
reencryption process the LUKS device is marked unavailable.
\fBNOTE:\fR LUKS2 format support is limited. Currently the tool uses default
values for new LUKS2 headers. Only those parameters shared with LUKS1 format
may be changed (\-\-hash and \-\-iter\-time only).
\fIWARNING\fR: The cryptsetup-reencrypt program is not resistant to hardware
or kernel failures during reencryption (you can lose you data in this case).
or kernel failures during reencryption (you can lose your data in this case).
\fIALWAYS BE SURE YOU HAVE RELIABLE BACKUP BEFORE USING THIS TOOL.\fR
.br
@@ -27,7 +23,7 @@ The reencryption can be temporarily suspended (by TERM signal or by
using ctrl+c) but you need to retain temporary files named LUKS-<uuid>.[log|org|new].
LUKS device is unavailable until reencryption is finished though.
Current working directory must by writable and temporary
Current working directory must be writable and temporary
files created during reencryption must be present.
For more info about LUKS see cryptsetup(8).
@@ -38,29 +34,94 @@ To start (or continue) re-encryption for <device> use:
.PP
\fIcryptsetup-reencrypt\fR <device>
\fB<options>\fR can be [\-\-batch-mode, \-\-block-size, \-\-cipher, \-\-debug,
\-\-device-size, \-\-hash, \-\-iter-time, \-\-use-random | \-\-use-urandom,
\-\-keep-key, \-\-key-size, \-\-key-file, \-\-key-slot, \-\-keyfile-offset,
\-\-keyfile-size, \-\-tries, \-\-use-directio, \-\-use-fsync, \-\-verbose, \-\-write-log,
\-\-uuid, \-\-progress-frequency]
\fB<options>\fR can be [\-\-batch-mode, \-\-block-size, \-\-cipher | \-\-keep-key,
\-\-debug, \-\-device-size, \-\-hash, \-\-header, \-\-iter-time | \-\-pbkdf\-force\-iterations,
\-\-key-file, \-\-key-size, \-\-key-slot, \-\-keyfile-offset, \-\-keyfile-size,
\-\-master\-key\-file, \-\-tries, \-\-pbkdf, \-\-pbkdf\-memory, \-\-pbkdf\-parallel,
\-\-progress-frequency, \-\-use-directio, \-\-use-random | \-\-use-urandom, \-\-use-fsync,
\-\-uuid, \-\-verbose, \-\-write-log]
To encrypt data on (not yet encrypted) device, use \fI\-\-new\fR with combination
with \fI\-\-reduce-device-size\fR.
with \fI\-\-reduce-device-size\fR or with \fI\-\-header\fR option for detached header.
To remove encryption from device, use \fI\-\-decrypt\fR.
For detailed description of encryption and key file options see \fIcryptsetup(8)\fR
man page.
.TP
.B "\-\-verbose, \-v"
Print more information on command execution.
.B "\-\-batch-mode, \-q"
Suppresses all warnings and reencryption progress output.
.TP
.B "\-\-block-size, \-B \fIvalue\fR"
Use re-encryption block size of <value> in MiB.
Values can be between 1 and 64 MiB.
.TP
.B "\-\-cipher, \-c" \fI<cipher-spec>\fR
Set the cipher specification string.
.TP
.B "\-\-debug"
Run in debug mode with full diagnostic logs. Debug output
lines are always prefixed by '#'.
.TP
.B "\-\-cipher, \-c" \fI<cipher-spec>\fR
Set the cipher specification string.
.B "\-\-decrypt"
Remove encryption (decrypt already encrypted device and remove LUKS header).
\fBWARNING:\fR This is destructive operation and cannot be reverted.
.TP
.B "\-\-device-size \fIsize[units]\fR"
Instead of real device size, use specified value.
It means that only specified area (from the start of the device
to the specified size) will be reencrypted.
If no unit suffix is specified, the size is in bytes.
Unit suffix can be S for 512 byte sectors, K/M/G/T (or KiB,MiB,GiB,TiB)
for units with 1024 base or KB/MB/GB/TB for 1000 base (SI scale).
\fBWARNING:\fR This is destructive operation.
.TP
.B "\-\-hash, \-h \fI<hash-spec>\fR"
Specifies the hash used in the LUKS1 key setup scheme and volume key digest.
\fBNOTE:\fR if this parameter is not specified, default hash algorithm is always used
for new LUKS1 device header.
\fBNOTE:\fR with LUKS2 format this option is only relevant when new keyslot pbkdf algorithm
is set to PBKDF2 (see \fI\-\-pbkdf\fR).
.TP
.B "\-\-header\fR \fI<LUKS header file>\fR"
Use a detached (separated) metadata device or file where the
LUKS header is stored. This option allows one to store ciphertext
and LUKS header on different devices.
\fBWARNING:\fR There is no check whether the ciphertext device specified
actually belongs to the header given.
If used with \fI\-\-new\fR option, the header file will created (or overwritten).
Use with care.
.TP
.B "\-\-iter-time, \-i \fI<milliseconds>\fR"
The number of milliseconds to spend with PBKDF2 passphrase processing for the
new LUKS header.
.TP
.B "\-\-keep-key"
Do not change encryption key, just reencrypt the LUKS header and keyslots.
This option can be combined only with \fI\-\-hash\fR, \fI\-\-iter-time\fR,
\fI\-\-pbkdf\-force\-iterations\fR, \fI\-\-pbkdf\fR (LUKS2 only),
\fI\-\-pbkdf\-memory\fR (Argon2i/id and LUKS2 only) and \fI\-\-pbkdf\-parallel\fR
(Argon2i/id and LUKS2 only) options.
.TP
.B "\-\-key-file, \-d \fIname\fR"
Read the passphrase from file.
\fBWARNING:\fR \-\-key-file option can be used only if there is only one active keyslot,
or alternatively, also if \-\-key-slot option is specified (then all other keyslots
will be disabled in new LUKS device).
If this option is not used, cryptsetup-reencrypt will ask for all active keyslot
passphrases.
.TP
.B "\-\-key-size, \-s \fI<bits>\fR"
Set key size in bits. The argument has to be a multiple of 8.
@@ -74,33 +135,8 @@ cannot be performed.
If there is not enough space for keyslots with new key size,
you can destructively shrink device with \-\-reduce-device-size option.
.TP
.B "\-\-hash, \-h \fI<hash-spec>\fR"
Specifies the hash used in the LUKS key setup scheme and volume key digest.
\fBNOTE:\fR if this parameter is not specified, default hash algorithm is always used
for new device header.
.TP
.B "\-\-iter-time, \-i \fI<milliseconds>\fR"
The number of milliseconds to spend with PBKDF2 passphrase processing for the
new LUKS header.
.TP
.B "\-\-use-random"
.TP
.B "\-\-use-urandom"
Define which kernel random number generator will be used to create the volume key.
.TP
.B "\-\-key-file, \-d \fIname\fR"
Read the passphrase from file.
\fBWARNING:\fR \-\-key-file option can be used only if there only one active keyslot,
or alternatively, also if \-\-key-slot option is specified (then all other keyslots
will be disabled in new LUKS device).
If this option is not used, cryptsetup-reencrypt will ask for all active keyslot
passphrases.
.TP
.B "\-\-key-slot, \-S <0-7>"
Specify which key slot is used.
.B "\-\-key-slot, \-S <0-MAX>"
Specify which key slot is used. For LUKS1, max keyslot number is 7. For LUKS2, it's 31.
\fBWARNING:\fR All other keyslots will be disabled if this option is used.
.TP
@@ -112,34 +148,39 @@ Read a maximum of \fIvalue\fR bytes from the key file.
Default is to read the whole file up to the compiled-in
maximum.
.TP
.B "\-\-keep-key"
Do not change encryption key, just reencrypt the LUKS header and keyslots.
This option can be combined only with \fI\-\-hash\fR or \fI\-\-iter-time\fR
options.
.B "\-\-master\-key\-file"
Use new volume (master) key stored in a file.
.TP
.B "\-\-tries, \-T"
Number of retries for invalid passphrase entry.
.B "\-\-new, \-N"
Create new header (encrypt not yet encrypted device).
This option must be used together with \-\-reduce-device-size.
\fBWARNING:\fR This is destructive operation and cannot be reverted.
.TP
.B "\-\-block-size, \-B \fIvalue\fR"
Use re-encryption block size of <value> in MiB.
.B "\-\-pbkdf"
Set Password-Based Key Derivation Function (PBKDF) algorithm for LUKS keyslot.
The PBKDF can be: \fIpbkdf2\fR, \fIargon2i\fR for Argon2i or \fIargon2id\fR for Argon2id.
Values can be between 1 and 64 MiB.
For LUKS1, only \fIpbkdf2\fR is accepted (no need to use this option).
.TP
.B "\-\-device-size \fIsize[units]\fR"
Instead of real device size, use specified value.
It means that only specified area (from the start of the device
to the specified size) will be reencrypted.
\fBWARNING:\fR This is destructive operation.
If no unit suffix is specified, the size is in bytes.
Unit suffix can be S for 512 byte sectors, K/M/G/T (or KiB,MiB,GiB,TiB)
for units with 1024 base or KB/MB/GB/TB for 1000 base (SI scale).
\fBWARNING:\fR This is destructive operation.
.B "\-\-pbkdf\-force\-iterations <num>"
Avoid PBKDF benchmark and set time cost (iterations) directly.
.TP
.B "\-\-pbkdf\-memory <number>"
Set the memory cost for PBKDF (for Argon2i/id the number represents kilobytes).
Note that it is maximal value, PBKDF benchmark or available physical memory
can decrease it.
This option is not available for PBKDF2.
.TP
.B "\-\-pbkdf\-parallel <number>"
Set the parallel cost for PBKDF (number of threads, up to 4).
Note that it is maximal value, it is decreased automatically if
CPU online count is lower.
This option is not available for PBKDF2.
.TP
.B "\-\-progress-frequency <seconds>"
Print separate line every <seconds> with reencryption progress.
.TP
.B "\-\-reduce-device-size \fIsize[units]\fR"
Enlarge data offset to specified value by shrinking device size.
@@ -153,22 +194,20 @@ partition (so last sectors contains no data).
For units suffix see \-\-device-size parameter description.
\fBWARNING:\fR This is destructive operation and cannot be reverted.
Use with extreme care - shrinked filesystems are usually unrecoverable.
You cannot shrink device more than by 64 MiB (131072 sectors).
.TP
.B "\-\-new, \-N"
Create new header (encrypt not yet encrypted device).
This option must be used together with \-\-reduce-device-size.
\fBWARNING:\fR This is destructive operation and cannot be reverted.
Use with extreme care - shrunk filesystems are usually unrecoverable.
.TP
.B "\-\-decrypt"
Remove encryption (decrypt already encrypted device and remove LUKS header).
.B "\-\-tries, \-T"
Number of retries for invalid passphrase entry.
.TP
.B "\-\-type <type>"
Use only while encrypting not yet encrypted device (see \-\-new).
\fBWARNING:\fR This is destructive operation and cannot be reverted.
Specify LUKS version when performing in-place encryption. If the parameter
is omitted default value (LUKS1) is used. Type may be one of: \fBluks\fR (default),
\fBluks1\fR or \fBluks2\fR.
.TP
.B "\-\-use-directio"
Use direct-io (O_DIRECT) for all read/write data operations related
@@ -181,9 +220,10 @@ operations (e.g. in virtual environments).
Use fsync call after every written block. This applies for reencryption
log files as well.
.TP
.B "\-\-write-log"
Update log file after every block write. This can slow down reencryption
but will minimize data loss in the case of system crash.
.B "\-\-use-random"
.TP
.B "\-\-use-urandom"
Define which kernel random number generator will be used to create the volume key.
.TP
.B "\-\-uuid" \fI<uuid>\fR
Use only while resuming an interrupted decryption process (see \-\-decrypt).
@@ -191,21 +231,16 @@ Use only while resuming an interrupted decryption process (see \-\-decrypt).
To find out what \fI<uuid>\fR to pass look for temporary files LUKS-<uuid>.[|log|org|new]
of the interrupted decryption process.
.TP
.B "\-\-batch-mode, \-q"
Suppresses all warnings and reencryption progress output.
.TP
.B "\-\-progress-frequency <seconds>"
Print separate line every <seconds> with reencryption progress.
.TP
.B "\-\-type <type>"
Use only while encrypting not yet encrypted device (see \-\-new).
Specify LUKS version when performing in-place encryption. If the parameter
is ommited default value (LUKS1) is used. Type may be one of: \fBluks\fR (default),
\fBluks1\fR or \fBluks2\fR.
.B "\-\-verbose, \-v"
Print more information on command execution.
.TP
.B "\-\-version"
Show the program version.
.TP
.B "\-\-write-log"
Update log file after every block write. This can slow down reencryption
but will minimize data loss in the case of system crash.
.SH RETURN CODES
Cryptsetup-reencrypt returns 0 on success and a non-zero value on error.
@@ -246,9 +281,9 @@ Please attach the output of the failed command with the
.SH AUTHORS
Cryptsetup-reencrypt was written by Milan Broz <gmazyland@gmail.com>.
.SH COPYRIGHT
Copyright \(co 2012-2017 Milan Broz
Copyright \(co 2012-2018 Milan Broz
.br
Copyright \(co 2012-2017 Red Hat, Inc.
Copyright \(co 2012-2018 Red Hat, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

View File

@@ -1,4 +1,4 @@
.TH CRYPTSETUP "8" "September 2017" "cryptsetup" "Maintenance Commands"
.TH CRYPTSETUP "8" "January 2018" "cryptsetup" "Maintenance Commands"
.SH NAME
cryptsetup - manage plain dm-crypt and LUKS encrypted volumes
.SH SYNOPSIS
@@ -270,15 +270,22 @@ Prompts interactively for a passphrase if \-\-key-file is not given.
.PP
\fIluksAddKey\fR <device> [<key file with new key>]
.IP
adds a new passphrase. An existing passphrase must be supplied
Adds a new passphrase. An existing passphrase must be supplied
interactively or via \-\-key-file.
The new passphrase to be added can be specified interactively
or read from the file given as positional argument.
\fBNOTE:\fR with \-\-unbound option the action creates new unbound
LUKS2 keyslot. The keyslot cannot be used for device activation.
If you don't pass new key via \-\-master\-key\-file option,
new random key is generated. Existing passphrase for any active keyslot
is not required.
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
\-\-keyfile\-size, \-\-new\-keyfile\-offset,
\-\-new\-keyfile\-size, \-\-key\-slot, \-\-master\-key\-file,
\-\-iter\-time, \-\-force\-password, \-\-header, \-\-disable\-locks].
\-\-iter\-time, \-\-force\-password, \-\-header, \-\-disable\-locks,
\-\-unbound].
.PP
\fIluksRemoveKey\fR <device> [<key file with passphrase to be removed>]
.IP
@@ -323,6 +330,30 @@ inaccessible.
\-\-new\-keyfile\-size, \-\-key\-slot, \-\-force\-password, \-\-header,
\-\-disable\-locks].
.PP
.PP
\fIluksConvertKey\fR <device>
.IP
Converts an existing LUKS2 keyslot to new pbkdf parameters. The
passphrase for keyslot to be converted must be supplied interactively
or via \-\-key\-file. If no \-\-pbkdf parameters are specified LUKS2
default pbkdf values will apply.
If a keyslot is specified (via \-\-key\-slot), the passphrase for that
keyslot must be given. If no keyslot is specified and there is still
a free keyslot, then the new parameters will be put into a free
keyslot before the keyslot containing the old parameters is
purged. If there is no free keyslot, then the keyslot with the old
parameters is overwritten directly.
\fBWARNING:\fR If a keyslot is overwritten, a media failure during
this operation can cause the overwrite to fail after the old
parameters have been wiped and make the LUKS container inaccessible.
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
\-\-keyfile\-size, \-\-key\-slot, \-\-header, \-\-disable\-locks,
\-\-iter-time, \-\-pbkdf, \-\-pbkdf\-force\-iterations,
\-\-pbkdf\-memory, \-\-pbkdf\-parallel].
.PP
\fIluksKillSlot\fR <device> <key slot number>
.IP
Wipe the key-slot number <key slot> from the LUKS device. Except running
@@ -374,17 +405,19 @@ means the device is a LUKS device.
Dump the header information of a LUKS device.
If the \-\-dump\-master\-key option is used, the LUKS device master key is
dumped instead of the keyslot info. Beware that the master key cannot be
changed and can be used to decrypt the data stored in the LUKS container
without a passphrase and even without the LUKS header. This means
that if the master key is compromised, the whole device has to be
erased to prevent further access. Use this option carefully.
dumped instead of the keyslot info. Together with \-\-master\-key\-file option,
master key is dumped to a file instead of standard output. Beware that the
master key cannot be changed without reencryption and can be used to decrypt
the data stored in the LUKS container without a passphrase and even without the
LUKS header. This means that if the master key is compromised, the whole device
has to be erased to prevent further access. Use this option carefully.
To dump the master key, a passphrase has to be supplied,
either interactively or via \-\-key\-file.
\fB<options>\fR can be [\-\-dump\-master\-key, \-\-key\-file,
\-\-keyfile\-offset, \-\-keyfile\-size, \-\-header, \-\-disable\-locks].
\-\-keyfile\-offset, \-\-keyfile\-size, \-\-header, \-\-disable\-locks,
\-\-master\-key\-file].
\fBWARNING:\fR If \-\-dump\-master\-key is used with \-\-key\-file
and the argument to \-\-key\-file is '-', no validation question
@@ -432,7 +465,7 @@ The \fItoken\fR command is supported only for LUKS2.
For adding new keyring token, option \-\-key\-description is mandatory.
Also, new token is assigned to key slot specified with \-\-key\-slot option or to all
active key slots in the case \-\-key\-slot option is ommited.
active key slots in the case \-\-key\-slot option is omitted.
To remove existing token, specify the token ID which should be removed with
\-\-token\-id option.
@@ -539,7 +572,7 @@ value, \fBadditionally to \-\-veracrypt \fR use either the
line or use \fB\-\-veracrypt\-query\-pim\fR to be prompted for the PIM.
The PIM value affects the number of iterations applied during key derivation. Please refer to
\fBhttps://www.veracrypt.fr/en/Personal%20Iterations%20Multiplier%20(PIM).html\fR
\fBhttps://www.veracrypt.fr/en/Personal%20Iterations%20Multiplier%20%28PIM%29.html\fR
for more detailed information.
\fBNOTE:\fR Activation with \fBtcryptOpen\fR is supported only for cipher chains
@@ -585,7 +618,7 @@ a mapping <name>.
\fB<options>\fR can be [\-\-key\-file, \-\-tcrypt\-hidden,
\-\-tcrypt\-system, \-\-tcrypt\-backup, \-\-readonly, \-\-test\-passphrase,
\-\-allow-discards, \-\-vracrypt, \-\-veracrypt\-pim, \-\-veracrypt\-querry\-pim].
\-\-allow-discards, \-\-veracrypt, \-\-veracrypt\-pim, \-\-veracrypt\-query\-pim].
The keyfile parameter allows a combination of file content with the
passphrase and can be repeated. Note that using keyfiles is compatible
@@ -770,6 +803,10 @@ LUKS header and all other parameters are the same,
then the new header decrypts the data encrypted with the
header the master key was taken from.
Action \fIluksDump\fR together with \-\-dump\-master\-key
option: The volume (master) key is stored in a file instead of
being printed out to standard output.
\fBWARNING:\fR If you create your own master key, you
need to make sure to do it right. Otherwise, you can end
up with a low-entropy or otherwise partially predictable
@@ -904,10 +941,11 @@ Specifying 0 as parameter selects the compiled-in default.
.TP
.B "\-\-pbkdf\-memory <number>"
Set the memory cost for PBKDF (for Argon2i/id the number represents kilobytes).
Note that it is maximal value, PBKDF benchmark can decrease it.
Note that it is maximal value, PBKDF benchmark or available physical memory
can decrease it.
This option is not available for PBKDF2.
.TP
.B "\-\-pbkdf\-paralell <number>"
.B "\-\-pbkdf\-parallel <number>"
Set the parallel cost for PBKDF (number of threads, up to 4).
Note that it is maximal value, it is decreased automatically if
CPU online count is lower.
@@ -1135,6 +1173,11 @@ to the sector.
aligned to page size and page-cache initiates read of a sector with invalid
integrity tag.
.TP
.B "\-\-unbound"
Creates new LUKS2 unbound keyslot. See \fIluksAddKey\fR action for more
details.
.TP
.B "\-\-tcrypt\-hidden"
.B "\-\-tcrypt\-system"
.B "\-\-tcrypt\-backup"
@@ -1347,7 +1390,7 @@ the status command output. Also see losetup(8).
The LUKS2 on-disk metadata is updated in several steps and
to achieve proper atomic update, there is a locking mechanism.
For an image in file, code uses \fIflock(2)\fR system call.
For a block device, lock is perfomed over a special file stored
For a block device, lock is performed over a special file stored
in a locking directory (by default \fI/run/lock/cryptsetup\fR).
The locking directory should be created with the proper security
context by the distribution during the boot-up phase.
@@ -1380,9 +1423,9 @@ Copyright \(co 2004 Jana Saout
.br
Copyright \(co 2004-2006 Clemens Fruhwirth
.br
Copyright \(co 2009-2017 Red Hat, Inc.
Copyright \(co 2009-2018 Red Hat, Inc.
.br
Copyright \(co 2009-2017 Milan Broz
Copyright \(co 2009-2018 Milan Broz
.br
Copyright \(co 2012-2014 Arno Wagner

View File

@@ -1,4 +1,4 @@
.TH INTEGRITYSETUP "8" "September 2017" "integritysetup" "Maintenance Commands"
.TH INTEGRITYSETUP "8" "January 2018" "integritysetup" "Maintenance Commands"
.SH NAME
integritysetup - manage dm-integrity (block level integrity) volumes
.SH SYNOPSIS
@@ -197,9 +197,9 @@ Please attach the output of the failed command with the
The integritysetup tool is written by Milan Broz <gmazyland@gmail.com>
and is part of the cryptsetup project.
.SH COPYRIGHT
Copyright \(co 2016-2017 Red Hat, Inc.
Copyright \(co 2016-2018 Red Hat, Inc.
.br
Copyright \(co 2016-2017 Milan Broz
Copyright \(co 2016-2018 Milan Broz
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

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