Compare commits

...

152 Commits

Author SHA1 Message Date
Milan Broz
b0d8815dab Relnote addition. 2012-10-16 22:00:19 +02:00
Milan Broz
831a0af508 Update some po files. 2012-10-14 21:11:20 +02:00
Milan Broz
488202feee Version 1.5.1. 2012-10-12 14:18:56 +02:00
Milan Broz
193402ad41 Check read & seek return codes, use uint64 offset.
Signed-off-by: Arno Wagner <wagner.arno@gmail.com>
Signed-off-by: Milan Broz <gmazyland@gmail.com>
2012-10-12 13:18:22 +02:00
Arno Wagner
1b86b7cb4b added keyslot checker Redesigned to only use public definitions
Signed-off-by: Arno Wagner <wagner.arno@gmail.com>
2012-10-11 18:07:35 +02:00
Milan Broz
e5dc991ffd Increase library and package version. 2012-09-19 15:57:56 +02:00
Milan Broz
89e09afdf6 Fix some problems found by Coverity static analysis. 2012-09-19 13:58:00 +02:00
Arno Wagner
bec7fcb14a synced with wiki 2012-09-18 23:30:38 +02:00
Milan Broz
f45d4d0755 Add crypt_keyslot_area() API call.
Useful if you want to analyze/wipe area of disk used for keyslot
from external tool.
2012-09-11 11:59:06 +02:00
Arno Wagner
64558a57e3 fixed typeo 94 -> 95 printable ASCII chars 2012-09-09 02:51:58 +02:00
Milan Broz
29e4414c35 Fix luksHeaderBackup for v1.0 (very old) headers and add some basic test. 2012-08-30 15:39:30 +02:00
Milan Broz
c2e12440d2 Add some offset/keyslot offset checks. 2012-08-30 14:08:34 +02:00
Milan Broz
1685aa5978 Proper handle error in device block get. 2012-08-28 13:30:17 +02:00
Milan Broz
6874f564c1 Remove unused includes. 2012-08-28 13:16:03 +02:00
Milan Broz
4882f70040 Replace round_up macro with function. 2012-08-28 13:11:02 +02:00
Milan Broz
1aca317c77 Move LUKS AF data sector alignment to AF helper function. 2012-08-27 16:52:19 +02:00
Milan Broz
af2730fe2a Always zero memory in crypt_safe_alloc. 2012-08-27 16:28:00 +02:00
Milan Broz
a6d64d1d44 Use AF_split_size() to calculate split data size. 2012-08-27 15:26:22 +02:00
Milan Broz
d15dd89bb7 Get rid of confusing LUKS_PHDR_SIZE macro. 2012-08-27 14:45:21 +02:00
Dave Reisner
961682aa6b lib/utils_crypt: optimize seek to keyfile-offset
Avoid using unbuffered reads when "seeking" to a keyfile offset. This is
abysmally slow when the key is hidden at the end of a large device.
Instead, try to actually call lseek, falling back on reading in chunks
of BUFSIZ bytes until the desired offset is reached.

Command line:

  cryptsetup luksOpen /dev/vdc1 home \
      --keyfile /dev/vdd --keyfile-size 4096 --keyfile-offset 123456789

Before:

  real   0m25.589s
  user   0m7.030s
  sys    0m18.479s

After:

  real   0m4.464s
  user   0m4.253s
  sys    0m0.157s
2012-08-27 13:10:00 +02:00
Milan Broz
2f37cfe569 Do not scan rotational flag for non-block devices / file images. 2012-08-27 12:42:15 +02:00
Arno Wagner
5b5c6dccc0 added prominent note to use LUKS (not plain dm-crypt) unless
understanding the crypto well.
2012-08-24 19:00:47 +02:00
Arno Wagner
d58a5c8cae synced with wiki 2012-08-24 17:02:59 +02:00
Milan Broz
1d5788f779 Set context for DM log for all DM backend entries.
Try to handle error if run as non-root user better.
2012-08-14 19:17:13 +02:00
Milan Broz
97224b072a Add context to DM helpers.
(To be used later.)
2012-08-14 16:25:21 +02:00
Milan Broz
15442c1747 Modprobe kernel modules early in api-test. 2012-08-14 15:54:31 +02:00
Milan Broz
ff9db165eb Use common utils_tools.c for all tools.
Unify tool environment and deduplicate code.
2012-08-13 18:31:26 +02:00
Milan Broz
48332d248f Remove debug line. 2012-08-13 17:16:37 +02:00
Milan Broz
07815c24cd Print better error message if device is read-only etc. 2012-08-13 16:54:41 +02:00
Milan Broz
49b018c765 Create hash image if doesn't exist in veritysetup format. 2012-08-12 23:42:41 +02:00
Milan Broz
65f975655c New device access backend.
Allocate loop device late (only when real block device needed).
Rework underlying device/file access functions.
Move all device (and ioctl) access to utils_device.c.

Allows using file where appropriate without allocation loop device.
2012-08-12 22:00:17 +02:00
Milan Broz
0c1efd1f8a Fix dracut example. 2012-08-03 15:27:59 +02:00
Arno Wagner
bc1cbd8065 update to current WIKI version 2012-08-02 15:58:36 +02:00
Milan Broz
50a2d89add Fix some issues in dict example. 2012-08-02 12:51:28 +02:00
Milan Broz
99643a82ae Be sure verity module is loaded in test. 2012-07-23 15:00:28 +02:00
Milan Broz
fcc35f459c Better define comment lines for for dict example. 2012-07-20 15:36:16 +02:00
Milan Broz
a5aa91ed99 Clear dict example a little bit. 2012-07-20 14:51:51 +02:00
Milan Broz
d83b872c55 Add example of dictionary search. 2012-07-20 00:15:20 +02:00
Milan Broz
8ec2651ad7 Use fixed dir (old dracut lib...) 2012-07-12 21:15:37 +02:00
Milan Broz
53e269c5f1 Add key option to dracut example. 2012-07-12 19:21:22 +02:00
Milan Broz
8b8e206c07 Skip multikey if not supported (e.g. FIPS mode - md5 for IV not available). 2012-07-12 12:53:26 +02:00
Milan Broz
e0562f9708 Version 1.5.0. 2012-07-10 20:20:27 +02:00
Milan Broz
6462ee55d3 Update example files for new dracut. 2012-07-10 19:59:44 +02:00
Milan Broz
91ba5742c6 Update release notes. 2012-07-10 13:09:35 +02:00
Milan Broz
667e469659 Version 1.5.0. 2012-07-10 12:54:22 +02:00
Milan Broz
37cecb5a5b Add example of dracut module for reencryption. 2012-07-10 12:53:32 +02:00
Milan Broz
a47ebccf9a Add module load to test. 2012-07-10 10:15:40 +02:00
Milan Broz
584d5b8d65 Fix library name for FIPS check. 2012-07-09 19:30:25 +02:00
Milan Broz
8eef5bde4f Add link to upstream tracker. 2012-07-09 19:04:39 +02:00
Milan Broz
3532be48c7 Fix libcryptsetup.h docs for verity type. 2012-07-09 18:47:05 +02:00
Milan Broz
5f7309bfa0 Add some verity api test.
Fix set_data_device bug it uncovered.
Fix api-test for nonFIPS hash.
2012-07-09 18:09:51 +02:00
Milan Broz
fa4a246744 Remove utils_debug from pot. 2012-07-08 20:29:30 +02:00
Milan Broz
321386db88 Fix password length unit in configure. 2012-06-28 10:16:49 +02:00
Milan Broz
b99b4825a2 Use resume instead of restart. 2012-06-27 21:28:11 +02:00
Petr Písař
9b455125e9 Pass help text to popt already translated
popt does not process the text registered by poptSetOtherOptionHelp()
through gettext on its own. Application must do it.
2012-06-26 21:26:04 +02:00
Milan Broz
adcb9bfb7d Update po files. 2012-06-26 14:33:08 +02:00
Milan Broz
4abfd38169 Remove open device debugging feature (no longer needed). 2012-06-26 12:55:14 +02:00
Milan Broz
b684fffdaf Switch to use unit suffix for --reduce-device-size option. 2012-06-25 16:06:43 +02:00
Milan Broz
fb3b62ca02 Add --device-size option for reencryption tool. 2012-06-25 15:34:11 +02:00
Milan Broz
c469e458b7 Version 1.5.0-rc2. 2012-06-20 11:29:46 +02:00
Milan Broz
be5473f242 Fix verity test.
(Writing just one byte from urandom means, that there is still
high probability the byte will be the same and it will cause
no data corruption :-)
2012-06-19 18:40:38 +02:00
Milan Broz
527c0fe4f9 Rename without_activation to test_passphrase. 2012-06-19 17:37:31 +02:00
Milan Broz
0ec4d4c9cf Add directio to reenc test. 2012-06-19 16:04:20 +02:00
Milan Broz
28f860def2 Remove old dm-verity superblock handling. 2012-06-19 15:57:05 +02:00
Milan Broz
42abcc0fac Remove some redundant brackets. 2012-06-19 15:49:56 +02:00
Milan Broz
a38fcafcff Add --without-activation option for luksOpen (check passphrase only). 2012-06-19 15:36:19 +02:00
Milan Broz
c4a533c3d5 Fix luks-header-from-active to not require header on device and add UUID setting. 2012-06-19 14:43:10 +02:00
Milan Broz
96f31a2cff Remove dubious compilation warning. 2012-06-19 12:49:16 +02:00
Milan Broz
8f4fb9303f Fix man page makefile. 2012-06-19 10:33:48 +02:00
Milan Broz
336be2da96 Update po files. 2012-06-19 09:56:55 +02:00
Milan Broz
e129bffce9 Remove redundant condition in overflow test. 2012-06-18 17:12:41 +02:00
Milan Broz
a9d9a2ad44 Fix hex_to_bytes and add it to common utils. 2012-06-18 17:09:48 +02:00
Milan Broz
c0a5293435 Introduce cryptsetup-reencrypt - experimental offline LUKS reencryption tool. 2012-06-18 16:06:14 +02:00
Milan Broz
b9ae00956d Add simple examples to man page. 2012-06-18 15:52:36 +02:00
Milan Broz
e37016bf64 Fix malloc of 0 size. 2012-06-18 15:03:47 +02:00
Milan Broz
104c7d6c4f If in progress, just use normal path (check passphrase). 2012-06-18 14:52:35 +02:00
Milan Broz
b773823a1b Add ability to encrypt plain device. 2012-06-18 14:29:22 +02:00
Milan Broz
0894814148 Add some simple reenc test. 2012-06-17 21:59:29 +02:00
Milan Broz
cc948df1dd Sanity check for some options. 2012-06-17 19:30:48 +02:00
Milan Broz
35e3660c61 Add possibility to change key size (optionally by shrinking device). 2012-06-17 15:09:34 +02:00
Milan Broz
28c6901de1 Do not touch new LUKS headers. 2012-06-17 12:44:53 +02:00
Milan Broz
dc067454c1 Rename to crypsetup-reencrypt.
Add man page.
Add configure option.
2012-06-17 12:12:17 +02:00
Milan Broz
32c2bd4222 Check device exclusively. 2012-06-17 02:11:41 +02:00
Milan Broz
cd4ea1c348 Fix signit if reencryption not yet started. 2012-06-17 00:43:45 +02:00
Milan Broz
8984e47414 Use ETA in progress report. 2012-06-17 00:06:30 +02:00
Milan Broz
491e79db4c Add fsync option. 2012-06-16 21:49:45 +02:00
Milan Broz
8a1a0547a8 Fix directio aligned buffer. 2012-06-16 21:13:47 +02:00
Milan Broz
9d47892342 Fix directio (again). 2012-06-16 20:59:21 +02:00
Milan Broz
32cfb1ca25 Fix some compile warnings. 2012-06-16 18:49:37 +02:00
Milan Broz
810aef34ca Do not use global context. 2012-06-16 18:28:49 +02:00
Milan Broz
b23b3c4dfe Fix verbose messages. 2012-06-16 18:10:01 +02:00
Milan Broz
b9d99a1626 Change log manipulation, print log always. 2012-06-16 17:07:29 +02:00
Milan Broz
496a07ed4c Properly support more keyslots.
If key file specified, use only one keyslot.
2012-06-16 01:23:42 +02:00
Milan Broz
fbba97552e Remove new file header option for now. 2012-06-15 15:16:49 +02:00
Milan Broz
0cefe2d107 Create smaller header device. 2012-06-15 15:03:09 +02:00
Milan Broz
768426ad99 Handle interrupts & restart. 2012-06-15 13:51:16 +02:00
Milan Broz
5a48ff5eb2 Fix backward roiutine on 32bit. 2012-06-14 16:13:59 +02:00
Milan Broz
96c8c7ba56 Print better progress status. 2012-06-14 14:58:36 +02:00
Milan Broz
29c2281ab2 Add some simple timer.
Do not use direct-io by default.
2012-06-13 13:52:51 +02:00
Milan Broz
0d70651c5a Merge branch 'reenc' of https://code.google.com/p/cryptsetup into reenc 2012-06-12 18:05:00 +02:00
Milan Broz
b1fb2532e0 Fix hex string conversion length. 2012-06-12 17:55:21 +02:00
Milan Broz
05b695d516 Merge branch 'reenc' of https://code.google.com/p/cryptsetup into reenc
Conflicts:
	src/Makefile.am
2012-06-12 13:26:09 +02:00
Milan Broz
44c9b2fc68 Comment out some temp code. 2012-06-12 13:24:39 +02:00
Milan Broz
018205a9a0 Implement forward/backward reencryption. 2012-06-12 13:24:38 +02:00
Milan Broz
c333108c61 Activate devices privately. 2012-06-12 13:24:38 +02:00
Milan Broz
2fcb521c77 Add experimental LUKS offline reencryption utility. 2012-06-12 13:24:38 +02:00
Milan Broz
0dc87d45a8 Version 1.5.0-rc1. 2012-06-11 14:56:17 +02:00
Milan Broz
03dc073f2b Use block sizes in superblock in 32bit. 2012-06-11 13:42:53 +02:00
Milan Broz
b402f087d7 Verity salt size is really uint16 in sb and uint32 internally. 2012-06-11 13:30:41 +02:00
Milan Broz
656fbde7d1 Fix inclusion of bitops.h. 2012-06-11 12:55:01 +02:00
Milan Broz
a89e6c0ca6 Introduce veritysetup for dm-verity target management. 2012-06-11 12:47:24 +02:00
Milan Broz
d380da7a32 Merge branch 'veritysetup' 2012-06-11 12:44:34 +02:00
Milan Broz
0de4b65ba6 Rename hash-start to hash-offset and switch to use bytes units. 2012-06-11 12:35:18 +02:00
Milan Broz
5c7954a0c7 Require only up to last keyslot area for header device (ignore data offset).
Fix header backup and restore to work on files with large data offset.
2012-06-11 12:20:19 +02:00
Milan Broz
62f334cfa5 Check various number limits. 2012-06-11 00:09:15 +02:00
Milan Broz
6d2c15ea79 Avoid some clang warnings. 2012-06-10 19:55:43 +02:00
Milan Broz
4b8f91d0d9 Remove some compilation warnings. 2012-06-10 18:56:04 +02:00
Milan Broz
c364290be9 Silence sb warning for now. 2012-06-10 18:20:59 +02:00
Milan Broz
a14aab5df7 Loop is automatically allocated in crypt_set_data_device(). 2012-06-10 17:59:14 +02:00
Arno Wagner
47c5b5ed06 Merge branch 'master' of https://code.google.com/p/cryptsetup 2012-06-10 17:59:00 +02:00
Arno Wagner
0eae181092 synced with wiki version 2012-06-10 17:57:22 +02:00
Milan Broz
1cbc53e8ee Get rid of backing_file in struct. 2012-06-10 17:19:08 +02:00
Milan Broz
7535fdb31b Fix man page. 2012-06-10 13:08:19 +02:00
Milan Broz
de9393879e Add more verity debug messages. 2012-06-10 12:58:18 +02:00
Milan Broz
db51a343de Move defines from header. 2012-06-09 23:26:45 +02:00
Milan Broz
e2375c8368 Add verity uuid specification. 2012-06-09 23:20:43 +02:00
Milan Broz
697c6c9324 Prepare new superblock format. 2012-06-09 22:02:06 +02:00
Milan Broz
6d07be898d Enhance status of active device. 2012-06-09 18:28:00 +02:00
Milan Broz
ade21e6c60 Support empty salt for verity, support no superblock. 2012-06-09 13:12:04 +02:00
Milan Broz
fcf5b414d6 Remove redundant flags. 2012-06-09 11:54:10 +02:00
Milan Broz
92d1bebdac Fix missing lines. 2012-06-08 22:47:45 +02:00
Milan Broz
39a5408e98 Add man page. 2012-06-08 22:40:57 +02:00
Milan Broz
937f969cc4 Add verity sources to translation. 2012-06-08 21:58:16 +02:00
Milan Broz
f4101d0f8b Use action names in veritysetup (similar to cryptsetup). 2012-06-08 21:51:58 +02:00
Milan Broz
ce2218ed65 Support init_by_name for verity. 2012-06-08 16:38:26 +02:00
Milan Broz
cdae1b4c60 Move verity_sb definition to private file. 2012-06-08 10:14:54 +02:00
Milan Broz
c4b16923bb Unify dm backend for crypt/verity. 2012-06-08 10:12:12 +02:00
Milan Broz
b016e65daa Use union in dm (crypt/verity) query structure. 2012-06-08 08:58:35 +02:00
Milan Broz
c35839afbc Use configure for defaults. 2012-06-07 15:19:19 +02:00
Milan Broz
cd8826618d Warn if block exceeds page size. 2012-06-07 15:09:58 +02:00
Milan Broz
ab0f7346bc Fix some strings, fix sb_offset. 2012-06-07 14:51:42 +02:00
Milan Broz
9fb8b816c5 Change int types. 2012-06-07 14:29:43 +02:00
Milan Broz
0e79728f86 Detect dm-verity in kernel. 2012-06-07 12:32:06 +02:00
Milan Broz
4b0b82adc5 Rewrite veritysetup to use libcryptsetup. 2012-06-07 00:18:49 +02:00
Milan Broz
850799802b Add simple veritysetup test. 2012-06-03 11:14:15 +02:00
Milan Broz
ed1b59fd25 Increase devel version. 2012-05-31 15:12:24 +02:00
Milan Broz
fa98297547 Merge branch 'master' into veritysetup 2012-05-31 15:11:00 +02:00
Milan Broz
9ae7e122ac Add veritysetup. 2012-05-28 16:04:07 +02:00
Milan Broz
624157ef7b Comment out some temp code. 2012-05-23 09:50:34 +02:00
Milan Broz
5c49268c47 Implement forward/backward reencryption. 2012-05-22 23:28:38 +02:00
Milan Broz
7df1d83ebb Activate devices privately. 2012-05-22 23:27:40 +02:00
Milan Broz
555d5f6e97 Add experimental LUKS offline reencryption utility. 2012-05-22 23:27:40 +02:00
73 changed files with 13122 additions and 3987 deletions

View File

@@ -1,3 +1,47 @@
2012-10-11 Milan Broz <gmazyland@gmail.com>
* Added keyslot checker (by Arno Wagner).
* Version 1.5.1.
2012-09-11 Milan Broz <gmazyland@gmail.com>
* Add crypt_keyslot_area() API call.
2012-08-27 Milan Broz <gmazyland@gmail.com>
* Optimize seek to keyfile-offset (Issue #135, thx to dreisner).
* Fix luksHeaderBackup for very old v1.0 unaligned LUKS headers.
2012-08-12 Milan Broz <gmazyland@gmail.com>
* Allocate loop device late (only when real block device needed).
* Rework underlying device/file access functions.
* Create hash image if doesn't exist in veritysetup format.
* Provide better error message if running as non-root user (device-mapper, loop).
2012-07-10 Milan Broz <gmazyland@gmail.com>
* Version 1.5.0.
2012-06-25 Milan Broz <gmazyland@gmail.com>
* Add --device-size option for reencryption tool.
* Switch to use unit suffix for --reduce-device-size option.
* Remove open device debugging feature (no longer needed).
* Fix library name for FIPS check.
2012-06-20 Milan Broz <gmazyland@gmail.com>
* Version 1.5.0-rc2.
2012-06-18 Milan Broz <gmazyland@gmail.com>
* Introduce cryptsetup-reencrypt - experimental offline LUKS reencryption tool.
* Fix luks-header-from-active script (do not use LUKS header on-disk, add UUID).
* Add --test-passphrase option for luksOpen (check passphrase only).
2012-06-11 Milan Broz <gmazyland@gmail.com>
* Introduce veritysetup for dm-verity target management.
* Version 1.5.0-rc1.
2012-06-10 Milan Broz <gmazyland@gmail.com>
* Both data and header device can now be a file.
* Loop is automatically allocated in crypt_set_data_device().
* Require only up to last keyslot area for header device (ignore data offset).
* Fix header backup and restore to work on files with large data offset.
2012-05-27 Milan Broz <gmazyland@gmail.com>
* Fix readonly activation if underlying device is readonly (1.4.0).
* Include stddef.h in libdevmapper.h (size_t definition).

332
FAQ
View File

@@ -8,6 +8,7 @@ Sections
6. Backup and Data Recovery
7. Interoperability with other Disk Encryption Tools
8. Issues with Specific Versions of cryptsetup
9. References and Further Reading
A. Contributors
@@ -37,6 +38,11 @@ A. Contributors
such a disaster! In particular, make sure you have a current header
backup before doing any potentially dangerous operations.
SSDs/FLASH DRIVES: SSDs and Flash are different. Currently it is
unclear how to get LUKS or plain dm-crypt to run on them with the
full set of security features intact. This may or may not be a
problem, depending on the attacher model. See Section 5.17.
BACKUP: Yes, encrypted disks die, just as normal ones do. A full
backup is mandatory, see Section "6. Backup and Data Recovery" on
options for doing encrypted backup.
@@ -58,7 +64,7 @@ A. Contributors
installers after a complete backup of all LUKS containers has been
made.
NO WARNING ON NON-INERACTIVE FORMAT: If you feed cryptsetup from
NO WARNING ON NON-INTERACTIVE FORMAT: If you feed cryptsetup from
STDIN (e.g. via GnuPG) on LUKS format, it does not give you the
warning that you are about to format (and e.g. will lose any
pre-existing LUKS container on the target), as it assumes it is
@@ -77,16 +83,16 @@ A. Contributors
PASSPHRASE CHARACTER SET: Some people have had difficulties with
this when upgrading distributions. It is highly advisable to only
use the 94 printable characters from the first 128 characters of
use the 95 printable characters from the first 128 characters of
the ASCII table, as they will always have the same binary
representation. Other characters may have different encoding
depending on system configuration and your passphrase will not
work with a different encoding. A table of the standardized first
128 ASCII caracters can, e.g. be found on
128 ASCII characters can, e.g. be found on
http://en.wikipedia.org/wiki/ASCII
* 1.3 System Specific warnings
* 1.3 System specific warnings
- Ubuntu as of 4/2011: It seems the installer offers to create
LUKS partitions in a way that several people mistook for an offer
@@ -98,8 +104,37 @@ A. Contributors
This issue has been acknowledged by the Ubuntu dev team, see here:
http://launchpad.net/bugs/420080
Update 7/2012: I am unsure whether this has been fixed by now, best
be careful.
* 1.4 Who wrote this?
* 1.4 My LUKS-device is broken! Help!
First: Do not panic! In many cases the data is still recoverable.
Do not do anything hasty! Steps:
- Take some deep breaths. Maybe add some relaxing music. This may
sound funny, but I am completely serious. Often, critical damage is
done only after the initial problem.
- Do not reboot. The keys mays still be in the kernel if the device
is mapped.
- Make sure others do not reboot the system.
- Do not write to your disk without a clear understanding why this
will not make matters worse. Do a sector-level backup before any
writes. Often you do not need to write at all to get enough access
to make a backup of the data.
- Relax some more.
- Read section 6 of this FAQ.
- Ask on the mailing-list if you need more help.
* 1.5 Who wrote this?
Current FAQ maintainer is Arno Wagner <arno@wagner.name>. Other
contributors are listed at the end. If you want to contribute, send
@@ -154,8 +189,12 @@ A. Contributors
* 2.1 What is the difference between "plain" and LUKS format?
First, unless you happen to understand the cryptographic background
well, you should use LUKS. It does protect the user from a lot of
common mistakes. Plain dm-crypt is for experts.
Plain format is just that: It has no metadata on disk, reads all
paramters from the commandline (or the defaults), derives a
parameters from the commandline (or the defaults), derives a
master-key from the passphrase and then uses that to de-/encrypt
the sectors of the device, with a direct 1:1 mapping between
encrypted and decrypted sectors.
@@ -182,15 +221,15 @@ A. Contributors
properties like key-slot diffusion and salts, etc..
LUKS format uses a metadata header and 8 key-slot areas that are
being placed ath the begining of the disk, see below under "What
being placed at the beginning of the disk, see below under "What
does the LUKS on-disk format looks like?". The passphrases are used
to decryt a single master key that is stored in the anti-forensic
to decrypt a single master key that is stored in the anti-forensic
stripes.
Advantages are a higher usability, automatic configuration of
non-default crypto parameters, defenses against low-entropy
passphrases like salting and iterated PBKDF2 passphrase hashing,
the ability to change passhrases, and others.
the ability to change passphrases, and others.
Disadvantages are that it is readily obvious there is encrypted
data on disk (but see side note above) and that damage to the
@@ -243,14 +282,14 @@ A. Contributors
new key-slot.
* 2.5 Encrytion on top of RAID or the other way round?
* 2.5 Encryption on top of RAID or the other way round?
Unless you have special needs, place encryption between RAID and
filesystem, i.e. encryption on top of RAID. You can do it the other
way round, but you have to be aware that you then need to give the
pasphrase for each individual disk and RAID autotetection will not
work anymore. Therefore it is better to encrypt the RAID device,
e.g. /dev/dm0 .
passphrase for each individual disk and RAID autodetection will
not work anymore. Therefore it is better to encrypt the RAID
device, e.g. /dev/dm0 .
* 2.6 How do I read a dm-crypt key from file?
@@ -358,7 +397,7 @@ A. Contributors
LUKS container does not resize the filesystem in it. The backup is
really non-optional here, as a lot can go wrong, resulting in
partial or complete data loss. Using something like gparted to
resize an encrypted partition is slow, but typicaly works. This
resize an encrypted partition is slow, but typically works. This
will not change the size of the filesystem hidden under the
encryption though.
@@ -455,7 +494,7 @@ A. Contributors
* 3.6 cryptsetup segfaults on Gentoo amd64 hardened ...
There seems to be some inteference between the hardening and and
There seems to be some interference between the hardening and and
the way cryptsetup benchmarks PBKDF2. The solution to this is
currently not quite clear for an encrypted root filesystem. For
other uses, you can apparently specify USE="dynamic" as compile
@@ -471,7 +510,7 @@ A. Contributors
This means that the given keyslot has an offset that points
outside the valid keyslot area. Typically, the reason is a
corrupted LUKS header because something was written to the start of
the device the LUKS contaner is on. Refer to Section "Backup and
the device the LUKS container is on. Refer to Section "Backup and
Data Recovery" and ask on the mailing list if you have trouble
diagnosing and (if still possible) repairing this.
@@ -535,7 +574,7 @@ A. Contributors
- Run Memtest86+ for one cycle
- Run memterster for one cycle (shut down as many other applications
- Run memtester for one cycle (shut down as many other applications
as possible)
- Run Memtest86+ for 24h or more
@@ -607,7 +646,7 @@ A. Contributors
(keyslots x stripes x keysize) + offset bytes. For the default
parameters, this is the 1'052'672 bytes, i.e. 1MiB + 4096 of the
LUKS partition. For 512 bit key length (e.g. for aes-xts-plain with
512 bit key) this is 2MiB. (The diferent offset stems from
512 bit key) this is 2MiB. (The different offset stems from
differences in the sector alignment of the key-slots.) If in doubt,
just be generous and overwrite the first 10MB or so, it will likely
still be fast enough. A single overwrite with zeros should be
@@ -629,8 +668,8 @@ A. Contributors
in this regard. Still, due to the anti-forensic properties of the
LUKS key-slots, a single overwrite of an SSD or FLASH drive could
be enough. If in doubt, use physical destruction in addition. Here
is a link to some current reseach results on erasing SSDs and FLASH
drives:
is a link to some current research results on erasing SSDs and
FLASH drives:
http://www.usenix.org/events/fast11/tech/full_papers/Wei.pdf
Keep in mind to also erase all backups.
@@ -845,7 +884,7 @@ A. Contributors
computed. This serves to prevent attacks using special programmable
circuits, like FPGAs, and attacks using graphics cards. PBKDF2
does not need a lot of memory and is vulnerable to these attacks.
However, the publication usually refered in these discussions is
However, the publication usually referred in these discussions is
not very convincing in proving that the presented hash really is
"large memory" (that may change, email the FAQ maintainer when it
does) and it is of limited usefulness anyways. Attackers that use
@@ -853,10 +892,10 @@ A. Contributors
memory" property. For example the US Secret Service is known to
use the off-hour time of all the office PCs of the Treasury for
password breaking. The Treasury has about 110'000 employees.
Asuming every one has an office PC, that is significant computing
Assuming every one has an office PC, that is significant computing
power, all of it with plenty of memory for computing "large
memory" hashes. Bot-net operators also have all the memory they
want. The only protection against a resouceful attacker is a
want. The only protection against a resourceful attacker is a
high-entropy passphrase, see items 5.8 and 5.9.
@@ -877,7 +916,7 @@ A. Contributors
to give it low entropy. One possibility is to supply the master key
yourself. If that key is low-entropy, then you get what you
deserve. The other known possibility is to use /dev/urandom for
key generation in an entropy-startved situation (e.g. automatic
key generation in an entropy-starved situation (e.g. automatic
installation on an embedded device without network and other entropy
sources).
@@ -893,6 +932,8 @@ A. Contributors
* 5.13 Why was the default aes-cbc-plain replaced with aes-cbc-essiv?
Note: This item applies both to plain dm-crypt and to LUKS
The problem is that cbc-plain has a fingerprint vulnerability, where
a specially crafted file placed into the crypto-container can be
recognized from the outside. The issue here is that for cbc-plain
@@ -971,6 +1012,132 @@ A. Contributors
entropy-starved situation.
* 5.16 What about Plausible Deniability?
First let me attempt a definition for the case of encrypted
filesystems: Plausible deniability is when you hide encrypted data
inside an encrypted container and it is not possible to prove it is
there. The idea is compelling and on first glance it seems
possible to do it. And from a cryptographic point of view, it
actually is possible.
So, does it work in practice? No, unfortunately. The reasoning used
by its proponents is fundamentally flawed in several ways and the
cryptographic properties fail fatally when colliding with the real
world.
First, why should "I do not have a hidden partition" be any more
plausible than "I forgot my crypto key" or "I wiped that partition
with random data, nothing in there"? I do not see any reason.
Second, there are two types of situations: Either they cannot force
you to give them the key (then you simply do not) or the can. In
the second case, they can always do bad things to you, because they
cannot prove that you have the key in the first place! This means
they do not have to prove you have the key, or that this random
looking data on your disk is actually encrypted data. So the
situation will allow them to waterboard/lock-up/deport you
anyways, regardless of how "plausible" your deniability is. Do not
have a hidden partition you could show to them, but there are
indications you may? Too bad for you. Unfortunately "plausible
deniability" also means you cannot prove there is no hidden data.
Third, hidden partitions are not that hidden. There are basically
just two possibilities: a) Make a large crypto container, but put a
smaller filesystem in there and put the hidden partition into the
free space. Unfortunately this is glaringly obvious and can be
detected in an automated fashion. This means that the initial
suspicion to put you under duress in order to make you reveal you
hidden data is given. b) Make a filesystem that spans the whole
encrypted partition, and put the hidden partition into space not
currently used by that filesystem. Unfortunately that is also
glaringly obvious, as you then cannot write to the filesystem
without a high risk of destroying data in the hidden container.
Have not written anything to the encrypted filesystem in a while?
Too bad, they have the suspicion they need to do unpleasant things
to you.
To be fair, if you prepare option b) carefully and directly before
going into danger, it may work. But then, the mere presence of
encrypted data may already be enough to get you into trouble in
those places were they can demand encryption keys.
Here is an additional reference for some problems with plausible
deniability: http://www.schneier.com/paper-truecrypt-dfs.pdf I
strongly suggest you read it.
So, no, I will not provide any instructions on how to do it with
plain dm-crypt or LUKS. If you insist on shooting yourself in the
foot, you can figure out how to do it yourself.
* 5.17 What about SSDs or Flash Drives?
The problem is that you cannot reliably erase parts of these
devices, mainly due to wear-leveling and possibly defect
management.
Basically, when overwriting a sector (of 512B), what the device
does is to move an internal sector (may be 128kB or even larger) to
some pool of discarded, not-yet erased unused sectors, take a
fresh empty sector from the empty-sector pool and copy the old
sector over with the changes to the small part you wrote. This is
done in some fashion so that larger writes do not cause a lot of
small internal updates.
The thing is that the mappings between outside-adressable sectors
and inside sectors is arbitrary (and the vendors are not talking).
Also the discarded sectors are not necessarily erased immediately.
They may linger a long time.
For plain dm-crypt, the consequences are that older encrypted data
may be lying around in some internal pools of the device. Thus may
or may not be a problem and depends on the application. Remember
the same can happen with a filesystem if consecutive writes to the
same area of a file can go to different sectors.
However, for LUKS, the worst case is that key-slots and LUKS
header may end up in these internal pools. This means that password
management functionality is compromised (the old passwords may
still be around, potentially for a very long time) and that fast
erase by overwriting the header and key-slot area is insecure.
Also keep in mind that the discarded/used pool may be large. For
example, a 240GB SSD has about 16GB of spare area in the chips that
it is free to do with as it likes. You would need to make each
individual key-slot larger than that to allow reliable overwriting.
And that assumes the disk thinks all other space is in use.
Reading the internal pools using forensic tools is not that hard,
but may involve some soldering.
What to do?
If you trust the device vendor (you probably should not...) you can
try an ATA "secure erase" command for SSDs. That does not work for
USB keys though. And if it finishes after a few seconds, it was
possibly faked by the SSD.
If you can do without password management and are fine with doing
physical destruction for permenently deleting data (allways after
one or several full overwrites!), you can use plain dm-crypt or
LUKS.
If you want or need the original LUKS security features to work,
you can use a detached LUKS header and put that on a conventional,
magnetic disk. That leaves potentially old encrypted data in the
pools on the disk, but otherwise you get LUKS with the same
security as on a magnetic disk.
If you are concerned about your laptop being stolen, you are likely
fine using LUKS on an SSD. An attacker would need to have access
to an old passphrase (and the key-slot for this old passphrase
would actually need to still be somewhere in the SSD) for your
data to be at risk. So unless you pasted your old passphrase all
over the Internet or the attacker has knowledge of it from some
other source and does a targetted laptop theft to get at your
data, you should be fine.
6. Backup and Data Recovery
@@ -986,7 +1153,7 @@ A. Contributors
impossible. This is a frequent occurrence. For example an
accidental format as FAT or some software overwriting the first
sector where it suspects a partition boot sector typically makes a
LUKS partition permanently inacessible. See more below on LUKS
LUKS partition permanently inaccessible. See more below on LUKS
header damage.
So, data-backup in some form is non-optional. For LUKS, you may
@@ -1017,7 +1184,7 @@ A. Contributors
cryptsetup -v isLuks <device>
on the device. Without the "-v" it just signals its result via
exit-status. You can alos use the more general test
exit-status. You can also use the more general test
blkid -p <device>
@@ -1059,7 +1226,7 @@ A. Contributors
cat backup.tbz2.gpg | gpg - | tar djf -
Note: Allways verify backups, especially encrypted ones.
Note: Always verify backups, especially encrypted ones.
In both cases GnuPG will ask you interactively for your symmetric
key. The verify will only output errors. Use "tar dvjf -" to get
@@ -1071,7 +1238,7 @@ A. Contributors
an asymmetric key if you have one and have a backup of the secret
key that belongs to it.
A second option for a filestem-level backup that can be used when
A second option for a filesystem-level backup that can be used when
the backup is also on local disk (e.g. an external USB drive) is
to use a LUKS container there and copy the files to be backed up
between both mounted containers. Also see next item.
@@ -1165,7 +1332,7 @@ A. Contributors
I have not tried the different ways to do this, but very likely you
will have written a new boot-sector, which in turn overwrites the
LUKS header, including the salts, making your data permanently
irretrivable, unless you have a LUKS header backup. You may also
irretrievable, unless you have a LUKS header backup. You may also
damage the key-slots in part or in full. See also last item.
@@ -1187,11 +1354,11 @@ A. Contributors
key afterwards. Changing the master key requires a full data
backup, luksFormat and then restore of the backup.
First, there is a script by Milan that automatizes the whole
First, there is a script by Milan that automates the whole
process, except generating a new LUKS header with the old master
key (it prints the command for that though):
http://code.google.com/p/cryptsetup/source/browse/trunk/misc/luks-header-from-active
http://code.google.com/p/cryptsetup/source/browse/misc/luks-header-from-active
You can also do this manually. Here is how:
@@ -1216,7 +1383,8 @@ http://code.google.com/p/cryptsetup/source/browse/trunk/misc/luks-header-from-ac
- Do a luksFormat to create a new LUKS header.
NOTE: If your header is intact and you just forgot the
passphrase, you can just set a new passphrase, see next subitem.
passphrase, you can just set a new passphrase, see next
sub-item.
Unmap the device before you do that (luksClose). Then do
@@ -1295,9 +1463,9 @@ http://code.google.com/p/cryptsetup/source/browse/trunk/misc/luks-header-from-ac
Note: From cryptsetup 1.3 onwards, alignment is set to 1MB. With
modern Linux partitioning tools that also align to 1MB, this will
result in aligmnet to 2k secors and typical Flash/SSD sectors,
result in alignment to 2k sectors and typical Flash/SSD sectors,
which is highly desirable for a number of reasons. Changing the
alignment is not recomended.
alignment is not recommended.
That said, with default parameters, the data area starts at
exactly 2MB offset (at 0x101000 for cryptsetup versions before
@@ -1339,7 +1507,7 @@ http://code.google.com/p/cryptsetup/source/browse/trunk/misc/luks-header-from-ac
cryptsetup luksFormat -c blowfish -s 64 --align-payload=8 /dev/loop0
This results in a data offset of 0x41000, i.e. 260kiB or 266240
bytes, with a minimal LUKS conatiner size of 260kiB + 512B or
bytes, with a minimal LUKS container size of 260kiB + 512B or
266752 bytes.
@@ -1366,7 +1534,7 @@ http://code.google.com/p/cryptsetup/source/browse/trunk/misc/luks-header-from-ac
container, then to clone the contents of the source container, with
both containers mapped, i.e. decrypted. You can clone the decrypted
contents of a LUKS container in binary mode, although you may run
into secondary issuses with GUIDs in filesystems, partition tables,
into secondary issues with GUIDs in filesystems, partition tables,
RAID-components and the like. These are just the normal problems
binary cloning causes.
@@ -1383,14 +1551,14 @@ http://code.google.com/p/cryptsetup/source/browse/trunk/misc/luks-header-from-ac
Cryptsetup for plain dm-crypt can be used to access a number of
on-disk formats created by tools like loop-aes patched into
losetup. This somtimes works and sometimes does not. This section
collects insights into what works, what does not and where more
information is required.
losetup. This sometimes works and sometimes does not. This
section collects insights into what works, what does not and where
more information is required.
Additional information may be found in the mailing-list archives,
mentioned at the start of this FAQ document. If you have a
solution working that is not yet documented here and think a wider
audience may be intertested, please email the FAQ maintainer.
audience may be interested, please email the FAQ maintainer.
* 7.2 loop-aes: General observations.
@@ -1399,7 +1567,7 @@ http://code.google.com/p/cryptsetup/source/browse/trunk/misc/luks-header-from-ac
loop-aes is a patch for losetup. Possible problems and deviations
from cryptsetup option syntax include:
- Offsets specifed in bytes (cryptsetup: 512 byte sectors)
- Offsets specified in bytes (cryptsetup: 512 byte sectors)
- The need to specify an IV offset
@@ -1410,27 +1578,27 @@ http://code.google.com/p/cryptsetup/source/browse/trunk/misc/luks-header-from-ac
- Passphrase hash algorithm needs specifying
Also note that because plain dm-crypt and loop-aes format does not
have metadata, autodetection, while feasible in most cases, would
be a lot of work that nobody really wants to do. If you still have
the old set-up, using a verbosity option (-v) on mapping with the
old tool or having a look into the system logs after setup could
give you the information you need.
have metadata, and while the loopAES extension for cryptsetup tries
autodetection (see command loopaesOpen), it may not always work.
If you still have the old set-up, using a verbosity option (-v)
on mapping with the old tool or having a look into the system logs
after setup could give you the information you need. Below, there
are also some things that worked for somebody.
* 7.3 loop-aes patched into losetup on debian 5.x, kernel 2.6.32
* 7.3 loop-aes patched into losetup on Debian 5.x, kernel 2.6.32
In this case, the main problem seems to be that this variant of
losetup takes the offset (-o option) in bytes, while cryptsetup
takes it in sectors of 512 bytes each. Example: The losetupp
command
takes it in sectors of 512 bytes each. Example: The losetup command
losetup -e twofish -o 2560 /dev/loop0 /dev/sdb1
mount /dev/loop0 mountpoint
mount /dev/loop0 mount-point
translates to
cryptsetup create -c twofish -o 5 --skip 5 e1 /dev/sdb1
mount /dev/mapper/e1 mountpoint
mount /dev/mapper/e1 mount-point
* 7.4 loop-aes with 160 bit key
@@ -1442,6 +1610,15 @@ http://code.google.com/p/cryptsetup/source/browse/trunk/misc/luks-header-from-ac
--cipher twofish-cbc-null -s 192 -h ripemd160:20
* 7.5 loop-aes v1 format OpenSUSE
Apparently this is done by older OpenSUSE distros and stopped
working from OpenSUSE 12.1 to 12.2. One user had success with the
following:
cryptsetup create <target> <device> -c aes -s 128 -h sha256
8. Issues with Specific Versions of cryptsetup
@@ -1473,6 +1650,59 @@ http://code.google.com/p/cryptsetup/source/browse/trunk/misc/luks-header-from-ac
version of cryptsetup (1.0.x) provided by SLED, which should also
not be used anymore as well. My advice would be to drop SLED 10.
9. References and Further Reading
* Purpose of this Section
The purpose of this section is to collect references to all
materials that do not fit the FAQ but are relevant in some fashion.
This can be core topics like the LUKS spec or disk encryption, but
it can also be more tangential, like secure storage management or
cryptography used in LUKS. It should still have relevance to
cryptsetup and its applications.
If you wan to see something added here, send email to the
maintainer (or the cryptsetup mailing list) giving an URL, a
description (1-3 lines preferred) and a section to put it in. You
can also propose new sections.
At this time I would like to limit the references to things that
are available on the web.
* Specifications
- LUKS on-disk format spec:
http://code.google.com/p/cryptsetup/wiki/Specification
* Code Examples
- Some code examples are in the source package under docs/examples
* Tools
* SSD and Flash Disk Related
* Disk Encryption
* Attacks Against Disk Encryption
* Risk Management as Relevant for Disk Encryption
* Cryptography
* Secure Storage
A. Contributors In no particular order:
- Arno Wagner

6
TODO
View File

@@ -1,7 +1,7 @@
Version 1.5.0:
Version 1.6.0:
- Export wipe device functions
- Support K/M suffixes for align payload (new switch?).
- FIPS patches (RNG, volume key restrictions, move changekey to library)
- FIPS: move changekey to library
- online reencryption api?
- integrate more metadata formats
- TRIM for keyslots
- TRIM for keyslots

View File

@@ -1,9 +1,11 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[1.4.3])
AC_INIT([cryptsetup],[1.5.1])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
LIBCRYPTSETUP_VERSION_INFO=6:0:2
LIBCRYPTSETUP_VERSION_INFO=8:0:4
dnl library file name for FIPS selfcheck
LIBCRYPTSETUP_VERSION_FIPS="libcryptsetup.so.4"
AC_CONFIG_SRCDIR(src/cryptsetup.c)
AC_CONFIG_MACRO_DIR([m4])
@@ -69,6 +71,8 @@ AC_ARG_ENABLE([fips], AS_HELP_STRING([--enable-fips],[enable FIPS mode restricti
if test "x$with_fips" = "xyes"; then
AC_DEFINE(ENABLE_FIPS, 1, [Enable FIPS mode restrictions])
AC_DEFINE_UNQUOTED(LIBCRYPTSETUP_VERSION_FIPS, ["$LIBCRYPTSETUP_VERSION_FIPS"],
[library file name for FIPS selfcheck])
if test "x$enable_static" = "xyes" -o "x$enable_static_cryptsetup" = "xyes" ; then
AC_MSG_ERROR([Static build is not compatible with FIPS.])
@@ -186,7 +190,17 @@ if test x$enable_static_cryptsetup = xyes; then
enable_static=yes
fi
fi
AM_CONDITIONAL(STATIC_CRYPTSETUP, test x$enable_static_cryptsetup = xyes)
AM_CONDITIONAL(STATIC_TOOLS, test x$enable_static_cryptsetup = xyes)
AC_ARG_ENABLE(veritysetup,
AS_HELP_STRING([--disable-veritysetup],
[disable veritysetup support]),[], [enable_veritysetup=yes])
AM_CONDITIONAL(VERITYSETUP, test x$enable_veritysetup = xyes)
AC_ARG_ENABLE([cryptsetup-reencrypt],
AS_HELP_STRING([--enable-cryptsetup-reencrypt],
[enable cryptsetup-reencrypt tool]))
AM_CONDITIONAL(REENCRYPT, test x$enable_cryptsetup_reencrypt = xyes)
AC_ARG_ENABLE(selinux,
AS_HELP_STRING([--disable-selinux],
@@ -279,6 +293,7 @@ AC_SUBST([CRYPTO_STATIC_LIBS])
AC_SUBST([LIBCRYPTSETUP_VERSION])
AC_SUBST([LIBCRYPTSETUP_VERSION_INFO])
AC_SUBST([LIBCRYPTSETUP_VERSION_FIPS])
dnl ==========================================================================
AC_ARG_ENABLE([dev-random], AS_HELP_STRING([--enable-dev-random],
@@ -335,8 +350,13 @@ CS_NUM_WITH([luks1-keybits],[key length in bits for LUKS1], [256])
CS_STR_WITH([loopaes-cipher], [cipher for loop-AES mode], [aes])
CS_NUM_WITH([loopaes-keybits],[key length in bits for loop-AES mode], [256])
CS_NUM_WITH([keyfile-size-maxkb],[maximum keyfile size (in kilobytes)], [8192])
CS_NUM_WITH([passphrase-size-max],[maximum keyfile size (in kilobytes)], [512])
CS_NUM_WITH([keyfile-size-maxkb],[maximum keyfile size (in KiB)], [8192])
CS_NUM_WITH([passphrase-size-max],[maximum keyfile size (in characters)], [512])
CS_STR_WITH([verity-hash], [hash function for verity mode], [sha256])
CS_NUM_WITH([verity-data-block], [data block size for verity mode], [4096])
CS_NUM_WITH([verity-hash-block], [hash block size for verity mode], [4096])
CS_NUM_WITH([verity-salt-size], [salt size for verity mode], [32])
dnl ==========================================================================
@@ -346,6 +366,7 @@ lib/libcryptsetup.pc
lib/crypto_backend/Makefile
lib/luks1/Makefile
lib/loopaes/Makefile
lib/verity/Makefile
src/Makefile
po/Makefile.in
man/Makefile

View File

@@ -3,6 +3,8 @@
*
* The documentation covers public parts of cryptsetup API. In the following sections you'll find
* the examples that describe some features of cryptsetup API.
* For more info about libcryptsetup API versions see
* <a href="http://upstream-tracker.org/versions/libcryptsetup.html">Upstream Tracker</a>.
*
* <OL type="A">
* <LI>@ref cexamples "Cryptsetup API examples"</LI>

241
docs/v1.5.0-ReleaseNotes Normal file
View File

@@ -0,0 +1,241 @@
Cryptsetup 1.5.0 Release Notes
==============================
This release covers mainly inclusion of:
* Veritysetup tool (and related libcryptsetup extensions for dm-verity).
* Experimental cryptsetup-reencrypt tool (LUKS offline reencryption).
Changes since version 1.5.0-rc2
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Add --device-size option for reencryption tool.
* Switch to use unit suffix for --reduce-device-size option.
* Remove open device debugging feature (no longer needed).
* Fix library name for FIPS check.
* Add example of using reencryption inside dracut (see misc/dracut).
Changes since version 1.5.0-rc1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Introduce cryptsetup-reencrypt - experimental offline LUKS reencryption tool.
! cryptsetup-reencrypt tool is EXPERIMENTAL
! ALWAYS BE SURE YOU HAVE RELIABLE BACKUP BEFORE USING THIS TOOL
This tool tries to simplify situation when you need to re-encrypt the whole
LUKS device in situ (without need to move data elsewhere).
This can happen for example when you want to change volume (master) key,
encryption algorithm, or other encryption parameter.
Cryptsetup-reencrypt can even optionally shift data on device
(reducing data device size - you need some free space at the end of device).
In general, cryptsetup-reencrypt can be used to
- re-generate volume key
- change arbitrary encryption parameters
- add encryption to not yet encrypted drive
Side effect of reencryption is that final device will contain
only ciphertext (for all sectors) so even if device was not properly
wiped by random data, after reencryption you cannot distinguish
which sectors are used.
(Reecryption is done always for the whole device.)
There are for sure bugs, please TEST IT IN TEST ENVIRONMENT before
use for your data.
This tool is not resistant to HW and kernel failures - hw crash
will cause serious data corruption.
You can enable compilation of this tool with --enable-cryptsetup-reencrypt
configure option (it is switched off by default).
(Tool requires libcryptsetup 1.4.3 and later.)
You have to provide all keyslot passphrases or use --keyslot-option
(then all other keyslots will be disabled).
EXAMPLES (from man page)
Reencrypt /dev/sdb1 (change volume key)
# cryptsetup-reencrypt /dev/sdb1
Reencrypt and also change cipher and cipher mode
# cryptsetup-reencrypt /dev/sdb1 -c aes-xts-plain64
Note: if you are changing key size, there must be enough space
for keyslots in header or you have to use --reduce-device size and
reduce fs in advance.
Add LUKS encryption to not yet encrypted device
First, be sure you have space added to disk.
Or, alternatively, shrink filesystem in advance.
Here we need 4096 512-bytes sectors (enough for 2x128 bit key).
# fdisk -u /dev/sdb # move sdb1 partition end + 4096 sectors
# cryptsetup-reencrypt /dev/sdb1 --new --reduce-device-size 4096
There are some options which can improve performance (depends on system),
namely --use-directio (use direct IO for all operations) can be faster
on some systems. See man page.
Progress and estimated time is printed during reencryption.
You can suspend reencryption (using ctrl+c or term signal).
To continue reencryption you have to provide only
the device parameter (offset is stored in temporary log file).
Please note LUKS device is marked invalid during reencryption and
you have to retain tool temporary files until reencryption finishes.
Temporary files are LUKS-<uuid>.[log|org|new]
Other changes
~~~~~~~~~~~~~
* Fix luks-header-from-active script (do not use LUKS header on-disk, add UUID).
* Add --test-passphrase option for luksOpen (check passphrase only).
* Fix parsing of hexadecimal string (salt or root hash) in veritysetup.
Changes since version 1.4.3
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Introduce veritysetup tool for dm-verity target management.
The dm-verity device-mapper target was added to Linux kernel 3.4 and
provides transparent integrity checking of block devices using a cryptographic
digest provided by the kernel crypto API. This target is read-only.
It is meant to be setup as part of a verified boot path (it was originally
developed by Chrome OS authors as part of verified boot infrastructure).
For deeper description please see http://code.google.com/p/cryptsetup/wiki/DMVerity
and kernel dm-verity documentation.
The libcryptsetup library was extended to support manipulation
with dm-verity kernel module and new veritysetup CLI tool is added.
There are no additional library requirements (it uses the same crypto
backend as cryptsetup).
If you want compile cryptsetup without veritysetup tool,
use --disable-veritysetup configure option.
For other configuration option see configure --help and veritysetup --help
(e.g. default parameters).
Supported libcryptsetup functions new CRYPT_VERITY type:
crypt_init
crypt_init_by_name
crypt_set_data device
crypt_get_type
crypt_format
crypt_load
crypt_get_active_device
crypt_activate_by_volume_key (volume key == root hash here)
crypt_dump
and new introduced function
crypt_get_verity_info
Please see comments in libcryptsetup.h and veritysetup.c as an code example
how to use CRYPT_VERITY API.
The veritysetup tool supports these operations:
veritysetup format <data_device> <hash_device>
Formats <hash_device> (calculates all hash areas according to <data_device>).
This is initial command to prepare device <hash_device> for later verification.
veritysetup create <name> <data_device> <hash_device> <root_hash>
Creates (activates) a dm-verity mapping with <name> backed by device <data_device>
and using <hash_device> for in-kernel verification.
veritysetup verify <data_device> <hash_device> <root_hash>
Verifies data in userspace (no kernel device is activated).
veritysetup remove <name>
Removes activated device from kernel (similar to dmsetup remove).
veritysetup status <name>
Reports status for the active kernel dm-verity device.
veritysetup dump <hash_device>
Reports parameters of verity device from on-disk stored superblock.
For more info see veritysetup --help and veritysetup man page.
Other changes
~~~~~~~~~~~~~
* Both data and header device can now be a file and
loop device is automatically allocated.
* Require only up to last keyslot area for header device, previously
backup (and activation) required device/file of size up to data start
offset (data payload).
* Fix header backup and restore to work on files with large data offset.
Backup and restore now works even if backup file is smaller than data offset.
Appendix: Examples of veritysetup use
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Format device using default parameters, info and final root hash is printed:
# veritysetup format /dev/sdb /dev/sdc
VERITY header information for /dev/sdc
UUID: fad30431-0c59-4fa6-9b57-732a90501f75
Hash type: 1
Data blocks: 52224
Data block size: 4096
Hash block size: 4096
Hash algorithm: sha256
Salt: 5cc52759af76a092e0c21829cd0ef6938f69831bf86926525106f92a7e9e3aa9
Root hash: 7aefa4506f7af497ac491a27f862cf8005ea782a5d97f6426945a6896ab557a1
Activation of device in-kernel:
# veritysetup create vr /dev/sdb /dev/sdc 7aefa4506f7af497ac491a27f862cf8005ea782a5d97f6426945a6896ab557a1
Note - if device is corrupted, kernel mapping is created but will report failure:
Verity device detected corruption after activation.
Userspace verification:
# veritysetup verify /dev/sdb /dev/sdc 7aefa4506f7af497ac491a27f862cf8005ea782a5d97f6426945a6896ab557a1
Verification failed at position 8192.
Verification of data area failed.
Active device status report:
# veritysetup status vr
/dev/mapper/vr is active.
type: VERITY
status: verified
hash type: 1
data block: 4096
hash block: 4096
hash name: sha256
salt: 5cc52759af76a092e0c21829cd0ef6938f69831bf86926525106f92a7e9e3aa9
data device: /dev/sdb
size: 417792 sectors
mode: readonly
hash device: /dev/sdc
hash offset: 8 sectors
Dump of on-disk superblock information:
# veritysetup dump /dev/sdc
VERITY header information for /dev/sdc
UUID: fad30431-0c59-4fa6-9b57-732a90501f75
Hash type: 1
Data blocks: 52224
Data block size: 4096
Hash block size: 4096
Hash algorithm: sha256
Salt: 5cc52759af76a092e0c21829cd0ef6938f69831bf86926525106f92a7e9e3aa9
Remove mapping:
# veritysetup remove vr

32
docs/v1.5.1-ReleaseNotes Normal file
View File

@@ -0,0 +1,32 @@
Cryptsetup 1.5.1 Release Notes
==============================
Changes since version 1.5.0
* The libcryptsetup library now tries to initialize device-mapper backend and
loop devices only if they are really needed (lazy initializations).
This allows some operations to be run by a non-root user.
(Unfortunately LUKS header keyslot operations still require temporary dm-crypt
device and device-mapper subsystem is available only to superuser.)
Also clear error messages are provided if running as non-root user and
operation requires privileged user.
* Veritysetup can be now used by a normal user for creating hash image to file
and also it can create hash image if doesn't exist.
(Previously it required pre-allocated space.)
* Added crypt_keyslot_area() API call which allows external tools
to get exact keyslot offsets and analyse content.
An example of a tool that searches the keyslot area of a LUKS container
for positions where entropy is low and hence there is a high probability
of damage is in misc/kesylot_checker.
(Thanks to Arno Wagner for the code.)
* Optimized seek to keyfile-offset if key offset is large.
* Fixed luksHeaderBackup for very old v1.0 unaligned LUKS headers.
* Various fixes for problems found by a several static analysis tools.

View File

@@ -1,4 +1,4 @@
SUBDIRS = crypto_backend luks1 loopaes
SUBDIRS = crypto_backend luks1 loopaes verity
moduledir = $(libdir)/cryptsetup
@@ -10,6 +10,7 @@ INCLUDES = \
-I$(top_srcdir)/lib/crypto_backend \
-I$(top_srcdir)/lib/luks1 \
-I$(top_srcdir)/lib/loopaes \
-I$(top_srcdir)/lib/verity \
-DDATADIR=\""$(datadir)"\" \
-DLIBDIR=\""$(libdir)"\" \
-DPREFIX=\""$(prefix)"\" \
@@ -24,7 +25,8 @@ lib_LTLIBRARIES = libcryptsetup.la
common_ldadd = \
crypto_backend/libcrypto_backend.la \
luks1/libluks1.la \
loopaes/libloopaes.la
loopaes/libloopaes.la \
verity/libverity.la
libcryptsetup_la_DEPENDENCIES = $(common_ldadd) libcryptsetup.sym
@@ -45,18 +47,19 @@ libcryptsetup_la_LIBADD = \
libcryptsetup_la_SOURCES = \
setup.c \
internal.h \
bitops.h \
nls.h \
libcryptsetup.h \
utils.c \
utils_crypt.c \
utils_crypt.h \
utils_debug.c \
utils_loop.c \
utils_loop.h \
utils_devpath.c \
utils_wipe.c \
utils_fips.c \
utils_fips.h \
utils_device.c \
libdevmapper.c \
utils_dm.h \
volumekey.c \

83
lib/bitops.h Normal file
View File

@@ -0,0 +1,83 @@
#ifndef BITOPS_H
#define BITOPS_H
#include <stdint.h>
/*
* Bit map related macros. Usually provided by libc.
*/
#include <sys/param.h>
#ifndef NBBY
# define NBBY CHAR_BIT
#endif
#ifndef setbit
# define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
# define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
# define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
# define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
#endif
/*
* Byte swab macros (based on linux/byteorder/swab.h)
*/
#define swab16(x) \
((uint16_t)( \
(((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
(((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
#define swab32(x) \
((uint32_t)( \
(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
#define swab64(x) \
((uint64_t)( \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
(uint64_t)(((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) ))
#ifdef WORDS_BIGENDIAN
#define cpu_to_le16(x) swab16(x)
#define cpu_to_le32(x) swab32(x)
#define cpu_to_le64(x) swab64(x)
#define cpu_to_be16(x) ((uint16_t)(x))
#define cpu_to_be32(x) ((uint32_t)(x))
#define cpu_to_be64(x) ((uint64_t)(x))
#define le16_to_cpu(x) swab16(x)
#define le32_to_cpu(x) swab32(x)
#define le64_to_cpu(x) swab64(x)
#define be16_to_cpu(x) ((uint16_t)(x))
#define be32_to_cpu(x) ((uint32_t)(x))
#define be64_to_cpu(x) ((uint64_t)(x))
#else /* !WORDS_BIGENDIAN */
#define cpu_to_le16(x) ((uint16_t)(x))
#define cpu_to_le32(x) ((uint32_t)(x))
#define cpu_to_le64(x) ((uint64_t)(x))
#define cpu_to_be16(x) swab16(x)
#define cpu_to_be32(x) swab32(x)
#define cpu_to_be64(x) swab64(x)
#define le16_to_cpu(x) ((uint16_t)(x))
#define le32_to_cpu(x) ((uint32_t)(x))
#define le64_to_cpu(x) ((uint64_t)(x))
#define be16_to_cpu(x) swab16(x)
#define be32_to_cpu(x) swab32(x)
#define be64_to_cpu(x) swab64(x)
#endif /* WORDS_BIGENDIAN */
#endif /* BITOPS_H */

View File

@@ -32,12 +32,15 @@
#include <inttypes.h>
#include "nls.h"
#include "bitops.h"
#include "utils_crypt.h"
#include "utils_loop.h"
#include "utils_dm.h"
#include "utils_fips.h"
#include "crypto_backend.h"
#include "libcryptsetup.h"
/* to silent gcc -Wcast-qual for const cast */
#define CONST_CAST(x) (x)(uintptr_t)
@@ -60,27 +63,44 @@ struct volume_key *crypt_alloc_volume_key(unsigned keylength, const char *key);
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, unsigned keylength);
void crypt_free_volume_key(struct volume_key *vk);
/* Device backend */
struct device;
int device_alloc(struct device **device, const char *path);
void device_free(struct device *device);
const char *device_path(const struct device *device);
const char *device_block_path(const struct device *device);
void device_topology_alignment(struct device *device,
unsigned long *required_alignment, /* bytes */
unsigned long *alignment_offset, /* bytes */
unsigned long default_alignment);
int device_block_size(struct device *device);
int device_read_ahead(struct device *device, uint32_t *read_ahead);
int device_size(struct device *device, uint64_t *size);
enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 };
int device_block_adjust(struct crypt_device *cd,
struct device *device,
enum devcheck device_check,
uint64_t device_offset,
uint64_t *size,
uint32_t *flags);
size_t size_round_up(size_t size, unsigned int block);
/* Receive backend devices from context helpers */
struct device *crypt_metadata_device(struct crypt_device *cd);
struct device *crypt_data_device(struct crypt_device *cd);
int crypt_confirm(struct crypt_device *cd, const char *msg);
char *crypt_lookup_dev(const char *dev_id);
int crypt_sysfs_check_crypt_segment(const char *device, uint64_t offset, uint64_t size);
int crypt_sysfs_get_rotational(int major, int minor, int *rotational);
int sector_size_for_device(const char *device);
int device_read_ahead(const char *dev, uint32_t *read_ahead);
ssize_t write_blockwise(int fd, void *buf, size_t count);
ssize_t read_blockwise(int fd, void *_buf, size_t count);
ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset);
int device_ready(struct crypt_device *cd, const char *device, int mode);
int device_size(const char *device, uint64_t *size);
ssize_t write_blockwise(int fd, int bsize, void *buf, size_t count);
ssize_t read_blockwise(int fd, int bsize, void *_buf, size_t count);
ssize_t write_lseek_blockwise(int fd, int bsize, char *buf, size_t count, off_t offset);
unsigned crypt_getpagesize(void);
enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 };
int device_check_and_adjust(struct crypt_device *cd,
const char *device,
enum devcheck device_check,
uint64_t *size,
uint64_t *offset,
uint32_t *flags);
void logger(struct crypt_device *cd, int class, const char *file, int line, const char *format, ...);
#define log_dbg(x...) logger(NULL, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
@@ -89,16 +109,10 @@ void logger(struct crypt_device *cd, int class, const char *file, int line, cons
#define log_err(c, x...) logger(c, CRYPT_LOG_ERROR, __FILE__, __LINE__, x)
int crypt_get_debug_level(void);
void debug_processes_using_device(const char *name);
int crypt_memlock_inc(struct crypt_device *ctx);
int crypt_memlock_dec(struct crypt_device *ctx);
void get_topology_alignment(const char *device,
unsigned long *required_alignment, /* bytes */
unsigned long *alignment_offset, /* bytes */
unsigned long default_alignment);
int crypt_random_init(struct crypt_device *ctx);
int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int quality);
void crypt_random_exit(void);
@@ -127,7 +141,7 @@ typedef enum {
* random algorithm */
} crypt_wipe_type;
int crypt_wipe(const char *device,
int crypt_wipe(struct device *device,
uint64_t offset,
uint64_t sectors,
crypt_wipe_type type,

View File

@@ -226,14 +226,13 @@ void crypt_set_iterarion_time(struct crypt_device *cd, uint64_t iteration_time_m
void crypt_set_password_verify(struct crypt_device *cd, int password_verify);
/**
* Set data device (encrypted payload area device) if LUKS header is separated
* Set data device
* For LUKS it is encrypted data device when LUKS header is separated.
* For VERITY it is data device when hash device is separated.
*
* @param cd crypt device handle
* @param device path to device
*
* @pre context is of LUKS type
* @pre unlike @ref crypt_init, in this function param @e device
* has to be block device (at least 512B large)
*/
int crypt_set_data_device(struct crypt_device *cd, const char *device);
@@ -301,6 +300,8 @@ int crypt_memory_lock(struct crypt_device *cd, int lock);
#define CRYPT_LUKS1 "LUKS1"
/** loop-AES compatibility mode */
#define CRYPT_LOOPAES "LOOPAES"
/** dm-verity mode */
#define CRYPT_VERITY "VERITY"
/**
* Get device type
@@ -351,6 +352,34 @@ struct crypt_params_loopaes {
uint64_t skip; /**< IV offset / initialization sector */
};
/**
*
* Structure used as parameter for dm-verity device type
*
* @see crypt_format, crypt_load
*
*/
/** No on-disk header (only hashes) */
#define CRYPT_VERITY_NO_HEADER (1 << 0)
/** Verity hash in userspace before activation */
#define CRYPT_VERITY_CHECK_HASH (1 << 1)
/** Create hash - format hash device */
#define CRYPT_VERITY_CREATE_HASH (1 << 2)
struct crypt_params_verity {
const char *hash_name; /**< hash function */
const char *data_device; /**< data_device (CRYPT_VERITY_CREATE_HASH) */
const char *hash_device; /**< hash_device (output only) */
const char *salt; /**< salt */
uint32_t salt_size; /**< salt size (in bytes) */
uint32_t hash_type; /**< in-kernel hashing type */
uint32_t data_block_size; /**< data block size (in bytes) */
uint32_t hash_block_size; /**< hash block size (in bytes) */
uint64_t data_size; /**< data area size (in data blocks) */
uint64_t hash_area_offset; /**< hash/header offset (in bytes) */
uint32_t flags; /**< CRYPT_VERITY* flags */
};
/** @} */
/**
@@ -369,8 +398,10 @@ struct crypt_params_loopaes {
*
* @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 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
* are ignored and verity specific attributes are set through mandatory params option.
*/
int crypt_format(struct crypt_device *cd,
const char *type,
@@ -406,7 +437,7 @@ int crypt_set_uuid(struct crypt_device *cd,
* @post In case LUKS header is read successfully but payload device is too small
* error is returned and device type in context is set to @e NULL
*
* @note Note that in current version load works only for LUKS device type
* @note Note that in current version load works only for LUKS and VERITY device type.
*
*/
int crypt_load(struct crypt_device *cd,
@@ -539,16 +570,6 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
const char *new_passphrase,
size_t new_passphrase_size);
/**
* Get number of keyslots supported for device type.
*
* @param type crypt device type
*
* @return slot count or negative errno otherwise if device
* doesn't not support keyslots.
*/
int crypt_keyslot_max(const char *type);
/**
* Add key slot using provided key file path
*
@@ -643,6 +664,8 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
#define CRYPT_ACTIVATE_ALLOW_DISCARDS (1 << 3)
/** skip global udev rules in activation ("private device"), input only */
#define CRYPT_ACTIVATE_PRIVATE (1 << 4)
/** corruption detected (verity), output only */
#define CRYPT_ACTIVATE_CORRUPTED (1 << 5)
/**
* Active device runtime attributes
@@ -734,6 +757,9 @@ int crypt_activate_by_keyfile(struct crypt_device *cd,
* @note If @e NULL is used for volume_key, device has to be initialized
* by previous operation (like @ref crypt_format
* or @ref crypt_init_by_name)
* @note For VERITY the volume key means root hash required for activation.
* Because kernel dm-verity is always read only, you have to provide
* CRYPT_ACTIVATE_READONLY flag always.
*/
int crypt_activate_by_volume_key(struct crypt_device *cd,
const char *name,
@@ -787,9 +813,8 @@ int crypt_volume_key_verify(struct crypt_device *cd,
const char *volume_key,
size_t volume_key_size);
/*
* @defgroup devstat "dmcrypt device status"
/**
* @defgroup devstat "Crypt and Verity device status"
* @addtogroup devstat
* @{
*/
@@ -816,7 +841,7 @@ typedef enum {
crypt_status_info crypt_status(struct crypt_device *cd, const char *name);
/**
* Dump text-formatted information about crypt device to log output
* Dump text-formatted information about crypt or verity device to log output
*
* @param cd crypt device handle
*
@@ -894,6 +919,19 @@ uint64_t crypt_get_iv_offset(struct crypt_device *cd);
*/
int crypt_get_volume_key_size(struct crypt_device *cd);
/**
* Get device parameters for VERITY device
*
* @param cd crypt device handle
* @param vp verity device info
*
* @e 0 on success or negative errno value otherwise.
*
*/
int crypt_get_verity_info(struct crypt_device *cd,
struct crypt_params_verity *vp);
/** @} */
/**
* @addtogroup keyslot
* @{
@@ -924,6 +962,32 @@ typedef enum {
crypt_keyslot_info crypt_keyslot_status(struct crypt_device *cd, int keyslot);
/** @} */
/**
* Get number of keyslots supported for device type.
*
* @param type crypt device type
*
* @return slot count or negative errno otherwise if device
* doesn't not support keyslots.
*/
int crypt_keyslot_max(const char *type);
/**
* Get keyslot area pointers (relative to metadata device)
*
* @param cd crypt device handle
* @param keyslot keyslot number
* @param offset offset on metadata device (in bytes)
* @param length length of keyslot area (in bytes)
*
* @return @e 0 on success or negative errno value otherwise.
*
*/
int crypt_keyslot_area(struct crypt_device *cd,
int keyslot,
uint64_t *offset,
uint64_t *length);
/**
* Backup header and keyslots to file
*

View File

@@ -46,6 +46,7 @@ CRYPTSETUP_1.0 {
crypt_get_iv_offset;
crypt_get_volume_key_size;
crypt_get_device_name;
crypt_get_verity_info;
crypt_get_type;
crypt_get_active_device;
@@ -54,6 +55,7 @@ CRYPTSETUP_1.0 {
crypt_get_rng_type;
crypt_keyslot_max;
crypt_keyslot_area;
crypt_keyslot_status;
crypt_last_error;
crypt_get_error;

File diff suppressed because it is too large Load Diff

View File

@@ -192,18 +192,21 @@ int LOOPAES_activate(struct crypt_device *cd,
uint32_t req_flags;
int r;
struct crypt_dm_active_device dmd = {
.device = crypt_get_device_name(cd),
.cipher = NULL,
.target = DM_CRYPT,
.uuid = crypt_get_uuid(cd),
.vk = vk,
.offset = crypt_get_data_offset(cd),
.iv_offset = crypt_get_iv_offset(cd),
.size = 0,
.flags = flags
.flags = flags,
.data_device = crypt_data_device(cd),
.u.crypt = {
.cipher = NULL,
.vk = vk,
.offset = crypt_get_data_offset(cd),
.iv_offset = crypt_get_iv_offset(cd),
}
};
r = device_check_and_adjust(cd, dmd.device, DEV_EXCL, &dmd.size, &dmd.offset, &flags);
r = device_block_adjust(cd, dmd.data_device, DEV_EXCL,
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
if (r)
return r;
@@ -217,10 +220,11 @@ int LOOPAES_activate(struct crypt_device *cd,
if (r < 0)
return -ENOMEM;
dmd.cipher = cipher;
log_dbg("Trying to activate loop-AES device %s using cipher %s.", name, dmd.cipher);
dmd.u.crypt.cipher = cipher;
log_dbg("Trying to activate loop-AES device %s using cipher %s.",
name, dmd.u.crypt.cipher);
r = dm_create_device(name, CRYPT_LOOPAES, &dmd, 0);
r = dm_create_device(cd, name, CRYPT_LOOPAES, &dmd, 0);
if (!r && !(dm_flags() & req_flags)) {
log_err(cd, _("Kernel doesn't support loop-AES compatible mapping.\n"));

View File

@@ -66,9 +66,14 @@ out:
static int diffuse(char *src, char *dst, size_t size, const char *hash_name)
{
unsigned int digest_size = crypt_hash_size(hash_name);
int hash_size = crypt_hash_size(hash_name);
unsigned int digest_size;
unsigned int i, blocks, padding;
if (hash_size <= 0)
return 1;
digest_size = hash_size;
blocks = size / digest_size;
padding = size % digest_size;
@@ -141,3 +146,17 @@ out:
free(bufblock);
return r;
}
/* Size of final split data including sector alignment */
size_t AF_split_sectors(size_t blocksize, unsigned int blocknumbers)
{
size_t af_size;
/* data material * stripes */
af_size = blocksize * blocknumbers;
/* round up to sector */
af_size = (af_size + (SECTOR_SIZE - 1)) / SECTOR_SIZE;
return af_size;
}

View File

@@ -38,5 +38,6 @@
int AF_split(char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash);
int AF_merge(char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash);
size_t AF_split_sectors(size_t blocksize, unsigned int blocknumbers);
#endif

View File

@@ -21,13 +21,6 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/utsname.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
@@ -36,54 +29,46 @@
#include "luks.h"
#include "internal.h"
#define div_round_up(a,b) ({ \
typeof(a) __a = (a); \
typeof(b) __b = (b); \
(__a - 1) / __b + 1; \
})
static inline int round_up_modulo(int x, int m) {
return div_round_up(x, m) * m;
}
static const char *cleaner_name=NULL;
static uint64_t cleaner_size = 0;
static int devfd=-1;
static int setup_mapping(const char *cipher, const char *name,
const char *device,
struct volume_key *vk,
unsigned int bsize, struct volume_key *vk,
unsigned int sector, size_t srcLength,
int mode, struct crypt_device *ctx)
{
int device_sector_size = sector_size_for_device(device);
struct device *device = crypt_metadata_device(ctx);
struct crypt_dm_active_device dmd = {
.device = device,
.cipher = cipher,
.target = DM_CRYPT,
.uuid = NULL,
.vk = vk,
.offset = sector,
.iv_offset = 0,
.size = 0,
.flags = 0
.size = size_round_up(srcLength, bsize) / SECTOR_SIZE,
.flags = CRYPT_ACTIVATE_PRIVATE,
.data_device = device,
.u.crypt = {
.cipher = cipher,
.vk = vk,
.offset = sector,
.iv_offset = 0,
}
};
int r;
dmd.flags = CRYPT_ACTIVATE_PRIVATE;
if (mode == O_RDONLY)
dmd.flags |= CRYPT_ACTIVATE_READONLY;
/*
* we need to round this to nearest multiple of the underlying
* device's sector size, otherwise the mapping will be refused.
*/
if(device_sector_size < 0) {
log_err(ctx, _("Unable to obtain sector size for %s"), device);
return -EINVAL;
r = device_block_adjust(ctx, dmd.data_device, DEV_OK,
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
if (r < 0)
return r;
if (mode != O_RDONLY && dmd.flags & CRYPT_ACTIVATE_READONLY) {
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
device_path(device));
return -EACCES;
}
dmd.size = round_up_modulo(srcLength,device_sector_size)/SECTOR_SIZE;
cleaner_size = dmd.size;
return dm_create_device(name, "TEMP", &dmd, 0);
return dm_create_device(ctx, name, "TEMP", &dmd, 0);
}
static void sigint_handler(int sig __attribute__((unused)))
@@ -92,7 +77,7 @@ static void sigint_handler(int sig __attribute__((unused)))
close(devfd);
devfd = -1;
if(cleaner_name)
dm_remove_device(cleaner_name, 1, cleaner_size);
dm_remove_device(NULL, cleaner_name, 1, cleaner_size);
signal(SIGINT, SIG_DFL);
kill(getpid(), SIGINT);
@@ -113,9 +98,8 @@ static const char *_error_hint(char *cipherMode, size_t keyLength)
static int LUKS_endec_template(char *src, size_t srcLength,
struct luks_phdr *hdr,
struct volume_key *vk,
const char *device,
unsigned int sector,
ssize_t (*func)(int, void *, size_t),
ssize_t (*func)(int, int, void *, size_t),
int mode,
struct crypt_device *ctx)
{
@@ -124,10 +108,14 @@ static int LUKS_endec_template(char *src, size_t srcLength,
char *dmCipherSpec = NULL;
const char *dmDir = dm_get_dir();
int r = -1;
int bsize = device_block_size(crypt_metadata_device(ctx));
if (bsize <= 0)
return -EINVAL;
if(dmDir == NULL) {
log_err(ctx, _("Failed to obtain device mapper directory."));
return -1;
return -EINVAL;
}
if(asprintf(&name,"temporary-cryptsetup-%d",getpid()) == -1 ||
asprintf(&fullpath,"%s/%s",dmDir,name) == -1 ||
@@ -139,12 +127,12 @@ static int LUKS_endec_template(char *src, size_t srcLength,
signal(SIGINT, sigint_handler);
cleaner_name = name;
r = setup_mapping(dmCipherSpec, name, device,
vk, sector, srcLength, mode, ctx);
r = setup_mapping(dmCipherSpec, name, bsize, vk, sector, srcLength, mode, ctx);
if(r < 0) {
log_err(ctx, _("Failed to setup dm-crypt key mapping for device %s.\n"
if (r != -EACCES && r != -ENOTSUP)
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%s"),
device, dmCipherSpec,
device_path(crypt_metadata_device(ctx)), dmCipherSpec,
_error_hint(hdr->cipherMode, vk->keylength * 8));
r = -EIO;
goto out1;
@@ -157,7 +145,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
goto out2;
}
r = func(devfd,src,srcLength);
r = func(devfd, bsize, src, srcLength);
if(r < 0) {
log_err(ctx, _("Failed to access temporary keystore device.\n"));
r = -EIO;
@@ -169,7 +157,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
close(devfd);
devfd = -1;
out2:
dm_remove_device(cleaner_name, 1, cleaner_size);
dm_remove_device(ctx, cleaner_name, 1, cleaner_size);
out1:
signal(SIGINT, SIG_DFL);
cleaner_name = NULL;
@@ -183,21 +171,19 @@ static int LUKS_endec_template(char *src, size_t srcLength,
int LUKS_encrypt_to_storage(char *src, size_t srcLength,
struct luks_phdr *hdr,
struct volume_key *vk,
const char *device,
unsigned int sector,
struct crypt_device *ctx)
{
return LUKS_endec_template(src,srcLength,hdr,vk, device,
sector, write_blockwise, O_RDWR, ctx);
return LUKS_endec_template(src, srcLength, hdr, vk, sector,
write_blockwise, O_RDWR, ctx);
}
int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
struct luks_phdr *hdr,
struct volume_key *vk,
const char *device,
unsigned int sector,
struct crypt_device *ctx)
{
return LUKS_endec_template(dst,dstLength,hdr,vk, device,
sector, read_blockwise, O_RDONLY, ctx);
return LUKS_endec_template(dst, dstLength, hdr, vk, sector,
read_blockwise, O_RDONLY, ctx);
}

View File

@@ -36,49 +36,61 @@
#include "pbkdf.h"
#include "internal.h"
#define div_round_up(a,b) ({ \
typeof(a) __a = (a); \
typeof(b) __b = (b); \
(__a - 1) / __b + 1; \
})
static inline int round_up_modulo(int x, int m) {
return div_round_up(x, m) * m;
}
/* Get size of struct luks_phrd with all keyslots material space */
static uint64_t LUKS_device_sectors(size_t keyLen, unsigned int stripes)
/* Get size of struct luks_phdr with all keyslots material space */
static size_t LUKS_device_sectors(size_t keyLen)
{
uint64_t keyslot_sectors, sector;
size_t keyslot_sectors, sector;
int i;
keyslot_sectors = div_round_up(keyLen * stripes, SECTOR_SIZE);
sector = round_up_modulo(LUKS_PHDR_SIZE, LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
keyslot_sectors = AF_split_sectors(keyLen, LUKS_STRIPES);
sector = LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE;
for (i = 0; i < LUKS_NUMKEYS; i++) {
sector = round_up_modulo(sector, LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
sector = size_round_up(sector, LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
sector += keyslot_sectors;
}
return sector;
}
static int LUKS_check_device_size(const char *device,
uint64_t min_sectors,
size_t keyLength)
int LUKS_keyslot_area(struct luks_phdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length)
{
uint64_t dev_size, req_sectors;
if(keyslot >= LUKS_NUMKEYS || keyslot < 0)
return -EINVAL;
req_sectors = LUKS_device_sectors(keyLength, LUKS_STRIPES);
if (min_sectors > req_sectors)
req_sectors = min_sectors;
*offset = hdr->keyblock[keyslot].keyMaterialOffset * SECTOR_SIZE;
*length = AF_split_sectors(hdr->keyBytes, LUKS_STRIPES) * SECTOR_SIZE;
if(device_size(device, &dev_size)) {
log_dbg("Cannot get device size for device %s.", device);
return 0;
}
static int LUKS_check_device_size(struct crypt_device *ctx, size_t keyLength)
{
struct device *device = crypt_metadata_device(ctx);
uint64_t dev_sectors, hdr_sectors;
if (!keyLength)
return -EINVAL;
if(device_size(device, &dev_sectors)) {
log_dbg("Cannot get device size for device %s.", device_path(device));
return -EIO;
}
return (req_sectors > (dev_size >> SECTOR_SHIFT));
dev_sectors >>= SECTOR_SHIFT;
hdr_sectors = LUKS_device_sectors(keyLength);
log_dbg("Key length %u, device size %" PRIu64 " sectors, header size %"
PRIu64 " sectors.",keyLength, dev_sectors, hdr_sectors);
if (hdr_sectors > dev_sectors) {
log_err(ctx, _("Device %s is too small.\n"), device_path(device));
return -EINVAL;
}
return 0;
}
/* Check keyslot to prevent access outside of header and keyslot area */
@@ -104,7 +116,7 @@ static int LUKS_check_keyslot_size(const struct luks_phdr *phdr, unsigned int ke
return 1;
}
secs_per_stripes = div_round_up(phdr->keyBytes * phdr->keyblock[keyIndex].stripes, SECTOR_SIZE);
secs_per_stripes = AF_split_sectors(phdr->keyBytes, phdr->keyblock[keyIndex].stripes);
if (phdr->payloadOffset < (phdr->keyblock[keyIndex].keyMaterialOffset + secs_per_stripes)) {
log_dbg("Invalid keyslot size %u (offset %u, stripes %u) in "
@@ -136,10 +148,10 @@ static const char *dbg_slot_state(crypt_keyslot_info ki)
int LUKS_hdr_backup(
const char *backup_file,
const char *device,
struct luks_phdr *hdr,
struct crypt_device *ctx)
{
struct device *device = crypt_metadata_device(ctx);
int r = 0, devfd = -1;
ssize_t buffer_size;
char *buffer = NULL;
@@ -150,11 +162,11 @@ int LUKS_hdr_backup(
return -EINVAL;
}
r = LUKS_read_phdr(device, hdr, 1, 0, ctx);
r = LUKS_read_phdr(hdr, 1, 0, ctx);
if (r)
return r;
buffer_size = hdr->payloadOffset << SECTOR_SHIFT;
buffer_size = LUKS_device_sectors(hdr->keyBytes) << SECTOR_SHIFT;
buffer = crypt_safe_alloc(buffer_size);
if (!buffer || buffer_size < LUKS_ALIGN_KEYSLOTS) {
r = -ENOMEM;
@@ -164,21 +176,22 @@ int LUKS_hdr_backup(
log_dbg("Storing backup of header (%u bytes) and keyslot area (%u bytes).",
sizeof(*hdr), buffer_size - LUKS_ALIGN_KEYSLOTS);
devfd = open(device, O_RDONLY | O_DIRECT | O_SYNC);
devfd = open(device_path(device), O_RDONLY | O_DIRECT | O_SYNC);
if(devfd == -1) {
log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device);
log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device_path(device));
r = -EINVAL;
goto out;
}
if(read_blockwise(devfd, buffer, buffer_size) < buffer_size) {
if(read_blockwise(devfd, device_block_size(device), buffer, buffer_size) < buffer_size) {
r = -EIO;
goto out;
}
close(devfd);
/* Wipe unused area, so backup cannot contain old signatures */
memset(buffer + sizeof(*hdr), 0, LUKS_ALIGN_KEYSLOTS - sizeof(*hdr));
if (hdr->keyblock[0].keyMaterialOffset * SECTOR_SIZE == LUKS_ALIGN_KEYSLOTS)
memset(buffer + sizeof(*hdr), 0, LUKS_ALIGN_KEYSLOTS - sizeof(*hdr));
devfd = creat(backup_file, S_IRUSR);
if(devfd == -1) {
@@ -202,12 +215,12 @@ out:
int LUKS_hdr_restore(
const char *backup_file,
const char *device,
struct luks_phdr *hdr,
struct crypt_device *ctx)
{
struct device *device = crypt_metadata_device(ctx);
int r = 0, devfd = -1, diff_uuid = 0;
ssize_t buffer_size;
ssize_t buffer_size = 0;
char *buffer = NULL, msg[200];
struct stat st;
struct luks_phdr hdr_file;
@@ -217,8 +230,9 @@ int LUKS_hdr_restore(
return -EINVAL;
}
r = LUKS_read_phdr_backup(backup_file, device, &hdr_file, 0, ctx);
buffer_size = hdr_file.payloadOffset << SECTOR_SHIFT;
r = LUKS_read_phdr_backup(backup_file, &hdr_file, 0, ctx);
if (!r)
buffer_size = LUKS_device_sectors(hdr_file.keyBytes) << SECTOR_SHIFT;
if (r || buffer_size < LUKS_ALIGN_KEYSLOTS) {
log_err(ctx, _("Backup file doesn't contain valid LUKS header.\n"));
@@ -246,9 +260,9 @@ int LUKS_hdr_restore(
}
close(devfd);
r = LUKS_read_phdr(device, hdr, 0, 0, ctx);
r = LUKS_read_phdr(hdr, 0, 0, ctx);
if (r == 0) {
log_dbg("Device %s already contains LUKS header, checking UUID and offset.", device);
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"));
@@ -259,7 +273,7 @@ int LUKS_hdr_restore(
diff_uuid = 1;
}
if (snprintf(msg, sizeof(msg), _("Device %s %s%s"), device,
if (snprintf(msg, sizeof(msg), _("Device %s %s%s"), device_path(device),
r ? _("does not contain LUKS header. Replacing header can destroy data on that device.") :
_("already contains LUKS header. Replacing header will destroy existing keyslots."),
diff_uuid ? _("\nWARNING: real device header has different UUID than backup!") : "") < 0) {
@@ -273,23 +287,27 @@ int LUKS_hdr_restore(
}
log_dbg("Storing backup of header (%u bytes) and keyslot area (%u bytes) to device %s.",
sizeof(*hdr), buffer_size - LUKS_ALIGN_KEYSLOTS, device);
sizeof(*hdr), buffer_size - LUKS_ALIGN_KEYSLOTS, device_path(device));
devfd = open(device, O_WRONLY | O_DIRECT | O_SYNC);
devfd = open(device_path(device), O_WRONLY | O_DIRECT | O_SYNC);
if(devfd == -1) {
log_err(ctx, _("Cannot open device %s.\n"), device);
if (errno == EACCES)
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
device_path(device));
else
log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
r = -EINVAL;
goto out;
}
if(write_blockwise(devfd, buffer, buffer_size) < buffer_size) {
if (write_blockwise(devfd, device_block_size(device), buffer, buffer_size) < buffer_size) {
r = -EIO;
goto out;
}
close(devfd);
/* Be sure to reload new data */
r = LUKS_read_phdr(device, hdr, 1, 0, ctx);
r = LUKS_read_phdr(hdr, 1, 0, ctx);
out:
if (devfd != -1)
close(devfd);
@@ -298,7 +316,7 @@ out:
}
/* This routine should do some just basic recovery for known problems. */
static int _keyslot_repair(const char *device, struct luks_phdr *phdr, struct crypt_device *ctx)
static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
{
struct luks_phdr temp_phdr;
const unsigned char *sector = (const unsigned char*)phdr;
@@ -327,7 +345,7 @@ static int _keyslot_repair(const char *device, struct luks_phdr *phdr, struct cr
phdr->hashSpec,phdr->uuid, LUKS_STRIPES,
phdr->payloadOffset, 0,
1, &PBKDF2_per_sec,
"/dev/null", ctx);
1, ctx);
if (r < 0) {
log_err(ctx, _("Repair failed."));
goto out;
@@ -375,7 +393,7 @@ static int _keyslot_repair(const char *device, struct luks_phdr *phdr, struct cr
if (need_write) {
log_verbose(ctx, _("Writing LUKS header to disk.\n"));
r = LUKS_write_phdr(device, phdr, ctx);
r = LUKS_write_phdr(phdr, ctx);
}
out:
crypt_free_volume_key(vk);
@@ -432,7 +450,7 @@ static int _check_and_convert_hdr(const char *device,
if (repair) {
if (r == -EINVAL)
r = _keyslot_repair(device, hdr, ctx);
r = _keyslot_repair(hdr, ctx);
else
log_verbose(ctx, _("No known problems detected for LUKS header.\n"));
}
@@ -455,7 +473,6 @@ static void LUKS_fix_header_compatible(struct luks_phdr *header)
}
int LUKS_read_phdr_backup(const char *backup_file,
const char *device,
struct luks_phdr *hdr,
int require_luks_device,
struct crypt_device *ctx)
@@ -468,7 +485,7 @@ int LUKS_read_phdr_backup(const char *backup_file,
devfd = open(backup_file, O_RDONLY);
if(-1 == devfd) {
log_err(ctx, _("Cannot open file %s.\n"), device);
log_err(ctx, _("Cannot open file %s.\n"), backup_file);
return -EINVAL;
}
@@ -484,41 +501,50 @@ int LUKS_read_phdr_backup(const char *backup_file,
return r;
}
int LUKS_read_phdr(const char *device,
struct luks_phdr *hdr,
int LUKS_read_phdr(struct luks_phdr *hdr,
int require_luks_device,
int repair,
struct crypt_device *ctx)
{
struct device *device = crypt_metadata_device(ctx);
ssize_t hdr_size = sizeof(struct luks_phdr);
int devfd = 0, r = 0;
/* LUKS header starts at offset 0, first keyslot on LUKS_ALIGN_KEYSLOTS */
assert(sizeof(struct luks_phdr) <= LUKS_ALIGN_KEYSLOTS);
/* Stripes count cannot be changed without additional code fixes yet */
assert(LUKS_STRIPES == 4000);
if (repair && !require_luks_device)
return -EINVAL;
log_dbg("Reading LUKS header of size %d from device %s",
hdr_size, device);
hdr_size, device_path(device));
devfd = open(device,O_RDONLY | O_DIRECT | O_SYNC);
if(-1 == devfd) {
log_err(ctx, _("Cannot open device %s.\n"), device);
devfd = open(device_path(device), O_RDONLY | O_DIRECT | O_SYNC);
if (devfd == -1) {
log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
return -EINVAL;
}
if (read_blockwise(devfd, hdr, hdr_size) < hdr_size)
if (read_blockwise(devfd, device_block_size(device), hdr, hdr_size) < hdr_size)
r = -EIO;
else
r = _check_and_convert_hdr(device, hdr, require_luks_device,
r = _check_and_convert_hdr(device_path(device), hdr, require_luks_device,
repair, ctx);
if (!r)
r = LUKS_check_device_size(ctx, hdr->keyBytes);
close(devfd);
return r;
}
int LUKS_write_phdr(const char *device,
struct luks_phdr *hdr,
int LUKS_write_phdr(struct luks_phdr *hdr,
struct crypt_device *ctx)
{
struct device *device = crypt_metadata_device(ctx);
ssize_t hdr_size = sizeof(struct luks_phdr);
int devfd = 0;
unsigned int i;
@@ -526,16 +552,19 @@ int LUKS_write_phdr(const char *device,
int r;
log_dbg("Updating LUKS header of size %d on device %s",
sizeof(struct luks_phdr), device);
sizeof(struct luks_phdr), device_path(device));
if (LUKS_check_device_size(device, hdr->payloadOffset, hdr->keyBytes)) {
log_err(ctx, _("Device %s is too small.\n"), device);
return -EINVAL;
}
r = LUKS_check_device_size(ctx, hdr->keyBytes);
if (r)
return r;
devfd = open(device,O_RDWR | O_DIRECT | O_SYNC);
devfd = open(device_path(device), O_RDWR | O_DIRECT | O_SYNC);
if(-1 == devfd) {
log_err(ctx, _("Cannot open device %s.\n"), device);
if (errno == EACCES)
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
device_path(device));
else
log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
return -EINVAL;
}
@@ -554,16 +583,17 @@ int LUKS_write_phdr(const char *device,
convHdr.keyblock[i].stripes = htonl(hdr->keyblock[i].stripes);
}
r = write_blockwise(devfd, &convHdr, hdr_size) < hdr_size ? -EIO : 0;
r = write_blockwise(devfd, device_block_size(device), &convHdr, hdr_size) < hdr_size ? -EIO : 0;
if (r)
log_err(ctx, _("Error during update of LUKS header on device %s.\n"), device);
log_err(ctx, _("Error during update of LUKS header on device %s.\n"), 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(device, hdr, 1, 0, ctx);
r = LUKS_read_phdr(hdr, 1, 0, ctx);
if (r)
log_err(ctx, _("Error re-reading LUKS header after update on device %s.\n"), device);
log_err(ctx, _("Error re-reading LUKS header after update on device %s.\n"),
device_path(device));
}
return r;
@@ -592,18 +622,17 @@ int LUKS_generate_phdr(struct luks_phdr *header,
unsigned int alignOffset,
uint32_t iteration_time_ms,
uint64_t *PBKDF2_per_sec,
const char *metadata_device,
int detached_metadata_device,
struct crypt_device *ctx)
{
unsigned int i=0;
unsigned int blocksPerStripeSet = div_round_up(vk->keylength*stripes,SECTOR_SIZE);
size_t blocksPerStripeSet, currentSector;
int r;
uuid_t partitionUuid;
int currentSector;
char luksMagic[] = LUKS_MAGIC;
/* For separate metadata device allow zero alignment */
if (alignPayload == 0 && !metadata_device)
if (alignPayload == 0 && !detached_metadata_device)
alignPayload = DEFAULT_DISK_ALIGNMENT / SECTOR_SIZE;
if (PBKDF2_HMAC_ready(hashSpec) < 0) {
@@ -659,21 +688,22 @@ int LUKS_generate_phdr(struct luks_phdr *header,
return r;
}
currentSector = round_up_modulo(LUKS_PHDR_SIZE, LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
currentSector = LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE;
blocksPerStripeSet = AF_split_sectors(vk->keylength, stripes);
for(i = 0; i < LUKS_NUMKEYS; ++i) {
header->keyblock[i].active = LUKS_KEY_DISABLED;
header->keyblock[i].keyMaterialOffset = currentSector;
header->keyblock[i].stripes = stripes;
currentSector = round_up_modulo(currentSector + blocksPerStripeSet,
currentSector = size_round_up(currentSector + blocksPerStripeSet,
LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
}
if (metadata_device) {
if (detached_metadata_device) {
/* for separate metadata device use alignPayload directly */
header->payloadOffset = alignPayload;
} else {
/* alignOffset - offset from natural device alignment provided by topology info */
currentSector = round_up_modulo(currentSector, alignPayload);
currentSector = size_round_up(currentSector, alignPayload);
header->payloadOffset = currentSector + alignOffset;
}
@@ -686,7 +716,6 @@ int LUKS_generate_phdr(struct luks_phdr *header,
}
int LUKS_hdr_uuid_set(
const char *device,
struct luks_phdr *hdr,
const char *uuid,
struct crypt_device *ctx)
@@ -702,10 +731,10 @@ int LUKS_hdr_uuid_set(
uuid_unparse(partitionUuid, hdr->uuid);
return LUKS_write_phdr(device, hdr, ctx);
return LUKS_write_phdr(hdr, ctx);
}
int LUKS_set_key(const char *device, unsigned int keyIndex,
int LUKS_set_key(unsigned int keyIndex,
const char *password, size_t passwordLen,
struct luks_phdr *hdr, struct volume_key *vk,
uint32_t iteration_time_ms,
@@ -714,7 +743,7 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
{
struct volume_key *derived_key;
char *AfKey = NULL;
unsigned int AFEKSize;
size_t AFEKSize;
uint64_t PBKDF2_temp;
int r;
@@ -723,7 +752,8 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
return -EINVAL;
}
if(hdr->keyblock[keyIndex].stripes < LUKS_STRIPES) {
/* LUKS keyslot has always at least 4000 stripes accoding to specification */
if(hdr->keyblock[keyIndex].stripes < 4000) {
log_err(ctx, _("Key slot %d material includes too few stripes. Header manipulation?\n"),
keyIndex);
return -EINVAL;
@@ -754,7 +784,7 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
r = crypt_random_get(ctx, hdr->keyblock[keyIndex].passwordSalt,
LUKS_SALTSIZE, CRYPT_RND_SALT);
if (r < 0)
return r;
goto out;
r = PBKDF2_HMAC(hdr->hashSpec, password,passwordLen,
hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
@@ -767,7 +797,7 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
* AF splitting, the masterkey stored in vk->key is split to AfKey
*/
assert(vk->keylength == hdr->keyBytes);
AFEKSize = hdr->keyblock[keyIndex].stripes*vk->keylength;
AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
AfKey = crypt_safe_alloc(AFEKSize);
if (!AfKey) {
r = -ENOMEM;
@@ -780,27 +810,24 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
if (r < 0)
goto out;
log_dbg("Updating key slot %d [0x%04x] area on device %s.", keyIndex,
hdr->keyblock[keyIndex].keyMaterialOffset << 9, device);
log_dbg("Updating key slot %d [0x%04x] area.", keyIndex,
hdr->keyblock[keyIndex].keyMaterialOffset << 9);
/* Encryption via dm */
r = LUKS_encrypt_to_storage(AfKey,
AFEKSize,
hdr,
derived_key,
device,
hdr->keyblock[keyIndex].keyMaterialOffset,
ctx);
if (r < 0) {
log_err(ctx, _("Failed to write to key storage.\n"));
if (r < 0)
goto out;
}
/* Mark the key as active in phdr */
r = LUKS_keyslot_set(hdr, (int)keyIndex, 1);
if (r < 0)
goto out;
r = LUKS_write_phdr(device, hdr, ctx);
r = LUKS_write_phdr(hdr, ctx);
if (r < 0)
goto out;
@@ -830,8 +857,7 @@ int LUKS_verify_volume_key(const struct luks_phdr *hdr,
}
/* Try to open a particular key slot */
static int LUKS_open_key(const char *device,
unsigned int keyIndex,
static int LUKS_open_key(unsigned int keyIndex,
const char *password,
size_t passwordLen,
struct luks_phdr *hdr,
@@ -855,10 +881,12 @@ static int LUKS_open_key(const char *device,
return -ENOMEM;
assert(vk->keylength == hdr->keyBytes);
AFEKSize = hdr->keyblock[keyIndex].stripes*vk->keylength;
AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
AfKey = crypt_safe_alloc(AFEKSize);
if (!AfKey)
return -ENOMEM;
if (!AfKey) {
r = -ENOMEM;
goto out;
}
r = PBKDF2_HMAC(hdr->hashSpec, password,passwordLen,
hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
@@ -872,13 +900,10 @@ static int LUKS_open_key(const char *device,
AFEKSize,
hdr,
derived_key,
device,
hdr->keyblock[keyIndex].keyMaterialOffset,
ctx);
if (r < 0) {
log_err(ctx, _("Failed to read from key storage.\n"));
if (r < 0)
goto out;
}
r = AF_merge(AfKey,vk->key,vk->keylength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec);
if (r < 0)
@@ -893,8 +918,7 @@ out:
return r;
}
int LUKS_open_key_with_hdr(const char *device,
int keyIndex,
int LUKS_open_key_with_hdr(int keyIndex,
const char *password,
size_t passwordLen,
struct luks_phdr *hdr,
@@ -907,12 +931,12 @@ int LUKS_open_key_with_hdr(const char *device,
*vk = crypt_alloc_volume_key(hdr->keyBytes, NULL);
if (keyIndex >= 0) {
r = LUKS_open_key(device, keyIndex, password, passwordLen, hdr, *vk, ctx);
r = LUKS_open_key(keyIndex, password, passwordLen, hdr, *vk, ctx);
return (r < 0) ? r : keyIndex;
}
for(i = 0; i < LUKS_NUMKEYS; i++) {
r = LUKS_open_key(device, i, password, passwordLen, hdr, *vk, ctx);
r = LUKS_open_key(i, password, passwordLen, hdr, *vk, ctx);
if(r == 0)
return i;
@@ -926,15 +950,15 @@ int LUKS_open_key_with_hdr(const char *device,
return -EPERM;
}
int LUKS_del_key(const char *device,
unsigned int keyIndex,
int LUKS_del_key(unsigned int keyIndex,
struct luks_phdr *hdr,
struct crypt_device *ctx)
{
unsigned int startOffset, endOffset, stripesLen;
struct device *device = crypt_metadata_device(ctx);
unsigned int startOffset, endOffset;
int r;
r = LUKS_read_phdr(device, hdr, 1, 0, ctx);
r = LUKS_read_phdr(hdr, 1, 0, ctx);
if (r)
return r;
@@ -947,14 +971,19 @@ int LUKS_del_key(const char *device,
/* secure deletion of key material */
startOffset = hdr->keyblock[keyIndex].keyMaterialOffset;
stripesLen = hdr->keyBytes * hdr->keyblock[keyIndex].stripes;
endOffset = startOffset + div_round_up(stripesLen, SECTOR_SIZE);
endOffset = startOffset + AF_split_sectors(hdr->keyBytes, hdr->keyblock[keyIndex].stripes);
r = crypt_wipe(device, startOffset * SECTOR_SIZE,
(endOffset - startOffset) * SECTOR_SIZE,
CRYPT_WIPE_DISK, 0);
if (r) {
log_err(ctx, _("Cannot wipe device %s.\n"), device);
if (r == -EACCES) {
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
device_path(device));
r = -EINVAL;
} else
log_err(ctx, _("Cannot wipe device %s.\n"),
device_path(device));
return r;
}
@@ -962,7 +991,7 @@ int LUKS_del_key(const char *device,
memset(&hdr->keyblock[keyIndex].passwordSalt, 0, LUKS_SALTSIZE);
hdr->keyblock[keyIndex].passwordIterations = 0;
r = LUKS_write_phdr(device, hdr, ctx);
r = LUKS_write_phdr(hdr, ctx);
return r;
}
@@ -1033,14 +1062,17 @@ int LUKS1_activate(struct crypt_device *cd,
char *dm_cipher = NULL;
enum devcheck device_check;
struct crypt_dm_active_device dmd = {
.device = crypt_get_device_name(cd),
.cipher = NULL,
.target = DM_CRYPT,
.uuid = crypt_get_uuid(cd),
.vk = vk,
.offset = crypt_get_data_offset(cd),
.iv_offset = 0,
.flags = flags,
.size = 0,
.flags = flags
.data_device = crypt_data_device(cd),
.u.crypt = {
.cipher = NULL,
.vk = vk,
.offset = crypt_get_data_offset(cd),
.iv_offset = 0,
}
};
if (dmd.flags & CRYPT_ACTIVATE_SHARED)
@@ -1048,8 +1080,8 @@ int LUKS1_activate(struct crypt_device *cd,
else
device_check = DEV_EXCL;
r = device_check_and_adjust(cd, dmd.device, device_check,
&dmd.size, &dmd.offset, &dmd.flags);
r = device_block_adjust(cd, dmd.data_device, device_check,
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
if (r)
return r;
@@ -1057,8 +1089,8 @@ int LUKS1_activate(struct crypt_device *cd,
if (r < 0)
return -ENOMEM;
dmd.cipher = dm_cipher;
r = dm_create_device(name, CRYPT_LUKS1, &dmd, 0);
dmd.u.crypt.cipher = dm_cipher;
r = dm_create_device(cd, name, CRYPT_LUKS1, &dmd, 0);
free(dm_cipher);
return r;

View File

@@ -51,8 +51,6 @@
#define LUKS_MAGIC {'L','U','K','S', 0xba, 0xbe};
#define LUKS_MAGIC_L 6
#define LUKS_PHDR_SIZE (sizeof(struct luks_phdr)/SECTOR_SIZE+1)
/* Actually we need only 37, but we don't want struct autoaligning to kick in */
#define UUID_STRING_L 40
@@ -63,6 +61,7 @@
converted */
struct volume_key;
struct device_backend;
struct luks_phdr {
char magic[LUKS_MAGIC_L];
@@ -108,11 +107,10 @@ int LUKS_generate_phdr(
unsigned int alignOffset,
uint32_t iteration_time_ms,
uint64_t *PBKDF2_per_sec,
const char *metadata_device,
int detached_metadata_device,
struct crypt_device *ctx);
int LUKS_read_phdr(
const char *device,
struct luks_phdr *hdr,
int require_luks_device,
int repair,
@@ -120,36 +118,30 @@ int LUKS_read_phdr(
int LUKS_read_phdr_backup(
const char *backup_file,
const char *device,
struct luks_phdr *hdr,
int require_luks_device,
struct crypt_device *ctx);
int LUKS_hdr_uuid_set(
const char *device,
struct luks_phdr *hdr,
const char *uuid,
struct crypt_device *ctx);
int LUKS_hdr_backup(
const char *backup_file,
const char *device,
struct luks_phdr *hdr,
struct crypt_device *ctx);
int LUKS_hdr_restore(
const char *backup_file,
const char *device,
struct luks_phdr *hdr,
struct crypt_device *ctx);
int LUKS_write_phdr(
const char *device,
struct luks_phdr *hdr,
struct crypt_device *ctx);
int LUKS_set_key(
const char *device,
unsigned int keyIndex,
const char *password,
size_t passwordLen,
@@ -160,7 +152,6 @@ int LUKS_set_key(
struct crypt_device *ctx);
int LUKS_open_key_with_hdr(
const char *device,
int keyIndex,
const char *password,
size_t passwordLen,
@@ -169,7 +160,6 @@ int LUKS_open_key_with_hdr(
struct crypt_device *ctx);
int LUKS_del_key(
const char *device,
unsigned int keyIndex,
struct luks_phdr *hdr,
struct crypt_device *ctx);
@@ -178,12 +168,15 @@ crypt_keyslot_info LUKS_keyslot_info(struct luks_phdr *hdr, int keyslot);
int LUKS_keyslot_find_empty(struct luks_phdr *hdr);
int LUKS_keyslot_active_count(struct luks_phdr *hdr);
int LUKS_keyslot_set(struct luks_phdr *hdr, int keyslot, int enable);
int LUKS_keyslot_area(struct luks_phdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length);
int LUKS_encrypt_to_storage(
char *src, size_t srcLength,
struct luks_phdr *hdr,
struct volume_key *vk,
const char *device,
unsigned int sector,
struct crypt_device *ctx);
@@ -191,7 +184,6 @@ int LUKS_decrypt_from_storage(
char *dst, size_t dstLength,
struct luks_phdr *hdr,
struct volume_key *vk,
const char *device,
unsigned int sector,
struct crypt_device *ctx);

File diff suppressed because it is too large Load Diff

View File

@@ -22,22 +22,17 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <errno.h>
#include <linux/fs.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include "libcryptsetup.h"
#include "internal.h"
unsigned crypt_getpagesize(void)
{
return (unsigned)sysconf(_SC_PAGESIZE);
}
static int get_alignment(int fd)
{
int alignment = DEFAULT_MEM_ALIGNMENT;
@@ -69,52 +64,15 @@ static void *aligned_malloc(void **base, int size, int alignment)
#endif
}
int device_read_ahead(const char *dev, uint32_t *read_ahead)
{
int fd, r = 0;
long read_ahead_long;
if ((fd = open(dev, O_RDONLY)) < 0)
return 0;
r = ioctl(fd, BLKRAGET, &read_ahead_long) ? 0 : 1;
close(fd);
if (r)
*read_ahead = (uint32_t) read_ahead_long;
return r;
}
static int sector_size(int fd)
{
int bsize;
if (ioctl(fd,BLKSSZGET, &bsize) < 0)
return -EINVAL;
else
return bsize;
}
int sector_size_for_device(const char *device)
{
int fd = open(device, O_RDONLY);
int r;
if(fd < 0)
return -EINVAL;
r = sector_size(fd);
close(fd);
return r;
}
ssize_t write_blockwise(int fd, void *orig_buf, size_t count)
ssize_t write_blockwise(int fd, int bsize, void *orig_buf, size_t count)
{
void *hangover_buf, *hangover_buf_base = NULL;
void *buf, *buf_base = NULL;
int r, hangover, solid, bsize, alignment;
int r, hangover, solid, alignment;
ssize_t ret = -1;
if ((bsize = sector_size(fd)) < 0)
return bsize;
if (fd == -1 || !orig_buf || bsize <= 0)
return -1;
hangover = count % bsize;
solid = count - hangover;
@@ -158,14 +116,14 @@ out:
return ret;
}
ssize_t read_blockwise(int fd, void *orig_buf, size_t count) {
ssize_t read_blockwise(int fd, int bsize, void *orig_buf, size_t count) {
void *hangover_buf, *hangover_buf_base = NULL;
void *buf, *buf_base = NULL;
int r, hangover, solid, bsize, alignment;
int r, hangover, solid, alignment;
ssize_t ret = -1;
if ((bsize = sector_size(fd)) < 0)
return bsize;
if (fd == -1 || !orig_buf || bsize <= 0)
return -1;
hangover = count % bsize;
solid = count - hangover;
@@ -208,15 +166,15 @@ out:
* 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, char *buf, size_t count, off_t offset) {
ssize_t write_lseek_blockwise(int fd, int bsize, char *buf, size_t count, off_t offset) {
char *frontPadBuf;
void *frontPadBuf_base = NULL;
int r, bsize, frontHang;
int r, frontHang;
size_t innerCount = 0;
ssize_t ret = -1;
if ((bsize = sector_size(fd)) < 0)
return bsize;
if (fd == -1 || !buf || bsize <= 0)
return -1;
frontHang = offset % bsize;
@@ -250,7 +208,7 @@ ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset) {
count -= innerCount;
}
ret = count ? write_blockwise(fd, buf, count) : 0;
ret = count ? write_blockwise(fd, bsize, buf, count) : 0;
if (ret >= 0)
ret += innerCount;
out:
@@ -259,171 +217,6 @@ out:
return ret;
}
int device_ready(struct crypt_device *cd, const char *device, int mode)
{
int devfd, r = 0;
ssize_t s;
struct stat st;
char buf[512];
if(stat(device, &st) < 0) {
log_err(cd, _("Device %s doesn't exist or access denied.\n"), device);
return -EINVAL;
}
if (!S_ISBLK(st.st_mode))
return -ENOTBLK;
log_dbg("Trying to open and read device %s.", device);
devfd = open(device, mode | O_DIRECT | O_SYNC);
if(devfd < 0) {
log_err(cd, _("Cannot open device %s for %s%s access.\n"), device,
(mode & O_EXCL) ? _("exclusive ") : "",
(mode & O_RDWR) ? _("writable") : _("read-only"));
return -EINVAL;
}
/* Try to read first sector */
s = read_blockwise(devfd, buf, sizeof(buf));
if (s < 0 || s != sizeof(buf)) {
log_verbose(cd, _("Cannot read device %s.\n"), device);
r = -EIO;
}
memset(buf, 0, sizeof(buf));
close(devfd);
return r;
}
int device_size(const char *device, uint64_t *size)
{
int devfd, r = 0;
devfd = open(device, O_RDONLY);
if(devfd == -1)
return -EINVAL;
if (ioctl(devfd, BLKGETSIZE64, size) < 0)
r = -EINVAL;
close(devfd);
return r;
}
static int get_device_infos(const char *device, enum devcheck device_check,
int *readonly, uint64_t *size)
{
struct stat st;
unsigned long size_small;
int fd, r = -1;
int flags = 0;
*readonly = 0;
*size = 0;
if (stat(device, &st) < 0)
return -EINVAL;
/* never wipe header on mounted device */
if (device_check == DEV_EXCL && S_ISBLK(st.st_mode))
flags |= O_EXCL;
/* Try to open read-write to check whether it is a read-only device */
fd = open(device, O_RDWR | flags);
if (fd == -1 && errno == EROFS) {
*readonly = 1;
fd = open(device, O_RDONLY | flags);
}
if (fd == -1 && device_check == DEV_EXCL && errno == EBUSY)
return -EBUSY;
if (fd == -1)
return -EINVAL;
/* If the device can be opened read-write, i.e. readonly is still 0, then
* check whether BKROGET says that it is read-only. E.g. read-only loop
* devices may be openend read-write but are read-only according to BLKROGET
*/
if (*readonly == 0 && (r = ioctl(fd, BLKROGET, readonly)) < 0)
goto out;
if (ioctl(fd, BLKGETSIZE64, size) >= 0) {
*size >>= SECTOR_SHIFT;
r = 0;
goto out;
}
if (ioctl(fd, BLKGETSIZE, &size_small) >= 0) {
*size = (uint64_t)size_small;
r = 0;
goto out;
}
r = -EINVAL;
out:
close(fd);
return r;
}
int device_check_and_adjust(struct crypt_device *cd,
const char *device,
enum devcheck device_check,
uint64_t *size,
uint64_t *offset,
uint32_t *flags)
{
int r, real_readonly;
uint64_t real_size;
if (!device)
return -ENOTBLK;
r = get_device_infos(device, device_check, &real_readonly, &real_size);
if (r < 0) {
if (r == -EBUSY)
log_err(cd, _("Cannot use device %s which is in use "
"(already mapped or mounted).\n"),
device);
else
log_err(cd, _("Cannot get info about device %s.\n"),
device);
return r;
}
if (*offset >= real_size) {
log_err(cd, _("Requested offset is beyond real size of device %s.\n"),
device);
return -EINVAL;
}
if (!*size) {
*size = real_size;
if (!*size) {
log_err(cd, _("Device %s has zero size.\n"), device);
return -ENOTBLK;
}
*size -= *offset;
}
/* in case of size is set by parameter */
if ((real_size - *offset) < *size) {
log_dbg("Device %s: offset = %" PRIu64 " requested size = %" PRIu64
", backing device size = %" PRIu64,
device, *offset, *size, real_size);
log_err(cd, _("Device %s is too small.\n"), device);
return -EINVAL;
}
if (real_readonly)
*flags |= CRYPT_ACTIVATE_READONLY;
log_dbg("Calculated device size is %" PRIu64 " sectors (%s), offset %" PRIu64 ".",
*size, real_readonly ? "RO" : "RW", *offset);
return 0;
}
/* MEMLOCK */
#define DEFAULT_PROCESS_PRIORITY -18
@@ -436,7 +229,7 @@ int crypt_memlock_inc(struct crypt_device *ctx)
if (!_memlock_count++) {
log_dbg("Locking memory.");
if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
log_err(ctx, _("WARNING!!! Possibly insecure memory. Are you root?\n"));
log_dbg("Cannot lock memory with mlockall.");
_memlock_count--;
return 0;
}
@@ -462,60 +255,3 @@ int crypt_memlock_dec(struct crypt_device *ctx)
}
return _memlock_count ? 1 : 0;
}
/* DEVICE TOPOLOGY */
/* block device topology ioctls, introduced in 2.6.32 */
#ifndef BLKIOMIN
#define BLKIOMIN _IO(0x12,120)
#define BLKIOOPT _IO(0x12,121)
#define BLKALIGNOFF _IO(0x12,122)
#endif
void get_topology_alignment(const char *device,
unsigned long *required_alignment, /* bytes */
unsigned long *alignment_offset, /* bytes */
unsigned long default_alignment)
{
int dev_alignment_offset = 0;
unsigned int min_io_size = 0, opt_io_size = 0;
unsigned long temp_alignment = 0;
int fd;
*required_alignment = default_alignment;
*alignment_offset = 0;
fd = open(device, O_RDONLY);
if (fd == -1)
return;
/* minimum io size */
if (ioctl(fd, BLKIOMIN, &min_io_size) == -1) {
log_dbg("Topology info for %s not supported, using default offset %lu bytes.",
device, default_alignment);
goto out;
}
/* optimal io size */
if (ioctl(fd, BLKIOOPT, &opt_io_size) == -1)
opt_io_size = min_io_size;
/* alignment offset, bogus -1 means misaligned/unknown */
if (ioctl(fd, BLKALIGNOFF, &dev_alignment_offset) == -1 || dev_alignment_offset < 0)
dev_alignment_offset = 0;
*alignment_offset = (unsigned long)dev_alignment_offset;
temp_alignment = (unsigned long)min_io_size;
if (temp_alignment < (unsigned long)opt_io_size)
temp_alignment = (unsigned long)opt_io_size;
/* If calculated alignment is multiple of default, keep default */
if (temp_alignment && (default_alignment % temp_alignment))
*required_alignment = temp_alignment;
log_dbg("Topology: IO (%u/%u), offset = %lu; Required alignment is %lu bytes.",
min_io_size, opt_io_size, *alignment_offset, *required_alignment);
out:
(void)close(fd);
}

View File

@@ -23,6 +23,8 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -90,7 +92,9 @@ void *crypt_safe_alloc(size_t size)
return NULL;
alloc->size = size;
memset(&alloc->data, 0, size);
/* coverity[leaked_storage] */
return &alloc->data;
}
@@ -259,6 +263,49 @@ out_err:
return r;
}
/*
* A simple call to lseek(3) might not be possible for some inputs (e.g.
* reading from a pipe), so this function instead reads of up to BUFSIZ bytes
* at a time until the specified number of bytes. It returns -1 on read error
* or when it reaches EOF before the requested number of bytes have been
* discarded.
*/
static int keyfile_seek(int fd, size_t bytes)
{
char tmp[BUFSIZ];
size_t next_read;
ssize_t bytes_r;
off_t r;
r = lseek(fd, bytes, SEEK_CUR);
if (r > 0)
return 0;
if (r < 0 && errno != ESPIPE)
return -1;
while (bytes > 0) {
/* figure out how much to read */
next_read = bytes > sizeof(tmp) ? sizeof(tmp) : bytes;
bytes_r = read(fd, tmp, next_read);
if (bytes_r < 0) {
if (errno == EINTR)
continue;
/* read error */
return -1;
}
if (bytes_r == 0)
/* EOF */
break;
bytes -= bytes_r;
}
return bytes == 0 ? 0 : -1;
}
/*
* Note: --key-file=- is interpreted as a read from a binary file (stdin)
* key_size_max == 0 means detect maximum according to input type (tty/file)
@@ -272,7 +319,7 @@ int crypt_get_key(const char *prompt,
{
int fd, regular_file, read_stdin, char_read, unlimited_read = 0;
int r = -EINVAL;
char *pass = NULL, tmp;
char *pass = NULL;
size_t buflen, i, file_read_size;
struct stat st;
@@ -340,11 +387,10 @@ int crypt_get_key(const char *prompt,
}
/* Discard keyfile_offset bytes on input */
for(i = 0; i < keyfile_offset; i++)
if (read(fd, &tmp, 1) != 1) {
log_err(cd, _("Cannot seek to requested keyfile offset.\n"));
goto out_err;
}
if (keyfile_offset && keyfile_seek(fd, keyfile_offset) < 0) {
log_err(cd, _("Cannot seek to requested keyfile offset.\n"));
goto out_err;
}
for(i = 0; i < keyfile_size_max; i++) {
if(i == buflen) {
@@ -397,3 +443,94 @@ out_err:
crypt_safe_free(pass);
return r;
}
ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc)
{
char buf[3] = "xx\0", *endp, *bytes;
size_t i, len;
len = strlen(hex);
if (len % 2)
return -EINVAL;
len /= 2;
bytes = safe_alloc ? crypt_safe_alloc(len) : malloc(len);
if (!bytes)
return -ENOMEM;
for (i = 0; i < len; i++) {
memcpy(buf, &hex[i * 2], 2);
bytes[i] = strtoul(buf, &endp, 16);
if (endp != &buf[2]) {
safe_alloc ? crypt_safe_free(bytes) : free(bytes);
return -EINVAL;
}
}
*result = bytes;
return i;
}
/*
* Device size string parsing, suffixes:
* s|S - 512 bytes sectors
* k |K |m |M |g |G |t |T - 1024 base
* kiB|KiB|miB|MiB|giB|GiB|tiB|TiB - 1024 base
* kb |KB |mM |MB |gB |GB |tB |TB - 1000 base
*/
int crypt_string_to_size(struct crypt_device *cd, const char *s, uint64_t *size)
{
char *endp = NULL;
size_t len;
uint64_t mult_base, mult, tmp;
*size = strtoull(s, &endp, 10);
if (!isdigit(s[0]) ||
(errno == ERANGE && *size == ULLONG_MAX) ||
(errno != 0 && *size == 0))
return -EINVAL;
if (!endp || !*endp)
return 0;
len = strlen(endp);
/* Allow "B" and "iB" suffixes */
if (len > 3 ||
(len == 3 && (endp[1] != 'i' || endp[2] != 'B')) ||
(len == 2 && endp[1] != 'B'))
return -EINVAL;
if (len == 1 || len == 3)
mult_base = 1024;
else
mult_base = 1000;
mult = 1;
switch (endp[0]) {
case 's':
case 'S': mult = 512;
break;
case 't':
case 'T': mult *= mult_base;
/* Fall through */
case 'g':
case 'G': mult *= mult_base;
/* Fall through */
case 'm':
case 'M': mult *= mult_base;
/* Fall through */
case 'k':
case 'K': mult *= mult_base;
break;
default:
return -EINVAL;
}
tmp = *size * mult;
if ((tmp / *size) != mult) {
log_dbg("Device size overflow.");
return -EINVAL;
}
*size = tmp;
return 0;
}

View File

@@ -43,4 +43,7 @@ void *crypt_safe_alloc(size_t size);
void crypt_safe_free(void *data);
void *crypt_safe_realloc(void *data, size_t size);
ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc);
int crypt_string_to_size(struct crypt_device *cd, const char *s, uint64_t *size);
#endif /* _UTILS_CRYPT_H */

View File

@@ -1,146 +0,0 @@
/*
* Temporary debug code to find processes locking internal cryptsetup devices.
* This code is intended to run only in debug mode.
*
* inspired by psmisc/fuser proc scanning code
*
* Copyright (C) 2009-2012, 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
* version 2 as published by the Free Software Foundation.
*
* 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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "libcryptsetup.h"
#include "internal.h"
#define MAX_PATHNAME 1024
#define MAX_SHORTNAME 64
static int numeric_name(const char *name)
{
return (name[0] < '0' || name[0] > '9') ? 0 : 1;
}
static int check_pid(const pid_t pid, const char *dev_name, const char *short_dev_name)
{
char dirpath[MAX_SHORTNAME], fdpath[MAX_SHORTNAME], linkpath[MAX_PATHNAME];
DIR *dirp;
struct dirent *direntry;
ssize_t len;
int r = 0;
snprintf(dirpath, sizeof(dirpath), "/proc/%d/fd", pid);
if (!(dirp = opendir(dirpath)))
return r;
while ((direntry = readdir(dirp))) {
if (!numeric_name(direntry->d_name))
continue;
snprintf(fdpath, sizeof(fdpath), "/proc/%d/fd/%s", pid, direntry->d_name);
if ((len = readlink(fdpath, linkpath, MAX_PATHNAME-1)) < 0)
break;
linkpath[len] = '\0';
if (!strcmp(dev_name, linkpath)) {
r = 1;
break;
}
if (!strcmp(short_dev_name, linkpath)) {
r = 2;
break;
}
}
closedir(dirp);
return r;
}
static int read_proc_info(const pid_t pid, pid_t *ppid, char *name, int max_size)
{
char path[MAX_SHORTNAME], info[max_size], c;
int fd, xpid, r = 0;
snprintf(path, sizeof(path), "/proc/%u/stat", pid);
if ((fd = open(path, O_RDONLY)) < 0)
return 0;
if (read(fd, info, max_size) > 0 &&
sscanf(info, "%d %s %c %d", &xpid, name, &c, ppid) == 4)
r = 1;
if (!r) {
*ppid = 0;
name[0] = '\0';
}
close(fd);
return r;
}
static void report_proc(const pid_t pid, const char *dev_name)
{
char name[MAX_PATHNAME], name2[MAX_PATHNAME];
pid_t ppid, ppid2;
if (read_proc_info(pid, &ppid, name, MAX_PATHNAME) &&
read_proc_info(ppid, &ppid2, name2, MAX_PATHNAME))
log_dbg("WARNING: Process PID %u %s [PPID %u %s] spying on internal device %s.",
pid, name, ppid, name2, dev_name);
}
void debug_processes_using_device(const char *dm_name)
{
char short_dev_name[MAX_SHORTNAME], dev_name[MAX_PATHNAME];
DIR *proc_dir;
struct dirent *proc_dentry;
struct stat st;
pid_t pid;
if (crypt_get_debug_level() != CRYPT_LOG_DEBUG)
return;
snprintf(dev_name, sizeof(dev_name), "/dev/mapper/%s", dm_name);
if (stat(dev_name, &st) || !S_ISBLK(st.st_mode))
return;
snprintf(short_dev_name, sizeof(short_dev_name), "/dev/dm-%u", minor(st.st_rdev));
if (!(proc_dir = opendir("/proc")))
return;
while ((proc_dentry = readdir(proc_dir))) {
if (!numeric_name(proc_dentry->d_name))
continue;
pid = atoi(proc_dentry->d_name);
switch(check_pid(pid, dev_name, short_dev_name)) {
case 1: report_proc(pid, dev_name);
break;
case 2: report_proc(pid, short_dev_name);
default:
break;
}
}
closedir(proc_dir);
}

429
lib/utils_device.c Normal file
View File

@@ -0,0 +1,429 @@
/*
* device backend utilities
*
* Copyright (C) 2004, Christophe Saout <christophe@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2012, 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
* version 2 as published by the Free Software Foundation.
*
* 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 <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <unistd.h>
#include "internal.h"
struct device {
char *path;
char *file_path;
int loop_fd;
int init_done:1;
};
static int device_ready(const char *device)
{
int devfd, r = 0;
struct stat st;
if(stat(device, &st) < 0) {
log_err(NULL, _("Device %s doesn't exist or access denied.\n"), device);
return -EINVAL;
}
if (!S_ISBLK(st.st_mode))
return S_ISREG(st.st_mode) ? -ENOTBLK : -EINVAL;
log_dbg("Trying to open and read device %s.", device);
devfd = open(device, O_RDONLY | O_DIRECT | O_SYNC);
if(devfd < 0) {
log_err(NULL, _("Cannot open device %s.\n"), device);
return -EINVAL;
}
close(devfd);
return r;
}
int device_alloc(struct device **device, const char *path)
{
struct device *dev;
int r;
if (!path) {
*device = NULL;
return 0;
}
dev = malloc(sizeof(struct device));
if (!dev)
return -ENOMEM;
memset(dev, 0, sizeof(struct device));
dev->loop_fd = -1;
r = device_ready(path);
if (!r) {
dev->init_done = 1;
} else if (r == -ENOTBLK) {
/* alloc loop later */
} else if (r < 0) {
free(dev);
return -ENOTBLK;
}
dev->path = strdup(path);
if (!dev->path) {
free(dev);
return -ENOMEM;
}
*device = dev;
return 0;
}
void device_free(struct device *device)
{
if (!device)
return;
if (device->loop_fd != -1) {
log_dbg("Closed loop %s (%s).", device->path, device->file_path);
close(device->loop_fd);
}
free(device->file_path);
free(device->path);
free(device);
}
/* Get block device path */
const char *device_block_path(const struct device *device)
{
if (!device || !device->init_done)
return NULL;
return device->path;
}
/* Get path to device / file */
const char *device_path(const struct device *device)
{
if (!device)
return NULL;
if (device->file_path)
return device->file_path;
return device->path;
}
/* block device topology ioctls, introduced in 2.6.32 */
#ifndef BLKIOMIN
#define BLKIOMIN _IO(0x12,120)
#define BLKIOOPT _IO(0x12,121)
#define BLKALIGNOFF _IO(0x12,122)
#endif
void device_topology_alignment(struct device *device,
unsigned long *required_alignment, /* bytes */
unsigned long *alignment_offset, /* bytes */
unsigned long default_alignment)
{
int dev_alignment_offset = 0;
unsigned int min_io_size = 0, opt_io_size = 0;
unsigned long temp_alignment = 0;
int fd;
*required_alignment = default_alignment;
*alignment_offset = 0;
if (!device || !device->path) //FIXME
return;
fd = open(device->path, O_RDONLY);
if (fd == -1)
return;
/* minimum io size */
if (ioctl(fd, BLKIOMIN, &min_io_size) == -1) {
log_dbg("Topology info for %s not supported, using default offset %lu bytes.",
device->path, default_alignment);
goto out;
}
/* optimal io size */
if (ioctl(fd, BLKIOOPT, &opt_io_size) == -1)
opt_io_size = min_io_size;
/* alignment offset, bogus -1 means misaligned/unknown */
if (ioctl(fd, BLKALIGNOFF, &dev_alignment_offset) == -1 || dev_alignment_offset < 0)
dev_alignment_offset = 0;
*alignment_offset = (unsigned long)dev_alignment_offset;
temp_alignment = (unsigned long)min_io_size;
if (temp_alignment < (unsigned long)opt_io_size)
temp_alignment = (unsigned long)opt_io_size;
/* If calculated alignment is multiple of default, keep default */
if (temp_alignment && (default_alignment % temp_alignment))
*required_alignment = temp_alignment;
log_dbg("Topology: IO (%u/%u), offset = %lu; Required alignment is %lu bytes.",
min_io_size, opt_io_size, *alignment_offset, *required_alignment);
out:
(void)close(fd);
}
int device_block_size(struct device *device)
{
struct stat st;
int fd, bsize = 0, r = -EINVAL;
if (!device)
return 0;
fd = open(device->path, O_RDONLY);
if(fd < 0)
return -EINVAL;
if (fstat(fd, &st) < 0)
goto out;
if (S_ISREG(st.st_mode)) {
r = (int)crypt_getpagesize();
goto out;
}
if (ioctl(fd, BLKSSZGET, &bsize) >= 0)
r = bsize;
out:
close(fd);
return r;
}
int device_read_ahead(struct device *device, uint32_t *read_ahead)
{
int fd, r = 0;
long read_ahead_long;
if (!device)
return 0;
if ((fd = open(device->path, O_RDONLY)) < 0)
return 0;
r = ioctl(fd, BLKRAGET, &read_ahead_long) ? 0 : 1;
close(fd);
if (r)
*read_ahead = (uint32_t) read_ahead_long;
return r;
}
/* Get data size in bytes */
int device_size(struct device *device, uint64_t *size)
{
struct stat st;
int devfd, r = -EINVAL;
devfd = open(device->path, O_RDONLY);
if(devfd == -1)
return -EINVAL;
if (fstat(devfd, &st) < 0)
goto out;
if (S_ISREG(st.st_mode)) {
*size = (uint64_t)st.st_size;
r = 0;
} else if (ioctl(devfd, BLKGETSIZE64, size) >= 0)
r = 0;
out:
close(devfd);
return r;
}
static int device_info(struct device *device,
enum devcheck device_check,
int *readonly, uint64_t *size)
{
struct stat st;
int fd, r = -EINVAL, flags = 0;
*readonly = 0;
*size = 0;
if (stat(device->path, &st) < 0)
return -EINVAL;
/* never wipe header on mounted device */
if (device_check == DEV_EXCL && S_ISBLK(st.st_mode))
flags |= O_EXCL;
/* Try to open read-write to check whether it is a read-only device */
fd = open(device->path, O_RDWR | flags);
if (fd == -1 && errno == EROFS) {
*readonly = 1;
fd = open(device->path, O_RDONLY | flags);
}
if (fd == -1 && device_check == DEV_EXCL && errno == EBUSY)
return -EBUSY;
if (fd == -1)
return -EINVAL;
if (S_ISREG(st.st_mode)) {
//FIXME: add readonly check
*size = (uint64_t)st.st_size;
*size >>= SECTOR_SHIFT;
} else {
/* If the device can be opened read-write, i.e. readonly is still 0, then
* check whether BKROGET says that it is read-only. E.g. read-only loop
* devices may be openend read-write but are read-only according to BLKROGET
*/
if (*readonly == 0 && (r = ioctl(fd, BLKROGET, readonly)) < 0)
goto out;
if (ioctl(fd, BLKGETSIZE64, size) >= 0) {
*size >>= SECTOR_SHIFT;
r = 0;
goto out;
}
}
r = -EINVAL;
out:
close(fd);
return r;
}
static int device_internal_prepare(struct crypt_device *cd, struct device *device)
{
char *loop_device;
int r, loop_fd, readonly = 0;
if (device->init_done)
return 0;
log_dbg("Allocating a free loop device.");
loop_device = crypt_loop_get_device();
if (!loop_device) {
if (getuid() || geteuid())
log_err(cd, _("Cannot use a loopback device, "
"running as non-root user.\n"));
else
log_err(cd, _("Cannot find a free loopback device.\n"));
return -ENOTSUP;
}
/* Keep the loop open, dettached on last close. */
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"));
free(loop_device);
return -EINVAL;
}
r = device_ready(loop_device);
if (r < 0) {
free(loop_device);
return r;
}
device->loop_fd = loop_fd;
device->file_path = device->path;
device->path = loop_device;
device->init_done = 1;
return 0;
}
int device_block_adjust(struct crypt_device *cd,
struct device *device,
enum devcheck device_check,
uint64_t device_offset,
uint64_t *size,
uint32_t *flags)
{
int r, real_readonly;
uint64_t real_size;
if (!device)
return -ENOTBLK;
r = device_internal_prepare(cd, device);
if (r)
return r;
r = device_info(device, device_check, &real_readonly, &real_size);
if (r < 0) {
if (r == -EBUSY)
log_err(cd, _("Cannot use device %s which is in use "
"(already mapped or mounted).\n"),
device->path);
else
log_err(cd, _("Cannot get info about device %s.\n"),
device->path);
return r;
}
if (device_offset >= real_size) {
log_err(cd, _("Requested offset is beyond real size of device %s.\n"),
device->path);
return -EINVAL;
}
if (size && !*size) {
*size = real_size;
if (!*size) {
log_err(cd, _("Device %s has zero size.\n"), device->path);
return -ENOTBLK;
}
*size -= device_offset;
}
/* in case of size is set by parameter */
if (size && ((real_size - device_offset) < *size)) {
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);
return -EINVAL;
}
if (flags && real_readonly)
*flags |= CRYPT_ACTIVATE_READONLY;
if (size)
log_dbg("Calculated device size is %" PRIu64" sectors (%s), offset %" PRIu64 ".",
*size, real_readonly ? "RO" : "RW", device_offset);
return 0;
}
size_t size_round_up(size_t size, unsigned int block)
{
size_t s = (size + (block - 1)) / block;
return s * block;
}

View File

@@ -30,8 +30,12 @@
#include <sys/types.h>
#include "utils_dm.h"
/* These are DM helpers used only by this file */
int dm_is_dm_device(int major, int minor);
int dm_is_dm_kernel_name(const char *name);
char *dm_device_path(const char *prefix, int major, int minor);
char *crypt_lookup_dev(const char *dev_id);
int crypt_sysfs_check_crypt_segment(const char *device, uint64_t offset, uint64_t size);
int crypt_sysfs_get_rotational(int major, int minor, int *rotational);
static char *__lookup_dev(char *path, dev_t dev, int dir_level, const int max_level)
@@ -135,7 +139,7 @@ char *crypt_lookup_dev(const char *dev_id)
if (snprintf(path, sizeof(path), "/sys/dev/block/%s", dev_id) < 0)
return NULL;
len = readlink(path, link, sizeof(link));
len = readlink(path, link, sizeof(link) - 1);
if (len < 0) {
/* Without /sys use old scan */
if (stat("/sys/dev/block", &st) < 0)
@@ -168,82 +172,6 @@ char *crypt_lookup_dev(const char *dev_id)
return devpath;
}
static int crypt_sysfs_get_major_minor(const char *kname, int *major, int *minor)
{
char path[PATH_MAX], tmp[64] = {0};
int fd, r = 0;
if (snprintf(path, sizeof(path), "/sys/block/%s/dev", kname) < 0)
return 0;
if ((fd = open(path, O_RDONLY)) < 0)
return 0;
r = read(fd, tmp, sizeof(tmp));
close(fd);
if (r <= 0)
return 0;
tmp[63] = '\0';
if (sscanf(tmp, "%d:%d", major, minor) != 2)
return 0;
return 1;
}
static int crypt_sysfs_get_holders_dir(const char *device, char *path, int size)
{
struct stat st;
if (stat(device, &st) < 0 || !S_ISBLK(st.st_mode))
return 0;
if (snprintf(path, size, "/sys/dev/block/%d:%d/holders",
major(st.st_rdev), minor(st.st_rdev)) < 0)
return 0;
return 1;
}
int crypt_sysfs_check_crypt_segment(const char *device, uint64_t offset, uint64_t size)
{
DIR *dir;
struct dirent *d;
char path[PATH_MAX], *dmname;
int major, minor, r = 0;
if (!crypt_sysfs_get_holders_dir(device, path, sizeof(path)))
return -EINVAL;
if (!(dir = opendir(path)))
return -EINVAL;
while (!r && (d = readdir(dir))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (!dm_is_dm_kernel_name(d->d_name)) {
r = -EBUSY;
break;
}
if (!crypt_sysfs_get_major_minor(d->d_name, &major, &minor)) {
r = -EINVAL;
break;
}
if (!(dmname = dm_device_path(NULL, major, minor))) {
r = -EINVAL;
break;
}
r = dm_check_segment(dmname, offset, size);
free(dmname);
}
closedir(dir);
return r;
}
int crypt_sysfs_get_rotational(int major, int minor, int *rotational)
{
char path[PATH_MAX], tmp[64] = {0};

View File

@@ -27,6 +27,8 @@
struct crypt_device;
struct volume_key;
struct crypt_params_verity;
struct device;
/* Device mapper backend - kernel support flags */
#define DM_KEY_WIPE_SUPPORTED (1 << 0) /* key wipe message */
@@ -34,48 +36,66 @@ struct volume_key;
#define DM_SECURE_SUPPORTED (1 << 2) /* wipe (secure) buffer flag */
#define DM_PLAIN64_SUPPORTED (1 << 3) /* plain64 IV */
#define DM_DISCARDS_SUPPORTED (1 << 4) /* discards/TRIM option is supported */
#define DM_VERITY_SUPPORTED (1 << 5) /* dm-verity target supported */
uint32_t dm_flags(void);
#define DM_ACTIVE_DEVICE (1 << 0)
#define DM_ACTIVE_CIPHER (1 << 1)
#define DM_ACTIVE_UUID (1 << 2)
#define DM_ACTIVE_KEYSIZE (1 << 3)
#define DM_ACTIVE_KEY (1 << 4)
#define DM_ACTIVE_UUID (1 << 1)
#define DM_ACTIVE_CRYPT_CIPHER (1 << 2)
#define DM_ACTIVE_CRYPT_KEYSIZE (1 << 3)
#define DM_ACTIVE_CRYPT_KEY (1 << 4)
#define DM_ACTIVE_VERITY_ROOT_HASH (1 << 5)
#define DM_ACTIVE_VERITY_HASH_DEVICE (1 << 6)
#define DM_ACTIVE_VERITY_PARAMS (1 << 7)
struct crypt_dm_active_device {
const char *device;
const char *cipher;
const char *uuid;
/* Active key for device */
struct volume_key *vk;
/* struct crypt_active_device */
uint64_t offset; /* offset in sectors */
uint64_t iv_offset; /* IV initilisation sector */
enum { DM_CRYPT = 0, DM_VERITY } target;
uint64_t size; /* active device size */
uint32_t flags; /* activation flags */
const char *uuid;
struct device *data_device;
union {
struct {
const char *cipher;
/* Active key for device */
struct volume_key *vk;
/* struct crypt_active_device */
uint64_t offset; /* offset in sectors */
uint64_t iv_offset; /* IV initilisation sector */
} crypt;
struct {
struct device *hash_device;
const char *root_hash;
uint32_t root_hash_size;
uint64_t hash_offset; /* hash offset in blocks (not header) */
struct crypt_params_verity *vp;
} verity;
} u;
};
void dm_backend_init(void);
void dm_backend_exit(void);
int dm_remove_device(struct crypt_device *cd, const char *name,
int force, uint64_t size);
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_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_and_wipe_key(struct crypt_device *cd, const char *name);
int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
size_t key_size, const char *key);
const char *dm_get_dir(void);
int dm_init(struct crypt_device *context, int check_kernel);
void dm_exit(void);
int dm_remove_device(const char *name, int force, uint64_t size);
int dm_status_device(const char *name);
int dm_status_suspended(const char *name);
int dm_query_device(const char *name, uint32_t get_flags,
struct crypt_dm_active_device *dmd);
int dm_create_device(const char *name,
const char *type,
struct crypt_dm_active_device *dmd,
int reload);
int dm_suspend_and_wipe_key(const char *name);
int dm_resume_and_reinstate_key(const char *name,
size_t key_size,
const char *key);
char *dm_device_path(const char *prefix, int major, int minor);
int dm_is_dm_device(int major, int minor);
int dm_is_dm_kernel_name(const char *name);
int dm_check_segment(const char *name, uint64_t offset, uint64_t size);
#endif /* _UTILS_DM_H */

View File

@@ -52,7 +52,7 @@ static void crypt_fips_verify(struct crypt_device *cd,
void crypt_fips_libcryptsetup_check(struct crypt_device *cd)
{
crypt_fips_verify(cd, "libcryptsetup.so", "crypt_init");
crypt_fips_verify(cd, LIBCRYPTSETUP_VERSION_FIPS, "crypt_init");
}
void crypt_fips_self_check(struct crypt_device *cd)

View File

@@ -34,18 +34,20 @@
#define MAXIMUM_WIPE_BYTES 1024 * 1024 * 32 /* 32 MiB */
static ssize_t _crypt_wipe_zero(int fd, char *buffer, uint64_t offset, uint64_t size)
static ssize_t _crypt_wipe_zero(int fd, int bsize, char *buffer,
uint64_t offset, uint64_t size)
{
memset(buffer, 0, size);
return write_lseek_blockwise(fd, buffer, size, offset);
return write_lseek_blockwise(fd, bsize, buffer, size, offset);
}
static ssize_t _crypt_wipe_random(int fd, char *buffer, uint64_t offset, uint64_t size)
static ssize_t _crypt_wipe_random(int fd, int bsize, char *buffer,
uint64_t offset, uint64_t size)
{
if (crypt_random_get(NULL, buffer, size, CRYPT_RND_NORMAL) < 0)
return -EINVAL;
return write_lseek_blockwise(fd, buffer, size, offset);
return write_lseek_blockwise(fd, bsize, buffer, size, offset);
}
/*
@@ -74,7 +76,8 @@ static void wipeSpecial(char *buffer, size_t buffer_size, unsigned int turn)
}
}
static ssize_t _crypt_wipe_disk(int fd, char *buffer, uint64_t offset, uint64_t size)
static ssize_t _crypt_wipe_disk(int fd, int bsize, char *buffer,
uint64_t offset, uint64_t size)
{
int r;
unsigned int i;
@@ -95,22 +98,23 @@ static ssize_t _crypt_wipe_disk(int fd, char *buffer, uint64_t offset, uint64_t
if (r < 0)
return r;
written = write_lseek_blockwise(fd, buffer, size, offset);
written = write_lseek_blockwise(fd, bsize, buffer, size, offset);
if (written < 0 || written != (ssize_t)size)
return written;
}
/* Rewrite it finally with random */
return _crypt_wipe_random(fd, buffer, offset, size);
return _crypt_wipe_random(fd, bsize, buffer, offset, size);
}
static ssize_t _crypt_wipe_ssd(int fd, char *buffer, uint64_t offset, uint64_t size)
static ssize_t _crypt_wipe_ssd(int fd, int bsize, char *buffer,
uint64_t offset, uint64_t size)
{
// FIXME: for now just rewrite it by random
return _crypt_wipe_random(fd, buffer, offset, size);
return _crypt_wipe_random(fd, bsize, buffer, offset, size);
}
int crypt_wipe(const char *device,
int crypt_wipe(struct device *device,
uint64_t offset,
uint64_t size,
crypt_wipe_type type,
@@ -118,21 +122,22 @@ int crypt_wipe(const char *device,
{
struct stat st;
char *buffer;
int devfd, flags, rotational;
int devfd, flags, rotational, bsize;
ssize_t written;
if (!size || size % SECTOR_SIZE || (size > MAXIMUM_WIPE_BYTES)) {
log_dbg("Unsuported wipe size for device %s: %ld.",
device, (unsigned long)size);
device_path(device), (unsigned long)size);
return -EINVAL;
}
if (stat(device, &st) < 0) {
log_dbg("Device %s not found.", device);
if (stat(device_path(device), &st) < 0) {
log_dbg("Device %s not found.", device_path(device));
return -EINVAL;
}
if (type == CRYPT_WIPE_DISK) {
if (type == CRYPT_WIPE_DISK && S_ISBLK(st.st_mode)) {
rotational = 0;
if (!crypt_sysfs_get_rotational(major(st.st_rdev),
minor(st.st_rdev),
&rotational))
@@ -142,6 +147,10 @@ int crypt_wipe(const char *device,
type = CRYPT_WIPE_SSD;
}
bsize = device_block_size(device);
if (bsize <= 0)
return -EINVAL;
buffer = malloc(size);
if (!buffer)
return -ENOMEM;
@@ -152,25 +161,25 @@ int crypt_wipe(const char *device,
if (exclusive && S_ISBLK(st.st_mode))
flags |= O_EXCL;
devfd = open(device, flags);
devfd = open(device_path(device), flags);
if (devfd == -1) {
free(buffer);
return errno == EBUSY ? -EBUSY : -EINVAL;
return errno ? -errno : -EINVAL;
}
// FIXME: use fixed block size and loop here
switch (type) {
case CRYPT_WIPE_ZERO:
written = _crypt_wipe_zero(devfd, buffer, offset, size);
written = _crypt_wipe_zero(devfd, bsize, buffer, offset, size);
break;
case CRYPT_WIPE_DISK:
written = _crypt_wipe_disk(devfd, buffer, offset, size);
written = _crypt_wipe_disk(devfd, bsize, buffer, offset, size);
break;
case CRYPT_WIPE_SSD:
written = _crypt_wipe_ssd(devfd, buffer, offset, size);
written = _crypt_wipe_ssd(devfd, bsize, buffer, offset, size);
break;
case CRYPT_WIPE_RANDOM:
written = _crypt_wipe_random(devfd, buffer, offset, size);
written = _crypt_wipe_random(devfd, bsize, buffer, offset, size);
break;
default:
log_dbg("Unsuported wipe type requested: (%d)", type);

16
lib/verity/Makefile.am Normal file
View File

@@ -0,0 +1,16 @@
moduledir = $(libdir)/cryptsetup
noinst_LTLIBRARIES = libverity.la
libverity_la_CFLAGS = -Wall @CRYPTO_CFLAGS@
libverity_la_SOURCES = \
verity_hash.c \
verity.c \
verity.h
INCLUDES = -D_GNU_SOURCE \
-D_LARGEFILE64_SOURCE \
-D_FILE_OFFSET_BITS=64 \
-I$(top_srcdir)/lib \
-I$(top_srcdir)/lib/crypto_backend

283
lib/verity/verity.c Normal file
View File

@@ -0,0 +1,283 @@
/*
* dm-verity volume handling
*
* Copyright (C) 2012, 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
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <uuid/uuid.h>
#include "libcryptsetup.h"
#include "verity.h"
#include "internal.h"
#define VERITY_SIGNATURE "verity\0\0"
/* http://code.google.com/p/cryptsetup/wiki/DMVerity#Verity_superblock_format */
struct verity_sb {
uint8_t signature[8]; /* "verity\0\0" */
uint32_t version; /* superblock version */
uint32_t hash_type; /* 0 - Chrome OS, 1 - normal */
uint8_t uuid[16]; /* UUID of hash device */
uint8_t algorithm[32];/* hash algorithm name */
uint32_t data_block_size; /* data block in bytes */
uint32_t hash_block_size; /* hash block in bytes */
uint64_t data_blocks; /* number of data blocks */
uint16_t salt_size; /* salt size */
uint8_t _pad1[6];
uint8_t salt[256]; /* salt */
uint8_t _pad2[168];
} __attribute__((packed));
/* Read verity superblock from disk */
int VERITY_read_sb(struct crypt_device *cd,
uint64_t sb_offset,
char **uuid_string,
struct crypt_params_verity *params)
{
const char *device = device_path(crypt_metadata_device(cd));
int bsize = device_block_size(crypt_metadata_device(cd));
struct verity_sb sb = {};
ssize_t hdr_size = sizeof(struct verity_sb);
int devfd = 0, sb_version;
log_dbg("Reading VERITY header of size %u on device %s, offset %" PRIu64 ".",
sizeof(struct verity_sb), device, sb_offset);
if (params->flags & CRYPT_VERITY_NO_HEADER) {
log_err(cd, _("Verity device doesn't use on-disk header.\n"), device);
return -EINVAL;
}
if (sb_offset % 512) {
log_err(cd, _("Unsupported VERITY hash offset.\n"));
return -EINVAL;
}
devfd = open(device ,O_RDONLY | O_DIRECT);
if(devfd == -1) {
log_err(cd, _("Cannot open device %s.\n"), device);
return -EINVAL;
}
if(lseek(devfd, sb_offset, SEEK_SET) < 0 ||
read_blockwise(devfd, bsize, &sb, hdr_size) < 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"), device);
return -EINVAL;
}
sb_version = le32_to_cpu(sb.version);
if (sb_version != 1) {
log_err(cd, _("Unsupported VERITY version %d.\n"), 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);
return -EINVAL;
}
params->data_block_size = le32_to_cpu(sb.data_block_size);
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"));
return -EINVAL;
}
params->data_size = le64_to_cpu(sb.data_blocks);
params->hash_name = strndup((const char*)sb.algorithm, sizeof(sb.algorithm));
if (!params->hash_name)
return -ENOMEM;
if (crypt_hash_size(params->hash_name) <= 0) {
log_err(cd, _("Hash algorithm %s not supported.\n"),
params->hash_name);
free(CONST_CAST(char*)params->hash_name);
return -EINVAL;
}
params->salt_size = le16_to_cpu(sb.salt_size);
if (params->salt_size > sizeof(sb.salt)) {
log_err(cd, _("VERITY header corrupted.\n"));
free(CONST_CAST(char*)params->hash_name);
return -EINVAL;
}
params->salt = malloc(params->salt_size);
if (!params->salt) {
free(CONST_CAST(char*)params->hash_name);
return -ENOMEM;
}
memcpy(CONST_CAST(char*)params->salt, sb.salt, params->salt_size);
if ((*uuid_string = malloc(40)))
uuid_unparse(sb.uuid, *uuid_string);
params->hash_area_offset = sb_offset;
return 0;
}
/* Write verity superblock to disk */
int VERITY_write_sb(struct crypt_device *cd,
uint64_t sb_offset,
const char *uuid_string,
struct crypt_params_verity *params)
{
const char *device = device_path(crypt_metadata_device(cd));
int bsize = device_block_size(crypt_metadata_device(cd));
struct verity_sb sb = {};
ssize_t hdr_size = sizeof(struct verity_sb);
uuid_t uuid;
int r, devfd = 0;
log_dbg("Updating VERITY header of size %u on device %s, offset %" PRIu64 ".",
sizeof(struct verity_sb), device, sb_offset);
if (!uuid_string || uuid_parse(uuid_string, uuid) == -1) {
log_err(cd, _("Wrong VERITY UUID format provided.\n"), device);
return -EINVAL;
}
if (params->flags & CRYPT_VERITY_NO_HEADER) {
log_err(cd, _("Verity device doesn't use on-disk header.\n"), device);
return -EINVAL;
}
devfd = open(device, O_RDWR | O_DIRECT);
if(devfd == -1) {
log_err(cd, _("Cannot open device %s.\n"), device);
return -EINVAL;
}
memcpy(&sb.signature, VERITY_SIGNATURE, sizeof(sb.signature));
sb.version = cpu_to_le32(1);
sb.hash_type = cpu_to_le32(params->hash_type);
sb.data_block_size = cpu_to_le32(params->data_block_size);
sb.hash_block_size = cpu_to_le32(params->hash_block_size);
sb.salt_size = cpu_to_le16(params->salt_size);
sb.data_blocks = cpu_to_le64(params->data_size);
strncpy((char *)sb.algorithm, params->hash_name, sizeof(sb.algorithm));
memcpy(sb.salt, params->salt, params->salt_size);
memcpy(sb.uuid, uuid, sizeof(sb.uuid));
r = write_lseek_blockwise(devfd, bsize, (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"), device);
close(devfd);
return r;
}
/* Calculate hash offset in hash blocks */
uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params)
{
uint64_t hash_offset = params->hash_area_offset;
if (params->flags & CRYPT_VERITY_NO_HEADER)
return hash_offset / params->hash_block_size;
hash_offset += sizeof(struct verity_sb);
hash_offset += params->hash_block_size - 1;
return hash_offset / params->hash_block_size;
}
int VERITY_UUID_generate(struct crypt_device *cd, char **uuid_string)
{
uuid_t uuid;
if (!(*uuid_string = malloc(40)))
return -ENOMEM;
uuid_generate(uuid);
uuid_unparse(uuid, *uuid_string);
return 0;
}
/* Activate verity device in kernel device-mapper */
int VERITY_activate(struct crypt_device *cd,
const char *name,
const char *root_hash,
size_t root_hash_size,
struct crypt_params_verity *verity_hdr,
uint32_t activation_flags)
{
struct crypt_dm_active_device dmd;
int r;
log_dbg("Trying to activate VERITY device %s using hash %s.",
name ?: "[none]", verity_hdr->hash_name);
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);
if (r < 0)
return r;
}
if (!name)
return 0;
dmd.target = DM_VERITY;
dmd.data_device = crypt_data_device(cd);
dmd.u.verity.hash_device = crypt_metadata_device(cd);
dmd.u.verity.root_hash = root_hash;
dmd.u.verity.root_hash_size = root_hash_size;
dmd.u.verity.hash_offset = VERITY_hash_offset_block(verity_hdr),
dmd.flags = activation_flags;
dmd.size = verity_hdr->data_size * verity_hdr->data_block_size / 512;
dmd.uuid = crypt_get_uuid(cd);
dmd.u.verity.vp = verity_hdr;
r = device_block_adjust(cd, dmd.u.verity.hash_device, DEV_OK,
0, NULL, NULL);
if (r)
return r;
r = device_block_adjust(cd, dmd.data_device, DEV_EXCL,
0, &dmd.size, &dmd.flags);
if (r)
return r;
r = dm_create_device(cd, name, CRYPT_VERITY, &dmd, 0);
if (!r && !(dm_flags() & DM_VERITY_SUPPORTED)) {
log_err(cd, _("Kernel doesn't support dm-verity mapping.\n"));
return -ENOTSUP;
}
if (r < 0)
return r;
r = dm_status_verity_ok(cd, name);
if (r < 0)
return r;
if (!r)
log_err(cd, _("Verity device detected corruption after activation.\n"));
return 0;
}

64
lib/verity/verity.h Normal file
View File

@@ -0,0 +1,64 @@
/*
* dm-verity volume handling
*
* Copyright (C) 2012, 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
* version 2 as published by the Free Software Foundation.
*
* 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 _VERITY_H
#define _VERITY_H
#include <unistd.h>
#include "config.h"
#define VERITY_MAX_HASH_TYPE 1
#define VERITY_BLOCK_SIZE_OK(x) ((x) % 512 || (x) < 512 || \
(x) > (512 * 1024) || (x) & ((x)-1))
struct crypt_device;
struct crypt_params_verity;
int VERITY_read_sb(struct crypt_device *cd,
uint64_t sb_offset,
char **uuid,
struct crypt_params_verity *params);
int VERITY_write_sb(struct crypt_device *cd,
uint64_t sb_offset,
const char *uuid_string,
struct crypt_params_verity *params);
int VERITY_activate(struct crypt_device *cd,
const char *name,
const char *root_hash,
size_t root_hash_size,
struct crypt_params_verity *verity_hdr,
uint32_t activation_flags);
int VERITY_verify(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr,
const char *root_hash,
size_t root_hash_size);
int VERITY_create(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr,
char *root_hash,
size_t root_hash_size);
uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params);
int VERITY_UUID_generate(struct crypt_device *cd, char **uuid_string);
#endif

431
lib/verity/verity_hash.c Normal file
View File

@@ -0,0 +1,431 @@
/*
* dm-verity volume handling
*
* Copyright (C) 2012, 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
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "verity.h"
#include "internal.h"
#define VERITY_MAX_LEVELS 63
static unsigned get_bits_up(size_t u)
{
unsigned i = 0;
while ((1U << i) < u)
i++;
return i;
}
static unsigned get_bits_down(size_t u)
{
unsigned i = 0;
while ((u >> i) > 1U)
i++;
return i;
}
static int verify_zero(struct crypt_device *cd, FILE *wr, size_t bytes)
{
char block[bytes];
size_t i;
if (fread(block, bytes, 1, wr) != 1) {
log_dbg("EIO while reading spare area.");
return -EIO;
}
for (i = 0; i < bytes; i++)
if (block[i]) {
log_err(cd, _("Spare area is not zeroed at position %" PRIu64 ".\n"),
ftello(wr) - bytes);
return -EPERM;
}
return 0;
}
static int verify_hash_block(const char *hash_name, int version,
char *hash, size_t hash_size,
const char *data, size_t data_size,
const char *salt, size_t salt_size)
{
struct crypt_hash *ctx = NULL;
int r;
if (crypt_hash_init(&ctx, hash_name))
return -EINVAL;
if (version == 1 && (r = crypt_hash_write(ctx, salt, salt_size)))
goto out;
if ((r = crypt_hash_write(ctx, data, data_size)))
goto out;
if (version == 0 && (r = crypt_hash_write(ctx, salt, salt_size)))
goto out;
r = crypt_hash_final(ctx, hash, hash_size);
out:
crypt_hash_destroy(ctx);
return r;
}
static int mult_overflow(off_t *u, off_t b, size_t size)
{
*u = (uint64_t)b * size;
if ((off_t)(*u / size) != b || (off_t)*u < 0)
return 1;
return 0;
}
static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
off_t data_block, size_t data_block_size,
off_t hash_block, size_t hash_block_size,
off_t blocks, int version,
const char *hash_name, int verify,
char *calculated_digest, size_t digest_size,
const char *salt, size_t salt_size)
{
char left_block[hash_block_size];
char data_buffer[data_block_size];
char read_digest[digest_size];
size_t hash_per_block = 1 << get_bits_down(hash_block_size / digest_size);
size_t digest_size_full = 1 << get_bits_up(digest_size);
off_t blocks_to_write = (blocks + hash_per_block - 1) / hash_per_block;
off_t seek_rd, seek_wr;
size_t left_bytes;
unsigned i;
int r;
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"));
return -EINVAL;
}
if (fseeko(rd, seek_rd, SEEK_SET)) {
log_dbg("Cannot seek to requested position in data device.");
return -EIO;
}
if (wr && fseeko(wr, seek_wr, SEEK_SET)) {
log_dbg("Cannot seek to requested position in hash device.");
return -EIO;
}
memset(left_block, 0, hash_block_size);
while (blocks_to_write--) {
left_bytes = hash_block_size;
for (i = 0; i < hash_per_block; i++) {
if (!blocks)
break;
blocks--;
if (fread(data_buffer, data_block_size, 1, rd) != 1) {
log_dbg("Cannot read data device block.");
return -EIO;
}
if (verify_hash_block(hash_name, version,
calculated_digest, digest_size,
data_buffer, data_block_size,
salt, salt_size))
return -EINVAL;
if (!wr)
break;
if (verify) {
if (fread(read_digest, digest_size, 1, wr) != 1) {
log_dbg("Cannot read digest form hash device.");
return -EIO;
}
if (memcmp(read_digest, calculated_digest, digest_size)) {
log_err(cd, _("Verification failed at position %" PRIu64 ".\n"),
ftello(rd) - data_block_size);
return -EPERM;
}
} else {
if (fwrite(calculated_digest, digest_size, 1, wr) != 1) {
log_dbg("Cannot write digest to hash device.");
return -EIO;
}
}
if (version == 0) {
left_bytes -= digest_size;
} else {
if (digest_size_full - digest_size) {
if (verify) {
r = verify_zero(cd, wr, digest_size_full - digest_size);
if (r)
return r;
} else if (fwrite(left_block, digest_size_full - digest_size, 1, wr) != 1) {
log_dbg("Cannot write spare area to hash device.");
return -EIO;
}
}
left_bytes -= digest_size_full;
}
}
if (wr && left_bytes) {
if (verify) {
r = verify_zero(cd , wr, left_bytes);
if (r)
return r;
} else if (fwrite(left_block, left_bytes, 1, wr) != 1) {
log_dbg("Cannot write remaining spare area to hash device.");
return -EIO;
}
}
}
return 0;
}
static int VERITY_create_or_verify_hash(struct crypt_device *cd,
int verify,
int version,
const char *hash_name,
struct device *hash_device,
struct device *data_device,
size_t hash_block_size,
size_t data_block_size,
off_t data_blocks,
off_t hash_position,
char *root_hash,
size_t digest_size,
const char *salt,
size_t salt_size)
{
char calculated_digest[digest_size];
FILE *data_file = NULL;
FILE *hash_file = NULL, *hash_file_2;
off_t hash_level_block[VERITY_MAX_LEVELS];
off_t hash_level_size[VERITY_MAX_LEVELS];
off_t data_file_blocks, s;
size_t hash_per_block, hash_per_block_bits;
off_t data_device_size = 0, hash_device_size = 0;
uint64_t dev_size;
int levels, i, r;
log_dbg("Hash %s %s, data device %s, data blocks %" PRIu64
", hash_device %s, offset %" PRIu64 ".",
verify ? "verification" : "creation", hash_name,
device_path(data_device), data_blocks,
device_path(hash_device), hash_position);
if (data_blocks < 0 || hash_position < 0) {
log_err(cd, _("Invalid size parameters for verity device.\n"));
return -EINVAL;
}
if (!data_blocks) {
r = device_size(data_device, &dev_size);
if (r < 0)
return r;
data_file_blocks = dev_size / data_block_size;
} else
data_file_blocks = data_blocks;
if (mult_overflow(&data_device_size, data_blocks, data_block_size)) {
log_err(cd, _("Device offset overflow.\n"));
return -EINVAL;
}
hash_per_block_bits = get_bits_down(hash_block_size / digest_size);
hash_per_block = 1 << hash_per_block_bits;
if (!hash_per_block_bits)
return -EINVAL;
levels = 0;
if (data_file_blocks) {
while (hash_per_block_bits * levels < 64 &&
(data_file_blocks - 1) >> (hash_per_block_bits * levels))
levels++;
}
log_dbg("Using %d hash levels.", levels);
if (levels > VERITY_MAX_LEVELS) {
log_err(cd, _("Too many tree levels for verity volume.\n"));
return -EINVAL;
}
for (i = levels - 1; i >= 0; i--) {
hash_level_block[i] = hash_position;
// verity position of block data_file_blocks at level i
s = data_file_blocks >> (i * hash_per_block_bits);
s = (s + hash_per_block - 1) / hash_per_block;
hash_level_size[i] = s;
if ((hash_position + s) < hash_position ||
(hash_position + s) < 0) {
log_err(cd, _("Device offset overflow.\n"));
return -EINVAL;
}
hash_position += s;
}
if (mult_overflow(&hash_device_size, hash_position, hash_block_size)) {
log_err(cd, _("Device offset overflow.\n"));
return -EINVAL;
}
log_dbg("Data device size required: %" PRIu64 " bytes.",
data_device_size);
data_file = fopen(device_path(data_device), "r");
if (!data_file) {
log_err(cd, _("Cannot open device %s.\n"),
device_path(data_device)
);
r = -EIO;
goto out;
}
log_dbg("Hash device size required: %" PRIu64 " bytes.",
hash_device_size);
hash_file = fopen(device_path(hash_device), verify ? "r" : "r+");
if (!hash_file) {
log_err(cd, _("Cannot open device %s.\n"),
device_path(hash_device));
r = -EIO;
goto out;
}
memset(calculated_digest, 0, digest_size);
for (i = 0; i < levels; i++) {
if (!i) {
r = create_or_verify(cd, data_file, hash_file,
0, data_block_size,
hash_level_block[i], hash_block_size,
data_file_blocks, version, hash_name, verify,
calculated_digest, digest_size, salt, salt_size);
if (r)
goto out;
} else {
hash_file_2 = fopen(device_path(hash_device), "r");
if (!hash_file_2) {
log_err(cd, _("Cannot open device %s.\n"),
device_path(hash_device));
r = -EIO;
goto out;
}
r = create_or_verify(cd, hash_file_2, hash_file,
hash_level_block[i - 1], hash_block_size,
hash_level_block[i], hash_block_size,
hash_level_size[i - 1], version, hash_name, verify,
calculated_digest, digest_size, salt, salt_size);
fclose(hash_file_2);
if (r)
goto out;
}
}
if (levels)
r = create_or_verify(cd, hash_file, NULL,
hash_level_block[levels - 1], hash_block_size,
0, hash_block_size,
1, version, hash_name, verify,
calculated_digest, digest_size, salt, salt_size);
else
r = create_or_verify(cd, data_file, NULL,
0, data_block_size,
0, hash_block_size,
data_file_blocks, version, hash_name, verify,
calculated_digest, digest_size, salt, salt_size);
out:
if (verify) {
if (r)
log_err(cd, _("Verification of data area failed.\n"));
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"));
else
log_dbg("Verification of root hash succeeded.");
}
} else {
if (r == -EIO)
log_err(cd, _("Input/output error while creating hash area.\n"));
else if (r)
log_err(cd, _("Creation of hash area failed.\n"));
else {
fsync(fileno(hash_file));
memcpy(root_hash, calculated_digest, digest_size);
}
}
if (data_file)
fclose(data_file);
if (hash_file)
fclose(hash_file);
return r;
}
/* Verify verity device using userspace crypto backend */
int VERITY_verify(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr,
const char *root_hash,
size_t root_hash_size)
{
return VERITY_create_or_verify_hash(cd, 1,
verity_hdr->hash_type,
verity_hdr->hash_name,
crypt_metadata_device(cd),
crypt_data_device(cd),
verity_hdr->hash_block_size,
verity_hdr->data_block_size,
verity_hdr->data_size,
VERITY_hash_offset_block(verity_hdr),
CONST_CAST(char*)root_hash,
root_hash_size,
verity_hdr->salt,
verity_hdr->salt_size);
}
/* Create verity hash */
int VERITY_create(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr,
char *root_hash,
size_t root_hash_size)
{
unsigned pgsize = crypt_getpagesize();
if (verity_hdr->salt_size > 256)
return -EINVAL;
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);
return VERITY_create_or_verify_hash(cd, 0,
verity_hdr->hash_type,
verity_hdr->hash_name,
crypt_metadata_device(cd),
crypt_data_device(cd),
verity_hdr->hash_block_size,
verity_hdr->data_block_size,
verity_hdr->data_size,
VERITY_hash_offset_block(verity_hdr),
root_hash,
root_hash_size,
verity_hdr->salt,
verity_hdr->salt_size);
}

View File

@@ -1,3 +1,11 @@
man8_MANS = cryptsetup.8
EXTRA_DIST = cryptsetup.8
if VERITYSETUP
man8_MANS += veritysetup.8
endif
if REENCRYPT
man8_MANS += cryptsetup-reencrypt.8
endif
EXTRA_DIST = cryptsetup.8 veritysetup.8 cryptsetup-reencrypt.8

210
man/cryptsetup-reencrypt.8 Normal file
View File

@@ -0,0 +1,210 @@
.TH CRYPTSETUP-REENCRYPT "8" "June 2012" "cryptsetup-reencrypt" "Maintenance Commands"
.SH NAME
cryptsetup-reencrypt - tool for offline LUKS device re-encryption
.SH SYNOPSIS
.B cryptsetup-reencrypt <options> <device>
.SH DESCRIPTION
.PP
Cryptsetup-reencrypt can be used to change reencryption parameters
which otherwise require full on-disk data change (re-encryption).
You can regenerate \fBvolume key\fR (the real key used in on-disk encryption
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.
\fIWARNING\fR: The cryptsetup-reencrypt program is not resistant to hardware
or kernel failures during reencryption (you can lose you data in this case).
\fIALWAYS BE SURE YOU HAVE RELIABLE BACKUP BEFORE USING THIS TOOL.\fR
.br
\fITHIS TOOL IS EXPERIMENTAL.\fR
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
files created during reencryption must be present.
For more info about LUKS see cryptsetup(8).
.PP
.SH OPTIONS
.TP
To start (or continue) re-encryption for <device> use:
.PP
\fIcryptsetup-reencrypt\fR <device>
\fB<options>\fR can be [\-\-block-size, \-\-cipher, \-\-hash, \-\-iter-time,
\-\-use-random | \-\-use-urandom, \-\-key-file, \-\-key-slot, \-\-keyfile-offset,
\-\-keyfile-size, \-\-tries, \-\-use-directio, \-\-use-fsync, \-\-write-log]
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.
.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.
.TP
.B "\-\-key-size, \-s \fI<bits>\fR"
Set key size in bits. The argument has to be a multiple of 8.
The possible key-sizes are limited by the cipher and mode used.
If you are increasing key size, there must be enough space in the LUKS header
for enlarged keyslots (data offset must be large enough) or reencryption
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.
.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.
WARNING: \-\-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.
WARNING: All other keyslots will be disabled if this option is used.
.TP
.B "\-\-keyfile-offset \fIvalue\fR"
Skip \fIvalue\fR bytes at the beginning of the key file.
.TP
.B "\-\-keyfile-size, \-l"
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 "\-\-tries, \-T"
Number of retries for invalid passphrase entry.
.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 "\-\-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.
WARNING: 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).
WARNING: This is destructive operation.
.TP
.B "\-\-reduce-device-size \fIsize[units]\fR"
Enlarge data offset to specified value by shrinking device size.
This means that last sectors on the original device will be lost,
ciphertext data will be effectively shifted by specified
number of sectors.
It can be usefull if you e.g. added some space to underlying
partition (so last sectors contains no data).
For units suffix see \-\-device-size parameter description.
WARNING: 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.
WARNING: This is destructive operation and cannot be reverted.
.TP
.B "\-\-use-directio"
Use direct-io (O_DIRECT) for all read/write data operations.
Usefull if direct-io operations perform better than normal buffered
operations (e.g. in virtual environments).
.TP
.B "\-\-use-fsync"
Use fsync call after every written block.
.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.
.TP
.B "\-\-batch-mode, \-q"
Suppresses all warnings and reencryption progress output.
.TP
.B "\-\-version"
Show the program version.
.SH RETURN CODES
Cryptsetup-reencrypt returns 0 on success and a non-zero value on error.
Error codes are: 1 wrong parameters, 2 no permission,
3 out of memory, 4 wrong device specified, 5 device already exists
or device is busy.
.SH EXAMPLES
.TP
Reencrypt /dev/sdb1 (change volume key)
cryptsetup-reencrypt /dev/sdb1
.TP
Reencrypt and also change cipher and cipher mode
cryptsetup-reencrypt /dev/sdb1 -c aes-xts-plain64
.TP
Add LUKS encryption to not yet encrypted device
First, be sure you have space added to disk.
Or alternatively shrink filesystem in advance.
.br
Here we need 4096 512-bytes sectors (enough for 2x128 bit key).
fdisk -u /dev/sdb # move sdb1 partition end + 4096 sectors
cryptsetup-reencrypt /dev/sdb1 --new --reduce-device-size 4096
.SH REPORTING BUGS
Report bugs, including ones in the documentation, on
the cryptsetup mailing list at <dm-crypt@saout.de>
or in the 'Issues' section on LUKS website.
Please attach the output of the failed command with the
\-\-debug option added.
.SH AUTHORS
Cryptsetup-reencrypt was written by Milan Broz <gmazyland@gmail.com>.
.SH COPYRIGHT
Copyright \(co 2012 Milan Broz
.br
Copyright \(co 2012 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.
.SH SEE ALSO
The project website at \fBhttp://code.google.com/p/cryptsetup/\fR

View File

@@ -10,6 +10,12 @@ device-mapper mappings. These include plain dm-crypt volumes and
LUKS volumes. The difference is that LUKS uses a metadata header
and can hence offer more features than plain dm-crypt. On the other
hand, the header is visible and vulnerable to damage.
.SH PLAIN DM-CRYPT OR LUKS?
.PP
Unless you understand the cryptographic background well, use LUKS.
With plain dm-crypt there are a number of possible user errors
that massively decrease security. While LUKS cannot fix them
all, it can lessen the impact for many of them.
.SH WARNINGS
.PP
A lot of good information on the risks of using encrypted storage,
@@ -144,7 +150,7 @@ The <device> parameter can be also specified by LUKS UUID in the
format UUID=<uuid>, which uses the symlinks in /dev/disk/by-uuid.
\fB<options>\fR can be [\-\-key-file, \-\-keyfile-offset,
\-\-keyfile-size, \-\-readonly,
\-\-keyfile-size, \-\-readonly, \-\-test-passphrase,
\-\-allow-discards, \-\-header, \-\-key-slot, \-\-master-key-file].
.PP
\fIluksClose\fR <name>
@@ -613,6 +619,10 @@ later. If in doubt, do no use it.
A kernel version of 3.1 or later is needed. For earlier kernels
this option is ignored.
.TP
.B "\-\-test-passphrase\fR"
Do not activate device, just verify passphrase.
This option is only relevant for \fIluksOpen\fR.
.TP
.B "\-\-header\fR <device or file storing the LUKS header>"
Use a detached (separated) metadata device or file where the
LUKS header is stored. This options allows to store ciphertext
@@ -803,7 +813,7 @@ Copyright \(co 2004 Christophe Saout
.br
Copyright \(co 2004-2006 Clemens Fruhwirth
.br
Copyright \(co 2009-2011 Red Hat, Inc.
Copyright \(co 2009-2012 Red Hat, Inc.
.br
Copyright \(co 2012 Arno Wagner

141
man/veritysetup.8 Normal file
View File

@@ -0,0 +1,141 @@
.TH VERITYSETUP "8" "June 2012" "veritysetup" "Maintenance Commands"
.SH NAME
veritysetup - manage dm-verity (block level verification) volumes
.SH SYNOPSIS
.B veritysetup <options> <action> <action args>
.SH DESCRIPTION
.PP
Veritysetup is used to configure dm-verity managed device-mapper mappings.
Device-mapper verity target provides read-only transparent integrity
checking of block devices using kernel crypto API.
The dm-verity devices are always read-only.
Veritysetup supports these operations:
.PP
\fIformat\fR <data_device> <hash_device>
.IP
Calculates and permanently stores hash verification data for data_device.
Hash area can be located on the same device after data if specified
by \-\-hash\-offset option.
Note you need to provide root hash string for device verification
or activation. Root hash must be trusted.
The data or hash device argument can be block device or file image.
If hash device path doesn't exist, it will be created as file.
\fB<options>\fR can be [\-\-hash, \-\-no-superblock, \-\-format,
\-\-data-block-size, \-\-hash-block-size, \-\-data-blocks, \-\-hash-offset,
\-\-salt, \-\-uuid]
.PP
\fIcreate\fR <name> <data_device> <hash_device> <root_hash>
.IP
Creates a mapping with <name> backed by device <data_device> and using
<hash_device> for in-kernel verification.
The <root_hash> is a hexadecimal string.
\fB<options>\fR can be [\-\-hash-offset, \-\-no-superblock]
If option \-\-no-superblock is used, you have to use as the same options
as in initial format operation.
.PP
\fIverify\fR <data_device> <hash_device> <root_hash>
.IP
Verifies data on data_device with use of hash blocks stored on hash_device.
This command performs userspace verification, no kernel device is created.
The <root_hash> is a hexadecimal string.
\fB<options>\fR can be [\-\-hash-offset, \-\-no-superblock]
If option \-\-no-superblock is used, you have to use as the same options
as in initial format operation.
.PP
\fIremove\fR <name>
.IP
Removes existing mapping <name>.
.PP
\fIstatus\fR <name>
.IP
Reports status for the active verity mapping <name>.
.PP
\fIdump\fR <hash_device>
.IP
Reports parameters of verity device from on-disk stored superblock.
\fB<options>\fR can be [\-\-no-superblock]
.SH OPTIONS
.TP
.B "\-\-verbose, \-v"
Print more information on command execution.
.TP
.B "\-\-debug"
Run in debug mode with full diagnostic logs. Debug output
lines are always prefixed by '#'.
.TP
.B "\-\-no-superblock"
Create or use dm-verity without permanent on-disk superblock.
.TP
.B "\-\-format=number"
Specifies the hash version type.
Format type 0 is original Chrome OS verion. Format type 1 is current version.
.TP
.B "\-\-data-block-size=bytes"
Used block size for the data device.
(Note kernel supports only page-size as maximum here.)
.TP
.B "\-\-hash-block-size=bytes"
Used block size for the hash device.
(Note kernel supports only page-size as maximum here.)
.TP
.B "\-\-data-blocks=blocks"
Size of data device used in verification.
If not specified, the whole device is used.
.TP
.B "\-\-hash-offset=bytes"
Offset of hash area/superblock on hash_device.
Value must be aligned to disk sector offset.
.TP
.B "\-\-salt=hex string"
Salt used for format or verification.
Format is a hexadecimal string.
.TP
.B "\-\-uuid=UUID"
Use the provided UUID for format command instead of generating new one.
The UUID must be provided in standard UUID format,
e.g. 12345678-1234-1234-1234-123456789abc.
.TP
.B "\-\-version"
Show the program version.
.SH RETURN CODES
Veritysetup returns 0 on success and a non-zero value on error.
Error codes are: 1 wrong parameters, 2 no permission,
3 out of memory, 4 wrong device specified, 5 device already exists
or device is busy.
.SH REPORTING BUGS
Report bugs, including ones in the documentation, on
the cryptsetup mailing list at <dm-crypt@saout.de>
or in the 'Issues' section on LUKS website.
Please attach the output of the failed command with the
\-\-debug option added.
.SH AUTHORS
The first implementation of veritysetup was written by Chrome OS authors.
This version is based on verification code written by Mikulas Patocka <mpatocka@redhat.com>
and rewritten for libcryptsetup by Milan Broz <gmazyland@gmail.com>.
.SH COPYRIGHT
Copyright \(co 2012 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.
.SH SEE ALSO
The project website at \fBhttp://code.google.com/p/cryptsetup/\fR
The verity on-disk format specification available at
\fBhttp://code.google.com/p/cryptsetup/wiki/DMVerity\fR

17
misc/dict_search/Makefile Normal file
View File

@@ -0,0 +1,17 @@
TARGET=luks_dict
CFLAGS=-O2 -g -Wall -D_GNU_SOURCE
LDLIBS=-lcryptsetup
CC=gcc
SOURCES=$(wildcard *.c)
OBJECTS=$(SOURCES:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) -o $@ $^ $(LDLIBS)
clean:
rm -f *.o *~ core $(TARGET)
.PHONY: clean

17
misc/dict_search/README Normal file
View File

@@ -0,0 +1,17 @@
Simple example how to use libcryptsetup
for password search.
Run: luks_dict <device|image> <dictionary> [cpus]
<device|image> is LUKS device or image
<dictionary> is list of passphrases to try
(note trailing EOL is stripped)
cpus - number of processes to start in parallel
Format of dictionary file is simple one password per line,
if first char on line s # it is skiped as comment.
You have it run as root (device-mapper cannot
create dmcrypt devices as nrmal user. Code need
to map keyslots as temporary dmcrypt device.)

View File

@@ -0,0 +1,130 @@
/*
* Example of LUKS password dictionary search
*
* Run this as root, e.g. ./luks_dict test.img /usr/share/john/password.lst 4
*
* Copyright (C) 2012 Milan Broz <asi@ucw.cz>
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <libcryptsetup.h>
#define MAX_LEN 512
static void check(struct crypt_device *cd, const char *pwd_file, unsigned my_id, unsigned max_id)
{
FILE *f;
int len, r = -1;
unsigned long line = 0;
char pwd[MAX_LEN];
if (fork())
return;
/* open password file, now in separate process */
f = fopen(pwd_file, "r");
if (!f) {
printf("Cannot open %s.\n", pwd_file);
exit(EXIT_FAILURE);
}
while (fgets(pwd, MAX_LEN, f)) {
/* every process tries N-th line, skip others */
if (line++ % max_id != my_id)
continue;
len = strlen(pwd);
/* strip EOL - this is like a input from tty */
if (len && pwd[len - 1] == '\n') {
pwd[len - 1] = '\0';
len--;
}
/* lines starting "#!comment" are comments */
if (len >= 9 && !strncmp(pwd, "#!comment", 9)) {
/* printf("skipping %s\n", pwd); */
continue;
}
/* printf("%d: checking %s\n", my_id, pwd); */
r = crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, pwd, len, 0);
if (r >= 0) {
printf("Found passphrase for slot %d: \"%s\"\n", r, pwd);
break;
}
}
fclose(f);
crypt_free(cd);
exit(r >= 0 ? 2 : EXIT_SUCCESS);
}
int main(int argc, char *argv[])
{
int i, status, procs = 4;
struct crypt_device *cd;
if (argc < 3 || argc > 4) {
printf("Use: %s <LUKS_device|file> <password file> [#processes] %d\n", argv[0], argc);
exit(EXIT_FAILURE);
}
if (argc == 4 && (sscanf(argv[3], "%i", &procs) != 1 || procs < 1)) {
printf("Wrong number of processes.\n");
exit(EXIT_FAILURE);
}
/* crypt_set_debug_level(CRYPT_DEBUG_ALL); */
/*
* Need to create temporary keyslot device-mapper devices and allocate loop if needed,
* so root is requried here.
*/
if (getuid() != 0) {
printf("You must be root to run this program.\n");
exit(EXIT_FAILURE);
}
/* signal all children if anything happens */
prctl(PR_SET_PDEATHSIG, SIGHUP);
setpriority(PRIO_PROCESS, 0, -5);
/* we are not going to modify anything, so common init is ok */
if (crypt_init(&cd, argv[1]) || crypt_load(cd, CRYPT_LUKS1, NULL)) {
printf("Cannot open %s.\n", argv[1]);
exit(EXIT_FAILURE);
}
/* run scan in separate processes, it is up to scheduler to assign CPUs inteligently */
for (i = 0; i < procs; i++)
check(cd, argv[2], i, procs);
/* wait until at least one finishes with error or status 2 (key found) */
while (wait(&status) != -1 && WIFEXITED(status)) {
if (WEXITSTATUS(status) == EXIT_SUCCESS)
continue;
/* kill rest of processes */
kill(0, SIGHUP);
/* not reached */
break;
}
exit(0);
}

View File

@@ -0,0 +1,23 @@
Example of simple dracut module for reencryption of system
LUKS drive on-the-fly.
Install in /usr/[share|lib]/dracut/modules.d/90reencrypt, then
rebuild intramfs "with dracut -f -a reencrypt".
Dracut then recognize argument rd_REENCRYPT=name:size,
e.g. rd_REENCRYPT=sda2:52G means only 52G of device
will be reencrypted (default is whole device).
(Name is kernel name of device.)
Note that reencryption context is stored in ramdisk, any
fail can mean complete lost of data!
Copyright (C) 2012 Milan Broz <asi@ucw.cz>
This copyrighted material is made available to anyone wishing to use,
modify, copy, or redistribute it subject to the terms and conditions
of the GNU General Public License v.2.
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.

View File

@@ -0,0 +1,5 @@
#!/bin/bash
which cryptsetup-reencrypt >/dev/null 2>&1 || exit 1
exit 0

View File

@@ -0,0 +1,6 @@
#!/bin/bash
inst cryptsetup-reencrypt
inst_hook cmdline 30 "$moddir/parse-reencrypt.sh"
inst "$moddir"/reencrypt.sh /sbin/reencrypt

View File

@@ -0,0 +1,22 @@
#!/bin/bash
check() {
[ -x /sbin/cryptsetup-reencrypt ] || return 1
return 255
}
depends() {
echo dm rootfs-block
return 0
}
installkernel() {
instmods dm_crypt =crypto
}
install() {
dracut_install cryptsetup-reencrypt
inst_hook cmdline 30 "$moddir/parse-reencrypt.sh"
inst_simple "$moddir"/reencrypt.sh /sbin/reencrypt
}

View File

@@ -0,0 +1,22 @@
#!/bin/sh
REENC=$(getargs rd_REENCRYPT=)
REENC_DEV=$(echo $REENC | sed 's/:.*//')
REENC_SIZE=$(echo $REENC | sed -n 's/.*://p')
REENC_KEY=$(getargs rd_REENCRYPT_KEY=)
if [ -z "$REENC_KEY" ] ; then
REENC_KEY=none
fi
if [ -n "$REENC_DEV" ] ; then
{
printf 'SUBSYSTEM!="block", GOTO="reenc_end"\n'
printf 'ACTION!="add|change", GOTO="reenc_end"\n'
printf 'KERNEL!="%s", GOTO="reenc_end"\n' $REENC_DEV
printf 'ENV{ID_FS_TYPE}=="crypto_LUKS", RUN+="/sbin/initqueue \
--unique --onetime --name crypt-reencrypt-%%k \
/sbin/reencrypt $env{DEVNAME} %s"\n' "$REENC_KEY $REENC_SIZE"
printf 'LABEL="reenc_end"\n'
} > /etc/udev/rules.d/69-reencryption.rules
fi

View File

@@ -0,0 +1,58 @@
#!/bin/sh
#
# $1=$device [$2=keyfile|none [$3=size]]
#
[ -d /sys/module/dm_crypt ] || modprobe dm_crypt
[ -f /tmp/reencrypted ] && exit 0
. /lib/dracut-lib.sh
# if device name is /dev/dm-X, convert to /dev/mapper/name
if [ "${1##/dev/dm-}" != "$1" ]; then
device="/dev/mapper/$(dmsetup info -c --noheadings -o name "$1")"
else
device="$1"
fi
PARAMS="$device -T 1 --use-fsync -B 32"
if [ -n "$3" ]; then
PARAMS="$PARAMS --device-size $3"
fi
reenc_readkey() {
local keypath="${1#*:}"
local keydev="${1%%:*}"
local mntp="/tmp/reencrypted-mount-tmp"
mkdir "$mntp"
mount -r "$keydev" "$mntp" && cat "$mntp/$keypath"
umount "$mntp"
rm -r "$mntp"
}
reenc_run() {
local cwd=$(pwd)
cd /tmp
if [ "$1" = "none" ] ; then
/bin/plymouth ask-for-password \
--prompt "LUKS password for REENCRYPTING $device" \
--command="/sbin/cryptsetup-reencrypt $PARAMS"
else
info "REENCRYPT using key $1"
reenc_readkey "$1" | /sbin/cryptsetup-reencrypt -d - $PARAMS
fi
cd $cwd
}
info "REENCRYPT $device requested"
# flock against other interactive activities
{ flock -s 9;
reenc_run $2
} 9>/.console.lock
# do not ask again
>> /tmp/reencrypted
exit 0

View File

@@ -0,0 +1,14 @@
TARGETS=chk_luks_keyslots
CFLAGS=-O0 -g -Wall -D_GNU_SOURCE
LDLIBS=-lcryptsetup -lm
CC=gcc
all: $(TARGETS)
chk_luks_keyslots: chk_luks_keyslots.o
$(CC) -o $@ $^ $(LDLIBS)
clean:
rm -f *.o *~ core $(TARGETS)
.PHONY: clean

118
misc/keyslot_checker/README Normal file
View File

@@ -0,0 +1,118 @@
Purpose
=======
chk_luks_keyslots is a tool that searches the keyslot area of a
LUKS container for positions where entropy is low and hence
there is a high probability of damage from overwrites of parts
of the key-slot with data such as a RAID superblock or a partition
table.
Installation
============
1. Install the version of cryptsetup the tool came with.
2. Compile with
gcc -lm -lcryptsetup chk_luks_keyslots.c -o chk_luks_keyslots
Usage
=====
Call chk_luks_keyslots without arguments for an option summary.
Example of a good keyslot area:
-------------------------------
root> ./chk_luks_keyslots /dev/loop0
parameters (commandline and LUKS header):
sector size: 512
threshold: 0.900000
- processing keyslot 0: start: 0x001000 end: 0x020400
- processing keyslot 1: start: 0x021000 end: 0x040400
- processing keyslot 2: start: 0x041000 end: 0x060400
- processing keyslot 3: start: 0x061000 end: 0x080400
- processing keyslot 4: start: 0x081000 end: 0x0a0400
- processing keyslot 5: start: 0x0a1000 end: 0x0c0400
- processing keyslot 6: start: 0x0c1000 end: 0x0e0400
- processing keyslot 7: start: 0x0e1000 end: 0x100400
Example of a fault in slot 8 at offset 0x100200:
-----------------------------
root>./chk_luks_keyslots /dev/loop2
parameters (commandline and LUKS header):
sector size: 512
threshold: 0.900000
- processing keyslot 0: start: 0x001000 end: 0x020400
- processing keyslot 1: start: 0x021000 end: 0x040400
- processing keyslot 2: start: 0x041000 end: 0x060400
- processing keyslot 3: start: 0x061000 end: 0x080400
- processing keyslot 4: start: 0x081000 end: 0x0a0400
- processing keyslot 5: start: 0x0a1000 end: 0x0c0400
- processing keyslot 6: start: 0x0c1000 end: 0x0e0400
- processing keyslot 7: start: 0x0e1000 end: 0x100400
low entropy at: 0x100200 entropy: 0.846546
Same as last, but verbose:
--------------------------
root>./chk_luks_keyslots -v /dev/loop2
parameters (commandline and LUKS header):
sector size: 512
threshold: 0.900000
- processing keyslot 0: start: 0x001000 end: 0x020400
- processing keyslot 1: start: 0x021000 end: 0x040400
- processing keyslot 2: start: 0x041000 end: 0x060400
- processing keyslot 3: start: 0x061000 end: 0x080400
- processing keyslot 4: start: 0x081000 end: 0x0a0400
- processing keyslot 5: start: 0x0a1000 end: 0x0c0400
- processing keyslot 6: start: 0x0c1000 end: 0x0e0400
- processing keyslot 7: start: 0x0e1000 end: 0x100400
low entropy at: 0x100200 entropy: 0.846546
Binary dump:
0x100200 BD 0E C7 A8 7D EF 04 F6 AF 83 DF 74 94 FE 04 56 ....}......t...V
0x100210 3B 64 BD 68 A9 F6 CF 3C 37 CD 66 B7 17 4D 63 2B ;d.h...<7.f..Mc+
0x100220 8F 6E 74 7E 96 7A 2B 27 32 1B F0 80 37 5A 9A 41 .nt~.z+'2...7Z.A
0x100230 4A 6E CB C0 CF 39 95 45 92 90 E1 0B E6 08 EE 2A Jn...9.E.......*
0x100240 FA 66 6D 67 49 89 76 B1 41 CD 24 57 AA 65 F7 69 .fmgI.v.A.$W.e.i
0x100250 33 16 A7 C7 61 3D 43 B7 74 D6 86 83 1D 19 BF 85 3...a=C.t.......
0x100260 E4 22 3E 16 66 1C B0 1E 11 0D D4 26 37 AD A4 02 .">.f......&7...
0x100270 40 77 9A 5A B8 40 39 E3 A3 A0 96 08 4D 57 C5 0C @w.Z.@9.....MW..
0x100280 D4 74 89 45 FA 93 F7 FE A7 9D D3 99 43 77 8E 35 .t.E........Cw.5
0x100290 E0 55 90 3E 91 29 EA DB 5C 13 19 C9 83 CE D8 0C .U.>.)..\.......
0x1002a0 85 7F 96 26 60 16 A0 0B E1 F9 01 13 1E 59 83 98 ...&`........Y..
0x1002b0 06 B5 1D 6F B6 81 9D 60 58 70 15 30 29 42 32 C6 ...o...`Xp.0)B2.
0x1002c0 A7 55 64 00 65 ED 41 1C B4 C1 C7 10 E1 8E 60 B0 .Ud.e.A.......`.
0x1002d0 F0 9E 9C 40 5A 84 92 8D 21 F0 B8 2D 61 4E 21 9D ...@Z...!..-aN!.
0x1002e0 FA B8 18 D3 47 A4 4F D4 AB 73 C0 93 F3 8E 9A 95 ....G.O..s......
0x1002f0 A4 F1 6D EB 36 85 F4 F7 62 BA 26 D5 15 57 0D 0C ..m.6...b.&..W..
0x100300 C9 4E 19 F2 5B 5A F5 54 B8 F4 B5 57 72 08 1B 7A .N..[Z.T...Wr..z
0x100310 C3 66 7F 82 1E 75 92 C2 E9 97 64 5E F7 FB A9 05 .f...u....d^....
0x100320 CF 30 C8 6A D1 35 9B 9D 22 52 22 46 0E 4B DE 53 .0.j.5.."R"F.K.S
0x100330 68 C8 DA 5F C7 CA 31 D0 C9 B4 57 CF 0F 1F 4B 9C h.._..1...W...K.
0x100340 DF 0C F8 7C F2 E3 32 52 3C 0D D2 DC 5C CF F0 00 ...|..2R<...\...
0x100350 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 XXXXXXXXXXXXXXXX
0x100360 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 XXXXXXXXXXXXXXXX
0x100370 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 XXXXXXXXXXXXXXXX
0x100380 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 XXXXXXXXXXXXXXXX
0x100390 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 XXXXXXXXXXXXXXXX
0x1003a0 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 XXXXXXXXXXXXXXXX
0x1003b0 B4 81 7A F0 BE 38 7E 00 A4 61 41 06 ED 7B 40 D9 ..z..8~..aA..{@.
0x1003c0 BF 58 51 C9 CD 37 78 4D 4D B3 6E B4 7D 86 3C CB .XQ..7xMM.n.}.<.
0x1003d0 D5 39 2E FC 78 B1 3E DE C0 7F 55 25 65 71 AD 2A .9..x.>...U%eq.*
0x1003e0 1E 68 D3 3B 78 17 5F D2 08 93 50 88 D8 0A 75 4F .h.;x._...P...uO
0x1003f0 E5 AA 26 0F B4 F7 F5 88 65 2B E4 92 18 08 32 9E ..&.....e+....2.
----
Copyright (C) 2012, Arno Wagner <arno@wagner.name>
This file is free documentation; the author gives
unlimited permission to copy, distribute and modify it.

View File

@@ -0,0 +1,370 @@
/*
* LUKS keyslot entropy tester. Works only for header version 1.
*
* Functionality: Determines sample entropy (symbols: bytes) for
* each (by default) 512B sector in each used keyslot. If it
* is lower than a threshold, the sector address is printed
* as it is suspected of having non-"random" data in it, indicating
* damage by overwriting. This can obviously not find overwriting
* with random or random-like data (encrypted, compressed).
*
* Version history:
* v0.1: 09.09.2012 Initial release
* v0.2: 08.10.2012 Converted to use libcryptsetup
*
* Copyright (C) 2012, Arno Wagner <arno@wagner.name>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <math.h>
#include <fcntl.h>
#include <inttypes.h>
#include <libcryptsetup.h>
const char *help =
"Version 0.2 [8.10.2012]\n"
"\n"
" chk_luks_keyslots [options] luks-device \n"
"\n"
"This tool checks all keyslots of a LUKS device for \n"
"low entropy sections. If any are found, they are reported. \n"
"This allows to find areas damaged by things like filesystem \n"
"creation or RAID superblocks. \n"
"\n"
"Options: \n"
" -t <num> Entropy threshold. Possible values 0.0 ... 1.0 \n"
" Default: 0.90, which works well for 512B sectors.\n"
" For 512B sectors, you will get frequent misdetections\n"
" at thresholds around 0.94\n"
" Higher value: more sensitive but more false detections.\n"
" -s <num> Sector size. Must divide keyslot-size.\n"
" Default: 512 Bytes.\n"
" Values smaller than 128 are generally not very useful.\n"
" For values smaller than the default, you need to adjust\n"
" the threshold down to reduce misdetection. For values\n"
" larger than the default you need to adjust the threshold\n"
" up to retain sensitivity.\n"
" -v Print found suspicuous sectors verbosely. \n"
" -d Print decimal addresses instead of hex ones.\n"
"\n";
/* Config defaults */
static int sector_size = 512;
static double threshold = 0.90;
static int print_decimal = 0;
static int verbose = 0;
/* tools */
/* Calculates and returns sample entropy on byte level for
* The argument.
*/
static double ent_samp(unsigned char * buf, int len)
{
int freq[256]; /* stores symbol frequencies */
int i;
double e, f;
/* 0. Plausibility checks */
if (len <= 0)
return 0.0;
/* 1. count all frequencies */
for (i = 0; i < 256; i++) {
freq[i] = 0.0;
}
for (i = 0; i < len; i ++)
freq[buf[i]]++;
/* 2. calculate sample entropy */
e = 0.0;
for (i = 0; i < 256; i++) {
f = freq[i];
if (f > 0) {
f = f / (double)len;
e += f * log2(f);
}
}
if (e != 0.0)
e = -1.0 * e;
e = e / 8.0;
return e;
}
static void print_address(FILE *out, uint64_t value)
{
if (print_decimal) {
fprintf(out,"%08" PRIu64 " ", value);
} else {
fprintf(out,"%#08" PRIx64 " ", value);
}
}
/* uses default "hd" style, i.e. 16 bytes followed by ASCII */
static void hexdump_line(FILE *out, uint64_t address, unsigned char *buf) {
int i;
static char tbl[16] = "0123456789ABCDEF";
fprintf(out," ");
print_address(out, address);
fprintf(out," ");
/* hex */
for (i = 0; i < 16; i++) {
fprintf(out, "%c%c",
tbl[(unsigned char)buf[i]>> 4],
tbl[(unsigned char)buf[i] & 0x0f]);
fprintf(out," ");
if (i == 7)
fprintf(out," ");
}
fprintf(out," ");
/* ascii */
for (i = 0; i < 16; i++) {
if (isprint(buf[i])) {
fprintf(out, "%c", buf[i]);
} else {
fprintf(out, ".");
}
}
fprintf(out, "\n");
}
static void hexdump_sector(FILE *out, unsigned char *buf, uint64_t address, int len)
{
int done;
done = 0;
while (len - done >= 16) {
hexdump_line(out, address + done, buf + done);
done += 16;
}
}
static int check_keyslots(FILE *out, struct crypt_device *cd, int f_luks)
{
int i;
double ent;
off_t ofs;
uint64_t start, length, end;
crypt_keyslot_info ki;
unsigned char buffer[sector_size];
for (i = 0; i < crypt_keyslot_max(CRYPT_LUKS1) ; i++) {
fprintf(out, "- processing keyslot %d:", i);
ki = crypt_keyslot_status(cd, i);
if (ki == CRYPT_SLOT_INACTIVE) {
fprintf(out, " keyslot not in use\n");
continue;
}
if (ki == CRYPT_SLOT_INVALID) {
fprintf(out, "\nError: keyslot invalid.\n");
return EXIT_FAILURE;
}
if (crypt_keyslot_area(cd, i, &start, &length) < 0) {
fprintf(stderr,"\nError: querying keyslot area failed for slot %d\n", i);
perror(NULL);
return EXIT_FAILURE;
}
end = start + length;
fprintf(out, " start: ");
print_address(out, start);
fprintf(out, " end: ");
print_address(out, end);
fprintf(out, "\n");
/* check whether sector-size divides size */
if (length % sector_size != 0) {
fprintf(stderr,"\nError: Argument to -s does not divide keyslot size\n");
return EXIT_FAILURE;
}
for (ofs = start; (uint64_t)ofs < end; ofs += sector_size) {
if (lseek(f_luks, ofs, SEEK_SET) != ofs) {
fprintf(stderr,"\nCannot seek to keyslot area.\n");
return EXIT_FAILURE;
}
if (read(f_luks, buffer, sector_size) != sector_size) {
fprintf(stderr,"\nCannot read keyslot area.\n");
return EXIT_FAILURE;
}
ent = ent_samp(buffer, sector_size);
if (ent < threshold) {
fprintf(out, " low entropy at: ");
print_address(out, ofs);
fprintf(out, " entropy: %f\n", ent);
if (verbose) {
fprintf(out, " Binary dump:\n");
hexdump_sector(out, buffer, (uint64_t)ofs, sector_size);
fprintf(out,"\n");
}
}
}
}
return EXIT_SUCCESS;
}
/* Main */
int main(int argc, char **argv)
{
/* for option processing */
int c, r;
char *device;
/* for use of libcryptsetup */
struct crypt_device *cd;
/* Other vars */
int f_luks; /* device file for the luks device */
FILE *out;
/* temporary helper vars */
int res;
/* getopt values */
char *s, *end;
double tvalue;
int svalue;
/* global initializations */
out = stdout;
/* get commandline parameters */
while ((c = getopt (argc, argv, "t:s:vd")) != -1) {
switch (c) {
case 't':
s = optarg;
tvalue = strtod(s, &end);
if (s == end) {
fprintf(stderr, "\nError: Parsing of argument to -t failed.\n");
exit(EXIT_FAILURE);
}
if (tvalue < 0.0 || tvalue > 1.0) {
fprintf(stderr,"\nError: Argument to -t must be in 0.0 ... 1.0\n");
exit(EXIT_FAILURE);
}
threshold = tvalue;
break;
case 's':
s = optarg;
svalue = strtol(s, &end, 10);
if (s == end) {
fprintf(stderr, "\nError: Parsing of argument to -s failed.\n");
exit(EXIT_FAILURE);
}
if (svalue < 1) {
fprintf(stderr,"\nError: Argument to -s must be >= 1 \n");
exit(EXIT_FAILURE);
}
sector_size = svalue;
break;
case 'v':
verbose = 1;
break;
case 'd':
print_decimal = 1;
break;
case '?':
if (optopt == 't' || optopt == 's')
fprintf (stderr,"\nError: Option -%c requires an argument.\n",
optopt);
else if (isprint (optopt)) {
fprintf(stderr,"\nError: Unknown option `-%c'.\n", optopt);
fprintf(stderr,"\n\n%s", help);
} else {
fprintf (stderr, "\nError: Unknown option character `\\x%x'.\n",
optopt);
fprintf(stderr,"\n\n%s", help);
}
exit(EXIT_SUCCESS);
default:
exit(EXIT_FAILURE);
}
}
/* parse non-option stuff. Should be exactly one, the device. */
if (optind+1 != argc) {
fprintf(stderr,"\nError: exactly one non-option argument expected!\n");
fprintf(stderr,"\n\n%s", help);
exit(EXIT_FAILURE);
}
device = argv[optind];
/* test whether we can open and read device */
/* This is neded as we are reading the actual data
* in the keyslots dirtectly from the LUKS container.
*/
f_luks = open(device, O_RDONLY);
if (f_luks == -1) {
fprintf(stderr,"\nError: Opening of device %s failed:\n", device);
perror(NULL);
exit(EXIT_FAILURE);
}
/* now get the parameters we need via libcryptsetup */
/* Basically we need all active keyslots and their placement on disk */
/* first init. This does the following:
* - gets us a crypt_device struct with some values filled in
* Note: This does some init stuff we do not need, but that
* should not cause trouble.
*/
res = crypt_init(&cd, device);
if (res < 0) {
fprintf(stderr, "crypt_init() failed. Maybe not running as root?\n");
close(f_luks);
exit(EXIT_FAILURE);
}
/* now load LUKS header into the crypt_device
* This should also make sure a valid LUKS1 header is on disk
* and hence we should be able to skip magic and version checks.
*/
res = crypt_load(cd, CRYPT_LUKS1, NULL);
if (res < 0) {
fprintf(stderr, "crypt_load() failed. LUKS header too broken/absent?\n");
crypt_free(cd);
close(f_luks);
exit(EXIT_FAILURE);
}
fprintf(out, "\nparameters (commandline and LUKS header):\n");
fprintf(out, " sector size: %d\n", sector_size);
fprintf(out, " threshold: %0f\n\n", threshold);
r = check_keyslots(out, cd, f_luks);
crypt_free(cd);
close(f_luks);
return r;
}

View File

@@ -2,7 +2,7 @@
# Try to get LUKS info and master key from active mapping and prepare parameters for cryptsetup.
#
# Copyright (C) 2010,2011 Milan Broz <asi@ucw.cz>
# Copyright (C) 2010,2011,2012 Milan Broz <asi@ucw.cz>
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
@@ -12,11 +12,22 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
umask 0077
fail() { echo -e $1 ; exit 1 ; }
field() { echo $(dmsetup table --target crypt --showkeys $DEVICE | sed 's/.*: //' | cut -d' ' -f$1) ; }
field_cryptsetup() { echo $(cryptsetup status $DEVICE | grep $1 | sed "s/.*$1:\s*//;s/\ .*//") ; }
field_uuid() { echo $(dmsetup info $1 --noheadings -c -o uuid) ; }
field_device() {
TEMP=$(readlink /sys/dev/block/$1 | sed -e 's/.*\///')
if [ ${TEMP:0:3} = "dm-" -a -e /sys/block/$TEMP/dm/name ] ; then
TEMP=/dev/mapper/$(cat /sys/block/$TEMP/dm/name)
else
TEMP=/dev/$TEMP
fi
echo $TEMP
}
which readlink >/dev/null || fail "You need readlink (part of coreutils package)."
which xxd >/dev/null || fail "You need xxd (part of vim package) installed to convert key."
[ -z "$2" ] && fail "Recover LUKS header from active mapping, use:\n $0 crypt_mapped_device mk_file_name"
@@ -26,20 +37,23 @@ MK_FILE=$2
[ -z "$(field 4)" ] && fail "Mapping $1 not active or it is not crypt target."
# FIXME:
# - add UUID
# - check for CRYPT-LUKS1-* DM-UUID
CIPHER=$(field_cryptsetup cipher)
OFFSET=$(field_cryptsetup offset)
REAL_DEVICE=$(field_cryptsetup device)
KEY_SIZE=$(field_cryptsetup keysize)
CIPHER=$(field 4)
OFFSET=$(field 8)
SYS_DEVICE=$(field 7)
REAL_DEVICE=$(field_device $SYS_DEVICE)
KEY=$(field 5)
KEY_SIZE=$(( ${#KEY} / 2 * 8 ))
SYS_UUID=$(field_uuid $DEVICE)
UUID="${SYS_UUID:12:8}-${SYS_UUID:20:4}-${SYS_UUID:24:4}-${SYS_UUID:28:4}-${SYS_UUID:32:12}"
[ -z "$CIPHER" -o -z "$OFFSET" -o "$OFFSET" -le 383 -o -z "$KEY" ] && fail "Incompatible device, sorry."
#echo "CIPHER=$CIPHER OFFSET=$OFFSET SYS_DEVICE=$SYS_DEVICE REAL_DEVICE=$REAL_DEVICE KEY_SIZE=$KEY_SIZE KEY=$KEY UUID=$UUID SYS_UUID=$SYS_UUID"
[ -z "$CIPHER" -o -z "$OFFSET" -o "$OFFSET" -le 383 -o \
-z "$KEY" -o -z "$UUID" -o -z "$REAL_DEVICE" -o "${SYS_UUID:0:12}" != "CRYPT-LUKS1-" ] && \
fail "Incompatible device, sorry."
echo "Generating master key to file $MK_FILE."
echo -E -n $KEY| xxd -r -p >$MK_FILE
echo "You can now try to reformat LUKS device using:"
echo " cryptsetup luksFormat -c $CIPHER -s $KEY_SIZE --align-payload=$OFFSET --master-key-file=$MK_FILE $REAL_DEVICE"
echo " cryptsetup luksFormat -c $CIPHER -s $KEY_SIZE --align-payload=$OFFSET --master-key-file=$MK_FILE --uuid=$UUID $REAL_DEVICE"

View File

@@ -6,10 +6,15 @@ lib/crypt_plain.c
lib/utils_crypt.c
lib/utils_loop.c
lib/utils_fips.c
lib/utils_debug.c
lib/utils_device.c
lib/luks1/af.c
lib/luks1/keyencryption.c
lib/luks1/keymanage.c
lib/luks1/pbkdf.c
lib/loopaes/loopaes.c
lib/verity/verity.c
lib/verity/verity_hash.c
src/cryptsetup.c
src/veritysetup.c
src/cryptsetup_reencrypt.c
src/utils_tools.c

1149
po/cs.po

File diff suppressed because it is too large Load Diff

1100
po/de.po

File diff suppressed because it is too large Load Diff

1499
po/fr.po

File diff suppressed because it is too large Load Diff

845
po/nl.po

File diff suppressed because it is too large Load Diff

1075
po/pl.po

File diff suppressed because it is too large Load Diff

1099
po/uk.po

File diff suppressed because it is too large Load Diff

1193
po/vi.po

File diff suppressed because it is too large Load Diff

View File

@@ -9,10 +9,12 @@ INCLUDES = \
-DVERSION=\""$(VERSION)"\" \
-D_GNU_SOURCE
# cryptsetup
cryptsetup_SOURCES = \
$(top_builddir)/lib/utils_crypt.c \
$(top_builddir)/lib/utils_loop.c \
$(top_builddir)/lib/utils_fips.c \
utils_tools.c \
cryptsetup.c \
cryptsetup.h
@@ -25,7 +27,7 @@ cryptsetup_CFLAGS = -Wall
sbin_PROGRAMS=cryptsetup
if STATIC_CRYPTSETUP
if STATIC_TOOLS
sbin_PROGRAMS += cryptsetup.static
cryptsetup_static_SOURCES = $(cryptsetup_SOURCES)
cryptsetup_static_CFLAGS = $(cryptsetup_CFLAGS)
@@ -35,3 +37,58 @@ cryptsetup_static_LDADD = $(cryptsetup_LDADD) \
@DEVMAPPER_STATIC_LIBS@ \
@UUID_LIBS@
endif
# veritysetup
if VERITYSETUP
veritysetup_SOURCES = \
$(top_builddir)/lib/utils_crypt.c \
$(top_builddir)/lib/utils_loop.c \
utils_tools.c \
veritysetup.c \
cryptsetup.h
veritysetup_LDADD = \
$(top_builddir)/lib/libcryptsetup.la \
@POPT_LIBS@
veritysetup_CFLAGS = $(cryptsetup_CFLAGS)
sbin_PROGRAMS += veritysetup
if STATIC_TOOLS
sbin_PROGRAMS += veritysetup.static
veritysetup_static_SOURCES = $(veritysetup_SOURCES)
veritysetup_static_CFLAGS = $(veritysetup_CFLAGS)
veritysetup_static_LDFLAGS = -all-static
veritysetup_static_LDADD = $(veritysetup_LDADD) \
@CRYPTO_STATIC_LIBS@ \
@DEVMAPPER_STATIC_LIBS@ \
@UUID_LIBS@
endif
endif
# reencrypt
if REENCRYPT
cryptsetup_reencrypt_SOURCES = \
$(top_builddir)/lib/utils_crypt.c \
utils_tools.c \
cryptsetup_reencrypt.c \
cryptsetup.h
cryptsetup_reencrypt_LDADD = $(cryptsetup_LDADD)
cryptsetup_reencrypt_CFLAGS = $(cryptsetup_CFLAGS)
sbin_PROGRAMS += cryptsetup-reencrypt
if STATIC_TOOLS
sbin_PROGRAMS += cryptsetup-reencrypt.static
cryptsetup_reencrypt_static_SOURCES = $(cryptsetup_reencrypt_SOURCES)
cryptsetup_reencrypt_static_CFLAGS = $(cryptsetup_reencrypt_CFLAGS)
cryptsetup_reencrypt_static_LDFLAGS = -all-static
cryptsetup_reencrypt_static_LDADD = $(cryptsetup_reencrypt_LDADD) \
@CRYPTO_STATIC_LIBS@ \
@DEVMAPPER_STATIC_LIBS@ \
@UUID_LIBS@
endif
endif

View File

@@ -19,26 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <inttypes.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <limits.h>
#include <libcryptsetup.h>
#include <popt.h>
#include "cryptsetup.h"
static int opt_verbose = 0;
static int opt_debug = 0;
static const char *opt_cipher = NULL;
static const char *opt_hash = NULL;
static int opt_verify_passphrase = 0;
@@ -59,7 +41,6 @@ static uint64_t opt_skip = 0;
static int opt_skip_valid = 0;
static int opt_readonly = 0;
static int opt_iteration_time = 1000;
static int opt_batch_mode = 0;
static int opt_version_mode = 0;
static int opt_timeout = 0;
static int opt_tries = 3;
@@ -69,9 +50,11 @@ static int opt_urandom = 0;
static int opt_dump_master_key = 0;
static int opt_shared = 0;
static int opt_allow_discards = 0;
static int opt_test_passphrase = 0;
static const char **action_argv;
static int action_argc;
static const char *null_action_argv[] = {NULL, NULL};
static int action_create(int arg);
static int action_remove(int arg);
@@ -126,84 +109,6 @@ static struct action_type {
{ NULL, NULL, 0, 0, 0, NULL, NULL }
};
__attribute__((format(printf, 5, 6)))
static void clogger(struct crypt_device *cd, int level, const char *file,
int line, const char *format, ...)
{
va_list argp;
char *target = NULL;
va_start(argp, format);
if (vasprintf(&target, format, argp) > 0) {
if (level >= 0) {
crypt_log(cd, level, target);
#ifdef CRYPT_DEBUG
} else if (opt_debug)
printf("# %s:%d %s\n", file ?: "?", line, target);
#else
} else if (opt_debug)
printf("# %s\n", target);
#endif
}
va_end(argp);
free(target);
}
static int _yesDialog(const char *msg, void *usrptr __attribute__((unused)))
{
char *answer = NULL;
size_t size = 0;
int r = 1;
if(isatty(STDIN_FILENO) && !opt_batch_mode) {
log_std("\nWARNING!\n========\n");
log_std("%s\n\nAre you sure? (Type uppercase yes): ", msg);
if(getline(&answer, &size, stdin) == -1) {
perror("getline");
free(answer);
return 0;
}
if(strcmp(answer, "YES\n"))
r = 0;
free(answer);
}
return r;
}
static void _log(int level, const char *msg, void *usrptr __attribute__((unused)))
{
switch(level) {
case CRYPT_LOG_NORMAL:
fputs(msg, stdout);
break;
case CRYPT_LOG_VERBOSE:
if (opt_verbose)
fputs(msg, stdout);
break;
case CRYPT_LOG_ERROR:
fputs(msg, stderr);
break;
case CRYPT_LOG_DEBUG:
if (opt_debug)
printf("# %s\n", msg);
break;
default:
fprintf(stderr, "Internal error on logging class for msg: %s", msg);
break;
}
}
static void _quiet_log(int level, const char *msg, void *usrptr)
{
if (!opt_verbose && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
level = CRYPT_LOG_VERBOSE;
_log(level, msg, usrptr);
}
static int _verify_passphrase(int def)
{
/* Batch mode switch off verify - if not overrided by -y */
@@ -222,60 +127,6 @@ static int _verify_passphrase(int def)
return def;
}
static void show_status(int errcode)
{
char error[256], *error_;
if(!opt_verbose)
return;
if(!errcode) {
log_std(_("Command successful.\n"));
return;
}
crypt_get_error(error, sizeof(error));
if (!error[0]) {
error_ = strerror_r(-errcode, error, sizeof(error));
if (error_ != error) {
strncpy(error, error_, sizeof(error));
error[sizeof(error) - 1] = '\0';
}
}
log_err(_("Command failed with code %i"), -errcode);
if (*error)
log_err(": %s\n", error);
else
log_err(".\n");
}
static const char *uuid_or_device(const char *spec)
{
static char device[PATH_MAX];
char s, *ptr;
int i = 0, uuid_len = 5;
/* Check if it is correct UUID=<LUKS_UUID> format */
if (spec && !strncmp(spec, "UUID=", uuid_len)) {
strcpy(device, "/dev/disk/by-uuid/");
ptr = &device[strlen(device)];
i = uuid_len;
while ((s = spec[i++]) && i < PATH_MAX) {
if (!isxdigit(s) && s != '-')
return spec; /* Bail it out */
if (isalpha(s))
s = tolower(s);
*ptr++ = s;
}
*ptr = '\0';
return device;
}
return spec;
}
static int action_create(int arg __attribute__((unused)))
{
struct crypt_device *cd = NULL;
@@ -490,6 +341,8 @@ static int action_status(int arg __attribute__((unused)))
}
out:
crypt_free(cd);
if (r == -ENOTSUP)
r = 0;
return r;
}
@@ -528,15 +381,15 @@ static int action_luksRepair(int arg __attribute__((unused)))
goto out;
/* Currently only LUKS1 allows repair */
crypt_set_log_callback(cd, _quiet_log, NULL);
crypt_set_log_callback(cd, quiet_log, NULL);
r = crypt_load(cd, CRYPT_LUKS1, NULL);
crypt_set_log_callback(cd, _log, NULL);
crypt_set_log_callback(cd, tool_log, NULL);
if (r == 0) {
log_verbose( _("No known problems detected for LUKS header.\n"));
goto out;
}
r = _yesDialog(_("Really try to repair LUKS device header?"),
r = yesDialog(_("Really try to repair LUKS device header?"),
NULL) ? 0 : -EINVAL;
if (r == 0)
r = crypt_repair(cd, CRYPT_LUKS1, NULL);
@@ -567,7 +420,7 @@ static int action_luksFormat(int arg __attribute__((unused)))
r = -ENOMEM;
goto out;
}
r = _yesDialog(msg, NULL) ? 0 : -EINVAL;
r = yesDialog(msg, NULL) ? 0 : -EINVAL;
free(msg);
if (r < 0)
goto out;
@@ -627,7 +480,7 @@ out:
static int action_luksOpen(int arg __attribute__((unused)))
{
struct crypt_device *cd = NULL;
const char *data_device, *header_device;
const char *data_device, *header_device, *activated_name;
char *key = NULL;
uint32_t flags = 0;
int r, keysize;
@@ -640,6 +493,8 @@ static int action_luksOpen(int arg __attribute__((unused)))
data_device = NULL;
}
activated_name = opt_test_passphrase ? NULL : action_argv[1];
if ((r = crypt_init(&cd, header_device)))
goto out;
@@ -674,15 +529,15 @@ static int action_luksOpen(int arg __attribute__((unused)))
r = _read_mk(opt_master_key_file, &key, keysize);
if (r < 0)
goto out;
r = crypt_activate_by_volume_key(cd, action_argv[1],
r = crypt_activate_by_volume_key(cd, activated_name,
key, keysize, flags);
} else if (opt_key_file) {
crypt_set_password_retry(cd, 1);
r = crypt_activate_by_keyfile_offset(cd, action_argv[1],
r = crypt_activate_by_keyfile_offset(cd, activated_name,
opt_key_slot, opt_key_file, opt_keyfile_size,
opt_keyfile_offset, flags);
} else
r = crypt_activate_by_passphrase(cd, action_argv[1],
r = crypt_activate_by_passphrase(cd, activated_name,
opt_key_slot, NULL, 0, flags);
out:
crypt_safe_free(key);
@@ -701,7 +556,7 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
int i, r;
ki = crypt_keyslot_status(cd, key_slot);
if (ki == CRYPT_SLOT_ACTIVE_LAST && msg_last && !_yesDialog(msg_last, NULL))
if (ki == CRYPT_SLOT_ACTIVE_LAST && msg_last && !yesDialog(msg_last, NULL))
return -EPERM;
r = crypt_get_key(msg_pass, &password, &passwordLen,
@@ -728,7 +583,7 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
}
}
if (r < 0)
if (r == -EPERM)
log_err(_("No key available with this passphrase.\n"));
out:
crypt_safe_free(password);
@@ -743,7 +598,7 @@ static int action_luksKillSlot(int arg __attribute__((unused)))
if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
goto out;
crypt_set_confirm_callback(cd, _yesDialog, NULL);
crypt_set_confirm_callback(cd, yesDialog, NULL);
crypt_set_timeout(cd, opt_timeout);
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
@@ -786,7 +641,7 @@ static int action_luksRemoveKey(int arg __attribute__((unused)))
if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
goto out;
crypt_set_confirm_callback(cd, _yesDialog, NULL);
crypt_set_confirm_callback(cd, yesDialog, NULL);
crypt_set_timeout(cd, opt_timeout);
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
@@ -810,7 +665,7 @@ static int action_luksRemoveKey(int arg __attribute__((unused)))
log_verbose(_("Key slot %d selected for deletion.\n"), opt_key_slot);
if (crypt_keyslot_status(cd, opt_key_slot) == CRYPT_SLOT_ACTIVE_LAST &&
!_yesDialog(_("This is the last keyslot. "
!yesDialog(_("This is the last keyslot. "
"Device will become unusable after purging this key."),
NULL)) {
r = -EPERM;
@@ -834,7 +689,7 @@ static int action_luksAddKey(int arg __attribute__((unused)))
if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
goto out;
crypt_set_confirm_callback(cd, _yesDialog, NULL);
crypt_set_confirm_callback(cd, yesDialog, NULL);
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
goto out;
@@ -973,7 +828,7 @@ static int action_isLuks(int arg __attribute__((unused)))
if ((r = crypt_init(&cd, action_argv[0])))
goto out;
crypt_set_log_callback(cd, _quiet_log, NULL);
crypt_set_log_callback(cd, quiet_log, NULL);
r = crypt_load(cd, CRYPT_LUKS1, NULL);
out:
crypt_free(cd);
@@ -989,7 +844,7 @@ static int action_luksUUID(int arg __attribute__((unused)))
if ((r = crypt_init(&cd, action_argv[0])))
goto out;
crypt_set_confirm_callback(cd, _yesDialog, NULL);
crypt_set_confirm_callback(cd, yesDialog, NULL);
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
goto out;
@@ -1014,8 +869,8 @@ static int luksDump_with_volume_key(struct crypt_device *cd)
unsigned i;
int r;
crypt_set_confirm_callback(cd, _yesDialog, NULL);
if (!_yesDialog(
crypt_set_confirm_callback(cd, yesDialog, NULL);
if (!yesDialog(
_("LUKS header dump with volume key is sensitive information\n"
"which allows access to encrypted partition without passphrase.\n"
"This dump should be always stored encrypted on safe place."),
@@ -1128,7 +983,7 @@ static int action_luksBackup(int arg __attribute__((unused)))
if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
goto out;
crypt_set_confirm_callback(cd, _yesDialog, NULL);
crypt_set_confirm_callback(cd, yesDialog, NULL);
r = crypt_header_backup(cd, CRYPT_LUKS1, opt_header_backup_file);
out:
@@ -1149,24 +1004,13 @@ static int action_luksRestore(int arg __attribute__((unused)))
if ((r = crypt_init(&cd, action_argv[0])))
goto out;
crypt_set_confirm_callback(cd, _yesDialog, NULL);
crypt_set_confirm_callback(cd, yesDialog, NULL);
r = crypt_header_restore(cd, CRYPT_LUKS1, opt_header_backup_file);
out:
crypt_free(cd);
return r;
}
static __attribute__ ((noreturn)) void usage(poptContext popt_context,
int exitcode, const char *error,
const char *more)
{
poptPrintUsage(popt_context, stderr, 0);
if (error)
log_err("%s: %s\n", more, error);
poptFreeContext(popt_context);
exit(exitcode);
}
static void help(poptContext popt_context,
enum poptCallbackReason reason __attribute__((unused)),
struct poptOption *key,
@@ -1211,19 +1055,6 @@ static void help(poptContext popt_context,
usage(popt_context, EXIT_SUCCESS, NULL, NULL);
}
static void _dbg_version_and_cmd(int argc, const char **argv)
{
int i;
log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
for (i = 0; i < argc; i++) {
if (i)
log_std(" ");
log_std("%s", argv[i]);
}
log_std("\"\n");
}
static int run_action(struct action_type *action)
{
int r;
@@ -1243,22 +1074,7 @@ static int run_action(struct action_type *action)
r = 0;
show_status(r);
/* Translate exit code to simple codes */
switch (r) {
case 0: r = EXIT_SUCCESS; break;
case -EEXIST:
case -EBUSY: r = 5; break;
case -ENOTBLK:
case -ENODEV: r = 4; break;
case -ENOMEM: r = 3; break;
case -EPERM: r = 2; break;
case -EINVAL:
case -ENOENT:
case -ENOSYS:
default: r = EXIT_FAILURE;
}
return r;
return translate_errno(r);
}
int main(int argc, const char **argv)
@@ -1303,15 +1119,15 @@ int main(int argc, const char **argv)
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("UUID for device to use."), NULL },
{ "allow-discards", '\0', POPT_ARG_NONE, &opt_allow_discards, 0, N_("Allow discards (aka TRIM) requests for device."), NULL },
{ "header", '\0', POPT_ARG_STRING, &opt_header_device, 0, N_("Device or file with separated LUKS header."), NULL },
{ "test-passphrase", '\0', POPT_ARG_NONE, &opt_test_passphrase, 0, N_("Do not activate device, just check passphrase."), NULL },
POPT_TABLEEND
};
poptContext popt_context;
struct action_type *action;
const char *aname;
int r;
const char *null_action_argv[] = {NULL};
crypt_set_log_callback(NULL, _log, NULL);
crypt_set_log_callback(NULL, tool_log, NULL);
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
@@ -1321,7 +1137,7 @@ int main(int argc, const char **argv)
popt_context = poptGetContext(PACKAGE, argc, argv, popt_options, 0);
poptSetOtherOptionHelp(popt_context,
N_("[OPTION...] <action> <action-specific>]"));
_("[OPTION...] <action> <action-specific>"));
while((r = poptGetNextOpt(popt_context)) > 0) {
unsigned long long ull_value;
@@ -1389,30 +1205,33 @@ int main(int argc, const char **argv)
/* FIXME: rewrite this from scratch */
if (opt_shared && strcmp(aname, "create")) {
if (opt_shared && strcmp(aname, "create"))
usage(popt_context, EXIT_FAILURE,
_("Option --shared is allowed only for create operation.\n"),
poptGetInvocationName(popt_context));
}
if (opt_allow_discards &&
strcmp(aname, "luksOpen") &&
strcmp(aname, "create") &&
strcmp(aname, "loopaesOpen")) {
strcmp(aname, "loopaesOpen"))
usage(popt_context, EXIT_FAILURE,
_("Option --allow-discards is allowed only for luksOpen, loopaesOpen and create operation.\n"),
poptGetInvocationName(popt_context));
}
if (opt_key_size &&
strcmp(aname, "luksFormat") &&
strcmp(aname, "create") &&
strcmp(aname, "loopaesOpen")) {
strcmp(aname, "loopaesOpen"))
usage(popt_context, EXIT_FAILURE,
_("Option --key-size is allowed only for luksFormat, create and loopaesOpen.\n"
"To limit read from keyfile use --keyfile-size=(bytes)."),
poptGetInvocationName(popt_context));
}
if (opt_test_passphrase &&
strcmp(aname, "luksOpen"))
usage(popt_context, EXIT_FAILURE,
_("Option --test-passphrase is allowed only for luksOpen.\n"),
poptGetInvocationName(popt_context));
if (opt_key_size % 8)
usage(popt_context, EXIT_FAILURE,
@@ -1436,11 +1255,10 @@ int main(int argc, const char **argv)
}
if (opt_keyfile_size < 0 || opt_new_keyfile_size < 0 || opt_key_size < 0 ||
opt_keyfile_offset < 0 || opt_new_keyfile_offset < 0) {
opt_keyfile_offset < 0 || opt_new_keyfile_offset < 0)
usage(popt_context, EXIT_FAILURE,
_("Negative number for option not permitted."),
poptGetInvocationName(popt_context));
}
if (opt_random && opt_urandom)
usage(popt_context, EXIT_FAILURE, _("Only one of --use-[u]random options is allowed."),
@@ -1471,7 +1289,7 @@ int main(int argc, const char **argv)
if (opt_debug) {
opt_verbose = 1;
crypt_set_debug_level(-1);
_dbg_version_and_cmd(argc, argv);
dbg_version_and_cmd(argc, argv);
}
r = run_action(action);

View File

@@ -22,15 +22,55 @@
#ifndef CRYPTSETUP_H
#define CRYPTSETUP_H
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
#include <config.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <unistd.h>
#include <inttypes.h>
#include <limits.h>
#include <ctype.h>
#include <fcntl.h>
#include <popt.h>
#include <sys/stat.h>
#include "lib/nls.h"
#include "lib/utils_crypt.h"
#include "lib/utils_loop.h"
#include "lib/utils_fips.h"
#define DEFAULT_CIPHER(type) (DEFAULT_##type##_CIPHER "-" DEFAULT_##type##_MODE)
#include "libcryptsetup.h"
#define CONST_CAST(x) (x)(uintptr_t)
#define DEFAULT_CIPHER(type) (DEFAULT_##type##_CIPHER "-" DEFAULT_##type##_MODE)
#define SECTOR_SIZE 512
#define ROUND_SECTOR(x) (((x) + SECTOR_SIZE - 1) / SECTOR_SIZE)
extern int opt_debug;
extern int opt_verbose;
extern int opt_batch_mode;
/* Common tools */
void clogger(struct crypt_device *cd, int level, const char *file, int line,
const char *format, ...);
void tool_log(int level, const char *msg, void *usrptr __attribute__((unused)));
void quiet_log(int level, const char *msg, void *usrptr);
int yesDialog(const char *msg, void *usrptr __attribute__((unused)));
void show_status(int errcode);
const char *uuid_or_device(const char *spec);
void usage(poptContext popt_context, int exitcode, const char *error, const char *more);
void dbg_version_and_cmd(int argc, const char **argv);
int translate_errno(int r);
/* Log */
#define log_dbg(x...) clogger(NULL, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
#define log_std(x...) clogger(NULL, CRYPT_LOG_NORMAL, __FILE__, __LINE__, x)
#define log_verbose(x...) clogger(NULL, CRYPT_LOG_VERBOSE, __FILE__, __LINE__, x)

1264
src/cryptsetup_reencrypt.c Normal file

File diff suppressed because it is too large Load Diff

201
src/utils_tools.c Normal file
View File

@@ -0,0 +1,201 @@
/*
* cryptsetup - setup cryptographic volumes for dm-crypt
*
* Copyright (C) 2004, Christophe Saout <christophe@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2012, 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
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "cryptsetup.h"
int opt_verbose = 0;
int opt_debug = 0;
int opt_batch_mode = 0;
__attribute__((format(printf, 5, 6)))
void clogger(struct crypt_device *cd, int level, const char *file, int line,
const char *format, ...)
{
va_list argp;
char *target = NULL;
va_start(argp, format);
if (vasprintf(&target, format, argp) > 0) {
if (level >= 0) {
crypt_log(cd, level, target);
#ifdef CRYPT_DEBUG
} else if (opt_debug)
printf("# %s:%d %s\n", file ?: "?", line, target);
#else
} else if (opt_debug)
printf("# %s\n", target);
#endif
}
va_end(argp);
free(target);
}
void tool_log(int level, const char *msg, void *usrptr __attribute__((unused)))
{
switch(level) {
case CRYPT_LOG_NORMAL:
fputs(msg, stdout);
break;
case CRYPT_LOG_VERBOSE:
if (opt_verbose)
fputs(msg, stdout);
break;
case CRYPT_LOG_ERROR:
fputs(msg, stderr);
break;
case CRYPT_LOG_DEBUG:
if (opt_debug)
printf("# %s\n", msg);
break;
default:
fprintf(stderr, "Internal error on logging class for msg: %s", msg);
break;
}
}
void quiet_log(int level, const char *msg, void *usrptr)
{
if (!opt_verbose && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
level = CRYPT_LOG_VERBOSE;
tool_log(level, msg, usrptr);
}
int yesDialog(const char *msg, void *usrptr __attribute__((unused)))
{
char *answer = NULL;
size_t size = 0;
int r = 1;
if(isatty(STDIN_FILENO) && !opt_batch_mode) {
log_std("\nWARNING!\n========\n");
log_std("%s\n\nAre you sure? (Type uppercase yes): ", msg);
if(getline(&answer, &size, stdin) == -1) {
perror("getline");
free(answer);
return 0;
}
if(strcmp(answer, "YES\n"))
r = 0;
free(answer);
}
return r;
}
void show_status(int errcode)
{
char error[256], *error_;
if(!opt_verbose)
return;
if(!errcode) {
log_std(_("Command successful.\n"));
return;
}
crypt_get_error(error, sizeof(error));
if (!error[0]) {
error_ = strerror_r(-errcode, error, sizeof(error));
if (error_ != error) {
strncpy(error, error_, sizeof(error));
error[sizeof(error) - 1] = '\0';
}
}
log_err(_("Command failed with code %i"), -errcode);
if (*error)
log_err(": %s\n", error);
else
log_err(".\n");
}
const char *uuid_or_device(const char *spec)
{
static char device[PATH_MAX];
char s, *ptr;
int i = 0, uuid_len = 5;
/* Check if it is correct UUID=<LUKS_UUID> format */
if (spec && !strncmp(spec, "UUID=", uuid_len)) {
strcpy(device, "/dev/disk/by-uuid/");
ptr = &device[strlen(device)];
i = uuid_len;
while ((s = spec[i++]) && i < PATH_MAX) {
if (!isxdigit(s) && s != '-')
return spec; /* Bail it out */
if (isalpha(s))
s = tolower(s);
*ptr++ = s;
}
*ptr = '\0';
return device;
}
return spec;
}
__attribute__ ((noreturn)) void usage(poptContext popt_context,
int exitcode, const char *error,
const char *more)
{
poptPrintUsage(popt_context, stderr, 0);
if (error)
log_err("%s: %s\n", more, error);
poptFreeContext(popt_context);
exit(exitcode);
}
void dbg_version_and_cmd(int argc, const char **argv)
{
int i;
log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
for (i = 0; i < argc; i++) {
if (i)
log_std(" ");
log_std("%s", argv[i]);
}
log_std("\"\n");
}
/* Translate exit code to simple codes */
int translate_errno(int r)
{
switch (r) {
case 0: r = EXIT_SUCCESS; break;
case -EEXIST:
case -EBUSY: r = 5; break;
case -ENOTBLK:
case -ENODEV: r = 4; break;
case -ENOMEM: r = 3; break;
case -EPERM: r = 2; break;
case -EINVAL:
case -ENOENT:
case -ENOSYS:
default: r = EXIT_FAILURE;
}
return r;
}

480
src/veritysetup.c Normal file
View File

@@ -0,0 +1,480 @@
/*
* veritysetup - setup cryptographic volumes for dm-verity
*
* Copyright (C) 2012, 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
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "cryptsetup.h"
#define PACKAGE_VERITY "veritysetup"
static int use_superblock = 1;
static const char *hash_algorithm = NULL;
static int hash_type = 1;
static int data_block_size = DEFAULT_VERITY_DATA_BLOCK;
static int hash_block_size = DEFAULT_VERITY_HASH_BLOCK;
static uint64_t data_blocks = 0;
static const char *salt_string = NULL;
static uint64_t hash_offset = 0;
static const char *opt_uuid = NULL;
static int opt_version_mode = 0;
static const char **action_argv;
static int action_argc;
static int _prepare_format(struct crypt_params_verity *params,
const char *data_device,
uint32_t flags)
{
char *salt = NULL;
int len;
params->hash_name = hash_algorithm ?: DEFAULT_VERITY_HASH;
params->data_device = data_device;
if (salt_string && !strcmp(salt_string, "-")) {
params->salt_size = 0;
params->salt = NULL;
} else if (salt_string) {
len = crypt_hex_to_bytes(salt_string, &salt, 0);
if (len < 0) {
log_err(_("Invalid salt string specified.\n"));
return -EINVAL;
}
params->salt_size = len;
params->salt = salt;
} else {
params->salt_size = DEFAULT_VERITY_SALT_SIZE;
params->salt = NULL;
}
params->data_block_size = data_block_size;
params->hash_block_size = hash_block_size;
params->data_size = data_blocks;
params->hash_area_offset = hash_offset;
params->hash_type = hash_type;
params->flags = flags;
return 0;
}
static int action_format(int arg)
{
struct crypt_device *cd = NULL;
struct crypt_params_verity params = {};
uint32_t flags = CRYPT_VERITY_CREATE_HASH;
struct stat st;
int r;
/* Try to create hash image if doesn't exist */
if (stat(action_argv[1], &st) < 0) {
log_dbg("Creating hash image %s.", action_argv[1]);
r = open(action_argv[1], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (r < 0) {
log_err(_("Cannot create hash image %s for writing.\n"), action_argv[1]);
return -EINVAL;
}
close(r);
}
if ((r = crypt_init(&cd, action_argv[1])))
goto out;
if (!use_superblock)
flags |= CRYPT_VERITY_NO_HEADER;
r = _prepare_format(&params, action_argv[0], flags);
if (r < 0)
goto out;
r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, opt_uuid, NULL, 0, &params);
if (!r)
crypt_dump(cd);
out:
crypt_free(cd);
free(CONST_CAST(char*)params.salt);
return r;
}
static int _activate(const char *dm_device,
const char *data_device,
const char *hash_device,
const char *root_hash,
uint32_t flags)
{
struct crypt_device *cd = NULL;
struct crypt_params_verity params = {};
uint32_t activate_flags = CRYPT_ACTIVATE_READONLY;
char *root_hash_bytes = NULL;
ssize_t hash_size;
int r;
if ((r = crypt_init(&cd, hash_device)))
goto out;
if (use_superblock) {
params.flags = flags;
params.hash_area_offset = hash_offset;
r = crypt_load(cd, CRYPT_VERITY, &params);
} else {
r = _prepare_format(&params, data_device, flags | CRYPT_VERITY_NO_HEADER);
if (r < 0)
goto out;
r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params);
}
if (r < 0)
goto out;
r = crypt_set_data_device(cd, data_device);
if (r < 0)
goto out;
hash_size = crypt_get_volume_key_size(cd);
if (crypt_hex_to_bytes(root_hash, &root_hash_bytes, 0) != hash_size) {
log_err(_("Invalid root hash string specified.\n"));
r = -EINVAL;
goto out;
}
r = crypt_activate_by_volume_key(cd, dm_device,
root_hash_bytes,
hash_size,
activate_flags);
out:
crypt_free(cd);
free(root_hash_bytes);
free(CONST_CAST(char*)params.salt);
return r;
}
static int action_create(int arg)
{
return _activate(action_argv[0],
action_argv[1],
action_argv[2],
action_argv[3], 0);
}
static int action_verify(int arg)
{
return _activate(NULL,
action_argv[0],
action_argv[1],
action_argv[2],
CRYPT_VERITY_CHECK_HASH);
}
static int action_remove(int arg)
{
struct crypt_device *cd = NULL;
int r;
r = crypt_init_by_name(&cd, action_argv[0]);
if (r == 0)
r = crypt_deactivate(cd, action_argv[0]);
crypt_free(cd);
return r;
}
static int action_status(int arg)
{
crypt_status_info ci;
struct crypt_active_device cad;
struct crypt_params_verity vp = {};
struct crypt_device *cd = NULL;
struct stat st;
char *backing_file;
unsigned i, path = 0;
int r = 0;
/* perhaps a path, not a dm device name */
if (strchr(action_argv[0], '/') && !stat(action_argv[0], &st))
path = 1;
ci = crypt_status(NULL, action_argv[0]);
switch (ci) {
case CRYPT_INVALID:
r = -EINVAL;
break;
case CRYPT_INACTIVE:
if (path)
log_std("%s is inactive.\n", action_argv[0]);
else
log_std("%s/%s is inactive.\n", crypt_get_dir(), action_argv[0]);
r = -ENODEV;
break;
case CRYPT_ACTIVE:
case CRYPT_BUSY:
if (path)
log_std("%s is active%s.\n", action_argv[0],
ci == CRYPT_BUSY ? " and is in use" : "");
else
log_std("%s/%s is active%s.\n", crypt_get_dir(), action_argv[0],
ci == CRYPT_BUSY ? " and is in use" : "");
r = crypt_init_by_name_and_header(&cd, action_argv[0], NULL);
if (r < 0 || !crypt_get_type(cd))
goto out;
log_std(" type: %s\n", crypt_get_type(cd));
r = crypt_get_active_device(cd, action_argv[0], &cad);
if (r < 0)
goto out;
log_std(" status: %s\n",
cad.flags & CRYPT_ACTIVATE_CORRUPTED ? "corrupted" : "verified");
r = crypt_get_verity_info(cd, &vp);
if (r < 0)
goto out;
log_std(" hash type: %u\n", vp.hash_type);
log_std(" data block: %u\n", vp.data_block_size);
log_std(" hash block: %u\n", vp.hash_block_size);
log_std(" hash name: %s\n", vp.hash_name);
log_std(" salt: ");
if (vp.salt_size)
for(i = 0; i < vp.salt_size; i++)
log_std("%02hhx", (const char)vp.salt[i]);
else
log_std("-");
log_std("\n");
log_std(" data device: %s\n", vp.data_device);
if (crypt_loop_device(vp.data_device)) {
backing_file = crypt_loop_backing_file(vp.data_device);
log_std(" data loop: %s\n", backing_file);
free(backing_file);
}
log_std(" size: %" PRIu64 " sectors\n", cad.size);
log_std(" mode: %s\n", cad.flags & CRYPT_ACTIVATE_READONLY ?
"readonly" : "read/write");
log_std(" hash device: %s\n", vp.hash_device);
if (crypt_loop_device(vp.hash_device)) {
backing_file = crypt_loop_backing_file(vp.hash_device);
log_std(" hash loop: %s\n", backing_file);
free(backing_file);
}
log_std(" hash offset: %" PRIu64 " sectors\n",
vp.hash_area_offset * vp.hash_block_size / 512);
}
out:
crypt_free(cd);
if (r == -ENOTSUP)
r = 0;
return r;
}
static int action_dump(int arg)
{
struct crypt_device *cd = NULL;
struct crypt_params_verity params = {};
int r;
if ((r = crypt_init(&cd, action_argv[0])))
return r;
params.hash_area_offset = hash_offset;
r = crypt_load(cd, CRYPT_VERITY, &params);
if (!r)
crypt_dump(cd);
crypt_free(cd);
return r;
}
static struct action_type {
const char *type;
int (*handler)(int);
int required_action_argc;
const char *arg_desc;
const char *desc;
} action_types[] = {
{ "format", action_format, 2, N_("<data_device> <hash_device>"),N_("format device") },
{ "verify", action_verify, 3, N_("<data_device> <hash_device> <root_hash>"),N_("verify device") },
{ "create", action_create, 4, N_("<name> <data_device> <hash_device> <root_hash>"),N_("create active device") },
{ "remove", action_remove, 1, N_("<name>"),N_("remove (deactivate) device") },
{ "status", action_status, 1, N_("<name>"),N_("show active device status") },
{ "dump", action_dump, 1, N_("<hash_device>"),N_("show on-disk information") },
{ NULL, NULL, 0, NULL, NULL }
};
static void help(poptContext popt_context,
enum poptCallbackReason reason __attribute__((unused)),
struct poptOption *key,
const char *arg __attribute__((unused)),
void *data __attribute__((unused)))
{
struct action_type *action;
if (key->shortName == '?') {
log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
poptPrintHelp(popt_context, stdout, 0);
log_std(_("\n"
"<action> is one of:\n"));
for(action = action_types; action->type; action++)
log_std("\t%s %s - %s\n", action->type, _(action->arg_desc), _(action->desc));
log_std(_("\n"
"<name> is the device to create under %s\n"
"<data_device> is the data device\n"
"<hash_device> is the device containing verification data\n"
"<root_hash> hash of the root node on <hash_device>\n"),
crypt_get_dir());
log_std(_("\nDefault compiled-in dm-verity parameters:\n"
"\tHash: %s, Data block (bytes): %u, "
"Hash block (bytes): %u, Salt size: %u, Hash format: %u\n"),
DEFAULT_VERITY_HASH, DEFAULT_VERITY_DATA_BLOCK,
DEFAULT_VERITY_HASH_BLOCK, DEFAULT_VERITY_SALT_SIZE,
1);
exit(EXIT_SUCCESS);
} else
usage(popt_context, EXIT_SUCCESS, NULL, NULL);
}
static int run_action(struct action_type *action)
{
int r;
log_dbg("Running command %s.", action->type);
r = action->handler(0);
show_status(r);
return translate_errno(r);
}
int main(int argc, const char **argv)
{
static char *popt_tmp;
static const char *null_action_argv[] = {NULL};
static struct poptOption popt_help_options[] = {
{ NULL, '\0', POPT_ARG_CALLBACK, help, 0, NULL, NULL },
{ "help", '?', POPT_ARG_NONE, NULL, 0, N_("Show this help message"), NULL },
{ "usage", '\0', POPT_ARG_NONE, NULL, 0, N_("Display brief usage"), NULL },
POPT_TABLEEND
};
static struct poptOption popt_options[] = {
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, N_("Help options:"), NULL },
{ "version", '\0', POPT_ARG_NONE, &opt_version_mode, 0, N_("Print package version"), NULL },
{ "verbose", 'v', POPT_ARG_NONE, &opt_verbose, 0, N_("Shows more detailed error messages"), NULL },
{ "debug", '\0', POPT_ARG_NONE, &opt_debug, 0, N_("Show debug messages"), NULL },
{ "no-superblock", 0, POPT_ARG_VAL, &use_superblock, 0, N_("Do not use verity superblock"), NULL },
{ "format", 0, POPT_ARG_INT, &hash_type, 0, N_("Format type (1 - normal, 0 - original Chrome OS)"), N_("number") },
{ "data-block-size", 0, POPT_ARG_INT, &data_block_size, 0, N_("Block size on the data device"), N_("bytes") },
{ "hash-block-size", 0, POPT_ARG_INT, &hash_block_size, 0, N_("Block size on the hash device"), N_("bytes") },
{ "data-blocks", 0, POPT_ARG_STRING, &popt_tmp, 1, N_("The number of blocks in the data file"), N_("blocks") },
{ "hash-offset", 0, POPT_ARG_STRING, &popt_tmp, 2, N_("Starting offset on the hash device"), N_("bytes") },
{ "hash", 'h', POPT_ARG_STRING, &hash_algorithm, 0, N_("Hash algorithm"), N_("string") },
{ "salt", 's', POPT_ARG_STRING, &salt_string, 0, N_("Salt"), N_("hex string") },
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("UUID for device to use."), NULL },
POPT_TABLEEND
};
poptContext popt_context;
struct action_type *action;
const char *aname;
int r;
crypt_set_log_callback(NULL, tool_log, NULL);
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
popt_context = poptGetContext("verity", argc, argv, popt_options, 0);
poptSetOtherOptionHelp(popt_context,
_("[OPTION...] <action> <action-specific>"));
while((r = poptGetNextOpt(popt_context)) > 0) {
unsigned long long ull_value;
char *endp;
errno = 0;
ull_value = strtoull(popt_tmp, &endp, 10);
if (*endp || !*popt_tmp || !isdigit(*popt_tmp) ||
(errno == ERANGE && ull_value == ULLONG_MAX) ||
(errno != 0 && ull_value == 0))
r = POPT_ERROR_BADNUMBER;
switch(r) {
case 1:
data_blocks = ull_value;
break;
case 2:
hash_offset = ull_value;
break;
}
if (r < 0)
break;
}
if (r < -1)
usage(popt_context, EXIT_FAILURE, poptStrerror(r),
poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
if (opt_version_mode) {
log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);
}
if (!(aname = poptGetArg(popt_context)))
usage(popt_context, EXIT_FAILURE, _("Argument <action> missing."),
poptGetInvocationName(popt_context));
for(action = action_types; action->type; action++)
if (strcmp(action->type, aname) == 0)
break;
if (!action->type)
usage(popt_context, EXIT_FAILURE, _("Unknown action."),
poptGetInvocationName(popt_context));
action_argc = 0;
action_argv = poptGetArgs(popt_context);
/* Make return values of poptGetArgs more consistent in case of remaining argc = 0 */
if(!action_argv)
action_argv = null_action_argv;
/* Count args, somewhat unnice, change? */
while(action_argv[action_argc] != NULL)
action_argc++;
if(action_argc < action->required_action_argc) {
char buf[128];
snprintf(buf, 128,_("%s: requires %s as arguments"), action->type, action->arg_desc);
usage(popt_context, EXIT_FAILURE, buf,
poptGetInvocationName(popt_context));
}
if (data_block_size < 0 || hash_block_size < 0 || hash_type < 0) {
usage(popt_context, EXIT_FAILURE,
_("Negative number for option not permitted."),
poptGetInvocationName(popt_context));
}
if (opt_debug) {
opt_verbose = 1;
crypt_set_debug_level(-1);
dbg_version_and_cmd(argc, argv);
}
r = run_action(action);
poptFreeContext(popt_context);
return r;
}

View File

@@ -1,11 +1,22 @@
TESTS = api-test compat-test loopaes-test align-test discards-test mode-test password-hash-test
EXTRA_DIST = compatimage.img.bz2 valid_header_file.bz2 \
if VERITYSETUP
TESTS += verity-compat-test
endif
if REENCRYPT
TESTS += reencryption-compat-test
endif
EXTRA_DIST = compatimage.img.bz2 compatv10image.img.bz2 \
valid_header_file.bz2 \
evil_hdr-payload_overwrite.bz2 \
evil_hdr-stripes_payload_dmg.bz2 \
evil_hdr-luks_hdr_damage.bz2 \
evil_hdr-small_luks_device.bz2 \
compat-test loopaes-test align-test discards-test mode-test password-hash-test \
verity-compat-test \
reencryption-compat-test \
cryptsetup-valg-supps valg.sh valg-api.sh
CLEANFILES = cryptsetup-tst* valglog*

View File

@@ -13,6 +13,7 @@ cleanup() {
fail()
{
echo "FAIL"
[ -n "$1" ] && echo "$1"
cleanup
exit 100
@@ -38,11 +39,10 @@ add_device() {
[ -b $DEV ] || fail "Cannot find $DEV."
}
format() # key_bits expected [forced]
{
if [ -z "$3" ] ; then
echo -n "Formatting using topology info ($1 bits key)...."
echo -n "Formatting using topology info ($1 bits key)..."
echo xxx| $CRYPTSETUP luksFormat $DEV -q -i1 -c aes-cbc-essiv:sha256 -s $1
else
echo -n "Formatting using forced sector alignment $3 ($1 bits key)..."
@@ -52,28 +52,52 @@ format() # key_bits expected [forced]
ALIGN=$($CRYPTSETUP luksDump $DEV |grep "Payload offset" | sed -e s/.*\\t//)
#echo "ALIGN = $ALIGN"
if [ -z "$ALIGN" ] ; then
fail "FAIL"
elif [ $ALIGN -ne $2 ] ; then
echo "FAIL"
fail "Expected alignment differs: expected $2 != detected $ALIGN"
fi
[ -z "$ALIGN" ] && fail
[ $ALIGN -ne $2 ] && fail "Expected alignment differs: expected $2 != detected $ALIGN"
# test some operation, just in case
echo -e "xxx\naaa" | $CRYPTSETUP luksAddKey $DEV -i1 --key-slot 1
if [ $? -ne 0 ] ; then
echo "FAIL"
fail "Keyslot add failed."
fi
[ $? -ne 0 ] && fail "Keyslot add failed."
$CRYPTSETUP -q luksKillSlot $DEV 1
if [ $? -ne 0 ] ; then
echo "FAIL"
fail "Keyslot removal failed."
fi
[ $? -ne 0 ] && fail "Keyslot removal failed."
echo "PASSED"
}
get_offsets()
{
$CRYPTSETUP luksDump $DEV | grep "$1" | cut -s -d ':' -f 2 | sed -e 's/\s//g' -e :a -e N -e 's/\n/:/g' -e 's/\s//g' -e ta
}
format_null()
{
if [ $3 -eq 0 ] ; then
echo -n "Formatting using topology info ($1 bits key) [slot 0"
echo xxx| $CRYPTSETUP luksFormat $DEV -q -i1 -c null -s $1
else
echo -n "Formatting using forced sector alignment $3 ($1 bits key) [slot 0"
echo xxx| $CRYPTSETUP luksFormat $DEV -q -i1 -c null -s $1 --align-payload=$3
fi
POFF=$(get_offsets "Payload offset")
[ -z "$POFF" ] && fail
[ $POFF != $2 ] && fail "Expected data offset differs: expected $2 != detected $POFF"
if [ -n "$4" ] ; then
for j in 1 2 3 4 5 6 7 ; do
echo -e "xxx\nblah$j" | $CRYPTSETUP luksAddKey $DEV -q -i1 --key-slot $j -c null $PARAMS
echo -n $j
[ $? -ne 0 ] && fail
done
KOFF=$(get_offsets "Key material offset")
[ -z "$KOFF" ] && fail
[ $KOFF != $4 ] && fail "Expected keyslots offsets differ: expected $4 != detected $KOFF"
fi
echo "]...PASSED"
}
if [ $(id -u) != 0 ]; then
echo "WARNING: You must be root to run this test, test skipped."
exit 0
@@ -111,7 +135,7 @@ format 128 2048
format 128 1536 8
cleanup
echo "# Create classic 512b drive and stack dm-linear"
echo "# Create classic 512B drive and stack dm-linear"
echo "# (logical_block_size=512, physical_block_size=512, alignment_offset=0)"
add_device dev_size_mb=16 sector_size=512 num_tgts=1
DEV2=$DEV
@@ -123,3 +147,52 @@ format 128 2048
format 128 1088 8
format 128 8192 8192
cleanup
echo "# Offset check: 512B sector drive"
add_device dev_size_mb=16 sector_size=512 num_tgts=1
# |k| expO reqO expected slot offsets
format_null 64 2048 0 8:72:136:200:264:328:392:456
format_null 64 520 1
format_null 64 520 8
format_null 64 640 128
format_null 64 2048 2048
format_null 128 2048 0 8:136:264:392:520:648:776:904
format_null 128 1032 1
format_null 128 1032 8
format_null 128 1152 128
format_null 128 2048 2048
format_null 256 4096 0 8:264:520:776:1032:1288:1544:1800
format_null 256 2056 1
format_null 256 2056 8
format_null 256 2176 128
format_null 256 4096 2048
format_null 512 4096 0 8:512:1016:1520:2024:2528:3032:3536
format_null 512 4040 1
format_null 512 4040 8
format_null 512 4096 128
format_null 512 4096 2048
cleanup
echo "# Offset check: 4096B sector drive"
add_device dev_size_mb=16 sector_size=4096 num_tgts=1
format_null 64 2048 0 8:72:136:200:264:328:392:456
format_null 64 520 1
format_null 64 520 8
format_null 64 640 128
format_null 64 2048 2048
format_null 128 2048 0 8:136:264:392:520:648:776:904
format_null 128 1032 1
format_null 128 1032 8
format_null 128 1152 128
format_null 128 2048 2048
format_null 256 4096 0 8:264:520:776:1032:1288:1544:1800
format_null 256 2056 1
format_null 256 2056 8
format_null 256 2176 128
format_null 256 4096 2048
format_null 512 4096 0 8:512:1016:1520:2024:2528:3032:3536
format_null 512 4040 1
format_null 512 4040 8
format_null 512 4096 128
format_null 512 4096 2048
cleanup

View File

@@ -440,6 +440,8 @@ static int _setup(void)
* volume_key = bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a */
_system(" [ ! -e " VALID_HEADER " ] && bzip2 -dk " VALID_HEADER ".bz2", 1);
_system("modprobe dm-crypt", 0);
_system("modprobe dm-verity", 0);
return 0;
}
@@ -986,7 +988,8 @@ static void AddDeviceLuks(void)
OK_(get_luks_offsets(0, key_size, params.data_alignment, 0, NULL, &r_payload_offset));
OK_(create_dmdevice_over_loop(L_DEVICE_0S, r_payload_offset));
OK_(create_dmdevice_over_loop(L_DEVICE_1S, r_payload_offset + 1));
OK_(create_dmdevice_over_loop(L_DEVICE_WRONG, r_payload_offset - 1));
//OK_(create_dmdevice_over_loop(L_DEVICE_WRONG, r_payload_offset - 1));
OK_(create_dmdevice_over_loop(L_DEVICE_WRONG, 2050 - 1)); //FIXME last keyslot - 1 sector
// 1 sector less than required
OK_(crypt_init(&cd, DMDIR L_DEVICE_WRONG));
@@ -1298,8 +1301,10 @@ static void LuksHeaderLoad(void)
// external header device
OK_(create_dmdevice_over_loop(H_DEVICE, r_header_size));
// prepared header on a device too small to contain header and payload
OK_(create_dmdevice_over_loop(H_DEVICE_WRONG, r_payload_offset - 1));
snprintf(cmd, sizeof(cmd), "dd if=" EVL_HEADER_4 " of=" DMDIR H_DEVICE_WRONG " bs=512 count=%" PRIu64, r_payload_offset - 1);
//OK_(create_dmdevice_over_loop(H_DEVICE_WRONG, r_payload_offset - 1));
OK_(create_dmdevice_over_loop(H_DEVICE_WRONG, 2050 - 1)); //FIXME
//snprintf(cmd, sizeof(cmd), "dd if=" EVL_HEADER_4 " of=" DMDIR H_DEVICE_WRONG " bs=512 count=%" PRIu64, r_payload_offset - 1);
snprintf(cmd, sizeof(cmd), "dd if=" EVL_HEADER_4 " of=" DMDIR H_DEVICE_WRONG " bs=512 count=%" PRIu64, 2050ULL - 1);
OK_(_system(cmd, 1));
// some device
OK_(create_dmdevice_over_loop(L_DEVICE_OK, r_payload_offset + 1000));
@@ -1342,7 +1347,7 @@ static void LuksHeaderLoad(void)
crypt_free(cd);
// damaged header
OK_(_system("dd if=/dev/zero of=" DMDIR L_DEVICE_0S "bs=512 count=8", 1));
OK_(_system("dd if=/dev/zero of=" DMDIR L_DEVICE_OK " bs=512 count=8", 1));
OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
FAIL_(crypt_load(cd, CRYPT_LUKS1, NULL), "Header not found");
crypt_free(cd);
@@ -1572,6 +1577,112 @@ static void HashDevicePlain(void)
crypt_free(cd);
}
static void VerityTest(void)
{
struct crypt_device *cd;
const char *salt_hex = "20c28ffc129c12360ba6ceea2b6cf04e89c2b41cfe6b8439eb53c1897f50df7b";
const char *root_hex = "ab018b003a967fc782effb293b6dccb60b4f40c06bf80d16391acf686d28b5d6";
char salt[256], root_hash[256];
struct crypt_active_device cad;
struct crypt_params_verity params = {
.data_device = DEVICE_EMPTY,
.salt = salt,
.data_size = 0, /* whole device */
.hash_area_offset = 0,
.flags = CRYPT_VERITY_CREATE_HASH,
};
crypt_decode_key(salt, salt_hex, strlen(salt_hex) / 2);
crypt_decode_key(root_hash, root_hex, strlen(root_hex) / 2);
/* Format */
OK_(crypt_init(&cd, DEVICE_2));
/* block size */
params.data_block_size = 333;
FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params),
"Unsupppored block size.");
params.data_block_size = 4096;
params.hash_block_size = 333;
FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params),
"Unsupppored block size.");
params.hash_block_size = 4096;
/* salt size */
params.salt_size = 257;
FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params),
"Too large salt.");
params.salt_size = 32;
/* hash_type */
params.hash_type = 3;
FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params),
"Unsupported hash type.");
params.hash_type = 1;
params.hash_name = "blah";
FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params),
"Unsupported hash name.");
params.hash_name = "sha256";
OK_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params));
crypt_free(cd);
/* Verify */
OK_(crypt_init(&cd, DEVICE_2));
memset(&params, 0, sizeof(params));
params.data_device = DEVICE_EMPTY;
params.flags = CRYPT_VERITY_CHECK_HASH;
OK_(crypt_load(cd, CRYPT_VERITY, &params));
/* check verity params */
EQ_(crypt_get_volume_key_size(cd), 32);
OK_(strcmp(CRYPT_VERITY, crypt_get_type(cd)));
memset(&params, 0, sizeof(params));
OK_(crypt_get_verity_info(cd, &params));
OK_(strcmp("sha256", params.hash_name));
EQ_(strlen(salt_hex) / 2, params.salt_size);
OK_(memcmp(salt, params.salt, params.salt_size));
EQ_(4096, params.data_block_size);
EQ_(4096, params.hash_block_size);
EQ_(1, params.hash_type);
EQ_(crypt_get_volume_key_size(cd), 32);
OK_(crypt_activate_by_volume_key(cd, NULL, root_hash, 32, 0));
OK_(crypt_set_data_device(cd, DEVICE_1));
FAIL_(crypt_activate_by_volume_key(cd, NULL, root_hash, 32, 0), "Data corrupted");;
OK_(crypt_set_data_device(cd, DEVICE_EMPTY));
if (crypt_activate_by_volume_key(cd, CDEVICE_1, root_hash, 32,
CRYPT_ACTIVATE_READONLY) == -ENOTSUP) {
printf("WARNING: kernel dm-verity not supported, skipping test.\n");
crypt_free(cd);
return;
}
OK_(crypt_get_active_device(cd, CDEVICE_1, &cad));
EQ_(CRYPT_ACTIVATE_READONLY, cad.flags);
crypt_free(cd);
OK_(crypt_init_by_name(&cd, CDEVICE_1));
OK_(crypt_deactivate(cd, CDEVICE_1));
/* hash fail */
root_hash[1] = ~root_hash[1];
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, root_hash, 32, CRYPT_ACTIVATE_READONLY));
OK_(crypt_get_active_device(cd, CDEVICE_1, &cad));
EQ_(CRYPT_ACTIVATE_READONLY|CRYPT_ACTIVATE_CORRUPTED, cad.flags);
OK_(crypt_deactivate(cd, CDEVICE_1));
root_hash[1] = ~root_hash[1];
/* data fail */
OK_(crypt_set_data_device(cd, DEVICE_1));
OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, root_hash, 32, CRYPT_ACTIVATE_READONLY));
OK_(crypt_get_active_device(cd, CDEVICE_1, &cad));
EQ_(CRYPT_ACTIVATE_READONLY|CRYPT_ACTIVATE_CORRUPTED, cad.flags);
OK_(crypt_deactivate(cd, CDEVICE_1));
crypt_free(cd);
}
// Check that gcrypt is properly initialised in format
static void NonFIPSAlg(void)
{
@@ -1586,22 +1697,28 @@ static void NonFIPSAlg(void)
OK_(crypt_init(&cd, DEVICE_2));
params.hash = "sha256";
OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, &params));
FAIL_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, &params),
"Already formatted.");
crypt_free(cd);
params.hash = "whirlpool";
OK_(crypt_init(&cd, DEVICE_2));
ret = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, &params);
if (ret < 0) {
printf("WARNING: whirlpool not supported, skipping test.\n");
crypt_free(cd);
return;
}
crypt_free(cd);
params.hash = "md5";
OK_(crypt_init(&cd, DEVICE_2));
FAIL_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, &params),
"MD5 unsupported, too short");
crypt_free(cd);
}
int main (int argc, char *argv[])
int main(int argc, char *argv[])
{
int i;
@@ -1634,8 +1751,8 @@ int main (int argc, char *argv[])
RUN_(UseLuksDevice, "Use pre-formated LUKS device");
RUN_(SuspendDevice, "Suspend/Resume test");
RUN_(UseTempVolumes, "Format and use temporary encrypted device");
RUN_(CallbacksTest, "API callbacks test");
RUN_(VerityTest, "DM verity test");
out:
_cleanup();
return 0;

View File

@@ -10,6 +10,7 @@ DEV_NAME2=dummy2
DEV_NAME3=dummy3
ORIG_IMG=luks-test-orig
IMG=luks-test
IMG10=luks-test-v10
HEADER_IMG=luks-header
KEY1=key1
KEY2=key2
@@ -39,7 +40,7 @@ function remove_mapping()
[ -b /dev/mapper/$DEV_NAME2 ] && dmsetup remove $DEV_NAME2
[ -b /dev/mapper/$DEV_NAME ] && dmsetup remove $DEV_NAME
losetup -d $LOOPDEV >/dev/null 2>&1
rm -f $ORIG_IMG $IMG $KEY1 $KEY2 $KEY5 $KEYE $HEADER_IMG >/dev/null 2>&1
rm -f $ORIG_IMG $IMG $IMG10 $KEY1 $KEY2 $KEY5 $KEYE $HEADER_IMG >/dev/null 2>&1
}
function force_uevent()
@@ -77,12 +78,14 @@ function prepare()
remove_mapping
bzip2 -cd compatimage.img.bz2 > $IMG
losetup $LOOPDEV $IMG
bzip2 -cd compatv10image.img.bz2 > $IMG10
;;
reuse | *)
if [ ! -e $IMG ]; then
bzip2 -cd compatimage.img.bz2 > $IMG
losetup $LOOPDEV $IMG
fi
[ ! -e $IMG10 ] && bzip2 -cd compatv10image.img.bz2 > $IMG10
;;
esac
@@ -143,9 +146,30 @@ echo "compatkey" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME || fail
check_exists
ORG_SHA1=$(sha1sum -b /dev/mapper/$DEV_NAME | cut -f 1 -d' ')
[ "$ORG_SHA1" = 676062b66ebf36669dab705442ea0762dfc091b0 ] || fail
$CRYPTSETUP -q luksClose $DEV_NAME || fail
# Check it can be opened from header backup as well
$CRYPTSETUP luksHeaderBackup $IMG --header-backup-file $HEADER_IMG
echo "compatkey" | $CRYPTSETUP luksOpen $IMG10 $DEV_NAME --header $HEADER_IMG || fail
check_exists
$CRYPTSETUP -q luksClose $DEV_NAME || fail
# Repeat for V1.0 header - not aligned first keyslot
echo "compatkey" | $CRYPTSETUP luksOpen $IMG10 $DEV_NAME || fail
check_exists
ORG_SHA1=$(sha1sum -b /dev/mapper/$DEV_NAME | cut -f 1 -d' ')
[ "$ORG_SHA1" = 51b48c2471a7593ceaf14dc5e66bca86ed05f6cc ] || fail
$CRYPTSETUP -q luksClose $DEV_NAME || fail
rm -f $HEADER_IMG
$CRYPTSETUP luksHeaderBackup $IMG10 --header-backup-file $HEADER_IMG
echo "compatkey" | $CRYPTSETUP luksOpen $IMG10 $DEV_NAME --header $HEADER_IMG || fail
check_exists
$CRYPTSETUP -q luksClose $DEV_NAME || fail
prepare "[2] open - compat image - denial check" new
echo "wrongkey" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail
echo "wrongkey" | $CRYPTSETUP luksOpen $IMG10 $DEV_NAME 2>/dev/null && fail
check
# All headers items and first key material section must change
@@ -158,6 +182,8 @@ echo "key0" | $CRYPTSETUP -i 1000 -h sha512 -c aes-cbc-essiv:sha256 -s 128 luksF
check "$LUKS_HEADER $KEY_SLOT0 $KEY_MATERIAL0"
prepare "[5] open"
echo "key0" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME --test-passphrase || fail
echo "blah" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME --test-passphrase 2>/dev/null && fail
echo "key0" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME || fail
check_exists

Binary file not shown.

Binary file not shown.

View File

@@ -152,7 +152,10 @@ for key_size in $KEY_SIZES ; do
for key in $KEY_FILES ; do
for offset in $DEV_OFFSET ; do
prepare "Open loop-AES $key / AES-$key_size / offset $offset"
$CRYPTSETUP loopaesOpen $LOOPDEV $DEV_NAME -s $key_size --key-file $key $(get_offset_params $offset) || fail
$CRYPTSETUP loopaesOpen $LOOPDEV $DEV_NAME \
-s $key_size --key-file $key $(get_offset_params $offset) \
2>/dev/null
[ $? -ne 0 ] && echo "[SKIPPED]" && continue
check_exists
check_sum $key $key_size $offset
$CRYPTSETUP loopaesClose $DEV_NAME || fail

134
tests/reencryption-compat-test Executable file
View File

@@ -0,0 +1,134 @@
#!/bin/bash
CRYPTSETUP=../src/cryptsetup
REENC=../src/cryptsetup-reencrypt
DEV_NAME=reenc9768
DEV_NAME2=reenc1273
IMG=reenc-data
KEY1=key1
function remove_mapping()
{
[ -b /dev/mapper/$DEV_NAME2 ] && dmsetup remove $DEV_NAME2
[ -b /dev/mapper/$DEV_NAME ] && dmsetup remove $DEV_NAME
[ ! -z "$LOOPDEV1" ] && losetup -d $LOOPDEV1 >/dev/null 2>&1
rm -f $IMG $KEY1 >/dev/null 2>&1
LOOPDEV1=""
}
function fail()
{
[ -n "$1" ] && echo "$1"
echo "FAILED"
remove_mapping
exit 2
}
function skip()
{
[ -n "$1" ] && echo "$1"
exit 0
}
function open_crypt()
{
if [ -n "$1" ] ; then
echo "$1" | $CRYPTSETUP luksOpen $LOOPDEV1 $DEV_NAME || fail
else
$CRYPTSETUP luksOpen -d key1 $LOOPDEV1 $DEV_NAME || fail
fi
}
function wipe_dev() # $1 dev
{
dd if=/dev/zero of=$1 bs=256k >/dev/null 2>&1
}
function wipe() # $1 pass
{
open_crypt $1
wipe_dev /dev/mapper/$DEV_NAME
$CRYPTSETUP luksClose $DEV_NAME || fail
}
function prepare() # $1 dev1_siz
{
remove_mapping
dd if=/dev/zero of=$IMG bs=1k count=$1 >/dev/null 2>&1
LOOPDEV1=$(losetup -f 2>/dev/null)
[ -z "$LOOPDEV1" ] && fail "No free loop device"
losetup $LOOPDEV1 $IMG
if [ ! -e $KEY1 ]; then
dd if=/dev/urandom of=$KEY1 count=1 bs=32 >/dev/null 2>&1
fi
}
function check_hash_dev() # $1 dev, $2 hash
{
HASH=$(sha256sum $1 | cut -d' ' -f 1)
[ $HASH != "$2" ] && fail "HASH differs ($HASH)"
}
function check_hash() # $1 pwd, $2 hash
{
open_crypt $1
check_hash_dev /dev/mapper/$DEV_NAME $2
$CRYPTSETUP remove $DEV_NAME || fail
}
[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped."
[ ! -x "$REENC" ] && skip "Cannot find $REENC, test skipped."
# REENCRYPTION tests
HASH1=b69dae56a14d1a8314ed40664c4033ea0a550eea2673e04df42a66ac6b9faf2c
HASH2=d85ef2a08aeac2812a648deb875485a6e3848fc3d43ce4aa380937f08199f86b
HASH3=e4e5749032a5163c45125eccf3e8598ba5ed840df442c97e1d5ad4ad84359605
echo "[1] Reencryption"
prepare 8192
echo "key0" | $CRYPTSETUP -q luksFormat -s 128 -c aes-cbc-plain -i 1 --align-payload 4096 $LOOPDEV1 || fail
wipe "key0"
check_hash "key0" $HASH1
echo "key0" | $REENC $LOOPDEV1 -q
check_hash "key0" $HASH1
echo "key0" | $REENC $LOOPDEV1 -q -s 256
check_hash "key0" $HASH1
echo "key0" | $REENC $LOOPDEV1 -q -s 256 -c aes-xts-plain64 -h sha256
check_hash "key0" $HASH1
echo "key0" | $REENC $LOOPDEV1 -q --use-directio
check_hash "key0" $HASH1
echo "[2] Reencryption with data shift"
echo "key0" | $CRYPTSETUP -q luksFormat -s 128 -i 1 --align-payload 2048 $LOOPDEV1 || fail
wipe "key0"
echo "key0" | $REENC $LOOPDEV1 -q -s 256 --reduce-device-size 1024S || fail
check_hash "key0" $HASH2
echo "key0" | $REENC $LOOPDEV1 -q -i 1 || fail
check_hash "key0" $HASH2
echo "[3] Reencryption with keyfile"
echo "key0" | $CRYPTSETUP -q luksFormat -d key1 -s 128 -i 1 --align-payload 4096 $LOOPDEV1 || fail
wipe
check_hash "" $HASH1
echo "key0" | $CRYPTSETUP -q luksAddKey -d key1 $LOOPDEV1 || fail
$REENC $LOOPDEV1 -d key1 -S 0 -i 1 -q || fail
check_hash "" $HASH1
# FIXME echo "key0" | $REENC ...
echo "[4] Encryption of not yet encrypted device"
# well, movin' zeroes :-)
OFFSET=2048
SIZE=$(blockdev --getsz $LOOPDEV1)
wipe_dev $LOOPDEV1
dmsetup create $DEV_NAME2 --table "0 $(($SIZE - $OFFSET)) linear $LOOPDEV1 0" || fail
check_hash_dev /dev/mapper/$DEV_NAME2 $HASH3
dmsetup remove $DEV_NAME2 || fail
echo "key0" | $REENC $LOOPDEV1 -s 128 --new --reduce-device-size "$OFFSET"S -q
check_hash "key0" $HASH3
remove_mapping
exit 0

184
tests/verity-compat-test Executable file
View File

@@ -0,0 +1,184 @@
#!/bin/bash
VERITYSETUP=../src/veritysetup
DEV_NAME=verity3273
DEV_OUT="$DEV_NAME.out"
IMG=verity-data
IMG_HASH=verity-hash
function remove_mapping()
{
[ -b /dev/mapper/$DEV_NAME ] && dmsetup remove $DEV_NAME
[ ! -z "$LOOPDEV1" ] && losetup -d $LOOPDEV1 >/dev/null 2>&1
rm -f $IMG $IMG_HASH $DEV_OUT >/dev/null 2>&1
LOOPDEV1=""
LOOPDEV2=""
}
function fail()
{
[ -n "$1" ] && echo "$1"
echo "FAILED"
[ -f $DEV_OUT ] && cat $DEV_OUT
remove_mapping
exit 2
}
function skip()
{
[ -n "$1" ] && echo "$1"
exit 0
}
function prepare() # $1 dev1_siz [$2 dev2_size]
{
remove_mapping
dd if=/dev/zero of=$IMG bs=1k count=$1 >/dev/null 2>&1
LOOPDEV1=$(losetup -f 2>/dev/null)
[ -z "$LOOPDEV1" ] && fail "No free loop device"
losetup $LOOPDEV1 $IMG
[ -z "$2" ] && return
LOOPDEV2=$IMG_HASH
}
function wipe()
{
dd if=/dev/zero of=$LOOPDEV1 bs=256k >/dev/null 2>&1
rm -f $IMG_HASH $DEV_OUT >/dev/null 2>&1
}
function check_exists()
{
[ -b /dev/mapper/$DEV_NAME ] || fail
}
function compare_out() # $1 what, $2 expected
{
OPT=$(grep -v "^#" $DEV_OUT | grep -i "$1" | sed -e s/.*\:\ // )
[ -z "$OPT" ] && fail
[ $OPT != $2 ] && fail "$1 differs ($2)"
}
function check_root_hash() # $1 size, $2 hash, $3 salt, $4 version, $5 hash, [$6 offset]
{
if [ -z "$LOOPDEV2" ] ; then
BLOCKS=$(($6 / $1))
DEV_PARAMS="$LOOPDEV1 $LOOPDEV1 \
--hash-offset $6 \
--data-blocks=$BLOCKS --debug"
else
DEV_PARAMS="$LOOPDEV1 $LOOPDEV2"
fi
for sb in yes no; do
FORMAT_PARAMS="--format=$4 --data-block-size=$1 --hash-block-size=$1 --hash=$5 --salt=$3"
if [ $sb == yes ] ; then
VERIFY_PARAMS=""
else
FORMAT_PAFAMS="$FORMAT_PARAMS --no-superlock"
VERIFY_PARAMS=$FORMAT_PARAMS
fi
for fail in data hash; do
wipe
echo -n "V$4(sb=$sb) $5 block size $1: "
$VERITYSETUP format $DEV_PARAMS $FORMAT_PARAMS >$DEV_OUT || fail
echo -n "[root hash]"
compare_out "root hash" $2
compare_out "salt" "$3"
$VERITYSETUP verify $DEV_PARAMS $VERIFY_PARAMS $2 >>$DEV_OUT 2>&1 || fail
echo -n "[verify]"
$VERITYSETUP create $DEV_NAME $DEV_PARAMS $VERIFY_PARAMS $2 >>$DEV_OUT 2>&1 || fail
check_exists
echo -n "[activate]"
dd if=/dev/mapper/$DEV_NAME of=/dev/null bs=$1 2>/dev/null
dmsetup status $DEV_NAME | grep "verity V" >/dev/null || fail
echo -n "[in-kernel verify]"
$VERITYSETUP remove $DEV_NAME || fail
case $fail in
data)
dd if=/dev/urandom of=$LOOPDEV1 bs=1 seek=3456 count=8 conv=notrunc 2>/dev/null
TXT="data_dev"
;;
hash)
if [ -z "$LOOPDEV2" ] ; then
dd if=/dev/urandom of=$LOOPDEV1 bs=1 seek=$((8193 + $4)) count=8 conv=notrunc 2>/dev/null
else
dd if=/dev/urandom of=$LOOPDEV2 bs=1 seek=8193 count=8 conv=notrunc 2>/dev/null
fi
TXT="hash_dev"
;;
esac
$VERITYSETUP verify $DEV_PARAMS $VERIFY_PARAMS $2 >>$DEV_OUT 2>&1 && \
fail "userspace check for $TXT corruption"
$VERITYSETUP create $DEV_NAME $DEV_PARAMS $VERIFY_PARAMS $2 >>$DEV_OUT 2>&1 || \
fail "activation"
dd if=/dev/mapper/$DEV_NAME of=/dev/null bs=$1 2>/dev/null
dmsetup status $DEV_NAME | grep "verity V" >/dev/null && \
fail "in-kernel check for $TXT corruption"
$VERITYSETUP remove $DEV_NAME || fail "deactivation"
echo "[$TXT corruption]"
done
done
}
function valgrind_setup()
{
which valgrind >/dev/null 2>&1 || fail "Cannot find valgrind."
[ ! -f $CRYPTSETUP_VALGRIND ] && fail "Unable to get location of cryptsetup executable."
#export LD_LIBRARY_PATH="$CRYPTSETUP_LIB_VALGRIND:$LD_LIBRARY_PATH"
}
function valgrind_run()
{
INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${VERITYSETUP} "$@"
}
[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped."
[ ! -x "$VERITYSETUP" ] && skip "Cannot find $VERITYSETUP, test skipped."
[ -n "$VALG" ] && valgrind_setup && VERITYSETUP=valgrind_run
modprobe dm-verity >/dev/null 2>&1
# VERITYSETUP tests
SALT=e48da609055204e89ae53b655ca2216dd983cf3cb829f34f63a297d106d53e2d
echo "Verity tests [separate devices]"
prepare 8192 1024
check_root_hash 512 9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174 $SALT 1 sha256
check_root_hash 1024 54d92778750495d1f80832b486ebd007617d746271511bbf0e295e143da2b3df $SALT 1 sha256
check_root_hash 4096 e522df0f97da4febb882ac40f30b37dc0b444bf6df418929463fa25280f09d5c $SALT 1 sha256
# version 0
check_root_hash 4096 cbbf4ebd004ef65e29b935bb635a39cf754d677f3fa10b0126da725bbdf10f7d $SALT 0 sha256
# no salt
check_root_hash 4096 ef29c902d87350f1da4bfa536e16cebc162a909bf89abe448b81ec500d4fb9bf - 1 sha256
# sha1
check_root_hash 1024 d0e9163ca8844aaa2e88fe5265a8c5d9ee494a99 $SALT 1 sha1
check_root_hash 1024 73509e8e868be6b8ac939817a98a3d35121413b2 dadada 1 sha1
echo "Verity tests [one device offset]"
prepare $((8192 + 1024))
check_root_hash 512 9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174 $SALT 1 sha256 8388608
check_root_hash 1024 54d92778750495d1f80832b486ebd007617d746271511bbf0e295e143da2b3df $SALT 1 sha256 8388608
check_root_hash 4096 e522df0f97da4febb882ac40f30b37dc0b444bf6df418929463fa25280f09d5c $SALT 1 sha256 8388608
# version 0
check_root_hash 4096 cbbf4ebd004ef65e29b935bb635a39cf754d677f3fa10b0126da725bbdf10f7d $SALT 0 sha256 8388608
# no salt
check_root_hash 4096 ef29c902d87350f1da4bfa536e16cebc162a909bf89abe448b81ec500d4fb9bf - 1 sha256 8388608
# sha1
check_root_hash 1024 d0e9163ca8844aaa2e88fe5265a8c5d9ee494a99 $SALT 1 sha1 8388608
check_root_hash 1024 73509e8e868be6b8ac939817a98a3d35121413b2 dadada 1 sha1 8388608
remove_mapping
exit 0