mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-08 17:30:03 +01:00
Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66fa12a521 | ||
|
|
c490ef638b | ||
|
|
f5d777e412 | ||
|
|
28eddd2f52 | ||
|
|
eb4720819e | ||
|
|
088a927c07 | ||
|
|
3c3e9570c4 | ||
|
|
b6e046835e | ||
|
|
158a5de3b4 | ||
|
|
02e36d7606 | ||
|
|
38ff882096 | ||
|
|
58a27a18ca | ||
|
|
94fb0b7781 | ||
|
|
c401fe3d04 | ||
|
|
3b10bf9558 | ||
|
|
d6016b1c2d | ||
|
|
9908cd4746 | ||
|
|
a24a594d1a | ||
|
|
56e73526ad | ||
|
|
e640f5e006 | ||
|
|
cb7fa0b9c7 | ||
|
|
60d59b0bc0 | ||
|
|
4f33a537ae | ||
|
|
96bddb363f | ||
|
|
dac000e1df | ||
|
|
be246c16ab | ||
|
|
cc3b39980b | ||
|
|
8c54d938ac | ||
|
|
d7960b9307 | ||
|
|
4e9fa4d2bb | ||
|
|
7a773f70f3 | ||
|
|
b72473eddf | ||
|
|
4d1b67eeb2 | ||
|
|
f54c7939f0 | ||
|
|
19bde65f5b | ||
|
|
d2fbc963ca | ||
|
|
61bec51be0 | ||
|
|
84ada5ddf6 | ||
|
|
7158c32b96 | ||
|
|
1a8bae8884 | ||
|
|
538169fb5b | ||
|
|
963ee0e6ee | ||
|
|
d20e2ff02d | ||
|
|
d5e48fcb00 | ||
|
|
4d99773009 | ||
|
|
f3ed801e8b | ||
|
|
1954792876 | ||
|
|
95009fff4b | ||
|
|
b8a7125225 | ||
|
|
6cede067a2 | ||
|
|
906c7897e1 | ||
|
|
c5b64b5479 | ||
|
|
4a295781d1 | ||
|
|
1f9efdf59a | ||
|
|
1f776bc979 | ||
|
|
104130c4c4 | ||
|
|
51d74c6029 | ||
|
|
7fe10e3d7b | ||
|
|
25c3271cd0 | ||
|
|
7665f8e805 | ||
|
|
6361e86daf | ||
|
|
3c5481709b | ||
|
|
c30fe505c5 | ||
|
|
a9ce2210bc | ||
|
|
e5244bc47c | ||
|
|
23e144daf4 | ||
|
|
03a8ba4d17 | ||
|
|
f80b506b65 | ||
|
|
f7f9e291f4 | ||
|
|
1bf26b9a90 | ||
|
|
261d0d05a5 | ||
|
|
9c71c74d59 | ||
|
|
39e6cfcb8a | ||
|
|
913ef7c07e | ||
|
|
69bd90055f | ||
|
|
7d496a6b69 | ||
|
|
642a838343 | ||
|
|
a1306ed01c | ||
|
|
790ef04304 | ||
|
|
d44d07c9eb | ||
|
|
5b8fb6f135 | ||
|
|
84079a1a49 | ||
|
|
1b7c97c333 | ||
|
|
96d67485d9 | ||
|
|
a5757c35f0 | ||
|
|
3f49ffd526 | ||
|
|
dfd018235b |
59
ChangeLog
59
ChangeLog
@@ -1,3 +1,54 @@
|
||||
2011-10-25 Milan Broz <mbroz@redhat.com>
|
||||
* Print informative message in isLuks only in verbose mode.
|
||||
* Version 1.4.0.
|
||||
|
||||
2011-10-10 Milan Broz <mbroz@redhat.com>
|
||||
* Version 1.4.0-rc1.
|
||||
|
||||
2011-10-05 Milan Broz <mbroz@redhat.com>
|
||||
* Support Nettle 2.4 crypto backend (for ripemd160).
|
||||
* If device is not rotational, do not use Gutmann wipe method.
|
||||
* Add crypt_last_error() API call.
|
||||
* Fix luksKillSLot exit code if slot is inactive or invalid.
|
||||
* Fix exit code if passphrases do not match in luksAddKey.
|
||||
* Add LUKS on-disk format description into package.
|
||||
|
||||
2011-09-22 Milan Broz <mbroz@redhat.com>
|
||||
* Support key-slot option for luksOpen (use only explicit keyslot).
|
||||
|
||||
2011-08-22 Milan Broz <mbroz@redhat.com>
|
||||
* Add more paranoid checks for LUKS header and keyslot attributes.
|
||||
* Fix crypt_load to properly check device size.
|
||||
* Use new /dev/loop-control (kernel 3.1) if possible.
|
||||
* Enhance check of device size before writing LUKS header.
|
||||
* Do not allow context format of already formatted device.
|
||||
|
||||
2011-07-25 Milan Broz <mbroz@redhat.com>
|
||||
* Remove hash/hmac restart from crypto backend and make it part of hash/hmac final.
|
||||
* Improve check for invalid offset and size values.
|
||||
|
||||
2011-07-19 Milan Broz <mbroz@redhat.com>
|
||||
* Revert default initialisation of volume key in crypt_init_by_name().
|
||||
* Do not allow key retrieval while suspended (key could be wiped).
|
||||
* Do not allow suspend for non-LUKS devices.
|
||||
* Support retries and timeout parameters for luksSuspend.
|
||||
* Add --header option for detached metadata (on-disk LUKS header) device.
|
||||
* Add crypt_init_by_name_and_header() and crypt_set_data_device() to API.
|
||||
* Allow different data offset setting for detached header.
|
||||
|
||||
2011-07-07 Milan Broz <mbroz@redhat.com>
|
||||
* Remove old API functions (all functions using crypt_options).
|
||||
* Add --enable-discards option to allow discards/TRIM requests.
|
||||
* Add crypt_get_iv_offset() function to API.
|
||||
|
||||
2011-07-01 Milan Broz <mbroz@redhat.com>
|
||||
* Add --shared option for creating non-overlapping crypt segments.
|
||||
* Add shared flag to libcryptsetup api.
|
||||
* Fix plain crypt format parameters to include size option (API change).
|
||||
|
||||
2011-06-08 Milan Broz <mbroz@redhat.com>
|
||||
* Fix return code for status command when device doesn't exists.
|
||||
|
||||
2011-05-24 Milan Broz <mbroz@redhat.com>
|
||||
* Version 1.3.1.
|
||||
|
||||
@@ -363,7 +414,7 @@
|
||||
* configure.in (AC_OUTPUT): Add m4/Makefile.
|
||||
(AM_GNU_GETTEXT_VERSION): Bump to 0.15.
|
||||
|
||||
2006-10-22 David H<EFBFBD>rdeman <david@hardeman.nu>
|
||||
2006-10-22 David Härdeman <david@hardeman.nu>
|
||||
|
||||
* Allow hashing of keys passed through stdin.
|
||||
|
||||
@@ -430,7 +481,7 @@
|
||||
|
||||
2006-08-04 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
|
||||
* lib/setup.c (get_key): Applied patch from David H<EFBFBD>rdeman
|
||||
* lib/setup.c (get_key): Applied patch from David Härdeman
|
||||
<david@2gen.com> for reading binary keys from stdin using
|
||||
the "-" as key file.
|
||||
|
||||
@@ -447,7 +498,7 @@
|
||||
|
||||
2006-07-23 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
|
||||
* Applied patches from David H<EFBFBD>rdeman <david@2gen.com> to fix 64
|
||||
* Applied patches from David Härdeman <david@2gen.com> to fix 64
|
||||
bit compiler warning issues.
|
||||
|
||||
2006-05-19 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
@@ -466,7 +517,7 @@
|
||||
|
||||
* configure.in: Release 1.0.3.
|
||||
|
||||
* Applied patch by Johannes Wei<EFBFBD>l for more meaningful exit codes
|
||||
* Applied patch by Johannes Weißl for more meaningful exit codes
|
||||
and password retries
|
||||
|
||||
2006-03-30 Clemens Fruhwirth <clemens@endorphin.org>
|
||||
|
||||
479
FAQ
479
FAQ
@@ -6,7 +6,8 @@ Sections
|
||||
4. Troubleshooting
|
||||
5. Security Aspects
|
||||
6. Backup and Data Recovery
|
||||
7. Issues with Specific Versions of cryptsetup
|
||||
7. Interoperability with other Disk Encryption Tools
|
||||
8. Issues with Specific Versions of cryptsetup
|
||||
A. Contributors
|
||||
|
||||
|
||||
@@ -17,11 +18,15 @@ A. Contributors
|
||||
|
||||
This is the FAQ (Frequently Asked Questions) for cryptsetup. It
|
||||
covers Linux disk encryption with plain dm-crypt (one passphrase,
|
||||
no management, no descriptor on disk) and LUKS (multiple user keys
|
||||
with one master key, anti-forensics, descriptor block at start of
|
||||
device, ...). The latest version should usually be available at
|
||||
no management, no metadata on disk) and LUKS (multiple user keys
|
||||
with one master key, anti-forensic features, metadata block at
|
||||
start of device, ...). The latest version of this FAQ should
|
||||
usually be available at
|
||||
http://code.google.com/p/cryptsetup/wiki/FrequentlyAskedQuestions
|
||||
|
||||
|
||||
* WARNINGS
|
||||
|
||||
ATTENTION: If you are going to read just one thing, make it the
|
||||
section on Backup and Data Recovery. By far the most questions on
|
||||
the cryptsetup mailing list are from people that just managed to
|
||||
@@ -31,6 +36,28 @@ A. Contributors
|
||||
limitations imposed by the LUKS security model BEFORE you face such
|
||||
a disaster!
|
||||
|
||||
PASSPHRASES: Some people have had difficulties when upgrading
|
||||
distributions. It is highly advisable to only use the 94 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 http://en.wikipedia.org/wiki/ASCII
|
||||
|
||||
|
||||
* 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
|
||||
to activate their existing LUKS partition. The installer gives no
|
||||
or an inadequate warning and will destroy your old LUKS header,
|
||||
causing permanent data loss. See also the section on Backup and
|
||||
Data Recovery.
|
||||
|
||||
This issue has been acknowledged by the Ubuntu dev team, see here:
|
||||
http://launchpad.net/bugs/420080
|
||||
|
||||
|
||||
* Who wrote this?
|
||||
|
||||
@@ -38,8 +65,9 @@ A. Contributors
|
||||
contributors are listed at the end. If you want to contribute, send
|
||||
your article, including a descriptive headline, to the maintainer,
|
||||
or the dm-crypt mailing list with something like "FAQ ..." in the
|
||||
subject. Please note that by contributing to this FAQ, you accept
|
||||
the license described below.
|
||||
subject. You can also send more raw information and have me write
|
||||
the section. Please note that by contributing to this FAQ, you
|
||||
accept the license described below.
|
||||
|
||||
This work is under the "Attribution-Share Alike 3.0 Unported"
|
||||
license, which means distribution is unlimited, you may create
|
||||
@@ -150,8 +178,9 @@ A. Contributors
|
||||
|
||||
* How do I use LUKS with a loop-device?
|
||||
|
||||
Just the same as with any block device. If you want, for example,
|
||||
to use a 100MiB file as LUKS container, do something like this:
|
||||
This can be very handy for experiments. Setup is just the same as
|
||||
with any block device. If you want, for example, to use a 100MiB
|
||||
file as LUKS container, do something like this:
|
||||
|
||||
head -c 100M /dev/zero > luksfile # create empty file
|
||||
losetup /dev/loop0 luksfile # map luksfile to /dev/loop0
|
||||
@@ -173,6 +202,16 @@ A. Contributors
|
||||
new key-slot.
|
||||
|
||||
|
||||
* Encrytion 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 .
|
||||
|
||||
|
||||
* How do I read a dm-crypt key from file?
|
||||
|
||||
Note that the file will still be hashed first, just like keyboard
|
||||
@@ -344,10 +383,14 @@ A. Contributors
|
||||
However, this operation will not change volume key iteration count
|
||||
(MK iterations in output of "cryptsetup luksDump"). In order to
|
||||
change that, you will have to backup the data in the LUKS
|
||||
container, luksFormat on the slow machine and restore the data.
|
||||
Note that in the original LUKS specification this value was fixed
|
||||
to 10, but it is now derived from the PBKDF2 benchmark as well and
|
||||
set to iterations in 0.125 sec or 1000, whichever is larger.
|
||||
container (i.e. your encrypted data), luksFormat on the slow
|
||||
machine and restore the data. Note that in the original LUKS
|
||||
specification this value was fixed to 10, but it is now derived
|
||||
from the PBKDF2 benchmark as well and set to iterations in 0.125
|
||||
sec or 1000, whichever is larger. Also note that MK iterations
|
||||
are not very security relevant. But as each key-slot already takes
|
||||
1 second, spending the additional 0.125 seconds really does not
|
||||
matter.
|
||||
|
||||
|
||||
* "blkid" sees a LUKS UUID and an ext2/swap UUID on the same device.
|
||||
@@ -409,12 +452,13 @@ A. Contributors
|
||||
ciphers. With the usual modes in cryptsetup (CBC, ESSIV, XTS), you
|
||||
get up to a completely changed 512 byte block per bit error. A
|
||||
corrupt block causes a lot more havoc than the occasionally
|
||||
flipped single bit and can result various obscure errors.
|
||||
flipped single bit and can result in various obscure errors.
|
||||
|
||||
Note however that a verify run on copying between encrypted or
|
||||
unencrypted devices can also show you corruption when the copying
|
||||
itself did not report any problems. If you find defect RAM, assume
|
||||
all backups and copied data to be suspect, unless you did a verify.
|
||||
Note, that a verify run on copying between encrypted or
|
||||
unencrypted devices will reliably detect corruption, even when the
|
||||
copying itself did not report any problems. If you find defect
|
||||
RAM, assume all backups and copied data to be suspect, unless you
|
||||
did a verify.
|
||||
|
||||
|
||||
* How do I test RAM?
|
||||
@@ -455,6 +499,31 @@ A. Contributors
|
||||
5. Security Aspects
|
||||
|
||||
|
||||
* Is LUKS insecure? Everybody can see I have encrypted data!
|
||||
|
||||
In practice it does not really matter. In most civilized countries
|
||||
you can just refuse to hand over the keys, no harm done. In some
|
||||
countries they can force you to hand over the keys, if they suspect
|
||||
encryption. However the suspicion is enough, they do not have to
|
||||
prove anything. This is for practical reasons, as even the presence
|
||||
of a header (like the LUKS header) is not enough to prove that you
|
||||
have any keys. It might have been an experiment, for example. Or it
|
||||
was used as encrypted swap with a key from /dev/random. So they
|
||||
make you prove you do not have encrypted data. Of course that is
|
||||
just as impossible as the other way round.
|
||||
|
||||
This means that if you have a large set of random-looking data,
|
||||
they can already lock you up. Hidden containers (encryption hidden
|
||||
within encryption), as possible with Truecrypt, do not help
|
||||
either. They will just assume the hidden container is there and
|
||||
unless you hand over the key, you will stay locked up. Don't have
|
||||
a hidden container? Though luck. Anybody could claim that.
|
||||
|
||||
Still, if you are concerned about the LUKS header, use plain
|
||||
dm-crypt with a good passphrase. See also Section 2, "What is the
|
||||
difference between "plain" and LUKS format?"
|
||||
|
||||
|
||||
* Should I initialize (overwrite) a new LUKS/dm-crypt partition?
|
||||
|
||||
If you just create a filesystem on it, most of the old data will
|
||||
@@ -561,8 +630,8 @@ A. Contributors
|
||||
to the last stage ("Acceptance") and think about what to do now.
|
||||
There is one exception that I know of: If your LUKS container is
|
||||
still open, then it may be possible to extract the master key from
|
||||
the running system. Ask on the mailing-list on how to do that and
|
||||
make sure nobody switches off the machine.
|
||||
the running system. See Item "How do I recover the master key from
|
||||
a mapped LUKS container?" in Section "Backup and Data Recovery".
|
||||
|
||||
|
||||
* What is a "salt"?
|
||||
@@ -595,6 +664,11 @@ A. Contributors
|
||||
|
||||
* Is LUKS secure with a low-entropy (bad) passphrase?
|
||||
|
||||
Note: You should only use the 94 printable characters from 7 bit
|
||||
ASCII code to prevent your passphrase from failing when the
|
||||
character encoding changes, e.g. because of a system upgrade, see
|
||||
also the note at the very start of this FAQ under "WARNINGS".
|
||||
|
||||
This needs a bit of theory. The quality of your passphrase is
|
||||
directly related to its entropy (information theoretic, not
|
||||
thermodynamic). The entropy says how many bits of "uncertainty" or
|
||||
@@ -629,7 +703,7 @@ A. Contributors
|
||||
days on a single CPU and is entirely feasible. To put that into
|
||||
perspective, using a number of Amazon EC2 High-CPU Extra Large
|
||||
instances (each gives about 8 real cores), this tests costs
|
||||
currently about $48, but can be made to run arbitrarily fast.
|
||||
currently about 50USD/EUR, but can be made to run arbitrarily fast.
|
||||
|
||||
On the other hand, choosing 1.5 lines from, say, the Wheel of Time
|
||||
is in itself not more secure, but the book selection adds quite a
|
||||
@@ -661,7 +735,7 @@ A. Contributors
|
||||
0.0001 seconds on a modern CPU.
|
||||
|
||||
Example 2: The user did a bit better and has 32 chars of English
|
||||
text. That would give use about 32 bits of entropy. With 1 second
|
||||
text. That would be about 32 bits of entropy. With 1 second
|
||||
iteration, that means an attacker on the same CPU needs around 136
|
||||
years. That is pretty impressive for such a weak passphrase.
|
||||
Without the iterations, it would be more like 50 days on a modern
|
||||
@@ -703,6 +777,13 @@ A. Contributors
|
||||
this danger significantly.
|
||||
|
||||
|
||||
* What about iteration count with plain dm-crypt?
|
||||
|
||||
Simple: There is none. There is also no salting. If you use plain
|
||||
dm-crypt, the only way to be secure is to use a high entropy
|
||||
passphrase. If in doubt, use LUKS instead.
|
||||
|
||||
|
||||
* Is LUKS with default parameters less secure on a slow CPU?
|
||||
|
||||
Unfortunately, yes. However the only aspect affected is the
|
||||
@@ -793,28 +874,138 @@ A. Contributors
|
||||
6. Backup and Data Recovery
|
||||
|
||||
|
||||
* Why do I need Backup?
|
||||
|
||||
First, disks die. The rate for well-treated (!) disk is about 5%
|
||||
per year, which is high enough to worry about. There is some
|
||||
indication that this may be even worse for some SSDs. This applies
|
||||
both to LUKS and plain dm-crypt partitions.
|
||||
|
||||
Second, for LUKS, if anything damages the LUKS header or the
|
||||
key-stripe area then decrypting the LUKS device can become
|
||||
impossible. This is a frequent occuurence. 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
|
||||
header damage.
|
||||
|
||||
So, data-backup in some form is non-optional. For LUKS, you may
|
||||
also want to store a header backup in some secure location. This
|
||||
only needs an update if you change passphrases.
|
||||
|
||||
|
||||
* How do I backup a LUKS header?
|
||||
|
||||
While you could just copy the appropriate number of bytes from the
|
||||
start of the LUKS partition, the best way is to use command option
|
||||
"luksHeaderBackup" of cryptsetup. This protects also against
|
||||
errors when non-standard parameters have been used in LUKS
|
||||
partition creation. Example:
|
||||
|
||||
|
||||
cryptsetup luksHeaderBackup --header-backup-file h /dev/mapper/c1
|
||||
|
||||
To restore, use the inverse command, i.e.
|
||||
|
||||
cryptsetup luksHeaderRestore --header-backup-file h /dev/mapper/c1
|
||||
|
||||
|
||||
* How do I backup a LUKS or dm-crypt partition?
|
||||
|
||||
There are two options, a sector-image and a plain file or
|
||||
filesystem backup of the contents of the partition. The sector
|
||||
image is already encrypted, but cannot be compressed and contains
|
||||
all empty space. The filesystem backup can be compressed, can
|
||||
contain only part of the encrypted device, but needs to be
|
||||
encrypted separately if so desired.
|
||||
|
||||
A sector-image will contain the whole partition in encrypted form,
|
||||
for LUKS the LUKS header, the keys-slots and the data area. It can
|
||||
be done under Linux e.g. with dd_rescue (for a direct image copy)
|
||||
and with "cat" or "dd". Example:
|
||||
|
||||
cat /dev/sda10 > sda10.img
|
||||
dd_rescue /dev/sda10 sda10.img
|
||||
|
||||
You can also use any other backup software that is capable of making
|
||||
a sector image of a partition. Note that compression is
|
||||
ineffective for encrypted data, hence it does not make sense to
|
||||
use it.
|
||||
|
||||
For a filesystem backup, you decrypt and mount the encrypted
|
||||
partition and back it up as you would a normal filesystem. In this
|
||||
case the backup is not encrypted, unless your encryption method
|
||||
does that. For example you can encrypt a backup with "tar" as
|
||||
follows with GnuPG:
|
||||
|
||||
tar cjf - <path> | gpg --cipher-algo AES -c - > backup.tbz2.gpg
|
||||
|
||||
And verify the backup like this if you are at "path":
|
||||
|
||||
cat backup.tbz2.gpg | gpg - | tar djf -
|
||||
|
||||
Note: Allways 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
|
||||
all comparison results. To make sure no data is written to disk
|
||||
unencrypted, turn off swap if it is not encrypted before doing the
|
||||
backup.
|
||||
|
||||
You can of course use different or no compression and you can use
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
* Do I need a backup of the full partition? Would the header and
|
||||
key-slots not be enough?
|
||||
|
||||
Backup protects you against two things: Disk loss or corruption
|
||||
and user error. By far the most questions on the dm-crypt mailing
|
||||
list about how to recover a damaged LUKS partition are related
|
||||
to user error. For example, if you create a new filesystem on a
|
||||
LUKS partition, chances are good that all data is lost
|
||||
permanently.
|
||||
|
||||
For this case, a header+key-slot backup would often be enough. But
|
||||
keep in mind that a well-treated (!) HDD has roughly a failure
|
||||
risk of 5% per year. It is highly advisable to have a complete
|
||||
backup to protect against this case.
|
||||
|
||||
|
||||
* *What do I need to backup if I use "decrypt_derived"?
|
||||
|
||||
This is a script in Debian, intended for mounting /tmp or swap with
|
||||
a key derived from the master key of an already decrypted device.
|
||||
If you use this for an device with data that should be persistent,
|
||||
you need to make sure you either do not lose access to that master
|
||||
key or have a backup of the data. If you derive from a LUKS
|
||||
device, a header backup of that device would cover backing up the
|
||||
master key. Keep in mind that this does not protect against disk
|
||||
loss.
|
||||
|
||||
Note: If you recreate the LUKS header of the device you derive from
|
||||
(using luksFormat), the master key changes even if you use the same
|
||||
passphrase(s) and you will not be able to decrypt the derived
|
||||
device with the new LUKS header.
|
||||
|
||||
|
||||
* Does a backup compromise security?
|
||||
|
||||
Depends on how you do it. First, a backup is non-optional with
|
||||
encrypted data just the same way it is with non-encrypted data.
|
||||
Disks do break and they do not care whether they make plain or
|
||||
encrypted data inaccessible. As a gideline, a well-treated HDD (!)
|
||||
breaks with about 5% probability per year. This means everybody
|
||||
will be hit sooner or later.
|
||||
Depends on how you do it. However if you do not have one, you are
|
||||
going to eventually lose your encrypted data.
|
||||
|
||||
However there are risks introduced by backups. For example if you
|
||||
There are risks introduced by backups. For example if you
|
||||
change/disable a key-slot in LUKS, a binary backup of the partition
|
||||
will still have the old key-slot. To deal with this, you have to
|
||||
be able to change the key-slot on the backup as well, or use a
|
||||
different set-up. One option is to have a different passphrase on
|
||||
the backup and to make the backup with both containers open.
|
||||
Another one is to make a backup of the original, opened container
|
||||
to a single file, e.g. with tar, and to encrypt that file with
|
||||
public-key-cryptography, e.g. with GnuPG. You can then keep the
|
||||
secret key in a safe place, because it is only used to decrypt a
|
||||
backup. The key the backup is encrypted with can be stored without
|
||||
special security measures, as long as an attacker cannot replace
|
||||
it with his own key.
|
||||
be able to change the key-slot on the backup as well, securely
|
||||
erase the backup or do a filesystem-level backup instead of a binary
|
||||
one.
|
||||
|
||||
If you use dm-crypt, backup is simpler: As there is no key
|
||||
management, the main risk is that you cannot wipe the backup when
|
||||
@@ -822,19 +1013,22 @@ A. Contributors
|
||||
should consist of forgetting the passphrase and that you can do
|
||||
without actual access to the backup.
|
||||
|
||||
In both cases, there is an additional (usually small) risk: An
|
||||
attacker can see how many sectors and which ones have been changed
|
||||
since the backup. This is not possible with the public-key method
|
||||
though.
|
||||
In both cases, there is an additional (usually small) risk with
|
||||
binary backups: An attacker can see how many sectors and which
|
||||
ones have been changed since the backup. To prevent this, use a
|
||||
filesystem level backup methid that encrypts the whole backup in
|
||||
one go, e.g. as described above with tar and GnuPG.
|
||||
|
||||
My personal advice is to use one USB disk (low value date) or
|
||||
My personal advice is to use one USB disk (low value data) or
|
||||
three disks (high value data) in rotating order for backups, and
|
||||
either use different passphrases or keep them easily accessible
|
||||
in case you need to disable a key-slot. If you do network-backup
|
||||
or tape-backup, I strongly recommend to go the public-key path,
|
||||
especially as you typically cannot reliably delete data in these
|
||||
scenarios. (Well, you can burn the tape if it is under your
|
||||
control...)
|
||||
either use independent LUKS partitions on them, or use encrypted
|
||||
backup with tar and GnuPG.
|
||||
|
||||
If you do network-backup or tape-backup, I strongly recommend to
|
||||
go the filesystem backup path with independent encryption, as you
|
||||
typically cannot reliably delete data in these scenarios,
|
||||
especially in a cloud setting. (Well, you can burn the tape if it
|
||||
is under your control...)
|
||||
|
||||
|
||||
* What happens if I overwrite the start of a LUKS partition or damage
|
||||
@@ -860,6 +1054,63 @@ A. Contributors
|
||||
damage the key-slots in part or in full. See also last item.
|
||||
|
||||
|
||||
* How do I recover the master key from a mapped LUKS container?
|
||||
|
||||
This is typically only needed if you managed to damage your LUKS
|
||||
header, but the container is still mapped, i.e. "luksOpen"ed.
|
||||
|
||||
WARNING: This exposes the master key of the LUKS container. Note
|
||||
that both ways to recreate a LUKS header with the old master key
|
||||
described below will write the master key to disk. Unless you are
|
||||
sure you have securely erased it afterwards, e.g. by writing it to
|
||||
an encrypted partition, RAM disk or by erasing the filesystem you
|
||||
wrote it to by a complete overwrite, you should change the master
|
||||
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 tries to automatize the
|
||||
whole process, including generating a new LUKS header with the old
|
||||
master key:
|
||||
|
||||
http://code.google.com/p/cryptsetup/source/browse/trunk/misc/luks-header-from-active
|
||||
|
||||
You can also do this manually. Here is how:
|
||||
|
||||
- Get the master key from the device mapper. This is done by the
|
||||
following command. Substitute c5 for whatever you mapped to:
|
||||
|
||||
# dmsetup table --target crypt --showkey /dev/mapper/c5
|
||||
Result:
|
||||
0 200704 crypt aes-cbc-essiv:sha256
|
||||
a1704d9715f73a1bb4db581dcacadaf405e700d591e93e2eaade13ba653d0d09
|
||||
0 7:0 4096
|
||||
|
||||
The result is actually one line, wrapped here for clarity. The long
|
||||
hex string is the master key.
|
||||
|
||||
- Convert the master key to a binary file representation. You can
|
||||
do this manually, e.g. with hexedit. You can also use the tool
|
||||
"xxd" from vim like this:
|
||||
|
||||
echo "a1704d9....53d0d09" | xxd -r -p > master_key
|
||||
|
||||
- Do a luksFormat to create a new LUKS header. Unmapthe device
|
||||
before you do that (luksClose). Replace \dev\dsa10 with the device
|
||||
the LUKS container is on:
|
||||
|
||||
cryptsetup luksFormat --master-key-file=master_key \dev\sda10
|
||||
|
||||
Note that if the container was created with other than the default
|
||||
settings of the cryptsetup version you are using, you need to give
|
||||
additional parameters specifying the deviations. If in doubt, just
|
||||
do the first step, keep the whole result safe and try with the
|
||||
script by Milan. It does recover the other parameters as well.
|
||||
|
||||
Side note: This is the way the decrypt_derived script gets at the
|
||||
master key. It just omits the conversion and hashes the master key
|
||||
string.
|
||||
|
||||
|
||||
* What does the on-disk structure of dm-crypt look like?
|
||||
|
||||
There is none. dm-crypt takes a block device and gives encrypted
|
||||
@@ -910,75 +1161,83 @@ A. Contributors
|
||||
http://code.google.com/p/cryptsetup/wiki/Specification
|
||||
|
||||
|
||||
* How do I backup a LUKS header?
|
||||
|
||||
While you could just copy the appropriate number of bytes from the
|
||||
start of the LUKS partition, the best way is to use command option
|
||||
"luksHeaderBackup" of cryptsetup. This protects also against
|
||||
errors when non-standard parameters have been used in LUKS
|
||||
partition creation. Example:
|
||||
|
||||
|
||||
cryptsetup luksHeaderBackup --header-backup-file h /dev/mapper/c1
|
||||
|
||||
To restore, use the inverse command, i.e.
|
||||
|
||||
cryptsetup luksHeaderRestore --header-backup-file h /dev/mapper/c1
|
||||
|
||||
|
||||
* How do I backup a LUKS partition?
|
||||
|
||||
You do a sector-image of the whole partition. This will contain
|
||||
the LUKS header, the keys-slots and the data ares. It can be done
|
||||
under Linux e.g. with dd_rescue (for a direct image copy) and with
|
||||
"cat" or "dd". Example:
|
||||
|
||||
cat /dev/sda10 > sda10.img
|
||||
dd_rescue /dev/sda10 sda10.img
|
||||
|
||||
You can also use any other backup software that is capable of making
|
||||
a sector image of a partition. Note that compression is
|
||||
ineffective for encrypted data, hence it does not make sense to
|
||||
use it.
|
||||
|
||||
|
||||
* Do I need a backup of the full partition? Would the header and
|
||||
key-slots not be enough?
|
||||
|
||||
Backup protects you against two things: Disk loss or corruption
|
||||
and user error. By far the most questions on the dm-crypt mailing
|
||||
list about how to recover a damaged LUKS partition are related
|
||||
to user error. For example, if you create a new filesystem on a
|
||||
LUKS partition, chances are good that all data is lost
|
||||
permanently.
|
||||
|
||||
For this case, a header+key-slot backup would often be enough. But
|
||||
keep in mind that a well-treated (!) HDD has roughly a failure
|
||||
risk of 5% per year. It is highly advisable to have a complete
|
||||
backup to protect against this case.
|
||||
|
||||
|
||||
* Are there security risks from a backup of the LUKS header or a
|
||||
whole LUKS partition?
|
||||
|
||||
Yes. One risk is that if you remove access rights for specific
|
||||
key-slots by deleting their contents, the data can still be
|
||||
accessed with invalidated passphrase and the backup. The other
|
||||
risk is that if you erase a LUKS partition, a backup could still
|
||||
grant access, especially if you only erased the LUKS header and
|
||||
not the whole partition.
|
||||
|
||||
|
||||
* I think this is overly complicated. Is there an alternative?
|
||||
|
||||
Yes, you can use plain dm-crypt. It does not allow multiple
|
||||
Not really. Encryption comes at a price. You can use plain
|
||||
dm-crypt to simplify things a bit. It does not allow multiple
|
||||
passphrases, but on the plus side, it has zero on disk description
|
||||
and if you overwrite some part of a plain dm-crypt partition,
|
||||
exactly the overwritten parts are lost (rounded up to sector
|
||||
borders).
|
||||
|
||||
|
||||
7. Issues with Specific Versions of cryptsetup
|
||||
7. Interoperability with other Disk Encryption Tools
|
||||
|
||||
|
||||
* What is this section about?
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
* loop-aes: General observations.
|
||||
|
||||
One problem is that there are different versions of losetup around.
|
||||
loop-aes is a patch for losetup. Possible problems and deviations
|
||||
from cryptsetup option syntax include:
|
||||
|
||||
- Offsets specifed in bytes (cryptsetup: 512 byte sectors)
|
||||
|
||||
- The need to specify an IV offset
|
||||
|
||||
- Encryption mode needs specifying (e.g. "-c twofish-cbc-plain")
|
||||
|
||||
- Key size needs specifying (e.g. "-s 128" for 128 bit keys)
|
||||
|
||||
- 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.
|
||||
|
||||
|
||||
* 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
|
||||
|
||||
losetup -e twofish -o 2560 /dev/loop0 /dev/sdb1
|
||||
mount /dev/loop0 mountpoint
|
||||
|
||||
translates to
|
||||
|
||||
cryptsetup create -c twofish -o 5 --skip 5 e1 /dev/sdb1
|
||||
mount /dev/mapper/e1 mountpoint
|
||||
|
||||
|
||||
* loop-aes with 160 bit key
|
||||
|
||||
This seems to be sometimes used with twofish and blowfish and
|
||||
represents a 160 bit ripemed160 hash output padded to 196 bit key
|
||||
length. It seems the corresponding options for cryptsetup are
|
||||
|
||||
--cipher twofish-cbc-null -s 192 -h ripemd160:20
|
||||
|
||||
|
||||
8. Issues with Specific Versions of cryptsetup
|
||||
|
||||
|
||||
* When using the create command for plain dm-crypt with cryptsetup
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
EXTRA_DIST = FAQ docs
|
||||
EXTRA_DIST = FAQ docs misc
|
||||
SUBDIRS = \
|
||||
lib \
|
||||
src \
|
||||
@@ -7,3 +7,6 @@ SUBDIRS = \
|
||||
po
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
clean-local:
|
||||
-rm -rf docs/doxygen_api_docs
|
||||
|
||||
9
TODO
9
TODO
@@ -1,5 +1,6 @@
|
||||
Version 1.4.0:
|
||||
- Remove old API (all calls using crypt_options)
|
||||
- Support separation of metadata device
|
||||
- Wipe device flag
|
||||
Version 1.5.0:
|
||||
- Export wipe device functions
|
||||
- Support K/M suffixes for align payload (new switch?).
|
||||
- FIPS patches (RNG, volume key restrictions, move changekey to library)
|
||||
- online reencryption api?
|
||||
- integrate more metadata formats
|
||||
|
||||
53
acinclude.m4
53
acinclude.m4
@@ -1,53 +0,0 @@
|
||||
dnl MODULE_HELPER(NAME, HELP, DEFAULT, COMMANDS)
|
||||
AC_DEFUN([MODULE_HELPER],[
|
||||
unset have_module
|
||||
AC_ARG_ENABLE([$1], [$2],,[
|
||||
if test "x${enable_all}" = "xdefault"; then
|
||||
enable_[$1]=[$3]
|
||||
else
|
||||
enable_[$1]="${enable_all}"
|
||||
fi
|
||||
])
|
||||
if test "x${enable_[$1]}" != "xno"; then
|
||||
$4
|
||||
AC_MSG_CHECKING([whether to build $1 module])
|
||||
if test -n "${have_module+set}"; then
|
||||
if test "x${enable_[$1]}" = "xauto"; then
|
||||
if test "x${enable_plugins}" != "xno"; then
|
||||
AC_MSG_RESULT([yes, as plugin])
|
||||
build_static=no
|
||||
build_shared=yes
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
build_static=yes
|
||||
build_shared=no
|
||||
fi
|
||||
elif test "x${enable_[$1]}" = "xshared"; then
|
||||
if test "x${enable_plugins}" != "xno"; then
|
||||
AC_MSG_RESULT([yes, as plugin])
|
||||
build_static=no
|
||||
build_shared=yes
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([Can't build [$1] module, plugins are disabled])
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
build_static=yes
|
||||
build_shared=no
|
||||
fi
|
||||
elif test "x${enable_[$1]}" != "xauto"; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([Unable to build $1 plugin, see messages above])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
build_static=no
|
||||
build_shared=no
|
||||
fi
|
||||
else
|
||||
AC_MSG_CHECKING([whether to build $1 module])
|
||||
AC_MSG_RESULT([no])
|
||||
build_static=no
|
||||
build_shared=no
|
||||
fi
|
||||
])
|
||||
15
configure.in
15
configure.in
@@ -1,9 +1,9 @@
|
||||
AC_PREREQ([2.67])
|
||||
AC_INIT([cryptsetup],[1.3.1])
|
||||
AC_INIT([cryptsetup],[1.4.0])
|
||||
|
||||
dnl library version from <major>.<minor>.<release>[-<suffix>]
|
||||
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
|
||||
LIBCRYPTSETUP_VERSION_INFO=3:0:2
|
||||
LIBCRYPTSETUP_VERSION_INFO=4:0:0
|
||||
|
||||
AC_CONFIG_SRCDIR(src/cryptsetup.c)
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
@@ -124,13 +124,11 @@ AC_DEFUN([CONFIGURE_NETTLE], [
|
||||
[AC_MSG_ERROR('You need Nettle cryptographic library.')])
|
||||
|
||||
saved_LIBS=$LIBS
|
||||
AC_CHECK_LIB(nettle, nettle_sha512_init,,
|
||||
[AC_MSG_ERROR('You need Nettle library version 2.1 or more recent.')])
|
||||
AC_CHECK_LIB(nettle, nettle_ripemd160_init,,
|
||||
[AC_MSG_ERROR('You need Nettle library version 2.4 or more recent.')])
|
||||
CRYPTO_LIBS=$LIBS
|
||||
LIBS=$saved_LIBS
|
||||
|
||||
AC_MSG_WARN([Nettle backend does NOT provide backward compatibility (missing ripemd160 hash).])
|
||||
|
||||
CRYPTO_STATIC_LIBS=$CRYPTO_LIBS
|
||||
])
|
||||
|
||||
@@ -220,6 +218,11 @@ if test x$enable_static_cryptsetup = xyes; then
|
||||
AC_CHECK_LIB(devmapper, dm_task_set_uuid,,
|
||||
AC_MSG_ERROR([Cannot link with static device-mapper library.]))
|
||||
|
||||
dnl Try to detect uuid static library.
|
||||
LIBS="$saved_LIBS -static"
|
||||
AC_CHECK_LIB(uuid, uuid_generate,,
|
||||
AC_MSG_ERROR([Cannot find static uuid library.]))
|
||||
|
||||
LIBS=$saved_LIBS
|
||||
PKG_CONFIG=$saved_PKG_CONFIG
|
||||
fi
|
||||
|
||||
280
docs/doxyfile
Normal file
280
docs/doxyfile
Normal file
@@ -0,0 +1,280 @@
|
||||
# Doxyfile 1.7.4
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = "cryptsetup API"
|
||||
PROJECT_NUMBER =
|
||||
PROJECT_BRIEF = "Public cryptsetup API"
|
||||
PROJECT_LOGO =
|
||||
OUTPUT_DIRECTORY = doxygen_api_docs
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF =
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
EXTENSION_MAPPING =
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SUBGROUPING = YES
|
||||
INLINE_GROUPED_CLASSES = NO
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
SYMBOL_CACHE_SIZE = 0
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
FORCE_LOCAL_INCLUDES = NO
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
STRICT_PROTO_MATCHING = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = "doxygen_index" "../lib/libcryptsetup.h"
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS =
|
||||
RECURSIVE = NO
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH = "examples"
|
||||
EXAMPLE_PATTERNS =
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
FILTER_SOURCE_PATTERNS =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = YES
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_EXTRA_FILES =
|
||||
HTML_COLORSTYLE_HUE = 220
|
||||
HTML_COLORSTYLE_SAT = 100
|
||||
HTML_COLORSTYLE_GAMMA = 80
|
||||
HTML_TIMESTAMP = YES
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
||||
DOCSET_PUBLISHER_NAME = Publisher
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
GENERATE_QHP = NO
|
||||
QCH_FILE =
|
||||
QHP_NAMESPACE = org.doxygen.Project
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
QHP_CUST_FILTER_NAME =
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
QHG_LOCATION =
|
||||
GENERATE_ECLIPSEHELP = NO
|
||||
ECLIPSE_DOC_ID = org.doxygen.Project
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
USE_INLINE_TREES = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
EXT_LINKS_IN_WINDOW = NO
|
||||
FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
USE_MATHJAX = NO
|
||||
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
|
||||
SEARCHENGINE = YES
|
||||
SERVER_BASED_SEARCH = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = YES
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
LATEX_FOOTER =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_SOURCE_CODE = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
DOT_NUM_THREADS = 0
|
||||
DOT_FONTNAME = Helvetica
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MSCFILE_DIRS =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
123
docs/doxygen_index
Normal file
123
docs/doxygen_index
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* @mainpage Cryptsetup API
|
||||
*
|
||||
* The documentation covers public parts of cryptsetup API. In the following sections you'll find
|
||||
* the examples that describe some features of cryptsetup API.
|
||||
*
|
||||
* <OL type="A">
|
||||
* <LI>@ref cexamples "Cryptsetup API examples"</LI>
|
||||
* <OL type="1">
|
||||
* <LI>@ref cluks "crypt_luks_usage" - cryptsetup LUKS device type usage examples</LI>
|
||||
* <UL>
|
||||
* <LI>@ref cinit "crypt_init()"</LI>
|
||||
* <LI>@ref cformat "crypt_format()" - header and payload on mutual device</LI>
|
||||
* <LI>@ref ckeys "Keyslot operations" </LI>
|
||||
* <UL>
|
||||
* <LI>@ref ckeyslot_vol "crypt_keyslot_add_by_volume_key()"</LI>
|
||||
* <LI>@ref ckeyslot_pass "crypt_keyslot_add_by_passphrase()"</LI>
|
||||
* </UL>
|
||||
* <LI>@ref cload "crypt_load()"
|
||||
* <LI>@ref cactivate "crypt_activate_by_passphrase()"</LI>
|
||||
* <LI>@ref cactive_pars "crypt_get_active_device()"</LI>
|
||||
* <LI>@ref cinit_by_name "crypt_init_by_name()"</LI>
|
||||
* <LI>@ref cdeactivate "crypt_deactivate()"</LI>
|
||||
* <LI>@ref cluks_ex "crypt_luks_usage.c"</LI>
|
||||
* </UL>
|
||||
* <LI>@ref clog "crypt_log_usage" - cryptsetup logging API examples</LI>
|
||||
* </OL>
|
||||
* </OL>
|
||||
*
|
||||
* @section cexamples Cryptsetup API examples
|
||||
* @section cluks crypt_luks_usage - cryptsetup LUKS device type usage
|
||||
* @subsection cinit crypt_init()
|
||||
*
|
||||
* Every time you need to do something with cryptsetup or dmcrypt device
|
||||
* you need a valid context. The first step to start your work is
|
||||
* @ref crypt_init call. You can call it either with path
|
||||
* to the block device or path to the regular file. If you don't supply the path,
|
||||
* empty context is initialized.
|
||||
*
|
||||
* @subsection cformat crypt_format() - header and payload on mutual device
|
||||
*
|
||||
* This section covers basic use cases for formatting LUKS devices. Format operation
|
||||
* sets device type in context and in case of LUKS header is written at the beginning
|
||||
* of block device. In the example bellow we use the scenario where LUKS header and data
|
||||
* are both stored on the same device. There's also a possibility to store header and
|
||||
* data separately.
|
||||
*
|
||||
* <B>Bear in mind</B> that @ref crypt_format() is destructive operation and it
|
||||
* overwrites part of the backing block device.
|
||||
*
|
||||
* @subsection ckeys Keyslot operations examples
|
||||
*
|
||||
* After successful @ref crypt_format of LUKS device, volume key is not stored
|
||||
* in a persistent way on the device. Keyslot area is an array beyond LUKS header, where
|
||||
* volume key is stored in the encrypted form using user input passphrase. For more info about
|
||||
* LUKS keyslots and how it's actually protected, please look at
|
||||
* <A HREF="http://code.google.com/p/cryptsetup/wiki/Specification">LUKS specification</A>.
|
||||
* There are two basic methods to create a new keyslot:
|
||||
*
|
||||
* @subsection ckeyslot_vol crypt_keyslot_add_by_volume_key()
|
||||
*
|
||||
* Creates a new keyslot directly by encrypting volume_key stored in the device
|
||||
* context. Passphrase should be supplied or user is prompted if passphrase param is
|
||||
* NULL.
|
||||
*
|
||||
* @subsection ckeyslot_pass crypt_keyslot_add_by_passphrase()
|
||||
*
|
||||
* Creates a new keyslot for the volume key by opening existing active keyslot,
|
||||
* extracting volume key from it and storing it into a new keyslot
|
||||
* protected by a new passphrase
|
||||
*
|
||||
* @subsection cload crypt_load()
|
||||
*
|
||||
* Function loads header from backing block device into device context.
|
||||
*
|
||||
* @subsection cactivate crypt_activate_by_passphrase()
|
||||
*
|
||||
* Activates crypt device by user supplied password for keyslot containing the volume_key.
|
||||
* If <I>keyslot</I> parameter is set to <I>CRYPT_ANY_SLOT</I> then all active keyslots
|
||||
* are tried one by one until the volume key is found.
|
||||
*
|
||||
* @subsection cactive_pars crypt_get_active_device()
|
||||
*
|
||||
* This call returns structure containing runtime attributes of active device.
|
||||
*
|
||||
* @subsection cinit_by_name crypt_init_by_name()
|
||||
*
|
||||
* In case you need to do operations with active device (device which already
|
||||
* has its corresponding mapping) and you miss valid device context stored in
|
||||
* *crypt_device reference, you should use this call. Function tries to
|
||||
* get path to backing device from DM, initializes context for it and loads LUKS
|
||||
* header.
|
||||
*
|
||||
* @subsection cdeactivate crypt_deactivate()
|
||||
*
|
||||
* Deactivates crypt device (removes DM mapping and safely erases volume key from kernel).
|
||||
*
|
||||
* @subsection cluks_ex crypt_luks_usage.c - Complex example
|
||||
*
|
||||
* To compile and run use following commands in examples directory:
|
||||
*
|
||||
* @code
|
||||
* make
|
||||
* ./crypt_luks_usage _path_to_[block_device]_file
|
||||
* @endcode
|
||||
*
|
||||
* Note that you need to have the cryptsetup library compiled. @include crypt_luks_usage.c
|
||||
*
|
||||
* @section clog crypt_log_usage - cryptsetup logging API example
|
||||
*
|
||||
* Example describes basic use case for cryptsetup logging. To compile and run
|
||||
* use following commands in examples directory:
|
||||
*
|
||||
* @code
|
||||
* make
|
||||
* ./crypt_log_usage
|
||||
* @endcode
|
||||
*
|
||||
* Note that you need to have the cryptsetup library compiled. @include crypt_log_usage.c
|
||||
*
|
||||
* @example crypt_luks_usage.c
|
||||
* @example crypt_log_usage.c
|
||||
*/
|
||||
17
docs/examples/Makefile
Normal file
17
docs/examples/Makefile
Normal file
@@ -0,0 +1,17 @@
|
||||
TARGETS=crypt_log_usage crypt_luks_usage
|
||||
CFLAGS=-O0 -g -Wall -D_GNU_SOURCE
|
||||
LDLIBS=-lcryptsetup
|
||||
CC=gcc
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
crypt_log_usage: crypt_log_usage.o
|
||||
$(CC) -o $@ $^ $(LDLIBS)
|
||||
|
||||
crypt_luks_usage: crypt_luks_usage.o
|
||||
$(CC) -o $@ $^ $(LDLIBS)
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ core $(TARGETS)
|
||||
|
||||
.PHONY: clean
|
||||
96
docs/examples/crypt_log_usage.c
Normal file
96
docs/examples/crypt_log_usage.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* An example of using logging through libcryptsetup API
|
||||
*
|
||||
* Copyright (C) 2011, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <libcryptsetup.h>
|
||||
|
||||
/*
|
||||
* This is an example of function that can be registered using crypt_set_log_callback API.
|
||||
*
|
||||
* Its prototype is void (*log)(int level, const char *msg, void *usrptr) as defined
|
||||
* in crypt_set_log_callback
|
||||
*/
|
||||
static void simple_syslog_wrapper(int level, const char *msg, void *usrptr)
|
||||
{
|
||||
const char *prefix = (const char *)usrptr;
|
||||
int priority;
|
||||
|
||||
switch(level) {
|
||||
case CRYPT_LOG_NORMAL: priority = LOG_NOTICE; break;
|
||||
case CRYPT_LOG_ERROR: priority = LOG_ERR; break;
|
||||
case CRYPT_LOG_VERBOSE: priority = LOG_INFO; break;
|
||||
case CRYPT_LOG_DEBUG: priority = LOG_DEBUG; break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported log level requested!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (prefix)
|
||||
syslog(priority, "%s:%s", prefix, msg);
|
||||
else
|
||||
syslog(priority, "%s", msg);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct crypt_device *cd;
|
||||
char usrprefix[] = "cslog_example";
|
||||
int r;
|
||||
|
||||
if (geteuid()) {
|
||||
printf("Using of libcryptsetup requires super user privileges.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
openlog("cryptsetup", LOG_CONS | LOG_PID, LOG_USER);
|
||||
|
||||
/* Initialize empty crypt device context */
|
||||
r = crypt_init(&cd, NULL);
|
||||
if (r < 0) {
|
||||
printf("crypt_init() failed.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* crypt_set_log_callback() - register a log function for crypt context */
|
||||
crypt_set_log_callback(cd, &simple_syslog_wrapper, (void *)usrprefix);
|
||||
|
||||
/* send messages ithrough the crypt_log() interface */
|
||||
crypt_log(cd, CRYPT_LOG_NORMAL, "This is normal log message");
|
||||
crypt_log(cd, CRYPT_LOG_ERROR, "This is error log message");
|
||||
crypt_log(cd, CRYPT_LOG_VERBOSE, "This is verbose log message");
|
||||
crypt_log(cd, CRYPT_LOG_DEBUG, "This is debug message");
|
||||
|
||||
/* release crypt context */
|
||||
crypt_free(cd);
|
||||
|
||||
/* Initialize default (global) log function */
|
||||
crypt_set_log_callback(NULL, &simple_syslog_wrapper, NULL);
|
||||
|
||||
crypt_log(NULL, CRYPT_LOG_NORMAL, "This is normal log message");
|
||||
crypt_log(NULL, CRYPT_LOG_ERROR, "This is error log message");
|
||||
crypt_log(NULL, CRYPT_LOG_VERBOSE, "This is verbose log message");
|
||||
crypt_log(NULL, CRYPT_LOG_DEBUG, "This is debug message");
|
||||
|
||||
closelog();
|
||||
return 0;
|
||||
}
|
||||
294
docs/examples/crypt_luks_usage.c
Normal file
294
docs/examples/crypt_luks_usage.c
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* An example of using LUKS device through libcryptsetup API
|
||||
*
|
||||
* Copyright (C) 2011, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <libcryptsetup.h>
|
||||
|
||||
static int format_and_add_keyslots(const char *path)
|
||||
{
|
||||
struct crypt_device *cd;
|
||||
struct crypt_params_luks1 params;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* crypt_init() call precedes most of operations of cryptsetup API. The call is used
|
||||
* to initialize crypt device context stored in structure referenced by _cd_ in
|
||||
* the example. Second parameter is used to pass underlaying device path.
|
||||
*
|
||||
* Note:
|
||||
* If path refers to a regular file it'll be attached to a first free loop device.
|
||||
* crypt_init() operation fails in case there's no more loop device available.
|
||||
* Also, loop device will have the AUTOCLEAR flag set, so the file loopback will
|
||||
* be detached automatically.
|
||||
*/
|
||||
|
||||
r = crypt_init(&cd, path);
|
||||
if (r < 0 ) {
|
||||
printf("crypt_init() failed for %s.\n", path);
|
||||
return r;
|
||||
}
|
||||
|
||||
printf("Context is attached to block device %s.\n", crypt_get_device_name(cd));
|
||||
|
||||
/*
|
||||
* So far no data were written on your device. This will change with call of
|
||||
* crypt_format() only if you specify CRYPT_LUKS1 as device type.
|
||||
*/
|
||||
printf("Device %s will be formatted to LUKS device after 5 seconds.\n"
|
||||
"Press CTRL+C now if you want to cancel this operation.\n", path);
|
||||
sleep(5);
|
||||
|
||||
|
||||
/*
|
||||
* Prepare LUKS format parameters
|
||||
*
|
||||
* hash parameter defines PBKDF2 hash algorithm used in LUKS header.
|
||||
* For compatibility reason we use SHA1 here.
|
||||
*/
|
||||
params.hash = "sha1";
|
||||
|
||||
/*
|
||||
* data_alignment parameter is relevant only in case of the luks header
|
||||
* and the payload are both stored on same device.
|
||||
*
|
||||
* if you set data_alignment = 0, cryptsetup will autodetect
|
||||
* data_alignment according to underlaying device topology.
|
||||
*/
|
||||
params.data_alignment = 0;
|
||||
|
||||
/*
|
||||
* data_device parameter defines that no external device
|
||||
* for luks header will be used
|
||||
*/
|
||||
params.data_device = NULL;
|
||||
|
||||
/*
|
||||
* NULLs for uuid and volume_key means that these attributes will be
|
||||
* generated during crypt_format(). Volume key is generated with respect
|
||||
* to key size parameter passed to function.
|
||||
*
|
||||
* crypt_format() checks device size (LUKS header must fit there).
|
||||
*/
|
||||
r = crypt_format(cd, /* crypt context */
|
||||
CRYPT_LUKS1, /* LUKS1 is standard LUKS header */
|
||||
"aes", /* used cipher */
|
||||
"xts-plain64", /* used block mode and IV generator*/
|
||||
NULL, /* generate UUID */
|
||||
NULL, /* generate volume key from RNG */
|
||||
256 / 8, /* 256bit key - here AES-128 in XTS mode, size is in bytes */
|
||||
¶ms); /* parameters above */
|
||||
|
||||
if(r < 0) {
|
||||
printf("crypt_format() failed on device %s\n", crypt_get_device_name(cd));
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* The device now contains LUKS1 header, but there is
|
||||
* no active keyslot with encrypted volume key yet.
|
||||
*/
|
||||
|
||||
/*
|
||||
* cryptt_kesylot_add_* call stores volume_key in encrypted form into keyslot.
|
||||
* Without keyslot you can't manipulate with LUKS device after the context will be freed.
|
||||
*
|
||||
* To create a new keyslot you need to supply the existing one (to get the volume key from) or
|
||||
* you need to supply the volume key.
|
||||
*
|
||||
* After format, we have volume key stored internally in context so add new keyslot
|
||||
* using this internal volume key.
|
||||
*/
|
||||
r = crypt_keyslot_add_by_volume_key(cd, /* crypt context */
|
||||
CRYPT_ANY_SLOT, /* just use first free slot */
|
||||
NULL, /* use internal volume key */
|
||||
0, /* unused (size of volume key) */
|
||||
"foo", /* passphrase - NULL means query*/
|
||||
3); /* size of passphrase */
|
||||
|
||||
if (r < 0) {
|
||||
printf("Adding keyslot failed.\n");
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
printf("The first keyslot is initialized.\n");
|
||||
|
||||
/*
|
||||
* Add another keyslot, now using the first keyslot.
|
||||
* It will decrypt volume key from the first keyslot and creates new one with another passphrase.
|
||||
*/
|
||||
r = crypt_keyslot_add_by_passphrase(cd, /* crypt context */
|
||||
CRYPT_ANY_SLOT, /* just use first free slot */
|
||||
"foo", 3, /* passphrase for the old keyslot */
|
||||
"bar", 3); /* passphrase for the new kesylot */
|
||||
if (r < 0) {
|
||||
printf("Adding keyslot failed.\n");
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
printf("The second keyslot is initialized.\n");
|
||||
|
||||
crypt_free(cd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int activate_and_check_status(const char *path, const char *device_name)
|
||||
{
|
||||
struct crypt_device *cd;
|
||||
struct crypt_active_device cad;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* LUKS device activation example.
|
||||
* It's sequence of sub-steps: device initialization, LUKS header load
|
||||
* and the device activation itself.
|
||||
*/
|
||||
r = crypt_init(&cd, path);
|
||||
if (r < 0 ) {
|
||||
printf("crypt_init() failed for %s.\n", path);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* crypt_load() is used to load the LUKS header from block device
|
||||
* into crypt_device context.
|
||||
*/
|
||||
r = crypt_load(cd, /* crypt context */
|
||||
CRYPT_LUKS1, /* requested type */
|
||||
NULL); /* additional parameters (not used) */
|
||||
|
||||
if (r < 0) {
|
||||
printf("crypt_load() failed on device %s.\n", crypt_get_device_name(cd));
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device activation creates device-mapper devie mapping with name device_name.
|
||||
*/
|
||||
r = crypt_activate_by_passphrase(cd, /* crypt context */
|
||||
device_name, /* device name to activate */
|
||||
CRYPT_ANY_SLOT,/* which slot use (ANY - try all) */
|
||||
"foo", 3, /* passphrase */
|
||||
CRYPT_ACTIVATE_READONLY); /* flags */
|
||||
if (r < 0) {
|
||||
printf("Device %s activation failed.\n", device_name);
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
printf("LUKS device %s/%s is active.\n", crypt_get_dir(), device_name);
|
||||
printf("\tcipher used: %s\n", crypt_get_cipher(cd));
|
||||
printf("\tcipher mode: %s\n", crypt_get_cipher_mode(cd));
|
||||
printf("\tdevice UUID: %s\n", crypt_get_uuid(cd));
|
||||
|
||||
/*
|
||||
* Get info about active device (query DM backend)
|
||||
*/
|
||||
r = crypt_get_active_device(cd, device_name, &cad);
|
||||
if (r < 0) {
|
||||
printf("Get info about active device %s failed.\n", device_name);
|
||||
crypt_deactivate(cd, device_name);
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
printf("Active device parameters for %s:\n"
|
||||
"\tDevice offset (in sectors): %" PRIu64 "\n"
|
||||
"\tIV offset (in sectors) : %" PRIu64 "\n"
|
||||
"\tdevice size (in sectors) : %" PRIu64 "\n"
|
||||
"\tread-only flag : %s\n",
|
||||
device_name, cad.offset, cad.iv_offset, cad.size,
|
||||
cad.flags & CRYPT_ACTIVATE_READONLY ? "1" : "0");
|
||||
|
||||
crypt_free(cd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_active_device(const char *device_name)
|
||||
{
|
||||
struct crypt_device *cd;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* crypt_init_by_name() initializes device context and loads LUKS header from backing device
|
||||
*/
|
||||
r = crypt_init_by_name(&cd, device_name);
|
||||
if (r < 0) {
|
||||
printf("crypt_init_by_name() failed for %s.\n", device_name);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (crypt_status(cd, device_name) == CRYPT_ACTIVE)
|
||||
printf("Device %s is still active.\n", device_name);
|
||||
else {
|
||||
printf("Something failed perhaps, device %s is not active.\n", device_name);
|
||||
crypt_free(cd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* crypt_deactivate() is used to deactivate device
|
||||
*/
|
||||
r = crypt_deactivate(cd, device_name);
|
||||
if (r < 0) {
|
||||
printf("crypt_deactivate() failed.\n");
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
}
|
||||
|
||||
printf("Device %s is now deactivated.\n", device_name);
|
||||
|
||||
crypt_free(cd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (geteuid()) {
|
||||
printf("Using of libcryptsetup requires super user privileges.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc != 2) {
|
||||
printf("usage: ./crypt_luks_usage <path>\n"
|
||||
"<path> refers to either a regular file or a block device.\n"
|
||||
" WARNING: the file or device will be wiped.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (format_and_add_keyslots(argv[1]))
|
||||
return 3;
|
||||
|
||||
if (activate_and_check_status(argv[1], "example_device"))
|
||||
return 4;
|
||||
|
||||
if (handle_active_device("example_device"))
|
||||
return 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
docs/on-disk-format.pdf
Normal file
BIN
docs/on-disk-format.pdf
Normal file
Binary file not shown.
131
docs/v1.4.0-ReleaseNotes
Normal file
131
docs/v1.4.0-ReleaseNotes
Normal file
@@ -0,0 +1,131 @@
|
||||
Cryptsetup 1.4.0 Release Notes
|
||||
==============================
|
||||
|
||||
Changes since version 1.3.1
|
||||
|
||||
Important changes
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
WARNING: This release removes old deprecated API from libcryptsetup
|
||||
(all functions using struct crypt_options).
|
||||
|
||||
This require libcrypsetup version change and
|
||||
rebuild of applications using cryptsetup library.
|
||||
All new API symbols are backward compatible.
|
||||
|
||||
* If device is not rotational disk, cryptsetup no longer tries
|
||||
to wipe keyslot with Gutmann algorithm for magnetic media erase
|
||||
but simply rewrites area once by random data.
|
||||
|
||||
* The on-disk LUKS header can now be detached (e.g. placed on separate
|
||||
device or in file) using new --header option.
|
||||
|
||||
This option is only relevant for LUKS devices and can be used in
|
||||
luksFormat, luksOpen, luksSuspend, luksResume and resize commands.
|
||||
|
||||
If used with luksFormat the --align-payload option is taken
|
||||
as absolute sector alignment on ciphertext device and can be zero.
|
||||
|
||||
Example:
|
||||
Create LUKS device with ciphertext device on /dev/sdb and header
|
||||
on device /dev/sdc. Use all space on /dev/sdb (no reserved area for header).
|
||||
|
||||
cryptsetup luksFormat /dev/sdb --header /dev/sdc --align-payload 0
|
||||
|
||||
Activate such device:
|
||||
cryptsetup luksOpen /dev/sdb --header /dev/sdc test_disk
|
||||
|
||||
You can use file for LUKS header (loop device will be used while
|
||||
manipulating with such detached header), just you have to create
|
||||
large enough file in advance.
|
||||
|
||||
dd if=/dev/zero of=/mnt/luks_header bs=1M count=4
|
||||
cryptsetup luksFormat /dev/sdb --header /mnt/luks_header --align-payload 0
|
||||
|
||||
Activation is the same as above.
|
||||
|
||||
cryptsetup luksOpen /dev/sdb --header /mnt/luks_header test_disk
|
||||
|
||||
All keyslot operations need to be run on _header_ not on ciphertext device,
|
||||
an example:
|
||||
|
||||
cryptsetup luksAddKey /mnt/luks_header
|
||||
|
||||
If you do not use --align-payload 0, you can later restore LUKS header
|
||||
on device itself (and use it as normal LUKS device without detached header).
|
||||
|
||||
WARNING: There is no possible check that specified ciphertext device
|
||||
matches detached on-disk header. Use with care, it can destroy
|
||||
your data in case of a mistake.
|
||||
|
||||
WARNING: Storing LUKS header in a file means that anti-forensic splitter
|
||||
cannot properly work (there is filesystem allocation layer between
|
||||
header and disk).
|
||||
|
||||
* Support --enable-discards option to allow discards/TRIM requests.
|
||||
|
||||
Since kernel 3.1, dm-crypt devices optionally (not by default) support
|
||||
block discards (TRIM) comands.
|
||||
If you want to enable this operation, you have to enable it manually
|
||||
on every activation using --enable-discards
|
||||
|
||||
cryptsetup luksOpen --enable-discards /dev/sdb test_disk
|
||||
|
||||
WARNING: There are several security consequences, please read at least
|
||||
http://asalor.blogspot.com/2011/08/trim-dm-crypt-problems.html
|
||||
before you enable it.
|
||||
|
||||
* Add --shared option for creating non-overlapping crypt segments.
|
||||
|
||||
The --shared options checks that mapped segments are not overlapping
|
||||
and allows non-exclusive access to underlying device.
|
||||
Only plain crypt devices can be used in this mode.
|
||||
|
||||
Example - map 64M of device disk and following 32 M area as another disk.
|
||||
|
||||
cryptsetup create outer_disk /dev/sdb --offset 0 --size 65536
|
||||
cryptsetup create inner_disk /dev/sdb --offset 65536 --size 32768 --shared
|
||||
|
||||
(It can be used to simulate trivial hidden disk concepts.)
|
||||
|
||||
libcryptsetup API changes:
|
||||
* Added options to suport detached metadata device
|
||||
crypt_init_by_name_and_header()
|
||||
crypt_set_data_device()
|
||||
* Add crypt_last_error() API call.
|
||||
* Fix plain crypt format parameters to include size option.
|
||||
* Add crypt_get_iv_offset() function.
|
||||
|
||||
* Remove old API functions (all functions using crypt_options).
|
||||
|
||||
* Support key-slot option for luksOpen (use only explicit keyslot).
|
||||
|
||||
You can now specify key slot in luksOpen and limit checking
|
||||
only to specified slot.
|
||||
|
||||
* Support retries and timeout parameters for luksSuspend.
|
||||
(The same way as in luksOpen.)
|
||||
|
||||
* Add doxygen-like documentation (it will be available on project page later).
|
||||
(To generate it manually run doxygen in docs directory.)
|
||||
|
||||
Other changes
|
||||
~~~~~~~~~~~~~
|
||||
* Fix crypt_load to properly check device size.
|
||||
* Do not allow context format of already formatted device.
|
||||
* Do not allow key retrieval while suspended (key could be wiped).
|
||||
* Do not allow suspend for non-LUKS devices.
|
||||
* Fix luksKillSLot exit code if slot is inactive or invalid.
|
||||
* Fix exit code if passphrases do not match in luksAddKey.
|
||||
* Fix return code for status command when device doesn't exists.
|
||||
* Fix verbose messages in isLuks command.
|
||||
* Support Nettle 2.4 crypto backend (supports ripemd160).
|
||||
* Add LUKS on-disk format description into package.
|
||||
* Enhance check of device size before writing LUKS header.
|
||||
* Add more paranoid checks for LUKS header and keyslot attributes.
|
||||
* Use new /dev/loop-control (kernel 3.1) if possible.
|
||||
* Remove hash/hmac restart from crypto backend and make it part of hash/hmac final.
|
||||
* Improve check for invalid offset and size values.
|
||||
* Revert default initialisation of volume key in crypt_init_by_name().
|
||||
* Add more regression tests.
|
||||
* Add some libcryptsetup example files (see docs/examples).
|
||||
@@ -53,6 +53,7 @@ libcryptsetup_la_SOURCES = \
|
||||
utils_loop.c \
|
||||
utils_loop.h \
|
||||
utils_devpath.c \
|
||||
utils_wipe.c \
|
||||
libdevmapper.c \
|
||||
utils_dm.h \
|
||||
volumekey.c \
|
||||
|
||||
@@ -54,8 +54,6 @@ static int hash(const char *hash_name, size_t key_size, char *key,
|
||||
|
||||
key += len;
|
||||
key_size -= len;
|
||||
if (key_size && crypt_hash_restart(md))
|
||||
r = 1;
|
||||
}
|
||||
|
||||
crypt_hash_destroy(md);
|
||||
|
||||
@@ -16,7 +16,6 @@ uint32_t crypt_backend_flags(void);
|
||||
/* HASH */
|
||||
int crypt_hash_size(const char *name);
|
||||
int crypt_hash_init(struct crypt_hash **ctx, const char *name);
|
||||
int crypt_hash_restart(struct crypt_hash *ctx);
|
||||
int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length);
|
||||
int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length);
|
||||
int crypt_hash_destroy(struct crypt_hash *ctx);
|
||||
@@ -25,7 +24,6 @@ int crypt_hash_destroy(struct crypt_hash *ctx);
|
||||
int crypt_hmac_size(const char *name);
|
||||
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
const void *buffer, size_t length);
|
||||
int crypt_hmac_restart(struct crypt_hmac *ctx);
|
||||
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length);
|
||||
int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length);
|
||||
int crypt_hmac_destroy(struct crypt_hmac *ctx);
|
||||
|
||||
@@ -117,10 +117,9 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_restart(struct crypt_hash *ctx)
|
||||
static void crypt_hash_restart(struct crypt_hash *ctx)
|
||||
{
|
||||
gcry_md_reset(ctx->hd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length)
|
||||
@@ -141,6 +140,8 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(buffer, hash, length);
|
||||
crypt_hash_restart(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -191,10 +192,9 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_restart(struct crypt_hmac *ctx)
|
||||
static void crypt_hmac_restart(struct crypt_hmac *ctx)
|
||||
{
|
||||
gcry_md_reset(ctx->hd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
|
||||
@@ -215,6 +215,8 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(buffer, hash, length);
|
||||
crypt_hmac_restart(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -176,11 +176,6 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_restart(struct crypt_hash *ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length)
|
||||
{
|
||||
ssize_t r;
|
||||
@@ -261,11 +256,6 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_restart(struct crypt_hmac *ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
|
||||
{
|
||||
ssize_t r;
|
||||
|
||||
@@ -81,6 +81,14 @@ static struct hash_alg hash_algs[] = {
|
||||
(digest_func) hmac_sha512_digest,
|
||||
(set_key_func) hmac_sha512_set_key,
|
||||
},
|
||||
{ "ripemd160", RIPEMD160_DIGEST_SIZE,
|
||||
(init_func) ripemd160_init,
|
||||
(update_func) ripemd160_update,
|
||||
(digest_func) ripemd160_digest,
|
||||
(update_func) hmac_ripemd160_update,
|
||||
(digest_func) hmac_ripemd160_digest,
|
||||
(set_key_func) hmac_ripemd160_set_key,
|
||||
},
|
||||
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, }
|
||||
};
|
||||
|
||||
@@ -159,10 +167,9 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_restart(struct crypt_hash *ctx)
|
||||
static void crypt_hash_restart(struct crypt_hash *ctx)
|
||||
{
|
||||
ctx->hash->init(&ctx->nettle_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length)
|
||||
@@ -177,6 +184,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
return -EINVAL;
|
||||
|
||||
ctx->hash->digest(&ctx->nettle_ctx, length, (uint8_t *)buffer);
|
||||
crypt_hash_restart(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -225,10 +233,9 @@ bad:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int crypt_hmac_restart(struct crypt_hmac *ctx)
|
||||
static void crypt_hmac_restart(struct crypt_hmac *ctx)
|
||||
{
|
||||
ctx->hash->hmac_set_key(&ctx->nettle_ctx, ctx->key_length, ctx->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
|
||||
@@ -243,6 +250,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
return -EINVAL;
|
||||
|
||||
ctx->hash->hmac_digest(&ctx->nettle_ctx, length, (uint8_t *)buffer);
|
||||
crypt_hmac_restart(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_restart(struct crypt_hash *ctx)
|
||||
static int crypt_hash_restart(struct crypt_hash *ctx)
|
||||
{
|
||||
if (PK11_DigestBegin(ctx->md) != SECSuccess)
|
||||
return -EINVAL;
|
||||
@@ -131,7 +131,7 @@ int crypt_hash_restart(struct crypt_hash *ctx)
|
||||
|
||||
int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length)
|
||||
{
|
||||
if (PK11_DigestOp(ctx->md, (unsigned char *)buffer, length) != SECSuccess)
|
||||
if (PK11_DigestOp(ctx->md, CONST_CAST(unsigned char *)buffer, length) != SECSuccess)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -154,6 +154,9 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
if (tmp_len < length)
|
||||
return -EINVAL;
|
||||
|
||||
if (crypt_hash_restart(ctx))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -179,7 +182,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
SECItem noParams;
|
||||
|
||||
keyItem.type = siBuffer;
|
||||
keyItem.data = (unsigned char *)buffer;
|
||||
keyItem.data = CONST_CAST(unsigned char *)buffer;
|
||||
keyItem.len = (int)length;
|
||||
|
||||
noParams.type = siBuffer;
|
||||
@@ -220,7 +223,7 @@ bad:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int crypt_hmac_restart(struct crypt_hmac *ctx)
|
||||
static int crypt_hmac_restart(struct crypt_hmac *ctx)
|
||||
{
|
||||
if (PK11_DigestBegin(ctx->md) != SECSuccess)
|
||||
return -EINVAL;
|
||||
@@ -230,7 +233,7 @@ int crypt_hmac_restart(struct crypt_hmac *ctx)
|
||||
|
||||
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
|
||||
{
|
||||
if (PK11_DigestOp(ctx->md, (unsigned char *)buffer, length) != SECSuccess)
|
||||
if (PK11_DigestOp(ctx->md, CONST_CAST(unsigned char *)buffer, length) != SECSuccess)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -253,6 +256,9 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
if (tmp_len < length)
|
||||
return -EINVAL;
|
||||
|
||||
if (crypt_hmac_restart(ctx))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hash_restart(struct crypt_hash *ctx)
|
||||
static int crypt_hash_restart(struct crypt_hash *ctx)
|
||||
{
|
||||
if (EVP_DigestInit(&ctx->md, ctx->hash_id) != 1)
|
||||
return -EINVAL;
|
||||
@@ -131,6 +131,9 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
|
||||
if (tmp_len < length)
|
||||
return -EINVAL;
|
||||
|
||||
if (crypt_hash_restart(ctx))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -171,10 +174,9 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_restart(struct crypt_hmac *ctx)
|
||||
static void crypt_hmac_restart(struct crypt_hmac *ctx)
|
||||
{
|
||||
HMAC_Init_ex(&ctx->md, NULL, 0, ctx->hash_id, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
|
||||
@@ -199,6 +201,8 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
|
||||
if (tmp_len < length)
|
||||
return -EINVAL;
|
||||
|
||||
crypt_hmac_restart(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,17 +15,14 @@
|
||||
#include "utils_loop.h"
|
||||
#include "utils_dm.h"
|
||||
|
||||
/* to silent gcc -Wcast-qual for const cast */
|
||||
#define CONST_CAST(x) (x)(uintptr_t)
|
||||
|
||||
#define SECTOR_SHIFT 9
|
||||
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
|
||||
#define DEFAULT_DISK_ALIGNMENT 1048576 /* 1MiB */
|
||||
#define DEFAULT_MEM_ALIGNMENT 4096
|
||||
|
||||
/* private struct crypt_options flags */
|
||||
|
||||
#define CRYPT_FLAG_FREE_DEVICE (1 << 24)
|
||||
#define CRYPT_FLAG_FREE_CIPHER (1 << 25)
|
||||
|
||||
#define CRYPT_FLAG_PRIVATE_MASK ((unsigned int)-1 << 24)
|
||||
#define MAX_ERROR_LENGTH 512
|
||||
|
||||
#define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); })
|
||||
|
||||
@@ -42,11 +39,9 @@ void crypt_free_volume_key(struct volume_key *vk);
|
||||
|
||||
int crypt_confirm(struct crypt_device *cd, const char *msg);
|
||||
|
||||
void set_error_va(const char *fmt, va_list va);
|
||||
void set_error(const char *fmt, ...);
|
||||
const char *get_error(void);
|
||||
|
||||
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);
|
||||
@@ -54,25 +49,21 @@ 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 get_device_infos(const char *device,
|
||||
int open_exclusive,
|
||||
int *readonly,
|
||||
uint64_t *size);
|
||||
int device_size(const char *device, uint64_t *size);
|
||||
|
||||
enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 };
|
||||
int device_check_and_adjust(struct crypt_device *cd,
|
||||
const char *device,
|
||||
int open_exclusive,
|
||||
enum devcheck device_check,
|
||||
uint64_t *size,
|
||||
uint64_t *offset,
|
||||
int *read_only);
|
||||
int wipe_device_header(const char *device, int sectors);
|
||||
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)
|
||||
#define log_std(c, x...) logger(c, CRYPT_LOG_NORMAL, __FILE__, __LINE__, x)
|
||||
#define log_verbose(c, x...) logger(c, CRYPT_LOG_VERBOSE, __FILE__, __LINE__, x)
|
||||
#define log_err(c, x...) do { \
|
||||
logger(c, CRYPT_LOG_ERROR, __FILE__, __LINE__, x); \
|
||||
set_error(x); } while(0)
|
||||
#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);
|
||||
@@ -95,5 +86,29 @@ int crypt_plain_hash(struct crypt_device *ctx,
|
||||
const char *hash_name,
|
||||
char *key, size_t key_size,
|
||||
const char *passphrase, size_t passphrase_size);
|
||||
int PLAIN_activate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vk,
|
||||
uint64_t size,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* Different methods used to erase sensitive data concerning
|
||||
* either encrypted payload area or master key inside keyslot
|
||||
* area
|
||||
*/
|
||||
typedef enum {
|
||||
CRYPT_WIPE_ZERO, /**< overwrite area using zero blocks */
|
||||
CRYPT_WIPE_DISK, /**< erase disk (using Gutmann method if it is rotational disk)*/
|
||||
CRYPT_WIPE_SSD, /**< erase solid state disk (random write) */
|
||||
CRYPT_WIPE_RANDOM /**< overwrite area using some up to now unspecified
|
||||
* random algorithm */
|
||||
} crypt_wipe_type;
|
||||
|
||||
int crypt_wipe(const char *device,
|
||||
uint64_t offset,
|
||||
uint64_t sectors,
|
||||
crypt_wipe_type type,
|
||||
int flags);
|
||||
|
||||
#endif /* INTERNAL_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ CRYPTSETUP_1.0 {
|
||||
global:
|
||||
crypt_init;
|
||||
crypt_init_by_name;
|
||||
crypt_init_by_name_and_header;
|
||||
crypt_set_log_callback;
|
||||
crypt_set_confirm_callback;
|
||||
crypt_set_password_callback;
|
||||
@@ -10,6 +11,7 @@ CRYPTSETUP_1.0 {
|
||||
crypt_set_iterarion_time;
|
||||
crypt_set_password_verify;
|
||||
crypt_set_uuid;
|
||||
crypt_set_data_device;
|
||||
|
||||
crypt_memory_lock;
|
||||
crypt_format;
|
||||
@@ -36,6 +38,7 @@ CRYPTSETUP_1.0 {
|
||||
crypt_get_cipher_mode;
|
||||
crypt_get_uuid;
|
||||
crypt_get_data_offset;
|
||||
crypt_get_iv_offset;
|
||||
crypt_get_volume_key_size;
|
||||
crypt_get_device_name;
|
||||
|
||||
@@ -47,6 +50,7 @@ CRYPTSETUP_1.0 {
|
||||
|
||||
crypt_keyslot_max;
|
||||
crypt_keyslot_status;
|
||||
crypt_last_error;
|
||||
crypt_get_error;
|
||||
crypt_get_dir;
|
||||
crypt_set_debug_level;
|
||||
@@ -54,22 +58,6 @@ CRYPTSETUP_1.0 {
|
||||
|
||||
crypt_header_backup;
|
||||
crypt_header_restore;
|
||||
|
||||
crypt_create_device;
|
||||
crypt_update_device;
|
||||
crypt_resize_device;
|
||||
crypt_query_device;
|
||||
crypt_remove_device;
|
||||
crypt_luksFormat;
|
||||
crypt_luksOpen;
|
||||
crypt_luksKillSlot;
|
||||
crypt_luksRemoveKey;
|
||||
crypt_luksAddKey;
|
||||
crypt_luksUUID;
|
||||
crypt_isLuks;
|
||||
crypt_luksDump;
|
||||
|
||||
crypt_put_options;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
@@ -119,6 +119,9 @@ static void _dm_set_crypt_compat(const char *dm_version, unsigned crypt_maj,
|
||||
if (crypt_maj >= 1 && crypt_min >= 8)
|
||||
_dm_crypt_flags |= DM_PLAIN64_SUPPORTED;
|
||||
|
||||
if (crypt_maj >= 1 && crypt_min >= 11)
|
||||
_dm_crypt_flags |= DM_DISCARDS_SUPPORTED;
|
||||
|
||||
/* Repeat test if dm-crypt is not present */
|
||||
if (crypt_maj > 0)
|
||||
_dm_crypt_checked = 1;
|
||||
@@ -206,7 +209,7 @@ void dm_exit(void)
|
||||
}
|
||||
|
||||
/* Return path to DM device */
|
||||
char *dm_device_path(int major, int minor)
|
||||
char *dm_device_path(const char *prefix, int major, int minor)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
const char *name;
|
||||
@@ -222,7 +225,7 @@ char *dm_device_path(int major, int minor)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (snprintf(path, sizeof(path), "/dev/mapper/%s", name) < 0)
|
||||
if (snprintf(path, sizeof(path), "%s%s", prefix ?: "", name) < 0)
|
||||
path[0] = '\0';
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
@@ -238,25 +241,39 @@ static void hex_key(char *hexkey, size_t key_size, const char *key)
|
||||
sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]);
|
||||
}
|
||||
|
||||
static char *get_params(const char *device, uint64_t skip, uint64_t offset,
|
||||
const char *cipher, size_t key_size, const char *key)
|
||||
static char *get_params(struct crypt_dm_active_device *dmd)
|
||||
{
|
||||
char *params;
|
||||
char *hexkey;
|
||||
int r, max_size;
|
||||
char *params, *hexkey;
|
||||
const char *features = "";
|
||||
|
||||
hexkey = crypt_safe_alloc(key_size * 2 + 1);
|
||||
if (dmd->flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) {
|
||||
if (dm_flags() & DM_DISCARDS_SUPPORTED) {
|
||||
features = " 1 allow_discards";
|
||||
log_dbg("Discard/TRIM is allowed.");
|
||||
} else
|
||||
log_dbg("Discard/TRIM is not supported by the kernel.");
|
||||
}
|
||||
|
||||
hexkey = crypt_safe_alloc(dmd->vk->keylength * 2 + 1);
|
||||
if (!hexkey)
|
||||
return NULL;
|
||||
|
||||
hex_key(hexkey, key_size, key);
|
||||
hex_key(hexkey, dmd->vk->keylength, dmd->vk->key);
|
||||
|
||||
params = crypt_safe_alloc(strlen(hexkey) + strlen(cipher) + strlen(device) + 64);
|
||||
max_size = strlen(hexkey) + strlen(dmd->cipher) +
|
||||
strlen(dmd->device) + strlen(features) + 64;
|
||||
params = crypt_safe_alloc(max_size);
|
||||
if (!params)
|
||||
goto out;
|
||||
|
||||
sprintf(params, "%s %s %" PRIu64 " %s %" PRIu64,
|
||||
cipher, hexkey, skip, device, offset);
|
||||
|
||||
r = snprintf(params, max_size, "%s %s %" PRIu64 " %s %" PRIu64 "%s",
|
||||
dmd->cipher, hexkey, dmd->iv_offset, dmd->device,
|
||||
dmd->offset, features);
|
||||
if (r < 0 || r >= max_size) {
|
||||
crypt_safe_free(params);
|
||||
params = NULL;
|
||||
}
|
||||
out:
|
||||
crypt_safe_free(hexkey);
|
||||
return params;
|
||||
@@ -396,29 +413,20 @@ static void dm_prepare_uuid(const char *name, const char *type, const char *uuid
|
||||
}
|
||||
|
||||
int dm_create_device(const char *name,
|
||||
const char *device,
|
||||
const char *cipher,
|
||||
const char *type,
|
||||
const char *uuid,
|
||||
uint64_t size,
|
||||
uint64_t skip,
|
||||
uint64_t offset,
|
||||
size_t key_size,
|
||||
const char *key,
|
||||
int read_only,
|
||||
struct crypt_dm_active_device *dmd,
|
||||
int reload)
|
||||
{
|
||||
struct dm_task *dmt = NULL;
|
||||
struct dm_info dmi;
|
||||
char *params = NULL;
|
||||
char *error = NULL;
|
||||
char dev_uuid[DM_UUID_LEN] = {0};
|
||||
int r = -EINVAL;
|
||||
uint32_t read_ahead = 0;
|
||||
uint32_t cookie = 0;
|
||||
uint16_t udev_flags = 0;
|
||||
|
||||
params = get_params(device, skip, offset, cipher, key_size, key);
|
||||
params = get_params(dmd);
|
||||
if (!params)
|
||||
goto out_no_removal;
|
||||
|
||||
@@ -433,7 +441,7 @@ int dm_create_device(const char *name,
|
||||
if (!dm_task_set_name(dmt, name))
|
||||
goto out_no_removal;
|
||||
} else {
|
||||
dm_prepare_uuid(name, type, uuid, dev_uuid, sizeof(dev_uuid));
|
||||
dm_prepare_uuid(name, type, dmd->uuid, dev_uuid, sizeof(dev_uuid));
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_CREATE)))
|
||||
goto out_no_removal;
|
||||
@@ -450,13 +458,13 @@ int dm_create_device(const char *name,
|
||||
|
||||
if ((dm_flags() & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt))
|
||||
goto out_no_removal;
|
||||
if (read_only && !dm_task_set_ro(dmt))
|
||||
if ((dmd->flags & CRYPT_ACTIVATE_READONLY) && !dm_task_set_ro(dmt))
|
||||
goto out_no_removal;
|
||||
if (!dm_task_add_target(dmt, 0, size, DM_CRYPT_TARGET, params))
|
||||
if (!dm_task_add_target(dmt, 0, dmd->size, DM_CRYPT_TARGET, params))
|
||||
goto out_no_removal;
|
||||
|
||||
#ifdef DM_READ_AHEAD_MINIMUM_FLAG
|
||||
if (device_read_ahead(device, &read_ahead) &&
|
||||
if (device_read_ahead(dmd->device, &read_ahead) &&
|
||||
!dm_task_set_read_ahead(dmt, read_ahead, DM_READ_AHEAD_MINIMUM_FLAG))
|
||||
goto out_no_removal;
|
||||
#endif
|
||||
@@ -470,7 +478,7 @@ int dm_create_device(const char *name,
|
||||
goto out;
|
||||
if (!dm_task_set_name(dmt, name))
|
||||
goto out;
|
||||
if (uuid && !dm_task_set_uuid(dmt, dev_uuid))
|
||||
if (dmd->uuid && !dm_task_set_uuid(dmt, dev_uuid))
|
||||
goto out;
|
||||
if (_dm_use_udev() && !_dm_task_set_cookie(dmt, &cookie, udev_flags))
|
||||
goto out;
|
||||
@@ -488,18 +496,9 @@ out:
|
||||
cookie = 0;
|
||||
}
|
||||
|
||||
if (r < 0 && !reload) {
|
||||
if (get_error())
|
||||
error = strdup(get_error());
|
||||
|
||||
if (r < 0 && !reload)
|
||||
dm_remove_device(name, 0, 0);
|
||||
|
||||
if (error) {
|
||||
set_error(error);
|
||||
free(error);
|
||||
}
|
||||
}
|
||||
|
||||
out_no_removal:
|
||||
if (cookie && _dm_use_udev())
|
||||
(void)_dm_udev_wait(cookie);
|
||||
@@ -513,10 +512,9 @@ out_no_removal:
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_status_device(const char *name)
|
||||
static int dm_status_dmi(const char *name, struct dm_info *dmi)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
struct dm_info dmi;
|
||||
uint64_t start, length;
|
||||
char *target_type, *params;
|
||||
void *next = NULL;
|
||||
@@ -531,10 +529,10 @@ int dm_status_device(const char *name)
|
||||
if (!dm_task_run(dmt))
|
||||
goto out;
|
||||
|
||||
if (!dm_task_get_info(dmt, &dmi))
|
||||
if (!dm_task_get_info(dmt, dmi))
|
||||
goto out;
|
||||
|
||||
if (!dmi.exists) {
|
||||
if (!dmi->exists) {
|
||||
r = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
@@ -545,7 +543,7 @@ int dm_status_device(const char *name)
|
||||
start != 0 || next)
|
||||
r = -EINVAL;
|
||||
else
|
||||
r = (dmi.open_count > 0);
|
||||
r = 0;
|
||||
out:
|
||||
if (dmt)
|
||||
dm_task_destroy(dmt);
|
||||
@@ -553,25 +551,43 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_query_device(const char *name,
|
||||
char **device,
|
||||
uint64_t *size,
|
||||
uint64_t *skip,
|
||||
uint64_t *offset,
|
||||
char **cipher,
|
||||
int *key_size,
|
||||
char **key,
|
||||
int *read_only,
|
||||
int *suspended,
|
||||
char **uuid)
|
||||
int dm_status_device(const char *name)
|
||||
{
|
||||
int r;
|
||||
struct dm_info dmi;
|
||||
|
||||
r = dm_status_dmi(name, &dmi);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return (dmi.open_count > 0);
|
||||
}
|
||||
|
||||
int dm_status_suspended(const char *name)
|
||||
{
|
||||
int r;
|
||||
struct dm_info dmi;
|
||||
|
||||
r = dm_status_dmi(name, &dmi);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return dmi.suspended ? 1 : 0;
|
||||
}
|
||||
|
||||
int dm_query_device(const char *name, uint32_t get_flags,
|
||||
struct crypt_dm_active_device *dmd)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
struct dm_info dmi;
|
||||
uint64_t start, length, val64;
|
||||
char *target_type, *params, *rcipher, *key_, *rdevice, *endp, buffer[3];
|
||||
char *target_type, *params, *rcipher, *key_, *rdevice, *endp, buffer[3], *arg;
|
||||
const char *tmp_uuid;
|
||||
void *next = NULL;
|
||||
int i, r = -EINVAL;
|
||||
unsigned int i;
|
||||
int r = -EINVAL;
|
||||
|
||||
memset(dmd, 0, sizeof(*dmd));
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
|
||||
goto out;
|
||||
@@ -592,19 +608,20 @@ int dm_query_device(const char *name,
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp_uuid = dm_task_get_uuid(dmt);
|
||||
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
if (!target_type || strcmp(target_type, DM_CRYPT_TARGET) != 0 ||
|
||||
start != 0 || next)
|
||||
goto out;
|
||||
|
||||
if (size)
|
||||
*size = length;
|
||||
dmd->size = length;
|
||||
|
||||
rcipher = strsep(¶ms, " ");
|
||||
/* cipher */
|
||||
if (cipher)
|
||||
*cipher = strdup(rcipher);
|
||||
if (get_flags & DM_ACTIVE_CIPHER)
|
||||
dmd->cipher = strdup(rcipher);
|
||||
|
||||
/* skip */
|
||||
key_ = strsep(¶ms, " ");
|
||||
@@ -614,57 +631,86 @@ int dm_query_device(const char *name,
|
||||
if (*params != ' ')
|
||||
goto out;
|
||||
params++;
|
||||
if (skip)
|
||||
*skip = val64;
|
||||
|
||||
dmd->iv_offset = val64;
|
||||
|
||||
/* device */
|
||||
rdevice = strsep(¶ms, " ");
|
||||
if (device)
|
||||
*device = crypt_lookup_dev(rdevice);
|
||||
if (get_flags & DM_ACTIVE_DEVICE)
|
||||
dmd->device = crypt_lookup_dev(rdevice);
|
||||
|
||||
/*offset */
|
||||
if (!params)
|
||||
goto out;
|
||||
val64 = strtoull(params, ¶ms, 10);
|
||||
if (*params)
|
||||
dmd->offset = val64;
|
||||
|
||||
/* Features section, available since crypt target version 1.11 */
|
||||
if (*params) {
|
||||
if (*params != ' ')
|
||||
goto out;
|
||||
params++;
|
||||
|
||||
/* Number of arguments */
|
||||
val64 = strtoull(params, ¶ms, 10);
|
||||
if (*params != ' ')
|
||||
goto out;
|
||||
params++;
|
||||
|
||||
for (i = 0; i < val64; i++) {
|
||||
if (!params)
|
||||
goto out;
|
||||
arg = strsep(¶ms, " ");
|
||||
if (!strcasecmp(arg, "allow_discards"))
|
||||
dmd->flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
|
||||
else /* unknown option */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* All parameters shold be processed */
|
||||
if (params)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Never allow to return empty key */
|
||||
if ((get_flags & DM_ACTIVE_KEY) && dmi.suspended) {
|
||||
log_dbg("Cannot read volume key while suspended.");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
if (offset)
|
||||
*offset = val64;
|
||||
}
|
||||
|
||||
/* key_size */
|
||||
if (key_size)
|
||||
*key_size = strlen(key_) / 2;
|
||||
|
||||
/* key */
|
||||
if (key_size && key) {
|
||||
*key = crypt_safe_alloc(*key_size);
|
||||
if (!*key) {
|
||||
if (get_flags & DM_ACTIVE_KEYSIZE) {
|
||||
dmd->vk = crypt_alloc_volume_key(strlen(key_) / 2, NULL);
|
||||
if (!dmd->vk) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buffer[2] = '\0';
|
||||
for(i = 0; i < *key_size; i++) {
|
||||
memcpy(buffer, &key_[i * 2], 2);
|
||||
(*key)[i] = strtoul(buffer, &endp, 16);
|
||||
if (endp != &buffer[2]) {
|
||||
crypt_safe_free(key);
|
||||
*key = NULL;
|
||||
goto out;
|
||||
if (get_flags & DM_ACTIVE_KEY) {
|
||||
buffer[2] = '\0';
|
||||
for(i = 0; i < dmd->vk->keylength; i++) {
|
||||
memcpy(buffer, &key_[i * 2], 2);
|
||||
dmd->vk->key[i] = strtoul(buffer, &endp, 16);
|
||||
if (endp != &buffer[2]) {
|
||||
crypt_free_volume_key(dmd->vk);
|
||||
dmd->vk = NULL;
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
memset(key_, 0, strlen(key_));
|
||||
|
||||
if (read_only)
|
||||
*read_only = dmi.read_only;
|
||||
if (dmi.read_only)
|
||||
dmd->flags |= CRYPT_ACTIVATE_READONLY;
|
||||
|
||||
if (suspended)
|
||||
*suspended = dmi.suspended;
|
||||
|
||||
if (uuid && (tmp_uuid = dm_task_get_uuid(dmt)) &&
|
||||
!strncmp(tmp_uuid, DM_UUID_PREFIX, DM_UUID_PREFIX_LEN))
|
||||
*uuid = strdup(tmp_uuid + DM_UUID_PREFIX_LEN);
|
||||
if (!tmp_uuid)
|
||||
dmd->flags |= CRYPT_ACTIVATE_NO_UUID;
|
||||
else if (get_flags & DM_ACTIVE_UUID) {
|
||||
if (!strncmp(tmp_uuid, DM_UUID_PREFIX, DM_UUID_PREFIX_LEN))
|
||||
dmd->uuid = strdup(tmp_uuid + DM_UUID_PREFIX_LEN);
|
||||
}
|
||||
|
||||
r = (dmi.open_count > 0);
|
||||
out:
|
||||
@@ -764,3 +810,26 @@ int dm_is_dm_kernel_name(const char *name)
|
||||
{
|
||||
return strncmp(name, "dm-", 3) ? 0 : 1;
|
||||
}
|
||||
|
||||
int dm_check_segment(const char *name, uint64_t offset, uint64_t size)
|
||||
{
|
||||
struct crypt_dm_active_device dmd;
|
||||
int r;
|
||||
|
||||
log_dbg("Checking segments for device %s.", name);
|
||||
|
||||
r = dm_query_device(name, 0, &dmd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (offset >= (dmd.offset + dmd.size) || (offset + size) <= dmd.offset)
|
||||
r = 0;
|
||||
else
|
||||
r = -EBUSY;
|
||||
|
||||
log_dbg("seg: %" PRIu64 " - %" PRIu64 ", new %" PRIu64 " - %" PRIu64 "%s",
|
||||
dmd.offset, dmd.offset + dmd.size, offset, offset + size,
|
||||
r ? " (overlapping)" : " (ok)");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -185,22 +185,24 @@ int LOOPAES_activate(struct crypt_device *cd,
|
||||
const char *base_cipher,
|
||||
unsigned int keys_count,
|
||||
struct volume_key *vk,
|
||||
uint64_t offset,
|
||||
uint64_t skip,
|
||||
uint32_t flags)
|
||||
{
|
||||
uint64_t size;
|
||||
char *cipher = NULL;
|
||||
uint32_t req_flags;
|
||||
char *cipher;
|
||||
const char *device;
|
||||
int read_only, r;
|
||||
int r;
|
||||
struct crypt_dm_active_device dmd = {
|
||||
.device = crypt_get_device_name(cd),
|
||||
.cipher = NULL,
|
||||
.uuid = crypt_get_uuid(cd),
|
||||
.vk = vk,
|
||||
.offset = crypt_get_data_offset(cd),
|
||||
.iv_offset = crypt_get_iv_offset(cd),
|
||||
.size = 0,
|
||||
.flags = flags
|
||||
};
|
||||
|
||||
size = 0;
|
||||
/* Initial IV (skip) is always the same as offset */
|
||||
device = crypt_get_device_name(cd);
|
||||
read_only = flags & CRYPT_ACTIVATE_READONLY;
|
||||
|
||||
r = device_check_and_adjust(cd, device, 1, &size, &offset, &read_only);
|
||||
r = device_check_and_adjust(cd, dmd.device, DEV_EXCL, &dmd.size, &dmd.offset, &flags);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@@ -214,12 +216,10 @@ int LOOPAES_activate(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
log_dbg("Trying to activate loop-AES device %s using cipher %s.", name, cipher);
|
||||
r = dm_create_device(name, device,
|
||||
cipher, CRYPT_LOOPAES,
|
||||
crypt_get_uuid(cd),
|
||||
size, skip, offset, vk->keylength, vk->key,
|
||||
read_only, 0);
|
||||
dmd.cipher = cipher;
|
||||
log_dbg("Trying to activate loop-AES device %s using cipher %s.", name, dmd.cipher);
|
||||
|
||||
r = dm_create_device(name, CRYPT_LOOPAES, &dmd, 0);
|
||||
|
||||
if (!r && !(dm_flags() & req_flags)) {
|
||||
log_err(cd, _("Kernel doesn't support loop-AES compatible mapping.\n"));
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include <unistd.h>
|
||||
#include "config.h"
|
||||
|
||||
struct crypt_device;
|
||||
struct volume_key;
|
||||
|
||||
#define LOOPAES_KEYS_MAX 65
|
||||
|
||||
int LOOPAES_parse_keyfile(struct crypt_device *cd,
|
||||
@@ -18,7 +21,5 @@ int LOOPAES_activate(struct crypt_device *cd,
|
||||
const char *base_cipher,
|
||||
unsigned int keys_count,
|
||||
struct volume_key *vk,
|
||||
uint64_t offset,
|
||||
uint64_t skip,
|
||||
uint32_t flags);
|
||||
#endif
|
||||
|
||||
@@ -51,12 +51,21 @@ static int devfd=-1;
|
||||
|
||||
static int setup_mapping(const char *cipher, const char *name,
|
||||
const char *device,
|
||||
const char *key, size_t keyLength,
|
||||
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);
|
||||
uint64_t size;
|
||||
struct crypt_dm_active_device dmd = {
|
||||
.device = device,
|
||||
.cipher = cipher,
|
||||
.uuid = NULL,
|
||||
.vk = vk,
|
||||
.offset = sector,
|
||||
.iv_offset = 0,
|
||||
.size = 0,
|
||||
.flags = (mode == O_RDONLY) ? CRYPT_ACTIVATE_READONLY : 0
|
||||
};
|
||||
|
||||
/*
|
||||
* we need to round this to nearest multiple of the underlying
|
||||
@@ -66,11 +75,11 @@ static int setup_mapping(const char *cipher, const char *name,
|
||||
log_err(ctx, _("Unable to obtain sector size for %s"), device);
|
||||
return -EINVAL;
|
||||
}
|
||||
size = round_up_modulo(srcLength,device_sector_size)/SECTOR_SIZE;
|
||||
cleaner_size = size;
|
||||
|
||||
return dm_create_device(name, device, cipher, "TEMP", NULL, size, 0, sector,
|
||||
keyLength, key, (mode == O_RDONLY), 0);
|
||||
dmd.size = round_up_modulo(srcLength,device_sector_size)/SECTOR_SIZE;
|
||||
cleaner_size = dmd.size;
|
||||
|
||||
return dm_create_device(name, "TEMP", &dmd, 0);
|
||||
}
|
||||
|
||||
static void sigint_handler(int sig __attribute__((unused)))
|
||||
@@ -88,29 +97,10 @@ static void sigint_handler(int sig __attribute__((unused)))
|
||||
static const char *_error_hint(char *cipherMode, size_t keyLength)
|
||||
{
|
||||
const char *hint= "";
|
||||
#ifdef __linux__
|
||||
char c, tmp[4] = {0};
|
||||
struct utsname uts;
|
||||
int i = 0, kernel_minor;
|
||||
|
||||
/* Nothing to suggest here */
|
||||
if (uname(&uts) || strncmp(uts.release, "2.6.", 4))
|
||||
return hint;
|
||||
|
||||
/* Get kernel minor without suffixes */
|
||||
while (i < 3 && (c = uts.release[i + 4]))
|
||||
tmp[i++] = isdigit(c) ? c : '\0';
|
||||
kernel_minor = atoi(tmp);
|
||||
|
||||
if (!strncmp(cipherMode, "xts", 3) && (keyLength != 256 && keyLength != 512))
|
||||
hint = _("Key size in XTS mode must be 256 or 512 bits.\n");
|
||||
else if (!strncmp(cipherMode, "xts", 3) && kernel_minor < 24)
|
||||
hint = _("Block mode XTS is available since kernel 2.6.24.\n");
|
||||
if (!strncmp(cipherMode, "lrw", 3) && (keyLength != 256 && keyLength != 512))
|
||||
hint = _("Key size in LRW mode must be 256 or 512 bits.\n");
|
||||
else if (!strncmp(cipherMode, "lrw", 3) && kernel_minor < 20)
|
||||
hint = _("Block mode LRW is available since kernel 2.6.20.\n");
|
||||
#endif
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
@@ -118,7 +108,7 @@ static const char *_error_hint(char *cipherMode, size_t keyLength)
|
||||
handler and global vars for cleaning */
|
||||
static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
struct luks_phdr *hdr,
|
||||
char *key, size_t keyLength,
|
||||
struct volume_key *vk,
|
||||
const char *device,
|
||||
unsigned int sector,
|
||||
ssize_t (*func)(int, void *, size_t),
|
||||
@@ -146,12 +136,12 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
cleaner_name = name;
|
||||
|
||||
r = setup_mapping(dmCipherSpec, name, device,
|
||||
key, keyLength, sector, srcLength, mode, ctx);
|
||||
vk, sector, srcLength, mode, ctx);
|
||||
if(r < 0) {
|
||||
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,
|
||||
_error_hint(hdr->cipherMode, keyLength * 8));
|
||||
_error_hint(hdr->cipherMode, vk->keylength * 8));
|
||||
r = -EIO;
|
||||
goto out1;
|
||||
}
|
||||
@@ -188,22 +178,22 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
|
||||
int LUKS_encrypt_to_storage(char *src, size_t srcLength,
|
||||
struct luks_phdr *hdr,
|
||||
char *key, size_t keyLength,
|
||||
struct volume_key *vk,
|
||||
const char *device,
|
||||
unsigned int sector,
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
return LUKS_endec_template(src,srcLength,hdr,key,keyLength, device,
|
||||
return LUKS_endec_template(src,srcLength,hdr,vk, device,
|
||||
sector, write_blockwise, O_RDWR, ctx);
|
||||
}
|
||||
|
||||
int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
struct luks_phdr *hdr,
|
||||
char *key, size_t keyLength,
|
||||
struct volume_key *vk,
|
||||
const char *device,
|
||||
unsigned int sector,
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
return LUKS_endec_template(dst,dstLength,hdr,key,keyLength, device,
|
||||
return LUKS_endec_template(dst,dstLength,hdr,vk, device,
|
||||
sector, read_blockwise, O_RDONLY, ctx);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
@@ -29,6 +27,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "luks.h"
|
||||
@@ -46,6 +45,79 @@ 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)
|
||||
{
|
||||
uint64_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);
|
||||
|
||||
for (i = 0; i < LUKS_NUMKEYS; i++) {
|
||||
sector = round_up_modulo(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)
|
||||
{
|
||||
uint64_t dev_size, req_sectors;
|
||||
|
||||
req_sectors = LUKS_device_sectors(keyLength, LUKS_STRIPES);
|
||||
if (min_sectors > req_sectors)
|
||||
req_sectors = min_sectors;
|
||||
|
||||
if(device_size(device, &dev_size)) {
|
||||
log_dbg("Cannot get device size for device %s.", device);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return (req_sectors > (dev_size >> SECTOR_SHIFT));
|
||||
}
|
||||
|
||||
/* Check keyslot to prevent access outside of header and keyslot area */
|
||||
static int LUKS_check_keyslot_size(const struct luks_phdr *phdr, unsigned int keyIndex)
|
||||
{
|
||||
uint32_t secs_per_stripes;
|
||||
|
||||
/* First sectors is the header itself */
|
||||
if (phdr->keyblock[keyIndex].keyMaterialOffset * SECTOR_SIZE < LUKS_ALIGN_KEYSLOTS) {
|
||||
log_dbg("Invalid offset %u in keyslot %u.",
|
||||
phdr->keyblock[keyIndex].keyMaterialOffset, keyIndex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Ignore following check for detached header where offset can be zero. */
|
||||
if (phdr->payloadOffset == 0)
|
||||
return 0;
|
||||
|
||||
if (phdr->payloadOffset <= phdr->keyblock[keyIndex].keyMaterialOffset) {
|
||||
log_dbg("Invalid offset %u in keyslot %u (beyond data area offset %u).",
|
||||
phdr->keyblock[keyIndex].keyMaterialOffset, keyIndex,
|
||||
phdr->payloadOffset);
|
||||
return 1;
|
||||
}
|
||||
|
||||
secs_per_stripes = div_round_up(phdr->keyBytes * phdr->keyblock[keyIndex].stripes, SECTOR_SIZE);
|
||||
|
||||
if (phdr->payloadOffset < (phdr->keyblock[keyIndex].keyMaterialOffset + secs_per_stripes)) {
|
||||
log_dbg("Invalid keyslot size %u (offset %u, stripes %u) in "
|
||||
"keyslot %u (beyond data area offset %u).",
|
||||
secs_per_stripes,
|
||||
phdr->keyblock[keyIndex].keyMaterialOffset,
|
||||
phdr->keyblock[keyIndex].stripes,
|
||||
keyIndex, phdr->payloadOffset);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *dbg_slot_state(crypt_keyslot_info ki)
|
||||
{
|
||||
switch(ki) {
|
||||
@@ -148,7 +220,7 @@ int LUKS_hdr_restore(
|
||||
buffer_size = hdr_file.payloadOffset << SECTOR_SHIFT;
|
||||
|
||||
if (r || buffer_size < LUKS_ALIGN_KEYSLOTS) {
|
||||
log_err(ctx, _("Backup file do not contain valid LUKS header.\n"));
|
||||
log_err(ctx, _("Backup file doesn't contain valid LUKS header.\n"));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -216,7 +288,7 @@ int LUKS_hdr_restore(
|
||||
close(devfd);
|
||||
|
||||
/* Be sure to reload new data */
|
||||
r = LUKS_read_phdr(device, hdr, 0, ctx);
|
||||
r = LUKS_read_phdr(device, hdr, 1, ctx);
|
||||
out:
|
||||
if (devfd != -1)
|
||||
close(devfd);
|
||||
@@ -237,8 +309,6 @@ static int _check_and_convert_hdr(const char *device,
|
||||
log_dbg("LUKS header not detected.");
|
||||
if (require_luks_device)
|
||||
log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device);
|
||||
else
|
||||
set_error(_("Device %s is not a valid LUKS device."), device);
|
||||
r = -EINVAL;
|
||||
} else if((hdr->version = ntohs(hdr->version)) != 1) { /* Convert every uint16/32_t item from network byte order */
|
||||
log_err(ctx, _("Unsupported LUKS version %d.\n"), hdr->version);
|
||||
@@ -256,7 +326,17 @@ static int _check_and_convert_hdr(const char *device,
|
||||
hdr->keyblock[i].passwordIterations = ntohl(hdr->keyblock[i].passwordIterations);
|
||||
hdr->keyblock[i].keyMaterialOffset = ntohl(hdr->keyblock[i].keyMaterialOffset);
|
||||
hdr->keyblock[i].stripes = ntohl(hdr->keyblock[i].stripes);
|
||||
if (LUKS_check_keyslot_size(hdr, i)) {
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
|
||||
// FIXME: allow header recovery
|
||||
r = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Avoid unterminated strings */
|
||||
hdr->cipherName[LUKS_CIPHERNAME_L - 1] = '\0';
|
||||
hdr->cipherMode[LUKS_CIPHERMODE_L - 1] = '\0';
|
||||
hdr->uuid[UUID_STRING_L - 1] = '\0';
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -312,7 +392,6 @@ int LUKS_read_phdr(const char *device,
|
||||
{
|
||||
ssize_t hdr_size = sizeof(struct luks_phdr);
|
||||
int devfd = 0, r = 0;
|
||||
uint64_t size;
|
||||
|
||||
log_dbg("Reading LUKS header of size %d from device %s",
|
||||
hdr_size, device);
|
||||
@@ -328,15 +407,7 @@ int LUKS_read_phdr(const char *device,
|
||||
else
|
||||
r = _check_and_convert_hdr(device, hdr, require_luks_device, ctx);
|
||||
|
||||
#ifdef BLKGETSIZE64
|
||||
if (r == 0 && (ioctl(devfd, BLKGETSIZE64, &size) < 0 ||
|
||||
size < (uint64_t)hdr->payloadOffset)) {
|
||||
log_err(ctx, _("LUKS header detected but device %s is too small.\n"), device);
|
||||
r = -EINVAL;
|
||||
}
|
||||
#endif
|
||||
close(devfd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -353,6 +424,11 @@ int LUKS_write_phdr(const char *device,
|
||||
log_dbg("Updating LUKS header of size %d on device %s",
|
||||
sizeof(struct luks_phdr), device);
|
||||
|
||||
if (LUKS_check_device_size(device, hdr->payloadOffset, hdr->keyBytes)) {
|
||||
log_err(ctx, _("Device %s is too small.\n"), device);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
devfd = open(device,O_RDWR | O_DIRECT | O_SYNC);
|
||||
if(-1 == devfd) {
|
||||
log_err(ctx, _("Cannot open device %s.\n"), device);
|
||||
@@ -412,6 +488,7 @@ 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,
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
unsigned int i=0;
|
||||
@@ -421,7 +498,8 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
int currentSector;
|
||||
char luksMagic[] = LUKS_MAGIC;
|
||||
|
||||
if (alignPayload == 0)
|
||||
/* For separate metadata device allow zero alignment */
|
||||
if (alignPayload == 0 && !metadata_device)
|
||||
alignPayload = DEFAULT_DISK_ALIGNMENT / SECTOR_SIZE;
|
||||
|
||||
if (PBKDF2_HMAC_ready(hashSpec) < 0) {
|
||||
@@ -485,10 +563,15 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
currentSector = round_up_modulo(currentSector + blocksPerStripeSet,
|
||||
LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
|
||||
}
|
||||
currentSector = round_up_modulo(currentSector, alignPayload);
|
||||
|
||||
/* alignOffset - offset from natural device alignment provided by topology info */
|
||||
header->payloadOffset = currentSector + alignOffset;
|
||||
if (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);
|
||||
header->payloadOffset = currentSector + alignOffset;
|
||||
}
|
||||
|
||||
uuid_unparse(partitionUuid, header->uuid);
|
||||
|
||||
@@ -525,7 +608,7 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
|
||||
uint64_t *PBKDF2_per_sec,
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
char derivedKey[hdr->keyBytes];
|
||||
struct volume_key *derived_key;
|
||||
char *AfKey = NULL;
|
||||
unsigned int AFEKSize;
|
||||
uint64_t PBKDF2_temp;
|
||||
@@ -560,23 +643,26 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
|
||||
|
||||
log_dbg("Key slot %d use %d password iterations.", keyIndex, hdr->keyblock[keyIndex].passwordIterations);
|
||||
|
||||
derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
|
||||
if (!derived_key)
|
||||
return -ENOMEM;
|
||||
|
||||
r = crypt_random_get(ctx, hdr->keyblock[keyIndex].passwordSalt,
|
||||
LUKS_SALTSIZE, CRYPT_RND_NORMAL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
// assert((vk->keylength % TWOFISH_BLOCKSIZE) == 0); FIXME
|
||||
|
||||
r = PBKDF2_HMAC(hdr->hashSpec, password,passwordLen,
|
||||
hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
|
||||
hdr->keyblock[keyIndex].passwordIterations,
|
||||
derivedKey, hdr->keyBytes);
|
||||
derived_key->key, hdr->keyBytes);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* AF splitting, the masterkey stored in vk->key is split to AfKey
|
||||
*/
|
||||
assert(vk->keylength == hdr->keyBytes);
|
||||
AFEKSize = hdr->keyblock[keyIndex].stripes*vk->keylength;
|
||||
AfKey = crypt_safe_alloc(AFEKSize);
|
||||
if (!AfKey) {
|
||||
@@ -596,14 +682,12 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
|
||||
r = LUKS_encrypt_to_storage(AfKey,
|
||||
AFEKSize,
|
||||
hdr,
|
||||
derivedKey,
|
||||
hdr->keyBytes,
|
||||
derived_key,
|
||||
device,
|
||||
hdr->keyblock[keyIndex].keyMaterialOffset,
|
||||
ctx);
|
||||
if (r < 0) {
|
||||
if(!get_error())
|
||||
log_err(ctx, _("Failed to write to key storage.\n"));
|
||||
log_err(ctx, _("Failed to write to key storage.\n"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -619,7 +703,7 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
|
||||
r = 0;
|
||||
out:
|
||||
crypt_safe_free(AfKey);
|
||||
memset(derivedKey, 0, sizeof(derivedKey));
|
||||
crypt_free_volume_key(derived_key);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -651,7 +735,7 @@ static int LUKS_open_key(const char *device,
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
crypt_keyslot_info ki = LUKS_keyslot_info(hdr, keyIndex);
|
||||
char derivedKey[hdr->keyBytes];
|
||||
struct volume_key *derived_key;
|
||||
char *AfKey;
|
||||
size_t AFEKSize;
|
||||
int r;
|
||||
@@ -662,8 +746,11 @@ static int LUKS_open_key(const char *device,
|
||||
if (ki < CRYPT_SLOT_ACTIVE)
|
||||
return -ENOENT;
|
||||
|
||||
// assert((vk->keylength % TWOFISH_BLOCKSIZE) == 0); FIXME
|
||||
derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
|
||||
if (!derived_key)
|
||||
return -ENOMEM;
|
||||
|
||||
assert(vk->keylength == hdr->keyBytes);
|
||||
AFEKSize = hdr->keyblock[keyIndex].stripes*vk->keylength;
|
||||
AfKey = crypt_safe_alloc(AFEKSize);
|
||||
if (!AfKey)
|
||||
@@ -672,7 +759,7 @@ static int LUKS_open_key(const char *device,
|
||||
r = PBKDF2_HMAC(hdr->hashSpec, password,passwordLen,
|
||||
hdr->keyblock[keyIndex].passwordSalt,LUKS_SALTSIZE,
|
||||
hdr->keyblock[keyIndex].passwordIterations,
|
||||
derivedKey, hdr->keyBytes);
|
||||
derived_key->key, hdr->keyBytes);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
@@ -680,8 +767,7 @@ static int LUKS_open_key(const char *device,
|
||||
r = LUKS_decrypt_from_storage(AfKey,
|
||||
AFEKSize,
|
||||
hdr,
|
||||
derivedKey,
|
||||
hdr->keyBytes,
|
||||
derived_key,
|
||||
device,
|
||||
hdr->keyblock[keyIndex].keyMaterialOffset,
|
||||
ctx);
|
||||
@@ -699,7 +785,7 @@ static int LUKS_open_key(const char *device,
|
||||
log_verbose(ctx, _("Key slot %d unlocked.\n"), keyIndex);
|
||||
out:
|
||||
crypt_safe_free(AfKey);
|
||||
memset(derivedKey, 0, sizeof(derivedKey));
|
||||
crypt_free_volume_key(derived_key);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -736,72 +822,6 @@ int LUKS_open_key_with_hdr(const char *device,
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wipe patterns according to Gutmann's Paper
|
||||
*/
|
||||
|
||||
static void wipeSpecial(char *buffer, size_t buffer_size, unsigned int turn)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
unsigned char write_modes[][3] = {
|
||||
{"\x55\x55\x55"}, {"\xaa\xaa\xaa"}, {"\x92\x49\x24"},
|
||||
{"\x49\x24\x92"}, {"\x24\x92\x49"}, {"\x00\x00\x00"},
|
||||
{"\x11\x11\x11"}, {"\x22\x22\x22"}, {"\x33\x33\x33"},
|
||||
{"\x44\x44\x44"}, {"\x55\x55\x55"}, {"\x66\x66\x66"},
|
||||
{"\x77\x77\x77"}, {"\x88\x88\x88"}, {"\x99\x99\x99"},
|
||||
{"\xaa\xaa\xaa"}, {"\xbb\xbb\xbb"}, {"\xcc\xcc\xcc"},
|
||||
{"\xdd\xdd\xdd"}, {"\xee\xee\xee"}, {"\xff\xff\xff"},
|
||||
{"\x92\x49\x24"}, {"\x49\x24\x92"}, {"\x24\x92\x49"},
|
||||
{"\x6d\xb6\xdb"}, {"\xb6\xdb\x6d"}, {"\xdb\x6d\xb6"}
|
||||
};
|
||||
|
||||
for(i = 0; i < buffer_size / 3; ++i) {
|
||||
memcpy(buffer, write_modes[turn], 3);
|
||||
buffer += 3;
|
||||
}
|
||||
}
|
||||
|
||||
static int wipe(const char *device, unsigned int from, unsigned int to)
|
||||
{
|
||||
int devfd, r = 0;
|
||||
char *buffer;
|
||||
unsigned int i, bufLen;
|
||||
ssize_t written;
|
||||
|
||||
devfd = open(device, O_RDWR | O_DIRECT | O_SYNC);
|
||||
if(devfd == -1)
|
||||
return -EINVAL;
|
||||
|
||||
bufLen = (to - from) * SECTOR_SIZE;
|
||||
buffer = malloc(bufLen);
|
||||
if(!buffer) {
|
||||
close(devfd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for(i = 0; i < 39; ++i) {
|
||||
if (i < 5) crypt_random_get(NULL, buffer, bufLen,
|
||||
CRYPT_RND_NORMAL);
|
||||
else if(i >= 5 && i < 32) wipeSpecial(buffer, bufLen, i - 5);
|
||||
else if(i >= 32 && i < 38) crypt_random_get(NULL, buffer, bufLen,
|
||||
CRYPT_RND_NORMAL);
|
||||
else if(i >= 38 && i < 39) memset(buffer, 0xFF, bufLen);
|
||||
|
||||
written = write_lseek_blockwise(devfd, buffer, bufLen,
|
||||
from * SECTOR_SIZE);
|
||||
if (written < 0 || written != bufLen) {
|
||||
r = -EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
close(devfd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS_del_key(const char *device,
|
||||
unsigned int keyIndex,
|
||||
struct luks_phdr *hdr,
|
||||
@@ -826,7 +846,9 @@ int LUKS_del_key(const char *device,
|
||||
stripesLen = hdr->keyBytes * hdr->keyblock[keyIndex].stripes;
|
||||
endOffset = startOffset + div_round_up(stripesLen, SECTOR_SIZE);
|
||||
|
||||
r = wipe(device, startOffset, endOffset);
|
||||
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);
|
||||
return r;
|
||||
@@ -897,3 +919,37 @@ int LUKS_keyslot_set(struct luks_phdr *hdr, int keyslot, int enable)
|
||||
log_dbg("Key slot %d was %s in LUKS header.", keyslot, enable ? "enabled" : "disabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS1_activate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vk,
|
||||
uint32_t flags)
|
||||
{
|
||||
int r;
|
||||
char *dm_cipher = NULL;
|
||||
struct crypt_dm_active_device dmd = {
|
||||
.device = crypt_get_device_name(cd),
|
||||
.cipher = NULL,
|
||||
.uuid = crypt_get_uuid(cd),
|
||||
.vk = vk,
|
||||
.offset = crypt_get_data_offset(cd),
|
||||
.iv_offset = 0,
|
||||
.size = 0,
|
||||
.flags = flags
|
||||
};
|
||||
|
||||
r = device_check_and_adjust(cd, dmd.device, DEV_EXCL,
|
||||
&dmd.size, &dmd.offset, &flags);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = asprintf(&dm_cipher, "%s-%s", crypt_get_cipher(cd), crypt_get_cipher_mode(cd));
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
dmd.cipher = dm_cipher;
|
||||
r = dm_create_device(name, CRYPT_LUKS1, &dmd, 0);
|
||||
|
||||
free(dm_cipher);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ int LUKS_generate_phdr(
|
||||
unsigned int alignOffset,
|
||||
uint32_t iteration_time_ms,
|
||||
uint64_t *PBKDF2_per_sec,
|
||||
const char *metadata_device,
|
||||
struct crypt_device *ctx);
|
||||
|
||||
int LUKS_read_phdr(
|
||||
@@ -160,7 +161,7 @@ int LUKS_keyslot_set(struct luks_phdr *hdr, int keyslot, int enable);
|
||||
int LUKS_encrypt_to_storage(
|
||||
char *src, size_t srcLength,
|
||||
struct luks_phdr *hdr,
|
||||
char *key, size_t keyLength,
|
||||
struct volume_key *vk,
|
||||
const char *device,
|
||||
unsigned int sector,
|
||||
struct crypt_device *ctx);
|
||||
@@ -168,9 +169,14 @@ int LUKS_encrypt_to_storage(
|
||||
int LUKS_decrypt_from_storage(
|
||||
char *dst, size_t dstLength,
|
||||
struct luks_phdr *hdr,
|
||||
char *key, size_t keyLength,
|
||||
struct volume_key *vk,
|
||||
const char *device,
|
||||
unsigned int sector,
|
||||
struct crypt_device *ctx);
|
||||
|
||||
int LUKS1_activate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vk,
|
||||
uint32_t flags);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -167,9 +167,6 @@ static int pkcs5_pbkdf2(const char *hash,
|
||||
memset(T, 0, hLen);
|
||||
|
||||
for (u = 1; u <= c ; u++) {
|
||||
if (crypt_hmac_restart(hmac))
|
||||
goto out;
|
||||
|
||||
if (u == 1) {
|
||||
memcpy(tmp, S, Slen);
|
||||
tmp[Slen + 0] = (i & 0xff000000) >> 24;
|
||||
|
||||
1336
lib/setup.c
1336
lib/setup.c
File diff suppressed because it is too large
Load Diff
140
lib/utils.c
140
lib/utils.c
@@ -38,46 +38,6 @@
|
||||
#include "libcryptsetup.h"
|
||||
#include "internal.h"
|
||||
|
||||
static char *error=NULL;
|
||||
|
||||
__attribute__((format(printf, 1, 0)))
|
||||
void set_error_va(const char *fmt, va_list va)
|
||||
{
|
||||
int r;
|
||||
|
||||
if(error) {
|
||||
free(error);
|
||||
error = NULL;
|
||||
}
|
||||
|
||||
if(!fmt) return;
|
||||
|
||||
r = vasprintf(&error, fmt, va);
|
||||
if (r < 0) {
|
||||
free(error);
|
||||
error = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (r && error[r - 1] == '\n')
|
||||
error[r - 1] = '\0';
|
||||
}
|
||||
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
void set_error(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
set_error_va(fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
const char *get_error(void)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
static int get_alignment(int fd)
|
||||
{
|
||||
int alignment = DEFAULT_MEM_ALIGNMENT;
|
||||
@@ -336,10 +296,23 @@ int device_ready(struct crypt_device *cd, const char *device, int mode)
|
||||
return r;
|
||||
}
|
||||
|
||||
int get_device_infos(const char *device,
|
||||
int open_exclusive,
|
||||
int *readonly,
|
||||
uint64_t *size)
|
||||
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;
|
||||
@@ -353,7 +326,7 @@ int get_device_infos(const char *device,
|
||||
return -EINVAL;
|
||||
|
||||
/* never wipe header on mounted device */
|
||||
if (open_exclusive && S_ISBLK(st.st_mode))
|
||||
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 */
|
||||
@@ -363,7 +336,7 @@ int get_device_infos(const char *device,
|
||||
fd = open(device, O_RDONLY | flags);
|
||||
}
|
||||
|
||||
if (fd == -1 && open_exclusive && errno == EBUSY)
|
||||
if (fd == -1 && device_check == DEV_EXCL && errno == EBUSY)
|
||||
return -EBUSY;
|
||||
|
||||
if (fd == -1)
|
||||
@@ -396,10 +369,10 @@ out:
|
||||
|
||||
int device_check_and_adjust(struct crypt_device *cd,
|
||||
const char *device,
|
||||
int open_exclusive,
|
||||
enum devcheck device_check,
|
||||
uint64_t *size,
|
||||
uint64_t *offset,
|
||||
int *read_only)
|
||||
uint32_t *flags)
|
||||
{
|
||||
int r, real_readonly;
|
||||
uint64_t real_size;
|
||||
@@ -407,7 +380,7 @@ int device_check_and_adjust(struct crypt_device *cd,
|
||||
if (!device)
|
||||
return -ENOTBLK;
|
||||
|
||||
r = get_device_infos(device, open_exclusive, &real_readonly, &real_size);
|
||||
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 "
|
||||
@@ -419,62 +392,49 @@ int device_check_and_adjust(struct crypt_device *cd,
|
||||
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;
|
||||
}
|
||||
if (*size < *offset) {
|
||||
log_err(cd, _("Device %s is too small.\n"), device);
|
||||
return -EINVAL;
|
||||
}
|
||||
*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 (device_check == DEV_SHARED) {
|
||||
log_dbg("Checking crypt segments for device %s.", device);
|
||||
r = crypt_sysfs_check_crypt_segment(device, *offset, *size);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Cannot use device %s (crypt segments "
|
||||
"overlaps or in use by another device).\n"),
|
||||
device);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (real_readonly)
|
||||
*read_only = 1;
|
||||
*flags |= CRYPT_ACTIVATE_READONLY;
|
||||
|
||||
log_dbg("Calculated device size is %" PRIu64 " sectors (%s), offset %" PRIu64 ".",
|
||||
*size, *read_only ? "RO" : "RW", *offset);
|
||||
*size, real_readonly ? "RO" : "RW", *offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wipe_device_header(const char *device, int sectors)
|
||||
{
|
||||
struct stat st;
|
||||
char *buffer;
|
||||
int size = sectors * SECTOR_SIZE;
|
||||
int r = -1;
|
||||
int devfd;
|
||||
int flags = O_RDWR | O_DIRECT | O_SYNC;
|
||||
|
||||
if (stat(device, &st) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* never wipe header on mounted device */
|
||||
if (S_ISBLK(st.st_mode))
|
||||
flags |= O_EXCL;
|
||||
|
||||
devfd = open(device, flags);
|
||||
if(devfd == -1)
|
||||
return errno == EBUSY ? -EBUSY : -EINVAL;
|
||||
|
||||
buffer = malloc(size);
|
||||
if (!buffer) {
|
||||
close(devfd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(buffer, 0, size);
|
||||
|
||||
r = write_blockwise(devfd, buffer, size) < size ? -EIO : 0;
|
||||
|
||||
free(buffer);
|
||||
close(devfd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* MEMLOCK */
|
||||
#define DEFAULT_PROCESS_PRIORITY -18
|
||||
|
||||
|
||||
@@ -235,6 +235,7 @@ static int crypt_get_key_tty(const char *prompt,
|
||||
|
||||
if (strncmp(pass, pass_verify, key_size_max)) {
|
||||
log_err(cd, _("Passphrases do not match.\n"));
|
||||
r = -EPERM;
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,11 +24,15 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "utils_dm.h"
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -146,7 +150,7 @@ char *crypt_lookup_dev(const char *dev_id)
|
||||
devname++;
|
||||
|
||||
if (dm_is_dm_kernel_name(devname))
|
||||
devpath = dm_device_path(major, minor);
|
||||
devpath = dm_device_path("/dev/mapper/", major, minor);
|
||||
else if (snprintf(path, sizeof(path), "/dev/%s", devname) > 0)
|
||||
devpath = strdup(path);
|
||||
|
||||
@@ -163,3 +167,102 @@ 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};
|
||||
int fd, r;
|
||||
|
||||
if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/queue/rotational",
|
||||
major, minor) < 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;
|
||||
|
||||
if (sscanf(tmp, "%d", rotational) != 1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -5,41 +5,56 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
struct crypt_device;
|
||||
struct volume_key;
|
||||
|
||||
/* Device mapper backend - kernel support flags */
|
||||
#define DM_KEY_WIPE_SUPPORTED (1 << 0) /* key wipe message */
|
||||
#define DM_LMK_SUPPORTED (1 << 1) /* lmk mode */
|
||||
#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 */
|
||||
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)
|
||||
|
||||
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 */
|
||||
uint64_t size; /* active device size */
|
||||
uint32_t flags; /* activation flags */
|
||||
};
|
||||
|
||||
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_query_device(const char *name,
|
||||
char **device,
|
||||
uint64_t *size,
|
||||
uint64_t *skip,
|
||||
uint64_t *offset,
|
||||
char **cipher,
|
||||
int *key_size,
|
||||
char **key,
|
||||
int *read_only,
|
||||
int *suspended,
|
||||
char **uuid);
|
||||
int dm_create_device(const char *name, const char *device, const char *cipher,
|
||||
const char *type, const char *uuid,
|
||||
uint64_t size, uint64_t skip, uint64_t offset,
|
||||
size_t key_size, const char *key,
|
||||
int read_only, int reload);
|
||||
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(int major, int minor);
|
||||
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 */
|
||||
|
||||
@@ -29,7 +29,17 @@
|
||||
|
||||
#include "utils_loop.h"
|
||||
|
||||
char *crypt_loop_get_device(void)
|
||||
#define LOOP_DEV_MAJOR 7
|
||||
|
||||
#ifndef LO_FLAGS_AUTOCLEAR
|
||||
#define LO_FLAGS_AUTOCLEAR 4
|
||||
#endif
|
||||
|
||||
#ifndef LOOP_CTL_GET_FREE
|
||||
#define LOOP_CTL_GET_FREE 0x4C82
|
||||
#endif
|
||||
|
||||
static char *crypt_loop_get_device_old(void)
|
||||
{
|
||||
char dev[20];
|
||||
int i, loop_fd;
|
||||
@@ -56,6 +66,32 @@ char *crypt_loop_get_device(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *crypt_loop_get_device(void)
|
||||
{
|
||||
char dev[64];
|
||||
int i, loop_fd;
|
||||
struct stat st;
|
||||
|
||||
loop_fd = open("/dev/loop-control", O_RDONLY);
|
||||
if (loop_fd < 0)
|
||||
return crypt_loop_get_device_old();
|
||||
|
||||
i = ioctl(loop_fd, LOOP_CTL_GET_FREE);
|
||||
if (i < 0) {
|
||||
close(loop_fd);
|
||||
return NULL;
|
||||
}
|
||||
close(loop_fd);
|
||||
|
||||
if (sprintf(dev, "/dev/loop%d", i) < 0)
|
||||
return NULL;
|
||||
|
||||
if (stat(dev, &st) || !S_ISBLK(st.st_mode))
|
||||
return NULL;
|
||||
|
||||
return strdup(dev);
|
||||
}
|
||||
|
||||
int crypt_loop_attach(const char *loop, const char *file, int offset,
|
||||
int autoclear, int *readonly)
|
||||
{
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
|
||||
/* loopback device helpers */
|
||||
|
||||
#define LOOP_DEV_MAJOR 7
|
||||
|
||||
#ifndef LO_FLAGS_AUTOCLEAR
|
||||
#define LO_FLAGS_AUTOCLEAR 4
|
||||
#endif
|
||||
|
||||
char *crypt_loop_get_device(void);
|
||||
char *crypt_loop_backing_file(const char *loop);
|
||||
int crypt_loop_device(const char *loop);
|
||||
|
||||
172
lib/utils_wipe.c
Normal file
172
lib/utils_wipe.c
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* utils_wipe - wipe a device
|
||||
*
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2011, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "libcryptsetup.h"
|
||||
#include "internal.h"
|
||||
|
||||
#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)
|
||||
{
|
||||
memset(buffer, 0, size);
|
||||
return write_lseek_blockwise(fd, buffer, size, offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wipe using Peter Gutmann method described in
|
||||
* http://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html
|
||||
*/
|
||||
static void wipeSpecial(char *buffer, size_t buffer_size, unsigned int turn)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
unsigned char write_modes[][3] = {
|
||||
{"\x55\x55\x55"}, {"\xaa\xaa\xaa"}, {"\x92\x49\x24"},
|
||||
{"\x49\x24\x92"}, {"\x24\x92\x49"}, {"\x00\x00\x00"},
|
||||
{"\x11\x11\x11"}, {"\x22\x22\x22"}, {"\x33\x33\x33"},
|
||||
{"\x44\x44\x44"}, {"\x55\x55\x55"}, {"\x66\x66\x66"},
|
||||
{"\x77\x77\x77"}, {"\x88\x88\x88"}, {"\x99\x99\x99"},
|
||||
{"\xaa\xaa\xaa"}, {"\xbb\xbb\xbb"}, {"\xcc\xcc\xcc"},
|
||||
{"\xdd\xdd\xdd"}, {"\xee\xee\xee"}, {"\xff\xff\xff"},
|
||||
{"\x92\x49\x24"}, {"\x49\x24\x92"}, {"\x24\x92\x49"},
|
||||
{"\x6d\xb6\xdb"}, {"\xb6\xdb\x6d"}, {"\xdb\x6d\xb6"}
|
||||
};
|
||||
|
||||
for(i = 0; i < buffer_size / 3; ++i) {
|
||||
memcpy(buffer, write_modes[turn], 3);
|
||||
buffer += 3;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t _crypt_wipe_disk(int fd, char *buffer, uint64_t offset, uint64_t size)
|
||||
{
|
||||
unsigned int i;
|
||||
ssize_t written;
|
||||
|
||||
for(i = 0; i < 39; ++i) {
|
||||
if (i < 5) crypt_random_get(NULL, buffer, size, CRYPT_RND_NORMAL);
|
||||
else if(i >= 5 && i < 32) wipeSpecial(buffer, size, i - 5);
|
||||
else if(i >= 32 && i < 38) crypt_random_get(NULL, buffer, size, CRYPT_RND_NORMAL);
|
||||
else if(i >= 38 && i < 39) memset(buffer, 0xFF, size);
|
||||
|
||||
written = write_lseek_blockwise(fd, buffer, size, offset);
|
||||
if (written < 0 || written != (ssize_t)size)
|
||||
return written;
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
static ssize_t _crypt_wipe_random(int fd, char *buffer, uint64_t offset, uint64_t size)
|
||||
{
|
||||
crypt_random_get(NULL, buffer, size, CRYPT_RND_NORMAL);
|
||||
return write_lseek_blockwise(fd, buffer, size, offset);
|
||||
}
|
||||
|
||||
static ssize_t _crypt_wipe_ssd(int fd, char *buffer, uint64_t offset, uint64_t size)
|
||||
{
|
||||
// FIXME: for now just rewrite it by random
|
||||
return _crypt_wipe_random(fd, buffer, offset, size);
|
||||
}
|
||||
|
||||
int crypt_wipe(const char *device,
|
||||
uint64_t offset,
|
||||
uint64_t size,
|
||||
crypt_wipe_type type,
|
||||
int exclusive)
|
||||
{
|
||||
struct stat st;
|
||||
char *buffer;
|
||||
int devfd, flags, rotational;
|
||||
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);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (stat(device, &st) < 0) {
|
||||
log_dbg("Device %s not found.", device);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (type == CRYPT_WIPE_DISK) {
|
||||
if (!crypt_sysfs_get_rotational(major(st.st_rdev),
|
||||
minor(st.st_rdev),
|
||||
&rotational))
|
||||
rotational = 1;
|
||||
log_dbg("Rotational flag is %d.", rotational);
|
||||
if (!rotational)
|
||||
type = CRYPT_WIPE_SSD;
|
||||
}
|
||||
|
||||
buffer = malloc(size);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
flags = O_WRONLY | O_DIRECT | O_SYNC;
|
||||
|
||||
/* use O_EXCL only for block devices */
|
||||
if (exclusive && S_ISBLK(st.st_mode))
|
||||
flags |= O_EXCL;
|
||||
|
||||
devfd = open(device, flags);
|
||||
if (devfd == -1) {
|
||||
free(buffer);
|
||||
return errno == EBUSY ? -EBUSY : -EINVAL;
|
||||
}
|
||||
|
||||
// FIXME: use fixed block size and loop here
|
||||
switch (type) {
|
||||
case CRYPT_WIPE_ZERO:
|
||||
written = _crypt_wipe_zero(devfd, buffer, offset, size);
|
||||
break;
|
||||
case CRYPT_WIPE_DISK:
|
||||
written = _crypt_wipe_disk(devfd, buffer, offset, size);
|
||||
case CRYPT_WIPE_SSD:
|
||||
written = _crypt_wipe_ssd(devfd, buffer, offset, size);
|
||||
break;
|
||||
case CRYPT_WIPE_RANDOM:
|
||||
written = _crypt_wipe_random(devfd, buffer, offset, size);
|
||||
default:
|
||||
log_dbg("Unsuported wipe type requested: (%d)", type);
|
||||
written = -1;
|
||||
}
|
||||
|
||||
close(devfd);
|
||||
free(buffer);
|
||||
|
||||
if (written != (ssize_t)size || written < 0)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -33,6 +33,8 @@ struct volume_key *crypt_alloc_volume_key(unsigned keylength, const char *key)
|
||||
vk->keylength = keylength;
|
||||
if (key)
|
||||
memcpy(&vk->key, key, keylength);
|
||||
else
|
||||
memset(&vk->key, 0, keylength);
|
||||
|
||||
return vk;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ For basic (plain) dm-crypt mappings, there are four operations.
|
||||
creates a mapping with <name> backed by device <device>.
|
||||
|
||||
\fB<options>\fR can be [\-\-hash, \-\-cipher, \-\-verify-passphrase,
|
||||
\-\-key-file, \-\-key-size, \-\-offset, \-\-skip, \-\-size, \-\-readonly]
|
||||
\-\-key-file, \-\-key-size, \-\-offset, \-\-skip, \-\-size, \-\-readonly, \-\-shared,
|
||||
\-\-allow-discards]
|
||||
.PP
|
||||
\fIremove\fR <name>
|
||||
.IP
|
||||
@@ -31,9 +32,16 @@ resizes an active mapping <name>.
|
||||
If \-\-size (in sectors) is not specified, the size of the underlying block device is used.
|
||||
.SH LUKS EXTENSION
|
||||
LUKS, Linux Unified Key Setup, is a standard for hard disk encryption.
|
||||
It standardizes a partition header, as well as the format of the bulk data.
|
||||
LUKS can manage multiple passwords, that can be revoked effectively
|
||||
and that are protected against dictionary attacks with PBKDF2.
|
||||
It standardizes a partition header as well as the format of the bulk data.
|
||||
LUKS can manage multiple passwords that can be individually revoked and
|
||||
effectively scrubbed from persistent media, and that are protected
|
||||
against dictionary attacks with PBKDF2.
|
||||
|
||||
Each password, usually called a
|
||||
.B key
|
||||
in this document, is associated with a slot, of which there are typically 8.
|
||||
Key operations that do not specify a slot affect the first slot
|
||||
matching the supplied key.
|
||||
|
||||
These are valid LUKS actions:
|
||||
|
||||
@@ -51,7 +59,8 @@ opens the LUKS partition <device> and sets up a mapping <name> after
|
||||
successful verification of the supplied key material
|
||||
(either via key file by \-\-key-file, or via prompting).
|
||||
|
||||
\fB<options>\fR can be [\-\-key-file, \-\-keyfile-size, \-\-readonly].
|
||||
\fB<options>\fR can be [\-\-key-file, \-\-keyfile-size, \-\-readonly, \-\-allow-discards,
|
||||
\-\-header, \-\-key-slot].
|
||||
.PP
|
||||
\fIluksClose\fR <name>
|
||||
.IP
|
||||
@@ -66,13 +75,15 @@ After that operation you have to use \fIluksResume\fR to reinstate
|
||||
encryption key (and resume device) or \fIluksClose\fR to remove mapped device.
|
||||
|
||||
\fBWARNING:\fR never try to suspend device where is the cryptsetup binary itself.
|
||||
|
||||
\fB<options>\fR can be [\-\-header].
|
||||
.PP
|
||||
\fIluksResume\fR <name>
|
||||
.IP
|
||||
Resumes suspended device and reinstates encryption key. You will need provide passphrase
|
||||
identical to \fIluksOpen\fR command (using prompting or key file).
|
||||
|
||||
\fB<options>\fR can be [\-\-key-file, \-\-keyfile-size]
|
||||
\fB<options>\fR can be [\-\-key-file, \-\-keyfile-size, \-\-header]
|
||||
.PP
|
||||
\fIluksAddKey\fR <device> [<new key file>]
|
||||
.IP
|
||||
@@ -84,7 +95,7 @@ The key file with the new material is supplied as a positional argument.
|
||||
.PP
|
||||
\fIluksRemoveKey\fR <device> [<key file>]
|
||||
.IP
|
||||
remove supplied key or key file from LUKS device
|
||||
remove supplied key or key file from LUKS device in the manner of \fIluksKillSlot\fR.
|
||||
.PP
|
||||
\fIluksChangeKey\fR <device> [<new key file>]
|
||||
.IP
|
||||
@@ -186,8 +197,8 @@ and not used it in IV sector calculations, you have to explicitly use
|
||||
Use \fB\-\-hash\fR to override hash function for password hashing
|
||||
(otherwise it is detected according to key size).
|
||||
|
||||
\fB<options>\fR can be [\-\-key-file, \-\-key-size, \-\-offset, \-\-skip,
|
||||
\-\-hash, \-\-readonly].
|
||||
\fB<options>\fR can be [\-\-key-file, \-\-key-size, \-\-offset, \-\-skip,
|
||||
\-\-hash, \-\-readonly, \-\-allow-discards].
|
||||
.PP
|
||||
\fIloopaesClose\fR <name>
|
||||
.IP
|
||||
@@ -284,7 +295,7 @@ to show default RNG.
|
||||
.B "\-\-key-slot, \-S"
|
||||
For LUKS operations that add key material, this options allows you
|
||||
to specify which key slot is selected for the new key.
|
||||
This option can be used for \fIluksFormat\fR and \fIluksAddKey\fR.
|
||||
This option can be used for \fIluksFormat\fR, \fIluksOpen\fR and \fIluksAddKey\fR.
|
||||
.TP
|
||||
.B "\-\-key-size, \-s"
|
||||
set key size in bits.
|
||||
@@ -319,6 +330,12 @@ This option is only relevant for \fIcreate\fR and \fIloopaesOpen\fR action.
|
||||
.B "\-\-readonly"
|
||||
set up a read-only mapping.
|
||||
.TP
|
||||
.B "\-\-shared"
|
||||
create another non-overlapping mapping to one common ciphertext device,
|
||||
e.g. to create hidden device inside another encrypted device.
|
||||
This option is only relevant for \fIcreate\fR action.
|
||||
Use \-\-offset, \-\-size and \-\-skip to specify mapped area.
|
||||
.TP
|
||||
.B "\-\-iter-time, \-i"
|
||||
The number of milliseconds to spend with PBKDF2 password processing.
|
||||
This option is only relevant to the LUKS operations as
|
||||
@@ -347,6 +364,9 @@ If not specified, cryptsetup tries to use topology info provided by kernel
|
||||
for underlying device to get optimal alignment.
|
||||
If not available (or calculated value is multiple of default) data is by
|
||||
default aligned to 1 MiB boundary (2048 512-byte sectors).
|
||||
|
||||
For detached LUKS header it specifies offset on data device.
|
||||
See also \-\-header option.
|
||||
.TP
|
||||
.B "\-\-uuid=\fIUUID\fR"
|
||||
Use provided \fIUUID\fR in \fIluksFormat\fR command instead of generating
|
||||
@@ -355,6 +375,35 @@ new one or change existing UUID in \fIluksUUID\fR command.
|
||||
The UUID must be provided in standard UUID format
|
||||
(e.g. 12345678-1234-1234-1234-123456789abc).
|
||||
.TP
|
||||
.B "\-\-allow-discards\fR"
|
||||
Allow using of discards (TRIM) requests for device.
|
||||
This option is only relevant for \fIcreate\fR, \fIluksOpen\fR or \fIloopaesOpen\fR.
|
||||
|
||||
\fBWARNING:\fR Assess the specific security risks carefully before enabling this
|
||||
option. For example, allowing discards on encrypted devices may lead to the leak
|
||||
of information about the ciphertext device (filesystem type, used space etc.)
|
||||
if the discarded blocks can be located easily on the device later.
|
||||
|
||||
Kernel version 3.1 or more recent is required.
|
||||
For older versions is the option ignored.
|
||||
.TP
|
||||
.B "\-\-header\fR"
|
||||
Set detached (separated) metadata device or file with LUKS header.
|
||||
|
||||
This options allows separation of ciphertext device and on-disk metadata header.
|
||||
|
||||
This option is only relevant for LUKS devices and can be used in \fIluksFormat\fR,
|
||||
\fIluksOpen\fR, \fIluksSuspend\fR, \fIluksResume\fR and \fIresize\fR commands.
|
||||
|
||||
If used with \fIluksFormat\fR the \-\-align-payload option is taken
|
||||
as absolute sector alignment on ciphertext device and can be zero.
|
||||
|
||||
For other commands with separated metadata device you have to always specify
|
||||
path to metadata device (not to the ciphertext device).
|
||||
|
||||
\fBWARNING:\fR There is no possible check that specified ciphertext device
|
||||
is correct if on-disk header is detached. Use with care.
|
||||
.TP
|
||||
.B "\-\-version"
|
||||
Show the version.
|
||||
.SH RETURN CODES
|
||||
|
||||
45
misc/luks-header-from-active
Executable file
45
misc/luks-header-from-active
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 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>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
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/\ .*//") ; }
|
||||
|
||||
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"
|
||||
|
||||
DEVICE=$1
|
||||
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)
|
||||
KEY=$(field 5)
|
||||
|
||||
[ -z "$CIPHER" -o -z "$OFFSET" -o "$OFFSET" -le 383 -o -z "$KEY" ] && 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"
|
||||
@@ -1,5 +1,6 @@
|
||||
cs
|
||||
de
|
||||
fi
|
||||
fr
|
||||
id
|
||||
it
|
||||
|
||||
140
src/cryptsetup.c
140
src/cryptsetup.c
@@ -29,6 +29,7 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <libcryptsetup.h>
|
||||
#include <popt.h>
|
||||
|
||||
@@ -43,6 +44,7 @@ static const char *opt_key_file = NULL;
|
||||
static const char *opt_master_key_file = NULL;
|
||||
static const char *opt_header_backup_file = NULL;
|
||||
static const char *opt_uuid = NULL;
|
||||
static const char *opt_header_device = NULL;
|
||||
static int opt_key_size = 0;
|
||||
static long opt_keyfile_size = 0;
|
||||
static long opt_new_keyfile_size = 0;
|
||||
@@ -61,6 +63,8 @@ static int opt_align_payload = 0;
|
||||
static int opt_random = 0;
|
||||
static int opt_urandom = 0;
|
||||
static int opt_dump_master_key = 0;
|
||||
static int opt_shared = 0;
|
||||
static int opt_allow_discards = 0;
|
||||
|
||||
static const char **action_argv;
|
||||
static int action_argc;
|
||||
@@ -187,6 +191,13 @@ static void _log(int level, const char *msg, void *usrptr __attribute__((unused)
|
||||
}
|
||||
}
|
||||
|
||||
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 void show_status(int errcode)
|
||||
{
|
||||
char error[256], *error_;
|
||||
@@ -224,10 +235,12 @@ static int action_create(int arg __attribute__((unused)))
|
||||
.hash = opt_hash ?: DEFAULT_PLAIN_HASH,
|
||||
.skip = opt_skip,
|
||||
.offset = opt_offset,
|
||||
.size = opt_size,
|
||||
};
|
||||
char *password = NULL;
|
||||
size_t passwordLen;
|
||||
size_t key_size = (opt_key_size ?: DEFAULT_PLAIN_KEYBITS) / 8;
|
||||
uint32_t activate_flags = 0;
|
||||
int r;
|
||||
|
||||
if (params.hash && !strcmp(params.hash, "plain"))
|
||||
@@ -262,11 +275,20 @@ static int action_create(int arg __attribute__((unused)))
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
if (opt_readonly)
|
||||
activate_flags |= CRYPT_ACTIVATE_READONLY;
|
||||
|
||||
if (opt_shared)
|
||||
activate_flags |= CRYPT_ACTIVATE_SHARED;
|
||||
|
||||
if (opt_allow_discards)
|
||||
activate_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
|
||||
|
||||
if (opt_key_file)
|
||||
/* With hashing, read the whole keyfile */
|
||||
r = crypt_activate_by_keyfile(cd, action_argv[0],
|
||||
CRYPT_ANY_SLOT, opt_key_file, params.hash ? 0 : key_size,
|
||||
opt_readonly ? CRYPT_ACTIVATE_READONLY : 0);
|
||||
activate_flags);
|
||||
else {
|
||||
r = crypt_get_key(_("Enter passphrase: "),
|
||||
&password, &passwordLen, opt_keyfile_size,
|
||||
@@ -277,17 +299,8 @@ static int action_create(int arg __attribute__((unused)))
|
||||
goto out;
|
||||
|
||||
r = crypt_activate_by_passphrase(cd, action_argv[0],
|
||||
CRYPT_ANY_SLOT, password, passwordLen,
|
||||
opt_readonly ? CRYPT_ACTIVATE_READONLY : 0);
|
||||
CRYPT_ANY_SLOT, password, passwordLen, activate_flags);
|
||||
}
|
||||
|
||||
/* FIXME: workaround, new api missing format parameter for size.
|
||||
* Properly fix it after bumping library version,
|
||||
* add start_offset and size into "PLAIN" format specifiers.
|
||||
*/
|
||||
if (r >= 0 && opt_size)
|
||||
r = crypt_resize(cd, action_argv[0], opt_size);
|
||||
|
||||
out:
|
||||
crypt_free(cd);
|
||||
crypt_safe_free(password);
|
||||
@@ -304,6 +317,7 @@ static int action_loopaesOpen(int arg __attribute__((unused)))
|
||||
.skip = opt_skip_valid ? opt_skip : opt_offset,
|
||||
};
|
||||
unsigned int key_size = (opt_key_size ?: DEFAULT_LOOPAES_KEYBITS) / 8;
|
||||
uint32_t activate_flags = 0;
|
||||
int r;
|
||||
|
||||
if (!opt_key_file) {
|
||||
@@ -311,6 +325,12 @@ static int action_loopaesOpen(int arg __attribute__((unused)))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (opt_readonly)
|
||||
activate_flags |= CRYPT_ACTIVATE_READONLY;
|
||||
|
||||
if (opt_allow_discards)
|
||||
activate_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
|
||||
|
||||
if ((r = crypt_init(&cd, action_argv[0])))
|
||||
goto out;
|
||||
|
||||
@@ -319,9 +339,8 @@ static int action_loopaesOpen(int arg __attribute__((unused)))
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = crypt_activate_by_keyfile(cd, action_argv[1],
|
||||
CRYPT_ANY_SLOT, opt_key_file, opt_keyfile_size,
|
||||
opt_readonly ? CRYPT_ACTIVATE_READONLY : 0);
|
||||
r = crypt_activate_by_keyfile(cd, action_argv[1], CRYPT_ANY_SLOT,
|
||||
opt_key_file, opt_keyfile_size, activate_flags);
|
||||
out:
|
||||
crypt_free(cd);
|
||||
|
||||
@@ -346,7 +365,7 @@ static int action_resize(int arg __attribute__((unused)))
|
||||
struct crypt_device *cd = NULL;
|
||||
int r;
|
||||
|
||||
r = crypt_init_by_name(&cd, action_argv[0]);
|
||||
r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device);
|
||||
if (r == 0)
|
||||
r = crypt_resize(cd, action_argv[0], opt_size);
|
||||
|
||||
@@ -366,10 +385,11 @@ static int action_status(int arg __attribute__((unused)))
|
||||
ci = crypt_status(NULL, action_argv[0]);
|
||||
switch (ci) {
|
||||
case CRYPT_INVALID:
|
||||
r = -ENODEV;
|
||||
r = -EINVAL;
|
||||
break;
|
||||
case CRYPT_INACTIVE:
|
||||
log_std("%s/%s is inactive.\n", crypt_get_dir(), action_argv[0]);
|
||||
r = -ENODEV;
|
||||
break;
|
||||
case CRYPT_ACTIVE:
|
||||
case CRYPT_BUSY:
|
||||
@@ -400,6 +420,8 @@ static int action_status(int arg __attribute__((unused)))
|
||||
log_std(" skipped: %" PRIu64 " sectors\n", cad.iv_offset);
|
||||
log_std(" mode: %s\n", cad.flags & CRYPT_ACTIVATE_READONLY ?
|
||||
"readonly" : "read/write");
|
||||
if (cad.flags & CRYPT_ACTIVATE_ALLOW_DISCARDS)
|
||||
log_std(" flags: discards\n");
|
||||
}
|
||||
out:
|
||||
crypt_free(cd);
|
||||
@@ -435,6 +457,7 @@ fail:
|
||||
static int action_luksFormat(int arg __attribute__((unused)))
|
||||
{
|
||||
int r = -EINVAL, keysize;
|
||||
const char *header_device;
|
||||
char *msg = NULL, *key = NULL, cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
|
||||
char *password = NULL;
|
||||
size_t passwordLen;
|
||||
@@ -442,9 +465,13 @@ static int action_luksFormat(int arg __attribute__((unused)))
|
||||
struct crypt_params_luks1 params = {
|
||||
.hash = opt_hash ?: DEFAULT_LUKS1_HASH,
|
||||
.data_alignment = opt_align_payload,
|
||||
.data_device = opt_header_device ? action_argv[0] : NULL,
|
||||
};
|
||||
|
||||
if(asprintf(&msg, _("This will overwrite data on %s irrevocably."), action_argv[0]) == -1) {
|
||||
header_device = opt_header_device ?: action_argv[0];
|
||||
|
||||
if(asprintf(&msg, _("This will overwrite data on %s irrevocably."),
|
||||
header_device) == -1) {
|
||||
log_err(_("memory allocation error in action_luksFormat"));
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
@@ -457,12 +484,15 @@ static int action_luksFormat(int arg __attribute__((unused)))
|
||||
r = crypt_parse_name_and_mode(opt_cipher ?: DEFAULT_CIPHER(LUKS1),
|
||||
cipher, NULL, cipher_mode);
|
||||
if (r < 0) {
|
||||
log_err("No known cipher specification pattern detected.\n");
|
||||
log_err(_("No known cipher specification pattern detected.\n"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((r = crypt_init(&cd, action_argv[0])))
|
||||
if ((r = crypt_init(&cd, header_device))) {
|
||||
if (opt_header_device)
|
||||
log_err(_("Cannot use %s as on-disk header.\n"), header_device);
|
||||
goto out;
|
||||
}
|
||||
|
||||
keysize = (opt_key_size ?: DEFAULT_LUKS1_KEYBITS) / 8;
|
||||
|
||||
@@ -507,31 +537,54 @@ out:
|
||||
static int action_luksOpen(int arg __attribute__((unused)))
|
||||
{
|
||||
struct crypt_device *cd = NULL;
|
||||
const char *data_device, *header_device;
|
||||
uint32_t flags = 0;
|
||||
int r;
|
||||
|
||||
if ((r = crypt_init(&cd, action_argv[0])))
|
||||
if (opt_header_device) {
|
||||
header_device = opt_header_device;
|
||||
data_device = action_argv[0];
|
||||
} else {
|
||||
header_device = action_argv[0];
|
||||
data_device = NULL;
|
||||
}
|
||||
|
||||
if ((r = crypt_init(&cd, header_device)))
|
||||
goto out;
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
|
||||
goto out;
|
||||
|
||||
if (data_device &&
|
||||
(r = crypt_set_data_device(cd, data_device)))
|
||||
goto out;
|
||||
|
||||
if (!data_device && (crypt_get_data_offset(cd) < 8)) {
|
||||
log_err(_("Reduced data offset is allowed only for detached LUKS header.\n"));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
crypt_set_timeout(cd, opt_timeout);
|
||||
crypt_set_password_retry(cd, opt_tries);
|
||||
|
||||
if (opt_iteration_time)
|
||||
crypt_set_iterarion_time(cd, opt_iteration_time);
|
||||
|
||||
if (opt_readonly)
|
||||
flags |= CRYPT_ACTIVATE_READONLY;
|
||||
|
||||
if (opt_allow_discards)
|
||||
flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
|
||||
|
||||
if (opt_key_file) {
|
||||
crypt_set_password_retry(cd, 1);
|
||||
r = crypt_activate_by_keyfile(cd, action_argv[1],
|
||||
CRYPT_ANY_SLOT, opt_key_file, opt_keyfile_size,
|
||||
opt_key_slot, opt_key_file, opt_keyfile_size,
|
||||
flags);
|
||||
} else
|
||||
r = crypt_activate_by_passphrase(cd, action_argv[1],
|
||||
CRYPT_ANY_SLOT, NULL, 0, flags);
|
||||
opt_key_slot, NULL, 0, flags);
|
||||
out:
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
@@ -603,6 +656,7 @@ static int action_luksKillSlot(int arg __attribute__((unused)))
|
||||
case CRYPT_SLOT_INACTIVE:
|
||||
log_err(_("Key %d not active. Can't wipe.\n"), opt_key_slot);
|
||||
case CRYPT_SLOT_INVALID:
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -816,6 +870,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);
|
||||
r = crypt_load(cd, CRYPT_LUKS1, NULL);
|
||||
out:
|
||||
crypt_free(cd);
|
||||
@@ -925,7 +980,7 @@ static int action_luksSuspend(int arg __attribute__((unused)))
|
||||
struct crypt_device *cd = NULL;
|
||||
int r;
|
||||
|
||||
r = crypt_init_by_name(&cd, action_argv[0]);
|
||||
r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device);
|
||||
if (!r)
|
||||
r = crypt_suspend(cd, action_argv[0]);
|
||||
|
||||
@@ -938,11 +993,11 @@ static int action_luksResume(int arg __attribute__((unused)))
|
||||
struct crypt_device *cd = NULL;
|
||||
int r;
|
||||
|
||||
if ((r = crypt_init_by_name(&cd, action_argv[0])))
|
||||
if ((r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device)))
|
||||
goto out;
|
||||
|
||||
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
|
||||
goto out;
|
||||
crypt_set_timeout(cd, opt_timeout);
|
||||
crypt_set_password_retry(cd, opt_tries);
|
||||
|
||||
if (opt_key_file)
|
||||
r = crypt_resume_by_keyfile(cd, action_argv[0], CRYPT_ANY_SLOT,
|
||||
@@ -1003,6 +1058,7 @@ static __attribute__ ((noreturn)) void usage(poptContext popt_context,
|
||||
poptPrintUsage(popt_context, stderr, 0);
|
||||
if (error)
|
||||
log_err("%s: %s\n", more, error);
|
||||
poptFreeContext(popt_context);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
@@ -1136,7 +1192,10 @@ int main(int argc, const char **argv)
|
||||
{ "header-backup-file",'\0', POPT_ARG_STRING, &opt_header_backup_file, 0, N_("File with LUKS header and keyslots backup."), NULL },
|
||||
{ "use-random", '\0', POPT_ARG_NONE, &opt_random, 0, N_("Use /dev/random for generating volume key."), NULL },
|
||||
{ "use-urandom", '\0', POPT_ARG_NONE, &opt_urandom, 0, N_("Use /dev/urandom for generating volume key."), NULL },
|
||||
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("UUID for device to use."), NULL },
|
||||
{ "shared", '\0', POPT_ARG_NONE, &opt_shared, 0, N_("Share device with another non-overlapping crypt segment."), NULL },
|
||||
{ "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 },
|
||||
POPT_TABLEEND
|
||||
};
|
||||
poptContext popt_context;
|
||||
@@ -1159,8 +1218,11 @@ int main(int argc, const char **argv)
|
||||
unsigned long long ull_value;
|
||||
char *endp;
|
||||
|
||||
errno = 0;
|
||||
ull_value = strtoull(popt_tmp, &endp, 0);
|
||||
if (*endp || !*popt_tmp)
|
||||
if (*endp || !*popt_tmp ||
|
||||
(errno == ERANGE && ull_value == ULLONG_MAX) ||
|
||||
(errno != 0 && ull_value == 0))
|
||||
r = POPT_ERROR_BADNUMBER;
|
||||
|
||||
switch(r) {
|
||||
@@ -1185,6 +1247,7 @@ int main(int argc, const char **argv)
|
||||
poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
|
||||
if (opt_version_mode) {
|
||||
log_std("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
|
||||
poptFreeContext(popt_context);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -1217,6 +1280,21 @@ int main(int argc, const char **argv)
|
||||
|
||||
/* FIXME: rewrite this from scratch */
|
||||
|
||||
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")) {
|
||||
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") &&
|
||||
@@ -1235,7 +1313,7 @@ int main(int argc, const char **argv)
|
||||
if (!strcmp(aname, "luksKillSlot") && action_argc > 1)
|
||||
opt_key_slot = atoi(action_argv[1]);
|
||||
if (opt_key_slot != CRYPT_ANY_SLOT &&
|
||||
(opt_key_slot < 0 || opt_key_slot > crypt_keyslot_max(CRYPT_LUKS1)))
|
||||
(opt_key_slot < 0 || opt_key_slot >= crypt_keyslot_max(CRYPT_LUKS1)))
|
||||
usage(popt_context, EXIT_FAILURE, _("Key slot is invalid."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
@@ -1281,5 +1359,7 @@ int main(int argc, const char **argv)
|
||||
_dbg_version_and_cmd(argc, argv);
|
||||
}
|
||||
|
||||
return run_action(action);
|
||||
r = run_action(action);
|
||||
poptFreeContext(popt_context);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
TESTS = api-test compat-test loopaes-test align-test mode-test password-hash-test
|
||||
TESTS = api-test compat-test loopaes-test align-test discards-test mode-test password-hash-test
|
||||
|
||||
EXTRA_DIST = compatimage.img.bz2 \
|
||||
compat-test loopaes-test align-test mode-test password-hash-test
|
||||
EXTRA_DIST = compatimage.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 \
|
||||
cryptsetup-valg-supps valg.sh valg-api.sh
|
||||
|
||||
CLEANFILES = cryptsetup-tst* valglog*
|
||||
|
||||
differ_SOURCES = differ.c
|
||||
differ_CFLAGS = -Wall -O2
|
||||
@@ -9,9 +16,15 @@ differ_CFLAGS = -Wall -O2
|
||||
api_test_SOURCES = api-test.c $(top_srcdir)/lib/utils_loop.c
|
||||
api_test_LDADD = ../lib/libcryptsetup.la
|
||||
api_test_LDFLAGS = -static
|
||||
api_test_CFLAGS = -g -Wall -O0 -I$(top_srcdir)/lib/
|
||||
api_test_CFLAGS = -g -Wall -O0 -I$(top_srcdir)/lib/ -I$(top_srcdir)/lib/luks1
|
||||
|
||||
check_PROGRAMS = api-test differ
|
||||
|
||||
compatimage.img:
|
||||
@bzip2 -k -d compatimage.img.bz2
|
||||
|
||||
valgrind-check: api-test differ
|
||||
@VALG=1 ./compat-test
|
||||
@INFOSTRING="api-test-000" ./valg-api.sh ./api-test
|
||||
|
||||
.PHONY: valgrind-check
|
||||
|
||||
1198
tests/api-test.c
1198
tests/api-test.c
File diff suppressed because it is too large
Load Diff
@@ -4,10 +4,12 @@ CRYPTSETUP=../src/cryptsetup
|
||||
|
||||
DEV_NAME=dummy
|
||||
DEV_NAME2=dummy2
|
||||
DEV_NAME3=dummy3
|
||||
ORIG_IMG=luks-test-orig
|
||||
IMG=luks-test
|
||||
KEY1=key1
|
||||
KEY2=key2
|
||||
KEY5=key5
|
||||
|
||||
LUKS_HEADER="S0-5 S6-7 S8-39 S40-71 S72-103 S104-107 S108-111 R112-131 R132-163 S164-167 S168-207 A0-591"
|
||||
KEY_SLOT0="S208-211 S212-215 R216-247 A248-251 A251-255"
|
||||
@@ -18,20 +20,26 @@ KEY_SLOT1="S256-259 S260-263 R264-295 A296-299 A300-303"
|
||||
KEY_MATERIAL1="R69632-133632"
|
||||
KEY_MATERIAL1_EXT="S69632-133632"
|
||||
|
||||
KEY_SLOT5="S448-451 S452-455 R456-487 A488-491 A492-495"
|
||||
KEY_MATERIAL5="R331776-395264"
|
||||
KEY_MATERIAL5_EXT="S331776-395264"
|
||||
|
||||
TEST_UUID="12345678-1234-1234-1234-123456789abc"
|
||||
|
||||
LOOPDEV=$(losetup -f 2>/dev/null)
|
||||
|
||||
function remove_mapping()
|
||||
{
|
||||
[ -b /dev/mapper/$DEV_NAME3 ] && dmsetup remove $DEV_NAME3
|
||||
[ -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 >/dev/null 2>&1
|
||||
rm -f $ORIG_IMG $IMG $KEY1 $KEY2 $KEY5 >/dev/null 2>&1
|
||||
}
|
||||
|
||||
function fail()
|
||||
{
|
||||
[ -n "$1" ] && echo "$1"
|
||||
remove_mapping
|
||||
echo "FAILED"
|
||||
exit 2
|
||||
@@ -75,6 +83,10 @@ function prepare()
|
||||
dd if=/dev/urandom of=$KEY2 count=1 bs=16 >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ ! -e $KEY5 ]; then
|
||||
dd if=/dev/urandom of=$KEY5 count=1 bs=16 >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
cp $IMG $ORIG_IMG
|
||||
[ -n "$1" ] && echo "CASE: $1"
|
||||
}
|
||||
@@ -92,14 +104,35 @@ function check_exists()
|
||||
check $1
|
||||
}
|
||||
|
||||
function valgrind_setup()
|
||||
{
|
||||
which valgrind >/dev/null 2>&1 || fail "Cannot find valgrind"
|
||||
|
||||
CRYPTSETUP_BIN=$($CRYPTSETUP --lt-debug --version 2>&1 \
|
||||
| grep "newargv\[0\]" \
|
||||
| sed 's/.*newargv\[0\]\:[[:space:]]\+\(.*\)$/\1/g')
|
||||
[ -z "$CRYPTSETUP_BIN" ] && fail "Unable to get location of cryptsetup executable."
|
||||
export LD_LIBRARY_PATH="../lib/.libs:$LD_LIBRARY_PATH"
|
||||
}
|
||||
|
||||
function valgrind_run()
|
||||
{
|
||||
INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${CRYPTSETUP_BIN} "$@"
|
||||
}
|
||||
|
||||
[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped."
|
||||
[ -z "$LOOPDEV" ] && skip "Cannot find free loop device, test skipped."
|
||||
|
||||
[ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run
|
||||
|
||||
# LUKS tests
|
||||
|
||||
|
||||
prepare "[1] open - compat image - acceptance check" new
|
||||
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
|
||||
|
||||
prepare "[2] open - compat image - denial check" new
|
||||
echo "wrongkey" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail
|
||||
@@ -127,6 +160,8 @@ echo "key1" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME || fail
|
||||
# Unsuccessful Key Delete - nothing may change
|
||||
prepare "[7] unsuccessful delete"
|
||||
echo "invalid" | $CRYPTSETUP luksKillSlot $LOOPDEV 1 2>/dev/null && fail
|
||||
$CRYPTSETUP -q luksKillSlot $LOOPDEV 8 2>/dev/null && fail
|
||||
$CRYPTSETUP -q luksKillSlot $LOOPDEV 7 2>/dev/null && fail
|
||||
check
|
||||
|
||||
# Delete Key Test
|
||||
@@ -255,6 +290,7 @@ $CRYPTSETUP -q status $DEV_NAME | grep "size:" | grep -q "100 sectors" || fail
|
||||
$CRYPTSETUP -q resize $DEV_NAME || fail
|
||||
$CRYPTSETUP -q status $DEV_NAME | grep "size:" | grep -q "19997 sectors" || fail
|
||||
$CRYPTSETUP -q remove $DEV_NAME || fail
|
||||
$CRYPTSETUP -q status $DEV_NAME >/dev/null && fail
|
||||
echo "key0" | $CRYPTSETUP create $DEV_NAME --hash sha1 $LOOPDEV || fail
|
||||
$CRYPTSETUP -q remove $DEV_NAME || fail
|
||||
echo "key0" | $CRYPTSETUP -q create $DEV_NAME --hash sha1 $LOOPDEV || fail
|
||||
@@ -354,5 +390,61 @@ echo "key0" | $CRYPTSETUP luksRemoveKey $LOOPDEV -l 2 2>/dev/null && fail
|
||||
echo "key01" | $CRYPTSETUP luksRemoveKey $LOOPDEV -d 4 2>/dev/null && fail
|
||||
echo -e "key0\n" | $CRYPTSETUP luksRemoveKey $LOOPDEV -d- -l 4 || fail
|
||||
|
||||
prepare "[25] Create non-overlapping segments" wipe
|
||||
echo "key0" | $CRYPTSETUP create $DEV_NAME $LOOPDEV --hash sha1 --offset 0 --size 256 || fail
|
||||
echo "key0" | $CRYPTSETUP create $DEV_NAME2 $LOOPDEV --hash sha1 --offset 512 --size 256 2>/dev/null && fail
|
||||
echo "key0" | $CRYPTSETUP create $DEV_NAME2 $LOOPDEV --hash sha1 --offset 512 --size 256 --shared || fail
|
||||
echo "key0" | $CRYPTSETUP create $DEV_NAME3 $LOOPDEV --hash sha1 --offset 255 --size 256 --shared 2>/dev/null && fail
|
||||
echo "key0" | $CRYPTSETUP create $DEV_NAME3 $LOOPDEV --hash sha1 --offset 256 --size 257 --shared 2>/dev/null && fail
|
||||
echo "key0" | $CRYPTSETUP create $DEV_NAME3 $LOOPDEV --hash sha1 --offset 256 --size 1024 --shared 2>/dev/null && fail
|
||||
echo "key0" | $CRYPTSETUP create $DEV_NAME3 $LOOPDEV --hash sha1 --offset 256 --size 256 --shared || fail
|
||||
$CRYPTSETUP -q remove $DEV_NAME3 || fail
|
||||
$CRYPTSETUP -q remove $DEV_NAME2 || fail
|
||||
$CRYPTSETUP -q remove $DEV_NAME || fail
|
||||
|
||||
prepare "[26] Suspend/Resume" wipe
|
||||
# only LUKS is supported
|
||||
echo "key0" | $CRYPTSETUP create $DEV_NAME --hash sha1 $LOOPDEV || fail
|
||||
$CRYPTSETUP luksSuspend $DEV_NAME 2>/dev/null && fail
|
||||
$CRYPTSETUP luksResume $DEV_NAME 2>/dev/null && fail
|
||||
$CRYPTSETUP -q remove $DEV_NAME || fail
|
||||
$CRYPTSETUP luksSuspend $DEV_NAME 2>/dev/null && fail
|
||||
# LUKS
|
||||
echo "key0" | $CRYPTSETUP -q luksFormat $LOOPDEV || fail
|
||||
echo "key0" | $CRYPTSETUP -q luksOpen $LOOPDEV $DEV_NAME || fail
|
||||
$CRYPTSETUP luksSuspend $DEV_NAME || fail
|
||||
$CRYPTSETUP -q resize $DEV_NAME 2>/dev/null && fail
|
||||
echo "xxx" | $CRYPTSETUP luksResume $DEV_NAME -T 1 2>/dev/null && fail
|
||||
echo "key0" | $CRYPTSETUP luksResume $DEV_NAME || fail
|
||||
$CRYPTSETUP -q luksClose $DEV_NAME || fail
|
||||
|
||||
prepare "[27] luksOpen with specified key slot number" wipe
|
||||
# first, let's try passphrase option
|
||||
echo "key5" | $CRYPTSETUP luksFormat -S 5 $LOOPDEV || fail
|
||||
check $LUKS_HEADER $KEY_SLOT5 $KEY_MATERIAL5
|
||||
echo "key5" | $CRYPTSETUP luksOpen -S 4 $LOOPDEV $DEV_NAME && fail
|
||||
[ -b /dev/mapper/$DEV_NAME ] && fail
|
||||
echo "key5" | $CRYPTSETUP luksOpen -S 5 $LOOPDEV $DEV_NAME || fail
|
||||
check_exists
|
||||
$CRYPTSETUP luksClose $DEV_NAME || fail
|
||||
echo -e "key5\nkey0" | $CRYPTSETUP luksAddKey -S 0 $LOOPDEV || fail
|
||||
check $LUKS_HEADER $KEY_SLOT0 $KEY_MATERIAL0
|
||||
echo "key5" | $CRYPTSETUP luksOpen -S 0 $LOOPDEV $DEV_NAME && fail
|
||||
[ -b /dev/mapper/$DEV_NAME ] && fail
|
||||
echo "key0" | $CRYPTSETUP luksOpen -S 5 $LOOPDEV $DEV_NAME && fail
|
||||
[ -b /dev/mapper/$DEV_NAME ] && fail
|
||||
# second, try it with keyfiles
|
||||
$CRYPTSETUP luksFormat -q -S 5 -d $KEY5 $LOOPDEV || fail
|
||||
check $LUKS_HEADER $KEY_SLOT5 $KEY_MATERIAL5
|
||||
$CRYPTSETUP luksAddKey -S 1 -d $KEY5 $LOOPDEV $KEY1 || fail
|
||||
check $LUKS_HEADER $KEY_SLOT1 $KEY_MATERIAL1
|
||||
$CRYPTSETUP luksOpen -S 5 -d $KEY5 $LOOPDEV $DEV_NAME || fail
|
||||
check_exists
|
||||
$CRYPTSETUP luksClose $DEV_NAME || fail
|
||||
$CRYPTSETUP luksOpen -S 1 -d $KEY5 $LOOPDEV $DEV_NAME && fail
|
||||
[ -b /dev/mapper/$DEV_NAME ] && fail
|
||||
$CRYPTSETUP luksOpen -S 5 -d $KEY1 $LOOPDEV $DEV_NAME && fail
|
||||
[ -b /dev/mapper/$DEV_NAME ] && fail
|
||||
|
||||
remove_mapping
|
||||
exit 0
|
||||
|
||||
36
tests/cryptsetup-valg-supps
Normal file
36
tests/cryptsetup-valg-supps
Normal file
@@ -0,0 +1,36 @@
|
||||
# Supresion file for valgrind
|
||||
|
||||
# known problem in libgcrypt
|
||||
{
|
||||
leak_in_libgcrypt_00
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
obj:/lib64/libgcrypt.so*
|
||||
...
|
||||
obj:/lib64/libgcrypt.so*
|
||||
fun:crypt_backend_init
|
||||
fun:init_crypto
|
||||
...
|
||||
}
|
||||
# following leaks/errors are addressed to libpopt...
|
||||
{
|
||||
popt_read_error
|
||||
Memcheck:Addr4
|
||||
obj:/lib*/libpopt.so*
|
||||
fun:poptGetNextOpt
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
popt_leak_poptGetNextOpt_00
|
||||
Memcheck:Leak
|
||||
fun:realloc
|
||||
fun:poptGetNextOpt
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
popt_leak_poptGetNextOpt_01
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:poptGetNextOpt
|
||||
fun:main
|
||||
}
|
||||
81
tests/discards-test
Executable file
81
tests/discards-test
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/bin/bash
|
||||
|
||||
CRYPTSETUP="../src/cryptsetup"
|
||||
DEV_NAME="discard-t3st"
|
||||
DEV=""
|
||||
|
||||
cleanup() {
|
||||
[ -b /dev/mapper/$DEV_NAME ] && dmsetup remove $DEV_NAME
|
||||
udevadm settle >/dev/null 2>&1
|
||||
rmmod scsi_debug 2>/dev/null
|
||||
sleep 2
|
||||
}
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "FAILED"
|
||||
cleanup
|
||||
exit 100
|
||||
}
|
||||
|
||||
add_device() {
|
||||
modprobe scsi_debug $@
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "This kernel seems to not support proper scsi_debug module, test skipped."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
DEV=$(grep scsi_debug /sys/block/*/device/model | cut -f4 -d /)
|
||||
|
||||
DEV="/dev/$DEV"
|
||||
[ -b $DEV ] || fail "Cannot find $DEV."
|
||||
}
|
||||
|
||||
function check_version()
|
||||
{
|
||||
VER_STR=$(dmsetup targets | grep crypt | cut -f 2 -dv)
|
||||
VER_MAJ=$(echo $VER_STR | cut -f 1 -d.)
|
||||
VER_MIN=$(echo $VER_STR | cut -f 2 -d.)
|
||||
|
||||
# option supported in 1.11
|
||||
test $VER_MAJ -gt 1 && return 0
|
||||
test $VER_MIN -ge 11 && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
if [ $(id -u) != 0 ]; then
|
||||
echo "WARNING: You must be root to run this test, test skipped."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
modprobe --dry-run scsi_debug || exit 0
|
||||
modprobe dm-crypt >/dev/null 2>&1
|
||||
if ! check_version ; then
|
||||
echo "Probably old kernel, test skipped."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
add_device dev_size_mb=16 sector_size=512 num_tgts=1 lbpu=1
|
||||
|
||||
# FIXME test hash of device (unmap -> zero)
|
||||
# for now just check that flag is enabled
|
||||
|
||||
echo "[1] Allowing discards for LUKS device"
|
||||
echo xxx | $CRYPTSETUP luksFormat $DEV -q -i1 || fail
|
||||
echo xxx | $CRYPTSETUP luksOpen $DEV $DEV_NAME --allow-discards || fail
|
||||
$CRYPTSETUP status $DEV_NAME | grep flags | grep discards >/dev/null || fail
|
||||
$CRYPTSETUP resize $DEV_NAME --size 100 || fail
|
||||
$CRYPTSETUP status $DEV_NAME | grep flags | grep discards >/dev/null || fail
|
||||
dmsetup table $DEV_NAME | grep allow_discards >/dev/null || fail
|
||||
$CRYPTSETUP luksClose $DEV_NAME || fail
|
||||
|
||||
echo "[2] Allowing discards for plain device"
|
||||
echo xxx | $CRYPTSETUP create $DEV_NAME $DEV --hash sha1 --allow-discards || fail
|
||||
$CRYPTSETUP status $DEV_NAME | grep flags | grep discards >/dev/null || fail
|
||||
$CRYPTSETUP resize $DEV_NAME --size 100 || fail
|
||||
$CRYPTSETUP status $DEV_NAME | grep flags | grep discards >/dev/null || fail
|
||||
dmsetup table $DEV_NAME | grep allow_discards >/dev/null || fail
|
||||
$CRYPTSETUP remove $DEV_NAME || fail
|
||||
|
||||
cleanup
|
||||
BIN
tests/evil_hdr-luks_hdr_damage.bz2
Normal file
BIN
tests/evil_hdr-luks_hdr_damage.bz2
Normal file
Binary file not shown.
BIN
tests/evil_hdr-payload_overwrite.bz2
Normal file
BIN
tests/evil_hdr-payload_overwrite.bz2
Normal file
Binary file not shown.
BIN
tests/evil_hdr-small_luks_device.bz2
Normal file
BIN
tests/evil_hdr-small_luks_device.bz2
Normal file
Binary file not shown.
BIN
tests/evil_hdr-stripes_payload_dmg.bz2
Normal file
BIN
tests/evil_hdr-stripes_payload_dmg.bz2
Normal file
Binary file not shown.
@@ -51,7 +51,7 @@ add_device() {
|
||||
|
||||
dmcrypt_check() # device outstring
|
||||
{
|
||||
X=$(dmsetup table $1 2>/dev/null | cut -d' ' -f 4)
|
||||
X=$(dmsetup table $1 2>/dev/null | sed 's/.*: //' | cut -d' ' -f 4)
|
||||
if [ $X = $2 ] ; then
|
||||
echo -n "[table OK]"
|
||||
else
|
||||
|
||||
@@ -63,7 +63,7 @@ crypt_key() # hash keysize pwd/file name outkey [limit]
|
||||
fi
|
||||
fi
|
||||
|
||||
VKEY=$(dmsetup table $DEV2 --showkeys 2>/dev/null | cut -d' ' -f 5)
|
||||
VKEY=$(dmsetup table $DEV2 --showkeys 2>/dev/null | sed 's/.*: //' | cut -d' ' -f 5)
|
||||
if [ "$VKEY" != "$5" ] ; then
|
||||
echo " [FAILED]"
|
||||
echo "expected: $5"
|
||||
|
||||
11
tests/valg-api.sh
Executable file
11
tests/valg-api.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
SUP="--suppressions=./cryptsetup-valg-supps"
|
||||
CHILD="--trace-children=no --child-silent-after-fork=yes"
|
||||
MALLOC="--malloc-fill=aa"
|
||||
FREE="--free-fill=21"
|
||||
STACK="--max-stackframe=300000"
|
||||
EXTRAS="--read-var-info=yes --show-reachable=yes"
|
||||
LOGFILE="--log-file=./valglog.$(date +%s)_${INFOSTRING}"
|
||||
LEAKCHECK="--leak-check=full --track-origins=yes"
|
||||
|
||||
exec valgrind $SUP $GETSUP $CHILD $MALLOC $FREE $STACK $EXTRAS $LOGFILE $LEAKCHECK "$@"
|
||||
11
tests/valg.sh
Executable file
11
tests/valg.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
SUP="--suppressions=./cryptsetup-valg-supps"
|
||||
CHILD="--trace-children=yes --child-silent-after-fork=yes"
|
||||
MALLOC="--malloc-fill=aa"
|
||||
FREE="--free-fill=21"
|
||||
STACK="--max-stackframe=300000"
|
||||
EXTRAS="--read-var-info=yes --show-reachable=yes"
|
||||
LOGFILE="--log-file=./valglog.$(date +%s)_${INFOSTRING}"
|
||||
LEAKCHECK="--leak-check=full --track-origins=yes"
|
||||
|
||||
exec valgrind $SUP $GETSUP $CHILD $MALLOC $FREE $STACK $EXTRAS $LOGFILE $LEAKCHECK "$@"
|
||||
BIN
tests/valid_header_file.bz2
Normal file
BIN
tests/valid_header_file.bz2
Normal file
Binary file not shown.
Reference in New Issue
Block a user