mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-06 00:10:04 +01:00
Compare commits
285 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
517b5da67a | ||
|
|
98460af44f | ||
|
|
7213d5a76b | ||
|
|
bb29c5b322 | ||
|
|
58ad7bae48 | ||
|
|
82a3480b12 | ||
|
|
c00811a846 | ||
|
|
27eaf46c8a | ||
|
|
202aeece3c | ||
|
|
825fc895dc | ||
|
|
a74aecedf1 | ||
|
|
fa1f63bcd0 | ||
|
|
c2bce3e93e | ||
|
|
a46733e701 | ||
|
|
8f350f9b9f | ||
|
|
484692aacd | ||
|
|
7f0df99511 | ||
|
|
bebd2fe7e7 | ||
|
|
36e8839675 | ||
|
|
61305a50c1 | ||
|
|
1d7749a40f | ||
|
|
f01d044618 | ||
|
|
31532adf86 | ||
|
|
879e06db39 | ||
|
|
4beb0f702a | ||
|
|
a771460dbd | ||
|
|
f849f83d84 | ||
|
|
1d084a41ad | ||
|
|
c4198986f1 | ||
|
|
7514786b20 | ||
|
|
9df042c0b8 | ||
|
|
37e0150f70 | ||
|
|
294e4cbcb7 | ||
|
|
952716afe1 | ||
|
|
24aba9a514 | ||
|
|
905993751c | ||
|
|
0b10d877b0 | ||
|
|
874fa5810d | ||
|
|
5be31bbce6 | ||
|
|
a6e3a31690 | ||
|
|
506f3f7b57 | ||
|
|
cd1c36ef94 | ||
|
|
ee689d88b4 | ||
|
|
b93b676336 | ||
|
|
1c6d66fccc | ||
|
|
114356ad2e | ||
|
|
7ab419701c | ||
|
|
d41b1a7560 | ||
|
|
622943529e | ||
|
|
9d7cc152f9 | ||
|
|
3f73d448f3 | ||
|
|
a1b606803f | ||
|
|
b2c7b40568 | ||
|
|
0cbe09d43a | ||
|
|
f1d5b94762 | ||
|
|
6fc2e7c774 | ||
|
|
3b39c1d1ef | ||
|
|
5a3e4abf71 | ||
|
|
48e9362186 | ||
|
|
03a74b74e5 | ||
|
|
248f99cad3 | ||
|
|
d2f0773eb8 | ||
|
|
dd36d56d47 | ||
|
|
0270fc66a1 | ||
|
|
69a844c654 | ||
|
|
5b5a64361f | ||
|
|
26f6d1cb10 | ||
|
|
f87eb1668a | ||
|
|
3114abfd55 | ||
|
|
5a94cff91e | ||
|
|
d704e87ee4 | ||
|
|
c8ce996872 | ||
|
|
0e7b068061 | ||
|
|
71dd149ca2 | ||
|
|
b30ba41d6a | ||
|
|
a0bf790892 | ||
|
|
caefc4eb8e | ||
|
|
31364c17d6 | ||
|
|
5e56966e72 | ||
|
|
1f951ed7ec | ||
|
|
ecd82f1fc9 | ||
|
|
7aaf1eeb1b | ||
|
|
e53fe70668 | ||
|
|
9e2e0a4a2d | ||
|
|
b52719fd73 | ||
|
|
7953976d25 | ||
|
|
39d6b94835 | ||
|
|
4fdce0695d | ||
|
|
ae8247fe6a | ||
|
|
d664565174 | ||
|
|
b24a46ad8f | ||
|
|
6bffe34faa | ||
|
|
abe3fb4acb | ||
|
|
39905bd8fd | ||
|
|
078dbfb0a9 | ||
|
|
dfeb5cfdd2 | ||
|
|
c1777cfb89 | ||
|
|
974072bdae | ||
|
|
b95e18956f | ||
|
|
3c1c5ef281 | ||
|
|
7194b14cd2 | ||
|
|
4e6f8d561c | ||
|
|
ac26921569 | ||
|
|
a60543728b | ||
|
|
f35ec9771e | ||
|
|
de4fe99e34 | ||
|
|
8ea6b3eebd | ||
|
|
a01836fe8d | ||
|
|
268dc97857 | ||
|
|
fc203c9654 | ||
|
|
8eedd5b277 | ||
|
|
561d9ac2bc | ||
|
|
1112da76f1 | ||
|
|
081aa18f39 | ||
|
|
c05c8bbba1 | ||
|
|
eabd23f31e | ||
|
|
cc27088df9 | ||
|
|
97ab7e9c65 | ||
|
|
bbf92828f6 | ||
|
|
2f83bf9f83 | ||
|
|
b2a1728201 | ||
|
|
18cbbbe9aa | ||
|
|
d90f8a3697 | ||
|
|
fe3ef6fc2e | ||
|
|
1b9148f12f | ||
|
|
deb8e49483 | ||
|
|
d75af2a156 | ||
|
|
9895edefff | ||
|
|
b60e856087 | ||
|
|
6244b4d00f | ||
|
|
ee167b1a43 | ||
|
|
e8b9bfe44c | ||
|
|
50f5593ffc | ||
|
|
3f0f7acbc0 | ||
|
|
7f6f8ec386 | ||
|
|
24d1798779 | ||
|
|
3e9d603f0b | ||
|
|
71a8fd3106 | ||
|
|
49279a3c19 | ||
|
|
43a1291f7c | ||
|
|
6dc5340f60 | ||
|
|
2a6e33bc73 | ||
|
|
0f6b2cfd3d | ||
|
|
30d109c0e9 | ||
|
|
e8e1f844d9 | ||
|
|
05a89e5566 | ||
|
|
c122889c95 | ||
|
|
9de5dc932b | ||
|
|
289c9ecf5d | ||
|
|
2c1a6e3f94 | ||
|
|
ad092a898d | ||
|
|
56f2548b6e | ||
|
|
25467243a6 | ||
|
|
e07d40fc26 | ||
|
|
09877e4e63 | ||
|
|
d3460b6cf5 | ||
|
|
ba384d15d2 | ||
|
|
2f38ade0e0 | ||
|
|
4d110d4c82 | ||
|
|
1bf5ff3e6e | ||
|
|
cd2a1a169f | ||
|
|
59b5f360af | ||
|
|
e8b6890318 | ||
|
|
d7b9ed05f0 | ||
|
|
dc852a100f | ||
|
|
838d51d296 | ||
|
|
e2845bc032 | ||
|
|
8c021fd784 | ||
|
|
406ec14585 | ||
|
|
c27b42e425 | ||
|
|
2d94d7ab0c | ||
|
|
5fcf430c81 | ||
|
|
cea4b3e363 | ||
|
|
e00d8fb544 | ||
|
|
e654fabe04 | ||
|
|
18592a08be | ||
|
|
1763260578 | ||
|
|
955f10e621 | ||
|
|
2565fedeb7 | ||
|
|
6b8e553ecc | ||
|
|
14f81cb275 | ||
|
|
ddb844226d | ||
|
|
f87ee5112a | ||
|
|
2a1a773777 | ||
|
|
7fede3ee45 | ||
|
|
abcd3511bf | ||
|
|
a387557970 | ||
|
|
daba04d54b | ||
|
|
b00a87d8fa | ||
|
|
aee55b0595 | ||
|
|
e58883c183 | ||
|
|
321e840c1c | ||
|
|
19ac1dd393 | ||
|
|
13796ee4c7 | ||
|
|
10bb78458d | ||
|
|
6997506bb9 | ||
|
|
480c7178a8 | ||
|
|
0279d8f466 | ||
|
|
1a6183d0c4 | ||
|
|
487acbb573 | ||
|
|
f97eba6539 | ||
|
|
cac84abdd9 | ||
|
|
ef045f9f65 | ||
|
|
6002099288 | ||
|
|
181f621a90 | ||
|
|
5a71c6f2eb | ||
|
|
487965dc8a | ||
|
|
874c573bd4 | ||
|
|
f63e1cfbfc | ||
|
|
f049f719f8 | ||
|
|
30754473fc | ||
|
|
7c70e6ce74 | ||
|
|
a702b7ccc5 | ||
|
|
f6be62ac5f | ||
|
|
dddd30bef8 | ||
|
|
a054206d25 | ||
|
|
5b6f06b2ac | ||
|
|
6f83822b6e | ||
|
|
9b635a3e90 | ||
|
|
172af5465d | ||
|
|
22f10dd8d2 | ||
|
|
790fdc0aa6 | ||
|
|
45356f5e12 | ||
|
|
08ee50403d | ||
|
|
aa1551c6e8 | ||
|
|
879403a172 | ||
|
|
6ddf765d8d | ||
|
|
38d83c27b4 | ||
|
|
103fa8fa2c | ||
|
|
53dcee6176 | ||
|
|
0c6129c54e | ||
|
|
1f01754ea6 | ||
|
|
f8a7ab1752 | ||
|
|
09842ce46f | ||
|
|
0b849985b2 | ||
|
|
34b8a48252 | ||
|
|
6f6e1efbc8 | ||
|
|
9a72ec366d | ||
|
|
d97302f351 | ||
|
|
4eb75f3c80 | ||
|
|
e5f72a0d4f | ||
|
|
b11b11f9b0 | ||
|
|
70077db07d | ||
|
|
eed682c529 | ||
|
|
fbf2d64f34 | ||
|
|
48bf08922c | ||
|
|
3616ee50c0 | ||
|
|
255c8e8ff4 | ||
|
|
0891e84bf8 | ||
|
|
a63db4ab24 | ||
|
|
169d45fbdb | ||
|
|
965e0237a3 | ||
|
|
4caef0dec7 | ||
|
|
622763b240 | ||
|
|
35d29b22c0 | ||
|
|
fee1d659cf | ||
|
|
869767a5cf | ||
|
|
23b01621ff | ||
|
|
f21ebaf839 | ||
|
|
f6f00b98a7 | ||
|
|
187170ec51 | ||
|
|
f7ad64a3d3 | ||
|
|
103d75f773 | ||
|
|
ed2968e3e8 | ||
|
|
fef5121cee | ||
|
|
c84983f91e | ||
|
|
86f4f4440a | ||
|
|
af0887fb48 | ||
|
|
610c7858d6 | ||
|
|
8d1fb88a20 | ||
|
|
1e2ad19d68 | ||
|
|
7bee66fe36 | ||
|
|
303fe886b7 | ||
|
|
761a472b45 | ||
|
|
3cf2da877f | ||
|
|
5b7b1596a2 | ||
|
|
dc58985ac6 | ||
|
|
5e0db46f17 | ||
|
|
4e19bc01d5 | ||
|
|
2d2acda404 | ||
|
|
fa8d5d1769 | ||
|
|
fe058e2c27 | ||
|
|
a22a24bc98 | ||
|
|
b7c2465887 | ||
|
|
f34158250a |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -6,10 +6,12 @@ Makefile.in.in
|
||||
*.lo
|
||||
*.la
|
||||
*.o
|
||||
**/*.dirstamp
|
||||
.deps/
|
||||
.libs/
|
||||
src/cryptsetup
|
||||
src/veritysetup
|
||||
ABOUT-NLS
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
compile
|
||||
@@ -21,8 +23,11 @@ config.rpath
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
cryptsetup
|
||||
cryptsetup-reencrypt
|
||||
depcomp
|
||||
install-sh
|
||||
integritysetup
|
||||
lib/libcryptsetup.pc
|
||||
libtool
|
||||
ltmain.sh
|
||||
@@ -36,5 +41,7 @@ po/*.header
|
||||
po/*.sed
|
||||
po/*.sin
|
||||
po/stamp-po
|
||||
scripts/cryptsetup.conf
|
||||
stamp-h1
|
||||
|
||||
veritysetup
|
||||
tests/valglog.*
|
||||
|
||||
@@ -38,18 +38,12 @@ function check_nonroot
|
||||
configure_travis \
|
||||
--enable-python \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
$MAKE || return
|
||||
|
||||
sudo modprobe dm-crypt
|
||||
sudo modprobe dm-verity
|
||||
sudo modprobe dm-integrity
|
||||
uname -a
|
||||
sudo dmsetup version
|
||||
sudo dmsetup targets
|
||||
|
||||
make check
|
||||
}
|
||||
|
||||
@@ -62,18 +56,12 @@ function check_root
|
||||
configure_travis \
|
||||
--enable-python \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
$MAKE || return
|
||||
|
||||
sudo modprobe dm-crypt
|
||||
sudo modprobe dm-verity
|
||||
sudo modprobe dm-integrity
|
||||
uname -a
|
||||
sudo dmsetup version
|
||||
sudo dmsetup targets
|
||||
|
||||
# FIXME: we should use -E option here
|
||||
sudo make check
|
||||
}
|
||||
@@ -87,6 +75,7 @@ function check_nonroot_compile_only
|
||||
configure_travis \
|
||||
--enable-python \
|
||||
--enable-cryptsetup-reencrypt \
|
||||
--enable-internal-sse-argon2 \
|
||||
"$cfg_opts" \
|
||||
|| return
|
||||
|
||||
@@ -116,6 +105,7 @@ function travis_install_script
|
||||
expect \
|
||||
keyutils \
|
||||
libjson-c-dev \
|
||||
libblkid-dev \
|
||||
|| return
|
||||
}
|
||||
|
||||
|
||||
2
FAQ
2
FAQ
@@ -128,7 +128,7 @@ A. Contributors
|
||||
recommended to not install Ubuntu on a system with existing LUKS
|
||||
containers without complete backups.
|
||||
|
||||
Update 11/2014: There seem to be other problems withe existing LUKS
|
||||
Update 11/2014: There seem to be other problems with existing LUKS
|
||||
containers and Ubuntu as well, be extra careful when using LUKS
|
||||
on Ubuntu in any way, but exactly as the Ubuntu installer does.
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ ACLOCAL_AMFLAGS = -I m4
|
||||
DISTCHECK_CONFIGURE_FLAGS = \
|
||||
--enable-python \
|
||||
--with-tmpfilesdir=$$dc_install_base/usr/lib/tmpfiles.d \
|
||||
--enable-internal-argon2
|
||||
--enable-internal-argon2 --enable-internal-sse-argon2
|
||||
|
||||
distclean-local:
|
||||
-find . -name \*~ -o -name \*.orig -o -name \*.rej | xargs rm -f
|
||||
|
||||
25
README.md
25
README.md
@@ -18,8 +18,7 @@ LUKS Design
|
||||
-----------
|
||||
**LUKS** is the standard for Linux hard disk encryption. By providing a standard on-disk-format, it does not
|
||||
only facilitate compatibility among distributions, but also provides secure management of multiple user passwords.
|
||||
In contrast to existing solution, LUKS stores all setup necessary setup information in the partition header,
|
||||
enabling the user to transport or migrate his data seamlessly.
|
||||
LUKS stores all necessary setup information in the partition header, enabling to transport or migrate data seamlessly.
|
||||
|
||||
Last version of the LUKS format specification is
|
||||
[available here](https://www.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf).
|
||||
@@ -42,13 +41,25 @@ Download
|
||||
--------
|
||||
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
|
||||
|
||||
**The latest cryptsetup version is 2.0.1**
|
||||
* [cryptsetup-2.0.1.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.1.tar.xz)
|
||||
* Signature [cryptsetup-2.0.1.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/cryptsetup-2.0.1.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.0.1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.1-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.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).
|
||||
@@ -78,7 +89,7 @@ mirror on [kernel.org](https://git.kernel.org/cgit/utils/cryptsetup/cryptsetup.g
|
||||
|
||||
For libcryptsetup documentation see [libcryptsetup API](https://gitlab.com/cryptsetup/cryptsetup/wikis/API/index.html) page.
|
||||
|
||||
The libcryptsetup API/ABI changes are tracked in [compatibility report](https://gitlab.com/cryptsetup/cryptsetup/wikis/ABI-tracker/timeline/libcryptsetup/index.html).
|
||||
The libcryptsetup API/ABI changes are tracked in [compatibility report](https://abi-laboratory.pro/tracker/timeline/cryptsetup/).
|
||||
|
||||
NLS PO files are maintained by [TranslationProject](http://translationproject.org/domain/cryptsetup.html).
|
||||
|
||||
|
||||
238
configure.ac
238
configure.ac
@@ -1,9 +1,9 @@
|
||||
AC_PREREQ([2.67])
|
||||
AC_INIT([cryptsetup],[2.0.2])
|
||||
AC_INIT([cryptsetup],[2.0.5])
|
||||
|
||||
dnl library version from <major>.<minor>.<release>[-<suffix>]
|
||||
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
|
||||
LIBCRYPTSETUP_VERSION_INFO=14:0:2
|
||||
LIBCRYPTSETUP_VERSION_INFO=15:0:3
|
||||
|
||||
AM_SILENT_RULES([yes])
|
||||
AC_CONFIG_SRCDIR(src/cryptsetup.c)
|
||||
@@ -63,7 +63,9 @@ AC_CHECK_HEADERS(fcntl.h malloc.h inttypes.h sys/ioctl.h sys/mman.h \
|
||||
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.])])
|
||||
|
||||
AC_ARG_ENABLE(keyring, AS_HELP_STRING([--disable-keyring],[disable kernel keyring support and builtin kernel keyring token]),[], [enable_keyring=yes])
|
||||
AC_ARG_ENABLE([keyring],
|
||||
AS_HELP_STRING([--disable-keyring], [disable kernel keyring support and builtin kernel keyring token]),
|
||||
[], [enable_keyring=yes])
|
||||
if test "x$enable_keyring" = "xyes"; then
|
||||
AC_CHECK_HEADERS(linux/keyctl.h,,[AC_MSG_ERROR([You need Linux kernel headers with kernel keyring service compiled.])])
|
||||
|
||||
@@ -84,7 +86,7 @@ if test "x$enable_keyring" = "xyes"; then
|
||||
|
||||
AC_DEFINE(KERNEL_KEYRING, 1, [Enable kernel keyring service support])
|
||||
fi
|
||||
AM_CONDITIONAL(KERNEL_KEYRING, test x$enable_keyring = xyes)
|
||||
AM_CONDITIONAL(KERNEL_KEYRING, test "x$enable_keyring" = "xyes")
|
||||
|
||||
saved_LIBS=$LIBS
|
||||
AC_CHECK_LIB(uuid, uuid_clear, ,[AC_MSG_ERROR([You need the uuid library.])])
|
||||
@@ -92,9 +94,9 @@ AC_SUBST(UUID_LIBS, $LIBS)
|
||||
LIBS=$saved_LIBS
|
||||
|
||||
AC_SEARCH_LIBS([clock_gettime],[rt posix4])
|
||||
AC_CHECK_FUNCS([posix_memalign clock_gettime posix_fallocate])
|
||||
AC_CHECK_FUNCS([posix_memalign clock_gettime posix_fallocate explicit_bzero])
|
||||
|
||||
if test "x$enable_largefile" = "xno" ; then
|
||||
if test "x$enable_largefile" = "xno"; then
|
||||
AC_MSG_ERROR([Building with --disable-largefile is not supported, it can cause data corruption.])
|
||||
fi
|
||||
|
||||
@@ -120,12 +122,10 @@ AC_SUBST(POPT_LIBS, $LIBS)
|
||||
LIBS=$saved_LIBS
|
||||
|
||||
dnl ==========================================================================
|
||||
dnl FIPS extensions (only for RHEL)
|
||||
AC_ARG_ENABLE([fips], AS_HELP_STRING([--enable-fips],[enable FIPS mode restrictions]),
|
||||
[with_fips=$enableval],
|
||||
[with_fips=no])
|
||||
|
||||
if test "x$with_fips" = "xyes"; then
|
||||
dnl FIPS extensions
|
||||
AC_ARG_ENABLE([fips],
|
||||
AS_HELP_STRING([--enable-fips], [enable FIPS mode restrictions]))
|
||||
if test "x$enable_fips" = "xyes"; then
|
||||
AC_DEFINE(ENABLE_FIPS, 1, [Enable FIPS mode restrictions])
|
||||
|
||||
if test "x$enable_static" = "xyes" -o "x$enable_static_cryptsetup" = "xyes" ; then
|
||||
@@ -134,7 +134,7 @@ if test "x$with_fips" = "xyes"; then
|
||||
fi
|
||||
|
||||
AC_DEFUN([NO_FIPS], [
|
||||
if test "x$with_fips" = "xyes"; then
|
||||
if test "x$enable_fips" = "xyes"; then
|
||||
AC_MSG_ERROR([This option is not compatible with FIPS.])
|
||||
fi
|
||||
])
|
||||
@@ -142,12 +142,9 @@ AC_DEFUN([NO_FIPS], [
|
||||
dnl ==========================================================================
|
||||
dnl pwquality library (cryptsetup CLI only)
|
||||
AC_ARG_ENABLE([pwquality],
|
||||
AS_HELP_STRING([--enable-pwquality],
|
||||
[enable password quality checking using pwquality library]),
|
||||
[with_pwquality=$enableval],
|
||||
[with_pwquality=no])
|
||||
AS_HELP_STRING([--enable-pwquality], [enable password quality checking using pwquality library]))
|
||||
|
||||
if test "x$with_pwquality" = "xyes"; then
|
||||
if test "x$enable_pwquality" = "xyes"; then
|
||||
AC_DEFINE(ENABLE_PWQUALITY, 1, [Enable password quality checking using pwquality library])
|
||||
PKG_CHECK_MODULES([PWQUALITY], [pwquality >= 1.0.0],,
|
||||
AC_MSG_ERROR([You need pwquality library.]))
|
||||
@@ -159,13 +156,11 @@ fi
|
||||
dnl ==========================================================================
|
||||
dnl passwdqc library (cryptsetup CLI only)
|
||||
AC_ARG_ENABLE([passwdqc],
|
||||
AS_HELP_STRING([--enable-passwdqc@<:@=CONFIG_PATH@:>@],
|
||||
[enable password quality checking using passwdqc library (optionally with CONFIG_PATH)]),
|
||||
[enable_passwdqc=$enableval],
|
||||
[enable_passwdqc=no])
|
||||
AS_HELP_STRING([--enable-passwdqc@<:@=CONFIG_PATH@:>@],
|
||||
[enable password quality checking using passwdqc library (optionally with CONFIG_PATH)]))
|
||||
|
||||
case "$enable_passwdqc" in
|
||||
yes|no) use_passwdqc_config="" ;;
|
||||
""|yes|no) use_passwdqc_config="" ;;
|
||||
/*) use_passwdqc_config="$enable_passwdqc"; enable_passwdqc=yes ;;
|
||||
*) AC_MSG_ERROR([Unrecognized --enable-passwdqc parameter.]) ;;
|
||||
esac
|
||||
@@ -177,7 +172,7 @@ if test "x$enable_passwdqc" = "xyes"; then
|
||||
PASSWDQC_LIBS="-lpasswdqc"
|
||||
fi
|
||||
|
||||
if test "x$with_pwquality$enable_passwdqc" = "xyesyes"; then
|
||||
if test "x$enable_pwquality$enable_passwdqc" = "xyesyes"; then
|
||||
AC_MSG_ERROR([--enable-pwquality and --enable-passwdqc are mutually incompatible.])
|
||||
fi
|
||||
|
||||
@@ -185,13 +180,14 @@ dnl ==========================================================================
|
||||
dnl Crypto backend functions
|
||||
|
||||
AC_DEFUN([CONFIGURE_GCRYPT], [
|
||||
if test "x$with_fips" = "xyes"; then
|
||||
if test "x$enable_fips" = "xyes"; then
|
||||
GCRYPT_REQ_VERSION=1.4.5
|
||||
else
|
||||
GCRYPT_REQ_VERSION=1.1.42
|
||||
fi
|
||||
dnl Check if we can use gcrypt PBKDF2 (1.6.0 supports empty password)
|
||||
AC_ARG_ENABLE([gcrypt-pbkdf2], AS_HELP_STRING([--enable-gcrypt-pbkdf2],[force enable internal gcrypt PBKDF2]),
|
||||
AC_ARG_ENABLE([gcrypt-pbkdf2],
|
||||
AS_HELP_STRING([--enable-gcrypt-pbkdf2], [force enable internal gcrypt PBKDF2]),
|
||||
if test "x$enableval" = "xyes"; then
|
||||
[use_internal_pbkdf2=0]
|
||||
else
|
||||
@@ -208,7 +204,7 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
|
||||
NO_FIPS([])
|
||||
fi
|
||||
|
||||
if test x$enable_static_cryptsetup = xyes; then
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
saved_LIBS=$LIBS
|
||||
LIBS="$saved_LIBS $LIBGCRYPT_LIBS -static"
|
||||
AC_CHECK_LIB(gcrypt, gcry_check_version,,
|
||||
@@ -232,7 +228,7 @@ AC_DEFUN([CONFIGURE_OPENSSL], [
|
||||
CRYPTO_LIBS=$OPENSSL_LIBS
|
||||
use_internal_pbkdf2=0
|
||||
|
||||
if test x$enable_static_cryptsetup = xyes; then
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
saved_PKG_CONFIG=$PKG_CONFIG
|
||||
PKG_CONFIG="$PKG_CONFIG --static"
|
||||
PKG_CHECK_MODULES([OPENSSL_STATIC], [openssl])
|
||||
@@ -242,7 +238,7 @@ AC_DEFUN([CONFIGURE_OPENSSL], [
|
||||
])
|
||||
|
||||
AC_DEFUN([CONFIGURE_NSS], [
|
||||
if test x$enable_static_cryptsetup = xyes; then
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
AC_MSG_ERROR([Static build of cryptsetup is not supported with NSS.])
|
||||
fi
|
||||
|
||||
@@ -291,43 +287,42 @@ dnl ==========================================================================
|
||||
saved_LIBS=$LIBS
|
||||
|
||||
AC_ARG_ENABLE([static-cryptsetup],
|
||||
AS_HELP_STRING([--enable-static-cryptsetup],
|
||||
[enable build of static version of tools]))
|
||||
if test x$enable_static_cryptsetup = xyes; then
|
||||
if test x$enable_static = xno; then
|
||||
AS_HELP_STRING([--enable-static-cryptsetup], [enable build of static version of tools]))
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
if test "x$enable_static" = "xno"; then
|
||||
AC_MSG_WARN([Requested static cryptsetup build, enabling static library.])
|
||||
enable_static=yes
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(STATIC_TOOLS, test x$enable_static_cryptsetup = xyes)
|
||||
AM_CONDITIONAL(STATIC_TOOLS, test "x$enable_static_cryptsetup" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE(cryptsetup,
|
||||
AS_HELP_STRING([--disable-cryptsetup],
|
||||
[disable cryptsetup support]),[], [enable_cryptsetup=yes])
|
||||
AM_CONDITIONAL(CRYPTSETUP, test x$enable_cryptsetup = xyes)
|
||||
AC_ARG_ENABLE([cryptsetup],
|
||||
AS_HELP_STRING([--disable-cryptsetup], [disable cryptsetup support]),
|
||||
[], [enable_cryptsetup=yes])
|
||||
AM_CONDITIONAL(CRYPTSETUP, test "x$enable_cryptsetup" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE(veritysetup,
|
||||
AS_HELP_STRING([--disable-veritysetup],
|
||||
[disable veritysetup support]),[], [enable_veritysetup=yes])
|
||||
AM_CONDITIONAL(VERITYSETUP, test x$enable_veritysetup = xyes)
|
||||
AC_ARG_ENABLE([veritysetup],
|
||||
AS_HELP_STRING([--disable-veritysetup], [disable veritysetup support]),
|
||||
[], [enable_veritysetup=yes])
|
||||
AM_CONDITIONAL(VERITYSETUP, test "x$enable_veritysetup" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE([cryptsetup-reencrypt],
|
||||
AS_HELP_STRING([--disable-cryptsetup-reencrypt],
|
||||
[disable cryptsetup-reencrypt tool]),[], [enable_cryptsetup_reencrypt=yes])
|
||||
AM_CONDITIONAL(REENCRYPT, test x$enable_cryptsetup_reencrypt = xyes)
|
||||
AS_HELP_STRING([--disable-cryptsetup-reencrypt], [disable cryptsetup-reencrypt tool]),
|
||||
[], [enable_cryptsetup_reencrypt=yes])
|
||||
AM_CONDITIONAL(REENCRYPT, test "x$enable_cryptsetup_reencrypt" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE(integritysetup,
|
||||
AS_HELP_STRING([--disable-integritysetup],
|
||||
[disable integritysetup support]),[], [enable_integritysetup=yes])
|
||||
AM_CONDITIONAL(INTEGRITYSETUP, test x$enable_integritysetup = xyes)
|
||||
AC_ARG_ENABLE([integritysetup],
|
||||
AS_HELP_STRING([--disable-integritysetup], [disable integritysetup support]),
|
||||
[], [enable_integritysetup=yes])
|
||||
AM_CONDITIONAL(INTEGRITYSETUP, test "x$enable_integritysetup" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE(selinux,
|
||||
AS_HELP_STRING([--disable-selinux],
|
||||
[disable selinux support [default=auto]]),[], [])
|
||||
AC_ARG_ENABLE([selinux],
|
||||
AS_HELP_STRING([--disable-selinux], [disable selinux support [default=auto]]),
|
||||
[], [enable_selinux=yes])
|
||||
|
||||
AC_ARG_ENABLE([udev],
|
||||
AS_HELP_STRING([--disable-udev],
|
||||
[disable udev support]),[], enable_udev=yes)
|
||||
AS_HELP_STRING([--disable-udev], [disable udev support]),
|
||||
[], [enable_udev=yes])
|
||||
|
||||
dnl Try to use pkg-config for devmapper, but fallback to old detection
|
||||
PKG_CHECK_MODULES([DEVMAPPER], [devmapper >= 1.02.03],, [
|
||||
@@ -361,16 +356,14 @@ PKG_CHECK_MODULES([JSON_C], [json-c])
|
||||
dnl Crypto backend configuration.
|
||||
AC_ARG_WITH([crypto_backend],
|
||||
AS_HELP_STRING([--with-crypto_backend=BACKEND], [crypto backend (gcrypt/openssl/nss/kernel/nettle) [gcrypt]]),
|
||||
[], with_crypto_backend=gcrypt
|
||||
)
|
||||
[], [with_crypto_backend=gcrypt])
|
||||
|
||||
dnl Kernel crypto API backend needed for benchmark and tcrypt
|
||||
AC_ARG_ENABLE([kernel_crypto], AS_HELP_STRING([--disable-kernel_crypto],
|
||||
[disable kernel userspace crypto (no benchmark and tcrypt)]),
|
||||
[with_kernel_crypto=$enableval],
|
||||
[with_kernel_crypto=yes])
|
||||
AC_ARG_ENABLE([kernel_crypto],
|
||||
AS_HELP_STRING([--disable-kernel_crypto], [disable kernel userspace crypto (no benchmark and tcrypt)]),
|
||||
[], [enable_kernel_crypto=yes])
|
||||
|
||||
if test "x$with_kernel_crypto" = "xyes"; then
|
||||
if test "x$enable_kernel_crypto" = "xyes"; then
|
||||
AC_CHECK_HEADERS(linux/if_alg.h,,
|
||||
[AC_MSG_ERROR([You need Linux kernel headers with userspace crypto interface. (Or use --disable-kernel_crypto.)])])
|
||||
AC_DEFINE(ENABLE_AF_ALG, 1, [Enable using of kernel userspace crypto])
|
||||
@@ -384,23 +377,24 @@ case $with_crypto_backend in
|
||||
nettle) CONFIGURE_NETTLE([]) ;;
|
||||
*) AC_MSG_ERROR([Unknown crypto backend.]) ;;
|
||||
esac
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_GCRYPT, test $with_crypto_backend = gcrypt)
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_OPENSSL, test $with_crypto_backend = openssl)
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_NSS, test $with_crypto_backend = nss)
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_KERNEL, test $with_crypto_backend = kernel)
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_NETTLE, test $with_crypto_backend = nettle)
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_GCRYPT, test "$with_crypto_backend" = "gcrypt")
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_OPENSSL, test "$with_crypto_backend" = "openssl")
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_NSS, test "$with_crypto_backend" = "nss")
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_KERNEL, test "$with_crypto_backend" = "kernel")
|
||||
AM_CONDITIONAL(CRYPTO_BACKEND_NETTLE, test "$with_crypto_backend" = "nettle")
|
||||
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_PBKDF2, test $use_internal_pbkdf2 = 1)
|
||||
AC_DEFINE_UNQUOTED(USE_INTERNAL_PBKDF2, [$use_internal_pbkdf2], [Use internal PBKDF2])
|
||||
|
||||
dnl Argon2 implementation
|
||||
AC_ARG_ENABLE(internal-argon2, AS_HELP_STRING([--disable-internal-argon2],
|
||||
[disable internal implementation of Argon2 PBKDF]),[], [enable_internal_argon2=yes])
|
||||
AC_ARG_ENABLE([internal-argon2],
|
||||
AS_HELP_STRING([--disable-internal-argon2], [disable internal implementation of Argon2 PBKDF]),
|
||||
[], [enable_internal_argon2=yes])
|
||||
|
||||
AC_ARG_ENABLE([libargon2], AS_HELP_STRING([--enable-libargon2],
|
||||
[enable external libargon2 (PHC) library (disables internal bundled version) ]),[], [enable_libargon2=no])
|
||||
AC_ARG_ENABLE([libargon2],
|
||||
AS_HELP_STRING([--enable-libargon2], [enable external libargon2 (PHC) library (disables internal bundled version)]))
|
||||
|
||||
if test x$enable_libargon2 = xyes ; then
|
||||
if test "x$enable_libargon2" = "xyes" ; then
|
||||
AC_CHECK_HEADERS(argon2.h,,
|
||||
[AC_MSG_ERROR([You need libargon2 development library installed.])])
|
||||
AC_CHECK_DECL(Argon2_id,,[AC_MSG_ERROR([You need more recent Argon2 library with support for Argon2id.])], [#include <argon2.h>])
|
||||
@@ -408,15 +402,63 @@ if test x$enable_libargon2 = xyes ; then
|
||||
enable_internal_argon2=no
|
||||
else
|
||||
AC_MSG_WARN([Argon2 bundled (slow) reference implementation will be used, please consider to use system library with --enable-libargon2.])
|
||||
|
||||
AC_ARG_ENABLE([internal-sse-argon2],
|
||||
AS_HELP_STRING([--enable-internal-sse-argon2], [enable internal SSE implementation of Argon2 PBKDF]))
|
||||
|
||||
if test "x$enable_internal_sse_argon2" = "xyes"; then
|
||||
AC_MSG_CHECKING(if Argon2 SSE optimization can be used)
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <emmintrin.h>
|
||||
__m128i testfunc(__m128i *a, __m128i *b) {
|
||||
return _mm_xor_si128(_mm_loadu_si128(a), _mm_loadu_si128(b));
|
||||
}
|
||||
]])],,[enable_internal_sse_argon2=no])
|
||||
AC_MSG_RESULT($enable_internal_sse_argon2)
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x$enable_internal_argon2 = xyes ; then
|
||||
if test "x$enable_internal_argon2" = "xyes"; then
|
||||
AC_DEFINE(USE_INTERNAL_ARGON2, 1, [Use internal Argon2])
|
||||
fi
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_ARGON2, test x$enable_internal_argon2 = xyes)
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_ARGON2, test "x$enable_internal_argon2" = "xyes")
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_SSE_ARGON2, test "x$enable_internal_sse_argon2" = "xyes")
|
||||
|
||||
dnl Link with blkid to check for other device types
|
||||
AC_ARG_ENABLE([blkid],
|
||||
AS_HELP_STRING([--disable-blkid], [disable use of blkid for device signature detection and wiping]),
|
||||
[], [enable_blkid=yes])
|
||||
|
||||
if test "x$enable_blkid" = "xyes"; then
|
||||
PKG_CHECK_MODULES([BLKID], [blkid],[AC_DEFINE([HAVE_BLKID], 1, [Define to 1 to use blkid for detection of disk signatures.])],[LIBBLKID_LIBS="-lblkid"])
|
||||
|
||||
AC_CHECK_HEADERS(blkid/blkid.h,,[AC_MSG_ERROR([You need blkid development library installed.])])
|
||||
AC_CHECK_DECL([blkid_do_wipe],
|
||||
[ AC_DEFINE([HAVE_BLKID_WIPE], 1, [Define to 1 to use blkid_do_wipe.])
|
||||
enable_blkid_wipe=yes
|
||||
],,
|
||||
[#include <blkid/blkid.h>])
|
||||
AC_CHECK_DECL([blkid_probe_step_back],
|
||||
[ AC_DEFINE([HAVE_BLKID_STEP_BACK], 1, [Define to 1 to use blkid_probe_step_back.])
|
||||
enable_blkid_step_back=yes
|
||||
],,
|
||||
[#include <blkid/blkid.h>])
|
||||
AC_CHECK_DECLS([ blkid_reset_probe,
|
||||
blkid_probe_set_device,
|
||||
blkid_probe_filter_superblocks_type,
|
||||
blkid_do_safeprobe,
|
||||
blkid_do_probe,
|
||||
blkid_probe_lookup_value
|
||||
],,
|
||||
[AC_MSG_ERROR([Can not compile with blkid support, disable it by --disable-blkid.])],
|
||||
[#include <blkid/blkid.h>])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_BLKID, test "x$enable_blkid" = "xyes")
|
||||
AM_CONDITIONAL(HAVE_BLKID_WIPE, test "x$enable_blkid_wipe" = "xyes")
|
||||
AM_CONDITIONAL(HAVE_BLKID_STEP_BACK, test "x$enable_blkid_step_back" = "xyes")
|
||||
|
||||
dnl Magic for cryptsetup.static build.
|
||||
if test x$enable_static_cryptsetup = xyes; then
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
saved_PKG_CONFIG=$PKG_CONFIG
|
||||
PKG_CONFIG="$PKG_CONFIG --static"
|
||||
|
||||
@@ -428,7 +470,7 @@ if test x$enable_static_cryptsetup = xyes; then
|
||||
LIBS="$saved_LIBS -static"
|
||||
PKG_CHECK_MODULES([DEVMAPPER_STATIC], [devmapper >= 1.02.27],,[
|
||||
DEVMAPPER_STATIC_LIBS=$DEVMAPPER_LIBS
|
||||
if test "x$enable_selinux" != xno; then
|
||||
if test "x$enable_selinux" = "xyes"; then
|
||||
AC_CHECK_LIB(sepol, sepol_bool_set)
|
||||
AC_CHECK_LIB(selinux, is_selinux_enabled)
|
||||
DEVMAPPER_STATIC_LIBS="$DEVMAPPER_STATIC_LIBS $LIBS"
|
||||
@@ -465,14 +507,19 @@ AC_SUBST([CRYPTO_STATIC_LIBS])
|
||||
|
||||
AC_SUBST([JSON_C_LIBS])
|
||||
AC_SUBST([LIBARGON2_LIBS])
|
||||
AC_SUBST([BLKID_LIBS])
|
||||
|
||||
AC_SUBST([LIBCRYPTSETUP_VERSION])
|
||||
AC_SUBST([LIBCRYPTSETUP_VERSION_INFO])
|
||||
|
||||
dnl ==========================================================================
|
||||
AC_ARG_ENABLE([dev-random], AS_HELP_STRING([--enable-dev-random],
|
||||
[use blocking /dev/random by default for key generator (otherwise use /dev/urandom)]),
|
||||
[default_rng=/dev/random], [default_rng=/dev/urandom])
|
||||
AC_ARG_ENABLE([dev-random],
|
||||
AS_HELP_STRING([--enable-dev-random], [use /dev/random by default for key generation (otherwise use /dev/urandom)]))
|
||||
if test "x$enable_dev_random" = "xyes"; then
|
||||
default_rng=/dev/random
|
||||
else
|
||||
default_rng=/dev/urandom
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_RNG, ["$default_rng"], [default RNG type for key generator])
|
||||
|
||||
dnl ==========================================================================
|
||||
@@ -492,17 +539,23 @@ AC_DEFUN([CS_NUM_WITH], [AC_ARG_WITH([$1],
|
||||
[CS_DEFINE([$1], [$3], [$2])]
|
||||
)])
|
||||
|
||||
AC_DEFUN([CS_ABSPATH], [
|
||||
case "$1" in
|
||||
/*) ;;
|
||||
*) AC_MSG_ERROR([$2 argument must be an absolute path.]);;
|
||||
esac
|
||||
])
|
||||
|
||||
dnl ==========================================================================
|
||||
dnl Python bindings
|
||||
AC_ARG_ENABLE([python], AS_HELP_STRING([--enable-python],[enable Python bindings]),
|
||||
[with_python=$enableval],
|
||||
[with_python=no])
|
||||
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$with_python" = "xyes"; then
|
||||
if test "x$enable_python" = "xyes"; then
|
||||
AM_PATH_PYTHON([$PYTHON_VERSION])
|
||||
|
||||
AC_PATH_PROGS([PYTHON_CONFIG], [python${PYTHON_VERSION}-config python-config], [no])
|
||||
@@ -520,7 +573,7 @@ if test "x$with_python" = "xyes"; then
|
||||
AC_MSG_RESULT($PYTHON_LIBS)
|
||||
AC_SUBST(PYTHON_LIBS)
|
||||
fi
|
||||
AM_CONDITIONAL([PYTHON_CRYPTSETUP], [test "x$with_python" = "xyes"])
|
||||
AM_CONDITIONAL([PYTHON_CRYPTSETUP], [test "x$enable_python" = "xyes"])
|
||||
|
||||
dnl ==========================================================================
|
||||
CS_STR_WITH([plain-hash], [password hashing function for plain mode], [ripemd160])
|
||||
@@ -553,17 +606,16 @@ CS_NUM_WITH([verity-fec-roots], [parity bytes for verity FEC], [2])
|
||||
|
||||
CS_STR_WITH([tmpfilesdir], [override default path to directory with systemd temporary files], [])
|
||||
test -z "$with_tmpfilesdir" && with_tmpfilesdir=$systemd_tmpfilesdir
|
||||
test "x$with_tmpfilesdir" == "xno" || {
|
||||
test "${with_tmpfilesdir:0:1}" = "/" || AC_MSG_ERROR([--with-tmpfilesdir argument must be an absolute path.])
|
||||
test "x$with_tmpfilesdir" = "xno" || {
|
||||
CS_ABSPATH([${with_tmpfilesdir}],[with-tmpfilesdir])
|
||||
DEFAULT_TMPFILESDIR=$with_tmpfilesdir
|
||||
AC_SUBST(DEFAULT_TMPFILESDIR)
|
||||
}
|
||||
AM_CONDITIONAL(CRYPTSETUP_TMPFILE, test -n "$DEFAULT_TMPFILESDIR")
|
||||
|
||||
|
||||
CS_STR_WITH([luks2-lock-path], [path to directory for LUKSv2 locks], [/run/cryptsetup])
|
||||
test -z "$with_luks2_lock_path" && with_luks2_lock_path=/run/cryptsetup
|
||||
test "${with_luks2_lock_path:0:1}" = "/" || AC_MSG_ERROR([--with-luks2-lock-path argument must be an absolute path.])
|
||||
CS_ABSPATH([${with_luks2_lock_path}],[with-luks2-lock-path])
|
||||
DEFAULT_LUKS2_LOCK_PATH=$with_luks2_lock_path
|
||||
AC_SUBST(DEFAULT_LUKS2_LOCK_PATH)
|
||||
|
||||
@@ -572,6 +624,18 @@ test -z "$with_luks2_lock_dir_perms" && with_luks2_lock_dir_perms=0700
|
||||
DEFAULT_LUKS2_LOCK_DIR_PERMS=$with_luks2_lock_dir_perms
|
||||
AC_SUBST(DEFAULT_LUKS2_LOCK_DIR_PERMS)
|
||||
|
||||
dnl Override default LUKS format version (for cryptsetup or cryptsetup-reencrypt format actions only).
|
||||
AC_ARG_WITH([default_luks_format],
|
||||
AS_HELP_STRING([--with-default-luks-format=FORMAT], [default LUKS format version (LUKS1/LUKS2) [LUKS1]]),
|
||||
[], [with_default_luks_format=LUKS1])
|
||||
|
||||
case $with_default_luks_format in
|
||||
LUKS1) default_luks=CRYPT_LUKS1 ;;
|
||||
LUKS2) default_luks=CRYPT_LUKS2 ;;
|
||||
*) AC_MSG_ERROR([Unknown default LUKS format. Use LUKS1 or LUKS2 only.]) ;;
|
||||
esac
|
||||
AC_DEFINE_UNQUOTED([DEFAULT_LUKS_FORMAT], [$default_luks], [default LUKS format version])
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
AC_CONFIG_FILES([ Makefile
|
||||
|
||||
@@ -1,279 +0,0 @@
|
||||
LUKS2 on-disk format
|
||||
====================
|
||||
|
||||
Note: these are temporary documentation notes only.
|
||||
The more formal definition will be published later.
|
||||
|
||||
Design goals
|
||||
~~~~~~~~~~~~
|
||||
The LUKS2 is an on-disk storage format designed to
|
||||
provide simple key management, primarily intended for Full Disk
|
||||
Encryption based on dm-crypt.
|
||||
|
||||
The LUKS2 is highly inspired by LUKS1 format and in some
|
||||
specific situations (most of the default installations) can be converted
|
||||
in-place (in both ways - to and from LUKS1).
|
||||
|
||||
The LUKS2 format is designed to allow future updates of various
|
||||
parts without the need to modify binary structures.
|
||||
|
||||
On-disk format provides redundancy of metadata, detection
|
||||
of metadata corruption and automatic repair from metadata copy.
|
||||
|
||||
NOTE: For security reasons, there is no redundancy in keyslots
|
||||
binary data (encrypted keys) but format allows updating to redundant
|
||||
keyslot encryption in future (add forward error correction codes
|
||||
is one possibility).
|
||||
|
||||
On-disk structure
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The LUKS2 header contains three parts:
|
||||
- binary header (one 4096 bytes sector)
|
||||
- area for metadata stored in JSON format
|
||||
- keyslot area (per-context binary data).
|
||||
|
||||
The binary header and JSON area are stored twice to increase
|
||||
redundancy. Keyslot area is allocated per-demand, and it is stored only once.
|
||||
|
||||
The basic on-disk structure is then
|
||||
|
||||
0 4096
|
||||
| bin hdr1 | JSON ... | bin hdr2 | JSON ... | Keyslot data | <padding> | (data payload)
|
||||
|
||||
Binary header
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The binary header is intended for quick scanning (by blkid and udev) and contains
|
||||
magic string to detect the device, basic information (labels), header size information
|
||||
and metadata checksum.
|
||||
Checksum covers both binary data and following JSON area and is calculated
|
||||
with checksum fields zeroed. By default plain SHA256 checksum is used.
|
||||
|
||||
The primary binary header is always stored in sector 0 of the device.
|
||||
|
||||
The C structure of binary header (see luks2.h) is
|
||||
|
||||
#define LUKS2_MAGIC_1ST "LUKS\xba\xbe"
|
||||
#define LUKS2_MAGIC_2ND "SKUL\xba\xbe"
|
||||
#define LUKS2_MAGIC_L 6
|
||||
#define LUKS2_UUID_L 40
|
||||
#define LUKS2_LABEL_L 48
|
||||
#define LUKS2_SALT_L 64
|
||||
#define LUKS2_CHECKSUM_ALG_L 32
|
||||
#define LUKS2_CHECKSUM_L 64
|
||||
|
||||
struct luks2_hdr_disk {
|
||||
char magic[LUKS2_MAGIC_L]; /* "LUKS\xba\xbe" (1st) or "SKUL\xba\be" (2nd) */
|
||||
uint16_t version; /* Version 2 */
|
||||
uint64_t hdr_size; /* in bytes, including JSON area */
|
||||
uint64_t seqid; /* sequence ID, increased on every update */
|
||||
char label[LUKS2_LABEL_L]; /* ASCII label or empty */
|
||||
char checksum_alg[LUKS2_CHECKSUM_ALG_L]; /* checksum algorithm, "sha256" */
|
||||
uint8_t salt[LUKS2_SALT_L]; /* random salt, unique for every header */
|
||||
char uuid[LUKS2_UUID_L]; /* UUID of device */
|
||||
char subsystem[LUKS2_LABEL_L]; /* owner subsystem label or empty */
|
||||
uint64_t hdr_offset; /* header offset from device start in bytes */
|
||||
char _padding[184]; /* must be zeroed */
|
||||
uint8_t csum[LUKS2_CHECKSUM_L]; /* header checksum */
|
||||
char _padding4096[7*512]; /* must be zeroed */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
The LUKS1 compatible field (magic, UUID) are placed intentionally on the same offsets.
|
||||
The header version must be set to 2.
|
||||
The UUID is the same format as in LUKS1.
|
||||
|
||||
Magic string differs between the first and second header.
|
||||
|
||||
The hdr_offset must match physical header offset on the device.
|
||||
If hdr_offset does not match, the header is misplaced and must not be used.
|
||||
(It is a prevention to partition resize or manipulation with device start offset.)
|
||||
|
||||
The hdr_size contains the size of the binary header and JSON data area.
|
||||
The offset and size of the second (backup) header must match to these data.
|
||||
(Prevention to rewrite of a header with different JSON area size.)
|
||||
|
||||
There are two labels - label and subsystem. Content of these fields will be visible
|
||||
in UDEV/blkid scan and can be used for similar purposes as a filesystem label.
|
||||
These fields are by default empty.
|
||||
|
||||
The salt field in binary header is generated by an RNG and is different for
|
||||
every header, even the backup header must contain a different salt.
|
||||
The salt in binary header is not used after the header is read, the main intention
|
||||
is to avoid deduplication of the header sector.
|
||||
The salt must be regenerated on every header repair (but not on regular update).
|
||||
|
||||
The sequential number (seqid) is a counter that is always increased when a new
|
||||
update of the header is written. The header with higher seqid is more recent and
|
||||
is used for recovery (if there are two headers with different seqid, the
|
||||
more recent one is automatically used).
|
||||
|
||||
The rest of binary header must be zeroed.
|
||||
|
||||
JSON area
|
||||
~~~~~~~~~
|
||||
The JSON area starts immediately after the binary header. Its size is set
|
||||
by binary header hdr_size field (JSON area size = hdr_size - 4096).
|
||||
|
||||
The area contains metadata in JSON format and is fixed. Unused remainder
|
||||
of the area must be empty.
|
||||
|
||||
The header cannot store larger metadata that this fixed buffer and header
|
||||
size must be set properly during format. For now, only areas with 14 kB
|
||||
header (4kB binary header + 14kB JSON area) is created during format.
|
||||
|
||||
The JSON is structured to be able to describe system in very generic way,
|
||||
but LUKS2 intentionally limits options to values that are supportable
|
||||
in implemented version.
|
||||
|
||||
JSON structure is as follows:
|
||||
|
||||
Mandatory sections (must be present but some can be empty):
|
||||
- config
|
||||
- keyslots
|
||||
- digests
|
||||
- segments
|
||||
- tokens
|
||||
|
||||
Except for config section, all section contains array of objects that must be named
|
||||
as number (unsigned integer) - for example keyslot "0", "1" etc.
|
||||
Every object is typed (must contain attribute "type").
|
||||
According to type, library decides how to handle (or ignore) such an object.
|
||||
|
||||
Binary data inside JSON (for example salt) is stored in Hexa64 encoding.
|
||||
|
||||
If a value is needed to be stored as a 64bit integer (usually offset or size),
|
||||
it is stored in text format and later converted to the 64bit integer.
|
||||
(JSON cannot store 64bit integers directly.)
|
||||
|
||||
Config section
|
||||
~~~~~~~~~~~~~~
|
||||
Config contains information about JSON buffer size (cross-checked with binary header),
|
||||
keyslot area size and optional object with activation flags.
|
||||
|
||||
The "flags" section is array of activation flags that are automatically used
|
||||
when LUKS device is activated (for example it can unconditionally allow TRIM/discard
|
||||
functionality on the encrypted device).
|
||||
|
||||
Segments sections
|
||||
~~~~~~~~~~~~~~~~~
|
||||
The segment is an encrypted area on the disk containing data (in LUKS1 often
|
||||
mentioned as a data payload).
|
||||
For now, only one data area is available for the user.
|
||||
(More segments will be later used for on-line re-encryption functionality.)
|
||||
|
||||
Segments contain definition about encryption parameters, sector size and
|
||||
start and length of the segments. By default, the segment starts directly
|
||||
after the LUKS2 header and is marked as "dynamic" (it automatically detects
|
||||
the size of the available device).
|
||||
|
||||
Optionally it can contain information about data integrity protection,
|
||||
then the data segments is formatted as dm-integrity device and dm-crypt
|
||||
encryption is stacked above.
|
||||
|
||||
To activate a segment, there must be at least one digest linked to it.
|
||||
|
||||
Keyslots section
|
||||
~~~~~~~~~~~~~~~~
|
||||
Keyslot object contains information stored key - area, where it is stored
|
||||
(keyslot data), encryption, anti-forensic function, and Key Derivation Function
|
||||
and its parameters (PBKDF type, costs, salt).
|
||||
|
||||
For now, only internal "luks2" keyslot type is available, it uses the same logic
|
||||
as LUKS1 keyslot, but allows to define per-keyslot algorithms
|
||||
(for example different PBKDF).
|
||||
|
||||
Digests section
|
||||
~~~~~~~~~~~~~~~
|
||||
The digest is used to verify that volume key decrypted from a keyslot is correct.
|
||||
A digest is linked to keyslots and segment.
|
||||
|
||||
For now, only "pbkdf2" digest (LUKS1 compatible digest that uses PBKDF2)
|
||||
is supported.
|
||||
|
||||
Tokens section
|
||||
~~~~~~~~~~~~~~
|
||||
A token is an object that can describe "how to get passphrase or key" to unlock
|
||||
particular keyslot or it can be used t store any additional data (even unrelated
|
||||
to a keyslot).
|
||||
This area can be user configurable, and libcryptsetup provides interface to
|
||||
store used data directly in JSON format.
|
||||
Some token types are implemented internally, for now, there is only "luks2-keyring".
|
||||
type. This token type tries to load unlocking passphrase from kernel keyring
|
||||
with stored identification.
|
||||
|
||||
There can be external application that uses token objects to store metadata and
|
||||
implements bindings to specific hardware (TPM etc.).
|
||||
|
||||
LUKS2 JSON Format Example
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
For illustration this is example of a LUKS2 device JSON:
|
||||
|
||||
{
|
||||
"keyslots":{
|
||||
"0":{
|
||||
"type":"luks2",
|
||||
"key_size":32,
|
||||
"kdf":{
|
||||
"type":"argon2i",
|
||||
"time":181,
|
||||
"memory":1024,
|
||||
"cpus":4,
|
||||
"salt":"Xfc5ScS8tCLrdbt6jtyWsBjCwAn3Msn\/enOYaAq8PEo="
|
||||
},
|
||||
"af":{
|
||||
"type":"luks1",
|
||||
"hash":"sha256",
|
||||
"stripes":4000
|
||||
},
|
||||
"area":{
|
||||
"type":"raw",
|
||||
"encryption":"aes-xts-plain64",
|
||||
"key_size":32,
|
||||
"offset":"32768",
|
||||
"size":"131072"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tokens":{
|
||||
"0":{
|
||||
"type":"luks2-keyring",
|
||||
"keyslots":[
|
||||
"0"
|
||||
],
|
||||
"key_description":"my-token"
|
||||
}
|
||||
},
|
||||
"segments":{
|
||||
"0":{
|
||||
"type":"crypt",
|
||||
"offset":"4194304",
|
||||
"iv_tweak":"0",
|
||||
"size":"dynamic",
|
||||
"encryption":"aes-xts-plain64",
|
||||
"sector_size":512
|
||||
}
|
||||
},
|
||||
"digests":{
|
||||
"0":{
|
||||
"type":"pbkdf2",
|
||||
"keyslots":[
|
||||
"0"
|
||||
],
|
||||
"segments":[
|
||||
"0"
|
||||
],
|
||||
"hash":"sha256",
|
||||
"iterations":155298,
|
||||
"salt":"WgMOideLECc5hfnmFVu3bwttJpkfnpf2RayE2WhP8zU=",
|
||||
"digest":"olobPk9pc0GItqofH78aMPmRaOZIbRevlvSlTZ91NLI="
|
||||
}
|
||||
},
|
||||
"config":{
|
||||
"json_size":"12288",
|
||||
"keyslots_size":"4161536",
|
||||
"flags":[
|
||||
"allow-discards"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@
|
||||
* @subsection cformat crypt_format() - header and payload on mutual device
|
||||
* This section covers basic use cases for formatting LUKS devices. Format operation
|
||||
* sets device type in context and in case of LUKS header is written at the beginning
|
||||
* of block device. In the example bellow we use the scenario where LUKS header and data
|
||||
* of block device. In the example below we use the scenario where LUKS header and data
|
||||
* are both stored on the same device. There's also a possibility to store header and
|
||||
* data separately.
|
||||
*
|
||||
|
||||
BIN
docs/on-disk-format-luks2.pdf
Normal file
BIN
docs/on-disk-format-luks2.pdf
Normal file
Binary file not shown.
@@ -30,7 +30,7 @@ Changes since version 2.0.1
|
||||
|
||||
* Add LUKS2 specific options for cryptsetup-reencrypt.
|
||||
Tokens and persistent flags are now transferred during reencryption;
|
||||
change of PBKDF keyslot parameters is now supported and alllows
|
||||
change of PBKDF keyslot parameters is now supported and allows
|
||||
to set precalculated values (no benchmarks).
|
||||
|
||||
* Do not allow LUKS2 --persistent and --test-passphrase cryptsetup flags
|
||||
|
||||
121
docs/v2.0.3-ReleaseNotes
Normal file
121
docs/v2.0.3-ReleaseNotes
Normal file
@@ -0,0 +1,121 @@
|
||||
Cryptsetup 2.0.3 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release with new features.
|
||||
|
||||
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
To provide all security features of authenticated encryption, we need
|
||||
a better nonce-reuse resistant algorithm in the kernel (see note below).
|
||||
For now, please use authenticated encryption as an experimental feature.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.2
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Expose interface to unbound LUKS2 keyslots.
|
||||
Unbound LUKS2 keyslot allows storing a key material that is independent
|
||||
of master volume key (it is not bound to encrypted data segment).
|
||||
|
||||
* New API extensions for unbound keyslots (LUKS2 only)
|
||||
crypt_keyslot_get_key_size() and crypt_volume_key_get()
|
||||
These functions allow to get key and key size for unbound keyslots.
|
||||
|
||||
* New enum value CRYPT_SLOT_UNBOUND for keyslot status (LUKS2 only).
|
||||
|
||||
* Add --unbound keyslot option to the cryptsetup luksAddKey command.
|
||||
|
||||
* Add crypt_get_active_integrity_failures() call to get integrity
|
||||
failure count for dm-integrity devices.
|
||||
|
||||
* Add crypt_get_pbkdf_default() function to get per-type PBKDF default
|
||||
setting.
|
||||
|
||||
* Add new flag to crypt_keyslot_add_by_key() to force update device
|
||||
volume key. This call is mainly intended for a wrapped key change.
|
||||
|
||||
* Allow volume key store in a file with cryptsetup.
|
||||
The --dump-master-key together with --master-key-file allows cryptsetup
|
||||
to store the binary volume key to a file instead of standard output.
|
||||
|
||||
* Add support detached header for cryptsetup-reencrypt command.
|
||||
|
||||
* Fix VeraCrypt PIM handling - use proper iterations count formula
|
||||
for PBKDF2-SHA512 and PBKDF2-Whirlpool used in system volumes.
|
||||
|
||||
* Fix cryptsetup tcryptDump for VeraCrypt PIM (support --veracrypt-pim).
|
||||
|
||||
* Add --with-default-luks-format configure time option.
|
||||
(Option to override default LUKS format version.)
|
||||
|
||||
* Fix LUKS version conversion for detached (and trimmed) LUKS headers.
|
||||
|
||||
* Add luksConvertKey cryptsetup command that converts specific keyslot
|
||||
from one PBKDF to another.
|
||||
|
||||
* Do not allow conversion to LUKS2 if LUKSMETA (external tool metadata)
|
||||
header is detected.
|
||||
|
||||
* More cleanup and hardening of LUKS2 keyslot specific validation options.
|
||||
Add more checks for cipher validity before writing metadata on-disk.
|
||||
|
||||
* Do not allow LUKS1 version downconversion if the header contains tokens.
|
||||
|
||||
* Add "paes" family ciphers (AES wrapped key scheme for mainframes)
|
||||
to allowed ciphers.
|
||||
Specific wrapped ley configuration logic must be done by 3rd party tool,
|
||||
LUKS2 stores only keyslot material and allow activation of the device.
|
||||
|
||||
* Add support for --check-at-most-once option (kernel 4.17) to veritysetup.
|
||||
This flag can be dangerous; if you can control underlying device
|
||||
(you can change its content after it was verified) it will no longer
|
||||
prevent reading tampered data and also it does not prevent silent
|
||||
data corruptions that appear after the block was once read.
|
||||
|
||||
* Fix return code (EPERM instead of EINVAL) and retry count for bad
|
||||
passphrase on non-tty input.
|
||||
|
||||
* Enable support for FEC decoding in veritysetup to check dm-verity devices
|
||||
with additional Reed-Solomon code in userspace (verify command).
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* There will be better documentation and examples (planned for 2.0.4).
|
||||
|
||||
* There will be some more formal definition of the threat model for integrity
|
||||
protection. (And a link to some papers discussing integrity protection,
|
||||
once it is, hopefully, accepted and published.)
|
||||
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition
|
||||
https://competitions.cr.yp.to/caesar-submissions.html.
|
||||
We plan to use AEGIS and MORUS, as CAESAR finalists.
|
||||
|
||||
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
|
||||
in the kernel have too small 96-bit nonces that are problematic with
|
||||
randomly generated IVs (the collision probability is not negligible).
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be REMOVED in version 2.1
|
||||
in favor of python bindings to the libblockdev library.
|
||||
See https://github.com/storaged-project/libblockdev/releases/tag/2.17-1 that
|
||||
already supports LUKS2 and VeraCrypt devices handling through libcryptsetup.
|
||||
119
docs/v2.0.4-ReleaseNotes
Normal file
119
docs/v2.0.4-ReleaseNotes
Normal file
@@ -0,0 +1,119 @@
|
||||
Cryptsetup 2.0.4 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release with new features.
|
||||
|
||||
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
To provide all security features of authenticated encryption, we need
|
||||
a better nonce-reuse resistant algorithm in the kernel (see note below).
|
||||
For now, please use authenticated encryption as an experimental feature.
|
||||
|
||||
Please do not use LUKS2 without properly configured backup or in
|
||||
production systems that need to be compatible with older systems.
|
||||
|
||||
Changes since version 2.0.3
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Use the libblkid (blockid) library to detect foreign signatures
|
||||
on a device before LUKS format and LUKS2 auto-recovery.
|
||||
|
||||
This change fixes an unexpected recovery using the secondary
|
||||
LUKS2 header after a device was already overwritten with
|
||||
another format (filesystem or LVM physical volume).
|
||||
|
||||
LUKS2 will not recreate a primary header if it detects a valid
|
||||
foreign signature. In this situation, a user must always
|
||||
use cryptsetup repair command for the recovery.
|
||||
|
||||
Note that libcryptsetup and utilities are now linked to libblkid
|
||||
as a new dependence.
|
||||
|
||||
To compile code without blockid support (strongly discouraged),
|
||||
use --disable-blkid configure switch.
|
||||
|
||||
* Add prompt for format and repair actions in cryptsetup and
|
||||
integritysetup if foreign signatures are detected on the device
|
||||
through the blockid library.
|
||||
|
||||
After the confirmation, all known signatures are then wiped as
|
||||
part of the format or repair procedure.
|
||||
|
||||
* Print consistent verbose message about keyslot and token numbers.
|
||||
For keyslot actions: Key slot <number> unlocked/created/removed.
|
||||
For token actions: Token <number> created/removed.
|
||||
|
||||
* Print error, if a non-existent token is tried to be removed.
|
||||
|
||||
* Add support for LUKS2 token definition export and import.
|
||||
|
||||
The token command now can export/import customized token JSON file
|
||||
directly from command line. See the man page for more details.
|
||||
|
||||
* Add support for new dm-integrity superblock version 2.
|
||||
|
||||
* Add an error message when nothing was read from a key file.
|
||||
|
||||
* Update cryptsetup man pages, including --type option usage.
|
||||
|
||||
* Add a snapshot of LUKS2 format specification to documentation
|
||||
and accordingly fix supported secondary header offsets.
|
||||
|
||||
* Add bundled optimized Argon2 SSE (X86_64 platform) code.
|
||||
|
||||
If the bundled Argon2 code is used and the new configure switch
|
||||
--enable-internal-sse-argon2 option is present, and compiler flags
|
||||
support required optimization, the code will try to use optimized
|
||||
and faster variant.
|
||||
|
||||
Always use the shared library (--enable-libargon2) if possible.
|
||||
|
||||
This option was added because an enterprise distribution
|
||||
rejected to support the shared Argon2 library and native support
|
||||
in generic cryptographic libraries is not ready yet.
|
||||
|
||||
* Fix compilation with crypto backend for LibreSSL >= 2.7.0.
|
||||
LibreSSL introduced OpenSSL 1.1.x API functions, so compatibility
|
||||
wrapper must be commented out.
|
||||
|
||||
* Fix on-disk header size calculation for LUKS2 format if a specific
|
||||
data alignment is requested. Until now, the code used default size
|
||||
that could be wrong for converted devices.
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Authenticated encryption will use new algorithms from CAESAR competition
|
||||
https://competitions.cr.yp.to/caesar-submissions.html.
|
||||
We plan to use AEGIS and MORUS (in kernel 4.18), as CAESAR finalists.
|
||||
|
||||
NOTE: Currently available authenticated modes (GCM, Chacha20-poly1305)
|
||||
in the kernel have too small 96-bit nonces that are problematic with
|
||||
randomly generated IVs (the collision probability is not negligible).
|
||||
|
||||
For more info about LUKS2 authenticated encryption, please see our paper
|
||||
https://arxiv.org/abs/1807.00309
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be REMOVED in version 2.1
|
||||
in favor of python bindings to the libblockdev library.
|
||||
See https://github.com/storaged-project/libblockdev/releases that
|
||||
already supports LUKS2 and VeraCrypt devices handling through libcryptsetup.
|
||||
|
||||
102
docs/v2.0.5-ReleaseNotes
Normal file
102
docs/v2.0.5-ReleaseNotes
Normal file
@@ -0,0 +1,102 @@
|
||||
Cryptsetup 2.0.5 Release Notes
|
||||
==============================
|
||||
Stable bug-fix release with new features.
|
||||
|
||||
Cryptsetup 2.x version introduces a new on-disk LUKS2 format.
|
||||
|
||||
The legacy LUKS (referenced as LUKS1) will be fully supported
|
||||
forever as well as a traditional and fully backward compatible format.
|
||||
|
||||
Please note that authenticated disk encryption, non-cryptographic
|
||||
data integrity protection (dm-integrity), use of Argon2 Password-Based
|
||||
Key Derivation Function and the LUKS2 on-disk format itself are new
|
||||
features and can contain some bugs.
|
||||
|
||||
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.4
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Wipe full header areas (including unused) during LUKS format.
|
||||
|
||||
Since this version, the whole area up to the data offset is zeroed,
|
||||
and subsequently, all keyslots areas are wiped with random data.
|
||||
This ensures that no remaining old data remains in the LUKS header
|
||||
areas, but it could slow down format operation on some devices.
|
||||
Previously only first 4k (or 32k for LUKS2) and the used keyslot
|
||||
was overwritten in the format operation.
|
||||
|
||||
* Several fixes to error messages that were unintentionally replaced
|
||||
in previous versions with a silent exit code.
|
||||
More descriptive error messages were added, including error
|
||||
messages if
|
||||
- a device is unusable (not a block device, no access, etc.),
|
||||
- a LUKS device is not detected,
|
||||
- LUKS header load code detects unsupported version,
|
||||
- a keyslot decryption fails (also happens in the cipher check),
|
||||
- converting an inactive keyslot.
|
||||
|
||||
* Device activation fails if data area overlaps with LUKS header.
|
||||
|
||||
* Code now uses explicit_bzero to wipe memory if available
|
||||
(instead of own implementation).
|
||||
|
||||
* Additional VeraCrypt modes are now supported, including Camellia
|
||||
and Kuznyechik symmetric ciphers (and cipher chains) and Streebog
|
||||
hash function. These were introduced in a recent VeraCrypt upstream.
|
||||
|
||||
Note that Kuznyechik requires out-of-tree kernel module and
|
||||
Streebog hash function is available only with the gcrypt cryptographic
|
||||
backend for now.
|
||||
|
||||
* Fixes static build for integritysetup if the pwquality library is used.
|
||||
|
||||
* Allows passphrase change for unbound keyslots.
|
||||
|
||||
* Fixes removed keyslot number in verbose message for luksKillSlot,
|
||||
luksRemoveKey and erase command.
|
||||
|
||||
* Adds blkid scan when attempting to open a plain device and warn the user
|
||||
about existing device signatures in a ciphertext device.
|
||||
|
||||
* Remove LUKS header signature if luksFormat fails to add the first keyslot.
|
||||
|
||||
* Remove O_SYNC from device open and use fsync() to speed up
|
||||
wipe operation considerably.
|
||||
|
||||
* Create --master-key-file in luksDump and fail if the file already exists.
|
||||
|
||||
* Fixes a bug when LUKS2 authenticated encryption with a detached header
|
||||
wiped the header device instead of dm-integrity data device area (causing
|
||||
unnecessary LUKS2 header auto recovery).
|
||||
|
||||
Unfinished things & TODO for next releases
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Authenticated encryption should use new algorithms from CAESAR competition
|
||||
https://competitions.cr.yp.to/caesar-submissions.html.
|
||||
AEGIS and MORUS are already available in kernel 4.18.
|
||||
|
||||
For more info about LUKS2 authenticated encryption, please see our paper
|
||||
https://arxiv.org/abs/1807.00309
|
||||
|
||||
Please note that authenticated encryption is still an experimental feature
|
||||
and can have performance problems for hish-speed devices and device
|
||||
with larger IO blocks (like RAID).
|
||||
|
||||
* Authenticated encryption do not set encryption for a dm-integrity journal.
|
||||
|
||||
While it does not influence data confidentiality or integrity protection,
|
||||
an attacker can get some more information from data journal or cause that
|
||||
system will corrupt sectors after journal replay. (That corruption will be
|
||||
detected though.)
|
||||
|
||||
* There are examples of user-defined tokens inside misc/luks2_keyslot_example
|
||||
directory (like a simple external program that uses libssh to unlock LUKS2
|
||||
using remote keyfile).
|
||||
|
||||
* The python binding (pycryptsetup) contains only basic functionality for LUKS1
|
||||
(it is not updated for new features) and will be REMOVED in version 2.1
|
||||
in favor of python bindings to the libblockdev library.
|
||||
See https://github.com/storaged-project/libblockdev/releases that
|
||||
already supports LUKS2 and VeraCrypt devices handling through libcryptsetup.
|
||||
@@ -3,10 +3,18 @@ pkgconfig_DATA = lib/libcryptsetup.pc
|
||||
|
||||
lib_LTLIBRARIES = libcryptsetup.la
|
||||
|
||||
noinst_LTLIBRARIES += libutils_io.la
|
||||
|
||||
include_HEADERS = lib/libcryptsetup.h
|
||||
|
||||
EXTRA_DIST += lib/libcryptsetup.pc.in lib/libcryptsetup.sym
|
||||
|
||||
libutils_io_la_CFLAGS = $(AM_CFLAGS)
|
||||
|
||||
libutils_io_la_SOURCES = \
|
||||
lib/utils_io.c \
|
||||
lib/utils_io.h
|
||||
|
||||
libcryptsetup_la_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||
-I $(top_srcdir)/lib/crypto_backend \
|
||||
-I $(top_srcdir)/lib/luks1 \
|
||||
@@ -16,7 +24,7 @@ libcryptsetup_la_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||
-I $(top_srcdir)/lib/tcrypt \
|
||||
-I $(top_srcdir)/lib/integrity
|
||||
|
||||
libcryptsetup_la_DEPENDENCIES = libcrypto_backend.la lib/libcryptsetup.sym
|
||||
libcryptsetup_la_DEPENDENCIES = libutils_io.la libcrypto_backend.la lib/libcryptsetup.sym
|
||||
|
||||
libcryptsetup_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \
|
||||
-Wl,--version-script=$(top_srcdir)/lib/libcryptsetup.sym \
|
||||
@@ -30,7 +38,9 @@ libcryptsetup_la_LIBADD = \
|
||||
@CRYPTO_LIBS@ \
|
||||
@LIBARGON2_LIBS@ \
|
||||
@JSON_C_LIBS@ \
|
||||
libcrypto_backend.la
|
||||
@BLKID_LIBS@ \
|
||||
libcrypto_backend.la \
|
||||
libutils_io.la
|
||||
|
||||
libcryptsetup_la_SOURCES = \
|
||||
lib/setup.c \
|
||||
@@ -77,6 +87,7 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/verity/verity.c \
|
||||
lib/verity/verity.h \
|
||||
lib/verity/rs_encode_char.c \
|
||||
lib/verity/rs_decode_char.c \
|
||||
lib/verity/rs.h \
|
||||
lib/luks2/luks2_disk_metadata.c \
|
||||
lib/luks2/luks2_json_format.c \
|
||||
@@ -89,4 +100,6 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/luks2/luks2_token_keyring.c \
|
||||
lib/luks2/luks2_token.c \
|
||||
lib/luks2/luks2_internal.h \
|
||||
lib/luks2/luks2.h
|
||||
lib/luks2/luks2.h \
|
||||
lib/utils_blkid.c \
|
||||
lib/utils_blkid.h
|
||||
|
||||
@@ -8,7 +8,8 @@ libcrypto_backend_la_SOURCES = \
|
||||
lib/crypto_backend/crypto_storage.c \
|
||||
lib/crypto_backend/pbkdf_check.c \
|
||||
lib/crypto_backend/crc32.c \
|
||||
lib/crypto_backend/argon2_generic.c
|
||||
lib/crypto_backend/argon2_generic.c \
|
||||
lib/crypto_backend/cipher_generic.c
|
||||
|
||||
if CRYPTO_BACKEND_GCRYPT
|
||||
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_gcrypt.c
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
noinst_LTLIBRARIES += libargon2.la
|
||||
|
||||
libargon2_la_CFLAGS = $(AM_CFLAGS) -std=c89 -pthread -O3
|
||||
libargon2_la_CPPFLAGS = $(AM_CPPFLAGS) -I lib/crypto_backend/argon2/blake2
|
||||
libargon2_la_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||
-I lib/crypto_backend/argon2 \
|
||||
-I lib/crypto_backend/argon2/blake2
|
||||
|
||||
libargon2_la_SOURCES = \
|
||||
lib/crypto_backend/argon2/blake2/blake2b.c \
|
||||
lib/crypto_backend/argon2/blake2/blake2.h \
|
||||
lib/crypto_backend/argon2/blake2/blake2-impl.h \
|
||||
lib/crypto_backend/argon2/blake2/blamka-round-ref.h \
|
||||
lib/crypto_backend/argon2/argon2.c \
|
||||
lib/crypto_backend/argon2/argon2.h \
|
||||
lib/crypto_backend/argon2/core.c \
|
||||
lib/crypto_backend/argon2/core.h \
|
||||
lib/crypto_backend/argon2/encoding.c \
|
||||
lib/crypto_backend/argon2/encoding.h \
|
||||
lib/crypto_backend/argon2/ref.c \
|
||||
lib/crypto_backend/argon2/thread.c \
|
||||
lib/crypto_backend/argon2/thread.h
|
||||
|
||||
if CRYPTO_INTERNAL_SSE_ARGON2
|
||||
libargon2_la_SOURCES += lib/crypto_backend/argon2/blake2/blamka-round-opt.h \
|
||||
lib/crypto_backend/argon2/opt.c
|
||||
else
|
||||
libargon2_la_SOURCES += lib/crypto_backend/argon2/blake2/blamka-round-ref.h \
|
||||
lib/crypto_backend/argon2/ref.c
|
||||
endif
|
||||
|
||||
EXTRA_DIST += lib/crypto_backend/argon2/LICENSE
|
||||
EXTRA_DIST += lib/crypto_backend/argon2/README
|
||||
|
||||
@@ -29,10 +29,13 @@ extern "C" {
|
||||
/* Symbols visibility control */
|
||||
#ifdef A2_VISCTL
|
||||
#define ARGON2_PUBLIC __attribute__((visibility("default")))
|
||||
#define ARGON2_LOCAL __attribute__ ((visibility ("hidden")))
|
||||
#elif _MSC_VER
|
||||
#define ARGON2_PUBLIC __declspec(dllexport)
|
||||
#define ARGON2_LOCAL
|
||||
#else
|
||||
#define ARGON2_PUBLIC
|
||||
#define ARGON2_LOCAL
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -90,7 +93,7 @@ extern "C" {
|
||||
#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1)
|
||||
|
||||
/* Global flag to determine if we are wiping internal memory buffers. This flag
|
||||
* is defined in core.c and deafults to 1 (wipe internal memory). */
|
||||
* is defined in core.c and defaults to 1 (wipe internal memory). */
|
||||
extern int FLAG_clear_internal_memory;
|
||||
|
||||
/* Error codes */
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
#ifndef PORTABLE_BLAKE2_H
|
||||
#define PORTABLE_BLAKE2_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "../argon2.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
@@ -69,19 +67,19 @@ enum {
|
||||
};
|
||||
|
||||
/* Streaming API */
|
||||
int blake2b_init(blake2b_state *S, size_t outlen);
|
||||
int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,
|
||||
ARGON2_LOCAL int blake2b_init(blake2b_state *S, size_t outlen);
|
||||
ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key,
|
||||
size_t keylen);
|
||||
int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
|
||||
int blake2b_update(blake2b_state *S, const void *in, size_t inlen);
|
||||
int blake2b_final(blake2b_state *S, void *out, size_t outlen);
|
||||
ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
|
||||
ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, size_t inlen);
|
||||
ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, size_t outlen);
|
||||
|
||||
/* Simple API */
|
||||
int blake2b(void *out, size_t outlen, const void *in, size_t inlen,
|
||||
const void *key, size_t keylen);
|
||||
ARGON2_LOCAL int blake2b(void *out, size_t outlen, const void *in, size_t inlen,
|
||||
const void *key, size_t keylen);
|
||||
|
||||
/* Argon2 Team - Begin Code */
|
||||
int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen);
|
||||
ARGON2_LOCAL int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen);
|
||||
/* Argon2 Team - End Code */
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
471
lib/crypto_backend/argon2/blake2/blamka-round-opt.h
Normal file
471
lib/crypto_backend/argon2/blake2/blamka-round-opt.h
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* 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 : 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.
|
||||
*/
|
||||
|
||||
#ifndef BLAKE_ROUND_MKA_OPT_H
|
||||
#define BLAKE_ROUND_MKA_OPT_H
|
||||
|
||||
#include "blake2-impl.h"
|
||||
|
||||
#include <emmintrin.h>
|
||||
#if defined(__SSSE3__)
|
||||
#include <tmmintrin.h> /* for _mm_shuffle_epi8 and _mm_alignr_epi8 */
|
||||
#endif
|
||||
|
||||
#if defined(__XOP__) && (defined(__GNUC__) || defined(__clang__))
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__AVX512F__)
|
||||
#if !defined(__AVX2__)
|
||||
#if !defined(__XOP__)
|
||||
#if defined(__SSSE3__)
|
||||
#define r16 \
|
||||
(_mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))
|
||||
#define r24 \
|
||||
(_mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))
|
||||
#define _mm_roti_epi64(x, c) \
|
||||
(-(c) == 32) \
|
||||
? _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) \
|
||||
: (-(c) == 24) \
|
||||
? _mm_shuffle_epi8((x), r24) \
|
||||
: (-(c) == 16) \
|
||||
? _mm_shuffle_epi8((x), r16) \
|
||||
: (-(c) == 63) \
|
||||
? _mm_xor_si128(_mm_srli_epi64((x), -(c)), \
|
||||
_mm_add_epi64((x), (x))) \
|
||||
: _mm_xor_si128(_mm_srli_epi64((x), -(c)), \
|
||||
_mm_slli_epi64((x), 64 - (-(c))))
|
||||
#else /* defined(__SSE2__) */
|
||||
#define _mm_roti_epi64(r, c) \
|
||||
_mm_xor_si128(_mm_srli_epi64((r), -(c)), _mm_slli_epi64((r), 64 - (-(c))))
|
||||
#endif
|
||||
#else
|
||||
#endif
|
||||
|
||||
static BLAKE2_INLINE __m128i fBlaMka(__m128i x, __m128i y) {
|
||||
const __m128i z = _mm_mul_epu32(x, y);
|
||||
return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z));
|
||||
}
|
||||
|
||||
#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
A0 = fBlaMka(A0, B0); \
|
||||
A1 = fBlaMka(A1, B1); \
|
||||
\
|
||||
D0 = _mm_xor_si128(D0, A0); \
|
||||
D1 = _mm_xor_si128(D1, A1); \
|
||||
\
|
||||
D0 = _mm_roti_epi64(D0, -32); \
|
||||
D1 = _mm_roti_epi64(D1, -32); \
|
||||
\
|
||||
C0 = fBlaMka(C0, D0); \
|
||||
C1 = fBlaMka(C1, D1); \
|
||||
\
|
||||
B0 = _mm_xor_si128(B0, C0); \
|
||||
B1 = _mm_xor_si128(B1, C1); \
|
||||
\
|
||||
B0 = _mm_roti_epi64(B0, -24); \
|
||||
B1 = _mm_roti_epi64(B1, -24); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
A0 = fBlaMka(A0, B0); \
|
||||
A1 = fBlaMka(A1, B1); \
|
||||
\
|
||||
D0 = _mm_xor_si128(D0, A0); \
|
||||
D1 = _mm_xor_si128(D1, A1); \
|
||||
\
|
||||
D0 = _mm_roti_epi64(D0, -16); \
|
||||
D1 = _mm_roti_epi64(D1, -16); \
|
||||
\
|
||||
C0 = fBlaMka(C0, D0); \
|
||||
C1 = fBlaMka(C1, D1); \
|
||||
\
|
||||
B0 = _mm_xor_si128(B0, C0); \
|
||||
B1 = _mm_xor_si128(B1, C1); \
|
||||
\
|
||||
B0 = _mm_roti_epi64(B0, -63); \
|
||||
B1 = _mm_roti_epi64(B1, -63); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#if defined(__SSSE3__)
|
||||
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
__m128i t0 = _mm_alignr_epi8(B1, B0, 8); \
|
||||
__m128i t1 = _mm_alignr_epi8(B0, B1, 8); \
|
||||
B0 = t0; \
|
||||
B1 = t1; \
|
||||
\
|
||||
t0 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = t0; \
|
||||
\
|
||||
t0 = _mm_alignr_epi8(D1, D0, 8); \
|
||||
t1 = _mm_alignr_epi8(D0, D1, 8); \
|
||||
D0 = t1; \
|
||||
D1 = t0; \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
__m128i t0 = _mm_alignr_epi8(B0, B1, 8); \
|
||||
__m128i t1 = _mm_alignr_epi8(B1, B0, 8); \
|
||||
B0 = t0; \
|
||||
B1 = t1; \
|
||||
\
|
||||
t0 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = t0; \
|
||||
\
|
||||
t0 = _mm_alignr_epi8(D0, D1, 8); \
|
||||
t1 = _mm_alignr_epi8(D1, D0, 8); \
|
||||
D0 = t1; \
|
||||
D1 = t0; \
|
||||
} while ((void)0, 0)
|
||||
#else /* SSE2 */
|
||||
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
__m128i t0 = D0; \
|
||||
__m128i t1 = B0; \
|
||||
D0 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = D0; \
|
||||
D0 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t0, t0)); \
|
||||
D1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(D1, D1)); \
|
||||
B0 = _mm_unpackhi_epi64(B0, _mm_unpacklo_epi64(B1, B1)); \
|
||||
B1 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(t1, t1)); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
__m128i t0, t1; \
|
||||
t0 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = t0; \
|
||||
t0 = B0; \
|
||||
t1 = D0; \
|
||||
B0 = _mm_unpackhi_epi64(B1, _mm_unpacklo_epi64(B0, B0)); \
|
||||
B1 = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(B1, B1)); \
|
||||
D0 = _mm_unpackhi_epi64(D0, _mm_unpacklo_epi64(D1, D1)); \
|
||||
D1 = _mm_unpackhi_epi64(D1, _mm_unpacklo_epi64(t1, t1)); \
|
||||
} while ((void)0, 0)
|
||||
#endif
|
||||
|
||||
#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
} while ((void)0, 0)
|
||||
#else /* __AVX2__ */
|
||||
|
||||
#include <immintrin.h>
|
||||
|
||||
#define rotr32(x) _mm256_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1))
|
||||
#define rotr24(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10, 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10))
|
||||
#define rotr16(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9, 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9))
|
||||
#define rotr63(x) _mm256_xor_si256(_mm256_srli_epi64((x), 63), _mm256_add_epi64((x), (x)))
|
||||
|
||||
#define G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
__m256i ml = _mm256_mul_epu32(A0, B0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \
|
||||
D0 = _mm256_xor_si256(D0, A0); \
|
||||
D0 = rotr32(D0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C0, D0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \
|
||||
\
|
||||
B0 = _mm256_xor_si256(B0, C0); \
|
||||
B0 = rotr24(B0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(A1, B1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \
|
||||
D1 = _mm256_xor_si256(D1, A1); \
|
||||
D1 = rotr32(D1); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C1, D1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \
|
||||
\
|
||||
B1 = _mm256_xor_si256(B1, C1); \
|
||||
B1 = rotr24(B1); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
__m256i ml = _mm256_mul_epu32(A0, B0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \
|
||||
D0 = _mm256_xor_si256(D0, A0); \
|
||||
D0 = rotr16(D0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C0, D0); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \
|
||||
B0 = _mm256_xor_si256(B0, C0); \
|
||||
B0 = rotr63(B0); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(A1, B1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \
|
||||
D1 = _mm256_xor_si256(D1, A1); \
|
||||
D1 = rotr16(D1); \
|
||||
\
|
||||
ml = _mm256_mul_epu32(C1, D1); \
|
||||
ml = _mm256_add_epi64(ml, ml); \
|
||||
C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \
|
||||
B1 = _mm256_xor_si256(B1, C1); \
|
||||
B1 = rotr63(B1); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
\
|
||||
B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
__m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \
|
||||
__m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \
|
||||
B1 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
B0 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
\
|
||||
tmp1 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = tmp1; \
|
||||
\
|
||||
tmp1 = _mm256_blend_epi32(D0, D1, 0xCC); \
|
||||
tmp2 = _mm256_blend_epi32(D0, D1, 0x33); \
|
||||
D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
} while(0);
|
||||
|
||||
#define UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
\
|
||||
B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
__m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \
|
||||
__m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \
|
||||
B0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
B1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
\
|
||||
tmp1 = C0; \
|
||||
C0 = C1; \
|
||||
C1 = tmp1; \
|
||||
\
|
||||
tmp1 = _mm256_blend_epi32(D0, D1, 0x33); \
|
||||
tmp2 = _mm256_blend_epi32(D0, D1, 0xCC); \
|
||||
D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \
|
||||
D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define BLAKE2_ROUND_1(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do{ \
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
\
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
} while((void)0, 0);
|
||||
|
||||
#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do{ \
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
\
|
||||
UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
} while((void)0, 0);
|
||||
|
||||
#endif /* __AVX2__ */
|
||||
|
||||
#else /* __AVX512F__ */
|
||||
|
||||
#include <immintrin.h>
|
||||
|
||||
#define ror64(x, n) _mm512_ror_epi64((x), (n))
|
||||
|
||||
static __m512i muladd(__m512i x, __m512i y)
|
||||
{
|
||||
__m512i z = _mm512_mul_epu32(x, y);
|
||||
return _mm512_add_epi64(_mm512_add_epi64(x, y), _mm512_add_epi64(z, z));
|
||||
}
|
||||
|
||||
#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
A0 = muladd(A0, B0); \
|
||||
A1 = muladd(A1, B1); \
|
||||
\
|
||||
D0 = _mm512_xor_si512(D0, A0); \
|
||||
D1 = _mm512_xor_si512(D1, A1); \
|
||||
\
|
||||
D0 = ror64(D0, 32); \
|
||||
D1 = ror64(D1, 32); \
|
||||
\
|
||||
C0 = muladd(C0, D0); \
|
||||
C1 = muladd(C1, D1); \
|
||||
\
|
||||
B0 = _mm512_xor_si512(B0, C0); \
|
||||
B1 = _mm512_xor_si512(B1, C1); \
|
||||
\
|
||||
B0 = ror64(B0, 24); \
|
||||
B1 = ror64(B1, 24); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
A0 = muladd(A0, B0); \
|
||||
A1 = muladd(A1, B1); \
|
||||
\
|
||||
D0 = _mm512_xor_si512(D0, A0); \
|
||||
D1 = _mm512_xor_si512(D1, A1); \
|
||||
\
|
||||
D0 = ror64(D0, 16); \
|
||||
D1 = ror64(D1, 16); \
|
||||
\
|
||||
C0 = muladd(C0, D0); \
|
||||
C1 = muladd(C1, D1); \
|
||||
\
|
||||
B0 = _mm512_xor_si512(B0, C0); \
|
||||
B1 = _mm512_xor_si512(B1, C1); \
|
||||
\
|
||||
B0 = ror64(B0, 63); \
|
||||
B1 = ror64(B1, 63); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
\
|
||||
C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
\
|
||||
D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \
|
||||
\
|
||||
C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \
|
||||
\
|
||||
D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1) \
|
||||
do { \
|
||||
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
G1(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
G2(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
\
|
||||
UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define SWAP_HALVES(A0, A1) \
|
||||
do { \
|
||||
__m512i t0, t1; \
|
||||
t0 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(1, 0, 1, 0)); \
|
||||
t1 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(3, 2, 3, 2)); \
|
||||
A0 = t0; \
|
||||
A1 = t1; \
|
||||
} while((void)0, 0)
|
||||
|
||||
#define SWAP_QUARTERS(A0, A1) \
|
||||
do { \
|
||||
SWAP_HALVES(A0, A1); \
|
||||
A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \
|
||||
A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \
|
||||
} while((void)0, 0)
|
||||
|
||||
#define UNSWAP_QUARTERS(A0, A1) \
|
||||
do { \
|
||||
A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \
|
||||
A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \
|
||||
SWAP_HALVES(A0, A1); \
|
||||
} while((void)0, 0)
|
||||
|
||||
#define BLAKE2_ROUND_1(A0, C0, B0, D0, A1, C1, B1, D1) \
|
||||
do { \
|
||||
SWAP_HALVES(A0, B0); \
|
||||
SWAP_HALVES(C0, D0); \
|
||||
SWAP_HALVES(A1, B1); \
|
||||
SWAP_HALVES(C1, D1); \
|
||||
BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
SWAP_HALVES(A0, B0); \
|
||||
SWAP_HALVES(C0, D0); \
|
||||
SWAP_HALVES(A1, B1); \
|
||||
SWAP_HALVES(C1, D1); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \
|
||||
do { \
|
||||
SWAP_QUARTERS(A0, A1); \
|
||||
SWAP_QUARTERS(B0, B1); \
|
||||
SWAP_QUARTERS(C0, C1); \
|
||||
SWAP_QUARTERS(D0, D1); \
|
||||
BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \
|
||||
UNSWAP_QUARTERS(A0, A1); \
|
||||
UNSWAP_QUARTERS(B0, B1); \
|
||||
UNSWAP_QUARTERS(C0, C1); \
|
||||
UNSWAP_QUARTERS(D0, D1); \
|
||||
} while ((void)0, 0)
|
||||
|
||||
#endif /* __AVX512F__ */
|
||||
#endif /* BLAKE_ROUND_MKA_OPT_H */
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "blake2.h"
|
||||
#include "blake2-impl.h"
|
||||
|
||||
/*designed by the Lyra PHC team */
|
||||
/* designed by the Lyra PHC team */
|
||||
static BLAKE2_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) {
|
||||
const uint64_t m = UINT64_C(0xFFFFFFFF);
|
||||
const uint64_t xy = (x & m) * (y & m);
|
||||
|
||||
283
lib/crypto_backend/argon2/opt.c
Normal file
283
lib/crypto_backend/argon2/opt.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Argon2 reference source code package - reference C implementations
|
||||
*
|
||||
* Copyright 2015
|
||||
* Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
|
||||
*
|
||||
* You may use this work under the terms of a Creative Commons CC0 1.0
|
||||
* 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 : 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.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "argon2.h"
|
||||
#include "core.h"
|
||||
|
||||
#include "blake2/blake2.h"
|
||||
#include "blake2/blamka-round-opt.h"
|
||||
|
||||
/*
|
||||
* Function fills a new memory block and optionally XORs the old block over the new one.
|
||||
* Memory must be initialized.
|
||||
* @param state Pointer to the just produced block. Content will be updated(!)
|
||||
* @param ref_block Pointer to the reference block
|
||||
* @param next_block Pointer to the block to be XORed over. May coincide with @ref_block
|
||||
* @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
|
||||
* @pre all block pointers must be valid
|
||||
*/
|
||||
#if defined(__AVX512F__)
|
||||
static void fill_block(__m512i *state, const block *ref_block,
|
||||
block *next_block, int with_xor) {
|
||||
__m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK];
|
||||
unsigned int i;
|
||||
|
||||
if (with_xor) {
|
||||
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm512_xor_si512(
|
||||
state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));
|
||||
block_XY[i] = _mm512_xor_si512(
|
||||
state[i], _mm512_loadu_si512((const __m512i *)next_block->v + i));
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
|
||||
block_XY[i] = state[i] = _mm512_xor_si512(
|
||||
state[i], _mm512_loadu_si512((const __m512i *)ref_block->v + i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
BLAKE2_ROUND_1(
|
||||
state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
|
||||
state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
BLAKE2_ROUND_2(
|
||||
state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i],
|
||||
state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm512_xor_si512(state[i], block_XY[i]);
|
||||
_mm512_storeu_si512((__m512i *)next_block->v + i, state[i]);
|
||||
}
|
||||
}
|
||||
#elif defined(__AVX2__)
|
||||
static void fill_block(__m256i *state, const block *ref_block,
|
||||
block *next_block, int with_xor) {
|
||||
__m256i block_XY[ARGON2_HWORDS_IN_BLOCK];
|
||||
unsigned int i;
|
||||
|
||||
if (with_xor) {
|
||||
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm256_xor_si256(
|
||||
state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));
|
||||
block_XY[i] = _mm256_xor_si256(
|
||||
state[i], _mm256_loadu_si256((const __m256i *)next_block->v + i));
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
|
||||
block_XY[i] = state[i] = _mm256_xor_si256(
|
||||
state[i], _mm256_loadu_si256((const __m256i *)ref_block->v + i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5],
|
||||
state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
BLAKE2_ROUND_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i],
|
||||
state[16 + i], state[20 + i], state[24 + i], state[28 + i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm256_xor_si256(state[i], block_XY[i]);
|
||||
_mm256_storeu_si256((__m256i *)next_block->v + i, state[i]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void fill_block(__m128i *state, const block *ref_block,
|
||||
block *next_block, int with_xor) {
|
||||
__m128i block_XY[ARGON2_OWORDS_IN_BLOCK];
|
||||
unsigned int i;
|
||||
|
||||
if (with_xor) {
|
||||
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm_xor_si128(
|
||||
state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));
|
||||
block_XY[i] = _mm_xor_si128(
|
||||
state[i], _mm_loadu_si128((const __m128i *)next_block->v + i));
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
|
||||
block_XY[i] = state[i] = _mm_xor_si128(
|
||||
state[i], _mm_loadu_si128((const __m128i *)ref_block->v + i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2],
|
||||
state[8 * i + 3], state[8 * i + 4], state[8 * i + 5],
|
||||
state[8 * i + 6], state[8 * i + 7]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i],
|
||||
state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i],
|
||||
state[8 * 6 + i], state[8 * 7 + i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) {
|
||||
state[i] = _mm_xor_si128(state[i], block_XY[i]);
|
||||
_mm_storeu_si128((__m128i *)next_block->v + i, state[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void next_addresses(block *address_block, block *input_block) {
|
||||
/*Temporary zero-initialized blocks*/
|
||||
#if defined(__AVX512F__)
|
||||
__m512i zero_block[ARGON2_512BIT_WORDS_IN_BLOCK];
|
||||
__m512i zero2_block[ARGON2_512BIT_WORDS_IN_BLOCK];
|
||||
#elif defined(__AVX2__)
|
||||
__m256i zero_block[ARGON2_HWORDS_IN_BLOCK];
|
||||
__m256i zero2_block[ARGON2_HWORDS_IN_BLOCK];
|
||||
#else
|
||||
__m128i zero_block[ARGON2_OWORDS_IN_BLOCK];
|
||||
__m128i zero2_block[ARGON2_OWORDS_IN_BLOCK];
|
||||
#endif
|
||||
|
||||
memset(zero_block, 0, sizeof(zero_block));
|
||||
memset(zero2_block, 0, sizeof(zero2_block));
|
||||
|
||||
/*Increasing index counter*/
|
||||
input_block->v[6]++;
|
||||
|
||||
/*First iteration of G*/
|
||||
fill_block(zero_block, input_block, address_block, 0);
|
||||
|
||||
/*Second iteration of G*/
|
||||
fill_block(zero2_block, address_block, address_block, 0);
|
||||
}
|
||||
|
||||
void fill_segment(const argon2_instance_t *instance,
|
||||
argon2_position_t position) {
|
||||
block *ref_block = NULL, *curr_block = NULL;
|
||||
block address_block, input_block;
|
||||
uint64_t pseudo_rand, ref_index, ref_lane;
|
||||
uint32_t prev_offset, curr_offset;
|
||||
uint32_t starting_index, i;
|
||||
#if defined(__AVX512F__)
|
||||
__m512i state[ARGON2_512BIT_WORDS_IN_BLOCK];
|
||||
#elif defined(__AVX2__)
|
||||
__m256i state[ARGON2_HWORDS_IN_BLOCK];
|
||||
#else
|
||||
__m128i state[ARGON2_OWORDS_IN_BLOCK];
|
||||
#endif
|
||||
int data_independent_addressing;
|
||||
|
||||
if (instance == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
data_independent_addressing =
|
||||
(instance->type == Argon2_i) ||
|
||||
(instance->type == Argon2_id && (position.pass == 0) &&
|
||||
(position.slice < ARGON2_SYNC_POINTS / 2));
|
||||
|
||||
if (data_independent_addressing) {
|
||||
init_block_value(&input_block, 0);
|
||||
|
||||
input_block.v[0] = position.pass;
|
||||
input_block.v[1] = position.lane;
|
||||
input_block.v[2] = position.slice;
|
||||
input_block.v[3] = instance->memory_blocks;
|
||||
input_block.v[4] = instance->passes;
|
||||
input_block.v[5] = instance->type;
|
||||
}
|
||||
|
||||
starting_index = 0;
|
||||
|
||||
if ((0 == position.pass) && (0 == position.slice)) {
|
||||
starting_index = 2; /* we have already generated the first two blocks */
|
||||
|
||||
/* Don't forget to generate the first block of addresses: */
|
||||
if (data_independent_addressing) {
|
||||
next_addresses(&address_block, &input_block);
|
||||
}
|
||||
}
|
||||
|
||||
/* Offset of the current block */
|
||||
curr_offset = position.lane * instance->lane_length +
|
||||
position.slice * instance->segment_length + starting_index;
|
||||
|
||||
if (0 == curr_offset % instance->lane_length) {
|
||||
/* Last block in this lane */
|
||||
prev_offset = curr_offset + instance->lane_length - 1;
|
||||
} else {
|
||||
/* Previous block */
|
||||
prev_offset = curr_offset - 1;
|
||||
}
|
||||
|
||||
memcpy(state, ((instance->memory + prev_offset)->v), ARGON2_BLOCK_SIZE);
|
||||
|
||||
for (i = starting_index; i < instance->segment_length;
|
||||
++i, ++curr_offset, ++prev_offset) {
|
||||
/*1.1 Rotating prev_offset if needed */
|
||||
if (curr_offset % instance->lane_length == 1) {
|
||||
prev_offset = curr_offset - 1;
|
||||
}
|
||||
|
||||
/* 1.2 Computing the index of the reference block */
|
||||
/* 1.2.1 Taking pseudo-random value from the previous block */
|
||||
if (data_independent_addressing) {
|
||||
if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
|
||||
next_addresses(&address_block, &input_block);
|
||||
}
|
||||
pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
|
||||
} else {
|
||||
pseudo_rand = instance->memory[prev_offset].v[0];
|
||||
}
|
||||
|
||||
/* 1.2.2 Computing the lane of the reference block */
|
||||
ref_lane = ((pseudo_rand >> 32)) % instance->lanes;
|
||||
|
||||
if ((position.pass == 0) && (position.slice == 0)) {
|
||||
/* Can not reference other lanes yet */
|
||||
ref_lane = position.lane;
|
||||
}
|
||||
|
||||
/* 1.2.3 Computing the number of possible reference block within the
|
||||
* lane.
|
||||
*/
|
||||
position.index = i;
|
||||
ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
|
||||
ref_lane == position.lane);
|
||||
|
||||
/* 2 Creating a new block */
|
||||
ref_block =
|
||||
instance->memory + instance->lane_length * ref_lane + ref_index;
|
||||
curr_block = instance->memory + curr_offset;
|
||||
if (ARGON2_VERSION_10 == instance->version) {
|
||||
/* version 1.2.1 and earlier: overwrite, not XOR */
|
||||
fill_block(state, ref_block, curr_block, 0);
|
||||
} else {
|
||||
if(0 == position.pass) {
|
||||
fill_block(state, ref_block, curr_block, 0);
|
||||
} else {
|
||||
fill_block(state, ref_block, curr_block, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
78
lib/crypto_backend/cipher_generic.c
Normal file
78
lib/crypto_backend/cipher_generic.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Linux kernel cipher generic utilities
|
||||
*
|
||||
* Copyright (C) 2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018, Milan Broz
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include "crypto_backend.h"
|
||||
|
||||
struct cipher_alg {
|
||||
const char *name;
|
||||
int blocksize;
|
||||
bool wrapped_key;
|
||||
};
|
||||
|
||||
/* FIXME: Getting block size should be dynamic from cipher backend. */
|
||||
static const struct cipher_alg cipher_algs[] = {
|
||||
{ "cipher_null", 16, false },
|
||||
{ "aes", 16, false },
|
||||
{ "serpent", 16, false },
|
||||
{ "twofish", 16, false },
|
||||
{ "anubis", 16, false },
|
||||
{ "blowfish", 8, false },
|
||||
{ "camellia", 16, false },
|
||||
{ "cast5", 8, false },
|
||||
{ "cast6", 16, false },
|
||||
{ "des", 8, false },
|
||||
{ "des3_ede", 8, false },
|
||||
{ "khazad", 8, false },
|
||||
{ "seed", 16, false },
|
||||
{ "tea", 8, false },
|
||||
{ "xtea", 8, false },
|
||||
{ "paes", 16, true }, /* protected AES, s390 wrapped key scheme */
|
||||
{ NULL, 0, false }
|
||||
};
|
||||
|
||||
static const struct cipher_alg *_get_alg(const char *name)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (name && cipher_algs[i].name) {
|
||||
if (!strcasecmp(name, cipher_algs[i].name))
|
||||
return &cipher_algs[i];
|
||||
i++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int crypt_cipher_blocksize(const char *name)
|
||||
{
|
||||
const struct cipher_alg *ca = _get_alg(name);
|
||||
|
||||
return ca ? ca->blocksize : -EINVAL;
|
||||
}
|
||||
|
||||
int crypt_cipher_wrapped_key(const char *name)
|
||||
{
|
||||
const struct cipher_alg *ca = _get_alg(name);
|
||||
|
||||
return ca ? (int)ca->wrapped_key : 0;
|
||||
}
|
||||
@@ -100,6 +100,7 @@ uint32_t crypt_crc32(uint32_t seed, const unsigned char *buf, size_t len);
|
||||
|
||||
/* ciphers */
|
||||
int crypt_cipher_blocksize(const char *name);
|
||||
int crypt_cipher_wrapped_key(const char *name);
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length);
|
||||
void crypt_cipher_destroy(struct crypt_cipher *ctx);
|
||||
@@ -123,8 +124,12 @@ int crypt_storage_encrypt(struct crypt_storage *ctx, uint64_t sector,
|
||||
/* Memzero helper (memset on stack can be optimized out) */
|
||||
static inline void crypt_backend_memzero(void *s, size_t n)
|
||||
{
|
||||
#ifdef HAVE_EXPLICIT_BZERO
|
||||
explicit_bzero(s, n);
|
||||
#else
|
||||
volatile uint8_t *p = (volatile uint8_t *)s;
|
||||
while(n--) *p++ = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* _CRYPTO_BACKEND_H */
|
||||
|
||||
@@ -44,56 +44,12 @@ struct crypt_cipher {
|
||||
int opfd;
|
||||
};
|
||||
|
||||
struct cipher_alg {
|
||||
const char *name;
|
||||
int blocksize;
|
||||
};
|
||||
|
||||
/* FIXME: Getting block size should be dynamic from cipher backend. */
|
||||
static struct cipher_alg cipher_algs[] = {
|
||||
{ "cipher_null", 16 },
|
||||
{ "aes", 16 },
|
||||
{ "serpent", 16 },
|
||||
{ "twofish", 16 },
|
||||
{ "anubis", 16 },
|
||||
{ "blowfish", 8 },
|
||||
{ "camellia", 16 },
|
||||
{ "cast5", 8 },
|
||||
{ "cast6", 16 },
|
||||
{ "des", 8 },
|
||||
{ "des3_ede", 8 },
|
||||
{ "khazad", 8 },
|
||||
{ "seed", 16 },
|
||||
{ "tea", 8 },
|
||||
{ "xtea", 8 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static struct cipher_alg *_get_alg(const char *name)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (name && cipher_algs[i].name) {
|
||||
if (!strcasecmp(name, cipher_algs[i].name))
|
||||
return &cipher_algs[i];
|
||||
i++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int crypt_cipher_blocksize(const char *name)
|
||||
{
|
||||
struct cipher_alg *ca = _get_alg(name);
|
||||
|
||||
return ca ? ca->blocksize : -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ciphers
|
||||
*
|
||||
* ENOENT - algorithm not available
|
||||
* ENOTSUP - AF_ALG family not available
|
||||
* (but cannot check specificaly for skcipher API)
|
||||
* (but cannot check specifically for skcipher API)
|
||||
*/
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *key, size_t key_length)
|
||||
@@ -236,12 +192,6 @@ void crypt_cipher_destroy(struct crypt_cipher *ctx)
|
||||
}
|
||||
|
||||
#else /* ENABLE_AF_ALG */
|
||||
|
||||
int crypt_cipher_blocksize(const char *name)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
|
||||
const char *mode, const void *buffer, size_t length)
|
||||
{
|
||||
|
||||
@@ -50,9 +50,11 @@ struct crypt_hmac {
|
||||
};
|
||||
|
||||
/*
|
||||
* Compatible wrappers for OpenSSL < 1.1.0
|
||||
* Compatible wrappers for OpenSSL < 1.1.0 and LibreSSL < 2.7.0
|
||||
*/
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
|
||||
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
|
||||
|
||||
static void openssl_backend_init(void)
|
||||
{
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
@@ -42,7 +42,7 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
|
||||
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) {
|
||||
(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;
|
||||
@@ -50,6 +50,8 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
|
||||
sb->integrity_tag_size = le16toh(sb->integrity_tag_size);
|
||||
sb->journal_sections = le32toh(sb->journal_sections);
|
||||
sb->provided_data_sectors = le64toh(sb->provided_data_sectors);
|
||||
sb->recalc_sector = le64toh(sb->recalc_sector);
|
||||
sb->flags = le32toh(sb->flags);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
@@ -82,11 +84,17 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
|
||||
return r;
|
||||
|
||||
log_std(cd, "Info for integrity device %s.\n", device_path(device));
|
||||
log_std(cd, "superblock_version %d\n", (unsigned)sb.version);
|
||||
log_std(cd, "log2_interleave_sectors %d\n", sb.log2_interleave_sectors);
|
||||
log_std(cd, "integrity_tag_size %u\n", sb.integrity_tag_size);
|
||||
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))
|
||||
log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
|
||||
log_std(cd, "flags %s%s\n",
|
||||
sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
|
||||
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -106,16 +114,16 @@ int INTEGRITY_data_sectors(struct crypt_device *cd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int INTEGRITY_key_size(struct crypt_device *cd)
|
||||
int INTEGRITY_key_size(struct crypt_device *cd, const char *integrity)
|
||||
{
|
||||
const char *integrity = crypt_get_integrity(cd);
|
||||
|
||||
if (!integrity)
|
||||
return 0;
|
||||
|
||||
//FIXME: use crypto backend hash size
|
||||
if (!strcmp(integrity, "aead"))
|
||||
return 0;
|
||||
else if (!strcmp(integrity, "hmac(sha1)"))
|
||||
return 20;
|
||||
else if (!strcmp(integrity, "hmac(sha256)"))
|
||||
return 32;
|
||||
else if (!strcmp(integrity, "hmac(sha512)"))
|
||||
@@ -145,6 +153,8 @@ int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||
iv_tag_size = 8;
|
||||
else if (!strcmp(cipher_mode, "ctr-random"))
|
||||
iv_tag_size = 16;
|
||||
else if (!strcmp(cipher, "aegis256") && !strcmp(cipher_mode, "random"))
|
||||
iv_tag_size = 32;
|
||||
else if (!strcmp(cipher_mode, "random"))
|
||||
iv_tag_size = 16;
|
||||
|
||||
@@ -155,6 +165,8 @@ int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||
auth_tag_size = 16; //FIXME gcm- mode only
|
||||
else if (!strcmp(integrity, "cmac(aes)"))
|
||||
auth_tag_size = 16;
|
||||
else if (!strcmp(integrity, "hmac(sha1)"))
|
||||
auth_tag_size = 20;
|
||||
else if (!strcmp(integrity, "hmac(sha256)"))
|
||||
auth_tag_size = 32;
|
||||
else if (!strcmp(integrity, "hmac(sha512)"))
|
||||
@@ -218,7 +230,7 @@ int INTEGRITY_activate(struct crypt_device *cd,
|
||||
|
||||
r = dm_create_device(cd, name, "INTEGRITY", &dmdi, 0);
|
||||
if (r < 0 && (dm_flags(DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
|
||||
log_err(cd, _("Kernel doesn't support dm-integrity mapping.\n"));
|
||||
log_err(cd, _("Kernel doesn't support dm-integrity mapping."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -269,7 +281,7 @@ int INTEGRITY_format(struct crypt_device *cd,
|
||||
|
||||
r = device_block_adjust(cd, dmdi.data_device, DEV_EXCL, dmdi.u.integrity.offset, NULL, NULL);
|
||||
if (r < 0 && (dm_flags(DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
|
||||
log_err(cd, _("Kernel doesn't support dm-integrity mapping.\n"));
|
||||
log_err(cd, _("Kernel doesn't support dm-integrity mapping."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if (r)
|
||||
|
||||
@@ -30,7 +30,11 @@ struct volume_key;
|
||||
|
||||
/* dm-integrity helper */
|
||||
#define SB_MAGIC "integrt"
|
||||
#define SB_VERSION 1
|
||||
#define SB_VERSION_1 1
|
||||
#define SB_VERSION_2 2
|
||||
|
||||
#define SB_FLAG_HAVE_JOURNAL_MAC (1 << 0)
|
||||
#define SB_FLAG_RECALCULATING (1 << 1) /* V2 only */
|
||||
|
||||
struct superblock {
|
||||
uint8_t magic[8];
|
||||
@@ -41,6 +45,8 @@ struct superblock {
|
||||
uint64_t provided_data_sectors;
|
||||
uint32_t flags;
|
||||
uint8_t log2_sectors_per_block;
|
||||
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);
|
||||
@@ -50,7 +56,8 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
|
||||
int INTEGRITY_data_sectors(struct crypt_device *cd,
|
||||
struct device *device, uint64_t offset,
|
||||
uint64_t *data_sectors);
|
||||
int INTEGRITY_key_size(struct crypt_device *cd);
|
||||
int INTEGRITY_key_size(struct crypt_device *cd,
|
||||
const char *integrity);
|
||||
int INTEGRITY_tag_size(struct crypt_device *cd,
|
||||
const char *integrity,
|
||||
const char *cipher,
|
||||
|
||||
@@ -32,11 +32,13 @@
|
||||
|
||||
#include "nls.h"
|
||||
#include "bitops.h"
|
||||
#include "utils_blkid.h"
|
||||
#include "utils_crypt.h"
|
||||
#include "utils_loop.h"
|
||||
#include "utils_dm.h"
|
||||
#include "utils_fips.h"
|
||||
#include "utils_keyring.h"
|
||||
#include "utils_io.h"
|
||||
#include "crypto_backend.h"
|
||||
|
||||
#include "libcryptsetup.h"
|
||||
@@ -44,15 +46,25 @@
|
||||
/* to silent gcc -Wcast-qual for const cast */
|
||||
#define CONST_CAST(x) (x)(uintptr_t)
|
||||
|
||||
#define SHIFT_4K 12
|
||||
#define SECTOR_SHIFT 9
|
||||
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
|
||||
#define MAX_SECTOR_SIZE 4096 /* min page size among all platforms */
|
||||
#define DEFAULT_DISK_ALIGNMENT 1048576 /* 1MiB */
|
||||
#define DEFAULT_MEM_ALIGNMENT 4096
|
||||
#define MAX_ERROR_LENGTH 512
|
||||
#define LOG_MAX_LEN 4096
|
||||
|
||||
#define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); })
|
||||
|
||||
#define MISALIGNED(a, b) ((a) & ((b) - 1))
|
||||
#define MISALIGNED_4K(a) MISALIGNED((a), 1 << SHIFT_4K)
|
||||
#define MISALIGNED_512(a) MISALIGNED((a), 1 << SECTOR_SHIFT)
|
||||
#define NOTPOW2(a) MISALIGNED((a), (a))
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
struct crypt_device;
|
||||
|
||||
struct volume_key {
|
||||
@@ -98,6 +110,7 @@ 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 device *device, int devfd);
|
||||
|
||||
int device_open_locked(struct device *device, int flags);
|
||||
int device_read_lock(struct crypt_device *cd, struct device *device);
|
||||
@@ -132,20 +145,13 @@ uint64_t crypt_dev_partition_offset(const char *dev_path);
|
||||
int lookup_by_disk_id(const char *dm_uuid);
|
||||
int lookup_by_sysfs_uuid_field(const char *dm_uuid, size_t max_len);
|
||||
|
||||
ssize_t write_buffer(int fd, const void *buf, size_t count);
|
||||
ssize_t read_buffer(int fd, void *buf, size_t count);
|
||||
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment, void *orig_buf, size_t count);
|
||||
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count);
|
||||
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count, off_t offset);
|
||||
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count, off_t offset);
|
||||
|
||||
size_t crypt_getpagesize(void);
|
||||
unsigned crypt_cpusonline(void);
|
||||
uint64_t crypt_getphysmemory_kb(void);
|
||||
|
||||
int init_crypto(struct crypt_device *ctx);
|
||||
|
||||
void logger(struct crypt_device *cd, int class, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
|
||||
void logger(struct crypt_device *cd, int level, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
|
||||
#define log_dbg(x...) logger(NULL, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
|
||||
#define log_std(c, x...) logger(c, CRYPT_LOG_NORMAL, __FILE__, __LINE__, x)
|
||||
#define log_verbose(c, x...) logger(c, CRYPT_LOG_VERBOSE, __FILE__, __LINE__, x)
|
||||
|
||||
@@ -247,7 +247,18 @@ int crypt_set_pbkdf_type(struct crypt_device *cd,
|
||||
const struct crypt_pbkdf_type *pbkdf);
|
||||
|
||||
/**
|
||||
* Get current default PBKDF (Password-Based Key Derivation Algorithm) for keyslots.
|
||||
* Get default PBKDF (Password-Based Key Derivation Algorithm) settings for keyslots.
|
||||
* Works only with LUKS device handles (both versions).
|
||||
*
|
||||
* @param type type of device (see @link crypt-type @endlink)
|
||||
*
|
||||
* @return struct on success or NULL value otherwise.
|
||||
*
|
||||
*/
|
||||
const struct crypt_pbkdf_type *crypt_get_pbkdf_default(const char *type);
|
||||
|
||||
/**
|
||||
* Get current PBKDF (Password-Based Key Derivation Algorithm) settings for keyslots.
|
||||
* Works only with LUKS device handles (both versions).
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
@@ -357,7 +368,7 @@ struct crypt_params_plain {
|
||||
*/
|
||||
struct crypt_params_luks1 {
|
||||
const char *hash; /**< hash used in LUKS header */
|
||||
size_t data_alignment; /**< data alignment in sectors, data offset is multiple of this */
|
||||
size_t data_alignment; /**< data area alignment in 512B sectors, data offset is multiple of this */
|
||||
const char *data_device; /**< detached encrypted data device or @e NULL */
|
||||
};
|
||||
|
||||
@@ -479,7 +490,7 @@ struct crypt_params_luks2 {
|
||||
const struct crypt_pbkdf_type *pbkdf; /**< PBKDF (and hash) parameters or @e NULL*/
|
||||
const char *integrity; /**< integrity algorithm or @e NULL */
|
||||
const struct crypt_params_integrity *integrity_params; /**< Data integrity parameters or @e NULL*/
|
||||
size_t data_alignment; /**< data alignment in sectors, data offset is multiple of this */
|
||||
size_t data_alignment; /**< data area alignment in 512B sectors, data offset is multiple of this */
|
||||
const char *data_device; /**< detached encrypted data device or @e NULL */
|
||||
uint32_t sector_size; /**< encryption sector size */
|
||||
const char *label; /**< header label or @e NULL*/
|
||||
@@ -535,8 +546,8 @@ int crypt_format(struct crypt_device *cd,
|
||||
*
|
||||
* @note Currently, only LUKS1->LUKS2 and LUKS2->LUKS1 conversions are supported.
|
||||
* Not all LUKS2 devices may be converted back to LUKS1. To make such a conversion
|
||||
* posible all active LUKS2 keyslots must be in LUKS1 compatible mode (i.e. pbkdf
|
||||
* type must be PBKDF2) and device cannot be formated with any authenticated
|
||||
* possible all active LUKS2 keyslots must be in LUKS1 compatible mode (i.e. pbkdf
|
||||
* type must be PBKDF2) and device cannot be formatted with any authenticated
|
||||
* encryption mode.
|
||||
*
|
||||
* @note Device must be offline for conversion. UUID change is not possible for active
|
||||
@@ -613,7 +624,7 @@ int crypt_load(struct crypt_device *cd,
|
||||
void *params);
|
||||
|
||||
/**
|
||||
* Try to repair crypt device LUKS1 on-disk header if invalid.
|
||||
* Try to repair crypt device LUKS on-disk header if invalid.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param requested_type @link crypt-type @endlink or @e NULL for all known
|
||||
@@ -621,9 +632,11 @@ int crypt_load(struct crypt_device *cd,
|
||||
*
|
||||
* @returns 0 on success or negative errno value otherwise.
|
||||
*
|
||||
* @note Does not support LUKS2 devices explicitly. LUKS2 header is auto-repaired
|
||||
* (if exactly one header checksum does not match) automatically on
|
||||
* crypt_load().
|
||||
* @note For LUKS2 device crypt_repair bypass blkid checks and
|
||||
* perform auto-recovery even though there're third party device
|
||||
* signatures found by blkid probes. Currently the crypt_repair on LUKS2
|
||||
* works only if exactly one header checksum does not match or exactly
|
||||
* one header is missing.
|
||||
*/
|
||||
int crypt_repair(struct crypt_device *cd,
|
||||
const char *requested_type,
|
||||
@@ -851,6 +864,9 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
|
||||
/** create keyslot with volume key not associated with current dm-crypt segment */
|
||||
#define CRYPT_VOLUME_KEY_NO_SEGMENT (1 << 0)
|
||||
|
||||
/** create keyslot with new volume key and assign it to current dm-crypt segment */
|
||||
#define CRYPT_VOLUME_KEY_SET (1 << 1)
|
||||
|
||||
/**
|
||||
* Add key slot using provided key.
|
||||
*
|
||||
@@ -867,10 +883,18 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
|
||||
* @return allocated key slot number or negative errno otherwise.
|
||||
*
|
||||
* @note in case volume_key is @e NULL following first matching rule will apply:
|
||||
* a) if cd is device handle used in crypt_format() by current process, the volume
|
||||
* key generated (passed) to crypt_format() will be stored in keyslot.
|
||||
* b) if CRYPT_VOLUME_KEY_NO_SEGMENT flag is raised the new volume_key will be
|
||||
* generated and stored in keyslot.
|
||||
* @li if cd is device handle used in crypt_format() by current process, the volume
|
||||
* key generated (or passed) in crypt_format() will be stored in keyslot.
|
||||
* @li if CRYPT_VOLUME_KEY_NO_SEGMENT flag is raised the new volume_key will be
|
||||
* generated and stored in keyslot. The keyslot will become unbound (unusable to
|
||||
* dm-crypt device activation).
|
||||
* @li fails with -EINVAL otherwise
|
||||
*
|
||||
* @warning CRYPT_VOLUME_KEY_SET flag force updates volume key. It is @b not @b reencryption!
|
||||
* By doing so you will most probably destroy your ciphertext data device. It's supposed
|
||||
* to be used only in wrapped keys scheme for key refresh process where real (inner) volume
|
||||
* key stays untouched. It may be involed on active @e keyslot which makes the (previously
|
||||
* unbound) keyslot new regular keyslot.
|
||||
*/
|
||||
int crypt_keyslot_add_by_key(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
@@ -932,6 +956,10 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
|
||||
#define CRYPT_ACTIVATE_RECOVERY (1 << 13)
|
||||
/** ignore persistently stored flags */
|
||||
#define CRYPT_ACTIVATE_IGNORE_PERSISTENT (1 << 14)
|
||||
/** dm-verity: check_at_most_once - check data blocks only the first time */
|
||||
#define CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE (1 << 15)
|
||||
/** allow activation check including unbound keyslots (keyslots without segments) */
|
||||
#define CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY (1 << 16)
|
||||
|
||||
/**
|
||||
* Active device runtime attributes
|
||||
@@ -954,8 +982,20 @@ struct crypt_active_device {
|
||||
*
|
||||
*/
|
||||
int crypt_get_active_device(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct crypt_active_device *cad);
|
||||
const char *name,
|
||||
struct crypt_active_device *cad);
|
||||
|
||||
/**
|
||||
* Get detected number of integrity failures.
|
||||
*
|
||||
* @param cd crypt device handle (can be @e NULL)
|
||||
* @param name name of active device
|
||||
*
|
||||
* @return number of integrity failures or @e 0 otherwise
|
||||
*
|
||||
*/
|
||||
uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd,
|
||||
const char *name);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@@ -996,7 +1036,7 @@ typedef enum {
|
||||
* stored persistently.
|
||||
*
|
||||
* @note Only requirements flags recognised by current library may be set.
|
||||
* CRYPT_REQUIREMENT_FLAG is illegal (output only) in set operation.
|
||||
* CRYPT_REQUIREMENT_UNKNOWN is illegal (output only) in set operation.
|
||||
*/
|
||||
int crypt_persistent_flags_set(struct crypt_device *cd,
|
||||
crypt_flags_type type,
|
||||
@@ -1413,8 +1453,10 @@ typedef enum {
|
||||
CRYPT_SLOT_INVALID, /**< invalid keyslot */
|
||||
CRYPT_SLOT_INACTIVE, /**< keyslot is inactive (free) */
|
||||
CRYPT_SLOT_ACTIVE, /**< keyslot is active (used) */
|
||||
CRYPT_SLOT_ACTIVE_LAST /**< keylost is active (used)
|
||||
CRYPT_SLOT_ACTIVE_LAST,/**< keylost is active (used)
|
||||
* and last used at the same time */
|
||||
CRYPT_SLOT_UNBOUND /**< keyslot is active and not bound
|
||||
* to any crypt segment (LUKS2 only) */
|
||||
} crypt_keyslot_info;
|
||||
|
||||
/**
|
||||
@@ -1485,6 +1527,18 @@ int crypt_keyslot_area(struct crypt_device *cd,
|
||||
uint64_t *offset,
|
||||
uint64_t *length);
|
||||
|
||||
/**
|
||||
* Get size (in bytes) of key for particular keyslot.
|
||||
* Use for LUKS2 unbound keyslots, for other keyslots it is the same as @ref crypt_get_volume_key_size
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param keyslot keyslot number
|
||||
*
|
||||
* @return volume key size or negative errno value otherwise.
|
||||
*
|
||||
*/
|
||||
int crypt_keyslot_get_key_size(struct crypt_device *cd, int keyslot);
|
||||
|
||||
/**
|
||||
* Get directory where mapped crypt devices are created
|
||||
*
|
||||
@@ -1562,17 +1616,20 @@ void crypt_set_debug_level(int level);
|
||||
* @param keyfile keyfile to read
|
||||
* @param key buffer for key
|
||||
* @param key_size_read size of read key
|
||||
* @param keyfile_offset keyfile offset
|
||||
* @param keyfile_size_max maximal size of keyfile to read
|
||||
* @param keyfile_offset key offset in keyfile
|
||||
* @param key_size exact key length to read from file or 0
|
||||
* @param flags keyfile read flags
|
||||
*
|
||||
* @return @e 0 on success or negative errno value otherwise.
|
||||
*
|
||||
* @note If key_size is set to zero we read internal max length
|
||||
* and actual size read is returned via key_size_read parameter.
|
||||
*/
|
||||
int crypt_keyfile_device_read(struct crypt_device *cd,
|
||||
const char *keyfile,
|
||||
char **key, size_t *key_size_read,
|
||||
uint64_t keyfile_offset,
|
||||
size_t keyfile_size_max,
|
||||
size_t key_size,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
@@ -1582,7 +1639,7 @@ int crypt_keyfile_read(struct crypt_device *cd,
|
||||
const char *keyfile,
|
||||
char **key, size_t *key_size_read,
|
||||
size_t keyfile_offset,
|
||||
size_t keyfile_size_max,
|
||||
size_t key_size,
|
||||
uint32_t flags);
|
||||
|
||||
/** Read key only to the first end of line (\\n). */
|
||||
@@ -1829,7 +1886,7 @@ typedef void (*crypt_token_buffer_free_func) (void *buffer, size_t buffer_len);
|
||||
|
||||
/**
|
||||
* Token handler validate function prototype.
|
||||
* This fuction validates JSON representation of user defined token for additional data
|
||||
* This function validates JSON representation of user defined token for additional data
|
||||
* specific for its token type. If defined in the handler, it's called
|
||||
* during @link crypt_activate_by_token @endlink. It may also be called during
|
||||
* @link crypt_token_json_set @endlink when appropriate token handler was registered before
|
||||
@@ -1842,7 +1899,7 @@ typedef int (*crypt_token_validate_func) (struct crypt_device *cd, const char *j
|
||||
|
||||
/**
|
||||
* Token handler dump function prototype.
|
||||
* This fuction is supposed to print token implementation specific details. It gets
|
||||
* This function is supposed to print token implementation specific details. It gets
|
||||
* called during @link crypt_dump @endlink if token handler was registered before.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
|
||||
@@ -77,6 +77,7 @@ CRYPTSETUP_2.0 {
|
||||
|
||||
crypt_get_type;
|
||||
crypt_get_active_device;
|
||||
crypt_get_active_integrity_failures;
|
||||
crypt_persistent_flags_set;
|
||||
crypt_persistent_flags_get;
|
||||
|
||||
@@ -84,10 +85,12 @@ CRYPTSETUP_2.0 {
|
||||
crypt_get_rng_type;
|
||||
crypt_set_pbkdf_type;
|
||||
crypt_get_pbkdf_type;
|
||||
crypt_get_pbkdf_default;
|
||||
|
||||
crypt_keyslot_max;
|
||||
crypt_keyslot_area;
|
||||
crypt_keyslot_status;
|
||||
crypt_keyslot_get_key_size;
|
||||
crypt_get_dir;
|
||||
crypt_set_debug_level;
|
||||
crypt_log;
|
||||
|
||||
@@ -96,7 +96,6 @@ static void set_dm_error(int level,
|
||||
if (vasprintf(&msg, f, va) > 0) {
|
||||
if (level < 4 && !_quiet_log) {
|
||||
log_err(_context, "%s", msg);
|
||||
log_err(_context, "\n");
|
||||
} else {
|
||||
/* We do not use DM visual stack backtrace here */
|
||||
if (strncmp(msg, "<backtrace>", 11))
|
||||
@@ -185,6 +184,7 @@ static void _dm_set_verity_compat(unsigned verity_maj,
|
||||
* ignore_zero_blocks since 1.3 (kernel 4.5)
|
||||
* (but some dm-verity targets 1.2 don't support it)
|
||||
* FEC is added in 1.3 as well.
|
||||
* Check at most once is added in 1.4 (kernel 4.17).
|
||||
*/
|
||||
if (_dm_satisfies_version(1, 3, 0, verity_maj, verity_min, verity_patch)) {
|
||||
_dm_flags |= DM_VERITY_ON_CORRUPTION_SUPPORTED;
|
||||
@@ -329,10 +329,10 @@ static int dm_init_context(struct crypt_device *cd, dm_target_type target)
|
||||
if (!_dm_check_versions(target)) {
|
||||
if (getuid() || geteuid())
|
||||
log_err(cd, _("Cannot initialize device-mapper, "
|
||||
"running as non-root user.\n"));
|
||||
"running as non-root user."));
|
||||
else
|
||||
log_err(cd, _("Cannot initialize device-mapper. "
|
||||
"Is dm_mod kernel module loaded?\n"));
|
||||
"Is dm_mod kernel module loaded?"));
|
||||
_context = NULL;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
@@ -376,15 +376,12 @@ static void hex_key(char *hexkey, size_t key_size, const char *key)
|
||||
sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]);
|
||||
}
|
||||
|
||||
/* get string length for key_size written in decimal system */
|
||||
static size_t get_key_size_strlen(size_t key_size)
|
||||
static size_t int_log10(size_t x)
|
||||
{
|
||||
size_t ret = 1;
|
||||
|
||||
while ((key_size /= 10))
|
||||
ret++;
|
||||
|
||||
return ret;
|
||||
size_t r = 0;
|
||||
for (x /= 10; x > 0; x /= 10)
|
||||
r++;
|
||||
return r;
|
||||
}
|
||||
|
||||
#define CLEN 64 /* 2*MAX_CIPHER_LEN */
|
||||
@@ -397,7 +394,7 @@ static int cipher_c2dm(const char *org_c, const char *org_i, unsigned tag_size,
|
||||
char *i_dm, int i_dm_size)
|
||||
{
|
||||
int c_size = 0, i_size = 0, i;
|
||||
char cipher[CLEN], mode[CLEN], iv[CLEN], tmp[CLEN];
|
||||
char cipher[CLEN], mode[CLEN], iv[CLEN+1], tmp[CLEN];
|
||||
char capi[CAPIL];
|
||||
|
||||
if (!c_dm || !c_dm_size || !i_dm || !i_dm_size)
|
||||
@@ -410,7 +407,7 @@ static int cipher_c2dm(const char *org_c, const char *org_i, unsigned tag_size,
|
||||
i = sscanf(tmp, "%" CLENS "[^-]-%" CLENS "s", mode, iv);
|
||||
if (i == 1) {
|
||||
memset(iv, 0, sizeof(iv));
|
||||
strncpy(iv, mode, sizeof(iv) - 1);
|
||||
strncpy(iv, mode, sizeof(iv)-1);
|
||||
*mode = '\0';
|
||||
if (snprintf(capi, sizeof(capi), "%s", cipher) < 0)
|
||||
return -EINVAL;
|
||||
@@ -457,7 +454,7 @@ static int cipher_c2dm(const char *org_c, const char *org_i, unsigned tag_size,
|
||||
static int cipher_dm2c(char **org_c, char **org_i, const char *c_dm, const char *i_dm)
|
||||
{
|
||||
char cipher[CLEN], mode[CLEN], iv[CLEN], auth[CLEN];
|
||||
char tmp[CAPIL*2], capi[CAPIL];
|
||||
char tmp[CAPIL], dmcrypt_tmp[CAPIL*2], capi[CAPIL+1];
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
@@ -500,16 +497,16 @@ static int cipher_dm2c(char **org_c, char **org_i, const char *c_dm, const char
|
||||
} else
|
||||
*org_i = NULL;
|
||||
memset(capi, 0, sizeof(capi));
|
||||
strncpy(capi, tmp, sizeof(capi) - 1);
|
||||
strncpy(capi, tmp, sizeof(capi)-1);
|
||||
}
|
||||
|
||||
i = sscanf(capi, "%" CLENS "[^(](%" CLENS "[^)])", mode, cipher);
|
||||
if (i == 2)
|
||||
snprintf(tmp, sizeof(tmp), "%s-%s-%s", cipher, mode, iv);
|
||||
snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s-%s", cipher, mode, iv);
|
||||
else
|
||||
snprintf(tmp, sizeof(tmp), "%s-%s", capi, iv);
|
||||
snprintf(dmcrypt_tmp, sizeof(dmcrypt_tmp), "%s-%s", capi, iv);
|
||||
|
||||
if (!(*org_c = strdup(tmp))) {
|
||||
if (!(*org_c = strdup(dmcrypt_tmp))) {
|
||||
free(*org_i);
|
||||
*org_i = NULL;
|
||||
return -ENOMEM;
|
||||
@@ -561,7 +558,7 @@ static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd, uint32_t fl
|
||||
null_cipher = 1;
|
||||
|
||||
if (flags & CRYPT_ACTIVATE_KEYRING_KEY) {
|
||||
keystr_len = strlen(dmd->u.crypt.vk->key_description) + get_key_size_strlen(dmd->u.crypt.vk->keylength) + 9;
|
||||
keystr_len = strlen(dmd->u.crypt.vk->key_description) + int_log10(dmd->u.crypt.vk->keylength) + 10;
|
||||
hexkey = crypt_safe_alloc(keystr_len);
|
||||
} else
|
||||
hexkey = crypt_safe_alloc(null_cipher ? 2 : (dmd->u.crypt.vk->keylength * 2 + 1));
|
||||
@@ -622,6 +619,8 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp,
|
||||
num_options++;
|
||||
if (flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS)
|
||||
num_options++;
|
||||
if (flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE)
|
||||
num_options++;
|
||||
|
||||
if (dmd->u.verity.fec_device) {
|
||||
num_options += 8;
|
||||
@@ -633,10 +632,11 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp,
|
||||
*fec_features = '\0';
|
||||
|
||||
if (num_options)
|
||||
snprintf(features, sizeof(features)-1, " %d%s%s%s", num_options,
|
||||
snprintf(features, sizeof(features)-1, " %d%s%s%s%s", num_options,
|
||||
(flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? " ignore_corruption" : "",
|
||||
(flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) ? " restart_on_corruption" : "",
|
||||
(flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? " ignore_zero_blocks" : "");
|
||||
(flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? " ignore_zero_blocks" : "",
|
||||
(flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) ? " check_at_most_once" : "");
|
||||
else
|
||||
*features = '\0';
|
||||
|
||||
@@ -684,7 +684,7 @@ static char *get_dm_integrity_params(struct crypt_dm_active_device *dmd, uint32_
|
||||
{
|
||||
int r, max_size, num_options = 0;
|
||||
char *params, *hexkey, mode;
|
||||
char features[256], feature[256];
|
||||
char features[512], feature[256];
|
||||
|
||||
if (!dmd)
|
||||
return NULL;
|
||||
@@ -932,7 +932,7 @@ int dm_remove_device(struct crypt_device *cd, const char *name, uint32_t flags)
|
||||
|
||||
dm_flags(DM_UNKNOWN, &dmt_flags);
|
||||
if (deferred && !(dmt_flags & DM_DEFERRED_SUPPORTED)) {
|
||||
log_err(cd, _("Requested deferred flag is not supported.\n"));
|
||||
log_err(cd, _("Requested deferred flag is not supported."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -997,7 +997,7 @@ static int dm_prepare_uuid(const char *name, const char *type, const char *uuid,
|
||||
|
||||
log_dbg("DM-UUID is %s", buf);
|
||||
if (i >= buflen)
|
||||
log_err(NULL, _("DM-UUID for device %s was truncated.\n"), name);
|
||||
log_err(NULL, _("DM-UUID for device %s was truncated."), name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1217,23 +1217,24 @@ int dm_create_device(struct crypt_device *cd, const char *name,
|
||||
if (r == -EINVAL &&
|
||||
dmd_flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT|CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) &&
|
||||
!(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED|DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED)))
|
||||
log_err(cd, _("Requested dm-crypt performance options are not supported.\n"));
|
||||
log_err(cd, _("Requested dm-crypt performance options are not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd_flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION|
|
||||
CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|
|
||||
CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) &&
|
||||
CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS|
|
||||
CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) &&
|
||||
!(dmt_flags & DM_VERITY_ON_CORRUPTION_SUPPORTED))
|
||||
log_err(cd, _("Requested dm-verity data corruption handling options are not supported.\n"));
|
||||
log_err(cd, _("Requested dm-verity data corruption handling options are not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->target == DM_VERITY && dmd->u.verity.fec_device &&
|
||||
!(dmt_flags & DM_VERITY_FEC_SUPPORTED))
|
||||
log_err(cd, _("Requested dm-verity FEC options are not supported.\n"));
|
||||
log_err(cd, _("Requested dm-verity FEC options are not supported."));
|
||||
|
||||
if (r == -EINVAL && dmd->target == DM_CRYPT) {
|
||||
if (dmd->u.crypt.integrity && !(dmt_flags & DM_INTEGRITY_SUPPORTED))
|
||||
log_err(cd, _("Requested data integrity options are not supported.\n"));
|
||||
log_err(cd, _("Requested data integrity options are not supported."));
|
||||
if (dmd->u.crypt.sector_size != SECTOR_SIZE && !(dmt_flags & DM_SECTOR_SIZE_SUPPORTED))
|
||||
log_err(cd, _("Requested sector_size option is not supported.\n"));
|
||||
log_err(cd, _("Requested sector_size option is not supported."));
|
||||
}
|
||||
out:
|
||||
crypt_safe_free(table_params);
|
||||
@@ -1360,6 +1361,29 @@ int dm_status_verity_ok(struct crypt_device *cd, const char *name)
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_status_integrity_failures(struct crypt_device *cd, const char *name, uint64_t *count)
|
||||
{
|
||||
int r;
|
||||
struct dm_info dmi;
|
||||
char *status_line = NULL;
|
||||
|
||||
if (dm_init_context(cd, DM_INTEGRITY))
|
||||
return -ENOTSUP;
|
||||
|
||||
r = dm_status_dmi(name, &dmi, DM_INTEGRITY_TARGET, &status_line);
|
||||
if (r < 0 || !status_line) {
|
||||
free(status_line);
|
||||
return r;
|
||||
}
|
||||
|
||||
log_dbg("Integrity volume %s failure status is %s.", name, status_line ?: "");
|
||||
*count = strtoull(status_line, NULL, 10);
|
||||
free(status_line);
|
||||
dm_exit_context();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME use hex wrapper, user val wrappers for line parsing */
|
||||
static int _dm_query_crypt(uint32_t get_flags,
|
||||
struct dm_info *dmi,
|
||||
@@ -1490,11 +1514,16 @@ static int _dm_query_crypt(uint32_t get_flags,
|
||||
|
||||
if (get_flags & DM_ACTIVE_CRYPT_KEY) {
|
||||
if (key_[0] == ':') {
|
||||
key_desc = strpbrk(strpbrk(key_ + 1, ":") + 1, ":") + 1;
|
||||
/* :<key_size>:<key_type>:<key_description> */
|
||||
key_desc = NULL;
|
||||
endp = strpbrk(key_ + 1, ":");
|
||||
if (endp)
|
||||
key_desc = strpbrk(endp + 1, ":");
|
||||
if (!key_desc) {
|
||||
r = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
key_desc++;
|
||||
crypt_volume_key_set_description(vk, key_desc);
|
||||
} else {
|
||||
buffer[2] = '\0';
|
||||
@@ -1684,6 +1713,8 @@ static int _dm_query_verity(uint32_t get_flags,
|
||||
dmd->flags |= CRYPT_ACTIVATE_RESTART_ON_CORRUPTION;
|
||||
else if (!strcasecmp(arg, "ignore_zero_blocks"))
|
||||
dmd->flags |= CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS;
|
||||
else if (!strcasecmp(arg, "check_at_most_once"))
|
||||
dmd->flags |= CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE;
|
||||
else if (!strcasecmp(arg, "use_fec_from_device")) {
|
||||
str = strsep(¶ms, " ");
|
||||
str2 = crypt_lookup_dev(str);
|
||||
@@ -1694,9 +1725,10 @@ static int _dm_query_verity(uint32_t get_flags,
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (vp)
|
||||
if (vp) {
|
||||
free(fec_dev_str);
|
||||
fec_dev_str = str2;
|
||||
else
|
||||
} else
|
||||
free(str2);
|
||||
i++;
|
||||
} else if (!strcasecmp(arg, "fec_start")) {
|
||||
@@ -2037,6 +2069,23 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_suspend_device(struct crypt_device *cd, const char *name)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (dm_init_context(cd, DM_UNKNOWN))
|
||||
return -ENOTSUP;
|
||||
|
||||
if (!_dm_simple(DM_DEVICE_SUSPEND, name, 0))
|
||||
r = -EINVAL;
|
||||
else
|
||||
r = 0;
|
||||
|
||||
dm_exit_context();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name)
|
||||
{
|
||||
uint32_t dmt_flags;
|
||||
@@ -2079,7 +2128,7 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
|
||||
goto out;
|
||||
|
||||
if (vk->key_description)
|
||||
msg_size = strlen(vk->key_description) + get_key_size_strlen(vk->keylength) + 17;
|
||||
msg_size = strlen(vk->key_description) + int_log10(vk->keylength) + 18;
|
||||
else
|
||||
msg_size = vk->keylength * 2 + 10; // key set <key>
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ static int hash_keys(struct crypt_device *cd,
|
||||
tweak = get_tweak(keys_count);
|
||||
|
||||
if (!keys_count || !key_len_output || !hash_name || !key_len_input) {
|
||||
log_err(cd, _("Key processing error (using hash %s).\n"),
|
||||
log_err(cd, _("Key processing error (using hash %s)."),
|
||||
hash_name ?: "[none]");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -165,7 +165,7 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
|
||||
}
|
||||
if (offset == buffer_len) {
|
||||
log_dbg("Unterminated key #%d in keyfile.", key_index);
|
||||
log_err(cd, _("Incompatible loop-AES keyfile detected.\n"));
|
||||
log_err(cd, _("Incompatible loop-AES keyfile detected."));
|
||||
return -EINVAL;
|
||||
}
|
||||
while (offset < buffer_len && !buffer[offset])
|
||||
@@ -185,7 +185,7 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
|
||||
|
||||
if (offset != buffer_len || key_len == 0 ||
|
||||
(key_index != 1 && key_index !=64 && key_index != 65)) {
|
||||
log_err(cd, _("Incompatible loop-AES keyfile detected.\n"));
|
||||
log_err(cd, _("Incompatible loop-AES keyfile detected."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ int LOOPAES_activate(struct crypt_device *cd,
|
||||
|
||||
if (r < 0 && !dm_flags(DM_CRYPT, &dmc_flags) &&
|
||||
(dmc_flags & req_flags) != req_flags) {
|
||||
log_err(cd, _("Kernel doesn't support loop-AES compatible mapping.\n"));
|
||||
log_err(cd, _("Kernel doesn't support loop-AES compatible mapping."));
|
||||
r = -ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#ifndef _LOOPAES_H
|
||||
#define _LOOPAES_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct crypt_device;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* AFsplitter diffuses information over a large stripe of data,
|
||||
* therefor supporting secure data destruction.
|
||||
* therefore supporting secure data destruction.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* AFsplitter diffuses information over a large stripe of data,
|
||||
* therefor supporting secure data destruction.
|
||||
* therefore supporting secure data destruction.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,6 +24,8 @@
|
||||
#ifndef INCLUDED_CRYPTSETUP_LUKS_AF_H
|
||||
#define INCLUDED_CRYPTSETUP_LUKS_AF_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* AF_split operates on src and produces information split data in
|
||||
* dst. src is assumed to be of the length blocksize. The data stripe
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include "luks.h"
|
||||
#include "af.h"
|
||||
#include "internal.h"
|
||||
@@ -37,13 +38,13 @@ static void _error_hint(struct crypt_device *ctx, const char *device,
|
||||
return;
|
||||
|
||||
log_err(ctx, _("Failed to setup dm-crypt key mapping for device %s.\n"
|
||||
"Check that kernel supports %s cipher (check syslog for more info).\n"),
|
||||
"Check that kernel supports %s cipher (check syslog for more info)."),
|
||||
device, cipher_spec);
|
||||
|
||||
if (!strncmp(mode, "xts", 3) && (keyLength != 256 && keyLength != 512))
|
||||
log_err(ctx, _("Key size in XTS mode must be 256 or 512 bits.\n"));
|
||||
log_err(ctx, _("Key size in XTS mode must be 256 or 512 bits."));
|
||||
else if (!(c = strchr(mode, '-')) || strlen(c) < 4)
|
||||
log_err(ctx, _("Cipher specification should be in [cipher]-[mode]-[iv] format.\n"));
|
||||
log_err(ctx, _("Cipher specification should be in [cipher]-[mode]-[iv] format."));
|
||||
}
|
||||
|
||||
static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
@@ -98,13 +99,13 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
r = device_block_adjust(ctx, dmd.data_device, DEV_OK,
|
||||
dmd.u.crypt.offset, &dmd.size, &dmd.flags);
|
||||
if (r < 0) {
|
||||
log_err(ctx, _("Device %s doesn't exist or access denied.\n"),
|
||||
log_err(ctx, _("Device %s doesn't exist or access denied."),
|
||||
device_path(dmd.data_device));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (mode != O_RDONLY && dmd.flags & CRYPT_ACTIVATE_READONLY) {
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied."),
|
||||
device_path(dmd.data_device));
|
||||
return -EACCES;
|
||||
}
|
||||
@@ -119,14 +120,14 @@ static int LUKS_endec_template(char *src, size_t srcLength,
|
||||
|
||||
devfd = open(path, mode | O_DIRECT | O_SYNC);
|
||||
if (devfd == -1) {
|
||||
log_err(ctx, _("Failed to open temporary keystore device.\n"));
|
||||
log_err(ctx, _("Failed to open temporary keystore device."));
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = func(devfd, bsize, alignment, src, srcLength);
|
||||
if (r < 0) {
|
||||
log_err(ctx, _("Failed to access temporary keystore device.\n"));
|
||||
log_err(ctx, _("Failed to access temporary keystore device."));
|
||||
r = -EIO;
|
||||
} else
|
||||
r = 0;
|
||||
@@ -150,7 +151,7 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
|
||||
int devfd = -1, r = 0;
|
||||
|
||||
/* Only whole sector writes supported */
|
||||
if (srcLength % SECTOR_SIZE)
|
||||
if (MISALIGNED_512(srcLength))
|
||||
return -EINVAL;
|
||||
|
||||
/* Encrypt buffer */
|
||||
@@ -193,10 +194,12 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
if (devfd >= 0)
|
||||
if (devfd >= 0) {
|
||||
device_sync(device, devfd);
|
||||
close(devfd);
|
||||
}
|
||||
if (r)
|
||||
log_err(ctx, _("IO error while encrypting keyslot.\n"));
|
||||
log_err(ctx, _("IO error while encrypting keyslot."));
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -210,10 +213,11 @@ 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 = -1, r = 0;
|
||||
|
||||
/* Only whole sector reads supported */
|
||||
if (dstLength % SECTOR_SIZE)
|
||||
if (MISALIGNED_512(dstLength))
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
@@ -235,17 +239,26 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
|
||||
log_dbg("Using userspace crypto wrapper to access keyslot area.");
|
||||
|
||||
r = -EIO;
|
||||
|
||||
/* Read buffer from device */
|
||||
devfd = device_open(device, O_RDONLY);
|
||||
if (devfd < 0)
|
||||
goto bad;
|
||||
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(device),
|
||||
device_alignment(device), dst, dstLength,
|
||||
sector * SECTOR_SIZE) < 0)
|
||||
goto bad;
|
||||
sector * SECTOR_SIZE) < 0) {
|
||||
if (!fstat(devfd, &st) && (st.st_size < (off_t)dstLength))
|
||||
log_err(ctx, _("Device %s is too small."), device_path(device));
|
||||
else
|
||||
log_err(ctx, _("IO error while decrypting keyslot."));
|
||||
|
||||
close(devfd);
|
||||
crypt_storage_destroy(s);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
close(devfd);
|
||||
|
||||
@@ -253,13 +266,5 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
|
||||
crypt_storage_destroy(s);
|
||||
|
||||
return r;
|
||||
bad:
|
||||
if (devfd >= 0)
|
||||
close(devfd);
|
||||
|
||||
log_err(ctx, _("IO error while decrypting keyslot.\n"));
|
||||
crypt_storage_destroy(s);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ static int LUKS_check_device_size(struct crypt_device *ctx, const struct luks_ph
|
||||
if (falloc && !device_fallocate(device, hdr_sectors << SECTOR_SHIFT))
|
||||
return 0;
|
||||
|
||||
log_err(ctx, _("Device %s is too small. (LUKS1 requires at least %" PRIu64 " bytes.)\n"),
|
||||
log_err(ctx, _("Device %s is too small. (LUKS1 requires at least %" PRIu64 " bytes.)"),
|
||||
device_path(device), hdr_sectors * SECTOR_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -146,7 +146,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
|
||||
if (phdr->keyblock[i].stripes != LUKS_STRIPES) {
|
||||
log_dbg("Invalid stripes count %u in keyslot %u.",
|
||||
phdr->keyblock[i].stripes, i);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
|
||||
if (phdr->keyblock[i].keyMaterialOffset * SECTOR_SIZE < sizeof(*phdr)) {
|
||||
log_dbg("Invalid offset %u in keyslot %u.",
|
||||
phdr->keyblock[i].keyMaterialOffset, i);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
|
||||
log_dbg("Invalid offset %u in keyslot %u (beyond data area offset %u).",
|
||||
phdr->keyblock[i].keyMaterialOffset, i,
|
||||
phdr->payloadOffset);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
|
||||
phdr->keyblock[i].keyMaterialOffset,
|
||||
phdr->keyblock[i].stripes,
|
||||
i, phdr->payloadOffset);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), i);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid."), i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -189,7 +189,7 @@ static int LUKS_check_keyslots(struct crypt_device *ctx, const struct luks_phdr
|
||||
if (phdr->keyblock[next].keyMaterialOffset <
|
||||
(phdr->keyblock[prev].keyMaterialOffset + secs_per_stripes)) {
|
||||
log_dbg("Not enough space in LUKS keyslot %d.", prev);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid.\n"), prev);
|
||||
log_err(ctx, _("LUKS keyslot %u is invalid."), prev);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -242,7 +242,7 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
|
||||
|
||||
devfd = device_open(device, O_RDONLY);
|
||||
if (devfd < 0) {
|
||||
log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device_path(device));
|
||||
log_err(ctx, _("Device %s is not a valid LUKS device."), device_path(device));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -261,14 +261,14 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx)
|
||||
devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
|
||||
if (devfd == -1) {
|
||||
if (errno == EEXIST)
|
||||
log_err(ctx, _("Requested header backup file %s already exists.\n"), backup_file);
|
||||
log_err(ctx, _("Requested header backup file %s already exists."), backup_file);
|
||||
else
|
||||
log_err(ctx, _("Cannot create header backup file %s.\n"), backup_file);
|
||||
log_err(ctx, _("Cannot create header backup file %s."), backup_file);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (write_buffer(devfd, buffer, buffer_size) < (ssize_t)buffer_size) {
|
||||
log_err(ctx, _("Cannot write header backup file %s.\n"), backup_file);
|
||||
log_err(ctx, _("Cannot write header backup file %s."), backup_file);
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
@@ -301,7 +301,7 @@ int LUKS_hdr_restore(
|
||||
buffer_size = LUKS_device_sectors(&hdr_file) << SECTOR_SHIFT;
|
||||
|
||||
if (r || buffer_size < LUKS_ALIGN_KEYSLOTS) {
|
||||
log_err(ctx, _("Backup file doesn't contain valid LUKS header.\n"));
|
||||
log_err(ctx, _("Backup file doesn't contain valid LUKS header."));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -314,13 +314,13 @@ int LUKS_hdr_restore(
|
||||
|
||||
devfd = open(backup_file, O_RDONLY);
|
||||
if (devfd == -1) {
|
||||
log_err(ctx, _("Cannot open header backup file %s.\n"), backup_file);
|
||||
log_err(ctx, _("Cannot open header backup file %s."), backup_file);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (read_buffer(devfd, buffer, buffer_size) < buffer_size) {
|
||||
log_err(ctx, _("Cannot read header backup file %s.\n"), backup_file);
|
||||
log_err(ctx, _("Cannot read header backup file %s."), backup_file);
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
@@ -332,7 +332,7 @@ int LUKS_hdr_restore(
|
||||
log_dbg("Device %s already contains LUKS header, checking UUID and offset.", device_path(device));
|
||||
if(hdr->payloadOffset != hdr_file.payloadOffset ||
|
||||
hdr->keyBytes != hdr_file.keyBytes) {
|
||||
log_err(ctx, _("Data offset or key size differs on device and backup, restore failed.\n"));
|
||||
log_err(ctx, _("Data offset or key size differs on device and backup, restore failed."));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -359,10 +359,10 @@ int LUKS_hdr_restore(
|
||||
devfd = device_open(device, O_RDWR);
|
||||
if (devfd < 0) {
|
||||
if (errno == EACCES)
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied."),
|
||||
device_path(device));
|
||||
else
|
||||
log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
|
||||
log_err(ctx, _("Cannot open device %s."), device_path(device));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -378,8 +378,10 @@ int LUKS_hdr_restore(
|
||||
/* Be sure to reload new data */
|
||||
r = LUKS_read_phdr(hdr, 1, 0, ctx);
|
||||
out:
|
||||
if (devfd >= 0)
|
||||
if (devfd >= 0) {
|
||||
device_sync(device, devfd);
|
||||
close(devfd);
|
||||
}
|
||||
crypt_safe_free(buffer);
|
||||
return r;
|
||||
}
|
||||
@@ -393,18 +395,22 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
||||
int i, bad, r, need_write = 0;
|
||||
|
||||
if (phdr->keyBytes != 16 && phdr->keyBytes != 32 && phdr->keyBytes != 64) {
|
||||
log_err(ctx, _("Non standard key size, manual repair required.\n"));
|
||||
log_err(ctx, _("Non standard key size, manual repair required."));
|
||||
return -EINVAL;
|
||||
}
|
||||
/* cryptsetup 1.0 did not align to 4k, cannot repair this one */
|
||||
if (LUKS_keyslots_offset(phdr) < (LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE)) {
|
||||
log_err(ctx, _("Non standard keyslots alignment, manual repair required.\n"));
|
||||
log_err(ctx, _("Non standard keyslots alignment, manual repair required."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = LUKS_check_cipher(ctx, phdr->keyBytes, phdr->cipherName, phdr->cipherMode);
|
||||
if (r < 0)
|
||||
return -EINVAL;
|
||||
|
||||
vk = crypt_alloc_volume_key(phdr->keyBytes, NULL);
|
||||
|
||||
log_verbose(ctx, _("Repairing keyslots.\n"));
|
||||
log_verbose(ctx, _("Repairing keyslots."));
|
||||
|
||||
log_dbg("Generating second header with the same parameters for check.");
|
||||
/* cipherName, cipherMode, hashSpec, uuid are already null terminated */
|
||||
@@ -424,7 +430,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
||||
|
||||
bad = 0;
|
||||
if (phdr->keyblock[i].keyMaterialOffset != temp_phdr.keyblock[i].keyMaterialOffset) {
|
||||
log_err(ctx, _("Keyslot %i: offset repaired (%u -> %u).\n"), i,
|
||||
log_err(ctx, _("Keyslot %i: offset repaired (%u -> %u)."), i,
|
||||
(unsigned)phdr->keyblock[i].keyMaterialOffset,
|
||||
(unsigned)temp_phdr.keyblock[i].keyMaterialOffset);
|
||||
phdr->keyblock[i].keyMaterialOffset = temp_phdr.keyblock[i].keyMaterialOffset;
|
||||
@@ -432,7 +438,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
||||
}
|
||||
|
||||
if (phdr->keyblock[i].stripes != temp_phdr.keyblock[i].stripes) {
|
||||
log_err(ctx, _("Keyslot %i: stripes repaired (%u -> %u).\n"), i,
|
||||
log_err(ctx, _("Keyslot %i: stripes repaired (%u -> %u)."), i,
|
||||
(unsigned)phdr->keyblock[i].stripes,
|
||||
(unsigned)temp_phdr.keyblock[i].stripes);
|
||||
phdr->keyblock[i].stripes = temp_phdr.keyblock[i].stripes;
|
||||
@@ -441,12 +447,12 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
||||
|
||||
/* Known case - MSDOS partition table signature */
|
||||
if (i == 6 && sector[0x1fe] == 0x55 && sector[0x1ff] == 0xaa) {
|
||||
log_err(ctx, _("Keyslot %i: bogus partition signature.\n"), i);
|
||||
log_err(ctx, _("Keyslot %i: bogus partition signature."), i);
|
||||
bad = 1;
|
||||
}
|
||||
|
||||
if(bad) {
|
||||
log_err(ctx, _("Keyslot %i: salt wiped.\n"), i);
|
||||
log_err(ctx, _("Keyslot %i: salt wiped."), i);
|
||||
phdr->keyblock[i].active = LUKS_KEY_DISABLED;
|
||||
memset(&phdr->keyblock[i].passwordSalt, 0x00, LUKS_SALTSIZE);
|
||||
phdr->keyblock[i].passwordIterations = 0;
|
||||
@@ -463,12 +469,12 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
||||
if (LUKS_check_keyslots(ctx, phdr))
|
||||
r = -EINVAL;
|
||||
else if (need_write) {
|
||||
log_verbose(ctx, _("Writing LUKS header to disk.\n"));
|
||||
log_verbose(ctx, _("Writing LUKS header to disk."));
|
||||
r = LUKS_write_phdr(phdr, ctx);
|
||||
}
|
||||
out:
|
||||
if (r)
|
||||
log_err(ctx, _("Repair failed.\n"));
|
||||
log_err(ctx, _("Repair failed."));
|
||||
crypt_free_volume_key(vk);
|
||||
crypt_memzero(&temp_phdr, sizeof(temp_phdr));
|
||||
return r;
|
||||
@@ -487,16 +493,16 @@ static int _check_and_convert_hdr(const char *device,
|
||||
if(memcmp(hdr->magic, luksMagic, LUKS_MAGIC_L)) { /* Check magic */
|
||||
log_dbg("LUKS header not detected.");
|
||||
if (require_luks_device)
|
||||
log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device);
|
||||
log_err(ctx, _("Device %s is not a valid LUKS device."), device);
|
||||
return -EINVAL;
|
||||
} else if((hdr->version = ntohs(hdr->version)) != 1) { /* Convert every uint16/32_t item from network byte order */
|
||||
log_err(ctx, _("Unsupported LUKS version %d.\n"), hdr->version);
|
||||
log_err(ctx, _("Unsupported LUKS version %d."), hdr->version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hdr->hashSpec[LUKS_HASHSPEC_L - 1] = '\0';
|
||||
if (crypt_hmac_size(hdr->hashSpec) < LUKS_DIGESTSIZE) {
|
||||
log_err(ctx, _("Requested LUKS hash %s is not supported.\n"), hdr->hashSpec);
|
||||
log_err(ctx, _("Requested LUKS hash %s is not supported."), hdr->hashSpec);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -524,7 +530,7 @@ static int _check_and_convert_hdr(const char *device,
|
||||
if (r == -EINVAL)
|
||||
r = _keyslot_repair(hdr, ctx);
|
||||
else
|
||||
log_verbose(ctx, _("No known problems detected for LUKS header.\n"));
|
||||
log_verbose(ctx, _("No known problems detected for LUKS header."));
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -564,7 +570,7 @@ int LUKS_read_phdr_backup(const char *backup_file,
|
||||
|
||||
devfd = open(backup_file, O_RDONLY);
|
||||
if (devfd == -1) {
|
||||
log_err(ctx, _("Cannot open header backup file %s.\n"), backup_file);
|
||||
log_err(ctx, _("Cannot open header backup file %s."), backup_file);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
@@ -603,7 +609,7 @@ int LUKS_read_phdr(struct luks_phdr *hdr,
|
||||
|
||||
devfd = device_open(device, O_RDONLY);
|
||||
if (devfd < 0) {
|
||||
log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
|
||||
log_err(ctx, _("Cannot open device %s."), device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -651,10 +657,10 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
|
||||
devfd = device_open(device, O_RDWR);
|
||||
if (devfd < 0) {
|
||||
if (errno == EACCES)
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied."),
|
||||
device_path(device));
|
||||
else
|
||||
log_err(ctx, _("Cannot open device %s.\n"), device_path(device));
|
||||
log_err(ctx, _("Cannot open device %s."), device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -676,14 +682,16 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
|
||||
r = write_blockwise(devfd, device_block_size(device), device_alignment(device),
|
||||
&convHdr, hdr_size) < hdr_size ? -EIO : 0;
|
||||
if (r)
|
||||
log_err(ctx, _("Error during update of LUKS header on device %s.\n"), device_path(device));
|
||||
log_err(ctx, _("Error during update of LUKS header on device %s."), device_path(device));
|
||||
|
||||
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) {
|
||||
r = LUKS_read_phdr(hdr, 1, 0, ctx);
|
||||
if (r)
|
||||
log_err(ctx, _("Error re-reading LUKS header after update on device %s.\n"),
|
||||
log_err(ctx, _("Error re-reading LUKS header after update on device %s."),
|
||||
device_path(device));
|
||||
}
|
||||
|
||||
@@ -691,23 +699,22 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
|
||||
}
|
||||
|
||||
/* Check that kernel supports requested cipher by decryption of one sector */
|
||||
static int LUKS_check_cipher(struct luks_phdr *hdr, struct crypt_device *ctx)
|
||||
int LUKS_check_cipher(struct crypt_device *ctx, size_t keylength, const char *cipher, const char *cipher_mode)
|
||||
{
|
||||
int r;
|
||||
struct volume_key *empty_key;
|
||||
char buf[SECTOR_SIZE];
|
||||
|
||||
log_dbg("Checking if cipher %s-%s is usable.", hdr->cipherName, hdr->cipherMode);
|
||||
log_dbg("Checking if cipher %s-%s is usable.", cipher, cipher_mode);
|
||||
|
||||
empty_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
|
||||
empty_key = crypt_alloc_volume_key(keylength, NULL);
|
||||
if (!empty_key)
|
||||
return -ENOMEM;
|
||||
|
||||
/* No need to get KEY quality random but it must avoid known weak keys. */
|
||||
r = crypt_random_get(ctx, empty_key->key, empty_key->keylength, CRYPT_RND_NORMAL);
|
||||
if (!r)
|
||||
r = LUKS_decrypt_from_storage(buf, sizeof(buf), hdr->cipherName,
|
||||
hdr->cipherMode, empty_key, 0, ctx);
|
||||
r = LUKS_decrypt_from_storage(buf, sizeof(buf), cipher, cipher_mode, empty_key, 0, ctx);
|
||||
|
||||
crypt_free_volume_key(empty_key);
|
||||
crypt_memzero(buf, sizeof(buf));
|
||||
@@ -737,18 +744,18 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
|
||||
if (alignPayload && detached_metadata_device && alignPayload < hdr_sectors) {
|
||||
log_err(ctx, _("Data offset for detached LUKS header must be "
|
||||
"either 0 or higher than header size (%d sectors).\n"),
|
||||
"either 0 or higher than header size (%d sectors)."),
|
||||
hdr_sectors);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (crypt_hmac_size(hashSpec) < LUKS_DIGESTSIZE) {
|
||||
log_err(ctx, _("Requested LUKS hash %s is not supported.\n"), hashSpec);
|
||||
log_err(ctx, _("Requested LUKS hash %s is not supported."), hashSpec);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
|
||||
log_err(ctx, _("Wrong LUKS UUID format provided.\n"));
|
||||
log_err(ctx, _("Wrong LUKS UUID format provided."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!uuid)
|
||||
@@ -767,17 +774,13 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
|
||||
LUKS_fix_header_compatible(header);
|
||||
|
||||
r = LUKS_check_cipher(header, ctx);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_dbg("Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes",
|
||||
header->version, header->hashSpec ,header->cipherName, header->cipherMode,
|
||||
header->keyBytes);
|
||||
|
||||
r = crypt_random_get(ctx, header->mkDigestSalt, LUKS_SALTSIZE, CRYPT_RND_SALT);
|
||||
if(r < 0) {
|
||||
log_err(ctx, _("Cannot create LUKS header: reading random salt failed.\n"));
|
||||
log_err(ctx, _("Cannot create LUKS header: reading random salt failed."));
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -798,7 +801,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
header->mkDigest,LUKS_DIGESTSIZE,
|
||||
header->mkDigestIterations, 0, 0);
|
||||
if(r < 0) {
|
||||
log_err(ctx, _("Cannot create LUKS header: header digest failed (using hash %s).\n"),
|
||||
log_err(ctx, _("Cannot create LUKS header: header digest failed (using hash %s)."),
|
||||
header->hashSpec);
|
||||
return r;
|
||||
}
|
||||
@@ -838,7 +841,7 @@ int LUKS_hdr_uuid_set(
|
||||
uuid_t partitionUuid;
|
||||
|
||||
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
|
||||
log_err(ctx, _("Wrong LUKS UUID format provided.\n"));
|
||||
log_err(ctx, _("Wrong LUKS UUID format provided."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!uuid)
|
||||
@@ -861,13 +864,13 @@ int LUKS_set_key(unsigned int keyIndex,
|
||||
int r;
|
||||
|
||||
if(hdr->keyblock[keyIndex].active != LUKS_KEY_DISABLED) {
|
||||
log_err(ctx, _("Key slot %d active, purge first.\n"), keyIndex);
|
||||
log_err(ctx, _("Key slot %d active, purge first."), keyIndex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* LUKS keyslot has always at least 4000 stripes according to specification */
|
||||
if(hdr->keyblock[keyIndex].stripes < 4000) {
|
||||
log_err(ctx, _("Key slot %d material includes too few stripes. Header manipulation?\n"),
|
||||
log_err(ctx, _("Key slot %d material includes too few stripes. Header manipulation?"),
|
||||
keyIndex);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1024,9 +1027,6 @@ static int LUKS_open_key(unsigned int keyIndex,
|
||||
/* Allow only empty passphrase with null cipher */
|
||||
if (!r && !strcmp(hdr->cipherName, "cipher_null") && passwordLen)
|
||||
r = -EPERM;
|
||||
|
||||
if (!r)
|
||||
log_verbose(ctx, _("Key slot %d unlocked.\n"), keyIndex);
|
||||
out:
|
||||
crypt_safe_free(AfKey);
|
||||
crypt_free_volume_key(derived_key);
|
||||
@@ -1061,7 +1061,6 @@ int LUKS_open_key_with_hdr(int keyIndex,
|
||||
return r;
|
||||
}
|
||||
/* Warning, early returns above */
|
||||
log_err(ctx, _("No key available with this passphrase.\n"));
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@@ -1079,7 +1078,7 @@ int LUKS_del_key(unsigned int keyIndex,
|
||||
|
||||
r = LUKS_keyslot_set(hdr, keyIndex, 0);
|
||||
if (r) {
|
||||
log_err(ctx, _("Key slot %d is invalid, please select keyslot between 0 and %d.\n"),
|
||||
log_err(ctx, _("Key slot %d is invalid, please select keyslot between 0 and %d."),
|
||||
keyIndex, LUKS_NUMKEYS - 1);
|
||||
return r;
|
||||
}
|
||||
@@ -1093,11 +1092,11 @@ int LUKS_del_key(unsigned int keyIndex,
|
||||
(endOffset - startOffset) * SECTOR_SIZE, NULL, NULL);
|
||||
if (r) {
|
||||
if (r == -EACCES) {
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied.\n"),
|
||||
log_err(ctx, _("Cannot write to device %s, permission denied."),
|
||||
device_path(device));
|
||||
r = -EINVAL;
|
||||
} else
|
||||
log_err(ctx, _("Cannot wipe device %s.\n"),
|
||||
log_err(ctx, _("Cannot wipe device %s."),
|
||||
device_path(device));
|
||||
return r;
|
||||
}
|
||||
@@ -1211,3 +1210,56 @@ int LUKS1_activate(struct crypt_device *cd,
|
||||
free(dm_cipher);
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS_wipe_header_areas(struct luks_phdr *hdr,
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
int i, r;
|
||||
uint64_t offset, length;
|
||||
size_t wipe_block;
|
||||
|
||||
/* Wipe complete header, keyslots and padding areas with zeroes. */
|
||||
offset = 0;
|
||||
length = (uint64_t)hdr->payloadOffset * SECTOR_SIZE;
|
||||
wipe_block = 1024 * 1024;
|
||||
|
||||
/* On detached header or bogus header, wipe at least the first 4k */
|
||||
if (length == 0 || length > (LUKS_MAX_KEYSLOT_SIZE * LUKS_NUMKEYS)) {
|
||||
length = 4096;
|
||||
wipe_block = 4096;
|
||||
}
|
||||
|
||||
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,
|
||||
offset, length, wipe_block, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Wipe keyslots areas */
|
||||
wipe_block = 1024 * 1024;
|
||||
for (i = 0; i < LUKS_NUMKEYS; i++) {
|
||||
r = LUKS_keyslot_area(hdr, i, &offset, &length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Ignore too big LUKS1 keyslots here */
|
||||
if (length > LUKS_MAX_KEYSLOT_SIZE ||
|
||||
offset > (LUKS_MAX_KEYSLOT_SIZE - length))
|
||||
continue;
|
||||
|
||||
if (length == 0 || offset < 4096)
|
||||
return -EINVAL;
|
||||
|
||||
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,
|
||||
offset, length, wipe_block, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -61,6 +61,9 @@
|
||||
/* Offset to keyslot area [in bytes] */
|
||||
#define LUKS_ALIGN_KEYSLOTS 4096
|
||||
|
||||
/* Maximal LUKS header size, for wipe [in bytes] */
|
||||
#define LUKS_MAX_KEYSLOT_SIZE 0x1000000 /* 16 MB, up to 32768 bits key */
|
||||
|
||||
/* Any integer values are stored in network byte order on disk and must be
|
||||
converted */
|
||||
|
||||
@@ -99,6 +102,11 @@ struct luks_phdr {
|
||||
int LUKS_verify_volume_key(const struct luks_phdr *hdr,
|
||||
const struct volume_key *vk);
|
||||
|
||||
int LUKS_check_cipher(struct crypt_device *ctx,
|
||||
size_t keylength,
|
||||
const char *cipher,
|
||||
const char *cipher_mode);
|
||||
|
||||
int LUKS_generate_phdr(
|
||||
struct luks_phdr *header,
|
||||
const struct volume_key *vk,
|
||||
@@ -163,6 +171,9 @@ int LUKS_del_key(
|
||||
struct luks_phdr *hdr,
|
||||
struct crypt_device *ctx);
|
||||
|
||||
int LUKS_wipe_header_areas(struct luks_phdr *hdr,
|
||||
struct crypt_device *ctx);
|
||||
|
||||
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);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
#define LUKS2_KEYSLOTS_MAX 32
|
||||
#define LUKS2_TOKENS_MAX 32
|
||||
#define LUKS2_SEGMENT_MAX 32
|
||||
|
||||
#define LUKS2_BUILTIN_TOKEN_PREFIX "luks2-"
|
||||
#define LUKS2_BUILTIN_TOKEN_PREFIX_LEN 6
|
||||
@@ -47,6 +48,8 @@
|
||||
#define CRYPT_DEFAULT_SEGMENT 0
|
||||
#define CRYPT_DEFAULT_SEGMENT_STR "0"
|
||||
|
||||
#define CRYPT_ANY_DIGEST -1
|
||||
|
||||
/*
|
||||
* LUKS2 header on-disk.
|
||||
*
|
||||
@@ -126,10 +129,14 @@ struct luks2_keyslot_params {
|
||||
|
||||
#define LUKS2_MAX_KEYSLOTS_SIZE 0x8000000 /* 128 MiB */
|
||||
|
||||
/* Offsets for secondary header (for scan if primary header is corrupted). */
|
||||
#define LUKS2_HDR2_OFFSETS { 0x04000, 0x008000, 0x010000, 0x020000, \
|
||||
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 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_dump(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
|
||||
@@ -155,6 +162,8 @@ int LUKS2_hdr_restore(struct crypt_device *cd,
|
||||
uint64_t LUKS2_hdr_and_areas_size(json_object *jobj);
|
||||
uint64_t LUKS2_keyslots_size(json_object *jobj);
|
||||
|
||||
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd);
|
||||
|
||||
/*
|
||||
* Generic LUKS2 keyslot
|
||||
*/
|
||||
@@ -247,6 +256,8 @@ 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
|
||||
*/
|
||||
@@ -320,6 +331,9 @@ int LUKS2_generate_hdr(
|
||||
unsigned int alignOffset,
|
||||
int detached_metadata_device);
|
||||
|
||||
int LUKS2_wipe_header_areas(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr);
|
||||
|
||||
uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr);
|
||||
int LUKS2_get_sector_size(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment);
|
||||
|
||||
@@ -121,8 +121,6 @@ int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
int digest, r;
|
||||
|
||||
digest = LUKS2_digest_by_keyslot(cd, hdr, keyslot);
|
||||
if (digest == -ENOENT)
|
||||
return 0;
|
||||
if (digest < 0)
|
||||
return digest;
|
||||
|
||||
@@ -137,7 +135,7 @@ int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return digest;
|
||||
}
|
||||
|
||||
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
|
||||
@@ -174,9 +172,10 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return digest;
|
||||
}
|
||||
|
||||
/* FIXME: segment can have more digests */
|
||||
int LUKS2_digest_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int segment)
|
||||
|
||||
@@ -95,7 +95,7 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
|
||||
{
|
||||
json_object *jobj_digest, *jobj_digests;
|
||||
char salt[LUKS_SALTSIZE], digest_raw[128], num[16];
|
||||
int r;
|
||||
int hmac_size, r;
|
||||
char *base64_str;
|
||||
struct luks2_hdr *hdr;
|
||||
struct crypt_pbkdf_limits pbkdf_limits;
|
||||
@@ -123,8 +123,12 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
hmac_size = crypt_hmac_size(pbkdf.hash);
|
||||
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, crypt_hmac_size(pbkdf.hash),
|
||||
salt, LUKS_SALTSIZE, digest_raw, hmac_size,
|
||||
pbkdf.iterations, 0, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -151,7 +155,7 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
|
||||
json_object_object_add(jobj_digest, "salt", json_object_new_string(base64_str));
|
||||
free(base64_str);
|
||||
|
||||
base64_encode_alloc(digest_raw, crypt_hmac_size(pbkdf.hash), &base64_str);
|
||||
base64_encode_alloc(digest_raw, hmac_size, &base64_str);
|
||||
if (!base64_str) {
|
||||
json_object_put(jobj_digest);
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -74,9 +74,10 @@ static int hdr_checksum_calculate(const char *alg, struct luks2_hdr_disk *hdr_di
|
||||
const char *json_area, size_t json_len)
|
||||
{
|
||||
struct crypt_hash *hd = NULL;
|
||||
int r;
|
||||
int hash_size, r;
|
||||
|
||||
if (crypt_hash_size(alg) <= 0 || crypt_hash_init(&hd, alg))
|
||||
hash_size = crypt_hash_size(alg);
|
||||
if (hash_size <= 0 || crypt_hash_init(&hd, alg))
|
||||
return -EINVAL;
|
||||
|
||||
/* Binary header, csum zeroed. */
|
||||
@@ -87,7 +88,7 @@ static int hdr_checksum_calculate(const char *alg, struct luks2_hdr_disk *hdr_di
|
||||
r = crypt_hash_write(hd, json_area, json_len);
|
||||
|
||||
if (!r)
|
||||
r = crypt_hash_final(hd, (char*)hdr_disk->csum, crypt_hash_size(alg));
|
||||
r = crypt_hash_final(hd, (char*)hdr_disk->csum, (size_t)hash_size);
|
||||
|
||||
crypt_hash_destroy(hd);
|
||||
return r;
|
||||
@@ -100,9 +101,10 @@ static int hdr_checksum_check(const char *alg, struct luks2_hdr_disk *hdr_disk,
|
||||
const char *json_area, size_t json_len)
|
||||
{
|
||||
struct luks2_hdr_disk hdr_tmp;
|
||||
int r;
|
||||
int hash_size, r;
|
||||
|
||||
if (crypt_hash_size(alg) <= 0)
|
||||
hash_size = crypt_hash_size(alg);
|
||||
if (hash_size <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Copy header and zero checksum. */
|
||||
@@ -116,7 +118,7 @@ static int hdr_checksum_check(const char *alg, struct luks2_hdr_disk *hdr_disk,
|
||||
log_dbg_checksum(hdr_disk->csum, alg, "on-disk");
|
||||
log_dbg_checksum(hdr_tmp.csum, alg, "in-memory");
|
||||
|
||||
if (memcmp(hdr_tmp.csum, hdr_disk->csum, crypt_hash_size(alg)))
|
||||
if (memcmp(hdr_tmp.csum, hdr_disk->csum, (size_t)hash_size))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -221,7 +223,7 @@ static int hdr_read_disk(struct device *device, struct luks2_hdr_disk *hdr_disk,
|
||||
size_t hdr_json_size = 0;
|
||||
int devfd = -1, r;
|
||||
|
||||
log_dbg("Trying to read %s LUKS2 header at offset %" PRIu64 ".",
|
||||
log_dbg("Trying to read %s LUKS2 header at offset 0x%" PRIx64 ".",
|
||||
secondary ? "secondary" : "primary", offset);
|
||||
|
||||
devfd = device_open_locked(device, O_RDONLY);
|
||||
@@ -339,6 +341,7 @@ static int hdr_write_disk(struct device *device, struct luks2_hdr *hdr,
|
||||
LUKS2_HDR_BIN_LEN, offset) < (ssize_t)LUKS2_HDR_BIN_LEN)
|
||||
r = -EIO;
|
||||
|
||||
device_sync(device, devfd);
|
||||
close(devfd);
|
||||
return r;
|
||||
}
|
||||
@@ -361,7 +364,7 @@ static int LUKS2_check_device_size(struct crypt_device *cd, struct device *devic
|
||||
if (falloc && !device_fallocate(device, hdr_size))
|
||||
return 0;
|
||||
|
||||
log_err(cd, _("Device %s is too small. (LUKS2 requires at least %" PRIu64 " bytes.)\n"),
|
||||
log_err(cd, _("Device %s is too small. (LUKS2 requires at least %" PRIu64 " bytes.)"),
|
||||
device_path(device), hdr_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -406,7 +409,8 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
|
||||
/*
|
||||
* Generate text space-efficient JSON representation to json area.
|
||||
*/
|
||||
json_text = json_object_to_json_string_ext(hdr->jobj, JSON_C_TO_STRING_PLAIN);
|
||||
json_text = json_object_to_json_string_ext(hdr->jobj,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
|
||||
if (!json_text || !*json_text) {
|
||||
log_dbg("Cannot parse JSON object to text representation.");
|
||||
free(json_area);
|
||||
@@ -424,7 +428,7 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
|
||||
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write device lock.\n"));
|
||||
log_err(cd, _("Failed to acquire write device lock."));
|
||||
free(json_area);
|
||||
return r;
|
||||
}
|
||||
@@ -490,6 +494,15 @@ static int validate_luks2_json_object(json_object *jobj_hdr)
|
||||
}
|
||||
|
||||
r = LUKS2_hdr_validate(jobj_hdr);
|
||||
if (r) {
|
||||
log_dbg("Repairing JSON metadata.");
|
||||
/* try to correct known glitches */
|
||||
LUKS2_hdr_repair(jobj_hdr);
|
||||
|
||||
/* run validation again */
|
||||
r = LUKS2_hdr_validate(jobj_hdr);
|
||||
}
|
||||
|
||||
if (r)
|
||||
log_dbg("ERROR: LUKS2 validation failed");
|
||||
|
||||
@@ -519,21 +532,71 @@ static json_object *parse_and_validate_json(const char *json_area, int length)
|
||||
return jobj;
|
||||
}
|
||||
|
||||
static int detect_device_signatures(const char *path)
|
||||
{
|
||||
blk_probe_status prb_state;
|
||||
int r;
|
||||
struct blkid_handle *h;
|
||||
|
||||
if (!blk_supported()) {
|
||||
log_dbg("Blkid probing of device signatures disabled.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((r = blk_init_by_path(&h, path))) {
|
||||
log_dbg("Failed to initialize blkid_handle by path.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* We don't care about details. Be fast. */
|
||||
blk_set_chains_for_fast_detection(h);
|
||||
|
||||
/* Filter out crypto_LUKS. we don't care now */
|
||||
blk_superblocks_filter_luks(h);
|
||||
|
||||
prb_state = blk_safeprobe(h);
|
||||
|
||||
switch (prb_state) {
|
||||
case PRB_AMBIGUOUS:
|
||||
log_dbg("Blkid probe couldn't decide device type unambiguously.");
|
||||
/* fall through */
|
||||
case PRB_FAIL:
|
||||
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("Blkid probe detected partition type '%s'", blk_get_partition_type(h));
|
||||
else if (blk_is_superblock(h))
|
||||
log_dbg("blkid probe detected superblock type '%s'", blk_get_superblock_type(h));
|
||||
break;
|
||||
case PRB_EMPTY:
|
||||
log_dbg("Blkid probe detected no foreign device signature.");
|
||||
}
|
||||
blk_free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and convert on-disk LUKS2 header to in-memory representation..
|
||||
* Try to do recovery if on-disk state is not consistent.
|
||||
*/
|
||||
int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct device *device, int do_recovery)
|
||||
struct device *device, int do_recovery, int do_blkprobe)
|
||||
{
|
||||
enum { HDR_OK, HDR_OBSOLETE, HDR_FAIL, HDR_FAIL_IO } state_hdr1, state_hdr2;
|
||||
struct luks2_hdr_disk hdr_disk1, hdr_disk2;
|
||||
char *json_area1 = NULL, *json_area2 = NULL;
|
||||
json_object *jobj_hdr1 = NULL, *jobj_hdr2 = NULL;
|
||||
int i, r;
|
||||
unsigned int i;
|
||||
int r;
|
||||
uint64_t hdr_size;
|
||||
uint64_t hdr2_offsets[] = LUKS2_HDR2_OFFSETS;
|
||||
|
||||
if (do_recovery && !crypt_metadata_locking_enabled()) {
|
||||
/* 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("Disabling header auto-recovery due to locking being disabled.");
|
||||
}
|
||||
@@ -564,8 +627,8 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
/*
|
||||
* No header size, check all known offsets.
|
||||
*/
|
||||
for (r = -EINVAL,i = 2; r < 0 && i <= 1024; i <<= 1)
|
||||
r = hdr_read_disk(device, &hdr_disk2, &json_area2, i * 4096, 1);
|
||||
for (r = -EINVAL,i = 0; r < 0 && i < ARRAY_SIZE(hdr2_offsets); i++)
|
||||
r = hdr_read_disk(device, &hdr_disk2, &json_area2, hdr2_offsets[i], 1);
|
||||
|
||||
if (r == 0) {
|
||||
jobj_hdr2 = parse_and_validate_json(json_area2, be64_to_cpu(hdr_disk2.hdr_size) - LUKS2_HDR_BIN_LEN);
|
||||
@@ -604,6 +667,12 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
if (state_hdr1 == HDR_OK && state_hdr2 != HDR_OK) {
|
||||
log_dbg("Secondary LUKS2 header requires recovery.");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (do_recovery) {
|
||||
memcpy(&hdr_disk2, &hdr_disk1, LUKS2_HDR_BIN_LEN);
|
||||
r = crypt_random_get(NULL, (char*)hdr_disk2.salt, sizeof(hdr_disk2.salt), CRYPT_RND_SALT);
|
||||
@@ -619,6 +688,12 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
} else if (state_hdr1 != HDR_OK && state_hdr2 == HDR_OK) {
|
||||
log_dbg("Primary LUKS2 header requires recovery.");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (do_recovery) {
|
||||
memcpy(&hdr_disk1, &hdr_disk2, LUKS2_HDR_BIN_LEN);
|
||||
r = crypt_random_get(NULL, (char*)hdr_disk1.salt, sizeof(hdr_disk1.salt), CRYPT_RND_SALT);
|
||||
|
||||
@@ -33,11 +33,16 @@
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
/* override useless forward slash escape when supported by json-c */
|
||||
#ifndef JSON_C_TO_STRING_NOSLASHESCAPE
|
||||
#define JSON_C_TO_STRING_NOSLASHESCAPE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On-disk access function prototypes
|
||||
*/
|
||||
int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
struct device *device, int do_recovery);
|
||||
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);
|
||||
|
||||
@@ -46,8 +51,9 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
*/
|
||||
json_object *LUKS2_get_keyslot_jobj(struct luks2_hdr *hdr, int keyslot);
|
||||
json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token);
|
||||
json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int keyslot);
|
||||
json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int digest);
|
||||
json_object *LUKS2_get_segment_jobj(struct luks2_hdr *hdr, int segment);
|
||||
json_object *LUKS2_get_tokens_jobj(struct luks2_hdr *hdr);
|
||||
|
||||
void hexprint_base64(struct crypt_device *cd, json_object *jobj,
|
||||
const char *sep, const char *line_sep);
|
||||
@@ -63,12 +69,22 @@ void JSON_DBG(json_object *jobj, const char *desc);
|
||||
* LUKS2 JSON validation
|
||||
*/
|
||||
|
||||
/* validation helper */
|
||||
json_object *json_contains(json_object *jobj, const char *name, const char *section,
|
||||
const char *key, json_type type);
|
||||
|
||||
int LUKS2_hdr_validate(json_object *hdr_jobj);
|
||||
int LUKS2_keyslot_validate(json_object *hdr_jobj, json_object *hdr_keyslot, const char *key);
|
||||
int LUKS2_check_json_size(const struct luks2_hdr *hdr);
|
||||
int LUKS2_token_validate(json_object *hdr_jobj, json_object *jobj_token, const char *key);
|
||||
void LUKS2_token_dump(struct crypt_device *cd, int token);
|
||||
|
||||
/*
|
||||
* LUKS2 JSON repair for known glitches
|
||||
*/
|
||||
void LUKS2_hdr_repair(json_object *jobj_hdr);
|
||||
void LUKS2_keyslots_repair(json_object *jobj_hdr);
|
||||
|
||||
/*
|
||||
* JSON array helpers
|
||||
*/
|
||||
@@ -85,6 +101,8 @@ struct json_object *LUKS2_array_remove(struct json_object *array, const char *nu
|
||||
typedef int (*keyslot_alloc_func)(struct crypt_device *cd, int keyslot,
|
||||
size_t volume_key_len,
|
||||
const struct luks2_keyslot_params *params);
|
||||
typedef int (*keyslot_update_func)(struct crypt_device *cd, int keyslot,
|
||||
const struct luks2_keyslot_params *params);
|
||||
typedef int (*keyslot_open_func) (struct crypt_device *cd, int keyslot,
|
||||
const char *password, size_t password_len,
|
||||
char *volume_key, size_t volume_key_len);
|
||||
@@ -93,21 +111,29 @@ typedef int (*keyslot_store_func)(struct crypt_device *cd, int keyslot,
|
||||
const char *volume_key, size_t volume_key_len);
|
||||
typedef int (*keyslot_wipe_func) (struct crypt_device *cd, int keyslot);
|
||||
typedef int (*keyslot_dump_func) (struct crypt_device *cd, int keyslot);
|
||||
typedef int (*keyslot_validate_func) (struct crypt_device *cd, int keyslot);
|
||||
typedef int (*keyslot_validate_func) (struct crypt_device *cd, json_object *jobj_keyslot);
|
||||
typedef void(*keyslot_repair_func) (struct crypt_device *cd, json_object *jobj_keyslot);
|
||||
|
||||
int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
/* see LUKS2_luks2_to_luks1 */
|
||||
int placeholder_keyslot_alloc(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
size_t volume_key_len,
|
||||
const struct luks2_keyslot_params *params);
|
||||
uint64_t area_offset,
|
||||
uint64_t area_length,
|
||||
size_t volume_key_len);
|
||||
|
||||
/* validate all keyslot implementations in hdr json */
|
||||
int LUKS2_keyslots_validate(json_object *hdr_jobj);
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
keyslot_alloc_func alloc;
|
||||
keyslot_update_func update;
|
||||
keyslot_open_func open;
|
||||
keyslot_store_func store;
|
||||
keyslot_wipe_func wipe;
|
||||
keyslot_dump_func dump;
|
||||
keyslot_validate_func validate;
|
||||
keyslot_repair_func repair;
|
||||
} keyslot_handler;
|
||||
|
||||
/**
|
||||
@@ -128,8 +154,6 @@ typedef struct {
|
||||
|
||||
const digest_handler *LUKS2_digest_handler_type(struct crypt_device *cd, const char *type);
|
||||
|
||||
#define CRYPT_ANY_DIGEST -1
|
||||
|
||||
/**
|
||||
* LUKS2 token handlers (internal use only)
|
||||
*/
|
||||
@@ -147,7 +171,6 @@ typedef struct {
|
||||
int token_keyring_set(json_object **, const void *);
|
||||
int token_keyring_get(json_object *, void *);
|
||||
|
||||
#define CRYPT_ANY_TOKEN -1
|
||||
int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
size_t keylength, uint64_t *area_offset, uint64_t *area_length);
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
}
|
||||
|
||||
if (get_max_offset(cd) && (offset + length) > get_max_offset(cd)) {
|
||||
log_err(cd, _("No space for new keyslot.\n"));
|
||||
log_err(cd, _("No space for new keyslot."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -122,9 +122,9 @@ int LUKS2_generate_hdr(
|
||||
const char *cipherMode,
|
||||
const char *integrity,
|
||||
const char *uuid,
|
||||
unsigned int sector_size,
|
||||
unsigned int alignPayload,
|
||||
unsigned int alignOffset,
|
||||
unsigned int sector_size, /* in bytes */
|
||||
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;
|
||||
@@ -142,7 +142,7 @@ int LUKS2_generate_hdr(
|
||||
crypt_random_get(NULL, (char*)hdr->salt2, LUKS2_SALT_L, CRYPT_RND_SALT);
|
||||
|
||||
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
|
||||
log_err(cd, _("Wrong LUKS UUID format provided.\n"));
|
||||
log_err(cd, _("Wrong LUKS UUID format provided."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!uuid)
|
||||
@@ -182,11 +182,11 @@ int LUKS2_generate_hdr(
|
||||
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 * sector_size;
|
||||
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 * sector_size);
|
||||
offset = size_round_up(LUKS2_HDR_DEFAULT_LEN, (size_t)alignPayload);
|
||||
offset += alignOffset;
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ int LUKS2_generate_hdr(
|
||||
|
||||
/* for detached metadata device compute reasonable keyslot areas size */
|
||||
// FIXME: this is coupled with FIXME above
|
||||
if (detached_metadata_device)
|
||||
if (detached_metadata_device && !offset)
|
||||
keyslots_size = LUKS2_HDR_DEFAULT_LEN - get_min_offset(hdr);
|
||||
else
|
||||
keyslots_size = offset - get_min_offset(hdr);
|
||||
@@ -229,3 +229,44 @@ int LUKS2_generate_hdr(
|
||||
JSON_DBG(hdr->jobj, "Header JSON");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_wipe_header_areas(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr)
|
||||
{
|
||||
int r;
|
||||
uint64_t offset, length;
|
||||
size_t wipe_block;
|
||||
|
||||
/* Wipe complete header, keyslots and padding areas with zeroes. */
|
||||
offset = 0;
|
||||
length = LUKS2_get_data_offset(hdr) * SECTOR_SIZE;
|
||||
wipe_block = 1024 * 1024;
|
||||
|
||||
if (LUKS2_hdr_validate(hdr->jobj))
|
||||
return -EINVAL;
|
||||
|
||||
/* On detached header wipe at least the first 4k */
|
||||
if (length == 0) {
|
||||
length = 4096;
|
||||
wipe_block = 4096;
|
||||
}
|
||||
|
||||
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,
|
||||
offset, length, wipe_block, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Wipe keyslot area */
|
||||
wipe_block = 1024 * 1024;
|
||||
offset = get_min_offset(hdr);
|
||||
length = LUKS2_keyslots_size(hdr->jobj);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,8 @@ void JSON_DBG(json_object *jobj, const char *desc)
|
||||
/* FIXME: make this conditional and disable for stable release. */
|
||||
if (desc)
|
||||
log_dbg("%s:", desc);
|
||||
log_dbg("%s", json_object_to_json_string_ext(jobj, JSON_C_TO_STRING_PRETTY));
|
||||
log_dbg("%s", json_object_to_json_string_ext(jobj,
|
||||
JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -120,6 +121,16 @@ json_object *LUKS2_get_keyslot_jobj(struct luks2_hdr *hdr, int keyslot)
|
||||
return jobj2;
|
||||
}
|
||||
|
||||
json_object *LUKS2_get_tokens_jobj(struct luks2_hdr *hdr)
|
||||
{
|
||||
json_object *jobj_tokens;
|
||||
|
||||
if (!hdr || !json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens))
|
||||
return NULL;
|
||||
|
||||
return jobj_tokens;
|
||||
}
|
||||
|
||||
json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token)
|
||||
{
|
||||
json_object *jobj1, *jobj2;
|
||||
@@ -128,10 +139,11 @@ json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token)
|
||||
if (!hdr || token < 0)
|
||||
return NULL;
|
||||
|
||||
if (snprintf(token_name, sizeof(token_name), "%u", token) < 1)
|
||||
jobj1 = LUKS2_get_tokens_jobj(hdr);
|
||||
if (!jobj1)
|
||||
return NULL;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "tokens", &jobj1))
|
||||
if (snprintf(token_name, sizeof(token_name), "%u", token) < 1)
|
||||
return NULL;
|
||||
|
||||
json_object_object_get_ex(jobj1, token_name, &jobj2);
|
||||
@@ -240,8 +252,8 @@ static json_bool numbered(const char *name, const char *key)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static json_object *contains(json_object *jobj, const char *name,
|
||||
const char *section, const char *key, json_type type)
|
||||
json_object *json_contains(json_object *jobj, const char *name,
|
||||
const char *section, const char *key, json_type type)
|
||||
{
|
||||
json_object *sobj;
|
||||
|
||||
@@ -305,7 +317,8 @@ static json_bool validate_keyslots_array(json_object *jarr, json_object *jobj_ke
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!contains(jobj_keys, "", "Keyslots section", json_object_get_string(jobj), json_type_object))
|
||||
if (!json_contains(jobj_keys, "", "Keyslots section",
|
||||
json_object_get_string(jobj), json_type_object))
|
||||
return FALSE;
|
||||
|
||||
i++;
|
||||
@@ -326,7 +339,8 @@ static json_bool validate_segments_array(json_object *jarr, json_object *jobj_se
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!contains(jobj_segments, "", "Segments section", json_object_get_string(jobj), json_type_object))
|
||||
if (!json_contains(jobj_segments, "", "Segments section",
|
||||
json_object_get_string(jobj), json_type_object))
|
||||
return FALSE;
|
||||
|
||||
i++;
|
||||
@@ -393,9 +407,9 @@ int LUKS2_keyslot_validate(json_object *hdr_jobj, json_object *hdr_keyslot, cons
|
||||
{
|
||||
json_object *jobj_key_size;
|
||||
|
||||
if (!contains(hdr_keyslot, key, "Keyslot", "type", json_type_string))
|
||||
if (!json_contains(hdr_keyslot, key, "Keyslot", "type", json_type_string))
|
||||
return 1;
|
||||
if (!(jobj_key_size = contains(hdr_keyslot, key, "Keyslot", "key_size", json_type_int)))
|
||||
if (!(jobj_key_size = json_contains(hdr_keyslot, key, "Keyslot", "key_size", json_type_int)))
|
||||
return 1;
|
||||
|
||||
/* enforce uint32_t type */
|
||||
@@ -415,13 +429,14 @@ int LUKS2_token_validate(json_object *hdr_jobj, json_object *jobj_token, const c
|
||||
{
|
||||
json_object *jarr, *jobj_keyslots;
|
||||
|
||||
/* keyslots are not yet validated, but we need to know token doesn't reference missing keyslot */
|
||||
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
|
||||
return 1;
|
||||
|
||||
if (!contains(jobj_token, key, "Token", "type", json_type_string))
|
||||
if (!json_contains(jobj_token, key, "Token", "type", json_type_string))
|
||||
return 1;
|
||||
|
||||
jarr = contains(jobj_token, key, "Token", "keyslots", json_type_array);
|
||||
jarr = json_contains(jobj_token, key, "Token", "keyslots", json_type_array);
|
||||
if (!jarr)
|
||||
return 1;
|
||||
|
||||
@@ -434,11 +449,18 @@ int LUKS2_token_validate(json_object *hdr_jobj, json_object *jobj_token, const c
|
||||
static int hdr_validate_json_size(json_object *hdr_jobj)
|
||||
{
|
||||
json_object *jobj, *jobj1;
|
||||
const char *json;
|
||||
uint64_t json_area_size, json_size;
|
||||
|
||||
json_object_object_get_ex(hdr_jobj, "config", &jobj);
|
||||
json_object_object_get_ex(jobj, "json_size", &jobj1);
|
||||
|
||||
return (strlen(json_object_to_json_string_ext(hdr_jobj, JSON_C_TO_STRING_PLAIN)) > json_object_get_uint64(jobj1));
|
||||
json = json_object_to_json_string_ext(hdr_jobj,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
|
||||
json_area_size = json_object_get_uint64(jobj1);
|
||||
json_size = (uint64_t)strlen(json);
|
||||
|
||||
return json_size > json_area_size ? 1 : 0;
|
||||
}
|
||||
|
||||
int LUKS2_check_json_size(const struct luks2_hdr *hdr)
|
||||
@@ -484,12 +506,59 @@ static int hdr_validate_tokens(json_object *hdr_jobj)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdr_validate_crypt_segment(json_object *jobj, const char *key, json_object *jobj_digests,
|
||||
uint64_t offset, uint64_t size)
|
||||
{
|
||||
json_object *jobj_ivoffset, *jobj_sector_size, *jobj_integrity;
|
||||
uint32_t sector_size;
|
||||
uint64_t ivoffset;
|
||||
|
||||
if (!(jobj_ivoffset = json_contains(jobj, key, "Segment", "iv_tweak", json_type_string)) ||
|
||||
!json_contains(jobj, key, "Segment", "encryption", json_type_string) ||
|
||||
!(jobj_sector_size = json_contains(jobj, key, "Segment", "sector_size", json_type_int)))
|
||||
return 1;
|
||||
|
||||
/* integrity */
|
||||
if (json_object_object_get_ex(jobj, "integrity", &jobj_integrity)) {
|
||||
if (!json_contains(jobj, key, "Segment", "integrity", json_type_object) ||
|
||||
!json_contains(jobj_integrity, key, "Segment integrity", "type", json_type_string) ||
|
||||
!json_contains(jobj_integrity, key, "Segment integrity", "journal_encryption", json_type_string) ||
|
||||
!json_contains(jobj_integrity, key, "Segment integrity", "journal_integrity", json_type_string))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* enforce uint32_t type */
|
||||
if (!validate_json_uint32(jobj_sector_size)) {
|
||||
log_dbg("Illegal field \"sector_size\":%s.",
|
||||
json_object_get_string(jobj_sector_size));
|
||||
return 1;
|
||||
}
|
||||
|
||||
sector_size = json_object_get_uint32(jobj_sector_size);
|
||||
if (!sector_size || MISALIGNED_512(sector_size)) {
|
||||
log_dbg("Illegal sector size: %" PRIu32, sector_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!numbered("iv_tweak", json_object_get_string(jobj_ivoffset)) ||
|
||||
!json_str_to_uint64(jobj_ivoffset, &ivoffset)) {
|
||||
log_dbg("Illegal iv_tweak value.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (size % sector_size) {
|
||||
log_dbg("Size field has to be aligned to sector size: %" PRIu32, sector_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return !segment_has_digest(key, jobj_digests);
|
||||
}
|
||||
|
||||
static int hdr_validate_segments(json_object *hdr_jobj)
|
||||
{
|
||||
json_object *jobj, *jobj_digests, *jobj_offset, *jobj_ivoffset,
|
||||
*jobj_length, *jobj_sector_size, *jobj_type, *jobj_integrity;
|
||||
uint32_t sector_size;
|
||||
uint64_t ivoffset, offset, length;
|
||||
json_object *jobj, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags;
|
||||
int i;
|
||||
uint64_t offset, size;
|
||||
|
||||
if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj)) {
|
||||
log_dbg("Missing segments section.");
|
||||
@@ -509,70 +578,46 @@ static int hdr_validate_segments(json_object *hdr_jobj)
|
||||
if (!numbered("Segment", key))
|
||||
return 1;
|
||||
|
||||
if (!contains(val, key, "Segment", "type", json_type_string) ||
|
||||
!(jobj_offset = contains(val, key, "Segment", "offset", json_type_string)) ||
|
||||
!(jobj_ivoffset = contains(val, key, "Segment", "iv_tweak", json_type_string)) ||
|
||||
!(jobj_length = contains(val, key, "Segment", "size", json_type_string)) ||
|
||||
!contains(val, key, "Segment", "encryption", json_type_string) ||
|
||||
!(jobj_sector_size = contains(val, key, "Segment", "sector_size", json_type_int)))
|
||||
/* those fields are mandatory for all segment types */
|
||||
if (!(jobj_type = json_contains(val, key, "Segment", "type", json_type_string)) ||
|
||||
!(jobj_offset = json_contains(val, key, "Segment", "offset", json_type_string)) ||
|
||||
!(jobj_size = json_contains(val, key, "Segment", "size", json_type_string)))
|
||||
return 1;
|
||||
|
||||
/* integrity */
|
||||
if (json_object_object_get_ex(val, "integrity", &jobj_integrity)) {
|
||||
if (!contains(val, key, "Segment", "integrity", json_type_object) ||
|
||||
!contains(jobj_integrity, key, "Segment integrity", "type", json_type_string) ||
|
||||
!contains(jobj_integrity, key, "Segment integrity", "journal_encryption", json_type_string) ||
|
||||
!contains(jobj_integrity, key, "Segment integrity", "journal_integrity", json_type_string))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* enforce uint32_t type */
|
||||
if (!validate_json_uint32(jobj_sector_size)) {
|
||||
log_dbg("Illegal field \"sector_size\":%s.",
|
||||
json_object_get_string(jobj_sector_size));
|
||||
return 1;
|
||||
}
|
||||
|
||||
sector_size = json_object_get_uint32(jobj_sector_size);
|
||||
if (!sector_size || sector_size % 512) {
|
||||
log_dbg("Illegal sector size: %" PRIu32, sector_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!numbered("offset", json_object_get_string(jobj_offset)) ||
|
||||
!numbered("iv_tweak", json_object_get_string(jobj_ivoffset)))
|
||||
!json_str_to_uint64(jobj_offset, &offset))
|
||||
return 1;
|
||||
|
||||
/* rule out values > UINT64_MAX */
|
||||
if (!json_str_to_uint64(jobj_offset, &offset) ||
|
||||
!json_str_to_uint64(jobj_ivoffset, &ivoffset))
|
||||
return 1;
|
||||
|
||||
if (offset % sector_size) {
|
||||
log_dbg("Offset field has to be aligned to sector size: %" PRIu32, sector_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ivoffset % sector_size) {
|
||||
log_dbg("IV offset field has to be aligned to sector size: %" PRIu32, sector_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* length "dynamic" means whole device starting at 'offset' */
|
||||
if (strcmp(json_object_get_string(jobj_length), "dynamic")) {
|
||||
if (!numbered("size", json_object_get_string(jobj_length)) ||
|
||||
!json_str_to_uint64(jobj_length, &length))
|
||||
/* size "dynamic" means whole device starting at 'offset' */
|
||||
if (strcmp(json_object_get_string(jobj_size), "dynamic")) {
|
||||
if (!numbered("size", json_object_get_string(jobj_size)) ||
|
||||
!json_str_to_uint64(jobj_size, &size) || !size)
|
||||
return 1;
|
||||
} else
|
||||
size = 0;
|
||||
|
||||
if (length % sector_size) {
|
||||
log_dbg("Length field has to be aligned to sector size: %" PRIu32, sector_size);
|
||||
return 1;
|
||||
}
|
||||
/* all device-mapper devices are aligned to 512 sector size */
|
||||
if (MISALIGNED_512(offset)) {
|
||||
log_dbg("Offset field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
|
||||
return 1;
|
||||
}
|
||||
if (MISALIGNED_512(size)) {
|
||||
log_dbg("Size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
json_object_object_get_ex(val, "type", &jobj_type);
|
||||
/* flags array is optional and must contain strings */
|
||||
if (json_object_object_get_ex(val, "flags", NULL)) {
|
||||
if (!(jobj_flags = json_contains(val, key, "Segment", "flags", json_type_array)))
|
||||
return 1;
|
||||
for (i = 0; i < (int) json_object_array_length(jobj_flags); i++)
|
||||
if (!json_object_is_type(json_object_array_get_idx(jobj_flags, i), json_type_string))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* crypt */
|
||||
if (!strcmp(json_object_get_string(jobj_type), "crypt") &&
|
||||
!segment_has_digest(key, jobj_digests))
|
||||
hdr_validate_crypt_segment(val, key, jobj_digests, offset, size))
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -586,11 +631,10 @@ static int hdr_validate_areas(json_object *hdr_jobj)
|
||||
int length, ret, i = 0;
|
||||
uint64_t first_offset;
|
||||
|
||||
/* keyslots should already be validated */
|
||||
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
|
||||
return 1;
|
||||
|
||||
/* segments should already be validated */
|
||||
/* segments are already validated */
|
||||
if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
|
||||
return 1;
|
||||
|
||||
@@ -613,9 +657,9 @@ static int hdr_validate_areas(json_object *hdr_jobj)
|
||||
|
||||
json_object_object_foreach(jobj_keyslots, key, val) {
|
||||
|
||||
if (!(jobj_area = contains(val, key, "Keyslot", "area", json_type_object)) ||
|
||||
!(jobj_offset = contains(jobj_area, key, "Keyslot", "offset", json_type_string)) ||
|
||||
!(jobj_length = contains(jobj_area, key, "Keyslot", "size", json_type_string)) ||
|
||||
if (!(jobj_area = json_contains(val, key, "Keyslot", "area", json_type_object)) ||
|
||||
!(jobj_offset = json_contains(jobj_area, key, "Keyslot", "offset", json_type_string)) ||
|
||||
!(jobj_length = json_contains(jobj_area, key, "Keyslot", "size", json_type_string)) ||
|
||||
!numbered("offset", json_object_get_string(jobj_offset)) ||
|
||||
!numbered("size", json_object_get_string(jobj_length))) {
|
||||
free(intervals);
|
||||
@@ -655,11 +699,11 @@ static int hdr_validate_digests(json_object *hdr_jobj)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* keyslots should already be validated */
|
||||
/* keyslots are not yet validated, but we need to know digest doesn't reference missing keyslot */
|
||||
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
|
||||
return 1;
|
||||
|
||||
/* segments are not validated atm, but we need to know digest doesn't reference missing segment */
|
||||
/* segments are not yet validated, but we need to know digest doesn't reference missing segment */
|
||||
if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
|
||||
return 1;
|
||||
|
||||
@@ -667,9 +711,9 @@ static int hdr_validate_digests(json_object *hdr_jobj)
|
||||
if (!numbered("Digest", key))
|
||||
return 1;
|
||||
|
||||
if (!contains(val, key, "Digest", "type", json_type_string) ||
|
||||
!(jarr_keys = contains(val, key, "Digest", "keyslots", json_type_array)) ||
|
||||
!(jarr_segs = contains(val, key, "Digest", "segments", json_type_array)))
|
||||
if (!json_contains(val, key, "Digest", "type", json_type_string) ||
|
||||
!(jarr_keys = json_contains(val, key, "Digest", "keyslots", json_type_array)) ||
|
||||
!(jarr_segs = json_contains(val, key, "Digest", "segments", json_type_array)))
|
||||
return 1;
|
||||
|
||||
if (!validate_keyslots_array(jarr_keys, jobj_keyslots))
|
||||
@@ -690,7 +734,7 @@ static int validate_keyslots_size(json_object *hdr_jobj, json_object *jobj_keysl
|
||||
if (!json_str_to_uint64(jobj_keyslots_size, &keyslots_size))
|
||||
return 1;
|
||||
|
||||
if (keyslots_size % 4096) {
|
||||
if (MISALIGNED_4K(keyslots_size)) {
|
||||
log_dbg("keyslots_size is not 4 KiB aligned");
|
||||
return 1;
|
||||
}
|
||||
@@ -737,7 +781,7 @@ static int hdr_validate_config(json_object *hdr_jobj)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(jobj = contains(jobj_config, "section", "Config", "json_size", json_type_string)) ||
|
||||
if (!(jobj = json_contains(jobj_config, "section", "Config", "json_size", json_type_string)) ||
|
||||
!json_str_to_uint64(jobj, &json_size))
|
||||
return 1;
|
||||
|
||||
@@ -747,12 +791,12 @@ static int hdr_validate_config(json_object *hdr_jobj)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (json_size % 4096) {
|
||||
if (MISALIGNED_4K(json_size)) {
|
||||
log_dbg("Json area is not properly aligned to 4 KiB.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(jobj = contains(jobj_config, "section", "Config", "keyslots_size", json_type_string)))
|
||||
if (!(jobj = json_contains(jobj_config, "section", "Config", "keyslots_size", json_type_string)))
|
||||
return 1;
|
||||
|
||||
if (validate_keyslots_size(hdr_jobj, jobj))
|
||||
@@ -760,7 +804,7 @@ static int hdr_validate_config(json_object *hdr_jobj)
|
||||
|
||||
/* Flags array is optional */
|
||||
if (json_object_object_get_ex(jobj_config, "flags", &jobj)) {
|
||||
if (!contains(jobj_config, "section", "Config", "flags", json_type_array))
|
||||
if (!json_contains(jobj_config, "section", "Config", "flags", json_type_array))
|
||||
return 1;
|
||||
|
||||
/* All array members must be strings */
|
||||
@@ -771,12 +815,12 @@ static int hdr_validate_config(json_object *hdr_jobj)
|
||||
|
||||
/* Requirements object is optional */
|
||||
if (json_object_object_get_ex(jobj_config, "requirements", &jobj)) {
|
||||
if (!contains(jobj_config, "section", "Config", "requirements", json_type_object))
|
||||
if (!json_contains(jobj_config, "section", "Config", "requirements", json_type_object))
|
||||
return 1;
|
||||
|
||||
/* Mandatory array is optional */
|
||||
if (json_object_object_get_ex(jobj, "mandatory", &jobj1)) {
|
||||
if (!contains(jobj, "section", "Requirements", "mandatory", json_type_array))
|
||||
if (!json_contains(jobj, "section", "Requirements", "mandatory", json_type_array))
|
||||
return 1;
|
||||
|
||||
/* All array members must be strings */
|
||||
@@ -794,10 +838,10 @@ int LUKS2_hdr_validate(json_object *hdr_jobj)
|
||||
struct {
|
||||
int (*validate)(json_object *);
|
||||
} checks[] = {
|
||||
{ hdr_validate_keyslots },
|
||||
{ hdr_validate_tokens },
|
||||
{ hdr_validate_digests },
|
||||
{ hdr_validate_segments },
|
||||
{ hdr_validate_keyslots },
|
||||
{ hdr_validate_areas },
|
||||
{ hdr_validate_config },
|
||||
{ NULL }
|
||||
@@ -816,33 +860,38 @@ int LUKS2_hdr_validate(json_object *hdr_jobj)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* validate keyslot implementations */
|
||||
if (LUKS2_keyslots_validate(hdr_jobj))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr)
|
||||
/* FIXME: should we expose do_recovery parameter explicitly? */
|
||||
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = device_read_lock(cd, crypt_metadata_device(cd));
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
|
||||
log_err(cd, _("Failed to acquire read lock on device %s."),
|
||||
device_path(crypt_metadata_device(cd)));
|
||||
return r;
|
||||
}
|
||||
|
||||
r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1);
|
||||
r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1, !repair);
|
||||
if (r == -EAGAIN) {
|
||||
/* unlikely: auto-recovery is required and failed due to read lock being held */
|
||||
device_read_unlock(crypt_metadata_device(cd));
|
||||
|
||||
r = device_write_lock(cd, crypt_metadata_device(cd));
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."),
|
||||
device_path(crypt_metadata_device(cd)));
|
||||
return r;
|
||||
}
|
||||
|
||||
r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1);
|
||||
r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1, !repair);
|
||||
|
||||
device_write_unlock(crypt_metadata_device(cd));
|
||||
} else
|
||||
@@ -851,17 +900,11 @@ int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* NOTE: is called before LUKS2 validation routines */
|
||||
static void LUKS2_hdr_free_unused_objects(struct crypt_device *cd, struct luks2_hdr *hdr)
|
||||
{
|
||||
/* erase unused digests (no assigned keyslot or segment) */
|
||||
LUKS2_digests_erase_unused(cd, hdr);
|
||||
}
|
||||
|
||||
int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr)
|
||||
{
|
||||
/* FIXME: we risk to hide future internal implementation bugs with this */
|
||||
LUKS2_hdr_free_unused_objects(cd, hdr);
|
||||
/* NOTE: is called before LUKS2 validation routines */
|
||||
/* erase unused digests (no assigned keyslot or segment) */
|
||||
LUKS2_digests_erase_unused(cd, hdr);
|
||||
|
||||
if (LUKS2_hdr_validate(hdr->jobj))
|
||||
return -EINVAL;
|
||||
@@ -874,7 +917,7 @@ int LUKS2_hdr_uuid(struct crypt_device *cd, struct luks2_hdr *hdr, const char *u
|
||||
uuid_t partitionUuid;
|
||||
|
||||
if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
|
||||
log_err(cd, _("Wrong LUKS UUID format provided.\n"));
|
||||
log_err(cd, _("Wrong LUKS UUID format provided."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!uuid)
|
||||
@@ -954,7 +997,7 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
|
||||
r = device_read_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
|
||||
log_err(cd, _("Failed to acquire read lock on device %s."),
|
||||
device_path(crypt_metadata_device(cd)));
|
||||
crypt_safe_free(buffer);
|
||||
return r;
|
||||
@@ -963,7 +1006,7 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
devfd = device_open_locked(device, O_RDONLY);
|
||||
if (devfd < 0) {
|
||||
device_read_unlock(device);
|
||||
log_err(cd, _("Device %s is not a valid LUKS device.\n"), device_path(device));
|
||||
log_err(cd, _("Device %s is not a valid LUKS device."), device_path(device));
|
||||
crypt_safe_free(buffer);
|
||||
return devfd == -1 ? -EINVAL : devfd;
|
||||
}
|
||||
@@ -982,14 +1025,14 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
|
||||
if (devfd == -1) {
|
||||
if (errno == EEXIST)
|
||||
log_err(cd, _("Requested header backup file %s already exists.\n"), backup_file);
|
||||
log_err(cd, _("Requested header backup file %s already exists."), backup_file);
|
||||
else
|
||||
log_err(cd, _("Cannot create header backup file %s.\n"), backup_file);
|
||||
log_err(cd, _("Cannot create header backup file %s."), backup_file);
|
||||
crypt_safe_free(buffer);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (write_buffer(devfd, buffer, buffer_size) < buffer_size) {
|
||||
log_err(cd, _("Cannot write header backup file %s.\n"), backup_file);
|
||||
log_err(cd, _("Cannot write header backup file %s."), backup_file);
|
||||
r = -EIO;
|
||||
} else
|
||||
r = 0;
|
||||
@@ -1027,24 +1070,24 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
/* FIXME: why lock backup device ? */
|
||||
r = device_read_lock(cd, backup_device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
|
||||
log_err(cd, _("Failed to acquire read lock on device %s."),
|
||||
device_path(backup_device));
|
||||
device_free(backup_device);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = LUKS2_disk_hdr_read(cd, &hdr_file, backup_device, 0);
|
||||
r = LUKS2_disk_hdr_read(cd, &hdr_file, backup_device, 0, 0);
|
||||
device_read_unlock(backup_device);
|
||||
device_free(backup_device);
|
||||
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Backup file doesn't contain valid LUKS header.\n"));
|
||||
log_err(cd, _("Backup file doesn't contain valid LUKS header."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* do not allow header restore from backup with unmet requirements */
|
||||
if (LUKS2_unmet_requirements(cd, &hdr_file, 0, 1)) {
|
||||
log_err(cd, _("Forbidden LUKS2 requirements detected in backup %s.\n"),
|
||||
log_err(cd, _("Forbidden LUKS2 requirements detected in backup %s."),
|
||||
backup_file);
|
||||
r = -ETXTBSY;
|
||||
goto out;
|
||||
@@ -1059,20 +1102,20 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
|
||||
devfd = open(backup_file, O_RDONLY);
|
||||
if (devfd == -1) {
|
||||
log_err(cd, _("Cannot open header backup file %s.\n"), backup_file);
|
||||
log_err(cd, _("Cannot open header backup file %s."), backup_file);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (read_buffer(devfd, buffer, buffer_size) < buffer_size) {
|
||||
log_err(cd, _("Cannot read header backup file %s.\n"), backup_file);
|
||||
log_err(cd, _("Cannot read header backup file %s."), backup_file);
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
close(devfd);
|
||||
devfd = -1;
|
||||
|
||||
r = LUKS2_hdr_read(cd, &tmp_hdr);
|
||||
r = LUKS2_hdr_read(cd, &tmp_hdr, 0);
|
||||
if (r == 0) {
|
||||
log_dbg("Device %s already contains LUKS2 header, checking UUID and requirements.", device_path(device));
|
||||
r = LUKS2_config_get_requirements(cd, &tmp_hdr, &reqs);
|
||||
@@ -1085,13 +1128,13 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
if (!reqs_reencrypt(reqs)) {
|
||||
log_dbg("Checking LUKS2 header size and offsets.");
|
||||
if (LUKS2_get_data_offset(&tmp_hdr) != LUKS2_get_data_offset(&hdr_file)) {
|
||||
log_err(cd, _("Data offset differ on device and backup, restore failed.\n"));
|
||||
log_err(cd, _("Data offset differ on device and backup, restore failed."));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/* FIXME: what could go wrong? Erase if we're fine with consequences */
|
||||
if (buffer_size != (ssize_t) LUKS2_hdr_and_areas_size(tmp_hdr.jobj)) {
|
||||
log_err(cd, _("Binary header with keyslot areas size differ on device and backup, restore failed.\n"));
|
||||
log_err(cd, _("Binary header with keyslot areas size differ on device and backup, restore failed."));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1121,7 +1164,7 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
/* TODO: perform header restore on bdev in stand-alone routine? */
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."),
|
||||
device_path(device));
|
||||
goto out;
|
||||
}
|
||||
@@ -1129,10 +1172,10 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
devfd = device_open_locked(device, O_RDWR);
|
||||
if (devfd < 0) {
|
||||
if (errno == EACCES)
|
||||
log_err(cd, _("Cannot write to device %s, permission denied.\n"),
|
||||
log_err(cd, _("Cannot write to device %s, permission denied."),
|
||||
device_path(device));
|
||||
else
|
||||
log_err(cd, _("Cannot open device %s.\n"), device_path(device));
|
||||
log_err(cd, _("Cannot open device %s."), device_path(device));
|
||||
device_write_unlock(device);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
@@ -1148,20 +1191,19 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
/* end of TODO */
|
||||
|
||||
out:
|
||||
LUKS2_hdr_free(hdr);
|
||||
LUKS2_hdr_free(&hdr_file);
|
||||
LUKS2_hdr_free(&tmp_hdr);
|
||||
crypt_memzero(&hdr_file, sizeof(hdr_file));
|
||||
crypt_memzero(&tmp_hdr, sizeof(tmp_hdr));
|
||||
crypt_safe_free(buffer);
|
||||
|
||||
if (devfd >= 0)
|
||||
if (devfd >= 0) {
|
||||
device_sync(device, devfd);
|
||||
close(devfd);
|
||||
|
||||
if (!r) {
|
||||
LUKS2_hdr_free(hdr);
|
||||
r = LUKS2_hdr_read(cd, hdr);
|
||||
}
|
||||
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1206,7 +1248,7 @@ int LUKS2_config_get_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
|
||||
found = 1;
|
||||
}
|
||||
if (!found)
|
||||
log_verbose(cd, _("Ignored unknown flag %s.\n"),
|
||||
log_verbose(cd, _("Ignored unknown flag %s."),
|
||||
json_object_get_string(jobj1));
|
||||
}
|
||||
|
||||
@@ -1498,40 +1540,56 @@ static void hdr_dump_tokens(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: sort segments when more segments available later */
|
||||
static void hdr_dump_segments(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
{
|
||||
json_object *jobj1, *jobj2, *jobj3;
|
||||
char segment[16];
|
||||
json_object *jobj_segments, *jobj_segment, *jobj1, *jobj2;
|
||||
int i, j, flags;
|
||||
uint64_t value;
|
||||
|
||||
log_std(cd, "Data segments:\n");
|
||||
json_object_object_get_ex(hdr_jobj, "segments", &jobj1);
|
||||
json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments);
|
||||
|
||||
json_object_object_foreach(jobj1, key, val) {
|
||||
json_object_object_get_ex(val, "type", &jobj2);
|
||||
log_std(cd, " %s: %s\n", key, json_object_get_string(jobj2));
|
||||
for (i = 0; i < LUKS2_SEGMENT_MAX; i++) {
|
||||
(void) snprintf(segment, sizeof(segment), "%i", i);
|
||||
if (!json_object_object_get_ex(jobj_segments, segment, &jobj_segment))
|
||||
continue;
|
||||
|
||||
json_object_object_get_ex(val, "offset", &jobj3);
|
||||
json_str_to_uint64(jobj3, &value);
|
||||
json_object_object_get_ex(jobj_segment, "type", &jobj1);
|
||||
log_std(cd, " %s: %s\n", segment, json_object_get_string(jobj1));
|
||||
|
||||
json_object_object_get_ex(jobj_segment, "offset", &jobj1);
|
||||
json_str_to_uint64(jobj1, &value);
|
||||
log_std(cd, "\toffset: %" PRIu64 " [bytes]\n", value);
|
||||
|
||||
json_object_object_get_ex(val, "size", &jobj3);
|
||||
if (!(strcmp(json_object_get_string(jobj3), "dynamic")))
|
||||
json_object_object_get_ex(jobj_segment, "size", &jobj1);
|
||||
if (!(strcmp(json_object_get_string(jobj1), "dynamic")))
|
||||
log_std(cd, "\tlength: (whole device)\n");
|
||||
else {
|
||||
json_str_to_uint64(jobj3, &value);
|
||||
json_str_to_uint64(jobj1, &value);
|
||||
log_std(cd, "\tlength: %" PRIu64 " [bytes]\n", value);
|
||||
}
|
||||
|
||||
json_object_object_get_ex(val, "encryption", &jobj3);
|
||||
log_std(cd, "\tcipher: %s\n", json_object_get_string(jobj3));
|
||||
if (json_object_object_get_ex(jobj_segment, "encryption", &jobj1))
|
||||
log_std(cd, "\tcipher: %s\n", json_object_get_string(jobj1));
|
||||
|
||||
json_object_object_get_ex(val, "sector_size", &jobj3);
|
||||
log_std(cd, "\tsector: %" PRIu32 " [bytes]\n", json_object_get_uint32(jobj3));
|
||||
if (json_object_object_get_ex(jobj_segment, "sector_size", &jobj1))
|
||||
log_std(cd, "\tsector: %" PRIu32 " [bytes]\n", json_object_get_uint32(jobj1));
|
||||
|
||||
if (json_object_object_get_ex(val, "integrity", &jobj2) &&
|
||||
json_object_object_get_ex(jobj2, "type", &jobj3))
|
||||
log_std(cd, "\tintegrity: %s\n", json_object_get_string(jobj3));
|
||||
if (json_object_object_get_ex(jobj_segment, "integrity", &jobj1) &&
|
||||
json_object_object_get_ex(jobj1, "type", &jobj2))
|
||||
log_std(cd, "\tintegrity: %s\n", json_object_get_string(jobj2));
|
||||
|
||||
if (json_object_object_get_ex(jobj_segment, "flags", &jobj1) &&
|
||||
(flags = (int)json_object_array_length(jobj1)) > 0) {
|
||||
jobj2 = json_object_array_get_idx(jobj1, 0);
|
||||
log_std(cd, "\tflags : %s", json_object_get_string(jobj2));
|
||||
for (j = 1; j < flags; j++) {
|
||||
jobj2 = json_object_array_get_idx(jobj1, j);
|
||||
log_std(cd, ", %s", json_object_get_string(jobj2));
|
||||
}
|
||||
log_std(cd, "\n");
|
||||
}
|
||||
|
||||
log_std(cd, "\n");
|
||||
}
|
||||
@@ -1609,10 +1667,12 @@ const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment)
|
||||
if (!json_object_object_get_ex(jobj1, buf, &jobj2))
|
||||
return NULL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj2, "encryption", &jobj3))
|
||||
return NULL;
|
||||
if (json_object_object_get_ex(jobj2, "encryption", &jobj3))
|
||||
return json_object_get_string(jobj3);
|
||||
|
||||
/* FIXME: default encryption (for other segment types) must be string here. */
|
||||
return "null";
|
||||
|
||||
return json_object_get_string(jobj3);
|
||||
}
|
||||
|
||||
static int luks2_keyslot_af_params(json_object *jobj_af, struct luks2_keyslot_params *params)
|
||||
@@ -1743,13 +1803,13 @@ static int LUKS2_keyslot_get_volume_key_size(struct luks2_hdr *hdr, const char *
|
||||
json_object *jobj1, *jobj2, *jobj3;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj1))
|
||||
return 0;
|
||||
return -1;
|
||||
|
||||
if (!json_object_object_get_ex(jobj1, keyslot, &jobj2))
|
||||
return 0;
|
||||
return -1;
|
||||
|
||||
if (!json_object_object_get_ex(jobj2, "key_size", &jobj3))
|
||||
return 0;
|
||||
return -1;
|
||||
|
||||
return json_object_get_int(jobj3);
|
||||
}
|
||||
@@ -1850,7 +1910,7 @@ int LUKS2_activate(struct crypt_device *cd,
|
||||
|
||||
if (dmd.u.crypt.tag_size) {
|
||||
if (!LUKS2_integrity_compatible(hdr)) {
|
||||
log_err(cd, "Unsupported device integrity configuration.\n");
|
||||
log_err(cd, "Unsupported device integrity configuration.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1877,7 +1937,7 @@ int LUKS2_activate(struct crypt_device *cd,
|
||||
crypt_get_data_offset(cd) * SECTOR_SIZE,
|
||||
&dmd.size);
|
||||
if (r < 0) {
|
||||
log_err(cd, "Cannot detect integrity device size.\n");
|
||||
log_err(cd, "Cannot detect integrity device size.");
|
||||
device_free(device);
|
||||
dm_remove_device(cd, dm_int_name, 0);
|
||||
return r;
|
||||
@@ -1903,14 +1963,14 @@ int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uin
|
||||
|
||||
if (r) {
|
||||
if (!quiet)
|
||||
log_err(cd, _("Failed to read LUKS2 requirements.\n"));
|
||||
log_err(cd, _("Failed to read LUKS2 requirements."));
|
||||
return r;
|
||||
}
|
||||
|
||||
/* do not mask unknown requirements check */
|
||||
if (reqs_unknown(reqs)) {
|
||||
if (!quiet)
|
||||
log_err(cd, _("Unmet LUKS2 requirements detected.\n"));
|
||||
log_err(cd, _("Unmet LUKS2 requirements detected."));
|
||||
return -ETXTBSY;
|
||||
}
|
||||
|
||||
@@ -1918,8 +1978,31 @@ int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uin
|
||||
reqs &= ~reqs_mask;
|
||||
|
||||
if (reqs_reencrypt(reqs) && !quiet)
|
||||
log_err(cd, _("Offline reencryption in progress. Aborting.\n"));
|
||||
log_err(cd, _("Offline reencryption in progress. Aborting."));
|
||||
|
||||
/* any remaining unmasked requirement fails the check */
|
||||
return reqs ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: this routine is called on json object that failed validation.
|
||||
* Proceed with caution :)
|
||||
*
|
||||
* known glitches so far:
|
||||
*
|
||||
* any version < 2.0.3:
|
||||
* - luks2 keyslot pbkdf params change via crypt_keyslot_change_by_passphrase()
|
||||
* could leave previous type parameters behind. Correct this by purging
|
||||
* all params not needed by current type.
|
||||
*/
|
||||
void LUKS2_hdr_repair(json_object *hdr_jobj)
|
||||
{
|
||||
json_object *jobj_keyslots;
|
||||
|
||||
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
|
||||
return;
|
||||
if (!json_object_is_type(jobj_keyslots, json_type_object))
|
||||
return;
|
||||
|
||||
LUKS2_keyslots_repair(jobj_keyslots);
|
||||
}
|
||||
|
||||
@@ -63,14 +63,6 @@ static const keyslot_handler
|
||||
return LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj2));
|
||||
}
|
||||
|
||||
static crypt_keyslot_info LUKS2_keyslot_active(struct luks2_hdr *hdr, int keyslot)
|
||||
{
|
||||
if (keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return CRYPT_SLOT_INVALID;
|
||||
|
||||
return LUKS2_get_keyslot_jobj(hdr, keyslot) ? CRYPT_SLOT_ACTIVE : CRYPT_SLOT_INACTIVE;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
|
||||
{
|
||||
int i;
|
||||
@@ -82,6 +74,7 @@ int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if a keyslot is asssigned to specific segment */
|
||||
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
|
||||
{
|
||||
int keyslot_digest, segment_digest;
|
||||
@@ -96,11 +89,12 @@ int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
|
||||
|
||||
segment_digest = LUKS2_digest_by_segment(NULL, hdr, segment);
|
||||
if (segment_digest < 0)
|
||||
return -EINVAL;
|
||||
return segment_digest;
|
||||
|
||||
return segment_digest == keyslot_digest ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
/* Number of keyslots assigned to a segment or all keyslots for CRYPT_ANY_SEGMENT */
|
||||
int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
|
||||
{
|
||||
int num = 0;
|
||||
@@ -117,6 +111,21 @@ int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
|
||||
return num;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd)
|
||||
{
|
||||
const char *cipher = crypt_get_cipher(cd);
|
||||
|
||||
/* Keyslot is already authenticated; we cannot use integrity tags here */
|
||||
if (crypt_get_integrity_tag_size(cd) || !cipher)
|
||||
return 1;
|
||||
|
||||
/* Wrapped key schemes cannot be used for keyslot encryption */
|
||||
if (crypt_cipher_wrapped_key(cipher))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
size_t key_size, struct luks2_keyslot_params *params)
|
||||
{
|
||||
@@ -140,7 +149,7 @@ int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
|
||||
/* set keyslot area encryption parameters */
|
||||
/* short circuit authenticated encryption hardcoded defaults */
|
||||
if (crypt_get_integrity_tag_size(cd) || key_size == 0) {
|
||||
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");
|
||||
@@ -161,18 +170,38 @@ int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int LUKS2_keyslot_unbound(struct luks2_hdr *hdr, int keyslot)
|
||||
{
|
||||
json_object *jobj_digest, *jobj_segments;
|
||||
int digest = LUKS2_digest_by_keyslot(NULL, hdr, keyslot);
|
||||
|
||||
if (digest < 0)
|
||||
return 0;
|
||||
|
||||
if (!(jobj_digest = LUKS2_get_digest_jobj(hdr, digest)))
|
||||
return 0;
|
||||
|
||||
json_object_object_get_ex(jobj_digest, "segments", &jobj_segments);
|
||||
if (!jobj_segments || !json_object_is_type(jobj_segments, json_type_array) ||
|
||||
json_object_array_length(jobj_segments) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot)
|
||||
{
|
||||
crypt_keyslot_info ki;
|
||||
|
||||
if(keyslot >= LUKS2_KEYSLOTS_MAX || keyslot < 0)
|
||||
return CRYPT_SLOT_INVALID;
|
||||
|
||||
ki = LUKS2_keyslot_active(hdr, keyslot);
|
||||
if (ki != CRYPT_SLOT_ACTIVE)
|
||||
return ki;
|
||||
if (!LUKS2_get_keyslot_jobj(hdr, keyslot))
|
||||
return CRYPT_SLOT_INACTIVE;
|
||||
|
||||
if (LUKS2_keyslot_active_count(hdr, CRYPT_DEFAULT_SEGMENT) == 1 && !LUKS2_keyslot_for_segment(hdr, keyslot, CRYPT_DEFAULT_SEGMENT))
|
||||
if (LUKS2_keyslot_unbound(hdr, keyslot))
|
||||
return CRYPT_SLOT_UNBOUND;
|
||||
|
||||
if (LUKS2_keyslot_active_count(hdr, CRYPT_DEFAULT_SEGMENT) == 1 &&
|
||||
!LUKS2_keyslot_for_segment(hdr, keyslot, CRYPT_DEFAULT_SEGMENT))
|
||||
return CRYPT_SLOT_ACTIVE_LAST;
|
||||
|
||||
return CRYPT_SLOT_ACTIVE;
|
||||
@@ -220,6 +249,12 @@ static int LUKS2_open_and_verify(struct crypt_device *cd,
|
||||
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
|
||||
return -ENOENT;
|
||||
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
log_dbg("Keyslot %d validation failed.", keyslot);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = LUKS2_keyslot_for_segment(hdr, keyslot, segment);
|
||||
if (r) {
|
||||
if (r == -ENOENT)
|
||||
@@ -343,10 +378,18 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
r = h->alloc(cd, keyslot, vk->keylength, params);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
|
||||
return -EINVAL;
|
||||
|
||||
r = h->validate(cd, keyslot);
|
||||
r = h->update(cd, keyslot, params);
|
||||
if (r) {
|
||||
log_dbg("Failed to update keyslot %d json.", keyslot);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
log_dbg("Keyslot validation failed.");
|
||||
return r;
|
||||
@@ -383,7 +426,7 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
/* Just check that nobody uses the metadata now */
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."),
|
||||
device_path(device));
|
||||
return r;
|
||||
}
|
||||
@@ -400,11 +443,11 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
area_length, area_length, NULL, NULL);
|
||||
if (r) {
|
||||
if (r == -EACCES) {
|
||||
log_err(cd, _("Cannot write to device %s, permission denied.\n"),
|
||||
log_err(cd, _("Cannot write to device %s, permission denied."),
|
||||
device_path(device));
|
||||
r = -EINVAL;
|
||||
} else
|
||||
log_err(cd, _("Cannot wipe device %s.\n"), device_path(device));
|
||||
log_err(cd, _("Cannot wipe device %s."), device_path(device));
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -467,3 +510,119 @@ int LUKS2_keyslot_priority_set(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
|
||||
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
|
||||
}
|
||||
|
||||
int placeholder_keyslot_alloc(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
uint64_t area_offset,
|
||||
uint64_t area_length,
|
||||
size_t volume_key_len)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
char num[16];
|
||||
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
|
||||
|
||||
log_dbg("Allocating placeholder keyslot %d for LUKS1 down conversion.", keyslot);
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (LUKS2_get_keyslot_jobj(hdr, keyslot))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_keyslot = json_object_new_object();
|
||||
json_object_object_add(jobj_keyslot, "type", json_object_new_string("placeholder"));
|
||||
/*
|
||||
* key_size = -1 makes placeholder keyslot impossible to pass validation.
|
||||
* It's a safeguard against accidentally storing temporary conversion
|
||||
* LUKS2 header.
|
||||
*/
|
||||
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(-1));
|
||||
|
||||
/* Area object */
|
||||
jobj_area = json_object_new_object();
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_uint64(area_offset));
|
||||
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_length));
|
||||
json_object_object_add(jobj_keyslot, "area", jobj_area);
|
||||
|
||||
snprintf(num, sizeof(num), "%d", keyslot);
|
||||
|
||||
json_object_object_add(jobj_keyslots, num, jobj_keyslot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned LUKS2_get_keyslot_digests_count(json_object *hdr_jobj, int keyslot)
|
||||
{
|
||||
char num[16];
|
||||
json_object *jobj_digests, *jobj_keyslots;
|
||||
unsigned count = 0;
|
||||
|
||||
if (!json_object_object_get_ex(hdr_jobj, "digests", &jobj_digests))
|
||||
return 0;
|
||||
|
||||
if (snprintf(num, sizeof(num), "%u", keyslot) < 0)
|
||||
return 0;
|
||||
|
||||
json_object_object_foreach(jobj_digests, key, val) {
|
||||
UNUSED(key);
|
||||
json_object_object_get_ex(val, "keyslots", &jobj_keyslots);
|
||||
if (LUKS2_array_jobj(jobj_keyslots, num))
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* run only on header that passed basic format validation */
|
||||
int LUKS2_keyslots_validate(json_object *hdr_jobj)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int keyslot;
|
||||
json_object *jobj_keyslots, *jobj_type;
|
||||
|
||||
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_foreach(jobj_keyslots, slot, val) {
|
||||
keyslot = atoi(slot);
|
||||
json_object_object_get_ex(val, "type", &jobj_type);
|
||||
h = LUKS2_keyslot_handler_type(NULL, json_object_get_string(jobj_type));
|
||||
if (!h)
|
||||
continue;
|
||||
if (h->validate && h->validate(NULL, val)) {
|
||||
log_dbg("Keyslot type %s validation failed on keyslot %d.", h->name, keyslot);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(h->name, "luks2") && LUKS2_get_keyslot_digests_count(hdr_jobj, keyslot) != 1) {
|
||||
log_dbg("Keyslot %d is not assigned to exactly 1 digest.", keyslot);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LUKS2_keyslots_repair(json_object *jobj_keyslots)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
json_object *jobj_type;
|
||||
|
||||
json_object_object_foreach(jobj_keyslots, slot, val) {
|
||||
UNUSED(slot);
|
||||
if (!json_object_is_type(val, json_type_object) ||
|
||||
!json_object_object_get_ex(val, "type", &jobj_type) ||
|
||||
!json_object_is_type(jobj_type, json_type_string))
|
||||
continue;
|
||||
|
||||
h = LUKS2_keyslot_handler_type(NULL, json_object_get_string(jobj_type));
|
||||
if (h && h->repair)
|
||||
h->repair(NULL, val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
|
||||
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
|
||||
int r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s.\n"), device_path(device));
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."), device_path(device));
|
||||
return r;
|
||||
}
|
||||
r = LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd);
|
||||
@@ -48,7 +48,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
|
||||
int devfd = -1, r;
|
||||
|
||||
/* Only whole sector writes supported */
|
||||
if (srcLength % SECTOR_SIZE)
|
||||
if (MISALIGNED_512(srcLength))
|
||||
return -EINVAL;
|
||||
|
||||
/* Encrypt buffer */
|
||||
@@ -66,7 +66,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
|
||||
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s.\n"),
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."),
|
||||
device_path(device));
|
||||
return r;
|
||||
}
|
||||
@@ -79,6 +79,8 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
|
||||
r = -EIO;
|
||||
else
|
||||
r = 0;
|
||||
|
||||
device_sync(device, devfd);
|
||||
close(devfd);
|
||||
} else
|
||||
r = -EIO;
|
||||
@@ -86,7 +88,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
|
||||
device_write_unlock(device);
|
||||
|
||||
if (r)
|
||||
log_err(cd, _("IO error while encrypting keyslot.\n"));
|
||||
log_err(cd, _("IO error while encrypting keyslot."));
|
||||
|
||||
return r;
|
||||
#endif
|
||||
@@ -100,7 +102,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
|
||||
int r = device_read_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire read lock on device %s.\n"), device_path(device));
|
||||
log_err(cd, _("Failed to acquire read lock on device %s."), device_path(device));
|
||||
return r;
|
||||
}
|
||||
r = LUKS_decrypt_from_storage(dst, dstLength, cipher, cipher_mode, vk, sector, cd);
|
||||
@@ -111,7 +113,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
int devfd = -1, r;
|
||||
|
||||
/* Only whole sector writes supported */
|
||||
if (dstLength % SECTOR_SIZE)
|
||||
if (MISALIGNED_512(dstLength))
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_storage_init(&s, 0, cipher, cipher_mode, vk->key, vk->keylength);
|
||||
@@ -123,7 +125,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
|
||||
r = device_read_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire read lock on device %s.\n"),
|
||||
log_err(cd, _("Failed to acquire read lock on device %s."),
|
||||
device_path(device));
|
||||
crypt_storage_destroy(s);
|
||||
return r;
|
||||
@@ -147,13 +149,64 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
|
||||
if (!r)
|
||||
r = crypt_storage_decrypt(s, 0, dstLength / SECTOR_SIZE, dst);
|
||||
else
|
||||
log_err(cd, _("IO error while decrypting keyslot.\n"));
|
||||
log_err(cd, _("IO error while decrypting keyslot."));
|
||||
|
||||
crypt_storage_destroy(s);
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int luks2_keyslot_get_pbkdf_params(json_object *jobj_keyslot,
|
||||
struct crypt_pbkdf_type *pbkdf, char *salt)
|
||||
{
|
||||
json_object *jobj_kdf, *jobj1, *jobj2;
|
||||
size_t salt_len;
|
||||
|
||||
if (!jobj_keyslot || !pbkdf)
|
||||
return -EINVAL;
|
||||
|
||||
memset(pbkdf, 0, sizeof(*pbkdf));
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
pbkdf->type = json_object_get_string(jobj1);
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
if (!json_object_object_get_ex(jobj_kdf, "hash", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->hash = json_object_get_string(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "iterations", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->iterations = json_object_get_int(jobj2);
|
||||
pbkdf->max_memory_kb = 0;
|
||||
pbkdf->parallel_threads = 0;
|
||||
} else {
|
||||
if (!json_object_object_get_ex(jobj_kdf, "time", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->iterations = json_object_get_int(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "memory", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->max_memory_kb = json_object_get_int(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "cpus", &jobj2))
|
||||
return -EINVAL;
|
||||
pbkdf->parallel_threads = json_object_get_int(jobj2);
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj2))
|
||||
return -EINVAL;
|
||||
salt_len = LUKS_SALTSIZE;
|
||||
if (!base64_decode(json_object_get_string(jobj2),
|
||||
json_object_get_string_len(jobj2),
|
||||
salt, &salt_len))
|
||||
return -EINVAL;
|
||||
if (salt_len != LUKS_SALTSIZE)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
json_object *jobj_keyslot,
|
||||
const char *password, size_t passwordLen,
|
||||
@@ -161,11 +214,12 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
{
|
||||
struct volume_key *derived_key;
|
||||
char salt[LUKS_SALTSIZE], cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
|
||||
char *AfKey = NULL, *salt_base64 = NULL;
|
||||
char *AfKey = NULL;
|
||||
const char *af_hash = NULL;
|
||||
size_t AFEKSize, keyslot_key_len;
|
||||
json_object *jobj2, *jobj_kdf, *jobj_af, *jobj_area;
|
||||
uint64_t area_offset;
|
||||
const struct crypt_pbkdf_type *pbkdf;
|
||||
struct crypt_pbkdf_type pbkdf;
|
||||
int r;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
@@ -173,6 +227,12 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return -EINVAL;
|
||||
|
||||
/* prevent accidental volume key size change after allocation */
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "key_size", &jobj2))
|
||||
return -EINVAL;
|
||||
if (json_object_get_int(jobj2) != (int)volume_key_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "offset", &jobj2))
|
||||
return -EINVAL;
|
||||
area_offset = json_object_get_uint64(jobj2);
|
||||
@@ -187,52 +247,27 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
keyslot_key_len = json_object_get_int(jobj2);
|
||||
|
||||
pbkdf = crypt_get_pbkdf_type(cd);
|
||||
if (!pbkdf)
|
||||
if (!json_object_object_get_ex(jobj_af, "hash", &jobj2))
|
||||
return -EINVAL;
|
||||
af_hash = json_object_get_string(jobj2);
|
||||
|
||||
if (luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, salt))
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, volume_key_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
json_object_object_add(jobj_kdf, "hash", json_object_new_string(pbkdf->hash));
|
||||
json_object_object_add(jobj_kdf, "iterations", json_object_new_int(pbkdf->iterations));
|
||||
} else {
|
||||
json_object_object_add(jobj_kdf, "time", json_object_new_int(pbkdf->iterations));
|
||||
json_object_object_add(jobj_kdf, "memory", json_object_new_int(pbkdf->max_memory_kb));
|
||||
json_object_object_add(jobj_kdf, "cpus", json_object_new_int(pbkdf->parallel_threads));
|
||||
}
|
||||
|
||||
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
|
||||
|
||||
/*
|
||||
* Get salt and allocate derived key storage.
|
||||
* Allocate derived key storage.
|
||||
*/
|
||||
r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
base64_encode_alloc(salt, LUKS_SALTSIZE, &salt_base64);
|
||||
if (!salt_base64)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_kdf, "salt", json_object_new_string(salt_base64));
|
||||
free(salt_base64);
|
||||
|
||||
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
|
||||
|
||||
json_object_object_add(jobj_af, "hash", json_object_new_string(pbkdf->hash));
|
||||
|
||||
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
|
||||
if (!derived_key)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* Calculate keyslot content, split and store it to keyslot area.
|
||||
*/
|
||||
r = crypt_pbkdf(pbkdf->type, pbkdf->hash, password, passwordLen,
|
||||
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
|
||||
salt, LUKS_SALTSIZE,
|
||||
derived_key->key, derived_key->keylength,
|
||||
pbkdf->iterations, pbkdf->max_memory_kb,
|
||||
pbkdf->parallel_threads);
|
||||
pbkdf.iterations, pbkdf.max_memory_kb,
|
||||
pbkdf.parallel_threads);
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(derived_key);
|
||||
return r;
|
||||
@@ -246,7 +281,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = AF_split(volume_key, AfKey, volume_key_len, LUKS_STRIPES, pbkdf->hash);
|
||||
r = AF_split(volume_key, AfKey, volume_key_len, LUKS_STRIPES, af_hash);
|
||||
|
||||
if (r == 0) {
|
||||
log_dbg("Updating keyslot area [0x%04x].", (unsigned)area_offset);
|
||||
@@ -260,7 +295,6 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
JSON_DBG(jobj_keyslot, "Keyslot JSON");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -270,53 +304,21 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
char *volume_key, size_t volume_key_len)
|
||||
{
|
||||
struct volume_key *derived_key;
|
||||
struct crypt_pbkdf_type pbkdf;
|
||||
char *AfKey;
|
||||
size_t AFEKSize;
|
||||
const char *hash = NULL, *af_hash = NULL, *kdf;
|
||||
const char *af_hash = NULL;
|
||||
char salt[LUKS_SALTSIZE], cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
|
||||
json_object *jobj1, *jobj2, *jobj_kdf, *jobj_af, *jobj_area;
|
||||
uint32_t iterations, memory, parallel;
|
||||
json_object *jobj2, *jobj_af, *jobj_area;
|
||||
uint64_t area_offset;
|
||||
size_t salt_len, keyslot_key_len;
|
||||
size_t keyslot_key_len;
|
||||
int r;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
kdf = json_object_get_string(jobj1);
|
||||
if (!strcmp(kdf, CRYPT_KDF_PBKDF2)) {
|
||||
if (!json_object_object_get_ex(jobj_kdf, "hash", &jobj2))
|
||||
return -EINVAL;
|
||||
hash = json_object_get_string(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "iterations", &jobj2))
|
||||
return -EINVAL;
|
||||
iterations = json_object_get_int(jobj2);
|
||||
memory = 0;
|
||||
parallel = 0;
|
||||
} else {
|
||||
if (!json_object_object_get_ex(jobj_kdf, "time", &jobj2))
|
||||
return -EINVAL;
|
||||
iterations = json_object_get_int(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "memory", &jobj2))
|
||||
return -EINVAL;
|
||||
memory = json_object_get_int(jobj2);
|
||||
if (!json_object_object_get_ex(jobj_kdf, "cpus", &jobj2))
|
||||
return -EINVAL;
|
||||
parallel = json_object_get_int(jobj2);
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "salt", &jobj2))
|
||||
return -EINVAL;
|
||||
salt_len = LUKS_SALTSIZE;
|
||||
if (!base64_decode(json_object_get_string(jobj2),
|
||||
json_object_get_string_len(jobj2),
|
||||
salt, &salt_len))
|
||||
return -EINVAL;
|
||||
if (salt_len != LUKS_SALTSIZE)
|
||||
if (luks2_keyslot_get_pbkdf_params(jobj_keyslot, &pbkdf, salt))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_af, "hash", &jobj2))
|
||||
@@ -353,10 +355,11 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
/*
|
||||
* Calculate derived key, decrypt keyslot content and merge it.
|
||||
*/
|
||||
r = crypt_pbkdf(kdf, hash, password, passwordLen,
|
||||
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
|
||||
salt, LUKS_SALTSIZE,
|
||||
derived_key->key, derived_key->keylength,
|
||||
iterations, memory, parallel);
|
||||
pbkdf.iterations, pbkdf.max_memory_kb,
|
||||
pbkdf.parallel_threads);
|
||||
|
||||
if (r == 0) {
|
||||
log_dbg("Reading keyslot area [0x%04x].", (unsigned)area_offset);
|
||||
@@ -374,16 +377,84 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
/*
|
||||
* currently we support update of only:
|
||||
*
|
||||
* - af hash function
|
||||
* - kdf params
|
||||
*/
|
||||
static int luks2_keyslot_update_json(struct crypt_device *cd,
|
||||
json_object *jobj_keyslot,
|
||||
const struct luks2_keyslot_params *params)
|
||||
{
|
||||
const struct crypt_pbkdf_type *pbkdf;
|
||||
json_object *jobj_af, *jobj_area, *jobj_kdf, *jobj1;
|
||||
char salt[LUKS_SALTSIZE], *salt_base64 = NULL;
|
||||
int r, keyslot_key_len;
|
||||
|
||||
/* jobj_keyslot is not yet validated */
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
|
||||
!json_object_object_get_ex(jobj_area, "key_size", &jobj1))
|
||||
return -EINVAL;
|
||||
|
||||
/* we do not allow any 'area' object modifications yet */
|
||||
keyslot_key_len = json_object_get_int(jobj1);
|
||||
if (keyslot_key_len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
pbkdf = crypt_get_pbkdf_type(cd);
|
||||
if (!pbkdf)
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, keyslot_key_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* refresh whole 'kdf' object */
|
||||
jobj_kdf = json_object_new_object();
|
||||
if (!jobj_kdf)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
json_object_object_add(jobj_kdf, "hash", json_object_new_string(pbkdf->hash));
|
||||
json_object_object_add(jobj_kdf, "iterations", json_object_new_int(pbkdf->iterations));
|
||||
} else {
|
||||
json_object_object_add(jobj_kdf, "time", json_object_new_int(pbkdf->iterations));
|
||||
json_object_object_add(jobj_kdf, "memory", json_object_new_int(pbkdf->max_memory_kb));
|
||||
json_object_object_add(jobj_kdf, "cpus", json_object_new_int(pbkdf->parallel_threads));
|
||||
}
|
||||
json_object_object_add(jobj_keyslot, "kdf", jobj_kdf);
|
||||
|
||||
/*
|
||||
* Regenerate salt and add it in 'kdf' object
|
||||
*/
|
||||
r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
base64_encode_alloc(salt, LUKS_SALTSIZE, &salt_base64);
|
||||
if (!salt_base64)
|
||||
return -ENOMEM;
|
||||
json_object_object_add(jobj_kdf, "salt", json_object_new_string(salt_base64));
|
||||
free(salt_base64);
|
||||
|
||||
/* update 'af' hash */
|
||||
json_object_object_add(jobj_af, "hash", json_object_new_string(params->af.luks1.hash));
|
||||
|
||||
JSON_DBG(jobj_keyslot, "Keyslot JSON");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
size_t volume_key_len,
|
||||
const struct luks2_keyslot_params *params)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
const struct crypt_pbkdf_type *pbkdf;
|
||||
char num[16];
|
||||
uint64_t area_offset, area_length;
|
||||
json_object *jobj_keyslots, *jobj_keyslot, *jobj_kdf, *jobj_af, *jobj_area;
|
||||
json_object *jobj_keyslots, *jobj_keyslot, *jobj_af, *jobj_area;
|
||||
int r;
|
||||
|
||||
log_dbg("Trying to allocate LUKS2 keyslot %d.", keyslot);
|
||||
@@ -400,7 +471,7 @@ int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
if (keyslot == CRYPT_ANY_SLOT)
|
||||
keyslot = LUKS2_keyslot_find_empty(hdr, "luks2");
|
||||
|
||||
if (keyslot < 0 || keyslot > LUKS2_KEYSLOTS_MAX)
|
||||
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return -ENOMEM;
|
||||
|
||||
if (LUKS2_get_keyslot_jobj(hdr, keyslot)) {
|
||||
@@ -415,37 +486,13 @@ int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
pbkdf = crypt_get_pbkdf_type(cd);
|
||||
if (!pbkdf)
|
||||
return -EINVAL;
|
||||
|
||||
r = crypt_benchmark_pbkdf_internal(cd, CONST_CAST(struct crypt_pbkdf_type *)pbkdf, volume_key_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
jobj_keyslot = json_object_new_object();
|
||||
json_object_object_add(jobj_keyslot, "type", json_object_new_string("luks2"));
|
||||
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(volume_key_len));
|
||||
|
||||
/* PBKDF object */
|
||||
jobj_kdf = json_object_new_object();
|
||||
json_object_object_add(jobj_kdf, "type", json_object_new_string(pbkdf->type));
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
json_object_object_add(jobj_kdf, "iterations", json_object_new_int(pbkdf->iterations));
|
||||
json_object_object_add(jobj_kdf, "hash", json_object_new_string(pbkdf->hash));
|
||||
json_object_object_add(jobj_kdf, "salt", json_object_new_string(""));
|
||||
} else {
|
||||
json_object_object_add(jobj_kdf, "time", json_object_new_int(pbkdf->iterations));
|
||||
json_object_object_add(jobj_kdf, "memory", json_object_new_int(pbkdf->max_memory_kb));
|
||||
json_object_object_add(jobj_kdf, "cpus", json_object_new_int(pbkdf->parallel_threads));
|
||||
json_object_object_add(jobj_kdf, "salt", json_object_new_string(""));
|
||||
}
|
||||
json_object_object_add(jobj_keyslot, "kdf", jobj_kdf);
|
||||
|
||||
/* AF object */
|
||||
jobj_af = json_object_new_object();
|
||||
json_object_object_add(jobj_af, "type", json_object_new_string("luks1"));
|
||||
json_object_object_add(jobj_af, "hash", json_object_new_string(params->af.luks1.hash));
|
||||
json_object_object_add(jobj_af, "stripes", json_object_new_int(params->af.luks1.stripes));
|
||||
json_object_object_add(jobj_keyslot, "af", jobj_af);
|
||||
|
||||
@@ -461,13 +508,18 @@ int luks2_keyslot_alloc(struct crypt_device *cd,
|
||||
snprintf(num, sizeof(num), "%d", keyslot);
|
||||
|
||||
json_object_object_add(jobj_keyslots, num, jobj_keyslot);
|
||||
if (LUKS2_check_json_size(hdr)) {
|
||||
|
||||
r = luks2_keyslot_update_json(cd, jobj_keyslot, params);
|
||||
|
||||
if (!r && LUKS2_check_json_size(hdr)) {
|
||||
log_dbg("Not enough space in header json area for new keyslot.");
|
||||
json_object_object_del(jobj_keyslots, num);
|
||||
return -ENOSPC;
|
||||
r = -ENOSPC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (r)
|
||||
json_object_object_del(jobj_keyslots, num);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_open(struct crypt_device *cd,
|
||||
@@ -494,6 +546,10 @@ static int luks2_keyslot_open(struct crypt_device *cd,
|
||||
volume_key, volume_key_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function must not modify json.
|
||||
* It's called after luks2 keyslot validation.
|
||||
*/
|
||||
static int luks2_keyslot_store(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *password,
|
||||
@@ -593,59 +649,47 @@ static int luks2_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int contains(json_object *jobj, const char *key, json_type type)
|
||||
static int luks2_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
|
||||
{
|
||||
json_object *sobj;
|
||||
json_object *jobj_kdf, *jobj_af, *jobj_area, *jobj1;
|
||||
const char *type;
|
||||
int count;
|
||||
|
||||
if (!json_object_object_get_ex(jobj, key, &sobj) ||
|
||||
!json_object_is_type(sobj, type))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_validate(struct crypt_device *cd, int keyslot)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
json_object *jobj_keyslot, *jobj_kdf, *jobj_af, *jobj_area, *jobj1;
|
||||
char num[16];
|
||||
|
||||
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
snprintf(num, sizeof(num), "%d", keyslot);
|
||||
if (LUKS2_keyslot_validate(hdr->jobj, jobj_keyslot, num))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
|
||||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
|
||||
return -EINVAL;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
count = json_object_object_length(jobj_kdf);
|
||||
|
||||
if (!strcmp(json_object_get_string(jobj1), CRYPT_KDF_PBKDF2)) {
|
||||
if (!contains(jobj_kdf, "hash", json_type_string) ||
|
||||
!contains(jobj_kdf, "iterations", json_type_int) ||
|
||||
!contains(jobj_kdf, "salt", json_type_string))
|
||||
jobj1 = json_contains(jobj_kdf, "", "kdf section", "type", json_type_string);
|
||||
if (!jobj1)
|
||||
return -EINVAL;
|
||||
type = json_object_get_string(jobj1);
|
||||
|
||||
if (!strcmp(type, CRYPT_KDF_PBKDF2)) {
|
||||
if (count != 4 || /* type, salt, hash, iterations only */
|
||||
!json_contains(jobj_kdf, "kdf type", type, "hash", json_type_string) ||
|
||||
!json_contains(jobj_kdf, "kdf type", type, "iterations", json_type_int) ||
|
||||
!json_contains(jobj_kdf, "kdf type", type, "salt", json_type_string))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (!contains(jobj_kdf, "time", json_type_int) ||
|
||||
!contains(jobj_kdf, "memory", json_type_int) ||
|
||||
!contains(jobj_kdf, "cpus", json_type_int) ||
|
||||
!contains(jobj_kdf, "salt", json_type_string))
|
||||
} else if (!strcmp(type, CRYPT_KDF_ARGON2I) || !strcmp(type, CRYPT_KDF_ARGON2ID)) {
|
||||
if (count != 5 || /* type, salt, time, memory, cpus only */
|
||||
!json_contains(jobj_kdf, "kdf type", type, "time", json_type_int) ||
|
||||
!json_contains(jobj_kdf, "kdf type", type, "memory", json_type_int) ||
|
||||
!json_contains(jobj_kdf, "kdf type", type, "cpus", json_type_int) ||
|
||||
!json_contains(jobj_kdf, "kdf type", type, "salt", json_type_string))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(jobj_af, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
if (!strcmp(json_object_get_string(jobj1), "luks1")) {
|
||||
if (!contains(jobj_af, "hash", json_type_string) ||
|
||||
!contains(jobj_af, "stripes", json_type_int))
|
||||
if (!json_contains(jobj_af, "", "luks1 af", "hash", json_type_string) ||
|
||||
!json_contains(jobj_af, "", "luks1 af", "stripes", json_type_int))
|
||||
return -EINVAL;
|
||||
} else
|
||||
return -EINVAL;
|
||||
@@ -654,10 +698,10 @@ static int luks2_keyslot_validate(struct crypt_device *cd, int keyslot)
|
||||
if (!json_object_object_get_ex(jobj_area, "type", &jobj1))
|
||||
return -EINVAL;
|
||||
if (!strcmp(json_object_get_string(jobj1), "raw")) {
|
||||
if (!contains(jobj_area, "encryption", json_type_string) ||
|
||||
!contains(jobj_area, "key_size", json_type_int) ||
|
||||
!contains(jobj_area, "offset", json_type_string) ||
|
||||
!contains(jobj_area, "size", json_type_string))
|
||||
if (!json_contains(jobj_area, "area", "raw type", "encryption", json_type_string) ||
|
||||
!json_contains(jobj_area, "area", "raw type", "key_size", json_type_int) ||
|
||||
!json_contains(jobj_area, "area", "raw type", "offset", json_type_string) ||
|
||||
!json_contains(jobj_area, "area", "raw type", "size", json_type_string))
|
||||
return -EINVAL;
|
||||
} else
|
||||
return -EINVAL;
|
||||
@@ -665,12 +709,78 @@ static int luks2_keyslot_validate(struct crypt_device *cd, int keyslot)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luks2_keyslot_update(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const struct luks2_keyslot_params *params)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
json_object *jobj_keyslot;
|
||||
int r;
|
||||
|
||||
log_dbg("Updating LUKS2 keyslot %d.", keyslot);
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
r = luks2_keyslot_update_json(cd, jobj_keyslot, params);
|
||||
|
||||
if (!r && LUKS2_check_json_size(hdr)) {
|
||||
log_dbg("Not enough space in header json area for updated keyslot %d.", keyslot);
|
||||
r = -ENOSPC;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void luks2_keyslot_repair(struct crypt_device *cd, json_object *jobj_keyslot)
|
||||
{
|
||||
const char *type;
|
||||
json_object *jobj_kdf, *jobj_type;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
|
||||
!json_object_is_type(jobj_kdf, json_type_object))
|
||||
return;
|
||||
|
||||
if (!json_object_object_get_ex(jobj_kdf, "type", &jobj_type) ||
|
||||
!json_object_is_type(jobj_type, json_type_string))
|
||||
return;
|
||||
|
||||
type = json_object_get_string(jobj_type);
|
||||
|
||||
if (!strcmp(type, CRYPT_KDF_PBKDF2)) {
|
||||
/* type, salt, hash, iterations only */
|
||||
json_object_object_foreach(jobj_kdf, key, val) {
|
||||
UNUSED(val);
|
||||
if (!strcmp(key, "type") || !strcmp(key, "salt") ||
|
||||
!strcmp(key, "hash") || !strcmp(key, "iterations"))
|
||||
continue;
|
||||
json_object_object_del(jobj_kdf, key);
|
||||
}
|
||||
} else if (!strcmp(type, CRYPT_KDF_ARGON2I) || !strcmp(type, CRYPT_KDF_ARGON2ID)) {
|
||||
/* type, salt, time, memory, cpus only */
|
||||
json_object_object_foreach(jobj_kdf, key, val) {
|
||||
UNUSED(val);
|
||||
if (!strcmp(key, "type") || !strcmp(key, "salt") ||
|
||||
!strcmp(key, "time") || !strcmp(key, "memory") ||
|
||||
!strcmp(key, "cpus"))
|
||||
continue;
|
||||
json_object_object_del(jobj_kdf, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const keyslot_handler luks2_keyslot = {
|
||||
.name = "luks2",
|
||||
.alloc = luks2_keyslot_alloc,
|
||||
.update = luks2_keyslot_update,
|
||||
.open = luks2_keyslot_open,
|
||||
.store = luks2_keyslot_store,
|
||||
.wipe = luks2_keyslot_wipe,
|
||||
.dump = luks2_keyslot_dump,
|
||||
.validate = luks2_keyslot_validate,
|
||||
.repair = luks2_keyslot_repair
|
||||
};
|
||||
|
||||
@@ -425,43 +425,48 @@ static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from,
|
||||
{
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
void *buf = NULL;
|
||||
int devfd = -1;
|
||||
int r = -EIO, devfd = -1;
|
||||
|
||||
log_dbg("Moving keyslot areas of size %zu from %jd to %jd.",
|
||||
buf_size, (intmax_t)offset_from, (intmax_t)offset_to);
|
||||
|
||||
// FIXME: export aligned_malloc from utils
|
||||
if (posix_memalign(&buf, crypt_getpagesize(), buf_size))
|
||||
return -ENOMEM;
|
||||
|
||||
devfd = device_open(device, O_RDWR);
|
||||
if (devfd == -1) {
|
||||
log_dbg("Cannot open device %s.", device_path(device));
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* This can safely fail (for block devices). It only allocates space if it is possible. */
|
||||
if (posix_fallocate(devfd, offset_to, buf_size))
|
||||
log_dbg("Preallocation (fallocate) of new keyslot area not available.");
|
||||
|
||||
/* Try to read *new* area to check that area is there (trimmed backup). */
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), buf, buf_size,
|
||||
offset_to)!= (ssize_t)buf_size)
|
||||
goto out;
|
||||
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), buf, buf_size,
|
||||
offset_from)!= (ssize_t)buf_size) {
|
||||
close(devfd);
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
offset_from)!= (ssize_t)buf_size)
|
||||
goto out;
|
||||
|
||||
if (write_lseek_blockwise(devfd, device_block_size(device),
|
||||
device_alignment(device), buf, buf_size,
|
||||
offset_to) != (ssize_t)buf_size) {
|
||||
close(devfd);
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
offset_to) != (ssize_t)buf_size)
|
||||
goto out;
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
device_sync(device, devfd);
|
||||
close(devfd);
|
||||
crypt_memzero(buf, buf_size);
|
||||
free(buf);
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int luks_header_in_use(struct crypt_device *cd)
|
||||
@@ -470,11 +475,41 @@ static int luks_header_in_use(struct crypt_device *cd)
|
||||
|
||||
r = lookup_dm_dev_by_uuid(crypt_get_uuid(cd), crypt_get_type(cd));
|
||||
if (r < 0)
|
||||
log_err(cd, _("Can not check status of device with uuid: %s.\n"), crypt_get_uuid(cd));
|
||||
log_err(cd, _("Can not check status of device with uuid: %s."), crypt_get_uuid(cd));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Check if there is a luksmeta area (foreign metadata created by the luksmeta package) */
|
||||
static int luksmeta_header_present(struct crypt_device *cd, off_t luks1_size)
|
||||
{
|
||||
static const uint8_t LM_MAGIC[] = { 'L', 'U', 'K', 'S', 'M', 'E', 'T', 'A' };
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
void *buf = NULL;
|
||||
int devfd, r = 0;
|
||||
|
||||
if (posix_memalign(&buf, crypt_getpagesize(), sizeof(LM_MAGIC)))
|
||||
return -ENOMEM;
|
||||
|
||||
devfd = device_open(device, O_RDONLY);
|
||||
if (devfd == -1) {
|
||||
free(buf);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Note: we must not detect failure as problem here, header can be trimmed. */
|
||||
if (read_lseek_blockwise(devfd, device_block_size(device), device_alignment(device),
|
||||
buf, sizeof(LM_MAGIC), luks1_size) == (ssize_t)sizeof(LM_MAGIC) &&
|
||||
!memcmp(LM_MAGIC, buf, sizeof(LM_MAGIC))) {
|
||||
log_err(cd, _("Unable to convert header with LUKSMETA additional metadata."));
|
||||
r = -EBUSY;
|
||||
}
|
||||
|
||||
close(devfd);
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Convert LUKS1 -> LUKS2 */
|
||||
int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct luks2_hdr *hdr2)
|
||||
{
|
||||
@@ -488,6 +523,7 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
|
||||
return r;
|
||||
|
||||
luks1_size = LUKS_device_sectors(hdr1) << SECTOR_SHIFT;
|
||||
luks1_size = size_round_up(luks1_size, LUKS_ALIGN_KEYSLOTS);
|
||||
if (!luks1_size)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -496,10 +532,13 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (luksmeta_header_present(cd, luks1_size))
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg("Max size: %" PRIu64 ", LUKS1 (full) header size %zu , required shift: %zu",
|
||||
max_size, luks1_size, luks1_shift);
|
||||
if ((max_size - luks1_size) < luks1_shift) {
|
||||
log_err(cd, _("Unable to move keyslot materials. Not enough space\n"));
|
||||
log_err(cd, _("Unable to move keyslot area. Not enough space."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -538,8 +577,10 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
|
||||
// move keyslots 4k -> 32k offset
|
||||
buf_offset = 2 * LUKS2_HDR_16K_LEN;
|
||||
buf_size = luks1_size - LUKS_ALIGN_KEYSLOTS;
|
||||
if ((r = move_keyslot_areas(cd, 8 * SECTOR_SIZE, buf_offset, buf_size)) < 0)
|
||||
if ((r = move_keyslot_areas(cd, 8 * SECTOR_SIZE, buf_offset, buf_size)) < 0) {
|
||||
log_err(cd, _("Unable to move keyslot area."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Write JSON hdr2
|
||||
r = LUKS2_hdr_write(cd, hdr2);
|
||||
@@ -582,6 +623,7 @@ static int keyslot_LUKS1_compatible(struct luks2_hdr *hdr, int keyslot, uint32_t
|
||||
return 0;
|
||||
|
||||
/* FIXME: should this go to validation code instead (aka invalid luks2 header if assigned to segment 0)? */
|
||||
/* FIXME: check all keyslots are assigned to segment id 0, and segments count == 1 */
|
||||
ks_key_size = LUKS2_get_keyslot_key_size(hdr, keyslot);
|
||||
if (ks_key_size < 0 || (int)key_size != LUKS2_get_keyslot_key_size(hdr, keyslot)) {
|
||||
log_dbg("Key length in keyslot %d is different from volume key length", keyslot);
|
||||
@@ -603,14 +645,13 @@ static int keyslot_LUKS1_compatible(struct luks2_hdr *hdr, int keyslot, uint32_t
|
||||
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];
|
||||
size_t len;
|
||||
json_object *jobj_keyslot, *jobj_digest, *jobj_segment, *jobj_kdf, *jobj_area, *jobj1, *jobj2;
|
||||
uint32_t key_size;
|
||||
int i, r, last_active = 0;
|
||||
uint64_t offset, area_length;
|
||||
struct luks2_keyslot_params params;
|
||||
char buf[256], luksMagic[] = LUKS_MAGIC;
|
||||
|
||||
jobj_digest = LUKS2_get_digest_jobj(hdr2, 0);
|
||||
@@ -625,37 +666,48 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
if (!json_object_object_get_ex(jobj_digest, "type", &jobj2) ||
|
||||
strcmp(json_object_get_string(jobj2), "pbkdf2") ||
|
||||
json_object_object_length(jobj1) != 1) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - key slot digests are not LUKS1 compatible.\n"));
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - key slot digests are not LUKS1 compatible."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* We really do not care about params later except keys_size */
|
||||
r = LUKS2_keyslot_params_default(cd, hdr2, 0, ¶ms);
|
||||
r = crypt_parse_name_and_mode(LUKS2_get_cipher(hdr2, CRYPT_DEFAULT_SEGMENT), cipher, NULL, cipher_mode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (crypt_cipher_wrapped_key(cipher)) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - device uses wrapped key cipher %s."), cipher);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = LUKS2_tokens_count(hdr2);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - LUKS2 header contains %u token(s)."), r);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = LUKS2_get_volume_key_size(hdr2, 0);
|
||||
if (r < 0)
|
||||
return -EINVAL;
|
||||
key_size = r;
|
||||
params.area.raw.key_size = key_size;
|
||||
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INACTIVE)
|
||||
continue;
|
||||
|
||||
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INVALID) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is in invalid state.\n"), i);
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is in invalid state."), i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (i >= LUKS_NUMKEYS) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - slot %u (over maximum slots) is still active.\n"), i);
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - slot %u (over maximum slots) is still active."), i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!keyslot_LUKS1_compatible(hdr2, i, key_size)) {
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is not LUKS1 compatible.\n"), i);
|
||||
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is not LUKS1 compatible."), i);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
@@ -677,8 +729,12 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
} else {
|
||||
if (LUKS2_find_area_gap(cd, hdr2, key_size, &offset, &area_length))
|
||||
return -EINVAL;
|
||||
/* FIXME: luks2 reload is required! */
|
||||
if (luks2_keyslot_alloc(cd, i, key_size, ¶ms))
|
||||
/*
|
||||
* We have to create placeholder luks2 keyslots in place of all
|
||||
* inactive keyslots. Otherwise we would allocate all
|
||||
* inactive luks1 keyslots over same binary keyslot area.
|
||||
*/
|
||||
if (placeholder_keyslot_alloc(cd, i, offset, area_length, key_size))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -773,7 +829,8 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
/* FIXME: LUKS1 requires offset == 0 || offset >= luks1_hdr_size */
|
||||
hdr1->payloadOffset = offset;
|
||||
|
||||
strncpy(hdr1->uuid, hdr2->uuid, UUID_STRING_L - 1); /* max 36 chars */
|
||||
strncpy(hdr1->uuid, hdr2->uuid, UUID_STRING_L); /* max 36 chars */
|
||||
hdr1->uuid[UUID_STRING_L-1] = '\0';
|
||||
|
||||
memcpy(hdr1->magic, luksMagic, LUKS_MAGIC_L);
|
||||
|
||||
@@ -787,8 +844,10 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
|
||||
buf_offset = 2 * LUKS2_HDR_16K_LEN;
|
||||
buf_size = LUKS2_keyslots_size(hdr2->jobj);
|
||||
r = move_keyslot_areas(cd, buf_offset, 8 * SECTOR_SIZE, buf_size);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Unable to move keyslot area."));
|
||||
return r;
|
||||
}
|
||||
|
||||
crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_ZERO, 0,
|
||||
8 * SECTOR_SIZE, 8 * SECTOR_SIZE, NULL, NULL);
|
||||
|
||||
@@ -182,6 +182,7 @@ int LUKS2_token_create(struct crypt_device *cd,
|
||||
|
||||
if (h && h->validate && h->validate(cd, json)) {
|
||||
json_object_put(jobj);
|
||||
log_dbg("Token type %s validation failed.", h->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -262,7 +263,7 @@ int LUKS2_builtin_token_create(struct crypt_device *cd,
|
||||
|
||||
if (token == CRYPT_ANY_TOKEN) {
|
||||
if ((token = LUKS2_token_find_free(hdr)) < 0)
|
||||
log_err(cd, _("No free token slot\n"));
|
||||
log_err(cd, _("No free token slot."));
|
||||
}
|
||||
if (token < 0 || token >= LUKS2_TOKENS_MAX)
|
||||
return -EINVAL;
|
||||
@@ -270,14 +271,15 @@ int LUKS2_builtin_token_create(struct crypt_device *cd,
|
||||
|
||||
r = th->set(&jobj_token, params);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to create builtin token %s\n"), type);
|
||||
log_err(cd, _("Failed to create builtin token %s."), type);
|
||||
return r;
|
||||
}
|
||||
|
||||
// builtin tokens must produce valid json
|
||||
r = LUKS2_token_validate(hdr->jobj, jobj_token, "new");
|
||||
assert(!r);
|
||||
r = th->h->validate(cd, json_object_to_json_string_ext(jobj_token, JSON_C_TO_STRING_PLAIN));
|
||||
r = th->h->validate(cd, json_object_to_json_string_ext(jobj_token,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE));
|
||||
assert(!r);
|
||||
|
||||
json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens);
|
||||
@@ -396,7 +398,8 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
|
||||
return r;
|
||||
|
||||
r = LUKS2_keyslot_open_by_token(cd, hdr, token,
|
||||
name ? CRYPT_DEFAULT_SEGMENT : CRYPT_ANY_SEGMENT,
|
||||
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ?
|
||||
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
|
||||
buffer, buffer_len, &vk);
|
||||
|
||||
LUKS2_token_buffer_free(cd, token, buffer, buffer_len);
|
||||
@@ -441,7 +444,8 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
|
||||
continue;
|
||||
|
||||
r = LUKS2_keyslot_open_by_token(cd, hdr, token,
|
||||
name ? CRYPT_DEFAULT_SEGMENT : CRYPT_ANY_SEGMENT,
|
||||
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ?
|
||||
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
|
||||
buffer, buffer_len, &vk);
|
||||
LUKS2_token_buffer_free(cd, token, buffer, buffer_len);
|
||||
if (r >= 0)
|
||||
@@ -472,7 +476,8 @@ void LUKS2_token_dump(struct crypt_device *cd, int token)
|
||||
if (h && h->dump) {
|
||||
jobj_token = LUKS2_get_token_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), token);
|
||||
if (jobj_token)
|
||||
h->dump(cd, json_object_to_json_string_ext(jobj_token, JSON_C_TO_STRING_PLAIN));
|
||||
h->dump(cd, json_object_to_json_string_ext(jobj_token,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,7 +490,8 @@ int LUKS2_token_json_get(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
if (!jobj_token)
|
||||
return -EINVAL;
|
||||
|
||||
*json = json_object_to_json_string_ext(jobj_token, JSON_C_TO_STRING_PLAIN);
|
||||
*json = json_object_to_json_string_ext(jobj_token,
|
||||
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -594,3 +600,12 @@ int LUKS2_token_is_assigned(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_tokens_count(struct luks2_hdr *hdr)
|
||||
{
|
||||
json_object *jobj_tokens = LUKS2_get_tokens_jobj(hdr);
|
||||
if (!jobj_tokens)
|
||||
return -EINVAL;
|
||||
|
||||
return json_object_object_length(jobj_tokens);
|
||||
}
|
||||
|
||||
@@ -167,13 +167,13 @@ int crypt_random_init(struct crypt_device *ctx)
|
||||
goto fail;
|
||||
|
||||
if (crypt_fips_mode())
|
||||
log_verbose(ctx, _("Running in FIPS mode.\n"));
|
||||
log_verbose(ctx, _("Running in FIPS mode."));
|
||||
|
||||
random_initialised = 1;
|
||||
return 0;
|
||||
fail:
|
||||
crypt_random_exit();
|
||||
log_err(ctx, _("Fatal error during RNG initialisation.\n"));
|
||||
log_err(ctx, _("Fatal error during RNG initialisation."));
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
@@ -210,12 +210,12 @@ int crypt_random_get(struct crypt_device *ctx, char *buf, size_t len, int qualit
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_err(ctx, _("Unknown RNG quality requested.\n"));
|
||||
log_err(ctx, _("Unknown RNG quality requested."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (status)
|
||||
log_err(ctx, _("Error reading from RNG.\n"));
|
||||
log_err(ctx, _("Error reading from RNG."));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
642
lib/setup.c
642
lib/setup.c
File diff suppressed because it is too large
Load Diff
@@ -37,19 +37,23 @@ static const struct {
|
||||
const char *name;
|
||||
const char *hash;
|
||||
unsigned int iterations;
|
||||
uint32_t veracrypt_pim_const;
|
||||
uint32_t veracrypt_pim_mult;
|
||||
} tcrypt_kdf[] = {
|
||||
{ 0, 0, "pbkdf2", "ripemd160", 2000 },
|
||||
{ 0, 0, "pbkdf2", "ripemd160", 1000 },
|
||||
{ 0, 0, "pbkdf2", "sha512", 1000 },
|
||||
{ 0, 0, "pbkdf2", "whirlpool", 1000 },
|
||||
{ 1, 0, "pbkdf2", "sha1", 2000 },
|
||||
{ 0, 1, "pbkdf2", "sha512", 500000 },
|
||||
{ 0, 1, "pbkdf2", "ripemd160", 655331 },
|
||||
{ 0, 1, "pbkdf2", "ripemd160", 327661 }, // boot only
|
||||
{ 0, 1, "pbkdf2", "whirlpool", 500000 },
|
||||
{ 0, 1, "pbkdf2", "sha256", 500000 }, // VeraCrypt 1.0f
|
||||
{ 0, 1, "pbkdf2", "sha256", 200000 }, // boot only
|
||||
{ 0, 0, NULL, NULL, 0 }
|
||||
{ 0, 0, "pbkdf2", "ripemd160", 2000, 0, 0 },
|
||||
{ 0, 0, "pbkdf2", "ripemd160", 1000, 0, 0 },
|
||||
{ 0, 0, "pbkdf2", "sha512", 1000, 0, 0 },
|
||||
{ 0, 0, "pbkdf2", "whirlpool", 1000, 0, 0 },
|
||||
{ 1, 0, "pbkdf2", "sha1", 2000, 0, 0 },
|
||||
{ 0, 1, "pbkdf2", "sha512", 500000, 15000, 1000 },
|
||||
{ 0, 1, "pbkdf2", "whirlpool", 500000, 15000, 1000 },
|
||||
{ 0, 1, "pbkdf2", "sha256", 500000, 15000, 1000 }, // VeraCrypt 1.0f
|
||||
{ 0, 1, "pbkdf2", "sha256", 200000, 0, 2048 }, // boot only
|
||||
{ 0, 1, "pbkdf2", "ripemd160", 655331, 15000, 1000 },
|
||||
{ 0, 1, "pbkdf2", "ripemd160", 327661, 0, 2048 }, // boot only
|
||||
{ 0, 1, "pbkdf2", "stribog512",500000, 15000, 1000 },
|
||||
// { 0, 1, "pbkdf2", "stribog512",200000, 0, 2048 }, // boot only
|
||||
{ 0, 0, NULL, NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
struct tcrypt_alg {
|
||||
@@ -96,6 +100,26 @@ static struct tcrypt_algs tcrypt_cipher[] = {
|
||||
{0,2,128,"serpent-twofish","xts-plain64",
|
||||
{{"serpent",64,16, 0,64,0},
|
||||
{"twofish",64,16,32,96,0}}},
|
||||
{0,1,64,"camellia","xts-plain64",
|
||||
{{"camellia", 64,16,0,32,0}}},
|
||||
{0,1,64,"kuznyechik","xts-plain64",
|
||||
{{"kuznyechik", 64,16,0,32,0}}},
|
||||
{0,2,128,"kuznyechik-camellia","xts-plain64",
|
||||
{{"kuznyechik",64,16, 0,64,0},
|
||||
{"camellia", 64,16,32,96,0}}},
|
||||
{0,2,128,"twofish-kuznyechik","xts-plain64",
|
||||
{{"twofish", 64,16, 0,64,0},
|
||||
{"kuznyechik",64,16,32,96,0}}},
|
||||
{0,2,128,"serpent-camellia","xts-plain64",
|
||||
{{"serpent", 64,16, 0,64,0},
|
||||
{"camellia", 64,16,32,96,0}}},
|
||||
{0,2,128,"aes-kuznyechik","xts-plain64",
|
||||
{{"aes", 64,16, 0,64,0},
|
||||
{"kuznyechik",64,16,32,96,0}}},
|
||||
{0,3,192,"camellia-serpent-kuznyechik","xts-plain64",
|
||||
{{"camellia", 64,16, 0, 96,0},
|
||||
{"serpent", 64,16,32,128,0},
|
||||
{"kuznyechik",64,16,64,160,0}}},
|
||||
|
||||
/* LRW mode */
|
||||
{0,1,48,"aes","lrw-benbi",
|
||||
@@ -470,14 +494,14 @@ static int TCRYPT_pool_keyfile(struct crypt_device *cd,
|
||||
|
||||
fd = open(keyfile, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
log_err(cd, _("Failed to open key file.\n"));
|
||||
log_err(cd, _("Failed to open key file."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
data_size = read_buffer(fd, data, TCRYPT_KEYFILE_LEN);
|
||||
close(fd);
|
||||
if (data_size < 0) {
|
||||
log_err(cd, _("Error reading keyfile %s.\n"), keyfile);
|
||||
log_err(cd, _("Error reading keyfile %s."), keyfile);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -517,7 +541,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
|
||||
passphrase_size = params->passphrase_size;
|
||||
|
||||
if (params->passphrase_size > TCRYPT_KEY_POOL_LEN) {
|
||||
log_err(cd, _("Maximum TCRYPT passphrase length (%d) exceeded.\n"),
|
||||
log_err(cd, _("Maximum TCRYPT passphrase length (%d) exceeded."),
|
||||
TCRYPT_KEY_POOL_LEN);
|
||||
goto out;
|
||||
}
|
||||
@@ -543,10 +567,8 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
|
||||
if (!tcrypt_kdf[i].veracrypt)
|
||||
continue;
|
||||
/* adjust iterations to given PIM cmdline parameter */
|
||||
if (params->flags & CRYPT_TCRYPT_SYSTEM_HEADER)
|
||||
iterations = params->veracrypt_pim * 2048;
|
||||
else
|
||||
iterations = 15000 + (params->veracrypt_pim * 1000);
|
||||
iterations = tcrypt_kdf[i].veracrypt_pim_const +
|
||||
(tcrypt_kdf[i].veracrypt_pim_mult * params->veracrypt_pim);
|
||||
} else
|
||||
iterations = tcrypt_kdf[i].iterations;
|
||||
|
||||
@@ -560,7 +582,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
|
||||
key, TCRYPT_HDR_KEY_LEN,
|
||||
iterations, 0, 0);
|
||||
if (r < 0 && crypt_hash_size(tcrypt_kdf[i].hash) < 0) {
|
||||
log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping.\n"),
|
||||
log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping."),
|
||||
tcrypt_kdf[i].hash);
|
||||
continue;
|
||||
}
|
||||
@@ -578,9 +600,9 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
|
||||
}
|
||||
|
||||
if ((r < 0 && r != -EPERM && skipped && skipped == i) || r == -ENOTSUP) {
|
||||
log_err(cd, _("Required kernel crypto interface not available.\n"));
|
||||
log_err(cd, _("Required kernel crypto interface not available."));
|
||||
#ifdef ENABLE_AF_ALG
|
||||
log_err(cd, _("Ensure you have algif_skcipher kernel module loaded.\n"));
|
||||
log_err(cd, _("Ensure you have algif_skcipher kernel module loaded."));
|
||||
#endif
|
||||
}
|
||||
if (r < 0)
|
||||
@@ -637,7 +659,7 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
|
||||
devfd = device_open(device, O_RDONLY);
|
||||
|
||||
if (devfd < 0) {
|
||||
log_err(cd, _("Cannot open device %s.\n"), device_path(device));
|
||||
log_err(cd, _("Cannot open device %s."), device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -726,13 +748,13 @@ int TCRYPT_activate(struct crypt_device *cd,
|
||||
}
|
||||
|
||||
if (hdr->d.sector_size && hdr->d.sector_size != SECTOR_SIZE) {
|
||||
log_err(cd, _("Activation is not supported for %d sector size.\n"),
|
||||
log_err(cd, _("Activation is not supported for %d sector size."),
|
||||
hdr->d.sector_size);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (strstr(params->mode, "-tcrypt")) {
|
||||
log_err(cd, _("Kernel doesn't support activation for this TCRYPT legacy mode.\n"));
|
||||
log_err(cd, _("Kernel doesn't support activation for this TCRYPT legacy mode."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -766,7 +788,7 @@ int TCRYPT_activate(struct crypt_device *cd,
|
||||
dmd.u.crypt.offset, dmd.size);
|
||||
if (part_path) {
|
||||
if (!device_alloc(&part_device, part_path)) {
|
||||
log_verbose(cd, _("Activating TCRYPT system encryption for partition %s.\n"),
|
||||
log_verbose(cd, _("Activating TCRYPT system encryption for partition %s."),
|
||||
part_path);
|
||||
dmd.data_device = part_device;
|
||||
dmd.u.crypt.offset = 0;
|
||||
@@ -834,7 +856,7 @@ int TCRYPT_activate(struct crypt_device *cd,
|
||||
|
||||
if (r < 0 &&
|
||||
(dm_flags(DM_CRYPT, &dmc_flags) || ((dmc_flags & req_flags) != req_flags))) {
|
||||
log_err(cd, _("Kernel doesn't support TCRYPT compatible mapping.\n"));
|
||||
log_err(cd, _("Kernel doesn't support TCRYPT compatible mapping."));
|
||||
r = -ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
302
lib/utils.c
302
lib/utils.c
@@ -22,13 +22,10 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
@@ -63,255 +60,6 @@ uint64_t crypt_getphysmemory_kb(void)
|
||||
return phys_memory_kb;
|
||||
}
|
||||
|
||||
ssize_t read_buffer(int fd, void *buf, size_t count)
|
||||
{
|
||||
size_t read_size = 0;
|
||||
ssize_t r;
|
||||
|
||||
if (fd < 0 || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
r = read(fd, buf, count - read_size);
|
||||
if (r == -1 && errno != EINTR)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return (ssize_t)read_size;
|
||||
if (r > 0) {
|
||||
read_size += (size_t)r;
|
||||
buf = (uint8_t*)buf + r;
|
||||
}
|
||||
} while (read_size != count);
|
||||
|
||||
return (ssize_t)count;
|
||||
}
|
||||
|
||||
ssize_t write_buffer(int fd, const void *buf, size_t count)
|
||||
{
|
||||
size_t write_size = 0;
|
||||
ssize_t w;
|
||||
|
||||
if (fd < 0 || !buf || !count)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
w = write(fd, buf, count - write_size);
|
||||
if (w < 0 && errno != EINTR)
|
||||
return w;
|
||||
if (w == 0)
|
||||
return (ssize_t)write_size;
|
||||
if (w > 0) {
|
||||
write_size += (size_t) w;
|
||||
buf = (const uint8_t*)buf + w;
|
||||
}
|
||||
} while (write_size != count);
|
||||
|
||||
return (ssize_t)write_size;
|
||||
}
|
||||
|
||||
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *orig_buf, size_t count)
|
||||
{
|
||||
void *hangover_buf = NULL, *buf = NULL;
|
||||
size_t hangover, solid;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !orig_buf || !bsize || !alignment)
|
||||
return -1;
|
||||
|
||||
hangover = count % bsize;
|
||||
solid = count - hangover;
|
||||
|
||||
if ((size_t)orig_buf & (alignment - 1)) {
|
||||
if (posix_memalign(&buf, alignment, count))
|
||||
return -1;
|
||||
memcpy(buf, orig_buf, count);
|
||||
} else
|
||||
buf = orig_buf;
|
||||
|
||||
if (solid) {
|
||||
r = write_buffer(fd, buf, solid);
|
||||
if (r < 0 || r != (ssize_t)solid)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hangover) {
|
||||
if (posix_memalign(&hangover_buf, alignment, bsize))
|
||||
goto out;
|
||||
|
||||
r = read_buffer(fd, hangover_buf, bsize);
|
||||
if (r < 0 || r < (ssize_t)hangover)
|
||||
goto out;
|
||||
|
||||
if (r < (ssize_t)bsize)
|
||||
bsize = r;
|
||||
|
||||
if (lseek(fd, -(off_t)bsize, SEEK_CUR) < 0)
|
||||
goto out;
|
||||
|
||||
memcpy(hangover_buf, (char*)buf + solid, hangover);
|
||||
|
||||
r = write_buffer(fd, hangover_buf, bsize);
|
||||
if (r < 0 || r < (ssize_t)hangover)
|
||||
goto out;
|
||||
}
|
||||
ret = count;
|
||||
out:
|
||||
free(hangover_buf);
|
||||
if (buf != orig_buf)
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *orig_buf, size_t count)
|
||||
{
|
||||
void *hangover_buf = NULL, *buf = NULL;
|
||||
size_t hangover, solid;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !orig_buf || !bsize || !alignment)
|
||||
return -1;
|
||||
|
||||
hangover = count % bsize;
|
||||
solid = count - hangover;
|
||||
|
||||
if ((size_t)orig_buf & (alignment - 1)) {
|
||||
if (posix_memalign(&buf, alignment, count))
|
||||
return -1;
|
||||
} else
|
||||
buf = orig_buf;
|
||||
|
||||
r = read_buffer(fd, buf, solid);
|
||||
if (r < 0 || r != (ssize_t)solid)
|
||||
goto out;
|
||||
|
||||
if (hangover) {
|
||||
if (posix_memalign(&hangover_buf, alignment, bsize))
|
||||
goto out;
|
||||
r = read_buffer(fd, hangover_buf, bsize);
|
||||
if (r < 0 || r < (ssize_t)hangover)
|
||||
goto out;
|
||||
|
||||
memcpy((char *)buf + solid, hangover_buf, hangover);
|
||||
}
|
||||
ret = count;
|
||||
out:
|
||||
free(hangover_buf);
|
||||
if (buf != orig_buf) {
|
||||
memcpy(orig_buf, buf, count);
|
||||
free(buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Combines llseek with blockwise write. write_blockwise can already deal with short writes
|
||||
* but we also need a function to deal with short writes at the start. But this information
|
||||
* is implicitly included in the read/write offset, which can not be set to non-aligned
|
||||
* boundaries. Hence, we combine llseek with write.
|
||||
*/
|
||||
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *buf, size_t count, off_t offset)
|
||||
{
|
||||
void *frontPadBuf = NULL;
|
||||
size_t frontHang, innerCount = 0;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !buf || !bsize || !alignment)
|
||||
return -1;
|
||||
|
||||
if (offset < 0)
|
||||
offset = lseek(fd, offset, SEEK_END);
|
||||
|
||||
if (offset < 0)
|
||||
return -1;
|
||||
|
||||
frontHang = offset % bsize;
|
||||
|
||||
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
|
||||
return -1;
|
||||
|
||||
if (frontHang) {
|
||||
if (posix_memalign(&frontPadBuf, alignment, bsize))
|
||||
return -1;
|
||||
|
||||
innerCount = bsize - frontHang;
|
||||
if (innerCount > count)
|
||||
innerCount = count;
|
||||
|
||||
r = read_buffer(fd, frontPadBuf, bsize);
|
||||
if (r < 0 || r < (ssize_t)(frontHang + innerCount))
|
||||
goto out;
|
||||
|
||||
memcpy((char*)frontPadBuf + frontHang, buf, innerCount);
|
||||
|
||||
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
|
||||
goto out;
|
||||
|
||||
r = write_buffer(fd, frontPadBuf, frontHang + innerCount);
|
||||
if (r < 0 || r != (ssize_t)(frontHang + innerCount))
|
||||
goto out;
|
||||
|
||||
buf = (char*)buf + innerCount;
|
||||
count -= innerCount;
|
||||
}
|
||||
|
||||
ret = count ? write_blockwise(fd, bsize, alignment, buf, count) : 0;
|
||||
if (ret >= 0)
|
||||
ret += innerCount;
|
||||
out:
|
||||
free(frontPadBuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *buf, size_t count, off_t offset)
|
||||
{
|
||||
void *frontPadBuf = NULL;
|
||||
size_t frontHang, innerCount = 0;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !buf || bsize <= 0)
|
||||
return -1;
|
||||
|
||||
if (offset < 0)
|
||||
offset = lseek(fd, offset, SEEK_END);
|
||||
|
||||
if (offset < 0)
|
||||
return -1;
|
||||
|
||||
frontHang = offset % bsize;
|
||||
|
||||
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
|
||||
return -1;
|
||||
|
||||
if (frontHang) {
|
||||
if (posix_memalign(&frontPadBuf, alignment, bsize))
|
||||
return -1;
|
||||
|
||||
innerCount = bsize - frontHang;
|
||||
if (innerCount > count)
|
||||
innerCount = count;
|
||||
|
||||
r = read_buffer(fd, frontPadBuf, bsize);
|
||||
if (r < 0 || r < (ssize_t)(frontHang + innerCount))
|
||||
goto out;
|
||||
|
||||
memcpy(buf, (char*)frontPadBuf + frontHang, innerCount);
|
||||
|
||||
buf = (char*)buf + innerCount;
|
||||
count -= innerCount;
|
||||
}
|
||||
|
||||
ret = read_blockwise(fd, bsize, alignment, buf, count);
|
||||
if (ret >= 0)
|
||||
ret += innerCount;
|
||||
out:
|
||||
free(frontPadBuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* MEMLOCK */
|
||||
#define DEFAULT_PROCESS_PRIORITY -18
|
||||
|
||||
@@ -330,7 +78,7 @@ int crypt_memlock_inc(struct crypt_device *ctx)
|
||||
}
|
||||
errno = 0;
|
||||
if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno)
|
||||
log_err(ctx, _("Cannot get process priority.\n"));
|
||||
log_err(ctx, _("Cannot get process priority."));
|
||||
else
|
||||
if (setpriority(PRIO_PROCESS, 0, DEFAULT_PROCESS_PRIORITY))
|
||||
log_dbg("setpriority %d failed: %s",
|
||||
@@ -344,7 +92,7 @@ int crypt_memlock_dec(struct crypt_device *ctx)
|
||||
if (_memlock_count && (!--_memlock_count)) {
|
||||
log_dbg("Unlocking memory.");
|
||||
if (munlockall() == -1)
|
||||
log_err(ctx, _("Cannot unlock memory.\n"));
|
||||
log_err(ctx, _("Cannot unlock memory."));
|
||||
if (setpriority(PRIO_PROCESS, 0, _priority))
|
||||
log_dbg("setpriority %d failed: %s", _priority, strerror(errno));
|
||||
}
|
||||
@@ -400,7 +148,7 @@ static int keyfile_seek(int fd, uint64_t bytes)
|
||||
|
||||
int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
|
||||
char **key, size_t *key_size_read,
|
||||
uint64_t keyfile_offset, size_t keyfile_size_max,
|
||||
uint64_t keyfile_offset, size_t key_size,
|
||||
uint32_t flags)
|
||||
{
|
||||
int fd, regular_file, char_to_read = 0, char_read = 0, unlimited_read = 0;
|
||||
@@ -418,29 +166,29 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
|
||||
|
||||
fd = keyfile ? open(keyfile, O_RDONLY) : STDIN_FILENO;
|
||||
if (fd < 0) {
|
||||
log_err(cd, _("Failed to open key file.\n"));
|
||||
log_err(cd, _("Failed to open key file."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (isatty(fd)) {
|
||||
log_err(cd, _("Cannot read keyfile from a terminal.\n"));
|
||||
log_err(cd, _("Cannot read keyfile from a terminal."));
|
||||
r = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* If not requested otherwise, we limit input to prevent memory exhaustion */
|
||||
if (keyfile_size_max == 0) {
|
||||
keyfile_size_max = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1;
|
||||
if (key_size == 0) {
|
||||
key_size = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1;
|
||||
unlimited_read = 1;
|
||||
/* use 4k for buffer (page divisor but avoid huge pages) */
|
||||
buflen = 4096 - sizeof(struct safe_allocation);
|
||||
} else
|
||||
buflen = keyfile_size_max;
|
||||
buflen = key_size;
|
||||
|
||||
regular_file = 0;
|
||||
if (keyfile) {
|
||||
if (stat(keyfile, &st) < 0) {
|
||||
log_err(cd, _("Failed to stat key file.\n"));
|
||||
log_err(cd, _("Failed to stat key file."));
|
||||
goto out_err;
|
||||
}
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
@@ -448,14 +196,14 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
|
||||
file_read_size = (uint64_t)st.st_size;
|
||||
|
||||
if (keyfile_offset > file_read_size) {
|
||||
log_err(cd, _("Cannot seek to requested keyfile offset.\n"));
|
||||
log_err(cd, _("Cannot seek to requested keyfile offset."));
|
||||
goto out_err;
|
||||
}
|
||||
file_read_size -= keyfile_offset;
|
||||
|
||||
/* known keyfile size, alloc it in one step */
|
||||
if (file_read_size >= (uint64_t)keyfile_size_max)
|
||||
buflen = keyfile_size_max;
|
||||
if (file_read_size >= (uint64_t)key_size)
|
||||
buflen = key_size;
|
||||
else if (file_read_size)
|
||||
buflen = file_read_size;
|
||||
}
|
||||
@@ -463,22 +211,22 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
|
||||
|
||||
pass = crypt_safe_alloc(buflen);
|
||||
if (!pass) {
|
||||
log_err(cd, _("Out of memory while reading passphrase.\n"));
|
||||
log_err(cd, _("Out of memory while reading passphrase."));
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Discard keyfile_offset bytes on input */
|
||||
if (keyfile_offset && keyfile_seek(fd, keyfile_offset) < 0) {
|
||||
log_err(cd, _("Cannot seek to requested keyfile offset.\n"));
|
||||
log_err(cd, _("Cannot seek to requested keyfile offset."));
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
for (i = 0, newline = 0; i < keyfile_size_max; i += char_read) {
|
||||
for (i = 0, newline = 0; i < key_size; i += char_read) {
|
||||
if (i == buflen) {
|
||||
buflen += 4096;
|
||||
pass = crypt_safe_realloc(pass, buflen);
|
||||
if (!pass) {
|
||||
log_err(cd, _("Out of memory while reading passphrase.\n"));
|
||||
log_err(cd, _("Out of memory while reading passphrase."));
|
||||
r = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
@@ -492,13 +240,13 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
|
||||
*/
|
||||
char_to_read = 1;
|
||||
} else {
|
||||
/* char_to_read = min(keyfile_size_max - i, buflen - i) */
|
||||
char_to_read = keyfile_size_max < buflen ?
|
||||
keyfile_size_max - i : buflen - i;
|
||||
/* char_to_read = min(key_size - i, buflen - i) */
|
||||
char_to_read = key_size < buflen ?
|
||||
key_size - i : buflen - i;
|
||||
}
|
||||
char_read = read_buffer(fd, &pass[i], char_to_read);
|
||||
if (char_read < 0) {
|
||||
log_err(cd, _("Error reading passphrase.\n"));
|
||||
log_err(cd, _("Error reading passphrase."));
|
||||
r = -EPIPE;
|
||||
goto out_err;
|
||||
}
|
||||
@@ -515,19 +263,19 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile,
|
||||
|
||||
/* Fail if piped input dies reading nothing */
|
||||
if (!i && !regular_file && !newline) {
|
||||
log_dbg("Nothing read on input.");
|
||||
log_err(cd, _("Nothing to read on input."));
|
||||
r = -EPIPE;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Fail if we exceeded internal default (no specified size) */
|
||||
if (unlimited_read && i == keyfile_size_max) {
|
||||
log_err(cd, _("Maximum keyfile size exceeded.\n"));
|
||||
if (unlimited_read && i == key_size) {
|
||||
log_err(cd, _("Maximum keyfile size exceeded."));
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (!unlimited_read && i != keyfile_size_max) {
|
||||
log_err(cd, _("Cannot read requested amount of data.\n"));
|
||||
if (!unlimited_read && i != key_size) {
|
||||
log_err(cd, _("Cannot read requested amount of data."));
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
|
||||
@@ -294,21 +294,20 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
|
||||
uint32_t ms_tmp;
|
||||
int r = -EINVAL;
|
||||
|
||||
/* Already benchmarked */
|
||||
if (pbkdf->iterations) {
|
||||
log_dbg("Reusing PBKDF values.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) {
|
||||
log_err(cd, _("PBKDF benchmark disabled but iterations not set.\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) {
|
||||
if (pbkdf->iterations) {
|
||||
log_dbg("Reusing PBKDF values (no benchmark flag is set).");
|
||||
return 0;
|
||||
}
|
||||
log_err(cd, _("PBKDF benchmark disabled but iterations not set."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* For PBKDF2 run benchmark always. Also note it depends on volume_key_size! */
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
/*
|
||||
* For PBKDF2 it is enough to run benchmark for only 1 second
|
||||
@@ -323,7 +322,7 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
|
||||
volume_key_size, &benchmark_callback, pbkdf);
|
||||
pbkdf->time_ms = ms_tmp;
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Not compatible PBKDF2 options (using hash algorithm %s).\n"),
|
||||
log_err(cd, _("Not compatible PBKDF2 options (using hash algorithm %s)."),
|
||||
pbkdf->hash);
|
||||
return r;
|
||||
}
|
||||
@@ -333,11 +332,17 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
pbkdf->iterations = at_least((uint32_t)PBKDF2_tmp, pbkdf_limits.min_iterations);
|
||||
} else {
|
||||
/* Already benchmarked */
|
||||
if (pbkdf->iterations) {
|
||||
log_dbg("Reusing PBKDF values.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = crypt_benchmark_pbkdf(cd, pbkdf, "foo", 3,
|
||||
"0123456789abcdef0123456789abcdef", 32,
|
||||
volume_key_size, &benchmark_callback, pbkdf);
|
||||
if (r < 0)
|
||||
log_err(cd, _("Not compatible PBKDF options.\n"));
|
||||
log_err(cd, _("Not compatible PBKDF options."));
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
309
lib/utils_blkid.c
Normal file
309
lib/utils_blkid.c
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* blkid probe utilities
|
||||
*
|
||||
* Copyright (C) 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
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utils_blkid.h"
|
||||
#include "utils_io.h"
|
||||
|
||||
#ifdef HAVE_BLKID
|
||||
#include <blkid/blkid.h>
|
||||
/* make bad checksums flag optional */
|
||||
#ifndef BLKID_SUBLKS_BADCSUM
|
||||
#define BLKID_SUBLKS_BADCSUM 0
|
||||
#endif
|
||||
struct blkid_handle {
|
||||
int fd;
|
||||
blkid_probe pr;
|
||||
};
|
||||
#ifndef HAVE_BLKID_WIPE
|
||||
static size_t crypt_getpagesize(void)
|
||||
{
|
||||
long r = sysconf(_SC_PAGESIZE);
|
||||
return r <= 0 ? 4096 : (size_t)r;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void blk_set_chains_for_wipes(struct blkid_handle *h)
|
||||
{
|
||||
#ifdef HAVE_BLKID
|
||||
blkid_probe_enable_partitions(h->pr, 1);
|
||||
blkid_probe_set_partitions_flags(h->pr, 0
|
||||
#ifdef HAVE_BLKID_WIPE
|
||||
| BLKID_PARTS_MAGIC
|
||||
#endif
|
||||
);
|
||||
|
||||
blkid_probe_enable_superblocks(h->pr, 1);
|
||||
blkid_probe_set_superblocks_flags(h->pr, BLKID_SUBLKS_LABEL |
|
||||
BLKID_SUBLKS_UUID |
|
||||
BLKID_SUBLKS_TYPE |
|
||||
BLKID_SUBLKS_USAGE |
|
||||
BLKID_SUBLKS_VERSION |
|
||||
BLKID_SUBLKS_MAGIC |
|
||||
BLKID_SUBLKS_BADCSUM);
|
||||
#endif
|
||||
}
|
||||
|
||||
void blk_set_chains_for_full_print(struct blkid_handle *h)
|
||||
{
|
||||
blk_set_chains_for_wipes(h);
|
||||
}
|
||||
|
||||
void blk_set_chains_for_fast_detection(struct blkid_handle *h)
|
||||
{
|
||||
#ifdef HAVE_BLKID
|
||||
blkid_probe_enable_partitions(h->pr, 1);
|
||||
blkid_probe_set_partitions_flags(h->pr, 0);
|
||||
|
||||
blkid_probe_enable_superblocks(h->pr, 1);
|
||||
blkid_probe_set_superblocks_flags(h->pr, BLKID_SUBLKS_TYPE);
|
||||
#endif
|
||||
}
|
||||
|
||||
int blk_init_by_path(struct blkid_handle **h, const char *path)
|
||||
{
|
||||
int r = -ENOTSUP;
|
||||
#ifdef HAVE_BLKID
|
||||
struct blkid_handle *tmp = malloc(sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
tmp->fd = -1;
|
||||
|
||||
tmp->pr = blkid_new_probe_from_filename(path);
|
||||
if (!tmp->pr) {
|
||||
free(tmp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*h = tmp;
|
||||
|
||||
r = 0;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
int blk_init_by_fd(struct blkid_handle **h, int fd)
|
||||
{
|
||||
int r = -ENOTSUP;
|
||||
#ifdef HAVE_BLKID
|
||||
struct blkid_handle *tmp = malloc(sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
tmp->pr = blkid_new_probe();
|
||||
if (!tmp->pr) {
|
||||
free(tmp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (blkid_probe_set_device(tmp->pr, fd, 0, 0)) {
|
||||
blkid_free_probe(tmp->pr);
|
||||
free(tmp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tmp->fd = fd;
|
||||
|
||||
*h = tmp;
|
||||
|
||||
r = 0;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
int blk_superblocks_filter_luks(struct blkid_handle *h)
|
||||
{
|
||||
int r = -ENOTSUP;
|
||||
#ifdef HAVE_BLKID
|
||||
char luks[] = "crypto_LUKS";
|
||||
char *luks_filter[] = {
|
||||
luks,
|
||||
NULL
|
||||
};
|
||||
r = blkid_probe_filter_superblocks_type(h->pr, BLKID_FLTR_NOTIN, luks_filter);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
blk_probe_status blk_probe(struct blkid_handle *h)
|
||||
{
|
||||
blk_probe_status pr = PRB_FAIL;
|
||||
#ifdef HAVE_BLKID
|
||||
int r = blkid_do_probe(h->pr);
|
||||
|
||||
if (r == 0)
|
||||
pr = PRB_OK;
|
||||
else if (r == 1)
|
||||
pr = PRB_EMPTY;
|
||||
#endif
|
||||
return pr;
|
||||
}
|
||||
|
||||
blk_probe_status blk_safeprobe(struct blkid_handle *h)
|
||||
{
|
||||
int r = -1;
|
||||
#ifdef HAVE_BLKID
|
||||
r = blkid_do_safeprobe(h->pr);
|
||||
#endif
|
||||
switch (r) {
|
||||
case -2:
|
||||
return PRB_AMBIGUOUS;
|
||||
case 1:
|
||||
return PRB_EMPTY;
|
||||
case 0:
|
||||
return PRB_OK;
|
||||
default:
|
||||
return PRB_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int blk_is_partition(struct blkid_handle *h)
|
||||
{
|
||||
int r = 0;
|
||||
#ifdef HAVE_BLKID
|
||||
r = blkid_probe_has_value(h->pr, "PTTYPE");
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
int blk_is_superblock(struct blkid_handle *h)
|
||||
{
|
||||
int r = 0;
|
||||
#ifdef HAVE_BLKID
|
||||
r = blkid_probe_has_value(h->pr, "TYPE");
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
const char *blk_get_partition_type(struct blkid_handle *h)
|
||||
{
|
||||
const char *value = NULL;
|
||||
#ifdef HAVE_BLKID
|
||||
(void) blkid_probe_lookup_value(h->pr, "PTTYPE", &value, NULL);
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
|
||||
const char *blk_get_superblock_type(struct blkid_handle *h)
|
||||
{
|
||||
const char *value = NULL;
|
||||
#ifdef HAVE_BLKID
|
||||
(void) blkid_probe_lookup_value(h->pr, "TYPE", &value, NULL);
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
|
||||
void blk_free(struct blkid_handle *h)
|
||||
{
|
||||
#ifdef HAVE_BLKID
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
if (h->pr)
|
||||
blkid_free_probe(h->pr);
|
||||
|
||||
free(h);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_BLKID
|
||||
#ifndef HAVE_BLKID_WIPE
|
||||
static int blk_step_back(struct blkid_handle *h)
|
||||
{
|
||||
#ifdef HAVE_BLKID_STEP_BACK
|
||||
return blkid_probe_step_back(h->pr);
|
||||
#else
|
||||
blkid_reset_probe(h->pr);
|
||||
blkid_probe_set_device(h->pr, h->fd, 0, 0);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif /* not HAVE_BLKID_WIPE */
|
||||
#endif /* HAVE_BLKID */
|
||||
|
||||
int blk_do_wipe(struct blkid_handle *h)
|
||||
{
|
||||
#ifdef HAVE_BLKID
|
||||
#ifdef HAVE_BLKID_WIPE
|
||||
return blkid_do_wipe(h->pr, 0);
|
||||
#else
|
||||
const char *offset;
|
||||
off_t offset_val;
|
||||
void *buf;
|
||||
ssize_t ret;
|
||||
size_t alignment, len, bsize = blkid_probe_get_sectorsize(h->pr);
|
||||
|
||||
if (h->fd < 0 || !bsize)
|
||||
return -EINVAL;
|
||||
|
||||
if (blk_is_partition(h)) {
|
||||
if (blkid_probe_lookup_value(h->pr, "PTMAGIC_OFFSET", &offset, NULL))
|
||||
return -EINVAL;
|
||||
if (blkid_probe_lookup_value(h->pr, "PTMAGIC", NULL, &len))
|
||||
return -EINVAL;
|
||||
} else if (blk_is_superblock(h)) {
|
||||
if (blkid_probe_lookup_value(h->pr, "SBMAGIC_OFFSET", &offset, NULL))
|
||||
return -EINVAL;
|
||||
if (blkid_probe_lookup_value(h->pr, "SBMAGIC", NULL, &len))
|
||||
return -EINVAL;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
alignment = crypt_getpagesize();
|
||||
|
||||
if (posix_memalign(&buf, alignment, len))
|
||||
return -EINVAL;
|
||||
memset(buf, 0, len);
|
||||
|
||||
offset_val = strtoll(offset, NULL, 10);
|
||||
|
||||
/* TODO: missing crypt_wipe_fd() */
|
||||
ret = write_lseek_blockwise(h->fd, bsize, alignment, buf, len, offset_val);
|
||||
free(buf);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
|
||||
if ((size_t)ret == len) {
|
||||
blk_step_back(h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
#endif
|
||||
#else /* HAVE_BLKID */
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
int blk_supported(void)
|
||||
{
|
||||
int r = 0;
|
||||
#ifdef HAVE_BLKID
|
||||
r = 1;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
62
lib/utils_blkid.h
Normal file
62
lib/utils_blkid.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* blkid probe utilities
|
||||
*
|
||||
* Copyright (C) 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
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _UTILS_BLKID_H
|
||||
#define _UTILS_BLKID_H
|
||||
|
||||
struct blkid_handle;
|
||||
|
||||
typedef enum { PRB_OK = 0, PRB_EMPTY, PRB_AMBIGUOUS, PRB_FAIL } blk_probe_status;
|
||||
|
||||
int blk_init_by_path(struct blkid_handle **h, const char *path);
|
||||
|
||||
void blk_free(struct blkid_handle *h);
|
||||
|
||||
/*
|
||||
* WARNING: This will reset file description offset as if
|
||||
* lseek(devfd, 0, SEEK_SET) was called!
|
||||
*/
|
||||
int blk_init_by_fd(struct blkid_handle **h, int fd);
|
||||
|
||||
void blk_set_chains_for_wipes(struct blkid_handle *h);
|
||||
|
||||
void blk_set_chains_for_full_print(struct blkid_handle *h);
|
||||
|
||||
void blk_set_chains_for_fast_detection(struct blkid_handle *h);
|
||||
|
||||
int blk_superblocks_filter_luks(struct blkid_handle *h);
|
||||
|
||||
blk_probe_status blk_safeprobe(struct blkid_handle *h);
|
||||
|
||||
blk_probe_status blk_probe(struct blkid_handle *h);
|
||||
|
||||
int blk_is_partition(struct blkid_handle *h);
|
||||
|
||||
int blk_is_superblock(struct blkid_handle *h);
|
||||
|
||||
const char *blk_get_partition_type(struct blkid_handle *h);
|
||||
|
||||
const char *blk_get_superblock_type(struct blkid_handle *h);
|
||||
|
||||
int blk_do_wipe(struct blkid_handle *h);
|
||||
|
||||
int blk_supported(void);
|
||||
|
||||
#endif
|
||||
@@ -105,6 +105,9 @@ int crypt_parse_integrity_mode(const char *s, char *integrity,
|
||||
!strcmp(s, "none")) {
|
||||
strncpy(integrity, s, MAX_CIPHER_LEN);
|
||||
ks = 0;
|
||||
} else if (!strcmp(s, "hmac-sha1")) {
|
||||
strncpy(integrity, "hmac(sha1)", MAX_CIPHER_LEN);
|
||||
ks = 20;
|
||||
} else if (!strcmp(s, "hmac-sha256")) {
|
||||
strncpy(integrity, "hmac(sha256)", MAX_CIPHER_LEN);
|
||||
ks = 32;
|
||||
@@ -152,10 +155,14 @@ int crypt_parse_pbkdf(const char *s, const char **pbkdf)
|
||||
*/
|
||||
void crypt_memzero(void *s, size_t n)
|
||||
{
|
||||
#ifdef HAVE_EXPLICIT_BZERO
|
||||
explicit_bzero(s, n);
|
||||
#else
|
||||
volatile uint8_t *p = (volatile uint8_t *)s;
|
||||
|
||||
while(n--)
|
||||
*p++ = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* safe allocations */
|
||||
|
||||
@@ -58,13 +58,19 @@ struct device {
|
||||
|
||||
static size_t device_fs_block_size_fd(int fd)
|
||||
{
|
||||
size_t page_size = crypt_getpagesize();
|
||||
|
||||
#ifdef HAVE_SYS_STATVFS_H
|
||||
struct statvfs buf;
|
||||
|
||||
if (!fstatvfs(fd, &buf) && buf.f_bsize)
|
||||
/*
|
||||
* NOTE: some filesystems (NFS) returns bogus blocksize (1MB).
|
||||
* Page-size io should always work and avoids increasing IO beyond aligned LUKS header.
|
||||
*/
|
||||
if (!fstatvfs(fd, &buf) && buf.f_bsize && buf.f_bsize <= page_size)
|
||||
return (size_t)buf.f_bsize;
|
||||
#endif
|
||||
return crypt_getpagesize();
|
||||
return page_size;
|
||||
}
|
||||
|
||||
static size_t device_block_size_fd(int fd, size_t *min_size)
|
||||
@@ -175,7 +181,7 @@ static int device_ready(struct device *device)
|
||||
}
|
||||
|
||||
if (devfd < 0) {
|
||||
log_err(NULL, _("Device %s doesn't exist or access denied.\n"),
|
||||
log_err(NULL, _("Device %s doesn't exist or access denied."),
|
||||
device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -184,6 +190,12 @@ static int device_ready(struct device *device)
|
||||
r = -EINVAL;
|
||||
else if (!S_ISBLK(st.st_mode))
|
||||
r = S_ISREG(st.st_mode) ? -ENOTBLK : -EINVAL;
|
||||
if (r == -EINVAL) {
|
||||
log_err(NULL, _("Device %s is not compatible."),
|
||||
device_path(device));
|
||||
close(devfd);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Allow only increase (loop device) */
|
||||
tmp_size = device_alignment_fd(devfd);
|
||||
@@ -223,6 +235,16 @@ static int _open_locked(struct device *device, int flags)
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Common wrapper for device sync.
|
||||
* FIXME: file descriptor will be in struct later.
|
||||
*/
|
||||
void device_sync(struct device *device, int devfd)
|
||||
{
|
||||
if (fsync(devfd) == -1)
|
||||
log_dbg("Cannot sync device %s.", device_path(device));
|
||||
}
|
||||
|
||||
/*
|
||||
* in non-locked mode returns always fd or -1
|
||||
*
|
||||
@@ -236,7 +258,6 @@ static int device_open_internal(struct device *device, int flags)
|
||||
{
|
||||
int devfd;
|
||||
|
||||
flags |= O_SYNC;
|
||||
if (device->o_direct)
|
||||
flags |= O_DIRECT;
|
||||
|
||||
@@ -246,7 +267,9 @@ static int device_open_internal(struct device *device, int flags)
|
||||
devfd = open(device_path(device), flags);
|
||||
|
||||
if (devfd < 0)
|
||||
log_dbg("Cannot open device %s.", device_path(device));
|
||||
log_dbg("Cannot open device %s%s.",
|
||||
device_path(device),
|
||||
(flags & O_ACCMODE) != O_RDONLY ? " for write" : "");
|
||||
|
||||
return devfd;
|
||||
}
|
||||
@@ -500,7 +523,7 @@ int device_fallocate(struct device *device, uint64_t size)
|
||||
struct stat st;
|
||||
int devfd, r = -EINVAL;
|
||||
|
||||
devfd = open(device_path(device), O_WRONLY);
|
||||
devfd = open(device_path(device), O_RDWR);
|
||||
if(devfd == -1)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -553,7 +576,7 @@ static int device_info(struct crypt_device *cd,
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
r = -EINVAL;
|
||||
r = errno ? -errno : -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -565,7 +588,7 @@ static int device_info(struct crypt_device *cd,
|
||||
} else {
|
||||
/* If the device can be opened read-write, i.e. readonly is still 0, then
|
||||
* check whether BKROGET says that it is read-only. E.g. read-only loop
|
||||
* devices may be openend read-write but are read-only according to BLKROGET
|
||||
* devices may be opened read-write but are read-only according to BLKROGET
|
||||
*/
|
||||
if (real_readonly == 0 && (r = ioctl(fd, BLKROGET, &real_readonly)) < 0)
|
||||
goto out;
|
||||
@@ -589,13 +612,14 @@ out:
|
||||
break;
|
||||
case -EBUSY:
|
||||
log_err(cd, _("Cannot use device %s which is in use "
|
||||
"(already mapped or mounted).\n"), device->path);
|
||||
"(already mapped or mounted)."), device_path(device));
|
||||
break;
|
||||
case -EACCES:
|
||||
log_err(cd, _("Cannot use device %s, permission denied.\n"), device->path);
|
||||
log_err(cd, _("Cannot use device %s, permission denied."), device_path(device));
|
||||
break;
|
||||
default:
|
||||
log_err(cd, _("Cannot get info about device %s.\n"), device->path);
|
||||
log_err(cd, _("Cannot get info about device %s."), device_path(device));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -618,7 +642,7 @@ static int device_internal_prepare(struct crypt_device *cd, struct device *devic
|
||||
|
||||
if (getuid() || geteuid()) {
|
||||
log_err(cd, _("Cannot use a loopback device, "
|
||||
"running as non-root user.\n"));
|
||||
"running as non-root user."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -628,7 +652,7 @@ static int device_internal_prepare(struct crypt_device *cd, struct device *devic
|
||||
loop_fd = crypt_loop_attach(&loop_device, device->path, 0, 1, &readonly);
|
||||
if (loop_fd == -1) {
|
||||
log_err(cd, _("Attaching loopback device failed "
|
||||
"(loop device with autoclear flag is required).\n"));
|
||||
"(loop device with autoclear flag is required)."));
|
||||
free(loop_device);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -673,15 +697,15 @@ int device_block_adjust(struct crypt_device *cd,
|
||||
return r;
|
||||
|
||||
if (device_offset >= real_size) {
|
||||
log_err(cd, _("Requested offset is beyond real size of device %s.\n"),
|
||||
device->path);
|
||||
log_err(cd, _("Requested offset is beyond real size of device %s."),
|
||||
device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (size && !*size) {
|
||||
*size = real_size;
|
||||
if (!*size) {
|
||||
log_err(cd, _("Device %s has zero size.\n"), device->path);
|
||||
log_err(cd, _("Device %s has zero size."), device_path(device));
|
||||
return -ENOTBLK;
|
||||
}
|
||||
*size -= device_offset;
|
||||
@@ -692,7 +716,7 @@ int device_block_adjust(struct crypt_device *cd,
|
||||
log_dbg("Device %s: offset = %" PRIu64 " requested size = %" PRIu64
|
||||
", backing device size = %" PRIu64,
|
||||
device->path, device_offset, *size, real_size);
|
||||
log_err(cd, _("Device %s is too small.\n"), device->path);
|
||||
log_err(cd, _("Device %s is too small."), device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ static int open_lock_dir(struct crypt_device *cd, const char *dir, const char *b
|
||||
if (dirfd < 0) {
|
||||
log_dbg("Failed to open directory %s: (%d: %s).", dir, errno, strerror(errno));
|
||||
if (errno == ENOTDIR || errno == ENOENT)
|
||||
log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (not a directory or missing).\n"), dir, base);
|
||||
log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (not a directory or missing)."), dir, base);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ static int open_lock_dir(struct crypt_device *cd, const char *dir, const char *b
|
||||
} else {
|
||||
log_dbg("Failed to open directory %s/%s: (%d: %s)", dir, base, errno, strerror(errno));
|
||||
if (errno == ENOTDIR || errno == ELOOP)
|
||||
log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (%s is not a directory).\n"), dir, base, base);
|
||||
log_err(cd, _("Locking aborted. The locking path %s/%s is unusable (%s is not a directory)."), dir, base, base);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ static void release_lock_handle(struct crypt_lock_handle *h)
|
||||
!flock(h->flock_fd, LOCK_EX | LOCK_NB) && /* lock to drop the file */
|
||||
!resource_by_devno(res, sizeof(res), h->devno, 1) && /* acquire lock resource name */
|
||||
!fstat(h->flock_fd, &buf_a) && /* read inode id referred by fd */
|
||||
!stat(res, &buf_b) && /* does path file stil exist? */
|
||||
!stat(res, &buf_b) && /* does path file still exist? */
|
||||
same_inode(buf_a, buf_b)) { /* is it same id as the one referenced by fd? */
|
||||
/* coverity[toctou] */
|
||||
if (unlink(res)) /* yes? unlink the file */
|
||||
|
||||
@@ -133,11 +133,13 @@ int dm_remove_device(struct crypt_device *cd, const char *name, uint32_t flags);
|
||||
int dm_status_device(struct crypt_device *cd, const char *name);
|
||||
int dm_status_suspended(struct crypt_device *cd, const char *name);
|
||||
int dm_status_verity_ok(struct crypt_device *cd, const char *name);
|
||||
int dm_status_integrity_failures(struct crypt_device *cd, const char *name, uint64_t *count);
|
||||
int dm_query_device(struct crypt_device *cd, const char *name,
|
||||
uint32_t get_flags, struct crypt_dm_active_device *dmd);
|
||||
int dm_create_device(struct crypt_device *cd, const char *name,
|
||||
const char *type, struct crypt_dm_active_device *dmd,
|
||||
int reload);
|
||||
int dm_suspend_device(struct crypt_device *cd, const char *name);
|
||||
int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name);
|
||||
int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
|
||||
const struct volume_key *vk);
|
||||
|
||||
299
lib/utils_io.c
Normal file
299
lib/utils_io.c
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* utils - miscellaneous I/O utilities for cryptsetup
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "utils_io.h"
|
||||
|
||||
static ssize_t _read_buffer(int fd, void *buf, size_t length, volatile int *quit)
|
||||
{
|
||||
size_t read_size = 0;
|
||||
ssize_t r;
|
||||
|
||||
if (fd < 0 || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
r = read(fd, buf, length - read_size);
|
||||
if (r == -1 && errno != EINTR)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
read_size += (size_t)r;
|
||||
buf = (uint8_t*)buf + r;
|
||||
}
|
||||
if (r == 0 || (quit && *quit))
|
||||
return (ssize_t)read_size;
|
||||
} while (read_size != length);
|
||||
|
||||
return (ssize_t)length;
|
||||
}
|
||||
|
||||
ssize_t read_buffer(int fd, void *buf, size_t length)
|
||||
{
|
||||
return _read_buffer(fd, buf, length, NULL);
|
||||
}
|
||||
|
||||
ssize_t read_buffer_intr(int fd, void *buf, size_t length, volatile int *quit)
|
||||
{
|
||||
return _read_buffer(fd, buf, length, quit);
|
||||
}
|
||||
|
||||
static ssize_t _write_buffer(int fd, const void *buf, size_t length, volatile int *quit)
|
||||
{
|
||||
size_t write_size = 0;
|
||||
ssize_t w;
|
||||
|
||||
if (fd < 0 || !buf || !length)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
w = write(fd, buf, length - write_size);
|
||||
if (w < 0 && errno != EINTR)
|
||||
return w;
|
||||
if (w > 0) {
|
||||
write_size += (size_t) w;
|
||||
buf = (const uint8_t*)buf + w;
|
||||
}
|
||||
if (w == 0 || (quit && *quit))
|
||||
return (ssize_t)write_size;
|
||||
} while (write_size != length);
|
||||
|
||||
return (ssize_t)write_size;
|
||||
}
|
||||
|
||||
ssize_t write_buffer(int fd, const void *buf, size_t length)
|
||||
{
|
||||
return _write_buffer(fd, buf, length, NULL);
|
||||
}
|
||||
|
||||
ssize_t write_buffer_intr(int fd, const void *buf, size_t length, volatile int *quit)
|
||||
{
|
||||
return _write_buffer(fd, buf, length, quit);
|
||||
}
|
||||
|
||||
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *orig_buf, size_t length)
|
||||
{
|
||||
void *hangover_buf = NULL, *buf = NULL;
|
||||
size_t hangover, solid;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !orig_buf || !bsize || !alignment)
|
||||
return -1;
|
||||
|
||||
hangover = length % bsize;
|
||||
solid = length - hangover;
|
||||
|
||||
if ((size_t)orig_buf & (alignment - 1)) {
|
||||
if (posix_memalign(&buf, alignment, length))
|
||||
return -1;
|
||||
memcpy(buf, orig_buf, length);
|
||||
} else
|
||||
buf = orig_buf;
|
||||
|
||||
if (solid) {
|
||||
r = write_buffer(fd, buf, solid);
|
||||
if (r < 0 || r != (ssize_t)solid)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hangover) {
|
||||
if (posix_memalign(&hangover_buf, alignment, bsize))
|
||||
goto out;
|
||||
memset(hangover_buf, 0, bsize);
|
||||
|
||||
r = read_buffer(fd, hangover_buf, bsize);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
if (lseek(fd, -(off_t)r, SEEK_CUR) < 0)
|
||||
goto out;
|
||||
|
||||
memcpy(hangover_buf, (char*)buf + solid, hangover);
|
||||
|
||||
r = write_buffer(fd, hangover_buf, bsize);
|
||||
if (r < 0 || r < (ssize_t)hangover)
|
||||
goto out;
|
||||
}
|
||||
ret = length;
|
||||
out:
|
||||
free(hangover_buf);
|
||||
if (buf != orig_buf)
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *orig_buf, size_t length)
|
||||
{
|
||||
void *hangover_buf = NULL, *buf = NULL;
|
||||
size_t hangover, solid;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !orig_buf || !bsize || !alignment)
|
||||
return -1;
|
||||
|
||||
hangover = length % bsize;
|
||||
solid = length - hangover;
|
||||
|
||||
if ((size_t)orig_buf & (alignment - 1)) {
|
||||
if (posix_memalign(&buf, alignment, length))
|
||||
return -1;
|
||||
} else
|
||||
buf = orig_buf;
|
||||
|
||||
r = read_buffer(fd, buf, solid);
|
||||
if (r < 0 || r != (ssize_t)solid)
|
||||
goto out;
|
||||
|
||||
if (hangover) {
|
||||
if (posix_memalign(&hangover_buf, alignment, bsize))
|
||||
goto out;
|
||||
r = read_buffer(fd, hangover_buf, bsize);
|
||||
if (r < 0 || r < (ssize_t)hangover)
|
||||
goto out;
|
||||
|
||||
memcpy((char *)buf + solid, hangover_buf, hangover);
|
||||
}
|
||||
ret = length;
|
||||
out:
|
||||
free(hangover_buf);
|
||||
if (buf != orig_buf) {
|
||||
if (ret != -1)
|
||||
memcpy(orig_buf, buf, length);
|
||||
free(buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Combines llseek with blockwise write. write_blockwise can already deal with short writes
|
||||
* but we also need a function to deal with short writes at the start. But this information
|
||||
* is implicitly included in the read/write offset, which can not be set to non-aligned
|
||||
* boundaries. Hence, we combine llseek with write.
|
||||
*/
|
||||
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *buf, size_t length, off_t offset)
|
||||
{
|
||||
void *frontPadBuf = NULL;
|
||||
size_t frontHang, innerCount = 0;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !buf || !bsize || !alignment)
|
||||
return -1;
|
||||
|
||||
if (offset < 0)
|
||||
offset = lseek(fd, offset, SEEK_END);
|
||||
|
||||
if (offset < 0)
|
||||
return -1;
|
||||
|
||||
frontHang = offset % bsize;
|
||||
|
||||
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
|
||||
return -1;
|
||||
|
||||
if (frontHang && length) {
|
||||
if (posix_memalign(&frontPadBuf, alignment, bsize))
|
||||
return -1;
|
||||
|
||||
innerCount = bsize - frontHang;
|
||||
if (innerCount > length)
|
||||
innerCount = length;
|
||||
|
||||
r = read_buffer(fd, frontPadBuf, bsize);
|
||||
if (r < 0 || r < (ssize_t)(frontHang + innerCount))
|
||||
goto out;
|
||||
|
||||
memcpy((char*)frontPadBuf + frontHang, buf, innerCount);
|
||||
|
||||
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
|
||||
goto out;
|
||||
|
||||
r = write_buffer(fd, frontPadBuf, bsize);
|
||||
if (r < 0 || r != (ssize_t)bsize)
|
||||
goto out;
|
||||
|
||||
buf = (char*)buf + innerCount;
|
||||
length -= innerCount;
|
||||
}
|
||||
|
||||
ret = length ? write_blockwise(fd, bsize, alignment, buf, length) : 0;
|
||||
if (ret >= 0)
|
||||
ret += innerCount;
|
||||
out:
|
||||
free(frontPadBuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *buf, size_t length, off_t offset)
|
||||
{
|
||||
void *frontPadBuf = NULL;
|
||||
size_t frontHang, innerCount = 0;
|
||||
ssize_t r, ret = -1;
|
||||
|
||||
if (fd == -1 || !buf || bsize <= 0)
|
||||
return -1;
|
||||
|
||||
if (offset < 0)
|
||||
offset = lseek(fd, offset, SEEK_END);
|
||||
|
||||
if (offset < 0)
|
||||
return -1;
|
||||
|
||||
frontHang = offset % bsize;
|
||||
|
||||
if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
|
||||
return -1;
|
||||
|
||||
if (frontHang && length) {
|
||||
if (posix_memalign(&frontPadBuf, alignment, bsize))
|
||||
return -1;
|
||||
|
||||
innerCount = bsize - frontHang;
|
||||
if (innerCount > length)
|
||||
innerCount = length;
|
||||
|
||||
r = read_buffer(fd, frontPadBuf, bsize);
|
||||
if (r < 0 || r < (ssize_t)(frontHang + innerCount))
|
||||
goto out;
|
||||
|
||||
memcpy(buf, (char*)frontPadBuf + frontHang, innerCount);
|
||||
|
||||
buf = (char*)buf + innerCount;
|
||||
length -= innerCount;
|
||||
}
|
||||
|
||||
ret = read_blockwise(fd, bsize, alignment, buf, length);
|
||||
if (ret >= 0)
|
||||
ret += innerCount;
|
||||
out:
|
||||
free(frontPadBuf);
|
||||
return ret;
|
||||
}
|
||||
42
lib/utils_io.h
Normal file
42
lib/utils_io.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* utils - miscellaneous I/O utilities for cryptsetup
|
||||
*
|
||||
* Copyright (C) 2004, Jana Saout <jana@saout.de>
|
||||
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2018, Milan Broz
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTSETUP_UTILS_IO_H
|
||||
#define _CRYPTSETUP_UTILS_IO_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
ssize_t read_buffer(int fd, void *buf, size_t length);
|
||||
ssize_t read_buffer_intr(int fd, void *buf, size_t length, volatile int *quit);
|
||||
ssize_t write_buffer(int fd, const void *buf, size_t length);
|
||||
ssize_t write_buffer_intr(int fd, const void *buf, size_t length, volatile int *quit);
|
||||
ssize_t write_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *orig_buf, size_t length);
|
||||
ssize_t read_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *orig_buf, size_t length);
|
||||
ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *buf, size_t length, off_t offset);
|
||||
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment,
|
||||
void *buf, size_t length, off_t offset);
|
||||
|
||||
#endif
|
||||
@@ -133,7 +133,8 @@ int keyring_get_passphrase(const char *key_desc,
|
||||
|
||||
if (ret < 0) {
|
||||
err = errno;
|
||||
crypt_memzero(buf, len);
|
||||
if (buf)
|
||||
crypt_memzero(buf, len);
|
||||
free(buf);
|
||||
return -err;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#ifndef _UTILS_KEYRING
|
||||
#define _UTILS_KEYRING
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
int keyring_check(void);
|
||||
|
||||
int keyring_get_passphrase(const char *key_desc,
|
||||
|
||||
@@ -65,13 +65,19 @@ int verify_pbkdf_params(struct crypt_device *cd,
|
||||
const char *pbkdf_type;
|
||||
int r = 0;
|
||||
|
||||
if (!pbkdf->type || !pbkdf->hash || !pbkdf->time_ms)
|
||||
if (!pbkdf->type ||
|
||||
(!pbkdf->hash && !strcmp(pbkdf->type, "pbkdf2")))
|
||||
return -EINVAL;
|
||||
|
||||
if (!pbkdf->time_ms && !(pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK)) {
|
||||
log_err(cd, _("Requested PBKDF target time cannot be zero."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* TODO: initialise crypto and check the hash and pbkdf are both available */
|
||||
r = crypt_parse_pbkdf(pbkdf->type, &pbkdf_type);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Unknown PBKDF type %s.\n"), pbkdf->type);
|
||||
log_err(cd, _("Unknown PBKDF type %s."), pbkdf->type);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -82,18 +88,18 @@ int verify_pbkdf_params(struct crypt_device *cd,
|
||||
if (crypt_get_type(cd) &&
|
||||
!strcmp(crypt_get_type(cd), CRYPT_LUKS1) &&
|
||||
strcmp(pbkdf_type, CRYPT_KDF_PBKDF2)) {
|
||||
log_err(cd, _("Requested PBKDF type is not supported for LUKS1.\n"));
|
||||
log_err(cd, _("Requested PBKDF type is not supported for LUKS1."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(pbkdf_type, CRYPT_KDF_PBKDF2)) {
|
||||
if (pbkdf->max_memory_kb || pbkdf->parallel_threads) {
|
||||
log_err(cd, _("PBKDF max memory or parallel threads must not be set with pbkdf2.\n"));
|
||||
log_err(cd, _("PBKDF max memory or parallel threads must not be set with pbkdf2."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK &&
|
||||
pbkdf->iterations < pbkdf_limits.min_iterations) {
|
||||
log_err(cd, _("Forced iteration count is too low for %s (minimum is %u).\n"),
|
||||
log_err(cd, _("Forced iteration count is too low for %s (minimum is %u)."),
|
||||
pbkdf_type, pbkdf_limits.min_iterations);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -103,32 +109,28 @@ int verify_pbkdf_params(struct crypt_device *cd,
|
||||
/* TODO: properly define minimal iterations and also minimal memory values */
|
||||
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) {
|
||||
if (pbkdf->iterations < pbkdf_limits.min_iterations) {
|
||||
log_err(cd, _("Forced iteration count is too low for %s (minimum is %u).\n"),
|
||||
log_err(cd, _("Forced iteration count is too low for %s (minimum is %u)."),
|
||||
pbkdf_type, pbkdf_limits.min_iterations);
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (pbkdf->max_memory_kb < pbkdf_limits.min_memory) {
|
||||
log_err(cd, _("Forced memory cost is too low for %s (minimum is %u kilobytes).\n"),
|
||||
log_err(cd, _("Forced memory cost is too low for %s (minimum is %u kilobytes)."),
|
||||
pbkdf_type, pbkdf_limits.min_memory);
|
||||
r = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (pbkdf->max_memory_kb > pbkdf_limits.max_memory) {
|
||||
log_err(cd, _("Requested maximum PBKDF memory cost is too high (maximum is %d kilobytes).\n"),
|
||||
log_err(cd, _("Requested maximum PBKDF memory cost is too high (maximum is %d kilobytes)."),
|
||||
pbkdf_limits.max_memory);
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (!pbkdf->max_memory_kb) {
|
||||
log_err(cd, _("Requested maximum PBKDF memory can not be zero.\n"));
|
||||
log_err(cd, _("Requested maximum PBKDF memory cannot be zero."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (!pbkdf->parallel_threads) {
|
||||
log_err(cd, _("Requested PBKDF parallel threads can not be zero.\n"));
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (!pbkdf->time_ms) {
|
||||
log_err(cd, _("Requested PBKDF target time can not be zero.\n"));
|
||||
log_err(cd, _("Requested PBKDF parallel threads cannot be zero."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
@@ -165,9 +167,9 @@ int init_pbkdf_type(struct crypt_device *cd,
|
||||
* It will fail later anyway :-)
|
||||
*/
|
||||
type = strdup(pbkdf->type);
|
||||
hash = strdup(pbkdf->hash);
|
||||
hash = pbkdf->hash ? strdup(pbkdf->hash) : NULL;
|
||||
|
||||
if (!type || !hash) {
|
||||
if (!type || (!hash && pbkdf->hash)) {
|
||||
free(CONST_CAST(void*)type);
|
||||
free(CONST_CAST(void*)hash);
|
||||
return -ENOMEM;
|
||||
@@ -251,6 +253,19 @@ const struct crypt_pbkdf_type *crypt_get_pbkdf_type(struct crypt_device *cd)
|
||||
return crypt_get_pbkdf(cd)->type ? crypt_get_pbkdf(cd) : NULL;
|
||||
}
|
||||
|
||||
const struct crypt_pbkdf_type *crypt_get_pbkdf_default(const char *type)
|
||||
{
|
||||
if (!type)
|
||||
return NULL;
|
||||
|
||||
if (!strcmp(type, CRYPT_LUKS1))
|
||||
return &default_luks1;
|
||||
else if (!strcmp(type, CRYPT_LUKS2))
|
||||
return &default_luks2;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_ms)
|
||||
{
|
||||
struct crypt_pbkdf_type *pbkdf;
|
||||
|
||||
@@ -153,7 +153,7 @@ int crypt_wipe_device(struct crypt_device *cd,
|
||||
/* FIXME: if wipe_block_size < bsize, then a wipe is highly ineffective */
|
||||
|
||||
/* Everything must be aligned to SECTOR_SIZE */
|
||||
if ((offset % SECTOR_SIZE) || (length % SECTOR_SIZE) || (wipe_block_size % SECTOR_SIZE))
|
||||
if (MISALIGNED_512(offset) || MISALIGNED_512(length) || MISALIGNED_512(wipe_block_size))
|
||||
return -EINVAL;
|
||||
|
||||
devfd = device_open(device, O_RDWR);
|
||||
@@ -161,9 +161,12 @@ int crypt_wipe_device(struct crypt_device *cd,
|
||||
return errno ? -errno : -EINVAL;
|
||||
|
||||
r = device_size(device, &dev_size);
|
||||
if (r)
|
||||
if (r || dev_size == 0)
|
||||
goto out;
|
||||
|
||||
if (dev_size < length)
|
||||
length = 0;
|
||||
|
||||
if (length) {
|
||||
if ((dev_size <= offset) || (dev_size - offset) < length) {
|
||||
r = -EINVAL;
|
||||
@@ -177,7 +180,7 @@ int crypt_wipe_device(struct crypt_device *cd,
|
||||
goto out;
|
||||
|
||||
if (lseek64(devfd, offset, SEEK_SET) < 0) {
|
||||
log_err(cd, "Cannot seek to device offset.\n");
|
||||
log_err(cd, "Cannot seek to device offset.");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -201,7 +204,7 @@ int crypt_wipe_device(struct crypt_device *cd,
|
||||
r = wipe_block(devfd, pattern, sf, bsize, alignment,
|
||||
wipe_block_size, offset, &need_block_init);
|
||||
if (r) {
|
||||
log_err(cd, "Device wipe error, offset %" PRIu64 ".\n", offset);
|
||||
log_err(cd, "Device wipe error, offset %" PRIu64 ".", offset);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -213,7 +216,7 @@ int crypt_wipe_device(struct crypt_device *cd,
|
||||
}
|
||||
}
|
||||
|
||||
fsync(devfd);
|
||||
device_sync(device, devfd);
|
||||
out:
|
||||
close(devfd);
|
||||
free(sf);
|
||||
|
||||
@@ -23,13 +23,41 @@
|
||||
#ifndef _LIBFEC_RS_H
|
||||
#define _LIBFEC_RS_H
|
||||
|
||||
/* Special reserved value encoding zero in index form. */
|
||||
#define A0 (rs->nn)
|
||||
|
||||
#define RS_MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
typedef unsigned char data_t;
|
||||
struct rs;
|
||||
|
||||
/* Reed-Solomon codec control block */
|
||||
struct rs {
|
||||
int mm; /* Bits per symbol */
|
||||
int nn; /* Symbols per block (= (1<<mm)-1) */
|
||||
data_t *alpha_to;/* log lookup table */
|
||||
data_t *index_of;/* Antilog lookup table */
|
||||
data_t *genpoly; /* Generator polynomial */
|
||||
int nroots; /* Number of generator roots = number of parity symbols */
|
||||
int fcr; /* First consecutive root, index form */
|
||||
int prim; /* Primitive element, index form */
|
||||
int iprim; /* prim-th root of 1, index form */
|
||||
int pad; /* Padding bytes in shortened block */
|
||||
};
|
||||
|
||||
static inline int modnn(struct rs *rs, int x)
|
||||
{
|
||||
while (x >= rs->nn) {
|
||||
x -= rs->nn;
|
||||
x = (x >> rs->mm) + (x & rs->nn);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
struct rs *init_rs_char(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad);
|
||||
void free_rs_char(struct rs *rs);
|
||||
|
||||
/* General purpose RS codec, 8-bit symbols */
|
||||
void encode_rs_char(struct rs *rs, data_t *data, data_t *parity);
|
||||
int decode_rs_char(struct rs *rs, data_t *data);
|
||||
|
||||
#endif
|
||||
|
||||
197
lib/verity/rs_decode_char.c
Normal file
197
lib/verity/rs_decode_char.c
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Reed-Solomon decoder, based on libfec
|
||||
*
|
||||
* Copyright (C) 2002, Phil Karn, KA9Q
|
||||
* libcryptsetup modifications
|
||||
* Copyright (C) 2017-2018, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rs.h"
|
||||
|
||||
int decode_rs_char(struct rs* rs, data_t* data)
|
||||
{
|
||||
int deg_lambda, el, deg_omega, syn_error, count;
|
||||
int i, j, r, k;
|
||||
data_t q, tmp, num1, num2, den, discr_r;
|
||||
/* FIXME: remove VLAs here */
|
||||
data_t lambda[rs->nroots + 1], s[rs->nroots]; /* Err+Eras Locator poly and syndrome poly */
|
||||
data_t b[rs->nroots + 1], t[rs->nroots + 1], omega[rs->nroots + 1];
|
||||
data_t root[rs->nroots], reg[rs->nroots + 1], loc[rs->nroots];
|
||||
|
||||
memset(s, 0, rs->nroots * sizeof(data_t));
|
||||
memset(b, 0, (rs->nroots + 1) * sizeof(data_t));
|
||||
|
||||
/* form the syndromes; i.e., evaluate data(x) at roots of g(x) */
|
||||
for (i = 0; i < rs->nroots; i++)
|
||||
s[i] = data[0];
|
||||
|
||||
for (j = 1; j < rs->nn - rs->pad; j++) {
|
||||
for (i = 0; i < rs->nroots; i++) {
|
||||
if (s[i] == 0) {
|
||||
s[i] = data[j];
|
||||
} else {
|
||||
s[i] = data[j] ^ rs->alpha_to[modnn(rs, rs->index_of[s[i]] + (rs->fcr + i) * rs->prim)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert syndromes to index form, checking for nonzero condition */
|
||||
syn_error = 0;
|
||||
for (i = 0; i < rs->nroots; i++) {
|
||||
syn_error |= s[i];
|
||||
s[i] = rs->index_of[s[i]];
|
||||
}
|
||||
|
||||
/*
|
||||
* if syndrome is zero, data[] is a codeword and there are no
|
||||
* errors to correct. So return data[] unmodified
|
||||
*/
|
||||
if (!syn_error)
|
||||
return 0;
|
||||
|
||||
memset(&lambda[1], 0, rs->nroots * sizeof(lambda[0]));
|
||||
lambda[0] = 1;
|
||||
|
||||
for (i = 0; i < rs->nroots + 1; i++)
|
||||
b[i] = rs->index_of[lambda[i]];
|
||||
|
||||
/*
|
||||
* Begin Berlekamp-Massey algorithm to determine error+erasure
|
||||
* locator polynomial
|
||||
*/
|
||||
r = 0;
|
||||
el = 0;
|
||||
while (++r <= rs->nroots) { /* r is the step number */
|
||||
/* Compute discrepancy at the r-th step in poly-form */
|
||||
discr_r = 0;
|
||||
for (i = 0; i < r; i++) {
|
||||
if ((lambda[i] != 0) && (s[r - i - 1] != A0)) {
|
||||
discr_r ^= rs->alpha_to[modnn(rs, rs->index_of[lambda[i]] + s[r - i - 1])];
|
||||
}
|
||||
}
|
||||
discr_r = rs->index_of[discr_r]; /* Index form */
|
||||
if (discr_r == A0) {
|
||||
/* 2 lines below: B(x) <-- x*B(x) */
|
||||
memmove(&b[1], b, rs->nroots * sizeof(b[0]));
|
||||
b[0] = A0;
|
||||
} else {
|
||||
/* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
|
||||
t[0] = lambda[0];
|
||||
for (i = 0; i < rs->nroots; i++) {
|
||||
if (b[i] != A0)
|
||||
t[i + 1] = lambda[i + 1] ^ rs->alpha_to[modnn(rs, discr_r + b[i])];
|
||||
else
|
||||
t[i + 1] = lambda[i + 1];
|
||||
}
|
||||
if (2 * el <= r - 1) {
|
||||
el = r - el;
|
||||
/*
|
||||
* 2 lines below: B(x) <-- inv(discr_r) *
|
||||
* lambda(x)
|
||||
*/
|
||||
for (i = 0; i <= rs->nroots; i++)
|
||||
b[i] = (lambda[i] == 0) ? A0 : modnn(rs, rs->index_of[lambda[i]] - discr_r + rs->nn);
|
||||
} else {
|
||||
/* 2 lines below: B(x) <-- x*B(x) */
|
||||
memmove(&b[1], b, rs->nroots * sizeof(b[0]));
|
||||
b[0] = A0;
|
||||
}
|
||||
memcpy(lambda, t, (rs->nroots + 1) * sizeof(t[0]));
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert lambda to index form and compute deg(lambda(x)) */
|
||||
deg_lambda = 0;
|
||||
for (i = 0; i < rs->nroots + 1; i++) {
|
||||
lambda[i] = rs->index_of[lambda[i]];
|
||||
if (lambda[i] != A0)
|
||||
deg_lambda = i;
|
||||
}
|
||||
/* Find roots of the error+erasure locator polynomial by Chien search */
|
||||
memcpy(®[1], &lambda[1], rs->nroots * sizeof(reg[0]));
|
||||
count = 0; /* Number of roots of lambda(x) */
|
||||
for (i = 1, k = rs->iprim - 1; i <= rs->nn; i++, k = modnn(rs, k + rs->iprim)) {
|
||||
q = 1; /* lambda[0] is always 0 */
|
||||
for (j = deg_lambda; j > 0; j--) {
|
||||
if (reg[j] != A0) {
|
||||
reg[j] = modnn(rs, reg[j] + j);
|
||||
q ^= rs->alpha_to[reg[j]];
|
||||
}
|
||||
}
|
||||
if (q != 0)
|
||||
continue; /* Not a root */
|
||||
|
||||
/* store root (index-form) and error location number */
|
||||
root[count] = i;
|
||||
loc[count] = k;
|
||||
/* If we've already found max possible roots, abort the search to save time */
|
||||
if (++count == deg_lambda)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* deg(lambda) unequal to number of roots => uncorrectable
|
||||
* error detected
|
||||
*/
|
||||
if (deg_lambda != count)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
|
||||
* x**rs->nroots). in index form. Also find deg(omega).
|
||||
*/
|
||||
deg_omega = deg_lambda - 1;
|
||||
for (i = 0; i <= deg_omega; i++) {
|
||||
tmp = 0;
|
||||
for (j = i; j >= 0; j--) {
|
||||
if ((s[i - j] != A0) && (lambda[j] != A0))
|
||||
tmp ^= rs->alpha_to[modnn(rs, s[i - j] + lambda[j])];
|
||||
}
|
||||
omega[i] = rs->index_of[tmp];
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
|
||||
* inv(X(l))**(rs->fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
|
||||
*/
|
||||
for (j = count - 1; j >= 0; j--) {
|
||||
num1 = 0;
|
||||
for (i = deg_omega; i >= 0; i--) {
|
||||
if (omega[i] != A0)
|
||||
num1 ^= rs->alpha_to[modnn(rs, omega[i] + i * root[j])];
|
||||
}
|
||||
num2 = rs->alpha_to[modnn(rs, root[j] * (rs->fcr - 1) + rs->nn)];
|
||||
den = 0;
|
||||
|
||||
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
|
||||
for (i = RS_MIN(deg_lambda, rs->nroots - 1) & ~1; i >= 0; i -= 2) {
|
||||
if (lambda[i + 1] != A0)
|
||||
den ^= rs->alpha_to[modnn(rs, lambda[i + 1] + i * root[j])];
|
||||
}
|
||||
|
||||
/* Apply error to data */
|
||||
if (num1 != 0 && loc[j] >= rs->pad) {
|
||||
data[loc[j] - rs->pad] ^= rs->alpha_to[modnn(rs, rs->index_of[num1] +
|
||||
rs->index_of[num2] + rs->nn - rs->index_of[den])];
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -25,32 +25,6 @@
|
||||
|
||||
#include "rs.h"
|
||||
|
||||
/* Special reserved value encoding zero in index form. */
|
||||
#define A0 (rs->nn)
|
||||
|
||||
/* Reed-Solomon codec control block */
|
||||
struct rs {
|
||||
int mm; /* Bits per symbol */
|
||||
int nn; /* Symbols per block (= (1<<mm)-1) */
|
||||
data_t *alpha_to;/* log lookup table */
|
||||
data_t *index_of;/* Antilog lookup table */
|
||||
data_t *genpoly; /* Generator polynomial */
|
||||
int nroots; /* Number of generator roots = number of parity symbols */
|
||||
int fcr; /* First consecutive root, index form */
|
||||
int prim; /* Primitive element, index form */
|
||||
int iprim; /* prim-th root of 1, index form */
|
||||
int pad; /* Padding bytes in shortened block */
|
||||
};
|
||||
|
||||
static inline int modnn(struct rs *rs, int x)
|
||||
{
|
||||
while (x >= rs->nn) {
|
||||
x -= rs->nn;
|
||||
x = (x >> rs->mm) + (x & rs->nn);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Initialize a Reed-Solomon codec
|
||||
* symsize = symbol size, bits
|
||||
* gfpoly = Field generator polynomial coefficients
|
||||
|
||||
@@ -66,19 +66,19 @@ int VERITY_read_sb(struct crypt_device *cd,
|
||||
sizeof(struct verity_sb), device_path(device), sb_offset);
|
||||
|
||||
if (params->flags & CRYPT_VERITY_NO_HEADER) {
|
||||
log_err(cd, _("Verity device %s doesn't use on-disk header.\n"),
|
||||
log_err(cd, _("Verity device %s doesn't use on-disk header."),
|
||||
device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sb_offset % 512) {
|
||||
log_err(cd, _("Unsupported VERITY hash offset.\n"));
|
||||
if (MISALIGNED_512(sb_offset)) {
|
||||
log_err(cd, _("Unsupported VERITY hash offset."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
devfd = device_open(device, O_RDONLY);
|
||||
if (devfd < 0) {
|
||||
log_err(cd, _("Cannot open device %s.\n"), device_path(device));
|
||||
log_err(cd, _("Cannot open device %s."), device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -91,19 +91,19 @@ int VERITY_read_sb(struct crypt_device *cd,
|
||||
close(devfd);
|
||||
|
||||
if (memcmp(sb.signature, VERITY_SIGNATURE, sizeof(sb.signature))) {
|
||||
log_err(cd, _("Device %s is not a valid VERITY device.\n"),
|
||||
log_err(cd, _("Device %s is not a valid VERITY device."),
|
||||
device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sb_version = le32_to_cpu(sb.version);
|
||||
if (sb_version != 1) {
|
||||
log_err(cd, _("Unsupported VERITY version %d.\n"), sb_version);
|
||||
log_err(cd, _("Unsupported VERITY version %d."), sb_version);
|
||||
return -EINVAL;
|
||||
}
|
||||
params->hash_type = le32_to_cpu(sb.hash_type);
|
||||
if (params->hash_type > VERITY_MAX_HASH_TYPE) {
|
||||
log_err(cd, _("Unsupported VERITY hash type %d.\n"), params->hash_type);
|
||||
log_err(cd, _("Unsupported VERITY hash type %d."), params->hash_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ int VERITY_read_sb(struct crypt_device *cd,
|
||||
params->hash_block_size = le32_to_cpu(sb.hash_block_size);
|
||||
if (VERITY_BLOCK_SIZE_OK(params->data_block_size) ||
|
||||
VERITY_BLOCK_SIZE_OK(params->hash_block_size)) {
|
||||
log_err(cd, _("Unsupported VERITY block size.\n"));
|
||||
log_err(cd, _("Unsupported VERITY block size."));
|
||||
return -EINVAL;
|
||||
}
|
||||
params->data_size = le64_to_cpu(sb.data_blocks);
|
||||
@@ -120,7 +120,7 @@ int VERITY_read_sb(struct crypt_device *cd,
|
||||
if (!params->hash_name)
|
||||
return -ENOMEM;
|
||||
if (crypt_hash_size(params->hash_name) <= 0) {
|
||||
log_err(cd, _("Hash algorithm %s not supported.\n"),
|
||||
log_err(cd, _("Hash algorithm %s not supported."),
|
||||
params->hash_name);
|
||||
free(CONST_CAST(char*)params->hash_name);
|
||||
params->hash_name = NULL;
|
||||
@@ -129,7 +129,7 @@ int VERITY_read_sb(struct crypt_device *cd,
|
||||
|
||||
params->salt_size = le16_to_cpu(sb.salt_size);
|
||||
if (params->salt_size > sizeof(sb.salt)) {
|
||||
log_err(cd, _("VERITY header corrupted.\n"));
|
||||
log_err(cd, _("VERITY header corrupted."));
|
||||
free(CONST_CAST(char*)params->hash_name);
|
||||
params->hash_name = NULL;
|
||||
return -EINVAL;
|
||||
@@ -166,20 +166,20 @@ int VERITY_write_sb(struct crypt_device *cd,
|
||||
sizeof(struct verity_sb), device_path(device), sb_offset);
|
||||
|
||||
if (!uuid_string || uuid_parse(uuid_string, uuid) == -1) {
|
||||
log_err(cd, _("Wrong VERITY UUID format provided on device %s.\n"),
|
||||
log_err(cd, _("Wrong VERITY UUID format provided on device %s."),
|
||||
device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (params->flags & CRYPT_VERITY_NO_HEADER) {
|
||||
log_err(cd, _("Verity device %s doesn't use on-disk header.\n"),
|
||||
log_err(cd, _("Verity device %s doesn't use on-disk header."),
|
||||
device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
devfd = device_open(device, O_RDWR);
|
||||
if (devfd < 0) {
|
||||
log_err(cd, _("Cannot open device %s.\n"), device_path(device));
|
||||
log_err(cd, _("Cannot open device %s."), device_path(device));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -199,8 +199,10 @@ int VERITY_write_sb(struct crypt_device *cd,
|
||||
r = write_lseek_blockwise(devfd, device_block_size(device), device_alignment(device),
|
||||
(char*)&sb, hdr_size, sb_offset) < hdr_size ? -EIO : 0;
|
||||
if (r)
|
||||
log_err(cd, _("Error during update of verity header on device %s.\n"),
|
||||
log_err(cd, _("Error during update of verity header on device %s."),
|
||||
device_path(device));
|
||||
|
||||
device_sync(device, devfd);
|
||||
close(devfd);
|
||||
|
||||
return r;
|
||||
@@ -242,6 +244,7 @@ int VERITY_activate(struct crypt_device *cd,
|
||||
{
|
||||
struct crypt_dm_active_device dmd;
|
||||
uint32_t dmv_flags;
|
||||
unsigned int fec_errors = 0;
|
||||
int r;
|
||||
|
||||
log_dbg("Trying to activate VERITY device %s using hash %s.",
|
||||
@@ -249,8 +252,18 @@ int VERITY_activate(struct crypt_device *cd,
|
||||
|
||||
if (verity_hdr->flags & CRYPT_VERITY_CHECK_HASH) {
|
||||
log_dbg("Verification of data in userspace required.");
|
||||
r = VERITY_verify(cd, verity_hdr,
|
||||
root_hash, root_hash_size);
|
||||
r = VERITY_verify(cd, verity_hdr, root_hash, root_hash_size);
|
||||
|
||||
if (r == -EPERM && fec_device) {
|
||||
log_dbg("Verification failed, trying to repair with FEC device.");
|
||||
r = VERITY_FEC_process(cd, verity_hdr, fec_device, 1, &fec_errors);
|
||||
if (r < 0)
|
||||
log_err(cd, _("Errors cannot be repaired with FEC device."));
|
||||
else if (fec_errors)
|
||||
log_err(cd, _("Found %u repairable errors with FEC device."),
|
||||
fec_errors);
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -291,7 +304,7 @@ int VERITY_activate(struct crypt_device *cd,
|
||||
|
||||
r = dm_create_device(cd, name, CRYPT_VERITY, &dmd, 0);
|
||||
if (r < 0 && (dm_flags(DM_VERITY, &dmv_flags) || !(dmv_flags & DM_VERITY_SUPPORTED))) {
|
||||
log_err(cd, _("Kernel doesn't support dm-verity mapping.\n"));
|
||||
log_err(cd, _("Kernel doesn't support dm-verity mapping."));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if (r < 0)
|
||||
@@ -302,6 +315,6 @@ int VERITY_activate(struct crypt_device *cd,
|
||||
return r;
|
||||
|
||||
if (!r)
|
||||
log_err(cd, _("Verity device detected corruption after activation.\n"));
|
||||
log_err(cd, _("Verity device detected corruption after activation."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef _VERITY_H
|
||||
#define _VERITY_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define VERITY_MAX_HASH_TYPE 1
|
||||
@@ -59,9 +60,11 @@ int VERITY_create(struct crypt_device *cd,
|
||||
char *root_hash,
|
||||
size_t root_hash_size);
|
||||
|
||||
int VERITY_FEC_create(struct crypt_device *cd,
|
||||
int VERITY_FEC_process(struct crypt_device *cd,
|
||||
struct crypt_params_verity *params,
|
||||
struct device *fec_device);
|
||||
struct device *fec_device,
|
||||
int check_fec,
|
||||
unsigned int *errors);
|
||||
|
||||
uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params);
|
||||
|
||||
|
||||
@@ -104,18 +104,18 @@ static int FEC_read_interleaved(struct fec_context *ctx, uint64_t i,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* encodes inputs to fd */
|
||||
static int FEC_encode_inputs(struct crypt_device *cd,
|
||||
struct crypt_params_verity *params,
|
||||
struct fec_input_device *inputs,
|
||||
size_t ninputs, int fd)
|
||||
/* encodes/decode inputs to/from fd */
|
||||
static int FEC_process_inputs(struct crypt_device *cd,
|
||||
struct crypt_params_verity *params,
|
||||
struct fec_input_device *inputs,
|
||||
size_t ninputs, int fd,
|
||||
int decode, unsigned int *errors)
|
||||
{
|
||||
int r = 0;
|
||||
unsigned int i;
|
||||
struct fec_context ctx;
|
||||
uint32_t b;
|
||||
uint64_t n;
|
||||
uint8_t parity[params->fec_roots];
|
||||
uint8_t rs_block[FEC_RSM];
|
||||
uint8_t *buf = NULL;
|
||||
void *rs;
|
||||
@@ -129,7 +129,7 @@ static int FEC_encode_inputs(struct crypt_device *cd,
|
||||
|
||||
rs = init_rs_char(FEC_PARAMS(ctx.roots));
|
||||
if (!rs) {
|
||||
log_err(cd, _("Failed to allocate RS context.\n"));
|
||||
log_err(cd, _("Failed to allocate RS context."));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -144,17 +144,17 @@ static int FEC_encode_inputs(struct crypt_device *cd,
|
||||
|
||||
buf = malloc((size_t)ctx.block_size * ctx.rsn);
|
||||
if (!buf) {
|
||||
log_err(cd, _("Failed to allocate buffer.\n"));
|
||||
log_err(cd, _("Failed to allocate buffer."));
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* encode input */
|
||||
/* encode/decode input */
|
||||
for (n = 0; n < ctx.rounds; ++n) {
|
||||
for (i = 0; i < ctx.rsn; ++i) {
|
||||
if (FEC_read_interleaved(&ctx, n * ctx.rsn * ctx.block_size + i,
|
||||
&buf[i * ctx.block_size], ctx.block_size)) {
|
||||
log_err(cd, _("Failed to read RS block %" PRIu64 " byte %d.\n"), n, i);
|
||||
log_err(cd, _("Failed to read RS block %" PRIu64 " byte %d."), n, i);
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
@@ -164,24 +164,45 @@ static int FEC_encode_inputs(struct crypt_device *cd,
|
||||
for (i = 0; i < ctx.rsn; ++i)
|
||||
rs_block[i] = buf[i * ctx.block_size + b];
|
||||
|
||||
encode_rs_char(rs, rs_block, parity);
|
||||
if (write_buffer(fd, parity, sizeof(parity)) != (ssize_t)sizeof(parity)) {
|
||||
log_err(cd, _("Failed to write parity for RS block %" PRIu64 ".\n"), n);
|
||||
r = -EIO;
|
||||
goto out;
|
||||
/* decoding from parity device */
|
||||
if (decode) {
|
||||
if (read_buffer(fd, &rs_block[ctx.rsn], ctx.roots) != ctx.roots) {
|
||||
log_err(cd, _("Failed to read parity for RS block %" PRIu64 "."), n);
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* coverity[tainted_data] */
|
||||
r = decode_rs_char(rs, rs_block);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Failed to repair parity for block %" PRIu64 "."), n);
|
||||
goto out;
|
||||
}
|
||||
/* return number of detected errors */
|
||||
if (errors)
|
||||
*errors += r;
|
||||
r = 0;
|
||||
} else {
|
||||
/* encoding and writing parity data to fec device */
|
||||
encode_rs_char(rs, rs_block, &rs_block[ctx.rsn]);
|
||||
if (write_buffer(fd, &rs_block[ctx.rsn], ctx.roots) != ctx.roots) {
|
||||
log_err(cd, _("Failed to write parity for RS block %" PRIu64 "."), n);
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
free_rs_char(rs);
|
||||
free(buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
int VERITY_FEC_create(struct crypt_device *cd,
|
||||
int VERITY_FEC_process(struct crypt_device *cd,
|
||||
struct crypt_params_verity *params,
|
||||
struct device *fec_device)
|
||||
struct device *fec_device, int check_fec,
|
||||
unsigned int *errors)
|
||||
{
|
||||
int r;
|
||||
int fd = -1;
|
||||
@@ -200,22 +221,25 @@ int VERITY_FEC_create(struct crypt_device *cd,
|
||||
|
||||
/* validate parameters */
|
||||
if (params->data_block_size != params->hash_block_size) {
|
||||
log_err(cd, _("Block sizes must match for FEC.\n"));
|
||||
log_err(cd, _("Block sizes must match for FEC."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (params->fec_roots > FEC_RSM - FEC_MIN_RSN ||
|
||||
params->fec_roots < FEC_RSM - FEC_MAX_RSN) {
|
||||
log_err(cd, _("Invalid number of parity bytes.\n"));
|
||||
log_err(cd, _("Invalid number of parity bytes."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = -EIO;
|
||||
|
||||
/* output device */
|
||||
fd = open(device_path(fec_device), O_RDWR);
|
||||
if (check_fec)
|
||||
fd = open(device_path(fec_device), O_RDONLY);
|
||||
else
|
||||
fd = open(device_path(fec_device), O_RDWR);
|
||||
|
||||
if (fd == -1) {
|
||||
log_err(cd, _("Cannot open device %s.\n"), device_path(fec_device));
|
||||
log_err(cd, _("Cannot open device %s."), device_path(fec_device));
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -227,25 +251,25 @@ int VERITY_FEC_create(struct crypt_device *cd,
|
||||
/* input devices */
|
||||
inputs[0].fd = open(device_path(inputs[0].device), O_RDONLY);
|
||||
if (inputs[0].fd == -1) {
|
||||
log_err(cd, _("Cannot open device %s.\n"), device_path(inputs[0].device));
|
||||
log_err(cd, _("Cannot open device %s."), device_path(inputs[0].device));
|
||||
goto out;
|
||||
}
|
||||
inputs[1].fd = open(device_path(inputs[1].device), O_RDONLY);
|
||||
if (inputs[1].fd == -1) {
|
||||
log_err(cd, _("Cannot open device %s.\n"), device_path(inputs[1].device));
|
||||
log_err(cd, _("Cannot open device %s."), device_path(inputs[1].device));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* cover the entire hash device starting from hash_offset */
|
||||
r = device_size(inputs[1].device, &inputs[1].count);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to determine size for device %s.\n"),
|
||||
log_err(cd, _("Failed to determine size for device %s."),
|
||||
device_path(inputs[1].device));
|
||||
goto out;
|
||||
}
|
||||
inputs[1].count -= inputs[1].start;
|
||||
|
||||
r = FEC_encode_inputs(cd, params, inputs, FEC_INPUT_DEVICES, fd);
|
||||
r = FEC_process_inputs(cd, params, inputs, FEC_INPUT_DEVICES, fd, check_fec, errors);
|
||||
out:
|
||||
if (inputs[0].fd != -1)
|
||||
close(inputs[0].fd);
|
||||
|
||||
@@ -56,7 +56,7 @@ static int verify_zero(struct crypt_device *cd, FILE *wr, size_t bytes)
|
||||
}
|
||||
for (i = 0; i < bytes; i++)
|
||||
if (block[i]) {
|
||||
log_err(cd, _("Spare area is not zeroed at position %" PRIu64 ".\n"),
|
||||
log_err(cd, _("Spare area is not zeroed at position %" PRIu64 "."),
|
||||
ftello(wr) - bytes);
|
||||
return -EPERM;
|
||||
}
|
||||
@@ -157,7 +157,7 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
|
||||
|
||||
if (mult_overflow(&seek_rd, data_block, data_block_size) ||
|
||||
mult_overflow(&seek_wr, hash_block, hash_block_size)) {
|
||||
log_err(cd, _("Device offset overflow.\n"));
|
||||
log_err(cd, _("Device offset overflow."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
|
||||
return -EIO;
|
||||
}
|
||||
if (memcmp(read_digest, calculated_digest, digest_size)) {
|
||||
log_err(cd, _("Verification failed at position %" PRIu64 ".\n"),
|
||||
log_err(cd, _("Verification failed at position %" PRIu64 "."),
|
||||
ftello(rd) - data_block_size);
|
||||
return -EPERM;
|
||||
}
|
||||
@@ -270,7 +270,7 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
|
||||
device_path(hash_device), hash_position);
|
||||
|
||||
if (data_blocks < 0 || hash_position < 0) {
|
||||
log_err(cd, _("Invalid size parameters for verity device.\n"));
|
||||
log_err(cd, _("Invalid size parameters for verity device."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -284,20 +284,20 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
|
||||
data_file_blocks = data_blocks;
|
||||
|
||||
if (mult_overflow(&data_device_size, data_blocks, data_block_size)) {
|
||||
log_err(cd, _("Device offset overflow.\n"));
|
||||
log_err(cd, _("Device offset overflow."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hash_levels(hash_block_size, digest_size, data_file_blocks, &hash_position,
|
||||
&levels, &hash_level_block[0], &hash_level_size[0])) {
|
||||
log_err(cd, _("Hash area overflow.\n"));
|
||||
log_err(cd, _("Hash area overflow."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
log_dbg("Using %d hash levels.", levels);
|
||||
|
||||
if (mult_overflow(&hash_device_size, hash_position, hash_block_size)) {
|
||||
log_err(cd, _("Device offset overflow.\n"));
|
||||
log_err(cd, _("Device offset overflow."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
|
||||
data_device_size);
|
||||
data_file = fopen(device_path(data_device), "r");
|
||||
if (!data_file) {
|
||||
log_err(cd, _("Cannot open device %s.\n"),
|
||||
log_err(cd, _("Cannot open device %s."),
|
||||
device_path(data_device)
|
||||
);
|
||||
r = -EIO;
|
||||
@@ -316,7 +316,7 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
|
||||
hash_device_size);
|
||||
hash_file = fopen(device_path(hash_device), verify ? "r" : "r+");
|
||||
if (!hash_file) {
|
||||
log_err(cd, _("Cannot open device %s.\n"),
|
||||
log_err(cd, _("Cannot open device %s."),
|
||||
device_path(hash_device));
|
||||
r = -EIO;
|
||||
goto out;
|
||||
@@ -336,7 +336,7 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
|
||||
} else {
|
||||
hash_file_2 = fopen(device_path(hash_device), "r");
|
||||
if (!hash_file_2) {
|
||||
log_err(cd, _("Cannot open device %s.\n"),
|
||||
log_err(cd, _("Cannot open device %s."),
|
||||
device_path(hash_device));
|
||||
r = -EIO;
|
||||
goto out;
|
||||
@@ -367,20 +367,20 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
|
||||
out:
|
||||
if (verify) {
|
||||
if (r)
|
||||
log_err(cd, _("Verification of data area failed.\n"));
|
||||
log_err(cd, _("Verification of data area failed."));
|
||||
else {
|
||||
log_dbg("Verification of data area succeeded.");
|
||||
r = memcmp(root_hash, calculated_digest, digest_size) ? -EPERM : 0;
|
||||
if (r)
|
||||
log_err(cd, _("Verification of root hash failed.\n"));
|
||||
log_err(cd, _("Verification of root hash failed."));
|
||||
else
|
||||
log_dbg("Verification of root hash succeeded.");
|
||||
}
|
||||
} else {
|
||||
if (r == -EIO)
|
||||
log_err(cd, _("Input/output error while creating hash area.\n"));
|
||||
log_err(cd, _("Input/output error while creating hash area."));
|
||||
else if (r)
|
||||
log_err(cd, _("Creation of hash area failed.\n"));
|
||||
log_err(cd, _("Creation of hash area failed."));
|
||||
else {
|
||||
fsync(fileno(hash_file));
|
||||
memcpy(root_hash, calculated_digest, digest_size);
|
||||
@@ -428,7 +428,7 @@ int VERITY_create(struct crypt_device *cd,
|
||||
|
||||
if (verity_hdr->data_block_size > pgsize)
|
||||
log_err(cd, _("WARNING: Kernel cannot activate device if data "
|
||||
"block size exceeds page size (%u).\n"), pgsize);
|
||||
"block size exceeds page size (%u)."), pgsize);
|
||||
|
||||
return VERITY_create_or_verify_hash(cd, 0,
|
||||
verity_hdr->hash_type,
|
||||
|
||||
@@ -23,7 +23,7 @@ The reencryption can be temporarily suspended (by TERM signal or by
|
||||
using ctrl+c) but you need to retain temporary files named LUKS-<uuid>.[log|org|new].
|
||||
LUKS device is unavailable until reencryption is finished though.
|
||||
|
||||
Current working directory must by writable and temporary
|
||||
Current working directory must be writable and temporary
|
||||
files created during reencryption must be present.
|
||||
|
||||
For more info about LUKS see cryptsetup(8).
|
||||
@@ -35,14 +35,14 @@ To start (or continue) re-encryption for <device> use:
|
||||
\fIcryptsetup-reencrypt\fR <device>
|
||||
|
||||
\fB<options>\fR can be [\-\-batch-mode, \-\-block-size, \-\-cipher | \-\-keep-key,
|
||||
\-\-debug, \-\-device-size, \-\-hash, \-\-iter-time | \-\-pbkdf\-force\-iterations,
|
||||
\-\-debug, \-\-device-size, \-\-hash, \-\-header, \-\-iter-time | \-\-pbkdf\-force\-iterations,
|
||||
\-\-key-file, \-\-key-size, \-\-key-slot, \-\-keyfile-offset, \-\-keyfile-size,
|
||||
\-\-tries, \-\-pbkdf, \-\-pbkdf\-memory, \-\-pbkdf\-parallel, \-\-progress-frequency,
|
||||
\-\-use-directio, \-\-use-random | \-\-use-urandom, \-\-use-fsync, \-\-uuid,
|
||||
\-\-verbose, \-\-write-log]
|
||||
\-\-master\-key\-file, \-\-tries, \-\-pbkdf, \-\-pbkdf\-memory, \-\-pbkdf\-parallel,
|
||||
\-\-progress-frequency, \-\-use-directio, \-\-use-random | \-\-use-urandom, \-\-use-fsync,
|
||||
\-\-uuid, \-\-verbose, \-\-write-log]
|
||||
|
||||
To encrypt data on (not yet encrypted) device, use \fI\-\-new\fR with combination
|
||||
with \fI\-\-reduce-device-size\fR.
|
||||
with \fI\-\-reduce-device-size\fR or with \fI\-\-header\fR option for detached header.
|
||||
|
||||
To remove encryption from device, use \fI\-\-decrypt\fR.
|
||||
|
||||
@@ -89,7 +89,17 @@ Specifies the hash used in the LUKS1 key setup scheme and volume key digest.
|
||||
for new LUKS1 device header.
|
||||
|
||||
\fBNOTE:\fR with LUKS2 format this option is only relevant when new keyslot pbkdf algorithm
|
||||
is set to PBKDF2 (see \fI\-\-pbkdf).
|
||||
is set to PBKDF2 (see \fI\-\-pbkdf\fR).
|
||||
.TP
|
||||
.B "\-\-header\fR \fI<LUKS header file>\fR"
|
||||
Use a detached (separated) metadata device or file where the
|
||||
LUKS header is stored. This option allows one to store ciphertext
|
||||
and LUKS header on different devices.
|
||||
|
||||
\fBWARNING:\fR There is no check whether the ciphertext device specified
|
||||
actually belongs to the header given.
|
||||
If used with \fI\-\-new\fR option, the header file will created (or overwritten).
|
||||
Use with care.
|
||||
.TP
|
||||
.B "\-\-iter-time, \-i \fI<milliseconds>\fR"
|
||||
The number of milliseconds to spend with PBKDF2 passphrase processing for the
|
||||
@@ -106,7 +116,7 @@ This option can be combined only with \fI\-\-hash\fR, \fI\-\-iter-time\fR,
|
||||
.B "\-\-key-file, \-d \fIname\fR"
|
||||
Read the passphrase from file.
|
||||
|
||||
\fBWARNING:\fR \-\-key-file option can be used only if there only one active keyslot,
|
||||
\fBWARNING:\fR \-\-key-file option can be used only if there is only one active keyslot,
|
||||
or alternatively, also if \-\-key-slot option is specified (then all other keyslots
|
||||
will be disabled in new LUKS device).
|
||||
|
||||
@@ -138,6 +148,9 @@ Read a maximum of \fIvalue\fR bytes from the key file.
|
||||
Default is to read the whole file up to the compiled-in
|
||||
maximum.
|
||||
.TP
|
||||
.B "\-\-master\-key\-file"
|
||||
Use new volume (master) key stored in a file.
|
||||
.TP
|
||||
.B "\-\-new, \-N"
|
||||
Create new header (encrypt not yet encrypted device).
|
||||
|
||||
|
||||
108
man/cryptsetup.8
108
man/cryptsetup.8
@@ -70,8 +70,8 @@ The following are valid actions for all supported device types.
|
||||
.IP
|
||||
Opens (creates a mapping with) <name> backed by device <device>.
|
||||
|
||||
Device type can be \fIplain\fR, \fIluks\fR (default), \fIloopaes\fR
|
||||
or \fItcrypt\fR.
|
||||
Device type can be \fIplain\fR, \fIluks\fR (default), \fIluks1\fR, \fIluks2\fR,
|
||||
\fIloopaes\fR or \fItcrypt\fR.
|
||||
|
||||
For backward compatibility there are \fBopen\fR command aliases:
|
||||
|
||||
@@ -243,7 +243,7 @@ the command prompts for it interactively.
|
||||
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
|
||||
\-\-keyfile\-size, \-\-readonly, \-\-test\-passphrase,
|
||||
\-\-allow\-discards, \-\-header, \-\-key-slot, \-\-master\-key\-file, \-\-token\-id,
|
||||
\-\-token\-only, \-\-disable\-keyring, \-\-disable\-locks].
|
||||
\-\-token\-only, \-\-disable\-keyring, \-\-disable\-locks, \-\-type].
|
||||
.PP
|
||||
\fIluksSuspend\fR <name>
|
||||
.IP
|
||||
@@ -266,19 +266,26 @@ Resumes a suspended device and reinstates the encryption key.
|
||||
Prompts interactively for a passphrase if \-\-key-file is not given.
|
||||
|
||||
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-size, \-\-header,
|
||||
\-\-disable\-keyring,\-\-disable\-locks]
|
||||
\-\-disable\-keyring, \-\-disable\-locks, \-\-type]
|
||||
.PP
|
||||
\fIluksAddKey\fR <device> [<key file with new key>]
|
||||
.IP
|
||||
adds a new passphrase. An existing passphrase must be supplied
|
||||
Adds a new passphrase. An existing passphrase must be supplied
|
||||
interactively or via \-\-key-file.
|
||||
The new passphrase to be added can be specified interactively
|
||||
or read from the file given as positional argument.
|
||||
|
||||
\fBNOTE:\fR with \-\-unbound option the action creates new unbound
|
||||
LUKS2 keyslot. The keyslot cannot be used for device activation.
|
||||
If you don't pass new key via \-\-master\-key\-file option,
|
||||
new random key is generated. Existing passphrase for any active keyslot
|
||||
is not required.
|
||||
|
||||
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
|
||||
\-\-keyfile\-size, \-\-new\-keyfile\-offset,
|
||||
\-\-new\-keyfile\-size, \-\-key\-slot, \-\-master\-key\-file,
|
||||
\-\-iter\-time, \-\-force\-password, \-\-header, \-\-disable\-locks].
|
||||
\-\-iter\-time, \-\-force\-password, \-\-header, \-\-disable\-locks,
|
||||
\-\-unbound, \-\-type].
|
||||
.PP
|
||||
\fIluksRemoveKey\fR <device> [<key file with passphrase to be removed>]
|
||||
.IP
|
||||
@@ -287,7 +294,7 @@ passphrase to be removed can be specified interactively,
|
||||
as the positional argument or via \-\-key-file.
|
||||
|
||||
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
|
||||
\-\-keyfile\-size, \-\-header, \-\-disable\-locks]
|
||||
\-\-keyfile\-size, \-\-header, \-\-disable\-locks, \-\-type]
|
||||
|
||||
\fBWARNING:\fR If you read the passphrase from stdin
|
||||
(without further argument or with '-' as an argument
|
||||
@@ -321,7 +328,31 @@ inaccessible.
|
||||
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
|
||||
\-\-keyfile\-size, \-\-new\-keyfile\-offset,
|
||||
\-\-new\-keyfile\-size, \-\-key\-slot, \-\-force\-password, \-\-header,
|
||||
\-\-disable\-locks].
|
||||
\-\-disable\-locks, \-\-type].
|
||||
.PP
|
||||
.PP
|
||||
\fIluksConvertKey\fR <device>
|
||||
.IP
|
||||
Converts an existing LUKS2 keyslot to new pbkdf parameters. The
|
||||
passphrase for keyslot to be converted must be supplied interactively
|
||||
or via \-\-key\-file. If no \-\-pbkdf parameters are specified LUKS2
|
||||
default pbkdf values will apply.
|
||||
|
||||
If a keyslot is specified (via \-\-key\-slot), the passphrase for that
|
||||
keyslot must be given. If no keyslot is specified and there is still
|
||||
a free keyslot, then the new parameters will be put into a free
|
||||
keyslot before the keyslot containing the old parameters is
|
||||
purged. If there is no free keyslot, then the keyslot with the old
|
||||
parameters is overwritten directly.
|
||||
|
||||
\fBWARNING:\fR If a keyslot is overwritten, a media failure during
|
||||
this operation can cause the overwrite to fail after the old
|
||||
parameters have been wiped and make the LUKS container inaccessible.
|
||||
|
||||
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
|
||||
\-\-keyfile\-size, \-\-key\-slot, \-\-header, \-\-disable\-locks,
|
||||
\-\-iter-time, \-\-pbkdf, \-\-pbkdf\-force\-iterations,
|
||||
\-\-pbkdf\-memory, \-\-pbkdf\-parallel].
|
||||
.PP
|
||||
\fIluksKillSlot\fR <device> <key slot number>
|
||||
.IP
|
||||
@@ -333,7 +364,7 @@ an interactive confirmation when doing so. Removing the last
|
||||
passphrase makes a LUKS container permanently inaccessible.
|
||||
|
||||
\fB<options>\fR can be [\-\-key\-file, \-\-keyfile\-offset,
|
||||
\-\-keyfile\-size, \-\-header, \-\-disable\-locks].
|
||||
\-\-keyfile\-size, \-\-header, \-\-disable\-locks, \-\-type].
|
||||
|
||||
\fBWARNING:\fR If you read the passphrase from stdin
|
||||
(without further argument or with '-' as an argument
|
||||
@@ -368,23 +399,27 @@ Set new UUID if \fI\-\-uuid\fR option is specified.
|
||||
Returns true, if <device> is a LUKS device, false otherwise.
|
||||
Use option \-v to get human-readable feedback. 'Command successful.'
|
||||
means the device is a LUKS device.
|
||||
|
||||
By specifying \-\-type you may query for specific LUKS version.
|
||||
.PP
|
||||
\fIluksDump\fR <device>
|
||||
.IP
|
||||
Dump the header information of a LUKS device.
|
||||
|
||||
If the \-\-dump\-master\-key option is used, the LUKS device master key is
|
||||
dumped instead of the keyslot info. Beware that the master key cannot be
|
||||
changed and can be used to decrypt the data stored in the LUKS container
|
||||
without a passphrase and even without the LUKS header. This means
|
||||
that if the master key is compromised, the whole device has to be
|
||||
erased to prevent further access. Use this option carefully.
|
||||
dumped instead of the keyslot info. Together with \-\-master\-key\-file option,
|
||||
master key is dumped to a file instead of standard output. Beware that the
|
||||
master key cannot be changed without reencryption and can be used to decrypt
|
||||
the data stored in the LUKS container without a passphrase and even without the
|
||||
LUKS header. This means that if the master key is compromised, the whole device
|
||||
has to be erased to prevent further access. Use this option carefully.
|
||||
|
||||
To dump the master key, a passphrase has to be supplied,
|
||||
either interactively or via \-\-key\-file.
|
||||
|
||||
\fB<options>\fR can be [\-\-dump\-master\-key, \-\-key\-file,
|
||||
\-\-keyfile\-offset, \-\-keyfile\-size, \-\-header, \-\-disable\-locks].
|
||||
\-\-keyfile\-offset, \-\-keyfile\-size, \-\-header, \-\-disable\-locks,
|
||||
\-\-master\-key\-file, \-\-type].
|
||||
|
||||
\fBWARNING:\fR If \-\-dump\-master\-key is used with \-\-key\-file
|
||||
and the argument to \-\-key\-file is '-', no validation question
|
||||
@@ -422,9 +457,9 @@ of the LUKS header already on the device and of the header backup
|
||||
match. Alternatively, if there is no LUKS header on the device,
|
||||
the backup will also be written to it.
|
||||
.PP
|
||||
\fItoken\fR <add|remove> <device>
|
||||
\fItoken\fR <add|remove|import|export> <device>
|
||||
.IP
|
||||
Adds a new keyring token to enable auto-activation of the device.
|
||||
Action \fIadd\fR creates new keyring token to enable auto-activation of the device.
|
||||
For the auto-activation, the passphrase must be stored in keyring with the specified
|
||||
description. Usually, the passphrase should be stored in \fIuser\fR or
|
||||
\fIuser-session\fR keyring.
|
||||
@@ -440,15 +475,27 @@ To remove existing token, specify the token ID which should be removed with
|
||||
\fBWARNING:\fR The action \fItoken remove\fR removes any token type, not just \fIkeyring\fR
|
||||
type from token slot specified by \-\-token\-id option.
|
||||
|
||||
\fB<options>\fR can be [\-\-header, \-\-token\-id, \-\-key-slot, \-\-key\-description,
|
||||
\-\-disable\-locks, \-\-disable\-keyring].
|
||||
Action \fIimport\fR can store arbitrary valid token json in LUKS2 header. It may be passed via
|
||||
standard input or via file passed in \-\-json\-file option. If you specify \-\-key\-slot then
|
||||
successfully imported token is also assigned to the key slot.
|
||||
|
||||
Action \fIexport\fR writes requested token json to a file passed with \-\-json\-file or
|
||||
to standard output.
|
||||
|
||||
\fB<options>\fR can be [\-\-header, \-\-token\-id, \-\-key\-slot, \-\-key\-description,
|
||||
\-\-disable\-locks, \-\-disable\-keyring, \-\-json\-file].
|
||||
.PP
|
||||
\fIconvert\fR <device> \-\-type <format>
|
||||
.IP
|
||||
Converts the device between LUKS and LUKS2 format (if possible).
|
||||
The conversion will not be performed if there is an additional LUKS2 feature or LUKS has
|
||||
Converts the device between LUKS1 and LUKS2 format (if possible).
|
||||
The conversion will not be performed if there is an additional LUKS2 feature or LUKS1 has
|
||||
unsupported header size.
|
||||
|
||||
Conversion (both directions) must be performed on inactive device. There must not be active
|
||||
dm-crypt mapping established for LUKS header requested for conversion.
|
||||
|
||||
\fB\-\-type\fR option is mandatory with following accepted values: \fIluks1\fR or \fIluks2\fR.
|
||||
|
||||
\fBWARNING:\fR The \fIconvert\fR action can destroy the LUKS header in the case of a crash
|
||||
during conversion or if a media error occurs.
|
||||
Always create a header backup before performing this operation!
|
||||
@@ -539,7 +586,7 @@ value, \fBadditionally to \-\-veracrypt \fR use either the
|
||||
line or use \fB\-\-veracrypt\-query\-pim\fR to be prompted for the PIM.
|
||||
|
||||
The PIM value affects the number of iterations applied during key derivation. Please refer to
|
||||
\fBhttps://www.veracrypt.fr/en/Personal%20Iterations%20Multiplier%20(PIM).html\fR
|
||||
\fBhttps://www.veracrypt.fr/en/Personal%20Iterations%20Multiplier%20%28PIM%29.html\fR
|
||||
for more detailed information.
|
||||
|
||||
\fBNOTE:\fR Activation with \fBtcryptOpen\fR is supported only for cipher chains
|
||||
@@ -630,7 +677,8 @@ for LUKS device type.
|
||||
This command is useful to fix some known benign LUKS metadata
|
||||
header corruptions. Only basic corruptions of unused keyslot
|
||||
are fixable. This command will only change the LUKS header, not
|
||||
any key-slot data.
|
||||
any key-slot data. You may enforce LUKS version by adding \-\-type
|
||||
option.
|
||||
|
||||
\fBWARNING:\fR Always create a binary backup of the original
|
||||
header before calling this command.
|
||||
@@ -770,6 +818,10 @@ LUKS header and all other parameters are the same,
|
||||
then the new header decrypts the data encrypted with the
|
||||
header the master key was taken from.
|
||||
|
||||
Action \fIluksDump\fR together with \-\-dump\-master\-key
|
||||
option: The volume (master) key is stored in a file instead of
|
||||
being printed out to standard output.
|
||||
|
||||
\fBWARNING:\fR If you create your own master key, you
|
||||
need to make sure to do it right. Otherwise, you can end
|
||||
up with a low-entropy or otherwise partially predictable
|
||||
@@ -786,6 +838,11 @@ For \fIluksDump\fR this option includes the master key in the displayed
|
||||
information. Use with care, as the master key can be used to
|
||||
bypass the passphrases, see also option \-\-master\-key\-file.
|
||||
.TP
|
||||
.B "\-\-json\-file"
|
||||
Read token json from a file or write token to it. See \fItoken\fR action for more
|
||||
information. \-\-json\-file=- reads json from standard input or writes it to
|
||||
standard output respectively.
|
||||
.TP
|
||||
.B "\-\-use\-random"
|
||||
.TP
|
||||
.B "\-\-use\-urandom"
|
||||
@@ -1136,6 +1193,11 @@ to the sector.
|
||||
aligned to page size and page-cache initiates read of a sector with invalid
|
||||
integrity tag.
|
||||
.TP
|
||||
.B "\-\-unbound"
|
||||
|
||||
Creates new LUKS2 unbound keyslot. See \fIluksAddKey\fR action for more
|
||||
details.
|
||||
.TP
|
||||
.B "\-\-tcrypt\-hidden"
|
||||
.B "\-\-tcrypt\-system"
|
||||
.B "\-\-tcrypt\-backup"
|
||||
|
||||
@@ -39,7 +39,8 @@ Creates a mapping with <name> backed by device <data_device> and using
|
||||
The <root_hash> is a hexadecimal string.
|
||||
|
||||
\fB<options>\fR can be [\-\-hash-offset, \-\-no-superblock,
|
||||
\-\-ignore-corruption or \-\-restart-on-corruption, \-\-ignore-zero-blocks]
|
||||
\-\-ignore-corruption or \-\-restart-on-corruption, \-\-ignore-zero-blocks,
|
||||
\-\-check-at-most-once]
|
||||
|
||||
If option \-\-no-superblock is used, you have to use as the same options
|
||||
as in initial format operation.
|
||||
@@ -133,6 +134,15 @@ and always directly return zeroes instead.
|
||||
\fBWARNING:\fR Use this option only in very specific cases.
|
||||
This option is available since Linux kernel version 4.5.
|
||||
.TP
|
||||
.B "\-\-check-at-most-once"
|
||||
Instruct kernel to verify blocks only the first time they are read
|
||||
from the data device, rather than every time.
|
||||
|
||||
\fBWARNING:\fR It provides a reduced level of security because only
|
||||
offline tampering of the data device's content will be detected,
|
||||
not online tampering.
|
||||
This option is available since Linux kernel version 4.17.
|
||||
.TP
|
||||
.B "\-\-hash=hash"
|
||||
Hash algorithm for dm-verity. For default see \-\-help option.
|
||||
.TP
|
||||
|
||||
@@ -123,7 +123,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
/*
|
||||
* Need to create temporary keyslot device-mapper devices and allocate loop if needed,
|
||||
* so root is requried here.
|
||||
* so root is required here.
|
||||
*/
|
||||
if (getuid() != 0) {
|
||||
printf("You must be root to run this program.\n");
|
||||
|
||||
@@ -28,4 +28,5 @@ install() {
|
||||
# shellcheck disable=SC2154
|
||||
inst_hook cmdline 30 "$moddir/parse-reencrypt.sh"
|
||||
inst_simple "$moddir"/reencrypt.sh /sbin/reencrypt
|
||||
inst_simple "$moddir"/reencrypt-verbose.sh /sbin/cryptsetup-reencrypt-verbose
|
||||
}
|
||||
|
||||
5
misc/dracut_90reencrypt/reencrypt-verbose.sh
Executable file
5
misc/dracut_90reencrypt/reencrypt-verbose.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Route stdout to stderr in initrd. Otherwise output is invisible
|
||||
# unless we run in debug mode.
|
||||
/sbin/cryptsetup-reencrypt $@ 1>&2
|
||||
@@ -18,7 +18,7 @@ else
|
||||
device="$1"
|
||||
fi
|
||||
|
||||
PARAMS="$device -T 1 --use-fsync -B 32"
|
||||
PARAMS="$device -T 1 --use-fsync --progress-frequency 5 -B 32"
|
||||
if [ "$3" != "any" ]; then
|
||||
PARAMS="$PARAMS -S $3"
|
||||
fi
|
||||
@@ -50,10 +50,10 @@ reenc_run() {
|
||||
fi
|
||||
/bin/plymouth ask-for-password \
|
||||
--prompt "$_prompt" \
|
||||
--command="/sbin/cryptsetup-reencrypt $PARAMS"
|
||||
--command="/sbin/cryptsetup-reencrypt-verbose $PARAMS"
|
||||
else
|
||||
info "REENCRYPT using key $1"
|
||||
reenc_readkey "$1" | /sbin/cryptsetup-reencrypt -d - $PARAMS
|
||||
reenc_readkey "$1" | /sbin/cryptsetup-reencrypt-verbose -d - $PARAMS
|
||||
fi
|
||||
_ret=$?
|
||||
cd $cwd
|
||||
|
||||
@@ -4,14 +4,11 @@ LDLIBS=-ljson-c -luuid -lgcrypt -ldevmapper -lpthread -lssh
|
||||
CC=gcc
|
||||
|
||||
TARGET2=keyslot_test_remote_pass
|
||||
TARGET4=keyslot_add_by_key
|
||||
|
||||
SOURCES=keyslot_test.c
|
||||
OBJECTS=$(SOURCES:.c=.o)
|
||||
SOURCES2=keyslot_test_remote_pass.c
|
||||
OBJECTS2=$(SOURCES2:.c=.o)
|
||||
SOURCES4=keyslot_add_by_key.c
|
||||
OBJECTS4=$(SOURCES4:.c=.o)
|
||||
|
||||
all: $(TARGET) $(TARGET2) $(TARGET4)
|
||||
|
||||
@@ -21,10 +18,7 @@ $(TARGET): $(OBJECTS) ../../.libs/libcryptsetup.a
|
||||
$(TARGET2): $(OBJECTS2) ../../.libs/libcryptsetup.a
|
||||
$(CC) -o $@ $^ $(LDLIBS)
|
||||
|
||||
$(TARGET4): $(OBJECTS4) ../../.libs/libcryptsetup.a
|
||||
$(CC) -o $@ $^ $(LDLIBS)
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ core $(TARGET) $(TARGET2) $(TARGET4)
|
||||
rm -f *.o *~ core $(TARGET) $(TARGET2)
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Prototype LUKS2 utility for keyslots unassigned to volume
|
||||
*
|
||||
* Copyright (C) 2017-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2017-2018, Ondrej Kozina <okozina@redhat.com>
|
||||
*
|
||||
* Use:
|
||||
* - generate LUKS2 device
|
||||
* - add new keyslot unassigned to segment using this example
|
||||
* (it'll generate random key with same size as volume key)
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libcryptsetup.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int r;
|
||||
struct crypt_device *cd;
|
||||
|
||||
if (argc < 3)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (crypt_init(&cd, argv[1])) {
|
||||
fprintf(stderr, "Failed to init device %s.\n", argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (crypt_load(cd, CRYPT_LUKS2, NULL)) {
|
||||
fprintf(stderr, "Failed to load luks2 device %s.\n", argv[1]);
|
||||
crypt_free(cd);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
r = crypt_keyslot_add_by_key(cd, CRYPT_ANY_SLOT, NULL,
|
||||
crypt_get_volume_key_size(cd), argv[2],
|
||||
strlen(argv[2]),
|
||||
CRYPT_VOLUME_KEY_NO_SEGMENT);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "Failed to load luks2 device %s.\n", argv[1]);
|
||||
|
||||
crypt_free(cd);
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
3181
po/pt_BR.po
3181
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
2810
po/zh_CN.po
2810
po/zh_CN.po
File diff suppressed because it is too large
Load Diff
@@ -512,6 +512,8 @@ static PyObject *CryptSetup_killSlot(CryptSetupObject* self, PyObject *args, PyO
|
||||
case CRYPT_SLOT_INVALID:
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid slot");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -4,8 +4,11 @@ if CRYPTSETUP
|
||||
cryptsetup_SOURCES = \
|
||||
lib/utils_crypt.c \
|
||||
lib/utils_loop.c \
|
||||
lib/utils_io.c \
|
||||
lib/utils_blkid.c \
|
||||
src/utils_tools.c \
|
||||
src/utils_password.c \
|
||||
src/utils_luks2.c \
|
||||
src/cryptsetup.c \
|
||||
src/cryptsetup.h
|
||||
|
||||
@@ -14,7 +17,8 @@ cryptsetup_LDADD = -lm \
|
||||
@POPT_LIBS@ \
|
||||
@PWQUALITY_LIBS@ \
|
||||
@PASSWDQC_LIBS@ \
|
||||
@UUID_LIBS@
|
||||
@UUID_LIBS@ \
|
||||
@BLKID_LIBS@
|
||||
|
||||
sbin_PROGRAMS += cryptsetup
|
||||
|
||||
@@ -36,13 +40,16 @@ if VERITYSETUP
|
||||
veritysetup_SOURCES = \
|
||||
lib/utils_crypt.c \
|
||||
lib/utils_loop.c \
|
||||
lib/utils_io.c \
|
||||
lib/utils_blkid.c \
|
||||
src/utils_tools.c \
|
||||
src/veritysetup.c \
|
||||
src/cryptsetup.h
|
||||
|
||||
veritysetup_LDADD = -lm \
|
||||
libcryptsetup.la \
|
||||
@POPT_LIBS@
|
||||
@POPT_LIBS@ \
|
||||
@BLKID_LIBS@
|
||||
|
||||
sbin_PROGRAMS += veritysetup
|
||||
|
||||
@@ -64,6 +71,8 @@ if INTEGRITYSETUP
|
||||
integritysetup_SOURCES = \
|
||||
lib/utils_crypt.c \
|
||||
lib/utils_loop.c \
|
||||
lib/utils_io.c \
|
||||
lib/utils_blkid.c \
|
||||
src/utils_tools.c \
|
||||
src/integritysetup.c \
|
||||
src/cryptsetup.h
|
||||
@@ -71,7 +80,8 @@ integritysetup_SOURCES = \
|
||||
integritysetup_LDADD = -lm \
|
||||
libcryptsetup.la \
|
||||
@POPT_LIBS@ \
|
||||
@UUID_LIBS@
|
||||
@UUID_LIBS@ \
|
||||
@BLKID_LIBS@
|
||||
|
||||
sbin_PROGRAMS += integritysetup
|
||||
|
||||
@@ -91,6 +101,8 @@ endif
|
||||
if REENCRYPT
|
||||
cryptsetup_reencrypt_SOURCES = \
|
||||
lib/utils_crypt.c \
|
||||
lib/utils_io.c \
|
||||
lib/utils_blkid.c \
|
||||
src/utils_tools.c \
|
||||
src/utils_password.c \
|
||||
src/cryptsetup_reencrypt.c \
|
||||
@@ -101,7 +113,8 @@ cryptsetup_reencrypt_LDADD = -lm \
|
||||
@POPT_LIBS@ \
|
||||
@PWQUALITY_LIBS@ \
|
||||
@PASSWDQC_LIBS@ \
|
||||
@UUID_LIBS@
|
||||
@UUID_LIBS@ \
|
||||
@BLKID_LIBS@
|
||||
|
||||
sbin_PROGRAMS += cryptsetup-reencrypt
|
||||
|
||||
|
||||
764
src/cryptsetup.c
764
src/cryptsetup.c
File diff suppressed because it is too large
Load Diff
@@ -43,6 +43,8 @@
|
||||
#include "lib/utils_crypt.h"
|
||||
#include "lib/utils_loop.h"
|
||||
#include "lib/utils_fips.h"
|
||||
#include "lib/utils_io.h"
|
||||
#include "lib/utils_blkid.h"
|
||||
|
||||
#include "libcryptsetup.h"
|
||||
|
||||
@@ -60,7 +62,6 @@ extern int opt_batch_mode;
|
||||
extern int opt_force_password;
|
||||
extern int opt_progress_frequency;
|
||||
|
||||
|
||||
/* Common tools */
|
||||
void clogger(struct crypt_device *cd, int level, const char *file, int line,
|
||||
const char *format, ...) __attribute__ ((format (printf, 5, 6)));
|
||||
@@ -75,6 +76,10 @@ void usage(poptContext popt_context, int exitcode, const char *error, const char
|
||||
void dbg_version_and_cmd(int argc, const char **argv);
|
||||
int translate_errno(int r);
|
||||
|
||||
typedef enum { CREATED, UNLOCKED, REMOVED } crypt_object_op;
|
||||
void tools_keyslot_msg(int keyslot, crypt_object_op op);
|
||||
void tools_token_msg(int token, crypt_object_op op);
|
||||
|
||||
extern volatile int quit;
|
||||
void set_int_block(int block);
|
||||
void set_int_handler(int block);
|
||||
@@ -87,6 +92,7 @@ int tools_get_key(const char *prompt,
|
||||
const char *key_file,
|
||||
int timeout, int verify, int pwquality,
|
||||
struct crypt_device *cd);
|
||||
void tools_passphrase_msg(int r);
|
||||
int tools_is_stdin(const char *key_file);
|
||||
int tools_string_to_size(struct crypt_device *cd, const char *s, uint64_t *size);
|
||||
int tools_is_cipher_null(const char *cipher);
|
||||
@@ -97,6 +103,15 @@ void tools_time_progress(uint64_t device_size, uint64_t bytes,
|
||||
struct timeval *start_time, struct timeval *end_time);
|
||||
int tools_wipe_progress(uint64_t size, uint64_t offset, void *usrptr);
|
||||
|
||||
int tools_read_mk(const char *file, char **key, int keysize);
|
||||
int tools_write_mk(const char *file, const char *key, int keysize);
|
||||
|
||||
int tools_read_json_file(struct crypt_device *cd, const char *file, char **json, size_t *json_size);
|
||||
int tools_write_json_file(struct crypt_device *cd, const char *file, const char *json);
|
||||
|
||||
int tools_detect_signatures(const char *device, int ignore_luks, size_t *count);
|
||||
int tools_wipe_all_signatures(const char *path);
|
||||
|
||||
/* Log */
|
||||
#define log_dbg(x...) clogger(NULL, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
|
||||
#define log_std(x...) clogger(NULL, CRYPT_LOG_NORMAL, __FILE__, __LINE__, x)
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
static const char *opt_cipher = NULL;
|
||||
static const char *opt_hash = NULL;
|
||||
static const char *opt_key_file = NULL;
|
||||
static const char *opt_master_key_file = NULL;
|
||||
static const char *opt_uuid = NULL;
|
||||
static const char *opt_type = "luks";
|
||||
static long opt_keyfile_size = 0;
|
||||
@@ -55,6 +56,7 @@ static int opt_key_size = 0;
|
||||
static int opt_new = 0;
|
||||
static int opt_keep_key = 0;
|
||||
static int opt_decrypt = 0;
|
||||
static const char *opt_header_device = NULL;
|
||||
|
||||
static const char *opt_reduce_size_str = NULL;
|
||||
static uint64_t opt_reduce_size = 0;
|
||||
@@ -68,6 +70,7 @@ static const char **action_argv;
|
||||
#define MAX_TOKEN 32
|
||||
struct reenc_ctx {
|
||||
char *device;
|
||||
char *device_header;
|
||||
char *device_uuid;
|
||||
const char *type;
|
||||
uint64_t device_size; /* overridden by parameter */
|
||||
@@ -140,13 +143,20 @@ static const char *luksType(const char *type)
|
||||
if (type && !strcmp(type, "luks2"))
|
||||
return CRYPT_LUKS2;
|
||||
|
||||
/* make LUKS1 default */
|
||||
if (type && (!strcmp(type, "luks1") || !strcmp(type, "luks")))
|
||||
if (type && !strcmp(type, "luks1"))
|
||||
return CRYPT_LUKS1;
|
||||
|
||||
if (!type || !strcmp(type, "luks"))
|
||||
return DEFAULT_LUKS_FORMAT;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *hdr_device(const struct reenc_ctx *rc)
|
||||
{
|
||||
return rc->device_header ?: rc->device;
|
||||
}
|
||||
|
||||
static int set_reencrypt_requirement(const struct reenc_ctx *rc)
|
||||
{
|
||||
uint32_t reqs;
|
||||
@@ -154,20 +164,20 @@ static int set_reencrypt_requirement(const struct reenc_ctx *rc)
|
||||
struct crypt_device *cd = NULL;
|
||||
struct crypt_params_integrity ip = { 0 };
|
||||
|
||||
if (crypt_init(&cd, rc->device) ||
|
||||
if (crypt_init(&cd, hdr_device(rc)) ||
|
||||
crypt_load(cd, CRYPT_LUKS2, NULL) ||
|
||||
crypt_persistent_flags_get(cd, CRYPT_FLAGS_REQUIREMENTS, &reqs))
|
||||
goto out;
|
||||
|
||||
/* reencrypt already in-progress */
|
||||
if (reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT) {
|
||||
log_err(_("Reencryption already in-progress.\n"));
|
||||
log_err(_("Reencryption already in-progress."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* raw integrity info is available since 2.0 */
|
||||
if (crypt_get_integrity_info(cd, &ip) || ip.tag_size) {
|
||||
log_err(_("Reencryption of device with integrity profile is not supported.\n"));
|
||||
log_err(_("Reencryption of device with integrity profile is not supported."));
|
||||
r = -ENOTSUP;
|
||||
goto out;
|
||||
}
|
||||
@@ -179,7 +189,7 @@ out:
|
||||
}
|
||||
|
||||
/* Depends on the first two fields of LUKS1 header format, magic and version */
|
||||
static int device_check(struct reenc_ctx *rc, header_magic set_magic)
|
||||
static int device_check(struct reenc_ctx *rc, const char *device, header_magic set_magic)
|
||||
{
|
||||
char *buf = NULL;
|
||||
int r, devfd;
|
||||
@@ -187,14 +197,14 @@ static int device_check(struct reenc_ctx *rc, header_magic set_magic)
|
||||
uint16_t version;
|
||||
size_t buf_size = pagesize();
|
||||
|
||||
devfd = open(rc->device, O_RDWR | O_EXCL | O_DIRECT);
|
||||
devfd = open(device, O_RDWR | O_EXCL | O_DIRECT);
|
||||
if (devfd == -1) {
|
||||
if (errno == EBUSY) {
|
||||
log_err(_("Cannot exclusively open %s, device in use.\n"),
|
||||
rc->device);
|
||||
log_err(_("Cannot exclusively open %s, device in use."),
|
||||
device);
|
||||
return -EBUSY;
|
||||
}
|
||||
log_err(_("Cannot open device %s.\n"), rc->device);
|
||||
log_err(_("Cannot open device %s."), device);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -204,14 +214,14 @@ static int device_check(struct reenc_ctx *rc, header_magic set_magic)
|
||||
}
|
||||
|
||||
if (posix_memalign((void *)&buf, alignment(devfd), buf_size)) {
|
||||
log_err(_("Allocation of aligned memory failed.\n"));
|
||||
log_err(_("Allocation of aligned memory failed."));
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
s = read(devfd, buf, buf_size);
|
||||
if (s < 0 || s != (ssize_t)buf_size) {
|
||||
log_err(_("Cannot read device %s.\n"), rc->device);
|
||||
log_err(_("Cannot read device %s."), device);
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
@@ -222,11 +232,11 @@ static int device_check(struct reenc_ctx *rc, header_magic set_magic)
|
||||
|
||||
if (set_magic == MAKE_UNUSABLE && !memcmp(buf, MAGIC, MAGIC_L) &&
|
||||
version == 1) {
|
||||
log_verbose(_("Marking LUKS1 device %s unusable.\n"), rc->device);
|
||||
log_verbose(_("Marking LUKS1 device %s unusable."), device);
|
||||
memcpy(buf, NOMAGIC, MAGIC_L);
|
||||
r = 0;
|
||||
} else if (set_magic == MAKE_UNUSABLE && version == 2) {
|
||||
log_verbose(_("Setting LUKS2 offline reencrypt flag on device %s.\n"), rc->device);
|
||||
log_verbose(_("Setting LUKS2 offline reencrypt flag on device %s."), device);
|
||||
r = set_reencrypt_requirement(rc);
|
||||
if (!r)
|
||||
rc->stained = 1;
|
||||
@@ -243,14 +253,14 @@ static int device_check(struct reenc_ctx *rc, header_magic set_magic)
|
||||
goto out;
|
||||
s = write(devfd, buf, buf_size);
|
||||
if (s < 0 || s != (ssize_t)buf_size) {
|
||||
log_err(_("Cannot write device %s.\n"), rc->device);
|
||||
log_err(_("Cannot write device %s."), device);
|
||||
r = -EIO;
|
||||
}
|
||||
if (s > 0 && set_magic == MAKE_UNUSABLE)
|
||||
rc->stained = 1;
|
||||
}
|
||||
if (r)
|
||||
log_dbg("LUKS signature check failed for %s.", rc->device);
|
||||
log_dbg("LUKS signature check failed for %s.", device);
|
||||
out:
|
||||
if (buf)
|
||||
memset(buf, 0, buf_size);
|
||||
@@ -284,7 +294,7 @@ static int create_empty_header(const char *new_file, const char *old_file,
|
||||
* if requesting key size change, try to use offset
|
||||
* here can be enough space to fit new key.
|
||||
*/
|
||||
if (opt_key_size)
|
||||
if (opt_key_size && data_sector)
|
||||
size = data_sector * SECTOR_SIZE;
|
||||
|
||||
/* if reducing size, be sure we have enough space */
|
||||
@@ -327,7 +337,7 @@ static int write_log(struct reenc_ctx *rc)
|
||||
|
||||
r = write(rc->log_fd, rc->log_buf, SECTOR_SIZE);
|
||||
if (r < 0 || r != SECTOR_SIZE) {
|
||||
log_err(_("Cannot write reencryption log file.\n"));
|
||||
log_err(_("Cannot write reencryption log file."));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -383,7 +393,7 @@ static int parse_log(struct reenc_ctx *rc)
|
||||
|
||||
s = read(rc->log_fd, rc->log_buf, SECTOR_SIZE);
|
||||
if (s == -1) {
|
||||
log_err(_("Cannot read reencryption log file.\n"));
|
||||
log_err(_("Cannot read reencryption log file."));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -394,7 +404,7 @@ static int parse_log(struct reenc_ctx *rc)
|
||||
if (end) {
|
||||
*end++ = '\0';
|
||||
if (parse_line_log(rc, start)) {
|
||||
log_err("Wrong log format.\n");
|
||||
log_err("Wrong log format.");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
@@ -471,7 +481,7 @@ static int activate_luks_headers(struct reenc_ctx *rc)
|
||||
(r = crypt_set_data_device(cd, rc->device)))
|
||||
goto out;
|
||||
|
||||
log_verbose(_("Activating temporary device using old LUKS header.\n"));
|
||||
log_verbose(_("Activating temporary device using old LUKS header."));
|
||||
if ((r = crypt_activate_by_passphrase(cd, rc->header_file_org,
|
||||
opt_key_slot, pwd_old, pwd_old_len,
|
||||
CRYPT_ACTIVATE_READONLY|CRYPT_ACTIVATE_PRIVATE)) < 0)
|
||||
@@ -482,7 +492,7 @@ static int activate_luks_headers(struct reenc_ctx *rc)
|
||||
(r = crypt_set_data_device(cd_new, rc->device)))
|
||||
goto out;
|
||||
|
||||
log_verbose(_("Activating temporary device using new LUKS header.\n"));
|
||||
log_verbose(_("Activating temporary device using new LUKS header."));
|
||||
if ((r = crypt_activate_by_passphrase(cd_new, rc->header_file_new,
|
||||
opt_key_slot, pwd_new, pwd_new_len,
|
||||
CRYPT_ACTIVATE_SHARED|CRYPT_ACTIVATE_PRIVATE)) < 0)
|
||||
@@ -492,7 +502,7 @@ out:
|
||||
crypt_free(cd);
|
||||
crypt_free(cd_new);
|
||||
if (r < 0)
|
||||
log_err(_("Activation of temporary devices failed.\n"));
|
||||
log_err(_("Activation of temporary devices failed."));
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -525,8 +535,38 @@ static int set_pbkdf_params(struct crypt_device *cd, const char *dev_type)
|
||||
return crypt_set_pbkdf_type(cd, &pbkdf);
|
||||
}
|
||||
|
||||
static int create_new_header(struct reenc_ctx *rc, const char *cipher,
|
||||
const char *cipher_mode, const char *uuid,
|
||||
static int create_new_keyslot(struct reenc_ctx *rc, int keyslot,
|
||||
struct crypt_device *cd_old,
|
||||
struct crypt_device *cd_new)
|
||||
{
|
||||
int r;
|
||||
char *key = NULL;
|
||||
size_t key_size;
|
||||
|
||||
if (cd_old && crypt_keyslot_status(cd_old, keyslot) == CRYPT_SLOT_UNBOUND) {
|
||||
key_size = 4096;
|
||||
key = crypt_safe_alloc(key_size);
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
r = crypt_volume_key_get(cd_old, keyslot, key, &key_size,
|
||||
rc->p[keyslot].password, rc->p[keyslot].passwordLen);
|
||||
if (r == keyslot) {
|
||||
r = crypt_keyslot_add_by_key(cd_new, keyslot, key, key_size,
|
||||
rc->p[keyslot].password, rc->p[keyslot].passwordLen,
|
||||
CRYPT_VOLUME_KEY_NO_SEGMENT);
|
||||
} else
|
||||
r = -EINVAL;
|
||||
crypt_safe_free(key);
|
||||
} else
|
||||
r = crypt_keyslot_add_by_volume_key(cd_new, keyslot, NULL, 0,
|
||||
rc->p[keyslot].password, rc->p[keyslot].passwordLen);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int create_new_header(struct reenc_ctx *rc, struct crypt_device *cd_old,
|
||||
const char *cipher, const char *cipher_mode,
|
||||
const char *uuid,
|
||||
const char *key, int key_size,
|
||||
const char *type,
|
||||
void *params)
|
||||
@@ -544,22 +584,23 @@ static int create_new_header(struct reenc_ctx *rc, const char *cipher,
|
||||
|
||||
r = set_pbkdf_params(cd_new, type);
|
||||
if (r) {
|
||||
log_err(_("Failed to set PBKDF parameters.\n"));
|
||||
log_err(_("Failed to set PBKDF parameters."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((r = crypt_format(cd_new, type, cipher, cipher_mode,
|
||||
uuid, key, key_size, params)))
|
||||
goto out;
|
||||
log_verbose(_("New LUKS header for device %s created.\n"), rc->device);
|
||||
log_verbose(_("New LUKS header for device %s created."), rc->device);
|
||||
|
||||
for (i = 0; i < crypt_keyslot_max(type); i++) {
|
||||
if (!rc->p[i].password)
|
||||
continue;
|
||||
if ((r = crypt_keyslot_add_by_volume_key(cd_new, i,
|
||||
NULL, 0, rc->p[i].password, rc->p[i].passwordLen)) < 0)
|
||||
|
||||
r = create_new_keyslot(rc, i, cd_old, cd_new);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
log_verbose(_("Activated keyslot %i.\n"), r);
|
||||
tools_keyslot_msg(r, CREATED);
|
||||
r = 0;
|
||||
}
|
||||
out:
|
||||
@@ -609,7 +650,7 @@ static int luks2_metadata_copy(struct reenc_ctx *rc)
|
||||
case CRYPT_TOKEN_INACTIVE:
|
||||
break;
|
||||
case CRYPT_TOKEN_INTERNAL_UNKNOWN:
|
||||
log_err(_("This version of cryptsetup-reencrypt can't handle new internal token type %s.\n"), type);
|
||||
log_err(_("This version of cryptsetup-reencrypt can't handle new internal token type %s."), type);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
case CRYPT_TOKEN_INTERNAL:
|
||||
@@ -631,19 +672,19 @@ static int luks2_metadata_copy(struct reenc_ctx *rc)
|
||||
}
|
||||
|
||||
if ((r = crypt_persistent_flags_get(cd_old, CRYPT_FLAGS_ACTIVATION, &flags))) {
|
||||
log_err(_("Failed to read activation flags from backup header.\n"));
|
||||
log_err(_("Failed to read activation flags from backup header."));
|
||||
goto out;
|
||||
}
|
||||
if ((r = crypt_persistent_flags_set(cd_new, CRYPT_FLAGS_ACTIVATION, flags))) {
|
||||
log_err(_("Failed to write activation flags to new header.\n"));
|
||||
log_err(_("Failed to write activation flags to new header."));
|
||||
goto out;
|
||||
}
|
||||
if ((r = crypt_persistent_flags_get(cd_old, CRYPT_FLAGS_REQUIREMENTS, &flags))) {
|
||||
log_err(_("Failed to read requirements from backup header.\n"));
|
||||
log_err(_("Failed to read requirements from backup header."));
|
||||
goto out;
|
||||
}
|
||||
if ((r = crypt_persistent_flags_set(cd_new, CRYPT_FLAGS_REQUIREMENTS, flags)))
|
||||
log_err(_("Failed to read requirements from backup header.\n"));
|
||||
log_err(_("Failed to read requirements from backup header."));
|
||||
out:
|
||||
crypt_free(cd_old);
|
||||
crypt_free(cd_new);
|
||||
@@ -659,13 +700,13 @@ static int backup_luks_headers(struct reenc_ctx *rc)
|
||||
struct crypt_params_luks2 params2 = {0};
|
||||
struct stat st;
|
||||
char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
|
||||
char *old_key = NULL;
|
||||
size_t old_key_size;
|
||||
char *key = NULL;
|
||||
size_t key_size;
|
||||
int r;
|
||||
|
||||
log_dbg("Creating LUKS header backup for device %s.", rc->device);
|
||||
log_dbg("Creating LUKS header backup for device %s.", hdr_device(rc));
|
||||
|
||||
if ((r = crypt_init(&cd, rc->device)) ||
|
||||
if ((r = crypt_init(&cd, hdr_device(rc))) ||
|
||||
(r = crypt_load(cd, CRYPT_LUKS, NULL)))
|
||||
goto out;
|
||||
|
||||
@@ -676,10 +717,11 @@ static int backup_luks_headers(struct reenc_ctx *rc)
|
||||
goto out;
|
||||
if ((r = stat(rc->header_file_tmp, &st)))
|
||||
goto out;
|
||||
/* coverity[toctou] */
|
||||
if ((r = chmod(rc->header_file_tmp, st.st_mode | S_IWUSR)))
|
||||
goto out;
|
||||
}
|
||||
log_verbose(_("%s header backup of device %s created.\n"), rc->device, isLUKS2(rc->type) ? "LUKS2" : "LUKS1");
|
||||
log_verbose(_("%s header backup of device %s created."), isLUKS2(rc->type) ? "LUKS2" : "LUKS1", rc->device);
|
||||
|
||||
/* For decrypt, new header will be fake one, so we are done here. */
|
||||
if (rc->reencrypt_mode == DECRYPT)
|
||||
@@ -699,31 +741,37 @@ static int backup_luks_headers(struct reenc_ctx *rc)
|
||||
if (opt_cipher) {
|
||||
r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
|
||||
if (r < 0) {
|
||||
log_err(_("No known cipher specification pattern detected.\n"));
|
||||
log_err(_("No known cipher specification pattern detected."));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
key_size = opt_key_size ? opt_key_size / 8 : crypt_get_volume_key_size(cd);
|
||||
|
||||
if (opt_keep_key) {
|
||||
log_dbg("Keeping key from old header.");
|
||||
old_key_size = crypt_get_volume_key_size(cd);
|
||||
old_key = crypt_safe_alloc(old_key_size);
|
||||
if (!old_key) {
|
||||
key_size = crypt_get_volume_key_size(cd);
|
||||
key = crypt_safe_alloc(key_size);
|
||||
if (!key) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, old_key, &old_key_size,
|
||||
r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, key, &key_size,
|
||||
rc->p[rc->keyslot].password, rc->p[rc->keyslot].passwordLen);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
} else if (opt_master_key_file) {
|
||||
log_dbg("Loading new key from file.");
|
||||
r = tools_read_mk(opt_master_key_file, &key, key_size);
|
||||
}
|
||||
|
||||
r = create_new_header(rc,
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = create_new_header(rc, cd,
|
||||
opt_cipher ? cipher : crypt_get_cipher(cd),
|
||||
opt_cipher ? cipher_mode : crypt_get_cipher_mode(cd),
|
||||
crypt_get_uuid(cd),
|
||||
old_key,
|
||||
opt_key_size ? opt_key_size / 8 : crypt_get_volume_key_size(cd),
|
||||
key,
|
||||
key_size,
|
||||
rc->type,
|
||||
isLUKS2(rc->type) ? (void*)¶ms2 : (void*)¶ms);
|
||||
|
||||
@@ -731,9 +779,9 @@ static int backup_luks_headers(struct reenc_ctx *rc)
|
||||
r = luks2_metadata_copy(rc);
|
||||
out:
|
||||
crypt_free(cd);
|
||||
crypt_safe_free(old_key);
|
||||
crypt_safe_free(key);
|
||||
if (r)
|
||||
log_err(_("Creation of LUKS backup headers failed.\n"));
|
||||
log_err(_("Creation of LUKS backup headers failed."));
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -767,7 +815,7 @@ static int backup_fake_header(struct reenc_ctx *rc)
|
||||
if (opt_cipher) {
|
||||
r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
|
||||
if (r < 0) {
|
||||
log_err(_("No known cipher specification pattern detected.\n"));
|
||||
log_err(_("No known cipher specification pattern detected."));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -804,7 +852,7 @@ static int backup_fake_header(struct reenc_ctx *rc)
|
||||
goto out;
|
||||
|
||||
params2.data_alignment = params.data_alignment = ROUND_SECTOR(opt_reduce_size);
|
||||
r = create_new_header(rc,
|
||||
r = create_new_header(rc, NULL,
|
||||
opt_cipher ? cipher : DEFAULT_LUKS1_CIPHER,
|
||||
opt_cipher ? cipher_mode : DEFAULT_LUKS1_MODE,
|
||||
NULL, NULL,
|
||||
@@ -834,21 +882,43 @@ static void remove_headers(struct reenc_ctx *rc)
|
||||
|
||||
static int restore_luks_header(struct reenc_ctx *rc)
|
||||
{
|
||||
struct stat st;
|
||||
struct crypt_device *cd = NULL;
|
||||
int r;
|
||||
int fd, r;
|
||||
|
||||
log_dbg("Restoring header for %s from %s.", rc->device, rc->header_file_new);
|
||||
log_dbg("Restoring header for %s from %s.", hdr_device(rc), rc->header_file_new);
|
||||
|
||||
r = crypt_init(&cd, rc->device);
|
||||
/*
|
||||
* For new encryption and new detached header in file just move it.
|
||||
* For existing file try to ensure we have prealocated space for restore.
|
||||
*/
|
||||
if (opt_new && rc->device_header) {
|
||||
r = stat(rc->device_header, &st);
|
||||
if (r == -1) {
|
||||
r = rename(rc->header_file_new, rc->device_header);
|
||||
goto out;
|
||||
} else if ((st.st_mode & S_IFMT) == S_IFREG &&
|
||||
stat(rc->header_file_new, &st) != -1) {
|
||||
/* coverity[toctou] */
|
||||
fd = open(rc->device_header, O_WRONLY);
|
||||
if (fd != -1) {
|
||||
if (posix_fallocate(fd, 0, st.st_size)) {};
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r = crypt_init(&cd, hdr_device(rc));
|
||||
if (r == 0) {
|
||||
r = crypt_header_restore(cd, rc->type, rc->header_file_new);
|
||||
}
|
||||
|
||||
crypt_free(cd);
|
||||
out:
|
||||
if (r)
|
||||
log_err(_("Cannot restore %s header on device %s.\n"), rc->device, isLUKS2(rc->type) ? "LUKS2" : "LUKS1");
|
||||
log_err(_("Cannot restore %s header on device %s."), isLUKS2(rc->type) ? "LUKS2" : "LUKS1", hdr_device(rc));
|
||||
else {
|
||||
log_verbose(_("%s header on device %s restored.\n"), rc->device, isLUKS2(rc->type) ? "LUKS2" : "LUKS1");
|
||||
log_verbose(_("%s header on device %s restored."), isLUKS2(rc->type) ? "LUKS2" : "LUKS1", hdr_device(rc));
|
||||
rc->stained = 0;
|
||||
}
|
||||
return r;
|
||||
@@ -886,7 +956,7 @@ static int copy_data_forward(struct reenc_ctx *rc, int fd_old, int fd_new,
|
||||
|
||||
if (lseek64(fd_old, rc->device_offset, SEEK_SET) < 0 ||
|
||||
lseek64(fd_new, rc->device_offset, SEEK_SET) < 0) {
|
||||
log_err(_("Cannot seek to device offset.\n"));
|
||||
log_err(_("Cannot seek to device offset."));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -966,7 +1036,7 @@ static int copy_data_backward(struct reenc_ctx *rc, int fd_old, int fd_new,
|
||||
|
||||
if (lseek64(fd_old, working_offset, SEEK_SET) < 0 ||
|
||||
lseek64(fd_new, working_offset, SEEK_SET) < 0) {
|
||||
log_err(_("Cannot seek to device offset.\n"));
|
||||
log_err(_("Cannot seek to device offset."));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -1048,23 +1118,23 @@ static int copy_data(struct reenc_ctx *rc)
|
||||
|
||||
fd_old = open(rc->crypt_path_org, O_RDONLY | (opt_directio ? O_DIRECT : 0));
|
||||
if (fd_old == -1) {
|
||||
log_err(_("Cannot open temporary LUKS device.\n"));
|
||||
log_err(_("Cannot open temporary LUKS device."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd_new = open(rc->crypt_path_new, O_WRONLY | (opt_directio ? O_DIRECT : 0));
|
||||
if (fd_new == -1) {
|
||||
log_err(_("Cannot open temporary LUKS device.\n"));
|
||||
log_err(_("Cannot open temporary LUKS device."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ioctl(fd_old, BLKGETSIZE64, &rc->device_size_org_real) < 0) {
|
||||
log_err(_("Cannot get device size.\n"));
|
||||
log_err(_("Cannot get device size."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ioctl(fd_new, BLKGETSIZE64, &rc->device_size_new_real) < 0) {
|
||||
log_err(_("Cannot get device size.\n"));
|
||||
log_err(_("Cannot get device size."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1076,7 +1146,7 @@ static int copy_data(struct reenc_ctx *rc)
|
||||
rc->device_size = rc->device_size_new_real;
|
||||
|
||||
if (posix_memalign((void *)&buf, alignment(fd_new), block_size)) {
|
||||
log_err(_("Allocation of aligned memory failed.\n"));
|
||||
log_err(_("Allocation of aligned memory failed."));
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
@@ -1101,9 +1171,9 @@ static int copy_data(struct reenc_ctx *rc)
|
||||
set_int_block(1);
|
||||
|
||||
if (r == -EAGAIN)
|
||||
log_err(_("Interrupted by a signal.\n"));
|
||||
log_err(_("Interrupted by a signal."));
|
||||
else if (r < 0)
|
||||
log_err(_("IO error during reencryption.\n"));
|
||||
log_err(_("IO error during reencryption."));
|
||||
|
||||
(void)write_log(rc);
|
||||
out:
|
||||
@@ -1134,13 +1204,13 @@ static int initialize_uuid(struct reenc_ctx *rc)
|
||||
if (!r)
|
||||
rc->device_uuid = strdup(opt_uuid);
|
||||
else
|
||||
log_err(_("Provided UUID is invalid.\n"));
|
||||
log_err(_("Provided UUID is invalid."));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Try to load LUKS from device */
|
||||
if ((r = crypt_init(&cd, rc->device)))
|
||||
if ((r = crypt_init(&cd, hdr_device(rc))))
|
||||
return r;
|
||||
crypt_set_log_callback(cd, _quiet_log, NULL);
|
||||
r = crypt_load(cd, CRYPT_LUKS, NULL);
|
||||
@@ -1148,7 +1218,7 @@ static int initialize_uuid(struct reenc_ctx *rc)
|
||||
rc->device_uuid = strdup(crypt_get_uuid(cd));
|
||||
else
|
||||
/* Reencryption already in progress - magic header? */
|
||||
r = device_check(rc, CHECK_UNUSABLE);
|
||||
r = device_check(rc, hdr_device(rc), CHECK_UNUSABLE);
|
||||
|
||||
if (!r)
|
||||
rc->type = isLUKS2(crypt_get_type(cd)) ? CRYPT_LUKS2 : CRYPT_LUKS1;
|
||||
@@ -1160,10 +1230,19 @@ static int initialize_uuid(struct reenc_ctx *rc)
|
||||
static int init_passphrase1(struct reenc_ctx *rc, struct crypt_device *cd,
|
||||
const char *msg, int slot_to_check, int check, int verify)
|
||||
{
|
||||
crypt_keyslot_info ki;
|
||||
char *password;
|
||||
int r = -EINVAL, retry_count;
|
||||
size_t passwordLen;
|
||||
|
||||
/* mode ENCRYPT call this without header */
|
||||
if (cd && slot_to_check != CRYPT_ANY_SLOT) {
|
||||
ki = crypt_keyslot_status(cd, slot_to_check);
|
||||
if (ki < CRYPT_SLOT_ACTIVE)
|
||||
return -ENOENT;
|
||||
} else
|
||||
ki = CRYPT_SLOT_ACTIVE;
|
||||
|
||||
retry_count = opt_tries ?: 1;
|
||||
while (retry_count--) {
|
||||
r = tools_get_key(msg, &password, &passwordLen, 0, 0,
|
||||
@@ -1179,7 +1258,7 @@ static int init_passphrase1(struct reenc_ctx *rc, struct crypt_device *cd,
|
||||
|
||||
if (check)
|
||||
r = crypt_activate_by_passphrase(cd, NULL, slot_to_check,
|
||||
password, passwordLen, 0);
|
||||
password, passwordLen, CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY);
|
||||
else
|
||||
r = (slot_to_check == CRYPT_ANY_SLOT) ? 0 : slot_to_check;
|
||||
|
||||
@@ -1190,13 +1269,16 @@ static int init_passphrase1(struct reenc_ctx *rc, struct crypt_device *cd,
|
||||
}
|
||||
if (r < 0 && r != -EPERM)
|
||||
return r;
|
||||
|
||||
if (r >= 0) {
|
||||
rc->keyslot = r;
|
||||
tools_keyslot_msg(r, UNLOCKED);
|
||||
rc->p[r].password = password;
|
||||
rc->p[r].passwordLen = passwordLen;
|
||||
if (ki != CRYPT_SLOT_UNBOUND)
|
||||
rc->keyslot = r;
|
||||
break;
|
||||
}
|
||||
log_err(_("No key available with this passphrase.\n"));
|
||||
tools_passphrase_msg(r);
|
||||
}
|
||||
|
||||
password = NULL;
|
||||
@@ -1226,14 +1308,13 @@ static int init_keyfile(struct reenc_ctx *rc, struct crypt_device *cd, int slot_
|
||||
if (r >= 0 && opt_key_slot == CRYPT_ANY_SLOT &&
|
||||
crypt_keyslot_status(cd, r) != CRYPT_SLOT_ACTIVE_LAST) {
|
||||
log_err(_("Key file can be used only with --key-slot or with "
|
||||
"exactly one key slot active.\n"));
|
||||
"exactly one key slot active."));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
crypt_safe_free(password);
|
||||
if (r == -EPERM)
|
||||
log_err(_("No key available with this passphrase.\n"));
|
||||
tools_passphrase_msg(r);
|
||||
} else {
|
||||
rc->keyslot = r;
|
||||
rc->p[r].password = password;
|
||||
@@ -1249,11 +1330,10 @@ static int init_keyfile(struct reenc_ctx *rc, struct crypt_device *cd, int slot_
|
||||
static int initialize_passphrase(struct reenc_ctx *rc, const char *device)
|
||||
{
|
||||
struct crypt_device *cd = NULL;
|
||||
crypt_keyslot_info ki;
|
||||
char msg[256];
|
||||
int i, r;
|
||||
|
||||
log_dbg("Passhrases initialization.");
|
||||
log_dbg("Passphrases initialization.");
|
||||
|
||||
if (rc->reencrypt_mode == ENCRYPT && !rc->in_progress) {
|
||||
r = init_passphrase1(rc, cd, _("Enter new passphrase: "), opt_key_slot, 0, 1);
|
||||
@@ -1280,12 +1360,12 @@ static int initialize_passphrase(struct reenc_ctx *rc, const char *device)
|
||||
rc->reencrypt_mode == DECRYPT) {
|
||||
r = init_passphrase1(rc, cd, msg, opt_key_slot, 1, 0);
|
||||
} else for (i = 0; i < crypt_keyslot_max(crypt_get_type(cd)); i++) {
|
||||
ki = crypt_keyslot_status(cd, i);
|
||||
if (ki != CRYPT_SLOT_ACTIVE && ki != CRYPT_SLOT_ACTIVE_LAST)
|
||||
continue;
|
||||
|
||||
snprintf(msg, sizeof(msg), _("Enter passphrase for key slot %u: "), i);
|
||||
r = init_passphrase1(rc, cd, msg, i, 1, 0);
|
||||
if (r == -ENOENT) {
|
||||
r = 0;
|
||||
continue;
|
||||
}
|
||||
if (r < 0)
|
||||
break;
|
||||
}
|
||||
@@ -1309,17 +1389,20 @@ static int initialize_context(struct reenc_ctx *rc, const char *device)
|
||||
if (!(rc->device = strndup(device, PATH_MAX)))
|
||||
return -ENOMEM;
|
||||
|
||||
if (device_check(rc, CHECK_OPEN) < 0)
|
||||
if (opt_header_device && !(rc->device_header = strndup(opt_header_device, PATH_MAX)))
|
||||
return -ENOMEM;
|
||||
|
||||
if (device_check(rc, rc->device, CHECK_OPEN) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (initialize_uuid(rc)) {
|
||||
log_err(_("Device %s is not a valid LUKS device.\n"), device);
|
||||
log_err(_("Device %s is not a valid LUKS device."), device);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (opt_key_slot != CRYPT_ANY_SLOT &&
|
||||
opt_key_slot >= crypt_keyslot_max(rc->type)) {
|
||||
log_err(_("Key slot is invalid.\n"));
|
||||
log_err(_("Key slot is invalid."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1348,14 +1431,14 @@ static int initialize_context(struct reenc_ctx *rc, const char *device)
|
||||
remove_headers(rc);
|
||||
|
||||
if (open_log(rc) < 0) {
|
||||
log_err(_("Cannot open reencryption log file.\n"));
|
||||
log_err(_("Cannot open reencryption log file."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!rc->in_progress) {
|
||||
if (opt_uuid) {
|
||||
log_err(_("No decryption in progress, provided UUID can "
|
||||
"be used only to resume suspended decryption process.\n"));
|
||||
"be used only to resume suspended decryption process."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1397,20 +1480,23 @@ static void destroy_context(struct reenc_ctx *rc)
|
||||
crypt_safe_free(rc->p[i].password);
|
||||
|
||||
free(rc->device);
|
||||
free(rc->device_header);
|
||||
free(rc->device_uuid);
|
||||
}
|
||||
|
||||
static int luks2_change_pbkdf_params(struct reenc_ctx *rc)
|
||||
{
|
||||
int i, r;
|
||||
struct crypt_device *cd;
|
||||
struct crypt_device *cd = NULL;
|
||||
|
||||
if ((r = initialize_passphrase(rc, rc->device)))
|
||||
if ((r = initialize_passphrase(rc, hdr_device(rc))))
|
||||
return r;
|
||||
|
||||
if (crypt_init(&cd, rc->device) ||
|
||||
crypt_load(cd, CRYPT_LUKS2, NULL))
|
||||
return -EINVAL;
|
||||
if (crypt_init(&cd, hdr_device(rc)) ||
|
||||
crypt_load(cd, CRYPT_LUKS2, NULL)) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((r = set_pbkdf_params(cd, CRYPT_LUKS2)))
|
||||
goto out;
|
||||
@@ -1426,7 +1512,7 @@ static int luks2_change_pbkdf_params(struct reenc_ctx *rc)
|
||||
rc->p[i].password, rc->p[i].passwordLen,
|
||||
rc->p[i].password, rc->p[i].passwordLen)) < 0)
|
||||
goto out;
|
||||
log_verbose(_("Changed pbkdf parameters in keyslot %i.\n"), r);
|
||||
log_verbose(_("Changed pbkdf parameters in keyslot %i."), r);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
@@ -1461,11 +1547,12 @@ static int run_reencrypt(const char *device)
|
||||
log_dbg("Running reencryption.");
|
||||
|
||||
if (!rc.in_progress) {
|
||||
if ((r = initialize_passphrase(&rc, rc.device)))
|
||||
if ((r = initialize_passphrase(&rc, hdr_device(&rc))))
|
||||
goto out;
|
||||
|
||||
log_dbg("Storing backup of LUKS headers.");
|
||||
if (rc.reencrypt_mode == ENCRYPT) {
|
||||
/* Create fake header for exising device */
|
||||
/* Create fake header for existing device */
|
||||
if ((r = backup_fake_header(&rc)))
|
||||
goto out;
|
||||
} else {
|
||||
@@ -1475,7 +1562,7 @@ static int run_reencrypt(const char *device)
|
||||
if (rc.reencrypt_mode == DECRYPT &&
|
||||
(r = backup_fake_header(&rc)))
|
||||
goto out;
|
||||
if ((r = device_check(&rc, MAKE_UNUSABLE)))
|
||||
if ((r = device_check(&rc, hdr_device(&rc), MAKE_UNUSABLE)))
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
@@ -1534,30 +1621,32 @@ int main(int argc, const char **argv)
|
||||
{ "cipher", 'c', POPT_ARG_STRING, &opt_cipher, 0, N_("The cipher used to encrypt the disk (see /proc/crypto)"), NULL },
|
||||
{ "key-size", 's', POPT_ARG_INT, &opt_key_size, 0, N_("The size of the encryption key"), N_("BITS") },
|
||||
{ "hash", 'h', POPT_ARG_STRING, &opt_hash, 0, N_("The hash used to create the encryption key from the passphrase"), NULL },
|
||||
{ "keep-key", '\0', POPT_ARG_NONE, &opt_keep_key, 0, N_("Do not change key, no data area reencryption."), NULL },
|
||||
{ "key-file", 'd', POPT_ARG_STRING, &opt_key_file, 0, N_("Read the key from a file."), NULL },
|
||||
{ "keep-key", '\0', POPT_ARG_NONE, &opt_keep_key, 0, N_("Do not change key, no data area reencryption"), NULL },
|
||||
{ "key-file", 'd', POPT_ARG_STRING, &opt_key_file, 0, N_("Read the key from a file"), NULL },
|
||||
{ "master-key-file", '\0', POPT_ARG_STRING, &opt_master_key_file, 0, N_("Read new volume (master) key from file"), NULL },
|
||||
{ "iter-time", 'i', POPT_ARG_INT, &opt_iteration_time, 0, N_("PBKDF2 iteration time for LUKS (in ms)"), N_("msecs") },
|
||||
{ "batch-mode", 'q', POPT_ARG_NONE, &opt_batch_mode, 0, N_("Do not ask for confirmation"), NULL },
|
||||
{ "progress-frequency",'\0', POPT_ARG_INT, &opt_progress_frequency, 0, N_("Progress line update (in seconds)"), N_("secs") },
|
||||
{ "tries", 'T', POPT_ARG_INT, &opt_tries, 0, N_("How often the input of the passphrase can be retried"), NULL },
|
||||
{ "use-random", '\0', POPT_ARG_NONE, &opt_random, 0, N_("Use /dev/random for generating volume key."), NULL },
|
||||
{ "use-urandom", '\0', POPT_ARG_NONE, &opt_urandom, 0, N_("Use /dev/urandom for generating volume key."), NULL },
|
||||
{ "use-directio", '\0', POPT_ARG_NONE, &opt_directio, 0, N_("Use direct-io when accessing devices."), NULL },
|
||||
{ "use-fsync", '\0', POPT_ARG_NONE, &opt_fsync, 0, N_("Use fsync after each block."), NULL },
|
||||
{ "write-log", '\0', POPT_ARG_NONE, &opt_write_log, 0, N_("Update log file after every block."), NULL },
|
||||
{ "key-slot", 'S', POPT_ARG_INT, &opt_key_slot, 0, N_("Use only this slot (others will be disabled)."), NULL },
|
||||
{ "use-random", '\0', POPT_ARG_NONE, &opt_random, 0, N_("Use /dev/random for generating volume key"), NULL },
|
||||
{ "use-urandom", '\0', POPT_ARG_NONE, &opt_urandom, 0, N_("Use /dev/urandom for generating volume key"), NULL },
|
||||
{ "use-directio", '\0', POPT_ARG_NONE, &opt_directio, 0, N_("Use direct-io when accessing devices"), NULL },
|
||||
{ "use-fsync", '\0', POPT_ARG_NONE, &opt_fsync, 0, N_("Use fsync after each block"), NULL },
|
||||
{ "write-log", '\0', POPT_ARG_NONE, &opt_write_log, 0, N_("Update log file after every block"), NULL },
|
||||
{ "key-slot", 'S', POPT_ARG_INT, &opt_key_slot, 0, N_("Use only this slot (others will be disabled)"), NULL },
|
||||
{ "keyfile-offset", '\0', POPT_ARG_LONG, &opt_keyfile_offset, 0, N_("Number of bytes to skip in keyfile"), N_("bytes") },
|
||||
{ "keyfile-size", 'l', POPT_ARG_LONG, &opt_keyfile_size, 0, N_("Limits the read from keyfile"), N_("bytes") },
|
||||
{ "reduce-device-size",'\0', POPT_ARG_STRING, &opt_reduce_size_str, 0, N_("Reduce data device size (move data offset). DANGEROUS!"), N_("bytes") },
|
||||
{ "device-size", '\0', POPT_ARG_STRING, &opt_device_size_str, 0, N_("Use only specified device size (ignore rest of device). DANGEROUS!"), N_("bytes") },
|
||||
{ "new", 'N', POPT_ARG_NONE, &opt_new, 0, N_("Create new header on not encrypted device."), NULL },
|
||||
{ "decrypt", '\0', POPT_ARG_NONE, &opt_decrypt, 0, N_("Permanently decrypt device (remove encryption)."), NULL },
|
||||
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("The uuid used to resume decryption."), NULL },
|
||||
{ "type", '\0', POPT_ARG_STRING, &opt_type, 0, N_("Type of LUKS metadata (luks1 or luks2)."), NULL },
|
||||
{ "pbkdf", '\0', POPT_ARG_STRING, &opt_pbkdf, 0, N_("PBKDF algorithm (for LUKS2) (argon2i/argon2id/pbkdf2)."), NULL },
|
||||
{ "new", 'N', POPT_ARG_NONE, &opt_new, 0, N_("Create new header on not encrypted device"), NULL },
|
||||
{ "decrypt", '\0', POPT_ARG_NONE, &opt_decrypt, 0, N_("Permanently decrypt device (remove encryption)"), NULL },
|
||||
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("The UUID used to resume decryption"), NULL },
|
||||
{ "type", '\0', POPT_ARG_STRING, &opt_type, 0, N_("Type of LUKS metadata: luks1, luks2"), NULL },
|
||||
{ "pbkdf", '\0', POPT_ARG_STRING, &opt_pbkdf, 0, N_("PBKDF algorithm (for LUKS2): argon2i, argon2id, pbkdf2"), NULL },
|
||||
{ "pbkdf-memory", '\0', POPT_ARG_LONG, &opt_pbkdf_memory, 0, N_("PBKDF memory cost limit"), N_("kilobytes") },
|
||||
{ "pbkdf-parallel", '\0', POPT_ARG_LONG, &opt_pbkdf_parallel, 0, N_("PBKDF parallel cost "), N_("threads") },
|
||||
{ "pbkdf-parallel", '\0', POPT_ARG_LONG, &opt_pbkdf_parallel, 0, N_("PBKDF parallel cost"), N_("threads") },
|
||||
{ "pbkdf-force-iterations",'\0',POPT_ARG_LONG, &opt_pbkdf_iterations, 0, N_("PBKDF iterations cost (forced, disables benchmark)"), NULL },
|
||||
{ "header", '\0', POPT_ARG_STRING, &opt_header_device, 0, N_("Device or file with separated LUKS header"), NULL },
|
||||
POPT_TABLEEND
|
||||
};
|
||||
poptContext popt_context;
|
||||
@@ -1587,7 +1676,7 @@ int main(int argc, const char **argv)
|
||||
}
|
||||
|
||||
if (!opt_batch_mode)
|
||||
log_verbose(_("Reencryption will change: %s%s%s%s%s%s.\n"),
|
||||
log_verbose(_("Reencryption will change: %s%s%s%s%s%s."),
|
||||
opt_keep_key ? "" : _("volume key"),
|
||||
(!opt_keep_key && opt_hash) ? ", " : "",
|
||||
opt_hash ? _("set hash to ") : "", opt_hash ?: "",
|
||||
@@ -1656,11 +1745,11 @@ int main(int argc, const char **argv)
|
||||
usage(popt_context, EXIT_FAILURE, _("Reduce size must be multiple of 512 bytes sector."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_new && !opt_reduce_size)
|
||||
usage(popt_context, EXIT_FAILURE, _("Option --new must be used together with --reduce-device-size."),
|
||||
if (opt_new && (!opt_reduce_size && !opt_header_device))
|
||||
usage(popt_context, EXIT_FAILURE, _("Option --new must be used together with --reduce-device-size or --header."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_keep_key && ((!opt_hash && !opt_iteration_time && !opt_pbkdf_iterations) || opt_cipher || opt_new))
|
||||
if (opt_keep_key && (opt_cipher || opt_new || opt_master_key_file))
|
||||
usage(popt_context, EXIT_FAILURE, _("Option --keep-key can be used only with --hash, --iter-time or --pbkdf-force-iterations."),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ static int _read_mk(const char *file, char **key, int keysize)
|
||||
int fd;
|
||||
|
||||
if (keysize <= 0 || keysize > MAX_KEY_SIZE) {
|
||||
log_err(_("Invalid key size.\n"));
|
||||
log_err(_("Invalid key size."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -75,11 +75,11 @@ static int _read_mk(const char *file, char **key, int keysize)
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
log_err(_("Cannot read keyfile %s.\n"), file);
|
||||
log_err(_("Cannot read keyfile %s."), file);
|
||||
goto fail;
|
||||
}
|
||||
if ((read(fd, *key, keysize) != keysize)) {
|
||||
log_err(_("Cannot read %d bytes from keyfile %s.\n"), keysize, file);
|
||||
log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
|
||||
close(fd);
|
||||
goto fail;
|
||||
}
|
||||
@@ -159,7 +159,7 @@ static int _wipe_data_device(struct crypt_device *cd, const char *integrity_key)
|
||||
r = crypt_wipe(cd, tmp_path, CRYPT_WIPE_ZERO, 0, 0, DEFAULT_WIPE_BLOCK,
|
||||
0, &tools_wipe_progress, NULL);
|
||||
if (crypt_deactivate(cd, tmp_name))
|
||||
log_err(_("Cannot deactivate temporary device %s.\n"), tmp_path);
|
||||
log_err(_("Cannot deactivate temporary device %s."), tmp_path);
|
||||
set_int_block(0);
|
||||
|
||||
return r;
|
||||
@@ -178,13 +178,14 @@ static int action_format(int arg)
|
||||
.sector_size = opt_sector_size ?: SECTOR_SIZE,
|
||||
};
|
||||
char integrity[MAX_CIPHER_LEN], journal_integrity[MAX_CIPHER_LEN], journal_crypt[MAX_CIPHER_LEN];
|
||||
char *integrity_key = NULL;
|
||||
char *integrity_key = NULL, *msg = NULL;
|
||||
int r;
|
||||
size_t signatures;
|
||||
|
||||
if (opt_integrity) {
|
||||
r = crypt_parse_hash_integrity_mode(opt_integrity, integrity);
|
||||
if (r < 0) {
|
||||
log_err(_("No known integrity specification pattern detected.\n"));
|
||||
log_err(_("No known integrity specification pattern detected."));
|
||||
return r;
|
||||
}
|
||||
params.integrity = integrity;
|
||||
@@ -193,7 +194,7 @@ static int action_format(int arg)
|
||||
if (opt_journal_integrity) {
|
||||
r = crypt_parse_hash_integrity_mode(opt_journal_integrity, journal_integrity);
|
||||
if (r < 0) {
|
||||
log_err(_("No known integrity specification pattern detected.\n"));
|
||||
log_err(_("No known integrity specification pattern detected."));
|
||||
return r;
|
||||
}
|
||||
params.journal_integrity = journal_integrity;
|
||||
@@ -202,7 +203,7 @@ static int action_format(int arg)
|
||||
if (opt_journal_crypt) {
|
||||
r = crypt_parse_hash_integrity_mode(opt_journal_crypt, journal_crypt);
|
||||
if (r < 0) {
|
||||
log_err(_("No known integrity specification pattern detected.\n"));
|
||||
log_err(_("No known integrity specification pattern detected."));
|
||||
return r;
|
||||
}
|
||||
params.journal_crypt = journal_crypt;
|
||||
@@ -216,10 +217,29 @@ static int action_format(int arg)
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = crypt_format(cd, CRYPT_INTEGRITY, NULL, NULL, NULL, NULL, 0, ¶ms);
|
||||
r = asprintf(&msg, _("This will overwrite data on %s irrevocably."), action_argv[0]);
|
||||
if (r == -1) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = yesDialog(msg, _("Operation aborted.\n")) ? 0 : -EINVAL;
|
||||
free(msg);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = tools_detect_signatures(action_argv[0], 0, &signatures);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
/* Signature candidates found */
|
||||
if (signatures && ((r = tools_wipe_all_signatures(action_argv[0])) < 0))
|
||||
goto out;
|
||||
|
||||
r = crypt_format(cd, CRYPT_INTEGRITY, NULL, NULL, NULL, NULL, 0, ¶ms);
|
||||
if (r < 0) /* FIXME: call wipe signatures again */
|
||||
goto out;
|
||||
|
||||
if (!opt_batch_mode)
|
||||
log_std(_("Formatted with tag size %u, internal integrity %s.\n"), opt_tag_size, opt_integrity);
|
||||
|
||||
@@ -249,7 +269,7 @@ static int action_open(int arg)
|
||||
if (opt_integrity) {
|
||||
r = crypt_parse_hash_integrity_mode(opt_integrity, integrity);
|
||||
if (r < 0) {
|
||||
log_err(_("No known integrity specification pattern detected.\n"));
|
||||
log_err(_("No known integrity specification pattern detected."));
|
||||
return r;
|
||||
}
|
||||
params.integrity = integrity;
|
||||
@@ -258,7 +278,7 @@ static int action_open(int arg)
|
||||
if (opt_journal_integrity) {
|
||||
r = crypt_parse_hash_integrity_mode(opt_journal_integrity, journal_integrity);
|
||||
if (r < 0) {
|
||||
log_err(_("No known integrity specification pattern detected.\n"));
|
||||
log_err(_("No known integrity specification pattern detected."));
|
||||
return r;
|
||||
|
||||
}
|
||||
@@ -268,7 +288,7 @@ static int action_open(int arg)
|
||||
if (opt_journal_crypt) {
|
||||
r = crypt_parse_hash_integrity_mode(opt_journal_crypt, journal_crypt);
|
||||
if (r < 0) {
|
||||
log_err(_("No known integrity specification pattern detected.\n"));
|
||||
log_err(_("No known integrity specification pattern detected."));
|
||||
return r;
|
||||
}
|
||||
params.journal_crypt = journal_crypt;
|
||||
@@ -376,6 +396,8 @@ static int action_status(int arg)
|
||||
log_std(" mode: %s%s\n",
|
||||
cad.flags & CRYPT_ACTIVATE_READONLY ? "readonly" : "read/write",
|
||||
cad.flags & CRYPT_ACTIVATE_RECOVERY ? " recovery" : "");
|
||||
log_std(" failures: %" PRIu64 "\n",
|
||||
crypt_get_active_integrity_failures(cd, action_argv[0]));
|
||||
if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL) {
|
||||
log_std(" journal: not active\n");
|
||||
} else {
|
||||
@@ -490,24 +512,24 @@ int main(int argc, const char **argv)
|
||||
{ "interleave-sectors", '\0', POPT_ARG_INT, &opt_interleave_sectors, 0, N_("Interleave sectors"), N_("SECTORS") },
|
||||
{ "journal-watermark", '\0', POPT_ARG_INT, &opt_journal_watermark, 0, N_("Journal watermark"),N_("percent") },
|
||||
{ "journal-commit-time",'\0', POPT_ARG_INT, &opt_journal_commit_time,0, N_("Journal commit time"), N_("ms") },
|
||||
{ "tag-size", 't', POPT_ARG_INT, &opt_tag_size, 0, N_("Tag size per-sector"), N_("bytes") },
|
||||
{ "tag-size", 't', POPT_ARG_INT, &opt_tag_size, 0, N_("Tag size (per-sector)"), N_("bytes") },
|
||||
{ "sector-size", 's', POPT_ARG_INT, &opt_sector_size, 0, N_("Sector size"), N_("bytes") },
|
||||
{ "buffer-sectors", '\0', POPT_ARG_INT, &opt_buffer_sectors, 0, N_("Buffers size"), N_("SECTORS") },
|
||||
|
||||
{ "integrity", 'I', POPT_ARG_STRING, &opt_integrity, 0, N_("Data integrity algorithm (default "DEFAULT_ALG_NAME ")"), NULL },
|
||||
{ "integrity", 'I', POPT_ARG_STRING, &opt_integrity, 0, N_("Data integrity algorithm"), NULL },
|
||||
{ "integrity-key-size", '\0', POPT_ARG_INT, &opt_integrity_key_size, 0, N_("The size of the data integrity key"), N_("BITS") },
|
||||
{ "integrity-key-file", '\0', POPT_ARG_STRING, &opt_integrity_key_file, 0, N_("Read the integrity key from a file."), NULL },
|
||||
{ "integrity-key-file", '\0', POPT_ARG_STRING, &opt_integrity_key_file, 0, N_("Read the integrity key from a file"), NULL },
|
||||
|
||||
{ "journal-integrity", '\0', POPT_ARG_STRING, &opt_journal_integrity, 0, N_("Journal integrity algorithm"), NULL },
|
||||
{ "journal-integrity-key-size",'\0', POPT_ARG_INT, &opt_journal_integrity_key_size,0, N_("The size of the journal integrity key"), N_("BITS") },
|
||||
{ "journal-integrity-key-file",'\0', POPT_ARG_STRING, &opt_journal_integrity_key_file,0, N_("Read the journal integrity key from a file."), NULL },
|
||||
{ "journal-integrity-key-file",'\0', POPT_ARG_STRING, &opt_journal_integrity_key_file,0, N_("Read the journal integrity key from a file"), NULL },
|
||||
|
||||
{ "journal-crypt", '\0', POPT_ARG_STRING, &opt_journal_crypt, 0, N_("Journal encryption algorithm"), NULL },
|
||||
{ "journal-crypt-key-size", '\0', POPT_ARG_INT, &opt_journal_crypt_key_size, 0, N_("The size of the journal encryption key"), N_("BITS") },
|
||||
{ "journal-crypt-key-file", '\0', POPT_ARG_STRING, &opt_journal_crypt_key_file, 0, N_("Read the journal encryption key from a file."), NULL },
|
||||
{ "journal-crypt-key-file", '\0', POPT_ARG_STRING, &opt_journal_crypt_key_file, 0, N_("Read the journal encryption key from a file"), NULL },
|
||||
|
||||
{ "integrity-no-journal", 'D', POPT_ARG_NONE, &opt_integrity_nojournal, 0, N_("Disable journal for integrity device."), NULL },
|
||||
{ "integrity-recovery-mode", 'R', POPT_ARG_NONE, &opt_integrity_recovery, 0, N_("Recovery mode (no journal, no tag checking)."), NULL },
|
||||
{ "integrity-no-journal", 'D', POPT_ARG_NONE, &opt_integrity_nojournal, 0, N_("Disable journal for integrity device"), NULL },
|
||||
{ "integrity-recovery-mode", 'R', POPT_ARG_NONE, &opt_integrity_recovery, 0, N_("Recovery mode (no journal, no tag checking)"), NULL },
|
||||
POPT_TABLEEND
|
||||
};
|
||||
poptContext popt_context;
|
||||
@@ -554,7 +576,7 @@ int main(int argc, const char **argv)
|
||||
action_argc++;
|
||||
|
||||
/* Handle aliases */
|
||||
if (!strcmp(aname, "create")) {
|
||||
if (!strcmp(aname, "create") && action_argc > 1) {
|
||||
/* create command had historically switched arguments */
|
||||
if (action_argv[0] && action_argv[1]) {
|
||||
const char *tmp = action_argv[0];
|
||||
|
||||
139
src/utils_luks2.c
Normal file
139
src/utils_luks2.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Helper utilities for LUKS2 features
|
||||
*
|
||||
* Copyright (C) 2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2018, Milan Broz
|
||||
* Copyright (C) 2018, 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 "cryptsetup.h"
|
||||
|
||||
/*
|
||||
* FIXME: 4MiBs is max LUKS2 mda length (including binary header).
|
||||
* In future, read max allowed JSON size from config section.
|
||||
*/
|
||||
#define LUKS2_MAX_MDA_SIZE 0x400000
|
||||
int tools_read_json_file(struct crypt_device *cd, const char *file, char **json, size_t *json_size)
|
||||
{
|
||||
ssize_t ret;
|
||||
int fd, block, r;
|
||||
void *buf = NULL;
|
||||
|
||||
block = tools_signals_blocked();
|
||||
if (block)
|
||||
set_int_block(0);
|
||||
|
||||
if (tools_is_stdin(file)) {
|
||||
fd = STDIN_FILENO;
|
||||
log_dbg("STDIN descriptor JSON read requested.");
|
||||
} else {
|
||||
log_dbg("File descriptor JSON read requested.");
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
log_err(_("Failed to open file %s in read-only mode."), file);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
buf = malloc(LUKS2_MAX_MDA_SIZE);
|
||||
if (!buf) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (isatty(fd) && !opt_batch_mode)
|
||||
log_std(_("Provide valid LUKS2 token JSON:\n"));
|
||||
|
||||
/* we expect JSON (string) */
|
||||
r = 0;
|
||||
ret = read_buffer_intr(fd, buf, LUKS2_MAX_MDA_SIZE - 1, &quit);
|
||||
if (ret < 0) {
|
||||
r = -EIO;
|
||||
log_err(_("Failed to read JSON file."));
|
||||
goto out;
|
||||
}
|
||||
check_signal(&r);
|
||||
if (r) {
|
||||
log_err(_("\nRead interrupted."));
|
||||
goto out;
|
||||
}
|
||||
|
||||
*json_size = (size_t)ret;
|
||||
*json = buf;
|
||||
*(*json + ret) = '\0';
|
||||
out:
|
||||
if (block && !quit)
|
||||
set_int_block(1);
|
||||
if (fd >= 0 && fd != STDIN_FILENO)
|
||||
close(fd);
|
||||
if (r && buf) {
|
||||
memset(buf, 0, LUKS2_MAX_MDA_SIZE);
|
||||
free(buf);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int tools_write_json_file(struct crypt_device *cd, const char *file, const char *json)
|
||||
{
|
||||
int block, fd, r;
|
||||
size_t json_len;
|
||||
ssize_t ret;
|
||||
|
||||
if (!json || !(json_len = strlen(json)) || json_len >= LUKS2_MAX_MDA_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
block = tools_signals_blocked();
|
||||
if (block)
|
||||
set_int_block(0);
|
||||
|
||||
if (tools_is_stdin(file)) {
|
||||
fd = STDOUT_FILENO;
|
||||
log_dbg("STDOUT descriptor JSON write requested.");
|
||||
} else {
|
||||
log_dbg("File descriptor JSON write requested.");
|
||||
fd = open(file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
log_err(_("Failed to open file %s in write mode."), file ?: "");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
ret = write_buffer_intr(fd, json, json_len, &quit);
|
||||
check_signal(&r);
|
||||
if (r) {
|
||||
log_err(_("\nWrite interrupted."));
|
||||
goto out;
|
||||
}
|
||||
if (ret < 0 || (size_t)ret != json_len) {
|
||||
log_err(_("Failed to write JSON file."));
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (isatty(fd))
|
||||
(void) write_buffer_intr(fd, "\n", 1, &quit);
|
||||
out:
|
||||
if (block && !quit)
|
||||
set_int_block(1);
|
||||
if (fd >=0 && fd != STDOUT_FILENO)
|
||||
close(fd);
|
||||
return r;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ static int tools_check_pwquality(const char *password)
|
||||
|
||||
r = pwquality_read_config(pwq, NULL, &auxerror);
|
||||
if (r) {
|
||||
log_err(_("Cannot check password quality: %s\n"),
|
||||
log_err(_("Cannot check password quality: %s"),
|
||||
pwquality_strerror(NULL, 0, r, auxerror));
|
||||
pwquality_free_settings(pwq);
|
||||
return -EINVAL;
|
||||
@@ -48,7 +48,7 @@ static int tools_check_pwquality(const char *password)
|
||||
|
||||
r = pwquality_check(pwq, password, NULL, NULL, &auxerror);
|
||||
if (r < 0) {
|
||||
log_err(_("Password quality check failed:\n %s\n"),
|
||||
log_err(_("Password quality check failed:\n %s"),
|
||||
pwquality_strerror(NULL, 0, r, auxerror));
|
||||
r = -EPERM;
|
||||
} else {
|
||||
@@ -72,7 +72,7 @@ static int tools_check_pwquality(const char *password)
|
||||
passwdqc_params_reset(¶ms);
|
||||
|
||||
if (*config && passwdqc_params_load(¶ms, &parse_reason, config)) {
|
||||
log_err(_("Cannot check password quality: %s\n"),
|
||||
log_err(_("Cannot check password quality: %s"),
|
||||
(parse_reason ? parse_reason : "Out of memory"));
|
||||
free(parse_reason);
|
||||
return -EINVAL;
|
||||
@@ -80,7 +80,7 @@ static int tools_check_pwquality(const char *password)
|
||||
|
||||
check_reason = passwdqc_check(¶ms.qc, password, NULL, NULL);
|
||||
if (check_reason) {
|
||||
log_err(_("Password quality check failed: Bad passphrase (%s)\n"),
|
||||
log_err(_("Password quality check failed: Bad passphrase (%s)"),
|
||||
check_reason);
|
||||
return -EPERM;
|
||||
}
|
||||
@@ -94,25 +94,6 @@ static int tools_check_pwquality(const char *password)
|
||||
}
|
||||
#endif /* ENABLE_PWQUALITY || ENABLE_PASSWDQC */
|
||||
|
||||
int tools_is_cipher_null(const char *cipher)
|
||||
{
|
||||
if (!cipher)
|
||||
return 0;
|
||||
|
||||
return !strcmp(cipher, "cipher_null") ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Keyfile - is standard input treated as a binary file (no EOL handling).
|
||||
*/
|
||||
int tools_is_stdin(const char *key_file)
|
||||
{
|
||||
if (!key_file)
|
||||
return 1;
|
||||
|
||||
return strcmp(key_file, "-") ? 0 : 1;
|
||||
}
|
||||
|
||||
/* Password reading helpers */
|
||||
static int untimed_read(int fd, char *pass, size_t maxlen)
|
||||
{
|
||||
@@ -204,12 +185,12 @@ static int crypt_get_key_tty(const char *prompt,
|
||||
|
||||
pass = crypt_safe_alloc(key_size_max + 1);
|
||||
if (!pass) {
|
||||
log_err( _("Out of memory while reading passphrase.\n"));
|
||||
log_err( _("Out of memory while reading passphrase."));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (interactive_pass(prompt, pass, key_size_max, timeout)) {
|
||||
log_err(_("Error reading passphrase from terminal.\n"));
|
||||
log_err(_("Error reading passphrase from terminal."));
|
||||
goto out_err;
|
||||
}
|
||||
pass[key_size_max] = '\0';
|
||||
@@ -217,19 +198,19 @@ static int crypt_get_key_tty(const char *prompt,
|
||||
if (verify) {
|
||||
pass_verify = crypt_safe_alloc(key_size_max);
|
||||
if (!pass_verify) {
|
||||
log_err(_("Out of memory while reading passphrase.\n"));
|
||||
log_err(_("Out of memory while reading passphrase."));
|
||||
r = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (interactive_pass(_("Verify passphrase: "),
|
||||
pass_verify, key_size_max, timeout)) {
|
||||
log_err(_("Error reading passphrase from terminal.\n"));
|
||||
log_err(_("Error reading passphrase from terminal."));
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (strncmp(pass, pass_verify, key_size_max)) {
|
||||
log_err(_("Passphrases do not match.\n"));
|
||||
log_err(_("Passphrases do not match."));
|
||||
r = -EPERM;
|
||||
goto out_err;
|
||||
}
|
||||
@@ -266,7 +247,7 @@ int tools_get_key(const char *prompt,
|
||||
if (tools_is_stdin(key_file)) {
|
||||
if (isatty(STDIN_FILENO)) {
|
||||
if (keyfile_offset) {
|
||||
log_err(_("Cannot use offset with terminal input.\n"));
|
||||
log_err(_("Cannot use offset with terminal input."));
|
||||
} else {
|
||||
if (!prompt && !crypt_get_device_name(cd))
|
||||
snprintf(tmp, sizeof(tmp), _("Enter passphrase: "));
|
||||
@@ -297,3 +278,54 @@ int tools_get_key(const char *prompt,
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void tools_passphrase_msg(int r)
|
||||
{
|
||||
if (r == -EPERM)
|
||||
log_err(_("No key available with this passphrase."));
|
||||
}
|
||||
|
||||
int tools_read_mk(const char *file, char **key, int keysize)
|
||||
{
|
||||
int fd;
|
||||
|
||||
*key = crypt_safe_alloc(keysize);
|
||||
if (!*key)
|
||||
return -ENOMEM;
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
log_err(_("Cannot read keyfile %s."), file);
|
||||
goto fail;
|
||||
}
|
||||
if ((read(fd, *key, keysize) != keysize)) {
|
||||
log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
|
||||
close(fd);
|
||||
goto fail;
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
fail:
|
||||
crypt_safe_free(*key);
|
||||
*key = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int tools_write_mk(const char *file, const char *key, int keysize)
|
||||
{
|
||||
int fd, r = -EINVAL;
|
||||
|
||||
fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
|
||||
if (fd < 0) {
|
||||
log_err(_("Cannot open keyfile %s for write."), file);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (write_buffer(fd, key, keysize) == keysize)
|
||||
r = 0;
|
||||
else
|
||||
log_err(_("Cannot write to keyfile %s."), file);
|
||||
|
||||
close(fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -76,17 +76,23 @@ void check_signal(int *r)
|
||||
*r = -EINTR;
|
||||
}
|
||||
|
||||
#define LOG_MAX_LEN 4096
|
||||
|
||||
__attribute__((format(printf, 5, 6)))
|
||||
void clogger(struct crypt_device *cd, int level, const char *file, int line,
|
||||
const char *format, ...)
|
||||
{
|
||||
va_list argp;
|
||||
char *target = NULL;
|
||||
char target[LOG_MAX_LEN + 2];
|
||||
|
||||
va_start(argp, format);
|
||||
|
||||
if (vasprintf(&target, format, argp) > 0) {
|
||||
if (vsnprintf(&target[0], LOG_MAX_LEN, format, argp) > 0) {
|
||||
if (level >= 0) {
|
||||
/* All verbose and error messages in tools end with EOL. */
|
||||
if (level == CRYPT_LOG_VERBOSE || level == CRYPT_LOG_ERROR)
|
||||
strncat(target, "\n", LOG_MAX_LEN);
|
||||
|
||||
crypt_log(cd, level, target);
|
||||
#ifdef CRYPT_DEBUG
|
||||
} else if (opt_debug)
|
||||
@@ -98,7 +104,6 @@ void clogger(struct crypt_device *cd, int level, const char *file, int line,
|
||||
}
|
||||
|
||||
va_end(argp);
|
||||
free(target);
|
||||
}
|
||||
|
||||
void tool_log(int level, const char *msg, void *usrptr __attribute__((unused)))
|
||||
@@ -151,7 +156,7 @@ int yesDialog(const char *msg, void *usrptr)
|
||||
r = 0;
|
||||
/* Aborted by signal */
|
||||
if (!quit)
|
||||
log_err(_("Error reading response from terminal.\n"));
|
||||
log_err(_("Error reading response from terminal."));
|
||||
else
|
||||
log_dbg("Query interrupted on signal.");
|
||||
} else if (strcmp(answer, "YES\n")) {
|
||||
@@ -230,7 +235,7 @@ __attribute__ ((noreturn)) void usage(poptContext popt_context,
|
||||
{
|
||||
poptPrintUsage(popt_context, stderr, 0);
|
||||
if (error)
|
||||
log_err("%s: %s\n", more, error);
|
||||
log_err("%s: %s", more, error);
|
||||
poptFreeContext(popt_context);
|
||||
exit(exitcode);
|
||||
}
|
||||
@@ -267,6 +272,30 @@ int translate_errno(int r)
|
||||
return r;
|
||||
}
|
||||
|
||||
void tools_keyslot_msg(int keyslot, crypt_object_op op)
|
||||
{
|
||||
if (keyslot < 0)
|
||||
return;
|
||||
|
||||
if (op == CREATED)
|
||||
log_verbose(_("Key slot %i created."), keyslot);
|
||||
else if (op == UNLOCKED)
|
||||
log_verbose(_("Key slot %i unlocked."), keyslot);
|
||||
else if (op == REMOVED)
|
||||
log_verbose(_("Key slot %i removed."), keyslot);
|
||||
}
|
||||
|
||||
void tools_token_msg(int token, crypt_object_op op)
|
||||
{
|
||||
if (token < 0)
|
||||
return;
|
||||
|
||||
if (op == CREATED)
|
||||
log_verbose(_("Token %i created."), token);
|
||||
else if (op == REMOVED)
|
||||
log_verbose(_("Token %i removed."), token);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device size string parsing, suffixes:
|
||||
* s|S - 512 bytes sectors
|
||||
@@ -419,8 +448,156 @@ int tools_wipe_progress(uint64_t size, uint64_t offset, void *usrptr)
|
||||
check_signal(&r);
|
||||
if (r) {
|
||||
tools_clear_line();
|
||||
log_err("\nWipe interrupted.\n");
|
||||
log_err("\nWipe interrupted.");
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void report_partition(const char *value, const char *device)
|
||||
{
|
||||
if (opt_batch_mode)
|
||||
log_dbg("Device %s already contains a '%s' partition signature.", device, value);
|
||||
else
|
||||
log_std(_("WARNING: Device %s already contains a '%s' partition signature.\n"), device, value);
|
||||
}
|
||||
|
||||
static void report_superblock(const char *value, const char *device)
|
||||
{
|
||||
if (opt_batch_mode)
|
||||
log_dbg("Device %s already contains a '%s' superblock signature.", device, value);
|
||||
else
|
||||
log_std(_("WARNING: Device %s already contains a '%s' superblock signature.\n"), device, value);
|
||||
}
|
||||
|
||||
int tools_detect_signatures(const char *device, int ignore_luks, size_t *count)
|
||||
{
|
||||
int r;
|
||||
size_t tmp_count;
|
||||
struct blkid_handle *h;
|
||||
blk_probe_status pr;
|
||||
|
||||
if (!count)
|
||||
count = &tmp_count;
|
||||
|
||||
*count = 0;
|
||||
|
||||
if (!blk_supported()) {
|
||||
log_dbg("Blkid support disabled.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((r = blk_init_by_path(&h, device))) {
|
||||
log_err(_("Failed to initialize device signature probes."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
blk_set_chains_for_full_print(h);
|
||||
|
||||
if (ignore_luks && blk_superblocks_filter_luks(h)) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while ((pr = blk_probe(h)) < PRB_EMPTY) {
|
||||
if (blk_is_partition(h))
|
||||
report_partition(blk_get_partition_type(h), device);
|
||||
else if (blk_is_superblock(h))
|
||||
report_superblock(blk_get_superblock_type(h), device);
|
||||
else {
|
||||
log_dbg("Internal tools_detect_signatures() error.");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (pr == PRB_FAIL)
|
||||
r = -EINVAL;
|
||||
out:
|
||||
blk_free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
int tools_wipe_all_signatures(const char *path)
|
||||
{
|
||||
int fd, flags, r;
|
||||
blk_probe_status pr;
|
||||
struct stat st;
|
||||
struct blkid_handle *h = NULL;
|
||||
|
||||
if (!blk_supported()) {
|
||||
log_dbg("Blkid support disabled.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stat(path, &st)) {
|
||||
log_err(_("Failed to stat device %s."), path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
flags = O_RDWR;
|
||||
if (S_ISBLK(st.st_mode))
|
||||
flags |= O_EXCL;
|
||||
|
||||
/* better than opening regular file with O_EXCL (undefined) */
|
||||
/* coverity[toctou] */
|
||||
fd = open(path, flags);
|
||||
if (fd < 0) {
|
||||
if (errno == EBUSY)
|
||||
log_err(_("Device %s is in use. Can not proceed with format operation."), path);
|
||||
else
|
||||
log_err(_("Failed to open file %s in read/write mode."), path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((r = blk_init_by_fd(&h, fd))) {
|
||||
log_err(_("Failed to initialize device signature probes."));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
blk_set_chains_for_wipes(h);
|
||||
|
||||
while ((pr = blk_probe(h)) < PRB_EMPTY) {
|
||||
if (blk_is_partition(h))
|
||||
log_verbose("Existing '%s' partition signature on device %s will be wiped.",
|
||||
blk_get_partition_type(h), path);
|
||||
if (blk_is_superblock(h))
|
||||
log_verbose("Existing '%s' superblock signature on device %s will be wiped.",
|
||||
blk_get_superblock_type(h), path);
|
||||
if (blk_do_wipe(h)) {
|
||||
log_err(_("Failed to wipe device signature."));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (pr != PRB_EMPTY) {
|
||||
log_err(_("Failed to probe device %s for a signature."), path);
|
||||
r = -EINVAL;
|
||||
}
|
||||
out:
|
||||
close(fd);
|
||||
blk_free(h);
|
||||
return r;
|
||||
}
|
||||
|
||||
int tools_is_cipher_null(const char *cipher)
|
||||
{
|
||||
if (!cipher)
|
||||
return 0;
|
||||
|
||||
return !strcmp(cipher, "cipher_null") ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Keyfile - is standard input treated as a binary file (no EOL handling).
|
||||
*/
|
||||
int tools_is_stdin(const char *key_file)
|
||||
{
|
||||
if (!key_file)
|
||||
return 1;
|
||||
|
||||
return strcmp(key_file, "-") ? 0 : 1;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user