Compare commits

...

35 Commits

Author SHA1 Message Date
Milan Broz
c67861e875 Update README. 2022-01-13 10:24:00 +01:00
Milan Broz
f566d7c911 Fix reencrypt mangle test for older jq. 2022-01-13 10:09:54 +01:00
Milan Broz
f21b07fb1b Version 2.4.3. 2022-01-12 18:42:14 +01:00
Milan Broz
904cdd1161 Add Release Notes. 2022-01-12 18:42:10 +01:00
Milan Broz
5d75632a16 Update LUKS2 on-disk description. 2022-01-12 18:42:06 +01:00
Ondrej Kozina
da8bcf7270 Allow reencryption metadata repair from cryptsetup. 2022-01-12 18:42:02 +01:00
Ondrej Kozina
bbc3ff69db Add CRYPT_REENCRYPT_REPAIR_NEEDED flag.
crypt_reencrypt_status() returns this flag if old
online-reencrypt requirement is detected and reencryption
keyslot digest is missing.

crypt_reencrypt_init_by_passphrase() with same flag applied
repairs (upgrade) reencryption metadata so that
automatic reencryption recovery during activation
is again possible and reencryption operation can be resumed
post CVE-2021-4122 fix.
2022-01-12 18:41:58 +01:00
Milan Broz
7ef0d9c73a Add reencryption mangle test 2022-01-12 18:41:55 +01:00
Ondrej Kozina
8ced413876 Make reencryption flag and keyslot inseparable.
LUKS2 validation code now requires reencrypt keyslot together with
online-reencryption flag or none of those.
2022-01-12 18:41:50 +01:00
Ondrej Kozina
80a77bce2a Rename LUKS2_keyslot_reencrypt_create function.
The function never writes on-disk. Also removed validation
function call-in since it will be called later before
writing on-disk and metadata does not have to be complete
at the moment of LUKS2_keyslot_reencrypt_allocate call.
2022-01-12 18:41:46 +01:00
Ondrej Kozina
334606b6aa Add segments validation for reencryption.
Effective segments during LUKS2 reencryption must
match key characteristics of backup segment
(cipher, sector_size, segment type).
2022-01-12 18:41:39 +01:00
Ondrej Kozina
1162f1e1e3 Split requirements validation from config section validation. 2022-01-12 14:49:11 +01:00
Ondrej Kozina
47a1d9a6d6 Expose json_segment_contains_flag to internal library. 2022-01-12 14:49:11 +01:00
Ondrej Kozina
c257ae1eb4 Move requirement helpers for later changes. 2022-01-12 14:49:11 +01:00
Milan Broz
d37c3f0db2 Add disable-luks2 reencryption configure option.
The option --disable-luks2-reencryption completely disable
LUKS2 reencryption code.

When used, the libcryptsetup library can read metadata with
reencryption code, but all reencryption API calls and cryptsetup
reencrypt commands are disabled.

Devices with online reencryption in progress cannot be activated.

This option can cause some incompatibilities. Please use with care.
2022-01-12 14:49:11 +01:00
Milan Broz
4a974ec582 Print better error if resilience hash is not available. 2022-01-12 14:49:11 +01:00
Milan Broz
c95a88f815 Do not run reencryption recovery when not needed. 2022-01-12 14:49:11 +01:00
Milan Broz
4af4a4a631 Reenc keyslot must have key_size == 1. 2022-01-12 14:49:11 +01:00
Milan Broz
3d269a5ae3 Fix debug message. 2022-01-12 14:49:11 +01:00
Ondrej Kozina
de98f01141 Fix CVE-2021-4122 - LUKS2 reencryption crash recovery attack
Fix possible attacks against data confidentiality through LUKS2 online
reencryption extension crash recovery.

An attacker can modify on-disk metadata to simulate decryption in
progress with crashed (unfinished) reencryption step and persistently
decrypt part of the LUKS device.

This attack requires repeated physical access to the LUKS device but
no knowledge of user passphrases.

The decryption step is performed after a valid user activates
the device with a correct passphrase and modified metadata.
There are no visible warnings for the user that such recovery happened
(except using the luksDump command). The attack can also be reversed
afterward (simulating crashed encryption from a plaintext) with
possible modification of revealed plaintext.

The problem was caused by reusing a mechanism designed for actual
reencryption operation without reassessing the security impact for new
encryption and decryption operations. While the reencryption requires
calculating and verifying both key digests, no digest was needed to
initiate decryption recovery if the destination is plaintext (no
encryption key). Also, some metadata (like encryption cipher) is not
protected, and an attacker could change it. Note that LUKS2 protects
visible metadata only when a random change occurs. It does not protect
against intentional modification but such modification must not cause
a violation of data confidentiality.

The fix introduces additional digest protection of reencryption
metadata. The digest is calculated from known keys and critical
reencryption metadata. Now an attacker cannot create correct metadata
digest without knowledge of a passphrase for used keyslots.
For more details, see LUKS2 On-Disk Format Specification version 1.1.0.
2022-01-12 14:49:11 +01:00
Vojtech Trefny
4d28153e53 bitlk: Fix support for startup key with new metadata entry
Windows 11 now includes the BitLocker volume GUID in the BEK file
metadata entries. This was previously not included so cryptsetup
refused to open the file because there was an unknown metadata
entry in the startup key.

Fixes: #690
2022-01-10 21:29:50 +01:00
Ondrej Kozina
dd864f5a61 Remove LUKS2 encryption data size restriction.
LUKS2 encryption with data shift required remaining
data size (size remaining after substracting --reduce-data-size value)
to be at least --reduce-data-size. This was wrong. Remaining
data size restriction should be correctly at least single sector
(whatever sector size is selected or auto-detected).
2022-01-10 21:29:32 +01:00
Josef Andersson
ca54398eec po: update sv.po (from translationproject.org) 2022-01-10 21:26:04 +01:00
Мирослав Николић
97cd16b8b9 po: update sr.po (from translationproject.org) 2022-01-10 21:25:55 +01:00
Antonio Ceballos
86d0d4f68e po: update es.po (from translationproject.org) 2022-01-10 21:25:44 +01:00
Tianjia Zhang
1a7d98b3ba Fix manual typo. 2022-01-10 21:25:30 +01:00
Sean
025a96df73 Update README.md 2022-01-10 21:25:17 +01:00
Milan Broz
e6edbc1fe5 Run CI on stable branches.
The stable branch is named "v2.<minor>.x".
2021-12-01 22:50:37 +01:00
Milan Broz
ed68b51526 Do not mix tabs and spaces in GitHub CI script. 2021-12-01 22:50:37 +01:00
Milan Broz
bcace16aa2 Do not mix tabs and spaces in Gitlab CI script. 2021-12-01 22:50:37 +01:00
Milan Broz
97aa31d32f Fix tabs in GitLab CI scripts and remove gcc comment.
The -Wall changes according to gcc versions.
2021-12-01 22:50:37 +01:00
Milan Broz
36a78ed17b Fix missing backslash in CI. 2021-12-01 22:50:37 +01:00
Milan Broz
0d4ecd92f1 Add limitation to cryptsetup group again in CI. 2021-12-01 22:50:37 +01:00
daniel.zatovic
94143c3428 Remove LLVM repo script 2021-12-01 22:50:37 +01:00
Daniel Zaťovič
af17d2256d Add compilation tests and static analysis on the Gitlab shared runner. 2021-12-01 22:50:37 +01:00
37 changed files with 4807 additions and 2517 deletions

View File

@@ -12,27 +12,27 @@ CXX="g++${COMPILER_VERSION:+-$COMPILER_VERSION}"
set -ex
for phase in "${PHASES[@]}"; do
case $phase in
CONFIGURE)
opts=(
--enable-libargon2
)
case $phase in
CONFIGURE)
opts=(
--enable-libargon2
)
sudo -E git clean -xdf
sudo -E git clean -xdf
./autogen.sh
CC="$CC" CXX="$CXX" CFLAGS="${CFLAGS[@]}" CXXFLAGS="${CXXFLAGS[@]}" ./configure "${opts[@]}"
;;
MAKE)
make -j
make -j -C tests check-programs
;;
CHECK)
make check
;;
./autogen.sh
CC="$CC" CXX="$CXX" CFLAGS="${CFLAGS[@]}" CXXFLAGS="${CXXFLAGS[@]}" ./configure "${opts[@]}"
;;
MAKE)
make -j
make -j -C tests check-programs
;;
CHECK)
make check
;;
*)
echo >&2 "Unknown phase '$phase'"
exit 1
esac
*)
echo >&2 "Unknown phase '$phase'"
exit 1
esac
done

View File

@@ -40,8 +40,8 @@ test-mergerq-job-debian-noroot:
stage: test
interruptible: true
rules:
# - if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
# when: never
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- make -j
@@ -62,7 +62,7 @@ test-main-commit-job-debian:
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
@@ -82,7 +82,7 @@ test-main-commit-job-dnf:
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
@@ -99,10 +99,15 @@ test-mergerq-job-dnf:
variables:
RUN_SSH_PLUGIN_TEST: "1"
rules:
# - if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
# when: never
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
include:
- local: .gitlab/ci/gitlab-shared-docker.yml
- local: .gitlab/ci/compilation-gcc.gitlab-ci.yml
- local: .gitlab/ci/compilation-clang.gitlab-ci.yml

View File

@@ -0,0 +1,49 @@
#!/bin/bash
set -ex
PACKAGES=(
git make autoconf automake autopoint pkg-config libtool libtool-bin
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol1-dev
libjson-c-dev libssh-dev libblkid-dev tar libargon2-0-dev libpwquality-dev
sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass
)
COMPILER="${COMPILER:?}"
COMPILER_VERSION="${COMPILER_VERSION:?}"
grep -E '^deb' /etc/apt/sources.list > /etc/apt/sources.list~
sed -Ei 's/^deb /deb-src /' /etc/apt/sources.list~
cat /etc/apt/sources.list~ >> /etc/apt/sources.list
apt-get -y update --fix-missing
DEBIAN_FRONTEND=noninteractive apt-get -yq install software-properties-common wget lsb-release
RELEASE="$(lsb_release -cs)"
if [[ $COMPILER == "gcc" ]]; then
# Latest gcc stack deb packages provided by
# https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test
add-apt-repository -y ppa:ubuntu-toolchain-r/test
PACKAGES+=(gcc-$COMPILER_VERSION)
elif [[ $COMPILER == "clang" ]]; then
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
add-apt-repository "deb http://apt.llvm.org/${RELEASE}/ llvm-toolchain-${RELEASE}-${COMPILER_VERSION} main"
# scan-build
PACKAGES+=(clang-tools-$COMPILER_VERSION clang-$COMPILER_VERSION lldb-$COMPILER_VERSION lld-$COMPILER_VERSION clangd-$COMPILER_VERSION)
PACKAGES+=(perl)
else
exit 1
fi
apt-get -y update --fix-missing
DEBIAN_FRONTEND=noninteractive apt-get -yq install "${PACKAGES[@]}"
apt-get -y build-dep cryptsetup
echo "====================== VERSIONS ==================="
if [[ $COMPILER == "clang" ]]; then
scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} --help
fi
${COMPILER}-$COMPILER_VERSION -v
echo "====================== END VERSIONS ==================="

55
.gitlab/ci/clang-Wall Executable file
View File

@@ -0,0 +1,55 @@
#!/bin/bash
# clang -Wall plus other important warnings not included in -Wall
for arg in "$@"
do
case $arg in
-O*) Wuninitialized=-Wuninitialized;; # only makes sense with `-O'
esac
done
CLANG="clang${COMPILER_VERSION:+-$COMPILER_VERSION}"
#PEDANTIC="-std=gnu99"
#PEDANTIC="-pedantic -std=gnu99"
#PEDANTIC="-pedantic -std=gnu99 -Wno-variadic-macros"
#CONVERSION="-Wconversion"
EXTRA="-Wextra \
-Wsign-compare \
-Werror-implicit-function-declaration \
-Wpointer-arith \
-Wwrite-strings \
-Wswitch \
-Wmissing-format-attribute \
-Winit-self \
-Wdeclaration-after-statement \
-Wold-style-definition \
-Wno-missing-field-initializers \
-Wno-unused-parameter \
-Wno-attributes \
-Wno-long-long"
exec $CLANG $PEDANTIC $CONVERSION \
-Wall $Wuninitialized \
-Wno-switch \
-Wdisabled-optimization \
-Wwrite-strings \
-Wpointer-arith \
-Wbad-function-cast \
-Wmissing-prototypes \
-Wmissing-declarations \
-Wstrict-prototypes \
-Wnested-externs \
-Wcomment \
-Winline \
-Wcast-align \
-Wcast-qual \
-Wredundant-decls $EXTRA \
"$@" 2>&1 | {
if [[ $USE_FILTER -eq 1 ]]; then
.gitlab/ci/warnings_filter.py
else
cat
fi
}

View File

@@ -0,0 +1,25 @@
test-clang-compilation:
extends:
- .gitlab-shared-clang
script:
- export CFLAGS="-Wall -Werror"
- ./configure --enable-pwquality --enable-libargon2
- make -j
# Clang doesn't support json output, so we cannot use the warnings filter
# test-clang-Wall-script:
# extends:
# - .gitlab-shared-clang
# script:
# - export CFLAGS="-g -O0"
# - export CC=".gitlab/ci/clang-Wall"
# - ./configure --enable-pwquality --enable-libargon2
# - make -j CFLAGS="-g -O0 -Werror"
test-scan-build:
extends:
- .gitlab-shared-clang
script:
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} -V ./configure CFLAGS="-g -O0" --enable-internal-sse-argon2 --enable-pwquality --enable-libargon2
- make clean
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} -maxloop 10 make -j

View File

@@ -0,0 +1,24 @@
test-gcc-compilation:
extends:
- .gitlab-shared-gcc
script:
- export CFLAGS="-Wall -Werror"
- ./configure --enable-pwquality --enable-libargon2
- make -j
test-gcc-Wall-script:
extends:
- .gitlab-shared-gcc
script:
- export CFLAGS="-g -O0"
- export CC=".gitlab/ci/gcc-Wall"
- USE_FILTER=0 ./configure --enable-pwquality --enable-libargon2
- USE_FILTER=1 make -j CFLAGS="-g -O0 -fdiagnostics-format=json"
test-gcc-fanalyzer:
extends:
- .gitlab-shared-gcc
script:
- export CFLAGS="-Wall -Werror -g -O0 -fanalyzer -fdiagnostics-path-format=separate-events"
- ./configure --enable-pwquality --enable-libargon2
- make -j

61
.gitlab/ci/gcc-Wall Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/bash
# gcc -Wall plus other important warnings not included in -Wall
for arg in "$@"
do
case $arg in
-O*) Wuninitialized=-Wuninitialized;; # only makes sense with `-O'
esac
done
GCC="gcc${COMPILER_VERSION:+-$COMPILER_VERSION}"
#PEDANTIC="-std=gnu99"
#PEDANTIC="-pedantic -std=gnu99"
#PEDANTIC="-pedantic -std=gnu99 -Wno-variadic-macros"
#CONVERSION="-Wconversion"
# -Wpacked \
EXTRA="-Wextra \
-Wsign-compare \
-Werror-implicit-function-declaration \
-Wpointer-arith \
-Wwrite-strings \
-Wswitch \
-Wmissing-format-attribute \
-Wstrict-aliasing=3 \
-Winit-self \
-Wunsafe-loop-optimizations \
-Wdeclaration-after-statement \
-Wold-style-definition \
-Wno-missing-field-initializers \
-Wno-unused-parameter \
-Wno-attributes \
-Wno-long-long \
-Wmaybe-uninitialized \
-Wvla"
exec $GCC $PEDANTIC $CONVERSION \
-Wall $Wuninitialized \
-Wno-switch \
-Wdisabled-optimization \
-Wwrite-strings \
-Wpointer-arith \
-Wbad-function-cast \
-Wmissing-prototypes \
-Wmissing-declarations \
-Wstrict-prototypes \
-Wnested-externs \
-Wcomment \
-Winline \
-Wcast-align \
-Wcast-qual \
-Wredundant-decls $EXTRA \
"$@" 2>&1 | {
if [[ $USE_FILTER -eq 1 ]]; then
.gitlab/ci/warnings_filter.py
else
cat
fi
}

View File

@@ -0,0 +1,29 @@
.gitlab-shared-docker:
image: ubuntu:focal
tags:
- gitlab-org-docker
stage: test
interruptible: true
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
before_script:
- .gitlab/ci/cibuild-setup-ubuntu.sh
- export CC="${COMPILER}${COMPILER_VERSION:+-$COMPILER_VERSION}"
- export CXX="${COMPILER}++${COMPILER_VERSION:+-$COMPILER_VERSION}"
- ./autogen.sh
.gitlab-shared-gcc:
extends:
- .gitlab-shared-docker
variables:
COMPILER: "gcc"
COMPILER_VERSION: "11"
RUN_SSH_PLUGIN_TEST: "1"
.gitlab-shared-clang:
extends:
- .gitlab-shared-docker
variables:
COMPILER: "clang"
COMPILER_VERSION: "13"
RUN_SSH_PLUGIN_TEST: "1"

31
.gitlab/ci/warnings_filter.py Executable file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/python3
import sys
import json
import linecache
if __name__ == "__main__":
json_string = sys.stdin.read()
if json_string in [None, ""]:
sys.exit(0)
parsed = json.loads(json_string)
#print(json.dumps(parsed, indent=4, sort_keys=True))
r = 0
for o in parsed:
kind = o["kind"]
start = o["locations"][0]["caret"]
l = linecache.getline(start["file"], int(start["line"]))
ignored = "json_object_object_foreach" in l
print(f"{o['kind']} {'ignored' if ignored else 'FOUND'} in {start['file']}:{start['line']}:{start['column']} {o['message']}")
print(f"line contains:\n\t{l}", end="")
if not ignored:
r = 1
sys.exit(r)

View File

@@ -46,16 +46,16 @@ Download
--------
All release tarballs and release notes are hosted on [kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
**The latest stable cryptsetup version is 2.4.2**
* [cryptsetup-2.4.2.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.2.tar.xz)
* Signature [cryptsetup-2.4.2.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.2.tar.sign)
**The latest stable cryptsetup version is 2.4.3**
* [cryptsetup-2.4.3.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.3.tar.xz)
* Signature [cryptsetup-2.4.3.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-2.4.3.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.4.2 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/v2.4.2-ReleaseNotes).
* [Cryptsetup 2.4.3 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/v2.4.3-ReleaseNotes).
Previous versions
* [Version 2.3.6](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.6.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.6.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.6-ReleaseNotes).
* [Version 2.3.7](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.7.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/cryptsetup-2.3.7.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.3/v2.3.7-ReleaseNotes).
* [Version 1.7.5](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).
@@ -73,7 +73,7 @@ NLS PO files are maintained by [TranslationProject](https://translationproject.o
Required packages
-----------------
All distributions provide cryptsetup as distro package. If you need to compile cryptsetup youfself, some packages are required for compilation. Please always prefer distro specific build tools to manually configuring cryptsetup.
All distributions provide cryptsetup as distro package. If you need to compile cryptsetup yourself, some packages are required for compilation. Please always prefer distro specific build tools to manually configuring cryptsetup.
For available compile options, check ``configure --help`` for more info. If you are using a git snapshot, you need to generate a configure script with ``autogen.sh`` script.
Here is the list of packages needed for the compilation of project for particular distributions:

View File

@@ -1,5 +1,5 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[2.4.2])
AC_INIT([cryptsetup],[2.4.3])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
@@ -140,6 +140,14 @@ if test "x$enable_ssh_token" = "xyes" -a "x$enable_external_tokens" = "xno"; the
AC_MSG_ERROR([Requested LUKS2 ssh-token build, but external tokens are disabled.])
fi
dnl LUKS2 online reencryption
AC_ARG_ENABLE([luks2-reencryption],
AS_HELP_STRING([--disable-luks2-reencryption], [disable LUKS2 online reencryption extension]),
[], [enable_luks2_reencryption=yes])
if test "x$enable_luks2_reencryption" = "xyes"; then
AC_DEFINE(USE_LUKS2_REENCRYPTION, 1, [Use LUKS2 online reencryption extension])
fi
dnl ==========================================================================
AM_GNU_GETTEXT([external],[need-ngettext])

Binary file not shown.

101
docs/v2.4.3-ReleaseNotes Normal file
View File

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

View File

@@ -100,6 +100,7 @@ libcryptsetup_la_SOURCES = \
lib/luks2/luks2_keyslot_luks2.c \
lib/luks2/luks2_keyslot_reenc.c \
lib/luks2/luks2_reencrypt.c \
lib/luks2/luks2_reencrypt_digest.c \
lib/luks2/luks2_segment.c \
lib/luks2/luks2_token_keyring.c \
lib/luks2/luks2_token.c \

View File

@@ -869,13 +869,20 @@ static int get_recovery_key(struct crypt_device *cd,
return 0;
}
static int parse_external_key_entry(struct crypt_device *cd, const char *data, int start, int end, struct volume_key **vk)
static int parse_external_key_entry(struct crypt_device *cd,
const char *data,
int start,
int end,
struct volume_key **vk,
const struct bitlk_metadata *params)
{
uint16_t key_entry_size = 0;
uint16_t key_entry_type = 0;
uint16_t key_entry_value = 0;
size_t key_size = 0;
const char *key = NULL;
struct bitlk_guid guid;
char guid_buf[UUID_STR_LEN] = {0};
while (end - start > 2) {
/* size of this entry */
@@ -892,8 +899,7 @@ static int parse_external_key_entry(struct crypt_device *cd, const char *data, i
key_entry_type = le16_to_cpu(key_entry_type);
key_entry_value = le16_to_cpu(key_entry_value);
/* only properties should be in this entry */
if (key_entry_type != BITLK_ENTRY_TYPE_PROPERTY) {
if (key_entry_type != BITLK_ENTRY_TYPE_PROPERTY && key_entry_type != BITLK_ENTRY_TYPE_VOLUME_GUID) {
log_err(cd, _("Unexpected metadata entry type '%u' found when parsing external key."), key_entry_type);
return -EINVAL;
}
@@ -908,7 +914,15 @@ static int parse_external_key_entry(struct crypt_device *cd, const char *data, i
/* optional "ExternalKey" string, we can safely ignore it */
} else if (key_entry_value == BITLK_ENTRY_VALUE_STRING)
;
else {
/* GUID of the BitLocker device we are trying to open with this key */
else if (key_entry_value == BITLK_ENTRY_VALUE_GUID) {
memcpy(&guid, data + start + BITLK_ENTRY_HEADER_LEN, sizeof(struct bitlk_guid));
guid_to_string(&guid, guid_buf);
if (strcmp(guid_buf, params->guid) != 0) {
log_err(cd, _("BEK file GUID '%s' does not match GUID of the volume."), guid_buf);
return -EINVAL;
}
} else {
log_err(cd, _("Unexpected metadata entry value '%u' found when parsing external key."), key_entry_value);
return -EINVAL;
}
@@ -925,7 +939,8 @@ static int get_startup_key(struct crypt_device *cd,
const char *password,
size_t passwordLen,
const struct bitlk_vmk *vmk,
struct volume_key **su_key)
struct volume_key **su_key,
const struct bitlk_metadata *params)
{
struct bitlk_bek_header bek_header = {0};
char guid_buf[UUID_STR_LEN] = {0};
@@ -975,7 +990,7 @@ static int get_startup_key(struct crypt_device *cd,
if (key_entry_type == BITLK_ENTRY_TYPE_STARTUP_KEY && key_entry_value == BITLK_ENTRY_VALUE_EXTERNAL_KEY) {
return parse_external_key_entry(cd, password,
BITLK_BEK_FILE_HEADER_LEN + BITLK_ENTRY_HEADER_LEN + BITLK_STARTUP_KEY_HEADER_LEN,
passwordLen, su_key);
passwordLen, su_key, params);
} else {
log_err(cd, _("Unexpected metadata entry found when parsing startup key."));
log_dbg(cd, "Entry type: %u, entry value: %u", key_entry_type, key_entry_value);
@@ -1142,7 +1157,7 @@ int BITLK_get_volume_key(struct crypt_device *cd,
if (r)
return r;
} else if (next_vmk->protection == BITLK_PROTECTION_STARTUP_KEY) {
r = get_startup_key(cd, password, passwordLen, next_vmk, &vmk_dec_key);
r = get_startup_key(cd, password, passwordLen, next_vmk, &vmk_dec_key, params);
if (r) {
next_vmk = next_vmk->next;
continue;

View File

@@ -61,6 +61,7 @@ typedef enum {
BITLK_ENTRY_TYPE_STARTUP_KEY = 0x0006,
BITLK_ENTRY_TYPE_DESCRIPTION = 0x0007,
BITLK_ENTRY_TYPE_VOLUME_HEADER = 0x000f,
BITLK_ENTRY_TYPE_VOLUME_GUID = 0x0019,
} BITLKFVEEntryType;
typedef enum {
@@ -76,6 +77,7 @@ typedef enum {
BITLK_ENTRY_VALUE_EXTERNAL_KEY = 0x0009,
BITLK_ENTRY_VALUE_OFFSET_SIZE = 0x000f,
BITLK_ENTRY_VALUE_RECOVERY_TIME = 0x015,
BITLK_ENTRY_VALUE_GUID = 0x0017,
} BITLKFVEEntryValue;
struct bitlk_vmk {

View File

@@ -2397,6 +2397,8 @@ int crypt_activate_by_token_pin(struct crypt_device *cd,
#define CRYPT_REENCRYPT_RESUME_ONLY (1 << 2)
/** Run reencryption recovery only. (in) */
#define CRYPT_REENCRYPT_RECOVERY (1 << 3)
/** Reencryption requires metadata protection. (in/out) */
#define CRYPT_REENCRYPT_REPAIR_NEEDED (1 << 4)
/**
* Reencryption direction

View File

@@ -401,6 +401,8 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs);
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit);
int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint32_t *version);
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
int LUKS2_key_description_by_segment(struct crypt_device *cd,
@@ -453,4 +455,8 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd,
bool activation,
bool dynamic);
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks);
#endif

View File

@@ -234,14 +234,20 @@ int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
const void *buffer,
size_t buffer_length);
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params);
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks);
int LUKS2_keyslot_dump(struct crypt_device *cd,
int keyslot);
int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length);
/* JSON helpers */
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise);
const char *json_segment_type(json_object *jobj_segment);
@@ -257,6 +263,8 @@ uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned b
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length, const char *cipher, uint32_t sector_size, unsigned reencryption);
int json_segments_segment_in_reencrypt(json_object *jobj_segments);
bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2);
bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len);
int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,
struct luks2_hdr *hdr,

View File

@@ -592,6 +592,78 @@ static bool validate_segment_intervals(struct crypt_device *cd,
return true;
}
static int reqs_unknown(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_UNKNOWN;
}
static int reqs_reencrypt(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT;
}
static int reqs_reencrypt_online(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT;
}
/*
* Config section requirements object must be valid.
* Also general segments section must be validated first.
*/
static int validate_reencrypt_segments(struct crypt_device *cd, json_object *hdr_jobj, json_object *jobj_segments, int first_backup, int segments_count)
{
json_object *jobj, *jobj_backup_previous = NULL, *jobj_backup_final = NULL;
uint32_t reqs;
int i, r;
struct luks2_hdr dummy = {
.jobj = hdr_jobj
};
r = LUKS2_config_get_requirements(cd, &dummy, &reqs);
if (r)
return 1;
if (reqs_reencrypt_online(reqs)) {
for (i = first_backup; i < segments_count; i++) {
jobj = json_segments_get_segment(jobj_segments, i);
if (!jobj)
return 1;
if (json_segment_contains_flag(jobj, "backup-final", 0))
jobj_backup_final = jobj;
else if (json_segment_contains_flag(jobj, "backup-previous", 0))
jobj_backup_previous = jobj;
}
if (!jobj_backup_final || !jobj_backup_previous) {
log_dbg(cd, "Backup segment is missing.");
return 1;
}
for (i = 0; i < first_backup; i++) {
jobj = json_segments_get_segment(jobj_segments, i);
if (!jobj)
return 1;
if (json_segment_contains_flag(jobj, "in-reencryption", 0)) {
if (!json_segment_cmp(jobj, jobj_backup_final)) {
log_dbg(cd, "Segment in reencryption does not match backup final segment.");
return 1;
}
continue;
}
if (!json_segment_cmp(jobj, jobj_backup_final) &&
!json_segment_cmp(jobj, jobj_backup_previous)) {
log_dbg(cd, "Segment does not match neither backup final or backup previous segment.");
return 1;
}
}
}
return 0;
}
static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
{
json_object *jobj_segments, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags, *jobj;
@@ -718,7 +790,7 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
}
}
return 0;
return validate_reencrypt_segments(cd, hdr_jobj, jobj_segments, first_backup, count);
}
static uint64_t LUKS2_metadata_size_jobj(json_object *jobj)
@@ -841,9 +913,10 @@ static int hdr_validate_digests(struct crypt_device *cd, json_object *hdr_jobj)
return 0;
}
/* requirements being validated in stand-alone routine */
static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj)
{
json_object *jobj_config, *jobj, *jobj1;
json_object *jobj_config, *jobj;
int i;
uint64_t keyslots_size, metadata_size, segment_offset;
@@ -898,6 +971,19 @@ static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj)
return 1;
}
return 0;
}
static int hdr_validate_requirements(struct crypt_device *cd, json_object *hdr_jobj)
{
int i;
json_object *jobj_config, *jobj, *jobj1;
if (!json_object_object_get_ex(hdr_jobj, "config", &jobj_config)) {
log_dbg(cd, "Missing config section.");
return 1;
}
/* Requirements object is optional */
if (json_object_object_get_ex(jobj_config, "requirements", &jobj)) {
if (!json_contains(cd, jobj_config, "section", "Config", "requirements", json_type_object))
@@ -923,6 +1009,7 @@ int LUKS2_hdr_validate(struct crypt_device *cd, json_object *hdr_jobj, uint64_t
struct {
int (*validate)(struct crypt_device *, json_object *);
} checks[] = {
{ hdr_validate_requirements },
{ hdr_validate_tokens },
{ hdr_validate_digests },
{ hdr_validate_segments },
@@ -1139,21 +1226,6 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
return r;
}
static int reqs_unknown(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_UNKNOWN;
}
static int reqs_reencrypt(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT;
}
static int reqs_reencrypt_online(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT;
}
int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
const char *backup_file)
{
@@ -1389,24 +1461,106 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
*/
/* LUKS2 library requirements */
static const struct {
struct requirement_flag {
uint32_t flag;
uint32_t version;
const char *description;
} requirements_flags[] = {
{ CRYPT_REQUIREMENT_OFFLINE_REENCRYPT, "offline-reencrypt" },
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, "online-reencrypt" },
{ 0, NULL }
};
static uint32_t get_requirement_by_name(const char *requirement)
static const struct requirement_flag unknown_requirement_flag = { CRYPT_REQUIREMENT_UNKNOWN, 0, NULL };
static const struct requirement_flag requirements_flags[] = {
{ CRYPT_REQUIREMENT_OFFLINE_REENCRYPT,1, "offline-reencrypt" },
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 2, "online-reencrypt-v2" },
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1, "online-reencrypt" },
{ 0, 0, NULL }
};
static const struct requirement_flag *get_requirement_by_name(const char *requirement)
{
int i;
for (i = 0; requirements_flags[i].description; i++)
if (!strcmp(requirement, requirements_flags[i].description))
return requirements_flags[i].flag;
return requirements_flags + i;
return CRYPT_REQUIREMENT_UNKNOWN;
return &unknown_requirement_flag;
}
int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint32_t *version)
{
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
int i, len;
const struct requirement_flag *req;
assert(hdr && version);
if (!hdr || !version)
return -EINVAL;
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
return -EINVAL;
if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements))
return -ENOENT;
if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory))
return -ENOENT;
len = (int) json_object_array_length(jobj_mandatory);
if (len <= 0)
return -ENOENT;
for (i = 0; i < len; i++) {
jobj = json_object_array_get_idx(jobj_mandatory, i);
/* search for requirements prefixed with "online-reencrypt" */
if (strncmp(json_object_get_string(jobj), "online-reencrypt", 16))
continue;
/* check current library is aware of the requirement */
req = get_requirement_by_name(json_object_get_string(jobj));
if (req->flag == (uint32_t)CRYPT_REQUIREMENT_UNKNOWN)
continue;
*version = req->version;
return 0;
}
return -ENOENT;
}
static const struct requirement_flag *stored_requirement_name_by_id(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t req_id)
{
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
int i, len;
const struct requirement_flag *req;
assert(hdr);
if (!hdr)
return NULL;
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
return NULL;
if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements))
return NULL;
if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory))
return NULL;
len = (int) json_object_array_length(jobj_mandatory);
if (len <= 0)
return 0;
for (i = 0; i < len; i++) {
jobj = json_object_array_get_idx(jobj_mandatory, i);
req = get_requirement_by_name(json_object_get_string(jobj));
if (req->flag == req_id)
return req;
}
return NULL;
}
/*
@@ -1416,7 +1570,7 @@ int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
{
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
int i, len;
uint32_t req;
const struct requirement_flag *req;
assert(hdr);
if (!hdr || !reqs)
@@ -1443,8 +1597,8 @@ int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
jobj = json_object_array_get_idx(jobj_mandatory, i);
req = get_requirement_by_name(json_object_get_string(jobj));
log_dbg(cd, "%s - %sknown", json_object_get_string(jobj),
reqs_unknown(req) ? "un" : "");
*reqs |= req;
reqs_unknown(req->flag) ? "un" : "");
*reqs |= req->flag;
}
return 0;
@@ -1454,6 +1608,8 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
{
json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
int i, r = -EINVAL;
const struct requirement_flag *req;
uint32_t req_id;
if (!hdr)
return -EINVAL;
@@ -1463,8 +1619,14 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
return -ENOMEM;
for (i = 0; requirements_flags[i].description; i++) {
if (reqs & requirements_flags[i].flag) {
jobj = json_object_new_string(requirements_flags[i].description);
req_id = reqs & requirements_flags[i].flag;
if (req_id) {
/* retain already stored version of requirement flag */
req = stored_requirement_name_by_id(cd, hdr, req_id);
if (req)
jobj = json_object_new_string(req->description);
else
jobj = json_object_new_string(requirements_flags[i].description);
if (!jobj) {
r = -ENOMEM;
goto err;

View File

@@ -27,7 +27,9 @@ extern const keyslot_handler reenc_keyslot;
static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
&luks2_keyslot,
#if USE_LUKS2_REENCRYPTION
&reenc_keyslot,
#endif
NULL
};
@@ -288,19 +290,9 @@ crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot)
return CRYPT_SLOT_ACTIVE;
}
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length)
int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length)
{
json_object *jobj_keyslot, *jobj_area, *jobj;
if(LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID)
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -ENOENT;
json_object *jobj_area, *jobj;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
return -EINVAL;
@@ -316,6 +308,23 @@ int LUKS2_keyslot_area(struct luks2_hdr *hdr,
return 0;
}
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
int keyslot,
uint64_t *offset,
uint64_t *length)
{
json_object *jobj_keyslot;
if (LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID)
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -ENOENT;
return LUKS2_keyslot_jobj_area(jobj_keyslot, offset, length);
}
static int _open_and_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
const keyslot_handler *h,
@@ -596,7 +605,7 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
return r;
}
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
const struct crypt_params_reencrypt *params)
@@ -625,9 +634,6 @@ int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
return r;
}
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
return -EINVAL;
return 0;
}
@@ -878,10 +884,17 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
const keyslot_handler *h;
int keyslot;
json_object *jobj_keyslots, *jobj_type;
uint32_t reqs, reencrypt_count = 0;
struct luks2_hdr dummy = {
.jobj = hdr_jobj
};
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return -EINVAL;
if (LUKS2_config_get_requirements(cd, &dummy, &reqs))
return -EINVAL;
json_object_object_foreach(jobj_keyslots, slot, val) {
keyslot = atoi(slot);
json_object_object_get_ex(val, "type", &jobj_type);
@@ -897,6 +910,24 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
log_dbg(cd, "Keyslot %d is not assigned to exactly 1 digest.", keyslot);
return -EINVAL;
}
if (!strcmp(h->name, "reencrypt"))
reencrypt_count++;
}
if ((reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count == 0) {
log_dbg(cd, "Missing reencryption keyslot.");
return -EINVAL;
}
if (!(reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count) {
log_dbg(cd, "Missing reencryption requirement flag.");
return -EINVAL;
}
if (reencrypt_count > 1) {
log_dbg(cd, "Too many reencryption keyslots.");
return -EINVAL;
}
return 0;

View File

@@ -176,9 +176,17 @@ static int reenc_keyslot_store(struct crypt_device *cd,
return r < 0 ? r : keyslot;
}
static int reenc_keyslot_wipe(struct crypt_device *cd __attribute__((unused)),
int keyslot __attribute__((unused)))
static int reenc_keyslot_wipe(struct crypt_device *cd,
int keyslot)
{
struct luks2_hdr *hdr;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
/* remove reencryption verification data */
LUKS2_digest_assign(cd, hdr, keyslot, CRYPT_ANY_DIGEST, 0, 0);
return 0;
}
@@ -222,7 +230,7 @@ static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot)
static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
{
json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction;
json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction, *jobj_key_size;
const char *mode, *type, *direction;
uint32_t sector_size;
uint64_t shift_size;
@@ -242,12 +250,18 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
!json_object_object_get_ex(jobj_area, "type", &jobj_type))
return -EINVAL;
jobj_key_size = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "key_size", json_type_int);
jobj_mode = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "mode", json_type_string);
jobj_direction = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "direction", json_type_string);
if (!jobj_mode || !jobj_direction)
if (!jobj_mode || !jobj_direction || !jobj_key_size)
return -EINVAL;
if (!validate_json_uint32(jobj_key_size) || crypt_jobj_get_uint32(jobj_key_size) != 1) {
log_dbg(cd, "Illegal reencrypt key size.");
return -EINVAL;
}
mode = json_object_get_string(jobj_mode);
type = json_object_get_string(jobj_type);
direction = json_object_get_string(jobj_direction);

View File

@@ -91,10 +91,11 @@ struct luks2_reencrypt {
struct crypt_lock_handle *reenc_lock;
};
#if USE_LUKS2_REENCRYPTION
static int reencrypt_keyslot_update(struct crypt_device *cd,
const struct luks2_reencrypt *rh)
{
int r;
json_object *jobj_keyslot, *jobj_area, *jobj_area_type;
struct luks2_hdr *hdr;
@@ -124,7 +125,11 @@ static int reencrypt_keyslot_update(struct crypt_device *cd,
} else
log_dbg(cd, "No update of reencrypt keyslot needed.");
return 0;
r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, rh->vks);
if (r < 0)
log_err(cd, "Failed to refresh reencryption verification digest.");
return r;
}
static json_object *reencrypt_segment(struct luks2_hdr *hdr, unsigned new)
@@ -190,7 +195,7 @@ static uint64_t reencrypt_get_data_offset_old(struct luks2_hdr *hdr)
{
return reencrypt_data_offset(hdr, 0);
}
#endif
static int reencrypt_digest(struct luks2_hdr *hdr, unsigned new)
{
int segment = LUKS2_get_segment_id_by_flag(hdr, new ? "backup-final" : "backup-previous");
@@ -249,7 +254,7 @@ static const char *reencrypt_resilience_hash(struct luks2_hdr *hdr)
return json_object_get_string(jobj_hash);
}
#if USE_LUKS2_REENCRYPTION
static uint32_t reencrypt_alignment(struct luks2_hdr *hdr)
{
json_object *jobj_keyslot, *jobj_area, *jobj_type, *jobj_hash, *jobj_sector_size;
@@ -661,7 +666,7 @@ static int reencrypt_make_post_segments(struct crypt_device *cd,
return rh->jobj_segs_post ? 0 : -EINVAL;
}
#endif
static uint64_t reencrypt_data_shift(struct luks2_hdr *hdr)
{
json_object *jobj_keyslot, *jobj_area, *jobj_data_shift;
@@ -767,7 +772,7 @@ void LUKS2_reencrypt_free(struct crypt_device *cd, struct luks2_reencrypt *rh)
crypt_unlock_internal(cd, rh->reenc_lock);
free(rh);
}
#if USE_LUKS2_REENCRYPTION
static size_t reencrypt_get_alignment(struct crypt_device *cd,
struct luks2_hdr *hdr)
{
@@ -825,7 +830,7 @@ static int reencrypt_offset_backward_moved(struct luks2_hdr *hdr, json_object *j
linear_length += LUKS2_segment_size(hdr, sg, 0);
/* all active linear segments length */
if (linear_length) {
if (linear_length && segs > 1) {
if (linear_length < data_shift)
return -EINVAL;
tmp = linear_length - data_shift;
@@ -1020,7 +1025,7 @@ static int reencrypt_context_init(struct crypt_device *cd, struct luks2_hdr *hdr
}
if (crypt_hash_init(&rh->rp.p.csum.ch, params->hash)) {
log_dbg(cd, "Failed to initialize checksum resilience hash %s", params->hash);
log_err(cd, _("Hash algorithm %s not supported."), params->hash);
return -EINVAL;
}
@@ -1745,7 +1750,8 @@ static int reencrypt_set_encrypt_segments(struct crypt_device *cd, struct luks2_
int r;
uint64_t first_segment_offset, first_segment_length,
second_segment_offset, second_segment_length,
data_offset = LUKS2_get_data_offset(hdr) << SECTOR_SHIFT;
data_offset = LUKS2_get_data_offset(hdr) << SECTOR_SHIFT,
data_size = dev_size - data_shift;
json_object *jobj_segment_first = NULL, *jobj_segment_second = NULL, *jobj_segments;
if (dev_size < data_shift)
@@ -1760,9 +1766,14 @@ static int reencrypt_set_encrypt_segments(struct crypt_device *cd, struct luks2_
* [future LUKS2 header (data shift size)][second data segment][gap (data shift size)][first data segment (data shift size)]
*/
first_segment_offset = dev_size;
first_segment_length = data_shift;
second_segment_offset = data_shift;
second_segment_length = dev_size - 2 * data_shift;
if (data_size < data_shift) {
first_segment_length = data_size;
second_segment_length = second_segment_offset = 0;
} else {
first_segment_length = data_shift;
second_segment_offset = data_shift;
second_segment_length = data_size - data_shift;
}
} else if (data_shift) {
first_segment_offset = data_offset;
first_segment_length = dev_size;
@@ -2163,17 +2174,10 @@ static int reencrypt_move_data(struct crypt_device *cd, int devfd, uint64_t data
log_dbg(cd, "Going to move data from head of data device.");
buffer_len = data_shift;
if (!buffer_len)
return -EINVAL;
offset = json_segment_get_offset(LUKS2_get_segment_jobj(hdr, 0), 0);
/* this is nonsense anyway */
if (buffer_len != json_segment_get_size(LUKS2_get_segment_jobj(hdr, 0), 0)) {
log_dbg(cd, "buffer_len %" PRIu64", segment size %" PRIu64, buffer_len, json_segment_get_size(LUKS2_get_segment_jobj(hdr, 0), 0));
buffer_len = json_segment_get_size(LUKS2_get_segment_jobj(hdr, 0), 0);
if (!buffer_len || buffer_len > data_shift)
return -EINVAL;
}
if (posix_memalign(&buffer, device_alignment(crypt_data_device(cd)), buffer_len))
return -ENOMEM;
@@ -2447,7 +2451,7 @@ static int reencrypt_init(struct crypt_device *cd,
* encryption initialization (or mount)
*/
if (move_first_segment) {
if (dev_size < 2 * (params->data_shift << SECTOR_SHIFT)) {
if (dev_size < (params->data_shift << SECTOR_SHIFT)) {
log_err(cd, _("Device %s is too small."), device_path(crypt_data_device(cd)));
return -EINVAL;
}
@@ -2470,7 +2474,7 @@ static int reencrypt_init(struct crypt_device *cd,
goto out;
}
r = LUKS2_keyslot_reencrypt_create(cd, hdr, reencrypt_keyslot,
r = LUKS2_keyslot_reencrypt_allocate(cd, hdr, reencrypt_keyslot,
params);
if (r < 0)
goto out;
@@ -2485,6 +2489,10 @@ static int reencrypt_init(struct crypt_device *cd,
if (r < 0)
goto out;
r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, *vks);
if (r < 0)
goto out;
if (name && params->mode != CRYPT_REENCRYPT_ENCRYPT) {
r = reencrypt_verify_and_upload_keys(cd, hdr, LUKS2_reencrypt_digest_old(hdr), LUKS2_reencrypt_digest_new(hdr), *vks);
if (r)
@@ -2615,20 +2623,28 @@ static int reencrypt_context_update(struct crypt_device *cd,
static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr,
uint64_t device_size,
const struct crypt_params_reencrypt *params,
struct volume_key *vks,
struct luks2_reencrypt **rh)
{
int r;
struct luks2_reencrypt *tmp = NULL;
crypt_reencrypt_info ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_NONE) {
log_err(cd, _("Device not marked for LUKS2 reencryption."));
return -EINVAL;
} else if (ri == CRYPT_REENCRYPT_INVALID)
return -EINVAL;
r = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
if (r < 0)
return r;
if (ri == CRYPT_REENCRYPT_CLEAN)
r = reencrypt_load_clean(cd, hdr, device_size, &tmp, params);
else if (ri == CRYPT_REENCRYPT_CRASH)
r = reencrypt_load_crashed(cd, hdr, device_size, &tmp);
else if (ri == CRYPT_REENCRYPT_NONE) {
log_err(cd, _("Device not marked for LUKS2 reencryption."));
return -EINVAL;
} else
else
r = -EINVAL;
if (r < 0 || !tmp) {
@@ -2640,7 +2656,7 @@ static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr,
return 0;
}
#endif
static int reencrypt_lock_internal(struct crypt_device *cd, const char *uuid, struct crypt_lock_handle **reencrypt_lock)
{
int r;
@@ -2702,7 +2718,7 @@ void LUKS2_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *r
{
crypt_unlock_internal(cd, reencrypt_lock);
}
#if USE_LUKS2_REENCRYPTION
static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr *hdr,
struct crypt_lock_handle **reencrypt_lock)
{
@@ -2877,7 +2893,7 @@ static int reencrypt_load_by_passphrase(struct crypt_device *cd,
rparams.device_size = required_size;
}
r = reencrypt_load(cd, hdr, device_size, &rparams, &rh);
r = reencrypt_load(cd, hdr, device_size, &rparams, *vks, &rh);
if (r < 0 || !rh)
goto err;
@@ -2972,6 +2988,85 @@ static int reencrypt_recovery_by_passphrase(struct crypt_device *cd,
return r;
}
static int reencrypt_repair_by_passphrase(
struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot_old,
int keyslot_new,
const char *passphrase,
size_t passphrase_size)
{
int r;
struct crypt_lock_handle *reencrypt_lock;
struct luks2_reencrypt *rh;
crypt_reencrypt_info ri;
struct volume_key *vks = NULL;
log_dbg(cd, "Loading LUKS2 reencryption context for metadata repair.");
rh = crypt_get_luks2_reencrypt(cd);
if (rh) {
LUKS2_reencrypt_free(cd, rh);
crypt_set_luks2_reencrypt(cd, NULL);
rh = NULL;
}
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID)
return -EINVAL;
if (ri < CRYPT_REENCRYPT_CLEAN) {
log_err(cd, _("Device is not in reencryption."));
return -EINVAL;
}
r = LUKS2_reencrypt_lock(cd, &reencrypt_lock);
if (r < 0) {
if (r == -EBUSY)
log_err(cd, _("Reencryption process is already running."));
else
log_err(cd, _("Failed to acquire reencryption lock."));
return r;
}
/* With reencryption lock held, reload device context and verify metadata state */
r = crypt_load(cd, CRYPT_LUKS2, NULL);
if (r)
goto out;
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID) {
r = -EINVAL;
goto out;
}
if (ri == CRYPT_REENCRYPT_NONE) {
r = 0;
goto out;
}
r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, keyslot_new, passphrase, passphrase_size, &vks);
if (r < 0)
goto out;
r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, vks);
crypt_free_volume_key(vks);
vks = NULL;
if (r < 0)
goto out;
/* removes online-reencrypt flag v1 */
if ((r = reencrypt_update_flag(cd, 0, false)))
goto out;
/* adds online-reencrypt flag v2 and commits metadata */
r = reencrypt_update_flag(cd, 1, true);
out:
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
crypt_free_volume_key(vks);
return r;
}
#endif
static int reencrypt_init_by_passphrase(struct crypt_device *cd,
const char *name,
const char *passphrase,
@@ -2982,12 +3077,17 @@ static int reencrypt_init_by_passphrase(struct crypt_device *cd,
const char *cipher_mode,
const struct crypt_params_reencrypt *params)
{
#if USE_LUKS2_REENCRYPTION
int r;
crypt_reencrypt_info ri;
struct volume_key *vks = NULL;
uint32_t flags = params ? params->flags : 0;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
/* short-circuit in reencryption metadata update and finish immediately. */
if (flags & CRYPT_REENCRYPT_REPAIR_NEEDED)
return reencrypt_repair_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size);
/* short-circuit in recovery and finish immediately. */
if (flags & CRYPT_REENCRYPT_RECOVERY)
return reencrypt_recovery_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size);
@@ -3037,6 +3137,10 @@ out:
crypt_drop_keyring_key(cd, vks);
crypt_free_volume_key(vks);
return r < 0 ? r : LUKS2_find_keyslot(hdr, "reencrypt");
#else
log_err(cd, _("This operation is not supported for this device type."));
return -ENOTSUP;
#endif
}
int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
@@ -3089,6 +3193,7 @@ int crypt_reencrypt_init_by_passphrase(struct crypt_device *cd,
return reencrypt_init_by_passphrase(cd, name, passphrase, passphrase_size, keyslot_old, keyslot_new, cipher, cipher_mode, params);
}
#if USE_LUKS2_REENCRYPTION
static reenc_status_t reencrypt_step(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct luks2_reencrypt *rh,
@@ -3097,13 +3202,6 @@ static reenc_status_t reencrypt_step(struct crypt_device *cd,
{
int r;
/* update reencrypt keyslot protection parameters in memory only */
r = reencrypt_keyslot_update(cd, rh);
if (r < 0) {
log_dbg(cd, "Keyslot update failed.");
return REENC_ERR;
}
/* in memory only */
r = reencrypt_make_segments(cd, hdr, rh, device_size);
if (r)
@@ -3273,15 +3371,20 @@ static int reencrypt_teardown_ok(struct crypt_device *cd, struct luks2_hdr *hdr,
log_dbg(cd, "Failed to set new keyslots area size.");
if (rh->digest_old >= 0 && rh->digest_new != rh->digest_old)
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++)
if (LUKS2_digest_by_keyslot(hdr, i) == rh->digest_old)
crypt_keyslot_destroy(cd, i);
crypt_keyslot_destroy(cd, rh->reenc_keyslot);
if (LUKS2_digest_by_keyslot(hdr, i) == rh->digest_old && crypt_keyslot_destroy(cd, i))
log_err(cd, _("Failed to remove unused (unbound) keyslot %d."), i);
if (reencrypt_erase_backup_segments(cd, hdr))
log_dbg(cd, "Failed to erase backup segments");
/* do we need atomic erase? */
if (reencrypt_update_flag(cd, 0, true))
log_err(cd, _("Failed to disable reencryption requirement flag."));
if (reencrypt_update_flag(cd, 0, false))
log_dbg(cd, "Failed to disable reencryption requirement flag.");
/* metadata commit point also removing reencryption flag on-disk */
if (crypt_keyslot_destroy(cd, rh->reenc_keyslot)) {
log_err(cd, _("Failed to remove reencryption keyslot."));
return -EINVAL;
}
}
return 0;
@@ -3330,12 +3433,14 @@ static int reencrypt_teardown(struct crypt_device *cd, struct luks2_hdr *hdr,
return r;
}
#endif
int crypt_reencrypt_run(
struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
void *usrptr)
{
#if USE_LUKS2_REENCRYPTION
int r;
crypt_reencrypt_info ri;
struct luks2_hdr *hdr;
@@ -3371,6 +3476,15 @@ int crypt_reencrypt_run(
rs = REENC_OK;
/* update reencrypt keyslot protection parameters in memory only */
if (!quit && (rh->device_size > rh->progress)) {
r = reencrypt_keyslot_update(cd, rh);
if (r < 0) {
log_dbg(cd, "Keyslot update failed.");
return reencrypt_teardown(cd, hdr, rh, REENC_ERR, quit, progress, usrptr);
}
}
while (!quit && (rh->device_size > rh->progress)) {
rs = reencrypt_step(cd, hdr, rh, rh->device_size, rh->online);
if (rs != REENC_OK)
@@ -3393,6 +3507,10 @@ int crypt_reencrypt_run(
r = reencrypt_teardown(cd, hdr, rh, rs, quit, progress, usrptr);
return r;
#else
log_err(cd, _("This operation is not supported for this device type."));
return -ENOTSUP;
#endif
}
int crypt_reencrypt(
@@ -3401,7 +3519,7 @@ int crypt_reencrypt(
{
return crypt_reencrypt_run(cd, progress, NULL);
}
#if USE_LUKS2_REENCRYPTION
static int reencrypt_recovery(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint64_t device_size,
@@ -3410,7 +3528,7 @@ static int reencrypt_recovery(struct crypt_device *cd,
int r;
struct luks2_reencrypt *rh = NULL;
r = reencrypt_load(cd, hdr, device_size, NULL, &rh);
r = reencrypt_load(cd, hdr, device_size, NULL, vks, &rh);
if (r < 0) {
log_err(cd, _("Failed to load LUKS2 reencryption context."));
return r;
@@ -3437,7 +3555,7 @@ out:
return r;
}
#endif
/*
* use only for calculation of minimal data device size.
* The real data offset is taken directly from segments!
@@ -3479,12 +3597,12 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd, struct luks2_hdr
return r;
log_dbg(cd, "Required minimal device size: %" PRIu64 " (%" PRIu64 " sectors)"
", real device size: %" PRIu64 " (%" PRIu64 " sectors)\n"
", real device size: %" PRIu64 " (%" PRIu64 " sectors) "
"calculated device size: %" PRIu64 " (%" PRIu64 " sectors)",
check_size, check_size >> SECTOR_SHIFT, real_size, real_size >> SECTOR_SHIFT,
real_size - data_offset, (real_size - data_offset) >> SECTOR_SHIFT);
if (real_size < data_offset || (check_size && (real_size - data_offset) < check_size)) {
if (real_size < data_offset || (check_size && real_size < check_size)) {
log_err(cd, _("Device %s is too small."), device_path(crypt_data_device(cd)));
return -EINVAL;
}
@@ -3493,7 +3611,7 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd, struct luks2_hdr
return 0;
}
#if USE_LUKS2_REENCRYPTION
/* returns keyslot number on success (>= 0) or negative errnor otherwise */
int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
int keyslot_old,
@@ -3543,16 +3661,32 @@ out:
return r < 0 ? r : keyslot;
}
#endif
crypt_reencrypt_info LUKS2_reencrypt_get_params(struct luks2_hdr *hdr,
struct crypt_params_reencrypt *params)
{
crypt_reencrypt_info ri;
int digest;
uint32_t version;
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_NONE || ri == CRYPT_REENCRYPT_INVALID || !params)
return ri;
digest = LUKS2_digest_by_keyslot(hdr, LUKS2_find_keyslot(hdr, "reencrypt"));
if (digest < 0 && digest != -ENOENT)
return CRYPT_REENCRYPT_INVALID;
/*
* In case there's an old "online-reencrypt" requirement or reencryption
* keyslot digest is missing inform caller reencryption metadata requires repair.
*/
if (!LUKS2_config_get_reencrypt_version(hdr, &version) &&
(version < 2 || digest == -ENOENT)) {
params->flags |= CRYPT_REENCRYPT_REPAIR_NEEDED;
return ri;
}
params->mode = reencrypt_mode(hdr);
params->direction = reencrypt_direction(hdr);
params->resilience = reencrypt_resilience_type(hdr);

View File

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

View File

@@ -123,7 +123,7 @@ static json_object *json_segment_get_flags(json_object *jobj_segment)
return jobj;
}
static bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
{
int r, i;
json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment);
@@ -410,3 +410,23 @@ json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)
return jobj_segment;
}
/* compares key characteristics of both segments */
bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2)
{
const char *type = json_segment_type(jobj_segment_1);
const char *type2 = json_segment_type(jobj_segment_2);
if (!type || !type2)
return false;
if (strcmp(type, type2))
return false;
if (!strcmp(type, "crypt"))
return (json_segment_get_sector_size(jobj_segment_1) == json_segment_get_sector_size(jobj_segment_2) &&
!strcmp(json_segment_get_cipher(jobj_segment_1),
json_segment_get_cipher(jobj_segment_2)));
return true;
}

View File

@@ -3955,21 +3955,6 @@ out:
return r;
}
static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks)
{
int r;
struct volume_key *vk = vks;
while (vk) {
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk));
if (r < 0)
return r;
vk = crypt_volume_key_next(vk);
}
return 0;
}
/* See fixmes in _open_and_activate_luks2 */
int update_reencryption_flag(struct crypt_device *cd, int enable, bool commit);
@@ -4017,6 +4002,22 @@ out:
return r < 0 ? r : keyslot;
}
#if USE_LUKS2_REENCRYPTION
static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks)
{
int r;
struct volume_key *vk = vks;
while (vk) {
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk));
if (r < 0)
return r;
vk = crypt_volume_key_next(vk);
}
return 0;
}
static int _open_all_keys(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -4131,6 +4132,12 @@ static int _open_and_activate_reencrypt_device(struct crypt_device *cd,
keyslot = r;
}
if (r >= 0) {
r = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
if (r < 0)
goto out;
}
log_dbg(cd, "Entering clean reencryption state mode.");
if (r >= 0)
@@ -4158,8 +4165,9 @@ static int _open_and_activate_luks2(struct crypt_device *cd,
uint32_t flags)
{
crypt_reencrypt_info ri;
int r;
int r, rv;
struct luks2_hdr *hdr = &cd->u.luks2.hdr;
struct volume_key *vks = NULL;
ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID)
@@ -4169,15 +4177,45 @@ static int _open_and_activate_luks2(struct crypt_device *cd,
if (name)
r = _open_and_activate_reencrypt_device(cd, hdr, keyslot, name, passphrase,
passphrase_size, flags);
else
else {
r = _open_all_keys(cd, hdr, keyslot, passphrase,
passphrase_size, flags, NULL);
passphrase_size, flags, &vks);
if (r < 0)
return r;
rv = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
crypt_free_volume_key(vks);
if (rv < 0)
return rv;
}
} else
r = _open_and_activate(cd, keyslot, name, passphrase,
passphrase_size, flags);
return r;
}
#else
static int _open_and_activate_luks2(struct crypt_device *cd,
int keyslot,
const char *name,
const char *passphrase,
size_t passphrase_size,
uint32_t flags)
{
crypt_reencrypt_info ri;
ri = LUKS2_reencrypt_status(&cd->u.luks2.hdr);
if (ri == CRYPT_REENCRYPT_INVALID)
return -EINVAL;
if (ri > CRYPT_REENCRYPT_NONE) {
log_err(cd, _("This operation is not supported for this device type."));
return -ENOTSUP;
}
return _open_and_activate(cd, keyslot, name, passphrase, passphrase_size, flags);
}
#endif
static int _activate_by_passphrase(struct crypt_device *cd,
const char *name,

View File

@@ -830,6 +830,13 @@ are fixable. This command will only change the LUKS header, not
any key-slot data. You may enforce LUKS version by adding \-\-type
option.
It also repairs (upgrades) LUKS2 reencryption metadata by adding
metadata digest that protects it against malicious changes.
If LUKS2 reencryption was interrupted in the middle of writting
reencryption segment the repair command can be used to perform
reencryption recovery so that reencryption can continue later.
\fBWARNING:\fR Always create a binary backup of the original
header before calling this command.
.PP
@@ -1568,7 +1575,7 @@ sudo cryptsetup luksAddKey --key-slot 5 /dev/sdX
Example 3: Create LUKS header backup and save it to file.
sudo cryptsetup luksHeaderBackup /dev/sdX --header-backup-file /var/tmp/NameOfBackupFile
.TP
Example 4: Open LUKS contaner on /dev/sdX and map it to sdX_crypt.
Example 4: Open LUKS container on /dev/sdX and map it to sdX_crypt.
sudo cryptsetup open /dev/sdX sdX_crypt
.TP
.B WARNING: The command in example 5 will erase all key slots.

View File

@@ -37,6 +37,7 @@ lib/luks2/luks2_keyslot_luks2.c
lib/luks2/luks2_keyslot_reenc.c
lib/luks2/luks2_luks1_convert.c
lib/luks2/luks2_reencrypt.c
lib/luks2/luks2_reencrypt_digest.c
lib/luks2/luks2_segment.c
lib/luks2/luks2_token.c
lib/luks2/luks2_token_keyring.c

1179
po/es.po

File diff suppressed because it is too large Load Diff

285
po/sr.po
View File

@@ -4,10 +4,10 @@
# Мирослав Николић <miroslavnikolic@rocketmail.com>, 20142021.
msgid ""
msgstr ""
"Project-Id-Version: cryptsetup-2.4.1-rc0\n"
"Project-Id-Version: cryptsetup-2.4.2-rc0\n"
"Report-Msgid-Bugs-To: dm-crypt@saout.de\n"
"POT-Creation-Date: 2021-08-30 12:40+0200\n"
"PO-Revision-Date: 2021-10-10 11:10+0200\n"
"POT-Creation-Date: 2021-11-11 19:08+0100\n"
"PO-Revision-Date: 2021-12-11 19:03+0200\n"
"Last-Translator: Мирослав Николић <miroslavnikolic@rocketmail.com>\n"
"Language-Team: Serbian <(nothing)>\n"
"Language: sr\n"
@@ -34,45 +34,45 @@ msgstr "Затражена одложена заставица није подр
msgid "DM-UUID for device %s was truncated."
msgstr "ДМ-УЈИБ за уређај „%s“ је скраћен."
#: lib/libdevmapper.c:1570
#: lib/libdevmapper.c:1567
msgid "Unknown dm target type."
msgstr "Непозната врста „dm“ мете."
#: lib/libdevmapper.c:1691 lib/libdevmapper.c:1696 lib/libdevmapper.c:1760
#: lib/libdevmapper.c:1763
#: lib/libdevmapper.c:1688 lib/libdevmapper.c:1693 lib/libdevmapper.c:1757
#: lib/libdevmapper.c:1760
msgid "Requested dm-crypt performance options are not supported."
msgstr "Затражене опције перформанси дм-шифровања нису подржане."
#: lib/libdevmapper.c:1703 lib/libdevmapper.c:1707
#: lib/libdevmapper.c:1700 lib/libdevmapper.c:1704
msgid "Requested dm-verity data corruption handling options are not supported."
msgstr "Затражене опције рада оштећених података дм-веритија нису подржане."
#: lib/libdevmapper.c:1711
#: lib/libdevmapper.c:1708
msgid "Requested dm-verity FEC options are not supported."
msgstr "Затражене „dm-verity FEC“ опције нису подржане."
#: lib/libdevmapper.c:1715
#: lib/libdevmapper.c:1712
msgid "Requested data integrity options are not supported."
msgstr "Затражене опције целовитости података нису подржане."
#: lib/libdevmapper.c:1717
#: lib/libdevmapper.c:1714
msgid "Requested sector_size option is not supported."
msgstr "Затражене опције величине одељка нису подржане."
#: lib/libdevmapper.c:1722 lib/libdevmapper.c:1726
#: lib/libdevmapper.c:1719 lib/libdevmapper.c:1723
msgid "Requested automatic recalculation of integrity tags is not supported."
msgstr "Затражене опције самосталног прерачунавања ознака целовитости нису подржане."
#: lib/libdevmapper.c:1730 lib/libdevmapper.c:1766 lib/libdevmapper.c:1769
#: lib/libdevmapper.c:1727 lib/libdevmapper.c:1763 lib/libdevmapper.c:1766
#: lib/luks2/luks2_json_metadata.c:2204
msgid "Discard/TRIM is not supported."
msgstr "Одбацивање/ОДСЕЦАЊЕ није подржано."
#: lib/libdevmapper.c:1734
#: lib/libdevmapper.c:1731
msgid "Requested dm-integrity bitmap mode is not supported."
msgstr "Затражени режим битмапе дм-целовитости није подржан."
#: lib/libdevmapper.c:2708
#: lib/libdevmapper.c:2705
#, c-format
msgid "Failed to query dm-%s segment."
msgstr "Нисам успео да пропитам „dm-%s“ подеок."
@@ -136,7 +136,7 @@ msgstr "Ова радња је подржана само за ЛУКС уређ
msgid "This operation is supported only for LUKS2 device."
msgstr "Ова радња је подржана само за ЛУКС2 уређај."
#: lib/setup.c:420 lib/luks2/luks2_reencrypt.c:2436
#: lib/setup.c:420 lib/luks2/luks2_reencrypt.c:2440
msgid "All key slots full."
msgstr "Сви утори кључева су пуни."
@@ -199,7 +199,7 @@ msgstr "УЈИБ није подржан за ову врсту криптогр
msgid "Detached metadata device is not supported for this crypt type."
msgstr "Откачени уређај метаподатака није подржан за ову врсту криптографије."
#: lib/setup.c:1552 lib/setup.c:1754 lib/luks2/luks2_reencrypt.c:2397
#: lib/setup.c:1552 lib/setup.c:1754 lib/luks2/luks2_reencrypt.c:2401
#: src/cryptsetup.c:1358 src/cryptsetup.c:3723
msgid "Unsupported encryption sector size."
msgstr "Неподржана величина одељка шифровања."
@@ -249,7 +249,7 @@ msgid "WARNING: LUKS2 keyslots area size changed to %<PRIu64> bytes.\n"
msgstr "УПОЗОРЕЊЕ: Величина области ЛУКС2 утора кључева је промењена на %<PRIu64> бајта.\n"
#: lib/setup.c:1915 lib/utils_device.c:909 lib/luks1/keyencryption.c:255
#: lib/luks2/luks2_reencrypt.c:2447 lib/luks2/luks2_reencrypt.c:3484
#: lib/luks2/luks2_reencrypt.c:2451 lib/luks2/luks2_reencrypt.c:3488
#, c-format
msgid "Device %s is too small."
msgstr "Уређај „%s“ је премали."
@@ -326,8 +326,8 @@ msgstr "Затражена је непозната врста „%s“ крип
msgid "Unsupported parameters on device %s."
msgstr "Неподржани параметри на уређају „%s“."
#: lib/setup.c:2622 lib/setup.c:2708 lib/luks2/luks2_reencrypt.c:2499
#: lib/luks2/luks2_reencrypt.c:2843
#: lib/setup.c:2622 lib/setup.c:2708 lib/luks2/luks2_reencrypt.c:2503
#: lib/luks2/luks2_reencrypt.c:2847
#, c-format
msgid "Mismatching parameters on device %s."
msgstr "Неодговарајући параметри на уређају „%s“."
@@ -337,7 +337,7 @@ msgid "Crypt devices mismatch."
msgstr "Криптографски уређаји се не поклапају."
#: lib/setup.c:2765 lib/setup.c:2770 lib/luks2/luks2_reencrypt.c:2143
#: lib/luks2/luks2_reencrypt.c:3251
#: lib/luks2/luks2_reencrypt.c:3255
#, c-format
msgid "Failed to reload device %s."
msgstr "Нисам успео поново да учитам уређај „%s“."
@@ -349,7 +349,7 @@ msgid "Failed to suspend device %s."
msgstr "Нисам успео да обуставим уређај „%s“."
#: lib/setup.c:2788 lib/luks2/luks2_reencrypt.c:2128
#: lib/luks2/luks2_reencrypt.c:3186 lib/luks2/luks2_reencrypt.c:3255
#: lib/luks2/luks2_reencrypt.c:3190 lib/luks2/luks2_reencrypt.c:3259
#, c-format
msgid "Failed to resume device %s."
msgstr "Нисам успео да наставим са уређајем „%s“."
@@ -444,11 +444,11 @@ msgid "Reencryption in-progress. Cannot activate device."
msgstr "Поновно шифровање је у току. Не могу да активирам уређај."
#: lib/setup.c:4091 lib/luks2/luks2_json_metadata.c:2287
#: lib/luks2/luks2_reencrypt.c:2942
#: lib/luks2/luks2_reencrypt.c:2946
msgid "Failed to get reencryption lock."
msgstr "Нисам успео да добавим закључавање поновног шифровања."
#: lib/setup.c:4104 lib/luks2/luks2_reencrypt.c:2961
#: lib/setup.c:4104 lib/luks2/luks2_reencrypt.c:2965
msgid "LUKS2 reencryption recovery failed."
msgstr "Опоравак ЛУКС2 поновног шифровања није успело."
@@ -551,7 +551,7 @@ msgstr "Нисам успео да доделим утор кључа „%d“
msgid "Kernel keyring is not supported by the kernel."
msgstr "Привезак кључева кернела није подржан кернелом."
#: lib/setup.c:6161 lib/luks2/luks2_reencrypt.c:3058
#: lib/setup.c:6161 lib/luks2/luks2_reencrypt.c:3062
#, c-format
msgid "Failed to read passphrase from keyring (error %d)."
msgstr "Нисам успео да прочитам пропусну реч из привеска кључа (грешка %d)."
@@ -1131,6 +1131,16 @@ msgstr "Нађох неочекивану врсту уноса метапода
msgid "Unexpected metadata entry value '%u' found when parsing external key."
msgstr "Нађох неочекивану вредност уноса метаподатака „%u“ приликом обраде спољног кључа."
#: lib/bitlk/bitlk.c:950
#, c-format
msgid "Unsupported BEK metadata version %<PRIu32>"
msgstr "Неподржани „BEK“ метаподаци издање %<PRIu32>"
#: lib/bitlk/bitlk.c:955
#, c-format
msgid "Unexpected BEK metadata size %<PRIu32> does not match BEK file length"
msgstr "Неочекивана величина „BEK“ метаподатака %<PRIu32> не одговара величини „BEK“ датотеке"
#: lib/bitlk/bitlk.c:980
msgid "Unexpected metadata entry found when parsing startup key."
msgstr "Нађох неочекивану врсту уноса метаподатака приликом обраде кључа почретања."
@@ -1315,17 +1325,17 @@ msgstr "Кернел не подржава поравнање фиксних м
msgid "Kernel refuses to activate insecure recalculate option (see legacy activation options to override)."
msgstr "Кернел одбија да покрене небезбедну опцију поновног израчунавања (видите старе опције покретања да избегнете ово)."
#: lib/luks2/luks2_disk_metadata.c:381 lib/luks2/luks2_json_metadata.c:973
#: lib/luks2/luks2_disk_metadata.c:393 lib/luks2/luks2_json_metadata.c:973
#: lib/luks2/luks2_json_metadata.c:1268
#, c-format
msgid "Failed to acquire write lock on device %s."
msgstr "Нисам успео да остварим закључавање писања на уређају „%s“."
#: lib/luks2/luks2_disk_metadata.c:390
#: lib/luks2/luks2_disk_metadata.c:402
msgid "Detected attempt for concurrent LUKS2 metadata update. Aborting operation."
msgstr "Открих покушај истовременог ажурирања ЛУКС2 метаподатака. Прекидам."
#: lib/luks2/luks2_disk_metadata.c:689 lib/luks2/luks2_disk_metadata.c:710
#: lib/luks2/luks2_disk_metadata.c:701 lib/luks2/luks2_disk_metadata.c:722
msgid ""
"Device contains ambiguous signatures, cannot auto-recover LUKS2.\n"
"Please run \"cryptsetup repair\" for recovery."
@@ -1400,7 +1410,7 @@ msgstr ""
msgid "Ignored unknown flag %s."
msgstr "Занемарена непозната заставица „%s“."
#: lib/luks2/luks2_json_metadata.c:2054 lib/luks2/luks2_reencrypt.c:1840
#: lib/luks2/luks2_json_metadata.c:2054 lib/luks2/luks2_reencrypt.c:1843
#, c-format
msgid "Missing key for dm-crypt segment %u"
msgstr "Недостаје кључ за „dm-crypt“ подеок %u"
@@ -1421,7 +1431,7 @@ msgstr "Неподржано подешавање целовитости уре
msgid "Reencryption in-progress. Cannot deactivate device."
msgstr "Поновно шифровање је у току. Не могу да деактивирам уређај."
#: lib/luks2/luks2_json_metadata.c:2296 lib/luks2/luks2_reencrypt.c:3296
#: lib/luks2/luks2_json_metadata.c:2296 lib/luks2/luks2_reencrypt.c:3300
#, c-format
msgid "Failed to replace suspended device %s with dm-error target."
msgstr "Нисам успео да заменим обустављени уређај „%s“ са метом „dm-error“."
@@ -1455,7 +1465,7 @@ msgstr "Отварање утора кључа није успело."
msgid "Cannot use %s-%s cipher for keyslot encryption."
msgstr "Не могу користити шифрер „%s-%s“ за шифровање утора кључа."
#: lib/luks2/luks2_keyslot_luks2.c:483
#: lib/luks2/luks2_keyslot_luks2.c:485
msgid "No space for new keyslot."
msgstr "Нема простора за нови утор кључа."
@@ -1530,7 +1540,7 @@ msgstr "Неподржан режим гипкости „%s“"
#: lib/luks2/luks2_reencrypt.c:1259 lib/luks2/luks2_reencrypt.c:1414
#: lib/luks2/luks2_reencrypt.c:1497 lib/luks2/luks2_reencrypt.c:1531
#: lib/luks2/luks2_reencrypt.c:3136
#: lib/luks2/luks2_reencrypt.c:3140
msgid "Failed to initialize old segment storage wrapper."
msgstr "Нисам успео да покренем старог увијача смештаја подеока."
@@ -1542,7 +1552,7 @@ msgstr "Нисам успео да покренем новог увијача с
msgid "Failed to read checksums for current hotzone."
msgstr "Нисам успео да прочитам суму провере за текућу врућу зону."
#: lib/luks2/luks2_reencrypt.c:1448 lib/luks2/luks2_reencrypt.c:3144
#: lib/luks2/luks2_reencrypt.c:1448 lib/luks2/luks2_reencrypt.c:3148
#, c-format
msgid "Failed to read hotzone area starting at %<PRIu64>."
msgstr "Нисам успео да прочитам област вруће зоне са почетком на %<PRIu64>."
@@ -1581,138 +1591,142 @@ msgstr "Нисам успео да учитам ново мапирање за
msgid "Failed to refresh reencryption devices stack."
msgstr "Нисам успео да освежим спремник уређаја поновног шифровања."
#: lib/luks2/luks2_reencrypt.c:2305
#: lib/luks2/luks2_reencrypt.c:2309
msgid "Failed to set new keyslots area size."
msgstr "Нисам успео да подесим нову величину области утора кључа."
#: lib/luks2/luks2_reencrypt.c:2409
#: lib/luks2/luks2_reencrypt.c:2413
#, c-format
msgid "Data shift is not aligned to requested encryption sector size (%<PRIu32> bytes)."
msgstr "Помак података није поравнат на захтевану величину одељка шифровања (%<PRIu32> бајта)."
#: lib/luks2/luks2_reencrypt.c:2430
#: lib/luks2/luks2_reencrypt.c:2434
#, c-format
msgid "Data device is not aligned to requested encryption sector size (%<PRIu32> bytes)."
msgstr "Уређај података није поравнат на захтевану величину одељка шифровања (%<PRIu32> бајта)."
#: lib/luks2/luks2_reencrypt.c:2451
#: lib/luks2/luks2_reencrypt.c:2455
#, c-format
msgid "Data shift (%<PRIu64> sectors) is less than future data offset (%<PRIu64> sectors)."
msgstr "Помак података (%<PRIu64> одељка) је мањи од будућег помераја података (%<PRIu64> одељка)."
#: lib/luks2/luks2_reencrypt.c:2457 lib/luks2/luks2_reencrypt.c:2885
#: lib/luks2/luks2_reencrypt.c:2906
#: lib/luks2/luks2_reencrypt.c:2461 lib/luks2/luks2_reencrypt.c:2889
#: lib/luks2/luks2_reencrypt.c:2910
#, c-format
msgid "Failed to open %s in exclusive mode (already mapped or mounted)."
msgstr "Нисам успео да отворим „%s“ у искључивом режиму (већ мапиран или прикачен)."
#: lib/luks2/luks2_reencrypt.c:2625
#: lib/luks2/luks2_reencrypt.c:2629
msgid "Device not marked for LUKS2 reencryption."
msgstr "Уређај није означен за ЛУКС2 поновно шифровање."
#: lib/luks2/luks2_reencrypt.c:2631 lib/luks2/luks2_reencrypt.c:3411
#: lib/luks2/luks2_reencrypt.c:2635 lib/luks2/luks2_reencrypt.c:3415
msgid "Failed to load LUKS2 reencryption context."
msgstr "Нисам успео да учитам контекст ЛУКС2 поновног шифровања."
#: lib/luks2/luks2_reencrypt.c:2711
#: lib/luks2/luks2_reencrypt.c:2715
msgid "Failed to get reencryption state."
msgstr "Нисам успео да добавим стање поновног шифровања."
#: lib/luks2/luks2_reencrypt.c:2715
#: lib/luks2/luks2_reencrypt.c:2719
msgid "Device is not in reencryption."
msgstr "Уређај није у поновном шифровању."
#: lib/luks2/luks2_reencrypt.c:2722
#: lib/luks2/luks2_reencrypt.c:2726
msgid "Reencryption process is already running."
msgstr "Процес поновног шифровања је већ покренут."
#: lib/luks2/luks2_reencrypt.c:2724
#: lib/luks2/luks2_reencrypt.c:2728
msgid "Failed to acquire reencryption lock."
msgstr "Нисам успео да остварим закључавање поновног шифровања."
#: lib/luks2/luks2_reencrypt.c:2742
#: lib/luks2/luks2_reencrypt.c:2746
msgid "Cannot proceed with reencryption. Run reencryption recovery first."
msgstr "Не могу да наставим са поновним шифровањем. Прво покрените опоравак поновног шифровања."
#: lib/luks2/luks2_reencrypt.c:2856
#: lib/luks2/luks2_reencrypt.c:2860
msgid "Active device size and requested reencryption size don't match."
msgstr "Активна величина уређаја и величина затраженог поновног шифровања не одговарају."
#: lib/luks2/luks2_reencrypt.c:2870
#: lib/luks2/luks2_reencrypt.c:2874
msgid "Illegal device size requested in reencryption parameters."
msgstr "Неисправна величина уређаја је затражена у параметрима поновног шифровања."
#: lib/luks2/luks2_reencrypt.c:2940
#: lib/luks2/luks2_reencrypt.c:2944
msgid "Reencryption in-progress. Cannot perform recovery."
msgstr "Поновно шифровање је у току. Не могу да обавим опоравак."
#: lib/luks2/luks2_reencrypt.c:3012
#: lib/luks2/luks2_reencrypt.c:3016
msgid "LUKS2 reencryption already initialized in metadata."
msgstr "ЛУКС2 поновно шифровање је већ покренуто у метаподацима."
#: lib/luks2/luks2_reencrypt.c:3019
#: lib/luks2/luks2_reencrypt.c:3023
msgid "Failed to initialize LUKS2 reencryption in metadata."
msgstr "Нисам успео да покренем ЛУКС2 поновно шифровање у метаподацима."
#: lib/luks2/luks2_reencrypt.c:3110
#: lib/luks2/luks2_reencrypt.c:3114
msgid "Failed to set device segments for next reencryption hotzone."
msgstr "Нисам успео да поставим подеоке уређаја за следећу врућу зону поновног шифровања."
#: lib/luks2/luks2_reencrypt.c:3152
#: lib/luks2/luks2_reencrypt.c:3156
msgid "Failed to write reencryption resilience metadata."
msgstr "Нисам успео да запишем метаподатаке гипкости поновног шифровања."
#: lib/luks2/luks2_reencrypt.c:3159
#: lib/luks2/luks2_reencrypt.c:3163
msgid "Decryption failed."
msgstr "Дешифровање није успело."
#: lib/luks2/luks2_reencrypt.c:3164
#: lib/luks2/luks2_reencrypt.c:3168
#, c-format
msgid "Failed to write hotzone area starting at %<PRIu64>."
msgstr "Нисам успео да запишем област вруће зоне са почетком на %<PRIu64>."
#: lib/luks2/luks2_reencrypt.c:3169
#: lib/luks2/luks2_reencrypt.c:3173
msgid "Failed to sync data."
msgstr "Нисам успео да усагласим податке."
#: lib/luks2/luks2_reencrypt.c:3177
#: lib/luks2/luks2_reencrypt.c:3181
msgid "Failed to update metadata after current reencryption hotzone completed."
msgstr "Нисам успео да освежим метаподатке након тренутно завршеног поновног шифровања вруће зоне."
#: lib/luks2/luks2_reencrypt.c:3244
#: lib/luks2/luks2_reencrypt.c:3248
msgid "Failed to write LUKS2 metadata."
msgstr "Нисам успео да запишем ЛУКС2 метаподатке."
#: lib/luks2/luks2_reencrypt.c:3267
#: lib/luks2/luks2_reencrypt.c:3271
msgid "Failed to wipe backup segment data."
msgstr "Нисам успео да очистим податке подеока резерве."
#: lib/luks2/luks2_reencrypt.c:3280
#: lib/luks2/luks2_reencrypt.c:3284
msgid "Failed to disable reencryption requirement flag."
msgstr "Нисам успео да искључим заставицу захтева поновног шифровања."
#: lib/luks2/luks2_reencrypt.c:3288
#: lib/luks2/luks2_reencrypt.c:3292
#, c-format
msgid "Fatal error while reencrypting chunk starting at %<PRIu64>, %<PRIu64> sectors long."
msgstr "Кобна грешка приликом поновног шифровања комада који почиње на %<PRIu64>, %<PRIu64> подеока дуг."
#: lib/luks2/luks2_reencrypt.c:3297
#: lib/luks2/luks2_reencrypt.c:3296
msgid "Online reencryption failed."
msgstr "Поновно шифровање на мрежи није успело."
#: lib/luks2/luks2_reencrypt.c:3301
msgid "Do not resume the device unless replaced with error target manually."
msgstr "Не наставља са уређајем осим ако није ручно замењен метом грешке."
#: lib/luks2/luks2_reencrypt.c:3349
#: lib/luks2/luks2_reencrypt.c:3353
msgid "Cannot proceed with reencryption. Unexpected reencryption status."
msgstr "Не могу да наставим са поновним шифровањем. Неочекивано стање поновног шифровања."
#: lib/luks2/luks2_reencrypt.c:3355
#: lib/luks2/luks2_reencrypt.c:3359
msgid "Missing or invalid reencrypt context."
msgstr "Недостаје или неисправан контекст поновног шифровања."
#: lib/luks2/luks2_reencrypt.c:3362
#: lib/luks2/luks2_reencrypt.c:3366
msgid "Failed to initialize reencryption device stack."
msgstr "Нисам успео да покренем поновно шифровање спремника уређаја."
#: lib/luks2/luks2_reencrypt.c:3381 lib/luks2/luks2_reencrypt.c:3424
#: lib/luks2/luks2_reencrypt.c:3385 lib/luks2/luks2_reencrypt.c:3428
msgid "Failed to update reencryption context."
msgstr "Нисам успео да освежим контекст поновног шифровања."
@@ -2177,6 +2191,15 @@ msgstr "Привремена датотека заглавља „%s“ већ
msgid "Cannot create temporary header file %s."
msgstr "Не могу да направим привремену датотеку заглавља „%s“."
#: src/cryptsetup.c:2975
msgid "LUKS2 metadata size is larger than data shift value."
msgstr "Величина ЛУКС2 метаподатака је већа од вредности помака података."
#: src/cryptsetup.c:3007
#, c-format
msgid "Failed to place new header at head of device %s."
msgstr "Нисам успео да ставим ново заглавље на главу уређаја „%s“."
#: src/cryptsetup.c:3018
#, c-format
msgid "%s/%s is now active and ready for online encryption.\n"
@@ -2910,6 +2933,10 @@ msgstr "Не могу да запишем датотеку дневника по
msgid "Cannot read reencryption log file."
msgstr "Не могу да прочитам датотеку дневника поновног шифровања."
#: src/cryptsetup_reencrypt.c:353
msgid "Wrong log format."
msgstr "Погрешан формат дневника."
#: src/cryptsetup_reencrypt.c:380
#, c-format
msgid "Log file %s exists, resuming reencryption.\n"
@@ -3062,112 +3089,134 @@ msgstr "Опција „--uuid“ је дозвољена само заједн
msgid "Invalid luks type. Use one of these: 'luks', 'luks1' or 'luks2'."
msgstr "Неисправна лукс врста. Користите: „luks“, „luks1“ или „luks2“."
#: src/utils_tools.c:126
#: src/utils_tools.c:119
msgid ""
"\n"
"WARNING!\n"
"========\n"
msgstr ""
"\n"
"УПОЗОРЕЊЕ!\n"
"========\n"
#. TRANSLATORS: User must type "YES" (in capital letters), do not translate this word.
#: src/utils_tools.c:121
#, c-format
msgid ""
"%s\n"
"\n"
"Are you sure? (Type 'yes' in capital letters): "
msgstr ""
"%s\n"
"\n"
"Да ли сте сигурни? (Упишите „yes“ великим словима): "
#: src/utils_tools.c:127
msgid "Error reading response from terminal."
msgstr "Грешка читања одговора из терминала."
#: src/utils_tools.c:158
#: src/utils_tools.c:159
msgid "Command successful."
msgstr "Наредба је успела."
#: src/utils_tools.c:166
#: src/utils_tools.c:167
msgid "wrong or missing parameters"
msgstr "погрешни или недостајући параметри"
#: src/utils_tools.c:168
#: src/utils_tools.c:169
msgid "no permission or bad passphrase"
msgstr "нема овлашћења или је лоша пропусна реч"
#: src/utils_tools.c:170
#: src/utils_tools.c:171
msgid "out of memory"
msgstr "нема више меморије"
#: src/utils_tools.c:172
#: src/utils_tools.c:173
msgid "wrong device or file specified"
msgstr "наведен је погрешан уређај или датотека"
#: src/utils_tools.c:174
#: src/utils_tools.c:175
msgid "device already exists or device is busy"
msgstr "уређај већ постоји или је заузет"
#: src/utils_tools.c:176
#: src/utils_tools.c:177
msgid "unknown error"
msgstr "непозната грешка"
#: src/utils_tools.c:178
#: src/utils_tools.c:179
#, c-format
msgid "Command failed with code %i (%s)."
msgstr "Наредба није успела са кодом %i (%s)."
#: src/utils_tools.c:256
#: src/utils_tools.c:257
#, c-format
msgid "Key slot %i created."
msgstr "Утор кључа „%i“ је направљен."
#: src/utils_tools.c:258
#: src/utils_tools.c:259
#, c-format
msgid "Key slot %i unlocked."
msgstr "Утор кључа „%i“ је откључан."
#: src/utils_tools.c:260
#: src/utils_tools.c:261
#, c-format
msgid "Key slot %i removed."
msgstr "Утор кључа „%i“ је уклоњен."
#: src/utils_tools.c:269
#: src/utils_tools.c:270
#, c-format
msgid "Token %i created."
msgstr "Скупина „%i“ је направљена."
#: src/utils_tools.c:271
#: src/utils_tools.c:272
#, c-format
msgid "Token %i removed."
msgstr "Скупина „%i“ је уклоњена."
#: src/utils_tools.c:281
#: src/utils_tools.c:282
msgid "No token could be unlocked with this PIN."
msgstr "Ниједна скупина неће бити откључана овим ПИН-ом."
#: src/utils_tools.c:283
#: src/utils_tools.c:284
#, c-format
msgid "Token %i requires PIN."
msgstr "Скупина „%i“ захтева ПИН."
#: src/utils_tools.c:285
#: src/utils_tools.c:286
#, c-format
msgid "Token (type %s) requires PIN."
msgstr "Скупина (врста „%s“) захтева ПИН."
#: src/utils_tools.c:288
#: src/utils_tools.c:289
#, c-format
msgid "Token %i cannot unlock assigned keyslot(s) (wrong keyslot passphrase)."
msgstr "Скупина „%i“ не може да откључа додељени утор кључа (погрешна лозинка)."
#: src/utils_tools.c:290
#: src/utils_tools.c:291
#, c-format
msgid "Token (type %s) cannot unlock assigned keyslot(s) (wrong keyslot passphrase)."
msgstr "Скупина (врста „%s“) не може да откључа додељени утор кључа (погрешна лозинка)."
#: src/utils_tools.c:293
#: src/utils_tools.c:294
#, c-format
msgid "Token %i requires additional missing resource."
msgstr "Скупина „%i“ захтева додтни ресурс који недостаје."
#: src/utils_tools.c:295
#: src/utils_tools.c:296
#, c-format
msgid "Token (type %s) requires additional missing resource."
msgstr "Скупина (врста „%s“) захтева додтни ресурс који недостаје."
#: src/utils_tools.c:298
#: src/utils_tools.c:299
#, c-format
msgid "No usable token (type %s) is available."
msgstr "Нема доступне употребљиве скупине (врста „%s“)."
#: src/utils_tools.c:300
#: src/utils_tools.c:301
msgid "No usable token is available."
msgstr "Нема доступне употребљиве скупине."
#: src/utils_tools.c:462
#: src/utils_tools.c:463
msgid ""
"\n"
"Wipe interrupted."
@@ -3175,7 +3224,7 @@ msgstr ""
"\n"
"Брисање је прекинуто."
#: src/utils_tools.c:491
#: src/utils_tools.c:492
msgid ""
"\n"
"Reencryption interrupted."
@@ -3183,6 +3232,26 @@ msgstr ""
"\n"
"Поновно шифровање је прекинуто."
#: src/utils_tools.c:511
#, c-format
msgid "Cannot read keyfile %s."
msgstr "Не могу да прочитам датотеку кључа „%s“."
#: src/utils_tools.c:516
#, c-format
msgid "Cannot read %d bytes from keyfile %s."
msgstr "Не могу да прочитам %d бајта из датотеке кључа „%s“."
#: src/utils_tools.c:541
#, c-format
msgid "Cannot open keyfile %s for write."
msgstr "Не могу да отворим датотеку кључа „%s“ за упис."
#: src/utils_tools.c:548
#, c-format
msgid "Cannot write to keyfile %s."
msgstr "Не могу да пишем у датотеку кључа „%s“."
#: src/utils_password.c:41 src/utils_password.c:74
#, c-format
msgid "Cannot check password quality: %s"
@@ -3236,26 +3305,6 @@ msgstr "Нема доступног кључа са овом пропусном
msgid "No usable keyslot is available."
msgstr "Нема доступног употребљивог утора кључа."
#: src/utils_password.c:335
#, c-format
msgid "Cannot read keyfile %s."
msgstr "Не могу да прочитам датотеку кључа „%s“."
#: src/utils_password.c:340
#, c-format
msgid "Cannot read %d bytes from keyfile %s."
msgstr "Не могу да прочитам %d бајта из датотеке кључа „%s“."
#: src/utils_password.c:365
#, c-format
msgid "Cannot open keyfile %s for write."
msgstr "Не могу да отворим датотеку кључа „%s“ за упис."
#: src/utils_password.c:372
#, c-format
msgid "Cannot write to keyfile %s."
msgstr "Не могу да пишем у датотеку кључа „%s“."
#: src/utils_luks2.c:47
#, c-format
msgid "Failed to open file %s in read-only mode."
@@ -3323,6 +3372,16 @@ msgstr "Уређај „%s“ је у употреби. Не могу да на
msgid "Failed to open file %s in read/write mode."
msgstr "Нисам успео да отворим датотеку „%s“ у режиму читања/писања."
#: src/utils_blockdev.c:294
#, c-format
msgid "Existing '%s' partition signature on device %s will be wiped."
msgstr "Постојећи потпис „%s“ партиције на уређају „%s“ биће обрисан."
#: src/utils_blockdev.c:297
#, c-format
msgid "Existing '%s' superblock signature on device %s will be wiped."
msgstr "Постојећи потпис „%s“ суперблока на уређају „%s“ биће обрисан."
#: src/utils_blockdev.c:300
msgid "Failed to wipe device signature."
msgstr "Нисам успео да обришем потпис уређаја."
@@ -4033,12 +4092,6 @@ msgstr "Грешка потврђивања идентитета јавног к
#~ msgid "Type of LUKS metadata: luks1, luks2"
#~ msgstr "Врста ЛУКС метаподатака: luks1, luks2"
#~ msgid "Existing '%s' partition signature (offset: %<PRIi64> bytes) on device %s will be wiped."
#~ msgstr "Постојећи „%s“ потпис партиције (померај: %<PRIi64> бајта) на уређају „%s“ биће обрисан."
#~ msgid "Existing '%s' superblock signature (offset: %<PRIi64> bytes) on device %s will be wiped."
#~ msgstr "Постојећи „%s“ потпис суперблока (померај: %<PRIi64> бајта) на уређају „%s“ биће обрисан."
#~ msgid "WARNING: Locking directory %s/%s is missing!\n"
#~ msgstr "УПОЗОРЕЊЕ: Директоријум закључавања „%s/%s“ недостаје!\n"

3677
po/sv.po

File diff suppressed because it is too large Load Diff

View File

@@ -1172,24 +1172,63 @@ static int set_keyslot_params(struct crypt_device *cd, int keyslot)
return crypt_set_pbkdf_type(cd, &pbkdf);
}
static int _do_luks2_reencrypt_recovery(struct crypt_device *cd)
static int reencrypt_metadata_repair(struct crypt_device *cd)
{
char *password;
size_t passwordLen;
int r;
struct crypt_params_reencrypt params = {
.flags = CRYPT_REENCRYPT_REPAIR_NEEDED
};
if (!ARG_SET(OPT_BATCH_MODE_ID) &&
!yesDialog(_("Unprotected LUKS2 reencryption metadata detected. "
"Please verify the reencryption operation is desirable (see luksDump output)\n"
"and continue (upgrade metadata) only if you acknowledge the operation as genuine."),
_("Operation aborted.\n")))
return -EINVAL;
r = tools_get_key(_("Enter passphrase to protect and uppgrade reencryption metadata: "),
&password, &passwordLen, ARG_UINT64(OPT_KEYFILE_OFFSET_ID),
ARG_UINT32(OPT_KEYFILE_SIZE_ID), ARG_STR(OPT_KEY_FILE_ID), ARG_UINT32(OPT_TIMEOUT_ID),
_verify_passphrase(0), 0, cd);
if (r < 0)
return r;
r = crypt_reencrypt_init_by_passphrase(cd, NULL, password, passwordLen,
ARG_INT32(OPT_KEY_SLOT_ID), ARG_INT32(OPT_KEY_SLOT_ID), NULL, NULL, &params);
tools_passphrase_msg(r);
if (r < 0)
goto out;
r = crypt_activate_by_passphrase(cd, NULL, ARG_INT32(OPT_KEY_SLOT_ID),
password, passwordLen, 0);
tools_passphrase_msg(r);
if (r >= 0)
r = 0;
out:
crypt_safe_free(password);
return r;
}
static int luks2_reencrypt_repair(struct crypt_device *cd)
{
int r;
size_t passwordLen;
const char *msg;
char *password = NULL;
struct crypt_params_reencrypt recovery_params = {
.flags = CRYPT_REENCRYPT_RECOVERY
};
struct crypt_params_reencrypt params = {};
crypt_reencrypt_info ri = crypt_reencrypt_status(cd, &params);
if (params.flags & CRYPT_REENCRYPT_REPAIR_NEEDED)
return reencrypt_metadata_repair(cd);
crypt_reencrypt_info ri = crypt_reencrypt_status(cd, NULL);
switch (ri) {
case CRYPT_REENCRYPT_NONE:
/* fall through */
return 0;
case CRYPT_REENCRYPT_CLEAN:
if (ARG_SET(OPT_BATCH_MODE_ID) ||
!noDialog(_("Seems device does not require reencryption recovery.\n"
"Do you want to proceed anyway?"), NULL))
return 0;
break;
case CRYPT_REENCRYPT_CRASH:
if (!ARG_SET(OPT_BATCH_MODE_ID) &&
@@ -1201,8 +1240,12 @@ static int _do_luks2_reencrypt_recovery(struct crypt_device *cd)
return -EINVAL;
}
r = tools_get_key(_("Enter passphrase for reencryption recovery: "),
&password, &passwordLen, ARG_UINT64(OPT_KEYFILE_OFFSET_ID),
if (ri == CRYPT_REENCRYPT_CLEAN)
msg = _("Enter passphrase to verify reencryption metadata digest: ");
else
msg = _("Enter passphrase for reencryption recovery: ");
r = tools_get_key(msg, &password, &passwordLen, ARG_UINT64(OPT_KEYFILE_OFFSET_ID),
ARG_UINT32(OPT_KEYFILE_SIZE_ID), ARG_STR(OPT_KEY_FILE_ID), ARG_UINT32(OPT_TIMEOUT_ID),
_verify_passphrase(0), 0, cd);
if (r < 0)
@@ -1213,8 +1256,14 @@ static int _do_luks2_reencrypt_recovery(struct crypt_device *cd)
if (r < 0)
goto out;
if (ri == CRYPT_REENCRYPT_CLEAN) {
r = 0;
goto out;
}
r = crypt_reencrypt_init_by_passphrase(cd, NULL, password, passwordLen,
ARG_INT32(OPT_KEY_SLOT_ID), ARG_INT32(OPT_KEY_SLOT_ID), NULL, NULL, &recovery_params);
ARG_INT32(OPT_KEY_SLOT_ID), ARG_INT32(OPT_KEY_SLOT_ID), NULL, NULL,
&(struct crypt_params_reencrypt){ .flags = CRYPT_REENCRYPT_RECOVERY });
if (r > 0)
r = 0;
out:
@@ -1255,9 +1304,9 @@ static int action_luksRepair(void)
else
r = crypt_repair(cd, luksType(device_type), NULL);
out:
/* Header is ok, check if possible interrupted reencryption need repairs. */
/* Header is ok, check if reencryption metadata needs repair/recovery. */
if (!r && isLUKS2(crypt_get_type(cd)))
r = _do_luks2_reencrypt_recovery(cd);
r = luks2_reencrypt_repair(cd);
crypt_free(cd);
return r;

View File

@@ -27,7 +27,7 @@ TESTS += verity-compat-test
endif
if REENCRYPT
TESTS += reencryption-compat-test reencryption-compat-test2 luks2-reencryption-test
TESTS += reencryption-compat-test reencryption-compat-test2 luks2-reencryption-test luks2-reencryption-mangle-test
endif
if INTEGRITYSETUP
@@ -72,6 +72,7 @@ EXTRA_DIST = compatimage.img.xz compatv10image.img.xz \
reencryption-compat-test \
reencryption-compat-test2 \
luks2-reencryption-test \
luks2-reencryption-mangle-test \
tcrypt-compat-test \
luks1-compat-test \
luks2-validation-test generators \
@@ -154,6 +155,7 @@ valgrind-check: api-test api-test-2 differ
@INFOSTRING="api-test-000" ./valg-api.sh ./api-test
@INFOSTRING="api-test-002" ./valg-api.sh ./api-test-2
@VALG=1 ./luks2-reencryption-test
@VALG=1 ./luks2-reencryption-mangle-test
@VALG=1 ./bitlk-compat-test
@VALG=1 ./tcrypt-compat-test
@grep -l "ERROR SUMMARY: [^0] errors" valglog* || echo "No leaks detected."

View File

@@ -3805,6 +3805,7 @@ static void Luks2Flags(void)
CRYPT_FREE(cd);
}
#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION
static int test_progress(uint64_t size __attribute__((unused)),
uint64_t offset __attribute__((unused)),
void *usrptr __attribute__((unused)))
@@ -3817,7 +3818,6 @@ static int test_progress(uint64_t size __attribute__((unused)),
static void Luks2Reencryption(void)
{
/* reencryption currently depends on kernel keyring support */
#if KERNEL_KEYRING
/* NOTES:
* - reencryption requires luks2 parameters. can we avoid it?
*/
@@ -4238,7 +4238,7 @@ static void Luks2Reencryption(void)
_cleanup_dmdevices();
OK_(create_dmdevice_over_loop(H_DEVICE, r_header_size));
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 12*1024*2+1));
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 8*1024*2+1));
/* encryption with datashift and moved segment (data shift + 1 sector) */
OK_(crypt_init(&cd, DMDIR H_DEVICE));
@@ -4258,11 +4258,11 @@ static void Luks2Reencryption(void)
_cleanup_dmdevices();
OK_(create_dmdevice_over_loop(H_DEVICE, r_header_size));
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 12*1024*2));
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 2*8200));
OK_(crypt_init(&cd, DMDIR H_DEVICE));
/* encryption with datashift and moved segment (data shift + data offset > device size) */
/* encryption with datashift and moved segment (data shift + data offset <= device size) */
memset(&rparams, 0, sizeof(rparams));
params2.sector_size = 512;
params2.data_device = DMDIR L_DEVICE_OK;
@@ -4538,8 +4538,8 @@ static void Luks2Reencryption(void)
crypt_free(cd);
_cleanup_dmdevices();
#endif
}
#endif
static void Luks2Repair(void)
{
@@ -4655,7 +4655,9 @@ int main(int argc, char *argv[])
RUN_(Luks2Integrity, "LUKS2 with data integrity");
RUN_(Luks2Refresh, "Active device table refresh");
RUN_(Luks2Flags, "LUKS2 persistent flags");
#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION
RUN_(Luks2Reencryption, "LUKS2 reencryption");
#endif
RUN_(Luks2Repair, "LUKS2 repair"); // test disables metadata locking. Run always last!
_cleanup();

Binary file not shown.

View File

@@ -0,0 +1,504 @@
#!/bin/bash
PS4='$LINENO:'
[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
CRYPTSETUP_RAW=$CRYPTSETUP
CRYPTSETUP_VALGRIND=../.libs/cryptsetup
CRYPTSETUP_LIB_VALGRIND=../.libs
IMG=reenc-mangle-data
IMG_HDR=$IMG.hdr
IMG_JSON=$IMG.json
KEY1=key1
DEV_NAME=reenc3492834
FAST_PBKDF2="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
CS_PWPARAMS="--disable-keyring --key-file $KEY1"
CS_PARAMS="-q --disable-locks $CS_PWPARAMS"
JSON_MSIZE=16384
function remove_mapping()
{
[ -b /dev/mapper/$DEV_NAME ] && dmsetup remove --retry $DEV_NAME
rm -f $IMG $IMG_HDR $IMG_JSON $KEY1 >/dev/null 2>&1
}
function fail()
{
local frame=0
[ -n "$1" ] && echo "$1"
echo "FAILED backtrace:"
while caller $frame; do ((frame++)); done
remove_mapping
exit 2
}
function skip()
{
[ -n "$1" ] && echo "$1"
remove_mapping
exit 77
}
function bin_check()
{
which $1 >/dev/null 2>&1 || skip "WARNING: test require $1 binary, test skipped."
}
function img_json_save()
{
# FIXME: why --json-file cannot be used?
$CRYPTSETUP luksDump --dump-json-metadata $IMG | jq -c -M . | tr -d '\n' >$IMG_JSON
}
function img_json_dump()
{
img_json_save
jq . $IMG_JSON
}
function img_hash_save()
{
IMG_HASH=$(sha256sum $IMG | cut -d' ' -f 1)
}
function img_hash_unchanged()
{
local IMG_HASH2=$(sha256sum $IMG | cut -d' ' -f 1)
[ "$IMG_HASH" != "$IMG_HASH2" ] && fail "Image changed!"
}
function img_prepare_raw() # $1 options
{
remove_mapping
if [ ! -e $KEY1 ]; then
dd if=/dev/urandom of=$KEY1 count=1 bs=32 >/dev/null 2>&1
fi
truncate -s 32M $IMG || fail
$CRYPTSETUP luksFormat $FAST_PBKDF2 $CS_PARAMS --luks2-metadata-size $JSON_MSIZE $IMG $1 || fail
}
function img_prepare() # $1 options
{
img_prepare_raw
# FIXME: resilience is not saved here (always none)?
$CRYPTSETUP reencrypt $IMG $CS_PARAMS -q --init-only --resilience none $1 >/dev/null 2>&1
[ $? -ne 0 ] && skip "Reencryption unsupported, test skipped."
img_json_save
img_hash_save
}
function _dd()
{
dd $@ status=none conv=notrunc bs=1
}
# header mangle functions
function img_update_json()
{
local LUKS2_BIN1_OFFSET=448
local LUKS2_BIN2_OFFSET=$((LUKS2_BIN1_OFFSET + $JSON_MSIZE))
local LUKS2_JSON_SIZE=$(($JSON_MSIZE - 4096))
# if present jq script, mangle JSON
if [ -n "$1" ]; then
local JSON=$(cat $IMG_JSON)
echo $JSON | jq -M -c "$1" >$IMG_JSON || fail
local JSON=$(cat $IMG_JSON)
echo $JSON | tr -d '\n' >$IMG_JSON || fail
fi
# wipe JSON areas
_dd if=/dev/zero of=$IMG count=$LUKS2_JSON_SIZE seek=4096
_dd if=/dev/zero of=$IMG count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096))
# write JSON data
_dd if=$IMG_JSON of=$IMG count=$LUKS2_JSON_SIZE seek=4096
_dd if=$IMG_JSON of=$IMG count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096))
# erase sha256 checksums
_dd if=/dev/zero of=$IMG count=64 seek=$LUKS2_BIN1_OFFSET
_dd if=/dev/zero of=$IMG count=64 seek=$LUKS2_BIN2_OFFSET
# calculate sha256 and write chexksums
local SUM1_HEX=$(_dd if=$IMG count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1)
echo $SUM1_HEX | xxd -r -p | _dd of=$IMG seek=$LUKS2_BIN1_OFFSET count=64 || fail
local SUM2_HEX=$(_dd if=$IMG skip=$JSON_MSIZE count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1)
echo $SUM2_HEX | xxd -r -p | _dd of=$IMG seek=$LUKS2_BIN2_OFFSET count=64 || fail
img_hash_save
}
function img_check_ok()
{
if [ $(id -u) == 0 ]; then
$CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME || fail
$CRYPTSETUP close $DEV_NAME || fail
fi
$CRYPTSETUP repair $IMG $CS_PARAMS || fail
}
function img_check_fail()
{
if [ $(id -u) == 0 ]; then
$CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail
fi
$CRYPTSETUP repair $IMG $CS_PARAMS 2>/dev/null && fail
img_hash_unchanged
}
function img_run_reenc_ok()
{
local EXPECT_TIMEOUT=5
[ -n "$VALG" ] && EXPECT_TIMEOUT=60
# For now, we cannot run reencryption in batch mode for non-block device. Just fake the terminal here.
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 2 }
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS --disable-locks --resilience none
expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
send "YES\n"
expect timeout abort eof
exit
EOF
[ $? -eq 0 ] || fail "Expect script failed."
}
function img_run_reenc_fail()
{
local EXPECT_TIMEOUT=5
[ -n "$VALG" ] && EXPECT_TIMEOUT=60
# For now, we cannot run reencryption in batch mode for non-block device. Just fake the terminal here.
expect_run - >/dev/null <<EOF
proc abort {} { send_error "Timeout. "; exit 42 }
set timeout $EXPECT_TIMEOUT
eval spawn $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS --disable-locks
expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
send "YES\n"
expect timeout abort eof
catch wait result
exit [lindex \$result 3]
EOF
local ret=$?
[ $ret -eq 0 ] && fail "Reencryption passed (should have failed)."
[ $ret -eq 42 ] && fail "Expect script failed."
img_hash_unchanged
}
function img_check_fail_repair_ok()
{
if [ $(id -u) == 0 ]; then
$CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail
fi
img_run_reenc_fail
# repair metadata
$CRYPTSETUP repair $IMG $CS_PARAMS || fail
img_check_ok
img_run_reenc_ok
}
function valgrind_setup()
{
bin_check valgrind
[ ! -f $CRYPTSETUP_VALGRIND ] && fail "Unable to get location of cryptsetup executable."
export LD_LIBRARY_PATH="$CRYPTSETUP_LIB_VALGRIND:$LD_LIBRARY_PATH"
CRYPTSETUP=valgrind_run
CRYPTSETUP_RAW="./valg.sh ${CRYPTSETUP_VALGRIND}"
}
function valgrind_run()
{
INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${CRYPTSETUP_VALGRIND} "$@"
}
function expect_run()
{
export INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}"
expect "$@"
}
bin_check jq
bin_check sha256sum
bin_check xxd
bin_check expect
export LANG=C
[ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run
#while false; do
echo "[1] Reencryption with old flag is rejected"
img_prepare
img_update_json '.config.requirements.mandatory = ["online-reencryptx"]'
img_check_fail
img_update_json '.config.requirements.mandatory = ["online-reencrypt-v2"]'
img_check_ok
img_run_reenc_ok
img_check_ok
# Simulate old reencryption with no digest (repairable)
img_prepare
img_update_json 'del(.digests."2") | .config.requirements.mandatory = ["online-reencrypt"]'
img_check_fail_repair_ok
# This must fail for new releases
echo "[2] Old reencryption in-progress (journal)"
img_prepare
img_update_json '
del(.digests."2") |
.keyslots."2".area.type = "journal" |
.segments = {
"0" : (.segments."0" +
{"size" : .keyslots."2".area.size} +
{"flags" : ["in-reencryption"]}),
"1" : (.segments."0" +
{"offset" : ((.segments."0".offset|tonumber) +
(.keyslots."2".area.size|tonumber))|tostring}),
"2" : .segments."1",
"3" : .segments."2"
} |
.digests."0".segments = ["1","2"] |
.digests."1".segments = ["0","3"] |
.config.requirements.mandatory = ["online-reencrypt"]'
img_check_fail_repair_ok
echo "[3] Old reencryption in-progress (checksum)"
img_prepare
img_update_json '
del(.digests."2") |
.keyslots."2".area.type = "checksum" |
.keyslots."2".area.hash = "sha256" |
.keyslots."2".area.sector_size = 4096 |
.segments = {
"0" : (.segments."0" +
{"size" : .keyslots."2".area.size} +
{"flags" : ["in-reencryption"]}),
"1" : (.segments."0" +
{"offset": ((.segments."0".offset|tonumber) +
(.keyslots."2".area.size|tonumber))|tostring}),
"2" : .segments."1",
"3" : .segments."2"
} |
.digests."0".segments = ["1","2"] |
.digests."1".segments = ["0","3"] |
.config.requirements.mandatory = ["online-reencrypt"]'
img_check_fail_repair_ok
# Note: older tools cannot create this from commandline
echo "[4] Old decryption in-progress (journal)"
img_prepare
img_update_json '
del(.digests."1") |
del(.digests."2") |
del(.keyslots."1") |
.keyslots."2".mode = "decrypt" |
.keyslots."2".area.type = "journal" |
.segments = {
"0" : {
"type" : "linear",
"offset" : .segments."0".offset,
"size" : .keyslots."2".area.size,
"flags" : ["in-reencryption"]
},
"1" : (.segments."0" +
{"offset" : ((.segments."0".offset|tonumber) +
(.keyslots."2".area.size|tonumber))|tostring}),
"2" : .segments."1",
"3" : {
"type" : "linear",
"offset" : .segments."0".offset,
"size" : "dynamic",
"flags" : ["backup-final"]
}
} |
.digests."0".segments = ["1","2"] |
.config.requirements.mandatory = ["online-reencrypt"]'
img_check_fail_repair_ok
echo "[5] Old decryption in-progress (checksum)"
img_prepare
img_update_json '
del(.digests."1") |
del(.digests."2") |
del(.keyslots."1") |
.keyslots."2".mode = "decrypt" |
.keyslots."2".area.type = "checksum" |
.keyslots."2".area.hash = "sha256" |
.keyslots."2".area.sector_size = 4096 |
.segments = {
"0" : {
"type" : "linear",
"offset" : .segments."0".offset,
"size" : .keyslots."2".area.size,
"flags" : ["in-reencryption"]
},
"1" : (.segments."0" +
{"offset" : ((.segments."0".offset|tonumber) +
(.keyslots."2".area.size|tonumber))|tostring}),
"2" : .segments."1",
"3" : {
"type" : "linear",
"offset" : .segments."0".offset,
"size" : "dynamic",
"flags" : ["backup-final"]
}
} |
.digests."0".segments = ["1","2"] |
.config.requirements.mandatory = ["online-reencrypt"]'
img_check_fail_repair_ok
# Note - offset is set to work with the old version (with a datashift bug)
echo "[6] Old reencryption in-progress (datashift)"
img_prepare
img_update_json '
del(.digests."2") |
.keyslots."2".direction = "backward" |
.keyslots."2".area.type = "datashift" |
.keyslots."2".area.size = "4096" |
.keyslots."2".area.shift_size = ((1 * 1024 * 1024)|tostring) |
.segments = {
"0" : (.segments."0" +
{"size" : ((13 * 1024 * 1024)|tostring)}),
"1" : (.segments."0" +
{"offset" : ((30 * 1024 * 1024)|tostring)}),
"2" : .segments."1",
"3" : (.segments."2" +
{"offset" : ((17 * 1024 * 1024)|tostring)}),
} |
.digests."0".segments = ["0","2"] |
.digests."1".segments = ["1","3"] |
.config.requirements.mandatory = ["online-reencrypt"]'
img_check_fail_repair_ok
#
# NEW metadata (with reenc digest)
#
echo "[7] Reencryption with various mangled metadata"
# Normal situation
img_prepare
img_run_reenc_ok
img_check_ok
# The same in various steps.
# Repair must validate not only metadata, but also reencryption digest.
img_prepare
img_update_json 'del(.digests."2")'
img_check_fail_repair_ok
img_prepare '--reduce-device-size 2M'
img_update_json '.keyslots."2".area.shift_size = ((.keyslots."2".area.shift_size|tonumber / 2)|tostring)'
img_check_fail
#FIXME: cannot check with correct digest for now (--init-only does not store area type)
img_prepare
img_update_json '
.keyslots."2".area.type = "checksum" |
.keyslots."2".area.hash = "sha256" |
.keyslots."2".area.sector_size = 4096'
img_check_fail
img_prepare
img_update_json '.keyslots."2".area.type = "journal"'
img_check_fail
img_prepare
img_update_json '.keyslots."2".mode = "decrypt"'
img_check_fail
img_prepare
img_update_json '.keyslots."2".direction = "backward"'
img_check_fail
# key_size must be 1
img_prepare
img_update_json '.keyslots."2".key_size = 16'
img_check_fail
# Mangling segments
img_prepare
img_update_json 'del(.segments."1")'
img_check_fail
img_prepare
img_update_json '.segments."0".encryption = "aes-cbc-null"'
img_check_fail
img_prepare
img_update_json '.segments."1".encryption = "aes-cbc-null"'
img_check_fail
img_prepare
img_update_json '.segments."2".encryption = "aes-cbc-null"'
img_check_fail
# Mangling digests
img_prepare
img_update_json '
.digests."2" = .digests."0" |
.digests."2".keyslots = ["2"] |
.digests."2".segments = []'
img_check_fail
img_prepare
img_update_json '.digests."2".iterations = 1111'
img_check_fail
# Simulate correct progress
img_prepare
img_update_json '
.segments = {
"0" : (.segments."0" +
{"size" : ((1 * 1024 * 1024)|tostring)}),
"1" : (.segments."0" +
{"offset" : ((17 * 1024 * 1024)|tostring)}),
"2" : .segments."1",
"3" : .segments."2"
} |
.digests."0".segments = ["1","2"] |
.digests."1".segments = ["0","3"]'
img_check_ok
# Mangling keyslots
# Set reencrypt slot to non-ignore priority
# This should be benign, just avoid noisy messages
img_prepare
img_update_json 'del(.keyslots."2".priority)'
img_check_ok
# Flags
# Remove mandatory reenc flag, but keep reenc metadata
img_prepare
img_update_json '.config.requirements.mandatory = []'
img_check_fail
# Unknown segment flag, should be ignored
img_prepare
img_update_json '.segments."0".flags = ["dead-parrot"]'
img_check_ok
echo "[8] Reencryption with AEAD is not supported"
img_prepare_raw
img_json_save
img_update_json '
.segments."0".integrity = {
"type" : "hmac(sha256)",
"journal_encryption": "none",
"journal_integrity": "none"
}'
$CRYPTSETUP reencrypt $IMG $CS_PARAMS >/dev/null 2>&1 && fail
remove_mapping
exit 0

View File

@@ -116,6 +116,7 @@ function fail()
function skip()
{
[ -n "$1" ] && echo "$1"
remove_mapping
exit 77
}
@@ -152,14 +153,30 @@ function open_crypt() # $1 pwd, $2 hdr
fi
}
function wipe_dev_head() # $1 dev, $2 length (in MiBs)
{
dd if=/dev/zero of=$1 bs=1M count=$2 conv=notrunc >/dev/null 2>&1
}
function wipe_dev() # $1 dev
{
if [ -b $1 ] ; then
blkdiscard --zeroout $1 2>/dev/null || dd if=/dev/zero of=$1 bs=1M conv=notrunc >/dev/null 2>&1
if [ $# -gt 2 ]; then
dd if=/dev/urandom of=$1 bs=1M seek=$2 conv=notrunc >/dev/null 2>&1
fi
else
local size=$(stat --printf="%s" $1)
truncate -s 0 $1
truncate -s $size $1
if [ $# -gt 2 ]; then
local diff=$((size-$2*1024*1024))
echo "size: $size, diff: $diff"
truncate -s $diff $1
# wipe_dev_head $1 $((diff/(1024*1024)))
dd if=/dev/urandom of=$1 bs=1M seek=$2 size=$((diff/(1024*1024))) conv=notrunc >/dev/null 2>&1
else
truncate -s $size $1
fi
fi
}
@@ -214,15 +231,16 @@ function check_hash() # $1 pwd, $2 hash, $3 hdr
$CRYPTSETUP remove $DEV_NAME || fail
}
function check_hash_dev_head() # $1 dev, $2 len, $3 hash
{
local hash=$(dd if=$1 bs=512 count=$2 2>/dev/null | sha256sum | cut -d' ' -f1)
[ $hash != "$3" ] && fail "HASH differs (expected: $3) (result $hash)"
}
function check_hash_head() # $1 pwd, $2 len, $3 hash, $4 hdr
{
open_crypt $1 $4
if [ -n "$4" ]; then
echo $1 | $CRYPTSETUP resize $DEV_NAME --size $2 --header $4 || fail
else
echo $1 | $CRYPTSETUP resize $DEV_NAME --size $2 || fail
fi
check_hash_dev /dev/mapper/$DEV_NAME $3
check_hash_dev_head /dev/mapper/$DEV_NAME $2 $3
$CRYPTSETUP remove $DEV_NAME || fail
}
@@ -733,6 +751,7 @@ echo -n "[512 sector]"
echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -s 128 -c aes-cbc-essiv:sha256 --offset 8192 $FAST_PBKDF_ARGON $DEV || fail
wipe $PWD1
check_hash $PWD1 $HASH1
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q $FAST_PBKDF_ARGON 2>&1 | tail -1 | grep -q "not supported" && skip " No reenryption support, test skipped."
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q $FAST_PBKDF_ARGON || fail
check_hash $PWD1 $HASH1
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q -s 256 -c twofish-cbc-essiv:sha256 --resilience journal $FAST_PBKDF_ARGON || fail
@@ -865,6 +884,21 @@ $CRYPTSETUP status $DEV_NAME >/dev/null 2>&1 || fail
$CRYPTSETUP close $DEV_NAME
echo $PWD1 | $CRYPTSETUP open $DEV --test-passphrase || fail
# Small device encryption test
preparebig 65
# wipe only 1st MiB (final data size after encryption)
wipe_dev $DEV 1
check_hash_dev_head $DEV 2048 $HASH2
echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --reduce-device-size 64M -q $FAST_PBKDF_ARGON || fail
check_hash_head $PWD1 2048 $HASH2
wipe_dev_head $DEV 1
check_hash_dev_head $DEV 2048 $HASH2
echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --reduce-device-size 64M --init-only -q $FAST_PBKDF_ARGON $DEV_NAME >/dev/null || fail
check_hash_dev_head /dev/mapper/$DEV_NAME 2048 $HASH2
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q || fail
check_hash_dev_head /dev/mapper/$DEV_NAME 2048 $HASH2
echo "[3] Encryption with detached header"
preparebig 256
wipe_dev $DEV