Compare commits

..

19 Commits

Author SHA1 Message Date
Milan Broz
ca50f2cd33 Version 2.7.1. 2024-03-07 15:47:06 +01:00
Milan Broz
d5559df2cc tests: Fix Makefile * Meson to include all fs images. 2024-03-07 15:39:12 +01:00
Milan Broz
a2d820649b Update LUKS2 spec. 2024-03-07 15:27:52 +01:00
Milan Broz
94286c387f Add 2.7.1 release notes. 2024-03-07 15:27:44 +01:00
Milan Broz
2c53e71415 test: Fix tests on RHEL7 clones (no keyring in dm-crypt). 2024-03-07 14:26:46 +01:00
Milan Broz
2f0e804fd1 Add xfs V5 image to tests.
XFS V4 can be disabled in kernel, add image V5.

Minimal 300M xfs size avoided by using QA variables magic in format:
export TEST_DIR=1 TEST_DEV=1 QA_CHECK_FS=1 ; mkfs -t xfs ...
2024-03-07 14:26:34 +01:00
Ondrej Kozina
d478e09f2e tests: fix compat-test-opal bug for empty LUKS2 passphrase.
The bug was hidden due to previously contradicting condition.
2024-03-07 14:26:22 +01:00
Ondrej Kozina
0645219c9d tests: move luks1 decryption resume test.
It cannot be run in fips mode due to empty passphrase
is no longer allowed.
2024-03-07 14:26:09 +01:00
Ondrej Kozina
ba7973236b tests: fix fips mode detection contradiction in various tests. 2024-03-07 14:25:53 +01:00
Yuri Chornoivan
5d6bcc2c3b po: update uk.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Remus-Gabriel Chelu
05b16f73f9 po: update ro.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Jakub Bogusz
60274f1fcf po: update pl.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Hiroshi Takekawa
f8b4931bb1 po: update ja.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Frédéric Marchal
cb59aeb85a po: update fr.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Roland Illig
2f72f227b5 po: update de.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Petr Pisar
004419e1d6 po: update cs.po (from translationproject.org) 2024-03-06 09:53:01 +01:00
Ondrej Kozina
5c3dba8688 Add regression test for resuming LUKS1 decryption. 2024-03-06 09:52:55 +01:00
Ondrej Kozina
25e3adab7e Fix regression in LUKS1 decryption.
With removal of cryptsetup-reencrypt there was
a bug introduced that broke resuming interrupted
LUKS1 decryption operation. LUKS2 code was not
affected.
2024-03-06 09:52:44 +01:00
Milan Broz
bbdf692104 Set version 2.7.1-rc0. 2024-02-29 20:45:28 +01:00
355 changed files with 21573 additions and 33423 deletions

View File

@@ -5,9 +5,9 @@ set -ex
PACKAGES=(
git make autoconf automake autopoint pkg-config libtool libtool-bin
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol-dev
libjson-c-dev libssh-dev libblkid-dev tar libargon2-dev libpwquality-dev
sharutils dmsetup jq xxd expect keyutils netcat-openbsd passwd openssh-client
sshpass asciidoctor meson ninja-build
libjson-c-dev libssh-dev libblkid-dev tar libargon2-0-dev libpwquality-dev
sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass
asciidoctor meson ninja-build
)
COMPILER="${COMPILER:?}"

View File

@@ -16,11 +16,11 @@ jobs:
fail-fast: false
matrix:
env:
- { COMPILER: "gcc", COMPILER_VERSION: "14", RUN_SSH_PLUGIN_TEST: "1" }
- { COMPILER: "gcc", COMPILER_VERSION: "13", RUN_SSH_PLUGIN_TEST: "1" }
env: ${{ matrix.env }}
steps:
- name: Repository checkout
uses: actions/checkout@v4
uses: actions/checkout@v1
- name: Ubuntu setup
run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh
- name: Configure & Make

View File

@@ -29,25 +29,21 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
config-file: .codeql-config.yml
- name: Install dependencies
run: |
sudo -E .github/workflows/cibuild-setup-ubuntu.sh
# Force autoconf for now, meson is broken in analysis step
rm meson.build
env: { COMPILER: "gcc", COMPILER_VERSION: "14", RUN_SSH_PLUGIN_TEST: "1" }
run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh
env: { COMPILER: "gcc", COMPILER_VERSION: "13", RUN_SSH_PLUGIN_TEST: "1" }
- name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v2

View File

@@ -12,12 +12,12 @@ jobs:
if: github.repository == 'mbroz/cryptsetup'
steps:
- name: Repository checkout
uses: actions/checkout@v4
uses: actions/checkout@v1
- name: Ubuntu setup
run: sudo -E .github/workflows/cibuild-setup-ubuntu.sh
env:
COMPILER: "gcc"
COMPILER_VERSION: "14"
COMPILER_VERSION: "13"
- name: Install Coverity
run: |
wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=mbroz/cryptsetup" -O cov-analysis-linux64.tar.gz

1
.gitignore vendored
View File

@@ -17,7 +17,6 @@ ABOUT-NLS
aclocal.m4
autom4te.cache/
compile
compile_commands.json
config.guess
config.h
config.h.in

View File

@@ -1,6 +1,5 @@
stages:
- test
- test-opal
.fail_if_coredump_generated:
after_script:
@@ -12,14 +11,12 @@ include:
- local: .gitlab/ci/fedora-opal.yml
- local: .gitlab/ci/rhel.yml
- local: .gitlab/ci/centos.yml
# - local: .gitlab/ci/annocheck.yml
- local: .gitlab/ci/annocheck.yml
- local: .gitlab/ci/csmock.yml
- local: .gitlab/ci/gitlab-shared-docker.yml
- local: .gitlab/ci/compilation-various-disables.yml
- local: .gitlab/ci/compilation-gcc.gitlab-ci.yml
- local: .gitlab/ci/compilation-clang.gitlab-ci.yml
- local: .gitlab/ci/compilation-spellcheck.yml
- local: .gitlab/ci/alpinelinux.yml
- local: .gitlab/ci/debian-i686.yml
- local: .gitlab/ci/cifuzz.yml
- local: .gitlab/ci/ubuntu.yml

View File

@@ -1,32 +0,0 @@
#!/bin/bash
set -e
SAVED_PWD=$(pwd)
GIT_DIR="$SAVED_PWD/upstream_git"
SPEC="$GIT_DIR/misc/fedora/cryptsetup.spec"
rm -fr $GIT_DIR
git clone -q --depth 1 https://gitlab.com/cryptsetup/cryptsetup.git $GIT_DIR
cd $GIT_DIR
GIT_COMMIT=$(git rev-parse --short=8 HEAD)
[ -z "$GIT_COMMIT" ] && exit 1
sed -i "s/^AC_INIT.*/AC_INIT([cryptsetup],[$GIT_COMMIT])/" $GIT_DIR/configure.ac
sed -i "s/^Version:.*/Version: $GIT_COMMIT/" $SPEC
sed -i "s/%{version_no_tilde}/$GIT_COMMIT/" $SPEC
sed -i "2i %global source_date_epoch_from_changelog 0" $SPEC
sed -i "3i %define _unpackaged_files_terminate_build 0" $SPEC
./autogen.sh
./configure
make -j dist
rpmbuild --define "_sourcedir $GIT_DIR" --define "_srcrpmdir $SAVED_PWD" -bs $SPEC
cd $SAVED_PWD
rm -fr $GIT_DIR
exit 0

View File

@@ -4,15 +4,13 @@
extends:
- .fail_if_coredump_generated
before_script:
- sudo dnf clean all
- >
sudo dnf -y -q install
autoconf automake device-mapper-devel gcc gettext-devel json-c-devel
libblkid-devel libpwquality-devel libselinux-devel libssh-devel libtool
libuuid-devel make popt-devel libsepol-devel nc openssh-clients passwd
pkgconfig sharutils sshpass tar uuid-devel vim-common device-mapper
expect gettext git jq keyutils openssl-devel openssl gem swtpm swtpm-tools
tpm2-tools
expect gettext git jq keyutils openssl-devel openssl gem
- sudo gem install asciidoctor
- sudo -E git clean -xdf
- ./autogen.sh
@@ -30,7 +28,6 @@ test-main-commit-centos-stream9:
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
when: never
@@ -52,7 +49,6 @@ test-mergerq-centos-stream9:
interruptible: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
when: never

View File

@@ -5,7 +5,7 @@ set -ex
PACKAGES=(
git make autoconf automake autopoint pkg-config libtool libtool-bin
gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol-dev
libjson-c-dev libssh-dev libblkid-dev tar libargon2-dev libpwquality-dev
libjson-c-dev libssh-dev libblkid-dev tar libargon2-0-dev libpwquality-dev
sharutils dmsetup jq xxd expect keyutils netcat-openbsd passwd openssh-client
sshpass asciidoctor
)
@@ -13,12 +13,9 @@ PACKAGES=(
COMPILER="${COMPILER:?}"
COMPILER_VERSION="${COMPILER_VERSION:?}"
sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources
# use this on older Ubuntu
# 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
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
@@ -31,7 +28,7 @@ if [[ $COMPILER == "gcc" ]]; then
PACKAGES+=(gcc-$COMPILER_VERSION)
elif [[ $COMPILER == "clang" ]]; then
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
add-apt-repository -n "deb http://apt.llvm.org/${RELEASE}/ llvm-toolchain-${RELEASE}-${COMPILER_VERSION} main"
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)
@@ -40,9 +37,7 @@ else
exit 1
fi
#apt-get -y update --fix-missing
(r=3;while ! apt-get -y update --fix-missing ; do ((--r))||exit;sleep 5;echo "Retrying";done)
apt-get -y update --fix-missing
DEBIAN_FRONTEND=noninteractive apt-get -yq install "${PACKAGES[@]}"
apt-get -y build-dep cryptsetup

View File

@@ -28,32 +28,3 @@ test-scan-build:
- make clean
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} --status-bugs -maxloop 10 make -j
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} --status-bugs -maxloop 10 make -j check-programs
test-scan-build-backends:
extends:
- .gitlab-shared-clang
parallel:
matrix:
- BACKENDS: [
"openssl",
"gcrypt",
"nss",
"kernel",
"nettle",
"mbedtls"
]
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
changes:
- lib/crypto_backend/*
script:
- DEBIAN_FRONTEND=noninteractive apt-get -yq install libgcrypt20-dev libnss3-dev nettle-dev libmbedtls-dev
- ./autogen.sh
- echo "Configuring with crypto backend $BACKENDS"
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} -V ./configure CFLAGS="-g -O0" --with-crypto_backend=$BACKENDS
- make clean
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} --status-bugs -maxloop 10 make -j
- scan-build${COMPILER_VERSION:+-$COMPILER_VERSION} --status-bugs -maxloop 10 make -j check-programs
- ./tests/vectors-test

View File

@@ -23,35 +23,8 @@ test-gcc-fanalyzer:
extends:
- .gitlab-shared-gcc
script:
- export CFLAGS="-Wall -Werror -g -O0 -fanalyzer -fdiagnostics-path-format=separate-events"
- ./autogen.sh
- ./configure CFLAGS="-Wall -Werror -g -O0 -fanalyzer -fdiagnostics-path-format=separate-events" --host=x86_64
- ./configure
- make -j
- make -j check-programs
test-gcc-fanalyzer-backends:
extends:
- .gitlab-shared-gcc
parallel:
matrix:
- BACKENDS: [
"openssl",
"gcrypt",
"nss",
"kernel",
"nettle",
"mbedtls"
]
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
changes:
- lib/crypto_backend/*
script:
- DEBIAN_FRONTEND=noninteractive apt-get -yq install libgcrypt20-dev libnss3-dev nettle-dev libmbedtls-dev
- ./autogen.sh
- echo "Configuring with crypto backend $BACKENDS"
- ./configure CFLAGS="-Wall -Werror -g -O0 -fanalyzer -fdiagnostics-path-format=separate-events" --host=x86_64 --with-crypto_backend=$BACKENDS
- make -j
- make -j check-programs
- ./tests/vectors-test

View File

@@ -1,20 +0,0 @@
test-run-spellcheck:
image: ubuntu:noble
tags:
- gitlab-org-docker
stage: test
interruptible: true
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
artifacts:
name: "spellcheck-$CI_COMMIT_REF_NAME"
paths:
- _spellcheck
before_script:
- apt-get -y update --fix-missing
- apt-get -y install git lintian codespell
script:
- echo "Running spellcheck"
- .gitlab/ci/spellcheck

View File

@@ -11,8 +11,7 @@ test-gcc-disable-compiles:
"kernel_crypto",
"udev",
"internal-argon2",
"blkid",
"hw-opal"
"blkid"
]
artifacts:
name: "meson-build-logs-$CI_COMMIT_REF_NAME"

View File

@@ -1,36 +1,25 @@
.dnf-csmock:
variables:
DISTRO: cryptsetup-fedora-rawhide
DISK_SIZE: 20
extends:
- .fail_if_coredump_generated
before_script:
- >
sudo dnf -y -q install
autoconf automake device-mapper-devel gcc gettext-devel json-c-devel
libblkid-devel libpwquality-devel libselinux-devel
libssh-devel libtool libuuid-devel make popt-devel
libsepol-devel.x86_64 pkgconfig tar uuid-devel git
openssl-devel asciidoctor meson ninja-build
rpm-build csmock
test-commit-job-csmock:
extends:
- .dnf-csmock
- .fail_if_coredump_generated
tags:
- libvirt
- cryptsetup-fedora-rawhide
- cryptsetup-rhel-9
stage: test
interruptible: true
allow_failure: true
variables:
DISTRO: cryptsetup-rhel-9
RUN_SSH_PLUGIN_TEST: "1"
DISK_SIZE: 20
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/ || $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- .gitlab/ci/build_srpm
- .gitlab/ci/run_csmock
- sudo /opt/run-csmock.sh
artifacts:
# Upload artifacts when a crash makes the job fail.
when: always
paths:
- cryptsetup-csmock-results.tar.xz
- cryptsetup-csmock-results

View File

@@ -3,14 +3,16 @@
- .fail_if_coredump_generated
before_script:
- sudo apt-get -y update
- >
[ -z "$RUN_SYSTEMD_PLUGIN_TEST" ] ||
sudo apt-get -y install -y -qq swtpm meson ninja-build python3-jinja2
gperf libcap-dev libtss2-dev libmount-dev swtpm-tools
- >
sudo apt-get -y install -y -qq git gcc make autoconf automake autopoint
pkgconf libtool libtool-bin gettext libssl-dev libdevmapper-dev
libpopt-dev uuid-dev libsepol-dev libjson-c-dev libssh-dev libblkid-dev
tar libargon2-dev libpwquality-dev sharutils dmsetup jq xxd expect
keyutils netcat-openbsd passwd openssh-client sshpass asciidoctor
swtpm meson ninja-build python3-jinja2 gperf libcap-dev libtss2-dev
libmount-dev swtpm-tools tpm2-tools
- sudo apt-get -y build-dep cryptsetup
- sudo -E git clean -xdf
- ./autogen.sh
@@ -27,7 +29,6 @@ test-mergerq-job-debian:
variables:
DISTRO: cryptsetup-debian-12
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
@@ -48,7 +49,6 @@ test-main-commit-job-debian:
variables:
DISTRO: cryptsetup-debian-12
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
@@ -70,7 +70,6 @@ test-mergerq-job-debian-meson:
variables:
DISTRO: cryptsetup-debian-12
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
@@ -92,7 +91,6 @@ test-main-commit-job-debian-meson:
variables:
DISTRO: cryptsetup-debian-12
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never

View File

@@ -1,11 +1,34 @@
.dnf-openssl-backend:
variables:
DISTRO: cryptsetup-fedora-rawhide
extends:
- .fail_if_coredump_generated
before_script:
- >
[ -z "$RUN_SYSTEMD_PLUGIN_TEST" ] ||
sudo dnf -y -q install
swtpm meson ninja-build python3-jinja2 gperf libcap-devel tpm2-tss-devel
libmount-devel swtpm-tools
- >
sudo dnf -y -q install
autoconf automake device-mapper-devel gcc gettext-devel json-c-devel
libargon2-devel libblkid-devel libpwquality-devel libselinux-devel
libssh-devel libtool libuuid-devel make popt-devel
libsepol-devel.x86_64 netcat openssh-clients passwd pkgconfig sharutils
sshpass tar uuid-devel vim-common device-mapper expect gettext git jq
keyutils openssl-devel openssl asciidoctor
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-fips --enable-pwquality --enable-libargon2 --with-crypto_backend=openssl --enable-asciidoc
.opal-template-fedora:
extends:
- .dnf-openssl-backend
tags:
- libvirt
- cryptsetup-fedora-rawhide
stage: test-opal
interruptible: false
stage: test
interruptible: true
variables:
OPAL2_DEV: "/dev/nvme0n1"
OPAL2_PSID_FILE: "/home/gitlab-runner/psid.txt"
@@ -27,8 +50,8 @@ test-commit-rawhide-samsung980:
- .opal-template-fedora
tags:
- tiber
resource_group: samsung980-on-tiber
interruptible: false
stage: test
interruptible: true
variables:
PCI_PASSTHROUGH_VENDOR_ID: "144d"
PCI_PASSTHROUGH_DEVICE_ID: "a809"
@@ -42,75 +65,43 @@ test-mergerq-rawhide-samsung980:
- .opal-template-fedora
tags:
- tiber
resource_group: samsung980-on-tiber
interruptible: false
stage: test
interruptible: true
variables:
PCI_PASSTHROUGH_VENDOR_ID: "144d"
PCI_PASSTHROUGH_DEVICE_ID: "a809"
# WD PC SN740 SDDQNQD-512G-1014 (on tiber machine)
# Disabled on 2025-03-20, seems broken
#test-commit-rawhide-sn740:
# rules:
# - if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
# when: never
# - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
# extends:
# - .opal-template-fedora
# tags:
# - tiber
# resource_group: sn740-on-tiber
# interruptible: false
# variables:
# PCI_PASSTHROUGH_VENDOR_ID: "15b7"
# PCI_PASSTHROUGH_DEVICE_ID: "5017"
# # WD PC SN740 SDDQNQD-512G-1014 (on tiber machine)
# test-commit-rawhide-sn740:
# rules:
# - if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
# when: never
# - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
# extends:
# - .opal-template-fedora
# tags:
# - tiber
# stage: test
# interruptible: true
# variables:
# PCI_PASSTHROUGH_VENDOR_ID: "15b7"
# PCI_PASSTHROUGH_DEVICE_ID: "5017"
#
# test-mergerq-rawhide-sn740:
# rules:
# - if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
# when: never
# - if: $CI_PIPELINE_SOURCE == "merge_request_event"
# extends:
# - .opal-template-fedora
# tags:
# - tiber
# stage: test
# interruptible: true
# variables:
# PCI_PASSTHROUGH_VENDOR_ID: "15b7"
# PCI_PASSTHROUGH_DEVICE_ID: "5017"
#
#test-mergerq-rawhide-sn740:
# rules:
# - if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
# when: never
# - if: $CI_PIPELINE_SOURCE == "merge_request_event"
# extends:
# - .opal-template-fedora
# tags:
# - tiber
# resource_group: sn740-on-tiber
# interruptible: false
# variables:
# PCI_PASSTHROUGH_VENDOR_ID: "15b7"
# PCI_PASSTHROUGH_DEVICE_ID: "5017"
# Samsung SSD 980 PRO 1TB (on trantor machine)
test-commit-rawhide-samsung980pro:
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
extends:
- .opal-template-fedora
tags:
- trantor
resource_group: samsung980pro-on-trantor
interruptible: false
variables:
PCI_PASSTHROUGH_VENDOR_ID: "144d"
PCI_PASSTHROUGH_DEVICE_ID: "a80a"
test-mergerq-rawhide-samsung980pro:
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
extends:
- .opal-template-fedora
tags:
- trantor
resource_group: samsung980pro-on-trantor
interruptible: false
variables:
PCI_PASSTHROUGH_VENDOR_ID: "144d"
PCI_PASSTHROUGH_DEVICE_ID: "a80a"
# # UMIS RPETJ256MGE2MDQ (on tiber machine)
# test-commit-rawhide-umis:
# rules:
@@ -121,9 +112,8 @@ test-mergerq-rawhide-samsung980pro:
# - .opal-template-fedora
# tags:
# - tiber
# resource_group: umis-on-tiber
# stage: test
# interruptible: false
# interruptible: true
# variables:
# PCI_PASSTHROUGH_VENDOR_ID: "1cc4"
# PCI_PASSTHROUGH_DEVICE_ID: "6302"
@@ -137,9 +127,8 @@ test-mergerq-rawhide-samsung980pro:
# - .opal-template-fedora
# tags:
# - tiber
# resource_group: umis-on-tiber
# stage: test
# interruptible: false
# interruptible: true
# variables:
# PCI_PASSTHROUGH_VENDOR_ID: "1cc4"
# PCI_PASSTHROUGH_DEVICE_ID: "6302"

View File

@@ -1,19 +1,22 @@
.dnf-openssl-backend:
variables:
DISTRO: cryptsetup-fedora-rawhide
PKGS: >-
extends:
- .fail_if_coredump_generated
before_script:
- >
[ -z "$RUN_SYSTEMD_PLUGIN_TEST" ] ||
sudo dnf -y -q install
swtpm meson ninja-build python3-jinja2 gperf libcap-devel tpm2-tss-devel
libmount-devel swtpm-tools
- >
sudo dnf -y -q install
autoconf automake device-mapper-devel gcc gettext-devel json-c-devel
libargon2-devel libblkid-devel libpwquality-devel libselinux-devel
libssh-devel libtool libuuid-devel make popt-devel
libsepol-devel.x86_64 netcat openssh-clients passwd pkgconfig sharutils
sshpass tar uuid-devel vim-common device-mapper expect gettext git jq
keyutils openssl-devel openssl asciidoctor swtpm meson ninja-build
python3-jinja2 gperf libcap-devel tpm2-tss-devel libmount-devel swtpm-tools
extends:
- .fail_if_coredump_generated
before_script:
- sudo dnf clean all
- (r=3;while ! sudo dnf -y -q install $PKGS ; do ((--r))||exit;sleep 5;echo "Retrying";done)
keyutils openssl-devel openssl asciidoctor
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-fips --enable-pwquality --enable-libargon2 --with-crypto_backend=openssl --enable-asciidoc
@@ -29,7 +32,6 @@ test-main-commit-job-rawhide:
allow_failure: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
@@ -50,7 +52,6 @@ test-mergerq-job-rawhide:
allow_failure: true
variables:
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never

View File

@@ -1,5 +1,5 @@
.gitlab-shared-docker:
image: ubuntu:noble
image: ubuntu:lunar
tags:
- gitlab-org-docker
stage: test
@@ -18,8 +18,7 @@
- .gitlab-shared-docker
variables:
COMPILER: "gcc"
COMPILER_VERSION: "14"
CC: "gcc-14"
COMPILER_VERSION: "11"
RUN_SSH_PLUGIN_TEST: "1"
.gitlab-shared-clang:
@@ -27,6 +26,5 @@
- .gitlab-shared-docker
variables:
COMPILER: "clang"
COMPILER_VERSION: "19"
CC: "clang-19"
COMPILER_VERSION: "17"
RUN_SSH_PLUGIN_TEST: "1"

View File

@@ -8,7 +8,7 @@
libblkid-devel libpwquality-devel libselinux-devel libssh-devel libtool
libuuid-devel make popt-devel libsepol-devel nc openssh-clients passwd
pkgconfig sharutils sshpass tar uuid-devel vim-common device-mapper
expect gettext git jq keyutils openssl-devel openssl gem
expect gettext git jq keyutils openssl-devel openssl gem > /dev/null 2>&1
- sudo gem install asciidoctor
- sudo -E git clean -xdf
- ./autogen.sh
@@ -60,29 +60,6 @@ test-main-commit-rhel9:
- make -j -C tests check-programs
- sudo -E make check
test-main-commit-rhel10:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- cryptsetup-rhel-10
stage: test
interruptible: true
allow_failure: true
variables:
DISTRO: cryptsetup-rhel-10
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
when: never
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
# FIPS jobs
test-main-commit-rhel8-fips:
@@ -103,7 +80,7 @@ test-main-commit-rhel8-fips:
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- grep -q fips=1 /proc/cmdline || exit 1
- fips-mode-setup --check || exit 1
- make -j
- make -j -C tests check-programs
- sudo -E make check
@@ -127,31 +104,7 @@ test-main-commit-rhel9-fips:
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- grep -q fips=1 /proc/cmdline || exit 1
- make -j
- make -j -C tests check-programs
- sudo -E make check
test-main-commit-rhel10-fips:
extends:
- .rhel-openssl-backend
tags:
- libvirt
- cryptsetup-rhel-10-fips
stage: test
interruptible: true
allow_failure: true
variables:
DISTRO: cryptsetup-rhel-10-fips
RUN_SSH_PLUGIN_TEST: "1"
rules:
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
when: never
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- grep -q fips=1 /proc/cmdline || exit 1
- fips-mode-setup --check || exit 1
- make -j
- make -j -C tests check-programs
- sudo -E make check

View File

@@ -1,22 +0,0 @@
#!/bin/bash
CSMOCK="sudo /usr/bin/csmock"
CSMOCK_TOOLS="gcc,clang,cppcheck,shellcheck"
CSMOCK_TXZ="cryptsetup-csmock-results.tar.xz"
CSMOCK_ERR="cryptsetup-csmock-results/scan-results.err"
$CSMOCK cryptsetup-*.src.rpm \
--keep-going --force \
--cswrap-timeout 300 \
--skip-patches \
--tools $CSMOCK_TOOLS \
--output $CSMOCK_TXZ \
--gcc-analyze \
--cppcheck-add-flag=--check-level=exhaustive \
|| { echo "csmock command failed"; exit 2; }
tar xJf $CSMOCK_TXZ $CSMOCK_ERR --strip-components 1 \
&& test -s $CSMOCK_ERR \
&& { echo "csmock discovered important errors"; echo 3; }
exit 0

View File

@@ -1,31 +0,0 @@
#!/bin/bash
set -e
DIR="_spellcheck"
[ ! -d $DIR ] && mkdir $DIR
echo "[SPELLINTIAN]"
git ls-tree -rz --name-only HEAD | grep -Evz -e '\.(pdf|xz)$' -e ^po/ | \
xargs -r0 spellintian | \
grep -v "(duplicate word)" | \
grep -v "docs/" | tee $DIR/spell1.txt
echo "[CODESPELL]"
git ls-tree -rz --name-only HEAD | grep -Evz -e '\.(pdf|xz)$' -e ^po/ | \
xargs -r0 codespell | \
grep -v "EXPCT" | \
grep -v "params, prams" | \
grep -v "pad, padded" | \
grep -v "CIPHER, CHIP" | \
grep -v "gost" | \
grep -v "userA" | \
grep -v "re-use" | \
grep -v "fo ==" | \
grep -v "docs/" | tee $DIR/spell2.txt
[ -s $DIR/spell1.txt ] && exit 1
[ -s $DIR/spell2.txt ] && exit 2
exit 0

View File

@@ -1,106 +0,0 @@
.ubuntu-prep:
extends:
- .fail_if_coredump_generated
before_script:
- sudo apt-get -y update
- >
sudo apt-get -y install -y -qq git gcc make autoconf automake autopoint
pkgconf libtool libtool-bin gettext libssl-dev libdevmapper-dev
libpopt-dev uuid-dev libsepol-dev libjson-c-dev libssh-dev libblkid-dev
tar libargon2-dev libpwquality-dev sharutils dmsetup jq xxd expect
keyutils netcat-openbsd passwd openssh-client sshpass asciidoctor
swtpm meson ninja-build python3-jinja2 gperf libcap-dev libtss2-dev
libmount-dev swtpm-tools tpm2-tools
# scsi_debug, gost crypto
- sudo apt-get -y install dkms linux-headers-$(uname -r) linux-modules-extra-$(uname -r) gost-crypto-dkms
- sudo apt-get -y build-dep cryptsetup
- sudo -E git clean -xdf
- ./autogen.sh
- ./configure --enable-libargon2 --enable-asciidoc
test-mergerq-job-ubuntu:
extends:
- .ubuntu-prep
tags:
- libvirt
- cryptsetup-ubuntu-2404
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-ubuntu-2404
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- 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
test-main-commit-job-ubuntu:
extends:
- .ubuntu-prep
tags:
- libvirt
- cryptsetup-ubuntu-2404
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-ubuntu-2404
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- make -j
- make -j -C tests check-programs
- sudo -E make check
# meson tests
test-mergerq-job-ubuntu-meson:
extends:
- .ubuntu-prep
tags:
- libvirt
- cryptsetup-ubuntu-2404
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-ubuntu-2404
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- sudo apt-get -y install -y -qq meson ninja-build
- meson setup build
- ninja -C build
- cd build && sudo -E meson test --verbose --print-errorlogs
test-main-commit-job-ubuntu-meson:
extends:
- .ubuntu-prep
tags:
- libvirt
- cryptsetup-ubuntu-2404
stage: test
interruptible: true
variables:
DISTRO: cryptsetup-ubuntu-2404
RUN_SSH_PLUGIN_TEST: "1"
RUN_KEYRING_TRUSTED_TEST: "1"
rules:
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
script:
- sudo apt-get -y install -y -qq meson ninja-build
- meson setup build
- ninja -C build
- cd build && sudo -E meson test --verbose --print-errorlogs

View File

@@ -1,158 +0,0 @@
Contributing to cryptsetup
==========================
For basic information about the cryptsetup project, please read [README](README.md).
The Cryptsetup project uses free, open-source licenses; details are described in [licensing](README.licensing).
For contribution code or documentation to the cryptsetup project, you must have the necessary rights to the content, and your contribution must be provided under the required license.
We welcome contributions from everyone.
Cryptsetup is an independent project with much volunteer effort, and our resources are limited.
Following the guidelines specified in this file makes it easier for us to process your issue.
Project maintainers can remove or reject abusive or otherwise unacceptable comments or code.
Git repository
--------------
The primary repository is located at [gitlab.com/cryptsetup/cryptsetup](https://gitlab.com/cryptsetup/cryptsetup).
The development branch is ``main``; minor stable releases can use their branches with cherry-picked or backported patches.
There are backup mirrors located at [github.com/mbroz/cryptsetup](https://github.com/mbroz/cryptsetup) and [git.kernel.org/pub/scm/utils/cryptsetup/cryptsetup.git](https://git.kernel.org/pub/scm/utils/cryptsetup/cryptsetup.git).
How to make a bug report
------------------------
To report an issue or feature request, please use GitLab [cryptsetup issue tracker](https://gitlab.com/cryptsetup/cryptsetup/-/issues).
Before reporting an issue, please try to search documentation and existing issues. Always try to reproduce the problem on the latest supported release.
Please *always* collect and attach ``--debug`` log and other information as instructed in the issue template.
Even if you think the problem is obvious, we need logged information about the environment (like versions of kernel modules, etc.).
Please do not report distribution-specific issues if they are not present in the latest upstream release.
For such reports, please use downstream distribution-specific trackers.
If the issue is related to upstream, downstream maintainers will redirect you here, or upstream maintainers will join the discussion.
If you think that you found some security bug, please follow the instructions in the [SECURITY](SECURITY.md) file.
How to contribute changes to cryptsetup
---------------------------------------
The following notes are a very short introduction to cryptsetup internal processes and an overview of generic rules that should be followed for all changes.
Changes from developers and external contributors should go through the GitLab repository [merge reguests](https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests).
Alternatively (for trivial changes), you can send a patch to [cryptsetup mailing list](mailto:cryptsetup@lists.linux.dev).
Please do not write personal emails with questions or patches to maintainers and developers.
### Project structure
Cryptsetup projects include a libcryptsetup library, tools, token plugins, documentation, and a test suite.
Cryptsetup library (libcryptsetup) exports [versioned symbols](lib/libcryptsetup.sym).
Tools (cryptsetup, veritysetup, integritysetup) use libcryptsetup shared library.
Some isolated parts in the lib directory can be reused for tools (the source is recompiled).
The basic directory structure in the repository is
```
├── docs - Documentation and release notes.
├── lib - libcryptsetup implementation
│   ├── bitlk - Bitlocker format
│   ├── crypto_backend - Cryptography backend
│   ├── fvault2 - FileVault2 format
│   ├── integrity - Linux dm-integrity interface
│   ├── loopaes - Linux LoopAES format
│   ├── luks1 - LUKS1 format
│   ├── luks2 - LUKS2 format including OPAL2 SED
│   ├── tcrypt - TrueCrypt / VeraCrypt format
│   └── verity - Linux dm-verity interface
├── man - Manual pages (in AsciiDoc format)
├── misc - Miscellaneous additions
├── po - Translation files
├── scripts - Scripts for system configuration
├── src - Tools implementation
├── tests - Testsuite (test units, regression tests, fuzzing)
└── tokens - Token plugins
```
### Coordination with other projects
The cryptsetup tools and library use low-level functions that depend on many other subsystems.
Currently, the project is supported only for Linux (it will not work on Android or other systems).
Cryptsetup project requires some parts of the Linux kernel, notably the *Device Mapper* (dm-crypt, dm-integrity, dm-verity, dm-zero modules) and kernel *userspace cryptographic interface*.
Missing kernel interface can significantly limit (or even disallow) cryptsetup functionality.
Integration in operating systems also depends on several other projects, most notably *systemd* (that implements its own tooling using libcryptsetup) and *util-Linux* (*blkid* parsing of supported format metadata). Some changes must be synchronized in all needed places (kernel, blkid, libcryptsetup).
Several other projects implement their own token metadata (either through binary token plugins or through generic libcryptsetup JSON token access functions).
### Used cryptography algorithms
Cryptsetup avoids implementing cryptographic primitives but uses cryptographic libraries.
Exceptions were PBKDF internal implementations - PBKDF2 and Argon2 until these were integrated into major cryptographic libraries.
Cryptsetup can be compiled with several cryptographic libraries backend (OpenSSL, libgcrypt, Nettle, NSS, and Linux kernel userspace API).
OpenSSL is the default and strongly recommended configuration.
If the cryptographic library does not implement some cryptographic primitive (for example, if running in a FIPS-140 environment or just
because it does not include it at all), functionality could be limited.
### Configuration and versioning
Cryptsetup can be configured using *Autoconf* or *Meson*. Autoconf support is being deprecated in the long term.
Currently, all new configuration options must be implemented in both systems.
Cryptsetup intentionally does not use a system configuration file (located in /etc).
All functionality must be determined dynamically.
All related /etc configuration files (crypttab, fstab and others) are maintained by systemd (in some legacy distributions by cryptsetup downstream).
Cryptsetup uses [semantic versioning](https://semver.org/).
Major and minor releases are always based on the main git branch; the minor stable (patch) versions can have some specific branch with backported or cherry-picked patches (from the main branch).
Usually, minor releases happen twice per year and stable patch updates according to reported bugs (in 1-3 month intervals).
### Compilation and debugging
The library and tools are written in C language; we require C99 and support gcc and Clang compilers.
Manual pages are generated from AsciiDoc sources and libcryptsetup API documentation by Doxygen (from libcryptsetup.h comments).
Testsuite is a combination of local C utilities, fuzzing implementation in C++, bash scripts, and uses many other system utilities.
All tools contain compiled-in debug messages that are available through --debug options.
With Autoconf and libtool, you can run the cryptsetup tool in the debugger without installation using this one-line script:
```
libtool --mode=execute gdb --args ./cryptsetup --debug $@
```
This will ensure that a properly compiled libcryptsetup file is used.
### Coding style
Cryptsetup uses [Linux kernel coding style](https://cdn.kernel.org/doc/html/latest/process/coding-style.html) for libcryptsetup and tools (where applicable) with some additional notes:
- Use tabulators for indentation; the line should not exceed 100 characters with an 8-character tabulator. Otherwise, use a tab of any length. :-).
- The minimal C standard required is C99.
- The ``goto`` use is allowed only for error path (``goto out`` for common code path, ``goto err`` for specific error code path).
- Split patches per change; do not submit huge patches combining several changes.
- Use an elaborative description in the patch header.
- No need to use sign-off-by lines.
- Use name prefixes (``crypt_``, ``LUKS2_`` and similar).
- Avoid extensive preprocessor use (specifically conditional ``#if`` or ``#ifdef`` sections).
- To check detected configuration options stored in config.h, always use ``#if SOMETHING`` (do NOT use ``#ifdef``).
- Use output only through ``log_err, log_std, log_verbose, log_dbg`` macros.
The ``log_dbg`` is always in English; the others should be wrapped in the ``_()`` macro for translation.
- Use ``assert()`` but only for simple invariants and variables (avoid calling functions).
Do not use assert for user-defined input (this should be a normal error path).
- The code style is quite relaxed in testing scripts (code there is not intended for production use).
### General rules and testing
- Cryptsetup should work on all architectures supported by the Linux kernel.
Only very few functionalities require specific hardware (notably Opal SED support).
If you want to introduce some specific hardware support, please discuss it with the maintainers first.
- All code changes should go through merge requests and reviews.
Code can be merged after review approval (done by someone with the commit right to the development repository), but reviews from external people are very welcome, too.
- All new functionality must come with at least rudimentary coverage in the test suite.
Always run the test suite before opening the merge request (``make check`` with root privilege).
- We have continuous integration (CI) that runs many tests automatically, but the output is not directly visible for external merge request authors (for security reasons).
All CI scripts are available in .gitlab and .github folders in the project repository.
Maintainers will provide you log files if anything fails. Your code must produce no warnings before it is merged.
- We run compilation with many extended [gcc](.gitlab/ci/gcc-Wall) and [Clang](.gitlab/ci/clang-Wall) warnings and include some analyzers, notably
- [Coverity](https://scan.coverity.com), GitHub CodeQL, Clang scan-build, and gcc static analyzer, and
- fuzzing integrated in [OSS-fuzz project](https://github.com/google/oss-fuzz/tree/master/projects/cryptsetup).
- Testsuite can also partially run under Valgrind dynamic analyzer with ``make valgrind-check``.

34
FAQ.md
View File

@@ -38,7 +38,7 @@
LUKS1 and LUKS2.
The LUKS1 on-disk format specification is at
https://cdn.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf
https://www.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf
The LUKS2 on-disk format specification is at
https://gitlab.com/cryptsetup/LUKS2-docs
@@ -169,12 +169,17 @@
me write the section. Please note that by contributing to this FAQ,
you accept the license described below.
This work is licensed under a Creative Commons CC-BY-SA-4.0
"Attribution-ShareAlike 4.0 International" license which means
distribution is unlimited, you may create derived works, but
This work is under the "Attribution-Share Alike 3.0 Unported" license,
which means distribution is unlimited, you may create derived works, but
attributions to original authors and this license statement must be
retained and the derived work must be under the same license.
See https://creativecommons.org/licenses/by-sa/4.0/ for more details.
retained and the derived work must be under the same license. See
https://creativecommons.org/licenses/by-sa/3.0/ for more details of the
license.
Side note: I did text license research some time ago and I think this
license is best suited for the purpose at hand and creates the least
problems.
* **1.6 Where is the project website?**
@@ -705,12 +710,9 @@
this. The only legitimate reason I can think of is if you want to have
two LUKS devices with the same volume key. Even then, I think it would
be preferable to just use key-slots with the same passphrase, or to use
plain dm-crypt instead.
plain dm-crypt instead. If you really have a good reason, please tell
me. If I am convinced, I will add how to do this here.
Use the --volume-key-file option, like this:
```
cryptsetup luksFormat --volume-key-file keyfile /dev/loop0
```
* **2.12 What are the security requirements for a key read from file?**
@@ -1926,6 +1928,10 @@
Hence, LUKS has no kill option because it would do much more harm than
good.
Still, if you have a good use-case (i.e. non-abstract real-world
situation) where a Nuke-Option would actually be beneficial, please let
me know.
* **5.22 Does cryptsetup open network connections to websites, etc. ?**
@@ -2679,7 +2685,8 @@ can be converted to the raw volume key for example via:
Note that at the time this FAQ item was written, 1.5.4 was the latest
1.5.x version and it has the flaw, i.e. works with the old Whirlpool
version. Possibly later 1.5.x versions will work as well.
version. Possibly later 1.5.x versions will work as well. If not,
please let me know.
The only two ways to access older LUKS containers created with Whirlpool
are to either decrypt with an old gcrypt version that has the flaw or to
@@ -2795,7 +2802,8 @@ can be converted to the raw volume key for example via:
03) Creating your own initrd
The two examples below should give you most of what is needed. This is
tested with LUKS1 and should work with LUKS2 as well.
tested with LUKS1 and should work with LUKS2 as well. If not, please
let me know.
Here is a really minimal example. It does nothing but set up some
things and then drop to an interactive shell. It is perfect to try out

View File

@@ -1,4 +1,4 @@
EXTRA_DIST = README.md SECURITY.md README.licensing CONTRIBUTING.md FAQ.md docs misc autogen.sh
EXTRA_DIST = README.md SECURITY.md COPYING.LGPL FAQ.md docs misc autogen.sh
EXTRA_DIST += meson_options.txt \
meson.build \
lib/crypto_backend/argon2/meson.build \

View File

@@ -1,20 +0,0 @@
The cryptsetup project does not use the same license for all of the code and documentation.
There is code and documentation under:
* GPL-2.0-or-later - GNU General Public License version 2, or any later version
* LGPL-2.1-or-later WITH cryptsetup-OpenSSL-exception
* LGPL-2.1-or-later - GNU Lesser General Public License 2.1 or any later version,
(with cryptsetup-OpenSSL-exception where applicable)
* Apache-2.0 - Apache License 2.0
* CC-BY-SA-4.0 - Creative Commons Attribution Share Alike 4.0 International
* Public Domain
Please, check the source code for more details.
The ./COPYING file (GPL-2.0-or-later) is the default license for code without
an explicitly defined license.

View File

@@ -30,22 +30,28 @@ which enables users to transport or migrate data seamlessly.
* The latest version of the
[LUKS2 format specification](https://gitlab.com/cryptsetup/LUKS2-docs).
* The latest version of the
[LUKS1 format specification](https://cdn.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf).
[LUKS1 format specification](https://www.kernel.org/pub/linux/utils/cryptsetup/LUKS_docs/on-disk-format.pdf).
* [Project home page](https://gitlab.com/cryptsetup/cryptsetup/).
* [Frequently asked questions (FAQ)](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions)
Download
--------
Release notes and tarballs are available at
[kernel.org](https://cdn.kernel.org/pub/linux/utils/cryptsetup/).
[kernel.org](https://www.kernel.org/pub/linux/utils/cryptsetup/).
**The latest stable cryptsetup release version is 2.8.0**
* [cryptsetup-2.8.0.tar.xz](https://cdn.kernel.org/pub/linux/utils/cryptsetup/v2.8/cryptsetup-2.8.0.tar.xz)
* Signature [cryptsetup-2.8.0.tar.sign](https://cdn.kernel.org/pub/linux/utils/cryptsetup/v2.8/cryptsetup-2.8.0.tar.sign)
**The latest stable cryptsetup release version is 2.7.1**
* [cryptsetup-2.7.1.tar.xz](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.7/cryptsetup-2.7.1.tar.xz)
* Signature [cryptsetup-2.7.1.tar.sign](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.7/cryptsetup-2.7.1.tar.sign)
_(You need to decompress file first to check signature.)_
* [Cryptsetup 2.8.0 Release Notes](https://cdn.kernel.org/pub/linux/utils/cryptsetup/v2.8/v2.8.0-ReleaseNotes).
* [Cryptsetup 2.7.1 Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.7/v2.7.1-ReleaseNotes).
[Previous versions](https://cdn.kernel.org/pub/linux/utils/cryptsetup)
Previous versions
* [Version 2.6.1](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.6/cryptsetup-2.6.1.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.6/cryptsetup-2.6.1.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v2.5/v2.5.0-ReleaseNotes).
* [Version 1.7.5](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz) -
[Signature](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.sign) -
[Release Notes](https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/v1.7.5-ReleaseNotes).
Source and API documentation
----------------------------
@@ -70,7 +76,8 @@ Below are the packages needed to build for certain Linux distributions:
**For Fedora**:
```
git gcc make autoconf automake gettext-devel pkgconfig openssl-devel popt-devel device-mapper-devel libuuid-devel json-c-devel libblkid-devel findutils libtool libssh-devel tar
git gcc make autoconf automake gettext-devel pkgconfig openssl-devel popt-devel device-mapper-devel
libuuid-devel json-c-devel libblkid-devel findutils libtool libssh-devel tar
Optionally: libargon2-devel libpwquality-devel
```
@@ -81,13 +88,14 @@ sharutils device-mapper jq vim-common expect keyutils netcat shadow-utils openss
**For Debian and Ubuntu**:
```
git gcc make autoconf automake autopoint pkg-config libtool gettext libssl-dev libdevmapper-dev libpopt-dev uuid-dev libsepol-dev libjson-c-dev libssh-dev libblkid-dev tar
git gcc make autoconf automake autopoint pkg-config libtool gettext libssl-dev libdevmapper-dev
libpopt-dev uuid-dev libsepol1-dev libjson-c-dev libssh-dev libblkid-dev tar
Optionally: libargon2-0-dev libpwquality-dev
```
To run the internal testsuite (make check) you also need to install
```
sharutils dmsetup jq xxd expect keyutils netcat-openbsd passwd openssh-client sshpass
sharutils dmsetup jq xxd expect keyutils netcat passwd openssh-client sshpass
```
Note that the list may change as Linux distributions evolve.

View File

@@ -1,9 +1,9 @@
AC_PREREQ([2.67])
AC_INIT([cryptsetup],[2.8.0])
AC_INIT([cryptsetup],[2.7.1])
dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
LIBCRYPTSETUP_VERSION_INFO=23:0:11
LIBCRYPTSETUP_VERSION_INFO=22:0:10
AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR(src/cryptsetup.c)
@@ -132,6 +132,7 @@ AC_C_BIGENDIAN
AC_TYPE_OFF_T
AC_SYS_LARGEFILE
AC_FUNC_FSEEKO
AC_PROG_GCC_TRADITIONAL
AC_FUNC_STRERROR_R
dnl ==========================================================================
@@ -399,23 +400,6 @@ AC_DEFUN([CONFIGURE_NETTLE], [
NO_FIPS([])
])
AC_DEFUN([CONFIGURE_MBEDTLS], [
AC_CHECK_HEADERS(mbedtls/version.h,,
[AC_MSG_ERROR([You need mbedTLS cryptographic library.])])
saved_LIBS=$LIBS
AC_CHECK_LIB(mbedcrypto, mbedtls_md_init,,
[AC_MSG_ERROR([You need mbedTLS cryptographic library.])])
AC_CHECK_FUNCS(mbedtls_pkcs5_pbkdf2_hmac_ext)
CRYPTO_LIBS=$LIBS
LIBS=$saved_LIBS
CRYPTO_STATIC_LIBS=$CRYPTO_LIBS
use_internal_pbkdf2=0
use_internal_argon2=1
NO_FIPS([])
])
dnl ==========================================================================
saved_LIBS=$LIBS
@@ -498,7 +482,7 @@ fi
dnl Crypto backend configuration.
AC_ARG_WITH([crypto_backend],
AS_HELP_STRING([--with-crypto_backend=BACKEND], [crypto backend (gcrypt/openssl/nss/kernel/nettle/mbedtls) [openssl]]),
AS_HELP_STRING([--with-crypto_backend=BACKEND], [crypto backend (gcrypt/openssl/nss/kernel/nettle) [openssl]]),
[], [with_crypto_backend=openssl])
dnl Kernel crypto API backend needed for benchmark and tcrypt
@@ -518,7 +502,6 @@ case $with_crypto_backend in
nss) CONFIGURE_NSS([]) ;;
kernel) CONFIGURE_KERNEL([]) ;;
nettle) CONFIGURE_NETTLE([]) ;;
mbedtls) CONFIGURE_MBEDTLS([]) ;;
*) AC_MSG_ERROR([Unknown crypto backend.]) ;;
esac
AM_CONDITIONAL(CRYPTO_BACKEND_GCRYPT, test "$with_crypto_backend" = "gcrypt")
@@ -526,7 +509,6 @@ AM_CONDITIONAL(CRYPTO_BACKEND_OPENSSL, test "$with_crypto_backend" = "openssl")
AM_CONDITIONAL(CRYPTO_BACKEND_NSS, test "$with_crypto_backend" = "nss")
AM_CONDITIONAL(CRYPTO_BACKEND_KERNEL, test "$with_crypto_backend" = "kernel")
AM_CONDITIONAL(CRYPTO_BACKEND_NETTLE, test "$with_crypto_backend" = "nettle")
AM_CONDITIONAL(CRYPTO_BACKEND_MBEDTLS, test "$with_crypto_backend" = "mbedtls")
AM_CONDITIONAL(CRYPTO_INTERNAL_PBKDF2, test $use_internal_pbkdf2 = 1)
AC_DEFINE_UNQUOTED(USE_INTERNAL_PBKDF2, [$use_internal_pbkdf2], [Use internal PBKDF2])

View File

@@ -1,8 +1,21 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* libcryptsetup API log example
*
* Copyright (C) 2011-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2024 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>

View File

@@ -1,8 +1,21 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* libcryptsetup API - using LUKS device example
*
* Copyright (C) 2011-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2024 Red Hat, Inc. All rights reserved.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>

View File

@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,428 +0,0 @@
Attribution-ShareAlike 4.0 International
=======================================================================
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution-ShareAlike 4.0 International Public
License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-ShareAlike 4.0 International Public License ("Public
License"). To the extent this Public License may be interpreted as a
contract, You are granted the Licensed Rights in consideration of Your
acceptance of these terms and conditions, and the Licensor grants You
such rights in consideration of benefits the Licensor receives from
making the Licensed Material available under these terms and
conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. BY-SA Compatible License means a license listed at
creativecommons.org/compatiblelicenses, approved by Creative
Commons as essentially the equivalent of this Public License.
d. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
e. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
f. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
g. License Elements means the license attributes listed in the name
of a Creative Commons Public License. The License Elements of this
Public License are Attribution and ShareAlike.
h. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
i. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
j. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
k. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
l. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
m. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part; and
b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. Additional offer from the Licensor -- Adapted Material.
Every recipient of Adapted Material from You
automatically receives an offer from the Licensor to
exercise the Licensed Rights in the Adapted Material
under the conditions of the Adapter's License You apply.
c. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
b. ShareAlike.
In addition to the conditions in Section 3(a), if You Share
Adapted Material You produce, the following conditions also apply.
1. The Adapter's License You apply must be a Creative Commons
license with the same License Elements, this version or
later, or a BY-SA Compatible License.
2. You must include the text of, or the URI or hyperlink to, the
Adapter's License You apply. You may satisfy this condition
in any reasonable manner based on the medium, means, and
context in which You Share Adapted Material.
3. You may not offer or impose any additional or different terms
or conditions on, or apply any Effective Technological
Measures to, Adapted Material that restrict exercise of the
rights granted under the Adapter's License You apply.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material,
including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.

View File

@@ -1,354 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
-----
In addition, as a special exception, the copyright holders give
permission to link the code of portions of this program with the
OpenSSL library under certain conditions as described in each
individual source file, and distribute linked combinations
including the two.
You must obey the GNU General Public License in all respects
for all of the code used other than OpenSSL. If you modify
file(s) with this exception, you may extend this exception to your
version of the file(s), but you are not obligated to do so. If you
do not wish to do so, delete this exception statement from your
version. If you delete this exception statement from all source
files in the program, then also delete it here.

Binary file not shown.

View File

@@ -1,31 +0,0 @@
Cryptsetup 2.7.2 Release Notes
==============================
Stable bug-fix release.
All users of cryptsetup 2.7 should upgrade to this version.
Changes since version 2.7.1
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix activation of OPAL-only encrypted LUKS device with tokens.
The issue was caused by an invalid volume key check (assert)
that is impossible without software encryption.
* Fix formatting of OPAL devices with 4096-byte sector size.
* Fix incorrect OPAL locking range alignment calculation if used
over an unaligned device partition.
* Add --hw-opal-factory-reset option description to the manual page.
* Do not check the passphrase quality for OPAL Admin PIN,
as this passphrase already exists.
* Update license for FAQ document to CC BY-SA 4.0.
NOTE: Please note that with OPAL-only (--hw-opal-only) encryption,
the configured OPAL administrator PIN (passphrase) allows unlocking
all configured locking ranges without LUKS keyslot decryption
(without knowledge of LUKS passphrase).
Because of many observed problems with compatibility, cryptsetup
currently DOES NOT use OPAL single-user mode, which would allow such
decoupling of OPAL admin PIN access.

View File

@@ -1,114 +0,0 @@
Cryptsetup 2.7.3 Release Notes
==============================
Stable bug-fix release with security fixes.
All users of cryptsetup 2.7 must upgrade to this version.
Changes since version 2.7.2
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Do not allow formatting LUKS2 with Opal SED (hardware encryption)
if the reported logical sector size for the block device and Opal
encryption logical block differs.
Such a configuration can lead to a partially encrypted Opal locking
range or data destruction following the expected locking range.
Some NVMe drives support multiple LBAF profiles (typically supporting
512-byte and 4096-byte sector size). Some broken Opal NVMe firmware can
report bogus encryption size that disagrees with real used sector size.
This usually happens after low-level NVMe reformatting (LBAF profile
change with nvme utility) to different sector size.
Moreover, some firmware versions do not properly reset this even after
explicit PSID revert.
Cryptsetup calculates the Opal locking range using the reported block
size in Opal geometry ioctl. Unfortunately, the broken firmware drive
internally uses the logical block size of the block device, which can
differ. This can lead to two possible situations:
- Opal reports a smaller block size (512-byte) while the drive uses
a 4096-byte sector. The configured locking range is then much larger,
destroying data following the expected locking range setting.
- Opal reports a larger block size (4096-byte) while the drive uses
a 512-byte sector. The configured locking range is then much smaller,
leaving the remaining space in the locking range unencrypted (violating
the confidentiality of data).
Cryptsetup now detects this discrepancy and disallows LUKS2 format with
Opal hardware encryption in such a case.
For already formatted devices, you will see this warning:
"Bogus OPAL logical block size differs from device block size."
If you also used software encryption (dm-crypt over Opal), data will
still be fully encrypted with software dm-crypt.
With hw-only encryption, your configuration is probably already broken
(insecure or accessing data beyond the assigned area).
Note that this is caused by bad firmware (seen with multiple vendors),
and the problem was reported, at least for drives we have access to.
* Fixes to wiping LUKS2 headers after Opal locking area erase.
As the hardware locking range is destroyed (cryptsetup erase command),
the LUKS2 header is no longer usable and was partially wiped.
Now the code fully wipes also the secondary header, as the previous
code wiped only the primary LUKS area.
Note that this is an exception, as the normal erase command wipes only
the keyslots, keeping the LUKS2 header in place. With Opal encryption,
the data segment is no longer valid, so the whole LUKS2 header is no
longer usable.
* Mention the need for possible PSID revert before Opal format for some
drives (man page).
* Fix Bitlocker-compatible code to ignore newly seen metadata entries.
Recent Windows OS versions started to include new (undocumented)
metadata entries in Bitlocker. These entries are now quietly ignored,
allowing Bitlocker images to open with cryptsetup again.
* Fix interactive query retry if LUKS2 unbound keyslot is present.
If an unbound keyslot is present, the password query retry count is
now properly applied.
* Detect unsupported zoned devices for LUKS header devices.
Zoned devices cannot be written with direct-io and used for LUKS header
logic in general. Code now rejects placing the LUKS header on a zoned
device, while you can still create a detached header and use a zoned
device for encrypted data.
* Allow "capi" cipher format for benchmark command and fix parsing
of plain IV in "capi" format.
Some ciphers can be specified only in Linux kernel crypto notation
(in short, "capi"). Code now allows this format also for benchmark,
for example, "benchmark -c capi:xts\(aes\)-plain64"
(that is equivalent to -c aes-xts-plain64).
* Add support for HCTR2 encryption mode.
The HCTR2 encryption mode was added to the Linux kernel for fscrypt,
but as it is a length-preserving mode (with sector tweak), it can be
easily used for disk encryption, too.
The mode has the same property as wide modes (any change is propagated
to the whole sector instead of only one block as in XTS mode).
As it needs a larger initialization vector (32 bytes), we need to add
an exception in the userspace format code.
You can now use --cipher aes-hctr2-plain64 for the format operation.
* Source code now uses SPDX license identifiers instead of full
license preambles.
* Fix missing includes for cryptographic backend that could cause
compilation errors for some systems.
* Fix tests to work correctly in FIPS mode with recent OpenSSL 3.2.
* Fix various (mostly false positive) issues detected by Coverity.

View File

@@ -1,62 +0,0 @@
Cryptsetup 2.7.4 Release Notes
==============================
Stable bug-fix release.
All users of cryptsetup 2.7 should upgrade to this version.
Changes since version 2.7.3
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Detect device busy failure for device-mapper table-referenced devices.
Some device-mapper ioctl failures can disappear in libdevmapper,
causing the libcryptsetup wrapper to return an invalid error (EINVAL)
instead of EEXIST or EBUSY. One such case is when there is a device
creation race, and the device-mapper device name is created, but
the following mapping table load fails. This can happen because some
block devices used in table mapping have already been claimed by
another process (the kernel needs exclusive access).
The kernel ioctl properly returns EBUSY; this errno is lost in
libdevmapper (dm_task_get_errno returns 0). It should be fixed by
libdevmapper in the future.
Such behavior was seen in the systemd way of handling dm-verity
devices. With these changes, the code should react for EEXIST and
EBUSY, as another process has already activated the device.
Code calling libcryptsetup also must not check the underlying device
with an exclusive open flag (O_EXCL). Otherwise, it could cause a race
in the kernel device-mapper, resulting in no process succeeding device
activation (see also CRYPT_ACTIVATE_SHARED flag below).
* Fix shared activation for dm-verity devices.
The CRYPT_ACTIVATE_SHARED flag was silently ignored when activating
dm-verity devices. Dm-verity shared activation is generally safe
since all verity devices are read-only.
The shared flag is a way to skip the exclusive access check for the
device, allowing it to create multiple mappings with the same device or
properly handle a racy concurrent activation of devices with the same
name from different processes.
* Add --shared option for veritysetup open action.
The option allows the data device to be used in multiple device-mapper
table mappings (skip exclusive access check) or to allow concurrent
dm-verity device activation of the same device (only one process
succeeds in this case; the other will return EEXIST or EBUSY).
* Do not use exclusive flag for the allocated backing loop files.
Using this flag is an undefined operation for opening an existing file.
The flag should be used only for allocated loop (block) devices.
* Fixes for problems found by static analyzers and Valgrind.
These include fixes for non-default libgcrypt, NSS, and Nettle
cryptographic backends, buffer operations to avoid partial read/write,
and several other workarounds for mostly false positive warnings.
* Fixes to tests and CI scripts.

View File

@@ -1,23 +0,0 @@
Cryptsetup 2.7.5 Release Notes
==============================
Stable bug-fix release.
All users of cryptsetup 2.7 must upgrade to this version.
Changes since version 2.7.4
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Fix possible online reencryption data corruption (only in 2.7.x).
In some situations (initializing a suspended device-mapper device),
cryptsetup disabled direct-io device access. This caused unsafe
online reencryption operations that could lead to data corruption.
The code now adds strict checks (and aborts the operation) and
changes direct-io detection code to prevent data corruption.
* Fix a clang compilation error in SSH token plugin.
As clang linker treats missing symbols as errors, the linker phase
for the SSH token failed as the optional cryptsetup_token_buffer_free
was not defined.
* Fix crypto backend initialization in crypt_format_luks2_opal API call.

View File

@@ -1,328 +0,0 @@
Cryptsetup 2.8.0 Release Notes
==============================
Stable release with new features and bug fixes
All users of cryptsetup 2.7 must upgrade to this version.
Changes since version 2.7.5
~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Introduce support for inline mode (use HW sectors with additional hardware metadata space).
Some enterprise NVMe drives allow formatting sector size with additional metadata space,
for example, sector size 4096 bytes + 64 bytes for metadata.
We hope common firmware will soon support such features in more recent models.
If this metadata space is available (not internally used by a data integrity profile),
it removes the need to use the dm-integrity layer for sector metadata allocation.
This means that the performance bottleneck caused by the dm-integrity journal is eliminated.
Note: such drive must be reformatted with an external nvme tool.
You can check for support (reported as LBA format) by running the command
"nvme id-ns -H <nvme device>" and then you can reformat to the selected profile
(with complete data loss) with "nvme format -l <lbaf>.
This way, you can also reformat NVMe drive to 4096-byte sectors,which is strongly recommended
for encryption performance.
The required device mapper for inline mode was introduced in Linux kernel version 6.11.
The inline mode can be used with the new --integrity-inline option.
For integritysetup, the kernel dm-integrity layer is still used, but it directly maps metadata
to the hardware (eliminating the journal).
For cryptsetup, the dm-integrity layer is eliminated, and only the dm-crypt kernel driver is used.
The libcryptsetup exports a new crypt_format_inline API call.
Examples (underlying device must provide inline HW metadata space):
Use integritysetup format with inline mode with default CRC32 checksums:
# integritysetup format --sector-size 4096 --integrity-inline <device> [--no-wipe]
# integritysetup open <device> test
# integritysetup status test
/dev/mapper/test is active.
type: INTEGRITY
tag size: 4 [bytes]
integrity: crc32c
device: <device>
sector size: 4096 [bytes]
...
inline mode
journal: not active
Use LUKS2 with authenticated encryption (here with AEGIS AEAD cipher):
# cryptsetup luksFormat --integrity-inline --integrity aead --sector-size 4096 \
-c aegis128-random --key-size 128 <device> [--integrity-no-wipe]
# cryptsetup open <device> test
# cryptsetup luksDump <device>
...
Requirements: inline-hw-tags
After format, the inline mode is used automatically, and no special options are needed.
Please check the manual pages for more details about used options.
Note that the LUKS2 authenticated encryption is still an experimental feature.
The inline mode only improves performance by removing the dm-integrity layer.
* Finalize use of keyslot context API.
Keyslot context is a generic abstraction over keyslot manipulation.
It extends many exiting commands by additional functions like tokens in activation, resume,
reencryption and similar commands without introducing new specific API functions.
* Make all keyslot context types fully self-contained.
In the previous version, the caller is responsible for releasing of some allocated memory.
In this version, all memory is allocated internally. The existing keyslot context API function
provides backward compatibility through versioned symbols.
* Add --key-description and --new-key-description cryptsetup options.
These can be used for the specification of the keyring with passphrase retrieval in the open,
resize, luksResume, luksFormat, luksAddKey and luksDump.
* Support more precise keyslot selection in reencryption initialization.
Reencryption must update stored keys in keyslots, so it needs to unlock all keyslots first.
When no specific keyslot is selected by the --key-slot option, all active keyslots are updated.
Users may narrow down the selection of keyslots by specifying either --token-id, --token-type
or --token-only option. Only keyslots associated with the specific token (--token-id) or
a specific type (--token-type) or any token (--token-only) will be updated.
All other keyslots will be erased after reencryption is finished.
During reencryption, there are two volume keys (old and new).
For very specific use cases, reencryption can also be initialized by providing
volume keys directly by --volume-key-file, --new-volume-key-file, --volume-key-keyring
or --new-volume-key-keyring options. These options allow reencryption of the device with
no active keyslots (these can be added later).
If the --force-no-keyslots option is specified, all active keyslots will be erased after
the reencryption operation is finished.
* Allow reencryption to resume using token and volume keys.
The reencryption can be resumed using tokens (similar to initialization described above).
For very specific use cases, reencryption can be resumed by providing volume keys.
* Cryptsetup repair command now tries to check LUKS keyslot areas for corruption.
A keyslot binary area contains an encrypted volume key diffused to a larger area by
the anti-forensic splitter. If this area is corrupted, the keyslot can no longer be unlocked,
even with the correct password.
Active keyslot area should look like random data, so some specific corruption can be detected
by randomness analysis.
Cryptsetup repair command now tries to analyze the area expecting a uniform distribution
of bytes in 4096-byte blocks. If a problem is detected, it tries to localize corruption
in a smaller block (using the expected bit count).
Both tests are based on the Chi-squared statistical test.
This analysis can replace the external keyslot check program and usually is more sensitive.
However, it cannot detect all corruptions and can produce false positives.
Please use it as a hint when your password is no longer accepted, and you suspect
header corruption. This is the example output of the analysis:
# cryptsetup repair <device>
Keyslot 2 binary data could be corrupted.
Suspected offset: 0x88000
You can use hexdump -v -C -n 128 -s <offset_0xXXXX> <device> to inspect the data.
The test does not modify the header. A keyslot corruption cannot be repaired.
You have to use a backup header.
* Opal2 SED: PSID keyfile is now expected to be 32 alphanumeric characters.
If the keyfile size is not explicitly set, it uses only first 32 bytes.
All Opal2 manufacturers seem to use PSID of this length.
* Opal2: Avoid the Erase method and use Secure Erase for locking range.
The Erase method is defined for Single-user mode (SUM) and works on SUM-enabled locking ranges.
As we do not use SUM yet, this always fails and falls back to Secure erase anyway.
* Opal2: Fix some error description (in debug only).
Some Opal error messages were incorrect.
Cryptsetup now use all codes according to TCG specifications.
* Opal2: Do not allow deferred deactivation.
The self-encrypting drive must be locked immediately; deferred deactivation is not supported.
* Allow --reduce-device-size and --device-size combination for reencryption (encrypt) action.
For some very specific cases, this can be used to encrypt only part of the device together
with allocation a new space for the LUKS header.
* Fix the userspace storage backend to support kernel "capi:" cipher specification format.
This avoids unnecessary fallback to the device-mapper instead of the userspace crypto library
in luksFormat. The "capi:" is Linux kernel cryptographic format.
For example, capi:xts(aes)-plain64 is equivalent of aes-xts-plain64.
* Disallow conversion from LUKS2 to LUKS1 if kernel "capi:" cipher specification is used.
LUKS1 never officially supported this cipher specification format.
Such devices cannot be converted to LUKS1 (while existing devices can still be activated).
* Explicitly disallow kernel "capi:" cipher specification format for LUKS2 keyslot encryption.
This specification is intended to be used for data encryption, not for keyslots.
* Do not allow conversion of LUKS2 to LUKS1 if an unbound keyslot is present.
LUKS1 does not support unbound keyslots. Such devices cannot be converted.
* cryptsetup: Adjust the XTS key size for kernel "capi:" cipher specification.
Double key size as there are two keys the same way as for dm-crypt format.
* Remove keyslot warning about possible failure due to low memory.
This check was intended to warn users about possible out-of-memory situations
but produced many false positives.
* Do not limit Argon2 KDF memory cost on systems with more than 4GB of available memory.
The memory cost is intended to be limited only in low-memory situations (like virtual machines
without swap), not on systems with plenty of RAM.
* Properly report out of memory error for cryptographic backends implementing Argon2.
* Avoid KDF2 memory cost overflow on 32-bit platforms.
* Do not use page size as a fallback for device block size.
This check produced wrong values if used on platforms with larger page sizes (64kB)
and specific underlying storage (like ZFS).
* veritysetup: Check hash device size in advance.
If hashes are stored in a file image, allocate the size in advance.
For a block device, check if hashes (Merkle tree) fits the device.
* Print a better error message for unsupported LUKS2 AEAD device resize.
* Optimize LUKS2 metadata writes.
LUKS2 supports several JSON area length configurations. Do not write full metadata
(including padding), as it may generate noticeable overhead with LUKS2.
* veritysetup: support --error-as-corruption option.
The panic/restart_on_error options were introduced in Linux kernel 6.12 and process errors
(like media read error) the same way as data corruption.
Use this flag in combination with --panic-on-corruption or --restart-on-corruption.
* Report all sizes in status and dump command output in the correct units.
Since the support of --sector-size option, the meaning of "sectors" became ambiguous as it
usually means 512-byte sectors (device-mapper unit). Confusion occurs when the sector size
is 4096 bytes while units used for display are 512-byte sectors.
All status commands in tools now display units explicitly to avoid confusion.
For example:
# cryptsetup status test
...
sector size: 4096 [bytes]
offset: 32768 [512-byte units] (134217728 [bytes])
size: 7501443760 [512-byte units] (30725913640960 [bytes])
If you parse the output of status commands, please check your scripts to ensure they work
with the new output properly.
* Add --integrity-key-size option to cryptsetup.
This option can be used to set up non-standard integrity key size (e.g. for HMAC).
It adds a new (optional) JSON "key_size" attribute in the segment.integrity JSON object
(see updated LUKS2 specification). If not set, the code uses selected hash length size.
* Support trusted & encrypted keyrings for plain devices.
* Support plain format resize with a keyring key.
If a plain dm-crypt device references the keyring, cryptsetup now allows resizing.
The user must ensure that the key in the keyring is unchanged since activation.
Otherwise, reloading the key can cause data corruption after an unexpected key change.
* TCRYPT: Clear mapping of system-encrypted partitions.
TrueCrypt/VeraCrypt supports full system encryption (only a partition table is not encrypted)
or system partition encryption (only a system partition is encrypted).
The metadata header then contains the offset and size of the encrypted area.
Cryptsetup needs to know the specific partition offset to calculate encryption parameters.
To properly map a partition, the user must specify a real partition device so cryptsetup
can calculate this offset. As the partition can be an image in a file, cryptsetup now tries
to determine proper parameters and use device size stored in VeraCrypt metadata.
Please see the manual page description (TCRYPT section) for a detailed description.
* TCRYPT: Print all information from the decrypted metadata header in the tcryptDump command.
Print also volume sizes (if present) and flags.
* Always lock the volume key structure in memory.
Some memory for safe allocation was not allocated from locked (unswappable) memory.
Older cryptsetup locked all memory. Selective locking was introduced in version 2.6.0.
* Do not run direct-io read check on block devices.
Block devices always support direct-io.
This check produced unnecessary error with locked Opal2 devices.
* Fix a possible segfault in deferred deactivation.
Thanks Clément Guérin for the report.
* Exclude cipher allocation time from the cryptsetup benchmark.
* Add Mbed-TLS optional crypto backend.
Mbed-TLS is a tiny TLS implementation designed for embedded environments.
The backend can be enabled with the --with-crypto_backend=mbedtls configure option.
* Fix the wrong preprocessor use of #ifdef for config.h processed by Meson.
Cryptsetup supports Autoconf and, optionally, Meson configuration.
Part of the code wrongly used #ifdef instead of #if conditional sections.
This caused problems with Meson-generated config.h.
* Reorganize license files.
The license text files are now in docs/licenses.
The COPYING file in the root directory is the default license.
Libcryptsetup API extensions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The libcryptsetup API is backward compatible with all existing symbols.
Due to the self-contained memory allocation, these symbols have the new version
crypt_keyslot_context_init_by_passphrase;
crypt_keyslot_context_init_by_keyfile;
crypt_keyslot_context_init_by_token;
crypt_keyslot_context_init_by_volume_key;
crypt_keyslot_context_init_by_signed_key;
crypt_keyslot_context_init_by_keyring;
crypt_keyslot_context_init_by_vk_in_keyring;
New symbols:
crypt_format_inline
crypt_get_old_volume_key_size
crypt_reencrypt_init_by_keyslot_context
crypt_safe_memcpy
New defines:
CRYPT_ACTIVATE_HIGH_PRIORITY
CRYPT_ACTIVATE_ERROR_AS_CORRUPTION
CRYPT_ACTIVATE_INLINE_MODE
CRYPT_REENCRYPT_CREATE_NEW_DIGEST
New requirement flag:
CRYPT_REQUIREMENT_INLINE_HW_TAGS

View File

@@ -1,10 +1,23 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* BITLK (BitLocker-compatible) volume handling
*
* Copyright (C) 2019-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2025 Milan Broz
* Copyright (C) 2019-2025 Vojtech Trefny
* Copyright (C) 2019-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2024 Milan Broz
* Copyright (C) 2019-2024 Vojtech Trefny
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
@@ -311,9 +324,6 @@ static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, in
/* unknown timestamps in recovery protected VMK */
} else if (key_entry_value == BITLK_ENTRY_VALUE_RECOVERY_TIME) {
;
/* optional hint (?) string (masked email?), we can safely ignore it */
} else if (key_entry_value == BITLK_ENTRY_VALUE_HINT) {
;
} else if (key_entry_value == BITLK_ENTRY_VALUE_STRING) {
if (key_entry_size < BITLK_ENTRY_HEADER_LEN)
return -EINVAL;
@@ -343,9 +353,6 @@ static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, in
/* no idea what this is, lets hope it's not important */
} else if (key_entry_value == BITLK_ENTRY_VALUE_USE_KEY && (*vmk)->protection == BITLK_PROTECTION_STARTUP_KEY) {
;
/* quietly ignore unsupported TPM key */
} else if (key_entry_value == BITLK_ENTRY_VALUE_TPM_KEY && (*vmk)->protection == BITLK_PROTECTION_TPM) {
;
} else {
if (supported) {
log_err(cd, _("Unexpected metadata entry value '%u' found when parsing supported Volume Master Key."), key_entry_value);
@@ -375,8 +382,10 @@ void BITLK_bitlk_vmk_free(struct bitlk_vmk *vmk)
struct bitlk_vmk *vmk_next = NULL;
while (vmk) {
free(vmk->guid);
free(vmk->name);
if (vmk->guid)
free(vmk->guid);
if (vmk->name)
free(vmk->name);
crypt_free_volume_key(vmk->vk);
vmk_next = vmk->next;
free(vmk);
@@ -390,7 +399,8 @@ void BITLK_bitlk_metadata_free(struct bitlk_metadata *metadata)
return;
free(metadata->guid);
free(metadata->description);
if (metadata->description)
free(metadata->description);
BITLK_bitlk_vmk_free(metadata->vmks);
BITLK_bitlk_fvek_free(metadata->fvek);
}
@@ -714,8 +724,10 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
start += entry_size;
}
out:
free(fve_entries);
if (fve_entries)
free(fve_entries);
return r;
}
@@ -737,7 +749,7 @@ int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_meta
log_std(cd, "Description: \t%s\n", params->description);
log_std(cd, "Cipher name: \t%s\n", params->cipher);
log_std(cd, "Cipher mode: \t%s\n", params->cipher_mode);
log_std(cd, "Cipher key: \t%u [bits]\n", params->key_size);
log_std(cd, "Cipher key: \t%u bits\n", params->key_size);
log_std(cd, "\n");
@@ -756,15 +768,15 @@ int BITLK_dump(struct crypt_device *cd, struct device *device, struct bitlk_meta
vk_p = vmk_p->vk;
while (vk_p) {
log_std(cd, "\tKey data size:\t%zu [bytes]\n", crypt_volume_key_length(vk_p));
vk_p = crypt_volume_key_next(vk_p);
log_std(cd, "\tKey data size:\t%zu [bytes]\n", vk_p->keylength);
vk_p = vk_p->next;
}
vmk_p = vmk_p->next;
next_id++;
}
log_std(cd, " %d: FVEK\n", next_id);
log_std(cd, "\tKey data size:\t%zu [bytes]\n", crypt_volume_key_length(params->fvek->vk));
log_std(cd, "\tKey data size:\t%zu [bytes]\n", params->fvek->vk->keylength);
log_std(cd, "\n");
@@ -1053,14 +1065,11 @@ static int decrypt_key(struct crypt_device *cd,
int r;
uint16_t key_size = 0;
outbuf = crypt_safe_alloc(crypt_volume_key_length(enc_key));
outbuf = crypt_safe_alloc(enc_key->keylength);
if (!outbuf)
return -ENOMEM;
r = crypt_bitlk_decrypt_key(crypt_volume_key_get_key(key),
crypt_volume_key_length(key),
crypt_volume_key_get_key(enc_key), outbuf,
crypt_volume_key_length(enc_key),
r = crypt_bitlk_decrypt_key(key->key, key->keylength, enc_key->key, outbuf, enc_key->keylength,
(const char*)iv, iv_size, (const char*)tag, tag_size);
if (r < 0) {
if (r == -ENOTSUP)
@@ -1071,10 +1080,9 @@ static int decrypt_key(struct crypt_device *cd,
/* key_data has it's size as part of the metadata */
memcpy(&key_size, outbuf, 2);
key_size = le16_to_cpu(key_size);
if (crypt_volume_key_length(enc_key) != key_size) {
if (enc_key->keylength != key_size) {
log_err(cd, _("Unexpected key data size."));
log_dbg(cd, "Expected key data size: %zu, got %" PRIu16 "",
crypt_volume_key_length(enc_key), key_size);
log_dbg(cd, "Expected key data size: %zu, got %" PRIu16 "", enc_key->keylength, key_size);
r = -EINVAL;
goto out;
@@ -1084,7 +1092,7 @@ static int decrypt_key(struct crypt_device *cd,
crypt_get_volume_key_size(cd) == 32) {
/* 128bit AES-CBC with Elephant -- key size is 256 bit (2 keys) but key data is 512 bits,
data: 16B CBC key, 16B empty, 16B elephant key, 16B empty */
crypt_safe_memcpy(outbuf + 16 + BITLK_OPEN_KEY_METADATA_LEN,
memcpy(outbuf + 16 + BITLK_OPEN_KEY_METADATA_LEN,
outbuf + 2 * 16 + BITLK_OPEN_KEY_METADATA_LEN, 16);
key_size = 32 + BITLK_OPEN_KEY_METADATA_LEN;
}
@@ -1133,8 +1141,7 @@ int BITLK_get_volume_key(struct crypt_device *cd,
continue;
}
log_dbg(cd, "Trying to use given password as a recovery key.");
r = bitlk_kdf(crypt_volume_key_get_key(recovery_key),
crypt_volume_key_length(recovery_key),
r = bitlk_kdf(recovery_key->key, recovery_key->keylength,
true, next_vmk->salt, &vmk_dec_key);
crypt_free_volume_key(recovery_key);
if (r)
@@ -1212,7 +1219,7 @@ static int _activate_check(struct crypt_device *cd,
next_vmk = params->vmks;
while (next_vmk) {
if (next_vmk->protection == BITLK_PROTECTION_CLEAR_KEY) {
log_err(cd, _("Activation of BITLK device with clear key protection is not supported."));
log_err(cd, _("Activation of partially decrypted BITLK device is not supported."));
return -ENOTSUP;
}
next_vmk = next_vmk->next;
@@ -1241,7 +1248,7 @@ static int _activate(struct crypt_device *cd,
uint64_t next_start = 0;
uint64_t next_end = 0;
uint64_t last_segment = 0;
uint64_t dmt_flags = 0;
uint32_t dmt_flags = 0;
r = _activate_check(cd, params);
if (r)
@@ -1365,7 +1372,7 @@ static int _activate(struct crypt_device *cd,
crypt_get_cipher_spec(cd),
segments[i].iv_offset,
segments[i].iv_offset,
NULL, 0, 0,
NULL, 0,
params->sector_size);
if (r)
goto out;
@@ -1401,17 +1408,54 @@ out:
return r;
}
int BITLK_activate_by_volume_key(struct crypt_device *cd,
int BITLK_activate_by_passphrase(struct crypt_device *cd,
const char *name,
struct volume_key *vk,
const char *password,
size_t passwordLen,
const struct bitlk_metadata *params,
uint32_t flags)
{
int r;
int r = 0;
struct volume_key *open_fvek_key = NULL;
r = _activate_check(cd, params);
if (r)
return r;
return _activate(cd, name, vk, params, flags);
r = BITLK_get_volume_key(cd, password, passwordLen, params, &open_fvek_key);
if (r < 0)
goto out;
/* Password verify only */
if (!name)
goto out;
r = _activate(cd, name, open_fvek_key, params, flags);
out:
crypt_free_volume_key(open_fvek_key);
return r;
}
int BITLK_activate_by_volume_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
size_t volume_key_size,
const struct bitlk_metadata *params,
uint32_t flags)
{
int r = 0;
struct volume_key *open_fvek_key = NULL;
r = _activate_check(cd, params);
if (r)
return r;
open_fvek_key = crypt_alloc_volume_key(volume_key_size, volume_key);
if (!open_fvek_key)
return -ENOMEM;
r = _activate(cd, name, open_fvek_key, params, flags);
crypt_free_volume_key(open_fvek_key);
return r;
}

View File

@@ -1,10 +1,23 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* BITLK (BitLocker-compatible) header definition
*
* Copyright (C) 2019-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2025 Milan Broz
* Copyright (C) 2019-2025 Vojtech Trefny
* Copyright (C) 2019-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2019-2024 Milan Broz
* Copyright (C) 2019-2024 Vojtech Trefny
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _CRYPTSETUP_BITLK_H
@@ -65,7 +78,6 @@ typedef enum {
BITLK_ENTRY_VALUE_OFFSET_SIZE = 0x000f,
BITLK_ENTRY_VALUE_RECOVERY_TIME = 0x015,
BITLK_ENTRY_VALUE_GUID = 0x0017,
BITLK_ENTRY_VALUE_HINT = 0x0018,
} BITLKFVEEntryValue;
struct bitlk_vmk {
@@ -115,9 +127,17 @@ int BITLK_get_volume_key(struct crypt_device *cd,
const struct bitlk_metadata *params,
struct volume_key **open_fvek_key);
int BITLK_activate_by_passphrase(struct crypt_device *cd,
const char *name,
const char *password,
size_t passwordLen,
const struct bitlk_metadata *params,
uint32_t flags);
int BITLK_activate_by_volume_key(struct crypt_device *cd,
const char *name,
struct volume_key *vk,
const char *volume_key,
size_t volume_key_size,
const struct bitlk_metadata *params,
uint32_t flags);

View File

@@ -10,13 +10,13 @@
#include <stdint.h>
#include <sys/param.h>
#if HAVE_BYTESWAP_H
#if defined(HAVE_BYTESWAP_H)
# include <byteswap.h>
#endif
#if HAVE_ENDIAN_H
#if defined(HAVE_ENDIAN_H)
# include <endian.h>
#elif HAVE_SYS_ENDIAN_H /* BSDs have them here */
#elif defined(HAVE_SYS_ENDIAN_H) /* BSDs have them here */
# include <sys/endian.h>
#endif

View File

@@ -1,10 +1,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* cryptsetup plain device helper functions
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 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 <string.h>
@@ -92,7 +105,7 @@ int crypt_plain_hash(struct crypt_device *cd,
log_dbg(cd, "Too short plain passphrase.");
return -EINVAL;
}
crypt_safe_memcpy(key, passphrase, hash_size);
memcpy(key, passphrase, hash_size);
r = 0;
} else
r = hash(hash_name_buf, hash_size, key, passphrase_size, passphrase);

View File

@@ -13,8 +13,7 @@ libcrypto_backend_la_SOURCES = \
lib/crypto_backend/utf8.c \
lib/crypto_backend/argon2_generic.c \
lib/crypto_backend/cipher_generic.c \
lib/crypto_backend/cipher_check.c \
lib/crypto_backend/memutils.c
lib/crypto_backend/cipher_check.c
if CRYPTO_BACKEND_GCRYPT
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_gcrypt.c
@@ -31,9 +30,6 @@ endif
if CRYPTO_BACKEND_NETTLE
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_nettle.c
endif
if CRYPTO_BACKEND_MBEDTLS
libcrypto_backend_la_SOURCES += lib/crypto_backend/crypto_mbedtls.c
endif
if CRYPTO_INTERNAL_PBKDF2
libcrypto_backend_la_SOURCES += lib/crypto_backend/pbkdf2_generic.c

View File

@@ -360,7 +360,7 @@ int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) {
TRY(blake2b_final(&blake_state, out, outlen));
} else {
uint32_t toproduce;
uint8_t out_buffer[BLAKE2B_OUTBYTES] = {0};
uint8_t out_buffer[BLAKE2B_OUTBYTES];
uint8_t in_buffer[BLAKE2B_OUTBYTES];
TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES));
TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));

View File

@@ -128,7 +128,7 @@ void secure_wipe_memory(void *v, size_t n) {
void secure_wipe_memory(void *v, size_t n) {
memset_s(v, n, 0, n);
}
#elif HAVE_EXPLICIT_BZERO
#elif defined(HAVE_EXPLICIT_BZERO)
void secure_wipe_memory(void *v, size_t n) {
explicit_bzero(v, n);
}
@@ -356,9 +356,12 @@ static int fill_memory_blocks_mt(argon2_instance_t *instance) {
}
fail:
free(thread);
free(thr_data);
if (thread != NULL) {
free(thread);
}
if (thr_data != NULL) {
free(thr_data);
}
return rc;
}

View File

@@ -83,7 +83,7 @@
static int b64_byte_to_char(unsigned x) {
return (LT(x, 26) & (x + 'A')) |
(GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) |
(GE(x, 52) & LT(x, 62) & (x - (52 - '0'))) | (EQ(x, 62) & '+') |
(GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') |
(EQ(x, 63) & '/');
}

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Argon2 PBKDF2 library wrapper
*
* Copyright (C) 2016-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2025 Milan Broz
* Copyright (C) 2016-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>

View File

@@ -1,11 +1,24 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Base64 "Not encryption" helpers, copied and adapted from systemd project.
*
* Copyright (C) 2010 Lennart Poettering
*
* cryptsetup related changes
* Copyright (C) 2021-2025 Milan Broz
* Copyright (C) 2021-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Cipher performance check
*
* Copyright (C) 2018-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2025 Milan Broz
* Copyright (C) 2018-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
@@ -42,36 +55,43 @@ static int time_ms(struct timespec *start, struct timespec *end, double *ms)
return 0;
}
static int cipher_perf_one(struct crypt_cipher_kernel *cipher, char *buffer, size_t buffer_size,
const char *iv, size_t iv_size, int enc)
static int cipher_perf_one(const char *name, const char *mode, char *buffer, size_t buffer_size,
const char *key, size_t key_size, const char *iv, size_t iv_size, int enc)
{
struct crypt_cipher_kernel cipher;
size_t done = 0, block = CIPHER_BLOCK_BYTES;
int r;
if (buffer_size < block)
block = buffer_size;
r = crypt_cipher_init_kernel(&cipher, name, mode, key, key_size);
if (r < 0)
return r;
while (done < buffer_size) {
if ((done + block) > buffer_size)
block = buffer_size - done;
if (enc)
r = crypt_cipher_encrypt_kernel(cipher, &buffer[done], &buffer[done],
r = crypt_cipher_encrypt_kernel(&cipher, &buffer[done], &buffer[done],
block, iv, iv_size);
else
r = crypt_cipher_decrypt_kernel(cipher, &buffer[done], &buffer[done],
r = crypt_cipher_decrypt_kernel(&cipher, &buffer[done], &buffer[done],
block, iv, iv_size);
if (r < 0)
return r;
break;
done += block;
}
return 0;
}
crypt_cipher_destroy_kernel(&cipher);
static int cipher_measure(struct crypt_cipher_kernel *cipher, char *buffer, size_t buffer_size,
const char *iv, size_t iv_size, int encrypt, double *ms)
return r;
}
static int cipher_measure(const char *name, const char *mode, char *buffer, size_t buffer_size,
const char *key, size_t key_size, const char *iv, size_t iv_size,
int encrypt, double *ms)
{
struct timespec start, end;
int r;
@@ -83,7 +103,7 @@ static int cipher_measure(struct crypt_cipher_kernel *cipher, char *buffer, size
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start) < 0)
return -EINVAL;
r = cipher_perf_one(cipher, buffer, buffer_size, iv, iv_size, encrypt);
r = cipher_perf_one(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, encrypt);
if (r < 0)
return r;
@@ -111,20 +131,15 @@ int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, s
const char *key, size_t key_size, const char *iv, size_t iv_size,
double *encryption_mbs, double *decryption_mbs)
{
struct crypt_cipher_kernel cipher;
double ms_enc, ms_dec, ms;
int r, repeat_enc, repeat_dec;
r = crypt_cipher_init_kernel(&cipher, name, mode, key, key_size);
if (r < 0)
return r;
ms_enc = 0.0;
repeat_enc = 1;
while (ms_enc < 1000.0) {
r = cipher_measure(&cipher, buffer, buffer_size, iv, iv_size, 1, &ms);
r = cipher_measure(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, 1, &ms);
if (r < 0)
goto out;
return r;
ms_enc += ms;
repeat_enc++;
}
@@ -132,9 +147,9 @@ int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, s
ms_dec = 0.0;
repeat_dec = 1;
while (ms_dec < 1000.0) {
r = cipher_measure(&cipher, buffer, buffer_size, iv, iv_size, 0, &ms);
r = cipher_measure(name, mode, buffer, buffer_size, key, key_size, iv, iv_size, 0, &ms);
if (r < 0)
goto out;
return r;
ms_dec += ms;
repeat_dec++;
}
@@ -142,8 +157,5 @@ int crypt_cipher_perf_kernel(const char *name, const char *mode, char *buffer, s
*encryption_mbs = speed_mbs(buffer_size * repeat_enc, ms_enc);
*decryption_mbs = speed_mbs(buffer_size * repeat_dec, ms_dec);
r = 0;
out:
crypt_cipher_destroy_kernel(&cipher);
return r;
return 0;
}

View File

@@ -1,13 +1,27 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Linux kernel cipher generic utilities
*
* Copyright (C) 2018-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2025 Milan Broz
* Copyright (C) 2018-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include <strings.h>
#include "crypto_backend.h"
struct cipher_alg {
@@ -62,9 +76,6 @@ int crypt_cipher_ivsize(const char *name, const char *mode)
if (!ca)
return -EINVAL;
if (mode && !strcasecmp(mode, "hctr2"))
return 32;
if (mode && !strcasecmp(mode, "ecb"))
return 0;

View File

@@ -38,6 +38,8 @@
*
*/
#include <stdio.h>
#include "crypto_backend.h"
static const uint32_t crc32_tab[] = {

View File

@@ -1,11 +1,23 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* crypto backend implementation
*
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _CRYPTO_BACKEND_H
#define _CRYPTO_BACKEND_H
@@ -14,17 +26,13 @@
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#if HAVE_UCHAR_H
#ifdef HAVE_UCHAR_H
#include <uchar.h>
#else
#define char32_t uint32_t
#define char16_t uint16_t
#endif
# ifdef __cplusplus
extern "C" {
# endif
struct crypt_hash;
struct crypt_hmac;
struct crypt_cipher;
@@ -136,10 +144,15 @@ int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *tag, size_t tag_length);
/* Memzero helper (memset on stack can be optimized out) */
void crypt_backend_memzero(void *s, size_t n);
/* Memcpy helper to avoid spilling sensitive data through additional registers */
void *crypt_backend_memcpy(void *dst, const void *src, size_t n);
static inline void crypt_backend_memzero(void *s, size_t n)
{
#ifdef HAVE_EXPLICIT_BZERO
explicit_bzero(s, n);
#else
volatile uint8_t *p = (volatile uint8_t *)s;
while(n--) *p++ = 0;
#endif
}
/* Memcmp helper (memcmp in constant time) */
int crypt_backend_memeq(const void *m1, const void *m2, size_t n);
@@ -147,8 +160,4 @@ int crypt_backend_memeq(const void *m1, const void *m2, size_t n);
/* crypto backend running in FIPS mode */
bool crypt_fips_mode(void);
# ifdef __cplusplus
}
# endif
#endif /* _CRYPTO_BACKEND_H */

View File

@@ -1,17 +1,29 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* crypto backend implementation
*
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _CRYPTO_BACKEND_INTERNAL_H
#define _CRYPTO_BACKEND_INTERNAL_H
#include "crypto_backend.h"
/* Internal PBKDF2 implementation */
/* internal PBKDF2 implementation */
int pkcs5_pbkdf2(const char *hash,
const char *P, size_t Plen,
const char *S, size_t Slen,
@@ -47,6 +59,17 @@ int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length,
const char *tag, size_t tag_length);
/* Internal implementation for constant time memory comparison */
int crypt_internal_memeq(const void *m1, const void *m2, size_t n);
static inline int crypt_internal_memeq(const void *m1, const void *m2, size_t n)
{
const unsigned char *_m1 = (const unsigned char *) m1;
const unsigned char *_m2 = (const unsigned char *) m2;
unsigned char result = 0;
size_t i;
for (i = 0; i < n; i++)
result |= _m1[i] ^ _m2[i];
return result;
}
#endif /* _CRYPTO_BACKEND_INTERNAL_H */

View File

@@ -1,20 +1,35 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Linux kernel userspace API crypto backend implementation (skcipher)
*
* Copyright (C) 2012-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2025 Milan Broz
* Copyright (C) 2012-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include "crypto_backend_internal.h"
#if ENABLE_AF_ALG
#ifdef ENABLE_AF_ALG
#include <linux/if_alg.h>
@@ -40,8 +55,6 @@ static int _crypt_cipher_init(struct crypt_cipher_kernel *ctx,
const void *key, size_t key_length,
size_t tag_length, struct sockaddr_alg *sa)
{
void *optval = NULL;
if (!ctx)
return -EINVAL;
@@ -62,7 +75,7 @@ static int _crypt_cipher_init(struct crypt_cipher_kernel *ctx,
return -EINVAL;
}
if (tag_length && setsockopt(ctx->tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, &optval, tag_length) < 0) {
if (tag_length && setsockopt(ctx->tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, tag_length) < 0) {
crypt_cipher_destroy_kernel(ctx);
return -EINVAL;
}
@@ -88,13 +101,9 @@ int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name,
if (!strcmp(name, "cipher_null"))
key_length = 0;
if (!strncmp(name, "capi:", 5))
strncpy((char *)sa.salg_name, &name[5], sizeof(sa.salg_name) - 1);
else {
r = snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(%s)", mode, name);
if (r < 0 || (size_t)r >= sizeof(sa.salg_name))
return -EINVAL;
}
r = snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(%s)", mode, name);
if (r < 0 || (size_t)r >= sizeof(sa.salg_name))
return -EINVAL;
return _crypt_cipher_init(ctx, key, key_length, 0, &sa);
}
@@ -155,7 +164,7 @@ static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
header->cmsg_len = iv_msg_size;
alg_iv = (void*)CMSG_DATA(header);
alg_iv->ivlen = iv_length;
crypt_backend_memcpy(alg_iv->iv, iv, iv_length);
memcpy(alg_iv->iv, iv, iv_length);
}
len = sendmsg(ctx->opfd, &msg, 0);
@@ -202,8 +211,8 @@ int crypt_cipher_check_kernel(const char *name, const char *mode,
const char *integrity, size_t key_length)
{
struct crypt_cipher_kernel c;
char mode_name[64], tmp_salg_name[180], *cipher_iv = NULL, *key;
const char *salg_type, *real_mode;
char mode_name[64], tmp_salg_name[180], *real_mode = NULL, *cipher_iv = NULL, *key;
const char *salg_type;
bool aead;
int r;
struct sockaddr_alg sa = {
@@ -211,7 +220,6 @@ int crypt_cipher_check_kernel(const char *name, const char *mode,
};
aead = integrity && strcmp(integrity, "none");
real_mode = NULL;
/* Remove IV if present */
if (mode) {
@@ -232,22 +240,14 @@ int crypt_cipher_check_kernel(const char *name, const char *mode,
memset(tmp_salg_name, 0, sizeof(tmp_salg_name));
/* FIXME: this is duplicating a part of devmapper backend */
if (aead) {
/* In AEAD, mode parameter can be just IV like "random" */
if (!strcmp(integrity, "poly1305"))
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "rfc7539(%s,%s)", name, integrity);
else if (!real_mode)
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s", name);
else if (!strcmp(real_mode, "ccm"))
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "rfc4309(%s(%s))", real_mode, name);
else
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s(%s)", real_mode, name);
} else {
if (!mode)
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s", name);
else
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s(%s)", real_mode ?: mode_name, name);
}
if (aead && !strcmp(integrity, "poly1305"))
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "rfc7539(%s,%s)", name, integrity);
else if (!real_mode)
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s", name);
else if (aead && !strcmp(real_mode, "ccm"))
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "rfc4309(%s(%s))", real_mode, name);
else
r = snprintf(tmp_salg_name, sizeof(tmp_salg_name), "%s(%s)", real_mode, name);
if (r < 0 || (size_t)r >= sizeof(tmp_salg_name))
return -EINVAL;

View File

@@ -1,14 +1,27 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* GCRYPT crypto backend implementation
*
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <strings.h>
#include <gcrypt.h>
#include <pthread.h>
#include "crypto_backend_internal.h"
@@ -51,6 +64,7 @@ static void crypt_hash_test_whirlpool_bug(void)
{
struct crypt_hash *h;
char buf[2] = "\0\0", hash_out1[64], hash_out2[64];
int r;
if (crypto_backend_whirlpool_bug >= 0)
return;
@@ -60,16 +74,16 @@ static void crypt_hash_test_whirlpool_bug(void)
return;
/* One shot */
if (crypt_hash_write(h, &buf[0], 2) ||
crypt_hash_final(h, hash_out1, 64)) {
if ((r = crypt_hash_write(h, &buf[0], 2)) ||
(r = crypt_hash_final(h, hash_out1, 64))) {
crypt_hash_destroy(h);
return;
}
/* Split buf (crypt_hash_final resets hash state) */
if (crypt_hash_write(h, &buf[0], 1) ||
crypt_hash_write(h, &buf[1], 1) ||
crypt_hash_final(h, hash_out2, 64)) {
if ((r = crypt_hash_write(h, &buf[0], 1)) ||
(r = crypt_hash_write(h, &buf[1], 1)) ||
(r = crypt_hash_final(h, hash_out2, 64))) {
crypt_hash_destroy(h);
return;
}
@@ -249,7 +263,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
if (!hash)
return -EINVAL;
crypt_backend_memcpy(buffer, hash, length);
memcpy(buffer, hash, length);
crypt_hash_restart(ctx);
return 0;
@@ -323,7 +337,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
if (!hash)
return -EINVAL;
crypt_backend_memcpy(buffer, hash, length);
memcpy(buffer, hash, length);
crypt_hmac_restart(ctx);
return 0;
@@ -451,7 +465,6 @@ static int gcrypt_argon2(const char *type,
.dispatch_job = gcrypt_dispatch_job,
.wait_all_jobs = gcrypt_wait_all_jobs
};
gpg_error_t err;
if (!strcmp(type, "argon2i"))
atype = GCRY_KDF_ARGON2I;
@@ -465,11 +478,12 @@ static int gcrypt_argon2(const char *type,
param[2] = memory;
param[3] = parallel;
err = gcry_kdf_open(&hd, GCRY_KDF_ARGON2, atype, param, 4,
if (gcry_kdf_open(&hd, GCRY_KDF_ARGON2, atype, param, 4,
password, password_length, salt, salt_length,
NULL, 0, NULL, 0);
if (err)
return ((err & GPG_ERR_CODE_MASK) == GPG_ERR_ENOMEM) ? -ENOMEM : -EINVAL;
NULL, 0, NULL, 0)) {
free(threads.jobs_ctx);
return -EINVAL;
}
if (parallel == 1) {
/* Do not use threads here */

View File

@@ -1,11 +1,25 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Linux kernel userspace API crypto backend implementation
*
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

View File

@@ -1,535 +0,0 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Mbed TLS crypto backend implementation
*
* Copyright (C) 2024-2025 Yiyuan Zhong
*/
#include "crypto_backend.h"
#include <errno.h>
#include <stdlib.h>
#include <mbedtls/ccm.h>
#include <mbedtls/constant_time.h>
#include <mbedtls/cipher.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/md.h>
#include <mbedtls/pkcs5.h>
#include <mbedtls/version.h>
#include "crypto_backend_internal.h"
struct crypt_hash {
const mbedtls_md_info_t *info;
mbedtls_md_context_t md;
};
struct crypt_hmac {
const mbedtls_md_info_t *info;
mbedtls_md_context_t md;
};
struct crypt_cipher {
const mbedtls_cipher_info_t *info;
mbedtls_cipher_context_t enc;
mbedtls_cipher_context_t dec;
int ecb;
};
static bool g_initialized = false;
static char g_backend_version[32];
static mbedtls_entropy_context g_entropy;
static mbedtls_ctr_drbg_context g_ctr_drbg;
static const mbedtls_md_info_t *crypt_get_hash(const char *name)
{
static const struct hash_alg {
const char *name;
mbedtls_md_type_t type;
} kHash[] = {
{"sha1", MBEDTLS_MD_SHA1 },
{"sha224", MBEDTLS_MD_SHA224 },
{"sha256", MBEDTLS_MD_SHA256 },
{"sha384", MBEDTLS_MD_SHA384 },
{"sha512", MBEDTLS_MD_SHA512 },
{"ripemd160", MBEDTLS_MD_RIPEMD160},
{NULL, 0, }
};
size_t i = 0;
while (name && kHash[i].name) {
if (strcmp(kHash[i].name, name) == 0)
return mbedtls_md_info_from_type(kHash[i].type);
i++;
}
return NULL;
}
int crypt_backend_init(bool fips)
{
int ret;
if (g_initialized)
return 0;
if (fips)
return -ENOTSUP;
mbedtls_version_get_string_full(g_backend_version);
mbedtls_entropy_init(&g_entropy);
mbedtls_ctr_drbg_init(&g_ctr_drbg);
ret = mbedtls_ctr_drbg_seed(
&g_ctr_drbg, mbedtls_entropy_func,
&g_entropy, NULL, MBEDTLS_CTR_DRBG_ENTROPY_LEN);
if (ret)
return -EINVAL;
g_initialized = true;
return 0;
}
void crypt_backend_destroy(void)
{
if (!g_initialized)
return;
mbedtls_ctr_drbg_free(&g_ctr_drbg);
mbedtls_entropy_free(&g_entropy);
g_initialized = false;
}
uint32_t crypt_backend_flags(void)
{
return 0;
}
const char *crypt_backend_version(void)
{
return g_backend_version;
}
bool crypt_fips_mode(void)
{
return false;
}
int crypt_backend_memeq(const void *m1, const void *m2, size_t n)
{
return mbedtls_ct_memcmp(m1, m2, n);
}
/* HASH */
int crypt_hash_size(const char *name)
{
const mbedtls_md_info_t *info;
info = crypt_get_hash(name);
return info ? mbedtls_md_get_size(info) : -ENOENT;
}
int crypt_hash_init(struct crypt_hash **ctx, const char *name)
{
struct crypt_hash *h;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
h->info = crypt_get_hash(name);
if (!h->info) {
free(h);
return -ENOENT;
}
mbedtls_md_init(&h->md);
if (mbedtls_md_setup(&h->md, h->info, 0)) {
mbedtls_md_free(&h->md);
free(h);
return -EINVAL;
}
if (mbedtls_md_starts(&h->md)) {
mbedtls_md_free(&h->md);
free(h);
return -EINVAL;
}
*ctx = h;
return 0;
}
int crypt_hash_write(struct crypt_hash *ctx, const char *buffer, size_t length)
{
if (mbedtls_md_update(&ctx->md, (const unsigned char *)buffer, length))
return -EINVAL;
return 0;
}
int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
{
unsigned char tmp[MBEDTLS_MD_MAX_SIZE];
if (length > mbedtls_md_get_size(ctx->info))
return -EINVAL;
if (mbedtls_md_finish(&ctx->md, tmp))
return -EINVAL;
crypt_backend_memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (mbedtls_md_starts(&ctx->md))
return -EINVAL;
return 0;
}
void crypt_hash_destroy(struct crypt_hash *ctx)
{
mbedtls_md_free(&ctx->md);
crypt_backend_memzero(ctx, sizeof(*ctx));
free(ctx);
}
/* HMAC */
int crypt_hmac_size(const char *name)
{
return crypt_hash_size(name);
}
int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
const void *key, size_t key_length)
{
struct crypt_hmac *h;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
h->info = crypt_get_hash(name);
if (!h->info) {
free(h);
return -ENOENT;
}
mbedtls_md_init(&h->md);
if (mbedtls_md_setup(&h->md, h->info, 1)) {
mbedtls_md_free(&h->md);
free(h);
return -EINVAL;
}
if (mbedtls_md_hmac_starts(&h->md, key, key_length)) {
mbedtls_md_free(&h->md);
free(h);
return -EINVAL;
}
*ctx = h;
return 0;
}
int crypt_hmac_write(struct crypt_hmac *ctx, const char *buffer, size_t length)
{
if (mbedtls_md_hmac_update(&ctx->md, (const unsigned char *)buffer, length))
return -EINVAL;
return 0;
}
int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
{
unsigned char tmp[MBEDTLS_MD_MAX_SIZE];
if (length > mbedtls_md_get_size(ctx->info))
return -EINVAL;
if (mbedtls_md_hmac_finish(&ctx->md, tmp))
return -EINVAL;
crypt_backend_memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (mbedtls_md_hmac_reset(&ctx->md))
return -EINVAL;
return 0;
}
void crypt_hmac_destroy(struct crypt_hmac *ctx)
{
mbedtls_md_free(&ctx->md);
crypt_backend_memzero(ctx, sizeof(*ctx));
free(ctx);
}
/* RNG */
int crypt_backend_rng(char *buffer, size_t length, int quality, int fips)
{
if (fips)
return -ENOTSUP;
/* Allow skipping reseeding for non-cryptographic strong random numbers */
if (quality == CRYPT_RND_NORMAL || quality == CRYPT_RND_SALT)
mbedtls_ctr_drbg_set_prediction_resistance(&g_ctr_drbg, MBEDTLS_CTR_DRBG_PR_OFF);
else
mbedtls_ctr_drbg_set_prediction_resistance(&g_ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON);
if (mbedtls_ctr_drbg_random(&g_ctr_drbg, (unsigned char *)buffer, length))
return -EINVAL;
return 0;
}
/* CIPHER */
int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
const char *mode, const void *key, size_t key_length)
{
static const struct {
const char *name;
mbedtls_cipher_id_t id;
} kCipher[] = {
{ "aes", MBEDTLS_CIPHER_ID_AES },
{ "aria", MBEDTLS_CIPHER_ID_ARIA },
{ "camellia", MBEDTLS_CIPHER_ID_CAMELLIA },
{ NULL, 0 }
};
static const struct {
const char *name;
mbedtls_cipher_mode_t mode;
} kMode[] = {
{ "ecb", MBEDTLS_MODE_ECB },
{ "cbc", MBEDTLS_MODE_CBC },
{ "cfb", MBEDTLS_MODE_CFB },
{ "ofb", MBEDTLS_MODE_OFB },
{ "ctr", MBEDTLS_MODE_CTR },
{ "xts", MBEDTLS_MODE_XTS },
{ NULL, 0 }
};
mbedtls_cipher_id_t cid = MBEDTLS_CIPHER_ID_NONE;
mbedtls_cipher_mode_t cmode = MBEDTLS_MODE_NONE;
struct crypt_cipher *h;
size_t i;
int bits;
for (i = 0; kCipher[i].name; i++) {
if (strcmp(kCipher[i].name, name) == 0) {
cid = kCipher[i].id;
break;
}
}
for (i = 0; kMode[i].name; i++) {
if (strcmp(kMode[i].name, mode) == 0) {
cmode = kMode[i].mode;
break;
}
}
if (cid == MBEDTLS_CIPHER_ID_NONE || cmode == MBEDTLS_MODE_NONE)
return -ENOENT;
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
bits = key_length * 8;
h->info = mbedtls_cipher_info_from_values(cid, bits, cmode);
if (!h->info) {
free(h);
return -ENOENT;
}
mbedtls_cipher_init(&h->enc);
mbedtls_cipher_init(&h->dec);
if (mbedtls_cipher_setup(&h->enc, h->info) ||
mbedtls_cipher_setup(&h->dec, h->info) ||
mbedtls_cipher_setkey(&h->enc, key, bits, MBEDTLS_ENCRYPT) ||
mbedtls_cipher_setkey(&h->dec, key, bits, MBEDTLS_DECRYPT)) {
mbedtls_cipher_free(&h->dec);
mbedtls_cipher_free(&h->enc);
free(h);
return -EINVAL;
}
if (cmode == MBEDTLS_MODE_CBC) {
if (mbedtls_cipher_set_padding_mode(&h->enc, MBEDTLS_PADDING_NONE) ||
mbedtls_cipher_set_padding_mode(&h->dec, MBEDTLS_PADDING_NONE)) {
mbedtls_cipher_free(&h->dec);
mbedtls_cipher_free(&h->enc);
free(h);
return -EINVAL;
}
}
h->ecb = cmode == MBEDTLS_MODE_ECB;
*ctx = h;
return 0;
}
void crypt_cipher_destroy(struct crypt_cipher *ctx)
{
mbedtls_cipher_free(&ctx->dec);
mbedtls_cipher_free(&ctx->enc);
free(ctx);
}
static int crypt_cipher_crypt(
mbedtls_cipher_context_t *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
int ecb)
{
const unsigned char *input;
unsigned char *output;
size_t outlen;
size_t block;
size_t len;
if (ecb) /* ECB requires exactly block length input */
block = mbedtls_cipher_get_block_size(ctx);
else
block = length;
input = (const unsigned char *)in;
output = (unsigned char *)out;
if (mbedtls_cipher_set_iv(ctx, (const unsigned char *)iv, iv_length))
return -EINVAL;
if (mbedtls_cipher_reset(ctx))
return -EINVAL;
while (length) {
len = length < block ? length : block;
if (mbedtls_cipher_update(ctx, input, len, output, &outlen))
return -EINVAL;
output += outlen;
length -= len;
input += len;
}
if (mbedtls_cipher_finish(ctx, output, &outlen))
return -EINVAL;
return 0;
}
int crypt_cipher_encrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_crypt(&ctx->enc, in, out, length, iv, iv_length, ctx->ecb);
}
int crypt_cipher_decrypt(struct crypt_cipher *ctx,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length)
{
return crypt_cipher_crypt(&ctx->dec, in, out, length, iv, iv_length, ctx->ecb);
}
bool crypt_cipher_kernel_only(struct crypt_cipher *ctx __attribute__((unused)))
{
return false;
}
int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length,
const char *salt, size_t salt_length,
char *key, size_t key_length,
uint32_t iterations, uint32_t memory, uint32_t parallel)
{
const mbedtls_md_info_t *info;
#if !HAVE_MBEDTLS_PKCS5_PBKDF2_HMAC_EXT
mbedtls_md_context_t md;
#endif
if (!kdf)
return -EINVAL;
if (strcmp(kdf, "pbkdf2") == 0) {
info = crypt_get_hash(hash);
if (!info)
return -EINVAL;
#if HAVE_MBEDTLS_PKCS5_PBKDF2_HMAC_EXT
if (mbedtls_pkcs5_pbkdf2_hmac_ext(mbedtls_md_get_type(info),
(const unsigned char *)password, password_length,
(const unsigned char *)salt, salt_length,
iterations, key_length, (unsigned char *)key)) {
return -EINVAL;
}
#else
mbedtls_md_init(&md);
if (mbedtls_md_setup(&md, info, 1))
return -EINVAL;
if (mbedtls_pkcs5_pbkdf2_hmac(&md,
(const unsigned char *)password, password_length,
(const unsigned char *)salt, salt_length,
iterations, key_length, (unsigned char *)key)) {
mbedtls_md_free(&md);
return -EINVAL;
}
mbedtls_md_free(&md);
#endif
return 0;
} else if (strncmp(kdf, "argon2", 6) == 0) {
return argon2(kdf, password, password_length, salt, salt_length,
key, key_length, iterations, memory, parallel);
}
return -EINVAL;
}
int crypt_bitlk_decrypt_key(const void *key, size_t key_length,
const char *in, char *out, size_t length,
const char *iv, size_t iv_length,
const char *tag, size_t tag_length)
{
const unsigned char *tagptr;
const unsigned char *input;
const unsigned char *ivptr;
mbedtls_ccm_context ctx;
unsigned char *output;
tagptr = (const unsigned char *)tag;
ivptr = (const unsigned char *)iv;
input = (const unsigned char *)in;
output = (unsigned char *)out;
mbedtls_ccm_init(&ctx);
if (mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key, key_length * 8)) {
mbedtls_ccm_free(&ctx);
return -EINVAL;
}
if (mbedtls_ccm_auth_decrypt(&ctx, length, ivptr, iv_length, NULL, 0,
input, output, tagptr, tag_length)) {
mbedtls_ccm_free(&ctx);
return -EINVAL;
}
mbedtls_ccm_free(&ctx);
return 0;
}

View File

@@ -1,12 +1,26 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Nettle crypto backend implementation
*
* Copyright (C) 2011-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2025 Milan Broz
* Copyright (C) 2011-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <nettle/sha.h>
#include <nettle/sha3.h>
@@ -284,7 +298,8 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
memset(h, 0, sizeof(*h));
memset(ctx, 0, sizeof(*ctx));
h->hash = _get_alg(name);
if (!h->hash) {
@@ -298,7 +313,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
return -ENOMEM;
}
crypt_backend_memcpy(h->key, key, key_length);
memcpy(h->key, key, key_length);
h->key_length = key_length;
h->hash->init(&h->nettle_ctx);

View File

@@ -1,12 +1,25 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* NSS crypto backend implementation
*
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <nss.h>
#include <pk11pub.h>
@@ -164,7 +177,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
if (PK11_DigestFinal(ctx->md, tmp, &tmp_len, length) != SECSuccess)
return -EINVAL;
crypt_backend_memcpy(buffer, tmp, length);
memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (tmp_len < length)
@@ -207,7 +220,8 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
memset(h, 0, sizeof(*h));
memset(ctx, 0, sizeof(*ctx));
h->hash = _get_alg(name);
if (!h->hash)
@@ -264,7 +278,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
if (PK11_DigestFinal(ctx->md, tmp, &tmp_len, length) != SECSuccess)
return -EINVAL;
crypt_backend_memcpy(buffer, tmp, length);
memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (tmp_len < length)

View File

@@ -1,15 +1,36 @@
// SPDX-License-Identifier: LGPL-2.1-or-later WITH cryptsetup-OpenSSL-exception
/*
* OPENSSL crypto backend implementation
*
* Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2025 Milan Broz
* Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Lesser General Public License in all respects
* for all of the code used other than OpenSSL.
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <strings.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
@@ -19,7 +40,6 @@
#include <openssl/provider.h>
#include <openssl/kdf.h>
#include <openssl/core_names.h>
#include <openssl/err.h>
static OSSL_PROVIDER *ossl_legacy = NULL;
static OSSL_PROVIDER *ossl_default = NULL;
static OSSL_LIB_CTX *ossl_ctx = NULL;
@@ -382,7 +402,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
if (EVP_DigestFinal_ex(ctx->md, tmp, &tmp_len) != 1)
return -EINVAL;
crypt_backend_memcpy(buffer, tmp, length);
memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (tmp_len < length)
@@ -511,7 +531,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
HMAC_Final(ctx->md, tmp, &tmp_len);
#endif
crypt_backend_memcpy(buffer, tmp, length);
memcpy(buffer, tmp, length);
crypt_backend_memzero(tmp, sizeof(tmp));
if (tmp_len < length)
@@ -625,7 +645,7 @@ static int openssl_argon2(const char *type, const char *password, size_t passwor
ctx = EVP_KDF_CTX_new(argon2);
if (!ctx) {
EVP_KDF_free(argon2);
return -EINVAL;
return -EINVAL;;
}
if (EVP_KDF_CTX_set_params(ctx, params) != 1) {
@@ -639,10 +659,6 @@ static int openssl_argon2(const char *type, const char *password, size_t passwor
EVP_KDF_CTX_free(ctx);
EVP_KDF_free(argon2);
/* Memory allocation is common issue with memory-hard Argon2 */
if (r == 0 && ERR_GET_REASON(ERR_get_error()) == ERR_R_MALLOC_FAILURE)
return -ENOMEM;
/* _derive() returns 0 or negative value on error, 1 on success */
return r == 1 ? 0 : -EINVAL;
#else

View File

@@ -1,21 +1,31 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Generic wrapper for storage encryption modes and Initial Vectors
* (reimplementation of some functions from Linux dm-crypt kernel)
*
* Copyright (C) 2014-2025 Milan Broz
* Copyright (C) 2014-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <strings.h>
#include "bitops.h"
#include "crypto_backend.h"
#define SECTOR_SHIFT 9
#define MAX_CAPI_LEN 64
#define MAX_CAPI_LEN_STR "63"
#define SECTOR_SHIFT 9
/*
* Internal IV helper
@@ -215,56 +225,43 @@ int crypt_storage_init(struct crypt_storage **ctx,
bool large_iv)
{
struct crypt_storage *s;
char cipher_name[MAX_CAPI_LEN], mode_name[MAX_CAPI_LEN], mode_tmp[MAX_CAPI_LEN];
char mode_name[64];
char *cipher_iv = NULL;
int r;
int r = -EIO;
if (sector_size < (1 << SECTOR_SHIFT) ||
sector_size > (1 << (SECTOR_SHIFT + 3)) ||
sector_size & (sector_size - 1))
return -EINVAL;
/* Convert from capi mode */
if (!strncmp(cipher, "capi:", 5)) {
r = sscanf(cipher, "capi:%" MAX_CAPI_LEN_STR "[^(](%" MAX_CAPI_LEN_STR "[^)])", mode_tmp, cipher_name);
if (r != 2)
return -EINVAL;
r = snprintf(mode_name, sizeof(mode_name), "%s-%s", mode_tmp, cipher_mode);
if (r < 0 || (size_t)r >= sizeof(mode_name))
return -EINVAL;
} else {
strncpy(cipher_name, cipher, sizeof(cipher_name));
cipher_name[sizeof(cipher_name) - 1] = 0;
strncpy(mode_name, cipher_mode, sizeof(mode_name));
mode_name[sizeof(mode_name) - 1] = 0;
}
s = malloc(sizeof(*s));
if (!s)
return -ENOMEM;
memset(s, 0, sizeof(*s));
/* Remove IV if present */
strncpy(mode_name, cipher_mode, sizeof(mode_name));
mode_name[sizeof(mode_name) - 1] = 0;
cipher_iv = strchr(mode_name, '-');
if (cipher_iv) {
*cipher_iv = '\0';
cipher_iv++;
}
s = malloc(sizeof(*s));
if (!s)
return -ENOMEM;
memset(s, 0, sizeof(*s));
r = crypt_cipher_init(&s->cipher, cipher_name, mode_name, key, key_length);
r = crypt_cipher_init(&s->cipher, cipher, mode_name, key, key_length);
if (r) {
crypt_storage_destroy(s);
return r;
}
r = crypt_sector_iv_init(&s->cipher_iv, cipher_name, mode_name, cipher_iv, key, key_length, sector_size);
r = crypt_sector_iv_init(&s->cipher_iv, cipher, mode_name, cipher_iv, key, key_length, sector_size);
if (r) {
crypt_storage_destroy(s);
return r;
}
s->sector_size = sector_size;
s->iv_shift = large_iv ? (unsigned)int_log2(sector_size) - SECTOR_SHIFT : 0;
s->iv_shift = large_iv ? int_log2(sector_size) - SECTOR_SHIFT : 0;
*ctx = s;
return 0;

View File

@@ -1,63 +0,0 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Safe memory utilities
*
* Copyright (C) 2024-2025 Milan Broz
*/
#include "crypto_backend_internal.h"
#define ATTR_NOINLINE __attribute__ ((noinline))
#define ATTR_ZERO_REGS
#if defined __has_attribute
# if __has_attribute (zero_call_used_regs)
# undef ATTR_ZERO_REGS
# define ATTR_ZERO_REGS __attribute__ ((zero_call_used_regs("used")))
# endif
#endif
/* Workaround for https://github.com/google/sanitizers/issues/1507 */
#if defined __has_feature
# if __has_feature (memory_sanitizer)
# undef HAVE_EXPLICIT_BZERO
# endif
#endif
/* Memzero helper (memset on stack can be optimized out) */
ATTR_NOINLINE ATTR_ZERO_REGS
void crypt_backend_memzero(void *s, size_t n)
{
#if HAVE_EXPLICIT_BZERO
explicit_bzero(s, n);
#else
volatile uint8_t *p = (volatile uint8_t *)s;
while(n--) *p++ = 0;
#endif
}
/* Memcpy helper to avoid spilling sensitive data through additional registers */
ATTR_NOINLINE ATTR_ZERO_REGS
void *crypt_backend_memcpy(void *dst, const void *src, size_t n)
{
volatile uint8_t *d = (volatile uint8_t *)dst;
const volatile uint8_t *s = (const volatile uint8_t *)src;
while(n--) *d++ = *s++;
return dst;
}
/* Internal implementation for constant time memory comparison */
ATTR_NOINLINE ATTR_ZERO_REGS
int crypt_internal_memeq(const void *m1, const void *m2, size_t n)
{
const unsigned char *_m1 = (const unsigned char *) m1;
const unsigned char *_m2 = (const unsigned char *) m2;
unsigned char result = 0;
size_t i;
for (i = 0; i < n; i++)
result |= _m1[i] ^ _m2[i];
return result;
}

View File

@@ -11,7 +11,6 @@ libcrypto_backend_link_with = []
libcrypto_backend_sources = files(
'argon2_generic.c',
'base64.c',
'memutils.c',
'cipher_check.c',
'cipher_generic.c',
'crc32.c',

View File

@@ -1,12 +1,26 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Implementation of Password-Based Cryptography as per PKCS#5
* Copyright (C) 2002,2003 Simon Josefsson
* Copyright (C) 2004 Free Software Foundation
*
* cryptsetup related changes
* Copyright (C) 2012-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2025 Milan Broz
* Copyright (C) 2012-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <errno.h>

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* PBKDF performance check
* Copyright (C) 2012-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2025 Milan Broz
* Copyright (C) 2012-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2024 Milan Broz
* Copyright (C) 2016-2020 Ondrej Mosnacek
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdlib.h>
@@ -300,7 +313,6 @@ static int crypt_argon2_check(const char *kdf, const char *password,
} while (ms < ms_atleast || ms > ms_atmost);
out:
if (key) {
/* Key can be derived from a real provided password */
crypt_backend_memzero(key, key_length);
free(key);
}
@@ -382,7 +394,6 @@ static int crypt_pbkdf_check(const char *kdf, const char *hash,
}
out:
if (key) {
/* Key can be derived from a real provided password */
crypt_backend_memzero(key, key_length);
free(key);
}
@@ -408,9 +419,6 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash,
if (r < 0)
return r;
if (parallel_threads > pbkdf_limits.max_parallel)
return -EINVAL;
min_memory = pbkdf_limits.min_bench_memory;
if (min_memory > max_memory_kb)
min_memory = max_memory_kb;

View File

@@ -1,11 +1,10 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* UTF8/16 helpers, copied and adapted from systemd project.
*
* Copyright (C) 2010 Lennart Poettering
*
* cryptsetup related changes
* Copyright (C) 2021-2025 Vojtech Trefny
* Copyright (C) 2021-2024 Vojtech Trefny
* Parts of the original systemd implementation are based on the GLIB utf8
* validation functions.
@@ -13,6 +12,20 @@
*
* Copyright (C) 1999 Tom Tromey
* Copyright (C) 2000 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
@@ -217,7 +230,6 @@ static size_t utf16_encode_unichar(char16_t *out, char32_t c)
return 1;
case 0x10000U ... 0x10ffffU:
/* coverity[overflow_const:FALSE] */
c -= 0x10000U;
out[0] = htole16((c >> 10) + 0xd800U);
out[1] = htole16((c & 0x3ffU) + 0xdc00U);

View File

@@ -1,8 +1,21 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* FVAULT2 (FileVault2-compatible) volume handling
*
* Copyright (C) 2021-2022 Pavel Tobias
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
@@ -513,7 +526,6 @@ static int _read_volume_header(
int r = 0;
struct device *dev = crypt_metadata_device(cd);
struct volume_header *vol_header = NULL;
void *enc_key = NULL;
assert(sizeof(*vol_header) == FVAULT2_VOL_HEADER_SIZE);
@@ -558,8 +570,8 @@ static int _read_volume_header(
goto out;
}
enc_key = crypt_safe_alloc(FVAULT2_XTS_KEY_SIZE);
if (!enc_key) {
*enc_md_key = crypt_alloc_volume_key(FVAULT2_XTS_KEY_SIZE, NULL);
if (*enc_md_key == NULL) {
r = -ENOMEM;
goto out;
}
@@ -567,15 +579,9 @@ static int _read_volume_header(
*block_size = le32_to_cpu(vol_header->block_size);
*disklbl_blkoff = le64_to_cpu(vol_header->disklbl_blkoff);
uuid_unparse(vol_header->ph_vol_uuid, ph_vol_uuid);
crypt_safe_memcpy(enc_key, vol_header->key_data, FVAULT2_AES_KEY_SIZE);
crypt_safe_memcpy((char *)enc_key + FVAULT2_AES_KEY_SIZE,
memcpy((*enc_md_key)->key, vol_header->key_data, FVAULT2_AES_KEY_SIZE);
memcpy((*enc_md_key)->key + FVAULT2_AES_KEY_SIZE,
vol_header->ph_vol_uuid, FVAULT2_AES_KEY_SIZE);
*enc_md_key = crypt_alloc_volume_key_by_safe_alloc(&enc_key);
if (*enc_md_key == NULL) {
crypt_safe_free(enc_key);
r = -ENOMEM;
}
out:
free(vol_header);
return r;
@@ -711,7 +717,7 @@ static int _read_encrypted_metadata(
goto out;
}
r = crypt_cipher_init(&cipher, "aes", "xts", crypt_volume_key_get_key(key), FVAULT2_XTS_KEY_SIZE);
r = crypt_cipher_init(&cipher, "aes", "xts", key->key, FVAULT2_XTS_KEY_SIZE);
if (r < 0)
goto out;
@@ -842,7 +848,8 @@ static int _activate(
r = dm_crypt_target_set(&dm_dev.segment, 0, dm_dev.size,
crypt_data_device(cd), vol_key, cipher,
crypt_get_iv_offset(cd), crypt_get_data_offset(cd),
NULL, 0, 0, crypt_get_sector_size(cd));
crypt_get_integrity(cd), crypt_get_integrity_tag_size(cd),
crypt_get_sector_size(cd));
if (!r)
r = dm_create_device(cd, name, CRYPT_FVAULT2, &dm_dev);
@@ -899,14 +906,15 @@ int FVAULT2_get_volume_key(
const char *passphrase,
size_t passphrase_len,
const struct fvault2_params *params,
struct volume_key **r_vol_key)
struct volume_key **vol_key)
{
int r = 0;
uint8_t family_uuid_bin[FVAULT2_UUID_BIN_SIZE];
struct volume_key *passphrase_key = NULL;
struct volume_key *kek = NULL;
struct crypt_hash *hash = NULL;
void *passphrase_key = NULL, *kek = NULL, *vol_key= NULL;
*r_vol_key = NULL;
*vol_key = NULL;
if (uuid_parse(params->family_uuid, family_uuid_bin) < 0) {
log_dbg(cd, "Could not parse logical volume family UUID: %s.",
@@ -915,62 +923,61 @@ int FVAULT2_get_volume_key(
goto out;
}
passphrase_key = crypt_safe_alloc(FVAULT2_AES_KEY_SIZE);
passphrase_key = crypt_alloc_volume_key(FVAULT2_AES_KEY_SIZE, NULL);
if (passphrase_key == NULL) {
r = -ENOMEM;
goto out;
}
r = crypt_pbkdf("pbkdf2", "sha256", passphrase, passphrase_len,
params->pbkdf2_salt, FVAULT2_PBKDF2_SALT_SIZE, passphrase_key,
params->pbkdf2_salt, FVAULT2_PBKDF2_SALT_SIZE, passphrase_key->key,
FVAULT2_AES_KEY_SIZE, params->pbkdf2_iters, 0, 0);
if (r < 0)
goto out;
kek = crypt_safe_alloc(FVAULT2_AES_KEY_SIZE);
kek = crypt_alloc_volume_key(FVAULT2_AES_KEY_SIZE, NULL);
if (kek == NULL) {
r = -ENOMEM;
goto out;
}
r = _unwrap_key(passphrase_key, FVAULT2_AES_KEY_SIZE, params->wrapped_kek,
FVAULT2_WRAPPED_KEY_SIZE, kek, FVAULT2_AES_KEY_SIZE);
r = _unwrap_key(passphrase_key->key, FVAULT2_AES_KEY_SIZE, params->wrapped_kek,
FVAULT2_WRAPPED_KEY_SIZE, kek->key, FVAULT2_AES_KEY_SIZE);
if (r < 0)
goto out;
vol_key = crypt_safe_alloc(FVAULT2_XTS_KEY_SIZE);
if (vol_key == NULL) {
*vol_key = crypt_alloc_volume_key(FVAULT2_XTS_KEY_SIZE, NULL);
if (*vol_key == NULL) {
r = -ENOMEM;
goto out;
}
r = _unwrap_key(kek, FVAULT2_AES_KEY_SIZE, params->wrapped_vk,
FVAULT2_WRAPPED_KEY_SIZE, vol_key, FVAULT2_AES_KEY_SIZE);
r = _unwrap_key(kek->key, FVAULT2_AES_KEY_SIZE, params->wrapped_vk,
FVAULT2_WRAPPED_KEY_SIZE, (*vol_key)->key, FVAULT2_AES_KEY_SIZE);
if (r < 0)
goto out;
r = crypt_hash_init(&hash, "sha256");
if (r < 0)
goto out;
r = crypt_hash_write(hash, vol_key, FVAULT2_AES_KEY_SIZE);
r = crypt_hash_write(hash, (*vol_key)->key, FVAULT2_AES_KEY_SIZE);
if (r < 0)
goto out;
r = crypt_hash_write(hash, (char *)family_uuid_bin,
FVAULT2_UUID_BIN_SIZE);
if (r < 0)
goto out;
r = crypt_hash_final(hash, (char *)vol_key + FVAULT2_AES_KEY_SIZE,
r = crypt_hash_final(hash, (*vol_key)->key + FVAULT2_AES_KEY_SIZE,
FVAULT2_AES_KEY_SIZE);
if (r < 0)
goto out;
*r_vol_key = crypt_alloc_volume_key_by_safe_alloc(&vol_key);
if (!*r_vol_key)
r = -ENOMEM;
out:
crypt_safe_free(passphrase_key);
crypt_safe_free(kek);
crypt_safe_free(vol_key);
crypt_free_volume_key(passphrase_key);
crypt_free_volume_key(kek);
if (r < 0) {
crypt_free_volume_key(*vol_key);
*vol_key = NULL;
}
if (hash != NULL)
crypt_hash_destroy(hash);
return r;
@@ -1003,19 +1010,48 @@ int FVAULT2_dump(
return 0;
}
int FVAULT2_activate_by_volume_key(
int FVAULT2_activate_by_passphrase(
struct crypt_device *cd,
const char *name,
struct volume_key *vk,
const char *passphrase,
size_t passphrase_len,
const struct fvault2_params *params,
uint32_t flags)
{
assert(crypt_volume_key_length(vk) == FVAULT2_XTS_KEY_SIZE);
int r;
struct volume_key *vol_key = NULL;
return _activate(cd, name, vk, params, flags);
r = FVAULT2_get_volume_key(cd, passphrase, passphrase_len, params, &vol_key);
if (r < 0)
return r;
if (name)
r = _activate(cd, name, vol_key, params, flags);
crypt_free_volume_key(vol_key);
return r;
}
size_t FVAULT2_volume_key_size(void)
int FVAULT2_activate_by_volume_key(
struct crypt_device *cd,
const char *name,
const char *key,
size_t key_size,
const struct fvault2_params *params,
uint32_t flags)
{
return FVAULT2_XTS_KEY_SIZE;
int r = 0;
struct volume_key *vol_key = NULL;
if (key_size != FVAULT2_XTS_KEY_SIZE)
return -EINVAL;
vol_key = crypt_alloc_volume_key(FVAULT2_XTS_KEY_SIZE, key);
if (vol_key == NULL)
return -ENOMEM;
r = _activate(cd, name, vol_key, params, flags);
crypt_free_volume_key(vol_key);
return r;
}

View File

@@ -1,8 +1,21 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* FVAULT2 (FileVault2-compatible) volume handling
*
* Copyright (C) 2021-2022 Pavel Tobias
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _CRYPTSETUP_FVAULT2_H
@@ -41,20 +54,27 @@ int FVAULT2_get_volume_key(
const char *passphrase,
size_t passphrase_len,
const struct fvault2_params *params,
struct volume_key **r_vol_key);
struct volume_key **vol_key);
int FVAULT2_dump(
struct crypt_device *cd,
struct device *device,
const struct fvault2_params *params);
int FVAULT2_activate_by_volume_key(
int FVAULT2_activate_by_passphrase(
struct crypt_device *cd,
const char *name,
struct volume_key *vk,
const char *passphrase,
size_t passphrase_len,
const struct fvault2_params *params,
uint32_t flags);
size_t FVAULT2_volume_key_size(void);
int FVAULT2_activate_by_volume_key(
struct crypt_device *cd,
const char *name,
const char *key,
size_t key_size,
const struct fvault2_params *params,
uint32_t flags);
#endif

View File

@@ -1,8 +1,21 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Integrity volume handling
*
* Copyright (C) 2016-2025 Milan Broz
* Copyright (C) 2016-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
@@ -31,22 +44,16 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
{
int devfd, r;
log_dbg(cd, "Reading kernel dm-integrity metadata on %s.", device_path(device));
devfd = device_open(cd, device, O_RDONLY);
if(devfd < 0)
return -EINVAL;
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb)) {
log_dbg(cd, "Cannot read kernel dm-integrity metadata on %s.", device_path(device));
return -EINVAL;
}
if (memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic))) {
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic))) {
log_dbg(cd, "No kernel dm-integrity metadata detected on %s.", device_path(device));
r = -EINVAL;
} else if (sb->version < SB_VERSION_1 || sb->version > SB_VERSION_6) {
} else if (sb->version < SB_VERSION_1 || sb->version > SB_VERSION_5) {
log_err(cd, _("Incompatible kernel dm-integrity metadata (version %u) detected on %s."),
sb->version, device_path(device));
r = -EINVAL;
@@ -73,10 +80,8 @@ int INTEGRITY_read_sb(struct crypt_device *cd,
if (r)
return r;
if (params) {
params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block;
params->tag_size = sb.integrity_tag_size;
}
params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block;
params->tag_size = sb.integrity_tag_size;
if (flags)
*flags = sb.flags;
@@ -87,32 +92,28 @@ int INTEGRITY_read_sb(struct crypt_device *cd,
int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offset)
{
struct superblock sb;
uint64_t sector_size;
int r;
r = INTEGRITY_read_superblock(cd, device, offset, &sb);
if (r)
return r;
sector_size = (uint64_t)SECTOR_SIZE << sb.log2_sectors_per_block;
log_std(cd, "INTEGRITY header information for %s.\n", device_path(device));
log_std(cd, "version: %d\n", (unsigned)sb.version);
log_std(cd, "tag size: %u [bytes]\n", sb.integrity_tag_size);
log_std(cd, "sector size: %" PRIu64 " [bytes]\n", sector_size);
log_std(cd, "data size: %" PRIu64 " [512-byte units] (%" PRIu64 " [bytes])\n",
sb.provided_data_sectors, sb.provided_data_sectors * SECTOR_SIZE);
log_std(cd, "Info for integrity device %s.\n", device_path(device));
log_std(cd, "superblock_version %d\n", (unsigned)sb.version);
log_std(cd, "log2_interleave_sectors %d\n", sb.log2_interleave_sectors);
log_std(cd, "integrity_tag_size %u\n", sb.integrity_tag_size);
log_std(cd, "journal_sections %u\n", sb.journal_sections);
log_std(cd, "provided_data_sectors %" PRIu64 "\n", sb.provided_data_sectors);
log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
if (sb.version >= SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
log_std(cd, "recalculate sector: %" PRIu64 "\n", sb.recalc_sector);
log_std(cd, "journal sections: %u\n", sb.journal_sections);
log_std(cd, "log2 interleave sectors: %d\n", sb.log2_interleave_sectors);
log_std(cd, "log2 blocks per bitmap: %u\n", sb.log2_blocks_per_bitmap_bit);
log_std(cd, "flags: %s%s%s%s%s%s\n",
log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
log_std(cd, "log2_blocks_per_bitmap %u\n", sb.log2_blocks_per_bitmap_bit);
log_std(cd, "flags %s%s%s%s%s\n",
sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "",
sb.flags & SB_FLAG_DIRTY_BITMAP ? "dirty_bitmap " : "",
sb.flags & SB_FLAG_FIXED_PADDING ? "fix_padding " : "",
sb.flags & SB_FLAG_FIXED_HMAC ? "fix_hmac " : "",
sb.flags & SB_FLAG_INLINE ? "inline " : "");
sb.flags & SB_FLAG_FIXED_HMAC ? "fix_hmac " : "");
return 0;
}
@@ -132,36 +133,26 @@ int INTEGRITY_data_sectors(struct crypt_device *cd,
return 0;
}
int INTEGRITY_key_size(const char *integrity, int required_key_size)
int INTEGRITY_key_size(const char *integrity)
{
int ks = 0;
if (!integrity && required_key_size)
return -EINVAL;
if (!integrity)
return 0;
//FIXME: use crypto backend hash size
if (!strcmp(integrity, "aead"))
ks = 0;
return 0;
else if (!strcmp(integrity, "hmac(sha1)"))
ks = required_key_size ?: 20;
return 20;
else if (!strcmp(integrity, "hmac(sha256)"))
ks = required_key_size ?: 32;
return 32;
else if (!strcmp(integrity, "hmac(sha512)"))
ks = required_key_size ?: 64;
return 64;
else if (!strcmp(integrity, "poly1305"))
ks = 0;
return 0;
else if (!strcmp(integrity, "none"))
ks = 0;
else
return -EINVAL;
return 0;
if (required_key_size && ks != required_key_size)
return -EINVAL;
return ks;
return -EINVAL;
}
/* Return hash or hmac(hash) size, if known */
@@ -252,9 +243,6 @@ int INTEGRITY_create_dmd_device(struct crypt_device *cd,
if (sb_flags & SB_FLAG_RECALCULATING)
dmd->flags |= CRYPT_ACTIVATE_RECALCULATE;
if (sb_flags & SB_FLAG_INLINE)
dmd->flags |= (CRYPT_ACTIVATE_NO_JOURNAL | CRYPT_ACTIVATE_INLINE_MODE);
r = INTEGRITY_data_sectors(cd, INTEGRITY_metadata_device(cd),
crypt_get_data_offset(cd) * SECTOR_SIZE, &dmd->size);
if (r < 0)
@@ -274,15 +262,14 @@ int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
uint32_t sb_flags)
{
int r;
uint64_t dmi_flags;
uint32_t dmi_flags;
struct dm_target *tgt = &dmd->segment;
if (!single_segment(dmd) || tgt->type != DM_INTEGRITY)
return -EINVAL;
log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d%s, provided sectors %" PRIu64".",
device_path(tgt->data_device), name, tgt->u.integrity.tag_size,
(sb_flags & SB_FLAG_INLINE) ? " (inline)" :"", dmd->size);
log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d, provided sectors %" PRIu64".",
device_path(tgt->data_device), name, tgt->u.integrity.tag_size, dmd->size);
r = create_or_reload_device(cd, name, type, dmd);
@@ -306,12 +293,6 @@ int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
return -ENOTSUP;
}
if (r < 0 && (sb_flags & SB_FLAG_INLINE) && !dm_flags(cd, DM_INTEGRITY, &dmi_flags) &&
!(dmi_flags & DM_INTEGRITY_INLINE_MODE_SUPPORTED)) {
log_err(cd, _("Kernel does not support dm-integrity inline mode."));
return -ENOTSUP;
}
return r;
}
@@ -404,14 +385,11 @@ static int _create_reduced_device(struct crypt_device *cd,
int INTEGRITY_format(struct crypt_device *cd,
const struct crypt_params_integrity *params,
struct volume_key *integrity_key,
struct volume_key *journal_crypt_key,
struct volume_key *journal_mac_key,
uint64_t backing_device_sectors,
uint32_t *sb_flags,
bool integrity_inline)
uint64_t backing_device_sectors)
{
uint64_t dmi_flags;
uint32_t dmi_flags;
char reduced_device_name[70], tmp_name[64], tmp_uuid[40];
struct crypt_dm_active_device dmdi = {
.size = 8,
@@ -422,6 +400,7 @@ int INTEGRITY_format(struct crypt_device *cd,
uuid_t tmp_uuid_bin;
uint64_t data_offset_sectors;
struct device *p_metadata_device, *p_data_device, *reduced_device = NULL;
struct volume_key *vk = NULL;
uuid_generate(tmp_uuid_bin);
uuid_unparse(tmp_uuid_bin, tmp_uuid);
@@ -456,18 +435,19 @@ int INTEGRITY_format(struct crypt_device *cd,
p_data_device = crypt_data_device(cd);
}
if (integrity_inline)
dmdi.flags |= (CRYPT_ACTIVATE_NO_JOURNAL | CRYPT_ACTIVATE_INLINE_MODE);
/* There is no data area, we can actually use fake zeroed key */
if (params && params->integrity_key_size)
vk = crypt_alloc_volume_key(params->integrity_key_size, NULL);
r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, p_metadata_device,
p_data_device, crypt_get_integrity_tag_size(cd),
data_offset_sectors, crypt_get_sector_size(cd), integrity_key,
data_offset_sectors, crypt_get_sector_size(cd), vk,
journal_crypt_key, journal_mac_key, params);
if (r < 0)
goto err;
log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d%s.",
device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size, integrity_inline ? " (inline)" : "");
log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d.",
device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size);
r = device_block_adjust(cd, tgt->data_device, DEV_EXCL, tgt->u.integrity.offset, NULL, NULL);
if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
@@ -488,14 +468,9 @@ int INTEGRITY_format(struct crypt_device *cd,
goto err;
r = dm_remove_device(cd, tmp_name, CRYPT_DEACTIVATE_FORCE);
if (r)
goto err;
/* reload sb_flags from superblock (important for SB_FLAG_INLINE) */
if (sb_flags)
r = INTEGRITY_read_sb(cd, NULL, sb_flags);
err:
dm_targets_free(cd, &dmdi);
crypt_free_volume_key(vk);
if (reduced_device) {
dm_remove_device(cd, reduced_device_name, CRYPT_DEACTIVATE_FORCE);
device_free(cd, reduced_device);

View File

@@ -1,15 +1,27 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Integrity header definition
*
* Copyright (C) 2016-2025 Milan Broz
* Copyright (C) 2016-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _CRYPTSETUP_INTEGRITY_H
#define _CRYPTSETUP_INTEGRITY_H
#include <stdint.h>
#include <stdbool.h>
struct crypt_device;
struct device;
@@ -24,14 +36,12 @@ struct crypt_dm_active_device;
#define SB_VERSION_3 3
#define SB_VERSION_4 4
#define SB_VERSION_5 5
#define SB_VERSION_6 6
#define SB_FLAG_HAVE_JOURNAL_MAC (1 << 0)
#define SB_FLAG_RECALCULATING (1 << 1) /* V2 only */
#define SB_FLAG_DIRTY_BITMAP (1 << 2) /* V3 only */
#define SB_FLAG_FIXED_PADDING (1 << 3) /* V4 only */
#define SB_FLAG_FIXED_HMAC (1 << 4) /* V5 only */
#define SB_FLAG_INLINE (1 << 5) /* V6 only */
struct superblock {
uint8_t magic[8];
@@ -43,10 +53,8 @@ struct superblock {
uint32_t flags;
uint8_t log2_sectors_per_block;
uint8_t log2_blocks_per_bitmap_bit; /* V3 only */
uint8_t pad[2]; /* (padding) */
uint8_t pad[2];
uint64_t recalc_sector; /* V2 only */
uint8_t pad2[8]; /* (padding) */
uint8_t salt[16]; /* for fixed hmac, V5 only */
} __attribute__ ((packed));
int INTEGRITY_read_sb(struct crypt_device *cd,
@@ -58,7 +66,7 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
int INTEGRITY_data_sectors(struct crypt_device *cd,
struct device *device, uint64_t offset,
uint64_t *data_sectors);
int INTEGRITY_key_size(const char *integrity, int required_key_size);
int INTEGRITY_key_size(const char *integrity);
int INTEGRITY_tag_size(const char *integrity,
const char *cipher,
const char *cipher_mode);
@@ -66,12 +74,9 @@ int INTEGRITY_hash_tag_size(const char *integrity);
int INTEGRITY_format(struct crypt_device *cd,
const struct crypt_params_integrity *params,
struct volume_key *integrity_key,
struct volume_key *journal_crypt_key,
struct volume_key *journal_mac_key,
uint64_t backing_device_sectors,
uint32_t *sb_flags,
bool integrity_inline);
uint64_t backing_device_sectors);
int INTEGRITY_activate(struct crypt_device *cd,
const char *name,

View File

@@ -1,11 +1,24 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* libcryptsetup - cryptsetup library internal
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2025 Milan Broz
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2024 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef INTERNAL_H
@@ -48,36 +61,24 @@
struct crypt_device;
struct luks2_reencrypt;
struct volume_key;
typedef enum {
KEY_QUALITY_KEY = 0,
KEY_QUALITY_NORMAL,
KEY_QUALITY_EMPTY
} key_quality_info;
struct volume_key {
int id;
size_t keylength;
const char *key_description;
struct volume_key *next;
char key[];
};
struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key);
struct volume_key *crypt_alloc_volume_key_by_safe_alloc(void **safe_alloc);
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength,
key_quality_info quality);
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength);
void crypt_free_volume_key(struct volume_key *vk);
const char *crypt_volume_key_get_key(const struct volume_key *vk);
size_t crypt_volume_key_length(const struct volume_key *vk);
int crypt_volume_key_set_description(struct volume_key *key,
const char *key_description, key_type_t keyring_key_type);
int crypt_volume_key_set_description_by_name(struct volume_key *vk, const char *key_name);
key_type_t crypt_volume_key_kernel_key_type(const struct volume_key *vk);
const char *crypt_volume_key_description(const struct volume_key *vk);
int crypt_volume_key_set_description(struct volume_key *key, const char *key_description);
void crypt_volume_key_set_id(struct volume_key *vk, int id);
int crypt_volume_key_get_id(const struct volume_key *vk);
void crypt_volume_key_add_next(struct volume_key **vks, struct volume_key *vk);
struct volume_key *crypt_volume_key_next(struct volume_key *vk);
struct volume_key *crypt_volume_key_by_id(struct volume_key *vk, int id);
void crypt_volume_key_pass_safe_alloc(struct volume_key *vk, void **safe_alloc);
bool crypt_volume_key_is_set(const struct volume_key *vk);
bool crypt_volume_key_upload_kernel_key(struct volume_key *vk);
void crypt_volume_key_drop_uploaded_kernel_key(struct crypt_device *cd, struct volume_key *vk);
void crypt_volume_key_drop_kernel_key(struct crypt_device *cd, struct volume_key *vk);
struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd);
int init_pbkdf_type(struct crypt_device *cd,
@@ -98,6 +99,7 @@ int device_alloc_no_check(struct device **device, const char *path);
void device_close(struct crypt_device *cd, struct device *device);
void device_free(struct crypt_device *cd, struct device *device);
const char *device_path(const struct device *device);
const char *device_dm_name(const struct device *device);
const char *device_block_path(const struct device *device);
void device_topology_alignment(struct crypt_device *cd,
struct device *device,
@@ -114,8 +116,6 @@ void device_disable_direct_io(struct device *device);
int device_is_identical(struct device *device1, struct device *device2);
int device_is_rotational(struct device *device);
int device_is_dax(struct device *device);
int device_is_zoned(struct device *device);
int device_is_nop_dif(struct device *device, uint32_t *tag_size);
size_t device_alignment(struct device *device);
int device_direct_io(const struct device *device);
int device_fallocate(struct device *device, uint64_t size);
@@ -166,8 +166,6 @@ int crypt_confirm(struct crypt_device *cd, const char *msg);
char *crypt_lookup_dev(const char *dev_id);
int crypt_dev_is_rotational(int major, int minor);
int crypt_dev_is_dax(int major, int minor);
int crypt_dev_is_zoned(int major, int minor);
int crypt_dev_is_nop_dif(int major, int minor, uint32_t *tag_size);
int crypt_dev_is_partition(const char *dev_path);
char *crypt_get_partition_device(const char *dev_path, uint64_t offset, uint64_t size);
int crypt_dev_get_partition_number(const char *dev_path);
@@ -175,6 +173,8 @@ char *crypt_get_base_device(const char *dev_path);
uint64_t crypt_dev_partition_offset(const char *dev_path);
int lookup_by_disk_id(const char *dm_uuid);
int lookup_by_sysfs_uuid_field(const char *dm_uuid);
int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid);
int crypt_uuid_type_cmp(const char *dm_uuid, const char *type);
size_t crypt_getpagesize(void);
unsigned crypt_cpusonline(void);
@@ -228,7 +228,7 @@ int crypt_wipe_device(struct crypt_device *cd,
/* Internal integrity helpers */
const char *crypt_get_integrity(struct crypt_device *cd);
int crypt_get_integrity_key_size(struct crypt_device *cd, bool dm_compat);
int crypt_get_integrity_key_size(struct crypt_device *cd);
int crypt_get_integrity_tag_size(struct crypt_device *cd);
int crypt_key_in_keyring(struct crypt_device *cd);
@@ -242,18 +242,9 @@ int crypt_keyring_get_key_by_name(struct crypt_device *cd,
const char *key_description,
char **key,
size_t *key_size);
int crypt_keyring_get_keysize_by_name(struct crypt_device *cd,
const char *key_description,
size_t *r_key_size);
int crypt_use_keyring_for_vk(struct crypt_device *cd);
void crypt_unlink_key_from_thread_keyring(struct crypt_device *cd,
key_serial_t key_id);
void crypt_unlink_key_by_description_from_thread_keyring(struct crypt_device *cd,
const char *key_description,
key_type_t ktype);
void crypt_drop_uploaded_keyring_key(struct crypt_device *cd, struct volume_key *vks);
void crypt_drop_keyring_key_by_description(struct crypt_device *cd, const char *key_description, key_type_t ktype);
void crypt_drop_keyring_key(struct crypt_device *cd, struct volume_key *vks);
static inline uint64_t compact_version(uint16_t major, uint16_t minor, uint16_t patch, uint16_t release)
{
@@ -275,8 +266,6 @@ static inline void *crypt_zalloc(size_t size) { return calloc(1, size); }
static inline bool uint64_mult_overflow(uint64_t *u, uint64_t b, size_t size)
{
*u = (uint64_t)b * size;
if (size == 0)
return true;
if ((uint64_t)(*u / size) != b)
return true;
return false;
@@ -286,6 +275,4 @@ static inline bool uint64_mult_overflow(uint64_t *u, uint64_t b, size_t size)
#define KEY_EXTERNAL_VERIFICATION -1
#define KEY_VERIFIED 0
size_t crypt_safe_alloc_size(const void *data);
#endif /* INTERNAL_H */

View File

@@ -1,15 +1,26 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup, keyslot unlock helpers
*
* Copyright (C) 2022-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2022-2025 Ondrej Kozina
* Copyright (C) 2022-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2022-2024 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
#include "bitlk/bitlk.h"
#include "fvault2/fvault2.h"
#include "luks1/luks.h"
#include "luks2/luks2.h"
#include "keyslot_context.h"
@@ -60,44 +71,6 @@ static int get_luks2_volume_key_by_passphrase(struct crypt_device *cd,
return get_luks2_key_by_passphrase(cd, kc, keyslot, CRYPT_DEFAULT_SEGMENT, r_vk);
}
static int get_bitlk_volume_key_by_passphrase(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct bitlk_metadata *params,
struct volume_key **r_vk)
{
int r;
assert(cd);
assert(kc && kc->type == CRYPT_KC_TYPE_PASSPHRASE);
assert(params);
assert(r_vk);
r = BITLK_get_volume_key(cd, kc->u.p.passphrase, kc->u.p.passphrase_size, params, r_vk);
if (r < 0)
kc->error = r;
return r;
}
static int get_fvault2_volume_key_by_passphrase(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct fvault2_params *params,
struct volume_key **r_vk)
{
int r;
assert(cd);
assert(kc && kc->type == CRYPT_KC_TYPE_PASSPHRASE);
assert(params);
assert(r_vk);
r = FVAULT2_get_volume_key(cd, kc->u.p.passphrase, kc->u.p.passphrase_size, params, r_vk);
if (r < 0)
kc->error = r;
return r;
}
static int get_passphrase_by_passphrase(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const char **r_passphrase,
@@ -200,56 +173,6 @@ static int get_luks1_volume_key_by_keyfile(struct crypt_device *cd,
return r;
}
static int get_bitlk_volume_key_by_keyfile(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct bitlk_metadata *params,
struct volume_key **r_vk)
{
int r;
const char *passphrase;
size_t passphrase_size;
assert(cd);
assert(kc && kc->type == CRYPT_KC_TYPE_KEYFILE);
assert(params);
assert(r_vk);
r = get_passphrase_by_keyfile(cd, kc, &passphrase, &passphrase_size);
if (r < 0)
return r;
r = BITLK_get_volume_key(cd, passphrase, passphrase_size, params, r_vk);
if (r < 0)
kc->error = r;
return r;
}
static int get_fvault2_volume_key_by_keyfile(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct fvault2_params *params,
struct volume_key **r_vk)
{
int r;
const char *passphrase;
size_t passphrase_size;
assert(cd);
assert(kc && kc->type == CRYPT_KC_TYPE_KEYFILE);
assert(params);
assert(r_vk);
r = get_passphrase_by_keyfile(cd, kc, &passphrase, &passphrase_size);
if (r < 0)
return r;
r = FVAULT2_get_volume_key(cd, passphrase, passphrase_size, params, r_vk);
if (r < 0)
kc->error = r;
return r;
}
static int get_key_by_key(struct crypt_device *cd __attribute__((unused)),
struct crypt_keyslot_context *kc,
int keyslot __attribute__((unused)),
@@ -288,22 +211,6 @@ static int get_generic_volume_key_by_key(struct crypt_device *cd,
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
}
static int get_bitlk_volume_key_by_key(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct bitlk_metadata *params __attribute__((unused)),
struct volume_key **r_vk)
{
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
}
static int get_fvault2_volume_key_by_key(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct fvault2_params *params __attribute__((unused)),
struct volume_key **r_vk)
{
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
}
static int get_generic_signed_key_by_key(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
struct volume_key **r_vk,
@@ -460,7 +367,7 @@ static int get_luks2_key_by_keyring(struct crypt_device *cd,
if (r < 0)
kc->error = r;
return r;
return 0;
}
static int get_luks2_volume_key_by_keyring(struct crypt_device *cd,
@@ -479,7 +386,7 @@ static int get_luks1_volume_key_by_keyring(struct crypt_device *cd,
int r;
assert(cd);
assert(kc && kc->type == CRYPT_KC_TYPE_KEYRING);
assert(kc && kc->type == CRYPT_KC_TYPE_PASSPHRASE);
assert(r_vk);
r = get_passphrase_by_keyring(cd, kc, CONST_CAST(const char **) &kc->i_passphrase,
@@ -520,9 +427,9 @@ static int get_key_by_vk_in_keyring(struct crypt_device *cd,
return -EINVAL;
}
*r_vk = crypt_alloc_volume_key_by_safe_alloc((void **)&key);
*r_vk = crypt_alloc_volume_key(key_size, key);
crypt_safe_free(key);
if (!*r_vk) {
crypt_safe_free(key);
kc->error = -ENOMEM;
return kc->error;
}
@@ -538,41 +445,16 @@ static int get_volume_key_by_vk_in_keyring(struct crypt_device *cd,
return get_key_by_vk_in_keyring(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
}
static void crypt_keyslot_context_init_common(struct crypt_keyslot_context *kc)
static void unlock_method_init_internal(struct crypt_keyslot_context *kc)
{
assert(kc);
kc->version = KC_VERSION_BASIC;
kc->error = 0;
kc->i_passphrase = NULL;
kc->i_passphrase_size = 0;
}
static void keyring_context_free(struct crypt_keyslot_context *kc)
{
assert(kc && kc->type == CRYPT_KC_TYPE_KEYRING);
free(kc->u.kr.i_key_description);
}
static int keyring_get_key_size(struct crypt_device *cd, struct crypt_keyslot_context *kc, size_t *r_key_size)
{
int r;
assert(kc && kc->type == CRYPT_KC_TYPE_VK_KEYRING);
assert(r_key_size);
if (!kc->u.vk_kr.i_key_size) {
r = crypt_keyring_get_keysize_by_name(cd, kc->u.vk_kr.key_description, &kc->u.vk_kr.i_key_size);
if (r < 0)
return r;
}
*r_key_size = kc->u.vk_kr.i_key_size;
return 0;
}
void crypt_keyslot_context_init_by_keyring_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_keyring_internal(struct crypt_keyslot_context *kc,
const char *key_description)
{
assert(kc);
@@ -581,32 +463,18 @@ void crypt_keyslot_context_init_by_keyring_internal(struct crypt_keyslot_context
kc->u.kr.key_description = key_description;
kc->get_luks2_key = get_luks2_key_by_keyring;
kc->get_luks1_volume_key = get_luks1_volume_key_by_keyring;
kc->get_luks2_volume_key = get_luks2_volume_key_by_keyring;
kc->get_luks1_volume_key = get_luks1_volume_key_by_keyring;
kc->get_passphrase = get_passphrase_by_keyring;
kc->context_free = keyring_context_free;
crypt_keyslot_context_init_common(kc);
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
static void key_context_free(struct crypt_keyslot_context *kc)
{
assert(kc && kc->type == CRYPT_KC_TYPE_KEY);
crypt_free_volume_key(kc->u.k.i_vk);
}
static int key_get_key_size(struct crypt_device *cd __attribute__((unused)),
struct crypt_keyslot_context *kc,
size_t *r_key_size)
{
assert(kc && kc->type == CRYPT_KC_TYPE_KEY);
assert(r_key_size);
*r_key_size = kc->u.k.volume_key_size;
return 0;
}
void crypt_keyslot_context_init_by_key_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_key_init_internal(struct crypt_keyslot_context *kc,
const char *volume_key,
size_t volume_key_size)
{
@@ -615,29 +483,19 @@ void crypt_keyslot_context_init_by_key_internal(struct crypt_keyslot_context *kc
kc->type = CRYPT_KC_TYPE_KEY;
kc->u.k.volume_key = volume_key;
kc->u.k.volume_key_size = volume_key_size;
kc->get_luks2_key = get_key_by_key;
kc->get_luks1_volume_key = get_volume_key_by_key;
kc->get_luks2_volume_key = get_volume_key_by_key;
kc->get_luks1_volume_key = get_volume_key_by_key;
kc->get_passphrase = NULL; /* keyslot key context does not provide passphrase */
kc->get_plain_volume_key = get_generic_volume_key_by_key;
kc->get_bitlk_volume_key = get_bitlk_volume_key_by_key;
kc->get_fvault2_volume_key = get_fvault2_volume_key_by_key;
kc->get_bitlk_volume_key = get_generic_volume_key_by_key;
kc->get_fvault2_volume_key = get_generic_volume_key_by_key;
kc->get_verity_volume_key = get_generic_signed_key_by_key;
kc->get_integrity_volume_key = get_generic_volume_key_by_key;
kc->get_key_size = key_get_key_size;
kc->context_free = key_context_free;
crypt_keyslot_context_init_common(kc);
unlock_method_init_internal(kc);
}
static void signed_key_context_free(struct crypt_keyslot_context *kc)
{
assert(kc && kc->type == CRYPT_KC_TYPE_SIGNED_KEY);
crypt_free_volume_key(kc->u.ks.i_vk);
crypt_free_volume_key(kc->u.ks.i_vk_sig);
}
void crypt_keyslot_context_init_by_signed_key_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_signed_key_init_internal(struct crypt_keyslot_context *kc,
const char *volume_key,
size_t volume_key_size,
const char *signature,
@@ -650,13 +508,19 @@ void crypt_keyslot_context_init_by_signed_key_internal(struct crypt_keyslot_cont
kc->u.ks.volume_key_size = volume_key_size;
kc->u.ks.signature = signature;
kc->u.ks.signature_size = signature_size;
kc->get_luks2_key = NULL;
kc->get_luks2_volume_key = NULL;
kc->get_luks1_volume_key = NULL;
kc->get_passphrase = NULL;
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = get_generic_signed_key_by_key;
kc->context_free = signed_key_context_free;
crypt_keyslot_context_init_common(kc);
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
void crypt_keyslot_context_init_by_passphrase_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_passphrase_init_internal(struct crypt_keyslot_context *kc,
const char *passphrase,
size_t passphrase_size)
{
@@ -665,24 +529,19 @@ void crypt_keyslot_context_init_by_passphrase_internal(struct crypt_keyslot_cont
kc->type = CRYPT_KC_TYPE_PASSPHRASE;
kc->u.p.passphrase = passphrase;
kc->u.p.passphrase_size = passphrase_size;
kc->get_luks2_key = get_luks2_key_by_passphrase;
kc->get_luks1_volume_key = get_luks1_volume_key_by_passphrase;
kc->get_luks2_volume_key = get_luks2_volume_key_by_passphrase;
kc->get_bitlk_volume_key = get_bitlk_volume_key_by_passphrase;
kc->get_fvault2_volume_key = get_fvault2_volume_key_by_passphrase;
kc->get_luks1_volume_key = get_luks1_volume_key_by_passphrase;
kc->get_passphrase = get_passphrase_by_passphrase;
crypt_keyslot_context_init_common(kc);
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
static void keyfile_context_free(struct crypt_keyslot_context *kc)
{
assert(kc && kc->type == CRYPT_KC_TYPE_KEYFILE);
free(kc->u.kf.i_keyfile);
}
void crypt_keyslot_context_init_by_keyfile_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_keyfile_init_internal(struct crypt_keyslot_context *kc,
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset)
@@ -691,28 +550,21 @@ void crypt_keyslot_context_init_by_keyfile_internal(struct crypt_keyslot_context
kc->type = CRYPT_KC_TYPE_KEYFILE;
kc->u.kf.keyfile = keyfile;
kc->u.kf.keyfile_offset = keyfile_offset;
kc->u.kf.keyfile_size = keyfile_size;
kc->u.kf.keyfile_offset = keyfile_offset;
kc->get_luks2_key = get_luks2_key_by_keyfile;
kc->get_luks1_volume_key = get_luks1_volume_key_by_keyfile;
kc->get_luks2_volume_key = get_luks2_volume_key_by_keyfile;
kc->get_bitlk_volume_key = get_bitlk_volume_key_by_keyfile;
kc->get_fvault2_volume_key = get_fvault2_volume_key_by_keyfile;
kc->get_luks1_volume_key = get_luks1_volume_key_by_keyfile;
kc->get_passphrase = get_passphrase_by_keyfile;
kc->context_free = keyfile_context_free;
crypt_keyslot_context_init_common(kc);
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
static void token_context_free(struct crypt_keyslot_context *kc)
{
assert(kc && kc->type == CRYPT_KC_TYPE_TOKEN);
free(kc->u.t.i_type);
crypt_safe_free(kc->u.t.i_pin);
}
void crypt_keyslot_context_init_by_token_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_token_init_internal(struct crypt_keyslot_context *kc,
int token,
const char *type,
const char *pin,
@@ -727,30 +579,47 @@ void crypt_keyslot_context_init_by_token_internal(struct crypt_keyslot_context *
kc->u.t.pin = pin;
kc->u.t.pin_size = pin_size;
kc->u.t.usrptr = usrptr;
kc->get_luks2_key = get_luks2_key_by_token;
kc->get_luks2_volume_key = get_luks2_volume_key_by_token;
kc->get_luks1_volume_key = NULL; /* LUKS1 is not supported */
kc->get_passphrase = get_passphrase_by_token;
kc->context_free = token_context_free;
crypt_keyslot_context_init_common(kc);
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
static void vk_in_keyring_context_free(struct crypt_keyslot_context *kc)
void crypt_keyslot_unlock_by_vk_in_keyring_internal(struct crypt_keyslot_context *kc,
const char *key_description)
{
assert(kc && kc->type == CRYPT_KC_TYPE_VK_KEYRING);
assert(kc);
free(kc->u.vk_kr.i_key_description);
kc->type = CRYPT_KC_TYPE_VK_KEYRING;
kc->u.vk_kr.key_description = key_description;
kc->get_luks2_key = get_key_by_vk_in_keyring;
kc->get_luks2_volume_key = get_volume_key_by_vk_in_keyring;
kc->get_luks1_volume_key = NULL;
kc->get_passphrase = NULL; /* keyslot key context does not provide passphrase */
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
void crypt_keyslot_context_destroy_internal(struct crypt_keyslot_context *kc)
{
if (!kc)
return;
if (kc->context_free)
kc->context_free(kc);
crypt_safe_free(kc->i_passphrase);
kc->i_passphrase = NULL;
kc->i_passphrase_size = 0;
}
void crypt_keyslot_context_free(struct crypt_keyslot_context *kc)
@@ -759,443 +628,157 @@ void crypt_keyslot_context_free(struct crypt_keyslot_context *kc)
free(kc);
}
static int _crypt_keyslot_context_init_by_passphrase(const char *passphrase,
int crypt_keyslot_context_init_by_passphrase(struct crypt_device *cd __attribute__((unused)),
const char *passphrase,
size_t passphrase_size,
struct crypt_keyslot_context **kc,
bool self_contained)
struct crypt_keyslot_context **kc)
{
struct crypt_keyslot_context *tmp;
char *i_passphrase = NULL;
if (!kc || !passphrase)
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained) {
if (passphrase_size) {
i_passphrase = crypt_safe_alloc(passphrase_size);
if (!i_passphrase) {
free(tmp);
return -ENOMEM;
}
crypt_safe_memcpy(i_passphrase, passphrase, passphrase_size);
passphrase = i_passphrase;
} else
/*
* some crypto backend libraries expect a pointer even though
* passed passphrase size is set to zero.
*/
passphrase = "";
}
crypt_keyslot_context_init_by_passphrase_internal(tmp, passphrase, passphrase_size);
if (self_contained) {
tmp->i_passphrase = i_passphrase;
tmp->i_passphrase_size = passphrase_size;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
crypt_keyslot_unlock_by_passphrase_init_internal(tmp, passphrase, passphrase_size);
*kc = tmp;
return 0;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_passphrase, 2, 8,
/* crypt_keyslot_context_init_by_passphrase parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *passphrase,
size_t passphrase_size,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_passphrase(passphrase, passphrase_size, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_passphrase, 2, 6,
/* crypt_keyslot_context_init_by_passphrase parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *passphrase,
size_t passphrase_size,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_passphrase(passphrase, passphrase_size, kc, false);
}
static int _crypt_keyslot_context_init_by_keyfile(const char *keyfile,
int crypt_keyslot_context_init_by_keyfile(struct crypt_device *cd __attribute__((unused)),
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset,
struct crypt_keyslot_context **kc,
bool self_contained)
struct crypt_keyslot_context **kc)
{
char *i_keyfile;
struct crypt_keyslot_context *tmp;
if (!kc || !keyfile)
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained) {
i_keyfile = strdup(keyfile);
if (!i_keyfile) {
free(tmp);
return -ENOMEM;
}
keyfile = i_keyfile;
}
crypt_keyslot_context_init_by_keyfile_internal(tmp, keyfile, keyfile_size, keyfile_offset);
if (self_contained) {
tmp->u.kf.i_keyfile = i_keyfile;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
crypt_keyslot_unlock_by_keyfile_init_internal(tmp, keyfile, keyfile_size, keyfile_offset);
*kc = tmp;
return 0;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_keyfile, 2, 8,
/* crypt_keyslot_context_init_by_keyfile parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_keyfile(keyfile, keyfile_size, keyfile_offset, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_keyfile, 2, 6,
/* crypt_keyslot_context_init_by_keyfile parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_keyfile(keyfile, keyfile_size, keyfile_offset, kc, false);
}
static int _crypt_keyslot_context_init_by_token(int token,
int crypt_keyslot_context_init_by_token(struct crypt_device *cd __attribute__((unused)),
int token,
const char *type,
const char *pin, size_t pin_size,
void *usrptr,
struct crypt_keyslot_context **kc,
bool self_contained)
struct crypt_keyslot_context **kc)
{
char *i_type = NULL, *i_pin = NULL;
struct crypt_keyslot_context *tmp;
if (!kc || (token < 0 && token != CRYPT_ANY_TOKEN) ||
(pin && !pin_size))
if (!kc || (token < 0 && token != CRYPT_ANY_TOKEN))
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained && type) {
if (!(i_type = strdup(type)))
goto err;
type = i_type;
}
if (self_contained && pin) {
if (!(i_pin = crypt_safe_alloc(pin_size)))
goto err;
crypt_safe_memcpy(i_pin, pin, pin_size);
pin = i_pin;
}
crypt_keyslot_context_init_by_token_internal(tmp, token, type, pin, pin_size, usrptr);
if (self_contained) {
tmp->u.t.i_pin = i_pin;
tmp->u.t.i_type = i_type;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
crypt_keyslot_unlock_by_token_init_internal(tmp, token, type, pin, pin_size, usrptr);
*kc = tmp;
return 0;
err:
crypt_safe_free(i_pin);
free(i_type);
free(tmp);
return -ENOMEM;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_token, 2, 8,
/* crypt_keyslot_context_init_by_token parameters follows */
struct crypt_device *cd __attribute__((unused)),
int token,
const char *type,
const char *pin, size_t pin_size,
void *usrptr,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_token(token, type, pin, pin_size, usrptr, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_token, 2, 6,
/* crypt_keyslot_context_init_by_token parameters follows */
struct crypt_device *cd __attribute__((unused)),
int token,
const char *type,
const char *pin, size_t pin_size,
void *usrptr,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_token(token, type, pin, pin_size, usrptr, kc, false);
}
static int _crypt_keyslot_context_init_by_volume_key(const char *volume_key,
int crypt_keyslot_context_init_by_volume_key(struct crypt_device *cd __attribute__((unused)),
const char *volume_key,
size_t volume_key_size,
struct crypt_keyslot_context **kc,
bool self_contained)
struct crypt_keyslot_context **kc)
{
struct volume_key *i_vk = NULL;
struct crypt_keyslot_context *tmp;
if (!kc)
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained && volume_key) {
if (!(i_vk = crypt_alloc_volume_key(volume_key_size, volume_key))) {
free(tmp);
return -ENOMEM;
}
volume_key = crypt_volume_key_get_key(i_vk);
}
crypt_keyslot_context_init_by_key_internal(tmp, volume_key, volume_key_size);
if (self_contained) {
tmp->u.k.i_vk = i_vk;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
crypt_keyslot_unlock_by_key_init_internal(tmp, volume_key, volume_key_size);
*kc = tmp;
return 0;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_volume_key, 2, 8,
/* crypt_keyslot_context_init_by_volume_key parameters follows */
struct crypt_device *cd __attribute__((unused)),
int crypt_keyslot_context_init_by_signed_key(struct crypt_device *cd __attribute__((unused)),
const char *volume_key,
size_t volume_key_size,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_volume_key(volume_key, volume_key_size, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_volume_key, 2, 6,
/* crypt_keyslot_context_init_by_volume_key parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *volume_key,
size_t volume_key_size,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_volume_key(volume_key, volume_key_size, kc, false);
}
static int _crypt_keyslot_context_init_by_signed_key(const char *volume_key,
size_t volume_key_size,
const char *signature,
size_t signature_size,
struct crypt_keyslot_context **kc,
bool self_contained)
struct crypt_keyslot_context **kc)
{
struct volume_key *i_vk = NULL, *i_vk_sig = NULL;
struct crypt_keyslot_context *tmp;
if (!kc)
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained && volume_key) {
if (!(i_vk = crypt_alloc_volume_key(volume_key_size, volume_key)))
goto err;
volume_key = crypt_volume_key_get_key(i_vk);
}
if (self_contained && signature) {
if (!(i_vk_sig = crypt_alloc_volume_key(signature_size, signature)))
goto err;
signature = crypt_volume_key_get_key(i_vk_sig);
}
crypt_keyslot_context_init_by_signed_key_internal(tmp, volume_key, volume_key_size,
crypt_keyslot_unlock_by_signed_key_init_internal(tmp, volume_key, volume_key_size,
signature, signature_size);
if (self_contained) {
tmp->u.ks.i_vk = i_vk;
tmp->u.ks.i_vk_sig = i_vk_sig;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
*kc = tmp;
return 0;
err:
crypt_free_volume_key(i_vk);
crypt_free_volume_key(i_vk_sig);
free(tmp);
return -ENOMEM;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_signed_key, 2, 8,
/* crypt_keyslot_context_init_by_signed_key parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *volume_key,
size_t volume_key_size,
const char *signature,
size_t signature_size,
int crypt_keyslot_context_init_by_keyring(struct crypt_device *cd __attribute__((unused)),
const char *key_description,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_signed_key(volume_key, volume_key_size, signature, signature_size, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_signed_key, 2, 7,
/* crypt_keyslot_context_init_by_signed_key parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *volume_key,
size_t volume_key_size,
const char *signature,
size_t signature_size,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_signed_key(volume_key, volume_key_size, signature, signature_size, kc, false);
}
static int _crypt_keyslot_context_init_by_keyring(const char *key_description,
struct crypt_keyslot_context **kc,
bool self_contained)
{
char *i_key_description;
struct crypt_keyslot_context *tmp;
if (!kc || !key_description)
if (!kc)
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained) {
if (!(i_key_description = strdup(key_description))) {
free(tmp);
return -ENOMEM;
}
key_description = i_key_description;
}
crypt_keyslot_context_init_by_keyring_internal(tmp, key_description);
if (self_contained) {
tmp->u.kr.i_key_description = i_key_description;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
crypt_keyslot_unlock_by_keyring_internal(tmp, key_description);
*kc = tmp;
return 0;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_keyring, 2, 8,
/* crypt_keyslot_context_init_by_keyring parameters follows */
struct crypt_device *cd __attribute__((unused)),
int crypt_keyslot_context_init_by_vk_in_keyring(struct crypt_device *cd __attribute__((unused)),
const char *key_description,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_keyring(key_description, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_keyring, 2, 7,
/* crypt_keyslot_context_init_by_keyring parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *key_description,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_keyring(key_description, kc, false);
}
static int _crypt_keyslot_context_init_by_vk_in_keyring(const char *key_description,
struct crypt_keyslot_context **kc,
bool self_contained)
{
char *i_key_description;
struct crypt_keyslot_context *tmp;
if (!kc || !key_description)
if (!kc)
return -EINVAL;
tmp = crypt_zalloc(sizeof(*tmp));
tmp = malloc(sizeof(*tmp));
if (!tmp)
return -ENOMEM;
if (self_contained) {
if (!(i_key_description = strdup(key_description))) {
free(tmp);
return -ENOMEM;
}
key_description = i_key_description;
}
tmp->type = CRYPT_KC_TYPE_VK_KEYRING;
tmp->u.vk_kr.key_description = key_description;
tmp->get_luks2_key = get_key_by_vk_in_keyring;
tmp->get_luks2_volume_key = get_volume_key_by_vk_in_keyring;
tmp->get_key_size = keyring_get_key_size;
tmp->context_free = vk_in_keyring_context_free;
crypt_keyslot_context_init_common(tmp);
if (self_contained) {
tmp->u.vk_kr.i_key_description = i_key_description;
tmp->version = KC_VERSION_SELF_CONTAINED;
}
crypt_keyslot_unlock_by_vk_in_keyring_internal(tmp, key_description);
*kc = tmp;
return 0;
}
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_keyslot_context_init_by_vk_in_keyring, 2, 8,
/* crypt_keyslot_context_init_by_vk_in_keyring parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *key_description,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_vk_in_keyring(key_description, kc, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_keyslot_context_init_by_vk_in_keyring, 2, 7,
/* crypt_keyslot_context_init_by_vk_in_keyring parameters follows */
struct crypt_device *cd __attribute__((unused)),
const char *key_description,
struct crypt_keyslot_context **kc)
{
return _crypt_keyslot_context_init_by_vk_in_keyring(key_description, kc, false);
}
int crypt_keyslot_context_get_error(struct crypt_keyslot_context *kc)
{
return kc ? kc->error : -EINVAL;
@@ -1205,21 +788,10 @@ int crypt_keyslot_context_set_pin(struct crypt_device *cd __attribute__((unused)
const char *pin, size_t pin_size,
struct crypt_keyslot_context *kc)
{
char *i_pin = NULL;
if (!kc || kc->type != CRYPT_KC_TYPE_TOKEN)
return -EINVAL;
if (kc->version >= KC_VERSION_SELF_CONTAINED && pin) {
if (!(i_pin = crypt_safe_alloc(pin_size)))
return -ENOMEM;
crypt_safe_memcpy(i_pin, pin, pin_size);
}
crypt_safe_free(kc->u.t.i_pin);
kc->u.t.i_pin = i_pin;
kc->u.t.pin = i_pin ?: pin;
kc->u.t.pin = pin;
kc->u.t.pin_size = pin_size;
kc->error = 0;

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup, keyslot unlock helpers
*
* Copyright (C) 2022-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2022-2025 Ondrej Kozina
* Copyright (C) 2022-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2022-2024 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef KEYSLOT_CONTEXT_H
@@ -14,9 +27,6 @@
#include "internal.h"
struct bitlk_metadata;
struct fvault2_params;
typedef int (*keyslot_context_get_key) (
struct crypt_device *cd,
struct crypt_keyslot_context *kc,
@@ -35,19 +45,6 @@ typedef int (*keyslot_context_get_generic_volume_key) (
struct crypt_keyslot_context *kc,
struct volume_key **r_vk);
typedef int (*keyslot_context_get_bitlk_volume_key) (
struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct bitlk_metadata *params,
struct volume_key **r_vk);
typedef int (*keyslot_context_get_fvault2_volume_key) (
struct crypt_device *cd,
struct crypt_keyslot_context *kc,
const struct fvault2_params *params,
struct volume_key **r_vk);
typedef int (*keyslot_context_get_generic_signed_key) (
struct crypt_device *cd,
struct crypt_keyslot_context *kc,
@@ -60,28 +57,10 @@ typedef int (*keyslot_context_get_passphrase) (
const char **r_passphrase,
size_t *r_passphrase_size);
typedef void (*keyslot_context_free) (
struct crypt_keyslot_context *kc);
typedef int (*keyslot_context_get_key_size) (
struct crypt_device *cd,
struct crypt_keyslot_context *kc,
size_t *r_key_size);
#define KC_VERSION_BASIC UINT8_C(1)
#define KC_VERSION_SELF_CONTAINED UINT8_C(2)
/* crypt_keyslot_context */
struct crypt_keyslot_context {
int type;
/* versions:
* v1: All passed pointers (e.g.: type, passphrase, keyfile,...) must
* be valid after ctx initialization.
* v2: Fully self-contained
*/
uint8_t version;
union {
struct {
const char *passphrase;
@@ -89,40 +68,31 @@ struct crypt_keyslot_context {
} p;
struct {
const char *keyfile;
char *i_keyfile;
uint64_t keyfile_offset;
size_t keyfile_size;
} kf;
struct {
int id;
const char *type;
char *i_type;
const char *pin;
char *i_pin;
size_t pin_size;
void *usrptr;
} t;
struct {
const char *volume_key;
size_t volume_key_size;
struct volume_key *i_vk;
} k;
struct {
const char *volume_key;
size_t volume_key_size;
struct volume_key *i_vk;
const char *signature;
size_t signature_size;
struct volume_key *i_vk_sig;
} ks;
struct {
const char *key_description;
char *i_key_description;
} kr;
struct {
const char *key_description;
char *i_key_description;
size_t i_key_size;
} vk_kr;
} u;
@@ -135,44 +105,45 @@ struct crypt_keyslot_context {
keyslot_context_get_volume_key get_luks1_volume_key;
keyslot_context_get_volume_key get_luks2_volume_key;
keyslot_context_get_generic_volume_key get_plain_volume_key;
keyslot_context_get_bitlk_volume_key get_bitlk_volume_key;
keyslot_context_get_fvault2_volume_key get_fvault2_volume_key;
keyslot_context_get_generic_volume_key get_bitlk_volume_key;
keyslot_context_get_generic_volume_key get_fvault2_volume_key;
keyslot_context_get_generic_signed_key get_verity_volume_key;
keyslot_context_get_generic_volume_key get_integrity_volume_key;
keyslot_context_get_passphrase get_passphrase;
keyslot_context_get_key_size get_key_size;
keyslot_context_free context_free;
};
void crypt_keyslot_context_destroy_internal(struct crypt_keyslot_context *method);
void crypt_keyslot_context_init_by_key_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_key_init_internal(struct crypt_keyslot_context *kc,
const char *volume_key,
size_t volume_key_size);
void crypt_keyslot_context_init_by_signed_key_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_signed_key_init_internal(struct crypt_keyslot_context *kc,
const char *volume_key,
size_t volume_key_size,
const char *signature,
size_t signature_size);
void crypt_keyslot_context_init_by_passphrase_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_passphrase_init_internal(struct crypt_keyslot_context *kc,
const char *passphrase,
size_t passphrase_size);
void crypt_keyslot_context_init_by_keyfile_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_keyfile_init_internal(struct crypt_keyslot_context *kc,
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset);
void crypt_keyslot_context_init_by_token_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_token_init_internal(struct crypt_keyslot_context *kc,
int token,
const char *type,
const char *pin,
size_t pin_size,
void *usrptr);
void crypt_keyslot_context_init_by_keyring_internal(struct crypt_keyslot_context *kc,
void crypt_keyslot_unlock_by_keyring_internal(struct crypt_keyslot_context *kc,
const char *key_description);
void crypt_keyslot_unlock_by_vk_in_keyring_internal(struct crypt_keyslot_context *kc,
const char *key_description);
const char *keyslot_context_type_string(const struct crypt_keyslot_context *kc);

View File

@@ -1,11 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* libcryptsetup - cryptsetup library
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2025 Milan Broz
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2024 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.
*/
/**
@@ -594,7 +607,7 @@ struct crypt_params_integrity {
uint32_t sector_size; /**< sector size in bytes */
uint32_t buffer_sectors; /**< number of sectors in one buffer */
const char *integrity; /**< integrity algorithm, NULL for LUKS2 */
uint32_t integrity_key_size; /**< integrity key size in bytes, info only */
uint32_t integrity_key_size; /**< integrity key size in bytes, info only, 0 for LUKS2 */
const char *journal_integrity; /**< journal integrity algorithm */
const char *journal_integrity_key; /**< journal integrity key, only for crypt_load */
@@ -703,35 +716,6 @@ int crypt_format_luks2_opal(struct crypt_device *cd,
struct crypt_params_luks2 *params,
struct crypt_params_hw_opal *opal_params);
/**
* Create (format) new integrity-protected device using integrity inline mode (HW sector tags).
* This can be used for @e INTEGRITY and @e LUKS2 with integrity protection
*
* @pre @e cd contains initialized and not formatted device context (device type must @b not be set)
*
* @param cd crypt device handle
* @param type type of device (optional params struct must be of this type)
* @param cipher (e.g. "aes") or @e NULL for @e INTEGRITY
* @param cipher_mode including IV specification (e.g. "xts-plain") or @e NULL for @e INTEGRITY
* @param uuid requested UUID or @e NULL if it should be generated
* @param volume_key pre-generated integrity/volume key (if needed) or @e NULL
* @param volume_key_size size of volume/integrity key in bytes.
* @param params crypt type specific parameters (see @link crypt-type @endlink)
*
* @returns @e 0 on success or negative errno value otherwise.
*
* @note Journal parameters must be set to zero in integrity part of @e params.
* Only tag_size, sector_size, buffer_sectors, integrity options should be set.
*/
int crypt_format_inline(struct crypt_device *cd,
const char *type,
const char *cipher,
const char *cipher_mode,
const char *uuid,
const char *volume_key,
size_t volume_key_size,
void *params);
/**
* Set format compatibility flags.
*
@@ -1233,10 +1217,6 @@ void crypt_keyslot_context_free(struct crypt_keyslot_context *kc);
* @param kc returns crypt keyslot context handle type CRYPT_KC_TYPE_PASSPHRASE
*
* @return zero on success or negative errno otherwise.
*
* @note The original buffer containing passphrase passed in parameters does
* not have to be valid after context initialization. The context
* contains copy of the original before freed with @link crypt_keyslot_context_free @endlink.
*/
int crypt_keyslot_context_init_by_passphrase(struct crypt_device *cd,
const char *passphrase,
@@ -1537,12 +1517,6 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
#define CRYPT_ACTIVATE_RECALCULATE_RESET (UINT32_C(1) << 26)
/** dm-verity: try to use tasklets */
#define CRYPT_ACTIVATE_TASKLETS (UINT32_C(1) << 27)
/** dm-crypt: use high-priority workqueues */
#define CRYPT_ACTIVATE_HIGH_PRIORITY (UINT32_C(1) << 28)
/** dm-verity: also restart/panic on error, use with RESTART_ON_CORRUPTION or PANIC_ON_CORRUPTION */
#define CRYPT_ACTIVATE_ERROR_AS_CORRUPTION (UINT32_C(1) << 29)
/** dm-integrity: inline mode for compatible hardware profile */
#define CRYPT_ACTIVATE_INLINE_MODE (UINT32_C(1) << 30)
/**
* Active device runtime attributes
@@ -1596,8 +1570,6 @@ uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd,
#define CRYPT_REQUIREMENT_ONLINE_REENCRYPT (UINT32_C(1) << 1)
/** Device configured with OPAL support */
#define CRYPT_REQUIREMENT_OPAL (UINT32_C(1) << 2)
/** Device configured with inline HW tags */
#define CRYPT_REQUIREMENT_INLINE_HW_TAGS (UINT32_C(1) << 3)
/** unknown requirement in header (output only) */
#define CRYPT_REQUIREMENT_UNKNOWN (UINT32_C(1) << 31)
@@ -1620,11 +1592,9 @@ typedef enum {
*
* @note Valid only for LUKS2.
*
* @note Not all activation flags can be stored. Only CRYPT_ACTIVATE_ALLOW_DISCARDS,
* CRYPT_ACTIVATE_SAME_CPU_CRYPT, CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS,
* CRYPT_ACTIVATE_NO_JOURNAL, CRYPT_ACTIVATE_NO_READ_WORKQUEUE,
* CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE and CRYPT_ACTIVATE_HIGH_PRIORITY
* can be stored persistently.
* @note Not all activation flags can be stored. Only ALLOW_DISCARD,
* SAME_CPU_CRYPT, SUBMIT_FROM_CRYPT_CPU and NO_JOURNAL can be
* stored persistently.
*
* @note Only requirements flags recognised by current library may be set.
* CRYPT_REQUIREMENT_UNKNOWN is illegal (output only) in set operation.
@@ -2067,19 +2037,6 @@ uint64_t crypt_get_iv_offset(struct crypt_device *cd);
*/
int crypt_get_volume_key_size(struct crypt_device *cd);
/**
* Get size (in bytes) of old volume key for LUKS2 device in reencryption.
*
* @param cd crypt LUKS2 device handle
*
* @return old volume key size when device is in reencryption state
*
* @note For LUKS2, this function can be used only if there is at least
* one keyslot assigned to old data segment. Also with reencryption
* mode 'encrypt' there's no old volume key.
*/
int crypt_get_old_volume_key_size(struct crypt_device *cd);
/**
* Get size (in bytes) of encryption sector for crypt device.
*
@@ -2651,11 +2608,11 @@ int crypt_token_luks2_keyring_get(struct crypt_device *cd,
* (There can be more keyslots assigned to one token id.)
*
* @param cd crypt device handle
* @param token specific token id
* @param token token id
* @param keyslot keyslot to be assigned to token (CRYPT_ANY SLOT
* assigns all active keyslots to token)
*
* @return requested token id to be assigned or negative errno otherwise.
* @return allocated token id or negative errno otherwise.
*/
int crypt_token_assign_keyslot(struct crypt_device *cd,
int token,
@@ -2666,11 +2623,11 @@ int crypt_token_assign_keyslot(struct crypt_device *cd,
* (There can be more keyslots assigned to one token id.)
*
* @param cd crypt device handle
* @param token specific token id
* @param token token id
* @param keyslot keyslot to be unassigned from token (CRYPT_ANY SLOT
* unassigns all active keyslots from token)
*
* @return requested token id to be unassigned or negative errno otherwise.
* @return allocated token id or negative errno otherwise.
*/
int crypt_token_unassign_keyslot(struct crypt_device *cd,
int token,
@@ -2955,12 +2912,6 @@ int crypt_activate_by_token_pin(struct crypt_device *cd,
#define CRYPT_REENCRYPT_RECOVERY (UINT32_C(1) << 3)
/** Reencryption requires metadata protection. (in/out) */
#define CRYPT_REENCRYPT_REPAIR_NEEDED (UINT32_C(1) << 4)
/**
* Calculate new (future) volume key digest directly during
* reencryption initialization. The keyslot context for new
* volume key must be CRYPT_KC_TYPE_KEY or
* CRYPT_KC_TYPE_VK_KEYRING. (in) */
#define CRYPT_REENCRYPT_CREATE_NEW_DIGEST (UINT32_C(1) << 5)
/**
* Reencryption direction
@@ -3057,71 +3008,6 @@ int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
const char *cipher_mode,
const struct crypt_params_reencrypt *params);
/**
*
* Initialize or reload LUKS2 reencryption operation using keyslot contexts.
*
* The function can initialize reencryption on-disk metadata or reload reencryption
* context from on-disk LUSK2 metadata to resume interrupted operation.
*
* If the device is not in reencryption state (@link crypt_reencrypt_status @endlink
* returns @link CRYPT_REENCRYPT_NONE @endlink) the function initializes on-disk
* metadata to include all necessary reencryption segments and new encryption
* parameters (cipher, cipher mode, encryption sector size) according to the
* provided parameters.
*
* If on-disk metadata already describes reencryption operation
* (@link crypt_reencrypt_status @endlink returns @link CRYPT_REENCRYPT_CLEAN @endlink),
* it loads these parameters and internally initializes reencryption context. It also verifies
* if the device is eligible to resume reencryption operation. Some reencryption parameters
* (@link crypt_params_reencrypt @endlink) may be modified depending on the original values in
* the initialization call. When resuming the operation, all parameters may be omitted except
* @e cd, @e name (offline/online),@e kc_old and @e kc_new.
*
* If on-disk metadata describes reencryption operation requiring recovery
* (@link crypt_reencrypt_status @endlink returns @link CRYPT_REENCRYPT_CRASH @endlink),
* it can be recovered by adding @link CRYPT_REENCRYPT_RECOVERY @endlink flag in @link
* crypt_params_reencrypt @endlink parameter.
*
* @param cd crypt device handle
* @param name name of the active device or @e NULL for offline reencryption
* @param kc_old keyslot context providing access to volume key in keyslot id @e keyslot_old.
* @param kc_new keyslot context providing access to volume key in keyslot id @e keyslot_new.
* @param keyslot_old keyslot id containing current volume key for the device or CRYPT_ANY_SLOT
* @param keyslot_new keyslot id containing (unbound) future volume key in encryption or reencryption
* operation. It must be set in the initialization call except when initializing the decrypt
* operation. In reencryption operation it may contain also the current volume key in case the
* volume key change is not requested.
* @param cipher new cipher specification (e.g. "aes") or @e NULL in decryption. Relevant only
* during metadata initialization.
* @param cipher_mode cipher mode and IV (e.g. "xts-plain64") or @e NULL in decryption.
* Relevant only during metadata initialization.
* @param params reencryption parameters @link crypt_params_reencrypt @endlink.
*
* @return reencryption key slot number or negative errno otherwise.
*
* @note Only after successful reencryption initialization you may run the operation with
* @link crypt_reencrypt_run @endlink.
*
* @note During @link CRYPT_REENCRYPT_REENCRYPT @endlink operation it is highly recommended
* to use same keyslot context (same passphrase, token, keyfile, etc) in both @e kc_old
* and @e kc_new parameters for at least one keyslot containing future volume key and one
* keyslot containing current volume key. If the same keyslot context can not be used
* to unlock any current or any future volume key it would be impossible to perform reencryption
* crash recovery during device activation for example after system reboot. Any keyslot
* passphrase may be changed in-before initializing reencryption operation via @link
* crypt_keyslot_change_by_passphrase @endlink.
*/
int crypt_reencrypt_init_by_keyslot_context(struct crypt_device *cd,
const char *name,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new,
int keyslot_old,
int keyslot_new,
const char *cipher,
const char *cipher_mode,
const struct crypt_params_reencrypt *params);
/**
* Legacy data reencryption function.
*
@@ -3146,8 +3032,6 @@ __attribute__((deprecated));
* @param usrptr progress specific data
*
* @return @e 0 on success or negative errno value otherwise.
*
* @note A @e progress callback can interrupt reencryption process by returning non-zero code.
*/
int crypt_reencrypt_run(struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
@@ -3216,15 +3100,6 @@ void *crypt_safe_realloc(void *data, size_t size);
*/
void crypt_safe_memzero(void *data, size_t size);
/**
* Memcpy helper to avoid spilling sensitive data through additional registers
*
* @param dst pointer to memory to be written
* @param src pointer to memory to be copied
* @param size size of memory in bytes
*/
void *crypt_safe_memcpy(void *dst, const void *src, size_t size);
/** @} */
/**

View File

@@ -180,18 +180,3 @@ CRYPTSETUP_2.7 {
crypt_set_keyring_to_link;
crypt_wipe_hw_opal;
} CRYPTSETUP_2.6;
CRYPTSETUP_2.8 {
global:
crypt_safe_memcpy;
crypt_keyslot_context_init_by_passphrase;
crypt_keyslot_context_init_by_keyfile;
crypt_keyslot_context_init_by_token;
crypt_keyslot_context_init_by_volume_key;
crypt_keyslot_context_init_by_signed_key;
crypt_keyslot_context_init_by_keyring;
crypt_keyslot_context_init_by_vk_in_keyring;
crypt_reencrypt_init_by_keyslot_context;
crypt_get_old_volume_key_size;
crypt_format_inline;
} CRYPTSETUP_2.7;

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Definitions of common constant and generic macros of libcryptsetup
*
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2025 Milan Broz
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2024 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _LIBCRYPTSETUP_MACROS_H
@@ -49,17 +62,9 @@
#define DEFAULT_MEM_ALIGNMENT 4096
#define DM_UUID_LEN 129
#define DM_NAME_LEN 128
#define DM_BY_ID_PREFIX "dm-uuid-"
#define DM_BY_ID_PREFIX_LEN 8
#define DM_UUID_PREFIX "CRYPT-"
#define DM_UUID_PREFIX_LEN 6
#define OPAL_PSID_LEN 32
/* LUKS AF stripes, never set to any other value than 4000 */
#ifndef LUKS_STRIPES
# define LUKS_STRIPES 4000
#endif
#endif /* _LIBCRYPTSETUP_MACROS_H */

View File

@@ -1,8 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Helpers for defining versioned symbols
*
* Copyright (C) 2021-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2021-2024 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _LIBCRYPTSETUP_SYMVER_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2025 Milan Broz
* Copyright (C) 2011-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
@@ -69,7 +82,6 @@ static int hash_keys(struct crypt_device *cd,
char tweak, *key_ptr;
unsigned int i;
int r = 0;
void *key = NULL;
hash_name = hash_override ?: get_hash(key_len_output);
tweak = get_tweak(keys_count);
@@ -80,30 +92,24 @@ static int hash_keys(struct crypt_device *cd,
return -EINVAL;
}
key = crypt_safe_alloc((size_t)key_len_output * keys_count);
if (!key)
*vk = crypt_alloc_volume_key((size_t)key_len_output * keys_count, NULL);
if (!*vk)
return -ENOMEM;
for (i = 0; i < keys_count; i++) {
key_ptr = &((char *)key)[i * key_len_output];
key_ptr = &(*vk)->key[i * key_len_output];
r = hash_key(input_keys[i], key_len_input, key_ptr,
key_len_output, hash_name);
if (r < 0)
goto err;
break;
key_ptr[0] ^= tweak;
}
*vk = crypt_alloc_volume_key_by_safe_alloc(&key);
if (!*vk) {
r = -ENOMEM;
goto err;
if (r < 0 && *vk) {
crypt_free_volume_key(*vk);
*vk = NULL;
}
return 0;
err:
crypt_safe_free(key);
*vk = NULL;
return r;
}
@@ -152,7 +158,7 @@ int LOOPAES_parse_keyfile(struct crypt_device *cd,
key_lengths[0] = 0;
while (offset < buffer_len && key_index < LOOPAES_KEYS_MAX) {
keys[key_index] = &buffer[offset];
key_lengths[key_index] = 0;
key_lengths[key_index] = 0;;
while (offset < buffer_len && buffer[offset]) {
offset++;
key_lengths[key_index]++;
@@ -198,7 +204,7 @@ int LOOPAES_activate(struct crypt_device *cd,
uint32_t flags)
{
int r;
uint64_t req_flags, dmc_flags;
uint32_t req_flags, dmc_flags;
char *cipher = NULL;
struct crypt_dm_active_device dmd = {
.flags = flags,
@@ -220,8 +226,9 @@ int LOOPAES_activate(struct crypt_device *cd,
return -ENOMEM;
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
vk, cipher, crypt_get_iv_offset(cd), crypt_get_data_offset(cd),
NULL, 0, 0, crypt_get_sector_size(cd));
vk, cipher, crypt_get_iv_offset(cd),
crypt_get_data_offset(cd), crypt_get_integrity(cd),
crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd));
if (r) {
free(cipher);

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* loop-AES compatible volume handling
*
* Copyright (C) 2011-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2025 Milan Broz
* Copyright (C) 2011-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2024 Milan Broz
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _LOOPAES_H

View File

@@ -1,12 +1,25 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AFsplitter - Anti forensic information splitter
*
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefore supporting secure data destruction.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* 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 Library 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 <stddef.h>

View File

@@ -1,11 +1,26 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* AFsplitter - Anti forensic information splitter
*
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
*
* AFsplitter diffuses information over a large stripe of data,
* therefore supporting secure data destruction.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* 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 Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef INCLUDED_CRYPTSETUP_LUKS_AF_H
#define INCLUDED_CRYPTSETUP_LUKS_AF_H

View File

@@ -1,10 +1,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2025 Milan Broz
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2024 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 <stdio.h>
@@ -88,7 +101,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size,
crypt_metadata_device(ctx), vk, cipher_spec, 0, sector,
NULL, 0, 0, SECTOR_SIZE);
NULL, 0, SECTOR_SIZE);
if (r)
goto out;
@@ -96,7 +109,7 @@ static int LUKS_endec_template(char *src, size_t srcLength,
if (r < 0) {
if (r != -EACCES && r != -ENOTSUP)
_error_hint(ctx, device_path(crypt_metadata_device(ctx)),
cipher, cipher_mode, crypt_volume_key_length(vk) * 8);
cipher, cipher_mode, vk->keylength * 8);
r = -EIO;
goto out;
}
@@ -140,8 +153,7 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
return -EINVAL;
/* Encrypt buffer */
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk), false);
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
if (r)
log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
@@ -154,7 +166,7 @@ int LUKS_encrypt_to_storage(char *src, size_t srcLength,
if (r) {
_error_hint(ctx, device_path(device), cipher, cipher_mode,
crypt_volume_key_length(vk) * 8);
vk->keylength * 8);
return r;
}
@@ -206,8 +218,7 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
if (MISALIGNED_512(dstLength))
return -EINVAL;
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk), false);
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
if (r)
log_dbg(ctx, "Userspace crypto wrapper cannot use %s-%s (%d).",
@@ -220,7 +231,7 @@ int LUKS_decrypt_from_storage(char *dst, size_t dstLength,
if (r) {
_error_hint(ctx, device_path(device), cipher, cipher_mode,
crypt_volume_key_length(vk) * 8);
vk->keylength * 8);
return r;
}

View File

@@ -1,10 +1,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2025 Milan Broz
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2013-2024 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 <sys/types.h>
@@ -378,7 +391,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
{
struct luks_phdr temp_phdr;
const unsigned char *sector = (const unsigned char*)phdr;
struct volume_key *fake_vk;
struct volume_key *vk;
int i, bad, r, need_write = 0;
if (phdr->keyBytes != 16 && phdr->keyBytes != 32 && phdr->keyBytes != 64) {
@@ -424,8 +437,8 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
if (r < 0)
return -EINVAL;
fake_vk = crypt_generate_volume_key(ctx, phdr->keyBytes, KEY_QUALITY_EMPTY);
if (!fake_vk)
vk = crypt_alloc_volume_key(phdr->keyBytes, NULL);
if (!vk)
return -ENOMEM;
log_verbose(ctx, _("Repairing keyslots."));
@@ -433,7 +446,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
log_dbg(ctx, "Generating second header with the same parameters for check.");
/* cipherName, cipherMode, hashSpec, uuid are already null terminated */
/* payloadOffset - cannot check */
r = LUKS_generate_phdr(&temp_phdr, fake_vk, phdr->cipherName, phdr->cipherMode,
r = LUKS_generate_phdr(&temp_phdr, vk, phdr->cipherName, phdr->cipherMode,
phdr->hashSpec, phdr->uuid,
phdr->payloadOffset * SECTOR_SIZE, 0, 0, ctx);
if (r < 0)
@@ -492,7 +505,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
out:
if (r)
log_err(ctx, _("Repair failed."));
crypt_free_volume_key(fake_vk);
crypt_free_volume_key(vk);
crypt_safe_memzero(&temp_phdr, sizeof(temp_phdr));
return r;
}
@@ -710,12 +723,14 @@ int LUKS_check_cipher(struct crypt_device *ctx, size_t keylength, const char *ci
log_dbg(ctx, "Checking if cipher %s-%s is usable.", cipher, cipher_mode);
/* No need to get KEY quality random but it must avoid known weak keys. */
empty_key = crypt_generate_volume_key(ctx, keylength, KEY_QUALITY_NORMAL);
empty_key = crypt_alloc_volume_key(keylength, NULL);
if (!empty_key)
return -ENOMEM;
r = LUKS_decrypt_from_storage(buf, sizeof(buf), cipher, cipher_mode, empty_key, 0, ctx);
/* No need to get KEY quality random but it must avoid known weak keys. */
r = crypt_random_get(ctx, empty_key->key, empty_key->keylength, CRYPT_RND_NORMAL);
if (!r)
r = LUKS_decrypt_from_storage(buf, sizeof(buf), cipher, cipher_mode, empty_key, 0, ctx);
crypt_free_volume_key(empty_key);
crypt_safe_memzero(buf, sizeof(buf));
@@ -746,7 +761,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
memset(header, 0, sizeof(struct luks_phdr));
keyslot_sectors = AF_split_sectors(crypt_volume_key_length(vk), LUKS_STRIPES);
keyslot_sectors = AF_split_sectors(vk->keylength, LUKS_STRIPES);
header_sectors = LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE;
for (i = 0; i < LUKS_NUMKEYS; i++) {
@@ -793,7 +808,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
strncpy(header->hashSpec,hashSpec,LUKS_HASHSPEC_L-1);
_to_lower(header->hashSpec, LUKS_HASHSPEC_L);
header->keyBytes = crypt_volume_key_length(vk);
header->keyBytes=vk->keylength;
log_dbg(ctx, "Generating LUKS header version %d using hash %s, %s, %s, MK %d bytes",
header->version, header->hashSpec ,header->cipherName, header->cipherMode,
@@ -807,7 +822,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
/* Compute volume key digest */
pbkdf = crypt_get_pbkdf(ctx);
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, crypt_volume_key_length(vk));
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, vk->keylength);
if (r < 0)
return r;
assert(pbkdf->iterations);
@@ -822,9 +837,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
header->mkDigestIterations = AT_LEAST((uint32_t)PBKDF2_temp, LUKS_MKD_ITERATIONS_MIN);
assert(header->mkDigestIterations);
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, header->hashSpec,
crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk),
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, header->hashSpec, vk->key,vk->keylength,
header->mkDigestSalt, LUKS_SALTSIZE,
header->mkDigest,LUKS_DIGESTSIZE,
header->mkDigestIterations, 0, 0);
@@ -866,9 +879,8 @@ int LUKS_set_key(unsigned int keyIndex,
struct luks_phdr *hdr, struct volume_key *vk,
struct crypt_device *ctx)
{
struct volume_key *derived_vk = NULL;
struct volume_key *derived_key;
char *AfKey = NULL;
void *derived_key = NULL;
size_t AFEKSize;
struct crypt_pbkdf_type *pbkdf;
int r;
@@ -887,7 +899,7 @@ int LUKS_set_key(unsigned int keyIndex,
log_dbg(ctx, "Calculating data for key slot %d", keyIndex);
pbkdf = crypt_get_pbkdf(ctx);
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, crypt_volume_key_length(vk));
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, vk->keylength);
if (r < 0)
return r;
assert(pbkdf->iterations);
@@ -900,11 +912,9 @@ int LUKS_set_key(unsigned int keyIndex,
log_dbg(ctx, "Key slot %d use %" PRIu32 " password iterations.", keyIndex,
hdr->keyblock[keyIndex].passwordIterations);
derived_key = crypt_safe_alloc(hdr->keyBytes);
if (!derived_key) {
r = -ENOMEM;
goto out;
}
derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
if (!derived_key)
return -ENOMEM;
r = crypt_random_get(ctx, hdr->keyblock[keyIndex].passwordSalt,
LUKS_SALTSIZE, CRYPT_RND_SALT);
@@ -913,7 +923,7 @@ int LUKS_set_key(unsigned int keyIndex,
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, password, passwordLen,
hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
derived_key, hdr->keyBytes,
derived_key->key, hdr->keyBytes,
hdr->keyblock[keyIndex].passwordIterations, 0, 0);
if (r < 0) {
if ((crypt_backend_flags() & CRYPT_BACKEND_PBKDF2_INT) &&
@@ -922,17 +932,11 @@ int LUKS_set_key(unsigned int keyIndex,
goto out;
}
derived_vk = crypt_alloc_volume_key_by_safe_alloc(&derived_key);
if (!derived_vk) {
r = -ENOMEM;
goto out;
}
/*
* AF splitting, the volume key stored in vk->key is split to AfKey
*/
assert(crypt_volume_key_length(vk) == hdr->keyBytes);
AFEKSize = AF_split_sectors(crypt_volume_key_length(vk), hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
assert(vk->keylength == hdr->keyBytes);
AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
AfKey = crypt_safe_alloc(AFEKSize);
if (!AfKey) {
r = -ENOMEM;
@@ -941,8 +945,7 @@ int LUKS_set_key(unsigned int keyIndex,
log_dbg(ctx, "Using hash %s for AF in key slot %d, %d stripes",
hdr->hashSpec, keyIndex, hdr->keyblock[keyIndex].stripes);
r = AF_split(ctx, crypt_volume_key_get_key(vk), AfKey, crypt_volume_key_length(vk),
hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
r = AF_split(ctx, vk->key, AfKey, vk->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
if (r < 0)
goto out;
@@ -952,7 +955,7 @@ int LUKS_set_key(unsigned int keyIndex,
r = LUKS_encrypt_to_storage(AfKey,
AFEKSize,
hdr->cipherName, hdr->cipherMode,
derived_vk,
derived_key,
hdr->keyblock[keyIndex].keyMaterialOffset,
ctx);
if (r < 0)
@@ -970,8 +973,7 @@ int LUKS_set_key(unsigned int keyIndex,
r = 0;
out:
crypt_safe_free(AfKey);
crypt_safe_free(derived_key);
crypt_free_volume_key(derived_vk);
crypt_free_volume_key(derived_key);
return r;
}
@@ -981,8 +983,7 @@ int LUKS_verify_volume_key(const struct luks_phdr *hdr,
{
char checkHashBuf[LUKS_DIGESTSIZE];
if (crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk),
if (crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, vk->key, vk->keylength,
hdr->mkDigestSalt, LUKS_SALTSIZE,
checkHashBuf, LUKS_DIGESTSIZE,
hdr->mkDigestIterations, 0, 0) < 0)
@@ -999,13 +1000,12 @@ static int LUKS_open_key(unsigned int keyIndex,
const char *password,
size_t passwordLen,
struct luks_phdr *hdr,
struct volume_key **r_vk,
struct volume_key **vk,
struct crypt_device *ctx)
{
crypt_keyslot_info ki = LUKS_keyslot_info(hdr, keyIndex);
struct volume_key *derived_vk = NULL, *vk = NULL;
struct volume_key *derived_key;
char *AfKey = NULL;
void *key = NULL, *derived_key = NULL;
size_t AFEKSize;
int r;
@@ -1015,12 +1015,12 @@ static int LUKS_open_key(unsigned int keyIndex,
if (ki < CRYPT_SLOT_ACTIVE)
return -ENOENT;
derived_key = crypt_safe_alloc(hdr->keyBytes);
derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
if (!derived_key)
return -ENOMEM;
key = crypt_safe_alloc(hdr->keyBytes);
if (!key) {
*vk = crypt_alloc_volume_key(hdr->keyBytes, NULL);
if (!*vk) {
r = -ENOMEM;
goto out;
}
@@ -1034,57 +1034,39 @@ static int LUKS_open_key(unsigned int keyIndex,
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, password, passwordLen,
hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
derived_key, hdr->keyBytes,
derived_key->key, hdr->keyBytes,
hdr->keyblock[keyIndex].passwordIterations, 0, 0);
if (r < 0) {
log_err(ctx, _("Cannot open keyslot (using hash %s)."), hdr->hashSpec);
goto out;
}
derived_vk = crypt_alloc_volume_key_by_safe_alloc(&derived_key);
if (!derived_vk) {
r = -ENOMEM;
goto out;
}
log_dbg(ctx, "Reading key slot %d area.", keyIndex);
r = LUKS_decrypt_from_storage(AfKey,
AFEKSize,
hdr->cipherName, hdr->cipherMode,
derived_vk,
derived_key,
hdr->keyblock[keyIndex].keyMaterialOffset,
ctx);
if (r < 0)
goto out;
r = AF_merge(AfKey, key, hdr->keyBytes, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
r = AF_merge(AfKey, (*vk)->key, (*vk)->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
if (r < 0)
goto out;
vk = crypt_alloc_volume_key_by_safe_alloc(&key);
if (!vk) {
r = -ENOMEM;
goto out;
}
r = LUKS_verify_volume_key(hdr, vk);
if (r < 0)
goto out;
r = LUKS_verify_volume_key(hdr, *vk);
/* Allow only empty passphrase with null cipher */
if (crypt_is_cipher_null(hdr->cipherName) && passwordLen)
if (!r && crypt_is_cipher_null(hdr->cipherName) && passwordLen)
r = -EPERM;
else
*r_vk = vk;
out:
if (r < 0) {
crypt_free_volume_key(vk);
*r_vk = NULL;
crypt_free_volume_key(*vk);
*vk = NULL;
}
crypt_safe_free(AfKey);
crypt_safe_free(key);
crypt_safe_free(derived_key);
crypt_free_volume_key(derived_vk);
crypt_free_volume_key(derived_key);
return r;
}
@@ -1235,7 +1217,8 @@ int LUKS1_activate(struct crypt_device *cd,
r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
vk, crypt_get_cipher_spec(cd), crypt_get_iv_offset(cd),
crypt_get_data_offset(cd), NULL, 0, 0, crypt_get_sector_size(cd));
crypt_get_data_offset(cd), crypt_get_integrity(cd),
crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd));
if (!r)
r = create_or_reload_device(cd, name, CRYPT_LUKS1, &dmd);

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup
*
* Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef INCLUDED_CRYPTSETUP_LUKS_LUKS_H

View File

@@ -1,10 +1,22 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* OPAL utilities
*
* Copyright (C) 2022-2023 Luca Boccassi <bluca@debian.org>
* Copyright (C) 2023-2025 Ondrej Kozina <okozina@redhat.com>
* Copyright (C) 2024-2025 Milan Broz
* 2023 Ondrej Kozina <okozina@redhat.com>
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
@@ -17,7 +29,7 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#if HAVE_SYS_SYSMACROS_H
#ifdef HAVE_SYS_SYSMACROS_H
# include <sys/sysmacros.h> /* for major, minor */
#endif
@@ -29,39 +41,39 @@
#if HAVE_HW_OPAL
#include <linux/sed-opal.h>
#include <linux/fs.h>
/* Error codes are defined in the specification:
* TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
* Section 5.1.5: Method Status Codes
* Names and values from table 166 */
typedef enum OpalStatus {
OPAL_STATUS_SUCCESS = 0x00,
OPAL_STATUS_NOT_AUTHORIZED = 0x01,
OPAL_STATUS_OBSOLETE0 = 0x02, /* Undefined but possible return values are called 'obsolete' */
OPAL_STATUS_SP_BUSY = 0x03,
OPAL_STATUS_SP_FAILED = 0x04,
OPAL_STATUS_SP_DISABLED = 0x05,
OPAL_STATUS_SP_FROZEN = 0x06,
OPAL_STATUS_NO_SESSIONS_AVAILABLE = 0x07,
OPAL_STATUS_UNIQUENESS_CONFLICT = 0x08,
OPAL_STATUS_INSUFFICIENT_SPACE = 0x09,
OPAL_STATUS_INSUFFICIENT_ROWS = 0x0a,
OPAL_STATUS_OBSOLETE1 = 0x0b, /* Undefined but possible return values are called 'obsolete' */
OPAL_STATUS_INVALID_PARAMETER = 0x0c,
OPAL_STATUS_OBSOLETE2 = 0x0d,
OPAL_STATUS_OBSOLETE3 = 0x0e,
OPAL_STATUS_TPER_MALFUNCTION = 0x0f,
OPAL_STATUS_TRANSACTION_FAILURE = 0x10,
OPAL_STATUS_RESPONSE_OVERFLOW = 0x11,
OPAL_STATUS_AUTHORITY_LOCKED_OUT = 0x12,
_OPAL_STATUS_MAX = 0x13,
OPAL_STATUS_SUCCESS,
OPAL_STATUS_NOT_AUTHORIZED,
OPAL_STATUS_OBSOLETE0, /* Undefined but possible return values are called 'obsolete' */
OPAL_STATUS_SP_BUSY,
OPAL_STATUS_SP_FAILED,
OPAL_STATUS_SP_DISABLED,
OPAL_STATUS_SP_FROZEN,
OPAL_STATUS_NO_SESSIONS_AVAILABLE,
OPAL_STATUS_UNIQUENESS_CONFLICT,
OPAL_STATUS_INSUFFICIENT_SPACE,
OPAL_STATUS_INSUFFICIENT_ROWS,
OPAL_STATUS_INVALID_PARAMETER,
OPAL_STATUS_OBSOLETE1,
OPAL_STATUS_OBSOLETE2,
OPAL_STATUS_TPER_MALFUNCTION,
OPAL_STATUS_TRANSACTION_FAILURE,
OPAL_STATUS_RESPONSE_OVERFLOW,
OPAL_STATUS_AUTHORITY_LOCKED_OUT,
OPAL_STATUS_FAIL = 0x3F, /* As defined by specification */
_OPAL_STATUS_MAX,
_OPAL_STATUS_INVALID = -EINVAL,
} OpalStatus;
static const char* const opal_status_table[_OPAL_STATUS_MAX] = {
[OPAL_STATUS_SUCCESS] = "success",
[OPAL_STATUS_NOT_AUTHORIZED] = "not authorized",
[OPAL_STATUS_OBSOLETE0] = "obsolete (0x02)",
[OPAL_STATUS_OBSOLETE0] = "obsolete",
[OPAL_STATUS_SP_BUSY] = "SP busy",
[OPAL_STATUS_SP_FAILED] = "SP failed",
[OPAL_STATUS_SP_DISABLED] = "SP disabled",
@@ -70,14 +82,14 @@ static const char* const opal_status_table[_OPAL_STATUS_MAX] = {
[OPAL_STATUS_UNIQUENESS_CONFLICT] = "uniqueness conflict",
[OPAL_STATUS_INSUFFICIENT_SPACE] = "insufficient space",
[OPAL_STATUS_INSUFFICIENT_ROWS] = "insufficient rows",
[OPAL_STATUS_OBSOLETE1] = "obsolete (0x0b)",
[OPAL_STATUS_INVALID_PARAMETER] = "invalid parameter",
[OPAL_STATUS_OBSOLETE2] = "obsolete (0x0d)",
[OPAL_STATUS_OBSOLETE3] = "obsolete (0x0e)",
[OPAL_STATUS_OBSOLETE1] = "obsolete",
[OPAL_STATUS_OBSOLETE2] = "obsolete",
[OPAL_STATUS_TPER_MALFUNCTION] = "TPer malfunction",
[OPAL_STATUS_TRANSACTION_FAILURE] = "transaction failure",
[OPAL_STATUS_RESPONSE_OVERFLOW] = "response overflow",
[OPAL_STATUS_AUTHORITY_LOCKED_OUT] = "authority locked out",
[OPAL_STATUS_FAIL] = "unknown failure",
};
static const char *opal_status_to_string(int t)
@@ -85,10 +97,6 @@ static const char *opal_status_to_string(int t)
if (t < 0)
return strerror(-t);
/* Fail, as defined by specification */
if (t == 0x3f)
return "unknown failure";
if (t >= _OPAL_STATUS_MAX)
return "unknown error";
@@ -282,7 +290,6 @@ static int opal_range_check_attributes_fd(struct crypt_device *cd,
{
int r;
struct opal_lr_status *lrs;
int device_block_bytes;
uint32_t opal_block_bytes = 0;
uint64_t offset, length;
bool read_locked, write_locked;
@@ -290,17 +297,12 @@ static int opal_range_check_attributes_fd(struct crypt_device *cd,
assert(fd >= 0);
assert(cd);
assert(vk);
assert(check_offset_sectors);
assert(check_length_sectors);
r = opal_geometry_fd(cd, fd, NULL, &opal_block_bytes, NULL, NULL);
if (r != OPAL_STATUS_SUCCESS)
return -EINVAL;
/* Keep this as warning only */
if (ioctl(fd, BLKSSZGET, &device_block_bytes) < 0 ||
(uint32_t)device_block_bytes != opal_block_bytes)
log_err(cd, _("Bogus OPAL logical block size differs from device block size."));
if (check_offset_sectors || check_length_sectors) {
r = opal_geometry_fd(cd, fd, NULL, &opal_block_bytes, NULL, NULL);
if (r != OPAL_STATUS_SUCCESS)
return -EINVAL;
}
lrs = crypt_safe_alloc(sizeof(*lrs));
if (!lrs)
@@ -310,13 +312,12 @@ static int opal_range_check_attributes_fd(struct crypt_device *cd,
.session = {
.who = segment_number + 1,
.opal_key = {
.key_len = crypt_volume_key_length(vk),
.key_len = vk->keylength,
.lr = segment_number
}
}
};
crypt_safe_memcpy(lrs->session.opal_key.key, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk));
memcpy(lrs->session.opal_key.key, vk->key, vk->keylength);
r = opal_ioctl(cd, fd, IOC_OPAL_GET_LR_STATUS, lrs);
if (r != OPAL_STATUS_SUCCESS) {
@@ -328,18 +329,22 @@ static int opal_range_check_attributes_fd(struct crypt_device *cd,
r = 0;
offset = lrs->range_start * opal_block_bytes / SECTOR_SIZE;
if (offset != *check_offset_sectors) {
log_err(cd, _("OPAL range %d offset %" PRIu64 " does not match expected values %" PRIu64 "."),
segment_number, offset, *check_offset_sectors);
r = -EINVAL;
if (check_offset_sectors) {
offset = lrs->range_start * opal_block_bytes / SECTOR_SIZE;
if (offset != *check_offset_sectors) {
log_err(cd, _("OPAL range %d offset %" PRIu64 " does not match expected values %" PRIu64 "."),
segment_number, offset, *check_offset_sectors);
r = -EINVAL;
}
}
length = lrs->range_length * opal_block_bytes / SECTOR_SIZE;
if (length != *check_length_sectors) {
log_err(cd, _("OPAL range %d length %" PRIu64" does not match device length %" PRIu64 "."),
segment_number, length, *check_length_sectors);
r = -EINVAL;
if (check_length_sectors) {
length = lrs->range_length * opal_block_bytes / SECTOR_SIZE;
if (length != *check_length_sectors) {
log_err(cd, _("OPAL range %d length %" PRIu64" does not match device length %" PRIu64 "."),
segment_number, length, *check_length_sectors);
r = -EINVAL;
}
}
if (!lrs->RLE || !lrs->WLE) {
@@ -400,9 +405,8 @@ static int opal_enabled(struct crypt_device *cd, struct device *dev)
int opal_setup_ranges(struct crypt_device *cd,
struct device *dev,
const struct volume_key *vk,
uint64_t range_start_blocks,
uint64_t range_length_blocks,
uint32_t opal_block_bytes,
uint64_t range_start,
uint64_t range_length,
uint32_t segment_number,
const void *admin_key,
size_t admin_key_len)
@@ -418,16 +422,11 @@ int opal_setup_ranges(struct crypt_device *cd,
assert(dev);
assert(vk);
assert(admin_key);
assert(crypt_volume_key_length(vk) <= OPAL_KEY_MAX);
assert(opal_block_bytes >= SECTOR_SIZE);
assert(vk->keylength <= OPAL_KEY_MAX);
if (admin_key_len > OPAL_KEY_MAX)
return -EINVAL;
if (((UINT64_MAX / opal_block_bytes) < range_start_blocks) ||
((UINT64_MAX / opal_block_bytes) < range_length_blocks))
return -EINVAL;
fd = device_open(cd, dev, O_RDONLY);
if (fd < 0)
return -EIO;
@@ -453,7 +452,7 @@ int opal_setup_ranges(struct crypt_device *cd,
*/
.lr = { 1, 2, 3, 4, 5, 6, 7, 8 },
};
crypt_safe_memcpy(activate->key.key, admin_key, admin_key_len);
memcpy(activate->key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_TAKE_OWNERSHIP, &activate->key);
if (r < 0) {
@@ -495,14 +494,19 @@ int opal_setup_ranges(struct crypt_device *cd,
.key_len = admin_key_len,
},
};
crypt_safe_memcpy(user_session->opal_key.key, admin_key, admin_key_len);
memcpy(user_session->opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session);
r = opal_ioctl(cd, fd, IOC_OPAL_ERASE_LR, user_session);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s",
log_dbg(cd, "Failed to reset (erase) OPAL locking range %u on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
}
}
@@ -519,7 +523,7 @@ int opal_setup_ranges(struct crypt_device *cd,
.key_len = admin_key_len,
},
};
crypt_safe_memcpy(user_session->opal_key.key, admin_key, admin_key_len);
memcpy(user_session->opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_USR, user_session);
if (r != OPAL_STATUS_SUCCESS) {
@@ -544,7 +548,7 @@ int opal_setup_ranges(struct crypt_device *cd,
},
.l_state = OPAL_RO,
};
crypt_safe_memcpy(user_add_to_lr->session.opal_key.key, admin_key, admin_key_len);
memcpy(user_add_to_lr->session.opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr);
if (r != OPAL_STATUS_SUCCESS) {
@@ -578,14 +582,13 @@ int opal_setup_ranges(struct crypt_device *cd,
.new_user_pw = {
.who = segment_number + 1,
.opal_key = {
.key_len = crypt_volume_key_length(vk),
.key_len = vk->keylength,
.lr = segment_number,
},
},
};
crypt_safe_memcpy(new_pw->new_user_pw.opal_key.key, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk));
crypt_safe_memcpy(new_pw->session.opal_key.key, admin_key, admin_key_len);
memcpy(new_pw->new_user_pw.opal_key.key, vk->key, vk->keylength);
memcpy(new_pw->session.opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_SET_PW, new_pw);
if (r != OPAL_STATUS_SUCCESS) {
@@ -601,8 +604,8 @@ int opal_setup_ranges(struct crypt_device *cd,
goto out;
}
*setup = (struct opal_user_lr_setup) {
.range_start = range_start_blocks,
.range_length = range_length_blocks,
.range_start = range_start,
.range_length = range_length,
/* Some drives do not enable Locking Ranges on setup. This have some
* interesting consequences: Lock command called later below will pass,
* but locking range will _not_ be locked at all.
@@ -617,7 +620,7 @@ int opal_setup_ranges(struct crypt_device *cd,
},
},
};
crypt_safe_memcpy(setup->session.opal_key.key, admin_key, admin_key_len);
memcpy(setup->session.opal_key.key, admin_key, admin_key_len);
r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup);
if (r != OPAL_STATUS_SUCCESS) {
@@ -639,13 +642,12 @@ int opal_setup_ranges(struct crypt_device *cd,
.session = {
.who = segment_number + 1,
.opal_key = {
.key_len = crypt_volume_key_length(vk),
.key_len = vk->keylength,
.lr = segment_number,
},
}
};
crypt_safe_memcpy(lock->session.opal_key.key, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk));
memcpy(lock->session.opal_key.key, vk->key, vk->keylength);
r = opal_ioctl(cd, fd, IOC_OPAL_LOCK_UNLOCK, lock);
if (r != OPAL_STATUS_SUCCESS) {
@@ -656,10 +658,9 @@ int opal_setup_ranges(struct crypt_device *cd,
}
/* Double check the locking range is locked and the ranges are set up as configured */
r = opal_range_check_attributes_fd(cd, fd, segment_number, vk,
&(uint64_t) {range_start_blocks * opal_block_bytes / SECTOR_SIZE},
&(uint64_t) {range_length_blocks * opal_block_bytes / SECTOR_SIZE},
&(bool) {true}, &(bool){true}, NULL, NULL);
r = opal_range_check_attributes_fd(cd, fd, segment_number, vk, &range_start,
&range_length, &(bool) {true}, &(bool){true},
NULL, NULL);
out:
crypt_safe_free(activate);
crypt_safe_free(user_session);
@@ -698,11 +699,10 @@ static int opal_lock_unlock(struct crypt_device *cd,
return -EIO;
if (!lock) {
assert(crypt_volume_key_length(vk) <= OPAL_KEY_MAX);
assert(vk->keylength <= OPAL_KEY_MAX);
unlock.session.opal_key.key_len = crypt_volume_key_length(vk);
crypt_safe_memcpy(unlock.session.opal_key.key, crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk));
unlock.session.opal_key.key_len = vk->keylength;
memcpy(unlock.session.opal_key.key, vk->key, vk->keylength);
}
r = opal_ioctl(cd, fd, IOC_OPAL_LOCK_UNLOCK, &unlock);
@@ -794,7 +794,7 @@ int opal_factory_reset(struct crypt_device *cd,
if (fd < 0)
return -EIO;
crypt_safe_memcpy(reset.key, password, password_len);
memcpy(reset.key, password, password_len);
r = opal_ioctl(cd, fd, IOC_OPAL_PSID_REVERT_TPR, &reset);
if (r < 0) {
@@ -851,7 +851,7 @@ int opal_reset_segment(struct crypt_device *cd,
.key_len = password_len,
},
};
crypt_safe_memcpy(user_session->opal_key.key, password, password_len);
memcpy(user_session->opal_key.key, password, password_len);
fd = device_open(cd, dev, O_RDONLY);
if (fd < 0) {
@@ -859,35 +859,42 @@ int opal_reset_segment(struct crypt_device *cd,
goto out;
}
r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session);
r = opal_ioctl(cd, fd, IOC_OPAL_ERASE_LR, user_session);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s",
log_dbg(cd, "Failed to reset (erase) OPAL locking range %u on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s",
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
/* Disable the locking range */
setup = crypt_safe_alloc(sizeof(struct opal_user_lr_setup));
if (!setup) {
r = -ENOMEM;
goto out;
}
*setup = (struct opal_user_lr_setup) {
.range_start = 0,
.range_length = 0,
.session = {
.who = OPAL_ADMIN1,
.opal_key = user_session->opal_key,
},
};
/* Unlike IOC_OPAL_ERASE_LR, IOC_OPAL_SECURE_ERASE_LR does not disable the locking range,
* we have to do that by hand.
*/
setup = crypt_safe_alloc(sizeof(struct opal_user_lr_setup));
if (!setup) {
r = -ENOMEM;
goto out;
}
*setup = (struct opal_user_lr_setup) {
.range_start = 0,
.range_length = 0,
.session = {
.who = OPAL_ADMIN1,
.opal_key = user_session->opal_key,
},
};
r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to disable locking range on OPAL device '%s': %s",
crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup);
if (r != OPAL_STATUS_SUCCESS) {
log_dbg(cd, "Failed to disable locking range on OPAL device '%s': %s",
crypt_get_device_name(cd), opal_status_to_string(r));
r = -EINVAL;
goto out;
}
}
out:
crypt_safe_free(user_session);
@@ -1004,9 +1011,8 @@ void opal_exclusive_unlock(struct crypt_device *cd, struct crypt_lock_handle *op
int opal_setup_ranges(struct crypt_device *cd,
struct device *dev,
const struct volume_key *vk,
uint64_t range_start_blocks,
uint64_t range_length_blocks,
uint32_t opal_block_bytes,
uint64_t range_start,
uint64_t range_length,
uint32_t segment_number,
const void *admin_key,
size_t admin_key_len)

View File

@@ -1,10 +1,22 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* OPAL utilities
*
* Copyright (C) 2022-2023 Luca Boccassi <bluca@debian.org>
* Copyright (C) 2023-2025 Ondrej Kozina <okozina@redhat.com>
* Copyright (C) 2024-2025 Milan Broz
* 2023 Ondrej Kozina <okozina@redhat.com>
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _UTILS_OPAL
@@ -17,9 +29,8 @@ struct crypt_lock_handle;
int opal_setup_ranges(struct crypt_device *cd,
struct device *dev,
const struct volume_key *vk,
uint64_t range_start_blocks,
uint64_t range_length_blocks,
uint32_t opal_block_bytes,
uint64_t range_start,
uint64_t range_length,
uint32_t segment_number,
const void *admin_key,
size_t admin_key_len);

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _CRYPTSETUP_LUKS2_ONDISK_H
@@ -37,8 +50,6 @@
#define LUKS2_DIGEST_MAX 8
#define LUKS2_MIN_INTEGRITY_KEY_BYTES 16
#define CRYPT_ANY_SEGMENT -1
#define CRYPT_DEFAULT_SEGMENT -2
#define CRYPT_ONE_SEGMENT -3
@@ -111,7 +122,6 @@ struct luks2_hdr {
char uuid[LUKS2_UUID_L];
void *jobj;
void *jobj_rollback;
size_t on_disk_json_end_offset;
};
struct luks2_keyslot_params {
@@ -148,8 +158,6 @@ struct luks2_keyslot_params {
#define LUKS2_HDR_OFFSET_MAX 0x400000 /* 4 MiB */
#define LUKS2_HDR_MAX_MDA_SIZE 2 * LUKS2_HDR_OFFSET_MAX + LUKS2_MAX_KEYSLOTS_SIZE
/* Offsets for secondary header (for scan if primary header is corrupted). */
#define LUKS2_HDR2_OFFSETS { 0x04000, 0x008000, 0x010000, 0x020000, \
0x40000, 0x080000, 0x100000, 0x200000, LUKS2_HDR_OFFSET_MAX }
@@ -199,11 +207,11 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
size_t password_len,
struct volume_key **vk);
int LUKS2_keyslot_context_open_all_segments(struct crypt_device *cd,
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new,
const char *password,
size_t password_len,
struct volume_key **vks);
int LUKS2_keyslot_store(struct crypt_device *cd,
@@ -231,24 +239,6 @@ int LUKS2_keyslot_swap(struct crypt_device *cd,
int keyslot,
int keyslot2);
/*
* Segments
*/
bool LUKS2_segment_set_size(struct luks2_hdr *hdr,
int segment,
const uint64_t *segment_size_bytes);
bool LUKS2_segment_is_hw_opal(struct luks2_hdr *hdr, int segment);
bool LUKS2_segment_is_hw_opal_crypt(struct luks2_hdr *hdr, int segment);
bool LUKS2_segment_is_hw_opal_only(struct luks2_hdr *hdr, int segment);
int LUKS2_get_opal_segment_number(struct luks2_hdr *hdr, int segment,
uint32_t *ret_opal_segment_number);
int LUKS2_get_opal_key_size(struct luks2_hdr *hdr, int segment);
bool LUKS2_segments_dynamic_size(struct luks2_hdr *hdr);
/*
* Generic LUKS2 token
*/
@@ -284,6 +274,17 @@ crypt_token_info LUKS2_token_status(struct crypt_device *cd,
int token,
const char **type);
int LUKS2_token_open_and_activate(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int token,
const char *name,
const char *type,
const char *pin,
size_t pin_size,
uint32_t flags,
void *usrptr);
int LUKS2_token_unlock_key(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
@@ -317,7 +318,8 @@ void crypt_token_unload_external_all(struct crypt_device *cd);
/*
* Generic LUKS2 digest
*/
int LUKS2_digest_verify_by_any_matching(struct crypt_device *cd,
int LUKS2_digest_any_matching(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk);
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
@@ -380,7 +382,6 @@ int LUKS2_generate_hdr(
const struct volume_key *vk,
const char *cipher_spec,
const char *integrity,
uint32_t integrity_key_size, /* in bytes, only if separate (HMAC) */
const char *uuid,
unsigned int sector_size,
uint64_t data_offset,
@@ -401,17 +402,15 @@ int LUKS2_check_metadata_area_size(uint64_t metadata_size);
int LUKS2_check_keyslots_area_size(uint64_t keyslots_size);
int LUKS2_wipe_header_areas(struct crypt_device *cd,
struct luks2_hdr *hdr);
struct luks2_hdr *hdr, bool detached_header);
uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr);
int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size, bool *dynamic);
uint32_t LUKS2_get_sector_size(struct luks2_hdr *hdr);
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment);
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment);
int LUKS2_get_integrity_key_size(struct luks2_hdr *hdr, int segment);
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
struct luks2_keyslot_params *params);
int LUKS2_get_old_volume_key_size(struct luks2_hdr *hdr);
int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment);
int LUKS2_get_keyslot_stored_key_size(struct luks2_hdr *hdr, int keyslot);
const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size);
@@ -439,7 +438,7 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
/*
* Requirements for device activation or header modification
*/
void LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs);
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_set_requirement_version(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t req_id, uint8_t req_version, bool commit);
@@ -447,10 +446,12 @@ int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint8_t *version);
bool LUKS2_reencrypt_requirement_candidate(struct luks2_hdr *hdr);
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t reqs_mask, int quiet);
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,
struct luks2_hdr *hdr, struct volume_key *vk, int segment);
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot);
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
struct volume_key *vk, int digest);
@@ -464,6 +465,13 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd,
/*
* LUKS2 reencryption
*/
int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
const char *passphrase,
size_t passphrase_size,
struct volume_key **vks);
int LUKS2_reencrypt_locked_recovery_by_vks(struct crypt_device *cd,
struct volume_key *vks);
@@ -492,10 +500,20 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd,
bool device_exclusive_check,
bool dynamic);
void LUKS2_reencrypt_lookup_key_ids(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vk);
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks);
unsigned LUKS2_reencrypt_vks_count(struct luks2_hdr *hdr);
int LUKS2_reencrypt_max_hotzone_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct reenc_protection *rp,
int reencrypt_keyslot,
uint64_t *r_length);
void LUKS2_reencrypt_protection_erase(struct reenc_protection *rp);
#endif

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup v2, digest handling
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 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"
@@ -75,7 +88,7 @@ int LUKS2_digest_create(struct crypt_device *cd,
log_dbg(cd, "Creating new digest %d (%s).", digest, type);
return dh->store(cd, digest, crypt_volume_key_get_key(vk), crypt_volume_key_length(vk)) ?: digest;
return dh->store(cd, digest, vk->key, vk->keylength) ?: digest;
}
int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
@@ -108,7 +121,7 @@ int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
if (!h)
return -EINVAL;
r = h->verify(cd, digest, crypt_volume_key_get_key(vk), crypt_volume_key_length(vk));
r = h->verify(cd, digest, vk->key, vk->keylength);
if (r < 0) {
log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r);
return r;
@@ -143,7 +156,8 @@ int LUKS2_digest_dump(struct crypt_device *cd, int digest)
return h->dump(cd, digest);
}
int LUKS2_digest_verify_by_any_matching(struct crypt_device *cd,
int LUKS2_digest_any_matching(struct crypt_device *cd,
struct luks2_hdr *hdr __attribute__((unused)),
const struct volume_key *vk)
{
int digest;
@@ -160,7 +174,7 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
int segment,
const struct volume_key *vk)
{
int r;
int r = -EINVAL;
unsigned s;
if (segment == CRYPT_ANY_SEGMENT) {
@@ -172,11 +186,7 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
return -EPERM;
}
r = LUKS2_digest_by_segment(hdr, segment);
if (r < 0)
return r;
return LUKS2_digest_verify_by_digest(cd, r, vk);
return LUKS2_digest_verify_by_digest(cd, LUKS2_digest_by_segment(hdr, segment), vk);
}
/* FIXME: segment can have more digests */
@@ -423,7 +433,21 @@ int LUKS2_key_description_by_segment(struct crypt_device *cd,
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_segment(hdr, segment));
int r;
r = crypt_volume_key_set_description(vk, desc, LOGON_KEY);
r = crypt_volume_key_set_description(vk, desc);
free(desc);
return r;
}
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot)
{
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_keyslot(hdr, keyslot));
int r;
r = crypt_volume_key_set_description(vk, desc);
if (!r)
r = crypt_volume_key_load_in_keyring(cd, vk);
free(desc);
return r;
}
@@ -434,7 +458,7 @@ int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
char *desc = get_key_description_by_digest(cd, digest);
int r;
r = crypt_volume_key_set_description(vk, desc, LOGON_KEY);
r = crypt_volume_key_set_description(vk, desc);
if (!r)
r = crypt_volume_key_load_in_keyring(cd, vk);

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup v2, PBKDF2 digest handler (LUKS1 compatible)
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 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"

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 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"
@@ -289,25 +302,22 @@ static int hdr_read_disk(struct crypt_device *cd,
*/
static int hdr_write_disk(struct crypt_device *cd,
struct device *device, struct luks2_hdr *hdr,
const char *json_area, size_t write_area_len,
int secondary)
const char *json_area, int secondary)
{
struct luks2_hdr_disk hdr_disk;
uint64_t offset = secondary ? hdr->hdr_size : 0;
size_t hdr_json_len;
int devfd, r;
hdr_json_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
assert(write_area_len <= hdr_json_len);
log_dbg(cd, "Trying to write LUKS2 header (%zu bytes) at offset %" PRIu64 ".",
write_area_len, offset);
hdr->hdr_size, offset);
devfd = device_open_locked(cd, device, O_RDWR);
if (devfd < 0)
return devfd == -1 ? -EINVAL : devfd;
hdr_json_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
hdr_to_disk(hdr, &hdr_disk, secondary, offset);
/*
@@ -324,8 +334,8 @@ static int hdr_write_disk(struct crypt_device *cd,
*/
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device),
CONST_CAST(char*)json_area, write_area_len,
LUKS2_HDR_BIN_LEN + offset) < (ssize_t)write_area_len) {
CONST_CAST(char*)json_area, hdr_json_len,
LUKS2_HDR_BIN_LEN + offset) < (ssize_t)hdr_json_len) {
return -EIO;
}
@@ -404,7 +414,7 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
{
char *json_area;
const char *json_text;
size_t json_data_len, json_area_len, json_area_write_len;
size_t json_area_len;
int r;
if (hdr->version != 2) {
@@ -416,47 +426,29 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
if (r)
return r;
/*
* Generate text space-efficient JSON representation to json area.
*/
json_text = crypt_jobj_to_string_on_disk(hdr->jobj);
if (!json_text || !*json_text) {
log_dbg(cd, "Cannot parse JSON object to text representation.");
return -ENOMEM;
}
json_area_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
json_area_write_len = json_data_len = strlen(json_text);
if (json_data_len > (json_area_len - 1)) {
log_dbg(cd, "JSON is too large (%zu > %zu).", json_data_len, json_area_len - 1);
return -EINVAL;
}
/*
* Allocate and zero JSON area (of proper header size).
*/
json_area_len = hdr->hdr_size - LUKS2_HDR_BIN_LEN;
json_area = crypt_zalloc(json_area_len);
if (!json_area)
return -ENOMEM;
/*
* If the metadata in 'json_area' buffer is smaller than last on-disk
* metadata we also have to erase the remaining bytes between the tail
* of current metadata and the on-disk metadata end pointer. Set write
* area length large enough to overwrite it.
*
* If seqid_check is turned off (during LUKS2 format) write entire
* LUKS2 metadata size instead.
*
* Turn off the optimization also during metadata upconversion
* (hdr->on_disk_json_end_offset == 0).
* Generate text space-efficient JSON representation to json area.
*/
if (seqid_check && (json_data_len < hdr->on_disk_json_end_offset))
json_area_write_len = hdr->on_disk_json_end_offset;
else if (!seqid_check || !hdr->on_disk_json_end_offset)
json_area_write_len = json_area_len;
json_text = json_object_to_json_string_ext(hdr->jobj,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
if (!json_text || !*json_text) {
log_dbg(cd, "Cannot parse JSON object to text representation.");
free(json_area);
return -ENOMEM;
}
if (strlen(json_text) > (json_area_len - 1)) {
log_dbg(cd, "JSON is too large (%zu > %zu).", strlen(json_text), json_area_len);
free(json_area);
return -EINVAL;
}
strncpy(json_area, json_text, json_area_len);
if (seqid_check)
@@ -472,16 +464,13 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct
hdr->seqid++;
/* Write primary and secondary header */
r = hdr_write_disk(cd, device, hdr, json_area, json_area_write_len, 0);
r = hdr_write_disk(cd, device, hdr, json_area, 0);
if (!r)
r = hdr_write_disk(cd, device, hdr, json_area, json_area_write_len, 1);
r = hdr_write_disk(cd, device, hdr, json_area, 1);
if (r)
log_dbg(cd, "LUKS2 header write failed (%d).", r);
/* store new json end pointer or reset it on error */
hdr->on_disk_json_end_offset = r ? 0 : json_data_len;
device_write_unlock(cd, device);
free(json_area);
@@ -549,15 +538,12 @@ static int validate_luks2_json_object(struct crypt_device *cd, json_object *jobj
}
static json_object *parse_and_validate_json(struct crypt_device *cd,
const char *json_area, uint64_t hdr_size,
uint64_t *json_area_end)
const char *json_area, uint64_t hdr_size)
{
int json_len, r;
json_object *jobj;
uint64_t max_length;
assert(json_area_end);
if (hdr_size <= LUKS2_HDR_BIN_LEN || hdr_size > LUKS2_HDR_OFFSET_MAX) {
log_dbg(cd, "LUKS2 header JSON has bogus size 0x%04" PRIx64 ".", hdr_size);
return NULL;
@@ -581,8 +567,6 @@ static json_object *parse_and_validate_json(struct crypt_device *cd,
jobj = NULL;
}
*json_area_end = json_len;
return jobj;
}
@@ -646,7 +630,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
json_object *jobj_hdr1 = NULL, *jobj_hdr2 = NULL;
unsigned int i;
int r;
uint64_t hdr_size, json_area_end1 = 0, json_area_end2 = 0;
uint64_t hdr_size;
uint64_t hdr2_offsets[] = LUKS2_HDR2_OFFSETS;
/* Skip auto-recovery if locks are disabled and we're not doing LUKS2 explicit repair */
@@ -661,7 +645,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
state_hdr1 = HDR_FAIL;
r = hdr_read_disk(cd, device, &hdr_disk1, &json_area1, 0, 0);
if (r == 0) {
jobj_hdr1 = parse_and_validate_json(cd, json_area1, be64_to_cpu(hdr_disk1.hdr_size), &json_area_end1);
jobj_hdr1 = parse_and_validate_json(cd, json_area1, be64_to_cpu(hdr_disk1.hdr_size));
state_hdr1 = jobj_hdr1 ? HDR_OK : HDR_OBSOLETE;
} else if (r == -EIO)
state_hdr1 = HDR_FAIL_IO;
@@ -673,7 +657,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
if (state_hdr1 != HDR_FAIL && state_hdr1 != HDR_FAIL_IO) {
r = hdr_read_disk(cd, device, &hdr_disk2, &json_area2, be64_to_cpu(hdr_disk1.hdr_size), 1);
if (r == 0) {
jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size), &json_area_end2);
jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size));
state_hdr2 = jobj_hdr2 ? HDR_OK : HDR_OBSOLETE;
} else if (r == -EIO)
state_hdr2 = HDR_FAIL_IO;
@@ -686,7 +670,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
r = hdr_read_disk(cd, device, &hdr_disk2, &json_area2, hdr2_offsets[i], 1);
if (r == 0) {
jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size), &json_area_end2);
jobj_hdr2 = parse_and_validate_json(cd, json_area2, be64_to_cpu(hdr_disk2.hdr_size));
state_hdr2 = jobj_hdr2 ? HDR_OK : HDR_OBSOLETE;
} else if (r == -EIO)
state_hdr2 = HDR_FAIL_IO;
@@ -735,7 +719,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
log_dbg(cd, "Cannot generate header salt.");
else {
hdr_from_disk(&hdr_disk1, &hdr_disk2, hdr, 0);
r = hdr_write_disk(cd, device, hdr, json_area1, hdr->hdr_size - LUKS2_HDR_BIN_LEN, 1);
r = hdr_write_disk(cd, device, hdr, json_area1, 1);
}
if (r)
log_dbg(cd, "Secondary LUKS2 header recovery failed.");
@@ -756,7 +740,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
log_dbg(cd, "Cannot generate header salt.");
else {
hdr_from_disk(&hdr_disk2, &hdr_disk1, hdr, 1);
r = hdr_write_disk(cd, device, hdr, json_area2, hdr->hdr_size - LUKS2_HDR_BIN_LEN, 0);
r = hdr_write_disk(cd, device, hdr, json_area2, 0);
}
if (r)
log_dbg(cd, "Primary LUKS2 header recovery failed.");
@@ -785,11 +769,6 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr,
json_object_put(jobj_hdr1);
}
if (json_area_end1 > json_area_end2)
hdr->on_disk_json_end_offset = json_area_end1;
else
hdr->on_disk_json_end_offset = json_area_end2;
/*
* FIXME: should this fail? At least one header was read correctly.
* r = (state_hdr1 == HDR_FAIL_IO || state_hdr2 == HDR_FAIL_IO) ? -EIO : -EINVAL;

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup v2 (with JSON internals)
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _CRYPTSETUP_LUKS2_INTERNAL_H
@@ -48,16 +61,6 @@ uint64_t crypt_jobj_get_uint64(json_object *jobj);
uint32_t crypt_jobj_get_uint32(json_object *jobj);
json_object *crypt_jobj_new_uint64(uint64_t value);
/*
* Generate json format string representation libcryptsetup uses
* to store json metadata on disk.
*/
static inline const char *crypt_jobj_to_string_on_disk(json_object *jobj)
{
return json_object_to_json_string_ext(jobj,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
}
int json_object_object_add_by_uint(json_object *jobj, unsigned key, json_object *jobj_val);
int json_object_object_add_by_uint_by_ref(json_object *jobj, unsigned key, json_object **jobj_val_ref);
void json_object_object_del_by_uint(json_object *jobj, unsigned key);
@@ -99,7 +102,7 @@ json_object *LUKS2_array_remove(json_object *array, const char *num);
*/
/**
* LUKS2 keyslots handlers
* LUKS2 keyslots handlers (EXPERIMENTAL)
*/
typedef int (*keyslot_alloc_func)(struct crypt_device *cd, int keyslot,
size_t volume_key_len,
@@ -162,7 +165,7 @@ struct reenc_protection {
};
/**
* LUKS2 digest handlers
* LUKS2 digest handlers (EXPERIMENTAL)
*/
typedef int (*digest_verify_func)(struct crypt_device *cd, int digest,
const char *volume_key, size_t volume_key_len);
@@ -302,7 +305,7 @@ void json_segment_remove_flag(json_object *jobj_segment, const char *flag);
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise);
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption);
json_object *json_segment_create_crypt(uint64_t offset, uint64_t iv_offset, const uint64_t *length,
const char *cipher, const char *integrity, uint32_t integrity_key_size,
const char *cipher, const char *integrity,
uint32_t sector_size, unsigned reencryption);
json_object *json_segment_create_opal(uint64_t offset, const uint64_t *length,
uint32_t segment_number, uint32_t key_size);
@@ -347,6 +350,10 @@ uint64_t LUKS2_segment_size(struct luks2_hdr *hdr,
int segment,
unsigned blockwise);
bool LUKS2_segment_set_size(struct luks2_hdr *hdr,
int segment,
const uint64_t *segment_size_bytes);
uint64_t LUKS2_opal_segment_size(struct luks2_hdr *hdr,
int segment,
unsigned blockwise);
@@ -355,6 +362,14 @@ int LUKS2_segment_is_type(struct luks2_hdr *hdr,
int segment,
const char *type);
bool LUKS2_segment_is_hw_opal(struct luks2_hdr *hdr, int segment);
bool LUKS2_segment_is_hw_opal_crypt(struct luks2_hdr *hdr, int segment);
bool LUKS2_segment_is_hw_opal_only(struct luks2_hdr *hdr, int segment);
int LUKS2_get_opal_segment_number(struct luks2_hdr *hdr, int segment,
uint32_t *ret_opal_segment_number);
int LUKS2_get_opal_key_size(struct luks2_hdr *hdr, int segment);
int LUKS2_segment_by_type(struct luks2_hdr *hdr,
const char *type);
@@ -363,20 +378,13 @@ int LUKS2_last_segment_by_type(struct luks2_hdr *hdr,
int LUKS2_get_default_segment(struct luks2_hdr *hdr);
bool LUKS2_segments_dynamic_size(struct luks2_hdr *hdr);
int LUKS2_reencrypt_digest_new(struct luks2_hdr *hdr);
int LUKS2_reencrypt_digest_old(struct luks2_hdr *hdr);
int LUKS2_reencrypt_segment_new(struct luks2_hdr *hdr);
int LUKS2_reencrypt_segment_old(struct luks2_hdr *hdr);
unsigned LUKS2_reencrypt_vks_count(struct luks2_hdr *hdr);
int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise);
int LUKS2_reencrypt_max_hotzone_size(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct reenc_protection *rp,
int reencrypt_keyslot,
uint64_t *r_length);
void LUKS2_reencrypt_protection_erase(struct reenc_protection *rp);
/*
* Generic LUKS2 digest
*/

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 header format code
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 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"
@@ -193,7 +206,6 @@ int LUKS2_generate_hdr(
const struct volume_key *vk,
const char *cipher_spec,
const char *integrity,
uint32_t integrity_key_size, /* in bytes, only if separate (HMAC) */
const char *uuid,
unsigned int sector_size, /* in bytes */
uint64_t data_offset, /* in bytes */
@@ -280,8 +292,8 @@ int LUKS2_generate_hdr(
if (!opal_key_size)
jobj_segment = json_segment_create_crypt(data_offset, 0,
NULL, cipher_spec,
integrity, integrity_key_size,
sector_size, 0);
integrity, sector_size,
0);
else if (opal_key_size && cipher_spec)
jobj_segment = json_segment_create_opal_crypt(data_offset, &device_size_bytes,
opal_segment_number, opal_key_size, 0,
@@ -314,43 +326,40 @@ err:
}
int LUKS2_wipe_header_areas(struct crypt_device *cd,
struct luks2_hdr *hdr)
struct luks2_hdr *hdr, bool detached_header)
{
int r;
uint64_t device_size_bytes, length, offset;
size_t wipe_block = 1024 * 1024;
uint64_t offset, length;
size_t wipe_block;
if (!hdr || LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
return -EINVAL;
r = device_size(crypt_metadata_device(cd), &device_size_bytes);
if (r < 0)
return -EINVAL;
/* Wipe up to maximal allowed metadata size, but do not write beyond data offset. */
/* Wipe complete header, keyslots and padding areas with zeroes. */
offset = 0;
length = LUKS2_get_data_offset(hdr) * SECTOR_SIZE;
if (!length || length > LUKS2_HDR_MAX_MDA_SIZE)
length = LUKS2_HDR_MAX_MDA_SIZE;
wipe_block = 1024 * 1024;
/* Also do not extend the device size yet (file backends) */
if (length > device_size_bytes)
length = device_size_bytes;
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
return -EINVAL;
log_dbg(cd, "Wiping LUKS areas (0x%06" PRIx64 " - 0x%06" PRIx64") with zeroes.",
0ULL, length);
/* On detached header wipe at least the first 4k */
if (detached_header) {
length = 4096;
wipe_block = 4096;
}
r = crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_ZERO, 0,
length, wipe_block, NULL, NULL);
if (r < 0)
return r;
/* Allocate at least actual LUKS2 metadata size */
r = device_check_size(cd, crypt_metadata_device(cd),
LUKS2_hdr_and_areas_size(hdr), 1);
r = device_check_size(cd, crypt_metadata_device(cd), length, 1);
if (r)
return r;
log_dbg(cd, "Wiping LUKS areas (0x%06" PRIx64 " - 0x%06" PRIx64") with zeroes.",
offset, length + offset);
r = crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_ZERO,
offset, length, wipe_block, NULL, NULL);
if (r < 0)
return r;
/* Wipe keyslot area */
wipe_block = 1024 * 1024;
offset = get_min_offset(hdr);
length = LUKS2_keyslots_size(hdr);

View File

@@ -1,10 +1,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup v2
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2025 Ondrej Kozina
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Milan Broz
* Copyright (C) 2015-2024 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "luks2_internal.h"
@@ -13,6 +26,8 @@
#include <ctype.h>
#include <uuid/uuid.h>
#define LUKS_STRIPES 4000
struct interval {
uint64_t offset;
uint64_t length;
@@ -465,7 +480,8 @@ static int hdr_validate_json_size(struct crypt_device *cd, json_object *hdr_jobj
json_object_object_get_ex(hdr_jobj, "config", &jobj);
json_object_object_get_ex(jobj, "json_size", &jobj1);
json = crypt_jobj_to_string_on_disk(hdr_jobj);
json = json_object_to_json_string_ext(hdr_jobj,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
if (!json)
return 1;
@@ -633,11 +649,6 @@ static int reqs_opal(uint32_t reqs)
return reqs & CRYPT_REQUIREMENT_OPAL;
}
static int reqs_inline_hw_tags(uint32_t reqs)
{
return reqs & CRYPT_REQUIREMENT_INLINE_HW_TAGS;
}
/*
* Config section requirements object must be valid.
* Also general segments section must be validated first.
@@ -646,12 +657,14 @@ static int validate_reencrypt_segments(struct crypt_device *cd, json_object *hdr
{
json_object *jobj, *jobj_backup_previous = NULL, *jobj_backup_final = NULL;
uint32_t reqs;
int i;
int i, r;
struct luks2_hdr dummy = {
.jobj = hdr_jobj
};
LUKS2_config_get_requirements(cd, &dummy, &reqs);
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++) {
@@ -1426,8 +1439,7 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
}
/* do not allow header restore from backup with unmet requirements */
if (LUKS2_unmet_requirements(cd, &hdr_file,
CRYPT_REQUIREMENT_ONLINE_REENCRYPT | CRYPT_REQUIREMENT_INLINE_HW_TAGS, 1)) {
if (LUKS2_unmet_requirements(cd, &hdr_file, CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1)) {
log_err(cd, _("Forbidden LUKS2 requirements detected in backup %s."),
backup_file);
r = -ETXTBSY;
@@ -1459,7 +1471,9 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
r = LUKS2_hdr_read(cd, &tmp_hdr, 0);
if (r == 0) {
log_dbg(cd, "Device %s already contains LUKS2 header, checking UUID and requirements.", device_path(device));
LUKS2_config_get_requirements(cd, &tmp_hdr, &reqs);
r = LUKS2_config_get_requirements(cd, &tmp_hdr, &reqs);
if (r)
goto out;
if (memcmp(tmp_hdr.uuid, hdr_file.uuid, LUKS2_UUID_L))
diff_uuid = 1;
@@ -1543,7 +1557,7 @@ out:
* Persistent config flags
*/
static const struct {
uint64_t flag;
uint32_t flag;
const char *description;
} persistent_flags[] = {
{ CRYPT_ACTIVATE_ALLOW_DISCARDS, "allow-discards" },
@@ -1552,7 +1566,6 @@ static const struct {
{ CRYPT_ACTIVATE_NO_JOURNAL, "no-journal" },
{ CRYPT_ACTIVATE_NO_READ_WORKQUEUE, "no-read-workqueue" },
{ CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE, "no-write-workqueue" },
{ CRYPT_ACTIVATE_HIGH_PRIORITY, "high_priority" },
{ 0, NULL }
};
@@ -1642,7 +1655,6 @@ static const struct requirement_flag requirements_flags[] = {
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 2, "online-reencrypt-v2" },
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 3, "online-reencrypt-v3" },
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1, "online-reencrypt" },
{ CRYPT_REQUIREMENT_INLINE_HW_TAGS, 1, "inline-hw-tags" },
{ CRYPT_REQUIREMENT_OPAL, 1, "opal" },
{ 0, 0, NULL }
};
@@ -1765,7 +1777,7 @@ static const struct requirement_flag *stored_requirement_name_by_id(struct luks2
/*
* returns count of requirements (past cryptsetup 2.0 release)
*/
void LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs)
int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs)
{
json_object *jobj_mandatory, *jobj;
int i, len;
@@ -1778,11 +1790,11 @@ void LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hd
jobj_mandatory = mandatory_requirements_jobj(hdr);
if (!jobj_mandatory)
return;
return 0;
len = (int) json_object_array_length(jobj_mandatory);
if (len <= 0)
return;
return 0;
log_dbg(cd, "LUKS2 requirements detected:");
@@ -1793,6 +1805,8 @@ void LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hd
reqs_unknown(req->flag) ? "un" : "");
*reqs |= req->flag;
}
return 0;
}
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit)
@@ -1800,7 +1814,7 @@ 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;
uint64_t req_id;
uint32_t req_id;
if (!hdr)
return -EINVAL;
@@ -2127,10 +2141,6 @@ static void hdr_dump_segments(struct crypt_device *cd, json_object *hdr_jobj)
json_object_object_get_ex(jobj1, "type", &jobj2))
log_std(cd, "\tintegrity: %s\n", json_object_get_string(jobj2));
if (json_object_object_get_ex(jobj_segment, "integrity", &jobj1) &&
json_object_object_get_ex(jobj1, "key_size", &jobj2))
log_std(cd, "\tintegrity key size: %" PRIu32 " [bits]\n", crypt_jobj_get_uint32(jobj2) * 8);
if (json_object_object_get_ex(jobj_segment, "flags", &jobj1) &&
(flags = (int)json_object_array_length(jobj1)) > 0) {
jobj2 = json_object_array_get_idx(jobj1, 0);
@@ -2307,7 +2317,12 @@ crypt_reencrypt_info LUKS2_reencrypt_status(struct luks2_hdr *hdr)
{
uint32_t reqs;
LUKS2_config_get_requirements(NULL, hdr, &reqs);
/*
* Any unknown requirement or offline reencryption should abort
* anything related to online-reencryption handling
*/
if (LUKS2_config_get_requirements(NULL, hdr, &reqs))
return CRYPT_REENCRYPT_INVALID;
if (!reqs_reencrypt_online(reqs))
return CRYPT_REENCRYPT_NONE;
@@ -2361,24 +2376,6 @@ const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment)
return json_object_get_string(jobj3);
}
int LUKS2_get_integrity_key_size(struct luks2_hdr *hdr, int segment)
{
json_object *jobj1, *jobj2, *jobj3;
jobj1 = LUKS2_get_segment_jobj(hdr, segment);
if (!jobj1)
return -1;
if (!json_object_object_get_ex(jobj1, "integrity", &jobj2))
return -1;
/* The value is optional, do not fail if not present */
if (!json_object_object_get_ex(jobj2, "key_size", &jobj3))
return 0;
return json_object_get_int(jobj3);
}
/* FIXME: this only ensures that once we have journal encryption, it is not ignored. */
/* implement segment count and type restrictions (crypt and only single crypt) */
static int LUKS2_integrity_compatible(struct luks2_hdr *hdr)
@@ -2466,19 +2463,6 @@ int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment)
return -1;
}
int LUKS2_get_old_volume_key_size(struct luks2_hdr *hdr)
{
int old_segment;
assert(hdr);
old_segment = LUKS2_reencrypt_segment_old(hdr);
if (old_segment < 0)
return old_segment;
return LUKS2_get_volume_key_size(hdr, old_segment);
}
uint32_t LUKS2_get_sector_size(struct luks2_hdr *hdr)
{
return json_segment_get_sector_size(LUKS2_get_segment_jobj(hdr, CRYPT_DEFAULT_SEGMENT));
@@ -2547,7 +2531,7 @@ int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,
crypt_data_device(cd), vk,
json_segment_get_cipher(jobj),
json_segment_get_iv_offset(jobj),
segment_offset, "none", 0, 0,
segment_offset, "none", 0,
json_segment_get_sector_size(jobj));
if (r) {
log_err(cd, _("Failed to set dm-crypt segment."));
@@ -2661,7 +2645,7 @@ int LUKS2_activate(struct crypt_device *cd,
{
int r;
bool dynamic, read_lock, write_lock, opal_lock_on_error = false;
uint32_t opal_segment_number, req_flags;
uint32_t opal_segment_number;
uint64_t range_offset_sectors, range_length_sectors, device_length_bytes;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
struct crypt_dm_active_device dmdi = {}, dmd = {
@@ -2670,8 +2654,7 @@ int LUKS2_activate(struct crypt_device *cd,
struct crypt_lock_handle *opal_lh = NULL;
/* do not allow activation when particular requirements detected */
if ((r = LUKS2_unmet_requirements(cd, hdr,
CRYPT_REQUIREMENT_OPAL | CRYPT_REQUIREMENT_INLINE_HW_TAGS, 0)))
if ((r = LUKS2_unmet_requirements(cd, hdr, CRYPT_REQUIREMENT_OPAL, 0)))
return r;
/* Check that cipher is in compatible format */
@@ -2744,7 +2727,7 @@ int LUKS2_activate(struct crypt_device *cd,
crypt_key, crypt_get_cipher_spec(cd),
crypt_get_iv_offset(cd), crypt_get_data_offset(cd),
crypt_get_integrity(cd) ?: "none",
crypt_get_integrity_key_size(cd, true), crypt_get_integrity_tag_size(cd),
crypt_get_integrity_tag_size(cd),
crypt_get_sector_size(cd));
} else
r = dm_linear_target_set(&dmd.segment, 0,
@@ -2760,13 +2743,7 @@ int LUKS2_activate(struct crypt_device *cd,
dmd.flags |= flags;
if (crypt_persistent_flags_get(cd, CRYPT_FLAGS_REQUIREMENTS, &req_flags)) {
r = -EINVAL;
goto out;
}
if (crypt_get_integrity_tag_size(cd) &&
!(req_flags & CRYPT_REQUIREMENT_INLINE_HW_TAGS)) {
if (crypt_get_integrity_tag_size(cd)) {
if (!LUKS2_integrity_compatible(hdr)) {
log_err(cd, _("Unsupported device integrity configuration."));
r = -EINVAL;
@@ -2846,14 +2823,14 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
struct crypt_dm_active_device dmdc;
uint32_t opal_segment_number;
char **dep, deps_uuid_prefix[40], *deps[MAX_DM_DEPS+1] = { 0 };
char *iname = NULL;
const char *namei = NULL;
struct crypt_lock_handle *reencrypt_lock = NULL, *opal_lh = NULL;
if (!dmd || !dmd->uuid || strncmp(CRYPT_LUKS2, dmd->uuid, sizeof(CRYPT_LUKS2)-1))
return -EINVAL;
/* uuid mismatch with metadata (if available) */
if (hdr && dm_uuid_cmp(dmd->uuid, hdr->uuid))
if (hdr && crypt_uuid_cmp(dmd->uuid, hdr->uuid))
return -EINVAL;
r = snprintf(deps_uuid_prefix, sizeof(deps_uuid_prefix), CRYPT_SUBDEV "-%.32s", dmd->uuid + 6);
@@ -2861,15 +2838,15 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
return -EINVAL;
/* check if active device has LUKS2-OPAL dm uuid prefix */
dm_opal_uuid = !dm_uuid_type_cmp(dmd->uuid, CRYPT_LUKS2_HW_OPAL);
dm_opal_uuid = !crypt_uuid_type_cmp(dmd->uuid, CRYPT_LUKS2_HW_OPAL);
if (dm_opal_uuid && hdr && !LUKS2_segment_is_hw_opal(hdr, CRYPT_DEFAULT_SEGMENT))
return -EINVAL;
tgt = &dmd->segment;
/* TODO: We have LUKS2 dependencies now */
if (tgt->type == DM_CRYPT && tgt->u.crypt.tag_size)
iname = dm_get_active_iname(cd, name);
if (single_segment(dmd) && tgt->type == DM_CRYPT && tgt->u.crypt.tag_size)
namei = device_dm_name(tgt->data_device);
r = dm_device_deps(cd, name, deps_uuid_prefix, deps, ARRAY_SIZE(deps));
if (r < 0)
@@ -2907,34 +2884,23 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
tgt = &dmdc.segment;
while (tgt) {
if (tgt->type == DM_CRYPT)
crypt_volume_key_drop_kernel_key(cd, tgt->u.crypt.vk);
crypt_drop_keyring_key_by_description(cd, tgt->u.crypt.vk->key_description,
LOGON_KEY);
tgt = tgt->next;
}
}
dm_targets_free(cd, &dmdc);
/* TODO: We have LUKS2 dependencies now */
if (r >= 0 && iname) {
log_dbg(cd, "Deactivating integrity device %s.", iname);
r = dm_remove_device(cd, iname, 0);
if (r >= 0 && namei) {
log_dbg(cd, "Deactivating integrity device %s.", namei);
r = dm_remove_device(cd, namei, 0);
}
if (!r) {
ret = 0;
dep = deps;
while (*dep) {
/*
* FIXME: dm-integrity has now proper SUBDEV prefix so
* it would be deactivated here, but due to specific
* dm_remove_device(iname) above the iname device
* is no longer active. This will be fixed when
* we switch to SUBDEV deactivation after 2.8 release.
*/
if (iname && !strcmp(*dep, iname)) {
dep++;
continue;
}
log_dbg(cd, "Deactivating LUKS2 dependent device %s.", *dep);
r = dm_query_device(cd, *dep, DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_CRYPT_KEYSIZE, &dmdc);
if (r < 0) {
@@ -2954,7 +2920,8 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
tgt = &dmdc.segment;
while (tgt) {
if (tgt->type == DM_CRYPT)
crypt_volume_key_drop_kernel_key(cd, tgt->u.crypt.vk);
crypt_drop_keyring_key_by_description(cd, tgt->u.crypt.vk->key_description,
LOGON_KEY);
tgt = tgt->next;
}
}
@@ -2996,7 +2963,6 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
out:
opal_exclusive_unlock(cd, opal_lh);
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
free(iname);
dep = deps;
while (*dep)
free(*dep++);
@@ -3004,11 +2970,16 @@ out:
return r;
}
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t reqs_mask, int quiet)
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet)
{
uint32_t reqs;
int r = LUKS2_config_get_requirements(cd, hdr, &reqs);
LUKS2_config_get_requirements(cd, hdr, &reqs);
if (r) {
if (!quiet)
log_err(cd, _("Failed to read LUKS2 requirements."));
return r;
}
/* do not mask unknown requirements check */
if (reqs_unknown(reqs)) {
@@ -3026,8 +2997,6 @@ int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uin
log_err(cd, _("Operation incompatible with device marked for LUKS2 reencryption. Aborting."));
if (reqs_opal(reqs) && !quiet)
log_err(cd, _("Operation incompatible with device using OPAL. Aborting."));
if (reqs_inline_hw_tags(reqs) && !quiet)
log_err(cd, _("Operation incompatible with device using inline HW tags. Aborting."));
/* any remaining unmasked requirement fails the check */
return reqs ? -EINVAL : 0;
@@ -3136,22 +3105,22 @@ int LUKS2_split_crypt_and_opal_keys(struct crypt_device *cd __attribute__((unuse
if (r < 0)
return -EINVAL;
if (crypt_volume_key_length(vk) < opal_user_key_size)
if (vk->keylength < opal_user_key_size)
return -EINVAL;
/* OPAL SEGMENT only */
if (crypt_volume_key_length(vk) == opal_user_key_size) {
if (vk->keylength == opal_user_key_size) {
*ret_crypt_key = NULL;
*ret_opal_key = NULL;
return 0;
}
opal_key = crypt_alloc_volume_key(opal_user_key_size, crypt_volume_key_get_key(vk));
opal_key = crypt_alloc_volume_key(opal_user_key_size, vk->key);
if (!opal_key)
return -ENOMEM;
crypt_key = crypt_alloc_volume_key(crypt_volume_key_length(vk) - opal_user_key_size,
crypt_volume_key_get_key(vk) + opal_user_key_size);
crypt_key = crypt_alloc_volume_key(vk->keylength - opal_user_key_size,
vk->key + opal_user_key_size);
if (!crypt_key) {
crypt_free_volume_key(opal_key);
return -ENOMEM;

View File

@@ -1,13 +1,25 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup v2, keyslot handling
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 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 "keyslot_context.h"
/* Internal implementations */
extern const keyslot_handler luks2_keyslot;
@@ -76,38 +88,8 @@ int LUKS2_keyslot_find_empty(struct crypt_device *cd, struct luks2_hdr *hdr, siz
/* Check if a keyslot is assigned to specific segment */
static int _keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
{
json_object *jobj_keyslots, *jobj;
crypt_keyslot_priority slot_priority;
unsigned s;
int keyslot_digest, count = 0;
/*
* Must not be called with both keyslot == CRYPT_ANY_SLOT
* and segment == CRYPT_ONE_SEGMENT. The CRYPT_DEFAULT_SEGMENT
* and CRYPT_ANY_SEGMENT are handled properly in upper layer.
*/
assert(keyslot >= 0 || segment >= 0);
if (keyslot == CRYPT_ANY_SLOT) {
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
json_object_object_foreach(jobj_keyslots, slot, val) {
if (!json_object_object_get_ex(val, "priority", &jobj))
slot_priority = CRYPT_SLOT_PRIORITY_NORMAL;
else
slot_priority = json_object_get_int(jobj);
if (slot_priority < CRYPT_SLOT_PRIORITY_NORMAL)
continue;
keyslot_digest = LUKS2_digest_by_keyslot(hdr, atoi(slot));
if (keyslot_digest >= 0 &&
keyslot_digest == LUKS2_digest_by_segment(hdr, segment))
return 1;
}
return 0;
}
unsigned s;
keyslot_digest = LUKS2_digest_by_keyslot(hdr, keyslot);
if (keyslot_digest < 0)
@@ -124,6 +106,16 @@ static int _keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
return count;
}
static int _keyslot_for_digest(struct luks2_hdr *hdr, int keyslot, int digest)
{
int r = -EINVAL;
r = LUKS2_digest_by_keyslot(hdr, keyslot);
if (r < 0)
return r;
return r == digest ? 0 : -ENOENT;
}
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
{
int r = -EINVAL;
@@ -168,16 +160,6 @@ int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd, const char *ciphe
if (!cipher_spec || crypt_is_cipher_null(cipher_spec))
return 1;
/*
* Do not allow capi format for keyslots
* Note: It always failed in ivsize check later anyway.
*/
if (!strncmp(cipher_spec, "capi:", 5))
return 1;
if (crypt_is_cipher_null(cipher_spec))
return 1;
if (crypt_parse_name_and_mode(cipher_spec, cipher, NULL, cipher_mode) < 0)
return 1;
@@ -349,43 +331,61 @@ static int _open_and_verify(struct crypt_device *cd,
int keyslot,
const char *password,
size_t password_len,
struct volume_key **r_vk)
struct volume_key **vk)
{
int r, key_size = LUKS2_get_keyslot_stored_key_size(hdr, keyslot);
struct volume_key *vk = NULL;
void *key = NULL;
if (key_size < 0)
return -EINVAL;
key = crypt_safe_alloc(key_size);
if (!key)
*vk = crypt_alloc_volume_key(key_size, NULL);
if (!*vk)
return -ENOMEM;
r = h->open(cd, keyslot, password, password_len, key, key_size);
if (r < 0) {
log_dbg(cd, "Keyslot %d (%s) open failed with %d.", keyslot, h->name, r);
goto err;
}
vk = crypt_alloc_volume_key_by_safe_alloc(&key);
if (!vk) {
r = -ENOMEM;
goto err;
}
r = LUKS2_digest_verify(cd, hdr, vk, keyslot);
r = h->open(cd, keyslot, password, password_len, (*vk)->key, (*vk)->keylength);
if (r < 0)
goto err;
log_dbg(cd, "Keyslot %d (%s) open failed with %d.", keyslot, h->name, r);
else
r = LUKS2_digest_verify(cd, hdr, *vk, keyslot);
crypt_volume_key_set_id(vk, r);
*r_vk = vk;
return keyslot;
err:
crypt_safe_free(key);
crypt_free_volume_key(vk);
if (r < 0) {
crypt_free_volume_key(*vk);
*vk = NULL;
}
return r;
crypt_volume_key_set_id(*vk, r);
return r < 0 ? r : keyslot;
}
static int LUKS2_open_and_verify_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int digest,
const char *password,
size_t password_len,
struct volume_key **vk)
{
const keyslot_handler *h;
int r;
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
return -ENOENT;
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
if (r) {
log_dbg(cd, "Keyslot %d validation failed.", keyslot);
return r;
}
r = _keyslot_for_digest(hdr, keyslot, digest);
if (r) {
if (r == -ENOENT)
log_dbg(cd, "Keyslot %d unusable for digest %d.", keyslot, digest);
return r;
}
return _open_and_verify(cd, hdr, h, keyslot, password, password_len, vk);
}
static int LUKS2_open_and_verify(struct crypt_device *cd,
@@ -418,6 +418,44 @@ static int LUKS2_open_and_verify(struct crypt_device *cd,
return _open_and_verify(cd, hdr, h, keyslot, password, password_len, vk);
}
static int LUKS2_keyslot_open_priority_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
crypt_keyslot_priority priority,
const char *password,
size_t password_len,
int digest,
struct volume_key **vk)
{
json_object *jobj_keyslots, *jobj;
crypt_keyslot_priority slot_priority;
int keyslot, r = -ENOENT;
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
json_object_object_foreach(jobj_keyslots, slot, val) {
if (!json_object_object_get_ex(val, "priority", &jobj))
slot_priority = CRYPT_SLOT_PRIORITY_NORMAL;
else
slot_priority = json_object_get_int(jobj);
keyslot = atoi(slot);
if (slot_priority != priority) {
log_dbg(cd, "Keyslot %d priority %d != %d (required), skipped.",
keyslot, slot_priority, priority);
continue;
}
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
/* Do not retry for errors that are no -EPERM or -ENOENT,
former meaning password wrong, latter key slot unusable for segment */
if ((r != -EPERM) && (r != -ENOENT))
break;
}
return r;
}
static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
struct luks2_hdr *hdr,
crypt_keyslot_priority priority,
@@ -428,13 +466,11 @@ static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
{
json_object *jobj_keyslots, *jobj;
crypt_keyslot_priority slot_priority;
int keyslot, r = -ENOENT, r_old;
int keyslot, r = -ENOENT;
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
json_object_object_foreach(jobj_keyslots, slot, val) {
r_old = r;
if (!json_object_object_get_ex(val, "priority", &jobj))
slot_priority = CRYPT_SLOT_PRIORITY_NORMAL;
else
@@ -453,91 +489,75 @@ static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
former meaning password wrong, latter key slot unusable for segment */
if ((r != -EPERM) && (r != -ENOENT))
break;
/* If a previous keyslot failed with EPERM (bad password) prefer it */
if (r_old == -EPERM && r == -ENOENT)
r = -EPERM;
}
return r;
}
static int keyslot_context_open_all_segments(struct crypt_device *cd,
static int LUKS2_keyslot_open_by_digest(struct crypt_device *cd,
struct luks2_hdr *hdr,
int keyslot,
int digest,
const char *password,
size_t password_len,
struct volume_key **vk)
{
int r_prio, r = -EINVAL;
if (digest < 0)
return r;
if (keyslot == CRYPT_ANY_SLOT) {
r_prio = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_PREFER,
password, password_len, digest, vk);
if (r_prio >= 0)
r = r_prio;
else if (r_prio != -EPERM && r_prio != -ENOENT)
r = r_prio;
else
r = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_NORMAL,
password, password_len, digest, vk);
/* Prefer password wrong to no entry from priority slot */
if (r_prio == -EPERM && r == -ENOENT)
r = r_prio;
} else
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
return r;
}
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
struct crypt_keyslot_context *kc_old,
struct crypt_keyslot_context *kc_new,
struct volume_key **r_vks)
const char *password,
size_t password_len,
struct volume_key **vks)
{
int segment_old, segment_new, digest_old = -1, digest_new = -1, r = -ENOENT;
struct luks2_hdr *hdr;
struct volume_key *vk = NULL;
int digest_old, digest_new, r = -EINVAL;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
assert(cd);
assert(!kc_old || kc_old->get_luks2_key);
assert(!kc_new || kc_new->get_luks2_key);
assert(r_vks);
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
segment_old = LUKS2_reencrypt_segment_old(hdr);
segment_new = LUKS2_reencrypt_segment_new(hdr);
if (segment_old < 0 || segment_new < 0)
return -EINVAL;
digest_old = LUKS2_digest_by_segment(hdr, segment_old);
digest_new = LUKS2_digest_by_segment(hdr, segment_new);
if (digest_old >= 0 && digest_new >= 0 && digest_old != digest_new && (!kc_old || !kc_new))
return -ESRCH;
if (digest_old >= 0 && kc_old) {
log_dbg(cd, "Checking current volume key (digest %d, segment: %d) using keyslot %d.",
digest_old, segment_old, keyslot_old);
/* key and key in keyring types do not have association with any keyslot */
if (kc_old->type != CRYPT_KC_TYPE_KEY && kc_old->type != CRYPT_KC_TYPE_VK_KEYRING) {
r = LUKS2_keyslot_for_segment(hdr, keyslot_old, segment_old);
if (r < 0)
goto out;
}
r = kc_old->get_luks2_key(cd, kc_old, keyslot_old, segment_old, &vk);
digest_old = LUKS2_reencrypt_digest_old(hdr);
if (digest_old >= 0) {
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_old, keyslot_old);
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_old, digest_old, password, password_len, &vk);
if (r < 0)
goto out;
crypt_volume_key_add_next(r_vks, vk);
if (crypt_volume_key_get_id(vk) < 0 && LUKS2_digest_verify_by_digest(cd, digest_old, vk) == digest_old)
crypt_volume_key_set_id(vk, digest_old);
if (crypt_volume_key_get_id(vk) != digest_old) {
r = -EPERM;
goto out;
}
crypt_volume_key_add_next(vks, vk);
}
if (digest_new >= 0 && digest_old != digest_new && kc_new) {
log_dbg(cd, "Checking new volume key (digest %d, segment: %d) using keyslot %d.",
digest_new, segment_new, keyslot_new);
/* key and key in keyring types do not have association with any keyslot */
if (kc_new->type != CRYPT_KC_TYPE_KEY && kc_new->type != CRYPT_KC_TYPE_VK_KEYRING) {
r = LUKS2_keyslot_for_segment(hdr, keyslot_new, segment_new);
if (r < 0)
goto out;
}
r = kc_new->get_luks2_key(cd, kc_new, keyslot_new, segment_new, &vk);
digest_new = LUKS2_reencrypt_digest_new(hdr);
if (digest_new >= 0 && digest_old != digest_new) {
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_new, keyslot_new);
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_new, digest_new, password, password_len, &vk);
if (r < 0)
goto out;
crypt_volume_key_add_next(r_vks, vk);
if (crypt_volume_key_get_id(vk) < 0 && LUKS2_digest_verify_by_digest(cd, digest_new, vk) == digest_new)
crypt_volume_key_set_id(vk, digest_new);
if (crypt_volume_key_get_id(vk) != digest_new)
r = -EPERM;
crypt_volume_key_add_next(vks, vk);
}
out:
if (r < 0) {
crypt_free_volume_key(*r_vks);
*r_vks = NULL;
crypt_free_volume_key(*vks);
*vks = NULL;
if (r == -ENOMEM)
log_err(cd, _("Not enough available memory to open a keyslot."));
@@ -547,25 +567,6 @@ out:
return r;
}
int LUKS2_keyslot_context_open_all_segments(struct crypt_device *cd,
int keyslot1,
int keyslot2,
struct crypt_keyslot_context *kc1,
struct crypt_keyslot_context *kc2,
struct volume_key **r_vks)
{
int r, r2;
r = keyslot_context_open_all_segments(cd, keyslot1, keyslot2, kc1, kc2, r_vks);
if (r == -EPERM || r == -ENOENT) {
r2 = keyslot_context_open_all_segments(cd, keyslot2, keyslot1, kc2, kc1, r_vks);
if (r2 != -ENOENT)
r = r2;
}
return r;
}
int LUKS2_keyslot_open(struct crypt_device *cd,
int keyslot,
int segment,
@@ -648,7 +649,7 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
if (!h)
return -EINVAL;
r = h->alloc(cd, keyslot, crypt_volume_key_length(vk), params);
r = h->alloc(cd, keyslot, vk->keylength, params);
if (r)
return r;
} else {
@@ -672,7 +673,7 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
return -EINVAL;
return h->store(cd, keyslot, password, password_len,
crypt_volume_key_get_key(vk), crypt_volume_key_length(vk));
vk->key, vk->keylength);
}
int LUKS2_keyslot_wipe(struct crypt_device *cd,
@@ -863,7 +864,8 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return -EINVAL;
LUKS2_config_get_requirements(cd, &dummy, &reqs);
if (LUKS2_config_get_requirements(cd, &dummy, &reqs))
return -EINVAL;
json_object_object_foreach(jobj_keyslots, slot, val) {
keyslot = atoi(slot);

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 type keyslot handler
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 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 <limits.h>
@@ -14,6 +27,7 @@
#define LUKS_SALTSIZE 32
#define LUKS_SLOT_ITERATIONS_MIN 1000
#define LUKS_STRIPES 4000
/* Serialize memory-hard keyslot access: optional workaround for parallel processing */
#define MIN_MEMORY_FOR_SERIALIZE_LOCK_KB 32*1024 /* 32MB */
@@ -24,7 +38,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
struct volume_key *vk, unsigned int sector,
struct crypt_device *cd)
{
#if !ENABLE_AF_ALG /* Support for old kernel without Crypto API */
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
return LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd);
#else
struct crypt_storage *s;
@@ -36,8 +50,7 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength,
return -EINVAL;
/* Encrypt buffer */
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode,
crypt_volume_key_get_key(vk), crypt_volume_key_length(vk), false);
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
if (r) {
log_err(cd, _("Cannot use %s-%s cipher for keyslot encryption."), cipher, cipher_mode);
return r;
@@ -75,7 +88,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
unsigned int sector, struct crypt_device *cd)
{
struct device *device = crypt_metadata_device(cd);
#if !ENABLE_AF_ALG /* Support for old kernel without Crypto API */
#ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */
int r = device_read_lock(cd, device);
if (r) {
log_err(cd, _("Failed to acquire read lock on device %s."), device_path(device));
@@ -92,9 +105,7 @@ static int luks2_decrypt_from_storage(char *dst, size_t dstLength,
if (MISALIGNED_512(dstLength))
return -EINVAL;
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode,
crypt_volume_key_get_key(vk),
crypt_volume_key_length(vk), false);
r = crypt_storage_init(&s, SECTOR_SIZE, cipher, cipher_mode, vk->key, vk->keylength, false);
if (r) {
log_err(cd, _("Cannot use %s-%s cipher for keyslot encryption."), cipher, cipher_mode);
return r;
@@ -192,6 +203,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
const char *password, size_t passwordLen,
const char *volume_key, size_t volume_key_len)
{
struct volume_key *derived_key;
char *salt = NULL, cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char *AfKey = NULL;
const char *af_hash = NULL;
@@ -200,8 +212,6 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
uint64_t area_offset;
struct crypt_pbkdf_type pbkdf;
int r;
struct volume_key *derived_vk = NULL;
void *derived_key = NULL;
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
@@ -239,7 +249,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
/*
* Allocate derived key storage.
*/
derived_key = crypt_safe_alloc(keyslot_key_len);
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
if (!derived_key) {
free(salt);
return -ENOMEM;
@@ -250,7 +260,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
log_dbg(cd, "Running keyslot key derivation.");
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
salt, LUKS_SALTSIZE,
derived_key, keyslot_key_len,
derived_key->key, derived_key->keylength,
pbkdf.iterations, pbkdf.max_memory_kb,
pbkdf.parallel_threads);
free(salt);
@@ -258,17 +268,16 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
if ((crypt_backend_flags() & CRYPT_BACKEND_PBKDF2_INT) &&
pbkdf.iterations > INT_MAX)
log_err(cd, _("PBKDF2 iteration value overflow."));
if (r == -ENOMEM)
log_err(cd, _("Not enough memory for keyslot key derivation."));
goto out;
crypt_free_volume_key(derived_key);
return r;
}
// FIXME: verity key_size to AFEKSize
AFEKSize = AF_split_sectors(volume_key_len, LUKS_STRIPES) * SECTOR_SIZE;
AfKey = crypt_safe_alloc(AFEKSize);
if (!AfKey) {
r = -ENOMEM;
goto out;
crypt_free_volume_key(derived_key);
return -ENOMEM;
}
r = crypt_hash_size(af_hash);
@@ -277,23 +286,15 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
else
r = AF_split(cd, volume_key, AfKey, volume_key_len, LUKS_STRIPES, af_hash);
if (r < 0)
goto out;
derived_vk = crypt_alloc_volume_key_by_safe_alloc(&derived_key);
if (!derived_vk) {
r = -ENOMEM;
goto out;
if (r == 0) {
log_dbg(cd, "Updating keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_encrypt... accordingly */
r = luks2_encrypt_to_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
}
log_dbg(cd, "Updating keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_encrypt... accordingly */
r = luks2_encrypt_to_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_vk, (unsigned)(area_offset / SECTOR_SIZE), cd);
out:
crypt_safe_free(AfKey);
crypt_safe_free(derived_key);
crypt_free_volume_key(derived_vk);
crypt_free_volume_key(derived_key);
if (r < 0)
return r;
@@ -305,7 +306,8 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
const char *password, size_t passwordLen,
char *volume_key, size_t volume_key_len)
{
struct crypt_pbkdf_type pbkdf;
struct volume_key *derived_key = NULL;
struct crypt_pbkdf_type pbkdf, *cd_pbkdf;
char *AfKey = NULL;
size_t AFEKSize;
const char *af_hash = NULL;
@@ -315,8 +317,6 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
size_t keyslot_key_len;
bool try_serialize_lock = false;
int r;
struct volume_key *derived_vk = NULL;
void *derived_key = NULL;
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
@@ -347,7 +347,7 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
/*
* Allocate derived key storage space.
*/
derived_key = crypt_safe_alloc(keyslot_key_len);
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
if (!derived_key) {
r = -ENOMEM;
goto out;
@@ -360,6 +360,16 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
goto out;
}
/*
* Print warning when keyslot requires more memory than available
* (if maximum memory was adjusted - no swap, not enough memory),
* but be silent if user set keyslot memory cost above default limit intentionally.
*/
cd_pbkdf = crypt_get_pbkdf(cd);
if (cd_pbkdf->max_memory_kb && pbkdf.max_memory_kb > cd_pbkdf->max_memory_kb &&
pbkdf.max_memory_kb <= DEFAULT_LUKS2_MEMORY_KB)
log_std(cd, _("Warning: keyslot operation could fail as it requires more than available memory.\n"));
/*
* If requested, serialize unlocking for memory-hard KDF. Usually NOOP.
*/
@@ -374,27 +384,20 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
log_dbg(cd, "Running keyslot key derivation.");
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
salt, LUKS_SALTSIZE,
derived_key, keyslot_key_len,
derived_key->key, derived_key->keylength,
pbkdf.iterations, pbkdf.max_memory_kb,
pbkdf.parallel_threads);
if (try_serialize_lock)
crypt_serialize_unlock(cd);
if (r < 0)
goto out;
derived_vk = crypt_alloc_volume_key_by_safe_alloc(&derived_key);
if (!derived_vk) {
r = -ENOMEM;
goto out;
if (r == 0) {
log_dbg(cd, "Reading keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
r = luks2_decrypt_from_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
}
log_dbg(cd, "Reading keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
r = luks2_decrypt_from_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_vk, (unsigned)(area_offset / SECTOR_SIZE), cd);
if (r == 0) {
r = crypt_hash_size(af_hash);
if (r < 0)
@@ -404,9 +407,8 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
}
out:
free(salt);
crypt_free_volume_key(derived_vk);
crypt_free_volume_key(derived_key);
crypt_safe_free(AfKey);
crypt_safe_free(derived_key);
return r;
}

View File

@@ -1,9 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup v2, reencryption keyslot handler
*
* Copyright (C) 2016-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2025 Ondrej Kozina
* Copyright (C) 2016-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2024 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "luks2_internal.h"

View File

@@ -1,10 +1,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LUKS - Linux Unified Key Setup v2, LUKS1 conversion code
*
* Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2025 Ondrej Kozina
* Copyright (C) 2015-2025 Milan Broz
* Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
* Copyright (C) 2015-2024 Ondrej Kozina
* Copyright (C) 2015-2024 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"
@@ -570,7 +583,6 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
json_object *jobj = NULL;
size_t buf_size, buf_offset, luks1_size, luks1_shift = 2 * LUKS2_HDR_16K_LEN - LUKS_ALIGN_KEYSLOTS;
uint64_t required_size, max_size = crypt_get_data_offset(cd) * SECTOR_SIZE;
char cipher_spec[MAX_CAPI_LEN];
/* for detached headers max size == device size */
if (!max_size && (r = device_size(crypt_metadata_device(cd), &max_size)))
@@ -592,15 +604,6 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
return -EINVAL;
}
r = snprintf(cipher_spec, sizeof(cipher_spec), "%s-%s", hdr1->cipherName, hdr1->cipherMode);
if (r < 0 || (size_t)r >= sizeof(cipher_spec))
return -EINVAL;
if (LUKS2_keyslot_cipher_incompatible(cd, cipher_spec)) {
log_err(cd, _("Unable to use cipher specification %s-%s for LUKS2 keyslot."),
hdr1->cipherName, hdr1->cipherMode);
return -EINVAL;
}
if (luksmeta_header_present(cd, luks1_size))
return -EINVAL;
@@ -618,10 +621,6 @@ int LUKS2_luks1_to_luks2(struct crypt_device *cd, struct luks_phdr *hdr1, struct
if (max_size < required_size)
max_size = required_size;
/* fix coverity false positive integer underflow */
if (max_size < 2 * LUKS2_HDR_16K_LEN)
return -EINVAL;
r = json_luks1_object(hdr1, &jobj, max_size - 2 * LUKS2_HDR_16K_LEN);
if (r < 0)
return r;
@@ -697,54 +696,30 @@ static int keyslot_LUKS1_compatible(struct crypt_device *cd, struct luks2_hdr *h
if (!jobj_keyslot)
return 1;
/* Keyslot type */
if (!json_object_object_get_ex(jobj_keyslot, "type", &jobj))
if (!json_object_object_get_ex(jobj_keyslot, "type", &jobj) ||
strcmp(json_object_get_string(jobj), "luks2"))
return 0;
if (strcmp(json_object_get_string(jobj), "luks2")) {
log_dbg(cd, "Keyslot %d type %s is not compatible.",
keyslot, json_object_get_string(jobj));
return 0;
}
/* Keyslot uses PBKDF2, this implies memory and parallel is not used. */
/* Using PBKDF2, this implies memory and parallel is not used. */
jobj = NULL;
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
!json_object_object_get_ex(jobj_kdf, "type", &jobj))
!json_object_object_get_ex(jobj_kdf, "type", &jobj) ||
strcmp(json_object_get_string(jobj), CRYPT_KDF_PBKDF2) ||
!json_object_object_get_ex(jobj_kdf, "hash", &jobj) ||
strcmp(json_object_get_string(jobj), hash))
return 0;
if (strcmp(json_object_get_string(jobj), CRYPT_KDF_PBKDF2)) {
log_dbg(cd, "Keyslot %d does not use PBKDF2.", keyslot);
return 0;
}
/* Keyslot KDF hash is the same as the digest hash. */
jobj = NULL;
if (!json_object_object_get_ex(jobj_kdf, "hash", &jobj))
return 0;
if (strcmp(json_object_get_string(jobj), hash)) {
log_dbg(cd, "Keyslot %d PBKDF uses different hash %s than digest hash %s.",
keyslot, json_object_get_string(jobj), hash);
return 0;
}
/* Keyslot AF use compatible striptes. */
jobj = NULL;
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
!json_object_object_get_ex(jobj_af, "stripes", &jobj))
!json_object_object_get_ex(jobj_af, "stripes", &jobj) ||
json_object_get_int(jobj) != LUKS_STRIPES)
return 0;
if (json_object_get_int(jobj) != LUKS_STRIPES) {
log_dbg(cd, "Keyslot %d AF uses incompatible stripes count.", keyslot);
return 0;
}
/* Keyslot AF hash is the same as the digest hash. */
jobj = NULL;
if (!json_object_object_get_ex(jobj_af, "hash", &jobj))
if (!json_object_object_get_ex(jobj_af, "hash", &jobj) ||
(crypt_hash_size(json_object_get_string(jobj)) < 0) ||
strcmp(json_object_get_string(jobj), hash))
return 0;
if (strcmp(json_object_get_string(jobj), hash)) {
log_dbg(cd, "Keyslot %d AF uses different hash %s than digest hash %s.",
keyslot, json_object_get_string(jobj), hash);
return 0;
}
ks_cipher = LUKS2_get_keyslot_cipher(hdr, keyslot, &ks_key_size);
data_cipher = LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT);
@@ -777,7 +752,6 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
int i, r, last_active = 0;
uint64_t offset, area_length;
char *buf, luksMagic[] = LUKS_MAGIC;
crypt_keyslot_info ki;
jobj_digest = LUKS2_get_digest_jobj(hdr2, 0);
if (!jobj_digest)
@@ -802,8 +776,6 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (!json_object_object_get_ex(jobj_digest, "hash", &jobj2))
return -EINVAL;
hash = json_object_get_string(jobj2);
if (crypt_hash_size(hash) < 0)
return -EINVAL;
r = crypt_parse_name_and_mode(LUKS2_get_cipher(hdr2, CRYPT_DEFAULT_SEGMENT), cipher, NULL, cipher_mode);
if (r < 0)
@@ -828,28 +800,19 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
}
r = LUKS2_get_volume_key_size(hdr2, 0);
if (r < 0) {
log_err(cd, _("Cannot convert to LUKS1 format - there are no active keyslots."), r);
if (r < 0)
return -EINVAL;
}
key_size = r;
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
ki = LUKS2_keyslot_info(hdr2, i);
if (ki == CRYPT_SLOT_INACTIVE)
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INACTIVE)
continue;
if (ki == CRYPT_SLOT_INVALID) {
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INVALID) {
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is in invalid state."), i);
return -EINVAL;
}
if (ki == CRYPT_SLOT_UNBOUND) {
log_err(cd, _("Cannot convert to LUKS1 format - keyslot %u is unbound."), i);
return -EINVAL;
}
if (i >= LUKS_NUMKEYS) {
log_err(cd, _("Cannot convert to LUKS1 format - slot %u (over maximum slots) is still active."), i);
return -EINVAL;

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