mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-07 08:50:05 +01:00
Compare commits
152 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0d8815dab | ||
|
|
831a0af508 | ||
|
|
488202feee | ||
|
|
193402ad41 | ||
|
|
1b86b7cb4b | ||
|
|
e5dc991ffd | ||
|
|
89e09afdf6 | ||
|
|
bec7fcb14a | ||
|
|
f45d4d0755 | ||
|
|
64558a57e3 | ||
|
|
29e4414c35 | ||
|
|
c2e12440d2 | ||
|
|
1685aa5978 | ||
|
|
6874f564c1 | ||
|
|
4882f70040 | ||
|
|
1aca317c77 | ||
|
|
af2730fe2a | ||
|
|
a6d64d1d44 | ||
|
|
d15dd89bb7 | ||
|
|
961682aa6b | ||
|
|
2f37cfe569 | ||
|
|
5b5c6dccc0 | ||
|
|
d58a5c8cae | ||
|
|
1d5788f779 | ||
|
|
97224b072a | ||
|
|
15442c1747 | ||
|
|
ff9db165eb | ||
|
|
48332d248f | ||
|
|
07815c24cd | ||
|
|
49b018c765 | ||
|
|
65f975655c | ||
|
|
0c1efd1f8a | ||
|
|
bc1cbd8065 | ||
|
|
50a2d89add | ||
|
|
99643a82ae | ||
|
|
fcc35f459c | ||
|
|
a5aa91ed99 | ||
|
|
d83b872c55 | ||
|
|
8ec2651ad7 | ||
|
|
53e269c5f1 | ||
|
|
8b8e206c07 | ||
|
|
e0562f9708 | ||
|
|
6462ee55d3 | ||
|
|
91ba5742c6 | ||
|
|
667e469659 | ||
|
|
37cecb5a5b | ||
|
|
a47ebccf9a | ||
|
|
584d5b8d65 | ||
|
|
8eef5bde4f | ||
|
|
3532be48c7 | ||
|
|
5f7309bfa0 | ||
|
|
fa4a246744 | ||
|
|
321386db88 | ||
|
|
b99b4825a2 | ||
|
|
9b455125e9 | ||
|
|
adcb9bfb7d | ||
|
|
4abfd38169 | ||
|
|
b684fffdaf | ||
|
|
fb3b62ca02 | ||
|
|
c469e458b7 | ||
|
|
be5473f242 | ||
|
|
527c0fe4f9 | ||
|
|
0ec4d4c9cf | ||
|
|
28f860def2 | ||
|
|
42abcc0fac | ||
|
|
a38fcafcff | ||
|
|
c4a533c3d5 | ||
|
|
96f31a2cff | ||
|
|
8f4fb9303f | ||
|
|
336be2da96 | ||
|
|
e129bffce9 | ||
|
|
a9d9a2ad44 | ||
|
|
c0a5293435 | ||
|
|
b9ae00956d | ||
|
|
e37016bf64 | ||
|
|
104c7d6c4f | ||
|
|
b773823a1b | ||
|
|
0894814148 | ||
|
|
cc948df1dd | ||
|
|
35e3660c61 | ||
|
|
28c6901de1 | ||
|
|
dc067454c1 | ||
|
|
32c2bd4222 | ||
|
|
cd4ea1c348 | ||
|
|
8984e47414 | ||
|
|
491e79db4c | ||
|
|
8a1a0547a8 | ||
|
|
9d47892342 | ||
|
|
32cfb1ca25 | ||
|
|
810aef34ca | ||
|
|
b23b3c4dfe | ||
|
|
b9d99a1626 | ||
|
|
496a07ed4c | ||
|
|
fbba97552e | ||
|
|
0cefe2d107 | ||
|
|
768426ad99 | ||
|
|
5a48ff5eb2 | ||
|
|
96c8c7ba56 | ||
|
|
29c2281ab2 | ||
|
|
0d70651c5a | ||
|
|
b1fb2532e0 | ||
|
|
05b695d516 | ||
|
|
44c9b2fc68 | ||
|
|
018205a9a0 | ||
|
|
c333108c61 | ||
|
|
2fcb521c77 | ||
|
|
0dc87d45a8 | ||
|
|
03dc073f2b | ||
|
|
b402f087d7 | ||
|
|
656fbde7d1 | ||
|
|
a89e6c0ca6 | ||
|
|
d380da7a32 | ||
|
|
0de4b65ba6 | ||
|
|
5c7954a0c7 | ||
|
|
62f334cfa5 | ||
|
|
6d2c15ea79 | ||
|
|
4b8f91d0d9 | ||
|
|
c364290be9 | ||
|
|
a14aab5df7 | ||
|
|
47c5b5ed06 | ||
|
|
0eae181092 | ||
|
|
1cbc53e8ee | ||
|
|
7535fdb31b | ||
|
|
de9393879e | ||
|
|
db51a343de | ||
|
|
e2375c8368 | ||
|
|
697c6c9324 | ||
|
|
6d07be898d | ||
|
|
ade21e6c60 | ||
|
|
fcf5b414d6 | ||
|
|
92d1bebdac | ||
|
|
39a5408e98 | ||
|
|
937f969cc4 | ||
|
|
f4101d0f8b | ||
|
|
ce2218ed65 | ||
|
|
cdae1b4c60 | ||
|
|
c4b16923bb | ||
|
|
b016e65daa | ||
|
|
c35839afbc | ||
|
|
cd8826618d | ||
|
|
ab0f7346bc | ||
|
|
9fb8b816c5 | ||
|
|
0e79728f86 | ||
|
|
4b0b82adc5 | ||
|
|
850799802b | ||
|
|
ed1b59fd25 | ||
|
|
fa98297547 | ||
|
|
9ae7e122ac | ||
|
|
624157ef7b | ||
|
|
5c49268c47 | ||
|
|
7df1d83ebb | ||
|
|
555d5f6e97 |
44
ChangeLog
44
ChangeLog
@@ -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
332
FAQ
@@ -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
6
TODO
@@ -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
|
||||
|
||||
31
configure.in
31
configure.in
@@ -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
|
||||
|
||||
@@ -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
241
docs/v1.5.0-ReleaseNotes
Normal 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
32
docs/v1.5.1-ReleaseNotes
Normal 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.
|
||||
@@ -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
83
lib/bitops.h
Normal 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 */
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
@@ -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"));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
839
lib/setup.c
839
lib/setup.c
File diff suppressed because it is too large
Load Diff
302
lib/utils.c
302
lib/utils.c
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
429
lib/utils_device.c
Normal 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;
|
||||
}
|
||||
@@ -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};
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
16
lib/verity/Makefile.am
Normal 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
283
lib/verity/verity.c
Normal 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
64
lib/verity/verity.h
Normal 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
431
lib/verity/verity_hash.c
Normal 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);
|
||||
}
|
||||
@@ -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
210
man/cryptsetup-reencrypt.8
Normal 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
|
||||
@@ -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
141
man/veritysetup.8
Normal 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
17
misc/dict_search/Makefile
Normal 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
17
misc/dict_search/README
Normal 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.)
|
||||
130
misc/dict_search/luks_dict.c
Normal file
130
misc/dict_search/luks_dict.c
Normal 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);
|
||||
}
|
||||
23
misc/dracut_90reencrypt/README
Normal file
23
misc/dracut_90reencrypt/README
Normal 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.
|
||||
5
misc/dracut_90reencrypt/check.old
Executable file
5
misc/dracut_90reencrypt/check.old
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
which cryptsetup-reencrypt >/dev/null 2>&1 || exit 1
|
||||
|
||||
exit 0
|
||||
6
misc/dracut_90reencrypt/install.old
Executable file
6
misc/dracut_90reencrypt/install.old
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
inst cryptsetup-reencrypt
|
||||
|
||||
inst_hook cmdline 30 "$moddir/parse-reencrypt.sh"
|
||||
inst "$moddir"/reencrypt.sh /sbin/reencrypt
|
||||
22
misc/dracut_90reencrypt/module-setup.sh
Executable file
22
misc/dracut_90reencrypt/module-setup.sh
Executable 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
|
||||
}
|
||||
22
misc/dracut_90reencrypt/parse-reencrypt.sh
Executable file
22
misc/dracut_90reencrypt/parse-reencrypt.sh
Executable 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
|
||||
58
misc/dracut_90reencrypt/reencrypt.sh
Executable file
58
misc/dracut_90reencrypt/reencrypt.sh
Executable 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
|
||||
14
misc/keyslot_checker/Makefile
Normal file
14
misc/keyslot_checker/Makefile
Normal 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
118
misc/keyslot_checker/README
Normal 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.
|
||||
370
misc/keyslot_checker/chk_luks_keyslots.c
Normal file
370
misc/keyslot_checker/chk_luks_keyslots.c
Normal 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;
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
264
src/cryptsetup.c
264
src/cryptsetup.c
@@ -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);
|
||||
|
||||
@@ -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
1264
src/cryptsetup_reencrypt.c
Normal file
File diff suppressed because it is too large
Load Diff
201
src/utils_tools.c
Normal file
201
src/utils_tools.c
Normal 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
480
src/veritysetup.c
Normal 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(¶ms, action_argv[0], flags);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, opt_uuid, NULL, 0, ¶ms);
|
||||
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, ¶ms);
|
||||
} else {
|
||||
r = _prepare_format(¶ms, data_device, flags | CRYPT_VERITY_NO_HEADER);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms);
|
||||
}
|
||||
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, ¶ms);
|
||||
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;
|
||||
}
|
||||
@@ -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*
|
||||
|
||||
107
tests/align-test
107
tests/align-test
@@ -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
|
||||
|
||||
129
tests/api-test.c
129
tests/api-test.c
@@ -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, ¶ms),
|
||||
"Unsupppored block size.");
|
||||
params.data_block_size = 4096;
|
||||
params.hash_block_size = 333;
|
||||
FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms),
|
||||
"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, ¶ms),
|
||||
"Too large salt.");
|
||||
params.salt_size = 32;
|
||||
|
||||
/* hash_type */
|
||||
params.hash_type = 3;
|
||||
FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms),
|
||||
"Unsupported hash type.");
|
||||
params.hash_type = 1;
|
||||
params.hash_name = "blah";
|
||||
FAIL_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms),
|
||||
"Unsupported hash name.");
|
||||
params.hash_name = "sha256";
|
||||
|
||||
OK_(crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms));
|
||||
crypt_free(cd);
|
||||
|
||||
/* Verify */
|
||||
OK_(crypt_init(&cd, DEVICE_2));
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.data_device = DEVICE_EMPTY;
|
||||
params.flags = CRYPT_VERITY_CHECK_HASH;
|
||||
OK_(crypt_load(cd, CRYPT_VERITY, ¶ms));
|
||||
|
||||
/* check verity params */
|
||||
EQ_(crypt_get_volume_key_size(cd), 32);
|
||||
OK_(strcmp(CRYPT_VERITY, crypt_get_type(cd)));
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
OK_(crypt_get_verity_info(cd, ¶ms));
|
||||
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, ¶ms));
|
||||
FAIL_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms),
|
||||
"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, ¶ms);
|
||||
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, ¶ms),
|
||||
"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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
BIN
tests/compatv10image.img.bz2
Normal file
BIN
tests/compatv10image.img.bz2
Normal file
Binary file not shown.
Binary file not shown.
@@ -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
134
tests/reencryption-compat-test
Executable 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
184
tests/verity-compat-test
Executable 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
|
||||
Reference in New Issue
Block a user