mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-06 16:30:04 +01:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c67861e875 | ||
|
|
f566d7c911 | ||
|
|
f21b07fb1b | ||
|
|
904cdd1161 | ||
|
|
5d75632a16 | ||
|
|
da8bcf7270 | ||
|
|
bbc3ff69db | ||
|
|
7ef0d9c73a | ||
|
|
8ced413876 | ||
|
|
80a77bce2a | ||
|
|
334606b6aa | ||
|
|
1162f1e1e3 | ||
|
|
47a1d9a6d6 | ||
|
|
c257ae1eb4 | ||
|
|
d37c3f0db2 | ||
|
|
4a974ec582 | ||
|
|
c95a88f815 | ||
|
|
4af4a4a631 | ||
|
|
3d269a5ae3 | ||
|
|
de98f01141 | ||
|
|
4d28153e53 | ||
|
|
dd864f5a61 | ||
|
|
ca54398eec | ||
|
|
97cd16b8b9 | ||
|
|
86d0d4f68e | ||
|
|
1a7d98b3ba | ||
|
|
025a96df73 | ||
|
|
e6edbc1fe5 | ||
|
|
ed68b51526 | ||
|
|
bcace16aa2 | ||
|
|
97aa31d32f | ||
|
|
36a78ed17b | ||
|
|
0d4ecd92f1 | ||
|
|
94143c3428 | ||
|
|
af17d2256d |
40
.github/workflows/cibuild.sh
vendored
40
.github/workflows/cibuild.sh
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
49
.gitlab/ci/cibuild-setup-ubuntu.sh
Executable file
49
.gitlab/ci/cibuild-setup-ubuntu.sh
Executable 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
55
.gitlab/ci/clang-Wall
Executable 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
|
||||
}
|
||||
25
.gitlab/ci/compilation-clang.gitlab-ci.yml
Normal file
25
.gitlab/ci/compilation-clang.gitlab-ci.yml
Normal 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
|
||||
24
.gitlab/ci/compilation-gcc.gitlab-ci.yml
Normal file
24
.gitlab/ci/compilation-gcc.gitlab-ci.yml
Normal 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
61
.gitlab/ci/gcc-Wall
Executable 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
|
||||
}
|
||||
29
.gitlab/ci/gitlab-shared-docker.yml
Normal file
29
.gitlab/ci/gitlab-shared-docker.yml
Normal 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
31
.gitlab/ci/warnings_filter.py
Executable 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)
|
||||
16
README.md
16
README.md
@@ -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:
|
||||
|
||||
10
configure.ac
10
configure.ac
@@ -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
101
docs/v2.4.3-ReleaseNotes
Normal 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.
|
||||
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
381
lib/luks2/luks2_reencrypt_digest.c
Normal file
381
lib/luks2/luks2_reencrypt_digest.c
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
74
lib/setup.c
74
lib/setup.c
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
285
po/sr.po
285
po/sr.po
@@ -4,10 +4,10 @@
|
||||
# Мирослав Николић <miroslavnikolic@rocketmail.com>, 2014–2021.
|
||||
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"
|
||||
|
||||
|
||||
@@ -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, ¶ms);
|
||||
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, ¶ms);
|
||||
|
||||
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;
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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.
504
tests/luks2-reencryption-mangle-test
Executable file
504
tests/luks2-reencryption-mangle-test
Executable 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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user