Compare commits

..

39 Commits

Author SHA1 Message Date
Milan Broz
3e763e1cd2 Update LUKS2 docs. 2018-12-03 09:34:35 +01:00
Milan Broz
060c807bc8 Add 2.0.6 release notes. 2018-12-03 09:34:27 +01:00
Milan Broz
0f82f90e14 Update po files. 2018-12-02 19:00:56 +01:00
Ondrej Kozina
66b6808cb8 Add validation tests for non-default metadata. 2018-12-02 18:58:36 +01:00
Ondrej Kozina
99b3a69e52 Update LUKS2 test images.
- update test images for validation fixes
  from previous commits

- erase leftover json data in between secondary
  header and keyslot areas.
2018-11-28 17:05:34 +01:00
Ondrej Kozina
1a940a49cb Remove redundant check in keyslot areas validation.
Due to previous fix it's no longer needed to add
all keyslot area lengths and check if result sum
is lower than keyslots_size.

(We already check lower limit, upper limit and
overlapping areas)
2018-11-28 17:05:02 +01:00
Ondrej Kozina
645c8b6026 Fix keyslot areas validation.
This commit fixes two problems:

a) Replace hardcoded 16KiB metadata variant as lower limit
   for keyslot area offset with current value set in config
   section (already validated).

b) Replace segment offset (if not zero) as upper limit for
   keyslot area offset + size with value calculated as
   2 * metadata size + keyslots_size as acquired from
   config section (also already validated)
2018-11-28 17:03:34 +01:00
Ondrej Kozina
00fc4beac1 Reshuffle config and keyslots areas validation code.
Swap config and keyslot areas validation code order.

Also split original keyslots_size validation code in
between config and keyslot areas routines for furhter
changes in the code later. This commit has no funtional
impact.
2018-11-28 17:00:55 +01:00
Ondrej Kozina
b220bef821 Do not validate keyslot areas so frantically.
Keyslot areas were validated from each keyslot
validation routine and later one more time
in general header validation routine. The call
from header validation routine is good enough.
2018-11-28 16:55:20 +01:00
Ondrej Kozina
d1cfdc7fd7 Test cryptsetup can handle all LUKS2 metadata variants.
following tests:

add keyslot
test passphrase
unlock device
store token in metadata
read token from metadata
2018-11-27 22:35:00 +01:00
Ondrej Kozina
ccfbd302bd Add LUKS2 metadata test images.
Test archive contains images with all supported
LUKS2 metadata size configurations. There's
one active keyslot 0 in every image that can be
unlocked with following passphrase (ignore
quotation marks): "Qx3qn46vq0v"
2018-11-27 22:34:51 +01:00
Ondrej Kozina
0dda2b0e33 Add validation tests for non-default json area size.
Test both primary and secondary header validation tests
with non-default LUKS2 json area size.

Check validation rejects config.keyslots_size with zero value.

Check validation rejects mismatching values for metadata size
set in binary header and in config json section.
2018-11-27 22:34:35 +01:00
Ondrej Kozina
4e70b9ce16 Extend baseline LUKS2 validation image to 16 MiBs. 2018-11-27 22:34:10 +01:00
Ondrej Kozina
7d8a62b7d5 Move some validation tests in new section. 2018-11-27 22:33:56 +01:00
Ondrej Kozina
b383e11372 Drop needless size restriction on keyslots size. 2018-11-27 11:54:35 +01:00
Milan Broz
a6e9399f7b Update POTFILES. 2018-11-25 16:03:40 +01:00
Milan Broz
e4fd2fafed Fix signed/unsigned comparison warning. 2018-11-25 15:12:22 +01:00
Milan Broz
e31b20d8d8 Set 2.0.6 version. 2018-11-25 15:04:24 +01:00
Milan Broz
838c91fef3 Update po file. 2018-11-25 15:03:23 +01:00
Milan Broz
be8c39749f Fix setting of integrity persistent flags (no-journal).
We have to query and set flags also for underlying dm-integrity device,
otherwise activation flags applied there are ignored.
2018-11-25 15:01:29 +01:00
Milan Broz
cec5f8a8bf Check for algorithms string lengths in crypt_cipher_check().
The kernel check will fail anyway if string is truncated, but this
make some compilers more happy.
2018-11-25 15:01:14 +01:00
Milan Broz
f6dde0f39e Fix LUKS2_hdr_validate funtion definition. 2018-11-25 15:00:58 +01:00
Milan Broz
2f265f81e7 Properly handle interrupt in cryptsetup-reencrypt and remove log.
Fixes #419.
2018-11-25 15:00:43 +01:00
Milan Broz
9da865e685 Fix sector-size tests for older kernels. 2018-11-25 15:00:28 +01:00
Milan Broz
8d4e794d39 Check for device size and sector size misalignment.
Kernel prevents activation of device that is not aligned
to requested sector size.

Add early check to plain and LUKS2 formats to disallow
creation of such a device.
(Activation will fail in kernel later anyway.)

Fixes #390.
2018-11-25 15:00:12 +01:00
Milan Broz
018486cea0 Add support for Adiantum cipher mode. 2018-11-25 14:57:25 +01:00
Milan Broz
96a3dc0a66 Try to check if AEAD cipher is available through kernel crypto API. 2018-11-25 14:42:50 +01:00
Milan Broz
efeada291a Fix unsigned return value. 2018-11-25 14:29:09 +01:00
Milan Broz
fb6935385c Properly propagate error from AF diffuse function. 2018-11-25 14:28:31 +01:00
Milan Broz
599748bc9f Check hash value in pbkdf setting early. 2018-11-25 14:27:59 +01:00
Milan Broz
d0d507e325 Fallback to default keyslot algorithm if backend does not know the cipher. 2018-11-25 14:27:37 +01:00
Ondrej Kozina
7d8f64fe21 Remove unused crypt_dm_active_device member. 2018-11-25 14:27:11 +01:00
Ondrej Kozina
a52dbc43d3 Secondary header offset must match header size. 2018-11-25 14:26:53 +01:00
Ondrej Kozina
7df458b74e Check json size matches value from binary LUKS2 header.
We have max json area length parameter stored twice. In
LUKS2 binary header and in json metadata. Those two values
must match.
2018-11-25 14:26:38 +01:00
Ondrej Kozina
bcd7527938 Change max json area length type to unsigned.
We use uint64_t for max json length everywhere else
including config.json_size field in LUKS2 metadata.

Also renames some misleading parameter names.
2018-11-25 14:26:23 +01:00
Ondrej Kozina
e7141383e3 Enable all supported metadata sizes in LUKS2 validation code.
LUKS2 specification allows various size of LUKS2 metadata.
The single metadata instance is composed of LUKS2 binary header
(4096 bytes) and immediately following json area. The resulting
assembled metadata size have to be one of following values,
all in KiB:

16, 32, 64, 128, 256, 512, 1024, 2048 or 4096
2018-11-25 14:25:59 +01:00
Milan Broz
cd968551d6 Add workaround for benchmarking Adiantum cipher. 2018-11-25 14:24:37 +01:00
Milan Broz
6a3e585141 Fix ext4 image to work without CONFIG_LBDAF. 2018-11-25 14:24:02 +01:00
Milan Broz
6f48bdf9e5 Add branch v2_0_x to Travis. 2018-11-19 13:26:41 +01:00
219 changed files with 20589 additions and 68604 deletions

10
.gitignore vendored
View File

@@ -36,6 +36,7 @@ missing
po/Makevars.template
po/POTFILES
po/Rules-quot
po/*.pot
po/*.header
po/*.sed
po/*.sin
@@ -44,12 +45,3 @@ scripts/cryptsetup.conf
stamp-h1
veritysetup
tests/valglog.*
*/*.dirstamp
*-debug-luks2-backup*
tests/api-test
tests/api-test-2
tests/differ
tests/luks1-images
tests/tcrypt-images
tests/unit-utils-io
tests/vectors-test

View File

@@ -1,15 +0,0 @@
### Issue description
<!-- Please, shortly describe the issue here. -->
### Steps for reproducing the issue
<!-- How it can be reproduced? Include all important steps. -->
### Additional info
<!-- Please mention what distribution you are using. -->
### Debug log
<!-- Paste a debug log of the failing command (add --debug option) between the markers below (to keep raw debug format).-->
```
Output with --debug option:
```

View File

@@ -1,5 +0,0 @@
### Documentation issue
<!-- Please, shortly describe the issue in documentation here. -->
### Additional info
<!-- Please mention what cryptsetup version you are using. -->

View File

@@ -1,5 +0,0 @@
### New feature description
<!-- Please, shortly describe the requested feature here. -->
### Additional info
<!-- Please mention what distribution and cryptsetup version you are using. -->

View File

@@ -36,6 +36,7 @@ function check_nonroot
[ -z "$cfg_opts" ] && return
configure_travis \
--enable-python \
--enable-cryptsetup-reencrypt \
--enable-internal-sse-argon2 \
"$cfg_opts" \
@@ -53,6 +54,7 @@ function check_root
[ -z "$cfg_opts" ] && return
configure_travis \
--enable-python \
--enable-cryptsetup-reencrypt \
--enable-internal-sse-argon2 \
"$cfg_opts" \
@@ -71,6 +73,7 @@ function check_nonroot_compile_only
[ -z "$cfg_opts" ] && return
configure_travis \
--enable-python \
--enable-cryptsetup-reencrypt \
--enable-internal-sse-argon2 \
"$cfg_opts" \
@@ -84,6 +87,7 @@ function travis_install_script
# install some packages from Ubuntu's default sources
sudo apt-get -qq update
sudo apt-get install -qq >/dev/null \
python-dev \
sharutils \
libgcrypt20-dev \
libssl-dev \
@@ -102,13 +106,7 @@ function travis_install_script
keyutils \
libjson-c-dev \
libblkid-dev \
dkms \
linux-headers-$(uname -r) \
linux-modules-extra-$(uname -r) \
|| return
# For VeraCrypt test
sudo apt-get install gost-crypto-dkms
}
function travis_before_script
@@ -142,13 +140,6 @@ function travis_script
openssl_compile)
check_nonroot_compile_only "--with-crypto_backend=openssl"
;;
kernel)
check_nonroot "--with-crypto_backend=kernel" && \
check_root "--with-crypto_backend=kernel"
;;
kernel_compile)
check_nonroot_compile_only "--with-crypto_backend=kernel"
;;
*)
echo "error, check environment (travis.yml)" >&2
false

View File

@@ -1,23 +1,20 @@
language: c
sudo: required
os: linux
dist: focal
group: edge
dist: trusty
compiler:
- gcc
env:
# MAKE_CHECK="gcrypt"
- MAKE_CHECK="gcrypt"
- MAKE_CHECK="openssl"
# MAKE_CHECK="kernel"
branches:
only:
- master
- wip-luks2
- v2.3.x
- v2_0_x
before_install:
- uname -a

View File

@@ -1,4 +1,3 @@
Jana Saout <jana@saout.de>
Clemens Fruhwirth <clemens@endorphin.org>
Milan Broz <gmazyland@gmail.com>
Ondrej Kozina <okozina@redhat.com>

3102
FAQ

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
EXTRA_DIST = COPYING.LGPL FAQ docs misc
SUBDIRS = po tests
TESTS =
CLEANFILES =
DISTCLEAN_TARGETS =
@@ -15,8 +16,6 @@ AM_CPPFLAGS = \
AM_CFLAGS = -Wall
AM_LDFLAGS =
LDADD = $(LTLIBINTL) -lm
tmpfilesddir = @DEFAULT_TMPFILESDIR@
noinst_LTLIBRARIES =
@@ -26,6 +25,8 @@ tmpfilesd_DATA =
include man/Makemodule.am
include python/Makemodule.am
include scripts/Makemodule.am
if CRYPTO_INTERNAL_ARGON2
@@ -39,6 +40,7 @@ include src/Makemodule.am
ACLOCAL_AMFLAGS = -I m4
DISTCHECK_CONFIGURE_FLAGS = \
--enable-python \
--with-tmpfilesdir=$$dc_install_base/usr/lib/tmpfiles.d \
--enable-internal-argon2 --enable-internal-sse-argon2

5
README
View File

@@ -14,8 +14,7 @@ FAQ:
MAILING LIST:
E-MAIL: dm-crypt@saout.de
URL: https://www.saout.de/mailman/listinfo/dm-crypt
ARCHIVE: https://lore.kernel.org/dm-crypt/
URL: http://www.saout.de/mailman/listinfo/dm-crypt
DOWNLOAD:
@@ -29,4 +28,4 @@ SOURCE CODE:
NLS (PO TRANSLATIONS):
PO files are maintained by:
https://translationproject.org/domain/cryptsetup.html
http://translationproject.org/domain/cryptsetup.html

View File

@@ -2,13 +2,13 @@
What the ...?
=============
**Cryptsetup** is a utility used to conveniently set up disk encryption based
on the [DMCrypt](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt) kernel module.
**Cryptsetup** is utility used to conveniently setup disk encryption based
on [DMCrypt](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt) kernel module.
These include **plain** **dm-crypt** volumes, **LUKS** volumes, **loop-AES**,
**TrueCrypt** (including **VeraCrypt** extension) and **BitLocker** formats.
These include **plain** **dm-crypt** volumes, **LUKS** volumes, **loop-AES**
and **TrueCrypt** (including **VeraCrypt** extension) format.
The project also includes a **veritysetup** utility used to conveniently setup
Project also includes **veritysetup** utility used to conveniently setup
[DMVerity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity) block integrity checking kernel module
and, since version 2.0, **integritysetup** to setup
[DMIntegrity](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMIntegrity) block integrity kernel module.
@@ -20,10 +20,7 @@ LUKS Design
only facilitate compatibility among distributions, but also provides secure management of multiple user passwords.
LUKS stores all necessary setup information in the partition header, enabling to transport or migrate data seamlessly.
Last version of the LUKS2 format specification is
[available here](https://gitlab.com/cryptsetup/LUKS2-docs).
Last version of the LUKS1 format specification is
Last version of the LUKS format specification is
[available here](https://www.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf).
Why LUKS?
@@ -44,30 +41,57 @@ Download
--------
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
**The latest stable cryptsetup version is 2.4.3**
* [cryptsetup-2.4.3.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.3.tar.xz)
* Signature [cryptsetup-2.4.3.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.3.tar.sign)
**The latest cryptsetup version is 2.0.5**
* [cryptsetup-2.0.5.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.5.tar.xz)
* Signature [cryptsetup-2.0.5.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.5.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.4.3 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/v2.4.3-ReleaseNotes).
* [Cryptsetup 2.0.5 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.5-ReleaseNotes).
Previous versions
* [Version 2.3.7](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.7.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.7.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.7-ReleaseNotes).
* [Version 2.0.4](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.4.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.4.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.4-ReleaseNotes).
* [Version 2.0.3](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.3.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.3.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.3-ReleaseNotes).
* [Version 2.0.2](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.2.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.2.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.2-ReleaseNotes).
* [Version 2.0.1](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.1.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.1.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.1-ReleaseNotes).
* [Version 2.0.0](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.0.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.0-ReleaseNotes).
* [Version 1.7.5](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).
* [Version 1.7.4](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.4.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.4.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.4-ReleaseNotes).
* [Version 1.7.3](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.3.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.3.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.3-ReleaseNotes).
* [Version 1.7.2](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.2.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.2.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.2-ReleaseNotes).
* [Version 1.7.1](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.1.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.1.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.1-ReleaseNotes).
* [Version 1.7.0](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.0.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.0.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.0-ReleaseNotes).
Source and API docs
-------------------
For development version code, please refer to [source](https://gitlab.com/cryptsetup/cryptsetup/tree/master) page,
mirror on [kernel.org](https://git.kernel.org/cgit/utils/cryptsetup/cryptsetup.git/) or [GitHub](https://github.com/mbroz/cryptsetup).
For libcryptsetup documentation see [libcryptsetup API](https://mbroz.fedorapeople.org/libcryptsetup_API/) page.
For libcryptsetup documentation see [libcryptsetup API](https://gitlab.com/cryptsetup/cryptsetup/wikis/API/index.html) page.
The libcryptsetup API/ABI changes are tracked in [compatibility report](https://abi-laboratory.pro/tracker/timeline/cryptsetup/).
NLS PO files are maintained by [TranslationProject](https://translationproject.org/domain/cryptsetup.html).
NLS PO files are maintained by [TranslationProject](http://translationproject.org/domain/cryptsetup.html).
Help!
-----
@@ -76,5 +100,5 @@ For cryptsetup and LUKS related questions, please use the dm-crypt mailing list,
If you want to subscribe just send an empty mail to [dm-crypt-subscribe@saout.de](mailto:dm-crypt-subscribe@saout.de).
You can also browse [list archive](https://www.saout.de/pipermail/dm-crypt/) or read and search it through
[web interface on lore.kernel.org](https://lore.kernel.org/dm-crypt/) or alternatively on [marc.info](https://marc.info/?l=dm-crypt).
You can also browse [list archive](http://www.saout.de/pipermail/dm-crypt/) or read it through
[web interface](https://marc.info/?l=dm-crypt).

View File

@@ -9,23 +9,16 @@ DIE=0
(autopoint --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have autopoint installed."
echo "Download the appropriate package for your distribution."
echo "Download the appropriate package for your distribution,"
echo "or see http://www.gnu.org/software/gettext"
DIE=1
}
(msgfmt --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Warning**: You should have gettext installed."
echo "Download the appropriate package for your distribution."
echo "To disable translation, you can also use --disable-nls"
echo "configure option."
}
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have autoconf installed."
echo "Download the appropriate package for your distribution."
echo "**Error**: You must have autoconf installed to."
echo "Download the appropriate package for your distribution,"
echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
DIE=1
}
@@ -33,7 +26,8 @@ DIE=0
(libtool --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have libtool installed."
echo "Download the appropriate package for your distribution."
echo "Get ftp://ftp.gnu.org/pub/gnu/"
echo "(or a newer version if it is available)"
DIE=1
}
}
@@ -41,7 +35,8 @@ DIE=0
(automake --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have automake installed."
echo "Download the appropriate package for your distribution."
echo "Get ftp://ftp.gnu.org/pub/gnu/"
echo "(or a newer version if it is available)"
DIE=1
NO_AUTOMAKE=yes
}
@@ -52,6 +47,8 @@ test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: Missing aclocal. The version of automake"
echo "installed doesn't appear recent enough."
echo "Get ftp://ftp.gnu.org/pub/gnu/"
echo "(or a newer version if it is available)"
DIE=1
}

View File

@@ -1,9 +1,9 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[2.3.7])
AC_INIT([cryptsetup],[2.0.6])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
LIBCRYPTSETUP_VERSION_INFO=18:0:6
LIBCRYPTSETUP_VERSION_INFO=15:0:3
AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR(src/cryptsetup.c)
@@ -33,7 +33,6 @@ AC_PROG_MAKE_SET
AC_ENABLE_STATIC(no)
LT_INIT
PKG_PROG_PKG_CONFIG
AM_ICONV
dnl ==========================================================================
dnl define PKG_CHECK_VAR for old pkg-config <= 0.28
@@ -57,14 +56,9 @@ dnl ==========================================================================
AC_C_RESTRICT
AC_HEADER_DIRENT
AC_HEADER_STDC
AC_CHECK_HEADERS(fcntl.h malloc.h inttypes.h sys/ioctl.h sys/mman.h \
sys/sysmacros.h sys/statvfs.h ctype.h unistd.h locale.h byteswap.h endian.h stdint.h)
AC_CHECK_DECLS([O_CLOEXEC],,[AC_DEFINE([O_CLOEXEC],[0], [Defined to 0 if not provided])],
[[
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
]])
AC_CHECK_HEADERS(uuid/uuid.h,,[AC_MSG_ERROR([You need the uuid library.])])
AC_CHECK_HEADER(libdevmapper.h,,[AC_MSG_ERROR([You need the device-mapper library.])])
@@ -145,14 +139,6 @@ AC_DEFUN([NO_FIPS], [
fi
])
dnl LUKS2 online reencryption
AC_ARG_ENABLE([luks2-reencryption],
AS_HELP_STRING([--disable-luks2-reencryption], [disable LUKS2 online reencryption extension]),
[], [enable_luks2_reencryption=yes])
if test "x$enable_luks2_reencryption" = "xyes"; then
AC_DEFINE(USE_LUKS2_REENCRYPTION, 1, [Use LUKS2 online reencryption extension])
fi
dnl ==========================================================================
dnl pwquality library (cryptsetup CLI only)
AC_ARG_ENABLE([pwquality],
@@ -183,15 +169,7 @@ AC_DEFINE_UNQUOTED([PASSWDQC_CONFIG_FILE], ["$use_passwdqc_config"], [passwdqc l
if test "x$enable_passwdqc" = "xyes"; then
AC_DEFINE(ENABLE_PASSWDQC, 1, [Enable password quality checking using passwdqc library])
saved_LIBS="$LIBS"
AC_SEARCH_LIBS([passwdqc_check], [passwdqc])
case "$ac_cv_search_passwdqc_check" in
no) AC_MSG_ERROR([failed to find passwdqc_check]) ;;
-l*) PASSWDQC_LIBS="$ac_cv_search_passwdqc_check" ;;
*) PASSWDQC_LIBS= ;;
esac
AC_CHECK_FUNCS([passwdqc_params_free])
LIBS="$saved_LIBS"
PASSWDQC_LIBS="-lpasswdqc"
fi
if test "x$enable_pwquality$enable_passwdqc" = "xyesyes"; then
@@ -207,12 +185,8 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
else
GCRYPT_REQ_VERSION=1.1.42
fi
dnl libgcrypt rejects to use pkgconfig, use AM_PATH_LIBGCRYPT from gcrypt-devel here.
dnl Do not require gcrypt-devel if other crypto backend is used.
m4_ifdef([AM_PATH_LIBGCRYPT],[
dnl Check if we can use gcrypt PBKDF2 (1.6.0 supports empty password)
AC_ARG_ENABLE([gcrypt-pbkdf2],
dnl Check if we can use gcrypt PBKDF2 (1.6.0 supports empty password)
AS_HELP_STRING([--enable-gcrypt-pbkdf2], [force enable internal gcrypt PBKDF2]),
if test "x$enableval" = "xyes"; then
[use_internal_pbkdf2=0]
@@ -220,8 +194,7 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
[use_internal_pbkdf2=1]
fi,
[AM_PATH_LIBGCRYPT([1.6.1], [use_internal_pbkdf2=0], [use_internal_pbkdf2=1])])
AM_PATH_LIBGCRYPT($GCRYPT_REQ_VERSION,,[AC_MSG_ERROR([You need the gcrypt library.])])],
AC_MSG_ERROR([Missing support for gcrypt: install gcrypt and regenerate configure.]))
AM_PATH_LIBGCRYPT($GCRYPT_REQ_VERSION,,[AC_MSG_ERROR([You need the gcrypt library.])])
AC_MSG_CHECKING([if internal cryptsetup PBKDF2 is compiled-in])
if test $use_internal_pbkdf2 = 0; then
@@ -231,8 +204,6 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
NO_FIPS([])
fi
AC_CHECK_DECLS([GCRY_CIPHER_MODE_XTS], [], [], [#include <gcrypt.h>])
if test "x$enable_static_cryptsetup" = "xyes"; then
saved_LIBS=$LIBS
LIBS="$saved_LIBS $LIBGCRYPT_LIBS -static"
@@ -300,7 +271,6 @@ AC_DEFUN([CONFIGURE_KERNEL], [
AC_DEFUN([CONFIGURE_NETTLE], [
AC_CHECK_HEADERS(nettle/sha.h,,
[AC_MSG_ERROR([You need Nettle cryptographic library.])])
AC_CHECK_HEADERS(nettle/version.h)
saved_LIBS=$LIBS
AC_CHECK_LIB(nettle, nettle_pbkdf2_hmac_sha256,,
@@ -370,8 +340,6 @@ AC_CHECK_DECLS([dm_task_retry_remove], [], [], [#include <libdevmapper.h>])
AC_CHECK_DECLS([dm_task_deferred_remove], [], [], [#include <libdevmapper.h>])
AC_CHECK_DECLS([dm_device_has_mounted_fs], [], [], [#include <libdevmapper.h>])
AC_CHECK_DECLS([dm_device_has_holders], [], [], [#include <libdevmapper.h>])
AC_CHECK_DECLS([dm_device_get_name], [], [], [#include <libdevmapper.h>])
AC_CHECK_DECLS([DM_DEVICE_GET_TARGET_VERSION], [], [], [#include <libdevmapper.h>])
AC_CHECK_DECLS([DM_UDEV_DISABLE_DISK_RULES_FLAG], [have_cookie=yes], [have_cookie=no], [#include <libdevmapper.h>])
if test "x$enable_udev" = xyes; then
if test "x$have_cookie" = xno; then
@@ -384,13 +352,11 @@ LIBS=$saved_LIBS
dnl Check for JSON-C used in LUKS2
PKG_CHECK_MODULES([JSON_C], [json-c])
AC_CHECK_DECLS([json_object_object_add_ex], [], [], [#include <json-c/json.h>])
AC_CHECK_DECLS([json_object_deep_copy], [], [], [#include <json-c/json.h>])
dnl Crypto backend configuration.
AC_ARG_WITH([crypto_backend],
AS_HELP_STRING([--with-crypto_backend=BACKEND], [crypto backend (gcrypt/openssl/nss/kernel/nettle) [openssl]]),
[], [with_crypto_backend=openssl])
AS_HELP_STRING([--with-crypto_backend=BACKEND], [crypto backend (gcrypt/openssl/nss/kernel/nettle) [gcrypt]]),
[], [with_crypto_backend=gcrypt])
dnl Kernel crypto API backend needed for benchmark and tcrypt
AC_ARG_ENABLE([kernel_crypto],
@@ -580,6 +546,35 @@ AC_DEFUN([CS_ABSPATH], [
esac
])
dnl ==========================================================================
dnl Python bindings
AC_ARG_ENABLE([python],
AS_HELP_STRING([--enable-python], [enable Python bindings]))
AC_ARG_WITH([python_version],
AS_HELP_STRING([--with-python_version=VERSION], [required Python version [2.6]]),
[PYTHON_VERSION=$withval], [PYTHON_VERSION=2.6])
if test "x$enable_python" = "xyes"; then
AM_PATH_PYTHON([$PYTHON_VERSION])
AC_PATH_PROGS([PYTHON_CONFIG], [python${PYTHON_VERSION}-config python-config], [no])
if test "${PYTHON_CONFIG}" = "no"; then
AC_MSG_ERROR([cannot find python${PYTHON_VERSION}-config or python-config in PATH])
fi
AC_MSG_CHECKING(for python headers using $PYTHON_CONFIG --includes)
PYTHON_INCLUDES=$($PYTHON_CONFIG --includes)
AC_MSG_RESULT($PYTHON_INCLUDES)
AC_SUBST(PYTHON_INCLUDES)
AC_MSG_CHECKING(for python libraries using $PYTHON_CONFIG --libs)
PYTHON_LIBS=$($PYTHON_CONFIG --libs)
AC_MSG_RESULT($PYTHON_LIBS)
AC_SUBST(PYTHON_LIBS)
fi
AM_CONDITIONAL([PYTHON_CRYPTSETUP], [test "x$enable_python" = "xyes"])
dnl ==========================================================================
CS_STR_WITH([plain-hash], [password hashing function for plain mode], [ripemd160])
CS_STR_WITH([plain-cipher], [cipher for plain mode], [aes])
@@ -591,28 +586,17 @@ CS_STR_WITH([luks1-cipher], [cipher for LUKS1], [aes])
CS_STR_WITH([luks1-mode], [cipher mode for LUKS1], [xts-plain64])
CS_NUM_WITH([luks1-keybits],[key length in bits for LUKS1], [256])
AC_ARG_ENABLE([luks_adjust_xts_keysize], AS_HELP_STRING([--disable-luks-adjust-xts-keysize],
[XTS mode requires two keys, double default LUKS keysize if needed]),
[], [enable_luks_adjust_xts_keysize=yes])
if test "x$enable_luks_adjust_xts_keysize" = "xyes"; then
AC_DEFINE(ENABLE_LUKS_ADJUST_XTS_KEYSIZE, 1, [XTS mode - double default LUKS keysize if needed])
fi
CS_STR_WITH([luks2-pbkdf], [Default PBKDF algorithm (pbkdf2 or argon2i/argon2id) for LUKS2], [argon2i])
CS_NUM_WITH([luks1-iter-time], [PBKDF2 iteration time for LUKS1 (in ms)], [2000])
CS_NUM_WITH([luks2-iter-time], [Argon2 PBKDF iteration time for LUKS2 (in ms)], [2000])
CS_NUM_WITH([luks2-memory-kb], [Argon2 PBKDF memory cost for LUKS2 (in kB)], [1048576])
CS_NUM_WITH([luks2-parallel-threads],[Argon2 PBKDF max parallel cost for LUKS2 (if CPUs available)], [4])
CS_STR_WITH([luks2-keyslot-cipher], [fallback cipher for LUKS2 keyslot (if data encryption is incompatible)], [aes-xts-plain64])
CS_NUM_WITH([luks2-keyslot-keybits],[fallback key size for LUKS2 keyslot (if data encryption is incompatible)], [512])
CS_STR_WITH([loopaes-cipher], [cipher for loop-AES mode], [aes])
CS_NUM_WITH([loopaes-keybits],[key length in bits for loop-AES mode], [256])
CS_NUM_WITH([keyfile-size-maxkb],[maximum keyfile size (in KiB)], [8192])
CS_NUM_WITH([integrity-keyfile-size-maxkb],[maximum integritysetup keyfile size (in KiB)], [4])
CS_NUM_WITH([passphrase-size-max],[maximum passphrase size (in characters)], [512])
CS_NUM_WITH([passphrase-size-max],[maximum keyfile size (in characters)], [512])
CS_STR_WITH([verity-hash], [hash function for verity mode], [sha256])
CS_NUM_WITH([verity-data-block], [data block size for verity mode], [4096])
@@ -642,8 +626,8 @@ AC_SUBST(DEFAULT_LUKS2_LOCK_DIR_PERMS)
dnl Override default LUKS format version (for cryptsetup or cryptsetup-reencrypt format actions only).
AC_ARG_WITH([default_luks_format],
AS_HELP_STRING([--with-default-luks-format=FORMAT], [default LUKS format version (LUKS1/LUKS2) [LUKS2]]),
[], [with_default_luks_format=LUKS2])
AS_HELP_STRING([--with-default-luks-format=FORMAT], [default LUKS format version (LUKS1/LUKS2) [LUKS1]]),
[], [with_default_luks_format=LUKS1])
case $with_default_luks_format in
LUKS1) default_luks=CRYPT_LUKS1 ;;

View File

@@ -195,7 +195,7 @@
2011-03-05 Milan Broz <mbroz@redhat.com>
* Add exception to COPYING for binary distribution linked with OpenSSL library.
* Set secure data flag (wipe all ioctl buffers) if devmapper library supports it.
* Set secure data flag (wipe all ioclt buffers) if devmapper library supports it.
2011-01-29 Milan Broz <mbroz@redhat.com>
* Fix mapping removal if device disappeared but node still exists.
@@ -636,7 +636,7 @@
2006-03-15 Clemens Fruhwirth <clemens@endorphin.org>
* configure.in: 1.0.3-rc3. Most displease release ever.
* configure.in: 1.0.3-rc3. Most unplease release ever.
* lib/setup.c (__crypt_create_device): More verbose error message.
2006-02-26 Clemens Fruhwirth <clemens@endorphin.org>

View File

@@ -1,7 +1,7 @@
/*
* libcryptsetup API log example
* An example of using logging through libcryptsetup API
*
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2018, Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,8 +25,10 @@
#include <libcryptsetup.h>
/*
* This is an example of crypt_set_log_callback API callback.
* 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)
{
@@ -69,7 +71,7 @@ int main(void)
return 2;
}
/* crypt_set_log_callback() - register a log callback for crypt context */
/* 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 */
@@ -81,7 +83,7 @@ int main(void)
/* release crypt context */
crypt_free(cd);
/* Initialize default (global) log callback */
/* 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");

View File

@@ -1,7 +1,7 @@
/*
* libcryptsetup API - using LUKS device example
* An example of using LUKS device through libcryptsetup API
*
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2018, Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -29,18 +29,23 @@
static int format_and_add_keyslots(const char *path)
{
struct crypt_device *cd;
struct crypt_params_luks1 params;
int r;
/*
* The crypt_init() call is used to initialize crypt_device context,
* The path parameter specifies a device path.
* 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.
*
* For path, you can use either link to a file or block device.
* The loopback device will be detached automatically.
* 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) {
if (r < 0 ) {
printf("crypt_init() failed for %s.\n", path);
return r;
}
@@ -48,37 +53,73 @@ static int format_and_add_keyslots(const char *path)
printf("Context is attached to block device %s.\n", crypt_get_device_name(cd));
/*
* So far, no data were written to the device.
* 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 as a LUKS device after 5 seconds.\n"
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().
* 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_LUKS2, /* LUKS2 is a new LUKS format; use CRYPT_LUKS1 for LUKS1 */
CRYPT_LUKS1, /* LUKS1 is standard LUKS header */
"aes", /* used cipher */
"xts-plain64", /* used block mode and IV */
"xts-plain64", /* used block mode and IV generator*/
NULL, /* generate UUID */
NULL, /* generate volume key from RNG */
512 / 8, /* 512bit key - here AES-256 in XTS mode, size is in bytes */
NULL); /* default parameters */
256 / 8, /* 256bit key - here AES-128 in XTS mode, size is in bytes */
&params); /* parameters above */
if (r < 0) {
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 a LUKS header, but there is no active keyslot.
* 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.
*
* crypt_keyslot_add_* call stores the volume_key in the encrypted form into the keyslot.
* 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, the volume key is stored internally.
* 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 */
@@ -96,8 +137,8 @@ static int format_and_add_keyslots(const char *path)
printf("The first keyslot is initialized.\n");
/*
* Add another keyslot, now authenticating with the first keyslot.
* It decrypts the volume key from the first keyslot and creates a new one with the specified passphrase.
* 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 */
@@ -123,18 +164,21 @@ static int activate_and_check_status(const char *path, const char *device_name)
/*
* 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) {
if (r < 0 ) {
printf("crypt_init() failed for %s.\n", path);
return r;
}
/*
* crypt_load() is used to load existing LUKS header from a block device
* crypt_load() is used to load the LUKS header from block device
* into crypt_device context.
*/
r = crypt_load(cd, /* crypt context */
CRYPT_LUKS, /* requested type - here LUKS of any type */
CRYPT_LUKS1, /* requested type */
NULL); /* additional parameters (not used) */
if (r < 0) {
@@ -144,11 +188,11 @@ static int activate_and_check_status(const char *path, const char *device_name)
}
/*
* Device activation creates a device-mapper device with the specified name.
* 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,/* the keyslot use (try all here) */
CRYPT_ANY_SLOT,/* which slot use (ANY - try all) */
"foo", 3, /* passphrase */
CRYPT_ACTIVATE_READONLY); /* flags */
if (r < 0) {
@@ -157,13 +201,13 @@ static int activate_and_check_status(const char *path, const char *device_name)
return r;
}
printf("%s device %s/%s is active.\n", crypt_get_type(cd), crypt_get_dir(), device_name);
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 the active device.
* Get info about active device (query DM backend)
*/
r = crypt_get_active_device(cd, device_name, &cad);
if (r < 0) {
@@ -191,7 +235,7 @@ static int handle_active_device(const char *device_name)
int r;
/*
* crypt_init_by_name() initializes context by an active device-mapper name
* 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) {
@@ -208,7 +252,7 @@ static int handle_active_device(const char *device_name)
}
/*
* crypt_deactivate() is used to deactivate a device
* crypt_deactivate() is used to deactivate device
*/
r = crypt_deactivate(cd, device_name);
if (r < 0) {

Binary file not shown.

View File

@@ -46,7 +46,7 @@ Side effect of reencryption is that final device will contain
only ciphertext (for all sectors) so even if device was not properly
wiped by random data, after reencryption you cannot distinguish
which sectors are used.
(Reencryption is done always for the whole device.)
(Reecryption is done always for the whole device.)
There are for sure bugs, please TEST IT IN TEST ENVIRONMENT before
use for your data.

View File

@@ -1,210 +0,0 @@
Cryptsetup 2.1.0 Release Notes
==============================
Stable release with new features and bug fixes.
Cryptsetup 2.1 version uses a new on-disk LUKS2 format as the default
LUKS format and increases default LUKS2 header size.
The legacy LUKS (referenced as LUKS1) will be fully supported forever
as well as a traditional and fully backward compatible format.
When upgrading a stable distribution, please use configure option
--with-default-luks-format=LUKS1 to maintain backward compatibility.
This release also switches to OpenSSL as a default cryptographic
backend for LUKS header processing. Use --with-crypto_backend=gcrypt
configure option if you need to preserve legacy libgcrypt backend.
Please do not use LUKS2 without properly configured backup or
in production systems that need to be compatible with older systems.
Changes since version 2.0.6
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* The default for cryptsetup LUKS format action is now LUKS2.
You can use LUKS1 with cryptsetup option --type luks1.
* The default size of the LUKS2 header is increased to 16 MB.
It includes metadata and the area used for binary keyslots;
it means that LUKS header backup is now 16MB in size.
Note, that used keyslot area is much smaller, but this increase
of reserved space allows implementation of later extensions
(like online reencryption).
It is fully compatible with older cryptsetup 2.0.x versions.
If you require to create LUKS2 header with the same size as
in the 2.0.x version, use --offset 8192 option for luksFormat
(units are in 512-bytes sectors; see notes below).
* Cryptsetup now doubles LUKS default key size if XTS mode is used
(XTS mode uses two internal keys). This does not apply if key size
is explicitly specified on the command line and it does not apply
for the plain mode.
This fixes a confusion with AES and 256bit key in XTS mode where
code used AES128 and not AES256 as often expected.
Also, the default keyslot encryption algorithm (if cannot be derived
from data encryption algorithm) is now available as configure
options --with-luks2-keyslot-cipher and --with-luks2-keyslot-keybits.
The default is aes-xts-plain64 with 2 * 256-bits key.
* Default cryptographic backend used for LUKS header processing is now
OpenSSL. For years, OpenSSL provided better performance for PBKDF.
NOTE: Cryptsetup/libcryptsetup supports several cryptographic
library backends. The fully supported are libgcrypt, OpenSSL and
kernel crypto API. FIPS mode extensions are maintained only for
libgcrypt and OpenSSL. Nettle and NSS are usable only for some
subset of algorithms and cannot provide full backward compatibility.
You can always switch to other backends by using a configure switch,
for libgcrypt (compatibility for older distributions) use:
--with-crypto_backend=gcrypt
* The Python bindings are no longer supported and the code was removed
from cryptsetup distribution. Please use the libblockdev project
that already covers most of the libcryptsetup functionality
including LUKS2.
* Cryptsetup now allows using --offset option also for luksFormat.
It means that the specified offset value is used for data offset.
LUKS2 header areas are automatically adjusted according to this value.
(Note units are in 512-byte sectors due to the previous definition
of this option in plain mode.)
This option can replace --align-payload with absolute alignment value.
* Cryptsetup now supports new refresh action (that is the alias for
"open --refresh").
It allows changes of parameters for an active device (like root
device mapping), for example, it can enable or disable TRIM support
on-the-fly.
It is supported for LUKS1, LUKS2, plain and loop-AES devices.
* Integritysetup now supports mode with detached data device through
new --data-device option.
Since kernel 4.18 there is a possibility to specify external data
device for dm-integrity that stores all integrity tags.
* Integritysetup now supports automatic integrity recalculation
through new --integrity-recalculate option.
Linux kernel since version 4.18 supports automatic background
recalculation of integrity tags for dm-integrity.
Other changes and fixes
~~~~~~~~~~~~~~~~~~~~~~~
* Fix for crypt_wipe call to allocate space if the header is backed
by a file. This means that if you use detached header file, it will
now have always the full size after luksFormat, even if only
a few keyslots are used.
* Fixes to offline cryptsetup-reencrypt to preserve LUKS2 keyslots
area sizes after reencryption and fixes for some other issues when
creating temporary reencryption headers.
* Added some FIPS mode workarounds. We cannot (yet) use Argon2 in
FIPS mode, libcryptsetup now fallbacks to use PBKDF2 in FIPS mode.
* Rejects conversion to LUKS1 if PBKDF2 hash algorithms
in keyslots differ.
* The hash setting on command line now applies also to LUKS2 PBKDF2
digest. In previous versions, the LUKS2 key digest used PBKDF2-SHA256
(except for converted headers).
* Allow LUKS2 keyslots area to increase if data offset allows it.
Cryptsetup can fine-tune LUKS2 metadata area sizes through
--luks2-metadata-size=BYTES and --luks2-keyslots-size=BYTES.
Please DO NOT use these low-level options until you need it for
some very specific additional feature.
Also, the code now prints these LUKS2 header area sizes in dump
command.
* For LUKS2, keyslot can use different encryption that data with
new options --keyslot-key-size=BITS and --keyslot-cipher=STRING
in all commands that create new LUKS keyslot.
Please DO NOT use these low-level options until you need it for
some very specific additional feature.
* Code now avoids data flush when reading device status through
device-mapper.
* The Nettle crypto backend and the userspace kernel crypto API
backend were enhanced to allow more available hash functions
(like SHA3 variants).
* Upstream code now does not require libgcrypt-devel
for autoconfigure, because OpenSSL is the default.
The libgcrypt does not use standard pkgconfig detection and
requires specific macro (part of libgcrypt development files)
to be always present during autoconfigure.
With other crypto backends, like OpenSSL, this makes no sense,
so this part of autoconfigure is now optional.
* Cryptsetup now understands new --debug-json option that allows
an additional dump of some JSON information. These are no longer
present in standard debug output because it could contain some
specific LUKS header parameters.
* The luksDump contains the hash algorithm used in Anti-Forensic
function.
* All debug messages are now sent through configured log callback
functions, so an application can easily use own debug messages
handling. In previous versions debug messages were printed directly
to standard output.)
Libcryptsetup API additions
~~~~~~~~~~~~~~~~~~~~~~~~~~~
These new calls are now exported, for details see libcryptsetup.h:
* crypt_init_data_device
* crypt_get_metadata_device_name
functions to init devices with separate metadata and data device
before a format function is called.
* crypt_set_data_offset
sets the data offset for LUKS to the specified value
in 512-byte sectors.
It should replace alignment calculation in LUKS param structures.
* crypt_get_metadata_size
* crypt_set_metadata_size
allows to set/get area sizes in LUKS header
(according to specification).
* crypt_get_default_type
get default compiled-in LUKS type (version).
* crypt_get_pbkdf_type_params
allows to get compiled-in PBKDF parameters.
* crypt_keyslot_set_encryption
* crypt_keyslot_get_encryption
allows to set/get per-keyslot encryption algorithm for LUKS2.
* crypt_keyslot_get_pbkdf
allows to get PBKDF parameters per-keyslot.
and these new defines:
* CRYPT_LOG_DEBUG_JSON (message type for JSON debug)
* CRYPT_DEBUG_JSON (log level for JSON debug)
* CRYPT_ACTIVATE_RECALCULATE (dm-integrity recalculate flag)
* CRYPT_ACTIVATE_REFRESH (new open with refresh flag)
All existing API calls should remain backward compatible.
Unfinished things & TODO for next releases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Optional authenticated encryption is still an experimental feature
and can have performance problems for high-speed devices and device
with larger IO blocks (like RAID).
* Authenticated encryption does not use encryption for a dm-integrity
journal. While it does not influence data confidentiality or
integrity protection, an attacker can get some more information
from data journal or cause that system will corrupt sectors after
journal replay. (That corruption will be detected though.)
* The LUKS2 metadata area increase is mainly needed for the new online
reencryption as the major feature for the next release.

View File

@@ -1,279 +0,0 @@
Cryptsetup 2.2.0 Release Notes
==============================
Stable release with new experimental features and bug fixes.
Cryptsetup 2.2 version introduces a new LUKS2 online reencryption
extension that allows reencryption of mounted LUKS2 devices
(device in use) in the background.
Online reencryption is a complex feature. Please be sure you
have a full data backup before using this feature.
Changes since version 2.1.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~
LUKS2 online reencryption
~~~~~~~~~~~~~~~~~~~~~~~~~
The reencryption is intended to provide a reliable way to change
volume key or an algorithm change while the encrypted device is still
in use.
It is based on userspace-only approach (no kernel changes needed)
that uses the device-mapper subsystem to remap active devices on-the-fly
dynamically. The device is split into several segments (encrypted by old
key, new key and so-called hotzone, where reencryption is actively running).
The flexible LUKS2 metadata format is used to store intermediate states
(segment mappings) and both version of keyslots (old and new keys).
Also, it provides a binary area (in the unused keyslot area space)
to provide recovery metadata in the case of unexpected failure during
reencryption. LUKS2 header is during the reencryption marked with
"online-reencryption" keyword. After the reencryption is finished,
this keyword is removed, and the device is backward compatible with all
older cryptsetup tools (that support LUKS2).
The recovery supports three resilience modes:
- checksum: default mode, where individual checksums of ciphertext hotzone
sectors are stored, so the recovery process can detect which sectors were
already reencrypted. It requires that the device sector write is atomic.
- journal: the hotzone is journaled in the binary area
(so the data are written twice)
- none: performance mode; there is no protection
(similar to old offline reencryption)
These resilience modes are not available if reencryption uses data shift.
Note: until we have full documentation (both of the process and metadata),
please refer to Ondrej's slides (some slight details are no longer relevant)
https://okozina.fedorapeople.org/online-disk-reencryption-with-luks2-compact.pdf
The offline reencryption tool (cryptsetup-reencrypt) is still supported
for both LUKS1 and LUKS2 format.
Cryptsetup examples for reencryption
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The reencryption feature is integrated directly into cryptsetup utility
as the new "reencrypt" action (command).
There are three basic modes - to perform reencryption (change of already
existing LUKS2 device), to add encryption to plaintext device and to remove
encryption from a device (decryption).
In all cases, if existing LUKS2 metadata contains information about
the ongoing reencryption process, following reencrypt command continues
with the ongoing reencryption process until it is finished.
You can activate a device with ongoing reencryption as the standard LUKS2
device, but the reencryption process will not continue until the cryptsetup
reencrypt command is issued.
1) Reencryption
~~~~~~~~~~~~~~~
This mode is intended to change any attribute of the data encryption
(change of the volume key, algorithm or sector size).
Note that authenticated encryption is not yet supported.
You can start the reencryption process by specifying a LUKS2 device or with
a detached LUKS2 header.
The code should automatically recognize if the device is in use (and if it
should use online mode of reencryption).
If you do not specify parameters, only volume key is changed
(a new random key is generated).
# cryptsetup reencrypt <device> [--header <hdr>]
You can also start reencryption using active mapped device name:
# cryptsetup reencrypt --active-name <name>
You can also specify the resilience mode (none, checksum, journal) with
--resilience=<mode> option, for checksum mode also the hash algorithm with
--resilience-hash=<alg> (only hash algorithms supported by cryptographic
backend are available).
The maximal size of reencryption hotzone can be limited by
--hotzone-size=<size> option and applies to all reencryption modes.
Note that for checksum and journal mode hotzone size is also limited
by available space in binary keyslot area.
2) Encryption
~~~~~~~~~~~~~
This mode provides a way to encrypt a plaintext device to LUKS2 format.
This option requires reduction of device size (for LUKS2 header) or new
detached header.
# cryptsetup reencrypt <device> --encrypt --reduce-device-size <size>
Or with detached header:
# cryptsetup reencrypt <device> --encrypt --header <hdr>
3) Decryption
~~~~~~~~~~~~~
This mode provides the removal of existing LUKS2 encryption and replacing
a device with plaintext content only.
For now, we support only decryption with a detached header.
# cryptsetup reencrypt <device> --decrypt --header <hdr>
For all three modes, you can split the process to metadata initialization
(prepare keyslots and segments but do not run reencryption yet) and the data
reencryption step by using --init-only option.
Prepares metadata:
# cryptsetup reencrypt --init-only <parameters>
Starts the data processing:
# cryptsetup reencrypt <device>
Please note, that due to the Linux kernel limitation, the encryption or
decryption process cannot be run entirely online - there must be at least
short offline window where operation adds/removes device-mapper crypt (LUKS2) layer.
This step should also include modification of /etc/crypttab and fstab UUIDs,
but it is out of the scope of cryptsetup tools.
Limitations
~~~~~~~~~~~
Most of these limitations will be (hopefully) fixed in next versions.
* Only one active keyslot is supported (all old keyslots will be removed
after reencryption).
* Only block devices are now supported as parameters. As a workaround
for images in a file, please explicitly map a loop device over the image
and use the loop device as the parameter.
* Devices with authenticated encryption are not supported. (Later it will
be limited by the fixed per-sector metadata, per-sector metadata size
cannot be changed without a new device format operation.)
* The reencryption uses userspace crypto library, with fallback to
the kernel (if available). There can be some specific configurations
where the fallback does not provide optimal performance.
* There are no translations of error messages until the final release
(some messages can be rephrased as well).
* The repair command is not finished; the recovery of interrupted
reencryption is made automatically on the first device activation.
* Reencryption triggers too many udev scans on metadata updates (on closing
write enabled file descriptors). This has a negative performance impact on the whole
reencryption and generates excessive I/O load on the system.
New libcryptsetup reencryption API
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The libcryptsetup contains new API calls that are used to setup and
run the reencryption.
Note that there can be some changes in API implementation of these functions
and/or some new function can be introduced in final cryptsetup 2.2 release.
New API symbols (see documentation in libcryptsetup.h)
* struct crypt_params_reencrypt - reencryption parameters
* crypt_reencrypt_init_by_passphrase
* crypt_reencrypt_init_by_keyring
- function to configure LUKS2 metadata for reencryption;
if metadata already exists, it configures the context from this metadata
* crypt_reencrypt
- run the reencryption process (processing the data)
- the optional callback function can be used to interrupt the reencryption
or report the progress.
* crypt_reencrypt_status
- function to query LUKS2 metadata about the reencryption state
Other changes and fixes
~~~~~~~~~~~~~~~~~~~~~~~
* Add optional global serialization lock for memory hard PBKDF.
(The --serialize-memory-hard-pbkdf option in cryptsetup and
CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF in activation flag.)
This is an "ugly" optional workaround for a situation when multiple devices
are being activated in parallel (like systemd crypttab activation).
The system instead of returning ENOMEM (no memory available) starts
out-of-memory (OOM) killer to kill processes randomly.
Until we find a reliable way how to work with memory-hard function
in these situations, cryptsetup provide a way how to serialize memory-hard
unlocking among parallel cryptsetup instances to workaround this problem.
This flag is intended to be used only in very specific situations,
never use it directly :-)
* Abort conversion to LUKS1 with incompatible sector size that is
not supported in LUKS1.
* Report error (-ENOENT) if no LUKS keyslots are available. User can now
distinguish between a wrong passphrase and no keyslot available.
* Fix a possible segfault in detached header handling (double free).
* Add integritysetup support for bitmap mode introduced in Linux kernel 5.2.
Integritysetup now supports --integrity-bitmap-mode option and
--bitmap-sector-per-bit and --bitmap-flush-time commandline options.
In the bitmap operation mode, if a bit in the bitmap is 1, the corresponding
region's data and integrity tags are not synchronized - if the machine
crashes, the unsynchronized regions will be recalculated.
The bitmap mode is faster than the journal mode because we don't have
to write the data twice, but it is also less reliable, because if data
corruption happens when the machine crashes, it may not be detected.
This can be used only for standalone devices, not with dm-crypt.
* The libcryptsetup now keeps all file descriptors to underlying device
open during the whole lifetime of crypt device context to avoid excessive
scanning in udev (udev run scan on every descriptor close).
* The luksDump command now prints more info for reencryption keyslot
(when a device is in-reencryption).
* New --device-size parameter is supported for LUKS2 reencryption.
It may be used to encrypt/reencrypt only the initial part of the data
device if the user is aware that the rest of the device is empty.
Note: This change causes API break since the last rc0 release
(crypt_params_reencrypt structure contains additional field).
* New --resume-only parameter is supported for LUKS2 reencryption.
This flag resumes reencryption process if it exists (not starting
new reencryption).
* The repair command now tries LUKS2 reencryption recovery if needed.
* If reencryption device is a file image, an interactive dialog now
asks if reencryption should be run safely in offline mode
(if autodetection of active devices failed).
* Fix activation through a token where dm-crypt volume key was not
set through keyring (but using old device-mapper table parameter mode).
* Online reencryption can now retain all keyslots (if all passphrases
are provided). Note that keyslot numbers will change in this case.
* Allow volume key file to be used if no LUKS2 keyslots are present.
If all keyslots are removed, LUKS2 has no longer information about
the volume key size (there is only key digest present).
Please use --key-size option to open the device or add a new keyslot
in these cases.
* Print a warning if online reencrypt is called over LUKS1 (not supported).
* Fix TCRYPT KDF failure in FIPS mode.
Some crypto backends support plain hash in FIPS mode but not for PBKDF2.
* Remove FIPS mode restriction for crypt_volume_key_get.
It is an application responsibility to use this API in the proper context.
* Reduce keyslots area size in luksFormat when the header device is too small.
Unless user explicitly asks for keyslots areas size (either via
--luks2-keyslots-size or --offset) reduce keyslots size so that it fits
in metadata device.
* Make resize action accept --device-size parameter (supports units suffix).

View File

@@ -1,36 +0,0 @@
Cryptsetup 2.2.1 Release Notes
==============================
Stable bug-fix release.
This version contains a fix for a possible data corruption bug
on 32-bit platforms.
All users of cryptsetup 2.1 and 2.2 should upgrade to this version.
Changes since version 2.2.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix possible data length and IV offset overflow on 32bit architectures.
Other 64-bit architectures are not affected.
The flawed helper function prototypes (introduced in version 2.1.0) used
size_t type, that is 32-bit integer on 32-bit systems.
This patch fixes the problem to properly use 64-bit types.
If the offset parameter addresses devices larger than 2TB, the value
overflows and stores incorrect information in the metadata.
For example, integrity device is smaller than expected size if used
over large disk on 32-bit architecture.
This issue is not present with the standard LUKS1/LUKS2 devices without
integrity extensions.
* Fix a regression in TrueCrypt/VeraCrypt system partition activation.
* Reinstate missing backing file hint for loop device.
If the encrypted device is backed by a file (loopback), cryptsetup now
shows the path to the backing file in passphrase query (as in 1.x version).
* LUKS2 reencryption block size is now aligned to reported optimal IO size.
This change eliminates possible non-aligned device warnings in kernel log
during reencryption.

View File

@@ -1,56 +0,0 @@
Cryptsetup 2.2.2 Release Notes
==============================
Stable bug-fix release.
All users of cryptsetup 2.1 and 2.2 should upgrade to this version.
Changes since version 2.2.1
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Print error message if a keyslot open failed for a different reason
than wrong passwords (for example there is not enough memory).
Only an exit code was present in this case.
* The progress function switches unit sizes (B/s to GiB/s) according
to the actual speed. Also, it properly calculates speed in the case
of a resumed reencryption operation.
* The --version now supports short -V short option and better handles
common option priorities.
* If cryptsetup wipes signatures during format actions through blkid,
it also prints signature device offsets.
* Compilation now properly uses LTLIBINTL gettext setting in Makefiles.
* Device-mapper backend now supports new DM_GET_TARGET_VERSION ioctl
(available since Linux kernel 5.4).
This should help to detect some kernel/userspace incompatibilities
earlier later after a failed device activation.
* Fixes LUKS2 reencryption on systems without kernel keyring.
* Fixes unlocking prompt for partitions mapped through loop devices
(to properly show the backing device).
* For LUKS2 decryption, a device is now marked for deferred removal
to be automatically deactivated.
* Reencryption now limits hotzone size to be maximal 1 GiB or 1/4
system memory (if lower).
* Reencryption now retains activation flags during online reencryption.
* Reencryption now allows LUKS2 device to activate device right after
LUKS2 encryption is initialized through optional active device name
for cryptsetup reencrypt --encrypt command.
This could help with automated encryption during boot.
NOTE: It means that part of the device is still not encrypted during
activation. Use with care!
* Fixes failure in resize and plain format activation if activated device
size was not aligned to underlying logical device size.
* Fixes conversion to LUKS2 format with detached header if a detached
header size was smaller than the expected aligned LUKS1 header size.

View File

@@ -1,209 +0,0 @@
Cryptsetup 2.3.0 Release Notes
==============================
Stable release with new experimental features and bug fixes.
Cryptsetup 2.3 version introduces support for BitLocker-compatible
devices (BITLK format). This format is used in Windows systems,
and in combination with a filesystem driver, cryptsetup now provides
native read-write access to BitLocker Full Disk Encryption devices.
The BITLK implementation is based on publicly available information
and it is an independent and opensource implementation that allows
to access this proprietary disk encryption.
Changes since version 2.2.2
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* BITLK (Windows BitLocker compatible) device access
BITLK userspace implementation is based on the master thesis and code
provided by Vojtech Trefny. Also, thanks to other opensource projects
like libbde (that provide alternative approach to decode this format)
we were able to verify cryptsetup implementation.
NOTE: Support for the BITLK device is EXPERIMENTAL and will require
a lot of testing. If you get some error message (mainly unsupported
metadata in the on-disk header), please help us by submitting an issue
to cryptsetup project, so we can fix it. Thank you!
Cryptsetup supports BITLK activation through passphrase or recovery
passphrase for existing devices (BitLocker and Bitlocker to Go).
Activation through TPM, SmartCard, or any other key protector
is not supported. And in some situations, mainly for TPM bind to some
PCR registers, it could be even impossible on Linux in the future.
All metadata (key protectors) are handled read-only, cryptsetup cannot
create or modify them. Except for old devices (created in old Vista
systems), all format variants should be recognized.
Data devices can be activated read-write (followed by mounting through
the proper filesystem driver). To access filesystem on the decrypted device
you need properly installed driver (vfat, NTFS or exFAT).
Foe AES-XTS, activation is supported on all recent Linux kernels.
For older AES-CBC encryption, Linux Kernel version 5.3 is required
(support for special IV variant); for AES-CBC with Elephant diffuser,
Linux Kernel 5.6 is required.
Please note that CBC variants are legacy, and we provide it only
for backward compatibility (to be able to access old drives).
Cryptsetup command now supports the new "bitlk" format and implement dump,
open, status, and close actions.
To activate a BITLK device, use
# cryptsetup open --type bitlk <device> <name>
or with alias
# cryptsetup bitlkOpen <device> <name>
Then with properly installed fs driver (usually NTFS, vfat or exFAT),
you can mount the plaintext device /dev/mapper<name> device as a common
filesystem.
To print metadata information about BITLK device, use
# crypotsetup bitlkDump <device>
To print information about the active device, use
# cryptsetup status <name>
Example (activation of disk image):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Recent blkid recognizes BitLocker device,just to verity
# blkid bitlocker_xts_ntfs.img
bitlocker_xts_ntfs.img: TYPE="BitLocker"
# Print visible metadata information (on-disk, form the image)
# cryptsetup bitlkDump bitlocker_xts_ntfs.img
Info for BITLK device bitlocker_xts_ntfs.img.
Version: 2
GUID: ...
Created: Wed Oct 23 17:38:15 2019
Description: DESKTOP-xxxxxxx E: 23.10.2019
Cipher name: aes
Cipher mode: xts-plain64
Cipher key: 128 bits
Keyslots:
0: VMK
GUID: ...
Protection: VMK protected with passphrase
Salt: ...
Key data size: 44 [bytes]
1: VMK
GUID: ...
Protection: VMK protected with recovery passphrase
Salt: ...
Key data size: 44 [bytes]
2: FVEK
Key data size: 44 [bytes]
# Activation (recovery passphrase works the same as password)
# cryptsetup bitlkOpen bitlocker_xts_ntfs.img test -v
Enter passphrase for bitlocker_xts_ntfs.img:
Command successful.
# Information about the active device
# cryptsetup status test
/dev/mapper/test is active.
type: BITLK
cipher: aes-xts-plain64
keysize: 128 bits
...
# Plaintext device should now contain decrypted NTFS filesystem
# blkid /dev/mapper/test
/dev/mapper/test: UUID="..." TYPE="ntfs"
# And can be mounted
# mount /dev/mapper/test /mnt/tst
# Deactivation
# umount /mnt/tst
# cryptsetup close test
* Veritysetup now supports activation with additional PKCS7 signature
of root hash through --root-hash-signature option.
The signature uses an in-kernel trusted key to validate the signature
of the root hash during activation. This option requires Linux kernel
5.4 with DM_VERITY_VERIFY_ROOTHASH_SIG option.
Verity devices activated with signature now has a special flag
(with signature) active in device status (veritysetup status <name>).
Usage:
# veritysetup open <data_device> name <hash_device> <root_hash> \
--root-hash-signature=<roothash_p7_sig_file>
* Integritysetup now calculates hash integrity size according to algorithm
instead of requiring an explicit tag size.
Previously, when integritysetup formats a device with hash or
HMAC integrity checksums, it required explicitly tag size entry from
a user (or used default value).
This led to confusion and unexpected shortened tag sizes.
Now, libcryptsetup calculates tag size according to real hash output.
Tag size can also be specified, then it warns if these values differ.
* Integritysetup now supports fixed padding for dm-integrity devices.
There was an in-kernel bug that wasted a lot of space when using metadata
areas for integrity-protected devices if a larger sector size than
512 bytes was used.
This problem affects both stand-alone dm-integrity and also LUKS2 with
authenticated encryption and larger sector size.
The new extension to dm-integrity superblock is needed, so devices
with the new optimal padding cannot be activated on older systems.
Integritysetup/Cryptsetup will use new padding automatically if it
detects the proper kernel. To create a compatible device with
the old padding, use --integrity-legacy-padding option.
* A lot of fixes to online LUKS2 reecryption.
* Add crypt_resume_by_volume_key() function to libcryptsetup.
If a user has a volume key available, the LUKS device can be resumed
directly using the provided volume key.
No keyslot derivation is needed, only the key digest is checked.
* Implement active device suspend info.
Add CRYPT_ACTIVATE_SUSPENDED bit to crypt_get_active_device() flags
that informs the caller that device is suspended (luksSuspend).
* Allow --test-passphrase for a detached header.
Before this fix, we required a data device specified on the command
line even though it was not necessary for the passphrase check.
* Allow --key-file option in legacy offline encryption.
The option was ignored for LUKS1 encryption initialization.
* Export memory safe functions.
To make developing of some extensions simpler, we now export
functions to handle memory with proper wipe on deallocation.
* Fail crypt_keyslot_get_pbkdf for inactive LUKS1 keyslot.
Libcryptsetup API extensions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The libcryptsetup API is backward compatible for existing symbols.
New symbols
crypt_set_compatibility
crypt_get_compatibility;
crypt_resume_by_volume_key;
crypt_activate_by_signed_key;
crypt_safe_alloc;
crypt_safe_realloc;
crypt_safe_free;
crypt_safe_memzero;
New defines introduced :
CRYPT_BITLK "BITLK" - BITLK (BitLocker-compatible mode
CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING - dm-integrity legacy padding
CRYPT_VERITY_ROOT_HASH_SIGNATURE - dm-verity root hash signature
CRYPT_ACTIVATE_SUSPENDED - device suspended info flag

View File

@@ -1,45 +0,0 @@
Cryptsetup 2.3.1 Release Notes
==============================
Stable bug-fix release.
All users of cryptsetup 2.x should upgrade to this version.
Changes since version 2.3.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Support VeraCrypt 128 bytes passwords.
VeraCrypt now allows passwords of maximal length 128 bytes
(compared to legacy TrueCrypt where it was limited by 64 bytes).
* Strip extra newline from BitLocker recovery keys
There might be a trailing newline added by the text editor when
the recovery passphrase was passed using the --key-file option.
* Detect separate libiconv library.
It should fix compilation issues on distributions with iconv
implemented in a separate library.
* Various fixes and workarounds to build on old Linux distributions.
* Split lines with hexadecimal digest printing for large key-sizes.
* Do not wipe the device with no integrity profile.
With --integrity none we performed useless full device wipe.
* Workaround for dm-integrity kernel table bug.
Some kernels show an invalid dm-integrity mapping table
if superblock contains the "recalculate" bit. This causes
integritysetup to not recognize the dm-integrity device.
Integritysetup now specifies kernel options such a way that
even on unpatched kernels mapping table is correct.
* Print error message if LUKS1 keyslot cannot be processed.
If the crypto backend is missing support for hash algorithms
used in PBKDF2, the error message was not visible.
* Properly align LUKS2 keyslots area on conversion.
If the LUKS1 payload offset (data offset) is not aligned
to 4 KiB boundary, new LUKS2 keyslots area in now aligned properly.
* Validate LUKS2 earlier on conversion to not corrupt the device
if binary keyslots areas metadata are not correct.

View File

@@ -1,42 +0,0 @@
Cryptsetup 2.3.2 Release Notes
==============================
Stable bug-fix release.
All users of cryptsetup 2.x should upgrade to this version.
Changes since version 2.3.1
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Support compilation with json-c library version 0.14.
* Update FAQ document for some LUKS2 specific information.
* Add option to dump content of LUKS2 unbound keyslot:
cryptsetup luksDump --unbound -S <slot> <device>
or optionally with --master-key-file option.
The slot number --key-slot (-S) option is mandatory here.
An unbound keyslot store a key is that is not assigned to data
area on disk (LUKS2 allows to store arbitrary keys).
* Rephrase some error messages and remove redundant end-of-lines.
* Add support for discards (TRIM) for standalone dm-integrity devices.
Linux kernel 5.7 adds support for optional discard/TRIM operation
over dm-integrity devices.
It is now supported through --allow-discards integritysetup option.
Note you need to add this flag in all activation calls.
Note that this option cannot be used for LUKS2 authenticated encryption
(that uses dm-integrity for storing additional per-sector metadata).
* Fix cryptsetup-reencrypt to work on devices that do not allow
direct-io device access.
* Fix a crash in the BitLocker-compatible code error path.
* Fix Veracrypt compatible support for longer (>64 bytes) passphrases.
It allows some older images to be correctly opened again.
The issue was introduced in version 2.3.1.

View File

@@ -1,42 +0,0 @@
Cryptsetup 2.3.3 Release Notes
==============================
Stable bug-fix release.
All users of cryptsetup 2.x should upgrade to this version.
Changes since version 2.3.2
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix BitLocker compatible device access that uses native 4kB sectors.
Devices formatted with storage that natively support 4096-bytes
sectors can also use this sector size for encryption units.
* Support large IV count (--iv-large-sectors) cryptsetup option
for plain device mapping.
The large IV count is supported in dm-crypt together with larger
sector encryption. It counts the Initialization Vector (IV) in
a larger sector size instead of 512-bytes sectors.
This option does not have any performance or security impact,
but it can be used for accessing incompatible existing disk images
from other systems.
Only open action with plain device type and sector size > 512 bytes
are supported.
* Fix a memory leak in BitLocker compatible handling.
* Allow EBOIV (Initialization Vector algorithm) use.
The EBOIV initialization vector is intended to be used internally
with BitLocker devices (for CBC mode). It can now be used also
outside of the BitLocker compatible code.
* Require both keyslot cipher and key size options.
If these LUKS2 keyslot parameters were not specified together,
cryptsetup silently failed.
* Update to man pages and FAQ.

View File

@@ -1,112 +0,0 @@
Cryptsetup 2.3.4 Release Notes
==============================
Stable bug-fix release with a security fix (32-bit only).
All users of cryptsetup 2.2.x and later should upgrade to this version.
Changes since version 2.3.3
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix a possible out-of-bounds memory write while validating LUKS2 data
segments metadata (CVE-2020-14382).
This problem can be triggered only on 32-bit builds (64-bit systems
are not affected).
LUKS2 format validation code contains a bug in segments validation code
where the code does not check for possible overflow on memory allocation.
Due to the bug, the libcryptsetup can be tricked to expect such allocation
was successful. Later it may read data from image crafted by an attacker and
actually write such data beyond allocated memory.
The bug was introduced in cryptsetup 2.2.0. All later releases until 2.3.4
are affected.
If you only backport the fix for this CVE, these master branch git commits
should be backported:
52f5cb8cedf22fb3e14c744814ec8af7614146c7
46ee71edcd13e1dad50815ad65c28779aa6f7503
752c9a52798f11d3b765b673ebaa3058eb25316e
Thanks to Tobias Stoeckmann for discovering this issue.
* Ignore reported optimal IO size if not aligned to minimal page size.
Some USB enclosures report bogus block device topology (see lsblk -t) that
prevents LUKS2 format with 4k sector size (reported values are not correctly
aligned). The code now ignores such values and uses the default alignment.
* Added support for new no_read/write_wrokqueue dm-crypt options (kernel 5.9).
These performance options, introduced in kernel 5.9, configure dm-crypt
to bypass read or write workqueues and run encryption synchronously.
Use --perf-no_read_workqueue or --perf-no_write_workqueue cryptsetup arguments
to use these dm-crypt flags.
These options are available only for low-level dm-crypt performance tuning,
use only if you need a change to default dm-crypt behavior.
For LUKS2, these flags can be persistently stored in metadata with
the --persistent option.
* Added support panic_on_corruption option for dm-verity devices (kernel 5.9).
Veritysetup now supports --panic-on-corruption argument that configures
the dm-verity device to panics kernel if a corruption is detected.
This option is intended for specific configurations, do not use it in
standard configurations.
* Support --master-key-file option for online LUKS2 reencryption
This can be used for reencryption of devices that uses protected key AES cipher
on some mainframes crypto accelerators.
* Always return EEXIST error code if a device already exists.
Some libcryptsetup functions (activate_by*) now return EEXIST error code,
so the caller can distinguish that call fails because some parallel process
already activated the device.
Previously all fails returned EINVAL (invalid value).
* Fix a problem in integritysetup if a hash algorithm has dash in the name.
If users want to use blake2b/blake2s, the kernel algorithm name includes
a dash (like "blake2s-256").
Theses algorithms can now be used for integritysetup devices.
* Fix crypto backend to properly handle ECB mode.
Even though it should never be used, it should still work for testing :)
This fixes a bug introduced in cryptsetup version 2.3.2.
* TrueCrypt/VeraCrypt compatible mode now supports the activation of devices
with a larger sector.
TrueCrypt/VeraCrypt always uses 512-byte sector for encryption, but for devices
with a larger native sector, it stores this value in the header.
This patch allows activation of such devices, basically ignoring
the mentioned sector size.
* LUKS2: Do not create excessively large headers.
When creating a LUKS2 header with a specified --offset larger than
the LUKS2 header size, do not create a larger file than needed.
* Fix unspecified sector size for BitLocker compatible mode.
Some BitLocker devices can contain zeroed sector size in the header.
In this case, the 512-byte sector should be used.
The bug was introduced in version 2.3.3.
* Fix reading key data size in metadata for BitLocker compatible mode.
Such devices with an unexpected entry in metadata can now be activated.
Thanks to all users reporting these problems, BitLocker metadata documentation
is not publicly available, and we depend only on these reports.
* Fix typos in documentation.

View File

@@ -1,181 +0,0 @@
Cryptsetup 2.3.5 Release Notes
==============================
Stable bug-fix release with minor extensions.
All users of cryptsetup 2.x and later should upgrade to this version.
Changes since version 2.3.4
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix partial reads of passphrase from an interactive terminal.
Some stable kernels (5.3.11) started to return buffer from a terminal
in parts of maximal size 64 bytes.
This breaks the reading of passphrases longer than 64 characters
entered through an interactive terminal. The change is already fixed
in later kernel releases, but tools now support such partial read from
terminal properly.
* Fix maximal length of password entered through a terminal.
Now the maximal interactive passphrase length is exactly
512 characters (not 511).
* integritysetup: support new dm-integrity HMAC recalculation options.
In older kernels (since version 4.19), an attacker can force
an automatic recalculation of integrity tags by modifying
the dm-integrity superblock.
This is a problem with a keyed algorithms (HMAC), where it expects
nobody can trigger such recalculation without the key.
(Automatic recalculation will start after the next activation.)
Note that dm-integrity in standalone mode was *not* supposed
to provide cryptographic data integrity protection.
Despite that, we try to keep the system secure if keyed algorithms
are used.
Thank Daniel Glöckner for the original report of this problem.
Authenticated encryption that provides data integrity protection (in
combination with dm-crypt and LUKS2) is not affected by this problem.
The fix in the kernel for this problem contains two parts.
Firstly, the dm-integrity kernel module disables integrity
recalculation if keyed algorithms (HMAC) are used.
This change is included in long-term stable kernels.
Secondly, since the kernel version 5.11, dm-integrity introduces
modified protection where a journal-integrity algorithm guards
superblock; also, journal sections are protected. An attacker cannot
copy sectors from one journal section to another, and the superblock
also contains salt to prevent header replacement from another device.
If you want to protect data with HMAC, you should always also use HMAC
for --journal-integrity. Keys can be independent.
If HMAC is used for data but not for the journal, the recalculation
option is disabled.
If you need to use (insecure) backward compatibility implementation,
two new integritysetup options are introduced:
- Use --integrity-legacy-recalc (instead of --integrity-recalc)
to allow recalculation on legacy devices.
- Use --integrity-legacy-hmac in format action to force old insecure
HMAC format.
Libcryptsetup API also introduces flags
CRYPT_COMPAT_LEGACY_INTEGRITY_HMAC and
CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC
to set these through crypt_set_compatibility() call.
* integritysetup: display of recalculating sector in dump command.
* veritysetup: fix verity FEC if stored in the same image with hashes.
Optional FEC (Forward Error Correction) data should cover the whole
data area, hashes (Merkle tree), and optionally additional metadata
(located after hash area).
Unfortunately, if FEC data is stored in the same file as hash,
the calculation wrongly used the whole file size, thus overlaps with
the FEC area itself. This produced unusable and too large FEC data.
There is no problem if the FEC image is a separate image.
The problem is now fixed, introducing FEC blocks calculation as:
- If the hash device is in a separate image, metadata covers the
whole rest of the image after the hash area. (Unchanged behavior.)
- If hash and FEC device is in the image, metadata ends on the FEC
area offset.
Note: there is also a fix for FEC in the dm-verity kernel (on the way
to stable kernels) that fixes error correction with larger RS roots.
* veritysetup: run FEC repair check even if root hash fails.
Note: The userspace FEC verify command reports are only informational
for now. Code does not check verity hash after FEC recovery in
userspace. The Reed-Solomon decoder can then report the possibility
that it fixed data even if parity is too damaged.
This will be fixed in the next major release.
* veritysetup: do not process hash image if hash area is empty.
Sometimes the device is so small that there is only a root hash
needed, and the hash area is not used.
Also, the size of the hash image is not increased for hash block
alignment in this case.
* veritysetup: store verity hash algorithm in superblock in lowercase.
Otherwise, the kernel could refuse the activation of the device.
* bitlk: fix a crash if the device disappears during BitLocker scan.
* bitlk: show a better error when trying to open an NTFS device.
Both BitLocker version 1 and NTFS have the same signature.
If a user opens an NTFS device without BitLocker, it now correctly
informs that it is not a BITLK device.
* bitlk: add support for startup key protected VMKs.
The startup key can be provided in --key-file option for open command.
* Fix LUKS1 repair code (regression since version 1.7.x).
We cannot trust possibly broken keyslots metadata in repair, so the
code recalculates them instead.
This makes the repair code working again when the master boot record
signature overwrites the LUKS header.
* Fix luksKeyChange for LUKS2 with assigned tokens.
The token references are now correctly assigned to the new keyslot
number.
* Fix cryptsetup resize using LUKS2 tokens.
Code needlessly asked for passphrase even though volume key was
already unlocked via LUKS2 token.
* Print a visible error if device resize is not supported.
* Add error message when suspending wrong non-LUKS device.
* Fix default XTS mode key size in reencryption.
The same luksFormat logic (double key size because XTS uses two keys)
is applied in the reencryption code.
* Rephrase missing locking directory warning and move it to debug level.
The system should later provide a safe transition to tempdir
configuration, so creating locking directory inside libcryptsetup
call is safe.
* Many fixes for the use of cipher_null (empty debug cipher).
Support for this empty cipher was intended as a debug feature and for
measuring performance overhead. Unfortunately, many systems started to
use it as an "empty shell" for LUKS (to enable encryption later).
This use is very dangerous and it creates a false sense of security.
Anyway, to not break such systems, we try to support these
configurations.
Using cipher_null in any production system is strongly discouraged!
Fixes include:
- allow LUKS resume for a device with cipher_null.
- do not upload key in keyring when data cipher is null.
- switch to default cipher when reencrypting cipher_null device.
- replace possible bogus cipher_null keyslots before reencryption.
- fix broken detection of null cipher in LUKS2.
cipher_null is no longer possible to be used in keyslot encryption
in LUKS2, it can be used only for data for debugging purposes.
* Fixes for libpasswdqc 2.0.x (optional passphrase quality check).
* Fixes for problems discovered by various tools for code analysis.
Fixes include a rework of libpopt command line option string leaks.
* Various fixes to man pages.

View File

@@ -1,56 +0,0 @@
Cryptsetup 2.3.6 Release Notes
==============================
Stable bug-fix release with minor extensions.
All users of cryptsetup 2.x and later should upgrade to this version.
Changes since version 2.3.5
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* integritysetup: Fix possible dm-integrity mapping table truncation.
While integritysetup in standalone mode (no encryption) was not
designed to provide keyed (and cryptographically strong) data
integrity protection, some options can use such algorithms (HMAC).
If a key is used, it is directly sent to the kernel dm-integrity as
a mapping table option (no key derivation is performed).
For HMAC, such a key could be quite long (up to 4096 bytes in
integritysetup CLI).
Unfortunately, due to fixed buffers and not correctly checking string
truncation, some parameter combinations could cause truncation
of the dm-integrity mapping table.
In most cases, the table was rejected by the kernel.
The worst possible case was key truncation for HMAC options
(internal_hash and journal_mac dm-integrity table options).
This release fixes possible truncation and also adds more sanity
checks to reject truncated options.
Also, integritysetup now mentions maximal allowed key size
in --help output.
For old standalone dm-integrity devices where the key length was
truncated, you have to modify (shorten) --integrity-key-size
resp. --journal-integrity-key-size option now.
This bug is _not_ present for dm-crypt/LUKS, LUKS2 (including
integrity protection), or dm-verity devices; it affects only
standalone dm-integrity with HMAC integrity protection.
* cryptsetup: Backup header can be used to activate TCRYPT device.
Use --header option to specify the header.
* cryptsetup: Avoid LUKS2 decryption without detached header.
This feature will be added later and is currently not supported.
* Additional fixes and workarounds for common warnings produced
by some static analysis tools (like gcc-11 analyzer) and additional
code hardening.
* Fix standalone libintl detection for compiled tests.
* Add Blake2b and Blake2s hash support for crypto backends.
Kernel and gcrypt crypto backend support all variants.
OpenSSL supports only Blake2b-512 and Blake2s-256.
Crypto backend supports kernel notation e.g. "blake2b-512".

View File

@@ -1,95 +0,0 @@
Cryptsetup 2.3.7 Release Notes
==============================
Stable security bug-fix release that fixes CVE-2021-4122.
All users of cryptsetup 2.3.x must upgrade to this version.
Changes since version 2.3.6
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix possible attacks against data confidentiality through LUKS2 online
reencryption extension crash recovery (CVE-2021-4122).
An attacker can modify on-disk metadata to simulate decryption in
progress with crashed (unfinished) reencryption step and persistently
decrypt part of the LUKS device.
This attack requires repeated physical access to the LUKS device but
no knowledge of user passphrases.
The decryption step is performed after a valid user activates
the device with a correct passphrase and modified metadata.
There are no visible warnings for the user that such recovery happened
(except using the luksDump command). The attack can also be reversed
afterward (simulating crashed encryption from a plaintext) with
possible modification of revealed plaintext.
The size of possible decrypted data depends on configured LUKS2 header
size (metadata size is configurable for LUKS2).
With the default parameters (16 MiB LUKS2 header) and only one
allocated keyslot (512 bit key for AES-XTS), simulated decryption with
checksum resilience SHA1 (20 bytes checksum for 4096-byte blocks),
the maximal decrypted size can be over 3GiB.
The attack is not applicable to LUKS1 format, but the attacker can
update metadata in place to LUKS2 format as an additional step.
For such a converted LUKS2 header, the keyslot area is limited to
decrypted size (with SHA1 checksums) over 300 MiB.
The issue is present in all cryptsetup releases since 2.2.0.
Versions 1.x, 2.0.x, and 2.1.x are not affected, as these do not
contain LUKS2 reencryption extension.
The problem was caused by reusing a mechanism designed for actual
reencryption operation without reassessing the security impact for new
encryption and decryption operations. While the reencryption requires
calculating and verifying both key digests, no digest was needed to
initiate decryption recovery if the destination is plaintext (no
encryption key). Also, some metadata (like encryption cipher) is not
protected, and an attacker could change it. Note that LUKS2 protects
visible metadata only when a random change occurs. It does not protect
against intentional modification but such modification must not cause
a violation of data confidentiality.
The fix introduces additional digest protection of reencryption
metadata. The digest is calculated from known keys and critical
reencryption metadata. Now an attacker cannot create correct metadata
digest without knowledge of a passphrase for used keyslots.
For more details, see LUKS2 On-Disk Format Specification version 1.1.0.
The former reencryption operation (without the additional digest) is no
longer supported (reencryption with the digest is not backward
compatible). You need to finish in-progress reencryption before
updating to new packages. The alternative approach is to perform
a repair command from the updated package to recalculate reencryption
digest and fix metadata.
The reencryption repair operation always require a user passphrase.
WARNING: Devices with older reencryption in progress can be no longer
activated without performing the action mentioned above.
Encryption in progress can be detected by running the luksDump command
(output includes reencrypt keyslot with reencryption parameters). Also,
during the active reencryption, no keyslot operations are available
(change of passphrases, etc.).
The issue was found by Milan Broz as cryptsetup maintainer.
Other changes
~~~~~~~~~~~~~
* Add configure option --disable-luks2-reencryption to completely disable
LUKS2 reencryption code.
When used, the libcryptsetup library can read metadata with
reencryption code, but all reencryption API calls and cryptsetup
reencrypt commands are disabled.
Devices with online reencryption in progress cannot be activated.
This option can cause some incompatibilities. Please use with care.
* Improve internal metadata validation code for reencryption metadata.
* Add updated documentation for LUKS2 On-Disk Format Specification
version 1.1.0 (with reencryption extension description and updated
metadata description). See docs/on-disk-format-luks2.pdf or online
version in https://gitlab.com/cryptsetup/LUKS2-docs repository.

View File

@@ -22,8 +22,7 @@ libcryptsetup_la_CPPFLAGS = $(AM_CPPFLAGS) \
-I $(top_srcdir)/lib/loopaes \
-I $(top_srcdir)/lib/verity \
-I $(top_srcdir)/lib/tcrypt \
-I $(top_srcdir)/lib/integrity \
-I $(top_srcdir)/lib/bitlk
-I $(top_srcdir)/lib/integrity
libcryptsetup_la_DEPENDENCIES = libutils_io.la libcrypto_backend.la lib/libcryptsetup.sym
@@ -40,7 +39,6 @@ libcryptsetup_la_LIBADD = \
@LIBARGON2_LIBS@ \
@JSON_C_LIBS@ \
@BLKID_LIBS@ \
$(LTLIBICONV) \
libcrypto_backend.la \
libutils_io.la
@@ -66,9 +64,6 @@ libcryptsetup_la_SOURCES = \
lib/utils_device_locking.c \
lib/utils_device_locking.h \
lib/utils_pbkdf.c \
lib/utils_safe_memory.c \
lib/utils_storage_wrappers.c \
lib/utils_storage_wrappers.h \
lib/libdevmapper.c \
lib/utils_dm.h \
lib/volumekey.c \
@@ -77,7 +72,7 @@ libcryptsetup_la_SOURCES = \
lib/base64.h \
lib/base64.c \
lib/integrity/integrity.h \
lib/integrity/integrity.c \
lib/integrity/integrity.c \
lib/loopaes/loopaes.h \
lib/loopaes/loopaes.c \
lib/tcrypt/tcrypt.h \
@@ -93,7 +88,7 @@ libcryptsetup_la_SOURCES = \
lib/verity/verity.h \
lib/verity/rs_encode_char.c \
lib/verity/rs_decode_char.c \
lib/verity/rs.h \
lib/verity/rs.h \
lib/luks2/luks2_disk_metadata.c \
lib/luks2/luks2_json_format.c \
lib/luks2/luks2_json_metadata.c \
@@ -102,15 +97,9 @@ libcryptsetup_la_SOURCES = \
lib/luks2/luks2_digest_pbkdf2.c \
lib/luks2/luks2_keyslot.c \
lib/luks2/luks2_keyslot_luks2.c \
lib/luks2/luks2_keyslot_reenc.c \
lib/luks2/luks2_reencrypt.c \
lib/luks2/luks2_reencrypt_digest.c \
lib/luks2/luks2_segment.c \
lib/luks2/luks2_token_keyring.c \
lib/luks2/luks2_token.c \
lib/luks2/luks2_internal.h \
lib/luks2/luks2.h \
lib/utils_blkid.c \
lib/utils_blkid.h \
lib/bitlk/bitlk.h \
lib/bitlk/bitlk.c
lib/utils_blkid.h

View File

@@ -1,5 +1,5 @@
/* base64.c -- Encode binary data using printable characters.
Copyright (C) 1999-2001, 2004-2006, 2009-2019 Free Software Foundation, Inc.
Copyright (C) 1999-2001, 2004-2006, 2009-2018 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -70,7 +70,7 @@ base64_encode_fast (const char *restrict in, size_t inlen, char *restrict out)
{
while (inlen)
{
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
*out++ = b64c[to_uchar (in[0]) >> 2];
*out++ = b64c[((to_uchar (in[0]) << 4) + (to_uchar (in[1]) >> 4)) & 0x3f];
*out++ = b64c[((to_uchar (in[1]) << 2) + (to_uchar (in[2]) >> 6)) & 0x3f];
*out++ = b64c[to_uchar (in[2]) & 0x3f];
@@ -103,7 +103,7 @@ base64_encode (const char *restrict in, size_t inlen,
while (inlen && outlen)
{
*out++ = b64c[(to_uchar (in[0]) >> 2) & 0x3f];
*out++ = b64c[to_uchar (in[0]) >> 2];
if (!--outlen)
break;
*out++ = b64c[((to_uchar (in[0]) << 4)

View File

@@ -1,5 +1,5 @@
/* base64.h -- Encode binary data using printable characters.
Copyright (C) 2004-2006, 2009-2019 Free Software Foundation, Inc.
Copyright (C) 2004-2006, 2009-2018 Free Software Foundation, Inc.
Written by Simon Josefsson.
This program is free software; you can redistribute it and/or modify

File diff suppressed because it is too large Load Diff

View File

@@ -1,131 +0,0 @@
/*
* BITLK (BitLocker-compatible) header definition
*
* Copyright (C) 2019-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2021 Milan Broz
* Copyright (C) 2019-2021 Vojtech Trefny
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _CRYPTSETUP_BITLK_H
#define _CRYPTSETUP_BITLK_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
struct crypt_device;
struct device;
#define BITLK_NONCE_SIZE 12
#define BITLK_SALT_SIZE 16
#define BITLK_VMK_MAC_TAG_SIZE 16
#define BITLK_STATE_NORMAL 0x0004
typedef enum {
BITLK_ENCRYPTION_TYPE_NORMAL = 0,
BITLK_ENCRYPTION_TYPE_EOW,
BITLK_ENCRYPTION_TYPE_UNKNOWN,
} BITLKEncryptionType;
typedef enum {
BITLK_PROTECTION_CLEAR_KEY = 0,
BITLK_PROTECTION_TPM,
BITLK_PROTECTION_STARTUP_KEY,
BITLK_PROTECTION_TPM_PIN,
BITLK_PROTECTION_RECOVERY_PASSPHRASE,
BITLK_PROTECTION_PASSPHRASE,
BITLK_PROTECTION_SMART_CARD,
BITLK_PROTECTION_UNKNOWN,
} BITLKVMKProtection;
typedef enum {
BITLK_ENTRY_TYPE_PROPERTY = 0x0000,
BITLK_ENTRY_TYPE_VMK = 0x0002,
BITLK_ENTRY_TYPE_FVEK = 0x0003,
BITLK_ENTRY_TYPE_STARTUP_KEY = 0x0006,
BITLK_ENTRY_TYPE_DESCRIPTION = 0x0007,
BITLK_ENTRY_TYPE_VOLUME_HEADER = 0x000f,
} BITLKFVEEntryType;
typedef enum {
BITLK_ENTRY_VALUE_ERASED = 0x0000,
BITLK_ENTRY_VALUE_KEY = 0x0001,
BITLK_ENTRY_VALUE_STRING = 0x0002,
BITLK_ENTRY_VALUE_STRETCH_KEY = 0x0003,
BITLK_ENTRY_VALUE_USE_KEY = 0x0004,
BITLK_ENTRY_VALUE_ENCRYPTED_KEY = 0x0005,
BITLK_ENTRY_VALUE_TPM_KEY = 0x0006,
BITLK_ENTRY_VALUE_VALIDATION = 0x0007,
BITLK_ENTRY_VALUE_VMK = 0x0008,
BITLK_ENTRY_VALUE_EXTERNAL_KEY = 0x0009,
BITLK_ENTRY_VALUE_OFFSET_SIZE = 0x000f,
BITLK_ENTRY_VALUE_RECOVERY_TIME = 0x015,
} BITLKFVEEntryValue;
struct bitlk_vmk {
char *guid;
char *name;
BITLKVMKProtection protection;
uint8_t salt[BITLK_SALT_SIZE];
uint8_t mac_tag[BITLK_VMK_MAC_TAG_SIZE];
uint8_t nonce[BITLK_NONCE_SIZE];
struct volume_key *vk;
struct bitlk_vmk *next;
};
struct bitlk_fvek {
uint8_t mac_tag[BITLK_VMK_MAC_TAG_SIZE];
uint8_t nonce[BITLK_NONCE_SIZE];
struct volume_key *vk;
};
struct bitlk_metadata {
uint16_t sector_size;
bool togo;
bool state;
BITLKEncryptionType type;
const char *cipher;
const char *cipher_mode;
uint16_t key_size;
char *guid;
uint64_t creation_time;
char *description;
uint64_t metadata_offset[3];
uint32_t metadata_version;
uint64_t volume_header_offset;
uint64_t volume_header_size;
struct bitlk_vmk *vmks;
struct bitlk_fvek *fvek;
};
int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params);
int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_metadata *params);
int BITLK_activate(struct crypt_device *cd,
const char *name,
const char *password,
size_t passwordLen,
const struct bitlk_metadata *params,
uint32_t flags);
void BITLK_bitlk_fvek_free(struct bitlk_fvek *fvek);
void BITLK_bitlk_vmk_free(struct bitlk_vmk *vmk);
void BITLK_bitlk_metadata_free(struct bitlk_metadata *params);
#endif

View File

@@ -1,9 +1,9 @@
/*
* cryptsetup plain device helper functions
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2018, Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -64,7 +64,7 @@ static int hash(const char *hash_name, size_t key_size, char *key,
#define PLAIN_HASH_LEN_MAX 256
int crypt_plain_hash(struct crypt_device *cd,
int crypt_plain_hash(struct crypt_device *ctx __attribute__((unused)),
const char *hash_name,
char *key, size_t key_size,
const char *passphrase, size_t passphrase_size)
@@ -73,7 +73,7 @@ int crypt_plain_hash(struct crypt_device *cd,
size_t hash_size, pad_size;
int r;
log_dbg(cd, "Plain: hashing passphrase using %s.", hash_name);
log_dbg("Plain: hashing passphrase using %s.", hash_name);
if (strlen(hash_name) >= PLAIN_HASH_LEN_MAX)
return -EINVAL;
@@ -85,11 +85,11 @@ int crypt_plain_hash(struct crypt_device *cd,
*s = '\0';
s++;
if (!*s || sscanf(s, "%zd", &hash_size) != 1) {
log_dbg(cd, "Hash length is not a number");
log_dbg("Hash length is not a number");
return -EINVAL;
}
if (hash_size > key_size) {
log_dbg(cd, "Hash length %zd > key length %zd",
log_dbg("Hash length %zd > key length %zd",
hash_size, key_size);
return -EINVAL;
}
@@ -102,7 +102,7 @@ int crypt_plain_hash(struct crypt_device *cd,
/* No hash, copy passphrase directly */
if (!strcmp(hash_name_buf, "plain")) {
if (passphrase_size < hash_size) {
log_dbg(cd, "Too short plain passphrase.");
log_dbg("Too short plain passphrase.");
return -EINVAL;
}
memcpy(key, passphrase, hash_size);

View File

@@ -4,14 +4,12 @@ libcrypto_backend_la_CFLAGS = $(AM_CFLAGS) @CRYPTO_CFLAGS@
libcrypto_backend_la_SOURCES = \
lib/crypto_backend/crypto_backend.h \
lib/crypto_backend/crypto_backend_internal.h \
lib/crypto_backend/crypto_cipher_kernel.c \
lib/crypto_backend/crypto_storage.c \
lib/crypto_backend/pbkdf_check.c \
lib/crypto_backend/crc32.c \
lib/crypto_backend/argon2_generic.c \
lib/crypto_backend/cipher_generic.c \
lib/crypto_backend/cipher_check.c
lib/crypto_backend/cipher_generic.c
if CRYPTO_BACKEND_GCRYPT
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_gcrypt.c

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
@@ -274,7 +274,6 @@ int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen,
}
/* No field can be longer than the encoded length */
/* coverity[strlen_assign] */
max_field_len = (uint32_t)encoded_len;
ctx.saltlen = max_field_len;
@@ -450,8 +449,6 @@ const char *argon2_error_message(int error_code) {
size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism,
uint32_t saltlen, uint32_t hashlen, argon2_type type) {
if (!argon2_type2string(type, 0))
return 0;
return strlen("$$v=$m=,t=,p=$$") + strlen(argon2_type2string(type, 0)) +
numlen(t_cost) + numlen(m_cost) + numlen(parallelism) +
b64len(saltlen) + b64len(hashlen) + numlen(ARGON2_VERSION_NUMBER) + 1;

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.
@@ -125,7 +125,7 @@ void NOT_OPTIMIZED secure_wipe_memory(void *v, size_t n) {
SecureZeroMemory(v, n);
#elif defined memset_s
memset_s(v, n, 0, n);
#elif defined(HAVE_EXPLICIT_BZERO)
#elif defined(__OpenBSD__)
explicit_bzero(v, n);
#else
static void *(*const volatile memset_sec)(void *, int, size_t) = &memset;
@@ -299,7 +299,7 @@ static int fill_memory_blocks_mt(argon2_instance_t *instance) {
for (r = 0; r < instance->passes; ++r) {
for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
uint32_t l, ll;
uint32_t l;
/* 2. Calling threads */
for (l = 0; l < instance->lanes; ++l) {
@@ -324,9 +324,6 @@ static int fill_memory_blocks_mt(argon2_instance_t *instance) {
sizeof(argon2_position_t));
if (argon2_thread_create(&thread[l], &fill_segment_thr,
(void *)&thr_data[l])) {
/* Wait for already running threads */
for (ll = 0; ll < l; ++ll)
argon2_thread_join(thread[ll]);
rc = ARGON2_THREAD_FAIL;
goto fail;
}

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -8,8 +8,8 @@
* License/Waiver or the Apache Public License 2.0, at your option. The terms of
* these licenses can be found at:
*
* - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
* - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
* - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
*
* You should have received a copy of both of these licenses along with this
* software. If not, they may be obtained at the above URLs.

View File

@@ -1,8 +1,8 @@
/*
* Argon2 PBKDF2 library wrapper
*
* Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021 Milan Broz
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,7 +20,7 @@
*/
#include <errno.h>
#include "crypto_backend_internal.h"
#include "crypto_backend.h"
#if HAVE_ARGON2_H
#include <argon2.h>
#else
@@ -77,3 +77,117 @@ int argon2(const char *type, const char *password, size_t password_length,
return r;
#endif
}
#if 0
#include <stdio.h>
struct test_vector {
argon2_type type;
unsigned int memory;
unsigned int iterations;
unsigned int parallelism;
const char *password;
unsigned int password_length;
const char *salt;
unsigned int salt_length;
const char *key;
unsigned int key_length;
const char *ad;
unsigned int ad_length;
const char *output;
unsigned int output_length;
};
struct test_vector test_vectors[] = {
/* Argon2 RFC */
{
Argon2_i, 32, 3, 4,
"\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\x01\x01", 32,
"\x02\x02\x02\x02\x02\x02\x02\x02"
"\x02\x02\x02\x02\x02\x02\x02\x02", 16,
"\x03\x03\x03\x03\x03\x03\x03\x03", 8,
"\x04\x04\x04\x04\x04\x04\x04\x04"
"\x04\x04\x04\x04", 12,
"\xc8\x14\xd9\xd1\xdc\x7f\x37\xaa"
"\x13\xf0\xd7\x7f\x24\x94\xbd\xa1"
"\xc8\xde\x6b\x01\x6d\xd3\x88\xd2"
"\x99\x52\xa4\xc4\x67\x2b\x6c\xe8", 32
},
{
Argon2_id, 32, 3, 4,
"\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\x01\x01", 32,
"\x02\x02\x02\x02\x02\x02\x02\x02"
"\x02\x02\x02\x02\x02\x02\x02\x02", 16,
"\x03\x03\x03\x03\x03\x03\x03\x03", 8,
"\x04\x04\x04\x04\x04\x04\x04\x04"
"\x04\x04\x04\x04", 12,
"\x0d\x64\x0d\xf5\x8d\x78\x76\x6c"
"\x08\xc0\x37\xa3\x4a\x8b\x53\xc9"
"\xd0\x1e\xf0\x45\x2d\x75\xb6\x5e"
"\xb5\x25\x20\xe9\x6b\x01\xe6\x59", 32
}
};
static void printhex(const char *s, const char *buf, size_t len)
{
size_t i;
printf("%s: ", s);
for (i = 0; i < len; i++)
printf("\\x%02x", (unsigned char)buf[i]);
printf("\n");
fflush(stdout);
}
static int argon2_test_vectors(void)
{
char result[64];
int i, r;
struct test_vector *vec;
argon2_context context;
printf("Argon2 running test vectors\n");
for (i = 0; i < (sizeof(test_vectors) / sizeof(*test_vectors)); i++) {
vec = &test_vectors[i];
memset(result, 0, sizeof(result));
memset(&context, 0, sizeof(context));
context.flags = ARGON2_DEFAULT_FLAGS;
context.version = ARGON2_VERSION_NUMBER;
context.out = (uint8_t *)result;
context.outlen = (uint32_t)vec->output_length;
context.pwd = (uint8_t *)vec->password;
context.pwdlen = (uint32_t)vec->password_length;
context.salt = (uint8_t *)vec->salt;
context.saltlen = (uint32_t)vec->salt_length;
context.secret = (uint8_t *)vec->key;
context.secretlen = (uint32_t)vec->key_length;;
context.ad = (uint8_t *)vec->ad;
context.adlen = (uint32_t)vec->ad_length;
context.t_cost = vec->iterations;
context.m_cost = vec->memory;
context.lanes = vec->parallelism;
context.threads = vec->parallelism;
r = argon2_ctx(&context, vec->type);
if (r != ARGON2_OK) {
printf("Argon2 failed %i, vector %d\n", r, i);
return -EINVAL;
}
if (memcmp(result, vec->output, vec->output_length) != 0) {
printf("vector %u\n", i);
printhex(" got", result, vec->output_length);
printhex("want", vec->output, vec->output_length);
return -EINVAL;
}
}
return 0;
}
#endif

View File

@@ -1,161 +0,0 @@
/*
* Cipher performance check
*
* Copyright (C) 2018-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
#include <time.h>
#include "crypto_backend_internal.h"
#ifndef CLOCK_MONOTONIC_RAW
#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
#endif
/*
* This is not simulating storage, so using disk block causes extreme overhead.
* Let's use some fixed block size where results are more reliable...
*/
#define CIPHER_BLOCK_BYTES 65536
/*
* If the measured value is lower, encrypted buffer is probably too small
* and calculated values are not reliable.
*/
#define CIPHER_TIME_MIN_MS 0.001
/*
* The whole test depends on Linux kernel usermode crypto API for now.
* (The same implementations are used in dm-crypt though.)
*/
static int time_ms(struct timespec *start, struct timespec *end, double *ms)
{
double start_ms, end_ms;
start_ms = start->tv_sec * 1000.0 + start->tv_nsec / (1000.0 * 1000);
end_ms = end->tv_sec * 1000.0 + end->tv_nsec / (1000.0 * 1000);
*ms = end_ms - start_ms;
return 0;
}
static int cipher_perf_one(const char *name, const char *mode, char *buffer, size_t buffer_size,
const char *key, size_t key_size, const char *iv, size_t iv_size, int enc)
{
struct crypt_cipher_kernel cipher;
size_t done = 0, block = CIPHER_BLOCK_BYTES;
int r;
if (buffer_size < block)
block = buffer_size;
r = crypt_cipher_init_kernel(&cipher, name, mode, key, key_size);
if (r < 0)
return r;
while (done < buffer_size) {
if ((done + block) > buffer_size)
block = buffer_size - done;
if (enc)
r = crypt_cipher_encrypt_kernel(&cipher, &buffer[done], &buffer[done],
block, iv, iv_size);
else
r = crypt_cipher_decrypt_kernel(&cipher, &buffer[done], &buffer[done],
block, iv, iv_size);
if (r < 0)
break;
done += block;
}
crypt_cipher_destroy_kernel(&cipher);
return r;
}
static int cipher_measure(const char *name, const char *mode, char *buffer, size_t buffer_size,
const char *key, size_t key_size, const char *iv, size_t iv_size,
int encrypt, double *ms)
{
struct timespec start, end;
int r;
/*
* Using getrusage would be better here but the precision
* is not adequate, so better stick with CLOCK_MONOTONIC
*/
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start) < 0)
return -EINVAL;
r = cipher_perf_one(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, encrypt);
if (r < 0)
return r;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &end) < 0)
return -EINVAL;
r = time_ms(&start, &end, ms);
if (r < 0)
return r;
if (*ms < CIPHER_TIME_MIN_MS)
return -ERANGE;
return 0;
}
static double speed_mbs(unsigned long bytes, double ms)
{
double speed = bytes, s = ms / 1000.;
return speed / (1024 * 1024) / s;
}
int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, size_t buffer_size,
const char *key, size_t key_size, const char *iv, size_t iv_size,
double *encryption_mbs, double *decryption_mbs)
{
double ms_enc, ms_dec, ms;
int r, repeat_enc, repeat_dec;
ms_enc = 0.0;
repeat_enc = 1;
while (ms_enc < 1000.0) {
r = cipher_measure(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, 1, &ms);
if (r < 0)
return r;
ms_enc += ms;
repeat_enc++;
}
ms_dec = 0.0;
repeat_dec = 1;
while (ms_dec < 1000.0) {
r = cipher_measure(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, 0, &ms);
if (r < 0)
return r;
ms_dec += ms;
repeat_dec++;
}
*encryption_mbs = speed_mbs(buffer_size * repeat_enc, ms_enc);
*decryption_mbs = speed_mbs(buffer_size * repeat_dec, ms_dec);
return 0;
}

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel cipher generic utilities
*
* Copyright (C) 2018-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2021 Milan Broz
* Copyright (C) 2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -51,7 +51,6 @@ static const struct cipher_alg cipher_algs[] = {
{ "paes", NULL, 16, true }, /* protected AES, s390 wrapped key scheme */
{ "xchacha12,aes", "adiantum", 32, false },
{ "xchacha20,aes", "adiantum", 32, false },
{ "sm4", NULL, 16, false },
{ NULL, NULL, 0, false }
};
@@ -73,13 +72,7 @@ int crypt_cipher_ivsize(const char *name, const char *mode)
{
const struct cipher_alg *ca = _get_alg(name, mode);
if (!ca)
return -EINVAL;
if (mode && !strcasecmp(mode, "ecb"))
return 0;
return ca->blocksize;
return ca ? ca->blocksize : -EINVAL;
}
int crypt_cipher_wrapped_key(const char *name, const char *mode)

View File

@@ -19,7 +19,7 @@
* order from highest-order term to lowest-order term. UARTs transmit
* characters in order from LSB to MSB. By storing the CRC this way,
* we hand it to the UART in the order low-byte to high-byte; the UART
* sends each low-bit to high-bit; and the result is transmission bit
* sends each low-bit to hight-bit; and the result is transmission bit
* by bit from highest- to lowest-order term without requiring any bit
* shuffling on our part. Reception works similarly.
*
@@ -42,6 +42,7 @@
#include "crypto_backend.h"
static const uint32_t crc32_tab[] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
@@ -112,3 +113,4 @@ uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len)
return crc;
}

View File

@@ -1,8 +1,8 @@
/*
* crypto backend implementation
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,16 +22,16 @@
#define _CRYPTO_BACKEND_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
struct crypt_device;
struct crypt_hash;
struct crypt_hmac;
struct crypt_cipher;
struct crypt_storage;
int crypt_backend_init(void);
int crypt_backend_init(struct crypt_device *ctx);
void crypt_backend_destroy(void);
#define CRYPT_BACKEND_KERNEL (1 << 0) /* Crypto uses kernel part, for benchmark */
@@ -58,15 +58,14 @@ void crypt_hmac_destroy(struct crypt_hmac *ctx);
enum { CRYPT_RND_NORMAL = 0, CRYPT_RND_KEY = 1, CRYPT_RND_SALT = 2 };
int crypt_backend_rng(char *buffer, size_t length, int quality, int fips);
/* PBKDF*/
struct crypt_pbkdf_limits {
uint32_t min_iterations, max_iterations;
uint32_t min_memory, max_memory;
uint32_t min_parallel, max_parallel;
};
int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *l);
/* PBKDF*/
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
@@ -80,10 +79,26 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
uint32_t *iterations_out, uint32_t *memory_out,
int (*progress)(uint32_t time_ms, void *usrptr), void *usrptr);
#if USE_INTERNAL_PBKDF2
/* internal PBKDF2 implementation */
int pkcs5_pbkdf2(const char *hash,
const char *P, size_t Plen,
const char *S, size_t Slen,
unsigned int c,
unsigned int dkLen, char *DK,
unsigned int hash_block_size);
#endif
/* Argon2 implementation wrapper */
int argon2(const char *type, const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
uint32_t iterations, uint32_t memory, uint32_t parallel);
/* CRC32 */
uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len);
/* Block ciphers */
/* ciphers */
int crypt_cipher_ivsize(const char *name, const char *mode);
int crypt_cipher_wrapped_key(const char *name, const char *mode);
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
@@ -95,34 +110,20 @@ int crypt_cipher_encrypt(struct crypt_cipher *ctx,
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length);
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx);
/* Benchmark of kernel cipher performance */
int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, size_t buffer_size,
const char *key, size_t key_size, const char *iv, size_t iv_size,
double *encryption_mbs, double *decryption_mbs);
/* Check availability of a cipher */
int crypt_cipher_check(const char *name, const char *mode,
const char *integrity, size_t key_length);
/* Check availability of a cipher (in kernel only) */
int crypt_cipher_check_kernel(const char *name, const char *mode,
const char *integrity, size_t key_length);
/* Storage encryption wrappers */
int crypt_storage_init(struct crypt_storage **ctx, size_t sector_size,
/* storage encryption wrappers */
int crypt_storage_init(struct crypt_storage **ctx, uint64_t sector_start,
const char *cipher, const char *cipher_mode,
const void *key, size_t key_length, bool large_iv);
const void *key, size_t key_length);
void crypt_storage_destroy(struct crypt_storage *ctx);
int crypt_storage_decrypt(struct crypt_storage *ctx, uint64_t iv_offset,
uint64_t length, char *buffer);
int crypt_storage_encrypt(struct crypt_storage *ctx, uint64_t iv_offset,
uint64_t length, char *buffer);
bool crypt_storage_kernel_only(struct crypt_storage *ctx);
/* Temporary Bitlk helper */
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length);
int crypt_storage_decrypt(struct crypt_storage *ctx, uint64_t sector,
size_t count, char *buffer);
int crypt_storage_encrypt(struct crypt_storage *ctx, uint64_t sector,
size_t count, char *buffer);
/* Memzero helper (memset on stack can be optimized out) */
static inline void crypt_backend_memzero(void *s, size_t n)

View File

@@ -1,63 +0,0 @@
/*
* crypto backend implementation
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _CRYPTO_BACKEND_INTERNAL_H
#define _CRYPTO_BACKEND_INTERNAL_H
#include "crypto_backend.h"
#if USE_INTERNAL_PBKDF2
/* internal PBKDF2 implementation */
int pkcs5_pbkdf2(const char *hash,
const char *P, size_t Plen,
const char *S, size_t Slen,
unsigned int c,
unsigned int dkLen, char *DK,
unsigned int hash_block_size);
#endif
/* Argon2 implementation wrapper */
int argon2(const char *type, const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
uint32_t iterations, uint32_t memory, uint32_t parallel);
/* Block ciphers: fallback to kernel crypto API */
struct crypt_cipher_kernel {
int tfmfd;
int opfd;
};
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
const char *mode, const void *key, size_t key_length);
int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length);
int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length);
void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx);
int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length);
#endif /* _CRYPTO_BACKEND_INTERNAL_H */

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel userspace API crypto backend implementation (skcipher)
*
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -27,7 +27,7 @@
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include "crypto_backend_internal.h"
#include "crypto_backend.h"
#ifdef ENABLE_AF_ALG
@@ -40,9 +40,10 @@
#define SOL_ALG 279
#endif
#ifndef ALG_SET_AEAD_AUTHSIZE
#define ALG_SET_AEAD_AUTHSIZE 5
#endif
struct crypt_cipher {
int tfmfd;
int opfd;
};
/*
* ciphers
@@ -51,69 +52,64 @@
* ENOTSUP - AF_ALG family not available
* (but cannot check specifically for skcipher API)
*/
static int _crypt_cipher_init(struct crypt_cipher_kernel *ctx,
static int _crypt_cipher_init(struct crypt_cipher **ctx,
const void *key, size_t key_length,
size_t tag_length, struct sockaddr_alg *sa)
struct sockaddr_alg *sa)
{
if (!ctx)
return -EINVAL;
struct crypt_cipher *h;
ctx->opfd = -1;
ctx->tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
if (ctx->tfmfd < 0) {
crypt_cipher_destroy_kernel(ctx);
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
h->opfd = -1;
h->tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
if (h->tfmfd < 0) {
crypt_cipher_destroy(h);
return -ENOTSUP;
}
if (bind(ctx->tfmfd, (struct sockaddr *)sa, sizeof(*sa)) < 0) {
crypt_cipher_destroy_kernel(ctx);
if (bind(h->tfmfd, (struct sockaddr *)sa, sizeof(*sa)) < 0) {
crypt_cipher_destroy(h);
return -ENOENT;
}
if (setsockopt(ctx->tfmfd, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) {
crypt_cipher_destroy_kernel(ctx);
if (setsockopt(h->tfmfd, SOL_ALG, ALG_SET_KEY, key, key_length) < 0) {
crypt_cipher_destroy(h);
return -EINVAL;
}
if (tag_length && setsockopt(ctx->tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, tag_length) < 0) {
crypt_cipher_destroy_kernel(ctx);
return -EINVAL;
}
ctx->opfd = accept(ctx->tfmfd, NULL, 0);
if (ctx->opfd < 0) {
crypt_cipher_destroy_kernel(ctx);
h->opfd = accept(h->tfmfd, NULL, 0);
if (h->opfd < 0) {
crypt_cipher_destroy(h);
return -EINVAL;
}
*ctx = h;
return 0;
}
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
const char *mode, const void *key, size_t key_length)
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
.salg_type = "skcipher",
};
int r;
if (!strcmp(name, "cipher_null"))
key_length = 0;
r = snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(%s)", mode, name);
if (r < 0 || (size_t)r >= sizeof(sa.salg_name))
return -EINVAL;
snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(%s)", mode, name);
return _crypt_cipher_init(ctx, key, key_length, 0, &sa);
return _crypt_cipher_init(ctx, key, key_length, &sa);
}
/* The in/out should be aligned to page boundary */
static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
const char *in, size_t in_length,
char *out, size_t out_length,
const char *iv, size_t iv_length,
uint32_t direction)
static int crypt_cipher_crypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
uint32_t direction)
{
int r = 0;
ssize_t len;
@@ -122,7 +118,7 @@ static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
uint32_t *type;
struct iovec iov = {
.iov_base = (void*)(uintptr_t)in,
.iov_len = in_length,
.iov_len = length,
};
int iv_msg_size = iv ? CMSG_SPACE(sizeof(*alg_iv) + iv_length) : 0;
char buffer[CMSG_SPACE(sizeof(*type)) + iv_msg_size];
@@ -133,7 +129,7 @@ static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
.msg_iovlen = 1,
};
if (!in || !out || !in_length)
if (!in || !out || !length)
return -EINVAL;
if ((!iv && iv_length) || (iv && !iv_length))
@@ -155,9 +151,6 @@ static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
/* Set IV */
if (iv) {
header = CMSG_NXTHDR(&msg, header);
if (!header)
return -EINVAL;
header->cmsg_level = SOL_ALG;
header->cmsg_type = ALG_SET_IV;
header->cmsg_len = iv_msg_size;
@@ -167,50 +160,49 @@ static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
}
len = sendmsg(ctx->opfd, &msg, 0);
if (len != (ssize_t)(in_length)) {
if (len != (ssize_t)length) {
r = -EIO;
goto bad;
}
len = read(ctx->opfd, out, out_length);
if (len != (ssize_t)out_length)
len = read(ctx->opfd, out, length);
if (len != (ssize_t)length)
r = -EIO;
bad:
crypt_backend_memzero(buffer, sizeof(buffer));
return r;
}
int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return _crypt_cipher_crypt(ctx, in, length, out, length,
iv, iv_length, ALG_OP_ENCRYPT);
return crypt_cipher_crypt(ctx, in, out, length,
iv, iv_length, ALG_OP_ENCRYPT);
}
int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return _crypt_cipher_crypt(ctx, in, length, out, length,
iv, iv_length, ALG_OP_DECRYPT);
return crypt_cipher_crypt(ctx, in, out, length,
iv, iv_length, ALG_OP_DECRYPT);
}
void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx)
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
if (ctx->tfmfd >= 0)
close(ctx->tfmfd);
if (ctx->opfd >= 0)
close(ctx->opfd);
ctx->tfmfd = -1;
ctx->opfd = -1;
memset(ctx, 0, sizeof(*ctx));
free(ctx);
}
int crypt_cipher_check_kernel(const char *name, const char *mode,
const char *integrity, size_t key_length)
int crypt_cipher_check(const char *name, const char *mode,
const char *integrity, size_t key_length)
{
struct crypt_cipher_kernel c;
struct crypt_cipher *c = NULL;
char mode_name[64], tmp_salg_name[180], *real_mode = NULL, *cipher_iv = NULL, *key;
const char *salg_type;
bool aead;
@@ -233,10 +225,7 @@ int crypt_cipher_check_kernel(const char *name, const char *mode,
}
salg_type = aead ? "aead" : "skcipher";
r = snprintf((char *)sa.salg_type, sizeof(sa.salg_type), "%s", salg_type);
if (r < 0 || (size_t)r >= sizeof(sa.salg_name))
return -EINVAL;
snprintf((char *)sa.salg_type, sizeof(sa.salg_type), "%s", salg_type);
memset(tmp_salg_name, 0, sizeof(tmp_salg_name));
/* FIXME: this is duplicating a part of devmapper backend */
@@ -249,7 +238,7 @@ int crypt_cipher_check_kernel(const char *name, const char *mode,
else
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s(%s)", real_mode, name);
if (r < 0 || (size_t)r >= sizeof(tmp_salg_name))
if (r <= 0 || r > (int)(sizeof(sa.salg_name) - 1))
return -EINVAL;
memcpy(sa.salg_name, tmp_salg_name, sizeof(sa.salg_name));
@@ -258,95 +247,47 @@ int crypt_cipher_check_kernel(const char *name, const char *mode,
if (!key)
return -ENOMEM;
/* We cannot use RNG yet, any key works here, tweak the first part if it is split key (XTS). */
memset(key, 0xab, key_length);
*key = 0xef;
r = crypt_backend_rng(key, key_length, CRYPT_RND_NORMAL, 0);
if (r < 0) {
free (key);
return r;
}
r = _crypt_cipher_init(&c, key, key_length, 0, &sa);
crypt_cipher_destroy_kernel(&c);
r = _crypt_cipher_init(&c, key, key_length, &sa);
if (c)
crypt_cipher_destroy(c);
free(key);
return r;
}
int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
struct crypt_cipher_kernel c;
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
.salg_type = "aead",
.salg_name = "ccm(aes)",
};
int r;
char buffer[128], ccm_iv[16];
if (length + tag_length > sizeof(buffer))
return -EINVAL;
if (iv_length > sizeof(ccm_iv) - 2)
return -EINVAL;
r = _crypt_cipher_init(&c, key, key_length, tag_length, &sa);
if (r < 0)
return r;
memcpy(buffer, in, length);
memcpy(buffer + length, tag, tag_length);
/* CCM IV - RFC3610 */
memset(ccm_iv, 0, sizeof(ccm_iv));
ccm_iv[0] = 15 - iv_length - 1;
memcpy(ccm_iv + 1, iv, iv_length);
memset(ccm_iv + 1 + iv_length, 0, ccm_iv[0] + 1);
iv_length = sizeof(ccm_iv);
r = _crypt_cipher_crypt(&c, buffer, length + tag_length, out, length,
ccm_iv, iv_length, ALG_OP_DECRYPT);
crypt_cipher_destroy_kernel(&c);
crypt_backend_memzero(buffer, sizeof(buffer));
return r;
}
#else /* ENABLE_AF_ALG */
int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
const char *mode, const void *key, size_t key_length)
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *buffer, size_t length)
{
return -ENOTSUP;
}
void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx)
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
return;
}
int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return -EINVAL;
}
int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return -EINVAL;
}
int crypt_cipher_check_kernel(const char *name, const char *mode,
const char *integrity, size_t key_length)
int crypt_cipher_check(const char *name, const char *mode,
const char *integrity, size_t key_length)
{
/* Cannot check, expect success. */
return 0;
}
int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
return -ENOTSUP;
}
#endif

View File

@@ -1,8 +1,8 @@
/*
* GCRYPT crypto backend implementation
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,7 +24,7 @@
#include <errno.h>
#include <assert.h>
#include <gcrypt.h>
#include "crypto_backend_internal.h"
#include "crypto_backend.h"
static int crypto_backend_initialised = 0;
static int crypto_backend_secmem = 1;
@@ -43,22 +43,9 @@ struct crypt_hmac {
int hash_len;
};
struct crypt_cipher {
bool use_kernel;
union {
struct crypt_cipher_kernel kernel;
gcry_cipher_hd_t hd;
} u;
};
struct hash_alg {
const char *name;
const char *gcrypt_name;
};
/*
* Test for wrong Whirlpool variant,
* Ref: https://lists.gnupg.org/pipermail/gcrypt-devel/2014-January/002889.html
* Ref: http://lists.gnupg.org/pipermail/gcrypt-devel/2014-January/002889.html
*/
static void crypt_hash_test_whirlpool_bug(void)
{
@@ -94,10 +81,8 @@ static void crypt_hash_test_whirlpool_bug(void)
crypto_backend_whirlpool_bug = 1;
}
int crypt_backend_init(void)
int crypt_backend_init(struct crypt_device *ctx)
{
int r;
if (crypto_backend_initialised)
return 0;
@@ -127,12 +112,11 @@ int crypt_backend_init(void)
crypto_backend_initialised = 1;
crypt_hash_test_whirlpool_bug();
r = snprintf(version, sizeof(version), "gcrypt %s%s%s",
snprintf(version, 64, "gcrypt %s%s%s",
gcry_check_version(NULL),
crypto_backend_secmem ? "" : ", secmem disabled",
crypto_backend_whirlpool_bug > 0 ? ", flawed whirlpool" : "");
if (r < 0 || (size_t)r >= sizeof(version))
return -EINVAL;
crypto_backend_whirlpool_bug > 0 ? ", flawed whirlpool" : ""
);
return 0;
}
@@ -158,24 +142,10 @@ uint32_t crypt_backend_flags(void)
static const char *crypt_hash_compat_name(const char *name, unsigned int *flags)
{
const char *hash_name = name;
int i;
static struct hash_alg hash_algs[] = {
{ "blake2b-160", "blake2b_160" },
{ "blake2b-256", "blake2b_256" },
{ "blake2b-384", "blake2b_384" },
{ "blake2b-512", "blake2b_512" },
{ "blake2s-128", "blake2s_128" },
{ "blake2s-160", "blake2s_160" },
{ "blake2s-224", "blake2s_224" },
{ "blake2s-256", "blake2s_256" },
{ NULL, NULL, }};
if (!name)
return NULL;
/* "whirlpool_gcryptbug" is out shortcut to flawed whirlpool
* in libgcrypt < 1.6.0 */
if (!strcasecmp(name, "whirlpool_gcryptbug")) {
if (name && !strcasecmp(name, "whirlpool_gcryptbug")) {
#if GCRYPT_VERSION_NUMBER >= 0x010601
if (flags)
*flags |= GCRY_MD_FLAG_BUGEMU1;
@@ -183,15 +153,6 @@ static const char *crypt_hash_compat_name(const char *name, unsigned int *flags)
hash_name = "whirlpool";
}
i = 0;
while (hash_algs[i].name) {
if (!strcasecmp(name, hash_algs[i].name)) {
hash_name = hash_algs[i].gcrypt_name;
break;
}
i++;
}
return hash_name;
}
@@ -405,148 +366,3 @@ int crypt_pbkdf(const char *kdf, const char *hash,
key, key_length, iterations, memory, parallel);
return -EINVAL;
}
/* Block ciphers */
static int _cipher_init(gcry_cipher_hd_t *hd, const char *name,
const char *mode, const void *buffer, size_t length)
{
int cipher_id, mode_id;
cipher_id = gcry_cipher_map_name(name);
if (cipher_id == GCRY_CIPHER_MODE_NONE)
return -ENOENT;
if (!strcmp(mode, "ecb"))
mode_id = GCRY_CIPHER_MODE_ECB;
else if (!strcmp(mode, "cbc"))
mode_id = GCRY_CIPHER_MODE_CBC;
#if HAVE_DECL_GCRY_CIPHER_MODE_XTS
else if (!strcmp(mode, "xts"))
mode_id = GCRY_CIPHER_MODE_XTS;
#endif
else
return -ENOENT;
if (gcry_cipher_open(hd, cipher_id, mode_id, 0))
return -EINVAL;
if (gcry_cipher_setkey(*hd, buffer, length)) {
gcry_cipher_close(*hd);
return -EINVAL;
}
return 0;
}
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
struct crypt_cipher *h;
int r;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
if (!_cipher_init(&h->u.hd, name, mode, key, key_length)) {
h->use_kernel = false;
*ctx = h;
return 0;
}
r = crypt_cipher_init_kernel(&h->u.kernel, name, mode, key, key_length);
if (r < 0) {
free(h);
return r;
}
h->use_kernel = true;
*ctx = h;
return 0;
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
if (ctx->use_kernel)
crypt_cipher_destroy_kernel(&ctx->u.kernel);
else
gcry_cipher_close(ctx->u.hd);
free(ctx);
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
if (ctx->use_kernel)
return crypt_cipher_encrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
if (iv && gcry_cipher_setiv(ctx->u.hd, iv, iv_length))
return -EINVAL;
if (gcry_cipher_encrypt(ctx->u.hd, out, length, in, length))
return -EINVAL;
return 0;
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
if (ctx->use_kernel)
return crypt_cipher_decrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
if (iv && gcry_cipher_setiv(ctx->u.hd, iv, iv_length))
return -EINVAL;
if (gcry_cipher_decrypt(ctx->u.hd, out, length, in, length))
return -EINVAL;
return 0;
}
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
{
return ctx->use_kernel;
}
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
#ifdef GCRY_CCM_BLOCK_LEN
gcry_cipher_hd_t hd;
uint64_t l[3];
int r = -EINVAL;
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CCM, 0))
return -EINVAL;
if (gcry_cipher_setkey(hd, key, key_length))
goto out;
if (gcry_cipher_setiv(hd, iv, iv_length))
goto out;
l[0] = length;
l[1] = 0;
l[2] = tag_length;
if (gcry_cipher_ctl(hd, GCRYCTL_SET_CCM_LENGTHS, l, sizeof(l)))
goto out;
if (gcry_cipher_decrypt(hd, out, length, in, length))
goto out;
if (gcry_cipher_checktag(hd, tag, tag_length))
goto out;
r = 0;
out:
gcry_cipher_close(hd);
return r;
#else
return -ENOTSUP;
#endif
}

View File

@@ -1,8 +1,8 @@
/*
* Linux kernel userspace API crypto backend implementation
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -27,7 +27,7 @@
#include <sys/socket.h>
#include <sys/utsname.h>
#include <linux/if_alg.h>
#include "crypto_backend_internal.h"
#include "crypto_backend.h"
/* FIXME: remove later */
#ifndef AF_ALG
@@ -48,29 +48,12 @@ struct hash_alg {
};
static struct hash_alg hash_algs[] = {
{ "sha1", "sha1", 20, 64 },
{ "sha224", "sha224", 28, 64 },
{ "sha256", "sha256", 32, 64 },
{ "sha384", "sha384", 48, 128 },
{ "sha512", "sha512", 64, 128 },
{ "ripemd160", "rmd160", 20, 64 },
{ "whirlpool", "wp512", 64, 64 },
{ "sha3-224", "sha3-224", 28, 144 },
{ "sha3-256", "sha3-256", 32, 136 },
{ "sha3-384", "sha3-384", 48, 104 },
{ "sha3-512", "sha3-512", 64, 72 },
{ "stribog256","streebog256", 32, 64 },
{ "stribog512","streebog512", 64, 64 },
{ "sm3", "sm3", 32, 64 },
{ "blake2b-160","blake2b-160",20, 128 },
{ "blake2b-256","blake2b-256",32, 128 },
{ "blake2b-384","blake2b-384",48, 128 },
{ "blake2b-512","blake2b-512",64, 128 },
{ "blake2s-128","blake2s-128",16, 64 },
{ "blake2s-160","blake2s-160",20, 64 },
{ "blake2s-224","blake2s-224",28, 64 },
{ "blake2s-256","blake2s-256",32, 64 },
{ NULL, NULL, 0, 0 }
{ "sha1", "sha1", 20, 64 },
{ "sha256", "sha256", 32, 64 },
{ "sha512", "sha512", 64, 128 },
{ "ripemd160", "rmd160", 20, 64 },
{ "whirlpool", "wp512", 64, 64 },
{ NULL, NULL, 0, 0 }
};
struct crypt_hash {
@@ -85,10 +68,6 @@ struct crypt_hmac {
int hash_len;
};
struct crypt_cipher {
struct crypt_cipher_kernel ck;
};
static int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *opfd,
const void *key, size_t key_length)
{
@@ -118,7 +97,7 @@ static int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *op
return 0;
}
int crypt_backend_init(void)
int crypt_backend_init(struct crypt_device *ctx)
{
struct utsname uts;
struct sockaddr_alg sa = {
@@ -126,7 +105,7 @@ int crypt_backend_init(void)
.salg_type = "hash",
.salg_name = "sha256",
};
int r, tfmfd = -1, opfd = -1;
int tfmfd = -1, opfd = -1;
if (crypto_backend_initialised)
return 0;
@@ -134,17 +113,15 @@ int crypt_backend_init(void)
if (uname(&uts) == -1 || strcmp(uts.sysname, "Linux"))
return -EINVAL;
r = snprintf(version, sizeof(version), "%s %s kernel cryptoAPI",
uts.sysname, uts.release);
if (r < 0 || (size_t)r >= sizeof(version))
return -EINVAL;
if (crypt_kernel_socket_init(&sa, &tfmfd, &opfd, NULL, 0) < 0)
return -EINVAL;
close(tfmfd);
close(opfd);
snprintf(version, sizeof(version), "%s %s kernel cryptoAPI",
uts.sysname, uts.release);
crypto_backend_initialised = 1;
return 0;
}
@@ -204,7 +181,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
}
h->hash_len = ha->length;
strncpy((char *)sa.salg_name, ha->kernel_name, sizeof(sa.salg_name)-1);
strncpy((char *)sa.salg_name, ha->kernel_name, sizeof(sa.salg_name));
if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd, NULL, 0) < 0) {
free(h);
@@ -265,7 +242,6 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
.salg_family = AF_ALG,
.salg_type = "hash",
};
int r;
h = malloc(sizeof(*h));
if (!h)
@@ -278,12 +254,8 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
}
h->hash_len = ha->length;
r = snprintf((char *)sa.salg_name, sizeof(sa.salg_name),
snprintf((char *)sa.salg_name, sizeof(sa.salg_name),
"hmac(%s)", ha->kernel_name);
if (r < 0 || (size_t)r >= sizeof(sa.salg_name)) {
free(h);
return -EINVAL;
}
if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd, key, key_length) < 0) {
free(h);
@@ -361,58 +333,3 @@ int crypt_pbkdf(const char *kdf, const char *hash,
return -EINVAL;
}
/* Block ciphers */
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
struct crypt_cipher *h;
int r;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
r = crypt_cipher_init_kernel(&h->ck, name, mode, key, key_length);
if (r < 0) {
free(h);
return r;
}
*ctx = h;
return 0;
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
crypt_cipher_destroy_kernel(&ctx->ck);
free(ctx);
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_encrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_decrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
}
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
{
return true;
}
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
iv, iv_length, tag, tag_length);
}

View File

@@ -1,8 +1,8 @@
/*
* Nettle crypto backend implementation
*
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2021 Milan Broz
* Copyright (C) 2011-2018 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,19 +23,11 @@
#include <string.h>
#include <errno.h>
#include <nettle/sha.h>
#include <nettle/sha3.h>
#include <nettle/hmac.h>
#include <nettle/pbkdf2.h>
#include "crypto_backend_internal.h"
#include "crypto_backend.h"
#if HAVE_NETTLE_VERSION_H
#include <nettle/version.h>
#define VSTR(s) STR(s)
#define STR(s) #s
static const char *version = "Nettle "VSTR(NETTLE_VERSION_MAJOR)"."VSTR(NETTLE_VERSION_MINOR);
#else
static const char *version = "Nettle";
#endif
static char *version = "Nettle";
typedef void (*init_func) (void *);
typedef void (*update_func) (void *, size_t, const uint8_t *);
@@ -53,24 +45,6 @@ struct hash_alg {
set_key_func hmac_set_key;
};
/* Missing HMAC wrappers in Nettle */
#define HMAC_FCE(xxx) \
struct xhmac_##xxx##_ctx HMAC_CTX(struct xxx##_ctx); \
static void xhmac_##xxx##_set_key(struct xhmac_##xxx##_ctx *ctx, \
size_t key_length, const uint8_t *key) \
{HMAC_SET_KEY(ctx, &nettle_##xxx, key_length, key);} \
static void xhmac_##xxx##_update(struct xhmac_##xxx##_ctx *ctx, \
size_t length, const uint8_t *data) \
{xxx##_update(&ctx->state, length, data);} \
static void xhmac_##xxx##_digest(struct xhmac_##xxx##_ctx *ctx, \
size_t length, uint8_t *digest) \
{HMAC_DIGEST(ctx, &nettle_##xxx, length, digest);}
HMAC_FCE(sha3_224);
HMAC_FCE(sha3_256);
HMAC_FCE(sha3_384);
HMAC_FCE(sha3_512);
static struct hash_alg hash_algs[] = {
{ "sha1", SHA1_DIGEST_SIZE,
(init_func) sha1_init,
@@ -120,41 +94,6 @@ static struct hash_alg hash_algs[] = {
(digest_func) hmac_ripemd160_digest,
(set_key_func) hmac_ripemd160_set_key,
},
/* Nettle prior to version 3.2 has incompatible SHA3 implementation */
#if NETTLE_SHA3_FIPS202
{ "sha3-224", SHA3_224_DIGEST_SIZE,
(init_func) sha3_224_init,
(update_func) sha3_224_update,
(digest_func) sha3_224_digest,
(update_func) xhmac_sha3_224_update,
(digest_func) xhmac_sha3_224_digest,
(set_key_func) xhmac_sha3_224_set_key,
},
{ "sha3-256", SHA3_256_DIGEST_SIZE,
(init_func) sha3_256_init,
(update_func) sha3_256_update,
(digest_func) sha3_256_digest,
(update_func) xhmac_sha3_256_update,
(digest_func) xhmac_sha3_256_digest,
(set_key_func) xhmac_sha3_256_set_key,
},
{ "sha3-384", SHA3_384_DIGEST_SIZE,
(init_func) sha3_384_init,
(update_func) sha3_384_update,
(digest_func) sha3_384_digest,
(update_func) xhmac_sha3_384_update,
(digest_func) xhmac_sha3_384_digest,
(set_key_func) xhmac_sha3_384_set_key,
},
{ "sha3-512", SHA3_512_DIGEST_SIZE,
(init_func) sha3_512_init,
(update_func) sha3_512_update,
(digest_func) sha3_512_digest,
(update_func) xhmac_sha3_512_update,
(digest_func) xhmac_sha3_512_digest,
(set_key_func) xhmac_sha3_512_set_key,
},
#endif
{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, }
};
@@ -166,11 +105,6 @@ struct crypt_hash {
struct sha256_ctx sha256;
struct sha384_ctx sha384;
struct sha512_ctx sha512;
struct ripemd160_ctx ripemd160;
struct sha3_224_ctx sha3_224;
struct sha3_256_ctx sha3_256;
struct sha3_384_ctx sha3_384;
struct sha3_512_ctx sha3_512;
} nettle_ctx;
};
@@ -182,20 +116,11 @@ struct crypt_hmac {
struct hmac_sha256_ctx sha256;
struct hmac_sha384_ctx sha384;
struct hmac_sha512_ctx sha512;
struct hmac_ripemd160_ctx ripemd160;
struct xhmac_sha3_224_ctx sha3_224;
struct xhmac_sha3_256_ctx sha3_256;
struct xhmac_sha3_384_ctx sha3_384;
struct xhmac_sha3_512_ctx sha3_512;
} nettle_ctx;
size_t key_length;
uint8_t *key;
};
struct crypt_cipher {
struct crypt_cipher_kernel ck;
};
uint32_t crypt_backend_flags(void)
{
return 0;
@@ -213,7 +138,7 @@ static struct hash_alg *_get_alg(const char *name)
return NULL;
}
int crypt_backend_init(void)
int crypt_backend_init(struct crypt_device *ctx)
{
return 0;
}
@@ -374,8 +299,8 @@ int crypt_pbkdf(const char *kdf, const char *hash,
if (r < 0)
return r;
nettle_pbkdf2(&h->nettle_ctx, h->hash->hmac_update,
h->hash->hmac_digest, h->hash->length, iterations,
nettle_pbkdf2(&h->nettle_ctx, h->hash->nettle_hmac_update,
h->hash->nettle_hmac_digest, h->hash->length, iterations,
salt_length, (const uint8_t *)salt, key_length,
(uint8_t *)key);
crypt_hmac_destroy(h);
@@ -387,58 +312,3 @@ int crypt_pbkdf(const char *kdf, const char *hash,
return -EINVAL;
}
/* Block ciphers */
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
struct crypt_cipher *h;
int r;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
r = crypt_cipher_init_kernel(&h->ck, name, mode, key, key_length);
if (r < 0) {
free(h);
return r;
}
*ctx = h;
return 0;
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
crypt_cipher_destroy_kernel(&ctx->ck);
free(ctx);
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_encrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_decrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
}
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
{
return true;
}
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
iv, iv_length, tag, tag_length);
}

View File

@@ -1,8 +1,8 @@
/*
* NSS crypto backend implementation
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,7 +23,7 @@
#include <errno.h>
#include <nss.h>
#include <pk11pub.h>
#include "crypto_backend_internal.h"
#include "crypto_backend.h"
#define CONST_CAST(x) (x)(uintptr_t)
@@ -59,10 +59,6 @@ struct crypt_hmac {
const struct hash_alg *hash;
};
struct crypt_cipher {
struct crypt_cipher_kernel ck;
};
static struct hash_alg *_get_alg(const char *name)
{
int i = 0;
@@ -75,10 +71,8 @@ static struct hash_alg *_get_alg(const char *name)
return NULL;
}
int crypt_backend_init(void)
int crypt_backend_init(struct crypt_device *ctx)
{
int r;
if (crypto_backend_initialised)
return 0;
@@ -86,13 +80,10 @@ int crypt_backend_init(void)
return -EINVAL;
#if HAVE_DECL_NSS_GETVERSION
r = snprintf(version, sizeof(version), "NSS %s", NSS_GetVersion());
snprintf(version, 64, "NSS %s", NSS_GetVersion());
#else
r = snprintf(version, sizeof(version), "NSS");
snprintf(version, 64, "NSS");
#endif
if (r < 0 || (size_t)r >= sizeof(version))
return -EINVAL;
crypto_backend_initialised = 1;
return 0;
}
@@ -340,58 +331,3 @@ int crypt_pbkdf(const char *kdf, const char *hash,
return -EINVAL;
}
/* Block ciphers */
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
struct crypt_cipher *h;
int r;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
r = crypt_cipher_init_kernel(&h->ck, name, mode, key, key_length);
if (r < 0) {
free(h);
return r;
}
*ctx = h;
return 0;
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
crypt_cipher_destroy_kernel(&ctx->ck);
free(ctx);
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_encrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_decrypt_kernel(&ctx->ck, in, out, length, iv, iv_length);
}
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
{
return true;
}
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length,
iv, iv_length, tag, tag_length);
}

View File

@@ -1,8 +1,8 @@
/*
* OPENSSL crypto backend implementation
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2021 Milan Broz
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -33,9 +33,7 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include "crypto_backend_internal.h"
#define CONST_CAST(x) (x)(uintptr_t)
#include "crypto_backend.h"
static int crypto_backend_initialised = 0;
@@ -51,23 +49,6 @@ struct crypt_hmac {
int hash_len;
};
struct crypt_cipher {
bool use_kernel;
union {
struct crypt_cipher_kernel kernel;
struct {
EVP_CIPHER_CTX *hd_enc;
EVP_CIPHER_CTX *hd_dec;
size_t iv_length;
} lib;
} u;
};
struct hash_alg {
const char *name;
const char *openssl_name;
};
/*
* Compatible wrappers for OpenSSL < 1.1.0 and LibreSSL < 2.7.0
*/
@@ -126,7 +107,7 @@ static const char *openssl_backend_version(void)
}
#endif
int crypt_backend_init(void)
int crypt_backend_init(struct crypt_device *ctx)
{
if (crypto_backend_initialised)
return 0;
@@ -152,36 +133,11 @@ const char *crypt_backend_version(void)
return openssl_backend_version();
}
static const char *crypt_hash_compat_name(const char *name)
{
const char *hash_name = name;
int i;
static struct hash_alg hash_algs[] = {
{ "blake2b-512", "blake2b512" },
{ "blake2s-256", "blake2s256" },
{ NULL, NULL, }};
if (!name)
return NULL;
i = 0;
while (hash_algs[i].name) {
if (!strcasecmp(name, hash_algs[i].name)) {
hash_name = hash_algs[i].openssl_name;
break;
}
i++;
}
return hash_name;
}
/* HASH */
int crypt_hash_size(const char *name)
{
const EVP_MD *hash_id;
const EVP_MD *hash_id = EVP_get_digestbyname(name);
hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
if (!hash_id)
return -EINVAL;
@@ -202,7 +158,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
return -ENOMEM;
}
h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
h->hash_id = EVP_get_digestbyname(name);
if (!h->hash_id) {
EVP_MD_CTX_free(h->md);
free(h);
@@ -287,7 +243,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
return -ENOMEM;
}
h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
h->hash_id = EVP_get_digestbyname(name);
if (!h->hash_id) {
HMAC_CTX_free(h->md);
free(h);
@@ -363,12 +319,12 @@ int crypt_pbkdf(const char *kdf, const char *hash,
return -EINVAL;
if (!strcmp(kdf, "pbkdf2")) {
hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash));
hash_id = EVP_get_digestbyname(hash);
if (!hash_id)
return -EINVAL;
if (!PKCS5_PBKDF2_HMAC(password, (int)password_length,
(const unsigned char *)salt, (int)salt_length,
(unsigned char *)salt, (int)salt_length,
(int)iterations, hash_id, (int)key_length, (unsigned char *)key))
return -EINVAL;
return 0;
@@ -379,198 +335,3 @@ int crypt_pbkdf(const char *kdf, const char *hash,
return -EINVAL;
}
/* Block ciphers */
static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec)
{
EVP_CIPHER_CTX_free(*hd_enc);
*hd_enc = NULL;
EVP_CIPHER_CTX_free(*hd_dec);
*hd_dec = NULL;
}
static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const char *name,
const char *mode, const void *key, size_t key_length, size_t *iv_length)
{
char cipher_name[256];
const EVP_CIPHER *type;
int r, key_bits;
key_bits = key_length * 8;
if (!strcmp(mode, "xts"))
key_bits /= 2;
r = snprintf(cipher_name, sizeof(cipher_name), "%s-%d-%s", name, key_bits, mode);
if (r < 0 || (size_t)r >= sizeof(cipher_name))
return -EINVAL;
type = EVP_get_cipherbyname(cipher_name);
if (!type)
return -ENOENT;
if (EVP_CIPHER_key_length(type) != (int)key_length)
return -EINVAL;
*hd_enc = EVP_CIPHER_CTX_new();
*hd_dec = EVP_CIPHER_CTX_new();
*iv_length = EVP_CIPHER_iv_length(type);
if (!*hd_enc || !*hd_dec)
return -EINVAL;
if (EVP_EncryptInit_ex(*hd_enc, type, NULL, key, NULL) != 1 ||
EVP_DecryptInit_ex(*hd_dec, type, NULL, key, NULL) != 1) {
_cipher_destroy(hd_enc, hd_dec);
return -EINVAL;
}
if (EVP_CIPHER_CTX_set_padding(*hd_enc, 0) != 1 ||
EVP_CIPHER_CTX_set_padding(*hd_dec, 0) != 1) {
_cipher_destroy(hd_enc, hd_dec);
return -EINVAL;
}
return 0;
}
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
struct crypt_cipher *h;
int r;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, name, mode, key,
key_length, &h->u.lib.iv_length)) {
h->use_kernel = false;
*ctx = h;
return 0;
}
r = crypt_cipher_init_kernel(&h->u.kernel, name, mode, key, key_length);
if (r < 0) {
free(h);
return r;
}
h->use_kernel = true;
*ctx = h;
return 0;
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
if (ctx->use_kernel)
crypt_cipher_destroy_kernel(&ctx->u.kernel);
else
_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec);
free(ctx);
}
static int _cipher_encrypt(struct crypt_cipher *ctx, const unsigned char *in, unsigned char *out,
int length, const unsigned char *iv, size_t iv_length)
{
int len;
if (ctx->u.lib.iv_length != iv_length)
return -EINVAL;
if (EVP_EncryptInit_ex(ctx->u.lib.hd_enc, NULL, NULL, NULL, iv) != 1)
return -EINVAL;
if (EVP_EncryptUpdate(ctx->u.lib.hd_enc, out, &len, in, length) != 1)
return -EINVAL;
if (EVP_EncryptFinal(ctx->u.lib.hd_enc, out + len, &len) != 1)
return -EINVAL;
return 0;
}
static int _cipher_decrypt(struct crypt_cipher *ctx, const unsigned char *in, unsigned char *out,
int length, const unsigned char *iv, size_t iv_length)
{
int len;
if (ctx->u.lib.iv_length != iv_length)
return -EINVAL;
if (EVP_DecryptInit_ex(ctx->u.lib.hd_dec, NULL, NULL, NULL, iv) != 1)
return -EINVAL;
if (EVP_DecryptUpdate(ctx->u.lib.hd_dec, out, &len, in, length) != 1)
return -EINVAL;
if (EVP_DecryptFinal(ctx->u.lib.hd_dec, out + len, &len) != 1)
return -EINVAL;
return 0;
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
if (ctx->use_kernel)
return crypt_cipher_encrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
return _cipher_encrypt(ctx, (const unsigned char*)in,
(unsigned char *)out, length, (const unsigned char*)iv, iv_length);
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
if (ctx->use_kernel)
return crypt_cipher_decrypt_kernel(&ctx->u.kernel, in, out, length, iv, iv_length);
return _cipher_decrypt(ctx, (const unsigned char*)in,
(unsigned char *)out, length, (const unsigned char*)iv, iv_length);
}
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx)
{
return ctx->use_kernel;
}
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
#ifdef EVP_CTRL_CCM_SET_IVLEN
EVP_CIPHER_CTX *ctx;
int len = 0, r = -EINVAL;
ctx = EVP_CIPHER_CTX_new();
if (!ctx)
return -EINVAL;
if (EVP_DecryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL) != 1)
goto out;
//EVP_CIPHER_CTX_key_length(ctx)
//EVP_CIPHER_CTX_iv_length(ctx)
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_length, NULL) != 1)
goto out;
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_length, CONST_CAST(void*)tag) != 1)
goto out;
if (EVP_DecryptInit_ex(ctx, NULL, NULL, key, (const unsigned char*)iv) != 1)
goto out;
if (EVP_DecryptUpdate(ctx, (unsigned char*)out, &len, (const unsigned char*)in, length) == 1)
r = 0;
out:
EVP_CIPHER_CTX_free(ctx);
return r;
#else
return -ENOTSUP;
#endif
}

View File

@@ -2,7 +2,7 @@
* Generic wrapper for storage encryption modes and Initial Vectors
* (reimplementation of some functions from Linux dm-crypt kernel)
*
* Copyright (C) 2014-2021 Milan Broz
* Copyright (C) 2014-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,23 +25,23 @@
#include "crypto_backend.h"
#define SECTOR_SHIFT 9
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
/*
* Internal IV helper
* IV documentation: https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt
*/
struct crypt_sector_iv {
enum { IV_NONE, IV_NULL, IV_PLAIN, IV_PLAIN64, IV_ESSIV, IV_BENBI, IV_PLAIN64BE, IV_EBOIV } type;
enum { IV_NONE, IV_NULL, IV_PLAIN, IV_PLAIN64, IV_ESSIV, IV_BENBI, IV_PLAIN64BE } type;
int iv_size;
char *iv;
struct crypt_cipher *cipher;
int shift;
struct crypt_cipher *essiv_cipher;
int benbi_shift;
};
/* Block encryption storage context */
struct crypt_storage {
size_t sector_size;
unsigned iv_shift;
uint64_t sector_start;
struct crypt_cipher *cipher;
struct crypt_sector_iv cipher_iv;
};
@@ -56,15 +56,12 @@ static int int_log2(unsigned int x)
static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
const char *cipher_name, const char *mode_name,
const char *iv_name, const void *key, size_t key_length,
size_t sector_size)
const char *iv_name, const void *key, size_t key_length)
{
int r;
memset(ctx, 0, sizeof(*ctx));
ctx->iv_size = crypt_cipher_ivsize(cipher_name, mode_name);
if (ctx->iv_size < 0 || (strcmp(mode_name, "ecb") && ctx->iv_size < 8))
if (ctx->iv_size < 8)
return -ENOENT;
if (!strcmp(cipher_name, "cipher_null") ||
@@ -89,6 +86,7 @@ static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
char *hash_name = strchr(iv_name, ':');
int hash_size;
char tmp[256];
int r;
if (!hash_name)
return -EINVAL;
@@ -116,7 +114,7 @@ static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
return r;
}
r = crypt_cipher_init(&ctx->cipher, cipher_name, "ecb",
r = crypt_cipher_init(&ctx->essiv_cipher, cipher_name, "ecb",
tmp, hash_size);
crypt_backend_memzero(tmp, sizeof(tmp));
if (r)
@@ -129,15 +127,7 @@ static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
return -EINVAL;
ctx->type = IV_BENBI;
ctx->shift = SECTOR_SHIFT - log;
} else if (!strncasecmp(iv_name, "eboiv", 5)) {
r = crypt_cipher_init(&ctx->cipher, cipher_name, "ecb",
key, key_length);
if (r)
return r;
ctx->type = IV_EBOIV;
ctx->shift = int_log2(sector_size);
ctx->benbi_shift = SECTOR_SHIFT - log;
} else
return -ENOENT;
@@ -173,20 +163,14 @@ static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector
case IV_ESSIV:
memset(ctx->iv, 0, ctx->iv_size);
*(uint64_t *)ctx->iv = cpu_to_le64(sector);
return crypt_cipher_encrypt(ctx->cipher,
return crypt_cipher_encrypt(ctx->essiv_cipher,
ctx->iv, ctx->iv, ctx->iv_size, NULL, 0);
break;
case IV_BENBI:
memset(ctx->iv, 0, ctx->iv_size);
val = cpu_to_be64((sector << ctx->shift) + 1);
val = cpu_to_be64((sector << ctx->benbi_shift) + 1);
memcpy(ctx->iv + ctx->iv_size - sizeof(val), &val, sizeof(val));
break;
case IV_EBOIV:
memset(ctx->iv, 0, ctx->iv_size);
*(uint64_t *)ctx->iv = cpu_to_le64(sector << ctx->shift);
return crypt_cipher_encrypt(ctx->cipher,
ctx->iv, ctx->iv, ctx->iv_size, NULL, 0);
break;
default:
return -EINVAL;
}
@@ -196,8 +180,8 @@ static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector
static void crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
{
if (ctx->type == IV_ESSIV || ctx->type == IV_EBOIV)
crypt_cipher_destroy(ctx->cipher);
if (ctx->type == IV_ESSIV)
crypt_cipher_destroy(ctx->essiv_cipher);
if (ctx->iv) {
memset(ctx->iv, 0, ctx->iv_size);
@@ -210,22 +194,16 @@ static void crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
/* Block encryption storage wrappers */
int crypt_storage_init(struct crypt_storage **ctx,
size_t sector_size,
uint64_t sector_start,
const char *cipher,
const char *cipher_mode,
const void *key, size_t key_length,
bool large_iv)
const void *key, size_t key_length)
{
struct crypt_storage *s;
char mode_name[64];
char *cipher_iv = NULL;
int r = -EIO;
if (sector_size < (1 << SECTOR_SHIFT) ||
sector_size > (1 << (SECTOR_SHIFT + 3)) ||
sector_size & (sector_size - 1))
return -EINVAL;
s = malloc(sizeof(*s));
if (!s)
return -ENOMEM;
@@ -246,40 +224,33 @@ int crypt_storage_init(struct crypt_storage **ctx,
return r;
}
r = crypt_sector_iv_init(&s->cipher_iv, cipher, mode_name, cipher_iv, key, key_length, sector_size);
r = crypt_sector_iv_init(&s->cipher_iv, cipher, mode_name, cipher_iv, key, key_length);
if (r) {
crypt_storage_destroy(s);
return r;
}
s->sector_size = sector_size;
s->iv_shift = large_iv ? int_log2(sector_size) - SECTOR_SHIFT : 0;
s->sector_start = sector_start;
*ctx = s;
return 0;
}
int crypt_storage_decrypt(struct crypt_storage *ctx,
uint64_t iv_offset,
uint64_t length, char *buffer)
uint64_t sector, size_t count,
char *buffer)
{
uint64_t i;
unsigned int i;
int r = 0;
if (length & (ctx->sector_size - 1))
return -EINVAL;
if (iv_offset & ((ctx->sector_size >> SECTOR_SHIFT) - 1))
return -EINVAL;
for (i = 0; i < length; i += ctx->sector_size) {
r = crypt_sector_iv_generate(&ctx->cipher_iv, (iv_offset + (i >> SECTOR_SHIFT)) >> ctx->iv_shift);
for (i = 0; i < count; i++) {
r = crypt_sector_iv_generate(&ctx->cipher_iv, sector + i);
if (r)
break;
r = crypt_cipher_decrypt(ctx->cipher,
&buffer[i],
&buffer[i],
ctx->sector_size,
&buffer[i * SECTOR_SIZE],
&buffer[i * SECTOR_SIZE],
SECTOR_SIZE,
ctx->cipher_iv.iv,
ctx->cipher_iv.iv_size);
if (r)
@@ -290,26 +261,20 @@ int crypt_storage_decrypt(struct crypt_storage *ctx,
}
int crypt_storage_encrypt(struct crypt_storage *ctx,
uint64_t iv_offset,
uint64_t length, char *buffer)
uint64_t sector, size_t count,
char *buffer)
{
uint64_t i;
unsigned int i;
int r = 0;
if (length & (ctx->sector_size - 1))
return -EINVAL;
if (iv_offset & ((ctx->sector_size >> SECTOR_SHIFT) - 1))
return -EINVAL;
for (i = 0; i < length; i += ctx->sector_size) {
r = crypt_sector_iv_generate(&ctx->cipher_iv, (iv_offset + (i >> SECTOR_SHIFT)) >> ctx->iv_shift);
for (i = 0; i < count; i++) {
r = crypt_sector_iv_generate(&ctx->cipher_iv, sector + i);
if (r)
break;
r = crypt_cipher_encrypt(ctx->cipher,
&buffer[i],
&buffer[i],
ctx->sector_size,
&buffer[i * SECTOR_SIZE],
&buffer[i * SECTOR_SIZE],
SECTOR_SIZE,
ctx->cipher_iv.iv,
ctx->cipher_iv.iv_size);
if (r)
@@ -332,8 +297,3 @@ void crypt_storage_destroy(struct crypt_storage *ctx)
memset(ctx, 0, sizeof(*ctx));
free(ctx);
}
bool crypt_storage_kernel_only(struct crypt_storage *ctx)
{
return crypt_cipher_kernel_only(ctx->cipher);
}

View File

@@ -4,8 +4,8 @@
* Copyright (C) 2004 Free Software Foundation
*
* cryptsetup related changes
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,7 +25,7 @@
#include <errno.h>
#include <alloca.h>
#include "crypto_backend_internal.h"
#include "crypto_backend.h"
static int hash_buf(const char *src, size_t src_len,
char *dst, size_t dst_len,
@@ -230,3 +230,197 @@ out:
return rc;
}
#if 0
#include <stdio.h>
struct test_vector {
const char *hash;
unsigned int hash_block_length;
unsigned int iterations;
const char *password;
unsigned int password_length;
const char *salt;
unsigned int salt_length;
const char *output;
unsigned int output_length;
};
struct test_vector test_vectors[] = {
/* RFC 3962 */
{
"sha1", 64, 1,
"password", 8,
"ATHENA.MIT.EDUraeburn", 21,
"\xcd\xed\xb5\x28\x1b\xb2\xf8\x01"
"\x56\x5a\x11\x22\xb2\x56\x35\x15"
"\x0a\xd1\xf7\xa0\x4b\xb9\xf3\xa3"
"\x33\xec\xc0\xe2\xe1\xf7\x08\x37", 32
}, {
"sha1", 64, 2,
"password", 8,
"ATHENA.MIT.EDUraeburn", 21,
"\x01\xdb\xee\x7f\x4a\x9e\x24\x3e"
"\x98\x8b\x62\xc7\x3c\xda\x93\x5d"
"\xa0\x53\x78\xb9\x32\x44\xec\x8f"
"\x48\xa9\x9e\x61\xad\x79\x9d\x86", 32
}, {
"sha1", 64, 1200,
"password", 8,
"ATHENA.MIT.EDUraeburn", 21,
"\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e"
"\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b"
"\xa7\xe5\x2d\xdb\xc5\xe5\x14\x2f"
"\x70\x8a\x31\xe2\xe6\x2b\x1e\x13", 32
}, {
"sha1", 64, 5,
"password", 8,
"\0224VxxV4\022", 8, // "\x1234567878563412
"\xd1\xda\xa7\x86\x15\xf2\x87\xe6"
"\xa1\xc8\xb1\x20\xd7\x06\x2a\x49"
"\x3f\x98\xd2\x03\xe6\xbe\x49\xa6"
"\xad\xf4\xfa\x57\x4b\x6e\x64\xee", 32
}, {
"sha1", 64, 1200,
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 64,
"pass phrase equals block size", 29,
"\x13\x9c\x30\xc0\x96\x6b\xc3\x2b"
"\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9"
"\xc5\xec\x59\xf1\xa4\x52\xf5\xcc"
"\x9a\xd9\x40\xfe\xa0\x59\x8e\xd1", 32
}, {
"sha1", 64, 1200,
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 65,
"pass phrase exceeds block size", 30,
"\x9c\xca\xd6\xd4\x68\x77\x0c\xd5"
"\x1b\x10\xe6\xa6\x87\x21\xbe\x61"
"\x1a\x8b\x4d\x28\x26\x01\xdb\x3b"
"\x36\xbe\x92\x46\x91\x5e\xc8\x2a", 32
}, {
"sha1", 64, 50,
"\360\235\204\236", 4, // g-clef ("\xf09d849e)
"EXAMPLE.COMpianist", 18,
"\x6b\x9c\xf2\x6d\x45\x45\x5a\x43"
"\xa5\xb8\xbb\x27\x6a\x40\x3b\x39"
"\xe7\xfe\x37\xa0\xc4\x1e\x02\xc2"
"\x81\xff\x30\x69\xe1\xe9\x4f\x52", 32
}, {
/* RFC-6070 */
"sha1", 64, 1,
"password", 8,
"salt", 4,
"\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9"
"\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6", 20
}, {
"sha1", 64, 2,
"password", 8,
"salt", 4,
"\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e"
"\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57", 20
}, {
"sha1", 64, 4096,
"password", 8,
"salt", 4,
"\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad"
"\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1", 20
}, {
"sha1", 64, 16777216,
"password", 8,
"salt", 4,
"\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94"
"\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84", 20
}, {
"sha1", 64, 4096,
"passwordPASSWORDpassword", 24,
"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
"\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8"
"\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96"
"\x4c\xf2\xf0\x70\x38", 25
}, {
"sha1", 64, 4096,
"pass\0word", 9,
"sa\0lt", 5,
"\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37"
"\xd7\xf0\x34\x25\xe0\xc3", 16
}, {
/* empty password test */
"sha1", 64, 2,
"", 0,
"salt", 4,
"\x13\x3a\x4c\xe8\x37\xb4\xd2\x52\x1e\xe2"
"\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97", 20
}, {
/* Password exceeds block size test */
"sha256", 64, 1200,
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 65,
"pass phrase exceeds block size", 30,
"\x22\x34\x4b\xc4\xb6\xe3\x26\x75"
"\xa8\x09\x0f\x3e\xa8\x0b\xe0\x1d"
"\x5f\x95\x12\x6a\x2c\xdd\xc3\xfa"
"\xcc\x4a\x5e\x6d\xca\x04\xec\x58", 32
}, {
"sha512", 128, 1200,
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 129,
"pass phrase exceeds block size", 30,
"\x0f\xb2\xed\x2c\x0e\x6e\xfb\x7d"
"\x7d\x8e\xdd\x58\x01\xb4\x59\x72"
"\x99\x92\x16\x30\x5e\xa4\x36\x8d"
"\x76\x14\x80\xf3\xe3\x7a\x22\xb9", 32
}, {
"whirlpool", 64, 1200,
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 65,
"pass phrase exceeds block size", 30,
"\x9c\x1c\x74\xf5\x88\x26\xe7\x6a"
"\x53\x58\xf4\x0c\x39\xe7\x80\x89"
"\x07\xc0\x31\x19\x9a\x50\xa2\x48"
"\xf1\xd9\xfe\x78\x64\xe5\x84\x50", 32
}
};
static void printhex(const char *s, const char *buf, size_t len)
{
size_t i;
printf("%s: ", s);
for (i = 0; i < len; i++)
printf("\\x%02x", (unsigned char)buf[i]);
printf("\n");
fflush(stdout);
}
static int pkcs5_pbkdf2_test_vectors(void)
{
char result[64];
unsigned int i, j;
struct test_vector *vec;
for (i = 0; i < (sizeof(test_vectors) / sizeof(*test_vectors)); i++) {
vec = &test_vectors[i];
for (j = 1; j <= vec->output_length; j++) {
if (pkcs5_pbkdf2(vec->hash,
vec->password, vec->password_length,
vec->salt, vec->salt_length,
vec->iterations,
j, result, vec->hash_block_length)) {
printf("pbkdf2 failed, vector %d\n", i);
return -EINVAL;
}
if (memcmp(result, vec->output, j) != 0) {
printf("vector %u\n", i);
printhex(" got", result, j);
printhex("want", vec->output, j);
return -EINVAL;
}
memset(result, 0, sizeof(result));
}
}
return 0;
}
#endif

View File

@@ -1,8 +1,8 @@
/*
* PBKDF performance check
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
* Copyright (C) 2016-2020 Ondrej Mosnacek
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2018, Milan Broz
* Copyright (C) 2016-2018, Ondrej Mosnacek
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -27,10 +27,6 @@
#include <sys/resource.h>
#include "crypto_backend.h"
#ifndef CLOCK_MONOTONIC_RAW
#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
#endif
#define BENCH_MIN_MS 250
#define BENCH_MIN_MS_FAST 10
#define BENCH_PERCENT_ATLEAST 95
@@ -155,7 +151,7 @@ static int next_argon2_params(uint32_t *t_cost, uint32_t *m_cost,
old_t_cost = *t_cost;
old_m_cost = *m_cost;
if ((uint32_t)ms > target_ms) {
if (ms > target_ms) {
/* decreasing, first try to lower t_cost, then m_cost */
num = (uint64_t)*t_cost * (uint64_t)target_ms;
denom = (uint64_t)ms;
@@ -206,7 +202,7 @@ static int next_argon2_params(uint32_t *t_cost, uint32_t *m_cost,
static int crypt_argon2_check(const char *kdf, const char *password,
size_t password_length, const char *salt,
size_t salt_length, size_t key_length,
uint32_t min_t_cost, uint32_t min_m_cost, uint32_t max_m_cost,
uint32_t min_t_cost, uint32_t max_m_cost,
uint32_t parallel, uint32_t target_ms,
uint32_t *out_t_cost, uint32_t *out_m_cost,
int (*progress)(uint32_t time_ms, void *usrptr),
@@ -214,7 +210,7 @@ static int crypt_argon2_check(const char *kdf, const char *password,
{
int r = 0;
char *key = NULL;
uint32_t t_cost, m_cost;
uint32_t t_cost, m_cost, min_m_cost = 8 * parallel;
long ms;
long ms_atleast = (long)target_ms * BENCH_PERCENT_ATLEAST / 100;
long ms_atmost = (long)target_ms * BENCH_PERCENT_ATMOST / 100;
@@ -222,9 +218,6 @@ static int crypt_argon2_check(const char *kdf, const char *password,
if (key_length <= 0 || target_ms <= 0)
return -EINVAL;
if (min_m_cost < (parallel * 8))
min_m_cost = parallel * 8;
if (max_m_cost < min_m_cost)
return -EINVAL;
@@ -361,10 +354,8 @@ static int crypt_pbkdf_check(const char *kdf, const char *hash,
ms = time_ms(&rstart, &rend);
if (ms) {
PBKDF2_temp = (double)iterations * target_ms / ms;
if (PBKDF2_temp > UINT32_MAX) {
r = -EINVAL;
goto out;
}
if (PBKDF2_temp > UINT32_MAX)
return -EINVAL;
*iter_secs = (uint32_t)PBKDF2_temp;
}
@@ -412,7 +403,6 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
if (!kdf || !iterations_out || !memory_out)
return -EINVAL;
/* FIXME: whole limits propagation should be more clear here */
r = crypt_pbkdf_get_limits(kdf, &pbkdf_limits);
if (r < 0)
return r;
@@ -428,9 +418,7 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
else if (!strncmp(kdf, "argon2", 6))
r = crypt_argon2_check(kdf, password, password_size,
salt, salt_size, volume_key_size,
pbkdf_limits.min_iterations,
pbkdf_limits.min_memory,
max_memory_kb,
pbkdf_limits.min_iterations, max_memory_kb,
parallel_threads, time_ms, iterations_out,
memory_out, progress, usrptr);
return r;

View File

@@ -1,7 +1,7 @@
/*
* Integrity volume handling
*
* Copyright (C) 2016-2021 Milan Broz
* Copyright (C) 2016-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <uuid/uuid.h>
#include "integrity.h"
@@ -33,14 +34,15 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
{
int devfd, r;
devfd = device_open(cd, device, O_RDONLY);
if(devfd < 0)
devfd = device_open(device, O_RDONLY);
if(devfd < 0) {
return -EINVAL;
}
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic)) ||
sb->version < SB_VERSION_1 || sb->version > SB_VERSION_5) {
(sb->version != SB_VERSION_1 && sb->version != SB_VERSION_2)) {
log_std(cd, "No integrity superblock detected on %s.\n",
device_path(device));
r = -EINVAL;
@@ -53,26 +55,22 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
r = 0;
}
close(devfd);
return r;
}
int INTEGRITY_read_sb(struct crypt_device *cd,
struct crypt_params_integrity *params,
uint32_t *flags)
int INTEGRITY_read_sb(struct crypt_device *cd, struct crypt_params_integrity *params)
{
struct superblock sb;
int r;
r = INTEGRITY_read_superblock(cd, crypt_metadata_device(cd), 0, &sb);
r = INTEGRITY_read_superblock(cd, crypt_data_device(cd), 0, &sb);
if (r)
return r;
params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block;
params->tag_size = sb.integrity_tag_size;
if (flags)
*flags = sb.flags;
return 0;
}
@@ -92,15 +90,11 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
log_std(cd, "journal_sections %u\n", sb.journal_sections);
log_std(cd, "provided_data_sectors %" PRIu64 "\n", sb.provided_data_sectors);
log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
if (sb.version >= SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
if (sb.version == SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
log_std(cd, "log2_blocks_per_bitmap %u\n", sb.log2_blocks_per_bitmap_bit);
log_std(cd, "flags %s%s%s%s%s\n",
log_std(cd, "flags %s%s\n",
sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "",
sb.flags & SB_FLAG_DIRTY_BITMAP ? "dirty_bitmap " : "",
sb.flags & SB_FLAG_FIXED_PADDING ? "fix_padding " : "",
sb.flags & SB_FLAG_FIXED_HMAC ? "fix_hmac " : "");
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "");
return 0;
}
@@ -142,27 +136,6 @@ int INTEGRITY_key_size(struct crypt_device *cd, const char *integrity)
return -EINVAL;
}
/* Return hash or hmac(hash) size, if known */
int INTEGRITY_hash_tag_size(const char *integrity)
{
char hash[MAX_CIPHER_LEN];
int r;
if (!integrity)
return 0;
if (!strcmp(integrity, "crc32") || !strcmp(integrity, "crc32c"))
return 4;
r = sscanf(integrity, "hmac(%" MAX_CIPHER_LEN_STR "[^)]s", hash);
if (r == 1)
r = crypt_hash_size(hash);
else
r = crypt_hash_size(integrity);
return r < 0 ? 0 : r;
}
int INTEGRITY_tag_size(struct crypt_device *cd,
const char *integrity,
const char *cipher,
@@ -207,107 +180,60 @@ int INTEGRITY_tag_size(struct crypt_device *cd,
return iv_tag_size + auth_tag_size;
}
int INTEGRITY_create_dmd_device(struct crypt_device *cd,
const struct crypt_params_integrity *params,
struct volume_key *vk,
struct volume_key *journal_crypt_key,
struct volume_key *journal_mac_key,
struct crypt_dm_active_device *dmd,
uint32_t flags, uint32_t sb_flags)
{
int r;
if (!dmd)
return -EINVAL;
*dmd = (struct crypt_dm_active_device) {
.flags = flags,
};
/* Workaround for kernel dm-integrity table bug */
if (sb_flags & SB_FLAG_RECALCULATING)
dmd->flags |= CRYPT_ACTIVATE_RECALCULATE;
r = INTEGRITY_data_sectors(cd, crypt_metadata_device(cd),
crypt_get_data_offset(cd) * SECTOR_SIZE, &dmd->size);
if (r < 0)
return r;
return dm_integrity_target_set(cd, &dmd->segment, 0, dmd->size,
crypt_metadata_device(cd), crypt_data_device(cd),
crypt_get_integrity_tag_size(cd), crypt_get_data_offset(cd),
crypt_get_sector_size(cd), vk, journal_crypt_key,
journal_mac_key, params);
}
int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
const char *name,
const char *type,
struct crypt_dm_active_device *dmd,
uint32_t sb_flags)
{
int r;
uint32_t dmi_flags;
struct dm_target *tgt = &dmd->segment;
if (!single_segment(dmd) || tgt->type != DM_INTEGRITY)
return -EINVAL;
log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d, provided sectors %" PRIu64".",
device_path(tgt->data_device), name, tgt->u.integrity.tag_size, dmd->size);
r = device_block_adjust(cd, tgt->data_device, DEV_EXCL,
tgt->u.integrity.offset, NULL, &dmd->flags);
if (r)
return r;
if (tgt->u.integrity.meta_device) {
r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
if (r)
return r;
}
r = dm_create_device(cd, name, type, dmd);
if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
log_err(cd, _("Kernel does not support dm-integrity mapping."));
return -ENOTSUP;
}
if (r < 0 && (sb_flags & SB_FLAG_FIXED_PADDING) && !dm_flags(cd, DM_INTEGRITY, &dmi_flags) &&
!(dmi_flags & DM_INTEGRITY_FIX_PADDING_SUPPORTED)) {
log_err(cd, _("Kernel does not support dm-integrity fixed metadata alignment."));
return -ENOTSUP;
}
if (r < 0 && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) &&
!(crypt_get_compatibility(cd) & CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC) &&
((sb_flags & SB_FLAG_FIXED_HMAC) ?
(tgt->u.integrity.vk && !tgt->u.integrity.journal_integrity_key) :
(tgt->u.integrity.vk || tgt->u.integrity.journal_integrity_key))) {
log_err(cd, _("Kernel refuses to activate insecure recalculate option (see legacy activation options to override)."));
return -ENOTSUP;
}
return r;
}
int INTEGRITY_activate(struct crypt_device *cd,
const char *name,
const struct crypt_params_integrity *params,
struct volume_key *vk,
struct volume_key *journal_crypt_key,
struct volume_key *journal_mac_key,
uint32_t flags, uint32_t sb_flags)
uint32_t flags)
{
struct crypt_dm_active_device dmd = {};
int r = INTEGRITY_create_dmd_device(cd, params, vk, journal_crypt_key,
journal_mac_key, &dmd, flags, sb_flags);
uint32_t dmi_flags;
struct crypt_dm_active_device dmdi = {
.target = DM_INTEGRITY,
.data_device = crypt_data_device(cd),
.flags = flags,
.u.integrity = {
.offset = crypt_get_data_offset(cd),
.tag_size = crypt_get_integrity_tag_size(cd),
.sector_size = crypt_get_sector_size(cd),
.vk = vk,
.journal_crypt_key = journal_crypt_key,
.journal_integrity_key = journal_mac_key,
}
};
int r;
r = INTEGRITY_data_sectors(cd, dmdi.data_device,
dmdi.u.integrity.offset * SECTOR_SIZE, &dmdi.size);
if (r < 0)
return r;
r = INTEGRITY_activate_dmd_device(cd, name, CRYPT_INTEGRITY, &dmd, sb_flags);
dm_targets_free(cd, &dmd);
if (params) {
dmdi.u.integrity.journal_size = params->journal_size;
dmdi.u.integrity.journal_watermark = params->journal_watermark;
dmdi.u.integrity.journal_commit_time = params->journal_commit_time;
dmdi.u.integrity.interleave_sectors = params->interleave_sectors;
dmdi.u.integrity.buffer_sectors = params->buffer_sectors;
dmdi.u.integrity.integrity = params->integrity;
dmdi.u.integrity.journal_integrity = params->journal_integrity;
dmdi.u.integrity.journal_crypt = params->journal_crypt;
}
log_dbg("Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d, provided sectors %" PRIu64".",
device_path(dmdi.data_device), name, dmdi.u.integrity.tag_size, dmdi.size);
r = device_block_adjust(cd, dmdi.data_device, DEV_EXCL,
dmdi.u.integrity.offset, NULL, &dmdi.flags);
if (r)
return r;
r = dm_create_device(cd, name, "INTEGRITY", &dmdi, 0);
if (r < 0 && (dm_flags(DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
log_err(cd, _("Kernel doesn't support dm-integrity mapping."));
return -ENOTSUP;
}
return r;
}
@@ -319,58 +245,55 @@ int INTEGRITY_format(struct crypt_device *cd,
uint32_t dmi_flags;
char tmp_name[64], tmp_uuid[40];
struct crypt_dm_active_device dmdi = {
.target = DM_INTEGRITY,
.data_device = crypt_data_device(cd),
.size = 8,
.flags = CRYPT_ACTIVATE_PRIVATE, /* We always create journal but it can be unused later */
.u.integrity = {
.offset = crypt_get_data_offset(cd),
.tag_size = crypt_get_integrity_tag_size(cd),
.sector_size = crypt_get_sector_size(cd),
.journal_crypt_key = journal_crypt_key,
.journal_integrity_key = journal_mac_key,
}
};
struct dm_target *tgt = &dmdi.segment;
int r;
uuid_t tmp_uuid_bin;
struct volume_key *vk = NULL;
if (params) {
dmdi.u.integrity.journal_size = params->journal_size;
dmdi.u.integrity.journal_watermark = params->journal_watermark;
dmdi.u.integrity.journal_commit_time = params->journal_commit_time;
dmdi.u.integrity.interleave_sectors = params->interleave_sectors;
dmdi.u.integrity.buffer_sectors = params->buffer_sectors;
dmdi.u.integrity.journal_integrity = params->journal_integrity;
dmdi.u.integrity.journal_crypt = params->journal_crypt;
dmdi.u.integrity.integrity = params->integrity;
}
uuid_generate(tmp_uuid_bin);
uuid_unparse(tmp_uuid_bin, tmp_uuid);
r = snprintf(tmp_name, sizeof(tmp_name), "temporary-cryptsetup-%s", tmp_uuid);
if (r < 0 || (size_t)r >= sizeof(tmp_name))
return -EINVAL;
snprintf(tmp_name, sizeof(tmp_name), "temporary-cryptsetup-%s", tmp_uuid);
log_dbg("Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d.",
device_path(dmdi.data_device), tmp_name, dmdi.u.integrity.tag_size);
r = device_block_adjust(cd, dmdi.data_device, DEV_EXCL, dmdi.u.integrity.offset, NULL, NULL);
if (r < 0 && (dm_flags(DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
log_err(cd, _("Kernel doesn't support dm-integrity mapping."));
return -ENOTSUP;
}
if (r)
return r;
/* There is no data area, we can actually use fake zeroed key */
if (params && params->integrity_key_size)
vk = crypt_alloc_volume_key(params->integrity_key_size, NULL);
dmdi.u.integrity.vk = crypt_alloc_volume_key(params->integrity_key_size, NULL);
r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, crypt_metadata_device(cd),
crypt_data_device(cd), crypt_get_integrity_tag_size(cd),
crypt_get_data_offset(cd), crypt_get_sector_size(cd), vk,
journal_crypt_key, journal_mac_key, params);
if (r < 0) {
crypt_free_volume_key(vk);
return r;
}
r = dm_create_device(cd, tmp_name, "INTEGRITY", &dmdi, 0);
log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d.",
device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size);
r = device_block_adjust(cd, tgt->data_device, DEV_EXCL, tgt->u.integrity.offset, NULL, NULL);
if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
log_err(cd, _("Kernel does not support dm-integrity mapping."));
r = -ENOTSUP;
}
if (r) {
dm_targets_free(cd, &dmdi);
return r;
}
if (tgt->u.integrity.meta_device) {
r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
if (r) {
dm_targets_free(cd, &dmdi);
return r;
}
}
r = dm_create_device(cd, tmp_name, CRYPT_INTEGRITY, &dmdi);
crypt_free_volume_key(vk);
dm_targets_free(cd, &dmdi);
crypt_free_volume_key(dmdi.u.integrity.vk);
if (r)
return r;

View File

@@ -1,7 +1,7 @@
/*
* Integrity header definition
* Integrity header defitinion
*
* Copyright (C) 2016-2021 Milan Broz
* Copyright (C) 2016-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -27,21 +27,14 @@ struct crypt_device;
struct device;
struct crypt_params_integrity;
struct volume_key;
struct crypt_dm_active_device;
/* dm-integrity helper */
#define SB_MAGIC "integrt"
#define SB_VERSION_1 1
#define SB_VERSION_2 2
#define SB_VERSION_3 3
#define SB_VERSION_4 4
#define SB_VERSION_5 5
#define SB_FLAG_HAVE_JOURNAL_MAC (1 << 0)
#define SB_FLAG_RECALCULATING (1 << 1) /* V2 only */
#define SB_FLAG_DIRTY_BITMAP (1 << 2) /* V3 only */
#define SB_FLAG_FIXED_PADDING (1 << 3) /* V4 only */
#define SB_FLAG_FIXED_HMAC (1 << 4) /* V5 only */
struct superblock {
uint8_t magic[8];
@@ -52,14 +45,11 @@ struct superblock {
uint64_t provided_data_sectors;
uint32_t flags;
uint8_t log2_sectors_per_block;
uint8_t log2_blocks_per_bitmap_bit; /* V3 only */
uint8_t pad[2];
uint64_t recalc_sector; /* V2 only */
uint8_t pad[3];
uint64_t recalc_sector; /* V2 only */
} __attribute__ ((packed));
int INTEGRITY_read_sb(struct crypt_device *cd,
struct crypt_params_integrity *params,
uint32_t *flags);
int INTEGRITY_read_sb(struct crypt_device *cd, struct crypt_params_integrity *params);
int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offset);
@@ -72,7 +62,6 @@ int INTEGRITY_tag_size(struct crypt_device *cd,
const char *integrity,
const char *cipher,
const char *cipher_mode);
int INTEGRITY_hash_tag_size(const char *integrity);
int INTEGRITY_format(struct crypt_device *cd,
const struct crypt_params_integrity *params,
@@ -85,19 +74,5 @@ int INTEGRITY_activate(struct crypt_device *cd,
struct volume_key *vk,
struct volume_key *journal_crypt_key,
struct volume_key *journal_mac_key,
uint32_t flags, uint32_t sb_flags);
int INTEGRITY_create_dmd_device(struct crypt_device *cd,
const struct crypt_params_integrity *params,
struct volume_key *vk,
struct volume_key *journal_crypt_key,
struct volume_key *journal_mac_key,
struct crypt_dm_active_device *dmd,
uint32_t flags, uint32_t sb_flags);
int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
const char *name,
const char *type,
struct crypt_dm_active_device *dmd,
uint32_t sb_flags);
uint32_t flags);
#endif

View File

@@ -1,10 +1,10 @@
/*
* libcryptsetup - cryptsetup library internal
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2018, Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -27,10 +27,8 @@
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include <fcntl.h>
#include "nls.h"
#include "bitops.h"
@@ -42,7 +40,6 @@
#include "utils_keyring.h"
#include "utils_io.h"
#include "crypto_backend.h"
#include "utils_storage_wrappers.h"
#include "libcryptsetup.h"
@@ -56,9 +53,6 @@
#define DEFAULT_DISK_ALIGNMENT 1048576 /* 1MiB */
#define DEFAULT_MEM_ALIGNMENT 4096
#define LOG_MAX_LEN 4096
#define MAX_DM_DEPS 32
#define CRYPT_SUBDEV "SUBDEV" /* prefix for sublayered devices underneath public crypt types */
#define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); })
@@ -71,25 +65,11 @@
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
#define MOVE_REF(x, y) \
do { \
typeof (x) *_px = &(x), *_py = &(y); \
*_px = *_py; \
*_py = NULL; \
} while (0)
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
struct crypt_device;
struct luks2_reencrypt;
struct volume_key {
int id;
size_t keylength;
const char *key_description;
struct volume_key *next;
char key[];
};
@@ -97,11 +77,6 @@ struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key);
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength);
void crypt_free_volume_key(struct volume_key *vk);
int crypt_volume_key_set_description(struct volume_key *key, const char *key_description);
void crypt_volume_key_set_id(struct volume_key *vk, int id);
int crypt_volume_key_get_id(const struct volume_key *vk);
void crypt_volume_key_add_next(struct volume_key **vks, struct volume_key *vk);
struct volume_key *crypt_volume_key_next(struct volume_key *vk);
struct volume_key *crypt_volume_key_by_id(struct volume_key *vk, int id);
struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd);
int init_pbkdf_type(struct crypt_device *cd,
@@ -112,47 +87,38 @@ int verify_pbkdf_params(struct crypt_device *cd,
int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
struct crypt_pbkdf_type *pbkdf,
size_t volume_key_size);
const char *crypt_get_cipher_spec(struct crypt_device *cd);
/* Device backend */
struct device;
int device_alloc(struct crypt_device *cd, struct device **device, const char *path);
int device_alloc(struct device **device, const char *path);
int device_alloc_no_check(struct device **device, const char *path);
void device_close(struct crypt_device *cd, struct device *device);
void device_free(struct crypt_device *cd, struct device *device);
void device_free(struct device *device);
const char *device_path(const struct device *device);
const char *device_dm_name(const struct device *device);
const char *device_block_path(const struct device *device);
void device_topology_alignment(struct crypt_device *cd,
struct device *device,
unsigned long *required_alignment, /* bytes */
unsigned long *alignment_offset, /* bytes */
unsigned long default_alignment);
size_t device_block_size(struct crypt_device *cd, struct device *device);
void device_topology_alignment(struct device *device,
unsigned long *required_alignment, /* bytes */
unsigned long *alignment_offset, /* bytes */
unsigned long default_alignment);
size_t device_block_size(struct device *device);
int device_read_ahead(struct device *device, uint32_t *read_ahead);
int device_size(struct device *device, uint64_t *size);
int device_open(struct crypt_device *cd, struct device *device, int flags);
int device_open_excl(struct crypt_device *cd, struct device *device, int flags);
void device_release_excl(struct crypt_device *cd, struct device *device);
int device_open(struct device *device, int flags);
void device_disable_direct_io(struct device *device);
int device_is_identical(struct device *device1, struct device *device2);
int device_is_rotational(struct device *device);
size_t device_alignment(struct device *device);
int device_direct_io(const struct device *device);
int device_fallocate(struct device *device, uint64_t size);
void device_sync(struct crypt_device *cd, struct device *device);
int device_check_size(struct crypt_device *cd,
struct device *device,
uint64_t req_offset, int falloc);
void device_sync(struct device *device, int devfd);
int device_open_locked(struct crypt_device *cd, struct device *device, int flags);
int device_open_locked(struct device *device, int flags);
int device_read_lock(struct crypt_device *cd, struct device *device);
int device_write_lock(struct crypt_device *cd, struct device *device);
void device_read_unlock(struct crypt_device *cd, struct device *device);
void device_write_unlock(struct crypt_device *cd, struct device *device);
bool device_is_locked(struct device *device);
void device_read_unlock(struct device *device);
void device_write_unlock(struct device *device);
enum devcheck { DEV_OK = 0, DEV_EXCL = 1 };
enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 };
int device_check_access(struct crypt_device *cd,
struct device *device,
enum devcheck device_check);
@@ -164,13 +130,6 @@ int device_block_adjust(struct crypt_device *cd,
uint32_t *flags);
size_t size_round_up(size_t size, size_t block);
int create_or_reload_device(struct crypt_device *cd, const char *name,
const char *type, struct crypt_dm_active_device *dmd);
int create_or_reload_device_with_integrity(struct crypt_device *cd, const char *name,
const char *type, struct crypt_dm_active_device *dmd,
struct crypt_dm_active_device *dmdi);
/* Receive backend devices from context helpers */
struct device *crypt_metadata_device(struct crypt_device *cd);
struct device *crypt_data_device(struct crypt_device *cd);
@@ -185,7 +144,6 @@ char *crypt_get_base_device(const char *dev_path);
uint64_t crypt_dev_partition_offset(const char *dev_path);
int lookup_by_disk_id(const char *dm_uuid);
int lookup_by_sysfs_uuid_field(const char *dm_uuid, size_t max_len);
int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid);
size_t crypt_getpagesize(void);
unsigned crypt_cpusonline(void);
@@ -194,7 +152,7 @@ uint64_t crypt_getphysmemory_kb(void);
int init_crypto(struct crypt_device *ctx);
void logger(struct crypt_device *cd, int level, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
#define log_dbg(c, x...) logger(c, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
#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...) logger(c, CRYPT_LOG_ERROR, __FILE__, __LINE__, x)
@@ -211,7 +169,7 @@ int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int qualit
void crypt_random_exit(void);
int crypt_random_default_key_rng(void);
int crypt_plain_hash(struct crypt_device *cd,
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);
@@ -222,11 +180,6 @@ int PLAIN_activate(struct crypt_device *cd,
uint32_t flags);
void *crypt_get_hdr(struct crypt_device *cd, const char *type);
void crypt_set_luks2_reencrypt(struct crypt_device *cd, struct luks2_reencrypt *rh);
struct luks2_reencrypt *crypt_get_luks2_reencrypt(struct crypt_device *cd);
int onlyLUKS2(struct crypt_device *cd);
int onlyLUKS2mask(struct crypt_device *cd, uint32_t mask);
int crypt_wipe_device(struct crypt_device *cd,
struct device *device,
@@ -245,9 +198,8 @@ int crypt_get_integrity_tag_size(struct crypt_device *cd);
int crypt_key_in_keyring(struct crypt_device *cd);
void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring);
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk);
int crypt_use_keyring_for_vk(struct crypt_device *cd);
void crypt_drop_keyring_key_by_description(struct crypt_device *cd, const char *key_description, key_type_t ktype);
void crypt_drop_keyring_key(struct crypt_device *cd, struct volume_key *vks);
int crypt_use_keyring_for_vk(const struct crypt_device *cd);
void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description);
static inline uint64_t version(uint16_t major, uint16_t minor, uint16_t patch, uint16_t release)
{
@@ -256,22 +208,4 @@ static inline uint64_t version(uint16_t major, uint16_t minor, uint16_t patch, u
int kernel_version(uint64_t *kversion);
int crypt_serialize_lock(struct crypt_device *cd);
void crypt_serialize_unlock(struct crypt_device *cd);
bool crypt_string_in(const char *str, char **list, size_t list_size);
int crypt_strcmp(const char *a, const char *b);
int crypt_compare_dm_devices(struct crypt_device *cd,
const struct crypt_dm_active_device *src,
const struct crypt_dm_active_device *tgt);
static inline void *crypt_zalloc(size_t size) { return calloc(1, size); }
static inline bool uint64_mult_overflow(uint64_t *u, uint64_t b, size_t size)
{
*u = (uint64_t)b * size;
if ((uint64_t)(*u / size) != b)
return true;
return false;
}
#endif /* INTERNAL_H */

View File

@@ -1,10 +1,10 @@
/*
* libcryptsetup - cryptsetup library
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2021 Milan Broz
* Copyright (C) 2004, Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2018, Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -64,23 +64,6 @@ struct crypt_device; /* crypt device handle */
*/
int crypt_init(struct crypt_device **cd, const char *device);
/**
* Initialize crypt device handle with optional data device and check
* if devices exist.
*
* @param cd Returns pointer to crypt device handle
* @param device Path to the backing device or detached header.
* @param data_device Path to the data device or @e NULL.
*
* @return @e 0 on success or negative errno value otherwise.
*
* @note Note that logging is not initialized here, possible messages use
* default log function.
*/
int crypt_init_data_device(struct crypt_device **cd,
const char *device,
const char *data_device);
/**
* Initialize crypt device handle from provided active device name,
* and, optionally, from separate metadata (header) device
@@ -148,29 +131,8 @@ void crypt_set_confirm_callback(struct crypt_device *cd,
* @param cd crypt device handle
* @param device path to device
*
* @returns 0 on success or negative errno value otherwise.
*/
int crypt_set_data_device(struct crypt_device *cd, const char *device);
/**
* Set data device offset in 512-byte sectors.
* Used for LUKS.
* This function is replacement for data alignment fields in LUKS param struct.
* If set to 0 (default), old behaviour is preserved.
* This value is reset on @link crypt_load @endlink.
*
* @param cd crypt device handle
* @param data_offset data offset in bytes
*
* @returns 0 on success or negative errno value otherwise.
*
* @note Data offset must be aligned to multiple of 8 (alignment to 4096-byte sectors)
* and must be big enough to accommodate the whole LUKS header with all keyslots.
* @note Data offset is enforced by this function, device topology
* information is no longer used after calling this function.
*/
int crypt_set_data_offset(struct crypt_device *cd, uint64_t data_offset);
/** @} */
/**
@@ -189,8 +151,6 @@ int crypt_set_data_offset(struct crypt_device *cd, uint64_t data_offset);
#define CRYPT_LOG_VERBOSE 2
/** debug log level - always on stdout */
#define CRYPT_LOG_DEBUG -1
/** debug log level - additional JSON output (for LUKS2) */
#define CRYPT_LOG_DEBUG_JSON -2
/**
* Set log function.
@@ -286,16 +246,6 @@ struct crypt_pbkdf_type {
int crypt_set_pbkdf_type(struct crypt_device *cd,
const struct crypt_pbkdf_type *pbkdf);
/**
* Get PBKDF (Password-Based Key Derivation Algorithm) parameters.
*
* @param pbkdf_type type of PBKDF
*
* @return struct on success or NULL value otherwise.
*
*/
const struct crypt_pbkdf_type *crypt_get_pbkdf_type_params(const char *pbkdf_type);
/**
* Get default PBKDF (Password-Based Key Derivation Algorithm) settings for keyslots.
* Works only with LUKS device handles (both versions).
@@ -357,39 +307,6 @@ int crypt_memory_lock(struct crypt_device *cd, int lock);
* In current version locking can be only switched off and cannot be switched on later.
*/
int crypt_metadata_locking(struct crypt_device *cd, int enable);
/**
* Set metadata header area sizes. This applies only to LUKS2.
* These values limit amount of metadata anf number of supportable keyslots.
*
* @param cd crypt device handle, can be @e NULL
* @param metadata_size size in bytes of JSON area + 4k binary header
* @param keyslots_size size in bytes of binary keyslots area
*
* @returns @e 0 on success or negative errno value otherwise.
*
* @note The metadata area is stored twice and both copies contain 4k binary header.
* Only 16,32,64,128,256,512,1024,2048 and 4096 kB value is allowed (see LUKS2 specification).
* @note Keyslots area size must be multiple of 4k with maximum 128MB.
*/
int crypt_set_metadata_size(struct crypt_device *cd,
uint64_t metadata_size,
uint64_t keyslots_size);
/**
* Get metadata header area sizes. This applies only to LUKS2.
* These values limit amount of metadata anf number of supportable keyslots.
*
* @param cd crypt device handle
* @param metadata_size size in bytes of JSON area + 4k binary header
* @param keyslots_size size in bytes of binary keyslots area
*
* @returns @e 0 on success or negative errno value otherwise.
*/
int crypt_get_metadata_size(struct crypt_device *cd,
uint64_t *metadata_size,
uint64_t *keyslots_size);
/** @} */
/**
@@ -414,8 +331,6 @@ int crypt_get_metadata_size(struct crypt_device *cd,
#define CRYPT_TCRYPT "TCRYPT"
/** INTEGRITY dm-integrity device */
#define CRYPT_INTEGRITY "INTEGRITY"
/** BITLK (BitLocker-compatible mode) */
#define CRYPT_BITLK "BITLK"
/** LUKS any version */
#define CRYPT_LUKS NULL
@@ -428,13 +343,6 @@ int crypt_get_metadata_size(struct crypt_device *cd,
*/
const char *crypt_get_type(struct crypt_device *cd);
/**
* Get device default LUKS type
*
* @return string according to device type (CRYPT_LUKS1 or CRYPT_LUKS2).
*/
const char *crypt_get_default_type(void);
/**
*
* Structure used as parameter for PLAIN device type.
@@ -507,8 +415,6 @@ struct crypt_params_verity {
#define CRYPT_VERITY_CHECK_HASH (1 << 1)
/** Create hash - format hash device */
#define CRYPT_VERITY_CREATE_HASH (1 << 2)
/** Root hash signature required for activation */
#define CRYPT_VERITY_ROOT_HASH_SIGNATURE (1 << 3)
/**
*
@@ -550,15 +456,11 @@ struct crypt_params_tcrypt {
*
* @see crypt_format, crypt_load
*
* @note In bitmap tracking mode, the journal is implicitly disabled.
* As an ugly workaround for compatibility, journal_watermark is overloaded
* to mean 512-bytes sectors-per-bit and journal_commit_time means bitmap flush time.
* All other journal parameters are not applied in the bitmap mode.
*/
struct crypt_params_integrity {
uint64_t journal_size; /**< size of journal in bytes */
unsigned int journal_watermark; /**< journal flush watermark in percents; in bitmap mode sectors-per-bit */
unsigned int journal_commit_time; /**< journal commit time (or bitmap flush time) in ms */
unsigned int journal_watermark; /**< journal flush watermark in percents */
unsigned int journal_commit_time; /**< journal commit time in ms */
uint32_t interleave_sectors; /**< number of interleave sectors (power of two) */
uint32_t tag_size; /**< tag size per-sector in bytes */
uint32_t sector_size; /**< sector size in bytes */
@@ -633,30 +535,6 @@ int crypt_format(struct crypt_device *cd,
size_t volume_key_size,
void *params);
/**
* Set format compatibility flags.
*
* @param cd crypt device handle
* @param flags CRYPT_COMPATIBILITY_* flags
*/
void crypt_set_compatibility(struct crypt_device *cd, uint32_t flags);
/**
* Get compatibility flags.
*
* @param cd crypt device handle
*
* @returns compatibility flags
*/
uint32_t crypt_get_compatibility(struct crypt_device *cd);
/** dm-integrity device uses less effective (legacy) padding (old kernels) */
#define CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING (1 << 0)
/** dm-integrity device does not protect superblock with HMAC (old kernels) */
#define CRYPT_COMPAT_LEGACY_INTEGRITY_HMAC (1 << 1)
/** dm-integrity allow recalculating of volumes with HMAC keys (old kernels) */
#define CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC (1 << 2)
/**
* Convert to new type for already existing device.
*
@@ -856,20 +734,6 @@ int crypt_resume_by_keyfile(struct crypt_device *cd,
int keyslot,
const char *keyfile,
size_t keyfile_size);
/**
* Resume crypt device using provided volume key.
*
* @param cd crypt device handle
* @param name name of device to resume
* @param volume_key provided volume key
* @param volume_key_size size of volume_key
*
* @return @e 0 on success or negative errno value otherwise.
*/
int crypt_resume_by_volume_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
size_t volume_key_size);
/** @} */
/**
@@ -916,6 +780,10 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
* @param new_passphrase_size size of @e new_passphrase (binary data)
*
* @return allocated key slot number or negative errno otherwise.
*
* @note This function is just internal implementation of luksChange
* command to avoid reading of volume key outside libcryptsetup boundary
* in FIPS mode.
*/
int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
int keyslot_old,
@@ -999,9 +867,6 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
/** create keyslot with new volume key and assign it to current dm-crypt segment */
#define CRYPT_VOLUME_KEY_SET (1 << 1)
/** Assign key to first matching digest before creating new digest */
#define CRYPT_VOLUME_KEY_DIGEST_REUSE (1 << 2)
/**
* Add key slot using provided key.
*
@@ -1095,24 +960,6 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
#define CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE (1 << 15)
/** allow activation check including unbound keyslots (keyslots without segments) */
#define CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY (1 << 16)
/** dm-integrity: activate automatic recalculation */
#define CRYPT_ACTIVATE_RECALCULATE (1 << 17)
/** reactivate existing and update flags, input only */
#define CRYPT_ACTIVATE_REFRESH (1 << 18)
/** Use global lock to serialize memory hard KDF on activation (OOM workaround) */
#define CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF (1 << 19)
/** dm-integrity: direct writes, use bitmap to track dirty sectors */
#define CRYPT_ACTIVATE_NO_JOURNAL_BITMAP (1 << 20)
/** device is suspended (key should be wiped from memory), output only */
#define CRYPT_ACTIVATE_SUSPENDED (1 << 21)
/** use IV sector counted in sector_size instead of default 512 bytes sectors */
#define CRYPT_ACTIVATE_IV_LARGE_SECTORS (1 << 22)
/** dm-verity: panic_on_corruption flag - panic kernel on corruption */
#define CRYPT_ACTIVATE_PANIC_ON_CORRUPTION (1 << 23)
/** dm-crypt: bypass internal workqueue and process read requests synchronously. */
#define CRYPT_ACTIVATE_NO_READ_WORKQUEUE (1 << 24)
/** dm-crypt: bypass internal workqueue and process write requests synchronously. */
#define CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE (1 << 25)
/**
* Active device runtime attributes
@@ -1162,8 +1009,6 @@ uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd,
*/
/** Unfinished offline reencryption */
#define CRYPT_REQUIREMENT_OFFLINE_REENCRYPT (1 << 0)
/** Online reencryption in-progress */
#define CRYPT_REQUIREMENT_ONLINE_REENCRYPT (1 << 1)
/** unknown requirement in header (output only) */
#define CRYPT_REQUIREMENT_UNKNOWN (1 << 31)
@@ -1304,31 +1149,6 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
size_t volume_key_size,
uint32_t flags);
/**
* Activate VERITY device using provided key and optional signature).
*
* @param cd crypt device handle
* @param name name of device to create
* @param volume_key provided volume key
* @param volume_key_size size of volume_key
* @param signature buffer with signature for the key
* @param signature_size bsize of signature buffer
* @param flags activation flags
*
* @return @e 0 on success or negative errno value otherwise.
*
* @note For VERITY the volume key means root hash required for activation.
* Because kernel dm-verity is always read only, you have to provide
* CRYPT_ACTIVATE_READONLY flag always.
*/
int crypt_activate_by_signed_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
size_t volume_key_size,
const char *signature,
size_t signature_size,
uint32_t flags);
/**
* Activate device using passphrase stored in kernel keyring.
*
@@ -1399,7 +1219,6 @@ int crypt_deactivate(struct crypt_device *cd, const char *name);
*
* @note For TCRYPT cipher chain is the volume key concatenated
* for all ciphers in chain.
* @note For VERITY the volume key means root hash used for activation.
*/
int crypt_volume_key_get(struct crypt_device *cd,
int keyslot,
@@ -1489,25 +1308,15 @@ const char *crypt_get_cipher_mode(struct crypt_device *cd);
const char *crypt_get_uuid(struct crypt_device *cd);
/**
* Get path to underlying device.
* Get path to underlaying device.
*
* @param cd crypt device handle
*
* @return path to underlying device name
* @return path to underlaying device name
*
*/
const char *crypt_get_device_name(struct crypt_device *cd);
/**
* Get path to detached metadata device or @e NULL if it is not detached.
*
* @param cd crypt device handle
*
* @return path to underlying device name
*
*/
const char *crypt_get_metadata_device_name(struct crypt_device *cd);
/**
* Get device offset in 512-bytes sectors where real data starts (on underlying device).
*
@@ -1535,8 +1344,6 @@ uint64_t crypt_get_iv_offset(struct crypt_device *cd);
*
* @return volume key size
*
* @note For LUKS2, this function can be used only if there is at least
* one keyslot assigned to data segment.
*/
int crypt_get_volume_key_size(struct crypt_device *cd);
@@ -1721,7 +1528,7 @@ int crypt_keyslot_area(struct crypt_device *cd,
uint64_t *length);
/**
* Get size (in bytes) of stored key in particular keyslot.
* Get size (in bytes) of key for particular keyslot.
* Use for LUKS2 unbound keyslots, for other keyslots it is the same as @ref crypt_get_volume_key_size
*
* @param cd crypt device handle
@@ -1732,50 +1539,6 @@ int crypt_keyslot_area(struct crypt_device *cd,
*/
int crypt_keyslot_get_key_size(struct crypt_device *cd, int keyslot);
/**
* Get cipher and key size for keyslot encryption.
* Use for LUKS2 keyslot to set different encryption type than for data encryption.
* Parameters will be used for next keyslot operations.
*
* @param cd crypt device handle
* @param keyslot keyslot number of CRYPT_ANY_SLOT for default
* @param key_size encryption key size (in bytes)
*
* @return cipher specification on success or @e NULL.
*
* @note This is the encryption of keyslot itself, not the data encryption algorithm!
*/
const char *crypt_keyslot_get_encryption(struct crypt_device *cd, int keyslot, size_t *key_size);
/**
* Get PBKDF parameters for keyslot.
*
* @param cd crypt device handle
* @param keyslot keyslot number
* @param pbkdf struct with returned PBKDF parameters
*
* @return @e 0 on success or negative errno value otherwise.
*/
int crypt_keyslot_get_pbkdf(struct crypt_device *cd, int keyslot, struct crypt_pbkdf_type *pbkdf);
/**
* Set encryption for keyslot.
* Use for LUKS2 keyslot to set different encryption type than for data encryption.
* Parameters will be used for next keyslot operations that create or change a keyslot.
*
* @param cd crypt device handle
* @param cipher (e.g. "aes-xts-plain64")
* @param key_size encryption key size (in bytes)
*
* @return @e 0 on success or negative errno value otherwise.
*
* @note To reset to default keyslot encryption (the same as for data)
* set cipher to NULL and key size to 0.
*/
int crypt_keyslot_set_encryption(struct crypt_device *cd,
const char *cipher,
size_t key_size);
/**
* Get directory where mapped crypt devices are created
*
@@ -1828,8 +1591,6 @@ int crypt_header_restore(struct crypt_device *cd,
/** Debug all */
#define CRYPT_DEBUG_ALL -1
/** Debug all with additional JSON dump (for LUKS2) */
#define CRYPT_DEBUG_JSON -2
/** Debug none */
#define CRYPT_DEBUG_NONE 0
@@ -2187,193 +1948,6 @@ int crypt_activate_by_token(struct crypt_device *cd,
uint32_t flags);
/** @} */
/**
* @defgroup crypt-reencryption LUKS2 volume reencryption support
*
* Set of functions to handling LUKS2 volume reencryption
*
* @addtogroup crypt-reencryption
* @{
*/
/** Initialize reencryption metadata but do not run reencryption yet. (in) */
#define CRYPT_REENCRYPT_INITIALIZE_ONLY (1 << 0)
/** Move the first segment, used only with data shift. (in/out) */
#define CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT (1 << 1)
/** Resume already initialized reencryption only. (in) */
#define CRYPT_REENCRYPT_RESUME_ONLY (1 << 2)
/** Run reencryption recovery only. (in) */
#define CRYPT_REENCRYPT_RECOVERY (1 << 3)
/** Reencryption requires metadata protection. (in/out) */
#define CRYPT_REENCRYPT_REPAIR_NEEDED (1 << 4)
/**
* Reencryption direction
*/
typedef enum {
CRYPT_REENCRYPT_FORWARD = 0, /**< forward direction */
CRYPT_REENCRYPT_BACKWARD /**< backward direction */
} crypt_reencrypt_direction_info;
/**
* Reencryption mode
*/
typedef enum {
CRYPT_REENCRYPT_REENCRYPT = 0, /**< Reencryption mode */
CRYPT_REENCRYPT_ENCRYPT, /**< Encryption mode */
CRYPT_REENCRYPT_DECRYPT, /**< Decryption mode */
} crypt_reencrypt_mode_info;
/**
* LUKS2 reencryption options.
*/
struct crypt_params_reencrypt {
crypt_reencrypt_mode_info mode; /**< Reencryption mode, immutable after first init. */
crypt_reencrypt_direction_info direction; /**< Reencryption direction, immutable after first init. */
const char *resilience; /**< Resilience mode: "none", "checksum", "journal" or "shift" (only "shift" is immutable after init) */
const char *hash; /**< Used hash for "checksum" resilience type, ignored otherwise. */
uint64_t data_shift; /**< Used in "shift" mode, must be non-zero, immutable after first init. */
uint64_t max_hotzone_size; /**< Exact hotzone size for "none" mode. Maximum hotzone size for "checksum" and "journal" modes. */
uint64_t device_size; /**< Reencrypt only initial part of the data device. */
const struct crypt_params_luks2 *luks2; /**< LUKS2 parameters for the final reencryption volume.*/
uint32_t flags; /**< Reencryption flags. */
};
/**
* Initialize reencryption metadata using passphrase.
*
* This function initializes on-disk metadata to include all reencryption segments,
* according to the provided options.
* If metadata already contains ongoing reencryption metadata, it loads these parameters
* (in this situation all parameters except @e name and @e passphrase can be omitted).
*
* @param cd crypt device handle
* @param name name of active device or @e NULL for offline reencryption
* @param passphrase passphrase used to unlock volume key
* @param passphrase_size size of @e passphrase (binary data)
* @param keyslot_old keyslot to unlock existing device or CRYPT_ANY_SLOT
* @param keyslot_new existing (unbound) reencryption keyslot; must be set except for decryption
* @param cipher cipher specification (e.g. "aes")
* @param cipher_mode cipher mode and IV (e.g. "xts-plain64")
* @param params reencryption parameters @link crypt_params_reencrypt @endlink.
*
* @return reencryption key slot number or negative errno otherwise.
*/
int crypt_reencrypt_init_by_passphrase(struct crypt_device *cd,
const char *name,
const char *passphrase,
size_t passphrase_size,
int keyslot_old,
int keyslot_new,
const char *cipher,
const char *cipher_mode,
const struct crypt_params_reencrypt *params);
/**
* Initialize reencryption metadata using passphrase in keyring.
*
* This function initializes on-disk metadata to include all reencryption segments,
* according to the provided options.
* If metadata already contains ongoing reencryption metadata, it loads these parameters
* (in this situation all parameters except @e name and @e key_description can be omitted).
*
* @param cd crypt device handle
* @param name name of active device or @e NULL for offline reencryption
* @param key_description passphrase (key) identification in keyring
* @param keyslot_old keyslot to unlock existing device or CRYPT_ANY_SLOT
* @param keyslot_new existing (unbound) reencryption keyslot; must be set except for decryption
* @param cipher cipher specification (e.g. "aes")
* @param cipher_mode cipher mode and IV (e.g. "xts-plain64")
* @param params reencryption parameters @link crypt_params_reencrypt @endlink.
*
* @return reencryption key slot number or negative errno otherwise.
*/
int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
const char *name,
const char *key_description,
int keyslot_old,
int keyslot_new,
const char *cipher,
const char *cipher_mode,
const struct crypt_params_reencrypt *params);
/**
* Run data reencryption.
*
* @param cd crypt device handle
* @param progress is a callback function reporting device \b size,
* current \b offset of reencryption and provided \b usrptr identification
*
* @return @e 0 on success or negative errno value otherwise.
*/
int crypt_reencrypt(struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr));
/**
* Reencryption status info
*/
typedef enum {
CRYPT_REENCRYPT_NONE = 0, /**< No reencryption in progress */
CRYPT_REENCRYPT_CLEAN, /**< Ongoing reencryption in a clean state. */
CRYPT_REENCRYPT_CRASH, /**< Aborted reencryption that need internal recovery. */
CRYPT_REENCRYPT_INVALID /**< Invalid state. */
} crypt_reencrypt_info;
/**
* LUKS2 reencryption status.
*
* @param cd crypt device handle
* @param params reencryption parameters
*
* @return reencryption status info and parameters.
*/
crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd,
struct crypt_params_reencrypt *params);
/** @} */
/**
* @defgroup crypt-memory Safe memory helpers functions
* @addtogroup crypt-memory
* @{
*/
/**
* Allocate safe memory (content is safely wiped on deallocation).
*
* @param size size of memory in bytes
*
* @return pointer to allocated memory or @e NULL.
*/
void *crypt_safe_alloc(size_t size);
/**
* Release safe memory, content is safely wiped.
* The pointer must be allocated with @link crypt_safe_alloc @endlink
*
* @param data pointer to memory to be deallocated
*/
void crypt_safe_free(void *data);
/**
* Reallocate safe memory (content is copied and safely wiped on deallocation).
*
* @param data pointer to memory to be deallocated
* @param size new size of memory in bytes
*
* @return pointer to allocated memory or @e NULL.
*/
void *crypt_safe_realloc(void *data, size_t size);
/**
* Safe clear memory area (compile should not compile this call out).
*
* @param data pointer to memory to be cleared
* @param size size of memory in bytes
*/
void crypt_safe_memzero(void *data, size_t size);
/** @} */
#ifdef __cplusplus
}
#endif

View File

@@ -1,7 +1,6 @@
CRYPTSETUP_2.0 {
global:
crypt_init;
crypt_init_data_device;
crypt_init_by_name;
crypt_init_by_name_and_header;
@@ -12,9 +11,6 @@ CRYPTSETUP_2.0 {
crypt_set_label;
crypt_set_data_device;
crypt_set_compatibility;
crypt_get_compatibility;
crypt_memory_lock;
crypt_metadata_locking;
crypt_format;
@@ -27,7 +23,6 @@ CRYPTSETUP_2.0 {
crypt_resume_by_keyfile;
crypt_resume_by_keyfile_offset;
crypt_resume_by_keyfile_device_offset;
crypt_resume_by_volume_key;
crypt_free;
crypt_keyslot_add_by_passphrase;
@@ -59,7 +54,6 @@ CRYPTSETUP_2.0 {
crypt_activate_by_keyfile_offset;
crypt_activate_by_keyfile_device_offset;
crypt_activate_by_volume_key;
crypt_activate_by_signed_key;
crypt_activate_by_keyring;
crypt_deactivate;
crypt_deactivate_by_name;
@@ -74,19 +68,14 @@ CRYPTSETUP_2.0 {
crypt_get_cipher_mode;
crypt_get_integrity_info;
crypt_get_uuid;
crypt_set_data_offset;
crypt_get_data_offset;
crypt_get_iv_offset;
crypt_get_volume_key_size;
crypt_get_device_name;
crypt_get_metadata_device_name;
crypt_get_metadata_size;
crypt_set_metadata_size;
crypt_get_verity_info;
crypt_get_sector_size;
crypt_get_type;
crypt_get_default_type;
crypt_get_active_device;
crypt_get_active_integrity_failures;
crypt_persistent_flags_set;
@@ -96,17 +85,12 @@ CRYPTSETUP_2.0 {
crypt_get_rng_type;
crypt_set_pbkdf_type;
crypt_get_pbkdf_type;
crypt_get_pbkdf_type_params;
crypt_get_pbkdf_default;
crypt_keyslot_max;
crypt_keyslot_area;
crypt_keyslot_status;
crypt_keyslot_get_key_size;
crypt_keyslot_set_encryption;
crypt_keyslot_get_encryption;
crypt_keyslot_get_pbkdf;
crypt_get_dir;
crypt_set_debug_level;
crypt_log;
@@ -118,16 +102,6 @@ CRYPTSETUP_2.0 {
crypt_keyfile_device_read;
crypt_wipe;
crypt_reencrypt_init_by_passphrase;
crypt_reencrypt_init_by_keyring;
crypt_reencrypt;
crypt_reencrypt_status;
crypt_safe_alloc;
crypt_safe_realloc;
crypt_safe_free;
crypt_safe_memzero;
local:
*;
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2021 Milan Broz
* Copyright (C) 2011-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -81,7 +81,7 @@ static int hash_keys(struct crypt_device *cd,
const char *hash_name;
char tweak, *key_ptr;
unsigned int i;
int r = 0;
int r;
hash_name = hash_override ?: get_hash(key_len_output);
tweak = get_tweak(keys_count);
@@ -137,13 +137,13 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
unsigned int key_lengths[LOOPAES_KEYS_MAX];
unsigned int i, key_index, key_len, offset;
log_dbg(cd, "Parsing loop-AES keyfile of size %zu.", buffer_len);
log_dbg("Parsing loop-AES keyfile of size %zu.", buffer_len);
if (!buffer_len)
return -EINVAL;
if (keyfile_is_gpg(buffer, buffer_len)) {
log_err(cd, _("Detected not yet supported GPG encrypted keyfile."));
log_err(cd, _("Detected not yet supported GPG encrypted keyfile.\n"));
log_std(cd, _("Please use gpg --decrypt <KEYFILE> | cryptsetup --keyfile=- ...\n"));
return -EINVAL;
}
@@ -164,7 +164,7 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
key_lengths[key_index]++;
}
if (offset == buffer_len) {
log_dbg(cd, "Unterminated key #%d in keyfile.", key_index);
log_dbg("Unterminated key #%d in keyfile.", key_index);
log_err(cd, _("Incompatible loop-AES keyfile detected."));
return -EINVAL;
}
@@ -177,7 +177,7 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
key_len = key_lengths[0];
for (i = 0; i < key_index; i++)
if (!key_lengths[i] || (key_lengths[i] != key_len)) {
log_dbg(cd, "Unexpected length %d of key #%d (should be %d).",
log_dbg("Unexpected length %d of key #%d (should be %d).",
key_lengths[i], i, key_len);
key_len = 0;
break;
@@ -189,7 +189,7 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
return -EINVAL;
}
log_dbg(cd, "Keyfile: %d keys of length %d.", key_index, key_len);
log_dbg("Keyfile: %d keys of length %d.", key_index, key_len);
*keys_count = key_index;
return hash_keys(cd, vk, hash, keys, key_index,
@@ -203,15 +203,25 @@ int LOOPAES_activate(struct crypt_device *cd,
struct volume_key *vk,
uint32_t flags)
{
int r;
uint32_t req_flags, dmc_flags;
char *cipher = NULL;
uint32_t req_flags, dmc_flags;
int r;
struct crypt_dm_active_device dmd = {
.flags = flags,
.target = DM_CRYPT,
.size = 0,
.flags = flags,
.data_device = crypt_data_device(cd),
.u.crypt = {
.cipher = NULL,
.vk = vk,
.offset = crypt_get_data_offset(cd),
.iv_offset = crypt_get_iv_offset(cd),
.sector_size = crypt_get_sector_size(cd),
}
};
r = device_block_adjust(cd, crypt_data_device(cd), DEV_EXCL,
crypt_get_data_offset(cd), &dmd.size, &dmd.flags);
r = device_block_adjust(cd, dmd.data_device, DEV_EXCL,
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
if (r)
return r;
@@ -225,29 +235,18 @@ int LOOPAES_activate(struct crypt_device *cd,
if (r < 0)
return -ENOMEM;
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
vk, cipher, crypt_get_iv_offset(cd),
crypt_get_data_offset(cd), crypt_get_integrity(cd),
crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd));
dmd.u.crypt.cipher = cipher;
log_dbg("Trying to activate loop-AES device %s using cipher %s.",
name, dmd.u.crypt.cipher);
if (r) {
free(cipher);
return r;
}
r = dm_create_device(cd, name, CRYPT_LOOPAES, &dmd, 0);
log_dbg(cd, "Trying to activate loop-AES device %s using cipher %s.",
name, cipher);
r = dm_create_device(cd, name, CRYPT_LOOPAES, &dmd);
if (r < 0 && !dm_flags(cd, DM_CRYPT, &dmc_flags) &&
if (r < 0 && !dm_flags(DM_CRYPT, &dmc_flags) &&
(dmc_flags & req_flags) != req_flags) {
log_err(cd, _("Kernel does not support loop-AES compatible mapping."));
log_err(cd, _("Kernel doesn't support loop-AES compatible mapping."));
r = -ENOTSUP;
}
dm_targets_free(cd, &dmd);
free(cipher);
return r;
}

View File

@@ -1,8 +1,8 @@
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2021 Milan Broz
* Copyright (C) 2011-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -1,8 +1,8 @@
/*
* AFsplitter - Anti forensic information splitter
*
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefore supporting secure data destruction.
@@ -25,6 +25,7 @@
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include "internal.h"
#include "af.h"
@@ -33,7 +34,7 @@ static void XORblock(const char *src1, const char *src2, char *dst, size_t n)
{
size_t j;
for (j = 0; j < n; j++)
for(j = 0; j < n; ++j)
dst[j] = src1[j] ^ src2[j];
}
@@ -44,7 +45,7 @@ static int hash_buf(const char *src, char *dst, uint32_t iv,
char *iv_char = (char *)&iv;
int r;
iv = be32_to_cpu(iv);
iv = htonl(iv);
if (crypt_hash_init(&hd, hash_name))
return -EINVAL;
@@ -60,8 +61,7 @@ out:
return r;
}
/*
* diffuse: Information spreading over the whole dataset with
/* diffuse: Information spreading over the whole dataset with
* the help of hash function.
*/
static int diffuse(char *src, char *dst, size_t size, const char *hash_name)
@@ -101,49 +101,48 @@ static int diffuse(char *src, char *dst, size_t size, const char *hash_name)
* blocknumbers. The same blocksize and blocknumbers values
* must be supplied to AF_merge to recover information.
*/
int AF_split(struct crypt_device *ctx, const char *src, char *dst,
size_t blocksize, unsigned int blocknumbers, const char *hash)
int AF_split(const char *src, char *dst, size_t blocksize,
unsigned int blocknumbers, const char *hash)
{
unsigned int i;
char *bufblock;
int r;
bufblock = crypt_safe_alloc(blocksize);
if (!bufblock)
return -ENOMEM;
if((bufblock = calloc(blocksize, 1)) == NULL) return -ENOMEM;
/* process everything except the last block */
for (i = 0; i < blocknumbers - 1; i++) {
r = crypt_random_get(ctx, dst + blocksize * i, blocksize, CRYPT_RND_NORMAL);
for(i=0; i<blocknumbers-1; i++) {
r = crypt_random_get(NULL, dst+(blocksize*i), blocksize, CRYPT_RND_NORMAL);
if (r < 0)
goto out;
XORblock(dst + blocksize * i, bufblock, bufblock, blocksize);
XORblock(dst+(blocksize*i),bufblock,bufblock,blocksize);
r = diffuse(bufblock, bufblock, blocksize, hash);
if (r < 0)
goto out;
}
/* the last block is computed */
XORblock(src, bufblock, dst + blocksize * i, blocksize);
XORblock(src,bufblock,dst+(i*blocksize),blocksize);
r = 0;
out:
crypt_safe_free(bufblock);
free(bufblock);
return r;
}
int AF_merge(struct crypt_device *ctx __attribute__((unused)), const char *src, char *dst,
size_t blocksize, unsigned int blocknumbers, const char *hash)
int AF_merge(const char *src, char *dst, size_t blocksize,
unsigned int blocknumbers, const char *hash)
{
unsigned int i;
char *bufblock;
int r;
bufblock = crypt_safe_alloc(blocksize);
if (!bufblock)
if((bufblock = calloc(blocksize, 1)) == NULL)
return -ENOMEM;
for(i = 0; i < blocknumbers - 1; i++) {
XORblock(src + blocksize * i, bufblock, bufblock, blocksize);
memset(bufblock,0,blocksize);
for(i=0; i<blocknumbers-1; i++) {
XORblock(src+(blocksize*i),bufblock,bufblock,blocksize);
r = diffuse(bufblock, bufblock, blocksize, hash);
if (r < 0)
goto out;
@@ -151,7 +150,7 @@ int AF_merge(struct crypt_device *ctx __attribute__((unused)), const char *src,
XORblock(src + blocksize * i, bufblock, dst, blocksize);
r = 0;
out:
crypt_safe_free(bufblock);
free(bufblock);
return r;
}

View File

@@ -1,8 +1,8 @@
/*
* AFsplitter - Anti forensic information splitter
*
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefore supporting secure data destruction.
@@ -39,10 +39,8 @@
* On error, both functions return -1, 0 otherwise.
*/
int AF_split(struct crypt_device *ctx, const char *src, char *dst,
size_t blocksize, unsigned int blocknumbers, const char *hash);
int AF_merge(struct crypt_device *ctx, const char *src, char *dst, size_t blocksize,
unsigned int blocknumbers, const char *hash);
int AF_split(const char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash);
int AF_merge(const char *src, char *dst, size_t blocksize, unsigned int blocknumbers, const char *hash);
size_t AF_split_sectors(size_t blocksize, unsigned int blocknumbers);
int LUKS_encrypt_to_storage(

View File

@@ -1,9 +1,9 @@
/*
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2018, Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include "luks.h"
@@ -57,15 +58,25 @@ static int LUKS_endec_template(char *src, size_t srcLength,
char name[PATH_MAX], path[PATH_MAX];
char cipher_spec[MAX_CIPHER_LEN * 3];
struct crypt_dm_active_device dmd = {
.flags = CRYPT_ACTIVATE_PRIVATE,
.target = DM_CRYPT,
.uuid = NULL,
.flags = CRYPT_ACTIVATE_PRIVATE,
.data_device = crypt_metadata_device(ctx),
.u.crypt = {
.cipher = cipher_spec,
.vk = vk,
.offset = sector,
.iv_offset = 0,
.sector_size = SECTOR_SIZE,
}
};
int r, devfd = -1, remove_dev = 0;
int r, devfd = -1;
size_t bsize, keyslot_alignment, alignment;
log_dbg(ctx, "Using dmcrypt to access keyslot area.");
log_dbg("Using dmcrypt to access keyslot area.");
bsize = device_block_size(ctx, crypt_metadata_device(ctx));
alignment = device_alignment(crypt_metadata_device(ctx));
bsize = device_block_size(dmd.data_device);
alignment = device_alignment(dmd.data_device);
if (!bsize || !alignment)
return -EINVAL;
@@ -85,35 +96,27 @@ static int LUKS_endec_template(char *src, size_t srcLength,
if (snprintf(cipher_spec, sizeof(cipher_spec), "%s-%s", cipher, cipher_mode) < 0)
return -ENOMEM;
r = device_block_adjust(ctx, crypt_metadata_device(ctx), DEV_OK,
sector, &dmd.size, &dmd.flags);
r = device_block_adjust(ctx, dmd.data_device, DEV_OK,
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
if (r < 0) {
log_err(ctx, _("Device %s does not exist or access denied."),
device_path(crypt_metadata_device(ctx)));
log_err(ctx, _("Device %s doesn't exist or access denied."),
device_path(dmd.data_device));
return -EIO;
}
if (mode != O_RDONLY && dmd.flags & CRYPT_ACTIVATE_READONLY) {
log_err(ctx, _("Cannot write to device %s, permission denied."),
device_path(crypt_metadata_device(ctx)));
device_path(dmd.data_device));
return -EACCES;
}
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size,
crypt_metadata_device(ctx), vk, cipher_spec, 0, sector,
NULL, 0, SECTOR_SIZE);
if (r)
goto out;
r = dm_create_device(ctx, name, "TEMP", &dmd);
r = dm_create_device(ctx, name, "TEMP", &dmd, 0);
if (r < 0) {
if (r != -EACCES && r != -ENOTSUP)
_error_hint(ctx, device_path(crypt_metadata_device(ctx)),
_error_hint(ctx, device_path(dmd.data_device),
cipher, cipher_mode, vk->keylength * 8);
r = -EIO;
goto out;
return -EIO;
}
remove_dev = 1;
devfd = open(path, mode | O_DIRECT | O_SYNC);
if (devfd == -1) {
@@ -129,11 +132,9 @@ static int LUKS_endec_template(char *src, size_t srcLength,
} else
r = 0;
out:
dm_targets_free(ctx, &dmd);
if (devfd != -1)
close(devfd);
if (remove_dev)
dm_remove_device(ctx, name, CRYPT_DEACTIVATE_FORCE);
dm_remove_device(ctx, name, CRYPT_DEACTIVATE_FORCE);
return r;
}
@@ -144,19 +145,20 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
unsigned int sector,
struct crypt_device *ctx)
{
struct device *device = crypt_metadata_device(ctx);
struct crypt_storage *s;
int devfd, r = 0;
int devfd = -1, r = 0;
/* Only whole sector writes supported */
if (MISALIGNED_512(srcLength))
return -EINVAL;
/* Encrypt buffer */
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
if (r)
log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
log_dbg("Userspace crypto wrapper cannot use %s-%s (%d).",
cipher, cipher_mode, r);
/* Fallback to old temporary dmcrypt device */
@@ -170,9 +172,9 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
return r;
}
log_dbg(ctx, "Using userspace crypto wrapper to access keyslot area.");
log_dbg("Using userspace crypto wrapper to access keyslot area.");
r = crypt_storage_encrypt(s, 0, srcLength, src);
r = crypt_storage_encrypt(s, 0, srcLength / SECTOR_SIZE, src);
crypt_storage_destroy(s);
if (r)
@@ -181,21 +183,21 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
r = -EIO;
/* Write buffer to device */
if (device_is_locked(device))
devfd = device_open_locked(ctx, device, O_RDWR);
else
devfd = device_open(ctx, device, O_RDWR);
devfd = device_open(device, O_RDWR);
if (devfd < 0)
goto out;
if (write_lseek_blockwise(devfd, device_block_size(ctx, device),
if (write_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), src, srcLength,
sector * SECTOR_SIZE) < 0)
goto out;
r = 0;
out:
device_sync(ctx, device);
if (devfd >= 0) {
device_sync(device, devfd);
close(devfd);
}
if (r)
log_err(ctx, _("IO error while encrypting keyslot."));
@@ -212,16 +214,16 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
struct device *device = crypt_metadata_device(ctx);
struct crypt_storage *s;
struct stat st;
int devfd, r = 0;
int devfd = -1, r = 0;
/* Only whole sector reads supported */
if (MISALIGNED_512(dstLength))
return -EINVAL;
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
if (r)
log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
log_dbg("Userspace crypto wrapper cannot use %s-%s (%d).",
cipher, cipher_mode, r);
/* Fallback to old temporary dmcrypt device */
@@ -235,20 +237,17 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
return r;
}
log_dbg(ctx, "Using userspace crypto wrapper to access keyslot area.");
log_dbg("Using userspace crypto wrapper to access keyslot area.");
/* Read buffer from device */
if (device_is_locked(device))
devfd = device_open_locked(ctx, device, O_RDONLY);
else
devfd = device_open(ctx, device, O_RDONLY);
devfd = device_open(device, O_RDONLY);
if (devfd < 0) {
log_err(ctx, _("Cannot open device %s."), device_path(device));
crypt_storage_destroy(s);
return -EIO;
}
if (read_lseek_blockwise(devfd, device_block_size(ctx, device),
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), dst, dstLength,
sector * SECTOR_SIZE) < 0) {
if (!fstat(devfd, &st) && (st.st_size < (off_t)dstLength))
@@ -256,12 +255,15 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
else
log_err(ctx, _("IO error while decrypting keyslot."));
close(devfd);
crypt_storage_destroy(s);
return -EIO;
}
close(devfd);
/* Decrypt buffer */
r = crypt_storage_decrypt(s, 0, dstLength, dst);
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
crypt_storage_destroy(s);
return r;

View File

@@ -1,9 +1,9 @@
/*
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2021 Milan Broz
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2018, Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -23,6 +23,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
@@ -36,6 +37,23 @@
#include "af.h"
#include "internal.h"
/* Get size of struct luks_phdr with all keyslots material space */
static size_t LUKS_calculate_device_sectors(size_t keyLen)
{
size_t keyslot_sectors, sector;
int i;
keyslot_sectors = AF_split_sectors(keyLen, LUKS_STRIPES);
sector = LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE;
for (i = 0; i < LUKS_NUMKEYS; i++) {
sector = size_round_up(sector, LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
sector += keyslot_sectors;
}
return sector;
}
int LUKS_keyslot_area(const struct luks_phdr *hdr,
int keyslot,
uint64_t *offset,
@@ -93,13 +111,13 @@ static int LUKS_check_device_size(struct crypt_device *ctx, const struct luks_ph
return -EINVAL;
if (device_size(device, &dev_sectors)) {
log_dbg(ctx, "Cannot get device size for device %s.", device_path(device));
log_dbg("Cannot get device size for device %s.", device_path(device));
return -EIO;
}
dev_sectors >>= SECTOR_SHIFT;
hdr_sectors = LUKS_device_sectors(hdr);
log_dbg(ctx, "Key length %u, device size %" PRIu64 " sectors, header size %"
log_dbg("Key length %u, device size %" PRIu64 " sectors, header size %"
PRIu64 " sectors.", hdr->keyBytes, dev_sectors, hdr_sectors);
if (hdr_sectors > dev_sectors) {
@@ -126,7 +144,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
for (i = 0; i < LUKS_NUMKEYS; i++) {
/* enforce stripes == 4000 */
if (phdr->keyblock[i].stripes != LUKS_STRIPES) {
log_dbg(ctx, "Invalid stripes count %u in keyslot %u.",
log_dbg("Invalid stripes count %u in keyslot %u.",
phdr->keyblock[i].stripes, i);
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
return -1;
@@ -134,7 +152,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
/* First sectors is the header itself */
if (phdr->keyblock[i].keyMaterialOffset * SECTOR_SIZE < sizeof(*phdr)) {
log_dbg(ctx, "Invalid offset %u in keyslot %u.",
log_dbg("Invalid offset %u in keyslot %u.",
phdr->keyblock[i].keyMaterialOffset, i);
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
return -1;
@@ -145,7 +163,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
continue;
if (phdr->payloadOffset <= phdr->keyblock[i].keyMaterialOffset) {
log_dbg(ctx, "Invalid offset %u in keyslot %u (beyond data area offset %u).",
log_dbg("Invalid offset %u in keyslot %u (beyond data area offset %u).",
phdr->keyblock[i].keyMaterialOffset, i,
phdr->payloadOffset);
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
@@ -153,7 +171,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
}
if (phdr->payloadOffset < (phdr->keyblock[i].keyMaterialOffset + secs_per_stripes)) {
log_dbg(ctx, "Invalid keyslot size %u (offset %u, stripes %u) in "
log_dbg("Invalid keyslot size %u (offset %u, stripes %u) in "
"keyslot %u (beyond data area offset %u).",
secs_per_stripes,
phdr->keyblock[i].keyMaterialOffset,
@@ -170,7 +188,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
next = sorted_areas[i];
if (phdr->keyblock[next].keyMaterialOffset <
(phdr->keyblock[prev].keyMaterialOffset + secs_per_stripes)) {
log_dbg(ctx, "Not enough space in LUKS keyslot %d.", prev);
log_dbg("Not enough space in LUKS keyslot %d.", prev);
log_err(ctx, _("LUKS keyslot %u is invalid."), prev);
return -1;
}
@@ -199,10 +217,9 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
{
struct device *device = crypt_metadata_device(ctx);
struct luks_phdr hdr;
int fd, devfd, r = 0;
int r = 0, devfd = -1;
size_t hdr_size;
size_t buffer_size;
ssize_t ret;
char *buffer = NULL;
r = LUKS_read_phdr(&hdr, 1, 0, ctx);
@@ -218,30 +235,31 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
goto out;
}
log_dbg(ctx, "Storing backup of header (%zu bytes) and keyslot area (%zu bytes).",
log_dbg("Storing backup of header (%zu bytes) and keyslot area (%zu bytes).",
sizeof(hdr), hdr_size - LUKS_ALIGN_KEYSLOTS);
log_dbg(ctx, "Output backup file size: %zu bytes.", buffer_size);
log_dbg("Output backup file size: %zu bytes.", buffer_size);
devfd = device_open(ctx, device, O_RDONLY);
devfd = device_open(device, O_RDONLY);
if (devfd < 0) {
log_err(ctx, _("Device %s is not a valid LUKS device."), device_path(device));
r = -EINVAL;
goto out;
}
if (read_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
buffer, hdr_size, 0) < (ssize_t)hdr_size) {
if (read_blockwise(devfd, device_block_size(device), device_alignment(device),
buffer, hdr_size) < (ssize_t)hdr_size) {
r = -EIO;
goto out;
}
close(devfd);
/* Wipe unused area, so backup cannot contain old signatures */
if (hdr.keyblock[0].keyMaterialOffset * SECTOR_SIZE == LUKS_ALIGN_KEYSLOTS)
memset(buffer + sizeof(hdr), 0, LUKS_ALIGN_KEYSLOTS - sizeof(hdr));
fd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
if (fd == -1) {
devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
if (devfd == -1) {
if (errno == EEXIST)
log_err(ctx, _("Requested header backup file %s already exists."), backup_file);
else
@@ -249,9 +267,7 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
r = -EINVAL;
goto out;
}
ret = write_buffer(fd, buffer, buffer_size);
close(fd);
if (ret < (ssize_t)buffer_size) {
if (write_buffer(devfd, buffer, buffer_size) < (ssize_t)buffer_size) {
log_err(ctx, _("Cannot write header backup file %s."), backup_file);
r = -EIO;
goto out;
@@ -259,7 +275,9 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
r = 0;
out:
crypt_safe_memzero(&hdr, sizeof(hdr));
if (devfd >= 0)
close(devfd);
crypt_memzero(&hdr, sizeof(hdr));
crypt_safe_free(buffer);
return r;
}
@@ -270,8 +288,8 @@ int LUKS_hdr_restore(
struct crypt_device *ctx)
{
struct device *device = crypt_metadata_device(ctx);
int fd, r = 0, devfd = -1, diff_uuid = 0;
ssize_t ret, buffer_size = 0;
int r = 0, devfd = -1, diff_uuid = 0;
ssize_t buffer_size = 0;
char *buffer = NULL, msg[200];
struct luks_phdr hdr_file;
@@ -283,7 +301,7 @@ int LUKS_hdr_restore(
buffer_size = LUKS_device_sectors(&hdr_file) << SECTOR_SHIFT;
if (r || buffer_size < LUKS_ALIGN_KEYSLOTS) {
log_err(ctx, _("Backup file does not contain valid LUKS header."));
log_err(ctx, _("Backup file doesn't contain valid LUKS header."));
r = -EINVAL;
goto out;
}
@@ -294,24 +312,24 @@ int LUKS_hdr_restore(
goto out;
}
fd = open(backup_file, O_RDONLY);
if (fd == -1) {
devfd = open(backup_file, O_RDONLY);
if (devfd == -1) {
log_err(ctx, _("Cannot open header backup file %s."), backup_file);
r = -EINVAL;
goto out;
}
ret = read_buffer(fd, buffer, buffer_size);
close(fd);
if (ret < buffer_size) {
if (read_buffer(devfd, buffer, buffer_size) < buffer_size) {
log_err(ctx, _("Cannot read header backup file %s."), backup_file);
r = -EIO;
goto out;
}
close(devfd);
devfd = -1;
r = LUKS_read_phdr(hdr, 0, 0, ctx);
if (r == 0) {
log_dbg(ctx, "Device %s already contains LUKS header, checking UUID and offset.", device_path(device));
log_dbg("Device %s already contains LUKS header, checking UUID and offset.", device_path(device));
if(hdr->payloadOffset != hdr_file.payloadOffset ||
hdr->keyBytes != hdr_file.keyBytes) {
log_err(ctx, _("Data offset or key size differs on device and backup, restore failed."));
@@ -335,10 +353,10 @@ int LUKS_hdr_restore(
goto out;
}
log_dbg(ctx, "Storing backup of header (%zu bytes) and keyslot area (%zu bytes) to device %s.",
log_dbg("Storing backup of header (%zu bytes) and keyslot area (%zu bytes) to device %s.",
sizeof(*hdr), buffer_size - LUKS_ALIGN_KEYSLOTS, device_path(device));
devfd = device_open(ctx, device, O_RDWR);
devfd = device_open(device, O_RDWR);
if (devfd < 0) {
if (errno == EACCES)
log_err(ctx, _("Cannot write to device %s, permission denied."),
@@ -349,16 +367,21 @@ int LUKS_hdr_restore(
goto out;
}
if (write_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
buffer, buffer_size, 0) < buffer_size) {
if (write_blockwise(devfd, device_block_size(device), device_alignment(device),
buffer, buffer_size) < buffer_size) {
r = -EIO;
goto out;
}
close(devfd);
devfd = -1;
/* Be sure to reload new data */
r = LUKS_read_phdr(hdr, 1, 0, ctx);
out:
device_sync(ctx, device);
if (devfd >= 0) {
device_sync(device, devfd);
close(devfd);
}
crypt_safe_free(buffer);
return r;
}
@@ -375,13 +398,8 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
log_err(ctx, _("Non standard key size, manual repair required."));
return -EINVAL;
}
/*
* cryptsetup 1.0 did not align keyslots to 4k, cannot repair this one
* Also we cannot trust possibly broken keyslots metadata here through LUKS_keyslots_offset().
* Expect first keyslot is aligned, if not, then manual repair is neccessary.
*/
if (phdr->keyblock[0].keyMaterialOffset < (LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE)) {
/* cryptsetup 1.0 did not align to 4k, cannot repair this one */
if (LUKS_keyslots_offset(phdr) < (LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE)) {
log_err(ctx, _("Non standard keyslots alignment, manual repair required."));
return -EINVAL;
}
@@ -391,23 +409,22 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
return -EINVAL;
vk = crypt_alloc_volume_key(phdr->keyBytes, NULL);
if (!vk)
return -ENOMEM;
log_verbose(ctx, _("Repairing keyslots."));
log_dbg(ctx, "Generating second header with the same parameters for check.");
log_dbg("Generating second header with the same parameters for check.");
/* cipherName, cipherMode, hashSpec, uuid are already null terminated */
/* payloadOffset - cannot check */
r = LUKS_generate_phdr(&temp_phdr, vk, phdr->cipherName, phdr->cipherMode,
phdr->hashSpec, phdr->uuid,
phdr->payloadOffset * SECTOR_SIZE, 0, 0, ctx);
phdr->hashSpec,phdr->uuid, LUKS_STRIPES,
phdr->payloadOffset, 0,
1, ctx);
if (r < 0)
goto out;
for(i = 0; i < LUKS_NUMKEYS; ++i) {
if (phdr->keyblock[i].active == LUKS_KEY_ENABLED) {
log_dbg(ctx, "Skipping repair for active keyslot %i.", i);
log_dbg("Skipping repair for active keyslot %i.", i);
continue;
}
@@ -459,7 +476,7 @@ out:
if (r)
log_err(ctx, _("Repair failed."));
crypt_free_volume_key(vk);
crypt_safe_memzero(&temp_phdr, sizeof(temp_phdr));
crypt_memzero(&temp_phdr, sizeof(temp_phdr));
return r;
}
@@ -474,7 +491,7 @@ static int _check_and_convert_hdr(const char *device,
char luksMagic[] = LUKS_MAGIC;
if(memcmp(hdr->magic, luksMagic, LUKS_MAGIC_L)) { /* Check magic */
log_dbg(ctx, "LUKS header not detected.");
log_dbg("LUKS header not detected.");
if (require_luks_device)
log_err(ctx, _("Device %s is not a valid LUKS device."), device);
return -EINVAL;
@@ -548,7 +565,7 @@ int LUKS_read_phdr_backup(const char *backup_file,
ssize_t hdr_size = sizeof(struct luks_phdr);
int devfd = 0, r = 0;
log_dbg(ctx, "Reading LUKS header of size %d from backup file %s",
log_dbg("Reading LUKS header of size %d from backup file %s",
(int)hdr_size, backup_file);
devfd = open(backup_file, O_RDONLY);
@@ -574,9 +591,9 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
int repair,
struct crypt_device *ctx)
{
int devfd, r = 0;
struct device *device = crypt_metadata_device(ctx);
ssize_t hdr_size = sizeof(struct luks_phdr);
int devfd = 0, r = 0;
/* LUKS header starts at offset 0, first keyslot on LUKS_ALIGN_KEYSLOTS */
assert(sizeof(struct luks_phdr) <= LUKS_ALIGN_KEYSLOTS);
@@ -587,17 +604,17 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
if (repair && !require_luks_device)
return -EINVAL;
log_dbg(ctx, "Reading LUKS header of size %zu from device %s",
log_dbg("Reading LUKS header of size %zu from device %s",
hdr_size, device_path(device));
devfd = device_open(ctx, device, O_RDONLY);
devfd = device_open(device, O_RDONLY);
if (devfd < 0) {
log_err(ctx, _("Cannot open device %s."), device_path(device));
return -EINVAL;
}
if (read_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
hdr, hdr_size, 0) < hdr_size)
if (read_blockwise(devfd, device_block_size(device), device_alignment(device),
hdr, hdr_size) < hdr_size)
r = -EIO;
else
r = _check_and_convert_hdr(device_path(device), hdr, require_luks_device,
@@ -612,10 +629,11 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
* has bigger sector size.
*/
if (!r && hdr->keyblock[0].keyMaterialOffset * SECTOR_SIZE < LUKS_ALIGN_KEYSLOTS) {
log_dbg(ctx, "Old unaligned LUKS keyslot detected, disabling direct-io.");
log_dbg("Old unaligned LUKS keyslot detected, disabling direct-io.");
device_disable_direct_io(device);
}
close(devfd);
return r;
}
@@ -629,14 +647,14 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
struct luks_phdr convHdr;
int r;
log_dbg(ctx, "Updating LUKS header of size %zu on device %s",
log_dbg("Updating LUKS header of size %zu on device %s",
sizeof(struct luks_phdr), device_path(device));
r = LUKS_check_device_size(ctx, hdr, 1);
if (r)
return r;
devfd = device_open(ctx, device, O_RDWR);
devfd = device_open(device, O_RDWR);
if (devfd < 0) {
if (errno == EACCES)
log_err(ctx, _("Cannot write to device %s, permission denied."),
@@ -661,12 +679,13 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
convHdr.keyblock[i].stripes = htonl(hdr->keyblock[i].stripes);
}
r = write_lseek_blockwise(devfd, device_block_size(ctx, device), device_alignment(device),
&convHdr, hdr_size, 0) < hdr_size ? -EIO : 0;
r = write_blockwise(devfd, device_block_size(device), device_alignment(device),
&convHdr, hdr_size) < hdr_size ? -EIO : 0;
if (r)
log_err(ctx, _("Error during update of LUKS header on device %s."), device_path(device));
device_sync(ctx, device);
device_sync(device, devfd);
close(devfd);
/* Re-read header from disk to be sure that in-memory and on-disk data are the same. */
if (!r) {
@@ -686,7 +705,7 @@ int LUKS_check_cipher(struct crypt_device *ctx, size_t keylength, const char *ci
struct volume_key *empty_key;
char buf[SECTOR_SIZE];
log_dbg(ctx, "Checking if cipher %s-%s is usable.", cipher, cipher_mode);
log_dbg("Checking if cipher %s-%s is usable.", cipher, cipher_mode);
empty_key = crypt_alloc_volume_key(keylength, NULL);
if (!empty_key)
@@ -698,58 +717,35 @@ int LUKS_check_cipher(struct crypt_device *ctx, size_t keylength, const char *ci
r = LUKS_decrypt_from_storage(buf, sizeof(buf), cipher, cipher_mode, empty_key, 0, ctx);
crypt_free_volume_key(empty_key);
crypt_safe_memzero(buf, sizeof(buf));
crypt_memzero(buf, sizeof(buf));
return r;
}
int LUKS_generate_phdr(struct luks_phdr *header,
const struct volume_key *vk,
const char *cipherName,
const char *cipherMode,
const char *hashSpec,
const char *uuid,
uint64_t data_offset, /* in bytes */
uint64_t align_offset, /* in bytes */
uint64_t required_alignment, /* in bytes */
struct crypt_device *ctx)
const struct volume_key *vk,
const char *cipherName, const char *cipherMode, const char *hashSpec,
const char *uuid, unsigned int stripes,
unsigned int alignPayload,
unsigned int alignOffset,
int detached_metadata_device,
struct crypt_device *ctx)
{
int i, r;
size_t keyslot_sectors, header_sectors;
unsigned int i = 0, hdr_sectors = LUKS_calculate_device_sectors(vk->keylength);
size_t blocksPerStripeSet, currentSector;
int r;
uuid_t partitionUuid;
struct crypt_pbkdf_type *pbkdf;
double PBKDF2_temp;
char luksMagic[] = LUKS_MAGIC;
if (data_offset % SECTOR_SIZE || align_offset % SECTOR_SIZE ||
required_alignment % SECTOR_SIZE)
return -EINVAL;
/* For separate metadata device allow zero alignment */
if (alignPayload == 0 && !detached_metadata_device)
alignPayload = DEFAULT_DISK_ALIGNMENT / SECTOR_SIZE;
memset(header, 0, sizeof(struct luks_phdr));
keyslot_sectors = AF_split_sectors(vk->keylength, LUKS_STRIPES);
header_sectors = LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE;
for (i = 0; i < LUKS_NUMKEYS; i++) {
header->keyblock[i].active = LUKS_KEY_DISABLED;
header->keyblock[i].keyMaterialOffset = header_sectors;
header->keyblock[i].stripes = LUKS_STRIPES;
header_sectors = size_round_up(header_sectors + keyslot_sectors,
LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
}
/* In sector is now size of all keyslot material space */
/* Data offset has priority */
if (data_offset)
header->payloadOffset = data_offset / SECTOR_SIZE;
else if (required_alignment) {
header->payloadOffset = size_round_up(header_sectors, (required_alignment / SECTOR_SIZE));
header->payloadOffset += (align_offset / SECTOR_SIZE);
} else
header->payloadOffset = 0;
if (header->payloadOffset && header->payloadOffset < header_sectors) {
log_err(ctx, _("Data offset for LUKS header must be "
"either 0 or higher than header size."));
if (alignPayload && detached_metadata_device && alignPayload < hdr_sectors) {
log_err(ctx, _("Data offset for detached LUKS header must be "
"either 0 or higher than header size (%d sectors)."),
hdr_sectors);
return -EINVAL;
}
@@ -765,6 +761,8 @@ int LUKS_generate_phdr(struct luks_phdr *header,
if (!uuid)
uuid_generate(partitionUuid);
memset(header,0,sizeof(struct luks_phdr));
/* Set Magic */
memcpy(header->magic,luksMagic,LUKS_MAGIC_L);
header->version=1;
@@ -776,7 +774,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
LUKS_fix_header_compatible(header);
log_dbg(ctx, "Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes",
log_dbg("Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes",
header->version, header->hashSpec ,header->cipherName, header->cipherMode,
header->keyBytes);
@@ -793,29 +791,43 @@ int LUKS_generate_phdr(struct luks_phdr *header,
return r;
assert(pbkdf->iterations);
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK && pbkdf->time_ms == 0)
PBKDF2_temp = LUKS_MKD_ITERATIONS_MIN;
else /* iterations per ms * LUKS_MKD_ITERATIONS_MS */
PBKDF2_temp = (double)pbkdf->iterations * LUKS_MKD_ITERATIONS_MS / pbkdf->time_ms;
PBKDF2_temp = (double)pbkdf->iterations * LUKS_MKD_ITERATIONS_MS / pbkdf->time_ms;
if (PBKDF2_temp > (double)UINT32_MAX)
return -EINVAL;
header->mkDigestIterations = at_least((uint32_t)PBKDF2_temp, LUKS_MKD_ITERATIONS_MIN);
assert(header->mkDigestIterations);
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, header->hashSpec, vk->key,vk->keylength,
header->mkDigestSalt, LUKS_SALTSIZE,
header->mkDigest,LUKS_DIGESTSIZE,
header->mkDigestIterations, 0, 0);
if (r < 0) {
if(r < 0) {
log_err(ctx, _("Cannot create LUKS header: header digest failed (using hash %s)."),
header->hashSpec);
return r;
}
currentSector = LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE;
blocksPerStripeSet = AF_split_sectors(vk->keylength, stripes);
for(i = 0; i < LUKS_NUMKEYS; ++i) {
header->keyblock[i].active = LUKS_KEY_DISABLED;
header->keyblock[i].keyMaterialOffset = currentSector;
header->keyblock[i].stripes = stripes;
currentSector = size_round_up(currentSector + blocksPerStripeSet,
LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE);
}
if (detached_metadata_device) {
/* for separate metadata device use alignPayload directly */
header->payloadOffset = alignPayload;
} else {
/* alignOffset - offset from natural device alignment provided by topology info */
currentSector = size_round_up(currentSector, alignPayload);
header->payloadOffset = currentSector + alignOffset;
}
uuid_unparse(partitionUuid, header->uuid);
log_dbg(ctx, "Data offset %d, UUID %s, digest iterations %" PRIu32,
log_dbg("Data offset %d, UUID %s, digest iterations %" PRIu32,
header->payloadOffset, header->uuid, header->mkDigestIterations);
return 0;
@@ -863,7 +875,7 @@ int LUKS_set_key(unsigned int keyIndex,
return -EINVAL;
}
log_dbg(ctx, "Calculating data for key slot %d", keyIndex);
log_dbg("Calculating data for key slot %d", keyIndex);
pbkdf = crypt_get_pbkdf(ctx);
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, vk->keylength);
if (r < 0)
@@ -875,7 +887,7 @@ int LUKS_set_key(unsigned int keyIndex,
*/
hdr->keyblock[keyIndex].passwordIterations =
at_least(pbkdf->iterations, LUKS_SLOT_ITERATIONS_MIN);
log_dbg(ctx, "Key slot %d use %" PRIu32 " password iterations.", keyIndex,
log_dbg("Key slot %d use %" PRIu32 " password iterations.", keyIndex,
hdr->keyblock[keyIndex].passwordIterations);
derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
@@ -905,13 +917,13 @@ int LUKS_set_key(unsigned int keyIndex,
goto out;
}
log_dbg(ctx, "Using hash %s for AF in key slot %d, %d stripes",
log_dbg("Using hash %s for AF in key slot %d, %d stripes",
hdr->hashSpec, keyIndex, hdr->keyblock[keyIndex].stripes);
r = AF_split(ctx, vk->key, AfKey, vk->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
r = AF_split(vk->key,AfKey,vk->keylength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec);
if (r < 0)
goto out;
log_dbg(ctx, "Updating key slot %d [0x%04x] area.", keyIndex,
log_dbg("Updating key slot %d [0x%04x] area.", keyIndex,
hdr->keyblock[keyIndex].keyMaterialOffset << 9);
/* Encryption via dm */
r = LUKS_encrypt_to_storage(AfKey,
@@ -924,7 +936,7 @@ int LUKS_set_key(unsigned int keyIndex,
goto out;
/* Mark the key as active in phdr */
r = LUKS_keyslot_set(hdr, (int)keyIndex, 1, ctx);
r = LUKS_keyslot_set(hdr, (int)keyIndex, 1);
if (r < 0)
goto out;
@@ -962,16 +974,16 @@ static int LUKS_open_key(unsigned int keyIndex,
const char *password,
size_t passwordLen,
struct luks_phdr *hdr,
struct volume_key **vk,
struct volume_key *vk,
struct crypt_device *ctx)
{
crypt_keyslot_info ki = LUKS_keyslot_info(hdr, keyIndex);
struct volume_key *derived_key;
char *AfKey = NULL;
char *AfKey;
size_t AFEKSize;
int r;
log_dbg(ctx, "Trying to open key slot %d [%s].", keyIndex,
log_dbg("Trying to open key slot %d [%s].", keyIndex,
dbg_slot_state(ki));
if (ki < CRYPT_SLOT_ACTIVE)
@@ -981,13 +993,8 @@ static int LUKS_open_key(unsigned int keyIndex,
if (!derived_key)
return -ENOMEM;
*vk = crypt_alloc_volume_key(hdr->keyBytes, NULL);
if (!*vk) {
r = -ENOMEM;
goto out;
}
AFEKSize = AF_split_sectors(hdr->keyBytes, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
assert(vk->keylength == hdr->keyBytes);
AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
AfKey = crypt_safe_alloc(AFEKSize);
if (!AfKey) {
r = -ENOMEM;
@@ -998,12 +1005,10 @@ static int LUKS_open_key(unsigned int keyIndex,
hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
derived_key->key, hdr->keyBytes,
hdr->keyblock[keyIndex].passwordIterations, 0, 0);
if (r < 0) {
log_err(ctx, _("Cannot open keyslot (using hash %s)."), hdr->hashSpec);
if (r < 0)
goto out;
}
log_dbg(ctx, "Reading key slot %d area.", keyIndex);
log_dbg("Reading key slot %d area.", keyIndex);
r = LUKS_decrypt_from_storage(AfKey,
AFEKSize,
hdr->cipherName, hdr->cipherMode,
@@ -1013,20 +1018,16 @@ static int LUKS_open_key(unsigned int keyIndex,
if (r < 0)
goto out;
r = AF_merge(ctx, AfKey, (*vk)->key, (*vk)->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
r = AF_merge(AfKey,vk->key,vk->keylength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec);
if (r < 0)
goto out;
r = LUKS_verify_volume_key(hdr, *vk);
r = LUKS_verify_volume_key(hdr, vk);
/* Allow only empty passphrase with null cipher */
if (!r && crypt_is_cipher_null(hdr->cipherName) && passwordLen)
if (!r && !strcmp(hdr->cipherName, "cipher_null") && passwordLen)
r = -EPERM;
out:
if (r < 0) {
crypt_free_volume_key(*vk);
*vk = NULL;
}
crypt_safe_free(AfKey);
crypt_free_volume_key(derived_key);
return r;
@@ -1039,28 +1040,28 @@ int LUKS_open_key_with_hdr(int keyIndex,
struct volume_key **vk,
struct crypt_device *ctx)
{
unsigned int i, tried = 0;
unsigned int i;
int r;
*vk = crypt_alloc_volume_key(hdr->keyBytes, NULL);
if (keyIndex >= 0) {
r = LUKS_open_key(keyIndex, password, passwordLen, hdr, vk, ctx);
r = LUKS_open_key(keyIndex, password, passwordLen, hdr, *vk, ctx);
return (r < 0) ? r : keyIndex;
}
for (i = 0; i < LUKS_NUMKEYS; i++) {
r = LUKS_open_key(i, password, passwordLen, hdr, vk, ctx);
if (r == 0)
for(i = 0; i < LUKS_NUMKEYS; i++) {
r = LUKS_open_key(i, password, passwordLen, hdr, *vk, ctx);
if(r == 0)
return i;
/* Do not retry for errors that are no -EPERM or -ENOENT,
former meaning password wrong, latter key slot inactive */
if ((r != -EPERM) && (r != -ENOENT))
return r;
if (r == -EPERM)
tried++;
}
/* Warning, early returns above */
return tried ? -EPERM : -ENOENT;
return -EPERM;
}
int LUKS_del_key(unsigned int keyIndex,
@@ -1075,7 +1076,7 @@ int LUKS_del_key(unsigned int keyIndex,
if (r)
return r;
r = LUKS_keyslot_set(hdr, keyIndex, 0, ctx);
r = LUKS_keyslot_set(hdr, keyIndex, 0);
if (r) {
log_err(ctx, _("Key slot %d is invalid, please select keyslot between 0 and %d."),
keyIndex, LUKS_NUMKEYS - 1);
@@ -1154,7 +1155,7 @@ int LUKS_keyslot_active_count(struct luks_phdr *hdr)
return num;
}
int LUKS_keyslot_set(struct luks_phdr *hdr, int keyslot, int enable, struct crypt_device *ctx)
int LUKS_keyslot_set(struct luks_phdr *hdr, int keyslot, int enable)
{
crypt_keyslot_info ki = LUKS_keyslot_info(hdr, keyslot);
@@ -1162,7 +1163,7 @@ int LUKS_keyslot_set(struct luks_phdr *hdr, int keyslot, int enable, struct cryp
return -EINVAL;
hdr->keyblock[keyslot].active = enable ? LUKS_KEY_ENABLED : LUKS_KEY_DISABLED;
log_dbg(ctx, "Key slot %d was %s in LUKS header.", keyslot, enable ? "enabled" : "disabled");
log_dbg("Key slot %d was %s in LUKS header.", keyslot, enable ? "enabled" : "disabled");
return 0;
}
@@ -1172,20 +1173,41 @@ int LUKS1_activate(struct crypt_device *cd,
uint32_t flags)
{
int r;
char *dm_cipher = NULL;
enum devcheck device_check;
struct crypt_dm_active_device dmd = {
.flags = flags,
.uuid = crypt_get_uuid(cd),
.target = DM_CRYPT,
.uuid = crypt_get_uuid(cd),
.flags = flags,
.size = 0,
.data_device = crypt_data_device(cd),
.u.crypt = {
.cipher = NULL,
.vk = vk,
.offset = crypt_get_data_offset(cd),
.iv_offset = 0,
.sector_size = crypt_get_sector_size(cd),
}
};
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
vk, crypt_get_cipher_spec(cd), crypt_get_iv_offset(cd),
crypt_get_data_offset(cd), crypt_get_integrity(cd),
crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd));
if (!r)
r = create_or_reload_device(cd, name, CRYPT_LUKS1, &dmd);
if (dmd.flags & CRYPT_ACTIVATE_SHARED)
device_check = DEV_SHARED;
else
device_check = DEV_EXCL;
dm_targets_free(cd, &dmd);
r = device_block_adjust(cd, dmd.data_device, device_check,
dmd.u.crypt.offset, &dmd.size, &dmd.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.u.crypt.cipher = dm_cipher;
r = dm_create_device(cd, name, CRYPT_LUKS1, &dmd, 0);
free(dm_cipher);
return r;
}
@@ -1207,7 +1229,7 @@ int LUKS_wipe_header_areas(struct luks_phdr *hdr,
wipe_block = 4096;
}
log_dbg(ctx, "Wiping LUKS areas (0x%06" PRIx64 " - 0x%06" PRIx64") with zeroes.",
log_dbg("Wiping LUKS areas (0x%06" PRIx64 " - 0x%06" PRIx64") with zeroes.",
offset, length + offset);
r = crypt_wipe_device(ctx, crypt_metadata_device(ctx), CRYPT_WIPE_ZERO,
@@ -1230,7 +1252,7 @@ int LUKS_wipe_header_areas(struct luks_phdr *hdr,
if (length == 0 || offset < 4096)
return -EINVAL;
log_dbg(ctx, "Wiping keyslot %i area (0x%06" PRIx64 " - 0x%06" PRIx64") with random data.",
log_dbg("Wiping keyslot %i area (0x%06" PRIx64 " - 0x%06" PRIx64") with random data.",
i, offset, length + offset);
r = crypt_wipe_device(ctx, crypt_metadata_device(ctx), CRYPT_WIPE_RANDOM,
@@ -1241,18 +1263,3 @@ int LUKS_wipe_header_areas(struct luks_phdr *hdr,
return r;
}
int LUKS_keyslot_pbkdf(struct luks_phdr *hdr, int keyslot, struct crypt_pbkdf_type *pbkdf)
{
if (LUKS_keyslot_info(hdr, keyslot) < CRYPT_SLOT_ACTIVE)
return -EINVAL;
pbkdf->type = CRYPT_KDF_PBKDF2;
pbkdf->hash = hdr->hashSpec;
pbkdf->iterations = hdr->keyblock[keyslot].passwordIterations;
pbkdf->max_memory_kb = 0;
pbkdf->parallel_threads = 0;
pbkdf->time_ms = 0;
pbkdf->flags = 0;
return 0;
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2006, Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -107,15 +107,17 @@ int LUKS_check_cipher(struct crypt_device *ctx,
const char *cipher,
const char *cipher_mode);
int LUKS_generate_phdr(struct luks_phdr *header,
int LUKS_generate_phdr(
struct luks_phdr *header,
const struct volume_key *vk,
const char *cipherName,
const char *cipherMode,
const char *hashSpec,
const char *uuid,
uint64_t data_offset,
uint64_t align_offset,
uint64_t required_alignment,
unsigned int stripes,
unsigned int alignPayload,
unsigned int alignOffset,
int detached_metadata_device,
struct crypt_device *ctx);
int LUKS_read_phdr(
@@ -175,16 +177,13 @@ int LUKS_wipe_header_areas(struct luks_phdr *hdr,
crypt_keyslot_info LUKS_keyslot_info(struct luks_phdr *hdr, int keyslot);
int LUKS_keyslot_find_empty(struct luks_phdr *hdr);
int LUKS_keyslot_active_count(struct luks_phdr *hdr);
int LUKS_keyslot_set(struct luks_phdr *hdr, int keyslot, int enable,
struct crypt_device *ctx);
int LUKS_keyslot_set(struct luks_phdr *hdr, int keyslot, int enable);
int LUKS_keyslot_area(const struct luks_phdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length);
size_t LUKS_device_sectors(const struct luks_phdr *hdr);
size_t LUKS_keyslots_offset(const struct luks_phdr *hdr);
int LUKS_keyslot_pbkdf(struct luks_phdr *hdr, int keyslot,
struct crypt_pbkdf_type *pbkdf);
int LUKS1_activate(struct crypt_device *cd,
const char *name,

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -22,10 +22,6 @@
#ifndef _CRYPTSETUP_LUKS2_ONDISK_H
#define _CRYPTSETUP_LUKS2_ONDISK_H
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include "libcryptsetup.h"
#define LUKS2_MAGIC_1ST "LUKS\xba\xbe"
@@ -49,23 +45,11 @@
#define LUKS2_DIGEST_MAX 8
#define CRYPT_ANY_SEGMENT -1
#define CRYPT_DEFAULT_SEGMENT -2
#define CRYPT_ONE_SEGMENT -3
#define CRYPT_DEFAULT_SEGMENT 0
#define CRYPT_DEFAULT_SEGMENT_STR "0"
#define CRYPT_ANY_DIGEST -1
/* 20 MiBs */
#define LUKS2_DEFAULT_NONE_REENCRYPTION_LENGTH 0x1400000
/* 1 GiB */
#define LUKS2_REENCRYPT_MAX_HOTZONE_LENGTH 0x40000000
struct device;
struct luks2_reencrypt;
struct crypt_lock_handle;
struct crypt_dm_active_device;
struct luks_phdr; /* LUKS1 for conversion */
/*
* LUKS2 header on-disk.
*
@@ -100,6 +84,7 @@ struct luks2_hdr_disk {
/*
* LUKS2 header in-memory.
*/
typedef struct json_object json_object;
struct luks2_hdr {
size_t hdr_size;
uint64_t seqid;
@@ -110,7 +95,7 @@ struct luks2_hdr {
uint8_t salt1[LUKS2_SALT_L];
uint8_t salt2[LUKS2_SALT_L];
char uuid[LUKS2_UUID_L];
void *jobj;
json_object *jobj;
};
struct luks2_keyslot_params {
@@ -140,23 +125,19 @@ struct luks2_keyslot_params {
#define LUKS2_HDR_BIN_LEN sizeof(struct luks2_hdr_disk)
//#define LUKS2_DEFAULT_HDR_SIZE 0x400000 /* 4 MiB */
#define LUKS2_DEFAULT_HDR_SIZE 0x1000000 /* 16 MiB */
#define LUKS2_HDR_DEFAULT_LEN 0x400000 /* 4 MiB */
#define LUKS2_MAX_KEYSLOTS_SIZE 0x8000000 /* 128 MiB */
#define LUKS2_HDR_OFFSET_MAX 0x400000 /* 4 MiB */
/* Offsets for secondary header (for scan if primary header is corrupted). */
#define LUKS2_HDR2_OFFSETS { 0x04000, 0x008000, 0x010000, 0x020000, \
0x40000, 0x080000, 0x100000, 0x200000, LUKS2_HDR_OFFSET_MAX }
0x40000, 0x080000, 0x100000, 0x200000, 0x400000 }
int LUKS2_hdr_version_unlocked(struct crypt_device *cd,
const char *backup_file);
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair);
int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr);
int LUKS2_hdr_write_force(struct crypt_device *cd, struct luks2_hdr *hdr);
int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr);
int LUKS2_hdr_uuid(struct crypt_device *cd,
@@ -169,7 +150,7 @@ int LUKS2_hdr_labels(struct crypt_device *cd,
const char *subsystem,
int commit);
void LUKS2_hdr_free(struct crypt_device *cd, struct luks2_hdr *hdr);
void LUKS2_hdr_free(struct luks2_hdr *hdr);
int LUKS2_hdr_backup(struct crypt_device *cd,
struct luks2_hdr *hdr,
@@ -178,11 +159,10 @@ int LUKS2_hdr_restore(struct crypt_device *cd,
struct luks2_hdr *hdr,
const char *backup_file);
uint64_t LUKS2_hdr_and_areas_size(struct luks2_hdr *hdr);
uint64_t LUKS2_keyslots_size(struct luks2_hdr *hdr);
uint64_t LUKS2_metadata_size(struct luks2_hdr *hdr);
uint64_t LUKS2_hdr_and_areas_size(json_object *jobj);
uint64_t LUKS2_keyslots_size(json_object *jobj);
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd, const char *cipher_spec);
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd);
/*
* Generic LUKS2 keyslot
@@ -194,13 +174,6 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
size_t password_len,
struct volume_key **vk);
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
const char *password,
size_t password_len,
struct volume_key **vks);
int LUKS2_keyslot_store(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -214,6 +187,9 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
int keyslot,
int wipe_area_only);
int LUKS2_keyslot_dump(struct crypt_device *cd,
int keyslot);
crypt_keyslot_priority LUKS2_keyslot_priority_get(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot);
@@ -244,12 +220,6 @@ int LUKS2_token_is_assigned(struct crypt_device *cd,
int keyslot,
int token);
int LUKS2_token_assignment_copy(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot_from,
int keyslot_to,
int commit);
int LUKS2_token_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
int token,
@@ -286,23 +256,31 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
const char *name,
uint32_t flags);
int LUKS2_tokens_count(struct luks2_hdr *hdr);
/*
* Generic LUKS2 digest
*/
int LUKS2_digest_any_matching(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk);
int LUKS2_digest_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
int segment);
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
int segment,
const struct volume_key *vk);
void LUKS2_digests_erase_unused(struct crypt_device *cd,
struct luks2_hdr *hdr);
int LUKS2_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk,
struct volume_key *vk,
int keyslot);
int LUKS2_digest_dump(struct crypt_device *cd,
int digest);
int LUKS2_digest_assign(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -317,9 +295,9 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd,
int assign,
int commit);
int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot);
int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment);
int LUKS2_digest_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot);
int LUKS2_digest_create(struct crypt_device *cd,
const char *type,
@@ -334,17 +312,11 @@ int LUKS2_activate(struct crypt_device *cd,
struct volume_key *vk,
uint32_t flags);
int LUKS2_activate_multi(struct crypt_device *cd,
const char *name,
struct volume_key *vks,
uint64_t device_size,
uint32_t flags);
int LUKS2_deactivate(struct crypt_device *cd,
const char *name,
int LUKS2_keyslot_luks2_format(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct crypt_dm_active_device *dmd,
uint32_t flags);
int keyslot,
const char *cipher,
size_t keylength);
int LUKS2_generate_hdr(
struct crypt_device *cd,
@@ -355,37 +327,34 @@ int LUKS2_generate_hdr(
const char *integrity,
const char *uuid,
unsigned int sector_size,
uint64_t data_offset,
uint64_t align_offset,
uint64_t required_alignment,
uint64_t metadata_size,
uint64_t keyslots_size);
unsigned int alignPayload,
unsigned int alignOffset,
int detached_metadata_device);
int LUKS2_check_metadata_area_size(uint64_t metadata_size);
int LUKS2_check_keyslots_area_size(uint64_t keyslots_size);
int LUKS2_wipe_header_areas(struct crypt_device *cd,
struct luks2_hdr *hdr, bool detached_header);
struct luks2_hdr *hdr);
uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr);
int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size, bool *dynamic);
int LUKS2_get_sector_size(struct luks2_hdr *hdr);
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment);
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment);
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
struct luks2_keyslot_params *params);
size_t key_size, struct luks2_keyslot_params *params);
int LUKS2_get_keyslot_params(struct luks2_hdr *hdr, int keyslot,
struct luks2_keyslot_params *params);
int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment);
int LUKS2_get_keyslot_stored_key_size(struct luks2_hdr *hdr, int keyslot);
const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size);
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr);
int LUKS2_get_keyslot_key_size(struct luks2_hdr *hdr, int keyslot);
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type);
int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment);
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment);
crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot);
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length);
int LUKS2_keyslot_pbkdf(struct luks2_hdr *hdr, int keyslot, struct crypt_pbkdf_type *pbkdf);
/*
* Permanent activation flags stored in header
*/
@@ -396,9 +365,7 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
* Requirements for device activation or header modification
*/
int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs);
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit);
int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint32_t *version);
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs);
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
@@ -406,9 +373,8 @@ int LUKS2_key_description_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int segment);
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot);
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int digest);
struct luks_phdr;
int LUKS2_luks1_to_luks2(struct crypt_device *cd,
struct luks_phdr *hdr1,
struct luks2_hdr *hdr2);
@@ -416,44 +382,4 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd,
struct luks2_hdr *hdr2,
struct luks_phdr *hdr1);
/*
* LUKS2 reencryption
*/
int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
const char *passphrase,
size_t passphrase_size,
uint32_t flags,
struct volume_key **vks);
void LUKS2_reencrypt_free(struct crypt_device *cd,
struct luks2_reencrypt *rh);
crypt_reencrypt_info LUKS2_reencrypt_status(struct luks2_hdr *hdr);
crypt_reencrypt_info LUKS2_reencrypt_get_params(struct luks2_hdr *hdr,
struct crypt_params_reencrypt *params);
int LUKS2_reencrypt_lock(struct crypt_device *cd,
struct crypt_lock_handle **reencrypt_lock);
int LUKS2_reencrypt_lock_by_dm_uuid(struct crypt_device *cd,
const char *dm_uuid,
struct crypt_lock_handle **reencrypt_lock);
void LUKS2_reencrypt_unlock(struct crypt_device *cd,
struct crypt_lock_handle *reencrypt_lock);
int LUKS2_reencrypt_check_device_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t check_size,
uint64_t *dev_size,
bool activation,
bool dynamic);
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks);
#endif

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, digest handling
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -28,7 +28,7 @@ static const digest_handler *digest_handlers[LUKS2_DIGEST_MAX] = {
NULL
};
static const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type)
const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type)
{
int i;
@@ -86,12 +86,14 @@ int LUKS2_digest_create(struct crypt_device *cd,
if (digest < 0)
return -EINVAL;
log_dbg(cd, "Creating new digest %d (%s).", digest, type);
log_dbg("Creating new digest %d (%s).", digest, type);
return dh->store(cd, digest, vk->key, vk->keylength) ?: digest;
}
int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
int LUKS2_digest_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot)
{
char keyslot_name[16];
json_object *jobj_digests, *jobj_digest_keyslots;
@@ -110,43 +112,32 @@ int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
return -ENOENT;
}
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
int LUKS2_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
int digest,
const struct volume_key *vk)
struct volume_key *vk,
int keyslot)
{
const digest_handler *h;
int r;
int digest, r;
digest = LUKS2_digest_by_keyslot(cd, hdr, keyslot);
if (digest < 0)
return digest;
log_dbg("Verifying key from keyslot %d, digest %d.", keyslot, digest);
h = LUKS2_digest_handler(cd, digest);
if (!h)
return -EINVAL;
r = h->verify(cd, digest, vk->key, vk->keylength);
if (r < 0) {
log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r);
log_dbg("Digest %d (%s) verify failed with %d.", digest, h->name, r);
return r;
}
return digest;
}
int LUKS2_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk,
int keyslot)
{
int digest;
digest = LUKS2_digest_by_keyslot(hdr, keyslot);
if (digest < 0)
return digest;
log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest);
return LUKS2_digest_verify_by_digest(cd, hdr, digest, vk);
}
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
{
const digest_handler *h;
@@ -157,36 +148,41 @@ int LUKS2_digest_dump(struct crypt_device *cd, int digest)
return h->dump(cd, digest);
}
int LUKS2_digest_any_matching(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk)
{
int digest;
for (digest = 0; digest < LUKS2_DIGEST_MAX; digest++)
if (LUKS2_digest_verify_by_digest(cd, hdr, digest, vk) == digest)
return digest;
return -ENOENT;
}
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
int segment,
const struct volume_key *vk)
{
return LUKS2_digest_verify_by_digest(cd, hdr, LUKS2_digest_by_segment(hdr, segment), vk);
const digest_handler *h;
int digest, r;
digest = LUKS2_digest_by_segment(cd, hdr, segment);
if (digest < 0)
return digest;
log_dbg("Verifying key digest %d.", digest);
h = LUKS2_digest_handler(cd, digest);
if (!h)
return -EINVAL;
r = h->verify(cd, digest, vk->key, vk->keylength);
if (r < 0) {
log_dbg("Digest %d (%s) verify failed with %d.", digest, h->name, r);
return r;
}
return digest;
}
/* FIXME: segment can have more digests */
int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment)
int LUKS2_digest_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr,
int segment)
{
char segment_name[16];
json_object *jobj_digests, *jobj_digest_segments;
if (segment == CRYPT_DEFAULT_SEGMENT)
segment = LUKS2_get_default_segment(hdr);
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)
@@ -209,7 +205,7 @@ static int assign_one_digest(struct crypt_device *cd, struct luks2_hdr *hdr,
json_object *jobj1, *jobj_digest, *jobj_digest_keyslots;
char num[16];
log_dbg(cd, "Keyslot %i %s digest %i.", keyslot, assign ? "assigned to" : "unassigned from", digest);
log_dbg("Keyslot %i %s digest %i.", keyslot, assign ? "assigned to" : "unassigned from", digest);
jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
if (!jobj_digest)
@@ -219,9 +215,7 @@ static int assign_one_digest(struct crypt_device *cd, struct luks2_hdr *hdr,
if (!jobj_digest_keyslots)
return -EINVAL;
if (snprintf(num, sizeof(num), "%d", keyslot) < 0)
return -EINVAL;
snprintf(num, sizeof(num), "%d", keyslot);
if (assign) {
jobj1 = LUKS2_array_jobj(jobj_digest_keyslots, num);
if (!jobj1)
@@ -260,43 +254,13 @@ int LUKS2_digest_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
}
static int assign_all_segments(struct crypt_device *cd, struct luks2_hdr *hdr,
int digest, int assign)
{
json_object *jobj1, *jobj_digest, *jobj_digest_segments;
jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
if (!jobj_digest)
return -EINVAL;
json_object_object_get_ex(jobj_digest, "segments", &jobj_digest_segments);
if (!jobj_digest_segments)
return -EINVAL;
if (assign) {
json_object_object_foreach(LUKS2_get_segments_jobj(hdr), key, value) {
UNUSED(value);
jobj1 = LUKS2_array_jobj(jobj_digest_segments, key);
if (!jobj1)
json_object_array_add(jobj_digest_segments, json_object_new_string(key));
}
} else {
jobj1 = json_object_new_array();
if (!jobj1)
return -ENOMEM;
json_object_object_add(jobj_digest, "segments", jobj1);
}
return 0;
}
static int assign_one_segment(struct crypt_device *cd, struct luks2_hdr *hdr,
int segment, int digest, int assign)
{
json_object *jobj1, *jobj_digest, *jobj_digest_segments;
char num[16];
log_dbg(cd, "Segment %i %s digest %i.", segment, assign ? "assigned to" : "unassigned from", digest);
log_dbg("Segment %i %s digest %i.", segment, assign ? "assigned to" : "unassigned from", digest);
jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
if (!jobj_digest)
@@ -306,9 +270,7 @@ static int assign_one_segment(struct crypt_device *cd, struct luks2_hdr *hdr,
if (!jobj_digest_segments)
return -EINVAL;
if (snprintf(num, sizeof(num), "%d", segment) < 0)
return -EINVAL;
snprintf(num, sizeof(num), "%d", segment);
if (assign) {
jobj1 = LUKS2_array_jobj(jobj_digest_segments, num);
if (!jobj1)
@@ -328,27 +290,17 @@ int LUKS2_digest_segment_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
json_object *jobj_digests;
int r = 0;
if (segment == CRYPT_DEFAULT_SEGMENT)
segment = LUKS2_get_default_segment(hdr);
if (digest == CRYPT_ANY_DIGEST) {
json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
json_object_object_foreach(jobj_digests, key, val) {
UNUSED(val);
if (segment == CRYPT_ANY_SEGMENT)
r = assign_all_segments(cd, hdr, atoi(key), assign);
else
r = assign_one_segment(cd, hdr, segment, atoi(key), assign);
r = assign_one_segment(cd, hdr, segment, atoi(key), assign);
if (r < 0)
break;
}
} else {
if (segment == CRYPT_ANY_SEGMENT)
r = assign_all_segments(cd, hdr, digest, assign);
else
r = assign_one_segment(cd, hdr, segment, digest, assign);
}
} else
r = assign_one_segment(cd, hdr, segment, digest, assign);
if (r < 0)
return r;
@@ -383,7 +335,7 @@ void LUKS2_digests_erase_unused(struct crypt_device *cd,
json_object_object_foreach(jobj_digests, key, val) {
if (digest_unused(val)) {
log_dbg(cd, "Erasing unused digest %d.", atoi(key));
log_dbg("Erasing unused digest %d.", atoi(key));
json_object_object_del(jobj_digests, key);
}
}
@@ -422,7 +374,7 @@ static char *get_key_description_by_digest(struct crypt_device *cd, int digest)
int LUKS2_key_description_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int segment)
{
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_segment(hdr, segment));
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_segment(cd, hdr, segment));
int r;
r = crypt_volume_key_set_description(vk, desc);
@@ -433,21 +385,7 @@ int LUKS2_key_description_by_segment(struct crypt_device *cd,
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot)
{
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_keyslot(hdr, keyslot));
int r;
r = crypt_volume_key_set_description(vk, desc);
if (!r)
r = crypt_volume_key_load_in_keyring(cd, vk);
free(desc);
return r;
}
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int digest)
{
char *desc = get_key_description_by_digest(cd, digest);
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_keyslot(cd, hdr, keyslot));
int r;
r = crypt_volume_key_set_description(vk, desc);

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, PBKDF2 digest handler (LUKS1 compatible)
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -94,25 +94,18 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
size_t volume_key_len)
{
json_object *jobj_digest, *jobj_digests;
char salt[LUKS_SALTSIZE], digest_raw[128];
char salt[LUKS_SALTSIZE], digest_raw[128], num[16];
int hmac_size, r;
char *base64_str;
struct luks2_hdr *hdr;
struct crypt_pbkdf_limits pbkdf_limits;
const struct crypt_pbkdf_type *pbkdf_cd;
struct crypt_pbkdf_type pbkdf = {
.type = CRYPT_KDF_PBKDF2,
.hash = "sha256",
.time_ms = LUKS_MKD_ITERATIONS_MS,
};
/* Inherit hash from PBKDF setting */
pbkdf_cd = crypt_get_pbkdf_type(cd);
if (pbkdf_cd)
pbkdf.hash = pbkdf_cd->hash;
if (!pbkdf.hash)
pbkdf.hash = DEFAULT_LUKS1_HASH;
log_dbg(cd, "Setting PBKDF2 type key digest %d.", digest);
log_dbg("Setting PBKDF2 type key digest %d.", digest);
r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
if (r < 0)
@@ -131,8 +124,8 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
}
hmac_size = crypt_hmac_size(pbkdf.hash);
if (hmac_size < 0 || hmac_size > (int)sizeof(digest_raw))
return -EINVAL;
if (hmac_size < 0)
return hmac_size;
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, pbkdf.hash, volume_key, volume_key_len,
salt, LUKS_SALTSIZE, digest_raw, hmac_size,
@@ -170,10 +163,12 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
json_object_object_add(jobj_digest, "digest", json_object_new_string(base64_str));
free(base64_str);
if (jobj_digests)
json_object_object_add_by_uint(jobj_digests, digest, jobj_digest);
if (jobj_digests) {
snprintf(num, sizeof(num), "%d", digest);
json_object_object_add(jobj_digests, num, jobj_digest);
}
JSON_DBG(cd, jobj_digest, "Digest JSON:");
JSON_DBG(jobj_digest, "Digest JSON");
return 0;
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -26,8 +26,7 @@
/*
* Helper functions
*/
static json_object *parse_json_len(struct crypt_device *cd, const char *json_area,
uint64_t max_length, int *json_len)
json_object *parse_json_len(const char *json_area, uint64_t max_length, int *json_len)
{
json_object *jobj;
struct json_tokener *jtok;
@@ -38,13 +37,13 @@ static json_object *parse_json_len(struct crypt_device *cd, const char *json_are
jtok = json_tokener_new();
if (!jtok) {
log_dbg(cd, "ERROR: Failed to init json tokener");
log_dbg("ERROR: Failed to init json tokener");
return NULL;
}
jobj = json_tokener_parse_ex(jtok, json_area, max_length);
if (!jobj)
log_dbg(cd, "ERROR: Failed to parse json data (%d): %s",
log_dbg("ERROR: Failed to parse json data (%d): %s",
json_tokener_get_error(jtok),
json_tokener_error_desc(json_tokener_get_error(jtok)));
else
@@ -55,8 +54,7 @@ static json_object *parse_json_len(struct crypt_device *cd, const char *json_are
return jobj;
}
static void log_dbg_checksum(struct crypt_device *cd,
const uint8_t *csum, const char *csum_alg, const char *info)
static void log_dbg_checksum(const uint8_t *csum, const char *csum_alg, const char *info)
{
char csum_txt[2*LUKS2_CHECKSUM_L+1];
int i;
@@ -65,7 +63,7 @@ static void log_dbg_checksum(struct crypt_device *cd,
snprintf(&csum_txt[i*2], 3, "%02hhx", (const char)csum[i]);
csum_txt[i*2+1] = '\0'; /* Just to be safe, sprintf should write \0 there. */
log_dbg(cd, "Checksum:%s (%s)", &csum_txt[0], info);
log_dbg("Checksum:%s (%s)", &csum_txt[0], info);
}
/*
@@ -100,8 +98,7 @@ static int hdr_checksum_calculate(const char *alg, struct luks2_hdr_disk *hdr_di
/*
* Compare hash (checksum) of on-disk and in-memory header.
*/
static int hdr_checksum_check(struct crypt_device *cd,
const char *alg, struct luks2_hdr_disk *hdr_disk,
static int hdr_checksum_check(const char *alg, struct luks2_hdr_disk *hdr_disk,
const char *json_area, size_t json_len)
{
struct luks2_hdr_disk hdr_tmp;
@@ -119,8 +116,8 @@ static int hdr_checksum_check(struct crypt_device *cd,
if (r < 0)
return r;
log_dbg_checksum(cd, hdr_disk->csum, alg, "on-disk");
log_dbg_checksum(cd, hdr_tmp.csum, alg, "in-memory");
log_dbg_checksum(hdr_disk->csum, alg, "on-disk");
log_dbg_checksum(hdr_tmp.csum, alg, "in-memory");
if (memcmp(hdr_tmp.csum, hdr_disk->csum, (size_t)hash_size))
return -EINVAL;
@@ -175,13 +172,13 @@ static void hdr_to_disk(struct luks2_hdr *hdr,
hdr_disk->hdr_offset = cpu_to_be64(offset);
hdr_disk->seqid = cpu_to_be64(hdr->seqid);
memcpy(hdr_disk->label, hdr->label, MIN(strlen(hdr->label), LUKS2_LABEL_L));
strncpy(hdr_disk->label, hdr->label, LUKS2_LABEL_L);
hdr_disk->label[LUKS2_LABEL_L - 1] = '\0';
memcpy(hdr_disk->subsystem, hdr->subsystem, MIN(strlen(hdr->subsystem), LUKS2_LABEL_L));
strncpy(hdr_disk->subsystem, hdr->subsystem, LUKS2_LABEL_L);
hdr_disk->subsystem[LUKS2_LABEL_L - 1] = '\0';
memcpy(hdr_disk->checksum_alg, hdr->checksum_alg, MIN(strlen(hdr->checksum_alg), LUKS2_CHECKSUM_ALG_L));
strncpy(hdr_disk->checksum_alg, hdr->checksum_alg, LUKS2_CHECKSUM_ALG_L);
hdr_disk->checksum_alg[LUKS2_CHECKSUM_ALG_L - 1] = '\0';
memcpy(hdr_disk->uuid, hdr->uuid, MIN(strlen(hdr->uuid), LUKS2_UUID_L));
strncpy(hdr_disk->uuid, hdr->uuid, LUKS2_UUID_L);
hdr_disk->uuid[LUKS2_UUID_L - 1] = '\0';
memcpy(hdr_disk->salt, secondary ? hdr->salt2 : hdr->salt1, LUKS2_SALT_L);
@@ -190,8 +187,7 @@ static void hdr_to_disk(struct luks2_hdr *hdr,
/*
* Sanity checks before checksum is validated
*/
static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
struct luks2_hdr_disk *hdr,
static int hdr_disk_sanity_check_pre(struct luks2_hdr_disk *hdr,
size_t *hdr_json_size, int secondary,
uint64_t offset)
{
@@ -199,25 +195,25 @@ static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
return -EINVAL;
if (be16_to_cpu(hdr->version) != 2) {
log_dbg(cd, "Unsupported LUKS2 header version %u.", be16_to_cpu(hdr->version));
log_dbg("Unsupported LUKS2 header version %u.", be16_to_cpu(hdr->version));
return -EINVAL;
}
if (offset != be64_to_cpu(hdr->hdr_offset)) {
log_dbg(cd, "LUKS2 offset 0x%04x on device differs to expected offset 0x%04x.",
log_dbg("LUKS2 offset 0x%04x on device differs to expected offset 0x%04x.",
(unsigned)be64_to_cpu(hdr->hdr_offset), (unsigned)offset);
return -EINVAL;
}
if (secondary && (offset != be64_to_cpu(hdr->hdr_size))) {
log_dbg(cd, "LUKS2 offset 0x%04x in secondary header does not match size 0x%04x.",
log_dbg("LUKS2 offset 0x%04x in secondary header doesn't match size 0x%04x.",
(unsigned)offset, (unsigned)be64_to_cpu(hdr->hdr_size));
return -EINVAL;
}
/* FIXME: sanity check checksum alg. */
log_dbg(cd, "LUKS2 header version %u of size %u bytes, checksum %s.",
log_dbg("LUKS2 header version %u of size %u bytes, checksum %s.",
(unsigned)be16_to_cpu(hdr->version), (unsigned)be64_to_cpu(hdr->hdr_size),
hdr->checksum_alg);
@@ -228,17 +224,16 @@ static int hdr_disk_sanity_check_pre(struct crypt_device *cd,
/*
* Read LUKS2 header from disk at specific offset.
*/
static int hdr_read_disk(struct crypt_device *cd,
struct device *device, struct luks2_hdr_disk *hdr_disk,
static int hdr_read_disk(struct device *device, struct luks2_hdr_disk *hdr_disk,
char **json_area, uint64_t offset, int secondary)
{
size_t hdr_json_size = 0;
int devfd, r;
int devfd = -1, r;
log_dbg(cd, "Trying to read %s LUKS2 header at offset 0x%" PRIx64 ".",
log_dbg("Trying to read %s LUKS2 header at offset 0x%" PRIx64 ".",
secondary ? "secondary" : "primary", offset);
devfd = device_open_locked(cd, device, O_RDONLY);
devfd = device_open_locked(device, O_RDONLY);
if (devfd < 0)
return devfd == -1 ? -EIO : devfd;
@@ -246,14 +241,16 @@ static int hdr_read_disk(struct crypt_device *cd,
* Read binary header and run sanity check before reading
* JSON area and validating checksum.
*/
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), hdr_disk,
LUKS2_HDR_BIN_LEN, offset) != LUKS2_HDR_BIN_LEN) {
close(devfd);
return -EIO;
}
r = hdr_disk_sanity_check_pre(cd, hdr_disk, &hdr_json_size, secondary, offset);
r = hdr_disk_sanity_check_pre(hdr_disk, &hdr_json_size, secondary, offset);
if (r < 0) {
close(devfd);
return r;
}
@@ -262,23 +259,27 @@ static int hdr_read_disk(struct crypt_device *cd,
*/
*json_area = malloc(hdr_json_size);
if (!*json_area) {
close(devfd);
return -ENOMEM;
}
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), *json_area, hdr_json_size,
offset + LUKS2_HDR_BIN_LEN) != (ssize_t)hdr_json_size) {
close(devfd);
free(*json_area);
*json_area = NULL;
return -EIO;
}
close(devfd);
/*
* Calculate and validate checksum and zero it afterwards.
*/
if (hdr_checksum_check(cd, hdr_disk->checksum_alg, hdr_disk,
if (hdr_checksum_check(hdr_disk->checksum_alg, hdr_disk,
*json_area, hdr_json_size)) {
log_dbg(cd, "LUKS2 header checksum error (offset %" PRIu64 ").", offset);
log_dbg("LUKS2 header checksum error (offset %" PRIu64 ").", offset);
r = -EINVAL;
}
memset(hdr_disk->csum, 0, LUKS2_CHECKSUM_L);
@@ -289,21 +290,20 @@ static int hdr_read_disk(struct crypt_device *cd,
/*
* Write LUKS2 header to disk at specific offset.
*/
static int hdr_write_disk(struct crypt_device *cd,
struct device *device, struct luks2_hdr *hdr,
const char *json_area, int secondary)
static int hdr_write_disk(struct device *device, struct luks2_hdr *hdr,
const char *json_area, int secondary)
{
struct luks2_hdr_disk hdr_disk;
uint64_t offset = secondary ? hdr->hdr_size : 0;
size_t hdr_json_len;
int devfd, r;
int devfd = -1, r;
log_dbg(cd, "Trying to write LUKS2 header (%zu bytes) at offset %" PRIu64 ".",
log_dbg("Trying to write LUKS2 header (%zu bytes) at offset %" PRIu64 ".",
hdr->hdr_size, offset);
/* FIXME: read-only device silent fail? */
devfd = device_open_locked(cd, device, O_RDWR);
devfd = device_open_locked(device, O_RDWR);
if (devfd < 0)
return devfd == -1 ? -EINVAL : devfd;
@@ -314,19 +314,21 @@ static int hdr_write_disk(struct crypt_device *cd,
/*
* Write header without checksum but with proper seqid.
*/
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
if (write_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), (char *)&hdr_disk,
LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN) {
close(devfd);
return -EIO;
}
/*
* Write json area.
*/
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
if (write_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device),
CONST_CAST(char*)json_area, hdr_json_len,
LUKS2_HDR_BIN_LEN + offset) < (ssize_t)hdr_json_len) {
close(devfd);
return -EIO;
}
@@ -336,62 +338,42 @@ static int hdr_write_disk(struct crypt_device *cd,
r = hdr_checksum_calculate(hdr_disk.checksum_alg, &hdr_disk,
json_area, hdr_json_len);
if (r < 0) {
close(devfd);
return r;
}
log_dbg_checksum(cd, hdr_disk.csum, hdr_disk.checksum_alg, "in-memory");
log_dbg_checksum(hdr_disk.csum, hdr_disk.checksum_alg, "in-memory");
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
if (write_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), (char *)&hdr_disk,
LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN)
r = -EIO;
device_sync(cd, device);
device_sync(device, devfd);
close(devfd);
return r;
}
static int LUKS2_check_sequence_id(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device)
static int LUKS2_check_device_size(struct crypt_device *cd, struct device *device,
uint64_t hdr_size, int falloc)
{
int devfd;
struct luks2_hdr_disk dhdr;
uint64_t dev_size;
if (!hdr)
return -EINVAL;
devfd = device_open_locked(cd, device, O_RDONLY);
if (devfd < 0)
return devfd == -1 ? -EINVAL : devfd;
/* we need only first 512 bytes, see luks2_hdr_disk structure */
if ((read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), &dhdr, 512, 0) != 512))
if (device_size(device, &dev_size)) {
log_dbg("Cannot get device size for device %s.", device_path(device));
return -EIO;
/* there's nothing to check if there's no LUKS2 header */
if ((be16_to_cpu(dhdr.version) != 2) ||
memcmp(dhdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L) ||
strcmp(dhdr.uuid, hdr->uuid))
return 0;
return hdr->seqid != be64_to_cpu(dhdr.seqid);
}
int LUKS2_device_write_lock(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device)
{
int r = device_write_lock(cd, device);
if (r < 0) {
log_err(cd, _("Failed to acquire write lock on device %s."), device_path(device));
return r;
}
/* run sequence id check only on first write lock (r == 1) and w/o LUKS2 reencryption in-progress */
if (r == 1 && !crypt_get_luks2_reencrypt(cd)) {
log_dbg(cd, "Checking context sequence id matches value stored on disk.");
if (LUKS2_check_sequence_id(cd, hdr, device)) {
device_write_unlock(cd, device);
log_err(cd, _("Detected attempt for concurrent LUKS2 metadata update. Aborting operation."));
return -EINVAL;
}
log_dbg("Device size %" PRIu64 ", header size %"
PRIu64 ".", dev_size, hdr_size);
if (hdr_size > dev_size) {
/* If it is header file, increase its size */
if (falloc && !device_fallocate(device, hdr_size))
return 0;
log_err(cd, _("Device %s is too small. (LUKS2 requires at least %" PRIu64 " bytes.)"),
device_path(device), hdr_size);
return -EINVAL;
}
return 0;
@@ -401,7 +383,7 @@ int LUKS2_device_write_lock(struct crypt_device *cd, struct luks2_hdr *hdr, stru
* Convert in-memory LUKS2 header and write it to disk.
* This will increase sequence id, write both header copies and calculate checksum.
*/
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device, bool seqid_check)
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device)
{
char *json_area;
const char *json_text;
@@ -409,11 +391,11 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
int r;
if (hdr->version != 2) {
log_dbg(cd, "Unsupported LUKS2 header version (%u).", hdr->version);
log_dbg("Unsupported LUKS2 header version (%u).", hdr->version);
return -EINVAL;
}
r = device_check_size(cd, crypt_metadata_device(cd), LUKS2_hdr_and_areas_size(hdr), 1);
r = LUKS2_check_device_size(cd, crypt_metadata_device(cd), LUKS2_hdr_and_areas_size(hdr->jobj), 1);
if (r)
return r;
@@ -421,9 +403,10 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
* Allocate and zero JSON area (of proper header size).
*/
json_area_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
json_area = crypt_zalloc(json_area_len);
json_area = malloc(json_area_len);
if (!json_area)
return -ENOMEM;
memset(json_area, 0, json_area_len);
/*
* Generate text space-efficient JSON representation to json area.
@@ -431,55 +414,55 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
json_text = json_object_to_json_string_ext(hdr->jobj,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
if (!json_text || !*json_text) {
log_dbg(cd, "Cannot parse JSON object to text representation.");
log_dbg("Cannot parse JSON object to text representation.");
free(json_area);
return -ENOMEM;
}
if (strlen(json_text) > (json_area_len - 1)) {
log_dbg(cd, "JSON is too large (%zu > %zu).", strlen(json_text), json_area_len);
log_dbg("JSON is too large (%zu > %zu).", strlen(json_text), json_area_len);
free(json_area);
return -EINVAL;
}
strncpy(json_area, json_text, json_area_len);
if (seqid_check)
r = LUKS2_device_write_lock(cd, hdr, device);
else
r = device_write_lock(cd, device);
if (r < 0) {
/* Increase sequence id before writing it to disk. */
hdr->seqid++;
r = device_write_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire write device lock."));
free(json_area);
return r;
}
/* Increase sequence id before writing it to disk. */
hdr->seqid++;
/* Write primary and secondary header */
r = hdr_write_disk(cd, device, hdr, json_area, 0);
r = hdr_write_disk(device, hdr, json_area, 0);
if (!r)
r = hdr_write_disk(cd, device, hdr, json_area, 1);
r = hdr_write_disk(device, hdr, json_area, 1);
if (r)
log_dbg(cd, "LUKS2 header write failed (%d).", r);
log_dbg("LUKS2 header write failed (%d).", r);
device_write_unlock(cd, device);
device_write_unlock(device);
/* FIXME: try recovery here? */
free(json_area);
return r;
}
static int validate_json_area(struct crypt_device *cd, const char *json_area,
uint64_t json_len, uint64_t max_length)
static int validate_json_area(const char *json_area, uint64_t json_len, uint64_t max_length)
{
char c;
/* Enforce there are no needless opening bytes */
if (*json_area != '{') {
log_dbg(cd, "ERROR: Opening character must be left curly bracket: '{'.");
log_dbg("ERROR: Opening character must be left curly bracket: '{'.");
return -EINVAL;
}
if (json_len >= max_length) {
log_dbg(cd, "ERROR: Missing trailing null byte beyond parsed json data string.");
log_dbg("ERROR: Missing trailing null byte beyond parsed json data string.");
return -EINVAL;
}
@@ -492,7 +475,7 @@ static int validate_json_area(struct crypt_device *cd, const char *json_area,
do {
c = *(json_area + json_len);
if (c != '\0') {
log_dbg(cd, "ERROR: Forbidden ascii code 0x%02hhx found beyond json data string at offset %" PRIu64,
log_dbg("ERROR: Forbidden ascii code 0x%02hhx found beyond json data string at offset %" PRIu64,
c, json_len);
return -EINVAL;
}
@@ -501,38 +484,37 @@ static int validate_json_area(struct crypt_device *cd, const char *json_area,
return 0;
}
static int validate_luks2_json_object(struct crypt_device *cd, json_object *jobj_hdr, uint64_t length)
static int validate_luks2_json_object(json_object *jobj_hdr, uint64_t length)
{
int r;
/* we require top level object to be of json_type_object */
r = !json_object_is_type(jobj_hdr, json_type_object);
if (r) {
log_dbg(cd, "ERROR: Resulting object is not a json object type");
log_dbg("ERROR: Resulting object is not a json object type");
return r;
}
r = LUKS2_hdr_validate(cd, jobj_hdr, length);
r = LUKS2_hdr_validate(jobj_hdr, length);
if (r) {
log_dbg(cd, "Repairing JSON metadata.");
log_dbg("Repairing JSON metadata.");
/* try to correct known glitches */
LUKS2_hdr_repair(cd, jobj_hdr);
LUKS2_hdr_repair(jobj_hdr);
/* run validation again */
r = LUKS2_hdr_validate(cd, jobj_hdr, length);
r = LUKS2_hdr_validate(jobj_hdr, length);
}
if (r)
log_dbg(cd, "ERROR: LUKS2 validation failed");
log_dbg("ERROR: LUKS2 validation failed");
return r;
}
static json_object *parse_and_validate_json(struct crypt_device *cd,
const char *json_area, uint64_t max_length)
static json_object *parse_and_validate_json(const char *json_area, uint64_t max_length)
{
int json_len, r;
json_object *jobj = parse_json_len(cd, json_area, max_length, &json_len);
json_object *jobj = parse_json_len(json_area, max_length, &json_len);
if (!jobj)
return NULL;
@@ -540,9 +522,9 @@ static json_object *parse_and_validate_json(struct crypt_device *cd,
/* successful parse_json_len must not return offset <= 0 */
assert(json_len > 0);
r = validate_json_area(cd, json_area, json_len, max_length);
r = validate_json_area(json_area, json_len, max_length);
if (!r)
r = validate_luks2_json_object(cd, jobj, max_length);
r = validate_luks2_json_object(jobj, max_length);
if (r) {
json_object_put(jobj);
@@ -552,19 +534,19 @@ static json_object *parse_and_validate_json(struct crypt_device *cd,
return jobj;
}
static int detect_device_signatures(struct crypt_device *cd, const char *path)
static int detect_device_signatures(const char *path)
{
blk_probe_status prb_state;
int r;
struct blkid_handle *h;
if (!blk_supported()) {
log_dbg(cd, "Blkid probing of device signatures disabled.");
log_dbg("Blkid probing of device signatures disabled.");
return 0;
}
if ((r = blk_init_by_path(&h, path))) {
log_dbg(cd, "Failed to initialize blkid_handle by path.");
log_dbg("Failed to initialize blkid_handle by path.");
return -EINVAL;
}
@@ -578,22 +560,22 @@ static int detect_device_signatures(struct crypt_device *cd, const char *path)
switch (prb_state) {
case PRB_AMBIGUOUS:
log_dbg(cd, "Blkid probe couldn't decide device type unambiguously.");
log_dbg("Blkid probe couldn't decide device type unambiguously.");
/* fall through */
case PRB_FAIL:
log_dbg(cd, "Blkid probe failed.");
log_dbg("Blkid probe failed.");
r = -EINVAL;
break;
case PRB_OK: /* crypto_LUKS type is filtered out */
r = -EINVAL;
if (blk_is_partition(h))
log_dbg(cd, "Blkid probe detected partition type '%s'", blk_get_partition_type(h));
log_dbg("Blkid probe detected partition type '%s'", blk_get_partition_type(h));
else if (blk_is_superblock(h))
log_dbg(cd, "blkid probe detected superblock type '%s'", blk_get_superblock_type(h));
log_dbg("blkid probe detected superblock type '%s'", blk_get_superblock_type(h));
break;
case PRB_EMPTY:
log_dbg(cd, "Blkid probe detected no foreign device signature.");
log_dbg("Blkid probe detected no foreign device signature.");
}
blk_free(h);
return r;
@@ -618,16 +600,16 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
/* Skip auto-recovery if locks are disabled and we're not doing LUKS2 explicit repair */
if (do_recovery && do_blkprobe && !crypt_metadata_locking_enabled()) {
do_recovery = 0;
log_dbg(cd, "Disabling header auto-recovery due to locking being disabled.");
log_dbg("Disabling header auto-recovery due to locking being disabled.");
}
/*
* Read primary LUKS2 header (offset 0).
*/
state_hdr1 = HDR_FAIL;
r = hdr_read_disk(cd, device, &hdr_disk1, &json_area1, 0, 0);
r = hdr_read_disk(device, &hdr_disk1, &json_area1, 0, 0);
if (r == 0) {
jobj_hdr1 = parse_and_validate_json(cd, json_area1, be64_to_cpu(hdr_disk1.hdr_size) - LUKS2_HDR_BIN_LEN);
jobj_hdr1 = parse_and_validate_json(json_area1, be64_to_cpu(hdr_disk1.hdr_size) - LUKS2_HDR_BIN_LEN);
state_hdr1 = jobj_hdr1 ? HDR_OK : HDR_OBSOLETE;
} else if (r == -EIO)
state_hdr1 = HDR_FAIL_IO;
@@ -637,9 +619,9 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
*/
state_hdr2 = HDR_FAIL;
if (state_hdr1 != HDR_FAIL && state_hdr1 != HDR_FAIL_IO) {
r = hdr_read_disk(cd, device, &hdr_disk2, &json_area2, be64_to_cpu(hdr_disk1.hdr_size), 1);
r = hdr_read_disk(device, &hdr_disk2, &json_area2, be64_to_cpu(hdr_disk1.hdr_size), 1);
if (r == 0) {
jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size) - LUKS2_HDR_BIN_LEN);
jobj_hdr2 = parse_and_validate_json(json_area2, be64_to_cpu(hdr_disk2.hdr_size) - LUKS2_HDR_BIN_LEN);
state_hdr2 = jobj_hdr2 ? HDR_OK : HDR_OBSOLETE;
} else if (r == -EIO)
state_hdr2 = HDR_FAIL_IO;
@@ -648,10 +630,10 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
* No header size, check all known offsets.
*/
for (r = -EINVAL,i = 0; r < 0 && i < ARRAY_SIZE(hdr2_offsets); i++)
r = hdr_read_disk(cd, device, &hdr_disk2, &json_area2, hdr2_offsets[i], 1);
r = hdr_read_disk(device, &hdr_disk2, &json_area2, hdr2_offsets[i], 1);
if (r == 0) {
jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size) - LUKS2_HDR_BIN_LEN);
jobj_hdr2 = parse_and_validate_json(json_area2, be64_to_cpu(hdr_disk2.hdr_size) - LUKS2_HDR_BIN_LEN);
state_hdr2 = jobj_hdr2 ? HDR_OK : HDR_OBSOLETE;
} else if (r == -EIO)
state_hdr2 = HDR_FAIL_IO;
@@ -669,15 +651,15 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
/* check header with keyslots to fit the device */
if (state_hdr1 == HDR_OK)
hdr_size = LUKS2_hdr_and_areas_size_jobj(jobj_hdr1);
hdr_size = LUKS2_hdr_and_areas_size(jobj_hdr1);
else if (state_hdr2 == HDR_OK)
hdr_size = LUKS2_hdr_and_areas_size_jobj(jobj_hdr2);
hdr_size = LUKS2_hdr_and_areas_size(jobj_hdr2);
else {
r = (state_hdr1 == HDR_FAIL_IO && state_hdr2 == HDR_FAIL_IO) ? -EIO : -EINVAL;
goto err;
}
r = device_check_size(cd, device, hdr_size, 0);
r = LUKS2_check_device_size(cd, device, hdr_size, 0);
if (r)
goto err;
@@ -685,9 +667,9 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
* Try to rewrite (recover) bad header. Always regenerate salt for bad header.
*/
if (state_hdr1 == HDR_OK && state_hdr2 != HDR_OK) {
log_dbg(cd, "Secondary LUKS2 header requires recovery.");
log_dbg("Secondary LUKS2 header requires recovery.");
if (do_blkprobe && (r = detect_device_signatures(cd, device_path(device)))) {
if (do_blkprobe && (r = detect_device_signatures(device_path(device)))) {
log_err(cd, _("Device contains ambiguous signatures, cannot auto-recover LUKS2.\n"
"Please run \"cryptsetup repair\" for recovery."));
goto err;
@@ -695,20 +677,20 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
if (do_recovery) {
memcpy(&hdr_disk2, &hdr_disk1, LUKS2_HDR_BIN_LEN);
r = crypt_random_get(cd, (char*)hdr_disk2.salt, sizeof(hdr_disk2.salt), CRYPT_RND_SALT);
r = crypt_random_get(NULL, (char*)hdr_disk2.salt, sizeof(hdr_disk2.salt), CRYPT_RND_SALT);
if (r)
log_dbg(cd, "Cannot generate master salt.");
log_dbg("Cannot generate master salt.");
else {
hdr_from_disk(&hdr_disk1, &hdr_disk2, hdr, 0);
r = hdr_write_disk(cd, device, hdr, json_area1, 1);
r = hdr_write_disk(device, hdr, json_area1, 1);
}
if (r)
log_dbg(cd, "Secondary LUKS2 header recovery failed.");
log_dbg("Secondary LUKS2 header recovery failed.");
}
} else if (state_hdr1 != HDR_OK && state_hdr2 == HDR_OK) {
log_dbg(cd, "Primary LUKS2 header requires recovery.");
log_dbg("Primary LUKS2 header requires recovery.");
if (do_blkprobe && (r = detect_device_signatures(cd, device_path(device)))) {
if (do_blkprobe && (r = detect_device_signatures(device_path(device)))) {
log_err(cd, _("Device contains ambiguous signatures, cannot auto-recover LUKS2.\n"
"Please run \"cryptsetup repair\" for recovery."));
goto err;
@@ -716,15 +698,15 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
if (do_recovery) {
memcpy(&hdr_disk1, &hdr_disk2, LUKS2_HDR_BIN_LEN);
r = crypt_random_get(cd, (char*)hdr_disk1.salt, sizeof(hdr_disk1.salt), CRYPT_RND_SALT);
r = crypt_random_get(NULL, (char*)hdr_disk1.salt, sizeof(hdr_disk1.salt), CRYPT_RND_SALT);
if (r)
log_dbg(cd, "Cannot generate master salt.");
log_dbg("Cannot generate master salt.");
else {
hdr_from_disk(&hdr_disk2, &hdr_disk1, hdr, 1);
r = hdr_write_disk(cd, device, hdr, json_area2, 0);
r = hdr_write_disk(device, hdr, json_area2, 0);
}
if (r)
log_dbg(cd, "Primary LUKS2 header recovery failed.");
log_dbg("Primary LUKS2 header recovery failed.");
}
}
@@ -756,7 +738,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
*/
return 0;
err:
log_dbg(cd, "LUKS2 header read failed (%d).", r);
log_dbg("LUKS2 header read failed (%d).", r);
free(json_area1);
free(json_area2);
@@ -777,7 +759,7 @@ int LUKS2_hdr_version_unlocked(struct crypt_device *cd, const char *backup_file)
if (!backup_file)
device = crypt_metadata_device(cd);
else if (device_alloc(cd, &device, backup_file) < 0)
else if (device_alloc(&device, backup_file) < 0)
return 0;
if (!device)
@@ -791,7 +773,7 @@ int LUKS2_hdr_version_unlocked(struct crypt_device *cd, const char *backup_file)
if (devfd < 0)
goto err;
if ((read_lseek_blockwise(devfd, device_block_size(cd, device),
if ((read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), &hdr, sizeof(hdr), 0) == sizeof(hdr)) &&
!memcmp(hdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L))
r = (int)be16_to_cpu(hdr.version);
@@ -800,7 +782,7 @@ err:
close(devfd);
if (backup_file)
device_free(cd, device);
device_free(device);
return r;
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -23,6 +23,7 @@
#define _CRYPTSETUP_LUKS2_INTERNAL_H
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <json-c/json.h>
@@ -43,9 +44,7 @@
int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
struct device *device, int do_recovery, int do_blkprobe);
int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr,
struct device *device, bool seqid_check);
int LUKS2_device_write_lock(struct crypt_device *cd,
struct luks2_hdr *hdr, struct device *device);
struct device *device);
/*
* JSON struct access helpers
@@ -55,47 +54,42 @@ json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token);
json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int digest);
json_object *LUKS2_get_segment_jobj(struct luks2_hdr *hdr, int segment);
json_object *LUKS2_get_tokens_jobj(struct luks2_hdr *hdr);
json_object *LUKS2_get_segments_jobj(struct luks2_hdr *hdr);
void hexprint_base64(struct crypt_device *cd, json_object *jobj,
const char *sep, const char *line_sep);
uint64_t crypt_jobj_get_uint64(json_object *jobj);
uint32_t crypt_jobj_get_uint32(json_object *jobj);
json_object *crypt_jobj_new_uint64(uint64_t value);
json_object *parse_json_len(const char *json_area, uint64_t max_length, int *json_len);
uint64_t json_object_get_uint64(json_object *jobj);
uint32_t json_object_get_uint32(json_object *jobj);
json_object *json_object_new_uint64(uint64_t value);
int json_object_object_add_by_uint(json_object *jobj, unsigned key, json_object *jobj_val);
void json_object_object_del_by_uint(json_object *jobj, unsigned key);
int json_object_copy(json_object *jobj_src, json_object **jobj_dst);
void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc);
void JSON_DBG(json_object *jobj, const char *desc);
/*
* LUKS2 JSON validation
*/
/* validation helper */
json_bool validate_json_uint32(json_object *jobj);
json_object *json_contains(struct crypt_device *cd, json_object *jobj, const char *name,
const char *section, const char *key, json_type type);
json_object *json_contains(json_object *jobj, const char *name, const char *section,
const char *key, json_type type);
int LUKS2_hdr_validate(struct crypt_device *cd, json_object *hdr_jobj, uint64_t json_size);
int LUKS2_check_json_size(struct crypt_device *cd, const struct luks2_hdr *hdr);
int LUKS2_token_validate(struct crypt_device *cd, json_object *hdr_jobj,
json_object *jobj_token, const char *key);
int LUKS2_hdr_validate(json_object *hdr_jobj, uint64_t json_size);
int LUKS2_keyslot_validate(json_object *hdr_jobj, json_object *hdr_keyslot, const char *key);
int LUKS2_check_json_size(const struct luks2_hdr *hdr);
int LUKS2_token_validate(json_object *hdr_jobj, json_object *jobj_token, const char *key);
void LUKS2_token_dump(struct crypt_device *cd, int token);
/*
* LUKS2 JSON repair for known glitches
*/
void LUKS2_hdr_repair(struct crypt_device *cd, json_object *jobj_hdr);
void LUKS2_keyslots_repair(struct crypt_device *cd, json_object *jobj_hdr);
void LUKS2_hdr_repair(json_object *jobj_hdr);
void LUKS2_keyslots_repair(json_object *jobj_hdr);
/*
* JSON array helpers
*/
json_object *LUKS2_array_jobj(json_object *array, const char *num);
json_object *LUKS2_array_remove(json_object *array, const char *num);
struct json_object *LUKS2_array_jobj(struct json_object *array, const char *num);
struct json_object *LUKS2_array_remove(struct json_object *array, const char *num);
/*
* Plugins API
@@ -128,7 +122,7 @@ int placeholder_keyslot_alloc(struct crypt_device *cd,
size_t volume_key_len);
/* validate all keyslot implementations in hdr json */
int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj);
int LUKS2_keyslots_validate(json_object *hdr_jobj);
typedef struct {
const char *name;
@@ -142,12 +136,6 @@ typedef struct {
keyslot_repair_func repair;
} keyslot_handler;
/* can not fit prototype alloc function */
int reenc_keyslot_alloc(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params);
/**
* LUKS2 digest handlers (EXPERIMENTAL)
*/
@@ -164,6 +152,8 @@ typedef struct {
digest_dump_func dump;
} digest_handler;
const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type);
/**
* LUKS2 token handlers (internal use only)
*/
@@ -183,148 +173,5 @@ int token_keyring_get(json_object *, void *);
int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
size_t keylength, uint64_t *area_offset, uint64_t *area_length);
int LUKS2_find_area_max_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
uint64_t *area_offset, uint64_t *area_length);
uint64_t LUKS2_hdr_and_areas_size_jobj(json_object *jobj);
int LUKS2_check_cipher(struct crypt_device *cd,
size_t keylength,
const char *cipher,
const char *cipher_mode);
static inline const char *crypt_reencrypt_mode_to_str(crypt_reencrypt_mode_info mi)
{
if (mi == CRYPT_REENCRYPT_REENCRYPT)
return "reencrypt";
if (mi == CRYPT_REENCRYPT_ENCRYPT)
return "encrypt";
if (mi == CRYPT_REENCRYPT_DECRYPT)
return "decrypt";
return "<unknown>";
}
/*
* Generic LUKS2 keyslot
*/
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const void *buffer,
size_t buffer_length);
int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params);
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks);
int LUKS2_keyslot_dump(struct crypt_device *cd,
int keyslot);
int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length);
/* JSON helpers */
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise);
const char *json_segment_type(json_object *jobj_segment);
uint64_t json_segment_get_iv_offset(json_object *jobj_segment);
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise);
const char *json_segment_get_cipher(json_object *jobj_segment);
int json_segment_get_sector_size(json_object *jobj_segment);
bool json_segment_is_backup(json_object *jobj_segment);
json_object *json_segments_get_segment(json_object *jobj_segments, int segment);
unsigned json_segments_count(json_object *jobj_segments);
void json_segment_remove_flag(json_object *jobj_segment, const char *flag);
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise);
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length, const char *cipher, uint32_t sector_size, unsigned reencryption);
int json_segments_segment_in_reencrypt(json_object *jobj_segments);
bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2);
bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len);
int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks,
json_object *jobj_segments,
struct crypt_dm_active_device *dmd);
/*
* Generic LUKS2 segment
*/
int LUKS2_segments_count(struct luks2_hdr *hdr);
int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr);
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag);
json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag);
int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag);
int LUKS2_segments_set(struct crypt_device *cd,
struct luks2_hdr *hdr,
json_object *jobj_segments,
int commit);
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr,
int segment,
unsigned blockwise);
uint64_t LUKS2_segment_size(struct luks2_hdr *hdr,
int segment,
unsigned blockwise);
int LUKS2_segment_is_type(struct luks2_hdr *hdr,
int segment,
const char *type);
int LUKS2_segment_by_type(struct luks2_hdr *hdr,
const char *type);
int LUKS2_last_segment_by_type(struct luks2_hdr *hdr,
const char *type);
int LUKS2_get_default_segment(struct luks2_hdr *hdr);
int LUKS2_reencrypt_digest_new(struct luks2_hdr *hdr);
int LUKS2_reencrypt_digest_old(struct luks2_hdr *hdr);
int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise);
/*
* Generic LUKS2 digest
*/
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int digest,
const struct volume_key *vk);
void LUKS2_digests_erase_unused(struct crypt_device *cd,
struct luks2_hdr *hdr);
int LUKS2_digest_dump(struct crypt_device *cd,
int digest);
/*
* Generic LUKS2 token
*/
int LUKS2_tokens_count(struct luks2_hdr *hdr);
/*
* LUKS2 generic
*/
int LUKS2_reload(struct crypt_device *cd,
const char *name,
struct volume_key *vks,
uint64_t device_size,
uint32_t flags);
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment);
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type);
int LUKS2_set_keyslots_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t data_offset);
#endif

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 header format code
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -21,7 +21,6 @@
#include "luks2_internal.h"
#include <uuid/uuid.h>
#include <assert.h>
struct area {
uint64_t offset;
@@ -39,83 +38,9 @@ static size_t get_min_offset(struct luks2_hdr *hdr)
return 2 * hdr->hdr_size;
}
static size_t get_max_offset(struct luks2_hdr *hdr)
static size_t get_max_offset(struct crypt_device *cd)
{
return LUKS2_hdr_and_areas_size(hdr);
}
int LUKS2_find_area_max_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
uint64_t *area_offset, uint64_t *area_length)
{
struct area areas[LUKS2_KEYSLOTS_MAX], sorted_areas[LUKS2_KEYSLOTS_MAX+1] = {};
int i, j, k, area_i;
size_t valid_offset, offset, length;
/* fill area offset + length table */
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
if (!LUKS2_keyslot_area(hdr, i, &areas[i].offset, &areas[i].length))
continue;
areas[i].length = 0;
areas[i].offset = 0;
}
/* sort table */
k = 0; /* index in sorted table */
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
offset = get_max_offset(hdr) ?: UINT64_MAX;
area_i = -1;
/* search for the smallest offset in table */
for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++)
if (areas[j].offset && areas[j].offset <= offset) {
area_i = j;
offset = areas[j].offset;
}
if (area_i >= 0) {
sorted_areas[k].length = areas[area_i].length;
sorted_areas[k].offset = areas[area_i].offset;
areas[area_i].length = 0;
areas[area_i].offset = 0;
k++;
}
}
sorted_areas[LUKS2_KEYSLOTS_MAX].offset = get_max_offset(hdr);
sorted_areas[LUKS2_KEYSLOTS_MAX].length = 1;
/* search for the gap we can use */
length = valid_offset = 0;
offset = get_min_offset(hdr);
for (i = 0; i < LUKS2_KEYSLOTS_MAX+1; i++) {
/* skip empty */
if (sorted_areas[i].offset == 0 || sorted_areas[i].length == 0)
continue;
/* found bigger gap than the last one */
if ((offset < sorted_areas[i].offset) && (sorted_areas[i].offset - offset) > length) {
length = sorted_areas[i].offset - offset;
valid_offset = offset;
}
/* move beyond allocated area */
offset = sorted_areas[i].offset + sorted_areas[i].length;
}
/* this search 'algorithm' does not work with unaligned areas */
assert(length == size_round_up(length, 4096));
assert(valid_offset == size_round_up(valid_offset, 4096));
if (!length) {
log_dbg(cd, "Not enough space in header keyslot area.");
return -EINVAL;
}
log_dbg(cd, "Found largest free area %zu -> %zu", valid_offset, length + valid_offset);
*area_offset = valid_offset;
*area_length = length;
return 0;
return crypt_get_data_offset(cd) * SECTOR_SIZE;
}
int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
@@ -136,7 +61,7 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
/* sort table */
k = 0; /* index in sorted table */
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
offset = get_max_offset(hdr) ?: UINT64_MAX;
offset = get_max_offset(cd) ?: UINT64_MAX;
area_i = -1;
/* search for the smallest offset in table */
for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++)
@@ -170,13 +95,20 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
offset = sorted_areas[i].offset + sorted_areas[i].length;
}
if ((offset + length) > get_max_offset(hdr)) {
log_dbg(cd, "Not enough space in header keyslot area.");
if (get_max_offset(cd) && (offset + length) > get_max_offset(cd)) {
log_err(cd, _("No space for new keyslot."));
return -EINVAL;
}
log_dbg(cd, "Found area %zu -> %zu", offset, length + offset);
log_dbg("Found area %zu -> %zu", offset, length + offset);
/*
log_dbg("Area offset min: %zu, max %zu, slots max %u",
get_min_offset(hdr), get_max_offset(cd), LUKS2_KEYSLOTS_MAX);
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++)
log_dbg("SLOT[%02i]: %-8" PRIu64 " -> %-8" PRIu64, i,
sorted_areas[i].offset,
sorted_areas[i].length + sorted_areas[i].offset);
*/
*area_offset = offset;
*area_length = length;
return 0;
@@ -207,78 +139,23 @@ int LUKS2_generate_hdr(
const char *integrity,
const char *uuid,
unsigned int sector_size, /* in bytes */
uint64_t data_offset, /* in bytes */
uint64_t align_offset, /* in bytes */
uint64_t required_alignment,
uint64_t metadata_size,
uint64_t keyslots_size)
unsigned int alignPayload, /* in bytes */
unsigned int alignOffset, /* in bytes */
int detached_metadata_device)
{
struct json_object *jobj_segment, *jobj_integrity, *jobj_keyslots, *jobj_segments, *jobj_config;
char cipher[128];
char num[24], cipher[128];
uint64_t offset, json_size, keyslots_size;
uuid_t partitionUuid;
int r, digest;
uint64_t mdev_size;
if (!metadata_size)
metadata_size = LUKS2_HDR_16K_LEN;
hdr->hdr_size = metadata_size;
if (data_offset && data_offset < get_min_offset(hdr)) {
log_err(cd, _("Requested data offset is too small."));
return -EINVAL;
}
/* Increase keyslot size according to data offset */
if (!keyslots_size && data_offset)
keyslots_size = data_offset - get_min_offset(hdr);
/* keyslots size has to be 4 KiB aligned */
keyslots_size -= (keyslots_size % 4096);
if (keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE)
keyslots_size = LUKS2_MAX_KEYSLOTS_SIZE;
if (!keyslots_size) {
assert(LUKS2_DEFAULT_HDR_SIZE > 2 * LUKS2_HDR_OFFSET_MAX);
keyslots_size = LUKS2_DEFAULT_HDR_SIZE - get_min_offset(hdr);
/* Decrease keyslots_size due to metadata device being too small */
if (!device_size(crypt_metadata_device(cd), &mdev_size) &&
((keyslots_size + get_min_offset(hdr)) > mdev_size) &&
device_fallocate(crypt_metadata_device(cd), keyslots_size + get_min_offset(hdr)) &&
(get_min_offset(hdr) <= mdev_size))
keyslots_size = mdev_size - get_min_offset(hdr);
}
/* Decrease keyslots_size if we have smaller data_offset */
if (data_offset && (keyslots_size + get_min_offset(hdr)) > data_offset) {
keyslots_size = data_offset - get_min_offset(hdr);
log_dbg(cd, "Decreasing keyslot area size to %" PRIu64
" bytes due to the requested data offset %"
PRIu64 " bytes.", keyslots_size, data_offset);
}
/* Data offset has priority */
if (!data_offset && required_alignment) {
data_offset = size_round_up(get_min_offset(hdr) + keyslots_size,
(size_t)required_alignment);
data_offset += align_offset;
}
log_dbg(cd, "Formatting LUKS2 with JSON metadata area %" PRIu64
" bytes and keyslots area %" PRIu64 " bytes.",
metadata_size - LUKS2_HDR_BIN_LEN, keyslots_size);
if (keyslots_size < (LUKS2_HDR_OFFSET_MAX - 2*LUKS2_HDR_16K_LEN))
log_std(cd, _("WARNING: keyslots area (%" PRIu64 " bytes) is very small,"
" available LUKS2 keyslot count is very limited.\n"),
keyslots_size);
int digest;
hdr->hdr_size = LUKS2_HDR_16K_LEN;
hdr->seqid = 1;
hdr->version = 2;
memset(hdr->label, 0, LUKS2_LABEL_L);
strcpy(hdr->checksum_alg, "sha256");
crypt_random_get(cd, (char*)hdr->salt1, LUKS2_SALT_L, CRYPT_RND_SALT);
crypt_random_get(cd, (char*)hdr->salt2, LUKS2_SALT_L, CRYPT_RND_SALT);
crypt_random_get(NULL, (char*)hdr->salt1, LUKS2_SALT_L, CRYPT_RND_SALT);
crypt_random_get(NULL, (char*)hdr->salt2, LUKS2_SALT_L, CRYPT_RND_SALT);
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
log_err(cd, _("Wrong LUKS UUID format provided."));
@@ -290,11 +167,9 @@ int LUKS2_generate_hdr(
uuid_unparse(partitionUuid, hdr->uuid);
if (*cipherMode != '\0')
r = snprintf(cipher, sizeof(cipher), "%s-%s", cipherName, cipherMode);
snprintf(cipher, sizeof(cipher), "%s-%s", cipherName, cipherMode);
else
r = snprintf(cipher, sizeof(cipher), "%s", cipherName);
if (r < 0 || (size_t)r >= sizeof(cipher))
return -EINVAL;
snprintf(cipher, sizeof(cipher), "%s", cipherName);
hdr->jobj = json_object_new_object();
@@ -308,15 +183,34 @@ int LUKS2_generate_hdr(
json_object_object_add(hdr->jobj, "config", jobj_config);
digest = LUKS2_digest_create(cd, "pbkdf2", hdr, vk);
if (digest < 0)
goto err;
if (digest < 0) {
json_object_put(hdr->jobj);
hdr->jobj = NULL;
return -EINVAL;
}
if (LUKS2_digest_segment_assign(cd, hdr, 0, digest, 1, 0) < 0)
goto err;
if (LUKS2_digest_segment_assign(cd, hdr, CRYPT_DEFAULT_SEGMENT, digest, 1, 0) < 0) {
json_object_put(hdr->jobj);
hdr->jobj = NULL;
return -EINVAL;
}
jobj_segment = json_segment_create_crypt(data_offset, 0, NULL, cipher, sector_size, 0);
if (!jobj_segment)
goto err;
jobj_segment = json_object_new_object();
json_object_object_add(jobj_segment, "type", json_object_new_string("crypt"));
if (detached_metadata_device)
offset = (uint64_t)alignPayload;
else {
//FIXME
//offset = size_round_up(areas[7].offset + areas[7].length, alignPayload * SECTOR_SIZE);
offset = size_round_up(LUKS2_HDR_DEFAULT_LEN, (size_t)alignPayload);
offset += alignOffset;
}
json_object_object_add(jobj_segment, "offset", json_object_new_uint64(offset));
json_object_object_add(jobj_segment, "iv_tweak", json_object_new_string("0"));
json_object_object_add(jobj_segment, "size", json_object_new_string("dynamic"));
json_object_object_add(jobj_segment, "encryption", json_object_new_string(cipher));
json_object_object_add(jobj_segment, "sector_size", json_object_new_int(sector_size));
if (integrity) {
jobj_integrity = json_object_new_object();
@@ -326,21 +220,34 @@ int LUKS2_generate_hdr(
json_object_object_add(jobj_segment, "integrity", jobj_integrity);
}
json_object_object_add_by_uint(jobj_segments, 0, jobj_segment);
snprintf(num, sizeof(num), "%u", CRYPT_DEFAULT_SEGMENT);
json_object_object_add(jobj_segments, num, jobj_segment);
json_object_object_add(jobj_config, "json_size", crypt_jobj_new_uint64(metadata_size - LUKS2_HDR_BIN_LEN));
json_object_object_add(jobj_config, "keyslots_size", crypt_jobj_new_uint64(keyslots_size));
json_size = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
json_object_object_add(jobj_config, "json_size", json_object_new_uint64(json_size));
JSON_DBG(cd, hdr->jobj, "Header JSON:");
/* for detached metadata device compute reasonable keyslot areas size */
// FIXME: this is coupled with FIXME above
if (detached_metadata_device && !offset)
keyslots_size = LUKS2_HDR_DEFAULT_LEN - get_min_offset(hdr);
else
keyslots_size = offset - get_min_offset(hdr);
/* keep keyslots_size reasonable for custom data alignments */
if (keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE)
keyslots_size = LUKS2_MAX_KEYSLOTS_SIZE;
/* keyslots size has to be 4 KiB aligned */
keyslots_size -= (keyslots_size % 4096);
json_object_object_add(jobj_config, "keyslots_size", json_object_new_uint64(keyslots_size));
JSON_DBG(hdr->jobj, "Header JSON");
return 0;
err:
json_object_put(hdr->jobj);
hdr->jobj = NULL;
return -EINVAL;
}
int LUKS2_wipe_header_areas(struct crypt_device *cd,
struct luks2_hdr *hdr, bool detached_header)
struct luks2_hdr *hdr)
{
int r;
uint64_t offset, length;
@@ -351,16 +258,16 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
length = LUKS2_get_data_offset(hdr) * SECTOR_SIZE;
wipe_block = 1024 * 1024;
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
if (LUKS2_hdr_validate(hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
return -EINVAL;
/* On detached header wipe at least the first 4k */
if (detached_header) {
if (length == 0) {
length = 4096;
wipe_block = 4096;
}
log_dbg(cd, "Wiping LUKS areas (0x%06" PRIx64 " - 0x%06" PRIx64") with zeroes.",
log_dbg("Wiping LUKS areas (0x%06" PRIx64 " - 0x%06" PRIx64") with zeroes.",
offset, length + offset);
r = crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_ZERO,
@@ -371,38 +278,11 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
/* Wipe keyslot area */
wipe_block = 1024 * 1024;
offset = get_min_offset(hdr);
length = LUKS2_keyslots_size(hdr);
length = LUKS2_keyslots_size(hdr->jobj);
log_dbg(cd, "Wiping keyslots area (0x%06" PRIx64 " - 0x%06" PRIx64") with random data.",
log_dbg("Wiping keyslots area (0x%06" PRIx64 " - 0x%06" PRIx64") with random data.",
offset, length + offset);
return crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_RANDOM,
offset, length, wipe_block, NULL, NULL);
}
/* FIXME: what if user wanted to keep original keyslots size? */
int LUKS2_set_keyslots_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t data_offset)
{
json_object *jobj_config;
uint64_t keyslots_size;
if (data_offset < get_min_offset(hdr))
return 1;
keyslots_size = data_offset - get_min_offset(hdr);
/* keep keyslots_size reasonable for custom data alignments */
if (keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE)
keyslots_size = LUKS2_MAX_KEYSLOTS_SIZE;
/* keyslots size has to be 4 KiB aligned */
keyslots_size -= (keyslots_size % 4096);
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
return 1;
json_object_object_add(jobj_config, "keyslots_size", crypt_jobj_new_uint64(keyslots_size));
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, keyslot handling
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -23,13 +23,9 @@
/* Internal implementations */
extern const keyslot_handler luks2_keyslot;
extern const keyslot_handler reenc_keyslot;
static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
&luks2_keyslot,
#if USE_LUKS2_REENCRYPTION
&reenc_keyslot,
#endif
NULL
};
@@ -67,7 +63,7 @@ static const keyslot_handler
return LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj2));
}
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr)
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
{
int i;
@@ -78,55 +74,24 @@ int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr)
return -EINVAL;
}
/* Check if a keyslot is assigned to specific segment */
static int _keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
{
int keyslot_digest, count = 0;
unsigned s;
keyslot_digest = LUKS2_digest_by_keyslot(hdr, keyslot);
if (keyslot_digest < 0)
return keyslot_digest;
if (segment >= 0)
return keyslot_digest == LUKS2_digest_by_segment(hdr, segment);
for (s = 0; s < json_segments_count(LUKS2_get_segments_jobj(hdr)); s++) {
if (keyslot_digest == LUKS2_digest_by_segment(hdr, s))
count++;
}
return count;
}
static int _keyslot_for_digest(struct luks2_hdr *hdr, int keyslot, int digest)
{
int r = -EINVAL;
r = LUKS2_digest_by_keyslot(hdr, keyslot);
if (r < 0)
return r;
return r == digest ? 0 : -ENOENT;
}
/* Check if a keyslot is asssigned to specific segment */
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
{
int r = -EINVAL;
int keyslot_digest, segment_digest;
/* no need to check anything */
if (segment == CRYPT_ANY_SEGMENT)
return 0; /* ok */
if (segment == CRYPT_DEFAULT_SEGMENT) {
segment = LUKS2_get_default_segment(hdr);
if (segment < 0)
return segment;
}
return 0;
r = _keyslot_for_segment(hdr, keyslot, segment);
if (r < 0)
return r;
keyslot_digest = LUKS2_digest_by_keyslot(NULL, hdr, keyslot);
if (keyslot_digest < 0)
return -EINVAL;
return r >= 1 ? 0 : -ENOENT;
segment_digest = LUKS2_digest_by_segment(NULL, hdr, segment);
if (segment_digest < 0)
return segment_digest;
return segment_digest == keyslot_digest ? 0 : -ENOENT;
}
/* Number of keyslots assigned to a segment or all keyslots for CRYPT_ANY_SEGMENT */
@@ -146,18 +111,13 @@ int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
return num;
}
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd, const char *cipher_spec)
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd)
{
char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
if (!cipher_spec || crypt_is_cipher_null(cipher_spec))
return 1;
if (crypt_parse_name_and_mode(cipher_spec, cipher, NULL, cipher_mode) < 0)
return 1;
const char *cipher = crypt_get_cipher(cd);
const char *cipher_mode = crypt_get_cipher_mode(cd);
/* Keyslot is already authenticated; we cannot use integrity tags here */
if (crypt_get_integrity_tag_size(cd))
if (crypt_get_integrity_tag_size(cd) || !cipher)
return 1;
/* Wrapped key schemes cannot be used for keyslot encryption */
@@ -172,75 +132,45 @@ int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd, const char *ciphe
}
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
struct luks2_keyslot_params *params)
size_t key_size, struct luks2_keyslot_params *params)
{
int r, integrity_key_size = crypt_get_integrity_key_size(cd);
const struct crypt_pbkdf_type *pbkdf = crypt_get_pbkdf_type(cd);
const char *cipher_spec;
size_t key_size;
int r;
if (!hdr || !pbkdf || !params)
return -EINVAL;
/*
* set keyslot area encryption parameters
*/
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
params->area_type = LUKS2_KEYSLOT_AREA_RAW;
cipher_spec = crypt_keyslot_get_encryption(cd, CRYPT_ANY_SLOT, &key_size);
if (!cipher_spec || !key_size)
/* set keyslot AF parameters */
/* currently we use hash for AF from pbkdf settings */
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash),
"%s", pbkdf->hash);
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
return -EINVAL;
params->area.raw.key_size = key_size;
r = snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption), "%s", cipher_spec);
params->af.luks1.stripes = 4000;
/* set keyslot area encryption parameters */
/* short circuit authenticated encryption hardcoded defaults */
if (LUKS2_keyslot_cipher_incompatible(cd) || key_size == 0) {
// FIXME: fixed cipher and key size can be wrong
snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption),
"aes-xts-plain64");
params->area.raw.key_size = 32;
return 0;
}
r = snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption),
"%s", LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT));
if (r < 0 || (size_t)r >= sizeof(params->area.raw.encryption))
return -EINVAL;
/*
* set keyslot AF parameters
*/
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
/* currently we use hash for AF from pbkdf settings */
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash), "%s", pbkdf->hash ?: DEFAULT_LUKS1_HASH);
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
/* Slot encryption tries to use the same key size as for the main algorithm */
if ((size_t)integrity_key_size > key_size)
return -EINVAL;
params->af.luks1.stripes = 4000;
return 0;
}
int LUKS2_keyslot_pbkdf(struct luks2_hdr *hdr, int keyslot, struct crypt_pbkdf_type *pbkdf)
{
json_object *jobj_keyslot, *jobj_kdf, *jobj;
if (!hdr || !pbkdf)
return -EINVAL;
if (LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID)
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -ENOENT;
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf))
return -EINVAL;
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj))
return -EINVAL;
memset(pbkdf, 0, sizeof(*pbkdf));
pbkdf->type = json_object_get_string(jobj);
if (json_object_object_get_ex(jobj_kdf, "hash", &jobj))
pbkdf->hash = json_object_get_string(jobj);
if (json_object_object_get_ex(jobj_kdf, "iterations", &jobj))
pbkdf->iterations = json_object_get_int(jobj);
if (json_object_object_get_ex(jobj_kdf, "time", &jobj))
pbkdf->iterations = json_object_get_int(jobj);
if (json_object_object_get_ex(jobj_kdf, "memory", &jobj))
pbkdf->max_memory_kb = json_object_get_int(jobj);
if (json_object_object_get_ex(jobj_kdf, "cpus", &jobj))
pbkdf->parallel_threads = json_object_get_int(jobj);
params->area.raw.key_size = key_size - integrity_key_size;
return 0;
}
@@ -248,7 +178,7 @@ int LUKS2_keyslot_pbkdf(struct luks2_hdr *hdr, int keyslot, struct crypt_pbkdf_t
static int LUKS2_keyslot_unbound(struct luks2_hdr *hdr, int keyslot)
{
json_object *jobj_digest, *jobj_segments;
int digest = LUKS2_digest_by_keyslot(hdr, keyslot);
int digest = LUKS2_digest_by_keyslot(NULL, hdr, keyslot);
if (digest < 0)
return 0;
@@ -272,8 +202,7 @@ crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot)
if (!LUKS2_get_keyslot_jobj(hdr, keyslot))
return CRYPT_SLOT_INACTIVE;
if (LUKS2_digest_by_keyslot(hdr, keyslot) < 0 ||
LUKS2_keyslot_unbound(hdr, keyslot))
if (LUKS2_keyslot_unbound(hdr, keyslot))
return CRYPT_SLOT_UNBOUND;
if (LUKS2_keyslot_active_count(hdr, CRYPT_DEFAULT_SEGMENT) == 1 &&
@@ -283,102 +212,32 @@ crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot)
return CRYPT_SLOT_ACTIVE;
}
int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length)
{
json_object *jobj_area, *jobj;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
if (!json_object_object_get_ex(jobj_area, "offset", &jobj))
return -EINVAL;
*offset = crypt_jobj_get_uint64(jobj);
if (!json_object_object_get_ex(jobj_area, "size", &jobj))
return -EINVAL;
*length = crypt_jobj_get_uint64(jobj);
return 0;
}
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length)
{
json_object *jobj_keyslot;
json_object *jobj_keyslot, *jobj_area, *jobj;
if (LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID)
if(LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID)
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -ENOENT;
return LUKS2_keyslot_jobj_area(jobj_keyslot, offset, length);
}
static int _open_and_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
const keyslot_handler *h,
int keyslot,
const char *password,
size_t password_len,
struct volume_key **vk)
{
int r, key_size = LUKS2_get_keyslot_stored_key_size(hdr, keyslot);
if (key_size < 0)
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
*vk = crypt_alloc_volume_key(key_size, NULL);
if (!*vk)
return -ENOMEM;
if (!json_object_object_get_ex(jobj_area, "offset", &jobj))
return -EINVAL;
*offset = json_object_get_int64(jobj);
r = h->open(cd, keyslot, password, password_len, (*vk)->key, (*vk)->keylength);
if (r < 0)
log_dbg(cd, "Keyslot %d (%s) open failed with %d.", keyslot, h->name, r);
else
r = LUKS2_digest_verify(cd, hdr, *vk, keyslot);
if (!json_object_object_get_ex(jobj_area, "size", &jobj))
return -EINVAL;
*length = json_object_get_int64(jobj);
if (r < 0) {
crypt_free_volume_key(*vk);
*vk = NULL;
}
crypt_volume_key_set_id(*vk, r);
return r < 0 ? r : keyslot;
}
static int LUKS2_open_and_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int digest,
const char *password,
size_t password_len,
struct volume_key **vk)
{
const keyslot_handler *h;
int r;
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
return -ENOENT;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot %d validation failed.", keyslot);
return r;
}
r = _keyslot_for_digest(hdr, keyslot, digest);
if (r) {
if (r == -ENOENT)
log_dbg(cd, "Keyslot %d unusable for digest %d.", keyslot, digest);
return r;
}
return _open_and_verify(cd, hdr, h, keyslot, password, password_len, vk);
return 0;
}
static int LUKS2_open_and_verify(struct crypt_device *cd,
@@ -390,63 +249,46 @@ static int LUKS2_open_and_verify(struct crypt_device *cd,
struct volume_key **vk)
{
const keyslot_handler *h;
int r;
int key_size, r;
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
return -ENOENT;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot %d validation failed.", keyslot);
log_dbg("Keyslot %d validation failed.", keyslot);
return r;
}
r = LUKS2_keyslot_for_segment(hdr, keyslot, segment);
if (r) {
if (r == -ENOENT)
log_dbg(cd, "Keyslot %d unusable for segment %d.", keyslot, segment);
log_dbg("Keyslot %d unusable for segment %d.", keyslot, segment);
return r;
}
return _open_and_verify(cd, hdr, h, keyslot, password, password_len, vk);
}
key_size = LUKS2_get_volume_key_size(hdr, segment);
if (key_size < 0)
key_size = LUKS2_get_keyslot_key_size(hdr, keyslot);
if (key_size < 0)
return -EINVAL;
static int LUKS2_keyslot_open_priority_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
crypt_keyslot_priority priority,
const char *password,
size_t password_len,
int digest,
struct volume_key **vk)
{
json_object *jobj_keyslots, *jobj;
crypt_keyslot_priority slot_priority;
int keyslot, r = -ENOENT;
*vk = crypt_alloc_volume_key(key_size, NULL);
if (!*vk)
return -ENOMEM;
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
r = h->open(cd, keyslot, password, password_len, (*vk)->key, (*vk)->keylength);
if (r < 0)
log_dbg("Keyslot %d (%s) open failed with %d.", keyslot, h->name, r);
else
r = LUKS2_digest_verify(cd, hdr, *vk, keyslot);
json_object_object_foreach(jobj_keyslots, slot, val) {
if (!json_object_object_get_ex(val, "priority", &jobj))
slot_priority = CRYPT_SLOT_PRIORITY_NORMAL;
else
slot_priority = json_object_get_int(jobj);
keyslot = atoi(slot);
if (slot_priority != priority) {
log_dbg(cd, "Keyslot %d priority %d != %d (required), skipped.",
keyslot, slot_priority, priority);
continue;
}
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
/* Do not retry for errors that are no -EPERM or -ENOENT,
former meaning password wrong, latter key slot unusable for segment */
if ((r != -EPERM) && (r != -ENOENT))
break;
if (r < 0) {
crypt_free_volume_key(*vk);
*vk = NULL;
}
return r;
return r < 0 ? r : keyslot;
}
static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
@@ -471,7 +313,7 @@ static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
keyslot = atoi(slot);
if (slot_priority != priority) {
log_dbg(cd, "Keyslot %d priority %d != %d (required), skipped.",
log_dbg("Keyslot %d priority %d != %d (required), skipped.",
keyslot, slot_priority, priority);
continue;
}
@@ -487,79 +329,6 @@ static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
return r;
}
static int LUKS2_keyslot_open_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int digest,
const char *password,
size_t password_len,
struct volume_key **vk)
{
int r_prio, r = -EINVAL;
if (digest < 0)
return r;
if (keyslot == CRYPT_ANY_SLOT) {
r_prio = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_PREFER,
password, password_len, digest, vk);
if (r_prio >= 0)
r = r_prio;
else if (r_prio != -EPERM && r_prio != -ENOENT)
r = r_prio;
else
r = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_NORMAL,
password, password_len, digest, vk);
/* Prefer password wrong to no entry from priority slot */
if (r_prio == -EPERM && r == -ENOENT)
r = r_prio;
} else
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
return r;
}
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
const char *password,
size_t password_len,
struct volume_key **vks)
{
struct volume_key *vk = NULL;
int digest_old, digest_new, r = -EINVAL;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
digest_old = LUKS2_reencrypt_digest_old(hdr);
if (digest_old >= 0) {
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_old, keyslot_old);
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_old, digest_old, password, password_len, &vk);
if (r < 0)
goto out;
crypt_volume_key_add_next(vks, vk);
}
digest_new = LUKS2_reencrypt_digest_new(hdr);
if (digest_new >= 0 && digest_old != digest_new) {
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_new, keyslot_new);
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_new, digest_new, password, password_len, &vk);
if (r < 0)
goto out;
crypt_volume_key_add_next(vks, vk);
}
out:
if (r < 0) {
crypt_free_volume_key(*vks);
*vks = NULL;
if (r == -ENOMEM)
log_err(cd, _("Not enough available memory to open a keyslot."));
else if (r != -EPERM)
log_err(cd, _("Keyslot open failed."));
}
return r;
}
int LUKS2_keyslot_open(struct crypt_device *cd,
int keyslot,
int segment,
@@ -588,71 +357,9 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
} else
r = LUKS2_open_and_verify(cd, hdr, keyslot, segment, password, password_len, vk);
if (r < 0) {
if (r == -ENOMEM)
log_err(cd, _("Not enough available memory to open a keyslot."));
else if (r != -EPERM)
log_err(cd, _("Keyslot open failed."));
}
return r;
}
int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params)
{
const keyslot_handler *h;
int r;
if (keyslot == CRYPT_ANY_SLOT)
return -EINVAL;
/* FIXME: find keyslot by type */
h = LUKS2_keyslot_handler_type(cd, "reencrypt");
if (!h)
return -EINVAL;
r = reenc_keyslot_alloc(cd, hdr, keyslot, params);
if (r < 0)
return r;
r = LUKS2_keyslot_priority_set(cd, hdr, keyslot, CRYPT_SLOT_PRIORITY_IGNORE, 0);
if (r < 0)
return r;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot validation failed.");
return r;
}
return 0;
}
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const void *buffer,
size_t buffer_length)
{
const keyslot_handler *h;
int r;
if (!(h = LUKS2_keyslot_handler(cd, keyslot)) || strcmp(h->name, "reencrypt"))
return -EINVAL;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot validation failed.");
return r;
}
return h->store(cd, keyslot, NULL, 0,
buffer, buffer_length);
}
int LUKS2_keyslot_store(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -682,20 +389,17 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
r = h->update(cd, keyslot, params);
if (r) {
log_dbg(cd, "Failed to update keyslot %d json.", keyslot);
log_dbg("Failed to update keyslot %d json.", keyslot);
return r;
}
}
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot validation failed.");
log_dbg("Keyslot validation failed.");
return r;
}
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
return -EINVAL;
return h->store(cd, keyslot, password, password_len,
vk->key, vk->keylength);
}
@@ -707,6 +411,7 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
{
struct device *device = crypt_metadata_device(cd);
uint64_t area_offset, area_length;
char num[16];
int r;
json_object *jobj_keyslot, *jobj_keyslots;
const keyslot_handler *h;
@@ -721,17 +426,23 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
return -ENOENT;
if (wipe_area_only)
log_dbg(cd, "Wiping keyslot %d area only.", keyslot);
log_dbg("Wiping keyslot %d area only.", keyslot);
r = LUKS2_device_write_lock(cd, hdr, device);
if (r)
/* Just check that nobody uses the metadata now */
r = device_write_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire write lock on device %s."),
device_path(device));
return r;
}
device_write_unlock(device);
/* secure deletion of possible key material in keyslot area */
r = crypt_keyslot_area(cd, keyslot, &area_offset, &area_length);
if (r && r != -ENOENT)
goto out;
return r;
/* We can destroy the binary keyslot area now without lock */
if (!r) {
r = crypt_wipe_device(cd, device, CRYPT_WIPE_SPECIAL, area_offset,
area_length, area_length, NULL, NULL);
@@ -742,27 +453,25 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
r = -EINVAL;
} else
log_err(cd, _("Cannot wipe device %s."), device_path(device));
goto out;
return r;
}
}
if (wipe_area_only)
goto out;
return r;
/* Slot specific wipe */
if (h) {
r = h->wipe(cd, keyslot);
if (r < 0)
goto out;
return r;
} else
log_dbg(cd, "Wiping keyslot %d without specific-slot handler loaded.", keyslot);
log_dbg("Wiping keyslot %d without specific-slot handler loaded.", keyslot);
json_object_object_del_by_uint(jobj_keyslots, keyslot);
snprintf(num, sizeof(num), "%d", keyslot);
json_object_object_del(jobj_keyslots, num);
r = LUKS2_hdr_write(cd, hdr);
out:
device_write_unlock(cd, crypt_metadata_device(cd));
return r;
return LUKS2_hdr_write(cd, hdr);
}
int LUKS2_keyslot_dump(struct crypt_device *cd, int keyslot)
@@ -814,9 +523,10 @@ int placeholder_keyslot_alloc(struct crypt_device *cd,
size_t volume_key_len)
{
struct luks2_hdr *hdr;
char num[16];
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
log_dbg(cd, "Allocating placeholder keyslot %d for LUKS1 down conversion.", keyslot);
log_dbg("Allocating placeholder keyslot %d for LUKS1 down conversion.", keyslot);
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
@@ -841,11 +551,13 @@ int placeholder_keyslot_alloc(struct crypt_device *cd,
/* Area object */
jobj_area = json_object_new_object();
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(area_offset));
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length));
json_object_object_add(jobj_area, "offset", json_object_new_uint64(area_offset));
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_length));
json_object_object_add(jobj_keyslot, "area", jobj_area);
json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
snprintf(num, sizeof(num), "%d", keyslot);
json_object_object_add(jobj_keyslots, num, jobj_keyslot);
return 0;
}
@@ -873,61 +585,36 @@ static unsigned LUKS2_get_keyslot_digests_count(json_object *hdr_jobj, int keysl
}
/* run only on header that passed basic format validation */
int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
int LUKS2_keyslots_validate(json_object *hdr_jobj)
{
const keyslot_handler *h;
int keyslot;
json_object *jobj_keyslots, *jobj_type;
uint32_t reqs, reencrypt_count = 0;
struct luks2_hdr dummy = {
.jobj = hdr_jobj
};
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return -EINVAL;
if (LUKS2_config_get_requirements(cd, &dummy, &reqs))
return -EINVAL;
json_object_object_foreach(jobj_keyslots, slot, val) {
keyslot = atoi(slot);
json_object_object_get_ex(val, "type", &jobj_type);
h = LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj_type));
h = LUKS2_keyslot_handler_type(NULL, json_object_get_string(jobj_type));
if (!h)
continue;
if (h->validate && h->validate(cd, val)) {
log_dbg(cd, "Keyslot type %s validation failed on keyslot %d.", h->name, keyslot);
if (h->validate && h->validate(NULL, val)) {
log_dbg("Keyslot type %s validation failed on keyslot %d.", h->name, keyslot);
return -EINVAL;
}
if (!strcmp(h->name, "luks2") && LUKS2_get_keyslot_digests_count(hdr_jobj, keyslot) != 1) {
log_dbg(cd, "Keyslot %d is not assigned to exactly 1 digest.", keyslot);
log_dbg("Keyslot %d is not assigned to exactly 1 digest.", keyslot);
return -EINVAL;
}
if (!strcmp(h->name, "reencrypt"))
reencrypt_count++;
}
if ((reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count == 0) {
log_dbg(cd, "Missing reencryption keyslot.");
return -EINVAL;
}
if (!(reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count) {
log_dbg(cd, "Missing reencryption requirement flag.");
return -EINVAL;
}
if (reencrypt_count > 1) {
log_dbg(cd, "Too many reencryption keyslots.");
return -EINVAL;
}
return 0;
}
void LUKS2_keyslots_repair(struct crypt_device *cd, json_object *jobj_keyslots)
void LUKS2_keyslots_repair(json_object *jobj_keyslots)
{
const keyslot_handler *h;
json_object *jobj_type;
@@ -939,30 +626,8 @@ void LUKS2_keyslots_repair(struct crypt_device *cd, json_object *jobj_keyslots)
!json_object_is_type(jobj_type, json_type_string))
continue;
h = LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj_type));
h = LUKS2_keyslot_handler_type(NULL, json_object_get_string(jobj_type));
if (h && h->repair)
h->repair(cd, val);
h->repair(NULL, val);
}
}
/* assumes valid header */
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type)
{
int i;
json_object *jobj_keyslot, *jobj_type;
if (!type)
return -EINVAL;
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, i);
if (!jobj_keyslot)
continue;
json_object_object_get_ex(jobj_keyslot, "type", &jobj_type);
if (!strcmp(json_object_get_string(jobj_type), type))
return i;
}
return -ENOENT;
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 type keyslot handler
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -28,52 +28,65 @@
#define LUKS_SLOT_ITERATIONS_MIN 1000
#define LUKS_STRIPES 4000
/* Serialize memory-hard keyslot access: optional workaround for parallel processing */
#define MIN_MEMORY_FOR_SERIALIZE_LOCK_KB 32*1024 /* 32MB */
static int luks2_encrypt_to_storage(char *src, size_t srcLength,
const char *cipher, const char *cipher_mode,
struct volume_key *vk, unsigned int sector,
struct crypt_device *cd)
{
struct device *device = crypt_metadata_device(cd);
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
return LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd);
int r = device_write_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire write lock on device %s."), device_path(device));
return r;
}
r = LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd);
device_write_unlock(crypt_metadata_device(cd));
return r;
#else
struct crypt_storage *s;
int devfd, r;
struct device *device = crypt_metadata_device(cd);
int devfd = -1, r;
/* Only whole sector writes supported */
if (MISALIGNED_512(srcLength))
return -EINVAL;
/* Encrypt buffer */
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
if (r) {
log_err(cd, _("Cannot use %s-%s cipher for keyslot encryption."), cipher, cipher_mode);
log_dbg("Userspace crypto wrapper cannot use %s-%s (%d).",
cipher, cipher_mode, r);
return r;
}
r = crypt_storage_encrypt(s, 0, srcLength, src);
r = crypt_storage_encrypt(s, 0, srcLength / SECTOR_SIZE, src);
crypt_storage_destroy(s);
if (r)
return r;
r = device_write_lock(cd, device);
if (r) {
log_err(cd, _("IO error while encrypting keyslot."));
log_err(cd, _("Failed to acquire write lock on device %s."),
device_path(device));
return r;
}
devfd = device_open_locked(cd, device, O_RDWR);
devfd = device_open_locked(device, O_RDWR);
if (devfd >= 0) {
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
if (write_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), src,
srcLength, sector * SECTOR_SIZE) < 0)
r = -EIO;
else
r = 0;
device_sync(cd, device);
device_sync(device, devfd);
close(devfd);
} else
r = -EIO;
device_write_unlock(device);
if (r)
log_err(cd, _("IO error while encrypting keyslot."));
@@ -93,19 +106,20 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
return r;
}
r = LUKS_decrypt_from_storage(dst, dstLength, cipher, cipher_mode, vk, sector, cd);
device_read_unlock(cd, crypt_metadata_device(cd));
device_read_unlock(crypt_metadata_device(cd));
return r;
#else
struct crypt_storage *s;
int devfd, r;
int devfd = -1, r;
/* Only whole sector writes supported */
if (MISALIGNED_512(dstLength))
return -EINVAL;
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
if (r) {
log_err(cd, _("Cannot use %s-%s cipher for keyslot encryption."), cipher, cipher_mode);
log_dbg("Userspace crypto wrapper cannot use %s-%s (%d).",
cipher, cipher_mode, r);
return r;
}
@@ -117,22 +131,23 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
return r;
}
devfd = device_open_locked(cd, device, O_RDONLY);
devfd = device_open_locked(device, O_RDONLY);
if (devfd >= 0) {
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), dst,
dstLength, sector * SECTOR_SIZE) < 0)
r = -EIO;
else
r = 0;
close(devfd);
} else
r = -EIO;
device_read_unlock(cd, device);
device_read_unlock(device);
/* Decrypt buffer */
if (!r)
r = crypt_storage_decrypt(s, 0, dstLength, dst);
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
else
log_err(cd, _("IO error while decrypting keyslot."));
@@ -220,7 +235,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
if (!json_object_object_get_ex(jobj_area, "offset", &jobj2))
return -EINVAL;
area_offset = crypt_jobj_get_uint64(jobj2);
area_offset = json_object_get_uint64(jobj2);
if (!json_object_object_get_ex(jobj_area, "encryption", &jobj2))
return -EINVAL;
@@ -266,10 +281,10 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
return -ENOMEM;
}
r = AF_split(cd, volume_key, AfKey, volume_key_len, LUKS_STRIPES, af_hash);
r = AF_split(volume_key, AfKey, volume_key_len, LUKS_STRIPES, af_hash);
if (r == 0) {
log_dbg(cd, "Updating keyslot area [0x%04x].", (unsigned)area_offset);
log_dbg("Updating keyslot area [0x%04x].", (unsigned)area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_encrypt... accordingly */
r = luks2_encrypt_to_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
@@ -297,7 +312,6 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
json_object *jobj2, *jobj_af, *jobj_area;
uint64_t area_offset;
size_t keyslot_key_len;
bool try_serialize_lock = false;
int r;
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
@@ -313,7 +327,7 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
if (!json_object_object_get_ex(jobj_area, "offset", &jobj2))
return -EINVAL;
area_offset = crypt_jobj_get_uint64(jobj2);
area_offset = json_object_get_uint64(jobj2);
if (!json_object_object_get_ex(jobj_area, "encryption", &jobj2))
return -EINVAL;
@@ -325,13 +339,6 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
return -EINVAL;
keyslot_key_len = json_object_get_int(jobj2);
/*
* If requested, serialize unlocking for memory-hard KDF. Usually NOOP.
*/
if (pbkdf.max_memory_kb > MIN_MEMORY_FOR_SERIALIZE_LOCK_KB)
try_serialize_lock = true;
if (try_serialize_lock && crypt_serialize_lock(cd))
return -EINVAL;
/*
* Allocate derived key storage space.
*/
@@ -354,18 +361,15 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
pbkdf.iterations, pbkdf.max_memory_kb,
pbkdf.parallel_threads);
if (try_serialize_lock)
crypt_serialize_unlock(cd);
if (r == 0) {
log_dbg(cd, "Reading keyslot area [0x%04x].", (unsigned)area_offset);
log_dbg("Reading keyslot area [0x%04x].", (unsigned)area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
r = luks2_decrypt_from_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
}
if (r == 0)
r = AF_merge(cd, AfKey, volume_key, volume_key_len, LUKS_STRIPES, af_hash);
r = AF_merge(AfKey, volume_key, volume_key_len, LUKS_STRIPES, af_hash);
crypt_free_volume_key(derived_key);
crypt_safe_free(AfKey);
@@ -384,25 +388,27 @@ static int luks2_keyslot_update_json(struct crypt_device *cd,
const struct luks2_keyslot_params *params)
{
const struct crypt_pbkdf_type *pbkdf;
json_object *jobj_af, *jobj_area, *jobj_kdf;
json_object *jobj_af, *jobj_area, *jobj_kdf, *jobj1;
char salt[LUKS_SALTSIZE], *salt_base64 = NULL;
int r;
int r, keyslot_key_len;
/* jobj_keyslot is not yet validated */
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "key_size", &jobj1))
return -EINVAL;
/* update area encryption parameters */
json_object_object_add(jobj_area, "encryption", json_object_new_string(params->area.raw.encryption));
json_object_object_add(jobj_area, "key_size", json_object_new_int(params->area.raw.key_size));
/* we do not allow any 'area' object modifications yet */
keyslot_key_len = json_object_get_int(jobj1);
if (keyslot_key_len < 0)
return -EINVAL;
pbkdf = crypt_get_pbkdf_type(cd);
if (!pbkdf)
return -EINVAL;
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, params->area.raw.key_size);
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, keyslot_key_len);
if (r < 0)
return r;
@@ -436,7 +442,7 @@ static int luks2_keyslot_update_json(struct crypt_device *cd,
/* update 'af' hash */
json_object_object_add(jobj_af, "hash", json_object_new_string(params->af.luks1.hash));
JSON_DBG(cd, jobj_keyslot, "Keyslot JSON:");
JSON_DBG(jobj_keyslot, "Keyslot JSON");
return 0;
}
@@ -446,15 +452,16 @@ static int luks2_keyslot_alloc(struct crypt_device *cd,
const struct luks2_keyslot_params *params)
{
struct luks2_hdr *hdr;
char num[16];
uint64_t area_offset, area_length;
json_object *jobj_keyslots, *jobj_keyslot, *jobj_af, *jobj_area;
int r;
log_dbg(cd, "Trying to allocate LUKS2 keyslot %d.", keyslot);
log_dbg("Trying to allocate LUKS2 keyslot %d.", keyslot);
if (!params || params->area_type != LUKS2_KEYSLOT_AREA_RAW ||
params->af_type != LUKS2_KEYSLOT_AF_LUKS1) {
log_dbg(cd, "Invalid LUKS2 keyslot parameters.");
log_dbg("Invalid LUKS2 keyslot parameters.");
return -EINVAL;
}
@@ -462,13 +469,13 @@ static int luks2_keyslot_alloc(struct crypt_device *cd,
return -EINVAL;
if (keyslot == CRYPT_ANY_SLOT)
keyslot = LUKS2_keyslot_find_empty(hdr);
keyslot = LUKS2_keyslot_find_empty(hdr, "luks2");
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
return -ENOMEM;
if (LUKS2_get_keyslot_jobj(hdr, keyslot)) {
log_dbg(cd, "Cannot modify already active keyslot %d.", keyslot);
log_dbg("Cannot modify already active keyslot %d.", keyslot);
return -EINVAL;
}
@@ -476,10 +483,8 @@ static int luks2_keyslot_alloc(struct crypt_device *cd,
return -EINVAL;
r = LUKS2_find_area_gap(cd, hdr, volume_key_len, &area_offset, &area_length);
if (r < 0) {
log_err(cd, _("No space for new keyslot."));
if (r < 0)
return r;
}
jobj_keyslot = json_object_new_object();
json_object_object_add(jobj_keyslot, "type", json_object_new_string("luks2"));
@@ -494,21 +499,25 @@ static int luks2_keyslot_alloc(struct crypt_device *cd,
/* Area object */
jobj_area = json_object_new_object();
json_object_object_add(jobj_area, "type", json_object_new_string("raw"));
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(area_offset));
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length));
json_object_object_add(jobj_area, "encryption", json_object_new_string(params->area.raw.encryption));
json_object_object_add(jobj_area, "key_size", json_object_new_int(params->area.raw.key_size));
json_object_object_add(jobj_area, "offset", json_object_new_uint64(area_offset));
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_length));
json_object_object_add(jobj_keyslot, "area", jobj_area);
json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
snprintf(num, sizeof(num), "%d", keyslot);
json_object_object_add(jobj_keyslots, num, jobj_keyslot);
r = luks2_keyslot_update_json(cd, jobj_keyslot, params);
if (!r && LUKS2_check_json_size(cd, hdr)) {
log_dbg(cd, "Not enough space in header json area for new keyslot.");
if (!r && LUKS2_check_json_size(hdr)) {
log_dbg("Not enough space in header json area for new keyslot.");
r = -ENOSPC;
}
if (r)
json_object_object_del_by_uint(jobj_keyslots, keyslot);
json_object_object_del(jobj_keyslots, num);
return r;
}
@@ -523,7 +532,7 @@ static int luks2_keyslot_open(struct crypt_device *cd,
struct luks2_hdr *hdr;
json_object *jobj_keyslot;
log_dbg(cd, "Trying to open LUKS2 keyslot %d.", keyslot);
log_dbg("Trying to open LUKS2 keyslot %d.", keyslot);
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
@@ -552,7 +561,7 @@ static int luks2_keyslot_store(struct crypt_device *cd,
json_object *jobj_keyslot;
int r;
log_dbg(cd, "Calculating attributes for LUKS2 keyslot %d.", keyslot);
log_dbg("Calculating attributes for LUKS2 keyslot %d.", keyslot);
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
@@ -561,19 +570,17 @@ static int luks2_keyslot_store(struct crypt_device *cd,
if (!jobj_keyslot)
return -EINVAL;
r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
if(r)
return r;
r = luks2_keyslot_set_key(cd, jobj_keyslot,
password, password_len,
volume_key, volume_key_len);
if (!r)
r = LUKS2_hdr_write(cd, hdr);
if (r < 0)
return r;
device_write_unlock(cd, crypt_metadata_device(cd));
r = LUKS2_hdr_write(cd, hdr);
if (r < 0)
return r;
return r < 0 ? r : keyslot;
return keyslot;
}
static int luks2_keyslot_wipe(struct crypt_device *cd, int keyslot)
@@ -606,9 +613,6 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
json_object_object_get_ex(jobj_area, "encryption", &jobj1);
log_std(cd, "\tCipher: %s\n", json_object_get_string(jobj1));
json_object_object_get_ex(jobj_area, "key_size", &jobj1);
log_std(cd, "\tCipher key: %u bits\n", crypt_jobj_get_uint32(jobj1) * 8);
json_object_object_get_ex(jobj_kdf, "type", &jobj1);
log_std(cd, "\tPBKDF: %s\n", json_object_get_string(jobj1));
@@ -617,7 +621,7 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
log_std(cd, "\tHash: %s\n", json_object_get_string(jobj1));
json_object_object_get_ex(jobj_kdf, "iterations", &jobj1);
log_std(cd, "\tIterations: %" PRIu64 "\n", crypt_jobj_get_uint64(jobj1));
log_std(cd, "\tIterations: %" PRIu64 "\n", json_object_get_uint64(jobj1));
} else {
json_object_object_get_ex(jobj_kdf, "time", &jobj1);
log_std(cd, "\tTime cost: %" PRIu64 "\n", json_object_get_int64(jobj1));
@@ -636,14 +640,11 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
json_object_object_get_ex(jobj_af, "stripes", &jobj1);
log_std(cd, "\tAF stripes: %u\n", json_object_get_int(jobj1));
json_object_object_get_ex(jobj_af, "hash", &jobj1);
log_std(cd, "\tAF hash: %s\n", json_object_get_string(jobj1));
json_object_object_get_ex(jobj_area, "offset", &jobj1);
log_std(cd, "\tArea offset:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1));
log_std(cd, "\tArea offset:%" PRIu64 " [bytes]\n", json_object_get_uint64(jobj1));
json_object_object_get_ex(jobj_area, "size", &jobj1);
log_std(cd, "\tArea length:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1));
log_std(cd, "\tArea length:%" PRIu64 " [bytes]\n", json_object_get_uint64(jobj1));
return 0;
}
@@ -664,31 +665,31 @@ static int luks2_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
count = json_object_object_length(jobj_kdf);
jobj1 = json_contains(cd, jobj_kdf, "", "kdf section", "type", json_type_string);
jobj1 = json_contains(jobj_kdf, "", "kdf section", "type", json_type_string);
if (!jobj1)
return -EINVAL;
type = json_object_get_string(jobj1);
if (!strcmp(type, CRYPT_KDF_PBKDF2)) {
if (count != 4 || /* type, salt, hash, iterations only */
!json_contains(cd, jobj_kdf, "kdf type", type, "hash", json_type_string) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "iterations", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "salt", json_type_string))
!json_contains(jobj_kdf, "kdf type", type, "hash", json_type_string) ||
!json_contains(jobj_kdf, "kdf type", type, "iterations", json_type_int) ||
!json_contains(jobj_kdf, "kdf type", type, "salt", json_type_string))
return -EINVAL;
} else if (!strcmp(type, CRYPT_KDF_ARGON2I) || !strcmp(type, CRYPT_KDF_ARGON2ID)) {
if (count != 5 || /* type, salt, time, memory, cpus only */
!json_contains(cd, jobj_kdf, "kdf type", type, "time", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "memory", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "cpus", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "salt", json_type_string))
!json_contains(jobj_kdf, "kdf type", type, "time", json_type_int) ||
!json_contains(jobj_kdf, "kdf type", type, "memory", json_type_int) ||
!json_contains(jobj_kdf, "kdf type", type, "cpus", json_type_int) ||
!json_contains(jobj_kdf, "kdf type", type, "salt", json_type_string))
return -EINVAL;
}
if (!json_object_object_get_ex(jobj_af, "type", &jobj1))
return -EINVAL;
if (!strcmp(json_object_get_string(jobj1), "luks1")) {
if (!json_contains(cd, jobj_af, "", "luks1 af", "hash", json_type_string) ||
!json_contains(cd, jobj_af, "", "luks1 af", "stripes", json_type_int))
if (!json_contains(jobj_af, "", "luks1 af", "hash", json_type_string) ||
!json_contains(jobj_af, "", "luks1 af", "stripes", json_type_int))
return -EINVAL;
} else
return -EINVAL;
@@ -697,10 +698,10 @@ static int luks2_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
if (!json_object_object_get_ex(jobj_area, "type", &jobj1))
return -EINVAL;
if (!strcmp(json_object_get_string(jobj1), "raw")) {
if (!json_contains(cd, jobj_area, "area", "raw type", "encryption", json_type_string) ||
!json_contains(cd, jobj_area, "area", "raw type", "key_size", json_type_int) ||
!json_contains(cd, jobj_area, "area", "raw type", "offset", json_type_string) ||
!json_contains(cd, jobj_area, "area", "raw type", "size", json_type_string))
if (!json_contains(jobj_area, "area", "raw type", "encryption", json_type_string) ||
!json_contains(jobj_area, "area", "raw type", "key_size", json_type_int) ||
!json_contains(jobj_area, "area", "raw type", "offset", json_type_string) ||
!json_contains(jobj_area, "area", "raw type", "size", json_type_string))
return -EINVAL;
} else
return -EINVAL;
@@ -716,7 +717,7 @@ static int luks2_keyslot_update(struct crypt_device *cd,
json_object *jobj_keyslot;
int r;
log_dbg(cd, "Updating LUKS2 keyslot %d.", keyslot);
log_dbg("Updating LUKS2 keyslot %d.", keyslot);
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
@@ -727,8 +728,8 @@ static int luks2_keyslot_update(struct crypt_device *cd,
r = luks2_keyslot_update_json(cd, jobj_keyslot, params);
if (!r && LUKS2_check_json_size(cd, hdr)) {
log_dbg(cd, "Not enough space in header json area for updated keyslot %d.", keyslot);
if (!r && LUKS2_check_json_size(hdr)) {
log_dbg("Not enough space in header json area for updated keyslot %d.", keyslot);
r = -ENOSPC;
}

View File

@@ -1,316 +0,0 @@
/*
* LUKS - Linux Unified Key Setup v2, reencryption keyslot handler
*
* Copyright (C) 2016-2021, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021, Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "luks2_internal.h"
static int reenc_keyslot_open(struct crypt_device *cd,
int keyslot,
const char *password,
size_t password_len,
char *volume_key,
size_t volume_key_len)
{
return -ENOENT;
}
int reenc_keyslot_alloc(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params)
{
int r;
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
uint64_t area_offset, area_length;
log_dbg(cd, "Allocating reencrypt keyslot %d.", keyslot);
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
return -ENOMEM;
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
return -EINVAL;
/* encryption doesn't require area (we shift data and backup will be available) */
if (!params->data_shift) {
r = LUKS2_find_area_max_gap(cd, hdr, &area_offset, &area_length);
if (r < 0)
return r;
} else { /* we can't have keyslot w/o area...bug? */
r = LUKS2_find_area_gap(cd, hdr, 1, &area_offset, &area_length);
if (r < 0)
return r;
}
jobj_keyslot = json_object_new_object();
if (!jobj_keyslot)
return -ENOMEM;
jobj_area = json_object_new_object();
if (params->data_shift) {
json_object_object_add(jobj_area, "type", json_object_new_string("datashift"));
json_object_object_add(jobj_area, "shift_size", crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
} else
/* except data shift protection, initial setting is irrelevant. Type can be changed during reencryption */
json_object_object_add(jobj_area, "type", json_object_new_string("none"));
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(area_offset));
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length));
json_object_object_add(jobj_keyslot, "type", json_object_new_string("reencrypt"));
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(1)); /* useless but mandatory */
json_object_object_add(jobj_keyslot, "mode", json_object_new_string(crypt_reencrypt_mode_to_str(params->mode)));
if (params->direction == CRYPT_REENCRYPT_FORWARD)
json_object_object_add(jobj_keyslot, "direction", json_object_new_string("forward"));
else if (params->direction == CRYPT_REENCRYPT_BACKWARD)
json_object_object_add(jobj_keyslot, "direction", json_object_new_string("backward"));
else
return -EINVAL;
json_object_object_add(jobj_keyslot, "area", jobj_area);
json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
if (LUKS2_check_json_size(cd, hdr)) {
log_dbg(cd, "New keyslot too large to fit in free metadata space.");
json_object_object_del_by_uint(jobj_keyslots, keyslot);
return -ENOSPC;
}
JSON_DBG(cd, hdr->jobj, "JSON:");
return 0;
}
static int reenc_keyslot_store_data(struct crypt_device *cd,
json_object *jobj_keyslot,
const void *buffer, size_t buffer_len)
{
int devfd, r;
json_object *jobj_area, *jobj_offset, *jobj_length;
uint64_t area_offset, area_length;
struct device *device = crypt_metadata_device(cd);
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "offset", &jobj_offset) ||
!json_object_object_get_ex(jobj_area, "size", &jobj_length))
return -EINVAL;
area_offset = crypt_jobj_get_uint64(jobj_offset);
area_length = crypt_jobj_get_uint64(jobj_length);
if (!area_offset || !area_length || ((uint64_t)buffer_len > area_length))
return -EINVAL;
devfd = device_open_locked(cd, device, O_RDWR);
if (devfd >= 0) {
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), CONST_CAST(void *)buffer,
buffer_len, area_offset) < 0)
r = -EIO;
else
r = 0;
} else
r = -EINVAL;
if (r)
log_err(cd, _("IO error while encrypting keyslot."));
return r;
}
static int reenc_keyslot_store(struct crypt_device *cd,
int keyslot,
const char *password __attribute__((unused)),
size_t password_len __attribute__((unused)),
const char *buffer,
size_t buffer_len)
{
struct luks2_hdr *hdr;
json_object *jobj_keyslot;
int r = 0;
if (!cd || !buffer || !buffer_len)
return -EINVAL;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
log_dbg(cd, "Reencrypt keyslot %d store.", keyslot);
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -EINVAL;
r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
if (r)
return r;
r = reenc_keyslot_store_data(cd, jobj_keyslot, buffer, buffer_len);
if (r < 0) {
device_write_unlock(cd, crypt_metadata_device(cd));
return r;
}
r = LUKS2_hdr_write(cd, hdr);
device_write_unlock(cd, crypt_metadata_device(cd));
return r < 0 ? r : keyslot;
}
static int reenc_keyslot_wipe(struct crypt_device *cd,
int keyslot)
{
struct luks2_hdr *hdr;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
/* remove reencryption verification data */
LUKS2_digest_assign(cd, hdr, keyslot, CRYPT_ANY_DIGEST, 0, 0);
return 0;
}
static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot)
{
json_object *jobj_keyslot, *jobj_area, *jobj_direction, *jobj_mode, *jobj_resilience,
*jobj1;
jobj_keyslot = LUKS2_get_keyslot_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), keyslot);
if (!jobj_keyslot)
return -EINVAL;
if (!json_object_object_get_ex(jobj_keyslot, "direction", &jobj_direction) ||
!json_object_object_get_ex(jobj_keyslot, "mode", &jobj_mode) ||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "type", &jobj_resilience))
return -EINVAL;
log_std(cd, "\t%-12s%s\n", "Mode:", json_object_get_string(jobj_mode));
log_std(cd, "\t%-12s%s\n", "Direction:", json_object_get_string(jobj_direction));
log_std(cd, "\t%-12s%s\n", "Resilience:", json_object_get_string(jobj_resilience));
if (!strcmp(json_object_get_string(jobj_resilience), "checksum")) {
json_object_object_get_ex(jobj_area, "hash", &jobj1);
log_std(cd, "\t%-12s%s\n", "Hash:", json_object_get_string(jobj1));
json_object_object_get_ex(jobj_area, "sector_size", &jobj1);
log_std(cd, "\t%-12s%d [bytes]\n", "Hash data:", json_object_get_int(jobj1));
} else if (!strcmp(json_object_get_string(jobj_resilience), "datashift")) {
json_object_object_get_ex(jobj_area, "shift_size", &jobj1);
log_std(cd, "\t%-12s%" PRIu64 "[bytes]\n", "Shift size:", crypt_jobj_get_uint64(jobj1));
}
json_object_object_get_ex(jobj_area, "offset", &jobj1);
log_std(cd, "\tArea offset:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1));
json_object_object_get_ex(jobj_area, "size", &jobj1);
log_std(cd, "\tArea length:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1));
return 0;
}
static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
{
json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction, *jobj_key_size;
const char *mode, *type, *direction;
uint32_t sector_size;
uint64_t shift_size;
/* mode (string: encrypt,reencrypt,decrypt)
* direction (string:)
* area {
* type: (string: datashift, journal, checksum, none)
* hash: (string: checksum only)
* sector_size (uint32: checksum only)
* shift_size (uint64: datashift only)
* }
*/
/* area and area type are validated in general validation code */
if (!jobj_keyslot || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_area, "type", &jobj_type))
return -EINVAL;
jobj_key_size = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "key_size", json_type_int);
jobj_mode = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "mode", json_type_string);
jobj_direction = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "direction", json_type_string);
if (!jobj_mode || !jobj_direction || !jobj_key_size)
return -EINVAL;
if (!validate_json_uint32(jobj_key_size) || crypt_jobj_get_uint32(jobj_key_size) != 1) {
log_dbg(cd, "Illegal reencrypt key size.");
return -EINVAL;
}
mode = json_object_get_string(jobj_mode);
type = json_object_get_string(jobj_type);
direction = json_object_get_string(jobj_direction);
if (strcmp(mode, "reencrypt") && strcmp(mode, "encrypt") &&
strcmp(mode, "decrypt")) {
log_dbg(cd, "Illegal reencrypt mode %s.", mode);
return -EINVAL;
}
if (strcmp(direction, "forward") && strcmp(direction, "backward")) {
log_dbg(cd, "Illegal reencrypt direction %s.", direction);
return -EINVAL;
}
if (!strcmp(type, "checksum")) {
jobj_hash = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "hash", json_type_string);
jobj_sector_size = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "sector_size", json_type_int);
if (!jobj_hash || !jobj_sector_size)
return -EINVAL;
if (!validate_json_uint32(jobj_sector_size))
return -EINVAL;
sector_size = crypt_jobj_get_uint32(jobj_sector_size);
if (sector_size < SECTOR_SIZE || NOTPOW2(sector_size)) {
log_dbg(cd, "Invalid sector_size (%" PRIu32 ") for checksum resilience mode.", sector_size);
return -EINVAL;
}
} else if (!strcmp(type, "datashift")) {
if (!(jobj_shift_size = json_contains(cd, jobj_area, "type:datashift", "Keyslot area", "shift_size", json_type_string)))
return -EINVAL;
shift_size = crypt_jobj_get_uint64(jobj_shift_size);
if (!shift_size)
return -EINVAL;
if (MISALIGNED_512(shift_size)) {
log_dbg(cd, "Shift size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
return -EINVAL;
}
}
return 0;
}
const keyslot_handler reenc_keyslot = {
.name = "reencrypt",
.open = reenc_keyslot_open,
.store = reenc_keyslot_store, /* initialization only or also per every chunk write */
.wipe = reenc_keyslot_wipe,
.dump = reenc_keyslot_dump,
.validate = reenc_keyslot_validate
};

View File

@@ -1,9 +1,9 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS1 conversion code
*
* Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2021 Ondrej Kozina
* Copyright (C) 2015-2021 Milan Broz
* Copyright (C) 2015-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2018, Ondrej Kozina. All rights reserved.
* Copyright (C) 2015-2018, Milan Broz. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,14 +24,6 @@
#include "../luks1/luks.h"
#include "../luks1/af.h"
int LUKS2_check_cipher(struct crypt_device *cd,
size_t keylength,
const char *cipher,
const char *cipher_mode)
{
return LUKS_check_cipher(cd, keylength, cipher, cipher_mode);
}
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struct json_object **keyslot_object)
{
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
@@ -91,8 +83,8 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
}
area_size = offs_b - offs_a;
json_object_object_add(jobj_area, "key_size", json_object_new_int(hdr_v1->keyBytes));
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(offset));
json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_size));
json_object_object_add(jobj_area, "offset", json_object_new_uint64(offset));
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_size));
json_object_object_add(keyslot_obj, "area", jobj_area);
*keyslot_object = keyslot_obj;
@@ -101,22 +93,24 @@ static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struc
static int json_luks1_keyslots(const struct luks_phdr *hdr_v1, struct json_object **keyslots_object)
{
int keyslot, r;
char keyslot_str[2];
int key_slot, r;
struct json_object *keyslot_obj, *field;
keyslot_obj = json_object_new_object();
if (!keyslot_obj)
return -ENOMEM;
for (keyslot = 0; keyslot < LUKS_NUMKEYS; keyslot++) {
if (hdr_v1->keyblock[keyslot].active != LUKS_KEY_ENABLED)
for (key_slot = 0; key_slot < LUKS_NUMKEYS; key_slot++) {
if (hdr_v1->keyblock[key_slot].active != LUKS_KEY_ENABLED)
continue;
r = json_luks1_keyslot(hdr_v1, keyslot, &field);
r = json_luks1_keyslot(hdr_v1, key_slot, &field);
if (r) {
json_object_put(keyslot_obj);
return r;
}
json_object_object_add_by_uint(keyslot_obj, keyslot, field);
(void) snprintf(keyslot_str, sizeof(keyslot_str), "%d", key_slot);
json_object_object_add(keyslot_obj, keyslot_str, field);
}
*keyslots_object = keyslot_obj;
@@ -145,7 +139,7 @@ static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object
/* offset field */
number = (uint64_t)hdr_v1->payloadOffset * SECTOR_SIZE;
field = crypt_jobj_new_uint64(number);
field = json_object_new_uint64(number);
if (!field) {
json_object_put(segment_obj);
return -ENOMEM;
@@ -196,6 +190,7 @@ static int json_luks1_segment(const struct luks_phdr *hdr_v1, struct json_object
static int json_luks1_segments(const struct luks_phdr *hdr_v1, struct json_object **segments_object)
{
char num[16];
int r;
struct json_object *segments_obj, *field;
@@ -208,7 +203,8 @@ static int json_luks1_segments(const struct luks_phdr *hdr_v1, struct json_objec
json_object_put(segments_obj);
return r;
}
json_object_object_add_by_uint(segments_obj, 0, field);
snprintf(num, sizeof(num), "%u", CRYPT_DEFAULT_SEGMENT);
json_object_object_add(segments_obj, num, field);
*segments_object = segments_obj;
return 0;
@@ -401,9 +397,8 @@ static int json_luks1_object(struct luks_phdr *hdr_v1, struct json_object **luks
json_object_object_add(luks1_obj, "config", field);
json_size = LUKS2_HDR_16K_LEN - LUKS2_HDR_BIN_LEN;
json_object_object_add(field, "json_size", crypt_jobj_new_uint64(json_size));
keyslots_size -= (keyslots_size % 4096);
json_object_object_add(field, "keyslots_size", crypt_jobj_new_uint64(keyslots_size));
json_object_object_add(field, "json_size", json_object_new_uint64(json_size));
json_object_object_add(field, "keyslots_size", json_object_new_uint64(keyslots_size));
*luks1_object = luks1_obj;
return 0;
@@ -419,8 +414,8 @@ static void move_keyslot_offset(json_object *jobj, int offset_add)
UNUSED(key);
json_object_object_get_ex(val, "area", &jobj_area);
json_object_object_get_ex(jobj_area, "offset", &jobj2);
offset = crypt_jobj_get_uint64(jobj2) + offset_add;
json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(offset));
offset = json_object_get_uint64(jobj2) + offset_add;
json_object_object_add(jobj_area, "offset", json_object_new_uint64(offset));
}
}
@@ -428,46 +423,47 @@ static void move_keyslot_offset(json_object *jobj, int offset_add)
static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
off_t offset_to, size_t buf_size)
{
int devfd, r = -EIO;
struct device *device = crypt_metadata_device(cd);
void *buf = NULL;
int r = -EIO, devfd = -1;
log_dbg(cd, "Moving keyslot areas of size %zu from %jd to %jd.",
log_dbg("Moving keyslot areas of size %zu from %jd to %jd.",
buf_size, (intmax_t)offset_from, (intmax_t)offset_to);
if (posix_memalign(&buf, crypt_getpagesize(), buf_size))
return -ENOMEM;
devfd = device_open(cd, device, O_RDWR);
if (devfd < 0) {
devfd = device_open(device, O_RDWR);
if (devfd == -1) {
free(buf);
return -EIO;
}
/* This can safely fail (for block devices). It only allocates space if it is possible. */
if (posix_fallocate(devfd, offset_to, buf_size))
log_dbg(cd, "Preallocation (fallocate) of new keyslot area not available.");
log_dbg("Preallocation (fallocate) of new keyslot area not available.");
/* Try to read *new* area to check that area is there (trimmed backup). */
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), buf, buf_size,
offset_to)!= (ssize_t)buf_size)
goto out;
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), buf, buf_size,
offset_from)!= (ssize_t)buf_size)
goto out;
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
if (write_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), buf, buf_size,
offset_to) != (ssize_t)buf_size)
goto out;
r = 0;
out:
device_sync(cd, device);
crypt_safe_memzero(buf, buf_size);
device_sync(device, devfd);
close(devfd);
crypt_memzero(buf, buf_size);
free(buf);
return r;
@@ -477,9 +473,9 @@ static int luks_header_in_use(struct crypt_device *cd)
{
int r;
r = lookup_dm_dev_by_uuid(cd, crypt_get_uuid(cd), crypt_get_type(cd));
r = lookup_dm_dev_by_uuid(crypt_get_uuid(cd), crypt_get_type(cd));
if (r < 0)
log_err(cd, _("Cannot check status of device with uuid: %s."), crypt_get_uuid(cd));
log_err(cd, _("Can not check status of device with uuid: %s."), crypt_get_uuid(cd));
return r;
}
@@ -487,28 +483,29 @@ static int luks_header_in_use(struct crypt_device *cd)
/* Check if there is a luksmeta area (foreign metadata created by the luksmeta package) */
static int luksmeta_header_present(struct crypt_device *cd, off_t luks1_size)
{
int devfd, r = 0;
static const uint8_t LM_MAGIC[] = { 'L', 'U', 'K', 'S', 'M', 'E', 'T', 'A' };
struct device *device = crypt_metadata_device(cd);
void *buf = NULL;
int devfd, r = 0;
if (posix_memalign(&buf, crypt_getpagesize(), sizeof(LM_MAGIC)))
return -ENOMEM;
devfd = device_open(cd, device, O_RDONLY);
if (devfd < 0) {
devfd = device_open(device, O_RDONLY);
if (devfd == -1) {
free(buf);
return -EIO;
}
/* Note: we must not detect failure as problem here, header can be trimmed. */
if (read_lseek_blockwise(devfd, device_block_size(cd, device), device_alignment(device),
if (read_lseek_blockwise(devfd, device_block_size(device), device_alignment(device),
buf, sizeof(LM_MAGIC), luks1_size) == (ssize_t)sizeof(LM_MAGIC) &&
!memcmp(LM_MAGIC, buf, sizeof(LM_MAGIC))) {
log_err(cd, _("Unable to convert header with LUKSMETA additional metadata."));
r = -EBUSY;
}
close(devfd);
free(buf);
return r;
}
@@ -519,7 +516,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
int r;
json_object *jobj = NULL;
size_t buf_size, buf_offset, luks1_size, luks1_shift = 2 * LUKS2_HDR_16K_LEN - LUKS_ALIGN_KEYSLOTS;
uint64_t required_size, max_size = crypt_get_data_offset(cd) * SECTOR_SIZE;
uint64_t max_size = crypt_get_data_offset(cd) * SECTOR_SIZE;
/* for detached headers max size == device size */
if (!max_size && (r = device_size(crypt_metadata_device(cd), &max_size)))
@@ -531,27 +528,20 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
return -EINVAL;
if (LUKS_keyslots_offset(hdr1) != (LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE)) {
log_dbg(cd, "Unsupported keyslots material offset: %zu.", LUKS_keyslots_offset(hdr1));
log_dbg("Unsupported keyslots material offset: %zu.", LUKS_keyslots_offset(hdr1));
return -EINVAL;
}
if (luksmeta_header_present(cd, luks1_size))
return -EINVAL;
log_dbg(cd, "Max size: %" PRIu64 ", LUKS1 (full) header size %zu , required shift: %zu",
log_dbg("Max size: %" PRIu64 ", LUKS1 (full) header size %zu , required shift: %zu",
max_size, luks1_size, luks1_shift);
required_size = luks1_size + luks1_shift;
if ((max_size < required_size) &&
device_fallocate(crypt_metadata_device(cd), required_size)) {
if ((max_size - luks1_size) < luks1_shift) {
log_err(cd, _("Unable to move keyslot area. Not enough space."));
return -EINVAL;
}
if (max_size < required_size)
max_size = required_size;
r = json_luks1_object(hdr1, &jobj, max_size - 2 * LUKS2_HDR_16K_LEN);
if (r < 0)
return r;
@@ -573,13 +563,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
* It duplicates check in LUKS2_hdr_write() but we don't want to move
* keyslot areas in case it would fail later
*/
if (max_size < LUKS2_hdr_and_areas_size(hdr2)) {
r = -EINVAL;
goto out;
}
/* check future LUKS2 metadata before moving keyslots area */
if (LUKS2_hdr_validate(cd, hdr2->jobj, hdr2->hdr_size - LUKS2_HDR_BIN_LEN)) {
if (max_size < LUKS2_hdr_and_areas_size(hdr2->jobj)) {
r = -EINVAL;
goto out;
}
@@ -593,14 +577,6 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
// move keyslots 4k -> 32k offset
buf_offset = 2 * LUKS2_HDR_16K_LEN;
buf_size = luks1_size - LUKS_ALIGN_KEYSLOTS;
/* check future LUKS2 keyslots area is at least as large as LUKS1 keyslots area */
if (buf_size > LUKS2_keyslots_size(hdr2)) {
log_err(cd, _("Unable to move keyslot area. LUKS2 keyslots area too small."));
r = -EINVAL;
goto out;
}
if ((r = move_keyslot_areas(cd, 8 * SECTOR_SIZE, buf_offset, buf_size)) < 0) {
log_err(cd, _("Unable to move keyslot area."));
goto out;
@@ -609,18 +585,16 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
// Write JSON hdr2
r = LUKS2_hdr_write(cd, hdr2);
out:
LUKS2_hdr_free(cd, hdr2);
LUKS2_hdr_free(hdr2);
return r;
}
static int keyslot_LUKS1_compatible(struct crypt_device *cd, struct luks2_hdr *hdr,
int keyslot, uint32_t key_size, const char *hash)
static int keyslot_LUKS1_compatible(struct luks2_hdr *hdr, int keyslot, uint32_t key_size)
{
json_object *jobj_keyslot, *jobj, *jobj_kdf, *jobj_af;
uint64_t l2_offset, l2_length;
size_t ks_key_size;
const char *ks_cipher, *data_cipher;
int ks_key_size;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
@@ -634,9 +608,7 @@ static int keyslot_LUKS1_compatible(struct crypt_device *cd, struct luks2_hdr *h
jobj = NULL;
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
!json_object_object_get_ex(jobj_kdf, "type", &jobj) ||
strcmp(json_object_get_string(jobj), CRYPT_KDF_PBKDF2) ||
!json_object_object_get_ex(jobj_kdf, "hash", &jobj) ||
strcmp(json_object_get_string(jobj), hash))
strcmp(json_object_get_string(jobj), CRYPT_KDF_PBKDF2))
return 0;
jobj = NULL;
@@ -647,16 +619,14 @@ static int keyslot_LUKS1_compatible(struct crypt_device *cd, struct luks2_hdr *h
jobj = NULL;
if (!json_object_object_get_ex(jobj_af, "hash", &jobj) ||
(crypt_hash_size(json_object_get_string(jobj)) < 0) ||
strcmp(json_object_get_string(jobj), hash))
crypt_hash_size(json_object_get_string(jobj)) < 0)
return 0;
/* FIXME: should this go to validation code instead (aka invalid luks2 header if assigned to segment 0)? */
/* FIXME: check all keyslots are assigned to segment id 0, and segments count == 1 */
ks_cipher = LUKS2_get_keyslot_cipher(hdr, keyslot, &ks_key_size);
data_cipher = LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT);
if (!ks_cipher || !data_cipher || key_size != ks_key_size || strcmp(ks_cipher, data_cipher)) {
log_dbg(cd, "Cipher in keyslot %d is different from volume key encryption.", keyslot);
ks_key_size = LUKS2_get_keyslot_key_size(hdr, keyslot);
if (ks_key_size < 0 || (int)key_size != LUKS2_get_keyslot_key_size(hdr, keyslot)) {
log_dbg("Key length in keyslot %d is different from volume key length", keyslot);
return 0;
}
@@ -664,7 +634,7 @@ static int keyslot_LUKS1_compatible(struct crypt_device *cd, struct luks2_hdr *h
return 0;
if (l2_length != (size_round_up(AF_split_sectors(key_size, LUKS_STRIPES) * SECTOR_SIZE, 4096))) {
log_dbg(cd, "Area length in LUKS2 keyslot (%d) is not compatible with LUKS1", keyslot);
log_dbg("Area length in LUKS2 keyslot (%d) is not compatible with LUKS1", keyslot);
return 0;
}
@@ -675,9 +645,8 @@ static int keyslot_LUKS1_compatible(struct crypt_device *cd, struct luks2_hdr *h
int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct luks_phdr *hdr1)
{
size_t buf_size, buf_offset;
char cipher[LUKS_CIPHERNAME_L], cipher_mode[LUKS_CIPHERMODE_L];
char cipher[LUKS_CIPHERNAME_L-1], cipher_mode[LUKS_CIPHERMODE_L-1];
char digest[LUKS_DIGESTSIZE], digest_salt[LUKS_SALTSIZE];
const char *hash;
size_t len;
json_object *jobj_keyslot, *jobj_digest, *jobj_segment, *jobj_kdf, *jobj_area, *jobj1, *jobj2;
uint32_t key_size;
@@ -693,11 +662,6 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (!jobj_segment)
return -EINVAL;
if (json_segment_get_sector_size(jobj_segment) != SECTOR_SIZE) {
log_err(cd, _("Cannot convert to LUKS1 format - default segment encryption sector size is not 512 bytes."));
return -EINVAL;
}
json_object_object_get_ex(hdr2->jobj, "digests", &jobj1);
if (!json_object_object_get_ex(jobj_digest, "type", &jobj2) ||
strcmp(json_object_get_string(jobj2), "pbkdf2") ||
@@ -705,9 +669,6 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
log_err(cd, _("Cannot convert to LUKS1 format - key slot digests are not LUKS1 compatible."));
return -EINVAL;
}
if (!json_object_object_get_ex(jobj_digest, "hash", &jobj2))
return -EINVAL;
hash = json_object_get_string(jobj2);
r = crypt_parse_name_and_mode(LUKS2_get_cipher(hdr2, CRYPT_DEFAULT_SEGMENT), cipher, NULL, cipher_mode);
if (r < 0)
@@ -745,7 +706,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
return -EINVAL;
}
if (!keyslot_LUKS1_compatible(cd, hdr2, i, key_size, hash)) {
if (!keyslot_LUKS1_compatible(hdr2, i, key_size)) {
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is not LUKS1 compatible."), i);
return -EINVAL;
}
@@ -764,7 +725,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
return -EINVAL;
if (!json_object_object_get_ex(jobj_area, "offset", &jobj1))
return -EINVAL;
offset = crypt_jobj_get_uint64(jobj1);
offset = json_object_get_uint64(jobj1);
} else {
if (LUKS2_find_area_gap(cd, hdr2, key_size, &offset, &area_length))
return -EINVAL;
@@ -796,7 +757,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (!json_object_object_get_ex(jobj_kdf, "iterations", &jobj1))
continue;
hdr1->keyblock[i].passwordIterations = crypt_jobj_get_uint32(jobj1);
hdr1->keyblock[i].passwordIterations = json_object_get_uint32(jobj1);
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj1))
continue;
@@ -824,10 +785,8 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (r < 0)
return r;
strncpy(hdr1->cipherName, cipher, LUKS_CIPHERNAME_L - 1);
hdr1->cipherName[LUKS_CIPHERNAME_L-1] = '\0';
strncpy(hdr1->cipherMode, cipher_mode, LUKS_CIPHERMODE_L - 1);
hdr1->cipherMode[LUKS_CIPHERMODE_L-1] = '\0';
strncpy(hdr1->cipherName, cipher, sizeof(hdr1->cipherName) - 1);
strncpy(hdr1->cipherMode, cipher_mode, sizeof(hdr1->cipherMode) - 1);
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf))
return -EINVAL;
@@ -839,7 +798,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (!json_object_object_get_ex(jobj_digest, "iterations", &jobj1))
return -EINVAL;
hdr1->mkDigestIterations = crypt_jobj_get_uint32(jobj1);
hdr1->mkDigestIterations = json_object_get_uint32(jobj1);
if (!json_object_object_get_ex(jobj_digest, "digest", &jobj1))
return -EINVAL;
@@ -864,7 +823,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (!json_object_object_get_ex(jobj_segment, "offset", &jobj1))
return -EINVAL;
offset = crypt_jobj_get_uint64(jobj1) / SECTOR_SIZE;
offset = json_object_get_uint64(jobj1) / SECTOR_SIZE;
if (offset > UINT32_MAX)
return -EINVAL;
/* FIXME: LUKS1 requires offset == 0 || offset >= luks1_hdr_size */
@@ -883,7 +842,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
// move keyslots 32k -> 4k offset
buf_offset = 2 * LUKS2_HDR_16K_LEN;
buf_size = LUKS2_keyslots_size(hdr2);
buf_size = LUKS2_keyslots_size(hdr2->jobj);
r = move_keyslot_areas(cd, buf_offset, 8 * SECTOR_SIZE, buf_size);
if (r < 0) {
log_err(cd, _("Unable to move keyslot area."));

File diff suppressed because it is too large Load Diff

View File

@@ -1,381 +0,0 @@
/*
* LUKS - Linux Unified Key Setup v2, reencryption digest helpers
*
* Copyright (C) 2022, Red Hat, Inc. All rights reserved.
* Copyright (C) 2022, Ondrej Kozina
* Copyright (C) 2022, Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "luks2_internal.h"
#include <assert.h>
#define MAX_STR 64
struct jtype {
enum { JNONE = 0, JSTR, JU64, JX64, JU32 } type;
json_object *jobj;
const char *id;
};
static size_t sr(struct jtype *j, uint8_t *ptr)
{
json_object *jobj;
size_t len = 0;
uint64_t u64;
uint32_t u32;
if (!json_object_is_type(j->jobj, json_type_object))
return 0;
if (!json_object_object_get_ex(j->jobj, j->id, &jobj))
return 0;
switch(j->type) {
case JSTR: /* JSON string */
if (!json_object_is_type(jobj, json_type_string))
return 0;
len = strlen(json_object_get_string(jobj));
if (len > MAX_STR)
return 0;
if (ptr)
memcpy(ptr, json_object_get_string(jobj), len);
break;
case JU64: /* Unsigned 64bit integer stored as string */
if (!json_object_is_type(jobj, json_type_string))
break;
len = sizeof(u64);
if (ptr) {
u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj));
memcpy(ptr, &u64, len);
}
break;
case JX64: /* Unsigned 64bit segment size (allows "dynamic") */
if (!json_object_is_type(jobj, json_type_string))
break;
if (!strcmp(json_object_get_string(jobj), "dynamic")) {
len = strlen("dynamic");
if (ptr)
memcpy(ptr, json_object_get_string(jobj), len);
} else {
len = sizeof(u64);
u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj));
if (ptr)
memcpy(ptr, &u64, len);
}
break;
case JU32: /* Unsigned 32bit integer, stored as JSON int */
if (!json_object_is_type(jobj, json_type_int))
return 0;
len = sizeof(u32);
if (ptr) {
u32 = cpu_to_be32(crypt_jobj_get_uint32(jobj));
memcpy(ptr, &u32, len);
}
break;
case JNONE:
return 0;
};
return len;
}
static size_t srs(struct jtype j[], uint8_t *ptr)
{
size_t l, len = 0;
while(j->jobj) {
l = sr(j, ptr);
if (!l)
return 0;
len += l;
if (ptr)
ptr += l;
j++;
}
return len;
}
static size_t segment_linear_serialize(json_object *jobj_segment, uint8_t *buffer)
{
struct jtype j[] = {
{ JSTR, jobj_segment, "type" },
{ JU64, jobj_segment, "offset" },
{ JX64, jobj_segment, "size" },
{}
};
return srs(j, buffer);
}
static size_t segment_crypt_serialize(json_object *jobj_segment, uint8_t *buffer)
{
struct jtype j[] = {
{ JSTR, jobj_segment, "type" },
{ JU64, jobj_segment, "offset" },
{ JX64, jobj_segment, "size" },
{ JU64, jobj_segment, "iv_tweak" },
{ JSTR, jobj_segment, "encryption" },
{ JU32, jobj_segment, "sector_size" },
{}
};
return srs(j, buffer);
}
static size_t segment_serialize(json_object *jobj_segment, uint8_t *buffer)
{
json_object *jobj_type;
const char *segment_type;
if (!json_object_object_get_ex(jobj_segment, "type", &jobj_type))
return 0;
if (!(segment_type = json_object_get_string(jobj_type)))
return 0;
if (!strcmp(segment_type, "crypt"))
return segment_crypt_serialize(jobj_segment, buffer);
else if (!strcmp(segment_type, "linear"))
return segment_linear_serialize(jobj_segment, buffer);
return 0;
}
static size_t backup_segments_serialize(struct luks2_hdr *hdr, uint8_t *buffer)
{
json_object *jobj_segment;
size_t l, len = 0;
jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-previous");
if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer)))
return 0;
len += l;
if (buffer)
buffer += l;
jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-final");
if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer)))
return 0;
len += l;
if (buffer)
buffer += l;
jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-moved-segment");
if (jobj_segment) {
if (!(l = segment_serialize(jobj_segment, buffer)))
return 0;
len += l;
}
return len;
}
static size_t reenc_keyslot_serialize(struct luks2_hdr *hdr, uint8_t *buffer)
{
json_object *jobj_keyslot, *jobj_area, *jobj_type;
const char *area_type;
int keyslot_reencrypt;
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
if (keyslot_reencrypt < 0)
return 0;
if (!(jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot_reencrypt)))
return 0;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return 0;
if (!json_object_object_get_ex(jobj_area, "type", &jobj_type))
return 0;
if (!(area_type = json_object_get_string(jobj_type)))
return 0;
struct jtype j[] = {
{ JSTR, jobj_keyslot, "mode" },
{ JSTR, jobj_keyslot, "direction" },
{ JSTR, jobj_area, "type" },
{ JU64, jobj_area, "offset" },
{ JU64, jobj_area, "size" },
{}
};
struct jtype j_datashift[] = {
{ JSTR, jobj_keyslot, "mode" },
{ JSTR, jobj_keyslot, "direction" },
{ JSTR, jobj_area, "type" },
{ JU64, jobj_area, "offset" },
{ JU64, jobj_area, "size" },
{ JU64, jobj_area, "shift_size" },
{}
};
struct jtype j_checksum[] = {
{ JSTR, jobj_keyslot, "mode" },
{ JSTR, jobj_keyslot, "direction" },
{ JSTR, jobj_area, "type" },
{ JU64, jobj_area, "offset" },
{ JU64, jobj_area, "size" },
{ JSTR, jobj_area, "hash" },
{ JU32, jobj_area, "sector_size" },
{}
};
if (!strcmp(area_type, "datashift"))
return srs(j_datashift, buffer);
else if (!strcmp(area_type, "checksum"))
return srs(j_checksum, buffer);
return srs(j, buffer);
}
static size_t blob_serialize(void *blob, size_t length, uint8_t *buffer)
{
if (buffer)
memcpy(buffer, blob, length);
return length;
}
static int reencrypt_assembly_verification_data(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks,
struct volume_key **verification_data)
{
uint8_t *ptr;
int digest_new, digest_old;
struct volume_key *data = NULL, *vk_old = NULL, *vk_new = NULL;
size_t keyslot_data_len, segments_data_len, data_len = 2;
/* Keys - calculate length */
digest_new = LUKS2_reencrypt_digest_new(hdr);
digest_old = LUKS2_reencrypt_digest_old(hdr);
if (digest_old >= 0) {
vk_old = crypt_volume_key_by_id(vks, digest_old);
if (!vk_old)
return -EINVAL;
data_len += blob_serialize(vk_old->key, vk_old->keylength, NULL);
}
if (digest_new >= 0 && digest_old != digest_new) {
vk_new = crypt_volume_key_by_id(vks, digest_new);
if (!vk_new)
return -EINVAL;
data_len += blob_serialize(vk_new->key, vk_new->keylength, NULL);
}
if (data_len == 2)
return -EINVAL;
/* Metadata - calculate length */
if (!(keyslot_data_len = reenc_keyslot_serialize(hdr, NULL)))
return -EINVAL;
data_len += keyslot_data_len;
if (!(segments_data_len = backup_segments_serialize(hdr, NULL)))
return -EINVAL;
data_len += segments_data_len;
/* Alloc and fill serialization data */
data = crypt_alloc_volume_key(data_len, NULL);
if (!data)
return -ENOMEM;
ptr = (uint8_t*)data->key;
/* v2 */
*ptr++ = 0x76;
*ptr++ = 0x32;
if (vk_old)
ptr += blob_serialize(vk_old->key, vk_old->keylength, ptr);
if (vk_new)
ptr += blob_serialize(vk_new->key, vk_new->keylength, ptr);
if (!reenc_keyslot_serialize(hdr, ptr))
goto bad;
ptr += keyslot_data_len;
if (!backup_segments_serialize(hdr, ptr))
goto bad;
ptr += segments_data_len;
assert((size_t)(ptr - (uint8_t*)data->key) == data_len);
*verification_data = data;
return 0;
bad:
crypt_free_volume_key(data);
return -EINVAL;
}
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks)
{
int digest_reencrypt, keyslot_reencrypt, r;
struct volume_key *data;
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
if (keyslot_reencrypt < 0)
return keyslot_reencrypt;
r = reencrypt_assembly_verification_data(cd, hdr, vks, &data);
if (r < 0)
return r;
r = LUKS2_digest_create(cd, "pbkdf2", hdr, data);
crypt_free_volume_key(data);
if (r < 0)
return r;
digest_reencrypt = r;
r = LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, CRYPT_ANY_DIGEST, 0, 0);
if (r < 0)
return r;
return LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, digest_reencrypt, 1, 0);
}
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks)
{
int r, keyslot_reencrypt;
struct volume_key *data;
keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
if (keyslot_reencrypt < 0)
return keyslot_reencrypt;
r = reencrypt_assembly_verification_data(cd, hdr, vks, &data);
if (r < 0)
return r;
r = LUKS2_digest_verify(cd, hdr, data, keyslot_reencrypt);
crypt_free_volume_key(data);
if (r < 0) {
if (r == -ENOENT)
log_dbg(cd, "Reencryption digest is missing.");
log_err(cd, _("Reencryption metadata is invalid."));
} else
log_dbg(cd, "Reencryption metadata verified.");
return r;
}

View File

@@ -1,432 +0,0 @@
/*
* LUKS - Linux Unified Key Setup v2, internal segment handling
*
* Copyright (C) 2018-2021, Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2021, Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "luks2_internal.h"
/* use only on already validated 'segments' object */
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise)
{
uint64_t tmp, min = blockwise ? UINT64_MAX >> SECTOR_SHIFT : UINT64_MAX;
if (!jobj_segments)
return 0;
json_object_object_foreach(jobj_segments, key, val) {
UNUSED(key);
if (json_segment_is_backup(val))
continue;
tmp = json_segment_get_offset(val, blockwise);
if (!tmp)
return tmp;
if (tmp < min)
min = tmp;
}
return min;
}
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise)
{
json_object *jobj;
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "offset", &jobj))
return 0;
return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);
}
const char *json_segment_type(json_object *jobj_segment)
{
json_object *jobj;
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "type", &jobj))
return NULL;
return json_object_get_string(jobj);
}
uint64_t json_segment_get_iv_offset(json_object *jobj_segment)
{
json_object *jobj;
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "iv_tweak", &jobj))
return 0;
return crypt_jobj_get_uint64(jobj);
}
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise)
{
json_object *jobj;
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "size", &jobj))
return 0;
return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);
}
const char *json_segment_get_cipher(json_object *jobj_segment)
{
json_object *jobj;
/* FIXME: Pseudo "null" cipher should be handled elsewhere */
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "encryption", &jobj))
return "null";
return json_object_get_string(jobj);
}
int json_segment_get_sector_size(json_object *jobj_segment)
{
json_object *jobj;
if (!jobj_segment ||
!json_object_object_get_ex(jobj_segment, "sector_size", &jobj))
return -1;
return json_object_get_int(jobj);
}
static json_object *json_segment_get_flags(json_object *jobj_segment)
{
json_object *jobj;
if (!jobj_segment || !(json_object_object_get_ex(jobj_segment, "flags", &jobj)))
return NULL;
return jobj;
}
bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
{
int r, i;
json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment);
if (!jobj_flags)
return false;
for (i = 0; i < (int)json_object_array_length(jobj_flags); i++) {
jobj = json_object_array_get_idx(jobj_flags, i);
if (len)
r = strncmp(json_object_get_string(jobj), flag_str, len);
else
r = strcmp(json_object_get_string(jobj), flag_str);
if (!r)
return true;
}
return false;
}
bool json_segment_is_backup(json_object *jobj_segment)
{
return json_segment_contains_flag(jobj_segment, "backup-", 7);
}
json_object *json_segments_get_segment(json_object *jobj_segments, int segment)
{
json_object *jobj;
char segment_name[16];
if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)
return NULL;
if (!json_object_object_get_ex(jobj_segments, segment_name, &jobj))
return NULL;
return jobj;
}
unsigned json_segments_count(json_object *jobj_segments)
{
unsigned count = 0;
if (!jobj_segments)
return 0;
json_object_object_foreach(jobj_segments, slot, val) {
UNUSED(slot);
if (!json_segment_is_backup(val))
count++;
}
return count;
}
static void _get_segment_or_id_by_flag(json_object *jobj_segments, const char *flag, unsigned id, void *retval)
{
json_object *jobj_flags, **jobj_ret = (json_object **)retval;
int *ret = (int *)retval;
if (!flag)
return;
json_object_object_foreach(jobj_segments, key, value) {
if (!json_object_object_get_ex(value, "flags", &jobj_flags))
continue;
if (LUKS2_array_jobj(jobj_flags, flag)) {
if (id)
*ret = atoi(key);
else
*jobj_ret = value;
return;
}
}
}
void json_segment_remove_flag(json_object *jobj_segment, const char *flag)
{
json_object *jobj_flags, *jobj_flags_new;
if (!jobj_segment)
return;
jobj_flags = json_segment_get_flags(jobj_segment);
if (!jobj_flags)
return;
jobj_flags_new = LUKS2_array_remove(jobj_flags, flag);
if (!jobj_flags_new)
return;
if (json_object_array_length(jobj_flags_new) <= 0) {
json_object_put(jobj_flags_new);
json_object_object_del(jobj_segment, "flags");
} else
json_object_object_add(jobj_segment, "flags", jobj_flags_new);
}
static json_object *_segment_create_generic(const char *type, uint64_t offset, const uint64_t *length)
{
json_object *jobj = json_object_new_object();
if (!jobj)
return NULL;
json_object_object_add(jobj, "type", json_object_new_string(type));
json_object_object_add(jobj, "offset", crypt_jobj_new_uint64(offset));
json_object_object_add(jobj, "size", length ? crypt_jobj_new_uint64(*length) : json_object_new_string("dynamic"));
return jobj;
}
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption)
{
json_object *jobj = _segment_create_generic("linear", offset, length);
if (reencryption)
LUKS2_segment_set_flag(jobj, "in-reencryption");
return jobj;
}
json_object *json_segment_create_crypt(uint64_t offset,
uint64_t iv_offset, const uint64_t *length,
const char *cipher, uint32_t sector_size,
unsigned reencryption)
{
json_object *jobj = _segment_create_generic("crypt", offset, length);
if (!jobj)
return NULL;
json_object_object_add(jobj, "iv_tweak", crypt_jobj_new_uint64(iv_offset));
json_object_object_add(jobj, "encryption", json_object_new_string(cipher));
json_object_object_add(jobj, "sector_size", json_object_new_int(sector_size));
if (reencryption)
LUKS2_segment_set_flag(jobj, "in-reencryption");
return jobj;
}
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr, int segment, unsigned blockwise)
{
return json_segment_get_offset(LUKS2_get_segment_jobj(hdr, segment), blockwise);
}
int json_segments_segment_in_reencrypt(json_object *jobj_segments)
{
json_object *jobj_flags;
json_object_object_foreach(jobj_segments, slot, val) {
if (!json_object_object_get_ex(val, "flags", &jobj_flags) ||
!LUKS2_array_jobj(jobj_flags, "in-reencryption"))
continue;
return atoi(slot);
}
return -1;
}
uint64_t LUKS2_segment_size(struct luks2_hdr *hdr, int segment, unsigned blockwise)
{
return json_segment_get_size(LUKS2_get_segment_jobj(hdr, segment), blockwise);
}
int LUKS2_segment_is_type(struct luks2_hdr *hdr, int segment, const char *type)
{
return !strcmp(json_segment_type(LUKS2_get_segment_jobj(hdr, segment)) ?: "", type);
}
int LUKS2_last_segment_by_type(struct luks2_hdr *hdr, const char *type)
{
json_object *jobj_segments;
int last_found = -1;
if (!type)
return -1;
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
return -1;
json_object_object_foreach(jobj_segments, slot, val) {
if (json_segment_is_backup(val))
continue;
if (strcmp(type, json_segment_type(val) ?: ""))
continue;
if (atoi(slot) > last_found)
last_found = atoi(slot);
}
return last_found;
}
int LUKS2_segment_by_type(struct luks2_hdr *hdr, const char *type)
{
json_object *jobj_segments;
int first_found = -1;
if (!type)
return -EINVAL;
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
return -EINVAL;
json_object_object_foreach(jobj_segments, slot, val) {
if (json_segment_is_backup(val))
continue;
if (strcmp(type, json_segment_type(val) ?: ""))
continue;
if (first_found < 0)
first_found = atoi(slot);
else if (atoi(slot) < first_found)
first_found = atoi(slot);
}
return first_found;
}
int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr)
{
json_object *jobj_segments;
int id, last_id = -1;
if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
return -EINVAL;
json_object_object_foreach(jobj_segments, slot, val) {
UNUSED(val);
id = atoi(slot);
if (id > last_id)
last_id = id;
}
return last_id + 1;
}
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag)
{
json_object *jobj_flags;
if (!jobj_segment || !flag)
return -EINVAL;
if (!json_object_object_get_ex(jobj_segment, "flags", &jobj_flags)) {
jobj_flags = json_object_new_array();
if (!jobj_flags)
return -ENOMEM;
json_object_object_add(jobj_segment, "flags", jobj_flags);
}
if (LUKS2_array_jobj(jobj_flags, flag))
return 0;
json_object_array_add(jobj_flags, json_object_new_string(flag));
return 0;
}
int LUKS2_segments_set(struct crypt_device *cd, struct luks2_hdr *hdr,
json_object *jobj_segments, int commit)
{
json_object_object_add(hdr->jobj, "segments", jobj_segments);
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
}
int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag)
{
int ret = -ENOENT;
json_object *jobj_segments = LUKS2_get_segments_jobj(hdr);
if (jobj_segments)
_get_segment_or_id_by_flag(jobj_segments, flag, 1, &ret);
return ret;
}
json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)
{
json_object *jobj_segment = NULL,
*jobj_segments = LUKS2_get_segments_jobj(hdr);
if (jobj_segments)
_get_segment_or_id_by_flag(jobj_segments, flag, 0, &jobj_segment);
return jobj_segment;
}
/* compares key characteristics of both segments */
bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2)
{
const char *type = json_segment_type(jobj_segment_1);
const char *type2 = json_segment_type(jobj_segment_2);
if (!type || !type2)
return false;
if (strcmp(type, type2))
return false;
if (!strcmp(type, "crypt"))
return (json_segment_get_sector_size(jobj_segment_1) == json_segment_get_sector_size(jobj_segment_2) &&
!strcmp(json_segment_get_cipher(jobj_segment_1),
json_segment_get_cipher(jobj_segment_2)));
return true;
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, token handling
*
* Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021 Milan Broz
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2018, Milan Broz. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -45,19 +45,21 @@ int crypt_token_register(const crypt_token_handler *handler)
int i;
if (is_builtin_candidate(handler->name)) {
log_dbg(NULL, "'" LUKS2_BUILTIN_TOKEN_PREFIX "' is reserved prefix for builtin tokens.");
log_dbg("'" LUKS2_BUILTIN_TOKEN_PREFIX "' is reserved prefix for builtin tokens.");
return -EINVAL;
}
for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].h; i++) {
if (!strcmp(token_handlers[i].h->name, handler->name)) {
log_dbg(NULL, "Keyslot handler %s is already registered.", handler->name);
log_dbg("Keyslot handler %s is already registered.", handler->name);
return -EINVAL;
}
}
if (i == LUKS2_TOKENS_MAX)
if (i == LUKS2_TOKENS_MAX) {
log_dbg("No more space for another token handler.");
return -EINVAL;
}
token_handlers[i].h = handler;
return 0;
@@ -147,21 +149,21 @@ int LUKS2_token_create(struct crypt_device *cd,
if (!json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens))
return -EINVAL;
if (snprintf(num, sizeof(num), "%d", token) < 0)
return -EINVAL;
/* Remove token */
if (!json)
if (!json) {
snprintf(num, sizeof(num), "%d", token);
json_object_object_del(jobj_tokens, num);
else {
} else {
jobj = json_tokener_parse_verbose(json, &jerr);
if (!jobj) {
log_dbg(cd, "Token JSON parse failed.");
log_dbg("Token JSON parse failed.");
return -EINVAL;
}
if (LUKS2_token_validate(cd, hdr->jobj, jobj, num)) {
snprintf(num, sizeof(num), "%d", token);
if (LUKS2_token_validate(hdr->jobj, jobj, num)) {
json_object_put(jobj);
return -EINVAL;
}
@@ -170,7 +172,7 @@ int LUKS2_token_create(struct crypt_device *cd,
if (is_builtin_candidate(json_object_get_string(jobj_type))) {
th = LUKS2_token_handler_type_internal(cd, json_object_get_string(jobj_type));
if (!th || !th->set) {
log_dbg(cd, "%s is builtin token candidate with missing handler", json_object_get_string(jobj_type));
log_dbg("%s is builtin token candidate with missing handler", json_object_get_string(jobj_type));
json_object_put(jobj);
return -EINVAL;
}
@@ -180,13 +182,13 @@ int LUKS2_token_create(struct crypt_device *cd,
if (h && h->validate && h->validate(cd, json)) {
json_object_put(jobj);
log_dbg(cd, "Token type %s validation failed.", h->name);
log_dbg("Token type %s validation failed.", h->name);
return -EINVAL;
}
json_object_object_add(jobj_tokens, num, jobj);
if (LUKS2_check_json_size(cd, hdr)) {
log_dbg(cd, "Not enough space in header json area for new token.");
if (LUKS2_check_json_size(hdr)) {
log_dbg("Not enough space in header json area for new token.");
json_object_object_del(jobj_tokens, num);
return -ENOSPC;
}
@@ -250,6 +252,7 @@ int LUKS2_builtin_token_create(struct crypt_device *cd,
int commit)
{
const token_handler *th;
char num[16];
int r;
json_object *jobj_token, *jobj_tokens;
@@ -264,6 +267,7 @@ int LUKS2_builtin_token_create(struct crypt_device *cd,
}
if (token < 0 || token >= LUKS2_TOKENS_MAX)
return -EINVAL;
snprintf(num, sizeof(num), "%u", token);
r = th->set(&jobj_token, params);
if (r) {
@@ -272,17 +276,17 @@ int LUKS2_builtin_token_create(struct crypt_device *cd,
}
// builtin tokens must produce valid json
r = LUKS2_token_validate(cd, hdr->jobj, jobj_token, "new");
r = LUKS2_token_validate(hdr->jobj, jobj_token, "new");
assert(!r);
r = th->h->validate(cd, json_object_to_json_string_ext(jobj_token,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE));
assert(!r);
json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens);
json_object_object_add_by_uint(jobj_tokens, token, jobj_token);
if (LUKS2_check_json_size(cd, hdr)) {
log_dbg(cd, "Not enough space in header json area for new %s token.", type);
json_object_object_del_by_uint(jobj_tokens, token);
json_object_object_add(jobj_tokens, num, jobj_token);
if (LUKS2_check_json_size(hdr)) {
log_dbg("Not enough space in header json area for new %s token.", type);
json_object_object_del(jobj_tokens, num);
return -ENOSPC;
}
@@ -311,14 +315,14 @@ static int LUKS2_token_open(struct crypt_device *cd,
return -EINVAL;
if (h->validate(cd, json)) {
log_dbg(cd, "Token %d (%s) validation failed.", token, h->name);
log_dbg("Token %d (%s) validation failed.", token, h->name);
return -EINVAL;
}
}
r = h->open(cd, token, buffer, buffer_len, usrptr);
if (r < 0)
log_dbg(cd, "Token %d (%s) open failed with %d.", token, h->name, r);
log_dbg("Token %d (%s) open failed with %d.", token, h->name, r);
return r;
}
@@ -330,10 +334,10 @@ static void LUKS2_token_buffer_free(struct crypt_device *cd,
{
const crypt_token_handler *h = LUKS2_token_handler(cd, token);
if (h && h->buffer_free)
if (h->buffer_free)
h->buffer_free(buffer, buffer_len);
else {
crypt_safe_memzero(buffer, buffer_len);
crypt_memzero(buffer, buffer_len);
free(buffer);
}
}
@@ -348,7 +352,7 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
{
const crypt_token_handler *h;
json_object *jobj_token, *jobj_token_keyslots, *jobj;
unsigned int num = 0;
const char *num = NULL;
int i, r;
if (!(h = LUKS2_token_handler(cd, token)))
@@ -366,15 +370,15 @@ static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
r = -EINVAL;
for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots) && r < 0; i++) {
jobj = json_object_array_get_idx(jobj_token_keyslots, i);
num = atoi(json_object_get_string(jobj));
log_dbg(cd, "Trying to open keyslot %u with token %d (type %s).", num, token, h->name);
r = LUKS2_keyslot_open(cd, num, segment, buffer, buffer_len, vk);
num = json_object_get_string(jobj);
log_dbg("Trying to open keyslot %s with token %d (type %s).", num, token, h->name);
r = LUKS2_keyslot_open(cd, atoi(num), segment, buffer, buffer_len, vk);
}
if (r < 0)
return r;
if (r >= 0 && num)
return atoi(num);
return num;
return r;
}
int LUKS2_token_open_and_activate(struct crypt_device *cd,
@@ -384,7 +388,6 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
uint32_t flags,
void *usrptr)
{
bool use_keyring;
int keyslot, r;
char *buffer;
size_t buffer_len;
@@ -406,22 +409,14 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
keyslot = r;
if (!crypt_use_keyring_for_vk(cd))
use_keyring = false;
else
use_keyring = ((name && !crypt_is_cipher_null(crypt_get_cipher(cd))) ||
(flags & CRYPT_ACTIVATE_KEYRING_KEY));
if (use_keyring) {
if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot)))
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
}
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot);
if (r >= 0 && name)
r = LUKS2_activate(cd, name, vk, flags);
if (r < 0)
crypt_drop_keyring_key(cd, vk);
if (r < 0 && vk)
crypt_drop_keyring_key(cd, vk->key_description);
crypt_free_volume_key(vk);
return r < 0 ? r : keyslot;
@@ -459,16 +454,14 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
keyslot = r;
if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) {
if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot)))
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
}
if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot);
if (r >= 0 && name)
r = LUKS2_activate(cd, name, vk, flags);
if (r < 0)
crypt_drop_keyring_key(cd, vk);
if (r < 0 && vk)
crypt_drop_keyring_key(cd, vk->key_description);
crypt_free_volume_key(vk);
return r < 0 ? r : keyslot;
@@ -508,7 +501,7 @@ static int assign_one_keyslot(struct crypt_device *cd, struct luks2_hdr *hdr,
json_object *jobj1, *jobj_token, *jobj_token_keyslots;
char num[16];
log_dbg(cd, "Keyslot %i %s token %i.", keyslot, assign ? "assigned to" : "unassigned from", token);
log_dbg("Keyslot %i %s token %i.", keyslot, assign ? "assigned to" : "unassigned from", token);
jobj_token = LUKS2_get_token_jobj(hdr, token);
if (!jobj_token)
@@ -518,9 +511,7 @@ static int assign_one_keyslot(struct crypt_device *cd, struct luks2_hdr *hdr,
if (!jobj_token_keyslots)
return -EINVAL;
if (snprintf(num, sizeof(num), "%d", keyslot) < 0)
return -EINVAL;
snprintf(num, sizeof(num), "%d", keyslot);
if (assign) {
jobj1 = LUKS2_array_jobj(jobj_token_keyslots, num);
if (!jobj1)
@@ -586,12 +577,16 @@ int LUKS2_token_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
return token;
}
static int token_is_assigned(struct luks2_hdr *hdr, int keyslot, int token)
int LUKS2_token_is_assigned(struct crypt_device *cd, struct luks2_hdr *hdr,
int keyslot, int token)
{
int i;
json_object *jobj, *jobj_token_keyslots,
*jobj_token = LUKS2_get_token_jobj(hdr, token);
json_object *jobj_token, *jobj_token_keyslots, *jobj;
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX || token < 0 || token >= LUKS2_TOKENS_MAX)
return -EINVAL;
jobj_token = LUKS2_get_token_jobj(hdr, token);
if (!jobj_token)
return -ENOENT;
@@ -606,15 +601,6 @@ static int token_is_assigned(struct luks2_hdr *hdr, int keyslot, int token)
return -ENOENT;
}
int LUKS2_token_is_assigned(struct crypt_device *cd, struct luks2_hdr *hdr,
int keyslot, int token)
{
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX || token < 0 || token >= LUKS2_TOKENS_MAX)
return -EINVAL;
return token_is_assigned(hdr, keyslot, token);
}
int LUKS2_tokens_count(struct luks2_hdr *hdr)
{
json_object *jobj_tokens = LUKS2_get_tokens_jobj(hdr);
@@ -623,28 +609,3 @@ int LUKS2_tokens_count(struct luks2_hdr *hdr)
return json_object_object_length(jobj_tokens);
}
int LUKS2_token_assignment_copy(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot_from,
int keyslot_to,
int commit)
{
int i, r;
if (keyslot_from < 0 || keyslot_from >= LUKS2_KEYSLOTS_MAX || keyslot_to < 0 || keyslot_to >= LUKS2_KEYSLOTS_MAX)
return -EINVAL;
r = LUKS2_tokens_count(hdr);
if (r <= 0)
return r;
for (i = 0; i < LUKS2_TOKENS_MAX; i++) {
if (!token_is_assigned(hdr, keyslot_from, i)) {
if ((r = assign_one_token(cd, hdr, keyslot_to, i, 1)))
return r;
}
}
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
}

View File

@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, kernel keyring token
*
* Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2021 Ondrej Kozina
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2018, Ondrej Kozina. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -44,10 +44,10 @@ static int keyring_open(struct crypt_device *cd,
r = keyring_get_passphrase(json_object_get_string(jobj_key), buffer, buffer_len);
if (r == -ENOTSUP) {
log_dbg(cd, "Kernel keyring features disabled.");
log_dbg("Kernel keyring features disabled.");
return -EINVAL;
} else if (r < 0) {
log_dbg(cd, "keyring_get_passphrase failed (error %d)", r);
log_dbg("keyring_get_passphrase failed (error %d)", r);
return -EINVAL;
}
@@ -61,26 +61,26 @@ static int keyring_validate(struct crypt_device *cd __attribute__((unused)),
json_object *jobj_token, *jobj_key;
int r = 1;
log_dbg(cd, "Validating keyring token json");
log_dbg("Validating keyring token json");
jobj_token = json_tokener_parse_verbose(json, &jerr);
if (!jobj_token) {
log_dbg(cd, "Keyring token JSON parse failed.");
log_dbg("Keyring token JSON parse failed.");
return r;
}
if (json_object_object_length(jobj_token) != 3) {
log_dbg(cd, "Keyring token is expected to have exactly 3 fields.");
log_dbg("Keyring token is expected to have exactly 3 fields.");
goto out;
}
if (!json_object_object_get_ex(jobj_token, "key_description", &jobj_key)) {
log_dbg(cd, "missing key_description field.");
log_dbg("missing key_description field.");
goto out;
}
if (!json_object_is_type(jobj_key, json_type_string)) {
log_dbg(cd, "key_description is not a string.");
log_dbg("key_description is not a string.");
goto out;
}

View File

@@ -1,7 +1,7 @@
/*
* cryptsetup kernel RNG access functions
*
* Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2018, Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <sys/select.h>
@@ -27,6 +28,10 @@
#include "libcryptsetup.h"
#include "internal.h"
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
static int random_initialised = 0;
#define URANDOM_DEVICE "/dev/urandom"

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
/*
* TCRYPT (TrueCrypt-compatible) and VeraCrypt volume handling
*
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include "libcryptsetup.h"
@@ -201,8 +202,7 @@ static struct tcrypt_algs tcrypt_cipher[] = {
{}
};
static int TCRYPT_hdr_from_disk(struct crypt_device *cd,
struct tcrypt_phdr *hdr,
static int TCRYPT_hdr_from_disk(struct tcrypt_phdr *hdr,
struct crypt_params_tcrypt *params,
int kdf_index, int cipher_index)
{
@@ -214,14 +214,14 @@ static int TCRYPT_hdr_from_disk(struct crypt_device *cd,
crc32 = crypt_crc32(~0, (unsigned char*)&hdr->d, size) ^ ~0;
if (be16_to_cpu(hdr->d.version) > 3 &&
crc32 != be32_to_cpu(hdr->d.header_crc32)) {
log_dbg(cd, "TCRYPT header CRC32 mismatch.");
log_dbg("TCRYPT header CRC32 mismatch.");
return -EINVAL;
}
/* Check CRC32 of keys */
crc32 = crypt_crc32(~0, (unsigned char*)hdr->d.keys, sizeof(hdr->d.keys)) ^ ~0;
if (crc32 != be32_to_cpu(hdr->d.keys_crc32)) {
log_dbg(cd, "TCRYPT keys CRC32 mismatch.");
log_dbg("TCRYPT keys CRC32 mismatch.");
return -EINVAL;
}
@@ -300,8 +300,8 @@ static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg,
}
crypt_cipher_destroy(cipher);
crypt_safe_memzero(iv, bs);
crypt_safe_memzero(iv_old, bs);
crypt_memzero(iv, bs);
crypt_memzero(iv_old, bs);
return r;
}
@@ -368,8 +368,8 @@ static int TCRYPT_decrypt_hdr_one(struct tcrypt_alg *alg, const char *mode,
crypt_cipher_destroy(cipher);
}
crypt_safe_memzero(backend_key, sizeof(backend_key));
crypt_safe_memzero(iv, TCRYPT_HDR_IV_LEN);
crypt_memzero(backend_key, sizeof(backend_key));
crypt_memzero(iv, TCRYPT_HDR_IV_LEN);
return r;
}
@@ -419,8 +419,8 @@ out:
if (cipher[j])
crypt_cipher_destroy(cipher[j]);
crypt_safe_memzero(iv, bs);
crypt_safe_memzero(iv_old, bs);
crypt_memzero(iv, bs);
crypt_memzero(iv_old, bs);
return r;
}
@@ -433,7 +433,7 @@ static int TCRYPT_decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr,
for (i = 0; tcrypt_cipher[i].chain_count; i++) {
if (!(flags & CRYPT_TCRYPT_LEGACY_MODES) && tcrypt_cipher[i].legacy)
continue;
log_dbg(cd, "TCRYPT: trying cipher %s-%s",
log_dbg("TCRYPT: trying cipher %s-%s",
tcrypt_cipher[i].long_name, tcrypt_cipher[i].mode);
memcpy(&hdr2.e, &hdr->e, TCRYPT_HDR_LEN);
@@ -450,7 +450,7 @@ static int TCRYPT_decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr,
}
if (r < 0) {
log_dbg(cd, "TCRYPT: returned error %d, skipped.", r);
log_dbg("TCRYPT: returned error %d, skipped.", r);
if (r == -ENOTSUP)
break;
r = -ENOENT;
@@ -458,14 +458,14 @@ static int TCRYPT_decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr,
}
if (!strncmp(hdr2.d.magic, TCRYPT_HDR_MAGIC, TCRYPT_HDR_MAGIC_LEN)) {
log_dbg(cd, "TCRYPT: Signature magic detected.");
log_dbg("TCRYPT: Signature magic detected.");
memcpy(&hdr->e, &hdr2.e, TCRYPT_HDR_LEN);
r = i;
break;
}
if ((flags & CRYPT_TCRYPT_VERA_MODES) &&
!strncmp(hdr2.d.magic, VCRYPT_HDR_MAGIC, TCRYPT_HDR_MAGIC_LEN)) {
log_dbg(cd, "TCRYPT: Signature magic detected (Veracrypt).");
log_dbg("TCRYPT: Signature magic detected (Veracrypt).");
memcpy(&hdr->e, &hdr2.e, TCRYPT_HDR_LEN);
r = i;
break;
@@ -473,19 +473,19 @@ static int TCRYPT_decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr,
r = -EPERM;
}
crypt_safe_memzero(&hdr2, sizeof(hdr2));
crypt_memzero(&hdr2, sizeof(hdr2));
return r;
}
static int TCRYPT_pool_keyfile(struct crypt_device *cd,
unsigned char pool[VCRYPT_KEY_POOL_LEN],
const char *keyfile, int keyfiles_pool_length)
unsigned char pool[TCRYPT_KEY_POOL_LEN],
const char *keyfile)
{
unsigned char *data;
int i, j, fd, data_size, r = -EIO;
uint32_t crc;
log_dbg(cd, "TCRYPT: using keyfile %s.", keyfile);
log_dbg("TCRYPT: using keyfile %s.", keyfile);
data = malloc(TCRYPT_KEYFILE_LEN);
if (!data)
@@ -511,12 +511,12 @@ static int TCRYPT_pool_keyfile(struct crypt_device *cd,
pool[j++] += (unsigned char)(crc >> 16);
pool[j++] += (unsigned char)(crc >> 8);
pool[j++] += (unsigned char)(crc);
j %= keyfiles_pool_length;
j %= TCRYPT_KEY_POOL_LEN;
}
r = 0;
out:
crypt_safe_memzero(&crc, sizeof(crc));
crypt_safe_memzero(data, TCRYPT_KEYFILE_LEN);
crypt_memzero(&crc, sizeof(crc));
crypt_memzero(data, TCRYPT_KEYFILE_LEN);
free(data);
return r;
@@ -526,39 +526,29 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
struct tcrypt_phdr *hdr,
struct crypt_params_tcrypt *params)
{
unsigned char pwd[VCRYPT_KEY_POOL_LEN] = {};
size_t passphrase_size, max_passphrase_size;
unsigned char pwd[TCRYPT_KEY_POOL_LEN] = {};
size_t passphrase_size;
char *key;
unsigned int i, skipped = 0, iterations;
int r = -EPERM, keyfiles_pool_length;
int r = -EPERM;
if (posix_memalign((void*)&key, crypt_getpagesize(), TCRYPT_HDR_KEY_LEN))
return -ENOMEM;
if (params->flags & CRYPT_TCRYPT_VERA_MODES &&
params->passphrase_size > TCRYPT_KEY_POOL_LEN) {
/* Really. Keyfile pool length depends on passphrase size in Veracrypt. */
max_passphrase_size = VCRYPT_KEY_POOL_LEN;
keyfiles_pool_length = VCRYPT_KEY_POOL_LEN;
} else {
max_passphrase_size = TCRYPT_KEY_POOL_LEN;
keyfiles_pool_length = TCRYPT_KEY_POOL_LEN;
}
if (params->keyfiles_count)
passphrase_size = max_passphrase_size;
passphrase_size = TCRYPT_KEY_POOL_LEN;
else
passphrase_size = params->passphrase_size;
if (params->passphrase_size > max_passphrase_size) {
log_err(cd, _("Maximum TCRYPT passphrase length (%zu) exceeded."),
max_passphrase_size);
if (params->passphrase_size > TCRYPT_KEY_POOL_LEN) {
log_err(cd, _("Maximum TCRYPT passphrase length (%d) exceeded."),
TCRYPT_KEY_POOL_LEN);
goto out;
}
/* Calculate pool content from keyfiles */
for (i = 0; i < params->keyfiles_count; i++) {
r = TCRYPT_pool_keyfile(cd, pwd, params->keyfiles[i], keyfiles_pool_length);
r = TCRYPT_pool_keyfile(cd, pwd, params->keyfiles[i]);
if (r < 0)
goto out;
}
@@ -583,7 +573,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
iterations = tcrypt_kdf[i].iterations;
/* Derive header key */
log_dbg(cd, "TCRYPT: trying KDF: %s-%s-%d%s.",
log_dbg("TCRYPT: trying KDF: %s-%s-%d%s.",
tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations,
params->veracrypt_pim && tcrypt_kdf[i].veracrypt ? "-PIM" : "");
r = crypt_pbkdf(tcrypt_kdf[i].name, tcrypt_kdf[i].hash,
@@ -591,11 +581,13 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
hdr->salt, TCRYPT_HDR_SALT_LEN,
key, TCRYPT_HDR_KEY_LEN,
iterations, 0, 0);
if (r < 0) {
if (r < 0 && crypt_hash_size(tcrypt_kdf[i].hash) < 0) {
log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping."),
tcrypt_kdf[i].hash);
continue;
}
if (r < 0)
break;
/* Decrypt header */
r = TCRYPT_decrypt_hdr(cd, hdr, key, params->flags);
@@ -616,21 +608,21 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
if (r < 0)
goto out;
r = TCRYPT_hdr_from_disk(cd, hdr, params, i, r);
r = TCRYPT_hdr_from_disk(hdr, params, i, r);
if (!r) {
log_dbg(cd, "TCRYPT: Magic: %s, Header version: %d, req. %d, sector %d"
log_dbg("TCRYPT: Magic: %s, Header version: %d, req. %d, sector %d"
", mk_offset %" PRIu64 ", hidden_size %" PRIu64
", volume size %" PRIu64, tcrypt_kdf[i].veracrypt ?
VCRYPT_HDR_MAGIC : TCRYPT_HDR_MAGIC,
(int)hdr->d.version, (int)hdr->d.version_tc, (int)hdr->d.sector_size,
hdr->d.mk_offset, hdr->d.hidden_volume_size, hdr->d.volume_size);
log_dbg(cd, "TCRYPT: Header cipher %s-%s, key size %zu",
log_dbg("TCRYPT: Header cipher %s-%s, key size %zu",
params->cipher, params->mode, params->key_size);
}
out:
crypt_safe_memzero(pwd, TCRYPT_KEY_POOL_LEN);
crypt_memzero(pwd, TCRYPT_KEY_POOL_LEN);
if (key)
crypt_safe_memzero(key, TCRYPT_HDR_KEY_LEN);
crypt_memzero(key, TCRYPT_HDR_KEY_LEN);
free(key);
return r;
}
@@ -639,71 +631,71 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
struct tcrypt_phdr *hdr,
struct crypt_params_tcrypt *params)
{
struct device *base_device = NULL, *device = crypt_metadata_device(cd);
struct device *base_device, *device = crypt_metadata_device(cd);
ssize_t hdr_size = sizeof(struct tcrypt_phdr);
char *base_device_path;
int devfd, r;
int devfd = 0, r;
assert(sizeof(struct tcrypt_phdr) == 512);
log_dbg(cd, "Reading TCRYPT header of size %zu bytes from device %s.",
log_dbg("Reading TCRYPT header of size %zu bytes from device %s.",
hdr_size, device_path(device));
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER &&
crypt_dev_is_partition(device_path(device))) {
base_device_path = crypt_get_base_device(device_path(device));
log_dbg(cd, "Reading TCRYPT system header from device %s.", base_device_path ?: "?");
log_dbg("Reading TCRYPT system header from device %s.", base_device_path ?: "?");
if (!base_device_path)
return -EINVAL;
r = device_alloc(cd, &base_device, base_device_path);
r = device_alloc(&base_device, base_device_path);
free(base_device_path);
if (r < 0)
return r;
devfd = device_open(cd, base_device, O_RDONLY);
devfd = device_open(base_device, O_RDONLY);
device_free(base_device);
} else
devfd = device_open(cd, device, O_RDONLY);
devfd = device_open(device, O_RDONLY);
if (devfd < 0) {
device_free(cd, base_device);
log_err(cd, _("Cannot open device %s."), device_path(device));
return -EINVAL;
}
r = -EIO;
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) {
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), hdr, hdr_size,
TCRYPT_HDR_SYSTEM_OFFSET) == hdr_size) {
r = TCRYPT_init_hdr(cd, hdr, params);
}
} else if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER) {
if (params->flags & CRYPT_TCRYPT_BACKUP_HEADER) {
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), hdr, hdr_size,
TCRYPT_HDR_HIDDEN_OFFSET_BCK) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
} else {
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), hdr, hdr_size,
TCRYPT_HDR_HIDDEN_OFFSET) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
if (r && read_lseek_blockwise(devfd, device_block_size(cd, device),
if (r && read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), hdr, hdr_size,
TCRYPT_HDR_HIDDEN_OFFSET_OLD) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
}
} else if (params->flags & CRYPT_TCRYPT_BACKUP_HEADER) {
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
if (read_lseek_blockwise(devfd, device_block_size(device),
device_alignment(device), hdr, hdr_size,
TCRYPT_HDR_OFFSET_BCK) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
} else if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), hdr, hdr_size, 0) == hdr_size)
} else if (read_blockwise(devfd, device_block_size(device),
device_alignment(device), hdr, hdr_size) == hdr_size)
r = TCRYPT_init_hdr(cd, hdr, params);
device_free(cd, base_device);
close(devfd);
if (r < 0)
memset(hdr, 0, sizeof (*hdr));
return r;
@@ -730,33 +722,39 @@ int TCRYPT_activate(struct crypt_device *cd,
struct crypt_params_tcrypt *params,
uint32_t flags)
{
char dm_name[PATH_MAX], dm_dev_name[PATH_MAX], cipher_spec[MAX_CIPHER_LEN*2+1];
char cipher[MAX_CIPHER_LEN], dm_name[PATH_MAX], dm_dev_name[PATH_MAX];
char *part_path;
struct device *device = NULL, *part_device = NULL;
unsigned int i;
int r;
uint32_t req_flags, dmc_flags;
struct tcrypt_algs *algs;
enum devcheck device_check;
uint64_t offset = crypt_get_data_offset(cd);
struct volume_key *vk = NULL;
struct device *ptr_dev = crypt_data_device(cd), *device = NULL, *part_device = NULL;
struct crypt_dm_active_device dmd = {
.flags = flags
.target = DM_CRYPT,
.size = 0,
.data_device = crypt_data_device(cd),
.u.crypt = {
.cipher = cipher,
.offset = crypt_get_data_offset(cd),
.iv_offset = crypt_get_iv_offset(cd),
.sector_size = crypt_get_sector_size(cd),
}
};
if (!hdr->d.version) {
log_dbg(cd, "TCRYPT: this function is not supported without encrypted header load.");
log_dbg("TCRYPT: this function is not supported without encrypted header load.");
return -ENOTSUP;
}
if (hdr->d.sector_size % SECTOR_SIZE) {
if (hdr->d.sector_size && hdr->d.sector_size != SECTOR_SIZE) {
log_err(cd, _("Activation is not supported for %d sector size."),
hdr->d.sector_size);
return -ENOTSUP;
}
if (strstr(params->mode, "-tcrypt")) {
log_err(cd, _("Kernel does not support activation for this TCRYPT legacy mode."));
log_err(cd, _("Kernel doesn't support activation for this TCRYPT legacy mode."));
return -ENOTSUP;
}
@@ -769,28 +767,31 @@ int TCRYPT_activate(struct crypt_device *cd,
if (!algs)
return -EINVAL;
if (hdr->d.sector_size == 0)
return -EINVAL;
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER)
dmd.size = 0;
else if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER)
dmd.size = hdr->d.hidden_volume_size / SECTOR_SIZE;
dmd.size = hdr->d.hidden_volume_size / hdr->d.sector_size;
else
dmd.size = hdr->d.volume_size / SECTOR_SIZE;
dmd.size = hdr->d.volume_size / hdr->d.sector_size;
if (dmd.flags & CRYPT_ACTIVATE_SHARED)
device_check = DEV_OK;
device_check = DEV_SHARED;
else
device_check = DEV_EXCL;
if ((params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) &&
!crypt_dev_is_partition(device_path(crypt_data_device(cd)))) {
part_path = crypt_get_partition_device(device_path(crypt_data_device(cd)),
crypt_get_data_offset(cd), dmd.size);
!crypt_dev_is_partition(device_path(dmd.data_device))) {
part_path = crypt_get_partition_device(device_path(dmd.data_device),
dmd.u.crypt.offset, dmd.size);
if (part_path) {
if (!device_alloc(cd, &part_device, part_path)) {
if (!device_alloc(&part_device, part_path)) {
log_verbose(cd, _("Activating TCRYPT system encryption for partition %s."),
part_path);
ptr_dev = part_device;
offset = 0;
dmd.data_device = part_device;
dmd.u.crypt.offset = 0;
}
free(part_path);
} else
@@ -798,20 +799,22 @@ int TCRYPT_activate(struct crypt_device *cd,
* System encryption use the whole device mapping, there can
* be active partitions.
*/
device_check = DEV_OK;
device_check = DEV_SHARED;
}
r = device_block_adjust(cd, ptr_dev, device_check,
offset, &dmd.size, &dmd.flags);
if (r)
goto out;
r = device_block_adjust(cd, dmd.data_device, device_check,
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
if (r) {
device_free(part_device);
return r;
}
/* From here, key size for every cipher must be the same */
vk = crypt_alloc_volume_key(algs->cipher[0].key_size +
algs->cipher[0].key_extra_size, NULL);
if (!vk) {
r = -ENOMEM;
goto out;
dmd.u.crypt.vk = crypt_alloc_volume_key(algs->cipher[0].key_size +
algs->cipher[0].key_extra_size, NULL);
if (!dmd.u.crypt.vk) {
device_free(part_device);
return -ENOMEM;
}
for (i = algs->chain_count; i > 0; i--) {
@@ -824,39 +827,27 @@ int TCRYPT_activate(struct crypt_device *cd,
dmd.flags = flags | CRYPT_ACTIVATE_PRIVATE;
}
snprintf(cipher, sizeof(cipher), "%s-%s",
algs->cipher[i-1].name, algs->mode);
TCRYPT_copy_key(&algs->cipher[i-1], algs->mode,
vk->key, hdr->d.keys);
dmd.u.crypt.vk->key, hdr->d.keys);
if (algs->chain_count != i) {
snprintf(dm_dev_name, sizeof(dm_dev_name), "%s/%s_%d",
dm_get_dir(), name, i);
r = device_alloc(cd, &device, dm_dev_name);
r = device_alloc(&device, dm_dev_name);
if (r)
break;
ptr_dev = device;
offset = 0;
dmd.data_device = device;
dmd.u.crypt.offset = 0;
}
r = snprintf(cipher_spec, sizeof(cipher_spec), "%s-%s", algs->cipher[i-1].name, algs->mode);
if (r < 0 || (size_t)r >= sizeof(cipher_spec)) {
r = -ENOMEM;
break;
}
log_dbg("Trying to activate TCRYPT device %s using cipher %s.",
dm_name, dmd.u.crypt.cipher);
r = dm_create_device(cd, dm_name, CRYPT_TCRYPT, &dmd, 0);
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, ptr_dev, vk,
cipher_spec, crypt_get_iv_offset(cd), offset,
crypt_get_integrity(cd),
crypt_get_integrity_tag_size(cd),
crypt_get_sector_size(cd));
if (r)
break;
log_dbg(cd, "Trying to activate TCRYPT device %s using cipher %s.",
dm_name, dmd.segment.u.crypt.cipher);
r = dm_create_device(cd, dm_name, CRYPT_TCRYPT, &dmd);
dm_targets_free(cd, &dmd);
device_free(cd, device);
device_free(device);
device = NULL;
if (r)
@@ -864,22 +855,20 @@ int TCRYPT_activate(struct crypt_device *cd,
}
if (r < 0 &&
(dm_flags(cd, DM_CRYPT, &dmc_flags) || ((dmc_flags & req_flags) != req_flags))) {
log_err(cd, _("Kernel does not support TCRYPT compatible mapping."));
(dm_flags(DM_CRYPT, &dmc_flags) || ((dmc_flags & req_flags) != req_flags))) {
log_err(cd, _("Kernel doesn't support TCRYPT compatible mapping."));
r = -ENOTSUP;
}
out:
crypt_free_volume_key(vk);
device_free(cd, device);
device_free(cd, part_device);
device_free(part_device);
crypt_free_volume_key(dmd.u.crypt.vk);
return r;
}
static int TCRYPT_remove_one(struct crypt_device *cd, const char *name,
const char *base_uuid, int index, uint32_t flags)
{
struct crypt_dm_active_device dmd;
struct crypt_dm_active_device dmd = {};
char dm_name[PATH_MAX];
int r;
@@ -900,7 +889,7 @@ static int TCRYPT_remove_one(struct crypt_device *cd, const char *name,
int TCRYPT_deactivate(struct crypt_device *cd, const char *name, uint32_t flags)
{
struct crypt_dm_active_device dmd;
struct crypt_dm_active_device dmd = {};
int r;
r = dm_query_device(cd, name, DM_ACTIVE_UUID, &dmd);
@@ -918,19 +907,19 @@ int TCRYPT_deactivate(struct crypt_device *cd, const char *name, uint32_t flags)
goto out;
r = TCRYPT_remove_one(cd, name, dmd.uuid, 2, flags);
if (r < 0)
goto out;
out:
free(CONST_CAST(void*)dmd.uuid);
return (r == -ENODEV) ? 0 : r;
}
static int TCRYPT_status_one(struct crypt_device *cd, const char *name,
const char *base_uuid, int index,
size_t *key_size, char *cipher,
struct tcrypt_phdr *tcrypt_hdr,
struct device **device)
const char *base_uuid, int index,
size_t *key_size, char *cipher,
uint64_t *data_offset, struct device **device)
{
struct crypt_dm_active_device dmd;
struct dm_target *tgt = &dmd.segment;
struct crypt_dm_active_device dmd = {};
char dm_name[PATH_MAX], *c;
int r;
@@ -945,35 +934,30 @@ static int TCRYPT_status_one(struct crypt_device *cd, const char *name,
DM_ACTIVE_UUID |
DM_ACTIVE_CRYPT_CIPHER |
DM_ACTIVE_CRYPT_KEYSIZE, &dmd);
if (r < 0)
return r;
if (!single_segment(&dmd) || tgt->type != DM_CRYPT) {
r = -ENOTSUP;
goto out;
}
r = 0;
if (!strncmp(dmd.uuid, base_uuid, strlen(base_uuid))) {
if ((c = strchr(tgt->u.crypt.cipher, '-')))
if (r > 0)
r = 0;
if (!r && !strncmp(dmd.uuid, base_uuid, strlen(base_uuid))) {
if ((c = strchr(dmd.u.crypt.cipher, '-')))
*c = '\0';
strcat(cipher, "-");
strncat(cipher, tgt->u.crypt.cipher, MAX_CIPHER_LEN);
*key_size += tgt->u.crypt.vk->keylength;
tcrypt_hdr->d.mk_offset = tgt->u.crypt.offset * SECTOR_SIZE;
device_free(cd, *device);
MOVE_REF(*device, tgt->data_device);
} else
strncat(cipher, dmd.u.crypt.cipher, MAX_CIPHER_LEN);
*key_size += dmd.u.crypt.vk->keylength;
*data_offset = dmd.u.crypt.offset * SECTOR_SIZE;
device_free(*device);
*device = dmd.data_device;
} else {
device_free(dmd.data_device);
r = -ENODEV;
out:
dm_targets_free(cd, &dmd);
}
free(CONST_CAST(void*)dmd.uuid);
free(CONST_CAST(void*)dmd.u.crypt.cipher);
crypt_free_volume_key(dmd.u.crypt.vk);
return r;
}
int TCRYPT_init_by_name(struct crypt_device *cd, const char *name,
const char *uuid,
const struct dm_target *tgt,
const struct crypt_dm_active_device *dmd,
struct device **device,
struct crypt_params_tcrypt *tcrypt_params,
struct tcrypt_phdr *tcrypt_hdr)
@@ -986,9 +970,9 @@ int TCRYPT_init_by_name(struct crypt_device *cd, const char *name,
memset(tcrypt_params, 0, sizeof(*tcrypt_params));
memset(tcrypt_hdr, 0, sizeof(*tcrypt_hdr));
tcrypt_hdr->d.sector_size = SECTOR_SIZE;
tcrypt_hdr->d.mk_offset = tgt->u.crypt.offset * SECTOR_SIZE;
tcrypt_hdr->d.mk_offset = dmd->u.crypt.offset * SECTOR_SIZE;
strncpy(cipher, tgt->u.crypt.cipher, MAX_CIPHER_LEN);
strncpy(cipher, dmd->u.crypt.cipher, MAX_CIPHER_LEN);
tmp = strchr(cipher, '-');
if (!tmp)
return -EINVAL;
@@ -996,12 +980,12 @@ int TCRYPT_init_by_name(struct crypt_device *cd, const char *name,
mode[MAX_CIPHER_LEN] = '\0';
strncpy(mode, ++tmp, MAX_CIPHER_LEN);
key_size = tgt->u.crypt.vk->keylength;
r = TCRYPT_status_one(cd, name, uuid, 1, &key_size,
cipher, tcrypt_hdr, device);
key_size = dmd->u.crypt.vk->keylength;
r = TCRYPT_status_one(cd, name, dmd->uuid, 1, &key_size,
cipher, &tcrypt_hdr->d.mk_offset, device);
if (!r)
r = TCRYPT_status_one(cd, name, uuid, 2, &key_size,
cipher, tcrypt_hdr, device);
r = TCRYPT_status_one(cd, name, dmd->uuid, 2, &key_size,
cipher, &tcrypt_hdr->d.mk_offset, device);
if (r < 0 && r != -ENODEV)
return r;
@@ -1028,7 +1012,7 @@ uint64_t TCRYPT_get_data_offset(struct crypt_device *cd,
/* Mapping through whole device, not partition! */
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER) {
if (crypt_dev_is_partition(device_path(crypt_data_device(cd))))
if (crypt_dev_is_partition(device_path(crypt_metadata_device(cd))))
return 0;
goto hdr_offset;
}
@@ -1039,11 +1023,11 @@ uint64_t TCRYPT_get_data_offset(struct crypt_device *cd,
if (params->flags & CRYPT_TCRYPT_HIDDEN_HEADER) {
if (hdr->d.version > 3)
return (hdr->d.mk_offset / SECTOR_SIZE);
return (hdr->d.mk_offset / hdr->d.sector_size);
if (device_size(crypt_metadata_device(cd), &size) < 0)
return 0;
return (size - hdr->d.hidden_volume_size +
(TCRYPT_HDR_HIDDEN_OFFSET_OLD)) / SECTOR_SIZE;
(TCRYPT_HDR_HIDDEN_OFFSET_OLD)) / hdr->d.sector_size;
}
goto hdr_offset;
}
@@ -1052,11 +1036,11 @@ uint64_t TCRYPT_get_data_offset(struct crypt_device *cd,
if (device_size(crypt_metadata_device(cd), &size) < 0)
return 0;
return (size - hdr->d.hidden_volume_size +
(TCRYPT_HDR_HIDDEN_OFFSET_OLD)) / SECTOR_SIZE;
(TCRYPT_HDR_HIDDEN_OFFSET_OLD)) / hdr->d.sector_size;
}
hdr_offset:
return hdr->d.mk_offset / SECTOR_SIZE;
return hdr->d.mk_offset / hdr->d.sector_size;
}
uint64_t TCRYPT_get_iv_offset(struct crypt_device *cd,
@@ -1070,10 +1054,10 @@ uint64_t TCRYPT_get_iv_offset(struct crypt_device *cd,
else if (params->mode && !strncmp(params->mode, "lrw", 3))
iv_offset = 0;
else
iv_offset = hdr->d.mk_offset / SECTOR_SIZE;
iv_offset = hdr->d.mk_offset / hdr->d.sector_size;
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER)
iv_offset += crypt_dev_partition_offset(device_path(crypt_data_device(cd)));
iv_offset += crypt_dev_partition_offset(device_path(crypt_metadata_device(cd)));
return iv_offset;
}

View File

@@ -1,8 +1,8 @@
/*
* TCRYPT (TrueCrypt-compatible) header definition
* TCRYPT (TrueCrypt-compatible) header defitinion
*
* Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2021 Milan Broz
* Copyright (C) 2012-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2018, Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -42,7 +42,6 @@
#define TCRYPT_LRW_IKEY_LEN 16
#define TCRYPT_KEY_POOL_LEN 64
#define VCRYPT_KEY_POOL_LEN 128
#define TCRYPT_KEYFILE_LEN 1048576
#define TCRYPT_HDR_FLAG_SYSTEM (1 << 0)
@@ -76,7 +75,6 @@ struct tcrypt_phdr {
struct crypt_device;
struct crypt_params_tcrypt;
struct crypt_dm_active_device;
struct dm_target;
struct volume_key;
struct device;
@@ -85,8 +83,7 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
struct crypt_params_tcrypt *params);
int TCRYPT_init_by_name(struct crypt_device *cd, const char *name,
const char *uuid,
const struct dm_target *tgt,
const struct crypt_dm_active_device *dmd,
struct device **device,
struct crypt_params_tcrypt *tcrypt_params,
struct tcrypt_phdr *tcrypt_hdr);

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